def types_from_Compare(self, node): # comparison: `x < y` 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 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 visit_If(self, node): validate_expected_type(node.test, BoolDefinition()) with self.namespace.enter_scope(): for n in node.body: self.visit(n) with self.namespace.enter_scope(): for n in node.orelse: self.visit(n)
def visit_Assert(self, node): if node.msg: _validate_revert_reason(node.msg) try: validate_expected_type(node.test, BoolDefinition()) except InvalidType: raise InvalidType("Assertion test value must be a boolean", node.test)
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 __init__( self, name: str, arguments: OrderedDict, # TODO rename to something like positional_args, keyword_args min_arg_count: int, max_arg_count: int, return_type: Optional[BaseTypeDefinition], function_visibility: FunctionVisibility, state_mutability: StateMutability, nonreentrant: Optional[str] = None, ) -> None: super().__init__( # A function definition type only exists while compiling DataLocation.UNSET, # A function definition type is immutable once created is_constant=True, # A function definition type is public if it's visibility is public is_public=(function_visibility == FunctionVisibility.EXTERNAL), ) self.name = name self.arguments = arguments self.min_arg_count = min_arg_count self.max_arg_count = max_arg_count self.return_type = return_type self.kwarg_keys = [] if min_arg_count < max_arg_count: self.kwarg_keys = list(self.arguments)[min_arg_count:] self.visibility = function_visibility self.mutability = state_mutability self.nonreentrant = nonreentrant # a list of internal functions this function calls self.called_functions: Set["ContractFunction"] = set() # special kwargs that are allowed in call site self.call_site_kwargs = { "gas": KwargSettings(Uint256Definition(), "gas"), "value": KwargSettings(Uint256Definition(), 0), "skip_contract_check": KwargSettings(BoolDefinition(), False, require_literal=True), "default_return_value": KwargSettings(return_type, None), }
def fetch_call_return(self, node: vy_ast.Call) -> Optional[BaseTypeDefinition]: if node.get( "func.value.id" ) == "self" and self.visibility == FunctionVisibility.EXTERNAL: raise CallViolation("Cannnot call external functions via 'self'", node) # for external calls, include gas and value as optional kwargs kwarg_keys = self.kwarg_keys.copy() if node.get("func.value.id") != "self": kwarg_keys += ["gas", "value", "skip_contract_check"] validate_call_args(node, (self.min_arg_count, self.max_arg_count), kwarg_keys) if self.mutability < StateMutability.PAYABLE: kwarg_node = next((k for k in node.keywords if k.arg == "value"), None) if kwarg_node is not None: raise CallViolation( "Cannnot send ether to nonpayable function", kwarg_node) for arg, expected in zip(node.args, self.arguments.values()): validate_expected_type(arg, expected) for kwarg in node.keywords: if kwarg.arg in ("gas", "value"): validate_expected_type(kwarg.value, Uint256Definition()) elif kwarg.arg in ("skip_contract_check"): validate_expected_type(kwarg.value, BoolDefinition()) if not isinstance(kwarg.value, vy_ast.NameConstant): raise InvalidType( "skip_contract_check must be literal bool", kwarg.value) else: validate_expected_type(kwarg.arg, kwarg.value) return self.return_type
def types_from_BoolOp(self, node): # boolean operation: `x and y` types_list = get_common_types(*node.values) _validate_op(node, types_list, "validate_boolean_op") return [BoolDefinition()]