Skip to content

Commit 5570ed5

Browse files
committed
AST: Clean up recursion guards in GenericEnvironment
Instead of using the recursiveConcreteType and recursiveSuperclass bits in EquivalenceClass, store an ErrorType to the cached value before we begin archetype construction. If a recursive call attempts to get the archetype for the same type re-entrantly, we will return an ErrorType.
1 parent 7f5eea4 commit 5570ed5

File tree

3 files changed

+73
-102
lines changed

3 files changed

+73
-102
lines changed

include/swift/AST/GenericEnvironment.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -151,6 +151,8 @@ class alignas(1 << DeclAlignInBits) GenericEnvironment final
151151
mapConformanceRefIntoContext(Type conformingType,
152152
ProtocolConformanceRef conformance) const;
153153

154+
/// Returns a substitution map that sends every generic parameter to its
155+
/// corresponding archetype in this generic environment.
154156
SubstitutionMap getForwardingSubstitutionMap() const;
155157

156158
void dump(raw_ostream &os) const;

lib/AST/GenericEnvironment.cpp

Lines changed: 70 additions & 101 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,9 @@ void GenericEnvironment::addMapping(GenericParamKey key,
7575
assert(genericParams[index] == key && "Bad generic parameter");
7676

7777
// Add the mapping from the generic parameter to the context type.
78-
assert(getContextTypes()[index].isNull() && "Already recoded this mapping");
78+
assert(getContextTypes()[index].isNull() ||
79+
getContextTypes()[index]->is<ErrorType>() &&
80+
"Already recoded this mapping");
7981
getContextTypes()[index] = contextType;
8082
}
8183

