M3rtzi
September 1, 2022, 6:55am
1
I'm really confused by this error
conflicting implementations of trait `std::convert::From<representations::script::ScriptNew>` for type `representations::script::ScriptNew` conflicting implementation in crate `core`: - impl<T> From<T> for T;
I've got this code:
pub struct Script {
id: Id,
name: Name,
source: Source,
description: Description,
is_active: bool,
owner_id: Option<i32>,
output_id: Option<i32>,
}
pub trait Tuple {
type Tuple;
fn to_tuple(&self) -> Self::Tuple;
}
impl Tuple for Script {
type Tuple = (
Option<i32>,
String,
String,
Option<String>,
bool,
Option<i32>,
Option<i32>,
);
fn to_tuple(&self) -> <Self as Tuple>::Tuple {
(
self.id.0.clone(),
self.name.0.clone(),
self.source.0.clone(),
self.description.0.clone(),
self.is_active,
self.owner_id,
self.output_id,
)
}
}
pub struct ScriptNew {
pub name: String,
pub source: String,
pub description: Option<String>,
pub is_active: bool,
pub owner_id: Option<i32>,
pub output_id: Option<i32>,
}
impl From<<Script as Tuple>::Tuple> for ScriptNew {
fn from(script: <Script as Tuple>::Tuple) -> Self {
!unimplemented!()
}
}
As far as I can understand - the trait is in fact not implemented, since I can't do:
let script_new: ScriptNew = script.to_tuple().into()
What am I missing? I need to be able to convert from <Script as Tuple>::Tuple
to ScriptNew
What's ScriptEntity
here? Its not declared anywhere, so we can't get the same error.
M3rtzi
September 1, 2022, 7:40am
3
sorry, it's just an alias for Script
, i copied the snippets from several files.. will adjust
No error for me - playground . The error seems to suggest that <Script as Tuple>::Tuple
is ScriptNew
and not the tuple you've written here, is this what your real code does?
M3rtzi
September 1, 2022, 7:53am
5
hmm, so strange.
Script
is defined in another crate than ScriptNew
, but I guess that should be fine as long as the trait Im implementing it on is in scope?
M3rtzi
September 1, 2022, 5:03pm
6
The wierdest thing.
If i replace <ScriptEntity as Tuple>::Tuple
with another identical tuple in From<T>
it doesnt throw an error, very grateful for any clues what's going on here, I find it very obscure.
This change to my code makes it compile (but is ugly and brittle)
impl
From<(
Option<i32>,
String,
String,
Option<String>,
bool,
Option<i32>,
Option<i32>,
)> for ScriptNew
{
fn from(script: <Script as Tuple>::Tuple) -> Self {
!unimplemented!()
}
}
What does this mean?
M3rtzi
September 1, 2022, 5:09pm
7
also... if I instead expose the tulpe by pub type ScriptTuple = (...);
in the same file where Script
is defined, then it also works
Like so:
// entities.rs
pub type ScriptTuple = (
Option<i32>,
String,
String,
Option<String>,
bool,
Option<i32>,
Option<i32>,
);
impl Tuple for Script {
type Tuple = ScriptTuple;
fn to_tuple(&self) -> <Self as Tuple>::Tuple {
(
self.id.0.clone(),
self.name.0.clone(),
self.source.0.clone(),
self.description.0.clone(),
self.is_active,
self.owner_id,
self.output_id,
)
}
}
Then i can use it:
// repository.rs
pub struct ScriptNew {
pub name: String,
pub source: String,
pub description: Option<String>,
pub is_active: bool,
pub owner_id: Option<i32>,
pub output_id: Option<i32>,
}
impl From<ScriptTuple> for ScriptNew {
fn from(script: <ScriptEntity as Tuple>::Tuple) -> Self {
!unimplemented!()
}
}
M3rtzi
September 1, 2022, 5:41pm
8
Alright, I think the mystery is solved (and known):
you cannot implement a trait with a generic trait not from this crate
opened 05:27AM - 21 Apr 18 UTC
A-traits
T-lang
C-bug
Sorry for the code dump. This is the smallest code I could make to reproduce the… problem.
```rust
use std::marker::PhantomData;
use std::convert::TryFrom;
trait Integer {}
impl Integer for u8 {}
trait Adapter<I: Integer>: TryFrom<I> + Into<I> {}
enum Choice {
Foo,
Bar,
Baz
}
impl From<Choice> for u8 {
fn from(c: Choice) -> u8 {
match c {
Choice::Foo => 1,
Choice::Bar => 2,
Choice::Baz => 3,
}
}
}
impl TryFrom<u8> for Choice {
type Error = ();
fn try_from(i: u8) -> Result<Choice, ()> {
match i {
1 => Ok(Choice::Foo),
2 => Ok(Choice::Bar),
3 => Ok(Choice::Baz),
_ => Err(()),
}
}
}
impl Adapter<u8> for Choice {}
struct Pick<I: Integer, A: Adapter<I>> {
phantom: PhantomData<A>,
value: I,
}
impl<I: Integer, A: Adapter<I>> From<A> for Pick<I, A> {
fn from(a: A) -> Pick<I, A> {
Pick {
phantom: PhantomData,
value: a.into(),
}
}
}
impl<I: Integer, A: Adapter<I>> TryFrom<Pick<I, A>> for A {
type Error = A::Error;
fn try_from(p: Pick<I, A>) -> Result<A, Self::Error> {
A::try_from(p.value)
}
}
```
Attempting to compile this produces:
```
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<Pick<_, _>>`:
--> src/main.rs:53:1
|
53 | impl<I: Integer, A: Adapter<I>> TryFrom<Pick<I, A>> for A {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where T: std::convert::From<U>;
error[E0210]: type parameter `A` must be used as the type parameter for some local type (e.g. `MyStruct<A>`)
--> src/main.rs:53:1
|
53 | impl<I: Integer, A: Adapter<I>> TryFrom<Pick<I, A>> for A {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `A` must be used as the type parameter for some local type
|
= note: only traits defined in the current crate can be implemented for a type parameter
```
I've spent several hours looking at this and I can't figure out why I'm getting these errors. The type parameter `A` is being used as the type parameter for a local type. Maybe the compiler can't tell because it is nested inside `TryFrom<>`?
But I'm also not sure why the first error occurs at all. The rule it conflicts with can basically be described as "types with infallible conversions implicitly implement fallible conversions." But in my case there is no infallible conversion. So I don't see where the conflict is arising from.
If there is really a bug and I'm not just overtired, this may impact #49305.
This is also the reason it works when it's all in one file. I think I'll go with the workaround in my previous post, altough I realize it's not ideal
system
Closed
November 30, 2022, 5:41pm
9
This topic was automatically closed 90 days after the last reply. We invite you to open a new topic if you have further questions or comments.