psalm
psalm copied to clipboard
RedundantCondition after changing array key inside IF block
https://psalm.dev/r/17293c1f80
Two things look weird to me:
- The result contains
RedundantCondition
error, but Psalm sees possiblenull
value in trace mode. -
testmode
key becomes constant1
after changing another key insideif
block.
If we comment out the line with changing array value, everything becomes normal. I'm not sure if it a bug or this behavior is planned, but it definitely looks unexpected.
I found these snippets:
https://psalm.dev/r/17293c1f80
<?php
/** @psalm-trace $item */
$item = [
'order_id' => random_int(0, 1) ?: null,
'testmode' => random_int(0, 1) ? 1 : 0,
];
if (!empty($item['testmode'])) {
$item['order_id'] = 9999999;
}
/** @psalm-trace $item */
if ($item['order_id'] !== null) {
}
Psalm output (using commit fe190c2):
INFO: Trace - 4:1 - $item: array{order_id: int|null, testmode: 0|1}
ERROR: RedundantCondition - 15:5 - int can never contain null
INFO: Trace - 15:1 - $item: array{order_id: 9999999|null, testmode: 1}
Rule of thumb: always insert semicolon after @psalm-trace
: https://psalm.dev/r/d6349bb26d
I found these snippets:
https://psalm.dev/r/d6349bb26d
<?php
/** @psalm-trace $item */
$item = [
'order_id' => random_int(0, 1) ?: null,
'testmode' => random_int(0, 1) ? 1 : 0,
];
if (!empty($item['testmode'])) {
$item['order_id'] = 9999999;
}
/** @psalm-trace $item */;
if ($item['order_id'] !== null) {
}
Psalm output (using commit fe190c2):
INFO: Trace - 4:1 - $item: array{order_id: int|null, testmode: 0|1}
INFO: Trace - 14:26 - $item: array{order_id: 9999999, testmode: 1}
ERROR: RedundantCondition - 15:5 - int can never contain null
Looks like if
scope bleeds into the outer scope: https://psalm.dev/r/88332e680e
I found these snippets:
https://psalm.dev/r/88332e680e
<?php
$item = [
'order_id' => random_int(0, 1) ?: null,
'testmode' => random_int(0, 1) ? 1 : 0,
];
/** @psalm-trace $item */;
if (!empty($item['testmode'])) {
/** @psalm-trace $item */;
$item['order_id'] = 9999999;
/** @psalm-trace $item */;
}
/** @psalm-trace $item */;
if ($item['order_id'] !== null) {
}
Psalm output (using commit fe190c2):
INFO: Trace - 8:26 - $item: array{order_id: int|null, testmode: 0|1}
INFO: Trace - 11:30 - $item: array{order_id: int|null, testmode: 1}
INFO: Trace - 13:30 - $item: array{order_id: 9999999, testmode: 1}
INFO: Trace - 16:26 - $item: array{order_id: 9999999, testmode: 1}
ERROR: RedundantCondition - 17:5 - int can never contain null
Simplified: https://psalm.dev/r/a0b62854e7
I found these snippets:
https://psalm.dev/r/a0b62854e7
<?php
$arr = [
'a' => rand(0,1) ? 0 : 1,
];
/** @psalm-trace $arr */;
if (1 !== $arr['a']) {
/** @psalm-trace $arr */;
$arr['a'] = 999;
/** @psalm-trace $arr */;
}
/** @psalm-trace $arr */; // expected array{a: 1|999}
Psalm output (using commit fe190c2):
INFO: Trace - 7:25 - $arr: array{a: 0|1}
INFO: Trace - 10:29 - $arr: array{a: 0}
INFO: Trace - 12:29 - $arr: array{a: 999}
INFO: Trace - 15:25 - $arr: array{a: 999}
I'm just going through old issues and it looks like the behavior has improved: https://psalm.dev/r/a0b62854e7 (same link as last comment)
Now $arr
has type array{a: 0|1|999}
, which is not as precise as it could be, but it's not wrong.
I found these snippets:
https://psalm.dev/r/a0b62854e7
<?php
$arr = [
'a' => rand(0,1) ? 0 : 1,
];
/** @psalm-trace $arr */;
if (1 !== $arr['a']) {
/** @psalm-trace $arr */;
$arr['a'] = 999;
/** @psalm-trace $arr */;
}
/** @psalm-trace $arr */; // expected array{a: 1|999}
Psalm output (using commit 6b27a6d):
INFO: Trace - 7:25 - $arr: array{a: 0|1}
INFO: Trace - 10:29 - $arr: array{a: 0}
INFO: Trace - 12:29 - $arr: array{a: 999}
INFO: Trace - 15:25 - $arr: array{a: 0|1|999}