@@ -93,6 +93,26 @@ static void dumpRangeable(SpecializeAttr *r, llvm::raw_ostream &f) {
93
93
llvm::errs () << " SpecializeAttr\n " ;
94
94
}
95
95
96
+ // / For Debugging
97
+ template <typename T>
98
+ bool doesRangeableRangeMatch (const T *x, const SourceManager &SM,
99
+ unsigned start, unsigned end,
100
+ StringRef file = " " ) {
101
+ auto const r = getRangeableSourceRange (x);
102
+ if (r.isInvalid ())
103
+ return false ;
104
+ if (start && SM.getLineNumber (r.Start ) != start)
105
+ return false ;
106
+ if (end && SM.getLineNumber (r.End ) != end)
107
+ return false ;
108
+ if (file.empty ())
109
+ return true ;
110
+ const auto buf = SM.findBufferContainingLoc (r.Start );
111
+ return SM.getIdentifierForBuffer (buf).endswith (file);
112
+ }
113
+
114
+ #pragma mark end of rangeable
115
+
96
116
static std::vector<ASTNode> asNodeVector (DeclRange dr) {
97
117
std::vector<ASTNode> nodes;
98
118
llvm::transform (dr, std::back_inserter (nodes),
@@ -165,9 +185,27 @@ class ScopeCreator final {
165
185
// / For allocating scopes.
166
186
ASTContext &ctx;
167
187
188
+ public:
189
+ // / Because type checking can mutate the AST, eagerly build the tree, then
190
+ // / freeze it
191
+ enum class Temperature {
192
+ Warm, // Can be lazy
193
+ Freezing, // Should expand everything eagerly
194
+ Frozen // No more changes, except when Decls are added to the source file
195
+ };
196
+
197
+ private:
198
+ // / Because type checking can mutate the AST, eagerly build the tree, then
199
+ // / freeze it
200
+ Temperature temperature = Temperature::Warm;
201
+
168
202
public:
169
203
ASTSourceFileScope *const sourceFileScope;
170
204
ASTContext &getASTContext () const { return ctx; }
205
+ bool getIsFrozen () const { return temperature == Temperature::Frozen; }
206
+ bool getIsFreezing () const { return temperature == Temperature::Freezing; }
207
+ void beFreezing () { temperature = Temperature::Freezing; }
208
+ void beFrozen () { temperature = Temperature::Frozen; }
171
209
172
210
// / The AST can have duplicate nodes, and we don't want to create scopes for
173
211
// / those.
@@ -366,7 +404,7 @@ class ScopeCreator final {
366
404
parent, vd);
367
405
});
368
406
}
369
- // HERE
407
+
370
408
public:
371
409
// / Create the matryoshka nested generic param scopes (if any)
372
410
// / that are subscopes of the receiver. Return
@@ -607,7 +645,9 @@ class ScopeCreator final {
607
645
return !n.isDecl (DeclKind::Var);
608
646
}
609
647
610
- bool shouldBeLazy () const { return ctx.LangOpts .LazyASTScopes ; }
648
+ bool shouldBeLazy () const {
649
+ return !getIsFreezing () && ctx.LangOpts .LazyASTScopes ;
650
+ }
611
651
612
652
public:
613
653
// / For debugging. Return true if scope tree contains all the decl contexts in
@@ -617,9 +657,11 @@ class ScopeCreator final {
617
657
auto allDeclContexts = findLocalizableDeclContextsInAST ();
618
658
llvm::DenseMap<const DeclContext *, const ASTScopeImpl *> bogusDCs;
619
659
bool rebuilt = false ;
620
- sourceFileScope->preOrderDo ([&](ASTScopeImpl *scope) {
621
- rebuilt |= scope->reexpandIfObsolete (*this );
622
- });
660
+ if (!getIsFrozen ()) {
661
+ sourceFileScope->preOrderDo ([&](ASTScopeImpl *scope) {
662
+ rebuilt |= scope->reexpandIfObsolete (*this );
663
+ });
664
+ }
623
665
sourceFileScope->postOrderDo ([&](ASTScopeImpl *scope) {
624
666
if (auto *dc = scope->getDeclContext ().getPtrOrNull ()) {
625
667
auto iter = allDeclContexts.find (dc);
@@ -699,12 +741,24 @@ class ScopeCreator final {
699
741
700
742
ASTScope::ASTScope (SourceFile *SF) : impl(createScopeTree(SF)) {}
701
743
744
+ void ASTScope::buildScopeTreeEagerly () {
745
+ impl->buildScopeTreeEagerly ();
746
+ }
747
+
702
748
ASTSourceFileScope *ASTScope::createScopeTree (SourceFile *SF) {
703
749
ScopeCreator *scopeCreator = new (SF->getASTContext ()) ScopeCreator (SF);
704
750
scopeCreator->sourceFileScope ->addNewDeclsToScopeTree ();
705
751
return scopeCreator->sourceFileScope ;
706
752
}
707
753
754
+ void ASTSourceFileScope::buildScopeTreeEagerly () {
755
+ scopeCreator->beFreezing ();
756
+ // Eagerly expand any decls already in the tree.
757
+ preOrderDo ([&](ASTScopeImpl *s) { s->reexpandIfObsolete (*scopeCreator); });
758
+ addNewDeclsToScopeTree ();
759
+ scopeCreator->beFrozen ();
760
+ }
761
+
708
762
void ASTSourceFileScope::addNewDeclsToScopeTree () {
709
763
assert (SF && scopeCreator);
710
764
ArrayRef<Decl *> decls = SF->Decls ;
@@ -805,6 +859,7 @@ class NodeAdder
805
859
VISIT_AND_CREATE_WHOLE_PORTION (ExtensionDecl, ExtensionScope)
806
860
VISIT_AND_CREATE_WHOLE_PORTION (StructDecl, NominalTypeScope)
807
861
VISIT_AND_CREATE_WHOLE_PORTION (ClassDecl, NominalTypeScope)
862
+ VISIT_AND_CREATE_WHOLE_PORTION (ProtocolDecl, NominalTypeScope)
808
863
VISIT_AND_CREATE_WHOLE_PORTION (EnumDecl, NominalTypeScope)
809
864
VISIT_AND_CREATE_WHOLE_PORTION (TypeAliasDecl, TypeAliasScope)
810
865
VISIT_AND_CREATE_WHOLE_PORTION (OpaqueTypeDecl, OpaqueTypeScope)
@@ -817,12 +872,6 @@ class NodeAdder
817
872
return visitAbstractFunctionDecl (ad, p, scopeCreator);
818
873
}
819
874
820
- NullablePtr<ASTScopeImpl> visitProtocolDecl (ProtocolDecl *e, ASTScopeImpl *p,
821
- ScopeCreator &scopeCreator) {
822
- return scopeCreator.ifUniqueConstructWithPortionExpandAndInsert <
823
- NominalTypeScope, GenericTypeOrExtensionWholePortion>(p, e);
824
- }
825
-
826
875
#pragma mark simple creation with deferred nodes
827
876
828
877
// Each of the following creates a new scope, so that nodes which were parsed
@@ -1011,6 +1060,9 @@ void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) {
1011
1060
assert (!child->getParent () && " child should not already have parent" );
1012
1061
child->parent = this ;
1013
1062
clearCachedSourceRangesOfMeAndAncestors ();
1063
+ // It's possible that some callees do lookups back into the tree.
1064
+ // So make sure childrenCountWhenLastExpanded is up to date.
1065
+ setChildrenCountWhenLastExpanded ();
1014
1066
}
1015
1067
1016
1068
void ASTScopeImpl::removeChildren () {
@@ -1036,8 +1088,7 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
1036
1088
insertionPointForDeferredExpansion ().get () == insertionPoint);
1037
1089
}
1038
1090
beCurrent ();
1039
- setChildrenCountWhenLastExpanded ();
1040
- assert (checkSourceRangeAfterExpansion ());
1091
+ assert (checkSourceRangeAfterExpansion (scopeCreator.getASTContext ()));
1041
1092
return insertionPoint;
1042
1093
}
1043
1094
@@ -1449,25 +1500,30 @@ void AttachedPropertyWrapperScope::
1449
1500
1450
1501
ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope (
1451
1502
GenericTypeOrExtensionScope *scope, ScopeCreator &scopeCreator) const {
1503
+ // Get now in case recursion emancipates scope
1504
+ auto *const ip = scope->getParent ().get ();
1505
+
1452
1506
// Prevent circular request bugs caused by illegal input and
1453
1507
// doing lookups that getExtendedNominal in the midst of getExtendedNominal.
1454
1508
// rdar://53972776
1455
1509
if (scope->shouldHaveABody () && !scope->doesDeclHaveABody ())
1456
- return scope-> getParent (). get () ;
1510
+ return ip ;
1457
1511
1458
1512
auto *deepestScope = scopeCreator.addNestedGenericParamScopesToTree (
1459
1513
scope->getDecl (), scope->getGenericContext ()->getGenericParams (), scope);
1460
1514
if (scope->getGenericContext ()->getTrailingWhereClause ())
1461
1515
scope->createTrailingWhereClauseScope (deepestScope, scopeCreator);
1462
1516
scope->createBodyScope (deepestScope, scopeCreator);
1463
- return scope-> getParent (). get () ;
1517
+ return ip ;
1464
1518
}
1465
1519
1466
1520
ASTScopeImpl *
1467
1521
IterableTypeBodyPortion::expandScope (GenericTypeOrExtensionScope *scope,
1468
1522
ScopeCreator &scopeCreator) const {
1523
+ // Get it now in case of recursion and this one gets emancipated
1524
+ auto *const ip = scope->getParent ().get ();
1469
1525
scope->expandBody (scopeCreator);
1470
- return scope-> getParent (). get () ;
1526
+ return ip ;
1471
1527
}
1472
1528
1473
1529
ASTScopeImpl *GenericTypeOrExtensionWherePortion::expandScope (
@@ -1671,7 +1727,9 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
1671
1727
#pragma mark - reexpandIfObsolete
1672
1728
1673
1729
bool ASTScopeImpl::reexpandIfObsolete (ScopeCreator &scopeCreator) {
1674
- if (isCurrent ())
1730
+ if (scopeCreator.getIsFrozen () ||
1731
+ (isCurrent () &&
1732
+ !scopeCreator.getASTContext ().LangOpts .StressASTScopeLookup ))
1675
1733
return false ;
1676
1734
reexpand (scopeCreator);
1677
1735
return true ;
@@ -1732,6 +1790,11 @@ NullablePtr<ASTScopeImpl> ASTScopeImpl::insertionPointForDeferredExpansion() {
1732
1790
return nullptr ;
1733
1791
}
1734
1792
1793
+ NullablePtr<ASTScopeImpl>
1794
+ AbstractFunctionBodyScope::insertionPointForDeferredExpansion () {
1795
+ return getParent ().get ();
1796
+ }
1797
+
1735
1798
NullablePtr<ASTScopeImpl>
1736
1799
IterableTypeScope::insertionPointForDeferredExpansion () {
1737
1800
return portion->insertionPointForDeferredExpansion (this );
@@ -1783,20 +1846,29 @@ bool TopLevelCodeScope::isCurrent() const {
1783
1846
return bodyWhenLastExpanded == decl->getBody ();
1784
1847
}
1785
1848
1849
+ // Try to avoid the work of counting
1850
+ static const bool assumeVarsDoNotGetAdded = true ;
1851
+
1852
+ static unsigned countVars (const PatternBindingEntry &entry) {
1853
+ unsigned varCount = 0 ;
1854
+ entry.getPattern ()->forEachVariable ([&](VarDecl *) { ++varCount; });
1855
+ return varCount;
1856
+ }
1857
+
1786
1858
void PatternEntryDeclScope::beCurrent () {
1787
1859
initWhenLastExpanded = getPatternEntry ().getOriginalInit ();
1788
- unsigned varCount = 0 ;
1789
- getPatternEntry ().getPattern ()->forEachVariable (
1790
- [&](VarDecl *) { ++varCount; });
1791
- varCountWhenLastExpanded = varCount;
1860
+ if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded)
1861
+ return ;
1862
+ varCountWhenLastExpanded = countVars (getPatternEntry ());
1792
1863
}
1793
1864
bool PatternEntryDeclScope::isCurrent () const {
1794
1865
if (initWhenLastExpanded != getPatternEntry ().getOriginalInit ())
1795
1866
return false ;
1796
- unsigned varCount = 0 ;
1797
- getPatternEntry ().getPattern ()->forEachVariable (
1798
- [&](VarDecl *) { ++varCount; });
1799
- return varCount == varCountWhenLastExpanded;
1867
+ if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) {
1868
+ assert (varCountWhenLastExpanded == countVars (getPatternEntry ()));
1869
+ return true ;
1870
+ }
1871
+ return countVars (getPatternEntry ()) == varCountWhenLastExpanded;
1800
1872
}
1801
1873
1802
1874
void WholeClosureScope::beCurrent () {
0 commit comments