Skip to content

fix(compiler): convert Big* values by value into native int/float/bool slots - #138

Open
Giandonn wants to merge 1 commit into
swoole:masterfrom
Giandonn:fix/big-number-native-conversion
Open

Giandonn wants to merge 1 commit into
swoole:masterfrom
Giandonn:fix/big-number-native-conversion

Conversation

@Giandonn

@Giandonn Giandonn commented Oct 2, 2026

Copy link
Copy Markdown
Contributor

Fixes #137

A BigInt, BigFloat or Decimal value is a php::Box resource. When one reached a native int, float or bool slot, convertExprType() called convertFloatExpr() / convertIntExpr() / convertBoolExpr() without the source type, so the generic php::toFloat() / php::toInt() ran zval_get_double() / zval_get_long() on the resource and produced its handle. Since a float literal with 16+ fractional digits is recognized as a Decimal literal, ordinary PHP code hits this:

function takesFloat(float $x): float { return $x; }
takesFloat(0.123456789012345678);
// PHP:      float(0.12345678901234568)
// compiled: float(4)   <- the box resource handle

The change

  • convertExprType() forwards a Big* source type, so the existing per-type conversion (php::Decimal::toFloat() etc.) is used for arguments, typed returns and fixed native locals.
  • Those conversions return a php::Variant, which does not convert to a native C++ scalar, so the Big* branch of convertFloatExpr() / convertIntExpr() / convertBoolExpr() now unwraps it with php::toFloat() / php::toInt() / php::toBool(). Before, that branch only produced valid C++ where a Variant was accepted, which is why nothing exercised it for native slots.

Explicit ->toFloat() calls and Big* arithmetic are untouched.

Verified on a binary

PHP 8.4.26 ZTS with embed, GCC 11, Linux x64. New PHPT tests/compiler/bignumber/native-scalar-conversions.phpt (arguments of all three Big* types into float/int/bool, typed returns, a fixed native local):

master this PR
native-scalar-conversions.phpt FAIL: float(4), float(5), float(6), float(7), int(8), int(9), … PASS
tests/compiler/bignumber + tests/compiler/operator — 59/59 PASS
bigint, decimal, std-bigint, std-bigfloat, std-decimal, var_convert, type_decl, float_edge, universal_method, optimizations, function, functions — 169 PASS, 1 skipped (also skipped on master)
PHPUnit BigInt|BigFloat|Decimal|BigNumber|Conversion|Cast|TypedScalar|NativeScalar|NativeType — 58 tests OK

Not covered

A Decimal literal handed to a dynamic Zend context still stays a box (sprintf('%.5f', 0.123456789012345678) prints 10.00000; an array element holds resource(…) of type (php::box)). That is a separate decision about how auto-detected Decimal literals should behave outside native slots, so it is left out of this PR and noted in #137.

…l slots

BigInt, BigFloat and Decimal values are php::Box resources. When one of them
reached a native int, float or bool slot, convertExprType() called
convertFloatExpr()/convertIntExpr()/convertBoolExpr() without the source
type, so the generic php::toFloat()/php::toInt() ran zval_get_double() /
zval_get_long() on the resource and produced its handle:

    function takesFloat(float $x): float { return $x; }
    takesFloat(0.123456789012345678);   // Decimal literal (16+ digits)
    // PHP:      float(0.12345678901234568)
    // compiled: float(4)               <- the resource handle

The same happened for typed returns, assignments to fixed native locals,
std::decimal()/std::bigInt()/std::bigFloat() arguments, and int/bool slots.

convertExprType() now forwards a Big* source type, so the existing
per-type conversion is used. That conversion returns a php::Variant, which
does not convert to a native C++ scalar, so it is now unwrapped with
php::toFloat()/php::toInt()/php::toBool(); the Big* branch of those helpers
previously produced C++ that only compiled where a Variant was accepted.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

Big* values reaching a native int/float/bool slot become the box resource handle

1 participant