Skip Menu |

This queue is for tickets about the Moose CPAN distribution.

Report information
The Basics
Id: 89713
Status: resolved
Priority: 0/
Queue: Moose

People
Owner: Nobody in particular
Requestors: KENTNL [...] cpan.org
Cc:
AdminCc:

Bug Information
Severity: Normal
Broken in:
  • 2.1102-TRIAL
  • 2.1105-TRIAL
Fixed in: 2.1106-TRIAL



Subject: Undefined subroutine &Class::MOP::Method::Constructor::throw_exception

Hit this bug while trying to add exception support for MX::Aliased

The real issue is I forgot to quote something somewhere ( stack frame #2 ) but this is obscured by a higher level failure that propagates a different error.

Its confusing, mostly because its obvious the containing scope is importing that method, but its not there when its called.

I tried rather hard to replicate the problem in a reduced amount of code, to no avail.

However, if I replaced the `use` statement with :

sub throw_exception {
    require Moose::Util;
    goto &Moose::Util::throw_exception;
}

It gave me a more appropriate stacktrace , which didn't require me to provide -MCarp::Always to get useful context out ( albeit a more messy result )

 

 

 

 

 

Subject: stacktrace
Download stacktrace
application/octet-stream 2.6k

Message body not shown because it is not plain text.

Subject: stacktrace_after
Download stacktrace_after
application/octet-stream 19.2k

Message body not shown because it is not plain text.

Apologies, it seems RT is not smart enough to determine content type without an extension.
Subject: stacktrace.txt
Undefined subroutine &Class::MOP::Method::Constructor::throw_exception called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Class/MOP/Method/Constructor.pm line 119. Class::MOP::Method::Constructor::catch {...} ("Failed to compile source: Bareword \"Aliases::InitArgConflict\""...) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/Try/Tiny.pm line 106 Try::Tiny::try(CODE(0x34b89a0), Try::Tiny::Catch=REF(0x34b81f8)) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Class/MOP/Method/Constructor.pm line 123 Class::MOP::Method::Constructor::_generate_constructor_method_inline(Moose::Meta::Method::Constructor=HASH(0x34b85a0)) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Moose/Meta/Method/Constructor.pm line 63 Moose::Meta::Method::Constructor::_initialize_body(Moose::Meta::Method::Constructor=HASH(0x34b85a0)) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Moose/Meta/Method/Constructor.pm line 54 Moose::Meta::Method::Constructor::new("Moose::Meta::Method::Constructor", "options", HASH(0x33ef238), "metaclass", Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x34933a0), "is_inline", 1, "package_name", "MyTest", ...) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Class/MOP/Class.pm line 1456 Class::MOP::Class::_inline_constructor(Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x34933a0), "inline_destructor", 1, "constructor_name", "new", "inline_accessors", 0, "line", 83, ...) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Class/MOP/Class.pm line 1412 Class::MOP::Class::_install_inlined_code(Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x34933a0), "destructor_class", "Moose::Meta::Method::Destructor", "line", 83, "inline_accessors", 0, "constructor_name", "new", ...) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Class/MOP/Class.pm line 1404 Class::MOP::Class::_initialize_immutable(Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x34933a0), "file", "/home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.1"..., "line", 83, "inline_accessors", 1, "inline_constructor", 1, ...) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Class/MOP/Class.pm line 1300 Class::MOP::Class::make_immutable(Moose::Meta::Class::__ANON__::SERIAL::1=HASH(0x34933a0)) called at /home/kent/perl5/perlbrew/perls/perl-5.19.3/lib/site_perl/5.19.3/x86_64-linux/Test/Moose.pm line 83 Test::Moose::with_immutable(CODE(0x34ab070), "MyTest") called at t/traits.t line 45
Subject: stacktrace_after.txt

Message body is not shown because it is too large.

On 2013-10-23 07:21:07, KENTNL wrote: Show quoted text
> Hit this bug while trying to add exception support for MX::Aliased
Please try again with the latest Moose trial; a few missing subs have been added!

On 2013-11-01 12:12:47, ETHER wrote:
> On 2013-10-23 07:21:07, KENTNL wrote:
> > Hit this bug while trying to add exception support for MX::Aliased
>
> Please try again with the latest Moose trial; a few missing subs have
> been added!


