mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
cgen: fix generic resolver on non generic function (#18381)
This commit is contained in:
parent
84a5fd0051
commit
e9960339f9
@ -1876,7 +1876,7 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T
|
||||
}
|
||||
|
||||
stmt_str := g.go_before_stmt(0).trim_space()
|
||||
styp := g.base_type(ret_typ)
|
||||
mut styp := g.base_type(ret_typ)
|
||||
g.empty_line = true
|
||||
|
||||
if g.table.sym(expr_typ).kind == .none_ {
|
||||
@ -1885,7 +1885,21 @@ fn (mut g Gen) expr_with_tmp_var(expr ast.Expr, expr_typ ast.Type, ret_typ ast.T
|
||||
g.writeln(';')
|
||||
} else {
|
||||
mut is_ptr_to_ptr_assign := false
|
||||
g.writeln('${g.typ(ret_typ)} ${tmp_var};')
|
||||
if ret_typ.has_flag(.generic) {
|
||||
if expr is ast.SelectorExpr && g.cur_concrete_types.len == 0 {
|
||||
// resolve generic struct on selectorExpr inside non-generic function
|
||||
if expr.expr is ast.Ident && (expr.expr as ast.Ident).obj is ast.Var {
|
||||
if ((expr.expr as ast.Ident).obj as ast.Var).expr is ast.StructInit {
|
||||
g.cur_concrete_types << (g.table.sym((expr.expr as ast.Ident).obj.typ).info as ast.Struct).concrete_types
|
||||
}
|
||||
}
|
||||
}
|
||||
styp = g.base_type(g.unwrap_generic(ret_typ))
|
||||
ret_styp := g.typ(g.unwrap_generic(ret_typ)).replace('*', '_ptr')
|
||||
g.writeln('${ret_styp} ${tmp_var};')
|
||||
} else {
|
||||
g.writeln('${g.typ(ret_typ)} ${tmp_var};')
|
||||
}
|
||||
if ret_typ.has_flag(.option) {
|
||||
if expr_typ.has_flag(.option) && expr in [ast.StructInit, ast.ArrayInit, ast.MapInit] {
|
||||
if expr is ast.StructInit && (expr as ast.StructInit).init_fields.len > 0 {
|
||||
@ -3693,8 +3707,9 @@ fn (mut g Gen) selector_expr(node ast.SelectorExpr) {
|
||||
return
|
||||
}
|
||||
}
|
||||
field_is_opt := node.expr is ast.Ident && (node.expr as ast.Ident).is_auto_heap()
|
||||
&& (node.expr as ast.Ident).or_expr.kind != .absent && field_typ.has_flag(.option)
|
||||
// var?.field_opt
|
||||
field_is_opt := (node.expr is ast.Ident && (node.expr as ast.Ident).is_auto_heap()
|
||||
&& (node.expr as ast.Ident).or_expr.kind != .absent && field_typ.has_flag(.option))
|
||||
if field_is_opt {
|
||||
g.write('((${g.base_type(field_typ)})')
|
||||
}
|
||||
|
@ -36,6 +36,25 @@ fn (mut g Gen) unwrap_generic(typ ast.Type) ast.Type {
|
||||
}
|
||||
}
|
||||
}
|
||||
} else if typ.has_flag(.generic) && g.table.sym(typ).kind == .struct_ {
|
||||
// resolve selector `a.foo` where `a` is struct[T] on non generic function
|
||||
sym := g.table.sym(typ)
|
||||
if sym.info is ast.Struct {
|
||||
if sym.info.generic_types.len > 0 {
|
||||
generic_names := sym.info.generic_types.map(g.table.sym(it).name)
|
||||
if t_typ := mut_table.resolve_generic_to_concrete(typ, generic_names,
|
||||
sym.info.concrete_types)
|
||||
{
|
||||
return t_typ
|
||||
}
|
||||
|
||||
if t_typ := mut_table.resolve_generic_to_concrete(typ, generic_names,
|
||||
g.cur_concrete_types)
|
||||
{
|
||||
return t_typ
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
return typ
|
||||
|
70
vlib/v/tests/generic_selector_test.v
Normal file
70
vlib/v/tests/generic_selector_test.v
Normal file
@ -0,0 +1,70 @@
|
||||
pub struct List[T] {
|
||||
mut:
|
||||
head ?&Node[T]
|
||||
size int
|
||||
}
|
||||
|
||||
pub fn (mut l List[T]) prepend(mut node Node[T]) {
|
||||
if head := l.head {
|
||||
node.next = head
|
||||
l.head = &node
|
||||
l.size = l.size + 1
|
||||
} else {
|
||||
l.size = 1
|
||||
l.head = &node
|
||||
}
|
||||
}
|
||||
|
||||
pub fn (mut l List[T]) append(mut node Node[T]) ?int {
|
||||
if h := l.head {
|
||||
_ := h
|
||||
} else {
|
||||
l.head = &node
|
||||
l.size = 0
|
||||
return l.size
|
||||
}
|
||||
|
||||
mut curr_node := l.head
|
||||
for {
|
||||
if curr_node != none {
|
||||
if next_node := curr_node?.next {
|
||||
curr_node = next_node
|
||||
} else {
|
||||
curr_node?.next = &node
|
||||
l.size = l.size + 1
|
||||
break
|
||||
}
|
||||
}
|
||||
}
|
||||
return l.size
|
||||
}
|
||||
|
||||
pub fn (mut l List[T]) find_last(node ?&Node[T]) ?&Node[T] {
|
||||
if next := node?.next {
|
||||
return l.find_last(next)
|
||||
} else {
|
||||
return node
|
||||
}
|
||||
}
|
||||
|
||||
[heap]
|
||||
pub struct Node[T] {
|
||||
mut:
|
||||
data T
|
||||
next ?&Node[T]
|
||||
}
|
||||
|
||||
fn test_main() {
|
||||
mut list := List[string]{}
|
||||
list.prepend(mut Node{ data: 'zero' })
|
||||
list.prepend(mut Node{ data: 'first' })
|
||||
list.append(mut Node{ data: 'last' }) or { panic('unable to append linked list') }
|
||||
list.append(mut Node{ data: 'very last' }) or { panic('unable to append linked list') }
|
||||
|
||||
assert list.find_last(list.head)? == Node{
|
||||
data: 'very last'
|
||||
}
|
||||
assert list.head?.next?.next?.next? == Node{
|
||||
data: 'very last'
|
||||
}
|
||||
}
|
Loading…
Reference in New Issue
Block a user