Skip to content

Implement #isolation macro to produce the isolation of the current context #70902

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Merged
merged 1 commit into from
Jan 16, 2024
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
4 changes: 3 additions & 1 deletion include/swift/AST/ASTBridging.h
Original file line number Diff line number Diff line change
Expand Up @@ -1492,7 +1492,9 @@ enum ENUM_EXTENSIBILITY_ATTR(open) BridgedMacroDefinitionKind : size_t {
/// or the new spelling `#externalMacro(module: "Module", type: "Type")`.
BridgedExternalMacro,
/// The builtin definition for "externalMacro".
BridgedBuiltinExternalMacro
BridgedBuiltinExternalMacro,
/// The builtin definition for the "isolation" macro.
BridgedBuiltinIsolationMacro,
};

SWIFT_NAME("BridgedGenericParamList.createParsed(_:leftAngleLoc:parameters:"
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -5564,6 +5564,8 @@ ERROR(isolated_parameter_global_actor_type,none,
ERROR(isolated_parameter_combined_nonisolated,none,
"%0 with 'isolated' parameter cannot be 'nonisolated'",
(DescriptiveDeclKind))
ERROR(isolation_macro_experimental,none,
"#isolation macro is experimental", ())

NOTE(in_derived_conformance, none,
"in derived conformance to %0",
Expand Down
33 changes: 33 additions & 0 deletions include/swift/AST/Expr.h
Original file line number Diff line number Diff line change
Expand Up @@ -6089,6 +6089,39 @@ class KeyPathExpr : public Expr {
}
};

/// Provides a value of type `(any Actor)?` that represents the actor
/// isolation of the current context, or `nil` if this is non-isolated
/// code.
///
/// This expression node is implicitly created by the type checker, and
/// has no in-source spelling.
class CurrentContextIsolationExpr : public Expr {
Expr *actorExpr = nullptr;
SourceLoc implicitLoc;

public:
CurrentContextIsolationExpr(SourceLoc implicitLoc, Type type)
: Expr(ExprKind::CurrentContextIsolation, /*isImplicit=*/true, type),
implicitLoc(implicitLoc) {}

/// The expression that produces the actor isolation value.
Expr *getActor() const { return actorExpr; }

void setActor(Expr *expr) {
actorExpr = expr;
}

SourceLoc getLoc() const { return implicitLoc; }

SourceRange getSourceRange() const {
return SourceRange(implicitLoc, implicitLoc);
}

static bool classof(const Expr *E) {
return E->getKind() == ExprKind::CurrentContextIsolation;
}
};

/// Represents the unusual behavior of a . in a \ keypath expression, such as
/// \.[0] and \Foo.?.
class KeyPathDotExpr : public Expr {
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/ExprNodes.def
Original file line number Diff line number Diff line change
Expand Up @@ -207,6 +207,7 @@ EXPR(LazyInitializer, Expr)
EXPR(EditorPlaceholder, Expr)
EXPR(ObjCSelector, Expr)
EXPR(KeyPath, Expr)
EXPR(CurrentContextIsolation, Expr)
EXPR(SingleValueStmt, Expr)
UNCHECKED_EXPR(KeyPathDot, Expr)
UNCHECKED_EXPR(OneWay, Expr)
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/MacroDefinition.h
Original file line number Diff line number Diff line change
Expand Up @@ -58,6 +58,8 @@ struct ExternalMacroReference {
enum class BuiltinMacroKind: uint8_t {
/// #externalMacro, which references an external macro.
ExternalMacro,
/// #isolation, which produces the isolation of the current context
IsolationMacro,
};

/// A single replacement
Expand Down
1 change: 1 addition & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1144,6 +1144,7 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
M = getLoadedModule(Id_Differentiation);
break;
case KnownProtocolKind::Actor:
case KnownProtocolKind::AnyActor:
case KnownProtocolKind::GlobalActor:
case KnownProtocolKind::AsyncSequence:
case KnownProtocolKind::AsyncIteratorProtocol:
Expand Down
9 changes: 9 additions & 0 deletions lib/AST/ASTDumper.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3147,6 +3147,15 @@ class PrintExpr : public ExprVisitor<PrintExpr, void, StringRef>,
printFoot();
}

void visitCurrentContextIsolationExpr(
CurrentContextIsolationExpr *E, StringRef label) {
printCommon(E, "current_context_isolation_expr", label);
if (auto actor = E->getActor())
printRec(actor);

printFoot();
}

void visitKeyPathDotExpr(KeyPathDotExpr *E, StringRef label) {
printCommon(E, "key_path_dot_expr", label);
printFoot();
Expand Down
9 changes: 9 additions & 0 deletions lib/AST/ASTPrinter.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5384,6 +5384,9 @@ void PrintAST::visitMacroDecl(MacroDecl *decl) {
case BuiltinMacroKind::ExternalMacro:
Printer << "ExternalMacro";
break;
case BuiltinMacroKind::IsolationMacro:
Printer << "IsolationMacro";
break;
}
break;

Expand Down Expand Up @@ -5653,6 +5656,12 @@ void PrintAST::visitEnumIsCaseExpr(EnumIsCaseExpr *expr) {
void PrintAST::visitForceValueExpr(ForceValueExpr *expr) {
}

void PrintAST::visitCurrentContextIsolationExpr(
CurrentContextIsolationExpr *expr) {
if (auto actor = expr->getActor())
visit(actor);
}

void PrintAST::visitKeyPathDotExpr(KeyPathDotExpr *expr) {
}

Expand Down
11 changes: 11 additions & 0 deletions lib/AST/ASTWalker.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1315,6 +1315,17 @@ class Traversal : public ASTVisitor<Traversal, Expr*, Stmt*,
return E;
}

Expr *visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
if (auto actor = E->getActor()) {
if (auto newActor = doIt(actor))
E->setActor(newActor);
else
return nullptr;
}

return E;
}

Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) { return E; }

Expr *visitSingleValueStmtExpr(SingleValueStmtExpr *E) {
Expand Down
8 changes: 6 additions & 2 deletions lib/AST/Expr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -321,8 +321,9 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
return cast<Id##Expr>(this)->Getter()
#define PASS_THROUGH_REFERENCE(Id, GetSubExpr) \
case ExprKind::Id: \
return cast<Id##Expr>(this) \
->GetSubExpr()->getReferencedDecl(stopAtParenExpr)
if (auto sub = cast<Id##Expr>(this)->GetSubExpr()) \
return sub->getReferencedDecl(stopAtParenExpr); \
return ConcreteDeclRef();

NO_REFERENCE(Error);
SIMPLE_REFERENCE(NilLiteral, getInitializer);
Expand Down Expand Up @@ -469,6 +470,7 @@ ConcreteDeclRef Expr::getReferencedDecl(bool stopAtParenExpr) const {
NO_REFERENCE(ObjCSelector);
NO_REFERENCE(KeyPath);
NO_REFERENCE(KeyPathDot);
PASS_THROUGH_REFERENCE(CurrentContextIsolation, getActor);
PASS_THROUGH_REFERENCE(OneWay, getSubExpr);
NO_REFERENCE(Tap);
NO_REFERENCE(TypeJoin);
Expand Down Expand Up @@ -842,6 +844,7 @@ bool Expr::canAppendPostfixExpression(bool appendingPostfixOperator) const {
return true;

case ExprKind::MacroExpansion:
case ExprKind::CurrentContextIsolation:
return true;
}

Expand Down Expand Up @@ -1022,6 +1025,7 @@ bool Expr::isValidParentOfTypeExpr(Expr *typeExpr) const {
case ExprKind::SingleValueStmt:
case ExprKind::TypeJoin:
case ExprKind::MacroExpansion:
case ExprKind::CurrentContextIsolation:
return false;
}

Expand Down
3 changes: 3 additions & 0 deletions lib/ASTGen/Sources/ASTGen/Macros.swift
Original file line number Diff line number Diff line change
Expand Up @@ -231,6 +231,9 @@ func checkMacroDefinition(
case "ExternalMacro":
return Int(BridgedMacroDefinitionKind.builtinExternalMacro.rawValue)

case "IsolationMacro":
return Int(BridgedMacroDefinitionKind.builtinIsolationMacro.rawValue)

// These builtins don't exist, but are put into the standard library at
// least for documentation purposes right now. Don't emit a warning for
// them, but do fail operation.
Expand Down
6 changes: 6 additions & 0 deletions lib/SILGen/SILGenExpr.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -580,6 +580,7 @@ namespace {
RValue visitConsumeExpr(ConsumeExpr *E, SGFContext C);
RValue visitCopyExpr(CopyExpr *E, SGFContext C);
RValue visitMacroExpansionExpr(MacroExpansionExpr *E, SGFContext C);
RValue visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E, SGFContext C);
};
} // end anonymous namespace

Expand Down Expand Up @@ -6536,6 +6537,11 @@ RValue RValueEmitter::visitMacroExpansionExpr(MacroExpansionExpr *E,
return RValue();
}

RValue RValueEmitter::visitCurrentContextIsolationExpr(
CurrentContextIsolationExpr *E, SGFContext C) {
return visit(E->getActor(), C);
}

RValue SILGenFunction::emitRValue(Expr *E, SGFContext C) {
assert(!E->getType()->hasLValueType() &&
"l-values must be emitted with emitLValue");
Expand Down
5 changes: 5 additions & 0 deletions lib/Sema/CSApply.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5396,6 +5396,11 @@ namespace {
buildKeyPathOptionalForceComponent(components);
}

Expr *visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
E->setType(simplifyType(cs.getType(E)));
return E;
}

Expr *visitKeyPathDotExpr(KeyPathDotExpr *E) {
llvm_unreachable("found KeyPathDotExpr in CSApply");
}
Expand Down
6 changes: 6 additions & 0 deletions lib/Sema/CSGen.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3914,6 +3914,12 @@ namespace {
return kpTy;
}

Type visitCurrentContextIsolationExpr(CurrentContextIsolationExpr *E) {
auto actorProto = CS.getASTContext().getProtocol(
KnownProtocolKind::AnyActor);
return OptionalType::get(actorProto->getDeclaredExistentialType());
}

Type visitKeyPathDotExpr(KeyPathDotExpr *E) {
llvm_unreachable("found KeyPathDotExpr in CSGen");
}
Expand Down
60 changes: 60 additions & 0 deletions lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -2764,6 +2764,9 @@ namespace {
}
}

if (auto isolationExpr = dyn_cast<CurrentContextIsolationExpr>(expr))
recordCurrentContextIsolation(isolationExpr);

return Action::Continue(expr);
}

Expand Down Expand Up @@ -3431,6 +3434,63 @@ namespace {
return false;
}

void recordCurrentContextIsolation(
CurrentContextIsolationExpr *isolationExpr) {
// If an actor has already been assigned, we're done.
if (isolationExpr->getActor())
return;

auto loc = isolationExpr->getLoc();
auto isolation = getActorIsolationOfContext(
const_cast<DeclContext *>(getDeclContext()),
getClosureActorIsolation);
Expr *actorExpr = nullptr;
Type optionalAnyActorType = isolationExpr->getType();
switch (isolation) {
case ActorIsolation::ActorInstance: {
const VarDecl *var = isolation.getActorInstance();
if (!var) {
auto dc = getDeclContext();
auto paramIdx = isolation.getActorInstanceParameter();
if (paramIdx == 0) {
var = cast<AbstractFunctionDecl>(dc)->getImplicitSelfDecl();
} else {
var = getParameterAt(dc, paramIdx - 1);
}
}
actorExpr = new (ctx) DeclRefExpr(
const_cast<VarDecl *>(var), DeclNameLoc(loc),
/*Implicit=*/true);
break;
}
case ActorIsolation::GlobalActor:
case ActorIsolation::GlobalActorUnsafe: {
// Form a <global actor type>.shared reference.
Type globalActorType = getDeclContext()->mapTypeIntoContext(
isolation.getGlobalActor());
auto typeExpr = TypeExpr::createImplicit(globalActorType, ctx);
actorExpr = new (ctx) UnresolvedDotExpr(
typeExpr, loc, DeclNameRef(ctx.Id_shared), DeclNameLoc(),
/*implicit=*/true);
break;
}

case ActorIsolation::Unspecified:
case ActorIsolation::Nonisolated:
case ActorIsolation::NonisolatedUnsafe:
actorExpr = new (ctx) NilLiteralExpr(loc, /*implicit=*/true);
break;
}

// Convert the actor argument to the appropriate type.
(void)TypeChecker::typeCheckExpression(
actorExpr, const_cast<DeclContext *>(getDeclContext()),
constraints::ContextualTypeInfo(
optionalAnyActorType, CTP_CallArgument));

isolationExpr->setActor(actorExpr);
}

/// Find the innermost context in which this declaration was explicitly
/// captured.
const DeclContext *findCapturedDeclContext(ValueDecl *value) {
Expand Down
Loading