diff --git a/docs/component/type.md b/docs/component/type.md index 2b0a4f3d..ae6031c0 100644 --- a/docs/component/type.md +++ b/docs/component/type.md @@ -17,7 +17,7 @@ - [dict](./../../src/Psl/Type/dict.php#L20) - [float](./../../src/Psl/Type/float.php#L10) - [int](./../../src/Psl/Type/int.php#L10) -- [intersection](./../../src/Psl/Type/intersection.php#L20) +- [intersection](./../../src/Psl/Type/intersection.php#L22) - [is_array](./../../src/Psl/Type/is_array.php#L20) ( deprecated ) - [is_arraykey](./../../src/Psl/Type/is_arraykey.php#L18) ( deprecated ) - [is_bool](./../../src/Psl/Type/is_bool.php#L20) ( deprecated ) diff --git a/src/Psl/Type/intersection.php b/src/Psl/Type/intersection.php index 2399ab1c..1a5a2e3d 100644 --- a/src/Psl/Type/intersection.php +++ b/src/Psl/Type/intersection.php @@ -7,20 +7,29 @@ use Psl; /** - * @template Tl - * @template Tr + * @template TFirst + * @template TSecond + * @template TRest * - * @param TypeInterface $left_type - * @param TypeInterface $right_type + * @param TypeInterface $first + * @param TypeInterface $second + * @param TypeInterface ...$rest * - * @throws Psl\Exception\InvariantViolationException If $left_type, or $right_type is optional. + * @throws Psl\Exception\InvariantViolationException If $first, $second or one of $rest is optional. * - * @return TypeInterface + * @return TypeInterface */ function intersection( - TypeInterface $left_type, - TypeInterface $right_type + TypeInterface $first, + TypeInterface $second, + TypeInterface ...$rest ): TypeInterface { - /** @var TypeInterface */ - return new Internal\IntersectionType($left_type, $right_type); + $accumulated_type = new Internal\IntersectionType($first, $second); + + foreach ($rest as $type) { + $accumulated_type = new Internal\IntersectionType($accumulated_type, $type); + } + + /** @var TypeInterface */ + return $accumulated_type; } diff --git a/tests/static-analysis/Type/intersection.php b/tests/static-analysis/Type/intersection.php new file mode 100644 index 00000000..581ecce9 --- /dev/null +++ b/tests/static-analysis/Type/intersection.php @@ -0,0 +1,46 @@ +assert('any')); + + /** @psalm-suppress MissingThrowsDocblock */ + takes_valid_intersection($new_codec->assert('any')); +} diff --git a/tests/unit/Type/IntersectionTypeTest.php b/tests/unit/Type/IntersectionTypeTest.php index e32dfe83..80a53f5e 100644 --- a/tests/unit/Type/IntersectionTypeTest.php +++ b/tests/unit/Type/IntersectionTypeTest.php @@ -13,7 +13,7 @@ final class IntersectionTypeTest extends TypeTest { public function testIntersectionLeft(): void { - $intersection = Type\intersection(Type\array_key(), Type\int()); + $intersection = Type\intersection(Type\array_key(), Type\int(), Type\positive_int()); static::assertSame(1, $intersection->coerce('1')); } @@ -53,14 +53,36 @@ public function getToStringExamples(): iterable 'Psl\Collection\IndexAccessInterface&Psl\Collection\CollectionInterface' ]; - yield [Type\intersection( - Type\object(IndexAccessInterface::class), - Type\union(Type\object(CollectionInterface::class), Type\object(Iterator::class)) - ), 'Psl\Collection\IndexAccessInterface&(Psl\Collection\CollectionInterface|Iterator)']; + yield [ + Type\intersection( + Type\object(IndexAccessInterface::class), + Type\union( + Type\object(CollectionInterface::class), + Type\object(Iterator::class) + ) + ), + 'Psl\Collection\IndexAccessInterface&(Psl\Collection\CollectionInterface|Iterator)' + ]; - yield [Type\intersection( - Type\union(Type\object(CollectionInterface::class), Type\object(Iterator::class)), - Type\object(IndexAccessInterface::class) - ), '(Psl\Collection\CollectionInterface|Iterator)&Psl\Collection\IndexAccessInterface']; + yield [ + Type\intersection( + Type\union( + Type\object(CollectionInterface::class), + Type\object(Iterator::class) + ), + Type\object(IndexAccessInterface::class) + ), + '(Psl\Collection\CollectionInterface|Iterator)&Psl\Collection\IndexAccessInterface' + ]; + + yield [ + Type\intersection( + Type\object(IndexAccessInterface::class), + Type\object(CollectionInterface::class), + Type\object(Iterator::class), + Type\shape(['id' => Type\string()]), + ), + 'Psl\Collection\IndexAccessInterface&Psl\Collection\CollectionInterface&Iterator&array{\'id\': string}' + ]; } }