Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Fix crash with function redefinition #14064

Merged
merged 2 commits into from Nov 11, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Jump to
Jump to file
Failed to load files.
Diff view
Diff view
6 changes: 5 additions & 1 deletion mypy/checker.py
Expand Up @@ -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.
Expand Down
11 changes: 11 additions & 0 deletions test-data/unit/check-functions.test
Expand Up @@ -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:
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

A simpler test would be just if False: The problem is that mypy considers if branch unreachable, and therefore doesn't type check it, and therefore the original definition doesn't get its type inferred (and stays None).

I think a better solution is to simply not show any error in this case:

  • It will be more consistent with not showing error in unreachable code
  • Technically, there is no redefinition, only one definition is ever executed.

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Note however, this will be inconsistent with foo: int = 1, where user will get an error, even if the first definition is unreachable, but IMO this is OK.

foo = 1
else:
def foo(obj): ... # E: Incompatible redefinition (redefinition with type "Callable[[Any], Any]", original type <nothing>)
[builtins fixtures/tuple.pyi]

[case testConditionalRedefinitionOfAnUnconditionalFunctionDefinition1]
from typing import Any
def f(x: str) -> None: pass
Expand Down