From c24ba1ce7dcbbde38f04c4de1ef631b1b18776d7 Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 10 Feb 2026 06:17:57 +0700 Subject: [PATCH 1/3] Fix unioned intersection on Assert Filter --- src/Assert/Filter.php | 10 ++++++++-- tests/FilterTest.php | 17 +++++++++++++++++ 2 files changed, 25 insertions(+), 2 deletions(-) diff --git a/src/Assert/Filter.php b/src/Assert/Filter.php index 4f765f9..46d0010 100644 --- a/src/Assert/Filter.php +++ b/src/Assert/Filter.php @@ -42,13 +42,19 @@ public static function boolean(callable $filter): void $separator = $returnType instanceof ReflectionUnionType ? '|' : '&'; $types = $returnType->getTypes(); - Assert::allIsInstanceOf($types, ReflectionNamedType::class); + Assert::allIsInstanceOfAny($types, [ReflectionNamedType::class, ReflectionIntersectionType::class]); throw new InvalidArgumentException( sprintf( self::MESSAGE, implode($separator, array_map( - static fn (ReflectionNamedType $reflectionNamedType): string => $reflectionNamedType->getName(), + static fn (ReflectionNamedType|ReflectionIntersectionType $reflectionType): string => + $reflectionType instanceof ReflectionNamedType + ? $reflectionType->getName() + : '(' . implode('&', array_map( + static fn (ReflectionNamedType $reflectionNamedType): string => $reflectionNamedType->getName(), + $reflectionType->getTypes() + )) . ')', $types )) ) diff --git a/tests/FilterTest.php b/tests/FilterTest.php index 3256e9d..b9ecad0 100644 --- a/tests/FilterTest.php +++ b/tests/FilterTest.php @@ -133,4 +133,21 @@ public function __invoke(int $datum): A&B AtLeast::once($data, $filter); } + + public function testWithUnionedIntersectionTypeCallable(): void + { + $this->expectException(InvalidArgumentException::class); + $this->expectExceptionMessage( + 'Expected a bool return type on callable filter, (ArrayLookup\Tests\A&ArrayLookup\Tests\B)|string given' + ); + + $data = [1, 2, 3]; + $filter = new class { + public function __invoke(int $datum): (A&B)|string + { + } + }; + + AtLeast::once($data, $filter); + } } From c9b0142449f5f86490d010066ec5641490ba518a Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 10 Feb 2026 06:20:36 +0700 Subject: [PATCH 2/3] cs fix --- src/Assert/Filter.php | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/src/Assert/Filter.php b/src/Assert/Filter.php index 46d0010..17fe103 100644 --- a/src/Assert/Filter.php +++ b/src/Assert/Filter.php @@ -52,7 +52,8 @@ public static function boolean(callable $filter): void $reflectionType instanceof ReflectionNamedType ? $reflectionType->getName() : '(' . implode('&', array_map( - static fn (ReflectionNamedType $reflectionNamedType): string => $reflectionNamedType->getName(), + static fn (ReflectionNamedType $reflectionNamedType): string + => $reflectionNamedType->getName(), $reflectionType->getTypes() )) . ')', $types From 6b3397a916321ddd76575002100c2ff4be02c1ff Mon Sep 17 00:00:00 2001 From: Abdul Malik Ikhsan Date: Tue, 10 Feb 2026 06:25:32 +0700 Subject: [PATCH 3/3] fix phpstan --- src/Assert/Filter.php | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/src/Assert/Filter.php b/src/Assert/Filter.php index 17fe103..2e6a79b 100644 --- a/src/Assert/Filter.php +++ b/src/Assert/Filter.php @@ -48,14 +48,20 @@ public static function boolean(callable $filter): void sprintf( self::MESSAGE, implode($separator, array_map( - static fn (ReflectionNamedType|ReflectionIntersectionType $reflectionType): string => - $reflectionType instanceof ReflectionNamedType - ? $reflectionType->getName() - : '(' . implode('&', array_map( - static fn (ReflectionNamedType $reflectionNamedType): string - => $reflectionNamedType->getName(), - $reflectionType->getTypes() - )) . ')', + function (ReflectionNamedType|ReflectionIntersectionType $reflectionType): string { + if ($reflectionType instanceof ReflectionNamedType) { + return $reflectionType->getName(); + } + + $subTypes = $reflectionType->getTypes(); + Assert::allIsInstanceOf($subTypes, ReflectionNamedType::class); + + return '(' . implode('&', array_map( + static fn (ReflectionNamedType $reflectionNamedType): string + => $reflectionNamedType->getName(), + $subTypes + )) . ')'; + }, $types )) )