mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
ast, checker, cgen: fix interface method with struct embed (#12783)
This commit is contained in:
parent
b116170735
commit
9b4329d2f6
@ -412,6 +412,18 @@ pub fn (t &Table) find_method_from_embeds(sym &TypeSymbol, method_name string) ?
|
||||
return none
|
||||
}
|
||||
|
||||
// find_method_with_embeds searches for a given method, also looking through embedded fields
|
||||
pub fn (t &Table) find_method_with_embeds(sym &TypeSymbol, method_name string) ?Fn {
|
||||
if func := t.find_method(sym, method_name) {
|
||||
return func
|
||||
} else {
|
||||
// look for embedded field
|
||||
first_err := err
|
||||
func, _ := t.find_method_from_embeds(sym, method_name) or { return first_err }
|
||||
return func
|
||||
}
|
||||
}
|
||||
|
||||
fn (t &Table) register_aggregate_field(mut sym TypeSymbol, name string) ?StructField {
|
||||
if sym.kind != .aggregate {
|
||||
t.panic('Unexpected type symbol: $sym.kind')
|
||||
|
@ -3232,7 +3232,7 @@ fn (mut c Checker) type_implements(typ ast.Type, interface_type ast.Type, pos to
|
||||
if utyp != ast.voidptr_type {
|
||||
// Verify methods
|
||||
for imethod in imethods {
|
||||
method := typ_sym.find_method(imethod.name) or {
|
||||
method := c.table.find_method_with_embeds(typ_sym, imethod.name) or {
|
||||
typ_sym.find_method_with_generic_parent(imethod.name) or {
|
||||
c.error("`$styp` doesn't implement method `$imethod.name` of interface `$inter_sym.name`",
|
||||
pos)
|
||||
|
@ -7310,6 +7310,12 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
||||
}
|
||||
else {}
|
||||
}
|
||||
if st_sym.info is ast.Struct {
|
||||
for embed in st_sym.info.embeds {
|
||||
embed_sym := g.table.get_type_symbol(embed)
|
||||
methods << embed_sym.methods
|
||||
}
|
||||
}
|
||||
for method in methods {
|
||||
mut name := method.name
|
||||
if inter_info.parent_type.has_flag(.generic) {
|
||||
@ -7345,7 +7351,7 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
||||
// hack to mutate typ
|
||||
params[0] = ast.Param{
|
||||
...params[0]
|
||||
typ: params[0].typ.set_nr_muls(1)
|
||||
typ: st.set_nr_muls(1)
|
||||
}
|
||||
fargs, _, _ := g.fn_args(params, voidptr(0))
|
||||
methods_wrapper.write_string(g.out.cut_last(g.out.len - params_start_pos))
|
||||
@ -7354,7 +7360,21 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
||||
if method.return_type != ast.void_type {
|
||||
methods_wrapper.write_string('return ')
|
||||
}
|
||||
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
||||
_, embed_types := g.table.find_method_from_embeds(st_sym, method.name) or {
|
||||
ast.Fn{}, []ast.Type{}
|
||||
}
|
||||
if embed_types.len > 0 {
|
||||
embed_sym := g.table.get_type_symbol(embed_types.last())
|
||||
method_name := '${embed_sym.cname}_$method.name'
|
||||
methods_wrapper.write_string('${method_name}(${fargs[0]}')
|
||||
for embed in embed_types {
|
||||
esym := g.table.get_type_symbol(embed)
|
||||
methods_wrapper.write_string('->$esym.embed_name()')
|
||||
}
|
||||
methods_wrapper.writeln('${fargs[1..].join(', ')});')
|
||||
} else {
|
||||
methods_wrapper.writeln('${method_call}(*${fargs.join(', ')});')
|
||||
}
|
||||
methods_wrapper.writeln('}')
|
||||
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
||||
method_call += iwpostfix
|
||||
|
35
vlib/v/tests/interface_method_with_struct_embed_test.v
Normal file
35
vlib/v/tests/interface_method_with_struct_embed_test.v
Normal file
@ -0,0 +1,35 @@
|
||||
struct Foo {
|
||||
x int
|
||||
}
|
||||
|
||||
fn (f Foo) get() int {
|
||||
return f.x
|
||||
}
|
||||
|
||||
struct Bar {
|
||||
Foo
|
||||
}
|
||||
|
||||
interface Getter {
|
||||
get() int
|
||||
}
|
||||
|
||||
fn test_interface_method_with_struct_embed() {
|
||||
mut getter := []Getter{}
|
||||
|
||||
foo := Foo{22}
|
||||
getter << foo
|
||||
|
||||
bar := Bar{Foo{11}}
|
||||
getter << bar
|
||||
|
||||
assert getter.len == 2
|
||||
|
||||
println(foo)
|
||||
println(getter[0])
|
||||
assert getter[0].get() == 22
|
||||
|
||||
println(bar)
|
||||
println(getter[1])
|
||||
assert getter[1].get() == 11
|
||||
}
|
Loading…
Reference in New Issue
Block a user