Skip to content
Permalink
Browse files

Fix #2454 - build up template map to better understand passed-through…

… data
  • Loading branch information
muglug committed Dec 11, 2019
1 parent 2e322ee commit 848cbbb4875c7d9be718c9377d482cfb71ba0c33
Showing with 119 additions and 1 deletion.
  1. +22 −1 src/Psalm/Internal/Analyzer/TypeAnalyzer.php
  2. +97 −0 tests/Template/ClassTemplateExtendsTest.php
@@ -1859,6 +1859,23 @@ private static function isMatchingTypeContainedBy(
}

if ($input_type_part->value !== $container_type_part->value && $input_class_storage) {
$input_template_types = $input_class_storage->template_types;
$i = 0;

$replacement_templates = [];

if ($input_template_types) {
foreach ($input_template_types as $template_name => $template_type_map) {
if (!isset($input_type_params[$i])) {
break;
}

$replacement_templates[$template_name][$input_type_part->value] = [$input_type_params[$i]];

$i++;
}
}

$template_extends = $input_class_storage->template_type_extends;

if (isset($template_extends[$container_type_part->value])) {
@@ -1886,7 +1903,7 @@ private static function isMatchingTypeContainedBy(

$candidate_param_type = $input_type_params[$old_params_offset];
} else {
$candidate_param_type = new Type\Union([$et]);
$candidate_param_type = new Type\Union([clone $et]);
}

$candidate_param_type->from_template_default = true;
@@ -1901,6 +1918,10 @@ private static function isMatchingTypeContainedBy(
}
}

$new_input_param->replaceTemplateTypesWithArgTypes(
$replacement_templates
);

$new_input_params[] = $new_input_param ?: Type::getMixed();
}
}
@@ -2480,6 +2480,54 @@ public function map(array $arr) {
}
}'
],
'allowExtendingWithTemplatedClass' => [
'<?php
/**
* @template T1
*/
class Foo {
/** @var T1 */
public $t;
/** @param T1 $t */
public function __construct($t) {
$this->t = $t;
}
}
/**
* @template T2
*/
class Bar {
/** @var T2 */
public $t;
/** @param T2 $t */
public function __construct($t) {
$this->t = $t;
}
}
/**
* @template T3
* @extends Bar<Foo<T3>>
*/
class BarOfFoo extends Bar {
/** @param T3 $t */
public function __construct($t) {
parent::__construct(new Foo($t));
}
}
/**
* @template T4
* @param T4 $t
* @return Bar<Foo<T4>>
*/
function baz($t) {
return new BarOfFoo($t);
}'
],
];
}

@@ -3415,6 +3463,55 @@ public function foo($offset) : void {
}',
'error_message' => 'MixedMethodCall'
],
'preventExtendingWithTemplatedClassWithExplicitTypeGiven' => [
'<?php
/**
* @template T1
*/
class Foo {
/** @var T */
public $t;
/** @param T $t */
public function __construct($t) {
$this->t = $t;
}
}
/**
* @template T
*/
class Bar {
/** @var T */
public $t;
/** @param T $t */
public function __construct($t) {
$this->t = $t;
}
}
/**
* @template T1
* @extends Bar<Foo<T1>>
*/
class BarOfFoo extends Bar {
/** @param T1 $t */
public function __construct($t) {
parent::__construct(new Foo($t));
}
}
/**
* @template T2
* @param T2 $t
* @return Bar<Foo<T2>>
*/
function baz($t) {
return new BarOfFoo("hello");
}',
'error_message' => 'InvalidReturnStatement'
],
];
}
}

0 comments on commit 848cbbb

Please sign in to comment.
You can’t perform that action at this time.