Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
434 commits
Select commit Hold shift + click to select a range
9ecdd80
Reprocess coalesce/ternary/match subjects on their narrowed scopes in…
ondrejmirtes Jun 26, 2026
93db202
Reprocess the foreach iteratee on the post-loop scope for value/key-t…
ondrejmirtes Jun 26, 2026
7a2021f
Narrow the pinned-name property fetch via applySpecifiedTypes, not fi…
ondrejmirtes Jun 26, 2026
d19e1de
Make specifyTypesCallback required and getSpecifiedTypesForScope non-…
ondrejmirtes Jun 26, 2026
d894c54
Narrow synthetic conditions via processExprOnDemand, not filterByTrut…
ondrejmirtes Jun 26, 2026
ae82c7c
Read wrapped operand types via getType/getNativeType in cast/clone/un…
ondrejmirtes Jun 27, 2026
2ae3433
Read child types via getType/getNativeType in post/pre-inc/dec, pipe,…
ondrejmirtes Jun 27, 2026
932c944
Read the ternary condition type via getType/getNativeType in the type…
ondrejmirtes Jun 27, 2026
803d230
Propagate the assigned value into byref-intertwined variables instead…
ondrejmirtes Jun 27, 2026
3982561
Read binary-op operands via getType/getNativeType in the type callback
ondrejmirtes Jun 27, 2026
cff7b4f
Read the left operand boolean via getType/getNativeType in boolean ty…
ondrejmirtes Jun 27, 2026
3ca756e
Resolve property fetch types without the asking scope
ondrejmirtes Jun 27, 2026
a685fe6
Resolve static property fetch types without the asking scope
ondrejmirtes Jun 27, 2026
1d99eac
Resolve method call return types without the asking scope
ondrejmirtes Jun 27, 2026
efd0002
Resolve static call return types without the asking scope
ondrejmirtes Jun 27, 2026
44d245b
Resolve function call return types without the asking scope
ondrejmirtes Jun 27, 2026
cc5190a
Resolve nullsafe fetch/call short-circuit types without the asking scope
ondrejmirtes Jun 27, 2026
e807c01
Read assignment and class-constant-fetch type callbacks via getType/g…
ondrejmirtes Jun 27, 2026
c492f0d
Read instanceof and coalesce type callbacks without the asking scope
ondrejmirtes Jun 27, 2026
24e139c
Read assign-op type callback without the asking scope
ondrejmirtes Jun 27, 2026
f3841fc
Pass the iteratee types into enterForeach instead of re-reading them
ondrejmirtes Jun 27, 2026
c8d7628
Pass the iteratee types into enterForeachKey instead of re-reading them
ondrejmirtes Jun 27, 2026
0ced7ff
Make the ExpressionResult typeCallback resolve from a native flag, no…
ondrejmirtes Jun 27, 2026
991f348
Require an ExpressionResult to have either a precomputed type or a ty…
ondrejmirtes Jun 27, 2026
2620c2a
Read the tracked holder directly in ExpressionResult, not via Scope::…
ondrejmirtes Jun 27, 2026
d09bc4f
Get rid of truthyScopeCallback and falseyScopeCallback
ondrejmirtes Jun 27, 2026
2e6dd71
Use the operand's own truthy/falsey scope for &&/|| narrowing
ondrejmirtes Jun 27, 2026
080797b
Record conditional holders from by-ref-updated variables via scope state
ondrejmirtes Jun 28, 2026
efc34ad
Derive statement exit points from never instead of findEarlyTerminati…
ondrejmirtes Jun 28, 2026
5e966bd
Narrower return type
ondrejmirtes Jun 29, 2026
57c15e9
Do not use getChildSpecifiedTypes
ondrejmirtes Jun 29, 2026
c48b6a6
Inline getSpecifiedTypesForScope instead of getChildSpecifiedTypes
ondrejmirtes Jun 30, 2026
2706ece
Keep getType for the dropped-self-condition complement
ondrejmirtes Jun 30, 2026
0e025ec
Add regression test for the type of a Closure::bind callback
ondrejmirtes Jun 30, 2026
1ee845c
Add regression test for array value type after foreach by-ref reassig…
ondrejmirtes Jun 30, 2026
f7a00be
Add regression test for list<non-empty-array> preserved after foreach…
ondrejmirtes Jun 30, 2026
ec294cd
Add regression test for ??= on a dynamic property array offset
ondrejmirtes Jun 30, 2026
b8a7298
Resolve ExpressionResult types from memoized per-flavour slots
ondrejmirtes Jul 2, 2026
4977c2a
Split readStoredOrPriceOnDemand into decisive primitives
ondrejmirtes Jul 2, 2026
8f0c911
Reintroduce readStoredResult as a storage-based assertion
ondrejmirtes Jul 2, 2026
32439d5
Narrow ?? by composing isset facts from chain results, not a syntheti…
ondrejmirtes Jul 2, 2026
a88fd29
Compose multi-subject isset() truthy narrowing from chain results
ondrejmirtes Jul 2, 2026
8b712a1
Consume the match arms' captured scope/type pairs instead of re-walki…
ondrejmirtes Jul 2, 2026
0a6983e
Answer plain variable reads from scope state instead of on-demand pro…
ondrejmirtes Jul 2, 2026
7043b41
Run AnalyserTest through FiberNodeScopeResolver like the other test h…
ondrejmirtes Jul 2, 2026
1599b3b
Resolve the offset-write property holder without re-reading the receiver
ondrejmirtes Jul 2, 2026
bc5892c
Answer maybe-stored reads from a tracked whole-expression holder with…
ondrejmirtes Jul 2, 2026
7bb3965
Skip the null-containment probe for bare variable narrowing subjects
ondrejmirtes Jul 3, 2026
b2e4087
Pin the dropped-self-condition complement type at holder-build time
ondrejmirtes Jul 3, 2026
cd60431
Compose createSubjectTypes entries from the result's own facts, never…
ondrejmirtes Jul 3, 2026
d2a4d6e
Collapse filterByTruthyValue/filterByFalseyValue onto applySpecifiedT…
ondrejmirtes Jul 3, 2026
470290d
Narrow match scopes via applySpecifiedTypes instead of filterBy*
ondrejmirtes Jul 3, 2026
965c365
Compute call narrowing on the evaluation scope, flavoured by the aski…
ondrejmirtes Jul 4, 2026
8ea385a
Compose null-identity narrowing from operand results in IdenticalNarr…
ondrejmirtes Jul 4, 2026
5273956
Narrow bool-literal identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 4, 2026
dd1795d
Narrow scalar-literal identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 4, 2026
6cc090b
Compose array_key_first-family null narrowing through the FuncCall co…
ondrejmirtes Jul 4, 2026
38a456a
Narrow get_class/get_debug_type identity comparisons in IdenticalNarr…
ondrejmirtes Jul 4, 2026
b012c94
Narrow gettype identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 4, 2026
9e43349
Narrow preg_match identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 4, 2026
8d668b8
Narrow strlen/mb_strlen identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
4689aee
Move count-size narrowing into CountNarrowingHelper
ondrejmirtes Jul 5, 2026
4bf9278
Narrow count/sizeof identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
9fe8149
Narrow string-function identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
8d2f751
Narrow trim and get_parent_class identity comparisons in IdenticalNar…
ondrejmirtes Jul 5, 2026
5285b28
Narrow ::class identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
356ba2a
Narrow general identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
a4b3b85
Compose function-family narrowing for type-based constant sides
ondrejmirtes Jul 5, 2026
4f49c1c
Narrow loose-equality comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
c1da2a3
Compose assign-time conditional holders from the assigned expression'…
ondrejmirtes Jul 5, 2026
5402695
Read assign-time ternary holder types from the captured walk results
ondrejmirtes Jul 5, 2026
6e36036
Extract conjunction narrowing into BooleanNarrowingHelper
ondrejmirtes Jul 5, 2026
0f842a5
Fold multi-subject isset narrowing through the conjunction helper
ondrejmirtes Jul 5, 2026
f67e08d
Extract disjunction narrowing into BooleanNarrowingHelper
ondrejmirtes Jul 5, 2026
2b98748
Share the single-subject isset narrowing in DefaultNarrowingHelper
ondrejmirtes Jul 5, 2026
01cf35c
Compose empty() narrowing through the disjunction helper
ondrejmirtes Jul 5, 2026
1fdb764
Compose ternary narrowing through the boolean helpers
ondrejmirtes Jul 5, 2026
56a3a06
Compose cast narrowing through the loose-equality helper
ondrejmirtes Jul 5, 2026
fb3352d
Read tracked foreach and @var types without synthetic pricing
ondrejmirtes Jul 5, 2026
fc1bf53
Capture call-argument results for the composed comparison narrowing
ondrejmirtes Jul 5, 2026
b10a1c2
Narrow bool-typed identity comparisons in IdenticalNarrowingHelper
ondrejmirtes Jul 5, 2026
75dc83e
Merge both directions of call-vs-call identity comparisons
ondrejmirtes Jul 5, 2026
7f6568a
Compose the last identity-comparison tails
ondrejmirtes Jul 5, 2026
4839aa9
Delete the old-world equality narrowing
ondrejmirtes Jul 5, 2026
2cb97c9
Key the closure type cache by the closure's actual inputs
ondrejmirtes Jul 5, 2026
de385ba
Read assign sentinel base result from the walk storage
ondrejmirtes Jul 5, 2026
77d0de5
Compose comparison verdicts from captured results instead of re-walking
ondrejmirtes Jul 5, 2026
582da03
Compose nullsafe method call null-removal from the receiver's stored …
ondrejmirtes Jul 5, 2026
39b7f49
Compose nullsafe property fetch null-removal from the receiver's stor…
ondrejmirtes Jul 5, 2026
e13f0c4
Compose variable-variable narrowing from the name expression's result
ondrejmirtes Jul 5, 2026
56bc4fc
Read by-ref destructuring item types from the scope directly
ondrejmirtes Jul 5, 2026
2b262b4
Compose match arm condition verdicts and narrowing from walk results
ondrejmirtes Jul 5, 2026
a451256
Use default narrowing directly for bool-variable contradiction probing
ondrejmirtes Jul 5, 2026
742e735
Compose single-condition match arm filtering verdicts from walk results
ondrejmirtes Jul 6, 2026
a2de5e1
Reuse the ensured-scope call result for the nullsafe maybe-null type
ondrejmirtes Jul 6, 2026
93d9130
Extract the coalesce type and falsey-narrowing composition into a helper
ondrejmirtes Jul 6, 2026
c0415b0
Compose ??= type and narrowing via the coalesce helper instead of syn…
ondrejmirtes Jul 6, 2026
1163143
Skip the synthetic constructor-call pricing when the return type cann…
ondrejmirtes Jul 6, 2026
806794c
Answer Scope::getType for a plain variable from scope state, not on d…
ondrejmirtes Jul 6, 2026
8590632
Prime the storage with argument results before dynamic function exten…
ondrejmirtes Jul 6, 2026
84fa161
Prime the storage for method and static call dynamic-return extension…
ondrejmirtes Jul 6, 2026
d88f58c
Revert "Answer Scope::getType for a plain variable from scope state, …
ondrejmirtes Jul 6, 2026
1b5bacd
Revert "Skip the synthetic constructor-call pricing when the return t…
ondrejmirtes Jul 6, 2026
e7943a5
Revert "Compose ??= type and narrowing via the coalesce helper instea…
ondrejmirtes Jul 6, 2026
1ef4ed6
Read narrowing subjects' current types from scope state, not on demand
ondrejmirtes Jul 6, 2026
a9dd57a
Derive non-nullability ensure types from scope state, not on demand
ondrejmirtes Jul 6, 2026
e238bb6
Derive narrowing-application base types from scope state, not on demand
ondrejmirtes Jul 6, 2026
c90893f
Keep void in typeCallbacks; project void to null at the value-read bo…
ondrejmirtes Jul 6, 2026
9f7f4a8
Push the walk's storage onto the scope-visible stack in processStmtNo…
ondrejmirtes Jul 6, 2026
74bfc1f
Move @phpstan-assert narrowing into DefaultNarrowingHelper, off TypeS…
ondrejmirtes Jul 6, 2026
368f1db
Move conditional-return-type narrowing into DefaultNarrowingHelper, o…
ondrejmirtes Jul 6, 2026
0647d6d
Finish the conditional-return-type move: remaining call sites + delet…
ondrejmirtes Jul 6, 2026
54b9134
Gate call-shaped narrowing subjects by reflection instead of walking …
ondrejmirtes Jul 6, 2026
45e2cff
Memoize the narrowing-application pricing pair per scope
ondrejmirtes Jul 6, 2026
1b71b92
Replace SpecifiedTypes::normalize() with symbolic alternative-form en…
ondrejmirtes Jul 6, 2026
9358a84
Defer boolean conditional-holder math to the application point
ondrejmirtes Jul 6, 2026
3d40492
Defer the either-branch union recovery to the application point
ondrejmirtes Jul 6, 2026
a2ce19d
Defer the disjunction holder projection to the application point
ondrejmirtes Jul 6, 2026
f71a5de
Compute disjunction decided-operand verdicts at the evaluation point
ondrejmirtes Jul 6, 2026
1163872
Compute comparison, coalesce and nullsafe-twin verdicts at the evalua…
ondrejmirtes Jul 6, 2026
df94147
Resolve isset/coalesce issetability verdicts on the evaluation scope
ondrejmirtes Jul 6, 2026
ed2aee5
Derive decomposition branch scopes from the evaluation point, not per…
ondrejmirtes Jul 6, 2026
2051c5e
Compose nullsafe narrowing from captured results instead of walking a…
ondrejmirtes Jul 6, 2026
2a8da34
Read isset chain-link types on the evaluation point
ondrejmirtes Jul 6, 2026
254676f
Memoize specify results per (context, flavour) at the evaluation point
ondrejmirtes Jul 6, 2026
a804a2a
Flip specifyTypesCallback to (TypeSpecifierContext, bool)
ondrejmirtes Jul 6, 2026
875bc57
Port the coalesce falsey-context gate to the composed narrowing
ondrejmirtes Jul 6, 2026
d2ccef2
Resolve boolean-decomposition branch scopes lazily
ondrejmirtes Jul 6, 2026
943c5f8
Flip createTypesCallback to (Type, TypeSpecifierContext, bool)
ondrejmirtes Jul 7, 2026
4e0fecf
Read match arm verdicts from the threaded per-arm state
ondrejmirtes Jul 7, 2026
a6d4db9
Answer foreign-position type asks from the scope's state uniformly
ondrejmirtes Jul 7, 2026
2b18f04
Read nullsafe receivers from before the enclosing ensure's device types
ondrejmirtes Jul 7, 2026
090a710
Release each file's captured results; drop dead filterBy* scope caches
ondrejmirtes Jul 7, 2026
1d8af07
Release resolved typeCallbacks, share the empty specify closure, move…
ondrejmirtes Jul 7, 2026
1d512d0
Process function and method bodies against a per-body result storage …
ondrejmirtes Jul 7, 2026
e3da6b3
Read ternary branch results on their processing scopes
ondrejmirtes Jul 7, 2026
4fce323
Expect the flavour-pure native type in the match arm always-true message
ondrejmirtes Jul 7, 2026
1d0a53e
Revert "Expect the flavour-pure native type in the match arm always-t…
ondrejmirtes Jul 7, 2026
649cede
Collect branch-union candidates from sureNot narrowings, skip templat…
ondrejmirtes Jul 7, 2026
3a5739b
Revert maybe-existing property promotion to its declared type
ondrejmirtes Jul 7, 2026
cad557c
Bind static to the named class when calling a static method through a…
ondrejmirtes Jul 7, 2026
f4be095
Strip the nullsafe short-circuit null from a static call's class-expr…
ondrejmirtes Jul 7, 2026
01f4576
Fan receiver-not-null through nullsafe chains from composed create ca…
ondrejmirtes Jul 7, 2026
12c47e7
Re-price stored results asked at a diverging variable position
ondrejmirtes Jul 7, 2026
4323629
Restore per-item array_map expectations lifted by counterfactual re-p…
ondrejmirtes Jul 7, 2026
eee1af2
Process the nullsafe receiver once and let the plain twin consume its…
ondrejmirtes Jul 7, 2026
55892c4
Exempt closures and arrow functions from the PHPSTAN_GUARD_NW pre-pro…
ondrejmirtes Jul 7, 2026
3b5e2d2
Exempt constant shapes and variable reads from the PHPSTAN_GUARD_NW g…
ondrejmirtes Jul 7, 2026
fad264e
Sanction deliberate before-the-walk reads under the PHPSTAN_GUARD_NW …
ondrejmirtes Jul 7, 2026
4fc30ce
Sanction closure-signature reads of parameter defaults and sibling ca…
ondrejmirtes Jul 7, 2026
fb5c867
Revert the PHPSTAN_GUARD_NW exemptions and sanctioned reads
ondrejmirtes Jul 7, 2026
afad6b3
Carry narrowing subjects' ExpressionResults into SpecifiedTypes
ondrejmirtes Jul 7, 2026
64aba32
Attach a result to its own narrowing entries as a weak subject reference
ondrejmirtes Jul 7, 2026
ba751b7
Consume or cache-price closure arguments in on-demand call re-walks
ondrejmirtes Jul 7, 2026
45b778b
Skip the synthetic constructor-call pricing when the return type cann…
ondrejmirtes Jul 6, 2026
bc3708a
Derive argument-less call subjects' narrowing base from reflection state
ondrejmirtes Jul 7, 2026
e47c403
Revert carrying narrowing subjects' ExpressionResults in SpecifiedTypes
ondrejmirtes Jul 7, 2026
8891add
Compose ??= from its child results like CoalesceHandler
ondrejmirtes Jul 7, 2026
d167878
Store the post-inc/dec synthetic's result before the virtual assign
ondrejmirtes Jul 7, 2026
a9d403d
Fabricate virtual assigned-expr results instead of pricing them on de…
ondrejmirtes Jul 7, 2026
7dea808
Add regression test for #14914
ondrejmirtes Jul 7, 2026
611a0b4
Add regression test for #14908
ondrejmirtes Jul 7, 2026
41dd2be
Add required lint version comments to bug-14914 and bug-14908 fixtures
ondrejmirtes Jul 7, 2026
3e161fc
Read the foreach iteratee off the scope instead of re-walking it
ondrejmirtes Jul 7, 2026
c5c0cbe
Compose the foreach non-empty-iteratee narrowing from the iteratee's …
ondrejmirtes Jul 7, 2026
2b13953
Compose switch case narrowing and read match/switch subjects off the …
ondrejmirtes Jul 7, 2026
0b11776
Read the coalesce left side off the left-is-set scope instead of re-w…
ondrejmirtes Jul 7, 2026
af6554a
Read the short-ternary condition off its truthy scope instead of re-w…
ondrejmirtes Jul 7, 2026
f58645b
Memoize flush-priced results for repeated rule asks
ondrejmirtes Jul 7, 2026
d037db9
Revert "Memoize flush-priced results for repeated rule asks"
ondrejmirtes Jul 7, 2026
d1a9e54
Build closure/arrow call-arg types from the single body walk
ondrejmirtes Jul 9, 2026
bc38540
Select the per-argument metadata acceptor only where its resolution i…
ondrejmirtes Jul 9, 2026
9e3f373
Make pass-local storages scope-visible and consume loop condition res…
ondrejmirtes Jul 9, 2026
4832011
Memoize the generator check per function-like node
ondrejmirtes Jul 9, 2026
a05eafc
Answer stored fiber asks without suspending
ondrejmirtes Jul 9, 2026
c2a3f52
Answer invalidation checks from a per-holder index of contained node …
ondrejmirtes Jul 9, 2026
9181bce
Memoize flush-priced answers for repeated rule asks
ondrejmirtes Jul 9, 2026
2169ccb
Create merge conditionals from the differing holders only
ondrejmirtes Jul 9, 2026
c29cba1
Skip loop verification passes whose entry scope did not change
ondrejmirtes Jul 9, 2026
f428d92
Batch type specifications into one scope copy per application
ondrejmirtes Jul 9, 2026
8b849f6
Run engine-feeding node-callback gatherers synchronously at the emiss…
ondrejmirtes Jul 9, 2026
05b4fae
Align the isset verdict gate with 2.2.x and pin null in falsey isset …
ondrejmirtes Jul 9, 2026
f087002
Store the assign-target property fetch's pre-assign result for parked…
ondrejmirtes Jul 9, 2026
32910e3
Price closure parameter defaults without a scope walk
ondrejmirtes Jul 9, 2026
372a84b
Create the function call's impure point after its arguments are proce…
ondrejmirtes Jul 9, 2026
424cb65
Restore the Array_ import dropped when replaying onto the ScopeOps ex…
ondrejmirtes Jul 16, 2026
723d9dc
Update test expectations after the rebase onto 2.2.x
ondrejmirtes Jul 16, 2026
0be539d
Remove the superseded ScopeOps invalidation helpers after the rebase
ondrejmirtes Jul 16, 2026
6361ec5
Answer invalidation checks from ScopeOps again
ondrejmirtes Jul 16, 2026
2a8477d
Sync the turbo native twins with the single-pass engine's shadowed cl…
ondrejmirtes Jul 16, 2026
574250a
Pin turbo extension version to cac4327
ondrejmirtes Jul 16, 2026
a8ce64b
Resolve the call return type once per call
ondrejmirtes Jul 16, 2026
0e624e1
Complete the stored preliminary call result in place instead of overw…
ondrejmirtes Jul 16, 2026
45e300c
Walk closure by-ref convergence passes in deep statement context
ondrejmirtes Jul 16, 2026
8005ebf
Drop unnecessary ?? null on always-set parameter types
ondrejmirtes Jul 22, 2026
6be9e76
Fix use-statement order left by the rebase auto-merge
ondrejmirtes Jul 22, 2026
8e4a47f
Price an offset read on never as ErrorType in the narrowing-base reader
ondrejmirtes Jul 28, 2026
56f1544
Avoid the nullsafe operator - simple-downgrader passes it through
ondrejmirtes Jul 28, 2026
6a83c53
Use ExtensionsCollection in ExpressionResult and tag PerFileAnalysisR…
ondrejmirtes Jul 28, 2026
80446f5
Construct name checks from extensions collections in ClassConstantPhp…
ondrejmirtes Jul 28, 2026
55852a2
Bump expected turbo version
ondrejmirtes Jul 28, 2026
07263fc
Restore the default-value gate in the isset verdict
ondrejmirtes Jul 28, 2026
473269b
Complete the callable-union parameter merge in createCallableParameters
ondrejmirtes Jul 28, 2026
0b54274
Bump expected turbo version
ondrejmirtes Jul 28, 2026
3419826
Absorb the upstream TypeSpecifierTest additions after the rebase
ondrejmirtes Jul 28, 2026
5229108
Drop the upstream toSureTypes copy that flowed into the holder helper
ondrejmirtes Jul 28, 2026
87ce290
Bump expected turbo version
ondrejmirtes Jul 28, 2026
6a2b33e
Drop the upstream duplicate of the differingKeys smoke block
ondrejmirtes Jul 28, 2026
924c054
Split processAssignVar into prepareTarget and applyWrite
ondrejmirtes Jul 28, 2026
cb2b86a
Produce the assignment target's read result inside prepareTarget
ondrejmirtes Jul 28, 2026
9449383
Pass the assigned value's result into applyWrite instead of pre-stori…
ondrejmirtes Jul 28, 2026
65557d5
Compose the ??= read from the walked target instead of a second walk
ondrejmirtes Jul 29, 2026
cc4c446
Compose target reads from handler composition methods, thread operand…
ondrejmirtes Jul 30, 2026
aa53945
Thread more in-hand results through the assignment narrowing and writ…
ondrejmirtes Jul 30, 2026
d86cd8b
Bump expected turbo version
ondrejmirtes Jul 30, 2026
237b5ff
Remove the ISSET_DEBUG diagnostic leftover
ondrejmirtes Jul 30, 2026
7046d7b
Emit SwitchConditionNode from the branch's switch processing
ondrejmirtes Jul 30, 2026
79c1c92
Walk the dynamic variable name once in prepareTarget
ondrejmirtes Jul 30, 2026
4fcfe6c
Reference the original chain in ExistingArrayDimFetch, drop the clone…
ondrejmirtes Jul 30, 2026
db9321a
Derive simulated-call throw points directly instead of walking synthe…
ondrejmirtes Jul 30, 2026
2462286
Resolve offsetGet and __toString return types directly
ondrejmirtes Jul 30, 2026
e2afaa3
Thread captured results through the remaining call-handler reads
ondrejmirtes Jul 30, 2026
b9eb2d9
Thread dynamic name and class results through fetch and call typeCall…
ondrejmirtes Jul 30, 2026
1ee8e20
Make the remaining handler type readers explicit about synthetic pricing
ondrejmirtes Jul 30, 2026
0267367
Delete findStoredResult and split readTypeOfMaybeStored's state fast …
ondrejmirtes Jul 30, 2026
ef020a2
Convert tracked-holder reads to readScopeStateOrSyntheticType
ondrejmirtes Jul 30, 2026
36b712b
Capture comparison-specify subresults at creation instead of the storage
ondrejmirtes Jul 30, 2026
778aa68
Drop captures and parameters orphaned by the maybe-stored elimination
ondrejmirtes Jul 30, 2026
1c34f46
Restore ??= right-side-scope tests dropped in rebase
ondrejmirtes Jul 30, 2026
8a8e731
Narrow the right side of ??= with falsey isset() semantics
ondrejmirtes Jul 30, 2026
c58325b
Resolve the native flavour of closure parameters through parameter cl…
ondrejmirtes Jul 30, 2026
344739e
Bump expected turbo version
ondrejmirtes Jul 30, 2026
ade71bd
Let the compositional-key shortcut clear virtual-node keys
ondrejmirtes Jul 30, 2026
87fb7d6
Bump expected turbo version
ondrejmirtes Jul 30, 2026
9fe9a3e
Drop the per-holder contained-node-keys invalidation index
ondrejmirtes Jul 30, 2026
a91dfef
Bump expected turbo version
ondrejmirtes Jul 30, 2026
176c3dd
Replace WeakMaps with spl_object_id-keyed arrays and a node attribute
ondrejmirtes Jul 30, 2026
7113817
Do not extend Expr in the call and nullsafe rule-facing virtual nodes
ondrejmirtes Jul 30, 2026
dcc8a51
Bump expected turbo version
ondrejmirtes Jul 30, 2026
cc31792
Gate the antecedent-swap on truthy narrowing equivalent to the truth
ondrejmirtes Jul 31, 2026
0a8def2
Bump expected turbo version
ondrejmirtes Jul 31, 2026
7303c9f
Remove test methods duplicated by the rebase
ondrejmirtes Jul 31, 2026
0925435
Conjoin alternative-form entries in SpecifiedTypes::unionWith()
ondrejmirtes Aug 4, 2026
db5aef2
Bump expected turbo version
ondrejmirtes Aug 4, 2026
b264802
Drop the cache-seeding call that flowed in from the upstream rebase
ondrejmirtes Aug 11, 2026
9266090
Construct VirtualAssignNodeCallback through its factory
ondrejmirtes Aug 11, 2026
9601a53
Do not narrow the falsey branch of a nested isset() at its intermedia…
ondrejmirtes Aug 11, 2026
9b005b3
Do not treat conditional-expression entries about a property fetch as…
ondrejmirtes Aug 11, 2026
934ff43
Bump expected turbo version
ondrejmirtes Aug 11, 2026
44a5b71
Add regression tests for #14999 and #13334
ondrejmirtes Aug 11, 2026
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
42 changes: 9 additions & 33 deletions phpstan-baseline.neon
Original file line number Diff line number Diff line change
Expand Up @@ -24,6 +24,12 @@ parameters:
count: 3
path: src/Analyser/ExprHandler/AssignHandler.php

