-
Notifications
You must be signed in to change notification settings - Fork 0
Issue #2498 has been resolved. #1
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
base: master
Are you sure you want to change the base?
Changes from all commits
File filter
Filter by extension
Conversations
Jump to
Diff view
Diff view
There are no files selected for viewing
| Original file line number | Diff line number | Diff line change | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|---|
|
|
@@ -191,37 +191,61 @@ def build_IR(self, expr, args, kwargs, context): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| class Convert(BuiltinFunctionT): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _id = "convert" | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _try_fold(self, node): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validate_call_args(node, 2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = node.args[0].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| target_type = node.args[1].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not isinstance(target_type, vy_ast.Name): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get the target type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| target_typedef = type_from_annotation(target_type) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not isinstance(target_typedef, (BoolT, AddressT, IntegerT, BytesM_T)): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Convert the value based on target type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(target_typedef, BoolT): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, vy_ast.Int): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = bool(value.value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(value, vy_ast.Bool): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Bool.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(target_typedef, AddressT): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, vy_ast.Hex): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Hex.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(target_typedef, IntegerT): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, (vy_ast.Int, vy_ast.Decimal)): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = int(value.value) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Int.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(target_typedef, BytesM_T): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, vy_ast.Hex): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Hex.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def fetch_call_return(self, node): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _, target_typedef = self.infer_arg_types(node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # note: more type conversion validation happens in convert.py | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return target_typedef.typedef | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # TODO: push this down into convert.py for more consistency | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def infer_arg_types(self, node, expected_return_typ=None): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validate_call_args(node, 2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self._validate_arg_types(node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value_type = get_possible_types_from_node(node.args[0]).pop() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| target_type = type_from_annotation(node.args[1]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value_types = get_possible_types_from_node(node.args[0]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # For `convert` of integer literals, we need to match type inference rules in | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # convert.py codegen routines. | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # TODO: This can probably be removed once constant folding for `convert` is implemented | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if len(value_types) > 1 and all(isinstance(v, IntegerT) for v in value_types): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # Get the smallest (and unsigned if available) type for non-integer target types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # (note this is different from the ordering returned by `get_possible_types_from_node`) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not isinstance(target_type, IntegerT): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value_types = sorted(value_types, key=lambda v: (v.is_signed, v.bits), reverse=True) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # filter out the target type from list of possible types | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value_types = [i for i in value_types if not target_type.compare_type(i)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value_type = value_types.pop() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| # block conversions between same type | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if target_type.compare_type(value_type): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise InvalidType(f"Value and target type are both '{target_type}'", node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return [value_type, TYPE_T(target_type)] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
245
to
249
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more. 🛠️ Refactor suggestion Non-deterministic type selection in
Use a deterministic selection strategy, e.g. sort by priority: - value_type = get_possible_types_from_node(node.args[0]).pop()
+ possible = sorted(
+ get_possible_types_from_node(node.args[0]),
+ key=lambda t: (t.typ, getattr(t, "bits", 0)) # or any stable rule
+ )
+ value_type = possible[0]📝 Committable suggestion
Suggested change
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def build_IR(self, expr, context): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -290,6 +314,39 @@ class Slice(BuiltinFunctionT): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ("length", UINT256_T), | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| ] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _try_fold(self, node): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validate_call_args(node, 3) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = node.args[0].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start = node.args[1].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| length = node.args[2].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not isinstance(start, vy_ast.Int) or not isinstance(length, vy_ast.Int): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start_val = start.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| length_val = length.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if length_val < 1: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ArgumentException("Length cannot be less than 1", node.args[2]) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, vy_ast.Bytes): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if start_val + length_val > len(value.value): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ArgumentException("slice out of bounds", node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.value[start_val:start_val + length_val] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Bytes.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(value, vy_ast.Str): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if start_val + length_val > len(value.value): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ArgumentException("slice out of bounds", node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.value[start_val:start_val + length_val] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Str.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(value, vy_ast.Hex): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if start_val + length_val > len(value.bytes_value): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ArgumentException("slice out of bounds", node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.bytes_value[start_val:start_val + length_val] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Bytes.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def fetch_call_return(self, node): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| arg_type, _, _ = self.infer_arg_types(node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
@@ -833,6 +890,29 @@ class Extract32(BuiltinFunctionT): | |||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _inputs = [("b", BytesT.any()), ("start", IntegerT.unsigneds())] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| _kwargs = {"output_type": KwargSettings(TYPE_T.any(), BYTES32_T)} | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def _try_fold(self, node): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| validate_call_args(node, 2) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| value = node.args[0].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start = node.args[1].get_folded_value() | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if not isinstance(start, vy_ast.Int): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| start_val = start.value | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if isinstance(value, vy_ast.Bytes): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if start_val + 32 > len(value.value): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ArgumentException("extract32 out of bounds", node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.value[start_val:start_val + 32] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Bytes.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| elif isinstance(value, vy_ast.Hex): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| if start_val + 32 > len(value.bytes_value): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise ArgumentException("extract32 out of bounds", node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| result = value.bytes_value[start_val:start_val + 32] | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return vy_ast.Bytes.from_node(node, value=result) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| else: | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| raise UnfoldableNode | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
Comment on lines
+893
to
+915
There was a problem hiding this comment. Choose a reason for hiding this commentThe reason will be displayed to describe this comment to others. Learn more.
Issues:
@@
- result = value.value[start_val:start_val + 32]
- return vy_ast.Bytes.from_node(node, value=result)
+ result = value.value[start_val : start_val + 32]
+
+ out_typedef = self.infer_kwarg_types(node)["output_type"].typedef
+
+ if isinstance(out_typedef, BytesM_T):
+ return vy_ast.Hex.from_node(node, value=result.hex())
+ elif isinstance(out_typedef, IntegerT):
+ return vy_ast.Int.from_node(node, value=int.from_bytes(result, "big"))
+ elif isinstance(out_typedef, AddressT):
+ return vy_ast.Hex.from_node(node, value="0x" + result.hex())
+ else:
+ raise CompilerPanic("Unhandled output_type in extract32 folding")Failing to honour
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| def fetch_call_return(self, node): | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| self._validate_arg_types(node) | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| return_type = self.infer_kwarg_types(node)["output_type"].typedef | ||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
|
|
||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
🛠️ Refactor suggestion
Constant-folded
convert()skips range / size validation – can emit ill-typed literals at compile timeThe new folding branch happily constructs the target literal without any of the safety checks that the runtime implementation performs:
IntegerTtargets noast_bounds(min / max) verification is done, soconvert(2**300, int128)would now be folded into an out-of-rangevy_ast.Intwhich later passes type-checking because its value has already been frozen.AddressTthe hex literal length is not verified (should be exactly 20 bytes / 40 hex chars).BytesM_Tthe produced literal is not checked againsttarget_typedef.length.DecimalT → IntegerTtruncates without a bounds check or aZeroDivisionException- style guard used elsewhere.This opens a correctness hole: an invalid literal is accepted during folding and only surfaces at execution, bypassing compile-time guarantees.
Similar guards are needed for the
AddressTandBytesM_Tbranches.📝 Committable suggestion