Files
swift-mirror/lib/AST/AvailabilityDomain.cpp
Allan Shortlidge 98869a9d12 AST: Remove * as the bottom AvailabilityDomain.
Modeling the universal AvailabilityDomain as the bottom element of a lattice
containing all domains was useful for checking unavailability, but it makes
some other algorithms harder to write elegantly using availability domain
algebra. Instead, special case `*` in unavailability computations and only form
an availability domain lattice with the ABI stable platform domains,
`anyAppleOS`, and `Swift`.
2026-03-15 11:19:44 -07:00

747 lines
24 KiB
C++

//===--- AvailabilityDomain.cpp - Swift Availability Domains --------------===//
//
// This source file is part of the Swift.org open source project
//
// Copyright (c) 2014 - 2017 Apple Inc. and the Swift project authors
// Licensed under Apache License v2.0 with Runtime Library Exception
//
// See https://swift.org/LICENSE.txt for license information
// See https://swift.org/CONTRIBUTORS.txt for the list of Swift project authors
//
//===----------------------------------------------------------------------===//
#include "swift/AST/AvailabilityDomain.h"
#include "swift/AST/ASTContext.h"
#include "swift/AST/Decl.h"
#include "swift/AST/DiagnosticsSema.h"
#include "swift/AST/Module.h"
#include "swift/AST/TypeCheckRequests.h"
#include "swift/Basic/Assertions.h"
#include "swift/ClangImporter/ClangImporter.h"
#include "clang/AST/ASTContext.h"
#include "clang/AST/Decl.h"
#include "llvm/ADT/StringSwitch.h"
using namespace swift;
CustomAvailabilityDomain::Kind
getCustomDomainKind(clang::FeatureAvailKind featureAvailKind) {
switch (featureAvailKind) {
case clang::FeatureAvailKind::Available:
return CustomAvailabilityDomain::Kind::Enabled;
case clang::FeatureAvailKind::Unavailable:
return CustomAvailabilityDomain::Kind::Disabled;
case clang::FeatureAvailKind::Dynamic:
return CustomAvailabilityDomain::Kind::Dynamic;
case clang::FeatureAvailKind::AlwaysAvailable:
return CustomAvailabilityDomain::Kind::AlwaysEnabled;
default:
llvm::report_fatal_error("unexpected kind");
}
}
static const CustomAvailabilityDomain *
customDomainForClangDecl(ValueDecl *decl) {
auto *clangDecl = decl->getClangDecl();
auto *varDecl = dyn_cast_or_null<clang::VarDecl>(clangDecl);
if (!varDecl)
return nullptr;
auto featureInfo = clangDecl->getASTContext().getFeatureAvailInfo(
const_cast<clang::VarDecl *>(varDecl));
// Ensure the decl actually represents an availability domain.
if (featureInfo.first.empty())
return nullptr;
// Check that the domain has a supported availability kind.
switch (featureInfo.second.Kind) {
case clang::FeatureAvailKind::Available:
case clang::FeatureAvailKind::Unavailable:
case clang::FeatureAvailKind::Dynamic:
case clang::FeatureAvailKind::AlwaysAvailable:
break;
default:
return nullptr;
}
auto &ctx = decl->getASTContext();
FuncDecl *predicate = nullptr;
if (featureInfo.second.Kind == clang::FeatureAvailKind::Dynamic)
predicate =
ctx.getClangModuleLoader()->getAvailabilityDomainPredicate(varDecl);
return CustomAvailabilityDomain::get(
featureInfo.first, getCustomDomainKind(featureInfo.second.Kind),
decl->getModuleContext(), decl, predicate, ctx);
}
std::optional<AvailabilityDomain>
AvailabilityDomainForDeclRequest::evaluate(Evaluator &evaluator,
ValueDecl *decl) const {
if (!decl)
return std::nullopt;
if (decl->hasClangNode()) {
if (auto *customDomain = customDomainForClangDecl(decl))
return AvailabilityDomain::forCustom(customDomain);
} else {
// FIXME: [availability] Handle Swift availability domains decls.
}
return std::nullopt;
}
std::optional<AvailabilityDomain>
AvailabilityDomain::forCustom(ValueDecl *decl) {
if (!decl)
return std::nullopt;
return evaluateOrDefault(decl->getASTContext().evaluator,
AvailabilityDomainForDeclRequest{decl}, {});
}
static AvailabilityDomain getSwiftRuntimeDomain(ASTContext &ctx) {
// If -enable-experimental-feature StandaloneSwiftAvailability is specified
// then forcibly separate platform and Swift runtime availability.
if (ctx.LangOpts.hasFeature(Feature::StandaloneSwiftAvailability))
return AvailabilityDomain::forStandaloneSwiftRuntime();
// FIXME: [runtime availability] Return the platform Swift runtime domain.
return AvailabilityDomain::forStandaloneSwiftRuntime();
}
std::optional<AvailabilityDomain>
AvailabilityDomain::builtinDomainForString(StringRef string,
const DeclContext *declContext) {
auto &ctx = declContext->getASTContext();
auto domain =
llvm::StringSwitch<std::optional<AvailabilityDomain>>(string)
.Case("*", AvailabilityDomain::forUniversal())
.Case("swift", AvailabilityDomain::forSwiftLanguageMode())
.Case("SwiftLanguageMode", AvailabilityDomain::forSwiftLanguageMode())
.Case("Swift", getSwiftRuntimeDomain(ctx))
.Case("_PackageDescription",
AvailabilityDomain::forPackageDescription())
.Default(std::nullopt);
if (domain)
return domain;
if (auto platformKind = platformFromString(string))
return AvailabilityDomain::forPlatform(*platformKind);
return std::nullopt;
}
bool AvailabilityDomain::isVersioned() const {
switch (getKind()) {
case Kind::Universal:
case Kind::Embedded:
return false;
case Kind::SwiftLanguageMode:
case Kind::StandaloneSwiftRuntime:
case Kind::PackageDescription:
case Kind::Platform:
return true;
case Kind::Custom:
// FIXME: [availability] Support versioned custom availability domains
return false;
}
}
bool AvailabilityDomain::isVersionValid(
const llvm::VersionTuple &version) const {
ASSERT(isVersioned());
switch (getKind()) {
case Kind::Universal:
case Kind::Embedded:
llvm_unreachable("unexpected domain kind");
case Kind::SwiftLanguageMode:
case Kind::PackageDescription:
return true;
case Kind::StandaloneSwiftRuntime:
// Swift 5.0 is the first ABI stable Swift runtime version.
if (version.getMajor() < 5)
return false;
return true;
case Kind::Platform:
// If the platform kind corresponds to a specific OS, LLVM is the source of
// truth for version validity.
if (auto osType = tripleOSTypeForPlatform(getPlatformKind()))
return llvm::Triple::isValidVersionForOS(*osType, version);
// Unified versioning for Apple's operating systems starts at 26.0.
if (getPlatformKind() == PlatformKind::anyAppleOS)
return (version.getMajor() >= 26);
return true;
case Kind::Custom:
return true;
}
}
bool AvailabilityDomain::supportsContextRefinement() const {
switch (getKind()) {
case Kind::Universal:
case Kind::Embedded:
case Kind::SwiftLanguageMode:
case Kind::PackageDescription:
return false;
case Kind::StandaloneSwiftRuntime:
case Kind::Platform:
case Kind::Custom:
return true;
}
}
bool AvailabilityDomain::supportsQueries() const {
switch (getKind()) {
case Kind::Universal:
case Kind::Embedded:
case Kind::SwiftLanguageMode:
case Kind::PackageDescription:
return false;
case Kind::StandaloneSwiftRuntime:
case Kind::Platform:
case Kind::Custom:
return true;
}
}
bool AvailabilityDomain::isActive(const ASTContext &ctx,
bool forTargetVariant) const {
switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguageMode:
case Kind::PackageDescription:
case Kind::Embedded:
return true;
case Kind::StandaloneSwiftRuntime:
// FIXME: [runtime availability] Active either when
// StandaloneSwiftAvailability is enabled or the target supports a
// standalone Swift runtime.
return ctx.LangOpts.hasFeature(Feature::SwiftRuntimeAvailability);
case Kind::Platform:
return isPlatformActive(getPlatformKind(), ctx.LangOpts, forTargetVariant);
case Kind::Custom:
// For now, custom domains are always active but it's conceivable that in
// the future someone might want to define a domain but leave it inactive.
return true;
}
}
bool AvailabilityDomain::isActivePlatform(const ASTContext &ctx,
bool forTargetVariant) const {
if (!isPlatform())
return false;
return isActive(ctx, forTargetVariant);
}
bool AvailabilityDomain::mustBeSpecifiedAlone() const {
switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguageMode:
case Kind::PackageDescription:
case Kind::Embedded:
case Kind::Custom:
return true;
case Kind::StandaloneSwiftRuntime:
case Kind::Platform:
// Platform and Swift runtime availability specifications can appear
// together, e.g. `@available(Swift 6, macOS 15, iOS 18, *)`.
// If there are ever multiple disjoint groups of domains that may be
// specified together in the future, this will need to be re-designed.
return false;
}
}
static std::optional<llvm::VersionTuple>
getDeploymentVersion(const AvailabilityDomain &domain, const ASTContext &ctx) {
switch (domain.getKind()) {
case AvailabilityDomain::Kind::Universal:
case AvailabilityDomain::Kind::Embedded:
case AvailabilityDomain::Kind::Custom:
return std::nullopt;
case AvailabilityDomain::Kind::SwiftLanguageMode:
return ctx.LangOpts.EffectiveLanguageVersion;
case AvailabilityDomain::Kind::PackageDescription:
return ctx.LangOpts.PackageDescriptionVersion;
case AvailabilityDomain::Kind::StandaloneSwiftRuntime:
if (!ctx.LangOpts.hasFeature(Feature::SwiftRuntimeAvailability))
return std::nullopt;
return ctx.LangOpts.MinSwiftRuntimeVersion;
case AvailabilityDomain::Kind::Platform:
if (domain.isActive(ctx))
return ctx.LangOpts.getMinPlatformVersion();
return std::nullopt;
}
}
std::optional<AvailabilityRange>
AvailabilityDomain::getDeploymentRange(const ASTContext &ctx) const {
if (isVersioned()) {
if (auto version = getDeploymentVersion(*this, ctx))
return AvailabilityRange{*version};
return std::nullopt;
}
if (auto customDomain = getCustomDomain()) {
switch (customDomain->getKind()) {
case CustomAvailabilityDomain::Kind::AlwaysEnabled:
return AvailabilityRange::alwaysAvailable();
case CustomAvailabilityDomain::Kind::Enabled:
case CustomAvailabilityDomain::Kind::Disabled:
case CustomAvailabilityDomain::Kind::Dynamic:
return std::nullopt;
}
}
return std::nullopt;
}
llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const {
switch (getKind()) {
case Kind::Universal:
return "*";
case Kind::SwiftLanguageMode:
// FIXME: [runtime availability] Render language mode diags differently.
return "Swift";
case Kind::StandaloneSwiftRuntime:
return "Swift";
case Kind::PackageDescription:
return "PackageDescription";
case Kind::Embedded:
return "Embedded Swift";
case Kind::Platform:
return swift::prettyPlatformString(getPlatformKind());
case Kind::Custom:
return getCustomDomain()->getName().str();
}
}
llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const {
switch (getKind()) {
case Kind::Universal:
return "*";
case Kind::SwiftLanguageMode:
return "swift";
case Kind::StandaloneSwiftRuntime:
return "Swift";
case Kind::PackageDescription:
return "_PackageDescription";
case Kind::Embedded:
return "Embedded";
case Kind::Platform:
return swift::platformString(getPlatformKind());
case Kind::Custom:
return getCustomDomain()->getName().str();
}
}
ValueDecl *AvailabilityDomain::getDecl() const {
if (auto *customDomain = getCustomDomain())
return customDomain->getDecl();
return nullptr;
}
ModuleDecl *AvailabilityDomain::getModule() const {
if (auto customDomain = getCustomDomain())
return customDomain->getModule();
return nullptr;
}
/// Returns true if `child` is a strict subset of `parent`.
static bool domainIsStrictSubsetOf(const AvailabilityDomain &child,
const AvailabilityDomain &parent) {
switch (parent.getKind()) {
case AvailabilityDomain::Kind::Universal:
case AvailabilityDomain::Kind::SwiftLanguageMode:
case AvailabilityDomain::Kind::StandaloneSwiftRuntime:
case AvailabilityDomain::Kind::PackageDescription:
case AvailabilityDomain::Kind::Embedded:
// These domains do not have any children in the lattice.
return false;
case AvailabilityDomain::Kind::Platform:
return inheritsAvailabilityFromPlatform(child.getPlatformKind(),
parent.getPlatformKind());
case AvailabilityDomain::Kind::Custom:
// Custom domains do not yet support inheritance relationships.
return false;
}
}
bool AvailabilityDomain::contains(const AvailabilityDomain &other) const {
if (other == *this)
return true;
return domainIsStrictSubsetOf(other, *this);
}
bool AvailabilityDomain::isSupersetOf(const AvailabilityDomain &other) const {
if (other == *this)
return false;
return domainIsStrictSubsetOf(other, *this);
}
bool AvailabilityDomain::isRelated(const AvailabilityDomain &other) const {
if (other == *this)
return true;
return domainIsStrictSubsetOf(other, *this) ||
domainIsStrictSubsetOf(*this, other);
}
bool AvailabilityDomain::isRoot() const {
switch (getKind()) {
case AvailabilityDomain::Kind::Universal:
case AvailabilityDomain::Kind::Embedded:
case AvailabilityDomain::Kind::SwiftLanguageMode:
case AvailabilityDomain::Kind::StandaloneSwiftRuntime:
case AvailabilityDomain::Kind::PackageDescription:
return true;
case AvailabilityDomain::Kind::Platform:
return getRootDomain() == *this;
case AvailabilityDomain::Kind::Custom:
// For now, all custom domains are their own root.
return true;
}
}
AvailabilityDomain AvailabilityDomain::getRootDomain() const {
// Currently, all non-platform domains are root domains.
if (!isPlatform())
return *this;
// iOS specifically contains a few other platforms.
auto iOSDomain = AvailabilityDomain::forPlatform(PlatformKind::iOS);
if (iOSDomain.contains(*this))
return iOSDomain;
// App Extension domains are contained by their base platform domain.
if (auto basePlatform = basePlatformForExtensionPlatform(getPlatformKind()))
return AvailabilityDomain::forPlatform(*basePlatform);
return *this;
}
static std::optional<PlatformKind>
getApplePlatformKindForTarget(const llvm::Triple &target) {
if (target.isMacOSX())
return PlatformKind::macOS;
if (target.isTvOS()) // Must be checked before isiOS.
return PlatformKind::tvOS;
if (target.isiOS())
return PlatformKind::iOS;
if (target.isWatchOS())
return PlatformKind::watchOS;
if (target.isXROS())
return PlatformKind::visionOS;
return std::nullopt;
}
std::optional<AvailabilityDomain>
AvailabilityDomain::getRemappedDomainOrNull(const ASTContext &ctx) const {
if (getPlatformKind() == PlatformKind::iOS &&
isPlatformActive(PlatformKind::visionOS, ctx.LangOpts))
return AvailabilityDomain::forPlatform(PlatformKind::visionOS);
if (getPlatformKind() == PlatformKind::anyAppleOS) {
if (auto applePlatformKind =
getApplePlatformKindForTarget(ctx.LangOpts.Target))
return AvailabilityDomain::forPlatform(*applePlatformKind);
return std::nullopt;
}
return std::nullopt;
}
static const clang::DarwinSDKInfo::RelatedTargetVersionMapping *
getFallbackVersionMapping(const ASTContext &Ctx,
clang::DarwinSDKInfo::OSEnvPair Kind) {
auto *SDKInfo = Ctx.getDarwinSDKInfo();
if (!SDKInfo)
return nullptr;
return SDKInfo->getVersionMapping(Kind);
}
static std::optional<clang::VersionTuple>
getRemappedIntroducedVersionForFallbackPlatform(
const ASTContext &Ctx, const llvm::VersionTuple &Version) {
const auto *Mapping = getFallbackVersionMapping(
Ctx, clang::DarwinSDKInfo::OSEnvPair(
llvm::Triple::IOS, llvm::Triple::UnknownEnvironment,
llvm::Triple::XROS, llvm::Triple::UnknownEnvironment));
if (!Mapping)
return std::nullopt;
return Mapping->mapIntroducedAvailabilityVersion(Version);
}
static std::optional<clang::VersionTuple>
getRemappedDeprecatedObsoletedVersionForFallbackPlatform(
const ASTContext &Ctx, const llvm::VersionTuple &Version) {
const auto *Mapping = getFallbackVersionMapping(
Ctx, clang::DarwinSDKInfo::OSEnvPair(
llvm::Triple::IOS, llvm::Triple::UnknownEnvironment,
llvm::Triple::XROS, llvm::Triple::UnknownEnvironment));
if (!Mapping)
return std::nullopt;
return Mapping->mapDeprecatedObsoletedAvailabilityVersion(Version);
}
AvailabilityRange AvailabilityDomain::getRemappedRange(
AvailabilityDomain toDomain, const llvm::VersionTuple &version,
AvailabilityVersionKind versionKind, const ASTContext &ctx) const {
// Precondition: The target domain inherits from this domain.
DEBUG_ASSERT(contains(toDomain));
// Currently, the only visionOS requires remapping versions from iOS.
if (getPlatformKind() == PlatformKind::iOS &&
AvailabilityDomain::forPlatform(PlatformKind::visionOS)
.contains(toDomain)) {
std::optional<clang::VersionTuple> remappedVersion;
switch (versionKind) {
case AvailabilityVersionKind::Introduced:
remappedVersion =
getRemappedIntroducedVersionForFallbackPlatform(ctx, version);
break;
case AvailabilityVersionKind::Deprecated:
case AvailabilityVersionKind::Obsoleted:
remappedVersion =
getRemappedDeprecatedObsoletedVersionForFallbackPlatform(ctx,
version);
break;
}
if (remappedVersion)
return AvailabilityRange(*remappedVersion);
}
// If there isn't a special remapping rule, the default remapping is to keep
// the version as-is and we know this is valid because the target domain
// inherits from this domain.
return AvailabilityRange{version};
}
AvailabilityDomainAndRange AvailabilityDomain::getRemappedDomainAndRange(
const llvm::VersionTuple &version, AvailabilityVersionKind versionKind,
const ASTContext &ctx) const {
auto remappedDomain = getRemappedDomainOrNull(ctx);
if (!remappedDomain)
return {*this, AvailabilityRange{version}};
return {*remappedDomain,
getRemappedRange(*remappedDomain, version, versionKind, ctx)};
}
bool IsCustomAvailabilityDomainPermanentlyEnabled::evaluate(
Evaluator &evaluator, const CustomAvailabilityDomain *customDomain) const {
switch (customDomain->getKind()) {
case CustomAvailabilityDomain::Kind::Enabled:
case CustomAvailabilityDomain::Kind::Disabled:
case CustomAvailabilityDomain::Kind::Dynamic:
return false;
case CustomAvailabilityDomain::Kind::AlwaysEnabled:
break;
}
auto *domainDecl = customDomain->getDecl();
if (!domainDecl)
return false;
if (auto deprecatedAttr = domainDecl->getDeprecatedAttr()) {
if (deprecatedAttr->getDomain().isUniversal())
return true;
}
if (auto unavailableAttr = domainDecl->getUnavailableAttr()) {
if (unavailableAttr->getDomain().isUniversal())
return true;
}
return false;
}
bool AvailabilityDomain::isPermanentlyAlwaysEnabled() const {
if (auto *customDomain = getCustomDomain()) {
if (auto *domainDecl = customDomain->getDecl())
return evaluateOrDefault(
domainDecl->getASTContext().evaluator,
IsCustomAvailabilityDomainPermanentlyEnabled{customDomain}, false);
}
return false;
}
void AvailabilityDomain::print(llvm::raw_ostream &os) const {
os << getNameForAttributePrinting();
}
AvailabilityDomain AvailabilityDomain::copy(ASTContext &ctx) const {
switch (getKind()) {
case Kind::Universal:
case Kind::SwiftLanguageMode:
case Kind::StandaloneSwiftRuntime:
case Kind::PackageDescription:
case Kind::Embedded:
case Kind::Platform:
// These domain kinds aren't ASTContext dependent.
return *this;
case Kind::Custom:
// To support this, the CustomAvailabilityDomain content would need to
// be copied to the other context, allocating new storage if necessary.
llvm::report_fatal_error("unsupported");
}
}
bool StableAvailabilityDomainComparator::operator()(
const AvailabilityDomain &lhs, const AvailabilityDomain &rhs) const {
auto lhsKind = lhs.getKind();
auto rhsKind = rhs.getKind();
if (lhsKind != rhsKind)
return lhsKind < rhsKind;
switch (lhsKind) {
case AvailabilityDomain::Kind::Universal:
case AvailabilityDomain::Kind::SwiftLanguageMode:
case AvailabilityDomain::Kind::StandaloneSwiftRuntime:
case AvailabilityDomain::Kind::PackageDescription:
case AvailabilityDomain::Kind::Embedded:
return false;
case AvailabilityDomain::Kind::Platform:
return lhs.getPlatformKind() < rhs.getPlatformKind();
case AvailabilityDomain::Kind::Custom: {
auto lhsMod = lhs.getModule();
auto rhsMod = rhs.getModule();
if (lhsMod != rhsMod)
return lhsMod->getName() < rhsMod->getName();
return lhs.getNameForAttributePrinting() <
rhs.getNameForAttributePrinting();
}
}
}
CustomAvailabilityDomain::CustomAvailabilityDomain(Identifier name, Kind kind,
ModuleDecl *mod,
ValueDecl *decl,
FuncDecl *predicateFunc)
: name(name), mod(mod), decl(decl), predicateFunc(predicateFunc),
kind(kind) {
ASSERT(!name.empty());
ASSERT(mod);
if (predicateFunc)
ASSERT(kind == Kind::Dynamic);
}
void CustomAvailabilityDomain::Profile(llvm::FoldingSetNodeID &ID,
Identifier name, ModuleDecl *mod) {
ID.AddPointer(name.getAsOpaquePointer());
ID.AddPointer(mod);
}
std::optional<AvailabilityDomain>
AvailabilityDomainOrIdentifier::lookUpInDeclContext(
SourceLoc loc, const DeclContext *declContext) const {
DEBUG_ASSERT(isIdentifier());
auto &ctx = declContext->getASTContext();
auto &diags = ctx.Diags;
std::optional<AvailabilityDomain> domain;
auto identifier = getAsIdentifier().value();
llvm::SmallVector<AvailabilityDomain> results;
declContext->lookupAvailabilityDomains(identifier, results);
if (results.size() > 0) {
// FIXME: [availability] Diagnose ambiguity if necessary.
domain = results.front();
}
bool hasCustomAvailability =
ctx.LangOpts.hasFeature(Feature::CustomAvailability);
bool hasSwiftRuntimeAvailability =
ctx.LangOpts.hasFeature(Feature::SwiftRuntimeAvailability);
if (!domain) {
auto domainString = identifier.str();
bool downgradeErrors =
!hasCustomAvailability || declContext->isInSwiftinterface();
if (auto suggestion = closestCorrectedPlatformString(domainString)) {
diags
.diagnose(loc, diag::availability_suggest_platform_name, identifier,
*suggestion)
.limitBehaviorIf(downgradeErrors, DiagnosticBehavior::Warning)
.fixItReplace(SourceRange(loc), *suggestion);
} else {
diags
.diagnose(loc, diag::availability_unrecognized_platform_name,
identifier)
.limitBehaviorIf(downgradeErrors, DiagnosticBehavior::Warning);
}
return std::nullopt;
}
// The remaining diagnostics are suppressed in .swiftinterfaces.
if (declContext->isInSwiftinterface())
return domain;
// Use of custom domains requires the 'CustomAvailability' feature.
if (domain->isCustom() && !hasCustomAvailability) {
diags.diagnose(loc, diag::availability_domain_requires_feature, *domain,
"CustomAvailability");
return std::nullopt;
}
// Use of the 'Swift' domain requires the 'SwiftRuntimeAvailability' feature.
if (!hasSwiftRuntimeAvailability && domain->isStandaloneSwiftRuntime()) {
diags.diagnose(loc, diag::availability_domain_requires_feature, *domain,
"SwiftRuntimeAvailability");
return std::nullopt;
}
if (domain->isSwiftLanguageMode()) {
// When the 'SwiftRuntimeAvailability' feature is enabled, the 'swift'
// domain spelling is deprecated in favor of 'SwiftLanguageMode'.
if (hasSwiftRuntimeAvailability && identifier.str() == "swift") {
diags
.diagnose(loc, diag::availability_domain_renamed, identifier,
"SwiftLanguageMode")
.fixItReplace(SourceRange(loc), "SwiftLanguageMode");
}
// Use of the 'SwiftLanguageMode' domain spelling requires the
// 'SwiftRuntimeAvailability' feature.
if (!hasSwiftRuntimeAvailability &&
identifier.str() == "SwiftLanguageMode") {
diags.diagnose(loc, diag::availability_domain_requires_feature, *domain,
"SwiftRuntimeAvailability");
return std::nullopt;
}
}
return domain;
}
AvailabilityDomainOrIdentifier
AvailabilityDomainOrIdentifier::copy(ASTContext &ctx) const {
if (auto identifier = getAsIdentifier())
return ctx.getIdentifier(identifier->str());
DEBUG_ASSERT(isDomain());
return getAsDomain()->copy(ctx);
}
void AvailabilityDomainOrIdentifier::print(llvm::raw_ostream &os) const {
if (auto identifier = getAsIdentifier())
os << identifier->str();
else
getAsDomain()->print(os);
}