blob: 90942f5669e1a7042ce9eb6453452e124eb0d4b1 [file] [log] [blame]
// RUN: %target-swift-emit-silgen -parse-as-library -module-name Swift -parse-stdlib %s | %FileCheck %s
// This test checks specific codegen related to converting curry thunks to
// canonical representations when we are emitting guaranteed normal
// arguments. Eventually it will be merged into the normal SILGen tests.
//////////////////
// Declarations //
//////////////////
precedencegroup AssignmentPrecedence {
assignment: true
}
enum Optional<T> {
case none
case some(T)
}
func _diagnoseUnexpectedNilOptional(_filenameStart: Builtin.RawPointer,
_filenameLength: Builtin.Word,
_filenameIsASCII: Builtin.Int1,
_line: Builtin.Word) {
// This would usually contain an assert, but we don't need one since we are
// just emitting SILGen.
}
class Klass {
init() {}
}
typealias AnyObject = Builtin.AnyObject
protocol ProtocolInitNoArg {
init()
}
protocol ClassProtocolInitNoArg : class {
init()
}
protocol ProtocolInitAddressOnly {
associatedtype SubType : ProtocolInitNoArg
init(t: SubType)
init(t2: AddrOnlyStructInitGeneric<Klass>)
init(t3: AddrOnlyStructInitGeneric<SubType>)
}
protocol ProtocolInitClassProtocol {
associatedtype SubType : ClassProtocolInitNoArg
init(t: SubType)
}
protocol ProtocolInitLoadable {
init(t: Klass)
}
protocol ClassProtocolInitAddressOnly : class {
associatedtype SubType : ProtocolInitNoArg
init(t: SubType)
}
protocol ClassProtocolInitClassProtocol : class {
associatedtype SubType : ClassProtocolInitNoArg
init(t: SubType)
}
protocol ClassProtocolInitLoadable : class {
init(t: Klass)
}
class LoadableClassInitLoadable {
init(_ k: Klass) {}
}
struct LoadableStructInitLoadable {
var k: Klass
init(_ newK: Klass) {
k = newK
}
}
struct AddrOnlyStructInitGeneric<T> {
var k: T
init(_ newK: T) {
k = newK
}
}
///////////
// Tests //
///////////
// CHECK-LABEL: sil hidden [ossa] @$ss021testLoadableClassInitB0yyF : $@convention(thin) () -> () {
// CHECK: bb0:
// CHECK: [[THUNK_REF:%.*]] = function_ref @$ss017LoadableClassInitA0CyABs5KlassCcfCTcTd : $@convention(thin) (@thick LoadableClassInitLoadable.Type) -> @owned @callee_guaranteed (@guaranteed Klass) -> @owned LoadableClassInitLoadable
// CHECK: [[CANONICAL_THUNK:%.*]] = apply [[THUNK_REF]](
// CHECK: [[BORROWED_CANONICAL_THUNK:%.*]] = begin_borrow [[CANONICAL_THUNK]]
// CHECK: [[BORROWED_CANONICAL_THUNK_COPY:%.*]] = copy_value [[BORROWED_CANONICAL_THUNK]]
// CHECK: [[ALLOCATING_INIT:%.*]] = function_ref @$ss5KlassCABycfC : $@convention(method) (@thick Klass.Type) -> @owned Klass
// CHECK: [[SELF:%.*]] = apply [[ALLOCATING_INIT]](
// CHECK: [[BORROWED_CANONICAL_THUNK:%.*]] = begin_borrow [[BORROWED_CANONICAL_THUNK_COPY]]
// CHECK: apply [[BORROWED_CANONICAL_THUNK]]([[SELF]])
// CHECK: } // end sil function '$ss021testLoadableClassInitB0yyF'
// Curry thunk.
//
// CHECK-LABEL: sil shared [thunk] [ossa] @$ss017LoadableClassInitA0CyABs5KlassCcfCTcTd : $@convention(thin) (@thick LoadableClassInitLoadable.Type) -> @owned @callee_guaranteed (@guaranteed Klass) -> @owned LoadableClassInitLoadable {
// CHECK: [[ALLOCATING_INIT_FN:%.*]] = function_ref @$ss017LoadableClassInitA0CyABs5KlassCcfC :
// CHECK: [[METATYPE_PA_ALLOCATING_INIT_FN:%.*]] = partial_apply [callee_guaranteed] [[ALLOCATING_INIT_FN]](
// CHECK: [[THUNK_FN:%.*]] = function_ref @$ss5KlassCs017LoadableClassInitB0CIegxo_AbDIeggo_TR :
// CHECK: [[THUNK_PA:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[METATYPE_PA_ALLOCATING_INIT_FN]]) : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @owned LoadableClassInitLoadable) -> @owned LoadableClassInitLoadable
// CHECK: return [[THUNK_PA]]
// CHECK: } // end sil function '$ss017LoadableClassInitA0CyABs5KlassCcfCTcTd'
// Reabstraction thunk.
//
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$ss5KlassCs017LoadableClassInitB0CIegxo_AbDIeggo_TR : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @owned LoadableClassInitLoadable) -> @owned LoadableClassInitLoadable {
// CHECK: bb0([[CLASS:%.*]] : @guaranteed $Klass, [[PA:%.*]] : @guaranteed $@callee_guaranteed (@owned Klass) -> @owned LoadableClassInitLoadable):
// CHECK: [[CLASS_COPY:%.*]] = copy_value [[CLASS]]
// CHECK: [[RESULT:%.*]] = apply [[PA]]([[CLASS_COPY]])
// CHECK: return [[RESULT]]
// CHECK: } // end sil function '$ss5KlassCs017LoadableClassInitB0CIegxo_AbDIeggo_TR'
func testLoadableClassInitLoadable() {
let x = LoadableClassInitLoadable.init
let y = x(Klass())
}
// CHECK-LABEL: sil hidden [ossa] @$ss022testLoadableStructInitB0yyF : $@convention(thin) () -> () {
// CHECK: [[THUNK_REF:%.*]] = function_ref @$ss018LoadableStructInitA0VyABs5KlassCcfCTc : $@convention(thin) (@thin LoadableStructInitLoadable.Type) -> @owned @callee_guaranteed (@guaranteed Klass) -> @owned LoadableStructInitLoadable
// CHECK: [[CANONICAL_THUNK:%.*]] = apply [[THUNK_REF]](
// CHECK: [[BORROWED_CANONICAL_THUNK:%.*]] = begin_borrow [[CANONICAL_THUNK]]
// CHECK: [[BORROWED_CANONICAL_THUNK_COPY:%.*]] = copy_value [[BORROWED_CANONICAL_THUNK]]
// CHECK: [[ALLOCATING_INIT:%.*]] = function_ref @$ss5KlassCABycfC : $@convention(method) (@thick Klass.Type) -> @owned Klass
// CHECK: [[SELF:%.*]] = apply [[ALLOCATING_INIT]](
// CHECK: [[BORROWED_CANONICAL_THUNK:%.*]] = begin_borrow [[BORROWED_CANONICAL_THUNK_COPY]]
// CHECK: apply [[BORROWED_CANONICAL_THUNK]]([[SELF]])
// CHECK: } // end sil function '$ss022testLoadableStructInitB0yyF'
// Curry thunk.
//
// CHECK-LABEL: sil shared [thunk] [ossa] @$ss018LoadableStructInitA0VyABs5KlassCcfCTc : $@convention(thin) (@thin LoadableStructInitLoadable.Type) -> @owned @callee_guaranteed (@guaranteed Klass) -> @owned LoadableStructInitLoadable {
// CHECK: [[ALLOCATING_INIT_FN:%.*]] = function_ref @$ss018LoadableStructInitA0VyABs5KlassCcfC :
// CHECK: [[METATYPE_PA_ALLOCATING_INIT_FN:%.*]] = partial_apply [callee_guaranteed] [[ALLOCATING_INIT_FN]](
// CHECK: [[THUNK_FN:%.*]] = function_ref @$ss5KlassCs018LoadableStructInitB0VIegxo_AbDIeggo_TR : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @owned LoadableStructInitLoadable) -> @owned LoadableStructInitLoadable
// CHECK: [[THUNK_PA:%.*]] = partial_apply [callee_guaranteed] [[THUNK_FN]]([[METATYPE_PA_ALLOCATING_INIT_FN]])
// CHECK: return [[THUNK_PA]]
// CHECK: } // end sil function '$ss018LoadableStructInitA0VyABs5KlassCcfCTc'
// Reabstraction thunk.
//
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$ss5KlassCs018LoadableStructInitB0VIegxo_AbDIeggo_TR : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @owned LoadableStructInitLoadable) -> @owned LoadableStructInitLoadable {
// CHECK: bb0([[CLASS:%.*]] : @guaranteed $Klass, [[PA:%.*]] : @guaranteed $@callee_guaranteed (@owned Klass) -> @owned LoadableStructInitLoadable):
// CHECK: [[CLASS_COPY:%.*]] = copy_value [[CLASS]]
// CHECK: [[RESULT:%.*]] = apply [[PA]]([[CLASS_COPY]])
// CHECK: return [[RESULT]]
// CHECK: } // end sil function '$ss5KlassCs018LoadableStructInitB0VIegxo_AbDIeggo_TR'
func testLoadableStructInitLoadable() {
let x = LoadableStructInitLoadable.init
let y = x(Klass())
}
// In this case we have a generic type that due to type lowering introduces an
// extra thunk.
//
// CHECK-LABEL: sil hidden [ossa] @$ss37testAddrOnlyStructInitGenericConcreteyyF : $@convention(thin) () -> () {
// CHECK: [[THUNK_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <τ_0_0> (@thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @owned @callee_guaranteed (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_0>
// CHECK: [[CURRY_THUNK:%.*]] = apply [[THUNK_REF]]<Klass>(
// CHECK: [[CANONICAL_THUNK_REF:%.*]] = function_ref @$ss5KlassCs25AddrOnlyStructInitGenericVyABGIegnr_AbEIeggo_TR : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@in_guaranteed Klass) -> @out AddrOnlyStructInitGeneric<Klass>) -> @owned AddrOnlyStructInitGeneric<Klass>
// CHECK: [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] [[CANONICAL_THUNK_REF]]([[CURRY_THUNK]]) :
// CHECK: [[BORROWED_CANONICAL_THUNK:%.*]] = begin_borrow [[CANONICAL_THUNK]]
// CHECK: [[BORROWED_CANONICAL_THUNK_COPY:%.*]] = copy_value [[BORROWED_CANONICAL_THUNK]]
// CHECK: [[ALLOCATING_INIT:%.*]] = function_ref @$ss5KlassCABycfC : $@convention(method) (@thick Klass.Type) -> @owned Klass
// CHECK: [[SELF:%.*]] = apply [[ALLOCATING_INIT]](
// CHECK: [[BORROWED_CANONICAL_THUNK:%.*]] = begin_borrow [[BORROWED_CANONICAL_THUNK_COPY]]
// CHECK: apply [[BORROWED_CANONICAL_THUNK]]([[SELF]])
// Curry thunk
//
// CHECK-LABEL: sil shared [thunk] [ossa] @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <T> (@thin AddrOnlyStructInitGeneric<T>.Type) -> @owned @callee_guaranteed (@in_guaranteed T) -> @out AddrOnlyStructInitGeneric<T> {
// CHECK: [[ALLOCATING_INIT_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfC : $@convention(method) <τ_0_0> (@in τ_0_0, @thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @out AddrOnlyStructInitGeneric<τ_0_0>
// CHECK: [[ALLOCATING_INIT:%.*]] = partial_apply [callee_guaranteed] [[ALLOCATING_INIT_REF]]<T>(
// CHECK: [[THUNK_REF:%.*]] = function_ref @$sxs25AddrOnlyStructInitGenericVyxGIegir_xACIegnr_lTR : $@convention(thin) <τ_0_0> (@in_guaranteed τ_0_0, @guaranteed @callee_guaranteed (@in τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_0>) -> @out AddrOnlyStructInitGeneric<τ_0_0>
// CHECK: [[THUNK:%.*]] = partial_apply [callee_guaranteed] [[THUNK_REF]]<T>([[ALLOCATING_INIT]])
// CHECK: return [[THUNK]]
// CHECK: } // end sil function '$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc'
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$sxs25AddrOnlyStructInitGenericVyxGIegir_xACIegnr_lTR : $@convention(thin) <T> (@in_guaranteed T, @guaranteed @callee_guaranteed (@in T) -> @out AddrOnlyStructInitGeneric<T>) -> @out AddrOnlyStructInitGeneric<T> {
// CHECK: bb0([[ARG0:%.*]] : $*AddrOnlyStructInitGeneric<T>, [[ARG1:%.*]] : $*T, [[ARG2:%.*]] : @guaranteed $@callee_guaranteed (@in T) -> @out AddrOnlyStructInitGeneric<T>):
// CHECK: [[STACK:%.*]] = alloc_stack $T
// CHECK: copy_addr [[ARG1]] to [initialization] [[STACK]] : $*T
// CHECK: apply [[ARG2]]([[ARG0]], [[STACK]]) : $@callee_guaranteed (@in T) -> @out AddrOnlyStructInitGeneric<T>
// CHECK: } // end sil function '$sxs25AddrOnlyStructInitGenericVyxGIegir_xACIegnr_lTR'
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$ss5KlassCs25AddrOnlyStructInitGenericVyABGIegnr_AbEIeggo_TR : $@convention(thin) (@guaranteed Klass, @guaranteed @callee_guaranteed (@in_guaranteed Klass) -> @out AddrOnlyStructInitGeneric<Klass>) -> @owned AddrOnlyStructInitGeneric<Klass> {
// CHECK: bb0([[ARG0:%.*]] : @guaranteed $Klass, [[ARG1:%.*]] : @guaranteed $@callee_guaranteed (@in_guaranteed Klass) -> @out AddrOnlyStructInitGeneric<Klass>):
// CHECK: [[STACK:%.*]] = alloc_stack $Klass
// CHECK: [[ARG0_COPY:%.*]] = copy_value [[ARG0]]
// CHECK: store [[ARG0_COPY]] to [init] [[STACK]]
// CHECK: [[STACK2:%.*]] = alloc_stack $AddrOnlyStructInitGeneric<Klass>
// CHECK: apply [[ARG1]]([[STACK2]], [[STACK]]) : $@callee_guaranteed (@in_guaranteed Klass) -> @out AddrOnlyStructInitGeneric<Klass>
// CHECK: [[RESULT:%.*]] = load [take] [[STACK2]]
// CHECK: destroy_addr [[STACK]]
// CHECK: return [[RESULT]]
// CHECK: } // end sil function '$ss5KlassCs25AddrOnlyStructInitGenericVyABGIegnr_AbEIeggo_TR'
func testAddrOnlyStructInitGenericConcrete() {
let x = AddrOnlyStructInitGeneric<Klass>.init
let y = x(Klass())
}
// CHECK-LABEL: sil hidden [ossa] @$ss029testAddrOnlyStructInitGenericbC01tyx_ts08Protocole7AddressC0RzlF : $@convention(thin) <T where T : ProtocolInitAddressOnly> (@in_guaranteed T) -> () {
// CHECK: [[CURRY_THUNK_REF:%.*]] = function_ref @$ss25AddrOnlyStructInitGenericVyAByxGxcfCTc : $@convention(thin) <τ_0_0> (@thin AddrOnlyStructInitGeneric<τ_0_0>.Type) -> @owned @callee_guaranteed (@in_guaranteed τ_0_0) -> @out AddrOnlyStructInitGeneric<τ_0_0>
// CHECK: [[CURRY_THUNK:%.*]] = apply [[CURRY_THUNK_REF]]<T.SubType>(
// CHECK: [[Y:%.*]] = alloc_stack $AddrOnlyStructInitGeneric<T.SubType>, let, name "y"
// CHECK: [[BORROWED_CURRY_THUNK:%.*]] = begin_borrow [[CURRY_THUNK]]
// CHECK: [[COPY_BORROWED_CURRY_THUNK:%.*]] = copy_value [[BORROWED_CURRY_THUNK]]
// CHECK: [[TMP:%.*]] = alloc_stack $T.SubType
// CHECK: [[WITNESS_METHOD:%.*]] = witness_method $T.SubType, #ProtocolInitNoArg.init!allocator.1 : <Self where Self : ProtocolInitNoArg> (Self.Type) -> () -> Self : $@convention(witness_method: ProtocolInitNoArg) <τ_0_0 where τ_0_0 : ProtocolInitNoArg> (@thick τ_0_0.Type) -> @out τ_0_0
// CHECK: apply [[WITNESS_METHOD]]<T.SubType>([[TMP]],
// CHECK: [[BORROWED_CURRY_THUNK:%.*]] = begin_borrow [[COPY_BORROWED_CURRY_THUNK]]
// CHECK: apply [[BORROWED_CURRY_THUNK]]([[Y]], [[TMP]])
// CHECK: } // end sil function '$ss029testAddrOnlyStructInitGenericbC01tyx_ts08Protocole7AddressC0RzlF'
func testAddrOnlyStructInitGenericAddrOnly<T : ProtocolInitAddressOnly>(t: T) {
let x = AddrOnlyStructInitGeneric<T.SubType>.init
let y = x(T.SubType())
}
// CHECK-LABEL: sil hidden [ossa] @$ss20testGenericInitClass1tyx_ts08ProtocolC8LoadableRzlF : $@convention(thin) <T where T : ProtocolInitLoadable> (@in_guaranteed T) -> () {
// CHECK: [[CURRY_THUNK_REF:%.*]] = function_ref @$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc : $@convention(thin) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@thick τ_0_0.Type) -> @owned @callee_guaranteed (@guaranteed Klass) -> @out τ_0_0
// CHECK: [[CURRY_THUNK:%.*]] = apply [[CURRY_THUNK_REF]]<T>(
// CHECK: [[Y:%.*]] = alloc_stack $T, let, name "y"
// CHECK: [[BORROWED_CURRY_THUNK:%.*]] = begin_borrow [[CURRY_THUNK]]
// CHECK: [[COPY_BORROWED_CURRY_THUNK:%.*]] = copy_value [[BORROWED_CURRY_THUNK]]
// CHECK: [[ALLOCATING_INIT:%.*]] = function_ref @$ss5KlassCABycfC : $@convention(method) (@thick Klass.Type) -> @owned Klass
// CHECK: [[SELF:%.*]] = apply [[ALLOCATING_INIT]](
// CHECK: [[BORROWED_CURRY_THUNK:%.*]] = begin_borrow [[COPY_BORROWED_CURRY_THUNK]]
// CHECK: apply [[BORROWED_CURRY_THUNK]]([[Y]], [[SELF]])
// CHECK: } // end sil function '$ss20testGenericInitClass1tyx_ts08ProtocolC8LoadableRzlF'
// Curry thunk.
//
// CHECK-LABEL: sil shared [thunk] [ossa] @$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc : $@convention(thin) <Self where Self : ProtocolInitLoadable> (@thick Self.Type) -> @owned @callee_guaranteed (@guaranteed Klass) -> @out Self {
// CHECK: [[WITNESS_METHOD_REF:%.*]] = witness_method $Self, #ProtocolInitLoadable.init!allocator.1 : <Self where Self : ProtocolInitLoadable> (Self.Type) -> (Klass) -> Self : $@convention(witness_method: ProtocolInitLoadable) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@owned Klass, @thick τ_0_0.Type) -> @out τ_0_0
// CHECK: [[WITNESS_METHOD:%.*]] = partial_apply [callee_guaranteed] [[WITNESS_METHOD_REF]]<Self>(
// CHECK: [[CANONICAL_THUNK_REF:%.*]] = function_ref @$ss5KlassCxIegxr_ABxIeggr_s20ProtocolInitLoadableRzlTR : $@convention(thin) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @out τ_0_0) -> @out τ_0_0
// CHECK: [[CANONICAL_THUNK:%.*]] = partial_apply [callee_guaranteed] %3<Self>(%2) : $@convention(thin) <τ_0_0 where τ_0_0 : ProtocolInitLoadable> (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @out τ_0_0) -> @out τ_0_0
// CHECK: return [[CANONICAL_THUNK]]
// CHECK: } // end sil function '$ss20ProtocolInitLoadableP1txs5KlassC_tcfCTc'
// Reabstraction thunk.
//
// CHECK-LABEL: sil shared [transparent] [serializable] [reabstraction_thunk] [ossa] @$ss5KlassCxIegxr_ABxIeggr_s20ProtocolInitLoadableRzlTR : $@convention(thin) <Self where Self : ProtocolInitLoadable> (@guaranteed Klass, @guaranteed @callee_guaranteed (@owned Klass) -> @out Self) -> @out Self {
// CHECK: bb0([[ARG0:%.*]] : $*Self, [[ARG1:%.*]] : @guaranteed $Klass, [[ARG2:%.*]] : @guaranteed $@callee_guaranteed (@owned Klass) -> @out Self):
// CHECK: [[ARG1_COPY:%.*]] = copy_value [[ARG1]]
// CHECK: apply [[ARG2]]([[ARG0]], [[ARG1_COPY]])
// CHECK: } // end sil function '$ss5KlassCxIegxr_ABxIeggr_s20ProtocolInitLoadableRzlTR'
func testGenericInitClass<T : ProtocolInitLoadable>(t: T) {
let x = T.init
let y = x(Klass())
}