Files
swift-mirror/test/IRGen/class_bounded_generics.swift
Slava Pestov 60f437abe1 IRGen: Change witness_method calling convention to take a witness table
This is another incremental step toward protocol resilience.

To support resiliently adding requirements with default implementations,
we need to emit the witness thunk for each default requirement once,
and share it between conformances.

However, the body of the witness thunk can call witness methods from
the conformance of <Self : P>. Formerly, witness thunks were only emitted
with a concrete Self type, so any calls were resolved statically.

Now that Self can be abstract in a witness thunk signature, we have to
pass in the witness table and do the necessary gymnastics on both sides
of the call.

At the call site, the witness table is either abstract, concrete, or
undefined, as follows:

- If the unsubstituted Self type is concrete in the witness method
  signature, no witness table is necessary; this is the case of a
  concrete (non-default) witness thunk.

- If the unsubstituted Self type is abstract and the substituted Self
  type is concrete, the witness table is accessed via direct reference.

- If the unsubstituted Self type is abstract and the substituted Self
  type is also abstract, the witness table comes from type metadata
  that was passed in to the function where the call is taking place.

Inside the body of the witness method thunk, we only bind the witness
table if Self is an abstract type; this rules out the first case above,
where the witness table is not needed and cannot be provided by the
caller.

The result of a SIL witness_method instruction now lowers as an
explosion containing two values, the function pointer itself and
the witness table.

Similarly, partial application thunks now grab the witness table and
package it up in the context.

Special care is taken to support function_ref + apply and
function_ref + partial_apply of @convention(witness_method) callees;
here, we can hit the case where we don't know the original conformance
because the callee is concrete, in which case we just pass in a null
pointer as the witness table.

Witness thunks with an abstract Self currently only work for protocols
without any associated type requirements; to support those, we need
to be able to fulfill associated type metadata from the witness
table for the <Self : P> conformance. This will be addressed as part
of @rjmccall's calling convention work.

Also I didn't make any attempt to support this for @objc protocols that
do not have a witness table. In this case, the extra parameter is not
necessary since we can perform dynamic dispatch on the 'self' value to
call requirements; however, @objc protocols will not support default
implementations, at least not in the near-term.
2016-02-16 01:46:18 -08:00

264 lines
13 KiB
Swift

