24
24
#include " swift/AST/Initializer.h"
25
25
#include " swift/AST/NameLookup.h"
26
26
#include " swift/AST/Pattern.h"
27
+ #include " swift/AST/PrettyStackTrace.h"
27
28
#include " swift/AST/ProtocolConformance.h"
28
29
#include " swift/AST/SourceFile.h"
29
30
#include " swift/AST/TypeDeclFinder.h"
@@ -320,21 +321,6 @@ static bool hasActiveAvailableAttribute(Decl *D,
320
321
return getActiveAvailableAttribute (D, AC);
321
322
}
322
323
323
- static bool shouldConstrainBodyToDeploymentTarget (Decl *D) {
324
- // The declaration contains code...
325
- if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
326
- // And it has a location so we can check it...
327
- if (!afd->isImplicit () && afd->getBodySourceRange ().isValid ()) {
328
- // And the code is within our resilience domain, so it should be
329
- // compiled with the minimum deployment target, not the minimum inlining
330
- // target.
331
- return afd->getResilienceExpansion () != ResilienceExpansion::Minimal;
332
- }
333
- }
334
-
335
- return false ;
336
- }
337
-
338
324
static bool computeContainedByDeploymentTarget (TypeRefinementContext *TRC,
339
325
ASTContext &ctx) {
340
326
return TRC->getAvailabilityInfo ()
@@ -418,6 +404,10 @@ class TypeRefinementContextBuilder : private ASTWalker {
418
404
ContextStack.push_back (Info);
419
405
}
420
406
407
+ const char *stackTraceAction () const {
408
+ return " building type refinement context" ;
409
+ }
410
+
421
411
public:
422
412
TypeRefinementContextBuilder (TypeRefinementContext *TRC, ASTContext &Context)
423
413
: Context(Context) {
@@ -426,20 +416,23 @@ class TypeRefinementContextBuilder : private ASTWalker {
426
416
}
427
417
428
418
void build (Decl *D) {
419
+ PrettyStackTraceDecl trace (stackTraceAction (), D);
429
420
unsigned StackHeight = ContextStack.size ();
430
421
D->walk (*this );
431
422
assert (ContextStack.size () == StackHeight);
432
423
(void )StackHeight;
433
424
}
434
425
435
426
void build (Stmt *S) {
427
+ PrettyStackTraceStmt trace (Context, stackTraceAction (), S);
436
428
unsigned StackHeight = ContextStack.size ();
437
429
S->walk (*this );
438
430
assert (ContextStack.size () == StackHeight);
439
431
(void )StackHeight;
440
432
}
441
433
442
434
void build (Expr *E) {
435
+ PrettyStackTraceExpr trace (Context, stackTraceAction (), E);
443
436
unsigned StackHeight = ContextStack.size ();
444
437
E->walk (*this );
445
438
assert (ContextStack.size () == StackHeight);
@@ -448,6 +441,8 @@ class TypeRefinementContextBuilder : private ASTWalker {
448
441
449
442
private:
450
443
bool walkToDeclPre (Decl *D) override {
444
+ PrettyStackTraceDecl trace (stackTraceAction (), D);
445
+
451
446
// Adds in a parent TRC for decls which are syntactically nested but are not
452
447
// represented that way in the AST. (Particularly, AbstractStorageDecl
453
448
// parents for AccessorDecl children.)
@@ -460,17 +455,12 @@ class TypeRefinementContextBuilder : private ASTWalker {
460
455
pushContext (DeclTRC, D);
461
456
}
462
457
463
- // Adds in a TRC that covers only the body of the declaration.
464
- if (auto BodyTRC = getNewContextForBodyOfDecl (D)) {
465
- pushContext (BodyTRC, D);
466
- }
467
-
458
+ // Create TRCs that cover only the body of the declaration.
459
+ buildContextsForBodyOfDecl (D);
468
460
return true ;
469
461
}
470
462
471
463
bool walkToDeclPost (Decl *D) override {
472
- // As seen above, we could have up to three TRCs in the stack for a single
473
- // declaration.
474
464
while (ContextStack.back ().ScopeNode .getAsDecl () == D) {
475
465
ContextStack.pop_back ();
476
466
}
@@ -515,7 +505,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
515
505
return nullptr ;
516
506
}
517
507
518
- // / Builds the type refinement hierarchy for the body of the function .
508
+ // / Builds the type refinement hierarchy for the signature of the declaration .
519
509
TypeRefinementContext *buildDeclarationRefinementContext (Decl *D) {
520
510
// We require a valid range in order to be able to query for the TRC
521
511
// corresponding to a given SourceLoc.
@@ -611,15 +601,19 @@ class TypeRefinementContextBuilder : private ASTWalker {
611
601
if (auto *storageDecl = dyn_cast<AbstractStorageDecl>(D)) {
612
602
// Use the declaration's availability for the context when checking
613
603
// the bodies of its accessors.
604
+ SourceRange Range = storageDecl->getSourceRange ();
614
605
615
- Decl *locDecl = D;
616
606
// For a variable declaration (without accessors) we use the range of the
617
607
// containing pattern binding declaration to make sure that we include
618
- // any type annotation in the type refinement context range.
619
- if (auto varDecl = dyn_cast<VarDecl>(storageDecl)) {
620
- auto *PBD = varDecl->getParentPatternBinding ();
621
- if (PBD)
622
- locDecl = PBD;
608
+ // any type annotation in the type refinement context range. We also
609
+ // need to include any attached property wrappers.
610
+ if (auto *varDecl = dyn_cast<VarDecl>(storageDecl)) {
611
+ if (auto *PBD = varDecl->getParentPatternBinding ())
612
+ Range = PBD->getSourceRange ();
613
+
614
+ for (auto *propertyWrapper : varDecl->getAttachedPropertyWrappers ()) {
615
+ Range.widen (propertyWrapper->getRange ());
616
+ }
623
617
}
624
618
625
619
// HACK: For synthesized trivial accessors we may have not a valid
@@ -628,58 +622,91 @@ class TypeRefinementContextBuilder : private ASTWalker {
628
622
// to update AbstractStorageDecl::addTrivialAccessors() to take brace
629
623
// locations and have callers of that method provide appropriate source
630
624
// locations.
631
- SourceLoc BracesEnd = storageDecl->getBracesRange ().End ;
632
- if (storageDecl->hasParsedAccessors () && BracesEnd.isValid ()) {
633
- return SourceRange (locDecl->getStartLoc (),
634
- BracesEnd);
625
+ SourceRange BracesRange = storageDecl->getBracesRange ();
626
+ if (storageDecl->hasParsedAccessors () && BracesRange.isValid ()) {
627
+ Range.widen (BracesRange);
635
628
}
636
629
637
- return locDecl-> getSourceRange () ;
630
+ return Range ;
638
631
}
639
632
640
633
return D->getSourceRange ();
641
634
}
642
635
643
- TypeRefinementContext *getNewContextForBodyOfDecl (Decl *D) {
644
- if (bodyIntroducesNewContext (D))
645
- return buildBodyRefinementContext (D);
636
+ TypeRefinementContext *createAPIBoundaryContext (Decl *D, SourceRange range) {
637
+ AvailabilityContext DeploymentTargetInfo =
638
+ AvailabilityContext::forDeploymentTarget (Context);
639
+ DeploymentTargetInfo.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
646
640
647
- return nullptr ;
641
+ return TypeRefinementContext::createForAPIBoundary (
642
+ Context, D, getCurrentTRC (), DeploymentTargetInfo, range);
648
643
}
649
644
650
- bool bodyIntroducesNewContext (Decl *D) {
651
- // Are we already constrained by the deployment target? If not, adding a
652
- // new context wouldn 't change availability.
645
+ void buildContextsForBodyOfDecl (Decl *D) {
646
+ // Are we already constrained by the deployment target? If not, adding
647
+ // new contexts won 't change availability.
653
648
if (isCurrentTRCContainedByDeploymentTarget ())
654
- return false ;
655
-
656
- // If we're in a function, check if it ought to use the deployment target.
657
- if (auto afd = dyn_cast<AbstractFunctionDecl>(D))
658
- return shouldConstrainBodyToDeploymentTarget (afd);
659
-
660
- // The only other case we care about is top-level code.
661
- return isa<TopLevelCodeDecl>(D);
662
- }
649
+ return ;
663
650
664
- TypeRefinementContext *buildBodyRefinementContext (Decl *D) {
665
- SourceRange range;
651
+ // Top level code always uses the deployment target.
666
652
if (auto tlcd = dyn_cast<TopLevelCodeDecl>(D)) {
667
- range = tlcd->getSourceRange ();
668
- } else if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
669
- range = afd->getBodySourceRange ();
670
- } else {
671
- llvm_unreachable (" unknown decl" );
653
+ pushContext (createAPIBoundaryContext (tlcd, tlcd->getSourceRange ()), D);
654
+ return ;
672
655
}
673
656
674
- AvailabilityContext DeploymentTargetInfo =
675
- AvailabilityContext::forDeploymentTarget (Context);
676
- DeploymentTargetInfo.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
657
+ // Function bodies use the deployment target if they are within the module's
658
+ // resilience domain.
659
+ if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
660
+ if (!afd->isImplicit () && afd->getBodySourceRange ().isValid () &&
661
+ afd->getResilienceExpansion () != ResilienceExpansion::Minimal) {
662
+ pushContext (createAPIBoundaryContext (afd, afd->getBodySourceRange ()),
663
+ D);
664
+ }
665
+ return ;
666
+ }
677
667
678
- return TypeRefinementContext::createForAPIBoundary (
679
- Context, D, getCurrentTRC (), DeploymentTargetInfo, range);
668
+ // Var decls may have associated pattern binding decls or property wrappers
669
+ // with init expressions. Those expressions need to be constrained to the
670
+ // deployment target unless they are exposed to clients.
671
+ if (auto vd = dyn_cast<VarDecl>(D)) {
672
+ if (!vd->hasInitialValue () || vd->isInitExposedToClients ())
673
+ return ;
674
+
675
+ if (auto *pbd = vd->getParentPatternBinding ()) {
676
+ int idx = pbd->getPatternEntryIndexForVarDecl (vd);
677
+ auto *initExpr = pbd->getInit (idx);
678
+ if (initExpr && !initExpr->isImplicit ()) {
679
+ assert (initExpr->getSourceRange ().isValid ());
680
+
681
+ // Create a TRC for the init written in the source. The ASTWalker
682
+ // won't visit these expressions so instead of pushing these onto the
683
+ // stack we build them directly.
684
+ auto *initTRC =
685
+ createAPIBoundaryContext (vd, initExpr->getSourceRange ());
686
+ TypeRefinementContextBuilder (initTRC, Context).build (initExpr);
687
+ }
688
+
689
+ // Ideally any init expression would be returned by `getInit()` above.
690
+ // However, for property wrappers it doesn't get populated until
691
+ // typechecking completes (which is too late). Instead, we find the
692
+ // the property wrapper attribute use its source range to create a TRC
693
+ // for the initializer expression.
694
+ // FIXME: Since we don't have an expression here, we can't build out its
695
+ // TRC. Currently that doesn't matter because expression contents don't
696
+ // ever contribute to the TRC, but it could become relevant if we ever
697
+ // get control flow expressions.
698
+ for (auto *wrapper : vd->getAttachedPropertyWrappers ()) {
699
+ createAPIBoundaryContext (vd, wrapper->getRange ());
700
+ }
701
+ }
702
+
703
+ return ;
704
+ }
680
705
}
681
706
682
707
std::pair<bool , Stmt *> walkToStmtPre (Stmt *S) override {
708
+ PrettyStackTraceStmt trace (Context, stackTraceAction (), S);
709
+
683
710
if (auto *IS = dyn_cast<IfStmt>(S)) {
684
711
buildIfStmtRefinementContext (IS);
685
712
return std::make_pair (false , S);
0 commit comments