From e4fb5d80d386dca9c5fa2debc3793319c18c4e8d Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Tue, 26 Dec 2023 23:50:52 +0800 Subject: [PATCH 01/13] remove folding --- vyper/codegen/expr.py | 14 +++++++++++--- vyper/compiler/phases.py | 2 +- vyper/semantics/analysis/module.py | 2 +- 3 files changed, 13 insertions(+), 5 deletions(-) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index d1687bfc29..3b463a421e 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -70,6 +70,14 @@ class Expr: # TODO: Once other refactors are made reevaluate all inline imports def __init__(self, node, context): + # use original node for better diagnostics + orig_node = node + if isinstance(node, vy_ast.VyperNode): + folded_node = node._metadata.get("folded_value") + if folded_node: + folded_node._metadata["type"] = node._metadata["type"] + node = folded_node + self.expr = node self.context = context @@ -80,13 +88,13 @@ def __init__(self, node, context): fn = getattr(self, f"parse_{type(node).__name__}", None) if fn is None: - raise TypeCheckFailure(f"Invalid statement node: {type(node).__name__}", node) + raise TypeCheckFailure(f"Invalid statement node: {type(node).__name__}", orig_node) - with tag_exceptions(node, fallback_exception_type=CodegenPanic): + with tag_exceptions(orig_node, fallback_exception_type=CodegenPanic): self.ir_node = fn() if self.ir_node is None: - raise TypeCheckFailure(f"{type(node).__name__} node did not produce IR.\n", node) + raise TypeCheckFailure(f"{type(node).__name__} node did not produce IR.\n", orig_node) self.ir_node.annotation = self.expr.get("node_source_code") self.ir_node.source_pos = getpos(self.expr) diff --git a/vyper/compiler/phases.py b/vyper/compiler/phases.py index 4982e84b68..184c60c113 100644 --- a/vyper/compiler/phases.py +++ b/vyper/compiler/phases.py @@ -280,7 +280,7 @@ def generate_folded_ast( symbol_tables = set_data_positions(vyper_module, storage_layout_overrides) vyper_module_folded = copy.deepcopy(vyper_module) - vy_ast.folding.fold(vyper_module_folded) + #vy_ast.folding.fold(vyper_module_folded) return vyper_module_folded, symbol_tables diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index ffbd2265db..fa2ac73724 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -495,7 +495,7 @@ def _parse_and_fold_ast(file: FileInput) -> vy_ast.VyperNode: resolved_path=str(file.resolved_path), ) vy_ast.validation.validate_literal_nodes(ret) - vy_ast.folding.fold(ret) + #vy_ast.folding.fold(ret) return ret From e1e557622bb771e6284eca5b032726eaccec38ce Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Wed, 27 Dec 2023 13:09:55 +0800 Subject: [PATCH 02/13] fix kwarg handling --- vyper/builtins/_signatures.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/builtins/_signatures.py b/vyper/builtins/_signatures.py index 7c8d396f3e..f955296ee0 100644 --- a/vyper/builtins/_signatures.py +++ b/vyper/builtins/_signatures.py @@ -34,7 +34,7 @@ def process_arg(arg, expected_arg_type, context): def process_kwarg(kwarg_node, kwarg_settings, expected_kwarg_type, context): if kwarg_settings.require_literal: - return kwarg_node.value + return kwarg_node.get_folded_value_throwing().value return process_arg(kwarg_node, expected_kwarg_type, context) From 3a642fbb1179f20e4bc3b110e5beb008c71ec88e Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Wed, 27 Dec 2023 15:12:39 +0800 Subject: [PATCH 03/13] fix kwargs and constant structs --- vyper/codegen/expr.py | 7 ++++ .../function_definitions/external_function.py | 40 +++++++++---------- 2 files changed, 27 insertions(+), 20 deletions(-) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index d42ba8babd..25927f1ab0 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -193,6 +193,13 @@ def parse_Name(self): # TODO: use self.expr._expr_info elif self.expr.id in self.context.globals: varinfo = self.context.globals[self.expr.id] + if varinfo.modifiability == Modifiability.ALWAYS_CONSTANT: + value_node = varinfo.decl_node.value + folded_value_node = value_node._metadata.get("folded_value") + if folded_value_node is not None: + value_node = folded_value_node + return Expr.parse_value_expr(value_node, self.context) + assert varinfo.modifiability == Modifiability.IMMUTABLE, "not an immutable!" ofst = varinfo.position.offset diff --git a/vyper/codegen/function_definitions/external_function.py b/vyper/codegen/function_definitions/external_function.py index f46aa6b2e5..f1a6a1ee1d 100644 --- a/vyper/codegen/function_definitions/external_function.py +++ b/vyper/codegen/function_definitions/external_function.py @@ -8,7 +8,7 @@ from vyper.codegen.stmt import parse_body from vyper.evm.address_space import CALLDATA, DATA, MEMORY from vyper.semantics.types import TupleT -from vyper.semantics.types.function import ContractFunctionT +from vyper.semantics.types.function import ContractFunctionT, KeywordArg, PositionalArg # register function args with the local calling context. @@ -63,12 +63,14 @@ def _generate_kwarg_handlers( # write default args to memory # goto external_function_common_ir - def handler_for(calldata_kwargs, original_default_kwargs, folded_default_kwargs): - calldata_args = func_t.positional_args + calldata_kwargs + def handler_for(calldata_kwargs_info, default_kwargs_info, default_kwargs): + calldata_args_info: list[Union[PositionalArg, KeywordArg]] = ( + func_t.positional_args + calldata_kwargs_info + ) # create a fake type so that get_element_ptr works - calldata_args_t = TupleT(list(arg.typ for arg in calldata_args)) + calldata_args_t = TupleT(list(arg.typ for arg in calldata_args_info)) - abi_sig = func_t.abi_signature_for_kwargs(calldata_kwargs) + abi_sig = func_t.abi_signature_for_kwargs(calldata_kwargs_info) calldata_kwargs_ofst = IRnode( 4, location=CALLDATA, typ=calldata_args_t, encoding=Encoding.ABI @@ -82,10 +84,10 @@ def handler_for(calldata_kwargs, original_default_kwargs, folded_default_kwargs) calldata_min_size = args_abi_t.min_size() + 4 # TODO optimize make_setter by using - # TupleT(list(arg.typ for arg in calldata_kwargs + folded_default_kwargs)) + # TupleT(list(arg.typ for arg in calldata_kwargs_info + default_kwargs_info)) # (must ensure memory area is contiguous) - for i, arg_meta in enumerate(calldata_kwargs): + for i, arg_meta in enumerate(calldata_kwargs_info): k = func_t.n_positional_args + i dst = context.lookup_var(arg_meta.name).pos @@ -98,7 +100,7 @@ def handler_for(calldata_kwargs, original_default_kwargs, folded_default_kwargs) copy_arg.source_pos = getpos(arg_meta.ast_source) ret.append(copy_arg) - for x, y in zip(original_default_kwargs, folded_default_kwargs): + for x, y in zip(default_kwargs_info, default_kwargs): dst = context.lookup_var(x.name).pos lhs = IRnode(dst, location=MEMORY, typ=x.typ) lhs.source_pos = getpos(y) @@ -116,26 +118,24 @@ def handler_for(calldata_kwargs, original_default_kwargs, folded_default_kwargs) ret = {} - keyword_args = func_t.keyword_args - folded_keyword_args = code.args.defaults + keyword_args_info = func_t.keyword_args + keyword_args = code.args.defaults - # allocate variable slots in memory - for arg in keyword_args: + # allocate keyword_args_info slots in memory + for arg in keyword_args_info: context.new_variable(arg.name, arg.typ, is_mutable=False) - for i, _ in enumerate(keyword_args): - calldata_kwargs = keyword_args[:i] - # folded ast - original_default_kwargs = keyword_args[i:] - # unfolded ast - folded_default_kwargs = folded_keyword_args[i:] + for i, _ in enumerate(keyword_args_info): + calldata_kwargs_info = keyword_args_info[:i] + default_kwargs_info: list[KeywordArg] = keyword_args_info[i:] + default_kwargs: list[vy_ast.VyperNode] = keyword_args[i:] sig, calldata_min_size, ir_node = handler_for( - calldata_kwargs, original_default_kwargs, folded_default_kwargs + calldata_kwargs_info, default_kwargs_info, default_kwargs ) ret[sig] = calldata_min_size, ir_node - sig, calldata_min_size, ir_node = handler_for(keyword_args, [], []) + sig, calldata_min_size, ir_node = handler_for(keyword_args_info, [], []) ret[sig] = calldata_min_size, ir_node From 27441ec27cff496a67001fb8f6b6e72fdd2e6170 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Wed, 27 Dec 2023 16:46:43 +0800 Subject: [PATCH 04/13] fix list codegen --- vyper/codegen/expr.py | 3 +++ 1 file changed, 3 insertions(+) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index 25927f1ab0..28de2a18be 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -720,6 +720,9 @@ def parse_List(self): if len(self.expr.elements) == 0: return IRnode.from_list("~empty", typ=typ) + for e in self.expr.elements: + if "type" not in e._metadata: + e._metadata["type"] = typ.subtype multi_ir = [Expr(x, self.context).ir_node for x in self.expr.elements] return IRnode.from_list(["multi"] + multi_ir, typ=typ) From 394c9fbf2c73e2a8d4603f3cd3ad7436a912c189 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Wed, 27 Dec 2023 17:21:57 +0800 Subject: [PATCH 05/13] uncatch vyper exception when prefolding call nodes --- vyper/semantics/analysis/pre_typecheck.py | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vyper/semantics/analysis/pre_typecheck.py b/vyper/semantics/analysis/pre_typecheck.py index 223407d839..b89c1c6759 100644 --- a/vyper/semantics/analysis/pre_typecheck.py +++ b/vyper/semantics/analysis/pre_typecheck.py @@ -1,5 +1,5 @@ from vyper import ast as vy_ast -from vyper.exceptions import UnfoldableNode, VyperException +from vyper.exceptions import UnfoldableNode def get_constants(node: vy_ast.Module) -> dict: @@ -66,7 +66,7 @@ def prefold(node: vy_ast.VyperNode, constants: dict[str, vy_ast.VyperNode]): try: node._metadata["folded_value"] = call_type.fold(node) return - except (UnfoldableNode, VyperException): + except UnfoldableNode: pass if getattr(node, "_is_prefoldable", None): From 17f01fafcb0089acae2325569d73692a265c1cd8 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 10:45:30 +0800 Subject: [PATCH 06/13] handle const, list and tuples --- vyper/ast/nodes.py | 47 ++++++++++++++++++++++++++++++- vyper/codegen/expr.py | 3 -- vyper/semantics/analysis/utils.py | 16 +---------- 3 files changed, 47 insertions(+), 19 deletions(-) diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index e4e9f37866..cc4929286e 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -777,7 +777,12 @@ class Constant(ExprNode): def __init__(self, parent: Optional["VyperNode"] = None, **kwargs: dict): super().__init__(parent, **kwargs) - self._metadata["folded_value"] = self + + def get_folded_value_throwing(self) -> "VyperNode": + return self + + def get_folded_value_maybe(self) -> Optional["VyperNode"]: + return self class Num(Constant): @@ -911,6 +916,18 @@ def s(self): return self.value +def check_literal(node: VyperNode) -> bool: + """ + Check if the given node is a literal value. + """ + if isinstance(node, Constant): + return True + elif isinstance(node, (Tuple, List)): + return all(check_literal(item) for item in node.elements) + + return False + + class List(ExprNode): __slots__ = ("elements",) _is_prefoldable = True @@ -920,6 +937,18 @@ def fold(self) -> Optional[ExprNode]: elements = [e.get_folded_value_throwing() for e in self.elements] return type(self).from_node(self, elements=elements) + def get_folded_value_throwing(self) -> "VyperNode": + if check_literal(self): + return self + + return super().get_folded_value_throwing() + + def get_folded_value_maybe(self) -> Optional["VyperNode"]: + if check_literal(self): + return self + + return super().get_folded_value_maybe() + class Tuple(ExprNode): __slots__ = ("elements",) @@ -929,6 +958,22 @@ def validate(self): if not self.elements: raise InvalidLiteral("Cannot have an empty tuple", self) + def fold(self) -> Optional[ExprNode]: + elements = [e.get_folded_value_throwing() for e in self.elements] + return type(self).from_node(self, elements=elements) + + def get_folded_value_throwing(self) -> "VyperNode": + if check_literal(self): + return self + + return super().get_folded_value_throwing() + + def get_folded_value_maybe(self) -> Optional["VyperNode"]: + if check_literal(self): + return self + + return super().get_folded_value_maybe() + class NameConstant(Constant): __slots__ = () diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index 28de2a18be..25927f1ab0 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -720,9 +720,6 @@ def parse_List(self): if len(self.expr.elements) == 0: return IRnode.from_list("~empty", typ=typ) - for e in self.expr.elements: - if "type" not in e._metadata: - e._metadata["type"] = typ.subtype multi_ir = [Expr(x, self.context).ir_node for x in self.expr.elements] return IRnode.from_list(["multi"] + multi_ir, typ=typ) diff --git a/vyper/semantics/analysis/utils.py b/vyper/semantics/analysis/utils.py index 3f91d5f258..dcf81b4d6e 100644 --- a/vyper/semantics/analysis/utils.py +++ b/vyper/semantics/analysis/utils.py @@ -624,25 +624,11 @@ def validate_unique_method_ids(functions: List) -> None: seen.add(method_id) -def _check_literal(node: vy_ast.VyperNode) -> bool: - """ - Check if the given node is a literal value. - """ - if isinstance(node, vy_ast.Constant): - return True - elif isinstance(node, (vy_ast.Tuple, vy_ast.List)): - return all(_check_literal(item) for item in node.elements) - - if node.get_folded_value_maybe(): - return True - return False - - def check_modifiability(node: vy_ast.VyperNode, modifiability: Modifiability) -> bool: """ Check if the given node is not more modifiable than the given modifiability. """ - if _check_literal(node): + if node.get_folded_value_maybe(): return True if isinstance(node, (vy_ast.BinOp, vy_ast.Compare)): From 93a9b4218cd4db82d0ebce0057270a081c913ff3 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 14:56:01 +0800 Subject: [PATCH 07/13] fix tuple --- vyper/ast/nodes.py | 1 + vyper/semantics/analysis/local.py | 10 ++++++---- 2 files changed, 7 insertions(+), 4 deletions(-) diff --git a/vyper/ast/nodes.py b/vyper/ast/nodes.py index cc4929286e..25da0714ee 100644 --- a/vyper/ast/nodes.py +++ b/vyper/ast/nodes.py @@ -952,6 +952,7 @@ def get_folded_value_maybe(self) -> Optional["VyperNode"]: class Tuple(ExprNode): __slots__ = ("elements",) + _is_prefoldable = True _translated_fields = {"elts": "elements"} def validate(self): diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 0163547d55..57a9e9afa9 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -545,13 +545,15 @@ def visit(self, node, typ): # can happen. super().visit(node, typ) - folded_value = node.get_folded_value_maybe() - if isinstance(folded_value, vy_ast.Constant): - validate_expected_type(folded_value, typ) - # annotate node._metadata["type"] = typ + # validate and annotate folded value + folded_value = node.get_folded_value_maybe() + if folded_value: + validate_expected_type(folded_value, typ) + folded_value._metadata["type"] = typ + def visit_Attribute(self, node: vy_ast.Attribute, typ: VyperType) -> None: _validate_msg_data_attribute(node) From 14d1e093d174c708e7fbd32906e67593e080780c Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:17:45 +0800 Subject: [PATCH 08/13] read folded value from metadata --- vyper/semantics/analysis/local.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 57a9e9afa9..417e9e7018 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -549,7 +549,7 @@ def visit(self, node, typ): node._metadata["type"] = typ # validate and annotate folded value - folded_value = node.get_folded_value_maybe() + folded_value = node._metadata.get("folded_value") if folded_value: validate_expected_type(folded_value, typ) folded_value._metadata["type"] = typ From 59f7d3650206d6ef9479043ff6bbef368f7511fe Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 16:53:23 +0800 Subject: [PATCH 09/13] try reverting const amendment --- vyper/codegen/expr.py | 7 ------- 1 file changed, 7 deletions(-) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index 25927f1ab0..d42ba8babd 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -193,13 +193,6 @@ def parse_Name(self): # TODO: use self.expr._expr_info elif self.expr.id in self.context.globals: varinfo = self.context.globals[self.expr.id] - if varinfo.modifiability == Modifiability.ALWAYS_CONSTANT: - value_node = varinfo.decl_node.value - folded_value_node = value_node._metadata.get("folded_value") - if folded_value_node is not None: - value_node = folded_value_node - return Expr.parse_value_expr(value_node, self.context) - assert varinfo.modifiability == Modifiability.IMMUTABLE, "not an immutable!" ofst = varinfo.position.offset From 1f57495816a54aa14b84ae60be8791235ec661c1 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:24:12 +0800 Subject: [PATCH 10/13] revert; assert struct --- vyper/codegen/expr.py | 8 ++++++++ 1 file changed, 8 insertions(+) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index d42ba8babd..a2c395631e 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -193,6 +193,14 @@ def parse_Name(self): # TODO: use self.expr._expr_info elif self.expr.id in self.context.globals: varinfo = self.context.globals[self.expr.id] + if varinfo.modifiability == Modifiability.ALWAYS_CONSTANT: + # non-struct constants should have been dispatched via the `Expr` ctor + # using the folded value metadata + assert isinstance(varinfo.typ, StructT) + value_node = varinfo.decl_node.value + value_node = value_node._metadata.get("folded_value", value_node) + return Expr.parse_value_expr(value_node, self.context) + assert varinfo.modifiability == Modifiability.IMMUTABLE, "not an immutable!" ofst = varinfo.position.offset From 13b341ba347958ab3fcc92e9c70eb916206cb0e1 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:31:49 +0800 Subject: [PATCH 11/13] clean up expr codegen ctor --- vyper/codegen/expr.py | 9 +--- .../function_definitions/external_function.py | 51 ++++++++----------- 2 files changed, 24 insertions(+), 36 deletions(-) diff --git a/vyper/codegen/expr.py b/vyper/codegen/expr.py index a2c395631e..27266577a0 100644 --- a/vyper/codegen/expr.py +++ b/vyper/codegen/expr.py @@ -70,13 +70,8 @@ class Expr: # TODO: Once other refactors are made reevaluate all inline imports def __init__(self, node, context): - # use original node for better diagnostics - orig_node = node if isinstance(node, vy_ast.VyperNode): - folded_node = node._metadata.get("folded_value") - if folded_node: - folded_node._metadata["type"] = node._metadata["type"] - node = folded_node + node = node._metadata.get("folded_value", node) self.expr = node self.context = context @@ -89,7 +84,7 @@ def __init__(self, node, context): return fn_name = f"parse_{type(node).__name__}" - with tag_exceptions(orig_node, fallback_exception_type=CodegenPanic, note=fn_name): + with tag_exceptions(node, fallback_exception_type=CodegenPanic, note=fn_name): fn = getattr(self, fn_name) self.ir_node = fn() assert isinstance(self.ir_node, IRnode), self.ir_node diff --git a/vyper/codegen/function_definitions/external_function.py b/vyper/codegen/function_definitions/external_function.py index f1a6a1ee1d..9a66708872 100644 --- a/vyper/codegen/function_definitions/external_function.py +++ b/vyper/codegen/function_definitions/external_function.py @@ -1,4 +1,3 @@ -from vyper import ast as vy_ast from vyper.codegen.abi_encoder import abi_encoding_matches_vyper from vyper.codegen.context import Context, VariableRecord from vyper.codegen.core import get_element_ptr, getpos, make_setter, needs_clamp @@ -8,7 +7,7 @@ from vyper.codegen.stmt import parse_body from vyper.evm.address_space import CALLDATA, DATA, MEMORY from vyper.semantics.types import TupleT -from vyper.semantics.types.function import ContractFunctionT, KeywordArg, PositionalArg +from vyper.semantics.types.function import ContractFunctionT # register function args with the local calling context. @@ -51,7 +50,7 @@ def _register_function_args(func_t: ContractFunctionT, context: Context) -> list def _generate_kwarg_handlers( - func_t: ContractFunctionT, context: Context, code: vy_ast.FunctionDef + func_t: ContractFunctionT, context: Context ) -> dict[str, tuple[int, IRnode]]: # generate kwarg handlers. # since they might come in thru calldata or be default, @@ -63,14 +62,12 @@ def _generate_kwarg_handlers( # write default args to memory # goto external_function_common_ir - def handler_for(calldata_kwargs_info, default_kwargs_info, default_kwargs): - calldata_args_info: list[Union[PositionalArg, KeywordArg]] = ( - func_t.positional_args + calldata_kwargs_info - ) + def handler_for(calldata_kwargs, default_kwargs): + calldata_args = func_t.positional_args + calldata_kwargs # create a fake type so that get_element_ptr works - calldata_args_t = TupleT(list(arg.typ for arg in calldata_args_info)) + calldata_args_t = TupleT(list(arg.typ for arg in calldata_args)) - abi_sig = func_t.abi_signature_for_kwargs(calldata_kwargs_info) + abi_sig = func_t.abi_signature_for_kwargs(calldata_kwargs) calldata_kwargs_ofst = IRnode( 4, location=CALLDATA, typ=calldata_args_t, encoding=Encoding.ABI @@ -84,10 +81,10 @@ def handler_for(calldata_kwargs_info, default_kwargs_info, default_kwargs): calldata_min_size = args_abi_t.min_size() + 4 # TODO optimize make_setter by using - # TupleT(list(arg.typ for arg in calldata_kwargs_info + default_kwargs_info)) + # TupleT(list(arg.typ for arg in calldata_kwargs + default_kwargs)) # (must ensure memory area is contiguous) - for i, arg_meta in enumerate(calldata_kwargs_info): + for i, arg_meta in enumerate(calldata_kwargs): k = func_t.n_positional_args + i dst = context.lookup_var(arg_meta.name).pos @@ -100,15 +97,15 @@ def handler_for(calldata_kwargs_info, default_kwargs_info, default_kwargs): copy_arg.source_pos = getpos(arg_meta.ast_source) ret.append(copy_arg) - for x, y in zip(default_kwargs_info, default_kwargs): + for x in default_kwargs: dst = context.lookup_var(x.name).pos lhs = IRnode(dst, location=MEMORY, typ=x.typ) - lhs.source_pos = getpos(y) - kw_ast_val = y + lhs.source_pos = getpos(x.ast_source) + kw_ast_val = func_t.default_values[x.name] # e.g. `3` in x: int = 3 rhs = Expr(kw_ast_val, context).ir_node copy_arg = make_setter(lhs, rhs) - copy_arg.source_pos = getpos(y) + copy_arg.source_pos = getpos(x.ast_source) ret.append(copy_arg) ret.append(["goto", func_t._ir_info.external_function_base_entry_label]) @@ -118,24 +115,20 @@ def handler_for(calldata_kwargs_info, default_kwargs_info, default_kwargs): ret = {} - keyword_args_info = func_t.keyword_args - keyword_args = code.args.defaults + keyword_args = func_t.keyword_args - # allocate keyword_args_info slots in memory - for arg in keyword_args_info: + # allocate variable slots in memory + for arg in keyword_args: context.new_variable(arg.name, arg.typ, is_mutable=False) - for i, _ in enumerate(keyword_args_info): - calldata_kwargs_info = keyword_args_info[:i] - default_kwargs_info: list[KeywordArg] = keyword_args_info[i:] - default_kwargs: list[vy_ast.VyperNode] = keyword_args[i:] + for i, _ in enumerate(keyword_args): + calldata_kwargs = keyword_args[:i] + default_kwargs = keyword_args[i:] - sig, calldata_min_size, ir_node = handler_for( - calldata_kwargs_info, default_kwargs_info, default_kwargs - ) + sig, calldata_min_size, ir_node = handler_for(calldata_kwargs, default_kwargs) ret[sig] = calldata_min_size, ir_node - sig, calldata_min_size, ir_node = handler_for(keyword_args_info, [], []) + sig, calldata_min_size, ir_node = handler_for(keyword_args, []) ret[sig] = calldata_min_size, ir_node @@ -160,7 +153,7 @@ def generate_ir_for_external_function(code, func_t, context): handle_base_args = _register_function_args(func_t, context) # generate handlers for kwargs and register the variable records - kwarg_handlers = _generate_kwarg_handlers(func_t, context, code) + kwarg_handlers = _generate_kwarg_handlers(func_t, context) body = ["seq"] # once optional args have been handled, @@ -192,4 +185,4 @@ def generate_ir_for_external_function(code, func_t, context): # besides any kwarg handling func_common_ir = IRnode.from_list(["seq", body, exit_], source_pos=getpos(code)) - return kwarg_handlers, func_common_ir + return kwarg_handlers, func_common_ir \ No newline at end of file From 1709d3a02abfe5279e9510b635d74fe963a852d6 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:32:16 +0800 Subject: [PATCH 12/13] relax module node for exception str --- vyper/exceptions.py | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vyper/exceptions.py b/vyper/exceptions.py index f216069eab..f625a7d3fb 100644 --- a/vyper/exceptions.py +++ b/vyper/exceptions.py @@ -108,7 +108,7 @@ def __str__(self): if isinstance(node, vy_ast.VyperNode): module_node = node.get_ancestor(vy_ast.Module) - if module_node.get("path") not in (None, ""): + if module_node and module_node.get("path") not in (None, ""): node_msg = f'{node_msg}contract "{module_node.path}:{node.lineno}", ' fn_node = node.get_ancestor(vy_ast.FunctionDef) From fe925d69127da3bb9074ca63694545ef55a6d189 Mon Sep 17 00:00:00 2001 From: tserg <8017125+tserg@users.noreply.github.com> Date: Thu, 28 Dec 2023 17:32:32 +0800 Subject: [PATCH 13/13] fix lint --- vyper/codegen/function_definitions/external_function.py | 2 +- vyper/compiler/phases.py | 2 +- vyper/semantics/analysis/module.py | 2 +- 3 files changed, 3 insertions(+), 3 deletions(-) diff --git a/vyper/codegen/function_definitions/external_function.py b/vyper/codegen/function_definitions/external_function.py index 9a66708872..65276469e7 100644 --- a/vyper/codegen/function_definitions/external_function.py +++ b/vyper/codegen/function_definitions/external_function.py @@ -185,4 +185,4 @@ def generate_ir_for_external_function(code, func_t, context): # besides any kwarg handling func_common_ir = IRnode.from_list(["seq", body, exit_], source_pos=getpos(code)) - return kwarg_handlers, func_common_ir \ No newline at end of file + return kwarg_handlers, func_common_ir diff --git a/vyper/compiler/phases.py b/vyper/compiler/phases.py index 184c60c113..7407c4f281 100644 --- a/vyper/compiler/phases.py +++ b/vyper/compiler/phases.py @@ -280,7 +280,7 @@ def generate_folded_ast( symbol_tables = set_data_positions(vyper_module, storage_layout_overrides) vyper_module_folded = copy.deepcopy(vyper_module) - #vy_ast.folding.fold(vyper_module_folded) + # vy_ast.folding.fold(vyper_module_folded) return vyper_module_folded, symbol_tables diff --git a/vyper/semantics/analysis/module.py b/vyper/semantics/analysis/module.py index fa2ac73724..9d828eaa2d 100644 --- a/vyper/semantics/analysis/module.py +++ b/vyper/semantics/analysis/module.py @@ -495,7 +495,7 @@ def _parse_and_fold_ast(file: FileInput) -> vy_ast.VyperNode: resolved_path=str(file.resolved_path), ) vy_ast.validation.validate_literal_nodes(ret) - #vy_ast.folding.fold(ret) + # vy_ast.folding.fold(ret) return ret