Skip to content

Commit e67b6d9

Browse files
authored
Merge pull request #12118 from slavapestov/some-classes-are-very-fulfilling
Teach IRGen to fulfill type parameters from class-constrained archetypes
2 parents c8c1ad5 + 15bbf2c commit e67b6d9

File tree

6 files changed

+102
-33
lines changed

6 files changed

+102
-33
lines changed

lib/IRGen/Fulfillment.cpp

Lines changed: 9 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -70,12 +70,12 @@ static bool isLeafTypeMetadata(CanType type) {
7070
case TypeKind::Tuple:
7171
return cast<TupleType>(type)->getNumElements() == 0;
7272

73-
// Nominal types might have parents.
73+
// Nominal types might have generic parents.
7474
case TypeKind::Class:
7575
case TypeKind::Enum:
7676
case TypeKind::Protocol:
7777
case TypeKind::Struct:
78-
return !cast<NominalType>(type)->getParent();
78+
return !cast<NominalType>(type)->getDecl()->isGenericContext();
7979

8080
// Bound generic types have type arguments.
8181
case TypeKind::BoundGenericClass:
@@ -125,6 +125,13 @@ bool FulfillmentMap::searchTypeMetadata(IRGenModule &IGM, CanType type,
125125
return hadFulfillment;
126126
}
127127

128+
if (keys.isInterestingType(type)) {
129+
if (auto superclassTy = keys.getSuperclassBound(type)) {
130+
return searchNominalTypeMetadata(IGM, superclassTy, source,
131+
std::move(path), keys);
132+
}
133+
}
134+
128135
// Inexact metadata will be a problem if we ever try to use this
129136
// to remember that we already have the metadata for something.
130137
if (isa<NominalType>(type) || isa<BoundGenericType>(type)) {
@@ -289,21 +296,6 @@ bool FulfillmentMap::addFulfillment(FulfillmentKey key,
289296
}
290297
}
291298

292-
bool FulfillmentMap::Everything::isInterestingType(CanType type) const {
293-
return true;
294-
}
295-
bool FulfillmentMap::Everything::hasInterestingType(CanType type) const {
296-
return true;
297-
}
298-
bool FulfillmentMap::Everything
299-
::hasLimitedInterestingConformances(CanType type) const {
300-
return false;
301-
}
302-
GenericSignature::ConformsToArray
303-
FulfillmentMap::Everything::getInterestingConformances(CanType type) const{
304-
return {};
305-
}
306-
307299
void FulfillmentMap::dump() const {
308300
auto &out = llvm::errs();
309301
for (auto &entry : Fulfillments) {

lib/IRGen/Fulfillment.h

Lines changed: 3 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -66,17 +66,10 @@ class FulfillmentMap {
6666
virtual GenericSignature::ConformsToArray
6767
getInterestingConformances(CanType type) const = 0;
6868

69-
virtual ~InterestingKeysCallback() = default;
70-
};
69+
/// Return the limited interesting conformances for an interesting type.
70+
virtual CanType getSuperclassBound(CanType type) const = 0;
7171

72-
/// An implementation of InterestingKeysCallback that returns everything
73-
/// fulfillable.
74-
struct Everything : InterestingKeysCallback {
75-
bool isInterestingType(CanType type) const override;
76-
bool hasInterestingType(CanType type) const override;
77-
bool hasLimitedInterestingConformances(CanType type) const override;
78-
GenericSignature::ConformsToArray
79-
getInterestingConformances(CanType type) const override;
72+
virtual ~InterestingKeysCallback() = default;
8073
};
8174

8275
FulfillmentMap() = default;

lib/IRGen/GenProto.cpp

Lines changed: 27 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -95,6 +95,12 @@ class PolymorphicConvention {
9595
return Generics->getConformsTo(t, M);
9696
}
9797

98+
CanType getSuperclassBound(Type t) {
99+
if (auto superclassTy = Generics->getSuperclassBound(t, M))
100+
return superclassTy->getCanonicalType();
101+
return CanType();
102+
}
103+
98104
public:
99105
PolymorphicConvention(IRGenModule &IGM, CanSILFunctionType fnType);
100106

@@ -291,6 +297,9 @@ bool PolymorphicConvention::considerType(CanType type, IsExact_t isExact,
291297
getInterestingConformances(CanType type) const override {
292298
return Self.getConformsTo(type);
293299
}
300+
CanType getSuperclassBound(CanType type) const override {
301+
return Self.getSuperclassBound(type);
302+
}
294303
} callbacks(*this);
295304
return Fulfillments.searchTypeMetadata(IGM, type, isExact, sourceIndex,
296305
std::move(path), callbacks);
@@ -367,6 +376,15 @@ void PolymorphicConvention::considerParameter(SILParameterInfo param,
367376
return;
368377
}
369378

379+
if (isa<GenericTypeParamType>(type)) {
380+
if (auto superclassTy = getSuperclassBound(type)) {
381+
considerNewTypeSource(MetadataSource::Kind::ClassPointer,
382+
paramIndex, superclassTy, IsInexact);
383+
return;
384+
385+
}
386+
}
387+
370388
// Thick metatypes are sources of metadata.
371389
if (auto metatypeTy = dyn_cast<MetatypeType>(type)) {
372390
if (metatypeTy->getRepresentation() != MetatypeRepresentation::Thick)
@@ -1284,6 +1302,11 @@ class AccessorConformanceInfo : public ConformanceInfo {
12841302
getInterestingConformances(CanType type) const override {
12851303
llvm_unreachable("no limits");
12861304
}
1305+
CanType getSuperclassBound(CanType type) const override {
1306+
if (auto superclassTy = cast<ArchetypeType>(type)->getSuperclass())
1307+
return superclassTy->getCanonicalType();
1308+
return CanType();
1309+
}
12871310
} callback;
12881311
Fulfillments->searchTypeMetadata(IGM, ConcreteType, IsExact,
12891312
/*sourceIndex*/ 0, MetadataPath(),
@@ -2023,7 +2046,10 @@ llvm::Value *MetadataPath::followComponent(IRGenFunction &IGF,
20232046
case Component::Kind::NominalTypeArgument:
20242047
case Component::Kind::NominalTypeArgumentConformance: {
20252048
assert(sourceKey.Kind == LocalTypeDataKind::forTypeMetadata());
2026-
auto *nominal = sourceKey.Type.getAnyNominal();
2049+
auto type = sourceKey.Type;
2050+
if (auto archetypeTy = dyn_cast<ArchetypeType>(type))
2051+
type = archetypeTy->getSuperclass()->getCanonicalType();
2052+
auto *nominal = type.getAnyNominal();
20272053
auto reqtIndex = component.getPrimaryIndex();
20282054

20292055
GenericTypeRequirements requirements(IGF.IGM, nominal);

lib/IRGen/LocalTypeData.cpp

Lines changed: 23 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -254,12 +254,34 @@ void LocalTypeDataCache::addAbstractForTypeMetadata(IRGenFunction &IGF,
254254
CanType type,
255255
IsExact_t isExact,
256256
llvm::Value *metadata) {
257+
struct Callback : FulfillmentMap::InterestingKeysCallback {
258+
bool isInterestingType(CanType type) const override {
259+
return true;
260+
}
261+
bool hasInterestingType(CanType type) const override {
262+
return true;
263+
}
264+
bool hasLimitedInterestingConformances(CanType type) const override {
265+
return false;
266+
}
267+
GenericSignature::ConformsToArray
268+
getInterestingConformances(CanType type) const override {
269+
llvm_unreachable("no limits");
270+
}
271+
CanType getSuperclassBound(CanType type) const override {
272+
if (auto arch = dyn_cast<ArchetypeType>(type))
273+
if (auto superclassTy = arch->getSuperclass())
274+
return superclassTy->getCanonicalType();
275+
return CanType();
276+
}
277+
} callbacks;
278+
257279
// Look for anything at all that's fulfilled by this. If we don't find
258280
// anything, stop.
259281
FulfillmentMap fulfillments;
260282
if (!fulfillments.searchTypeMetadata(IGF.IGM, type, isExact,
261283
/*source*/ 0, MetadataPath(),
262-
FulfillmentMap::Everything())) {
284+
callbacks)) {
263285
return;
264286
}
265287

lib/SIL/SILFunctionType.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -100,6 +100,9 @@ SILFunctionType::getDefaultWitnessMethodProtocol(ModuleDecl &M) const {
100100
assert(getRepresentation() == SILFunctionTypeRepresentation::WitnessMethod);
101101
auto selfTy = getSelfInstanceType();
102102
if (auto paramTy = dyn_cast<GenericTypeParamType>(selfTy)) {
103+
auto superclass = GenericSig->getSuperclassBound(paramTy, M);
104+
if (superclass)
105+
return nullptr;
103106
assert(paramTy->getDepth() == 0 && paramTy->getIndex() == 0);
104107
auto protos = GenericSig->getConformsTo(paramTy, M);
105108
assert(protos.size() == 1);

test/IRGen/class_bounded_generics.swift

Lines changed: 37 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %target-swift-frontend -assume-parsing-unqualified-ownership-sil -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
1+
// RUN: %target-swift-frontend -emit-ir -primary-file %s -disable-objc-attr-requires-foundation-module | %FileCheck %s
22

33
// REQUIRES: CPU=x86_64
44
// XFAIL: linux
@@ -9,7 +9,7 @@ protocol ClassBound : class {
99
protocol ClassBound2 : class {
1010
func classBoundMethod2()
1111
}
12-
protocol ClassBoundBinary : class, ClassBound {
12+
protocol ClassBoundBinary : ClassBound {
1313
func classBoundBinaryMethod(_ x: Self)
1414
}
1515
@objc protocol ObjCClassBound {
@@ -214,7 +214,7 @@ func objc_class_bounded_protocol_conversion_4
214214
}
215215

216216
// CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i64 } @_T022class_bounded_generics0A28_generic_field_struct_fields{{[_0-9a-zA-Z]*}}F(i64, %objc_object*, i64, %swift.type* %T, i8** %T.ClassBound)
217-
func class_generic_field_struct_fields<T : ClassBound>
217+
func class_generic_field_struct_fields<T>
218218
(_ x:ClassGenericFieldStruct<T>) -> (Int, T, Int) {
219219
return (x.x, x.y, x.z)
220220
}
@@ -226,7 +226,7 @@ func class_protocol_field_struct_fields
226226
}
227227

228228
// CHECK-LABEL: define hidden swiftcc { i64, %objc_object*, i64 } @_T022class_bounded_generics0a15_generic_field_A7_fields{{[_0-9a-zA-Z]*}}F(%T22class_bounded_generics017ClassGenericFieldD0C*)
229-
func class_generic_field_class_fields<T : ClassBound>
229+
func class_generic_field_class_fields<T>
230230
(_ x:ClassGenericFieldClass<T>) -> (Int, T, Int) {
231231
return (x.x, x.y, x.z)
232232
// CHECK: getelementptr inbounds %T22class_bounded_generics017ClassGenericFieldD0C, %T22class_bounded_generics017ClassGenericFieldD0C* %0, i32 0, i32 1
@@ -273,3 +273,36 @@ class M<T, S: A<T>> {
273273
s = S.init()
274274
}
275275
}
276+
277+
// CHECK-LABEL: define hidden swiftcc void @_T022class_bounded_generics14takes_metatypeyxmlF(%swift.type*, %swift.type* %T)
278+
func takes_metatype<T>(_: T.Type) {}
279+
280+
// CHECK-LABEL: define hidden swiftcc void @_T022class_bounded_generics023archetype_with_generic_A11_constraintyx1t_tAA1ACyq_GRbzr0_lF(%T22class_bounded_generics1AC.2*, %swift.type* %T)
281+
// CHECK: [[ISA_ADDR:%.*]] = bitcast %T22class_bounded_generics1AC.2* %0 to %swift.type**
282+
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
283+
// CHECK-NEXT: call swiftcc void @_T022class_bounded_generics14takes_metatypeyxmlF(%swift.type* %T, %swift.type* %T)
284+
// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
285+
// CHECK-NEXT: [[U_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
286+
// CHECK-NEXT: [[U:%.*]] = load %swift.type*, %swift.type** [[U_ADDR]]
287+
// CHECK-NEXT: call swiftcc void @_T022class_bounded_generics14takes_metatypeyxmlF(%swift.type* %U, %swift.type* %U)
288+
// CHECK: ret void
289+
290+
func archetype_with_generic_class_constraint<T, U>(t: T) where T : A<U> {
291+
takes_metatype(T.self)
292+
takes_metatype(U.self)
293+
}
294+
295+
// CHECK-LABEL: define hidden swiftcc void @_T022class_bounded_generics029calls_archetype_with_generic_A11_constraintyAA1ACyxG1a_tlF(%T22class_bounded_generics1AC*) #0 {
296+
// CHECK: [[ISA_ADDR:%.*]] = getelementptr inbounds %T22class_bounded_generics1AC, %T22class_bounded_generics1AC* %0, i32 0, i32 0, i32 0
297+
// CHECK-NEXT: [[ISA:%.*]] = load %swift.type*, %swift.type** [[ISA_ADDR]]
298+
// CHECK: [[SELF:%.*]] = bitcast %T22class_bounded_generics1AC* %0 to %T22class_bounded_generics1AC.2*
299+
// CHECK-NEXT: [[ISA_PTR:%.*]] = bitcast %swift.type* [[ISA]] to %swift.type**
300+
// CHECK-NEXT: [[T_ADDR:%.*]] = getelementptr inbounds %swift.type*, %swift.type** [[ISA_PTR]], i64 10
301+
// CHECK-NEXT: [[T:%.*]] = load %swift.type*, %swift.type** [[T_ADDR]]
302+
// CHECK-NEXT: [[A_OF_T:%.*]] = call %swift.type* @_T022class_bounded_generics1ACMa(%swift.type* [[T]])
303+
// CHECK-NEXT: call swiftcc void @_T022class_bounded_generics023archetype_with_generic_A11_constraintyx1t_tAA1ACyq_GRbzr0_lF(%T22class_bounded_generics1AC.2* [[SELF]], %swift.type* [[A_OF_T]])
304+
// CHECK: ret void
305+
306+
func calls_archetype_with_generic_class_constraint<T>(a: A<T>) {
307+
archetype_with_generic_class_constraint(t: a)
308+
}

0 commit comments

Comments
 (0)