1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00
Prevent input types becoming part of the inferred generic params when a match is found
This commit is contained in:
Matt Brown 2021-01-09 18:08:02 -05:00
parent c1a710999c
commit 6ef0f2e63e
2 changed files with 63 additions and 0 deletions

View File

@ -18,6 +18,11 @@ class TemplateStandinTypeReplacer
{
/**
* This replaces template types in unions with standins (normally the template as type)
*
* $input_type here is normally the argument passed to a templated function or method.
*
* This method fills in the values in $template_result based on how the various atomic types
* of $union_type match up to the types inside $input_type
*/
public static function replace(
Union $union_type,
@ -36,6 +41,23 @@ class TemplateStandinTypeReplacer
$original_atomic_types = $union_type->getAtomicTypes();
// here we want to subtract atomic types from the input type
// when they're also in the union type, so those shared atomic
// types will never be inferred as part of the generic type
if ($input_type && !$input_type->isSingle()) {
$new_input_type = clone $input_type;
foreach ($original_atomic_types as $key => $_) {
if ($new_input_type->hasType($key)) {
$new_input_type->removeType($key);
}
}
if ($new_input_type->getAtomicTypes()) {
$input_type = $new_input_type;
}
}
$had_template = false;
foreach ($original_atomic_types as $key => $atomic_type) {

View File

@ -1444,6 +1444,47 @@ class FunctionTemplateTest extends TestCase
$value = takesClosure(function(Foo $foo) : void {})(new Foo());'
],
'subtractTemplatedNull' => [
'<?php
/**
* @template T
* @param T|null $var
* @return T
*/
function notNull($var) {
if ($var === null) {
throw new \InvalidArgumentException("");
}
return $var;
}
function takesNullableString(?string $s) : string {
return notNull($s);
}'
],
'subtractTemplatedInt' => [
'<?php
/**
* @template T
* @param T|int $var
* @return T
*/
function notNull($var) {
if (\is_int($var)) {
throw new \InvalidArgumentException("");
}
return $var;
}
function takesNullableString(string|int $s) : string {
return notNull($s);
}',
[],
[],
'8.0'
],
];
}