From e034b3514435d86508a1b5bbf7a07b0abae7a527 Mon Sep 17 00:00:00 2001 From: yuyi Date: Fri, 5 Aug 2022 08:01:11 +0800 Subject: [PATCH] cgen: fix generic interface call with reference argument (#15345) --- vlib/v/gen/c/fn.v | 48 +++++++++---------- .../inout/dump_generic_interface_ref_arg.out | 6 +++ .../inout/dump_generic_interface_ref_arg.vv | 46 ++++++++++++++++++ 3 files changed, 76 insertions(+), 24 deletions(-) create mode 100644 vlib/v/tests/inout/dump_generic_interface_ref_arg.out create mode 100644 vlib/v/tests/inout/dump_generic_interface_ref_arg.vv diff --git a/vlib/v/gen/c/fn.v b/vlib/v/gen/c/fn.v index 53bf1eec6d..c41e673cb6 100644 --- a/vlib/v/gen/c/fn.v +++ b/vlib/v/gen/c/fn.v @@ -689,6 +689,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { if node.receiver_type == 0 { g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos) } + left_type := g.unwrap_generic(node.left_type) mut unwrapped_rec_type := node.receiver_type if unsafe { g.cur_fn != 0 } && g.cur_fn.generic_names.len > 0 { // in generic fn unwrapped_rec_type = g.unwrap_generic(node.receiver_type) @@ -722,13 +723,13 @@ fn (mut g Gen) method_call(node ast.CallExpr) { eprintln('>>> interface typ_sym.name: $typ_sym.name | receiver_type_name: $receiver_type_name | pos: $node.pos') } - left_is_shared := node.left_type.has_flag(.shared_f) - left_cc_type := g.cc_type(g.table.unaliased_type(node.left_type), false) + left_is_shared := left_type.has_flag(.shared_f) + left_cc_type := g.cc_type(g.table.unaliased_type(left_type), false) left_type_name := util.no_dots(left_cc_type) g.write('${c_name(left_type_name)}_name_table[') - if node.left.is_auto_deref_var() && node.left_type.nr_muls() > 1 { + if node.left.is_auto_deref_var() && left_type.nr_muls() > 1 { g.write('(') - g.write('*'.repeat(node.left_type.nr_muls() - 1)) + g.write('*'.repeat(left_type.nr_muls() - 1)) g.expr(node.left) g.write(')') } else { @@ -736,16 +737,16 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } dot := if left_is_shared { '->val.' - } else if node.left_type.is_ptr() { + } else if left_type.is_ptr() { '->' } else { '.' } mname := c_name(node.name) g.write('${dot}_typ]._method_${mname}(') - if node.left.is_auto_deref_var() && node.left_type.nr_muls() > 1 { + if node.left.is_auto_deref_var() && left_type.nr_muls() > 1 { g.write('(') - g.write('*'.repeat(node.left_type.nr_muls() - 1)) + g.write('*'.repeat(left_type.nr_muls() - 1)) g.expr(node.left) g.write(')') } else { @@ -759,8 +760,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.write(')') return } - left_sym := g.table.sym(node.left_type) - final_left_sym := g.table.final_sym(node.left_type) + left_sym := g.table.sym(left_type) + final_left_sym := g.table.final_sym(left_type) if left_sym.kind == .array { match node.name { 'filter' { @@ -784,7 +785,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { return } 'contains' { - g.gen_array_contains(node.left_type, node.left, node.args[0].expr) + g.gen_array_contains(left_type, node.left, node.args[0].expr) return } 'index' { @@ -811,7 +812,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { left_info := left_sym.info as ast.Map elem_type_str := g.typ(left_info.key_type) g.write('map_delete(') - if node.left_type.is_ptr() { + if left_type.is_ptr() { g.expr(node.left) } else { g.write('&') @@ -823,7 +824,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { return } else if left_sym.kind == .array && node.name == 'delete' { g.write('array_delete(') - if node.left_type.is_ptr() { + if left_type.is_ptr() { g.expr(node.left) } else { g.write('&') @@ -968,7 +969,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { // if so, then instead of calling array_clone(&array_slice(...)) // call array_clone_static(array_slice(...)) mut is_range_slice := false - if node.receiver_type.is_ptr() && !node.left_type.is_ptr() { + if node.receiver_type.is_ptr() && !left_type.is_ptr() { if node.left is ast.IndexExpr { idx := node.left.index if idx is ast.RangeExpr { @@ -982,11 +983,11 @@ fn (mut g Gen) method_call(node ast.CallExpr) { name = g.generic_fn_name(node.concrete_types, name, false) // TODO2 // g.generate_tmp_autofree_arg_vars(node, name) - if !node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name == 'str' { + if !node.receiver_type.is_ptr() && left_type.is_ptr() && node.name == 'str' { g.write('ptr_str(') - } else if node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name == 'str' + } else if node.receiver_type.is_ptr() && left_type.is_ptr() && node.name == 'str' && !left_sym.has_method('str') { - g.gen_expr_to_string(node.left, node.left_type) + g.gen_expr_to_string(node.left, left_type) return } else { if left_sym.kind == .array { @@ -998,10 +999,9 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.write('${name}(') } } - if node.receiver_type.is_ptr() - && (!node.left_type.is_ptr() || node.left_type.has_flag(.variadic) + if node.receiver_type.is_ptr() && (!left_type.is_ptr() || left_type.has_flag(.variadic) || node.from_embed_types.len != 0 - || (node.left_type.has_flag(.shared_f) && node.name != 'str')) { + || (left_type.has_flag(.shared_f) && node.name != 'str')) { // The receiver is a reference, but the caller provided a value // Add `&` automatically. // TODO same logic in call_args() @@ -1013,13 +1013,13 @@ fn (mut g Gen) method_call(node ast.CallExpr) { g.write('&') } } - } else if !node.receiver_type.is_ptr() && node.left_type.is_ptr() && node.name != 'str' + } else if !node.receiver_type.is_ptr() && left_type.is_ptr() && node.name != 'str' && node.from_embed_types.len == 0 { - if !node.left_type.has_flag(.shared_f) { + if !left_type.has_flag(.shared_f) { g.write('/*rec*/*') } } else if !is_range_slice && node.from_embed_types.len == 0 && node.name != 'str' { - diff := node.left_type.nr_muls() - node.receiver_type.nr_muls() + diff := left_type.nr_muls() - node.receiver_type.nr_muls() if diff < 0 { // TODO // g.write('&') @@ -1050,7 +1050,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { embed_sym := g.table.sym(embed) embed_name := embed_sym.embed_name() is_left_ptr := if i == 0 { - node.left_type.is_ptr() + left_type.is_ptr() } else { node.from_embed_types[i - 1].is_ptr() } @@ -1061,7 +1061,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) { } g.write(embed_name) } - if node.left_type.has_flag(.shared_f) { + if left_type.has_flag(.shared_f) { g.write('->val') } } diff --git a/vlib/v/tests/inout/dump_generic_interface_ref_arg.out b/vlib/v/tests/inout/dump_generic_interface_ref_arg.out new file mode 100644 index 0000000000..d5c99f92ad --- /dev/null +++ b/vlib/v/tests/inout/dump_generic_interface_ref_arg.out @@ -0,0 +1,6 @@ +[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:30] mi.in_(): 1. +[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:31] mi.out(): 2. +[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:36] in_put.in_(): 1. +[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:37] in_put.out(): 2. +[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:39] in_put.in_(): 1. +[vlib/v/tests/inout/dump_generic_interface_ref_arg.vv:40] in_put.out(): 2. diff --git a/vlib/v/tests/inout/dump_generic_interface_ref_arg.vv b/vlib/v/tests/inout/dump_generic_interface_ref_arg.vv new file mode 100644 index 0000000000..435975656b --- /dev/null +++ b/vlib/v/tests/inout/dump_generic_interface_ref_arg.vv @@ -0,0 +1,46 @@ +interface In { + in_() f64 +} + +interface Out { + out() f64 +} + +interface InOut { +} + +struct MyImpl { + in_ f64 + out f64 +} + +pub fn (mi &MyImpl) in_() f64 { + return mi.in_ +} + +pub fn (mi &MyImpl) out() f64 { + return mi.out +} + +fn main() { + mi := MyImpl{ + in_: 1.0 + out: 2.0 + } + dump(mi.in_()) + dump(mi.out()) + run(&mi) +} + +fn run(in_put T) { + dump(in_put.in_()) + dump(in_put.out()) + $if T is InOut { + dump(in_put.in_()) + dump(in_put.out()) + } $else $if T is In { + dump(in_put.in_()) + } $else $if T is Out { + dump(in_put.out()) + } +}