
// RUN: %target-swift-emit-silgen -module-name modify %s | %FileCheck %s

class Base {
  var stored: Int = 0

// CHECK-LABEL: sil hidden [transparent] @$s6modify4BaseC6storedSivM : $@yield_once @convention(method) (@guaranteed Base) -> @yields @inout Int {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $Base):
// CHECK:   [[T0:%.*]] = ref_element_addr [[SELF]] : $Base, #Base.stored
// CHECK:   [[T1:%.*]] = begin_access [modify] [dynamic] [[T0]]
// CHECK:   yield [[T1]] : $*Int
// CHECK:   end_access [[T1]]
// CHECK:   return {{%.*}} : $()
// CHECK: }

// CHECK-LABEL: sil hidden [transparent] @$s6modify4BaseC8computedSivM : $@yield_once @convention(method) (@guaranteed Base) -> @yields @inout Int {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $Base):
// CHECK:   [[ADDR:%.*]] = alloc_stack $Int
// CHECK:   [[T0:%.*]] = function_ref @$s6modify4BaseC8computedSivg
// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
// CHECK:   store [[T1]] to [trivial] [[ADDR]] : $*Int
// CHECK:   yield [[ADDR]] : $*Int
// CHECK:   [[T2:%.*]] = load [trivial] [[ADDR]] : $*Int
// CHECK:   [[SETTER:%.*]] = function_ref @$s6modify4BaseC8computedSivs
// CHECK:   apply [[SETTER]]([[T2]], [[SELF]])
// CHECK:   return {{%.*}} : $()
// CHECK: }

  var computed: Int {
    get { return 0 }
    set(value) {}
  }

  var storedFunction: () -> Int = { 0 }
  final var finalStoredFunction: () -> Int = { 0 }
  var computedFunction: () -> Int {
    get { return {0} }
    set {}
  }
  static var staticFunction: () -> Int {
    get { return {0} }
    set {}
  }
}

class Derived : Base {}

protocol Abstractable {
  associatedtype Result
  var storedFunction: () -> Result { get set }
  var finalStoredFunction: () -> Result { get set }
  var computedFunction: () -> Result { get set }
  static var staticFunction: () -> Result { get set }
}

// Validate that we thunk materializeForSet correctly when there's
// an abstraction pattern present.

extension Derived : Abstractable {}

// CHECK-LABEL: sil private [transparent] [thunk] @$s6modify7DerivedCAA12AbstractableA2aDP14storedFunction6ResultQzycvMTW
// CHECK: bb0(%0 : @trivial $*Derived):
// CHECK-NEXT: [[T0:%.*]] = load_borrow %0 : $*Derived
// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
// CHECK-NEXT: [[FN:%.*]] = class_method [[SELF]] : $Base, #Base.storedFunction!modify.1
// CHECK-NEXT: ([[SUPER_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]])
// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed () -> @out Int
// CHECK-NEXT: [[SUPER_FN:%.*]] = load [take] [[SUPER_ADDR]]
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[SUPER_FN]])
// CHECK-NEXT: store [[T1]] to [init] [[SUB_ADDR]]
// CHECK-NEXT: yield [[SUB_ADDR]] : $*@callee_guaranteed () -> @out Int, resume bb1, unwind bb2
// CHECK:    bb1:
// CHECK-NEXT: [[SUB_FN:%.*]] = load [take] [[SUB_ADDR]]
// CHECK-NEXT: function_ref
// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[SUB_FN]])
// CHECK-NEXT: store [[T1]] to [init] [[SUPER_ADDR]]
// CHECK-NEXT: dealloc_stack [[SUB_ADDR]]
// CHECK-NEXT: end_apply [[TOKEN]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: end_borrow [[T0]]
// CHECK-NEXT: return

