-
Notifications
You must be signed in to change notification settings - Fork 583
Single-pass expression analysis groundwork - answer type questions from ExpressionResults #5857
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Open
ondrejmirtes
wants to merge
408
commits into
2.2.x
Choose a base branch
from
resolve-type-rewrite-2
base: 2.2.x
Could not load branches
Branch not found: {{ refName }}
Loading
Could not load tags
Nothing to show
Loading
Are you sure you want to change the base?
Some commits from the old base branch may be removed from the timeline,
and old review comments may become outdated.
Open
Changes from all commits
Commits
Show all changes
408 commits
Select commit
Hold shift + click to select a range
f33f668
Compute Closure::bind's bound scope from its processed arguments
ondrejmirtes ef54dee
Fix PHPStan self-analysis errors in NodeScopeResolver
ondrejmirtes cb40e4e
Read impossible-check narrowing from the call's ExpressionResult
ondrejmirtes b047de2
Gate the processArgs fast path on parameter late-resolvability only
ondrejmirtes 5c68683
Don't route curl_setopt(_array) through the metadata pre-pass
ondrejmirtes 7b5058f
Don't route implode/join through the metadata pre-pass
ondrejmirtes 5715d68
Supply array_map's callback parameter type via a closure-type extension
ondrejmirtes b1e1cbf
Supply array_filter/walk/find callback parameter types via closure-ty…
ondrejmirtes e7b0a2a
Read array_walk's original array type after its argument is processed
ondrejmirtes 5f879a3
Make Closure::bind/bindTo single-pass; drop the empty argsHaveIntrins…
ondrejmirtes eb2e745
Resolve single-variant generic acceptors incrementally so they are si…
ondrejmirtes bc115c4
Select multi-variant acceptors by argument count so processArgs is si…
ondrejmirtes 74be7f2
Deduplicate constant-condition vs impossible-check reports via collec…
ondrejmirtes 7c6af95
Process a dynamic function-call name before reading its type
ondrejmirtes e806ecb
Process a nested array-dimension before reading its type in AssignHan…
ondrejmirtes 7028f9a
Process an assign-op Variable/property target as a read before compos…
ondrejmirtes ee15448
Process Closure::call's new-$this argument before reading its type
ondrejmirtes 40acb8c
Process clone()'s arguments before reading them in clone-with handling
ondrejmirtes 1939fca
Evaluate an array-dim assignment's value before reading its type
ondrejmirtes 6922c27
Read the foreach value variable's narrowed type by name in the loop a…
ondrejmirtes 1ad22d8
Carry the nullsafe receiver type to its rule via a virtual node
ondrejmirtes b51ae6a
Drop the dead Expr parameter from ExpressionResult's typeCallback
ondrejmirtes 3abc935
Build pre-inc/dec literal types via ConstantTypeHelper, not the scope
ondrejmirtes 140c80b
Resolve lexical context once at create()-time in three type callbacks
ondrejmirtes fb25d6c
Resolve the instanceof Name class type once at create()-time
ondrejmirtes 6d76513
Reprocess the switch subject for the exhaustiveness check instead of …
ondrejmirtes 0e3f0f4
Reprocess the foreach iteratee and while condition on their narrowed …
ondrejmirtes bd9c469
Reprocess coalesce/ternary/match subjects on their narrowed scopes in…
ondrejmirtes 5065ca7
Reprocess the foreach iteratee on the post-loop scope for value/key-t…
ondrejmirtes 792d949
Narrow the pinned-name property fetch via applySpecifiedTypes, not fi…
ondrejmirtes 7b56e0b
Make specifyTypesCallback required and getSpecifiedTypesForScope non-…
ondrejmirtes 632f8a8
Narrow synthetic conditions via processExprOnDemand, not filterByTrut…
ondrejmirtes b099fc2
Read wrapped operand types via getType/getNativeType in cast/clone/un…
ondrejmirtes 0883c8b
Read child types via getType/getNativeType in post/pre-inc/dec, pipe,…
ondrejmirtes 7dab191
Read the ternary condition type via getType/getNativeType in the type…
ondrejmirtes 861d128
Propagate the assigned value into byref-intertwined variables instead…
ondrejmirtes bbb7020
Read binary-op operands via getType/getNativeType in the type callback
ondrejmirtes e86cf12
Read the left operand boolean via getType/getNativeType in boolean ty…
ondrejmirtes ed3f5c2
Resolve property fetch types without the asking scope
ondrejmirtes 7e73016
Resolve static property fetch types without the asking scope
ondrejmirtes d8b3928
Resolve method call return types without the asking scope
ondrejmirtes 8826030
Resolve static call return types without the asking scope
ondrejmirtes cec32f3
Resolve function call return types without the asking scope
ondrejmirtes 2fc79f4
Resolve nullsafe fetch/call short-circuit types without the asking scope
ondrejmirtes 2fcd8b0
Read assignment and class-constant-fetch type callbacks via getType/g…
ondrejmirtes a8fbea4
Read instanceof and coalesce type callbacks without the asking scope
ondrejmirtes 476985f
Read assign-op type callback without the asking scope
ondrejmirtes 9eb7e3b
Pass the iteratee types into enterForeach instead of re-reading them
ondrejmirtes 8d3d039
Pass the iteratee types into enterForeachKey instead of re-reading them
ondrejmirtes 85ce228
Make the ExpressionResult typeCallback resolve from a native flag, no…
ondrejmirtes 5369fe8
Require an ExpressionResult to have either a precomputed type or a ty…
ondrejmirtes c3d53a6
Read the tracked holder directly in ExpressionResult, not via Scope::…
ondrejmirtes 473d346
Get rid of truthyScopeCallback and falseyScopeCallback
ondrejmirtes 44640be
Use the operand's own truthy/falsey scope for &&/|| narrowing
ondrejmirtes 55475ad
Record conditional holders from by-ref-updated variables via scope state
ondrejmirtes ea1c466
Derive statement exit points from never instead of findEarlyTerminati…
ondrejmirtes 110efa3
Narrower return type
ondrejmirtes 3c9d3d1
Do not use getChildSpecifiedTypes
ondrejmirtes 19ac231
Inline getSpecifiedTypesForScope instead of getChildSpecifiedTypes
ondrejmirtes ca27627
Keep getType for the dropped-self-condition complement
ondrejmirtes e5c4091
Add regression test for the type of a Closure::bind callback
ondrejmirtes 9193045
Add regression test for array value type after foreach by-ref reassig…
ondrejmirtes 375a4e1
Add regression test for list<non-empty-array> preserved after foreach…
ondrejmirtes 75222d4
Add regression test for ??= on a dynamic property array offset
ondrejmirtes 17c332d
Resolve ExpressionResult types from memoized per-flavour slots
ondrejmirtes 5ce5c20
Split readStoredOrPriceOnDemand into decisive primitives
ondrejmirtes 065a4aa
Reintroduce readStoredResult as a storage-based assertion
ondrejmirtes 66cd0e5
Narrow ?? by composing isset facts from chain results, not a syntheti…
ondrejmirtes ce046a4
Compose multi-subject isset() truthy narrowing from chain results
ondrejmirtes ca211cd
Consume the match arms' captured scope/type pairs instead of re-walki…
ondrejmirtes df1473b
Answer plain variable reads from scope state instead of on-demand pro…
ondrejmirtes 3be9f3e
Run AnalyserTest through FiberNodeScopeResolver like the other test h…
ondrejmirtes e8a88e3
Resolve the offset-write property holder without re-reading the receiver
ondrejmirtes 62ae594
Answer maybe-stored reads from a tracked whole-expression holder with…
ondrejmirtes 2c86dec
Skip the null-containment probe for bare variable narrowing subjects
ondrejmirtes 12fa7a9
Pin the dropped-self-condition complement type at holder-build time
ondrejmirtes 1bdd850
Compose createSubjectTypes entries from the result's own facts, never…
ondrejmirtes 3bf1e4b
Collapse filterByTruthyValue/filterByFalseyValue onto applySpecifiedT…
ondrejmirtes fea541c
Narrow match scopes via applySpecifiedTypes instead of filterBy*
ondrejmirtes 2e9667c
Compute call narrowing on the evaluation scope, flavoured by the aski…
ondrejmirtes 6f80e81
Compose null-identity narrowing from operand results in IdenticalNarr…
ondrejmirtes 0dfcda7
Narrow bool-literal identity comparisons in IdenticalNarrowingHelper
ondrejmirtes c0c8790
Narrow scalar-literal identity comparisons in IdenticalNarrowingHelper
ondrejmirtes ca98ac6
Compose array_key_first-family null narrowing through the FuncCall co…
ondrejmirtes 48f5fec
Narrow get_class/get_debug_type identity comparisons in IdenticalNarr…
ondrejmirtes 9d7d36c
Narrow gettype identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 539aee4
Narrow preg_match identity comparisons in IdenticalNarrowingHelper
ondrejmirtes ffb6b2b
Narrow strlen/mb_strlen identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 3c74556
Move count-size narrowing into CountNarrowingHelper
ondrejmirtes a537718
Narrow count/sizeof identity comparisons in IdenticalNarrowingHelper
ondrejmirtes cc8a299
Narrow string-function identity comparisons in IdenticalNarrowingHelper
ondrejmirtes ec76c04
Narrow trim and get_parent_class identity comparisons in IdenticalNar…
ondrejmirtes bc0e542
Narrow ::class identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 7718a2e
Narrow general identity comparisons in IdenticalNarrowingHelper
ondrejmirtes a9766d9
Compose function-family narrowing for type-based constant sides
ondrejmirtes 5399276
Narrow loose-equality comparisons in IdenticalNarrowingHelper
ondrejmirtes 7d80939
Compose assign-time conditional holders from the assigned expression'…
ondrejmirtes 6d17726
Read assign-time ternary holder types from the captured walk results
ondrejmirtes 06e4f73
Extract conjunction narrowing into BooleanNarrowingHelper
ondrejmirtes 69ded03
Fold multi-subject isset narrowing through the conjunction helper
ondrejmirtes 87df97d
Extract disjunction narrowing into BooleanNarrowingHelper
ondrejmirtes d79eefb
Share the single-subject isset narrowing in DefaultNarrowingHelper
ondrejmirtes 755b54b
Compose empty() narrowing through the disjunction helper
ondrejmirtes 7935192
Compose ternary narrowing through the boolean helpers
ondrejmirtes f3b4c54
Compose cast narrowing through the loose-equality helper
ondrejmirtes 8a7ef3f
Read tracked foreach and @var types without synthetic pricing
ondrejmirtes b4b462b
Capture call-argument results for the composed comparison narrowing
ondrejmirtes bfb9ec6
Narrow bool-typed identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 0776bb6
Merge both directions of call-vs-call identity comparisons
ondrejmirtes 21cf27c
Compose the last identity-comparison tails
ondrejmirtes 4f295f6
Delete the old-world equality narrowing
ondrejmirtes d866cb9
Key the closure type cache by the closure's actual inputs
ondrejmirtes 3917dff
Read assign sentinel base result from the walk storage
ondrejmirtes 08191ae
Compose comparison verdicts from captured results instead of re-walking
ondrejmirtes 5d463eb
Compose nullsafe method call null-removal from the receiver's stored …
ondrejmirtes 19db366
Compose nullsafe property fetch null-removal from the receiver's stor…
ondrejmirtes b5dbeb6
Compose variable-variable narrowing from the name expression's result
ondrejmirtes fcea771
Read by-ref destructuring item types from the scope directly
ondrejmirtes 1519e97
Compose match arm condition verdicts and narrowing from walk results
ondrejmirtes 71b5aa0
Use default narrowing directly for bool-variable contradiction probing
ondrejmirtes 1f457ec
Compose single-condition match arm filtering verdicts from walk results
ondrejmirtes 65ca584
Reuse the ensured-scope call result for the nullsafe maybe-null type
ondrejmirtes 04e56f6
Extract the coalesce type and falsey-narrowing composition into a helper
ondrejmirtes 2a9b09d
Compose ??= type and narrowing via the coalesce helper instead of syn…
ondrejmirtes 8fe6018
Skip the synthetic constructor-call pricing when the return type cann…
ondrejmirtes 307610d
Answer Scope::getType for a plain variable from scope state, not on d…
ondrejmirtes c45cee9
Prime the storage with argument results before dynamic function exten…
ondrejmirtes 58eaa19
Prime the storage for method and static call dynamic-return extension…
ondrejmirtes 15dec37
Revert "Answer Scope::getType for a plain variable from scope state, …
ondrejmirtes 7384a07
Revert "Skip the synthetic constructor-call pricing when the return t…
ondrejmirtes a790cf4
Revert "Compose ??= type and narrowing via the coalesce helper instea…
ondrejmirtes da5caf0
Read narrowing subjects' current types from scope state, not on demand
ondrejmirtes 9b7ac7b
Derive non-nullability ensure types from scope state, not on demand
ondrejmirtes c698342
Derive narrowing-application base types from scope state, not on demand
ondrejmirtes 9c2f8aa
Keep void in typeCallbacks; project void to null at the value-read bo…
ondrejmirtes 2313a60
Push the walk's storage onto the scope-visible stack in processStmtNo…
ondrejmirtes 398d943
Move @phpstan-assert narrowing into DefaultNarrowingHelper, off TypeS…
ondrejmirtes ad6652e
Move conditional-return-type narrowing into DefaultNarrowingHelper, o…
ondrejmirtes eabb225
Finish the conditional-return-type move: remaining call sites + delet…
ondrejmirtes fe7793b
Gate call-shaped narrowing subjects by reflection instead of walking …
ondrejmirtes 375a764
Memoize the narrowing-application pricing pair per scope
ondrejmirtes 8ef68e0
Replace SpecifiedTypes::normalize() with symbolic alternative-form en…
ondrejmirtes 1fcfc68
Defer boolean conditional-holder math to the application point
ondrejmirtes 6666bfe
Defer the either-branch union recovery to the application point
ondrejmirtes 2347829
Defer the disjunction holder projection to the application point
ondrejmirtes 973a353
Compute disjunction decided-operand verdicts at the evaluation point
ondrejmirtes 77902b9
Compute comparison, coalesce and nullsafe-twin verdicts at the evalua…
ondrejmirtes 4bfa998
Resolve isset/coalesce issetability verdicts on the evaluation scope
ondrejmirtes 8951037
Derive decomposition branch scopes from the evaluation point, not per…
ondrejmirtes 74f364d
Compose nullsafe narrowing from captured results instead of walking a…
ondrejmirtes 334a9a9
Read isset chain-link types on the evaluation point
ondrejmirtes f27df41
Memoize specify results per (context, flavour) at the evaluation point
ondrejmirtes cc184e3
Flip specifyTypesCallback to (TypeSpecifierContext, bool)
ondrejmirtes 77c90f4
Port the coalesce falsey-context gate to the composed narrowing
ondrejmirtes 179234f
Resolve boolean-decomposition branch scopes lazily
ondrejmirtes 1fb4c64
Flip createTypesCallback to (Type, TypeSpecifierContext, bool)
ondrejmirtes cdf1e64
Read match arm verdicts from the threaded per-arm state
ondrejmirtes 08fda3e
Answer foreign-position type asks from the scope's state uniformly
ondrejmirtes e7b54d4
Read nullsafe receivers from before the enclosing ensure's device types
ondrejmirtes 0a18539
Release each file's captured results; drop dead filterBy* scope caches
ondrejmirtes 841a139
Release resolved typeCallbacks, share the empty specify closure, move…
ondrejmirtes 124804d
Process function and method bodies against a per-body result storage …
ondrejmirtes 73d05c6
Read ternary branch results on their processing scopes
ondrejmirtes 5bf4d4e
Expect the flavour-pure native type in the match arm always-true message
ondrejmirtes a7b1094
Revert "Expect the flavour-pure native type in the match arm always-t…
ondrejmirtes e0689a9
Collect branch-union candidates from sureNot narrowings, skip templat…
ondrejmirtes c7dd2da
Revert maybe-existing property promotion to its declared type
ondrejmirtes fb529e9
Bind static to the named class when calling a static method through a…
ondrejmirtes 16f1e3d
Strip the nullsafe short-circuit null from a static call's class-expr…
ondrejmirtes afa4b46
Fan receiver-not-null through nullsafe chains from composed create ca…
ondrejmirtes 9cf757a
Re-price stored results asked at a diverging variable position
ondrejmirtes cc32e26
Restore per-item array_map expectations lifted by counterfactual re-p…
ondrejmirtes 234e13c
Process the nullsafe receiver once and let the plain twin consume its…
ondrejmirtes 3a4f66b
Exempt closures and arrow functions from the PHPSTAN_GUARD_NW pre-pro…
ondrejmirtes f60a81b
Exempt constant shapes and variable reads from the PHPSTAN_GUARD_NW g…
ondrejmirtes fedc49a
Sanction deliberate before-the-walk reads under the PHPSTAN_GUARD_NW …
ondrejmirtes 829c6cc
Sanction closure-signature reads of parameter defaults and sibling ca…
ondrejmirtes 45ac08f
Revert the PHPSTAN_GUARD_NW exemptions and sanctioned reads
ondrejmirtes 236ffd5
Carry narrowing subjects' ExpressionResults into SpecifiedTypes
ondrejmirtes e162cd2
Attach a result to its own narrowing entries as a weak subject reference
ondrejmirtes a18ddd1
Consume or cache-price closure arguments in on-demand call re-walks
ondrejmirtes 896a31c
Skip the synthetic constructor-call pricing when the return type cann…
ondrejmirtes b57cf8b
Derive argument-less call subjects' narrowing base from reflection state
ondrejmirtes 4b33531
Revert carrying narrowing subjects' ExpressionResults in SpecifiedTypes
ondrejmirtes d460eb4
Compose ??= from its child results like CoalesceHandler
ondrejmirtes ca2c59b
Store the post-inc/dec synthetic's result before the virtual assign
ondrejmirtes 4c14954
Fabricate virtual assigned-expr results instead of pricing them on de…
ondrejmirtes 64b52af
Add regression test for #14914
ondrejmirtes 04f9f0f
Add regression test for #14908
ondrejmirtes 1463ff7
Add required lint version comments to bug-14914 and bug-14908 fixtures
ondrejmirtes 210d788
Read the foreach iteratee off the scope instead of re-walking it
ondrejmirtes 7953a7a
Compose the foreach non-empty-iteratee narrowing from the iteratee's …
ondrejmirtes b959b0b
Compose switch case narrowing and read match/switch subjects off the …
ondrejmirtes 8a39843
Read the coalesce left side off the left-is-set scope instead of re-w…
ondrejmirtes 6b5f83a
Read the short-ternary condition off its truthy scope instead of re-w…
ondrejmirtes 6150101
Memoize flush-priced results for repeated rule asks
ondrejmirtes 8208a7f
Revert "Memoize flush-priced results for repeated rule asks"
ondrejmirtes bc70222
Build closure/arrow call-arg types from the single body walk
ondrejmirtes ff5f239
Select the per-argument metadata acceptor only where its resolution i…
ondrejmirtes ac8f7e1
Make pass-local storages scope-visible and consume loop condition res…
ondrejmirtes f82883e
Memoize the generator check per function-like node
ondrejmirtes 5c39670
Answer stored fiber asks without suspending
ondrejmirtes a6989a4
Answer invalidation checks from a per-holder index of contained node …
ondrejmirtes 66c146d
Memoize flush-priced answers for repeated rule asks
ondrejmirtes 12f38f2
Create merge conditionals from the differing holders only
ondrejmirtes c13ee7f
Skip loop verification passes whose entry scope did not change
ondrejmirtes 2e71936
Batch type specifications into one scope copy per application
ondrejmirtes fce83d8
Run engine-feeding node-callback gatherers synchronously at the emiss…
ondrejmirtes 1c364b1
Align the isset verdict gate with 2.2.x and pin null in falsey isset …
ondrejmirtes 6a82e53
Store the assign-target property fetch's pre-assign result for parked…
ondrejmirtes 5e6558c
Price closure parameter defaults without a scope walk
ondrejmirtes 5a41b22
Create the function call's impure point after its arguments are proce…
ondrejmirtes 3c66674
Restore the Array_ import dropped when replaying onto the ScopeOps ex…
ondrejmirtes cffde37
Update test expectations after the rebase onto 2.2.x
ondrejmirtes 7bb39be
Remove the superseded ScopeOps invalidation helpers after the rebase
ondrejmirtes 512fee5
Answer invalidation checks from ScopeOps again
ondrejmirtes cc01bac
Sync the turbo native twins with the single-pass engine's shadowed cl…
ondrejmirtes 56da14c
Pin turbo extension version to cac4327
ondrejmirtes 466676e
Resolve the call return type once per call
ondrejmirtes e7fc3fc
Complete the stored preliminary call result in place instead of overw…
ondrejmirtes 05b8a2b
Walk closure by-ref convergence passes in deep statement context
ondrejmirtes e99d82d
Drop unnecessary ?? null on always-set parameter types
ondrejmirtes 4524da6
Drop the buildTypeSpecifications smoke block for the removed helper
ondrejmirtes 82105a2
Fix use-statement order left by the rebase auto-merge
ondrejmirtes 2d05cc1
Price an offset read on never as ErrorType in the narrowing-base reader
ondrejmirtes ed25511
Avoid the nullsafe operator - simple-downgrader passes it through
ondrejmirtes 1b82a35
Use ExtensionsCollection in ExpressionResult and tag PerFileAnalysisR…
ondrejmirtes 85d5a6c
Construct name checks from extensions collections in ClassConstantPhp…
ondrejmirtes ba3cf79
Bump expected turbo version
ondrejmirtes f00014d
Restore the default-value gate in the isset verdict
ondrejmirtes 3672b5d
Complete the callable-union parameter merge in createCallableParameters
ondrejmirtes 2044bde
Bump expected turbo version
ondrejmirtes 571a793
Absorb the upstream TypeSpecifierTest additions after the rebase
ondrejmirtes 4d23d82
Drop the upstream toSureTypes copy that flowed into the holder helper
ondrejmirtes 53be7c3
Bump expected turbo version
ondrejmirtes 3626da3
Drop the upstream duplicate of the differingKeys smoke block
ondrejmirtes b06eb5f
Split processAssignVar into prepareTarget and applyWrite
ondrejmirtes b03cd22
Produce the assignment target's read result inside prepareTarget
ondrejmirtes 92e6c76
Pass the assigned value's result into applyWrite instead of pre-stori…
ondrejmirtes 35b04db
Compose the ??= read from the walked target instead of a second walk
ondrejmirtes 77b1c04
Compose target reads from handler composition methods, thread operand…
ondrejmirtes 9aacdcc
Thread more in-hand results through the assignment narrowing and writ…
ondrejmirtes 895a302
Bump expected turbo version
ondrejmirtes 6d4ebf9
Remove the ISSET_DEBUG diagnostic leftover
ondrejmirtes d4f72ca
Emit SwitchConditionNode from the branch's switch processing
ondrejmirtes b26edc9
Walk the dynamic variable name once in prepareTarget
ondrejmirtes 8bccf27
Reference the original chain in ExistingArrayDimFetch, drop the clone…
ondrejmirtes ce774e8
Derive simulated-call throw points directly instead of walking synthe…
ondrejmirtes 6fef606
Resolve offsetGet and __toString return types directly
ondrejmirtes fcb397b
Thread captured results through the remaining call-handler reads
ondrejmirtes File filter
Filter by extension
Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
There are no files selected for viewing
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
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,76 @@ | ||
| <?php declare(strict_types = 1); | ||
|
|
||
| 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 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(); | ||
| } | ||
|
|
||
| public function hasYield(): bool | ||
| { | ||
| return $this->expressionResult->hasYield(); | ||
| } | ||
|
|
||
| public function isAlwaysTerminating(): bool | ||
| { | ||
| return $this->expressionResult->isAlwaysTerminating(); | ||
| } | ||
|
|
||
| /** | ||
| * @return InternalThrowPoint[] | ||
| */ | ||
| public function getThrowPoints(): array | ||
| { | ||
| return $this->expressionResult->getThrowPoints(); | ||
| } | ||
|
|
||
| /** | ||
| * @return ImpurePoint[] | ||
| */ | ||
| public function getImpurePoints(): array | ||
| { | ||
| return $this->expressionResult->getImpurePoints(); | ||
| } | ||
|
|
||
| public function getResolvedParametersAcceptor(): ?ParametersAcceptor | ||
| { | ||
| return $this->resolvedParametersAcceptor; | ||
| } | ||
|
|
||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,118 @@ | ||
| <?php declare(strict_types = 1); | ||
|
|
||
| namespace PHPStan\Analyser; | ||
|
|
||
| use PhpParser\Node\Expr; | ||
| use PHPStan\Type\NeverType; | ||
| use PHPStan\Type\Type; | ||
| use PHPStan\Type\TypeCombinator; | ||
| use function array_key_exists; | ||
|
|
||
| /** | ||
| * A deferred description of the boolean-decomposition conditional holders | ||
| * (`&&` asserted false, `||` asserted true): the raw narrowing entries of the | ||
| * condition side and the holder side, captured where the boolean narrowing was | ||
| * composed. The state-dependent math - the condition complements against the | ||
| * current type, the holder target types, the vacuity checks - runs in | ||
| * evaluate() against the scope the narrowing is applied to | ||
| * (MutatingScope::applySpecifiedTypes()), never the scope the composition ran | ||
| * on. | ||
| */ | ||
| final class ConditionalExpressionHolderRecipe | ||
| { | ||
|
|
||
| /** | ||
| * @param list<array{string, Expr, bool, Type}> $conditionEntries [exprString, expr, fromSureTypes, type] | ||
| * @param list<array{string, Expr, Type, ?Type}> $holderEntries [exprString, expr, type, target type pinned at compose time (null = read the applying scope)] | ||
| */ | ||
| public function __construct( | ||
| private array $conditionEntries, | ||
| private array $holderEntries, | ||
| private bool $holdersFromSureTypes, | ||
| ) | ||
| { | ||
| } | ||
|
|
||
| /** | ||
| * @return array<string, ConditionalExpressionHolder[]> | ||
| */ | ||
| public function evaluate(MutatingScope $scope): array | ||
| { | ||
| $conditionExpressionTypes = []; | ||
| $droppedNoOpConditions = []; | ||
| // the unnarrowed type of each condition expression, for the | ||
| // dropped-self-condition complement below | ||
| $conditionOriginalTypes = []; | ||
| foreach ($this->conditionEntries as [$exprString, $expr, $fromSureTypes, $type]) { | ||
| $scopeType = $scope->getStateType($expr); | ||
| $conditionType = $fromSureTypes | ||
| ? TypeCombinator::remove($scopeType, $type) | ||
| : TypeCombinator::intersect($scopeType, $type); | ||
| if ($scopeType->equals($conditionType)) { | ||
| $droppedNoOpConditions[$exprString] = true; | ||
| continue; | ||
| } | ||
|
|
||
| $conditionExpressionTypes[$exprString] = ExpressionTypeHolder::createYes($expr, $conditionType); | ||
| $conditionOriginalTypes[$exprString] = $scopeType; | ||
| } | ||
|
|
||
| if ($conditionExpressionTypes === []) { | ||
| return []; | ||
| } | ||
|
|
||
| $holders = []; | ||
| foreach ($this->holderEntries as [$exprString, $expr, $type, $pinnedTargetType]) { | ||
| // The target's only link to the antecedent was a no-op relation (e.g. | ||
| // `$a === $b`) that got dropped, so the antecedent no longer constrains | ||
| // it. Projecting a consequent onto it would fire unsoundly. Skip it. | ||
| if (array_key_exists($exprString, $droppedNoOpConditions)) { | ||
| continue; | ||
| } | ||
|
|
||
| $conditions = $conditionExpressionTypes; | ||
| $droppedSelfCondition = null; | ||
| if (isset($conditions[$exprString])) { | ||
| $droppedSelfCondition = $conditions[$exprString]; | ||
| unset($conditions[$exprString]); | ||
| } | ||
|
|
||
| if ($conditions === []) { | ||
| continue; | ||
| } | ||
|
|
||
| $targetType = $pinnedTargetType ?? $scope->getStateType($expr); | ||
| $holderType = $this->holdersFromSureTypes | ||
| ? TypeCombinator::intersect($targetType, $type) | ||
| : TypeCombinator::remove($targetType, $type); | ||
|
|
||
| // The dropped self-condition narrowed the target; without it the | ||
| // holder must allow the values it excluded, or it over-narrows when | ||
| // only the remaining conditions hold. So union back the complement. | ||
| if ($droppedSelfCondition !== null) { | ||
| $complement = TypeCombinator::remove($conditionOriginalTypes[$exprString], $droppedSelfCondition->getType()); | ||
| if (!$complement instanceof NeverType) { | ||
| $holderType = TypeCombinator::union($holderType, $complement); | ||
| } | ||
| } | ||
|
|
||
| // These boolean-decomposition holders only refine an expression's | ||
| // type in a future scope; they must never collapse it to never and | ||
| // thereby mark the whole scope unreachable. A never result is an | ||
| // artifact (e.g. removing a non-nullable property's full type after | ||
| // swapping isset() narrowing), not a real contradiction. | ||
| if ($holderType instanceof NeverType && !$targetType instanceof NeverType) { | ||
| continue; | ||
| } | ||
| $holder = new ConditionalExpressionHolder( | ||
| $conditions, | ||
| ExpressionTypeHolder::createYes($expr, $holderType), | ||
| ); | ||
| $holders[$exprString] ??= []; | ||
| $holders[$exprString][$holder->getKey()] = $holder; | ||
| } | ||
|
|
||
| return $holders; | ||
| } | ||
|
|
||
| } |
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
| Original file line number | Diff line number | Diff line change |
|---|---|---|
| @@ -0,0 +1,17 @@ | ||
| <?php declare(strict_types = 1); | ||
|
|
||
| namespace PHPStan\Analyser; | ||
|
|
||
| /** | ||
| * A state-dependent augmentation of a SpecifiedTypes, deferred to the | ||
| * application point: MutatingScope::applySpecifiedTypes() evaluates it against | ||
| * the applying scope and unions the produced entries into the applied batch. | ||
| * The composition captures only position-fixed facts (operand-walk reads); | ||
| * everything that must reflect the current state runs in evaluate(). | ||
| */ | ||
| interface DeferredSpecifiedTypesAugment | ||
| { | ||
|
|
||
| public function evaluate(MutatingScope $scope): ?SpecifiedTypes; | ||
|
|
||
| } |
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
Oops, something went wrong.
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.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
should this read
withFiber?