@@ -26,6 +26,9 @@ GenericEnvironment::GenericEnvironment(
26
26
TypeSubstitutionMap interfaceToArchetypeMap)
27
27
: Signature(signature), Builder(builder)
28
28
{
29
+ NumMappingsRecorded = 0 ;
30
+ NumArchetypeToInterfaceMappings = 0 ;
31
+
29
32
// Clear out the memory that holds the context types.
30
33
std::uninitialized_fill (getContextTypes ().begin (), getContextTypes ().end (), Type ());
31
34
@@ -35,9 +38,6 @@ GenericEnvironment::GenericEnvironment(
35
38
// mapTypeOutOfContext() produces a human-readable type.
36
39
for (auto entry : interfaceToArchetypeMap)
37
40
addMapping (entry.first ->castTo <GenericTypeParamType>(), entry.second );
38
-
39
- // Make sure this generic environment gets destroyed.
40
- signature->getASTContext ().addDestructorCleanup (*this );
41
41
}
42
42
43
43
void GenericEnvironment::addMapping (GenericParamKey key,
@@ -54,22 +54,52 @@ void GenericEnvironment::addMapping(GenericParamKey key,
54
54
55
55
// If we mapped the generic parameter to an archetype, add it to the
56
56
// reverse mapping.
57
- auto *archetype = contextType->getAs <ArchetypeType>();
58
- if (!archetype) return ;
59
-
60
- // Check whether we've already recorded an interface type for this archetype.
61
- // If not, record one and we're done.
62
- auto genericParam = genericParams[index];
63
- auto result = ArchetypeToInterfaceMap.insert ({archetype, genericParam});
64
- if (result.second ) return ;
65
-
66
- // Multiple generic parameters map to the same archetype. If the
67
- // existing entry comes from a later generic parameter, replace it with
68
- // the earlier generic parameter. This gives us a deterministic reverse
69
- // mapping.
70
- auto otherGP = result.first ->second ->castTo <GenericTypeParamType>();
71
- if (GenericParamKey (genericParam) < GenericParamKey (otherGP))
72
- result.first ->second = genericParam;
57
+ if (auto *archetype = contextType->getAs <ArchetypeType>()) {
58
+ auto genericParam = genericParams[index];
59
+
60
+ // Check whether we've already recorded a generic parameter for this
61
+ // archetype. Note that we always perform a linear search, because we
62
+ // won't have sorted the list yet.
63
+ bool found = false ;
64
+ for (auto &mapping : getActiveArchetypeToInterfaceMappings ()) {
65
+ if (mapping.first != archetype) continue ;
66
+
67
+ // Multiple generic parameters map to the same archetype. If the
68
+ // existing entry comes from a later generic parameter, replace it with
69
+ // the earlier generic parameter. This gives us a deterministic reverse
70
+ // mapping.
71
+ auto otherGP = mapping.second ->castTo <GenericTypeParamType>();
72
+ if (GenericParamKey (genericParam) < GenericParamKey (otherGP))
73
+ mapping.second = genericParam;
74
+ found = true ;
75
+ break ;
76
+ }
77
+
78
+ // If we haven't recorded a generic parameter for this archetype, do so now.
79
+ if (!found) {
80
+ void *ptr = getArchetypeToInterfaceMappingsBuffer ().data ()
81
+ + NumArchetypeToInterfaceMappings;
82
+ new (ptr) ArchetypeToInterfaceMapping (archetype, genericParam);
83
+ ++NumArchetypeToInterfaceMappings;
84
+ }
85
+ }
86
+
87
+ // Note that we've recorded this mapping.
88
+ ++NumMappingsRecorded;
89
+
90
+ // If we've recorded all of the mappings, go ahead and sort the array of
91
+ // archetype-to-interface-type mappings.
92
+ if (NumMappingsRecorded == genericParams.size ()) {
93
+ llvm::array_pod_sort (getActiveArchetypeToInterfaceMappings ().begin (),
94
+ getActiveArchetypeToInterfaceMappings ().end (),
95
+ [](const ArchetypeToInterfaceMapping *lhs,
96
+ const ArchetypeToInterfaceMapping *rhs) -> int {
97
+ std::less<ArchetypeType *> compare;
98
+ if (compare (lhs->first , rhs->first )) return -1 ;
99
+ if (compare (rhs->first , lhs->first )) return 1 ;
100
+ return 0 ;
101
+ });
102
+ }
73
103
}
74
104
75
105
Optional<Type> GenericEnvironment::getMappingIfPresent (
@@ -88,11 +118,13 @@ Optional<Type> GenericEnvironment::getMappingIfPresent(
88
118
89
119
bool GenericEnvironment::containsPrimaryArchetype (
90
120
ArchetypeType *archetype) const {
91
- return ArchetypeToInterfaceMap.count (archetype) > 0 ;
121
+ return static_cast <bool >(
122
+ QueryArchetypeToInterfaceSubstitutions (this )(archetype));
92
123
}
93
124
94
125
Type GenericEnvironment::mapTypeOutOfContext (ModuleDecl *M, Type type) const {
95
- type = type.subst (M, ArchetypeToInterfaceMap, SubstFlags::AllowLoweredTypes);
126
+ type = type.subst (M, QueryArchetypeToInterfaceSubstitutions (this ),
127
+ SubstFlags::AllowLoweredTypes);
96
128
assert (!type->hasArchetype () && " not fully substituted" );
97
129
return type;
98
130
}
@@ -132,6 +164,70 @@ Type GenericEnvironment::QueryInterfaceTypeSubstitutions::operator()(
132
164
return Type ();
133
165
}
134
166
167
+ Type GenericEnvironment::QueryArchetypeToInterfaceSubstitutions::operator ()(
168
+ SubstitutableType *type) const {
169
+ auto archetype = type->getAs <ArchetypeType>();
170
+ if (!archetype) return Type ();
171
+
172
+ // If not all generic parameters have had their context types recorded,
173
+ // perform a linear search.
174
+ auto genericParams = self->Signature ->getGenericParams ();
175
+ unsigned numGenericParams = genericParams.size ();
176
+ if (self->NumMappingsRecorded < numGenericParams) {
177
+ // Search through all of the active archetype-to-interface mappings.
178
+ for (auto &mapping : self->getActiveArchetypeToInterfaceMappings ())
179
+ if (mapping.first == archetype) return mapping.second ;
180
+
181
+ // We don't know if the archetype is from a different context or if we
182
+ // simply haven't recorded it yet. Spin through all of the generic
183
+ // parameters looking for one that provides this mapping.
184
+ for (auto gp : genericParams) {
185
+ // Map the generic parameter into our context. If we get back an
186
+ // archetype that matches, we're done.
187
+ auto gpArchetype = self->mapTypeIntoContext (gp)->getAs <ArchetypeType>();
188
+ if (gpArchetype == archetype) return gp;
189
+ }
190
+
191
+ // We have checked all of the generic parameters and not found anything;
192
+ // there is no substitution.
193
+ return Type ();
194
+ }
195
+
196
+ // All generic parameters have ad their context types recorded, which means
197
+ // that the archetypes-to-interface-types array is sorted by address. Use a
198
+ // binary search.
199
+ struct MappingComparison {
200
+ bool operator ()(const ArchetypeToInterfaceMapping &lhs,
201
+ const ArchetypeType *rhs) const {
202
+ std::less<const ArchetypeType *> compare;
203
+
204
+ return compare (lhs.first , rhs);
205
+ }
206
+
207
+ bool operator ()(const ArchetypeType *lhs,
208
+ const ArchetypeToInterfaceMapping &rhs) const {
209
+ std::less<const ArchetypeType *> compare;
210
+
211
+ return compare (lhs, rhs.first );
212
+ }
213
+
214
+ bool operator ()(const ArchetypeToInterfaceMapping &lhs,
215
+ const ArchetypeToInterfaceMapping &rhs) const {
216
+ std::less<const ArchetypeType *> compare;
217
+
218
+ return compare (lhs.first , rhs.first );
219
+ }
220
+ } mappingComparison;
221
+
222
+ auto mappings = self->getActiveArchetypeToInterfaceMappings ();
223
+ auto known = std::lower_bound (mappings.begin (), mappings.end (), archetype,
224
+ mappingComparison);
225
+ if (known != mappings.end () && known->first == archetype)
226
+ return known->second ;
227
+
228
+ return Type ();
229
+ }
230
+
135
231
Type GenericEnvironment::mapTypeIntoContext (ModuleDecl *M, Type type) const {
136
232
type = type.subst (M, QueryInterfaceTypeSubstitutions (this ),
137
233
SubstFlags::AllowLoweredTypes);
0 commit comments