blob: 6b6c6d4503fa1a1f267a78a6a055825ebdf17cda [file] [log] [blame]
// RUN: %target-swift-emit-silgen -Xllvm -sil-full-demangle -parse-as-library -disable-objc-attr-requires-foundation-module -enable-objc-interop %s | %FileCheck %s
var zero: Int = 0
func use(_: Int) {}
func takeInt(_ a : Int) {}
public struct DidSetWillSetTests {
// CHECK-LABEL: sil [ossa] @$s9observers010DidSetWillC5TestsV{{[_0-9a-zA-Z]*}}fC
public init(x : Int) {
// Accesses to didset/willset variables are direct in init methods and dtors.
a = x
a = x
// CHECK: bb0(%0 : $Int, %1 : $@thin DidSetWillSetTests.Type):
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself]
// CHECK: [[PB_SELF:%.*]] = project_box [[SELF]]
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_SELF]]
// CHECK: [[P1:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign %0 to [[P1]]
// CHECK: [[WRITE:%.*]] = begin_access [modify] [unknown] [[PB_SELF]]
// CHECK: [[P2:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign %0 to [[P2]]
}
public var a: Int {
// CHECK-LABEL: sil private [ossa] @$s9observers010DidSetWillC5TestsV1a{{[_0-9a-zA-Z]*}}vw
willSet(newA) {
// CHECK: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
// CHECK-NEXT: debug_value %0
// CHECK-NEXT: debug_value_addr %1 : $*DidSetWillSetTests
takeInt(a)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] %1
// CHECK-NEXT: [[FIELDPTR:%.*]] = struct_element_addr [[READ]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: [[A:%.*]] = load [trivial] [[FIELDPTR]] : $*Int
// CHECK-NEXT: end_access [[READ]]
// CHECK: [[TAKEINTFN:%.*]] = function_ref @$s9observers7takeInt{{[_0-9a-zA-Z]*}}F
// CHECK-NEXT: apply [[TAKEINTFN]]([[A]]) : $@convention(thin) (Int) -> ()
takeInt(newA)
// CHECK-NEXT: // function_ref observers.takeInt(Swift.Int) -> ()
// CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @$s9observers7takeInt{{[_0-9a-zA-Z]*}}F
// CHECK-NEXT: apply [[TAKEINTFN]](%0) : $@convention(thin) (Int) -> ()
a = zero // reassign, but don't infinite loop.
// CHECK-NEXT: // function_ref observers.zero.unsafeMutableAddressor : Swift.Int
// CHECK-NEXT: [[ZEROFN:%.*]] = function_ref @$s9observers4zero{{[_0-9a-zA-Z]*}}vau
// CHECK-NEXT: [[ZERORAW:%.*]] = apply [[ZEROFN]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[ZEROADDR:%.*]] = pointer_to_address [[ZERORAW]] : $Builtin.RawPointer to [strict] $*Int
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[ZEROADDR]] : $*Int
// CHECK-NEXT: [[ZERO:%.*]] = load [trivial] [[READ]]
// CHECK-NEXT: end_access [[READ]] : $*Int
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] %1
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign [[ZERO]] to [[AADDR]]
}
// CHECK-LABEL: sil private [ossa] @$s9observers010DidSetWillC5TestsV1a{{[_0-9a-zA-Z]*}}vW
didSet {
// CHECK: bb0(%0 : $*DidSetWillSetTests):
// CHECK-NEXT: debug_value_addr %0 : $*DidSetWillSetTests
takeInt(a)
// CHECK: [[READ:%.*]] = begin_access [read] [unknown] %0
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[READ]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: [[A:%.*]] = load [trivial] [[AADDR]] : $*Int
// CHECK-NEXT: end_access [[READ]]
// CHECK-NEXT: // function_ref observers.takeInt(Swift.Int) -> ()
// CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @$s9observers7takeInt{{[_0-9a-zA-Z]*}}F
// CHECK-NEXT: apply [[TAKEINTFN]]([[A]]) : $@convention(thin) (Int) -> ()
(self).a = zero // reassign, but don't infinite loop.
// CHECK-NEXT: // function_ref observers.zero.unsafeMutableAddressor : Swift.Int
// CHECK-NEXT: [[ZEROFN:%.*]] = function_ref @$s9observers4zero{{[_0-9a-zA-Z]*}}vau
// CHECK-NEXT: [[ZERORAW:%.*]] = apply [[ZEROFN]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[ZEROADDR:%.*]] = pointer_to_address [[ZERORAW]] : $Builtin.RawPointer to [strict] $*Int
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[ZEROADDR]] : $*Int
// CHECK-NEXT: [[ZERO:%.*]] = load [trivial] [[READ]]
// CHECK-NEXT: end_access [[READ]] : $*Int
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] %0
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[WRITE]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign [[ZERO]] to [[AADDR]]
}
// This is the synthesized getter and setter for the willset/didset variable.
// CHECK-LABEL: sil [transparent] [serialized] [ossa] @$s9observers010DidSetWillC5TestsV1aSivg
// CHECK: bb0(%0 : $DidSetWillSetTests):
// CHECK-NEXT: debug_value %0
// CHECK-NEXT: %2 = struct_extract %0 : $DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: return %2 : $Int{{.*}} // id: %3
// CHECK-LABEL: sil [ossa] @$s9observers010DidSetWillC5TestsV1aSivs : $@convention(method) (Int, @inout DidSetWillSetTests) -> () {
// CHECK: bb0([[NEWVALUE:%.*]] : $Int, %1 : $*DidSetWillSetTests):
// CHECK-NEXT: debug_value [[NEWVALUE]] : $Int, let, name "value", argno 1
// CHECK-NEXT: debug_value_addr %1
// CHECK-NEXT: [[MODIFY_ONE:%.*]] = begin_access [modify] [unknown] %1 : $*DidSetWillSetTests
// CHECK-NEXT: // function_ref observers.DidSetWillSetTests.a.willset : Swift.Int
// CHECK-NEXT: [[WILLSETFN:%.*]] = function_ref @$s9observers010DidSetWillC5TestsV1aSivw : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
// CHECK-NEXT: [[RESULT:%.*]] = apply [[WILLSETFN]]([[NEWVALUE]], [[MODIFY_ONE]]) : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
// CHECK-NEXT: end_access [[MODIFY_ONE]] : $*DidSetWillSetTests
// CHECK-NEXT: [[MODIFY_TWO:%.*]] = begin_access [modify] [unknown] %1 : $*DidSetWillSetTests
// CHECK-NEXT: [[ADDR:%.*]] = struct_element_addr [[MODIFY_TWO]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign [[NEWVALUE]] to [[ADDR]] : $*Int
// CHECK-NEXT: end_access [[MODIFY_TWO]] : $*DidSetWillSetTests
// CHECK-NEXT: [[MODIFY_THREE:%.*]] = begin_access [modify] [unknown] %1 : $*DidSetWillSetTests
// CHECK-NEXT: // function_ref observers.DidSetWillSetTests.a.didset : Swift.Int
// CHECK-NEXT: [[DIDSETFN:%.*]] = function_ref @$s9observers010DidSetWillC5TestsV1aSivW : $@convention(method) (@inout DidSetWillSetTests) -> ()
// CHECK-NEXT: [[RESULT:%.*]] = apply [[DIDSETFN]]([[MODIFY_THREE]]) : $@convention(method) (@inout DidSetWillSetTests) -> ()
// CHECK-NEXT: end_access [[MODIFY_THREE]] : $*DidSetWillSetTests
// CHECK-NEXT: [[TUPLE:%.*]] = tuple ()
// CHECK-NEXT: return [[TUPLE]] : $()
}
// CHECK-LABEL: sil hidden [ossa] @$s9observers010DidSetWillC5TestsV8testReadSiyF
// CHECK: [[SELF:%.*]] = begin_access [read] [unknown] %0 : $*DidSetWillSetTests
// CHECK-NEXT: [[PROP:%.*]] = struct_element_addr [[SELF]] : $*DidSetWillSetTests
// CHECK-NEXT: [[LOAD:%.*]] = load [trivial] [[PROP]] : $*Int
// CHECK-NEXT: end_access [[SELF]] : $*DidSetWillSetTests
// CHECK-NEXT: return [[LOAD]] : $Int
mutating func testRead() -> Int {
return a
}
// CHECK-LABEL: sil hidden [ossa] @$s9observers010DidSetWillC5TestsV9testWrite5inputySi_tF
// CHECK: [[SELF:%.*]] = begin_access [modify] [unknown] %1 : $*DidSetWillSetTests
// CHECK-NEXT: // function_ref observers.DidSetWillSetTests.a.setter
// CHECK-NEXT: [[SETTER:%.*]] = function_ref @$s9observers010DidSetWillC5TestsV1aSivs
// CHECK-NEXT: apply [[SETTER]](%0, [[SELF]])
// CHECK-NEXT: end_access [[SELF]] : $*DidSetWillSetTests
// CHECK-NEXT: [[RET:%.*]] = tuple ()
// CHECK-NEXT: return [[RET]] : $()
mutating func testWrite(input: Int) {
a = input
}
// CHECK-LABEL: sil hidden [ossa] @$s9observers010DidSetWillC5TestsV13testReadWrite5inputySi_tF
// CHECK: [[SELF:%.*]] = begin_access [modify] [unknown] %1 : $*DidSetWillSetTests
// CHECK-NEXT: [[TEMP:%.*]] = alloc_stack $Int
// CHECK-NEXT: [[PROP:%.*]] = struct_element_addr [[SELF]] : $*DidSetWillSetTests
// CHECK-NEXT: [[LOAD:%.*]] = load [trivial] [[PROP]] : $*Int
// CHECK-NEXT: store [[LOAD]] to [trivial] [[TEMP]] : $*Int
// (modification goes here)
// CHECK: [[RELOAD:%.*]] = load [trivial] [[TEMP]] : $*Int
// CHECK-NEXT: // function_ref observers.DidSetWillSetTests.a.setter
// CHECK-NEXT: [[SETTER:%.*]] = function_ref @$s9observers010DidSetWillC5TestsV1aSivs
// CHECK-NEXT: apply [[SETTER]]([[RELOAD]], [[SELF]])
// CHECK-NEXT: end_access [[SELF]] : $*DidSetWillSetTests
// CHECK-NEXT: dealloc_stack [[TEMP]] : $*Int
// CHECK-NEXT: [[RET:%.*]] = tuple ()
// CHECK-NEXT: return [[RET]] : $()
mutating func testReadWrite(input: Int) {
a += input
}
}
// Test global observing properties.
var global_observing_property : Int = zero {
// The variable is initialized with "zero".
// CHECK-LABEL: sil private [global_init_once_fn] [ossa] @{{.*}}WZ : $@convention(c) () -> () {
// CHECK: bb0:
// CHECK-NEXT: alloc_global @$s9observers25global_observing_propertySiv
// CHECK-NEXT: %1 = global_addr @$s9observers25global_observing_propertySivp : $*Int
// CHECK: observers.zero.unsafeMutableAddressor
// CHECK: return
// global_observing_property's setter needs to call didSet.
// CHECK-LABEL: sil private [ossa] @$s9observers25global_observing_property{{[_0-9a-zA-Z]*}}vW
didSet {
// The didSet implementation needs to call takeInt.
takeInt(global_observing_property)
// CHECK: function_ref observers.takeInt
// CHECK-NEXT: function_ref @$s9observers7takeInt{{[_0-9a-zA-Z]*}}F
// Setting the variable from within its own didSet doesn't recursively call didSet.
global_observing_property = zero
// CHECK: // function_ref observers.global_observing_property.unsafeMutableAddressor : Swift.Int
// CHECK-NEXT: [[ADDRESSOR:%.*]] = function_ref @$s9observers25global_observing_propertySivau : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[ADDRESS:%.*]] = apply [[ADDRESSOR]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[POINTER:%.*]] = pointer_to_address [[ADDRESS]] : $Builtin.RawPointer to [strict] $*Int
// CHECK-NEXT: // function_ref observers.zero.unsafeMutableAddressor : Swift.Int
// CHECK-NEXT: [[ZEROFN:%.*]] = function_ref @$s9observers4zero{{[_0-9a-zA-Z]*}}vau
// CHECK-NEXT: [[ZERORAW:%.*]] = apply [[ZEROFN]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[ZEROADDR:%.*]] = pointer_to_address [[ZERORAW]] : $Builtin.RawPointer to [strict] $*Int
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[ZEROADDR]] : $*Int
// CHECK-NEXT: [[ZERO:%.*]] = load [trivial] [[READ]]
// CHECK-NEXT: end_access [[READ]] : $*Int
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [dynamic] [[POINTER]] : $*Int
// CHECK-NEXT: assign [[ZERO]] to [[WRITE]] : $*Int
// CHECK-NEXT: end_access [[WRITE]] : $*Int
// CHECK-NOT: function_ref @$s9observers25global_observing_property{{[_0-9a-zA-Z]*}}vW
// CHECK: end sil function
}
// CHECK-LABEL: sil hidden [ossa] @$s9observers25global_observing_property{{[_0-9a-zA-Z]*}}vs
// CHECK: function_ref observers.global_observing_property.unsafeMutableAddressor
// CHECK-NEXT: function_ref @$s9observers25global_observing_property{{[_0-9a-zA-Z]*}}vau
// CHECK: function_ref observers.global_observing_property.didset
// CHECK-NEXT: function_ref @$s9observers25global_observing_property{{[_0-9a-zA-Z]*}}vW
}
func force_global_observing_property_setter() {
let x = global_observing_property
global_observing_property = x
}
// Test local observing properties.
// CHECK-LABEL: sil hidden [ossa] @$s9observers24local_observing_property{{[_0-9a-zA-Z]*}}SiF
func local_observing_property(_ arg: Int) {
var localproperty: Int = arg {
didSet {
takeInt(localproperty)
localproperty = zero
}
}
takeInt(localproperty)
localproperty = arg
// Alloc and initialize the property to the argument value.
// CHECK: bb0([[ARG:%[0-9]+]] : $Int)
// CHECK: [[BOX:%[0-9]+]] = alloc_box ${ var Int }
// CHECK: [[PB:%.*]] = project_box [[BOX]]
// CHECK: store [[ARG]] to [trivial] [[PB]]
}
// didSet of localproperty (above)
// Ensure that setting the variable from within its own didSet doesn't recursively call didSet.
// CHECK-LABEL: sil private [ossa] @$s9observers24local_observing_property{{[_0-9a-zA-Z]*}}SiF13localproperty{{[_0-9a-zA-Z]*}}SivW
// CHECK: bb0(%0 : @guaranteed ${ var Int })
// CHECK: [[POINTER:%.*]] = project_box %0 : ${ var Int }, 0
// CHECK: // function_ref observers.zero.unsafeMutableAddressor : Swift.Int
// CHECK-NEXT: [[ZEROFN:%.*]] = function_ref @$s9observers4zero{{[_0-9a-zA-Z]*}}vau
// CHECK-NEXT: [[ZERORAW:%.*]] = apply [[ZEROFN]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[ZEROADDR:%.*]] = pointer_to_address [[ZERORAW]] : $Builtin.RawPointer to [strict] $*Int
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [dynamic] [[ZEROADDR]] : $*Int
// CHECK-NEXT: [[ZERO:%.*]] = load [trivial] [[READ]]
// CHECK-NEXT: end_access [[READ]] : $*Int
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[POINTER]] : $*Int
// CHECK-NEXT: assign [[ZERO]] to [[WRITE]] : $*Int
// CHECK-NEXT: end_access [[WRITE]] : $*Int
// CHECK-NOT: function_ref @$s9observers24local_observing_property{{[_0-9a-zA-Z]*}}SiF13localproperty{{[_0-9a-zA-Z]*}}SivW
// CHECK: end sil function
func local_generic_observing_property<T>(_ arg: Int, _: T) {
var localproperty1: Int = arg {
didSet {
takeInt(localproperty1)
}
}
takeInt(localproperty1)
localproperty1 = arg
var localproperty2: Int = arg {
didSet {
_ = T.self
takeInt(localproperty2)
}
}
takeInt(localproperty2)
localproperty2 = arg
}
// <rdar://problem/16006333> observing properties don't work in @objc classes
@objc
class ObservingPropertyInObjCClass {
var bounds: Int {
willSet {}
didSet {}
}
init(b: Int) { bounds = b }
}
// CHECK-LABEL: sil hidden [ossa] @$s9observers32propertyWithDidSetTakingOldValueyyF : $@convention(thin) () -> () {
func propertyWithDidSetTakingOldValue() {
var p : Int = zero {
didSet(oldValue) {
// access to oldValue
use(oldValue)
// and newValue.
use(p)
}
}
p = zero
}
// CHECK-LABEL: sil private [ossa] @$s9observers32propertyWithDidSetTakingOldValueyyF1pL_Sivs
// CHECK: bb0([[ARG1:%.*]] : $Int, [[ARG2:%.*]] : @guaranteed ${ var Int }):
// CHECK-NEXT: debug_value [[ARG1]] : $Int, let, name "value", argno 1
// CHECK-NEXT: [[ARG2_PB:%.*]] = project_box [[ARG2]]
// CHECK-NEXT: debug_value_addr [[ARG2_PB]] : $*Int, var, name "p", argno 2
// CHECK-NEXT: [[READ:%.*]] = begin_access [read] [unknown] [[ARG2_PB]]
// CHECK-NEXT: [[ARG2_PB_VAL:%.*]] = load [trivial] [[READ]] : $*Int
// CHECK-NEXT: end_access [[READ]]
// CHECK-NEXT: debug_value [[ARG2_PB_VAL]] : $Int
// CHECK-NEXT: [[WRITE:%.*]] = begin_access [modify] [unknown] [[ARG2_PB]]
// CHECK-NEXT: assign [[ARG1]] to [[WRITE]] : $*Int
// CHECK-NEXT: end_access [[WRITE]]
// SEMANTIC ARC TODO: Another case where we need to put the mark_function_escape on a new projection after a copy.
// CHECK-NEXT: mark_function_escape [[ARG2_PB]]
// CHECK-NEXT: // function_ref
// CHECK-NEXT: [[FUNC:%.*]] = function_ref @$s9observers32propertyWithDidSetTakingOldValueyyF1pL_SivW : $@convention(thin) (Int, @guaranteed { var Int }) -> ()
// CHECK-NEXT: %{{.*}} = apply [[FUNC]]([[ARG2_PB_VAL]], [[ARG2]]) : $@convention(thin) (Int, @guaranteed { var Int }) -> ()
// CHECK-NEXT: %{{.*}} = tuple ()
// CHECK-NEXT: return %{{.*}} : $()
// CHECK-NEXT:} // end sil function '$s9observers32propertyWithDidSetTakingOldValue{{[_0-9a-zA-Z]*}}'
// <rdar://problem/16406886> Observing properties don't work with ownership types
class Ref {}
struct ObservingPropertiesWithOwnershipTypes {
unowned var alwaysPresent : Ref {
didSet {
}
}
init(res: Ref) {
alwaysPresent = res
}
}
// CHECK-LABEL: sil private [ossa] @$s9observers37ObservingPropertiesWithOwnershipTypesV13alwaysPresentAA3RefCvW : $@convention(method) (@inout ObservingPropertiesWithOwnershipTypes) -> () {
struct ObservingPropertiesWithOwnershipTypesInferred {
unowned var alwaysPresent = Ref() {
didSet {
}
}
weak var maybePresent = nil as Ref? {
willSet {
}
}
}
// CHECK-LABEL: sil private [ossa] @$s9observers45ObservingPropertiesWithOwnershipTypesInferredV13alwaysPresentAA3RefCvW : $@convention(method) (@inout ObservingPropertiesWithOwnershipTypesInferred) -> () {
// CHECK-LABEL: sil private [ossa] @$s9observers45ObservingPropertiesWithOwnershipTypesInferredV12maybePresentAA3RefCSgvw : $@convention(method) (@guaranteed Optional<Ref>, @inout ObservingPropertiesWithOwnershipTypesInferred) -> () {
//<rdar://problem/16620121> Initializing constructor tries to initialize computed property overridden with willSet/didSet
class ObservedBase {
var printInfo: Ref!
}
class ObservedDerived : ObservedBase {
override init() {}
override var printInfo: Ref! {
didSet { }
}
}
// CHECK-LABEL: sil private [ossa] @$s9observers15ObservedDerivedC9printInfoAA3RefCSgvW : $@convention(method) (@guaranteed ObservedDerived) -> () {
/// <rdar://problem/26408353> crash when overriding internal property with
/// public property
public class BaseClassWithInternalProperty {
var x: () = ()
}
public class DerivedClassWithPublicProperty : BaseClassWithInternalProperty {
public override var x: () {
didSet {}
}
}
// CHECK-LABEL: sil hidden [transparent] [ossa] @$s9observers29BaseClassWithInternalPropertyC1xytvg
// CHECK-LABEL: sil [ossa] @$s9observers30DerivedClassWithPublicPropertyC1xytvg
// CHECK: bb0([[SELF:%.*]] : @guaranteed $DerivedClassWithPublicProperty):
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]] : $DerivedClassWithPublicProperty
// CHECK-NEXT: [[SUPER:%.*]] = upcast [[SELF_COPY]] : $DerivedClassWithPublicProperty to $BaseClassWithInternalProperty
// CHECK-NEXT: [[BORROWED_SUPER:%.*]] = begin_borrow [[SUPER]]
// CHECK-NEXT: // function_ref observers.BaseClassWithInternalProperty.x.getter : ()
// CHECK-NEXT: [[METHOD:%.*]] = function_ref @$s9observers29BaseClassWithInternalPropertyC1xytvg : $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
// CHECK-NEXT: [[RESULT:%.*]] = apply [[METHOD]]([[BORROWED_SUPER]]) : $@convention(method) (@guaranteed BaseClassWithInternalProperty) -> ()
// CHECK-NEXT: end_borrow [[BORROWED_SUPER]]
// CHECK-NEXT: destroy_value [[SUPER]] : $BaseClassWithInternalProperty
// CHECK: } // end sil function '$s9observers30DerivedClassWithPublicPropertyC1xytvg'
// Make sure we use the correct substitutions when referencing a property in a
// generic base class
public class GenericBase<T> {
var storage: T? = nil
}
public class ConcreteDerived : GenericBase<Int> {
override var storage: Int? {
didSet {}
}
}
// CHECK-LABEL: sil private [ossa] @$s9observers15ConcreteDerivedC7storageSiSgvW : $@convention(method) (@guaranteed ConcreteDerived) -> () {
// Make sure we upcast properly when the overridden property is in an ancestor
// of our superclass
public class BaseObserved {
var x: Int = 0
}
public class MiddleObserved : BaseObserved {}
public class DerivedObserved : MiddleObserved {
override var x: Int {
didSet {}
}
}
// CHECK-LABEL: sil private [ossa] @$s9observers15DerivedObservedC1xSivW : $@convention(method) (@guaranteed DerivedObserved) -> () {