vimeo / psalm

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

Composition of pure methods not considered pure #9876

Open gmazzap opened 1 year ago

gmazzap commented 1 year ago

I found a few tickets around this topic, so not sure if this is a duplicate, I'm sorry if so.

Some quick theory first.

Given two pure functions, A -> B and B -> C, their composition, A -> B -> C, is also pure.

In PHP, we can write:

/** @psalm-pure */
function a(int $a): string {
    return (string)$a;
}

/** @psalm-pure */
function b(string $b): string {
    return $b . $b;
}

/** @psalm-pure */
function c(int $a): string {
    return b(a($a));
}

Psalm correctly understand this.

However, it does not understand this when the functions are object methods.

It seems that Psalm throws an ImpureVariableerror as soon as the variable $this is encountered in pure contexts.

However, if $this is used for pure method calls (documented and verified as so), there's no "impurity" because the composition of pure functions is always pure.

I know this can be avoided by using static methods, but there's much less the point in a pure annotation if I'm forced to use static methods anyway.

psalm-github-bot[bot] commented 1 year ago

I found these snippets:

https://psalm.dev/r/d3795aa34b ```php
https://psalm.dev/r/aa278425ba ```php b($this->a($a)); } } ``` ``` Psalm output (using commit e15e03d): ERROR: ImpureVariable - 16:16 - Cannot reference $this in a pure context ERROR: ImpureVariable - 16:25 - Cannot reference $this in a pure context ```