// RUN: %target-swift-frontend -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | FileCheck %s
// REQUIRES: CPU=x86_64
// XFAIL: linux
protocol ClassBound : class {
func classBoundMethod()
}
protocol ClassBound2 : class {
func classBoundMethod2()
}
protocol ClassBoundBinary : class, ClassBound {
func classBoundBinaryMethod(x: Self)
}
@objc protocol ObjCClassBound {
func objCClassBoundMethod()
}
@objc protocol ObjCClassBound2 {
func objCClassBoundMethod2()
}
protocol NotClassBound {
func notClassBoundMethod()
func notClassBoundBinaryMethod(x: Self)
}
struct ClassGenericFieldStruct<T:ClassBound> {
var x : Int
var y : T
var z : Int
}
struct ClassProtocolFieldStruct {
var x : Int
var y : ClassBound
var z : Int
}
class ClassGenericFieldClass<T:ClassBound> {
final var x : Int = 0
final var y : T
final var z : Int = 0
init(t: T) {
y = t
}
}
class ClassProtocolFieldClass {
var x : Int = 0
var y : ClassBound
var z : Int = 0
init(classBound cb: ClassBound) {
y = cb
}
}
// CHECK: %C22class_bounded_generics22ClassGenericFieldClass = type <{ %swift.refcounted, %Si, %objc_object*, %Si }>
// CHECK: %V22class_bounded_generics23ClassGenericFieldStruct = type <{ %Si, %objc_object*, %Si }>
// CHECK: %V22class_bounded_generics24ClassProtocolFieldStruct = type <{ %Si, %P22class_bounded_generics10ClassBound_, %Si }>
// CHECK-LABEL: define hidden %objc_object* @_TF22class_bounded_generics23class_bounded_archetype{{.*}}(%objc_object*, %swift.type* %T, i8** %T.ClassBound)
func class_bounded_archetype<T : ClassBound>(x: T) -> T {
return x
}
class SomeClass {}
class SomeSubclass : SomeClass {}
// CHECK-LABEL: define hidden %C22class_bounded_generics9SomeClass* @_TF22class_bounded_generics28superclass_bounded_archetype{{.*}}(%C22class_bounded_generics9SomeClass*, %swift.type* %T)
func superclass_bounded_archetype<T : SomeClass>(x: T) -> T {
return x
}
// CHECK-LABEL: define hidden { %C22class_bounded_generics9SomeClass*, %C22class_bounded_generics12SomeSubclass* } @_TF22class_bounded_generics33superclass_bounded_archetype_call{{.*}}(%C22class_bounded_generics9SomeClass*, %C22class_bounded_generics12SomeSubclass*)
func superclass_bounded_archetype_call(x: SomeClass, y: SomeSubclass) -> (SomeClass, SomeSubclass) {
return (superclass_bounded_archetype(x),
superclass_bounded_archetype(y));
// CHECK: [[SOMECLASS_RESULT:%.*]] = call %C22class_bounded_generics9SomeClass* @_TF22class_bounded_generics28superclass_bounded_archetype{{.*}}(%C22class_bounded_generics9SomeClass* {{%.*}}, {{.*}})
// CHECK: [[SOMESUPERCLASS_IN:%.*]] = bitcast %C22class_bounded_generics12SomeSubclass* {{%.*}} to %C22class_bounded_generics9SomeClass*
// CHECK: [[SOMESUPERCLASS_RESULT:%.*]] = call %C22class_bounded_generics9SomeClass* @_TF22class_bounded_generics28superclass_bounded_archetype{{.*}}(%C22class_bounded_generics9SomeClass* [[SOMESUPERCLASS_IN]], {{.*}})
// CHECK: bitcast %C22class_bounded_generics9SomeClass* [[SOMESUPERCLASS_RESULT]] to %C22class_bounded_generics12SomeSubclass*
}
// CHECK-LABEL: define hidden void @_TF22class_bounded_generics30class_bounded_archetype_method{{.*}}(%objc_object*, %objc_object*, %swift.type* %T, i8** %T.ClassBoundBinary)
func class_bounded_archetype_method<T : ClassBoundBinary>(x: T, y: T) {
x.classBoundMethod()
// CHECK: [[INHERITED:%.*]] = load i8*, i8** %T.ClassBoundBinary, align 8
// CHECK: [[INHERITED_WTBL:%.*]] = bitcast i8* [[INHERITED]] to i8**
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[INHERITED_WTBL]], align 8
// CHECK: [[WITNESS_FUNC:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %swift.type*, i8**)
// CHECK: call void [[WITNESS_FUNC]](%objc_object* %0, %swift.type* {{.*}}, i8** [[INHERITED_WTBL]])
x.classBoundBinaryMethod(y)
// CHECK: [[WITNESS_ENTRY:%.*]] = getelementptr inbounds i8*, i8** %T.ClassBoundBinary, i32 1
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_ENTRY]], align 8
// CHECK: call void @swift_unknownRetain(%objc_object* [[Y:%.*]])
// CHECK: [[WITNESS_FUNC:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %objc_object*, %swift.type*, i8**)
// CHECK: call void [[WITNESS_FUNC]](%objc_object* [[Y]], %objc_object* %0, %swift.type* %T, i8** %T.ClassBoundBinary)
}
// CHECK-LABEL: define hidden { %objc_object*, %objc_object* } @_TF22class_bounded_generics29class_bounded_archetype_tuple{{.*}}(%objc_object*, %swift.type* %T, i8** %T.ClassBound)
func class_bounded_archetype_tuple<T : ClassBound>(x: T) -> (T, T) {
return (x, x)
}
class ConcreteClass : ClassBoundBinary, NotClassBound {
func classBoundMethod() {}
func classBoundBinaryMethod(x: ConcreteClass) {}
func notClassBoundMethod() {}
func notClassBoundBinaryMethod(x: ConcreteClass) {}
}
// CHECK-LABEL: define hidden %C22class_bounded_generics13ConcreteClass* @_TF22class_bounded_generics28call_class_bounded_archetype{{.*}}(%C22class_bounded_generics13ConcreteClass*) {{.*}} {
func call_class_bounded_archetype(x: ConcreteClass) -> ConcreteClass {
return class_bounded_archetype(x)
// CHECK: [[IN:%.*]] = bitcast %C22class_bounded_generics13ConcreteClass* {{%.*}} to %objc_object*
// CHECK: [[OUT_ORIG:%.*]] = call %objc_object* @_TF22class_bounded_generics23class_bounded_archetype{{.*}}(%objc_object* [[IN]], {{.*}})
// CHECK: [[OUT:%.*]] = bitcast %objc_object* [[OUT_ORIG]] to %C22class_bounded_generics13ConcreteClass*
// CHECK: ret %C22class_bounded_generics13ConcreteClass* [[OUT]]
}
// CHECK: define hidden void @_TF22class_bounded_generics27not_class_bounded_archetype{{.*}}(%swift.opaque* noalias nocapture sret, %swift.opaque* noalias nocapture, %swift.type* %T, i8** %T.NotClassBound)
func not_class_bounded_archetype<T : NotClassBound>(x: T) -> T {
return x
}
// CHECK-LABEL: define hidden %objc_object* @_TF22class_bounded_generics44class_bounded_archetype_to_not_class_bounded{{.*}}(%objc_object*, %swift.type* %T, i8** %T.ClassBound, i8** %T.NotClassBound) {{.*}} {
func class_bounded_archetype_to_not_class_bounded
<T:protocol<ClassBound, NotClassBound>>(x:T) -> T {
// CHECK: alloca %objc_object*, align 8
return not_class_bounded_archetype(x)
}
/* TODO Abstraction remapping to non-class-bounded witnesses
func class_and_not_class_bounded_archetype_methods
<T:protocol<ClassBound, NotClassBound>>(x:T, y:T) {
x.classBoundMethod()
x.classBoundBinaryMethod(y)
x.notClassBoundMethod()
x.notClassBoundBinaryMethod(y)
}
*/
// CHECK-LABEL: define hidden { %objc_object*, i8** } @_TF22class_bounded_generics21class_bounded_erasure{{.*}}(%C22class_bounded_generics13ConcreteClass*) {{.*}} {
func class_bounded_erasure(x: ConcreteClass) -> ClassBound {
return x
// CHECK: [[INSTANCE_OPAQUE:%.*]] = bitcast %C22class_bounded_generics13ConcreteClass* [[INSTANCE:%.*]] to %objc_object*
// CHECK: [[T0:%.*]] = insertvalue { %objc_object*, i8** } undef, %objc_object* [[INSTANCE_OPAQUE]], 0
// CHECK: [[T1:%.*]] = insertvalue { %objc_object*, i8** } [[T0]], i8** getelementptr inbounds ([1 x i8*], [1 x i8*]* @_TWPC22class_bounded_generics13ConcreteClassS_10ClassBoundS_, i32 0, i32 0), 1
// CHECK: ret { %objc_object*, i8** } [[T1]]
}
// CHECK-LABEL: define hidden void @_TF22class_bounded_generics29class_bounded_protocol_method{{.*}}(%objc_object*, i8**) {{.*}} {
func class_bounded_protocol_method(x: ClassBound) {
x.classBoundMethod()
// CHECK: [[METADATA:%.*]] = call %swift.type* @swift_getObjectType(%objc_object* %0)
// CHECK: [[WITNESS:%.*]] = load i8*, i8** [[WITNESS_TABLE:%.*]], align 8
// CHECK: [[WITNESS_FN:%.*]] = bitcast i8* [[WITNESS]] to void (%objc_object*, %swift.type*, i8**)
// CHECK: call void [[WITNESS_FN]](%objc_object* %0, %swift.type* [[METADATA]], i8** [[WITNESS_TABLE]])
}
// CHECK-LABEL: define hidden %C22class_bounded_generics13ConcreteClass* @_TF22class_bounded_generics28class_bounded_archetype_cast{{.*}}(%objc_object*, %swift.type* %T, i8** %T.ClassBound)
func class_bounded_archetype_cast<T : ClassBound>(x: T) -> ConcreteClass {
return x as! ConcreteClass
// CHECK: [[IN_PTR:%.*]] = bitcast %objc_object* {{%.*}} to i8*
// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC22class_bounded_generics13ConcreteClass()
// CHECK: [[T1:%.*]] = bitcast %swift.type* [[T0]] to i8*
// CHECK: [[OUT_PTR:%.*]] = call i8* @swift_dynamicCastClassUnconditional(i8* [[IN_PTR]], i8* [[T1]])
// CHECK: [[OUT:%.*]] = bitcast i8* [[OUT_PTR]] to %C22class_bounded_generics13ConcreteClass*
// CHECK: ret %C22class_bounded_generics13ConcreteClass* [[OUT]]
}
// CHECK-LABEL: define hidden %C22class_bounded_generics13ConcreteClass* @_TF22class_bounded_generics27class_bounded_protocol_cast{{.*}}(%objc_object*, i8**)
func class_bounded_protocol_cast(x: ClassBound) -> ConcreteClass {
return x as! ConcreteClass
// CHECK: [[IN_PTR:%.*]] = bitcast %objc_object* {{%.*}} to i8*
// CHECK: [[T0:%.*]] = call %swift.type* @_TMaC22class_bounded_generics13ConcreteClass()
// CHECK: [[T1:%.*]] = bitcast %swift.type* [[T0]] to i8*
// CHECK: [[OUT_PTR:%.*]] = call i8* @swift_dynamicCastClassUnconditional(i8* [[IN_PTR]], i8* [[T1]])
// CHECK: [[OUT:%.*]] = bitcast i8* [[OUT_PTR]] to %C22class_bounded_generics13ConcreteClass*
// CHECK: ret %C22class_bounded_generics13ConcreteClass* [[OUT]]
}
// CHECK-LABEL: define hidden { %objc_object*, i8** } @_TF22class_bounded_generics35class_bounded_protocol_conversion{{.*}}(%objc_object*, i8**, i8**) {{.*}} {
func class_bounded_protocol_conversion_1(x: protocol<ClassBound, ClassBound2>)
-> ClassBound {
return x
}
// CHECK-LABEL: define hidden { %objc_object*, i8** } @_TF22class_bounded_generics35class_bounded_protocol_conversion{{.*}}(%objc_object*, i8**, i8**) {{.*}} {
func class_bounded_protocol_conversion_2(x: protocol<ClassBound, ClassBound2>)
-> ClassBound2 {
return x
}
// CHECK-LABEL: define hidden { %objc_object*, i8** } @_TF22class_bounded_generics40objc_class_bounded_protocol_conversion{{.*}}(%objc_object*, i8**) {{.*}} {
func objc_class_bounded_protocol_conversion_1
(x:protocol<ClassBound, ObjCClassBound>) -> ClassBound {
return x
}
// CHECK-LABEL: define hidden %objc_object* @_TF22class_bounded_generics40objc_class_bounded_protocol_conversion{{.*}}(%objc_object*, i8**) {{.*}} {
func objc_class_bounded_protocol_conversion_2
(x:protocol<ClassBound, ObjCClassBound>) -> ObjCClassBound {
return x
}
// CHECK-LABEL: define hidden %objc_object* @_TF22class_bounded_generics40objc_class_bounded_protocol_conversion{{.*}}(%objc_object*)
func objc_class_bounded_protocol_conversion_3
(x:protocol<ObjCClassBound, ObjCClassBound2>) -> ObjCClassBound {
return x
}
// CHECK-LABEL: define hidden %objc_object* @_TF22class_bounded_generics40objc_class_bounded_protocol_conversion{{.*}}(%objc_object*)
func objc_class_bounded_protocol_conversion_4
(x:protocol<ObjCClassBound, ObjCClassBound2>) -> ObjCClassBound2 {
return x
}
// CHECK-LABEL: define hidden { i64, %objc_object*, i64 } @_TF22class_bounded_generics33class_generic_field_struct_fields{{.*}}(i64, %objc_object*, i64, %swift.type* %T, i8** %T.ClassBound)
func class_generic_field_struct_fields<T : ClassBound>
(x:ClassGenericFieldStruct<T>) -> (Int, T, Int) {
return (x.x, x.y, x.z)
}
// CHECK-LABEL: define hidden void @_TF22class_bounded_generics34class_protocol_field_struct_fields{{.*}}(<{ %Si, %P22class_bounded_generics10ClassBound_, %Si }>* noalias nocapture sret, %V22class_bounded_generics24ClassProtocolFieldStruct* noalias nocapture dereferenceable({{.*}}))
func class_protocol_field_struct_fields
(x:ClassProtocolFieldStruct) -> (Int, ClassBound, Int) {
return (x.x, x.y, x.z)
}
// CHECK-LABEL: define hidden { i64, %objc_object*, i64 } @_TF22class_bounded_generics32class_generic_field_class_fields{{.*}}(%C22class_bounded_generics22ClassGenericFieldClass*)
func class_generic_field_class_fields<T : ClassBound>
(x:ClassGenericFieldClass<T>) -> (Int, T, Int) {
return (x.x, x.y, x.z)
// CHECK: getelementptr inbounds %C22class_bounded_generics22ClassGenericFieldClass, %C22class_bounded_generics22ClassGenericFieldClass* %0, i32 0, i32 1
// CHECK: getelementptr inbounds %C22class_bounded_generics22ClassGenericFieldClass, %C22class_bounded_generics22ClassGenericFieldClass* %0, i32 0, i32 2
// CHECK: getelementptr inbounds %C22class_bounded_generics22ClassGenericFieldClass, %C22class_bounded_generics22ClassGenericFieldClass* %0, i32 0, i32 3
}
// CHECK-LABEL: define hidden void @_TF22class_bounded_generics33class_protocol_field_class_fields{{.*}}(<{ %Si, %P22class_bounded_generics10ClassBound_, %Si }>* noalias nocapture sret, %C22class_bounded_generics23ClassProtocolFieldClass*)
func class_protocol_field_class_fields(x: ClassProtocolFieldClass)
-> (Int, ClassBound, Int) {
return (x.x, x.y, x.z)
// CHECK: = call i64 %{{[0-9]+}}
// CHECK: = call { %objc_object*, i8** } %{{[0-9]+}}
// CHECK: = call i64 %{{[0-9]+}}
}
class SomeSwiftClass {
class func foo() {}
}
// T must have a Swift layout, so we can load this metatype with a direct access.
// CHECK-LABEL: define hidden void @_TF22class_bounded_generics22class_bounded_metatype
// CHECK: [[T0:%.*]] = getelementptr inbounds %C22class_bounded_generics14SomeSwiftClass, %C22class_bounded_generics14SomeSwiftClass* {{%.*}}, i32 0, i32 0, i32 0
// CHECK-NEXT: [[T1:%.*]] = load %swift.type*, %swift.type** [[T0]], align 8
// CHECK-NEXT: [[T2:%.*]] = bitcast %swift.type* [[T1]] to void (%swift.type*)**
// CHECK-NEXT: [[T3:%.*]] = getelementptr inbounds void (%swift.type*)*, void (%swift.type*)** [[T2]], i64 10
// CHECK-NEXT: load void (%swift.type*)*, void (%swift.type*)** [[T3]], align 8
func class_bounded_metatype<T: SomeSwiftClass>(t : T) {
t.dynamicType.foo()
}
class WeakRef<T: AnyObject> {
weak var value: T?
}