Skip to content

Commit 203d2c2

Browse files
authored
Merge pull request swiftlang#34573 from DougGregor/async-let
[Concurrency] Implement type checking for 'async let' declarations.
2 parents 937fee4 + 4017888 commit 203d2c2

22 files changed

+477
-22
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -588,6 +588,12 @@ SIMPLE_DECL_ATTR(_specializeExtension, SpecializeExtension,
588588
ABIStableToAdd | ABIStableToRemove | APIStableToAdd | APIStableToRemove,
589589
105)
590590

591+
CONTEXTUAL_SIMPLE_DECL_ATTR(async, Async,
592+
DeclModifier | OnVar | OnFunc | ConcurrencyOnly |
593+
ABIBreakingToAdd | ABIBreakingToRemove |
594+
APIBreakingToAdd | APIBreakingToRemove,
595+
106)
596+
591597
#undef TYPE_ATTR
592598
#undef DECL_ATTR_ALIAS
593599
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Decl.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1784,6 +1784,9 @@ class PatternBindingDecl final : public Decl,
17841784
/// Is the pattern binding entry for this variable currently being computed?
17851785
bool isComputingPatternBindingEntry(const VarDecl *vd) const;
17861786

1787+
/// Is this an "async let" declaration?
1788+
bool isAsyncLet() const;
1789+
17871790
/// Gets the text of the initializer expression for the pattern entry at the
17881791
/// given index, stripping out inactive branches of any #ifs inside the
17891792
/// expression.
@@ -4727,6 +4730,9 @@ class VarDecl : public AbstractStorageDecl {
47274730
/// getSpecifier() == Specifier::Default.
47284731
bool isLet() const { return getIntroducer() == Introducer::Let; }
47294732

4733+
/// Is this an "async let" property?
4734+
bool isAsyncLet() const;
4735+
47304736
Introducer getIntroducer() const {
47314737
return Introducer(Bits.VarDecl.Introducer);
47324738
}

include/swift/AST/DiagnosticsParse.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -324,6 +324,8 @@ ERROR(func_decl_expected_arrow,none,
324324
ERROR(operator_static_in_protocol,none,
325325
"operator '%0' declared in protocol must be 'static'",
326326
(StringRef))
327+
ERROR(async_func_modifier,none,
328+
"'async' must be written after the parameter list of a function", ())
327329

328330
// Enum
329331
ERROR(expected_lbrace_enum,PointsToFirstBadToken,

include/swift/AST/DiagnosticsSema.def

Lines changed: 23 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4067,6 +4067,8 @@ ERROR(throwing_interpolation_without_try,none,
40674067
"interpolation can throw but is not marked with 'try'", ())
40684068
ERROR(throwing_call_without_try,none,
40694069
"call can throw but is not marked with 'try'", ())
4070+
ERROR(throwing_async_let_without_try,none,
4071+
"reading 'async let' can throw but is not marked with 'try'", ())
40704072
NOTE(note_forgot_try,none,
40714073
"did you mean to use 'try'?", ())
40724074
NOTE(note_error_to_optional,none,
@@ -4087,6 +4089,9 @@ ERROR(async_call_without_await,none,
40874089
"call is 'async' but is not marked with 'await'", ())
40884090
ERROR(async_call_without_await_in_autoclosure,none,
40894091
"call is 'async' in an autoclosure argument that is not marked with 'await'", ())
4092+
ERROR(async_call_without_await_in_async_let,none,
4093+
"call is 'async' in an 'async let' initializer that is not marked "
4094+
"with 'await'", ())
40904095
WARNING(no_async_in_await,none,
40914096
"no calls to 'async' functions occur within 'await' expression", ())
40924097
ERROR(async_call_in_illegal_context,none,
@@ -4098,9 +4103,9 @@ ERROR(await_in_illegal_context,none,
40984103
"%select{<<ERROR>>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
40994104
(unsigned))
41004105
ERROR(async_in_nonasync_function,none,
4101-
"%select{'async'|'await'}0 in %select{a function|an autoclosure}1 that "
4102-
"does not support concurrency",
4103-
(bool, bool))
4106+
"%select{'async'|'await'|'async let'}0 in "
4107+
"%select{a function|an autoclosure}1 that does not support concurrency",
4108+
(unsigned, bool))
41044109
NOTE(note_add_async_to_function,none,
41054110
"add 'async' to function %0 to make it asynchronous", (DeclName))
41064111
NOTE(note_add_asynchandler_to_function,none,
@@ -4118,6 +4123,21 @@ NOTE(protocol_witness_async_conflict,none,
41184123
ERROR(async_autoclosure_nonasync_function,none,
41194124
"'async' autoclosure parameter in a non-'async' function", ())
41204125

4126+
ERROR(async_not_let,none,
4127+
"'async' can only be used with 'let' declarations", ())
4128+
ERROR(async_let_not_local,none,
4129+
"'async let' can only be used on local declarations", ())
4130+
ERROR(async_let_not_initialized,none,
4131+
"'async let' binding requires an initializer expression", ())
4132+
ERROR(async_let_no_variables,none,
4133+
"'async let' requires at least one named variable", ())
4134+
ERROR(async_let_without_await,none,
4135+
"reference to async let %0 is not marked with 'await'", (DeclName))
4136+
ERROR(async_let_in_illegal_context,none,
4137+
"async let %0 cannot be referenced in "
4138+
"%select{<<ERROR>>|a default argument|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}1",
4139+
(DeclName, unsigned))
4140+
41214141
ERROR(asynchandler_non_func,none,
41224142
"'@asyncHandler' can only be applied to functions",
41234143
())

include/swift/AST/Expr.h

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3903,7 +3903,10 @@ class AutoClosureExpr : public AbstractClosureExpr {
39033903

39043904
// An autoclosure with type (Self) -> (Args...) -> Result. Formed from type
39053905
// checking a partial application.
3906-
DoubleCurryThunk = 2
3906+
DoubleCurryThunk = 2,
3907+
3908+
// An autoclosure with type () -> Result that was formed for an async let.
3909+
AsyncLet = 3,
39073910
};
39083911

39093912
AutoClosureExpr(Expr *Body, Type ResultTy, unsigned Discriminator,

include/swift/Sema/ConstraintSystem.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4373,7 +4373,8 @@ class ConstraintSystem {
43734373
/// Build implicit autoclosure expression wrapping a given expression.
43744374
/// Given expression represents computed result of the closure.
43754375
Expr *buildAutoClosureExpr(Expr *expr, FunctionType *closureType,
4376-
bool isDefaultWrappedValue = false);
4376+
bool isDefaultWrappedValue = false,
4377+
bool isAsyncLetWrapper = false);
43774378

43784379
/// Builds a type-erased return expression that can be used in dynamic
43794380
/// replacement.

lib/AST/Decl.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1545,6 +1545,13 @@ StaticSpellingKind PatternBindingDecl::getCorrectStaticSpelling() const {
15451545
return getCorrectStaticSpellingForDecl(this);
15461546
}
15471547

1548+
bool PatternBindingDecl::isAsyncLet() const {
1549+
if (auto var = getAnchoringVarDecl(0))
1550+
return var->isAsyncLet();
1551+
1552+
return false;
1553+
}
1554+
15481555

15491556
bool PatternBindingDecl::hasStorage() const {
15501557
// Walk the pattern, to check to see if any of the VarDecls included in it
@@ -5740,6 +5747,10 @@ bool VarDecl::isMemberwiseInitialized(bool preferDeclaredProperties) const {
57405747
return true;
57415748
}
57425749

5750+
bool VarDecl::isAsyncLet() const {
5751+
return getAttrs().hasAttribute<AsyncAttr>();
5752+
}
5753+
57435754
void ParamDecl::setSpecifier(Specifier specifier) {
57445755
// FIXME: Revisit this; in particular shouldn't __owned parameters be
57455756
// ::Let also?

lib/AST/Expr.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2031,6 +2031,7 @@ Expr *AutoClosureExpr::getUnwrappedCurryThunkExpr() const {
20312031

20322032
switch (getThunkKind()) {
20332033
case AutoClosureExpr::Kind::None:
2034+
case AutoClosureExpr::Kind::AsyncLet:
20342035
break;
20352036

20362037
case AutoClosureExpr::Kind::SingleCurryThunk: {

lib/Parse/ParseDecl.cpp

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6558,6 +6558,19 @@ ParserResult<FuncDecl> Parser::parseDeclFunc(SourceLoc StaticLoc,
65586558

65596559
diagnoseWhereClauseInGenericParamList(GenericParams);
65606560

6561+
// If there was an 'async' modifier, put it in the right place for a function.
6562+
bool isAsync = asyncLoc.isValid();
6563+
if (auto asyncAttr = Attributes.getAttribute<AsyncAttr>()) {
6564+
SourceLoc insertLoc = Lexer::getLocForEndOfToken(
6565+
SourceMgr, BodyParams->getRParenLoc());
6566+
6567+
diagnose(asyncAttr->getLocation(), diag::async_func_modifier)
6568+
.fixItRemove(asyncAttr->getRange())
6569+
.fixItInsert(insertLoc, " async");
6570+
asyncAttr->setInvalid();
6571+
isAsync = true;
6572+
}
6573+
65616574
// Create the decl for the func and add it to the parent scope.
65626575
auto *FD = FuncDecl::create(Context, StaticLoc, StaticSpelling,
65636576
FuncLoc, FullName, NameLoc,

lib/SIL/IR/SILDeclRef.cpp

Lines changed: 8 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -447,8 +447,15 @@ bool SILDeclRef::isTransparent() const {
447447

448448
if (hasAutoClosureExpr()) {
449449
auto *ace = getAutoClosureExpr();
450-
if (ace->getThunkKind() == AutoClosureExpr::Kind::None)
450+
switch (ace->getThunkKind()) {
451+
case AutoClosureExpr::Kind::None:
451452
return true;
453+
454+
case AutoClosureExpr::Kind::AsyncLet:
455+
case AutoClosureExpr::Kind::DoubleCurryThunk:
456+
case AutoClosureExpr::Kind::SingleCurryThunk:
457+
break;
458+
}
452459
}
453460

454461
if (hasDecl()) {

0 commit comments

Comments
 (0)