-
-
Notifications
You must be signed in to change notification settings - Fork 2.8k
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
Check deferred nodes after all first passes in an import cycle #2264
Conversation
[file b.py] | ||
import a | ||
def g() -> int: | ||
return a.y |
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.
Reveal the type of a.y
(to verify that it doesn't somehow fall back to Any
).
[file a.py] | ||
import b | ||
def f() -> int: | ||
return b.x |
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.
Reveal the type of b.x
.
in options.strict_optional_whitelist) | ||
|
||
def check_first_pass(self) -> None: | ||
"""Type check the entire file, but defer functions with forward references.""" |
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.
Be more explicit about forward reference mean. In particular, they mean references to definitions whose types haven't been inferred yet.
Looks good to me! This hopefully fixes one of the biggest pain points mypy users with large code bases have had. I'd like to see some more test cases before merging:
|
I'll add more tests. I also discovered that reveal_type() needs to check for current_node_deferred. |
e5b8733
to
1471cb4
Compare
Rebased, generalized the multi-pass machinery, and added a test that would require 3 passes. Still needs tests for (2) and (3). Also, there are still some print() calls left. |
I could use a hint for (2). |
I think I have all the required tests now. Jukka, can you double-check? |
Current coverage is 84.90% (diff: 100%)@@ master #2264 diff @@
==========================================
Files 72 72
Lines 19037 20953 +1916
Methods 0 0
Messages 0 0
Branches 3919 4824 +905
==========================================
+ Hits 15819 17790 +1971
+ Misses 2618 2588 -30
+ Partials 600 575 -25
|
return False | ||
self.errors.set_file(self.path) | ||
self.pass_num += 1 | ||
print('---', self.path, 'pass', self.pass_num + 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.
Remove print.
for node, type_name in todo: | ||
if node in done: | ||
continue | ||
print(type_name, '.', node.fullname() or node.name()) |
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.
Remove another print.
tmp/a.py:4: error: Cannot determine type of 'x2' | ||
|
||
[case testErrorInPassTwo] | ||
# flags: --hide-error-context |
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.
Don't hide error context to test the it works correctly for errors reported in the second pass.
import a | ||
x = 1 + 1 | ||
[out] | ||
tmp/a.py:4: error: Unsupported operand types for + ("int" and "str") |
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.
Maybe also test this the other way as well (error reported in b.py
in addition a.py
).
[file b.py] | ||
from typing import Any | ||
import a | ||
def deco(f: Any) -> Any: |
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.
This decorator probably doesn't trigger a second pass, since simple decorator signatures are special cased in semantic analysis. A more complex decorator signature such as Callable[[T], int]
-> Callable[[T]], str]
is needed.
[file a.py] | ||
import b | ||
def g() -> None: | ||
f() |
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.
Make sure that the decorator function returns an interesting type (not Any
) and do reveal_type(f())
here to verify that decorator got applied correctly.
These verify that deferral due to a cross-module dependency works.
f1b8872
to
3357393
Compare
3357393
to
d1778da
Compare
Ready for review/merge. |
LGTM now -- thanks for the updates! |
OK, rebased and made all requested amendments.
|
Might fix #481.