Skip to content

Fix phpstan/phpstan#6139: False positive for covariant generic parameter#5338

Open
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ttfe0ca
Open

Fix phpstan/phpstan#6139: False positive for covariant generic parameter#5338
phpstan-bot wants to merge 1 commit intophpstan:2.1.xfrom
phpstan-bot:create-pull-request/patch-ttfe0ca

Conversation

@phpstan-bot
Copy link
Copy Markdown
Collaborator

Summary

When a covariant generic type like Element<T> (where Element declares @template-covariant T) is used as a method parameter type, PHPStan was incorrectly reporting that the covariant template type T occurs in a contravariant position. Since the covariant generic only produces values of type T, using it in a parameter position does not create a true contravariant use of T.

Changes

  • Modified src/Rules/Generics/VarianceCheck.php:
    • Added findCovariantTemplatesInCovariantGeneric() method that detects when a covariant template type is used directly as a type argument to a covariant generic type in a parameter position
    • Uses getObjectClassReflections() and getTemplateType() instead of instanceof GenericObjectType to follow PHPStan's type-checking conventions
    • The check() method now skips variance errors for these identified template types
  • Updated tests/PHPStan/Rules/Generics/MethodSignatureVarianceRuleTest.php:
    • Removed expected error for @param Out<X> in covariant class test (parameter f)
    • Removed expected error for @param Out<X> in static method covariant class test (parameter c)
    • Added testBug6139() test method
  • Added tests/PHPStan/Rules/Generics/data/bug-6139.php regression test

Root cause

The variance check composed the position variance (contravariant for parameters) with the generic type's template variance (covariant) using the standard multiplication rule: contravariant × covariant = contravariant. This treated any covariant template type used as a type argument to a covariant generic in a parameter as a variance violation.

The fix identifies this specific pattern at the top level (in VarianceCheck::check) and skips the error for direct template type arguments that have matching covariant variance with the generic class's template parameter. This avoids the false positive while preserving correct variance checking for nested generic types (e.g., @return In<Out<X>> is still correctly flagged).

Test

Added tests/PHPStan/Rules/Generics/data/bug-6139.php which reproduces the original issue:

  • Element<T> interface with @template-covariant T
  • FormatLoader<T> interface with @template-covariant T and method addElement(Element<T> $element)
  • The test expects no errors (empty expected errors array)

Fixes phpstan/phpstan#6139

- When a covariant generic type (e.g. Element<T> with @template-covariant T)
  is used as a method parameter type, covariant template type arguments are
  no longer falsely reported as variance violations
- Added findCovariantTemplatesInCovariantGeneric() in VarianceCheck to detect
  and skip these cases using getObjectClassReflections() and getTemplateType()
- New regression test in tests/PHPStan/Rules/Generics/data/bug-6139.php
- Updated existing covariant variance test expectations to reflect the fix
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

Successfully merging this pull request may close these issues.

1 participant