44
44
#include " llvm/Support/SaveAndRestore.h"
45
45
using namespace swift ;
46
46
47
+ static const Decl *
48
+ concreteSyntaxDeclForAvailableAttribute (const Decl *AbstractSyntaxDecl);
49
+
47
50
ExportContext::ExportContext (
48
51
DeclContext *DC, AvailabilityRange runningOSVersion,
49
52
FragileFunctionKind kind, bool spi, bool exported, bool implicit,
@@ -451,6 +454,8 @@ class TypeRefinementContextBuilder : private ASTWalker {
451
454
};
452
455
std::vector<ContextInfo> ContextStack;
453
456
457
+ llvm::SmallVector<const Decl *, 4 > ConcreteDeclStack;
458
+
454
459
// / Represents an entry in a stack of pending decl body type refinement
455
460
// / contexts. TRCs in this stack should be pushed onto \p ContextStack when
456
461
// / \p BodyStmt is encountered.
@@ -540,12 +545,27 @@ class TypeRefinementContextBuilder : private ASTWalker {
540
545
return MacroWalking::Arguments;
541
546
}
542
547
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
+
543
564
PreWalkAction walkToDeclPre (Decl *D) override {
544
565
PrettyStackTraceDecl trace (stackTraceAction (), D);
545
566
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 ();
549
569
550
570
// The AST of this decl may not be ready to traverse yet if it hasn't been
551
571
// full typechecked. If that's the case, we leave a placeholder node in the
@@ -561,10 +581,21 @@ class TypeRefinementContextBuilder : private ASTWalker {
561
581
562
582
// Create TRCs that cover only the body of the declaration.
563
583
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
+ }
564
591
return Action::Continue ();
565
592
}
566
593
567
594
PostWalkAction walkToDeclPost (Decl *D) override {
595
+ if (!ConcreteDeclStack.empty () && ConcreteDeclStack.back () == D) {
596
+ ConcreteDeclStack.pop_back ();
597
+ }
598
+
568
599
while (ContextStack.back ().ScopeNode .getAsDecl () == D) {
569
600
ContextStack.pop_back ();
570
601
}
@@ -640,6 +671,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
640
671
// / if no new context should be introduced.
641
672
TypeRefinementContext *getNewContextForSignatureOfDecl (Decl *D) {
642
673
if (!isa<ValueDecl>(D) &&
674
+ !isa<EnumCaseDecl>(D) &&
643
675
!isa<ExtensionDecl>(D) &&
644
676
!isa<MacroExpansionDecl>(D) &&
645
677
!isa<PatternBindingDecl>(D))
@@ -651,12 +683,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
651
683
if (isa<AbstractStorageDecl>(D) && D->getDeclContext ()->isLocalContext ())
652
684
return nullptr ;
653
685
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 ;
660
690
661
691
// Declarations with an explicit availability attribute always get a TRC.
662
692
if (hasActiveAvailableAttribute (D, Context)) {
@@ -1312,18 +1342,20 @@ class TypeRefinementContextBuilder : private ASTWalker {
1312
1342
} // end anonymous namespace
1313
1343
1314
1344
void TypeChecker::buildTypeRefinementContextHierarchy (SourceFile &SF) {
1315
- TypeRefinementContext *RootTRC = SF.getTypeRefinementContext ();
1316
1345
ASTContext &Context = SF.getASTContext ();
1317
1346
assert (!Context.LangOpts .DisableAvailabilityChecking );
1318
1347
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);
1327
1359
1328
1360
// Build refinement contexts, if necessary, for all declarations starting
1329
1361
// with StartElem.
@@ -1680,7 +1712,8 @@ concreteSyntaxDeclForAvailableAttribute(const Decl *AbstractSyntaxDecl) {
1680
1712
// event, multiple variables can be introduced with a single 'var'),
1681
1713
// so suggest adding an attribute to the PatterningBindingDecl instead.
1682
1714
if (auto *VD = dyn_cast<VarDecl>(AbstractSyntaxDecl)) {
1683
- return VD->getParentPatternBinding ();
1715
+ if (auto *PBD = VD->getParentPatternBinding ())
1716
+ return PBD;
1684
1717
}
1685
1718
1686
1719
// Similarly suggest applying the Fix-It to the parent enum case rather than
0 commit comments