Skip to content

Commit 665e091

Browse files
committed
Discard partials remaining after inference failure
1 parent fb16e93 commit 665e091

File tree

2 files changed

+78
-9
lines changed

2 files changed

+78
-9
lines changed

mypy/checker.py

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3294,9 +3294,12 @@ def check_assignment(
32943294
del partial_types[var]
32953295
lvalue_type = var.type
32963296
else:
3297-
# Try to infer a partial type. No need to check the return value, as
3298-
# an error will be reported elsewhere.
3299-
self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type)
3297+
# Try to infer a partial type.
3298+
if not self.infer_partial_type(lvalue_type.var, lvalue, rvalue_type):
3299+
# If that also failed, give up and let the caller know that we
3300+
# cannot read their mind. The definition site will be reported later.
3301+
rvalue_type = fixup_partial_type(lvalue_type)
3302+
self.set_inferred_type(var, lvalue, rvalue_type)
33003303
elif (
33013304
is_literal_none(rvalue)
33023305
and isinstance(lvalue, NameExpr)

test-data/unit/check-inference.test

Lines changed: 72 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -2522,7 +2522,6 @@ class C:
25222522
def __init__(self) -> None:
25232523
self.x = [] # E: Need type annotation for "x" (hint: "x: list[<type>] = ...")
25242524
[builtins fixtures/list.pyi]
2525-
[out]
25262525

25272526
[case testNoCrashOnPartialVariable]
25282527
from typing import Tuple, TypeVar
@@ -2534,7 +2533,6 @@ x = None
25342533
(x,) = f('')
25352534
reveal_type(x) # N: Revealed type is "builtins.str"
25362535
[builtins fixtures/tuple.pyi]
2537-
[out]
25382536

25392537
[case testNoCrashOnPartialVariable2]
25402538
# flags: --no-local-partial-types
@@ -2543,11 +2541,10 @@ T = TypeVar('T', bound=str)
25432541

25442542
def f() -> Tuple[T]:
25452543
...
2546-
x = None
2544+
x = None # E: Need type annotation for "x"
25472545
if int():
25482546
(x,) = f()
25492547
[builtins fixtures/tuple.pyi]
2550-
[out]
25512548

25522549
[case testNoCrashOnPartialVariable3]
25532550
from typing import Tuple, TypeVar
@@ -2559,7 +2556,77 @@ x = None
25592556
(x, x) = f('')
25602557
reveal_type(x) # N: Revealed type is "builtins.str"
25612558
[builtins fixtures/tuple.pyi]
2562-
[out]
2559+
2560+
[case testRejectsPartialWithUninhabited]
2561+
from typing import Generic, TypeVar
2562+
T = TypeVar('T')
2563+
2564+
class Foo(Generic[T]): ...
2565+
2566+
def check() -> None:
2567+
x = None # E: Need type annotation for "x"
2568+
if int():
2569+
x = Foo()
2570+
reveal_type(x) # N: Revealed type is "Union[Any, None]"
2571+
2572+
[case testRejectsPartialWithUninhabited2]
2573+
from typing import Generic, TypeVar
2574+
T = TypeVar('T')
2575+
2576+
class Foo(Generic[T]): ...
2577+
2578+
x = None # E: Need type annotation for "x"
2579+
2580+
def check() -> None:
2581+
global x
2582+
x = Foo()
2583+
reveal_type(x) # N: Revealed type is "Union[Any, None]"
2584+
2585+
[case testRejectsPartialWithUninhabited3]
2586+
# Without force-rejecting Partial<None>, this crashes:
2587+
# https://github.com/python/mypy/issues/16573
2588+
from typing import Generic, TypeVar
2589+
T = TypeVar('T')
2590+
2591+
class Foo(Generic[T]): ...
2592+
2593+
def check() -> None:
2594+
client = None # E: Need type annotation for "client"
2595+
2596+
if client := Foo():
2597+
reveal_type(client) # N: Revealed type is "Any"
2598+
pass
2599+
2600+
reveal_type(client) # N: Revealed type is "Union[Any, None]"
2601+
2602+
client = 0
2603+
reveal_type(client) # N: Revealed type is "builtins.int"
2604+
2605+
[case testRejectsPartialWithUninhabitedIndependently]
2606+
from typing import Generic, TypeVar
2607+
T = TypeVar('T')
2608+
2609+
class Foo(Generic[T]): ...
2610+
2611+
client = None # E: Need type annotation for "client"
2612+
2613+
def bad() -> None:
2614+
global client
2615+
client = Foo()
2616+
reveal_type(client) # N: Revealed type is "Union[Any, None]"
2617+
2618+
def good() -> None:
2619+
global client
2620+
client = 1
2621+
reveal_type(client) # N: Revealed type is "builtins.int"
2622+
2623+
def bad2() -> None:
2624+
global client
2625+
client = Foo()
2626+
# This doesn't look optimal, we should keep saying `Any | None`
2627+
# But once we store `Any | None` globally, it gives enough context
2628+
# to infer Foo[Any] instead of Foo[Never]
2629+
reveal_type(client) # N: Revealed type is "__main__.Foo[Any]"
25632630

25642631
[case testInferenceNestedTuplesFromGenericIterable]
25652632
from typing import Tuple, TypeVar
@@ -2574,7 +2641,6 @@ def main() -> None:
25742641
reveal_type(a) # N: Revealed type is "builtins.int"
25752642
reveal_type(b) # N: Revealed type is "builtins.int"
25762643
[builtins fixtures/tuple.pyi]
2577-
[out]
25782644

25792645
[case testDontMarkUnreachableAfterInferenceUninhabited]
25802646
from typing import TypeVar

0 commit comments

Comments
 (0)