Skip to content

Add -enable-experimental-feature X for experimental features. #59113

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 7 commits into from
May 27, 2022
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 4 additions & 0 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,10 @@ ERROR(error_unsupported_target_os, none,
ERROR(error_unsupported_target_arch, none,
"unsupported target architecture: '%0'", (StringRef))

ERROR(error_experimental_feature_not_available, none,
"experimental feature '%0' cannot be enabled in a production compiler",
(StringRef))

ERROR(error_unknown_library_level, none,
"unknown library level '%0', "
"expected one of 'api', 'spi' or 'other'", (StringRef))
Expand Down
12 changes: 8 additions & 4 deletions include/swift/Basic/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,18 +18,18 @@
namespace swift {

class LangOptions;

/// Enumeration describing all of the named features.
enum class Feature {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
FeatureName,
#include "swift/Basic/Features.def"
FeatureName,
#include "swift/Basic/Features.def"
};

constexpr unsigned numFeatures() {
enum Features {
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option) \
FeatureName,
FeatureName,
#include "swift/Basic/Features.def"
NumFeatures
};
Expand All @@ -51,6 +51,10 @@ inline bool featureImpliesFeature(Feature feature, Feature implied) {
return (unsigned) feature < (unsigned) implied;
}

/// Get the feature corresponding to this "experimental" feature, if there is
/// one.
llvm::Optional<Feature> getExperimentalFeature(llvm::StringRef name);

}

#endif // SWIFT_BASIC_FEATURES_H
16 changes: 15 additions & 1 deletion include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,12 @@
LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
#endif

LANGUAGE_FEATURE(StaticAssert, 0, "#assert", langOpts.EnableExperimentalStaticAssert)
#ifndef EXPERIMENTAL_FEATURE
# define EXPERIMENTAL_FEATURE(FeatureName) \
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName, \
langOpts.hasFeature(#FeatureName))
#endif

LANGUAGE_FEATURE(AsyncAwait, 296, "async/await", true)
LANGUAGE_FEATURE(EffectfulProp, 310, "Effectful properties", true)
LANGUAGE_FEATURE(MarkerProtocol, 0, "@_marker protocol", true)
Expand Down Expand Up @@ -78,5 +83,14 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(PrimaryAssociatedTypes2, 346, "Primary associated
SUPPRESSIBLE_LANGUAGE_FEATURE(UnavailableFromAsync, 0, "@_unavailableFromAsync", true)
SUPPRESSIBLE_LANGUAGE_FEATURE(NoAsyncAvailability, 340, "@available(*, noasync)", true)

EXPERIMENTAL_FEATURE(StaticAssert)
EXPERIMENTAL_FEATURE(VariadicGenerics)
EXPERIMENTAL_FEATURE(NamedOpaqueTypes)
EXPERIMENTAL_FEATURE(FlowSensitiveConcurrencyCaptures)
EXPERIMENTAL_FEATURE(MoveOnly)
EXPERIMENTAL_FEATURE(OneWayClosureParameters)
EXPERIMENTAL_FEATURE(TypeWitnessSystemInference)

#undef EXPERIMENTAL_FEATURE
#undef SUPPRESSIBLE_LANGUAGE_FEATURE
#undef LANGUAGE_FEATURE
36 changes: 12 additions & 24 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -18,13 +18,15 @@
#ifndef SWIFT_BASIC_LANGOPTIONS_H
#define SWIFT_BASIC_LANGOPTIONS_H

#include "swift/Basic/Feature.h"
#include "swift/Basic/FunctionBodySkipping.h"
#include "swift/Basic/LLVM.h"
#include "swift/Basic/Version.h"
#include "swift/Config.h"
#include "llvm/ADT/ArrayRef.h"
#include "llvm/ADT/Hashing.h"
#include "llvm/ADT/SmallString.h"
#include "llvm/ADT/SmallSet.h"
#include "llvm/ADT/SmallVector.h"
#include "llvm/ADT/StringRef.h"
#include "llvm/ADT/Triple.h"
Expand Down Expand Up @@ -312,23 +314,13 @@ namespace swift {
/// Specifies how strict concurrency checking will be.
StrictConcurrency StrictConcurrencyLevel = StrictConcurrency::Targeted;

/// Enable experimental #assert feature.
bool EnableExperimentalStaticAssert = false;

/// Enable experimental concurrency model.
bool EnableExperimentalConcurrency = false;

/// Enable experimental support for named opaque result types, e.g.
/// `func f() -> <T> T`.
bool EnableExperimentalNamedOpaqueTypes = false;

/// Enable support for implicitly opening existential argument types
/// in calls to generic functions.
bool EnableOpenedExistentialTypes = false;

/// Enable experimental flow-sensitive concurrent captures.
bool EnableExperimentalFlowSensitiveConcurrentCaptures = false;

/// Disable experimental ClangImporter diagnostics.
bool DisableExperimentalClangImporterDiagnostics = false;

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

/// Enable experimental 'move only' features.
bool EnableExperimentalMoveOnly = false;

/// Enable variadic generics.
bool EnableExperimentalVariadicGenerics = false;

/// Enable experimental associated type inference using type witness
/// systems.
bool EnableExperimentalAssociatedTypeInference = false;

/// Disable the implicit import of the _Concurrency module.
bool DisableImplicitConcurrencyModuleImport =
!SWIFT_IMPLICIT_CONCURRENCY_IMPORT;
Expand All @@ -369,6 +351,9 @@ namespace swift {
/// behavior. This is a staging flag, and will be removed in the future.
bool EnableNewOperatorLookup = false;

/// The set of features that have been enabled.
llvm::SmallSet<Feature, 2> Features;

/// Use Clang function types for computing canonical types.
/// If this option is false, the clang function types will still be computed
/// but will not be used for checking type equality.
Expand Down Expand Up @@ -616,6 +601,13 @@ namespace swift {
return EffectiveLanguageVersion.isVersionAtLeast(major, minor);
}

/// Determine whether the given feature is enabled.
bool hasFeature(Feature feature) const;

/// Determine whether the given feature is enabled, looking up the feature
/// by name.
bool hasFeature(llvm::StringRef featureName) const;

/// Returns true if the given platform condition argument represents
/// a supported target operating system.
///
Expand Down Expand Up @@ -725,10 +717,6 @@ namespace swift {
/// Disable constraint system performance hacks.
bool DisableConstraintSolverPerformanceHacks = false;

/// Enable experimental support for one-way constraints for the
/// parameters of closures.
bool EnableOneWayClosureParameters = false;

/// See \ref FrontendOptions.PrintFullConvention
bool PrintFullConvention = false;
};
Expand Down
5 changes: 5 additions & 0 deletions include/swift/Option/Options.td
Original file line number Diff line number Diff line change
Expand Up @@ -691,6 +691,11 @@ def strict_concurrency : Joined<["-"], "strict-concurrency=">,
"concurrency model, or 'complete' ('Sendable' and other checking is "
"enabled for all code in the module)">;

def enable_experimental_feature :
Separate<["-"], "enable-experimental-feature">,
Flags<[FrontendOption]>,
HelpText<"Enable an experimental feature">;

def Rpass_EQ : Joined<["-"], "Rpass=">,
Flags<[FrontendOption]>,
HelpText<"Report performed transformations by optimization passes whose "
Expand Down
24 changes: 24 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2999,6 +2999,30 @@ static bool usesFeatureNoAsyncAvailability(Decl *decl) {
return decl->getAttrs().getNoAsync(decl->getASTContext()) != nullptr;
}

static bool usesFeatureVariadicGenerics(Decl *decl) {
return false;
}

static bool usesFeatureNamedOpaqueTypes(Decl *decl) {
return false;
}

static bool usesFeatureFlowSensitiveConcurrencyCaptures(Decl *decl) {
return false;
}

static bool usesFeatureMoveOnly(Decl *decl) {
return false;
}

static bool usesFeatureOneWayClosureParameters(Decl *decl) {
return false;
}

static bool usesFeatureTypeWitnessSystemInference(Decl *decl) {
return false;
}

static void
suppressingFeatureNoAsyncAvailability(PrintOptions &options,
llvm::function_ref<void()> action) {
Expand Down
23 changes: 23 additions & 0 deletions lib/Basic/LangOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,20 @@ bool LangOptions::isCustomConditionalCompilationFlagSet(StringRef Name) const {
!= CustomConditionalCompilationFlags.end();
}

bool LangOptions::hasFeature(Feature feature) const {
if (Features.contains(feature))
return true;

return false;
}

bool LangOptions::hasFeature(llvm::StringRef featureName) const {
if (auto feature = getExperimentalFeature(featureName))
return hasFeature(*feature);

return false;
}

std::pair<bool, bool> LangOptions::setTarget(llvm::Triple triple) {
clearAllPlatformConditionValues();

Expand Down Expand Up @@ -409,6 +423,15 @@ bool swift::isSuppressibleFeature(Feature feature) {
llvm_unreachable("covered switch");
}

llvm::Optional<Feature> swift::getExperimentalFeature(llvm::StringRef name) {
return llvm::StringSwitch<Optional<Feature>>(name)
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description, Option)
#define EXPERIMENTAL_FEATURE(FeatureName) \
.Case(#FeatureName, Feature::FeatureName)
#include "swift/Basic/Features.def"
.Default(None);
}

DiagnosticBehavior LangOptions::getAccessNoteFailureLimit() const {
switch (AccessNoteBehavior) {
case AccessNoteDiagnosticBehavior::Ignore:
Expand Down
1 change: 1 addition & 0 deletions lib/Driver/ToolChains.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -236,6 +236,7 @@ void ToolChain::addCommonFrontendArgs(const OutputInfo &OI,
options::OPT_disable_actor_data_race_checks);
inputArgs.AddLastArg(arguments, options::OPT_warn_concurrency);
inputArgs.AddLastArg(arguments, options::OPT_strict_concurrency);
inputArgs.AddAllArgs(arguments, options::OPT_enable_experimental_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);
Expand Down
51 changes: 31 additions & 20 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -447,35 +447,18 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.DiagnosticsEditorMode |= Args.hasArg(OPT_diagnostics_editor_mode,
OPT_serialize_diagnostics_path);

Opts.EnableExperimentalStaticAssert |=
Args.hasArg(OPT_enable_experimental_static_assert);

Opts.EnableExperimentalConcurrency |=
Args.hasArg(OPT_enable_experimental_concurrency);

Opts.EnableExperimentalNamedOpaqueTypes |=
Args.hasArg(OPT_enable_experimental_named_opaque_types);

Opts.EnableOpenedExistentialTypes =
Args.hasFlag(OPT_enable_experimental_opened_existential_types,
OPT_disable_experimental_opened_existential_types,
true);

Opts.EnableExperimentalVariadicGenerics |=
Args.hasArg(OPT_enable_experimental_variadic_generics);

Opts.EnableExperimentalAssociatedTypeInference |=
Args.hasArg(OPT_enable_experimental_associated_type_inference);

Opts.EnableExperimentalMoveOnly |=
Args.hasArg(OPT_enable_experimental_move_only);

Opts.EnableInferPublicSendable |=
Args.hasFlag(OPT_enable_infer_public_concurrent_value,
OPT_disable_infer_public_concurrent_value,
false);
Opts.EnableExperimentalFlowSensitiveConcurrentCaptures |=
Args.hasArg(OPT_enable_experimental_flow_sensitive_concurrent_captures);

Opts.DisableExperimentalClangImporterDiagnostics |=
Args.hasArg(OPT_disable_experimental_clang_importer_diagnostics);
Expand Down Expand Up @@ -649,6 +632,37 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args,
Opts.addCustomConditionalCompilationFlag(A->getValue());
}

for (const Arg *A : Args.filtered(OPT_enable_experimental_feature)) {
// If this is a known experimental feature, allow it in +Asserts
// (non-release) builds for testing purposes.
if (auto feature = getExperimentalFeature(A->getValue())) {
#ifdef NDEBUG
Diags.diagnose(SourceLoc(),
diag::error_experimental_feature_not_available,
A->getValue());
#endif

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))
Opts.Features.insert(Feature::VariadicGenerics);
if (Args.hasArg(OPT_enable_experimental_static_assert))
Opts.Features.insert(Feature::StaticAssert);
if (Args.hasArg(OPT_enable_experimental_named_opaque_types))
Opts.Features.insert(Feature::NamedOpaqueTypes);
if (Args.hasArg(OPT_enable_experimental_flow_sensitive_concurrent_captures))
Opts.Features.insert(Feature::FlowSensitiveConcurrencyCaptures);
if (Args.hasArg(OPT_enable_experimental_move_only))
Opts.Features.insert(Feature::MoveOnly);
if (Args.hasArg(OPT_experimental_one_way_closure_params))
Opts.Features.insert(Feature::OneWayClosureParameters);
if (Args.hasArg(OPT_enable_experimental_associated_type_inference))
Opts.Features.insert(Feature::TypeWitnessSystemInference);

Opts.EnableAppExtensionRestrictions |= Args.hasArg(OPT_enable_app_extension);

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

Opts.EnableOneWayClosureParameters |=
Args.hasArg(OPT_experimental_one_way_closure_params);

Opts.PrintFullConvention |=
Args.hasArg(OPT_experimental_print_full_convention);

Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2908,7 +2908,7 @@ bool Parser::parseNewDeclAttribute(DeclAttributes &Attributes, SourceLoc AtLoc,
break;
}
case DAK_TypeSequence: {
if (Context.LangOpts.EnableExperimentalVariadicGenerics) {
if (Context.LangOpts.hasFeature(Feature::VariadicGenerics)) {
auto range = SourceRange(Loc, Tok.getRange().getStart());
Attributes.add(TypeSequenceAttr::create(Context, AtLoc, range));
} else {
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseStmt.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2719,7 +2719,7 @@ ParserResult<Stmt> Parser::parseStmtPoundAssert() {

// We check this after consuming everything, so that the SyntaxContext
// understands this statement even when the feature is disabled.
if (!Context.LangOpts.EnableExperimentalStaticAssert) {
if (!Context.LangOpts.hasFeature(Feature::StaticAssert)) {
diagnose(startLoc, diag::pound_assert_disabled);
return makeParserError();
}
Expand Down
2 changes: 1 addition & 1 deletion lib/Parse/ParseType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -564,7 +564,7 @@ ParserResult<TypeRepr> Parser::parseType(

ParserResult<TypeRepr> Parser::parseTypeWithOpaqueParams(Diag<> MessageID) {
GenericParamList *genericParams = nullptr;
if (Context.LangOpts.EnableExperimentalNamedOpaqueTypes) {
if (Context.LangOpts.hasFeature(Feature::NamedOpaqueTypes)) {
auto result = maybeParseGenericParams();
genericParams = result.getPtrOrNull();
if (result.hasCodeCompletion())
Expand Down
6 changes: 3 additions & 3 deletions lib/SILGen/SILGenDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -474,7 +474,7 @@ class LetValueInitialization : public Initialization {

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

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

if (getASTContext().LangOpts.EnableExperimentalMoveOnly) {
if (getASTContext().LangOpts.hasFeature(Feature::MoveOnly)) {
if (auto *mvi = dyn_cast<MarkMustCheckInst>(Val.getDefiningInstruction())) {
if (mvi->isNoImplicitCopy()) {
if (auto *cvi = dyn_cast<CopyValueInst>(mvi->getOperand())) {
Expand Down
Loading