Skip to content

[Distributed] Introduce "roundtrip" test and AS, remove duplication and cleanups #41056

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 3 commits into from
Jan 28, 2022
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
30 changes: 15 additions & 15 deletions include/swift/AST/ASTContext.h
Original file line number Diff line number Diff line change
Expand Up @@ -670,38 +670,38 @@ class ASTContext final {
NominalTypeDecl *actorOrSystem,
bool isVoidReturn) const;

/// Retrieve the declaration of DistributedActorSystem.make().
///
/// \param actorOrSystem distributed actor or actor system to get the
/// remoteCall function for. Since the method we're looking for is an ad-hoc
/// requirement, a specific type MUST be passed here as it is not possible
/// to obtain the decl from just the `DistributedActorSystem` protocol type.
FuncDecl *getMakeInvocationEncoderOnDistributedActorSystem(
NominalTypeDecl *actorOrSystem) const;

// Retrieve the declaration of DistributedInvocationEncoder.recordArgument(_:).
//
// \param nominal optionally provide a 'NominalTypeDecl' from which the
// function decl shall be extracted. This is useful to avoid witness calls
// through the protocol which is looked up when nominal is null.
FuncDecl *getRecordArgumentOnDistributedInvocationEncoder(
NominalTypeDecl *nominal = nullptr) const;
NominalTypeDecl *nominal) const;

// Retrieve the declaration of DistributedInvocationEncoder.recordErrorType().
//
// \param nominal optionally provide a 'NominalTypeDecl' from which the
// function decl shall be extracted. This is useful to avoid witness calls
// through the protocol which is looked up when nominal is null.
// Retrieve the declaration of DistributedInvocationEncoder.recordErrorType(_:).
FuncDecl *getRecordErrorTypeOnDistributedInvocationEncoder(
NominalTypeDecl *nominal = nullptr) const;
NominalTypeDecl *nominal) const;

// Retrieve the declaration of DistributedInvocationEncoder.recordReturnType().
//
// \param nominal optionally provide a 'NominalTypeDecl' from which the
// function decl shall be extracted. This is useful to avoid witness calls
// through the protocol which is looked up when nominal is null.
// Retrieve the declaration of DistributedInvocationEncoder.recordReturnType(_:).
FuncDecl *getRecordReturnTypeOnDistributedInvocationEncoder(
NominalTypeDecl *nominal = nullptr) const;
NominalTypeDecl *nominal) const;

// Retrieve the declaration of DistributedInvocationEncoder.doneRecording().
//
// \param nominal optionally provide a 'NominalTypeDecl' from which the
// function decl shall be extracted. This is useful to avoid witness calls
// through the protocol which is looked up when nominal is null.
FuncDecl *getDoneRecordingOnDistributedInvocationEncoder(
NominalTypeDecl *nominal = nullptr) const;

NominalTypeDecl *nominal) const;

