I think re-rebalancing coherence (RFC#2451) is partially to blame here for the inconsistency. Going back to 1.34.0, when TryFrom
was stabilized and re-rebalancing coherence was not yet in, I get a different set of errors that also disallows the impl on Rc
:
use std::rc::Rc;
use std::convert::TryFrom;
struct MyRc<T>(Rc<T>);
struct MyBox<T>(Box<T>);
impl<T> TryFrom<MyRc<T>> for Rc<T> {}
impl<T> TryFrom<Rc<T>> for MyRc<T> {}
impl<T> TryFrom<MyBox<T>> for Box<T> {}
impl<T> TryFrom<Box<T>> for MyBox<T> {}
1.41.0 (re-rebalancing coherence)
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<MyBox<_>>` for type `std::boxed::Box<_>`:
--> src/lib.rs:10:1
|
10 | impl<T> TryFrom<MyBox<T>> for Box<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where U: std::convert::Into<T>;
= note: downstream crates may implement trait `std::convert::From<MyBox<_>>` for type `std::boxed::Box<_>`
error[E0119]: conflicting implementations of trait `std::convert::TryFrom<std::boxed::Box<_>>` for type `MyBox<_>`:
--> src/lib.rs:11:1
|
11 | impl<T> TryFrom<Box<T>> for MyBox<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where U: std::convert::Into<T>;
= note: downstream crates may implement trait `std::convert::From<std::boxed::Box<_>>` for type `MyBox<_>`
error[E0210]: type parameter `T` must be covered by another type when it appears before the first local type (`MyBox<T>`)
--> src/lib.rs:10:6
|
10 | impl<T> TryFrom<MyBox<T>> for Box<T> {}
| ^ type parameter `T` must be covered by another type when it appears before the first local type (`MyBox<T>`)
|
= note: implementing a foreign trait is only possible if at least one of the types for which is it implemented is local, and no uncovered type parameters appear before that first local type
= note: in this case, 'before' refers to the following order: `impl<..> ForeignTrait<T1, ..., Tn> for T0`, where `T0` is the first and `Tn` is the last
1.34.0 (pre-re-rebalancing coherence)
error: conflicting implementations of trait `std::convert::TryFrom<MyBox<_>>` for type `std::boxed::Box<_>`: (E0119)
--> src\main.rs:10:1
|
10 | impl<T> TryFrom<MyBox<T>> for Box<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= note: #[deny(incoherent_fundamental_impls)] on by default
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205>
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where U: std::convert::Into<T>;
= note: downstream crates may implement trait `std::convert::From<MyBox<_>>` for type `std::boxed::Box<_>`
error: conflicting implementations of trait `std::convert::TryFrom<std::boxed::Box<_>>` for type `MyBox<_>`: (E0119)
--> src\main.rs:11:1
|
11 | impl<T> TryFrom<Box<T>> for MyBox<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
|
= warning: this was previously accepted by the compiler but is being phased out; it will become a hard error in a future release!
= note: for more information, see issue #46205 <https://github.com/rust-lang/rust/issues/46205>
= note: conflicting implementation in crate `core`:
- impl<T, U> std::convert::TryFrom<U> for T
where U: std::convert::Into<T>;
= note: downstream crates may implement trait `std::convert::From<std::boxed::Box<_>>` for type `MyBox<_>`
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src\main.rs:7:1
|
7 | impl<T> TryFrom<MyRc<T>> for Rc<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` 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
error[E0210]: type parameter `T` must be used as the type parameter for some local type (e.g., `MyStruct<T>`)
--> src\main.rs:10:1
|
10 | impl<T> TryFrom<MyBox<T>> for Box<T> {}
| ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ type parameter `T` 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
Ooh, further tidbit: the Box
impl used to be allowed, and was deprecated/removed with #46205. That issue contains some further information about why this is incoherent.
So two takeaway points: under rebalancing coherence, both of these cases are disallowed; re-rebalancing coherence allows it for non-fundamental (covering) types. And specialization doesn't even help you at all.
#[fundamental]
is inherently about negative reasoning. A #[fundamental]
trait can be assumed to not be implemented (e.g. Fn*
and Sized
) if it is not currently implemented. A #[fundamental]
type is slightly different; per my reading of re-rebalancing coherence, a fundamental type's only quality is that its locality is always that of its (singular) type argument, and as such cannot "cover" a type variable.
Without knowing the exact use case of your BoxBar
, it's not really possible to suggest other paths. My only suggestion would really be to, if at all possible, use Box<Bar<T>>
(where Bar
is a repr(transparent)
wrapper) rather than a custom box type.