diff --git a/src/Type/Generic/TemplateTypeTrait.php b/src/Type/Generic/TemplateTypeTrait.php index d823f9b20d5..d4ed8baf373 100644 --- a/src/Type/Generic/TemplateTypeTrait.php +++ b/src/Type/Generic/TemplateTypeTrait.php @@ -368,6 +368,10 @@ public function traverseSimultaneously(Type $right, callable $cb): Type public function tryRemove(Type $typeToRemove): ?Type { + if ($typeToRemove instanceof TemplateType) { + return null; + } + $bound = TypeCombinator::remove($this->getBound(), $typeToRemove); if ($this->getBound() === $bound) { return null; diff --git a/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php b/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php index 0cb376aebc8..037c95ee4f0 100644 --- a/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php +++ b/tests/PHPStan/Rules/TooWideTypehints/TooWideMethodReturnTypehintRuleTest.php @@ -309,4 +309,10 @@ public function testBug13676(): void $this->analyse([__DIR__ . '/data/bug-13676.php'], []); } + #[RequiresPhp('>= 8.2')] + public function testBug11430(): void + { + $this->analyse([__DIR__ . '/data/bug-11430.php'], []); + } + } diff --git a/tests/PHPStan/Rules/TooWideTypehints/data/bug-11430.php b/tests/PHPStan/Rules/TooWideTypehints/data/bug-11430.php new file mode 100644 index 00000000000..45377722b39 --- /dev/null +++ b/tests/PHPStan/Rules/TooWideTypehints/data/bug-11430.php @@ -0,0 +1,51 @@ += 8.2 + +declare(strict_types = 1); + +namespace Bug11430; + +/** + * @template T + */ +interface Option {} + +/** + * @template T + * @implements Option + */ +class Some implements Option +{ + /** + * @param T $value + */ + public function __construct(public mixed $value) {} +} + +/** + * @implements Option + */ +class None implements Option {} + +/** + * @internal + */ +final class Choice +{ + /** + * @template T + * @template S + * + * @param T $value + * @param S $none + * + * @return (T is S ? None : Some) + */ + public static function from(mixed $value, mixed $none = null): Option + { + if ($value === $none) { + return new None(); + } + + return new Some($value); + } +}