Skip to content

Commit 5891413

Browse files
committed
Move the join-based narrowing logic towards a union-based narrowing logic.
More concretely: use `make_simplified_union` instead of `join_simple` in `ConditionalTypeBinder.update_from_options`
1 parent 1711de8 commit 5891413

File tree

3 files changed

+38
-2
lines changed

3 files changed

+38
-2
lines changed

mypy/binder.py

Lines changed: 16 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@
1010
from mypy.literals import Key, literal, literal_hash, subkeys
1111
from mypy.nodes import Expression, IndexExpr, MemberExpr, NameExpr, RefExpr, TypeInfo, Var
1212
from mypy.subtypes import is_same_type, is_subtype
13+
from mypy.typeops import make_simplified_union
1314
from mypy.types import (
1415
AnyType,
1516
Instance,
@@ -237,8 +238,22 @@ def update_from_options(self, frames: list[Frame]) -> bool:
237238
type = AnyType(TypeOfAny.from_another_any, source_any=declaration_type)
238239
else:
239240
for other in resulting_values[1:]:
241+
240242
assert other is not None
241-
type = join_simple(self.declarations[key], type, other.type)
243+
244+
if (
245+
isinstance(t1 := get_proper_type(type), TupleType)
246+
and isinstance(t2 := get_proper_type(other.type), TupleType)
247+
and (len(l1 := t1.items) == len(l2 := t2.items))
248+
and (find_unpack_in_list(l1) is None)
249+
and (find_unpack_in_list(l2) is None)
250+
):
251+
type = t1.copy_modified(
252+
items=[make_simplified_union([i1, i2]) for i1, i2 in zip(l1, l2)]
253+
)
254+
else:
255+
type = make_simplified_union([type, other.type])
256+
242257
# Try simplifying resulting type for unions involving variadic tuples.
243258
# Technically, everything is still valid without this step, but if we do
244259
# not do this, this may create long unions after exiting an if check like:

test-data/unit/check-narrowing.test

Lines changed: 21 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2352,3 +2352,24 @@ def fn_while(arg: T) -> None:
23522352
return None
23532353
return None
23542354
[builtins fixtures/primitives.pyi]
2355+
2356+
2357+
[case testNarrowingIsinstanceCreatesUnion]
2358+
2359+
class A: ...
2360+
class B(A): y: int
2361+
class C(A): y: int
2362+
class D(C): ...
2363+
class E(C): ...
2364+
class F(C): ...
2365+
2366+
def f(x: A):
2367+
if isinstance(x, B): ...
2368+
elif isinstance(x, D): ...
2369+
elif isinstance(x, E): ...
2370+
elif isinstance(x, F): ...
2371+
else: return
2372+
reveal_type(x) # N: Revealed type is "Union[__main__.B, __main__.D, __main__.E, __main__.F]"
2373+
reveal_type(x.y) # N: Revealed type is "builtins.int"
2374+
2375+
[builtins fixtures/isinstance.pyi]

test-data/unit/check-redefine.test

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -321,7 +321,7 @@ def f() -> None:
321321
x = 1
322322
if int():
323323
x = ''
324-
reveal_type(x) # N: Revealed type is "builtins.object"
324+
reveal_type(x) # N: Revealed type is "Union[builtins.str, builtins.int]"
325325
x = ''
326326
reveal_type(x) # N: Revealed type is "builtins.str"
327327
if int():

0 commit comments

Comments
 (0)