Skip to content

Commit e819c9f

Browse files
committed
[Concurrency] NonisolatedNonsendingByDefault: Turn inferred nonisolated into nonisolated(nonsending)
Inferred `nonisolated` from the context i.e. an extension should mark the member as `@concurrent` instead it should behave as `nonisolated(nonsending)` when `NonisolatedNonsendingByDefault` is enabled. Resolves: rdar://157789572
1 parent 80152b2 commit e819c9f

File tree

3 files changed

+107
-7
lines changed

3 files changed

+107
-7
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -6513,6 +6513,20 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
65136513
}
65146514
}
65156515

6516+
// When `NonisolatedNonsendingByDefault` feature is enabled and the value is
6517+
// asynchronous `nonisolated` always means `nonisolated(nonsending)`.
6518+
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&
6519+
inferred.isNonisolated() && value->isAsync()) {
6520+
// Either current module or async variant of an ObjC API.
6521+
if (value->getModuleContext() == ctx.MainModule ||
6522+
(value->hasClangNode() &&
6523+
!isa<ProtocolDecl>(value->getDeclContext()))) {
6524+
inferred =
6525+
ActorIsolation::forCallerIsolationInheriting().withPreconcurrency(
6526+
inferred.preconcurrency());
6527+
}
6528+
}
6529+
65166530
// Add an implicit attribute to capture the actor isolation that was
65176531
// inferred, so that (e.g.) it will be printed and serialized.
65186532
switch (inferred) {
@@ -6724,13 +6738,6 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
67246738
if (shouldSelfIsolationOverrideDefault(
67256739
ctx, value->getDeclContext(), selfTypeIsolation.isolation)) {
67266740
auto isolation = selfTypeIsolation.isolation;
6727-
6728-
if (ctx.LangOpts.hasFeature(Feature::NonisolatedNonsendingByDefault) &&
6729-
value->isAsync() && value->getModuleContext() == ctx.MainModule &&
6730-
isolation.isNonisolated()) {
6731-
isolation = ActorIsolation::forCallerIsolationInheriting();
6732-
}
6733-
67346741
return {inferredIsolation(isolation, onlyGlobal),
67356742
selfTypeIsolation.source};
67366743
}

test/Concurrency/attr_execution/nonisolated_cross_module_with_flag_enabled.swift

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -47,6 +47,36 @@ public struct InferenceTest {
4747
public func testAutoclosure(value2 fn: nonisolated(nonsending) @autoclosure () async -> Int) async { await fn() }
4848
}
4949

50+
// CHECK: nonisolated extension A.InferenceTest {
51+
// CHECK: nonisolated(nonsending) public func testInExtension() async
52+
// CHECK: @concurrent public func testConcurrentInExtension() async
53+
// CHECK: }
54+
nonisolated public extension InferenceTest {
55+
func testInExtension() async {}
56+
@concurrent func testConcurrentInExtension() async {}
57+
}
58+
59+
// CHECK: public protocol P {
60+
// CHECK: nonisolated(nonsending) func testWitness() async
61+
// CHECK: }
62+
public protocol P {
63+
func testWitness() async
64+
}
65+
66+
// CHECK: public struct WitnessTest : nonisolated A.P {
67+
// CHECK: nonisolated(nonsending) public func testWitness() async
68+
// CHECK: }
69+
public struct WitnessTest: nonisolated P {
70+
public func testWitness() async {}
71+
}
72+
73+
// CHECK: nonisolated public class NoinsolatedClassTest {
74+
// CHECK: nonisolated(nonsending) public func test() async
75+
// CHECK: }
76+
nonisolated public class NoinsolatedClassTest {
77+
public func test() async {}
78+
}
79+
5080
//--- Client.swift
5181
import A
5282

@@ -75,13 +105,18 @@ func testWithCallback(t: Test) async {
75105
// CHECK: function_ref @$s1A13InferenceTestV10infersAttryyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed InferenceTest) -> ()
76106
// 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) -> ()
77107
// CHECK: function_ref @$s1A13InferenceTestV10testNested4dictySDySSyyYaYCcSgG_tF : $@convention(method) (@guaranteed Dictionary<String, Optional<nonisolated(nonsending) () async -> ()>>, @in_guaranteed InferenceTest) -> ()
108+
// CHECK: function_ref @$s1A13InferenceTestV15testInExtensionyyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed InferenceTest) -> ()
109+
// CHECK: function_ref @$s1A13InferenceTestV25testConcurrentInExtensionyyYaF : $@convention(method) @async (@in_guaranteed InferenceTest) -> ()
78110
// CHECK: } // end sil function '$s6Client13testInference1ty1A0C4TestV_tYaF'
79111
@MainActor
80112
func testInference(t: InferenceTest) async {
81113
await t.infersAttr()
82114

83115
t.testNested { _ in }
84116
t.testNested(dict: [:])
117+
118+
await t.testInExtension()
119+
await t.testConcurrentInExtension()
85120
}
86121

87122
// CHECK-LABEL: sil hidden @$s6Client15testAutoclosure1ty1A13InferenceTestV_tYaF : $@convention(thin) @async (@in_guaranteed InferenceTest) -> ()
@@ -92,3 +127,17 @@ func testAutoclosure(t: InferenceTest) async {
92127
await t.testAutoclosure(value1: 42)
93128
await t.testAutoclosure(value2: 42)
94129
}
130+
131+
// CHECK-LABEL: sil hidden @$s6Client26testWitnessWithNonisolated1ty1A0C4TestV_tYaF : $@convention(thin) @async (@in_guaranteed WitnessTest) -> ()
132+
// CHECK: function_ref @$s1A11WitnessTestV04testA0yyYaF : $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @in_guaranteed WitnessTest) -> ()
133+
// CHECK: } // end sil function '$s6Client26testWitnessWithNonisolated1ty1A0C4TestV_tYaF'
134+
func testWitnessWithNonisolated(t: WitnessTest) async {
135+
await t.testWitness()
136+
}
137+
138+
// CHECK-LABEL: sil hidden @$s6Client20testNonisolatedClass1ty1A011NoinsolatedD4TestC_tYaF : $@convention(thin) @async (@guaranteed NoinsolatedClassTest) -> ()
139+
// CHECK: class_method {{.*}}, #NoinsolatedClassTest.test : (NoinsolatedClassTest) -> () async -> (), $@convention(method) @async (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor, @guaranteed NoinsolatedClassTest) -> ()
140+
// CHECK: } // end sil function '$s6Client20testNonisolatedClass1ty1A011NoinsolatedD4TestC_tYaF'
141+
func testNonisolatedClass(t: NoinsolatedClassTest) async {
142+
await t.test()
143+
}
Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,44 @@
1+
// RUN: %empty-directory(%t)
2+
// RUN: %empty-directory(%t/src)
3+
// RUN: split-file %s %t/src
4+
5+
// RUN: %target-swift-frontend(mock-sdk: %clang-importer-sdk) -emit-sil %t/src/main.swift \
6+
// RUN: -import-objc-header %t/src/Test.h \
7+
// RUN: -swift-version 5 \
8+
// RUN: -strict-concurrency=complete \
9+
// RUN: -enable-upcoming-feature NonisolatedNonsendingByDefault \
10+
// RUN: -module-name main -I %t -verify
11+
12+
// REQUIRES: objc_interop
13+
// REQUIRES: concurrency
14+
// REQUIRES: swift_feature_NonisolatedNonsendingByDefault
15+
16+
//--- Test.h
17+
#define SWIFT_NONISOLATED __attribute__((__swift_attr__("nonisolated")))
18+
19+
#pragma clang assume_nonnull begin
20+
21+
@import Foundation;
22+
23+
SWIFT_NONISOLATED
24+
@interface Doc : NSObject
25+
- (void)saveWithCompletionHandler:(void (^ __nullable)(BOOL success))completionHandler;
26+
@end
27+
28+
SWIFT_NONISOLATED
29+
@interface Doc(Reset)
30+
- (void)resetWithCompletionHandler:(void (^ __nullable)(BOOL success))completionHandler;
31+
@end
32+
33+
#pragma clang assume_nonnull end
34+
35+
//--- main.swift
36+
37+
final class Test {
38+
let doc = Doc()
39+
40+
func test() async {
41+
_ = await doc.save() // Ok
42+
_ = await doc.reset() // Ok
43+
}
44+
}

0 commit comments

Comments
 (0)