Files
swift-mirror/test/expr/unary/async_await.swift
Doug Gregor 3c38ffe0ea [Concurrency] await try -> try await
The `try await` ordering is both easier to read and indicates the order
of operations better, because the suspension point occurs first and
then one can observe a thrown error.
2020-12-23 13:21:59 -08:00

194 lines
7.1 KiB
Swift

// RUN: %target-swift-frontend -typecheck -verify %s -enable-experimental-concurrency -verify-syntax-tree
// REQUIRES: concurrency
func test1(asyncfp : () async -> Int, fp : () -> Int) async {
_ = await asyncfp()
_ = await asyncfp() + asyncfp()
_ = await asyncfp() + fp()
_ = await fp() + 42 // expected-warning {{no calls to 'async' functions occur within 'await' expression}}
_ = asyncfp() // expected-error {{call is 'async' but is not marked with 'await'}}{{7-7=await }}
}
func getInt() async -> Int { return 5 }
// Locations where "await" is prohibited.
func test2(
defaulted: Int = await getInt() // expected-error{{'async' call cannot occur in a default argument}}
) async {
defer {
_ = await getInt() // expected-error{{'async' call cannot occur in a defer body}}
}
print("foo")
}
func test3() { // expected-note{{add 'async' to function 'test3()' to make it asynchronous}} {{none}}
// expected-note@-1{{add '@asyncHandler' to function 'test3()' to create an implicit asynchronous context}}{{1-1=@asyncHandler }}
_ = await getInt() // expected-error{{'async' in a function that does not support concurrency}}
}
enum SomeEnum: Int {
case foo = await 5 // expected-error{{raw value for enum case must be a literal}}
}
struct SomeStruct {
var x = await getInt() // expected-error{{'async' call cannot occur in a property initializer}}
static var y = await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}}
}
func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { }
func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { }
func acceptAutoclosureAsyncThrows(_: @autoclosure () async throws -> Int) async { }
func acceptAutoclosureAsyncThrowsRethrows(_: @autoclosure () async throws -> Int) async rethrows { }
func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) -> Int { 0 }
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
// expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}} {{none}}
struct HasAsyncBad {
init(_: @autoclosure () async -> Int) { }
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
}
func testAutoclosure() async {
await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}}{{32-32=await }}
await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
await acceptAutoclosureAsync(await getInt())
await acceptAutoclosureNonAsync(await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument that is not marked with 'await'}}{{32-32=await }}
await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
}
// Test inference of 'async' from the body of a closure.
func testClosure() {
let closure = {
await getInt()
}
let _: () -> Int = closure // expected-error{{invalid conversion from 'async' function of type '() async -> Int' to synchronous function type '() -> Int'}}
let closure2 = { () async -> Int in
print("here")
return await getInt()
}
let _: () -> Int = closure2 // expected-error{{invalid conversion from 'async' function of type '() async -> Int' to synchronous function type '() -> Int'}}
}
// Nesting async and await together
func throwingAndAsync() async throws -> Int { return 0 }
enum HomeworkError : Error {
case dogAteIt
}
func testThrowingAndAsync() async throws {
_ = try await throwingAndAsync()
_ = await try throwingAndAsync() // expected-warning{{'try' must precede 'await'}}{{7-13=}}{{17-17=await }}
_ = await (try throwingAndAsync())
_ = try (await throwingAndAsync())
// Errors
_ = await throwingAndAsync() // expected-error{{call can throw but is not marked with 'try'}}
// expected-note@-1{{did you mean to use 'try'?}}
// expected-note@-2{{did you mean to handle error as optional value?}}
// expected-note@-3{{did you mean to disable error propagation?}}
_ = try throwingAndAsync() // expected-error{{call is 'async' but is not marked with 'await'}}{{11-11=await }}
}
func testExhaustiveDoCatch() async {
do {
_ = try await throwingAndAsync()
} catch {
}
do {
_ = try await throwingAndAsync()
// expected-error@-1{{errors thrown from here are not handled because the enclosing catch is not exhaustive}}
} catch let e as HomeworkError {
}
// Ensure that we infer 'async' through an exhaustive do-catch.
let fn = {
do {
_ = try await throwingAndAsync()
} catch {
}
}
let _: Int = fn // expected-error{{cannot convert value of type '() async -> ()'}}
// Ensure that we infer 'async' through a non-exhaustive do-catch.
let fn2 = {
do {
_ = try await throwingAndAsync()
} catch let e as HomeworkError {
}
}
let _: Int = fn2 // expected-error{{cannot convert value of type '() async throws -> ()'}}
}
// String interpolation
func testStringInterpolation() async throws {
_ = "Eventually produces \(getInt())" // expected-error{{call is 'async' but is not marked with 'await'}}
_ = "Eventually produces \(await getInt())"
_ = await "Eventually produces \(getInt())"
}
func invalidAsyncFunction() async {
_ = try await throwingAndAsync() // expected-error {{errors thrown from here are not handled}}
}
func validAsyncFunction() async throws {
_ = try await throwingAndAsync()
}
// Async let checking
func mightThrow() throws { }
func getIntUnsafely() throws -> Int { 0 }
func getIntUnsafelyAsync() async throws -> Int { 0 }
extension Error {
var number: Int { 0 }
}
func testAsyncLet() async throws {
async let x = await getInt()
print(x) // expected-error{{reference to async let 'x' is not marked with 'await'}}
print(await x)
do {
try mightThrow()
} catch let e where e.number == x { // expected-error{{async let 'x' cannot be referenced in a catch guard expression}}
} catch {
}
async let x1 = getIntUnsafely() // okay, try is implicit here
async let x2 = getInt() // okay, await is implicit here
async let x3 = try getIntUnsafely()
async let x4 = try! getIntUnsafely()
async let x5 = try? getIntUnsafely()
_ = await x1 // expected-error{{reading 'async let' can throw but is not marked with 'try'}}
_ = await x2
_ = try await x3
_ = await x4
_ = await x5
}
// expected-note@+2 4{{add 'async' to function 'testAsyncLetOutOfAsync()' to make it asynchronous}} {{none}}
// expected-note@+1 4{{add '@asyncHandler' to function 'testAsyncLetOutOfAsync()' to create an implicit asynchronous context}} {{1-1=@asyncHandler }}
func testAsyncLetOutOfAsync() {
async let x = 1 // expected-error{{'async let' in a function that does not support concurrency}}
// FIXME: expected-error@-1{{'async' in a function that does not support concurrency}}
_ = await x // expected-error{{'async let' in a function that does not support concurrency}}
_ = x // expected-error{{'async let' in a function that does not support concurrency}}
}