mirror of
https://github.com/apple/swift.git
synced 2025-12-21 12:14:44 +01:00
Merge pull request #59055 from DougGregor/future-feature
[SE-0362] Piecemeal adoption of upcoming language improvements
This commit is contained in:
13
CHANGELOG.md
13
CHANGELOG.md
@@ -3,6 +3,17 @@ CHANGELOG
|
||||
|
||||
_**Note:** This is in reverse chronological order, so newer entries are added to the top._
|
||||
|
||||
## Swift 5.8
|
||||
|
||||
* [SE-0362][]:
|
||||
|
||||
The compiler flag `-enable-upcoming-feature X` can now be used to enable a specific feature `X` that has been accepted by the evolution process, but whose introduction into the language is waiting for the next major version (e.g., version 6). The `X` is specified by any proposal that falls into this category:
|
||||
* `ConciseMagicFile` enables the new `#file` semantics in [SE-0274][].
|
||||
* `ForwardTrailingClosures` disables the "backward" scanning behavior of [SE-0286][].
|
||||
* `BareSlashRegexLiterals` enables the regex literal syntax of [SE-0352][].
|
||||
|
||||
Features can be detected in source code with `#if hasFeature(X)`.
|
||||
|
||||
## Swift 5.7
|
||||
|
||||
* The Swift compiler no longer warns about redundant requirements in generic declarations. For example,
|
||||
@@ -9459,6 +9470,7 @@ Swift 1.0
|
||||
[SE-0267]: <https://github.com/apple/swift-evolution/blob/main/proposals/0267-where-on-contextually-generic.md>
|
||||
[SE-0268]: <https://github.com/apple/swift-evolution/blob/main/proposals/0268-didset-semantics.md>
|
||||
[SE-0269]: <https://github.com/apple/swift-evolution/blob/main/proposals/0269-implicit-self-explicit-capture.md>
|
||||
[SE-0274]: <https://github.com/apple/swift-evolution/blob/main/proposals/0274-magic-file.md>
|
||||
[SE-0276]: <https://github.com/apple/swift-evolution/blob/main/proposals/0276-multi-pattern-catch-clauses.md>
|
||||
[SE-0279]: <https://github.com/apple/swift-evolution/blob/main/proposals/0279-multiple-trailing-closures.md>
|
||||
[SE-0280]: <https://github.com/apple/swift-evolution/blob/main/proposals/0280-enum-cases-as-protocol-witnesses.md>
|
||||
@@ -9509,6 +9521,7 @@ Swift 1.0
|
||||
[SE-0355]: <https://github.com/apple/swift-evolution/blob/main/proposals/0355-regex-syntax-run-time-construction.md>
|
||||
[SE-0357]: <https://github.com/apple/swift-evolution/blob/main/proposals/0357-regex-string-processing-algorithms.md>
|
||||
[SE-0358]: <https://github.com/apple/swift-evolution/blob/main/proposals/0358-primary-associated-types-in-stdlib.md>
|
||||
[SE-0362]: <https://github.com/apple/swift-evolution/blob/main/proposals/0362-piecemeal-future-features.md>
|
||||
|
||||
[SR-75]: <https://bugs.swift.org/browse/SR-75>
|
||||
[SR-106]: <https://bugs.swift.org/browse/SR-106>
|
||||
|
||||
@@ -40,6 +40,10 @@ ERROR(error_experimental_feature_not_available, none,
|
||||
"experimental feature '%0' cannot be enabled in a production compiler",
|
||||
(StringRef))
|
||||
|
||||
ERROR(error_upcoming_feature_on_by_default, none,
|
||||
"upcoming feature '%0' is already enabled as of Swift version %1",
|
||||
(StringRef, unsigned))
|
||||
|
||||
ERROR(error_unknown_library_level, none,
|
||||
"unknown library level '%0', "
|
||||
"expected one of 'api', 'spi' or 'other'", (StringRef))
|
||||
|
||||
@@ -53,7 +53,7 @@ inline bool featureImpliesFeature(Feature feature, Feature implied) {
|
||||
}
|
||||
|
||||
/// Get the feature corresponding to this "future" feature, if there is one.
|
||||
llvm::Optional<Feature> getFutureFeature(llvm::StringRef name);
|
||||
llvm::Optional<Feature> getUpcomingFeature(llvm::StringRef name);
|
||||
|
||||
/// Get the feature corresponding to this "experimental" feature, if there is
|
||||
/// one.
|
||||
|
||||
@@ -48,8 +48,8 @@
|
||||
LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
|
||||
#endif
|
||||
|
||||
#ifndef FUTURE_FEATURE
|
||||
# define FUTURE_FEATURE(FeatureName, SENumber, Version) \
|
||||
#ifndef UPCOMING_FEATURE
|
||||
# define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
|
||||
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName, \
|
||||
langOpts.hasFeature(#FeatureName))
|
||||
#endif
|
||||
@@ -90,9 +90,9 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes2, 346, "Primary associated
|
||||
SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true)
|
||||
SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true)
|
||||
|
||||
FUTURE_FEATURE(ConciseMagicFile, 274, 6)
|
||||
FUTURE_FEATURE(ForwardTrailingClosures, 286, 6)
|
||||
FUTURE_FEATURE(BareSlashRegexLiterals, 354, 6)
|
||||
UPCOMING_FEATURE(ConciseMagicFile, 274, 6)
|
||||
UPCOMING_FEATURE(ForwardTrailingClosures, 286, 6)
|
||||
UPCOMING_FEATURE(BareSlashRegexLiterals, 354, 6)
|
||||
|
||||
EXPERIMENTAL_FEATURE(StaticAssert)
|
||||
EXPERIMENTAL_FEATURE(VariadicGenerics)
|
||||
@@ -118,6 +118,6 @@ EXPERIMENTAL_FEATURE(AdditiveArithmeticDerivedConformances)
|
||||
EXPERIMENTAL_FEATURE(SendableCompletionHandlers)
|
||||
|
||||
#undef EXPERIMENTAL_FEATURE
|
||||
#undef FUTURE_FEATURE
|
||||
#undef UPCOMING_FEATURE
|
||||
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
|
||||
#undef LANGUAGE_FEATURE
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "llvm/ADT/SmallString.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/SmallVector.h"
|
||||
#include "llvm/ADT/SmallSet.h"
|
||||
#include "llvm/ADT/StringRef.h"
|
||||
#include "llvm/ADT/Triple.h"
|
||||
#include "llvm/Support/Regex.h"
|
||||
|
||||
@@ -696,6 +696,11 @@ def enable_experimental_feature :
|
||||
Flags<[FrontendOption]>,
|
||||
HelpText<"Enable an experimental feature">;
|
||||
|
||||
def enable_upcoming_feature : Separate<["-"], "enable-upcoming-feature">,
|
||||
Flags<[FrontendOption]>,
|
||||
HelpText<"Enable a feature that will be introduced in an upcoming language "
|
||||
"version">;
|
||||
|
||||
def Rpass_EQ : Joined<["-"], "Rpass=">,
|
||||
Flags<[FrontendOption]>,
|
||||
HelpText<"Report performed transformations by optimization passes whose "
|
||||
|
||||
@@ -240,7 +240,7 @@ bool LangOptions::hasFeature(Feature feature) const {
|
||||
}
|
||||
|
||||
bool LangOptions::hasFeature(llvm::StringRef featureName) const {
|
||||
if (auto feature = getFutureFeature(featureName))
|
||||
if (auto feature = getUpcomingFeature(featureName))
|
||||
return hasFeature(*feature);
|
||||
|
||||
if (auto feature = getExperimentalFeature(featureName))
|
||||
@@ -434,10 +434,10 @@ bool swift::isSuppressibleFeature(Feature feature) {
|
||||
llvm_unreachable("covered switch");
|
||||
}
|
||||
|
||||
llvm::Optional<Feature> swift::getFutureFeature(llvm::StringRef name) {
|
||||
llvm::Optional<Feature> swift::getUpcomingFeature(llvm::StringRef name) {
|
||||
return llvm::StringSwitch<Optional<Feature>>(name)
|
||||
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
|
||||
#define FUTURE_FEATURE(FeatureName, SENumber, Version) \
|
||||
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
|
||||
.Case(#FeatureName, Feature::FeatureName)
|
||||
#include "swift/Basic/Features.def"
|
||||
.Default(None);
|
||||
@@ -455,7 +455,7 @@ llvm::Optional<Feature> swift::getExperimentalFeature(llvm::StringRef name) {
|
||||
llvm::Optional<unsigned> swift::getFeatureLanguageVersion(Feature feature) {
|
||||
switch (feature) {
|
||||
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
|
||||
#define FUTURE_FEATURE(FeatureName, SENumber, Version) \
|
||||
#define UPCOMING_FEATURE(FeatureName, SENumber, Version) \
|
||||
case Feature::FeatureName: return Version;
|
||||
#include "swift/Basic/Features.def"
|
||||
default: return None;
|
||||
|
||||
@@ -237,6 +237,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
|
||||
inputArgs.AddLastArg(arguments, options::OPT_warn_concurrency);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_strict_concurrency);
|
||||
inputArgs.AddAllArgs(arguments, options::OPT_enable_experimental_feature);
|
||||
inputArgs.AddAllArgs(arguments, options::OPT_enable_upcoming_feature);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
|
||||
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);
|
||||
|
||||
@@ -15,6 +15,7 @@
|
||||
|
||||
#include "ArgsToFrontendOptionsConverter.h"
|
||||
#include "swift/AST/DiagnosticsFrontend.h"
|
||||
#include "swift/Basic/Feature.h"
|
||||
#include "swift/Basic/Platform.h"
|
||||
#include "swift/Option/Options.h"
|
||||
#include "swift/Option/SanitizerOptions.h"
|
||||
@@ -637,6 +638,26 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
|
||||
}
|
||||
}
|
||||
|
||||
// Map historical flags over to future features.
|
||||
for (const Arg *A : Args.filtered(OPT_enable_upcoming_feature)) {
|
||||
// Ignore unknown features.
|
||||
auto feature = getUpcomingFeature(A->getValue());
|
||||
if (!feature)
|
||||
continue;
|
||||
|
||||
// Check if this feature was introduced already in this language version.
|
||||
if (auto firstVersion = getFeatureLanguageVersion(*feature)) {
|
||||
if (Opts.isSwiftVersionAtLeast(*firstVersion)) {
|
||||
Diags.diagnose(SourceLoc(), diag::error_upcoming_feature_on_by_default,
|
||||
A->getValue(), *firstVersion);
|
||||
continue;
|
||||
}
|
||||
}
|
||||
|
||||
// Add the feature.
|
||||
Opts.Features.insert(*feature);
|
||||
}
|
||||
|
||||
// Map historical flags over to experimental features. We do this for all
|
||||
// compilers because that's how existing experimental feature flags work.
|
||||
if (Args.hasArg(OPT_enable_experimental_variadic_generics))
|
||||
|
||||
@@ -133,6 +133,13 @@ static Expr *getSingleSubExp(ArgumentList *args, StringRef kindName,
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
/// Returns \c true if the condition is a version check.
|
||||
static bool isVersionIfConfigCondition(Expr *Condition);
|
||||
|
||||
/// Evaluate the condition.
|
||||
/// \c true if success, \c false if failed.
|
||||
static bool evaluateIfConfigCondition(Expr *Condition, ASTContext &Context);
|
||||
|
||||
/// The condition validator.
|
||||
class ValidateIfConfigCondition :
|
||||
public ExprVisitor<ValidateIfConfigCondition, Expr*> {
|
||||
@@ -202,7 +209,7 @@ class ValidateIfConfigCondition :
|
||||
|
||||
// We will definitely be consuming at least one operator.
|
||||
// Pull out the prospective RHS and slice off the first two elements.
|
||||
Expr *RHS = validate(S[1]);
|
||||
Expr *RHS = S[1];
|
||||
S = S.slice(2);
|
||||
|
||||
while (true) {
|
||||
@@ -226,7 +233,7 @@ class ValidateIfConfigCondition :
|
||||
|
||||
OpName = NextOpName;
|
||||
Op = S[0];
|
||||
RHS = validate(S[1]);
|
||||
RHS = S[1];
|
||||
S = S.slice(2);
|
||||
}
|
||||
|
||||
@@ -329,6 +336,16 @@ public:
|
||||
return E;
|
||||
}
|
||||
|
||||
if (*KindName == "hasFeature") {
|
||||
if (!getDeclRefStr(Arg, DeclRefKind::Ordinary)) {
|
||||
D.diagnose(E->getLoc(), diag::unsupported_platform_condition_argument,
|
||||
"feature name");
|
||||
return nullptr;
|
||||
}
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
// ( 'os' | 'arch' | '_endian' | '_runtime' ) '(' identifier ')''
|
||||
auto Kind = getPlatformConditionKind(*KindName);
|
||||
if (!Kind.hasValue()) {
|
||||
@@ -416,14 +433,37 @@ public:
|
||||
return E;
|
||||
}
|
||||
|
||||
Expr *visitBinaryExpr(BinaryExpr *E) {
|
||||
auto OpName = getDeclRefStr(E->getFn(), DeclRefKind::BinaryOperator);
|
||||
if (auto lhs = validate(E->getLHS())) {
|
||||
// If the left-hand side is a versioned condition, skip evaluation of
|
||||
// the right-hand side if it won't ever affect the result.
|
||||
if (OpName && isVersionIfConfigCondition(lhs)) {
|
||||
assert(*OpName == "&&" || *OpName == "||");
|
||||
bool isLHSTrue = evaluateIfConfigCondition(lhs, Ctx);
|
||||
if (isLHSTrue && *OpName == "||")
|
||||
return lhs;
|
||||
if (!isLHSTrue && *OpName == "&&")
|
||||
return lhs;
|
||||
}
|
||||
|
||||
E->getArgs()->setExpr(0, lhs);
|
||||
}
|
||||
|
||||
if (auto rhs = validate(E->getRHS()))
|
||||
E->getArgs()->setExpr(1, rhs);
|
||||
|
||||
return E;
|
||||
}
|
||||
|
||||
// Fold sequence expression for non-Swift3 mode.
|
||||
Expr *visitSequenceExpr(SequenceExpr *E) {
|
||||
ArrayRef<Expr*> Elts = E->getElements();
|
||||
Expr *foldedExpr = validate(Elts[0]);
|
||||
Expr *foldedExpr = Elts[0];
|
||||
Elts = Elts.slice(1);
|
||||
foldedExpr = foldSequence(foldedExpr, Elts);
|
||||
assert(Elts.empty());
|
||||
return foldedExpr;
|
||||
return validate(foldedExpr);
|
||||
}
|
||||
|
||||
// Other expression types are unsupported.
|
||||
@@ -484,6 +524,7 @@ public:
|
||||
bool isKnownFeature = llvm::StringSwitch<bool>(Name)
|
||||
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
|
||||
.Case("$" #FeatureName, Option)
|
||||
#define UPCOMING_FEATURE(FeatureName, SENumber, Version)
|
||||
#include "swift/Basic/Features.def"
|
||||
.Default(false);
|
||||
|
||||
@@ -530,6 +571,9 @@ public:
|
||||
ImportPath::Module::Builder builder(Ctx, Str, /*separator=*/'.',
|
||||
Arg->getStartLoc());
|
||||
return Ctx.canImportModule(builder.get(), version, underlyingModule);
|
||||
} else if (KindName == "hasFeature") {
|
||||
auto featureName = getDeclRefStr(Arg);
|
||||
return Ctx.LangOpts.hasFeature(featureName);
|
||||
}
|
||||
|
||||
auto Val = getDeclRefStr(Arg);
|
||||
@@ -594,7 +638,6 @@ public:
|
||||
bool visitExpr(Expr *E) { return false; }
|
||||
};
|
||||
|
||||
/// Returns \c true if the condition is a version check.
|
||||
static bool isVersionIfConfigCondition(Expr *Condition) {
|
||||
return IsVersionIfConfigCondition().visit(Condition);
|
||||
}
|
||||
|
||||
26
test/Frontend/upcoming_feature.swift
Normal file
26
test/Frontend/upcoming_feature.swift
Normal file
@@ -0,0 +1,26 @@
|
||||
// Make sure that hasFeature(ConciseMagicFile) evaluates true when provided
|
||||
// explicitly.
|
||||
// RUN: %target-swift-frontend -typecheck -enable-upcoming-feature ConciseMagicFile %s
|
||||
|
||||
// Make sure that hasFeature(ConciseMagicFile) evaluates true in Swift 6.
|
||||
// RUN: %target-swift-frontend -typecheck -swift-version 6 %s
|
||||
|
||||
// Make sure that hasFeature(ConciseMagicFile) is off prior to Swift 6
|
||||
// RUN: %target-typecheck-verify-swift %s
|
||||
|
||||
// It's fine to provide a feature that we don't know about
|
||||
// RUN: %target-swift-frontend -typecheck -enable-upcoming-feature ConciseMagicFile -enable-upcoming-feature UnknownFeature %s
|
||||
// RUN: %target-swift-frontend -typecheck -enable-upcoming-feature UnknownFeature -enable-upcoming-feature ConciseMagicFile %s
|
||||
|
||||
|
||||
// It's not fine to provide a feature that's in the specified language version.
|
||||
// RUN: not %target-swift-frontend -typecheck -enable-upcoming-feature ConciseMagicFile -swift-version 6 %s 2>&1 | %FileCheck %s
|
||||
// REQUIRES: asserts
|
||||
|
||||
// CHECK: error: upcoming feature 'ConciseMagicFile' is already enabled as of Swift version 6
|
||||
|
||||
#if hasFeature(ConciseMagicFile)
|
||||
let x = 0
|
||||
#else
|
||||
let y = boom // expected-error{{'boom'}}
|
||||
#endif
|
||||
28
test/Parse/unknown_platform.swift
Normal file
28
test/Parse/unknown_platform.swift
Normal file
@@ -0,0 +1,28 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// expected-error@+1{{unexpected platform condition}}
|
||||
#if hasGreeble(blah)
|
||||
#endif
|
||||
|
||||
// Future compiler, short-circuit right-hand side
|
||||
#if compiler(>=10.0) && hasGreeble(blah)
|
||||
#endif
|
||||
|
||||
// Current compiler, short-circuit right-hand side
|
||||
#if compiler(<10.0) || hasGreeble(blah)
|
||||
#endif
|
||||
|
||||
// This compiler, don't short-circuit.
|
||||
// expected-error@+1{{unexpected platform condition}}
|
||||
#if compiler(>=5.7) && hasGreeble(blah)
|
||||
#endif
|
||||
|
||||
// This compiler, don't short-circuit.
|
||||
// expected-error@+1{{unexpected platform condition}}
|
||||
#if compiler(<5.8) || hasGreeble(blah)
|
||||
#endif
|
||||
|
||||
// Not a "version" check, so don't short-circuit.
|
||||
// expected-error@+1{{unexpected platform condition}}
|
||||
#if os(macOS) && hasGreeble(blah)
|
||||
#endif
|
||||
5
test/Parse/upcoming_feature.swift
Normal file
5
test/Parse/upcoming_feature.swift
Normal file
@@ -0,0 +1,5 @@
|
||||
// RUN: %target-typecheck-verify-swift
|
||||
|
||||
// expected-error@+1{{unexpected platform condition argument: expected feature name}}
|
||||
#if hasFeature(17)
|
||||
#endif
|
||||
@@ -1,5 +1,6 @@
|
||||
// The future "Swift 6 mode" behavior is staged in behind `-enable-experimental-concise-pound-file`.
|
||||
// The upcoming "Swift 6 mode" behavior is staged in behind `-enable-experimental-concise-pound-file`.
|
||||
// RUN: %target-typecheck-verify-swift -enable-experimental-concise-pound-file
|
||||
// RUN: %target-typecheck-verify-swift -enable-upcoming-feature ConciseMagicFile
|
||||
|
||||
// And is also available in Swift 6 mode on asserts compilers.
|
||||
// RUN: %target-typecheck-verify-swift -swift-version 6
|
||||
|
||||
Reference in New Issue
Block a user