Skip to content

feat: Type::Tiny support — investigation and fixes#475

Open
fglock wants to merge 13 commits intomasterfrom
feature/type-tiny-support
Open

feat: Type::Tiny support — investigation and fixes#475
fglock wants to merge 13 commits intomasterfrom
feature/type-tiny-support

Conversation

@fglock
Copy link
Copy Markdown
Owner

@fglock fglock commented Apr 9, 2026

Summary

Investigate and fix ./jcpan --jobs 8 -t Type::Tiny test failures for Type::Tiny 2.010001.

  • Add dev/modules/type_tiny.md investigation plan with 14 categorized issues
  • Fix looks_like_number() to parse string values (Phase 1)
  • Fix my scoping in for statement modifier (Phase 2)
  • Fix prototype ;$ with | infix operator parsing (Phase 3)

Test plan

  • make passes (no regressions)
  • ./jcpan --jobs 8 -t Type::Tiny shows improved pass rate
  • looks_like_number('1.1') returns true
  • for (my ($s, @a) = @_) scopes variables to enclosing block
  • ArrayRef | HashRef parses correctly with ;$ prototype

Generated with Devin

fglock and others added 9 commits April 9, 2026 22:21
Add dev/modules/type_tiny.md documenting the investigation of
jcpan Type::Tiny test failures, categorizing 14 distinct issues
by root cause and priority.

Key findings:
- looks_like_number() only checks internal type, not string content
- my declarations in for statement modifier dont leak to outer scope
- Prototype ;$ functions followed by | infix cause syntax errors
- Type::Params v2 wrap_subs cant find functions in callers stash

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
'for (my ($s, @A) = @_)' with outer parentheses caused the modifier
expression to be wrapped in a ListNode, which prevented the existing
my-hoisting logic from matching the BinaryOperatorNode pattern.

Now unwraps single-element ListNode before checking for the assignment
pattern, so both 'for my @w = LIST' and 'for (my @w = LIST)' correctly
hoist variable declarations to the enclosing scope.

This fixes the dominant Type::Tiny failure (~40+ tests) caused by
Type::Tiny.pm line 610: 'for (my ($s, @A) = @_)' where $s was
not visible on the next line.

Part of Type::Tiny support (Phase 2).

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Functions with ;$ prototype (e.g. ArrayRef, HashRef from Types::Standard)
now correctly parse binary-only infix operators as argument terminators.
For example, ArrayRef | HashRef is now parsed as (ArrayRef()) | (HashRef())
instead of trying to parse | HashRef as an argument to ArrayRef.

Added |, ^, |., ^., &., ==, !=, >, >=, .., ..., =~, !~, and ? to
isArgumentTerminator in PrototypeArgs.java. This matches Perl behavior
where these operators cannot start a primary expression.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When a subroutine contains goto $variable, PerlOnJava falls back to
the interpreter backend for that sub. Previously, caller() in such
subs returned the wrong package because ExceptionFormatter consumed
CallerStack entries from compile-time contexts (BEGIN/use) for
interpreter frames.

Fix: Remove CallerStack usage from interpreter frame processing
entirely. Interpreter frames now always use tokenIndex/PC-based
lookup via ByteCodeSourceMapper, avoiding contamination from
compile-time CallerStack entries. Also remove unused pre-scan code
and all DEBUG_CALLER instrumentation.

This fixes Type::Params::signature_for which uses goto $compiled
and needs correct caller() to find functions in the caller stash.

Tests now passing: v2-defaults.t (2/2), v2-positional.t (13/13),
v2-named.t (15/15), v2-allowdash.t (20/20), v2-listtonamed.t (17/17)

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Add instruction in AGENTS.md to write commit messages to a temp file
and use `git commit -F` instead of `-m`. This avoids problems with
apostrophes, backticks, and other special characters in commit messages.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Perl allows ${^_TYPE_PARAMS_MULTISIG} and similar variables where the
first character after ^ is underscore. The parser only accepted
uppercase letters (A-Z), causing compilation failures for code using
this syntax.

This fixes Type::Params multisig support which uses ${^_TYPE_PARAMS_MULTISIG}
internally to track which signature alternative matched.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Compiler infrastructure frames (e.g., anonymous sub wrappers from
runSpecialBlock for use/BEGIN argument evaluation) can have JVM line
number -1, producing stack frames with empty package and line -1.

Skip these invalid frames so caller() returns the correct package
in compile-time contexts like use constant FBB => enum(...).

This fixes Type::Tiny::Enum and other modules that call caller()
through wrapper functions during compile-time evaluation.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
…sing

- BitwiseOperators: check for overloaded '(~' on blessed objects in
  bitwiseNot() and integerBitwiseNot() before performing bitwise NOT
- PrototypeArgs: treat ;$ and ;_ prototypes as named unary operators
  so that expressions like ArrayRef[Int] | HashRef[Int] parse correctly
  (| terminates the first argument instead of being consumed by it)

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Two fixes:

1. PrototypeArgs: recognize comma as "no argument" for named-unary
   operators with ;$ or ;_ prototypes. Previously, `Foo, bar` with
   sub Foo (;$) caused a syntax error because the comma wasn't
   treated as an argument terminator. This fixes Type::Params::Parameter
   loading (syntax error at line 445) and unblocks many Type::Tiny tests.

2. BytecodeInterpreter: EQ_STR and NE_STR opcodes now call
   CompareOperators.eq()/ne() instead of CompareOperators.cmp().
   The old code only checked the (cmp overload, missing the (eq/(ne
   overloads. This fixes matchfor.t where objects with overloaded eq
   were compared as plain strings.

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
@fglock fglock force-pushed the feature/type-tiny-support branch from 0fb24a8 to a379cb5 Compare April 9, 2026 21:14
fglock and others added 4 commits April 9, 2026 23:36
…umber

Two fixes:

1. Bytecode compiler (eval context) now compiles the right operand of
   grep/map/sort/all/any in LIST context, matching the JVM backend.
   Previously, the outer scalar context propagated to the list operand,
   causing `scalar(grep { ... } @array)` to only see the array count
   (a single number) instead of the actual array elements.

   Also simplified the ARRAY_SIZE opcode to use operand.scalar()
   uniformly, since RuntimeArray.scalar() already returns the count.

2. looks_like_number now recognizes signed Inf/NaN strings (-Inf, +Inf,
   -NaN, +NaN) and case-insensitive variants (inf, nan, etc.).

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Updated dev/modules/type_tiny.md with:
- Phase 5a/5b completed phases and fixes
- Results history table (baseline → 99.0%)
- Remaining 10 failing tests analysis
- Next steps

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
Three fixes that improve Type::Tiny pass rate from 99.1% to 99.3%:

1. Numify overload: Overload.numify() can return a STRING (e.g., "3.1"
   from a 0+ handler). getNumberLarge() now converts string results to
   proper numeric types. Fixes 0+$obj returning truncated integer.

2. AUTOLOAD $AUTOLOAD persistence: autoloadVariableName was permanently
   set on RuntimeCode objects after first AUTOLOAD fallback. This caused
   $self->SUPER::AUTOLOAD(@_) to overwrite $AUTOLOAD with garbage.
   Fixed by skipping $AUTOLOAD assignment when method name IS "AUTOLOAD".

3. Interpreter grep/map outer @_: executeGrep/executeMap didn't pass
   the enclosing sub's @_ to grep/map blocks (register 1), unlike the
   JVM backend. Dict+Slurpy inline checks use $_[0] inside grep blocks.

Tests fixed: structured.t (110→115/115), Bitfield/basic.t (80→81/81),
ConstrainedObject/basic.t (24→27/27), multisig-custom-message.t (→21/21)

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
When compiling `local @_ = @_`, the RHS @_ evaluated to register 1.
PUSH_LOCAL_VARIABLE then cleared register 1 before ARRAY_SET_FROM_LIST
could read from it, resulting in @_ always being empty after localizing.

Fix: when valueReg == regIdx, copy RHS to a temporary register via
NEW_ARRAY + ARRAY_SET_FROM_LIST before calling PUSH_LOCAL_VARIABLE.

The JVM backend is not affected (already clones the RHS list before
localizing).

This fix unlocks 246 more Type::Tiny tests that were previously dying
in Type::Params::Alternatives multisig dispatch. v2-returns.t now
passes all 5/5 subtests.

Type::Tiny results: 345/375 files, 3130/3166 subtests (98.9%)

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

Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com>
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