@@ -52,7 +52,23 @@ using namespace irgen;
52
52
53
53
static llvm::Value *emitArchetypeTypeMetadataRef (IRGenFunction &IGF,
54
54
CanArchetypeType archetype) {
55
- return IGF.getLocalTypeData (archetype, LocalTypeDataKind::forTypeMetadata ());
55
+ // Check for an existing cache entry.
56
+ auto localDataKind = LocalTypeDataKind::forTypeMetadata ();
57
+ auto metadata = IGF.tryGetLocalTypeData (archetype, localDataKind);
58
+
59
+ // If that's not present, this must be an associated type.
60
+ if (!metadata) {
61
+ assert (!archetype->isPrimary () &&
62
+ " type metadata for primary archetype was not bound in context" );
63
+
64
+ CanArchetypeType parent (archetype->getParent ());
65
+ metadata = emitAssociatedTypeMetadataRef (IGF, parent,
66
+ archetype->getAssocType ());
67
+
68
+ IGF.setScopedLocalTypeData (archetype, localDataKind, metadata);
69
+ }
70
+
71
+ return metadata;
56
72
}
57
73
58
74
namespace {
@@ -88,8 +104,30 @@ class ArchetypeTypeInfoBase {
88
104
unsigned which) const {
89
105
assert (which < getNumStoredProtocols ());
90
106
auto protocol = archetype->getConformsTo ()[which];
91
- return IGF.getLocalTypeData (archetype,
92
- LocalTypeDataKind::forAbstractProtocolWitnessTable (protocol));
107
+ auto localDataKind =
108
+ LocalTypeDataKind::forAbstractProtocolWitnessTable (protocol);
109
+
110
+ // Check for an existing cache entry.
111
+ auto wtable = IGF.tryGetLocalTypeData (archetype, localDataKind);
112
+
113
+ // If that's not present, this must be an associated type; drill
114
+ // down from the parent.
115
+ if (!wtable) {
116
+ assert (!archetype->isPrimary () &&
117
+ " witness table for primary archetype was not bound in context" );
118
+
119
+ // To do this, we need the metadata for the associated type.
120
+ auto associatedMetadata = emitArchetypeTypeMetadataRef (IGF, archetype);
121
+
122
+ CanArchetypeType parent (archetype->getParent ());
123
+ wtable = emitAssociatedTypeWitnessTableRef (IGF, parent,
124
+ archetype->getAssocType (),
125
+ associatedMetadata,
126
+ protocol);
127
+ IGF.setScopedLocalTypeData (archetype, localDataKind, wtable);
128
+ }
129
+
130
+ return wtable;
93
131
}
94
132
};
95
133
@@ -174,10 +212,19 @@ llvm::Value *irgen::emitArchetypeWitnessTableRef(IRGenFunction &IGF,
174
212
assert (Lowering::TypeConverter::protocolRequiresWitnessTable (proto) &&
175
213
" looking up witness table for protocol that doesn't have one" );
176
214
215
+ // Check immediately for an existing cache entry.
216
+ auto wtable = IGF.tryGetLocalTypeData (archetype,
217
+ LocalTypeDataKind::forAbstractProtocolWitnessTable (proto));
218
+ if (wtable) return wtable;
219
+
220
+ // Otherwise, find the best path from one of the protocols directly
221
+ // conformed to by the protocol, then get that conformance.
222
+ // TODO: this isn't necessarily optimal if the direct conformance isn't
223
+ // concretely available; we really ought to be comparing the full paths
224
+ // to this conformance from concrete sources.
177
225
auto &archTI = getArchetypeInfo (IGF, archetype,
178
226
IGF.getTypeInfoForLowered (archetype));
179
- auto wtable = emitImpliedWitnessTableRef (IGF, archTI.getStoredProtocols (),
180
- proto,
227
+ wtable = emitImpliedWitnessTableRef (IGF, archTI.getStoredProtocols (), proto,
181
228
[&](unsigned originIndex) -> llvm::Value* {
182
229
return archTI.getWitnessTable (IGF, archetype, originIndex);
183
230
});
0 commit comments