[Concurrency/Distributed] ensure distributed thunks are @concurrent

Otherwise the "nonisolated nonsending by default" mode blows up as
distributed thunk signatures dont match expectations.

This undoes the fix from https://github.com/swiftlang/swift/pull/83940
and applies the fix on the synthesis side of the distributed thunks,
such that they are @concurrent always -- which keeps their old semantics
basically, regardless of what "default" mode we have.
This commit is contained in:
Konrad Malawski
2025-09-03 18:23:59 +09:00
parent 1b856e1fc9
commit ced1756142
3 changed files with 22 additions and 12 deletions

View File

@@ -737,8 +737,11 @@ static FuncDecl *createSameSignatureDistributedThunkDecl(DeclContext *DC,
thunk->setSynthesized(true); thunk->setSynthesized(true);
thunk->setDistributedThunk(true); thunk->setDistributedThunk(true);
// TODO(distributed): These would benefit from becoming nonisolated(nonsending)
thunk->getAttrs().add(NonisolatedAttr::createImplicit(C)); thunk->getAttrs().add(NonisolatedAttr::createImplicit(C));
// TODO(distributed): It would be nicer to make distributed thunks nonisolated(nonsending) instead;
// this way we would not hop off the caller when calling system.remoteCall;
// it'd need new ABI and the remoteCall also to become nonisolated(nonsending)
thunk->getAttrs().add(new (C) ConcurrentAttr(/*IsImplicit=*/true));
return thunk; return thunk;
} }

View File

@@ -5212,13 +5212,6 @@ getIsolationFromAttributes(const Decl *decl, bool shouldDiagnose = true,
if (decl->getASTContext().LangOpts.hasFeature( if (decl->getASTContext().LangOpts.hasFeature(
Feature::NonisolatedNonsendingByDefault)) { Feature::NonisolatedNonsendingByDefault)) {
if (auto *value = dyn_cast<ValueDecl>(decl)) { if (auto *value = dyn_cast<ValueDecl>(decl)) {
// TODO(distributed): make distributed thunks nonisolated(nonsending) and remove this if
if (value->isAsync() && value->isDistributedThunk()) {
// don't change isolation of distributed thunks until we make them nonisolated(nonsending),
// since the runtime calling them assumes they're just nonisolated right now.
return ActorIsolation::forNonisolated(nonisolatedAttr->isUnsafe());
}
if (value->isAsync() && if (value->isAsync() &&
value->getModuleContext() == decl->getASTContext().MainModule) { value->getModuleContext() == decl->getASTContext().MainModule) {
return ActorIsolation::forCallerIsolationInheriting(); return ActorIsolation::forCallerIsolationInheriting();

View File

@@ -33,15 +33,23 @@ distributed actor Greeter: CustomStringConvertible {
return "Echo: \(name) (impl on: \(self.id))" return "Echo: \(name) (impl on: \(self.id))"
} }
distributed func error() throws -> String {
throw SomeError()
}
nonisolated var description: String { nonisolated var description: String {
"\(Self.self)(\(id))" "\(Self.self)(\(id))"
} }
} }
extension Greeter {
distributed func echoInExtension(name: String) -> String {
return "Echo: \(name) (impl on: \(self.id))"
}
}
nonisolated extension Greeter {
distributed func echoInNonisolatedExtension(name: String) -> String {
return "Echo: \(name) (impl on: \(self.id))"
}
}
struct SomeError: Error {} struct SomeError: Error {}
// ==== Test ------------------------------------------------------------------- // ==== Test -------------------------------------------------------------------
@@ -64,6 +72,12 @@ func test() async throws {
print("got: \(reply)") print("got: \(reply)")
// CHECK: got: Echo: Caplin (impl on: ActorAddress(address: "<unique-id>")) // CHECK: got: Echo: Caplin (impl on: ActorAddress(address: "<unique-id>"))
// just double check there's no surprises with distributed thunks in extensions
_ = try await ref.echoInExtension(name: "Bob")
_ = try await ref.echoInNonisolatedExtension(name: "Alice")
print("OK") // CHECK: OK
} }
@main struct Main { @main struct Main {