Filing this at @VincentLanglet's request on phpstan/phpstan-src#5568.
Summary
PHPStan 2.1.52+ produces generator.valueType false positives where a closure's inferred Generator value type rejects the very yields it was synthesised from. The oversized-array generalization in TypeCombinator::optimizeConstantArrays produces a type that is not a super-type of the variants it was derived from.
The error is self-inconsistent: PHPStan complains that each yielded value (with a perfectly valid concrete shape) does not match the Generator value type — but that inferred value type is synthesized from those very same yields. A function cannot legitimately yield a value its own inferred return type rejects; the oversized-array generalization step is producing a type that fails to be a super-type of its own contributors.
Symptom signature: the inferred type contains &oversized-array markers on shapes that are themselves empty (array{}&oversized-array) or fully-generalized array<intKey, V>&accessories mixed in the same union as preserved array{...}&oversized-array records.
Reproducer
https://phpstan.org/r/5b811780-35b4-4ebf-b2a6-cecb90f02b2b
(level: max, bleedingEdge: true, treatPhpDocTypesAsCertain: true.)
A standalone version with non-numeric-string yield keys is included in the PR's test data file: bug-yield-oversized-self-rejection.php.
Affected versions
| Version |
Result |
| 2.1.51 |
OK |
| 2.1.52 |
9 errors (regression) |
| 2.1.53 |
9 errors |
| 2.1.54 |
9 errors (still broken) |
| with #5568 |
0 errors |
Introduced by 2f66c45222 ("Preserve constant array when assigning a union of scalars") in 2.1.52. That commit is itself a correct precision improvement; it exposed two latent bugs in TypeCombinator downstream.
Filing this at @VincentLanglet's request on phpstan/phpstan-src#5568.
Summary
PHPStan 2.1.52+ produces
generator.valueTypefalse positives where a closure's inferredGeneratorvalue type rejects the very yields it was synthesised from. The oversized-array generalization inTypeCombinator::optimizeConstantArraysproduces a type that is not a super-type of the variants it was derived from.The error is self-inconsistent: PHPStan complains that each yielded value (with a perfectly valid concrete shape) does not match the
Generatorvalue type — but that inferred value type is synthesized from those very same yields. A function cannot legitimately yield a value its own inferred return type rejects; the oversized-array generalization step is producing a type that fails to be a super-type of its own contributors.Symptom signature: the inferred type contains
&oversized-arraymarkers on shapes that are themselves empty (array{}&oversized-array) or fully-generalizedarray<intKey, V>&accessoriesmixed in the same union as preservedarray{...}&oversized-arrayrecords.Reproducer
https://phpstan.org/r/5b811780-35b4-4ebf-b2a6-cecb90f02b2b
(
level: max,bleedingEdge: true,treatPhpDocTypesAsCertain: true.)A standalone version with non-numeric-string yield keys is included in the PR's test data file:
bug-yield-oversized-self-rejection.php.Affected versions
Introduced by 2f66c45222 ("Preserve constant array when assigning a union of scalars") in 2.1.52. That commit is itself a correct precision improvement; it exposed two latent bugs in
TypeCombinatordownstream.