-
Notifications
You must be signed in to change notification settings - Fork 582
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
378
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
378 commits
Select commit
Hold shift + click to select a range
d5a984c
Revert "Simplify ExpressionResult::getType methods now that TypeResol…
ondrejmirtes c5f2716
Compose AlwaysRememberedExpr narrowing inside-out via createTypesCall…
ondrejmirtes cde6f76
Compose nullsafe narrowing inside-out via createTypesCallback
ondrejmirtes ef89073
Compose method/static call narrowing inside-out via createTypesCallback
ondrejmirtes 82afa50
Compose function call narrowing inside-out via createTypesCallback
ondrejmirtes 1c698fa
Gate the nullsafe createTypesCallback on containsNull
ondrejmirtes 6954ac7
Compose equality operand narrowing inside-out via createSubjectTypes
ondrejmirtes 30c2378
Route all of EqualityTypeSpecifyingHelper's narrowing through createF…
ondrejmirtes 26e81c4
Route BinaryOp / Isset / conditional-holder narrowing through createF…
ondrejmirtes 9c68a16
Resolve child narrowing on demand instead of via specifyTypesInCondition
ondrejmirtes 0bf9be6
Resolve BinaryOpHandler re-dispatched conditions on demand
ondrejmirtes 618b252
Resolve equality re-dispatched conditions on demand
ondrejmirtes 32ad245
Resolve empty()'s isset-or-falsey condition on demand
ondrejmirtes d96e467
Compose negation narrowing from the operand result; isset on demand
ondrejmirtes 7e44e88
Thread operand results into equality narrowing
ondrejmirtes 16004b3
Compose remembered-operand narrowing from the result, dropping manual…
ondrejmirtes e9f9840
Drop the AlwaysRememberedExpr fan-out from TypeSpecifier::create
ondrejmirtes 8fcdf21
Resolve conditional-after-assign narrowing on demand
ondrejmirtes b4eb6b4
Resolve nullsafe receiver-and-fetch condition on demand
ondrejmirtes d7e292f
Read expression-statement narrowing from its result
ondrejmirtes 78b5dad
Resolve the impossible-check condition through the scope's dispatcher
ondrejmirtes f08846e
Apply the expression-statement narrowing via applySpecifiedTypes
ondrejmirtes 99241d9
Apply do-while exit narrowing from the condition result
ondrejmirtes 83064b5
Narrow control-flow scopes via applySpecifiedTypes, not filterBy*Value
ondrejmirtes b8388ca
Require typeCallback and specifyTypesCallback on ExpressionResult
ondrejmirtes 8d48d17
Remove todo
ondrejmirtes 41aa004
Replace handleDefaultTruthyOrFalseyContext with specifyDefaultTypes
ondrejmirtes baef4f1
Read operand/receiver types from their results, not Scope::getType
ondrejmirtes 5a7389c
Guard on-demand pricing paths with PHPSTAN_GUARD_NW
ondrejmirtes b3c00ea
Capture per-arg ExpressionResults; read appending-arg types from them
ondrejmirtes 0a3f04d
Read array_splice and resolveReturnType arg types from their results
ondrejmirtes 9ed412b
Carry the ??= left side's isset descriptor into its coalesce type
ondrejmirtes 681f224
Find the early-terminating expression after processing the statement
ondrejmirtes 184385c
Consume the processed arg result for the callable-arg check in proces…
ondrejmirtes 28c9e41
Resolve the arrow function return type after its body is processed
ondrejmirtes f5d2f1f
Compute Closure::bind's bound scope from its processed arguments
ondrejmirtes b29d3ca
Fix PHPStan self-analysis errors in NodeScopeResolver
ondrejmirtes 9e99955
Read impossible-check narrowing from the call's ExpressionResult
ondrejmirtes 3987447
Gate the processArgs fast path on parameter late-resolvability only
ondrejmirtes 8e6e7f0
Don't route curl_setopt(_array) through the metadata pre-pass
ondrejmirtes 1c46542
Don't route implode/join through the metadata pre-pass
ondrejmirtes 1a60e43
Supply array_map's callback parameter type via a closure-type extension
ondrejmirtes 82b3c23
Supply array_filter/walk/find callback parameter types via closure-ty…
ondrejmirtes 97e0686
Read array_walk's original array type after its argument is processed
ondrejmirtes ea774a3
Make Closure::bind/bindTo single-pass; drop the empty argsHaveIntrins…
ondrejmirtes 5a89b02
Resolve single-variant generic acceptors incrementally so they are si…
ondrejmirtes 53cf4b8
Select multi-variant acceptors by argument count so processArgs is si…
ondrejmirtes 379b8a7
Deduplicate constant-condition vs impossible-check reports via collec…
ondrejmirtes 1411031
Process a dynamic function-call name before reading its type
ondrejmirtes e13d727
Process a nested array-dimension before reading its type in AssignHan…
ondrejmirtes fd0cb91
Process an assign-op Variable/property target as a read before compos…
ondrejmirtes 05cb725
Process Closure::call's new-$this argument before reading its type
ondrejmirtes 536392d
Process clone()'s arguments before reading them in clone-with handling
ondrejmirtes 4f47074
Evaluate an array-dim assignment's value before reading its type
ondrejmirtes 8268166
Read the foreach value variable's narrowed type by name in the loop a…
ondrejmirtes 5b8d9db
Carry the nullsafe receiver type to its rule via a virtual node
ondrejmirtes c3bc1ff
Drop the dead Expr parameter from ExpressionResult's typeCallback
ondrejmirtes 3fce90c
Build pre-inc/dec literal types via ConstantTypeHelper, not the scope
ondrejmirtes 9676d5c
Resolve lexical context once at create()-time in three type callbacks
ondrejmirtes 1515c80
Resolve the instanceof Name class type once at create()-time
ondrejmirtes 3a7f381
Reprocess the switch subject for the exhaustiveness check instead of …
ondrejmirtes 15dc4a2
Reprocess the foreach iteratee and while condition on their narrowed …
ondrejmirtes 34fdf94
Reprocess coalesce/ternary/match subjects on their narrowed scopes in…
ondrejmirtes 28a4e2d
Reprocess the foreach iteratee on the post-loop scope for value/key-t…
ondrejmirtes f092ff8
Narrow the pinned-name property fetch via applySpecifiedTypes, not fi…
ondrejmirtes 3f71bc8
Make specifyTypesCallback required and getSpecifiedTypesForScope non-…
ondrejmirtes 98624ea
Narrow synthetic conditions via processExprOnDemand, not filterByTrut…
ondrejmirtes 58840ae
Read wrapped operand types via getType/getNativeType in cast/clone/un…
ondrejmirtes 000901e
Read child types via getType/getNativeType in post/pre-inc/dec, pipe,…
ondrejmirtes 679e66e
Read the ternary condition type via getType/getNativeType in the type…
ondrejmirtes da43c40
Propagate the assigned value into byref-intertwined variables instead…
ondrejmirtes d284746
Read binary-op operands via getType/getNativeType in the type callback
ondrejmirtes c00cc98
Read the left operand boolean via getType/getNativeType in boolean ty…
ondrejmirtes 9041160
Resolve property fetch types without the asking scope
ondrejmirtes 7ecc6e1
Resolve static property fetch types without the asking scope
ondrejmirtes a6f24e7
Resolve method call return types without the asking scope
ondrejmirtes e529031
Resolve static call return types without the asking scope
ondrejmirtes c9108ba
Resolve function call return types without the asking scope
ondrejmirtes 69c1b08
Resolve nullsafe fetch/call short-circuit types without the asking scope
ondrejmirtes 26b6c9a
Read assignment and class-constant-fetch type callbacks via getType/g…
ondrejmirtes 222ed3e
Read instanceof and coalesce type callbacks without the asking scope
ondrejmirtes 2909134
Read assign-op type callback without the asking scope
ondrejmirtes 8a4f8a2
Pass the iteratee types into enterForeach instead of re-reading them
ondrejmirtes b1d0c60
Pass the iteratee types into enterForeachKey instead of re-reading them
ondrejmirtes d1549ba
Make the ExpressionResult typeCallback resolve from a native flag, no…
ondrejmirtes cacc4e3
Require an ExpressionResult to have either a precomputed type or a ty…
ondrejmirtes 7d6aad0
Read the tracked holder directly in ExpressionResult, not via Scope::…
ondrejmirtes 4ac500f
Get rid of truthyScopeCallback and falseyScopeCallback
ondrejmirtes ce9d54b
Use the operand's own truthy/falsey scope for &&/|| narrowing
ondrejmirtes fa6df9e
Record conditional holders from by-ref-updated variables via scope state
ondrejmirtes 103d013
Derive statement exit points from never instead of findEarlyTerminati…
ondrejmirtes c638a4d
Narrower return type
ondrejmirtes d3fe412
Do not use getChildSpecifiedTypes
ondrejmirtes bc3bc99
Inline getSpecifiedTypesForScope instead of getChildSpecifiedTypes
ondrejmirtes 2df5e26
Keep getType for the dropped-self-condition complement
ondrejmirtes cc25fe5
Add regression test for the type of a Closure::bind callback
ondrejmirtes 80924c2
Add regression test for array value type after foreach by-ref reassig…
ondrejmirtes be884aa
Add regression test for list<non-empty-array> preserved after foreach…
ondrejmirtes 8a9e1cf
Add regression test for ??= on a dynamic property array offset
ondrejmirtes 70476f4
Resolve ExpressionResult types from memoized per-flavour slots
ondrejmirtes 6644eaf
Split readStoredOrPriceOnDemand into decisive primitives
ondrejmirtes 0b22f94
Reintroduce readStoredResult as a storage-based assertion
ondrejmirtes a190af4
Narrow ?? by composing isset facts from chain results, not a syntheti…
ondrejmirtes c0efb63
Compose multi-subject isset() truthy narrowing from chain results
ondrejmirtes 3e8eff2
Consume the match arms' captured scope/type pairs instead of re-walki…
ondrejmirtes 29c5853
Answer plain variable reads from scope state instead of on-demand pro…
ondrejmirtes 01cfe07
Run AnalyserTest through FiberNodeScopeResolver like the other test h…
ondrejmirtes a550495
Resolve the offset-write property holder without re-reading the receiver
ondrejmirtes ef0db15
Answer maybe-stored reads from a tracked whole-expression holder with…
ondrejmirtes f22bab9
Skip the null-containment probe for bare variable narrowing subjects
ondrejmirtes d29fd66
Pin the dropped-self-condition complement type at holder-build time
ondrejmirtes 3e92356
Compose createSubjectTypes entries from the result's own facts, never…
ondrejmirtes 56e1845
Collapse filterByTruthyValue/filterByFalseyValue onto applySpecifiedT…
ondrejmirtes 4d665e0
Narrow match scopes via applySpecifiedTypes instead of filterBy*
ondrejmirtes 7349060
Compute call narrowing on the evaluation scope, flavoured by the aski…
ondrejmirtes 8ca03f1
Compose null-identity narrowing from operand results in IdenticalNarr…
ondrejmirtes 95ca533
Narrow bool-literal identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 59b981f
Narrow scalar-literal identity comparisons in IdenticalNarrowingHelper
ondrejmirtes fcd671c
Compose array_key_first-family null narrowing through the FuncCall co…
ondrejmirtes 955fa4d
Narrow get_class/get_debug_type identity comparisons in IdenticalNarr…
ondrejmirtes b200b57
Narrow gettype identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 0d5a1a6
Narrow preg_match identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 813a75c
Narrow strlen/mb_strlen identity comparisons in IdenticalNarrowingHelper
ondrejmirtes ce8ad99
Move count-size narrowing into CountNarrowingHelper
ondrejmirtes 9b76f3f
Narrow count/sizeof identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 66d82f8
Narrow string-function identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 054509e
Narrow trim and get_parent_class identity comparisons in IdenticalNar…
ondrejmirtes 9397f76
Narrow ::class identity comparisons in IdenticalNarrowingHelper
ondrejmirtes a33367f
Narrow general identity comparisons in IdenticalNarrowingHelper
ondrejmirtes a9cd707
Compose function-family narrowing for type-based constant sides
ondrejmirtes b149cf9
Narrow loose-equality comparisons in IdenticalNarrowingHelper
ondrejmirtes 3041c05
Compose assign-time conditional holders from the assigned expression'…
ondrejmirtes cdb14dc
Read assign-time ternary holder types from the captured walk results
ondrejmirtes 8d7d1a7
Extract conjunction narrowing into BooleanNarrowingHelper
ondrejmirtes e1ce90e
Fold multi-subject isset narrowing through the conjunction helper
ondrejmirtes 561755e
Extract disjunction narrowing into BooleanNarrowingHelper
ondrejmirtes e4d106e
Share the single-subject isset narrowing in DefaultNarrowingHelper
ondrejmirtes 8053322
Compose empty() narrowing through the disjunction helper
ondrejmirtes d8910d6
Compose ternary narrowing through the boolean helpers
ondrejmirtes 8b4ab41
Compose cast narrowing through the loose-equality helper
ondrejmirtes 52ad10e
Read tracked foreach and @var types without synthetic pricing
ondrejmirtes d1e0a49
Capture call-argument results for the composed comparison narrowing
ondrejmirtes f23e3ef
Narrow bool-typed identity comparisons in IdenticalNarrowingHelper
ondrejmirtes 176195e
Merge both directions of call-vs-call identity comparisons
ondrejmirtes 2dd0937
Compose the last identity-comparison tails
ondrejmirtes 847ae5e
Delete the old-world equality narrowing
ondrejmirtes 730b5e8
Key the closure type cache by the closure's actual inputs
ondrejmirtes 5c04416
Read assign sentinel base result from the walk storage
ondrejmirtes 60dc9c3
Compose comparison verdicts from captured results instead of re-walking
ondrejmirtes 43c5b46
Compose nullsafe method call null-removal from the receiver's stored …
ondrejmirtes 39b2538
Compose nullsafe property fetch null-removal from the receiver's stor…
ondrejmirtes 4ff61af
Compose variable-variable narrowing from the name expression's result
ondrejmirtes 1ec7c65
Read by-ref destructuring item types from the scope directly
ondrejmirtes fa16a1f
Compose match arm condition verdicts and narrowing from walk results
ondrejmirtes 61b1534
Use default narrowing directly for bool-variable contradiction probing
ondrejmirtes 0e9f037
Compose single-condition match arm filtering verdicts from walk results
ondrejmirtes 2865496
Reuse the ensured-scope call result for the nullsafe maybe-null type
ondrejmirtes d4577e3
Extract the coalesce type and falsey-narrowing composition into a helper
ondrejmirtes 637f339
Compose ??= type and narrowing via the coalesce helper instead of syn…
ondrejmirtes a0e64b0
Skip the synthetic constructor-call pricing when the return type cann…
ondrejmirtes 3bf3c14
Answer Scope::getType for a plain variable from scope state, not on d…
ondrejmirtes 42ddab4
Prime the storage with argument results before dynamic function exten…
ondrejmirtes 1432bf6
Prime the storage for method and static call dynamic-return extension…
ondrejmirtes 1c068fa
Revert "Answer Scope::getType for a plain variable from scope state, …
ondrejmirtes 0061b8f
Revert "Skip the synthetic constructor-call pricing when the return t…
ondrejmirtes fa67aba
Revert "Compose ??= type and narrowing via the coalesce helper instea…
ondrejmirtes 16233dd
Read narrowing subjects' current types from scope state, not on demand
ondrejmirtes 66485ce
Derive non-nullability ensure types from scope state, not on demand
ondrejmirtes 500be3a
Derive narrowing-application base types from scope state, not on demand
ondrejmirtes 46c3762
Keep void in typeCallbacks; project void to null at the value-read bo…
ondrejmirtes 9004eb7
Push the walk's storage onto the scope-visible stack in processStmtNo…
ondrejmirtes 95d0826
Move @phpstan-assert narrowing into DefaultNarrowingHelper, off TypeS…
ondrejmirtes 34b7414
Move conditional-return-type narrowing into DefaultNarrowingHelper, o…
ondrejmirtes 34bd261
Finish the conditional-return-type move: remaining call sites + delet…
ondrejmirtes 4b66947
Gate call-shaped narrowing subjects by reflection instead of walking …
ondrejmirtes 536cab1
Memoize the narrowing-application pricing pair per scope
ondrejmirtes 5add00f
Replace SpecifiedTypes::normalize() with symbolic alternative-form en…
ondrejmirtes 42aaf98
Defer boolean conditional-holder math to the application point
ondrejmirtes d64418c
Defer the either-branch union recovery to the application point
ondrejmirtes a6fd2a1
Defer the disjunction holder projection to the application point
ondrejmirtes e1e21d1
Compute disjunction decided-operand verdicts at the evaluation point
ondrejmirtes c330e96
Compute comparison, coalesce and nullsafe-twin verdicts at the evalua…
ondrejmirtes 0afee6b
Resolve isset/coalesce issetability verdicts on the evaluation scope
ondrejmirtes 0047099
Derive decomposition branch scopes from the evaluation point, not per…
ondrejmirtes 994e720
Compose nullsafe narrowing from captured results instead of walking a…
ondrejmirtes 14a0ac8
Read isset chain-link types on the evaluation point
ondrejmirtes ab9358c
Memoize specify results per (context, flavour) at the evaluation point
ondrejmirtes f203fc3
Flip specifyTypesCallback to (TypeSpecifierContext, bool)
ondrejmirtes 53482f8
Port the coalesce falsey-context gate to the composed narrowing
ondrejmirtes 22b31b4
Resolve boolean-decomposition branch scopes lazily
ondrejmirtes 9c84484
Flip createTypesCallback to (Type, TypeSpecifierContext, bool)
ondrejmirtes ecb54d2
Read match arm verdicts from the threaded per-arm state
ondrejmirtes 97789ce
Answer foreign-position type asks from the scope's state uniformly
ondrejmirtes 52b759e
Read nullsafe receivers from before the enclosing ensure's device types
ondrejmirtes 4eb33cf
Release each file's captured results; drop dead filterBy* scope caches
ondrejmirtes 5a0ef64
Release resolved typeCallbacks, share the empty specify closure, move…
ondrejmirtes 31560e3
Process function and method bodies against a per-body result storage …
ondrejmirtes b42c9dc
Read ternary branch results on their processing scopes
ondrejmirtes de5888f
Expect the flavour-pure native type in the match arm always-true message
ondrejmirtes 5acc289
Revert "Expect the flavour-pure native type in the match arm always-t…
ondrejmirtes 5e6fb4b
Collect branch-union candidates from sureNot narrowings, skip templat…
ondrejmirtes 71a798f
Revert maybe-existing property promotion to its declared type
ondrejmirtes 282bd8e
Bind static to the named class when calling a static method through a…
ondrejmirtes a9ee7db
Strip the nullsafe short-circuit null from a static call's class-expr…
ondrejmirtes ff15cfb
Fan receiver-not-null through nullsafe chains from composed create ca…
ondrejmirtes 488354f
Re-price stored results asked at a diverging variable position
ondrejmirtes 872e9b0
Restore per-item array_map expectations lifted by counterfactual re-p…
ondrejmirtes 83c11ad
Process the nullsafe receiver once and let the plain twin consume its…
ondrejmirtes dbf535b
Exempt closures and arrow functions from the PHPSTAN_GUARD_NW pre-pro…
ondrejmirtes 79ccb9f
Exempt constant shapes and variable reads from the PHPSTAN_GUARD_NW g…
ondrejmirtes 247d224
Sanction deliberate before-the-walk reads under the PHPSTAN_GUARD_NW …
ondrejmirtes c98b28f
Sanction closure-signature reads of parameter defaults and sibling ca…
ondrejmirtes 5f0f199
Revert the PHPSTAN_GUARD_NW exemptions and sanctioned reads
ondrejmirtes b0d1337
Carry narrowing subjects' ExpressionResults into SpecifiedTypes
ondrejmirtes 1a2699e
Attach a result to its own narrowing entries as a weak subject reference
ondrejmirtes 2172e36
Consume or cache-price closure arguments in on-demand call re-walks
ondrejmirtes 35eddf1
Skip the synthetic constructor-call pricing when the return type cann…
ondrejmirtes 8c824db
Derive argument-less call subjects' narrowing base from reflection state
ondrejmirtes 37254f7
Revert carrying narrowing subjects' ExpressionResults in SpecifiedTypes
ondrejmirtes 09e5536
Compose ??= from its child results like CoalesceHandler
ondrejmirtes 03a5a02
Store the post-inc/dec synthetic's result before the virtual assign
ondrejmirtes 43074b0
Fabricate virtual assigned-expr results instead of pricing them on de…
ondrejmirtes 23b499d
Add regression test for #14914
ondrejmirtes 5238cce
Add regression test for #14908
ondrejmirtes ff87aac
Add required lint version comments to bug-14914 and bug-14908 fixtures
ondrejmirtes db705ae
Read the foreach iteratee off the scope instead of re-walking it
ondrejmirtes 6a85ecb
Compose the foreach non-empty-iteratee narrowing from the iteratee's …
ondrejmirtes 02280c3
Compose switch case narrowing and read match/switch subjects off the …
ondrejmirtes abf31f6
Read the coalesce left side off the left-is-set scope instead of re-w…
ondrejmirtes 8d857cb
Read the short-ternary condition off its truthy scope instead of re-w…
ondrejmirtes c605537
Memoize flush-priced results for repeated rule asks
ondrejmirtes 80a35f8
Revert "Memoize flush-priced results for repeated rule asks"
ondrejmirtes 12b2043
Build closure/arrow call-arg types from the single body walk
ondrejmirtes 712a3c1
Select the per-argument metadata acceptor only where its resolution i…
ondrejmirtes 430cb05
Make pass-local storages scope-visible and consume loop condition res…
ondrejmirtes 6dd2842
Memoize the generator check per function-like node
ondrejmirtes c6a7aff
Answer stored fiber asks without suspending
ondrejmirtes 25b590e
Answer invalidation checks from a per-holder index of contained node …
ondrejmirtes d4608b7
Memoize flush-priced answers for repeated rule asks
ondrejmirtes 5fd0e7f
Create merge conditionals from the differing holders only
ondrejmirtes 553c3a8
Skip loop verification passes whose entry scope did not change
ondrejmirtes b7fc37d
Batch type specifications into one scope copy per application
ondrejmirtes 230acf3
Run engine-feeding node-callback gatherers synchronously at the emiss…
ondrejmirtes 21492ff
Align the isset verdict gate with 2.2.x and pin null in falsey isset …
ondrejmirtes cf3e581
Store the assign-target property fetch's pre-assign result for parked…
ondrejmirtes 525f050
Price closure parameter defaults without a scope walk
ondrejmirtes c923c62
Create the function call's impure point after its arguments are proce…
ondrejmirtes e940ad1
Restore the Array_ import dropped when replaying onto the ScopeOps ex…
ondrejmirtes 9d3d921
Update test expectations after the rebase onto 2.2.x
ondrejmirtes e38aadd
Remove the superseded ScopeOps invalidation helpers after the rebase
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.
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?