1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-26 20:34:47 +01:00

Fix #947 - interpret type hints of unpacked args

This commit is contained in:
Matthew Brown 2018-08-20 22:11:01 -04:00
parent 14e336e69a
commit 8814dff3c1
4 changed files with 60 additions and 3 deletions

View File

@ -397,6 +397,33 @@ class AssignmentChecker
); );
} }
foreach ($var_comments as $var_comment) {
try {
if ($var_comment->var_id === $list_var_id) {
$var_comment_type = ExpressionChecker::fleshOutType(
$statements_checker->getFileChecker()->project_checker,
$var_comment->type,
$context->self,
$context->self
);
$var_comment_type->setFromDocblock();
$new_assign_type = $var_comment_type;
break;
}
} catch (\UnexpectedValueException $e) {
if (IssueBuffer::accepts(
new InvalidDocblock(
(string)$e->getMessage(),
new CodeLocation($statements_checker->getSource(), $assign_var)
)
)) {
// fall through
}
}
}
$context->vars_in_scope[$list_var_id] = $new_assign_type ?: Type::getMixed(); $context->vars_in_scope[$list_var_id] = $new_assign_type ?: Type::getMixed();
} }
} }

View File

@ -47,6 +47,7 @@ use Psalm\Type\Atomic\TGenericParam;
use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TInt;
use Psalm\Type\Atomic\TMixed; use Psalm\Type\Atomic\TMixed;
use Psalm\Type\Atomic\TNamedObject; use Psalm\Type\Atomic\TNamedObject;
use Psalm\Type\Atomic\TNull;
use Psalm\Type\Atomic\TObject; use Psalm\Type\Atomic\TObject;
use Psalm\Type\Atomic\TString; use Psalm\Type\Atomic\TString;
use Psalm\Type\TypeCombination; use Psalm\Type\TypeCombination;
@ -428,11 +429,13 @@ class ExpressionChecker
foreach ($stmt->expr->inferredType->getTypes() as $type) { foreach ($stmt->expr->inferredType->getTypes() as $type) {
if ($type instanceof Scalar) { if ($type instanceof Scalar) {
$permissible_atomic_types[] = new TArray([Type::getInt(), new Type\Union([$type])]); $permissible_atomic_types[] = new ObjectLike([new Type\Union([$type])]);
} elseif ($type instanceof TNull) {
$permissible_atomic_types[] = new TArray([Type::getEmpty(), Type::getEmpty()]);
} elseif ($type instanceof TArray) { } elseif ($type instanceof TArray) {
$permissible_atomic_types[] = $type; $permissible_atomic_types[] = clone $type;
} elseif ($type instanceof ObjectLike) { } elseif ($type instanceof ObjectLike) {
$permissible_atomic_types[] = $type->getGenericArrayType(); $permissible_atomic_types[] = clone $type;
} else { } else {
$all_permissible = false; $all_permissible = false;
break; break;

View File

@ -1127,6 +1127,24 @@ class AnnotationTest extends TestCase
bar(foo());' bar(foo());'
], ],
'listUnpackWithDocblock' => [
'<?php
interface I {}
class A implements I {
public function bar() : void {}
}
/** @return I[] */
function foo() : array {
return [new A()];
}
/** @var A $a1 */
[$a1, $a2] = foo();
$a1->bar();',
],
]; ];
} }

View File

@ -932,6 +932,15 @@ class ArrayAssignmentTest extends TestCase
$arr[BAR] = [6]; $arr[BAR] = [6];
$bar = $arr[BAR][0];', $bar = $arr[BAR][0];',
], ],
'castToArray' => [
'<?php
$a = (array) (rand(0, 1) ? [1 => "one"] : 0);
$b = (array) null;',
'assertions' => [
'$a' => 'array{1?:string, 0?:int}',
'$b' => 'array<empty, empty>',
],
]
]; ];
} }