1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix #609 - fix callable coercion in reconciliation step

This commit is contained in:
Matt Brown 2018-03-20 13:24:16 -04:00
parent b8a8e9bc5b
commit 24490aac0e
4 changed files with 50 additions and 36 deletions

View File

@ -540,22 +540,6 @@ class TypeChecker
return true;
}
if ($input_type_part instanceof TCallable &&
(
$container_type_part instanceof TString ||
$container_type_part instanceof TArray ||
$container_type_part instanceof ObjectLike ||
(
$container_type_part instanceof TNamedObject &&
$codebase->classExists($container_type_part->value) &&
$codebase->methodExists($container_type_part->value . '::__invoke')
)
)
) {
// @todo add value checks if possible here
return true;
}
if ($input_type_part instanceof TNumeric) {
if ($container_type_part->isNumericType()) {
$has_scalar_match = true;

View File

@ -14,6 +14,7 @@ use Psalm\Issue\TypeDoesNotContainNull;
use Psalm\Issue\TypeDoesNotContainType;
use Psalm\IssueBuffer;
use Psalm\Type;
use Psalm\Type\Atomic\ObjectLike;
use Psalm\Type\Atomic\Scalar;
use Psalm\Type\Atomic\TArray;
use Psalm\Type\Atomic\TBool;
@ -27,6 +28,7 @@ use Psalm\Type\Atomic\TNumeric;
use Psalm\Type\Atomic\TNumericString;
use Psalm\Type\Atomic\TObject;
use Psalm\Type\Atomic\TResource;
use Psalm\Type\Atomic\TString;
use Psalm\Type\Atomic\TTrue;
class Reconciler
@ -809,6 +811,22 @@ class Reconciler
$has_local_match = true;
break;
}
if ($new_type_part instanceof TCallable &&
(
$existing_var_type_part instanceof TString ||
$existing_var_type_part instanceof TArray ||
$existing_var_type_part instanceof ObjectLike ||
(
$existing_var_type_part instanceof TNamedObject &&
$codebase->classExists($existing_var_type_part->value) &&
$codebase->methodExists($existing_var_type_part->value . '::__invoke')
)
)
) {
$has_local_match = true;
break;
}
}
if (!$has_local_match) {

View File

@ -1,7 +1,7 @@
<?php
namespace Psalm\Tests;
class ClosureTest extends TestCase
class CallableTest extends TestCase
{
use Traits\FileCheckerInvalidCodeParseTestTrait;
use Traits\FileCheckerValidCodeParseTestTrait;
@ -227,7 +227,7 @@ class ClosureTest extends TestCase
passes("asd");',
],
'SKIPPED-callableWithInvokable' => [
'callableWithInvokable' => [
'<?php
function asd(): void {}
class A { public function __invoke(): void {} }
@ -239,6 +239,36 @@ class ClosureTest extends TestCase
fails("asd");',
],
'isCallableArray' => [
'<?php
class A
{
public function callMeMaybe(string $method): void
{
$handleMethod = [$this, $method];
if (is_callable($handleMethod)) {
$handleMethod();
}
}
public function foo(): void {}
}
$a = new A();
$a->callMeMaybe("foo");',
],
'isCallableString' => [
'<?php
function foo(): void {}
function callMeMaybe(string $method): void {
if (is_callable($method)) {
$method();
}
}
callMeMaybe("foo");',
],
];
}

View File

@ -599,24 +599,6 @@ class TypeReconciliationTest extends TestCase
return "backup";
}',
],
'isCallableArray' => [
'<?php
class A
{
public function callMeMaybe(string $method): void
{
$handleMethod = [$this, $method];
if (is_callable($handleMethod)) {
$handleMethod();
}
}
public function foo(): void {}
}
$a = new A();
$a->callMeMaybe("foo");',
],
'stringOrCallableArg' => [
'<?php
/**