@@ -356,21 +356,34 @@ namespace {
356
356
// / A class to walk the AST to build the type refinement context hierarchy.
357
357
class TypeRefinementContextBuilder : private ASTWalker {
358
358
359
+ ASTContext &Context;
360
+
361
+ // / Represents an entry in a stack of active type refinement contexts. The
362
+ // / stack is used to facilitate building the TRC's tree structure. A new TRC
363
+ // / is pushed onto this stack before visiting children whenever the current
364
+ // / AST node requires a new context and the TRC is then popped
365
+ // / post-visitation.
359
366
struct ContextInfo {
360
367
TypeRefinementContext *TRC;
361
368
362
- // / The node whose end marks the end of the refinement context.
363
- // / If the builder sees this node in a post-visitor, it will pop
364
- // / the context from the stack. This node can be null (ParentTy()),
369
+ // / The AST node. This node can be null (ParentTy()),
365
370
// / indicating that custom logic elsewhere will handle removing
366
371
// / the context when needed.
367
372
ParentTy ScopeNode;
368
373
369
374
bool ContainedByDeploymentTarget;
370
375
};
371
-
372
376
std::vector<ContextInfo> ContextStack;
373
- ASTContext &Context;
377
+
378
+ // / Represents an entry in a stack of pending decl body type refinement
379
+ // / contexts. TRCs in this stack should be pushed onto \p ContextStack when
380
+ // / \p BodyStmt is encountered.
381
+ struct DeclBodyContextInfo {
382
+ TypeRefinementContext *TRC;
383
+ Decl *Decl;
384
+ Stmt *BodyStmt;
385
+ };
386
+ std::vector<DeclBodyContextInfo> DeclBodyContextStack;
374
387
375
388
// / A mapping from abstract storage declarations with accessors to
376
389
// / to the type refinement contexts for those declarations. We refer to
@@ -411,6 +424,15 @@ class TypeRefinementContextBuilder : private ASTWalker {
411
424
ContextStack.push_back (Info);
412
425
}
413
426
427
+ void pushDeclBodyContext (TypeRefinementContext *TRC, Decl *D, Stmt *S) {
428
+ DeclBodyContextInfo Info;
429
+ Info.TRC = TRC;
430
+ Info.Decl = D;
431
+ Info.BodyStmt = S;
432
+
433
+ DeclBodyContextStack.push_back (Info);
434
+ }
435
+
414
436
const char *stackTraceAction () const {
415
437
return " building type refinement context for" ;
416
438
}
@@ -474,6 +496,12 @@ class TypeRefinementContextBuilder : private ASTWalker {
474
496
while (ContextStack.back ().ScopeNode .getAsDecl () == D) {
475
497
ContextStack.pop_back ();
476
498
}
499
+
500
+ while (!DeclBodyContextStack.empty () &&
501
+ DeclBodyContextStack.back ().Decl == D) {
502
+ DeclBodyContextStack.pop_back ();
503
+ }
504
+
477
505
return true ;
478
506
}
479
507
@@ -689,18 +717,22 @@ class TypeRefinementContextBuilder : private ASTWalker {
689
717
690
718
// Top level code always uses the deployment target.
691
719
if (auto tlcd = dyn_cast<TopLevelCodeDecl>(D)) {
692
- auto *topLevelTRC = createContext (tlcd, tlcd->getSourceRange ());
693
- pushContext (topLevelTRC, D);
720
+ if (auto bodyStmt = tlcd->getBody ()) {
721
+ pushDeclBodyContext (createContext (tlcd, tlcd->getSourceRange ()), tlcd,
722
+ bodyStmt);
723
+ }
694
724
return ;
695
725
}
696
726
697
727
// Function bodies use the deployment target if they are within the module's
698
728
// resilience domain.
699
729
if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
700
- if (!afd->isImplicit () && afd-> getBodySourceRange (). isValid () &&
730
+ if (!afd->isImplicit () &&
701
731
afd->getResilienceExpansion () != ResilienceExpansion::Minimal) {
702
- auto *functionBodyTRC = createContext (afd, afd->getBodySourceRange ());
703
- pushContext (functionBodyTRC, D);
732
+ if (auto body = afd->getBody (/* canSynthesize*/ false )) {
733
+ pushDeclBodyContext (createContext (afd, afd->getBodySourceRange ()),
734
+ afd, body);
735
+ }
704
736
}
705
737
return ;
706
738
}
@@ -748,6 +780,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
748
780
std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
749
781
PrettyStackTraceStmt trace (Context, stackTraceAction (), S);
750
782
783
+ if (consumeDeclBodyContextIfNecessary (S)) {
784
+ return std::make_pair (true , S);
785
+ }
786
+
751
787
if (auto *IS = dyn_cast<IfStmt>(S)) {
752
788
buildIfStmtRefinementContext (IS);
753
789
return std::make_pair (false , S);
@@ -778,6 +814,22 @@ class TypeRefinementContextBuilder : private ASTWalker {
778
814
return S;
779
815
}
780
816
817
+ // / Consumes the top TRC from \p DeclBodyContextStack and pushes it onto the
818
+ // / \p Context stack if the given \p Stmt is the matching body statement.
819
+ // / Returns \p true if a context was pushed.
820
+ bool consumeDeclBodyContextIfNecessary (Stmt *S) {
821
+ if (DeclBodyContextStack.empty ())
822
+ return false ;
823
+
824
+ auto Info = DeclBodyContextStack.back ();
825
+ if (S != Info.BodyStmt )
826
+ return false ;
827
+
828
+ pushContext (Info.TRC , Info.BodyStmt );
829
+ DeclBodyContextStack.pop_back ();
830
+ return true ;
831
+ }
832
+
781
833
// / Builds the type refinement hierarchy for the IfStmt if the guard
782
834
// / introduces a new refinement context for the Then branch.
783
835
// / There is no need for the caller to explicitly traverse the children
0 commit comments