mirror of
https://github.com/vlang/v.git
synced 2025-09-16 02:49:31 -04:00
ast,checker,cgen: fix generics function with embedded structs, ensure correct link generation in cgen (#20900)
This commit is contained in:
parent
ac6231709d
commit
0367f343b0
@ -290,6 +290,7 @@ pub mut:
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -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()
|
||||
} else {
|
||||
node.from_embed_types[i - 1].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_left_ptr {
|
||||
g.write('->')
|
||||
} else {
|
||||
g.write('.')
|
||||
}
|
||||
g.write(embed_name)
|
||||
}
|
||||
if !is_find {
|
||||
g.write_selector_expr_embed_name(node, node.from_embed_types)
|
||||
}
|
||||
} else {
|
||||
g.write_selector_expr_embed_name(node, node.from_embed_types)
|
||||
}
|
||||
} 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 {
|
||||
|
46
vlib/v/tests/generics_method_with_embedded_structs_test.v
Normal file
46
vlib/v/tests/generics_method_with_embedded_structs_test.v
Normal 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
|
||||
}
|
Loading…
x
Reference in New Issue
Block a user