Skip to content

[Distributed] Initializer and lifecycle call synthesis via SIL #38822

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

Closed
Closed
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
6 changes: 5 additions & 1 deletion include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3357,7 +3357,11 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// for types that are not global actors.
VarDecl *getGlobalActorInstance() const;

bool hasDistributedActorLocalInitializer() const;
/// Check if the declaration has an user-defined initializer.
/// If so, we may want to e.g. not generate a default initializer etc.
///
/// \returns true if the decl has an user-defined designated initializer.
bool hasUserDefinedDesignatedInit() const;

/// Whether this type is a global actor, which can be used as an
/// attribute to decorate declarations for inclusion in the actor-isolated
Expand Down
33 changes: 12 additions & 21 deletions include/swift/AST/DiagnosticsSema.def
Original file line number Diff line number Diff line change
Expand Up @@ -4542,27 +4542,6 @@ ERROR(actor_instance_property_wrapper,none,
ERROR(distributed_actor_func_defined_outside_of_distributed_actor,none,
"distributed function %0 is declared outside of an distributed actor",
(DeclName))
ERROR(distributed_actor_local_init_explicitly_defined,none,
"'distributed actor' local-initializer 'init(transport:)' "
"cannot be implemented explicitly.",
())
ERROR(distributed_actor_init_resolve_must_not_be_user_defined,none,
"'distributed actor' resolve-initializer 'init(resolve:using:)' "
"cannot be implemented explicitly.",
())
ERROR(distributed_actor_init_user_defined_must_be_convenience,none,
"'distributed actor' initializer %0 must be 'convenience' initializer. "
"Distributed actors have an implicitly synthesized designated "
"'init(transport:)' local-initializer, which other initializers must delegate to",
(DeclName))
ERROR(distributed_actor_init_must_delegate_to_local_init,none,
"'distributed actor' initializer %0 must (directly or indirectly) delegate "
"to 'init(transport:)'",
(DeclName))
ERROR(distributed_actor_init_must_not_delegate_to_resolve_init,none,
"'distributed actor' initializer %0 cannot delegate to resolve-initializer "
"'init(resolve:using:)', as it may result resolving a storageless proxy instance",
(DeclName))
ERROR(distributed_actor_local_var,none,
"'distributed' can not be applied to local variables",
())
Expand All @@ -4586,6 +4565,18 @@ ERROR(distributed_actor_func_static,none,
ERROR(distributed_actor_func_not_in_distributed_actor,none,
"'distributed' function can only be declared within 'distributed actor'",
())
ERROR(distributed_actor_designated_ctor_must_have_one_transport_param,none,
"designated distributed actor initializer %0 must accept exactly one "
"ActorTransport parameter, found %1",
(DeclName, int))
ERROR(distributed_actor_designated_ctor_missing_transport_param,none,
"designated distributed actor initializer %0 is missing required "
"ActorTransport parameter",
(DeclName))
ERROR(distributed_actor_user_defined_special_property,none,
"property %0 cannot be defined explicitly, as it conflicts with "
"distributed actor synthesized stored property",
(DeclName))
ERROR(distributed_actor_independent_property_must_be_let,none,
"_distributedActorIndependent can be applied to properties, however they must be 'let'",
())
Expand Down
1 change: 1 addition & 0 deletions include/swift/AST/KnownProtocols.def
Original file line number Diff line number Diff line change
Expand Up @@ -96,6 +96,7 @@ PROTOCOL(Differentiable)

// Distributed Actors
PROTOCOL(DistributedActor)
PROTOCOL(ActorIdentity)
PROTOCOL(ActorTransport)

PROTOCOL(AsyncSequence)
Expand Down
19 changes: 19 additions & 0 deletions include/swift/AST/TypeCheckRequests.h
Original file line number Diff line number Diff line change
Expand Up @@ -2065,6 +2065,7 @@ enum class ImplicitMemberAction : uint8_t {
ResolveDecodable,
ResolveDistributedActor,
ResolveDistributedActorIdentity,
ResolveDistributedActorTransport,
};

class ResolveImplicitMemberRequest
Expand Down Expand Up @@ -2249,6 +2250,24 @@ class HasCircularRawValueRequest
bool isCached() const { return true; }
};

/// Checks if the _Distributed module is available.
class DistributedModuleIsAvailableRequest
: public SimpleRequest<DistributedModuleIsAvailableRequest, bool(Decl *),
RequestFlags::Cached> {
public:
using SimpleRequest::SimpleRequest;

private:
friend SimpleRequest;

// Evaluation.
bool evaluate(Evaluator &evaluator, Decl *decl) const;

public:
// Cached.
bool isCached() const { return true; }
};

/// Computes an initializer context for a parameter with a default argument.
class DefaultArgumentInitContextRequest
: public SimpleRequest<DefaultArgumentInitContextRequest,
Expand Down
2 changes: 2 additions & 0 deletions include/swift/AST/TypeCheckerTypeIDZone.def
Original file line number Diff line number Diff line change
Expand Up @@ -140,6 +140,8 @@ SWIFT_REQUEST(TypeChecker, InferredGenericSignatureRequest,
SmallVector<Requirement, 2>,
SmallVector<TypeLoc, 2>, bool),
Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, DistributedModuleIsAvailableRequest,
bool(ModuleDecl *), Cached, NoLocationInfo)
SWIFT_REQUEST(TypeChecker, InheritedTypeRequest,
Type(llvm::PointerUnion<const TypeDecl *, const ExtensionDecl *>,
unsigned, TypeResolutionStage),
Expand Down
2 changes: 2 additions & 0 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1036,6 +1036,8 @@ ProtocolDecl *ASTContext::getProtocol(KnownProtocolKind kind) const {
M = getLoadedModule(Id_Concurrency);
break;
case KnownProtocolKind::DistributedActor:
case KnownProtocolKind::ActorTransport:
case KnownProtocolKind::ActorIdentity:
M = getLoadedModule(Id_Distributed);
break;
default:
Expand Down
11 changes: 8 additions & 3 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -4204,10 +4204,15 @@ ConstructorDecl *NominalTypeDecl::getDefaultInitializer() const {
SynthesizeDefaultInitRequest{mutableThis}, nullptr);
}

bool NominalTypeDecl::hasDistributedActorLocalInitializer() const {
bool NominalTypeDecl::hasUserDefinedDesignatedInit() const {
// Imported decls don't have a designated initializer defined by the user.
if (hasClangNode())
return false;

auto &ctx = getASTContext();
auto *mutableThis = const_cast<NominalTypeDecl *>(this);
return evaluateOrDefault(ctx.evaluator, HasDistributedActorLocalInitRequest{mutableThis},
return evaluateOrDefault(ctx.evaluator,
HasUserDefinedDesignatedInitRequest{mutableThis},
false);
}

Expand Down Expand Up @@ -4238,7 +4243,7 @@ void NominalTypeDecl::synthesizeSemanticMembersIfNeeded(DeclName member) {
if ((member.isSimpleName() || argumentNames.front() == Context.Id_from)) {
action.emplace(ImplicitMemberAction::ResolveDecodable);
} else if (argumentNames.front() == Context.Id_transport) {
action.emplace(ImplicitMemberAction::ResolveDistributedActor);
action.emplace(ImplicitMemberAction::ResolveDistributedActorTransport);
}
} else if (!baseName.isSpecial() &&
baseName.getIdentifier() == Context.Id_encode &&
Expand Down
5 changes: 4 additions & 1 deletion lib/AST/TypeCheckRequests.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1034,11 +1034,14 @@ void swift::simple_display(llvm::raw_ostream &out,
out << "resolve Decodable.init(from:)";
break;
case ImplicitMemberAction::ResolveDistributedActor:
out << "resolve DistributedActor[init(transport:), init(resolve:using:)]";
out << "resolve DistributedActor";
break;
case ImplicitMemberAction::ResolveDistributedActorIdentity:
out << "resolve DistributedActor.id";
break;
case ImplicitMemberAction::ResolveDistributedActorTransport:
out << "resolve DistributedActor.actorTransport";
break;
}
}

Expand Down
1 change: 1 addition & 0 deletions lib/IRGen/GenMeta.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -5167,6 +5167,7 @@ SpecialProtocol irgen::getSpecialProtocolID(ProtocolDecl *P) {
case KnownProtocolKind::Actor:
case KnownProtocolKind::ActorTransport:
case KnownProtocolKind::DistributedActor:
case KnownProtocolKind::ActorIdentity:
case KnownProtocolKind::SerialExecutor:
case KnownProtocolKind::Sendable:
case KnownProtocolKind::UnsafeSendable:
Expand Down
1 change: 1 addition & 0 deletions lib/SILGen/CMakeLists.txt
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,7 @@ add_swift_host_library(swiftSILGen STATIC
SILGenConvert.cpp
SILGenDecl.cpp
SILGenDestructor.cpp
SILGenDistributed.cpp
SILGenDynamicCast.cpp
SILGenEpilog.cpp
SILGenExpr.cpp
Expand Down
173 changes: 0 additions & 173 deletions lib/SILGen/SILGenBridging.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -1975,179 +1975,6 @@ void SILGenFunction::emitNativeToForeignThunk(SILDeclRef thunk) {
B.createReturn(loc, result);
}

void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
// Check if actor is local or remote and call respective function
//
// func X_distributedThunk(...) async throws -> T {
// if __isRemoteActor(self) {
// return try await self._remote_X(...)
// } else {
// return try await self.X(...)
// }
// }
//

assert(thunk.isDistributed);
SILDeclRef native = thunk.asDistributed(false);
auto fd = cast<AbstractFunctionDecl>(thunk.getDecl());

ASTContext &ctx = getASTContext();

// Use the same generic environment as the native entry point.
F.setGenericEnvironment(SGM.Types.getConstantGenericEnvironment(native));

auto loc = thunk.getAsRegularLocation();
loc.markAutoGenerated();
Scope scope(Cleanups, CleanupLocation(loc));

auto isRemoteBB = createBasicBlock();
auto isLocalBB = createBasicBlock();
auto localErrorBB = createBasicBlock();
auto remoteErrorBB = createBasicBlock();
auto localReturnBB = createBasicBlock();
auto remoteReturnBB = createBasicBlock();
auto errorBB = createBasicBlock();
auto returnBB = createBasicBlock();

auto methodTy = SGM.Types.getConstantOverrideType(getTypeExpansionContext(),
thunk);
auto derivativeFnSILTy = SILType::getPrimitiveObjectType(methodTy);
auto silFnType = derivativeFnSILTy.castTo<SILFunctionType>();
SILFunctionConventions fnConv(silFnType, SGM.M);
auto resultType = fnConv.getSILResultType(getTypeExpansionContext());

auto *selfDecl = fd->getImplicitSelfDecl();

SmallVector<SILValue, 8> params;

bindParametersForForwarding(fd->getParameters(), params);
bindParameterForForwarding(selfDecl, params);
auto selfValue = ManagedValue::forUnmanaged(params[params.size() - 1]);
auto selfType = selfDecl->getType();

// if __isRemoteActor(self) {
// ...
// } else {
// ...
// }
{
FuncDecl* isRemoteFn = ctx.getIsRemoteDistributedActor();
assert(isRemoteFn &&
"Could not find 'is remote' function, is the '_Distributed' module available?");

ManagedValue selfAnyObject = B.createInitExistentialRef(loc, getLoweredType(ctx.getAnyObjectType()),
CanType(selfType),
selfValue, {});
auto result = emitApplyOfLibraryIntrinsic(loc, isRemoteFn, SubstitutionMap(),
{selfAnyObject}, SGFContext());

SILValue isRemoteResult = std::move(result).forwardAsSingleValue(*this, loc);
SILValue isRemoteResultUnwrapped = emitUnwrapIntegerResult(loc, isRemoteResult);

B.createCondBranch(loc, isRemoteResultUnwrapped, isRemoteBB, isLocalBB);
}

// // if __isRemoteActor(self)
// {
// return try await self._remote_X(...)
// }
{
B.emitBlock(isRemoteBB);

auto *selfTyDecl = FunctionDC->getParent()->getSelfNominalTypeDecl();
assert(selfTyDecl && "distributed function declared outside of actor");

auto remoteFnDecl = selfTyDecl->lookupDirectRemoteFunc(fd);
assert(remoteFnDecl && "Could not find _remote_<dist_func_name> function");
auto remoteFnRef = SILDeclRef(remoteFnDecl);

SILGenFunctionBuilder builder(SGM);
auto remoteFnSIL = builder.getOrCreateFunction(loc, remoteFnRef, ForDefinition);
SILValue remoteFn = B.createFunctionRefFor(loc, remoteFnSIL);

auto subs = F.getForwardingSubstitutionMap();

SmallVector<SILValue, 8> remoteParams(params);

B.createTryApply(loc, remoteFn, subs, remoteParams, remoteReturnBB, remoteErrorBB);
}

// // else
// {
// return (try)? (await)? self.X(...)
// }
{
B.emitBlock(isLocalBB);

auto nativeMethodTy = SGM.Types.getConstantOverrideType(getTypeExpansionContext(),
native);
auto nativeFnSILTy = SILType::getPrimitiveObjectType(nativeMethodTy);
auto nativeSilFnType = nativeFnSILTy.castTo<SILFunctionType>();

SILValue nativeFn = emitClassMethodRef(
loc, params[params.size() - 1], native, nativeMethodTy);
auto subs = F.getForwardingSubstitutionMap();

if (nativeSilFnType->hasErrorResult()) {
B.createTryApply(loc, nativeFn, subs, params, localReturnBB, localErrorBB);
} else {
auto result = B.createApply(loc, nativeFn, subs, params);
B.createBranch(loc, returnBB, {result});
}
}

{
B.emitBlock(remoteErrorBB);
SILValue error = remoteErrorBB->createPhiArgument(
fnConv.getSILErrorType(getTypeExpansionContext()),
OwnershipKind::Owned);

B.createBranch(loc, errorBB, {error});
}

{
B.emitBlock(localErrorBB);
SILValue error = localErrorBB->createPhiArgument(
fnConv.getSILErrorType(getTypeExpansionContext()),
OwnershipKind::Owned);

B.createBranch(loc, errorBB, {error});
}

{
B.emitBlock(remoteReturnBB);
SILValue result = remoteReturnBB->createPhiArgument(
resultType, OwnershipKind::Owned);
B.createBranch(loc, returnBB, {result});
}

{
B.emitBlock(localReturnBB);
SILValue result = localReturnBB->createPhiArgument(
resultType, OwnershipKind::Owned);
B.createBranch(loc, returnBB, {result});
}

// Emit return logic
{
B.emitBlock(returnBB);
SILValue resArg = returnBB->createPhiArgument(
resultType, OwnershipKind::Owned);
B.createReturn(loc, resArg);
}

// Emit the rethrow logic.
{
B.emitBlock(errorBB);
SILValue error = errorBB->createPhiArgument(
fnConv.getSILErrorType(getTypeExpansionContext()),
OwnershipKind::Owned);

Cleanups.emitCleanupsForReturn(CleanupLocation(loc), IsForUnwind);
B.createThrow(loc, error);
}
}

static SILValue
getThunkedForeignFunctionRef(SILGenFunction &SGF,
SILLocation loc,
Expand Down
Loading