mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
In @objc protocols, the initializing entry point is witnessed (as an -init method) rather than the allocating entry point, so the extension initializer needs to allocate the object and delegate to the initializing constructor. Swift SVN r27940
310 lines
15 KiB
Swift
310 lines
15 KiB
Swift
// RUN: %target-swift-frontend -disable-objc-attr-requires-foundation-module -emit-silgen %s | FileCheck %s
|
|
|
|
public protocol P1 {
|
|
func reqP1a()
|
|
}
|
|
|
|
extension P1 {
|
|
// CHECK-LABEL: sil hidden @_TFP19protocol_extensions2P16extP1aUS0___fQPS0_FT_T_ : $@convention(method) <Self where Self : P1> (@in_guaranteed Self) -> () {
|
|
// CHECK-NEXT: bb0([[SELF:%[0-9]+]] : $*Self):
|
|
final func extP1a() {
|
|
// CHECK: [[WITNESS:%[0-9]+]] = witness_method $Self, #P1.reqP1a!1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
|
|
// CHECK-NEXT: apply [[WITNESS]]<Self>([[SELF]]) : $@convention(witness_method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
|
|
reqP1a()
|
|
// CHECK: return
|
|
}
|
|
|
|
// CHECK-LABEL: sil @_TFP19protocol_extensions2P16extP1bUS0___fQPS0_FT_T_ : $@convention(method) <Self where Self : P1> (@in_guaranteed Self) -> () {
|
|
// CHECK-NEXT: bb0([[SELF:%[0-9]+]] : $*Self):
|
|
public final func extP1b() {
|
|
// CHECK: [[FN:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P16extP1aUS0___fQPS0_FT_T_ : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
|
|
// CHECK-NEXT: apply [[FN]]<Self>([[SELF]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
|
|
extP1a()
|
|
// CHECK: return
|
|
}
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Using protocol extension members with concrete types
|
|
// ----------------------------------------------------------------------------
|
|
class C : P1 {
|
|
func reqP1a() { }
|
|
}
|
|
|
|
class D : C { }
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions5testDFCS_1DT_ : $@convention(thin) (@owned D) -> () {
|
|
// CHECK-NEXT: bb0([[D:%[0-9]+]] : $D):
|
|
func testD(d: D) {
|
|
// CHECK: [[D2:%[0-9]+]] = alloc_box $D
|
|
// CHECK: [[FN:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P111returnsSelfUS0___fQPS0_FT_S1_
|
|
// CHECK: [[DCOPY:%[0-9]+]] = alloc_stack $D
|
|
// CHECK: store [[D]] to [[DCOPY]]#1 : $*D
|
|
// CHECK: [[RESULT:%[0-9]+]] = alloc_stack $D
|
|
// CHECK: apply [[FN]]<D>([[RESULT]]#1, [[DCOPY]]#1) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@out τ_0_0, @in_guaranteed τ_0_0) -> ()
|
|
var d2: D = d.returnsSelf()
|
|
}
|
|
|
|
// ----------------------------------------------------------------------------
|
|
// Using protocol extension members with existentials
|
|
// ----------------------------------------------------------------------------
|
|
extension P1 {
|
|
final func f1() { }
|
|
|
|
final func curried1(b: Bool)(_ i: Int64) { }
|
|
|
|
final subscript (i: Int64) -> Bool {
|
|
get { return true }
|
|
}
|
|
|
|
final var prop: Bool {
|
|
get { return true }
|
|
}
|
|
|
|
final func returnsSelf() -> Self { return self }
|
|
|
|
final var prop2: Bool {
|
|
get { return true }
|
|
set { }
|
|
}
|
|
|
|
final subscript (b: Bool) -> Bool {
|
|
get { return b }
|
|
set { }
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions17testExistentials1
|
|
// CHECK: bb0([[P:%[0-9]+]] : $*P1, [[B:%[0-9]+]] : $Bool, [[I:%[0-9]+]] : $Int64):
|
|
func testExistentials1(p1: P1, b: Bool, i: Int64) {
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]])
|
|
// CHECK: [[F1:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P12f1US0___fQPS0_FT_T_
|
|
// CHECK: apply [[F1]]<@opened([[UUID]]) P1>([[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> ()
|
|
p1.f1()
|
|
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: [[CURRIED1:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P18curried1US0___fQPS0_fSbFVSs5Int64T_
|
|
// CHECK: [[CURRIED1]]<@opened([[UUID]]) P1>([[I]], [[B]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Int64, Bool, @in_guaranteed τ_0_0) -> ()
|
|
p1.curried1(b)(i)
|
|
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]]#1
|
|
// CHECK: [[GETTER:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1g9subscriptFVSs5Int64Sb
|
|
// CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[I]], [[POPENED_COPY]]#1) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Int64, @in_guaranteed τ_0_0) -> Bool
|
|
// CHECK: destroy_addr [[POPENED_COPY]]#1
|
|
// CHECK: store{{.*}} : $*Bool
|
|
// CHECK: dealloc_stack [[POPENED_COPY]]
|
|
var b2 = p1[i]
|
|
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]]#1
|
|
// CHECK: [[GETTER:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1g4propSb
|
|
// CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[POPENED_COPY]]#1) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool
|
|
// CHECK: store{{.*}} : $*Bool
|
|
// CHECK: dealloc_stack [[POPENED_COPY]]
|
|
var b3 = p1.prop
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions17testExistentials2
|
|
// CHECK: bb0([[P:%[0-9]+]] : $*P1):
|
|
func testExistentials2(p1: P1) {
|
|
// CHECK: [[P1A:%[0-9]+]] = alloc_box $P1
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: [[P1AINIT:%[0-9]+]] = init_existential_addr [[P1A]]#1 : $*P1, $@opened([[UUID2:".*"]]) P1
|
|
// CHECK: [[FN:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P111returnsSelfUS0___fQPS0_FT_S1_
|
|
// CHECK: apply [[FN]]<@opened([[UUID]]) P1>([[P1AINIT]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@out τ_0_0, @in_guaranteed τ_0_0) -> ()
|
|
var p1a: P1 = p1.returnsSelf()
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions23testExistentialsGetters
|
|
// CHECK: bb0([[P:%[0-9]+]] : $*P1):
|
|
func testExistentialsGetters(p1: P1) {
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]]#1
|
|
// CHECK: [[FN:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1g5prop2Sb
|
|
// CHECK: [[B:%[0-9]+]] = apply [[FN]]<@opened([[UUID]]) P1>([[POPENED_COPY]]#1) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (@in_guaranteed τ_0_0) -> Bool
|
|
let b: Bool = p1.prop2
|
|
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[P]] : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: copy_addr [[POPENED]] to [initialization] [[POPENED_COPY:%.*]]#1
|
|
// CHECK: [[GETTER:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1g9subscriptFSbSb
|
|
// CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[B]], [[POPENED_COPY]]#1) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @in_guaranteed τ_0_0) -> Bool
|
|
let b2: Bool = p1[b]
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions22testExistentialSetters
|
|
// CHECK: bb0([[P:%[0-9]+]] : $*P1, [[B:%[0-9]+]] : $Bool):
|
|
func testExistentialSetters(var p1: P1, b: Bool) {
|
|
// CHECK: [[PBOX:%[0-9]+]] = alloc_box $P1
|
|
// CHECK-NEXT: copy_addr [take] [[P]] to [initialization] [[PBOX]]#1 : $*P1
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[PBOX]]#1 : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: [[GETTER:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1s5prop2Sb
|
|
// CHECK: apply [[GETTER]]<@opened([[UUID]]) P1>([[B]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> ()
|
|
// CHECK-NOT: deinit_existential_addr
|
|
p1.prop2 = b
|
|
|
|
// CHECK: [[POPENED:%[0-9]+]] = open_existential_addr [[PBOX]]#1 : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: [[SUBSETTER:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1s9subscriptFSbSb
|
|
// CHECK: apply [[SUBSETTER]]<@opened([[UUID]]) P1>([[B]], [[B]], [[POPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, Bool, @inout τ_0_0) -> ()
|
|
// CHECK-NOT: deinit_existential_addr [[PBOX]]#1 : $*P1
|
|
p1[b] = b
|
|
|
|
// CHECK: return
|
|
}
|
|
|
|
struct HasAP1 {
|
|
var p1: P1
|
|
|
|
var someP1: P1 {
|
|
get { return p1 }
|
|
set { p1 = newValue }
|
|
}
|
|
}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions29testLogicalExistentialSetters
|
|
// CHECK: bb0([[HASP1:%[0-9]+]] : $*HasAP1, [[B:%[0-9]+]] : $Bool)
|
|
func testLogicalExistentialSetters(var hasAP1: HasAP1, _ b: Bool) {
|
|
// CHECK: [[HASP1_BOX:%[0-9]+]] = alloc_box $HasAP1
|
|
// CHECK-NEXT: copy_addr [take] [[HASP1]] to [initialization] [[HASP1_BOX]]#1 : $*HasAP1
|
|
// CHECK: [[P1_COPY:%[0-9]+]] = alloc_stack $P1
|
|
// CHECK-NEXT: [[HASP1_COPY:%[0-9]+]] = alloc_stack $HasAP1
|
|
// CHECK-NEXT: copy_addr [[HASP1_BOX]]#1 to [initialization] [[HASP1_COPY]]#1 : $*HasAP1
|
|
// CHECK: [[SOMEP1_GETTER:%[0-9]+]] = function_ref @_TFV19protocol_extensions6HasAP1g6someP1PS_2P1_ : $@convention(method) (@out P1, @in_guaranteed HasAP1) -> ()
|
|
// CHECK: [[RESULT:%[0-9]+]] = apply [[SOMEP1_GETTER]]([[P1_COPY]]#1, %6#1) : $@convention(method) (@out P1, @in_guaranteed HasAP1) -> ()
|
|
// CHECK: [[P1_OPENED:%[0-9]+]] = open_existential_addr [[P1_COPY]]#1 : $*P1 to $*@opened([[UUID:".*"]]) P1
|
|
// CHECK: [[PROP2_SETTER:%[0-9]+]] = function_ref @_TFP19protocol_extensions2P1s5prop2Sb : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> ()
|
|
// CHECK: apply [[PROP2_SETTER]]<@opened([[UUID]]) P1>([[B]], [[P1_OPENED]]) : $@convention(method) <τ_0_0 where τ_0_0 : P1> (Bool, @inout τ_0_0) -> ()
|
|
// CHECK: [[SOMEP1_SETTER:%[0-9]+]] = function_ref @_TFV19protocol_extensions6HasAP1s6someP1PS_2P1_ : $@convention(method) (@in P1, @inout HasAP1) -> ()
|
|
// CHECK: apply [[SOMEP1_SETTER]]([[P1_COPY]]#1, [[HASP1_BOX]]#1) : $@convention(method) (@in P1, @inout HasAP1) -> ()
|
|
// CHECK-NOT: deinit_existential_addr
|
|
hasAP1.someP1.prop2 = b
|
|
// CHECK: return
|
|
}
|
|
|
|
func plusOneP1() -> P1 {}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions38test_open_existential_semantics_opaque
|
|
func test_open_existential_semantics_opaque(guaranteed: P1,
|
|
var immediate: P1) {
|
|
// CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box $P1
|
|
// CHECK: [[VALUE:%.*]] = open_existential_addr %0
|
|
// CHECK: [[METHOD:%.*]] = function_ref
|
|
// CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
|
|
|
|
guaranteed.f1()
|
|
|
|
// -- Need a guaranteed copy because it's immutable
|
|
// CHECK: copy_addr [[IMMEDIATE_BOX]]#1 to [initialization] [[IMMEDIATE:%.*]]#1
|
|
// CHECK: [[VALUE:%.*]] = open_existential_addr [[IMMEDIATE]]#1
|
|
// CHECK: [[METHOD:%.*]] = function_ref
|
|
// -- Can consume the value from our own copy
|
|
// CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
|
|
// CHECK: deinit_existential_addr [[IMMEDIATE]]
|
|
// CHECK: dealloc_stack [[IMMEDIATE]]
|
|
immediate.f1()
|
|
|
|
// CHECK: [[PLUS_ONE:%.*]] = alloc_stack $P1
|
|
// CHECK: [[VALUE:%.*]] = open_existential_addr [[PLUS_ONE]]#1
|
|
// CHECK: [[METHOD:%.*]] = function_ref
|
|
// -- Can consume the value from our own copy
|
|
// CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
|
|
// CHECK: deinit_existential_addr [[PLUS_ONE]]
|
|
// CHECK: dealloc_stack [[PLUS_ONE]]
|
|
plusOneP1().f1()
|
|
}
|
|
|
|
protocol CP1: class {}
|
|
|
|
extension CP1 {
|
|
final func f1() { }
|
|
}
|
|
|
|
func plusOneCP1() -> CP1 {}
|
|
|
|
// CHECK-LABEL: sil hidden @_TF19protocol_extensions37test_open_existential_semantics_class
|
|
func test_open_existential_semantics_class(guaranteed: CP1,
|
|
var immediate: CP1) {
|
|
// CHECK: [[IMMEDIATE_BOX:%.*]] = alloc_box $CP1
|
|
|
|
// CHECK-NOT: strong_retain %0
|
|
// CHECK: [[VALUE:%.*]] = open_existential_ref %0
|
|
// CHECK: [[METHOD:%.*]] = function_ref
|
|
// CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
|
|
// CHECK-NOT: strong_release [[VALUE]]
|
|
// CHECK-NOT: strong_release %0
|
|
guaranteed.f1()
|
|
|
|
// CHECK: [[IMMEDIATE:%.*]] = load [[IMMEDIATE_BOX]]
|
|
// CHECK: strong_retain [[IMMEDIATE]]
|
|
// CHECK: [[VALUE:%.*]] = open_existential_ref [[IMMEDIATE]]
|
|
// CHECK: [[METHOD:%.*]] = function_ref
|
|
// CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
|
|
// CHECK: strong_release [[VALUE]]
|
|
// CHECK-NOT: strong_release [[IMMEDIATE]]
|
|
immediate.f1()
|
|
|
|
// CHECK: [[F:%.*]] = function_ref {{.*}}plusOneCP1
|
|
// CHECK: [[PLUS_ONE:%.*]] = apply [[F]]()
|
|
// CHECK: [[VALUE:%.*]] = open_existential_ref [[PLUS_ONE]]
|
|
// CHECK: [[METHOD:%.*]] = function_ref
|
|
// CHECK: apply [[METHOD]]<{{.*}}>([[VALUE]])
|
|
// CHECK: strong_release [[VALUE]]
|
|
// CHECK-NOT: strong_release [[PLUS_ONE]]
|
|
plusOneCP1().f1()
|
|
}
|
|
|
|
protocol InitRequirement {
|
|
init(c: C)
|
|
}
|
|
|
|
extension InitRequirement {
|
|
// CHECK-LABEL: sil hidden @_TFP19protocol_extensions15InitRequirementCUS0___fMQPS0_FT1dCS_1D_S1_ : $@convention(thin) <Self where Self : InitRequirement> (@out Self, @owned D, @thick Self.Type) -> ()
|
|
// CHECK: bb0([[OUT:%.*]] : $*Self, [[ARG:%.*]] : $D, [[SELF_TYPE:%.*]] : $@thick Self.Type):
|
|
init(d: D) {
|
|
// CHECK: [[DELEGATEE:%.*]] = witness_method $Self, #InitRequirement.init!allocator.1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : InitRequirement> (@out τ_0_0, @owned C, @thick τ_0_0.Type) -> ()
|
|
// CHECK: [[ARG_UP:%.*]] = upcast [[ARG]]
|
|
// CHECK: apply [[DELEGATEE]]<Self>({{%.*}}, [[ARG_UP]], [[SELF_TYPE]])
|
|
self.init(c: d)
|
|
}
|
|
}
|
|
|
|
protocol ClassInitRequirement: class {
|
|
init(c: C)
|
|
}
|
|
|
|
extension ClassInitRequirement {
|
|
// CHECK-LABEL: sil hidden @_TFP19protocol_extensions20ClassInitRequirementCUS0___fMQPS0_FT1dCS_1D_S1_ : $@convention(thin) <Self where Self : ClassInitRequirement> (@owned D, @thick Self.Type) -> @owned Self
|
|
// CHECK: bb0([[ARG:%.*]] : $D, [[SELF_TYPE:%.*]] : $@thick Self.Type):
|
|
// CHECK: [[DELEGATEE:%.*]] = witness_method $Self, #ClassInitRequirement.init!allocator.1 : $@convention(witness_method) <τ_0_0 where τ_0_0 : ClassInitRequirement> (@owned C, @thick τ_0_0.Type) -> @owned τ_0_0
|
|
// CHECK: [[ARG_UP:%.*]] = upcast [[ARG]]
|
|
// CHECK: apply [[DELEGATEE]]<Self>([[ARG_UP]], [[SELF_TYPE]])
|
|
init(d: D) {
|
|
self.init(c: d)
|
|
}
|
|
}
|
|
|
|
@objc class OC {}
|
|
@objc class OD: OC {}
|
|
|
|
@objc protocol ObjCInitRequirement {
|
|
init(c: OC, d: OC)
|
|
}
|
|
|
|
func foo(t: ObjCInitRequirement.Type, c: OC) -> ObjCInitRequirement {
|
|
return t(c: OC(), d: OC())
|
|
}
|
|
|
|
extension ObjCInitRequirement {
|
|
// CHECK-LABEL: sil hidden @_TFP19protocol_extensions19ObjCInitRequirementCUS0___fMQPS0_FT1dCS_2OD_S1_ : $@convention(thin) <Self where Self : ObjCInitRequirement> (@owned OD, @thick Self.Type) -> @owned Self
|
|
// CHECK: bb0([[ARG:%.*]] : $OD, [[SELF_TYPE:%.*]] : $@thick Self.Type):
|
|
// CHECK: [[OBJC_SELF_TYPE:%.*]] = thick_to_objc_metatype [[SELF_TYPE]]
|
|
// CHECK: [[SELF:%.*]] = alloc_ref_dynamic [objc] [[OBJC_SELF_TYPE]] : $@objc_metatype Self.Type, $Self
|
|
// CHECK: [[WITNESS:%.*]] = witness_method [volatile] $Self, #ObjCInitRequirement.init!initializer.1.foreign : $@convention(objc_method) <τ_0_0 where τ_0_0 : ObjCInitRequirement> (OC, OC, @owned τ_0_0) -> @owned τ_0_0
|
|
// CHECK: [[UPCAST1:%.*]] = upcast [[ARG]]
|
|
// CHECK: [[UPCAST2:%.*]] = upcast [[ARG]]
|
|
// CHECK: apply [[WITNESS]]<Self>([[UPCAST1]], [[UPCAST2]], [[SELF]])
|
|
init(d: OD) {
|
|
self.init(c: d, d: d)
|
|
}
|
|
}
|