vyper
vyper copied to clipboard
Folding Not Supported in Certain Locations
Version Information
- vyper Version (output of
vyper --versionOR linkable commit hash vyperlang/vyper@): vyperlang/vyper@b43fface148b45cbd2c90b5d24f77398a63745b5
Issue Description
Several Vyper constructs require or can be optimized if constant values are provided. To achieve this, AST nodes can be folded to constants by the compiler, however, the following locations do not support folding:
-
lengthinslice(x, start, length)whenxismsg.dataoraddress.code:isinstance(parent.args[2], vy_ast.Int)in_validate_msg_data_attribute()isinstance(parent.args[2], vy_ast.Int)in_validate_address_code()
-
lengthinslice(x, start, length):if length_literal is not Nonecondition inSlice.fetch_call_return()
-
indexinvariable[index]when the variable is an array.isinstance(node, vy_ast.Int)in_SequenceT.validate_index_type()
-
indexinvariable[index]when the variable is a tuple.not isinstance(node, vy_ast.Int)inTupleT.validate_index_type()
-
xoryinx ** y:left, right = _get_lr()inNumericT.validate_numeric_op()
-
xinconvert(x, T)_convert._to_int(),_convert.to_decimal()and_convert._cast_bytestring()does not check ifexprhas a folded value.
-
topicinraw_log(topic, data).not isinstance(node.args[0], vy_ast.List)inRawLog.infer_arg_types()
POC
The following example demonstrates the different issues.
@external
def foo():
x: Bytes[32] = slice(msg.data, 0, 31 + 1) # StructureException
@external
def foo(tuple: (uint256,uint256)) -> uint256:
return tuple[0+1] # InvalidType
k: constant(Bytes[3]) = b'aaa'
@external
def foo():
a: Bytes[2] = convert (k, Bytes[2]) # compiles instead of failing
b: Bytes[2] = convert (b'aaa', Bytes[2]) # TypeMismatch
a: constant(uint256) = 12
@external
def foo():
# The following check is inserted by the compiler although it is not necessary
# [assert, [iszero, [shr, 128, 12 <12>]]],
b: uint128 = convert (a, uint128)
topic: constant(bytes32) = 0x1212121212121210212801291212121212121210121212121212121212121212
@external
def foo():
raw_log([[topic]][0], b'') # InvalidType
One more location to add: default values.
Example:
@external
def foo(x: int256 = 2**255-1):
does not compile with:
TypeMismatch('Expected int256 but literal can only be cast as uint256.', vyper.ast.nodes.Int:
One more location to add: default values.
Example:
@external def foo(x: int256 = 2**255-1):does not compile with:
TypeMismatch('Expected int256 but literal can only be cast as uint256.', vyper.ast.nodes.Int:
this one is expected behavior i think, since 2**255 is out of bounds of the range of int256, and compile-time safemath should match runtime safemath.
The following have been fixed in https://github.com/vyperlang/vyper/commit/75fb0594ab3011491fd124abe534573dbd9ba052:
indexinvariable[index]when the variable is an array.indexinvariable[index]when the variable is a tuple.
The x or y case in x ** y have been fixed in https://github.com/vyperlang/vyper/commit/e1adb7b3344c1ac03facfa553830a94dd7def2e2.