Skip to content

Commit 5679a89

Browse files
committed
Fix 1.20 regression: use explicit walrus check instead of binder version guard
The binder version guard introduced in PR #20622 was too broad: it disabled union fallback for any expression that modifies the binder, including generator expressions with ternary operators. This caused type narrowing via reassignment to fail for non-walrus expressions. Replace the binder_version == self.binder.version check with an explicit check for AssignmentExpr (walrus :=) in the expression tree, which is the actual problematic case. This restores type narrowing for generator expressions and other non-walrus constructs while preserving the walrus safety guard.
1 parent 93bc02b commit 5679a89

1 file changed

Lines changed: 20 additions & 2 deletions

File tree

mypy/checker.py

Lines changed: 20 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -379,6 +379,17 @@ def __exit__(self, exc_type: object, exc_val: object, exc_tb: object) -> Literal
379379
return False
380380

381381

382+
class _AssignmentExprSeeker(TraverserVisitor):
383+
"""Check if an expression tree contains a walrus operator (:=)."""
384+
385+
def __init__(self) -> None:
386+
super().__init__()
387+
self.found = False
388+
389+
def visit_assignment_expr(self, o: AssignmentExpr) -> None:
390+
self.found = True
391+
392+
382393
class TypeChecker(NodeVisitor[None], TypeCheckerSharedApi, SplittingVisitor):
383394
"""Mypy type checker.
384395
@@ -4757,7 +4768,7 @@ def infer_rvalue_with_fallback_context(
47574768
# context that is ultimately used. This is however tricky with redefinitions.
47584769
# For now we simply disable second accept in cases known to cause problems,
47594770
# see e.g. testAssignToOptionalTupleWalrus.
4760-
binder_version = self.binder.version
4771+
has_walrus = self._has_assignment_expr(rvalue)
47614772

47624773
fallback_context_used = False
47634774
with (
@@ -4787,7 +4798,7 @@ def infer_rvalue_with_fallback_context(
47874798
union_fallback = (
47884799
preferred_context is not None
47894800
and isinstance(get_proper_type(lvalue_type), UnionType)
4790-
and binder_version == self.binder.version
4801+
and not has_walrus
47914802
)
47924803

47934804
# Skip literal types, as they have special logic (for better errors).
@@ -5091,6 +5102,13 @@ def visit_return_stmt(self, s: ReturnStmt) -> None:
50915102
self.check_return_stmt(s)
50925103
self.binder.unreachable()
50935104

5105+
@staticmethod
5106+
def _has_assignment_expr(expr: Expression) -> bool:
5107+
"""Check if an expression tree contains a walrus operator (:=)."""
5108+
seeker = _AssignmentExprSeeker()
5109+
expr.accept(seeker)
5110+
return seeker.found
5111+
50945112
def infer_context_dependent(
50955113
self, expr: Expression, type_ctx: Type, allow_none_func_call: bool
50965114
) -> ProperType:

0 commit comments

Comments
 (0)