// CHECK-LABEL: sil private [transparent] [thunk] @$s6modify7DerivedCAA12AbstractableA2aDP19finalStoredFunction6ResultQzycvMTW
// CHECK: bb0(%0 : @trivial $*Derived):
// CHECK-NEXT: [[T0:%.*]] = load_borrow %0 : $*Derived
// CHECK-NEXT: [[SELF:%.*]] = upcast [[T0]] : $Derived to $Base
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[FN:%.*]] = function_ref @$s6modify4BaseC19finalStoredFunctionSiycvM
// CHECK-NEXT: ([[SUPER_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]])
// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed () -> @out Int
// CHECK-NEXT: [[SUPER_FN:%.*]] = load [take] [[SUPER_ADDR]]
// CHECK-NEXT: function_ref
// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[SUPER_FN]])
// CHECK-NEXT: store [[T1]] to [init] [[SUB_ADDR]]
// CHECK-NEXT: yield [[SUB_ADDR]] : $*@callee_guaranteed () -> @out Int, resume bb1, unwind bb2
// CHECK:    bb1:
// CHECK-NEXT: [[SUB_FN:%.*]] = load [take] [[SUB_ADDR]]
// CHECK-NEXT: function_ref
// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[SUB_FN]])
// CHECK-NEXT: store [[T1]] to [init] [[SUPER_ADDR]]
// CHECK-NEXT: dealloc_stack [[SUB_ADDR]]
// CHECK-NEXT: end_apply [[TOKEN]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: end_borrow [[T0]]
// CHECK-NEXT: return

// CHECK-LABEL: sil private [transparent] [thunk] @$s6modify7DerivedCAA12AbstractableA2aDP14staticFunction6ResultQzycvMZTW
// CHECK: bb0(%0 : @trivial $@thick Derived.Type):
// CHECK-NEXT: [[SELF:%.*]] = upcast %0 : $@thick Derived.Type to $@thick Base.Type
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[FN:%.*]] = function_ref @$s6modify4BaseC14staticFunctionSiycvMZ
// CHECK-NEXT: ([[SUPER_ADDR:%.*]], [[TOKEN:%.*]]) = begin_apply [[FN]]([[SELF]])
// CHECK-NEXT: [[SUB_ADDR:%.*]] = alloc_stack $@callee_guaranteed () -> @out Int
// CHECK-NEXT: [[SUPER_FN:%.*]] = load [take] [[SUPER_ADDR]]
// CHECK-NEXT: function_ref
// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegd_SiIegr_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> Int) -> @out Int
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[SUPER_FN]])
// CHECK-NEXT: store [[T1]] to [init] [[SUB_ADDR]]
// CHECK-NEXT: yield [[SUB_ADDR]] : $*@callee_guaranteed () -> @out Int, resume bb1, unwind bb2
// CHECK:    bb1:
// CHECK-NEXT: [[SUB_FN:%.*]] = load [take] [[SUB_ADDR]]
// CHECK-NEXT: function_ref
// CHECK-NEXT: [[REABSTRACTOR:%.*]] = function_ref @$sSiIegr_SiIegd_TR : $@convention(thin) (@guaranteed @callee_guaranteed () -> @out Int) -> Int
// CHECK-NEXT: [[T1:%.*]] = partial_apply [callee_guaranteed] [[REABSTRACTOR]]([[SUB_FN]])
// CHECK-NEXT: store [[T1]] to [init] [[SUPER_ADDR]]
// CHECK-NEXT: dealloc_stack [[SUB_ADDR]]
// CHECK-NEXT: end_apply [[TOKEN]]
// CHECK-NEXT: tuple ()
// CHECK-NEXT: return

protocol ClassAbstractable : class {
  associatedtype Result
  var storedFunction: () -> Result { get set }
  var finalStoredFunction: () -> Result { get set }
  var computedFunction: () -> Result { get set }
  static var staticFunction: () -> Result { get set }
}

extension Derived : ClassAbstractable {}

protocol Signatures {
  associatedtype Result
  var computedFunction: () -> Result { get set }
}
protocol Implementations {}
extension Implementations {
  var computedFunction: () -> Int {
    get { return {0} }
    set {}
  }
}

class ImplementingClass : Implementations, Signatures {}
struct ImplementingStruct : Implementations, Signatures {
  var ref: ImplementingClass?
}

class HasDidSet : Base {
  override var stored: Int {
    didSet {}
  }

// CHECK-LABEL: sil hidden [transparent] @$s6modify9HasDidSetC6storedSivM : $@yield_once @convention(method) (@guaranteed HasDidSet) -> @yields @inout Int {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $HasDidSet):
// CHECK:   [[ADDR:%.*]] = alloc_stack $Int
// CHECK:   [[T0:%.*]] = function_ref @$s6modify9HasDidSetC6storedSivg
// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
// CHECK:   store [[T1]] to [trivial] [[ADDR]] : $*Int
// CHECK:   yield [[ADDR]]
// CHECK:   [[T2:%.*]] = load [trivial] [[ADDR]]
// CHECK:   [[T3:%.*]] = function_ref @$s6modify9HasDidSetC6storedSivs
// CHECK:   apply [[T3]]([[T2]], [[SELF]])
// CHECK:   dealloc_stack [[ADDR]]
// CHECK:   return {{%.*}} : $()
// CHECK: }

