Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

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

Open
p6rt opened this issue Jun 29, 2017 · 6 comments
Open

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

p6rt opened this issue Jun 29, 2017 · 6 comments

Comments

@p6rt
Copy link

p6rt commented Jun 29, 2017

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

Searchable as RT131676$

@p6rt
Copy link
Author

p6rt commented Jun 29, 2017

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 <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 )

@p6rt
Copy link
Author

p6rt commented Aug 7, 2017

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 <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 Raku/doc#1438

@p6rt
Copy link
Author

p6rt commented Sep 23, 2017

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 <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 Raku/doc#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
Copy link
Author

p6rt commented Sep 23, 2017

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

@p6rt
Copy link
Author

p6rt commented Sep 23, 2017

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 <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 Raku/doc#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
Copy link

usev6 commented Oct 8, 2023

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants