Skip to content

Commit 028f202

Browse files
authored
New analyzer: reverse order of modules within SCC (#7163)
This brings the new semantic analyzer closer to the old one and slightly helps performance.
1 parent a514ba2 commit 028f202

File tree

6 files changed

+76
-12
lines changed

6 files changed

+76
-12
lines changed

mypy/newsemanal/semanal_main.py

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -66,6 +66,9 @@ def semantic_analysis_for_scc(graph: 'Graph', scc: List[str], errors: Errors) ->
6666
"""Perform semantic analysis for all modules in a SCC (import cycle).
6767
6868
Assume that reachability analysis has already been performed.
69+
70+
The scc will be processed roughly in the order the modules are included
71+
in the list.
6972
"""
7073
patches = [] # type: Patches
7174
# Note that functions can't define new module-level attributes
@@ -152,6 +155,10 @@ def restore_saved_attrs(saved_attrs: SavedAttributes) -> None:
152155
def process_top_levels(graph: 'Graph', scc: List[str], patches: Patches) -> None:
153156
# Process top levels until everything has been bound.
154157

158+
# Reverse order of the scc so the first modules in the original list will be
159+
# be processed first. This helps with performance.
160+
scc = list(reversed(scc))
161+
155162
# Initialize ASTs and symbol tables.
156163
for id in scc:
157164
state = graph[id]

test-data/unit/check-attr.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1156,7 +1156,9 @@ C(0).total = 1 # E: Property "total" defined in "C" is read-only
11561156
import lib
11571157
[file lib.py]
11581158
import attr
1159-
from other import *
1159+
MYPY = False
1160+
if MYPY: # Force deferral
1161+
from other import *
11601162

11611163
@attr.s
11621164
class C:

test-data/unit/check-classes.test

Lines changed: 46 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5925,3 +5925,49 @@ class B:
59255925

59265926
class C(A, B): pass
59275927
[out]
5928+
5929+
[case testAttributeDefOrder1]
5930+
import a
5931+
5932+
[file a.py]
5933+
from b import C
5934+
5935+
class D(C):
5936+
def g(self) -> None:
5937+
self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
5938+
5939+
def f(self) -> None:
5940+
reveal_type(self.x) # N: Revealed type is 'builtins.int'
5941+
5942+
5943+
[file b.py]
5944+
import a
5945+
5946+
class C:
5947+
def __init__(self) -> None:
5948+
self.x = 0
5949+
5950+
[targets b, a, b.C.__init__, a.D.g, a.D.f, __main__]
5951+
5952+
[case testAttributeDefOrder2]
5953+
class D(C):
5954+
def g(self) -> None:
5955+
self.x = ''
5956+
5957+
def f(self) -> None:
5958+
# https://github.com/python/mypy/issues/7162
5959+
reveal_type(self.x) # N: Revealed type is 'builtins.str'
5960+
5961+
5962+
class C:
5963+
def __init__(self) -> None:
5964+
self.x = 0
5965+
5966+
class E(C):
5967+
def g(self) -> None:
5968+
self.x = '' # E: Incompatible types in assignment (expression has type "str", variable has type "int")
5969+
5970+
def f(self) -> None:
5971+
reveal_type(self.x) # N: Revealed type is 'builtins.int'
5972+
5973+
[targets __main__, __main__, __main__.D.g, __main__.D.f, __main__.C.__init__, __main__.E.g, __main__.E.f]

test-data/unit/check-dataclasses.test

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -670,7 +670,9 @@ c.x = 1 # E: Property "x" defined in "C" is read-only
670670
import lib
671671
[file lib.py]
672672
from dataclasses import dataclass
673-
from other import *
673+
MYPY = False
674+
if MYPY: # Force deferral
675+
from other import *
674676

675677
@dataclass
676678
class C:

test-data/unit/check-incremental.test

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -4521,12 +4521,12 @@ B = List[A]
45214521

45224522
[builtins fixtures/list.pyi]
45234523
[out]
4524-
tmp/other.pyi:2: error: Module 'lib' has no attribute 'A'
4524+
tmp/lib.pyi:4: error: Module 'other' has no attribute 'B'
45254525
tmp/other.pyi:3: error: Cannot resolve name "B" (possible cyclic definition)
45264526
[out2]
4527-
tmp/other.pyi:2: error: Module 'lib' has no attribute 'A'
4527+
tmp/lib.pyi:4: error: Module 'other' has no attribute 'B'
45284528
tmp/other.pyi:3: error: Cannot resolve name "B" (possible cyclic definition)
4529-
tmp/a.py:3: note: Revealed type is 'builtins.list[builtins.list[Any]]'
4529+
tmp/a.py:3: note: Revealed type is 'builtins.list[Any]'
45304530

45314531
[case testRecursiveNamedTupleTypedDict]
45324532
# https://github.com/python/mypy/issues/7125

test-data/unit/check-newsemanal.test

Lines changed: 14 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -74,10 +74,11 @@ from a import bad2 # E: Module 'a' has no attribute 'bad2'; maybe "bad"?
7474
[case testNewAnalyzerTypeAnnotationCycle4]
7575
import b
7676
[file a.py]
77-
# TODO: Could we generate an error here as well?
78-
from b import bad
77+
from b import bad # E: Module 'b' has no attribute 'bad'
7978
[file b.py]
80-
from a import bad # E: Module 'a' has no attribute 'bad'
79+
# TODO: Could we generate an error here as well?
80+
from a import bad
81+
[targets a, b, a, b, a, b, a, b, __main__]
8182

8283
[case testNewAnalyzerExportedValuesInImportAll]
8384
from m import *
@@ -225,6 +226,8 @@ class A:
225226
class C(B):
226227
c: int
227228

229+
[targets b, a, b, a, __main__]
230+
228231
[case testNewAnalyzerTypedDictClass]
229232
from mypy_extensions import TypedDict
230233
import a
@@ -298,6 +301,8 @@ from a import x
298301

299302
def f(): pass
300303

304+
[targets a, b, a, a.y, b.f, __main__]
305+
301306
[case testNewAnalyzerRedefinitionAndDeferral1b]
302307
import a
303308

@@ -323,6 +328,8 @@ if MYPY: # Tweak processing order
323328

324329
def f(): pass
325330

331+
[targets b, a, b, a, b.f, a.y, __main__]
332+
326333
[case testNewAnalyzerRedefinitionAndDeferral2a]
327334
import a
328335

@@ -436,11 +443,11 @@ def main() -> None:
436443
import b
437444
[file a.py]
438445
import b
439-
x = b.x # E: Cannot determine type of 'x'
446+
x = b.x # E: Cannot resolve attribute "x" (possible cyclic definition) \
447+
# E: Module has no attribute "x"
440448
[file b.py]
441449
import a
442-
x = a.x # E: Cannot resolve attribute "x" (possible cyclic definition) \
443-
# E: Module has no attribute "x"
450+
x = a.x
444451
[builtins fixtures/module.pyi]
445452

446453
[case testNewAnalyzerMutuallyRecursiveOverloadedFunctions]
@@ -3081,4 +3088,4 @@ class Yes: ...
30813088
import a
30823089

30833090
def func() -> int: ...
3084-
[targets a, b, a, b.func, a.func, __main__]
3091+
[targets b, a, a, b.func, a.func, __main__]

0 commit comments

Comments
 (0)