  override var computed: Int {
    get { return 0 }
    set(value) {}
  }

// CHECK-LABEL: sil hidden [transparent] @$s6modify9HasDidSetC8computedSivM : $@yield_once @convention(method) (@guaranteed HasDidSet) -> @yields @inout Int {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $HasDidSet):
// CHECK:   [[ADDR:%.*]] = alloc_stack $Int
// CHECK:   [[T0:%.*]] = function_ref @$s6modify9HasDidSetC8computedSivg
// CHECK:   [[T1:%.*]] = apply [[T0]]([[SELF]])
// CHECK:   store [[T1]] to [trivial] [[ADDR]] : $*Int
// CHECK:   yield [[ADDR]]
// CHECK:   [[T2:%.*]] = load [trivial] [[ADDR]]
// CHECK:   [[T3:%.*]] = function_ref @$s6modify9HasDidSetC8computedSivs
// CHECK:   apply [[T3]]([[T2]], [[SELF]])
// CHECK:   dealloc_stack [[ADDR]]
// CHECK:   return {{%.*}} : $()
// CHECK: }
}

class HasStoredDidSet {
  var stored: Int = 0 {
    didSet {}
  }

// CHECK-LABEL: sil hidden [transparent] @$s6modify15HasStoredDidSetC6storedSivM : $@yield_once @convention(method) (@guaranteed HasStoredDidSet) -> @yields @inout Int {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $HasStoredDidSet):
// CHECK:   [[ADDR:%.*]] = alloc_stack $Int
// CHECK:   [[T0:%.*]] = ref_element_addr [[SELF]] : $HasStoredDidSet, #HasStoredDidSet.stored
// CHECK:   [[T1:%.*]] = begin_access [read] [dynamic] [[T0]] : $*Int
// CHECK:   [[T2:%.*]] = load [trivial] [[T1]]
// CHECK:   end_access [[T1]] : $*Int
// CHECK:   store [[T2]] to [trivial] [[ADDR]]
// CHECK:   yield [[ADDR]]
// CHECK:   [[T0:%.*]] = load [trivial] [[ADDR]]
// CHECK:   [[SETTER:%.*]] = function_ref @$s6modify15HasStoredDidSetC6storedSivs
// CHECK:   apply [[SETTER]]([[T0]], [[SELF]])
// CHECK:   dealloc_stack [[ADDR]]
// CHECK:   return {{%.*}} : $()
// CHECK: }
}

class HasWeak {
  weak var weakvar: HasWeak?
}
// CHECK-LABEL: sil hidden [transparent] @$s6modify7HasWeakC7weakvarACSgXwvM : $@yield_once @convention(method) (@guaranteed HasWeak) -> @yields @inout Optional<HasWeak> {
// CHECK: bb0([[SELF:%.*]] : @guaranteed $HasWeak):
// CHECK:   [[PROP:%.*]] = ref_element_addr [[SELF]] : $HasWeak, #HasWeak.weakvar
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[PROP]] : $*@sil_weak Optional<HasWeak>
// CHECK:   [[ADDR:%.*]] = alloc_stack $Optional<HasWeak>
// CHECK:   [[T0:%.*]] = load_weak [[ACCESS]]
// CHECK:   store [[T0]] to [init] [[ADDR]]
// CHECK:   yield [[ADDR]]
// CHECK:   [[T0:%.*]] = load [take] [[ADDR]]
// CHECK:   store_weak [[T0]] to [[ACCESS]]
// CHECK:   destroy_value [[T0]]
// CHECK:   end_access [[ACCESS]]
// CHECK:   dealloc_stack [[ADDR]]
// CHECK:   return {{%.*}} : $()
// CHECK: }

