Conflicting Blanket Implementations of TryFrom

Hello everyone!

I'm trying to implement TryFrom on a custom container type, but I'm getting some errors I can't make sense of. Here's a rough MVP of my problem: Rust Playground

I will admit, straight-up, that this seems like a duplicate of this post, but it never got an answer, so I'm testing the waters again! : v)

So! I have a custom container that stores a single piece of data:

struct Container<T: ?Sized> {
    data: Box<T>,

When it holds a DST, I want to implement TryFrom for it, to be able to emulate a 'downcast' that gives a concretely typed version of the container. I can do this by hand by implementing TryFrom on every type I care about:

impl TryFrom<Container<dyn MyTrait>> for Container<MyStruct1> { ... }
impl TryFrom<Container<dyn MyTrait>> for Container<MyStruct2> { ... }

This compiles, but is A) very tedious and B) breaks down if someone outside my crate wanted to implement MyTrait on their own type. This function should exist for any type implementing MyTrait, so a blanket implementation seems like the right solution:

impl<T: MyTrait> TryFrom<Container<dyn MyTrait>> for Container<T> { ... }

But when I try to compile this, I get the following error:

error[E0119]: conflicting implementations of trait `std::convert::TryFrom<Container<(dyn MyTrait + 'static)>>` for type `Container<_>`
  --> src/
16 | impl<T: MyTrait> TryFrom<Container<dyn MyTrait>> for Container<T> {
   | ^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^
   = note: conflicting implementation in crate `core`:
           - impl<T, U> TryFrom<U> for T
             where U: Into<T>;

It says that my implementation conflicts with another blanket implementation in the core. But I don't understand where that's coming from. So, what impl is this conflicting with? Is there some special magic with the From/Into traits I'm getting caught up here? Any help in the right direction is appreciated!

I understand why implementing Into would get you TryFrom for free, but I don't implement Into or From for this type. So it shouldn't be getting the auto-generated impl from those.

And the reflexive implementation of From<T> for T can't apply here.
T is Sized, so T can't be dyn MyTrait, so this shouldn't happen:

impl TryFrom<Container<dyn MyTrait>> for Container<dyn MyTrait>
1 Like

If you want it, tell it to the compiler.
Edit: nvm

Sized is already the default for generic parameters. The only place that's different is that traits are implicitly Self: ?Sized by default.


Thanks for answering! : v)

But as @cuviper said, it's Sized by default. I edited the question to (hopefully) make it a little more clear; The Sized part wasn't the main focus. I only mentioned it because that should rule out the reflexive case:

impl TryFrom<Container<dyn MyTrait> for Container<dyn MyTrait>

where you're converting a type into itself. It's 'ruled out' because dyn MyTrait is not Sized.

But genuinely, let me know any other thoughts you have! I'm just as much at a loss here myself!

1 Like

Container<dyn MyTrait> is just a newtype around Box<dyn MyTrait>, and it has size 16. (A primary use of boxing is to have a Sized handle on some unsized thing.) The blanket implementation applies.

(Maybe it would help to have some variation in names:

struct Container<Internal: ?Sized> { /* ... */ }

T=Container<dyn MyTrait> is Sized even though Internal=dyn MyTrait is not.)

Hey! Thanks for joining the fray!!
Everything you said is totally correct, and the example is appreciated, but there's a slight difference between it and the problem I'm running into.

In the impl I'm trying to write T is Internal, since I'm implementing it for Container<T> and not just for T:

impl<T: MyTrait> TryFrom<Container<dyn MyTrait>> for Container<T> { ... }

So the blanket still shouldn't apply (right?), since like you said
Interal = dyn MyTrait isn't Sized.

I think the only valid T should be MyStruct; it implements MyTrait and is Sized.
MyTrait isn't Sized, and while Container is Sized, it doesn't implement MyTrait, so it still shouldn't fit the bounds of T. Or is my understanding of this totally broken? (wouldn't be the first time...)

I left the type as T to keep it short, but do you think it would be more clear to write out Internal as the type name? I've been messing with Rust for a while, but the Rust forum (and it's conventions) are totally new to me!

And, as always, if there's a better way to write this I'm totally open to suggestions! This was just the only way I could think to express it.

1 Like

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.