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

A method installed by an Attribute object during compile time doesn't preserve it's closure. #2255

Open
vrurg opened this issue Sep 7, 2018 · 3 comments

Comments

Projects
None yet
1 participant
@vrurg
Copy link
Member

commented Sep 7, 2018

The Problem

This report stems from a stackoverflow question. In short, if a role applied to an Attribute object which is being composed into a role installs a method on that role the method loses its closure causing Cannot invoke this object (REPR: Null; VMNull) error message during run time when the method is called. The problem occurs only if class and roles it is consuming are defined in different files; the class must consume one role directly whereas that role does the second one:

class Foo does FooRole;
role FooRole does BarRole;

Steps to Reproduce

Files in the archive demonstrate the problem.

compile-time-closure.tar.gz

Actual behavior

Executing compose_method_inject.p6 from the archive produces the following output:

> Class
not using closure
by class: attr $!fubar
by attr $!fubar
by attr $!fubar - public
> FooRole
{attr-foo => <anon>, check-foo => <anon>, role-foo => <anon>}
not using closure
by role: attr $!foo
Cannot invoke this object (REPR: Null; VMNull)

Note that injected methods work for a class. Also, methods not using closure or installed by a role applied to ParametricRoleHOW class are working as expected. But a method installed by FooAttr role fails most likely because $attr it is referring to doesn't exists at run time.

It is doesn't look like intended behavior. Taking the BarRole away from FooRole declaration and applying it directly to the class results in the correct output:

> Class
not using closure
by class: attr $!fubar
by attr $!fubar
by attr $!fubar - public
> FooRole
{attr-foo => <anon>, check-foo => <anon>, role-foo => <anon>}
not using closure
by role: attr $!foo
by attr $!foo
> BarRole
{attr-bar => <anon>, check-bar => <anon>, role-bar => <anon>}
not using closure
by role: attr $!bar
by attr $!bar

The problem also seem to be macOS/darwin related because testing on Linux Mint 19 went ok, all variants of the attached scripts are working as expected.

Environment

  • Operating system: macOS 10.13
  • Compiler version (perl6 -v): This is Rakudo version 2018.08 built on MoarVM version 2018.08
    Same symptoms are observed for 2018.06 and 2017.10
@vrurg

This comment has been minimized.

Copy link
Member Author

commented Sep 8, 2018

Additional testing revealed another significant detail about what's going on. It seems that it is not needed for FooRole to consume BarRole. use compose-barrole; is sufficient for reproducing the problem.

vrurg added a commit to vrurg/Perl6-AttrX-Mooish that referenced this issue Sep 8, 2018

Workaround for bug #2255
rakudo/rakudo#2255

Fixed incorrect TypeCheck exception throw

vrurg added a commit to vrurg/Perl6-AttrX-Mooish that referenced this issue Sep 8, 2018

Workaround for bug #2255
rakudo/rakudo#2255

Fixed incorrect TypeCheck exception throw
@vrurg

This comment has been minimized.

Copy link
Member Author

commented Mar 11, 2019

One more correction: linux version is affected too. It looks like because vmware shared folder was mounted with wrong permissions no precompilation was used resulting in correct script output.

@vrurg

This comment has been minimized.

Copy link
Member Author

commented Mar 12, 2019

Further investigation into the problem reveals that what happens here is that a closure gets lost upon serialization or deserialization of the modules. In the attached example methods added by the code in trait-foo.pm6 get their closure from applying the trait to a role in the latest loaded compose-barrole.pm6 file; but closures from applying the role in compose-foorole.pm6 are getting lost.

A workaround is to use 'no precompilationintrait-foo.pm6`.

Another workaround is to use .set_name on generated methods and use unique names.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
You can’t perform that action at this time.