From 59f07227c40d80a3cc901e16fa982160bb4a0e2f Mon Sep 17 00:00:00 2001 From: "Flavio S. Glock" Date: Wed, 26 Aug 2026 18:56:24 +0200 Subject: [PATCH] fix: preserve references in utf8 downgrade Treat utf8::downgrade on references as Perl's successful no-op instead of stringifying and overwriting the reference. This restores HTTP::Message content callback handling. Closes #1117 Generated with [Codex](https://openai.com/codex/) Co-Authored-By: Codex --- docs/about/changelog.md | 1 + .../perlonjava/runtime/perlmodule/Utf8.java | 8 +++++++ .../unit/utf8_downgrade_references.t | 23 +++++++++++++++++++ 3 files changed, 32 insertions(+) create mode 100644 src/test/resources/unit/utf8_downgrade_references.t diff --git a/docs/about/changelog.md b/docs/about/changelog.md index d1746669a..9247d1ab1 100644 --- a/docs/about/changelog.md +++ b/docs/about/changelog.md @@ -7,6 +7,7 @@ Release history of PerlOnJava. See [Roadmap](roadmap.md) for future plans. - Fix localization of numbered regex captures. - Fix IO-handle type checks and uninitialized-value warning locations. - Fix numeric-zero results from failed `s///` substitutions. +- Preserve references in `utf8::downgrade`. - Bundle the complete CPAN `File::Path` 2.18 implementation, including modern `rmtree`/`remove_tree` options such as `keep_root`, `error`, `result`, `safe`, and `verbose`. diff --git a/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java b/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java index 9f6ce336a..fe15f351d 100644 --- a/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java +++ b/src/main/java/org/perlonjava/runtime/perlmodule/Utf8.java @@ -172,6 +172,14 @@ public static RuntimeList downgrade(RuntimeArray args, int ctx) { RuntimeScalar scalar = args.get(0); boolean wasTainted = GlobalContext.isTaintModeActive() && scalar.isTainted(); boolean failOk = args.size() == 2 && args.get(1).getBoolean(); + + // References do not have a UTF-8 flag. Perl treats downgrade() on a + // reference as a successful no-op; converting it through toString() + // would replace the reference with its stringified form. + if (RuntimeScalarType.isReference(scalar)) { + return RuntimeScalarCache.scalarTrue.getList(); + } + String string = scalar.toString(); // Check if the string can be represented in ISO-8859-1 diff --git a/src/test/resources/unit/utf8_downgrade_references.t b/src/test/resources/unit/utf8_downgrade_references.t new file mode 100644 index 000000000..60246d424 --- /dev/null +++ b/src/test/resources/unit/utf8_downgrade_references.t @@ -0,0 +1,23 @@ +use strict; +use warnings; +use Test::More; + +my $scalar = 'value'; +my $object = bless {}, 'Local::Downgrade::Object'; +my @references = ( + [ CODE => sub { 42 } ], + [ ARRAY => [] ], + [ HASH => {} ], + [ SCALAR => \$scalar ], + [ 'Local::Downgrade::Object' => $object ], +); + +for my $case (@references) { + my ($expected_type, $value) = @$case; + is(utf8::downgrade($value, 1), 1, "downgrade succeeds for $expected_type reference"); + is(ref($value), $expected_type, "downgrade preserves $expected_type reference"); +} + +is($references[0][1]->(), 42, 'downgrade preserves a callable code reference'); + +done_testing;