Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

No option to specify 'pure' or 'immutable' for callback arguments #9132

Closed
bitwise-operators opened this issue Jan 18, 2023 · 4 comments
Closed

Comments

@bitwise-operators
Copy link
Contributor

Take the following example:
https://psalm.dev/r/355b85ceb8

Psalm throws an ImpureFunctionCall on the array_reduce call because $callback is not specified as immutable or pure.

However, the current callable syntax doesn't have any way to do so, meaning this function will require a @psalm-suppress ImpureFunctionCall.

Even specifying the callback using an existing pure function will give the error (see this example ), as the pure-ness is not enforced in the class method.

I don't really have a good suggestion on how to fix this. The original discussion on how to type-hint callables in docblocks had several alternative styles that would allow for more information on the callable, but implementing a completely different syntax just for this seems over the top.

Maybe the simplest solution would be to add a new pseudo type pure-callable. Developers would probably need to use @psalm-param when using it, but since I suspect this isn't exactly a common issue, I think that's acceptable.

@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/355b85ceb8
<?php
/**
 * @psalm-immutable
 */
class test {
    /** @var list<int> $a */
    private array $a = [];
    
    /**
     * @param callable(int, int): int $callback
     * @psalm-mutation-free
     */
    public function sum_up(callable $callback): int {
        return array_reduce($this->a, $callback, 0);
    }
}
Psalm output (using commit b6bdc94):

ERROR: ImpureFunctionCall - 14:16 - Cannot call an impure function from a mutation-free context
https://psalm.dev/r/84e95e30f8
<?php
/**
 * @psalm-pure
 */
function sum(int $a, int $b): int {
    return $a + $b;
}

/**
 * @psalm-immutable
 */
class test {
    /** @var list<int> $a */
    private array $a;
    public function __construct(int ...$a) {
        $this->a = array_values($a);
    }
    
    /**
     * @param callable(int, int): int $callback
     * @psalm-mutation-free
     */
    public function sum_up(callable $callback): int {
        return array_reduce($this->a, $callback, 0);
    }
}

$x = new test(1,2,3,4);

echo $x->sum_up(sum(...));
Psalm output (using commit b6bdc94):

ERROR: ImpureFunctionCall - 24:16 - Cannot call an impure function from a mutation-free context

@danog
Copy link
Collaborator

danog commented Jan 18, 2023

pure-callable and pure-Closure are already implemented: https://psalm.dev/r/dea1c375b5

@danog danog closed this as completed Jan 18, 2023
@psalm-github-bot
Copy link

I found these snippets:

https://psalm.dev/r/dea1c375b5
<?php
/**
 * @psalm-immutable
 */
class test {
    /** @var list<int> $a */
    private array $a = [];
    
    /**
     * @param pure-callable(int, int): int $callback
     * @psalm-mutation-free
     */
    public function sum_up(callable $callback): int {
        return array_reduce($this->a, $callback, 0);
    }
}
Psalm output (using commit a91661a):

No issues!

@bitwise-operators
Copy link
Contributor Author

That's awesome, thanks!

I've created a PR to add it to de docs.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

No branches or pull requests

2 participants