From 29c8aaeb89bf453e1172e097adecc1c0aab1bc66 Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sun, 2 Jul 2023 00:54:52 -0300 Subject: [PATCH] cgen: fix selector code to use interface method table on closure when needed (#18736) --- vlib/v/gen/c/cgen.v | 22 ++++++++++++++------ vlib/v/tests/interface_closure_test.v | 30 +++++++++++++++++++++++++++ 2 files changed, 46 insertions(+), 6 deletions(-) create mode 100644 vlib/v/tests/interface_closure_test.v diff --git a/vlib/v/gen/c/cgen.v b/vlib/v/gen/c/cgen.v index 2da3ce603d..1671e231f2 100644 --- a/vlib/v/gen/c/cgen.v +++ b/vlib/v/gen/c/cgen.v @@ -3579,9 +3579,6 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { opt_base_typ := g.base_type(node.expr_type) g.write('(*(${opt_base_typ}*)') } - if sym.kind in [.interface_, .sum_type] { - g.write('(*(') - } if sym.kind == .array_fixed { if node.field_name != 'len' { g.error('field_name should be `len`', node.pos) @@ -3601,6 +3598,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { if f := g.table.find_field_with_embeds(sym, node.field_name) { field_sym := g.table.sym(f.typ) field_typ = f.typ + if sym.kind in [.interface_, .sum_type] { + g.write('(*(') + } if field_sym.kind in [.sum_type, .interface_] { if !prevent_sum_type_unwrapping_once { // check first if field is sum type because scope searching is expensive @@ -3675,9 +3675,15 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { method_name = g.generic_fn_name(rec_sym.info.concrete_types, m.name) } } - sb.write_string('${expr_styp}_${method_name}(') - if !receiver.typ.is_ptr() { - sb.write_string('*') + if rec_sym.info is ast.Interface { + left_cc_type := g.cc_type(g.table.unaliased_type(receiver.typ), false) + left_type_name := util.no_dots(left_cc_type) + sb.write_string('${c_name(left_type_name)}_name_table[a0->_typ]._method_${method_name}(') + } else { + sb.write_string('${expr_styp}_${method_name}(') + if !receiver.typ.is_ptr() { + sb.write_string('*') + } } for i in 0 .. m.params.len { if i != 0 { @@ -3705,6 +3711,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) { g.write(')') return } + } else { + if sym.kind in [.interface_, .sum_type] { + g.write('(*(') + } } // var?.field_opt field_is_opt := (node.expr is ast.Ident && node.expr.is_auto_heap() diff --git a/vlib/v/tests/interface_closure_test.v b/vlib/v/tests/interface_closure_test.v new file mode 100644 index 0000000000..0784f584de --- /dev/null +++ b/vlib/v/tests/interface_closure_test.v @@ -0,0 +1,30 @@ +interface ITest { +mut: + caller(a Test) ! +} + +struct Test { +} + +struct Test2 { +} + +fn (t2 Test2) with_reader(func fn (a Test) !) ! { + return func(Test{}) +} + +fn (t Test) caller(a Test) ! { + println('ok') +} + +fn get() ITest { + return Test{} +} + +fn test_main() { + mut a := get() + + b := Test2{} + b.with_reader(a.caller)! + assert true +}