Skip to content

Commit 17a8706

Browse files
authored
Merge pull request #85130 from tshortli/refactor-version-remap
AST: Refactor availability version remapping
2 parents fce3adb + 05f7cb7 commit 17a8706

13 files changed

+165
-289
lines changed

include/swift/AST/AvailabilityDomain.h

Lines changed: 24 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -33,12 +33,21 @@
3333

3434
namespace swift {
3535
class ASTContext;
36+
class AvailabilityDomainAndRange;
3637
class CustomAvailabilityDomain;
3738
class DeclContext;
3839
class FuncDecl;
3940
class ModuleDecl;
4041
class ValueDecl;
4142

43+
/// Discriminates whether a version tuple represents the `introduced:`,
44+
/// `deprecated:`, or `obsoleted:` version of an `@available` attribute.
45+
enum class AvailabilityVersionKind {
46+
Introduced,
47+
Deprecated,
48+
Obsoleted,
49+
};
50+
4251
/// Represents a dimension of availability (e.g. macOS platform or Swift
4352
/// language mode).
4453
class AvailabilityDomain final {
@@ -131,6 +140,9 @@ class AvailabilityDomain final {
131140
: std::nullopt;
132141
}
133142

143+
std::optional<AvailabilityDomain>
144+
getRemappedDomainOrNull(const ASTContext &ctx) const;
145+
134146
public:
135147
AvailabilityDomain() {}
136148

@@ -294,19 +306,22 @@ class AvailabilityDomain final {
294306
/// descendants of the iOS domain.
295307
AvailabilityDomain getRootDomain() const;
296308

297-
/// Returns the canonical domain that versions in this domain must be remapped
298-
/// to before making availability comparisons in the current compilation
299-
/// context. Sets \p didRemap to `true` if a remap was required.
300-
const AvailabilityDomain getRemappedDomain(const ASTContext &ctx,
301-
bool &didRemap) const;
302-
303309
/// Returns the canonical domain that versions in this domain must be remapped
304310
/// to before making availability comparisons in the current compilation
305311
/// context.
306312
const AvailabilityDomain getRemappedDomain(const ASTContext &ctx) const {
307-
bool unused;
308-
return getRemappedDomain(ctx, unused);
309-
}
313+
auto remappedDomain = getRemappedDomainOrNull(ctx);
314+
return remappedDomain ? *remappedDomain : *this;
315+
}
316+
317+
/// Converts the domain and the given version into a canonical domain and
318+
/// range that can be used for availability comparisons in the current current
319+
/// compilation context. If no conversion is necessary or possible, the domain
320+
/// and range are returned unmodified.
321+
AvailabilityDomainAndRange
322+
getRemappedDomainAndRange(const llvm::VersionTuple &version,
323+
AvailabilityVersionKind versionKind,
324+
const ASTContext &ctx) const;
310325

311326
/// Returns true for a domain that is permanently always available, and
312327
/// therefore availability constraints in the domain are effectively the same

include/swift/AST/AvailabilityInference.h

Lines changed: 2 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -25,7 +25,6 @@
2525
namespace swift {
2626
class ASTContext;
2727
class AvailabilityDomain;
28-
class BackDeployedAttr;
2928
class Decl;
3029
class SemanticAvailableAttr;
3130

@@ -49,37 +48,8 @@ class AvailabilityInference {
4948
static std::optional<AvailabilityRange>
5049
annotatedAvailableRange(const Decl *D);
5150

52-
static AvailabilityRange
53-
annotatedAvailableRangeForAttr(const Decl *D, const AbstractSpecializeAttr *attr,
54-
ASTContext &ctx);
55-
56-
/// For the attribute's introduction version, update the platform and version
57-
/// values to the re-mapped platform's, if using a fallback platform.
58-
/// Returns `true` if a remap occured.
59-
static bool updateIntroducedAvailabilityDomainForFallback(
60-
const SemanticAvailableAttr &attr, const ASTContext &ctx,
61-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer);
62-
63-
/// For the attribute's deprecation version, update the platform and version
64-
/// values to the re-mapped platform's, if using a fallback platform.
65-
/// Returns `true` if a remap occured.
66-
static bool updateDeprecatedAvailabilityDomainForFallback(
67-
const SemanticAvailableAttr &attr, const ASTContext &ctx,
68-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer);
69-
70-
/// For the attribute's obsoletion version, update the platform and version
71-
/// values to the re-mapped platform's, if using a fallback platform.
72-
/// Returns `true` if a remap occured.
73-
static bool updateObsoletedAvailabilityDomainForFallback(
74-
const SemanticAvailableAttr &attr, const ASTContext &ctx,
75-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer);
76-
77-
/// For the attribute's before version, update the platform and version
78-
/// values to the re-mapped platform's, if using a fallback platform.
79-
/// Returns `true` if a remap occured.
80-
static bool updateBeforeAvailabilityDomainForFallback(
81-
const BackDeployedAttr *attr, const ASTContext &ctx,
82-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer);
51+
static AvailabilityRange annotatedAvailableRangeForAttr(
52+
const Decl *D, const AbstractSpecializeAttr *attr, ASTContext &ctx);
8353
};
8454

8555
} // end namespace swift

include/swift/AST/Decl.h

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1134,8 +1134,7 @@ class alignas(1 << DeclAlignInBits) Decl : public ASTAllocated<Decl>, public Swi
11341134
/// Returns the active `@backDeployed` attribute and the `AvailabilityRange`
11351135
/// in which the decl is available as ABI.
11361136
std::optional<std::pair<const BackDeployedAttr *, AvailabilityRange>>
1137-
getBackDeployedAttrAndRange(ASTContext &Ctx,
1138-
bool forTargetVariant = false) const;
1137+
getBackDeployedAttrAndRange(bool forTargetVariant = false) const;
11391138

11401139
/// Returns true if the decl has a valid and active `@backDeployed` attribute.
11411140
bool isBackDeployed() const;

lib/AST/Attr.cpp

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,7 +18,6 @@
1818
#include "swift/AST/ASTContext.h"
1919
#include "swift/AST/ASTPrinter.h"
2020
#include "swift/AST/AvailabilityDomain.h"
21-
#include "swift/AST/AvailabilityInference.h"
2221
#include "swift/AST/Decl.h"
2322
#include "swift/AST/Expr.h"
2423
#include "swift/AST/GenericEnvironment.h"

lib/AST/Availability.cpp

Lines changed: 37 additions & 188 deletions
Original file line numberDiff line numberDiff line change
@@ -256,128 +256,6 @@ static bool isBetterThan(const SemanticAvailableAttr &newAttr,
256256
prevAttr->getPlatform());
257257
}
258258

259-
static const clang::DarwinSDKInfo::RelatedTargetVersionMapping *
260-
getFallbackVersionMapping(const ASTContext &Ctx,
261-
clang::DarwinSDKInfo::OSEnvPair Kind) {
262-
auto *SDKInfo = Ctx.getDarwinSDKInfo();
263-
if (SDKInfo)
264-
return SDKInfo->getVersionMapping(Kind);
265-
266-
return Ctx.getAuxiliaryDarwinPlatformRemapInfo(Kind);
267-
}
268-
269-
static std::optional<clang::VersionTuple>
270-
getRemappedIntroducedVersionForFallbackPlatform(
271-
const ASTContext &Ctx, const llvm::VersionTuple &Version) {
272-
const auto *Mapping = getFallbackVersionMapping(
273-
Ctx, clang::DarwinSDKInfo::OSEnvPair(
274-
llvm::Triple::IOS, llvm::Triple::UnknownEnvironment,
275-
llvm::Triple::XROS, llvm::Triple::UnknownEnvironment));
276-
if (!Mapping)
277-
return std::nullopt;
278-
return Mapping->mapIntroducedAvailabilityVersion(Version);
279-
}
280-
281-
static std::optional<clang::VersionTuple>
282-
getRemappedDeprecatedObsoletedVersionForFallbackPlatform(
283-
const ASTContext &Ctx, const llvm::VersionTuple &Version) {
284-
const auto *Mapping = getFallbackVersionMapping(
285-
Ctx, clang::DarwinSDKInfo::OSEnvPair(
286-
llvm::Triple::IOS, llvm::Triple::UnknownEnvironment,
287-
llvm::Triple::XROS, llvm::Triple::UnknownEnvironment));
288-
if (!Mapping)
289-
return std::nullopt;
290-
return Mapping->mapDeprecatedObsoletedAvailabilityVersion(Version);
291-
}
292-
293-
bool AvailabilityInference::updateIntroducedAvailabilityDomainForFallback(
294-
const SemanticAvailableAttr &attr, const ASTContext &ctx,
295-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer) {
296-
std::optional<llvm::VersionTuple> introducedVersion = attr.getIntroduced();
297-
if (!introducedVersion.has_value())
298-
return false;
299-
300-
bool hasRemap = false;
301-
auto remappedDomain = attr.getDomain().getRemappedDomain(ctx, hasRemap);
302-
if (!hasRemap)
303-
return false;
304-
305-
auto potentiallyRemappedIntroducedVersion =
306-
getRemappedIntroducedVersionForFallbackPlatform(ctx, *introducedVersion);
307-
if (potentiallyRemappedIntroducedVersion.has_value()) {
308-
domain = remappedDomain;
309-
platformVer = potentiallyRemappedIntroducedVersion.value();
310-
return true;
311-
}
312-
return false;
313-
}
314-
315-
bool AvailabilityInference::updateDeprecatedAvailabilityDomainForFallback(
316-
const SemanticAvailableAttr &attr, const ASTContext &ctx,
317-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer) {
318-
std::optional<llvm::VersionTuple> deprecatedVersion = attr.getDeprecated();
319-
if (!deprecatedVersion.has_value())
320-
return false;
321-
322-
bool hasRemap = false;
323-
auto remappedDomain = attr.getDomain().getRemappedDomain(ctx, hasRemap);
324-
if (!hasRemap)
325-
return false;
326-
327-
auto potentiallyRemappedDeprecatedVersion =
328-
getRemappedDeprecatedObsoletedVersionForFallbackPlatform(
329-
ctx, *deprecatedVersion);
330-
if (potentiallyRemappedDeprecatedVersion.has_value()) {
331-
domain = remappedDomain;
332-
platformVer = potentiallyRemappedDeprecatedVersion.value();
333-
return true;
334-
}
335-
return false;
336-
}
337-
338-
bool AvailabilityInference::updateObsoletedAvailabilityDomainForFallback(
339-
const SemanticAvailableAttr &attr, const ASTContext &ctx,
340-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer) {
341-
std::optional<llvm::VersionTuple> obsoletedVersion = attr.getObsoleted();
342-
if (!obsoletedVersion.has_value())
343-
return false;
344-
345-
bool hasRemap = false;
346-
auto remappedDomain = attr.getDomain().getRemappedDomain(ctx, hasRemap);
347-
if (!hasRemap)
348-
return false;
349-
350-
auto potentiallyRemappedObsoletedVersion =
351-
getRemappedDeprecatedObsoletedVersionForFallbackPlatform(
352-
ctx, *obsoletedVersion);
353-
if (potentiallyRemappedObsoletedVersion.has_value()) {
354-
domain = remappedDomain;
355-
platformVer = potentiallyRemappedObsoletedVersion.value();
356-
return true;
357-
}
358-
return false;
359-
}
360-
361-
bool AvailabilityInference::updateBeforeAvailabilityDomainForFallback(
362-
const BackDeployedAttr *attr, const ASTContext &ctx,
363-
AvailabilityDomain &domain, llvm::VersionTuple &platformVer) {
364-
bool hasRemap = false;
365-
auto remappedDomain =
366-
attr->getAvailabilityDomain().getRemappedDomain(ctx, hasRemap);
367-
if (!hasRemap)
368-
return false;
369-
370-
auto beforeVersion = attr->getVersion();
371-
auto potentiallyRemappedIntroducedVersion =
372-
getRemappedIntroducedVersionForFallbackPlatform(ctx, beforeVersion);
373-
if (potentiallyRemappedIntroducedVersion.has_value()) {
374-
domain = remappedDomain;
375-
platformVer = potentiallyRemappedIntroducedVersion.value();
376-
return true;
377-
}
378-
return false;
379-
}
380-
381259
static std::optional<SemanticAvailableAttr>
382260
getDeclAvailableAttrForPlatformIntroduction(const Decl *D) {
383261
std::optional<SemanticAvailableAttr> bestAvailAttr;
@@ -917,40 +795,31 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getIntroduced() const {
917795
std::optional<AvailabilityDomainAndRange>
918796
SemanticAvailableAttr::getIntroducedDomainAndRange(
919797
const ASTContext &Ctx) const {
920-
auto *attr = getParsedAttr();
921798
auto domain = getDomain();
922-
923799
if (domain.isUniversal())
924800
return std::nullopt;
925801

926-
if (!attr->getRawIntroduced().has_value()) {
927-
// For versioned domains, an "introduced:" version is always required to
928-
// indicate introduction.
929-
if (domain.isVersioned())
930-
return std::nullopt;
802+
if (auto introduced = getIntroduced())
803+
return domain.getRemappedDomainAndRange(
804+
*introduced, AvailabilityVersionKind::Introduced, Ctx);
931805

932-
// For version-less domains, an attribute that does not indicate some other
933-
// kind of unconditional availability constraint implicitly specifies that
934-
// the decl is available in all versions of the domain.
935-
switch (attr->getKind()) {
936-
case AvailableAttr::Kind::Default:
937-
return AvailabilityDomainAndRange(domain.getRemappedDomain(Ctx),
938-
AvailabilityRange::alwaysAvailable());
939-
case AvailableAttr::Kind::Deprecated:
940-
case AvailableAttr::Kind::Unavailable:
941-
case AvailableAttr::Kind::NoAsync:
942-
return std::nullopt;
943-
}
944-
}
945-
946-
llvm::VersionTuple introducedVersion = getIntroduced().value();
947-
llvm::VersionTuple remappedVersion;
948-
if (AvailabilityInference::updateIntroducedAvailabilityDomainForFallback(
949-
*this, Ctx, domain, remappedVersion))
950-
introducedVersion = remappedVersion;
806+
// For versioned domains, an "introduced:" version is always required to
807+
// indicate introduction.
808+
if (domain.isVersioned())
809+
return std::nullopt;
951810

952-
return AvailabilityDomainAndRange(domain,
953-
AvailabilityRange{introducedVersion});
811+
// For version-less domains, an attribute that does not indicate some other
812+
// kind of unconditional availability constraint implicitly specifies that
813+
// the decl is available in all versions of the domain.
814+
switch (attr->getKind()) {
815+
case AvailableAttr::Kind::Default:
816+
return AvailabilityDomainAndRange(domain.getRemappedDomain(Ctx),
817+
AvailabilityRange::alwaysAvailable());
818+
case AvailableAttr::Kind::Deprecated:
819+
case AvailableAttr::Kind::Unavailable:
820+
case AvailableAttr::Kind::NoAsync:
821+
return std::nullopt;
822+
}
954823
}
955824

956825
std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
@@ -962,28 +831,18 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getDeprecated() const {
962831
std::optional<AvailabilityDomainAndRange>
963832
SemanticAvailableAttr::getDeprecatedDomainAndRange(
964833
const ASTContext &Ctx) const {
965-
auto *attr = getParsedAttr();
966-
AvailabilityDomain domain = getDomain();
967-
968-
if (!attr->getRawDeprecated().has_value()) {
969-
// Regardless of the whether the domain supports versions or not, an
970-
// unconditional deprecation attribute indicates the decl is always
971-
// deprecated.
972-
if (isUnconditionallyDeprecated())
973-
return AvailabilityDomainAndRange(domain.getRemappedDomain(Ctx),
974-
AvailabilityRange::alwaysAvailable());
975-
976-
return std::nullopt;
977-
}
834+
if (auto deprecated = getDeprecated())
835+
return getDomain().getRemappedDomainAndRange(
836+
*deprecated, AvailabilityVersionKind::Deprecated, Ctx);
978837

979-
llvm::VersionTuple deprecatedVersion = getDeprecated().value();
980-
llvm::VersionTuple remappedVersion;
981-
if (AvailabilityInference::updateDeprecatedAvailabilityDomainForFallback(
982-
*this, Ctx, domain, remappedVersion))
983-
deprecatedVersion = remappedVersion;
838+
// Regardless of the whether the domain supports versions or not, an
839+
// unconditional deprecation attribute indicates the decl is always
840+
// deprecated.
841+
if (isUnconditionallyDeprecated())
842+
return AvailabilityDomainAndRange(getDomain().getRemappedDomain(Ctx),
843+
AvailabilityRange::alwaysAvailable());
984844

985-
return AvailabilityDomainAndRange(domain,
986-
AvailabilityRange{deprecatedVersion});
845+
return std::nullopt;
987846
}
988847

989848
std::optional<llvm::VersionTuple> SemanticAvailableAttr::getObsoleted() const {
@@ -994,26 +853,16 @@ std::optional<llvm::VersionTuple> SemanticAvailableAttr::getObsoleted() const {
994853

995854
std::optional<AvailabilityDomainAndRange>
996855
SemanticAvailableAttr::getObsoletedDomainAndRange(const ASTContext &Ctx) const {
997-
auto *attr = getParsedAttr();
998-
AvailabilityDomain domain = getDomain();
999-
1000-
if (!attr->getRawObsoleted().has_value()) {
1001-
// An "unavailable" attribute effectively means obsolete in all versions.
1002-
if (attr->isUnconditionallyUnavailable())
1003-
return AvailabilityDomainAndRange(domain.getRemappedDomain(Ctx),
1004-
AvailabilityRange::alwaysAvailable());
856+
if (auto obsoleted = getObsoleted())
857+
return getDomain().getRemappedDomainAndRange(
858+
*obsoleted, AvailabilityVersionKind::Obsoleted, Ctx);
1005859

1006-
return std::nullopt;
1007-
}
860+
// An "unavailable" attribute effectively means obsolete in all versions.
861+
if (isUnconditionallyUnavailable())
862+
return AvailabilityDomainAndRange(getDomain().getRemappedDomain(Ctx),
863+
AvailabilityRange::alwaysAvailable());
1008864

1009-
llvm::VersionTuple obsoletedVersion = getObsoleted().value();
1010-
llvm::VersionTuple remappedVersion;
1011-
if (AvailabilityInference::updateObsoletedAvailabilityDomainForFallback(
1012-
*this, Ctx, domain, remappedVersion))
1013-
obsoletedVersion = remappedVersion;
1014-
1015-
return AvailabilityDomainAndRange(domain,
1016-
AvailabilityRange{obsoletedVersion});
865+
return std::nullopt;
1017866
}
1018867

1019868
namespace {

0 commit comments

Comments
 (0)