8000 Fix crashes in class scoped imports by hauntsaninja · Pull Request #12023 · python/mypy · GitHub
[go: up one dir, main page]

Skip to content

Fix crashes in class scoped imports #12023

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

Merged
merged 33 commits into from
Feb 17, 2022
Merged
Show file tree
Hide file tree
Changes from 1 commit
Commits
Show all changes
33 commits
Select commit Hold shift + click to select a range
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Prev Previous commit
Next Next commit
Fix self binding and improve line number diagnostics
  • Loading branch information
hauntsaninja committed Feb 15, 2022
commit 2119c3d2db0cf42400dc9ab1996a8a1ff3e3a131
16 changes: 10 additions & 6 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -48,6 +48,7 @@
reduce memory use).
"""

import copy
from contextlib import contextmanager

from typing import (
Expand Down Expand Up @@ -4788,10 +4789,6 @@ def add_imported_symbol(self,
assert not module_hidden or not module_public

symbol_node: Optional[SymbolNode] = node.node
# I promise this type checks; I'm just making mypyc issues go away.
# mypyc is absolutely convinced that `symbol_node` narrows to a Var in the following,
# when it can also be a FuncBase.
symbol_node_any: Any = cast(Any, symbol_node)
if self.is_class_scope() and isinstance(symbol_node, (FuncBase, Var)):
# We construct a new node to represent this symbol and set its `info` attribute
# to `self.type`. Note that imports inside class scope do not produce methods, so
Expand All @@ -4802,12 +4799,19 @@ def add_imported_symbol(self,
# constructed Var, so check for possible redefinitions here.
existing is not None
and isinstance(existing.node, Var)
and existing.type == symbol_node_any.type
and existing.type == symbol_node.type
):
symbol_node = existing.node
else:
symbol_node = Var(symbol_node_any.name, symbol_node_any.type)
if isinstance(symbol_node, Var):
symbol_node = Var(symbol_node.name, symbol_node.type)
elif isinstance(symbol_node, FuncBase):
symbol_node = copy.copy(symbol_node)
else:
assert False
assert self.type is not None
symbol_node.line = context.line
symbol_node.column = context.column
symbol_node.info = self.type
symbol_node._fullname = self.qualified_name(name)

Expand Down
10 changes: 6 additions & 4 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -7140,7 +7140,8 @@ class Foo:
from mod import foo

reveal_type(Foo.foo) # N: Revealed type is "def (x: builtins.int, y: builtins.int) -> builtins.int"
reveal_type(Foo().foo) # N: Revealed type is "def (x: builtins.int, y: builtins.int) -> builtins.int"
reveal_type(Foo().foo) # E: Invalid self argument "Foo" to attribute function "foo" with type "Callable[[int, int], int]" \
# N: Revealed type is "def (y: builtins.int) -> builtins.int"
[file mod.py]
def foo(x: int, y: int) -> int: ...

Expand Down Expand Up @@ -7195,7 +7196,8 @@ class Foo:
from mod import baz

reveal_type(Foo.Bar.baz) # N: Revealed type is "def (x: builtins.int) -> builtins.int"
reveal_type(Foo.Bar().baz) # N: Revealed type is "def (x: builtins.int) -> builtins.int"
reveal_type(Foo.Bar().baz) # E: Invalid self argument "Bar" to attribute function "baz" with type "Callable[[int], int]" \
# N: Revealed type is "def () -> builtins.int"
[file mod.py]
def baz(x: int) -> int: ...

Expand All @@ -7219,10 +7221,10 @@ def foo(x: int, y: int) -> int: ...
[case testClassScopeImportVarious]
class Foo:
from mod1 import foo
from mod2 import foo # E: Name "foo" already defined (possibly by an import)
from mod2 import foo # E: Name "foo" already defined on line 2

from mod1 import meth1
def meth1(self, a: str) -> str: ... # E: Name "meth1" already defined (possibly by an import)
def meth1(self, a: str) -> str: ... # E: Name "meth1" already defined on line 5

def meth2(self, a: str) -> str: ...
from mod1 import meth2 # E: Name "meth2" already defined on line 8
Expand Down
0