diff --git a/src/Psalm/Internal/Visitor/ReflectorVisitor.php b/src/Psalm/Internal/Visitor/ReflectorVisitor.php index 93ddd716ad2..957dde1fdec 100644 --- a/src/Psalm/Internal/Visitor/ReflectorVisitor.php +++ b/src/Psalm/Internal/Visitor/ReflectorVisitor.php @@ -2440,11 +2440,18 @@ private function getAssertionParts( $assertion_type_parts = explode('|', $assertion_type); foreach ($assertion_type_parts as $i => $assertion_type_part) { - if ($assertion_type_part !== 'falsy' - && !isset($template_types[$assertion_type_part]) - && !isset(Type::PSALM_RESERVED_WORDS[$assertion_type_part]) - ) { - $assertion_type_parts[$i] = $prefix . Type::getFQCLNFromString($assertion_type_part, $this->aliases); + if ($assertion_type_part !== 'falsy') { + $namespaced_type = Type::parseTokens( + Type::fixUpLocalType( + $assertion_type_part, + $this->aliases, + $this->function_template_types + $this->class_template_types, + $this->type_aliases, + null + ) + ); + + $assertion_type_parts[$i] = $prefix . $namespaced_type->getId(); } else { $assertion_type_parts[$i] = $prefix . $assertion_type_part; } diff --git a/tests/AssertTest.php b/tests/AssertTest.php index 3ef15a8c1a0..f57ab027c60 100644 --- a/tests/AssertTest.php +++ b/tests/AssertTest.php @@ -908,6 +908,54 @@ function assertIntOrFoo($b) : void { if (!is_int($a)) $a->bar();', ], + 'assertUnionInNamespace' => [ + ' $interface + * @psalm-assert ExpectedType|class-string $value + */ + function implementsInterface($value, $interface, string $message = ""): void {} + + /** + * @psalm-template ExpectedType of object + * @param mixed $value + * @psalm-param class-string $interface + * @psalm-assert null|ExpectedType|class-string $value + */ + function nullOrImplementsInterface(?object $value, $interface, string $message = ""): void {} + + interface A + { + } + + /** + * @param mixed $value + * + * @psalm-return A|class-string + */ + function consume($value) { + implementsInterface($value, A::class); + + return $value; + } + + + /** + * @param mixed $value + * + * @psalm-return A|class-string|null + */ + function consume2($value) + { + nullOrImplementsInterface($value, A::class); + + return $value; + }' + ], ]; }