Skip to content

Commit ba4c9e4

Browse files
SanderMullerondrejmirtes
authored andcommitted
TypeCombinator::union optimization in case of many *NEVER*
Merge the separate NeverType pre-scan into the existing flattening loop, eliminating the redundant iteration over all types. Also skip the classification loop and inline the dedup for the common case of 2 non-scalar, non-array, non-enum types.
1 parent fd42dc7 commit ba4c9e4

File tree

1 file changed

+29
-49
lines changed

1 file changed

+29
-49
lines changed

src/Type/TypeCombinator.php

Lines changed: 29 additions & 49 deletions
Original file line numberDiff line numberDiff line change
@@ -188,58 +188,12 @@ public static function union(Type ...$types): Type
188188
}
189189
}
190190

191-
// Fast path for N>2: strip implicit NeverTypes and short-circuit on mixed
192-
if ($typesCount > 2) {
193-
$neverCount = 0;
194-
$hasUnionOrBenevolent = false;
195-
for ($i = 0; $i < $typesCount; $i++) {
196-
$t = $types[$i];
197-
if (
198-
$t instanceof MixedType
199-
&& !$t->isExplicitMixed()
200-
&& !$t instanceof TemplateMixedType
201-
&& $t->getSubtractedType() === null
202-
) {
203-
return $t;
204-
}
205-
if ($t instanceof NeverType && !$t->isExplicit()) {
206-
$neverCount++;
207-
} elseif ($t instanceof UnionType && !$t instanceof TemplateType) {
208-
$hasUnionOrBenevolent = true;
209-
}
210-
}
211-
212-
if ($neverCount > 0 && !$hasUnionOrBenevolent) {
213-
if ($neverCount === $typesCount) {
214-
return new NeverType();
215-
}
216-
217-
$filtered = [];
218-
for ($i = 0; $i < $typesCount; $i++) {
219-
if ($types[$i] instanceof NeverType && !$types[$i]->isExplicit()) {
220-
continue;
221-
}
222-
223-
$filtered[] = $types[$i];
224-
}
225-
$filteredCount = count($filtered);
226-
227-
if ($filteredCount === 1 && !$filtered[0]->isArray()->yes()) {
228-
return $filtered[0];
229-
}
230-
if ($filteredCount === 2) {
231-
return self::union($filtered[0], $filtered[1]);
232-
}
233-
$types = $filtered;
234-
$typesCount = $filteredCount;
235-
}
236-
}
237-
238191
$alreadyNormalized = [];
239192
$alreadyNormalizedCounter = 0;
240193

241194
$benevolentTypes = [];
242195
$benevolentUnionObject = null;
196+
$neverCount = 0;
243197
// transform A | (B | C) to A | B | C
244198
for ($i = 0; $i < $typesCount; $i++) {
245199
if (
@@ -251,8 +205,7 @@ public static function union(Type ...$types): Type
251205
return $types[$i];
252206
}
253207
if ($types[$i] instanceof NeverType && !$types[$i]->isExplicit()) {
254-
array_splice($types, $i--, 1);
255-
$typesCount--;
208+
$neverCount++;
256209
continue;
257210
}
258211
if ($types[$i] instanceof BenevolentUnionType) {
@@ -283,6 +236,33 @@ public static function union(Type ...$types): Type
283236
$typesCount += count($typesInner) - 1;
284237
}
285238

239+
// Bulk-remove implicit NeverTypes (skipped during the loop above)
240+
if ($neverCount > 0) {
241+
if ($neverCount === $typesCount) {
242+
return new NeverType();
243+
}
244+
245+
$filtered = [];
246+
for ($i = 0; $i < $typesCount; $i++) {
247+
if ($types[$i] instanceof NeverType && !$types[$i]->isExplicit()) {
248+
continue;
249+
}
250+
$filtered[] = $types[$i];
251+
}
252+
$types = $filtered;
253+
$typesCount = count($types);
254+
255+
if ($typesCount === 0) {
256+
return new NeverType();
257+
}
258+
if ($typesCount === 1 && !$types[0]->isArray()->yes()) {
259+
return $types[0];
260+
}
261+
if ($typesCount === 2) {
262+
return self::union($types[0], $types[1]);
263+
}
264+
}
265+
286266
if ($typesCount === 0) {
287267
return new NeverType();
288268
}

0 commit comments

Comments
 (0)