mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Ensure class template types are mapped to static methods where necessary
Ref #4733
This commit is contained in:
parent
2840faa519
commit
ad5ec9501d
@ -1071,7 +1071,7 @@ class ClassAnalyzer extends ClassLikeAnalyzer
|
||||
$storage,
|
||||
null,
|
||||
new Type\Atomic\TNamedObject($fq_class_name),
|
||||
'$this'
|
||||
true
|
||||
);
|
||||
|
||||
$template_result = new \Psalm\Internal\Type\TemplateResult(
|
||||
|
@ -802,7 +802,7 @@ class ReturnTypeAnalyzer
|
||||
$codebase->classlike_storage_provider->get($context->self),
|
||||
strtolower($function->name->name),
|
||||
new Type\Atomic\TNamedObject($context->self),
|
||||
'$this'
|
||||
true
|
||||
);
|
||||
|
||||
$class_template_params = $class_template_params ?: [];
|
||||
|
@ -28,7 +28,7 @@ class ClassTemplateParamCollector
|
||||
ClassLikeStorage $static_class_storage,
|
||||
?string $method_name = null,
|
||||
?Type\Atomic $lhs_type_part = null,
|
||||
?string $lhs_var_id = null
|
||||
bool $self_call = false
|
||||
): ?array {
|
||||
$static_fq_class_name = $static_class_storage->name;
|
||||
|
||||
@ -96,7 +96,7 @@ class ClassTemplateParamCollector
|
||||
|
||||
foreach ($static_class_storage->template_types as $type_name => $_) {
|
||||
if (isset($lhs_type_part->type_params[$i])) {
|
||||
if ($lhs_var_id !== '$this' || $static_fq_class_name !== $static_class_storage->name) {
|
||||
if (!$self_call || $static_fq_class_name !== $static_class_storage->name) {
|
||||
$class_template_params[$type_name][$static_class_storage->name]
|
||||
= $lhs_type_part->type_params[$i];
|
||||
}
|
||||
@ -183,13 +183,13 @@ class ClassTemplateParamCollector
|
||||
}
|
||||
}
|
||||
|
||||
if ($lhs_var_id !== '$this' || $static_fq_class_name !== $class_storage->name) {
|
||||
if (!$self_call || $static_fq_class_name !== $class_storage->name) {
|
||||
$class_template_params[$type_name][$class_storage->name]
|
||||
= $output_type_extends ?: Type::getMixed();
|
||||
}
|
||||
}
|
||||
|
||||
if (($lhs_var_id !== '$this' || $static_fq_class_name !== $class_storage->name)
|
||||
if ((!$self_call || $static_fq_class_name !== $class_storage->name)
|
||||
&& !isset($class_template_params[$type_name])
|
||||
) {
|
||||
$class_template_params[$type_name] = [$class_storage->name => Type::getMixed()];
|
||||
@ -216,7 +216,7 @@ class ClassTemplateParamCollector
|
||||
}
|
||||
}
|
||||
|
||||
if ($lhs_var_id !== '$this') {
|
||||
if (!$self_call) {
|
||||
if (!isset($class_template_params[$type_name])) {
|
||||
$class_template_params[$type_name][$class_storage->name] = $type;
|
||||
}
|
||||
|
@ -730,7 +730,7 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$codebase->classlike_storage_provider->get($fq_class_name),
|
||||
null,
|
||||
$lhs_type_part,
|
||||
$lhs_var_id
|
||||
$lhs_var_id === '$this'
|
||||
);
|
||||
|
||||
$lhs_type_part = clone $mixin;
|
||||
|
@ -145,7 +145,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$class_storage,
|
||||
$method_name_lc,
|
||||
$lhs_type_part,
|
||||
$lhs_var_id
|
||||
$lhs_var_id === '$this'
|
||||
);
|
||||
|
||||
if ($lhs_var_id === '$this' && $parent_source instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer) {
|
||||
@ -167,7 +167,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$class_storage,
|
||||
$method_name_lc,
|
||||
$lhs_type_part,
|
||||
$lhs_var_id
|
||||
$lhs_var_id === '$this'
|
||||
);
|
||||
}
|
||||
}
|
||||
|
@ -130,7 +130,7 @@ class ExistingAtomicStaticCallAnalyzer
|
||||
$class_storage,
|
||||
$method_name_lc,
|
||||
$lhs_type_part,
|
||||
null
|
||||
!$statements_analyzer->isStatic() && $method_id->fq_class_name === $context->self
|
||||
);
|
||||
|
||||
if ($found_generic_params
|
||||
|
@ -259,7 +259,7 @@ class ReturnAnalyzer
|
||||
$class_storage,
|
||||
strtolower($method_name),
|
||||
null,
|
||||
'$this'
|
||||
true
|
||||
);
|
||||
|
||||
if ($found_generic_params) {
|
||||
|
@ -3105,6 +3105,89 @@ class ClassTemplateTest extends TestCase
|
||||
takesFMixed($f);
|
||||
}'
|
||||
],
|
||||
'arrayCollectionMapInternal' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-template TKey of array-key
|
||||
* @psalm-template T
|
||||
* @psalm-consistent-constructor
|
||||
*/
|
||||
class ArrayCollection
|
||||
{
|
||||
/** @psalm-var array<TKey,T> */
|
||||
private $elements;
|
||||
|
||||
/** @psalm-param array<TKey,T> $elements */
|
||||
public function __construct(array $elements = [])
|
||||
{
|
||||
$this->elements = $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @template TNewKey of array-key
|
||||
* @template TNew
|
||||
* @psalm-param array<TNewKey, TNew> $elements
|
||||
* @psalm-return static<TNewKey, TNew>
|
||||
*/
|
||||
protected static function createFrom(array $elements)
|
||||
{
|
||||
return new static($elements);
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-template U
|
||||
* @psalm-param Closure(T=):U $func
|
||||
* @psalm-return static<TKey, U>
|
||||
*/
|
||||
public function map(Closure $func)
|
||||
{
|
||||
$new_elements = array_map($func, $this->elements);
|
||||
return self::createFrom($new_elements);
|
||||
}
|
||||
}'
|
||||
],
|
||||
'arrayCollectionMapExternal' => [
|
||||
'<?php
|
||||
/**
|
||||
* @psalm-template TKey of array-key
|
||||
* @psalm-template T
|
||||
* @psalm-consistent-constructor
|
||||
*/
|
||||
class ArrayCollection
|
||||
{
|
||||
/** @psalm-var array<TKey,T> */
|
||||
private $elements;
|
||||
|
||||
/** @psalm-param array<TKey,T> $elements */
|
||||
public function __construct(array $elements = [])
|
||||
{
|
||||
$this->elements = $elements;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-template U
|
||||
* @psalm-param Closure(T=):U $func
|
||||
* @psalm-return ArrayCollection<TKey, U>
|
||||
*/
|
||||
public function map(Closure $func)
|
||||
{
|
||||
$new_elements = array_map($func, $this->elements);
|
||||
return Creator::createFrom($new_elements);
|
||||
}
|
||||
}
|
||||
|
||||
class Creator {
|
||||
/**
|
||||
* @template TNewKey of array-key
|
||||
* @template TNew
|
||||
* @psalm-param array<TNewKey, TNew> $elements
|
||||
* @psalm-return ArrayCollection<TNewKey, TNew>
|
||||
*/
|
||||
public static function createFrom(array $elements) {
|
||||
return new ArrayCollection($elements);
|
||||
}
|
||||
}'
|
||||
],
|
||||
];
|
||||
}
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user