Skip to content

Commit dc62a99

Browse files
committed
Fix #2978.
1 parent c53e0ca commit dc62a99

File tree

4 files changed

+36
-8
lines changed

4 files changed

+36
-8
lines changed

mypy/checkexpr.py

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2213,7 +2213,8 @@ def narrow_type_from_binder(self, expr: Expression, known_type: Type) -> Type:
22132213
if expr.literal >= LITERAL_TYPE:
22142214
restriction = self.chk.binder.get(expr)
22152215
if restriction:
2216-
return narrow_declared_type(known_type, restriction)
2216+
ans = narrow_declared_type(known_type, restriction)
2217+
return ans
22172218
return known_type
22182219

22192220

mypy/join.py

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
UninhabitedType, TypeType, true_or_false
1111
)
1212
from mypy.maptype import map_instance_to_supertype
13-
from mypy.subtypes import is_subtype, is_equivalent, is_subtype_ignoring_tvars
13+
from mypy.subtypes import is_subtype, is_equivalent, is_subtype_ignoring_tvars, is_proper_subtype
1414

1515
from mypy import experiments
1616

@@ -29,10 +29,10 @@ def join_simple(declaration: Type, s: Type, t: Type) -> Type:
2929
if isinstance(s, ErasedType):
3030
return t
3131

32-
if is_subtype(s, t):
32+
if is_proper_subtype(s, t):
3333
return t
3434

35-
if is_subtype(t, s):
35+
if is_proper_subtype(t, s):
3636
return s
3737

3838
if isinstance(declaration, UnionType):

mypy/subtypes.py

Lines changed: 17 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -7,6 +7,7 @@
77
)
88
import mypy.applytype
99
import mypy.constraints
10+
from mypy.erasetype import erase_type
1011
# Circular import; done in the function instead.
1112
# import mypy.solve
1213
from mypy import messages, sametypes
@@ -496,13 +497,22 @@ def unify_generic_callable(type: CallableType, target: CallableType,
496497

497498

498499
def restrict_subtype_away(t: Type, s: Type) -> Type:
499-
"""Return a supertype of (t intersect not s)
500+
"""Return t minus s.
500501
501-
Currently just remove elements of a union type.
502+
If we can't determine a precise result, return a supertype of the
503+
ideal result (just t is a valid result).
504+
505+
This is used for type inference of runtime type checks such as
506+
isinstance.
507+
508+
Currently this just removes elements of a union type.
502509
"""
503510
if isinstance(t, UnionType):
504-
new_items = [item for item in t.items if (not is_subtype(item, s)
505-
or isinstance(item, AnyType))]
511+
# Since runtime type checks will ignore type arguments, erase the types.
512+
erased_s = erase_type(s)
513+
new_items = [item for item in t.items
514+
if (not is_proper_subtype(erase_type(item), erased_s)
515+
or isinstance(item, AnyType))]
506516
return UnionType.make_union(new_items)
507517
else:
508518
return t
@@ -624,6 +634,9 @@ def visit_tuple_type(self, left: TupleType) -> bool:
624634
if not right.args:
625635
return False
626636
iter_type = right.args[0]
637+
if is_named_instance(right, 'builtins.tuple') and isinstance(iter_type, AnyType):
638+
# Special case plain 'tuple' which is needed for isinstance(x, tuple).
639+
return True
627640
return all(is_proper_subtype(li, iter_type) for li in left.items)
628641
return is_proper_subtype(left.fallback, right)
629642
elif isinstance(right, TupleType):

test-data/unit/check-optional.test

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -575,3 +575,17 @@ reveal_type(u(a, None)) # E: Revealed type is 'Union[builtins.None, Any]'
575575
reveal_type(u(None, a)) # E: Revealed type is 'Union[Any, builtins.None]'
576576
reveal_type(u(1, None)) # E: Revealed type is 'Union[builtins.None, builtins.int*]'
577577
reveal_type(u(None, 1)) # E: Revealed type is 'Union[builtins.int*, builtins.None]'
578+
579+
[case testIsinstanceAndOptionalAndAnyBase]
580+
from typing import Any, Optional
581+
582+
class A(Any): pass
583+
584+
def f(a: Optional[A]):
585+
reveal_type(a) # E: Revealed type is 'Union[__main__.A, builtins.None]'
586+
if a is not None:
587+
reveal_type(a) # E: Revealed type is '__main__.A'
588+
else:
589+
reveal_type(a) # E: Revealed type is 'builtins.None'
590+
reveal_type(a) # E: Revealed type is 'Union[__main__.A, builtins.None]'
591+
[builtins fixtures/isinstance.pyi]

0 commit comments

Comments
 (0)