Skip to content

Commit ed725c8

Browse files
authored
Merge pull request #83700 from tshortli/check-obsoletion-with-contextual-availability
2 parents ad95ec7 + 9390283 commit ed725c8

6 files changed

+252
-66
lines changed

lib/AST/AvailabilityConstraint.cpp

Lines changed: 11 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -205,26 +205,23 @@ getAvailabilityConstraintForAttr(const Decl *decl,
205205
auto &ctx = decl->getASTContext();
206206
auto domain = attr.getDomain();
207207
auto deploymentRange = domain.getDeploymentRange(ctx);
208+
bool domainSupportsRefinement = domain.supportsContextRefinement();
209+
std::optional<AvailabilityRange> availableRange =
210+
domainSupportsRefinement ? context.getAvailabilityRange(domain, ctx)
211+
: deploymentRange;
208212

209-
// Is the decl obsoleted in the deployment context?
213+
// Is the decl obsoleted in this context?
210214
if (auto obsoletedRange = attr.getObsoletedRange(ctx)) {
211-
if (deploymentRange && deploymentRange->isContainedIn(*obsoletedRange))
215+
if (availableRange && availableRange->isContainedIn(*obsoletedRange))
212216
return AvailabilityConstraint::unavailableObsolete(attr);
213217
}
214218

215-
// Is the decl not yet introduced in the local context?
219+
// Is the decl not yet introduced in this context?
216220
if (auto introducedRange = attr.getIntroducedRange(ctx)) {
217-
if (domain.supportsContextRefinement()) {
218-
auto availableRange = context.getAvailabilityRange(domain, ctx);
219-
if (!availableRange || !availableRange->isContainedIn(*introducedRange))
220-
return AvailabilityConstraint::unintroduced(attr);
221-
222-
return std::nullopt;
223-
}
224-
225-
// Is the decl not yet introduced in the deployment context?
226-
if (deploymentRange && !deploymentRange->isContainedIn(*introducedRange))
227-
return AvailabilityConstraint::unavailableUnintroduced(attr);
221+
if (!availableRange || !availableRange->isContainedIn(*introducedRange))
222+
return domainSupportsRefinement
223+
? AvailabilityConstraint::unintroduced(attr)
224+
: AvailabilityConstraint::unavailableUnintroduced(attr);
228225
}
229226

230227
return std::nullopt;

lib/AST/AvailabilityContext.cpp

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -355,10 +355,13 @@ void AvailabilityContext::constrainWithDecl(const Decl *decl) {
355355
void AvailabilityContext::constrainWithDeclAndPlatformRange(
356356
const Decl *decl, const AvailabilityRange &otherPlatformRange) {
357357
auto &ctx = decl->getASTContext();
358+
359+
// Constrain the platform range first since this may have an effect on
360+
// whether the decl is considered obsolete.
361+
constrainWithPlatformRange(otherPlatformRange, ctx);
362+
358363
bool isConstrained = false;
359364
auto platformRange = storage->platformRange;
360-
isConstrained |= constrainRange(platformRange, otherPlatformRange);
361-
362365
bool isDeprecated = storage->isDeprecated;
363366
isConstrained |= constrainBool(isDeprecated, decl->isDeprecated());
364367

lib/AST/AvailabilityScopeBuilder.cpp

Lines changed: 15 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,7 @@
1818

1919
#include "swift/AST/ASTContext.h"
2020
#include "swift/AST/ASTWalker.h"
21+
#include "swift/AST/AvailabilityConstraint.h"
2122
#include "swift/AST/AvailabilityInference.h"
2223
#include "swift/AST/AvailabilitySpec.h"
2324
#include "swift/AST/Decl.h"
@@ -461,10 +462,17 @@ class AvailabilityScopeBuilder : private ASTWalker {
461462
// As a convenience, explicitly unavailable decls are constrained to the
462463
// deployment target. There's not much benefit to checking these decls at a
463464
// lower availability version floor since they can't be invoked by clients.
464-
if (getCurrentScope()->getAvailabilityContext().isUnavailable() ||
465-
decl->isUnavailable())
465+
auto context = getCurrentScope()->getAvailabilityContext();
466+
if (context.isUnavailable())
466467
return true;
467468

469+
// Check whether the decl is unavailable relative to the current context.
470+
if (auto constraint = getAvailabilityConstraintsForDecl(decl, context)
471+
.getPrimaryConstraint()) {
472+
if (constraint->isUnavailable())
473+
return true;
474+
}
475+
468476
// To remain compatible with a lot of existing SPIs that are declared
469477
// without availability attributes, constrain them to the deployment target
470478
// too.
@@ -584,8 +592,7 @@ class AvailabilityScopeBuilder : private ASTWalker {
584592
}
585593

586594
void buildContextsForBodyOfDecl(Decl *decl) {
587-
// Are we already constrained by the deployment target and the declaration
588-
// doesn't explicitly allow unsafe constructs in its definition, adding
595+
// If we are already constrained by the deployment target then adding
589596
// new contexts won't change availability.
590597
if (isCurrentScopeContainedByDeploymentTarget())
591598
return;
@@ -599,8 +606,10 @@ class AvailabilityScopeBuilder : private ASTWalker {
599606
// Apply deployment-target availability if appropriate for this body.
600607
if (!isCurrentScopeContainedByDeploymentTarget() &&
601608
bodyIsDeploymentTarget(decl)) {
602-
availability.constrainWithPlatformRange(
603-
AvailabilityRange::forDeploymentTarget(Context), Context);
609+
// Also constrain availability with the decl itself to handle the case
610+
// where the decl becomes obsolete at the deployment target.
611+
availability.constrainWithDeclAndPlatformRange(
612+
decl, AvailabilityRange::forDeploymentTarget(Context));
604613
}
605614

606615
nodesAndScopes.push_back(

0 commit comments

Comments
 (0)