From 5e29333d6b1be74a8f90ac3ecc3a8c801453f675 Mon Sep 17 00:00:00 2001 From: Doug Gregor Date: Wed, 9 Apr 2025 16:06:14 -0700 Subject: [PATCH] [SE-0470] Enable isolated conformances by default The IsolatedConformances feature moves to a normal, supported feature. Remove all of the experimental-feature flags on test cases and such. The InferIsolatedConformances feature moves to an upcoming feature for Swift 7. This should become an adoptable feature, adding "nonisolated" where needed. (cherry picked from commit 3380331e7eb5ffb0b188d392ca533f7a24f0f1c2) --- CHANGELOG.md | 29 +++++++++++++++ include/swift/AST/DiagnosticsSema.def | 4 -- include/swift/Basic/Features.def | 5 +++ lib/AST/ConformanceLookup.cpp | 37 +++++++++---------- lib/Parse/ParseType.cpp | 4 +- lib/Sema/TypeCheckConcurrency.cpp | 7 +--- lib/Sema/TypeCheckProtocol.cpp | 10 +---- .../Runtime/isolated_conformance.swift | 3 +- test/Concurrency/isolated_conformance.swift | 3 +- .../isolated_conformance_default_actor.swift | 3 +- .../isolated_conformance_inference.swift | 4 +- test/Concurrency/sendable_metatype.swift | 3 +- .../sendable_metatype_typecheck.swift | 3 +- test/IRGen/isolated_conformance.swift | 3 +- .../isolated_conformance.swift | 3 +- .../constant_propagation_casts_ossa.sil | 3 +- test/SILOptimizer/isolated_conformances.swift | 6 +-- .../simplify_unconditional_check_cast.sil | 3 +- test/Serialization/isolated_conformance.swift | 5 +-- 19 files changed, 70 insertions(+), 68 deletions(-) diff --git a/CHANGELOG.md b/CHANGELOG.md index 3ee272369c8..05c0b540902 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -32,6 +32,34 @@ strategy, given that the code would eventually become ambiguous anyways when the deployment target is raised. +* [SE-0470][]: + A protocol conformance can be isolated to a specific global actor, meaning that the conformance can only be used by code running on that actor. Isolated conformances are expressed by specifying the global actor on the conformance itself: + + ```swift + protocol P { + func f() + } + + @MainActor + class MyType: @MainActor P { + /*@MainActor*/ func f() { + // must be called on the main actor + } + } + ``` + + Swift will produce diagnostics if the conformance is directly accessed in code that isn't guaranteed to execute in the same global actor. For example: + + ```swift + func acceptP(_ value: T) { } + + /*nonisolated*/ func useIsolatedConformance(myType: MyType) { + acceptP(myType) // error: main actor-isolated conformance of 'MyType' to 'P' cannot be used in nonisolated context + } + ``` + + To address such issues, only use an isolated conformance from code that executes on the same global actor. + * [SE-0419][]: Introduced the new `Runtime` module, which contains a public API that can generate backtraces, presently supported on macOS and Linux. Capturing a @@ -10759,6 +10787,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig [SE-0442]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0442-allow-taskgroup-childtaskresult-type-to-be-inferred.md [SE-0444]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0444-member-import-visibility.md [SE-0458]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0458-strict-memory-safety.md +[SE-0470]: https://github.com/swiftlang/swift-evolution/blob/main/proposals/0470-isolated-conformances.md [#64927]: [#42697]: [#42728]: diff --git a/include/swift/AST/DiagnosticsSema.def b/include/swift/AST/DiagnosticsSema.def index 12c44ff07a0..062b5bf76f1 100644 --- a/include/swift/AST/DiagnosticsSema.def +++ b/include/swift/AST/DiagnosticsSema.def @@ -8486,10 +8486,6 @@ ERROR(attr_abi_failable_mismatch,none, //===----------------------------------------------------------------------===// // MARK: Isolated conformances //===----------------------------------------------------------------------===// -GROUPED_ERROR(isolated_conformance_experimental_feature,IsolatedConformances, - none, - "isolated conformances require experimental feature " - " 'IsolatedConformances'", ()) NOTE(note_isolate_conformance_to_global_actor,none, "isolate this conformance to the %select{global actor %0|main actor}1 " "with '@%2'", (Type, bool, StringRef)) diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 21e3af02aeb..b3c01fcf0eb 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -254,6 +254,7 @@ SUPPRESSIBLE_LANGUAGE_FEATURE(MemorySafetyAttributes, 458, "@unsafe attribute") LANGUAGE_FEATURE(ValueGenerics, 452, "Value generics feature (integer generics)") LANGUAGE_FEATURE(RawIdentifiers, 451, "Raw identifiers") LANGUAGE_FEATURE(SendableCompletionHandlers, 463, "Objective-C completion handler parameters are imported as @Sendable") +LANGUAGE_FEATURE(IsolatedConformances, 407, "Global-actor isolated conformances") // Swift 6 UPCOMING_FEATURE(ConciseMagicFile, 274, 6) @@ -276,6 +277,7 @@ UPCOMING_FEATURE(GlobalActorIsolatedTypesUsability, 0434, 6) ADOPTABLE_UPCOMING_FEATURE(ExistentialAny, 335, 7) UPCOMING_FEATURE(InternalImportsByDefault, 409, 7) UPCOMING_FEATURE(MemberImportVisibility, 444, 7) +UPCOMING_FEATURE(InferIsolatedConformances, 470, 7) // Optional language features / modes @@ -495,6 +497,7 @@ ADOPTABLE_EXPERIMENTAL_FEATURE(AsyncCallerExecution, false) /// Allow custom availability domains to be defined and referenced. EXPERIMENTAL_FEATURE(CustomAvailability, true) +<<<<<<< HEAD /// Allow public enumerations to be extensible by default /// regardless of whether the module they are declared in /// is resilient or not. @@ -506,6 +509,8 @@ EXPERIMENTAL_FEATURE(IsolatedConformances, true) /// Infer conformance isolation on global-actor-conforming types. EXPERIMENTAL_FEATURE(InferIsolatedConformances, true) +======= +>>>>>>> 3380331e7eb ([SE-0470] Enable isolated conformances by default) /// Allow SwiftSettings EXPERIMENTAL_FEATURE(SwiftSettings, false) diff --git a/lib/AST/ConformanceLookup.cpp b/lib/AST/ConformanceLookup.cpp index dc02e369d7d..93d78317219 100644 --- a/lib/AST/ConformanceLookup.cpp +++ b/lib/AST/ConformanceLookup.cpp @@ -386,33 +386,30 @@ static ProtocolConformanceRef getBuiltinMetaTypeTypeConformance( // All metatypes are Copyable, Escapable, and BitwiseCopyable. if (auto kp = protocol->getKnownProtocolKind()) { switch (*kp) { - case KnownProtocolKind::Sendable: + case KnownProtocolKind::Sendable: { // Metatypes are generally Sendable, but with isolated conformances we // cannot assume that metatypes based on type parameters are Sendable. // Therefore, check for conformance to SendableMetatype. - if (ctx.LangOpts.hasFeature(Feature::IsolatedConformances)) { - auto sendableMetatypeProto = - ctx.getProtocol(KnownProtocolKind::SendableMetatype); - if (sendableMetatypeProto) { - Type instanceType = metatypeType->getInstanceType(); + auto sendableMetatypeProto = + ctx.getProtocol(KnownProtocolKind::SendableMetatype); + if (sendableMetatypeProto) { + Type instanceType = metatypeType->getInstanceType(); - // If the instance type is a type parameter, it is not necessarily - // Sendable. There will need to be a Sendable requirement. - if (instanceType->isTypeParameter()) - break; + // If the instance type is a type parameter, it is not necessarily + // Sendable. There will need to be a Sendable requirement. + if (instanceType->isTypeParameter()) + break; - // If the instance type conforms to SendableMetatype, then its - // metatype is Sendable. - auto instanceConformance = lookupConformance( - instanceType, sendableMetatypeProto); - if (instanceConformance.isInvalid() || - instanceConformance.hasMissingConformance()) - break; - } - - // Every other metatype is Sendable. + // If the instance type conforms to SendableMetatype, then its + // metatype is Sendable. + auto instanceConformance = lookupConformance( + instanceType, sendableMetatypeProto); + if (instanceConformance.isInvalid() || + instanceConformance.hasMissingConformance()) + break; } LLVM_FALLTHROUGH; + } case KnownProtocolKind::Copyable: case KnownProtocolKind::Escapable: diff --git a/lib/Parse/ParseType.cpp b/lib/Parse/ParseType.cpp index 414b6056bac..5ac469fe59c 100644 --- a/lib/Parse/ParseType.cpp +++ b/lib/Parse/ParseType.cpp @@ -163,9 +163,7 @@ ParserResult Parser::parseTypeSimple( Diag<> MessageID, ParseTypeReason reason) { ParserResult ty; - if (isParameterSpecifier() && - !(!Context.LangOpts.hasFeature(Feature::IsolatedConformances) && - Tok.isContextualKeyword("isolated"))) { + if (isParameterSpecifier()) { // Type specifier should already be parsed before here. This only happens // for construct like 'P1 & inout P2'. diagnose(Tok.getLoc(), diag::attr_only_on_parameters, Tok.getRawText()); diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 640911ae563..fc32dad4122 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -3021,10 +3021,9 @@ namespace { // FIXME: When passing to a sending parameter, should this be handled // by region isolation? Or should it always be handled by region // isolation? - if (ctx.LangOpts.hasFeature(Feature::IsolatedConformances) && - (mayExecuteConcurrentlyWith( + if (mayExecuteConcurrentlyWith( localFunc.getAsDeclContext(), getDeclContext()) || - (explicitClosure && explicitClosure->isPassedToSendingParameter()))) { + (explicitClosure && explicitClosure->isPassedToSendingParameter())) { GenericSignature genericSig; if (auto afd = localFunc.getAbstractFunctionDecl()) genericSig = afd->getGenericSignature(); @@ -7931,8 +7930,6 @@ ConformanceIsolationRequest::evaluate(Evaluator &evaluator, ProtocolConformance auto dc = rootNormal->getDeclContext(); ASTContext &ctx = dc->getASTContext(); - if (!ctx.LangOpts.hasFeature(Feature::IsolatedConformances)) - return ActorIsolation::forNonisolated(false); // If the protocol itself is isolated, don't infer isolation for the // conformance. diff --git a/lib/Sema/TypeCheckProtocol.cpp b/lib/Sema/TypeCheckProtocol.cpp index 13abba03c1d..d12803a8554 100644 --- a/lib/Sema/TypeCheckProtocol.cpp +++ b/lib/Sema/TypeCheckProtocol.cpp @@ -2567,13 +2567,6 @@ checkIndividualConformance(NormalProtocolConformance *conformance) { ComplainLoc, diag::unchecked_conformance_not_special, ProtoType); } - // Complain if the global-actor-isolated conformances are not enabled. - if (conformance->isIsolated() && - !Context.LangOpts.hasFeature(Feature::IsolatedConformances)) { - Context.Diags.diagnose( - ComplainLoc, diag::isolated_conformance_experimental_feature); - } - bool allowImpliedConditionalConformance = false; if (Proto->isSpecificProtocol(KnownProtocolKind::Sendable)) { // In -swift-version 5 mode, a conditional conformance to a protocol can imply @@ -4978,8 +4971,7 @@ static void diagnoseConformanceIsolationErrors( } // Suggest isolating the conformance, if possible. - if (ctx.LangOpts.hasFeature(Feature::IsolatedConformances) && - potentialIsolation && potentialIsolation->isGlobalActor() && + if (potentialIsolation && potentialIsolation->isGlobalActor() && !conformance->isIsolated()) { bool isMainActor = false; Type globalActorIsolation = potentialIsolation->getGlobalActor(); diff --git a/test/Concurrency/Runtime/isolated_conformance.swift b/test/Concurrency/Runtime/isolated_conformance.swift index ca3a3534404..bc795e22e59 100644 --- a/test/Concurrency/Runtime/isolated_conformance.swift +++ b/test/Concurrency/Runtime/isolated_conformance.swift @@ -1,9 +1,8 @@ -// RUN: %target-run-simple-swift(-enable-experimental-feature IsolatedConformances -target %target-swift-5.1-abi-triple) | %FileCheck %s +// RUN: %target-run-simple-swift(-target %target-swift-5.1-abi-triple) | %FileCheck %s // REQUIRES: executable_test // REQUIRES: concurrency // REQUIRES: concurrency_runtime -// REQUIRES: swift_feature_IsolatedConformances // UNSUPPORTED: back_deployment_runtime // FIXME: WebAssembly doesn't currently have a good way to install the diff --git a/test/Concurrency/isolated_conformance.swift b/test/Concurrency/isolated_conformance.swift index dd6416ec171..92343133eaa 100644 --- a/test/Concurrency/isolated_conformance.swift +++ b/test/Concurrency/isolated_conformance.swift @@ -1,6 +1,5 @@ -// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete -enable-experimental-feature IsolatedConformances %s +// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 5 -strict-concurrency=complete %s -// REQUIRES: swift_feature_IsolatedConformances // REQUIRES: concurrency protocol P { diff --git a/test/Concurrency/isolated_conformance_default_actor.swift b/test/Concurrency/isolated_conformance_default_actor.swift index 3b302234207..ce8cce07ecc 100644 --- a/test/Concurrency/isolated_conformance_default_actor.swift +++ b/test/Concurrency/isolated_conformance_default_actor.swift @@ -1,6 +1,5 @@ -// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances -default-isolation MainActor %s +// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -default-isolation MainActor %s -// REQUIRES: swift_feature_IsolatedConformances // REQUIRES: concurrency nonisolated diff --git a/test/Concurrency/isolated_conformance_inference.swift b/test/Concurrency/isolated_conformance_inference.swift index ed0bc91ac2a..e513f3f8a77 100644 --- a/test/Concurrency/isolated_conformance_inference.swift +++ b/test/Concurrency/isolated_conformance_inference.swift @@ -1,7 +1,5 @@ -// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances -enable-experimental-feature InferIsolatedConformances %s +// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-upcoming-feature InferIsolatedConformances %s -// REQUIRES: swift_feature_IsolatedConformances -// REQUIRES: swift_feature_InferIsolatedConformances // REQUIRES: concurrency protocol P { diff --git a/test/Concurrency/sendable_metatype.swift b/test/Concurrency/sendable_metatype.swift index a21366ac6f0..1371456d97e 100644 --- a/test/Concurrency/sendable_metatype.swift +++ b/test/Concurrency/sendable_metatype.swift @@ -1,7 +1,6 @@ -// RUN: %target-typecheck-verify-swift -swift-version 6 -enable-experimental-feature IsolatedConformances -emit-sil -o /dev/null +// RUN: %target-typecheck-verify-swift -swift-version 6 -emit-sil -o /dev/null // REQUIRES: concurrency -// REQUIRES: swift_feature_IsolatedConformances protocol Q { diff --git a/test/Concurrency/sendable_metatype_typecheck.swift b/test/Concurrency/sendable_metatype_typecheck.swift index 6ba6def4956..494ab2b8c9c 100644 --- a/test/Concurrency/sendable_metatype_typecheck.swift +++ b/test/Concurrency/sendable_metatype_typecheck.swift @@ -1,7 +1,6 @@ -// RUN: %target-typecheck-verify-swift -swift-version 6 -enable-experimental-feature IsolatedConformances +// RUN: %target-typecheck-verify-swift -swift-version 6 // REQUIRES: concurrency -// REQUIRES: swift_feature_IsolatedConformances // This test checks for typecheck-only diagnostics involving non-sendable // metatypes. diff --git a/test/IRGen/isolated_conformance.swift b/test/IRGen/isolated_conformance.swift index 6240933188e..6900cf90573 100644 --- a/test/IRGen/isolated_conformance.swift +++ b/test/IRGen/isolated_conformance.swift @@ -1,8 +1,7 @@ -// RUN: %target-swift-frontend -primary-file %s -emit-ir -swift-version 6 -enable-experimental-feature IsolatedConformances | %FileCheck %s -DINT=i%target-ptrsize +// RUN: %target-swift-frontend -primary-file %s -emit-ir -swift-version 6 | %FileCheck %s -DINT=i%target-ptrsize // REQUIRES: PTRSIZE=64 // REQUIRES: concurrency -// REQUIRES: swift_feature_IsolatedConformances // UNSUPPORTED: CPU=arm64e protocol P { diff --git a/test/ModuleInterface/isolated_conformance.swift b/test/ModuleInterface/isolated_conformance.swift index 23d93fcdd45..9ed21b8b67e 100644 --- a/test/ModuleInterface/isolated_conformance.swift +++ b/test/ModuleInterface/isolated_conformance.swift @@ -1,6 +1,5 @@ -// RUN: %target-swift-frontend -typecheck -swift-version 6 -enable-library-evolution -module-name isolated_conformance -enable-experimental-feature IsolatedConformances -emit-module-interface-path - %s | %FileCheck %s +// RUN: %target-swift-frontend -typecheck -swift-version 6 -enable-library-evolution -module-name isolated_conformance -emit-module-interface-path - %s | %FileCheck %s -// REQUIRES: swift_feature_IsolatedConformances // REQUIRES: concurrency public protocol MyProtocol { diff --git a/test/SILOptimizer/constant_propagation_casts_ossa.sil b/test/SILOptimizer/constant_propagation_casts_ossa.sil index c2ce3a3cfc8..875d0c9c7ab 100644 --- a/test/SILOptimizer/constant_propagation_casts_ossa.sil +++ b/test/SILOptimizer/constant_propagation_casts_ossa.sil @@ -1,6 +1,5 @@ -// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnostic-constant-propagation -enable-experimental-feature IsolatedConformances | %FileCheck %s +// RUN: %target-sil-opt -enable-sil-verify-all %s -diagnostic-constant-propagation | %FileCheck %s -// REQUIRES: swift_feature_IsolatedConformances // REQUIRES: concurrency sil_stage canonical diff --git a/test/SILOptimizer/isolated_conformances.swift b/test/SILOptimizer/isolated_conformances.swift index f51da74545c..2c5e66d0942 100644 --- a/test/SILOptimizer/isolated_conformances.swift +++ b/test/SILOptimizer/isolated_conformances.swift @@ -1,14 +1,14 @@ // RUN: %empty-directory(%t) -// RUN: %target-build-swift -parse-as-library -O %s -enable-experimental-feature IsolatedConformances -o %t/a.out +// RUN: %target-build-swift -parse-as-library -O %s -o %t/a.out // RUN: %target-codesign %t/a.out // RUN: %target-run %t/a.out | %FileCheck %s --check-prefix=CHECK-OUTPUT -// RUN: %target-build-swift -parse-as-library -O %s -enable-experimental-feature IsolatedConformances -Xllvm -sil-disable-pass=function-signature-opts -emit-sil | %FileCheck %s +// RUN: %target-build-swift -parse-as-library -O %s -Xllvm -sil-disable-pass=function-signature-opts -emit-sil | %FileCheck %s // REQUIRES: concurrency // REQUIRES: executable_test // REQUIRES: concurrency_runtime -// REQUIRES: swift_feature_IsolatedConformances +// REQUIRES: OS=macosx || OS=linux-gnu // UNSUPPORTED: back_deployment_runtime // UNSUPPORTED: back_deploy_concurrency diff --git a/test/SILOptimizer/simplify_unconditional_check_cast.sil b/test/SILOptimizer/simplify_unconditional_check_cast.sil index 21134ec91a0..1b667b2e60d 100644 --- a/test/SILOptimizer/simplify_unconditional_check_cast.sil +++ b/test/SILOptimizer/simplify_unconditional_check_cast.sil @@ -1,6 +1,5 @@ -// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=unconditional_checked_cast -enable-experimental-feature IsolatedConformances | %FileCheck %s +// RUN: %target-sil-opt -enable-sil-verify-all %s -simplification -simplify-instruction=unconditional_checked_cast | %FileCheck %s -// REQUIRES: swift_feature_IsolatedConformances // REQUIRES: concurrency import Swift diff --git a/test/Serialization/isolated_conformance.swift b/test/Serialization/isolated_conformance.swift index beeb48aa106..064bdf03345 100644 --- a/test/Serialization/isolated_conformance.swift +++ b/test/Serialization/isolated_conformance.swift @@ -1,9 +1,8 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances -o %t/def_isolated_conformance.swiftmodule %S/Inputs/def_isolated_conformance.swift +// RUN: %target-swift-frontend -emit-module -target %target-swift-5.1-abi-triple -swift-version 6 -o %t/def_isolated_conformance.swiftmodule %S/Inputs/def_isolated_conformance.swift -// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 -enable-experimental-feature IsolatedConformances %s -I %t +// RUN: %target-swift-frontend -typecheck -verify -target %target-swift-5.1-abi-triple -swift-version 6 %s -I %t -// REQUIRES: swift_feature_IsolatedConformances // REQUIRES: concurrency import def_isolated_conformance