rust-lang / rust-lang/rust

next solver: `Send` proofs through nested types need a much deeper recursion limit

Open
#162,648 2 comments 0 reactions 0 assignees View on GitHub

Nobody has claimed this yet.

C-bug I-compilemem needs-triage WG-trait-system-refactor
Dominant language
Rust
Stars
119k
Forks
16.1k
PR merge metrics
PR metrics pending

Description

Proving that the futures generated by remoc's #[rtc::remote] macro are Send reaches the recursion limit far earlier with the next solver than with the old one, and once it overflows, memory and time roughly triple.

Probably the same root cause as #161748 and #160036.

I tried this code

Cargo.toml:

[dependencies]
remoc = "0.20.2"
serde = { version = "1", features = ["derive"] }

src/lib.rs, each level's method returns the client of the level below:

#![recursion_limit = "256"]

use remoc::{robj::lazy_blob::LazyBlob, rtc};

macro_rules! level {
    ($name:ident $(, $next:ty)?) => {
        #[rtc::remote(server(Shared))]
        pub trait $name {
            $( async fn next(&self) -> Result<$next, rtc::CallError>; )?
            async fn blob(&self) -> Result<LazyBlob, rtc::CallError>;
        }
    };
}

level!(L0);
level!(L1, L0Client);
level!(L2, L1Client);
level!(L3, L2Client);
level!(L4, L3Client);

Code available at https://github.com/surban/remoc-next-solver-repro

I expected to see this happen

It compiles cleanly, as with -Znext-solver=coherence.

Instead, this happened

warning: overflow evaluating the requirement `impl Future<Output = Result<Forwarded<<L0ReqReceiver<Codec> as ServerBase>::Client>, ServeError>>: Send`
  --> src/lib.rs:12:9
   = note: which requires `{async fn body of <L0ReqReceiver<Codec> as ReqReceiver<Codec>>::forward()}: Send`
   ...
   = note: which requires `remoc::rch::mpsc::Receiver<Req<L0ReqValue<Codec>, L0ReqRef<Codec>, L0ReqRefMut<Codec>>, Codec, 16, 16777216>: Send`
   = note: which requires `Mutex<Option<tokio::sync::oneshot::Sender<ReceiverInner<Req<...>>>>>: Send`
   ...
   = note: and so on...
   = note: `#[warn(recursion_depth_exceeding_limit)]` (part of `#[warn(future_incompatible)]`) on by default

Without the recursion_limit attribute the next solver reports the warning already for a single level and six E0275 errors for five, where the old solver reports one error.

cargo check, peak rustc memory and time in type_check_crate from -Ztime-passes:

recursion limit next solver -Znext-solver=coherence
256 0.8 GB, 0.77 s, 1 warning 0.7 GB, 0.76 s, clean
128 (default) 2.5 GB, 2.62 s, 6 errors 0.7 GB, 0.26 s, 1 error

Each remoc channel wrapper is proven Send by unfolding its fields through tokio's channel internals, and the payload type occurs several times per wrapper, so the proof tree branches at every nesting level.

Workaround

remoc 0.20.2 has an explicit-auto-traits feature that adds unsafe impl Send/Sync for its channel types, with the bounds checked against the fields at compile time. With it the example type-checks in 0.4 s at 0.8 GB with either solver. I would rather not keep it: it is unsafe code in a crate that otherwise forbids it, it restates what the compiler already should infer, and it exists only to work around issues in the trait solver.

Meta

rustc 1.100.0-nightly (a36d05efa 2026-09-09)
binary: rustc
commit-hash: a36d05efab632d1ddf902b6a5c33b6d5d3b64131
commit-date: 2026-09-09
host: x86_64-unknown-linux-gnu
release: 1.100.0-nightly
LLVM version: 23.1.1

Contributor guide

Open the contributing guide

First steps

  1. Read the whole issue, then the project's contributing guide.
  2. Comment on the issue to say you are picking it up — it saves two people doing the same work.
  3. Fork the repository and make your change on a branch.
  4. Open a pull request that references the issue number.

Research direction

Start with the remoc-next-solver-repro example's Cargo.toml and src/lib.rs, then run cargo check at the reported recursion limits with and without -Znext-solver=coherence. Trace the next solver's Send proof recursion for the nested remote clients and compare its behavior with the old solver and the related issues. Done means the example type-checks without explicit-auto-traits, without spurious overflow errors, and without the reported excessive resource use.

Written by the indexing model from the issue text.

Assessment

Tech stack
rust
Domain
compilers
Issue type
Bug
Difficulty
5/5
Estimated time
Over a week
Activity status
Active
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.