@@ -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 ;
@@ -1011,6 +1065,9 @@ void ASTScopeImpl::addChild(ASTScopeImpl *child, ASTContext &ctx) {
1011
1065
assert (!child->getParent () && " child should not already have parent" );
1012
1066
child->parent = this ;
1013
1067
clearCachedSourceRangesOfMeAndAncestors ();
1068
+ // When adding a ProtocolDecl, createGenericParamsIfMissing() can call back into this tree.
1069
+ // So make sure childrenCountWhenLastExpanded is up to date.
1070
+ setChildrenCountWhenLastExpanded ();
1014
1071
}
1015
1072
1016
1073
void ASTScopeImpl::removeChildren () {
@@ -1036,8 +1093,7 @@ ASTScopeImpl *ASTScopeImpl::expandAndBeCurrent(ScopeCreator &scopeCreator) {
1036
1093
insertionPointForDeferredExpansion ().get () == insertionPoint);
1037
1094
}
1038
1095
beCurrent ();
1039
- setChildrenCountWhenLastExpanded ();
1040
- assert (checkSourceRangeAfterExpansion ());
1096
+ assert (checkSourceRangeAfterExpansion (scopeCreator.getASTContext ()));
1041
1097
return insertionPoint;
1042
1098
}
1043
1099
@@ -1448,25 +1504,30 @@ void AttachedPropertyWrapperScope::
1448
1504
1449
1505
ASTScopeImpl *GenericTypeOrExtensionWholePortion::expandScope (
1450
1506
GenericTypeOrExtensionScope *scope, ScopeCreator &scopeCreator) const {
1507
+ // Get now in case recursion emancipates scope
1508
+ auto *const ip = scope->getParent ().get ();
1509
+
1451
1510
// Prevent circular request bugs caused by illegal input and
1452
1511
// doing lookups that getExtendedNominal in the midst of getExtendedNominal.
1453
1512
// rdar://53972776
1454
1513
if (scope->shouldHaveABody () && !scope->doesDeclHaveABody ())
1455
- return scope-> getParent (). get () ;
1514
+ return ip ;
1456
1515
1457
1516
auto *deepestScope = scopeCreator.addNestedGenericParamScopesToTree (
1458
1517
scope->getDecl (), scope->getGenericContext ()->getGenericParams (), scope);
1459
1518
if (scope->getGenericContext ()->getTrailingWhereClause ())
1460
1519
scope->createTrailingWhereClauseScope (deepestScope, scopeCreator);
1461
1520
scope->createBodyScope (deepestScope, scopeCreator);
1462
- return scope-> getParent (). get () ;
1521
+ return ip ;
1463
1522
}
1464
1523
1465
1524
ASTScopeImpl *
1466
1525
IterableTypeBodyPortion::expandScope (GenericTypeOrExtensionScope *scope,
1467
1526
ScopeCreator &scopeCreator) const {
1527
+ // Get it now in case of recursion and this one gets emancipated
1528
+ auto *const ip = scope->getParent ().get ();
1468
1529
scope->expandBody (scopeCreator);
1469
- return scope-> getParent (). get () ;
1530
+ return ip ;
1470
1531
}
1471
1532
1472
1533
ASTScopeImpl *GenericTypeOrExtensionWherePortion::expandScope (
@@ -1670,7 +1731,9 @@ void IterableTypeScope::expandBody(ScopeCreator &scopeCreator) {
1670
1731
#pragma mark - reexpandIfObsolete
1671
1732
1672
1733
bool ASTScopeImpl::reexpandIfObsolete (ScopeCreator &scopeCreator) {
1673
- if (isCurrent ())
1734
+ if (scopeCreator.getIsFrozen () ||
1735
+ (isCurrent () &&
1736
+ !scopeCreator.getASTContext ().LangOpts .StressASTScopeLookup ))
1674
1737
return false ;
1675
1738
reexpand (scopeCreator);
1676
1739
return true ;
@@ -1731,6 +1794,11 @@ NullablePtr<ASTScopeImpl> ASTScopeImpl::insertionPointForDeferredExpansion() {
1731
1794
return nullptr ;
1732
1795
}
1733
1796
1797
+ NullablePtr<ASTScopeImpl>
1798
+ AbstractFunctionBodyScope::insertionPointForDeferredExpansion () {
1799
+ return getParent ().get ();
1800
+ }
1801
+
1734
1802
NullablePtr<ASTScopeImpl>
1735
1803
IterableTypeScope::insertionPointForDeferredExpansion () {
1736
1804
return portion->insertionPointForDeferredExpansion (this );
@@ -1782,20 +1850,29 @@ bool TopLevelCodeScope::isCurrent() const {
1782
1850
return bodyWhenLastExpanded == decl->getBody ();
1783
1851
}
1784
1852
1853
+ // Try to avoid the work of counting
1854
+ static const bool assumeVarsDoNotGetAdded = true ;
1855
+
1856
+ static unsigned countVars (const PatternBindingEntry &entry) {
1857
+ unsigned varCount = 0 ;
1858
+ entry.getPattern ()->forEachVariable ([&](VarDecl *) { ++varCount; });
1859
+ return varCount;
1860
+ }
1861
+
1785
1862
void PatternEntryDeclScope::beCurrent () {
1786
1863
initWhenLastExpanded = getPatternEntry ().getOriginalInit ();
1787
- unsigned varCount = 0 ;
1788
- getPatternEntry ().getPattern ()->forEachVariable (
1789
- [&](VarDecl *) { ++varCount; });
1790
- varCountWhenLastExpanded = varCount;
1864
+ if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded)
1865
+ return ;
1866
+ varCountWhenLastExpanded = countVars (getPatternEntry ());
1791
1867
}
1792
1868
bool PatternEntryDeclScope::isCurrent () const {
1793
1869
if (initWhenLastExpanded != getPatternEntry ().getOriginalInit ())
1794
1870
return false ;
1795
- unsigned varCount = 0 ;
1796
- getPatternEntry ().getPattern ()->forEachVariable (
1797
- [&](VarDecl *) { ++varCount; });
1798
- return varCount == varCountWhenLastExpanded;
1871
+ if (assumeVarsDoNotGetAdded && varCountWhenLastExpanded) {
1872
+ assert (varCountWhenLastExpanded == countVars (getPatternEntry ()));
1873
+ return true ;
1874
+ }
1875
+ return countVars (getPatternEntry ()) == varCountWhenLastExpanded;
1799
1876
}
1800
1877
1801
1878
void WholeClosureScope::beCurrent () {
0 commit comments