Skip to content

[Basic] Features: Align "migration" mode with the latest proposal draft #81149

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 3 commits into from
Apr 29, 2025
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: 2 additions & 2 deletions include/swift/AST/DiagnosticsFrontend.def
Original file line number Diff line number Diff line change
Expand Up @@ -59,9 +59,9 @@ GROUPED_WARNING(cannot_disable_feature_with_mode, StrictLanguageFeatures, none,
"'%0' argument '%1' cannot specify a mode",
(StringRef, StringRef))

GROUPED_WARNING(feature_does_not_support_adoption_mode, StrictLanguageFeatures,
GROUPED_WARNING(feature_does_not_support_migration_mode, StrictLanguageFeatures,
none,
"feature '%0' does not support adoption mode",
"feature '%0' does not support migration mode",
(StringRef))

ERROR(error_unknown_library_level, none,
Expand Down
4 changes: 2 additions & 2 deletions include/swift/Basic/Feature.h
Original file line number Diff line number Diff line change
Expand Up @@ -57,8 +57,8 @@ struct Feature {
/// Determine the in-source name of the given feature.
llvm::StringRef getName() const;

/// Determine whether the given feature supports adoption mode.
bool isAdoptable() const;
/// Determine whether the given feature supports migration mode.
bool isMigratable() const;

/// Determine whether this feature should be included in the
/// module interface
Expand Down
30 changes: 15 additions & 15 deletions include/swift/Basic/Features.def
Original file line number Diff line number Diff line change
Expand Up @@ -121,36 +121,36 @@
LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#endif

// An upcoming feature that supports adoption mode.
// An upcoming feature that supports migration mode.
//
// If the feature is source-breaking and provides for a
// mechanical code migration, it should implement adoption mode.
// mechanical code migration, it should implement migration mode.
//
// Adoption mode is a feature-oriented code migration mechanism: a mode
// Migration mode is a feature-oriented code migration mechanism: a mode
// of operation that should produce compiler warnings with attached
// fix-its that can be applied to preserve the behavior of the code once
// the upcoming feature is enacted.
// These warnings must belong to a diagnostic group named after the
// feature. Adoption mode itself *and* the fix-its it produces must be
// feature. Migration mode itself *and* the fix-its it produces must be
// source and binary compatible with how the code is compiled when the
// feature is disabled.
#ifndef ADOPTABLE_UPCOMING_FEATURE
#ifndef MIGRATABLE_UPCOMING_FEATURE
#if defined(UPCOMING_FEATURE)
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
UPCOMING_FEATURE(FeatureName, SENumber, Version)
#else
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
LANGUAGE_FEATURE(FeatureName, SENumber, #FeatureName)
#endif
#endif

// See `ADOPTABLE_UPCOMING_FEATURE`.
#ifndef ADOPTABLE_EXPERIMENTAL_FEATURE
// See `MIGRATABLE_UPCOMING_FEATURE`.
#ifndef MIGRATABLE_EXPERIMENTAL_FEATURE
#if defined(EXPERIMENTAL_FEATURE)
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
#else
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
LANGUAGE_FEATURE(FeatureName, 0, #FeatureName)
#endif
#endif
Expand Down Expand Up @@ -276,11 +276,11 @@ UPCOMING_FEATURE(NonfrozenEnumExhaustivity, 192, 6)
UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6)

// Swift 7
ADOPTABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7)
MIGRATABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7)
UPCOMING_FEATURE(InternalImportsByDefault, 409, 7)
UPCOMING_FEATURE(MemberImportVisibility, 444, 7)
UPCOMING_FEATURE(InferIsolatedConformances, 470, 7)
ADOPTABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)
MIGRATABLE_UPCOMING_FEATURE(NonisolatedNonsendingByDefault, 461, 7)

// Optional language features / modes

Expand Down Expand Up @@ -520,8 +520,8 @@ SUPPRESSIBLE_EXPERIMENTAL_FEATURE(ExtensibleAttribute, false)
#undef EXPERIMENTAL_FEATURE_EXCLUDED_FROM_MODULE_INTERFACE
#undef EXPERIMENTAL_FEATURE
#undef UPCOMING_FEATURE
#undef ADOPTABLE_UPCOMING_FEATURE
#undef ADOPTABLE_EXPERIMENTAL_FEATURE
#undef MIGRATABLE_UPCOMING_FEATURE
#undef MIGRATABLE_EXPERIMENTAL_FEATURE
#undef BASELINE_LANGUAGE_FEATURE
#undef OPTIONAL_LANGUAGE_FEATURE
#undef CONDITIONALLY_SUPPRESSIBLE_EXPERIMENTAL_FEATURE
Expand Down
12 changes: 6 additions & 6 deletions include/swift/Basic/LangOptions.h
Original file line number Diff line number Diff line change
Expand Up @@ -830,7 +830,7 @@ namespace swift {

/// A wrapper around the feature state enumeration.
struct FeatureState {
enum class Kind : uint8_t { Off, EnabledForAdoption, Enabled };
enum class Kind : uint8_t { Off, EnabledForMigration, Enabled };

private:
Feature feature;
Expand All @@ -843,9 +843,9 @@ namespace swift {
/// Returns whether the feature is enabled.
bool isEnabled() const;

/// Returns whether the feature is enabled in adoption mode. Should only
/// Returns whether the feature is enabled in migration mode. Should only
/// be called if the feature is known to support this mode.
bool isEnabledForAdoption() const;
bool isEnabledForMigration() const;

operator Kind() const { return state; }
};
Expand Down Expand Up @@ -878,9 +878,9 @@ namespace swift {
/// `false` if a feature by this name is not known.
bool hasFeature(llvm::StringRef featureName) const;

/// Enables the given feature (enables in adoption mode if `forAdoption` is
/// `true`).
void enableFeature(Feature feature, bool forAdoption = false);
/// Enables the given feature (enables in migration mode if `forMigration`
/// is `true`).
void enableFeature(Feature feature, bool forMigration = false);

/// Disables the given feature.
void disableFeature(Feature feature);
Expand Down
10 changes: 5 additions & 5 deletions lib/Basic/Feature.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -69,18 +69,18 @@ std::optional<unsigned> Feature::getLanguageVersion() const {
}
}

bool Feature::isAdoptable() const {
bool Feature::isMigratable() const {
switch (kind) {
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version)
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd)
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description) \
case Feature::FeatureName:
#include "swift/Basic/Features.def"
return false;
#define LANGUAGE_FEATURE(FeatureName, SENumber, Description)
#define ADOPTABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
#define MIGRATABLE_UPCOMING_FEATURE(FeatureName, SENumber, Version) \
case Feature::FeatureName:
#define ADOPTABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
#define MIGRATABLE_EXPERIMENTAL_FEATURE(FeatureName, AvailableInProd) \
case Feature::FeatureName:
#include "swift/Basic/Features.def"
return true;
Expand Down
14 changes: 7 additions & 7 deletions lib/Basic/LangOptions.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -298,10 +298,10 @@ bool LangOptions::FeatureState::isEnabled() const {
return state == FeatureState::Kind::Enabled;
}

bool LangOptions::FeatureState::isEnabledForAdoption() const {
ASSERT(feature.isAdoptable() && "You forgot to make the feature adoptable!");
bool LangOptions::FeatureState::isEnabledForMigration() const {
ASSERT(feature.isMigratable() && "You forgot to make the feature migratable!");

return state == FeatureState::Kind::EnabledForAdoption;
return state == FeatureState::Kind::EnabledForMigration;
}

LangOptions::FeatureStateStorage::FeatureStateStorage()
Expand Down Expand Up @@ -357,10 +357,10 @@ bool LangOptions::hasFeature(llvm::StringRef featureName) const {
return false;
}

void LangOptions::enableFeature(Feature feature, bool forAdoption) {
if (forAdoption) {
ASSERT(feature.isAdoptable());
featureStates.setState(feature, FeatureState::Kind::EnabledForAdoption);
void LangOptions::enableFeature(Feature feature, bool forMigration) {
if (forMigration) {
ASSERT(feature.isMigratable());
featureStates.setState(feature, FeatureState::Kind::EnabledForMigration);
return;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Basic/SupportedFeatures.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -48,7 +48,7 @@ void printSupportedFeatures(llvm::raw_ostream &out) {
auto printFeature = [&out](const Feature &feature) {
out << " ";
out << "{ \"name\": \"" << feature.getName() << "\"";
if (feature.isAdoptable()) {
if (feature.isMigratable()) {
out << ", \"migratable\": true";
}
if (auto version = feature.getLanguageVersion()) {
Expand Down
14 changes: 7 additions & 7 deletions lib/Frontend/CompilerInvocation.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -816,7 +816,7 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,
continue;
}

// For all other features, the argument format is `<name>[:adoption]`.
// For all other features, the argument format is `<name>[:migrate]`.
StringRef featureName;
std::optional<StringRef> featureMode;
std::tie(featureName, featureMode) = argValue.rsplit(':');
Expand Down Expand Up @@ -872,21 +872,21 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,

if (featureMode) {
if (isEnableFeatureFlag) {
const auto isAdoptable = feature->isAdoptable();
const auto isMigratable = feature->isMigratable();

// Diagnose an invalid mode.
StringRef validModeName = "adoption";
StringRef validModeName = "migrate";
if (*featureMode != validModeName) {
Diags.diagnose(SourceLoc(), diag::invalid_feature_mode, *featureMode,
featureName,
/*didYouMean=*/validModeName,
/*showDidYouMean=*/isAdoptable);
/*showDidYouMean=*/isMigratable);
continue;
}

if (!isAdoptable) {
if (!isMigratable) {
Diags.diagnose(SourceLoc(),
diag::feature_does_not_support_adoption_mode,
diag::feature_does_not_support_migration_mode,
featureName);
continue;
}
Expand All @@ -904,7 +904,7 @@ static bool ParseEnabledFeatureArgs(LangOptions &Opts, ArgList &Args,

// Enable the feature if requested.
if (isEnableFeatureFlag)
Opts.enableFeature(*feature, /*forAdoption=*/featureMode.has_value());
Opts.enableFeature(*feature, /*forMigration=*/featureMode.has_value());
}

// Since pseudo-features don't have a boolean on/off state, process them in
Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/NonisolatedNonsendingByDefaultMigration.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -60,7 +60,7 @@ void NonisolatedNonsendingByDefaultMigrationTarget::diagnose() const {
const auto feature = Feature::NonisolatedNonsendingByDefault;

ASSERT(node);
ASSERT(ctx.LangOpts.getFeatureState(feature).isEnabledForAdoption());
ASSERT(ctx.LangOpts.getFeatureState(feature).isEnabledForMigration());

ValueDecl *decl = nullptr;
ClosureExpr *closure = nullptr;
Expand Down
4 changes: 2 additions & 2 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4752,7 +4752,7 @@ ActorIsolation ActorIsolationChecker::determineClosureIsolation(
isolation = isolation.withPreconcurrency(preconcurrency);

if (ctx.LangOpts.getFeatureState(Feature::NonisolatedNonsendingByDefault)
.isEnabledForAdoption()) {
.isEnabledForMigration()) {
warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, closure, isolation);
}

Expand Down Expand Up @@ -6260,7 +6260,7 @@ InferredActorIsolation ActorIsolationRequest::evaluate(Evaluator &evaluator,

auto &ctx = value->getASTContext();
if (ctx.LangOpts.getFeatureState(Feature::NonisolatedNonsendingByDefault)
.isEnabledForAdoption()) {
.isEnabledForMigration()) {
warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, value,
inferredIsolation.isolation);
}
Expand Down
8 changes: 4 additions & 4 deletions lib/Sema/TypeCheckType.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4246,7 +4246,7 @@ NeverNullType TypeResolver::resolveASTFunctionType(
isolation = FunctionTypeIsolation::forNonIsolated();
} else {
if (ctx.LangOpts.getFeatureState(Feature::NonisolatedNonsendingByDefault)
.isEnabledForAdoption()) {
.isEnabledForMigration()) {
// Diagnose only in the interface stage, which is run once.
if (inStage(TypeResolutionStage::Interface)) {
warnAboutNewNonisolatedAsyncExecutionBehavior(ctx, repr, isolation);
Expand Down Expand Up @@ -6572,7 +6572,7 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
// A missing `any` or `some` is always diagnosed if this feature not
// disabled.
auto featureState = ctx.LangOpts.getFeatureState(Feature::ExistentialAny);
if (featureState.isEnabled() || featureState.isEnabledForAdoption()) {
if (featureState.isEnabled() || featureState.isEnabledForMigration()) {
return true;
}

Expand Down Expand Up @@ -6665,10 +6665,10 @@ class ExistentialTypeSyntaxChecker : public ASTWalker {
/*isAlias=*/isa<TypeAliasDecl>(decl)));
}

// If `ExistentialAny` is enabled in adoption mode, warn unconditionally.
// If `ExistentialAny` is enabled in migration mode, warn unconditionally.
// Otherwise, warn until the feature's coming-of-age language mode.
const auto feature = Feature::ExistentialAny;
if (Ctx.LangOpts.getFeatureState(feature).isEnabledForAdoption()) {
if (Ctx.LangOpts.getFeatureState(feature).isEnabledForMigration()) {
diag->limitBehavior(DiagnosticBehavior::Warning);
} else {
diag->warnUntilSwiftVersion(feature.getLanguageVersion().value());
Expand Down
4 changes: 2 additions & 2 deletions test/Concurrency/attr_execution/adoption_mode.swift
Original file line number Diff line number Diff line change
@@ -1,5 +1,5 @@
// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 5 -enable-upcoming-feature NonisolatedNonsendingByDefault:adoption
// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault:adoption
// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 5 -enable-upcoming-feature NonisolatedNonsendingByDefault:migrate
// RUN: %target-typecheck-verify-swift -target %target-swift-5.1-abi-triple -swift-version 6 -enable-upcoming-feature NonisolatedNonsendingByDefault:migrate

// REQUIRES: swift_feature_NonisolatedNonsendingByDefault

Expand Down
32 changes: 16 additions & 16 deletions test/Frontend/features/adoption_mode.swift
Original file line number Diff line number Diff line change
Expand Up @@ -4,48 +4,48 @@
// RUN: %target-swift-frontend -parse -swift-version 5 \
// RUN: -enable-upcoming-feature DynamicActorIsolation:invalid1 \
// RUN: -enable-upcoming-feature DynamicActorIsolation:invalid2 \
// RUN: -enable-upcoming-feature DynamicActorIsolation:adoption \
// RUN: -enable-upcoming-feature DynamicActorIsolation:adoption \
// RUN: -enable-upcoming-feature DynamicActorIsolation:migrate \
// RUN: -enable-upcoming-feature DynamicActorIsolation:migrate \
// RUN: -enable-experimental-feature DynamicActorIsolation:invalid3 \
// RUN: -enable-experimental-feature DynamicActorIsolation:invalid4 \
// RUN: -enable-experimental-feature DynamicActorIsolation:adoption \
// RUN: -enable-experimental-feature DynamicActorIsolation:adoption \
// RUN: -enable-experimental-feature DynamicActorIsolation:migrate \
// RUN: -enable-experimental-feature DynamicActorIsolation:migrate \
// RUN: -disable-upcoming-feature DynamicActorIsolation:invalid5 \
// RUN: -disable-upcoming-feature DynamicActorIsolation:invalid6 \
// RUN: -disable-upcoming-feature DynamicActorIsolation:adoption \
// RUN: -disable-upcoming-feature DynamicActorIsolation:migrate \
// RUN: -disable-experimental-feature DynamicActorIsolation:invalid7 \
// RUN: -disable-experimental-feature DynamicActorIsolation:invalid8 \
// RUN: -disable-experimental-feature DynamicActorIsolation:adoption \
// RUN: -disable-experimental-feature DynamicActorIsolation:migrate \
// RUN: %s 2>&1 | %FileCheck %s --check-prefix=CHECK-SWIFT-5

// RUN: %target-swift-frontend -parse -swift-version 6 \
// RUN: -enable-upcoming-feature DynamicActorIsolation:invalid1 \
// RUN: -enable-upcoming-feature DynamicActorIsolation:adoption \
// RUN: -enable-upcoming-feature DynamicActorIsolation:migrate \
// RUN: -enable-experimental-feature DynamicActorIsolation:invalid2 \
// RUN: -enable-experimental-feature DynamicActorIsolation:adoption \
// RUN: -enable-experimental-feature DynamicActorIsolation:migrate \
// RUN: -disable-upcoming-feature DynamicActorIsolation:invalid3 \
// RUN: -disable-upcoming-feature DynamicActorIsolation:adoption \
// RUN: -disable-upcoming-feature DynamicActorIsolation:migrate \
// RUN: -disable-experimental-feature DynamicActorIsolation:invalid4 \
// RUN: -disable-experimental-feature DynamicActorIsolation:adoption \
// RUN: -disable-experimental-feature DynamicActorIsolation:migrate \
// RUN: %s 2>&1 | %FileCheck %s --check-prefix=CHECK-SWIFT-6

// REQUIRES: swift_feature_DynamicActorIsolation

// CHECK-NOT: error:

// CHECK-SWIFT-5-NOT: warning:
// CHECK-SWIFT-5: warning: '-disable-experimental-feature' argument 'DynamicActorIsolation:adoption' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5: warning: '-disable-experimental-feature' argument 'DynamicActorIsolation:migrate' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: '-disable-experimental-feature' argument 'DynamicActorIsolation:invalid8' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: '-disable-experimental-feature' argument 'DynamicActorIsolation:invalid7' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: '-disable-upcoming-feature' argument 'DynamicActorIsolation:adoption' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: '-disable-upcoming-feature' argument 'DynamicActorIsolation:migrate' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: '-disable-upcoming-feature' argument 'DynamicActorIsolation:invalid6' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: '-disable-upcoming-feature' argument 'DynamicActorIsolation:invalid5' cannot specify a mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support adoption mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support adoption mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support migration mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support migration mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: 'invalid4' is not a recognized mode for feature 'DynamicActorIsolation' [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: 'invalid3' is not a recognized mode for feature 'DynamicActorIsolation' [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support adoption mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support adoption mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support migration mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: feature 'DynamicActorIsolation' does not support migration mode [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: 'invalid2' is not a recognized mode for feature 'DynamicActorIsolation' [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NEXT: warning: 'invalid1' is not a recognized mode for feature 'DynamicActorIsolation' [#StrictLanguageFeatures]{{$}}
// CHECK-SWIFT-5-NOT: warning:
Expand Down
Loading