Definitely not. Why would you? This is not a compiler bug.
This has also nothing to do with my solution. DynEq
doesn't "break downcasting". It's a simple misunderstanding on your part, and a design error.
The OpaqueData
trait has an as_any()
method – i.e., it has the same name as the as_any()
method on DynEq
. That's Bad™, because DynEq
is (necessarily) blanket-impl'd for all eligible types T: PartialEq + 'static
, including Arc<T: PartialEq + 'static>: PartialEq + 'static
.
Now dyn_a
is Arc<dyn OpaqueData>
, so when you call dyn_a.as_any()
, it actually resolves to <Arc<dyn OpaqueData> as DynEq>::as_any()
, i.e., directly on the Arc
, without dereferencing it. Of course, downcasting an Arc<A>
to A
is not going to work, because they are not the same type.
If, however, you omit the PartialEq
impl on dyn OpaqueData
, then that transitively gets rid of the PartialEq
impl on Arc<dyn OpaqueData>
. This means that Arc<dyn OpaqueData>
no longer impls DynEq
. Therefore, method resolution has to dig deeper, auto-deref, and find the correct <A as DynEq>::as_any()
method, which it will call.
The correct solution(s) include:
- Not putting identically-named methods on super- and subtraits, and/or
- Explicitly dereferencing smart pointers.
I.e., this works:
let downcasted = (*dyn_a).as_any().downcast_ref::<A>().unwrap();
As for the lifetime error: &dyn Trait
in a signature is implicitly &'a dyn Trait + 'a
, which is not what you want – you want &'_ dyn DynEq + 'static
, because you can't downcast it unless it's 'static
-bounded. This error is also fixed in the linked playground, and then you can just impl PartialEq
as self.as_dyn_eq() == other.as_dyn_eq()
.