diff --git a/CHANGELOG.md b/CHANGELOG.md index eb763ecd68ba6..d9a47e70ac52f 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -5,6 +5,28 @@ ## Swift 5.11 +* [SE-0411][]: + + Default value expressions can now have the same isolation as the enclosing + function or the corresponding stored property: + + ```swift + @MainActor + func requiresMainActor() -> Int { ... } + + class C { + @MainActor + var x: Int = requiresMainActor() + } + + @MainActor func defaultArg(value: Int = requiresMainActor()) { ... } + ``` + + For isolated default values of stored properties, the implicit initialization + only happens in the body of an `init` with the same isolation. This closes + an important data-race safety hole where global-actor-isolated default values + could inadvertently run synchronously from outside the actor. + * [SE-0413][]: Functions can now specify the type of error that they throw as part of the @@ -9904,6 +9926,7 @@ using the `.dynamicType` member to retrieve the type of an expression should mig [SE-0394]: https://github.com/apple/swift-evolution/blob/main/proposals/0394-swiftpm-expression-macros.md [SE-0397]: https://github.com/apple/swift-evolution/blob/main/proposals/0397-freestanding-declaration-macros.md [SE-0407]: https://github.com/apple/swift-evolution/blob/main/proposals/0407-member-macro-conformances.md +[SE-0411]: https://github.com/apple/swift-evolution/blob/main/proposals/0411-isolated-default-values.md [SE-0413]: https://github.com/apple/swift-evolution/blob/main/proposals/0413-typed-throws.md [#64927]: [#42697]: diff --git a/include/swift/Basic/Features.def b/include/swift/Basic/Features.def index 47bdbdd71bfff..a380f10b4eba4 100644 --- a/include/swift/Basic/Features.def +++ b/include/swift/Basic/Features.def @@ -120,6 +120,7 @@ UPCOMING_FEATURE(DeprecateApplicationMain, 383, 6) UPCOMING_FEATURE(ImportObjcForwardDeclarations, 384, 6) UPCOMING_FEATURE(DisableOutwardActorInference, 401, 6) UPCOMING_FEATURE(InternalImportsByDefault, 409, 6) +UPCOMING_FEATURE(IsolatedDefaultValues, 411, 6) UPCOMING_FEATURE(GlobalConcurrency, 412, 6) UPCOMING_FEATURE(FullTypedThrows, 413, 6) @@ -218,9 +219,6 @@ EXPERIMENTAL_FEATURE(StrictConcurrency, true) /// Region Based Isolation testing using the TransferNonSendable pass EXPERIMENTAL_FEATURE(RegionBasedIsolation, false) -/// Allow default values to require isolation at the call-site. -EXPERIMENTAL_FEATURE(IsolatedDefaultValues, false) - /// Enable extended callbacks (with additional parameters) to be used when the /// "playground transform" is enabled. EXPERIMENTAL_FEATURE(PlaygroundExtendedCallbacks, true) diff --git a/lib/Frontend/CompilerInvocation.cpp b/lib/Frontend/CompilerInvocation.cpp index 4696311f4bd1a..a998b3850fc34 100644 --- a/lib/Frontend/CompilerInvocation.cpp +++ b/lib/Frontend/CompilerInvocation.cpp @@ -880,6 +880,7 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, if (Opts.hasFeature(Feature::CompleteConcurrency)) { Opts.StrictConcurrencyLevel = StrictConcurrency::Complete; Opts.enableFeature(Feature::DisableOutwardActorInference); + Opts.enableFeature(Feature::IsolatedDefaultValues); Opts.enableFeature(Feature::GlobalConcurrency); } @@ -1019,6 +1020,11 @@ static bool ParseLangArgs(LangOptions &Opts, ArgList &Args, Opts.StrictConcurrencyLevel = StrictConcurrency::Minimal; } + // StrictConcurrency::Complete enables all data-race safety features. + if (Opts.StrictConcurrencyLevel == StrictConcurrency::Complete) { + Opts.enableFeature(Feature::IsolatedDefaultValues); + } + Opts.WarnImplicitOverrides = Args.hasArg(OPT_warn_implicit_overrides); diff --git a/lib/SILGen/SILGenApply.cpp b/lib/SILGen/SILGenApply.cpp index a07ff4d39d3c5..b44ef977513d1 100644 --- a/lib/SILGen/SILGenApply.cpp +++ b/lib/SILGen/SILGenApply.cpp @@ -2718,6 +2718,28 @@ class DelayedArgument { return LV().Loc; } + bool isDefaultArg() const { + return Kind == DefaultArgument; + } + + SILLocation getDefaultArgLoc() const { + assert(isDefaultArg()); + auto storage = Value.get(Kind); + return storage.loc; + } + + llvm::Optional getIsolation() const { + if (!isDefaultArg()) + return llvm::None; + + auto storage = Value.get(Kind); + if (!storage.implicitlyAsync) + return llvm::None; + + auto callee = storage.defaultArgsOwner.getDecl(); + return getActorIsolation(callee); + } + void emit(SILGenFunction &SGF, SmallVectorImpl &args, size_t &argIndex) { switch (Kind) { @@ -2943,6 +2965,31 @@ static void emitDelayedArguments(SILGenFunction &SGF, MutableArrayRef> args) { assert(!delayedArgs.empty()); + // If any of the delayed arguments are isolated default arguments, + // argument evaluation happens in the following order: + // + // 1. Left-to-right evalution of explicit r-value arguments + // 2. Left-to-right evaluation of formal access arguments + // 3. Hop to the callee's isolation domain + // 4. Left-to-right evaluation of default arguments + + // So, if any delayed arguments are isolated, all default arguments + // are collected during the first pass over the delayed arguments, + // and emitted separately after a hop to the callee's isolation domain. + + llvm::Optional defaultArgIsolation; + for (auto &arg : delayedArgs) { + if (auto isolation = arg.getIsolation()) { + defaultArgIsolation = isolation; + break; + } + } + + SmallVector, 2> isolatedArgs; + SmallVector, 4> emittedInoutArgs; auto delayedNext = delayedArgs.begin(); @@ -2951,7 +2998,8 @@ static void emitDelayedArguments(SILGenFunction &SGF, // wherever there's a delayed argument to insert. // // Note that this also begins the formal accesses in evaluation order. - for (auto &siteArgs : args) { + for (auto argsIt = args.begin(); argsIt != args.end(); ++argsIt) { + auto &siteArgs = *argsIt; // NB: siteArgs.size() may change during iteration for (size_t i = 0; i < siteArgs.size(); ) { auto &siteArg = siteArgs[i]; @@ -2964,6 +3012,15 @@ static void emitDelayedArguments(SILGenFunction &SGF, assert(delayedNext != delayedArgs.end()); auto &delayedArg = *delayedNext; + if (defaultArgIsolation && delayedArg.isDefaultArg()) { + isolatedArgs.push_back(std::make_tuple(delayedNext, argsIt, i)); + if (++delayedNext == delayedArgs.end()) { + goto done; + } else { + continue; + } + } + // Emit the delayed argument and replace it in the arguments array. delayedArg.emit(SGF, siteArgs, i); @@ -2984,6 +3041,45 @@ static void emitDelayedArguments(SILGenFunction &SGF, done: + if (defaultArgIsolation) { + assert(SGF.F.isAsync()); + assert(!isolatedArgs.empty()); + + auto &firstArg = *std::get<0>(isolatedArgs[0]); + auto loc = firstArg.getDefaultArgLoc(); + + SILValue executor; + switch (*defaultArgIsolation) { + case ActorIsolation::GlobalActor: + case ActorIsolation::GlobalActorUnsafe: + executor = SGF.emitLoadGlobalActorExecutor( + defaultArgIsolation->getGlobalActor()); + break; + + case ActorIsolation::ActorInstance: + llvm_unreachable("default arg cannot be actor instance isolated"); + + case ActorIsolation::Unspecified: + case ActorIsolation::Nonisolated: + case ActorIsolation::NonisolatedUnsafe: + llvm_unreachable("Not isolated"); + } + + // Hop to the target isolation domain once to evaluate all + // default arguments. + SGF.emitHopToTargetExecutor(loc, executor); + + size_t argsEmitted = 0; + for (auto &isolatedArg : isolatedArgs) { + auto &delayedArg = *std::get<0>(isolatedArg); + auto &siteArgs = *std::get<1>(isolatedArg); + auto argIndex = std::get<2>(isolatedArg) + argsEmitted; + auto origIndex = argIndex; + delayedArg.emit(SGF, siteArgs, argIndex); + argsEmitted += (argIndex - origIndex); + } + } + // Check to see if we have multiple inout arguments which obviously // alias. Note that we could do this in a later SILDiagnostics pass // as well: this would be stronger (more equivalences exposed) but diff --git a/lib/SILGen/SILGenExpr.cpp b/lib/SILGen/SILGenExpr.cpp index 4f4cba0aa4c4c..b5f34dbfdb0f1 100644 --- a/lib/SILGen/SILGenExpr.cpp +++ b/lib/SILGen/SILGenExpr.cpp @@ -2647,24 +2647,8 @@ SILGenFunction::emitApplyOfDefaultArgGenerator(SILLocation loc, emitCaptures(loc, generator, CaptureEmission::ImmediateApplication, captures); - // The default argument might require the callee's isolation. If so, - // make sure to emit an actor hop. - // - // FIXME: Instead of hopping back and forth for each individual isolated - // default argument, we should emit one hop for all default arguments if - // any of them are isolated, and immediately enter the function after. - llvm::Optional implicitActorHopTarget = llvm::None; - if (implicitlyAsync) { - auto *param = getParameterAt(defaultArgsOwner.getDecl(), destIndex); - auto isolation = param->getInitializerIsolation(); - if (isolation.isActorIsolated()) { - implicitActorHopTarget = isolation; - } - } - return emitApply(std::move(resultPtr), std::move(argScope), loc, fnRef, subs, - captures, calleeTypeInfo, ApplyOptions(), C, - implicitActorHopTarget); + captures, calleeTypeInfo, ApplyOptions(), C, llvm::None); } RValue SILGenFunction::emitApplyOfStoredPropertyInitializer( diff --git a/lib/Sema/CodeSynthesis.cpp b/lib/Sema/CodeSynthesis.cpp index c02ad3bdf95e4..a4d2d17cf0462 100644 --- a/lib/Sema/CodeSynthesis.cpp +++ b/lib/Sema/CodeSynthesis.cpp @@ -337,7 +337,8 @@ static ConstructorDecl *createImplicitConstructor(NominalTypeDecl *decl, ctor->setSynthesized(); ctor->setAccess(accessLevel); - if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues)) { + if (ctx.LangOpts.hasFeature(Feature::IsolatedDefaultValues) && + !decl->isActor()) { // If any of the type's actor-isolated properties: // 1. Have non-Sendable type, or // 2. Have an isolated initial value diff --git a/test/Concurrency/actor_isolation.swift b/test/Concurrency/actor_isolation.swift index d7908cb22a69b..3d6a7dd3423ff 100644 --- a/test/Concurrency/actor_isolation.swift +++ b/test/Concurrency/actor_isolation.swift @@ -765,7 +765,6 @@ actor LocalFunctionIsolatedActor { @available(SwiftStdlib 5.1, *) actor LazyActor { var v: Int = 0 - // expected-note@-1 6 {{property declared here}} let l: Int = 0 @@ -773,7 +772,7 @@ actor LazyActor { lazy var l12: Int = v lazy var l13: Int = { self.v }() lazy var l14: Int = self.v - lazy var l15: Int = { [unowned self] in self.v }() // expected-error{{actor-isolated property 'v' can not be referenced from a non-isolated context}} + lazy var l15: Int = { [unowned self] in self.v }() lazy var l21: Int = { l }() lazy var l22: Int = l @@ -782,15 +781,15 @@ actor LazyActor { lazy var l25: Int = { [unowned self] in self.l }() nonisolated lazy var l31: Int = { v }() - // expected-error@-1 {{actor-isolated property 'v' can not be referenced from a non-isolated context}} + // expected-error@-1 {{actor-isolated default value in a nonisolated context}} nonisolated lazy var l32: Int = v - // expected-error@-1 {{actor-isolated property 'v' can not be referenced from a non-isolated context}} + // expected-error@-1 {{actor-isolated default value in a nonisolated context}} nonisolated lazy var l33: Int = { self.v }() - // expected-error@-1 {{actor-isolated property 'v' can not be referenced from a non-isolated context}} + // expected-error@-1 {{actor-isolated default value in a nonisolated context}} nonisolated lazy var l34: Int = self.v - // expected-error@-1 {{actor-isolated property 'v' can not be referenced from a non-isolated context}} + // expected-error@-1 {{actor-isolated default value in a nonisolated context}} nonisolated lazy var l35: Int = { [unowned self] in self.v }() - // expected-error@-1 {{actor-isolated property 'v' can not be referenced from a non-isolated context}} + // expected-error@-1 {{actor-isolated default value in a nonisolated context}} nonisolated lazy var l41: Int = { l }() nonisolated lazy var l42: Int = l diff --git a/test/Concurrency/global_actor_inference.swift b/test/Concurrency/global_actor_inference.swift index 398dba292d6eb..95cce1651109c 100644 --- a/test/Concurrency/global_actor_inference.swift +++ b/test/Concurrency/global_actor_inference.swift @@ -1,8 +1,8 @@ // RUN: %empty-directory(%t) // RUN: %target-swift-frontend -emit-module -emit-module-path %t/other_global_actor_inference.swiftmodule -module-name other_global_actor_inference -strict-concurrency=complete %S/Inputs/other_global_actor_inference.swift -// RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -// RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted +// RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -verify-additional-prefix minimal-targeted- +// RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted -verify-additional-prefix minimal-targeted- // RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix complete-tns- // RUN: %target-swift-frontend -I %t -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-experimental-feature RegionBasedIsolation -verify-additional-prefix complete-tns- @@ -437,13 +437,15 @@ actor WrapperActorBad2 { struct WrapperWithMainActorDefaultInit { var wrappedValue: Int { fatalError() } - @MainActor init() {} // expected-note 2 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + @MainActor init() {} // expected-note {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + // expected-minimal-targeted-note@-1 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} } actor ActorWithWrapper { @WrapperOnActor var synced: Int = 0 // expected-note@-1 3{{property declared here}} - @WrapperWithMainActorDefaultInit var property: Int // expected-error {{call to main actor-isolated initializer 'init()' in a synchronous actor-isolated context}} + @WrapperWithMainActorDefaultInit var property: Int // expected-minimal-targeted-error {{call to main actor-isolated initializer 'init()' in a synchronous actor-isolated context}} + // expected-complete-tns-error@-1 {{main actor-isolated default value in a actor-isolated context}} func f() { _ = synced // expected-error{{main actor-isolated property 'synced' can not be referenced on a different actor instance}} _ = $synced // expected-error{{global actor 'SomeGlobalActor'-isolated property '$synced' can not be referenced on a different actor instance}} @@ -557,8 +559,9 @@ struct WrapperOnUnsafeActor { } } +// HasWrapperOnUnsafeActor gets an inferred @MainActor attribute. struct HasWrapperOnUnsafeActor { - @WrapperOnUnsafeActor var synced: Int = 0 + @WrapperOnUnsafeActor var synced: Int = 0 // expected-complete-tns-error {{global actor 'OtherGlobalActor'-isolated default value in a main actor-isolated context}} // expected-note @-1 3{{property declared here}} // expected-complete-tns-note @-2 3{{property declared here}} @@ -643,11 +646,11 @@ func acceptAsyncSendableClosureInheriting(@_inheritActorContext _: @Sendable // defer bodies inherit global actor-ness @MainActor -var statefulThingy: Bool = false // expected-note {{var declared here}} +var statefulThingy: Bool = false // expected-minimal-targeted-note {{var declared here}} // expected-complete-tns-error @-1 {{top-level code variables cannot have a global actor}} @MainActor -func useFooInADefer() -> String { // expected-note {{calls to global function 'useFooInADefer()' from outside of its actor context are implicitly asynchronous}} +func useFooInADefer() -> String { // expected-minimal-targeted-note {{calls to global function 'useFooInADefer()' from outside of its actor context are implicitly asynchronous}} defer { statefulThingy = true } @@ -677,9 +680,11 @@ class Cutter { @SomeGlobalActor class Butter { - var a = useFooInADefer() // expected-error {{call to main actor-isolated global function 'useFooInADefer()' in a synchronous global actor 'SomeGlobalActor'-isolated context}} + var a = useFooInADefer() // expected-minimal-targeted-error {{call to main actor-isolated global function 'useFooInADefer()' in a synchronous global actor 'SomeGlobalActor'-isolated context}} + // expected-complete-tns-error@-1 {{main actor-isolated default value in a global actor 'SomeGlobalActor'-isolated context}} - nonisolated let b = statefulThingy // expected-error {{main actor-isolated var 'statefulThingy' can not be referenced from a non-isolated context}} + nonisolated let b = statefulThingy // expected-minimal-targeted-error {{main actor-isolated var 'statefulThingy' can not be referenced from a non-isolated context}} + // expected-complete-tns-error@-1 {{main actor-isolated default value in a nonisolated context}} var c: Int = { return getGlobal7() diff --git a/test/Concurrency/isolated_default_argument_eval.swift b/test/Concurrency/isolated_default_argument_eval.swift index 0f131a52b725e..0ccfd01ca1de5 100644 --- a/test/Concurrency/isolated_default_argument_eval.swift +++ b/test/Concurrency/isolated_default_argument_eval.swift @@ -1,4 +1,4 @@ -// RUN: %target-swift-emit-silgen -I %t -disable-availability-checking -strict-concurrency=complete -enable-experimental-feature IsolatedDefaultValues -parse-as-library %s | %FileCheck %s +// RUN: %target-swift-emit-silgen -I %t -disable-availability-checking -strict-concurrency=complete -enable-upcoming-feature IsolatedDefaultValues -parse-as-library %s | %FileCheck %s // REQUIRES: concurrency // REQUIRES: asserts @@ -9,19 +9,62 @@ func requiresMainActor() -> Int { 0 } @MainActor func mainActorDefaultArg(value: Int = requiresMainActor()) {} +@MainActor +func mainActorMultiDefaultArg(x: Int = requiresMainActor(), + y: Int = 0, + tuple: (Int, Int) = (requiresMainActor(), 2), + z: Int = 0) {} + // CHECK-LABEL: sil hidden [ossa] @$s30isolated_default_argument_eval15mainActorCalleryyF @MainActor func mainActorCaller() { mainActorDefaultArg() + mainActorMultiDefaultArg() } // CHECK-LABEL: sil hidden [ossa] @$s30isolated_default_argument_eval22nonisolatedAsyncCalleryyYaF func nonisolatedAsyncCaller() async { // CHECK: hop_to_executor {{.*}} : $Optional - // CHECK: [[GETARG:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval19mainActorDefaultArg5valueySi_tFfA_ // CHECK: hop_to_executor {{.*}} : $MainActor - // CHECK-NEXT: apply [[GETARG]]() - // CHECK-NEXT: end_borrow {{.*}} : $MainActor - // CHECK-NEXT: destroy_value {{.*}} : $MainActor - // CHECK-NEXT: hop_to_executor {{.*}} : $Optional + // CHECK: [[GET_VALUE:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval19mainActorDefaultArg5valueySi_tFfA_ + // CHECK-NEXT: apply [[GET_VALUE]]() + // CHECK: hop_to_executor {{.*}} : $Optional await mainActorDefaultArg() + + // CHECK: hop_to_executor {{.*}} : $MainActor + // CHECK: [[GET_X:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval24mainActorMultiDefaultArg1x1y5tuple1zySi_S2i_SitSitFfA_ + // CHECK-NEXT: apply [[GET_X]]() + // CHECK-NOT: hop_to_executor + // CHECK: [[GET_Y:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval24mainActorMultiDefaultArg1x1y5tuple1zySi_S2i_SitSitFfA0_ + // CHECK-NEXT: apply [[GET_Y]]() + // CHECK-NOT: hop_to_executor + // CHECK: [[GET_TUPLE:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval24mainActorMultiDefaultArg1x1y5tuple1zySi_S2i_SitSitFfA1_ + // CHECK-NEXT: apply [[GET_TUPLE]]() + // CHECK-NOT: hop_to_executor + // CHECK: [[GET_Z:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval24mainActorMultiDefaultArg1x1y5tuple1zySi_S2i_SitSitFfA2_ + // CHECK-NEXT: apply [[GET_Z]]() + // CHECK: hop_to_executor {{.*}} : $Optional + await mainActorMultiDefaultArg() +} + +@MainActor +func isolatedDefaultInoutMix(x: inout Int, y: Int, z: Int = requiresMainActor()) {} + +var argValue: Int { 0 } + +// CHECK-LABEL: sil hidden [ossa] @$s30isolated_default_argument_eval20passInoutWithDefaultyyYaF +func passInoutWithDefault() async { + // CHECK: hop_to_executor {{.*}} : $Optional + + var x = 0 + + // CHECK: [[GET_ARG_VALUE:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval8argValueSivg + // CHECK-NEXT: [[ARG_VALUE:%[0-9]+]] = apply [[GET_ARG_VALUE]]() + // CHECK-NEXT: [[INOUT_X:%[0-9]+]] = begin_access [modify] + // CHECK: hop_to_executor {{.*}} : $MainActor + // CHECK: [[GET_Z:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval0A15DefaultInoutMix1x1y1zySiz_S2itFfA1_ + // CHECK-NEXT: [[Z:%[0-9]+]] = apply [[GET_Z]]() + // CHECK: [[FN:%[0-9]+]] = function_ref @$s30isolated_default_argument_eval0A15DefaultInoutMix1x1y1zySiz_S2itF : $@convention(thin) (@inout Int, Int, Int) -> () + // CHECK: apply [[FN]]([[INOUT_X]], [[ARG_VALUE]], [[Z]]) + // CHECK: hop_to_executor {{.*}} : $Optional + await isolatedDefaultInoutMix(x: &x, y: argValue) } diff --git a/test/Concurrency/isolated_default_arguments.swift b/test/Concurrency/isolated_default_arguments.swift index 3cc69daa8b261..da5efcb0c09e6 100644 --- a/test/Concurrency/isolated_default_arguments.swift +++ b/test/Concurrency/isolated_default_arguments.swift @@ -2,8 +2,8 @@ // RUN: %target-swift-frontend -emit-module -emit-module-path %t/OtherActors.swiftmodule -module-name OtherActors %S/Inputs/OtherActors.swift -disable-availability-checking -// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -enable-experimental-feature IsolatedDefaultValues -parse-as-library -emit-sil -o /dev/null -verify %s -// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-experimental-feature IsolatedDefaultValues -enable-experimental-feature RegionBasedIsolation %s +// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -enable-upcoming-feature IsolatedDefaultValues -parse-as-library -emit-sil -o /dev/null -verify %s +// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-upcoming-feature IsolatedDefaultValues -enable-experimental-feature RegionBasedIsolation %s // REQUIRES: concurrency // REQUIRES: asserts diff --git a/test/Concurrency/isolated_default_arguments_serialized.swift b/test/Concurrency/isolated_default_arguments_serialized.swift index ab8620351e611..e66dc87be4ffa 100644 --- a/test/Concurrency/isolated_default_arguments_serialized.swift +++ b/test/Concurrency/isolated_default_arguments_serialized.swift @@ -1,8 +1,8 @@ // RUN: %empty-directory(%t) -// RUN: %target-swift-frontend -emit-module -swift-version 5 -emit-module-path %t/SerializedDefaultArguments.swiftmodule -module-name SerializedDefaultArguments -enable-experimental-feature IsolatedDefaultValues %S/Inputs/serialized_default_arguments.swift +// RUN: %target-swift-frontend -emit-module -swift-version 5 -emit-module-path %t/SerializedDefaultArguments.swiftmodule -module-name SerializedDefaultArguments -enable-upcoming-feature IsolatedDefaultValues %S/Inputs/serialized_default_arguments.swift // RUN: %target-swift-frontend %s -emit-sil -o /dev/null -verify -disable-availability-checking -swift-version 6 -I %t -// RUN: %target-swift-frontend %s -emit-sil -o /dev/null -verify -disable-availability-checking -swift-version 6 -I %t -enable-experimental-feature RegionBasedIsolation -enable-experimental-feature IsolatedDefaultValues +// RUN: %target-swift-frontend %s -emit-sil -o /dev/null -verify -disable-availability-checking -swift-version 6 -I %t -enable-experimental-feature RegionBasedIsolation -enable-upcoming-feature IsolatedDefaultValues // REQUIRES: concurrency // REQUIRES: asserts diff --git a/test/Concurrency/isolated_default_property_inits.swift b/test/Concurrency/isolated_default_property_inits.swift index 7d7487cbedd95..0e18489f24eee 100644 --- a/test/Concurrency/isolated_default_property_inits.swift +++ b/test/Concurrency/isolated_default_property_inits.swift @@ -2,8 +2,8 @@ // RUN: %target-swift-frontend -emit-module -emit-module-path %t/OtherActors.swiftmodule -module-name OtherActors %S/Inputs/OtherActors.swift -disable-availability-checking -// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -enable-experimental-feature IsolatedDefaultValues -parse-as-library -emit-sil -o /dev/null -verify %s -// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-experimental-feature IsolatedDefaultValues -enable-experimental-feature RegionBasedIsolation %s +// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -enable-upcoming-feature IsolatedDefaultValues -parse-as-library -emit-sil -o /dev/null -verify %s +// RUN: %target-swift-frontend -I %t -disable-availability-checking -strict-concurrency=complete -parse-as-library -emit-sil -o /dev/null -verify -enable-upcoming-feature IsolatedDefaultValues -enable-experimental-feature RegionBasedIsolation %s // REQUIRES: concurrency // REQUIRES: asserts diff --git a/test/Concurrency/predates_concurrency.swift b/test/Concurrency/predates_concurrency.swift index 31805d8bb7656..0f96b0683f339 100644 --- a/test/Concurrency/predates_concurrency.swift +++ b/test/Concurrency/predates_concurrency.swift @@ -73,13 +73,15 @@ func testElsewhere(x: X) { // expected-complete-tns-note @-1 {{calls to global function 'onMainActorAlways()' from outside of its actor context are implicitly asynchronous}} @preconcurrency @MainActor class MyModelClass { - // expected-complete-tns-note @-1 {{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + + // default init() is 'nonisolated' in '-strict-concurrency=complete' + func f() { } // expected-complete-tns-note @-1 {{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}} } func testCalls(x: X) { - // expected-complete-tns-note @-1 3{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}} + // expected-complete-tns-note @-1 2{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}} unsafelyMainActorClosure { onMainActor() } @@ -102,8 +104,9 @@ func testCalls(x: X) { // Ok with minimal/targeted concurrency, Not ok with complete. let _: () -> Void = onMainActorAlways // expected-complete-tns-warning {{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}} - // both okay with minimal/targeted... an error with complete. - let c = MyModelClass() // expected-complete-tns-warning {{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}} + let c = MyModelClass() + + // okay with minimal/targeted... an error with complete. c.f() // expected-complete-tns-warning {{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}} } @@ -113,8 +116,9 @@ func testCallsWithAsync() async { let _: () -> Void = onMainActorAlways // expected-warning {{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}} - let c = MyModelClass() // expected-warning{{expression is 'async' but is not marked with 'await'}} - // expected-note@-1{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + let c = MyModelClass() // expected-minimal-targeted-warning{{expression is 'async' but is not marked with 'await'}} + // expected-minimal-targeted-note@-1{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + c.f() // expected-warning{{expression is 'async' but is not marked with 'await'}} // expected-note@-1{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}} } diff --git a/test/Concurrency/predates_concurrency_swift6.swift b/test/Concurrency/predates_concurrency_swift6.swift index 96748ac75bf61..4b13e5328c376 100644 --- a/test/Concurrency/predates_concurrency_swift6.swift +++ b/test/Concurrency/predates_concurrency_swift6.swift @@ -59,18 +59,18 @@ func testElsewhere(x: X) { // expected-note@-1{{are implicitly asynchronous}} @preconcurrency @MainActor class MyModelClass { - // expected-note@-1{{are implicitly asynchronous}} func f() { } // expected-note@-1{{are implicitly asynchronous}} } func testCalls(x: X) { - // expected-note@-1 3{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}} + // expected-note@-1 2{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}} onMainActorAlways() // expected-error{{call to main actor-isolated global function 'onMainActorAlways()' in a synchronous nonisolated context}} let _: () -> Void = onMainActorAlways // expected-error{{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}} - let c = MyModelClass() // expected-error{{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}} + let c = MyModelClass() // okay, synthesized init() is 'nonisolated' + c.f() // expected-error{{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}} } @@ -80,8 +80,8 @@ func testCallsWithAsync() async { let _: () -> Void = onMainActorAlways // expected-error{{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}} - let c = MyModelClass() // expected-error{{expression is 'async' but is not marked with 'await'}} - // expected-note@-1{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}} + let c = MyModelClass() // okay, synthesized init() is 'nonisolated' + c.f() // expected-error{{expression is 'async' but is not marked with 'await'}} // expected-note@-1{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}} }