// rdar://22109071
// Test that we don't use modify from a protocol extension.
protocol Magic {}
extension Magic {
  var hocus: Int {
    get { return 0 }
    set {}
  }
}
struct Wizard : Magic {}
func improve(_ x: inout Int) {}
func improveWizard(_ wizard: inout Wizard) {
  improve(&wizard.hocus)
}
// CHECK-LABEL: sil hidden @$s6modify13improveWizardyyAA0C0VzF
// CHECK:       [[WRITE:%.*]] = begin_access [modify] [unknown] %0 : $*Wizard
// CHECK-NEXT:  [[TEMP:%.*]] = alloc_stack $Int
//   Call the getter and materialize the result in the temporary.
// CHECK-NEXT:  [[T0:%.*]] = load [trivial] [[WRITE:.*]] : $*Wizard
// CHECK:       [[WTEMP:%.*]] = alloc_stack $Wizard
// CHECK-NEXT:  store [[T0]] to [trivial] [[WTEMP]]
// CHECK:       [[GETTER:%.*]] = function_ref @$s6modify5MagicPAAE5hocusSivg
// CHECK-NEXT:  [[T0:%.*]] = apply [[GETTER]]<Wizard>([[WTEMP]])
// CHECK-NEXT:  dealloc_stack [[WTEMP]]
// CHECK-NEXT:  store [[T0]] to [trivial] [[TEMP]]
//   Call improve.
// CHECK:       [[IMPROVE:%.*]] = function_ref @$s6modify7improveyySizF :
// CHECK-NEXT:  apply [[IMPROVE]]([[TEMP]])
// CHECK-NEXT:  [[T0:%.*]] = load [trivial] [[TEMP]]
// CHECK:       [[SETTER:%.*]] = function_ref @$s6modify5MagicPAAE5hocusSivs
// CHECK-NEXT:  apply [[SETTER]]<Wizard>([[T0]], [[WRITE]])
// CHECK-NEXT:  end_access [[WRITE]] : $*Wizard
// CHECK-NEXT:  dealloc_stack [[TEMP]]

protocol Totalled {
  var total: Int { get set }
}

struct Bill : Totalled {
  var total: Int
}

// CHECK-LABEL: sil hidden [transparent] @$s6modify4BillV5totalSivM : $@yield_once @convention(method) (@inout Bill) -> @yields @inout Int {
// CHECK: bb0([[SELF:%.*]] : @trivial $*Bill):
// CHECK:   [[ACCESS:%.*]] = begin_access [modify] [unknown] [[SELF]]
// CHECK:   [[T0:%.*]] = struct_element_addr [[ACCESS]] : $*Bill, #Bill.total
// CHECK:   yield [[T0]]
// CHECK:   end_access [[ACCESS]]
// CHECK: }

// CHECK-LABEL:  sil private [transparent] [thunk] @$s6modify4BillVAA8TotalledA2aDP5totalSivMTW : $@yield_once @convention(witness_method: Totalled) (@inout Bill) -> @yields @inout Int {
// CHECK:        bb0([[SELF:%.*]] : @trivial $*Bill):
// CHECK:          [[T0:%.*]] = function_ref @$s6modify4BillV5totalSivM
// CHECK-NEXT:     ([[T1:%.*]], [[TOKEN:%.*]]) = begin_apply [[T0]]([[SELF]])
// CHECK-NEXT:     yield [[T1]] : $*Int, resume bb1, unwind bb2
// CHECK:        bb1:
// CHECK-NEXT:     end_apply [[TOKEN]]
// CHECK-NEXT:     [[T1:%.*]] = tuple ()
// CHECK-NEXT:     return [[T1]] :

protocol AddressOnlySubscript {
  associatedtype Index
  subscript(i: Index) -> Index { get set }
}

struct Foo<T>: AddressOnlySubscript {
  subscript(i: T) -> T {
    get { return i }
    set { print("\(i) = \(newValue)") }
  }
}

func increment(_ x: inout Int) { x += 1 }

// Generic subscripts.

protocol GenericSubscriptProtocol {
  subscript<T>(_: T) -> T { get set }
}

struct GenericSubscriptWitness : GenericSubscriptProtocol {
  subscript<T>(_: T) -> T { get { } set { } }
}

// CHECK-LABEL: sil hidden [transparent] @$s6modify23GenericSubscriptWitnessVyxxcluiM
// CHECK:         function_ref @$s6modify23GenericSubscriptWitnessVyxxcluig
// CHECK:         function_ref @$s6modify23GenericSubscriptWitnessVyxxcluis

extension GenericSubscriptProtocol {
  subscript<T>(t: T) -> T { get { } set { } }
}

struct GenericSubscriptDefaultWitness : GenericSubscriptProtocol { }

