trait TraitA {}
trait TraitB {}
impl TraitA for u64 {}
impl TraitA for i64 {}
impl TraitB for u64 {}
impl TraitB for u8 {}
fn foo<T: TraitA + TraitB>(x: T) {}
fn main() {
foo(5);
}
error[E0277]: the trait bound `i32: TraitA` is not satisfied
The compiler defaults 5 to i32 and fails even though only u64 satisfies both traits. I guess it doesn't use traits to deduce types if a trait is implemented by at least two types. Is this documented behavior?
Naturally, since we don't know what T is, we can't find the specific impl; but based on the bound, we can say that there exists an impl which the caller must provide.
We use the term obligation to refer to a trait reference in need of an impl. Basically, the trait resolution system resolves an obligation by proving that an appropriate impl does exist.
During type checking, we do not store the results of trait selection. We simply wish to verify that trait selection will succeed.
Update:
The error msg could be more user-friendly if it's pointed out. Now Rust emits the candidates separately
= help: the following other types implement trait `TraitA`:
i64
u64
= help: the following other types implement trait `TraitB`:
u64
u8
It's well-known that integer type inference is flaky and behaves like that. I don't know whether there is a specific place where it's described.
The error messages could be better, though. I guess the compiler should state that it's defaulting to i32 since there isn't a constraint which uniquely specifies the type. TraitA + TraitB isn't it, because trait bounds are checked separately. What you want looks a bit like specialization for {integer}.