Skip to content

Commit 255009d

Browse files
committed
Implement #isolation macro to produce the isolation of the current context
Introduce a new expression macro that produces an value of type `(any AnyActor)?` that describes the current actor isolation. This isolation will be `nil` in non-isolated code, and refer to either the actor instance of shared global actor in other cases. This is currently behind the experimental feature flag OptionalIsolatedParameters.
1 parent e6a0641 commit 255009d

File tree

20 files changed

+306
-14
lines changed

20 files changed

+306
-14
lines changed

include/swift/AST/ASTBridging.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1492,7 +1492,9 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedMacroDefinitionKind : size_t {
14921492
/// or the new spelling `#externalMacro(module: "Module", type: "Type")`.
14931493
BridgedExternalMacro,
14941494
/// The builtin definition for "externalMacro".
1495-
BridgedBuiltinExternalMacro
1495+
BridgedBuiltinExternalMacro,
1496+
/// The builtin definition for the "isolation" macro.
1497+
BridgedBuiltinIsolationMacro,
14961498
};
14971499

14981500
SWIFT_NAME("BridgedGenericParamList.createParsed(_:leftAngleLoc:parameters:"

include/swift/AST/DiagnosticsSema.def

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5564,6 +5564,8 @@ ERROR(isolated_parameter_global_actor_type,none,
55645564
ERROR(isolated_parameter_combined_nonisolated,none,
55655565
"%0 with 'isolated' parameter cannot be 'nonisolated'",
55665566
(DescriptiveDeclKind))
5567+
ERROR(isolation_macro_experimental,none,
5568+
"#isolation macro is experimental", ())
55675569

55685570
NOTE(in_derived_conformance, none,
55695571
"in derived conformance to %0",

include/swift/AST/Expr.h

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6089,6 +6089,39 @@ class KeyPathExpr : public Expr {
60896089
}
60906090
};
60916091

6092+
/// Provides a value of type `(any Actor)?` that represents the actor
6093+
/// isolation of the current context, or `nil` if this is non-isolated
6094+
/// code.
6095+
///
6096+
/// This expression node is implicitly created by the type checker, and
6097+
/// has no in-source spelling.
6098+
class CurrentContextIsolationExpr : public Expr {
6099+
Expr *actorExpr = nullptr;
6100+
SourceLoc implicitLoc;
6101+
6102+
public:
6103+
CurrentContextIsolationExpr(SourceLoc implicitLoc, Type type)
6104+
: Expr(ExprKind::CurrentContextIsolation, /*isImplicit=*/true, type),
6105+
implicitLoc(implicitLoc) {}
6106+
6107+
/// The expression that produces the actor isolation value.
6108+
Expr *getActor() const { return actorExpr; }
6109+
6110+
void setActor(Expr *expr) {
6111+
actorExpr = expr;
6112+
}
6113+
6114+
SourceLoc getLoc() const { return implicitLoc; }
6115+
6116+
SourceRange getSourceRange() const {
6117+
return SourceRange(implicitLoc, implicitLoc);
6118+
}
6119+
6120+
static bool classof(const Expr *E) {
6121+
return E->getKind() == ExprKind::CurrentContextIsolation;
6122+
}
6123+
};
6124+
60926125
/// Represents the unusual behavior of a . in a \ keypath expression, such as
60936126
/// \.[0] and \Foo.?.
60946127
class KeyPathDotExpr : public Expr {

include/swift/AST/ExprNodes.def

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -207,6 +207,7 @@ EXPR(LazyInitializer, Expr)
207207
EXPR(EditorPlaceholder, Expr)
208208
EXPR(ObjCSelector, Expr)
209209
EXPR(KeyPath, Expr)
210+
EXPR(CurrentContextIsolation, Expr)
210211
EXPR(SingleValueStmt, Expr)
211212
UNCHECKED_EXPR(KeyPathDot, Expr)
212213
UNCHECKED_EXPR(OneWay, Expr)

include/swift/AST/MacroDefinition.h

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -58,6 +58,8 @@ struct ExternalMacroReference {
5858
enum class BuiltinMacroKind: uint8_t {
5959
/// #externalMacro, which references an external macro.
6060
ExternalMacro,
61+
/// #isolation, which produces the isolation of the current context
62+
IsolationMacro,
6163
};
6264

6365
/// A single replacement

lib/AST/ASTContext.cpp

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1144,6 +1144,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
11441144
M = getLoadedModule(Id_Differentiation);
11451145
break;
11461146
case KnownProtocolKind::Actor:
1147+
case KnownProtocolKind::AnyActor:
11471148
case KnownProtocolKind::GlobalActor:
11481149
case KnownProtocolKind::AsyncSequence:
11491150
case KnownProtocolKind::AsyncIteratorProtocol:

lib/AST/ASTDumper.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3147,6 +3147,15 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
31473147
printFoot();
31483148
}
31493149

3150+
void visitCurrentContextIsolationExpr(
3151+
CurrentContextIsolationExpr *E, StringRef label) {
3152+
printCommon(E, "current_context_isolation_expr", label);
3153+
if (auto actor = E->getActor())
3154+
printRec(actor);
3155+
3156+
printFoot();
3157+
}
3158+
31503159
void visitKeyPathDotExpr(KeyPathDotExpr *E, StringRef label) {
31513160
printCommon(E, "key_path_dot_expr", label);
31523161
printFoot();

lib/AST/ASTPrinter.cpp

Lines changed: 9 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5384,6 +5384,9 @@ void PrintAST::visitMacroDecl(MacroDecl *decl) {
53845384
case BuiltinMacroKind::ExternalMacro:
53855385
Printer << "ExternalMacro";
53865386
break;
5387+
case BuiltinMacroKind::IsolationMacro:
5388+
Printer << "IsolationMacro";
5389+
break;
53875390
}
53885391
break;
53895392

@@ -5653,6 +5656,12 @@ void PrintAST::visitEnumIsCaseExpr(EnumIsCaseExpr *expr) {
56535656
void PrintAST::visitForceValueExpr(ForceValueExpr *expr) {
56545657
}
56555658

5659+
void PrintAST::visitCurrentContextIsolationExpr(
5660+
CurrentContextIsolationExpr *expr) {
5661+
if (auto actor = expr->getActor())
5662+
visit(actor);
5663+
}
5664+
56565665
void PrintAST::visitKeyPathDotExpr(KeyPathDotExpr *expr) {
56575666
}
56585667

lib/AST/ASTWalker.cpp

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1315,6 +1315,17 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
13151315
return E;
13161316
}
13171317

1318+
Expr *visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
1319+
if (auto actor = E->getActor()) {
1320+
if (auto newActor = doIt(actor))
1321+
E->setActor(newActor);
1322+
else
1323+
return nullptr;
1324+
}
1325+
1326+
return E;
1327+
}
1328+
13181329
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { return E; }
13191330

13201331
Expr *visitSingleValueStmtExpr(SingleValueStmtExpr *E) {

lib/AST/Expr.cpp

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -321,8 +321,9 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
321321
return cast<Id##Expr>(this)->Getter()
322322
#define PASS_THROUGH_REFERENCE(Id, GetSubExpr) \
323323
case ExprKind::Id: \
324-
return cast<Id##Expr>(this) \
325-
->GetSubExpr()->getReferencedDecl(stopAtParenExpr)
324+
if (auto sub = cast<Id##Expr>(this)->GetSubExpr()) \
325+
return sub->getReferencedDecl(stopAtParenExpr); \
326+
return ConcreteDeclRef();
326327

327328
NO_REFERENCE(Error);
328329
SIMPLE_REFERENCE(NilLiteral, getInitializer);
@@ -469,6 +470,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
469470
NO_REFERENCE(ObjCSelector);
470471
NO_REFERENCE(KeyPath);
471472
NO_REFERENCE(KeyPathDot);
473+
PASS_THROUGH_REFERENCE(CurrentContextIsolation, getActor);
472474
PASS_THROUGH_REFERENCE(OneWay, getSubExpr);
473475
NO_REFERENCE(Tap);
474476
NO_REFERENCE(TypeJoin);
@@ -842,6 +844,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
842844
return true;
843845

844846
case ExprKind::MacroExpansion:
847+
case ExprKind::CurrentContextIsolation:
845848
return true;
846849
}
847850

@@ -1022,6 +1025,7 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
10221025
case ExprKind::SingleValueStmt:
10231026
case ExprKind::TypeJoin:
10241027
case ExprKind::MacroExpansion:
1028+
case ExprKind::CurrentContextIsolation:
10251029
return false;
10261030
}
10271031

lib/ASTGen/Sources/ASTGen/Macros.swift

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -231,6 +231,9 @@ func checkMacroDefinition(
231231
case "ExternalMacro":
232232
return Int(BridgedMacroDefinitionKind.builtinExternalMacro.rawValue)
233233

234+
case "IsolationMacro":
235+
return Int(BridgedMacroDefinitionKind.builtinIsolationMacro.rawValue)
236+
234237
// These builtins don't exist, but are put into the standard library at
235238
// least for documentation purposes right now. Don't emit a warning for
236239
// them, but do fail operation.

lib/SILGen/SILGenExpr.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -580,6 +580,7 @@ namespace {
580580
RValue visitConsumeExpr(ConsumeExpr *E, SGFContext C);
581581
RValue visitCopyExpr(CopyExpr *E, SGFContext C);
582582
RValue visitMacroExpansionExpr(MacroExpansionExpr *E, SGFContext C);
583+
RValue visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E, SGFContext C);
583584
};
584585
} // end anonymous namespace
585586

@@ -6536,6 +6537,11 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E,
65366537
return RValue();
65376538
}
65386539

6540+
RValue RValueEmitter::visitCurrentContextIsolationExpr(
6541+
CurrentContextIsolationExpr *E, SGFContext C) {
6542+
return visit(E->getActor(), C);
6543+
}
6544+
65396545
RValue SILGenFunction::emitRValue(Expr *E, SGFContext C) {
65406546
assert(!E->getType()->hasLValueType() &&
65416547
"l-values must be emitted with emitLValue");

lib/Sema/CSApply.cpp

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5396,6 +5396,11 @@ namespace {
53965396
buildKeyPathOptionalForceComponent(components);
53975397
}
53985398

5399+
Expr *visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
5400+
E->setType(simplifyType(cs.getType(E)));
5401+
return E;
5402+
}
5403+
53995404
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) {
54005405
llvm_unreachable("found KeyPathDotExpr in CSApply");
54015406
}

