Skip to content

Commit

Permalink
Merge pull request #8418 from Nicelocal/fix_8414
Browse files Browse the repository at this point in the history
fix: Fix template resolution of complex extended types
  • Loading branch information
orklah committed Aug 17, 2022
2 parents 42462b8 + 979091d commit afe85fa
Show file tree
Hide file tree
Showing 2 changed files with 70 additions and 4 deletions.
Expand Up @@ -2,7 +2,9 @@

namespace Psalm\Internal\Analyzer\Statements\Expression\Call;

use AssertionError;
use Psalm\Codebase;
use Psalm\Internal\Type\TemplateResult;
use Psalm\Internal\Type\TypeExpander;
use Psalm\Storage\ClassLikeStorage;
use Psalm\Type;
Expand Down Expand Up @@ -107,6 +109,23 @@ public static function collect(
}
}

$template_result = null;
if ($class_storage !== $static_class_storage && $static_class_storage->template_types) {
$templates = self::collect(
$codebase,
$static_class_storage,
$static_class_storage,
null,
$lhs_type_part
);
if ($templates === null) {
throw new AssertionError("Could not collect templates!");
}
$template_result = new TemplateResult(
$static_class_storage->template_types,
$templates
);
}
foreach ($template_types as $type_name => $_) {
if (isset($class_template_params[$type_name])) {
continue;
Expand All @@ -118,9 +137,11 @@ public static function collect(
$input_type_extends = $e[$class_storage->name][$type_name];

$output_type_extends = self::resolveTemplateParam(
$codebase,
$input_type_extends,
$static_class_storage,
$lhs_type_part
$lhs_type_part,
$template_result
);

$class_template_params[$type_name][$class_storage->name]
Expand Down Expand Up @@ -163,10 +184,12 @@ public static function collect(
return $class_template_params;
}

public static function resolveTemplateParam(
private static function resolveTemplateParam(
Codebase $codebase,
Union $input_type_extends,
ClassLikeStorage $static_class_storage,
TGenericObject $lhs_type_part
TGenericObject $lhs_type_part,
?TemplateResult $template_result = null
): ?Union {
$output_type_extends = null;
foreach ($input_type_extends->getAtomicTypes() as $type_extends_atomic) {
Expand Down Expand Up @@ -199,12 +222,14 @@ public static function resolveTemplateParam(
[$type_extends_atomic->param_name]
)) {
$nested_output_type = self::resolveTemplateParam(
$codebase,
$static_class_storage
->template_extended_params
[$type_extends_atomic->defining_class]
[$type_extends_atomic->param_name],
$static_class_storage,
$lhs_type_part
$lhs_type_part,
$template_result
);
if ($nested_output_type !== null) {
$output_type_extends = Type::combineUnionTypes(
Expand All @@ -214,6 +239,13 @@ public static function resolveTemplateParam(
}
}
} else {
if ($template_result !== null) {
$type_extends_atomic = clone $type_extends_atomic;
$type_extends_atomic->replaceTemplateTypesWithArgTypes(
$template_result,
$codebase
);
}
$output_type_extends = Type::combineUnionTypes(
new Union([$type_extends_atomic]),
$output_type_extends
Expand Down
34 changes: 34 additions & 0 deletions tests/Template/ClassTemplateTest.php
Expand Up @@ -3764,6 +3764,40 @@ protected function setUp(): void
}
}',
],
'complexTypes' => [
'code' => '<?php
/**
* @template T
*/
class Future {
/**
* @param T $v
*/
public function __construct(private $v) {}
/** @return T */
public function get() { return $this->v; }
}
/**
* @template TTObject
*
* @extends Future<ArrayObject<int, TTObject>>
*/
class FutureB extends Future {
/** @param TTObject $data */
public function __construct($data) { parent::__construct(new ArrayObject([$data])); }
}
$a = new FutureB(123);
$r = $a->get();',
'assertions' => [
'$a===' => 'FutureB<123>',
'$r===' => 'ArrayObject<int, 123>'
]
]
];
}

Expand Down

0 comments on commit afe85fa

Please sign in to comment.