psalm icon indicating copy to clipboard operation
psalm copied to clipboard

RedundantCondition after changing array key inside IF block

Open white43 opened this issue 3 years ago • 9 comments

https://psalm.dev/r/17293c1f80

Two things look weird to me:

  1. The result contains RedundantCondition error, but Psalm sees possible null value in trace mode.
  2. testmode key becomes constant 1 after changing another key inside if 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.

white43 avatar May 06 '21 19:05 white43

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}

psalm-github-bot[bot] avatar May 06 '21 19:05 psalm-github-bot[bot]

Rule of thumb: always insert semicolon after @psalm-trace: https://psalm.dev/r/d6349bb26d

weirdan avatar May 06 '21 19:05 weirdan

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

psalm-github-bot[bot] avatar May 06 '21 19:05 psalm-github-bot[bot]

Looks like if scope bleeds into the outer scope: https://psalm.dev/r/88332e680e

weirdan avatar May 06 '21 19:05 weirdan

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

psalm-github-bot[bot] avatar May 06 '21 19:05 psalm-github-bot[bot]

Simplified: https://psalm.dev/r/a0b62854e7

weirdan avatar May 06 '21 20:05 weirdan

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}

psalm-github-bot[bot] avatar May 06 '21 20:05 psalm-github-bot[bot]

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.

edsrzf avatar Feb 11 '24 00:02 edsrzf

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}

psalm-github-bot[bot] avatar Feb 11 '24 00:02 psalm-github-bot[bot]