Repository: vyperlang/vyper

Issue:
Literal division returns wrong result
When I used ``vyper-run`` on this code:

```
@public
def test() -> decimal:
   return 5 / 2
```

I get the following output:
```
* Calling test()
- Returns:
'5'
- Logs:
```

When the expected result was ``2.5`` instead of ``5``.

After a few more tests with other numbers, it looks like the bug is that ``vyper-run`` prints out the original number before the division. So ``7 / 3`` returns 7. I am not sure yet if the problem is with ``vyper-run`` or Vyper itself.

There is a bug if the result is an ``int`` but is saved as a ``decimal``.

For example, the same code as above but with ``10 / 5`` produces ``2E-10``. While it should either produce ``2.0`` or throw an error.

#### Cute Animal Picture

![image](https://user-images.githubusercontent.com/10667901/41818261-9988ec7c-77b3-11e8-93c5-befd04212eb8.png)




Discussion:
This a bug with the literal simplification.
@zaq1tomo, go for it!

Our approach was to evaluate the constants in Python and set them to one number in our generated code output. It should match the data types being used, so `5/2` should floor to 2 but `convert(5/2, 'fixed168x10')` should convert to 2.5

Resolving patch:
diff --git a/vyper/parser/expr.py b/vyper/parser/expr.py
--- a/vyper/parser/expr.py
+++ b/vyper/parser/expr.py
@@ -271,7 +271,7 @@ def arithmetic(self):
             elif isinstance(self.expr.op, ast.Mult):
                 val = left.value * right.value
             elif isinstance(self.expr.op, ast.Div):
-                val = left.value / right.value
+                val = left.value // right.value
             elif isinstance(self.expr.op, ast.Mod):
                 val = left.value % right.value
             elif isinstance(self.expr.op, ast.Pow):
@@ -279,10 +279,6 @@ def arithmetic(self):
             else:
                 raise ParserException('Unsupported literal operator: %s' % str(type(self.expr.op)), self.expr)
 
-            # For scenario were mul and div produce a whole number:
-            if isinstance(val, float) and val.is_integer():
-                val = int(val)
-
             num = ast.Num(val)
             num.source_code = self.expr.source_code
             num.lineno = self.expr.lineno
diff --git a/vyper/parser/stmt.py b/vyper/parser/stmt.py
--- a/vyper/parser/stmt.py
+++ b/vyper/parser/stmt.py
@@ -418,7 +418,7 @@ def parse_return(self):
             elif is_base_type(sub.typ, self.context.return_type.typ) or \
                     (is_base_type(sub.typ, 'int128') and is_base_type(self.context.return_type, 'int256')):
                 return LLLnode.from_list(['seq', ['mstore', 0, sub], ['return', 0, 32]], typ=None, pos=getpos(self.stmt))
-            if sub.typ.is_literal and SizeLimits.in_bounds(self.context.return_type.typ, sub.value):
+            if sub.typ.is_literal and SizeLimits.in_bounds(self.context.return_type.typ, sub.value) and self.context.return_type.typ == sub.typ:
                 return LLLnode.from_list(['seq', ['mstore', 0, sub], ['return', 0, 32]], typ=None, pos=getpos(self.stmt))
             else:
                 raise TypeMismatchException("Unsupported type conversion: %r to %r" % (sub.typ, self.context.return_type), self.stmt.value)
diff --git a/vyper/utils.py b/vyper/utils.py
--- a/vyper/utils.py
+++ b/vyper/utils.py
@@ -141,14 +141,17 @@ def in_bounds(cls, type_str, value):
 valid_global_keywords = ['public', 'modifying', 'event'] + valid_units + valid_call_keywords
 
 # Cannot be used for variable or member naming
-reserved_words = ['int128', 'int256', 'uint256', 'address', 'bytes32',
-                  'if', 'for', 'while', 'until',
-                  'pass', 'def', 'push', 'dup', 'swap', 'send', 'call',
-                  'selfdestruct', 'assert', 'stop', 'throw',
-                  'raise', 'init', '_init_', '___init___', '____init____',
-                  'true', 'false', 'self', 'this', 'continue', 'ether',
-                  'wei', 'finney', 'szabo', 'shannon', 'lovelace', 'ada',
-                  'babbage', 'gwei', 'kwei', 'mwei', 'twei', 'pwei', 'contract', 'units']
+reserved_words = [
+    'int128', 'int256', 'uint256', 'address', 'bytes32',
+    'if', 'for', 'while', 'until',
+    'pass', 'def', 'push', 'dup', 'swap', 'send', 'call',
+    'selfdestruct', 'assert', 'stop', 'throw',
+    'raise', 'init', '_init_', '___init___', '____init____',
+    'true', 'false', 'self', 'this', 'continue',
+    'ether', 'wei', 'finney', 'szabo', 'shannon', 'lovelace', 'ada', 'babbage', 'gwei', 'kwei', 'mwei', 'twei', 'pwei', 'contract',
+    'units',
+    'zero_address', 'max_int128', 'min_int128', 'max_decimal', 'min_decimal', 'max_uint256',  # constants
+]
 
 
 # Is a variable or member variable name valid?


Test patch:
diff --git a/tests/parser/types/numbers/test_constants.py b/tests/parser/types/numbers/test_constants.py
--- a/tests/parser/types/numbers/test_constants.py
+++ b/tests/parser/types/numbers/test_constants.py
@@ -44,3 +44,12 @@ def test_arithmetic(a: int128) -> int128:
     assert c.test_uint256(2**256 - 1) is True
 
     assert c.test_arithmetic(5000) == 2**127 - 1 - 5000
+
+
+def test_reserved_keyword(get_contract, assert_compile_failed):
+    code = """
+@public
+def test():
+    ZERO_ADDRESS: address
+    """
+    assert_compile_failed(lambda: get_contract(code))
diff --git a/tests/parser/types/numbers/test_int128.py b/tests/parser/types/numbers/test_int128.py
--- a/tests/parser/types/numbers/test_int128.py
+++ b/tests/parser/types/numbers/test_int128.py
@@ -209,3 +209,26 @@ def num_pow(a: int128, b: int128) -> int128:
     assert c.num_pow(-2, 127) == (-2**127)
     assert c.num_pow(2, 126) == (2**126)
     assert_tx_failed(lambda: c.num_pow(2**126, 2))
+
+
+def test_literal_int_division(get_contract):
+    code = """
+@public
+def foo() -> int128:
+    z: int128 = 5 / 2
+    return z
+    """
+
+    c = get_contract(code)
+
+    assert c.foo() == 2
+
+
+def test_literal_int_division_return(get_contract, assert_compile_failed):
+    code = """
+@public
+def test() -> decimal:
+    return 5 / 2
+    """
+
+    assert_compile_failed(lambda: get_contract(code))