Skip to content

Commit e152c14

Browse files
authored
Merge pull request #37162 from DougGregor/spawn-let
2 parents 9def053 + 1fa2d16 commit e152c14

22 files changed

+130
-94
lines changed

include/swift/AST/Attr.def

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -657,6 +657,12 @@ SIMPLE_DECL_ATTR(_inheritActorContext, InheritActorContext,
657657
ABIStableToAdd | ABIStableToRemove | APIBreakingToAdd | APIBreakingToRemove,
658658
116)
659659

660+
CONTEXTUAL_SIMPLE_DECL_ATTR(spawn, Spawn,
661+
DeclModifier | OnVar | ConcurrencyOnly |
662+
ABIBreakingToAdd | ABIBreakingToRemove |
663+
APIBreakingToAdd | APIBreakingToRemove,
664+
117)
665+
660666
#undef TYPE_ATTR
661667
#undef DECL_ATTR_ALIAS
662668
#undef CONTEXTUAL_DECL_ATTR_ALIAS

include/swift/AST/Decl.h

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

18641864
/// Is this an "async let" declaration?
1865-
bool isAsyncLet() const;
1865+
bool isSpawnLet() const;
18661866

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

49444944
/// Is this an "async let" property?
4945-
bool isAsyncLet() const;
4945+
bool isSpawnLet() const;
49464946

