Skip to content

Commit

Permalink
Use InvalidScalarArgument only when we can be sure PHP attempts coercion
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Dec 19, 2021
1 parent 2e32a18 commit 87a7a88
Show file tree
Hide file tree
Showing 13 changed files with 28 additions and 23 deletions.
Expand Up @@ -983,7 +983,7 @@ public static function verifyType(
),
$statements_analyzer->getSuppressedIssues()
);
} else {
} elseif ($cased_method_id !== 'echo' && $cased_method_id !== 'print') {
IssueBuffer::maybeAdd(
new ArgumentTypeCoercion(
'Argument ' . ($argument_offset + 1) . $method_identifier . ' expects ' . $param_type->getId() .
Expand Down
11 changes: 8 additions & 3 deletions src/Psalm/Internal/Type/Comparator/ScalarTypeComparator.php
Expand Up @@ -27,6 +27,7 @@
use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNonEmptyLowercaseString;
use Psalm\Type\Atomic\TNonEmptyNonspecificLiteralString;
use Psalm\Type\Atomic\TNonEmptyScalar;
use Psalm\Type\Atomic\TNonEmptyString;
use Psalm\Type\Atomic\TNonFalsyString;
use Psalm\Type\Atomic\TNonspecificLiteralInt;
Expand Down Expand Up @@ -299,7 +300,7 @@ public static function isContainedBy(
if ($atomic_comparison_result) {
$atomic_comparison_result->type_coerced = true;
$atomic_comparison_result->type_coerced_from_mixed = true;
$atomic_comparison_result->scalar_type_match_found = true;
$atomic_comparison_result->scalar_type_match_found = !$container_type_part->from_docblock;
}

return false;
Expand Down Expand Up @@ -621,7 +622,8 @@ public static function isContainedBy(
if ($input_type_part instanceof TNumeric) {
if ($container_type_part->isNumericType()) {
if ($atomic_comparison_result) {
$atomic_comparison_result->scalar_type_match_found = true;
$atomic_comparison_result->type_coerced = true;
$atomic_comparison_result->scalar_type_match_found = !$container_type_part->from_docblock;
}
}
}
Expand All @@ -632,7 +634,10 @@ public static function isContainedBy(
&& !$container_type_part instanceof TLiteralFloat
) {
if ($atomic_comparison_result) {
$atomic_comparison_result->scalar_type_match_found = true;
$atomic_comparison_result->type_coerced
= $atomic_comparison_result->type_coerced_from_scalar
= ($input_type_part instanceof TScalar || $input_type_part instanceof TNonEmptyScalar);
$atomic_comparison_result->scalar_type_match_found = !$container_type_part->from_docblock;
}
}
}
Expand Down
6 changes: 3 additions & 3 deletions tests/AnnotationTest.php
Expand Up @@ -1864,7 +1864,7 @@ function foo(&...$s) : void {}
$a = 1;
foo($a);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'spreadOperatorByRefAnnotationBadCall2' => [
'<?php
Expand All @@ -1873,7 +1873,7 @@ function foo(&...$s) : void {}
$b = 2;
foo($b);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'spreadOperatorByRefAnnotationBadCall3' => [
'<?php
Expand All @@ -1882,7 +1882,7 @@ function foo(&...$s) : void {}
$c = 3;
foo($c);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'identifyReturnType' => [
'<?php
Expand Down
10 changes: 5 additions & 5 deletions tests/ArgTest.php
Expand Up @@ -160,9 +160,9 @@ function takesInt(int $i) : void {}
function foo($b) : void {}
foo(null);',
],
'allowArrayIntScalarForArrayStringWithScalarIgnored' => [
'allowArrayIntScalarForArrayStringWithArgumentTypeCoercionIgnored' => [
'<?php
/** @param array<int|string> $arr */
/** @param array<array-key> $arr */
function foo(array $arr) : void {
}
Expand All @@ -171,10 +171,10 @@ function bar() : array {
return [];
}
/** @psalm-suppress InvalidScalarArgument */
/** @psalm-suppress ArgumentTypeCoercion */
foo(bar());',
],
'allowArrayScalarForArrayStringWithScalarIgnored' => [
'allowArrayScalarForArrayStringWithArgumentTypeCoercionIgnored' => [
'<?php declare(strict_types=1);
/** @param array<string> $arr */
function foo(array $arr) : void {}
Expand All @@ -184,7 +184,7 @@ function bar() : array {
return [];
}
/** @psalm-suppress InvalidScalarArgument */
/** @psalm-suppress ArgumentTypeCoercion */
foo(bar());',
],
'unpackObjectlikeListArgs' => [
Expand Down
4 changes: 2 additions & 2 deletions tests/ArrayAssignmentTest.php
Expand Up @@ -1868,7 +1868,7 @@ function takesArray(array $arr) : void {}
$a[] = 2;
takesArray($a);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'listUsedAsArrayWrongListType' => [
'<?php
Expand All @@ -1880,7 +1880,7 @@ function takesArray(array $arr) : void {}
$a[] = 2;
takesArray($a);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'nonEmptyAssignmentToListElementChangeType' => [
'<?php
Expand Down
2 changes: 1 addition & 1 deletion tests/CallableTest.php
Expand Up @@ -1268,7 +1268,7 @@ function takesCallableReturningString(callable $c) : void {
function foo(string $c) : void {
takesCallableReturningString([$c, "bar"]);
}',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'inexistantCallableinCallableString' => [
'<?php
Expand Down
2 changes: 1 addition & 1 deletion tests/DocblockInheritanceTest.php
Expand Up @@ -173,7 +173,7 @@ public function boo(array $arr) : void {}
}
(new X())->boo([1, 2]);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
];
}
Expand Down
2 changes: 1 addition & 1 deletion tests/FunctionCallTest.php
Expand Up @@ -1941,7 +1941,7 @@ function a($b): int
}
a(["a" => "hello"]);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'objectLikeKeyChecksAgainstDifferentTKeyedArray' => [
'<?php
Expand Down
2 changes: 1 addition & 1 deletion tests/IncludeTest.php
Expand Up @@ -722,7 +722,7 @@ function fooFoo($bar): void {
'files_to_check' => [
getcwd() . DIRECTORY_SEPARATOR . 'file2.php',
],
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'namespacedRequireFunction' => [
'files' => [
Expand Down
4 changes: 2 additions & 2 deletions tests/MagicMethodAnnotationTest.php
Expand Up @@ -813,7 +813,7 @@ class Child extends ParentClass {}
$child = new Child();
$child->setString("five");',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'unionAnnotationInvalidArg' => [
'<?php
Expand All @@ -829,7 +829,7 @@ class Child extends ParentClass {}
$child = new Child();
$b = $child->setBool("hello", 5);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'validAnnotationWithInvalidVariadicCall' => [
'<?php
Expand Down
2 changes: 1 addition & 1 deletion tests/Template/ClassTemplateExtendsTest.php
Expand Up @@ -4626,7 +4626,7 @@ public function getID()
class AppUser extends User {}
$au = new AppUser("string");',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'extendsTwiceDifferentNameBrokenChain' => [
'<?php
Expand Down
2 changes: 1 addition & 1 deletion tests/Template/ClassTemplateTest.php
Expand Up @@ -3822,7 +3822,7 @@ function takesIntCollection(Collection $c): void {}
takesStringCollection($collection);
takesIntCollection($collection);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'argumentExpectsFleshOutTIndexedAccess' => [
'<?php
Expand Down
2 changes: 1 addition & 1 deletion tests/Template/FunctionTemplateTest.php
Expand Up @@ -1811,7 +1811,7 @@ function(callable $s) {
function takesReturnTCallable(callable $s) {}
takesReturnTCallable($b);',
'error_message' => 'InvalidScalarArgument',
'error_message' => 'InvalidArgument',
],
'multipleArgConstraintWithMoreRestrictiveFirstArg' => [
'<?php
Expand Down

0 comments on commit 87a7a88

Please sign in to comment.