Skip to content

Commit 8b514ec

Browse files
authored
Merge pull request #70902 from DougGregor/isolation-macro
Implement `#isolation` macro to produce the isolation of the current context
2 parents 677e971 + 255009d commit 8b514ec

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
@@ -5552,6 +5552,8 @@ ERROR(isolated_parameter_global_actor_type,none,
55525552
ERROR(isolated_parameter_combined_nonisolated,none,
55535553
"%0 with 'isolated' parameter cannot be 'nonisolated'",
55545554
(DescriptiveDeclKind))
5555+
ERROR(isolation_macro_experimental,none,
5556+
"#isolation macro is experimental", ())
55555557

55565558
NOTE(in_derived_conformance, none,
55575559
"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
@@ -3148,6 +3148,15 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
31483148
printFoot();
31493149
}
31503150

3151+
void visitCurrentContextIsolationExpr(
3152+
CurrentContextIsolationExpr *E, StringRef label) {
3153+
printCommon(E, "current_context_isolation_expr", label);
3154+
if (auto actor = E->getActor())
3155+
printRec(actor);
3156+
3157+
printFoot();
3158+
}
3159+
31513160
void visitKeyPathDotExpr(KeyPathDotExpr *E, StringRef label) {
31523161
printCommon(E, "key_path_dot_expr", label);
31533162
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
@@ -5362,6 +5362,11 @@ namespace {
53625362
buildKeyPathOptionalForceComponent(components);
53635363
}
53645364

5365+
Expr *visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
5366+
E->setType(simplifyType(cs.getType(E)));
5367+
return E;
5368+
}
5369+
53655370
Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) {
53665371
llvm_unreachable("found KeyPathDotExpr in CSApply");
53675372
}

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
@@ -2799,6 +2799,9 @@ namespace {
27992799
}
28002800
}
28012801

2802+
if (auto isolationExpr = dyn_cast<CurrentContextIsolationExpr>(expr))
2803+
recordCurrentContextIsolation(isolationExpr);
2804+
28022805
return Action::Continue(expr);
28032806
}
28042807

@@ -3466,6 +3469,63 @@ namespace {
34663469
return false;
34673470
}
34683471

3472+
void recordCurrentContextIsolation(
3473+
CurrentContextIsolationExpr *isolationExpr) {
3474+
// If an actor has already been assigned, we're done.
3475+
if (isolationExpr->getActor())
3476+
return;
3477+
3478+
auto loc = isolationExpr->getLoc();
3479+
auto isolation = getActorIsolationOfContext(
3480+
const_cast<DeclContext *>(getDeclContext()),
3481+
getClosureActorIsolation);
3482+
Expr *actorExpr = nullptr;
3483+
Type optionalAnyActorType = isolationExpr->getType();
3484+
switch (isolation) {
3485+
case ActorIsolation::ActorInstance: {
3486+
const VarDecl *var = isolation.getActorInstance();
3487+
if (!var) {
3488+
auto dc = getDeclContext();
3489+
auto paramIdx = isolation.getActorInstanceParameter();
3490+
if (paramIdx == 0) {
3491+
var = cast<AbstractFunctionDecl>(dc)->getImplicitSelfDecl();
3492+
} else {
3493+
var = getParameterAt(dc, paramIdx - 1);
3494+
}
3495+
}
3496+
actorExpr = new (ctx) DeclRefExpr(
3497+
const_cast<VarDecl *>(var), DeclNameLoc(loc),
3498+
/*Implicit=*/true);
3499+
break;
3500+
}
3501+
case ActorIsolation::GlobalActor:
3502+
case ActorIsolation::GlobalActorUnsafe: {
3503+
// Form a <global actor type>.shared reference.
3504+
Type globalActorType = getDeclContext()->mapTypeIntoContext(
3505+
isolation.getGlobalActor());
3506+
auto typeExpr = TypeExpr::createImplicit(globalActorType, ctx);
3507+
actorExpr = new (ctx) UnresolvedDotExpr(
3508+
typeExpr, loc, DeclNameRef(ctx.Id_shared), DeclNameLoc(),
3509+
/*implicit=*/true);
3510+
break;
3511+
}
3512+
3513+
case ActorIsolation::Unspecified:
3514+
case ActorIsolation::Nonisolated:
3515+
case ActorIsolation::NonisolatedUnsafe:
3516+
actorExpr = new (ctx) NilLiteralExpr(loc, /*implicit=*/true);
3517+
break;
3518+
}
3519+
3520+
// Convert the actor argument to the appropriate type.
3521+
(void)TypeChecker::typeCheckExpression(
3522+
actorExpr, const_cast<DeclContext *>(getDeclContext()),
3523+
constraints::ContextualTypeInfo(
3524+
optionalAnyActorType, CTP_CallArgument));
3525+
3526+
isolationExpr->setActor(actorExpr);
3527+
}
3528+
34693529
/// Find the innermost context in which this declaration was explicitly
34703530
/// captured.
34713531
const DeclContext *findCapturedDeclContext(ValueDecl *value) {

0 commit comments

Comments
 (0)