Skip to content

Commit 154ac75

Browse files
committed
Run dataclass plugin before checking type var bounds (#12908)
The plugin may add attributes that are needed to perform the bound check. Fixes #12876.
1 parent f649e2d commit 154ac75

File tree

3 files changed

+49
-4
lines changed

3 files changed

+49
-4
lines changed

Diff for: mypy/semanal_main.py

+3-4
Original file line numberDiff line numberDiff line change
@@ -82,10 +82,10 @@ def semantic_analysis_for_scc(graph: 'Graph', scc: List[str], errors: Errors) ->
8282
# We use patch callbacks to fix up things when we expect relatively few
8383
# callbacks to be required.
8484
apply_semantic_analyzer_patches(patches)
85-
# This pass might need fallbacks calculated above.
86-
check_type_arguments(graph, scc, errors)
8785
# Run class decorator hooks (they requite complete MROs and no placeholders).
8886
apply_class_plugin_hooks(graph, scc, errors)
87+
# This pass might need fallbacks calculated above and the results of hooks.
88+
check_type_arguments(graph, scc, errors)
8989
calculate_class_properties(graph, scc, errors)
9090
check_blockers(graph, scc)
9191
# Clean-up builtins, so that TypeVar etc. are not accessible without importing.
@@ -133,10 +133,9 @@ def semantic_analysis_for_targets(
133133
process_top_level_function(analyzer, state, state.id,
134134
n.node.fullname, n.node, n.active_typeinfo, patches)
135135
apply_semantic_analyzer_patches(patches)
136-
136+
apply_class_plugin_hooks(graph, [state.id], state.manager.errors)
137137
check_type_arguments_in_targets(nodes, state, state.manager.errors)
138138
calculate_class_properties(graph, [state.id], state.manager.errors)
139-
apply_class_plugin_hooks(graph, [state.id], state.manager.errors)
140139

141140

142141
def restore_saved_attrs(saved_attrs: SavedAttributes) -> None:

Diff for: test-data/unit/check-dataclasses.test

+18
Original file line numberDiff line numberDiff line change
@@ -1772,3 +1772,21 @@ c = C()
17721772
c2 = C(x=1)
17731773
c.x # E: "C" has no attribute "x"
17741774
[builtins fixtures/dataclasses.pyi]
1775+
1776+
[case testDataclassCheckTypeVarBounds]
1777+
# flags: --python-version 3.7
1778+
from dataclasses import dataclass
1779+
from typing import Protocol, Dict, TypeVar, Generic
1780+
1781+
class DataclassProtocol(Protocol):
1782+
__dataclass_fields__: Dict
1783+
1784+
T = TypeVar("T", bound=DataclassProtocol)
1785+
1786+
@dataclass
1787+
class MyDataclass:
1788+
x: int = 1
1789+
1790+
class MyGeneric(Generic[T]): ...
1791+
class MyClass(MyGeneric[MyDataclass]): ...
1792+
[builtins fixtures/dataclasses.pyi]

Diff for: test-data/unit/fine-grained.test

+28
Original file line numberDiff line numberDiff line change
@@ -9734,6 +9734,7 @@ class C:
97349734
[out]
97359735
==
97369736
main:5: error: Unsupported left operand type for + ("str")
9737+
97379738
[case testNoneAttribute]
97389739
from typing import Generic, TypeVar
97399740

@@ -9759,3 +9760,30 @@ class ExampleClass(Generic[T]):
97599760
self.example_attribute = None
97609761
[out]
97619762
==
9763+
9764+
[case testDataclassCheckTypeVarBoundsInReprocess]
9765+
# flags: --python-version 3.7
9766+
from dataclasses import dataclass
9767+
from typing import Protocol, Dict, TypeVar, Generic
9768+
from m import x
9769+
9770+
class DataclassProtocol(Protocol):
9771+
__dataclass_fields__: Dict
9772+
9773+
T = TypeVar("T", bound=DataclassProtocol)
9774+
9775+
@dataclass
9776+
class MyDataclass:
9777+
x: int = 1
9778+
9779+
class MyGeneric(Generic[T]): ...
9780+
class MyClass(MyGeneric[MyDataclass]): ...
9781+
9782+
[file m.py]
9783+
x: int
9784+
[file m.py.2]
9785+
x: str
9786+
9787+
[builtins fixtures/dataclasses.pyi]
9788+
[out]
9789+
==

0 commit comments

Comments
 (0)