diff --git a/docs/types.rst b/docs/types.rst index 0ad13967e9..a8be721b1a 100644 --- a/docs/types.rst +++ b/docs/types.rst @@ -299,7 +299,7 @@ Members Member Type Description =============== =========== ========================================================================== ``balance`` ``uint256`` Balance of an address -``codehash`` ``bytes32`` Keccak of code at an address, ``EMPTY_BYTES32`` if no contract is deployed +``codehash`` ``bytes32`` Keccak of code at an address, ``0xc5d2460186f7233c927e7db2dcc703c0e500b653ca82273b7bfad8045d85a470`` if no contract is deployed (see `EIP-1052 `_) ``codesize`` ``uint256`` Size of code deployed at an address, in bytes ``is_contract`` ``bool`` Boolean indicating if a contract is deployed at an address ``code`` ``Bytes`` Contract bytecode diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index d1687bfc29..1b5934d41f 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -74,19 +74,17 @@ def __init__(self, node, context): self.context = context if isinstance(node, IRnode): - # TODO this seems bad + # this is a kludge for parse_AugAssign to pass in IRnodes + # directly. + # TODO fixme! self.ir_node = node return - fn = getattr(self, f"parse_{type(node).__name__}", None) - if fn is None: - raise TypeCheckFailure(f"Invalid statement node: {type(node).__name__}", node) - - with tag_exceptions(node, fallback_exception_type=CodegenPanic): + fn_name = f"parse_{type(node).__name__}" + with tag_exceptions(node, fallback_exception_type=CodegenPanic, note=fn_name): + fn = getattr(self, fn_name) self.ir_node = fn() - - if self.ir_node is None: - raise TypeCheckFailure(f"{type(node).__name__} node did not produce IR.\n", node) + assert isinstance(self.ir_node, IRnode), self.ir_node self.ir_node.annotation = self.expr.get("node_source_code") self.ir_node.source_pos = getpos(self.expr) @@ -363,9 +361,9 @@ def parse_Subscript(self): index = self.expr.slice.value.n # note: this check should also happen in get_element_ptr if not 0 <= index < len(sub.typ.member_types): - return + raise TypeCheckFailure("unreachable") else: - return + raise TypeCheckFailure("unreachable") ir_node = get_element_ptr(sub, index) ir_node.mutable = sub.mutable @@ -400,13 +398,13 @@ def parse_BinOp(self): new_typ = left.typ if new_typ.bits != 256: # TODO implement me. ["and", 2**bits - 1, shl(right, left)] - return + raise TypeCheckFailure("unreachable") return IRnode.from_list(shl(right, left), typ=new_typ) if isinstance(self.expr.op, vy_ast.RShift): new_typ = left.typ if new_typ.bits != 256: # TODO implement me. promote_signed_int(op(right, left), bits) - return + raise TypeCheckFailure("unreachable") op = shr if not left.typ.is_signed else sar return IRnode.from_list(op(right, left), typ=new_typ) @@ -449,7 +447,7 @@ def build_in_comparator(self): elif isinstance(self.expr.op, vy_ast.NotIn): found, not_found = 0, 1 else: # pragma: no cover - return + raise TypeCheckFailure("unreachable") i = IRnode.from_list(self.context.fresh_varname("in_ix"), typ=UINT256_T) @@ -511,7 +509,7 @@ def parse_Compare(self): right = Expr.parse_value_expr(self.expr.right, self.context) if right.value is None: - return + raise TypeCheckFailure("unreachable") if isinstance(self.expr.op, (vy_ast.In, vy_ast.NotIn)): if is_array_like(right.typ): @@ -563,7 +561,7 @@ def parse_Compare(self): elif left.typ._is_prim_word and right.typ._is_prim_word: if op not in ("eq", "ne"): - return + raise TypeCheckFailure("unreachable") else: # kludge to block behavior in #2638 # TODO actually implement equality for complex types diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py index 18e5c3d494..bc29a79734 100644 --- a/vyper/codegen/stmt.py +++ b/vyper/codegen/stmt.py @@ -40,16 +40,14 @@ class Stmt: def __init__(self, node: vy_ast.VyperNode, context: Context) -> None: self.stmt = node self.context = context - fn = getattr(self, f"parse_{type(node).__name__}", None) - if fn is None: - raise TypeCheckFailure(f"Invalid statement node: {type(node).__name__}") - with context.internal_memory_scope(): - with tag_exceptions(node, fallback_exception_type=CodegenPanic): + fn_name = f"parse_{type(node).__name__}" + with tag_exceptions(node, fallback_exception_type=CodegenPanic, note=fn_name): + fn = getattr(self, fn_name) + with context.internal_memory_scope(): self.ir_node = fn() - if self.ir_node is None: - raise TypeCheckFailure("Statement node did not produce IR") + assert isinstance(self.ir_node, IRnode), self.ir_node self.ir_node.annotation = self.stmt.get("node_source_code") self.ir_node.source_pos = getpos(self.stmt) @@ -347,7 +345,7 @@ def parse_AugAssign(self): # because of this check, we do not need to check for # make_setter references lhs<->rhs as in parse_Assign - # single word load/stores are atomic. - return + raise TypeCheckFailure("unreachable") with target.cache_when_complex("_loc") as (b, target): rhs = Expr.parse_value_expr( diff --git a/vyper/exceptions.py b/vyper/exceptions.py index 8921814188..f216069eab 100644 --- a/vyper/exceptions.py +++ b/vyper/exceptions.py @@ -359,14 +359,17 @@ class InvalidABIType(VyperInternalException): @contextlib.contextmanager -def tag_exceptions( - node, fallback_exception_type=CompilerPanic, fallback_message="unhandled exception" -): +def tag_exceptions(node, fallback_exception_type=CompilerPanic, note=None): try: yield except _BaseVyperException as e: if not e.annotations and not e.lineno: - raise e.with_annotation(node) from None + tb = e.__traceback__ + raise e.with_annotation(node).with_traceback(tb) raise e from None except Exception as e: - raise fallback_exception_type(fallback_message, node) from e + tb = e.__traceback__ + fallback_message = "unhandled exception" + if note: + fallback_message += f", {note}" + raise fallback_exception_type(fallback_message, node).with_traceback(tb)