From 73bfce5667999345b617783804cfc8cc563cb48e Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 5 Jun 2024 16:25:07 +0100 Subject: [PATCH 1/3] [PEP 695] Don't crash when redefining something as a type alias Generate an error instead. --- mypy/semanal.py | 6 +++++- test-data/unit/check-python312.test | 27 +++++++++++++++++++++++++++ 2 files changed, 32 insertions(+), 1 deletion(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 2448ea8485f7..7f8851986a90 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -5318,6 +5318,11 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None: all_type_params_names = [p.name for p in s.type_args] try: + existing = self.current_symbol_table().get(s.name.name) + if existing and not isinstance(existing.node, (PlaceholderNode, TypeAlias)): + self.already_defined(s.name.name, s, existing, "Name") + return + tag = self.track_incomplete_refs() res, alias_tvars, depends_on, qualified_tvars, empty_tuple_index = self.analyze_alias( s.name.name, @@ -5373,7 +5378,6 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None: python_3_12_type_alias=True, ) - existing = self.current_symbol_table().get(s.name.name) if ( existing and isinstance(existing.node, (PlaceholderNode, TypeAlias)) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 2b67f56e679c..2081d671bdb1 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1453,3 +1453,30 @@ class E[T]: reveal_type(E[str]().a) # N: Revealed type is "builtins.list[Any]" [builtins fixtures/tuple.pyi] [typing fixtures/typing-full.pyi] + +[case testPEP695RedefineAsTypeAlias1] +# flags: --enable-incomplete-feature=NewGenericSyntax +class C: pass +type C = int # E: Name "C" already defined on line 2 + +A = 0 +type A = str # E: Name "A" already defined on line 5 +reveal_type(A) # N: Revealed type is "builtins.int" + +[case testPEP695RedefineAsTypeAlias2] +# flags: --enable-incomplete-feature=NewGenericSyntax +from m import D +type D = int # E: Name "D" already defined (possibly by an import) +a: D +reveal_type(a) # N: Revealed type is "m.D" +[file m.py] +class D: pass + +[case testPEP695MultiDefinitionsForTypeAlias] +# flags: --enable-incomplete-feature=NewGenericSyntax +if int(): + type A[T] = list[T] +else: + type A[T] = str # E: Name "A" already defined on line 3 +a: A[int] +reveal_type(a) # N: Revealed type is "builtins.list[builtins.int]" From 00242ef1d7905c2bed23e1d884359c2436f6e418 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 5 Jun 2024 16:47:46 +0100 Subject: [PATCH 2/3] Handle placeholders better --- mypy/semanal.py | 5 ++++- test-data/unit/check-python312.test | 6 ++++++ 2 files changed, 10 insertions(+), 1 deletion(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 7f8851986a90..dde652449fc7 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -5319,7 +5319,10 @@ def visit_type_alias_stmt(self, s: TypeAliasStmt) -> None: try: existing = self.current_symbol_table().get(s.name.name) - if existing and not isinstance(existing.node, (PlaceholderNode, TypeAlias)): + if existing and not ( + isinstance(existing.node, TypeAlias) + or (isinstance(existing.node, PlaceholderNode) and existing.node.line == s.line) + ): self.already_defined(s.name.name, s, existing, "Name") return diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 2081d671bdb1..18817ab5aa28 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1472,6 +1472,12 @@ reveal_type(a) # N: Revealed type is "m.D" [file m.py] class D: pass +[case testPEP695RedefineAsTypeAlias3] +# flags: --enable-incomplete-feature=NewGenericSyntax +D = list["Forward"] +type D = int # E: Name "D" already defined on line 2 +Forward = str + [case testPEP695MultiDefinitionsForTypeAlias] # flags: --enable-incomplete-feature=NewGenericSyntax if int(): From 7a22997e5700d8fb7a79c3aebc240610c41eaabc Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Wed, 5 Jun 2024 16:49:19 +0100 Subject: [PATCH 3/3] Update test case --- test-data/unit/check-python312.test | 3 +++ 1 file changed, 3 insertions(+) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 18817ab5aa28..52f77243fd0a 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1477,6 +1477,8 @@ class D: pass D = list["Forward"] type D = int # E: Name "D" already defined on line 2 Forward = str +x: D +reveal_type(x) # N: Revealed type is "builtins.list[builtins.str]" [case testPEP695MultiDefinitionsForTypeAlias] # flags: --enable-incomplete-feature=NewGenericSyntax @@ -1484,5 +1486,6 @@ if int(): type A[T] = list[T] else: type A[T] = str # E: Name "A" already defined on line 3 +x: T # E: Name "T" is not defined a: A[int] reveal_type(a) # N: Revealed type is "builtins.list[builtins.int]"