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().