psalm
psalm copied to clipboard
PossiblyUndefinedIntArrayOffset wrong for list
https://psalm.dev/r/55cf73b6a8 shouldn't give an error, as it's a list where keys are 0, 1, 2, 3,...
If any key is validated, any prior keys are automatically valid too.
I found these snippets:
https://psalm.dev/r/55cf73b6a8
<?php
/**
* @param list<string> $arg
* @return void
*/
function foo( $arg ) {
if ( isset( $arg[10] ) ) {
echo $arg[5];
}
}
Psalm output (using commit afe85fa):
INFO: PossiblyUndefinedIntArrayOffset - 9:11 - Possibly undefined array offset '5' is risky given expected type 'int'. Consider using isset beforehand.
If isset($arg[10])
is true, it doesn't imply that isset($arg[5])
is also true:
php > $x = [10 => 1];
php > var_dump(isset($x[10]));
bool(true)
php > var_dump(isset($x[5]));
bool(false)
@bor0 your example is an associative array, not a list. This issue is purely for lists. See here what a list is: https://psalm.dev/docs/annotating_code/type_syntax/array_types/
The issue here is a possibly not precise enough refinement: https://psalm.dev/r/a71c257367
The isset turns the list<string>
into a array{10: string}<int, string>
This is technically correct but it's not the best way to store the new type. Instead, it should become a non-empty-list<string>
and have the hidden property TNonEmptyList::$count
set to 11 (maybe check the off by one here).
I found these snippets:
https://psalm.dev/r/a71c257367
<?php
/**
* @param list<string> $arg
* @return void
*/
function foo( $arg ) {
if ( isset( $arg[10] ) ) {
/** @psalm-trace $arg */;
echo $arg[5];
}
}
Psalm output (using commit 028ac7f):
INFO: Trace - 9:33 - $arg: array{10: string}<int, string>
INFO: PossiblyUndefinedIntArrayOffset - 10:11 - Possibly undefined array offset '5' is risky given expected type 'int'. Consider using isset beforehand.