From 52632443d04146f1a2f02f40bad94d30e4a0f4b8 Mon Sep 17 00:00:00 2001 From: Flavio Soibelmann Glock Date: Mon, 13 Apr 2026 14:50:30 +0200 Subject: [PATCH 1/2] fix: dispatch <> overload on blessed objects instead of warning When a blessed object with `use overload '<>' => sub { ... }` was used in `<$obj>`, PerlOnJava treated it as readline on an unopened filehandle instead of invoking the overloaded method. Fix adds overload check in Readline.readline() before the unopened filehandle warning, and routes blessed objects through Readline in the bytecode interpreter backend. This fixes Iterator::Simple test failures (67/67 tests now pass). Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- .../backend/bytecode/OpcodeHandlerExtended.java | 7 ++++++- src/main/java/org/perlonjava/core/Configuration.java | 4 ++-- .../org/perlonjava/runtime/operators/Readline.java | 12 ++++++++++++ 3 files changed, 20 insertions(+), 3 deletions(-) diff --git a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java index c218df163..60918e057 100644 --- a/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java +++ b/src/main/java/org/perlonjava/backend/bytecode/OpcodeHandlerExtended.java @@ -837,8 +837,13 @@ public static int executeReadline(int[] bytecode, int pc, RuntimeBase[] register RuntimeScalar fh = (RuntimeScalar) registers[fhReg]; // Diamond operator <> passes a plain string scalar (not a glob/IO). // Route to DiamondIO.readline which manages @ARGV / STDIN iteration. + // But blessed objects may have <> overload, so route those to Readline. if (fh.getRuntimeIO() == null) { - registers[rd] = DiamondIO.readline(fh, ctx); + if (RuntimeScalarType.blessedId(fh) < 0) { + registers[rd] = Readline.readline(fh, ctx); + } else { + registers[rd] = DiamondIO.readline(fh, ctx); + } } else { registers[rd] = Readline.readline(fh, ctx); } diff --git a/src/main/java/org/perlonjava/core/Configuration.java b/src/main/java/org/perlonjava/core/Configuration.java index 7fd7161c1..11f1db198 100644 --- a/src/main/java/org/perlonjava/core/Configuration.java +++ b/src/main/java/org/perlonjava/core/Configuration.java @@ -33,7 +33,7 @@ public final class Configuration { * Automatically populated by Gradle/Maven during build. * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String gitCommitId = "7bf93f44f"; + public static final String gitCommitId = "0d83f6c7e"; /** * Git commit date of the build (ISO format: YYYY-MM-DD). @@ -48,7 +48,7 @@ public final class Configuration { * Parsed by App::perlbrew and other tools via: perl -V | grep "Compiled at" * DO NOT EDIT MANUALLY - this value is replaced at build time. */ - public static final String buildTimestamp = "Apr 13 2026 14:15:09"; + public static final String buildTimestamp = "Apr 13 2026 14:49:28"; // Prevent instantiation private Configuration() { diff --git a/src/main/java/org/perlonjava/runtime/operators/Readline.java b/src/main/java/org/perlonjava/runtime/operators/Readline.java index a4b02a21a..a4d95863e 100644 --- a/src/main/java/org/perlonjava/runtime/operators/Readline.java +++ b/src/main/java/org/perlonjava/runtime/operators/Readline.java @@ -20,6 +20,18 @@ public static RuntimeBase readline(RuntimeScalar fileHandle, int ctx) { RuntimeIO fh = fileHandle.getRuntimeIO(); if (fh == null) { + // Check for <> overload before warning about unopened filehandle + int blessId = RuntimeScalarType.blessedId(fileHandle); + if (blessId < 0) { + OverloadContext overloadCtx = OverloadContext.prepare(blessId); + if (overloadCtx != null) { + RuntimeScalar result = overloadCtx.tryOverload("(<>", new RuntimeArray(fileHandle)); + if (result != null) { + return result; + } + } + } + // Perl warns and returns undef for unopened filehandle, doesn't die WarnDie.warn(new RuntimeScalar("readline() on unopened filehandle"), new RuntimeScalar("\n")); return ctx == RuntimeContextType.LIST ? new RuntimeList() : scalarUndef; From ac320f568601f9d1f323d31aac0cb618f808d1aa Mon Sep 17 00:00:00 2001 From: Flavio Soibelmann Glock Date: Mon, 13 Apr 2026 15:00:58 +0200 Subject: [PATCH 2/2] docs: mark <> overload as implemented in feature matrix Generated with [Devin](https://cli.devin.ai/docs) Co-Authored-By: Devin <158243242+devin-ai-integration[bot]@users.noreply.github.com> --- docs/reference/feature-matrix.md | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/docs/reference/feature-matrix.md b/docs/reference/feature-matrix.md index e8e7c819e..59e4cadba 100644 --- a/docs/reference/feature-matrix.md +++ b/docs/reference/feature-matrix.md @@ -663,7 +663,8 @@ The `:encoding()` layer supports all encodings provided by Java's `Charset.forNa - ✅ Implemented: `<=>`, `cmp`, `<`, `<=`, `>`, `>=`, `==`, `!=`, `lt`, `le`, `gt`, `ge`, `eq`, `ne`. - ✅ Implemented: `qr`. - ✅ Implemented: `+=`, `-=`, `*=`, `/=`, `%=`. - - ❌ Missing: `++`, `--`, `=`, `<>`. + - ✅ Implemented: `<>`. + - ❌ Missing: `++`, `--`, `=`. - ❌ Missing: `&`, `|`, `^`, `~`, `<<`, `>>`, `&.`, `|.`, `^.`, `~.`, `x`, `.`. - ❌ Missing: `**=`, `<<=`, `>>=`, `x=`, `.=`, `&=`, `|=`, `^=`, `&.=`, `|.=`, `^.=`. - ❌ Missing: `-X`.