fix(optimizer): preserve typed builtin argument validation - #18
Conversation
matyhtf
left a comment
There was a problem hiding this comment.
Thank you for the thorough investigation and for preserving the whole-call fallback path. The original mixed argument issue is real, and this PR fixes that case in the right direction.
I found two remaining correctness issues in hasOptimizerSafeTypedArguments() that need to be addressed before merging:
- Treating every Native scalar-to-scalar conversion as safe is too broad.
declare(strict_types=1);
function typedInt(): int
{
return 1;
}
in_array('1', [1], typedInt());Zend throws a TypeError, but this PR emits php::toBool(...) and returns false. A declared Native return type does not make a cross-type conversion valid for an internal function. The fast path should normally require an exact type, with only explicitly proven Zend-compatible widening such as int -> float; otherwise the whole call should fall back to Zend dispatch.
- Literal
nullcannot be accepted unconditionally.
declare(strict_types=1);
strlen(null);Zend throws a TypeError, while this PR emits php::toString(php::null) and returns 0. Please use the reflected nullable metadata when deciding whether null is safe. If a particular wrapper intentionally accepts null as a legacy/default policy, that exception should be explicit per function/parameter rather than globally applied.
I reproduced both differences by compiling the PR head and comparing the resulting executable with Zend PHP. These are implementation issues rather than requests for additional test coverage.
The macOS PHP 8.5 CI failure appears unrelated: Composer failed because Packagist DNS resolution timed out. The remaining CI jobs passed.
1dae4c2 to
5d38a73
Compare
|
Addressed both blocking points in
I removed Verification on the revised head:
Fresh CI is running. The local full stdlib run is documented in the PR body, including the installed PHPX 2.6.7 vs current-master 2.6.8 boundary. |
5d38a73 to
9f6e31c
Compare
Summary
int -> floatwidening; fall back the whole call for all other runtime scalar conversionsnullonly for parameters marked nullable by Reflection, including selected custom handlersInvariant
An optimizer must not erase the runtime zval type before an internal function has applied its parameter contract. A direct ABI call is valid only when the compiler proves that its conversion has the same accepted/rejected behavior as Zend; otherwise all arguments remain on the ordered
php::call()path.This fixes strict calls such as a
mixedor declaredintresult passed toin_array()'s boolean parameter being coerced by generated C++ instead of raising the sameTypeErroras Zend. It also prevents non-nullable calls such asstrlen(null)from being lowered to a permissive C++ conversion.Coverage
string,int,float,bool, andarrayABI parametersint -> floatwidening remain direct;int/float/boolcross-conversions otherwise fall backnullremains direct; non-nullable and optional-but-non-nullablenullfalls backarray_keys,array_key_exists,round,count,define, andfunction_exists)round()and nativeCountablebranches remain ahead of the shared guardThe existing
null_optional_arg.phptnow declares strict types and distinguishes nullable parameters such assubstr()length from optional but non-nullable parameters such as offsets and boolean flags.Verification
array_keys, lookup calls,func_get_arg, and two Decimalround()paths)The previous CI run passed 11/12 jobs; the sole macOS PHP 8.5 failure was a Packagist DNS timeout, as noted in review. A fresh CI run is in progress for this revision. Non-MSVC native artifacts were not run locally.