From 4c4cf8fbff4eb8288cc6e7ef4616c30b034f3ff1 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Thu, 10 Nov 2022 17:33:40 -0800 Subject: [PATCH 1/2] Fix crash with function redefinition Fixes #14027 --- mypy/checker.py | 6 +++++- test-data/unit/check-functions.test | 11 +++++++++++ 2 files changed, 16 insertions(+), 1 deletion(-) diff --git a/mypy/checker.py b/mypy/checker.py index fef85d085496..328304792171 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -960,7 +960,11 @@ def _visit_func_def(self, defn: FuncDef) -> None: # Function definition overrides a variable initialized via assignment or a # decorated function. orig_type = defn.original_def.type - assert orig_type is not None, f"Error checking function redefinition {defn}" + if orig_type is None: + # I'm not sure why this happens, probably a bug elsewhere + # See testConditionalFunctionDefinitionWithTuple + # Setting orig_type to UninhabitedType ensures an error is reported + orig_type = UninhabitedType() if isinstance(orig_type, PartialType): if orig_type.type is None: # Ah this is a partial type. Give it the type of the function. diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index bb36b65f35de..697a81d3803b 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -1475,6 +1475,17 @@ else: @dec def f(): pass +[case testConditionalFunctionDefinitionWithTuple] +def bar() -> None: + # weirdly, needs to be an empty tuple. empty lists and various other special assignments + # don't trigger the bug + cond = () + if cond: + foo = 1 + else: + def foo(obj): ... # E: Incompatible redefinition (redefinition with type "Callable[[Any], Any]", original type ) +[builtins fixtures/tuple.pyi] + [case testConditionalRedefinitionOfAnUnconditionalFunctionDefinition1] from typing import Any def f(x: str) -> None: pass From c3739994f88c897f558c72ad9471243ecf404128 Mon Sep 17 00:00:00 2001 From: hauntsaninja Date: Fri, 11 Nov 2022 11:03:49 -0800 Subject: [PATCH 2/2] code review --- mypy/checker.py | 7 +++---- test-data/unit/check-functions.test | 15 +++++++++------ 2 files changed, 12 insertions(+), 10 deletions(-) diff --git a/mypy/checker.py b/mypy/checker.py index 328304792171..dfd7ca5e857e 100644 --- a/mypy/checker.py +++ b/mypy/checker.py @@ -961,10 +961,9 @@ def _visit_func_def(self, defn: FuncDef) -> None: # decorated function. orig_type = defn.original_def.type if orig_type is None: - # I'm not sure why this happens, probably a bug elsewhere - # See testConditionalFunctionDefinitionWithTuple - # Setting orig_type to UninhabitedType ensures an error is reported - orig_type = UninhabitedType() + # If other branch is unreachable, we don't type check it and so we might + # not have a type for the original definition + return if isinstance(orig_type, PartialType): if orig_type.type is None: # Ah this is a partial type. Give it the type of the function. diff --git a/test-data/unit/check-functions.test b/test-data/unit/check-functions.test index 697a81d3803b..ae6424f743be 100644 --- a/test-data/unit/check-functions.test +++ b/test-data/unit/check-functions.test @@ -1475,15 +1475,18 @@ else: @dec def f(): pass -[case testConditionalFunctionDefinitionWithTuple] +[case testConditionalFunctionDefinitionUnreachable] def bar() -> None: - # weirdly, needs to be an empty tuple. empty lists and various other special assignments - # don't trigger the bug - cond = () - if cond: + if False: foo = 1 else: - def foo(obj): ... # E: Incompatible redefinition (redefinition with type "Callable[[Any], Any]", original type ) + def foo(obj): ... + +def baz() -> None: + if False: + foo: int = 1 + else: + def foo(obj): ... # E: Incompatible redefinition (redefinition with type "Callable[[Any], Any]", original type "int") [builtins fixtures/tuple.pyi] [case testConditionalRedefinitionOfAnUnconditionalFunctionDefinition1]