Skip to content
Merged
Show file tree
Hide file tree
Changes from all 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
20 changes: 10 additions & 10 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -1557,11 +1557,11 @@ def visit_operator_assignment_stmt(self,
s: OperatorAssignmentStmt) -> Type:
"""Type check an operator assignment statement, e.g. x += 1."""
lvalue_type = self.accept(s.lvalue)
method = infer_operator_assignment_method(lvalue_type, s.op)
inplace, method = infer_operator_assignment_method(lvalue_type, s.op)
rvalue_type, method_type = self.expr_checker.check_op(
method, lvalue_type, s.rvalue, s)

if isinstance(s.lvalue, IndexExpr):
if isinstance(s.lvalue, IndexExpr) and not inplace:
self.check_indexed_assignment(s.lvalue, s.rvalue, s.rvalue)
else:
if not is_subtype(rvalue_type, lvalue_type):
Expand Down Expand Up @@ -2630,19 +2630,19 @@ def is_more_precise_signature(t: CallableType, s: CallableType) -> bool:
return is_more_precise(t.ret_type, s.ret_type)


def infer_operator_assignment_method(type: Type, operator: str) -> str:
"""Return the method used for operator assignment for given value type.
def infer_operator_assignment_method(type: Type, operator: str) -> Tuple[bool, str]:
"""Determine if operator assignment on given value type is in-place, and the method name.

For example, if operator is '+', return '__iadd__' or '__add__' depending
on which method is supported by the type.
For example, if operator is '+', return (True, '__iadd__') or (False, '__add__')
depending on which method is supported by the type.
"""
method = nodes.op_methods[operator]
if isinstance(type, Instance):
if operator in nodes.ops_with_inplace_method:
inplace = '__i' + method[2:]
if type.type.has_readable_member(inplace):
method = inplace
return method
inplace_method = '__i' + method[2:]
if type.type.has_readable_member(inplace_method):
return True, inplace_method
return False, method


def is_valid_inferred_type(typ: Type) -> bool:
Expand Down
16 changes: 16 additions & 0 deletions test-data/unit/check-statements.test
Original file line number Diff line number Diff line change
Expand Up @@ -301,6 +301,22 @@ a *= ''
a += '' # E: Argument 1 to "__iadd__" of "A" has incompatible type "str"; expected "int"
a *= 1 # E: Argument 1 to "__imul__" of "A" has incompatible type "int"; expected "str"

[case testInplaceSetitem]
class A(object):
def __init__(self):
self.a = 0

def __iadd__(self, a):
# type: (int) -> A
self.a += 1
return self

a = A()
b = [a]
b[0] += 1
[builtins fixtures/list.pyi]
[out]


-- Assert statement
-- ----------------
Expand Down