Repository: python/mypy

Issue:
Regression: type inference can fall back to List[<nothing>]
Previously if mypy couldn't infer a type for a variable, it would fall back to a type such as `List[Any]` instead of `List[<nothing>]`. However, #8036 accidentally changed this, as can be seen from this example:

```py
x = []  # type: ignore
print(x)
x = []
reveal_type(x)    # List[<nothing>] (used to be List[Any])
```

We should revert to the old behavior.


Discussion:

Resolving patch:
diff --git a/mypy/checker.py b/mypy/checker.py
--- a/mypy/checker.py
+++ b/mypy/checker.py
@@ -2173,7 +2173,7 @@ def try_infer_partial_generic_type_from_assignment(self,
             rvalue_type = self.expr_checker.accept(rvalue)
             rvalue_type = get_proper_type(rvalue_type)
             if isinstance(rvalue_type, Instance):
-                if rvalue_type.type == typ.type:
+                if rvalue_type.type == typ.type and is_valid_inferred_type(rvalue_type):
                     var.type = rvalue_type
                     del partial_types[var]
             elif isinstance(rvalue_type, AnyType):
@@ -2855,10 +2855,14 @@ def set_inference_error_fallback_type(self, var: Var, lvalue: Lvalue, type: Type
 
         We implement this here by giving x a valid type (replacing inferred <nothing> with Any).
         """
+        fallback = self.inference_error_fallback_type(type)
+        self.set_inferred_type(var, lvalue, fallback)
+
+    def inference_error_fallback_type(self, type: Type) -> Type:
         fallback = type.accept(SetNothingToAny())
         # Type variables may leak from inference, see https://github.com/python/mypy/issues/5738,
         # we therefore need to erase them.
-        self.set_inferred_type(var, lvalue, erase_typevars(fallback))
+        return erase_typevars(fallback)
 
     def check_simple_assignment(self, lvalue_type: Optional[Type], rvalue: Expression,
                                 context: Context,


Test patch:
diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test
--- a/test-data/unit/check-inference.test
+++ b/test-data/unit/check-inference.test
@@ -1585,6 +1585,29 @@ oo.update(d)
 reveal_type(oo) # N: Revealed type is 'collections.OrderedDict[builtins.int*, builtins.str*]'
 [builtins fixtures/dict.pyi]
 
+[case testEmptyCollectionAssignedToVariableTwiceIncremental]
+x = [] # E: Need type annotation for 'x' (hint: "x: List[<type>] = ...")
+y = x
+x = []
+reveal_type(x) # N: Revealed type is 'builtins.list[Any]'
+d = {} # E: Need type annotation for 'd' (hint: "d: Dict[<type>, <type>] = ...")
+z = d
+d = {}
+reveal_type(d) # N: Revealed type is 'builtins.dict[Any, Any]'
+[builtins fixtures/dict.pyi]
+[out2]
+main:1: error: Need type annotation for 'x' (hint: "x: List[<type>] = ...")
+main:4: note: Revealed type is 'builtins.list[Any]'
+main:5: error: Need type annotation for 'd' (hint: "d: Dict[<type>, <type>] = ...")
+main:8: note: Revealed type is 'builtins.dict[Any, Any]'
+
+[case testEmptyCollectionAssignedToVariableTwiceNoReadIncremental]
+x = [] # E: Need type annotation for 'x' (hint: "x: List[<type>] = ...")
+x = []
+[builtins fixtures/list.pyi]
+[out2]
+main:1: error: Need type annotation for 'x' (hint: "x: List[<type>] = ...")
+
 [case testInferAttributeInitializedToEmptyAndAssigned]
 class C:
     def __init__(self) -> None: