mirror of
https://github.com/apple/swift.git
synced 2025-12-14 20:36:38 +01:00
This includes a bunch of fixes. It is not exhaustive but fit my time boxed time period I set aside to look at this today. A quick non-exhaustive list: 1. I removed unnecessary verify-additional-prefix lines. 2. Split tests with typechecker error and non-typechecker error components. 3. Removed complete- lines that we used when testing w/without send non sednable. 4. Translated complete-and-tns- lines to be just complete- since they are just testing strict-concurrency=complete and we are not testing complete without send non sendable anymore.
149 lines
5.4 KiB
Swift
149 lines
5.4 KiB
Swift
// RUN: %target-swift-frontend -strict-concurrency=targeted -target %target-swift-5.1-abi-triple %s -o /dev/null -verify -emit-sil -DALLOW_TYPECHECKER_ERRORS -verify-additional-prefix typechecker-
|
|
// RUN: %target-swift-frontend -strict-concurrency=complete -target %target-swift-5.1-abi-triple %s -o /dev/null -verify -emit-sil -DALLOW_TYPECHECKER_ERRORS -verify-additional-prefix typechecker-
|
|
// RUN: %target-swift-frontend -strict-concurrency=complete -target %target-swift-5.1-abi-triple %s -o /dev/null -verify -emit-sil -verify-additional-prefix complete-
|
|
|
|
// REQUIRES: concurrency
|
|
// REQUIRES: asserts
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func someAsyncFunc() async -> String { "" }
|
|
|
|
struct MyError: Error {}
|
|
@available(SwiftStdlib 5.1, *)
|
|
func someThrowingAsyncFunc() async throws -> String { throw MyError() }
|
|
|
|
// ==== Unsafe Continuations ---------------------------------------------------
|
|
|
|
struct Vegetable {}
|
|
|
|
func buyVegetables(
|
|
shoppingList: [String],
|
|
// a) if all veggies were in store, this is invoked *exactly-once*
|
|
onGotAllVegetables: ([Vegetable]) -> (),
|
|
|
|
// b) if not all veggies were in store, invoked one by one (one or more times)
|
|
onGotVegetable: (Vegetable) -> (),
|
|
// b) if at least one onGotVegetable was called *exactly-once*
|
|
// this is invoked once no more veggies will be emitted
|
|
onNoMoreVegetables: () -> (),
|
|
// c) if no veggies _at all_ were available, this is invoked *exactly once*
|
|
onNoVegetablesInStore: (Error) -> ()
|
|
) {}
|
|
|
|
// returns 1 or more vegetables or throws an error
|
|
@available(SwiftStdlib 5.1, *)
|
|
func buyVegetables(shoppingList: [String]) async throws -> [Vegetable] {
|
|
try await withUnsafeThrowingContinuation { continuation in
|
|
var veggies: [Vegetable] = []
|
|
|
|
buyVegetables(
|
|
shoppingList: shoppingList,
|
|
onGotAllVegetables: { veggies in continuation.resume(returning: veggies) },
|
|
onGotVegetable: { v in veggies.append(v) },
|
|
onNoMoreVegetables: { continuation.resume(returning: veggies) },
|
|
onNoVegetablesInStore: { error in continuation.resume(throwing: error) }
|
|
)
|
|
}
|
|
}
|
|
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func test_unsafeContinuations() async {
|
|
// the closure should not allow async operations;
|
|
// after all: if you have async code, just call it directly, without the unsafe continuation
|
|
#if ALLOW_TYPECHECKER_ERRORS
|
|
let _: String = withUnsafeContinuation { continuation in // expected-typechecker-error{{cannot pass function of type '(UnsafeContinuation<String, Never>) async -> Void' to parameter expecting synchronous function type}}
|
|
let s = await someAsyncFunc() // expected-typechecker-note {{'async' inferred from asynchronous operation used here}}
|
|
continuation.resume(returning: s)
|
|
}
|
|
#endif
|
|
|
|
let _: String = await withUnsafeContinuation { continuation in
|
|
continuation.resume(returning: "")
|
|
}
|
|
|
|
// rdar://76475495 - suppress warnings for invalid expressions
|
|
#if ALLOW_TYPECHECKER_ERRORS
|
|
func test_invalid_async_no_warnings() async -> Int {
|
|
return await withUnsafeContinuation {
|
|
$0.resume(throwing: 1) // expected-typechecker-error {{cannot convert value of type 'Int' to expected argument type 'Never'}}
|
|
}
|
|
}
|
|
#endif
|
|
}
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func test_unsafeThrowingContinuations() async throws {
|
|
let _: String = try await withUnsafeThrowingContinuation { continuation in
|
|
continuation.resume(returning: "")
|
|
}
|
|
|
|
let _: String = try await withUnsafeThrowingContinuation { continuation in
|
|
continuation.resume(throwing: MyError())
|
|
}
|
|
|
|
// using resume(with:)
|
|
let _: String = try await withUnsafeThrowingContinuation { continuation in
|
|
let result : Result<String, MyError> = .success("")
|
|
continuation.resume(with: result)
|
|
}
|
|
|
|
let _: String = try await withUnsafeThrowingContinuation { continuation in
|
|
continuation.resume(with: .failure(MyError()))
|
|
}
|
|
|
|
// TODO: Potentially could offer some warnings if we know that a continuation was resumed or escaped at all in a closure?
|
|
}
|
|
|
|
// ==== Sendability ------------------------------------------------------------
|
|
class NotSendable { }
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func test_nonsendableContinuation() async throws {
|
|
let _: NotSendable = try await withUnsafeThrowingContinuation { continuation in
|
|
continuation.resume(returning: NotSendable())
|
|
}
|
|
|
|
let _: NotSendable = try await withUnsafeThrowingContinuation { continuation in
|
|
Task {
|
|
continuation.resume(returning: NotSendable()) // okay
|
|
}
|
|
}
|
|
}
|
|
|
|
// ==== Detached Tasks ---------------------------------------------------------
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func test_detached() async throws {
|
|
let handle = Task.detached {
|
|
await someAsyncFunc() // able to call async functions
|
|
}
|
|
|
|
let result: String = await handle.value
|
|
_ = result
|
|
}
|
|
|
|
@available(SwiftStdlib 5.1, *)
|
|
func test_detached_throwing() async -> String {
|
|
let handle: Task<String, Error> = Task.detached {
|
|
try await someThrowingAsyncFunc() // able to call async functions
|
|
}
|
|
|
|
do {
|
|
return try await handle.value
|
|
} catch {
|
|
print("caught: \(error)")
|
|
}
|
|
|
|
return ""
|
|
}
|
|
|
|
// ==== Detached Tasks with inout Params---------------------------------------
|
|
@available(SwiftStdlib 5.1, *)
|
|
func printOrderNumber(n: inout Int) async { // expected-complete-note {{parameter 'n' is declared 'inout'}}
|
|
Task.detached { // expected-complete-error {{escaping closure captures 'inout' parameter 'n'}}
|
|
n+=1 // expected-complete-note {{captured here}}
|
|
print(n) // expected-complete-note {{captured here}}
|
|
}
|
|
}
|