Narrow impl shadows wider impl?

I am struggling to get this code to compile:

struct Marker;
struct Input;
struct Output;

trait Coerce<T, U> {
    fn coerce(val: T) -> U;
}

impl<T> Coerce<T, Output> for Marker {
    fn coerce(_val: T) -> Output {
        Output
    }
}

fn test_coerce1<T>(x: T) -> Output
where
    Marker: Coerce<T, Output>,
{
    Marker::coerce(x)
}

fn test_coerce2<U>(x: U) -> Output
// where
//     Marker: Coerce<U, Output>,
{
    test_coerce1(Input)
}

fn test_coerce3<V>(x: V) -> Output
where
    Marker: Coerce<V, Output>,
{
    test_coerce1(Input) // error[E0308]: mismatched types
}

test_coerce2() compiles successfully, so I imagine test_coerce3() should compile as well!

It seems that adding the bound Marker: Coerce<V, Output> bound somehow prevents the compiler from noticing that there already exists a more general implementation: impl<T> Coerce<T, Output> for Marker.

It is trying to substitute V for T, but it SHOULD be substituting Input for T.

Is this a known bug? Is there any way to work around this, other than manually specifying a fully-qualified path? I really would like to avoid using a fully-qualified path since the full type might be extremely complicated (e.g. potentially involving async), or possibly even opaque.

This looks like an edge case of Rust's type inference to me. I can't point you to a specific issue on GitHub for this, but my guess would be that this is already known. Not sure if you mean this by manually using a fully-qualified path, but explicitly setting T of the test_coerce1(Input) call makes test_coerce3 compile:

fn test_coerce3<V>(x: V) -> Output
where
    Marker: Coerce<V, Output>,
{
    test_coerce1::<Input>(Input)
}

Playground.

You know what, I just came up with a profoundly dumb way to solve this:

fn test_coerce3<V>(x: V) -> Output
where
    Marker: Coerce<V, Output>,
{
    fn inner<V>(_x: V) -> Output {
        test_coerce1(Input)
    }
    inner(x)
}

Yes that occurred to me but I am trying to work with opaque types here. Are you aware of a specific GitHub issue tracking this? Or should I just open a separate issue at risk of it being a duplicate?

From a glance, this looks like a similar report to me:

A longer standing issue:

A recent conversation about it on this forum:


You can't leave the bound off ala test_coerce2?

1 Like

Side note: I've also found this comment which is linked from the original issue. That's maybe the reason for the confusing compiler errors this bug often causes à la "expected type parameter V, found Input" like in the initial example of this topic.

1 Like