Skip to content

Preserve dual numeric/string semantics for numeric-looking qw literals #1308

Description

@fglock

Summary

List::PowerSet 0.01 exposes a PerlOnJava scalar-semantics bug. The module correctly copies its input values, but numeric-looking values supplied by qw(...) are represented as string-only scalars. Standard Perl preserves numeric/string dual-value semantics for these values, so the upstream deep comparison passes there and fails on PerlOnJava.

CPAN evidence

  • Distribution: List-PowerSet 0.01
  • CPAN run: 20260908-125510-82561
  • Failure record: FAIL List::PowerSet List::PowerSet
  • Failing test: t/01basic.t, test 4
  • System Perl: all 13 tests pass
  • PerlOnJava: 1 of 13 tests fails on both the JVM and interpreter backends
  • Environment: pure-Perl distribution; no XS, native library, display, service, or platform prerequisite

The failing assertion compares the result of powerset(qw(1 2 3)) with [[1, 2, 3], [2, 3], [1, 3], [3], [1, 2], [2], [1], []]. PerlOnJava displays the copied values as '1', '2', and '3', while the expected numeric literals are displayed as 1, 2, and 3.

Minimal reproducer

use List::PowerSet qw(powerset);
use Test::Differences;

eq_or_diff(
    powerset(qw(1 2 3)),
    [[1, 2, 3], [2, 3], [1, 3], [3], [1, 2], [2], [1], []],
    'powerset preserves scalar semantics',
);

This passes under system Perl and fails under both PerlOnJava backends. The same distribution test also demonstrates that powerset_lazy(1 .. 3) passes, because the range expressions are numeric literals rather than qw string literals.

Confirmed root cause

StringParser.parseWordsString creates a StringNode for every qw word. The bytecode compiler consequently emits a byte-string/string scalar for 1, 2, and 3. In Perl, numeric-looking quoted values retain dual numeric/string behavior used by type-sensitive comparisons such as Test::Differences::eq_or_diff; they are not equivalent to an arbitrary nonnumeric string scalar.

List::PowerSet::powerset only performs [$first, @$_] and [ @$_ ], so it preserves the incoming scalar values and is not the source of the mismatch. The failure is therefore in PerlOnJava literal/scalar representation and its propagation through list construction, not in the CPAN module or test environment.

Impact

This affects pure-Perl code that passes numeric-looking quoted values through APIs and later compares them with numeric values using deep or scalar-type-sensitive operations. It is a general compatibility issue, with List::PowerSet providing a small, reproducible CPAN case. It is related to, but broader than, the numeric-zero dual-value case tracked in #1262 and the JSON typing issue in #1260.

Expected fix

Preserve Perl-compatible dual numeric/string semantics for numeric-looking quoted literals, including values produced by qw(...), when they are copied through arrays, lists, and pure-Perl subroutines. The fix must retain genuine string-versus-number distinctions where Perl retains them and work on both execution backends.

Add permanent project-owned regression coverage for:

  1. A numeric-looking qw value compared with a numeric literal through the Test::Differences path.
  2. List::PowerSet-style recursive list copying.
  3. Both JVM and interpreter execution.
  4. Ordinary nonnumeric strings remaining strings.

Do not change List::PowerSet or weaken Test::Differences to hide the incompatibility.

Related issues

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

    area:backendJVM interpreter or execution-backend behaviorarea:cpan-portCPAN compatibility ports and providersarea:runtimeCore Perl runtime semanticsbugSomething isn't working

    Projects

    No projects

      Milestone

      No milestone

      Relationships

      None yet

      Development

      No branches or pull requests

      Issue actions