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
@ -282,15 +282,16 @@ pub:
|
|||||||
mut_pos token.Pos
|
mut_pos token.Pos
|
||||||
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`
|
||||||
or_block OrExpr
|
or_block OrExpr
|
||||||
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 = unsafe { nil }
|
scope &Scope = unsafe { nil }
|
||||||
from_embed_types []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
|
||||||
has_hidden_receiver bool
|
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.
|
// root_ident returns the origin ident where the selector started.
|
||||||
|
@ -1583,6 +1583,7 @@ fn (mut c Checker) selector_expr(mut node ast.SelectorExpr) ast.Type {
|
|||||||
ast.StructField{}, []ast.Type{}
|
ast.StructField{}, []ast.Type{}
|
||||||
}
|
}
|
||||||
node.from_embed_types = embed_types
|
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
|
// struct embedding
|
||||||
if sym.info in [ast.Struct, ast.Aggregate] {
|
if sym.info in [ast.Struct, ast.Aggregate] {
|
||||||
for i, embed in node.from_embed_types {
|
if node.generic_from_embed_types.len > 0 && sym.info is ast.Struct {
|
||||||
embed_sym := g.table.sym(embed)
|
if sym.info.embeds.len > 0 {
|
||||||
embed_name := embed_sym.embed_name()
|
mut is_find := false
|
||||||
is_left_ptr := if i == 0 {
|
for arr_val in node.generic_from_embed_types {
|
||||||
node.expr_type.is_ptr()
|
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 {
|
} else {
|
||||||
node.from_embed_types[i - 1].is_ptr()
|
g.write_selector_expr_embed_name(node, node.from_embed_types)
|
||||||
}
|
}
|
||||||
if is_left_ptr {
|
} else {
|
||||||
g.write('->')
|
g.write_selector_expr_embed_name(node, node.from_embed_types)
|
||||||
} else {
|
|
||||||
g.write('.')
|
|
||||||
}
|
|
||||||
g.write(embed_name)
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
alias_to_ptr := sym.info is ast.Alias && sym.info.parent_type.is_ptr()
|
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
|
// check_var_scope checks if the variable has its value known from the node position
|
||||||
@[inline]
|
@[inline]
|
||||||
fn (mut g Gen) check_var_scope(obj ast.Var, node_pos int) bool {
|
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