@@ -356,21 +356,34 @@ namespace {
356356// / A class to walk the AST to build the type refinement context hierarchy.
357357class TypeRefinementContextBuilder : private ASTWalker {
358358
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.
359366 struct ContextInfo {
360367 TypeRefinementContext *TRC;
361368
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()),
365370 // / indicating that custom logic elsewhere will handle removing
366371 // / the context when needed.
367372 ParentTy ScopeNode;
368373
369374 bool ContainedByDeploymentTarget;
370375 };
371-
372376 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;
374387
375388 // / A mapping from abstract storage declarations with accessors to
376389 // / to the type refinement contexts for those declarations. We refer to
@@ -411,6 +424,15 @@ class TypeRefinementContextBuilder : private ASTWalker {
411424 ContextStack.push_back (Info);
412425 }
413426
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+
414436 const char *stackTraceAction () const {
415437 return " building type refinement context for" ;
416438 }
@@ -474,6 +496,12 @@ class TypeRefinementContextBuilder : private ASTWalker {
474496 while (ContextStack.back ().ScopeNode .getAsDecl () == D) {
475497 ContextStack.pop_back ();
476498 }
499+
500+ while (!DeclBodyContextStack.empty () &&
501+ DeclBodyContextStack.back ().Decl == D) {
502+ DeclBodyContextStack.pop_back ();
503+ }
504+
477505 return true ;
478506 }
479507
@@ -689,18 +717,22 @@ class TypeRefinementContextBuilder : private ASTWalker {
689717
690718 // Top level code always uses the deployment target.
691719 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+ }
694724 return ;
695725 }
696726
697727 // Function bodies use the deployment target if they are within the module's
698728 // resilience domain.
699729 if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
700- if (!afd->isImplicit () && afd-> getBodySourceRange (). isValid () &&
730+ if (!afd->isImplicit () &&
701731 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+ }
704736 }
705737 return ;
706738 }
@@ -748,6 +780,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
748780 std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
749781 PrettyStackTraceStmt trace (Context, stackTraceAction (), S);
750782
783+ if (consumeDeclBodyContextIfNecessary (S)) {
784+ return std::make_pair (true , S);
785+ }
786+
751787 if (auto *IS = dyn_cast<IfStmt>(S)) {
752788 buildIfStmtRefinementContext (IS);
753789 return std::make_pair (false , S);
@@ -778,6 +814,22 @@ class TypeRefinementContextBuilder : private ASTWalker {
778814 return S;
779815 }
780816
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+
781833 // / Builds the type refinement hierarchy for the IfStmt if the guard
782834 // / introduces a new refinement context for the Then branch.
783835 // / There is no need for the caller to explicitly traverse the children
0 commit comments