From 268092fa4b6c2a110b968277ce66e9003709b1a8 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 5 Dec 2019 14:13:29 +0000 Subject: [PATCH 1/4] Fix type inference regression --- mypy/checker.py | 2 +- test-data/unit/check-inference.test | 11 +++++++++++ 2 files changed, 12 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index e6d1048185ea..f33a75d6a868 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2174,7 +2174,7 @@ def try_infer_partial_generic_type_from_assignment(self, rvalue_type = get_proper_type(rvalue_type) if isinstance(rvalue_type, Instance): if rvalue_type.type == typ.type: - var.type = rvalue_type + self.infer_variable_type(var, lvalue, rvalue_type, rvalue) del partial_types[var] elif isinstance(rvalue_type, AnyType): var.type = fill_typevars_with_any(typ.type) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 5366de858018..07bdfa66ec04 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1585,6 +1585,17 @@ oo.update(d) reveal_type(oo) # N: Revealed type is 'collections.OrderedDict[builtins.int*, builtins.str*]' [builtins fixtures/dict.pyi] +[case testEmptyCollectionAssignedToVariableTwice] +x = [] # E: Need type annotation for 'x' (hint: "x: List[] = ...") +y = x +x = [] +reveal_type(x) # N: Revealed type is 'builtins.list[Any]' +d = {} # E: Need type annotation for 'd' (hint: "d: Dict[, ] = ...") +z = d +d = {} +reveal_type(d) # N: Revealed type is 'builtins.dict[Any, Any]' +[builtins fixtures/dict.pyi] + [case testInferAttributeInitializedToEmptyAndAssigned] class C: def __init__(self) -> None: From de6902fd1e185a29fe78f827a74186de6e59f99f Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Thu, 5 Dec 2019 14:48:20 +0000 Subject: [PATCH 2/4] Better fix --- mypy/checker.py | 12 ++++++++++-- test-data/unit/check-inference.test | 7 ++++++- 2 files changed, 16 insertions(+), 3 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index f33a75d6a868..1aea2a31cc39 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2174,7 +2174,10 @@ def try_infer_partial_generic_type_from_assignment(self, rvalue_type = get_proper_type(rvalue_type) if isinstance(rvalue_type, Instance): if rvalue_type.type == typ.type: - self.infer_variable_type(var, lvalue, rvalue_type, rvalue) + if is_valid_inferred_type(rvalue_type): + var.type = rvalue_type + else: + var.type = self.inference_error_fallback_type(rvalue_type) del partial_types[var] elif isinstance(rvalue_type, AnyType): var.type = fill_typevars_with_any(typ.type) @@ -2785,6 +2788,7 @@ def infer_variable_type(self, name: Var, lvalue: Lvalue, init_type = get_proper_type(init_type) if isinstance(init_type, DeletedType): self.msg.deleted_as_rvalue(init_type, context) + name.type = AnyType(TypeOfAny.from_error) elif not is_valid_inferred_type(init_type) and not self.no_partial_types: # We cannot use the type of the initialization expression for full type # inference (it's not specific enough), but we might be able to give @@ -2855,10 +2859,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 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, diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 07bdfa66ec04..1d744beb5761 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1585,7 +1585,7 @@ oo.update(d) reveal_type(oo) # N: Revealed type is 'collections.OrderedDict[builtins.int*, builtins.str*]' [builtins fixtures/dict.pyi] -[case testEmptyCollectionAssignedToVariableTwice] +[case testEmptyCollectionAssignedToVariableTwiceIncremental] x = [] # E: Need type annotation for 'x' (hint: "x: List[] = ...") y = x x = [] @@ -1595,6 +1595,11 @@ 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[] = ...") +main:4: note: Revealed type is 'builtins.list[Any]' +main:5: error: Need type annotation for 'd' (hint: "d: Dict[, ] = ...") +main:8: note: Revealed type is 'builtins.dict[Any, Any]' [case testInferAttributeInitializedToEmptyAndAssigned] class C: From cf19dfa737d41edc50cef652ea22a47a69bd8d35 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 6 Dec 2019 11:00:17 +0000 Subject: [PATCH 3/4] Fix special case --- mypy/checker.py | 7 ++----- test-data/unit/check-inference.test | 7 +++++++ 2 files changed, 9 insertions(+), 5 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 1aea2a31cc39..6cc465ef4b17 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2173,11 +2173,8 @@ 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 is_valid_inferred_type(rvalue_type): - var.type = rvalue_type - else: - var.type = self.inference_error_fallback_type(rvalue_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): var.type = fill_typevars_with_any(typ.type) diff --git a/test-data/unit/check-inference.test b/test-data/unit/check-inference.test index 1d744beb5761..665d789cf71e 100644 --- a/test-data/unit/check-inference.test +++ b/test-data/unit/check-inference.test @@ -1601,6 +1601,13 @@ main:4: note: Revealed type is 'builtins.list[Any]' main:5: error: Need type annotation for 'd' (hint: "d: Dict[, ] = ...") main:8: note: Revealed type is 'builtins.dict[Any, Any]' +[case testEmptyCollectionAssignedToVariableTwiceNoReadIncremental] +x = [] # E: Need type annotation for 'x' (hint: "x: List[] = ...") +x = [] +[builtins fixtures/list.pyi] +[out2] +main:1: error: Need type annotation for 'x' (hint: "x: List[] = ...") + [case testInferAttributeInitializedToEmptyAndAssigned] class C: def __init__(self) -> None: From a8441e02572798f99dde924c71d44f8e083dad55 Mon Sep 17 00:00:00 2001 From: Jukka Lehtosalo Date: Fri, 6 Dec 2019 11:24:21 +0000 Subject: [PATCH 4/4] Revert unrelated change --- mypy/checker.py | 1 - 1 file changed, 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index 6cc465ef4b17..9a826cd41496 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -2785,7 +2785,6 @@ def infer_variable_type(self, name: Var, lvalue: Lvalue, init_type = get_proper_type(init_type) if isinstance(init_type, DeletedType): self.msg.deleted_as_rvalue(init_type, context) - name.type = AnyType(TypeOfAny.from_error) elif not is_valid_inferred_type(init_type) and not self.no_partial_types: # We cannot use the type of the initialization expression for full type # inference (it's not specific enough), but we might be able to give