From 5b10da3b5e1f68b0c5c2d4ba782c6661e3dadf02 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Tue, 5 Nov 2024 16:07:07 +0100 Subject: [PATCH 1/2] Introduce filterTypes --- src/Analyser/MutatingScope.php | 62 +++++----------------------------- src/Type/UnionType.php | 22 ++++++++++++ 2 files changed, 30 insertions(+), 54 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 90b3fdd465..3e1292f2be 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -5594,18 +5594,10 @@ private function exactInstantiation(New_ $node, string $className): ?Type private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): ?Type { if ($typeWithMethod instanceof UnionType) { - $newTypes = []; - foreach ($typeWithMethod->getTypes() as $innerType) { - if (!$innerType->hasMethod($methodName)->yes()) { - continue; - } - - $newTypes[] = $innerType; - } - if (count($newTypes) === 0) { + $typeWithMethod = $typeWithMethod->filterTypes(fn (Type $innerType) => $innerType->hasMethod($methodName)->yes()); + if ($typeWithMethod === null) { return null; } - $typeWithMethod = TypeCombinator::union(...$newTypes); } if (!$typeWithMethod->hasMethod($methodName)->yes()) { @@ -5709,18 +5701,10 @@ private function methodCallReturnType(Type $typeWithMethod, string $methodName, public function getPropertyReflection(Type $typeWithProperty, string $propertyName): ?ExtendedPropertyReflection { if ($typeWithProperty instanceof UnionType) { - $newTypes = []; - foreach ($typeWithProperty->getTypes() as $innerType) { - if (!$innerType->hasProperty($propertyName)->yes()) { - continue; - } - - $newTypes[] = $innerType; - } - if (count($newTypes) === 0) { + $typeWithProperty = $typeWithProperty->filterTypes(fn (Type $innerType) => $innerType->hasProperty($propertyName)->yes()); + if ($typeWithProperty === null) { return null; } - $typeWithProperty = TypeCombinator::union(...$newTypes); } if (!$typeWithProperty->hasProperty($propertyName)->yes()) { return null; @@ -5749,18 +5733,10 @@ private function propertyFetchType(Type $fetchedOnType, string $propertyName, Ex public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ConstantReflection { if ($typeWithConstant instanceof UnionType) { - $newTypes = []; - foreach ($typeWithConstant->getTypes() as $innerType) { - if (!$innerType->hasConstant($constantName)->yes()) { - continue; - } - - $newTypes[] = $innerType; - } - if (count($newTypes) === 0) { + $typeWithConstant = $typeWithConstant->filterTypes(fn (Type $innerType) => $innerType->hasConstant($constantName)->yes()); + if ($typeWithConstant === null) { return null; } - $typeWithConstant = TypeCombinator::union(...$newTypes); } if (!$typeWithConstant->hasConstant($constantName)->yes()) { return null; @@ -5804,18 +5780,7 @@ private function getNativeConstantTypes(): array public function getIterableKeyType(Type $iteratee): Type { if ($iteratee instanceof UnionType) { - $newTypes = []; - foreach ($iteratee->getTypes() as $innerType) { - if (!$innerType->isIterable()->yes()) { - continue; - } - - $newTypes[] = $innerType; - } - if (count($newTypes) === 0) { - return $iteratee->getIterableKeyType(); - } - $iteratee = TypeCombinator::union(...$newTypes); + $iteratee = $iteratee->filterTypes(fn (Type $innerType) => $innerType->isIterable()->yes()) ?? $iteratee; } return $iteratee->getIterableKeyType(); @@ -5824,18 +5789,7 @@ public function getIterableKeyType(Type $iteratee): Type public function getIterableValueType(Type $iteratee): Type { if ($iteratee instanceof UnionType) { - $newTypes = []; - foreach ($iteratee->getTypes() as $innerType) { - if (!$innerType->isIterable()->yes()) { - continue; - } - - $newTypes[] = $innerType; - } - if (count($newTypes) === 0) { - return $iteratee->getIterableValueType(); - } - $iteratee = TypeCombinator::union(...$newTypes); + $iteratee = $iteratee->filterTypes(fn (Type $innerType) => $innerType->isIterable()->yes()) ?? $iteratee; } return $iteratee->getIterableValueType(); diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index 6b828625b6..a596b5ea4a 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -86,6 +86,28 @@ public function getTypes(): array return $this->types; } + /** + * @param callable(Type $type): bool $filterCb + * + * @return Type|null + */ + public function filterTypes(callable $filterCb): ?Type + { + $newTypes = []; + foreach ($this->getTypes() as $innerType) { + if (!$filterCb($innerType)) { + continue; + } + + $newTypes[] = $innerType; + } + if (count($newTypes) === 0) { + return null; + } + + return TypeCombinator::union(...$newTypes); + } + public function isNormalized(): bool { return $this->normalized; From 6b65db315b7aa407deaf2d145ca38bcd98b1c221 Mon Sep 17 00:00:00 2001 From: Vincent Langlet Date: Tue, 5 Nov 2024 16:39:40 +0100 Subject: [PATCH 2/2] Improve --- src/Analyser/MutatingScope.php | 25 +++++++++++-------------- src/Type/UnionType.php | 7 +------ 2 files changed, 12 insertions(+), 20 deletions(-) diff --git a/src/Analyser/MutatingScope.php b/src/Analyser/MutatingScope.php index 3e1292f2be..c24defb1f8 100644 --- a/src/Analyser/MutatingScope.php +++ b/src/Analyser/MutatingScope.php @@ -5594,10 +5594,7 @@ private function exactInstantiation(New_ $node, string $className): ?Type private function filterTypeWithMethod(Type $typeWithMethod, string $methodName): ?Type { if ($typeWithMethod instanceof UnionType) { - $typeWithMethod = $typeWithMethod->filterTypes(fn (Type $innerType) => $innerType->hasMethod($methodName)->yes()); - if ($typeWithMethod === null) { - return null; - } + $typeWithMethod = $typeWithMethod->filterTypes(static fn (Type $innerType) => $innerType->hasMethod($methodName)->yes()); } if (!$typeWithMethod->hasMethod($methodName)->yes()) { @@ -5701,10 +5698,7 @@ private function methodCallReturnType(Type $typeWithMethod, string $methodName, public function getPropertyReflection(Type $typeWithProperty, string $propertyName): ?ExtendedPropertyReflection { if ($typeWithProperty instanceof UnionType) { - $typeWithProperty = $typeWithProperty->filterTypes(fn (Type $innerType) => $innerType->hasProperty($propertyName)->yes()); - if ($typeWithProperty === null) { - return null; - } + $typeWithProperty = $typeWithProperty->filterTypes(static fn (Type $innerType) => $innerType->hasProperty($propertyName)->yes()); } if (!$typeWithProperty->hasProperty($propertyName)->yes()) { return null; @@ -5733,10 +5727,7 @@ private function propertyFetchType(Type $fetchedOnType, string $propertyName, Ex public function getConstantReflection(Type $typeWithConstant, string $constantName): ?ConstantReflection { if ($typeWithConstant instanceof UnionType) { - $typeWithConstant = $typeWithConstant->filterTypes(fn (Type $innerType) => $innerType->hasConstant($constantName)->yes()); - if ($typeWithConstant === null) { - return null; - } + $typeWithConstant = $typeWithConstant->filterTypes(static fn (Type $innerType) => $innerType->hasConstant($constantName)->yes()); } if (!$typeWithConstant->hasConstant($constantName)->yes()) { return null; @@ -5780,7 +5771,10 @@ private function getNativeConstantTypes(): array public function getIterableKeyType(Type $iteratee): Type { if ($iteratee instanceof UnionType) { - $iteratee = $iteratee->filterTypes(fn (Type $innerType) => $innerType->isIterable()->yes()) ?? $iteratee; + $filtered = $iteratee->filterTypes(static fn (Type $innerType) => $innerType->isIterable()->yes()); + if (!$filtered instanceof NeverType) { + $iteratee = $filtered; + } } return $iteratee->getIterableKeyType(); @@ -5789,7 +5783,10 @@ public function getIterableKeyType(Type $iteratee): Type public function getIterableValueType(Type $iteratee): Type { if ($iteratee instanceof UnionType) { - $iteratee = $iteratee->filterTypes(fn (Type $innerType) => $innerType->isIterable()->yes()) ?? $iteratee; + $filtered = $iteratee->filterTypes(static fn (Type $innerType) => $innerType->isIterable()->yes()); + if (!$filtered instanceof NeverType) { + $iteratee = $filtered; + } } return $iteratee->getIterableValueType(); diff --git a/src/Type/UnionType.php b/src/Type/UnionType.php index a596b5ea4a..b7e794378a 100644 --- a/src/Type/UnionType.php +++ b/src/Type/UnionType.php @@ -88,10 +88,8 @@ public function getTypes(): array /** * @param callable(Type $type): bool $filterCb - * - * @return Type|null */ - public function filterTypes(callable $filterCb): ?Type + public function filterTypes(callable $filterCb): Type { $newTypes = []; foreach ($this->getTypes() as $innerType) { @@ -101,9 +99,6 @@ public function filterTypes(callable $filterCb): ?Type $newTypes[] = $innerType; } - if (count($newTypes) === 0) { - return null; - } return TypeCombinator::union(...$newTypes); }