Skip to content

Commit f792aea

Browse files
committed
[AST] Teach the AST verifier not to deserialize generic environments.
The AST verifier was causing deserialization of generic environments, which slows things down considerably and affects our ability to test for laziness in deserialization. Prevent it from doing so---and only do the extra checkig if something else deserialized the generic environment already. ... except there are some cases where it happens through means that are harder to control (e.g., the AST walker for patterns) that need more thought.
1 parent 9ff7ff7 commit f792aea

File tree

5 files changed

+134
-41
lines changed

5 files changed

+134
-41
lines changed

include/swift/AST/Decl.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1467,6 +1467,10 @@ class GenericContext : public DeclContext {
14671467
GenericSignature *genericSig,
14681468
uint64_t genericEnvData);
14691469

1470+
/// Whether this generic context has a lazily-created generic environment
1471+
/// that has not yet been constructed.
1472+
bool hasLazyGenericEnvironment() const;
1473+
14701474
/// Set the generic context of this context.
14711475
void setGenericEnvironment(GenericEnvironment *genericEnv);
14721476
};

include/swift/AST/DeclContext.h

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -312,6 +312,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
312312
/// of its parents.
313313
GenericEnvironment *getGenericEnvironmentOfContext() const;
314314

315+
/// Whether the context has a generic environment that will be constructed
316+
/// on first access (but has not yet been constructed).
317+
bool contextHasLazyGenericEnvironment() const;
318+
315319
/// Map an interface type to a contextual type within this context.
316320
Type mapTypeIntoContext(Type type) const;
317321

lib/AST/ASTVerifier.cpp

Lines changed: 91 additions & 41 deletions
Original file line numberDiff line numberDiff line change
@@ -141,6 +141,46 @@ std::pair<bool, Expr *> dispatchVisitPreExprHelper(
141141
return {false, node};
142142
}
143143

