Repository: vyperlang/vyper

Issue:
Bitwise not operator fails on literals
### Version Information

* vyper Version (output of `vyper --version`): 0.3.8+commit.a16af3d7
* OS: OSX
* Python Version (output of `python --version`): 3.8.0

### What's your issue about?

Using the bitwise not operator on an `uint256` literal leads the compiler to raise an `InvalidType` exception while the same operation on an `uint256` such that folding is not involved compiles and run without any issue.

In the following, `Contract A` compiles fine while `Contract B` fails with the given output.

`Contract A`
```Vyper
@external
def test():
    a:uint256 = 12
    b:uint256 = ~ a
```
`Contract B`
```Vyper
@external
def test():
    b:uint256 = ~ 12
```
```Bash
Error compiling: tests/customs/code.vy
Traceback (most recent call last):
  File "/Users/trocher/Documents/thesis/vyper/venv/bin/vyper", line 11, in <module>
    load_entry_point('vyper==0.3.8', 'console_scripts', 'vyper')()
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 57, in _parse_cli_args
    return _parse_args(sys.argv[1:])
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 154, in _parse_args
    compiled = compile_files(
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 294, in compile_files
    compiler_data = vyper.compile_codes(
  File "/Users/trocher/Documents/thesis/vyper/vyper/evm/opcodes.py", line 226, in _wrapper
    return fn(*args, **kwargs)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/__init__.py", line 141, in compile_codes
    exc_handler(contract_name, exc)
  File "/Users/trocher/Documents/thesis/vyper/vyper/cli/vyper_compile.py", line 189, in exc_handler
    raise exception
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/__init__.py", line 138, in compile_codes
    out[contract_name][output_format] = OUTPUT_FORMATS[output_format](compiler_data)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/output.py", line 248, in build_bytecode_output
    return f"0x{compiler_data.bytecode.hex()}"
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/functools.py", line 966, in __get__
    val = self.func(instance)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 150, in bytecode
    self.assembly, is_runtime=False, no_bytecode_metadata=self.no_bytecode_metadata
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/functools.py", line 966, in __get__
    val = self.func(instance)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 141, in assembly
    return generate_assembly(self.ir_nodes, self.no_optimize)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 126, in ir_nodes
    ir, ir_runtime, sigs = self._ir_output
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/functools.py", line 966, in __get__
    val = self.func(instance)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 122, in _ir_output
    return generate_ir_nodes(self.global_ctx, self.no_optimize)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 117, in global_ctx
    return GlobalContext(self.vyper_module_folded)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 107, in vyper_module_folded
    module, storage_layout = self._folded_module
  File "/Library/Frameworks/Python.framework/Versions/3.8/lib/python3.8/functools.py", line 966, in __get__
    val = self.func(instance)
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 101, in _folded_module
    return generate_folded_ast(
  File "/Users/trocher/Documents/thesis/vyper/vyper/compiler/phases.py", line 229, in generate_folded_ast
    validate_semantics(vyper_module_folded, interface_codes)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/__init__.py", line 13, in validate_semantics
    validate_functions(vyper_ast)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/local.py", line 63, in validate_functions
    err_list.raise_if_not_empty()
  File "/Users/trocher/Documents/thesis/vyper/vyper/exceptions.py", line 18, in raise_if_not_empty
    raise self[0]
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/local.py", line 59, in validate_functions
    FunctionNodeVisitor(vy_module, node, namespace)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/local.py", line 179, in __init__
    self.visit(node)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/local.py", line 222, in visit
    super().visit(node)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/common.py", line 20, in visit
    visitor_fn(node, *args)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/local.py", line 236, in visit_AnnAssign
    validate_expected_type(node.value, type_)
  File "/Users/trocher/Documents/thesis/vyper/vyper/semantics/analysis/utils.py", line 535, in validate_expected_type
    raise InvalidType(
vyper.exceptions.InvalidType: Expected uint256 but literal can only be cast as int104 or int96.
  contract "tests/customs/code.vy:5", function "test", line 5:16 
       4 def test():
  ---> 5     b:uint256 = ~ 12
  -----------------------^
       6
```


Discussion:

Resolving patch:
diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py
--- a/vyper/ast/nodes.py
+++ b/vyper/ast/nodes.py
@@ -937,7 +937,9 @@ class Invert(Operator):
     __slots__ = ()
     _description = "bitwise not"
     _pretty = "~"
-    _op = operator.inv
+
+    def _op(self, value):
+        return (2 ** 256 - 1) ^ value
 
 
 class BinOp(ExprNode):


Test patch:
diff --git a/tests/builtins/folding/test_bitwise.py b/tests/builtins/folding/test_bitwise.py
--- a/tests/builtins/folding/test_bitwise.py
+++ b/tests/builtins/folding/test_bitwise.py
@@ -40,9 +40,9 @@ def foo(a: uint256) -> uint256:
     """
     contract = get_contract(source)
 
-    vyper_ast = vy_ast.parse_to_ast(f"bitwise_not({value})")
+    vyper_ast = vy_ast.parse_to_ast(f"~{value}")
     old_node = vyper_ast.body[0].value
-    new_node = vy_fn.BitwiseNot().evaluate(old_node)
+    new_node = old_node.evaluate()
 
     assert contract.foo(value) == new_node.value