From 07dd3b414646384a259103e7a4b9e98f18da1307 Mon Sep 17 00:00:00 2001 From: Timm Friebe Date: Fri, 4 Oct 2024 19:28:00 +0200 Subject: [PATCH] Fix enclosing scopes when using references --- ChangeLog.md | 2 ++ src/main/php/lang/ast/emit/PHP.class.php | 16 +++++++-------- .../emit/ControlStructuresTest.class.php | 20 +++++++++++++++++++ 3 files changed, 30 insertions(+), 8 deletions(-) diff --git a/ChangeLog.md b/ChangeLog.md index 57b04c0f..ce98002c 100644 --- a/ChangeLog.md +++ b/ChangeLog.md @@ -3,6 +3,8 @@ XP Compiler ChangeLog ## ?.?.? / ????-??-?? +* Fixed enclosing scopes when using references - @thekid + ## 9.3.0 / 2024-08-31 * Fixed checks for property hooks emulation with asymmetric visibility diff --git a/src/main/php/lang/ast/emit/PHP.class.php b/src/main/php/lang/ast/emit/PHP.class.php index f4445bfe..85253045 100755 --- a/src/main/php/lang/ast/emit/PHP.class.php +++ b/src/main/php/lang/ast/emit/PHP.class.php @@ -125,7 +125,7 @@ protected function enclose($result, $node, $signature, $static, $emit) { $capture= []; foreach ($result->codegen->search($node, 'variable') as $var) { if (isset($result->locals[$var->pointer])) { - $capture[$var->pointer]= true; + $capture[$var->pointer]??= ($result->locals[$var->pointer] ? '&$' : '$').$var->pointer; } } unset($capture['this']); @@ -143,9 +143,9 @@ protected function enclose($result, $node, $signature, $static, $emit) { } if ($capture) { - $result->out->write('use($'.implode(', $', array_keys($capture)).')'); - foreach ($capture as $name => $_) { - $result->locals[$name]= true; + $result->out->write('use('.implode(', ', $capture).')'); + foreach ($capture as $name => $variable) { + $result->locals[$name]= '&' === $variable[0]; } } @@ -298,7 +298,7 @@ protected function emitArray($result, $array) { } protected function emitParameter($result, $parameter) { - $result->locals[$parameter->name]= true; + $result->locals[$parameter->name]= $parameter->reference; $parameter->annotations && $this->emitOne($result, $parameter->annotations); // If we have a non-constant default and a type, emit a nullable type hint @@ -340,7 +340,7 @@ protected function emitSignature($result, $signature, $use= null) { if ($use) { $result->out->write(' use('.implode(',', $use).') '); foreach ($use as $variable) { - $result->locals[substr($variable, 1)]= true; + $result->locals[ltrim($variable, '&$')]= '&' === $variable[0]; } } @@ -675,7 +675,7 @@ protected function emitProperty($result, $property) { protected function emitMethod($result, $method) { $locals= $result->locals; - $result->locals= ['this' => true]; + $result->locals= ['this' => false]; $meta= [ DETAIL_RETURNS => $method->signature->returns ? $method->signature->returns->name() : 'var', DETAIL_ANNOTATIONS => $method->annotations, @@ -798,7 +798,7 @@ protected function emitOffset($result, $offset) { protected function emitAssign($result, $target) { if ($target instanceof Variable && $target->const) { $result->out->write('$'.$target->pointer); - $result->locals[$target->pointer]= true; + $result->locals[$target->pointer]= false; } else if ($target instanceof ArrayLiteral) { $result->out->write('['); foreach ($target->values as $pair) { diff --git a/src/test/php/lang/ast/unittest/emit/ControlStructuresTest.class.php b/src/test/php/lang/ast/unittest/emit/ControlStructuresTest.class.php index c42344c4..81cb042b 100755 --- a/src/test/php/lang/ast/unittest/emit/ControlStructuresTest.class.php +++ b/src/test/php/lang/ast/unittest/emit/ControlStructuresTest.class.php @@ -211,4 +211,24 @@ public function run() { Assert::equals('one item', $r(1)); } + + #[Test] + public function match_block_inside_function_using_ref() { + $r= $this->run('class %T { + public function run() { + $test= "Original"; + (function() use(&$test) { + match (true) { + true => { + $test= "Changed"; + return true; + } + }; + })(); + return $test; + } + }'); + + Assert::equals('Changed', $r); + } } \ No newline at end of file