Skip to content

Error when a class member is redefined #6686

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 9 commits into from
Apr 30, 2019

Conversation

onlined
Copy link
Contributor

@onlined onlined commented Apr 17, 2019

Fixes #6571.

@onlined onlined changed the title Fix Error when a class member is redefined Apr 17, 2019
@ilevkivskyi
Copy link
Member

Note that your fix broke a whole bunch of new analyzer tests.

@onlined
Copy link
Contributor Author

onlined commented Apr 17, 2019

Fixed.

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

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

Thanks! Here I have some comments.

@@ -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.

class C:
def __init__(self) -> None:
self.foo = 12
self.foo: int = 12 # E: Name 'self.foo' already defined on line 3
Copy link
Member

Choose a reason for hiding this comment

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

Could you please also add a test for something like this:

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

Copy link
Member

Choose a reason for hiding this comment

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

You didn't add this test.

mypy/semanal.py Outdated
@@ -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.name_already_defined('self.' + lval.name, lval, cur_node)
Copy link
Member

Choose a reason for hiding this comment

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

I wouldn't use this error message because self.foo is not a name, it is an attribute. I would better use Attribute "foo" already defined ....

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Fixed.

@@ -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):
self.name_already_defined('self.' + lval.name, lval, cur_node)
Copy link
Member

Choose a reason for hiding this comment

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

Using this in the new analyzer is dangerous, it not not only shows the error, but also has some special code for deferring unknown names.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I couldn't understand what you meant. Could you explain it a little more?

Copy link
Member

Choose a reason for hiding this comment

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

I actually confused with with name_not_defined(). This one is OK. Anyway, did you check that in the situation where an error is emitted, no new variable created, and the l.h.s. points to an existing one?

Copy link
Contributor Author

@onlined onlined Apr 29, 2019

Choose a reason for hiding this comment

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

Yes, basically if cur_node is not None, l.h.s. points to an existing variable.

def __init__(self) -> None:
self.foo = 12
self.foo: int = 12 # E: Name 'self.foo' already defined on line 3

Copy link
Contributor Author

Choose a reason for hiding this comment

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

I am not very sure about this. Should I really add same tests to new semantic analyzer tests?

Copy link
Member

Choose a reason for hiding this comment

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

You don't need to duplicate tests, most test are currently run with both analyzers.

Copy link
Contributor Author

Choose a reason for hiding this comment

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

Removed redundant tests.

@ilevkivskyi
Copy link
Member

Thanks for updates! I left few more comments.

Copy link
Member

@ilevkivskyi ilevkivskyi left a comment

Choose a reason for hiding this comment

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

Thanks for updates! I have just one remaining question, otherwise this PR is ready.

@@ -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.

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

@ilevkivskyi ilevkivskyi merged commit ebd0479 into python:master Apr 30, 2019
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

No error when type annotation for self.foo comes after type is already inferred
2 participants