diff --git a/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php b/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php index 9dd33594e91..9d0c9a9126e 100644 --- a/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php +++ b/src/Psalm/Internal/PhpVisitor/Reflector/ClassLikeNodeScanner.php @@ -1453,6 +1453,10 @@ private function visitEnumDeclaration( $fq_classlike_name, ); + if ($case_type && $case_type->isSingleEnumCase()) { + $case_type = Type\Atomic\TValueOf::getValueType($case_type, $this->codebase); + } + if ($case_type) { if ($case_type->isSingleIntLiteral()) { $enum_value = $case_type->getSingleIntLiteral()->value; diff --git a/src/Psalm/Type/MutableUnion.php b/src/Psalm/Type/MutableUnion.php index d22059efcab..0b8fd3b524d 100644 --- a/src/Psalm/Type/MutableUnion.php +++ b/src/Psalm/Type/MutableUnion.php @@ -9,6 +9,7 @@ use Psalm\Type\Atomic\Scalar; use Psalm\Type\Atomic\TArray; use Psalm\Type\Atomic\TClassString; +use Psalm\Type\Atomic\TEnumCase; use Psalm\Type\Atomic\TFalse; use Psalm\Type\Atomic\TFloat; use Psalm\Type\Atomic\TInt; @@ -174,6 +175,11 @@ final class MutableUnion implements TypeNode */ private array $literal_float_types = []; + /** + * @var array + */ + private array $enum_case_types = []; + /** * True if the type was passed or returned by reference, or if the type refers to an object's * property or an item in an array. Note that this is not true for locally created references diff --git a/src/Psalm/Type/Union.php b/src/Psalm/Type/Union.php index c6602cd19a4..90e815dd3fb 100644 --- a/src/Psalm/Type/Union.php +++ b/src/Psalm/Type/Union.php @@ -6,6 +6,7 @@ use Psalm\Internal\TypeVisitor\FromDocblockSetter; use Psalm\Storage\ImmutableNonCloneableTrait; use Psalm\Type\Atomic\TClassString; +use Psalm\Type\Atomic\TEnumCase; use Psalm\Type\Atomic\TLiteralFloat; use Psalm\Type\Atomic\TLiteralInt; use Psalm\Type\Atomic\TLiteralString; @@ -186,6 +187,11 @@ final class Union implements TypeNode */ private array $literal_float_types = []; + /** + * @var array + */ + private array $enum_case_types = []; + /** * True if the type was passed or returned by reference, or if the type refers to an object's * property or an item in an array. Note that this is not true for locally created references diff --git a/src/Psalm/Type/UnionTrait.php b/src/Psalm/Type/UnionTrait.php index a500789cf41..443a8a8b4a2 100644 --- a/src/Psalm/Type/UnionTrait.php +++ b/src/Psalm/Type/UnionTrait.php @@ -21,6 +21,7 @@ use Psalm\Type\Atomic\TClosure; use Psalm\Type\Atomic\TConditional; use Psalm\Type\Atomic\TEmptyMixed; +use Psalm\Type\Atomic\TEnumCase; use Psalm\Type\Atomic\TFalse; use Psalm\Type\Atomic\TInt; use Psalm\Type\Atomic\TIntRange; @@ -97,6 +98,8 @@ public function __construct(array $types, array $properties = []) && ($type->as_type || $type instanceof TTemplateParamClass) ) { $this->typed_class_strings[$key] = $type; + } elseif ($type instanceof TEnumCase) { + $this->enum_case_types[$key] = $type; } elseif ($type instanceof TNever) { $this->explicit_never = true; } @@ -1558,4 +1561,9 @@ public function visit(TypeVisitor $visitor): bool return true; } + + public function isSingleEnumCase(): bool + { + return count($this->types) === 1 && count($this->enum_case_types) === 1; + } }