1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker, cgen: allow implementing an interface with an embedded struct (#9042)

This commit is contained in:
spaceface 2021-03-01 21:47:00 +01:00 committed by GitHub
parent 65900e55e3
commit 2b53992c01
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 68 additions and 4 deletions

View File

@ -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)

View File

@ -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)
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.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 {

View File

@ -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]

View File

@ -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
}