Repository navigation
Compute operators and loose comparison on value sets - #6957
Merged
Merged
Conversation
…er and strings The always-equal values of a scalar no longer come from testing a fixed list of candidate values. null and the booleans follow its truthiness, the numbers its number, and the strings are its own, its number's and the falsy ones, printed independently of the precision ini settings. The numbers that can equal a number type are read from its toNumberSet() instead of instanceof checks on the integer and float types. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
Every type now describes its values as a ValueSet: null, the booleans, a NumberSet of numbers, constant strings and the other strings, arrays by emptiness, objects and resources. A union of types is the union of their sets, an intersection their intersection. getPossiblyLooselyEqualType() and getAlwaysLooselyEqualType() are computed on the ValueSet, so the per-type dispatch in LooseComparisonHelper is gone; it keeps the comparison of two values and the PHP version helpers. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
The operand handling of +, -, *, /, intdiv, %, **, negation and the bitwise operators moves from OperatorTypeHelper and ExponentiateHelper onto ValueSet and NumberSet. Types describe themselves through toValueSet() (invalid, unknown, never, arrays, benevolent) and the OperatorTypeTrait methods delegate to it. ExponentiateHelper is removed; OperatorTypeHelper keeps only concatenation and array union. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
The value set every Type::toValueSet() returns, with the arithmetic, bitwise and loose-equality computations on it, is implemented natively in ValueSet.cpp. LooseComparisonHelper stays PHP and is called from it. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
ValueSet keeps its strings as a StringSet: the constant strings plus the type of the other strings. The . operator concatenates the strings the values cast to, and the strings of numbers keep what their type cannot say: they never end in whitespace, and those of non-negative integers are digits only. A numeric left side thus stays numeric after digits whatever produced them, and after a decimal integer string a fraction or exponent keeps it numeric. A never operand gives never, as it does for the arithmetic operators. The native mirror is StringSet.cpp. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
OperatorTypeTrait::arrayUnion() unions the arrays itself, the last operator OperatorTypeHelper computed, which is removed. Its native body moves to OperatorTypeTrait.cpp. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
PhpVersions::getLooseComparisonVersions() lists the versions whose loose comparison semantics differ; numeric string parsing moves to StringSet. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
The main process peaks at 428 MB on 2.3.x and already runs out of the 450M limit on Windows. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
The PHP 7.4 downgrade does not transform ?->, and PHP 8.5 warns when casting NAN to bool. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
Handlers passed to reg::Class::method() need ZEND_FASTCALL, which is __vectorcall on Windows, and MSVC has no __builtin_*_overflow. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
AcceptsResult: :or() takes a single operand. Spreading every member into it dropped all but the first in PHP, and the native AcceptsResult::or() rejected the call when Turbo trusts PHPStan's own types. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
zend_is_true() warns on NAN on PHP 8.5, like the (bool) cast in PHP. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
A benevolent array<string>|string, such as str_replace() of mixed, concatenates as its strings again, as Type::toString() of a BenevolentUnionType leaves out what cannot be cast. Amp-Thread-ID: https://ampcode.com/threads/T-01a1a1e7-5e72-7235-a4b2-ba1b689f7e1b
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.
Moves the remaining operator and loose comparison logic out of
OperatorTypeHelperandLooseComparisonHelperinto polymorphic value sets, and deletes both helpers (andExponentiateHelper).Type::toValueSet()on every type describes the values it holds: null/false/true, numbers (NumberSet), strings (StringSet), arrays, objects, resources, plus unknown/benevolent/invalid flags.UnionTypeunions member sets,IntersectionTypeintersects them.getPossiblyLooselyEqual,getAlwaysLooselyEqual,looseCompare) is computed onValueSet. Constant folding of==and<=>isValueSet::compareScalarValues(), with the versions to compare under fromPhpVersions::getLooseComparisonVersions().%,intdiv,& | ^, negation and**are onNumberSet, alongside+ - * / << >>. Operand handling (arrays/objects error,neverabsorbs,mixedgives benevolentint|float) is onValueSet.StringSet, which tracks constant strings, a type for the rest, anddigits/whitespaceFreeflags that decide whether numeric-string survives.+lives inOperatorTypeTrait.ValueSet,NumberSetandStringSetare shadowed by native Turbo mirrors in the same commits.Behaviour changes (concatenation only):
neveroperand in.givesnever(bcmath-number.phpline 387, two write-only-property errors gone fromTypesAssignedToPropertiesRuleTest);decimal-int-string . <float or numeric>andint|null . <digits>keep numeric-string.The other commits are pure refactors: a dump of all operator and loose-equality results over a catalog of ~120 types on PHP 7.4/8.0/8.4 is byte-identical before and after each of them, with Turbo on and off (the only earlier difference:
neverpossibly-equalsneverinstead ofmixed).Verified: full test suite with and without Turbo, self-analysis identical with Turbo on/off, operator fuzzer on all 11 PHP versions with Turbo on/off,
side-by-side.php,smoke.php,signature-parity.php,make lint-turbo.Closes phpstan/phpstan#15388