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
|
typ: embed
|
||||||
fields: init_fields_to_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.write('.$embed_name = ')
|
||||||
g.struct_init(default_init)
|
g.struct_init(default_init)
|
||||||
|
|
||||||
|
g.inside_cast_in_heap = inside_cast_in_heap // restore value for further struct inits
|
||||||
if is_multiline {
|
if is_multiline {
|
||||||
g.writeln(',')
|
g.writeln(',')
|
||||||
} else {
|
} else {
|
||||||
|
@ -7262,9 +7267,7 @@ fn (mut g Gen) interface_table() string {
|
||||||
// i.e. cctype is always just Cat, not Cat_ptr:
|
// i.e. cctype is always just Cat, not Cat_ptr:
|
||||||
cctype := g.cc_type(st, true)
|
cctype := g.cc_type(st, true)
|
||||||
$if debug_interface_table ? {
|
$if debug_interface_table ? {
|
||||||
eprintln(
|
eprintln('>> interface name: $isym.name | concrete type: $st.debug() | st symname: $st_sym.name')
|
||||||
'>> interface name: $isym.name | concrete type: $st.debug() | st symname: ' +
|
|
||||||
st_sym.name)
|
|
||||||
}
|
}
|
||||||
// Speaker_Cat_index = 0
|
// Speaker_Cat_index = 0
|
||||||
interface_index_name := '_${interface_name}_${cctype}_index'
|
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
|
mut methods := st_sym.methods
|
||||||
|
method_names := methods.map(it.name)
|
||||||
match st_sym.info {
|
match st_sym.info {
|
||||||
ast.Struct, ast.Interface, ast.SumType {
|
ast.Struct, ast.Interface, ast.SumType {
|
||||||
if st_sym.info.parent_type.has_flag(.generic) {
|
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 {
|
if st_sym.info is ast.Struct {
|
||||||
for embed in st_sym.info.embeds {
|
for embed in st_sym.info.embeds {
|
||||||
embed_sym := g.table.get_type_symbol(embed)
|
embed_sym := g.table.get_type_symbol(embed)
|
||||||
method_names := methods.map(it.name)
|
|
||||||
for embed_method in embed_sym.methods {
|
for embed_method in embed_sym.methods {
|
||||||
if embed_method.name !in method_names {
|
if embed_method.name !in method_names {
|
||||||
methods << embed_method
|
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 {
|
_, embed_types := g.table.find_method_from_embeds(st_sym, method.name) or {
|
||||||
ast.Fn{}, []ast.Type{}
|
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())
|
embed_sym := g.table.get_type_symbol(embed_types.last())
|
||||||
method_name := '${embed_sym.cname}_$method.name'
|
method_name := '${embed_sym.cname}_$method.name'
|
||||||
methods_wrapper.write_string('${method_name}(${fargs[0]}')
|
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