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,
|
$storage,
|
||||||
null,
|
null,
|
||||||
new Type\Atomic\TNamedObject($fq_class_name),
|
new Type\Atomic\TNamedObject($fq_class_name),
|
||||||
'$this'
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
$template_result = new \Psalm\Internal\Type\TemplateResult(
|
$template_result = new \Psalm\Internal\Type\TemplateResult(
|
||||||
|
@ -802,7 +802,7 @@ class ReturnTypeAnalyzer
|
|||||||
$codebase->classlike_storage_provider->get($context->self),
|
$codebase->classlike_storage_provider->get($context->self),
|
||||||
strtolower($function->name->name),
|
strtolower($function->name->name),
|
||||||
new Type\Atomic\TNamedObject($context->self),
|
new Type\Atomic\TNamedObject($context->self),
|
||||||
'$this'
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
$class_template_params = $class_template_params ?: [];
|
$class_template_params = $class_template_params ?: [];
|
||||||
|
@ -28,7 +28,7 @@ class ClassTemplateParamCollector
|
|||||||
ClassLikeStorage $static_class_storage,
|
ClassLikeStorage $static_class_storage,
|
||||||
?string $method_name = null,
|
?string $method_name = null,
|
||||||
?Type\Atomic $lhs_type_part = null,
|
?Type\Atomic $lhs_type_part = null,
|
||||||
?string $lhs_var_id = null
|
bool $self_call = false
|
||||||
): ?array {
|
): ?array {
|
||||||
$static_fq_class_name = $static_class_storage->name;
|
$static_fq_class_name = $static_class_storage->name;
|
||||||
|
|
||||||
@ -96,7 +96,7 @@ class ClassTemplateParamCollector
|
|||||||
|
|
||||||
foreach ($static_class_storage->template_types as $type_name => $_) {
|
foreach ($static_class_storage->template_types as $type_name => $_) {
|
||||||
if (isset($lhs_type_part->type_params[$i])) {
|
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]
|
$class_template_params[$type_name][$static_class_storage->name]
|
||||||
= $lhs_type_part->type_params[$i];
|
= $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]
|
$class_template_params[$type_name][$class_storage->name]
|
||||||
= $output_type_extends ?: Type::getMixed();
|
= $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])
|
&& !isset($class_template_params[$type_name])
|
||||||
) {
|
) {
|
||||||
$class_template_params[$type_name] = [$class_storage->name => Type::getMixed()];
|
$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])) {
|
if (!isset($class_template_params[$type_name])) {
|
||||||
$class_template_params[$type_name][$class_storage->name] = $type;
|
$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),
|
$codebase->classlike_storage_provider->get($fq_class_name),
|
||||||
null,
|
null,
|
||||||
$lhs_type_part,
|
$lhs_type_part,
|
||||||
$lhs_var_id
|
$lhs_var_id === '$this'
|
||||||
);
|
);
|
||||||
|
|
||||||
$lhs_type_part = clone $mixin;
|
$lhs_type_part = clone $mixin;
|
||||||
|
@ -145,7 +145,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer
|
|||||||
$class_storage,
|
$class_storage,
|
||||||
$method_name_lc,
|
$method_name_lc,
|
||||||
$lhs_type_part,
|
$lhs_type_part,
|
||||||
$lhs_var_id
|
$lhs_var_id === '$this'
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($lhs_var_id === '$this' && $parent_source instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer) {
|
if ($lhs_var_id === '$this' && $parent_source instanceof \Psalm\Internal\Analyzer\FunctionLikeAnalyzer) {
|
||||||
@ -167,7 +167,7 @@ class ExistingAtomicMethodCallAnalyzer extends CallAnalyzer
|
|||||||
$class_storage,
|
$class_storage,
|
||||||
$method_name_lc,
|
$method_name_lc,
|
||||||
$lhs_type_part,
|
$lhs_type_part,
|
||||||
$lhs_var_id
|
$lhs_var_id === '$this'
|
||||||
);
|
);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -130,7 +130,7 @@ class ExistingAtomicStaticCallAnalyzer
|
|||||||
$class_storage,
|
$class_storage,
|
||||||
$method_name_lc,
|
$method_name_lc,
|
||||||
$lhs_type_part,
|
$lhs_type_part,
|
||||||
null
|
!$statements_analyzer->isStatic() && $method_id->fq_class_name === $context->self
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($found_generic_params
|
if ($found_generic_params
|
||||||
|
@ -259,7 +259,7 @@ class ReturnAnalyzer
|
|||||||
$class_storage,
|
$class_storage,
|
||||||
strtolower($method_name),
|
strtolower($method_name),
|
||||||
null,
|
null,
|
||||||
'$this'
|
true
|
||||||
);
|
);
|
||||||
|
|
||||||
if ($found_generic_params) {
|
if ($found_generic_params) {
|
||||||
|
@ -3105,6 +3105,89 @@ class ClassTemplateTest extends TestCase
|
|||||||
takesFMixed($f);
|
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