Skip to content

Commit ff40d17

Browse files
authored
Merge pull request #9651 from DougGregor/lazy-generic-env-deserialization
[Serialization] Stop pre-loading generic environments.
2 parents 6dbf523 + f5b99c7 commit ff40d17

File tree

8 files changed

+135
-65
lines changed

8 files changed

+135
-65
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

include/swift/Serialization/ModuleFile.h

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -84,17 +84,6 @@ class ModuleFile : public LazyMemberLoader {
8484
/// The number of entities that are currently being deserialized.
8585
unsigned NumCurrentDeserializingEntities = 0;
8686

87-
/// Declaration contexts with delayed generic environments, which will be
88-
/// completed as a pending action.
89-
///
90-
/// This should only be used on the module returned by
91-
/// getModuleFileForDelayedActions().
92-
///
93-
/// FIXME: This is needed because completing a generic environment can
94-
/// require the type checker, which might be gone if we delay generic
95-
/// environments too far. It is a hack.
96-
std::vector<DeclContext *> DelayedGenericEnvironments;
97-
9887
/// RAII class to be used when deserializing an entity.
9988
class DeserializingEntityRAII {
10089
ModuleFile &MF;

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);

lib/Serialization/Deserialization.cpp

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -207,12 +207,6 @@ ModuleFile &ModuleFile::getModuleFileForDelayedActions() {
207207
void ModuleFile::finishPendingActions() {
208208
assert(&getModuleFileForDelayedActions() == this &&
209209
"wrong module used for delayed actions");
210-
while (!DelayedGenericEnvironments.empty()) {
211-
// Force completion of the last generic environment.
212-
auto genericEnvDC = DelayedGenericEnvironments.back();
213-
DelayedGenericEnvironments.pop_back();
214-
(void)genericEnvDC->getGenericEnvironmentOfContext();
215-
}
216210
}
217211

218212
/// Translate from the serialization DefaultArgumentKind enumerators, which are
@@ -922,8 +916,6 @@ void ModuleFile::configureGenericEnvironment(
922916
// creation.
923917
if (auto genericSig = sigOrEnv.dyn_cast<GenericSignature *>()) {
924918
genericDecl->setLazyGenericEnvironment(this, genericSig, envID);
925-
ModuleFile &delayedActionFile = getModuleFileForDelayedActions();
926-
delayedActionFile.DelayedGenericEnvironments.push_back(genericDecl);
927919
return;
928920
}
929921

lib/Serialization/ModuleFile.cpp

Lines changed: 1 addition & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1297,11 +1297,7 @@ Status ModuleFile::associateWithFileContext(FileUnit *file,
12971297
return getStatus();
12981298
}
12991299

1300-
ModuleFile::~ModuleFile() {
1301-
assert(DelayedGenericEnvironments.empty() &&
1302-
"either finishPendingActions() was never called, or someone forgot "
1303-
"to use getModuleFileForDelayedActions()");
1304-
}
1300+
ModuleFile::~ModuleFile() { }
13051301

13061302
void ModuleFile::lookupValue(DeclName name,
13071303
SmallVectorImpl<ValueDecl*> &results) {

0 commit comments

Comments
 (0)