Repository: python/mypy

Issue:
Crash with 'mypy.types.ProperType object expected; got mypy.types.TypeAliasType'
**Crash Report**

When running mypy on the below code it crashes. Please note that it seems to be related to mypyc, bc when using pure mypy it seems to work fine.

**Traceback**

```
foo.py:16: error: INTERNAL ERROR -- Please try using mypy master on GitHub:
https://mypy.readthedocs.io/en/stable/common_issues.html#using-a-development-mypy-build
Please report a bug at https://github.com/python/mypy/issues
version: 1.0.1
Traceback (most recent call last):
  File "mypy/checker.py", line 582, in accept
  File "mypy/nodes.py", line 1301, in accept
  File "mypy/checker.py", line 2648, in visit_assignment_stmt
  File "mypy/checker.py", line 2708, in check_assignment
  File "mypy/checker.py", line 3661, in check_lvalue
  File "mypy/checkexpr.py", line 2779, in analyze_ordinary_member_access
  File "mypy/checkmember.py", line 201, in analyze_member_access
  File "mypy/checkmember.py", line 229, in _analyze_member_access
  File "mypy/checkmember.py", line 431, in analyze_type_type_member_access
  File "mypy/checkmember.py", line 990, in analyze_class_attribute_access
TypeError: mypy.types.ProperType object expected; got mypy.types.TypeAliasType
foo.py:16: : note: use --pdb to drop into pdb
```

**To Reproduce**

```py
from __future__ import annotations

from typing import Any, Callable, Generic, TypeVar, Union

T = TypeVar("T", bound="DummyClass[Any]")
GetterType = Union[str, int]
GetterCall = Callable[[], GetterType]

class DummyClass(Generic[T]):
    _getter: GetterCall | None = None

    @classmethod
    def set_getter(cls, getter: GetterType | GetterCall) -> None:
        cls._getter = (lambda: getter) if isinstance(getter, (str, int)) else getter
```

**Your Environment**


- Mypy version used: 1.0.1
- Mypy command-line flags: n/a
- Mypy configuration options from `mypy.ini` (and other config files): see below
- Python version used:  3.11.0
- Operating system and version: SUSE Linux Enterprise Server 15 SP3

```toml
[tool.mypy]
pretty = true
show_column_numbers = true
warn_unused_configs = true
strict_optional = false
disable_error_code = ["annotation-unchecked"]
explicit_package_bases = true
```



Discussion:
Still happens with mypy 1.1.1

Resolving patch:
diff --git a/mypy/expandtype.py b/mypy/expandtype.py
--- a/mypy/expandtype.py
+++ b/mypy/expandtype.py
@@ -453,9 +453,15 @@ def visit_union_type(self, t: UnionType) -> Type:
         # After substituting for type variables in t.items, some resulting types
         # might be subtypes of others, however calling  make_simplified_union()
         # can cause recursion, so we just remove strict duplicates.
-        return UnionType.make_union(
+        simplified = UnionType.make_union(
             remove_trivial(flatten_nested_unions(expanded)), t.line, t.column
         )
+        # This call to get_proper_type() is unfortunate but is required to preserve
+        # the invariant that ProperType will stay ProperType after applying expand_type(),
+        # otherwise a single item union of a type alias will break it. Note this should not
+        # cause infinite recursion since pathological aliases like A = Union[A, B] are
+        # banned at the semantic analysis level.
+        return get_proper_type(simplified)
 
     def visit_partial_type(self, t: PartialType) -> Type:
         return t


Test patch:
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
@@ -1028,3 +1028,18 @@ RHSAlias3: type = tuple[int, ...]
 WrongTypeElement = str | tuple[float, 1]  # E: Invalid type: try using Literal[1] instead?
 WrongEllipsis = str | tuple[float, float, ...]  # E: Unexpected "..."
 [builtins fixtures/tuple.pyi]
+
+[case testCompiledNoCrashOnSingleItemUnion]
+# flags: --no-strict-optional
+from typing import Callable, Union, Generic, TypeVar
+
+Alias = Callable[[], int]
+
+T = TypeVar("T")
+class C(Generic[T]):
+    attr: Union[Alias, None] = None
+
+    @classmethod
+    def test(cls) -> None:
+        cls.attr
+[builtins fixtures/classmethod.pyi]