From 04221475d1fc3d41aeef116440ad2a924f724b95 Mon Sep 17 00:00:00 2001 From: yuyi Date: Tue, 29 Jun 2021 16:16:15 +0800 Subject: [PATCH] cgen: fix go call interface method (fix #10520) (#10602) --- vlib/v/gen/c/cgen.v | 21 +++++++++++++-- vlib/v/tests/go_call_interface_method_test.v | 28 ++++++++++++++++++++ 2 files changed, 47 insertions(+), 2 deletions(-) create mode 100644 vlib/v/tests/go_call_interface_method_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index a6b6cb74af..8e4516f4ba 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -5935,12 +5935,29 @@ fn (mut g Gen) go_expr(node ast.GoExpr) { } else { g.gowrappers.write_string('\t') } - g.gowrappers.write_string('${name}(') if expr.is_method { - g.gowrappers.write_string('arg->arg0') + unwrapped_rec_type := g.unwrap_generic(expr.receiver_type) + typ_sym := g.table.get_type_symbol(unwrapped_rec_type) + if typ_sym.kind == .interface_ + && (typ_sym.info as ast.Interface).defines_method(expr.name) { + rec_cc_type := g.cc_type(unwrapped_rec_type, false) + receiver_type_name := util.no_dots(rec_cc_type) + g.gowrappers.write_string('${c_name(receiver_type_name)}_name_table[') + g.gowrappers.write_string('arg->arg0') + dot := if expr.left_type.is_ptr() { '->' } else { '.' } + mname := c_name(expr.name) + g.gowrappers.write_string('${dot}_typ]._method_${mname}(') + g.gowrappers.write_string('arg->arg0') + g.gowrappers.write_string('${dot}_object') + } else { + g.gowrappers.write_string('${name}(') + g.gowrappers.write_string('arg->arg0') + } if expr.args.len > 0 { g.gowrappers.write_string(', ') } + } else { + g.gowrappers.write_string('${name}(') } if expr.args.len > 0 { mut has_cast := false diff --git a/vlib/v/tests/go_call_interface_method_test.v b/vlib/v/tests/go_call_interface_method_test.v new file mode 100644 index 0000000000..0533f93c1b --- /dev/null +++ b/vlib/v/tests/go_call_interface_method_test.v @@ -0,0 +1,28 @@ +interface CanPerformTask { + task() +} + +struct Task1 {} + +fn (task1 Task1) task() { + println('task1') +} + +struct Task2 {} + +fn (task2 Task2) task() { + println('task2') +} + +fn test_go_call_interface_method() { + mut tasks := []CanPerformTask{} + + tasks << Task1{} + tasks << Task2{} + + for task in tasks { + go task.task() + } + + assert true +}