49474947
Introducer getIntroducer() const {
49484948
return Introducer(Bits.VarDecl.Introducer);

include/swift/AST/DiagnosticsSema.def

Lines changed: 22 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -4231,8 +4231,8 @@ ERROR(throwing_interpolation_without_try,none,
42314231
"interpolation can throw but is not marked with 'try'", ())
42324232
ERROR(throwing_call_without_try,none,
42334233
"call can throw but is not marked with 'try'", ())
4234-
ERROR(throwing_async_let_without_try,none,
4235-
"reading 'async let' can throw but is not marked with 'try'", ())
4234+
ERROR(throwing_spawn_let_without_try,none,
4235+
"reading 'spawn let' can throw but is not marked with 'try'", ())
42364236
ERROR(throwing_prop_access_without_try,none,
42374237
"property access can throw but is not marked with 'try'", ())
42384238
ERROR(throwing_subscript_access_without_try,none,
@@ -4261,8 +4261,8 @@ NOTE(async_access_without_await,none,
42614261

42624262
NOTE(async_call_without_await_in_autoclosure,none,
42634263
"call is 'async' in an autoclosure argument", ())
4264-
NOTE(async_call_without_await_in_async_let,none,
4265-
"call is 'async' in an 'async let' initializer", ())
4264+
NOTE(async_call_without_await_in_spawn_let,none,
4265+
"call is 'async' in an 'spawn let' initializer", ())
42664266

42674267
WARNING(no_async_in_await,none,
42684268
"no 'async' operations occur within 'await' expression", ())
@@ -4275,7 +4275,7 @@ ERROR(await_in_illegal_context,none,
42754275
"%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",
42764276
(unsigned))
42774277
ERROR(async_in_nonasync_function,none,
4278-
"%select{'async'|'async' call|'await'|'async let'|'async' property access|'async' subscript access}0 in "
4278+
"%select{'async'|'async' call|'await'|'spawn let'|'async' property access|'async' subscript access}0 in "
42794279
"%select{a function|an autoclosure}1 that does not support concurrency",
42804280
(unsigned, bool))
42814281
NOTE(note_add_async_to_function,none,
@@ -4302,18 +4302,21 @@ NOTE(protocol_witness_async_conflict,none,
43024302
ERROR(async_autoclosure_nonasync_function,none,
43034303
"'async' autoclosure parameter in a non-'async' function", ())
43044304

4305-
ERROR(async_not_let,none,
4306-
"'async' can only be used with 'let' declarations", ())
4307-
ERROR(async_let_not_local,none,
4308-
"'async let' can only be used on local declarations", ())
4309-
ERROR(async_let_not_initialized,none,
4310-
"'async let' binding requires an initializer expression", ())
4311-
ERROR(async_let_no_variables,none,
4312-
"'async let' requires at least one named variable", ())
4313-
NOTE(async_let_without_await,none,
4314-
"reference to async let %0 is 'async'", (DeclName))
4315-
ERROR(async_let_in_illegal_context,none,
4316-
"async let %0 cannot be referenced in "
4305+
WARNING(async_let_is_spawn_let,none,
4306+
"'async let' is now 'spawn let'", ())
4307+
4308+
ERROR(spawn_not_let,none,
4309+
"'spawn' can only be used with 'let' declarations", ())
4310+
ERROR(spawn_let_not_local,none,
4311+
"'spawn let' can only be used on local declarations", ())
4312+
ERROR(spawn_let_not_initialized,none,
4313+
"'spawn let' binding requires an initializer expression", ())
4314+
ERROR(spawn_let_no_variables,none,
4315+
"'spawn let' requires at least one named variable", ())
4316+
NOTE(spawn_let_without_await,none,
4317+
"reference to spawn let %0 is 'async'", (DeclName))
4318+
ERROR(spawn_let_in_illegal_context,none,
4319+
"spawn let %0 cannot be referenced in "
43174320
"%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",
43184321
(DeclName, unsigned))
43194322

@@ -4403,8 +4406,8 @@ ERROR(actor_isolated_from_concurrent_closure,none,
44034406
ERROR(actor_isolated_from_concurrent_function,none,
44044407
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from a concurrent function",
44054408
(DescriptiveDeclKind, DeclName, unsigned))
4406-
ERROR(actor_isolated_from_async_let,none,
4407-
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from 'async let' initializer",
4409+
ERROR(actor_isolated_from_spawn_let,none,
4410+
"actor-isolated %0 %1 cannot be %select{referenced|mutated|used 'inout'}2 from 'spawn let' initializer",
44084411
(DescriptiveDeclKind, DeclName, unsigned))
44094412
ERROR(actor_isolated_keypath_component,none,
44104413
"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
@@ -4430,7 +4430,7 @@ class ConstraintSystem {
44304430
/// Given expression represents computed result of the closure.
44314431
Expr *buildAutoClosureExpr(Expr *expr, FunctionType *closureType,
44324432
bool isDefaultWrappedValue = false,
4433-
bool isAsyncLetWrapper = false);
4433+
bool isSpawnLetWrapper = false);
44344434

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

lib/AST/Decl.cpp

Lines changed: 4 additions & 4 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::isAsyncLet() const {
1584+
bool PatternBindingDecl::isSpawnLet() const {
15851585
if (auto var = getAnchoringVarDecl(0))
1586-
return var->isAsyncLet();
1586+
return var->isSpawnLet();
15871587

15881588
return false;
15891589
}
@@ -5875,8 +5875,8 @@ bool VarDecl::isMemberwiseInitialized(bool preferDeclaredProperties) const {
58755875
return true;
58765876
}
58775877

5878-
bool VarDecl::isAsyncLet() const {
5879-
return getAttrs().hasAttribute<AsyncAttr>();
5878+
bool VarDecl::isSpawnLet() const {
5879+
return getAttrs().hasAttribute<AsyncAttr>() || getAttrs().hasAttribute<SpawnAttr>();
58805880
}
58815881

58825882
void ParamDecl::setSpecifier(Specifier specifier) {

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->isAsyncLet()) {
443+
} else if (vd->isSpawnLet()) {
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->isAsyncLet()) {
1147+
if (PBD->isSpawnLet()) {
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->isAsyncLet() && accessKind != AccessKind::Write) {
2819+
if (var->isSpawnLet() && 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
@@ -8283,7 +8283,7 @@ static Expr *wrapAsyncLetInitializer(
82838283
ASTContext &ctx = dc->getASTContext();
82848284
Expr *autoclosureExpr = cs.buildAutoClosureExpr(
82858285
initializer, closureType, /*isDefaultWrappedValue=*/false,
8286-
/*isAsyncLetWrapper=*/true);
8286+
/*isSpawnLetWrapper=*/true);
82878287

82888288
// Call the autoclosure so that the AST types line up. SILGen will ignore the
82898289
// actual calls and translate them into a different mechanism.
@@ -8384,7 +8384,7 @@ static Optional<SolutionApplicationTarget> applySolutionToInitialization(
83848384
// For an async let, wrap the initializer appropriately to make it a child
83858385
// task.
83868386
if (auto patternBinding = target.getInitializationPatternBindingDecl()) {
8387-
if (patternBinding->isAsyncLet()) {
8387+
if (patternBinding->isSpawnLet()) {
83888388
resultTarget.setExpr(
83898389
wrapAsyncLetInitializer(
83908390
cs, resultTarget.getAsExpr(), resultTarget.getDeclContext()));

lib/Sema/ConstraintSystem.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2508,7 +2508,7 @@ FunctionType::ExtInfo ConstraintSystem::closureEffects(ClosureExpr *expr) {
25082508
bool walkToDeclPre(Decl *decl) override {
25092509
// Do not walk into function or type declarations.
25102510
if (auto *patternBinding = dyn_cast<PatternBindingDecl>(decl)) {
2511-
if (patternBinding->isAsyncLet())
2511+
if (patternBinding->isSpawnLet())
25122512
FoundAsync = true;
25132513

25142514
return true;
@@ -4972,7 +4972,7 @@ ConstraintSystem::isConversionEphemeral(ConversionRestrictionKind conversion,
49724972
Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr,
49734973
FunctionType *closureType,
49744974
bool isDefaultWrappedValue,
4975-
bool isAsyncLetWrapper) {
4975+
bool isSpawnLetWrapper) {
49764976
auto &Context = DC->getASTContext();
49774977
bool isInDefaultArgumentContext = false;
49784978
if (auto *init = dyn_cast<Initializer>(DC)) {
@@ -4994,7 +4994,7 @@ Expr *ConstraintSystem::buildAutoClosureExpr(Expr *expr,
49944994

49954995
closure->setParameterList(ParameterList::createEmpty(Context));
49964996

4997-
if (isAsyncLetWrapper)
4997+
if (isSpawnLetWrapper)
49984998
closure->setThunkKind(AutoClosureExpr::Kind::AsyncLet);
49994999

50005000
Expr *result = closure;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 20 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -284,6 +284,8 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
284284
void visitActorIndependentAttr(ActorIndependentAttr *attr);
285285
void visitGlobalActorAttr(GlobalActorAttr *attr);
286286
void visitAsyncAttr(AsyncAttr *attr);
287+
void visitSpawnAttr(SpawnAttr *attr);
288+
void visitAsyncOrSpawnAttr(DeclAttribute *attr);
287289
void visitMarkerAttr(MarkerAttr *attr);
288290

289291
void visitReasyncAttr(ReasyncAttr *attr);
@@ -5500,6 +5502,20 @@ void AttributeChecker::visitGlobalActorAttr(GlobalActorAttr *attr) {
55005502
}
55015503

55025504
void AttributeChecker::visitAsyncAttr(AsyncAttr *attr) {
5505+
if (isa<VarDecl>(D)) {
5506+
D->getASTContext().Diags.diagnose(
5507+
attr->getLocation(), diag::async_let_is_spawn_let)
5508+
.fixItReplace(attr->getRange(), "spawn");
5509+
5510+
visitAsyncOrSpawnAttr(attr);
5511+
}
5512+
}
5513+
5514+
void AttributeChecker::visitSpawnAttr(SpawnAttr *attr) {
5515+
visitAsyncOrSpawnAttr(attr);
5516+
}
5517+
5518+
void AttributeChecker::visitAsyncOrSpawnAttr(DeclAttribute *attr) {
55035519
auto var = dyn_cast<VarDecl>(D);
55045520
if (!var)
55055521
return;
@@ -5510,7 +5526,7 @@ void AttributeChecker::visitAsyncAttr(AsyncAttr *attr) {
55105526

55115527
// "Async" modifier can only be applied to local declarations.
55125528
if (!patternBinding->getDeclContext()->isLocalContext()) {
5513-
diagnoseAndRemoveAttr(attr, diag::async_let_not_local);
5529+
diagnoseAndRemoveAttr(attr, diag::spawn_let_not_local);
55145530
return;
55155531
}
55165532

@@ -5531,21 +5547,21 @@ void AttributeChecker::visitAsyncAttr(AsyncAttr *attr) {
55315547
// Each entry must bind at least one named variable, so that there is
55325548
// something to "await".
55335549
if (!foundAnyVariable) {
5534-
diagnose(pattern->getLoc(), diag::async_let_no_variables);
5550+
diagnose(pattern->getLoc(), diag::spawn_let_no_variables);
55355551
attr->setInvalid();
55365552
return;
55375553
}
55385554

55395555
// Async can only be used on an "async let".
55405556
if (!isLet && !diagnosedVar) {
5541-
diagnose(patternBinding->getLoc(), diag::async_not_let)
5557+
diagnose(patternBinding->getLoc(), diag::spawn_not_let)
55425558
.fixItReplace(patternBinding->getLoc(), "let");
55435559
diagnosedVar = true;
55445560
}
55455561

55465562
// Each pattern entry must have an initializer expression.
55475563
if (patternBinding->getEqualLoc(index).isInvalid()) {
5548-
diagnose(pattern->getLoc(), diag::async_let_not_initialized);
5564+
diagnose(pattern->getLoc(), diag::spawn_let_not_initialized);
55495565
attr->setInvalid();
55505566
return;
55515567
}

0 commit comments

Comments
 (0)