psalm
psalm copied to clipboard
Optional property type of object is being forgotten
https://psalm.dev/r/65da587980 Compare output for f1 through f4. Here it is handily organized in a table:
| array | object | |
|---|---|---|
| non-optional | f1$a1: array{p: bool}$a1['p']: bool |
f2$o1: object{p:mixed}$o1->p: bool |
| optional | f3$a2: array{p?: mixed}$a2['p']: bool |
f4$o2: object{p?:mixed}$o2->p: mixedMixedReturnStatement |
the type in f3 should be $a2: array{p?: bool} and I'd expect objects to have more detailed types like arrays.
Psalm should not show an error for the f4 case.
I found these snippets:
https://psalm.dev/r/65da587980
<?php
/** @param array{p: mixed} $a1 */
function f1(array $a1): bool {
if (!is_bool($a1['p'])) {
throw new RuntimeException();
}
/** @psalm-trace $a1 $a1['p'] */
return $a1['p'];
}
/** @param object{p: mixed} $o1 */
function f2(object $o1): bool {
if (!is_bool($o1->p)) {
throw new RuntimeException();
}
/** @psalm-trace $o1 $o1->p */
return $o1->p;
}
/** @param array{p?: mixed} $a2 */
function f3(array $a2): bool {
if (array_key_exists('p', $a2) && !is_bool($a2['p'])) {
throw new RuntimeException();
}
/** @psalm-trace $a2 $a2['p'] */
return $a2['p'];
}
/** @param object{p?: mixed} $o2 */
function f4(object $o2): bool {
if (property_exists($o2, 'p') && !is_bool($o2->p)) {
throw new RuntimeException();
}
/** @psalm-trace $o2 $o2->p */
return $o2->p ?? false;
}
Psalm output (using commit c65b0f0):
INFO: Trace - 8:5 - $a1: array{p: bool}
INFO: Trace - 8:5 - $a1['p']: bool
INFO: Trace - 17:5 - $o1: object{p:mixed}
INFO: Trace - 17:5 - $o1->p: bool
INFO: Trace - 26:5 - $a2: array{p?: mixed}
INFO: Trace - 26:5 - $a2['p']: bool
INFO: MixedReturnStatement - 35:12 - Possibly-mixed return value
INFO: MixedReturnStatement - 35:12 - Could not infer a return type
INFO: Trace - 35:5 - $o2: object{p?:mixed}
INFO: Trace - 35:5 - $o2->p: mixed
I just noticed that in the f3 case psalm should complain that the property may be unset, but it didn't.