1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132
|
// RUN: %target-swift-frontend -typecheck -verify -disable-availability-checking -strict-concurrency=complete -enable-upcoming-feature InferSendableFromCaptures %s
// REQUIRES: asserts
func globalNonisolatedFunction() {}
@MainActor func globalMainActorFunction() {}
actor A {
func actorFunction() {}
func asyncActorFunction() async {}
func asyncThrowsActorFunction() async throws {}
func actorFunctionWithArgs(value: Int) async -> String { "" }
}
func testBasic_sync() {
// TODO: this is a pretty bad diagnostic
let fn: @isolated(any) () -> () = globalNonisolatedFunction // expected-note {{calls to let 'fn' from outside of its actor context are implicitly asynchronous}}
fn() // expected-error {{call to @isolated(any) let 'fn' in a synchronous nonisolated context}}
}
func testBasic_async_noawait() async {
// TODO: this is a pretty bad diagnostic
let fn: @isolated(any) () -> () = globalNonisolatedFunction
// expected-error @+2 {{expression is 'async' but is not marked with 'await'}}
// expected-note @+1 {{calls to let 'fn' from outside of its actor context are implicitly asynchronous}}
fn()
}
func testBasic_async_await() async {
let fn: @isolated(any) () -> () = globalNonisolatedFunction
await fn()
}
func requireSendableIsolatedAny(_ fn: @Sendable @isolated(any) () -> ()) {}
func testEraseFromNonisolated() {
requireSendableIsolatedAny(globalNonisolatedFunction)
}
func testEraseFromGlobalActor() {
requireSendableIsolatedAny(globalMainActorFunction)
}
// Apparently, the only way to get something that Sema will consider
// an actor-instance-isolated `@Sendable` function value is with
// `@_inheritActorContext`.
func requireSendableIsolatedAnyInheritContext(@_inheritActorContext _ fn : @Sendable @isolated(any) () -> ()) {}
extension A {
func testEraseFromActorFunction() {
// This actually works even without @isolated(any), which is a bug.
// But it should definitely work with @isolated(any).
requireSendableIsolatedAnyInheritContext {
self.actorFunction()
}
}
}
func hasIsolatedArgument(actor: isolated A) {}
func requireIsolatedAnyWithActorArgument(_ fn: @Sendable @isolated(any) (A) -> ()) {}
func testEraseFromIsolatedArgument() {
// expected-error @+1 {{cannot convert value of type '@Sendable (isolated A) -> ()' to expected argument type '@isolated(any) @Sendable (A) -> ()'}}
requireIsolatedAnyWithActorArgument(hasIsolatedArgument)
}
func requireSendableNonIsolated(_ fn: @Sendable () -> ()) {}
func testConvertIsolatedAnyToNonIsolated(fn: @Sendable @isolated(any) () -> ()) {
requireSendableNonIsolated(fn)
}
func requireSendableGlobalActor(_ fn: @Sendable @MainActor () -> ()) {}
func testConvertIsolatedAnyToMainActor(fn: @Sendable @isolated(any) () -> ()) {
// expected-error @+1 {{cannot convert value of type '@isolated(any) @Sendable () -> ()' to expected argument type '@MainActor @Sendable () -> ()'}}
requireSendableGlobalActor(fn)
}
func extractFunctionIsolation(_ fn: @isolated(any) @Sendable @escaping () async -> Void) {
let _: (any Actor)? = extractIsolation(fn)
let myActor = A()
let _: (any Actor)? = extractIsolation(myActor.asyncActorFunction)
let _: (any Actor)? = extractIsolation(myActor.asyncThrowsActorFunction)
let _: (any Actor)? = extractIsolation(myActor.actorFunctionWithArgs(value:))
}
func extractFunctionIsolationExpr(
_ fn1: @isolated(any) @Sendable @escaping () async -> Void,
_ fn2: @isolated(any) @Sendable @escaping (Int, String) -> Bool
) {
let _: (any Actor)? = fn1.isolation
let _: (any Actor)? = fn2.isolation
// Only `@isolated(any)` functions have `.isolation`
let myActor = A()
let _: (any Actor)? = myActor.actorFunction.isolation // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
let _: (any Actor)? = myActor.asyncActorFunction.isolation // expected-error {{value of type '@Sendable () async -> ()' has no member 'isolation'}}
let _: (any Actor)? = myActor.asyncThrowsActorFunction.isolation // expected-error {{value of type '@Sendable () async throws -> ()' has no member 'isolation'}}
let _: (any Actor)? = myActor.actorFunctionWithArgs.isolation // expected-error {{value of type '@Sendable (Int) async -> String' has no member 'isolation'}}
let _: (any Actor)? = globalNonisolatedFunction.isolation // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
let _: (any Actor)? = globalMainActorFunction.isolation // expected-error {{value of type '@MainActor @Sendable () -> ()' has no member 'isolation'}}
}
func requireDotIsolation(_ fn: (any Actor)?) -> (any Actor)? { return fn }
func testDotIsolation() {
let _ : (any Actor)? = requireDotIsolation(globalMainActorFunction.isolation) // expected-error {{value of type '@MainActor @Sendable () -> ()' has no member 'isolation'}}
let _ : (any Actor)? = requireDotIsolation(globalNonisolatedFunction.isolation) // expected-error {{value of type '@Sendable () -> ()' has no member 'isolation'}}
}
func testFunctionIsolationExpr1(_ fn: (@isolated(any) () -> Void)?) -> (any Actor)? {
return fn?.isolation
}
func testFunctionIsolationExpr2(_ fn: Optional<(@isolated(any) () -> Void)>) -> Optional<any Actor> {
return fn?.isolation
}
func testFunctionIsolationExprTuple(
_ fn1: (@isolated(any) @Sendable () -> Void)?,
_ fn2: (@isolated(any) @Sendable () -> Void)?
) -> ((any Actor)?, (any Actor)?)
{
return (fn1?.isolation, fn2?.isolation)
}
func nonSendableIsolatedAny(
_ fn: @escaping @isolated(any) () -> Void // expected-note {{parameter 'fn' is implicitly non-sendable}}
) {
let _: @Sendable () -> Void = fn // expected-warning {{using non-sendable parameter 'fn' in a context expecting a @Sendable closure}}
}
|