Files
swift-mirror/test/SILGen/properties.swift
Joe Groff e2962ed213 SILGen: Implement recursive local function references.
Instead of immediately creating closures for local function declarations and treating them directly as capturable values, break function captures down and transitively capture the storage necessary to invoke the captured functions. Change the way SILGen emits calls to closures and local functions so that it treats the capture list as the first curry level of an invocation, so that full applications of closure literals or nested functions don't require a partial apply at all. This allows references among local functions with captures to work within the existing confines of partial_apply, and also has the nice benefit that circular references would work without creating reference cycles (though Sema unfortunately rejects them; something we arguably ought to fix.)

This fixes rdar://problem/11266246 and improves codegen of local functions. Full applications of functions, or immediate applications of closure literals like { }(), now never need to allocate a closure.

Swift SVN r28112
2015-05-04 05:33:55 +00:00

976 lines
34 KiB
Swift

// RUN: %target-swift-frontend -parse-as-library -emit-silgen -disable-objc-attr-requires-foundation-module %s | FileCheck %s
var zero: Int = 0
func use(_:Int) {}
func getInt() -> Int { return zero }
// CHECK-LABEL: sil hidden @{{.*}}physical_tuple_lvalue
// CHECK-NEXT: bb0(%0 : $Int):
func physical_tuple_lvalue(c: Int) {
var x : (Int, Int)
// CHECK: [[XADDR1:%[0-9]+]] = alloc_box $(Int, Int)
// CHECK: [[XADDR:%[0-9]+]] = mark_uninitialized [var] [[XADDR1]]
x.1 = c
// CHECK: [[X_1:%[0-9]+]] = tuple_element_addr [[XADDR]] : {{.*}}, 1
// CHECK: assign %0 to [[X_1]]
}
func tuple_rvalue() -> (Int, Int) {}
// CHECK-LABEL: sil hidden @{{.*}}physical_tuple_rvalue
func physical_tuple_rvalue() -> Int {
return tuple_rvalue().1
// CHECK: [[FUNC:%[0-9]+]] = function_ref @_TF10properties12tuple_rvalue
// CHECK: [[TUPLE:%[0-9]+]] = apply [[FUNC]]()
// CHECK: [[RET:%[0-9]+]] = tuple_extract [[TUPLE]] : {{.*}}, 1
// CHECK: return [[RET]]
}
// CHECK-LABEL: sil hidden @_TF10properties16tuple_assignment
func tuple_assignment(inout a: Int, inout b: Int) {
// CHECK: bb0([[A_ADDR:%[0-9]+]] : $*Int, [[B_ADDR:%[0-9]+]] : $*Int):
// CHECK: [[A_LOCAL:%.*]] = alloc_box $Int
// CHECK: [[B_LOCAL:%.*]] = alloc_box $Int
// CHECK: [[B:%[0-9]+]] = load [[B_LOCAL]]#1
// CHECK: [[A:%[0-9]+]] = load [[A_LOCAL]]#1
// CHECK: assign [[B]] to [[A_LOCAL]]#1
// CHECK: assign [[A]] to [[B_LOCAL]]#1
(a, b) = (b, a)
}
// CHECK-LABEL: sil hidden @_TF10properties18tuple_assignment_2
func tuple_assignment_2(inout a: Int, inout b: Int, xy: (Int, Int)) {
// CHECK: bb0([[A_ADDR:%[0-9]+]] : $*Int, [[B_ADDR:%[0-9]+]] : $*Int, [[X:%[0-9]+]] : $Int, [[Y:%[0-9]+]] : $Int):
// CHECK: [[A_LOCAL:%.*]] = alloc_box $Int
// CHECK: [[B_LOCAL:%.*]] = alloc_box $Int
(a, b) = xy
// CHECK: [[XY2:%[0-9]+]] = tuple ([[X]] : $Int, [[Y]] : $Int)
// CHECK: [[X:%[0-9]+]] = tuple_extract [[XY2]] : {{.*}}, 0
// CHECK: [[Y:%[0-9]+]] = tuple_extract [[XY2]] : {{.*}}, 1
// CHECK: assign [[X]] to [[A_LOCAL]]#1
// CHECK: assign [[Y]] to [[B_LOCAL]]#1
}
class Ref {
var x, y : Int
var ref : Ref
var z: Int { get {} set {} }
var val_prop: Val { get {} set {} }
subscript(i: Int) -> Float { get {} set {} }
init(i: Int) {
x = i
y = i
ref = self
}
}
class RefSubclass : Ref {
var w : Int
override init (i: Int) {
w = i
super.init(i: i)
}
}
struct Val {
var x, y : Int
var ref : Ref
var z: Int { get {} set {} }
var z_tuple: (Int, Int) { get {} set {} }
subscript(i: Int) -> Float { get {} set {} }
}
// CHECK-LABEL: sil hidden @_TF10properties22physical_struct_lvalue
func physical_struct_lvalue(c: Int) {
var v : Val
// CHECK: [[VADDR:%[0-9]+]] = alloc_box $Val
v.y = c
// CHECK: assign %0 to [[X_1]]
}
// CHECK-LABEL: sil hidden @_TF10properties21physical_class_lvalue
func physical_class_lvalue(r: Ref, a: Int) {
r.y = a
// CHECK: [[FN:%[0-9]+]] = class_method %0 : $Ref, #Ref.y!setter.1
// CHECK: apply [[FN]](%1, %0) : $@convention(method) (Int, @guaranteed Ref) -> ()
// CHECK: strong_release %0 : $Ref
}
// CHECK-LABEL: sil hidden @_TF10properties24physical_subclass_lvalue
func physical_subclass_lvalue(r: RefSubclass, a: Int) {
r.y = a
// strong_retain %0 : $RefSubclass
// CHECK: [[R_SUP:%[0-9]+]] = upcast %0 : $RefSubclass to $Ref
// CHECK: [[FN:%[0-9]+]] = class_method [[R_SUP]] : $Ref, #Ref.y!setter.1 : Ref -> (Int) -> () , $@convention(method) (Int, @guaranteed Ref) -> ()
// CHECK: apply [[FN]](%1, [[R_SUP]]) :
// CHECK: strong_release [[R_SUP]]
r.w = a
// CHECK: [[FN:%[0-9]+]] = class_method %0 : $RefSubclass, #RefSubclass.w!setter.1
// CHECK: apply [[FN]](%1, %0) : $@convention(method) (Int, @guaranteed RefSubclass) -> ()
}
func struct_rvalue() -> Val {}
// CHECK-LABEL: sil hidden @_TF10properties22physical_struct_rvalue
func physical_struct_rvalue() -> Int {
return struct_rvalue().y
// CHECK: [[FUNC:%[0-9]+]] = function_ref @_TF10properties13struct_rvalueFT_VS_3Val
// CHECK: [[STRUCT:%[0-9]+]] = apply [[FUNC]]()
// CHECK: [[RET:%[0-9]+]] = struct_extract [[STRUCT]] : $Val, #Val.y
// CHECK: return [[RET]]
}
func class_rvalue() -> Ref {}
// CHECK-LABEL: sil hidden @_TF10properties21physical_class_rvalue
func physical_class_rvalue() -> Int {
return class_rvalue().y
// CHECK: [[FUNC:%[0-9]+]] = function_ref @_TF10properties12class_rvalueFT_CS_3Ref
// CHECK: [[CLASS:%[0-9]+]] = apply [[FUNC]]()
// CHECK: [[FN:%[0-9]+]] = class_method [[CLASS]] : $Ref, #Ref.y!getter.1
// CHECK: [[RET:%[0-9]+]] = apply [[FN]]([[CLASS]])
// CHECK: return [[RET]]
}
// CHECK-LABEL: sil hidden @_TF10properties18logical_struct_get
func logical_struct_get() -> Int {
return struct_rvalue().z
// CHECK: [[GET_RVAL:%[0-9]+]] = function_ref @_TF10properties13struct_rvalue
// CHECK: [[STRUCT:%[0-9]+]] = apply [[GET_RVAL]]()
// CHECK: [[GET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Valg1z
// CHECK: [[VALUE:%[0-9]+]] = apply [[GET_METHOD]]([[STRUCT]])
// CHECK: return [[VALUE]]
}
// CHECK-LABEL: sil hidden @_TF10properties18logical_struct_set
func logical_struct_set(inout value: Val, z: Int) {
// CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z:%[0-9]+]] : $Int):
value.z = z
// CHECK: [[VAL_LOCAL:%[0-9]+]] = alloc_box $Val
// CHECK: [[Z_SET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Vals1z
// CHECK: apply [[Z_SET_METHOD]]([[Z]], [[VAL_LOCAL]]#1)
// CHECK: return
}
// CHECK-LABEL: sil hidden @_TF10properties27logical_struct_in_tuple_set
func logical_struct_in_tuple_set(inout value: (Int, Val), z: Int) {
// CHECK: bb0([[VAL:%[0-9]+]] : $*(Int, Val), [[Z:%[0-9]+]] : $Int):
value.1.z = z
// CHECK: [[VAL_LOCAL:%[0-9]+]] = alloc_box $(Int, Val)
// CHECK: [[VAL_1:%[0-9]+]] = tuple_element_addr [[VAL_LOCAL]]#1 : {{.*}}, 1
// CHECK: [[Z_SET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Vals1z
// CHECK: apply [[Z_SET_METHOD]]([[Z]], [[VAL_1]])
// CHECK: return
}
// CHECK-LABEL: sil hidden @_TF10properties29logical_struct_in_reftype_set
func logical_struct_in_reftype_set(inout value: Val, z1: Int) {
// CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z1:%[0-9]+]] : $Int):
value.ref.val_prop.z_tuple.1 = z1
// CHECK: [[VAL_LOCAL:%[0-9]+]] = alloc_box $Val
// -- val.ref
// CHECK: [[VAL_REF_ADDR:%[0-9]+]] = struct_element_addr [[VAL_LOCAL]]#1 : $*Val, #Val.ref
// CHECK: [[VAL_REF:%[0-9]+]] = load [[VAL_REF_ADDR]]
// -- getters and setters
// -- val.ref.val_prop
// CHECK: [[STORAGE:%.*]] = alloc_stack $Builtin.UnsafeValueBuffer
// CHECK: [[VAL_REF_VAL_PROP_TEMP:%.*]] = alloc_stack $Val
// CHECK: [[T0:%.*]] = address_to_pointer [[VAL_REF_VAL_PROP_TEMP]]#1 : $*Val to $Builtin.RawPointer
// CHECK: [[MAT_VAL_PROP_METHOD:%[0-9]+]] = class_method {{.*}} : $Ref, #Ref.val_prop!materializeForSet.1 : Ref -> (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer) -> (Builtin.RawPointer, (@convention(thin) (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer, inout Ref, @thick Ref.Type) -> ())?)
// CHECK: [[MAT_RESULT:%[0-9]+]] = apply [[MAT_VAL_PROP_METHOD]]([[T0]], [[STORAGE]]#1, [[VAL_REF]])
// CHECK: [[T0:%.*]] = tuple_extract [[MAT_RESULT]] : $(Builtin.RawPointer, Optional<@convention(thin) (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer, inout Ref, @thick Ref.Type) -> ()>), 0
// CHECK: [[T1:%[0-9]+]] = pointer_to_address [[T0]] : $Builtin.RawPointer to $*Val
// CHECK: [[OPT_CALLBACK:%.*]] = tuple_extract [[MAT_RESULT]] : $(Builtin.RawPointer, Optional<@convention(thin) (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer, inout Ref, @thick Ref.Type) -> ()>), 1
// CHECK: [[VAL_REF_VAL_PROP_MAT:%.*]] = mark_dependence [[T1]] : $*Val on [[VAL_REF]]
// CHECK: [[V_R_VP_Z_TUPLE_MAT:%[0-9]+]] = alloc_stack $(Int, Int)
// CHECK: [[LD:%[0-9]+]] = load [[VAL_REF_VAL_PROP_MAT]]
// CHECK: retain_value [[LD]]
// -- val.ref.val_prop.z_tuple
// CHECK: [[GET_Z_TUPLE_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Valg7z_tupleT
// CHECK: [[V_R_VP_Z_TUPLE:%[0-9]+]] = apply [[GET_Z_TUPLE_METHOD]]([[LD]])
// CHECK: store [[V_R_VP_Z_TUPLE]] to [[V_R_VP_Z_TUPLE_MAT]]#1
// -- write to val.ref.val_prop.z_tuple.1
// CHECK: [[V_R_VP_Z_TUPLE_1:%[0-9]+]] = tuple_element_addr [[V_R_VP_Z_TUPLE_MAT]]#1 : {{.*}}, 1
// CHECK: assign [[Z1]] to [[V_R_VP_Z_TUPLE_1]]
// -- writeback to val.ref.val_prop.z_tuple
// CHECK: [[WB_V_R_VP_Z_TUPLE:%[0-9]+]] = load [[V_R_VP_Z_TUPLE_MAT]]#1
// CHECK: [[SET_Z_TUPLE_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Vals7z_tupleT
// CHECK: apply [[SET_Z_TUPLE_METHOD]]({{%[0-9]+, %[0-9]+}}, [[VAL_REF_VAL_PROP_MAT]])
// -- writeback to val.ref.val_prop
// CHECK: switch_enum [[OPT_CALLBACK]] : $Optional<@convention(thin) (Builtin.RawPointer, inout Builtin.UnsafeValueBuffer, inout Ref, @thick Ref.Type) -> ()>, case #Optional.Some!enumelt.1: [[WRITEBACK:bb[0-9]+]], case #Optional.None!enumelt: [[CONT:bb[0-9]+]]
// CHECK: [[WRITEBACK]]([[CALLBACK:%.*]] : $@convention(thin) (Builtin.RawPointer, @inout Builtin.UnsafeValueBuffer, @inout Ref, @thick Ref.Type) -> ()):
// CHECK: [[REF_MAT:%.*]] = alloc_stack $Ref
// CHECK: store [[VAL_REF]] to [[REF_MAT]]#1
// CHECK: [[T0:%.*]] = metatype $@thick Ref.Type
// CHECK: [[T1:%.*]] = address_to_pointer [[VAL_REF_VAL_PROP_MAT]]
// CHECK: apply [[CALLBACK]]([[T1]], [[STORAGE]]#1, [[REF_MAT]]#1, [[T0]])
// CHECK: br [[CONT]]
// CHECK: [[CONT]]:
// -- cleanup
// CHECK: dealloc_stack [[V_R_VP_Z_TUPLE_MAT]]#0
// CHECK: dealloc_stack [[VAL_REF_VAL_PROP_TEMP]]#0
// -- don't need to write back to val.ref because it's a ref type
}
func reftype_rvalue() -> Ref {}
// CHECK-LABEL: sil hidden @_TF10properties18reftype_rvalue_set
func reftype_rvalue_set(value: Val) {
reftype_rvalue().val_prop = value
}
// CHECK-LABEL: sil hidden @_TF10properties27tuple_in_logical_struct_set
func tuple_in_logical_struct_set(inout value: Val, z1: Int) {
// CHECK: bb0([[VAL:%[0-9]+]] : $*Val, [[Z1:%[0-9]+]] : $Int):
value.z_tuple.1 = z1
// CHECK: [[VAL_LOCAL:%[0-9]+]] = alloc_box $Val
// CHECK: [[Z_TUPLE_MATERIALIZED:%[0-9]+]] = alloc_stack $(Int, Int)
// CHECK: [[VAL1:%[0-9]+]] = load [[VAL_LOCAL]]
// CHECK: retain_value [[VAL1]]
// CHECK: [[Z_GET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Valg7z_tupleT
// CHECK: [[Z_TUPLE:%[0-9]+]] = apply [[Z_GET_METHOD]]([[VAL1]])
// CHECK: store [[Z_TUPLE]] to [[Z_TUPLE_MATERIALIZED]]#1
// CHECK: [[Z_TUPLE_1:%[0-9]+]] = tuple_element_addr [[Z_TUPLE_MATERIALIZED]]#1 : {{.*}}, 1
// CHECK: assign [[Z1]] to [[Z_TUPLE_1]]
// CHECK: [[Z_TUPLE_MODIFIED:%[0-9]+]] = load [[Z_TUPLE_MATERIALIZED]]#1
// CHECK: [[Z_SET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Vals7z_tupleT
// CHECK: apply [[Z_SET_METHOD]]({{%[0-9]+, %[0-9]+}}, [[VAL_LOCAL]]#1)
// CHECK: dealloc_stack [[Z_TUPLE_MATERIALIZED]]#0
// CHECK: return
}
var global_prop : Int {
// CHECK-LABEL: sil hidden @_TF10propertiesg11global_prop
get {
return zero
}
// CHECK-LABEL: sil hidden @_TF10propertiess11global_prop
set {
use(newValue)
}
}
// CHECK-LABEL: sil hidden @_TF10properties18logical_global_get
func logical_global_get() -> Int {
return global_prop
// CHECK: [[GET:%[0-9]+]] = function_ref @_TF10propertiesg11global_prop
// CHECK: [[VALUE:%[0-9]+]] = apply [[GET]]()
// CHECK: return [[VALUE]]
}
// CHECK-LABEL: sil hidden @_TF10properties18logical_global_set
func logical_global_set(x: Int) {
global_prop = x
// CHECK: [[SET:%[0-9]+]] = function_ref @_TF10propertiess11global_prop
// CHECK: apply [[SET]](%0)
}
// CHECK-LABEL: sil hidden @_TF10properties17logical_local_get
func logical_local_get(x: Int) -> Int {
var prop : Int {
get {
return x
}
}
// CHECK: [[GET_REF:%[0-9]+]] = function_ref [[PROP_GET_CLOSURE:@_TFF10properties17logical_local_get]]
// CHECK: apply [[GET_REF]](%0)
return prop
}
// CHECK-: sil shared [[PROP_GET_CLOSURE]]
// CHECK: bb0(%{{[0-9]+}} : $Int):
// CHECK-LABEL: sil hidden @_TF10properties26logical_local_captured_get
func logical_local_captured_get(x: Int) -> Int {
var prop : Int {
get {
return x
}
}
func get_prop() -> Int {
return prop
}
return get_prop()
// CHECK: [[FUNC_REF:%[0-9]+]] = function_ref @_TFF10properties26logical_local_captured_get
// CHECK: apply [[FUNC_REF]](%0)
}
// CHECK: sil shared @_TFF10properties26logical_local_captured_get
// CHECK: bb0(%{{[0-9]+}} : $Int):
func inout_arg(inout x: Int) {}
// CHECK-LABEL: sil hidden @_TF10properties14physical_inout
func physical_inout(var x: Int) {
// CHECK: [[XADDR:%[0-9]+]] = alloc_box $Int
inout_arg(&x)
// CHECK: [[INOUT_ARG:%[0-9]+]] = function_ref @_TF10properties9inout_arg
// CHECK: apply [[INOUT_ARG]]([[XADDR]]#1)
}
/* TODO check writeback to more complex logical prop, check that writeback
* reuses temporaries */
// CHECK-LABEL: sil hidden @_TF10properties17val_subscript_get
// CHECK-NEXT: bb0([[VVAL:%[0-9]+]] : $Val, [[I:%[0-9]+]] : $Int):
func val_subscript_get(v: Val, i: Int) -> Float {
return v[i]
// CHECK: [[SUBSCRIPT_GET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Valg9subscript
// CHECK: [[RET:%[0-9]+]] = apply [[SUBSCRIPT_GET_METHOD]]([[I]], [[VVAL]]) : $@convention(method) (Int, @guaranteed Val)
// CHECK: return [[RET]]
}
// CHECK-LABEL: sil hidden @_TF10properties17val_subscript_set
// CHECK: bb0(%0 : $Val, [[I:%[0-9]+]] : $Int, [[X:%[0-9]+]] : $Float):
func val_subscript_set(var v: Val, i: Int, x: Float) {
v[i] = x
// CHECK: [[VADDR:%[0-9]+]] = alloc_box $Val
// CHECK: [[SUBSCRIPT_SET_METHOD:%[0-9]+]] = function_ref @_TFV10properties3Vals9subscript
// CHECK: apply [[SUBSCRIPT_SET_METHOD]]([[X]], [[I]], [[VADDR]]#1)
}
struct Generic<T> {
var mono_phys:Int
var mono_log: Int { get {} set {} }
var typevar_member:T
subscript(x: Int) -> Float { get {} set {} }
subscript(x: T) -> T { get {} set {} }
// CHECK-LABEL: sil hidden @_TFV10properties7Generic19copy_typevar_member
mutating
func copy_typevar_member(x: Generic<T>) {
typevar_member = x.typevar_member
}
}
// CHECK-LABEL: sil hidden @_TF10properties21generic_mono_phys_get
func generic_mono_phys_get<T>(g: Generic<T>) -> Int {
return g.mono_phys
// CHECK: struct_element_addr %{{.*}}, #Generic.mono_phys
}
// CHECK-LABEL: sil hidden @_TF10properties20generic_mono_log_get
func generic_mono_log_get<T>(g: Generic<T>) -> Int {
return g.mono_log
// CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @_TFV10properties7Genericg8mono_log
// CHECK: apply [[GENERIC_GET_METHOD]]<
}
// CHECK-LABEL: sil hidden @_TF10properties20generic_mono_log_set
func generic_mono_log_set<T>(var g: Generic<T>, x: Int) {
g.mono_log = x
// CHECK: [[GENERIC_SET_METHOD:%[0-9]+]] = function_ref @_TFV10properties7Generics8mono_log
// CHECK: apply [[GENERIC_SET_METHOD]]<
}
// CHECK-LABEL: sil hidden @_TF10properties26generic_mono_subscript_get
func generic_mono_subscript_get<T>(g: Generic<T>, i: Int) -> Float {
return g[i]
// CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @_TFV10properties7Genericg9subscript
// CHECK: apply [[GENERIC_GET_METHOD]]<
}
// CHECK-LABEL: sil hidden @{{.*}}generic_mono_subscript_set
func generic_mono_subscript_set<T>(inout g: Generic<T>, i: Int, x: Float) {
g[i] = x
// CHECK: [[GENERIC_SET_METHOD:%[0-9]+]] = function_ref @_TFV10properties7Generics9subscript
// CHECK: apply [[GENERIC_SET_METHOD]]<
}
// CHECK-LABEL: sil hidden @{{.*}}bound_generic_mono_phys_get
func bound_generic_mono_phys_get(inout g: Generic<UnicodeScalar>, x: Int) -> Int {
return g.mono_phys
// CHECK: struct_element_addr %{{.*}}, #Generic.mono_phys
}
// CHECK-LABEL: sil hidden @_TF10properties26bound_generic_mono_log_get
func bound_generic_mono_log_get(g: Generic<UnicodeScalar>, x: Int) -> Int {
return g.mono_log
// CHECK: [[GENERIC_GET_METHOD:%[0-9]+]] = function_ref @_TFV10properties7Genericg8mono_log
// CHECK: apply [[GENERIC_GET_METHOD]]<
}
// CHECK-LABEL: sil hidden @_TF10properties22generic_subscript_type
func generic_subscript_type<T>(var g: Generic<T>, i: T, x: T) -> T {
g[i] = x
return g[i]
}
/*TODO: archetype and existential properties and subscripts */
struct StaticProperty {
static var foo: Int {
get {
return zero
}
set {}
}
}
// CHECK-LABEL: sil hidden @_TF10properties10static_get
// CHECK: function_ref @_TZFV10properties14StaticPropertyg3foo{{.*}} : $@convention(thin) (@thin StaticProperty.Type) -> Int
func static_get() -> Int {
return StaticProperty.foo
}
// CHECK-LABEL: sil hidden @_TF10properties10static_set
// CHECK: function_ref @_TZFV10properties14StaticPropertys3foo{{.*}} : $@convention(thin) (Int, @thin StaticProperty.Type) -> ()
func static_set(x: Int) {
StaticProperty.foo = x
}
func takeInt(a : Int) {}
struct DidSetWillSetTests {
var a : Int {
willSet(newA) {
// CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.willset
// CHECK-NEXT: sil hidden @_TFV10properties18DidSetWillSetTestsw1a
// CHECK-NEXT: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
// CHECK-NEXT: debug_value %0
// CHECK-NEXT: [[SELFBOX:%.*]] = alloc_box $DidSetWillSetTests
// CHECK-NEXT: copy_addr %1 to [initialization] [[SELFBOX]]#1 : $*DidSetWillSetTests
takeInt(a)
// CHECK-NEXT: // function_ref properties.takeInt
// CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @_TF10properties7takeInt
// CHECK-NEXT: [[FIELDPTR:%.*]] = struct_element_addr [[SELFBOX]]#1 : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: [[A:%.*]] = load [[FIELDPTR]] : $*Int
// CHECK-NEXT: apply [[TAKEINTFN]]([[A]]) : $@convention(thin) (Int) -> ()
takeInt(newA)
// CHECK-NEXT: // function_ref properties.takeInt (Swift.Int) -> ()
// CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @_TF10properties7takeInt
// CHECK-NEXT: apply [[TAKEINTFN]](%0) : $@convention(thin) (Int) -> ()
// CHECK-NEXT: copy_addr [[SELFBOX]]#1 to %1 : $*DidSetWillSetTests
}
didSet {
// CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.didset
// CHECK-NEXT: sil hidden @_TFV10properties18DidSetWillSetTestsW1a
// CHECK-NEXT: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
// CHECK-NEXT: debug
// CHECK-NEXT: [[SELFBOX:%.*]] = alloc_box $DidSetWillSetTests
// CHECK-NEXT: copy_addr %1 to [initialization] [[SELFBOX:%.*]]#1 : $*DidSetWillSetTests
takeInt(a)
// CHECK-NEXT: // function_ref properties.takeInt (Swift.Int) -> ()
// CHECK-NEXT: [[TAKEINTFN:%.*]] = function_ref @_TF10properties7takeInt
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[SELFBOX:%.*]]#1 : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: [[A:%.*]] = load [[AADDR]] : $*Int
// CHECK-NEXT: apply %5([[A]]) : $@convention(thin) (Int) -> ()
a = zero // reassign, but don't infinite loop.
// CHECK-NEXT: // function_ref properties.zero.unsafeMutableAddressor : Swift.Int
// CHECK-NEXT: [[ZEROFN:%.*]] = function_ref @_TF10propertiesau4zero
// CHECK-NEXT: [[ZERORAW:%.*]] = apply [[ZEROFN]]() : $@convention(thin) () -> Builtin.RawPointer
// CHECK-NEXT: [[ZEROADDR:%.*]] = pointer_to_address [[ZERORAW]] : $Builtin.RawPointer to $*Int
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[SELFBOX:%.*]]#1 : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: copy_addr [[ZEROADDR]] to [[AADDR]] : $*Int
// CHECK-NEXT: copy_addr [[SELFBOX]]#1 to %1 : $*DidSetWillSetTests
}
}
init(x : Int) {
// Accesses to didset/willset variables are direct in init methods and dtors.
a = x
a = x
}
// These are the synthesized getter and setter for the willset/didset variable.
// CHECK-LABEL: // {{.*}}.DidSetWillSetTests.a.getter
// CHECK-NEXT: sil hidden [transparent] @_TFV10properties18DidSetWillSetTestsg1a
// CHECK-NEXT: 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: // {{.*}}.DidSetWillSetTests.a.setter
// CHECK-NEXT: sil hidden @_TFV10properties18DidSetWillSetTestss1a
// CHECK-NEXT: bb0(%0 : $Int, %1 : $*DidSetWillSetTests):
// CHECK-NEXT: debug_value %0
// CHECK-NEXT: [[SELFBOX:%.*]] = alloc_box $DidSetWillSetTests
// CHECK-NEXT: copy_addr %1 to [initialization] [[SELFBOX]]#1 : $*DidSetWillSetTests
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[SELFBOX:%.*]]#1 : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: [[OLDVAL:%.*]] = load [[AADDR]] : $*Int
// CHECK-NEXT: debug_value [[OLDVAL]] : $Int // let tmp
// CHECK-NEXT: // function_ref {{.*}}.DidSetWillSetTests.a.willset : Swift.Int
// CHECK-NEXT: [[WILLSETFN:%.*]] = function_ref @_TFV10properties18DidSetWillSetTestsw1a
// CHECK-NEXT: apply [[WILLSETFN]](%0, [[SELFBOX]]#1) : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
// CHECK-NEXT: [[AADDR:%.*]] = struct_element_addr [[SELFBOX:%.*]]#1 : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign %0 to [[AADDR]] : $*Int
// CHECK-NEXT: // function_ref {{.*}}.DidSetWillSetTests.a.didset : Swift.Int
// CHECK-NEXT: [[DIDSETFN:%.*]] = function_ref @_TFV10properties18DidSetWillSetTestsW1a{{.*}} : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
// CHECK-NEXT: apply [[DIDSETFN]]([[OLDVAL]], [[SELFBOX]]#1) : $@convention(method) (Int, @inout DidSetWillSetTests) -> ()
// CHECK-NEXT: copy_addr [[SELFBOX]]#1 to %1 : $*DidSetWillSetTests
// CHECK-LABEL: sil hidden @_TFV10properties18DidSetWillSetTestsCfMS0_FT1x
// CHECK-NEXT: bb0(%0 : $Int, %1 : $@thin DidSetWillSetTests.Type):
// CHECK: [[SELF:%.*]] = mark_uninitialized [rootself]
// CHECK: [[P1:%.*]] = struct_element_addr [[SELF]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign %0 to [[P1]]
// CHECK: [[P2:%.*]] = struct_element_addr [[SELF]] : $*DidSetWillSetTests, #DidSetWillSetTests.a
// CHECK-NEXT: assign %0 to [[P2]]
}
// Test global observing properties.
var global_observing_property : Int = zero {
didSet {
takeInt(global_observing_property)
}
}
// The property is initialized with "zero".
// CHECK-LABEL: sil private @globalinit_{{.*}}_func1 : $@convention(thin) () -> () {
// CHECK-NEXT: bb0:
// CHECK-NEXT: %0 = global_addr @_Tv10properties25global_observing_propertySi : $*Int
// CHECK: properties.zero.unsafeMutableAddressor
// CHECK: return
// The didSet implementation needs to call takeInt.
// CHECK-LABEL: sil hidden @_TF10propertiesW25global_observing_property
// CHECK: function_ref properties.takeInt
// CHECK-NEXT: function_ref @_TF10properties7takeInt
// The setter needs to call didSet implementation.
// CHECK-LABEL: sil hidden @_TF10propertiess25global_observing_property
// CHECK: function_ref properties.global_observing_property.unsafeMutableAddressor
// CHECK-NEXT: function_ref @_TF10propertiesau25global_observing_property
// CHECK: function_ref properties.global_observing_property.didset
// CHECK-NEXT: function_ref @_TF10propertiesW25global_observing_property
// Test local observing properties.
func local_observing_property(arg: Int) {
var localproperty: Int = arg {
didSet {
takeInt(localproperty)
}
}
takeInt(localproperty)
localproperty = arg
}
// This is the local_observing_property function itself. First alloc and
// initialize the property to the argument value.
// CHECK-LABEL: sil hidden @{{.*}}local_observing_property
// CHECK-NEXT: bb0([[ARG:%[0-9]+]] : $Int)
// CHECK: [[BOX:%[0-9]+]] = alloc_box $Int
// CHECK: store [[ARG]] to [[BOX]]#1
// <rdar://problem/16006333> observing properties don't work in @objc classes
@objc
class ObservingPropertyInObjCClass {
var bounds: Int {
willSet {}
didSet {}
}
init(b: Int) { bounds = b }
}
// Superclass init methods should not get direct access to be class properties.
// rdar://16151899
class rdar16151899Base {
var x: Int = zero {
willSet {
use(x)
}
}
}
class rdar16151899Derived : rdar16151899Base {
// CHECK-LABEL: sil hidden @_TFC10properties19rdar16151899DerivedcfMS0_FT_S0_
override init() {
super.init()
// CHECK: upcast {{.*}} : $rdar16151899Derived to $rdar16151899Base
// CHECK-NEXT: function_ref properties.rdar16151899Base.init
// This should not be a direct access, it should call the setter in the
// base.
x = zero
// CHECK: [[BASEPTR:%[0-9]+]] = upcast {{.*}} : $rdar16151899Derived to $rdar16151899Base
// CHECK: load{{.*}}Int
// CHECK-NEXT: [[SETTER:%[0-9]+]] = class_method {{.*}} : $rdar16151899Base, #rdar16151899Base.x!setter.1 : rdar16151899Base
// CHECK-NEXT: apply [[SETTER]]({{.*}}, [[BASEPTR]])
}
}
func propertyWithDidSetTakingOldValue() {
var p : Int = zero {
didSet(oldValue) {
// access to oldValue
use(oldValue)
// and newValue.
use(p)
}
}
p = zero
}
// CHECK: // properties.(propertyWithDidSetTakingOldValue () -> ()).(p #1).setter : Swift.Int
// CHECK-NEXT: sil {{.*}} @_TFF10properties32propertyWithDidSetTakingOldValue
// CHECK-NEXT: bb0(%0 : $Int, %1 : $Builtin.NativeObject, %2 : $*Int):
// CHECK-NEXT: debug_value %0 : $Int
// CHECK-NEXT: %4 = load %2 : $*Int
// CHECK-NEXT: debug_value %4 : $Int
// CHECK-NEXT: assign %0 to %2 : $*Int
// CHECK-NEXT: strong_retain %1 : $Builtin.NativeObject
// CHECK-NEXT: // function_ref
// CHECK-NEXT: %8 = function_ref @_TFF10properties32propertyWithDidSetTakingOldValueFT_T_WL_1pSi : $@convention(thin) (Int, @owned Builtin.NativeObject, @inout Int) -> ()
// CHECK-NEXT: %9 = apply %8(%4, %1, %2) : $@convention(thin) (Int, @owned Builtin.NativeObject, @inout Int) -> ()
// CHECK-NEXT: strong_release %1 : $Builtin.NativeObject
// CHECK-NEXT: %11 = tuple ()
// CHECK-NEXT: return %11 : $()
// CHECK-NEXT:}
class BaseProperty {
var x : Int { get {} set {} }
}
class DerivedProperty : BaseProperty {
override var x : Int { get {} set {} }
func super_property_reference() -> Int {
return super.x
}
}
// rdar://16381392 - Super property references in non-objc classes should be direct.
// CHECK: sil hidden @_TFC10properties15DerivedProperty24super_property_referencefS0_FT_
// CHECK-NEXT: bb0(%0 : $DerivedProperty):
// CHECK: [[BASEPTR:%[0-9]+]] = upcast %0 : $DerivedProperty to $BaseProperty
// CHECK: // function_ref properties.BaseProperty.x.getter
// CHECK: [[FN:%[0-9]+]] = function_ref @_TFC10properties12BasePropertyg1x
// CHECK: apply [[FN]]([[BASEPTR]]) : $@convention(method) (@guaranteed BaseProperty) -> Int // user: %7
// <rdar://problem/16411449> ownership qualifiers don't work with non-mutating struct property
struct ReferenceStorageTypeRValues {
unowned var p1 : Ref
func testRValueUnowned() -> Ref {
return p1
}
// CHECK: sil hidden @{{.*}}testRValueUnowned
// CHECK-NEXT: bb0(%0 : $ReferenceStorageTypeRValues):
// CHECK-NEXT: debug_value %0 : $ReferenceStorageTypeRValues
// CHECK-NEXT: %2 = struct_extract %0 : $ReferenceStorageTypeRValues, #ReferenceStorageTypeRValues.p1
// CHECK-NEXT: strong_retain_unowned %2 : $@sil_unowned Ref
// CHECK-NEXT: %4 = unowned_to_ref %2 : $@sil_unowned Ref to $Ref
// CHECK-NEXT: return %4 : $Ref
init() {
}
}
// <rdar://problem/16406886> Observing properties don't work with ownership types
struct ObservingPropertiesWithOwnershipTypes {
unowned var alwaysPresent : Ref {
didSet {
}
}
init(res: Ref) {
alwaysPresent = res
}
}
struct ObservingPropertiesWithOwnershipTypesInferred {
unowned var alwaysPresent = Ref(i: 0) {
didSet {
}
}
weak var maybePresent = nil as Ref? {
willSet {
}
}
}
// <rdar://problem/16554876> property accessor synthesization of weak variables doesn't work
protocol WeakPropertyProtocol {
weak var maybePresent : Ref? { get set }
}
struct WeakPropertyStruct : WeakPropertyProtocol {
weak var maybePresent : Ref?
init() {
maybePresent = nil
}
}
// <rdar://problem/16629598> direct property accesses to generic struct
// properties were being mischecked as computed property accesses.
struct SomeGenericStruct<T> {
var x: Int
}
// CHECK-LABEL: sil hidden @_TF10properties4getX
// CHECK: struct_extract {{%.*}} : $SomeGenericStruct<T>, #SomeGenericStruct.x
func getX<T>(g: SomeGenericStruct<T>) -> Int {
return g.x
}
// <rdar://problem/16189360> [DF] Assert on subscript with variadic parameter
struct VariadicSubscript {
subscript(subs: Int...) -> Int {
get {
return 42
}
}
func test() {
var s = VariadicSubscript()
var x = s[0, 1, 2]
}
}
//<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 { }
}
}
/// <rdar://problem/16953517> Class properties should be allowed in protocols, even without stored class properties
protocol ProtoWithClassProp {
static var x: Int { get }
}
class ClassWithClassProp : ProtoWithClassProp {
class var x: Int {
return 42
}
}
struct StructWithClassProp : ProtoWithClassProp {
static var x: Int {
return 19
}
}
func getX<T : ProtoWithClassProp>(a : T) -> Int {
return T.x
}
func testClassPropertiesInProtocol() -> Int {
return getX(ClassWithClassProp())+getX(StructWithClassProp())
}
class GenericClass<T> {
var x: T
var y: Int
final let z: T
init() { fatalError("scaffold") }
}
// CHECK-LABEL: sil hidden @_TF10properties12genericPropsFGCS_12GenericClassSS_T_
func genericProps(x: GenericClass<String>) {
// CHECK: class_method %0 : $GenericClass<String>, #GenericClass.x!getter.1
let _ = x.x
// CHECK: class_method %0 : $GenericClass<String>, #GenericClass.y!getter.1
let _ = x.y
// CHECK: [[Z:%.*]] = ref_element_addr %0 : $GenericClass<String>, #GenericClass.z
// CHECK: load [[Z]] : $*String
let _ = x.z
}
// CHECK-LABEL: sil hidden @_TF10properties28genericPropsInGenericContextU__FGCS_12GenericClassQ__T_
func genericPropsInGenericContext<U>(x: GenericClass<U>) {
// CHECK: [[Z:%.*]] = ref_element_addr %0 : $GenericClass<U>, #GenericClass.z
// CHECK: copy_addr [[Z]] {{.*}} : $*U
let _ = x.z
}
// <rdar://problem/18275556> 'let' properties in a class should be implicitly final
class ClassWithLetProperty {
let p = 42
dynamic let q = 97
// We shouldn't have any dynamic dispatch within this method, just load p.
func ReturnConstant() -> Int { return p }
// CHECK-LABEL: sil hidden @_TFC10properties20ClassWithLetProperty14ReturnConstantfS0_FT_Si
// CHECK-NEXT: bb0(%0 : $ClassWithLetProperty):
// CHECK-NEXT: debug_value
// CHECK-NEXT: [[PTR:%[0-9]+]] = ref_element_addr %0 : $ClassWithLetProperty, #ClassWithLetProperty.p
// CHECK-NEXT: [[VAL:%[0-9]+]] = load [[PTR]] : $*Int
// CHECK-NEXT: return [[VAL]] : $Int
// This property is marked dynamic, so go through the getter, always.
func ReturnDynamicConstant() -> Int { return q }
// CHECK-LABEL: sil hidden @_TFC10properties20ClassWithLetProperty21ReturnDynamicConstantfS0_FT_Si
// CHECK: class_method [volatile] %0 : $ClassWithLetProperty, #ClassWithLetProperty.q!getter.1.foreign
}
// <rdar://problem/19254812> DI bug when referencing let member of a class
class r19254812Base {}
class r19254812Derived: r19254812Base{
let pi = 3.14159265359
init(x : ()) {
println(pi)
}
// Accessing the "pi" property should not retain/release self.
// CHECK-LABEL: sil hidden @_TFC10properties16r19254812DerivedcfMS0_FT1xT__S0_
// CHECK: [[SELFMUI:%[0-9]+]] = mark_uninitialized [derivedself]
// Initialization of the pi field: no retains/releases.
// CHECK: [[SELF:%[0-9]+]] = load [[SELFMUI]] : $*r19254812Derived
// CHECK-NEXT: [[PIPTR:%[0-9]+]] = ref_element_addr [[SELF]] : $r19254812Derived, #r19254812Derived.pi
// CHECK-NEXT: assign {{.*}} to [[PIPTR]] : $*Double
// CHECK-NOT: strong_release
// CHECK-NOT: strong_retain
// Load of the pi field: no retains/releases.
// CHECK: [[SELF:%[0-9]+]] = load [[SELFMUI]] : $*r19254812Derived
// CHECK-NEXT: [[PIPTR:%[0-9]+]] = ref_element_addr [[SELF]] : $r19254812Derived, #r19254812Derived.pi
// CHECK-NEXT: {{.*}} = load [[PIPTR]] : $*Double
// CHECK: return
}
class RedundantSelfRetains {
final var f : RedundantSelfRetains
init() {
f = RedundantSelfRetains()
}
// <rdar://problem/19275047> Extraneous retains/releases of self are bad
func testMethod1() {
f = RedundantSelfRetains()
}
// CHECK-LABEL: sil hidden @_TFC10properties20RedundantSelfRetains11testMethod1fS0_FT_T_
// CHECK-NEXT: bb0(%0 : $RedundantSelfRetains):
// CHECK-NOT: strong_retain
// CHECK: [[FPTR:%[0-9]+]] = ref_element_addr %0 : $RedundantSelfRetains, #RedundantSelfRetains.f
// CHECK-NEXT: assign {{.*}} to [[FPTR]] : $*RedundantSelfRetains
// CHECK: return
}
class RedundantRetains {
final var field = 0
}
func testRedundantRetains() {
let a = RedundantRetains()
a.field = 4 // no retain/release of a necessary here.
}
// CHECK-LABEL: sil hidden @_TF10properties20testRedundantRetainsFT_T_ : $@convention(thin) () -> () {
// CHECK: [[A:%[0-9]+]] = apply
// CHECK-NOT: strong_retain
// CHECK: strong_release [[A]] : $RedundantRetains
// CHECK-NOT: strong_retain
// CHECK-NOT: strong_release
// CHECK: return
struct AddressOnlyNonmutatingSet<T> {
var x: T
init(x: T) { self.x = x }
var prop: Int {
get { return 0 }
nonmutating set { }
}
}
func addressOnlyNonmutatingProperty<T>(x: AddressOnlyNonmutatingSet<T>)
-> Int {
x.prop = 0
return x.prop
}
// CHECK-LABEL: sil hidden @_TF10properties30addressOnlyNonmutatingPropertyU__FGVS_25AddressOnlyNonmutatingSetQ__Si : $@convention(thin) <T> (@in AddressOnlyNonmutatingSet<T>) -> Int {
// CHECK: [[SET:%.*]] = function_ref @_TFV10properties25AddressOnlyNonmutatingSets4propSi
// CHECK: apply [[SET]]<T>({{%.*}}, [[TMP:%.*]]#1)
// CHECK: destroy_addr [[TMP]]
// CHECK: dealloc_stack [[TMP]]
// CHECK: [[GET:%.*]] = function_ref @_TFV10properties25AddressOnlyNonmutatingSetg4propSi
// CHECK: apply [[GET]]<T>([[TMP:%.*]]#1)
// CHECK: destroy_addr [[TMP]]
// CHECK: dealloc_stack [[TMP]]
protocol MakeAddressOnly {}
struct AddressOnlyReadOnlySubscript {
var x: MakeAddressOnly?
subscript(z: Int) -> Int { return z }
}
// CHECK-LABEL: sil hidden @_TF10properties43addressOnlyReadOnlySubscriptFromMutableBaseFSiT_
// CHECK: [[BASE:%.*]] = alloc_box $AddressOnlyReadOnlySubscript
// CHECK: copy_addr [[BASE:%.*]]#1 to [initialization] [[COPY:%.*]]#1
// CHECK: [[GETTER:%.*]] = function_ref @_TFV10properties28AddressOnlyReadOnlySubscriptg9subscriptFSiSi
// CHECK: apply [[GETTER]]({{%.*}}, [[COPY]]#1)
func addressOnlyReadOnlySubscriptFromMutableBase(x: Int) {
var base = AddressOnlyReadOnlySubscript()
_ = base[x]
}