File: predates_concurrency.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 (334 lines) | stat: -rw-r--r-- 15,410 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
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
271
272
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
300
301
302
303
304
305
306
307
308
309
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
327
328
329
330
331
332
333
334
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -verify-additional-prefix minimal-targeted-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=targeted -verify-additional-prefix minimal-targeted-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -verify-additional-prefix complete-tns-
// RUN: %target-swift-frontend -disable-availability-checking %s -emit-sil -o /dev/null -verify -strict-concurrency=complete -enable-upcoming-feature RegionBasedIsolation -verify-additional-prefix complete-tns-

// REQUIRES: concurrency
// REQUIRES: asserts

@preconcurrency func unsafelySendableClosure(_ closure: @Sendable () -> Void) { }

@preconcurrency func unsafelyMainActorClosure(_ closure: @MainActor () -> Void) { }

@preconcurrency func unsafelyDoEverythingClosure(_ closure: @MainActor @Sendable () -> Void) { }

struct X {
  @preconcurrency func unsafelyDoEverythingClosure(_ closure: @MainActor @Sendable () -> Void) { }

  @preconcurrency var sendableVar: @Sendable () -> Void
  @preconcurrency var mainActorVar: @MainActor () -> Void

  @preconcurrency
  subscript(_: @MainActor () -> Void) -> (@Sendable () -> Void) { {} }

  @preconcurrency
  static subscript(statically _: @MainActor () -> Void) -> (@Sendable () -> Void) { { } }
}

@MainActor func onMainActor() { }

