@@ -460,6 +460,9 @@ class TypeRefinementContextBuilder : private ASTWalker {
460
460
// Adds in a TRC that covers the entire declaration.
461
461
if (auto DeclTRC = getNewContextForSignatureOfDecl (D)) {
462
462
pushContext (DeclTRC, D);
463
+
464
+ // Possibly use this as an effective parent context later.
465
+ recordEffectiveParentContext (D, DeclTRC);
463
466
}
464
467
465
468
// Create TRCs that cover only the body of the declaration.
@@ -542,46 +545,63 @@ class TypeRefinementContextBuilder : private ASTWalker {
542
545
return nullptr ;
543
546
}
544
547
545
- // A decl only introduces a new context when it either has explicit
546
- // availability or requires the deployment target.
547
- bool HasExplicitAvailability = hasActiveAvailableAttribute (D, Context);
548
- bool ConstrainToDeploymentTarget =
549
- shouldConstrainSignatureToDeploymentTarget (D);
550
- if (!HasExplicitAvailability && !ConstrainToDeploymentTarget)
551
- return nullptr ;
548
+ // Declarations with an explicit availability attribute always get a TRC.
549
+ if (hasActiveAvailableAttribute (D, Context)) {
550
+ AvailabilityContext DeclaredAvailability =
551
+ swift::AvailabilityInference::availableRange (D, Context);
552
552
553
- // We require a valid range in order to be able to query for the TRC
554
- // corresponding to a given SourceLoc.
555
- // If this assert fires, it means we have probably synthesized an implicit
556
- // declaration without location information. The appropriate fix is
557
- // probably to gin up a source range for the declaration when synthesizing
558
- // it.
559
- assert (D->getSourceRange ().isValid ());
553
+ return TypeRefinementContext::createForDecl (
554
+ Context, D, getCurrentTRC (),
555
+ getEffectiveAvailabilityForDeclSignature (D, DeclaredAvailability),
556
+ DeclaredAvailability, refinementSourceRangeForDecl (D));
557
+ }
560
558
561
- // The potential versions in the declaration are constrained by both
562
- // the declared availability of the declaration and the potential versions
563
- // of its lexical context.
564
- AvailabilityContext ExplicitDeclInfo =
565
- swift::AvailabilityInference::availableRange (D, Context);
566
- AvailabilityContext DeclInfo = ExplicitDeclInfo;
567
- DeclInfo.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
568
-
569
- if (ConstrainToDeploymentTarget)
570
- DeclInfo.intersectWith (AvailabilityContext::forDeploymentTarget (Context));
571
-
572
- SourceRange Range = refinementSourceRangeForDecl (D);
573
- TypeRefinementContext *NewTRC;
574
- if (HasExplicitAvailability)
575
- NewTRC = TypeRefinementContext::createForDecl (
576
- Context, D, getCurrentTRC (), DeclInfo, ExplicitDeclInfo, Range);
577
- else
578
- NewTRC = TypeRefinementContext::createForAPIBoundary (
579
- Context, D, getCurrentTRC (), DeclInfo, Range);
559
+ // Declarations without explicit availability get a TRC if they are
560
+ // effectively less available than the surrounding context. For example, an
561
+ // internal property in a public struct can be effectively less available
562
+ // than the containing struct decl because the internal property will only
563
+ // be accessed by code running at the deployment target or later.
564
+ AvailabilityContext CurrentAvailability =
565
+ getCurrentTRC ()->getAvailabilityInfo ();
566
+ AvailabilityContext EffectiveAvailability =
567
+ getEffectiveAvailabilityForDeclSignature (D, CurrentAvailability);
568
+ if (CurrentAvailability.isSupersetOf (EffectiveAvailability))
569
+ return TypeRefinementContext::createForDeclImplicit (
570
+ Context, D, getCurrentTRC (), EffectiveAvailability,
571
+ refinementSourceRangeForDecl (D));
572
+
573
+ return nullptr ;
574
+ }
580
575
581
- // Possibly use this as an effective parent context later.
582
- recordEffectiveParentContext (D, NewTRC);
576
+ AvailabilityContext getEffectiveAvailabilityForDeclSignature (
577
+ Decl *D, const AvailabilityContext BaseAvailability) {
578
+ AvailabilityContext EffectiveAvailability = BaseAvailability;
579
+
580
+ // As a special case, extension decls are treated as effectively as
581
+ // available as the nominal type they extend, up to the deployment target.
582
+ // This rule is a convenience for library authors who have written
583
+ // extensions without specifying availabilty on the extension itself.
584
+ if (auto *ED = dyn_cast<ExtensionDecl>(D)) {
585
+ auto *Nominal = ED->getExtendedNominal ();
586
+ if (Nominal && !hasActiveAvailableAttribute (D, Context)) {
587
+ EffectiveAvailability.intersectWith (
588
+ swift::AvailabilityInference::availableRange (Nominal, Context));
589
+
590
+ // We want to require availability to be specified on extensions of
591
+ // types that would be potentially unavailable to the module containing
592
+ // the extension, so limit the effective availability to the deployment
593
+ // target.
594
+ EffectiveAvailability.unionWith (
595
+ AvailabilityContext::forDeploymentTarget (Context));
596
+ }
597
+ }
583
598
584
- return NewTRC;
599
+ EffectiveAvailability.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
600
+ if (shouldConstrainSignatureToDeploymentTarget (D))
601
+ EffectiveAvailability.intersectWith (
602
+ AvailabilityContext::forDeploymentTarget (Context));
603
+
604
+ return EffectiveAvailability;
585
605
}
586
606
587
607
// / Checks whether the entire declaration, including its signature, should be
@@ -607,6 +627,14 @@ class TypeRefinementContextBuilder : private ASTWalker {
607
627
// / provides a convenient place to specify the refined range when it is
608
628
// / different than the declaration's source range.
609
629
SourceRange refinementSourceRangeForDecl (Decl *D) {
630
+ // We require a valid range in order to be able to query for the TRC
631
+ // corresponding to a given SourceLoc.
632
+ // If this assert fires, it means we have probably synthesized an implicit
633
+ // declaration without location information. The appropriate fix is
634
+ // probably to gin up a source range for the declaration when synthesizing
635
+ // it.
636
+ assert (D->getSourceRange ().isValid ());
637
+
610
638
if (auto *storageDecl = dyn_cast<AbstractStorageDecl>(D)) {
611
639
// Use the declaration's availability for the context when checking
612
640
// the bodies of its accessors.
@@ -642,25 +670,26 @@ class TypeRefinementContextBuilder : private ASTWalker {
642
670
return D->getSourceRange ();
643
671
}
644
672
645
- TypeRefinementContext *createAPIBoundaryContext (Decl *D, SourceRange range) {
646
- AvailabilityContext DeploymentTargetInfo =
647
- AvailabilityContext::forDeploymentTarget (Context);
648
- DeploymentTargetInfo.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
649
-
650
- return TypeRefinementContext::createForAPIBoundary (
651
- Context, D, getCurrentTRC (), DeploymentTargetInfo, range);
652
- }
653
-
654
673
void buildContextsForBodyOfDecl (Decl *D) {
655
674
// Are we already constrained by the deployment target? If not, adding
656
675
// new contexts won't change availability.
657
676
if (isCurrentTRCContainedByDeploymentTarget ())
658
677
return ;
659
678
679
+ // A lambda that creates an implicit decl TRC specifying the deployment
680
+ // target for `range` in decl `D`.
681
+ auto createContext = [this ](Decl *D, SourceRange range) {
682
+ AvailabilityContext Availability =
683
+ AvailabilityContext::forDeploymentTarget (Context);
684
+ Availability.intersectWith (getCurrentTRC ()->getAvailabilityInfo ());
685
+
686
+ return TypeRefinementContext::createForDeclImplicit (
687
+ Context, D, getCurrentTRC (), Availability, range);
688
+ };
689
+
660
690
// Top level code always uses the deployment target.
661
691
if (auto tlcd = dyn_cast<TopLevelCodeDecl>(D)) {
662
- auto *topLevelTRC =
663
- createAPIBoundaryContext (tlcd, tlcd->getSourceRange ());
692
+ auto *topLevelTRC = createContext (tlcd, tlcd->getSourceRange ());
664
693
pushContext (topLevelTRC, D);
665
694
return ;
666
695
}
@@ -670,8 +699,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
670
699
if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
671
700
if (!afd->isImplicit () && afd->getBodySourceRange ().isValid () &&
672
701
afd->getResilienceExpansion () != ResilienceExpansion::Minimal) {
673
- auto *functionBodyTRC =
674
- createAPIBoundaryContext (afd, afd->getBodySourceRange ());
702
+ auto *functionBodyTRC = createContext (afd, afd->getBodySourceRange ());
675
703
pushContext (functionBodyTRC, D);
676
704
}
677
705
return ;
@@ -693,8 +721,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
693
721
// Create a TRC for the init written in the source. The ASTWalker
694
722
// won't visit these expressions so instead of pushing these onto the
695
723
// stack we build them directly.
696
- auto *initTRC =
697
- createAPIBoundaryContext (vd, initExpr->getSourceRange ());
724
+ auto *initTRC = createContext (vd, initExpr->getSourceRange ());
698
725
TypeRefinementContextBuilder (initTRC, Context).build (initExpr);
699
726
}
700
727
@@ -710,7 +737,7 @@ class TypeRefinementContextBuilder : private ASTWalker {
710
737
// example, property wrapper initializers that takes block arguments
711
738
// are not handled correctly because of this (rdar://77841331).
712
739
for (auto *wrapper : vd->getAttachedPropertyWrappers ()) {
713
- createAPIBoundaryContext (vd, wrapper->getRange ());
740
+ createContext (vd, wrapper->getRange ());
714
741
}
715
742
}
716
743
0 commit comments