Skip to content

Commit 75ea5a5

Browse files
authored
Merge pull request #33446 from DougGregor/async-autoclosure-check
[Concurrency] async autoclosures are only legal on async functions.
2 parents ca28b99 + eda621f commit 75ea5a5

File tree

3 files changed

+48
-22
lines changed

3 files changed

+48
-22
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 19 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -2174,9 +2174,6 @@ NOTE(protocol_witness_settable_conflict,none,
21742174
"candidate is not settable, but protocol requires it", ())
21752175
NOTE(protocol_witness_rethrows_conflict,none,
21762176
"candidate is not 'rethrows', but protocol requires it", ())
2177-
NOTE(protocol_witness_async_conflict,none,
2178-
"candidate is %select{not |}0'async', but protocol requirement is%select{| not}0",
2179-
(bool))
21802177
NOTE(protocol_witness_throws_conflict,none,
21812178
"candidate throws, but protocol does not allow it", ())
21822179
NOTE(protocol_witness_not_objc,none,
@@ -4037,6 +4034,16 @@ NOTE(note_error_to_optional,none,
40374034
"did you mean to handle error as optional value?", ())
40384035
NOTE(note_disable_error_propagation,none,
40394036
"did you mean to disable error propagation?", ())
4037+
4038+
WARNING(no_throw_in_try,none,
4039+
"no calls to throwing functions occur within 'try' expression", ())
4040+
4041+
WARNING(no_throw_in_do_with_catch,none,
4042+
"'catch' block is unreachable because no errors are thrown in 'do' block", ())
4043+
4044+
//------------------------------------------------------------------------------
4045+
// MARK: Concurrency
4046+
//------------------------------------------------------------------------------
40404047
ERROR(async_call_without_await,none,
40414048
"call is 'async' but is not marked with 'await'", ())
40424049
ERROR(async_call_without_await_in_autoclosure,none,
@@ -4057,12 +4064,15 @@ ERROR(async_in_nonasync_function,none,
40574064
(bool, bool))
40584065
NOTE(note_add_async_to_function,none,
40594066
"add 'async' to function %0 to make it asynchronous", (DeclName))
4060-
4061-
WARNING(no_throw_in_try,none,
4062-
"no calls to throwing functions occur within 'try' expression", ())
4063-
4064-
WARNING(no_throw_in_do_with_catch,none,
4065-
"'catch' block is unreachable because no errors are thrown in 'do' block", ())
4067+
ERROR(not_objc_function_async,none,
4068+
"'async' function cannot be represented in Objective-C", ())
4069+
NOTE(not_objc_function_type_async,none,
4070+
"'async' function types cannot be represented in Objective-C", ())
4071+
NOTE(protocol_witness_async_conflict,none,
4072+
"candidate is %select{not |}0'async', but protocol requirement is%select{| not}0",
4073+
(bool))
4074+
ERROR(async_autoclosure_nonasync_function,none,
4075+
"'async' autoclosure parameter in a non-'async' function", ())
40664076

40674077
//------------------------------------------------------------------------------
40684078
// MARK: Type Check Types
@@ -4418,10 +4428,6 @@ NOTE(not_objc_generic_type_param,none,
44184428
NOTE(not_objc_function_type_param,none,
44194429
"function types cannot be represented in Objective-C unless their "
44204430
"parameters and returns can be", ())
4421-
ERROR(not_objc_function_async,none,
4422-
"'async' function cannot be represented in Objective-C", ())
4423-
NOTE(not_objc_function_type_async,none,
4424-
"'async' function types cannot be represented in Objective-C", ())
44254431
NOTE(not_objc_function_type_throwing,none,
44264432
"throwing function types cannot be represented in Objective-C", ())
44274433
NOTE(objc_inferring_on_objc_protocol_member,none,

lib/Sema/TypeCheckDecl.cpp

Lines changed: 14 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2148,9 +2148,22 @@ static Type validateParameterType(ParamDecl *decl) {
21482148
decl->setInvalid();
21492149
return ErrorType::get(ctx);
21502150
}
2151+
}
21512152

2152-
return Ty;
2153+
// async autoclosures can only occur as parameters to async functions.
2154+
if (decl->isAutoClosure()) {
2155+
if (auto fnType = Ty->getAs<FunctionType>()) {
2156+
if (fnType->isAsync() &&
2157+
!(isa<AbstractFunctionDecl>(dc) &&
2158+
cast<AbstractFunctionDecl>(dc)->hasAsync())) {
2159+
decl->diagnose(diag::async_autoclosure_nonasync_function);
2160+
if (auto func = dyn_cast<FuncDecl>(dc)) {
2161+
func->diagnose(diag::note_add_async_to_function, func->getName());
2162+
}
2163+
}
2164+
}
21532165
}
2166+
21542167
return Ty;
21552168
}
21562169

test/expr/unary/async_await.swift

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -33,20 +33,27 @@ struct SomeStruct {
3333
static var y = __await getInt() // expected-error{{'async' call cannot occur in a global variable initializer}}
3434
}
3535

36-
func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) { }
37-
func acceptAutoclosureAsync(_: @autoclosure () async -> Int) { }
36+
func acceptAutoclosureNonAsync(_: @autoclosure () -> Int) async { }
37+
func acceptAutoclosureAsync(_: @autoclosure () async -> Int) async { }
38+
39+
func acceptAutoclosureNonAsyncBad(_: @autoclosure () async -> Int) { }
40+
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
41+
// expected-note@-2{{add 'async' to function 'acceptAutoclosureNonAsyncBad' to make it asynchronous}}
42+
43+
struct HasAsyncBad {
44+
init(_: @autoclosure () async -> Int) { }
45+
// expected-error@-1{{'async' autoclosure parameter in a non-'async' function}}
46+
}
3847

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

43-
acceptAutoclosureAsync(__await getInt())
44-
acceptAutoclosureNonAsync(__await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
52+
__await acceptAutoclosureAsync(__await getInt())
53+
__await acceptAutoclosureNonAsync(__await getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
4554

4655
__await acceptAutoclosureAsync(getInt()) // expected-error{{call is 'async' in an autoclosure argument is not marked with 'await'}}
47-
// expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}}
4856
__await acceptAutoclosureNonAsync(getInt()) // expected-error{{'async' in an autoclosure that does not support concurrency}}
49-
// expected-warning@-1{{no calls to 'async' functions occur within 'await' expression}}
5057
}
5158

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

0 commit comments

Comments
 (0)