tobyink / p5-moops

16 stars 4 forks source link

Flaw in determining package names #19

Open tobyink opened 3 years ago

tobyink commented 3 years ago

Migrated from rt.cpan.org #123445 (status was 'open')

Requestors:

From $_ = 'spro^^%^6ut#@&$%*c>#!^!#&!pan.org'; y/a-z.@//cd; print on 2017-10-30 01:18:50 :

If I run this script:

!perl

package What::Ever;

use Moops; class Foo {

};

eval { Foo->meta }; warn $@ if $@; eval { What::Ever::Foo->meta }; warn $@ if $@; END

I get this error message:

Can't locate object method "meta" via package "Foo" (perhaps you forgot to load "Foo"?) at - line 9.

If I comment out the package declaration, I get this error message:

Can't locate object method "meta" via package "What::Ever::Foo" (perhaps you forgot to load "What::Ever::Foo"?) at - line 7.

Judging by the code, I think this is by design. But here is the catch: When a module (or any file) is loaded via ‘use’ or ‘require’, the package in which the module is initially compiled is that of the caller (the code containing the ‘require’ statement). That means that this module:

$ cat Pfoom.pm use Moops; class Pfoom { } END

may define a top-level Pfoom class (if ‘use Pfoom’ is in main), or it may define a subpackage, such as Gromple::Pfoom (if ‘use Pfoom’ is in the Gromple package).

Now, there is a glitch in existing Perl versions up to 5.27.4, in that, while PL_curstash points to the package of the code currently being compiled and PL_curstname is a char* holding the package name, sometimes they can get out of synch, because PL_curstname is set only with ‘package’ declarations, and not at the beginning of a string eval or file.

In bleadperl (5.27.5) I fixed it, because it was causing the wrong package to show up in error messages (see https://perl5.git.perl.org/perl.git/commitdiff/04680144c43).

Now Parse::Keyword::compiling_package, which Moops happens to use, gets the name from PL_curstname, the variable that is sometimes off.

This means that

eval "use Pfoom";

will create a Pfoom class as long as there is no currently compiling scope, but

use Pfoom;

will create a package named Whatever::Pfoom, assuming that the scope in which ‘use’ occurs has a ‘package Whatever’ declaration in it.

As of 5.27.6, the former behaves consistently the same way as the latter, which happens to break Pod::Elemental::Transformer::Splint (https://rt.perl.org/Ticket/Display.html?id=132373).

I can see two possible ways for you to fix this unpredictability in the way Moops handles unqualified package names:

1) Drop support for nested package names; just do things the Perl 5 way.

2) Look at the file name of the code that is currently being compiled. (I don’t know offhand how to do that from pure-Perl, but I can look into it if you want to follow this route.)

tobyink commented 3 years ago

From $_ = 'spro^^%^6ut#@&$%*c>#!^!#&!pan.org'; y/a-z.@//cd; print on 2017-10-30 01:31:26 :

On Sun Oct 29 21:18:50 2017, SPROUT wrote:

PL_curstname is a char* holding the package name,

Correction: PL_curstname is an SV*, but this does not affect Moops.