lib/Sema/CSGen.cpp

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3914,6 +3914,12 @@ namespace {
39143914
return kpTy;
39153915
}
39163916

3917+
Type visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
3918+
auto actorProto = CS.getASTContext().getProtocol(
3919+
KnownProtocolKind::AnyActor);
3920+
return OptionalType::get(actorProto->getDeclaredExistentialType());
3921+
}
3922+
39173923
Type visitKeyPathDotExpr(KeyPathDotExpr *E) {
39183924
llvm_unreachable("found KeyPathDotExpr in CSGen");
39193925
}

lib/Sema/TypeCheckConcurrency.cpp

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2764,6 +2764,9 @@ namespace {
27642764
}
27652765
}
27662766

2767+
if (auto isolationExpr = dyn_cast<CurrentContextIsolationExpr>(expr))
2768+
recordCurrentContextIsolation(isolationExpr);
2769+
27672770
return Action::Continue(expr);
27682771
}
27692772

@@ -3431,6 +3434,63 @@ namespace {
34313434
return false;
34323435
}
34333436

3437+
void recordCurrentContextIsolation(
3438+
CurrentContextIsolationExpr *isolationExpr) {
3439+
// If an actor has already been assigned, we're done.
3440+
if (isolationExpr->getActor())
3441+
return;
3442+
3443+
auto loc = isolationExpr->getLoc();
3444+
auto isolation = getActorIsolationOfContext(
3445+
const_cast<DeclContext *>(getDeclContext()),
3446+
getClosureActorIsolation);
3447+
Expr *actorExpr = nullptr;
3448+
Type optionalAnyActorType = isolationExpr->getType();
3449+
switch (isolation) {
3450+
case ActorIsolation::ActorInstance: {
3451+
const VarDecl *var = isolation.getActorInstance();
3452+
if (!var) {
3453+
auto dc = getDeclContext();
3454+
auto paramIdx = isolation.getActorInstanceParameter();
3455+
if (paramIdx == 0) {
3456+
var = cast<AbstractFunctionDecl>(dc)->getImplicitSelfDecl();
3457+
} else {
3458+
var = getParameterAt(dc, paramIdx - 1);
3459+
}
3460+
}
3461+
actorExpr = new (ctx) DeclRefExpr(
3462+
const_cast<VarDecl *>(var), DeclNameLoc(loc),
3463+
/*Implicit=*/true);
3464+
break;
3465+
}
3466+
case ActorIsolation::GlobalActor:
3467+
case ActorIsolation::GlobalActorUnsafe: {
3468+
// Form a <global actor type>.shared reference.
3469+
Type globalActorType = getDeclContext()->mapTypeIntoContext(
3470+
isolation.getGlobalActor());
3471+
auto typeExpr = TypeExpr::createImplicit(globalActorType, ctx);
3472+
actorExpr = new (ctx) UnresolvedDotExpr(
3473+
typeExpr, loc, DeclNameRef(ctx.Id_shared), DeclNameLoc(),
3474+
/*implicit=*/true);
3475+
break;
3476+
}
3477+
3478+
case ActorIsolation::Unspecified:
3479+
case ActorIsolation::Nonisolated:
3480+
case ActorIsolation::NonisolatedUnsafe:
3481+
actorExpr = new (ctx) NilLiteralExpr(loc, /*implicit=*/true);
3482+
break;
3483+
}
3484+
3485+
// Convert the actor argument to the appropriate type.
3486+
(void)TypeChecker::typeCheckExpression(
3487+
actorExpr, const_cast<DeclContext *>(getDeclContext()),
3488+
constraints::ContextualTypeInfo(
3489+
optionalAnyActorType, CTP_CallArgument));
3490+
3491+
isolationExpr->setActor(actorExpr);
3492+
}
3493+
34343494
/// Find the innermost context in which this declaration was explicitly
34353495
/// captured.
34363496
const DeclContext *findCapturedDeclContext(ValueDecl *value) {

0 commit comments

Comments
 (0)