From a249be5ec4e4d162c546f6f58796513094385ced Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Mon, 16 Sep 2024 14:19:41 +0100 Subject: [PATCH 1/7] Add failing test case --- test-data/unit/check-python312.test | 21 +++++++++++++++++++++ 1 file changed, 21 insertions(+) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index a3f4c87120cd..da2495ae851d 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1713,3 +1713,24 @@ type XNested = (1 + (yield 1)) # E: Yield expression cannot be used within a ty type YNested = (1 + (yield from [])) # E: Yield expression cannot be used within a type alias type ZNested = (1 + (a := 1)) # E: Named expression cannot be used within a type alias type KNested = (1 + (await 1)) # E: Await expression cannot be used within a type alias + +[case testPEP695NestedGenericClass] +# flags: --enable-incomplete-feature=NewGenericSyntax +class C[T]: + def g(self) -> T: ... + +class A: + class B[T]: + def __init__(self, a: T) -> None: + self.a = a + + def f(self, x: T) -> T: + return x + def g(self) -> T: + return self.a + +x: A.B[int] +x.f("x") # E: x +reveal_type(x.f) # N: x +reveal_type(x.a) # N: Revealed type is "builtins.int" +reveal_type(x) # N: Revealed type is "__main__.A.B[builtins.int]" From 41c68cec1e2be249e0664191431ee85138bd182c Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 17 Sep 2024 11:45:54 +0100 Subject: [PATCH 2/7] Fix nested class by setting up enclosing class correctly --- mypy/semanal.py | 6 ++++++ test-data/unit/check-python312.test | 18 ++++++++++-------- 2 files changed, 16 insertions(+), 8 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index 782985e3fbab..b73d48b12519 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -824,6 +824,12 @@ def file_context( self.num_incomplete_refs = 0 if active_type: + fn = active_type.fullname + enclosing_fullname = ".".join(fn.split(".")[:-1]) + if "." in enclosing_fullname: + enclosing_node = self.lookup_fully_qualified_or_none(enclosing_fullname) + if enclosing_node and isinstance(enclosing_node.node, TypeInfo): + self._type = enclosing_node.node self.push_type_args(active_type.defn.type_args, active_type.defn) self.incomplete_type_stack.append(False) scope.enter_class(active_type) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index da2495ae851d..035a79c9dd4c 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1717,20 +1717,22 @@ type KNested = (1 + (await 1)) # E: Await expression cannot be used within a ty [case testPEP695NestedGenericClass] # flags: --enable-incomplete-feature=NewGenericSyntax class C[T]: - def g(self) -> T: ... + def f(self) -> T: ... class A: - class B[T]: - def __init__(self, a: T) -> None: + class B[Q]: + def __init__(self, a: Q) -> None: self.a = a - def f(self, x: T) -> T: - return x - def g(self) -> T: + def f(self) -> Q: return self.a + def g(self, x: Q) -> None: ... + + b: B[str] + x: A.B[int] -x.f("x") # E: x -reveal_type(x.f) # N: x +x.g("x") # E: Argument 1 to "g" of "B" has incompatible type "str"; expected "int" reveal_type(x.a) # N: Revealed type is "builtins.int" reveal_type(x) # N: Revealed type is "__main__.A.B[builtins.int]" +reveal_type(A.b) # N: Revealed type is "__main__.A.B[builtins.str]" From 480fa63d7956083de5941d268f7bb6076170d7d3 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 17 Sep 2024 12:47:45 +0100 Subject: [PATCH 3/7] Add test case --- test-data/unit/check-python312.test | 15 ++++++++++++++- 1 file changed, 14 insertions(+), 1 deletion(-) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 035a79c9dd4c..4073b5d23154 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1714,7 +1714,7 @@ type YNested = (1 + (yield from [])) # E: Yield expression cannot be used within type ZNested = (1 + (a := 1)) # E: Named expression cannot be used within a type alias type KNested = (1 + (await 1)) # E: Await expression cannot be used within a type alias -[case testPEP695NestedGenericClass] +[case testPEP695NestedGenericClass1] # flags: --enable-incomplete-feature=NewGenericSyntax class C[T]: def f(self) -> T: ... @@ -1736,3 +1736,16 @@ x.g("x") # E: Argument 1 to "g" of "B" has incompatible type "str"; expected "i reveal_type(x.a) # N: Revealed type is "builtins.int" reveal_type(x) # N: Revealed type is "__main__.A.B[builtins.int]" reveal_type(A.b) # N: Revealed type is "__main__.A.B[builtins.str]" + +[case testPEP695NestedGenericClass2] +# flags: --enable-incomplete-feature=NewGenericSyntax +class A: + def m(self) -> None: + class B[T]: + def f(self) -> T: ... + x: B[int] + reveal_type(x.f()) # N: Revealed type is "builtins.int" + self.a = B[str]() + +reveal_type(A().a) # N: Revealed type is "__main__.B@4[builtins.str]" +reveal_type(A().a.f()) # N: Revealed type is "builtins.str" From b3c56972aaee007c1058fa3c79abfa7988c10034 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 17 Sep 2024 12:52:08 +0100 Subject: [PATCH 4/7] Add another test case --- test-data/unit/check-python312.test | 19 +++++++++++++++++++ 1 file changed, 19 insertions(+) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 4073b5d23154..23e92eb96d5c 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1749,3 +1749,22 @@ class A: reveal_type(A().a) # N: Revealed type is "__main__.B@4[builtins.str]" reveal_type(A().a.f()) # N: Revealed type is "builtins.str" + +[case testPEP695NestedGenericClass3] +# flags: --enable-incomplete-feature=NewGenericSyntax +class C[T]: + def f(self) -> T: ... + class D[S]: + x: T # E: Name "T" is not defined + def g(self) -> S: ... + +a: C[int] +reveal_type(a.f()) # N: Revealed type is "builtins.int" +b: C.D[str] +reveal_type(b.g()) # N: Revealed type is "builtins.str" + +class E[T]: + class F[T]: # E: "T" already defined as a type parameter + x: T + +c: E.F[int] From 71aa04e724e32f7d105320dd6cf097778d10cd35 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 17 Sep 2024 13:10:02 +0100 Subject: [PATCH 5/7] Refactor --- mypy/semanal.py | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/mypy/semanal.py b/mypy/semanal.py index b73d48b12519..522b4abdd5e9 100644 --- a/mypy/semanal.py +++ b/mypy/semanal.py @@ -824,8 +824,7 @@ def file_context( self.num_incomplete_refs = 0 if active_type: - fn = active_type.fullname - enclosing_fullname = ".".join(fn.split(".")[:-1]) + enclosing_fullname = active_type.fullname.rsplit(".", 1)[0] if "." in enclosing_fullname: enclosing_node = self.lookup_fully_qualified_or_none(enclosing_fullname) if enclosing_node and isinstance(enclosing_node.node, TypeInfo): From d2369c43d1af469f0e5b417774e104e211960107 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 17 Sep 2024 13:12:32 +0100 Subject: [PATCH 6/7] Add another test case --- test-data/unit/check-python312.test | 11 +++++++++++ 1 file changed, 11 insertions(+) diff --git a/test-data/unit/check-python312.test b/test-data/unit/check-python312.test index 23e92eb96d5c..89ced8be2c6f 100644 --- a/test-data/unit/check-python312.test +++ b/test-data/unit/check-python312.test @@ -1768,3 +1768,14 @@ class E[T]: x: T c: E.F[int] + +[case testPEP695NestedGenericClass4] +# flags: --enable-incomplete-feature=NewGenericSyntax +class A: + class B[T]: + def __get__(self, instance: A, owner: type[A]) -> T: + return None # E: Incompatible return value type (got "None", expected "T") + f = B[int]() + +a = A() +v = a.f From 5c4cbd2bc24e1310ac9e818ced1524e5c76b210f Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Tue, 17 Sep 2024 13:27:44 +0100 Subject: [PATCH 7/7] Add daemon test case --- test-data/unit/fine-grained-python312.test | 20 ++++++++++++++++++++ 1 file changed, 20 insertions(+) diff --git a/test-data/unit/fine-grained-python312.test b/test-data/unit/fine-grained-python312.test index 3970c8cacfbf..80e4e4ca3bd8 100644 --- a/test-data/unit/fine-grained-python312.test +++ b/test-data/unit/fine-grained-python312.test @@ -80,3 +80,23 @@ from builtins import tuple as B == main:4: error: Incompatible types in assignment (expression has type "int", variable has type "tuple[int, str]") main:5: error: Incompatible types in assignment (expression has type "str", variable has type "tuple[int, str]") + +[case testPEP695NestedGenericClassMethodUpdated] +# flags: --enable-incomplete-feature=NewGenericSyntax +from a import f + +class C: + class D[T]: + x: T + def m(self) -> T: + f() + return self.x + +[file a.py] +def f() -> None: pass + +[file a.py.2] +def f(x: int) -> None: pass +[out] +== +main:8: error: Missing positional argument "x" in call to "f"