fix(compiler): make numeric string arithmetic match PHP semantics - #136
Open
alwaysLinger wants to merge 1 commit into
Open
alwaysLinger wants to merge 1 commit into
alwaysLinger wants to merge 1 commit into
Conversation
…heir arithmetic matches PHP semantics across all modes
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
问题
同一算术表达式,数字串字面量形态与变量形态行为不一致——变量形态正确,字符串形态偏离:
PHP 手册规定:纯十进制整数且在 int64 范围内的数字串("5"、"10")按 int 参与算术,其余数字串("1e2"、"1.5")按 float。此偏离不在官方不兼容清单内。
根因
三条路径都未把数字串字面量当作数值操作数:
src/CompilerBase.phpdetectTypeOfExpr()算术分支,一侧为原生 Int 时无条件返回Type::INT——赋值目标被声明为php::Int槽位,double 值写入即截断。src/CompilerBase.phpparseNumericIdentifier()用(string) floatval("1e2")转换数字串,得到"100"(无小数点),发出的 C++ 是整型字面量。src/Parser/BinaryOpTrait.phpconstantNumericValue()不处理Node\Scalar\String_,字符串派生的常量绕过溢出检查与折叠。修复
isIntNumericString()/isFloatNumericString()(src/Parser/TypeDetectionTrait.php):is_numeric+ 纯整数语法正则 + int64 范围检查,与 PHP 数字串分类语义一致。detectTypeOfExpr():一侧为浮点数字串时,+ - * / **结果提升为Type::FLOAT(%/移位/位运算排除);varint 模式下整型语法数字串视同 int 操作数参与常量求值。parseNumericIdentifier():浮点数字串经仓库现有shortestFloatRepr()发射,保留 C++ double 形态(1e+2);溢出为 INF 时退回运行时字符串路径。constantNumericValue():读取数字串字面量(整型语法 → intval,其余有限数字串 → floatval)。现有常量溢出防护因此覆盖字符串常量:native 模式下"9223372036854775807" * 2与 int 字面量写法一致地被编译期拒绝;varint 模式下折叠为 PHP float。行为变化
"9223372036854775807" * 2从“编译通过、运行时未定义行为”变为编译期拒绝——与 int 字面量写法一致。"5" / 2从int(2)修正为float(2.5)(官方文档 varint_types 职责:“溢出转浮点与小数除法”)。"9223372036854775807" * 2从运行时崩溃(ValueError: Invalid BigInt numeric string)修复为精确 BigInt 运算。保持不变
"10" / 2 → int(5)、"5" + 1 → int(6)——逐字节与修复前一致。$f = "1e2"; $f / 3)原本正确,未触碰。%/移位/位运算不涉及。验证
Linux x86-64 Docker,PHP 8.4.26 NTS,GCC:
php基准逐字节对拍(含大写E、负指数、.5/5.、首尾空白、INF、int64 边界、幂/比较/移位/位运算/复合赋值),native 与 varint 双模式,-O0/-O2/-O3一致;use bigint_types独立对拍:修复前运行时崩溃、修复后精确 BigInt。tests/compiler/{operator,basic,std-array,class}188 项无新增失败(唯一失败pow-int-overflow在未修改基线上同样失败,为容器precision=14环境差异);全量 phpunit 2409 项仅 2 例失败(容器缺 python3,基线相同)。