mirror of
https://github.com/danog/psalm.git
synced 2024-11-26 20:34:47 +01:00
Support better mixin handling
This commit is contained in:
parent
203ed6d94f
commit
3c60609c21
@ -344,6 +344,20 @@ class AtomicMethodCallAnalyzer extends CallAnalyzer
|
||||
$codebase
|
||||
);
|
||||
|
||||
$lhs_type_expanded = \Psalm\Internal\Type\TypeExpander::expandUnion(
|
||||
$codebase,
|
||||
new Type\Union([$lhs_type_part]),
|
||||
$mixin_declaring_class_storage->name,
|
||||
$fq_class_name,
|
||||
$class_storage->parent_class
|
||||
);
|
||||
|
||||
$new_lhs_type_part = array_values($lhs_type_expanded->getAtomicTypes())[0];
|
||||
|
||||
if ($new_lhs_type_part instanceof Type\Atomic\TNamedObject) {
|
||||
$lhs_type_part = $new_lhs_type_part;
|
||||
}
|
||||
|
||||
$mixin_class_storage = $codebase->classlike_storage_provider->get($class_storage->mixin->value);
|
||||
|
||||
$fq_class_name = $mixin_class_storage->name;
|
||||
|
@ -224,7 +224,7 @@ class MixinAnnotationTest extends TestCase
|
||||
return $b->foo;
|
||||
}'
|
||||
],
|
||||
'inheritTemplatedMixin' => [
|
||||
'inheritTemplatedMixinWithStatic' => [
|
||||
'<?php
|
||||
/**
|
||||
* @template T
|
||||
@ -316,6 +316,60 @@ class MixinAnnotationTest extends TestCase
|
||||
(new A)->foo();',
|
||||
'error_message' => 'UndefinedMethod'
|
||||
],
|
||||
'inheritTemplatedMixinWithSelf' => [
|
||||
'<?php
|
||||
/**
|
||||
* @template T
|
||||
*/
|
||||
class Mixin {
|
||||
/**
|
||||
* @psalm-var T
|
||||
*/
|
||||
private $var;
|
||||
|
||||
/**
|
||||
* @psalm-param T $var
|
||||
*/
|
||||
public function __construct ($var) {
|
||||
$this->var = $var;
|
||||
}
|
||||
|
||||
/**
|
||||
* @psalm-return T
|
||||
*/
|
||||
public function type() {
|
||||
return $this->var;
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @template T as object
|
||||
* @mixin Mixin<T>
|
||||
*/
|
||||
abstract class Foo {
|
||||
/** @var Mixin<T> */
|
||||
public object $obj;
|
||||
|
||||
public function __call(string $name, array $args) {
|
||||
return $this->obj->$name(...$args);
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @extends Foo<self>
|
||||
*/
|
||||
abstract class FooChild extends Foo{}
|
||||
|
||||
/**
|
||||
* @psalm-suppress MissingConstructor
|
||||
*/
|
||||
final class FooGrandChild extends FooChild {}
|
||||
|
||||
function test() : FooGrandChild {
|
||||
return (new FooGrandChild)->type();
|
||||
}',
|
||||
'error_message' => 'LessSpecificReturnStatement'
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user