Repository: python/mypy

Issue:
(regression: 0.960) Generic[Protocol] fails with dataclass
<!--
  If you're new to mypy and you're not sure whether what you're experiencing is a mypy bug, please see the "Question and Help" form
  instead.
  Please also consider:

  - checking our common issues page: https://mypy.readthedocs.io/en/stable/common_issues.html
  - searching our issue tracker: https://github.com/python/mypy/issues to see if
    it's already been reported
  - asking on gitter chat: https://gitter.im/python/typing
-->

**Bug Report**

<!--
Note: If the problem you are reporting is about a specific library function, then the typeshed tracker is better suited
for this report: https://github.com/python/typeshed/issues
-->

The following code uses Generic with Protocol for dataclass. It passes with mypy 0.950, but fails with 0.960.

```python
from dataclasses import dataclass
from typing import Protocol, Dict, TypeVar, Generic


class DataclassProtocol(Protocol):
    __dataclass_fields__: Dict


T = TypeVar("T", bound=DataclassProtocol)


@dataclass
class MyDataclass:
    x: int = 1


class MyGeneric(Generic[T]):
    ...


class MyClass(MyGeneric[MyDataclass]):
    ...

```

Error messge:

```
error: Type argument "MyDataclass" of "MyGeneric" must be a subtype of "DataclassProtocol"
```

**Your Environment**

<!-- Includhttps://github.com/JSS95e as many relevant details about the environment you experienced the bug in -->

- Mypy version used: 0.960
- Mypy command-line flags: no flag
- Mypy configuration options from `mypy.ini` (and other config files): no config
- Python version used: 3.10
- Operating system and version: Ubuntu 20.04

<!--
You can freely edit this text, please remove all the lines
you believe are unnecessary.
-->

(Edit)

Using `typing.ClassVar` fixes this.

```python
from dataclasses import Field
from typing import Protocol, ClassVar, Dict

class DataclassProtocol(Protocol):
    __dataclass_fields__: ClassVar[Dict[str, Field]]
```



Discussion:
Thanks for opening a new issue with repro! mypy_primer bisects this to #12762

Resolving patch:
diff --git a/mypy/semanal_main.py b/mypy/semanal_main.py
--- a/mypy/semanal_main.py
+++ b/mypy/semanal_main.py
@@ -82,10 +82,10 @@ def semantic_analysis_for_scc(graph: 'Graph', scc: List[str], errors: Errors) ->
     # We use patch callbacks to fix up things when we expect relatively few
     # callbacks to be required.
     apply_semantic_analyzer_patches(patches)
-    # This pass might need fallbacks calculated above.
-    check_type_arguments(graph, scc, errors)
     # Run class decorator hooks (they requite complete MROs and no placeholders).
     apply_class_plugin_hooks(graph, scc, errors)
+    # This pass might need fallbacks calculated above and the results of hooks.
+    check_type_arguments(graph, scc, errors)
     calculate_class_properties(graph, scc, errors)
     check_blockers(graph, scc)
     # Clean-up builtins, so that TypeVar etc. are not accessible without importing.
@@ -133,10 +133,9 @@ def semantic_analysis_for_targets(
         process_top_level_function(analyzer, state, state.id,
                                    n.node.fullname, n.node, n.active_typeinfo, patches)
     apply_semantic_analyzer_patches(patches)
-
+    apply_class_plugin_hooks(graph, [state.id], state.manager.errors)
     check_type_arguments_in_targets(nodes, state, state.manager.errors)
     calculate_class_properties(graph, [state.id], state.manager.errors)
-    apply_class_plugin_hooks(graph, [state.id], state.manager.errors)
 
 
 def restore_saved_attrs(saved_attrs: SavedAttributes) -> None:


Test patch:
diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test
--- a/test-data/unit/check-dataclasses.test
+++ b/test-data/unit/check-dataclasses.test
@@ -1772,3 +1772,21 @@ c = C()
 c2 = C(x=1)
 c.x  # E: "C" has no attribute "x"
 [builtins fixtures/dataclasses.pyi]
+
+[case testDataclassCheckTypeVarBounds]
+# flags: --python-version 3.7
+from dataclasses import dataclass
+from typing import Protocol, Dict, TypeVar, Generic
+
+class DataclassProtocol(Protocol):
+    __dataclass_fields__: Dict
+
+T = TypeVar("T", bound=DataclassProtocol)
+
+@dataclass
+class MyDataclass:
+    x: int = 1
+
+class MyGeneric(Generic[T]): ...
+class MyClass(MyGeneric[MyDataclass]): ...
+[builtins fixtures/dataclasses.pyi]
diff --git a/test-data/unit/fine-grained.test b/test-data/unit/fine-grained.test
--- a/test-data/unit/fine-grained.test
+++ b/test-data/unit/fine-grained.test
@@ -9734,6 +9734,7 @@ class C:
 [out]
 ==
 main:5: error: Unsupported left operand type for + ("str")
+
 [case testNoneAttribute]
 from typing import Generic, TypeVar
 
@@ -9759,3 +9760,30 @@ class ExampleClass(Generic[T]):
         self.example_attribute = None
 [out]
 ==
+
+[case testDataclassCheckTypeVarBoundsInReprocess]
+# flags: --python-version 3.7
+from dataclasses import dataclass
+from typing import Protocol, Dict, TypeVar, Generic
+from m import x
+
+class DataclassProtocol(Protocol):
+    __dataclass_fields__: Dict
+
+T = TypeVar("T", bound=DataclassProtocol)
+
+@dataclass
+class MyDataclass:
+    x: int = 1
+
+class MyGeneric(Generic[T]): ...
+class MyClass(MyGeneric[MyDataclass]):  ...
+
+[file m.py]
+x: int
+[file m.py.2]
+x: str
+
+[builtins fixtures/dataclasses.pyi]
+[out]
+==