From 0ceb6ada277292012b333d4923ceea89eb5f8227 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Mon, 13 Jan 2025 00:38:31 +0100 Subject: [PATCH 1/4] Do not call get_proper_type for traversing type alias: that creates a copy preventing union items update. --- mypy/semanal_typeargs.py | 2 +- test-data/unit/check-python312.test | 16 ++++++++++++++++ test-data/unit/check-type-aliases.test | 13 +++++++++---- 3 files changed, 26 insertions(+), 5 deletions(-) diff --git a/mypy/semanal_typeargs.py b/mypy/semanal_typeargs.py index 435abb78ca43..e9240f74a951 100644 --- a/mypy/semanal_typeargs.py +++ b/mypy/semanal_typeargs.py @@ -101,7 +101,7 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None: if not is_error: # If there was already an error for the alias itself, there is no point in checking # the expansion, most likely it will result in the same kind of error. - get_proper_type(t).accept(self) + t.alias.target.accept(self) def visit_tuple_type(self, t: TupleType) -> None: t.items = flatten_nested_tuples(t.items) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 8b4d638ecdaa..80cceea85581 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1972,3 +1972,19 @@ class D: class G[Q]: def g(self, x: Q): ... d: G[str] + +[case testTypeAliasNormalization] +from collections.abc import Callable +from typing import Unpack +from typing_extensions import TypeAlias + +type RK_function_args = tuple[float, int] +type RK_functionBIS = Callable[[Unpack[RK_function_args], int], int] + +def ff(a: float, b: int, c: int) -> int: + return 2 + +bis: RK_functionBIS = ff +res: int = bis(1.0, 2, 3) +[builtins fixtures/tuple.pyi] +[typing fixtures/typing-full.pyi] diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index f04bd777ee4e..df635483f3d1 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -977,13 +977,18 @@ class C(Generic[T]): ... class D(C[S]): ... # E: Invalid type argument value for "C" U = TypeVar("U") -A = List[C[U]] -x: A[bytes] # E: Value of type variable "T" of "C" cannot be "bytes" +A = List[C[U]] # E: Type variable "U" not valid as type argument value for "C" +A2 = List[C[T]] +x: A[bytes] +x2: A2[bytes] # E: Value of type variable "T" of "A2" cannot be "bytes" V = TypeVar("V", bound=int) +V2 = TypeVar("V2", bound=int) class E(Generic[V]): ... -B = List[E[U]] -y: B[str] # E: Type argument "str" of "E" must be a subtype of "int" +B = List[E[U]] # E: Type argument "U" of "E" must be a subtype of "int" +B2 = List[E[V2]] +y: B[str] +y2: B2[str] # E: Type argument "str" of "B2" must be a subtype of "int" [case testValidTypeAliasValuesMoreRestrictive] from typing import TypeVar, Generic, List From 7ed6d1b0a2543b5f29cdc281277ac625324ed467 Mon Sep 17 00:00:00 2001 From: STerliakov Date: Wed, 15 Jan 2025 00:40:13 +0100 Subject: [PATCH 2/4] Address what ilevkivskyi noticed: there's a missing traversal path --- mypy/mixedtraverser.py | 16 +++++++++++++--- 1 file changed, 13 insertions(+), 3 deletions(-) diff --git a/mypy/mixedtraverser.py b/mypy/mixedtraverser.py index 9fdc4457d18e..1e49922b94b8 100644 --- a/mypy/mixedtraverser.py +++ b/mypy/mixedtraverser.py @@ -10,7 +10,9 @@ NamedTupleExpr, NewTypeExpr, PromoteExpr, + TypeAlias, TypeAliasExpr, + TypeAliasStmt, TypeApplication, TypedDictExpr, TypeVarExpr, @@ -48,9 +50,7 @@ def visit_class_def(self, o: ClassDef, /) -> None: def visit_type_alias_expr(self, o: TypeAliasExpr, /) -> None: super().visit_type_alias_expr(o) - self.in_type_alias_expr = True - o.node.target.accept(self) - self.in_type_alias_expr = False + o.node.accept(self) def visit_type_var_expr(self, o: TypeVarExpr, /) -> None: super().visit_type_var_expr(o) @@ -81,6 +81,16 @@ def visit_assignment_stmt(self, o: AssignmentStmt, /) -> None: super().visit_assignment_stmt(o) self.visit_optional_type(o.type) + def visit_type_alias_stmt(self, o: TypeAliasStmt, /) -> None: + super().visit_type_alias_stmt(o) + self.visit_optional_type(o.alias_node) + + def visit_type_alias(self, o: TypeAlias, /) -> None: + super().visit_type_alias(o) + self.in_type_alias_expr = True + o.target.accept(self) + self.in_type_alias_expr = False + def visit_for_stmt(self, o: ForStmt, /) -> None: super().visit_for_stmt(o) self.visit_optional_type(o.index_type) From aa00f0777d143fae27755cfe2cc068028076e84b Mon Sep 17 00:00:00 2001 From: STerliakov Date: Wed, 15 Jan 2025 00:41:15 +0100 Subject: [PATCH 3/4] Revert the previous attempt --- mypy/semanal_typeargs.py | 2 +- test-data/unit/check-type-aliases.test | 13 ++++--------- 2 files changed, 5 insertions(+), 10 deletions(-) diff --git a/mypy/semanal_typeargs.py b/mypy/semanal_typeargs.py index e9240f74a951..435abb78ca43 100644 --- a/mypy/semanal_typeargs.py +++ b/mypy/semanal_typeargs.py @@ -101,7 +101,7 @@ def visit_type_alias_type(self, t: TypeAliasType) -> None: if not is_error: # If there was already an error for the alias itself, there is no point in checking # the expansion, most likely it will result in the same kind of error. - t.alias.target.accept(self) + get_proper_type(t).accept(self) def visit_tuple_type(self, t: TupleType) -> None: t.items = flatten_nested_tuples(t.items) diff --git a/test-data/unit/check-type-aliases.test b/test-data/unit/check-type-aliases.test index df635483f3d1..f04bd777ee4e 100644 --- a/test-data/unit/check-type-aliases.test +++ b/test-data/unit/check-type-aliases.test @@ -977,18 +977,13 @@ class C(Generic[T]): ... class D(C[S]): ... # E: Invalid type argument value for "C" U = TypeVar("U") -A = List[C[U]] # E: Type variable "U" not valid as type argument value for "C" -A2 = List[C[T]] -x: A[bytes] -x2: A2[bytes] # E: Value of type variable "T" of "A2" cannot be "bytes" +A = List[C[U]] +x: A[bytes] # E: Value of type variable "T" of "C" cannot be "bytes" V = TypeVar("V", bound=int) -V2 = TypeVar("V2", bound=int) class E(Generic[V]): ... -B = List[E[U]] # E: Type argument "U" of "E" must be a subtype of "int" -B2 = List[E[V2]] -y: B[str] -y2: B2[str] # E: Type argument "str" of "B2" must be a subtype of "int" +B = List[E[U]] +y: B[str] # E: Type argument "str" of "E" must be a subtype of "int" [case testValidTypeAliasValuesMoreRestrictive] from typing import TypeVar, Generic, List From 79cbce7d439e02ba549863f521b937f412ae197c Mon Sep 17 00:00:00 2001 From: STerliakov Date: Wed, 15 Jan 2025 00:50:50 +0100 Subject: [PATCH 4/4] Fix typing --- mypy/mixedtraverser.py | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/mypy/mixedtraverser.py b/mypy/mixedtraverser.py index 1e49922b94b8..324e8a87c1bd 100644 --- a/mypy/mixedtraverser.py +++ b/mypy/mixedtraverser.py @@ -83,7 +83,8 @@ def visit_assignment_stmt(self, o: AssignmentStmt, /) -> None: def visit_type_alias_stmt(self, o: TypeAliasStmt, /) -> None: super().visit_type_alias_stmt(o) - self.visit_optional_type(o.alias_node) + if o.alias_node is not None: + o.alias_node.accept(self) def visit_type_alias(self, o: TypeAlias, /) -> None: super().visit_type_alias(o)