Why are these conflicting implementations?

trait Something {}

trait DerefsIntoDynSomething {
    fn dyn_something(&self) -> &dyn Something;
}

impl<T> DerefsIntoDynSomething for T where T: Deref, T::Target: Something + Sized {
    fn dyn_something(&self) -> &dyn Something {
        self.deref()
    }
}

impl<T> DerefsIntoDynSomething for T where T: Deref<Target = dyn Something> {
    fn dyn_something(&self) -> &dyn Something {
        self.deref()
    }
}

dyn Something is clearly !Sized

The conflict checker doesn’t treat compiler-relevant traits like Sized and Copy any differently than others. As far as it’s concerned, the next version of Rust might add Sized to dyn Trait and Copy to &mut T, and it insists on protecting you from that possibility.

It feels like these would be reasonable special cases to add, but I suspect it’d need to go through some form of the RFC process; you might want to ask about adding this over at https://internals.rust-lang.org.

1 Like

It's not strictly related to your question, but I'm starting to think of Deref bounds like this as a code smell. The reason is because, in an example like this, any function that takes a &T where T: DerefsIntoDynSomething should actually just take a &S where S: Something. The dereference can take place in the caller, and is often automatic -- that's what Deref is all about, after all.

That assumes that there isn’t storage involved. When I write code like this, it’s usually because I want to generically store &T, Box<T>, Rc<T>, etc where T is anything that implements some trait.

The semantics I need are closer to Borrow, but the stored value needs to be an associated type to avoid “unconstrained type parameter” errors. I’ve started moving to explicitly implementing the trait for each pointer type, though, with a macro to define more— it causes less trouble for other generic impls.

I'm sure there are exceptions, which is why I said "code smell". I've never needed to write a Deref bound, and the cases I've seen where people do are mostly not what I would call good code. But that doesn't mean you can't write good code that uses Deref as a bound, it's just a trend I've noticed.

1 Like

Actually I adopted my real use case to use types from std. I'm not actually using Deref this way.