4444#include " llvm/Support/SaveAndRestore.h"
4545using namespace swift ;
4646
47+ static const Decl *
48+ concreteSyntaxDeclForAvailableAttribute (const Decl *AbstractSyntaxDecl);
49+
4750ExportContext::ExportContext (
4851 DeclContext *DC, AvailabilityRange runningOSVersion,
4952 FragileFunctionKind kind, bool spi, bool exported, bool implicit,
@@ -451,6 +454,8 @@ class TypeRefinementContextBuilder : private ASTWalker {
451454 };
452455 std::vector<ContextInfo> ContextStack;
453456
457+ llvm::SmallVector<const Decl *, 4 > ConcreteDeclStack;
458+
454459 // / Represents an entry in a stack of pending decl body type refinement
455460 // / contexts. TRCs in this stack should be pushed onto \p ContextStack when
456461 // / \p BodyStmt is encountered.
@@ -540,12 +545,27 @@ class TypeRefinementContextBuilder : private ASTWalker {
540545 return MacroWalking::Arguments;
541546 }
542547
548+ bool shouldSkipDecl (Decl *D) const {
549+ // Implicit decls don't have source locations so they cannot have a TRC.
550+ if (D->isImplicit ())
551+ return true ;
552+
553+ // Only visit a node that has a corresponding concrete syntax node if we are
554+ // already walking that concrete syntax node.
555+ auto *concreteDecl = concreteSyntaxDeclForAvailableAttribute (D);
556+ if (concreteDecl != D) {
557+ if (ConcreteDeclStack.empty () || ConcreteDeclStack.back () != concreteDecl)
558+ return true ;
559+ }
560+
561+ return false ;
562+ }
563+
543564 PreWalkAction walkToDeclPre (Decl *D) override {
544565 PrettyStackTraceDecl trace (stackTraceAction (), D);
545566
546- // Implicit decls don't have source locations so they cannot have a TRC.
547- if (D->isImplicit ())
548- return Action::Continue ();
567+ if (shouldSkipDecl (D))
568+ return Action::SkipNode ();
549569
550570 // The AST of this decl may not be ready to traverse yet if it hasn't been
551571 // full typechecked. If that's the case, we leave a placeholder node in the
@@ -561,10 +581,21 @@ class TypeRefinementContextBuilder : private ASTWalker {
561581
562582 // Create TRCs that cover only the body of the declaration.
563583 buildContextsForBodyOfDecl (D);
584+
585+ // If this decl is the concrete syntax decl for some abstract syntax decl,
586+ // push it onto the stack so that the abstract syntax decls may be visited.
587+ auto *abstractDecl = abstractSyntaxDeclForAvailableAttribute (D);
588+ if (abstractDecl != D) {
589+ ConcreteDeclStack.push_back (D);
590+ }
564591 return Action::Continue ();
565592 }
566593
567594 PostWalkAction walkToDeclPost (Decl *D) override {
595+ if (!ConcreteDeclStack.empty () && ConcreteDeclStack.back () == D) {
596+ ConcreteDeclStack.pop_back ();
597+ }
598+
568599 while (ContextStack.back ().ScopeNode .getAsDecl () == D) {
569600 ContextStack.pop_back ();
570601 }
@@ -640,6 +671,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
640671 // / if no new context should be introduced.
641672 TypeRefinementContext *getNewContextForSignatureOfDecl (Decl *D) {
642673 if (!isa<ValueDecl>(D) &&
674+ !isa<EnumCaseDecl>(D) &&
643675 !isa<ExtensionDecl>(D) &&
644676 !isa<MacroExpansionDecl>(D) &&
645677 !isa<PatternBindingDecl>(D))
@@ -651,12 +683,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
651683 if (isa<AbstractStorageDecl>(D) && D->getDeclContext ()->isLocalContext ())
652684 return nullptr ;
653685
654- // Don't introduce for variable declarations that have a parent pattern
655- // binding; all of the relevant information is on the pattern binding.
656- if (auto var = dyn_cast<VarDecl>(D)) {
657- if (var->getParentPatternBinding ())
658- return nullptr ;
659- }
686+ // Don't introduce for abstract syntax nodes that have separate concrete
687+ // syntax nodes. The TRC will be introduced for the concrete node instead.
688+ if (concreteSyntaxDeclForAvailableAttribute (D) != D)
689+ return nullptr ;
660690
661691 // Declarations with an explicit availability attribute always get a TRC.
662692 if (hasActiveAvailableAttribute (D, Context)) {
@@ -1312,18 +1342,20 @@ class TypeRefinementContextBuilder : private ASTWalker {
13121342} // end anonymous namespace
13131343
13141344void TypeChecker::buildTypeRefinementContextHierarchy (SourceFile &SF) {
1315- TypeRefinementContext *RootTRC = SF.getTypeRefinementContext ();
13161345 ASTContext &Context = SF.getASTContext ();
13171346 assert (!Context.LangOpts .DisableAvailabilityChecking );
13181347
1319- if (!RootTRC) {
1320- // The root type refinement context reflects the fact that all parts of
1321- // the source file are guaranteed to be executing on at least the minimum
1322- // platform version for inlining.
1323- auto MinPlatformReq = AvailabilityRange::forInliningTarget (Context);
1324- RootTRC = TypeRefinementContext::createForSourceFile (&SF, MinPlatformReq);
1325- SF.setTypeRefinementContext (RootTRC);
1326- }
1348+ // If there's already a root node, then we're done.
1349+ if (SF.getTypeRefinementContext ())
1350+ return ;
1351+
1352+ // The root type refinement context reflects the fact that all parts of
1353+ // the source file are guaranteed to be executing on at least the minimum
1354+ // platform version for inlining.
1355+ auto MinPlatformReq = AvailabilityRange::forInliningTarget (Context);
1356+ TypeRefinementContext *RootTRC =
1357+ TypeRefinementContext::createForSourceFile (&SF, MinPlatformReq);
1358+ SF.setTypeRefinementContext (RootTRC);
13271359
13281360 // Build refinement contexts, if necessary, for all declarations starting
13291361 // with StartElem.
@@ -1680,7 +1712,8 @@ concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl) {
16801712 // event, multiple variables can be introduced with a single 'var'),
16811713 // so suggest adding an attribute to the PatterningBindingDecl instead.
16821714 if (auto *VD = dyn_cast<VarDecl>(AbstractSyntaxDecl)) {
1683- return VD->getParentPatternBinding ();
1715+ if (auto *PBD = VD->getParentPatternBinding ())
1716+ return PBD;
16841717 }
16851718
16861719 // Similarly suggest applying the Fix-It to the parent enum case rather than
0 commit comments