Description
Bug report
I have a method which returns a very big array shape (array{....}
). But when I use this shape in a ternary / null coalesce operation with a "fallback" to []
the type get's manged. In this case the shape is lost and it's converted into a generic array where the key type some of the keys but as a union, and after a certain amount (seems to be 64 and above) the keys are just "lost" (not added to the union), and the same happens to the value types, these are combined into a union as well, and new / unique types after the first 64 seem to be lost.
So see the linked example. Line 12 correctly dumps the array shape (array{1: string, ..., 64: float}|null
), while when combining it with a ?? []
(on line 13) it's converted into array<1|2|3|...|63, bool|int|string>
(notice that float
is only used as type for key 64
, and is not part of the converted generic either). And the same happens when using a normal ternary (truty ? shape() : []
).
Also not that dropping a single array key isn't enough (while it would limit the size to 63, which is the number of items in the array key union), and at least 2 keys need to be dropped.
While the code is (very) badly designed I would still like to report this and see if this is something which maybe can be fixed (but it might as well be an artificial limit as these big shapes might hurt performance?)
Code snippet that reproduces the problem
https://phpstan.org/r/8b1640c3-2c07-4c7a-85fc-c143048ef03d
Expected output
Line 13 should log:
Dumped type: array{}|array{1: string, 2: int, 3: bool, 4: string, 5: int, 6: bool, 7: string, 8: int, 9: bool, 10: string, 11: int, 12: bool, 13: string, 14: int, 15: bool, 16: string, 17: int, 18: bool, 19: string, 20: int, 21: bool, 22: string, 23: int, 24: bool, 25: string, 26: int, 27: bool, 28: string, 29: int, 30: bool, 31: string, 32: int, 33: bool, 34: string, 35: int, 36: bool, 37: string, 38: int, 39: bool, 40: string, 41: int, 42: bool, 43: string, 44: int, 45: bool, 46: string, 47: int, 48: bool, 49: string, 50: int, 51: bool, 52: string, 53: int, 54: bool, 55: string, 56: int, 57: bool, 58: string, 59: int, 60: bool, 61: string, 62: int, 63: bool, 64: float}
(which is the same as line 12, except |null
now being array{}
)
And line 15 should be array{}|array{1: ...}|null
Did PHPStan help you today? Did it make you happy in any way?
PHPStan is helping me a lot with refactoring and adding type hints to a very old code base. Generate baseline, refactor, run again, and if there are no (new) errors I'm pretty sure I didn't break anything 😄.