@@ -869,100 +869,140 @@ class AvailabilityScopeBuilder : private ASTWalker {
869
869
return Range;
870
870
}
871
871
872
- // Creates an implicit decl scope specifying the deployment target for
873
- // `range` in decl `D`.
874
- AvailabilityScope *
875
- createImplicitDeclContextForDeploymentTarget (Decl *D, SourceRange range) {
876
- const AvailabilityContext Availability =
877
- constrainCurrentAvailabilityWithPlatformRange (
878
- AvailabilityRange::forDeploymentTarget (Context));
879
- return AvailabilityScope::createForDeclImplicit (
880
- Context, D, getCurrentScope (), Availability, range);
881
- }
882
-
883
- void buildContextsForBodyOfDecl (Decl *D) {
884
- // Are we already constrained by the deployment target? If not, adding
885
- // new contexts won't change availability.
886
- if (isCurrentScopeContainedByDeploymentTarget ())
887
- return ;
888
-
872
+ // / Enumerate the AST nodes and their corresponding source ranges for
873
+ // / the body (or bodies) of the given declaration.
874
+ void enumerateBodyRanges (
875
+ Decl *decl,
876
+ llvm::function_ref<void (Decl *decl, ASTNode body, SourceRange)> acceptBody
877
+ ) {
889
878
// Top level code always uses the deployment target.
890
- if (auto tlcd = dyn_cast<TopLevelCodeDecl>(D )) {
879
+ if (auto tlcd = dyn_cast<TopLevelCodeDecl>(decl )) {
891
880
if (auto bodyStmt = tlcd->getBody ()) {
892
- pushDeclBodyContext (
893
- tlcd, {{bodyStmt, createImplicitDeclContextForDeploymentTarget (
894
- tlcd, refinementSourceRangeForDecl (tlcd))}});
881
+ acceptBody (tlcd, bodyStmt, refinementSourceRangeForDecl (tlcd));
895
882
}
896
883
return ;
897
884
}
898
885
899
- // Function bodies use the deployment target if they are within the module's
900
- // resilience domain.
901
- if (auto afd = dyn_cast<AbstractFunctionDecl>(D)) {
902
- if (!afd->isImplicit () &&
903
- afd->getResilienceExpansion () != ResilienceExpansion::Minimal) {
886
+ // For functions, provide the body source range.
887
+ if (auto afd = dyn_cast<AbstractFunctionDecl>(decl)) {
888
+ if (!afd->isImplicit ()) {
904
889
if (auto body = afd->getBody (/* canSynthesize*/ false )) {
905
- pushDeclBodyContext (
906
- afd, {{body, createImplicitDeclContextForDeploymentTarget (
907
- afd, afd->getBodySourceRange ())}});
890
+ acceptBody (afd, body, afd->getBodySourceRange ());
908
891
}
909
892
}
910
893
return ;
911
894
}
912
895
913
- // Pattern binding declarations can have children corresponding to property
914
- // wrappers and the initial values provided in each pattern binding entry
915
- if (auto *pbd = dyn_cast<PatternBindingDecl>(D)) {
916
- llvm::SmallVector<std::pair<ASTNode, AvailabilityScope *>, 4 >
917
- nodesAndScopes;
918
-
896
+ // Pattern binding declarations have initial values that are their
897
+ // bodies.
898
+ if (auto *pbd = dyn_cast<PatternBindingDecl>(decl)) {
919
899
for (unsigned index : range (pbd->getNumPatternEntries ())) {
920
900
auto var = pbd->getAnchoringVarDecl (index);
921
901
if (!var)
922
902
continue ;
923
903
924
- // Var decls may have associated pattern binding decls or property
925
- // wrappers with init expressions. Those expressions need to be
926
- // constrained to the deployment target unless they are exposed to
927
- // clients.
928
- if (!var->hasInitialValue () || var->isInitExposedToClients ())
929
- continue ;
930
-
931
904
auto *initExpr = pbd->getInit (index);
932
905
if (initExpr && !initExpr->isImplicit ()) {
933
906
assert (initExpr->getSourceRange ().isValid ());
934
907
935
908
// Create a scope for the init written in the source.
936
- nodesAndScopes.push_back (
937
- {initExpr, createImplicitDeclContextForDeploymentTarget (
938
- var, initExpr->getSourceRange ())});
909
+ acceptBody (var, initExpr, initExpr->getSourceRange ());
939
910
}
940
911
}
912
+ return ;
913
+ }
914
+ }
915
+
916
+ // Creates an implicit decl scope specifying the deployment target for
917
+ // `range` in decl `D`.
918
+ AvailabilityScope *
919
+ createImplicitDeclContextForDeploymentTarget (Decl *D, SourceRange range) {
920
+ const AvailabilityContext Availability =
921
+ constrainCurrentAvailabilityWithPlatformRange (
922
+ AvailabilityRange::forDeploymentTarget (Context));
923
+ return AvailabilityScope::createForDeclImplicit (
924
+ Context, D, getCurrentScope (), Availability, range);
925
+ }
926
+
927
+ // / Determine whether the body of the given declaration has
928
+ // / deployment-target availability.
929
+ static bool bodyIsDeploymentTarget (Decl *decl) {
930
+ if (auto afd = dyn_cast<AbstractFunctionDecl>(decl)) {
931
+ return afd->getResilienceExpansion () != ResilienceExpansion::Minimal;
932
+ }
933
+
934
+ if (auto var = dyn_cast<VarDecl>(decl)) {
935
+ // Var decls may have associated pattern binding decls or property
936
+ // wrappers with init expressions. Those expressions need to be
937
+ // constrained to the deployment target unless they are exposed to
938
+ // clients.
939
+ return var->hasInitialValue () && !var->isInitExposedToClients ();
940
+ }
941
+
942
+ return true ;
943
+ }
944
+
945
+ void buildContextsForBodyOfDecl (Decl *D) {
946
+ // Are we already constrained by the deployment target and the declaration
947
+ // doesn't explicitly allow unsafe constructs in its definition, adding
948
+ // new contexts won't change availability.
949
+ bool allowsUnsafe = D->getAttrs ().hasAttribute <SafeAttr>();
950
+ if (isCurrentScopeContainedByDeploymentTarget () && !allowsUnsafe)
951
+ return ;
952
+
953
+ // Enumerate all of the body scopes to apply availability.
954
+ llvm::SmallVector<std::pair<ASTNode, AvailabilityScope *>, 4 >
955
+ nodesAndScopes;
956
+ enumerateBodyRanges (D, [&](Decl *decl, ASTNode body, SourceRange range) {
957
+ auto availability = getCurrentScope ()->getAvailabilityContext ();
958
+
959
+ // Apply deployment-target availability if appropriate for this body.
960
+ if (!isCurrentScopeContainedByDeploymentTarget () &&
961
+ bodyIsDeploymentTarget (decl)) {
962
+ availability.constrainWithPlatformRange (
963
+ AvailabilityRange::forDeploymentTarget (Context), Context);
964
+ }
965
+
966
+ // Allow unsafe if appropriate for this body.
967
+ if (allowsUnsafe) {
968
+ availability.constrainWithAllowsUnsafe (Context);
969
+ }
941
970
942
- if (nodesAndScopes.size () > 0 )
943
- pushDeclBodyContext (pbd, nodesAndScopes);
944
-
945
- // Ideally any init expression would be returned by `getInit()` above.
946
- // However, for property wrappers it doesn't get populated until
947
- // typechecking completes (which is too late). Instead, we find the
948
- // the property wrapper attribute and use its source range to create a
949
- // scope for the initializer expression.
950
- //
951
- // FIXME: Since we don't have an expression here, we can't build out its
952
- // scope. If the Expr that will eventually be created contains a closure
953
- // expression, then it might have AST nodes that need to be refined. For
954
- // example, property wrapper initializers that takes block arguments
955
- // are not handled correctly because of this (rdar://77841331).
956
- if (auto firstVar = pbd->getAnchoringVarDecl (0 )) {
957
- if (firstVar->hasInitialValue () &&
958
- !firstVar->isInitExposedToClients ()) {
959
- for (auto *wrapper : firstVar->getAttachedPropertyWrappers ()) {
960
- createImplicitDeclContextForDeploymentTarget (firstVar,
961
- wrapper->getRange ());
971
+ nodesAndScopes.push_back ({
972
+ body,
973
+ AvailabilityScope::createForDeclImplicit (
974
+ Context, decl, getCurrentScope (), availability, range)
975
+ });
976
+ });
977
+
978
+ if (nodesAndScopes.size () > 0 )
979
+ pushDeclBodyContext (D, nodesAndScopes);
980
+
981
+ if (!isCurrentScopeContainedByDeploymentTarget ()) {
982
+ // Pattern binding declarations can have children corresponding to property
983
+ // wrappers, which we handle separately.
984
+ if (auto *pbd = dyn_cast<PatternBindingDecl>(D)) {
985
+ // Ideally any init expression would be returned by `getInit()` above.
986
+ // However, for property wrappers it doesn't get populated until
987
+ // typechecking completes (which is too late). Instead, we find the
988
+ // the property wrapper attribute and use its source range to create a
989
+ // scope for the initializer expression.
990
+ //
991
+ // FIXME: Since we don't have an expression here, we can't build out its
992
+ // scope. If the Expr that will eventually be created contains a closure
993
+ // expression, then it might have AST nodes that need to be refined. For
994
+ // example, property wrapper initializers that takes block arguments
995
+ // are not handled correctly because of this (rdar://77841331).
996
+ if (auto firstVar = pbd->getAnchoringVarDecl (0 )) {
997
+ if (firstVar->hasInitialValue () &&
998
+ !firstVar->isInitExposedToClients ()) {
999
+ for (auto *wrapper : firstVar->getAttachedPropertyWrappers ()) {
1000
+ createImplicitDeclContextForDeploymentTarget (firstVar,
1001
+ wrapper->getRange ());
1002
+ }
962
1003
}
963
1004
}
964
1005
}
965
- return ;
966
1006
}
967
1007
}
968
1008
0 commit comments