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 as get(&1u32)
) in the generic parameter Q
. The first is to choose Q = u32
, the second being Q = K
. Since the method requires u32: B<Q>
, even though both satisfy this bound, Q = K
is selected, because it comes from a trait bound in the caller method, while Q = u32
comes from the environment (the impl impl<T> B<T> for T
).
This special case is done to aid inference in cases like the following:
fn foo<T: Into<String>>(v: T) {
let s = v.into();
}
Here, the programmer obviously wants s
to have type String
. 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.