def types_from_Compare(self, node): # comparison: `x < y` if isinstance(node.op, vy_ast.In): # x in y left = self.get_possible_types_from_node(node.left) right = self.get_possible_types_from_node(node.right) if next((i for i in left if isinstance(i, ArrayDefinition)), False): raise InvalidOperation( "Left operand in membership comparison cannot be Array type", node.left, ) if next((i for i in right if not isinstance(i, ArrayDefinition)), False): raise InvalidOperation( "Right operand must be Array for membership comparison", node.right) types_list = [ i for i in left if _is_type_in_list(i, [i.value_type for i in right]) ] if not types_list: raise TypeMismatch( "Cannot perform membership comparison between dislike types", node) else: types_list = get_common_types(node.left, node.right) _validate_op(node, types_list, "validate_comparator") return [BoolDefinition()]
def validate_numeric_op( self, node: Union[vy_ast.UnaryOp, vy_ast.BinOp, vy_ast.AugAssign]) -> None: if self._invalid_op and isinstance(node.op, self._invalid_op): raise InvalidOperation( f"Cannot perform {node.op.description} on {self}", node) if isinstance(node.op, vy_ast.Pow): if isinstance(node, vy_ast.BinOp): left, right = node.left, node.right elif isinstance(node, vy_ast.AugAssign): left, right = node.target, node.value else: raise CompilerPanic( f"Unexpected node type for numeric op: {type(node).__name__}" ) value_bits = self._bits - (1 if self._is_signed else 0) # constant folding ensures one of `(left, right)` is never a literal if isinstance(left, vy_ast.Int): if left.value >= 2**value_bits: raise OverflowException( "Base is too large, calculation will always overflow", left) elif left.value < -(2**value_bits): raise OverflowException( "Base is too small, calculation will always underflow", left) elif isinstance(right, vy_ast.Int): if right.value < 0: raise InvalidOperation("Cannot calculate a negative power", right) if right.value > value_bits: raise OverflowException( "Power is too large, calculation will always overflow", right) else: msg = ( "Cannot apply an overflow check on exponentiation when both " "the base and power are unknown at compile-time.") if not self._is_signed: msg = ( f"{msg} To perform this operation without an overflow check, use " f"`pow_mod256({left.node_source_code}, {right.node_source_code})`" ) raise InvalidOperation(msg, node)
def _op(self, left, right): if isinstance(left, decimal.Decimal): raise TypeMismatch( "Cannot perform exponentiation on decimal values.", self._parent) if right < 0: raise InvalidOperation("Cannot calculate a negative power", self._parent) return int(left**right)
def validate_boolean_op(self, node: vy_ast.BoolOp) -> None: """ Validate a boolean operation for this type. Arguments --------- node : BoolOp Vyper ast node of the boolean operation to be validated. Returns ------- None. A failed validation must raise an exception. """ raise InvalidOperation(f"Invalid type for operand: {self}", node)
def types_from_Compare(self, node): # comparisons, e.g. `x < y` # TODO fixme circular import from vyper.semantics.types.user.enum import EnumDefinition if isinstance(node.op, (vy_ast.In, vy_ast.NotIn)): # x in y left = self.get_possible_types_from_node(node.left) right = self.get_possible_types_from_node(node.right) if any(isinstance(t, EnumDefinition) for t in left): types_list = get_common_types(node.left, node.right) _validate_op(node, types_list, "validate_comparator") return [BoolDefinition()] if any(isinstance(i, ArrayDefinition) for i in left): raise InvalidOperation( "Left operand in membership comparison cannot be Array type", node.left) if any(not isinstance(i, (DynamicArrayDefinition, ArrayDefinition)) for i in right): raise InvalidOperation( "Right operand must be Array for membership comparison", node.right) types_list = [ i for i in left if _is_type_in_list(i, [i.value_type for i in right]) ] if not types_list: raise TypeMismatch( "Cannot perform membership comparison between dislike types", node) else: types_list = get_common_types(node.left, node.right) _validate_op(node, types_list, "validate_comparator") return [BoolDefinition()]
def validate_numeric_op( self, node: Union[vy_ast.UnaryOp, vy_ast.BinOp, vy_ast.AugAssign] ) -> None: """ Validate a numeric operation for this type. Arguments --------- node : UnaryOp | BinOp | AugAssign Vyper ast node of the numeric operation to be validated. Returns ------- None. A failed validation must raise an exception. """ raise InvalidOperation(f"Cannot perform {node.op.description} on {self}", node)
def validate_comparator(self, node: vy_ast.Compare) -> None: """ Validate a comparator for this type. Arguments --------- node : Compare Vyper ast node of the comparator to be validated. Returns ------- None. A failed validation must raise an exception. """ if not isinstance(node.op, (vy_ast.Eq, vy_ast.NotEq)): raise InvalidOperation( f"Cannot perform {node.op.description} comparison on {self}", node)
def _validate_op(node, types_list, validation_fn_name): if not types_list: raise TypeMismatch(f"Cannot perform {node.op.description} between dislike types", node) if len(types_list) == 1: getattr(types_list[0], validation_fn_name)(node) return types_list for type_ in types_list.copy(): try: getattr(type_, validation_fn_name)(node) except InvalidOperation: types_list.remove(type_) if types_list: return types_list raise InvalidOperation(f"Cannot perform {node.op.description} on value", node)
def validate_modification( cls, node: Union[vy_ast.Assign, vy_ast.AugAssign]) -> None: # always raises - do not implement in inherited classes raise InvalidOperation("Cannot assign to a type", node)