Skip to content

Commit

Permalink
Disallow assignments to methods
Browse files Browse the repository at this point in the history
  • Loading branch information
JukkaL committed Feb 12, 2013
1 parent 3c13419 commit 3ce8d6a
Show file tree
Hide file tree
Showing 4 changed files with 28 additions and 9 deletions.
8 changes: 8 additions & 0 deletions mypy/checker.py
Original file line number Diff line number Diff line change
Expand Up @@ -396,6 +396,14 @@ def infer_local_variable_type(self, x, y, z):
lvalue_types.append(None)
index_lvalues.append(ilv)
inferred.append(None)
elif isinstance(lv, MemberExpr):
mlv = (MemberExpr)lv
lvalue_types.append(
self.expr_checker.analyse_ordinary_member_access(mlv,
True))
self.store_type(mlv, lvalue_types[-1])
index_lvalues.append(None)
inferred.append(None)
else:
lvalue_types.append(self.accept(lv))
index_lvalues.append(None)
Expand Down
18 changes: 9 additions & 9 deletions mypy/checkmember.py
Original file line number Diff line number Diff line change
Expand Up @@ -43,13 +43,10 @@
info = override_info

# Look up the member. First look up the method dictionary.
FuncBase method = None
if not is_lvalue:
method = info.get_method(name)

method = info.get_method(name)
if method:
# Found a method. The call below has a unique result for all valid
# programs.
if is_lvalue:
msg.fail(messages.CANNOT_ASSIGN_TO_METHOD, node)
itype = map_instance_to_supertype(itype, method.info)
return expand_type_by_instance(method_type(method), itype)
else:
Expand All @@ -65,10 +62,11 @@
return analyse_member_access(name, basic_types.tuple, node, is_lvalue,
is_super, basic_types, msg)
elif isinstance(typ, FunctionLike) and ((FunctionLike)typ).is_type_obj():
# TODO super? lvalue?
# TODO super?
sig = (FunctionLike)typ
itype = (Instance)sig.items()[0].ret_type
result = analyse_class_attribute_access(itype, name, node, msg)
result = analyse_class_attribute_access(itype, name, node, is_lvalue,
msg)
if result:
return result
# Look up from the 'type' type.
Expand Down Expand Up @@ -148,9 +146,11 @@


Type analyse_class_attribute_access(Instance itype, str name, Context context,
MessageBuilder msg):
bool is_lvalue, MessageBuilder msg):
node = itype.type.get(name)
if node:
if is_lvalue and isinstance(node.node, FuncDef):
msg.fail(messages.CANNOT_ASSIGN_TO_METHOD, context)
t = node.type()
if t:
return add_class_tvars(t, itype.type)
Expand Down
1 change: 1 addition & 0 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,6 +47,7 @@
INVALID_SLICE_INDEX = 'Slice index must be an integer or None'
CANNOT_INFER_LAMBDA_TYPE = 'Cannot infer type of lambda'
CANNOT_ACCESS_INIT = 'Cannot access "__init__" directly'
CANNOT_ASSIGN_TO_METHOD = 'Cannot assign to a method'


class MessageBuilder:
Expand Down
10 changes: 10 additions & 0 deletions test/data/check-classes.test
Original file line number Diff line number Diff line change
Expand Up @@ -104,6 +104,11 @@ main: In member "f" of class "A":
main, line 3: Incompatible types in assignment
main, line 4: "A" has no attribute "g"

[case testAssignToMethodViaInstance]
class A:
def f(self): pass
A().f = None # E: Cannot assign to a method


-- Attributes
-- ----------
Expand Down Expand Up @@ -460,6 +465,11 @@ A.__init__(a, b)
A.__init__(b, b) # E: Argument 1 to "__init__" of "A" has incompatible type "B"
A.__init__(a, a) # E: Argument 2 to "__init__" of "A" has incompatible type "A"

[case testAssignToMethodViaClass]
class A:
def f(self): pass
A.f = None # E: Cannot assign to a method


-- Nested classes
-- --------------
Expand Down

0 comments on commit 3ce8d6a

Please sign in to comment.