Just tried, but no.

 

The issue here is not that the method is not defined in the code, the method is really there, just the time at which I manage to trigger the metacircular fail is during class composition.

At least, thats the appearance.

The real problem is that I've attempted to inline literal code, and there's been a typeo in that code, but the actual problem is obscured

Here is the code *after* I fixed the typo, which makes the failure stop occurring.

https://github.com/kentfredric/moosex-aliases/blob/mx_exceptions/lib/MooseX/Aliases/Meta/Trait/Class.pm#L26

To bring the bug back, all you have to do is modify that literal string so it would be a 'strict' error

And the sub *does* exist, at least, it does normally:

perl -MClass::MOP -MClass::MOP::Method::Constructor  -E' say Class::MOP::Method::Constructor::throw_exception(Legacy => {})'

Confirms that method exists, just at the time the above compilation occurs, that method doesn't appear to have been imported yet ( or its vanished by some cleaning tool ), which is why explicitly declaring a sub solves the problem.
 

It only *looks* tangentially related to the change involving the addition/removal of throw_error.

Ok, I've managed to reduce MooseX::Aliases to a smaller subset of failing behaviour so its clearer.

 

The problem basically occurs during immutabilization, and as far as I can tell, only immutabilzation, because that's the phase that gets bunches of text stored in strings, and compiles them into the constructor.

https://metacpan.org/source/ETHER/Moose-2.1105-TRIAL/lib/Class/MOP/Method/Constructor.pm#L114

And its the bad text in the source which causes that to die(), and that die is later caught here:

https://metacpan.org/source/ETHER/Moose-2.1105-TRIAL/lib/Class/MOP/Method/Constructor.pm#L116

Which attempts to call throw_exception on line 118 , which should work, after all, its the same source file right?

However, it doesn't, so in the process of attempting to throw the right exception, it fails, and gives a plain perl die error instead, obscuring the real problem.

 

Attached is a tar.xz of a source tree I've tested that replicates the scenario for me on dev perl.

Subject: Fail.tar.xz
Download Fail.tar.xz
application/x-xz 1.3k

Message body not shown because it is not plain text.

Welp. Its a compile-time metacircularity problem, found a reduced test case FINALLY

 

use strict;
use warnings;
use Moose::Util qw( throw_exception );

my $class = Class::MOP::Method::Constructor->new();

Its really that simple.

 

because "use Moose::Util"  does "use Class::MOP " BEFORE the sub exists, so when Class::MOP does "use Moose::Util", it doesn't import a sub, it imports an UNDEFINED SUB , which means as long as Moose::Util is 'used' before Class::MOP::Method::Constructor, every single reference to throw_exception in Class::MOP::Method::Constructor will die with "undefined subroutine"  when it is called.

Which means this code is far more broken than simply suppressing compile errors.

 

Fortunately, this is easy to solve.

Define a proxy method in relevant places that runtime requires their dependency and uses a goto, and this problem should melt away.

 

Subject: Re: [rt.cpan.org #89713] Undefined subroutine &Class::MOP::Method::Constructor::throw_exception
Date: Thu, 31 Oct 2013 21:37:25 -0700
To: Kent Fredric via RT <bug-Moose [...] rt.cpan.org>
From: Karen Etheridge <ether [...] cpan.org>
On Thu, Oct 31, 2013 at 11:18:29PM -0400, Kent Fredric via RT wrote: Show quoted text
> Fortunately, this is easy to solve. > > Define a proxy method in relevant places that runtime requires their dependency > and uses a goto, and this problem should melt away.
How about we move the 'use Class::MOP' at the top of lib/Moose/Util.pm to the bottom, after all the subs are defined? I don't think that will be too late for anything, as all the references to Class::MOP in that file are fully-qualified subs (no use of imports).

Not a huge difference, but its there, and I've run the full test suite against the change, nothing broke.

( Nothing was expected to break, but if things were always as expected, tests would be unnecessary )

https://github.com/kentfredric/moose/compare/topic;rt89713?expand=1

How does 2.1106 fare?
Confirming fix, syntax errors in metalayer are now represented by a relevant error, instead of some obscure unrelated error-while-erroring error =)