ast, checker, cgen: fix nested struct embed error (fix #12659) (#12712)

pull/12714/head
yuyi 2021-12-04 16:19:19 +08:00 committed by GitHub
parent 7e6d4ebfe1
commit 2d43fdb42a
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
6 changed files with 46 additions and 25 deletions

View File

@ -1345,7 +1345,7 @@ fn (t Tree) selector_expr(node ast.SelectorExpr) &Node {
obj.add('typ', t.type_node(node.typ)) obj.add('typ', t.type_node(node.typ))
obj.add('name_type', t.type_node(node.name_type)) obj.add('name_type', t.type_node(node.name_type))
obj.add('gkind_field', t.enum_node(node.gkind_field)) obj.add('gkind_field', t.enum_node(node.gkind_field))
obj.add('from_embed_type', t.type_node(node.from_embed_type)) obj.add('from_embed_types', t.array_node_type(node.from_embed_types))
obj.add('next_token', t.token_node(node.next_token)) obj.add('next_token', t.token_node(node.next_token))
obj.add('pos', t.position(node.pos)) obj.add('pos', t.position(node.pos))
obj.add('scope', t.number_node(int(node.scope))) obj.add('scope', t.number_node(int(node.scope)))

View File

@ -223,13 +223,13 @@ pub:
mut_pos token.Position mut_pos token.Position
next_token token.Kind next_token token.Kind
pub mut: pub mut:
expr Expr // expr.field_name expr Expr // expr.field_name
expr_type Type // type of `Foo` in `Foo.bar` expr_type Type // type of `Foo` in `Foo.bar`
typ Type // type of the entire thing (`Foo.bar`) typ Type // type of the entire thing (`Foo.bar`)
name_type Type // T in `T.name` or typeof in `typeof(expr).name` name_type Type // T in `T.name` or typeof in `typeof(expr).name`
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
scope &Scope scope &Scope
from_embed_type Type // holds the type of the embed that the method is called from from_embed_types []Type // holds the type of the embed that the method is called from
} }
// root_ident returns the origin ident where the selector started. // root_ident returns the origin ident where the selector started.

View File