-
rawMessage: Casting to string something that's already string.
identifier: cast.useless
count: 3
path: src/Analyser/ExprHandler/Helper/ConditionalExpressionHolderHelper.php

-
rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantStringType is error-prone and deprecated. Use Type::getConstantStrings() instead.'
identifier: phpstanApi.instanceofType
Expand All @@ -36,40 +42,22 @@ parameters:
count: 2
path: src/Analyser/ExprHandler/BinaryOpHandler.php

-
rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantBooleanType is error-prone and deprecated. Use Type::isTrue() or Type::isFalse() instead.'
identifier: phpstanApi.instanceofType
count: 1
path: src/Analyser/ExprHandler/BooleanNotHandler.php

-
rawMessage: 'Doing instanceof PHPStan\Type\ConstantScalarType is error-prone and deprecated. Use Type::isConstantScalarValue() or Type::getConstantScalarTypes() or Type::getConstantScalarValues() instead.'
identifier: phpstanApi.instanceofType
count: 2
path: src/Analyser/ExprHandler/Helper/EqualityTypeSpecifyingHelper.php

-
rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantBooleanType is error-prone and deprecated. Use Type::isTrue() or Type::isFalse() instead.'
identifier: phpstanApi.instanceofType
count: 3
path: src/Analyser/ExprHandler/Helper/EqualityTypeSpecifyingHelper.php

