Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Spurious "note: downstream crates may implement trait Foo for type &_" #48869

Open
glandium opened this issue Mar 9, 2018 · 10 comments
Open
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.

Comments

@glandium
Copy link
Contributor

glandium commented Mar 9, 2018

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.

@estebank estebank added the A-diagnostics Area: Messages for errors, warnings, and lints label Mar 9, 2018
Dushistov added a commit to Dushistov/flapigen-rs that referenced this issue Apr 26, 2018
may be it is possible to simplify code after
resolving rust-lang/rust#48869
Dushistov added a commit to Dushistov/flapigen-rs that referenced this issue Apr 26, 2018
may be it is possible to simplify code after
resolving rust-lang/rust#48869
Dushistov added a commit to Dushistov/flapigen-rs that referenced this issue Apr 26, 2018
may be it is possible to simplify code after
resolving rust-lang/rust#48869
@XAMPPRocky XAMPPRocky added C-enhancement Category: An issue proposing an enhancement or a PR with one. T-lang Relevant to the language team, which will review and decide on the PR/issue. labels May 14, 2018
@eviltak
Copy link

eviltak commented May 24, 2018

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()
    }
}

@qnighy
Copy link
Contributor

qnighy commented May 24, 2018

@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)
    }
}

@rustonaut
Copy link

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

Seems to be the same problem as issue #50238

@eviltak
Copy link

eviltak commented May 24, 2018

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.

@tbraun96
Copy link

Any updates fam?

@msrd0
Copy link
Contributor

msrd0 commented Mar 30, 2020

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

@jonas-schievink jonas-schievink added the T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. label Apr 20, 2020
@jeekobu
Copy link

jeekobu commented Apr 23, 2020

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.)

@dhardy
Copy link
Contributor

dhardy commented Dec 22, 2020

Reduced version which still fails (Bar replaces Display):

trait Foo {}

trait Bar {}
impl<'a, T: Bar> Bar for &'a T {}

impl<T: Foo> Bar for T {}

From what I understand, downstream may do this:

struct S;
impl Foo for &'static S {}
impl Bar for S {}

... and now we have conflicting impls of Bar for &'static S.

But it does seem like the coherence rule here is too strong, since it would be sufficient to prevent the downstream crate from creating both those impls.

@dhardy
Copy link
Contributor

dhardy commented Dec 22, 2020

This is then essentially the same restriction as #22865: a library may not provide impls which the user could cause to impl. But note that this restriction is not applied uniformly; for example, the following is allowed:

pub trait Foo {}
impl<T> Foo for T {}

In the latter case, we simply prevent conflicting implementations downstream (e.g. struct S; impl From<S> for S {}).

@Aandreba
Copy link

Are there any updates?

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
A-diagnostics Area: Messages for errors, warnings, and lints C-enhancement Category: An issue proposing an enhancement or a PR with one. T-compiler Relevant to the compiler team, which will review and decide on the PR/issue. T-lang Relevant to the language team, which will review and decide on the PR/issue.
Projects
None yet
Development

No branches or pull requests