1
0
mirror of https://github.com/danog/psalm.git synced 2024-11-27 04:45:20 +01:00

Improve handling of default extended params

This commit is contained in:
Brown 2019-11-14 12:12:09 -05:00
parent 70b8df268d
commit b693b726c7
3 changed files with 77 additions and 6 deletions

View File

@ -145,6 +145,7 @@ class TypeAnalyzer
if ($input_type_part instanceof TMixed if ($input_type_part instanceof TMixed
&& $input_type->from_template_default && $input_type->from_template_default
&& $input_type->from_docblock
&& $atomic_comparison_result && $atomic_comparison_result
&& $atomic_comparison_result->type_coerced_from_mixed && $atomic_comparison_result->type_coerced_from_mixed
) { ) {
@ -250,7 +251,9 @@ class TypeAnalyzer
if ($all_type_coerced_from_mixed) { if ($all_type_coerced_from_mixed) {
$union_comparison_result->type_coerced_from_mixed = true; $union_comparison_result->type_coerced_from_mixed = true;
if ($input_type->from_template_default || $all_type_coerced_from_as_mixed) { if (($input_type->from_template_default && $input_type->from_docblock)
|| $all_type_coerced_from_as_mixed
) {
$union_comparison_result->type_coerced_from_as_mixed = true; $union_comparison_result->type_coerced_from_as_mixed = true;
} }
} }
@ -265,7 +268,9 @@ class TypeAnalyzer
if ($some_type_coerced_from_mixed) { if ($some_type_coerced_from_mixed) {
$union_comparison_result->type_coerced_from_mixed = true; $union_comparison_result->type_coerced_from_mixed = true;
if ($input_type->from_template_default || $all_type_coerced_from_as_mixed) { if (($input_type->from_template_default && $input_type->from_docblock)
|| $all_type_coerced_from_as_mixed
) {
$union_comparison_result->type_coerced_from_as_mixed = true; $union_comparison_result->type_coerced_from_as_mixed = true;
} }
} }

View File

@ -403,8 +403,10 @@ class Populator
foreach ($trait_storage->template_types as $template_name => $template_type_map) { foreach ($trait_storage->template_types as $template_name => $template_type_map) {
foreach ($template_type_map as $template_type) { foreach ($template_type_map as $template_type) {
$default_param = clone $template_type[0];
$default_param->from_docblock = false;
$storage->template_type_extends[$trait_storage->name][$template_name] $storage->template_type_extends[$trait_storage->name][$template_name]
= $template_type[0]; = $default_param;
} }
} }
} }
@ -517,8 +519,10 @@ class Populator
foreach ($parent_storage->template_types as $template_name => $template_type_map) { foreach ($parent_storage->template_types as $template_name => $template_type_map) {
foreach ($template_type_map as $template_type) { foreach ($template_type_map as $template_type) {
$default_param = clone $template_type[0];
$default_param->from_docblock = false;
$storage->template_type_extends[$parent_storage->name][$template_name] $storage->template_type_extends[$parent_storage->name][$template_name]
= $template_type[0]; = $default_param;
} }
} }
@ -655,8 +659,10 @@ class Populator
foreach ($parent_interface_storage->template_types as $template_name => $template_type_map) { foreach ($parent_interface_storage->template_types as $template_name => $template_type_map) {
foreach ($template_type_map as $template_type) { foreach ($template_type_map as $template_type) {
$default_param = clone $template_type[0];
$default_param->from_docblock = false;
$storage->template_type_extends[$parent_interface_storage->name][$template_name] $storage->template_type_extends[$parent_interface_storage->name][$template_name]
= $template_type[0]; = $default_param;
} }
} }
} }
@ -747,8 +753,10 @@ class Populator
foreach ($implemented_interface_storage->template_types as $template_name => $template_type_map) { foreach ($implemented_interface_storage->template_types as $template_name => $template_type_map) {
foreach ($template_type_map as $template_type) { foreach ($template_type_map as $template_type) {
$default_param = clone $template_type[0];
$default_param->from_docblock = false;
$storage->template_type_extends[$implemented_interface_storage->name][$template_name] $storage->template_type_extends[$implemented_interface_storage->name][$template_name]
= $template_type[0]; = $default_param;
} }
} }
} }

View File

@ -321,6 +321,64 @@ class ClassTemplateCovarianceTest extends TestCase
class CovariantFoo extends InvariantFoo {}', class CovariantFoo extends InvariantFoo {}',
'error_message' => 'InvalidTemplateParam', 'error_message' => 'InvalidTemplateParam',
], ],
'expectsTemplatedObject' => [
'<?php
/**
* @template T
* @template-implements ArrayAccess<int,T>
*/
class MyArray implements ArrayAccess, IteratorAggregate {
/** @var array<int,T> */
private $values = [];
public function __construct() {
$this->values = [];
}
/**
* @param int $offset
* @param T $value
*/
public function offsetSet($offset, $value) {
$this->values[$offset] = $value;
}
/**
* @param int $offset
* @return T
*/
public function offsetGet($offset) {
return $this->values[$offset];
}
/**
* @param int $offset
* @return bool
*/
public function offsetExists($offset) {
return isset($this->values[$offset]);
}
/**
* @param int $offset
*/
public function offsetUnset($offset) {
unset($this->values[$offset]);
}
public function getIterator() : Traversable {
return new ArrayObject($this->values);
}
}
class A {}
class AChild extends A {}
/** @param IteratorAggregate<int, A> $i */
function expectsIteratorAggregateOfA(IteratorAggregate $i) : void {}
/** @param MyArray<AChild> $m */
function takesMyArrayOfAChild(MyArray $m) : void {
expectsIteratorAggregateOfA($m);
}',
'error_message' => 'MixedArgumentTypeCoercion',
],
]; ];
} }
} }