diff --git a/mypy/newsemanal/semanal_main.py b/mypy/newsemanal/semanal_main.py index 08bdd36a0e91..e0cafda90172 100644 --- a/mypy/newsemanal/semanal_main.py +++ b/mypy/newsemanal/semanal_main.py @@ -66,6 +66,9 @@ def semantic_analysis_for_scc(graph: 'Graph', scc: List[str], errors: Errors) -> """Perform semantic analysis for all modules in a SCC (import cycle). Assume that reachability analysis has already been performed. + + The scc will be processed roughly in the order the modules are included + in the list. """ patches = [] # type: Patches # Note that functions can't define new module-level attributes @@ -152,6 +155,10 @@ def restore_saved_attrs(saved_attrs: SavedAttributes) -> None: def process_top_levels(graph: 'Graph', scc: List[str], patches: Patches) -> None: # Process top levels until everything has been bound. + # Reverse order of the scc so the first modules in the original list will be + # be processed first. This helps with performance. + scc = list(reversed(scc)) + # Initialize ASTs and symbol tables. for id in scc: state = graph[id] diff --git a/test-data/unit/check-attr.test b/test-data/unit/check-attr.test index c98433cf742d..bc5ad3293290 100644 --- a/test-data/unit/check-attr.test +++ b/test-data/unit/check-attr.test @@ -1156,7 +1156,9 @@ C(0).total = 1 # E: Property "total" defined in "C" is read-only import lib [file lib.py] import attr -from other import * +MYPY = False +if MYPY: # Force deferral + from other import * @attr.s class C: diff --git a/test-data/unit/check-classes.test b/test-data/unit/check-classes.test index 563149956ea1..4bed558ead0d 100644 --- a/test-data/unit/check-classes.test +++ b/test-data/unit/check-classes.test @@ -5925,3 +5925,49 @@ class B: class C(A, B): pass [out] + +[case testAttributeDefOrder1] +import a + +[file a.py] +from b import C + +class D(C): + def g(self) -> None: + self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int") + + def f(self) -> None: + reveal_type(self.x) # N: Revealed type is 'builtins.int' + + +[file b.py] +import a + +class C: + def __init__(self) -> None: + self.x = 0 + +[targets b, a, b.C.__init__, a.D.g, a.D.f, __main__] + +[case testAttributeDefOrder2] +class D(C): + def g(self) -> None: + self.x = '' + + def f(self) -> None: + # https://github.com/python/mypy/issues/7162 + reveal_type(self.x) # N: Revealed type is 'builtins.str' + + +class C: + def __init__(self) -> None: + self.x = 0 + +class E(C): + def g(self) -> None: + self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int") + + def f(self) -> None: + reveal_type(self.x) # N: Revealed type is 'builtins.int' + +[targets __main__, __main__, __main__.D.g, __main__.D.f, __main__.C.__init__, __main__.E.g, __main__.E.f] diff --git a/test-data/unit/check-dataclasses.test b/test-data/unit/check-dataclasses.test index 288c37664d22..87c4c850bed0 100644 --- a/test-data/unit/check-dataclasses.test +++ b/test-data/unit/check-dataclasses.test @@ -670,7 +670,9 @@ c.x = 1 # E: Property "x" defined in "C" is read-only import lib [file lib.py] from dataclasses import dataclass -from other import * +MYPY = False +if MYPY: # Force deferral + from other import * @dataclass class C: diff --git a/test-data/unit/check-incremental.test b/test-data/unit/check-incremental.test index 02a7077f4fe2..bee93d77f404 100644 --- a/test-data/unit/check-incremental.test +++ b/test-data/unit/check-incremental.test @@ -4521,12 +4521,12 @@ B = List[A] [builtins fixtures/list.pyi] [out] -tmp/other.pyi:2: error: Module 'lib' has no attribute 'A' +tmp/lib.pyi:4: error: Module 'other' has no attribute 'B' tmp/other.pyi:3: error: Cannot resolve name "B" (possible cyclic definition) [out2] -tmp/other.pyi:2: error: Module 'lib' has no attribute 'A' +tmp/lib.pyi:4: error: Module 'other' has no attribute 'B' tmp/other.pyi:3: error: Cannot resolve name "B" (possible cyclic definition) -tmp/a.py:3: note: Revealed type is 'builtins.list[builtins.list[Any]]' +tmp/a.py:3: note: Revealed type is 'builtins.list[Any]' [case testRecursiveNamedTupleTypedDict] # https://github.com/python/mypy/issues/7125 diff --git a/test-data/unit/check-newsemanal.test b/test-data/unit/check-newsemanal.test index 7483d2513b76..d7030cf07932 100644 --- a/test-data/unit/check-newsemanal.test +++ b/test-data/unit/check-newsemanal.test @@ -74,10 +74,11 @@ from a import bad2 # E: Module 'a' has no attribute 'bad2'; maybe "bad"? [case testNewAnalyzerTypeAnnotationCycle4] import b [file a.py] -# TODO: Could we generate an error here as well? -from b import bad +from b import bad # E: Module 'b' has no attribute 'bad' [file b.py] -from a import bad # E: Module 'a' has no attribute 'bad' +# TODO: Could we generate an error here as well? +from a import bad +[targets a, b, a, b, a, b, a, b, __main__] [case testNewAnalyzerExportedValuesInImportAll] from m import * @@ -225,6 +226,8 @@ class A: class C(B): c: int +[targets b, a, b, a, __main__] + [case testNewAnalyzerTypedDictClass] from mypy_extensions import TypedDict import a @@ -298,6 +301,8 @@ from a import x def f(): pass +[targets a, b, a, a.y, b.f, __main__] + [case testNewAnalyzerRedefinitionAndDeferral1b] import a @@ -323,6 +328,8 @@ if MYPY: # Tweak processing order def f(): pass +[targets b, a, b, a, b.f, a.y, __main__] + [case testNewAnalyzerRedefinitionAndDeferral2a] import a @@ -436,11 +443,11 @@ def main() -> None: import b [file a.py] import b -x = b.x # E: Cannot determine type of 'x' +x = b.x # E: Cannot resolve attribute "x" (possible cyclic definition) \ + # E: Module has no attribute "x" [file b.py] import a -x = a.x # E: Cannot resolve attribute "x" (possible cyclic definition) \ - # E: Module has no attribute "x" +x = a.x [builtins fixtures/module.pyi] [case testNewAnalyzerMutuallyRecursiveOverloadedFunctions] @@ -3081,4 +3088,4 @@ class Yes: ... import a def func() -> int: ... -[targets a, b, a, b.func, a.func, __main__] +[targets b, a, a, b.func, a.func, __main__]