Skip to content

Commit 6d82448

Browse files
committed
Add -enable-experimental-feature X for experimental features.
Experimental features can only be enabled in non-production (+Asserts) builds. They can be detected with `hasFeature` in the same manner as "future" features. The `-enable-experimental-feature X` flag will also look for future features by that name, so that when an experimental feature becomes an accepted future feature, it will still be enabled in the same manner. Switch variadic generics over to this approach, eliminating the specific LangOption for it.
1 parent a07636b commit 6d82448

File tree

14 files changed

+105
-14
lines changed

14 files changed

+105
-14
lines changed

include/swift/AST/DiagnosticsFrontend.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -36,6 +36,10 @@ ERROR(error_unsupported_target_os, none,
3636
ERROR(error_unsupported_target_arch, none,
3737
"unsupported target architecture: '%0'", (StringRef))
3838

39+
ERROR(error_experimental_feature_not_available, none,
40+
"experimental feature '%0' cannot be enabled in a production compiler",
41+
(StringRef))
42+
3943
ERROR(error_unknown_library_level, none,
4044
"unknown library level '%0', "
4145
"expected one of 'api', 'spi' or 'other'", (StringRef))

include/swift/Basic/Feature.h

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -18,18 +18,18 @@
1818
namespace swift {
1919

2020
class LangOptions;
21-
21+
2222
/// Enumeration describing all of the named features.
2323
enum class Feature {
2424
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
25-
FeatureName,
26-
#include "swift/Basic/Features.def"
25+
FeatureName,
26+
#include "swift/Basic/Features.def"
2727
};
2828

2929
constexpr unsigned numFeatures() {
3030
enum Features {
3131
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
32-
FeatureName,
32+
FeatureName,
3333
#include "swift/Basic/Features.def"
3434
NumFeatures
3535
};
@@ -51,6 +51,10 @@ inline bool featureImpliesFeature(Feature feature, Feature implied) {
5151
return (unsigned) feature < (unsigned) implied;
5252
}
5353

54+
/// Get the feature corresponding to this "experimental" feature, if there is
55+
/// one.
56+
llvm::Optional<Feature> getExperimentalFeature(llvm::StringRef name);
57+
5458
}
5559

5660
#endif // SWIFT_BASIC_FEATURES_H

include/swift/Basic/Features.def

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -48,6 +48,12 @@
4848
LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
4949
#endif
5050

51+
#ifndef EXPERIMENTAL_FEATURE
52+
# define EXPERIMENTAL_FEATURE(FeatureName) \
53+
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName, \
54+
langOpts.hasFeature(#FeatureName))
55+
#endif
56+
5157
LANGUAGE_FEATURE(StaticAssert, 0, "#assert", langOpts.EnableExperimentalStaticAssert)
5258
LANGUAGE_FEATURE(AsyncAwait, 296, "async/await", true)
5359
LANGUAGE_FEATURE(EffectfulProp, 310, "Effectful properties", true)
@@ -78,5 +84,8 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes2, 346, "Primary associated
7884
SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true)
7985
SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true)
8086

87+
EXPERIMENTAL_FEATURE(VariadicGenerics)
88+
89+
#undef EXPERIMENTAL_FEATURE
8190
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
8291
#undef LANGUAGE_FEATURE

include/swift/Basic/LangOptions.h

Lines changed: 12 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -18,13 +18,15 @@
1818
#ifndef SWIFT_BASIC_LANGOPTIONS_H
1919
#define SWIFT_BASIC_LANGOPTIONS_H
2020

21+
#include "swift/Basic/Feature.h"
2122
#include "swift/Basic/FunctionBodySkipping.h"
2223
#include "swift/Basic/LLVM.h"
2324
#include "swift/Basic/Version.h"
2425
#include "swift/Config.h"
2526
#include "llvm/ADT/ArrayRef.h"
2627
#include "llvm/ADT/Hashing.h"
2728
#include "llvm/ADT/SmallString.h"
29+
#include "llvm/ADT/SmallSet.h"
2830
#include "llvm/ADT/SmallVector.h"
2931
#include "llvm/ADT/StringRef.h"
3032
#include "llvm/ADT/Triple.h"
@@ -341,9 +343,6 @@ namespace swift {
341343
/// Enable experimental 'move only' features.
342344
bool EnableExperimentalMoveOnly = false;
343345

344-
/// Enable variadic generics.
345-
bool EnableExperimentalVariadicGenerics = false;
346-
347346
/// Enable experimental associated type inference using type witness
348347
/// systems.
349348
bool EnableExperimentalAssociatedTypeInference = false;
@@ -369,6 +368,9 @@ namespace swift {
369368
/// behavior. This is a staging flag, and will be removed in the future.
370369
bool EnableNewOperatorLookup = false;
371370

371+
/// The set of features that have been enabled.
372+
llvm::SmallSet<Feature, 2> Features;
373+
372374
/// Use Clang function types for computing canonical types.
373375
/// If this option is false, the clang function types will still be computed
374376
/// but will not be used for checking type equality.
@@ -616,6 +618,13 @@ namespace swift {
616618
return EffectiveLanguageVersion.isVersionAtLeast(major, minor);
617619
}
618620

621+
/// Determine whether the given feature is enabled.
622+
bool hasFeature(Feature feature) const;
623+
624+
/// Determine whether the given feature is enabled, looking up the feature
625+
/// by name.
626+
bool hasFeature(llvm::StringRef featureName) const;
627+
619628
/// Returns true if the given platform condition argument represents
620629
/// a supported target operating system.
621630
///

include/swift/Option/Options.td

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -691,6 +691,11 @@ def strict_concurrency : Joined<["-"], "strict-concurrency=">,
691691
"concurrency model, or 'complete' ('Sendable' and other checking is "
692692
"enabled for all code in the module)">;
693693

694+
def enable_experimental_feature :
695+
Separate<["-"], "enable-experimental-feature">,
696+
Flags<[FrontendOption]>,
697+
HelpText<"Enable an experimental feature">;
698+
694699
def Rpass_EQ : Joined<["-"], "Rpass=">,
695700
Flags<[FrontendOption]>,
696701
HelpText<"Report performed transformations by optimization passes whose "

lib/AST/ASTPrinter.cpp

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2999,6 +2999,10 @@ static bool usesFeatureNoAsyncAvailability(Decl *decl) {
29992999
return decl->getAttrs().getNoAsync(decl->getASTContext()) != nullptr;
30003000
}
30013001

3002+
static bool usesFeatureVariadicGenerics(Decl *decl) {
3003+
return false;
3004+
}
3005+
30023006
static void
30033007
suppressingFeatureNoAsyncAvailability(PrintOptions &options,
30043008
llvm::function_ref<void()> action) {

lib/Basic/LangOptions.cpp

Lines changed: 23 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -224,6 +224,20 @@ bool LangOptions::isCustomConditionalCompilationFlagSet(StringRef Name) const {
224224
!= CustomConditionalCompilationFlags.end();
225225
}
226226

227+
bool LangOptions::hasFeature(Feature feature) const {
228+
if (Features.contains(feature))
229+
return true;
230+
231+
return false;
232+
}
233+
234+
bool LangOptions::hasFeature(llvm::StringRef featureName) const {
235+
if (auto feature = getExperimentalFeature(featureName))
236+
return hasFeature(*feature);
237+
238+
return false;
239+
}
240+
227241
std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
228242
clearAllPlatformConditionValues();
229243

@@ -409,6 +423,15 @@ bool swift::isSuppressibleFeature(Feature feature) {
409423
llvm_unreachable("covered switch");
410424
}
411425

426+
llvm::Optional<Feature> swift::getExperimentalFeature(llvm::StringRef name) {
427+
return llvm::StringSwitch<Optional<Feature>>(name)
428+
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
429+
#define EXPERIMENTAL_FEATURE(FeatureName) \
430+
.Case(#FeatureName, Feature::FeatureName)
431+
#include "swift/Basic/Features.def"
432+
.Default(None);
433+
}
434+
412435
DiagnosticBehavior LangOptions::getAccessNoteFailureLimit() const {
413436
switch (AccessNoteBehavior) {
414437
case AccessNoteDiagnosticBehavior::Ignore:

lib/Driver/ToolChains.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -236,6 +236,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
236236
options::OPT_disable_actor_data_race_checks);
237237
inputArgs.AddLastArg(arguments, options::OPT_warn_concurrency);
238238
inputArgs.AddLastArg(arguments, options::OPT_strict_concurrency);
239+
inputArgs.AddAllArgs(arguments, options::OPT_enable_experimental_feature);
239240
inputArgs.AddLastArg(arguments, options::OPT_warn_implicit_overrides);
240241
inputArgs.AddLastArg(arguments, options::OPT_typo_correction_limit);
241242
inputArgs.AddLastArg(arguments, options::OPT_enable_app_extension);

lib/Frontend/CompilerInvocation.cpp

Lines changed: 19 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -461,9 +461,6 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
461461
OPT_disable_experimental_opened_existential_types,
462462
true);
463463

464-
Opts.EnableExperimentalVariadicGenerics |=
465-
Args.hasArg(OPT_enable_experimental_variadic_generics);
466-
467464
Opts.EnableExperimentalAssociatedTypeInference |=
468465
Args.hasArg(OPT_enable_experimental_associated_type_inference);
469466

@@ -649,6 +646,25 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
649646
Opts.addCustomConditionalCompilationFlag(A->getValue());
650647
}
651648

649+
for (const Arg *A : Args.filtered(OPT_enable_experimental_feature)) {
650+
// If this is a known experimental feature, allow it in +Asserts
651+
// (non-release) builds for testing purposes.
652+
if (auto feature = getExperimentalFeature(A->getValue())) {
653+
#ifdef NDEBUG
654+
Diags.diagnose(SourceLoc(),
655+
diag::error_experimental_feature_not_available,
656+
A->getValue());
657+
#endif
658+
659+
Opts.Features.insert(*feature);
660+
}
661+
}
662+
663+
// Map historical flags over to experimental features. We do this for all
664+
// compilers because that's how existing experimental feature flags work.
665+
if (Args.hasArg(OPT_enable_experimental_variadic_generics))
666+
Opts.Features.insert(Feature::VariadicGenerics);
667+
652668
Opts.EnableAppExtensionRestrictions |= Args.hasArg(OPT_enable_app_extension);
653669

654670
Opts.EnableSwift3ObjCInference =

lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2908,7 +2908,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
29082908
break;
29092909
}
29102910
case DAK_TypeSequence: {
2911-
if (Context.LangOpts.EnableExperimentalVariadicGenerics) {
2911+
if (Context.LangOpts.hasFeature(Feature::VariadicGenerics)) {
29122912
auto range = SourceRange(Loc, Tok.getRange().getStart());
29132913
Attributes.add(TypeSequenceAttr::create(Context, AtLoc, range));
29142914
} else {

lib/Sema/CSApply.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -5629,7 +5629,7 @@ ArgumentList *ExprRewriter::coerceCallArguments(
56295629
auto paramLabel = param.getLabel();
56305630

56315631
// Handle variadic generic parameters.
5632-
if (ctx.LangOpts.EnableExperimentalVariadicGenerics &&
5632+
if (ctx.LangOpts.hasFeature(Feature::VariadicGenerics) &&
56335633
paramInfo.isVariadicGenericParameter(paramIdx)) {
56345634
assert(param.isVariadic());
56355635
assert(!param.isInOut());

lib/Sema/CSSimplify.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1746,7 +1746,7 @@ static ConstraintSystem::TypeMatchResult matchCallArguments(
17461746
// We pull these out special because variadic parameters ban lots of
17471747
// the more interesting typing constructs called out below like
17481748
// inout and @autoclosure.
1749-
if (cs.getASTContext().LangOpts.EnableExperimentalVariadicGenerics &&
1749+
if (cs.getASTContext().LangOpts.hasFeature(Feature::VariadicGenerics) &&
17501750
paramInfo.isVariadicGenericParameter(paramIdx)) {
17511751
auto *PET = paramTy->castTo<PackExpansionType>();
17521752
OpenTypeSequenceElements openTypeSequence{cs, PET};

lib/Sema/TypeCheckType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3815,7 +3815,7 @@ NeverNullType TypeResolver::resolveTupleType(TupleTypeRepr *repr,
38153815

38163816
bool complained = false;
38173817
if (repr->hasEllipsis()) {
3818-
if (getASTContext().LangOpts.EnableExperimentalVariadicGenerics &&
3818+
if (getASTContext().LangOpts.hasFeature(Feature::VariadicGenerics) &&
38193819
repr->getNumElements() == 1 && !repr->hasElementNames()) {
38203820
// This is probably a pack expansion. Try to resolve the pattern type.
38213821
auto patternTy = resolveType(repr->getElementType(0), elementOptions);
Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,16 @@
1+
// RUN: %target-swift-frontend -typecheck -enable-experimental-feature VariadicGenerics -enable-experimental-feature UnknownFeature %s
2+
3+
// REQUIRES: asserts
4+
5+
// Make sure definition is defined for variadic generics
6+
#if $VariadicGenerics
7+
// okay
8+
#else
9+
let x = BOOM
10+
#endif
11+
12+
// Use variadic generics
13+
func debugPrint<@_typeSequence T>(_ items: T...)
14+
where T: CustomDebugStringConvertible
15+
{
16+
}

0 commit comments

Comments
 (0)