Repository: python/mypy

Issue:
Variant of alias for enum type cannot be used as Literal
```python
class Foo(Enum):
    A = 1

F = Foo

# works
x: Literal[Foo.A]
# name-defined error
y: Literal[F.A]
```

Is there a simple workaround here? I also tried `F: Final = Foo` which doesn't work either


Discussion:
This looks like a bug. I'm not sure if there's any general workaround right now.

cc @Michael0x2a (literal types) and @ilevkivskyi (type aliases)
This looks like a missing case in `lookup_qualified()`, this doesn't work either:
```python
class Out:
    class In:
        ...
O = Out
z: O.In  # Same name not defined error
```
Interestingly, `visit_member_expr()` has an `elif` branch for this, so for example this works (on master):
```python
f: Final = F.A
reveal_type(f)  # Revealed type is 'Literal[__main__.Foo.A]?'
```
Should be easy to fix.

Resolving patch:
diff --git a/mypy/semanal.py b/mypy/semanal.py
--- a/mypy/semanal.py
+++ b/mypy/semanal.py
@@ -3621,7 +3621,6 @@ def visit_member_expr(self, expr: MemberExpr) -> None:
                         type_info = self.type
             elif isinstance(base.node, TypeAlias) and base.node.no_args:
                 assert isinstance(base.node.target, ProperType)
-                # TODO: support chained aliases.
                 if isinstance(base.node.target, Instance):
                     type_info = base.node.target.type
 
@@ -3969,6 +3968,10 @@ def lookup_qualified(self, name: str, ctx: Context,
                     namespace = node.fullname
                 elif isinstance(node, PlaceholderNode):
                     return sym
+                elif isinstance(node, TypeAlias) and node.no_args:
+                    assert isinstance(node.target, ProperType)
+                    if isinstance(node.target, Instance):
+                        nextsym = node.target.type.get(part)
                 else:
                     if isinstance(node, Var):
                         typ = get_proper_type(node.type)


Test patch:
diff --git a/test-data/unit/check-literal.test b/test-data/unit/check-literal.test
--- a/test-data/unit/check-literal.test
+++ b/test-data/unit/check-literal.test
@@ -3149,3 +3149,17 @@ err_code = -TWO
 if bool():
     err_code = -THREE
 [builtins fixtures/float.pyi]
+
+[case testAliasForEnumTypeAsLiteral]
+from typing_extensions import Literal
+from enum import Enum
+
+class Foo(Enum):
+    A = 1
+
+F = Foo
+
+x: Literal[Foo.A]
+y: Literal[F.A]
+reveal_type(x)  # N: Revealed type is 'Literal[__main__.Foo.A]'
+reveal_type(y)  # N: Revealed type is 'Literal[__main__.Foo.A]'
diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test
--- a/test-data/unit/check-type-aliases.test
+++ b/test-data/unit/check-type-aliases.test
@@ -632,3 +632,24 @@ except E as e:
     reveal_type(e)  # N: Revealed type is '__main__.E'
 [builtins fixtures/exception.pyi]
 [out]
+
+[case testNestedClassOnAliasAsType]
+class Out:
+    class In:
+        class Inner:
+            pass
+
+O = Out
+I = Out.In
+OI = O.In
+A = Out
+B = A
+
+w: O.In
+x: I.Inner
+y: OI.Inner
+z: B.In
+reveal_type(w)  # N: Revealed type is '__main__.Out.In'
+reveal_type(x)  # N: Revealed type is '__main__.Out.In.Inner'
+reveal_type(y)  # N: Revealed type is '__main__.Out.In.Inner'
+reveal_type(z)  # N: Revealed type is '__main__.Out.In'