mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix selector code to use interface method table on closure when needed (#18736)
This commit is contained in:
parent
7ce96b2c41
commit
29c8aaeb89
@ -3579,9 +3579,6 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
|||||||
opt_base_typ := g.base_type(node.expr_type)
|
opt_base_typ := g.base_type(node.expr_type)
|
||||||
g.write('(*(${opt_base_typ}*)')
|
g.write('(*(${opt_base_typ}*)')
|
||||||
}
|
}
|
||||||
if sym.kind in [.interface_, .sum_type] {
|
|
||||||
g.write('(*(')
|
|
||||||
}
|
|
||||||
if sym.kind == .array_fixed {
|
if sym.kind == .array_fixed {
|
||||||
if node.field_name != 'len' {
|
if node.field_name != 'len' {
|
||||||
g.error('field_name should be `len`', node.pos)
|
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) {
|
if f := g.table.find_field_with_embeds(sym, node.field_name) {
|
||||||
field_sym := g.table.sym(f.typ)
|
field_sym := g.table.sym(f.typ)
|
||||||
field_typ = f.typ
|
field_typ = f.typ
|
||||||
|
if sym.kind in [.interface_, .sum_type] {
|
||||||
|
g.write('(*(')
|
||||||
|
}
|
||||||
if field_sym.kind in [.sum_type, .interface_] {
|
if field_sym.kind in [.sum_type, .interface_] {
|
||||||
if !prevent_sum_type_unwrapping_once {
|
if !prevent_sum_type_unwrapping_once {
|
||||||
// check first if field is sum type because scope searching is expensive
|
// check first if field is sum type because scope searching is expensive
|
||||||
@ -3675,10 +3675,16 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
|||||||
method_name = g.generic_fn_name(rec_sym.info.concrete_types, m.name)
|
method_name = g.generic_fn_name(rec_sym.info.concrete_types, m.name)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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}(')
|
sb.write_string('${expr_styp}_${method_name}(')
|
||||||
if !receiver.typ.is_ptr() {
|
if !receiver.typ.is_ptr() {
|
||||||
sb.write_string('*')
|
sb.write_string('*')
|
||||||
}
|
}
|
||||||
|
}
|
||||||
for i in 0 .. m.params.len {
|
for i in 0 .. m.params.len {
|
||||||
if i != 0 {
|
if i != 0 {
|
||||||
sb.write_string(', ')
|
sb.write_string(', ')
|
||||||
@ -3705,6 +3711,10 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
|||||||
g.write(')')
|
g.write(')')
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
} else {
|
||||||
|
if sym.kind in [.interface_, .sum_type] {
|
||||||
|
g.write('(*(')
|
||||||
|
}
|
||||||
}
|
}
|
||||||
// var?.field_opt
|
// var?.field_opt
|
||||||
field_is_opt := (node.expr is ast.Ident && node.expr.is_auto_heap()
|
field_is_opt := (node.expr is ast.Ident && node.expr.is_auto_heap()
|
||||||
|
30
vlib/v/tests/interface_closure_test.v
Normal file
30
vlib/v/tests/interface_closure_test.v
Normal file
@ -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
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user