-
rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantStringType is error-prone and deprecated. Use Type::getConstantStrings() instead.'
identifier: phpstanApi.instanceofType
count: 2
path: src/Analyser/ExprHandler/IssetHandler.php
path: src/Analyser/ExprHandler/Helper/DefaultNarrowingHelper.php

-
rawMessage: 'Only numeric types are allowed in pre-increment, float|int|string|null given.'
identifier: preInc.nonNumeric
count: 1
path: src/Analyser/ExprHandler/PreIncHandler.php
path: src/Analyser/ExprHandler/Helper/IncDecTypeHelper.php

-
rawMessage: Casting to string something that's already string.
identifier: cast.useless
count: 1
count: 4
path: src/Analyser/MutatingScope.php

-
Expand Down Expand Up @@ -114,18 +102,6 @@ parameters:
count: 1
path: src/Analyser/RuleErrorTransformer.php

-
rawMessage: Casting to string something that's already string.
identifier: cast.useless
count: 2
path: src/Analyser/ScopeOps.php

-
rawMessage: 'Doing instanceof PHPStan\Type\Constant\ConstantBooleanType is error-prone and deprecated. Use Type::isTrue() or Type::isFalse() instead.'
identifier: phpstanApi.instanceofType
count: 2
path: src/Analyser/TypeSpecifier.php

