Skip to content

Commit

Permalink
Merged in jwalden/mypy/unary-plus (pull request #1)
Browse files Browse the repository at this point in the history
Add support for modeling unary plus, including with respect to a custom __pos__
  • Loading branch information
JukkaL committed Jul 15, 2014
2 parents 5c34cdb + 5ca7147 commit 86ec658
Show file tree
Hide file tree
Showing 10 changed files with 67 additions and 5 deletions.
10 changes: 8 additions & 2 deletions mypy/checkexpr.py
Original file line number Diff line number Diff line change
Expand Up @@ -850,7 +850,7 @@ def check_list_multiply(self, e: OpExpr) -> Type:
return result

def visit_unary_expr(self, e: UnaryExpr) -> Type:
"""Type check an unary operation ('not', '-' or '~')."""
"""Type check an unary operation ('not', '-', '+' or '~')."""
operand_type = self.accept(e.expr)
op = e.op
if op == 'not':
Expand All @@ -861,7 +861,13 @@ def visit_unary_expr(self, e: UnaryExpr) -> Type:
operand_type, e)
result, method_type = self.check_call(method_type, [], [], e)
e.method_type = method_type
elif op == '~':
elif op == '+':
method_type = self.analyse_external_member_access('__pos__',
operand_type, e)
result, method_type = self.check_call(method_type, [], [], e)
e.method_type = method_type
else:
assert op == '~', "unhandled unary operator"
method_type = self.analyse_external_member_access('__invert__',
operand_type, e)
result, method_type = self.check_call(method_type, [], [], e)
Expand Down
4 changes: 3 additions & 1 deletion mypy/icode.py
Original file line number Diff line number Diff line change
Expand Up @@ -639,10 +639,12 @@ def visit_unary_expr(self, e: UnaryExpr) -> int:
else:
if e.op == '-':
method = '__neg__'
elif e.op == '+':
method = '__pos__'
elif e.op == '~':
method = '__invert__'
else:
raise NotImplementedError()
raise NotImplementedError("unhandled op: " + e.op)
inst = cast(Instance, operand_type) # TODO more flexible
self.add(CallMethod(target, operand, method, inst.type, []))
return target
Expand Down
3 changes: 3 additions & 0 deletions mypy/messages.py
Original file line number Diff line number Diff line change
Expand Up @@ -230,6 +230,9 @@ def has_no_attr(self, typ: Type, member: str, context: Context) -> Type:
elif member == '__neg__':
self.fail('Unsupported operand type for unary - ({})'.format(
self.format(typ)), context)
elif member == '__pos__':
self.fail('Unsupported operand type for unary + ({})'.format(
self.format(typ)), context)
elif member == '__invert__':
self.fail('Unsupported operand type for ~ ({})'.format(
self.format(typ)), context)
Expand Down
16 changes: 16 additions & 0 deletions mypy/test/data/check-expressions.test
Original file line number Diff line number Diff line change
Expand Up @@ -554,6 +554,22 @@ class B:
main, line 3: Incompatible types in assignment
main, line 4: Unsupported operand type for unary - ("B")

[case testUnaryPlus]
from typing import Undefined
a, b = Undefined, Undefined # type: (A, B)
a = +a # Fail
b = +b # Fail
b = +a

class A:
def __pos__(self) -> 'B':
pass
class B:
pass
[out]
main, line 3: Incompatible types in assignment
main, line 4: Unsupported operand type for unary + ("B")

[case testUnaryNot]
from typing import Undefined
a, b = Undefined, Undefined # type: (A, bool)
Expand Down
27 changes: 25 additions & 2 deletions mypy/test/data/dyncheck-trans-basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -1321,7 +1321,7 @@ x = x in a
a: A = Undefined
x = {Any <= int {A x} in a}

[case testUnaryOperator]
[case testUnaryMinusOperator]
from typing import Undefined, Any
class A:
def __neg__(self) -> bool: pass
Expand All @@ -1334,6 +1334,19 @@ x = -a
a: A = Undefined
x = {Any <= bool -a}

[case testUnaryPlusOperator]
from typing import Undefined, Any
class A:
def __pos__(self) -> bool: pass
x = Undefined # type: Any
a = Undefined # type: A
x = +a
[builtins fixtures/ops.py]
[out]
...
a: A = Undefined
x = {Any <= bool +a}

