ast, checker, cgen: fix interface method with struct embed (#12783)
parent
b116170735
commit
9b4329d2f6
|
@ -412,6 +412,18 @@ pub fn (t &Table) find_method_from_embeds(sym &TypeSymbol, method_name string) ?
|
||||||
return none
|
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 {
|
fn (t &Table) register_aggregate_field(mut sym TypeSymbol, name string) ?StructField {
|
||||||
if sym.kind != .aggregate {
|
if sym.kind != .aggregate {
|
||||||
t.panic('Unexpected type symbol: $sym.kind')
|
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 {
|
if utyp != ast.voidptr_type {
|
||||||
// Verify methods
|
// Verify methods
|
||||||
for imethod in imethods {
|
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 {
|
typ_sym.find_method_with_generic_parent(imethod.name) or {
|
||||||
c.error("`$styp` doesn't implement method `$imethod.name` of interface `$inter_sym.name`",
|
c.error("`$styp` doesn't implement method `$imethod.name` of interface `$inter_sym.name`",
|
||||||
pos)
|
pos)
|
||||||
|
|
|
@ -7310,6 +7310,12 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
||||||
}
|
}
|
||||||
else {}
|
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 {
|
for method in methods {
|
||||||
mut name := method.name
|
mut name := method.name
|
||||||
if inter_info.parent_type.has_flag(.generic) {
|
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
|
// hack to mutate typ
|
||||||
params[0] = ast.Param{
|
params[0] = ast.Param{
|
||||||
...params[0]
|
...params[0]
|
||||||
typ: params[0].typ.set_nr_muls(1)
|
typ: st.set_nr_muls(1)
|
||||||
}
|
}
|
||||||
fargs, _, _ := g.fn_args(params, voidptr(0))
|
fargs, _, _ := g.fn_args(params, voidptr(0))
|
||||||
methods_wrapper.write_string(g.out.cut_last(g.out.len - params_start_pos))
|
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 {
|
if method.return_type != ast.void_type {
|
||||||
methods_wrapper.write_string('return ')
|
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('}')
|
methods_wrapper.writeln('}')
|
||||||
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
// .speak = Cat_speak_Interface_Animal_method_wrapper
|
||||||
method_call += iwpostfix
|
method_call += iwpostfix
|
||||||
|
|
|
@ -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