Skip to content

Commit 40c7341

Browse files
authored
Merge pull request #37306 from DougGregor/async-let-family
Reinstate "async let", with "spawn let" as an alias.
2 parents 1496c20 + 38b652d commit 40c7341

21 files changed

+128
-101
lines changed

include/swift/AST/Decl.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1865,7 +1865,7 @@ class PatternBindingDecl final : public Decl,
18651865
bool isComputingPatternBindingEntry(const VarDecl *vd) const;
18661866

18671867
/// Is this an "async let" declaration?
1868-
bool isSpawnLet() const;
1868+
bool isAsyncLet() const;
18691869

18701870
/// Gets the text of the initializer expression for the pattern entry at the
18711871
/// given index, stripping out inactive branches of any #ifs inside the
@@ -4945,7 +4945,7 @@ class VarDecl : public AbstractStorageDecl {
49454945
bool isLet() const { return getIntroducer() == Introducer::Let; }
49464946

49474947
/// Is this an "async let" property?
4948-
bool isSpawnLet() const;
4948+
bool isAsyncLet() const;
49494949

49504950
Introducer getIntroducer() const {
49514951
return Introducer(Bits.VarDecl.Introducer);

include/swift/AST/DiagnosticsSema.def

Lines changed: 19 additions & 22 deletions
Original file line numberDiff line numberDiff line change
@@ -4246,8 +4246,8 @@ ERROR(throwing_interpolation_without_try,none,
42464246
"interpolation can throw but is not marked with 'try'", ())
42474247
ERROR(throwing_call_without_try,none,
42484248
"call can throw but is not marked with 'try'", ())
4249-
ERROR(throwing_spawn_let_without_try,none,
4250-
"reading 'spawn let' can throw but is not marked with 'try'", ())
4249+
ERROR(throwing_async_let_without_try,none,
4250+
"reading 'async let' can throw but is not marked with 'try'", ())
42514251
ERROR(throwing_prop_access_without_try,none,
42524252
"property access can throw but is not marked with 'try'", ())
42534253
ERROR(throwing_subscript_access_without_try,none,
@@ -4276,8 +4276,8 @@ NOTE(async_access_without_await,none,
42764276

42774277
NOTE(async_call_without_await_in_autoclosure,none,
42784278
"call is 'async' in an autoclosure argument", ())
4279-
NOTE(async_call_without_await_in_spawn_let,none,
4280-
"call is 'async' in an 'spawn let' initializer", ())
4279+
NOTE(async_call_without_await_in_async_let,none,
4280+
"call is 'async' in an 'async let' initializer", ())
42814281

42824282
WARNING(no_async_in_await,none,
42834283
"no 'async' operations occur within 'await' expression", ())
@@ -4290,7 +4290,7 @@ ERROR(await_in_illegal_context,none,
42904290
"%select{<<ERROR>>|a default argument|a property wrapper initializer|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}0",
42914291
(unsigned))
42924292
ERROR(async_in_nonasync_function,none,
4293-
"%select{'async'|'async' call|'await'|'spawn let'|'async' property access|'async' subscript access}0 in "
4293+
"%select{'async'|'async' call|'await'|'async let'|'async' property access|'async' subscript access}0 in "
42944294
"%select{a function|an autoclosure}1 that does not support concurrency",
42954295
(unsigned, bool))
42964296
NOTE(note_add_async_to_function,none,
@@ -4317,21 +4317,18 @@ NOTE(protocol_witness_async_conflict,none,
43174317
ERROR(async_autoclosure_nonasync_function,none,
43184318
"'async' autoclosure parameter in a non-'async' function", ())
43194319

4320-
WARNING(async_let_is_spawn_let,none,
4321-
"'async let' is now 'spawn let'", ())
4322-
4323-
ERROR(spawn_not_let,none,
4324-
"'spawn' can only be used with 'let' declarations", ())
4325-
ERROR(spawn_let_not_local,none,
4326-
"'spawn let' can only be used on local declarations", ())
4327-
ERROR(spawn_let_not_initialized,none,
4328-
"'spawn let' binding requires an initializer expression", ())
4329-
ERROR(spawn_let_no_variables,none,
4330-
"'spawn let' requires at least one named variable", ())
4331-
NOTE(spawn_let_without_await,none,
4332-
"reference to spawn let %0 is 'async'", (DeclName))
4333-
ERROR(spawn_let_in_illegal_context,none,
4334-
"spawn let %0 cannot be referenced in "
4320+
ERROR(async_not_let,none,
4321+
"'async' can only be used with 'let' declarations", ())
4322+
ERROR(async_let_not_local,none,
4323+
"'async let' can only be used on local declarations", ())
4324+
ERROR(async_let_not_initialized,none,
4325+
"'async let' binding requires an initializer expression", ())
4326+
ERROR(async_let_no_variables,none,
4327+
"'async let' requires at least one named variable", ())
4328+
NOTE(async_let_without_await,none,
4329+
"reference to async let %0 is 'async'", (DeclName))
4330+
ERROR(async_let_in_illegal_context,none,
4331+
"async let %0 cannot be referenced in "
43354332
"%select{<<ERROR>>|a default argument|a property wrapper initializer|a property initializer|a global variable initializer|an enum case raw value|a catch pattern|a catch guard expression|a defer body}1",
43364333
(DeclName, unsigned))
43374334

@@ -4428,8 +4425,8 @@ ERROR(actor_isolated_from_concurrent_closure,none,
44284425
ERROR(actor_isolated_from_concurrent_function,none,
44294426
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from a concurrent function",
44304427
(DescriptiveDeclKind, DeclName, unsigned))
4431-
ERROR(actor_isolated_from_spawn_let,none,
4432-
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from 'spawn let' initializer",
4428+
ERROR(actor_isolated_from_async_let,none,
4429+
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from 'async let' initializer",
44334430
(DescriptiveDeclKind, DeclName, unsigned))
44344431
ERROR(actor_isolated_keypath_component,none,
44354432
"cannot form key path to actor-isolated %0 %1",

include/swift/Sema/ConstraintSystem.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -4431,7 +4431,7 @@ class ConstraintSystem {
44314431
/// Given expression represents computed result of the closure.
44324432
Expr *buildAutoClosureExpr(Expr *expr, FunctionType *closureType,
44334433
bool isDefaultWrappedValue = false,
4434-
bool isSpawnLetWrapper = false);
4434+
bool isAsyncLetWrapper = false);
44354435

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

lib/AST/Decl.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1581,9 +1581,9 @@ StaticSpellingKind PatternBindingDecl::getCorrectStaticSpelling() const {
15811581
return getCorrectStaticSpellingForDecl(this);
15821582
}
15831583

1584-
bool PatternBindingDecl::isSpawnLet() const {
1584+
bool PatternBindingDecl::isAsyncLet() const {
15851585
if (auto var = getAnchoringVarDecl(0))
1586-
return var->isSpawnLet();
1586+
return var->isAsyncLet();
15871587

15881588
return false;
15891589
}
@@ -5877,7 +5877,7 @@ bool VarDecl::isMemberwiseInitialized(bool preferDeclaredProperties) const {
58775877
return true;
58785878
}
58795879

5880-
bool VarDecl::isSpawnLet() const {
5880+
bool VarDecl::isAsyncLet() const {
58815881
return getAttrs().hasAttribute<AsyncAttr>() || getAttrs().hasAttribute<SpawnAttr>();
58825882
}
58835883

lib/SILGen/SILGenDecl.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -440,7 +440,7 @@ class LetValueInitialization : public Initialization {
440440
// buffer. DI will make sure it is only assigned to once.
441441
needsTemporaryBuffer = true;
442442
isUninitialized = true;
443-
} else if (vd->isSpawnLet()) {
443+
} else if (vd->isAsyncLet()) {
444444
// If this is an async let, treat it like a let-value without an
445445
// initializer. The initializer runs concurrently in a child task,
446446
// and value will be initialized at the point the variable in the
@@ -1144,7 +1144,7 @@ void SILGenFunction::emitPatternBinding(PatternBindingDecl *PBD,
11441144

11451145
// If this is an async let, create a child task to compute the initializer
11461146
// value.
1147-
if (PBD->isSpawnLet()) {
1147+
if (PBD->isAsyncLet()) {
11481148
// Look through the implicit await (if present), try (if present), and
11491149
// call to reach the autoclosure that computes the value.
11501150
auto *init = PBD->getExecutableInit(idx);

lib/SILGen/SILGenLValue.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2816,7 +2816,7 @@ SILGenFunction::maybeEmitValueOfLocalVarDecl(
28162816
if (It != VarLocs.end()) {
28172817
// If the variable is part of an async let, ensure that the child task
28182818
// has completed first.
2819-
if (var->isSpawnLet() && accessKind != AccessKind::Write) {
2819+
if (var->isAsyncLet() && accessKind != AccessKind::Write) {
28202820
auto patternBinding = var->getParentPatternBinding();
28212821
unsigned index = patternBinding->getPatternEntryIndexForVarDecl(var);
28222822
completeAsyncLetChildTask(patternBinding, index);

lib/Sema/CSApply.cpp

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8316,7 +8316,7 @@ static Expr *wrapAsyncLetInitializer(
83168316
ASTContext &ctx = dc->getASTContext();
83178317
Expr *autoclosureExpr = cs.buildAutoClosureExpr(
83188318
initializer, closureType, /*isDefaultWrappedValue=*/false,
8319-
/*isSpawnLetWrapper=*/true);
8319+
/*isAsyncLetWrapper=*/true);
83208320

83218321
// Call the autoclosure so that the AST types line up. SILGen will ignore the
83228322
// actual calls and translate them into a different mechanism.
@@ -8417,7 +8417,7 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
84178417
// For an async let, wrap the initializer appropriately to make it a child
84188418
// task.
84198419
if (auto patternBinding = target.getInitializationPatternBindingDecl()) {
8420-
if (patternBinding->isSpawnLet()) {
8420+
if (patternBinding->isAsyncLet()) {
84218421
resultTarget.setExpr(
84228422
wrapAsyncLetInitializer(
84238423
cs, resultTarget.getAsExpr(), resultTarget.getDeclContext()));

lib/Sema/ConstraintSystem.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4945,7 +4945,7 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
49454945
Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr,
49464946
FunctionType *closureType,
49474947
bool isDefaultWrappedValue,
4948-
bool isSpawnLetWrapper) {
4948+
bool isAsyncLetWrapper) {
49494949
auto &Context = DC->getASTContext();
49504950
bool isInDefaultArgumentContext = false;
49514951
if (auto *init = dyn_cast<Initializer>(DC)) {
@@ -4967,7 +4967,7 @@ Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr,
49674967

49684968
closure->setParameterList(ParameterList::createEmpty(Context));
49694969

4970-
if (isSpawnLetWrapper)
4970+
if (isAsyncLetWrapper)
49714971
closure->setThunkKind(AutoClosureExpr::Kind::AsyncLet);
49724972

49734973
Expr *result = closure;
@@ -5709,7 +5709,7 @@ ASTNode constraints::findAsyncNode(ClosureExpr *closure) {
57095709
bool walkToDeclPre(Decl *decl) override {
57105710
// Do not walk into function or type declarations.
57115711
if (auto *patternBinding = dyn_cast<PatternBindingDecl>(decl)) {
5712-
if (patternBinding->isSpawnLet())
5712+
if (patternBinding->isAsyncLet())
57135713
AsyncNode = patternBinding;
57145714

57155715
return true;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -5503,10 +5503,6 @@ void AttributeChecker::visitGlobalActorAttr(GlobalActorAttr *attr) {
55035503

55045504
void AttributeChecker::visitAsyncAttr(AsyncAttr *attr) {
55055505
if (isa<VarDecl>(D)) {
5506-
D->getASTContext().Diags.diagnose(
5507-
attr->getLocation(), diag::async_let_is_spawn_let)
5508-
.fixItReplace(attr->getRange(), "spawn");
5509-
55105506
visitAsyncOrSpawnAttr(attr);
55115507
}
55125508
}
@@ -5526,7 +5522,7 @@ void AttributeChecker::visitAsyncOrSpawnAttr(DeclAttribute *attr) {
55265522

55275523
// "Async" modifier can only be applied to local declarations.
55285524
if (!patternBinding->getDeclContext()->isLocalContext()) {
5529-
diagnoseAndRemoveAttr(attr, diag::spawn_let_not_local);
5525+
diagnoseAndRemoveAttr(attr, diag::async_let_not_local);
55305526
return;
55315527
}
55325528

@@ -5547,21 +5543,21 @@ void AttributeChecker::visitAsyncOrSpawnAttr(DeclAttribute *attr) {
55475543
// Each entry must bind at least one named variable, so that there is
55485544
// something to "await".
55495545
if (!foundAnyVariable) {
5550-
diagnose(pattern->getLoc(), diag::spawn_let_no_variables);
5546+
diagnose(pattern->getLoc(), diag::async_let_no_variables);
55515547
attr->setInvalid();
55525548
return;
55535549
}
55545550

55555551
// Async can only be used on an "async let".
55565552
if (!isLet && !diagnosedVar) {
5557-
diagnose(patternBinding->getLoc(), diag::spawn_not_let)
5553+
diagnose(patternBinding->getLoc(), diag::async_not_let)
55585554
.fixItReplace(patternBinding->getLoc(), "let");
55595555
diagnosedVar = true;
55605556
}
55615557

55625558
// Each pattern entry must have an initializer expression.
55635559
if (patternBinding->getEqualLoc(index).isInvalid()) {
5564-
diagnose(pattern->getLoc(), diag::spawn_let_not_initialized);
5560+
diagnose(pattern->getLoc(), diag::async_let_not_initialized);
55655561
attr->setInvalid();
55665562
return;
55675563
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2044,7 +2044,7 @@ namespace {
20442044
if (auto autoclosure = dyn_cast<AutoClosureExpr>(dc)) {
20452045
switch (autoclosure->getThunkKind()) {
20462046
case AutoClosureExpr::Kind::AsyncLet:
2047-
return diag::actor_isolated_from_spawn_let;
2047+
return diag::actor_isolated_from_async_let;
20482048

20492049
case AutoClosureExpr::Kind::DoubleCurryThunk:
20502050
case AutoClosureExpr::Kind::SingleCurryThunk:

lib/Sema/TypeCheckEffects.cpp

Lines changed: 10 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -418,7 +418,7 @@ class EffectsHandlingWalker : public ASTWalker {
418418
if (auto ic = dyn_cast<IfConfigDecl>(D)) {
419419
recurse = asImpl().checkIfConfig(ic);
420420
} else if (auto patternBinding = dyn_cast<PatternBindingDecl>(D)) {
421-
if (patternBinding->isSpawnLet())
421+
if (patternBinding->isAsyncLet())
422422
recurse = asImpl().checkAsyncLet(patternBinding);
423423
} else {
424424
recurse = ShouldNotRecurse;
@@ -1689,7 +1689,7 @@ class Context {
16891689
bool suggestTryFixIt = reasonKind == PotentialEffectReason::Kind::Apply;
16901690

16911691
if (reasonKind == PotentialEffectReason::Kind::AsyncLet) {
1692-
message = diag::throwing_spawn_let_without_try;
1692+
message = diag::throwing_async_let_without_try;
16931693

16941694
} else if (reasonKind == PotentialEffectReason::Kind::PropertyAccess) {
16951695
message = diag::throwing_prop_access_without_try;
@@ -1922,20 +1922,20 @@ class Context {
19221922

19231923
if (auto declRef = dyn_cast<DeclRefExpr>(e)) {
19241924
if (auto var = dyn_cast<VarDecl>(declRef->getDecl())) {
1925-
if (var->isSpawnLet()) {
1925+
if (var->isAsyncLet()) {
19261926
Diags.diagnose(
1927-
e->getLoc(), diag::spawn_let_in_illegal_context,
1927+
e->getLoc(), diag::async_let_in_illegal_context,
19281928
var->getName(), static_cast<unsigned>(getKind()));
19291929
return;
19301930
}
19311931
}
19321932
}
19331933
} else if (auto patternBinding = dyn_cast_or_null<PatternBindingDecl>(
19341934
node.dyn_cast<Decl *>())) {
1935-
if (patternBinding->isSpawnLet()) {
1935+
if (patternBinding->isAsyncLet()) {
19361936
auto var = patternBinding->getAnchoringVarDecl(0);
19371937
Diags.diagnose(
1938-
e->getLoc(), diag::spawn_let_in_illegal_context,
1938+
e->getLoc(), diag::async_let_in_illegal_context,
19391939
var->getName(), static_cast<unsigned>(getKind()));
19401940
return;
19411941
}
@@ -2529,7 +2529,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
25292529
// "Async let" declarations are treated as an asynchronous call
25302530
// (to the underlying task's "get"). If the initializer was throwing,
25312531
// then the access is also treated as throwing.
2532-
if (var->isSpawnLet()) {
2532+
if (var->isAsyncLet()) {
25332533
// If the initializer could throw, we will have a 'try' in the
25342534
// application of its autoclosure.
25352535
bool throws = false;
@@ -2831,9 +2831,9 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
28312831
case PotentialEffectReason::Kind::AsyncLet:
28322832
if (auto declR = dyn_cast<DeclRefExpr>(&diag.expr)) {
28332833
if (auto var = dyn_cast<VarDecl>(declR->getDecl())) {
2834-
if (var->isSpawnLet()) {
2834+
if (var->isAsyncLet()) {
28352835
Ctx.Diags.diagnose(declR->getLoc(),
2836-
diag::spawn_let_without_await,
2836+
diag::async_let_without_await,
28372837
var->getName());
28382838
continue;
28392839
}
@@ -2862,7 +2862,7 @@ class CheckEffectsCoverage : public EffectsHandlingWalker<CheckEffectsCoverage>
28622862
break;
28632863
case AutoClosureExpr::Kind::AsyncLet:
28642864
Ctx.Diags.diagnose(diag.expr.getStartLoc(),
2865-
diag::async_call_without_await_in_spawn_let);
2865+
diag::async_call_without_await_in_async_let);
28662866
break;
28672867
case AutoClosureExpr::Kind::SingleCurryThunk:
28682868
case AutoClosureExpr::Kind::DoubleCurryThunk:

stdlib/public/CompatibilityOverride/CompatibilityOverrideConcurrency.def

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -100,10 +100,10 @@ OVERRIDE_TASK(task_create_group_future_common, AsyncTaskAndContext, , , ,
100100
(JobFlags flags, TaskGroup *group,
101101
const Metadata *futureResultType,
102102
FutureAsyncSignature::FunctionType *function,
103-
void *closureContext, bool isSpawnLetTask,
103+
void *closureContext, bool isAsyncLetTask,
104104
size_t initialContextSize),
105105
(flags, group, futureResultType, function, closureContext,
106-
isSpawnLetTask, initialContextSize))
106+
isAsyncLetTask, initialContextSize))
107107

108108
OVERRIDE_TASK(task_future_wait, void, SWIFT_EXPORT_FROM(swift_Concurrency),
109109
SWIFT_CC(swiftasync), swift::,

0 commit comments

Comments
 (0)