Skip to content
Merged
Show file tree
Hide file tree
Changes from 8 commits
Commits
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
21 changes: 17 additions & 4 deletions mypy/newsemanal/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2563,6 +2563,9 @@ def analyze_member_lvalue(self, lval: MemberExpr, explicit_type: bool, is_final:
if cur_node and is_final:
# Overrides will be checked in type checker.
self.fail("Cannot redefine an existing name as final", lval)
if (not lval.node and cur_node and isinstance(cur_node.node, Var) and
cur_node.node.is_inferred and explicit_type):
Copy link
Member

Choose a reason for hiding this comment

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

TBH I don't follow the logic here, maybe add a comment explaining this?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I can write a comment. But before, let me explain: Fail if passing first time, the node exists and it's a Var node, it's type is inferred, and new assignment has an explicit type.

Copy link
Member

@ilevkivskyi ilevkivskyi Apr 26, 2019

Choose a reason for hiding this comment

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

Basically yes. But please try to avoid this:

x += 1  # Increment x

Describe the intent and how the code achieves it.

Copy link
Member

Choose a reason for hiding this comment

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

@onlined Are you going to add this comment (also in the old analyzer)?

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Yes, I will.

self.attribute_already_defined(lval.name, lval, cur_node)
# If the attribute of self is not defined in superclasses, create a new Var, ...
if ((node is None or isinstance(node.node, Var) and node.node.is_abstract_var) or
# ... also an explicit declaration on self also creates a new Var.
Expand Down Expand Up @@ -4298,9 +4301,9 @@ def name_not_defined(self, name: str, ctx: Context, namespace: Optional[str] = N
# Yes. Generate a helpful note.
self.add_fixture_note(fullname, ctx)

def name_already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None
) -> None:
def already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None, *,
noun: str) -> None:
if isinstance(original_ctx, SymbolTableNode):
node = original_ctx.node # type: Optional[SymbolNode]
elif isinstance(original_ctx, SymbolNode):
Expand All @@ -4319,7 +4322,17 @@ def name_already_defined(self, name: str, ctx: Context,
extra_msg = ' on line {}'.format(node.line)
else:
extra_msg = ' (possibly by an import)'
self.fail("Name '{}' already defined{}".format(unmangle(name), extra_msg), ctx)
self.fail("{} '{}' already defined{}".format(noun, unmangle(name), extra_msg), ctx)

def name_already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None
) -> None:
self.already_defined(name, ctx, original_ctx, noun='Name')

def attribute_already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None
) -> None:
self.already_defined(name, ctx, original_ctx, noun='Attribute')

def is_local_name(self, name: str) -> bool:
"""Does name look like reference to a definition in the current module?"""
Expand Down
20 changes: 17 additions & 3 deletions mypy/semanal.py
Original file line number Diff line number Diff line change
Expand Up @@ -2288,6 +2288,9 @@ def analyze_member_lvalue(self, lval: MemberExpr, explicit_type: bool, is_final:
if cur_node and is_final:
# Overrides will be checked in type checker.
self.fail("Cannot redefine an existing name as final", lval)
if (cur_node and isinstance(cur_node.node, Var) and cur_node.node.is_inferred and
explicit_type):
self.attribute_already_defined(lval.name, lval, cur_node)
# If the attribute of self is not defined in superclasses, create a new Var, ...
if ((node is None or isinstance(node.node, Var) and node.node.is_abstract_var) or
# ... also an explicit declaration on self also creates a new Var.
Expand Down Expand Up @@ -3736,8 +3739,9 @@ def name_not_defined(self, name: str, ctx: Context) -> None:
# Yes. Generate a helpful note.
self.add_fixture_note(fullname, ctx)

def name_already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None) -> None:
def already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None, *,
noun: str) -> None:
if isinstance(original_ctx, SymbolTableNode):
node = original_ctx.node
elif isinstance(original_ctx, SymbolNode):
Expand All @@ -3752,7 +3756,17 @@ def name_already_defined(self, name: str, ctx: Context,
extra_msg = ' on line {}'.format(node.line)
else:
extra_msg = ' (possibly by an import)'
self.fail("Name '{}' already defined{}".format(unmangle(name), extra_msg), ctx)
self.fail("{} '{}' already defined{}".format(noun, unmangle(name), extra_msg), ctx)

def name_already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None
) -> None:
self.already_defined(name, ctx, original_ctx, noun='Name')

def attribute_already_defined(self, name: str, ctx: Context,
original_ctx: Optional[Union[SymbolTableNode, SymbolNode]] = None
) -> None:
self.already_defined(name, ctx, original_ctx, noun='Attribute')

def fail(self, msg: str, ctx: Context, serious: bool = False, *,
blocker: bool = False) -> None:
Expand Down
12 changes: 12 additions & 0 deletions test-data/unit/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -5838,6 +5838,18 @@ def test() -> None:
reveal_type(x) # E: Revealed type is 'Union[Type[__main__.One], Type[__main__.Other]]'
[builtins fixtures/isinstancelist.pyi]

[case testMemberRedefinition]
class C:
def __init__(self) -> None:
self.foo = 12
self.foo: int = 12 # E: Attribute 'foo' already defined on line 3

[case testMemberRedefinitionDefinedInClass]
class C:
foo = 12
def __init__(self) -> None:
self.foo: int = 12 # E: Attribute 'foo' already defined on line 2

[case testAbstractInit]
from abc import abstractmethod, ABCMeta
class A(metaclass=ABCMeta):
Expand Down