Repository navigation
Conversation
568511a to
8aa4092
Compare
8aa4092 to
b5a6e6e
Compare
|
This pull request has been marked as ready for review. |
| if ($commonReasons !== null && count($commonReasons) > 0) { | ||
| $decorated = []; | ||
| foreach (array_keys($innerAccepts) as $i) { | ||
| foreach (array_keys($innerAccepts) as $innerAcceptsIndex) { |
There was a problem hiding this comment.
I think we have the same problem here.. this change got necessary because the PR broke polluteScopeWithAlwaysIterableForeach?
There was a problem hiding this comment.
You're right, and my earlier reply was wrong. Sorry. I checked: $i in UnionType::accepts() becomes defined after the first loop only because of this change, and it matches what polluteScopeWithAlwaysIterableForeach: true already produces. So it is the same leak, not a flag-independent fact.
The leak flows through conditionals between variables the loop body builds (here $innerAccepts), not through the iterated expression itself, and I could not strip it without also dropping non-emptiness that other code legitimately relies on. So instead of chasing full containment, I've gated the whole behaviour behind a bleedingEdge toggle, narrowForeachBodyNonEmpty.
With bleedingEdge off (stable), polluteScopeWithAlwaysIterableForeach: false behaves exactly as before: no in-body narrowing, no after-loop change. With bleedingEdge on, the body narrows and #13312 is fixed. This rename and the ConstantArrayType guards are only needed because the self-analysis config runs with bleedingEdge on.
There was a problem hiding this comment.
please remove unrelated changes in
- src/Type/UnionType.php
- src/Type/Constant/ConstantArrayType.php
There was a problem hiding this comment.
Done. I dropped both files. The toggle is no longer enabled under bleedingEdge, so the self-analysis config never turns it on and those source changes are not needed. It is opt-in only until the after-loop leak is fully contained.
There was a problem hiding this comment.
The toggle is no longer enabled under bleedingEdge, so the self-analysis config never turns it on and those source changes are not needed. It is opt-in only until the after-loop leak is fully contained.
I think this indicates that this PR is still breaking polluteScopeWithAlwaysIterableForeach: false?
b5a6e6e to
54ac5fd
Compare
| polluteScopeWithAlwaysIterableForeach: false | ||
| featureToggles: | ||
| narrowForeachBodyNonEmpty: true |
There was a problem hiding this comment.
do we need more tests with other combinations of this toggles?
There was a problem hiding this comment.
Added Bug13312StableTest for the toggle-off case (foreach body left as list<mixed>, while the separate for-loop narrowing still applies). Bug13312NoPolluteTest covers toggle-on. Happy to add pollute-on combinations too if you want them.
54ac5fd to
3af0acb
Compare
3af0acb to
c3389dc
Compare
7cfb7ea to
eb6fb26
Compare
Inside a foreach body the iterated expression is provably non-empty, so it can be narrowed (list to non-empty-list, array to non-empty-array) at body entry. Before, this happened only when polluteScopeWithAlwaysIterableForeach was on, so with the flag off (as phpstan-strict-rules sets it) the narrowing disappeared even though the body is only entered when the iteratee is non-empty. The narrowing is gated behind the new feature toggle narrowForeachBodyNonEmpty, off by default. With it off the body scope is built exactly as before, so no behaviour changes. With it on, the body narrows regardless of the flag. The after-loop scope keeps that precision (a value variable can be seen as defined where the iteratee is later proven non-empty), which is why the toggle is opt-in and not enabled under bleedingEdge yet. Closes phpstan/phpstan#13312 Amp-Thread-ID: https://ampcode.com/threads/T-01a19219-6260-7460-a52b-a418f709e4bf
eb6fb26 to
bef3992
Compare
Closes phpstan/phpstan#13312
This reproduces with
polluteScopeWithAlwaysIterableForeach: false, whichphpstan-strict-rulessets.Inside the loop body
$arris provably non-empty. PHPStan already narrowed it there, but only as a side effect ofpolluteScopeWithAlwaysIterableForeach: with the flag off the in-body narrowing disappeared. A previous fix (phpstan-src#4162) added a test for it, but only under the default flag value, so the reported case kept failing underphpstan-strict-rulesand the issue was reopened.Opt-in toggle
The narrowing is gated behind a new feature toggle
narrowForeachBodyNonEmpty, off by default and not enabled under bleedingEdge.The narrowing also sharpens the after-loop scope: a value variable can be seen as defined where the iteratee is later proven non-empty (e.g. via
count() > 0). This is more precise but changes whatpolluteScopeWithAlwaysIterableForeach: falsereports, so the toggle stays opt-in for now rather than being enabled under bleedingEdge.Bug13312NoPolluteTestcovers the toggle on;Bug13312StableTestcovers the default (off), where the foreach body is left as-is.