python / mypy

Optional static typing for Python
https://www.mypy-lang.org/
Other
18.25k stars 2.79k forks source link

nested if/while walrus operator loses typing (nullability) information #14573

Open ds-cbo opened 1 year ago

ds-cbo commented 1 year ago

To Reproduce

# Needed to allow recursive type of Tree.child: Tree
from __future__ import annotations

class Tree:
    child: Tree | None
    def __init__(self, child: Tree | None):
        self.child = child

root: Tree | None = Tree(child=Tree(child=Tree(child=None)))

if child := root:
    print("there is a tree with children:")
    while child := child.child:  # <<< error here
        print(child)

https://mypy-play.net/?mypy=latest&python=3.11&gist=1b0d0e7878dbce6c88e64135eb31bbb6

Actual Behavior

error: Item "None" of "Optional[Tree]" has no attribute "child"  [union-attr]
error: Item "None" of "Union[Tree, Any, None]" has no attribute "child"  [union-attr]

Your Environment

Mypy 0.991 on Python 3.10.9 without configuration file or command-line flags

tmke8 commented 1 year ago

It seems mypy gets confused by the re-use of the child variable. It works if you replace the last two lines with:

while child2 := child.child:
    print(child2)

But it's still strange that this happens.