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

Fix #2308 - prevent specialisation from bound params

This commit is contained in:
Brown 2019-11-06 11:20:51 -05:00
parent d7e435c352
commit a8ed6ba9c4
9 changed files with 67 additions and 26 deletions

View File

@ -760,6 +760,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
$fleshed_out_type,
$template_result,
$codebase,
null,
null
);
}
@ -1719,6 +1720,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
$return_type,
$template_result,
$codebase,
null,
null
);
}

View File

@ -728,6 +728,7 @@ class ReturnTypeAnalyzer
$fleshed_out_return_type,
$template_result,
$codebase,
null,
null
);
}

View File

@ -249,7 +249,7 @@ class CallAnalyzer
protected static function checkMethodArgs(
$method_id,
array $args,
?TemplateResult $template_result,
?TemplateResult $class_template_result,
Context $context,
CodeLocation $code_location,
StatementsAnalyzer $statements_analyzer
@ -266,7 +266,7 @@ class CallAnalyzer
$method_params,
$method_id,
$context,
$template_result
$class_template_result
) === false) {
return false;
}
@ -325,7 +325,7 @@ class CallAnalyzer
$method_params,
$method_storage,
$class_storage,
$template_result,
$class_template_result,
$code_location,
$context
) === false) {
@ -475,6 +475,7 @@ class CallAnalyzer
$replaced_type,
$replace_template_result,
$codebase,
null,
null
);
@ -564,7 +565,8 @@ class CallAnalyzer
$codebase,
isset($arg->value->inferredType)
? $arg->value->inferredType
: null
: null,
null
);
if ($replace_template_result->generic_params) {
@ -1124,7 +1126,7 @@ class CallAnalyzer
array $function_params,
$function_storage,
$class_storage,
?TemplateResult $existing_template_result,
?TemplateResult $class_template_result,
CodeLocation $code_location,
Context $context
) {
@ -1195,6 +1197,10 @@ class CallAnalyzer
$template_result = null;
$class_generic_params = $class_template_result
? $class_template_result->generic_params
: [];
if ($function_storage) {
$template_types = self::getTemplateTypesForFunction(
$function_storage,
@ -1203,7 +1209,7 @@ class CallAnalyzer
);
if ($template_types) {
$template_result = $existing_template_result;
$template_result = $class_template_result;
if (!$template_result) {
$template_result = new TemplateResult($template_types, []);
@ -1228,23 +1234,20 @@ class CallAnalyzer
$template_result,
$codebase,
$arg->value->inferredType,
$context->self ?: '',
false
);
if (!$existing_template_result) {
if (!$class_template_result) {
$template_result->generic_params = [];
}
}
}
}
$existing_generic_params = $existing_template_result
? $existing_template_result->generic_params
: [];
foreach ($existing_generic_params as $template_name => $type_map) {
foreach ($class_generic_params as $template_name => $type_map) {
foreach ($type_map as $class => $type) {
$existing_generic_params[$template_name][$class][0] = clone $type[0];
$class_generic_params[$template_name][$class][0] = clone $type[0];
}
}
@ -1305,7 +1308,7 @@ class CallAnalyzer
$argument_offset,
$arg,
$context,
$existing_generic_params,
$class_generic_params,
$template_result,
$function_storage ? $function_storage->pure : false,
$in_call_map
@ -1416,6 +1419,7 @@ class CallAnalyzer
$template_result,
$codebase,
clone $param->default_type,
null,
true
);
}
@ -1424,7 +1428,7 @@ class CallAnalyzer
}
/**
* @param array<string, array<string, array{Type\Union, 1?:int}>> $existing_generic_params
* @param array<string, array<string, array{Type\Union, 1?:int}>> $class_generic_params
* @return false|null
*/
private static function checkFunctionLikeArgumentMatches(
@ -1437,7 +1441,7 @@ class CallAnalyzer
int $argument_offset,
PhpParser\Node\Arg $arg,
Context $context,
array $existing_generic_params,
array $class_generic_params,
?TemplateResult $template_result,
bool $function_is_pure,
bool $in_call_map
@ -1509,7 +1513,7 @@ class CallAnalyzer
$argument_offset,
$arg,
$context,
$existing_generic_params,
$class_generic_params,
$template_result,
$function_is_pure,
$in_call_map
@ -1611,7 +1615,8 @@ class CallAnalyzer
$codebase,
isset($arg->value->inferredType)
? $arg->value->inferredType
: null
: null,
null
);
if ($template_result->generic_params) {
@ -1648,7 +1653,7 @@ class CallAnalyzer
}
/**
* @param array<string, array<string, array{Type\Union, 1?:int}>> $existing_generic_params
* @param array<string, array<string, array{Type\Union, 1?:int}>> $class_generic_params
* @param array<string, array<string, array{Type\Union, 1?:int}>> $generic_params
* @param array<string, array<string, array{Type\Union}>> $template_types
* @return false|null
@ -1665,7 +1670,7 @@ class CallAnalyzer
int $argument_offset,
PhpParser\Node\Arg $arg,
Context $context,
?array $existing_generic_params,
?array $class_generic_params,
?TemplateResult $template_result,
bool $function_is_pure,
bool $in_call_map
@ -1680,23 +1685,25 @@ class CallAnalyzer
$param_type = clone $function_param->type;
}
if ($existing_generic_params) {
if ($class_generic_params) {
$empty_generic_params = [];
$empty_template_result = new TemplateResult($existing_generic_params, $empty_generic_params);
$empty_template_result = new TemplateResult($class_generic_params, $empty_generic_params);
$param_type = UnionTemplateHandler::replaceTemplateTypesWithStandins(
$param_type,
$empty_template_result,
$codebase,
$arg->value->inferredType
$arg->value->inferredType,
$context->self ?: ''
);
$arg_type = UnionTemplateHandler::replaceTemplateTypesWithStandins(
$arg_type,
$empty_template_result,
$codebase,
$arg->value->inferredType
$arg->value->inferredType,
$context->self ?: ''
);
}
@ -1727,7 +1734,8 @@ class CallAnalyzer
$param_type,
$template_result,
$codebase,
$arg_type_param
$arg_type_param,
$context->self ?: ''
);
}

View File

@ -22,6 +22,7 @@ class UnionTemplateHandler
TemplateResult $template_result,
?Codebase $codebase,
?Union $input_type,
?string $calling_class = null,
bool $replace = true,
bool $add_upper_bound = false,
int $depth = 0
@ -39,6 +40,7 @@ class UnionTemplateHandler
$template_result,
$codebase,
$input_type,
$calling_class,
$replace,
$add_upper_bound,
$depth,
@ -77,6 +79,7 @@ class UnionTemplateHandler
TemplateResult $template_result,
?Codebase $codebase,
?Union $input_type,
?string $calling_class,
bool $replace,
bool $add_upper_bound,
int $depth,
@ -94,6 +97,7 @@ class UnionTemplateHandler
$atomic_type,
$key,
$input_type,
$calling_class,
$template_result,
$codebase,
$replace,
@ -334,6 +338,7 @@ class UnionTemplateHandler
Atomic\TTemplateParam $atomic_type,
string $key,
?Union $input_type,
?string $calling_class,
TemplateResult $template_result,
?Codebase $codebase,
bool $replace,
@ -395,8 +400,11 @@ class UnionTemplateHandler
}
}
if ($replacement_atomic_type instanceof Atomic\TTemplateParam) {
if ($replacement_atomic_type instanceof Atomic\TTemplateParam
&& $replacement_atomic_type->defining_class !== $calling_class
) {
foreach ($replacement_atomic_type->as->getTypes() as $nested_type_atomic) {
$replacements_found = true;
$atomic_types[] = clone $nested_type_atomic;
}
}

View File

@ -223,6 +223,7 @@ trait CallableTrait
$template_result,
$codebase,
$input_param_type,
null,
$replace,
!$add_upper_bound,
$depth
@ -239,6 +240,7 @@ trait CallableTrait
$template_result,
$codebase,
$input_type->return_type,
null,
$replace,
$add_upper_bound
);

View File

@ -193,6 +193,7 @@ trait GenericTrait
$template_result,
$codebase,
$input_type_param,
null,
$replace,
$add_upper_bound,
$depth + 1

View File

@ -343,6 +343,7 @@ class ObjectLike extends \Psalm\Type\Atomic
$template_result,
$codebase,
$input_type_param,
null,
$replace,
$add_upper_bound,
$depth

View File

@ -153,6 +153,7 @@ class TList extends \Psalm\Type\Atomic
$template_result,
$codebase,
$input_type_param,
null,
$replace,
$add_upper_bound,
$depth + 1

View File

@ -2365,6 +2365,23 @@ class ClassTemplateTest extends TestCase
function expectsShape($_): void {}',
'error_message' => 'MixedArgumentTypeCoercion'
],
'preventUseWithMoreSpecificParam' => [
'<?php
/** @template T */
abstract class Collection {
/** @param T $elem */
public function add($elem): void {}
}
/**
* @template T
* @param Collection<T> $col
*/
function usesCollection(Collection $col): void {
$col->add(456);
}',
'error_message' => 'InvalidArgument'
],
];
}
}