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:
- A scalar containing a glob reference.
local *$globref inside a dynamic scope.
- Opening or assigning through
*$globref inside that scope.
- Restoration of the original glob after scope exit.
- JVM and interpreter backend success.
Test-Spec v0.54 should then be rerun as integration coverage.
Summary
PerlOnJava cannot compile the valid Perl construct
local *$globref, where a typeglob is selected through a scalar glob reference. This blocksTest::Specv0.54 becauseTest::Trap::Builder::TempFileuses this construct to temporarily replace an output glob.CPAN evidence
Archived CPAN random tester run:
20260908-125510-82561Distribution:
Test-Specv0.54The upstream suite passes under system Perl:
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:
The CPAN run reports the source location as the
local *$globrefstatement inTest::Trap::Builder::TempFile.pm.Minimal reproduction
With
Test::Trapavailable inPERL5LIB, this succeeds under system Perl:Both PerlOnJava backends fail deterministically:
Both produce the same
Unsupported local operand: OperatorNodediagnostic. The failure is pure Perl and does not require XS, a service, a display, or network access.Triggering code
Test::Trap::Builder::TempFilecontains the following pattern: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:
local *FHis handled by the JVM emitter and bytecode compiler.local *{expr}is handled by the bytecode compiler when the*operand contains aBlockNode.local *$globrefparses aslocalapplied to a*OperatorNodewhose operand is the$globrefOperatorNode.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 operandfor this shape. The JVM emitter similarly recognizes only a*operand containing anIdentifierNode; the glob-reference form is not emitted as a dynamic glob localization operation.The implementation needs to resolve the runtime
RuntimeGlobrepresented 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 subsequentopen *$globref,binmode *$globref, and method calls must operate on the localized glob.Expected behavior
local *$globrefshould 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:
local *$globrefinside a dynamic scope.*$globrefinside that scope.Test-Specv0.54 should then be rerun as integration coverage.