Skip to content

Commit d33371a

Browse files
authored
Merge pull request #79178 from xedin/execution-attr-in-type-context
[AST/Parse] Initial implementation of `@execution(concurrent | caller)` in type context
2 parents 098f2a9 + aad858d commit d33371a

17 files changed

+279
-44
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2143,6 +2143,18 @@ BridgedTypeAttribute BridgedTypeAttribute_createIsolated(
21432143
BridgedSourceLoc cLPLoc, BridgedSourceLoc cIsolationLoc,
21442144
BridgedIsolatedTypeAttrIsolationKind cIsolation, BridgedSourceLoc cRPLoc);
21452145

2146+
enum ENUM_EXTENSIBILITY_ATTR(closed) BridgedExecutionTypeAttrExecutionKind {
2147+
BridgedExecutionTypeAttrExecutionKind_Concurrent,
2148+
BridgedExecutionTypeAttrExecutionKind_Caller
2149+
};
2150+
2151+
SWIFT_NAME("BridgedTypeAttribute.createExecution(_:atLoc:nameLoc:lpLoc:behaviorLoc:behavior:rpLoc:)")
2152+
BridgedTypeAttribute BridgedTypeAttribute_createExecution(
2153+
BridgedASTContext cContext,
2154+
BridgedSourceLoc cAtLoc, BridgedSourceLoc cNameLoc,
2155+
BridgedSourceLoc cLPLoc, BridgedSourceLoc cBehaviorLoc,
2156+
BridgedExecutionTypeAttrExecutionKind behavior, BridgedSourceLoc cRPLoc);
2157+
21462158
//===----------------------------------------------------------------------===//
21472159
// MARK: TypeReprs
21482160
//===----------------------------------------------------------------------===//

include/swift/AST/Attr.h

Lines changed: 26 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3475,6 +3475,10 @@ class alignas(1 << AttrAlignInBits) TypeAttribute
34753475
SWIFT_INLINE_BITFIELD_FULL(IsolatedTypeAttr, TypeAttribute, 8,
34763476
Kind : 8
34773477
);
3478+
3479+
SWIFT_INLINE_BITFIELD_FULL(ExecutionTypeAttr, TypeAttribute, 8,
3480+
Behavior : 8
3481+
);
34783482
} Bits;
34793483
// clang-format on
34803484

@@ -3740,6 +3744,28 @@ class IsolatedTypeAttr : public SimpleTypeAttrWithArgs<TypeAttrKind::Isolated> {
37403744
void printImpl(ASTPrinter &printer, const PrintOptions &options) const;
37413745
};
37423746

3747+
/// The @execution function type attribute.
3748+
class ExecutionTypeAttr : public SimpleTypeAttrWithArgs<TypeAttrKind::Execution> {
3749+
SourceLoc BehaviorLoc;
3750+
3751+
public:
3752+
ExecutionTypeAttr(SourceLoc atLoc, SourceLoc kwLoc, SourceRange parensRange,
3753+
Located<ExecutionKind> behavior)
3754+
: SimpleTypeAttr(atLoc, kwLoc, parensRange), BehaviorLoc(behavior.Loc) {
3755+
Bits.ExecutionTypeAttr.Behavior = uint8_t(behavior.Item);
3756+
}
3757+
3758+
ExecutionKind getBehavior() const {
3759+
return ExecutionKind(Bits.ExecutionTypeAttr.Behavior);
3760+
}
3761+
3762+
SourceLoc getBehaviorLoc() const {
3763+
return BehaviorLoc;
3764+
}
3765+
3766+
void printImpl(ASTPrinter &printer, const PrintOptions &options) const;
3767+
};
3768+
37433769
using TypeOrCustomAttr =
37443770
llvm::PointerUnion<CustomAttr*, TypeAttribute*>;
37453771

include/swift/AST/DeclAttr.def

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -545,7 +545,6 @@ DECL_ATTR_FEATURE_REQUIREMENT(ABI, ABIAttribute)
545545
DECL_ATTR(execution, Execution,
546546
OnFunc | ABIBreakingToAdd | ABIBreakingToRemove | APIBreakingToAdd | APIBreakingToRemove,
547547
166)
548-
DECL_ATTR_FEATURE_REQUIREMENT(Execution, NonIsolatedAsyncInheritsIsolationFromContext)
549548

550549
LAST_DECL_ATTR(Execution)
551550

include/swift/AST/DiagnosticsParse.def

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1679,6 +1679,14 @@ ERROR(attr_isolated_expected_rparen,none,
16791679
ERROR(attr_isolated_expected_kind,none,
16801680
"expected 'any' as the isolation kind", ())
16811681

1682+
ERROR(attr_execution_expected_lparen,none,
1683+
"expected '(' after '@execution'",
1684+
())
1685+
ERROR(attr_execution_expected_rparen,none,
1686+
"expected ')' after execution behavior", ())
1687+
ERROR(attr_execution_expected_kind,none,
1688+
"expected 'concurrent' or 'caller' as the execution behavior", ())
1689+
16821690
ERROR(attr_private_import_expected_rparen,none,
16831691
"expected ')' after function name for @_private", ())
16841692
ERROR(attr_private_import_expected_sourcefile, none,

include/swift/AST/DiagnosticsSema.def

Lines changed: 19 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -8257,10 +8257,14 @@ ERROR(attr_abi_incompatible_with_silgen_name,none,
82578257
// MARK: @execution Attribute
82588258
//===----------------------------------------------------------------------===//
82598259

8260-
ERROR(attr_execution_concurrent_only_on_async,none,
8261-
"cannot use '@execution(concurrent)' on non-async %kind0",
8260+
ERROR(attr_execution_only_on_async,none,
8261+
"cannot use '@execution' on non-async %kind0",
82628262
(ValueDecl *))
82638263

8264+
ERROR(attr_execution_type_attr_only_on_async,none,
8265+
"cannot use '@execution' on non-async function type",
8266+
())
8267+
82648268
ERROR(attr_execution_concurrent_incompatible_isolated_parameter,none,
82658269
"cannot use '@execution(concurrent)' on %kind0 because it has "
82668270
"an isolated parameter: %1",
@@ -8276,6 +8280,19 @@ ERROR(attr_execution_concurrent_incompatible_with_nonisolated,none,
82768280
"because they serve the same purpose",
82778281
(ValueDecl *))
82788282

8283+
ERROR(attr_execution_concurrent_type_attr_incompatible_with_global_isolation,none,
8284+
"cannot use '@execution(concurrent)' because function type is "
8285+
"isolated to global actor %0",
8286+
(Type))
8287+
8288+
ERROR(attr_execution_concurrent_type_attr_incompatible_with_isolated_param,none,
8289+
"cannot use '@execution(concurrent)' together with isolated parameter",
8290+
())
8291+
8292+
ERROR(attr_execution_concurrent_type_attr_incompatible_with_isolated_any,none,
8293+
"cannot use '@execution(concurrent)' together with @isolated(any)",
8294+
())
8295+
82798296

82808297
#define UNDEFINE_DIAGNOSTIC_MACROS
82818298
#include "DefineDiagnosticMacros.h"

include/swift/AST/TypeAttr.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,7 @@ SIMPLE_TYPE_ATTR(_noMetadata, NoMetadata)
6666
TYPE_ATTR(_opaqueReturnTypeOf, OpaqueReturnTypeOf)
6767
TYPE_ATTR(isolated, Isolated)
6868
SIMPLE_TYPE_ATTR(_addressable, Addressable)
69+
TYPE_ATTR(execution, Execution)
6970

7071
// SIL-specific attributes
7172
SIMPLE_SIL_TYPE_ATTR(async, Async)

lib/AST/Attr.cpp

Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -303,6 +303,23 @@ void IsolatedTypeAttr::printImpl(ASTPrinter &printer,
303303
printer.printStructurePost(PrintStructureKind::BuiltinAttribute);
304304
}
305305

306+
void ExecutionTypeAttr::printImpl(ASTPrinter &printer,
307+
const PrintOptions &options) const {
308+
printer.callPrintStructurePre(PrintStructureKind::BuiltinAttribute);
309+
printer.printAttrName("@execution");
310+
printer << "(";
311+
switch (getBehavior()) {
312+
case ExecutionKind::Concurrent:
313+
printer << "concurrent";
314+
break;
315+
case ExecutionKind::Caller:
316+
printer << "caller";
317+
break;
318+
}
319+
printer << ")";
320+
printer.printStructurePost(PrintStructureKind::BuiltinAttribute);
321+
}
322+
306323
/// Given a name like "inline", return the decl attribute ID that corresponds
307324
/// to it. Note that this is a many-to-one mapping, and that the identifier
308325
/// passed in may only be the first portion of the attribute (e.g. in the case

lib/AST/Bridging/TypeAttributeBridging.cpp

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,3 +91,23 @@ BridgedTypeAttribute BridgedTypeAttribute_createIsolated(
9191
{cLPLoc.unbridged(), cRPLoc.unbridged()},
9292
{isolationKind, cIsolationLoc.unbridged()});
9393
}
94+
95+
BridgedTypeAttribute BridgedTypeAttribute_createExecution(
96+
BridgedASTContext cContext, BridgedSourceLoc cAtLoc,
97+
BridgedSourceLoc cNameLoc, BridgedSourceLoc cLPLoc,
98+
BridgedSourceLoc cBehaviorLoc,
99+
BridgedExecutionTypeAttrExecutionKind behavior, BridgedSourceLoc cRPLoc) {
100+
auto behaviorKind = [=] {
101+
switch (behavior) {
102+
case BridgedExecutionTypeAttrExecutionKind_Concurrent:
103+
return ExecutionKind::Concurrent;
104+
case BridgedExecutionTypeAttrExecutionKind_Caller:
105+
return ExecutionKind::Caller;
106+
}
107+
llvm_unreachable("bad kind");
108+
}();
109+
return new (cContext.unbridged())
110+
ExecutionTypeAttr(cAtLoc.unbridged(), cNameLoc.unbridged(),
111+
{cLPLoc.unbridged(), cRPLoc.unbridged()},
112+
{behaviorKind, cBehaviorLoc.unbridged()});
113+
}

lib/ASTGen/Sources/ASTGen/TypeAttrs.swift

Lines changed: 34 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -91,6 +91,9 @@ extension ASTGenVisitor {
9191
case .isolated:
9292
return self.generateIsolatedTypeAttr(attribute: node)
9393

94+
case .execution:
95+
return self.generateExecutionTypeAttr(attribute: node)
96+
9497
// SIL type attributes are not supported.
9598
case .autoreleased,
9699
.blockStorage,
@@ -173,4 +176,35 @@ extension ASTGenVisitor {
173176
isolationKind: isolationKind,
174177
rpLoc: self.generateSourceLoc(node.rightParen!))
175178
}
179+
180+
func generateExecutionTypeAttr(attribute node: AttributeSyntax) -> BridgedTypeAttribute? {
181+
guard case .argumentList(let executionArgs) = node.arguments,
182+
executionArgs.count == 1,
183+
let labelArg = executionArgs.first,
184+
labelArg.label == nil,
185+
let behaviorExpr = labelArg.expression.as(DeclReferenceExprSyntax.self),
186+
behaviorExpr.argumentNames == nil
187+
else {
188+
// TODO: Diagnose.
189+
return nil
190+
}
191+
192+
var behavior: BridgedExecutionTypeAttrExecutionKind
193+
switch behaviorExpr.baseName {
194+
case "concurrent": behavior = .concurrent
195+
case "caller": behavior = .caller
196+
default:
197+
// TODO: Diagnose.
198+
return nil
199+
}
200+
201+
return BridgedTypeAttribute.createExecution(
202+
self.ctx,
203+
atLoc: self.generateSourceLoc(node.atSign),
204+
nameLoc: self.generateSourceLoc(node.attributeName),
205+
lpLoc: self.generateSourceLoc(node.leftParen!),
206+
behaviorLoc: self.generateSourceLoc(behaviorExpr.baseName),
207+
behavior: behavior,
208+
rpLoc: self.generateSourceLoc(node.rightParen!))
209+
}
176210
}

lib/Parse/ParseDecl.cpp

Lines changed: 44 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4675,6 +4675,50 @@ ParserStatus Parser::parseTypeAttribute(TypeOrCustomAttr &result,
46754675
return makeParserSuccess();
46764676
}
46774677

4678+
case TypeAttrKind::Execution: {
4679+
SourceLoc lpLoc = Tok.getLoc(), behaviorLoc, rpLoc;
4680+
if (!consumeIfNotAtStartOfLine(tok::l_paren)) {
4681+
if (!justChecking) {
4682+
diagnose(Tok, diag::attr_execution_expected_lparen);
4683+
// TODO: should we suggest removing the `@`?
4684+
}
4685+
return makeParserError();
4686+
}
4687+
4688+
bool invalid = false;
4689+
std::optional<ExecutionKind> behavior;
4690+
if (isIdentifier(Tok, "concurrent")) {
4691+
behaviorLoc = consumeToken(tok::identifier);
4692+
behavior = ExecutionKind::Concurrent;
4693+
} else if (isIdentifier(Tok, "caller")) {
4694+
behaviorLoc = consumeToken(tok::identifier);
4695+
behavior = ExecutionKind::Caller;
4696+
} else {
4697+
if (!justChecking) {
4698+
diagnose(Tok, diag::attr_execution_expected_kind);
4699+
}
4700+
invalid = true;
4701+
consumeIf(tok::identifier);
4702+
}
4703+
4704+
if (justChecking && !Tok.is(tok::r_paren))
4705+
return makeParserError();
4706+
if (parseMatchingToken(tok::r_paren, rpLoc,
4707+
diag::attr_execution_expected_rparen,
4708+
lpLoc))
4709+
return makeParserError();
4710+
4711+
if (invalid)
4712+
return makeParserError();
4713+
assert(behavior);
4714+
4715+
if (!justChecking) {
4716+
result = new (Context) ExecutionTypeAttr(AtLoc, attrLoc, {lpLoc, rpLoc},
4717+
{*behavior, behaviorLoc});
4718+
}
4719+
return makeParserSuccess();
4720+
}
4721+
46784722
case TypeAttrKind::Opened: {
46794723
// Parse the opened existential ID string in parens
46804724
SourceLoc beginLoc = Tok.getLoc(), idLoc, endLoc;

lib/Sema/TypeCheckAttr.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -259,8 +259,7 @@ class AttributeChecker : public AttributeVisitor<AttributeChecker> {
259259
return;
260260

261261
if (!F->hasAsync()) {
262-
diagnoseAndRemoveAttr(attr, diag::attr_execution_concurrent_only_on_async,
263-
F);
262+
diagnoseAndRemoveAttr(attr, diag::attr_execution_only_on_async, F);
264263
return;
265264
}
266265

lib/Sema/TypeCheckType.cpp

Lines changed: 45 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4197,6 +4197,51 @@ NeverNullType TypeResolver::resolveASTFunctionType(
41974197
}
41984198
}
41994199

4200+
if (auto executionAttr = claim<ExecutionTypeAttr>(attrs)) {
4201+
if (!repr->isAsync()) {
4202+
diagnoseInvalid(repr, executionAttr->getAtLoc(),
4203+
diag::attr_execution_type_attr_only_on_async);
4204+
}
4205+
4206+
switch (isolation.getKind()) {
4207+
case FunctionTypeIsolation::Kind::NonIsolated:
4208+
break;
4209+
4210+
case FunctionTypeIsolation::Kind::GlobalActor:
4211+
diagnoseInvalid(
4212+
repr, executionAttr->getAtLoc(),
4213+
diag::
4214+
attr_execution_concurrent_type_attr_incompatible_with_global_isolation,
4215+
isolation.getGlobalActorType());
4216+
break;
4217+
4218+
case FunctionTypeIsolation::Kind::Parameter:
4219+
diagnoseInvalid(
4220+
repr, executionAttr->getAtLoc(),
4221+
diag::
4222+
attr_execution_concurrent_type_attr_incompatible_with_isolated_param);
4223+
break;
4224+
4225+
case FunctionTypeIsolation::Kind::Erased:
4226+
diagnoseInvalid(
4227+
repr, executionAttr->getAtLoc(),
4228+
diag::
4229+
attr_execution_concurrent_type_attr_incompatible_with_isolated_any);
4230+
break;
4231+
}
4232+
4233+
if (!repr->isInvalid()) {
4234+
switch (executionAttr->getBehavior()) {
4235+
case ExecutionKind::Concurrent:
4236+
// TODO: We need to introduce a new isolation kind to support this.
4237+
break;
4238+
case ExecutionKind::Caller:
4239+
isolation = FunctionTypeIsolation::forNonIsolated();
4240+
break;
4241+
}
4242+
}
4243+
}
4244+
42004245
if (auto *lifetimeRepr = dyn_cast_or_null<LifetimeDependentTypeRepr>(
42014246
repr->getResultTypeRepr())) {
42024247
diagnoseInvalid(lifetimeRepr, lifetimeRepr->getLoc(),

test/IDE/complete_decl_attribute.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -251,6 +251,7 @@ struct _S {
251251
// ON_METHOD-DAG: Keyword/None: preconcurrency[#Func Attribute#]; name=preconcurrency
252252
// ON_METHOD-DAG: Keyword/None: backDeployed[#Func Attribute#]; name=backDeployed
253253
// ON_METHOD-DAG: Keyword/None: lifetime[#Func Attribute#]; name=lifetime
254+
// ON_METHOD-DAG: Keyword/None: execution[#Func Attribute#]; name=execution
254255
// ON_METHOD-NOT: Keyword
255256
// ON_METHOD-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
256257
// ON_METHOD-DAG: Decl[Struct]/CurrModule: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper
@@ -325,6 +326,7 @@ struct _S {
325326
// ON_MEMBER_LAST-DAG: Keyword/None: freestanding[#Declaration Attribute#]; name=freestanding
326327
// ON_MEMBER_LAST-DAG: Keyword/None: storageRestrictions[#Declaration Attribute#]; name=storageRestrictions
327328
// ON_MEMBER_LAST-DAG: Keyword/None: lifetime[#Declaration Attribute#]; name=lifetime
329+
// ON_MEMBER_LAST-DAG: Keyword/None: execution[#Declaration Attribute#]; name=execution
328330
// ON_MEMBER_LAST-NOT: Keyword
329331
// ON_MEMBER_LAST-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
330332
// ON_MEMBER_LAST-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyPropertyWrapper[#Property Wrapper#]; name=MyPropertyWrapper
@@ -397,6 +399,7 @@ func dummy2() {}
397399
// KEYWORD_LAST-DAG: Keyword/None: attached[#Declaration Attribute#]; name=attached
398400
// KEYWORD_LAST-DAG: Keyword/None: storageRestrictions[#Declaration Attribute#]; name=storageRestrictions
399401
// KEYWORD_LAST-DAG: Keyword/None: lifetime[#Declaration Attribute#]; name=lifetime
402+
// KEYWORD_LAST-DAG: Keyword/None: execution[#Declaration Attribute#]; name=execution
400403
// KEYWORD_LAST-NOT: Keyword
401404
// KEYWORD_LAST-DAG: Decl[Struct]/CurrModule: MyStruct[#MyStruct#]; name=MyStruct
402405
// KEYWORD_LAST-DAG: Decl[Struct]/CurrModule/TypeRelation[Convertible]: MyGenericPropertyWrapper[#Property Wrapper#]; name=MyGenericPropertyWrapper

0 commit comments

Comments
 (0)