1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

cgen: fix generic interface call with reference argument (#15345)

This commit is contained in:
yuyi 2022-08-05 08:01:11 +08:00 committed by GitHub
parent d7a3b866ee
commit e034b35144
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
3 changed files with 76 additions and 24 deletions

View File

@ -689,6 +689,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
if node.receiver_type == 0 { if node.receiver_type == 0 {
g.checker_bug('CallExpr.receiver_type is 0 in method_call', node.pos) 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 mut unwrapped_rec_type := node.receiver_type
if unsafe { g.cur_fn != 0 } && g.cur_fn.generic_names.len > 0 { // in generic fn 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) 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') 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_is_shared := left_type.has_flag(.shared_f)
left_cc_type := g.cc_type(g.table.unaliased_type(node.left_type), false) left_cc_type := g.cc_type(g.table.unaliased_type(left_type), false)
left_type_name := util.no_dots(left_cc_type) left_type_name := util.no_dots(left_cc_type)
g.write('${c_name(left_type_name)}_name_table[') 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('(')
g.write('*'.repeat(node.left_type.nr_muls() - 1)) g.write('*'.repeat(left_type.nr_muls() - 1))
g.expr(node.left) g.expr(node.left)
g.write(')') g.write(')')
} else { } else {
@ -736,16 +737,16 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
} }
dot := if left_is_shared { dot := if left_is_shared {
'->val.' '->val.'
} else if node.left_type.is_ptr() { } else if left_type.is_ptr() {
'->' '->'
} else { } else {
'.' '.'
} }
mname := c_name(node.name) mname := c_name(node.name)
g.write('${dot}_typ]._method_${mname}(') 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('(')
g.write('*'.repeat(node.left_type.nr_muls() - 1)) g.write('*'.repeat(left_type.nr_muls() - 1))
g.expr(node.left) g.expr(node.left)
g.write(')') g.write(')')
} else { } else {
@ -759,8 +760,8 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.write(')') g.write(')')
return return
} }
left_sym := g.table.sym(node.left_type) left_sym := g.table.sym(left_type)
final_left_sym := g.table.final_sym(node.left_type) final_left_sym := g.table.final_sym(left_type)
if left_sym.kind == .array { if left_sym.kind == .array {
match node.name { match node.name {
'filter' { 'filter' {
@ -784,7 +785,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
return return
} }
'contains' { '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 return
} }
'index' { 'index' {
@ -811,7 +812,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
left_info := left_sym.info as ast.Map left_info := left_sym.info as ast.Map
elem_type_str := g.typ(left_info.key_type) elem_type_str := g.typ(left_info.key_type)
g.write('map_delete(') g.write('map_delete(')
if node.left_type.is_ptr() { if left_type.is_ptr() {
g.expr(node.left) g.expr(node.left)
} else { } else {
g.write('&') g.write('&')
@ -823,7 +824,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
return return
} else if left_sym.kind == .array && node.name == 'delete' { } else if left_sym.kind == .array && node.name == 'delete' {
g.write('array_delete(') g.write('array_delete(')
if node.left_type.is_ptr() { if left_type.is_ptr() {
g.expr(node.left) g.expr(node.left)
} else { } else {
g.write('&') 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(...)) // if so, then instead of calling array_clone(&array_slice(...))
// call array_clone_static(array_slice(...)) // call array_clone_static(array_slice(...))
mut is_range_slice := false 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 { if node.left is ast.IndexExpr {
idx := node.left.index idx := node.left.index
if idx is ast.RangeExpr { 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) name = g.generic_fn_name(node.concrete_types, name, false)
// TODO2 // TODO2
// g.generate_tmp_autofree_arg_vars(node, name) // 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(') 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') { && !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 return
} else { } else {
if left_sym.kind == .array { if left_sym.kind == .array {
@ -998,10 +999,9 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.write('${name}(') g.write('${name}(')
} }
} }
if node.receiver_type.is_ptr() if node.receiver_type.is_ptr() && (!left_type.is_ptr() || left_type.has_flag(.variadic)
&& (!node.left_type.is_ptr() || node.left_type.has_flag(.variadic)
|| node.from_embed_types.len != 0 || 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 // The receiver is a reference, but the caller provided a value
// Add `&` automatically. // Add `&` automatically.
// TODO same logic in call_args() // TODO same logic in call_args()
@ -1013,13 +1013,13 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
g.write('&') 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 { && node.from_embed_types.len == 0 {
if !node.left_type.has_flag(.shared_f) { if !left_type.has_flag(.shared_f) {
g.write('/*rec*/*') g.write('/*rec*/*')
} }
} else if !is_range_slice && node.from_embed_types.len == 0 && node.name != 'str' { } 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 { if diff < 0 {
// TODO // TODO
// g.write('&') // g.write('&')
@ -1050,7 +1050,7 @@ fn (mut g Gen) method_call(node ast.CallExpr) {
embed_sym := g.table.sym(embed) embed_sym := g.table.sym(embed)
embed_name := embed_sym.embed_name() embed_name := embed_sym.embed_name()
is_left_ptr := if i == 0 { is_left_ptr := if i == 0 {
node.left_type.is_ptr() left_type.is_ptr()
} else { } else {
node.from_embed_types[i - 1].is_ptr() 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) g.write(embed_name)
} }
if node.left_type.has_flag(.shared_f) { if left_type.has_flag(.shared_f) {
g.write('->val') g.write('->val')
} }
} }

View File

@ -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.

View File

@ -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<T>(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())
}
}