Files
Elsa Keirouz 81480212ff [Distributed] Don't hop to the actor before a distributed thunk witness call
A cross-actor call to a synchronous distributed func is marked implicitly
async, with the actor as its hop target. callsDistributedThunk() is meant
to skip that hop when the call is dispatched through the distributed
thunk, which never needs to run on the actor. It decides this by checking
whether the callee's SILDeclRef is a distributed thunk reference. That is
the case for direct calls, but not for calls through a protocol
requirement: there the callee still names the requirement, and it is
redirected to the requirement's distributed thunk only later, when the
callee value is emitted (Callee::getFnValue). Generic code therefore
still emitted:

  hop_to_executor %w
  try_apply witness_method $W, #P.f!distributed_thunk(...)

which hops onto an actor that may be a remote reference, before the
thunk's isRemote check. For a remote reference the hop lands on
DistributedRemoteActorReferenceExecutor, whose enqueue is a fatal error.

OptimizeHopToExecutor normally deletes this hop, which is why it went
unnoticed. With -enable-sil-opaque-values, AddressLowering materializes
the @in_guaranteed argument with a store_borrow between the hop and the
call, the hop survives causing a crash with the following error:
"Attempted to enqueue ExecutorJob ... on executor of remote distributed actor reference!".

Make callsDistributedThunk() also return true for witness method callees
that will be redirected to the thunk. It asks the same question as
getFnValue so the two decisions cannot diverge.

Add test/Distributed/SIL/distributed_thunk_call_no_hop.swift, which checks
that no hop to the actor is emitted before direct, generic and
distributed var calls, with and without opaque values.
2026-10-08 15:09:37 +01:00
..