[Sema] Implement validation of @execution(...) in type context

This commit is contained in:
Pavel Yaskevich
2025-02-05 10:11:38 -08:00
parent 84fb4967cb
commit aad858d66c
5 changed files with 112 additions and 7 deletions

View File

@@ -8257,10 +8257,14 @@ ERROR(attr_abi_incompatible_with_silgen_name,none,
// MARK: @execution Attribute
//===----------------------------------------------------------------------===//
ERROR(attr_execution_concurrent_only_on_async,none,
"cannot use '@execution(concurrent)' on non-async %kind0",
ERROR(attr_execution_only_on_async,none,
"cannot use '@execution' on non-async %kind0",
(ValueDecl *))
ERROR(attr_execution_type_attr_only_on_async,none,
"cannot use '@execution' on non-async function type",
())
ERROR(attr_execution_concurrent_incompatible_isolated_parameter,none,
"cannot use '@execution(concurrent)' on %kind0 because it has "
"an isolated parameter: %1",
@@ -8276,6 +8280,19 @@ ERROR(attr_execution_concurrent_incompatible_with_nonisolated,none,
"because they serve the same purpose",
(ValueDecl *))
ERROR(attr_execution_concurrent_type_attr_incompatible_with_global_isolation,none,
"cannot use '@execution(concurrent)' because function type is "
"isolated to global actor %0",
(Type))
ERROR(attr_execution_concurrent_type_attr_incompatible_with_isolated_param,none,
"cannot use '@execution(concurrent)' together with isolated parameter",
())
ERROR(attr_execution_concurrent_type_attr_incompatible_with_isolated_any,none,
"cannot use '@execution(concurrent)' together with @isolated(any)",
())
#define UNDEFINE_DIAGNOSTIC_MACROS
#include "DefineDiagnosticMacros.h"

View File

@@ -259,8 +259,7 @@ public:
return;
if (!F->hasAsync()) {
diagnoseAndRemoveAttr(attr, diag::attr_execution_concurrent_only_on_async,
F);
diagnoseAndRemoveAttr(attr, diag::attr_execution_only_on_async, F);
return;
}

View File

@@ -4197,6 +4197,51 @@ NeverNullType TypeResolver::resolveASTFunctionType(
}
}
if (auto executionAttr = claim<ExecutionTypeAttr>(attrs)) {
if (!repr->isAsync()) {
diagnoseInvalid(repr, executionAttr->getAtLoc(),
diag::attr_execution_type_attr_only_on_async);
}
switch (isolation.getKind()) {
case FunctionTypeIsolation::Kind::NonIsolated:
break;
case FunctionTypeIsolation::Kind::GlobalActor:
diagnoseInvalid(
repr, executionAttr->getAtLoc(),
diag::
attr_execution_concurrent_type_attr_incompatible_with_global_isolation,
isolation.getGlobalActorType());
break;
case FunctionTypeIsolation::Kind::Parameter:
diagnoseInvalid(
repr, executionAttr->getAtLoc(),
diag::
attr_execution_concurrent_type_attr_incompatible_with_isolated_param);
break;
case FunctionTypeIsolation::Kind::Erased:
diagnoseInvalid(
repr, executionAttr->getAtLoc(),
diag::
attr_execution_concurrent_type_attr_incompatible_with_isolated_any);
break;
}
if (!repr->isInvalid()) {
switch (executionAttr->getBehavior()) {
case ExecutionKind::Concurrent:
// TODO: We need to introduce a new isolation kind to support this.
break;
case ExecutionKind::Caller:
isolation = FunctionTypeIsolation::forNonIsolated();
break;
}
}
}
if (auto *lifetimeRepr = dyn_cast_or_null<LifetimeDependentTypeRepr>(
repr->getResultTypeRepr())) {
diagnoseInvalid(lifetimeRepr, lifetimeRepr->getLoc(),

View File

@@ -0,0 +1,44 @@
// RUN: %target-typecheck-verify-swift -disable-availability-checking
typealias F = @execution(concurrent) () async -> Void
typealias E = @execution(concurrent) () -> Void
// expected-error@-1 {{cannot use '@execution' on non-async function type}}
func test1(_: @execution(caller) (Int...) async -> Void) {}
func test2(_: @execution(concurrent) (Int...) async -> Void) {}
func test_err1(_: @execution(concurrent) @MainActor () async -> Void) {}
// expected-error@-1 {{cannot use '@execution(concurrent)' because function type is isolated to global actor 'MainActor'}}
func test_err2(_: @execution(concurrent) @isolated(any) () async -> Void) {}
// expected-error@-1 {{cannot use '@execution(concurrent)' together with @isolated(any)}}
func test_err3(_: @execution(concurrent) (isolated (any Actor)?) async -> Void) {}
// expected-error@-1 {{cannot use '@execution(concurrent)' together with isolated parameter}}
func test_err4(_: @execution (Int) -> Void) {}
// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}}
// expected-error@-2 {{expected parameter type following ':'}}
func test_err5(_: @execution( () async -> Void) {}
// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}}
// expected-note@-2 {{to match this opening '('}}
// expected-error@-3 {{expected ')' after execution behavior}}
func test_err6(_: @execution(hello) () async -> Void) {}
// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}}
func test_err7(_: @execution(hello () async -> Void) {}
// expected-error@-1 {{expected 'concurrent' or 'caller' as the execution behavior}}
// expected-note@-2 {{to match this opening '('}}
// expected-error@-3 {{expected ')' after execution behavior}}
func test_err8(_: @execution(concurrent) Int) {} // expected-error {{attribute does not apply to type}}
do {
let _ = [@execution(caller) () async -> Void]()
let _ = [@execution(caller) () -> Void]()
// expected-error@-1 {{cannot use '@execution' on non-async function type}}
}

View File

@@ -9,10 +9,10 @@
// expected-error@-1 {{duplicate attribute}} expected-note@-1 {{attribute already specified here}}
@execution(concurrent) func nonAsync1() {}
// expected-error@-1 {{cannot use '@execution(concurrent)' on non-async global function 'nonAsync1()'}}
// expected-error@-1 {{cannot use '@execution' on non-async global function 'nonAsync1()'}}
@execution(caller) func nonAsync2() {}
// expected-error@-1 {{cannot use '@execution(concurrent)' on non-async global function 'nonAsync2()'}}
// expected-error@-1 {{cannot use '@execution' on non-async global function 'nonAsync2()'}}
@execution(concurrent) func testGlobal() async {} // Ok
@@ -21,7 +21,7 @@ struct Test {
// expected-error@-1 {{@execution(concurrent) may only be used on 'func' declarations}}
@execution(concurrent) func member() {}
// expected-error@-1 {{cannot use '@execution(concurrent)' on non-async instance method 'member()'}}
// expected-error@-1 {{cannot use '@execution' on non-async instance method 'member()'}}
@execution(concurrent) func member() async {} // Ok