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:
parent
ff958ef643
commit
d891c068b4
@ -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];
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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',
|
||||
]
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
x
Reference in New Issue
Block a user