diff --git a/src/Parser/TypeConversionTrait.php b/src/Parser/TypeConversionTrait.php index 6312298d..b1a7c020 100644 --- a/src/Parser/TypeConversionTrait.php +++ b/src/Parser/TypeConversionTrait.php @@ -56,7 +56,8 @@ protected function convertIntExpr(string $expr, string $fromType = ''): string default => null, }; if ($bigConversion !== null) { - return $bigConversion . '(' . $expr . ')'; + // The Big* conversions return a php::Variant; unwrap it to the native scalar. + return 'php::toInt(' . $bigConversion . '(' . $expr . '))'; } if (!$this->isClosedExpr($expr, 'php::toInt')) { return 'php::toInt(' . $expr . ')'; @@ -74,7 +75,8 @@ protected function convertFloatExpr(string $expr, string $fromType = ''): string default => null, }; if ($bigConversion !== null) { - return $bigConversion . '(' . $expr . ')'; + // The Big* conversions return a php::Variant; unwrap it to the native scalar. + return 'php::toFloat(' . $bigConversion . '(' . $expr . '))'; } if (!$this->isClosedExpr($expr, 'php::toFloat')) { return 'php::toFloat(' . $expr . ')'; @@ -184,7 +186,8 @@ protected function convertBoolExpr(string $expr, string $fromType = ''): string default => null, }; if ($bigConversion !== null) { - return $bigConversion . '(' . $expr . ')'; + // The Big* conversions return a php::Variant; unwrap it to the native scalar. + return 'php::toBool(' . $bigConversion . '(' . $expr . '))'; } if (!$this->isClosedExpr($expr, 'php::toBool')) { return 'php::toBool(' . $expr . ')'; @@ -203,16 +206,25 @@ protected function convertConditionExpr(NodeAbstract $node, string $expr): strin return $this->convertBoolExpr($expr, $type); } + protected function bigNumberTypeOf(mixed $type): ?string + { + return in_array($type, [Type::BIGINT, Type::BIGFLOAT, Type::DECIMAL], true) ? $type : null; + } + protected function convertExprType(string $expr, $leftType, $rightType): string { + // A BigInt/BigFloat/Decimal operand is a php::Box resource. The generic + // php::toFloat()/php::toInt() would read its resource handle, so the + // conversion must go through the high-precision type itself. + $bigType = $this->bigNumberTypeOf($rightType) ?? $this->bigNumberTypeOf($leftType) ?? ''; if ($leftType === Type::FLOAT or $rightType === Type::FLOAT) { - return $this->convertFloatExpr($expr); + return $this->convertFloatExpr($expr, $bigType); } if ($leftType === Type::INT or $rightType === Type::INT) { - return $this->convertIntExpr($expr); + return $this->convertIntExpr($expr, $bigType); } if ($leftType === Type::BOOL or $rightType === Type::BOOL) { - return $this->convertBoolExpr($expr); + return $this->convertBoolExpr($expr, $bigType); } return $expr; diff --git a/tests/compiler/bignumber/native-scalar-conversions.phpt b/tests/compiler/bignumber/native-scalar-conversions.phpt new file mode 100755 index 00000000..59afa2c2 --- /dev/null +++ b/tests/compiler/bignumber/native-scalar-conversions.phpt @@ -0,0 +1,46 @@ +--TEST-- +BigInt/BigFloat/Decimal values convert by value (not by box resource handle) into native int/float/bool slots +--FILE-- + +--EXPECT-- +float(0.12345678901234568) +float(1.5) +float(42) +float(2.25) +int(42) +int(7) +bool(false) +bool(true) +float(0.12345678901234568) +int(42) +float(0.12345678901234568)