Skip to content

Commit 18fee78

Browse files
authored
[PEP 695] Generate error if new-style type alias used as base class (#17789)
It doesn't work at runtime.
1 parent a646f33 commit 18fee78

File tree

2 files changed

+50
-3
lines changed

2 files changed

+50
-3
lines changed

mypy/semanal.py

+15
Original file line numberDiff line numberDiff line change
@@ -1824,6 +1824,8 @@ def analyze_class(self, defn: ClassDef) -> None:
18241824
defn, bases, context=defn
18251825
)
18261826

1827+
self.check_type_alias_bases(bases)
1828+
18271829
for tvd in tvar_defs:
18281830
if isinstance(tvd, TypeVarType) and any(
18291831
has_placeholder(t) for t in [tvd.upper_bound] + tvd.values
@@ -1895,6 +1897,19 @@ def analyze_class(self, defn: ClassDef) -> None:
18951897

18961898
self.analyze_class_body_common(defn)
18971899

1900+
def check_type_alias_bases(self, bases: list[Expression]) -> None:
1901+
for base in bases:
1902+
if isinstance(base, IndexExpr):
1903+
base = base.base
1904+
if (
1905+
isinstance(base, RefExpr)
1906+
and isinstance(base.node, TypeAlias)
1907+
and base.node.python_3_12_type_alias
1908+
):
1909+
self.fail(
1910+
'Type alias defined using "type" statement not valid as base class', base
1911+
)
1912+
18981913
def setup_type_vars(self, defn: ClassDef, tvar_defs: list[TypeVarLikeType]) -> None:
18991914
defn.type_vars = tvar_defs
19001915
defn.info.type_vars = []

test-data/unit/check-python312.test

+35-3
Original file line numberDiff line numberDiff line change
@@ -591,6 +591,40 @@ a4: A4
591591
reveal_type(a4) # N: Revealed type is "Union[builtins.int, builtins.str]"
592592
[builtins fixtures/type.pyi]
593593

594+
[case testPEP695TypeAliasNotValidAsBaseClass]
595+
# flags: --enable-incomplete-feature=NewGenericSyntax
596+
from typing import TypeAlias
597+
598+
import m
599+
600+
type A1 = int
601+
class Bad1(A1): # E: Type alias defined using "type" statement not valid as base class
602+
pass
603+
604+
type A2[T] = list[T]
605+
class Bad2(A2[int]): # E: Type alias defined using "type" statement not valid as base class
606+
pass
607+
608+
class Bad3(m.A1): # E: Type alias defined using "type" statement not valid as base class
609+
pass
610+
611+
class Bad4(m.A2[int]): # E: Type alias defined using "type" statement not valid as base class
612+
pass
613+
614+
B1 = int
615+
B2 = list
616+
B3: TypeAlias = int
617+
class Good1(B1): pass
618+
class Good2(B2[int]): pass
619+
class Good3(list[A1]): pass
620+
class Good4(list[A2[int]]): pass
621+
class Good5(B3): pass
622+
623+
[file m.py]
624+
type A1 = str
625+
type A2[T] = list[T]
626+
[typing fixtures/typing-medium.pyi]
627+
594628
[case testPEP695TypeAliasWithUnusedTypeParams]
595629
# flags: --enable-incomplete-feature=NewGenericSyntax
596630
type A[T] = int
@@ -637,9 +671,7 @@ class D: pass
637671

638672
type A = C
639673

640-
# Note that this doesn't actually work at runtime, but we currently don't
641-
# keep track whether a type alias is valid in various runtime type contexts.
642-
class D(A):
674+
class D(A): # E: Type alias defined using "type" statement not valid as base class
643675
pass
644676

645677
class C: pass

0 commit comments

Comments
 (0)