1
0
mirror of https://github.com/danog/psalm.git synced 2025-01-21 21:31:13 +01:00

Fix #1197 - add support for method templating without override

This commit is contained in:
Matthew Brown 2019-01-11 09:35:32 -05:00
parent ff958ef643
commit d891c068b4
2 changed files with 93 additions and 4 deletions

View File

@ -582,6 +582,7 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
if ($class_storage->template_types) {
$class_template_params = [];
$e = $calling_class_storage->template_type_extends;
if ($lhs_type_part instanceof TGenericObject) {
if ($calling_class_storage->template_types) {
@ -598,8 +599,6 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
}
}
$e = $calling_class_storage->template_type_extends;
$i = 0;
foreach ($class_storage->template_types as $type_name => $_) {
if (isset($class_template_params[$type_name])) {
@ -638,11 +637,26 @@ class MethodCallAnalyzer extends \Psalm\Internal\Analyzer\Statements\Expression\
$i++;
}
} else {
foreach ($class_storage->template_types as $type_name => $_) {
foreach ($class_storage->template_types as $type_name => list($type)) {
if ($class_storage !== $calling_class_storage
&& isset($e[strtolower($class_storage->name)][$type_name])
) {
$type_extends = $e[strtolower($class_storage->name)][$type_name];
if (!$type_extends instanceof Type\Atomic\TGenericParam) {
$class_template_params[$type_name] = [
new Type\Union([$type_extends]),
$class_storage->name,
];
}
}
if (!$stmt->var instanceof PhpParser\Node\Expr\Variable
|| $stmt->var->name !== 'this'
) {
$class_template_params[$type_name] = [Type::getMixed(), null];
if (!isset($class_template_params[$type_name])) {
$class_template_params[$type_name] = [$type, $class_storage->name];
}
}
}
}

View File

@ -1572,6 +1572,81 @@ class TemplateTest extends TestCase
'$f2' => 'Foo',
]
],
'extendsWithNonTemplateWithoutImplementing' => [
'<?php
/**
* @template T as array-key
*/
abstract class User
{
/**
* @var T
*/
private $id;
/**
* @param T $id
*/
public function __construct($id)
{
$this->id = $id;
}
/**
* @return T
*/
public function getID()
{
return $this->id;
}
}
/**
* @template-extends User<int>
*/
class AppUser extends User {}
$au = new AppUser(-1);
$id = $au->getId();',
[
'$au' => 'AppUser',
'$id' => 'int',
]
],
'doesntExtendTemplateAndDoesNotOverride' => [
'<?php
/**
* @template T as array-key
*/
abstract class User
{
/**
* @var T
*/
private $id;
/**
* @param T $id
*/
public function __construct($id)
{
$this->id = $id;
}
/**
* @return T
*/
public function getID()
{
return $this->id;
}
}
class AppUser extends User {}
$au = new AppUser(-1);
$id = $au->getId();',
[
'$au' => 'AppUser',
'$id' => 'array-key',
]
],
];
}