Skip to content

Commit 3db9fcb

Browse files
committed
[Concurrency] DefaultIsolation: Add isolation attributes to declarations inferred as @MainActor
When declaration gets inferred as `@MainActor` that needs to be reflected in its attributes as well because that's the only reliable way propagate isolation across modules. Resolves: rdar://164077275 (cherry picked from commit 721723f)
1 parent bca5a24 commit 3db9fcb

File tree

3 files changed

+117
-1
lines changed

3 files changed

+117
-1
lines changed

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6779,6 +6779,18 @@ static InferredActorIsolation computeActorIsolation(Evaluator &evaluator,
67796779
// default.
67806780
addAttributesForActorIsolation(value, defaultIsolation.isolation);
67816781
}
6782+
6783+
// In `@MainActor` by default mode, let's inject the attributes when the
6784+
// isolation was inferred. This would make sure that the declaration is
6785+
// going to retain the isolation when printed in swift interface file and
6786+
// serialized.
6787+
if (value->getModuleContext() == ctx.MainModule &&
6788+
getDefaultIsolationForContext(value->getDeclContext()) ==
6789+
DefaultIsolation::MainActor &&
6790+
defaultIsolation.isolation.isMainActor()) {
6791+
addAttributesForActorIsolation(value, defaultIsolation.isolation);
6792+
}
6793+
67826794
return defaultIsolation;
67836795
}
67846796

test/Concurrency/approachable_concurrency.swift

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -16,7 +16,8 @@ func testSendableInference(s: S) {
1616
takesSendable(s.test)
1717
}
1818

19-
// CHECK-LABEL: sil hidden [ossa] @$s24approachable_concurrency25testNonisolatedNonSendingyyyyYaYCXEYaF : $@convention(thin) @async (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()) -> ()
19+
// The declaration is @MainActor @preconcurrency because language mode is less than 6
20+
// CHECK-LABEL: sil hidden [ossa] @$s24approachable_concurrency25testNonisolatedNonSendingyyyyYaXEYaF : $@convention(thin) @async (@guaranteed @noescape @async @callee_guaranteed (@sil_isolated @sil_implicit_leading_param @guaranteed Builtin.ImplicitActor) -> ()) -> ()
2021
func testNonisolatedNonSending(_: () async -> Void) async {
2122
}
2223

Lines changed: 103 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,103 @@
1+
// RUN: %empty-directory(%t/src)
2+
// RUN: split-file %s %t/src
3+
4+
/// Build the library A
5+
// RUN: %target-swift-frontend -emit-module %t/src/A.swift \
6+
// RUN: -module-name A -swift-version 5 \
7+
// RUN: -default-isolation MainActor \
8+
// RUN: -enable-library-evolution \
9+
// RUN: -emit-module-path %t/A.swiftmodule \
10+
// RUN: -emit-module-interface-path %t/A.swiftinterface
11+
12+
// RUN: %FileCheck %t/src/A.swift < %t/A.swiftinterface
13+
14+
// Build the client using module
15+
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unrelated -I %t -primary-file %t/src/Client.swift
16+
17+
// RUN: rm %t/A.swiftmodule
18+
19+
// Re-build the client using interface
20+
// RUN: %target-swift-frontend -typecheck -verify -verify-ignore-unrelated -I %t -primary-file %t/src/Client.swift
21+
22+
// REQUIRES: concurrency
23+
24+
//--- A.swift
25+
26+
// CHECK: @_Concurrency.MainActor @preconcurrency public protocol P
27+
public protocol P {
28+
}
29+
30+
// CHECK: nonisolated public protocol Q : Swift.Sendable
31+
nonisolated public protocol Q: Sendable {
32+
}
33+
34+
// CHECK: @_Concurrency.MainActor @preconcurrency public struct S : A.P {
35+
public struct S: P {
36+
// CHECK: @_Concurrency.MainActor @preconcurrency public func f()
37+
public func f() {}
38+
39+
// CHECK: @_Concurrency.MainActor @preconcurrency public struct Inner {
40+
public struct Inner {
41+
// CHECK: @_Concurrency.MainActor @preconcurrency public init()
42+
public init() {}
43+
}
44+
// CHECK: }
45+
}
46+
// CHECK: }
47+
48+
// CHECK: public struct R : A.Q {
49+
public struct R: Q {
50+
// CHECK: public struct Inner {
51+
public struct Inner {
52+
// CHECK: public init()
53+
public init() {}
54+
}
55+
// CHECK: }
56+
57+
// CHECK: @_Concurrency.MainActor @preconcurrency public struct InnerIsolated : A.P {
58+
// CHECK: }
59+
public struct InnerIsolated: P {}
60+
}
61+
// CHECK: }
62+
63+
// CHECK: @_Concurrency.MainActor @preconcurrency public func testGlobal()
64+
public func testGlobal() {}
65+
66+
// CHECK: @_Concurrency.MainActor @preconcurrency public class C {
67+
public class C {
68+
// CHECK: @_Concurrency.MainActor @preconcurrency public init()
69+
public init() {}
70+
71+
// CHECK: @_Concurrency.MainActor @preconcurrency public static var value: Swift.Int
72+
public static var value = 42
73+
74+
// CHECK: {{(@objc )?}} @_Concurrency.MainActor deinit
75+
}
76+
// CHECK: }
77+
78+
// CHECK: @_Concurrency.MainActor @preconcurrency open class IsolatedDeinitTest {
79+
open class IsolatedDeinitTest {
80+
// CHECK: {{(@objc )?}} isolated deinit
81+
isolated deinit {}
82+
}
83+
// CHECK: }
84+
85+
86+
//--- Client.swift
87+
import A
88+
89+
final class IsolatedDeinitChild: IsolatedDeinitTest {} // Ok
90+
91+
nonisolated func testIsolation() {
92+
testGlobal() // expected-warning {{call to main actor-isolated global function 'testGlobal()' in a synchronous nonisolated context}}
93+
94+
func test(s: S) {
95+
s.f() // expected-warning {{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
96+
}
97+
98+
_ = S.Inner() // expected-warning {{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}}
99+
_ = R.Inner() // Ok
100+
101+
_ = C() // expected-warning {{call to main actor-isolated initializer 'init()' in a synchronous nonisolated context}}
102+
_ = C.value // expected-warning {{main actor-isolated class property 'value' can not be referenced from a nonisolated context}}
103+
}

0 commit comments

Comments
 (0)