Skip to content

Commit 3c61234

Browse files
committed
TypeCombinator::union optimization in case of many *NEVER*
1 parent e0ce431 commit 3c61234

File tree

1 file changed

+55
-0
lines changed

1 file changed

+55
-0
lines changed

src/Type/TypeCombinator.php

Lines changed: 55 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -153,6 +153,14 @@ public static function union(Type ...$types): Type
153153
return new NeverType();
154154
}
155155

156+
// Fast path for single non-union type
157+
if ($typesCount === 1) {
158+
$singleType = $types[0];
159+
if (!$singleType instanceof UnionType && !$singleType->isArray()->yes()) {
160+
return $singleType;
161+
}
162+
}
163+
156164
// Fast path for common 2-type cases
157165
if ($typesCount === 2) {
158166
$a = $types[0];
@@ -180,6 +188,53 @@ public static function union(Type ...$types): Type
180188
}
181189
}
182190

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+
183238
$alreadyNormalized = [];
184239
$alreadyNormalizedCounter = 0;
185240

0 commit comments

Comments
 (0)