Skip to content

Commit 93fef05

Browse files
authored
Merge pull request #59113 from DougGregor/enable-experimental-feature
Add -enable-experimental-feature X for experimental features.
2 parents f7f0a54 + 8da6cae commit 93fef05

24 files changed

+161
-69
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: 15 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -48,7 +48,12 @@
4848
LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
4949
#endif
5050

51-
LANGUAGE_FEATURE(StaticAssert, 0, "#assert", langOpts.EnableExperimentalStaticAssert)
51+
#ifndef EXPERIMENTAL_FEATURE
52+
# define EXPERIMENTAL_FEATURE(FeatureName) \
53+
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName, \
54+
langOpts.hasFeature(#FeatureName))
55+
#endif
56+
5257
LANGUAGE_FEATURE(AsyncAwait, 296, "async/await", true)
5358
LANGUAGE_FEATURE(EffectfulProp, 310, "Effectful properties", true)
5459
LANGUAGE_FEATURE(MarkerProtocol, 0, "@_marker protocol", true)
@@ -78,5 +83,14 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes2, 346, "Primary associated
7883
SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true)
7984
SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true)
8085

86+
EXPERIMENTAL_FEATURE(StaticAssert)
87+
EXPERIMENTAL_FEATURE(VariadicGenerics)
88+
EXPERIMENTAL_FEATURE(NamedOpaqueTypes)
89+
EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures)
90+
EXPERIMENTAL_FEATURE(MoveOnly)
91+
EXPERIMENTAL_FEATURE(OneWayClosureParameters)
92+
EXPERIMENTAL_FEATURE(TypeWitnessSystemInference)
93+
94+
#undef EXPERIMENTAL_FEATURE
8195
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
8296
#undef LANGUAGE_FEATURE

include/swift/Basic/LangOptions.h

