Rust: Spurious "note: downstream crates may implement trait `Foo` for type `&_`"

Created on 9 Mar 2018  路  7Comments  路  Source: rust-lang/rust

The following code:

trait Foo {}

impl<T: Foo> std::fmt::Display for T {
    fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
        Ok(())
    }
}

produces the following compiler output:

error[E0119]: conflicting implementations of trait `std::fmt::Display` for type `&_`:
 --> src/main.rs:3:1
  |
3 | impl<T: Foo> std::fmt::Display for T {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<'a, T> std::fmt::Display for &'a T
            where T: std::fmt::Display, T: ?Sized;
  = note: downstream crates may implement trait `Foo` for type `&_`

error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g. `MyStruct<T>`); only traits defined in the current crate can be implemented for a type parameter
 --> src/main.rs:3:1
  |
3 | / impl<T: Foo> std::fmt::Display for T {
4 | |     fn fmt(&self, f: &mut std::fmt::Formatter) -> std::fmt::Result {
5 | |         Ok(())
6 | |     }
7 | | }
  | |_^

error: aborting due to 2 previous errors

While there might be legitimate reasons why this is not allowed, the note is wrong: the trait Foo is not public, a downstream can't possibly implement it for some type.

A-diagnostics C-enhancement T-compiler T-lang

Most helpful comment

Given that there seem to be no updates, does anybody have a workaround for this issue yet?

All 7 comments

Similar problem when using Box:

trait Foo {
    fn foo(&self) -> u32;
}

trait Bar {
    fn bar(&self) -> u32;
}

impl<T: Foo> Bar for Vec<T> {
    fn bar(&self) -> u32 {
        self.iter().map(|x| x.foo()).sum()
    }
}

impl<T: Foo> Bar for Vec<Box<T>> {
    fn bar(&self) -> u32 {
        self.iter().map(|x| x.foo()).sum()
    }
}
error[E0119]: conflicting implementations of trait `Bar` for type `std::vec::Vec<std::boxed::Box<_>>`:
  --> src/main.rs:19:1
   |
13 | impl<T: Foo> Bar for Vec<T> {
   | --------------------------- first implementation here
...
19 | impl<T: Foo> Bar for Vec<Box<T>> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `std::vec::Vec<std::boxed::Box<_>>`
   |
   = note: downstream crates may implement trait `Foo` for type `std::boxed::Box<_>`

error: aborting due to previous error

This problem is possibly more definitive than the OP's as it is impossible for downstream crates to implement Foo (public or not) for Box, since neither the trait (Foo) _nor_ the struct (Box) belong to the downstream crate.

Unlike the assumption I made, however, this problem does not occur with other types in the prelude (like Option).

This problem does not occur when using a concrete type instead of the generic type parameter:

trait Foo {
    fn foo(&self) -> u32;
}

trait Baz : Foo {}

trait Bar {
    fn bar(&self) -> u32;
}

impl<T: Foo> Bar for Vec<T> {
    fn bar(&self) -> u32 {
        self.iter().map(|x| x.foo()).sum()
    }
}

impl Bar for Vec<Box<Baz>> {
    fn bar(&self) -> u32 {
        self.iter().map(|x| x.foo()).sum()
    }
}

The problem can be (suboptimally) worked around by implementing Foo for Box<T> where T : Foo _provided_ the usages of the boxed and non-boxed versions of the trait objects are the same, like in my example:

trait Foo {
    fn foo(&self) -> u32;
}

impl<T: Foo> Foo for Box<T> {
    fn foo(&self) -> u32 {
        self.as_ref().foo()
    }
}

trait Bar {
    fn bar(&self) -> u32;
}

impl<T: Foo> Bar for Vec<T> {
    fn bar(&self) -> u32 {
        self.iter().map(|x| x.foo()).sum()
    }
}

@eviltak As described in RFC 1023, fundamental structs like Box<_> are treated transparently by the coherence rules. Therefore you can actually implement an upstream trait for Box.

struct A;

impl std::ops::Add for Box<A> {
    type Output = Box<A>;
    fn add(self, rhs: Box<A>) -> Self::Output {
        Box::new(A)
    }
}

@qnighy but std::ops::Add is public while neither Foo nor Bar are

Seems to be the same problem as issue #50238

I wasn't aware of that, @qnighy. Thanks for that useful snippet of information!

Thank you for pointing me to #50238, @dathinab! #50238 should be the issue to follow for my problem.

Any updates fam?

Given that there seem to be no updates, does anybody have a workaround for this issue yet?

I just had a similar case, only there was no note about downstream crates. This was in some ways even more confusing, as

  • The error said my generic impl<T> TraitA resulting in a conflicting impl TraitB, but
  • Replacing the impl<T> TraitA with a direct non-generic impl TraitB compiled meaning
  • There was no (existing) conflict and the error was stating a non-fact

I tried to reproduce this in the playground but my reduced version _did_ have the note about downstream crates, which led me here. Perhaps because the original involved separate crates, not just separate modules.

I didn't find a different bug for this error message when there is no spurious note, but I'm wondering if there is one... or if anyone is interested enough that I should try harder to reproduce the situation and open one.

(And incidentally, my work around was to macro up some impls for concrete types to replace the generic impl.)

Was this page helpful?
0 / 5 - 0 ratings