Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Folding Not Supported in Certain Locations #4190

Open
ritzdorf opened this issue Apr 25, 2024 · 2 comments
Open

Folding Not Supported in Certain Locations #4190

ritzdorf opened this issue Apr 25, 2024 · 2 comments

Comments

@ritzdorf
Copy link
Contributor

Version Information

  • vyper Version (output of vyper --version OR linkable commit hash vyperlang/vyper@): b43ffac

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:

  • length in slice(x, start, length) when x is msg.data or
    address.code:

    • isinstance(parent.args[2], vy_ast.Int) in
      _validate_msg_data_attribute()
    • isinstance(parent.args[2], vy_ast.Int) in
      _validate_address_code()
  • length in slice(x, start, length):

    • if length_literal is not None condition in
      Slice.fetch_call_return()
  • index in variable[index] when the variable is an array.

    • isinstance(node, vy_ast.Int) in
      _SequenceT.validate_index_type()
  • index in variable[index] when the variable is a tuple.

    • not isinstance(node, vy_ast.Int) in
      TupleT.validate_index_type()
  • x or y in x ** y:

    • left, right = _get_lr() in NumericT.validate_numeric_op()
  • x in convert(x, T)

    • _convert._to_int(), _convert.to_decimal() and
      _convert._cast_bytestring() does not check if expr has a
      folded value.
  • topic in raw_log(topic, data) .

    • not isinstance(node.args[0], vy_ast.List) in
      RawLog.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
@ritzdorf
Copy link
Contributor Author

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:

@cyberthirst cyberthirst transferred this issue from another repository Jul 16, 2024
@charles-cooper
Copy link
Member

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.

@cyberthirst cyberthirst transferred this issue from another repository Jul 29, 2024
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Projects
None yet
Development

No branches or pull requests

2 participants