@@ -869,100 +869,140 @@ class AvailabilityScopeBuilder : private ASTWalker {
869869 return Range;
870870 }
871871
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+ ) {
889878 // Top level code always uses the deployment target.
890- if (auto tlcd = dyn_cast<TopLevelCodeDecl>(D )) {
879+ if (auto tlcd = dyn_cast<TopLevelCodeDecl>(decl )) {
891880 if (auto bodyStmt = tlcd->getBody ()) {
892- pushDeclBodyContext (
893- tlcd, {{bodyStmt, createImplicitDeclContextForDeploymentTarget (
894- tlcd, refinementSourceRangeForDecl (tlcd))}});
881+ acceptBody (tlcd, bodyStmt, refinementSourceRangeForDecl (tlcd));
895882 }
896883 return ;
897884 }
898885
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 ()) {
904889 if (auto body = afd->getBody (/* canSynthesize*/ false )) {
905- pushDeclBodyContext (
906- afd, {{body, createImplicitDeclContextForDeploymentTarget (
907- afd, afd->getBodySourceRange ())}});
890+ acceptBody (afd, body, afd->getBodySourceRange ());
908891 }
909892 }
910893 return ;
911894 }
912895
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)) {
919899 for (unsigned index : range (pbd->getNumPatternEntries ())) {
920900 auto var = pbd->getAnchoringVarDecl (index);
921901 if (!var)
922902 continue ;
923903
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-
931904 auto *initExpr = pbd->getInit (index);
932905 if (initExpr && !initExpr->isImplicit ()) {
933906 assert (initExpr->getSourceRange ().isValid ());
934907
935908 // 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 ());
939910 }
940911 }
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+ }
941970
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+ }
9621003 }
9631004 }
9641005 }
965- return ;
9661006 }
9671007 }
9681008
0 commit comments