Skip to content

Commit 3b9ca2f

Browse files
committed
AST: Consolidate availability version remapping.
Introduce `SemanticAvailableAttr` conveniences to compute the deprecated and obsoleted ranges for an attribute and ensure they remap versions when needed.
1 parent 143d683 commit 3b9ca2f

File tree

7 files changed

+113
-79
lines changed

7 files changed

+113
-79
lines changed

include/swift/AST/Attr.h

Lines changed: 10 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -3309,8 +3309,8 @@ class SemanticAvailableAttr final {
33093309
/// The source range of the `introduced:` version component.
33103310
SourceRange getIntroducedSourceRange() const { return attr->IntroducedRange; }
33113311

3312-
/// Returns the effective range in which the declaration with this attribute
3313-
/// was introduced.
3312+
/// Returns the effective availability range for the attribute's `introduced:`
3313+
/// component (remapping or canonicalizing if necessary).
33143314
AvailabilityRange getIntroducedRange(const ASTContext &Ctx) const;
33153315

33163316
/// The version tuple for the `deprecated:` component.
@@ -3319,12 +3319,20 @@ class SemanticAvailableAttr final {
33193319
/// The source range of the `deprecated:` version component.
33203320
SourceRange getDeprecatedSourceRange() const { return attr->DeprecatedRange; }
33213321

3322+
/// Returns the effective availability range for the attribute's `deprecated:`
3323+
/// component (remapping or canonicalizing if necessary).
3324+
AvailabilityRange getDeprecatedRange(const ASTContext &Ctx) const;
3325+
33223326
/// The version tuple for the `obsoleted:` component.
33233327
std::optional<llvm::VersionTuple> getObsoleted() const;
33243328

33253329
/// The source range of the `obsoleted:` version component.
33263330
SourceRange getObsoletedSourceRange() const { return attr->ObsoletedRange; }
33273331

3332+
/// Returns the effective availability range for the attribute's `obsoleted:`
3333+
/// component (remapping or canonicalizing if necessary).
3334+
AvailabilityRange getObsoletedRange(const ASTContext &Ctx) const;
3335+
33283336
/// Returns the `message:` field of the attribute, or an empty string.
33293337
StringRef getMessage() const { return attr->Message; }
33303338

@@ -3372,12 +3380,6 @@ class SemanticAvailableAttr final {
33723380
/// Whether this attribute an attribute that is specific to Embedded Swift.
33733381
bool isEmbeddedSpecific() const { return getDomain().isEmbedded(); }
33743382

3375-
/// Returns the active version from the AST context corresponding to
3376-
/// the available kind. For example, this will return the effective language
3377-
/// version for swift version-specific availability kind, PackageDescription
3378-
/// version for PackageDescription version-specific availability.
3379-
llvm::VersionTuple getActiveVersion(const ASTContext &ctx) const;
3380-
33813383
/// Returns true if this attribute is considered active in the current
33823384
/// compilation context.
33833385
bool isActive(ASTContext &ctx) const;

include/swift/AST/AvailabilityDomain.h

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -19,6 +19,7 @@
1919
#define SWIFT_AST_AVAILABILITY_DOMAIN_H
2020

2121
#include "swift/AST/ASTAllocated.h"
22+
#include "swift/AST/AvailabilityRange.h"
2223
#include "swift/AST/Identifier.h"
2324
#include "swift/AST/PlatformKind.h"
2425
#include "swift/Basic/Assertions.h"
@@ -215,6 +216,14 @@ class AvailabilityDomain final {
215216
/// compilation context.
216217
bool isActive(const ASTContext &ctx) const;
217218

219+
/// Returns the minimum available range for the attribute's domain. For
220+
/// example, for the domain of the platform that compilation is targeting,
221+
/// this will be the deployment target. For the Swift language domain, this
222+
/// will be the language mode for compilation. For domains which have don't
223+
/// have a "deployment target", this returns `std::nullopt`.
224+
std::optional<AvailabilityRange>
225+
getDeploymentRange(const ASTContext &ctx) const;
226+
218227
/// Returns the string to use in diagnostics to identify the domain. May
219228
/// return an empty string.
220229
llvm::StringRef getNameForDiagnostics() const;

lib/AST/Attr.cpp

Lines changed: 0 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -2289,17 +2289,6 @@ bool AvailableAttr::isNoAsync() const {
22892289
llvm_unreachable("Unhandled AvailableAttr::Kind in switch.");
22902290
}
22912291

2292-
llvm::VersionTuple
2293-
SemanticAvailableAttr::getActiveVersion(const ASTContext &ctx) const {
2294-
if (isSwiftLanguageModeSpecific()) {
2295-
return ctx.LangOpts.EffectiveLanguageVersion;
2296-
} else if (isPackageDescriptionVersionSpecific()) {
2297-
return ctx.LangOpts.PackageDescriptionVersion;
2298-
} else {
2299-
return ctx.LangOpts.getMinPlatformVersion();
2300-
}
2301-
}
2302-
23032292
SpecializeAttr::SpecializeAttr(SourceLoc atLoc, SourceRange range,
23042293
TrailingWhereClause *clause, bool exported,
23052294
SpecializationKind kind,

lib/AST/Availability.cpp

Lines changed: 53 additions & 26 deletions
Original file line numberDiff line numberDiff line change
@@ -454,24 +454,15 @@ std::optional<SemanticAvailableAttr> Decl::getDeprecatedAttr() const {
454454
if (attr.isUnconditionallyDeprecated())
455455
return attr;
456456

457-
auto deprecatedVersion = attr.getDeprecated();
458-
459-
AvailabilityDomain unusedDomain;
460-
llvm::VersionTuple remappedDeprecatedVersion;
461-
if (AvailabilityInference::updateDeprecatedAvailabilityDomainForFallback(
462-
attr, ctx, unusedDomain, remappedDeprecatedVersion))
463-
deprecatedVersion = remappedDeprecatedVersion;
464-
465-
if (!deprecatedVersion.has_value())
457+
auto deprecatedRange = attr.getDeprecatedRange(ctx);
458+
if (deprecatedRange.isKnownUnreachable())
466459
continue;
467460

468-
llvm::VersionTuple minVersion = attr.getActiveVersion(ctx);
469-
470461
// We treat the declaration as deprecated if it is deprecated on
471462
// all deployment targets.
472-
if (deprecatedVersion.value() <= minVersion) {
463+
auto deploymentRange = attr.getDomain().getDeploymentRange(ctx);
464+
if (deploymentRange && deploymentRange->isContainedIn(deprecatedRange))
473465
result.emplace(attr);
474-
}
475466
}
476467
return result;
477468
}
@@ -485,14 +476,14 @@ std::optional<SemanticAvailableAttr> Decl::getSoftDeprecatedAttr() const {
485476
if (attr.isPlatformSpecific() && (!bestActive || attr != bestActive))
486477
continue;
487478

488-
// FIXME: This needs to do a version remap.
489-
auto deprecatedVersion = attr.getDeprecated();
490-
if (!deprecatedVersion.has_value())
479+
auto deprecatedRange = attr.getDeprecatedRange(ctx);
480+
if (deprecatedRange.isKnownUnreachable())
491481
continue;
492482

493-
llvm::VersionTuple activeVersion = attr.getActiveVersion(ctx);
494-
495-
if (deprecatedVersion.value() > activeVersion)
483+
// We treat the declaration as soft-deprecated if it is deprecated in a
484+
// future version.
485+
auto deploymentRange = attr.getDomain().getDeploymentRange(ctx);
486+
if (!deploymentRange || !deploymentRange->isContainedIn(deprecatedRange))
496487
result.emplace(attr);
497488
}
498489
return result;
@@ -849,20 +840,20 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getIntroduced() const {
849840

850841
AvailabilityRange
851842
SemanticAvailableAttr::getIntroducedRange(const ASTContext &Ctx) const {
852-
assert(getDomain().isActive(Ctx));
843+
DEBUG_ASSERT(getDomain().isActive(Ctx));
853844

854845
auto *attr = getParsedAttr();
855846
if (!attr->getRawIntroduced().has_value())
856847
return AvailabilityRange::alwaysAvailable();
857848

858-
llvm::VersionTuple IntroducedVersion = getIntroduced().value();
859-
AvailabilityDomain UnusedDomain;
860-
llvm::VersionTuple RemappedIntroducedVersion;
849+
llvm::VersionTuple introducedVersion = getIntroduced().value();
850+
AvailabilityDomain unusedDomain;
851+
llvm::VersionTuple remappedVersion;
861852
if (AvailabilityInference::updateIntroducedAvailabilityDomainForFallback(
862-
*this, Ctx, UnusedDomain, RemappedIntroducedVersion))
863-
IntroducedVersion = RemappedIntroducedVersion;
853+
*this, Ctx, unusedDomain, remappedVersion))
854+
introducedVersion = remappedVersion;
864855

865-
return AvailabilityRange{VersionRange::allGTE(IntroducedVersion)};
856+
return AvailabilityRange{VersionRange::allGTE(introducedVersion)};
866857
}
867858

868859
std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
@@ -871,12 +862,48 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
871862
return std::nullopt;
872863
}
873864

865+
AvailabilityRange
866+
SemanticAvailableAttr::getDeprecatedRange(const ASTContext &Ctx) const {
867+
DEBUG_ASSERT(getDomain().isActive(Ctx));
868+
869+
auto *attr = getParsedAttr();
870+
if (!attr->getRawDeprecated().has_value())
871+
return AvailabilityRange::neverAvailable();
872+
873+
llvm::VersionTuple deprecatedVersion = getDeprecated().value();
874+
AvailabilityDomain unusedDomain;
875+
llvm::VersionTuple remappedVersion;
876+
if (AvailabilityInference::updateDeprecatedAvailabilityDomainForFallback(
877+
*this, Ctx, unusedDomain, remappedVersion))
878+
deprecatedVersion = remappedVersion;
879+
880+
return AvailabilityRange{VersionRange::allGTE(deprecatedVersion)};
881+
}
882+
874883
std::optional<llvm::VersionTuple> SemanticAvailableAttr::getObsoleted() const {
875884
if (auto version = attr->getRawObsoleted())
876885
return canonicalizePlatformVersion(getPlatform(), *version);
877886
return std::nullopt;
878887
}
879888

889+
AvailabilityRange
890+
SemanticAvailableAttr::getObsoletedRange(const ASTContext &Ctx) const {
891+
DEBUG_ASSERT(getDomain().isActive(Ctx));
892+
893+
auto *attr = getParsedAttr();
894+
if (!attr->getRawObsoleted().has_value())
895+
return AvailabilityRange::neverAvailable();
896+
897+
llvm::VersionTuple obsoletedVersion = getObsoleted().value();
898+
AvailabilityDomain unusedDomain;
899+
llvm::VersionTuple remappedVersion;
900+
if (AvailabilityInference::updateObsoletedAvailabilityDomainForFallback(
901+
*this, Ctx, unusedDomain, remappedVersion))
902+
obsoletedVersion = remappedVersion;
903+
904+
return AvailabilityRange{VersionRange::allGTE(obsoletedVersion)};
905+
}
906+
880907
namespace {
881908
/// Infers the availability required to access a type.
882909
class AvailabilityInferenceTypeWalker : public TypeWalker {

lib/AST/AvailabilityConstraint.cpp

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -148,20 +148,10 @@ getAvailabilityConstraintForAttr(const Decl *decl,
148148
return AvailabilityConstraint::unconditionallyUnavailable(attr);
149149

150150
auto &ctx = decl->getASTContext();
151-
auto deploymentVersion = attr.getActiveVersion(ctx);
152-
auto deploymentRange =
153-
AvailabilityRange(VersionRange::allGTE(deploymentVersion));
154-
std::optional<llvm::VersionTuple> obsoletedVersion = attr.getObsoleted();
155-
156-
{
157-
AvailabilityDomain unusedDomain;
158-
llvm::VersionTuple remappedObsoletedVersion;
159-
if (AvailabilityInference::updateObsoletedAvailabilityDomainForFallback(
160-
attr, ctx, unusedDomain, remappedObsoletedVersion))
161-
obsoletedVersion = remappedObsoletedVersion;
162-
}
151+
auto deploymentRange = attr.getDomain().getDeploymentRange(ctx);
163152

164-
if (obsoletedVersion && *obsoletedVersion <= deploymentVersion)
153+
auto obsoletedRange = attr.getObsoletedRange(ctx);
154+
if (deploymentRange && deploymentRange->isContainedIn(obsoletedRange))
165155
return AvailabilityConstraint::obsoleted(attr);
166156

167157
AvailabilityRange introducedRange = attr.getIntroducedRange(ctx);
@@ -170,7 +160,8 @@ getAvailabilityConstraintForAttr(const Decl *decl,
170160
if (attr.isPlatformSpecific()) {
171161
if (!context.getPlatformRange().isContainedIn(introducedRange))
172162
return AvailabilityConstraint::introducedInLaterDynamicVersion(attr);
173-
} else if (!deploymentRange.isContainedIn(introducedRange)) {
163+
} else if (deploymentRange &&
164+
!deploymentRange->isContainedIn(introducedRange)) {
174165
return AvailabilityConstraint::introducedInLaterVersion(attr);
175166
}
176167

lib/AST/AvailabilityDomain.cpp

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -105,6 +105,31 @@ bool AvailabilityDomain::isActive(const ASTContext &ctx) const {
105105
}
106106
}
107107

108+
static std::optional<llvm::VersionTuple>
109+
getDeploymentVersion(const AvailabilityDomain &domain, const ASTContext &ctx) {
110+
switch (domain.getKind()) {
111+
case AvailabilityDomain::Kind::Universal:
112+
case AvailabilityDomain::Kind::Embedded:
113+
case AvailabilityDomain::Kind::Custom:
114+
return std::nullopt;
115+
case AvailabilityDomain::Kind::SwiftLanguage:
116+
return ctx.LangOpts.EffectiveLanguageVersion;
117+
case AvailabilityDomain::Kind::PackageDescription:
118+
return ctx.LangOpts.PackageDescriptionVersion;
119+
case AvailabilityDomain::Kind::Platform:
120+
if (domain.isActive(ctx))
121+
return ctx.LangOpts.getMinPlatformVersion();
122+
return std::nullopt;
123+
}
124+
}
125+
126+
std::optional<AvailabilityRange>
127+
AvailabilityDomain::getDeploymentRange(const ASTContext &ctx) const {
128+
if (auto version = getDeploymentVersion(*this, ctx))
129+
return AvailabilityRange{VersionRange::allGTE(*version)};
130+
return std::nullopt;
131+
}
132+
108133
llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const {
109134
switch (getKind()) {
110135
case Kind::Universal:

lib/Sema/TypeCheckAvailability.cpp

Lines changed: 11 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -2821,28 +2821,23 @@ static void diagnoseIfDeprecated(SourceRange ReferenceRange,
28212821
return;
28222822

28232823
auto Domain = Attr->getDomain();
2824+
auto DeprecatedRange = Attr->getDeprecatedRange(Context);
28242825
llvm::VersionTuple DeprecatedVersion;
2825-
if (Attr->getDeprecated())
2826-
DeprecatedVersion = Attr->getDeprecated().value();
2826+
if (DeprecatedRange.hasMinimumVersion())
2827+
DeprecatedVersion = DeprecatedRange.getRawMinimumVersion();
28272828

28282829
auto Message = Attr->getMessage();
28292830
auto NewName = Attr->getRename();
28302831
if (Message.empty() && NewName.empty()) {
28312832
Context.Diags
28322833
.diagnose(ReferenceRange.Start, diag::availability_deprecated,
28332834
DeprecatedDecl, Attr->isPlatformSpecific(), Domain,
2834-
Attr->getDeprecated().has_value(), DeprecatedVersion,
2835+
!DeprecatedVersion.empty(), DeprecatedVersion,
28352836
/*message*/ StringRef())
28362837
.highlight(Attr->getParsedAttr()->getRange());
28372838
return;
28382839
}
28392840

2840-
// FIXME: [availability] Remap before emitting diagnostic above.
2841-
llvm::VersionTuple RemappedDeprecatedVersion;
2842-
if (AvailabilityInference::updateDeprecatedAvailabilityDomainForFallback(
2843-
*Attr, Context, Domain, RemappedDeprecatedVersion))
2844-
DeprecatedVersion = RemappedDeprecatedVersion;
2845-
28462841
SmallString<32> newNameBuf;
28472842
std::optional<ReplacementDeclKind> replacementDeclKind =
28482843
describeRename(Context, NewName, /*decl*/ nullptr, newNameBuf);
@@ -2853,7 +2848,7 @@ static void diagnoseIfDeprecated(SourceRange ReferenceRange,
28532848
Context.Diags
28542849
.diagnose(ReferenceRange.Start, diag::availability_deprecated,
28552850
DeprecatedDecl, Attr->isPlatformSpecific(), Domain,
2856-
Attr->getDeprecated().has_value(), DeprecatedVersion,
2851+
!DeprecatedVersion.empty(), DeprecatedVersion,
28572852
EncodedMessage.Message)
28582853
.highlight(Attr->getParsedAttr()->getRange());
28592854
} else {
@@ -2862,7 +2857,7 @@ static void diagnoseIfDeprecated(SourceRange ReferenceRange,
28622857
Context.Diags
28632858
.diagnose(ReferenceRange.Start, diag::availability_deprecated_rename,
28642859
DeprecatedDecl, Attr->isPlatformSpecific(), Domain,
2865-
Attr->getDeprecated().has_value(), DeprecatedVersion,
2860+
!DeprecatedVersion.empty(), DeprecatedVersion,
28662861
replacementDeclKind.has_value(), rawReplaceKind, newName)
28672862
.highlight(Attr->getParsedAttr()->getRange());
28682863
}
@@ -2909,21 +2904,17 @@ static bool diagnoseIfDeprecated(SourceLoc loc,
29092904
auto proto = rootConf->getProtocol()->getDeclaredInterfaceType();
29102905

29112906
auto domain = attr->getDomain();
2907+
auto deprecatedRange = attr->getDeprecatedRange(ctx);
29122908
llvm::VersionTuple deprecatedVersion;
2913-
if (attr->getDeprecated())
2914-
deprecatedVersion = attr->getDeprecated().value();
2915-
2916-
llvm::VersionTuple remappedDeprecatedVersion;
2917-
if (AvailabilityInference::updateDeprecatedAvailabilityDomainForFallback(
2918-
*attr, ctx, domain, remappedDeprecatedVersion))
2919-
deprecatedVersion = remappedDeprecatedVersion;
2909+
if (deprecatedRange.hasMinimumVersion())
2910+
deprecatedVersion = deprecatedRange.getRawMinimumVersion();
29202911

29212912
auto message = attr->getMessage();
29222913
if (message.empty()) {
29232914
ctx.Diags
29242915
.diagnose(loc, diag::conformance_availability_deprecated, type, proto,
29252916
attr->isPlatformSpecific(), domain,
2926-
attr->getDeprecated().has_value(), deprecatedVersion,
2917+
!deprecatedVersion.empty(), deprecatedVersion,
29272918
/*message*/ StringRef())
29282919
.highlight(attr->getParsedAttr()->getRange());
29292920
return true;
@@ -2933,7 +2924,7 @@ static bool diagnoseIfDeprecated(SourceLoc loc,
29332924
ctx.Diags
29342925
.diagnose(loc, diag::conformance_availability_deprecated, type, proto,
29352926
attr->isPlatformSpecific(), domain,
2936-
attr->getDeprecated().has_value(), deprecatedVersion,
2927+
!deprecatedVersion.empty(), deprecatedVersion,
29372928
encodedMessage.Message)
29382929
.highlight(attr->getParsedAttr()->getRange());
29392930
return true;

0 commit comments

Comments
 (0)