1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-22 05:41:20 +01:00

Fix #1044 - allow templated params in assert

This commit is contained in:
Matthew Brown 2018-10-30 09:20:34 -04:00
parent 2eb0122549
commit d1baff4b92
5 changed files with 56 additions and 2 deletions

View File

@ -481,6 +481,7 @@ class FunctionCallChecker extends \Psalm\Checker\Statements\Expression\CallCheck
self::applyAssertionsToContext( self::applyAssertionsToContext(
$function_storage->assertions, $function_storage->assertions,
$stmt->args, $stmt->args,
$function_storage->template_typeof_params ?: [],
$context, $context,
$statements_checker $statements_checker
); );

View File

@ -694,6 +694,7 @@ class MethodCallChecker extends \Psalm\Checker\Statements\Expression\CallChecker
self::applyAssertionsToContext( self::applyAssertionsToContext(
$method_storage->assertions, $method_storage->assertions,
$args, $args,
$method_storage->template_typeof_params ?: [],
$context, $context,
$statements_checker $statements_checker
); );

View File

@ -512,6 +512,7 @@ class StaticCallChecker extends \Psalm\Checker\Statements\Expression\CallChecker
self::applyAssertionsToContext( self::applyAssertionsToContext(
$method_storage->assertions, $method_storage->assertions,
$stmt->args, $stmt->args,
$method_storage->template_typeof_params ?: [],
$context, $context,
$statements_checker $statements_checker
); );

View File

@ -2092,6 +2092,7 @@ class CallChecker
* @param \Psalm\Storage\Assertion[] $assertions * @param \Psalm\Storage\Assertion[] $assertions
* @param array<int, PhpParser\Node\Arg> $args * @param array<int, PhpParser\Node\Arg> $args
* @param Context $context * @param Context $context
* @param array<int, string> $template_typeof_params
* @param StatementsChecker $statements_checker * @param StatementsChecker $statements_checker
* *
* @return void * @return void
@ -2099,12 +2100,15 @@ class CallChecker
protected static function applyAssertionsToContext( protected static function applyAssertionsToContext(
array $assertions, array $assertions,
array $args, array $args,
array $template_typeof_params,
Context $context, Context $context,
StatementsChecker $statements_checker StatementsChecker $statements_checker
) { ) {
$type_assertions = []; $type_assertions = [];
foreach ($assertions as $assertion) { foreach ($assertions as $assertion) {
$assertion_var_id = null;
if (is_int($assertion->var_id)) { if (is_int($assertion->var_id)) {
if (!isset($args[$assertion->var_id])) { if (!isset($args[$assertion->var_id])) {
continue; continue;
@ -2115,10 +2119,26 @@ class CallChecker
$arg_var_id = ExpressionChecker::getArrayVarId($arg_value, null, $statements_checker); $arg_var_id = ExpressionChecker::getArrayVarId($arg_value, null, $statements_checker);
if ($arg_var_id) { if ($arg_var_id) {
$type_assertions[$arg_var_id] = $assertion->rule; $assertion_var_id = $arg_var_id;
} }
} else { } else {
$type_assertions[$assertion->var_id] = $assertion->rule; $assertion_var_id = $assertion->var_id;
}
if ($assertion_var_id) {
$offset = array_search($assertion->rule[0][0], $template_typeof_params, true);
if ($offset !== false) {
if (isset($args[$offset]->value->inferredType)) {
$templated_type = $args[$offset]->value->inferredType;
if ($templated_type->isSingleStringLiteral()) {
$type_assertions[$assertion_var_id] = [[$templated_type->getSingleStringLiteral()->value]];
}
}
} else {
$type_assertions[$assertion_var_id] = $assertion->rule;
}
} }
} }

View File

@ -204,6 +204,37 @@ class AssertTest extends TestCase
$i = substr($_SERVER["abc"], 1, 2); $i = substr($_SERVER["abc"], 1, 2);
}', }',
], ],
'assertTemplatedType' => [
'<?php
interface Foo {}
class Bar implements Foo {
public function sayHello(): void {
echo "Hello";
}
}
/**
* @param mixed $value
* @param class-string $type
* @template T
* @template-typeof T $type
* @psalm-assert T $value
*/
function assertInstanceOf($value, string $type): void {
// some code
}
// Returns concreate implmenetation of Foo, which in this case is Bar
function getImplementationOfFoo(): Foo {
return new Bar();
}
$bar = getImplementationOfFoo();
assertInstanceOf($bar, Bar::class);
$bar->sayHello();'
],
]; ];
} }