Repository navigation
Subtract a union from plain mixed at once and build comparison forms once per node - #6972
Closed
ondrejmirtes wants to merge 3 commits into
Closed
ondrejmirtes wants to merge 3 commits into
ondrejmirtes wants to merge 3 commits into
Conversation
Removing a union from mixed peeled its members one at a time, and every step rebuilt the growing subtracted union. Plain mixed minus a union is mixed with that union subtracted, so subtract it in one step. The comparison types (getSmallerType() and friends) build exactly that, and since floats narrow into ranges their subtracted unions carry NAN and a float range as well. Amp-Thread-ID: https://ampcode.com/threads/T-01a1b134-f541-75cc-9cd3-8f0206f0ec3f
Resolving a comparison and specifying its types each built the equivalent and complementary forms again and printed every one of them to look it up in the scope. Keep the forms with their printed keys in the comparison node's attributes and read the scope's holders by key. Amp-Thread-ID: https://ampcode.com/threads/T-01a1b134-f541-75cc-9cd3-8f0206f0ec3f
Merging the cached equivalent and complement forms on every lookup built a new array each time, and reading them from the node attribute left array_merge() without a list type. Store the forms followed by their complements next to the plain forms and return one of the two. Amp-Thread-ID: https://ampcode.com/threads/T-01a1b134-f541-75cc-9cd3-8f0206f0ec3f
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.
This makes the analysis of
tests/bench/data/bug-6265.php,bug-12159.phpandbug-14869.phpcheaper again after two recent commits made them slower. Inferred types and reported errors are unchanged.Cause
getSmallerType(),getGreaterOrEqualType(), … onIntegerRangeTypeandConstantNumericComparisonTypeTrait, and the false branch inBinaryOpHandler) buildTypeCombinator::remove(new MixedType(), <union>), and their unions now also holdNANand aFloatRangeType.TypeCombinator::doRemove()removed such a union frommixedone member at a time, and every step went throughMixedType::subtract(), which rebuilt the growing subtracted union withTypeCombinator::union(). In an xdebug profile of bug-12159,remove()went from 57 M to 134 M units.===,!==,==,!=,<,<=,>,>=#6948): every===,!==,==,!=,<,<=,>and>=built 2–6 new form nodes twice, once when resolving its type and once inspecifyTypes. Each lookup withhasExpressionType()printed these nodes through the pretty printer, because new nodes have no cached print.Changes
Each PHP change is mirrored in its turbo-ext C++ twin in the same commit.
TypeCombinator::doRemove()): when the type is exactlyMixedTypewith no subtracted type and the removed type is exactly aUnionType, the result is$fromType->subtract($union), built once. The condition is deliberately narrow. Letting everymixedremove a union at once changed a type description innsrt/mixed-subtract.php(array<mixed, mixed>becamearray<mixed>). With the narrow condition, a temporary check over the whole test suite compared the result with the member-by-member result (equals()plusprecise()andcache()descriptions) and found no difference.BinaryOpHandler): the forms and their printed keys are kept in aphpstan_comparison_formsattribute on the comparison node. The cache is checked against the node's class and its left and right operands, because attributes are copied to new nodes. The scope holders are then read by key fromMutatingScope::$expressionTypeswith the same certainty-yes check. The "integer operands" guard on the complement forms is unchanged.Overlap with another change
5247de4 ("Subtract a union from plain mixed at once") overlaps with 762a3d716 "Remove a union from mixed by subtracting its members at once" (f23d802 after its rebase, branch
bug-15061-isset-fold, Amp thread T-01a1b134-ed02-7078-a72e-a1e527d957a3). Both change howTypeCombinator::doRemove()removes a union frommixed. Whichever lands second gets rebased onto the other.Measurements
Net instruction counts: cachegrind over one
BenchCase::runAnalyse()of the file, minus the same for an empty file, after two warm-up runs. This is the PHP implementation with OPcache off. Base is origin/2.3.x bcca2b0; the branch is 2c7e7f7.Wall clock:
bin/phpstan analyse -c <config> --debug --no-progress -q tests/bench/data/<file>.tests/bench/phpstan.neondoes not exist, so the config was a temporary one mirroringBenchCase:conf/bleedingEdge.neonpluslevel: max, with a separatetmpDirper side. The result cache was cleared before every run. There were 28 base/branch pairs, run alternately, and the first 3 pairs were dropped as warm-up, so each median is over 25 runs per side. No turbo extension was loaded. The machine is an Amp orb (Intel Xeon @ 2.60 GHz, 16 vCPUs) running PHP 8.4.27 NTS, with OPcache enabled and JIT disabled by PHPStan's restart. The times were taken on b3adc67, before the follow-up commit.On this machine the wall-clock difference is within noise: the paired differences of the three files are about the same as the −17 ms of the empty file, and the run-to-run spread is around ±50 ms. Counting instructions under
bin/phpstan(OPcache on, children traced) also gave a drop of the same size as the table above. That measurement varies by about 0.1 G between runs, because the CLI does timing-dependent work, so it is not reported here.Tests
make tests(paratest, 23472 tests) passes without the turbo extension, and with it loaded throughPHP_INI_SCAN_DIR. Reflection confirmed the nativeTypeCombinator::doRemove()andBinaryOpHandler::createComparisonForms()were active.make WARN_FLAGS="$(make -s print-warn-flags)"),tests/smoke.php(ALL OK),tests/signature-parity.php(OK), andtests/walk-trace.php(identical, 700329 trace lines).bin/side-by-side.phpreports nothing for the changed classes. On this PHP 8.4 build it reports the same 59 "stale" generated headers on clean 2.3.x as on this branch, which come from renderingself.make cs(phpcs) passes, andbin/phpstan analyse -c build/phpstan.neonon the two changed PHP files is clean.