@@ -4294,48 +4294,62 @@ def check_nested_and(maybe: bool) -> None:
42944294[case testInferWalrusAssignmentNestedInConditionNotAlwaysEvaluated]
42954295from typing import List
42964296
4297+ # Each condition puts the walrus on the right of an `and`, which is where the
4298+ # assignment is not carried by the binder and this narrowing applies.
4299+
42974300def check_ternary_branch(maybe: bool) -> None:
42984301 woo = None
4299- if 1 if maybe else (woo := 5):
4302+ if maybe and ( 1 if maybe else (woo := 5) ):
43004303 reveal_type(woo) # N: Revealed type is "builtins.int | None"
43014304 else:
43024305 reveal_type(woo) # N: Revealed type is "builtins.int | None"
43034306
43044307def check_ternary_condition(maybe: bool) -> None:
43054308 woo = None
4306- if 1 if (woo := 5) else 0:
4309+ if maybe and ( 1 if (woo := 5) else 0) :
43074310 reveal_type(woo) # N: Revealed type is "builtins.int"
43084311
4309- def check_comprehension(xs: List[int]) -> None:
4312+ def check_comprehension(maybe: bool, xs: List[int]) -> None:
43104313 woo = None
4311- if [y for y in xs if (woo := y)]:
4314+ if maybe and [y for y in xs if (woo := y)]:
43124315 reveal_type(woo) # N: Revealed type is "builtins.int | None"
43134316
4314- def check_chained_comparison(a: int, b: int) -> None:
4315- # The else branch should stay optional, and does not. Pre-existing: chain
4316- # operands are checked in one binder frame, so the assignment is recorded
4317- # even when short-circuiting means it never ran.
4317+ def check_chained_comparison(maybe: bool, a: int, b: int) -> None:
4318+ # Conservative: entering the branch does imply a < b was true and so the
4319+ # walrus ran, but operands after the second are not walked into.
43184320 woo = None
4319- if a < b < (woo := 5):
4320- reveal_type(woo) # N: Revealed type is "builtins.int"
4321- else:
4322- reveal_type(woo) # N: Revealed type is "builtins.int"
4321+ if maybe and a < b < (woo := 5):
4322+ reveal_type(woo) # N: Revealed type is "builtins.int | None"
43234323[builtins fixtures/len.pyi]
43244324
43254325[case testInferWalrusAssignmentDoesNotWeakenNarrowing]
43264326from typing import Optional, Union
43274327
4328- def check_truthiness(val: Optional[int]) -> None:
4329- if x := val:
4328+ # The walrus goes on the right of an `and` so that the narrowing added for the
4329+ # assignment has to give way to the more precise narrowing from the condition.
4330+
4331+ def check_truthiness(maybe: bool, val: Optional[int]) -> None:
4332+ if maybe and (x := val):
43304333 reveal_type(x) # N: Revealed type is "builtins.int"
43314334
4332- def check_isinstance(val: Union[int, str]) -> None:
4333- if isinstance(x := val, int):
4335+ def check_isinstance(maybe: bool, val: Union[int, str]) -> None:
4336+ if maybe and isinstance(x := val, int):
43344337 reveal_type(x) # N: Revealed type is "builtins.int"
43354338
4336- def check_is_not_none(val: Optional[int]) -> None:
4337- if (x := val) is not None:
4339+ def check_is_not_none(maybe: bool, val: Optional[int]) -> None:
4340+ if maybe and (x := val) is not None:
43384341 reveal_type(x) # N: Revealed type is "builtins.int"
4342+
4343+ def truthy(x: object) -> bool: ...
4344+
4345+ def check_declaration_wider_than_assignment(val: Optional[int], n: int) -> None:
4346+ # An operand that is always evaluated must not be given a map entry: the
4347+ # branches would then join through the declaration of x, which is wider than
4348+ # what the walrus assigned. Reported by mypy_primer against rotki.
4349+ x = val
4350+ if truthy(x := n):
4351+ pass
4352+ reveal_type(x) # N: Revealed type is "builtins.int"
43394353[builtins fixtures/isinstancelist.pyi]
43404354
43414355[case testInferOptionalAgainstAny]
0 commit comments