144+
/// Describes a generic environment that might be lazily deserialized.
145+
///
146+
/// This class abstracts over a declaration context that may have a generic
147+
/// environment, ensuring that we don't deserialize the environment.
148+
struct LazyGenericEnvironment {
149+
llvm::PointerUnion<DeclContext *, GenericEnvironment *> storage;
150+
151+
explicit operator bool() const {
152+
if (storage.dyn_cast<GenericEnvironment *>())
153+
return true;
154+
155+
if (auto dc = storage.dyn_cast<DeclContext *>())
156+
return dc->getGenericSignatureOfContext();
157+
158+
return false;
159+
}
160+
161+
bool isLazy() const {
162+
if (auto dc = storage.dyn_cast<DeclContext *>())
163+
return dc->contextHasLazyGenericEnvironment();
164+
165+
return false;
166+
}
167+
168+
bool containsPrimaryArchetype(ArchetypeType *archetype) const {
169+
// Assume true so we don't deserialize.
170+
if (isLazy()) return true;
171+
172+
if (auto genericEnv = storage.dyn_cast<GenericEnvironment *>())
173+
return genericEnv->containsPrimaryArchetype(archetype);
174+
175+
if (auto dc = storage.dyn_cast<DeclContext *>()) {
176+
if (auto genericEnv = dc->getGenericEnvironmentOfContext())
177+
return genericEnv->containsPrimaryArchetype(archetype);
178+
}
179+
180+
return false;
181+
}
182+
};
183+
144184
class Verifier : public ASTWalker {
145185
PointerUnion<ModuleDecl *, SourceFile *> M;
146186
ASTContext &Ctx;
@@ -155,8 +195,8 @@ class Verifier : public ASTWalker {
155195
using ScopeLike = llvm::PointerUnion<DeclContext *, BraceStmt *>;
156196
SmallVector<ScopeLike, 4> Scopes;
157197

158-
/// The set of primary archetypes that are currently available.
159-
SmallVector<GenericEnvironment *, 2> GenericEnv;
198+
/// The stack of generic environments.
199+
SmallVector<LazyGenericEnvironment, 2> GenericEnv;
160200

161201
/// \brief The stack of optional evaluations active at this point.
162202
SmallVector<OptionalEvaluationExpr *, 4> OptionalEvaluations;
@@ -197,7 +237,7 @@ class Verifier : public ASTWalker {
197237
: M.get<SourceFile *>()->getASTContext()),
198238
Out(llvm::errs()), HadError(Ctx.hadError()) {
199239
Scopes.push_back(DC);
200-
GenericEnv.push_back(DC->getGenericEnvironmentOfContext());
240+
GenericEnv.push_back({DC});
201241
}
202242

203243
public:
@@ -447,7 +487,7 @@ class Verifier : public ASTWalker {
447487
}
448488
void verifyCheckedAlways(Stmt *S) {}
449489
void verifyCheckedAlways(Pattern *P) {
450-
if (P->hasType())
490+
if (P->hasType() && !P->getDelayedInterfaceType())
451491
verifyChecked(P->getType());
452492
}
453493
void verifyCheckedAlways(Decl *D) {
@@ -536,7 +576,7 @@ class Verifier : public ASTWalker {
536576
// Get the primary archetype.
537577
auto *parent = archetype->getPrimary();
538578

539-
if (!GenericEnv.back()->containsPrimaryArchetype(parent)) {
579+
if (!GenericEnv.back().containsPrimaryArchetype(parent)) {
540580
Out << "AST verification error: archetype "
541581
<< archetype->getString() << " not allowed in this context\n";
542582

@@ -587,14 +627,14 @@ class Verifier : public ASTWalker {
587627

588628
void pushScope(DeclContext *scope) {
589629
Scopes.push_back(scope);
590-
GenericEnv.push_back(scope->getGenericEnvironmentOfContext());
630+
GenericEnv.push_back({scope});
591631
}
592632
void pushScope(BraceStmt *scope) {
593633
Scopes.push_back(scope);
594634
}
595635
void popScope(DeclContext *scope) {
596636
assert(Scopes.back().get<DeclContext*>() == scope);
597-
assert(GenericEnv.back() == scope->getGenericEnvironmentOfContext());
637+
assert(GenericEnv.back().storage.get<DeclContext *>() == scope);
598638
Scopes.pop_back();
599639
GenericEnv.pop_back();
600640
}
@@ -2008,23 +2048,25 @@ class Verifier : public ASTWalker {
20082048

20092049
Type typeForAccessors =
20102050
var->getInterfaceType()->getReferenceStorageReferent();
2011-
typeForAccessors =
2012-
var->getDeclContext()->mapTypeIntoContext(typeForAccessors);
2013-
if (const FuncDecl *getter = var->getGetter()) {
2014-
if (getter->getParameterLists().back()->size() != 0) {
2015-
Out << "property getter has parameters\n";
2016-
abort();
2017-
}
2018-
Type getterResultType = getter->getResultInterfaceType();
2019-
getterResultType =
2020-
var->getDeclContext()->mapTypeIntoContext(getterResultType);
2021-
if (!getterResultType->isEqual(typeForAccessors)) {
2022-
Out << "property and getter have mismatched types: '";
2023-
typeForAccessors.print(Out);
2024-
Out << "' vs. '";
2025-
getterResultType.print(Out);
2026-
Out << "'\n";
2027-
abort();
2051+
if (!var->getDeclContext()->contextHasLazyGenericEnvironment()) {
2052+
typeForAccessors =
2053+
var->getDeclContext()->mapTypeIntoContext(typeForAccessors);
2054+
if (const FuncDecl *getter = var->getGetter()) {
2055+
if (getter->getParameterLists().back()->size() != 0) {
2056+
Out << "property getter has parameters\n";
2057+
abort();
2058+
}
2059+
Type getterResultType = getter->getResultInterfaceType();
2060+
getterResultType =
2061+
var->getDeclContext()->mapTypeIntoContext(getterResultType);
2062+
if (!getterResultType->isEqual(typeForAccessors)) {
2063+
Out << "property and getter have mismatched types: '";
2064+
typeForAccessors.print(Out);
2065+
Out << "' vs. '";
2066+
getterResultType.print(Out);
2067+
Out << "'\n";
2068+
abort();
2069+
}
20282070
}
20292071
}
20302072

@@ -2043,14 +2085,16 @@ class Verifier : public ASTWalker {
20432085
}
20442086
const ParamDecl *param = setter->getParameterLists().back()->get(0);
20452087
Type paramType = param->getInterfaceType();
2046-
paramType = var->getDeclContext()->mapTypeIntoContext(paramType);
2047-
if (!paramType->isEqual(typeForAccessors)) {
2048-
Out << "property and setter param have mismatched types: '";
2049-
typeForAccessors.print(Out);
2050-
Out << "' vs. '";
2051-
paramType.print(Out);
2052-
Out << "'\n";
2053-
abort();
2088+
if (!var->getDeclContext()->contextHasLazyGenericEnvironment()) {
2089+
paramType = var->getDeclContext()->mapTypeIntoContext(paramType);
2090+
if (!paramType->isEqual(typeForAccessors)) {
2091+
Out << "property and setter param have mismatched types: '";
2092+
typeForAccessors.print(Out);
2093+
Out << "' vs. '";
2094+
paramType.print(Out);
2095+
Out << "'\n";
2096+
abort();
2097+
}
20542098
}
20552099
}
20562100

@@ -2226,11 +2270,12 @@ class Verifier : public ASTWalker {
22262270
const auto &witness = normal->getWitness(req, nullptr);
22272271

22282272
if (witness.requiresSubstitution()) {
2229-
GenericEnv.push_back(witness.getSyntheticEnvironment());
2273+
GenericEnv.push_back({witness.getSyntheticEnvironment()});
22302274
for (const auto &sub : witness.getSubstitutions()) {
22312275
verifyChecked(sub.getReplacement());
22322276
}
2233-
assert(GenericEnv.back() == witness.getSyntheticEnvironment());
2277+
assert(GenericEnv.back().storage.dyn_cast<GenericEnvironment *>()
2278+
== witness.getSyntheticEnvironment());
22342279
GenericEnv.pop_back();
22352280
}
22362281

@@ -2293,9 +2338,12 @@ class Verifier : public ASTWalker {
22932338
}
22942339

22952340
void verifyChecked(GenericTypeDecl *generic) {
2296-
verifyGenericEnvironment(generic,
2297-
generic->getGenericSignature(),
2298-
generic->getGenericEnvironment());
2341+
if (!generic->hasLazyGenericEnvironment()) {
2342+
verifyGenericEnvironment(generic,
2343+
generic->getGenericSignature(),
2344+
generic->getGenericEnvironment());
2345+
}
2346+
22992347
verifyCheckedBase(generic);
23002348
}
23012349

@@ -2472,15 +2520,17 @@ class Verifier : public ASTWalker {
24722520
// If the function has a generic interface type, it should also have a
24732521
// generic signature.
24742522
if (AFD->isGenericContext() !=
2475-
(AFD->getGenericEnvironment() != nullptr)) {
2523+
(AFD->getGenericSignature() != nullptr)) {
24762524
Out << "Functions in generic context must have a generic signature\n";
24772525
AFD->dump(Out);
24782526
abort();
24792527
}
24802528

2481-
verifyGenericEnvironment(AFD,
2482-
AFD->getGenericSignature(),
2483-
AFD->getGenericEnvironment());
2529+
if (!AFD->hasLazyGenericEnvironment()) {
2530+
verifyGenericEnvironment(AFD,
2531+
AFD->getGenericSignature(),
2532+
AFD->getGenericEnvironment());
2533+
}
24842534

24852535
// If there is an interface type, it shouldn't have any unresolved
24862536
// dependent member types.

lib/AST/Decl.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -654,6 +654,10 @@ GenericEnvironment *GenericContext::getGenericEnvironment() const {
654654
return nullptr;
655655
}
656656

657+
bool GenericContext::hasLazyGenericEnvironment() const {
658+
return GenericSigOrEnv.dyn_cast<GenericSignature *>() != nullptr;
659+
}
660+
657661
void GenericContext::setGenericEnvironment(GenericEnvironment *genericEnv) {
658662
assert((GenericSigOrEnv.isNull() ||
659663
getGenericSignature()->getCanonicalSignature() ==

lib/AST/DeclContext.cpp

Lines changed: 31 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -286,6 +286,37 @@ GenericEnvironment *DeclContext::getGenericEnvironmentOfContext() const {
286286
}
287287
}
288288

289+
bool DeclContext::contextHasLazyGenericEnvironment() const {
290+
for (const DeclContext *dc = this; ; dc = dc->getParent()) {
291+
switch (dc->getContextKind()) {
292+
case DeclContextKind::Module:
293+
case DeclContextKind::FileUnit:
294+
case DeclContextKind::TopLevelCodeDecl:
295+
return false;
296+
297+
case DeclContextKind::Initializer:
298+
case DeclContextKind::SerializedLocal:
299+
case DeclContextKind::AbstractClosureExpr:
300+
// Closures and initializers can't themselves be generic, but they
301+
// can occur in generic contexts.
302+
continue;
303+
304+
case DeclContextKind::SubscriptDecl:
305+
return cast<SubscriptDecl>(dc)->hasLazyGenericEnvironment();
306+
307+
case DeclContextKind::AbstractFunctionDecl:
308+
return cast<AbstractFunctionDecl>(dc)->hasLazyGenericEnvironment();
309+
310+
case DeclContextKind::GenericTypeDecl:
311+
return cast<GenericTypeDecl>(dc)->hasLazyGenericEnvironment();
312+
313+
case DeclContextKind::ExtensionDecl:
314+
return cast<ExtensionDecl>(dc)->hasLazyGenericEnvironment();
315+
}
316+
llvm_unreachable("bad DeclContextKind");
317+
}
318+
}
319+
289320
Type DeclContext::mapTypeIntoContext(Type type) const {
290321
return GenericEnvironment::mapTypeIntoContext(
291322
getGenericEnvironmentOfContext(), type);

0 commit comments

Comments
 (0)