Skip to content

Commit

Permalink
Merge branch 'master' into fix-isinstance-tuple
Browse files Browse the repository at this point in the history
  • Loading branch information
pkch committed Mar 28, 2017
2 parents 6e85c32 + 6dc65f6 commit 8e385f0
Show file tree
Hide file tree
Showing 4 changed files with 47 additions and 48 deletions.
58 changes: 35 additions & 23 deletions mypy/binder.py
Original file line number Diff line number Diff line change
Expand Up @@ -8,6 +8,12 @@
from mypy.join import join_simple
from mypy.sametypes import is_same_type

from mypy.nodes import IndexExpr, MemberExpr, NameExpr


BindableTypes = (IndexExpr, MemberExpr, NameExpr)
BindableExpression = Union[IndexExpr, MemberExpr, NameExpr]


class Frame(Dict[Key, Type]):
"""A Frame represents a specific point in the execution of a program.
Expand Down Expand Up @@ -92,7 +98,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 @@ -103,19 +109,23 @@ 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(self, expr: Expression, typ: Type) -> None:
# TODO: replace with isinstance(expr, BindableTypes)
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)
assert isinstance(expr, BindableTypes)
self.declarations[key] = get_declaration(expr)
self._add_dependencies(key)
self._push(key, typ)
self._put(key, typ)

def unreachable(self) -> None:
self.frames[-1].unreachable = True

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

def is_unreachable(self) -> bool:
Expand Down Expand Up @@ -163,7 +173,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

self.frames[-1].unreachable = not frames
Expand All @@ -189,19 +199,13 @@ def pop_frame(self, can_skip: bool, fall_through: int) -> Frame:

return result

def get_declaration(self, expr: Node) -> Type:
if isinstance(expr, RefExpr) and isinstance(expr.node, Var):
type = expr.node.type
if isinstance(type, PartialType):
return None
return type
else:
return None

def assign_type(self, expr: Expression,
type: Type,
declared_type: Type,
restrict_any: bool = False) -> None:
# TODO: replace with isinstance(expr, BindableTypes)
if not isinstance(expr, (IndexExpr, MemberExpr, NameExpr)):
return None
if not expr.literal:
return
self.invalidate_dependencies(expr)
Expand All @@ -226,16 +230,16 @@ def assign_type(self, expr: Expression,
and not restrict_any):
pass
elif isinstance(type, AnyType):
self.push(expr, declared_type)
self.put(expr, declared_type)
else:
self.push(expr, type)
self.put(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: BindableExpression) -> 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 @@ -246,11 +250,11 @@ 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: BindableExpression, type: Type) -> Type:
if isinstance(type, AnyType):
return self.get_declaration(expr)
return get_declaration(expr)
key = expr.literal_hash
enclosers = ([self.get_declaration(expr)] +
enclosers = ([get_declaration(expr)] +
[f[key] for f in self.frames
if key in f and is_subtype(type, f[key])])
return enclosers[-1]
Expand Down Expand Up @@ -334,3 +338,11 @@ def top_frame_context(self) -> Iterator[Frame]:
assert len(self.frames) == 1
yield self.push_frame()
self.pop_frame(True, 0)


def get_declaration(expr: BindableExpression) -> Type:
if isinstance(expr, RefExpr) and isinstance(expr.node, Var):
type = expr.node.type
if not isinstance(type, PartialType):
return type
return None
16 changes: 5 additions & 11 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,8 +48,8 @@
from mypy.visitor import StatementVisitor
from mypy.join import join_types
from mypy.treetransform import TransformVisitor
from mypy.binder import ConditionalTypeBinder, get_declaration
from mypy.meet import is_overlapping_types
from mypy.binder import ConditionalTypeBinder
from mypy.options import Options

from mypy import experiments
Expand Down Expand Up @@ -1221,10 +1221,7 @@ def check_assignment(self, lvalue: Lvalue, rvalue: Expression, infer_lvalue_type
" to a variable of type '{}'".format(lvalue_type), rvalue)
return
if rvalue_type and infer_lvalue_type:
self.binder.assign_type(lvalue,
rvalue_type,
lvalue_type,
False)
self.binder.assign_type(lvalue, rvalue_type, lvalue_type, False)
elif index_lvalue:
self.check_indexed_assignment(index_lvalue, rvalue, lvalue)

Expand Down Expand Up @@ -1927,7 +1924,6 @@ def visit_assert_stmt(self, s: AssertStmt) -> None:

# If this is asserting some isinstance check, bind that type in the following code
true_map, _ = self.find_isinstance_check(s.expr)

self.push_type_map(true_map)

def visit_raise_stmt(self, s: RaiseStmt) -> None:
Expand Down Expand Up @@ -2171,10 +2167,8 @@ def visit_del_stmt(self, s: DelStmt) -> None:
s.expr.accept(self.expr_checker)
for elt in flatten(s.expr):
if isinstance(elt, NameExpr):
self.binder.assign_type(elt,
DeletedType(source=elt.name),
self.binder.get_declaration(elt),
False)
self.binder.assign_type(elt, DeletedType(source=elt.name),
get_declaration(elt), False)

def visit_decorator(self, e: Decorator) -> None:
for d in e.decorators:
Expand Down Expand Up @@ -2463,7 +2457,7 @@ def push_type_map(self, type_map: Optional[Dict[Expression, Type]]) -> None:
self.binder.unreachable()
else:
for expr, type in type_map.items():
self.binder.push(expr, type)
self.binder.put(expr, type)

# Data structure returned by find_isinstance_check representing
# information learned from the truth or falsehood of a condition. The
Expand Down
13 changes: 4 additions & 9 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -160,18 +160,13 @@ def analyze_ref_expr(self, e: RefExpr, lvalue: bool = False) -> Type:
return result

def analyze_var_ref(self, var: Var, context: Context) -> Type:
if not var.type:
if var.type:
return var.type
else:
if not var.is_ready and self.chk.in_checked_function():
self.chk.handle_cannot_determine_type(var.name(), context)
# Implicit 'Any' type.
return AnyType()
else:
# Look up local type of variable with type (inferred or explicit).
val = self.chk.binder.get(var)
if val is None:
return var.type
else:
return val

def visit_call_expr(self, e: CallExpr, allow_none_return: bool = False) -> Type:
"""Type check a call expression."""
Expand Down Expand Up @@ -1954,7 +1949,7 @@ def check_for_comp(self, e: Union[GeneratorExpr, DictionaryComprehension]) -> No

if true_map:
for var, type in true_map.items():
self.chk.binder.push(var, type)
self.chk.binder.put(var, type)

def visit_conditional_expr(self, e: ConditionalExpr) -> Type:
cond_type = self.accept(e.cond)
Expand Down
8 changes: 3 additions & 5 deletions mypy/nodes.py
Original file line number Diff line number Diff line change
Expand Up @@ -116,11 +116,6 @@ class Node(Context):
line = -1
column = -1

# TODO: Move to Expression
# See [Note Literals and literal_hash] below
literal = LITERAL_NO
literal_hash = None # type: Key

def __str__(self) -> str:
ans = self.accept(mypy.strconv.StrConv())
if ans is None:
Expand Down Expand Up @@ -161,6 +156,9 @@ def accept(self, visitor: StatementVisitor[T]) -> T:

class Expression(Node):
"""An expression node."""
literal = LITERAL_NO
literal_hash = None # type: Key

def accept(self, visitor: ExpressionVisitor[T]) -> T:
raise RuntimeError('Not implemented')

Expand Down

0 comments on commit 8e385f0

Please sign in to comment.