#conflicting implementations of a trait (not clear why!)

21 messages · Page 1 of 1 (latest)

jovial vapor
#

Hi guys, need some help,
when I run this I get a conflicting implementation error:

trait MyTrait {
    type inner: Clone;
}

#[derive(Clone)]
struct Cloneable {}

struct Ft {}

impl MyTrait for Ft {
    type inner =  Cloneable;
}

impl From<u8> for Ft {
    fn from(value: u8) -> Ft {
        todo!()
    }
}

impl<T: MyTrait> From<T::inner> for Ft {
    fn from(value: T::inner) -> Ft {
        todo!()
    }
}

fn main() {}

error:

error[E0119]: conflicting implementations of trait `From<Ft>` for type `Ft`
  --> src/main.rs:20:1
   |
20 | impl<T: MyTrait> From<T::inner> for Ft {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   |
   = note: conflicting implementation in crate `core`:
           - impl<T> From<T> for T;

I am trying to understand why such an error occurs

round kettle
jovial vapor
#

Thanks, this makes so much sense

#

Hi, so I changed the trait from Clone to something Ft cannot implement and I still get the same error

trait RandomTraitThatFtDoesNotImplement {}

trait MyTrait {
    type inner: RandomTraitThatFtDoesNotImplement;
}

struct InnerStruct {}
impl RandomTraitThatFtDoesNotImplement for InnerStruct {}

struct Ft {}
impl MyTrait for Ft {
    type inner = InnerStruct;
}

impl From<u8> for Ft {
    fn from(value: u8) -> Ft {
        todo!()
    }
}

impl<T: MyTrait> From<T::inner> for Ft {
    fn from(value: T::inner) -> Ft {
        todo!();
    }
}

fn main() {}

now it shouldn't be possible to have inner = Ft, so the hypothetical impl cases should occur

inland wave
#

you're not going to be able to write a blanket impl for From because of the existing std lib impl<T> From<T> for T, even if you add trait bounds that in theory avoid the problem

jovial vapor
#

what would blanked impl mean in this case

inland wave
#

impl<T: SomeTrait> From<T> for Foo

jovial vapor
#

but this works: impl From<u8> for Ft

#

trying to understand why that works and the other doesn't

inland wave
#

well that only has specific concrete types there

jovial vapor
#

let me try another experiment

#

hmm, you are right, this doesn't work either

trait Another {
    type inner: RandomTraitThatFtDoesNotImplement;
}
trait RandomTraitThatFtDoesNotImplement {}

struct Ft {}

impl From<u8> for Ft {
    fn from(value: u8) -> Ft {
        todo!()
    }
}

impl<T: Another> From<T::inner> for Ft {
    fn from(value: T::inner) -> Ft {
        todo!();
    }
}

fn main() {}
inland wave
#

my suggestion is just make your own method instead of using From for this

impl Ft {
    fn from_mytrait<T: MyTrait>(value: T) -> Self {
        todo!()
    }
}
jovial vapor
#

let me give more context to my specific case

#

I am trying to implement this trait, and it has a set of supertraits

pub trait PrimeField:
    Field<BasePrimeField = Self>
    + FftField
    + FromStr
    + From<<Self as PrimeField>::BigInt>
    + Into<<Self as PrimeField>::BigInt>
    + From<BigUint>
    + Into<BigUint>

the problematic one is From<<Self as PrimeField>::BigInt>

#

this is how I try to implement it:

impl<T: PrimeField> From<<Self as PrimeField>::BigInt> for Ft<T> {
    fn from(value: <Self as PrimeField>::BigInt) -> Self {
        T::from(value).into()
    }
}

then I get the conflicting error

inland wave
#

yeah because as far as rust is concerned that whole <Self as PrimeField>::BigInt can be any type including Ft<T>, even if there are additional trait bound restrictions that would currently in theory prevent that

#

I believe the solution here is to just write a impl<T: PrimeField> From<u8> for Ft<T> for each of the number types you want to support. Macros can help since I imagine most the implementations will look the same

jovial vapor
#

I guess the biggest issue is that BigInt is a trait and I cannot pre-determine what the concrete implementation will be.
I am creating something that wraps a PrimeField but is also a PrimeField, so defers functionality to the inner.

struct Ft<T: PrimeField> {
    inner: T,
}

then I implement PrimeField on it, so functions that expect PrimeField can just take it

impl<T: PrimeField> PrimeField for Ft<T> {
...
}

so the usecase will be

type SomeConcretePrimeField

Ft<SomeConcretePrimeField>

hence the goal is to export some Ft, that can wrap anything that implements PrimeField

mighty lance
#

Usually, it's viable to tell callers "convert this yourself if you want to".