// Make sure we correctly infer the 'T : Magic' requirement on all the accessors
// of the subscript.

struct GenericTypeWithRequirement<T : Magic> {}

protocol InferredRequirementOnSubscriptProtocol {
  subscript<T>(i: Int) -> GenericTypeWithRequirement<T> { get set }
}

struct InferredRequirementOnSubscript : InferredRequirementOnSubscriptProtocol {
  subscript<T>(i: Int) -> GenericTypeWithRequirement<T> {
    get { }
    set { }
  }
}

// CHECK-LABEL: sil hidden @$s6modify30InferredRequirementOnSubscriptVyAA015GenericTypeWithC0VyxGSicAA5MagicRzluig : $@convention(method) <T where T : Magic> (Int, InferredRequirementOnSubscript) -> GenericTypeWithRequirement<T>

// CHECK-LABEL: sil hidden @$s6modify30InferredRequirementOnSubscriptVyAA015GenericTypeWithC0VyxGSicAA5MagicRzluis : $@convention(method) <T where T : Magic> (GenericTypeWithRequirement<T>, Int, @inout InferredRequirementOnSubscript) -> ()

// CHECK-LABEL: sil hidden [transparent] @$s6modify30InferredRequirementOnSubscriptVyAA015GenericTypeWithC0VyxGSicAA5MagicRzluiM : $@yield_once @convention(method) <T where T : Magic> (Int, @inout InferredRequirementOnSubscript) -> @yields @inout GenericTypeWithRequirement<T>

// Test for materializeForSet vs static properties of structs.

protocol Beverage {
  static var abv: Int { get set }
}

struct Beer : Beverage {
  static var abv: Int {
    get {
      return 7
    }
    set { }
  }
}

struct Wine<Color> : Beverage {
  static var abv: Int {
    get {
      return 14
    }
    set { }
  }
}

// Make sure we can perform an inout access of such a property too.

func inoutAccessOfStaticProperty<T : Beverage>(_ t: T.Type) {
  increment(&t.abv)
}

// Test for materializeForSet vs overridden computed property of classes.
class BaseForOverride {
  var valueStored: Int
  var valueComputed: Int { get { } set { } }

  init(valueStored: Int) {
    self.valueStored = valueStored
  }
}

class DerivedForOverride : BaseForOverride {
  override var valueStored: Int { get { } set { } }
  override var valueComputed: Int { get { } set { } }
}

// Test for materializeForSet vs static properties of classes.

class ReferenceBeer {
  class var abv: Int {
    get {
      return 7
    }
    set { }
  }
}

func inoutAccessOfClassProperty() {
  increment(&ReferenceBeer.abv)
}

// Test for materializeForSet when Self is re-abstracted.
//
// We have to open-code the materializeForSelf witness, and not screw up
// the re-abstraction.

protocol Panda {
  var x: (Self) -> Self { get set }
}

func id<T>(_ t: T) -> T { return t }

extension Panda {
  var x: (Self) -> Self {
    get { return id }
    set { }
  }
}

struct TuxedoPanda : Panda { }


// CHECK-LABEL: sil private [transparent] [thunk] @$s6modify11TuxedoPandaVAA0C0A2aDP1xyxxcvMTW

// CHECK: [[T0:%.*]] = function_ref @$s6modify5PandaPAAE1xyxxcvM
// CHECK: ([[T1:%.*]], [[TOKEN:%.*]]) = begin_apply [[T0]]<TuxedoPanda>(%0)
// CHECK: yield [[T1]]
// CHECK: end_apply [[TOKEN]]
// CHECK: }


// Test for materializeForSet vs lazy properties of structs.

struct LazyStructProperty {
  lazy var cat: Int = 5
}

// CHECK-LABEL: sil hidden @$s6modify31inoutAccessOfLazyStructProperty1lyAA0efG0Vz_tF
// CHECK:   function_ref @$s6modify18LazyStructPropertyV3catSivg
// CHECK:   function_ref @$s6modify18LazyStructPropertyV3catSivs
func inoutAccessOfLazyStructProperty(l: inout LazyStructProperty) {
  increment(&l.cat)
}

// Test for materializeForSet vs lazy properties of classes.

// CHECK-LABEL: sil hidden [transparent] @$s6modify17LazyClassPropertyC3catSivM

class LazyClassProperty {
  lazy var cat: Int = 5
}

