Skip to content

Commit 1bbe9dc

Browse files
authored
Prevent unnecessary work in IntersectionType
1 parent 0b8e988 commit 1bbe9dc

File tree

3 files changed

+76
-2
lines changed

3 files changed

+76
-2
lines changed

src/Type/AcceptsResult.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -152,4 +152,37 @@ public static function maxMin(self ...$operands): self
152152
return new self(TrinaryLogic::maxMin(...$results), array_values(array_unique($reasons)));
153153
}
154154

155+
/**
156+
* @template T
157+
* @param T[] $objects
158+
* @param callable(T): self $callback
159+
*/
160+
public static function lazyMaxMin(
161+
array $objects,
162+
callable $callback,
163+
): self
164+
{
165+
$results = [];
166+
$reasons = [];
167+
$hasNo = false;
168+
foreach ($objects as $object) {
169+
$isAcceptedBy = $callback($object);
170+
if ($isAcceptedBy->result->yes()) {
171+
return $isAcceptedBy;
172+
} elseif ($isAcceptedBy->result->no()) {
173+
$hasNo = true;
174+
}
175+
$results[] = $isAcceptedBy;
176+
177+
foreach ($isAcceptedBy->reasons as $reason) {
178+
$reasons[] = $reason;
179+
}
180+
}
181+
182+
return new self(
183+
$hasNo ? TrinaryLogic::createNo() : TrinaryLogic::createMaybe(),
184+
array_values(array_unique($reasons)),
185+
);
186+
}
187+
155188
}

src/Type/IntersectionType.php

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -266,7 +266,11 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
266266
return $otherType->isSuperTypeOf($this);
267267
}
268268

269-
$result = IsSuperTypeOfResult::maxMin(...array_map(static fn (Type $innerType) => $otherType->isSuperTypeOf($innerType), $this->types));
269+
$result = IsSuperTypeOfResult::lazyMaxMin(
270+
$this->types,
271+
static fn (Type $innerType) => $otherType->isSuperTypeOf($innerType),
272+
);
273+
270274
if (
271275
!$result->no()
272276
&& $this->isOversizedArray()->yes()
@@ -280,7 +284,11 @@ public function isSubTypeOf(Type $otherType): IsSuperTypeOfResult
280284

281285
public function isAcceptedBy(Type $acceptingType, bool $strictTypes): AcceptsResult
282286
{
283-
$result = AcceptsResult::maxMin(...array_map(static fn (Type $innerType) => $acceptingType->accepts($innerType, $strictTypes), $this->types));
287+
$result = AcceptsResult::lazyMaxMin(
288+
$this->types,
289+
static fn (Type $innerType) => $acceptingType->accepts($innerType, $strictTypes),
290+
);
291+
284292
if ($this->isOversizedArray()->yes()) {
285293
if (!$result->no()) {
286294
return AcceptsResult::createYes();

src/Type/IsSuperTypeOfResult.php

Lines changed: 33 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -185,6 +185,39 @@ public static function maxMin(self ...$operands): self
185185
return new self(TrinaryLogic::maxMin(...$results), array_values(array_unique($reasons)));
186186
}
187187

188+
/**
189+
* @template T
190+
* @param T[] $objects
191+
* @param callable(T): self $callback
192+
*/
193+
public static function lazyMaxMin(
194+
array $objects,
195+
callable $callback,
196+
): self
197+
{
198+
$results = [];
199+
$reasons = [];
200+
$hasNo = false;
201+
foreach ($objects as $object) {
202+
$isSuperTypeOf = $callback($object);
203+
if ($isSuperTypeOf->result->yes()) {
204+
return $isSuperTypeOf;
205+
} elseif ($isSuperTypeOf->result->no()) {
206+
$hasNo = true;
207+
}
208+
$results[] = $isSuperTypeOf;
209+
210+
foreach ($isSuperTypeOf->reasons as $reason) {
211+
$reasons[] = $reason;
212+
}
213+
}
214+
215+
return new self(
216+
$hasNo ? TrinaryLogic::createNo() : TrinaryLogic::createMaybe(),
217+
array_values(array_unique($reasons)),
218+
);
219+
}
220+
188221
public function negate(): self
189222
{
190223
return new self($this->result->negate(), $this->reasons);

0 commit comments

Comments
 (0)