Skip to content

fix(methods): static return of an inherited method is the class that inherits it - #12994

Open
jirkace wants to merge 1 commit into
vimeo:masterfrom
jirkace:fix/7847-inherited-static-return-interface
Open

jirkace wants to merge 1 commit into
vimeo:masterfrom
jirkace:fix/7847-inherited-static-return-interface

Conversation

@jirkace

@jirkace jirkace commented Nov 1, 2026

Copy link
Copy Markdown

A class whose parent has a static-returning method reports MethodSignatureMismatch when it implements an interface that declares the same method.

Before

interface ModelInterface {
    public function setId(?string $value): static;
}

abstract class BaseModel {
    public function setId(?string $value): static { return $this; }
}

class ConcreteModel extends BaseModel implements ModelInterface {} // MethodSignatureMismatch: Method BaseModel::setId with return type 'BaseModel' is different to return type 'ModelInterface'

After

class ConcreteModel extends BaseModel implements ModelInterface {} // no issue

Fixes #7847

…inherits it vimeo#7847

Co-Authored-By: Claude Sonnet 5.5 <noreply@anthropic.com>
@jirkace

jirkace commented Nov 1, 2026

Copy link
Copy Markdown
Author

Behaviour change

  • When the implementing method is compared with the method it implements, its static return type is resolved to the class being analysed (the class that inherits the method), as PHP does, instead of the class that declares it. ConcreteModel extends BaseModel implements ModelInterface no longer reports MethodSignatureMismatch for a static return.
  • The message of a remaining mismatch names the inheriting class ('Concrete3' instead of 'Base3'); an unrelated return type is still rejected (guard test). No existing test expectation was edited.
@github-actions

github-actions Bot commented Nov 1, 2026

Copy link
Copy Markdown
Contributor

✅ Performance: unchanged · Issues: decreased

Project Memory (MB) Wall (s) Issues Weighted
✅ laravel 1 906 98.1 $\color{gray}{\textsf{+0.4\%}}$ 30 843 51 781
✅ symfony 3 378 104.1 $\color{gray}{\textsf{-3.1\%}}$ 52 855 88 405
✅ doctrine-orm 443 17.3 $\color{gray}{\textsf{+0.3\%}}$ 4 601 5 589
✅ psl 664 21.3 $\color{gray}{\textsf{+0.4\%}}$ 3 622 5 569
✅ phpunit 528 10.1 $\color{gray}{\textsf{-0.2\%}}$ 4 195 1 285
✅ php-parser 255 9.1 $\color{gray}{\textsf{+0.1\%}}$ 18 020 20 643
✅ amphp-amp 60 2.1 $\color{gray}{\textsf{-1.4\%}}$ 69 79
✅ webmozarts-assert 270 4.8 $\color{gray}{\textsf{-3.2\%}}$ 642 2 717
✅ guzzle-promises 55 2.1 $\color{gray}{\textsf{+0.5\%}}$ 203 407
✅ drupal 5 388 186.4 $\color{gray}{\textsf{-0.9\%}}$ 107 677 $\color{gray}{\textsf{+0}}$ $\color{green}{\textsf{-7}}$ 162 730 $\color{green}{\textsf{-49}}$
Total 12 945 455.5 $\color{gray}{\textsf{-1.0\%}}$ 222 727 $\color{gray}{\textsf{+0}}$ $\color{green}{\textsf{-7}}$ 339 205 $\color{green}{\textsf{-49}}$
How to read this table
  • Memory: Psalm's own peak figure, threads=1. More than +5 % fails, unless the PR changes composer.json.
  • Wall: base and head run on the same runner; ±10 % is noise. Above +20 % warns, never fails. re-run: a reversed second run was taken and the faster kept.
  • Issues: head count, then $\color{red}{\textsf{+added}}$ $\color{green}{\textsf{-removed}}$ against base.
  • Weighted: issues weighted by error level (levels 1–8 as is, always-errors 10, feature-specific and purity suggestions 0). The projects' own code is pinned and their dependencies resolve identically for base and head, so a change means Psalm reports more, fewer or differently serious issues. A rise is not necessarily a regression.
  • Total: sum over the projects compared on both sides. Thresholds apply per project, not to the total.
  • Colors: $\color{red}{\textsf{red}}$ past a fail or warn threshold (or more issues), $\color{green}{\textsf{green}}$ an improvement past noise (or fewer issues), $\color{gray}{\textsf{gray}}$ noise.
  • Performance: regressed if a head run crashed or timed out or a memory or wall delta is red, else improved if one is green, else unchanged. Its icon is the check result: ❌ fail · ⚠️ warn · ✅ pass; the icon next to each project is that project's result, 💥 = not comparable: base crashed or timed out (counts as ⚠️).
  • Issues (heading): the total weighted change, increased · decreased · unchanged. Informational, never fails the check.
✅ drupal: issues +0 −7

Memory 5 388 → 5 388 MB (<0.1 %) · Wall 188.1 → 186.4 s (−0.9 %)

Weighted 162 779 → 162 730 (−49, −0.03 %): L7 −7

Issue type added removed
MethodSignatureMismatch 0 7

Removed (7)

  • core/lib/Drupal/Core/Config/Entity/Query/Condition.php:14 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterface' of i…
  • core/lib/Drupal/Core/Entity/KeyValueStore/Query/Condition.php:10 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterfac…
  • core/lib/Drupal/Core/Entity/Query/ConditionBase.php:8 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterface' of inher…
  • core/lib/Drupal/Core/Entity/Query/Null/Condition.php:10 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterface' of inh…
  • core/lib/Drupal/Core/Entity/Query/Sql/Condition.php:12 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterface' of inhe…
  • core/lib/Drupal/Core/Entity/Query/Sql/pgsql/Condition.php:18 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterface' o…
  • core/modules/pgsql/src/EntityQuery/Condition.php:11 MethodSignatureMismatch (error): Method Drupal\Core\Entity\Query\ConditionFundamentals::setQuery with return type 'Drupal\Core\Entity\Query\ConditionFundamentals' is different to return type 'Drupal\Core\Entity\Query\ConditionInterface' of inherit…

head 3190ad3 · base fbaedcb (merge-base) · workflow run

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

1 participant