diff --git a/src/Psalm/Internal/Analyzer/TypeAnalyzer.php b/src/Psalm/Internal/Analyzer/TypeAnalyzer.php index b813ad7f5f2..d7850e5b36e 100644 --- a/src/Psalm/Internal/Analyzer/TypeAnalyzer.php +++ b/src/Psalm/Internal/Analyzer/TypeAnalyzer.php @@ -664,7 +664,10 @@ private static function isObjectContainedByObject( || $intersection_input_type instanceof TTemplateParam ) { if ($intersection_container_type_lower === $intersection_input_type_lower) { - if ($container_was_static && !$input_was_static) { + if ($container_was_static + && !$input_was_static + && !$intersection_input_type instanceof TTemplateParam + ) { if ($atomic_comparison_result) { $atomic_comparison_result->type_coerced = true; } diff --git a/tests/Template/ClassTemplateExtendsTest.php b/tests/Template/ClassTemplateExtendsTest.php index d339acbac09..6c308c96847 100644 --- a/tests/Template/ClassTemplateExtendsTest.php +++ b/tests/Template/ClassTemplateExtendsTest.php @@ -3591,6 +3591,62 @@ public function i($changedArgumentName): void { } }' ], + 'acceptTemplatedObjectAsStaticParam' => [ + 'id = $id; + } + + /** + * @param static $id + */ + final public function equals(self $id): bool + { + return $this->id === $id->id; + } + } + + /** + * @template T of Id + */ + final class Ids + { + /** + * @psalm-var list + */ + private array $ids; + + /** + * @psalm-param list $ids + */ + private function __construct(array $ids) + { + $this->ids = $ids; + } + + /** + * @psalm-param T $id + */ + public function contains(Id $id): bool + { + foreach ($this->ids as $oneId) { + if ($oneId->equals($id)) { + return true; + } + } + + return false; + } + }' + ], ]; }