// CHECK-LABEL: sil hidden @$s6modify30inoutAccessOfLazyClassProperty1lyAA0efG0Cz_tF
// CHECK:    class_method {{.*}} : $LazyClassProperty, #LazyClassProperty.cat!modify.1
func inoutAccessOfLazyClassProperty(l: inout LazyClassProperty) {
  increment(&l.cat)
}

// Test for materializeForSet vs lazy properties of final classes.

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

// CHECK-LABEL: sil hidden @$s6modify35inoutAccessOfLazyFinalClassProperty1lyAA0efgH0Cz_tF
// CHECK:    function_ref @$s6modify22LazyFinalClassPropertyC3catSivg
// CHECK:    function_ref @$s6modify22LazyFinalClassPropertyC3catSivs
func inoutAccessOfLazyFinalClassProperty(l: inout LazyFinalClassProperty) {
  increment(&l.cat)
}

// Make sure the below doesn't crash SILGen
struct FooClosure {
 var computed: (((Int) -> Int) -> Int)? {
   get { return stored }
   set {}
 }
 var stored: (((Int) -> Int) -> Int)? = nil
}

// CHECK-LABEL: $s6modify22testMaterializedSetteryyF
func testMaterializedSetter() {
  // CHECK: function_ref @$s6modify10FooClosureVACycfC
  var f = FooClosure()
  // CHECK: function_ref @$s6modify10FooClosureV8computedS3iXEcSgvg
  // CHECK: function_ref @$s6modify10FooClosureV8computedS3iXEcSgvs
  f.computed = f.computed
}

// Odd corner case -- mutating getter, non-mutating setter
protocol BackwardMutationProtocol {
  var value: Int {
    mutating get
    nonmutating set
  }
}

struct BackwardMutation : BackwardMutationProtocol {
  var value: Int {
    mutating get { return 0 }
    nonmutating set { }
  }
}

func doBackwardMutation(m: inout BackwardMutationProtocol) {
  m.value += 1
}

// materializeForSet for a constrained-extension protocol witness requires
// open coding.

protocol ConditionalSubscript {
  subscript(_: Int) -> Self { get set }
}

struct HasConditionalSubscript<T> {}

extension HasConditionalSubscript: ConditionalSubscript where T: ConditionalSubscript {
  subscript(_: Int) -> HasConditionalSubscript<T> {
    get { return self }
    set { }
  }
}

// CHECK-LABEL: sil hidden [transparent] @$s6modify23HasConditionalSubscriptVA2A0cD0RzlEyACyxGSiciM
// CHECK:         function_ref @$s6modify23HasConditionalSubscriptVA2A0cD0RzlEyACyxGSicig

// CHECK-LABEL: sil_vtable DerivedForOverride {
// CHECK:   #BaseForOverride.valueStored!getter.1: (BaseForOverride) -> () -> Int : @$s6modify18DerivedForOverrideC11valueStoredSivg
// CHECK:   #BaseForOverride.valueStored!setter.1: (BaseForOverride) -> (Int) -> () : @$s6modify18DerivedForOverrideC11valueStoredSivs
// CHECK:   #BaseForOverride.valueStored!modify.1: (BaseForOverride) -> () -> () : @$s6modify18DerivedForOverrideC11valueStoredSivM
// CHECK:   #BaseForOverride.valueComputed!getter.1: (BaseForOverride) -> () -> Int : @$s6modify18DerivedForOverrideC13valueComputedSivg
// CHECK:   #BaseForOverride.valueComputed!setter.1: (BaseForOverride) -> (Int) -> () : @$s6modify18DerivedForOverrideC13valueComputedSivs
// CHECK:   #BaseForOverride.valueComputed!modify.1: (BaseForOverride) -> () -> () : @$s6modify18DerivedForOverrideC13valueComputedSivM
// CHECK: }

// CHECK-LABEL: sil_witness_table hidden Bill: Totalled module modify {
// CHECK:   method #Totalled.total!getter.1: {{.*}} : @$s6modify4BillVAA8TotalledA2aDP5totalSivgTW
// CHECK:   method #Totalled.total!setter.1: {{.*}} : @$s6modify4BillVAA8TotalledA2aDP5totalSivsTW
// CHECK:   method #Totalled.total!modify.1: {{.*}} : @$s6modify4BillVAA8TotalledA2aDP5totalSivMTW
// CHECK: }
