diff --git a/vyper/codegen/stmt.py b/vyper/codegen/stmt.py index 95fc635f68..c7f152fc2d 100644 --- a/vyper/codegen/stmt.py +++ b/vyper/codegen/stmt.py @@ -93,7 +93,13 @@ def parse_If(self): def parse_Log(self): event = self.stmt._metadata["type"] - args = [Expr(arg.value, self.context).ir_node for arg in self.stmt.value.keywords] + args = [] + if len(self.stmt.value.keywords) > 0: + # keyword arguments + args = [Expr(arg.value, self.context).ir_node for arg in self.stmt.value.keywords] + else: + # positional arguments + args = [Expr(arg, self.context).ir_node for arg in self.stmt.value.args] topic_ir = [] data_ir = [] diff --git a/vyper/semantics/analysis/local.py b/vyper/semantics/analysis/local.py index 887caac47b..809c6532c6 100644 --- a/vyper/semantics/analysis/local.py +++ b/vyper/semantics/analysis/local.py @@ -812,8 +812,13 @@ def visit_Call(self, node: vy_ast.Call, typ: VyperType) -> None: elif is_type_t(func_type, EventT): # event ctors expected_types = func_type.typedef.arguments.values() # type: ignore - for kwarg, arg_type in zip(node.keywords, expected_types): - self.visit(kwarg.value, arg_type) + # Handle keyword args if present, otherwise use positional args + if len(node.keywords) > 0: + for kwarg, arg_type in zip(node.keywords, expected_types): + self.visit(kwarg.value, arg_type) + else: + for arg, typ in zip(node.args, expected_types): + self.visit(arg, typ) elif is_type_t(func_type, StructT): # struct ctors expected_types = func_type.typedef.members.values() # type: ignore diff --git a/vyper/semantics/types/user.py b/vyper/semantics/types/user.py index b0edf06941..5d2624548c 100644 --- a/vyper/semantics/types/user.py +++ b/vyper/semantics/types/user.py @@ -282,32 +282,32 @@ def from_EventDef(cls, base_node: vy_ast.EventDef) -> "EventT": return cls(base_node.name, members, indexed, base_node) def _ctor_call_return(self, node: vy_ast.Call) -> None: - # Handle positional args by converting them to kwargs + # validate keyword arguments if provided + if len(node.keywords) > 0: + return self._ctor_call_return_with_kwargs(node) + + # warn about positional argument depreciation + msg = "Instantiating events with positional arguments is " + msg += "deprecated as of v0.4.1 and will be disallowed " + msg += "in a future release. Use kwargs instead eg. " + msg += "Foo(a=1, b=2)" + + vyper_warn(msg, node) + + validate_call_args(node, len(self.arguments)) + for arg, expected in zip(node.args, self.arguments.values()): + validate_expected_type(arg, expected) + + + def _ctor_call_return_with_kwargs(self, node: vy_ast.Call) -> None: # TODO: Remove block when positional args are removed if len(node.args) > 0: - if len(node.keywords) > 0: - # can't mix args and kwargs - raise InstantiationException( - "Event instantiation requires either all positional arguments " - "or all keyword arguments", - node, - ) - - msg = "Instantiating events with positional arguments is " - msg += "deprecated as of v0.4.1 and will be disallowed " - msg += "in a future release. Use kwargs instead eg. " - msg += "Foo(a=1, b=2)" - - vyper_warn(msg, node) - - # convert positional args to keywords - kw_list = [] - for kw, val in zip(self.arguments.keys(), node.args): - kw_node = vy_ast.keyword(arg=kw, value=val) - kw_node.set_parent(node) - kw_list.append(kw_node) - node.keywords = kw_list - node.args = [] + # can't mix args and kwargs + raise InstantiationException( + "Event instantiation requires either all positional arguments " + "or all keyword arguments", + node, + ) # manually validate kwargs for better error messages instead of # relying on `validate_call_args` (same as structs)