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 {
|
if mut inter_sym.info is table.Interface {
|
||||||
for ifield in inter_sym.info.fields {
|
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 {
|
if ifield.typ != field.typ {
|
||||||
exp := c.table.type_to_str(ifield.typ)
|
exp := c.table.type_to_str(ifield.typ)
|
||||||
got := c.table.type_to_str(field.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.
|
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
|
mut current_iinidx := iinidx_minimum_base
|
||||||
for st in inter_info.types {
|
for st in inter_info.types {
|
||||||
|
st_sym := g.table.get_type_symbol(st)
|
||||||
// cctype is the Cleaned Concrete Type name, *without ptr*,
|
// cctype is the Cleaned Concrete Type name, *without ptr*,
|
||||||
// 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: $ityp.name | concrete type: $st.debug() | st symname: ' +
|
'>> interface name: $ityp.name | concrete type: $st.debug() | st symname: ' +
|
||||||
g.table.get_type_symbol(st).name)
|
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'
|
||||||
|
@ -6189,7 +6190,20 @@ fn (mut g Gen) interface_table() string {
|
||||||
for field in inter_info.fields {
|
for field in inter_info.fields {
|
||||||
cname := c_name(field.name)
|
cname := c_name(field.name)
|
||||||
field_styp := g.typ(field.typ)
|
field_styp := g.typ(field.typ)
|
||||||
|
if _ := st_sym.find_field(field.name) {
|
||||||
cast_struct.writeln('\t\t.$cname = ($field_styp*)((char*)x + __offsetof($cctype, $cname)),')
|
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.write_string('\t}')
|
||||||
cast_struct_str := cast_struct.str()
|
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 {
|
if g.pref.build_mode != .build_module {
|
||||||
methods_struct.writeln('\t{')
|
methods_struct.writeln('\t{')
|
||||||
}
|
}
|
||||||
st_sym := g.table.get_type_symbol(st)
|
|
||||||
mut method := table.Fn{}
|
mut method := table.Fn{}
|
||||||
for _, m in ityp.methods {
|
for _, m in ityp.methods {
|
||||||
for mm in st_sym.methods {
|
for mm in st_sym.methods {
|
||||||
|
|
|
@ -296,6 +296,32 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) ?Field {
|
||||||
return none
|
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]
|
[inline]
|
||||||
pub fn (t &Table) find_type_idx(name string) int {
|
pub fn (t &Table) find_type_idx(name string) int {
|
||||||
return t.type_idxs[name]
|
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