Commit 032c128
Answer
`finiteTypeSetContainedIn()` only ever compared two unions, so a union of values
asked about one value still walked its members. That is the shape
`TypeCombinator::doRemove()` opens with: `$typeToRemove->isSuperTypeOf($fromType)`
lands on `UnionType::isSubTypeOf()` through the `CompoundType` delegation, once
per removal, over the whole union.
A single value is a one-member set, so the map answers it: the union is under
that value only if it has nothing else in it, and disjoint from it if the key is
missing. `FiniteTypeSet::containedInKey()` is `containedIn()` for that case, and
the helper now treats a non-union other type as the set holding just that value.
`isAcceptedBy()` shares the helper and keeps its yes-only guard. As it happens no
constant value accepts another one - not a numeric string an int, in either
direction - so the guard cannot change an answer today; it stays because that is
a fact about the current value types rather than something the map guarantees.
Measured on the reproducer from phpstan/phpstan#15004, a `1|2|...|N` parameter
narrowed by a chain of N `!==` clauses, `analyse -l 8` wall clock:
| N | before the identity map | at HEAD | with this commit |
| --- | --- | --- | --- |
| 50 | 1.30 s | 1.20 s | 1.20 s |
| 100 | 3.11 s | 2.70 s | 2.41 s |
| 200 | 15.02 s | 12.92 s | 10.42 s |
| 300 | 46.27 s | 39.57 s | 30.95 s |
This is a constant factor, not the fix that issue wants: counting calls at N=100
shows 79674 `doRemove()`s costing 0.92 s, split 0.40 s `isSubTypeOf()` and 0.47 s
`tryRemove()`, and both are O(n) per call against an O(n) chain of O(n) removals.
Keying takes the first of the two down to a lookup; the growth stays ~O(N^2.7),
which only stopping the removals themselves would change.
The reference-implementation matrix now runs `isSubTypeOf()` and `isAcceptedBy()`
over the 17x18 union/non-union pairs as well as the union pairs, and asserts that
no member attaches a reason to an answer the map now gives on its behalf.
Mutating the fix afterwards fails 399 cases (a miss answering yes), 1 (never
answering yes), 92 (dropping the completeness gate) and 36 (keying an unkeyable
other type).
Co-Authored-By: Claude Opus 5 <noreply@anthropic.com>isSubTypeOf() against a single value from the FiniteTypeSet too1 parent 4c0234d commit 032c128
3 files changed
Lines changed: 147 additions & 10 deletions
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
264 | 264 | | |
265 | 265 | | |
266 | 266 | | |
| 267 | + | |
| 268 | + | |
| 269 | + | |
| 270 | + | |
| 271 | + | |
| 272 | + | |
| 273 | + | |
| 274 | + | |
| 275 | + | |
| 276 | + | |
| 277 | + | |
| 278 | + | |
| 279 | + | |
| 280 | + | |
| 281 | + | |
| 282 | + | |
| 283 | + | |
| 284 | + | |
| 285 | + | |
| 286 | + | |
| 287 | + | |
| 288 | + | |
| 289 | + | |
267 | 290 | | |
268 | 291 | | |
269 | 292 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
394 | 394 | | |
395 | 395 | | |
396 | 396 | | |
397 | | - | |
398 | | - | |
| 397 | + | |
| 398 | + | |
| 399 | + | |
| 400 | + | |
| 401 | + | |
399 | 402 | | |
400 | 403 | | |
401 | 404 | | |
402 | 405 | | |
403 | 406 | | |
404 | 407 | | |
405 | | - | |
406 | | - | |
407 | | - | |
408 | | - | |
409 | 408 | | |
410 | 409 | | |
411 | 410 | | |
412 | 411 | | |
413 | 412 | | |
| 413 | + | |
| 414 | + | |
| 415 | + | |
| 416 | + | |
| 417 | + | |
| 418 | + | |
| 419 | + | |
| 420 | + | |
| 421 | + | |
| 422 | + | |
| 423 | + | |
| 424 | + | |
| 425 | + | |
| 426 | + | |
| 427 | + | |
| 428 | + | |
| 429 | + | |
| 430 | + | |
| 431 | + | |
| 432 | + | |
| 433 | + | |
| 434 | + | |
| 435 | + | |
| 436 | + | |
| 437 | + | |
| 438 | + | |
414 | 439 | | |
415 | 440 | | |
416 | 441 | | |
| |||
| Original file line number | Diff line number | Diff line change | |
|---|---|---|---|
| |||
154 | 154 | | |
155 | 155 | | |
156 | 156 | | |
157 | | - | |
| 157 | + | |
| 158 | + | |
| 159 | + | |
| 160 | + | |
| 161 | + | |
158 | 162 | | |
159 | 163 | | |
160 | | - | |
| 164 | + | |
| 165 | + | |
161 | 166 | | |
162 | 167 | | |
| 168 | + | |
| 169 | + | |
| 170 | + | |
| 171 | + | |
| 172 | + | |
163 | 173 | | |
164 | 174 | | |
165 | 175 | | |
| |||
198 | 208 | | |
199 | 209 | | |
200 | 210 | | |
201 | | - | |
| 211 | + | |
| 212 | + | |
202 | 213 | | |
203 | 214 | | |
204 | 215 | | |
205 | 216 | | |
206 | 217 | | |
207 | 218 | | |
| 219 | + | |
| 220 | + | |
| 221 | + | |
| 222 | + | |
| 223 | + | |
| 224 | + | |
| 225 | + | |
| 226 | + | |
| 227 | + | |
| 228 | + | |
| 229 | + | |
| 230 | + | |
| 231 | + | |
| 232 | + | |
| 233 | + | |
| 234 | + | |
208 | 235 | | |
209 | 236 | | |
210 | 237 | | |
211 | | - | |
| 238 | + | |
| 239 | + | |
212 | 240 | | |
213 | 241 | | |
214 | 242 | | |
| |||
484 | 512 | | |
485 | 513 | | |
486 | 514 | | |
| 515 | + | |
| 516 | + | |
| 517 | + | |
| 518 | + | |
| 519 | + | |
| 520 | + | |
| 521 | + | |
| 522 | + | |
| 523 | + | |
| 524 | + | |
| 525 | + | |
| 526 | + | |
| 527 | + | |
| 528 | + | |
| 529 | + | |
| 530 | + | |
| 531 | + | |
| 532 | + | |
| 533 | + | |
| 534 | + | |
| 535 | + | |
| 536 | + | |
| 537 | + | |
| 538 | + | |
| 539 | + | |
| 540 | + | |
| 541 | + | |
| 542 | + | |
| 543 | + | |
| 544 | + | |
| 545 | + | |
| 546 | + | |
| 547 | + | |
| 548 | + | |
| 549 | + | |
| 550 | + | |
| 551 | + | |
| 552 | + | |
| 553 | + | |
| 554 | + | |
| 555 | + | |
| 556 | + | |
| 557 | + | |
| 558 | + | |
| 559 | + | |
| 560 | + | |
| 561 | + | |
| 562 | + | |
| 563 | + | |
| 564 | + | |
| 565 | + | |
| 566 | + | |
| 567 | + | |
| 568 | + | |
| 569 | + | |
| 570 | + | |
| 571 | + | |
| 572 | + | |
| 573 | + | |
| 574 | + | |
| 575 | + | |
487 | 576 | | |
488 | 577 | | |
489 | 578 | | |
| |||
0 commit comments