diff --git a/tests/functional/syntax/test_as_wei_value.py b/tests/functional/syntax/test_as_wei_value.py index fd5f9e20ba..4ed3f0a224 100644 --- a/tests/functional/syntax/test_as_wei_value.py +++ b/tests/functional/syntax/test_as_wei_value.py @@ -61,6 +61,24 @@ def foo(): """, InvalidLiteral, ), + ( + """ +FOO: constant(uint256) = as_wei_value(5, szabo) + """, + ArgumentException, + ), + ( + """ +FOO: constant(uint256) = as_wei_value(5, "szaboo") + """, + ArgumentException, + ), + ( + """ +FOO: constant(uint256) = as_wei_value(-1, "szabo") + """, + InvalidLiteral, + ), ] diff --git a/tests/functional/syntax/test_epsilon.py b/tests/functional/syntax/test_epsilon.py new file mode 100644 index 0000000000..73369d4b8a --- /dev/null +++ b/tests/functional/syntax/test_epsilon.py @@ -0,0 +1,14 @@ +import pytest + +from vyper.exceptions import InvalidType + +fail_list = [ + """ +FOO: constant(address) = epsilon(address) + """ +] + + +@pytest.mark.parametrize("bad_code", fail_list) +def test_block_fail(assert_compile_failed, get_contract_with_gas_estimation, bad_code): + assert_compile_failed(lambda: get_contract_with_gas_estimation(bad_code), InvalidType) diff --git a/tests/functional/syntax/test_method_id.py b/tests/functional/syntax/test_method_id.py index 1a59f6bd6e..da67e67fe3 100644 --- a/tests/functional/syntax/test_method_id.py +++ b/tests/functional/syntax/test_method_id.py @@ -1,7 +1,7 @@ import pytest from vyper import compiler -from vyper.exceptions import InvalidLiteral +from vyper.exceptions import InvalidLiteral, InvalidType fail_list = [ ( @@ -11,7 +11,19 @@ def foo(): a: Bytes[4] = method_id("bar ()") """, InvalidLiteral, - ) + ), + ( + """ +FOO: constant(Bytes[4]) = method_id(1) + """, + InvalidType, + ), + ( + """ +FOO: constant(Bytes[4]) = method_id("bar ()") + """, + InvalidLiteral, + ), ] diff --git a/tests/functional/syntax/test_minmax_value.py b/tests/functional/syntax/test_minmax_value.py index e154cad23f..14b61e2f0a 100644 --- a/tests/functional/syntax/test_minmax_value.py +++ b/tests/functional/syntax/test_minmax_value.py @@ -13,6 +13,9 @@ def foo(): def foo(): a: address = max_value(address) """, + """ +FOO: constant(address) = min_value(address) + """, ] diff --git a/vyper/builtins/functions.py b/vyper/builtins/functions.py index 2aea650ea0..9106c0def1 100644 --- a/vyper/builtins/functions.py +++ b/vyper/builtins/functions.py @@ -742,6 +742,11 @@ def fetch_call_return(self, node): type_ = self.infer_kwarg_types(node)["output_type"].typedef return type_ + def infer_arg_types(self, node, expected_return_typ=None): + # call `evaluate` for its typechecking side effects + self.evaluate(node) + return [self._inputs[0][1]] + def infer_kwarg_types(self, node): # If `output_type` is not given, default to `Bytes[4]` output_typedef = TYPE_T(BytesT(4)) @@ -977,16 +982,12 @@ class AsWeiValue(BuiltinFunction): ("kether", "grand"): 10**21, } - def _get_denomination_node(self, node): + def get_denomination(self, node): value = node.args[1]._metadata.get("folded_value") if not isinstance(value, vy_ast.Str): raise ArgumentException( "Wei denomination must be given as a literal string", node.args[1] ) - return value - - def get_denomination(self, node): - value = self._get_denomination_node(node) try: denom = next(v for k, v in self.wei_denoms.items() if value.value in k) except StopIteration: @@ -1013,9 +1014,12 @@ def fetch_call_return(self, node): return self._return_type def infer_arg_types(self, node, expected_return_typ=None): - # raise a better error message by first calling this function - # for its side effects of checking the denom - self._get_denomination_node(node) + # call `evaluate` for its typechecking side effects` + try: + self.evaluate(node) + except UnfoldableNode: + pass + self._validate_arg_types(node) # return a concrete type instead of abstract type value_type = get_possible_types_from_node(node.args[0]).pop() @@ -2585,6 +2589,12 @@ def evaluate(self, node): ret._metadata["type"] = input_type return ret + def infer_arg_types(self, node, expected_return_typ=None): + # call `evaluate` for its typechecking side effects + self.evaluate(node) + input_typedef = TYPE_T(type_from_annotation(node.args[0])) + return [input_typedef] + class MinValue(_MinMaxValue): _id = "min_value" diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index 6952bb1ee4..651c92c4aa 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -240,13 +240,13 @@ def _validate_self_namespace(): raise exc.with_annotation(node) from None if node.is_constant: + ExprVisitor().visit(node.value, type_) if not node.value: raise VariableDeclarationException("Constant must be declared with a value", node) if not check_variable_constancy(node.value, VariableConstancy.COMPILE_TIME_CONSTANT): raise StateAccessViolation("Value must be a literal", node.value) validate_expected_type(node.value, type_) - ExprVisitor().visit(node.value, type_) _validate_self_namespace() return _finalize()