Skip to content

New semantic analyzer: Make assignment analysis logic more straightforward #6527

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 27 commits into from
Mar 15, 2019

Conversation

ilevkivskyi
Copy link
Member

Fixes #6412
Fixes #6453

In this PR:

  • Wait until we can classify r.h.s. of an assignment as normal, type alias, named tuple etc.
  • Choose the corresponding branch instead of performing all of them (as it used to be before)
  • Never create (or rely on creation of) temporary Vars
  • Add every symbol to symbol table only once (as it is done for classes)
  • Don't "patch" existing symbols (with one exception for type variables, see below)
  • Add and update docstrings and comments

Notes:

  • I allow placeholders for type alias targets and NewTypes targets, they essentially behave as base classes. In general I make logic for type aliases and NewTypes much more similar to logic of class definitions (especially NewTypes), this allows to support a whole bunch of tricky forward references
  • I don't store types with placeholders in annotations, and instead if an alias target got updated (e.g. placeholders are resolved), I set progress=True

Follow-ups:

  • There is still a small hack to keep compatibility with old analyzer in type checker, but now it is basically "don't use binder for l.h.s. of special forms"
  • Type variable declarations still have a bug that duplicate type variable definition is not reported as error, second one silently wins, this will be fixed in a separate PR
  • This PR doesn't aim to fix aspects of assignment analysis related to New semantic analyzer: Clean-up logic for classes in functions #6422, that will be also a separate PR

Test updates:

  • Add and enable more tests for type aliases and NewTypes
  • Add test for cyclic definition error messages
  • Change order of error messages on the same line in few tests
  • Enable one test file where previously only some tests were opted in (I think it was not enabled by mistake in one of the previous PRs, I enable it here since order of errors in one test in that file is affected by this PR.)

@ilevkivskyi ilevkivskyi requested a review from JukkaL March 8, 2019 23:18
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.

Here's a partial code review (mostly various nits). I still haven't looked at everything.

@ilevkivskyi
Copy link
Member Author

@JukkaL Thanks for review! I implemented the suggestions.

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 the final part of my review. Looks good -- things are much easier to reason about now. Left a bunch of minor comments. Feel free to ignore some if you are short on time (and maybe create follow-up issues if it seems worth it).

@@ -337,7 +339,7 @@ class C(B): pass # E: Cannot subclass NewType
from typing import Protocol, NewType

class P(Protocol):
attr: int
attr: int = 0
Copy link
Collaborator

Choose a reason for hiding this comment

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

What's this change?

Copy link
Member Author

Choose a reason for hiding this comment

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

As I explained offline, there was previously a false negative in this test (the NewType is abstract otherwise).

@@ -339,14 +339,25 @@ def main() -> None:
x # E: Name 'x' is not defined

[case testNewAnalyzerCyclicDefinitions]
gx = gy # E: Cannot determine type of 'gy'
gx = gy # E: Cannot resolve name "gy", possible cyclic definition
Copy link
Collaborator

Choose a reason for hiding this comment

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

Grammar nit: run-on sentence in error message. Suggestion:

Cannot resolve name "gy" (possible cyclic definition)

[file b.py]
import a
x = a.x # E: Cannot resolve attribute "x", possible cyclic definition \
# E: Module has no attribute "x"
Copy link
Collaborator

Choose a reason for hiding this comment

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

Would it be easy to get rid of the second error, as it seems redundant and a bit confusing.

Copy link
Member Author

Choose a reason for hiding this comment

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

Opened #6551 for this.

return False

def is_type_ref(self, rv: Expression, bare: bool = False) -> bool:
"""Does this expression refer to a type?
Copy link
Collaborator

Choose a reason for hiding this comment

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

The docstring doesn't make it clear whether C[int] would be considered a type reference. It would be good to be explicit about this. Also, probably worth mentioning that this assumes a type alias context. It's important since some of the error messages generated below only make sense when defining a type alias.

return
if self.analyze_typeddict_assign(s):

# The r.h.s. is now ready to be classified, first check if it is a special form:
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 much cleaner than what we had previously! Thanks for cleaning this up.

@@ -3379,7 +3515,12 @@ def visit_member_expr(self, expr: MemberExpr) -> None:
n = self.rebind_symbol_table_node(n)
if n:
if isinstance(n.node, PlaceholderNode):
self.defer()
if self.final_iteration:
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 duplicated above. Maybe move this if statement to a helper method?

@ilevkivskyi
Copy link
Member Author

@JukkaL Thanks! I implemented all comments except one (for that I opened a follow-up issue).

@ilevkivskyi ilevkivskyi merged commit 5d52eac into python:master Mar 15, 2019
@ilevkivskyi ilevkivskyi deleted the polish-aliases-new branch March 15, 2019 21:56
ilevkivskyi added a commit that referenced this pull request Jun 26, 2019
…nd fix stale upper bounds and values (#6563)

This is a follow up for #6527.

Fixes #7037
I think this also essentially concludes #6300

This PR prohibits duplicate type variable definitions, previously the second one was silently winning. Also now the first one wins. Note that it didn't require additional attribute on `TypeVarExpr` as I initially though, it looks like we can simple use `s.rvalue.analyzed` for the purpose of linking assignments to variables.

This PR also naturally fixes an issue where stale upper bound or value appears in a class that uses the type variable.
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
2 participants