Skip to content

Commit 4fa8dad

Browse files
authored
Merge pull request #26626 from slavapestov/enable-delayed-member-parsing
Enable delayed member parsing
2 parents da39eec + 2f33356 commit 4fa8dad

File tree

17 files changed

+286
-121
lines changed

17 files changed

+286
-121
lines changed

include/swift/AST/ASTContext.h

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -829,10 +829,6 @@ class ASTContext final {
829829
/// \param IDC The context whose member decls should be lazily parsed.
830830
void parseMembers(IterableDeclContext *IDC);
831831

832-
/// Use the lazy parsers associated with the context to check whether the decl
833-
/// context has been parsed.
834-
bool hasUnparsedMembers(const IterableDeclContext *IDC) const;
835-
836832
/// Get the lazy function data for the given generic context.
837833
///
838834
/// \param lazyLoader If non-null, the lazy loader to use when creating the

include/swift/AST/DeclContext.h

Lines changed: 50 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -459,6 +459,10 @@ class alignas(1 << DeclContextAlignInBits) DeclContext {
459459
/// are used.
460460
ResilienceExpansion getResilienceExpansion() const;
461461

462+
/// Returns true if this context may possibly contain members visible to
463+
/// AnyObject dynamic lookup.
464+
bool mayContainMembersAccessedByDynamicLookup() const;
465+
462466
/// Returns true if lookups within this context could affect downstream files.
463467
///
464468
/// \param functionsAreNonCascading If true, functions are considered non-
@@ -697,7 +701,18 @@ class IterableDeclContext {
697701
/// detect when a member has been added. A bit would suffice,
698702
/// but would be more fragile, The scope code could count the members each
699703
/// time, but I think it's a better trade to just keep a count here.
700-
unsigned memberCount = 0;
704+
unsigned MemberCount : 29;
705+
706+
/// Whether parsing the members of this context has been delayed.
707+
unsigned HasUnparsedMembers : 1;
708+
709+
/// Whether delayed parsing detected a possible operator definition
710+
/// while skipping the body of this context.
711+
unsigned HasOperatorDeclarations : 1;
712+
713+
/// Whether delayed parsing detect a possible nested class definition
714+
/// while skipping the body of this context.
715+
unsigned HasNestedClassDeclarations : 1;
701716

702717
template<class A, class B, class C>
703718
friend struct ::llvm::cast_convert_val;
@@ -709,13 +724,44 @@ class IterableDeclContext {
709724

710725
public:
711726
IterableDeclContext(IterableDeclContextKind kind)
712-
: LastDeclAndKind(nullptr, kind) { }
727+
: LastDeclAndKind(nullptr, kind) {
728+
MemberCount = 0;
729+
HasOperatorDeclarations = 0;
730+
HasUnparsedMembers = 0;
731+
HasNestedClassDeclarations = 0;
732+
}
713733

714734
/// Determine the kind of iterable context we have.
715735
IterableDeclContextKind getIterableContextKind() const {
716736
return LastDeclAndKind.getInt();
717737
}
718738

739+
bool hasUnparsedMembers() const {
740+
return HasUnparsedMembers;
741+
}
742+
743+
void setHasUnparsedMembers() {
744+
HasUnparsedMembers = 1;
745+
}
746+
747+
bool maybeHasOperatorDeclarations() const {
748+
return HasOperatorDeclarations;
749+
}
750+
751+
void setMaybeHasOperatorDeclarations() {
752+
assert(hasUnparsedMembers());
753+
HasOperatorDeclarations = 1;
754+
}
755+
756+
bool maybeHasNestedClassDeclarations() const {
757+
return HasNestedClassDeclarations;
758+
}
759+
760+
void setMaybeHasNestedClassDeclarations() {
761+
assert(hasUnparsedMembers());
762+
HasNestedClassDeclarations = 1;
763+
}
764+
719765
/// Retrieve the set of members in this context.
720766
DeclRange getMembers() const;
721767

@@ -728,8 +774,8 @@ class IterableDeclContext {
728774
/// is inserted immediately after the hint.
729775
void addMember(Decl *member, Decl *hint = nullptr);
730776

731-
/// See \c memberCount
732-
unsigned getMemberCount() const { return memberCount; }
777+
/// See \c MemberCount
778+
unsigned getMemberCount() const { return MemberCount; }
733779

734780
/// Check whether there are lazily-loaded members.
735781
bool hasLazyMembers() const {

include/swift/Frontend/Frontend.h

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -374,6 +374,8 @@ class CompilerInstance {
374374
std::unique_ptr<ASTContext> Context;
375375
std::unique_ptr<SILModule> TheSILModule;
376376

377+
std::unique_ptr<PersistentParserState> PersistentState;
378+
377379
/// Null if no tracker.
378380
std::unique_ptr<DependencyTracker> DepTracker;
379381

@@ -634,21 +636,18 @@ class CompilerInstance {
634636

635637
void parseLibraryFile(unsigned BufferID,
636638
const ImplicitImports &implicitImports,
637-
PersistentParserState &PersistentState,
638639
DelayedParsingCallbacks *DelayedCB);
639640

640641
/// Return true if had load error
641642
bool
642643
parsePartialModulesAndLibraryFiles(const ImplicitImports &implicitImports,
643-
PersistentParserState &PersistentState,
644644
DelayedParsingCallbacks *DelayedCB);
645645

646646
OptionSet<TypeCheckingFlags> computeTypeCheckingOptions();
647647

648648
void forEachFileToTypeCheck(llvm::function_ref<void(SourceFile &)> fn);
649649

650650
void parseAndTypeCheckMainFileUpTo(SourceFile::ASTStage_t LimitStage,
651-
PersistentParserState &PersistentState,
652651
DelayedParsingCallbacks *DelayedParseCB,
653652
OptionSet<TypeCheckingFlags> TypeCheckOptions);
654653

include/swift/Parse/Parser.h

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -887,7 +887,14 @@ class Parser {
887887

888888
void parseDeclListDelayed(IterableDeclContext *IDC);
889889

890-
bool canDelayMemberDeclParsing();
890+
bool parseMemberDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
891+
SourceLoc PosBeforeLB,
892+
Diag<> ErrorDiag,
893+
ParseDeclOptions Options,
894+
IterableDeclContext *IDC);
895+
896+
bool canDelayMemberDeclParsing(bool &HasOperatorDeclarations,
897+
bool &HasNestedClassDeclarations);
891898

892899
bool delayParsingDeclList(SourceLoc LBLoc, SourceLoc &RBLoc,
893900
SourceLoc PosBeforeLB,

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2008,13 +2008,8 @@ LazyContextData *ASTContext::getOrCreateLazyContextData(
20082008
return entry;
20092009
}
20102010

2011-
bool ASTContext::hasUnparsedMembers(const IterableDeclContext *IDC) const {
2012-
auto parsers = getImpl().lazyParsers;
2013-
return std::any_of(parsers.begin(), parsers.end(),
2014-
[IDC](LazyMemberParser *p) { return p->hasUnparsedMembers(IDC); });
2015-
}
2016-
20172011
void ASTContext::parseMembers(IterableDeclContext *IDC) {
2012+
assert(IDC->hasUnparsedMembers());
20182013
for (auto *p: getImpl().lazyParsers) {
20192014
if (p->hasUnparsedMembers(IDC))
20202015
p->parseMembers(IDC);

lib/AST/ASTVerifier.cpp

Lines changed: 11 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -748,17 +748,17 @@ class Verifier : public ASTWalker {
748748
void cleanup(NODE *fn) { \
749749
popFunction(fn); \
750750
}
751-
#define SCOPE_LIKE(NODE) \
752-
bool shouldVerify(NODE *fn) { \
753-
pushScope(fn); \
754-
if (fn->hasLazyMembers()) \
751+
#define TYPE_LIKE(NODE) \
752+
bool shouldVerify(NODE *dc) { \
753+
pushScope(dc); \
754+
if (dc->hasLazyMembers()) \
755755
return false; \
756-
if (fn->getASTContext().hasUnparsedMembers(fn)) \
756+
if (dc->hasUnparsedMembers()) \
757757
return false; \
758-
return shouldVerify(cast<ASTNodeBase<NODE*>::BaseTy>(fn));\
758+
return shouldVerify(cast<ASTNodeBase<NODE*>::BaseTy>(dc));\
759759
} \
760-
void cleanup(NODE *fn) { \
761-
popScope(fn); \
760+
void cleanup(NODE *dc) { \
761+
popScope(dc); \
762762
}
763763

764764
FUNCTION_LIKE(AbstractClosureExpr)
@@ -767,10 +767,10 @@ class Verifier : public ASTWalker {
767767
FUNCTION_LIKE(FuncDecl)
768768
FUNCTION_LIKE(EnumElementDecl)
769769
FUNCTION_LIKE(SubscriptDecl)
770-
SCOPE_LIKE(NominalTypeDecl)
771-
SCOPE_LIKE(ExtensionDecl)
770+
TYPE_LIKE(NominalTypeDecl)
771+
TYPE_LIKE(ExtensionDecl)
772772

773-
#undef SCOPE_LIKE
773+
#undef TYPE_LIKE
774774
#undef FUNCTION_LIKE
775775

776776
bool shouldVerify(BraceStmt *BS) {

lib/AST/Decl.cpp

Lines changed: 2 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -2672,26 +2672,14 @@ bool ValueDecl::canBeAccessedByDynamicLookup() const {
26722672
if (!hasName())
26732673
return false;
26742674

2675-
// Dynamic lookup can only find class and protocol members, or extensions of
2676-
// classes.
2677-
auto nominalDC = getDeclContext()->getSelfNominalTypeDecl();
2678-
if (!nominalDC ||
2679-
(!isa<ClassDecl>(nominalDC) && !isa<ProtocolDecl>(nominalDC)))
2680-
return false;
2681-
2682-
// Dynamic lookup cannot find results within a non-protocol generic context,
2683-
// because there is no sensible way to infer the generic arguments.
2684-
if (getDeclContext()->isGenericContext() && !isa<ProtocolDecl>(nominalDC))
2675+
auto *dc = getDeclContext();
2676+
if (!dc->mayContainMembersAccessedByDynamicLookup())
26852677
return false;
26862678

26872679
// Dynamic lookup can find functions, variables, and subscripts.
26882680
if (!isa<FuncDecl>(this) && !isa<VarDecl>(this) && !isa<SubscriptDecl>(this))
26892681
return false;
26902682

2691-
// Dynamic lookup can only find @objc members.
2692-
if (!isObjC())
2693-
return false;
2694-
26952683
return true;
26962684
}
26972685

lib/AST/DeclContext.cpp

Lines changed: 28 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -475,6 +475,25 @@ unsigned DeclContext::getSemanticDepth() const {
475475
return 1 + getParent()->getSemanticDepth();
476476
}
477477

478+
bool DeclContext::mayContainMembersAccessedByDynamicLookup() const {
479+
// Dynamic lookup can only find class and protocol members, or extensions of
480+
// classes.
481+
if (auto *NTD = dyn_cast<NominalTypeDecl>(this)) {
482+
if (isa<ClassDecl>(NTD))
483+
if (!isGenericContext())
484+
return true;
485+
if (auto *PD = dyn_cast<ProtocolDecl>(NTD))
486+
if (PD->getAttrs().hasAttribute<ObjCAttr>())
487+
return true;
488+
} else if (auto *ED = dyn_cast<ExtensionDecl>(this)) {
489+
if (auto *CD = dyn_cast<ClassDecl>(ED->getExtendedNominal()))
490+
if (!CD->isGenericContext())
491+
return true;
492+
}
493+
494+
return false;
495+
}
496+
478497
bool DeclContext::walkContext(ASTWalker &Walker) {
479498
switch (getContextKind()) {
480499
case DeclContextKind::Module:
@@ -726,7 +745,7 @@ DeclRange IterableDeclContext::getMembers() const {
726745
void IterableDeclContext::addMember(Decl *member, Decl *Hint) {
727746
// Add the member to the list of declarations without notification.
728747
addMemberSilently(member, Hint);
729-
++memberCount;
748+
++MemberCount;
730749

731750
// Notify our parent declaration that we have added the member, which can
732751
// be used to update the lookup tables.
@@ -794,13 +813,19 @@ void IterableDeclContext::setMemberLoader(LazyMemberLoader *loader,
794813
}
795814

796815
void IterableDeclContext::loadAllMembers() const {
816+
ASTContext &ctx = getASTContext();
817+
797818
// Lazily parse members.
798-
getASTContext().parseMembers(const_cast<IterableDeclContext*>(this));
819+
if (HasUnparsedMembers) {
820+
auto *IDC = const_cast<IterableDeclContext *>(this);
821+
ctx.parseMembers(IDC);
822+
IDC->HasUnparsedMembers = 0;
823+
}
824+
799825
if (!hasLazyMembers())
800826
return;
801827

802828
// Don't try to load all members re-entrant-ly.
803-
ASTContext &ctx = getASTContext();
804829
auto contextInfo = ctx.getOrCreateLazyIterableContextData(this,
805830
/*lazyLoader=*/nullptr);
806831
auto lazyMembers = FirstDeclAndLazyMembers.getInt() & ~LazyMembers::Present;

lib/AST/Module.cpp

Lines changed: 19 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -189,30 +189,40 @@ template<typename Range>
189189
void SourceLookupCache::doPopulateCache(Range decls,
190190
bool onlyOperators) {
191191
for (Decl *D : decls) {
192-
if (auto *VD = dyn_cast<ValueDecl>(D))
192+
if (auto *VD = dyn_cast<ValueDecl>(D)) {
193193
if (onlyOperators ? VD->isOperator() : VD->hasName()) {
194194
// Cache the value under both its compound name and its full name.
195195
TopLevelValues.add(VD);
196196
}
197+
}
198+
197199
if (auto *NTD = dyn_cast<NominalTypeDecl>(D))
198-
doPopulateCache(NTD->getMembers(), true);
200+
if (!NTD->hasUnparsedMembers() || NTD->maybeHasOperatorDeclarations())
201+
doPopulateCache(NTD->getMembers(), true);
199202

200203
// Avoid populating the cache with the members of invalid extension
201204
// declarations. These members can be used to point validation inside of
202205
// a malformed context.
203206
if (D->isInvalid()) continue;
204207

205208
if (auto *ED = dyn_cast<ExtensionDecl>(D))
206-
doPopulateCache(ED->getMembers(), true);
209+
if (!ED->hasUnparsedMembers() || ED->maybeHasOperatorDeclarations())
210+
doPopulateCache(ED->getMembers(), true);
207211
}
208212
}
209213

210214
void SourceLookupCache::populateMemberCache(const SourceFile &SF) {
211215
for (const Decl *D : SF.Decls) {
212216
if (const auto *NTD = dyn_cast<NominalTypeDecl>(D)) {
213-
addToMemberCache(NTD->getMembers());
217+
if (!NTD->hasUnparsedMembers() ||
218+
NTD->maybeHasNestedClassDeclarations() ||
219+
NTD->mayContainMembersAccessedByDynamicLookup())
220+
addToMemberCache(NTD->getMembers());
214221
} else if (const auto *ED = dyn_cast<ExtensionDecl>(D)) {
215-
addToMemberCache(ED->getMembers());
222+
if (!ED->hasUnparsedMembers() ||
223+
ED->maybeHasNestedClassDeclarations() ||
224+
ED->mayContainMembersAccessedByDynamicLookup())
225+
addToMemberCache(ED->getMembers());
216226
}
217227
}
218228

@@ -228,7 +238,10 @@ void SourceLookupCache::addToMemberCache(DeclRange decls) {
228238
if (auto NTD = dyn_cast<NominalTypeDecl>(VD)) {
229239
assert(!VD->canBeAccessedByDynamicLookup() &&
230240
"inner types cannot be accessed by dynamic lookup");
231-
addToMemberCache(NTD->getMembers());
241+
if (!NTD->hasUnparsedMembers() ||
242+
NTD->maybeHasNestedClassDeclarations() ||
243+
NTD->mayContainMembersAccessedByDynamicLookup())
244+
addToMemberCache(NTD->getMembers());
232245
} else if (VD->canBeAccessedByDynamicLookup()) {
233246
ClassMembers.add(VD);
234247
}

lib/AST/NameLookup.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1025,6 +1025,7 @@ populateLookupTableEntryFromExtensions(ASTContext &ctx,
10251025
if (!ignoreNewExtensions) {
10261026
for (auto e : nominal->getExtensions()) {
10271027
if (e->wasDeserialized() || e->hasClangNode()) {
1028+
assert(!e->hasUnparsedMembers());
10281029
if (populateLookupTableEntryFromLazyIDCLoader(ctx, table,
10291030
name, e)) {
10301031
return true;
@@ -1054,6 +1055,8 @@ void NominalTypeDecl::prepareLookupTable(bool ignoreNewExtensions) {
10541055
}
10551056

10561057
if (hasLazyMembers()) {
1058+
assert(!hasUnparsedMembers());
1059+
10571060
// Lazy members: if the table needs population, populate the table _only
10581061
// from those members already in the IDC member list_ such as implicits or
10591062
// globals-as-members, then update table entries from the extensions that
@@ -1186,6 +1189,14 @@ TinyPtrVector<ValueDecl *> NominalTypeDecl::lookupDirect(
11861189
for (auto E : getExtensions())
11871190
(void)E->getMembers();
11881191
}
1192+
} else {
1193+
// We still have to parse any unparsed extensions.
1194+
if (!ignoreNewExtensions) {
1195+
for (auto *e : getExtensions()) {
1196+
if (e->hasUnparsedMembers())
1197+
e->loadAllMembers();
1198+
}
1199+
}
11891200
}
11901201

11911202
// Next, in all cases, prepare the lookup table for use, possibly

0 commit comments

Comments
 (0)