Lines changed: 12 additions & 24 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"
@@ -312,23 +314,13 @@ namespace swift {
312314
/// Specifies how strict concurrency checking will be.
313315
StrictConcurrency StrictConcurrencyLevel = StrictConcurrency::Targeted;
314316

315-
/// Enable experimental #assert feature.
316-
bool EnableExperimentalStaticAssert = false;
317-
318317
/// Enable experimental concurrency model.
319318
bool EnableExperimentalConcurrency = false;
320319

321-
/// Enable experimental support for named opaque result types, e.g.
322-
/// `func f() -> <T> T`.
323-
bool EnableExperimentalNamedOpaqueTypes = false;
324-
325320
/// Enable support for implicitly opening existential argument types
326321
/// in calls to generic functions.
327322
bool EnableOpenedExistentialTypes = false;
328323

329-
/// Enable experimental flow-sensitive concurrent captures.
330-
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;
331-
332324
/// Disable experimental ClangImporter diagnostics.
333325
bool DisableExperimentalClangImporterDiagnostics = false;
334326

@@ -338,16 +330,6 @@ namespace swift {
338330
/// Enable inference of Sendable conformances for public types.
339331
bool EnableInferPublicSendable = false;
340332

341-
/// Enable experimental 'move only' features.
342-
bool EnableExperimentalMoveOnly = false;
343-
344-
/// Enable variadic generics.
345-
bool EnableExperimentalVariadicGenerics = false;
346-
347-
/// Enable experimental associated type inference using type witness
348-
/// systems.
349-
bool EnableExperimentalAssociatedTypeInference = false;
350-
351333
/// Disable the implicit import of the _Concurrency module.
352334
bool DisableImplicitConcurrencyModuleImport =
353335
!SWIFT_IMPLICIT_CONCURRENCY_IMPORT;
@@ -369,6 +351,9 @@ namespace swift {
369351
/// behavior. This is a staging flag, and will be removed in the future.
370352
bool EnableNewOperatorLookup = false;
371353

354+
/// The set of features that have been enabled.
355+
llvm::SmallSet<Feature, 2> Features;
356+
372357
/// Use Clang function types for computing canonical types.
373358
/// If this option is false, the clang function types will still be computed
374359
/// but will not be used for checking type equality.
@@ -616,6 +601,13 @@ namespace swift {
616601
return EffectiveLanguageVersion.isVersionAtLeast(major, minor);
617602
}
618603

604+
/// Determine whether the given feature is enabled.
605+
bool hasFeature(Feature feature) const;
606+
607+
/// Determine whether the given feature is enabled, looking up the feature
608+
/// by name.
609+
bool hasFeature(llvm::StringRef featureName) const;
610+
619611
/// Returns true if the given platform condition argument represents
620612
/// a supported target operating system.
621613
///
@@ -725,10 +717,6 @@ namespace swift {
725717
/// Disable constraint system performance hacks.
726718
bool DisableConstraintSolverPerformanceHacks = false;
727719

728-
/// Enable experimental support for one-way constraints for the
729-
/// parameters of closures.
730-
bool EnableOneWayClosureParameters = false;
731-
732720
/// See \ref FrontendOptions.PrintFullConvention
733721
bool PrintFullConvention = false;
734722
};

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: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2999,6 +2999,30 @@ 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+
3006+
static bool usesFeatureNamedOpaqueTypes(Decl *decl) {
3007+
return false;
3008+
}
3009+
3010+
static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
3011+
return false;
3012+
}
3013+
3014+
static bool usesFeatureMoveOnly(Decl *decl) {
3015+
return false;
3016+
}
3017+
3018+
static bool usesFeatureOneWayClosureParameters(Decl *decl) {
3019+
return false;
3020+
}
3021+
3022+
static bool usesFeatureTypeWitnessSystemInference(Decl *decl) {
3023+
return false;
3024+
}
3025+
30023026
static void
30033027
suppressingFeatureNoAsyncAvailability(PrintOptions &options,
30043028
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: 31 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -447,35 +447,18 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
447447
Opts.DiagnosticsEditorMode |= Args.hasArg(OPT_diagnostics_editor_mode,
448448
OPT_serialize_diagnostics_path);
449449

450-
Opts.EnableExperimentalStaticAssert |=
451-
Args.hasArg(OPT_enable_experimental_static_assert);
452-
453450
Opts.EnableExperimentalConcurrency |=
454451
Args.hasArg(OPT_enable_experimental_concurrency);
455452

456-
Opts.EnableExperimentalNamedOpaqueTypes |=
457-
Args.hasArg(OPT_enable_experimental_named_opaque_types);
458-
459453
Opts.EnableOpenedExistentialTypes =
460454
Args.hasFlag(OPT_enable_experimental_opened_existential_types,
461455
OPT_disable_experimental_opened_existential_types,
462456
true);
463457

464-
Opts.EnableExperimentalVariadicGenerics |=
465-
Args.hasArg(OPT_enable_experimental_variadic_generics);
466-
467-
Opts.EnableExperimentalAssociatedTypeInference |=
468-
Args.hasArg(OPT_enable_experimental_associated_type_inference);
469-
470-
Opts.EnableExperimentalMoveOnly |=
471-
Args.hasArg(OPT_enable_experimental_move_only);
472-
473458
Opts.EnableInferPublicSendable |=
474459
Args.hasFlag(OPT_enable_infer_public_concurrent_value,
475460
OPT_disable_infer_public_concurrent_value,
476461
false);
477-
Opts.EnableExperimentalFlowSensitiveConcurrentCaptures |=
478-
Args.hasArg(OPT_enable_experimental_flow_sensitive_concurrent_captures);
479462

480463
Opts.DisableExperimentalClangImporterDiagnostics |=
481464
Args.hasArg(OPT_disable_experimental_clang_importer_diagnostics);
@@ -649,6 +632,37 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
649632
Opts.addCustomConditionalCompilationFlag(A->getValue());
650633
}
651634

635+
for (const Arg *A : Args.filtered(OPT_enable_experimental_feature)) {
636+
// If this is a known experimental feature, allow it in +Asserts
637+
// (non-release) builds for testing purposes.
638+
if (auto feature = getExperimentalFeature(A->getValue())) {
639+
#ifdef NDEBUG
640+
Diags.diagnose(SourceLoc(),
641+
diag::error_experimental_feature_not_available,
642+
A->getValue());
643+
#endif
644+
645+
Opts.Features.insert(*feature);
646+
}
647+
}
648+
649+
// Map historical flags over to experimental features. We do this for all
650+
// compilers because that's how existing experimental feature flags work.
651+
if (Args.hasArg(OPT_enable_experimental_variadic_generics))
652+
Opts.Features.insert(Feature::VariadicGenerics);
653+
if (Args.hasArg(OPT_enable_experimental_static_assert))
654+
Opts.Features.insert(Feature::StaticAssert);
655+
if (Args.hasArg(OPT_enable_experimental_named_opaque_types))
656+
Opts.Features.insert(Feature::NamedOpaqueTypes);
657+
if (Args.hasArg(OPT_enable_experimental_flow_sensitive_concurrent_captures))
658+
Opts.Features.insert(Feature::FlowSensitiveConcurrencyCaptures);
659+
if (Args.hasArg(OPT_enable_experimental_move_only))
660+
Opts.Features.insert(Feature::MoveOnly);
661+
if (Args.hasArg(OPT_experimental_one_way_closure_params))
662+
Opts.Features.insert(Feature::OneWayClosureParameters);
663+
if (Args.hasArg(OPT_enable_experimental_associated_type_inference))
664+
Opts.Features.insert(Feature::TypeWitnessSystemInference);
665+
652666
Opts.EnableAppExtensionRestrictions |= Args.hasArg(OPT_enable_app_extension);
653667

654668
Opts.EnableSwift3ObjCInference =
@@ -1098,9 +1112,6 @@ static bool ParseTypeCheckerArgs(TypeCheckerOptions &Opts, ArgList &Args,
10981112
// Always enable operator designated types for the standard library.
10991113
Opts.EnableOperatorDesignatedTypes |= FrontendOpts.ParseStdlib;
11001114

1101-
Opts.EnableOneWayClosureParameters |=
1102-
Args.hasArg(OPT_experimental_one_way_closure_params);
1103-
11041115
Opts.PrintFullConvention |=
11051116
Args.hasArg(OPT_experimental_print_full_convention);
11061117

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/Parse/ParseStmt.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2719,7 +2719,7 @@ ParserResult<Stmt> Parser::parseStmtPoundAssert() {
27192719

27202720
// We check this after consuming everything, so that the SyntaxContext
27212721
// understands this statement even when the feature is disabled.
2722-
if (!Context.LangOpts.EnableExperimentalStaticAssert) {
2722+
if (!Context.LangOpts.hasFeature(Feature::StaticAssert)) {
27232723
diagnose(startLoc, diag::pound_assert_disabled);
27242724
return makeParserError();
27252725
}

lib/Parse/ParseType.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -564,7 +564,7 @@ ParserResult<TypeRepr> Parser::parseType(
564564

565565
ParserResult<TypeRepr> Parser::parseTypeWithOpaqueParams(Diag<> MessageID) {
566566
GenericParamList *genericParams = nullptr;
567-
if (Context.LangOpts.EnableExperimentalNamedOpaqueTypes) {
567+
if (Context.LangOpts.hasFeature(Feature::NamedOpaqueTypes)) {
568568
auto result = maybeParseGenericParams();
569569
genericParams = result.getPtrOrNull();
570570
if (result.hasCodeCompletion())

lib/SILGen/SILGenDecl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -474,7 +474,7 @@ class LetValueInitialization : public Initialization {
474474

475475
// Make sure that we have a non-address only type when binding a
476476
// @_noImplicitCopy let.
477-
if (SGF.getASTContext().LangOpts.EnableExperimentalMoveOnly &&
477+
if (SGF.getASTContext().LangOpts.hasFeature(Feature::MoveOnly) &&
478478
lowering.isAddressOnly() &&
479479
vd->getAttrs().hasAttribute<NoImplicitCopyAttr>()) {
480480
auto d = diag::noimplicitcopy_used_on_generic_or_existential;
@@ -556,7 +556,7 @@ class LetValueInitialization : public Initialization {
556556

557557
if (SGF.getASTContext().SILOpts.supportsLexicalLifetimes(SGF.getModule()) &&
558558
value->getOwnershipKind() != OwnershipKind::None) {
559-
if (!SGF.getASTContext().LangOpts.EnableExperimentalMoveOnly) {
559+
if (!SGF.getASTContext().LangOpts.hasFeature(Feature::MoveOnly)) {
560560
value = SILValue(
561561
SGF.B.createBeginBorrow(PrologueLoc, value, /*isLexical*/ true));
562562
} else {
@@ -1801,7 +1801,7 @@ void SILGenFunction::destroyLocalVariable(SILLocation silLoc, VarDecl *vd) {
18011801
return;
18021802
}
18031803

1804-
if (getASTContext().LangOpts.EnableExperimentalMoveOnly) {
1804+
if (getASTContext().LangOpts.hasFeature(Feature::MoveOnly)) {
18051805
if (auto *mvi = dyn_cast<MarkMustCheckInst>(Val.getDefiningInstruction())) {
18061806
if (mvi->isNoImplicitCopy()) {
18071807
if (auto *cvi = dyn_cast<CopyValueInst>(mvi->getOperand())) {

0 commit comments

Comments
 (0)