Skip to content

Commit 939aaa9

Browse files
author
Adam Cmiel
committed
[Sema] Permit dot reference with isolation change without call
A dot-reference of a method defined on `Self` (as well as through `self`) should be permitted to be made in a different actor isolation than the referenced function's actor isolation if a call is not yet made, as the DeclRefExpr can store the isolation of the referenced decl. That said, we currently can only express that known isolation with global actor annotations until the language adopts closure isolation control. This is fixed on main so just recomming for the tests
1 parent f042eb8 commit 939aaa9

File tree

2 files changed

+80
-0
lines changed

2 files changed

+80
-0
lines changed

test/Concurrency/actor_isolation.swift

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1723,3 +1723,44 @@ class InferIsolationViaOverride: SuperWithIsolatedMethod {
17231723
// expected-error@-1 {{call to main actor-isolated instance method 'isolatedMethod()' in a synchronous nonisolated context}}
17241724
}
17251725
}
1726+
1727+
struct ReferenceSelfDotMethods {
1728+
@MainActor
1729+
func mainActorAffinedFunction() {}
1730+
1731+
nonisolated
1732+
private func testCurry() -> (Self) -> (@MainActor () -> Void) {
1733+
let functionRef = Self.mainActorAffinedFunction
1734+
// warning goes away with InferSendableFromCaptures, see actor_isolation_swift6.swift
1735+
return functionRef // expected-warning {{converting non-sendable function value to '@MainActor @Sendable () -> Void' may introduce data races}}
1736+
}
1737+
1738+
@MainActor
1739+
private func callOnMainActorOk() {
1740+
let mainActorAffinedClosure = testCurry()(self)
1741+
mainActorAffinedClosure()
1742+
}
1743+
1744+
nonisolated
1745+
private func nonisolatedCallErrors() {
1746+
let mainActorAffinedClosure = testCurry()(self)
1747+
// expected-note@-1 {{calls to let 'mainActorAffinedClosure' from outside of its actor context are implicitly asynchronous}}
1748+
mainActorAffinedClosure()
1749+
// expected-error@-1 {{call to main actor-isolated let 'mainActorAffinedClosure' in a synchronous nonisolated context}}
1750+
}
1751+
}
1752+
1753+
actor UserDefinedActorSelfDotMethod {
1754+
func actorAffinedFunc() {} // expected-note {{calls to instance method 'actorAffinedFunc()' from outside of its actor context are implicitly asynchronous}}
1755+
1756+
// Unfortunately we can't express the desired isolation of this returned closure statically to
1757+
// be able to call it on the desired actor. This may be possible with the acceptance of
1758+
// https://forums.swift.org/t/closure-isolation-control/70378 but I think we need more expressivity
1759+
// in the type system to express this sort of curry.
1760+
nonisolated
1761+
private func testCurry() -> (UserDefinedActorSelfDotMethod) -> (@isolated(any) () -> Void) {
1762+
let functionRef = Self.actorAffinedFunc // expected-error {{call to actor-isolated instance method 'actorAffinedFunc()' in a synchronous nonisolated context}}
1763+
// error message changes with InferSendabaleFromCaptures - see actor_isolation_swift6.swift
1764+
return functionRef // expected-error {{cannot convert return expression of type '(isolated Self) -> () -> ()' to return type '(UserDefinedActorSelfDotMethod) -> @isolated(any) () -> Void'}}
1765+
}
1766+
}

test/Concurrency/actor_isolation_swift6.swift

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -95,3 +95,42 @@ nonisolated func accessAcrossActors() {
9595
// expected-error@+1 {{main actor-isolated static property 'shared' can not be referenced from a nonisolated context}}
9696
let _ = MainActorIsolated.shared
9797
}
98+
99+
struct ReferenceSelfDotMethods {
100+
@MainActor
101+
func mainActorAffinedFunction() {}
102+
103+
nonisolated
104+
private func testCurry() -> (Self) -> (@MainActor () -> Void) {
105+
let functionRef = Self.mainActorAffinedFunction
106+
return functionRef
107+
}
108+
109+
@MainActor
110+
private func callOnMainActorOk() {
111+
let mainActorAffinedClosure = testCurry()(self)
112+
mainActorAffinedClosure()
113+
}
114+
115+
nonisolated
116+
private func nonisolatedCallErrors() {
117+
let mainActorAffinedClosure = testCurry()(self)
118+
// expected-note@-1 {{calls to let 'mainActorAffinedClosure' from outside of its actor context are implicitly asynchronous}}
119+
mainActorAffinedClosure()
120+
// expected-error@-1 {{call to main actor-isolated let 'mainActorAffinedClosure' in a synchronous nonisolated context}}
121+
}
122+
}
123+
124+
actor UserDefinedActorSelfDotMethod {
125+
func actorAffinedFunc() {} // expected-note {{calls to instance method 'actorAffinedFunc()' from outside of its actor context are implicitly asynchronous}}
126+
127+
// Unfortunately we can't express the desired isolation of this returned closure statically to
128+
// be able to call it on the desired actor. This may be possible with the acceptance of
129+
// https://forums.swift.org/t/closure-isolation-control/70378 but I think we need more expressivity
130+
// in the type system to express this sort of curry.
131+
nonisolated
132+
private func testCurry() -> (UserDefinedActorSelfDotMethod) -> (@isolated(any) () -> Void) {
133+
let functionRef = Self.actorAffinedFunc // expected-error {{call to actor-isolated instance method 'actorAffinedFunc()' in a synchronous nonisolated context}}
134+
return functionRef // expected-error {{cannot convert return expression of type '@Sendable (isolated Self) -> @Sendable () -> ()' to return type '(UserDefinedActorSelfDotMethod) -> @isolated(any) () -> Void'}}
135+
}
136+
}

0 commit comments

Comments
 (0)