Adding a trait impl for an integer type causes existing code to break with misleading error
Nobody has claimed this yet.
- Dominant language
- Rust
- Stars
- 119k
- Forks
- 16.1k
- PR merge metrics
- PR metrics pending
Description
Code
#![allow(dead_code)]
// There's a type `Foo`...
struct Foo(pub usize);
// ...that you can easily create from a `usize`.
impl From<usize> for Foo {
fn from(value: usize) -> Self {
Foo(value)
}
}
// There's also a trait `FooLike`...
trait FooLike {}
// ...that is implemented by anything we can turn into a `Foo`.
impl<T> FooLike for T where Foo: From<T> {}
// I have a generic function that accepts any implementation of `FooLike`.
fn use_foo_like(_f: impl FooLike) -> Result<(), ()> {
Ok(())
}
fn main() -> Result<(), ()> {
// If I invoke that function with the literal `0`,
// the compiler correctly determines that it's a `usize`.
use_foo_like(0)
}
// However, if you uncomment the code below, the program no longer compiles.
// The error is:
// error[E0277]: the trait bound `Foo: From<i32>` is not satisfied
/*
impl From<u32> for Foo {
fn from(value: u32) -> Self {
Foo(value as usize)
}
}
*/
Current output
error[E0277]: the trait bound `Foo: From<i32>` is not satisfied
--> src/main.rs:26:18
|
26 | use_foo_like(0)
| ------------ ^ the trait `From<i32>` is not implemented for `Foo`
| |
| required by a bound introduced by this call
|
= help: the following other types implement trait `From<T>`:
`Foo` implements `From<u32>`
`Foo` implements `From<usize>`
note: required for `i32` to implement `FooLike`
--> src/main.rs:16:9
|
16 | impl<T> FooLike for T where Foo: From<T> {}
| ^^^^^^^ ^ ------- unsatisfied trait bound introduced here
note: required by a bound in `use_foo_like`
--> src/main.rs:19:26
|
19 | fn use_foo_like(_f: impl FooLike) -> Result<(), ()> {
| ^^^^^^^ required by this bound in `use_foo_like`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Desired output
error[E0277]: the integer type of literal `0` is ambiguous
--> src/main.rs:26:18
|
26 | use_foo_like(0)
| ------------ ^ trait `FooLike` is implemented for multiple integer types
| |
| required by a bound introduced by this call
|
= help: the following integer types implement trait `FooLike`:
`u32` implements `FooLike`
`usize` implements `FooLike`
note: when multiple integer types implement a trait, integer literals without a type hint are considered `i32`
hint: consider implementing `FooLike` for `i32`
note: required by a bound in `use_foo_like`
--> src/main.rs:19:26
|
19 | fn use_foo_like(_f: impl FooLike) -> Result<(), ()> {
| ^^^^^^^ required by this bound in `use_foo_like`
For more information about this error, try `rustc --explain E0277`.
error: could not compile `playground` (bin "playground") due to 1 previous error
Rationale and extra context
This appears to be an edge case in the type resolver. When only one integer type implements the necessary trait, the compiler can correctly infer that a bare integer literal must be of that type. However, when an implementation of that trait for a second integer type is added, it breaks existing user code because the type resolver is obligated to fall back to treating bare integer literals as i32.
The current diagnostic output doesn't explain why it's talking about i32, and users will likely be very surprised that adding a trait implementation breaks their build.
Other cases
Rust Version
rustc 1.85.0 (4d91de4e4 2025-02-17)
binary: rustc
commit-hash: 4d91de4e48198da2e33413efdcd9cd2cc0c46688
commit-date: 2025-02-17
host: aarch64-apple-darwin
release: 1.85.0
LLVM version: 19.1.7
Anything else?
No response
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 example in the linked Playground using rustc 1.85.0, first with only From, then with From. Compare the diagnostics at use_foo_like(0). Done means the multiple-integer ambiguity is explained, applicable FooLike integer types are identified, and the fallback to i32 is made understandable.
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
- Stale
- Clarity
- Mostly clear
- Newbie friendliness
- 35/100