Skip to content

New semantic analyzer: Prohibit duplicate type variable definitions and fix stale upper bounds and values #6563

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 11 commits into from
Jun 26, 2019

Conversation

ilevkivskyi
Copy link
Member

@ilevkivskyi ilevkivskyi commented Mar 18, 2019

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.

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

Thanks! I have one question about incrementally updating a type variable definition and a few nits.

if existing and not isinstance(existing.node, (TypeVarExpr, PlaceholderNode)):
if existing and not (isinstance(existing.node, PlaceholderNode) or
# Also give error for another type variable with the same name.
isinstance(existing.node, TypeVarExpr) and
Copy link
Collaborator

Choose a reason for hiding this comment

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

Style nit: Use parentheses to make precedence explicit when mixing and/or.

# T = TypeVar('T', bound=C[Any])
# class C(Generic[T]):
# ...
# We can use allow_placeholder=True for upper bound and values to avoid this,
Copy link
Collaborator

Choose a reason for hiding this comment

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

This doesn't make it clear whether we are actually doing this. Instead, write something like "We could use ..., but we don't do this, because ...".

What happens if the type variable definition and the class definition are in different parts of an import cycle? Do we ensure that once the type variable has been completed, the new bound will be used in the class definition?

@ilevkivskyi ilevkivskyi changed the title New semantic analyzer: Prohibit duplicate type variable definitions New semantic analyzer: Prohibit duplicate type variable definitions and fix stale upper bounds and values Jun 25, 2019
@@ -282,7 +282,7 @@ def visit_deleted_type(self, t: DeletedType) -> T:
return self.strategy([])

def visit_type_var(self, t: TypeVarType) -> T:
return self.strategy([])
return self.query_types([t.upper_bound] + t.values)
Copy link
Member Author

@ilevkivskyi ilevkivskyi Jun 25, 2019

Choose a reason for hiding this comment

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

This is strictly speaking unrelated, but it made one new test fail (because has_placeholder() was wrong).

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 looks like a good way to deal with the problem. I was worried that we need to do something drastic to address the issue, and I'm glad that this is a pretty straightforward change.

Left a few minor comments, otherwise looks good.

assert isinstance(call.analyzed, TypeVarExpr)
call.analyzed.upper_bound = upper_bound
call.analyzed.values = values
self.progress = True
Copy link
Collaborator

Choose a reason for hiding this comment

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

Is this always progress, or should we check for changes in the bounds?

# self.defer().
analyzed = AnyType(TypeOfAny.special_form)
# Type variables are special: we need to place them in the symbol table
# soon, even if upper bound is not ready yet.
Copy link
Collaborator

Choose a reason for hiding this comment

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

Can you explain why they need to be added to the symbol table soon?

allow_placeholder=True)
if analyzed is None:
# Type variables are special: we need to place them in the symbol table
# soon, even if some value is not ready yet.
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: can you explain why?

@JukkaL
Copy link
Collaborator

JukkaL commented Jun 26, 2019

Oh and feel free to merge when you've addressed my comments.

@ilevkivskyi
Copy link
Member Author

Travis hook seems to be stuck, all tests have passed, so I am merging this now.

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.

New semantic analyzer: regression with circular import and TypeVar
2 participants