8000 [WIP] Tighten Lvalues and remove all references to Node by elazarg · Pull Request #2221 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

[WIP] Tighten Lvalues and remove all references to Node #2221

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

Closed
wants to merge 14 commits into from
Closed
54 changes: 30 additions & 24 deletions mypy/binder.py
Original file line number Diff line number Diff line change
@@ -1,22 +1,27 @@
from typing import (Any, Dict, List, Set, Iterator, Union)
from typing import (Dict, List, Set, Iterator, Union)
from contextlib import contextmanager

from mypy.types import Type, AnyType, PartialType
from mypy.nodes import (Node, Expression, Var, RefExpr, SymbolTableNode)
from mypy.nodes import (Expression, Var, RefExpr, SymbolTableNode)

from mypy.subtypes import is_subtype
from mypy.join import join_simple
from mypy.sametypes import is_same_type

from mypy.nodes import IndexExpr, MemberExpr, NameExpr

class Frame(Dict[Any, Type]):
pass

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I don't understand why is it needed. This can be fixed regardless of this PR.

BLval = Union[IndexExpr, MemberExpr, NameExpr]


class Key(AnyType):
pass


class Frame(Dict[Key, Type]):
pass


class ConditionalTypeBinder:
"""Keep track of conditional types of variables.

Expand Down Expand Up @@ -85,7 +90,7 @@ def push_frame(self) -> Frame:
self.options_on_return.append([])
return f

def _push(self, key: Key, type: Type, index: int=-1) -> None:
def _put(self, key: Key, type: Type, index: int=-1) -> None:
self.frames[index][key] = type

def _get(self, key: Key, index: int=-1) -> Type:
Expand All @@ -96,20 +101,22 @@ def _get(self, key: Key, index: int=-1) -> Type:
return self.frames[i][key]
return None

def push(self, node: Node, typ: Type) -> None:
if not node.literal:
def put_if_bindable(self, expr: Expression, typ: Type) -> None:
if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)):
return
key = node.literal_hash
if not expr.literal:
return
key = expr.literal_hash
if key not in self.declarations:
self.declarations[key] = self.get_declaration(node)
self.declarations[key] = self.get_declaration(expr)
self._add_dependencies(key)
self._push(key, typ)
self._put(key, typ)

def get(self, expr: Union[Expression, Var]) -> Type:
def get(self, expr: BLval) -> Type:
return self._get(expr.literal_hash)

def cleanse(self, expr: Expression) -> None:
"""Remove all references to a Node from the binder."""
def cleanse(self, expr: BLval) -> None:
"""Remove all references to an Expression from the binder."""
self._cleanse_key(expr.literal_hash)

def _cleanse_key(self, key: Key) -> None:
Expand Down Expand Up @@ -144,7 +151,7 @@ def update_from_options(self, frames: List[Frame]) -> bool:
for other in resulting_values[1:]:
type = join_simple(self.declarations[key], type, other)
if not is_same_type(type, current_value):
self._push(key, type)
self._put(key, type)
changed = True

return changed
Expand All @@ -165,21 +172,20 @@ def pop_frame(self, fall_through: int = 0) -> Frame:

return result

def get_declaration(self, node: Node) -> Type:
if isinstance(node, (RefExpr, SymbolTableNode)) and isinstance(node.node, Var):
type = node.node.type
def get_declaration(self, expr: BLval) -> Type:
if isinstance(expr, (RefExpr, SymbolTableNode)) and isinstance(expr.node, Var):
type = expr.node.type
Copy link
Contributor Author

Choose a reason for hiding this comment

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

The test here is never true, and I think the original (changed in one of my previous PRs) was never true either. I wonder why.

if isinstance(type, PartialType):
return None
return type
else:
return None

def assign_type(self, expr: Expression,
def assign_type(self, expr: BLval,
type: Type,
declared_type: Type,
restrict_any: bool = False) -> None:
if not expr.literal:
return
assert expr.literal
self.invalidate_dependencies(expr)

if declared_type is None:
Expand All @@ -202,16 +208,16 @@ def assign_type(self, expr: Expression,
and not restrict_any):
pass
elif isinstance(type, AnyType):
self.push(expr, declared_type)
self.put_if_bindable(expr, declared_type)
else:
self.push(expr, type)
self.put_if_bindable(expr, type)

for i in self.try_frames:
# XXX This should probably not copy the entire frame, but
# just copy this variable into a single stored frame.
self.allow_jump(i)

def invalidate_dependencies(self, expr: Expression) -> None:
def invalidate_dependencies(self, expr: BLval) -> None:
"""Invalidate knowledge of types that include expr, but not expr itself.

For example, when expr is foo.bar, invalidate foo.bar.baz.
Expand All @@ -222,7 +228,7 @@ def invalidate_dependencies(self, expr: Expression) -> None:
for dep in self.dependencies.get(expr.literal_hash, set()):
self._cleanse_key(dep)

def most_recent_enclosing_type(self, expr: Expression, type: Type) -> Type:
def most_recent_enclosing_type(self, expr: BLval, type: Type) -> Type:
if isinstance(type, AnyType):
return self.get_declaration(expr)
key = expr.literal_hash
Expand Down
Loading
0