From ac822f3b97d9227b4d31fd99b56cbf1ff65ed803 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 25 Dec 2021 18:39:03 +0300 Subject: [PATCH 1/3] Attempt to fix `bool` re-narrowing --- mypy/binder.py | 7 +++++-- mypy/checker.py | 8 +++++--- test-data/unit/check-narrowing.test | 14 ++++++++++++++ 3 files changed, 24 insertions(+), 5 deletions(-) diff --git a/mypy/binder.py b/mypy/binder.py index 2f83ffb095fc..d7200455a6f0 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -135,14 +135,16 @@ def _get(self, key: Key, index: int = -1) -> Optional[Type]: return self.frames[i].types[key] return None - def put(self, expr: Expression, typ: Type) -> None: + def put(self, expr: Expression, typ: Type, *, redeclare: bool = False) -> None: if not isinstance(expr, (IndexExpr, MemberExpr, AssignmentExpr, NameExpr)): return if not literal(expr): return key = literal_hash(expr) assert key is not None, 'Internal error: binder tried to put non-literal' - if key not in self.declarations: + if redeclare: + self.declarations[key] = typ + elif key not in self.declarations: self.declarations[key] = get_declaration(expr) self._add_dependencies(key) self._put(key, typ) @@ -203,6 +205,7 @@ def update_from_options(self, frames: List[Frame]) -> bool: type = resulting_values[0] assert type is not None declaration_type = get_proper_type(self.declarations.get(key)) + print(key, declaration_type) if isinstance(declaration_type, AnyType): # At this point resulting values can't contain None, see continue above if not all(is_same_type(type, cast(Type, t)) for t in resulting_values[1:]): diff --git a/mypy/checker.py b/mypy/checker.py index b90221a0a5a5..60fd78208b5d 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -3479,7 +3479,9 @@ def visit_assert_stmt(self, s: AssertStmt) -> None: true_map, else_map = self.find_isinstance_check(s.expr) if s.msg is not None: self.expr_checker.analyze_cond_branch(else_map, s.msg, None) - self.push_type_map(true_map) + # We want to redeclare the type in type_map, because it was refined + # for the rest of the frame. + self.push_type_map(true_map, redeclare=True) def visit_raise_stmt(self, s: RaiseStmt) -> None: """Type check a raise statement.""" @@ -5244,12 +5246,12 @@ def iterable_item_type(self, instance: Instance) -> Type: def function_type(self, func: FuncBase) -> FunctionLike: return function_type(func, self.named_type('builtins.function')) - def push_type_map(self, type_map: 'TypeMap') -> None: + def push_type_map(self, type_map: 'TypeMap', *, redeclare: bool = False) -> None: if type_map is None: self.binder.unreachable() else: for expr, type in type_map.items(): - self.binder.put(expr, type) + self.binder.put(expr, type, redeclare=redeclare) def infer_issubclass_maps(self, node: CallExpr, expr: Expression, diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index d6b25ef456d9..c043da04fad9 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1245,3 +1245,17 @@ def two_type_vars(x: Union[str, Dict[str, int], Dict[bool, object], int]) -> Non else: reveal_type(x) # N: Revealed type is "builtins.int" [builtins fixtures/dict.pyi] + +[case testBoolNarrowingAfterLiterallFallback] +from typing import Any + +var: Any +reveal_type(var) # N: Revealed type is "Any" +assert isinstance(var, bool) +reveal_type(var) # N: Revealed type is "builtins.bool" + +if var: + reveal_type(var) # N: Revealed type is "Literal[True]" + pass +reveal_type(var) # N: Revealed type is "builtins.bool" +[builtins fixtures/isinstance.pyi] From 25f2429f741a2f46033b833634c8f6b76d17eed0 Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 25 Dec 2021 18:52:58 +0300 Subject: [PATCH 2/3] Fixes CI --- mypy/binder.py | 1 - test-data/unit/check-narrowing.test | 2 +- 2 files changed, 1 insertion(+), 2 deletions(-) diff --git a/mypy/binder.py b/mypy/binder.py index d7200455a6f0..a53fb45c7ca4 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -205,7 +205,6 @@ def update_from_options(self, frames: List[Frame]) -> bool: type = resulting_values[0] assert type is not None declaration_type = get_proper_type(self.declarations.get(key)) - print(key, declaration_type) if isinstance(declaration_type, AnyType): # At this point resulting values can't contain None, see continue above if not all(is_same_type(type, cast(Type, t)) for t in resulting_values[1:]): diff --git a/test-data/unit/check-narrowing.test b/test-data/unit/check-narrowing.test index c043da04fad9..d0aa5d57ef55 100644 --- a/test-data/unit/check-narrowing.test +++ b/test-data/unit/check-narrowing.test @@ -1247,6 +1247,7 @@ def two_type_vars(x: Union[str, Dict[str, int], Dict[bool, object], int]) -> Non [builtins fixtures/dict.pyi] [case testBoolNarrowingAfterLiterallFallback] +# https://github.com/python/mypy/issues/11839 from typing import Any var: Any @@ -1256,6 +1257,5 @@ reveal_type(var) # N: Revealed type is "builtins.bool" if var: reveal_type(var) # N: Revealed type is "Literal[True]" - pass reveal_type(var) # N: Revealed type is "builtins.bool" [builtins fixtures/isinstance.pyi] From e21f005525738860fd783393e3acb1bfc022cbcb Mon Sep 17 00:00:00 2001 From: sobolevn Date: Sat, 25 Dec 2021 19:11:56 +0300 Subject: [PATCH 3/3] Maybe this will fix mypyc tests? --- mypy/binder.py | 5 +++-- 1 file changed, 3 insertions(+), 2 deletions(-) diff --git a/mypy/binder.py b/mypy/binder.py index a53fb45c7ca4..dee24c516b8b 100644 --- a/mypy/binder.py +++ b/mypy/binder.py @@ -142,8 +142,9 @@ def put(self, expr: Expression, typ: Type, *, redeclare: bool = False) -> None: return key = literal_hash(expr) assert key is not None, 'Internal error: binder tried to put non-literal' - if redeclare: - self.declarations[key] = typ + proper = get_proper_type(typ) + if redeclare and proper: + self.declarations[key] = proper elif key not in self.declarations: self.declarations[key] = get_declaration(expr) self._add_dependencies(key)