Skip to content

[SILGen] Ensure that we emit the distributed-actor-as-actor conformance #71105

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
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
1 change: 1 addition & 0 deletions include/swift/AST/KnownIdentifiers.def
Original file line number Diff line number Diff line change
Expand Up @@ -32,6 +32,7 @@ IDENTIFIER(accumulated)
IDENTIFIER(ActorType)
IDENTIFIER(Any)
IDENTIFIER(ArrayLiteralElement)
IDENTIFIER(asLocalActor)
IDENTIFIER(atIndexedSubscript)
IDENTIFIER_(bridgeToObjectiveC)
IDENTIFIER(buildArray)
Expand Down
18 changes: 18 additions & 0 deletions lib/SILGen/SILGen.h
Original file line number Diff line number Diff line change
Expand Up @@ -83,6 +83,10 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
/// Set of delayed conformances that have already been forced.
llvm::DenseSet<NormalProtocolConformance *> forcedConformances;

/// The conformance for any DistributedActor to the Actor protocol,
/// used only by the `distributedActorAsAnyActor` builtin.
RootProtocolConformance *distributedActorAsActorConformance = nullptr;

size_t anonymousSymbolCounter = 0;

llvm::Optional<SILDeclRef> StringToNSStringFn;
Expand Down Expand Up @@ -605,6 +609,20 @@ class LLVM_LIBRARY_VISIBILITY SILGenModule : public ASTVisitor<SILGenModule> {
/// mentioned by the given type.
void useConformancesFromObjectiveCType(CanType type);

/// Retrieve a protocol conformance to the `Actor` protocol for a
/// distributed actor type that is described via a substitution map for
/// the generic signature `<T: DistributedActor>`.
///
/// The protocol conformance is a special one that is currently
/// only used by the `distributedActorAsAnyActor` builtin.
ProtocolConformanceRef
getDistributedActorAsActorConformance(SubstitutionMap subs);

/// Make a note of a member reference expression, which allows us
/// to ensure that the conformance above is emitted wherever it
/// needs to be.
void noteMemberRefExpr(MemberRefExpr *e);

/// Map the substitutions for the original declaration to substitutions for
/// the overridden declaration.
static SubstitutionMap mapSubstitutionsForWitnessOverride(
Expand Down
91 changes: 54 additions & 37 deletions lib/SILGen/SILGenBuiltin.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1889,13 +1889,10 @@ static ManagedValue emitBuiltinInjectEnumTag(SILGenFunction &SGF, SILLocation lo
return ManagedValue::forObjectRValueWithoutOwnership(bi);
}

static ExtensionDecl *distributedActorAsAnyActorExt = nullptr;

/// Find the extension on DistributedActor that defines __actorUnownedExecutor.
static ExtensionDecl *findDistributedActorAsActorExtension(
ProtocolDecl *distributedActorProto, ModuleDecl *module) {
ASTContext &ctx = distributedActorProto->getASTContext();
#if true
auto name = ctx.getIdentifier("__actorUnownedExecutor");
auto results = distributedActorProto->lookupDirect(
name, SourceLoc(),
Expand All @@ -1907,53 +1904,73 @@ static ExtensionDecl *findDistributedActorAsActorExtension(
}

return nullptr;
#else
if (!distributedActorAsAnyActorExt) {
auto ext = ExtensionDecl::create(
ctx, SourceLoc(), nullptr, { }, module, nullptr);
ctx.evaluator.cacheOutput(ExtendedTypeRequest{ext},
distributedActorProto->getDeclaredInterfaceType());
ctx.evaluator.cacheOutput(ExtendedNominalRequest{ext},
distributedActorProto);

distributedActorAsAnyActorExt = ext;
}

ProtocolConformanceRef
SILGenModule::getDistributedActorAsActorConformance(SubstitutionMap subs) {
ASTContext &ctx = M.getASTContext();
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
Type distributedActorType = subs.getReplacementTypes()[0];

if (!distributedActorAsActorConformance) {
auto distributedActorProto = ctx.getProtocol(KnownProtocolKind::DistributedActor);
if (!distributedActorProto)
return ProtocolConformanceRef();

auto ext = findDistributedActorAsActorExtension(
distributedActorProto, M.getSwiftModule());
if (!ext)
return ProtocolConformanceRef();

// Conformance of DistributedActor to Actor.
auto genericParam = subs.getGenericSignature().getGenericParams()[0];
distributedActorAsActorConformance = ctx.getNormalConformance(
Type(genericParam), actorProto, SourceLoc(), ext,
ProtocolConformanceState::Incomplete, /*isUnchecked=*/false,
/*isPreconcurrency=*/false);
}

return ProtocolConformanceRef(
actorProto,
ctx.getSpecializedConformance(distributedActorType,
distributedActorAsActorConformance,
subs));
}

void SILGenModule::noteMemberRefExpr(MemberRefExpr *e) {
VarDecl *var = cast<VarDecl>(e->getMember().getDecl());

// If the member is the special `asLocalActor` operation on
// distributed actors, make sure we have the conformance needed
// for a builtin.
ASTContext &ctx = var->getASTContext();
if (var->getName() == ctx.Id_asLocalActor &&
var->getDeclContext()->getSelfProtocolDecl() &&
var->getDeclContext()->getSelfProtocolDecl()
->isSpecificProtocol(KnownProtocolKind::DistributedActor)) {
auto conformance =
getDistributedActorAsActorConformance(
e->getMember().getSubstitutions());
useConformance(conformance);
}

return distributedActorAsAnyActorExt;
#endif
}

static ManagedValue emitBuiltinDistributedActorAsAnyActor(
SILGenFunction &SGF, SILLocation loc, SubstitutionMap subs,
ArrayRef<ManagedValue> args, SGFContext C) {
auto &ctx = SGF.getASTContext();
auto distributedActor = args[0];

auto builtinDecl = cast<FuncDecl>(getBuiltinValueDecl(
ctx, ctx.getIdentifier("distributedActorAsAnyActor")));
auto genericSignature = builtinDecl->getGenericSignature();
auto genericParam = genericSignature.getGenericParams()[0];

auto distributedActorProto = ctx.getProtocol(KnownProtocolKind::DistributedActor);
auto ext = findDistributedActorAsActorExtension(
distributedActorProto, SGF.getModule().getSwiftModule());

// Conformance of DistributedActor to Actor.
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
CanType distributedActorType = distributedActor.getType().getASTType();
RootProtocolConformance *daAsActorConformance = ctx.getNormalConformance(
Type(genericParam), actorProto, SourceLoc(), ext,
ProtocolConformanceState::Incomplete, /*isUnchecked=*/false,
/*isPreconcurrency=*/false);
ProtocolConformanceRef conformance(
actorProto,
ctx.getSpecializedConformance(distributedActorType, daAsActorConformance,
subs));
ProtocolConformanceRef conformances[1] = { conformance };
ProtocolConformanceRef conformances[1] = {
SGF.SGM.getDistributedActorAsActorConformance(subs)
};

// Erase the distributed actor instance into an `any Actor` existential with
// the special conformance.
CanType distributedActorType =
subs.getReplacementTypes()[0]->getCanonicalType();
auto &distributedActorTL = SGF.getTypeLowering(distributedActorType);
auto actorProto = ctx.getProtocol(KnownProtocolKind::Actor);
auto &anyActorTL = SGF.getTypeLowering(actorProto->getDeclaredExistentialType());
return SGF.emitExistentialErasure(
loc, distributedActorType, distributedActorTL, anyActorTL,
Expand Down
6 changes: 6 additions & 0 deletions lib/SILGen/SILGenLValue.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3055,6 +3055,9 @@ class LLVM_LIBRARY_VISIBILITY SILGenBorrowedBaseVisitor
options, e->isSuper(), accessKind, strategy,
getSubstFormalRValueType(e),
false /*is on self parameter*/, actorIso);

SGF.SGM.noteMemberRefExpr(e);

return lv;
}

Expand Down Expand Up @@ -3864,6 +3867,9 @@ LValue SILGenLValue::visitMemberRefExpr(MemberRefExpr *e,
lv.addMemberVarComponent(SGF, e, var, e->getMember().getSubstitutions(),
options, e->isSuper(), accessKind, strategy,
substFormalRValueType, isOnSelfParameter, actorIso);

SGF.SGM.noteMemberRefExpr(e);

return lv;
}

Expand Down
2 changes: 1 addition & 1 deletion lib/Sema/TypeCheckConcurrency.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -3465,7 +3465,7 @@ namespace {
// actor.
if (isolation.isDistributedActor()) {
actorExpr = UnresolvedDotExpr::createImplicit(
ctx, actorExpr, ctx.getIdentifier("asLocalActor"));
ctx, actorExpr, ctx.Id_asLocalActor);
}
break;
}
Expand Down
11 changes: 1 addition & 10 deletions test/Distributed/Runtime/distributed_actor_to_actor.swift
Original file line number Diff line number Diff line change
@@ -1,6 +1,6 @@
// RUN: %empty-directory(%t)
// RUN: %target-swift-frontend-emit-module -emit-module-path %t/FakeDistributedActorSystems.swiftmodule -module-name FakeDistributedActorSystems %S/../Inputs/FakeDistributedActorSystems.swift
// RUN: %target-build-swift -module-name main %import-libdispatch -j2 -parse-as-library -Xfrontend -disable-availability-checking -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -g -o %t/a.out -enable-experimental-feature BuiltinModule
// RUN: %target-build-swift -module-name main %import-libdispatch -j2 -parse-as-library -Xfrontend -disable-availability-checking -I %t %s %S/../Inputs/FakeDistributedActorSystems.swift -g -o %t/a.out
// RUN: %target-codesign %t/a.out
// RUN: %target-run %t/a.out | %FileCheck %s --color

Expand All @@ -16,21 +16,12 @@
// FIXME(distributed): Distributed actors currently have some issues on windows rdar://82593574
// UNSUPPORTED: OS=windows-msvc

import Builtin // FIXME: Part of a hack to get the protocol conformance defined properly
import Dispatch
import Distributed
import FakeDistributedActorSystems

typealias DefaultDistributedActorSystem = FakeRoundtripActorSystem

extension DistributedActor {
func localDistributedAsActor() -> any Actor {
// FIXME: Part of a hack that forces the protocol conformance for DistributedActor -> Actor to be defined
// FIXME: Drop usage of this once we resolve the issue above
Builtin.distributedActorAsAnyActor(self)
}
}

distributed actor Worker {
var counter: Int = 0

Expand Down