Skip to content

Commit

Permalink
Fix #5211 - prevent infinite loop in template inference
Browse files Browse the repository at this point in the history
  • Loading branch information
muglug committed Feb 13, 2021
1 parent 7e61012 commit 6fb7423
Show file tree
Hide file tree
Showing 3 changed files with 14 additions and 18 deletions.
Original file line number Diff line number Diff line change
Expand Up @@ -409,17 +409,13 @@ function ($assertion) use ($generic_params) {
$generic_param_types = null;

if ($storage->template_types) {
$declaring_fq_class_name = $declaring_method_id
? $declaring_method_id->fq_class_name
: $fq_class_name;

foreach ($storage->template_types as $template_name => $base_type) {
if (isset($template_result->upper_bounds[$template_name][$fq_class_name])) {
$generic_param_type
= $template_result->upper_bounds[$template_name][$fq_class_name]->type;
} elseif ($storage->template_extended_params && $template_result->upper_bounds) {
$generic_param_type = self::getGenericParamForOffset(
$declaring_fq_class_name,
$fq_class_name,
$template_name,
$storage->template_extended_params,
array_map(
Expand Down
16 changes: 3 additions & 13 deletions src/Psalm/Internal/Analyzer/Statements/Expression/CallAnalyzer.php
Original file line number Diff line number Diff line change
Expand Up @@ -440,28 +440,18 @@ public static function getGenericParamForOffset(
bool $mapped = false
): Type\Union {
if (isset($found_generic_params[$template_name][$fq_class_name])) {
if (!$mapped && isset($template_extended_params[$fq_class_name][$template_name])) {
foreach ($template_extended_params[$fq_class_name][$template_name]->getAtomicTypes() as $t) {
if ($t instanceof Type\Atomic\TTemplateParam) {
if ($t->param_name !== $template_name) {
return $t->as;
}
}
}
}

return $found_generic_params[$template_name][$fq_class_name];
}

foreach ($template_extended_params as $type_map) {
foreach ($template_extended_params as $extended_class_name => $type_map) {
foreach ($type_map as $extended_template_name => $extended_type) {
foreach ($extended_type->getAtomicTypes() as $extended_atomic_type) {
if ($extended_atomic_type instanceof Type\Atomic\TTemplateParam
&& $extended_atomic_type->param_name === $template_name
&& $extended_template_name !== $template_name
&& $extended_atomic_type->defining_class === $fq_class_name
) {
return self::getGenericParamForOffset(
$fq_class_name,
$extended_class_name,
$extended_template_name,
$template_extended_params,
$found_generic_params,
Expand Down
10 changes: 10 additions & 0 deletions tests/Template/ClassTemplateExtendsTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4372,6 +4372,16 @@ public function foo() : string {
/** @extends Collection<string> */
class StringCollection extends Collection {}',
],
'noInfiniteLoop' => [
'<?php
/**
* @template TValue
* @template-extends SplObjectStorage<object, TValue>
*/
class ObjectStorage extends SplObjectStorage {}
$foo = new ObjectStorage();'
],
];
}

Expand Down

0 comments on commit 6fb7423

Please sign in to comment.