/// Look for the declaration with the given name within the
/// passed in module.
Expand Down
3 changes: 0 additions & 3 deletions include/swift/AST/Decl.h
Original file line number Diff line number Diff line change
Expand Up @@ -3370,9 +3370,6 @@ class NominalTypeDecl : public GenericTypeDecl, public IterableDeclContext {
/// Find, or potentially synthesize, the implicit 'id' property of this actor.
VarDecl *getDistributedActorIDProperty() const;

/// Find the 'makeInvocation' function.
AbstractFunctionDecl* getDistributedActorSystemMakeInvocationEncoderFunction() const;

/// Find the 'RemoteCallTarget.init(_mangledName:)' initializer function
ConstructorDecl* getDistributedRemoteCallTargetInitFunction() const;

Expand Down
126 changes: 49 additions & 77 deletions lib/AST/ASTContext.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -267,18 +267,6 @@ struct ASTContext::Implementation {
/// -> Builtin.Int1
FuncDecl *IsOSVersionAtLeastDecl = nullptr;

/// func recordArgument(_:) throws
FuncDecl *RecordArgumentDistributedInvocationEncoderDecl = nullptr;

/// func recordErrorType(_:) throws
FuncDecl *RecordErrorTypeDistributedInvocationEncoderDecl = nullptr;

/// func recordReturnType(_:) throws
FuncDecl *RecordReturnTypeDistributedInvocationEncoderDecl = nullptr;

/// func doneRecording() throws
FuncDecl *DoneRecordingDistributedInvocationEncoderDecl = nullptr;

/// The set of known protocols, lazily populated as needed.
ProtocolDecl *KnownProtocols[NumKnownProtocols] = { };

Expand Down Expand Up @@ -1295,7 +1283,7 @@ AbstractFunctionDecl *ASTContext::getRemoteCallOnDistributedActorSystem(
NominalTypeDecl *actorOrSystem, bool isVoidReturn) const {
assert(actorOrSystem && "distributed actor (or system) decl must be provided");
const NominalTypeDecl *system = actorOrSystem;
if (actorOrSystem && actorOrSystem->isDistributedActor()) {
if (actorOrSystem->isDistributedActor()) {
auto var = actorOrSystem->getDistributedActorSystemProperty();
system = var->getInterfaceType()->getAnyNominal();
}
Expand All @@ -1310,113 +1298,99 @@ AbstractFunctionDecl *ASTContext::getRemoteCallOnDistributedActorSystem(
nullptr);
}

FuncDecl *ASTContext::getRecordArgumentOnDistributedInvocationEncoder(
NominalTypeDecl *nominal) const {
if (getImpl().RecordArgumentDistributedInvocationEncoderDecl) {
return getImpl().RecordArgumentDistributedInvocationEncoderDecl;
FuncDecl *ASTContext::getMakeInvocationEncoderOnDistributedActorSystem(
NominalTypeDecl *actorOrSystem) const {
NominalTypeDecl *system = actorOrSystem;
assert(actorOrSystem && "distributed actor (or system) decl must be provided");
if (actorOrSystem->isDistributedActor()) {
auto var = actorOrSystem->getDistributedActorSystemProperty();
system = var->getInterfaceType()->getAnyNominal();
}

NominalTypeDecl *encoderProto = nominal ?
nominal :
getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
assert(encoderProto && "Missing DistributedTargetInvocationEncoder protocol");
for (auto result : encoderProto->lookupDirect(Id_recordArgument)) {
for (auto result : system->lookupDirect(Id_makeInvocationEncoder)) {
auto *fd = dyn_cast<FuncDecl>(result);
if (!fd)
continue;
if (fd->getParameters()->size() != 0)
continue;
if (fd->hasAsync())
continue;
if (fd->hasThrows())
continue;
// TODO(distributed): more checks, return type etc

return fd;
}

return nullptr;
}

FuncDecl *ASTContext::getRecordArgumentOnDistributedInvocationEncoder(
NominalTypeDecl *nominal) const {
for (auto result : nominal->lookupDirect(Id_recordArgument)) {
auto *fd = dyn_cast<FuncDecl>(result);
if (!fd)
continue;
if (fd->getParameters()->size() != 1)
continue;

if (fd->hasAsync())
continue;
if (!fd->hasThrows())
continue;
// TODO(distributed): more checks

if (fd->getResultInterfaceType()->isVoid() &&
fd->hasThrows() &&
!fd->hasAsync()) {
getImpl().RecordArgumentDistributedInvocationEncoderDecl = fd;
if (fd->getResultInterfaceType()->isVoid())
return fd;
}
}

return nullptr;
}

FuncDecl *ASTContext::getRecordErrorTypeOnDistributedInvocationEncoder(
NominalTypeDecl *nominal) const {
if (getImpl().RecordErrorTypeDistributedInvocationEncoderDecl) {
return getImpl().RecordErrorTypeDistributedInvocationEncoderDecl;
}

NominalTypeDecl *encoderProto =
nominal
? nominal
: getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
assert(encoderProto && "Missing DistributedTargetInvocationEncoder protocol");
for (auto result : encoderProto->lookupDirect(Id_recordErrorType)) {
for (auto result : nominal->lookupDirect(Id_recordErrorType)) {
auto *fd = dyn_cast<FuncDecl>(result);
if (!fd)
continue;

if (fd->getParameters()->size() != 1)
continue;
if (fd->hasAsync())
continue;
if (!fd->hasThrows())
continue;
// TODO(distributed): more checks

// TODO(distributed): more checks that the arg type matches (!!!)

if (fd->getResultInterfaceType()->isVoid() &&
fd->hasThrows() &&
!fd->hasAsync()) {
getImpl().RecordErrorTypeDistributedInvocationEncoderDecl = fd;
if (fd->getResultInterfaceType()->isVoid())
return fd;
}
}

return nullptr;
}

FuncDecl *ASTContext::getRecordReturnTypeOnDistributedInvocationEncoder(
NominalTypeDecl *nominal) const {
if (getImpl().RecordReturnTypeDistributedInvocationEncoderDecl) {
return getImpl().RecordReturnTypeDistributedInvocationEncoderDecl;
}

NominalTypeDecl *encoderProto =
nominal
? nominal
: getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
assert(encoderProto && "Missing DistributedTargetInvocationEncoder protocol");
for (auto result : encoderProto->lookupDirect(Id_recordReturnType)) {
for (auto result : nominal->lookupDirect(Id_recordReturnType)) {
auto *fd = dyn_cast<FuncDecl>(result);
if (!fd)
continue;

if (fd->getParameters()->size() != 1)
continue;
if (fd->hasAsync())
continue;
if (!fd->hasThrows())
continue;
// TODO(distributed): more checks

// TODO(distributed): more checks that the arg type matches (!!!)

if (fd->getResultInterfaceType()->isVoid() &&
fd->hasThrows() &&
!fd->hasAsync()) {
getImpl().RecordReturnTypeDistributedInvocationEncoderDecl = fd;
if (fd->getResultInterfaceType()->isVoid())
return fd;
}
}

return nullptr;
}

FuncDecl *ASTContext::getDoneRecordingOnDistributedInvocationEncoder(
NominalTypeDecl *nominal) const {
if (getImpl().DoneRecordingDistributedInvocationEncoderDecl) {
return getImpl().DoneRecordingDistributedInvocationEncoderDecl;
}

NominalTypeDecl *encoderProto =
nominal
? nominal
: getProtocol(KnownProtocolKind::DistributedTargetInvocationEncoder);
assert(encoderProto && "Missing DistributedTargetInvocationEncoder protocol");
for (auto result : encoderProto->lookupDirect(Id_doneRecording)) {
for (auto result : nominal->lookupDirect(Id_doneRecording)) {
auto *fd = dyn_cast<FuncDecl>(result);
if (!fd)
continue;
Expand All @@ -1426,10 +1400,8 @@ FuncDecl *ASTContext::getDoneRecordingOnDistributedInvocationEncoder(

if (fd->getResultInterfaceType()->isVoid() &&
fd->hasThrows() &&
!fd->hasAsync()) {
getImpl().DoneRecordingDistributedInvocationEncoderDecl = fd;
!fd->hasAsync())
return fd;
}
}

return nullptr;
Expand Down
62 changes: 26 additions & 36 deletions lib/AST/Decl.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -7402,17 +7402,14 @@ bool AbstractFunctionDecl::isDistributedActorSystemRemoteCall(bool isVoidReturn)
auto callId = isVoidReturn ? C.Id_remoteCallVoid : C.Id_remoteCall;

// Check the name
if (this->getBaseName() != callId)
if (getBaseName() != callId)
return false;

auto params = this->getParameters();
auto params = getParameters();
unsigned int expectedParamNum = isVoidReturn ? 4 : 5;

// Check the expected argument count
// - for value returning remoteCall:
if (!params || (!isVoidReturn && params->size() != 5))
return false;
// - for void returning remoteCallVoid:
if (!params || (isVoidReturn && params->size() != 4))
// Check the expected argument count:
if (!params || params->size() != expectedParamNum)
return false;

// Check API names of the arguments
Expand All @@ -7422,7 +7419,7 @@ bool AbstractFunctionDecl::isDistributedActorSystemRemoteCall(bool isVoidReturn)
auto thrownTypeParam = params->get(3);
if (actorParam->getArgumentName() != C.Id_on ||
targetParam->getArgumentName() != C.Id_target ||
invocationParam->getArgumentName() != C.Id_invocationDecoder ||
invocationParam->getArgumentName() != C.Id_invocation ||
thrownTypeParam->getArgumentName() != C.Id_throwing)
return false;

Expand All @@ -7432,41 +7429,34 @@ bool AbstractFunctionDecl::isDistributedActorSystemRemoteCall(bool isVoidReturn)
return false;
}

// FIXME(distributed): check the right types of the args and generics...
// FIXME(distributed): check access level actually is ok, i.e. not private etc

return true;
}
if (!isGeneric())
return false;

bool AbstractFunctionDecl::isDistributed() const {
return this->getAttrs().hasAttribute<DistributedActorAttr>();
}
auto genericParams = getGenericParams();
unsigned int expectedGenericParamNum = isVoidReturn ? 2 : 3;

AbstractFunctionDecl*
NominalTypeDecl::getDistributedActorSystemMakeInvocationEncoderFunction() const {
auto &C = this->getASTContext();
NominalTypeDecl *system = const_cast<NominalTypeDecl *>(this);
if (this->isDistributedActor()) {
auto var = this->getDistributedActorSystemProperty();
system = var->getInterfaceType()->getAnyNominal();
// We expect: Act, Err, Res?
if (genericParams->size() != expectedGenericParamNum) {
return false;
}

// FIXME(distributed): implement more properly...
for (auto value : system->lookupDirect(C.Id_makeInvocationEncoder)) {
auto func = dyn_cast<AbstractFunctionDecl>(value);
if (!func)
continue;
// FIXME(distributed): check the exact generic requirements

if (func->getParameters()->size() != 0)
continue;
// === check the return type
if (isVoidReturn) {
if (auto func = dyn_cast<FuncDecl>(this))
if (!func->getResultInterfaceType()->isVoid())
return false;
}

// TODO(distriuted): return type must conform to our expected protocol
// FIXME(distributed): check the right types of the args and generics...
// FIXME(distributed): check access level actually is ok, i.e. not private etc

return func;
}
return true;
}

// TODO(distributed): make a Request for it?
return nullptr;
bool AbstractFunctionDecl::isDistributed() const {
return getAttrs().hasAttribute<DistributedActorAttr>();
}

ConstructorDecl*
Expand Down
8 changes: 4 additions & 4 deletions lib/SILGen/SILGenDistributed.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -724,8 +724,8 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {

// === `InvocationEncoder` types
AbstractFunctionDecl *makeInvocationEncoderFnDecl =
selfTyDecl->getDistributedActorSystemMakeInvocationEncoderFunction();
assert(makeInvocationEncoderFnDecl && "no remoteCall func found!");
ctx.getMakeInvocationEncoderOnDistributedActorSystem(selfTyDecl);
assert(makeInvocationEncoderFnDecl && "no 'makeInvocationEncoder' func found!");
auto makeInvocationEncoderFnRef = SILDeclRef(makeInvocationEncoderFnDecl);

ProtocolDecl *invocationEncoderProto =
Expand Down Expand Up @@ -882,7 +882,7 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {

// function_ref FakeActorSystem.makeInvocationEncoder()
// %19 = function_ref @$s27FakeDistributedActorSystems0aC6SystemV21makeInvocationEncoderAA0aG0VyF : $@convention(method) (@guaranteed FakeActorSystem) -> FakeInvocation // user: %20
auto makeInvocationEncoderFnSIL =
SILFunction *makeInvocationEncoderFnSIL =
builder.getOrCreateFunction(loc, makeInvocationEncoderFnRef, NotForDefinition);
SILValue makeInvocationEncoderFn =
B.createFunctionRefFor(loc, makeInvocationEncoderFnSIL);
Expand Down Expand Up @@ -1395,7 +1395,7 @@ void SILGenFunction::emitDistributedThunk(SILDeclRef thunk) {
}
assert(returnMetatypeValue);

// function_ref FakeActorSystem.remoteCall<A, B, C>(on:target:invocationDecoder:throwing:returning:)
// function_ref FakeActorSystem.remoteCall<A, B, C>(on:target:invocation:throwing:returning:)
// %49 = function_ref @$s27FakeDistributedActorSystems0aC6SystemV10remoteCall2on6target17invocationDecoder8throwing9returningq0_x_01_B006RemoteG6TargetVAA0A10InvocationVzq_mq0_mSgtYaKAJ0bC0RzSeR0_SER0_AA0C7AddressV2IDRtzr1_lF : $@convention(method) @async <τ_0_0, τ_0_1, τ_0_2 where τ_0_0 : DistributedActor, τ_0_2 : Decodable, τ_0_2 : Encodable, τ_0_0.ID == ActorAddress> (@guaranteed τ_0_0, @in_guaranteed RemoteCallTarget, @inout FakeInvocation, @thick τ_0_1.Type, Optional<@thick τ_0_2.Type>, @guaranteed FakeActorSystem) -> (@out τ_0_2, @error Error) // user: %50
auto remoteCallFnDecl =
ctx.getRemoteCallOnDistributedActorSystem(selfTyDecl, /*isVoid=*/resultType.isVoid());
Expand Down
Loading