You signed in with another tab or window. Reload to refresh your session.You signed out in another tab or window. Reload to refresh your session.You switched accounts on another tab or window. Reload to refresh your session.Dismiss alert
Fix accessing qualified import in incremental mode (#3548)
Fixes#3274.
The problem was that mypy was previously doing the following,
given an empty cache:
1. Analyze the SCCs (ignoring the builtins) in this exact order:
`['c.d']`, then `['c']`, then `['b']`, then `['a']`. No issues here.
2. Parse, typecheck, and write `c.d` to cache -- also no issues here.
2. Parse, typecheck, and write `c` to cache. The error occurs here --
mypy doesn't recognize that `c` has any submodules, and so will not
record `c.d` into `c`'s symbol table. This means the saved cache for
`c` will be essentially empty.
3. When parsing `b`, mypy *will* recognize that `c.d` is a submodule of `c`
due to the import. During the semantic analysis phase, mypy will then
actually modify `c`'s symbol table to include `d`. This exact process
takes place in `SemanticAnalyzer.add_submodules_to_parent_modules`.
This is why typechecking succeeds for `a` and `b` during a fresh
However, this change wasn't ever written to the cache, so won't
be remembered in the next run!
4. Will parse and typecheck `a`, using the modified (but not preserved)
symbol table.
Or to put it more succinctly, the code sometimes seems to be relying on
the assumption that a symbol table for a given module will not be modified
after that SCC is processed. However, this invariant is false due to the
'parent patching' mechanism. It's worth nothing that this patching also
occurs during Python's runtime -- it isn't just an artifact of mypy's
parsing process.
This commit opts for a relatively conservative course of action by
simply re-running this patching process when handling fresh SCCs.
Other potential fixes include deferring writing to cache until *all*
SCCs are processed (which initially seemed like a more robust solution
but broke multiple tests when I tried it), or replacing the current
parent patching mechanism with something entirely different (which seems
like the sort of thing that could subtly break code).
0 commit comments