@ -503,22 +503,23 @@ pub fn (t &Table) find_field(s &TypeSymbol, name string) ?StructField {
pub fn (t &Table) find_field_from_embeds_recursive(sym &TypeSymbol, field_name string) ?(StructField, []Type) { pub fn (t &Table) find_field_from_embeds_recursive(sym &TypeSymbol, field_name string) ?(StructField, []Type) {
if sym.info is Struct { if sym.info is Struct {
mut found_fields := []StructField{} mut found_fields := []StructField{}
mut embeds_of_found_fields := [][]Type{} mut embeds_of_found_fields := []Type{}
for embed in sym.info.embeds { for embed in sym.info.embeds {
embed_sym := t.get_type_symbol(embed) embed_sym := t.get_type_symbol(embed)
if field := t.find_field(embed_sym, field_name) { if field := t.find_field(embed_sym, field_name) {
found_fields << field found_fields << field
embeds_of_found_fields << [embed] embeds_of_found_fields << embed
} else { } else {
field, types := t.find_field_from_embeds_recursive(embed_sym, field_name) or { field, types := t.find_field_from_embeds_recursive(embed_sym, field_name) or {
StructField{}, []Type{} continue
} }
found_fields << field found_fields << field
embeds_of_found_fields << embed
embeds_of_found_fields << types embeds_of_found_fields << types
} }
} }
if found_fields.len == 1 { if found_fields.len == 1 {
return found_fields[0], embeds_of_found_fields[0] return found_fields[0], embeds_of_found_fields
} else if found_fields.len > 1 { } else if found_fields.len > 1 {
return error('ambiguous field `$field_name`') return error('ambiguous field `$field_name`')
} }
@ -526,7 +527,7 @@ pub fn (t &Table) find_field_from_embeds_recursive(sym &TypeSymbol, field_name s
for typ in sym.info.types { for typ in sym.info.types {
agg_sym := t.get_type_symbol(typ) agg_sym := t.get_type_symbol(typ)
field, embed_types := t.find_field_from_embeds_recursive(agg_sym, field_name) or { field, embed_types := t.find_field_from_embeds_recursive(agg_sym, field_name) or {
return err continue
} }
if embed_types.len > 0 { if embed_types.len > 0 {
return field, embed_types return field, embed_types
@ -578,7 +579,7 @@ pub fn (t &Table) find_field_with_embeds(sym &TypeSymbol, field_name string) ?St
} else { } else {
// look for embedded field // look for embedded field
first_err := err first_err := err
field, _ := t.find_field_from_embeds(sym, field_name) or { return first_err } field, _ := t.find_field_from_embeds_recursive(sym, field_name) or { return first_err }
return field return field
} }
} }

View File

@ -3460,15 +3460,15 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
} else { } else {
// look for embedded field // look for embedded field
has_field = true has_field = true
mut embed_type := ast.Type(0) mut embed_types := []ast.Type{}
field, embed_type = c.table.find_field_from_embeds(sym, field_name) or { field, embed_types = c.table.find_field_from_embeds_recursive(sym, field_name) or {
if err.msg != '' { if err.msg != '' {
c.error(err.msg, node.pos) c.error(err.msg, node.pos)
} }
has_field = false has_field = false
ast.StructField{}, ast.Type(0) ast.StructField{}, []ast.Type{}
} }
node.from_embed_type = embed_type node.from_embed_types = embed_types
if sym.kind in [.aggregate, .sum_type] { if sym.kind in [.aggregate, .sum_type] {
unknown_field_msg = err.msg unknown_field_msg = err.msg
} }
@ -3489,15 +3489,15 @@ pub fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
} else { } else {
// look for embedded field // look for embedded field
has_field = true has_field = true
mut embed_type := ast.Type(0) mut embed_types := []ast.Type{}
field, embed_type = c.table.find_field_from_embeds(gs, field_name) or { field, embed_types = c.table.find_field_from_embeds_recursive(gs, field_name) or {
if err.msg != '' { if err.msg != '' {
c.error(err.msg, node.pos) c.error(err.msg, node.pos)
} }
has_field = false has_field = false
ast.StructField{}, ast.Type(0) ast.StructField{}, []ast.Type{}
} }
node.from_embed_type = embed_type node.from_embed_types = embed_types
} }
} }
} }

View File

@ -4226,8 +4226,8 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
} }
// struct embedding // struct embedding
if sym.info in [ast.Struct, ast.Aggregate] { if sym.info in [ast.Struct, ast.Aggregate] {
if node.from_embed_type != 0 { for embed in node.from_embed_types {
embed_sym := g.table.get_type_symbol(node.from_embed_type) embed_sym := g.table.get_type_symbol(embed)
embed_name := embed_sym.embed_name() embed_name := embed_sym.embed_name()
if node.expr_type.is_ptr() { if node.expr_type.is_ptr() {
g.write('->') g.write('->')
@ -4237,7 +4237,7 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
g.write(embed_name) g.write(embed_name)
} }
} }
if (node.expr_type.is_ptr() || sym.kind == .chan) && node.from_embed_type == 0 { if (node.expr_type.is_ptr() || sym.kind == .chan) && node.from_embed_types.len == 0 {
g.write('->') g.write('->')
} else { } else {
// g.write('. /*typ= $it.expr_type */') // ${g.typ(it.expr_type)} /') // g.write('. /*typ= $it.expr_type */') // ${g.typ(it.expr_type)} /')

View File

@ -0,0 +1,20 @@
struct Foo {
mut:
x int
}
struct Bar {
Foo
}
struct Baz {
Bar
}
fn test_nested_struct_embed() {
mut baz := Baz{}
baz.x = 3
println(baz.x)
assert baz.x == 3
}