which calls https://docs.rs/erased-serde/0.3.18/erased_serde/fn.serialize.html. The first argument of that function call is constrained by a trait bound T: erased_serde::Serialize. The serialize_trait_object! macro is counting on dyn MyTrait to have a compiler-generated impl erased_serde::Serialize for dyn MyTrait because it's expecting trait MyTrait: erased_serde::Serialize at the trait definition.
However, in the case that the caller forgot their erased_serde::Serialize supertrait, the impl being selected instead is erased-serde's impl<T> erased_serde::Serialize for T where T: ?Sized + serde::Serialize, which involves calling the serde Serialize impl. But the serde Serialize impl in this case is what's shown above, impl<'erased> serde::Serialize for dyn MyTrait + 'erased, which involves calling the erased-serde impl. Thus cycle and stack overflow.
The fact that there are 2 potentially applicable impls of erased_serde::Serialize for dyn MyTrait (one compiler-generated and one handwritten blanket impl in the erased-serde crate) is related to the soundness issue https://github.com/rust-lang/rust/issues/57893 but is not unsound in our case because erased_serde::Serialize has no associated types.
The fix will be for serialize_trait_object! to verify that the given trait has the required erased_serde::Serialize supertrait, for example by doing:
The
serialize_trait_object!
call is expanding to something like:which calls https://docs.rs/erased-serde/0.3.18/erased_serde/fn.serialize.html. The first argument of that function call is constrained by a trait bound
T: erased_serde::Serialize
. Theserialize_trait_object!
macro is counting ondyn MyTrait
to have a compiler-generatedimpl erased_serde::Serialize for dyn MyTrait
because it's expectingtrait MyTrait: erased_serde::Serialize
at the trait definition.However, in the case that the caller forgot their erased_serde::Serialize supertrait, the impl being selected instead is erased-serde's
impl<T> erased_serde::Serialize for T where T: ?Sized + serde::Serialize
, which involves calling the serde Serialize impl. But the serde Serialize impl in this case is what's shown above,impl<'erased> serde::Serialize for dyn MyTrait + 'erased
, which involves calling the erased-serde impl. Thus cycle and stack overflow.The fact that there are 2 potentially applicable impls of
erased_serde::Serialize
fordyn MyTrait
(one compiler-generated and one handwritten blanket impl in the erased-serde crate) is related to the soundness issue https://github.com/rust-lang/rust/issues/57893 but is not unsound in our case because erased_serde::Serialize has no associated types.The fix will be for
serialize_trait_object!
to verify that the given trait has the requirederased_serde::Serialize
supertrait, for example by doing: