Repository navigation
Settle the conditional targets before deriving the guards - #6428
Merged
Merged
Conversation
Collaborator
|
You've opened the pull request against the latest branch 2.3.x. PHPStan 2.3 is not going to be released for months. If your code is relevant on 2.2.x and you want it to be released sooner, please rebase your pull request and change its target to 2.2.x. |
createConditionalExpressions() derived a guard for every differing key, and since the guard type became the branch set difference that costs a TypeCombinator::remove() of the two branch types - the most expensive step of a merge. A guard is only ever consumed paired with a target: a different key in the first target loop, any key in the second. So the targets are settled first with the cheap checks, the merge returns early when no key can be one, and the subtraction is skipped for a guard whose only possible target is its own key, which the target loop unsets from its own guard set anyway. The first target loop reuses the settled set instead of repeating the checks. Analysing Slevomat: 603.1s -> 591.6s user CPU, with byte-identical output. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01LDqrN1pcN3qWc7xzKfkJaF
ondrejmirtes
force-pushed
the
conditional-guard-target-perf
branch
from
September 12, 2026 15:18
e2c6601 to
bff769c
Compare
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.
createConditionalExpressions()derives a guard for every differing key, and since the guard type became the branch set difference (#6394) that costs aTypeCombinator::remove()of the two branch types — the most expensive step of a merge. On Slevomat that is 422,500 subtraction calls from this one function, 21.96s of CPU.A guard is only ever consumed paired with a target: a different key in the first target loop, any key in the second. So the targets are settled first using only the cheap checks, the merge returns early when no key can be one, and the subtraction is skipped for a guard whose only possible target is its own key — which the target loop unsets from its own guard set anyway. The first target loop then reuses the settled set instead of repeating the same three checks.
Mirrored in
turbo-ext/src/ScopeOps.cpp, with the version bump in the follow-up commit.Measurements
Analysing Slevomat, turbo on, forward+reverse passes to cancel session drift:
93c49a1b95(before the set-difference guards)0f5817a75d(after)Output is byte-identical, on Slevomat and on ShipMonk.
The remainder above the pre-#6394 baseline is the feature's genuine cost — the extra conditional expressions the sharper guards create, and the subtractions that do produce a usable guard. A companion PR against 2.2.x (#6427) attacks the subtraction itself; the two are not additive, since this one already skips most of those calls.
Verification
tests/PHPStan/Analyser,tests/PHPStan/Type,tests/PHPStan/Rulesgreentests/PHPStan/Analysergreen again with the extension loaded, so both twins agreeturbo-ext/tests/smoke.phpandturbo-ext/bin/side-by-side.phppass🤖 Generated with Claude Code
https://claude.ai/code/session_01LDqrN1pcN3qWc7xzKfkJaF