Here is toy code that demonstrates the problem:
trait Foo {}
trait Boo<T> {
fn f() -> T;
}
impl<T> Boo<T> for i32
where
T: Foo,
{
fn f() -> T {
unimplemented!();
}
}
impl<'a, T> Boo<&'a T> for i32
where
T: Foo,
{
fn f() -> T {
unimplemented!();
}
}
I want to have two generic implementations of trait Boo
, but it doesn't compile:
error[E0119]: conflicting implementations of trait `Boo<&_>` for type `i32`:
--> src/main.rs:16:1
|
7 | / impl<T> Boo<T> for i32
8 | | where
9 | | T: Foo,
10 | | {
... |
13 | | }
14 | | }
| |_- first implementation here
15 |
16 | / impl<'a, T> Boo<&'a T> for i32
17 | | where
18 | | T: Foo,
19 | | {
... |
22 | | }
23 | | }
| |_^ conflicting implementation for `i32`
|
= note: downstream crates may implement trait `Foo` for type `&_`
I do not plan to make this part of functionality to other crates. I tried:
mod
pub(crate)
all with no success.
Is there anyway to give the compiler a hint that it should not care that anybody will implement Foo
for any reference?
Maybe my toy example is not the best, so here is the real code. It's used for integration with the C part of my program, so it's a little complicated.
impl<T: MyTrait> MyFrom<Option<T>> for *mut c_void {
fn my_from(x: Option<T>) -> Self {
match x {
Some(x) => <T>::alloc_heap_for(x),
None => ptr::null_mut(),
}
}
}
impl<'a, T: MyTrait> MyFrom<Option<&'a T>> for *mut c_void {
fn my_from(x: Option<&'a T>) -> Self {
match x {
Some(x) => x as *const T as *mut c_void,
None => ptr::null_mut(),
}
}
}
The conflict here doesn't have anything to do with the reference-ness of the latter implementation. The issue is that, in the first implementation, T
can be any type, including reference types. Suppose you make the following function call:
let x: i32 = 10;
let result: &u8 = x.f();
At this point, the type resolver needs to figure out what function is being called. It finds a conflicting implementation:
impl Boo<&u8> for i32 via Boo<T> (T == &u8),
impl Boo<&u8> for i32 via Boo<&T> (T == u8),
You'd have exactly the same issue if you used a concrete type in the latter implementation:
// This will fail to compile
impl<T> Boo<T> for i32 { ... }
impl Boo<String> for i32 { ... }
This conflict means that the compiler can't allow these two implementations to coexist.
The specific thing you're looking to do here is called "specialization"; it refers to a proposal for a set of rules that says that overlapping implementations like this are allowed to exist if one of them is unambiguously more "specific" than the other, in which case the compiler will pick the more specific implementation. This is tracked as RFC #1210.
If you love us? You can donate to us via Paypal or buy me a coffee so we can maintain and grow! Thank you!
Donate Us With