Skip to content

Support local *$globref dynamic typeglob localization #1305

Description

@fglock

Summary

PerlOnJava cannot compile the valid Perl construct local *$globref, where a typeglob is selected through a scalar glob reference. This blocks Test::Spec v0.54 because Test::Trap::Builder::TempFile uses this construct to temporarily replace an output glob.

CPAN evidence

Archived CPAN random tester run: 20260908-125510-82561

Distribution: Test-Spec v0.54

The upstream suite passes under system Perl:

  • 19 test programs
  • 171 tests passed
  • 2 author-only test programs skipped

PerlOnJava fails 23/23 executed subtests across 17/19 test programs. The failures occur while loading the dependency Test::Trap::Builder::TempFile, before most Test::Spec tests can run.

Representative diagnostic:

Unsupported local operand: OperatorNode

The CPAN run reports the source location as the local *$globref statement in Test::Trap::Builder::TempFile.pm.

Minimal reproduction

With Test::Trap available in PERL5LIB, this succeeds under system Perl:

perl -MTest::Trap::Builder::TempFile -e 1

Both PerlOnJava backends fail deterministically:

./jperl -MTest::Trap::Builder::TempFile -e 1
./jperl --interpreter -MTest::Trap::Builder::TempFile -e 1

Both produce the same Unsupported local operand: OperatorNode diagnostic. The failure is pure Perl and does not require XS, a service, a display, or network access.

Triggering code

Test::Trap::Builder::TempFile contains the following pattern:

my ($name, $fileno, $globref) = @_;
local *$globref;
{
    no warnings 'io';
    local ($!, $^E);
    open *$globref, '>>', $file;
}

The glob reference is then used for PerlIO::get_layers, binmode, and autoflush operations.

Root cause

PerlOnJava has partial typeglob localization support, but the supported AST shapes do not include a glob dereference whose operand is a scalar variable:

  • Named local *FH is handled by the JVM emitter and bytecode compiler.
  • Dynamic local *{expr} is handled by the bytecode compiler when the * operand contains a BlockNode.
  • local *$globref parses as local applied to a * OperatorNode whose operand is the $globref OperatorNode.

The bytecode compiler's local handling accepts the named-identifier and block-expression forms, then falls through to its generic error path and raises Unsupported local operand for this shape. The JVM emitter similarly recognizes only a * operand containing an IdentifierNode; the glob-reference form is not emitted as a dynamic glob localization operation.

The implementation needs to resolve the runtime RuntimeGlob represented by the glob reference and pass it through the existing local-glob save/restore machinery. The behavior must preserve the complete glob, including its IO slot, and restore it when the dynamic scope exits. The subsequent open *$globref, binmode *$globref, and method calls must operate on the localized glob.

Expected behavior

local *$globref should compile and run on both JVM and interpreter backends with Perl-compatible dynamic scoping. After the scope exits, the original glob and its IO state should be restored.

Regression coverage

Add a project-owned focused unit test covering at least:

  1. A scalar containing a glob reference.
  2. local *$globref inside a dynamic scope.
  3. Opening or assigning through *$globref inside that scope.
  4. Restoration of the original glob after scope exit.
  5. JVM and interpreter backend success.

Test-Spec v0.54 should then be rerun as integration coverage.

Activity

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Metadata

Metadata

Assignees

No one assigned

    Labels

    bugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions