Skip to content

Commit 5e632f8

Browse files
committed
Reflection: Walk up the superclass chain when resolving associated types
Now that IRGen emits the right metadata, we can make use of it to fix associated type lookup. Fixes <rdar://problem/28331935>.
1 parent 30b1efa commit 5e632f8

File tree

5 files changed

+337
-58
lines changed

5 files changed

+337
-58
lines changed

include/swift/Reflection/TypeRefBuilder.h

+14-3
Original file line numberDiff line numberDiff line change
@@ -138,6 +138,10 @@ class TypeRefBuilder {
138138
/// this TypeRefBuilder and are automatically released.
139139
std::vector<std::unique_ptr<const TypeRef>> TypeRefPool;
140140

141+
/// Cache for associated type lookups.
142+
std::unordered_map<TypeRefID, const TypeRef *,
143+
TypeRefID::Hash, TypeRefID::Equal> AssociatedTypeCache;
144+
141145
TypeConverter TC;
142146
MetadataSourceBuilder MSB;
143147

@@ -295,14 +299,21 @@ class TypeRefBuilder {
295299

296300
const AssociatedTypeDescriptor *
297301
lookupAssociatedTypes(const std::string &MangledTypeName,
298-
const DependentMemberTypeRef *DependentMember);
302+
const TypeRef *Protocol);
299303

300304
public:
301305
TypeConverter &getTypeConverter() { return TC; }
302306

303307
const TypeRef *
304-
getDependentMemberTypeRef(const std::string &MangledTypeName,
305-
const DependentMemberTypeRef *DependentMember);
308+
lookupTypeWitness(const std::string &MangledTypeName,
309+
const std::string &Member,
310+
const TypeRef *Protocol);
311+
312+
const TypeRef *
313+
lookupSuperclass(const std::string &MangledTypeName);
314+
315+
const TypeRef *
316+
lookupSuperclass(const TypeRef *TR);
306317

307318
/// Load unsubstituted field types for a nominal type.
308319
const FieldDescriptor *getFieldTypeInfo(const TypeRef *TR);

stdlib/public/Reflection/TypeRef.cpp

+26-28
Original file line numberDiff line numberDiff line change
@@ -22,12 +22,6 @@
2222
using namespace swift;
2323
using namespace reflection;
2424

25-
[[noreturn]]
26-
static void unreachable(const char *Message) {
27-
std::cerr << "fatal error: " << Message << "\n";
28-
std::abort();
29-
}
30-
3125
class PrintTypeRef : public TypeRefVisitor<PrintTypeRef, void> {
3226
std::ostream &OS;
3327
unsigned Indent;
@@ -354,14 +348,9 @@ bool TypeRef::isConcreteAfterSubstitutions(
354348

355349
unsigned NominalTypeTrait::getDepth() const {
356350
if (auto P = Parent) {
357-
switch (P->getKind()) {
358-
case TypeRefKind::Nominal:
359-
return 1 + cast<NominalTypeRef>(P)->getDepth();
360-
case TypeRefKind::BoundGeneric:
361-
return 1 + cast<BoundGenericTypeRef>(P)->getDepth();
362-
default:
363-
unreachable("Asked for depth on non-nominal typeref");
364-
}
351+
if (auto *Nominal = dyn_cast<NominalTypeRef>(P))
352+
return 1 + Nominal->getDepth();
353+
return 1 + cast<BoundGenericTypeRef>(P)->getDepth();
365354
}
366355

367356
return 0;
@@ -657,20 +646,29 @@ class TypeRefSubstitution
657646

658647
const TypeRef *TypeWitness = nullptr;
659648

660-
// Get the original type of the witness from the conformance.
661-
switch (SubstBase->getKind()) {
662-
case TypeRefKind::Nominal: {
663-
auto Nominal = cast<NominalTypeRef>(SubstBase);
664-
TypeWitness = Builder.getDependentMemberTypeRef(Nominal->getMangledName(), DM);
665-
break;
666-
}
667-
case TypeRefKind::BoundGeneric: {
668-
auto BG = cast<BoundGenericTypeRef>(SubstBase);
669-
TypeWitness = Builder.getDependentMemberTypeRef(BG->getMangledName(), DM);
670-
break;
671-
}
672-
default:
673-
unreachable("Unknown base type");
649+
while (TypeWitness == nullptr) {
650+
auto &Member = DM->getMember();
651+
auto *Protocol = DM->getProtocol();
652+
653+
// Get the original type of the witness from the conformance.
654+
if (auto *Nominal = dyn_cast<NominalTypeRef>(SubstBase)) {
655+
TypeWitness = Builder.lookupTypeWitness(Nominal->getMangledName(),
656+
Member, Protocol);
657+
} else {
658+
auto BG = cast<BoundGenericTypeRef>(SubstBase);
659+
TypeWitness = Builder.lookupTypeWitness(BG->getMangledName(),
660+
Member, Protocol);
661+
}
662+
663+
if (TypeWitness != nullptr)
664+
break;
665+
666+
// If we didn't find the member type, check the superclass.
667+
auto *Superclass = Builder.lookupSuperclass(SubstBase);
668+
if (Superclass == nullptr)
669+
break;
670+
671+
SubstBase = Superclass;
674672
}
675673

676674
// We didn't find the member type, so return something to let the

stdlib/public/Reflection/TypeRefBuilder.cpp

+45-19
Original file line numberDiff line numberDiff line change
@@ -28,46 +28,72 @@ using namespace reflection;
2828

2929
TypeRefBuilder::TypeRefBuilder() : TC(*this) {}
3030

31-
const AssociatedTypeDescriptor * TypeRefBuilder::
32-
lookupAssociatedTypes(const std::string &MangledTypeName,
33-
const DependentMemberTypeRef *DependentMember) {
31+
const TypeRef * TypeRefBuilder::
32+
lookupTypeWitness(const std::string &MangledTypeName,
33+
const std::string &Member,
34+
const TypeRef *Protocol) {
35+
TypeRefID key;
36+
key.addString(MangledTypeName);
37+
key.addString(Member);
38+
key.addPointer(Protocol);
39+
auto found = AssociatedTypeCache.find(key);
40+
if (found != AssociatedTypeCache.end())
41+
return found->second;
42+
3443
// Cache missed - we need to look through all of the assocty sections
3544
// for all images that we've been notified about.
3645
for (auto &Info : ReflectionInfos) {
3746
for (const auto &AssocTyDescriptor : Info.assocty) {
3847
std::string ConformingTypeName(AssocTyDescriptor.ConformingTypeName);
3948
if (ConformingTypeName.compare(MangledTypeName) != 0)
4049
continue;
50+
4151
std::string ProtocolMangledName(AssocTyDescriptor.ProtocolTypeName);
4252
auto DemangledProto = Demangle::demangleTypeAsNode(ProtocolMangledName);
4353
auto TR = swift::remote::decodeMangledType(*this, DemangledProto);
4454

45-
auto &Conformance = *DependentMember->getProtocol();
46-
if (auto Protocol = dyn_cast<ProtocolTypeRef>(TR)) {
47-
if (*Protocol != Conformance)
55+
if (Protocol != TR)
56+
continue;
57+
58+
for (auto &AssocTy : AssocTyDescriptor) {
59+
if (Member.compare(AssocTy.getName()) != 0)
4860
continue;
49-
return &AssocTyDescriptor;
61+
62+
auto SubstitutedTypeName = AssocTy.getMangledSubstitutedTypeName();
63+
auto Demangled = Demangle::demangleTypeAsNode(SubstitutedTypeName);
64+
auto *TypeWitness = swift::remote::decodeMangledType(*this, Demangled);
65+
66+
AssociatedTypeCache.insert(std::make_pair(key, TypeWitness));
67+
return TypeWitness;
5068
}
5169
}
5270
}
5371
return nullptr;
5472
}
5573

5674
const TypeRef * TypeRefBuilder::
57-
getDependentMemberTypeRef(const std::string &MangledTypeName,
58-
const DependentMemberTypeRef *DependentMember) {
59-
60-
if (auto AssocTys = lookupAssociatedTypes(MangledTypeName, DependentMember)) {
61-
for (auto &AssocTy : *AssocTys) {
62-
if (DependentMember->getMember().compare(AssocTy.getName()) != 0)
63-
continue;
75+
lookupSuperclass(const std::string &MangledTypeName) {
76+
// Superclasses are recorded as a special associated type named 'super'
77+
// on the 'AnyObject' protocol.
78+
return lookupTypeWitness(MangledTypeName, "super",
79+
ProtocolTypeRef::create(*this, "Ps9AnyObject_"));
80+
}
6481

65-
auto SubstitutedTypeName = AssocTy.getMangledSubstitutedTypeName();
66-
auto Demangled = Demangle::demangleTypeAsNode(SubstitutedTypeName);
67-
return swift::remote::decodeMangledType(*this, Demangled);
68-
}
82+
const TypeRef * TypeRefBuilder::
83+
lookupSuperclass(const TypeRef *TR) {
84+
const TypeRef *Superclass = nullptr;
85+
86+
if (auto *Nominal = dyn_cast<NominalTypeRef>(TR)) {
87+
Superclass = lookupSuperclass(Nominal->getMangledName());
88+
} else {
89+
auto BG = cast<BoundGenericTypeRef>(TR);
90+
Superclass = lookupSuperclass(BG->getMangledName());
6991
}
70-
return nullptr;
92+
93+
if (Superclass == nullptr)
94+
return nullptr;
95+
96+
return Superclass->subst(*this, TR->getSubstMap());
7197
}
7298

7399
const FieldDescriptor *

test/Reflection/Inputs/TypeLowering.swift

+22-2
Original file line numberDiff line numberDiff line change
@@ -17,19 +17,39 @@ public protocol P {
1717
associatedtype B
1818
}
1919

20-
public struct Foo<T, U> : P {
20+
public protocol Q : P {}
21+
22+
public struct ConformsP<T, U> : P {
23+
public typealias A = Box<U>
24+
public typealias B = Box<T>
25+
}
26+
27+
public struct ConformsQ<T, U> : Q {
2128
public typealias A = Box<U>
2229
public typealias B = Box<T>
2330
}
2431

32+
public class Base<T, U> : P {
33+
public typealias A = Box<T>
34+
public typealias B = Box<U>
35+
}
36+
37+
public class Derived : Base<Int8, Int16> {}
38+
39+
public class GenericDerived<T> : Base<T, T> {}
40+
2541
public struct Bar<T : P> {
2642
public let a: T.A
2743
public let b: T.B
2844
public let c: (T.A, T.B)
2945
}
3046

3147
public struct AssocTypeStruct {
32-
public let t: Bar<Foo<Int8, Int16>>
48+
public let t1: Bar<ConformsP<Int8, Int16>>
49+
public let t2: Bar<ConformsQ<Int8, Int16>>
50+
public let t3: Bar<Base<Int8, Int16>>
51+
public let t4: Bar<Derived>
52+
public let t5: Bar<GenericDerived<Int8>>
3353
}
3454

3555
public class C {}

0 commit comments

Comments
 (0)