I have a broad base trait. Some types only care about subset of its functionality, so I added a subtrait requiring user to implement smaller set of functions.
This code fails:
trait Base<T> {
fn foo(arg: bool);
}
// Ext is a narrowing of Base requiring user to provide alternative, simpler interface for the same functionality
trait Ext<T>: Base<T> {
fn bar();
}
// implement Base<T> for all types implementing Ext<T>
impl<T, E> Base<T> for E
where
E: Ext<T>,
{
fn foo(arg: bool) {
Self::bar();
}
}
struct Data<T>;
// error[E0119]: conflicting implementations of trait `Base<_>` for type `Data<_>`:
impl<T> Base<T> for Data<T> {
fn foo(arg: bool) {}
}
With following error:
error[E0119]: conflicting implementations of trait `Base<_>` for type `Data<_>`:
--> src/lib.rs:22:1
|
11 | / impl<T, E> Base<T> for E
12 | | where
13 | | E: Ext<T>,
14 | | {
... |
17 | | }
18 | | }
| |_- first implementation here
...
22 | impl<T> Base<T> for Data<T> {
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^ conflicting implementation for `Data<_>`
|
= note: downstream crates may implement trait `Ext<_>` for type `Data<_>`
Interestingly, it works when I remove generality over T
:
trait Base {
fn foo(arg: bool);
}
// Ext is a narrowing of Base requiring user to provide alternative, simpler interface for the same functionality
trait Ext: Base {
fn bar();
}
// implement Base for all types implementing Ext
impl<E> Base for E
where
E: Ext,
{
fn foo(arg: bool) {
Self::bar();
}
}
struct Data;
// works just fine
impl Base for Data {
fn foo(arg: bool) {}
}
Some other posts on stackoverflow mentioned similar problems, but they generally have issues with foreign traits (the one from standard library). In my case both trait and type are local, therefore orphan rules should not kick in as far as I understand.
Basically, error mentions that downstream crates may implement trait 'Ext<_>' for type 'Data<_>'
, which isn't true because both Ext
and Data
would be foreign for those crates.
To summarize, my questions are:
- Why my blanket impl is rejected even though it doesn't seem to be possible for other crates to create a collision.
- Why version without
T
is not rejected, even though its mostly the same blanket impl? - Is there any workaround for this issue?