func testInAsync(x: X, plainClosure: () -> Void) async { // expected-note 2{{parameter 'plainClosure' is implicitly non-sendable}}
  let _: Int = unsafelySendableClosure // expected-error{{type '(@Sendable () -> Void) -> ()'}}
  let _: Int = unsafelyMainActorClosure // expected-error{{type '(@MainActor () -> Void) -> ()'}}
  let _: Int = unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = x.unsafelyDoEverythingClosure // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = X.unsafelyDoEverythingClosure // expected-error{{type '(X) -> (@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = (X.unsafelyDoEverythingClosure)(x) // expected-error{{type '(@MainActor @Sendable () -> Void) -> ()'}}

  let _: Int = x.sendableVar // expected-error{{type '@Sendable () -> Void'}}
  let _: Int = x.mainActorVar // expected-error{{type '@MainActor () -> Void'}}

  let _: Int = x[{ onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}
  let _: Int = X[statically: { onMainActor() }] // expected-error{{type '@Sendable () -> Void'}}

  unsafelySendableClosure(plainClosure) // expected-warning {{passing non-sendable parameter 'plainClosure' to function expecting a @Sendable closure}}
  unsafelyMainActorClosure(plainClosure)
  unsafelyDoEverythingClosure(plainClosure) // expected-warning {{passing non-sendable parameter 'plainClosure' to function expecting a @Sendable closure}}
}

func testElsewhere(x: X) {
  let _: Int = unsafelySendableClosure // expected-minimal-targeted-error {{type '(() -> Void) -> ()'}}
  // expected-complete-tns-error @-1 {{type '(@Sendable () -> Void) -> ()'}}
  let _: Int = unsafelyMainActorClosure // expected-minimal-targeted-error {{type '(() -> Void) -> ()'}}
  // expected-complete-tns-error @-1 {{type '(@MainActor () -> Void) -> ()'}}
  let _: Int = unsafelyDoEverythingClosure // expected-minimal-targeted-error {{type '(() -> Void) -> ()'}}
  // expected-complete-tns-error @-1 {{type '(@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = x.unsafelyDoEverythingClosure // expected-minimal-targeted-error{{type '(() -> Void) -> ()'}}
  // expected-complete-tns-error @-1 {{type '(@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = X.unsafelyDoEverythingClosure // expected-minimal-targeted-error{{type '(X) -> (() -> Void) -> ()'}}
  // expected-complete-tns-error @-1 {{type '(X) -> (@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = (X.unsafelyDoEverythingClosure)(x) // expected-minimal-targeted-error{{type '(() -> Void) -> ()'}}
  // expected-complete-tns-error @-1 {{type '(@MainActor @Sendable () -> Void) -> ()'}}
  let _: Int = x.sendableVar // expected-minimal-targeted-error {{type '() -> Void'}}
  // expected-complete-tns-error @-1 {{type '@Sendable () -> Void'}}
  let _: Int = x.mainActorVar // expected-minimal-targeted-error {{type '() -> Void'}}
  // expected-complete-tns-error @-1 {{type '@MainActor () -> Void'}}
  let _: Int = x[{ onMainActor() }] // expected-minimal-targeted-error {{type '() -> Void'}}
  // expected-complete-tns-error @-1 {{type '@Sendable () -> Void'}}
  let _: Int = X[statically: { onMainActor() }] // expected-minimal-targeted-error {{type '() -> Void'}}
  // expected-complete-tns-error @-1 {{type '@Sendable () -> Void'}}
}

@MainActor @preconcurrency func onMainActorAlways() { }
// expected-complete-tns-note @-1 {{calls to global function 'onMainActorAlways()' from outside of its actor context are implicitly asynchronous}}

@preconcurrency @MainActor class MyModelClass {

  // default init() is 'nonisolated' in '-strict-concurrency=complete'

  func f() { }
  // expected-complete-tns-note @-1 {{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}
}

func testCalls(x: X) {
  // expected-complete-tns-note @-1 2{{add '@MainActor' to make global function 'testCalls(x:)' part of global actor 'MainActor'}}
  unsafelyMainActorClosure {
    onMainActor()
  }

  unsafelyDoEverythingClosure {
    onMainActor()
  }

  x.unsafelyDoEverythingClosure {
    onMainActor()
    onMainActorAlways()
  }
  (X.unsafelyDoEverythingClosure)(x)( {
    onMainActor()
    })

  onMainActorAlways() // okay with minimal/targeted concurrency. Not ok with complete.
  // expected-complete-tns-warning @-1 {{call to main actor-isolated global function 'onMainActorAlways()' in a synchronous nonisolated context}}

  // Ok with minimal/targeted concurrency, Not ok with complete.
  let _: () -> Void = onMainActorAlways // expected-complete-tns-warning {{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}}

  let c = MyModelClass()

  // okay with minimal/targeted... an error with complete.
  c.f() // expected-complete-tns-warning {{call to main actor-isolated instance method 'f()' in a synchronous nonisolated context}}
}

func testCallsWithAsync() async {
  onMainActorAlways() // expected-warning{{expression is 'async' but is not marked with 'await'}}
  // expected-note@-1{{calls to global function 'onMainActorAlways()' from outside of its actor context are implicitly asynchronous}}

  let _: () -> Void = onMainActorAlways // expected-warning {{converting function value of type '@MainActor () -> ()' to '() -> Void' loses global actor 'MainActor'}}

  let c = MyModelClass() // expected-minimal-targeted-warning{{expression is 'async' but is not marked with 'await'}}
  // expected-minimal-targeted-note@-1{{calls to initializer 'init()' from outside of its actor context are implicitly asynchronous}}

  c.f() // expected-warning{{expression is 'async' but is not marked with 'await'}}
  // expected-note@-1{{calls to instance method 'f()' from outside of its actor context are implicitly asynchronous}}
}

// ---------------------------------------------------------------------------
// Protocols that inherit Sendable and predate concurrency.
// ---------------------------------------------------------------------------
@preconcurrency protocol P: Sendable { }
protocol Q: P { }

class NS { } // expected-note{{class 'NS' does not conform to the 'Sendable' protocol}}
// expected-complete-tns-note @-1 2{{class 'NS' does not conform to the 'Sendable' protocol}}

struct S1: P {
  var ns: NS // expected-complete-tns-warning {{stored property 'ns' of 'Sendable'-conforming struct 'S1' has non-sendable type 'NS'}}
}

struct S2: Q {
  var ns: NS // expected-complete-tns-warning {{stored property 'ns' of 'Sendable'-conforming struct 'S2' has non-sendable type 'NS'}}
}

struct S3: Q, Sendable {
  var ns: NS // expected-warning{{stored property 'ns' of 'Sendable'-conforming struct 'S3' has non-sendable type 'NS'}}
}

// ---------------------------------------------------------------------------
// Historical attribute names do nothing (but are permitted)
// ---------------------------------------------------------------------------
func aFailedExperiment(@_unsafeSendable _ body: @escaping () -> Void) { }
// expected-warning@-1{{'_unsafeSendable' attribute has been removed in favor of @preconcurrency}}

func anothingFailedExperiment(@_unsafeMainActor _ body: @escaping () -> Void) { }
// expected-warning@-1{{'_unsafeMainActor' attribute has been removed in favor of @preconcurrency}}

// ---------------------------------------------------------------------------
// Random bugs
// ---------------------------------------------------------------------------

public enum StringPlacement : Sendable {
  public typealias StringPosition = @Sendable (_: [String]) -> Int

  @preconcurrency
  public static func position(before string: String) -> StringPosition {
    return { _ in 0 }
  }

  @preconcurrency
  public static func position(after string: String) -> StringPosition {
    return { _ in 0 }
  }
}

func testStringPlacement() {
  let fn1 = StringPlacement.position(before: "Test")
  let _: Int = fn1   // expected-minimal-targeted-error{{cannot convert value of type '([String]) -> Int' to specified type 'Int'}}
  // expected-complete-tns-error @-1 {{type 'StringPlacement.StringPosition' (aka '@Sendable (Array<String>) -> Int')}}

  let fn2 = StringPlacement.position(before:)
  let _: Int = fn2 // expected-minimal-targeted-error{{cannot convert value of type '(String) -> ([String]) -> Int' to specified type 'Int'}}
  // expected-complete-tns-error @-1 {{type '(String) -> StringPlacement.StringPosition' (aka '(String) -> @Sendable (Array<String>) -> Int')}}
}

// @preconcurrency in an outer closure
// (https://github.com/apple/swift/issues/59910)
struct Scheduled<T> { }

@preconcurrency
func doPreconcurrency(_: @Sendable () -> Void) { }

class EventLoop {
  @discardableResult
  @preconcurrency
  func scheduleTask<T>(deadline: Int, _ task: @escaping @Sendable () throws -> T) -> Scheduled<T> { fatalError("") }
}

class C { // expected-complete-tns-note {{'C' does not conform to the 'Sendable' protocol}}
  var ev: EventLoop? = nil

  func test(i: Int) {
    func doNext() { // expected-complete-tns-warning {{concurrently-executed local function 'doNext()' must be marked as '@Sendable'}}
      doPreconcurrency {
        self.ev?.scheduleTask(deadline: i, doNext)
        // expected-complete-tns-warning @-1 {{capture of 'self' with non-sendable type 'C' in a `@Sendable` closure}}
        // expected-complete-tns-warning @-2 {{converting non-sendable function value to '@Sendable () throws -> ()' may introduce data races}}
        // expected-complete-tns-warning @-3 {{capture of 'doNext()' with non-sendable type '() -> ()' in a `@Sendable` closure}}
        // expected-complete-tns-note @-4 {{a function type must be marked '@Sendable' to conform to 'Sendable'}}
        return
      }
    }
  }
}

@preconcurrency @MainActor
class MainActorPreconcurrency {}

class InferMainActorPreconcurrency: MainActorPreconcurrency {
  static func predatesConcurrency() {}
  // expected-note@-1 {{calls to static method 'predatesConcurrency()' from outside of its actor context are implicitly asynchronous}}
}

nonisolated func blah() {
  InferMainActorPreconcurrency.predatesConcurrency()
  // expected-warning@-1 {{call to main actor-isolated static method 'predatesConcurrency()' in a synchronous nonisolated context}}
}

protocol NotIsolated {
  func requirement()
  // expected-complete-tns-note@-1 {{mark the protocol requirement 'requirement()' 'async' to allow actor-isolated conformances}}
}

extension MainActorPreconcurrency: NotIsolated {
  // expected-complete-note@-1{{add '@preconcurrency' to the 'NotIsolated' conformance to suppress isolation-related diagnostics}}{{36-36=@preconcurrency }}
  // expected-complete-tns-note@-2{{add '@preconcurrency' to the 'NotIsolated' conformance to defer isolation checking to run time}}{{36-36=@preconcurrency }}

  func requirement() {}
  // expected-complete-tns-warning@-1 {{main actor-isolated instance method 'requirement()' cannot be used to satisfy nonisolated protocol requirement}}
  // expected-complete-tns-note@-2 {{add 'nonisolated' to 'requirement()' to make this instance method not isolated to the actor}}
  // expected-complete-tns-note@-3 {{calls to instance method 'requirement()' from outside of its actor context are implicitly asynchronous}}


  class Nested {
    weak var c: MainActorPreconcurrency?

    func test() {
    // expected-complete-tns-note@-1 {{add '@MainActor' to make instance method 'test()' part of global actor 'MainActor'}}

      if let c {
        c.requirement()
        // expected-complete-tns-warning@-1 {{call to main actor-isolated instance method 'requirement()' in a synchronous nonisolated context}}
      }
    }
  }
}

// Override matching with @preconcurrency properties.
do {
  class Base {
    @preconcurrency
    open var test1 : ([any Sendable])? // expected-note {{overridden declaration is here}}

    @preconcurrency
    open var test2: [String: [Int: any Sendable]] // expected-note {{overridden declaration is here}}

    @preconcurrency
    open var test3: any Sendable // expected-note {{overridden declaration is here}}

    @preconcurrency
    open var test4: (((Any)?) -> Void)? { // expected-note {{overridden declaration is here}}
      nil
    }

    init() {
      self.test1 = nil
      self.test2 = [:]
      self.test3 = 42
    }
  }

  class Test : Base {
    override var test1: [Any]? {
      // expected-warning@-1 {{declaration 'test1' has a type with different sendability from any potential overrides; this is an error in the Swift 6 language mode}}
      get { nil }
      set { }
    }

    override var test2: [String: [Int: Any]] {
      // expected-warning@-1 {{declaration 'test2' has a type with different sendability from any potential overrides; this is an error in the Swift 6 language mode}}
      get { [:] }
      set {}
    }

    override var test3: Any {
      // expected-warning@-1 {{declaration 'test3' has a type with different sendability from any potential overrides; this is an error in the Swift 6 language mode}}
      get { 42 }
      set { }
    }

    override var test4: (((any Sendable)?) -> Void)? {
      // expected-warning@-1 {{declaration 'test4' has a type with different sendability from any potential overrides; this is an error in the Swift 6 language mode}}
      nil
    }
  }
}

// rdar://132700409 - coercion PartialKeyPath & Sendable -> PartialKeyPath crashes in CSApply
do {
  struct Test {
    enum KeyPath {
      static var member: PartialKeyPath<Test> {
        fatalError()
      }
    }
  }

  struct KeyPathComparator<Compared> {
    @preconcurrency public let keyPath: any PartialKeyPath<Compared> & Sendable

    func testDirect() {
      switch keyPath { // Ok
      case Test.KeyPath.member: break // Ok
      default: break
      }
    }

    func testErasure() {
      let kp: PartialKeyPath<Compared> = keyPath
      switch kp { // Ok
      case Test.KeyPath.member: break // Ok
      default: break
      }
    }
  }
}