fix(compiler): unbox runtime modulo results

master
韩天峰 3 weeks ago
parent f50f41e811
commit a6cd47b8dc
  1. 2
      phpunit/src/TypedScalarArithmeticCodegenTest.php
  2. 14
      src/Parser/BinaryOpTrait.php
  3. 45
      tests/compiler/object_property/runtime-mod-int-property-assignment.phpt

@ -23,7 +23,7 @@ final class TypedScalarArithmeticCodegenTest extends \BaseTest
{
$code = $this->compileFixture();
self::assertStringContainsString('php::fn::mod(a, b)', $code);
self::assertStringContainsString('php::toInt(php::fn::mod(a, b))', $code);
self::assertStringNotContainsString('((a) % (b))', $code);
}

@ -143,17 +143,21 @@ trait BinaryOpTrait
}
if ($op === '%') {
if (!($leftType === Type::INT and $rightType === Type::INT)) {
return 'php::fn::mod(' . $leftExpr . ', ' . $rightExpr . ')';
}
$requiresRuntimeModulo = $leftType !== Type::INT || $rightType !== Type::INT;
// varint_types retains PHP's catchable modulo errors and
// PHP_INT_MIN % -1 behavior. Native integers use raw C++ rules.
if ($this->varIntTypes
if (!$requiresRuntimeModulo
&& $this->varIntTypes
&& !$this->isExplicitNativeArithmeticExpr($left)
&& !$this->isExplicitNativeArithmeticExpr($right)
&& $this->evaluateConstantIntArithmetic($left, $right, '%') === null
) {
return 'php::fn::mod(' . $leftExpr . ', ' . $rightExpr . ')';
$requiresRuntimeModulo = true;
}
if ($requiresRuntimeModulo) {
return $this->convertIntExpr(
'php::fn::mod(' . $leftExpr . ', ' . $rightExpr . ')',
);
}
}

@ -0,0 +1,45 @@
--TEST--
Runtime modulo result can be assigned to an optimized int property
--FILE--
<?php
namespace RuntimeModuloNamespace {
final class Cursor
{
private array $items = [];
private int $selected = 5;
public function refresh(callable $provider): void
{
$this->items = $provider();
}
public function move(): void
{
$count = count($this->items);
$this->selected = $this->selected % $count;
}
public function selected(): int
{
return $this->selected;
}
}
}
namespace {
function main(): void
{
$cursor = new RuntimeModuloNamespace\Cursor();
$cursor->refresh(fn(): array => [1, 2]);
$cursor->move();
var_dump($cursor->selected());
}
}
?>
--EXPECT--
int(1)
Loading…
Cancel
Save