vimeo / psalm

A static analysis tool for finding errors in PHP applications
https://psalm.dev
MIT License
5.52k stars 656 forks source link

False-positive `PossiblyNullArgument` when using `??=` on `ArrayAccess` with nullable `offsetGet()` #10857

Open Shira-3749 opened 4 months ago

Shira-3749 commented 4 months ago

When using ??= on an implementation of ArrayAccess whose offsetGet() can return null for nonexistent offsets, I'm getting a false-positive PossiblyNullArgument:

https://psalm.dev/r/f82e852479

// Psalm infers $foo as Foo|null even though that's impossible
$foo = ($map['foo'] ??= new Foo());

The offsetGet() method is not called at all when ??= is used so it is impossible for it to influence the call to offsetSet() or the result of the ??= operator:

https://3v4l.org/vQqLV

psalm-github-bot[bot] commented 4 months ago

I found these snippets:

https://psalm.dev/r/f82e852479 ```php */ abstract class Map implements ArrayAccess { /** * @param TKey $offset */ abstract function offsetExists(mixed $offset): bool; /** * @param TKey $offset * @return TValue|null */ abstract function offsetGet(mixed $offset): mixed; /** * @param TKey $offset * @param TValue $value */ abstract function offsetSet(mixed $offset, mixed $value): void; /** * @param TKey $offset */ abstract function offsetUnset(mixed $offset): void; } class Foo {} /** * @param Map $map * @psalm-suppress UnusedVariable */ function example(Map $map): void { /** @psalm-trace $foo */ $foo = ($map['foo'] ??= new Foo()); } ``` ``` Psalm output (using commit ef3b018): ERROR: PossiblyNullArgument - 43:13 - Argument 2 of Map::offsetSet cannot be null, possibly null value provided INFO: Trace - 43:5 - $foo: Foo|null ```
jacekkarczmarczyk commented 3 months ago

Duplicate of https://github.com/vimeo/psalm/issues/9960?

Shira-3749 commented 3 months ago

It could be the same cause, just with ??= instead of ??. Also in this case offsetGet() does not get called at all.