Repository: python/mypy
Pull request: Add regression test for recently fixed `deque.copy()` bug
Closes #12641.

This test fails without #12590 applied, but passes on master.

Problem statement:
[Add test case] Bug in return type of `deque.copy()` in generic type

**Bug Report**

Mypy reasons incorrectly about the return type of `collections.deque.copy()` if the item type is a generic with a type parameter inside a generic class.



**To Reproduce**

```py
from collections import deque
from typing import Any, Callable, Generic, List, Protocol, TypeVar

T = TypeVar("T")

def test(item_type: T) -> None:
    a: deque[List[T]] = deque()
    b: deque[List[T]] = a.copy()  # ok


class Test(Generic[T]):
    def test(self) -> None:
        a: deque[List[T]] = deque()
        b: deque[List[T]] = a.copy()  # error: Incompatible types in assignment (expression has type "deque[List[List[T]]]", variable has type "deque[List[T]]")  [assignment]
```

**Expected Behavior**

The return type in the above example should be `List[T]` not `List[List[T]]`.


<!--
  How did you expect your project to behave?
  It’s fine if you’re not sure your understanding is correct.
  Write down what you thought would happen. If you just expected no errors, you can delete this section.
-->


**Your Environment**

<!-- Include as many relevant details about the environment you experienced the bug in -->

- Mypy version used: 0.942
- Mypy command-line flags: `mypy test.py`
- Mypy configuration options from `mypy.ini` (and other config files):
    ```toml
    [tool.mypy]
    strict = true
    namespace_packages = true
    ignore_missing_imports = true
    show_error_codes = true
    exclude = "tests"
    ```

- Python version used: 3.10.2
- Operating system and version: OSX 12.2.1 Monterey

<!--
You can freely edit this text, please remove all the lines
you believe are unnecessary.
-->

Hints from issue discussion:
`deque.copy` in typeshed is just `def copy(self: Self) -> Self:`, so I do think this is a bug in mypy. Does it reproduce on current master with #12590 applied?
> `deque.copy` in typeshed is just `def copy(self: Self) -> Self:`, so I do think this is a bug in mypy. Does it reproduce on current master with #12590 applied?

I can reproduce with 0.942, but not with mypy master. The "first good commit" is indeed 20b0b9b460cd11a4755f70ae08823fa6a8f5fbd4 -- so yep, #12590 fixed this.
Great, let's add a test case for this one too.

Commit message: Add regression test for recently fixed `deque.copy()` bug

Patch to review:
diff --git a/test-data/unit/check-selftype.test b/test-data/unit/check-selftype.test
index ef3d5289ddfd..7e7b0b9affd4 100644
--- a/test-data/unit/check-selftype.test
+++ b/test-data/unit/check-selftype.test
@@ -1220,3 +1220,20 @@ class ThingCollection(Generic[T]):
     def do_thing(self) -> None:
         self.index.update((idx, c) for idx, (k, c) in enumerate(self.collection))
 [builtins fixtures/tuple.pyi]
+
+[case testDequeReturningSelfFromCopy]
+# Tests a bug with generic self types identified in issue #12641
+from typing import Generic, Sequence, TypeVar
+
+T = TypeVar("T")
+Self = TypeVar("Self")
+
+class deque(Sequence[T]):
+    def copy(self: Self) -> Self: ...
+
+class List(Sequence[T]): ...
+
+class Test(Generic[T]):
+    def test(self) -> None:
+        a: deque[List[T]]
+        b: deque[List[T]] = a.copy()


Code review comments:
diff_hunk: @@ -1220,3 +1220,20 @@ class ThingCollection(Generic[T]):
     def do_thing(self) -> None:
         self.index.update((idx, c) for idx, (k, c) in enumerate(self.collection))
 [builtins fixtures/tuple.pyi]
+
+[case testDequeReturningSelfFromCopy]
+# Tests a bug with generic self types identified in issue #12641
+from typing import Generic, Sequence, TypeVar
+
+T = TypeVar("T")
+Self = TypeVar("Self")
+
+class deque(Sequence[T]):
+    def copy(self: Self) -> Self: ...
+
+class List(Sequence[T]): ...
+
+class Test(Generic[T]):
+    def test(self) -> None:
+        a: deque[List[T]]
+        b: deque[List[T]] = a.copy()
path: test-data/unit/check-selftype.test
text: @author:
```suggestion
        # previously this failed with 'Incompatible types in assignment (expression has type "deque[List[List[T]]]", variable has type "deque[List[T]]")'
        b: deque[List[T]] = a.copy()
```