1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-30 04:39:00 +01:00

Improve handling of parent method calls

This commit is contained in:
Brown 2019-06-24 17:45:10 -04:00
parent 4baa4d70d8
commit 69b05f5052
5 changed files with 59 additions and 39 deletions

View File

@ -707,6 +707,28 @@ class StaticCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
null
);
if ($found_generic_params
&& $stmt->class instanceof PhpParser\Node\Name
&& $stmt->class->parts === ['parent']
&& $context->self
) {
$self_class_storage = $codebase->classlike_storage_provider->get($context->self);
$extended_types = $self_class_storage->template_type_extends[strtolower($fq_class_name)] ?? [];
if ($extended_types) {
foreach ($extended_types as $type_key => $extended_type) {
if (!is_string($type_key)) {
continue;
}
if (isset($found_generic_params[$type_key][$fq_class_name])) {
$found_generic_params[$type_key][$fq_class_name][0] = clone $extended_type;
}
}
}
}
if (self::checkMethodArgs(
$method_id,
$args,

View File

@ -570,7 +570,10 @@ class Methods
$appearing_fq_class_storage = $this->classlike_storage_provider->get($appearing_fq_class_name);
if (!$appearing_fq_class_storage->user_defined && CallMap::inCallMap($appearing_method_id)) {
if (!$appearing_fq_class_storage->user_defined
&& !$appearing_fq_class_storage->stubbed
&& CallMap::inCallMap($appearing_method_id)
) {
if ($appearing_method_id === 'Closure::fromcallable'
&& isset($args[0]->value->inferredType)
&& $args[0]->value->inferredType->isSingle()

View File

@ -1435,7 +1435,7 @@ class Reconciler
$codebase,
$new_type_part,
$existing_type_part,
false,
true,
false,
$scalar_type_match_found,
$type_coerced,

View File

@ -1319,8 +1319,6 @@ class Union
$atomic_type->replaceTemplateTypesWithArgTypes($template_types, $codebase);
if ($atomic_type instanceof Type\Atomic\TTemplateParam) {
$keys_to_unset[] = $key;
$template_type = null;
if (isset($template_types[$atomic_type->param_name][$atomic_type->defining_class ?: ''])) {
@ -1385,6 +1383,8 @@ class Union
}
if ($template_type) {
$keys_to_unset[] = $key;
foreach ($template_type->types as $template_type_part) {
if ($template_type_part instanceof Type\Atomic\TMixed) {
$is_mixed = true;
@ -1392,12 +1392,6 @@ class Union
$new_types[$template_type_part->getKey()] = $template_type_part;
}
} else {
if ($atomic_type->as->isSingle()) {
$new_types[$key] = array_values($atomic_type->as->getTypes())[0];
} else {
$new_types[$key] = new Type\Atomic\TMixed;
}
}
} elseif ($atomic_type instanceof Type\Atomic\TTemplateParamClass) {
$template_type = isset($template_types[$atomic_type->param_name][$atomic_type->defining_class ?: ''])

View File

@ -1646,35 +1646,6 @@ class TemplateExtendsTest extends TestCase
ord((new Child())->example("str"));'
],
'allowWiderParentType' => [
'<?php
/**
* @template T
*/
abstract class Stringer {
/**
* @param T $t
*/
public static function getString($t, object $o = null) : string {
return "hello";
}
}
class A {}
/**
* @template-extends Stringer<A>
*/
class AStringer extends Stringer {
public static function getString($t, object $o = null) : string {
if ($o) {
return parent::getString($o);
}
return "a";
}
}'
],
'allowTraitExtendAndImplementWithExplicitParamType' => [
'<?php
/**
@ -2772,6 +2743,36 @@ class TemplateExtendsTest extends TestCase
class CovariantFoo extends InvariantFoo {}',
'error_message' => 'InvalidTemplateParam'
],
'preventWiderParentType' => [
'<?php
/**
* @template T
*/
abstract class Stringer {
/**
* @param T $t
*/
public static function getString($t, object $o = null) : string {
return "hello";
}
}
class A {}
/**
* @template-extends Stringer<A>
*/
class AStringer extends Stringer {
public static function getString($t, object $o = null) : string {
if ($o) {
return parent::getString($o);
}
return "a";
}
}',
'error_message' => 'ArgumentTypeCoercion'
],
];
}
}