diff --git a/tests/parser/types/test_node_types.py b/tests/parser/types/test_node_types.py index c614085c359..d20a7b05653 100644 --- a/tests/parser/types/test_node_types.py +++ b/tests/parser/types/test_node_types.py @@ -7,7 +7,6 @@ ByteArrayType, ListType, MappingType, - NullType, StructType, TupleType, canonicalize_type, @@ -15,13 +14,6 @@ ) -def test_null_type(): - node1 = NullType() - node2 = NullType() - - assert node1 == node2 - - def test_bytearray_node_type(): node1 = ByteArrayType(12) diff --git a/vyper/functions/functions.py b/vyper/functions/functions.py index 12f1f2cedd4..5e8d95f252e 100644 --- a/vyper/functions/functions.py +++ b/vyper/functions/functions.py @@ -33,7 +33,6 @@ ByteArrayLike, ByteArrayType, ListType, - NullType, StringType, TupleType, are_units_compatible, @@ -1260,8 +1259,8 @@ def sqrt(expr, args, kwargs, context): def clear(expr, context): if len(expr.args) != 1: raise ParserException('function expects two parameters.', expr) - output_type = context.parse_type(expr.args[0], expr.args[0].value.id) - return LLLnode(None, typ=NullType(output_type), pos=getpos(expr)) + output_type = context.parse_type(expr.args[0], expr.args[0]) + return LLLnode(None, typ=output_type, pos=getpos(expr)) dispatch_table = { diff --git a/vyper/parser/expr.py b/vyper/parser/expr.py index 93ec4879854..374a1fd98d0 100644 --- a/vyper/parser/expr.py +++ b/vyper/parser/expr.py @@ -34,7 +34,6 @@ ContractType, ListType, MappingType, - NullType, StringType, StructType, TupleType, @@ -755,7 +754,7 @@ def compare(self): left = Expr.parse_value_expr(self.expr.left, self.context) right = Expr.parse_value_expr(self.expr.comparators[0], self.context) - if isinstance(right.typ, NullType): + if right.value is None: raise InvalidLiteralException( 'Comparison to None is not allowed, compare against a default value.', self.expr, diff --git a/vyper/parser/lll_node.py b/vyper/parser/lll_node.py index 5344a978e10..85451efdacb 100644 --- a/vyper/parser/lll_node.py +++ b/vyper/parser/lll_node.py @@ -12,7 +12,6 @@ from vyper.types import ( BaseType, NodeType, - NullType, ceil32, ) from vyper.utils import ( @@ -213,7 +212,8 @@ def __init__(self, self.gas = sum([arg.gas for arg in self.args]) + 30 if self.value == 'if_unchecked': self.gas = self.args[0].gas + self.args[1].gas + 17 - elif self.value is None and isinstance(self.typ, NullType): + elif self.value is None: + # TODO revisit this self.valency = 1 self.gas = 5 else: diff --git a/vyper/parser/parser_utils.py b/vyper/parser/parser_utils.py index aebf077e42b..f5168d10cd5 100644 --- a/vyper/parser/parser_utils.py +++ b/vyper/parser/parser_utils.py @@ -23,7 +23,6 @@ ByteArrayType, ListType, MappingType, - NullType, StringType, StructType, TupleLike, @@ -86,7 +85,7 @@ def get_original_if_0_prefixed(expr, context): # Copies byte array def make_byte_array_copier(destination, source, pos=None): - if not isinstance(source.typ, (ByteArrayLike, NullType)): + if not isinstance(source.typ, ByteArrayLike): btype = 'byte array' if isinstance(destination.typ, ByteArrayType) else 'string' raise TypeMismatchException(f"Can only set a {btype} to another {btype}", pos) if isinstance(source.typ, ByteArrayLike) and source.typ.maxlen > destination.typ.maxlen: @@ -107,7 +106,7 @@ def make_byte_array_copier(destination, source, pos=None): pos_node = LLLnode.from_list('_pos', typ=source.typ, location=source.location) # Get the length - if isinstance(source.typ, NullType): + if source.value is None: length = 1 elif source.location == "memory": length = ['add', ['mload', '_pos'], 32] @@ -127,10 +126,10 @@ def make_byte_array_copier(destination, source, pos=None): location=destination.location, ) # Maximum theoretical length - max_length = 32 if isinstance(source.typ, NullType) else source.typ.maxlen + 32 + max_length = 32 if source.value is None else source.typ.maxlen + 32 return LLLnode.from_list([ 'with', '_pos', - 0 if isinstance(source.typ, NullType) else source, + 0 if source.value is None else source, make_byte_slice_copier(destination, pos_node, length, max_length, pos=pos) ], typ=None) @@ -152,7 +151,7 @@ def make_byte_slice_copier(destination, source, length, max_length, pos=None): ] ], typ=None, annotation=f'copy byte slice dest: {str(destination)}') # special case: rhs is zero - if isinstance(source.typ, NullType): + if source.value is None: return mzero(destination, max_length) # Copy over data if source.location == "memory": @@ -393,7 +392,7 @@ def base_type_conversion(orig, frm, to, pos, in_function_call=False): raise InvalidLiteralException( f"Function calls require explicit unit definitions on calls, expected {to}", pos ) - if not isinstance(frm, (BaseType, NullType)) or not isinstance(to, BaseType): + if not isinstance(frm, BaseType) or not isinstance(to, BaseType): raise TypeMismatchException( f"Base type conversion from or to non-base type: {frm} {to}", pos ) @@ -406,13 +405,6 @@ def base_type_conversion(orig, frm, to, pos, in_function_call=False): ['mul', orig, DECIMAL_DIVISOR], typ=BaseType('decimal', to.unit, to.positional), ) - elif isinstance(frm, NullType): - if to.typ not in ('int128', 'bool', 'uint256', 'address', 'bytes32', 'decimal'): - # This is only to future proof the use of base_type_conversion. - raise TypeMismatchException( # pragma: no cover - f"Cannot convert null-type object to type {to}", pos - ) - return LLLnode.from_list(0, typ=to) # Integer literal conversion. elif (frm.typ, to.typ, frm.is_literal) == ('int128', 'uint256', True): return LLLnode(orig.value, orig.args, typ=to, add_gas_estimate=orig.add_gas_estimate) @@ -522,9 +514,6 @@ def pack_arguments(signature, args, context, stmt_expr, return_placeholder=True) # Create an x=y statement, where the types may be compound def make_setter(left, right, location, pos, in_function_call=False): - if isinstance(right.typ, NullType): - if right.typ.typ is not None and right.typ.typ != left.typ: - raise TypeMismatchException('attempt to clear {left.typ} but provided {right.typ.typ}') # Basic types if isinstance(left.typ, BaseType): right = base_type_conversion( @@ -542,6 +531,8 @@ def make_setter(left, right, location, pos, in_function_call=False): f"Number out of range for {left.typ}: {right.value}", pos ) + if right.value is None: + right.value = 0 if location == 'storage': return LLLnode.from_list(['sstore', left, right], typ=None) elif location == 'memory': @@ -557,20 +548,14 @@ def make_setter(left, right, location, pos, in_function_call=False): # Cannot do something like [a, b, c] = [1, 2, 3] if left.value == "multi": raise Exception("Target of set statement must be a single item") - if not isinstance(right.typ, (ListType, NullType)): + if not isinstance(right.typ, ListType): raise TypeMismatchException( - f"Setter type mismatch: left side is array, right side is {right.typ}", pos + f"Setter type mismatch: left side is {left.typ}, right side is {right.typ}", pos ) left_token = LLLnode.from_list('_L', typ=left.typ, location=left.location) if left.location == "storage": left = LLLnode.from_list(['sha3_32', left], typ=left.typ, location="storage_prehashed") left_token.location = "storage_prehashed" - # Type checks - if not isinstance(right.typ, NullType): - if not isinstance(right.typ, ListType): - raise TypeMismatchException("Left side is array, right side is not", pos) - if left.typ.count != right.typ.count: - raise TypeMismatchException("Mismatched number of elements", pos) # If the right side is a literal if right.value == "multi": if len(right.args) != left.typ.count: @@ -584,7 +569,7 @@ def make_setter(left, right, location, pos, in_function_call=False): array_bounds_check=False, ), right.args[i], location, pos=pos)) return LLLnode.from_list(['with', '_L', left, ['seq'] + subs], typ=None) - elif isinstance(right.typ, NullType): + elif right.value is None: if left.location == 'memory': return mzero(left, get_size_of_type(left.typ)) @@ -595,7 +580,7 @@ def make_setter(left, right, location, pos, in_function_call=False): LLLnode.from_list(i, typ='int128'), pos=pos, array_bounds_check=False, - ), LLLnode.from_list(None, typ=NullType(left.typ)), location, pos=pos)) + ), LLLnode.from_list(None, typ=left.typ.subtype), location, pos=pos)) return LLLnode.from_list(['with', '_L', left, ['seq'] + subs], typ=None) # If the right side is a variable else: @@ -621,7 +606,7 @@ def make_setter(left, right, location, pos, in_function_call=False): elif isinstance(left.typ, (StructType, TupleType)): if left.value == "multi" and isinstance(left.typ, StructType): raise Exception("Target of set statement must be a single item") - if not isinstance(right.typ, NullType): + if right.value is not None: if not isinstance(right.typ, left.typ.__class__): raise TypeMismatchException( f"Setter type mismatch: left side is {left.typ}, right side is {right.typ}", @@ -630,6 +615,7 @@ def make_setter(left, right, location, pos, in_function_call=False): if isinstance(left.typ, StructType): for k in right.args: if k.value is None: + raise CompilerPanic("Unreachable", pos) raise InvalidLiteralException( 'Setting struct value to None is not allowed, use a default value.', pos, @@ -685,15 +671,15 @@ def make_setter(left, right, location, pos, in_function_call=False): )) return LLLnode.from_list(['with', '_L', left, ['seq'] + subs], typ=None) # If the right side is a null - elif isinstance(right.typ, NullType): + elif right.value is None: if left.location == 'memory': return mzero(left, get_size_of_type(left.typ)) subs = [] - for typ, loc in zip(keyz, locations): + for key, loc in zip(keyz, locations): subs.append(make_setter( - add_variable_offset(left_token, typ, pos=pos), - LLLnode.from_list(None, typ=NullType(typ)), + add_variable_offset(left_token, key, pos=pos), + LLLnode.from_list(None, typ=left.typ.members[key]), loc, pos=pos, )) diff --git a/vyper/parser/stmt.py b/vyper/parser/stmt.py index 52ccae5687b..491c21d8bee 100644 --- a/vyper/parser/stmt.py +++ b/vyper/parser/stmt.py @@ -46,7 +46,6 @@ ContractType, ListType, NodeType, - NullType, StructType, TupleType, get_size_of_type, @@ -127,11 +126,7 @@ def _check_valid_assign(self, sub): else: raise TypeMismatchException('Invalid type, expected: bytes32', self.stmt) elif isinstance(self.stmt.annotation, ast.Subscript): - check_typ = sub.typ - if isinstance(check_typ, NullType): - check_typ = check_typ.typ - good = isinstance(check_typ, (ListType, ByteArrayLike)) - if not good: + if not isinstance(sub.typ, (ListType, ByteArrayLike)): raise TypeMismatchException( f'Invalid type, expected: {self.stmt.annotation.value.id},' f' got: {sub.typ}', self.stmt @@ -340,11 +335,12 @@ def _clear(self): # Get target variable target = self.get_target(self.stmt.args[0]) - zero = LLLnode(None, typ=NullType(target.typ), pos=getpos(self.expr)) + pos = getpos(self.stmt) + + zero = LLLnode(None, typ=target.typ, pos=pos) # Generate LLL node to set to zero - o = make_setter(target, zero, target.location, pos=getpos(self.stmt)) - o.pos = getpos(self.stmt) + o = make_setter(target, zero, target.location, pos=pos) return o @@ -358,14 +354,14 @@ def call(self): ) and isinstance(self.stmt.func.value, ast.Name) and self.stmt.func.value.id == 'log' if isinstance(self.stmt.func, ast.Name): - if self.stmt.func.id in stmt_dispatch_table: - if self.stmt.func.id == 'clear': - return self._clear() - else: - return stmt_dispatch_table[self.stmt.func.id](self.stmt, self.context) - elif self.stmt.func.id in dispatch_table: + funcname = self.stmt.func.id + if funcname == 'clear': + return self._clear() + if funcname in stmt_dispatch_table: + return stmt_dispatch_table[funcname](self.stmt, self.context) + elif funcname in dispatch_table: raise StructureException( - f"Function {self.stmt.func.id} can not be called without being used.", + f"Function {funcname} can not be called without being used.", self.stmt, ) else: diff --git a/vyper/types/types.py b/vyper/types/types.py index 7d38a7790b0..5b255b50609 100644 --- a/vyper/types/types.py +++ b/vyper/types/types.py @@ -234,15 +234,6 @@ def tuple_items(self): return list(enumerate(self.members)) -# Sentinel type to represent zeroing operations -class NullType(NodeType): - def __init__(self, typ=None): - self.typ = typ # optional type for typechecking - - def eq(self, other): - return True - - # Convert type into common form used in ABI def canonicalize_type(t, is_indexed=False): if isinstance(t, ByteArrayLike):