rust-lang / rust

Empowering everyone to build reliable and efficient software.
https://www.rust-lang.org
Other
96.56k stars 12.47k forks source link

Type inference seems to pick up the wrong trait bound #77625

Open orium opened 3 years ago

orium commented 3 years ago

Hi. I apologize if this is a dup (I tried to search, but is it not easy to distill this into words to search for). If it's not a dup please update the title to something more meaningful.

When trying to compile (in play)

pub trait Distribution<T> {}

impl Distribution<u16> for () {}

fn gen<K>() -> K
where
    (): Distribution<K> {
    todo!()
}

fn foo<T>() -> u16
where
    (): Distribution<T>,
{
    gen()
}

I get the error:

error[E0308]: mismatched types
  --> src/lib.rs:15:5
   |
11 | fn foo<T>() -> u16
   |        -       --- expected `u16` because of return type
   |        |
   |        this type parameter
...
15 |     gen()
   |     ^^^^^ expected `u16`, found type parameter `T`
   |
   = note:        expected type `u16`
           found type parameter `T`

It it should be able to determine that the hole in gen::<_>() is u16 because that's the return type of foo(). Instead the compiler thinks the hole must be T, which is not true (in fact, if you change the call to gen() to gen::<u16>() the code compiles).

This happens in stable (1.46.0) as well as nightly 1.49.0-nightly (2020-10-05 a1dfd2490a6cb456b92e).

jonas-schievink commented 3 years ago

Presumably this is just fallout from the fact that predicates in where-clauses having higher precedence than impls

jonas-schievink commented 3 years ago

Meaning: In foo, at the call to gen(), the compiler has to prove the (): Distribution<K> predicate in the where-clause on gen, which means proving (): Distribution<$0> where $0 is an inference variable. It eagerly selects the (): Distribution<T> predicate from the where-clause of foo to do that and thus unifies $0 with T.