On Mon, 07 Aug 2017 08:25:10 -0700, c...@zoffix.com wrote:
> On Thu, 29 Jun 2017 03:46:02 -0700, c...@zoffix.com 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.

Reply via email to