Raku / old-issue-tracker

Tickets from RT
https://github.com/Raku/old-issue-tracker/issues
2 stars 1 forks source link

doing a role fails to find inherited methods in some cases #6367

Open p6rt opened 7 years ago

p6rt commented 7 years ago

Migrated from rt.perl.org#131676 (status was 'open')

Searchable as RT131676$

p6rt commented 7 years ago

From @zoffixznet

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 \␤Method 'iterator' must be implemented by Bar because it is required by roles​: Meow.␤at \​: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 )

p6rt commented 7 years ago

From @zoffixznet

On Thu, 29 Jun 2017 03​:46​:02 -0700, cpan@​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 \␤Method 'iterator' must be implemented by Bar because it is required by roles​: Meow.␤at \​: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

p6rt commented 6 years ago

From @skids

On Mon, 07 Aug 2017 08​:25​:10 -0700, cpan@​zoffix.com wrote​:

On Thu, 29 Jun 2017 03​:46​:02 -0700, cpan@​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 \␤Method 'iterator' must be implemented by Bar because it is required by roles​: Meow.␤at \​: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.

p6rt commented 6 years ago

The RT System itself - Status changed from 'new' to 'open'

p6rt commented 6 years ago

From @skids

On Mon, 07 Aug 2017 08​:25​:10 -0700, cpan@​zoffix.com wrote​:

On Thu, 29 Jun 2017 03​:46​:02 -0700, cpan@​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 \␤Method 'iterator' must be implemented by Bar because it is required by roles​: Meow.␤at \​: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

Rakudo PR request 1170 submitted to address this.

With that patch applied both above examples work and this still fails, as it should​:

$ perl6 -e 'class Foo { method x {} }; role Meow { method elems {…} }; class Bar is Mu does Meow {}' ===SORRY!=== Error while compiling -e Method 'elems' must be implemented by Bar because it is required by roles​: Meow. at -e​:1

usev6 commented 10 months ago

As a status update: The code from the original post doesn't die anymore (and neither does the code from the first response).

$ ./rakudo-m -e 'role Meow { method iterator {...} }; class Bar does Meow {}; say "alive"'
alive

And the evaluation from the last response, which is supposed to die, dies:

$ ./rakudo-m -e 'class Foo { method x {} }; role Meow { method elems {...} }; class Bar is Mu does Meow {}'
===SORRY!=== Error while compiling -e
Method 'elems' must be implemented by Bar because it is required by roles: Meow.
at -e:1

So, it looks like this could be closed. But we should check if this is covered by tests.