@@ -121,6 +123,8 @@ Type TypeBase::mapTypeOutOfContext() {
121123
Type
122124
GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
123125
auto &builder = *getGenericSignatureBuilder();
126+
auto &ctx = builder.getASTContext();
127+
124128
auto resolved =
125129
builder.maybeResolveEquivalenceClass(
126130
depType,
@@ -129,122 +133,86 @@ GenericEnvironment::getOrCreateArchetypeFromInterfaceType(Type depType) {
129133
if (!resolved)
130134
return ErrorType::get(depType);
131135

132-
if (auto concrete = resolved.getAsConcreteType())
133-
return concrete;
136+
if (auto concrete = resolved.getAsConcreteType()) {
137+
return mapTypeIntoContext(concrete,
138+
builder.getLookupConformanceFn());
139+
}
134140

135141
auto *equivClass = resolved.getEquivalenceClass(builder);
136142

137143
auto genericParams = getGenericParams();
138144
Type anchor = equivClass->getAnchor(builder, genericParams);
139145

140-
// If this equivalence class is mapped to a concrete type, produce that
141-
// type.
142-
if (equivClass->concreteType) {
143-
if (equivClass->recursiveConcreteType)
144-
return ErrorType::get(anchor);
145-
146-
// Prevent recursive substitution.
147-
equivClass->recursiveConcreteType = true;
148-
SWIFT_DEFER {
149-
equivClass->recursiveConcreteType = false;
150-
};
151-
152-
return mapTypeIntoContext(equivClass->concreteType,
153-
builder.getLookupConformanceFn());
154-
}
155-
156-
// Local function to check whether we have a generic parameter that has
157-
// already been recorded
158-
auto getAlreadyRecoveredGenericParam = [&]() -> Type {
159-
auto genericParam = anchor->getAs<GenericTypeParamType>();
160-
if (!genericParam) return Type();
161-
162-
auto type = getMappingIfPresent(genericParam);
163-
if (!type) return Type();
164-
165-
// We already have a mapping for this generic parameter in the generic
166-
// environment. Return it.
167-
return *type;
168-
};
169-
170-
AssociatedTypeDecl *assocType = nullptr;
146+
// First, write an ErrorType to the location where this type is cached,
147+
// to catch re-entrant lookups that might arise from an invalid generic
148+
// signature (eg, <X where X == Array<X>>).
171149
ArchetypeType *parentArchetype = nullptr;
150+
GenericTypeParamType *genericParam = nullptr;
172151
if (auto depMemTy = anchor->getAs<DependentMemberType>()) {
173-
// Map the parent type into this context.
174152
parentArchetype =
175153
getOrCreateArchetypeFromInterfaceType(depMemTy->getBase())
176154
->getAs<ArchetypeType>();
177155
if (!parentArchetype)
178156
return ErrorType::get(depMemTy);
179157

180-
// If we already have a nested type with this name, return it.
181-
assocType = depMemTy->getAssocType();
182-
if (auto nested =
183-
parentArchetype->getNestedTypeIfKnown(assocType->getName())) {
184-
return *nested;
185-
}
158+
auto name = depMemTy->getName();
159+
if (auto type = parentArchetype->getNestedTypeIfKnown(name))
160+
return *type;
186161

187-
// We will build the archetype below.
188-
} else if (auto result = getAlreadyRecoveredGenericParam()) {
189-
// Return already-contextualized generic type parameter.
190-
return result;
162+
parentArchetype->registerNestedType(name, ErrorType::get(ctx));
163+
} else {
164+
genericParam = anchor->castTo<GenericTypeParamType>();
165+
if (auto type = getMappingIfPresent(genericParam))
166+
return *type;
167+
addMapping(genericParam, ErrorType::get(ctx));
191168
}
192169

193-
// Substitute into the superclass.
194-
Type superclass = (equivClass->recursiveSuperclassType
195-
? Type() : equivClass->superclass);
196-
if (superclass && superclass->hasTypeParameter()) {
197-
// Prevent recursive substitution.
198-
equivClass->recursiveSuperclassType = true;
199-
SWIFT_DEFER {
200-
equivClass->recursiveSuperclassType = false;
201-
};
202-
203-
superclass = mapTypeIntoContext(superclass,
204-
builder.getLookupConformanceFn());
205-
if (superclass->is<ErrorType>())
206-
superclass = Type();
207-
208-
// We might have recursively recorded the archetype; if so, return early.
209-
// FIXME: This should be detectable before we end up building archetypes.
210-
if (auto result = getAlreadyRecoveredGenericParam())
211-
return result;
212-
}
170+
Type result;
213171

214-
// Build a new archetype.
172+
// If this equivalence class is mapped to a concrete type, produce that
173+
// type.
174+
if (equivClass->concreteType) {
175+
result = mapTypeIntoContext(equivClass->concreteType,
176+
builder.getLookupConformanceFn());
177+
} else {
178+
// Substitute into the superclass.
179+
Type superclass = equivClass->superclass;
180+
if (superclass && superclass->hasTypeParameter()) {
181+
superclass = mapTypeIntoContext(superclass,
182+
builder.getLookupConformanceFn());
183+
if (superclass->is<ErrorType>())
184+
superclass = Type();
185+
}
215186

216-
// Collect the protocol conformances for the archetype.
217-
SmallVector<ProtocolDecl *, 4> protos;
218-
for (const auto &conforms : equivClass->conformsTo) {
219-
auto proto = conforms.first;
187+
// Collect the protocol conformances for the archetype.
188+
SmallVector<ProtocolDecl *, 4> protos;
189+
for (const auto &conforms : equivClass->conformsTo) {
190+
auto proto = conforms.first;
220191

221-
if (!equivClass->isConformanceSatisfiedBySuperclass(proto))
222-
protos.push_back(proto);
223-
}
192+
if (!equivClass->isConformanceSatisfiedBySuperclass(proto))
193+
protos.push_back(proto);
194+
}
224195

225-
ArchetypeType *archetype;
226-
ASTContext &ctx = builder.getASTContext();
227-
if (parentArchetype) {
228-
// Create a nested archetype.
229-
auto *depMemTy = anchor->castTo<DependentMemberType>();
230-
archetype = NestedArchetypeType::getNew(ctx, parentArchetype, depMemTy,
196+
if (parentArchetype) {
197+
auto *depMemTy = anchor->castTo<DependentMemberType>();
198+
result = NestedArchetypeType::getNew(ctx, parentArchetype, depMemTy,
199+
protos, superclass,
200+
equivClass->layout);
201+
} else {
202+
result = PrimaryArchetypeType::getNew(ctx, this, genericParam,
231203
protos, superclass,
232204
equivClass->layout);
205+
}
206+
}
233207

234-
// Register this archetype with its parent.
235-
parentArchetype->registerNestedType(assocType->getName(), archetype);
208+
// Cache the new archetype for future lookups.
209+
if (auto depMemTy = anchor->getAs<DependentMemberType>()) {
210+
parentArchetype->registerNestedType(depMemTy->getName(), result);
236211
} else {
237-
// Create a top-level archetype.
238-
auto genericParam = anchor->castTo<GenericTypeParamType>();
239-
archetype = PrimaryArchetypeType::getNew(ctx, this, genericParam,
240-
protos, superclass,
241-
equivClass->layout);
242-
243-
// Register the archetype with the generic environment.
244-
addMapping(genericParam, archetype);
212+
addMapping(genericParam, result);
245213
}
246214

247-
return archetype;
215+
return result;
248216
}
249217

250218
void ArchetypeType::resolveNestedType(
@@ -258,7 +226,7 @@ void ArchetypeType::resolveNestedType(
258226

259227
assert(!nested.second ||
260228
nested.second->isEqual(result) ||
261-
(nested.second->hasError() && result->hasError()));
229+
nested.second->is<ErrorType>());
262230
nested.second = result;
263231
}
264232

@@ -275,17 +243,18 @@ Type QueryInterfaceTypeSubstitutions::operator()(SubstitutableType *type) const{
275243
return Type();
276244

277245
// If the context type isn't already known, lazily create it.
278-
Type contextType = self->getContextTypes()[index];
279-
if (!contextType) {
280-
auto mutableSelf = const_cast<GenericEnvironment *>(self);
281-
contextType = mutableSelf->getOrCreateArchetypeFromInterfaceType(type);
282-
283-
// FIXME: Redundant mapping from key -> index.
284-
if (self->getContextTypes()[index].isNull())
285-
mutableSelf->addMapping(key, contextType);
286-
}
246+
auto mutableSelf = const_cast<GenericEnvironment *>(self);
247+
Type &contextType = mutableSelf->getContextTypes()[index];
248+
if (contextType)
249+
return contextType;
287250

288-
return contextType;
251+
auto result = mutableSelf->getOrCreateArchetypeFromInterfaceType(type);
252+
253+
assert (!contextType ||
254+
contextType->isEqual(result) ||
255+
contextType->is<ErrorType>());
256+
contextType = result;
257+
return result;
289258
}
290259

291260
return Type();

lib/AST/Type.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3472,7 +3472,7 @@ void ArchetypeType::registerNestedType(Identifier name, Type nested) {
34723472
"Unable to find nested type?");
34733473
assert(!found->second ||
34743474
found->second->isEqual(nested) ||
3475-
(found->second->hasError() && nested->hasError()));
3475+
found->second->is<ErrorType>());
34763476
found->second = nested;
34773477
}
34783478

0 commit comments

Comments
 (0)