Skip to content

Commit

Permalink
Merge pull request #9866 from klimick/fix-generic-type-params-mapping
Browse files Browse the repository at this point in the history
Fix generic type params mapping
  • Loading branch information
orklah committed Jun 4, 2023
2 parents 43df1dc + 02addbe commit 9d1c2c4
Show file tree
Hide file tree
Showing 2 changed files with 76 additions and 29 deletions.
63 changes: 34 additions & 29 deletions src/Psalm/Internal/Type/TemplateStandinTypeReplacer.php
Original file line number Diff line number Diff line change
Expand Up @@ -36,6 +36,7 @@
use Psalm\Type\Union;

use function array_fill;
use function array_filter;
use function array_keys;
use function array_merge;
use function array_search;
Expand Down Expand Up @@ -1253,6 +1254,7 @@ public static function getMappedGenericTypeParams(
Atomic $container_type_part,
?array &$container_type_params_covariant = null
): array {
$_ = null;
if ($input_type_part instanceof TGenericObject || $input_type_part instanceof TIterable) {
$input_type_params = $input_type_part->type_params;
} elseif ($codebase->classlike_storage_provider->has($input_type_part->value)) {
Expand Down Expand Up @@ -1316,40 +1318,43 @@ public static function getMappedGenericTypeParams(
foreach ($params as $extended_input_param_type) {
$new_input_param = null;

foreach ($extended_input_param_type->getAtomicTypes() as $et) {
if ($et instanceof TTemplateParam) {
$ets = Methods::getExtendedTemplatedTypes(
$et,
$template_extends,
);
} else {
$ets = [];
}

if ($ets
&& $ets[0] instanceof TTemplateParam
&& isset(
$input_class_storage->template_types
[$ets[0]->param_name]
[$ets[0]->defining_class],
foreach ($extended_input_param_type->getAtomicTypes() as $extended_template) {
$extended_templates = $extended_template instanceof TTemplateParam
? array_values(
array_filter(
Methods::getExtendedTemplatedTypes($extended_template, $template_extends),
static fn(Atomic $a) => $a instanceof TTemplateParam,
),
)
) {
$old_params_offset = (int) array_search(
$ets[0]->param_name,
array_keys($input_class_storage->template_types),
);

$candidate_param_type = $input_type_params[$old_params_offset] ?? Type::getMixed();
$candidate_param_type = $candidate_param_type->setProperties([
'from_template_default' => true,
]);
} else {
$candidate_param_type = new Union([$et], ['from_template_default' => true]);
: [];

$candidate_param_types = [];

if ($extended_templates) {
foreach ($extended_templates as $template) {
if (!isset(
$input_class_storage->template_types
[$template->param_name]
[$template->defining_class],
)) {
continue;
}

$old_params_offset = (int) array_search(
$template->param_name,
array_keys($input_class_storage->template_types),
);

$candidate_param_types[] = ($input_type_params[$old_params_offset] ?? Type::getMixed())
->setProperties(['from_template_default' => true]);
}
}

$new_input_param = Type::combineUnionTypes(
$new_input_param,
$candidate_param_type,
$candidate_param_types
? Type::combineUnionTypeArray($candidate_param_types, $codebase)
: new Union([$extended_template], ['from_template_default' => true]),
);
}

Expand Down
42 changes: 42 additions & 0 deletions tests/Template/ClassTemplateTest.php
Original file line number Diff line number Diff line change
Expand Up @@ -4138,6 +4138,48 @@ protected function normalize($value)
}
',
],
'typesOrderInsideImplementsNotMatter' => [
'code' => '<?php
/** @template T */
interface I {}
/**
* @template T
* @extends I<T>
*/
interface ExtendedI extends I {}
/**
* @template T
* @implements ExtendedI<T|null>
*/
final class TWithNull implements ExtendedI
{
/** @param T $_value */
public function __construct($_value) {}
}
/**
* @template T
* @implements ExtendedI<null|T>
*/
final class NullWithT implements ExtendedI
{
/** @param T $_value */
public function __construct($_value) {}
}
/** @param I<null|int> $_type */
function nullWithInt(I $_type): void {}
/** @param I<int|null> $_type */
function intWithNull(I $_type): void {}
nullWithInt(new TWithNull(1));
nullWithInt(new NullWithT(1));
intWithNull(new TWithNull(1));
intWithNull(new NullWithT(1));',
],
];
}

Expand Down

0 comments on commit 9d1c2c4

Please sign in to comment.