|
29 | 29 | SymbolTableNode, MODULE_REF)
|
30 | 30 | from mypy.semanal import FirstPass, SemanticAnalyzer, ThirdPass
|
31 | 31 | from mypy.checker import TypeChecker
|
| 32 | +from mypy.indirection import TypeIndirectionVisitor |
32 | 33 | from mypy.errors import Errors, CompileError, DecodeError, report_internal_error
|
33 | 34 | from mypy import fixup
|
34 | 35 | from mypy.report import Reports
|
@@ -305,6 +306,7 @@ def default_lib_path(data_dir: str, pyversion: Tuple[int, int]) -> List[str]:
|
305 | 306 | PRI_HIGH = 5 # top-level "from X import blah"
|
306 | 307 | PRI_MED = 10 # top-level "import X"
|
307 | 308 | PRI_LOW = 20 # either form inside a function
|
| 309 | +PRI_INDIRECT = 30 # an indirect dependency |
308 | 310 | PRI_ALL = 99 # include all priorities
|
309 | 311 |
|
310 | 312 |
|
@@ -351,6 +353,7 @@ def __init__(self, data_dir: str,
|
351 | 353 | self.modules = self.semantic_analyzer.modules
|
352 | 354 | self.semantic_analyzer_pass3 = ThirdPass(self.modules, self.errors)
|
353 | 355 | self.type_checker = TypeChecker(self.errors, self.modules, options=options)
|
| 356 | + self.indirection_detector = TypeIndirectionVisitor() |
354 | 357 | self.missing_modules = set() # type: Set[str]
|
355 | 358 | self.stale_modules = set() # type: Set[str]
|
356 | 359 | self.rechecked_modules = set() # type: Set[str]
|
@@ -1415,11 +1418,35 @@ def type_check(self) -> None:
|
1415 | 1418 | return
|
1416 | 1419 | with self.wrap_context():
|
1417 | 1420 | manager.type_checker.visit_file(self.tree, self.xpath)
|
| 1421 | + |
| 1422 | + if manager.options.incremental: |
| 1423 | + self._patch_indirect_dependencies(manager.type_checker.module_refs) |
| 1424 | + |
1418 | 1425 | if manager.options.dump_inference_stats:
|
1419 | 1426 | dump_type_stats(self.tree, self.xpath, inferred=True,
|
1420 | 1427 | typemap=manager.type_checker.type_map)
|
1421 | 1428 | manager.report_file(self.tree)
|
1422 | 1429 |
|
| 1430 | + def _patch_indirect_dependencies(self, module_refs: Set[str]) -> None: |
| 1431 | + types = self.manager.type_checker.module_type_map.values() |
| 1432 | + valid = self.valid_references() |
| 1433 | + |
| 1434 | + encountered = self.manager.indirection_detector.find_modules(types) | module_refs |
| 1435 | + extra = encountered - valid |
| 1436 | + |
| 1437 | + for dep in sorted(extra): |
| 1438 | + self.dependencies.append(dep) |
| 1439 | + self.priorities[dep] = PRI_INDIRECT |
| 1440 | + |
| 1441 | + def valid_references(self) -> Set[str]: |
| 1442 | + valid_refs = set(self.dependencies + self.suppressed + self.ancestors) |
| 1443 | + valid_refs .add(self.id) |
| 1444 | + |
| 1445 | + if "os" in valid_refs: |
| 1446 | + valid_refs.add("os.path") |
| 1447 | + |
| 1448 | + return valid_refs |
| 1449 | + |
1423 | 1450 | def write_cache(self) -> None:
|
1424 | 1451 | if self.path and self.manager.options.incremental and not self.manager.errors.is_errors():
|
1425 | 1452 | dep_prios = [self.priorities.get(dep, PRI_HIGH) for dep in self.dependencies]
|
@@ -1598,25 +1625,6 @@ def process_graph(graph: Graph, manager: BuildManager) -> None:
|
1598 | 1625 | else:
|
1599 | 1626 | process_stale_scc(graph, scc)
|
1600 | 1627 |
|
1601 |
| - # TODO: This is a workaround to get around the "chaining imports" problem |
1602 |
| - # with the interface checks. |
1603 |
| - # |
1604 |
| - # That is, if we have a file named `module_a.py` which does: |
1605 |
| - # |
1606 |
| - # import module_b |
1607 |
| - # module_b.module_c.foo(3) |
1608 |
| - # |
1609 |
| - # ...and if the type signature of `module_c.foo(...)` were to change, |
1610 |
| - # module_a_ would not be rechecked since the interface of `module_b` |
1611 |
| - # would not be considered changed. |
1612 |
| - # |
1613 |
| - # As a workaround, this check will force a module's interface to be |
1614 |
| - # considered stale if anything it imports has a stale interface, |
1615 |
| - # which ensures these changes are caught and propagated. |
1616 |
| - if len(stale_deps) > 0: |
1617 |
| - for id in scc: |
1618 |
| - graph[id].mark_interface_stale() |
1619 |
| - |
1620 | 1628 |
|
1621 | 1629 | def order_ascc(graph: Graph, ascc: AbstractSet[str], pri_max: int = PRI_ALL) -> List[str]:
|
1622 | 1630 | """Come up with the ideal processing order within an SCC.
|
|
0 commit comments