Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
77 changes: 77 additions & 0 deletions website/errors/method.impureOverridePureUnlessCallable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,77 @@
---
title: "method.impureOverridePureUnlessCallable"
shortDescription: "Impure method overrides a parent method marked @pure-unless-callable-is-impure."
ignorable: true
---

## Code example

```php
<?php declare(strict_types = 1);

interface PureUnlessParent
{

/**
* @pure-unless-callable-is-impure $cb
*/
public function run(callable $cb): int;

}

class ImpureChild implements PureUnlessParent
{

/**
* @phpstan-impure
*/
public function run(callable $cb): int // ERROR: Impure method ImpureChild::run() overrides method PureUnlessParent::run() marked @pure-unless-callable-is-impure.
{
echo 'side effect';

return $cb(1);
}

}
```

## Why is it reported?

The `@pure-unless-callable-is-impure` tag declares that the parent method is pure *except* when the given callable parameter is impure. Its purity is conditional on the callable passed in, but the method's own body is expected to have no other side effects.

An overriding method marked `@phpstan-impure` breaks this contract: it introduces side effects regardless of the callable. Code that relies on the parent's conditional purity — for example when the parent is called with a pure callable — would then be reasoning about a method that is always impure. The override is therefore incompatible with the inherited purity guarantee.

## How to fix it

Remove `@phpstan-impure` from the child and keep its body free of side effects other than invoking the flagged callable, so it honors the inherited `@pure-unless-callable-is-impure` contract:

```diff-php
class ImpureChild implements PureUnlessParent
{

- /**
- * @phpstan-impure
- */
public function run(callable $cb): int
{
- echo 'side effect';
-
return $cb(1);
}

}
```

If the child genuinely needs side effects, the parent's purity contract cannot hold across all implementations. Remove `@pure-unless-callable-is-impure` from the parent method:

```diff-php
interface PureUnlessParent
{

- /**
- * @pure-unless-callable-is-impure $cb
- */
public function run(callable $cb): int;

}
```
69 changes: 69 additions & 0 deletions website/errors/pureFunction.redundantUnlessCallable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,69 @@
---
title: "pureFunction.redundantUnlessCallable"
shortDescription: "Function is marked @pure-unless-callable-is-impure for a parameter that is already a pure callable."
ignorable: true
---

## Code example

```php
<?php declare(strict_types = 1);

/**
* @param pure-callable(int): int $f
* @param array<int> $arr
* @return array<int>
* @pure-unless-callable-is-impure $f
*/
function myMap(callable $f, array $arr): array
{
$result = [];
foreach ($arr as $i => $v) {
$result[$i] = $f($v);
}

return $result;
}
```

## Why is it reported?

The `@pure-unless-callable-is-impure` tag marks a function as pure *except* when the named callable parameter is impure — its purity depends on the callable passed in at each call site.

Here the parameter `$f` is typed as `pure-callable`, which guarantees it is always pure. Because the only condition that could make the function impure can never happen, the tag has no effect: the function is unconditionally pure. Marking it `@pure-unless-callable-is-impure` is misleading and hides the fact that the function can simply be declared `@phpstan-pure`.

## How to fix it

Replace `@pure-unless-callable-is-impure` with `@phpstan-pure`:

```diff-php
/**
* @param pure-callable(int): int $f
* @param array<int> $arr
* @return array<int>
- * @pure-unless-callable-is-impure $f
+ * @phpstan-pure
*/
function myMap(callable $f, array $arr): array
{
$result = [];
foreach ($arr as $i => $v) {
$result[$i] = $f($v);
}

return $result;
}
```

If the function is actually meant to accept impure callables, widen the parameter type from `pure-callable` to `callable` so that the `@pure-unless-callable-is-impure` tag becomes meaningful again:

```diff-php
/**
- * @param pure-callable(int): int $f
+ * @param callable(int): int $f
* @param array<int> $arr
* @return array<int>
* @pure-unless-callable-is-impure $f
*/
function myMap(callable $f, array $arr): array
```
66 changes: 66 additions & 0 deletions website/errors/pureMethod.redundantUnlessCallable.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,66 @@
---
title: "pureMethod.redundantUnlessCallable"
shortDescription: "Method is marked @pure-unless-callable-is-impure for a parameter that is already a pure callable."
ignorable: true
---

## Code example

```php
<?php declare(strict_types = 1);

class Mapper
{

/**
* @param pure-callable(int): int $f
* @param array<int> $arr
* @return array<int>
* @pure-unless-callable-is-impure $f
*/
public function map(callable $f, array $arr): array
{
$result = [];
foreach ($arr as $i => $v) {
$result[$i] = $f($v);
}

return $result;
}

}
```

## Why is it reported?

The `@pure-unless-callable-is-impure` tag marks a method as pure *except* when the named callable parameter is impure — its purity depends on the callable passed in at each call site.

Here the parameter `$f` is typed as `pure-callable`, which guarantees it is always pure. Because the only condition that could make the method impure can never happen, the tag has no effect: the method is unconditionally pure. Marking it `@pure-unless-callable-is-impure` is misleading and hides the fact that the method can simply be declared `@phpstan-pure`.

## How to fix it

Replace `@pure-unless-callable-is-impure` with `@phpstan-pure`:

```diff-php
/**
* @param pure-callable(int): int $f
* @param array<int> $arr
* @return array<int>
- * @pure-unless-callable-is-impure $f
+ * @phpstan-pure
*/
public function map(callable $f, array $arr): array
```

If the method is actually meant to accept impure callables, widen the parameter type from `pure-callable` to `callable` so that the `@pure-unless-callable-is-impure` tag becomes meaningful again:

```diff-php
/**
- * @param pure-callable(int): int $f
+ * @param callable(int): int $f
* @param array<int> $arr
* @return array<int>
* @pure-unless-callable-is-impure $f
*/
public function map(callable $f, array $arr): array
```
Loading