-
Notifications
You must be signed in to change notification settings - Fork 699
Casting down iterable doesn't give the expected type #1997
Copy link
Copy link
Closed
Labels
Description
iterable can't be cast to array, which should be valid:
https://www.php.net/manual/en/function.is-iterable.php
When iterable is cast to Traversable, it loses template types.
Example (https://psalm.dev/r/426c998c6e):
<?php
/**
* @param array<int> $x
* @psalm-suppress UnusedParam
*/
function takesArray (array $x): void {}
/** @var iterable<int> */
$x = null;
assert(is_array($x));
takesArray($x);
if (is_array($x)) {
takesArray($x);
}
/**
* @param Traversable<int> $x
* @psalm-suppress UnusedParam
*/
function takesTraversable (Traversable $x): void {}
/** @var iterable<int> */
$x = null;
assert($x instanceof Traversable);
takesTraversable($x);Example output:
Psalm output (using commit 3f78082):
ERROR: InvalidArgument - 11:12 - Argument 1 of takesArray expects array<array-key, int>, iterable<array-key, int> provided
ERROR: DocblockTypeContradiction - 12:5 - Cannot resolve types for $x - docblock-defined type iterable<array-key, int> does not contain array<array-key, mixed>
ERROR: MixedArgumentTypeCoercion - 13:16 - Argument 1 of takesArray expects array<array-key, int>, parent type array<array-key, mixed> provided
ERROR: MixedArgumentTypeCoercion - 25:18 - Argument 1 of takesTraversable expects Traversable<mixed, int>, parent type Traversable provided
Reactions are currently unavailable