[case testTransformBinaryOpOperands]
from typing import Any, Undefined
class A:
Expand All @@ -1358,7 +1371,7 @@ a[f(1)]
a: A = Undefined
a[f({Any <= int 1})]

[case testTransformUnaryOperand]
[case testTransformUnaryMinusOperand]
from typing import Any
class A:
def __neg__(self) -> int: pass
Expand All @@ -1367,3 +1380,13 @@ def f(x: Any) -> A: pass
[out]
...
-f({Any <= int 1})

[case testTransformUnaryPlusOperand]
from typing import Any
class A:
def __pos__(self) -> int: pass
def f(x: Any) -> A: pass
+f(1)
[out]
...
+f({Any <= int 1})
1 change: 1 addition & 0 deletions mypy/test/data/fixtures/icodegen.py
Original file line number Diff line number Diff line change
Expand Up @@ -19,6 +19,7 @@ def __add__(self, n: int) -> int: pass
def __sub__(self, n: int) -> int: pass
def __mul__(self, n: int) -> int: pass
def __neg__(self) -> int: pass
def __pos__(self) -> int: pass
def __eq__(self, n: int) -> bool: pass
def __ne__(self, n: int) -> bool: pass
def __lt__(self, n: int) -> bool: pass
Expand Down
1 change: 1 addition & 0 deletions mypy/test/data/fixtures/ops.py
Original file line number Diff line number Diff line change
Expand Up @@ -22,6 +22,7 @@ def __sub__(self, x: 'int') -> 'int': pass
def __mul__(self, x: 'int') -> 'int': pass
def __mod__(self, x: 'int') -> 'int': pass
def __floordiv__(self, x: 'int') -> 'int': pass
def __pos__(self) -> 'int': pass
def __neg__(self) -> 'int': pass
def __eq__(self, x: object) -> bool: pass
def __ne__(self, x: object) -> bool: pass
Expand Down
6 changes: 6 additions & 0 deletions mypy/test/data/icode-basic.test
Original file line number Diff line number Diff line change
Expand Up @@ -531,15 +531,21 @@ def f:
import typing
class A:
def __neg__(self) -> int: pass
def __pos__(self) -> int: pass
def __invert__(self) -> int: pass
def f(a: A) -> int:
return -a
def g(a: A) -> int:
return +a
def h(a: A) -> int:
return ~a
[out]
def f:
r1 = r0.__neg__() [A]
return r1
def g:
r1 = r0.__pos__() [A]
return r1
def h:
r1 = r0.__invert__() [A]
return r1
2 changes: 2 additions & 0 deletions stubs/2.7/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -101,6 +101,7 @@ def __rlshift__(self, n: int) -> int: pass
def __rrshift__(self, n: int) -> int: pass

def __neg__(self) -> int: pass
def __pos__(self) -> int: pass
def __invert__(self) -> int: pass

def __eq__(self, x: object) -> bool: pass
Expand Down Expand Up @@ -159,6 +160,7 @@ def __le__(self, x: float) -> bool: pass
def __gt__(self, x: float) -> bool: pass
def __ge__(self, x: float) -> bool: pass
def __neg__(self) -> float: pass
def __pos__(self) -> float: pass

def __str__(self) -> str: pass
def __int__(self) -> int: pass
Expand Down
2 changes: 2 additions & 0 deletions stubs/3.2/builtins.py
Original file line number Diff line number Diff line change
Expand Up @@ -114,6 +114,7 @@ def __rlshift__(self, n: int) -> int: pass
def __rrshift__(self, n: int) -> int: pass

def __neg__(self) -> int: pass
def __pos__(self) -> int: pass
def __invert__(self) -> int: pass

def __eq__(self, x: object) -> bool: pass
Expand Down Expand Up @@ -179,6 +180,7 @@ def __le__(self, x: float) -> bool: pass
def __gt__(self, x: float) -> bool: pass
def __ge__(self, x: float) -> bool: pass
def __neg__(self) -> float: pass
def __pos__(self) -> float: pass

def __str__(self) -> str: pass
def __int__(self) -> int: pass
Expand Down

0 comments on commit 86ec658

Please sign in to comment.