Commit 3beaa09
Generalize unsealed
`generalize()` early-returned `$this` when `count($keyTypes) === 0`,
which is correct for actually empty sealed arrays but wrong for a
CAT with no explicit keys but real unsealed extras
(`array{...<int, 'foo'>}` — type-checked construction; the builder
normally collapses this shape to `ArrayType`, but it can still
appear through `recreate()` paths). The constant values inside the
unsealed slot survived `generalize()` untouched.
Two fixes, mirroring each other:
1. Only early-return for "no explicit keys *and* not unsealed".
When the CAT carries real extras, proceed through the normal
path so the unsealed key/value are generalized through
`getIterableKeyType()` / `getIterableValueType()`.
2. Switch the `NonEmptyArrayType` gate from
`keyTypesCount > optionalKeysCount` to `isIterableAtLeastOnce()->yes()`.
The old gate was a proxy for "the array is definitely non-empty"
that only looked at explicit keys; for "no explicit keys + real
extras" it would incorrectly require the accessory. The
`isIterableAtLeastOnce()` answer is what we actually want — and
for sealed shapes it matches the previous gate exactly.
Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>ConstantArrayType instead of returning it unchanged1 parent ba6d89c commit 3beaa09
2 files changed
Lines changed: 21 additions & 3 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
2250 | 2250 | | |
2251 | 2251 | | |
2252 | 2252 | | |
2253 | | - | |
| 2253 | + | |
| 2254 | + | |
2254 | 2255 | | |
2255 | 2256 | | |
2256 | 2257 | | |
| |||
2275 | 2276 | | |
2276 | 2277 | | |
2277 | 2278 | | |
2278 | | - | |
| 2279 | + | |
| 2280 | + | |
| 2281 | + | |
| 2282 | + | |
| 2283 | + | |
| 2284 | + | |
| 2285 | + | |
| 2286 | + | |
2279 | 2287 | | |
2280 | 2288 | | |
2281 | 2289 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
1932 | 1932 | | |
1933 | 1933 | | |
1934 | 1934 | | |
1935 | | - | |
| 1935 | + | |
| 1936 | + | |
| 1937 | + | |
| 1938 | + | |
| 1939 | + | |
| 1940 | + | |
| 1941 | + | |
| 1942 | + | |
| 1943 | + | |
| 1944 | + | |
| 1945 | + | |
1936 | 1946 | | |
1937 | 1947 | | |
1938 | 1948 | | |
| |||
0 commit comments