mirror of
https://github.com/danog/psalm.git
synced 2024-11-30 04:39:00 +01:00
Add better typing rules for generic objects
This commit is contained in:
parent
a9852c3bc0
commit
1f7d95dde0
@ -11,6 +11,7 @@ use Psalm\Type\Atomic\TBool;
|
||||
use Psalm\Type\Atomic\TCallable;
|
||||
use Psalm\Type\Atomic\TFalse;
|
||||
use Psalm\Type\Atomic\TFloat;
|
||||
use Psalm\Type\Atomic\TGenericObject;
|
||||
use Psalm\Type\Atomic\TInt;
|
||||
use Psalm\Type\Atomic\TMixed;
|
||||
use Psalm\Type\Atomic\TNamedObject;
|
||||
@ -286,13 +287,49 @@ class TypeChecker
|
||||
|
||||
if ($input_type_part->shallowEquals($container_type_part) ||
|
||||
(
|
||||
$input_type_part instanceof TNamedObject &&
|
||||
$container_type_part instanceof TNamedObject &&
|
||||
self::isObjectContainedByObject($codebase, $input_type_part, $container_type_part)
|
||||
$input_type_part instanceof TNamedObject
|
||||
&& $container_type_part instanceof TNamedObject
|
||||
&& self::isObjectContainedByObject($codebase, $input_type_part, $container_type_part)
|
||||
)
|
||||
) {
|
||||
if ($container_type_part instanceof TGenericObject && !$input_type_part instanceof TGenericObject) {
|
||||
$type_coerced = true;
|
||||
$type_coerced_from_mixed = true;
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
$all_types_contain = true;
|
||||
|
||||
if ($input_type_part instanceof TGenericObject && $container_type_part instanceof TGenericObject) {
|
||||
foreach ($input_type_part->type_params as $i => $input_param) {
|
||||
if (!isset($container_type_part->type_params[$i])) {
|
||||
$type_coerced = true;
|
||||
$type_coerced_from_mixed = true;
|
||||
|
||||
$all_types_contain = false;
|
||||
break;
|
||||
}
|
||||
|
||||
$container_param = $container_type_part->type_params[$i];
|
||||
|
||||
if (!$input_param->isEmpty() &&
|
||||
!self::isContainedBy(
|
||||
$codebase,
|
||||
$input_param,
|
||||
$container_param,
|
||||
$input_param->ignore_nullable_issues,
|
||||
$input_param->ignore_falsable_issues,
|
||||
$has_scalar_match,
|
||||
$type_coerced,
|
||||
$type_coerced_from_mixed
|
||||
)
|
||||
) {
|
||||
$all_types_contain = false;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (($input_type_part instanceof TArray || $input_type_part instanceof ObjectLike)
|
||||
&& ($container_type_part instanceof TArray || $container_type_part instanceof ObjectLike)
|
||||
) {
|
||||
|
@ -164,7 +164,7 @@ class ArrayObject implements IteratorAggregate, Traversable, ArrayAccess, Serial
|
||||
/**
|
||||
* Construct a new array object
|
||||
* @link http://php.net/manual/en/arrayobject.construct.php
|
||||
* @param array<Tkey, TValue>|object $input The input parameter accepts an array or an Object.
|
||||
* @param array<TKey, TValue>|object $input The input parameter accepts an array or an Object.
|
||||
* @param int $flags Flags to control the behaviour of the ArrayObject object.
|
||||
* @param string $iterator_class Specify the class that will be used for iteration of the ArrayObject object. ArrayIterator is the default class used.
|
||||
* @since 5.0.0
|
||||
|
@ -692,6 +692,24 @@ class ReturnTypeTest extends TestCase
|
||||
}',
|
||||
'error_message' => 'LessSpecificReturnStatement',
|
||||
],
|
||||
'moreSpecificGenericReturnType' => [
|
||||
'<?php
|
||||
/** @return Iterator<int, string> */
|
||||
function foo(array $a) {
|
||||
$obj = new ArrayObject($a);
|
||||
return $obj->getIterator();
|
||||
}',
|
||||
'error_message' => 'LessSpecificReturnStatement',
|
||||
],
|
||||
'invalidGenericReturnType' => [
|
||||
'<?php
|
||||
/** @return ArrayIterator<int, string> */
|
||||
function foo(array $a) {
|
||||
$obj = new ArrayObject([1, 2, 3, 4]);
|
||||
return $obj->getIterator();
|
||||
}',
|
||||
'error_message' => 'InvalidReturnStatement',
|
||||
],
|
||||
];
|
||||
}
|
||||
}
|
||||
|
Loading…
Reference in New Issue
Block a user