-
-
Notifications
You must be signed in to change notification settings - Fork 3k
Description
Consider this code (run with --strict-optional):
from typing import Optional
def f():
# untyped function; often from silent import
return 0 # always returns an int
def g(x: Optional[int]) -> int
if x is None:
x = f()
return x # E: Incompatible return value type (got "Optional[int]", expected "int")
Mypy doesn't infer that x is not None in g. I think this a bug -- mypy
should be permissive here.
If we wanted to fix this, we'd run into a problem: what type should x have
after x = f()? We don't want it to be Any, because we don't want that
behavior in the general case. It shouldn't be int -- f() could be intended
to unconditionally return None instead. To fix this, I think we need to
introduce a new special type, which I will call AnyUnion. AnyUnion[A, B, C] would represent a type which is allowed to be used as any of A, B, or
C (similarly to how Any is allowed to be used as any type). In this case,
we could have x's type bound to AnyUnion[int, None], which would fix this
error.
Other helpful uses of AnyUnion:
powwill no longer need to returnAnyin builtins. Instead, it could
return the much less broadAnyUnion[int, float].AnyUnion[X, None]would provide a per-variable opt-out of strict None
checking. This could be helpful for classes with delayed initialization where
a lot of effort would be needed to refactor them into a state that would work
properly with strict None checking.
Cons:
- Additional complexity of the type system affects implementation complexity and
makes things slightly harder for users to understand. - The motivating problem also exists with subclasses (with the way the binder
currently works), butAnyUniondoesn't help much with that.