From 7d1eb4c25633faa5e2fef84a86c354340d2c8c4e Mon Sep 17 00:00:00 2001 From: Alexander Shparun Date: Wed, 8 Oct 2025 19:07:50 +0200 Subject: [PATCH] [fleet] tail call hotfix GitOrigin-RevId: 8913cc6b19131c60dae6ad1a0380700b9877910f --- .../fleet/rpc/server/RpcExecutor.kt | 23 +++++++++++++------ 1 file changed, 16 insertions(+), 7 deletions(-) diff --git a/fleet/rpc.server/srcCommonMain/fleet/rpc/server/RpcExecutor.kt b/fleet/rpc.server/srcCommonMain/fleet/rpc/server/RpcExecutor.kt index bcf4089258d9..1412526a7bb6 100644 --- a/fleet/rpc.server/srcCommonMain/fleet/rpc/server/RpcExecutor.kt +++ b/fleet/rpc.server/srcCommonMain/fleet/rpc/server/RpcExecutor.kt @@ -21,6 +21,7 @@ import kotlinx.serialization.json.Json import fleet.multiplatform.shims.ConcurrentHashMap import fleet.multiplatform.shims.ConcurrentHashSet import fleet.util.async.withSupervisor +import kotlinx.serialization.builtins.serializer import kotlin.coroutines.EmptyCoroutineContext class RpcExecutor private constructor( @@ -207,16 +208,24 @@ class RpcExecutor private constructor( Json.encodeToJsonElement(InstanceId.serializer(), remoteObjectId) } else { - val (resultSerialized, streamDescriptors) = withSerializationContext("Result of ${message.displayName}", null, serviceScope) { - val kserializer = returnType.serializer(message.classMethodDisplayName()) - json.encodeToJsonElement(kserializer, result) + // tail call optimization might pass our continuation to whatever function was last in the method and we will get its return value + // usually kotlin will ignore it and replace with Unit, but because we are invoking an abstract lambda it gets confused + // TODO not the best approach, obviously, but it works without changes in the compiler plugin + if (returnType is RemoteKind.Data && returnType.serializer == Unit.serializer()) { + json.encodeToJsonElement(Unit.serializer(), Unit) } + else { + val (resultSerialized, streamDescriptors) = withSerializationContext("Result of ${message.displayName}", null, serviceScope) { + val kserializer = returnType.serializer(message.classMethodDisplayName()) + json.encodeToJsonElement(kserializer, result) + } - streamDescriptors.forEach { - registeredStreams.add(registerStream(serviceScope, it, clientId)) + streamDescriptors.forEach { + registeredStreams.add(registerStream(serviceScope, it, clientId)) + } + + resultSerialized } - - resultSerialized } logger.trace { "Sending result: requestId=${request.requestId}, result=$result" }