On Mon, 07 Aug 2017 08:25:10 -0700, [email protected] wrote:
> On Thu, 29 Jun 2017 03:46:02 -0700, [email protected] wrote:
> > Mu provides iterator method, but when you mix in a role that wants it
> > implemented, it doesn't find it:
> >
> > m: role Meow { method iterator {…} }; class Bar does Meow {}
> > camelia rakudo-moar 2a8d1e: OUTPUT: «5===SORRY!5=== Error while
> > compiling <tmp>â¤Method 'iterator' must be implemented by Bar
> > because
> > it is required by roles: Meow.â¤at <tmp>:1â¤Â»
> >
> > Yet it all works fine if you are also doing `is SomethingUnrelated`:
> >
> > m: class Foo { method x {} }; role Meow { method iterator {…} };
> > class
> > Bar is Foo does Meow {}
> > camelia rakudo-moar 2a8d1e: ( no output )
>
>
> Another example turned up; fails to notice the method is provided by
> `handles`:
>
> class HTTP::Header does Associative does Iterable {
> subset StrOrArrayOfStr where Str | ( Array & {.all ~~ Str} );
>
> has %!fields of StrOrArrayOfStr
> handles <AT-KEY EXISTS-KEY DELETE-KEY push
> iterator list kv keys values>;
>
> method Str { #`[not shown, for brevity] }
> }
>
> This is from https://github.com/perl6/doc/issues/1438
I've traced this as far back as RoleToClassApplier.has_method
not getting anything in .^mro except itself... unless there
is an "is", in which case it gets the inherited class.
It will then get Any/Mu thereby. Unless that "is" was an
"is Mu" in which case it only gets Mu:
# This fails... .elems is from Any and compute_mro recurses
# into the type in the "is".
perl6 -e 'role Meow { method elems {...} }; class Boo { }; class Bar is Mu does
Meow { }; Bar.^mro.say'
It looks like with a not-yet-composed class C3MRI.compute_mro
will not find Any/Mu... it is not the case that comput_mro was
called even earlier than this and cached an incomplete $!mro.
There must be a fixup to prevent this situation because:
$ perl6 -e 'role Meow { method split {...} }; class Boo { }; class Bar does
Meow { method split { 42 } }; Bar.^mro.say'
((Bar) (Any) (Mu))
...the code in C3MRO if left to its own devices would have
left Bar with only itself in .^mro in this situation.
Tracing it back up, if you look several lines under the call to
RoleToClassApplier.apply, you'll see the code that adds
.get_default_parent_type to the mro. I'm too tired to try at
the moment, but either this needs to be done earlier, or we
need to emulate it in RoleToClassApplier.