The main problem comes from upcasting the potentially existent dyn SubParser
into a dyn Parser
. Although this should be possible, it is currently not the case in Rust, since there are some unresolved issues about the precise mechanism to achieve this, see this thread and this other one.
This does indeed resolve the upcasting issue, since it adds an explicit method on the vtable in charge of performing the upcasting. It is annoying because it forces you to write the trivial implementation every time you want to implement the trait.
My poor phrasing is to blame, here; the argument is required to be a &mut dyn Parser
, which does indeed use dynamic dispatch based on a very precise vtable: dyn Parser
's vtable (i.e., dyn SubParser
's vtable does not do the trick here).
Now, dyn Parser
implements Parser
and so does dyn SubParser
too. Meaning that both these types could be Self
in your example, provided there is not a Self : Sized
bound.
-
My
&mut impl Parser + ?Sized
(i.e.,<P : Parser + ?Sized> ... &mut P
) solution on the called function allowed to solve the issue since then such function would be able to momonorphise (statically dispatch) to both theP = dyn Parser
andP = dyn SubParser
cases. -
And yes, it is true that having to add
?Sized
for each generic is annoying it's a retrocompatibility artifact fromSized
's current design not having existed at the beginning of Rust...
And when Self = dyn SubParser
, &mut Self
cannot be coerced to a &mut dyn Parser
, since that would imply upcasting, which is not a conversion available in Rust directly; hence the requirement for a method such as as_parser_mut
.
I hope it's clearer, now