mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Invertible protocols are currently always mangled with `Ri`, followed by a single letter for each invertible protocol (e.g., `c` and `e` for `Copyable` and `Escapable`, respectively), followed by the generic parameter index. However, this requires that we extend the mangling for any future invertible protocols, which mean they won't be backward compatible. Replace this mangling with one that mangles the bit # for the invertible protocol, e.g., `Ri_` (followed by the generic parameter index) is bit 0, which is `Copyable`. `Ri0_` (then generic parameter index) is bit 1, which is `Escapable`. This allows us to round-trip through mangled names for any invertible protocol, without any knowledge of what the invertible protocol is, providing forward compatibility. The same forward compatibility is present in all metadata and the runtime, allowing us to add more invertible protocols in the future without updating any of them, and also allowing backward compatibility. Only the demangling to human-readable strings maps the bit numbers back to their names, and there's a fallback printing with just the bit number when appropriate. Also generalize the mangling a bit to allow for mangling of invertible requirements on associated types, e.g., `S.Sequence: ~Copyable`. This is currently unsupported by the compiler or runtime, but that may change, and it was easy enough to finish off the mangling work for it.
878 lines
42 KiB
Swift
878 lines
42 KiB
Swift
|
|
// RUN: %target-swift-emit-silgen -module-name closures -parse-stdlib -parse-as-library %s | %FileCheck %s
|
|
// RUN: %target-swift-emit-silgen -module-name closures -parse-stdlib -parse-as-library %s | %FileCheck %s --check-prefix=GUARANTEED
|
|
|
|
import Swift
|
|
|
|
var zero = 0
|
|
|
|
// <rdar://problem/15921334>
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures46return_local_generic_function_without_captures{{[_0-9a-zA-Z]*}}F : $@convention(thin) <A, R> () -> @owned @callee_guaranteed @substituted <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1 for <A, R> {
|
|
|
|
func return_local_generic_function_without_captures<A, R>() -> (A) -> R {
|
|
func f(_: A) -> R {
|
|
Builtin.int_trap()
|
|
}
|
|
// CHECK: [[FN:%.*]] = function_ref @$s8closures46return_local_generic_function_without_captures{{[_0-9a-zA-Z]*}} : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1
|
|
// CHECK: [[FN_WITH_GENERIC_PARAMS:%.*]] = partial_apply [callee_guaranteed] [[FN]]<A, R>() : $@convention(thin) <τ_0_0, τ_0_1> (@in_guaranteed τ_0_0) -> @out τ_0_1
|
|
// CHECK: [[FN_CONV:%.*]] = convert_function [[FN_WITH_GENERIC_PARAMS]]
|
|
// CHECK: return [[FN_CONV]] :
|
|
return f
|
|
}
|
|
|
|
func return_local_generic_function_with_captures<A, R>(_ a: A) -> (A) -> R {
|
|
func f(_: A) -> R {
|
|
_ = a
|
|
}
|
|
|
|
return f
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures17read_only_captureyS2iF : $@convention(thin) (Int) -> Int {
|
|
func read_only_capture(_ x: Int) -> Int {
|
|
var x = x
|
|
// CHECK: bb0([[X:%[0-9]+]] : $Int):
|
|
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// SEMANTIC ARC TODO: This is incorrect. We need to do the project_box on the copy.
|
|
// CHECK: [[LIFETIME:%.*]] = begin_borrow [var_decl] [[XBOX]]
|
|
// CHECK: [[PROJECT:%.*]] = project_box [[LIFETIME]]
|
|
// CHECK: store [[X]] to [trivial] [[PROJECT]]
|
|
|
|
func cap() -> Int {
|
|
return x
|
|
}
|
|
|
|
return cap()
|
|
// SEMANTIC ARC TODO: See above. This needs to happen on the copy_valued box.
|
|
// CHECK: mark_function_escape [[PROJECT]]
|
|
// CHECK: [[CAP:%[0-9]+]] = function_ref @[[CAP_NAME:\$s8closures17read_only_capture.*]] : $@convention(thin) (@guaranteed { var Int }) -> Int
|
|
// CHECK: [[RET:%[0-9]+]] = apply [[CAP]]([[LIFETIME]])
|
|
// CHECK: destroy_value [[XBOX]]
|
|
// CHECK: return [[RET]]
|
|
}
|
|
// CHECK: } // end sil function '$s8closures17read_only_captureyS2iF'
|
|
|
|
// CHECK: sil private [ossa] @[[CAP_NAME]]
|
|
// CHECK: bb0([[XBOX:%[0-9]+]] : @closureCapture @guaranteed ${ var Int }):
|
|
// CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
|
|
// CHECK: [[X:%[0-9]+]] = load [trivial] [[ACCESS]]
|
|
// CHECK: return [[X]]
|
|
// } // end sil function '[[CAP_NAME]]'
|
|
|
|
// SEMANTIC ARC TODO: This is a place where we have again project_box too early.
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures16write_to_captureyS2iF : $@convention(thin) (Int) -> Int {
|
|
func write_to_capture(_ x: Int) -> Int {
|
|
var x = x
|
|
// CHECK: bb0([[X:%[0-9]+]] : $Int):
|
|
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[LIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[XBOX]]
|
|
// CHECK: [[XBOX_PB:%[0-9]+]] = project_box [[LIFETIME]]
|
|
// CHECK: store [[X]] to [trivial] [[XBOX_PB]]
|
|
// CHECK: [[X2BOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[X2LIFETIME:%.*]] = begin_borrow [var_decl] [[X2BOX]]
|
|
// CHECK: [[X2BOX_PB:%.*]] = project_box [[X2LIFETIME]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XBOX_PB]] : $*Int
|
|
// CHECK: copy_addr [[ACCESS]] to [init] [[X2BOX_PB]]
|
|
// CHECK: mark_function_escape [[X2BOX_PB]]
|
|
var x2 = x
|
|
|
|
func scribble() {
|
|
x2 = zero
|
|
}
|
|
|
|
scribble()
|
|
// CHECK: [[SCRIB:%[0-9]+]] = function_ref @[[SCRIB_NAME:\$s8closures16write_to_capture.*]] : $@convention(thin) (@guaranteed { var Int }) -> ()
|
|
// CHECK: apply [[SCRIB]]([[X2LIFETIME]])
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[X2BOX_PB]] : $*Int
|
|
// CHECK: [[RET:%[0-9]+]] = load [trivial] [[ACCESS]]
|
|
// CHECK: destroy_value [[X2BOX]]
|
|
// CHECK: destroy_value [[XBOX]]
|
|
// CHECK: return [[RET]]
|
|
return x2
|
|
}
|
|
// CHECK: } // end sil function '$s8closures16write_to_captureyS2iF'
|
|
|
|
// CHECK: sil private [ossa] @[[SCRIB_NAME]]
|
|
// CHECK: bb0([[XBOX:%[0-9]+]] : @closureCapture @guaranteed ${ var Int }):
|
|
// CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [unknown] [[XADDR]] : $*Int
|
|
// CHECK: assign {{%[0-9]+}} to [[ACCESS]]
|
|
// CHECK: return
|
|
// CHECK: } // end sil function '[[SCRIB_NAME]]'
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures21multiple_closure_refs{{[_0-9a-zA-Z]*}}F
|
|
func multiple_closure_refs(_ x: Int) -> (() -> Int, () -> Int) {
|
|
var x = x
|
|
func cap() -> Int {
|
|
return x
|
|
}
|
|
|
|
return (cap, cap)
|
|
// CHECK: [[CAP:%[0-9]+]] = function_ref @[[CAP_NAME:\$s8closures21multiple_closure_refs.*]] : $@convention(thin) (@guaranteed { var Int }) -> Int
|
|
// CHECK: [[CAP_CLOSURE_1:%[0-9]+]] = partial_apply [callee_guaranteed] [[CAP]]
|
|
// CHECK: [[CAP:%[0-9]+]] = function_ref @[[CAP_NAME:\$s8closures21multiple_closure_refs.*]] : $@convention(thin) (@guaranteed { var Int }) -> Int
|
|
// CHECK: [[CAP_CLOSURE_2:%[0-9]+]] = partial_apply [callee_guaranteed] [[CAP]]
|
|
// CHECK: [[RET:%[0-9]+]] = tuple ([[CAP_CLOSURE_1]] : {{.*}}, [[CAP_CLOSURE_2]] : {{.*}})
|
|
// CHECK: return [[RET]]
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures18capture_local_funcySiycycSiF : $@convention(thin) (Int) -> @owned @callee_guaranteed () -> @owned @callee_guaranteed () -> Int {
|
|
func capture_local_func(_ x: Int) -> () -> () -> Int {
|
|
// CHECK: bb0([[ARG:%.*]] : $Int):
|
|
var x = x
|
|
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[LIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[XBOX]]
|
|
// CHECK: [[XBOX_PB:%[0-9]+]] = project_box [[LIFETIME]]
|
|
// CHECK: store [[ARG]] to [trivial] [[XBOX_PB]]
|
|
|
|
func aleph() -> Int { return x }
|
|
|
|
func beth() -> () -> Int { return aleph }
|
|
// CHECK: [[BETH_REF:%.*]] = function_ref @[[BETH_NAME:\$s8closures18capture_local_funcySiycycSiF4bethL_SiycyF]] : $@convention(thin) (@guaranteed { var Int }) -> @owned @callee_guaranteed () -> Int
|
|
// CHECK: [[XBOX_COPY:%.*]] = copy_value [[LIFETIME]]
|
|
// SEMANTIC ARC TODO: This is incorrect. This should be a project_box from XBOX_COPY.
|
|
// CHECK: mark_function_escape [[XBOX_PB]]
|
|
// CHECK: [[BETH_CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[BETH_REF]]([[XBOX_COPY]])
|
|
|
|
return beth
|
|
// CHECK: destroy_value [[XBOX]]
|
|
// CHECK: return [[BETH_CLOSURE]]
|
|
}
|
|
// CHECK: } // end sil function '$s8closures18capture_local_funcySiycycSiF'
|
|
|
|
// CHECK: sil private [ossa] @[[ALEPH_NAME:\$s8closures18capture_local_funcySiycycSiF5alephL_SiyF]] : $@convention(thin) (@guaranteed { var Int }) -> Int {
|
|
// CHECK: bb0([[XBOX:%[0-9]+]] : @closureCapture @guaranteed ${ var Int }):
|
|
|
|
// CHECK: sil private [ossa] @[[BETH_NAME]] : $@convention(thin) (@guaranteed { var Int }) -> @owned @callee_guaranteed () -> Int {
|
|
// CHECK: bb0([[XBOX:%[0-9]+]] : @closureCapture @guaranteed ${ var Int }):
|
|
// CHECK: [[XBOX_PB:%.*]] = project_box [[XBOX]]
|
|
// CHECK: [[ALEPH_REF:%[0-9]+]] = function_ref @[[ALEPH_NAME]] : $@convention(thin) (@guaranteed { var Int }) -> Int
|
|
// CHECK: [[XBOX_COPY:%.*]] = copy_value [[XBOX]]
|
|
// SEMANTIC ARC TODO: This should be on a PB from XBOX_COPY.
|
|
// CHECK: mark_function_escape [[XBOX_PB]]
|
|
// CHECK: [[ALEPH_CLOSURE:%[0-9]+]] = partial_apply [callee_guaranteed] [[ALEPH_REF]]([[XBOX_COPY]])
|
|
// CHECK: return [[ALEPH_CLOSURE]]
|
|
// CHECK: } // end sil function '[[BETH_NAME]]'
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures22anon_read_only_capture{{[_0-9a-zA-Z]*}}F
|
|
func anon_read_only_capture(_ x: Int) -> Int {
|
|
var x = x
|
|
// CHECK: bb0([[X:%[0-9]+]] : $Int):
|
|
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[LIFETIME:%[0-9]+]] = begin_borrow [var_decl] [[XBOX]]
|
|
// CHECK: [[PB:%[0-9]+]] = project_box [[LIFETIME]]
|
|
|
|
return ({ x })()
|
|
// -- func expression
|
|
// CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$s8closures22anon_read_only_capture[_0-9a-zA-Z]*]] : $@convention(thin) (@inout_aliasable Int) -> Int
|
|
// -- apply expression
|
|
// CHECK: [[RET:%[0-9]+]] = apply [[ANON]]([[PB]])
|
|
// -- cleanup
|
|
// CHECK: destroy_value [[XBOX]]
|
|
// CHECK: return [[RET]]
|
|
}
|
|
// CHECK: sil private [ossa] @[[CLOSURE_NAME]]
|
|
// CHECK: bb0([[XADDR:%[0-9]+]] : @closureCapture $*Int):
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
|
|
// CHECK: [[X:%[0-9]+]] = load [trivial] [[ACCESS]]
|
|
// CHECK: return [[X]]
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures21small_closure_capture{{[_0-9a-zA-Z]*}}F
|
|
func small_closure_capture(_ x: Int) -> Int {
|
|
var x = x
|
|
// CHECK: bb0([[X:%[0-9]+]] : $Int):
|
|
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[LIFETIME:%.*]] = begin_borrow [var_decl] [[XBOX]]
|
|
// CHECK: [[PB:%.*]] = project_box [[LIFETIME]]
|
|
|
|
return { x }()
|
|
// -- func expression
|
|
// CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$s8closures21small_closure_capture[_0-9a-zA-Z]*]] : $@convention(thin) (@inout_aliasable Int) -> Int
|
|
// -- apply expression
|
|
// CHECK: [[RET:%[0-9]+]] = apply [[ANON]]([[PB]])
|
|
// -- cleanup
|
|
// CHECK: destroy_value [[XBOX]]
|
|
// CHECK: return [[RET]]
|
|
}
|
|
// CHECK: sil private [ossa] @[[CLOSURE_NAME]]
|
|
// CHECK: bb0([[XADDR:%[0-9]+]] : @closureCapture $*Int):
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [unknown] [[XADDR]] : $*Int
|
|
// CHECK: [[X:%[0-9]+]] = load [trivial] [[ACCESS]]
|
|
// CHECK: return [[X]]
|
|
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures35small_closure_capture_with_argument{{[_0-9a-zA-Z]*}}F
|
|
func small_closure_capture_with_argument(_ x: Int) -> (_ y: Int) -> Int {
|
|
var x = x
|
|
// CHECK: [[XBOX:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[LIFETIME:%.*]] = begin_borrow [var_decl] [[XBOX]]
|
|
|
|
return { x + $0 }
|
|
// -- func expression
|
|
// CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$s8closures35small_closure_capture_with_argument.*]] : $@convention(thin) (Int, @guaranteed { var Int }) -> Int
|
|
// CHECK: [[XBOX_COPY:%.*]] = copy_value [[LIFETIME]]
|
|
// CHECK: [[ANON_CLOSURE_APP:%[0-9]+]] = partial_apply [callee_guaranteed] [[ANON]]([[XBOX_COPY]])
|
|
// -- return
|
|
// CHECK: destroy_value [[XBOX]]
|
|
// CHECK: return [[ANON_CLOSURE_APP]]
|
|
}
|
|
// CHECK: sil private [ossa] @[[CLOSURE_NAME]] : $@convention(thin) (Int, @guaranteed { var Int }) -> Int
|
|
// CHECK: bb0([[DOLLAR0:%[0-9]+]] : $Int, [[XBOX:%[0-9]+]] : @closureCapture @guaranteed ${ var Int }):
|
|
// CHECK: [[XADDR:%[0-9]+]] = project_box [[XBOX]]
|
|
// CHECK: [[INTTYPE:%[0-9]+]] = metatype $@thin Int.Type
|
|
// CHECK: [[XACCESS:%[0-9]+]] = begin_access [read] [unknown] [[XADDR]] : $*Int
|
|
// CHECK: [[LHS:%[0-9]+]] = load [trivial] [[XACCESS]]
|
|
// CHECK: end_access [[XACCESS]] : $*Int
|
|
// CHECK: [[PLUS:%[0-9]+]] = function_ref @$sSi1poiyS2i_SitFZ{{.*}}
|
|
// CHECK: [[RET:%[0-9]+]] = apply [[PLUS]]([[LHS]], [[DOLLAR0]], [[INTTYPE]])
|
|
// CHECK: return [[RET]]
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures24small_closure_no_capture{{[_0-9a-zA-Z]*}}F
|
|
func small_closure_no_capture() -> (_ y: Int) -> Int {
|
|
// CHECK: [[ANON:%[0-9]+]] = function_ref @[[CLOSURE_NAME:\$s8closures24small_closure_no_captureS2icyFS2icfU_]] : $@convention(thin) (Int) -> Int
|
|
// CHECK: [[ANON_THICK:%[0-9]+]] = thin_to_thick_function [[ANON]] : ${{.*}} to $@callee_guaranteed (Int) -> Int
|
|
// CHECK: return [[ANON_THICK]]
|
|
return { $0 }
|
|
}
|
|
// CHECK: sil private [ossa] @[[CLOSURE_NAME]] : $@convention(thin) (Int) -> Int
|
|
// CHECK: bb0([[YARG:%[0-9]+]] : $Int):
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures17uncaptured_locals{{[_0-9a-zA-Z]*}}F :
|
|
func uncaptured_locals(_ x: Int) -> (Int, Int) {
|
|
var x = x
|
|
// -- locals without captures are stack-allocated
|
|
// CHECK: bb0([[XARG:%[0-9]+]] : $Int):
|
|
// CHECK: [[XADDR:%[0-9]+]] = alloc_box ${ var Int }
|
|
// CHECK: [[LIFETIME:%.*]] = begin_borrow [var_decl] [[XADDR]]
|
|
// CHECK: [[PB:%.*]] = project_box [[LIFETIME]]
|
|
// CHECK: store [[XARG]] to [trivial] [[PB]]
|
|
|
|
var y = zero
|
|
// CHECK: [[YADDR:%[0-9]+]] = alloc_box ${ var Int }
|
|
return (x, y)
|
|
|
|
}
|
|
|
|
class SomeClass {
|
|
var x : Int = zero
|
|
|
|
init() {
|
|
x = { self.x }() // Closing over self.
|
|
}
|
|
}
|
|
|
|
// Closures within destructors <rdar://problem/15883734>
|
|
class SomeGenericClass<T> {
|
|
deinit {
|
|
var i: Int = zero
|
|
// CHECK: [[C1REF:%[0-9]+]] = function_ref @$s8closures16SomeGenericClassCfdSiyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> Int
|
|
// CHECK: apply [[C1REF]]([[IBOX:%[0-9]+]]) : $@convention(thin) (@inout_aliasable Int) -> Int
|
|
var x = { i + zero } ()
|
|
|
|
// CHECK: [[C2REF:%[0-9]+]] = function_ref @$s8closures16SomeGenericClassCfdSiyXEfU0_ : $@convention(thin) () -> Int
|
|
// CHECK: apply [[C2REF]]() : $@convention(thin) () -> Int
|
|
var y = { zero } ()
|
|
|
|
// CHECK: [[C3REF:%[0-9]+]] = function_ref @$s8closures16SomeGenericClassCfdyyXEfU1_ : $@convention(thin) <τ_0_0> () -> ()
|
|
// CHECK: apply [[C3REF]]<T>() : $@convention(thin) <τ_0_0> () -> ()
|
|
var z = { _ = T.self } ()
|
|
}
|
|
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures16SomeGenericClassCfdSiyXEfU_ : $@convention(thin) (@inout_aliasable Int) -> Int
|
|
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures16SomeGenericClassCfdSiyXEfU0_ : $@convention(thin) () -> Int
|
|
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures16SomeGenericClassCfdyyXEfU1_ : $@convention(thin) <T> () -> ()
|
|
}
|
|
|
|
// This is basically testing that the constraint system ranking
|
|
// function conversions as worse than others, and therefore performs
|
|
// the conversion within closures when possible.
|
|
class SomeSpecificClass : SomeClass {}
|
|
func takesSomeClassGenerator(_ fn : () -> SomeClass) {}
|
|
func generateWithConstant(_ x : SomeSpecificClass) {
|
|
takesSomeClassGenerator({ x })
|
|
}
|
|
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures20generateWithConstantyyAA17SomeSpecificClassCFAA0eG0CyXEfU_ : $@convention(thin) (@guaranteed SomeSpecificClass) -> @owned SomeClass {
|
|
// CHECK: bb0([[T0:%.*]] : @closureCapture @guaranteed $SomeSpecificClass):
|
|
// CHECK: debug_value [[T0]] : $SomeSpecificClass, let, name "x", argno 1
|
|
// CHECK: [[T0_COPY:%.*]] = copy_value [[T0]]
|
|
// CHECK: [[T0_COPY_CASTED:%.*]] = upcast [[T0_COPY]] : $SomeSpecificClass to $SomeClass
|
|
// CHECK: return [[T0_COPY_CASTED]]
|
|
// CHECK: } // end sil function '$s8closures20generateWithConstantyyAA17SomeSpecificClassCFAA0eG0CyXEfU_'
|
|
|
|
|
|
// Check the annoying case of capturing 'self' in a derived class 'init'
|
|
// method. We allocate a mutable box to deal with 'self' potentially being
|
|
// rebound by super.init, but 'self' is formally immutable and so is captured
|
|
// by value. <rdar://problem/15599464>
|
|
class Base {}
|
|
|
|
class SelfCapturedInInit : Base {
|
|
var foo : () -> SelfCapturedInInit
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures18SelfCapturedInInitC{{[_0-9a-zA-Z]*}}fc : $@convention(method) (@owned SelfCapturedInInit) -> @owned SelfCapturedInInit {
|
|
// CHECK: bb0([[SELF:%.*]] : @owned $SelfCapturedInInit):
|
|
//
|
|
// First create our initial value for self.
|
|
// CHECK: [[SELF_BOX:%.*]] = alloc_box ${ var SelfCapturedInInit }, let, name "self"
|
|
// CHECK: [[UNINIT_SELF:%.*]] = mark_uninitialized [derivedself] [[SELF_BOX]]
|
|
// CHECK: [[SELF_LIFETIME:%.*]] = begin_borrow [lexical] [var_decl] [[UNINIT_SELF]]
|
|
// CHECK: [[PB_SELF_BOX:%.*]] = project_box [[SELF_LIFETIME]]
|
|
// CHECK: store [[SELF]] to [init] [[PB_SELF_BOX]]
|
|
//
|
|
// Then perform the super init sequence.
|
|
// CHECK: [[TAKEN_SELF:%.*]] = load [take] [[PB_SELF_BOX]]
|
|
// CHECK: [[UPCAST_TAKEN_SELF:%.*]] = upcast [[TAKEN_SELF]]
|
|
// CHECK: [[NEW_SELF:%.*]] = apply {{.*}}([[UPCAST_TAKEN_SELF]]) : $@convention(method) (@owned Base) -> @owned Base
|
|
// CHECK: [[DOWNCAST_NEW_SELF:%.*]] = unchecked_ref_cast [[NEW_SELF]] : $Base to $SelfCapturedInInit
|
|
// CHECK: store [[DOWNCAST_NEW_SELF]] to [init] [[PB_SELF_BOX]]
|
|
//
|
|
// Finally put self in the closure.
|
|
// CHECK: [[BORROWED_SELF:%.*]] = load_borrow [[PB_SELF_BOX]]
|
|
// CHECK: [[COPIED_SELF:%.*]] = load [copy] [[PB_SELF_BOX]]
|
|
// CHECK: [[FOO_VALUE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[COPIED_SELF]]) : $@convention(thin) (@guaranteed SelfCapturedInInit) -> @owned SelfCapturedInInit
|
|
// CHECK: [[FOO_LOCATION:%.*]] = ref_element_addr [[BORROWED_SELF]]
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [modify] [dynamic] [[FOO_LOCATION]] : $*@callee_guaranteed () -> @owned SelfCapturedInInit
|
|
// CHECK: assign [[FOO_VALUE]] to [[ACCESS]]
|
|
override init() {
|
|
super.init()
|
|
foo = { self }
|
|
}
|
|
}
|
|
|
|
func takeClosure(_ fn: () -> Int) -> Int { return fn() }
|
|
|
|
class TestCaptureList {
|
|
var x = zero
|
|
|
|
func testUnowned() {
|
|
let aLet = self
|
|
takeClosure { aLet.x }
|
|
takeClosure { [unowned aLet] in aLet.x }
|
|
takeClosure { [weak aLet] in aLet!.x }
|
|
|
|
var aVar = self
|
|
takeClosure { aVar.x }
|
|
takeClosure { [unowned aVar] in aVar.x }
|
|
takeClosure { [weak aVar] in aVar!.x }
|
|
|
|
takeClosure { self.x }
|
|
takeClosure { [unowned self] in self.x }
|
|
takeClosure { [weak self] in self!.x }
|
|
|
|
takeClosure { [unowned newVal = TestCaptureList()] in newVal.x }
|
|
takeClosure { [weak newVal = TestCaptureList()] in newVal!.x }
|
|
}
|
|
}
|
|
|
|
class ClassWithIntProperty { final var x = 42 }
|
|
|
|
func closeOverLetLValue() {
|
|
let a : ClassWithIntProperty
|
|
a = ClassWithIntProperty()
|
|
|
|
takeClosure { a.x }
|
|
}
|
|
|
|
// The let property needs to be captured into a temporary stack slot so that it
|
|
// is loadable even though we capture the value.
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures18closeOverLetLValueyyFSiyXEfU_ : $@convention(thin) (@guaranteed ClassWithIntProperty) -> Int {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $ClassWithIntProperty):
|
|
// CHECK: [[TMP_CLASS_ADDR:%.*]] = alloc_stack $ClassWithIntProperty, let, name "a", argno 1
|
|
// CHECK: [[COPY_ARG:%.*]] = copy_value [[ARG]]
|
|
// CHECK: store [[COPY_ARG]] to [init] [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
|
|
// CHECK: [[BORROWED_LOADED_CLASS:%.*]] = load_borrow [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
|
|
// CHECK: [[INT_IN_CLASS_ADDR:%.*]] = ref_element_addr [[BORROWED_LOADED_CLASS]] : $ClassWithIntProperty, #ClassWithIntProperty.x
|
|
// CHECK: [[ACCESS:%.*]] = begin_access [read] [dynamic] [[INT_IN_CLASS_ADDR]] : $*Int
|
|
// CHECK: [[INT_IN_CLASS:%.*]] = load [trivial] [[ACCESS]] : $*Int
|
|
// CHECK: end_borrow [[BORROWED_LOADED_CLASS]]
|
|
// CHECK: destroy_addr [[TMP_CLASS_ADDR]] : $*ClassWithIntProperty
|
|
// CHECK: dealloc_stack %1 : $*ClassWithIntProperty
|
|
// CHECK: return [[INT_IN_CLASS]]
|
|
// CHECK: } // end sil function '$s8closures18closeOverLetLValueyyFSiyXEfU_'
|
|
|
|
// GUARANTEED-LABEL: sil private [ossa] @$s8closures18closeOverLetLValueyyFSiyXEfU_ : $@convention(thin) (@guaranteed ClassWithIntProperty) -> Int {
|
|
// GUARANTEED: bb0(%0 : @closureCapture @guaranteed $ClassWithIntProperty):
|
|
// GUARANTEED: [[TMP:%.*]] = alloc_stack $ClassWithIntProperty
|
|
// GUARANTEED: [[COPY:%.*]] = copy_value %0 : $ClassWithIntProperty
|
|
// GUARANTEED: store [[COPY]] to [init] [[TMP]] : $*ClassWithIntProperty
|
|
// GUARANTEED: [[BORROWED:%.*]] = load_borrow [[TMP]]
|
|
// GUARANTEED: end_borrow [[BORROWED]]
|
|
// GUARANTEED: destroy_addr [[TMP]]
|
|
// GUARANTEED: } // end sil function '$s8closures18closeOverLetLValueyyFSiyXEfU_'
|
|
|
|
|
|
// Use an external function so inout deshadowing cannot see its body.
|
|
@_silgen_name("takesNoEscapeClosure")
|
|
func takesNoEscapeClosure(fn : () -> Int)
|
|
|
|
struct StructWithMutatingMethod {
|
|
var x = 42
|
|
|
|
mutating func mutatingMethod() {
|
|
// This should not capture the refcount of the self shadow.
|
|
takesNoEscapeClosure { x = 42; return x }
|
|
}
|
|
}
|
|
|
|
// Check that the address of self is passed in, but not the refcount pointer.
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures24StructWithMutatingMethodV08mutatingE0{{[_0-9a-zA-Z]*}}F
|
|
// CHECK: bb0(%0 : $*StructWithMutatingMethod):
|
|
// CHECK: [[CLOSURE:%[0-9]+]] = function_ref @$s8closures24StructWithMutatingMethodV08mutatingE0{{.*}} : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int
|
|
// CHECK: partial_apply [callee_guaranteed] [[CLOSURE]](%0) : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int
|
|
|
|
// Check that the closure body only takes the pointer.
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures24StructWithMutatingMethodV08mutatingE0{{.*}} : $@convention(thin) (@inout_aliasable StructWithMutatingMethod) -> Int {
|
|
// CHECK: bb0(%0 : @closureCapture $*StructWithMutatingMethod):
|
|
|
|
class SuperBase {
|
|
func boom() {}
|
|
}
|
|
class SuperSub : SuperBase {
|
|
override func boom() {}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1ayyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$s8closures8SuperSubC1a[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: apply [[INNER]]([[SELF]])
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1ayyF'
|
|
func a() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[CLASS_METHOD:%.*]] = class_method [[ARG]] : $SuperSub, #SuperSub.boom :
|
|
// CHECK: = apply [[CLASS_METHOD]]([[ARG]])
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%[0-9]+]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPER]])
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_1]]'
|
|
func a1() {
|
|
self.boom()
|
|
super.boom()
|
|
}
|
|
a1()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1byyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$s8closures8SuperSubC1b[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: = apply [[INNER]]([[SELF]])
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1byyF'
|
|
func b() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$s8closures8SuperSubC1b.*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: = apply [[INNER]]([[ARG]])
|
|
// CHECK: } // end sil function '[[INNER_FUNC_1]]'
|
|
func b1() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_2]] : $@convention(thin) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[CLASS_METHOD:%.*]] = class_method [[ARG]] : $SuperSub, #SuperSub.boom :
|
|
// CHECK: = apply [[CLASS_METHOD]]([[ARG]]) : $@convention(method) (@guaranteed SuperSub) -> ()
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%.*]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPER]]) : $@convention(method) (@guaranteed SuperBase)
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_2]]'
|
|
func b2() {
|
|
self.boom()
|
|
super.boom()
|
|
}
|
|
b2()
|
|
}
|
|
b1()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1cyyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$s8closures8SuperSubC1c[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
|
|
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[SELF_COPY]])
|
|
// CHECK: [[MOVED_PA:%.*]] = move_value [lexical] [var_decl] [[PA]]
|
|
// CHECK: [[B:%.*]] = begin_borrow [[MOVED_PA]]
|
|
// CHECK: [[B_COPY:%.*]] = copy_value [[B]]
|
|
// CHECK: [[B2:%.*]] = begin_borrow [[B_COPY]]
|
|
// CHECK: apply [[B2]]()
|
|
// CHECK: end_borrow [[B2]]
|
|
// CHECK: destroy_value [[B_COPY]]
|
|
// CHECK: end_borrow [[B]]
|
|
// CHECK: destroy_value [[MOVED_PA]]
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1cyyF'
|
|
func c() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[CLASS_METHOD:%.*]] = class_method [[ARG]] : $SuperSub, #SuperSub.boom :
|
|
// CHECK: = apply [[CLASS_METHOD]]([[ARG]]) : $@convention(method) (@guaranteed SuperSub) -> ()
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%[0-9]+]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPER]])
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_1]]'
|
|
let c1 = { () -> Void in
|
|
self.boom()
|
|
super.boom()
|
|
}
|
|
c1()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1dyyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$s8closures8SuperSubC1d[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
|
|
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[SELF_COPY]])
|
|
// CHECK: [[MOVED_PA:%.*]] = move_value [lexical] [var_decl] [[PA]]
|
|
// CHECK: [[B:%.*]] = begin_borrow [[MOVED_PA]]
|
|
// CHECK: [[PA_COPY:%.*]] = copy_value [[B]]
|
|
// CHECK: [[B2:%.*]] = begin_borrow [[PA_COPY]]
|
|
// CHECK: apply [[B2]]()
|
|
// CHECK: end_borrow [[B2]]
|
|
// CHECK: destroy_value [[B_COPY]]
|
|
// CHECK: end_borrow [[B]]
|
|
// CHECK: destroy_value [[MOVED_PA]]
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1dyyF'
|
|
func d() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$s8closures8SuperSubC1d.*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: = apply [[INNER]]([[ARG]])
|
|
// CHECK: } // end sil function '[[INNER_FUNC_1]]'
|
|
let d1 = { () -> Void in
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_2]] : $@convention(thin) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%.*]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPER]])
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_2]]'
|
|
func d2() {
|
|
super.boom()
|
|
}
|
|
d2()
|
|
}
|
|
d1()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1eyyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_NAME1:\$s8closures8SuperSubC1e[_0-9a-zA-Z]*]] : $@convention(thin)
|
|
// CHECK: = apply [[INNER]]([[SELF]])
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1eyyF'
|
|
func e() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_NAME1]] : $@convention(thin)
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_NAME2:\$s8closures8SuperSubC1e.*]] : $@convention(thin)
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[ARG_COPY]])
|
|
// CHECK: [[MOVED_PA:%.*]] = move_value [lexical] [var_decl] [[PA]]
|
|
// CHECK: [[B:%.*]] = begin_borrow [[MOVED_PA]]
|
|
// CHECK: [[PA_COPY:%.*]] = copy_value [[B]]
|
|
// CHECK: [[B2:%.*]] = begin_borrow [[PA_COPY]]
|
|
// CHECK: apply [[B2]]()
|
|
// CHECK: end_borrow [[B2]]
|
|
// CHECK: destroy_value [[B_COPY]]
|
|
// CHECK: end_borrow [[B]]
|
|
// CHECK: destroy_value [[MOVED_PA]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_NAME1]]'
|
|
func e1() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_NAME2]] : $@convention(thin)
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPERCAST:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%.*]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPERCAST]])
|
|
// CHECK: destroy_value [[ARG_COPY_SUPERCAST]]
|
|
// CHECK: return
|
|
// CHECK: } // end sil function '[[INNER_FUNC_NAME2]]'
|
|
let e2 = {
|
|
super.boom()
|
|
}
|
|
e2()
|
|
}
|
|
e1()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1fyyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$s8closures8SuperSubC1fyyFyycfU_]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
|
|
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[SELF_COPY]])
|
|
// CHECK: [[MOVED_PA:%.*]] = move_value [lexical] [var_decl] [[PA]]
|
|
// CHECK: destroy_value [[MOVED_PA]]
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1fyyF'
|
|
func f() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$s8closures8SuperSubC1fyyFyycfU_yyKXEfu_]] :
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[ARG_COPY]])
|
|
// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [not_guaranteed] [[PA]]
|
|
// CHECK: [[TRY_APPLY_AUTOCLOSURE:%.*]] = function_ref @$ss2qqoiyxxSgn_xyKXKtKRi_zlF :
|
|
// CHECK: try_apply [[TRY_APPLY_AUTOCLOSURE]]<()>({{.*}}, {{.*}}, [[CVT]]) : {{.*}}, normal [[NORMAL_BB:bb1]], error [[ERROR_BB:bb2]]
|
|
// CHECK: [[NORMAL_BB]]{{.*}}
|
|
// CHECK: } // end sil function '[[INNER_FUNC_1]]'
|
|
let f1 = {
|
|
// CHECK: sil private [transparent] [ossa] @[[INNER_FUNC_2]]
|
|
// CHECK: bb0({{.*}}, [[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%.*]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPER]]) : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_2]]'
|
|
nil ?? super.boom()
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures8SuperSubC1gyyF : $@convention(method) (@guaranteed SuperSub) -> () {
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_1:\$s8closures8SuperSubC1g[_0-9a-zA-Z]*]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: = apply [[INNER]]([[SELF]])
|
|
// CHECK: } // end sil function '$s8closures8SuperSubC1gyyF'
|
|
func g() {
|
|
// CHECK: sil private [ossa] @[[INNER_FUNC_1]] : $@convention(thin) (@guaranteed SuperSub) -> ()
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[INNER:%.*]] = function_ref @[[INNER_FUNC_2:\$s8closures8SuperSubC1g.*]] :
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[PA:%.*]] = partial_apply [callee_guaranteed] [[INNER]]([[ARG_COPY]])
|
|
// CHECK: [[CVT:%.*]] = convert_escape_to_noescape [not_guaranteed] [[PA]] :
|
|
// CHECK: [[TRY_APPLY_FUNC:%.*]] = function_ref @$ss2qqoiyxxSgn_xyKXKtKRi_zlF :
|
|
// CHECK: try_apply [[TRY_APPLY_FUNC]]<()>({{.*}}, {{.*}}, [[CVT]]) : {{.*}}, normal [[NORMAL_BB:bb1]], error [[ERROR_BB:bb2]]
|
|
// CHECK: [[NORMAL_BB]]{{.*}}
|
|
// CHECK: } // end sil function '[[INNER_FUNC_1]]'
|
|
func g1() {
|
|
// CHECK: sil private [transparent] [ossa] @[[INNER_FUNC_2]] :
|
|
// CHECK: bb0({{.*}}, [[ARG:%.*]] : @closureCapture @guaranteed $SuperSub):
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $SuperSub to $SuperBase
|
|
// CHECK: [[SUPER_METHOD:%.*]] = function_ref @$s8closures9SuperBaseC4boomyyF : $@convention(method) (@guaranteed SuperBase) -> ()
|
|
// CHECK: = apply [[SUPER_METHOD]]([[ARG_COPY_SUPER]])
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '[[INNER_FUNC_2]]'
|
|
nil ?? super.boom()
|
|
}
|
|
g1()
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures24UnownedSelfNestedCaptureC06nestedE0{{[_0-9a-zA-Z]*}}F : $@convention(method) (@guaranteed UnownedSelfNestedCapture) -> ()
|
|
// -- We enter with an assumed strong +1.
|
|
// CHECK: bb0([[SELF:%.*]] : @guaranteed $UnownedSelfNestedCapture):
|
|
// CHECK: [[OUTER_SELF_CAPTURE:%.*]] = alloc_box ${ var @sil_unowned UnownedSelfNestedCapture }
|
|
// CHECK: [[OUTER_SELF_LIFETIME:%.*]] = begin_borrow [lexical] [var_decl] [[OUTER_SELF_CAPTURE]]
|
|
// CHECK: [[PB:%.*]] = project_box [[OUTER_SELF_LIFETIME]]
|
|
// -- strong +2
|
|
// CHECK: [[SELF_COPY:%.*]] = copy_value [[SELF]]
|
|
// CHECK: [[UNOWNED_SELF:%.*]] = ref_to_unowned [[SELF_COPY]] :
|
|
// -- TODO: A lot of fussy r/r traffic and owned/unowned conversions here.
|
|
// -- strong +2, unowned +1
|
|
// CHECK: [[UNOWNED_SELF_COPY:%.*]] = copy_value [[UNOWNED_SELF]]
|
|
// CHECK: store [[UNOWNED_SELF_COPY]] to [init] [[PB]]
|
|
// SEMANTIC ARC TODO: This destroy_value should probably be /after/ the load from PB on the next line.
|
|
// CHECK: destroy_value [[SELF_COPY]]
|
|
// CHECK: [[UNOWNED_SELF:%.*]] = load_borrow [[PB]]
|
|
// -- strong +2, unowned +1
|
|
// CHECK: [[SELF:%.*]] = strong_copy_unowned_value [[UNOWNED_SELF]]
|
|
// CHECK: end_borrow [[UNOWNED_SELF]]
|
|
// CHECK: [[UNOWNED_SELF2:%.*]] = ref_to_unowned [[SELF]]
|
|
// -- strong +2, unowned +2
|
|
// CHECK: [[UNOWNED_SELF2_COPY:%.*]] = copy_value [[UNOWNED_SELF2]]
|
|
// -- strong +1, unowned +2
|
|
// CHECK: destroy_value [[SELF]]
|
|
// -- closure takes unowned ownership
|
|
// CHECK: [[OUTER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[UNOWNED_SELF2_COPY]])
|
|
// CHECK: [[OUTER_CONVERT:%.*]] = convert_escape_to_noescape [not_guaranteed] [[OUTER_CLOSURE]]
|
|
// CHECK: [[OUTER_CONVERT_B:%.*]] = begin_borrow [[OUTER_CONVERT]]
|
|
// -- call consumes closure
|
|
// -- strong +1, unowned +1
|
|
// CHECK: [[INNER_CLOSURE:%.*]] = apply [[OUTER_CONVERT_B]]
|
|
// CHECK: [[B:%.*]] = begin_borrow [[INNER_CLOSURE]]
|
|
// CHECK: [[CONSUMED_RESULT:%.*]] = apply [[B]]()
|
|
// CHECK: destroy_value [[CONSUMED_RESULT]]
|
|
// CHECK: destroy_value [[INNER_CLOSURE]]
|
|
// -- destroy_values unowned self in box
|
|
// -- strong +1, unowned +0
|
|
// CHECK: destroy_value [[OUTER_SELF_CAPTURE]]
|
|
// -- strong +0, unowned +0
|
|
// CHECK: } // end sil function '$s8closures24UnownedSelfNestedCaptureC06nestedE0{{[_0-9a-zA-Z]*}}F'
|
|
|
|
// -- outer closure
|
|
// -- strong +0, unowned +1
|
|
// CHECK: sil private [ossa] @[[OUTER_CLOSURE_FUN:\$s8closures24UnownedSelfNestedCaptureC06nestedE0yyFACycyXEfU_]] : $@convention(thin) (@guaranteed @sil_unowned UnownedSelfNestedCapture) -> @owned @callee_guaranteed () -> @owned UnownedSelfNestedCapture {
|
|
// CHECK: bb0([[CAPTURED_SELF:%.*]] : @closureCapture @guaranteed $@sil_unowned UnownedSelfNestedCapture):
|
|
// -- strong +0, unowned +2
|
|
// CHECK: [[CAPTURED_SELF_COPY:%.*]] = copy_value [[CAPTURED_SELF]] :
|
|
// -- closure takes ownership of unowned ref
|
|
// CHECK: [[INNER_CLOSURE:%.*]] = partial_apply [callee_guaranteed] {{%.*}}([[CAPTURED_SELF_COPY]])
|
|
// -- strong +0, unowned +1 (claimed by closure)
|
|
// CHECK: return [[INNER_CLOSURE]]
|
|
// CHECK: } // end sil function '[[OUTER_CLOSURE_FUN]]'
|
|
|
|
// -- inner closure
|
|
// -- strong +0, unowned +1
|
|
// CHECK: sil private [ossa] @[[INNER_CLOSURE_FUN:\$s8closures24UnownedSelfNestedCaptureC06nestedE0yyFACycyXEfU_ACycfU_]] : $@convention(thin) (@guaranteed @sil_unowned UnownedSelfNestedCapture) -> @owned UnownedSelfNestedCapture {
|
|
// CHECK: bb0([[CAPTURED_SELF:%.*]] : @closureCapture @guaranteed $@sil_unowned UnownedSelfNestedCapture):
|
|
// -- strong +1, unowned +1
|
|
// CHECK: [[SELF:%.*]] = strong_copy_unowned_value [[CAPTURED_SELF:%.*]] :
|
|
// -- strong +1, unowned +0 (claimed by return)
|
|
// CHECK: return [[SELF]]
|
|
// CHECK: } // end sil function '[[INNER_CLOSURE_FUN]]'
|
|
class UnownedSelfNestedCapture {
|
|
func nestedCapture() {
|
|
{[unowned self] in { self } }()()
|
|
}
|
|
}
|
|
|
|
// Check that capturing 'self' via a 'super' call also captures the generic
|
|
// signature if the base class is concrete and the derived class is generic
|
|
|
|
class ConcreteBase {
|
|
func swim() {}
|
|
}
|
|
|
|
// CHECK-LABEL: sil private [ossa] @$s8closures14GenericDerivedC4swimyyFyyXEfU_ : $@convention(thin) <Ocean> (@guaranteed GenericDerived<Ocean>) -> ()
|
|
// CHECK: bb0([[ARG:%.*]] : @closureCapture @guaranteed $GenericDerived<Ocean>):
|
|
// CHECK: [[ARG_COPY:%.*]] = copy_value [[ARG]]
|
|
// CHECK: [[ARG_COPY_SUPER:%.*]] = upcast [[ARG_COPY]] : $GenericDerived<Ocean> to $ConcreteBase
|
|
// CHECK: [[METHOD:%.*]] = function_ref @$s8closures12ConcreteBaseC4swimyyF
|
|
// CHECK: apply [[METHOD]]([[ARG_COPY_SUPER]]) : $@convention(method) (@guaranteed ConcreteBase) -> ()
|
|
// CHECK: destroy_value [[ARG_COPY_SUPER]]
|
|
// CHECK: } // end sil function '$s8closures14GenericDerivedC4swimyyFyyXEfU_'
|
|
|
|
class GenericDerived<Ocean> : ConcreteBase {
|
|
override func swim() {
|
|
withFlotationAid {
|
|
super.swim()
|
|
}
|
|
}
|
|
|
|
func withFlotationAid(_ fn: () -> ()) {}
|
|
}
|
|
|
|
// Don't crash on this
|
|
func r25993258_helper(_ fn: (inout Int, Int) -> ()) {}
|
|
func r25993258() {
|
|
r25993258_helper { _, _ in () }
|
|
}
|
|
|
|
// rdar://29810997
|
|
//
|
|
// Using a let from a closure in an init was causing the type-checker
|
|
// to produce invalid AST: 'self.fn' was an l-value, but 'self' was already
|
|
// loaded to make an r-value. This was ultimately because CSApply was
|
|
// building the member reference correctly in the context of the closure,
|
|
// where 'fn' is not settable, but CSGen / CSSimplify was processing it
|
|
// in the general DC of the constraint system, i.e. the init, where
|
|
// 'fn' *is* settable.
|
|
func r29810997_helper(_ fn: (Int) -> Int) -> Int { return fn(0) }
|
|
struct r29810997 {
|
|
private let fn: (Int) -> Int
|
|
private var x: Int
|
|
|
|
init(function: @escaping (Int) -> Int) {
|
|
fn = function
|
|
x = r29810997_helper { fn($0) }
|
|
}
|
|
}
|
|
|
|
// DI will turn this into a direct capture of the specific stored property.
|
|
// CHECK-LABEL: sil hidden [ossa] @$s8closures16r29810997_helperyS3iXEF : $@convention(thin) (@guaranteed @noescape @callee_guaranteed (Int) -> Int) -> Int
|
|
|
|
// rdar://problem/37790062
|
|
|
|
protocol P_37790062 {
|
|
associatedtype T
|
|
var elt: T { get }
|
|
}
|
|
|
|
func rdar37790062() {
|
|
struct S<T> {
|
|
init(_ a: () -> T, _ b: () -> T) {}
|
|
}
|
|
|
|
class C1 : P_37790062 {
|
|
typealias T = Int
|
|
var elt: T { return 42 }
|
|
}
|
|
|
|
class C2 : P_37790062 {
|
|
typealias T = (String, Int, Void)
|
|
var elt: T { return ("question", 42, ()) }
|
|
}
|
|
|
|
func foo() -> Int { return 42 }
|
|
func bar() -> Void {}
|
|
func baz() -> (String, Int) { return ("question", 42) }
|
|
func bzz<T>(_ a: T) -> T { return a }
|
|
func faz<T: P_37790062>(_ a: T) -> T.T { return a.elt }
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU0_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ foo() }, { bar() })
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU1_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU2_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ baz() }, { bar() })
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU3_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU4_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ bzz(("question", 42)) }, { bar() })
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU5_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU6_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ bzz(String.self) }, { bar() })
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU7_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU8_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ bzz(((), (()))) }, { bar() })
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU9_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU10_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ bzz(C1()) }, { bar() })
|
|
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU11_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyFyyXEfU12_
|
|
// CHECK: function_ref @$s8closures12rdar37790062yyF1SL_VyADyxGxyXE_xyXEtcfC
|
|
_ = S({ faz(C2()) }, { bar() })
|
|
}
|
|
|
|
// Make sure that if we capture a trivial value, we do not try to copy it. This
|
|
// violates SIL invariants and the SILVerifier will explode as such.
|
|
func closeOverStructDontCopyTrivial() {
|
|
let a : StructWithMutatingMethod
|
|
a = StructWithMutatingMethod()
|
|
takeClosure { a.x }
|
|
}
|
|
|
|
// Make sure that we handle closure argument initialization when due to forward
|
|
// declaration we represent a let as an lvalue
|
|
func test() {
|
|
let k: SomeClass
|
|
let k2: SomeClass
|
|
var boolean: Bool { true }
|
|
|
|
if boolean {
|
|
k = SomeClass()
|
|
k2 = SomeClass()
|
|
} else {
|
|
k = SomeClass()
|
|
k2 = SomeClass()
|
|
}
|
|
|
|
assert(k.x == k2.x)
|
|
}
|
|
|