cgen: fix overwriting methods of embedded structs + empty struct for interfaces (#12876)
parent
b482da74e9
commit
130d189fce
|
@ -6034,8 +6034,13 @@ fn (mut g Gen) struct_init(node ast.StructInit) {
|
|||
typ: embed
|
||||
fields: init_fields_to_embed
|
||||
}
|
||||
inside_cast_in_heap := g.inside_cast_in_heap
|
||||
g.inside_cast_in_heap = 0 // prevent use of pointers in child structs
|
||||
|
||||
g.write('.$embed_name = ')
|
||||
g.struct_init(default_init)
|
||||
|
||||
g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits
|
||||
if is_multiline {
|
||||
g.writeln(',')
|
||||
} else {
|
||||
|
@ -7262,9 +7267,7 @@ fn (mut g Gen) interface_table() string {
|
|||
// i.e. cctype is always just Cat, not Cat_ptr:
|
||||
cctype := g.cc_type(st, true)
|
||||
$if debug_interface_table ? {
|
||||
eprintln(
|
||||
'>> interface name: $isym.name | concrete type: $st.debug() | st symname: ' +
|
||||
st_sym.name)
|
||||
eprintln('>> interface name: $isym.name | concrete type: $st.debug() | st symname: $st_sym.name')
|
||||
}
|
||||
// Speaker_Cat_index = 0
|
||||
interface_index_name := '_${interface_name}_${cctype}_index'
|
||||
|
@ -7323,6 +7326,7 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
|||
}
|
||||
}
|
||||
mut methods := st_sym.methods
|
||||
method_names := methods.map(it.name)
|
||||
match st_sym.info {
|
||||
ast.Struct, ast.Interface, ast.SumType {
|
||||
if st_sym.info.parent_type.has_flag(.generic) {
|
||||
|
@ -7341,7 +7345,6 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
|||
if st_sym.info is ast.Struct {
|
||||
for embed in st_sym.info.embeds {
|
||||
embed_sym := g.table.get_type_symbol(embed)
|
||||
method_names := methods.map(it.name)
|
||||
for embed_method in embed_sym.methods {
|
||||
if embed_method.name !in method_names {
|
||||
methods << embed_method
|
||||
|
@ -7396,7 +7399,7 @@ static inline $interface_name I_${cctype}_to_Interface_${interface_name}($cctype
|
|||
_, embed_types := g.table.find_method_from_embeds(st_sym, method.name) or {
|
||||
ast.Fn{}, []ast.Type{}
|
||||
}
|
||||
if embed_types.len > 0 {
|
||||
if embed_types.len > 0 && method.name !in method_names {
|
||||
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]}')
|
||||
|
|
|
@ -0,0 +1,67 @@
|
|||
module main
|
||||
|
||||
interface Getter {
|
||||
get() string
|
||||
}
|
||||
|
||||
struct Struct {
|
||||
msg string
|
||||
}
|
||||
|
||||
fn (s Struct) get() string {
|
||||
return s.msg
|
||||
}
|
||||
|
||||
struct EmbeddingStruct {
|
||||
Struct
|
||||
}
|
||||
|
||||
fn (s EmbeddingStruct) get() string {
|
||||
return 'embedded: $s.msg'
|
||||
}
|
||||
|
||||
fn test_struct_embedding() {
|
||||
s1 := EmbeddingStruct{
|
||||
msg: '1'
|
||||
}
|
||||
getter1 := Getter(s1)
|
||||
s2 := &EmbeddingStruct{
|
||||
msg: '2'
|
||||
}
|
||||
getter2 := Getter(s2)
|
||||
getter3 := Getter(EmbeddingStruct{
|
||||
msg: '3'
|
||||
})
|
||||
getter4 := Getter(&EmbeddingStruct{
|
||||
msg: '4'
|
||||
})
|
||||
|
||||
assert getter1.get() == 'embedded: 1'
|
||||
assert getter2.get() == 'embedded: 2'
|
||||
assert getter3.get() == 'embedded: 3'
|
||||
assert getter4.get() == 'embedded: 4'
|
||||
}
|
||||
|
||||
struct EmptyStruct {}
|
||||
|
||||
fn (s EmptyStruct) get() string {
|
||||
return 'empty'
|
||||
}
|
||||
|
||||
struct EmbeddingEmptyStruct {
|
||||
EmptyStruct
|
||||
}
|
||||
|
||||
fn test_empty_struct_embedding() {
|
||||
s1 := EmbeddingEmptyStruct{}
|
||||
getter1 := Getter(s1)
|
||||
s2 := &EmbeddingEmptyStruct{}
|
||||
getter2 := Getter(s2)
|
||||
getter3 := Getter(EmbeddingEmptyStruct{})
|
||||
getter4 := Getter(&EmbeddingEmptyStruct{})
|
||||
|
||||
assert getter1.get() == 'empty'
|
||||
assert getter2.get() == 'empty'
|
||||
assert getter3.get() == 'empty'
|
||||
assert getter4.get() == 'empty'
|
||||
}
|
Loading…
Reference in New Issue