
// RUN: %target-swift-frontend -module-name access_marker_verify -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -emit-silgen -swift-version 4 -parse-as-library %s | %FileCheck %s
// RUN: %target-swift-frontend -module-name access_marker_verify -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -Onone -emit-sil -swift-version 4 -parse-as-library %s -o /dev/null
// RUN: %target-swift-frontend -module-name access_marker_verify -enable-verify-exclusivity -enforce-exclusivity=checked -enable-sil-ownership -O -emit-sil -swift-version 4 -parse-as-library %s -o /dev/null
// REQUIRES: asserts

// Test the combination of SILGen + DiagnoseStaticExclusivity with verification.
//
// This is a collection of tests that cover SILGen cases that require special
// handling for exclusivity verification. SILGen must generate access markers,
// possibly unenforced, to satisfy the verification run during the
// DiagnoseStaticExclusivity pass.
//
// These cases are mostly covered by existing SILGen tests, but need to be
// repeated here to ensure they are run with exclusivity verification enabled.
import SwiftShims

protocol P {}
struct StructP : P {}

protocol PBar {
  func bar()
}

class BaseClass  {
  init() {}
}
class SubClass : BaseClass {
  override required init() {}
}

enum E {
case V(Int)
}

func takesClosure(_ f: () -> ()) {
  f()
}

// --- struct initialization.
struct StructOfInt {
  var i: Int

  init() {
    i = 1
  }

  mutating func changeMe() {
    i = 3
  }
}
// The verifier ignores the load of the self box.
// CHECK-LABEL: sil hidden @$S20access_marker_verify11StructOfIntVACycfC : $@convention(method) (@thin StructOfInt.Type) -> StructOfInt {
// CHECK: bb0(%0 : @trivial $@thin StructOfInt.Type):
// CHECK:   [[BOX:%.*]] = alloc_box ${ var StructOfInt }, var, name "self"
// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [rootself] [[BOX]] : ${ var StructOfInt }
// CHECK:   [[PROJ:%.*]] = project_box [[UNINIT]] : ${ var StructOfInt }, 0
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJ]] : $*StructOfInt
// CHECK:   [[ADR:%.*]] = struct_element_addr [[ACCESS]] : $*StructOfInt, #StructOfInt.i
// CHECK:   assign %{{.*}} to [[ADR]] : $*Int
// CHECK:   end_access [[ACCESS]] : $*StructOfInt
// CHECK-NOT: begin_access
// CHECK:   [[VAL:%.*]] = load [trivial] [[PROJ]] : $*StructOfInt
// CHECK:   destroy_value [[UNINIT]] : ${ var StructOfInt }
// CHECK:   return [[VAL]] : $StructOfInt
// CHECK-LABEL: } // end sil function '$S20access_marker_verify11StructOfIntVACycfC'

// --- class initialization.
class SuperHasInt {
  var i: Int

  init() {
    i = 3
  }
}

class SubHasInt : SuperHasInt {
  var j: Int
  
  override init() {
    j = 4
    super.init()
  }

