Skip to content

Commit a2f44c6

Browse files
authored
New semantic analyzer: Fix import prios (#6424)
Old semantic analyzer first pass is setting whether an import is a top level one or not. New semantic analyzer reachability pass didn't do this. As a result, this screwed up import priorities, and in turn, ordering of modules within SCCs. This caused many `Cannot determine type of 'foo'` errors since we don't defer module top levels.
1 parent 027b86d commit a2f44c6

File tree

3 files changed

+37
-2
lines changed

3 files changed

+37
-2
lines changed

mypy/newsemanal/semanal_pass1.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,8 @@
11
"""Block/import reachability analysis."""
22

33
from mypy.nodes import (
4-
MypyFile, AssertStmt, IfStmt, Block, AssignmentStmt, ExpressionStmt, ReturnStmt, ForStmt
4+
MypyFile, AssertStmt, IfStmt, Block, AssignmentStmt, ExpressionStmt, ReturnStmt, ForStmt,
5+
Import, ImportAll, ImportFrom, ClassDef, FuncDef
56
)
67
from mypy.traverser import TraverserVisitor
78
from mypy.options import Options
@@ -40,16 +41,32 @@ def visit_file(self, file: MypyFile, fnam: str, mod_id: str, options: Options) -
4041
self.cur_mod_id = mod_id
4142
self.cur_mod_node = file
4243
self.options = options
44+
self.is_global_scope = True
4345

4446
for i, defn in enumerate(file.defs):
47+
if isinstance(defn, (ClassDef, FuncDef)):
48+
self.is_global_scope = False
4549
defn.accept(self)
50+
self.is_global_scope = True
4651
if isinstance(defn, AssertStmt) and assert_will_always_fail(defn, options):
4752
# We've encountered an assert that's always false,
4853
# e.g. assert sys.platform == 'lol'. Truncate the
4954
# list of statements. This mutates file.defs too.
5055
del file.defs[i + 1:]
5156
break
5257

58+
def visit_import_from(self, node: ImportFrom) -> None:
59+
node.is_top_level = self.is_global_scope
60+
super().visit_import_from(node)
61+
62+
def visit_import_all(self, node: ImportAll) -> None:
63+
node.is_top_level = self.is_global_scope
64+
super().visit_import_all(node)
65+
66+
def visit_import(self, node: Import) -> None:
67+
node.is_top_level = self.is_global_scope
68+
super().visit_import(node)
69+
5370
def visit_if_stmt(self, s: IfStmt) -> None:
5471
infer_reachability_of_if_statement(s, self.options)
5572
for node in s.body:

test-data/unit/check-newsemanal.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1399,3 +1399,21 @@ a = A()
13991399
reveal_type(a.x) # E: Revealed type is '__main__.B'
14001400
a.y = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "B")
14011401
[builtins fixtures/property.pyi]
1402+
1403+
[case testNewAnalyzerImportPriosB]
1404+
import b
1405+
[file a.py]
1406+
from b import x
1407+
reveal_type(x) # E: Revealed type is 'Tuple[builtins.int, builtins.int]'
1408+
[file b.py]
1409+
import a
1410+
x = (1, 2)
1411+
1412+
[case testNewAnalyzerImportPriosA]
1413+
import a
1414+
[file a.py]
1415+
from b import x
1416+
reveal_type(x) # E: Revealed type is 'Tuple[builtins.int, builtins.int]'
1417+
[file b.py]
1418+
import a
1419+
x = (1, 2)

test-data/unit/pythoneval.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1369,6 +1369,6 @@ reveal_type(x['test'][0])
13691369
-- fully analyze typeshed
13701370
typing.pyi:251: error: Class typing.Sequence has abstract attributes "__len__"
13711371
typing.pyi:251: note: If it is meant to be abstract, add 'abc.ABCMeta' as an explicit metaclass
1372-
codecs.pyi:49: error: Cannot overwrite NamedTuple attribute "__init__"
13731372
ast.pyi:31: error: Name 'PyCF_ONLY_AST' already defined (possibly by an import)
1373+
codecs.pyi:49: error: Cannot overwrite NamedTuple attribute "__init__"
13741374
_testNewAnalyzerBasicTypeshed_newsemanal.py:4: error: Revealed type is 'builtins.int*'

0 commit comments

Comments
 (0)