Skip to content

We need a better story about Any #3194

Open
@ilevkivskyi

Description

@ilevkivskyi

While working on protocols, I noticed that stubs often use Any where object will be more appropriate and vice versa. Because of how protocol inference works and how current mypy solver works, this leads to problems since sometimes mypy infers Any instead of giving an error (maybe we could improve this by "tightening" solver?)

I think the root of the problem is that wee don't have a good story about Any. I believe the rules for interaction between Any and other things should be like this (where C is a normal class like int or str):

(1) join(Any, object) == object
(2) meet(Any, object) == Any
(3) join(Any, C) == C
(4) meet(Any, C) == C
(5) join(Any, NoReturn) == Any
(6) meet(Any, NoReturn) == NoReturn

I use NoReturn for uninhabited type, since it is how it is currently called in PEP 484. The above rules could be summarized in a simple diagram:

        object
          |
         Any (if it appears in a meet)
        / | \
... all other types ...
        \ | /
         Any (if it appear in a join)
          |
       NoReturn

Currently, mypy behaves in a completely different way, and I believe this is not right, let me explain why. We could focus on rules (3) and (4). Currently, mypy returns Any in both these cases. Here is why it is not safe:

from typing import Any

x = 'a'
y: Any = 1

lst = [x, y]
lst[0] >> 1  # not detected by mypy, fails at runtime, will be fixed by rule (3)

def f(x: int) -> None:
    x >> 1
def g(x: Any) -> None:
    pass

funs = [f, g]
funs[0]('a')  # not detected by mypy, fails at runtime, will be fixed by rule (4)

@JukkaL I will be grateful for your opinion.

Metadata

Metadata

Assignees

No one assigned

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions