Skip to content

[Concurrency] async autoclosures are only legal on async functions. #33446

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 2 commits into from
Aug 13, 2020
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
32 changes: 19 additions & 13 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -2174,9 +2174,6 @@ NOTE(protocol_witness_settable_conflict,none,
"candidate is not settable, but protocol requires it", ())
NOTE(protocol_witness_rethrows_conflict,none,
"candidate is not 'rethrows', but protocol requires it", ())
NOTE(protocol_witness_async_conflict,none,
"candidate is %select{not |}0'async', but protocol requirement is%select{| not}0",
(bool))
NOTE(protocol_witness_throws_conflict,none,
"candidate throws, but protocol does not allow it", ())
NOTE(protocol_witness_not_objc,none,
Expand Down Expand Up @@ -4036,6 +4033,16 @@ NOTE(note_error_to_optional,none,
"did you mean to handle error as optional value?", ())
NOTE(note_disable_error_propagation,none,
"did you mean to disable error propagation?", ())

WARNING(no_throw_in_try,none,
"no calls to throwing functions occur within 'try' expression", ())

WARNING(no_throw_in_do_with_catch,none,
"'catch' block is unreachable because no errors are thrown in 'do' block", ())

//------------------------------------------------------------------------------
// MARK: Concurrency
//------------------------------------------------------------------------------
ERROR(async_call_without_await,none,
"call is 'async' but is not marked with 'await'", ())
ERROR(async_call_without_await_in_autoclosure,none,
Expand All @@ -4056,12 +4063,15 @@ ERROR(async_in_nonasync_function,none,
(bool, bool))
NOTE(note_add_async_to_function,none,
"add 'async' to function %0 to make it asynchronous", (DeclName))

WARNING(no_throw_in_try,none,
"no calls to throwing functions occur within 'try' expression", ())

WARNING(no_throw_in_do_with_catch,none,
"'catch' block is unreachable because no errors are thrown in 'do' block", ())
ERROR(not_objc_function_async,none,
"'async' function cannot be represented in Objective-C", ())
NOTE(not_objc_function_type_async,none,
"'async' function types cannot be represented in Objective-C", ())
NOTE(protocol_witness_async_conflict,none,
"candidate is %select{not |}0'async', but protocol requirement is%select{| not}0",
(bool))
ERROR(async_autoclosure_nonasync_function,none,
"'async' autoclosure parameter in a non-'async' function", ())

//------------------------------------------------------------------------------
// MARK: Type Check Types
Expand Down Expand Up @@ -4417,10 +4427,6 @@ NOTE(not_objc_generic_type_param,none,
NOTE(not_objc_function_type_param,none,
"function types cannot be represented in Objective-C unless their "
"parameters and returns can be", ())
ERROR(not_objc_function_async,none,
"'async' function cannot be represented in Objective-C", ())
NOTE(not_objc_function_type_async,none,
"'async' function types cannot be represented in Objective-C", ())
NOTE(not_objc_function_type_throwing,none,
"throwing function types cannot be represented in Objective-C", ())
NOTE(objc_inferring_on_objc_protocol_member,none,
Expand Down
15 changes: 14 additions & 1 deletion lib/Sema/TypeCheckDecl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2148,9 +2148,22 @@ static Type validateParameterType(ParamDecl *decl) {
decl->setInvalid();
return ErrorType::get(ctx);
}
}

return Ty;
// async autoclosures can only occur as parameters to async functions.
if (decl->isAutoClosure()) {
if (auto fnType = Ty->getAs<FunctionType>()) {
if (fnType->isAsync() &&
!(isa<AbstractFunctionDecl>(dc) &&
cast<AbstractFunctionDecl>(dc)->hasAsync())) {
decl->diagnose(diag::async_autoclosure_nonasync_function);
if (auto func = dyn_cast<FuncDecl>(dc)) {
func->diagnose(diag::note_add_async_to_function, func->getName());
}
}
}
}

return Ty;
}

Expand Down
23 changes: 15 additions & 8 deletions test/expr/unary/async_await.swift
Original file line number Diff line number Diff line change
Expand Up @@ -33,20 +33,27 @@ struct SomeStruct {
static var y = __await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}}
}

func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) { }
func acceptAutoclosureAsync(_: @autoclosure () async -> Int) { }
func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { }
func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { }

func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) { }
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
// expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}}

struct HasAsyncBad {
init(_: @autoclosure () async -> Int) { }
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
}

func testAutoclosure() async {
acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}}
acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
__await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}}
__await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}

acceptAutoclosureAsync(__await getInt())
acceptAutoclosureNonAsync(__await 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 is not marked with 'await'}}
// expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}}
__await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
// expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}}
}

// Test inference of 'async' from the body of a closure.
Expand Down