Preserve constant array when setting a union of constant scalar keys#4528
Preserve constant array when setting a union of constant scalar keys#4528staabm wants to merge 4 commits intophpstan:2.1.xfrom
Conversation
4cbca5e to
8cbe785
Compare
|
This pull request has been marked as ready for review. |
|
ok, I see now that this new fix no longer fixes issues, which were reported by issue-bot in the previous PR. |
8cbe785 to
7964b98
Compare
7964b98 to
95ac439
Compare
95ac439 to
bbe90ae
Compare
|
@phpstan-bot please debug why some existing tests are failing and some errors reappear? |
|
Claude finished @staabm's task in 6m 14s —— View job Debugging Test Failures
Root Cause AnalysisThe PR adds union-splitting logic in both The core problem: This interacts badly with loop analysis and multi-step array construction. Here's why: Problem 1: Combinatorial explosion in loopsWhen an array is assigned in a loop with a union key type, each iteration compounds the number of union members: // pr-4390.php: for ($i = 0; $i < 10; $i++) { $locations[$i] = []; ... }The loop analyzer runs the body multiple times and merges results. With the old code, With the new code, when CI failure: Problem 2: Loss of type precision in foreach with constant array keys// bug-11846.php
$idList = [1, 2];
foreach ($idList as $id) { // $id: 1|2
$outerList[$id] = []; // splits into 2 arrays
array_push($outerList[$id], []); // now operates on a union, loses track
}With the old code, after the loop,
CI failures: Problem 3: New false positive errors (bug-7594, bug-4829, bug-12115)These tests expected no errors but now produce errors because the union-splitting causes the array types to degrade during loop/conditional processing:
Problem 4: Dramatically fewer errors detected (bug-7903)The Why the Issue-Bot PassedThe issue-bot tests passed because they test different patterns — likely not involving union-key assignments on constant arrays inside loops. The Fundamental IssueThe
Suggested Fix DirectionThe union-splitting approach works well for the simple, non-loop case (like the new test Possible approaches:
The simplest approach might be option 2: add a guard that checks whether |
closes #4520