From be1cd5275e7a3fea6446097cf5c43852ec46250a Mon Sep 17 00:00:00 2001 From: Matt Brown Date: Fri, 16 Oct 2020 17:56:31 -0400 Subject: [PATCH] Fix #4349 - improve types for suggested unions --- .../FunctionLike/ReturnTypeAnalyzer.php | 4 +-- src/Psalm/Type/Atomic/TLiteralInt.php | 2 +- src/Psalm/Type/Atomic/TPositiveInt.php | 18 ++++++++++ src/Psalm/Type/Union.php | 34 ++++++------------- tests/BinaryOperationTest.php | 12 +++---- tests/JsonOutputTest.php | 2 +- tests/Php56Test.php | 4 +-- tests/TypeReconciliation/TypeTest.php | 2 +- 8 files changed, 42 insertions(+), 36 deletions(-) diff --git a/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php b/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php index 9bb0ec1186e..ee7bbd8994f 100644 --- a/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/FunctionLike/ReturnTypeAnalyzer.php @@ -305,7 +305,7 @@ public static function verifyReturnType( if (IssueBuffer::accepts( new MissingClosureReturnType( - 'Closure does not have a return type, expecting ' . $inferred_return_type, + 'Closure does not have a return type, expecting ' . $inferred_return_type->getId(), new CodeLocation($function_like_analyzer, $function, null, true) ), $suppressed_issues, @@ -345,7 +345,7 @@ public static function verifyReturnType( if (IssueBuffer::accepts( new MissingReturnType( 'Method ' . $cased_method_id . ' does not have a return type' . - (!$inferred_return_type->hasMixed() ? ', expecting ' . $inferred_return_type : ''), + (!$inferred_return_type->hasMixed() ? ', expecting ' . $inferred_return_type->getId() : ''), new CodeLocation($function_like_analyzer, $function->name, null, true) ), $suppressed_issues, diff --git a/src/Psalm/Type/Atomic/TLiteralInt.php b/src/Psalm/Type/Atomic/TLiteralInt.php index 4ffea4b30ce..ed7977cd711 100644 --- a/src/Psalm/Type/Atomic/TLiteralInt.php +++ b/src/Psalm/Type/Atomic/TLiteralInt.php @@ -44,6 +44,6 @@ public function toNamespacedString( ?string $this_class, bool $use_phpdoc_format ): string { - return 'int'; + return $use_phpdoc_format ? 'int' : $this->value; } } diff --git a/src/Psalm/Type/Atomic/TPositiveInt.php b/src/Psalm/Type/Atomic/TPositiveInt.php index 8526769808e..69f23c4efb8 100644 --- a/src/Psalm/Type/Atomic/TPositiveInt.php +++ b/src/Psalm/Type/Atomic/TPositiveInt.php @@ -8,6 +8,11 @@ public function getId(bool $nested = false): string return 'positive-int'; } + public function __toString(): string + { + return 'positive-int'; + } + /** * @return false */ @@ -15,4 +20,17 @@ public function canBeFullyExpressedInPhp(): bool { return false; } + + /** + * @param array $aliased_classes + * + */ + public function toNamespacedString( + ?string $namespace, + array $aliased_classes, + ?string $this_class, + bool $use_phpdoc_format + ): string { + return 'positive-int'; + } } diff --git a/src/Psalm/Type/Union.php b/src/Psalm/Type/Union.php index 1a46299a1f2..5ad8a987926 100644 --- a/src/Psalm/Type/Union.php +++ b/src/Psalm/Type/Union.php @@ -402,40 +402,28 @@ public function toNamespacedString( ?string $this_class, bool $use_phpdoc_format ): string { - $printed_int = false; - $printed_float = false; - $printed_string = false; - $types = []; + $multi_ints = count($this->literal_int_types) > 1; + $multi_strings = count($this->literal_string_types) > 1; + $multi_floats = count($this->literal_float_types) > 1; + foreach ($this->types as $type) { $type_string = $type->toNamespacedString($namespace, $aliased_classes, $this_class, $use_phpdoc_format); - if ($type instanceof TLiteralFloat && $type_string === 'float') { - if ($printed_float) { - continue; - } - - $printed_float = true; - } elseif ($type instanceof TLiteralString && $type_string === 'string') { - if ($printed_string) { - continue; - } - - $printed_string = true; - } elseif ($type instanceof TLiteralInt && $type_string === 'int') { - if ($printed_int) { - continue; - } - - $printed_int = true; + if ($type instanceof TLiteralInt && !$multi_ints) { + $type_string = 'int'; + } elseif ($type instanceof TLiteralFloat && !$multi_floats) { + $type_string = 'float'; + } elseif ($type instanceof TLiteralString && !$multi_strings) { + $type_string = 'string'; } $types[] = $type_string; } sort($types); - return implode('|', $types); + return implode('|', array_unique($types)); } /** diff --git a/tests/BinaryOperationTest.php b/tests/BinaryOperationTest.php index d83ba51e430..78567dae921 100644 --- a/tests/BinaryOperationTest.php +++ b/tests/BinaryOperationTest.php @@ -174,9 +174,9 @@ function foo(string $s) : int { 'assertions' => [ '$a' => 'int', '$b' => 'int', - '$c' => 'int', - '$d' => 'int', - '$e' => 'int', + '$c' => 'positive-int', + '$d' => 'positive-int', + '$e' => 'positive-int', '$f' => 'string', ], ], @@ -187,8 +187,8 @@ function foo(string $s) : int { $c = (true xor false); $d = (false xor false);', 'assertions' => [ - '$a' => 'int', - '$b' => 'int', + '$a' => 'positive-int', + '$b' => 'positive-int', '$c' => 'bool', '$d' => 'bool', ], @@ -220,7 +220,7 @@ function foo(string $s) : int { $b = 4 ^ 5;', 'assertions' => [ '$a' => 'string', - '$b' => 'int', + '$b' => 'positive-int', ], ], 'bitwiseNot' => [ diff --git a/tests/JsonOutputTest.php b/tests/JsonOutputTest.php index 79beb9c1a9d..b02ce435fc5 100644 --- a/tests/JsonOutputTest.php +++ b/tests/JsonOutputTest.php @@ -98,7 +98,7 @@ function fooFoo(Badger\Bodger $a): Badger\Bodger { function fooFoo() { return "hello"; }', - 'message' => 'Method fooFoo does not have a return type, expecting string', + 'message' => 'Method fooFoo does not have a return type, expecting string(hello)', 'line' => 2, 'error' => 'fooFoo', ], diff --git a/tests/Php56Test.php b/tests/Php56Test.php index 3ca80894144..cdc1f786d43 100644 --- a/tests/Php56Test.php +++ b/tests/Php56Test.php @@ -49,8 +49,8 @@ public function f($a = self::ONE + self::THREE) { $c4 = (new C)->four;', 'assertions' => [ '$c1' => 'int', - '$c2' => 'int', - '$c3' => 'int', + '$c2' => 'positive-int', + '$c3' => 'positive-int', '$c1_3rd' => 'float|int', '$c_sentence' => 'string', '$cf' => 'int', diff --git a/tests/TypeReconciliation/TypeTest.php b/tests/TypeReconciliation/TypeTest.php index d765713f0fe..171d361d589 100644 --- a/tests/TypeReconciliation/TypeTest.php +++ b/tests/TypeReconciliation/TypeTest.php @@ -863,7 +863,7 @@ function fooFoo(A $a) { $a = 0; $b = $a++;', 'assertions' => [ - '$a' => 'int', + '$a' => 'positive-int', ], ], 'typedValueAssertion' => [