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:
parent
2eb0122549
commit
d1baff4b92
@ -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
|
||||||
);
|
);
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
|
@ -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
|
||||||
);
|
);
|
||||||
|
@ -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;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -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();'
|
||||||
|
],
|
||||||
];
|
];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
Loading…
x
Reference in New Issue
Block a user