-
-
Notifications
You must be signed in to change notification settings - Fork 2.9k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
Foundation for fine-grained incremental checking #2838
Conversation
@@ -0,0 +1,495 @@ | |||
-- Test cases for AST merge (user for fine-grained incremental checking) |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The important thing here is that we test that identities of certain nodes are preserved across merge. <id>
suffixes represent object identities (somewhat similar to id(x)
), and they only make sense within a single test case. Two things within a single test case that share an id have the same identity, and two things with different ids have different identities.
The travis failures look strange. I'll investigate them tomorrow. |
mypy/server/astdiff.py
Outdated
* If one of the types is not valid for whatever reason, they are | ||
considered different. | ||
|
||
* Sometimes require types to be structurally identical, even if the |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo "if the are" -> "if they are"
mypy/server/aststrip.py
Outdated
@@ -0,0 +1,49 @@ | |||
"""Strip AST from from semantic and type information.""" |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
typo: "from from" -> "from"
Rebased and squashed most commits to help rebasing. Still trying to get a passing travis build. |
self.pass_num += 1 | ||
todo = self.deferred_nodes | ||
if not todo: | ||
todo = self.deferred_nodes |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Hm, what if todo and self.deferred_nodes are both non-empty?
mypy/checker.py
Outdated
@@ -568,7 +584,7 @@ def is_implicit_any(t: Type) -> bool: | |||
for i in range(len(typ.arg_types)): | |||
arg_type = typ.arg_types[i] | |||
|
|||
ref_type = self.scope.active_class() | |||
ref_type = self.scope.active_self_type() # type: Type |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Optional[Type]
mypy/checker.py
Outdated
|
||
def __init__(self, module: MypyFile) -> None: | ||
self.stack = [module] | ||
|
||
def top_function(self) -> Optional[FuncItem]: | ||
def top_function(self) -> Optional[FuncDef]: | ||
for e in reversed(self.stack): | ||
if isinstance(e, FuncItem): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
FuncDef
self.pop_target_component() | ||
|
||
def push_target_component(self, name: str) -> None: | ||
if self.target and not self.function_or_member[-1]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Can you explain the relationship between target and function_and_member?
def refresh_top_level(self, file_node: MypyFile) -> None: | ||
"""Reanalyze a stale module top-level in fine-grained incremental mode.""" | ||
for d in file_node.defs: | ||
if not isinstance(d, (FuncItem, ClassDef)): |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
TODO: analyze class bodies?
class B(C): pass | ||
[file m.py.2] | ||
class C: pass | ||
class B: pass |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Preserve C.g.
mypy/semanal.py
Outdated
defn.defs.accept(self) | ||
|
||
@contextmanager | ||
def analyze_class_body(self, defn: ClassDef) -> Iterator[None]: |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Better name??
* Add AST diff * Add fine-grained dependency generation * Add AST merge for merging old and new ASTs for a module * Update AST dump to show various object identities * Add various tests
In fine-grained incremental mode keep reporting errors for targets with errors even if the targets weren't explicitly triggered during successive iterations. We currently repeatedly type check these targets. Alternatively, we could perhaps just keep generating the errors without actually re-type-checking the targets, but there's a risk that it will be hard to always do this correctly, so we are starting with this simple-minded approach which is good enough for now.
Also change order of processing stale nodes in fine-grained incremental to be more similar to normal mode.
A class target covers the entire class body and all definitions within it.
Also fix cases where multiple namespaces cause additional steps.
Relative imports are not yet supported.
This is no longer necessary since runtests was recently fixed to not spawn multiple parallel pytest jobs.
mypy/test/testfinegrained.py
Outdated
@@ -71,6 +71,9 @@ def run_case(self, testcase: DataDrivenTestCase) -> None: | |||
a.append('==') | |||
a.extend(new_messages) | |||
|
|||
# Normalize paths in test output (for Windows). | |||
a = [line.replace('\\', '/') for line in a] |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I guess this doesn't really matter as much, but I am always hesitant to use unix forward slash on Windows, I think it is okay here as long as it is internal and the file itself is never written to disk, but to avoid bugs I always favor the platform specific separator. Just a thought.
Currently fine-grained incremental checking can only be run through unit tests -- there's no interactive way to use it. It only supports a small Python subset, and it doesn't support all kinds of modifications.
mypy/server/update.py
is the main entry point and has more documentation.