Skip to content

New semantic analyzer: Support multiple passes over functions. #6280

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

Merged
merged 23 commits into from
Feb 1, 2019

Conversation

ilevkivskyi
Copy link
Member

This allows supporting forward references within function namespaces. The logic is very simple, go over and over each top-level function/method until everything inside it is resolved, plus one more pass to report errors.

The big diff in _visit_func_def() is because of whitespace, I didn't change any function body analysis logic apart from removing previous two-pass special-casing for functions (GitHub has an option to ignore whitespace in the diff).

@ilevkivskyi ilevkivskyi requested a review from JukkaL January 31, 2019 16:54
Copy link
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a very clean way to deal with forward references! Left a few comments. Also, it's not clear if this will we able to catch references to variables before their definition, similar to the old semantic analyzer. I mean things like x; x = 1 currently generate an error. If this is a regression that is non-trivial to fix, it's okay to fix it later.

@@ -150,6 +150,8 @@ def run_case_once(self, testcase: DataDrivenTestCase,
options.show_traceback = True
if 'optional' in testcase.file:
options.strict_optional = True
if 'newsemanal' in testcase.file:
options.new_semantic_analyzer = True
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This is a good idea!

active_type)
assert not deferred # There can't be cross-function forward refs
assert not incomplete # Ditto
iteration = 0
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be better to move the new logic to a separate function. I think that process_functions is now too big.

@@ -630,6 +602,9 @@ def analyze_overload_sigs_and_impl(
types = []
non_overload_indexes = []
impl = None # type: Optional[OverloadPart]
if defn.impl:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ew the way this works is ugly (the existing logic, not this change in particular). Add TODO item about not modifying the items list.

return int()
def other() -> str:
reveal_type(one()) # E: Revealed type is 'builtins.int'
return str()
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would be good to have a test case where we hit the maximum iteration count (cyclic definition).

@@ -228,6 +211,8 @@ def __init__(self,
errors: Report analysis errors using this instance
"""
self.locals = [None]
# Saved namespaces from previous passes.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A more detailed explanation would be nice here. Also, avoid the use of the term 'pass' since this means a different thing in the old semantic analyzer (maybe 'iteration'?).

def enter(self) -> None:
self.locals.append(SymbolTable())
def enter(self, function: Optional[FuncItem] = None) -> None:
if function:
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Add docstring and describe the argument. Also discuss when it's okay to leave it out.

assert not deferred # There can't be cross-function forward refs
assert not incomplete # Ditto
iteration = 0
# We need one more pass after incomplete is False.
Copy link
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Similar to above, it's probably better to avoid the term 'pass' here. Also consider renaming the more_passes variable.

@ilevkivskyi
Copy link
Member Author

I mean things like x; x = 1 currently generate an error.

Yes, it looks like non-trivial to fix in general, I will open an issue.

Copy link
Collaborator

@JukkaL JukkaL left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good now!

@ilevkivskyi ilevkivskyi merged commit b027308 into python:master Feb 1, 2019
@ilevkivskyi ilevkivskyi deleted the support-nested-stuff branch February 1, 2019 19:36
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

2 participants