diff --git a/src/Type/ArrayType.php b/src/Type/ArrayType.php index 80cfc6b09f..ffd213eb93 100644 --- a/src/Type/ArrayType.php +++ b/src/Type/ArrayType.php @@ -609,6 +609,10 @@ public function tryRemove(Type $typeToRemove): ?Type return TypeCombinator::intersect($this, new NonEmptyArrayType()); } + if ($typeToRemove->isSuperTypeOf(new ConstantArrayType([], []))->yes()) { + return TypeCombinator::intersect($this, new NonEmptyArrayType()); + } + if ($typeToRemove instanceof NonEmptyArrayType) { return new ConstantArrayType([], []); } diff --git a/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php b/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php index 1b788158d6..d4e1c621d4 100644 --- a/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php +++ b/tests/PHPStan/Analyser/nsrt/array-is-list-type-specifying.php @@ -8,7 +8,7 @@ function foo(array $foo) { if (array_is_list($foo)) { assertType('list', $foo); } else { - assertType('array', $foo); + assertType('non-empty-array', $foo); } } @@ -51,7 +51,7 @@ function foo4(array $foo) { if (array_is_list($foo)) { assertType('list', $foo); } else { - assertType('array', $foo); + assertType('non-empty-array', $foo); } $baz = []; diff --git a/tests/PHPStan/Analyser/nsrt/assert-docblock.php b/tests/PHPStan/Analyser/nsrt/assert-docblock.php index a1cbcc9b3e..459b925ca3 100644 --- a/tests/PHPStan/Analyser/nsrt/assert-docblock.php +++ b/tests/PHPStan/Analyser/nsrt/assert-docblock.php @@ -71,7 +71,7 @@ function takesArrayIfTrue(array $arr) : void { if (validateStringArrayIfTrue($arr)) { assertType('array', $arr); } else { - assertType('array', $arr); + assertType('non-empty-array', $arr); } } /** @@ -81,7 +81,7 @@ function takesArrayIfTrue1(array $arr) : void { assertType('array', $arr); if (!validateStringArrayIfTrue($arr)) { - assertType('array', $arr); + assertType('non-empty-array', $arr); } else { assertType('array', $arr); } @@ -96,7 +96,7 @@ function takesArrayIfFalse(array $arr) : void { if (!validateStringArrayIfFalse($arr)) { assertType('array', $arr); } else { - assertType('array', $arr); + assertType('non-empty-array', $arr); } } @@ -107,7 +107,7 @@ function takesArrayIfFalse1(array $arr) : void { assertType('array', $arr); if (validateStringArrayIfFalse($arr)) { - assertType('array', $arr); + assertType('non-empty-array', $arr); } else { assertType('array', $arr); } diff --git a/tests/PHPStan/Analyser/nsrt/bug-9734.php b/tests/PHPStan/Analyser/nsrt/bug-9734.php index 1628ad6859..52c3dd1c20 100644 --- a/tests/PHPStan/Analyser/nsrt/bug-9734.php +++ b/tests/PHPStan/Analyser/nsrt/bug-9734.php @@ -17,7 +17,7 @@ public function doFoo(array $a): void if (array_is_list($a)) { assertType('list', $a); } else { - assertType('array', $a); // could be non-empty-array + assertType('non-empty-array', $a); } } @@ -44,4 +44,104 @@ public function doFoo3(array $a): void } } + /** + * @param mixed $a + * @return void + */ + public function doFoo4($a): void + { + if (array_is_list($a)) { + assertType('list', $a); + } else { + assertType('mixed~list', $a); + } + } + +} + +class Bar +{ + /** + * @param array $value + * @return ($value is non-empty-list ? true : false) + */ + public function assertIsNonEmptyList($value): bool + { + return false; + } + + /** + * @param array $value + * @return ($value is list ? true : false) + */ + public function assertIsStringList($value): bool + { + return false; + } + + /** + * @param array $value + * @return ($value is list{string, string} ? true : false) + */ + public function assertIsConstantList($value): bool + { + return false; + } + + /** + * @param array $value + * @return ($value is list{0?: string, 1?: string} ? true : false) + */ + public function assertIsOptionalConstantList($value): bool + { + return false; + } + + /** + * @param array $value + * @return ($value is array ? true : false) + */ + public function assertIsStringArray($value): bool + { + return false; + } + + /** + * @param array $a + * @return void + */ + public function doFoo(array $a): void + { + if ($this->assertIsNonEmptyList($a)) { + assertType('non-empty-list', $a); + } else { + assertType('array', $a); + } + + if ($this->assertIsStringList($a)) { + assertType('list', $a); + } else { + assertType('non-empty-array', $a); + } + + if ($this->assertIsConstantList($a)) { + assertType('array{string, string}', $a); + } else { + assertType('array', $a); + } + + if ($this->assertIsOptionalConstantList($a)) { + assertType('list{0?: string, 1?: string}', $a); + } else { + assertType('non-empty-array', $a); + } + + if ($this->assertIsStringArray($a)) { + assertType('array', $a); + } else { + assertType('non-empty-array', $a); + } + } + + }