trait B<T> {}
impl<T> B<T> for T {}
fn f<K>()
where
// u32: B<u32>, // 4
u32: B<K>, // 3
{
// get::<u32>(&1u32); // 2
get(&1u32); // 1 error
}
fn get<Q>(k: &Q)
where
u32: B<Q>,
{
}
fn main() {}
error at 1:
error[E0308]: mismatched types
--> src/main.rs:10:9
|
4 | fn f<K>()
| - expected this type parameter
...
10 | get(&1u32); // 1 error
| --- ^^^^^ expected `&K`, found `&u32`
| |
| arguments to this function are incorrect
|
= note: expected reference `&K`
found reference `&u32`
However, &u32 also satisfy trait bound of get.
if I change 1 to 2, it is OK.
if I remove 3, it is OK.
if I add 4, it is OK.
Why?
This is a case of a somewhat less-known detail of Rust's inference: if there are two possible method candidates, and one of them comes from a trait bound of the function (and the other does not), Rust prefers the trait bound's method, unless explicitly told otherwise.
In your case, there are two possible candidates for
get::<_>(&u32)(written asget(&1u32)) in the generic parameterQ. The first is to chooseQ = u32, the second beingQ = K. Since the method requiresu32: B<Q>, even though both satisfy this bound,Q = Kis selected, because it comes from a trait bound in the caller method, whileQ = u32comes from the environment (the implimpl<T> B<T> for T).This special case is done to aid inference in cases like the following:
Here, the programmer obviously wants
sto have typeString. However, there are actually two candidates here: one being<T as Into<String>>::into(), but the other is the reflexive impl<T as Into<T>>::into(), provided by std. In order for this to not be ambiguous, Rust prefers the trait bound unless explicitly told otherwise.