Skip to content

Commit ab99c46

Browse files
committed
Fix type narrowing for variable swaps after isinstance checks
1 parent 0cd1541 commit ab99c46

3 files changed

Lines changed: 50 additions & 0 deletions

File tree

mypy/checker.py

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4175,7 +4175,21 @@ def check_assignment_to_multiple_lvalues(
41754175
lr_pairs.append((star_lv.expr, rv_list))
41764176
lr_pairs.extend(zip(right_lvs, right_rvs))
41774177

4178+
captured_pairs: list[tuple[Lvalue, Expression]] = []
4179+
41784180
for lv, rv in lr_pairs:
4181+
if isinstance(rv, NameExpr):
4182+
narrowed = self.binder.get(rv)
4183+
4184+
if narrowed is not None:
4185+
captured_pairs.append(
4186+
(lv, self.temp_node(narrowed, context=rv))
4187+
)
4188+
continue
4189+
4190+
captured_pairs.append((lv, rv))
4191+
4192+
for lv, rv in captured_pairs:
41794193
self.check_assignment(lv, rv, infer_lvalue_type)
41804194
else:
41814195
self.check_multi_assignment(lvalues, rvalue, context, infer_lvalue_type)

test-data/unit/check-isinstance.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3377,3 +3377,21 @@ def f2(x: A | None, t: type[A]):
33773377
else:
33783378
reveal_type(x) # N: Revealed type is "None"
33793379
[builtins fixtures/isinstancelist.pyi]
3380+
3381+
[case testTupleSwapAfterIsinstance]
3382+
class Base: pass
3383+
class Sub1(Base): pass
3384+
class Sub2(Base): pass
3385+
3386+
def f(a: Base, b: Base) -> None:
3387+
if isinstance(b, Sub1) and isinstance(a, Sub2):
3388+
t = (b, a)
3389+
3390+
reveal_type(t) # N: Revealed type is "tuple[__main__.Sub1, __main__.Sub2]"
3391+
3392+
a, b = t
3393+
3394+
reveal_type(a) # N: Revealed type is "__main__.Sub1"
3395+
reveal_type(b) # N: Revealed type is "__main__.Sub2"
3396+
3397+
[builtins fixtures/isinstancelist.pyi]

test-data/unit/check-narrowing.test

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4281,3 +4281,21 @@ def func(y: H) -> H:
42814281
else:
42824282
return y
42834283
[builtins fixtures/primitives.pyi]
4284+
4285+
[case testIsInstanceVariableSwapNarrowing]
4286+
class Base:
4287+
pass
4288+
4289+
class Sub1(Base):
4290+
pass
4291+
4292+
class Sub2(Base):
4293+
pass
4294+
4295+
def f(a: Base, b: Base) -> None:
4296+
if isinstance(b, Sub1) and isinstance(a, Sub2):
4297+
a, b = b, a
4298+
reveal_type(a) # N: Revealed type is "__main__.Sub1"
4299+
reveal_type(b) # N: Revealed type is "__main__.Sub2"
4300+
4301+
[builtins fixtures/isinstancelist.pyi]

0 commit comments

Comments
 (0)