From e345b0d82ad33f614370bfe9bb1c597ce48349bf Mon Sep 17 00:00:00 2001 From: tianfenghan Date: Sun, 2 Aug 2026 19:15:15 +0800 Subject: [PATCH] fix(decimal): optimize integer to decimal conversion without string intermediate - Changed integer to decimal conversion from php::toDecimal(php::toString(expr)) to direct php::toDecimal(expr) - Added test case to verify decimal integer operand does not convert through string - Created new test file decimal-int-operand.php to test decimal multiplication with integer operands - Added phpt test for decimal multiplication accepting Int and dynamically typed Int operands - Fixed type conversion trait to handle INT type directly without string conversion --- .../code/big-numeric/decimal-int-operand.php | 22 ++++++++++++++++ phpunit/src/BigNumericValidationTest.php | 25 +++++++++++++++++++ src/Parser/TypeConversionTrait.php | 2 +- ...int-operand-without-string-conversion.phpt | 22 ++++++++++++++++ 4 files changed, 70 insertions(+), 1 deletion(-) create mode 100644 phpunit/code/big-numeric/decimal-int-operand.php create mode 100644 tests/compiler/decimal/int-operand-without-string-conversion.phpt diff --git a/phpunit/code/big-numeric/decimal-int-operand.php b/phpunit/code/big-numeric/decimal-int-operand.php new file mode 100644 index 00000000..06bb2c41 --- /dev/null +++ b/phpunit/code/big-numeric/decimal-int-operand.php @@ -0,0 +1,22 @@ +toString(); +} + +function multiplyDecimalByVar($factor): string +{ + $value = std::decimal('123.456'); + $value = $value * $factor; + return $value->toString(); +} + +function main(): void +{ + echo multiplyDecimalByInt(1000), "\n"; + echo multiplyDecimalByVar(1000), "\n"; +} diff --git a/phpunit/src/BigNumericValidationTest.php b/phpunit/src/BigNumericValidationTest.php index e02aae0e..95841307 100644 --- a/phpunit/src/BigNumericValidationTest.php +++ b/phpunit/src/BigNumericValidationTest.php @@ -2,6 +2,31 @@ class BigNumericValidationTest extends \BaseTest { + public function testDecimalIntegerOperandDoesNotConvertThroughString(): void + { + global $translator; + $compiler = \TypePhp\CompilerTest::create(ROOT_PATH); + $translator = $compiler; + $testFile = __DIR__ . '/../code/big-numeric/decimal-int-operand.php'; + $compiler->addFiles([$testFile]); + $compiler->prepareFile($testFile); + $cppFile = $compiler->convertFile($testFile); + $cpp = file_get_contents($cppFile); + + $this->assertStringContainsString( + 'php::Decimal::mul(value, php::toDecimal(1000L))', + $cpp, + ); + $this->assertStringNotContainsString( + 'php::toDecimal(php::toString(1000L))', + $cpp, + ); + $this->assertStringContainsString( + 'php::Decimal::mul(value, factor)', + $cpp, + ); + } + public function testDecimalPowerOperatorIsRejected(): void { $this->exec("Operator '**' is not supported for Decimal or BigFloat", 'big-numeric/decimal-pow-operator.php'); diff --git a/src/Parser/TypeConversionTrait.php b/src/Parser/TypeConversionTrait.php index 1180e05d..be20056a 100644 --- a/src/Parser/TypeConversionTrait.php +++ b/src/Parser/TypeConversionTrait.php @@ -85,7 +85,7 @@ trait TypeConversionTrait return 'php::toDecimal(php::toString(' . $expr . '))'; } if ($fromType === Type::INT) { - return 'php::toDecimal(php::toString(' . $expr . '))'; + return 'php::toDecimal(' . $expr . ')'; } if ($fromType === Type::BIGINT) { return 'php::toDecimal(php::BigInt::toString(' . $expr . '))'; diff --git a/tests/compiler/decimal/int-operand-without-string-conversion.phpt b/tests/compiler/decimal/int-operand-without-string-conversion.phpt new file mode 100644 index 00000000..8e71685f --- /dev/null +++ b/tests/compiler/decimal/int-operand-without-string-conversion.phpt @@ -0,0 +1,22 @@ +--TEST-- +Decimal multiplication accepts Int and dynamically typed Int operands +--FILE-- +toString(); +} + +function main(): void +{ + $value = std::decimal('123.456'); + echo ($value * 1000)->toString(), "\n"; + echo multiplyDecimal(1000), "\n"; +} +?> +--EXPECT-- +123456.000 +123456.000