From 1a86cd9c265d62da2e54163cd0eaec93f1cb15bf Mon Sep 17 00:00:00 2001 From: Allan Shortlidge Date: Tue, 7 Oct 2025 22:38:41 -0700 Subject: [PATCH] AST: Introduce a Swift runtime availability domain. Add support for the `Swift` availability domain, which represents availability with respect to the Swift runtime. Use of this domain is restricted by the experimental feature `SwiftRuntimeAvailability`. --- include/swift/AST/AvailabilityDomain.h | 13 +++ include/swift/Basic/LangOptions.h | 3 + include/swift/Option/Options.td | 7 ++ lib/AST/Availability.cpp | 4 +- lib/AST/AvailabilityConstraint.cpp | 2 + lib/AST/AvailabilityDomain.cpp | 100 ++++++++++++++---- lib/AST/AvailabilityQuery.cpp | 1 + lib/AST/AvailabilityScopeBuilder.cpp | 9 +- lib/Frontend/CompilerInvocation.cpp | 9 ++ lib/Sema/MiscDiagnostics.cpp | 11 +- lib/Sema/TypeCheckAttr.cpp | 10 +- lib/Sema/TypeCheckAvailability.cpp | 1 + lib/Sema/TypeCheckDeclOverride.cpp | 1 + lib/Sema/TypeCheckProtocol.cpp | 1 + lib/Serialization/Deserialization.cpp | 4 + lib/Serialization/ModuleFormat.h | 1 + lib/Serialization/Serialization.cpp | 2 + .../availability_swift_runtime.swift | 34 ++++-- .../attr_availability_swift_runtime.swift | 48 +++++++++ 19 files changed, 213 insertions(+), 48 deletions(-) create mode 100644 test/attr/attr_availability_swift_runtime.swift diff --git a/include/swift/AST/AvailabilityDomain.h b/include/swift/AST/AvailabilityDomain.h index ca86d15b6f7..2318ddd0646 100644 --- a/include/swift/AST/AvailabilityDomain.h +++ b/include/swift/AST/AvailabilityDomain.h @@ -51,6 +51,9 @@ public: /// Represents availability with respect to Swift language mode. SwiftLanguageMode, + /// Represents availability with respect to the Swift runtime. + SwiftRuntime, + /// Represents PackageDescription availability. PackageDescription, @@ -144,6 +147,10 @@ public: return AvailabilityDomain(Kind::SwiftLanguageMode); } + static AvailabilityDomain forSwiftRuntime() { + return AvailabilityDomain(Kind::SwiftRuntime); + } + static AvailabilityDomain forPackageDescription() { return AvailabilityDomain(Kind::PackageDescription); } @@ -185,6 +192,8 @@ public: return getKind() == Kind::SwiftLanguageMode; } + bool isSwiftRuntime() const { return getKind() == Kind::SwiftRuntime; } + bool isPackageDescription() const { return getKind() == Kind::PackageDescription; } @@ -236,6 +245,10 @@ public: bool isActivePlatform(const ASTContext &ctx, bool forTargetVariant = false) const; + /// Returns true if availability in this domain must be specified alone in + /// `@available` attributes and `if #available` queries. + bool mustBeSpecifiedAlone() const; + /// Returns the domain's minimum available range for type checking. For /// example, for the domain of the platform that compilation is targeting, /// this version is specified with the `-target` option. For the Swift diff --git a/include/swift/Basic/LangOptions.h b/include/swift/Basic/LangOptions.h index 02dc33a3fee..4687beea7d7 100644 --- a/include/swift/Basic/LangOptions.h +++ b/include/swift/Basic/LangOptions.h @@ -188,6 +188,9 @@ namespace swift { /// Swift runtime version to compile for. version::Version RuntimeVersion = version::Version::getCurrentLanguageVersion(); + /// The minimum Swift runtime version that the progam can be deployed to. + version::Version MinSwiftRuntimeVersion; + /// PackageDescription version to compile for. version::Version PackageDescriptionVersion; diff --git a/include/swift/Option/Options.td b/include/swift/Option/Options.td index 10ffc1b2dc6..99f714fd22e 100644 --- a/include/swift/Option/Options.td +++ b/include/swift/Option/Options.td @@ -298,6 +298,13 @@ def language_mode : Separate<["-"], "language-mode">, MetaVarName<"">, Alias; +def min_swift_runtime_version + : Separate<["-"], "min-swift-runtime-version">, + Flags<[FrontendOption, ModuleInterfaceOptionIgnorable]>, + HelpText<"The minimum Swift runtime version " + "that will be available at runtime">, + MetaVarName<"">; + def package_description_version: Separate<["-"], "package-description-version">, Flags<[FrontendOption, HelpHidden, ModuleInterfaceOption]>, HelpText<"The version number to be applied on the input for the PackageDescription availability kind">, diff --git a/lib/AST/Availability.cpp b/lib/AST/Availability.cpp index 0ccb60eebfd..b6bd0ae6f6a 100644 --- a/lib/AST/Availability.cpp +++ b/lib/AST/Availability.cpp @@ -640,6 +640,7 @@ computeDeclRuntimeAvailability(const Decl *decl) { if (!domain.isActive(ctx) && !isTargetDomain) continue; + // FIXME: [runtime availability] Update this? if (!domain.isRoot()) continue; @@ -855,7 +856,8 @@ SemanticAvailableAttrRequest::evaluate(swift::Evaluator &evaluator, return std::nullopt; } - if (domain->isSwiftLanguageMode() || domain->isPackageDescription()) { + if (domain->isSwiftLanguageMode() || domain->isPackageDescription() || + domain->isSwiftRuntime()) { switch (attr->getKind()) { case AvailableAttr::Kind::Deprecated: diags.diagnose(attrLoc, diff --git a/lib/AST/AvailabilityConstraint.cpp b/lib/AST/AvailabilityConstraint.cpp index aaa3efd0f2d..1eb15477f23 100644 --- a/lib/AST/AvailabilityConstraint.cpp +++ b/lib/AST/AvailabilityConstraint.cpp @@ -343,6 +343,7 @@ domainCanBeUnconditionallyUnavailableAtRuntime(AvailabilityDomain domain, return domain.isActive(ctx); case AvailabilityDomain::Kind::SwiftLanguageMode: + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::PackageDescription: return false; @@ -370,6 +371,7 @@ domainIsUnavailableAtRuntimeIfUnintroduced(AvailabilityDomain domain, case AvailabilityDomain::Kind::Universal: case AvailabilityDomain::Kind::Platform: case AvailabilityDomain::Kind::SwiftLanguageMode: + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::PackageDescription: return false; diff --git a/lib/AST/AvailabilityDomain.cpp b/lib/AST/AvailabilityDomain.cpp index 6f7d094a2f5..d2924fb985b 100644 --- a/lib/AST/AvailabilityDomain.cpp +++ b/lib/AST/AvailabilityDomain.cpp @@ -112,6 +112,7 @@ AvailabilityDomain::builtinDomainForString(StringRef string, .Case("*", AvailabilityDomain::forUniversal()) .Case("swift", AvailabilityDomain::forSwiftLanguageMode()) .Case("SwiftLanguageMode", AvailabilityDomain::forSwiftLanguageMode()) + .Case("Swift", AvailabilityDomain::forSwiftRuntime()) .Case("_PackageDescription", AvailabilityDomain::forPackageDescription()) .Default(std::nullopt); @@ -131,6 +132,7 @@ bool AvailabilityDomain::isVersioned() const { case Kind::Embedded: return false; case Kind::SwiftLanguageMode: + case Kind::SwiftRuntime: case Kind::PackageDescription: case Kind::Platform: return true; @@ -151,6 +153,12 @@ bool AvailabilityDomain::isVersionValid( case Kind::SwiftLanguageMode: case Kind::PackageDescription: return true; + case Kind::SwiftRuntime: + // Swift 5.0 is the first ABI stable Swift runtime version. + if (version.getMajor() < 5) + return false; + return true; + case Kind::Platform: if (auto osType = tripleOSTypeForPlatform(getPlatformKind())) return llvm::Triple::isValidVersionForOS(*osType, version); @@ -167,6 +175,7 @@ bool AvailabilityDomain::supportsContextRefinement() const { case Kind::SwiftLanguageMode: case Kind::PackageDescription: return false; + case Kind::SwiftRuntime: case Kind::Platform: case Kind::Custom: return true; @@ -180,6 +189,7 @@ bool AvailabilityDomain::supportsQueries() const { case Kind::SwiftLanguageMode: case Kind::PackageDescription: return false; + case Kind::SwiftRuntime: case Kind::Platform: case Kind::Custom: return true; @@ -194,6 +204,8 @@ bool AvailabilityDomain::isActive(const ASTContext &ctx, case Kind::PackageDescription: case Kind::Embedded: return true; + case Kind::SwiftRuntime: + return ctx.LangOpts.hasFeature(Feature::SwiftRuntimeAvailability); case Kind::Platform: return isPlatformActive(getPlatformKind(), ctx.LangOpts, forTargetVariant); case Kind::Custom: @@ -211,6 +223,24 @@ bool AvailabilityDomain::isActivePlatform(const ASTContext &ctx, 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::SwiftRuntime: + 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 getDeploymentVersion(const AvailabilityDomain &domain, const ASTContext &ctx) { switch (domain.getKind()) { @@ -222,6 +252,10 @@ getDeploymentVersion(const AvailabilityDomain &domain, const ASTContext &ctx) { return ctx.LangOpts.EffectiveLanguageVersion; case AvailabilityDomain::Kind::PackageDescription: return ctx.LangOpts.PackageDescriptionVersion; + case AvailabilityDomain::Kind::SwiftRuntime: + 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(); @@ -256,6 +290,9 @@ llvm::StringRef AvailabilityDomain::getNameForDiagnostics() const { case Kind::Universal: return "*"; case Kind::SwiftLanguageMode: + // FIXME: [runtime availability] Render language mode diags differently. + return "Swift"; + case Kind::SwiftRuntime: return "Swift"; case Kind::PackageDescription: return "PackageDescription"; @@ -274,6 +311,8 @@ llvm::StringRef AvailabilityDomain::getNameForAttributePrinting() const { return "*"; case Kind::SwiftLanguageMode: return "swift"; + case Kind::SwiftRuntime: + return "Swift"; case Kind::PackageDescription: return "_PackageDescription"; case Kind::Embedded: @@ -308,6 +347,8 @@ bool AvailabilityDomain::contains(const AvailabilityDomain &other) const { case Kind::Embedded: case Kind::Custom: return other == *this; + case Kind::SwiftRuntime: + return other.isPlatform() || other == *this; case Kind::Platform: if (getPlatformKind() == other.getPlatformKind()) return true; @@ -321,6 +362,7 @@ bool AvailabilityDomain::isRoot() const { case AvailabilityDomain::Kind::Universal: case AvailabilityDomain::Kind::Embedded: case AvailabilityDomain::Kind::SwiftLanguageMode: + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::PackageDescription: return true; case AvailabilityDomain::Kind::Platform: @@ -406,6 +448,7 @@ AvailabilityDomain AvailabilityDomain::copy(ASTContext &ctx) const { switch (getKind()) { case Kind::Universal: case Kind::SwiftLanguageMode: + case Kind::SwiftRuntime: case Kind::PackageDescription: case Kind::Embedded: case Kind::Platform: @@ -428,6 +471,7 @@ bool StableAvailabilityDomainComparator::operator()( switch (lhsKind) { case AvailabilityDomain::Kind::Universal: case AvailabilityDomain::Kind::SwiftLanguageMode: + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::PackageDescription: case AvailabilityDomain::Kind::Embedded: return false; @@ -504,31 +548,41 @@ AvailabilityDomainOrIdentifier::lookUpInDeclContext( return std::nullopt; } - if (!declContext->isInSwiftinterface()) { - if (domain->isCustom() && !hasCustomAvailability) { - diags.diagnose(loc, diag::availability_domain_requires_feature, *domain, - "CustomAvailability"); - 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->isSwiftRuntime()) { + 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"); } - if (domain->isSwiftLanguageMode()) { - // 'swift' -> 'SwiftLanguageMode' - if (hasSwiftRuntimeAvailability && identifier.str() == "swift") { - diags - .diagnose(loc, diag::availability_domain_renamed, identifier, - "SwiftLanguageMode") - .fixItReplace(SourceRange(loc), "SwiftLanguageMode"); - } - - if (!hasSwiftRuntimeAvailability && - identifier.str() == "SwiftLanguageMode") { - // This diagnostic ("Swift requires '-enable-experimental-feature - // SwiftRuntimeAvailability'") is confusing but it's also temporary, - // assuming the experimental feature becomes official. - diags.diagnose(loc, diag::availability_domain_requires_feature, *domain, - "SwiftRuntimeAvailability"); - return std::nullopt; - } + // 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; } } diff --git a/lib/AST/AvailabilityQuery.cpp b/lib/AST/AvailabilityQuery.cpp index a8c3ba5ad7a..16b3b41c2ae 100644 --- a/lib/AST/AvailabilityQuery.cpp +++ b/lib/AST/AvailabilityQuery.cpp @@ -133,6 +133,7 @@ FuncDecl *AvailabilityQuery::getDynamicQueryDeclAndArguments( switch (domain.getKind()) { case AvailabilityDomain::Kind::Universal: case AvailabilityDomain::Kind::SwiftLanguageMode: + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::PackageDescription: case AvailabilityDomain::Kind::Embedded: return nullptr; diff --git a/lib/AST/AvailabilityScopeBuilder.cpp b/lib/AST/AvailabilityScopeBuilder.cpp index 0956390e9ee..47273ff7ac7 100644 --- a/lib/AST/AvailabilityScopeBuilder.cpp +++ b/lib/AST/AvailabilityScopeBuilder.cpp @@ -869,11 +869,12 @@ private: return AvailabilityQuery::dynamic(variantSpec->getDomain(), primaryRange, variantRange); + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::Platform: - // Platform checks are always dynamic. The SIL optimizer is responsible - // eliminating these checks when it can prove that they can never fail - // (due to the deployment target). We can't perform that analysis here - // because it may depend on inlining. + // Platform and Swift runtime checks are always dynamic. The SIL optimizer + // is responsible eliminating these checks when it can prove that they can + // never fail (due to the deployment target). We can't perform that + // analysis here because it may depend on inlining. return AvailabilityQuery::dynamic(domain, primaryRange, variantRange); case AvailabilityDomain::Kind::Custom: auto customDomain = domain.getCustomDomain(); diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 67748923d9e..b5a33751614 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -1046,6 +1046,15 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, // HadError = true; } + if (auto A = Args.getLastArg(OPT_min_swift_runtime_version)) { + if (auto vers = VersionParser::parseVersionString(A->getValue(), + SourceLoc(), &Diags)) { + Opts.MinSwiftRuntimeVersion = *vers; + } else { + return true; + } + } + if (auto A = Args.getLastArg(OPT_package_description_version)) { auto vers = VersionParser::parseVersionString(A->getValue(), SourceLoc(), &Diags); diff --git a/lib/Sema/MiscDiagnostics.cpp b/lib/Sema/MiscDiagnostics.cpp index f9bfc444c89..780ea16a13d 100644 --- a/lib/Sema/MiscDiagnostics.cpp +++ b/lib/Sema/MiscDiagnostics.cpp @@ -5131,7 +5131,7 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, info->isUnavailability() ? "#unavailable" : "#available"; bool hasValidSpecs = false; - bool allValidSpecsArePlatform = true; + bool wildcardRequiredInList = false; std::optional wildcardLoc; llvm::SmallSet seenDomains; for (auto spec : info->getSemanticAvailabilitySpecs(DC)) { @@ -5144,6 +5144,7 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, auto domain = spec.getDomain(); auto loc = parsedSpec->getStartLoc(); bool hasVersion = !spec.getVersion().empty(); + bool mustBeSpecifiedAlone = domain.mustBeSpecifiedAlone(); if (!domain.supportsQueries()) { diags.diagnose(loc, diag::availability_query_not_allowed, domain, @@ -5151,7 +5152,7 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, return true; } - if (!domain.isPlatform() && info->getQueries().size() > 1) { + if (mustBeSpecifiedAlone && info->getQueries().size() > 1) { diags.diagnose(loc, diag::availability_must_occur_alone, domain, hasVersion); return true; @@ -5199,8 +5200,8 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, } hasValidSpecs = true; - if (!domain.isPlatform()) - allValidSpecsArePlatform = false; + if (!mustBeSpecifiedAlone) + wildcardRequiredInList = true; } if (info->isUnavailability()) { @@ -5210,7 +5211,7 @@ static bool diagnoseAvailabilityCondition(PoundAvailableInfo *info, diag::unavailability_query_wildcard_not_required) .fixItRemove(*wildcardLoc); } - } else if (!wildcardLoc && hasValidSpecs && allValidSpecsArePlatform) { + } else if (!wildcardLoc && hasValidSpecs && wildcardRequiredInList) { if (info->getQueries().size() > 0) { auto insertLoc = info->getQueries().back()->getSourceRange().End; diags.diagnose(insertLoc, diag::availability_query_wildcard_required) diff --git a/lib/Sema/TypeCheckAttr.cpp b/lib/Sema/TypeCheckAttr.cpp index 064b6f0d467..b005626ffe5 100644 --- a/lib/Sema/TypeCheckAttr.cpp +++ b/lib/Sema/TypeCheckAttr.cpp @@ -5195,7 +5195,7 @@ void AttributeChecker::checkAvailableAttrs(ArrayRef attrs) { SourceLoc groupEndLoc; bool foundWildcard = false; bool hasValidSpecs = false; - bool allValidSpecsArePlatform = true; + bool wildcardRequiredInList = true; int groupAttrCount = 0; for (auto *groupedAttr = groupHead; groupedAttr != nullptr; groupedAttr = groupedAttr->getNextGroupedAvailableAttr()) { @@ -5219,7 +5219,7 @@ void AttributeChecker::checkAvailableAttrs(ArrayRef attrs) { foundWildcard) { // Only platform availability is allowed to be written groups with more // than one member. - if (!domain.isPlatform()) { + if (domain.mustBeSpecifiedAlone()) { diagnose(loc, diag::availability_must_occur_alone, domain, domain.isVersioned()); continue; @@ -5234,11 +5234,11 @@ void AttributeChecker::checkAvailableAttrs(ArrayRef attrs) { } hasValidSpecs = true; - if (!domain.isPlatform()) - allValidSpecsArePlatform = false; + if (domain.mustBeSpecifiedAlone()) + wildcardRequiredInList = false; } - if (!foundWildcard && hasValidSpecs && allValidSpecsArePlatform) { + if (!foundWildcard && hasValidSpecs && wildcardRequiredInList) { diagnose(groupEndLoc, diag::availability_query_wildcard_required) .fixItInsert(groupEndLoc, ", *"); } diff --git a/lib/Sema/TypeCheckAvailability.cpp b/lib/Sema/TypeCheckAvailability.cpp index cad67fd0f4d..9befa1030cf 100644 --- a/lib/Sema/TypeCheckAvailability.cpp +++ b/lib/Sema/TypeCheckAvailability.cpp @@ -1699,6 +1699,7 @@ bool shouldHideDomainNameForConstraintDiagnostic( case AvailabilityDomain::Kind::Custom: case AvailabilityDomain::Kind::PackageDescription: return true; + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::Platform: return false; case AvailabilityDomain::Kind::SwiftLanguageMode: diff --git a/lib/Sema/TypeCheckDeclOverride.cpp b/lib/Sema/TypeCheckDeclOverride.cpp index b354ed85153..b733602c721 100644 --- a/lib/Sema/TypeCheckDeclOverride.cpp +++ b/lib/Sema/TypeCheckDeclOverride.cpp @@ -2197,6 +2197,7 @@ static bool checkSingleOverride(ValueDecl *override, ValueDecl *base) { switch (domain.getKind()) { case AvailabilityDomain::Kind::Universal: case AvailabilityDomain::Kind::SwiftLanguageMode: + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::PackageDescription: case AvailabilityDomain::Kind::Platform: // FIXME: [availability] Diagnose as an error in a future Swift version. diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 4e24f1c06d1..e2b5049d072 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -5257,6 +5257,7 @@ diagnoseTypeWitnessAvailability(NormalProtocolConformance *conformance, case AvailabilityDomain::Kind::PackageDescription: case AvailabilityDomain::Kind::Platform: break; + case AvailabilityDomain::Kind::SwiftRuntime: case AvailabilityDomain::Kind::Embedded: case AvailabilityDomain::Kind::Custom: shouldError = true; diff --git a/lib/Serialization/Deserialization.cpp b/lib/Serialization/Deserialization.cpp index 5ce70771e00..8869182e094 100644 --- a/lib/Serialization/Deserialization.cpp +++ b/lib/Serialization/Deserialization.cpp @@ -5813,6 +5813,8 @@ decodeDomainKind(uint8_t kind) { return AvailabilityDomainKind::Universal; case static_cast(AvailabilityDomainKind::SwiftLanguageMode): return AvailabilityDomainKind::SwiftLanguageMode; + case static_cast(AvailabilityDomainKind::SwiftRuntime): + return AvailabilityDomainKind::SwiftRuntime; case static_cast(AvailabilityDomainKind::PackageDescription): return AvailabilityDomainKind::PackageDescription; case static_cast(AvailabilityDomainKind::Embedded): @@ -5834,6 +5836,8 @@ decodeAvailabilityDomain(AvailabilityDomainKind domainKind, return AvailabilityDomain::forUniversal(); case AvailabilityDomainKind::SwiftLanguageMode: return AvailabilityDomain::forSwiftLanguageMode(); + case AvailabilityDomainKind::SwiftRuntime: + return AvailabilityDomain::forSwiftRuntime(); case AvailabilityDomainKind::PackageDescription: return AvailabilityDomain::forPackageDescription(); case AvailabilityDomainKind::Embedded: diff --git a/lib/Serialization/ModuleFormat.h b/lib/Serialization/ModuleFormat.h index 33f4f1e1114..5b812d3e305 100644 --- a/lib/Serialization/ModuleFormat.h +++ b/lib/Serialization/ModuleFormat.h @@ -776,6 +776,7 @@ enum class AvailabilityDomainKind : uint8_t { Embedded, Platform, Custom, + SwiftRuntime, }; using AvailabilityDomainKindField = BCFixed<3>; diff --git a/lib/Serialization/Serialization.cpp b/lib/Serialization/Serialization.cpp index 22e84f18b94..1cb8b9d9b7a 100644 --- a/lib/Serialization/Serialization.cpp +++ b/lib/Serialization/Serialization.cpp @@ -3134,6 +3134,8 @@ class Serializer::DeclSerializer : public DeclVisitor { return AvailabilityDomainKind::Universal; case AvailabilityDomain::Kind::SwiftLanguageMode: return AvailabilityDomainKind::SwiftLanguageMode; + case AvailabilityDomain::Kind::SwiftRuntime: + return AvailabilityDomainKind::SwiftRuntime; case AvailabilityDomain::Kind::PackageDescription: return AvailabilityDomainKind::PackageDescription; case AvailabilityDomain::Kind::Embedded: diff --git a/test/Availability/availability_swift_runtime.swift b/test/Availability/availability_swift_runtime.swift index 3c7718ae915..dd7913d7a95 100644 --- a/test/Availability/availability_swift_runtime.swift +++ b/test/Availability/availability_swift_runtime.swift @@ -1,16 +1,30 @@ -// RUN: %target-typecheck-verify-swift -parse-as-library -enable-experimental-feature SwiftRuntimeAvailability +// RUN: %target-typecheck-verify-swift -parse-as-library -enable-experimental-feature SwiftRuntimeAvailability -min-swift-runtime-version 5.5 // REQUIRES: swift_feature_SwiftRuntimeAvailability -@available(swift 99) // expected-warning {{'swift' has been renamed to 'SwiftLanguageMode'}}{{12-17=SwiftLanguageMode}} -func availableInSwift99() { } -// expected-note@-1 {{'availableInSwift99()' was introduced in Swift 99}} +@available(Swift 5.0, *) +func availableInSwift5_0Runtime() { } -@available(SwiftLanguageMode 99) -func availableInSwift99LanguageMode() { } -// expected-note@-1 {{'availableInSwift99LanguageMode()' was introduced in Swift 99}} +@available(Swift 5.5, *) +func availableInSwift5_5Runtime() { } -func testUses() { - availableInSwift99() // expected-error {{'availableInSwift99()' is unavailable in Swift}} - availableInSwift99LanguageMode() // expected-error {{'availableInSwift99LanguageMode()' is unavailable in Swift}} +@available(Swift 6.0, *) +func availableInSwift6_0Runtime() { } + +func alwaysAvailable() { + // expected-note@-1 {{add '@available' attribute to enclosing global function}}{{1-1=@available(Swift 6.0)\n}} + + availableInSwift5_0Runtime() + availableInSwift5_5Runtime() + availableInSwift6_0Runtime() // expected-error {{'availableInSwift6_0Runtime()' is only available in Swift 6.0 or newer}} + // expected-note@-1 {{add 'if #available' version check}}{{3-31=if #available(Swift 6.0) {\n availableInSwift6_0Runtime()\n \} else {\n // Fallback on earlier versions\n \}}} + + if #available(Swift 6.0, *) { + availableInSwift6_0Runtime() + } +} + +@available(Swift 6.0, *) +func availableSwift6() { + availableInSwift6_0Runtime() } diff --git a/test/attr/attr_availability_swift_runtime.swift b/test/attr/attr_availability_swift_runtime.swift new file mode 100644 index 00000000000..81eb35ba71e --- /dev/null +++ b/test/attr/attr_availability_swift_runtime.swift @@ -0,0 +1,48 @@ +// RUN: %target-typecheck-verify-swift -swift-version 5 -parse-as-library -enable-experimental-feature SwiftRuntimeAvailability + +// REQUIRES: swift_feature_SwiftRuntimeAvailability + +@available(Swift 6, *) +func availableInSwiftRuntime6Short() { } + +@available(Swift 6.0, *) +func availableInSwiftRuntime6_0Short() { } + +@available(Swift 6, macOS 15, iOS 18, watchOS 11, tvOS 18, visionOS 2, *) +func availableInSwiftRuntime6ShortWithPlatforms() { } + +@available(Swift, introduced: 6) +func availableInSwiftRuntime6() { } + +@available(Swift, introduced: 6.0) +func availableInSwiftRuntime6_0() { } + +@available(Swift, introduced: 5.1, obsoleted: 6) +func availableInSwiftRuntime5_1Thru6() { } + +@available(Swift, deprecated: 5.9) +func deprecatedInSwiftRuntime5_9() { } + +@available(Swift 4, *) // expected-warning {{'4' is not a valid version number for Swift}} +func availableInSwiftRuntime4() { } + +@available(Swift 4.9, *) // expected-warning {{'4.9' is not a valid version number for Swift}} +func availableInSwiftRuntime4_9() { } + +// Swift 5.0 is the earliest possible runtime version +@available(Swift 5, *) +func availableInSwiftRuntime5() { } + +@available(Swift, unavailable) // expected-warning {{'unavailable' cannot be used in '@available' attribute for Swift}} +func unavailableInSwiftRuntime() { } + +// MARK: Swift language mode + +@available(swift 6) // expected-warning {{'swift' has been renamed to 'SwiftLanguageMode'}}{{12-17=SwiftLanguageMode}} +func swift6OldSpellingShort() { } + +@available(swift, introduced: 6) // expected-warning {{'swift' has been renamed to 'SwiftLanguageMode'}}{{12-17=SwiftLanguageMode}} +func swift6OldSpelling() { } + +@available(SwiftLanguageMode 6) +func swiftLanguageModeShort6() { }