Skip to content

Commit 36e0c9e

Browse files
authored
Merge pull request #74010 from hborla/6.0-non-sendable-isolated-any
[6.0][Concurrency] `@isolated(any)` does not imply `@Sendable`.
2 parents e85beea + 3675679 commit 36e0c9e

File tree

9 files changed

+61
-30
lines changed

9 files changed

+61
-30
lines changed

lib/Sema/CSSimplify.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -9766,9 +9766,9 @@ performMemberLookup(ConstraintKind constraintKind, DeclNameRef memberName,
97669766

97679767
// Dynamically isolated function types have a magic '.isolation'
97689768
// member that extracts the isolation value.
9769-
if (auto *fn = dyn_cast<FunctionType>(instanceTy)) {
9769+
if (auto *fn = instanceTy->getAs<FunctionType>()) {
97709770
if (fn->getIsolation().isErased() &&
9771-
memberName.getBaseIdentifier().str() == "isolation") {
9771+
memberName.isSimpleName(Context.Id_isolation)) {
97729772
result.ViableCandidates.push_back(
97739773
OverloadChoice(baseTy, OverloadChoiceKind::ExtractFunctionIsolation));
97749774
}

lib/Sema/TypeCheckType.cpp

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3946,9 +3946,6 @@ NeverNullType TypeResolver::resolveASTFunctionType(
39463946
conventionAttr->getConventionName());
39473947
} else {
39483948
isolation = FunctionTypeIsolation::forErased();
3949-
3950-
// @isolated(any) implies @Sendable, unconditionally for now.
3951-
sendable = true;
39523949
}
39533950
break;
39543951
}

test/Concurrency/isolated_any.swift

Lines changed: 37 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -75,7 +75,7 @@ func testConvertIsolatedAnyToMainActor(fn: @Sendable @isolated(any) () -> ()) {
7575
requireSendableGlobalActor(fn)
7676
}
7777

78-
func extractFunctionIsolation(_ fn: @isolated(any) @escaping () async -> Void) {
78+
func extractFunctionIsolation(_ fn: @isolated(any) @Sendable @escaping () async -> Void) {
7979
let _: (any Actor)? = extractIsolation(fn)
8080

8181
let myActor = A()
@@ -85,14 +85,48 @@ func extractFunctionIsolation(_ fn: @isolated(any) @escaping () async -> Void) {
8585
}
8686

8787
func extractFunctionIsolationExpr(
88-
_ fn1: @isolated(any) @escaping () async -> Void,
89-
_ fn2: @isolated(any) @escaping (Int, String) -> Bool
88+
_ fn1: @isolated(any) @Sendable @escaping () async -> Void,
89+
_ fn2: @isolated(any) @Sendable @escaping (Int, String) -> Bool
9090
) {
9191
let _: (any Actor)? = fn1.isolation
9292
let _: (any Actor)? = fn2.isolation
9393

9494
// Only `@isolated(any)` functions have `.isolation`
9595
let myActor = A()
96+
let _: (any Actor)? = myActor.actorFunction.isolation // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
9697
let _: (any Actor)? = myActor.asyncActorFunction.isolation // expected-error {{value of type '@Sendable () async -> ()' has no member 'isolation'}}
98+
let _: (any Actor)? = myActor.asyncThrowsActorFunction.isolation // expected-error {{value of type '@Sendable () async throws -> ()' has no member 'isolation'}}
99+
let _: (any Actor)? = myActor.actorFunctionWithArgs.isolation // expected-error {{value of type '@Sendable (Int) async -> String' has no member 'isolation'}}
100+
97101
let _: (any Actor)? = globalNonisolatedFunction.isolation // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
102+
let _: (any Actor)? = globalMainActorFunction.isolation // expected-error {{value of type '@MainActor @Sendable () -> ()' has no member 'isolation'}}
103+
}
104+
105+
func requireDotIsolation(_ fn: (any Actor)?) -> (any Actor)? { return fn }
106+
107+
func testDotIsolation() {
108+
let _ : (any Actor)? = requireDotIsolation(globalMainActorFunction.isolation) // expected-error {{value of type '@MainActor @Sendable () -> ()' has no member 'isolation'}}
109+
let _ : (any Actor)? = requireDotIsolation(globalNonisolatedFunction.isolation) // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
110+
}
111+
112+
func testFunctionIsolationExpr1(_ fn: (@isolated(any) () -> Void)?) -> (any Actor)? {
113+
return fn?.isolation
114+
}
115+
116+
func testFunctionIsolationExpr2(_ fn: Optional<(@isolated(any) () -> Void)>) -> Optional<any Actor> {
117+
return fn?.isolation
118+
}
119+
120+
func testFunctionIsolationExprTuple(
121+
_ fn1: (@isolated(any) @Sendable () -> Void)?,
122+
_ fn2: (@isolated(any) @Sendable () -> Void)?
123+
) -> ((any Actor)?, (any Actor)?)
124+
{
125+
return (fn1?.isolation, fn2?.isolation)
126+
}
127+
128+
func nonSendableIsolatedAny(
129+
_ fn: @escaping @isolated(any) () -> Void // expected-note {{parameter 'fn' is implicitly non-sendable}}
130+
) {
131+
let _: @Sendable () -> Void = fn // expected-warning {{using non-sendable parameter 'fn' in a context expecting a @Sendable closure}}
98132
}

test/Distributed/distributed_actor_isolated_any.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -12,7 +12,7 @@ import FakeDistributedActorSystems
1212

1313
typealias DefaultDistributedActorSystem = FakeActorSystem
1414

15-
func takeInheritingAsyncIsolatedAny(@_inheritActorContext fn: @escaping @isolated(any) () async -> ()) {}
15+
func takeInheritingAsyncIsolatedAny(@_inheritActorContext fn: @escaping @isolated(any) @Sendable () async -> ()) {}
1616

1717
// CHECK-LABEL: sil hidden [distributed] [ossa] @$s4test2DAC0A20DistributedIsolationyyF
1818
// CHECK: // function_ref closure #1

test/IRGen/isolated_any_metadata.sil

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -13,8 +13,8 @@ sil_stage canonical
1313
// CHECK-NEXT: ret ptr [[METADATA]]
1414
sil @get_metadata : $() -> @thick Any.Type {
1515
entry:
16-
%type = metatype $@thick (@isolated(any) () -> ()).Type
17-
%result = init_existential_metatype %type : $@thick (@isolated(any) () -> ()).Type, $@thick Any.Type
16+
%type = metatype $@thick (@isolated(any) @Sendable () -> ()).Type
17+
%result = init_existential_metatype %type : $@thick (@isolated(any) @Sendable () -> ()).Type, $@thick Any.Type
1818
return %result : $@thick Any.Type
1919
}
2020

test/ModuleInterface/isolated_any_suppression.swift

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -6,18 +6,18 @@
66
// CHECK: #if compiler(>=5.3) && $IsolatedAny
77
// CHECK-NEXT: {{^}}public func test1(fn: @isolated(any) @Sendable () -> ())
88
// CHECK-NEXT: #endif
9-
public func test1(fn: @isolated(any) () -> ()) {}
9+
public func test1(fn: @isolated(any) @Sendable () -> ()) {}
1010

1111
// CHECK-NEXT: #if compiler(>=5.3) && $IsolatedAny
1212
// CHECK-NEXT: {{^}}public func test2(fn: @isolated(any) @Sendable () -> ())
1313
// CHECK-NEXT: #endif
1414
@_allowFeatureSuppression(XXX)
15-
public func test2(fn: @isolated(any) () -> ()) {}
15+
public func test2(fn: @isolated(any) @Sendable () -> ()) {}
1616

1717
// CHECK-NEXT: #if compiler(>=5.3) && $IsolatedAny
1818
// CHECK-NEXT: {{^}}public func test3(fn: @isolated(any) @Sendable () -> ())
1919
// CHECK-NEXT: #else
2020
// CHECK-NEXT: {{^}}public func test3(fn: @Sendable () -> ())
2121
// CHECK-NEXT: #endif
2222
@_allowFeatureSuppression(IsolatedAny)
23-
public func test3(fn: @isolated(any) () -> ()) {}
23+
public func test3(fn: @isolated(any) @Sendable () -> ()) {}

test/SILGen/isolated_any.swift

Lines changed: 14 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -14,7 +14,7 @@
1414
// CHECK-NEXT: end_borrow [[FN_BORROW2]]
1515
// CHECK-NEXT: end_borrow [[FN_BORROW1]]
1616
// CHECK-NEXT: hop_to_executor [[NIL_EXECUTOR]]
17-
func callSync(fn: @isolated(any) () -> ()) async {
17+
func callSync(fn: @isolated(any) @Sendable () -> ()) async {
1818
await fn()
1919
}
2020

@@ -26,7 +26,7 @@ func callSync(fn: @isolated(any) () -> ()) async {
2626
// CHECK-NEXT: apply [[FN_BORROW2]]()
2727
// CHECK-NEXT: end_borrow [[FN_BORROW2]]
2828
// CHECK-NEXT: hop_to_executor [[NIL_EXECUTOR]]
29-
func callAsync(fn: @isolated(any) () async -> ()) async {
29+
func callAsync(fn: @isolated(any) @Sendable () async -> ()) async {
3030
await fn()
3131
}
3232

@@ -40,7 +40,7 @@ func callAsync(fn: @isolated(any) () async -> ()) async {
4040
// CHECK-NEXT: [[THUNKED_FN:%.*]] = partial_apply [callee_guaranteed] [isolated_any] [[THUNK]]([[ISOLATION]], [[FN_COPY]])
4141
// CHECK-NEXT: return [[THUNKED_FN]] : $@isolated(any) @Sendable @async @callee_guaranteed () -> ()
4242
func convertFromNonIsolated(fn: @escaping @Sendable () async -> ())
43-
-> @isolated(any) () async -> () {
43+
-> @isolated(any) @Sendable () async -> () {
4444
return fn
4545
}
4646

@@ -71,7 +71,7 @@ func convertFromNonIsolated(fn: @escaping @Sendable () async -> ())
7171
// CHECK-NEXT: [[THUNKED_FN:%.*]] = partial_apply [callee_guaranteed] [isolated_any] [[THUNK]]([[ISOLATION]], [[FN_COPY]])
7272
// CHECK-NEXT: return [[THUNKED_FN]] : $@isolated(any) @Sendable @async @callee_guaranteed () -> ()
7373
func convertFromMainActor(fn: @escaping @Sendable @MainActor () async -> ())
74-
-> @isolated(any) () async -> () {
74+
-> @isolated(any) @Sendable () async -> () {
7575
return fn
7676
}
7777

@@ -90,7 +90,7 @@ func convertFromMainActor(fn: @escaping @Sendable @MainActor () async -> ())
9090
// CHECK-NEXT: [[THUNKED_FN:%.*]] = partial_apply [callee_guaranteed] [isolated_any] [[THUNK]]([[ISOLATION]], [[FN_COPY]])
9191
// CHECK-NEXT: return [[THUNKED_FN]] : $@isolated(any) @Sendable @async @callee_guaranteed () -> Optional<Int>
9292
func convertFromMainActorWithOtherChanges(fn: @escaping @Sendable @MainActor () async -> Int)
93-
-> @isolated(any) () async -> Int? {
93+
-> @isolated(any) @Sendable () async -> Int? {
9494
return fn
9595
}
9696

@@ -107,7 +107,7 @@ func convertFromMainActorWithOtherChanges(fn: @escaping @Sendable @MainActor ()
107107
// CHECK-NEXT: [[FN_COPY:%.*]] = copy_value %0 :
108108
// CHECK-NEXT: [[FN_CONVERTED:%.*]] = convert_function [[FN_COPY]] : $@isolated(any) @Sendable @async @callee_guaranteed () -> () to $@Sendable @async @callee_guaranteed () -> ()
109109
// CHECK-NEXT: return [[FN_CONVERTED]] :
110-
func convertToNonIsolated(fn: @escaping @isolated(any) () async -> ())
110+
func convertToNonIsolated(fn: @escaping @isolated(any) @Sendable () async -> ())
111111
-> @Sendable () async -> () {
112112
return fn
113113
}
@@ -129,16 +129,16 @@ func convertToNonIsolated(fn: @escaping @isolated(any) () async -> ())
129129
// CHECK-NEXT: [[SOME_INT:%.*]] = enum $Optional<Int>, #Optional.some!enumelt, [[INT]] : $Int
130130
// CHECK-NEXT: return [[SOME_INT]] : $Optional<Int>
131131

132-
func convertToNonIsolatedWithOtherChanges(fn: @escaping @isolated(any) () async -> Int) -> @Sendable () async -> Int? {
132+
func convertToNonIsolatedWithOtherChanges(fn: @escaping @isolated(any) @Sendable () async -> Int) -> @Sendable () async -> Int? {
133133
return fn
134134
}
135135

136136
/*-- Sync closures --*/
137137

138138
func syncAction() {}
139139

140-
func takeSyncIsolatedAny(fn: @escaping @isolated(any) () -> ()) {}
141-
func takeInheritingSyncIsolatedAny(@_inheritActorContext fn: @escaping @isolated(any) () -> ()) {}
140+
func takeSyncIsolatedAny(fn: @escaping @isolated(any) @Sendable () -> ()) {}
141+
func takeInheritingSyncIsolatedAny(@_inheritActorContext fn: @escaping @isolated(any) @Sendable () -> ()) {}
142142

143143
// CHECK-LABEL: sil hidden [ossa] @$s4test0A27EraseSyncNonIsolatedClosureyyF
144144
// CHECK: // function_ref closure #1
@@ -246,8 +246,8 @@ actor MyActor {
246246

247247
func asyncAction() async {}
248248

249-
func takeAsyncIsolatedAny(fn: @escaping @isolated(any) () async -> ()) {}
250-
func takeInheritingAsyncIsolatedAny(@_inheritActorContext fn: @escaping @isolated(any) () async -> ()) {}
249+
func takeAsyncIsolatedAny(fn: @escaping @isolated(any) @Sendable () async -> ()) {}
250+
func takeInheritingAsyncIsolatedAny(@_inheritActorContext fn: @escaping @isolated(any) @Sendable () async -> ()) {}
251251

252252
// CHECK-LABEL: sil hidden [ossa] @$s4test0A28EraseAsyncNonIsolatedClosureyyF
253253
// CHECK: // function_ref closure #1
@@ -383,7 +383,7 @@ extension MyActor {
383383
func asyncAction() async {}
384384
}
385385

386-
func takeInheritingOptionalAsyncIsolatedAny(@_inheritActorContext fn: Optional<@isolated(any) () async -> ()>) {}
386+
func takeInheritingOptionalAsyncIsolatedAny(@_inheritActorContext fn: Optional<@isolated(any) @Sendable () async -> ()>) {}
387387

388388
// CHECK-LABEL: sil hidden [ossa] @$s4test7MyActorC0a20EraseInheritingAsyncC19ClosureIntoOptionalyyF
389389
// CHECK: // function_ref closure #1
@@ -406,7 +406,7 @@ extension MyActor {
406406
}
407407
}
408408

409-
func takeInheritingAsyncIsolatedAny_optionalResult(@_inheritActorContext fn: @escaping @isolated(any) () async -> Int?) {}
409+
func takeInheritingAsyncIsolatedAny_optionalResult(@_inheritActorContext fn: @escaping @isolated(any) @Sendable () async -> Int?) {}
410410

411411
// Test that we correctly handle isolation erasure from closures even when
412412
// we can't completely apply the conversion as a peephole.
@@ -526,6 +526,6 @@ func testEraseAsyncActorIsolatedPartialApplication(a: MyActor) {
526526
// CHECK-NEXT: end_borrow [[FN_BORROW]] : $@isolated(any) @Sendable @callee_guaranteed () -> ()
527527
// CHECK-NEXT: destroy_value [[FN]] : $@isolated(any) @Sendable @callee_guaranteed () -> ()
528528
// CHECK-NEXT: return [[RESULT]] : $Optional<any Actor>
529-
func extractIsolation(fn: @escaping @isolated(any) () -> Void) -> (any Actor)? {
529+
func extractIsolation(fn: @escaping @isolated(any) @Sendable () -> Void) -> (any Actor)? {
530530
fn.isolation
531531
}

test/SILGen/isolated_any_conformance.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// introduced a protocol for different task group types.
88

99
struct A<T> {
10-
func enqueue(operation: @escaping @isolated(any) () async -> T) {}
10+
func enqueue(operation: @escaping @isolated(any) @Sendable () async -> T) {}
1111
}
1212

1313
protocol Enqueuer {

test/decl/protocol/conforms/isolated_any.swift

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,7 @@ protocol AnnotatedEnqueuer {
99
associatedtype Result
1010

1111
// expected-note @+1 {{protocol requires function}}
12-
func enqueue(operation: @escaping @isolated(any) () async -> Result)
12+
func enqueue(operation: @escaping @isolated(any) @Sendable () async -> Result)
1313
}
1414

1515
// expected-error @+1 {{type 'A<T>' does not conform to protocol 'AnnotatedEnqueuer'}}

0 commit comments

Comments
 (0)