From 2dce25805e604794235dba39d660e30b5aea51f1 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Fri, 28 Nov 2025 12:49:45 +0400 Subject: [PATCH 1/4] Fix the conversion of lists to strings --- src/PseudoTypes/List_.php | 2 +- src/PseudoTypes/NonEmptyArray.php | 2 +- src/PseudoTypes/NonEmptyList.php | 2 +- src/Types/AbstractList.php | 19 +++++---- src/Types/Iterable_.php | 2 +- tests/unit/PseudoTypes/ListTest.php | 2 +- tests/unit/PseudoTypes/NonEmptyArrayTest.php | 2 +- tests/unit/PseudoTypes/NonEmptyListTest.php | 2 +- tests/unit/TypeResolverTest.php | 26 ++++++++++++ tests/unit/Types/ArrayTest.php | 43 +++++++++++++++++++- tests/unit/Types/IterableTest.php | 2 +- 11 files changed, 88 insertions(+), 16 deletions(-) diff --git a/src/PseudoTypes/List_.php b/src/PseudoTypes/List_.php index f9f0c6b..5db50d0 100644 --- a/src/PseudoTypes/List_.php +++ b/src/PseudoTypes/List_.php @@ -41,7 +41,7 @@ public function __construct(?Type $valueType = null) */ public function __toString(): string { - if ($this->valueType instanceof Mixed_) { + if ($this->valueType === null) { return 'list'; } diff --git a/src/PseudoTypes/NonEmptyArray.php b/src/PseudoTypes/NonEmptyArray.php index f0cc4a6..4aca454 100644 --- a/src/PseudoTypes/NonEmptyArray.php +++ b/src/PseudoTypes/NonEmptyArray.php @@ -39,7 +39,7 @@ public function __toString(): string return 'non-empty-array<' . $this->keyType . ',' . $this->valueType . '>'; } - if ($this->valueType instanceof Mixed_) { + if ($this->valueType === null) { return 'non-empty-array'; } diff --git a/src/PseudoTypes/NonEmptyList.php b/src/PseudoTypes/NonEmptyList.php index 384b629..afcbeee 100644 --- a/src/PseudoTypes/NonEmptyList.php +++ b/src/PseudoTypes/NonEmptyList.php @@ -41,7 +41,7 @@ public function __construct(?Type $valueType = null) */ public function __toString(): string { - if ($this->valueType instanceof Mixed_) { + if ($this->valueType === null) { return 'non-empty-list'; } diff --git a/src/Types/AbstractList.php b/src/Types/AbstractList.php index d5fe03d..fa24390 100644 --- a/src/Types/AbstractList.php +++ b/src/Types/AbstractList.php @@ -22,7 +22,7 @@ */ abstract class AbstractList implements Type { - /** @var Type */ + /** @var Type|null */ protected $valueType; /** @var Type|null */ @@ -31,15 +31,15 @@ abstract class AbstractList implements Type /** @var Type */ protected $defaultKeyType; + /** @var Type */ + protected $defaultValueType; + /** * Initializes this representation of an array with the given Type. */ public function __construct(?Type $valueType = null, ?Type $keyType = null) { - if ($valueType === null) { - $valueType = new Mixed_(); - } - + $this->defaultValueType = new Mixed_(); $this->valueType = $valueType; $this->defaultKeyType = new Compound([new String_(), new Integer()]); $this->keyType = $keyType; @@ -50,6 +50,11 @@ public function getOriginalKeyType(): ?Type return $this->keyType; } + public function getOriginalValueType(): ?Type + { + return $this->valueType; + } + /** * Returns the type for the keys of this array. */ @@ -63,7 +68,7 @@ public function getKeyType(): Type */ public function getValueType(): Type { - return $this->valueType; + return $this->valueType ?? $this->defaultValueType; } /** @@ -75,7 +80,7 @@ public function __toString(): string return 'array<' . $this->keyType . ',' . $this->valueType . '>'; } - if ($this->valueType instanceof Mixed_) { + if ($this->valueType === null) { return 'array'; } diff --git a/src/Types/Iterable_.php b/src/Types/Iterable_.php index 1ca069f..36bc6a6 100644 --- a/src/Types/Iterable_.php +++ b/src/Types/Iterable_.php @@ -29,7 +29,7 @@ public function __toString(): string return 'iterable<' . $this->keyType . ',' . $this->valueType . '>'; } - if ($this->valueType instanceof Mixed_) { + if ($this->valueType === null) { return 'iterable'; } diff --git a/tests/unit/PseudoTypes/ListTest.php b/tests/unit/PseudoTypes/ListTest.php index aca7db8..ebd5676 100644 --- a/tests/unit/PseudoTypes/ListTest.php +++ b/tests/unit/PseudoTypes/ListTest.php @@ -40,7 +40,7 @@ public function provideArrays(): array { return [ 'simple list' => [new List_(), 'list'], - 'list of mixed' => [new List_(new Mixed_()), 'list'], + 'list of mixed' => [new List_(new Mixed_()), 'list'], 'list of single type' => [new List_(new String_()), 'list'], 'list of compound type' => [new List_(new Compound([new Integer(), new String_()])), 'list'], ]; diff --git a/tests/unit/PseudoTypes/NonEmptyArrayTest.php b/tests/unit/PseudoTypes/NonEmptyArrayTest.php index 5d7e508..b151129 100644 --- a/tests/unit/PseudoTypes/NonEmptyArrayTest.php +++ b/tests/unit/PseudoTypes/NonEmptyArrayTest.php @@ -40,7 +40,7 @@ public function provideArrays(): array { return [ 'simple non-empty-array' => [new NonEmptyArray(), 'non-empty-array'], - 'non-empty-array of mixed' => [new NonEmptyArray(new Mixed_()), 'non-empty-array'], + 'non-empty-array of mixed' => [new NonEmptyArray(new Mixed_()), 'non-empty-array'], 'non-empty-array of single type' => [new NonEmptyArray(new String_()), 'non-empty-array'], 'non-empty-array of compound type' => [ diff --git a/tests/unit/PseudoTypes/NonEmptyListTest.php b/tests/unit/PseudoTypes/NonEmptyListTest.php index a576f95..8f14405 100644 --- a/tests/unit/PseudoTypes/NonEmptyListTest.php +++ b/tests/unit/PseudoTypes/NonEmptyListTest.php @@ -40,7 +40,7 @@ public function provideArrays(): array { return [ 'simple non-empty-list' => [new NonEmptyList(), 'non-empty-list'], - 'non-empty-list of mixed' => [new NonEmptyList(new Mixed_()), 'non-empty-list'], + 'non-empty-list of mixed' => [new NonEmptyList(new Mixed_()), 'non-empty-list'], 'non-empty-list of single type' => [new NonEmptyList(new String_()), 'non-empty-list'], 'non-empty-list of compound type' => [new NonEmptyList(new Compound([new Integer(), new String_()])), 'non-empty-list'], diff --git a/tests/unit/TypeResolverTest.php b/tests/unit/TypeResolverTest.php index a79fd9f..56cc23c 100644 --- a/tests/unit/TypeResolverTest.php +++ b/tests/unit/TypeResolverTest.php @@ -982,12 +982,22 @@ public function typeProvider(): array ), ]), ], + [ + 'array', + new Array_(), + ], [ 'string[]', new Array_( new String_() ), ], + [ + 'mixed[]', + new Array_( + new Mixed_() + ), + ], [ '$this', new This(), @@ -1178,6 +1188,22 @@ public function genericsProvider(): array new Object_(new Fqsen('\\phpDocumentor\\ThirdClass')), ), ], + [ + 'array', + new Array_(new Mixed_()), + ], + [ + 'iterable', + new Iterable_(new Mixed_()), + ], + [ + 'non-empty-array', + new NonEmptyArray(new Mixed_()), + ], + [ + 'non-empty-list', + new NonEmptyList(new Mixed_()), + ], ]; } diff --git a/tests/unit/Types/ArrayTest.php b/tests/unit/Types/ArrayTest.php index 88117c1..ba3ad41 100644 --- a/tests/unit/Types/ArrayTest.php +++ b/tests/unit/Types/ArrayTest.php @@ -13,6 +13,7 @@ namespace phpDocumentor\Reflection\Types; +use phpDocumentor\Reflection\Fqsen; use PHPUnit\Framework\TestCase; /** @@ -20,6 +21,46 @@ */ class ArrayTest extends TestCase { + /** + * @covers ::getOriginalKeyType + * @covers ::getOriginalValueType + * @covers ::getKeyType + * @covers ::getValueType + */ + public function testCreateWithoutParams(): void + { + $type = new Array_(); + + $this->assertNull($type->getOriginalKeyType()); + $this->assertNull($type->getOriginalValueType()); + $this->assertEquals(new Compound([new String_(), new Integer()]), $type->getKeyType()); + $this->assertEquals(new Mixed_(), $type->getValueType()); + } + + /** + * @covers ::getOriginalKeyType + * @covers ::getOriginalValueType + * @covers ::getKeyType + * @covers ::getValueType + */ + public function testCreateWithParams(): void + { + $valueType = new Object_(new Fqsen('\\phpDocumentor\\Foo\\Bar')); + $keyType = new Compound( + [ + new String_(), + new Integer(), + ] + ); + + $type = new Array_($valueType, $keyType); + + $this->assertSame($keyType, $type->getOriginalKeyType()); + $this->assertSame($valueType, $type->getOriginalValueType()); + $this->assertSame($keyType, $type->getKeyType()); + $this->assertSame($valueType, $type->getValueType()); + } + /** * @dataProvider provideArrays * @covers ::__toString @@ -36,7 +77,7 @@ public function provideArrays(): array { return [ 'simple array' => [new Array_(), 'array'], - 'array of mixed' => [new Array_(new Mixed_()), 'array'], + 'array of mixed' => [new Array_(new Mixed_()), 'mixed[]'], 'array of single type' => [new Array_(new String_()), 'string[]'], 'array of compound type' => [new Array_(new Compound([new Integer(), new String_()])), '(int|string)[]'], 'array with key type' => [new Array_(new String_(), new Integer()), 'array'], diff --git a/tests/unit/Types/IterableTest.php b/tests/unit/Types/IterableTest.php index 6184160..ebbe3f6 100644 --- a/tests/unit/Types/IterableTest.php +++ b/tests/unit/Types/IterableTest.php @@ -36,7 +36,7 @@ public function provideIterables(): array { return [ 'simple iterable' => [new Iterable_(), 'iterable'], - 'iterable of mixed' => [new Iterable_(new Mixed_()), 'iterable'], + 'iterable of mixed' => [new Iterable_(new Mixed_()), 'iterable'], 'iterable of single type' => [new Iterable_(new String_()), 'iterable'], 'iterable of compound type' => [ new Iterable_(new Compound([new Integer(), new String_()])), From 38eee5e976c993d1339eb19f67508f6ab8bd215d Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Fri, 28 Nov 2025 13:14:24 +0400 Subject: [PATCH 2/4] Fix Psalm errors --- src/PseudoTypes/NonEmptyArray.php | 8 ++++---- src/Types/AbstractList.php | 8 ++++---- src/Types/Collection.php | 7 +++++-- src/Types/Iterable_.php | 8 ++++---- 4 files changed, 17 insertions(+), 14 deletions(-) diff --git a/src/PseudoTypes/NonEmptyArray.php b/src/PseudoTypes/NonEmptyArray.php index 4aca454..94c06ff 100644 --- a/src/PseudoTypes/NonEmptyArray.php +++ b/src/PseudoTypes/NonEmptyArray.php @@ -35,14 +35,14 @@ public function underlyingType(): Type */ public function __toString(): string { - if ($this->keyType) { - return 'non-empty-array<' . $this->keyType . ',' . $this->valueType . '>'; - } - if ($this->valueType === null) { return 'non-empty-array'; } + if ($this->keyType) { + return 'non-empty-array<' . $this->keyType . ',' . $this->valueType . '>'; + } + return 'non-empty-array<' . $this->valueType . '>'; } } diff --git a/src/Types/AbstractList.php b/src/Types/AbstractList.php index fa24390..68c1f88 100644 --- a/src/Types/AbstractList.php +++ b/src/Types/AbstractList.php @@ -76,14 +76,14 @@ public function getValueType(): Type */ public function __toString(): string { - if ($this->keyType) { - return 'array<' . $this->keyType . ',' . $this->valueType . '>'; - } - if ($this->valueType === null) { return 'array'; } + if ($this->keyType) { + return 'array<' . $this->keyType . ',' . $this->valueType . '>'; + } + if ($this->valueType instanceof Compound) { return '(' . $this->valueType . ')[]'; } diff --git a/src/Types/Collection.php b/src/Types/Collection.php index 943cc22..3d2a1f5 100644 --- a/src/Types/Collection.php +++ b/src/Types/Collection.php @@ -59,10 +59,13 @@ public function __toString(): string { $objectType = (string) ($this->fqsen ?? 'object'); + /** @var string */ + $valueType = $this->valueType; + if ($this->keyType === null) { - return $objectType . '<' . $this->valueType . '>'; + return $objectType . '<' . $valueType . '>'; } - return $objectType . '<' . $this->keyType . ',' . $this->valueType . '>'; + return $objectType . '<' . $this->keyType . ',' . $valueType . '>'; } } diff --git a/src/Types/Iterable_.php b/src/Types/Iterable_.php index 36bc6a6..f7d2264 100644 --- a/src/Types/Iterable_.php +++ b/src/Types/Iterable_.php @@ -25,14 +25,14 @@ final class Iterable_ extends AbstractList */ public function __toString(): string { - if ($this->keyType) { - return 'iterable<' . $this->keyType . ',' . $this->valueType . '>'; - } - if ($this->valueType === null) { return 'iterable'; } + if ($this->keyType) { + return 'iterable<' . $this->keyType . ',' . $this->valueType . '>'; + } + return 'iterable<' . $this->valueType . '>'; } } From 6e5113b8e480fde1e269ff84c51726a0e76b6fce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Fri, 28 Nov 2025 13:22:56 +0400 Subject: [PATCH 3/4] Fix CS --- src/PseudoTypes/List_.php | 1 - src/PseudoTypes/NonEmptyArray.php | 1 - src/PseudoTypes/NonEmptyList.php | 1 - src/Types/Collection.php | 2 +- 4 files changed, 1 insertion(+), 4 deletions(-) diff --git a/src/PseudoTypes/List_.php b/src/PseudoTypes/List_.php index 5db50d0..3488731 100644 --- a/src/PseudoTypes/List_.php +++ b/src/PseudoTypes/List_.php @@ -17,7 +17,6 @@ use phpDocumentor\Reflection\Type; use phpDocumentor\Reflection\Types\Array_; use phpDocumentor\Reflection\Types\Integer; -use phpDocumentor\Reflection\Types\Mixed_; /** * Value Object representing the type 'list'. diff --git a/src/PseudoTypes/NonEmptyArray.php b/src/PseudoTypes/NonEmptyArray.php index 94c06ff..d353686 100644 --- a/src/PseudoTypes/NonEmptyArray.php +++ b/src/PseudoTypes/NonEmptyArray.php @@ -16,7 +16,6 @@ use phpDocumentor\Reflection\PseudoType; use phpDocumentor\Reflection\Type; use phpDocumentor\Reflection\Types\Array_; -use phpDocumentor\Reflection\Types\Mixed_; /** * Value Object representing the type 'non-empty-array'. diff --git a/src/PseudoTypes/NonEmptyList.php b/src/PseudoTypes/NonEmptyList.php index afcbeee..e44f590 100644 --- a/src/PseudoTypes/NonEmptyList.php +++ b/src/PseudoTypes/NonEmptyList.php @@ -17,7 +17,6 @@ use phpDocumentor\Reflection\Type; use phpDocumentor\Reflection\Types\Array_; use phpDocumentor\Reflection\Types\Integer; -use phpDocumentor\Reflection\Types\Mixed_; /** * Value Object representing the type 'non-empty-list'. diff --git a/src/Types/Collection.php b/src/Types/Collection.php index 3d2a1f5..305b3ac 100644 --- a/src/Types/Collection.php +++ b/src/Types/Collection.php @@ -59,7 +59,7 @@ public function __toString(): string { $objectType = (string) ($this->fqsen ?? 'object'); - /** @var string */ + /** @var string $valueType */ $valueType = $this->valueType; if ($this->keyType === null) { From 7475dd4a05055829de431e694a6306f92d279b3c Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?=D0=9C=D0=B0=D0=BA=D1=81=D0=B8=D0=BC=20=D0=A1=D0=BF=D0=B8?= =?UTF-8?q?=D1=80=D0=BA=D0=BE=D0=B2?= Date: Fri, 28 Nov 2025 13:25:17 +0400 Subject: [PATCH 4/4] Fix CS error --- src/Types/Collection.php | 4 +--- 1 file changed, 1 insertion(+), 3 deletions(-) diff --git a/src/Types/Collection.php b/src/Types/Collection.php index 305b3ac..0963787 100644 --- a/src/Types/Collection.php +++ b/src/Types/Collection.php @@ -58,9 +58,7 @@ public function getFqsen(): ?Fqsen public function __toString(): string { $objectType = (string) ($this->fqsen ?? 'object'); - - /** @var string $valueType */ - $valueType = $this->valueType; + $valueType = $this->getValueType(); if ($this->keyType === null) { return $objectType . '<' . $valueType . '>';