Skip to content

Commit

Permalink
fix[lang]: allow print() schema larger than 32 bytes (#4456)
Browse files Browse the repository at this point in the history
historically, the schema generated internally by the `print()` builtin
was not allowed to be larger than 32 bytes, ostensibly to simplify the
code for generating the IR, leading to a panic if the user tried to
print a sufficiently complex type (i.e. with an ABI type larger than
32 bytes).

this commit replaces the code for generating the schema in IR with
`Expr._make_bytelike` (along with a small refactor for `_make_bytelike`
to make it a classmethod instead of an instance method), generalizing
to schemas of any size.
  • Loading branch information
charles-cooper authored Feb 19, 2025
1 parent 8da4e6f commit 9e396fb
Show file tree
Hide file tree
Showing 2 changed files with 9 additions and 15 deletions.
13 changes: 3 additions & 10 deletions vyper/builtins/functions.py
Original file line number Diff line number Diff line change
Expand Up @@ -2293,19 +2293,12 @@ def build_IR(self, expr, args, kwargs, context):

else:
method_id = method_id_int("log(string,bytes)")
schema = args_abi_t.selector_name().encode("utf-8")
if len(schema) > 32:
raise CompilerPanic(f"print signature too long: {schema}")

schema = args_abi_t.selector_name().encode("utf-8")
schema_t = StringT(len(schema))
schema_buf = context.new_internal_variable(schema_t)
ret = ["seq"]
ret.append(["mstore", schema_buf, len(schema)])
schema_buf = Expr._make_bytelike(context, StringT, schema)

# TODO use Expr.make_bytelike, or better have a `bytestring` IRnode type
ret.append(
["mstore", add_ofst(schema_buf, 32), bytes_to_int(schema.ljust(32, b"\x00"))]
)
ret = ["seq"]

payload_buflen = args_abi_t.size_bound()
payload_t = BytesT(payload_buflen)
Expand Down
11 changes: 6 additions & 5 deletions vyper/codegen/expr.py
Original file line number Diff line number Diff line change
Expand Up @@ -130,21 +130,22 @@ def parse_Hex(self):
# String literals
def parse_Str(self):
bytez = self.expr.value.encode("utf-8")
return self._make_bytelike(StringT, bytez)
return self._make_bytelike(self.context, StringT, bytez)

# Byte literals
def parse_Bytes(self):
return self._make_bytelike(BytesT, self.expr.value)
return self._make_bytelike(self.context, BytesT, self.expr.value)

def parse_HexBytes(self):
# HexBytes already has value as bytes
assert isinstance(self.expr.value, bytes)
return self._make_bytelike(BytesT, self.expr.value)
return self._make_bytelike(self.context, BytesT, self.expr.value)

def _make_bytelike(self, typeclass, bytez):
@classmethod
def _make_bytelike(cls, context, typeclass, bytez):
bytez_length = len(bytez)
btype = typeclass(bytez_length)
placeholder = self.context.new_internal_variable(btype)
placeholder = context.new_internal_variable(btype)
seq = []
seq.append(["mstore", placeholder, bytez_length])
for i in range(0, len(bytez), 32):
Expand Down

0 comments on commit 9e396fb

Please sign in to comment.