Skip to content

Fix Moo support: stash keys, &{} overload, and local @_ in eval#321

Merged
fglock merged 3 commits into
masterfrom
fix/moo-local-eval-stash
Mar 16, 2026
Merged

Fix Moo support: stash keys, &{} overload, and local @_ in eval#321
fglock merged 3 commits into
masterfrom
fix/moo-local-eval-stash

Conversation

@fglock
Copy link
Copy Markdown
Owner

@fglock fglock commented Mar 16, 2026

Summary

This PR fixes several issues discovered while improving Moo CPAN module support:

Phase 22: Stash Keys and Overload Handling

  • Fixed stash keys for nested packages - keys %Foo::Bar:: now correctly returns Baz:: (with trailing ::) instead of Baz
  • Fixed &{$blessed_obj} handling - Now correctly throws "Not a subroutine reference" for blessed objects without &{} overload

Phase 23: Local @_ in String Eval

  • Fixed local @_ = (...) in string eval to use register-based localization instead of global @main::_
  • This was critical for Sub::Quote's inlinification pattern used by Moo for coerce/trigger/isa

Files Changed

  • HashSpecialVariable.java - Fixed nested package stash key formatting
  • RuntimeCode.java - Added &{} overload check in createCodeReference
  • BytecodeCompiler.java - Added isReservedVariable() check for register-based local
  • CompileAssignment.java - Updated to use register-based PUSH_LOCAL_VARIABLE for @_
  • dev/design/moo_support.md - Updated design doc with Phase 22 and 23

Test Results

  • Moo tests: 62/71 programs passing (87%), 768/829 subtests (93%)
  • All remaining failures are expected due to Java limitations (weak refs, DESTROY)

Test plan

  • All existing unit tests pass
  • Moo test suite shows improvement (49/49 on method-generate-accessor.t)
  • t/load_module_role_tiny.t now passes
  • t/coerce-1.t now fully passes

Generated with Devin

fglock and others added 3 commits March 16, 2026 07:11
Two fixes for Moo compatibility:

1. Stash keys for nested packages must include trailing `::`
   - `keys %Foo::Bar::` was returning `Baz` instead of `Baz::`
   - This broke Role::Tiny::_load_module which checks for `/::\z/` suffix
   - Fix: HashSpecialVariable.java - include `::` in entryKey

2. \&{$blessed_obj} must throw "Not a subroutine reference"
   - For objects without &{} overload, was creating symbolic reference
   - Perl throws "Not a subroutine reference" in this case
   - Fix: RuntimeCode.java - check blessId and throw if no &{} overload

Moo test results: 61/71 programs passing (86%), 765/829 subtests (92%)

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
When compiling local @_ = (...) in string eval, the compiler was
localizing @main::_ (global array) instead of register 1 which holds
the actual @_ for the subroutine.

In PerlOnJava, @_ in a subroutine (register 1) and @main::_ are
different arrays. This caused Sub::Quote local @_ = ($value)
inlinification pattern to fail silently.

Fix: For reserved variables like @_, use PUSH_LOCAL_VARIABLE on the
register directly instead of loading and localizing the global array.

Moo test results: 62/71 programs (87%), 768/829 subtests (93%)
- method-generate-accessor.t: 49/49 (was 46/49)

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
When *a = *b is followed by *a = \@x, both aliased globs should be
updated because they share the same glob slots. Previously, only the
directly assigned glob was updated, breaking ISA resolution.

Added glob alias tracking:
- GlobalVariable.globAliases map tracks which globs share slots
- getGlobAliasGroup() returns all globs aliased to the same target
- When assigning array/hash refs to a glob, all aliased globs are updated

This fixes the regression where mro/isa_aliases.t dropped from 11/13 to
10/13 passing tests. Now all 13 tests pass.

Generated with [Devin](https://cli.devin.ai/docs)

Co-Authored-By: Devin <noreply@cognition.ai>
@fglock
Copy link
Copy Markdown
Owner Author

fglock commented Mar 16, 2026

Additional Fix: Glob Aliasing Regression

Added a fix for the mro/isa_aliases.t regression (11/13 → 13/13 now passing).

Root Cause: When *a = *b is followed by *a = \@x, both aliased globs should be updated because they share the same glob slots. Previously, only the directly assigned glob was updated, breaking ISA resolution.

Solution: Added glob alias tracking:

  • GlobalVariable.globAliases map tracks which globs share slots
  • getGlobAliasGroup() returns all globs aliased to the same target
  • When assigning array/hash refs to a glob, all aliased globs are updated

This also fixes previously failing tests 10 and 12 in mro/isa_aliases.t (going from 11/13 to 13/13).

@fglock fglock merged commit 2d245bc into master Mar 16, 2026
2 checks passed
@fglock fglock deleted the fix/moo-local-eval-stash branch March 16, 2026 08:27
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

Successfully merging this pull request may close these issues.

1 participant