diff --git a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php index d780b69f225..59449e096d7 100644 --- a/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php +++ b/src/Psalm/Internal/Analyzer/Statements/Expression/Call/FunctionCallReturnTypeFetcher.php @@ -300,7 +300,7 @@ private static function getReturnTypeFromCallMapWithArgs( return new Type\Union([ $atomic_types['array']->count !== null ? new Type\Atomic\TLiteralInt($atomic_types['array']->count) - : new Type\Atomic\TInt + : new Type\Atomic\TPositiveInt ]); } @@ -308,7 +308,7 @@ private static function getReturnTypeFromCallMapWithArgs( return new Type\Union([ $atomic_types['array']->count !== null ? new Type\Atomic\TLiteralInt($atomic_types['array']->count) - : new Type\Atomic\TInt + : new Type\Atomic\TPositiveInt ]); } @@ -319,6 +319,11 @@ private static function getReturnTypeFromCallMapWithArgs( new Type\Atomic\TLiteralInt(count($atomic_types['array']->properties)) ]); } + + return new Type\Union([ + new Type\Atomic\TLiteralInt(0), + new Type\Atomic\TPositiveInt + ]); } } } diff --git a/tests/FunctionCallTest.php b/tests/FunctionCallTest.php index ea53d00bf15..ba1141ca506 100644 --- a/tests/FunctionCallTest.php +++ b/tests/FunctionCallTest.php @@ -1054,6 +1054,83 @@ function example($x) : void { } }' ], + 'countNonEmptyArrayShouldBePositiveInt' => [ + ' [ + ' [ + ' [ + ' $x + * @return 0 + */ + function example($x) : int { + return count($x); + }', + ], + 'countConstantSizeArrayShouldBeConstantInteger' => [ + ' [ + ' [ + ' [ ' 'TypeDoesNotContainType', ], + 'countOnObjectCannotBePositive' => [ + ' 'LessSpecificReturnStatement', + ], + 'countOnUnknownObjectCannotBePure' => [ + ' 'ImpureFunctionCall', + ], 'coerceCallMapArgsInStrictMode' => [ '