  init(x: Int) {
    j = x
    super.init()
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify11SuperHasIntCACycfc : $@convention(method) (@owned SuperHasInt) -> @owned SuperHasInt {
// CHECK:   bb0(%0 : @owned $SuperHasInt):
// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [rootself] %0 : $SuperHasInt
// CHECK:   [[BORROW:%.*]] = begin_borrow [[UNINIT]] : $SuperHasInt
// CHECK:   [[ADR:%.*]] = ref_element_addr [[BORROW]] : $SuperHasInt, #SuperHasInt.i
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Int
// CHECK:   assign %{{.*}} to [[ACCESS]] : $*Int
// CHECK:   end_access [[ACCESS]] : $*Int
// CHECK:   end_borrow [[BORROW]] from [[UNINIT]] : $SuperHasInt, $SuperHasInt
// CHECK-NOT: begin_access
// CHECK:   [[VAL:%.*]] = copy_value [[UNINIT]] : $SuperHasInt
// CHECK:   destroy_value [[UNINIT]] : $SuperHasInt
// CHECK:   return [[VAL]] : $SuperHasInt
// CHECK-LABEL: } // end sil function '$S20access_marker_verify11SuperHasIntCACycfc'

// CHECK-LABEL: sil hidden @$S20access_marker_verify9SubHasIntCACycfc : $@convention(method) (@owned SubHasInt) -> @owned SubHasInt {
// CHECK: bb0(%0 : @owned $SubHasInt):
// CHECK:   [[BOX:%.*]] = alloc_box ${ var SubHasInt }, let, name "self"
// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [derivedself] [[BOX]] : ${ var SubHasInt }
// CHECK:   [[PROJ:%.*]] = project_box [[UNINIT]] : ${ var SubHasInt }, 0
// CHECK-NOT: begin_access
// CHECK:   store %0 to [init] [[PROJ]] : $*SubHasInt
// CHECK-NOT: begin_access
// CHECK:   [[BORROW:%.*]] = load_borrow [[PROJ]] : $*SubHasInt
// CHECK:   [[ADR:%.*]] = ref_element_addr [[BORROW]] : $SubHasInt, #SubHasInt.j
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Int
// CHECK:   assign %{{.*}} to [[ACCESS]] : $*Int
// CHECK:   end_access [[ACCESS]] : $*Int
// CHECK:   end_borrow [[BORROW]] from [[PROJ]] : $SubHasInt, $*SubHasInt
// CHECK-NOT: begin_access
// CHECK:   load [take] [[PROJ]] : $*SubHasInt
// CHECK:   upcast %{{.*}} : $SubHasInt to $SuperHasInt
// CHECK:   function_ref @$S20access_marker_verify11SuperHasIntCACycfc : $@convention(method) (@owned SuperHasInt) -> @owned SuperHasInt
// CHECK:   apply
// CHECK:   unchecked_ref_cast %{{.*}} : $SuperHasInt to $SubHasInt
// CHECK-NOT: begin_access
// CHECK:   store %{{.*}} to [init] [[PROJ]] : $*SubHasInt
// CHECK:   [[VAL:%.*]] = load [copy] [[PROJ]] : $*SubHasInt
// CHECK:   destroy_value [[UNINIT]] : ${ var SubHasInt }
// CHECK:   return [[VAL]] : $SubHasInt
// CHECK-LABEL: } // end sil function '$S20access_marker_verify9SubHasIntCACycfc'

// CHECK-LABEL: sil hidden @$S20access_marker_verify9SubHasIntC1xACSi_tcfc : $@convention(method) (Int, @owned SubHasInt) -> @owned SubHasInt {
// CHECK: bb0(%0 : @trivial $Int, %1 : @owned $SubHasInt):
// CHECK:   [[BOX:%.*]] = alloc_box ${ var SubHasInt }, let, name "self"
// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [derivedself] [[BOX]] : ${ var SubHasInt }
// CHECK:   [[PROJ:%.*]] = project_box [[UNINIT]] : ${ var SubHasInt }, 0
// CHECK-NOT: begin_access
// CHECK:   store %{{.*}} to [init] [[PROJ]] : $*SubHasInt
// CHECK-NOT: begin_access
// CHECK:   [[BORROW:%.*]] = load_borrow [[PROJ]] : $*SubHasInt
// CHECK:   [[ADR:%.*]] = ref_element_addr [[BORROW]] : $SubHasInt, #SubHasInt.j
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[ADR]] : $*Int
// CHECK:   assign %0 to [[ACCESS]] : $*Int
// CHECK:   end_access [[ACCESS]] : $*Int
// CHECK:   end_borrow [[BORROW]] from [[PROJ]] : $SubHasInt, $*SubHasInt
// CHECK-NOT: begin_access
// CHECK:   load [take] [[PROJ]] : $*SubHasInt
// CHECK:   upcast %{{.*}} : $SubHasInt to $SuperHasInt
// CHECK:   function_ref @$S20access_marker_verify11SuperHasIntCACycfc : $@convention(method) (@owned SuperHasInt) -> @owned SuperHasInt
// CHECK:   apply
// CHECK:   unchecked_ref_cast %{{.*}} : $SuperHasInt to $SubHasInt
// CHECK-NOT: begin_access
// CHECK:   store %{{.*}} to [init] [[PROJ]] : $*SubHasInt
// CHECK:   [[VAL:%.*]] = load [copy] [[PROJ]] : $*SubHasInt
// CHECK:   destroy_value [[UNINIT]] : ${ var SubHasInt }
// CHECK:   return [[VAL]] : $SubHasInt
// CHECK-LABEL: } // end sil function '$S20access_marker_verify9SubHasIntC1xACSi_tcfc'

// --- access `let` property.
class LetClass {
  let x = 3
}

// FIXME: should be a [unknown] access.
//
// CHECK-LABEL: sil hidden @$S20access_marker_verify10testGetLet1cSiAA0F5ClassC_tF : $@convention(thin) (@guaranteed LetClass) -> Int {
// CHECK: bb0(%0 : @guaranteed $LetClass):
// CHECK:   ref_element_addr
// CHECK:   load [trivial]
// CHECK:   return
// CHECK-LABEL: } // end sil function '$S20access_marker_verify10testGetLet1cSiAA0F5ClassC_tF'
func testGetLet(c: LetClass) -> Int {
  return c.x
}

// --- initialize let property and superclass.
struct IntWrapper {
  var x: Int
}

final class SubWrapper : BaseClass {
  let val: IntWrapper

  init(_ val: IntWrapper) {
    self.val = val
    super.init()
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify10SubWrapperCyAcA03IntE0Vcfc : $@convention(method) (IntWrapper, @owned SubWrapper) -> @owned SubWrapper {
// CHECK: bb0(%0 : @trivial $IntWrapper, %1 : @owned $SubWrapper):
// CHECK:   alloc_box ${ var SubWrapper }, let, name "self"
// CHECK:   mark_uninitialized [derivedself]
// CHECK:   project_box
// CHECK-NOT: begin_access
// CHECK:   store %1 to [init]
// CHECK-NOT: begin_access
// CHECK:   load_borrow
// CHECK:   ref_element_addr
// CHECK:   assign %0 to
// CHECK:   end_borrow
// CHECK-NOT: begin_access
// CHECK:   load [take]
// CHECK-NOT: begin_access
// CHECK:   store %{{.*}} to [init]
// CHECK:   [[VAL:%.*]] = load [copy]
// CHECK:   destroy_value %{{.*}} : ${ var SubWrapper }
// CHECK:   return [[VAL]] : $SubWrapper
// CHECK-LABEL: } // end sil function '$S20access_marker_verify10SubWrapperCyAcA03IntE0Vcfc'

// --- captured local.
func testCaptureLocal() -> ()->() {
  var x = 1
  let f = { x = 3 }
  _ = x
  return f
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify16testCaptureLocalyycyF : $@convention(thin) () -> @owned @callee_guaranteed () -> () {
// CHECK: bb0:
// CHECK:   alloc_box ${ var Int }, var, name "x"
// CHECK:   [[PROJ:%.*]] = project_box
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]] : $*Int
// CHECK:   store %{{.*}} to [trivial] [[ACCESS]]
// CHECK:   end_access
// CHECK:   [[CAPTURE:%.*]] = copy_value %0 : ${ var Int }
// CHECK:   partial_apply [callee_guaranteed] %{{.*}}([[CAPTURE]]) : $@convention(thin) (@guaranteed { var Int }) -> ()
// CHECK:   alloc_stack $Int
// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [var]
// CHECK:   begin_access [read] [unknown] [[PROJ]]
// CHECK:   [[VAL:%.*]] = load [trivial]
// CHECK:   end_access
// CHECK-NOT: begin_access
// CHECK:   assign [[VAL]] to [[UNINIT]] : $*Int
// CHECK:   return {{.*}} : $@callee_guaranteed () -> ()
// CHECK-LABEL: } // end sil function '$S20access_marker_verify16testCaptureLocalyycyF'

// --- mutating struct.
func testModifyS(_ arg: StructOfInt) -> StructOfInt {
  var lhs: StructOfInt
  lhs = arg
  lhs.changeMe()
  return lhs
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify11testModifySyAA11StructOfIntVADF : $@convention(thin) (StructOfInt) -> StructOfInt {
// CHECK: bb0(%0 : @trivial $StructOfInt):
// CHECK:   alloc_box ${ var StructOfInt }, var, name "lhs"
// CHECK:   mark_uninitialized [var]
// CHECK:   project_box
// CHECK:   begin_access [modify] [unknown]
// CHECK:   assign
// CHECK:   end_access
// CHECK:   begin_access [modify] [unknown]
// CHECK:   function_ref @$S20access_marker_verify11StructOfIntV8changeMeyyF : $@convention(method) (@inout StructOfInt) -> ()
// CHECK:   apply
// CHECK:   end_access
// CHECK:   begin_access [read] [unknown]
// CHECK:   load [trivial]
// CHECK:   end_access
// CHECK-LABEL: } // end sil function '$S20access_marker_verify11testModifySyAA11StructOfIntVADF'

// --- initialize LValue.
protocol HasIntGetter {
  var x: Int { get }
}
func testInitLValue(p: HasIntGetter) -> Int {
  var x = p.x
  return x
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify14testInitLValue1pSiAA12HasIntGetter_p_tF : $@convention(thin) (@in_guaranteed HasIntGetter) -> Int {
// CHECK: bb0(%0 : @trivial $*HasIntGetter):
// CHECK:   alloc_box ${ var Int }, var, name "x"
// CHECK:   [[PROJ:%.*]] = project_box
// CHECK:   [[OPENED:%.*]] = open_existential_addr immutable_access %0
// CHECK:   [[X:%.*]] = alloc_stack $@opened
// CHECK-NOT: begin_access
// CHECK:   copy_addr %{{.*}} to [initialization] [[X]] : $*@opened
// CHECK:   witness_method $@opened
// CHECK:   apply %{{.*}}<@opened("{{.*}}") HasIntGetter>([[X]]) : $@convention(witness_method: HasIntGetter) <τ_0_0 where τ_0_0 : HasIntGetter> (@in_guaranteed τ_0_0) -> Int
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]] : $*Int
// CHECK:   store %{{.*}} to [trivial] [[ACCESS]] : $*Int
// CHECK:   end_access
// CHECK:   destroy_addr
// CHECK:   dealloc_stack
// CHECK:   begin_access [read] [unknown] [[PROJ]]
// CHECK:   load [trivial]
// CHECK:   end_access
// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testInitLValue1pSiAA12HasIntGetter_p_tF'

// --- initialize let.
func testCopyS(_ arg: StructOfInt) -> StructOfInt {
  let lhs: StructOfInt
  lhs = arg
  return lhs
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify9testCopySyAA11StructOfIntVADF : $@convention(thin) (StructOfInt) -> StructOfInt {
// CHECK: bb0(%0 : @trivial $StructOfInt):
// CHECK:   alloc_stack $StructOfInt, let, name "lhs"
// CHECK:   [[UNINIT:%.*]] = mark_uninitialized [var]
// CHECK-NOT: begin_access
// CHECK:   assign %0 to [[UNINIT]] : $*StructOfInt
// CHECK-NOT: begin_access
// CHECK:   %5 = load [trivial] [[UNINIT]] : $*StructOfInt
// CHECK-LABEL: } // end sil function '$S20access_marker_verify9testCopySyAA11StructOfIntVADF'

// --- local var init (single buffer).
func testLocalVarInit(_ arg: StructOfInt) -> Int {
  var lhs = arg
  return lhs.i
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify16testLocalVarInitySiAA11StructOfIntVF : $@convention(thin) (StructOfInt) -> Int {
// CHECK: bb0(%0 : @trivial $StructOfInt):
// CHECK:   alloc_box ${ var StructOfInt }, var, name "lhs"
// CHECK:   [[BOX:%.*]] = project_box
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[BOX]]
// CHECK:   store %0 to [trivial] [[ACCESS]]
// CHECK:   end_access
// CHECK-LABEL: } // end sil function '$S20access_marker_verify16testLocalVarInitySiAA11StructOfIntVF'

// --- init generic enum
enum GenericEnum<T> {
case V(T)

  init?(t: T) {
    self = .V(t)
  }
}

func testInitGenericEnum<T>(t: T) -> GenericEnum<T>? {
  return GenericEnum(t: t)
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify11GenericEnumO1tACyxGSgx_tcfC : $@convention(method) <T> (@in T, @thin GenericEnum<T>.Type) -> @out Optional<GenericEnum<T>> {
// CHECK: bb0(%0 : @trivial $*Optional<GenericEnum<T>>, %1 : @trivial $*T, %2 : @trivial $@thin GenericEnum<T>.Type):
// CHECK:   alloc_box $<τ_0_0> { var GenericEnum<τ_0_0> } <T>, var, name "self"
// CHECK:   mark_uninitialized [delegatingself] %3 : $<τ_0_0> { var GenericEnum<τ_0_0> } <T>
// CHECK:   [[PROJ:%.*]] = project_box
// CHECK:   [[STK:%.*]] = alloc_stack $GenericEnum<T>
// CHECK:   [[ADR1:%.*]] = init_enum_data_addr [[STK]]
// CHECK-NOT: begin_access
// CHECK:   copy_addr %1 to [initialization] [[ADR1]] : $*T
// CHECK:   inject_enum_addr
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[PROJ]]
// CHECK:   copy_addr [take] %{{.*}} to [[ACCESS]] : $*GenericEnum<T>
// CHECK:   end_access [[ACCESS]] : $*GenericEnum<T>
// CHECK:   [[ADR2:%.*]] = init_enum_data_addr %0
// CHECK-NOT: begin_access
// CHECK:   copy_addr %{{.*}} to [initialization] [[ADR2]] : $*GenericEnum<T>
// CHECK:   inject_enum_addr %0 : $*Optional<GenericEnum<T>>, #Optional.some!enumelt.1
// CHECK-LABEL: } // end sil function '$S20access_marker_verify11GenericEnumO1tACyxGSgx_tcfC'

// -- initialize indirect enum.
enum IndirectEnum {
  indirect case V(Int)
}

func testIndirectEnum() -> IndirectEnum {
  return IndirectEnum.V(3)
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify16testIndirectEnumAA0eF0OyF : $@convention(thin) () -> @owned IndirectEnum {
// CHECK: bb0:
// CHECK:   alloc_box ${ var Int }
// CHECK:   [[PROJ:%.*]] = project_box
// CHECK:   apply
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]]
// CHECK:   store %{{.*}} to [trivial] [[ACCESS]] : $*Int
// CHECK:   end_access
// CHECK:   enum $IndirectEnum, #IndirectEnum.V!enumelt.1
// CHECK:   return
// CHECK-LABEL: } // end sil function '$S20access_marker_verify16testIndirectEnumAA0eF0OyF'

// -- indirect enum with getter.
enum IntEnum {
  indirect case int(Int)

  var getValue: Int {
    switch self {
    case .int(let x): return x
    }
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify7IntEnumO8getValueSivg : $@convention(method) (@guaranteed IntEnum) -> Int {
// CHECK: bb0(%0 : @guaranteed $IntEnum):
// CHECK:   switch_enum %{{.*}} : $IntEnum, case #IntEnum.int!enumelt.1: bb1
// CHECK: bb1(%{{.*}} : @owned ${ var Int }):
// CHECK:   [[PROJ:%.*]] = project_box
// CHECK-NOT: begin_access
// CHECK:   load [trivial] [[PROJ]] : $*Int
// CHECK-LABEL: } // end sil function '$S20access_marker_verify7IntEnumO8getValueSivg'

// -- indirect enum reference.
enum RefEnum {
  indirect case ref(BaseClass)

  var getValue: BaseClass {
    switch self {
    case .ref(let c): return c
    }
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify7RefEnumO8getValueAA9BaseClassCvg : $@convention(method) (@guaranteed RefEnum) -> @owned BaseClass {
// CHECK: bb0(%0 : @guaranteed $RefEnum):
// CHECK:   switch_enum %{{.*}} : $RefEnum, case #RefEnum.ref!enumelt.1: bb1
// CHECK: bb1(%{{.*}} : @owned ${ var BaseClass }):
// CHECK:   [[PROJ:%.*]] = project_box %{{.*}} : ${ var BaseClass }, 0
// CHECK-NOT: begin_access
// CHECK:   load_borrow [[PROJ]] : $*BaseClass
// CHECK-LABEL: } // end sil function '$S20access_marker_verify7RefEnumO8getValueAA9BaseClassCvg'

// --- indirect enum pattern.
func testEnumPattern(ie: IndirectEnum) -> Bool {
  guard case .V(let kind) = ie else {
    return false
  }
  _ = kind
  return true
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify15testEnumPattern2ieSbAA08IndirectE0O_tF : $@convention(thin) (@guaranteed IndirectEnum) -> Bool {
// CHECK: bb0(%0 : @guaranteed $IndirectEnum):
// CHECK:   switch_enum %{{.*}} : $IndirectEnum, case #IndirectEnum.V!enumelt.1: [[BBV:bb.*]], default bb
// CHECK: [[BBV]](%{{.*}} : @owned ${ var Int }):
// CHECK:   [[PROJ:%.*]] = project_box
// CHECK-NOT: begin_access
// CHECK:   load [trivial] [[PROJ]] : $*Int
// CHECK-LABEL: } // end sil function '$S20access_marker_verify15testEnumPattern2ieSbAA08IndirectE0O_tF'

// --- enum LValue.
struct StructOfEnum {
  var e: E
  var f: E
}
func enumLValueHelper(_: inout E, _: inout E) {}

// CHECK-LABEL: sil hidden @$S20access_marker_verify14testEnumLValue1syAA08StructOfE0Vz_tF : $@convention(thin) (@inout StructOfEnum) -> () {
// CHECK: bb0(%0 : @trivial $*StructOfEnum):
// CHECK:   begin_access [modify] [unknown] %0 : $*StructOfEnum
// CHECK:   struct_element_addr %2 : $*StructOfEnum, #StructOfEnum.e
// CHECK:   begin_access [modify] [unknown] %0 : $*StructOfEnum
// CHECK:   struct_element_addr %4 : $*StructOfEnum, #StructOfEnum.f
// CHECK:   function_ref @$S20access_marker_verify16enumLValueHelperyyAA1EOz_ADztF : $@convention(thin) (@inout E, @inout E) -> ()
// CHECK:   apply %6(%3, %5) : $@convention(thin) (@inout E, @inout E) -> ()
// CHECK:   end_access %4 : $*StructOfEnum
// CHECK:   end_access %2 : $*StructOfEnum
// CHECK:   %10 = tuple ()
// CHECK:   return %10 : $()
// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testEnumLValue1syAA08StructOfE0Vz_tF'
func testEnumLValue(s: inout StructOfEnum) {
  enumLValueHelper(&s.e, &s.f)
}

// --- Optional access.
func accessOptionalArray(_ dict : [Int : [Int]] = [:]) {
  var dict = dict
  dict[1]?.append(2)
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify0A13OptionalArrayyySDySiSaySiGGF : $@convention(thin) (@guaranteed Dictionary<Int, Array<Int>>) -> () {
// CHECK: bb0(%0 : @guaranteed $Dictionary<Int, Array<Int>>):
// CHECK:   alloc_box ${ var Dictionary<Int, Array<Int>> }, var, name "dict"
// CHECK:   [[PROJ:%.*]] = project_box
// ----- initialize the box.
// CHECK:   [[INITACCESS:%.*]] = begin_access [modify] [unsafe] [[PROJ]]
// CHECK:   store %{{.*}} to [init] [[INITACCESS]]
// CHECK:   end_access [[INITACCESS]]
// ----- begin formal access for Dictionary.subscript.setter
// CHECK:   [[BOXACCESS:%.*]] = begin_access [modify] [unknown] [[PROJ]]
// CHECK:   [[TEMP:%.*]] = alloc_stack $Optional<Array<Int>>
// CHECK:   load_borrow [[BOXACCESS]] : $*Dictionary<Int, Array<Int>>
// ----- Initialize some trivial temporaries.
// CHECK:   alloc_stack $Int
// CHECK-NOT: begin_access
// CHECK:   store %{{.*}} to [trivial]
// ----- Call Dictionary.subscript.getter.
// CHECK-NOT: begin_access
// CHECK:   apply %{{.*}}<Int, [Int]>
// ----- access the temporary array result of the getter
// CHECK:   [[TEMPACCESS:%.*]] = begin_access [modify] [unsafe] [[TEMP]]
// CHECK:   [[HAS_VALUE:%.*]] = select_enum_addr [[TEMPACCESS]]
// CHECK:   cond_br [[HAS_VALUE]], bb2, bb1
//
// CHECK: bb1:
// CHECK:   [[TEMPARRAY:%.*]] = load [copy] [[TEMPACCESS]]
// CHECK:   [[WRITEBACK:%.*]] = alloc_stack $Optional<Array<Int>>
// CHECK-NOT: begin_access
// CHECK:   store [[TEMPARRAY]] to [init] [[WRITEBACK]]
// CHECK:   [[TEMP3:%.*]] = alloc_stack $Int
// CHECK-NOT: begin_access
// CHECK:   store %{{.*}} to [trivial] [[TEMP3]] : $*Int
// Call Dictionary.subscript.setter
// CHECK:   apply %{{.*}}<Int, [Int]>([[WRITEBACK]], [[TEMP3]], [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
// CHECK:   end_access [[TEMPACCESS]] : $*Optional<Array<Int>>
// CHECK:   end_access [[BOXACCESS]] : $*Dictionary<Int, Array<Int>>
// CHECK:   br
//
// CHECK: bb2:
// CHECK-NOT: begin_access
// CHECK:   [[TEMPARRAYADR:%.*]] = unchecked_take_enum_data_addr [[TEMPACCESS]] : $*Optional<Array<Int>>, #Optional.some!enumelt.1
// ----- call Array.append
// CHECK:   alloc_stack $Int
// CHECK:   store %{{.*}} to [trivial]
// CHECK:   function_ref @$SSa6appendyyxF : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout Array<τ_0_0>) -> ()
// CHECK:   apply %{{.*}}<Int>(%{{.*}}, [[TEMPARRAYADR]]) : $@convention(method) <τ_0_0> (@in_guaranteed τ_0_0, @inout Array<τ_0_0>) -> ()
// CHECK:   [[TEMPARRAYVAL:%.*]] = load [take] [[TEMPACCESS]] : $*Optional<Array<Int>>
// CHECK:   [[ARRAYCOPY:%.*]] = alloc_stack $Optional<Array<Int>>
// CHECK:   store [[TEMPARRAYVAL]] to [init] [[ARRAYCOPY]] : $*Optional<Array<Int>>
// CHECK:   alloc_stack $Int
// CHECK:   store %{{.*}} to [trivial]
// ----- call Dictionary.subscript.setter
// CHECK: apply %{{.*}}<Int, [Int]>([[ARRAYCOPY]], %{{.*}}, [[BOXACCESS]]) : $@convention(method) <τ_0_0, τ_0_1 where τ_0_0 : Hashable> (@in Optional<τ_0_1>, @in τ_0_0, @inout Dictionary<τ_0_0, τ_0_1>) -> ()
// CHECK-LABEL: } // end sil function '$S20access_marker_verify0A13OptionalArrayyySDySiSaySiGGF'

// --- Optional map.
enum OptionalWithMap<Wrapped> {
  case none

  case some(Wrapped)

  init(_ some: Wrapped) { self = .some(some) }

  func map<U>(
    _ transform: (Wrapped) throws -> U
  ) rethrows -> U? {
    switch self {
    case .some(let y):
      return .some(try transform(y))
    case .none:
      return .none
    }
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF : $@convention(method) <Wrapped><U> (@noescape @callee_guaranteed (@in_guaranteed Wrapped) -> (@out U, @error Error), @in_guaranteed OptionalWithMap<Wrapped>) -> (@out Optional<U>, @error Error) {
// CHECK: bb0(%0 : @trivial $*Optional<U>, %1 : @trivial $@noescape @callee_guaranteed (@in_guaranteed Wrapped) -> (@out U, @error Error), %2 : @trivial $*OptionalWithMap<Wrapped>):
// CHECK: [[STK:%.]] = alloc_stack $OptionalWithMap<Wrapped>
// CHECK-NOT: begin_access
// CHECK: copy_addr %2 to [initialization] [[STK]] : $*OptionalWithMap<Wrapped>
// CHECK: switch_enum_addr [[STK]] : $*OptionalWithMap<Wrapped>, case #OptionalWithMap.some!enumelt.1: [[BBSOME:bb.*]], case #OptionalWithMap.none!enumelt: bb
//
// CHECK: [[BBSOME]]:
// CHECK-NOT: begin_access
// CHECK: [[ADR:%.*]] = unchecked_take_enum_data_addr [[STK]]
// CHECK: alloc_stack $Wrapped, let, name "y"
// CHECK-NOT: begin_access
// CHECK: copy_addr [take] [[ADR]] to [initialization]
// ----- call transform.
// CHECK: try_apply
// CHECK-LABEL: } // end sil function '$S20access_marker_verify15OptionalWithMapO3mapyqd__Sgqd__xKXEKlF'

// --- delegating initializer.
struct DelegatingInit {
  var i: Int
  init(i: Int) {
    self.i = i
  }
  init() {
    self.init(i: 4)
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify14DelegatingInitV1iACSi_tcfC : $@convention(method) (Int, @thin DelegatingInit.Type) -> DelegatingInit {
// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $@thin DelegatingInit.Type):
// CHECK:   alloc_box ${ var DelegatingInit }, var, name "self"
// CHECK:   mark_uninitialized [rootself] %2 : ${ var DelegatingInit }
// CHECK:   [[BOX:%.*]] = project_box
// CHECK:   begin_access [modify] [unknown]
// CHECK:   struct_element_addr
// CHECK:   assign
// CHECK:   end_access
// CHECK-NOT: begin_access
// CHECK:   load [trivial] [[BOX]] : $*DelegatingInit
// CHECK:   destroy_value
// CHECK:   return %10 : $DelegatingInit
// CHECK-LABEL: } // end sil function '$S20access_marker_verify14DelegatingInitV1iACSi_tcfC'

// --- addressor.
func testAddressor(p: UnsafePointer<Int>) -> Int {
  return p.pointee
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify13testAddressor1pSiSPySiG_tF : $@convention(thin) (UnsafePointer<Int>) -> Int {
// CHECK: bb0(%0 : @trivial $UnsafePointer<Int>):
// CHECK:   apply
// CHECK:   struct_extract
// CHECK:   [[ADR:%.*]] = pointer_to_address
// CHECK:   [[ACCESS:%.*]] = begin_access [read] [unsafe] [[ADR]] : $*Int
// CHECK:   load [trivial] [[ACCESS]] : $*Int
// CHECK:   return
// CHECK-LABEL: } // end sil function '$S20access_marker_verify13testAddressor1pSiSPySiG_tF'

// --- shims.
func testShims() -> UInt32 {
  return _SwiftKeyPathBufferHeader_SizeMask
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify9testShimss6UInt32VyF : $@convention(thin) () -> UInt32 {
// CHECK: bb0:
// CHECK:   [[GA:%.*]] = global_addr @_SwiftKeyPathBufferHeader_SizeMask : $*UInt32
// CHECK-NOT: begin_access
// CHECK:   load [trivial] [[GA]] : $*UInt32
// CHECK:   return
// CHECK-LABEL: } // end sil function '$S20access_marker_verify9testShimss6UInt32VyF'

// --- global variable initialization.
var globalString1 = "⓪" // start non-empty
// CHECK-LABEL: sil private @globalinit_33_{{.*}}_func0 : $@convention(c) () -> () {
// CHECK: alloc_global @$S20access_marker_verify13globalString1SSvp
// CHECK: [[GA:%.*]] = global_addr @$S20access_marker_verify13globalString1SSvp : $*String
// CHECK: apply
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[GA]] : $*String
// CHECK: store %{{.*}} to [init] [[ACCESS]] : $*String
// CHECK: end_access
// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func0'

var globalString2 = globalString1
// CHECK-LABEL: sil private @globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1 : $@convention(c) () -> () {
// CHECK: alloc_global @$S20access_marker_verify13globalString2SSvp
// CHECK: [[GA:%.*]] = global_addr @$S20access_marker_verify13globalString2SSvp : $*String
// CHECK: apply
// CHECK: [[PTR:%.*]] = pointer_to_address
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[PTR]] : $*String
// CHECK: [[INIT:%.*]] = begin_access [modify] [unsafe] [[GA]] : $*String
// CHECK: copy_addr [[ACCESS]] to [initialization] [[INIT]] : $*String
// CHECK: end_access [[INIT]] : $*String
// CHECK: end_access [[ACCESS]] : $*String
// CHECK-NOT: end_access
// CHECK-LABEL: } // end sil function 'globalinit_33_180BF7B9126DB0C8C6C26F15ACD01908_func1'


// --- getter.
struct GenericStructWithGetter<T> {
  var t: T
  var val: Int

  struct Value {
    internal var val: Int
    
    internal init(_ val: Int) { self.val = val }
  }
  var value : Value {
    get { return Value(val) }
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify23GenericStructWithGetterV5valueAC5ValueVyx_Gvg : $@convention(method) <T> (@in_guaranteed GenericStructWithGetter<T>) -> GenericStructWithGetter<T>.Value {
// CHECK: bb0(%0 : @trivial $*GenericStructWithGetter<T>):
// CHECK:   [[ADR:%.*]] = struct_element_addr %0 : $*GenericStructWithGetter<T>, #GenericStructWithGetter.val
// CHECK-NOT: begin_access
// CHECK:   load [trivial] [[ADR]] : $*Int
// CHECK:   apply
// CHECK-LABEL: } // end sil function '$S20access_marker_verify23GenericStructWithGetterV5valueAC5ValueVyx_Gvg'

// --- setter.
struct StructWithSetter {
  var _val: Int

  internal var val: Int {
    get {
      return _val
    }
    set {
      _val = newValue
    }
  }

  mutating func inc(incVal: Int) {
    val += incVal
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify16StructWithSetterV3inc0G3ValySi_tF : $@convention(method) (Int, @inout StructWithSetter) -> () {
// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $*StructWithSetter):
// CHECK: [[FORMALACCESS:%.*]] = begin_access [modify] [unknown] %1
// CHECK: alloc_stack $Int
// CHECK: load [trivial] [[FORMALACCESS]] : $*StructWithSetter
// CHECK: [[GETTER:%.*]] = function_ref @$S20access_marker_verify16StructWithSetterV3valSivg
// CHECK: apply [[GETTER]]
// CHECK: begin_access [modify] [unsafe]
// CHECK: store %{{.*}} to [trivial]
// CHECK: end_access
// CHECK: begin_access [modify] [unsafe]
// CHECK: [[INC:%.*]] = function_ref @$SSi2peoiyySiz_SitFZ
// CHECK: apply [[INC]]
// CHECK: load [trivial] %13 : $*Int
// CHECK: [[SETTER:%.*]] = function_ref @$S20access_marker_verify16StructWithSetterV3valSivs
// CHECK: apply [[SETTER]]
// CHECK: end_access
// CHECK: end_access [[FORMALACCESS]]
// CHECK-LABEL: } // end sil function '$S20access_marker_verify16StructWithSetterV3inc0G3ValySi_tF'

// --- lazy inout.
func increment(_ x: inout Int) { x += 1 }

final class LazyFinalClassProperty {
  lazy var cat: Int = 5
}

func inoutWriteOfLazyFinalClassProperty(l: inout LazyFinalClassProperty) {
  increment(&l.cat)
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify34inoutWriteOfLazyFinalClassProperty1lyAA0ghiJ0Cz_tF : $@convention(thin) (@inout LazyFinalClassProperty) -> () {
// CHECK: bb0(%0 : @trivial $*LazyFinalClassProperty):
// CHECK:   [[FORMALACCESS:%.*]] = begin_access [read] [unknown] %0 : $*LazyFinalClassProperty
// CHECK:   load [copy] [[FORMALACCESS]] : $*LazyFinalClassProperty
// CHECK:   end_access [[FORMALACCESS]] : $*LazyFinalClassProperty
// CHECK:   // function_ref LazyFinalClassProperty.cat.getter
// CHECK:   [[GETTER:%.*]] = function_ref @$S20access_marker_verify22LazyFinalClassPropertyC3catSivg
// CHECK:   apply [[GETTER]]
// CHECK:   begin_access [modify] [unsafe]
// CHECK:   store %{{.*}} to [trivial]
// CHECK:   end_access
// CHECK:   [[TEMPACCESS:%.*]] = begin_access [modify] [unsafe] %5 : $*Int
// CHECK:   [[INC:%.*]] = function_ref @$S20access_marker_verify9incrementyySizF : $@convention(thin) (@inout Int) -> ()
// CHECK:   apply [[INC]]([[TEMPACCESS]]) : $@convention(thin) (@inout Int) -> ()
// CHECK:   load [trivial] [[TEMPACCESS]] : $*Int
// CHECK:   [[SETTER:%.*]] = function_ref @$S20access_marker_verify22LazyFinalClassPropertyC3catSivs
// CHECK:   apply [[SETTER]]
// CHECK:   end_access [[TEMPACCESS]] : $*Int
// CHECK-LABEL: } // end sil function '$S20access_marker_verify34inoutWriteOfLazyFinalClassProperty1lyAA0ghiJ0Cz_tF'

// --- lazy getter.
func inoutAccessOfLazyFinalClassProperty(
  l: inout LazyFinalClassProperty
) -> Int {
  return l.cat
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify35inoutAccessOfLazyFinalClassProperty1lSiAA0ghiJ0Cz_tF : $@convention(thin) (@inout LazyFinalClassProperty) -> Int {
// CHECK: bb0(%0 : @trivial $*LazyFinalClassProperty):
// CHECK:   begin_access [read] [unknown] %0
// CHECK:   load [copy]
// CHECK:   end_access
// CHECK:   [[GETTER:%.*]] = function_ref @$S20access_marker_verify22LazyFinalClassPropertyC3catSivg : $@convention(method) (@guaranteed LazyFinalClassProperty) -> Int
// CHECK:   apply [[GETTER]]
// CHECK-LABEL: } // end sil function '$S20access_marker_verify35inoutAccessOfLazyFinalClassProperty1lSiAA0ghiJ0Cz_tF'

// --- polymorphic getter
protocol Abstractable {
  associatedtype Result
  var storedFunction: () -> Result { get set }
}

class C : Abstractable {
  var storedFunction: () -> Int = { 0 }
}
// CHECK-LABEL: sil private [transparent] [thunk] @$S20access_marker_verify1CCAA12AbstractableA2aDP14storedFunction6ResultQzycvMTW : $@yield_once @convention(witness_method: Abstractable) (@inout C) -> @yields @inout @callee_guaranteed () -> @out Int
// CHECK:      bb0(%0 : @trivial $*C):
// CHECK-NEXT:   [[SELF:%.*]] = load_borrow %0 : $*C
// CHECK-NEXT:   [[MODIFY:%.*]] = class_method [[SELF]] : $C, #C.storedFunction!modify.1
// CHECK-NEXT:   ([[ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[MODIFY]]([[SELF]])
// CHECK-NEXT:   [[TEMP:%.*]] = alloc_stack $@callee_guaranteed () -> @out Int
// CHECK-NEXT:   [[OLD_FN:%.*]] = load [take] [[ADDR]]
// CHECK-NEXT:   // function_ref thunk
// CHECK-NEXT:   [[THUNK:%.*]] = function_ref @$SSiIegd_SiIegr_TR
// CHECK-NEXT:   [[THUNKED_OLD_FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[OLD_FN]])
// CHECK-NEXT:   store [[THUNKED_OLD_FN]] to [init] [[TEMP]] :
// CHECK-NEXT:   yield [[TEMP]] : $*@callee_guaranteed () -> @out Int, resume bb1, unwind bb2

// CHECK:      bb1:
// CHECK-NEXT:   [[NEW_FN:%.*]] = load [take] [[TEMP]]
// CHECK-NEXT:   // function_ref thunk
// CHECK-NEXT:   [[THUNK:%.*]] = function_ref @$SSiIegr_SiIegd_TR
// CHECK-NEXT:   [[THUNKED_NEW_FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[NEW_FN]])
// CHECK-NEXT:   store [[THUNKED_NEW_FN]] to [init] [[ADDR]] :
// CHECK-NEXT:   dealloc_stack [[TEMP]]
// CHECK-NEXT:   end_apply [[TOKEN]]
// CHECK-NEXT:   [[TUPLE:%.*]] = tuple ()
// CHECK-NEXT:   end_borrow [[SELF]] from %0 : $C
// CHECK-NEXT:   return [[TUPLE]]

// CHECK:      bb2:
// CHECK-NEXT:   [[NEW_FN:%.*]] = load [take] [[TEMP]]
// CHECK-NEXT:   // function_ref thunk
// CHECK-NEXT:   [[THUNK:%.*]] = function_ref @$SSiIegr_SiIegd_TR
// CHECK-NEXT:   [[THUNKED_NEW_FN:%.*]] = partial_apply [callee_guaranteed] [[THUNK]]([[NEW_FN]])
// CHECK-NEXT:   store [[THUNKED_NEW_FN]] to [init] [[ADDR]] :
// CHECK-NEXT:   dealloc_stack [[TEMP]]
// CHECK-NEXT:   abort_apply [[TOKEN]]
// CHECK-NEXT:   end_borrow [[SELF]] from %0 : $C
// CHECK-NEXT:   unwind

// --- writeback address-only.
var addressOnly: P {
  get {
    return StructP()
  }
  set {}
}

func takesInoutP(x: inout P) {}

func testWriteback() {
  takesInoutP(x: &addressOnly)
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify13testWritebackyyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK:   %0 = alloc_stack $P
// CHECK: [[GETTER:%.*]] = apply
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] %0 : $*P
// Call takesInoutP
// CHECK: apply %{{.*}}([[ACCESS]]) : $@convention(thin) (@inout P) -> ()
// Call addressOnly.setter
// CHECK: apply %{{.*}}([[ACCESS]]) : $@convention(thin) (@in P) -> ()
// CHECK: end_access [[ACCESS]] : $*P
// CHECK-LABEL: } // end sil function '$S20access_marker_verify13testWritebackyyF'

// --- writeback temp.
struct MutableStorage {
  mutating func push() {}
}

class Container {
  var storage: MutableStorage

  init() {
    storage = MutableStorage()
  }

  func testWritebackTemp() {
    self.storage.push()
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify9ContainerC17testWritebackTempyyF : $@convention(method) (@guaranteed Container) -> () {
// CHECK: bb0(%0 : @guaranteed $Container):
// call storage.materializeForSet
// CHECK: [[MODIFY:%.*]] = class_method %0 : $Container, #Container.storage!modify.1
// CHECK: begin_apply [[MODIFY]]
// call MutableStorage.push()
// CHECK: apply %{{.*}}(%{{.*}}) : $@convention(method) (@inout MutableStorage) -> ()
// CHECK: end_apply
// CHECK-LABEL: } // end sil function '$S20access_marker_verify9ContainerC17testWritebackTempyyF'

// --- return mixed tuple
protocol HasClassGetter {
  var c: BaseClass { get }
}
func testMixedTuple(p: HasClassGetter) -> (BaseClass, Any) {
  return (p.c, p.c)
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF : $@convention(thin) (@in_guaranteed HasClassGetter) -> (@owned BaseClass, @out Any) {
// CHECK: bb0(%0 : @trivial $*Any, %1 : @trivial $*HasClassGetter):
// CHECK: [[P1:%.*]] = open_existential_addr immutable_access %1 : $*HasClassGetter to $*@opened
// CHECK: [[TEMP1:%.*]] = alloc_stack $@opened
// CHECK-NOT: begin_access
// CHECK: copy_addr [[P1]] to [initialization] [[TEMP1]] : $*@opened
// CHECK-NOT: begin_access
// CHECK: [[OUTC:%.*]] = apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
// CHECK: [[P2:%.*]] = open_existential_addr immutable_access %1 : $*HasClassGetter to $*@opened
// CHECK: [[TEMP2:%.*]] = alloc_stack $@opened
// CHECK-NOT: begin_access
// CHECK: copy_addr [[P2]] to [initialization] [[TEMP2]] : $*@opened
// CHECK-NOT: begin_access
// CHECK: apply {{.*}} $@convention(witness_method: HasClassGetter) <τ_0_0 where τ_0_0 : HasClassGetter> (@in_guaranteed τ_0_0) -> @owned BaseClass
// CHECK: [[OUTANY:%.*]] = init_existential_addr %0 : $*Any, $BaseClass
// CHECK: store %{{.*}} to [init] [[OUTANY]] : $*BaseClass
// CHECK: return [[OUTC]] : $BaseClass
// CHECK-LABEL: } // end sil function '$S20access_marker_verify14testMixedTuple1pAA9BaseClassC_yptAA03HasH6Getter_p_tF'

// --- existential cast.
internal protocol CanCast {
  func unbox<T : Hashable>() -> T?
}

internal struct CanCastStruct<Base : Hashable> : CanCast {
  internal var base: Base

  internal func unbox<T : Hashable>() -> T? {
    return (self as CanCast as? CanCastStruct<T>)?.base
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify13CanCastStructV5unboxqd__SgySHRd__lF : $@convention(method) <Base where Base : Hashable><T where T : Hashable> (@in_guaranteed CanCastStruct<Base>) -> @out Optional<T> {
// CHECK: bb0(%0 : @trivial $*Optional<T>, %1 : @trivial $*CanCastStruct<Base>):
// CHECK: [[OUT_ENUM:%.*3]] = init_enum_data_addr %0 : $*Optional<T>, #Optional.some!enumelt.1
// CHECK: [[TEMP_SUB:%.*]] = alloc_stack $Optional<CanCastStruct<T>>
// CHECK: [[TEMP_BASE:%.*]] = alloc_stack $CanCast
// CHECK: [[TEMP_BASE_ADR:%.*]] = init_existential_addr [[TEMP_BASE]] : $*CanCast, $CanCastStruct<Base>
// CHECK-NOT: begin_access
// CHECK: copy_addr %1 to [initialization] [[TEMP_BASE_ADR]] : $*CanCastStruct<Base>
// CHECK-NOT: begin_access
// CHECK: [[TEMP_SUB_ADR:%.*]] = init_enum_data_addr [[TEMP_SUB]] : $*Optional<CanCastStruct<T>>, #Optional.some!enumelt.1
// CHECK-NOT: begin_access
// CHECK: checked_cast_addr_br take_always CanCast in [[TEMP_BASE]] : $*CanCast to CanCastStruct<T> in [[TEMP_SUB_ADR]] : $*CanCastStruct<T>
// CHECK-NOT: begin_access
// CHECK: [[TEMP_DATA:%.*]] = unchecked_take_enum_data_addr [[TEMP_SUB]] : $*Optional<CanCastStruct<T>>, #Optional.some!enumelt.1
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unsafe] [[TEMP_DATA]] : $*CanCastStruct<T>
// CHECK: [[BASE_ADR:%.*]] = struct_element_addr [[ACCESS]] : $*CanCastStruct<T>, #CanCastStruct.base
// CHECK-NOT: begin_access
// CHECK: copy_addr [[BASE_ADR]] to [initialization] [[OUT_ENUM]] : $*T
// CHECK: end_access [[ACCESS]] : $*CanCastStruct<T>
// CHECK-NOT: begin_access
// CHECK: inject_enum_addr %0 : $*Optional<T>, #Optional.some!enumelt.1
// CHECK-LABEL: } // end sil function '$S20access_marker_verify13CanCastStructV5unboxqd__SgySHRd__lF'

// --- open existential
protocol Q : PBar {}

func testOpenExistential(p: PBar) {
  let q0 = p as? Q
  if q0 != nil, let q = q0 {
    q.bar()
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify19testOpenExistential1pyAA4PBar_p_tF : $@convention(thin) (@in_guaranteed PBar) -> () {
// CHECK: bb0(%0 : @trivial $*PBar):
// CHECK: [[Q0:%.*]] = alloc_stack $Optional<Q>, let, name "q0"
// CHECK: [[PBAR:%.*]] = alloc_stack $PBar
// CHECK-NOT: begin_access
// CHECK: copy_addr %0 to [initialization] [[PBAR]] : $*PBar
// CHECK-NOT: begin_access
// CHECK: [[Q0_DATA:%.*]] = init_enum_data_addr [[Q0]] : $*Optional<Q>, #Optional.some!enumelt.1
// CHECK-NOT: begin_access
// CHECK: checked_cast_addr_br take_always PBar in [[PBAR]] : $*PBar to Q in [[Q0_DATA]] : $*Q, bb1, bb2
// CHECK-NOT: begin_access
// CHECK: inject_enum_addr [[Q0]] : $*Optional<Q>, #Optional.some!enumelt.1
// CHECK-NOT: begin_access
// CHECK: apply %{{.*}}<Q>([[Q0]], {{.*}}) : $@convention(method) <τ_0_0> (@in_guaranteed Optional<τ_0_0>, _OptionalNilComparisonType, @thin Optional<τ_0_0>.Type) -> Bool
// CHECK: [[Q:%.*]] = alloc_stack $Q, let, name "q"
// CHECK: [[OPT_Q:%.*]] = alloc_stack $Optional<Q>
// CHECK-NOT: begin_access
// CHECK: copy_addr [[Q0]] to [initialization] [[OPT_Q]] : $*Optional<Q>
// CHECK-NOT: begin_access
// CHECK: switch_enum_addr [[OPT_Q]] : $*Optional<Q>, case #Optional.some!enumelt.1: bb
// CHECK-NOT: begin_access
// CHECK: [[OPT_Q_ADR:%.*]] = unchecked_take_enum_data_addr [[OPT_Q]] : $*Optional<Q>, #Optional.some!enumelt.1
// CHECK-NOT: begin_access
// CHECK: copy_addr [take] [[OPT_Q_ADR]] to [initialization] [[Q]] : $*Q
// CHECK-NOT: begin_access
// CHECK: [[Q_ADR:%.*]] = open_existential_addr immutable_access [[Q]] : $*Q to $*@opened("{{.*}}") Q
// CHECK: witness_method $@opened("{{.*}}") Q, #PBar.bar!1
// CHECK: apply %{{.*}}<@opened("{{.*}}") Q>([[Q_ADR]])
// CHECK-LABEL: } // end sil function '$S20access_marker_verify19testOpenExistential1pyAA4PBar_p_tF'

// --- local existential
func getP() -> P {
  struct S : P {}
  return S()
}

func testLocalExistential() {
  var p = getP()
  takesClosure { p = getP() }
  _ = p
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify20testLocalExistentialyyF : $@convention(thin) () -> () {
// CHECK: alloc_box ${ var P }, var, name "p"
// CHECK: [[PROJ:%.*]] = project_box %{{.*}} : ${ var P }, 0
// CHECK-NOT: begin_access
// CHECK: apply %{{.*}}([[PROJ]]) : $@convention(thin) () -> @out P
// CHECK-NOT: begin_access
// CHECK: partial_apply [callee_guaranteed] %{{.*}}([[PROJ]]) : $@convention(thin) (@inout_aliasable P) -> ()
// CHECK-NOT: begin_access
// CHECK: apply
// CHECK: [[TMP:%.*]] = alloc_stack $P
// CHECK: [[UNINIT:%.*]] = mark_uninitialized [var] [[TMP]] : $*P
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[PROJ]] : $*P
// CHECK: [[COPY:%.*]] = alloc_stack $P
// CHECK-NOT: begin_access
// CHECK: copy_addr [[ACCESS]] to [initialization] [[COPY]] : $*P
// CHECK: end_access
// CHECK-NOT: begin_access
// CHECK: copy_addr [take] [[COPY]] to [[UNINIT]] : $*P
// CHECK-LABEL: } // end sil function '$S20access_marker_verify20testLocalExistentialyyF'

// --- address-only argument.
protocol UsesSelf {
  func bar(_: Self)
}

extension UsesSelf {
  static func testSelf(a: Self, b: Self) {
    a.bar(b)
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify8UsesSelfPAAE04testE01a1byx_xtFZ : $@convention(method) <Self where Self : UsesSelf> (@in_guaranteed Self, @in_guaranteed Self, @thick Self.Type) -> () {
// CHECK: bb0(%0 : @trivial $*Self, %1 : @trivial $*Self, %2 : @trivial $@thick Self.Type):
// CHECK: apply %{{.*}}<Self>(%1, %0) : $@convention(witness_method: UsesSelf) <τ_0_0 where τ_0_0 : UsesSelf> (@in_guaranteed τ_0_0, @in_guaranteed τ_0_0) -> ()
// CHECK-LABEL: } // end sil function '$S20access_marker_verify8UsesSelfPAAE04testE01a1byx_xtFZ'

// --- autoclosure
struct StructWithLayout {
  internal init() {
    assert(MemoryLayout.size(ofValue: self) >= 0)
  }
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify16StructWithLayoutVACycfC : $@convention(method) (@thin StructWithLayout.Type) -> StructWithLayout {
// CHECK: bb0(%0 : @trivial $@thin StructWithLayout.Type):
// CHECK: alloc_box ${ var StructWithLayout }, var, name "self"
// CHECK: mark_uninitialized [rootself] %{{.*}} : ${ var StructWithLayout }
// CHECK: [[PROJ:%.*]] = project_box %{{.*}} : ${ var StructWithLayout }, 0
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] %{{.*}}([[PROJ]]) : $@convention(thin) (@inout_aliasable StructWithLayout) -> Bool
// CHECK: [[CLOSURE:%.*]] = convert_escape_to_noescape [not_guaranteed] [[PA]] : $@callee_guaranteed () -> Bool to $@noescape @callee_guaranteed () -> Bool
// call StaticString.init
// CHECK: apply
// call UInt.init(_builtinIntegerLiteral:)
// CHECK: apply
// call default argument
// call _sanityCheck(_:_:file:line:)
// CHECK: apply %{{.*}}([[CLOSURE]], {{.*}})
// CHECK: load [trivial] [[PROJ]] : $*StructWithLayout
// CHECK-LABEL: } // end sil function '$S20access_marker_verify16StructWithLayoutVACycfC'

// --- pointer_to_address
// Verification should ignore this case.
func testPointerInit(x: Int, y: UnsafeMutablePointer<Int>) {
  y.pointee = x
}
// CHECK-LABEL: sil hidden @$S20access_marker_verify15testPointerInit1x1yySi_SpySiGtF : $@convention(thin) (Int, UnsafeMutablePointer<Int>) -> () {
// CHECK: bb0(%0 : @trivial $Int, %1 : @trivial $UnsafeMutablePointer<Int>):
// call addressor
// CHECK: [[POINTEE:%.*]] = apply %{{.*}}<Int>(%1) : $@convention(method) <τ_0_0> (UnsafeMutablePointer<τ_0_0>) -> UnsafeMutablePointer<τ_0_0>
// CHECK: [[RAWPTR:%.*]] = struct_extract [[POINTEE]] : $UnsafeMutablePointer<Int>, #UnsafeMutablePointer._rawValue
// CHECK: [[ADR:%.*]] = pointer_to_address [[RAWPTR]] : $Builtin.RawPointer to [strict] $*Int
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unsafe] [[ADR]] : $*Int
// CHECK: assign %0 to [[ACCESS]] : $*Int
// CHECK-LABEL: } // end sil function '$S20access_marker_verify15testPointerInit1x1yySi_SpySiGtF'

// Verification should ignore the address operand of init_existential_addr.
class testInitExistentialGlobal {
  static var testProperty: P = StructP()
}
// CHECK-LABEL: sil private @globalinit{{.*}} : $@convention(c) () -> () {
// CHECK:   alloc_global @$S20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ
// CHECK:   [[GADR:%.*]] = global_addr @$S20access_marker_verify25testInitExistentialGlobalC0D8PropertyAA1P_pvpZ : $*P
// CHECK:   %{{.*}} = apply %{{.*}}({{.*}}) : $@convention(method) (@thin StructP.Type) -> StructP
// CHECK:   [[EADR:%.*]] = init_existential_addr [[GADR]] : $*P, $StructP
// CHECK:   store %{{.*}} to [trivial] [[EADR]] : $*StructP
// CHECK-LABEL: } // end sil function 'globalinit

public enum SomeError: Swift.Error {
    case error
}

// Verification should ignore addresses produced by project_existential_box.
public func testInitBox() throws {
    throw SomeError.error
}
// CHECK-LABEL: sil @$S20access_marker_verify11testInitBoxyyKF : $@convention(thin) () -> @error Error {
// CHECK: [[BOXALLOC:%.*]] = alloc_existential_box $Error, $SomeError
// CHECK: [[PROJ:%.*]] = project_existential_box $SomeError in [[BOXALLOC]] : $Error
// CHECK: store [[BOXALLOC]] to [init] [[BOXBUF:%.*]] :
// CHECK: store %{{.*}} to [trivial] [[PROJ]] : $*SomeError
// CHECK: [[BOXALLOC2:%.*]] = load [take] [[BOXBUF]]
// CHECK: throw [[BOXALLOC2]] : $Error
// CHECK-LABEL: } // end sil function '$S20access_marker_verify11testInitBoxyyKF'

public final class HasStaticProp {
  public static let empty: HasStaticProp = HasStaticProp()
}

// A global addressor produces an unenforced RawPointer. This looke
// like an Unidentified access with no access marker. Ensure that
// verification doesn't assert.
public func getStaticProp() -> HasStaticProp {
  return .empty
}

// CHECK-LABEL: sil @$S20access_marker_verify13getStaticPropAA03HaseF0CyF : $@convention(thin) () -> @owned HasStaticProp {
// function_ref HasStaticProp.empty.unsafeMutableAddressor
// CHECK: [[F:%.*]] = function_ref @$S20access_marker_verify13HasStaticPropC5emptyACvau : $@convention(thin) () -> Builtin.RawPointer
// CHECK: [[RP:%.*]] = apply [[F]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK: [[ADR:%.*]] = pointer_to_address [[RP]] : $Builtin.RawPointer to [strict] $*HasStaticProp
// CHECK: load [copy] [[ADR]] : $*HasStaticProp
// CHECK-LABEL: } // end sil function '$S20access_marker_verify13getStaticPropAA03HaseF0CyF'
