Browse files

Fix merge and sync with python#4072

  • Loading branch information...
ilevkivskyi committed Oct 13, 2017
1 parent 46e8c2d commit a877957d2aee8a2f2fe99cab7c2cd5f10e7d5a25
Showing with 30 additions and 17 deletions.
  1. +17 −12 mypy/
  2. +13 −5 mypy/
@@ -53,7 +53,7 @@
from mypy.erasetype import erase_typevars
from mypy.expandtype import expand_type, expand_type_by_instance
from mypy.visitor import NodeVisitor
from mypy.join import join_types, join_type_list
from mypy.join import join_types
from mypy.treetransform import TransformVisitor
from mypy.binder import ConditionalTypeBinder, get_declaration
from import is_overlapping_types
@@ -2957,12 +2957,12 @@ def builtin_item_type(tp: Type) -> Optional[Type]:
if tp.type.fullname() in ['builtins.list', 'builtins.tuple', 'builtins.dict',
'builtins.set', 'builtins.frozenset']:
if not tp.args:
# TODO: make lib-stub/builtins.pyi define generic tuple.
# TODO: fix tuple in lib-stub/builtins.pyi (it should be generic).
return None
if not isinstance(tp.args[0], AnyType):
return tp.args[0]
elif isinstance(tp, TupleType) and all(not isinstance(it, AnyType) for it in tp.items):
return join_type_list(tp.items)
return UnionType.make_simplified_union(tp.items) # this type is not externally visible
elif isinstance(tp, TypedDictType):
# TypedDict always has non-optional string keys.
if tp.fallback.type.fullname() == 'typing.Mapping':
@@ -3084,15 +3084,6 @@ def find_isinstance_check(node: Expression,
if literal(expr) == LITERAL_TYPE:
vartype = type_map[expr]
return conditional_callable_type_map(expr, vartype)
elif isinstance(node, ComparisonExpr) and node.operators in [['in'], ['not in']]:
expr = node.operands[0]
cont_type = type_map[node.operands[1]]
item_type = builtin_item_type(cont_type)
if item_type and literal(expr) == LITERAL_TYPE and not is_literal_none(expr):
if node.operators == ['in']:
return {expr: item_type}, {}
if node.operators == ['not in']:
return {}, {expr: item_type}
elif isinstance(node, ComparisonExpr) and experiments.STRICT_OPTIONAL:
# Check for `x is None` and `x is not None`.
is_not = node.operators == ['is not']
@@ -3127,6 +3118,20 @@ def find_isinstance_check(node: Expression,
optional_expr = node.operands[1]
if is_overlapping_types(optional_type, comp_type):
return {optional_expr: remove_optional(optional_type)}, {}
elif node.operators in [['in'], ['not in']]:
expr = node.operands[0]
left_type = type_map[expr]
right_type = builtin_item_type(type_map[node.operands[1]])
right_ok = right_type and (not is_optional(right_type) and
(not isinstance(right_type, Instance) or
right_type.type.fullname() != 'builtins.object'))
if (right_type and right_ok and is_optional(left_type) and
literal(expr) == LITERAL_TYPE and not is_literal_none(expr) and
is_overlapping_types(left_type, right_type)):
if node.operators == ['in']:
return {expr: remove_optional(left_type)}, {}
if node.operators == ['not in']:
return {}, {expr: remove_optional(left_type)}
elif isinstance(node, RefExpr):
# Restrict the type of the variable to True-ish/False-ish in the if and else branches
# respectively
@@ -152,7 +152,7 @@ def visit_decorator(self, dec: Decorator) -> None:
for expr in dec.decorators:
preserve_type = False
if isinstance(expr, RefExpr) and isinstance(expr.node, FuncDef):
if is_identity_signature(expr.node.type):
if expr.node.type and is_identity_signature(expr.node.type):
preserve_type = True
if not preserve_type:
decorator_preserves_type = False
@@ -246,31 +246,38 @@ def perform_transform(self, node: Union[Node, SymbolTableNode],
transform: Callable[[Type], Type]) -> None:
"""Apply transform to all types associated with node."""
if isinstance(node, ForStmt):
node.index_type = transform(node.index_type)
if node.index_type:
node.index_type = transform(node.index_type)
self.transform_types_in_lvalue(node.index, transform)
if isinstance(node, WithStmt):
node.target_type = transform(node.target_type)
if node.target_type:
node.target_type = transform(node.target_type)
for n in
if isinstance(n, NameExpr) and isinstance(n.node, Var) and n.node.type:
n.node.type = transform(n.node.type)
if isinstance(node, (FuncDef, CastExpr, AssignmentStmt, TypeAliasExpr, Var)):
assert node.type, "Scheduled patch for non-existent type"
node.type = transform(node.type)
if isinstance(node, NewTypeExpr):
assert node.old_type, "Scheduled patch for non-existent type"
node.old_type = transform(node.old_type)
if isinstance(node, TypeVarExpr):
if node.upper_bound:
node.upper_bound = transform(node.upper_bound)
if node.values:
node.values = [transform(v) for v in node.values]
if isinstance(node, TypedDictExpr):
assert, "Scheduled patch for non-existent type" = cast(TypedDictType,
if isinstance(node, NamedTupleExpr):
assert, "Scheduled patch for non-existent type" = cast(TupleType,
if isinstance(node, TypeApplication):
node.types = [transform(t) for t in node.types]
if isinstance(node, SymbolTableNode):
assert node.type_override, "Scheduled patch for non-existent type"
node.type_override = transform(node.type_override)
if isinstance(node, TypeInfo):
for tvar in node.defn.type_vars:
@@ -296,7 +303,8 @@ def transform_types_in_lvalue(self, lvalue: Lvalue,
if isinstance(lvalue, RefExpr):
if isinstance(lvalue.node, Var):
var = lvalue.node
var.type = transform(var.type)
if var.type:
var.type = transform(var.type)
elif isinstance(lvalue, TupleExpr):
for item in lvalue.items:
self.transform_types_in_lvalue(item, transform)
@@ -355,7 +363,7 @@ def fail(self, msg: str, ctx: Context, *, blocker: bool = False) -> None:
def fail_blocker(self, msg: str, ctx: Context) -> None:, ctx, blocker=True)
def builtin_type(self, name: str, args: List[Type] = None) -> Instance:
def builtin_type(self, name: str, args: Optional[List[Type]] = None) -> Instance:
names = self.modules['builtins']
sym = names.names[name]
node = sym.node

0 comments on commit a877957

Please sign in to comment.