@@ -4358,48 +4358,62 @@ def check_nested_and(maybe: bool) -> None:
43584358[case testInferWalrusAssignmentNestedInConditionNotAlwaysEvaluated]
43594359from typing import List
43604360
4361+ # Each condition puts the walrus on the right of an `and`, which is where the
4362+ # assignment is not carried by the binder and this narrowing applies.
4363+
43614364def check_ternary_branch(maybe: bool) -> None:
43624365 woo = None
4363- if 1 if maybe else (woo := 5):
4366+ if maybe and ( 1 if maybe else (woo := 5) ):
43644367 reveal_type(woo) # N: Revealed type is "builtins.int | None"
43654368 else:
43664369 reveal_type(woo) # N: Revealed type is "builtins.int | None"
43674370
43684371def check_ternary_condition(maybe: bool) -> None:
43694372 woo = None
4370- if 1 if (woo := 5) else 0:
4373+ if maybe and ( 1 if (woo := 5) else 0) :
43714374 reveal_type(woo) # N: Revealed type is "builtins.int"
43724375
4373- def check_comprehension(xs: List[int]) -> None:
4376+ def check_comprehension(maybe: bool, xs: List[int]) -> None:
43744377 woo = None
4375- if [y for y in xs if (woo := y)]:
4378+ if maybe and [y for y in xs if (woo := y)]:
43764379 reveal_type(woo) # N: Revealed type is "builtins.int | None"
43774380
4378- def check_chained_comparison(a: int, b: int) -> None:
4379- # The else branch should stay optional, and does not. Pre-existing: chain
4380- # operands are checked in one binder frame, so the assignment is recorded
4381- # even when short-circuiting means it never ran.
4381+ def check_chained_comparison(maybe: bool, a: int, b: int) -> None:
4382+ # Conservative: entering the branch does imply a < b was true and so the
4383+ # walrus ran, but operands after the second are not walked into.
43824384 woo = None
4383- if a < b < (woo := 5):
4384- reveal_type(woo) # N: Revealed type is "builtins.int"
4385- else:
4386- reveal_type(woo) # N: Revealed type is "builtins.int"
4385+ if maybe and a < b < (woo := 5):
4386+ reveal_type(woo) # N: Revealed type is "builtins.int | None"
43874387[builtins fixtures/len.pyi]
43884388
43894389[case testInferWalrusAssignmentDoesNotWeakenNarrowing]
43904390from typing import Optional, Union
43914391
4392- def check_truthiness(val: Optional[int]) -> None:
4393- if x := val:
4392+ # The walrus goes on the right of an `and` so that the narrowing added for the
4393+ # assignment has to give way to the more precise narrowing from the condition.
4394+
4395+ def check_truthiness(maybe: bool, val: Optional[int]) -> None:
4396+ if maybe and (x := val):
43944397 reveal_type(x) # N: Revealed type is "builtins.int"
43954398
4396- def check_isinstance(val: Union[int, str]) -> None:
4397- if isinstance(x := val, int):
4399+ def check_isinstance(maybe: bool, val: Union[int, str]) -> None:
4400+ if maybe and isinstance(x := val, int):
43984401 reveal_type(x) # N: Revealed type is "builtins.int"
43994402
4400- def check_is_not_none(val: Optional[int]) -> None:
4401- if (x := val) is not None:
4403+ def check_is_not_none(maybe: bool, val: Optional[int]) -> None:
4404+ if maybe and (x := val) is not None:
44024405 reveal_type(x) # N: Revealed type is "builtins.int"
4406+
4407+ def truthy(x: object) -> bool: ...
4408+
4409+ def check_declaration_wider_than_assignment(val: Optional[int], n: int) -> None:
4410+ # An operand that is always evaluated must not be given a map entry: the
4411+ # branches would then join through the declaration of x, which is wider than
4412+ # what the walrus assigned. Reported by mypy_primer against rotki.
4413+ x = val
4414+ if truthy(x := n):
4415+ pass
4416+ reveal_type(x) # N: Revealed type is "builtins.int"
44034417[builtins fixtures/isinstancelist.pyi]
44044418
44054419[case testInferOptionalAgainstAny]
0 commit comments