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 = K
is selected, because it comes from a trait bound in the caller method, whileQ = u32
comes 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
s
to 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.