For the last case,

x: Any
x = 42

pytype isn't narrowing; it's ignoring the `x: Any` annotation due to a bug. (Inside functions, pytype ignores variable annotations without initial values...) pytype's current, non-buggy behavior is to treat `x: Any = 42` and `x: Any; x = 42` the same. We actually special-cased Any to prevent narrowing, so that users could annotate variables as Any to essentially disable inference in cases in which pytype was doing something questionable.

The first two recommendations seem reasonable to me.

Best,
Rebecca

On Wed, Sep 2, 2020 at 11:27 AM Guido van Rossum <guido@python.org> wrote:
Consider these two similar functions:
```
from typing import Union

def f() -> int:
    x: Union[int, str] = 42
    return x  # Error here

def g() -> int:
    x: Union[int, str]
    x = 42
    return x  # But not here
```
Quite a while ago (2016-2017) there was a long discussion about this in the mypy tracker: https://github.com/python/mypy/issues/2008

Not only is it surprising that these two functions are type-checked differently, there are differences across type checkers. I tried mypy, pytype, pyre and pyright. All of them consider the second function correct. But all except pyright produce a type error on the first function, something along the lines of
```
t.py:5: error: Incompatible return value type (got "Union[int, str]", expected "int")
```
(It's possible that there are configuration settings to change the behavior; I didn't look into this.)

I think it would be in everybody's interest if all type checkers agreed on this. I also think it's surprising to users that the two functions are treated differently. (But as the old mypy issue shows, not everybody agrees they should be treated the same either. :-)

There's another twist (note the return type is str here):
```
from typing import Any

def h() -> str:
    x: Any = 42
    return x
```
This is an error in pyre but not in mypy, pytype or pyright. And for good measure the other variant:
```
def i() -> str:
    x: Any
    x = 42
    return x
```
This is accepted by mypy and pyright, but an error to pyre and pytype.

To summarize, it seems the type of x will be as follows:
```
x: Union[int, str] = 42
# mypy: Union; pytype: Union; pyre: Union; pyright: int
# majority doesn't narrow

x: Union[int, str]
x = 42
# mypy: int; pytype: int; pyre: int; pyright: int
# everybody narrows

x: Any = 42
# mypy: Any; pytype: Any; pyre: int; pyright: Any
# majority doesn't narrow

x: Any
x = 42
# mypy: Any; pytype: int; pyre: int; pyright: Any
# even split
```

Looking at this, I'd say if we follow the majority, we would have to make the following changes:

- pyright should stop narrowing for `x: Union[..] = value`
- pyre should stop narrowing for `x: Any = value`
- mypy and pyright should start narrowing for `x: Any; x = value`

(The latter recommendation is debatable, since it's an even split, but I like it better if Union and Any are treated similarly in this case.)

Let the debate begin.

--
--Guido van Rossum (python.org/~guido)
_______________________________________________
Typing-sig mailing list -- typing-sig@python.org
To unsubscribe send an email to typing-sig-leave@python.org
https://mail.python.org/mailman3/lists/typing-sig.python.org/
Member address: rechen@google.com