-
Notifications
You must be signed in to change notification settings - Fork 10.5k
[Distributed] Fix when we invoke thunk, base it on typesystem implicit effects #39542
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
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
Original file line number | Diff line number | Diff line change |
---|---|---|
|
@@ -1003,14 +1003,16 @@ namespace { | |
/// | ||
/// and we reach up to mark the CallExpr. | ||
void markNearestCallAsImplicitly( | ||
Optional<ImplicitActorHopTarget> setAsync, bool setThrows = false) { | ||
Optional<ImplicitActorHopTarget> setAsync, | ||
bool setThrows = false, bool setDistributedThunk = false) { | ||
assert(applyStack.size() > 0 && "not contained within an Apply?"); | ||
|
||
const auto End = applyStack.rend(); | ||
for (auto I = applyStack.rbegin(); I != End; ++I) | ||
if (auto call = dyn_cast<CallExpr>(*I)) { | ||
if (setAsync) call->setImplicitlyAsync(*setAsync); | ||
if (setThrows) call->setImplicitlyThrows(true); | ||
if (setDistributedThunk) call->setShouldApplyDistributedThunk(true); | ||
return; | ||
} | ||
llvm_unreachable("expected a CallExpr in applyStack!"); | ||
|
@@ -1667,7 +1669,6 @@ namespace { | |
ThrowsMarkingResult tryMarkImplicitlyThrows(SourceLoc declLoc, | ||
ConcreteDeclRef concDeclRef, | ||
Expr* context) { | ||
|
||
ValueDecl *decl = concDeclRef.getDecl(); | ||
ThrowsMarkingResult result = ThrowsMarkingResult::NotFound; | ||
|
||
|
@@ -1869,8 +1870,11 @@ namespace { | |
} | ||
|
||
switch (contextIsolation) { | ||
case ActorIsolation::ActorInstance: | ||
case ActorIsolation::DistributedActorInstance: { | ||
case ActorIsolation::DistributedActorInstance: | ||
markNearestCallAsImplicitly(/*setAsync*/None, /*setThrows*/false, | ||
/*setDistributedThunk*/true); | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. I don't understand this. It doesn't seem like There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Yeah I think we can collapse the two - an implicit throws (currently) always implies that it's a distributed call. I wasn't sure if we want to keep it separate, technically there could be other reasons for an implicit throw in the future I guess...? We also need to cause the think even if the implicit throws is not in effect because the func is throwing anyway |
||
LLVM_FALLTHROUGH; | ||
case ActorIsolation::ActorInstance: { | ||
auto result = tryMarkImplicitlyAsync( | ||
loc, valueRef, context, | ||
ImplicitActorHopTarget::forGlobalActor(globalActor)); | ||
|
@@ -2277,7 +2281,10 @@ namespace { | |
} else if (func->isDistributed()) { | ||
tryMarkImplicitlyAsync(memberLoc, memberRef, context, | ||
ImplicitActorHopTarget::forInstanceSelf()); | ||
tryMarkImplicitlyThrows(memberLoc, memberRef, context); | ||
tryMarkImplicitlyThrows(memberLoc, memberRef, context); | ||
markNearestCallAsImplicitly(/*setAsync*/None, /*setThrows*/false, | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. Oh, this is because the |
||
/*setDistributedThunk*/true); | ||
|
||
} else { | ||
// neither static or distributed, apply full distributed isolation | ||
ctx.Diags.diagnose(memberLoc, diag::distributed_actor_isolated_method) | ||
|
@@ -2362,8 +2369,7 @@ namespace { | |
} | ||
|
||
// It wasn't a distributed func, so ban the access | ||
// TODO(distributed): handle subscripts here too | ||
if (auto var = dyn_cast<VarDecl>(member)) { | ||
if (isPropOrSubscript(member)) { | ||
ctx.Diags.diagnose( | ||
memberLoc, diag::distributed_actor_isolated_non_self_reference, | ||
member->getDescriptiveKind(), member->getName()); | ||
|
@@ -2379,6 +2385,8 @@ namespace { | |
if (isolation.getActorType()->isDistributedActor() && | ||
!isolatedActor.isPotentiallyIsolated) { | ||
tryMarkImplicitlyThrows(memberLoc, memberRef, context); | ||
markNearestCallAsImplicitly(/*setAsync*/None, /*setThrows*/false, | ||
/*setDistributedThunk*/true); | ||
} | ||
|
||
if (implicitAsyncResult == AsyncMarkingResult::FoundAsync) | ||
|
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -1,4 +1,4 @@ | ||
// RUN: %target-run-simple-swift(-Xfrontend -enable-experimental-distributed -parse-as-library) | %FileCheck %s --dump-input=always | ||
// RUN: %target-run-simple-swift(-Xfrontend -disable-availability-checking -Xfrontend -enable-experimental-distributed -parse-as-library) | %FileCheck %s --dump-input=always | ||
|
||
// REQUIRES: executable_test | ||
// REQUIRES: concurrency | ||
|
@@ -11,8 +11,6 @@ | |
// rdar://77798215 | ||
// UNSUPPORTED: OS=windows-msvc | ||
|
||
// REQUIRES: rdar78290608 | ||
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. we enable all of them in #38914 |
||
|
||
import _Distributed | ||
import _Concurrency | ||
|
||
|
@@ -43,6 +41,31 @@ distributed actor SomeSpecificDistributedActor { | |
"local(\(#function))" | ||
} | ||
|
||
distributed func callTaskSelf_inner() async throws -> String { | ||
"local(\(#function))" | ||
} | ||
distributed func callTaskSelf() async -> String { | ||
do { | ||
return try await Task { | ||
let called = try await callTaskSelf_inner() // shouldn't use the distributed thunk! | ||
return "local(\(#function)) -> \(called)" | ||
}.value | ||
} catch { | ||
return "WRONG local(\(#function)) thrown(\(error))" | ||
} | ||
} | ||
|
||
distributed func callDetachedSelf() async -> String { | ||
do { | ||
return try await Task.detached { | ||
let called = try await self.callTaskSelf_inner() // shouldn't use the distributed thunk! | ||
return "local(\(#function)) -> \(called)" | ||
}.value | ||
} catch { | ||
return "WRONG local(\(#function)) thrown(\(error))" | ||
} | ||
} | ||
|
||
// === errors | ||
|
||
distributed func helloThrowsImplBoom() throws -> String { | ||
|
@@ -76,6 +99,21 @@ extension SomeSpecificDistributedActor { | |
"remote(\(#function))" | ||
} | ||
|
||
@_dynamicReplacement(for:_remote_callTaskSelf()) | ||
nonisolated func _remote_impl_callTaskSelf() async throws -> String { | ||
"remote(\(#function))" | ||
} | ||
|
||
@_dynamicReplacement(for:_remote_callDetachedSelf()) | ||
nonisolated func _remote_impl_callDetachedSelf() async throws -> String { | ||
"remote(\(#function))" | ||
} | ||
|
||
@_dynamicReplacement(for:_remote_callTaskSelf_inner()) | ||
nonisolated func _remote_impl_callTaskSelf_inner() async throws -> String { | ||
"remote(\(#function))" | ||
} | ||
|
||
// === errors | ||
|
||
@_dynamicReplacement(for:_remote_helloThrowsImplBoom()) | ||
|
@@ -103,9 +141,6 @@ func __isLocalActor(_ actor: AnyObject) -> Bool { | |
@available(SwiftStdlib 5.5, *) | ||
struct ActorAddress: ActorIdentity { | ||
let address: String | ||
init(parse address : String) { | ||
self.address = address | ||
} | ||
} | ||
|
||
@available(SwiftStdlib 5.5, *) | ||
|
@@ -114,15 +149,15 @@ struct FakeTransport: ActorTransport { | |
fatalError("not implemented:\(#function)") | ||
} | ||
|
||
func resolve<Act>(_ identity: Act.ID, as actorType: Act.Type) | ||
func resolve<Act>(_ identity: AnyActorIdentity, as actorType: Act.Type) | ||
throws -> Act? | ||
where Act: DistributedActor { | ||
return nil | ||
} | ||
|
||
func assignIdentity<Act>(_ actorType: Act.Type) -> AnyActorIdentity | ||
where Act: DistributedActor { | ||
.init(ActorAddress(parse: "")) | ||
.init(ActorAddress(address: "")) | ||
} | ||
|
||
func actorReady<Act>(_ actor: Act) where Act: DistributedActor { | ||
|
@@ -151,25 +186,31 @@ func test_remote_invoke(address: ActorAddress, transport: ActorTransport) async | |
let h4 = try! await actor.hello() | ||
print("\(personality) - hello: \(h4)") | ||
|
||
let h5 = try! await actor.callTaskSelf() | ||
print("\(personality) - callTaskSelf: \(h5)") | ||
|
||
let h6 = try! await actor.callDetachedSelf() | ||
print("\(personality) - callDetachedSelf: \(h6)") | ||
|
||
// error throws | ||
if __isRemoteActor(actor) { | ||
do { | ||
_ = try await actor.helloThrowsTransportBoom() | ||
preconditionFailure("helloThrowsTransportBoom: should have thrown") | ||
print("WRONG: helloThrowsTransportBoom: should have thrown") | ||
} catch { | ||
print("\(personality) - helloThrowsTransportBoom: \(error)") | ||
} | ||
} else { | ||
do { | ||
_ = try await actor.helloThrowsImplBoom() | ||
preconditionFailure("helloThrowsImplBoom: Should have thrown") | ||
print("WRONG: helloThrowsImplBoom: Should have thrown") | ||
ktoso marked this conversation as resolved.
Show resolved
Hide resolved
|
||
} catch { | ||
print("\(personality) - helloThrowsImplBoom: \(error)") | ||
} | ||
} | ||
} | ||
|
||
let remote = try! SomeSpecificDistributedActor(resolve: .init(address), using: transport) | ||
let remote = try! SomeSpecificDistributedActor.resolve(.init(address), using: transport) | ||
assert(__isRemoteActor(remote) == true, "should be remote") | ||
|
||
let local = SomeSpecificDistributedActor(transport: transport) | ||
|
@@ -182,6 +223,8 @@ func test_remote_invoke(address: ActorAddress, transport: ActorTransport) async | |
// CHECK: local - helloAsync: local(helloAsync()) | ||
// CHECK: local - helloThrows: local(helloThrows()) | ||
// CHECK: local - hello: local(hello()) | ||
// CHECK: local - callTaskSelf: local(callTaskSelf()) -> local(callTaskSelf_inner()) | ||
// CHECK: local - callDetachedSelf: local(callDetachedSelf()) -> local(callTaskSelf_inner()) | ||
// CHECK: local - helloThrowsImplBoom: Boom(whoFailed: "impl") | ||
|
||
print("remote isRemote: \(__isRemoteActor(remote))") | ||
|
@@ -191,6 +234,8 @@ func test_remote_invoke(address: ActorAddress, transport: ActorTransport) async | |
// CHECK: remote - helloAsync: remote(_remote_impl_helloAsync()) | ||
// CHECK: remote - helloThrows: remote(_remote_impl_helloThrows()) | ||
// CHECK: remote - hello: remote(_remote_impl_hello()) | ||
// CHECK: remote - callTaskSelf: remote(_remote_impl_callTaskSelf()) | ||
// CHECK: remote - callDetachedSelf: remote(_remote_impl_callDetachedSelf()) | ||
// CHECK: remote - helloThrowsTransportBoom: Boom(whoFailed: "transport") | ||
|
||
print(local) | ||
|
@@ -200,7 +245,7 @@ func test_remote_invoke(address: ActorAddress, transport: ActorTransport) async | |
@available(SwiftStdlib 5.5, *) | ||
@main struct Main { | ||
static func main() async { | ||
let address = ActorAddress(parse: "") | ||
let address = ActorAddress(address: "") | ||
let transport = FakeTransport() | ||
|
||
await test_remote_invoke(address: address, transport: transport) | ||
|
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This needs to be set to
false
in theApplyExpr
constructor, or you'll end up with spuriously-distributed calls due to uninitialized memory.There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Oh man, thanks I totally forgot about that 😱