checker, cgen: allow implementing an interface with an embedded struct (#9042)
parent
65900e55e3
commit
2b53992c01
|
@ -2060,7 +2060,7 @@ fn (mut c Checker) type_implements(typ table.Type, inter_typ table.Type, pos tok
|
|||
}
|
||||
if mut inter_sym.info is table.Interface {
|
||||
for ifield in inter_sym.info.fields {
|
||||
if field := typ_sym.find_field(ifield.name) {
|
||||
if field := c.table.find_field_with_embeds(typ_sym, ifield.name) {
|
||||
if ifield.typ != field.typ {
|
||||
exp := c.table.type_to_str(ifield.typ)
|
||||
got := c.table.type_to_str(field.typ)
|
||||
|
|
|
@ -6164,13 +6164,14 @@ fn (mut g Gen) interface_table() string {
|
|||
iinidx_minimum_base := 1000 // NB: NOT 0, to avoid map entries set to 0 later, so `if already_generated_mwrappers[name] > 0 {` works.
|
||||
mut current_iinidx := iinidx_minimum_base
|
||||
for st in inter_info.types {
|
||||
st_sym := g.table.get_type_symbol(st)
|
||||
// cctype is the Cleaned Concrete Type name, *without ptr*,
|
||||
// i.e. cctype is always just Cat, not Cat_ptr:
|
||||
cctype := g.cc_type(st, true)
|
||||
$if debug_interface_table ? {
|
||||
eprintln(
|
||||
'>> interface name: $ityp.name | concrete type: $st.debug() | st symname: ' +
|
||||
g.table.get_type_symbol(st).name)
|
||||
st_sym.name)
|
||||
}
|
||||
// Speaker_Cat_index = 0
|
||||
interface_index_name := '_${interface_name}_${cctype}_index'
|
||||
|
@ -6189,7 +6190,20 @@ fn (mut g Gen) interface_table() string {
|
|||
for field in inter_info.fields {
|
||||
cname := c_name(field.name)
|
||||
field_styp := g.typ(field.typ)
|
||||
cast_struct.writeln('\t\t.$cname = ($field_styp*)((char*)x + __offsetof($cctype, $cname)),')
|
||||
if _ := st_sym.find_field(field.name) {
|
||||
cast_struct.writeln('\t\t.$cname = ($field_styp*)((char*)x + __offsetof($cctype, $cname)),')
|
||||
} else {
|
||||
// the field is embedded in another struct
|
||||
cast_struct.write_string('\t\t.$cname = ($field_styp*)((char*)x')
|
||||
for embed_type in st_sym.struct_info().embeds {
|
||||
embed_sym := g.table.get_type_symbol(embed_type)
|
||||
if _ := embed_sym.find_field(field.name) {
|
||||
cast_struct.write_string(' + __offsetof($cctype, $embed_sym.embed_name()) + __offsetof($embed_sym.cname, $cname)')
|
||||
break
|
||||
}
|
||||
}
|
||||
cast_struct.writeln('),')
|
||||
}
|
||||
}
|
||||
cast_struct.write_string('\t}')
|
||||
cast_struct_str := cast_struct.str()
|
||||
|
@ -6208,7 +6222,6 @@ $staticprefix $interface_name* I_${cctype}_to_Interface_${interface_name}_ptr($c
|
|||
if g.pref.build_mode != .build_module {
|
||||
methods_struct.writeln('\t{')
|
||||
}
|
||||
st_sym := g.table.get_type_symbol(st)
|
||||
mut method := table.Fn{}
|
||||
for _, m in ityp.methods {
|
||||
for mm in st_sym.methods {
|
||||
|
|
|
@ -296,6 +296,32 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) ?Field {
|
|||
return none
|
||||
}
|
||||
|
||||
// search for a given field, looking through embedded fields
|
||||
pub fn (t &Table) find_field_with_embeds(sym &TypeSymbol, field_name string) ?Field {
|
||||
if f := t.find_field(sym, field_name) {
|
||||
return f
|
||||
} else {
|
||||
// look for embedded field
|
||||
if sym.info is Struct {
|
||||
mut found_fields := []Field{}
|
||||
mut embed_of_found_fields := []Type{}
|
||||
for embed in sym.info.embeds {
|
||||
embed_sym := t.get_type_symbol(embed)
|
||||
if f := t.find_field(embed_sym, field_name) {
|
||||
found_fields << f
|
||||
embed_of_found_fields << embed
|
||||
}
|
||||
}
|
||||
if found_fields.len == 1 {
|
||||
return found_fields[0]
|
||||
} else if found_fields.len > 1 {
|
||||
return error('ambiguous field `$field_name`')
|
||||
}
|
||||
}
|
||||
return err
|
||||
}
|
||||
}
|
||||
|
||||
[inline]
|
||||
pub fn (t &Table) find_type_idx(name string) int {
|
||||
return t.type_idxs[name]
|
||||
|
|
|
@ -305,3 +305,28 @@ fn animal_match(a Animal) {
|
|||
}
|
||||
}
|
||||
*/
|
||||
|
||||
interface II {
|
||||
mut:
|
||||
my_field int
|
||||
}
|
||||
|
||||
struct AA {
|
||||
BB
|
||||
}
|
||||
|
||||
struct BB {
|
||||
pad [10]byte
|
||||
mut:
|
||||
my_field int
|
||||
}
|
||||
|
||||
fn main() {
|
||||
mut aa := AA{}
|
||||
mut ii := II(aa)
|
||||
assert ii.my_field == 0
|
||||
aa.my_field = 123
|
||||
assert ii.my_field == 123
|
||||
ii.my_field = 1234
|
||||
assert aa.my_field == 1234
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue