diff --git a/mypy/checker.py b/mypy/checker.py index 2dd7f10e6f354..7e0d9acb6e3e7 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -3294,9 +3294,19 @@ def check_assignment( del partial_types[var] lvalue_type = var.type else: - # Try to infer a partial type. No need to check the return value, as - # an error will be reported elsewhere. - self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type) + # Try to infer a partial type. + if not self.infer_partial_type(var, lvalue, rvalue_type): + # If that also failed, give up and let the caller know that we + # cannot read their mind. The definition site will be reported later. + # Calling .put() directly because the newly inferred type is + # not a subtype of None - we are not looking for narrowing + fallback = self.inference_error_fallback_type(rvalue_type) + self.binder.put(lvalue, fallback) + # Same as self.set_inference_error_fallback_type but inlined + # to avoid computing fallback twice. + # We are replacing partial now, so the variable type + # should remain optional. + self.set_inferred_type(var, lvalue, make_optional_type(fallback)) elif ( is_literal_none(rvalue) and isinstance(lvalue, NameExpr) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 24ea61f2c7156..9ed9c5e9ec787 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -2522,7 +2522,6 @@ class C: def __init__(self) -> None: self.x = [] # E: Need type annotation for "x" (hint: "x: list[] = ...") [builtins fixtures/list.pyi] -[out] [case testNoCrashOnPartialVariable] from typing import Tuple, TypeVar @@ -2534,7 +2533,6 @@ x = None (x,) = f('') reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/tuple.pyi] -[out] [case testNoCrashOnPartialVariable2] # flags: --no-local-partial-types @@ -2543,11 +2541,10 @@ T = TypeVar('T', bound=str) def f() -> Tuple[T]: ... -x = None +x = None # E: Need type annotation for "x" if int(): (x,) = f() [builtins fixtures/tuple.pyi] -[out] [case testNoCrashOnPartialVariable3] from typing import Tuple, TypeVar @@ -2559,7 +2556,76 @@ x = None (x, x) = f('') reveal_type(x) # N: Revealed type is "builtins.str" [builtins fixtures/tuple.pyi] -[out] + +[case testRejectsPartialWithUninhabited] +from typing import Generic, TypeVar +T = TypeVar('T') + +class Foo(Generic[T]): ... + +def check() -> None: + x = None # E: Need type annotation for "x" + if int(): + x = Foo() + reveal_type(x) # N: Revealed type is "__main__.Foo[Any]" + reveal_type(x) # N: Revealed type is "Union[__main__.Foo[Any], None]" + +[case testRejectsPartialWithUninhabited2] +from typing import Generic, TypeVar +T = TypeVar('T') + +class Foo(Generic[T]): ... + +x = None # E: Need type annotation for "x" + +def check() -> None: + global x + x = Foo() + reveal_type(x) # N: Revealed type is "__main__.Foo[Any]" + +reveal_type(x) # N: Revealed type is "Union[__main__.Foo[Any], None]" + +[case testRejectsPartialWithUninhabited3] +# Without force-rejecting Partial, this crashes: +# https://github.com/python/mypy/issues/16573 +from typing import Generic, TypeVar +T = TypeVar('T') + +class Foo(Generic[T]): ... + +def check() -> None: + client = None # E: Need type annotation for "client" + + if client := Foo(): + reveal_type(client) # N: Revealed type is "__main__.Foo[Any]" + + reveal_type(client) # N: Revealed type is "Union[__main__.Foo[Any], None]" + + client = 0 # E: Incompatible types in assignment (expression has type "int", variable has type "Optional[Foo[Any]]") + reveal_type(client) # N: Revealed type is "Union[__main__.Foo[Any], None]" + +[case testRejectsPartialWithUninhabitedIndependently] +from typing import Generic, TypeVar +T = TypeVar('T') + +class Foo(Generic[T]): ... + +client = None # E: Need type annotation for "client" + +def bad() -> None: + global client + client = Foo() + reveal_type(client) # N: Revealed type is "__main__.Foo[Any]" + +def good() -> None: + global client + client = 1 # E: Incompatible types in assignment (expression has type "int", variable has type "Optional[Foo[Any]]") + reveal_type(client) # N: Revealed type is "Union[__main__.Foo[Any], None]" + +def bad2() -> None: + global client + client = Foo() + reveal_type(client) # N: Revealed type is "__main__.Foo[Any]" [case testInferenceNestedTuplesFromGenericIterable] from typing import Tuple, TypeVar @@ -2574,7 +2640,6 @@ def main() -> None: reveal_type(a) # N: Revealed type is "builtins.int" reveal_type(b) # N: Revealed type is "builtins.int" [builtins fixtures/tuple.pyi] -[out] [case testDontMarkUnreachableAfterInferenceUninhabited] from typing import TypeVar