next solver: `Send` proofs through nested types need a much deeper recursion limit
Nobody has claimed this yet.
- 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
First steps
- Read the whole issue, then the project's contributing guide.
- Comment on the issue to say you are picking it up — it saves two people doing the same work.
- Fork the repository and make your change on a branch.
- 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