-
rawMessage: 'Template type TNodeType is declared as covariant, but occurs in contravariant position in parameter node of method PHPStan\Collectors\Collector::processNode().'
identifier: generics.variance
Expand Down
19 changes: 17 additions & 2 deletions src/Analyser/ArgsResult.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,26 +2,41 @@

namespace PHPStan\Analyser;

use PhpParser\Node\Expr;
use PHPStan\Reflection\ParametersAcceptor;
use function spl_object_id;

/**
* Result of NodeScopeResolver::processArgs(): the scope/throw/impure state after
* processing all arguments (wrapped ExpressionResult) plus the ParametersAcceptor
* resolved from the arg types gathered on the arg-to-arg evolving scope. The
* resolved acceptor is type-driven (selectFromTypes) so its generics are resolved
* against the actual argument types - callers wire it into the call's return
* type. Null when the call had no variants (dynamic callee).
* against the actual argument types - callers wire it into the call expression's
* stored return type. Null when the call had no variants (dynamic callee).
*/
final class ArgsResult
{

/**
* @param array<int, ExpressionResult> $argResults keyed by spl_object_id of each argument's value expression
*/
public function __construct(
private ExpressionResult $expressionResult,
private ?ParametersAcceptor $resolvedParametersAcceptor,
private array $argResults = [],
)
{
}

/**
* The already-processed ExpressionResult of a call argument's value expression,
* so callers read its type via the result instead of re-asking the scope.
*/
public function getArgResult(Expr $argValue): ?ExpressionResult
{
return $this->argResults[spl_object_id($argValue)] ?? null;
}

public function getScope(): MutatingScope
{
return $this->expressionResult->getScope();
Expand Down
4 changes: 2 additions & 2 deletions src/Analyser/ConditionalExpressionHolderRecipe.php
Original file line number Diff line number Diff line change
Expand Up @@ -44,7 +44,7 @@ public function evaluate(MutatingScope $scope): array
// dropped-self-condition complement below
$conditionOriginalTypes = [];
foreach ($this->conditionEntries as [$exprString, $expr, $fromSureTypes, $type]) {
$scopeType = $scope->getType($expr);
$scopeType = $scope->getStateType($expr);
$conditionType = $fromSureTypes
? TypeCombinator::remove($scopeType, $type)
: TypeCombinator::intersect($scopeType, $type);
Expand Down Expand Up @@ -81,7 +81,7 @@ public function evaluate(MutatingScope $scope): array
continue;
}

$targetType = $pinnedTargetType ?? $scope->getType($expr);
$targetType = $pinnedTargetType ?? $scope->getStateType($expr);
$holderType = $this->holdersFromSureTypes
? TypeCombinator::intersect($targetType, $type)
: TypeCombinator::remove($targetType, $type);
Expand Down
30 changes: 13 additions & 17 deletions src/Analyser/DirectInternalScopeFactory.php
Original file line number Diff line number Diff line change
Expand Up @@ -20,6 +20,8 @@
final class DirectInternalScopeFactory implements InternalScopeFactory
{

private ExpressionResultStorageStack $expressionResultStorageStack;

/**
* @param int|array{min: int, max: int}|null $configPhpVersion
* @param callable(Node $node, Scope $scope): void|null $nodeCallback
Expand All @@ -40,8 +42,10 @@ public function __construct(
private $nodeCallback,
private ConstantResolver $constantResolver,
private bool $fiber = false,
?ExpressionResultStorageStack $expressionResultStorageStack = null,
)
{
$this->expressionResultStorageStack = $expressionResultStorageStack ?? new ExpressionResultStorageStack();
}

public function create(
Expand Down Expand Up @@ -79,6 +83,7 @@ public function create(
$this->propertyReflectionFinder,
$this->parser,
$this->constantResolver,
$this->expressionResultStorageStack,
$context,
$this->phpVersion,
$this->attributeReflectionFactory,
Expand All @@ -104,25 +109,15 @@ public function create(

public function toFiberFactory(): InternalScopeFactory
{
return new self(
$this->container,
$this->reflectionProvider,
$this->initializerExprTypeResolver,
$this->expressionTypeResolverExtensions,
$this->exprPrinter,
$this->typeSpecifier,
$this->propertyReflectionFinder,
$this->parser,
$this->phpVersion,
$this->attributeReflectionFactory,
$this->configPhpVersion,
$this->nodeCallback,
$this->constantResolver,
true,
);
return $this->withFlavor(true);
}

public function toMutatingFactory(): InternalScopeFactory
{
return $this->withFlavor(false);
}

private function withFlavor(bool $fiber): self

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

should this read withFiber?

{
return new self(
$this->container,
Expand All @@ -138,7 +133,8 @@ public function toMutatingFactory(): InternalScopeFactory
$this->configPhpVersion,
$this->nodeCallback,
$this->constantResolver,
false,
$fiber,
$this->expressionResultStorageStack,
);
}

Expand Down
8 changes: 5 additions & 3 deletions src/Analyser/DisjunctionBranchUnionAugment.php
Original file line number Diff line number Diff line change
Expand Up @@ -3,6 +3,7 @@
namespace PHPStan\Analyser;

use PhpParser\Node\Expr;
use PHPStan\Analyser\ExprHandler\Helper\DefaultNarrowingHelper;
use PHPStan\Type\Type;
use PHPStan\Type\TypeCombinator;
use PHPStan\Type\TypeUtils;
Expand All @@ -23,7 +24,8 @@ final class DisjunctionBranchUnionAugment implements DeferredSpecifiedTypesAugme
* @param list<array{Expr, Type, Type}> $candidates [target expr, left branch type, right branch type]
*/
public function __construct(
private TypeSpecifier $typeSpecifier,
private NodeScopeResolver $nodeScopeResolver,
private DefaultNarrowingHelper $defaultNarrowingHelper,
private array $candidates,
)
{
Expand All @@ -38,7 +40,7 @@ public function evaluate(MutatingScope $scope): ?SpecifiedTypes
}

// the guard above pins the target as tracked on the applying scope
$originalType = $scope->getType($targetExpr);
$originalType = $this->nodeScopeResolver->readScopeStateOrSyntheticType($targetExpr, $scope);
// re-pinning eagerly priced branch forms of a template-typed subject
// stacks the template inside its own bound (`T of T of ...` - the
// pin intersects with the declared template); its narrowing already
Expand All @@ -62,7 +64,7 @@ public function evaluate(MutatingScope $scope): ?SpecifiedTypes
continue;
}

$created = $this->typeSpecifier->create($targetExpr, $unionType, TypeSpecifierContext::createTrue(), $scope);
$created = $this->defaultNarrowingHelper->createForSubject($targetExpr, $unionType, TypeSpecifierContext::createTrue(), $scope);
$result = $result === null ? $created : $result->unionWith($created);
}

Expand Down
23 changes: 15 additions & 8 deletions src/Analyser/DisjunctionHolderProjectionAugment.php
Original file line number Diff line number Diff line change
Expand Up @@ -2,6 +2,7 @@

namespace PHPStan\Analyser;

use PHPStan\Analyser\ExprHandler\Helper\DefaultNarrowingHelper;
use PHPStan\Type\TypeCombinator;
use function array_key_first;

Expand Down Expand Up @@ -29,7 +30,8 @@ final class DisjunctionHolderProjectionAugment implements DeferredSpecifiedTypes
* be added on top
*/
public function __construct(
private TypeSpecifier $typeSpecifier,
private NodeScopeResolver $nodeScopeResolver,
private DefaultNarrowingHelper $defaultNarrowingHelper,
private $leftTruthyScope,
private MutatingScope $leftFalseyScope,
private $rightTruthyScope,
Expand Down Expand Up @@ -69,19 +71,24 @@ public function evaluate(MutatingScope $scope): ?SpecifiedTypes
}
$leftTruthyScope ??= ($this->leftTruthyScope)();
$rightTruthyScope ??= ($this->rightTruthyScope)();
if (!$leftTruthyScope->hasExpressionType($targetExpr)->yes()) {
continue;
}
if (!$rightTruthyScope->hasExpressionType($targetExpr)->yes()) {
continue;
}

// the guard above pins the target as tracked on the applying
// scope; the branch scopes are its own filtered views, so their
// reads answer from state (or price the same tracked state)
$origType = $scope->getType($targetExpr);
// the guards above pin the target as tracked on all three scopes -
// scope state answers without a walk
$origType = $this->nodeScopeResolver->readScopeStateOrSyntheticType($targetExpr, $scope);

$leftType = $leftTruthyScope->getType($targetExpr);
$leftType = $this->nodeScopeResolver->readScopeStateOrSyntheticType($targetExpr, $leftTruthyScope);
$leftNarrowed = !$leftType->equals($origType) && $origType->isSuperTypeOf($leftType)->yes();
if (!$leftNarrowed) {
continue;
}

$rightType = $rightTruthyScope->getType($targetExpr);
$rightType = $this->nodeScopeResolver->readScopeStateOrSyntheticType($targetExpr, $rightTruthyScope);
$rightNarrowed = !$rightType->equals($origType) && $origType->isSuperTypeOf($rightType)->yes();
if (!$rightNarrowed) {
continue;
Expand All @@ -92,7 +99,7 @@ public function evaluate(MutatingScope $scope): ?SpecifiedTypes
continue;
}

$created = $this->typeSpecifier->create($targetExpr, $unionType, TypeSpecifierContext::createTrue(), $scope);
$created = $this->defaultNarrowingHelper->createSubjectTypes($scope, $targetExpr, null, $unionType, TypeSpecifierContext::createTrue());
$result = $result === null ? $created : $result->unionWith($created);
}
}
Expand Down
16 changes: 0 additions & 16 deletions src/Analyser/ExprHandler.php
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,6 @@
use PhpParser\Node\Expr;
use PhpParser\Node\Stmt;
use PHPStan\DependencyInjection\ExtensionInterface;
use PHPStan\Type\Type;

/**
* @template T of Expr
Expand Down Expand Up @@ -34,19 +33,4 @@ public function processExpr(
ExpressionContext $context,
): ExpressionResult;

/**
* @param T $expr
*/
public function resolveType(MutatingScope $scope, Expr $expr): Type;

/**
* @param T $expr
*/
public function specifyTypes(
TypeSpecifier $typeSpecifier,
Scope $scope,
Expr $expr,
TypeSpecifierContext $context,
): SpecifiedTypes;

}
Loading
Loading