Skip to content

Commit fccaab0

Browse files
authored
Fix crash on single item union of alias (#14876)
Fixes #14744
1 parent 59886d2 commit fccaab0

File tree

2 files changed

+22
-1
lines changed

2 files changed

+22
-1
lines changed

mypy/expandtype.py

Lines changed: 7 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -485,9 +485,15 @@ def visit_union_type(self, t: UnionType) -> Type:
485485
# After substituting for type variables in t.items, some resulting types
486486
# might be subtypes of others, however calling make_simplified_union()
487487
# can cause recursion, so we just remove strict duplicates.
488-
return UnionType.make_union(
488+
simplified = UnionType.make_union(
489489
remove_trivial(flatten_nested_unions(expanded)), t.line, t.column
490490
)
491+
# This call to get_proper_type() is unfortunate but is required to preserve
492+
# the invariant that ProperType will stay ProperType after applying expand_type(),
493+
# otherwise a single item union of a type alias will break it. Note this should not
494+
# cause infinite recursion since pathological aliases like A = Union[A, B] are
495+
# banned at the semantic analysis level.
496+
return get_proper_type(simplified)
491497

492498
def visit_partial_type(self, t: PartialType) -> Type:
493499
return t

test-data/unit/check-type-aliases.test

Lines changed: 15 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1028,3 +1028,18 @@ RHSAlias3: type = tuple[int, ...]
10281028
WrongTypeElement = str | tuple[float, 1] # E: Invalid type: try using Literal[1] instead?
10291029
WrongEllipsis = str | tuple[float, float, ...] # E: Unexpected "..."
10301030
[builtins fixtures/tuple.pyi]
1031+
1032+
[case testCompiledNoCrashOnSingleItemUnion]
1033+
# flags: --no-strict-optional
1034+
from typing import Callable, Union, Generic, TypeVar
1035+
1036+
Alias = Callable[[], int]
1037+
1038+
T = TypeVar("T")
1039+
class C(Generic[T]):
1040+
attr: Union[Alias, None] = None
1041+
1042+
@classmethod
1043+
def test(cls) -> None:
1044+
cls.attr
1045+
[builtins fixtures/classmethod.pyi]

0 commit comments

Comments
 (0)