psalm
psalm copied to clipboard
Assert reconciliation doesn't work for templates until called twice
The issue is spotted on L22. But the most interesting magic happen if assertable method called twice — reconciliation works in this case (L29)! Such behavior advises me that fix can be trivial for those familiar in internals. I could be wrong though :D
https://psalm.dev/r/d667ca7193
I found these snippets:
https://psalm.dev/r/d667ca7193
<?php
/**
* @psalm-immutable
* @template T
*/
class A {
/** @psalm-assert-if-true !null $this->some() */
function assertIfTrue(): bool {
return true;
}
/** @return null|T */
function some() {
return null;
}
}
/** @var A<int> $a */
if ($a->assertIfTrue()) {
$b = $a->some();
/** @psalm-trace $b */;
}
/** @var A<int> $a2 */
$a2->some(); // <------- Miracle is happening here
if ($a2->assertIfTrue()) {
$b = $a2->some();
/** @psalm-trace $b */;
}
Psalm output (using commit 24f7920):
INFO: Trace - 22:27 - $b: T:A as mixed
ERROR: UnusedMethodCall - 26:6 - The call to A::some is not used
INFO: Trace - 29:27 - $b: int
INFO: UnusedVariable - 21:5 - $b is never referenced or the value is not used
INFO: UnusedVariable - 28:5 - $b is never referenced or the value is not used