rust-lang / rust

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

False conflicting implementations error with associated types #109559

Open nandesu-utils opened 1 year ago

nandesu-utils commented 1 year ago

I tried this code:

struct Error;

#[allow(unused_qualifications)]
impl std::convert::From<<u64 as std::str::FromStr>::Err> for Error {
    #[allow(deprecated)]
    fn from(source: <u64 as std::str::FromStr>::Err) -> Self {
        Error
    }
}

I expected to see this happen: proper compilation and no errors

Instead, this happened: error about conflicting implementations,

error[E0119]: conflicting implementations of trait `From<Error>` for type `Error`
 --> a.rs:4:1
  |
4 | impl std::convert::From<<u64 as std::str::FromStr>::Err> for Error {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> From<T> for T;

So compiler thinks this associated Err might be locally defined Error type.

Perhaps there are few issues from different perspectives:

The trait and implementing Self (which is u64) type are both external (the u64 is a primitive though but it acts as if it was external here since you wouldn't be able to implement the external trait on it), and cyclic dependencies aren't possible so there is no way this associated type may be equal to local Error struct.

And this seems to be trivially resolvable since the implementation that is getting selected is selected via concrete types so the associated type may be resolved right away and checked for equality and, hence, conflicts.

Meta

rustc --version --verbose:

rustc 1.70.0-nightly (1459b3128 2023-03-23)
binary: rustc
commit-hash: 1459b3128e288a85fcc4dd1fee7ada2cdcf28794
commit-date: 2023-03-23
host: x86_64-unknown-linux-gnu
release: 1.70.0-nightly
LLVM version: 15.0.7

cbondurant commented 1 year ago

I also have run into this behavior, notably the same does not occur with a user defined type that implements FromStr, only the builtin types. This code compiles without issue.


struct Error;

struct FromStringType;
struct FromStringTypeErr;

impl std::str::FromStr for FromStringType {
    type Err = FromStringTypeErr;
    fn from_str(_: &str) -> Result<Self, Self::Err> { 
        Ok(FromStringType)
    }
}

impl From<<FromStringType as std::str::FromStr>::Err> for Error {
    fn from(_: <FromStringType as std::str::FromStr>::Err) -> Self {
        Self
    }
}

rustc --version --verbose:

rustc 1.68.2 (9eb3afe9e 2023-03-27)
binary: rustc
commit-hash: 9eb3afe9ebe9c7d2b84b71002d44f4a0edac95e0
commit-date: 2023-03-27
host: x86_64-unknown-linux-gnu
release: 1.68.2
LLVM version: 15.0.6
taeruh commented 10 months ago

I can confirm this behavior.

Let's assume we have a library up with the following contents:

pub trait Trait {
    type Assoc;
}

pub struct Inner;

pub struct AssocInner;
impl Trait for AssocInner {
    type Assoc = Inner;
}

In a dependent crate we want to implement the From trait for a wrapper:

use up::{AssocInner, Inner, Trait};

struct Outer(Inner);

impl From<<AssocInner as Trait>::Assoc> for Outer {
    fn from(_: <AssocInner as Trait>::Assoc) -> Self {
        Outer(Inner)
    }
}

This does not compile:

cargo check
    Checking down v0.1.0 (/home/jannis/s/o/projects/weird_bug_questionmark/down)
error[E0119]: conflicting implementations of trait `From<Outer>` for type `Outer`
 --> src/lib.rs:5:1
  |
5 | impl From<<AssocInner as Trait>::Assoc> for Outer {
  | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
  |
  = note: conflicting implementation in crate `core`:
          - impl<T> From<T> for T;

For more information about this error, try `rustc --explain E0119`.
error: could not compile `down` (lib) due to previous error

In the attached files (see below), I tried exactly examine where the problem is coming from. It seems to be definitely from Trait, Inner and AssocInner being external and using the asssociated type for the generic type parameter in From<...> in line 5. I don't understand it because the compiler seems to know what the type of the associated type is when used in other situations.

rustc --vesion --verbose

rustc 1.74.1 (a28077b28 2023-12-04)
binary: rustc
commit-hash: a28077b28a02b92985b3a3faecf92813155f1ea1
commit-date: 2023-12-04
host: x86_64-unknown-linux-gnu
release: 1.74.1
LLVM version: 17.0.4

up.md down.md

lcnr commented 6 months ago

closing this as a duplicate of https://github.com/rust-lang/rust/issues/85576#issuecomment-2058244779. Thanks for opening this issue