Skip to content

Commit 00af0ee

Browse files
authored
Merge pull request #79975 from xedin/execution-attr-on-closures
[Concurrency] Extend `@execution(...)` attribute support to closures
2 parents 6e9faa1 + 570eedb commit 00af0ee

File tree

6 files changed

+87
-0
lines changed

6 files changed

+87
-0
lines changed

include/swift/AST/DiagnosticsSema.def

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8354,6 +8354,10 @@ ERROR(attr_execution_only_on_async,none,
83548354
"cannot use '@execution' on non-async %kind0",
83558355
(ValueDecl *))
83568356

8357+
ERROR(attr_execution_only_on_async_closure,none,
8358+
"cannot use '@execution' on non-async closure",
8359+
())
8360+
83578361
ERROR(attr_execution_type_attr_only_on_async,none,
83588362
"cannot use '@execution' on non-async function type",
83598363
())

lib/Sema/CSGen.cpp

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2542,6 +2542,16 @@ namespace {
25422542
return FunctionTypeIsolation::forGlobalActor(actorType);
25432543
}
25442544

2545+
if (auto *execution =
2546+
closure->getAttrs().getAttribute<ExecutionAttr>()) {
2547+
switch (execution->getBehavior()) {
2548+
case ExecutionKind::Caller:
2549+
return FunctionTypeIsolation::forNonIsolatedCaller();
2550+
case ExecutionKind::Concurrent:
2551+
return FunctionTypeIsolation::forNonIsolated();
2552+
}
2553+
}
2554+
25452555
return FunctionTypeIsolation::forNonIsolated();
25462556
}();
25472557
extInfo = extInfo.withIsolation(isolation);

lib/Sema/ConstraintSystem.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,6 +1399,12 @@ FunctionType::ExtInfo ClosureEffectsRequest::evaluate(
13991399
bool throws = expr->getThrowsLoc().isValid();
14001400
bool async = expr->getAsyncLoc().isValid();
14011401
bool sendable = expr->getAttrs().hasAttribute<SendableAttr>();
1402+
1403+
// `@execution(...)` attribute is only valid on asynchronous function types.
1404+
if (expr->getAttrs().hasAttribute<ExecutionAttr>()) {
1405+
async = true;
1406+
}
1407+
14021408
if (throws || async) {
14031409
return ASTExtInfoBuilder()
14041410
.withThrows(throws, /*FIXME:*/Type())

lib/Sema/TypeCheckAttr.cpp

Lines changed: 38 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8242,6 +8242,44 @@ class ClosureAttributeChecker
82428242
// Nothing else to check.
82438243
}
82448244

8245+
void visitExecutionAttr(ExecutionAttr *attr) {
8246+
if (!ctx.LangOpts.hasFeature(Feature::ExecutionAttribute)) {
8247+
visitDeclAttribute(attr);
8248+
return;
8249+
}
8250+
8251+
// `@execution(...)` implies `async`.
8252+
if (closure->hasExplicitResultType() &&
8253+
closure->getAsyncLoc().isInvalid()) {
8254+
ctx.Diags
8255+
.diagnose(attr->getLocation(),
8256+
diag::attr_execution_only_on_async_closure)
8257+
.fixItRemove(attr->getRangeWithAt());
8258+
attr->setInvalid();
8259+
}
8260+
8261+
if (auto actorType = getExplicitGlobalActor(closure)) {
8262+
ctx.Diags
8263+
.diagnose(
8264+
attr->getLocation(),
8265+
diag::attr_execution_type_attr_incompatible_with_global_isolation,
8266+
actorType)
8267+
.fixItRemove(attr->getRangeWithAt());
8268+
attr->setInvalid();
8269+
}
8270+
8271+
if (auto *paramList = closure->getParameters()) {
8272+
if (llvm::any_of(*paramList, [](auto *P) { return P->isIsolated(); })) {
8273+
ctx.Diags
8274+
.diagnose(
8275+
attr->getLocation(),
8276+
diag::attr_execution_type_attr_incompatible_with_isolated_param)
8277+
.fixItRemove(attr->getRangeWithAt());
8278+
attr->setInvalid();
8279+
}
8280+
}
8281+
}
8282+
82458283
void visitNonisolatedAttr(NonisolatedAttr *attr) {
82468284
if (attr->isUnsafe() ||
82478285
!ctx.LangOpts.hasFeature(Feature::ClosureIsolation)) {

test/Concurrency/attr_execution_conversions.swift

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -82,6 +82,17 @@ do {
8282
// expected-error@-1 {{cannot convert value of type '(@execution(caller) () async -> ()).Type' to expected argument type '(@isolated(any) () async -> Void).Type'}}
8383
}
8484

85+
do {
86+
let _: () -> Void = { @execution(concurrent) in
87+
// expected-error@-1 {{invalid conversion from 'async' function of type '() async -> Void' to synchronous function type '() -> Void'}}
88+
}
89+
90+
func test(_: () -> Void) {}
91+
92+
test { @execution(caller) in
93+
// expected-error@-1 {{cannot pass function of type '@execution(caller) () async -> ()' to parameter expecting synchronous function type}}
94+
}
95+
}
8596

8697
// Converting to `@execution(caller)` function
8798
class NonSendable {}

test/attr/attr_execution.swift

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -75,3 +75,21 @@ struct InfersMainActor : P {
7575
struct IsolatedType {
7676
@execution(concurrent) func test() async {}
7777
}
78+
79+
_ = { @execution(caller) in // Ok
80+
}
81+
82+
_ = { @execution(concurrent) in // Ok
83+
}
84+
85+
_ = { @MainActor @execution(concurrent) in
86+
// expected-error@-1 {{cannot use '@execution' because function type is isolated to a global actor 'MainActor'}}
87+
}
88+
89+
_ = { @execution(concurrent) () -> Int in
90+
// expected-error@-1 {{'@execution' on non-async closure}}
91+
}
92+
93+
_ = { @execution(caller) (x: isolated (any Actor)?) in
94+
// expected-error@-1 {{cannot use '@execution' together with an isolated parameter}}
95+
}

0 commit comments

Comments
 (0)