From 8bee4c35380bb1fa5254fb4a0cc281a38ff87800 Mon Sep 17 00:00:00 2001 From: Quinton Miller <nicetas.c@gmail.com> Date: Sat, 13 Feb 2021 09:13:00 +0800 Subject: [PATCH] Don't use key names for method_missing call's named params --- spec/compiler/codegen/method_missing_spec.cr | 13 +++++++------ .../crystal/semantic/method_missing.cr | 19 +++++++++++-------- 2 files changed, 18 insertions(+), 14 deletions(-) diff --git a/spec/compiler/codegen/method_missing_spec.cr b/spec/compiler/codegen/method_missing_spec.cr index 35cba34610f4..721f32a5929d 100644 --- a/spec/compiler/codegen/method_missing_spec.cr +++ b/spec/compiler/codegen/method_missing_spec.cr @@ -382,11 +382,12 @@ describe "Code gen: method_missing" do )).to_string.should eq("bar") end - it "works with named arguments, using names (#3654)" do + it "works with named arguments (#3654)" do run(%( class A macro method_missing(call) - x &+ y + {{call.named_args[0].value}} &+ + {{call.named_args[1].value}} end end @@ -395,17 +396,17 @@ describe "Code gen: method_missing" do )).to_i.should eq(3) end - it "works with named arguments, named args in call (#3654)" do + it "works with named arguments that aren't legal variable names (#10381)" do run(%( class A macro method_missing(call) - {{call.named_args[0].name}} &+ - {{call.named_args[1].name}} + {{call.named_args[0].value}} &+ + {{call.named_args[1].value}} end end a = A.new - a.b(x: 1, y: 2) + a.b("@x": 1, Y: 2) )).to_i.should eq(3) end diff --git a/src/compiler/crystal/semantic/method_missing.cr b/src/compiler/crystal/semantic/method_missing.cr index ceb95571a82e..5b108e73befb 100644 --- a/src/compiler/crystal/semantic/method_missing.cr +++ b/src/compiler/crystal/semantic/method_missing.cr @@ -31,18 +31,19 @@ module Crystal name_node = StringLiteral.new(signature.name) args_nodes = [] of ASTNode named_args_nodes = nil - args_nodes_names = Set(String).new + args_nodes_names = [] of {String?, String} # external <-> internal name signature.arg_types.each_index do |index| arg_node_name = "_arg#{index}" args_nodes << MacroId.new(arg_node_name) - args_nodes_names << arg_node_name + args_nodes_names << {nil, arg_node_name} end if named_args = signature.named_args - args_nodes_names << "" - named_args.each do |named_arg| + args_nodes_names << {nil, ""} + named_args.each_with_index do |named_arg, index| + named_arg_node_name = "_named_arg#{index}" named_args_nodes ||= [] of NamedArgument - named_args_nodes << NamedArgument.new(named_arg.name, MacroId.new(named_arg.name)) - args_nodes_names << named_arg.name + named_args_nodes << NamedArgument.new(named_arg.name, MacroId.new(named_arg_node_name)) + args_nodes_names << {named_arg.name, named_arg_node_name} end end if block = signature.block @@ -56,7 +57,7 @@ module Crystal block_node = Nop.new end - a_def = Def.new(signature.name, args_nodes_names.map { |name| Arg.new(name) }) + a_def = Def.new(signature.name, args_nodes_names.map { |ext_name, name| Arg.new(name, external_name: ext_name) }) a_def.splat_index = signature.arg_types.size if signature.named_args call = Call.new(nil, signature.name, @@ -70,9 +71,11 @@ module Crystal # Check if the expanded macro is a def. We do this # by just lexing the result and seeing if the first # token is `def` + macro_vars = Set(String).new + args_nodes_names.each { |_, name| macro_vars << name } expands_to_def = starts_with_def?(expanded_macro) generated_nodes = - program.parse_macro_source(expanded_macro, macro_expansion_pragmas, method_missing, method_missing, args_nodes_names) do |parser| + program.parse_macro_source(expanded_macro, macro_expansion_pragmas, method_missing, method_missing, macro_vars) do |parser| if expands_to_def parser.parse else