diff --git a/src/Psalm/Internal/Type/TypeCombiner.php b/src/Psalm/Internal/Type/TypeCombiner.php
index 099ae82c7..5e05fea1c 100644
--- a/src/Psalm/Internal/Type/TypeCombiner.php
+++ b/src/Psalm/Internal/Type/TypeCombiner.php
@@ -1005,7 +1005,20 @@ final class TypeCombiner
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 841fbd67e..8cab04fca 100644
--- a/tests/TypeCombinationTest.php
+++ b/tests/TypeCombinationTest.php
@@ -940,6 +940,13 @@ class TypeCombinationTest extends TestCase
'"0"',
],
],
+ 'unionOfClassStringAndClassStringWithIntersection' => [
+ 'class-string',
+ [
+ 'class-string',
+ 'class-string',
+ ],
+ ],
];
}
diff --git a/tests/TypeParseTest.php b/tests/TypeParseTest.php
index 2156257e2..e3ddeec2a 100644
--- a/tests/TypeParseTest.php
+++ b/tests/TypeParseTest.php
@@ -1148,6 +1148,14 @@ class TypeParseTest extends TestCase
$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')) {