diff --git a/src/Psalm/Internal/Type/TypeCombiner.php b/src/Psalm/Internal/Type/TypeCombiner.php index 099ae82c7fc..5e05fea1cff 100644 --- a/src/Psalm/Internal/Type/TypeCombiner.php +++ b/src/Psalm/Internal/Type/TypeCombiner.php @@ -1005,7 +1005,20 @@ private static function scrapeStringProperties( if (!$type->as_type) { $combination->class_string_types['object'] = new TObject(); } else { - $combination->class_string_types[$type->as] = $type->as_type; + if (isset($combination->class_string_types[$type->as]) + && $combination->class_string_types[$type->as] instanceof TNamedObject + ) { + if ($combination->class_string_types[$type->as]->extra_types === []) { + // do nothing, existing type is wider or the same + } elseif ($type->as_type->extra_types === []) { + $combination->class_string_types[$type->as] = $type->as_type; + } else { + // todo: figure out what to do with class-string|class-string + $combination->class_string_types[$type->as] = $type->as_type; + } + } else { + $combination->class_string_types[$type->as] = $type->as_type; + } } } elseif ($type instanceof TLiteralString) { if ($combination->strings !== null && count($combination->strings) < $literal_limit) { diff --git a/tests/TypeCombinationTest.php b/tests/TypeCombinationTest.php index 841fbd67e36..8cab04fcacd 100644 --- a/tests/TypeCombinationTest.php +++ b/tests/TypeCombinationTest.php @@ -940,6 +940,13 @@ public function providerTestValidTypeCombination(): array '"0"', ], ], + 'unionOfClassStringAndClassStringWithIntersection' => [ + 'class-string', + [ + 'class-string', + 'class-string', + ], + ], ]; } diff --git a/tests/TypeParseTest.php b/tests/TypeParseTest.php index 2156257e2e5..e3ddeec2ad2 100644 --- a/tests/TypeParseTest.php +++ b/tests/TypeParseTest.php @@ -1148,6 +1148,14 @@ public function testIntMaskOfWithValidValueOf(): void $this->assertSame('int-mask-of>', $docblock_type->getId()); } + public function testUnionOfClassStringAndClassStringWithIntersection(): void + { + $this->assertSame( + 'class-string', + (string) Type::parseString('class-string|class-string'), + ); + } + public function testReflectionTypeParse(): void { if (!function_exists('Psalm\Tests\someFunction')) {