ast,checker,cgen: fix generics function with embedded structs, ensure correct link generation in cgen (#20900)

This commit is contained in:
GGRei 2024-02-25 17:47:27 +01:00 committed by GitHub
parent ac6231709d
commit 0367f343b0
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 93 additions and 21 deletions

View File

@ -282,15 +282,16 @@ pub:
mut_pos token.Pos
next_token token.Kind
pub mut:
expr Expr // expr.field_name
expr_type Type // type of `Foo` in `Foo.bar`
typ Type // type of the entire thing (`Foo.bar`)
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
or_block OrExpr
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
scope &Scope = unsafe { nil }
from_embed_types []Type // holds the type of the embed that the method is called from
has_hidden_receiver bool
expr Expr // expr.field_name
expr_type Type // type of `Foo` in `Foo.bar`
typ Type // type of the entire thing (`Foo.bar`)
name_type Type // T in `T.name` or typeof in `typeof(expr).name`
or_block OrExpr
gkind_field GenericKindField // `T.name` => ast.GenericKindField.name, `T.typ` => ast.GenericKindField.typ, or .unknown
scope &Scope = unsafe { nil }
from_embed_types []Type // holds the type of the embed that the method is called from
generic_from_embed_types [][]Type // holds the types of the embeds for each generic instance when the same generic method is called.
has_hidden_receiver bool
}
// root_ident returns the origin ident where the selector started.

View File

@ -1583,6 +1583,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
ast.StructField{}, []ast.Type{}
}
node.from_embed_types = embed_types
node.generic_from_embed_types << embed_types
}
}
}

View File

@ -3889,20 +3889,26 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
}
// struct embedding
if sym.info in [ast.Struct, ast.Aggregate] {
for i, embed in node.from_embed_types {
embed_sym := g.table.sym(embed)
embed_name := embed_sym.embed_name()
is_left_ptr := if i == 0 {
node.expr_type.is_ptr()
if node.generic_from_embed_types.len > 0 && sym.info is ast.Struct {
if sym.info.embeds.len > 0 {
mut is_find := false
for arr_val in node.generic_from_embed_types {
if arr_val.len > 0 {
if arr_val[0] == sym.info.embeds[0] {
g.write_selector_expr_embed_name(node, arr_val)
is_find = true
break
}
}
}
if !is_find {
g.write_selector_expr_embed_name(node, node.from_embed_types)
}
} else {
node.from_embed_types[i - 1].is_ptr()
g.write_selector_expr_embed_name(node, node.from_embed_types)
}
if is_left_ptr {
g.write('->')
} else {
g.write('.')
}
g.write(embed_name)
} else {
g.write_selector_expr_embed_name(node, node.from_embed_types)
}
}
alias_to_ptr := sym.info is ast.Alias && sym.info.parent_type.is_ptr()
@ -3928,6 +3934,24 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
}
}
fn (mut g Gen) write_selector_expr_embed_name(node ast.SelectorExpr, embed_types []ast.Type) {
for i, embed in embed_types {
embed_sym := g.table.sym(embed)
embed_name := embed_sym.embed_name()
is_left_ptr := if i == 0 {
node.expr_type.is_ptr()
} else {
embed_types[i - 1].is_ptr()
}
if is_left_ptr {
g.write('->')
} else {
g.write('.')
}
g.write(embed_name)
}
}
// check_var_scope checks if the variable has its value known from the node position
@[inline]
fn (mut g Gen) check_var_scope(obj ast.Var, node_pos int) bool {

View File

@ -0,0 +1,46 @@
struct Base {
i int
}
struct Base1 {
Base
}
struct Base2 {
Base
}
struct Struct1 {
Base1
}
struct Struct1O {
Struct1
}
struct Struct2 {
Base2
}
struct Struct2O {
Struct2
}
fn (b &Base) func[T]() T {
t := T{
i: b.i
}
if t.i == 0 {
}
return t
}
fn test_generic_fn_with_embedded_structs() {
s1 := Struct1{}
s2 := Struct2{}
res1 := s1.func[Struct1O]()
res2 := s2.func[Struct2O]()
assert res1.i == 0
assert res2.i == 0
}