-
Notifications
You must be signed in to change notification settings - Fork 696
Description
Consider the following snippet:
/**
* @psalm-type Foo = object{
* bar: object{
* baz: string|null,
* },
* }
*/
/** @var Foo */
$foo = (object) [
'bar' => (object) [
'baz' => null,
],
];
if ($foo->bar->baz === null) {
$foo->bar->baz = 'foobarbaz';
return;
}
$foo->bar->baz = 'foobarbaz';As you can see, in lines 19 and 23, the exact same thing happens: We're setting a nested object property.
Up until line 19, everything is fine, and Psalm happily fetches the nested property value in line 18 and also allows to set the value in line 19. However, in line 23, it no longer seems to know the type of the bar property; it inferred mixed.
Now, there are a lot of different things you can do to break it even more, or partially unbreak it.
For example, moving line 23 before the if will not trigger anything.
$foo->bar->baz = 'foobarbaz';
if ($foo->bar->baz === null) {
$foo->bar->baz = 'foobarbaz';
return;
}Or storing the conditional in a variable will make the issue go away too:
$isNull = $foo->bar->baz === null;
if ($isNull) {
$foo->bar->baz = 'foobarbaz';
return;
}
$foo->bar->baz = 'foobarbaz';Funnily, using is_null instead of manually comparing with null will work, too, even when inline:
if (is_null($foo->bar->baz)) {
$foo->bar->baz = 'foobarbaz';
return;
}
$foo->bar->baz = 'foobarbaz';Or empty() or !isset() etc.
Is there anything I am doing wrong? Is Psalm?
Does that look like a bug to you too?
Happy to provide additional information, but it looks like Psalm discards (partial) information after a manual comparison inside a control structure (or something like that), and thus falls back to mixed, which then leads to various issues like MixedPropertyAssignment, MixedPropertyFetch, MixedArrayAssignment, MixedOperand etc.