diff --git a/lib/Sema/TypeCheckConcurrency.cpp b/lib/Sema/TypeCheckConcurrency.cpp index 9cfe3bac19fc5..a75be814e8466 100644 --- a/lib/Sema/TypeCheckConcurrency.cpp +++ b/lib/Sema/TypeCheckConcurrency.cpp @@ -6513,6 +6513,20 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, } } + // When `NonisolatedNonsendingByDefault` feature is enabled and the value is + // asynchronous `nonisolated` always means `nonisolated(nonsending)`. + if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) && + inferred.isNonisolated() && value->isAsync()) { + // Either current module or async variant of an ObjC API. + if (value->getModuleContext() == ctx.MainModule || + (value->hasClangNode() && + !isa(value->getDeclContext()))) { + inferred = + ActorIsolation::forCallerIsolationInheriting().withPreconcurrency( + inferred.preconcurrency()); + } + } + // Add an implicit attribute to capture the actor isolation that was // inferred, so that (e.g.) it will be printed and serialized. switch (inferred) { @@ -6724,13 +6738,6 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator, if (shouldSelfIsolationOverrideDefault( ctx, value->getDeclContext(), selfTypeIsolation.isolation)) { auto isolation = selfTypeIsolation.isolation; - - if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) && - value->isAsync() && value->getModuleContext() == ctx.MainModule && - isolation.isNonisolated()) { - isolation = ActorIsolation::forCallerIsolationInheriting(); - } - return {inferredIsolation(isolation, onlyGlobal), selfTypeIsolation.source}; } diff --git a/test/Concurrency/attr_execution/nonisolated_cross_module_with_flag_enabled.swift b/test/Concurrency/attr_execution/nonisolated_cross_module_with_flag_enabled.swift index c952f4c9455dd..23561e8427d7e 100644 --- a/test/Concurrency/attr_execution/nonisolated_cross_module_with_flag_enabled.swift +++ b/test/Concurrency/attr_execution/nonisolated_cross_module_with_flag_enabled.swift @@ -47,6 +47,36 @@ public struct InferenceTest { public func testAutoclosure(value2 fn: nonisolated(nonsending) @autoclosure () async -> Int) async { await fn() } } +// CHECK: nonisolated extension A.InferenceTest { +// CHECK: nonisolated(nonsending) public func testInExtension() async +// CHECK: @concurrent public func testConcurrentInExtension() async +// CHECK: } +nonisolated public extension InferenceTest { + func testInExtension() async {} + @concurrent func testConcurrentInExtension() async {} +} + +// CHECK: public protocol P { +// CHECK: nonisolated(nonsending) func testWitness() async +// CHECK: } +public protocol P { + func testWitness() async +} + +// CHECK: public struct WitnessTest : nonisolated A.P { +// CHECK: nonisolated(nonsending) public func testWitness() async +// CHECK: } +public struct WitnessTest: nonisolated P { + public func testWitness() async {} +} + +// CHECK: nonisolated public class NoinsolatedClassTest { +// CHECK: nonisolated(nonsending) public func test() async +// CHECK: } +nonisolated public class NoinsolatedClassTest { + public func test() async {} +} + //--- Client.swift import A @@ -75,6 +105,8 @@ func testWithCallback(t: Test) async { // CHECK: function_ref @$s1A13InferenceTestV10infersAttryyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed InferenceTest) -> () // CHECK: function_ref @$s1A13InferenceTestV10testNested8callbackyyyyYaYbYCXEc_tF : $@convention(method) (@guaranteed @callee_guaranteed (@guaranteed @noescape @Sendable @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()) -> (), @in_guaranteed InferenceTest) -> () // CHECK: function_ref @$s1A13InferenceTestV10testNested4dictySDySSyyYaYCcSgG_tF : $@convention(method) (@guaranteed Dictionary ()>>, @in_guaranteed InferenceTest) -> () +// CHECK: function_ref @$s1A13InferenceTestV15testInExtensionyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed InferenceTest) -> () +// CHECK: function_ref @$s1A13InferenceTestV25testConcurrentInExtensionyyYaF : $@convention(method) @async (@in_guaranteed InferenceTest) -> () // CHECK: } // end sil function '$s6Client13testInference1ty1A0C4TestV_tYaF' @MainActor func testInference(t: InferenceTest) async { @@ -82,6 +114,9 @@ func testInference(t: InferenceTest) async { t.testNested { _ in } t.testNested(dict: [:]) + + await t.testInExtension() + await t.testConcurrentInExtension() } // CHECK-LABEL: sil hidden @$s6Client15testAutoclosure1ty1A13InferenceTestV_tYaF : $@convention(thin) @async (@in_guaranteed InferenceTest) -> () @@ -92,3 +127,17 @@ func testAutoclosure(t: InferenceTest) async { await t.testAutoclosure(value1: 42) await t.testAutoclosure(value2: 42) } + +// CHECK-LABEL: sil hidden @$s6Client26testWitnessWithNonisolated1ty1A0C4TestV_tYaF : $@convention(thin) @async (@in_guaranteed WitnessTest) -> () +// CHECK: function_ref @$s1A11WitnessTestV04testA0yyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed WitnessTest) -> () +// CHECK: } // end sil function '$s6Client26testWitnessWithNonisolated1ty1A0C4TestV_tYaF' +func testWitnessWithNonisolated(t: WitnessTest) async { + await t.testWitness() +} + +// CHECK-LABEL: sil hidden @$s6Client20testNonisolatedClass1ty1A011NoinsolatedD4TestC_tYaF : $@convention(thin) @async (@guaranteed NoinsolatedClassTest) -> () +// CHECK: class_method {{.*}}, #NoinsolatedClassTest.test : (NoinsolatedClassTest) -> () async -> (), $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed NoinsolatedClassTest) -> () +// CHECK: } // end sil function '$s6Client20testNonisolatedClass1ty1A011NoinsolatedD4TestC_tYaF' +func testNonisolatedClass(t: NoinsolatedClassTest) async { + await t.test() +} diff --git a/test/Concurrency/attr_execution/nonisolated_nonsending_by_default_and_objc_nonisolated.swift b/test/Concurrency/attr_execution/nonisolated_nonsending_by_default_and_objc_nonisolated.swift new file mode 100644 index 0000000000000..bc765c78732a5 --- /dev/null +++ b/test/Concurrency/attr_execution/nonisolated_nonsending_by_default_and_objc_nonisolated.swift @@ -0,0 +1,44 @@ +// RUN: %empty-directory(%t) +// RUN: %empty-directory(%t/src) +// RUN: split-file %s %t/src + +// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil %t/src/main.swift \ +// RUN: -import-objc-header %t/src/Test.h \ +// RUN: -swift-version 5 \ +// RUN: -strict-concurrency=complete \ +// RUN: -enable-upcoming-feature NonisolatedNonsendingByDefault \ +// RUN: -module-name main -I %t -verify + +// REQUIRES: objc_interop +// REQUIRES: concurrency +// REQUIRES: swift_feature_NonisolatedNonsendingByDefault + +//--- Test.h +#define SWIFT_NONISOLATED __attribute__((__swift_attr__("nonisolated"))) + +#pragma clang assume_nonnull begin + +@import Foundation; + +SWIFT_NONISOLATED +@interface Doc : NSObject +- (void)saveWithCompletionHandler:(void (^ __nullable)(BOOL success))completionHandler; +@end + +SWIFT_NONISOLATED +@interface Doc(Reset) +- (void)resetWithCompletionHandler:(void (^ __nullable)(BOOL success))completionHandler; +@end + +#pragma clang assume_nonnull end + +//--- main.swift + +final class Test { + let doc = Doc() + + func test() async { + _ = await doc.save() // Ok + _ = await doc.reset() // Ok + } +}