File: isolated_any.swift

package info (click to toggle)
swiftlang 6.0.3-2
  • links: PTS, VCS
  • area: main
  • in suites: forky, sid, trixie
  • size: 2,519,992 kB
  • sloc: cpp: 9,107,863; ansic: 2,040,022; asm: 1,135,751; python: 296,500; objc: 82,456; f90: 60,502; lisp: 34,951; pascal: 19,946; sh: 18,133; perl: 7,482; ml: 4,937; javascript: 4,117; makefile: 3,840; awk: 3,535; xml: 914; fortran: 619; cs: 573; ruby: 573
file content (132 lines) | stat: -rw-r--r-- 5,749 bytes parent folder | download
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}}
}