Identify which tuple item fails to implement a trait when using fake variadics
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
trait WorksOnDefault {
fn do_something() {}
}
impl<T: Default> WorksOnDefault for T {}
fn main() {
let _success = <(i32, u32, String)>::do_something();
let _failure = <(i32, &u32, String)>::do_something();
}
Current output
error[E0599]: the function or associated item `do_something` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
--> examples/hello_world.rs:11:28
|
11 | <(i32, &u32, String)>::do_something();
| ^^^^^^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
|
note: the following trait bounds were not satisfied:
`&(i32, &u32, String): Default`
`&mut (i32, &u32, String): Default`
`(i32, &u32, String): Default`
Desired output
No method `works_on_default` found for <(i32, &u32, String)>`
The method `do_something` is available via the `WorksOnDefault` trait for any type T where T implements the `Default` trait.
If every member of the tuple (i32, &u32, String) implemented the `Default` trait, the `Default` trait would be implemented for the tuple.
However, `&u32` does not implement the `Default` trait.
note: did you mean `u32`, which implements the `Default` trait?
Rationale and extra context
This is an extremely common pattern for Bevy, primarily in our system and bundle code patterns. The poor error messages are one of our largest UX / teaching problems,. See https://github.com/rust-lang/rust/issues/89681 for that specific issue, which could be fixed by more general improvements here.
This pattern occurs all over the place: the minimal example here uses Default, which relies on the same flavor of fake variadics for tuples where all tuple elements implement a given trait. Bevy's Bundle tuples matches this form exactly, while our Systems use the same sort of trick but with functions, where each parameter must implement SystemParam.
Other cases
fn main(){
let _successful_default = <(i32, u32, String)>::default();
let _failed_default = <(i32, &u32, String)>::default();
}
The error output when calling methods from the trait directly correctly identifies the problematic variant:
error[E0599]: the function or associated item `default` exists for tuple `(i32, &u32, String)`, but its trait bounds were not satisfied
--> src/main.rs:3:50
|
3 | let _failed_default = <(i32, &u32, String)>::default();
| ^^^^^^^ function or associated item cannot be called on `(i32, &u32, String)` due to unsatisfied trait bounds
|
= note: the following trait bounds were not satisfied:
`&u32: Default`
which is required by `(i32, &u32, String): Default`
``
Rust Version
rustc 1.87.0 (17067e9ac 2025-05-09)
binary: rustc
commit-hash: 17067e9ac6d7ecb70e50f92c1944e545188d2359
commit-date: 2025-05-09
host: x86_64-unknown-linux-gnu
release: 1.87.0
LLVM version: 20.1.1
Anything else?
Discussed with @estebank and @joshtriplett at RustWeek 2025, where I was encouraged to file an issue so we can improve diagnostics without waiting on full variadics!
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
Reproduce the diagnostic with the minimal example in examples/hello_world.rs and compare it with the direct Default case in src/main.rs using rustc 1.87.0. Start by examining how these tuple trait-bound errors are reported. Done means the fake-variadic case identifies the tuple element that lacks the required trait while preserving the existing diagnostic context.
Written by the indexing model from the issue text.
Assessment
- Tech stack
- rust
- Domain
- compilers
- Issue type
- Bug
- Difficulty
- 4/5
- Estimated time
- 3-5 days
- Activity status
- Quiet
- Clarity
- Mostly clear
- Newbie friendliness
- 48/100