Skip to content

Commit

Permalink
cgen: fix generic resolver on non generic function (#18381)
Browse files Browse the repository at this point in the history
  • Loading branch information
felipensp committed Jun 25, 2023
1 parent 84a5fd0 commit e996033
Show file tree
Hide file tree
Showing 3 changed files with 108 additions and 4 deletions.
23 changes: 19 additions & 4 deletions vlib/v/gen/c/cgen.v
Expand Up @@ -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_ {
Expand All @@ -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 {
Expand Down Expand Up @@ -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)})')
}
Expand Down
19 changes: 19 additions & 0 deletions vlib/v/gen/c/utils.v
Expand Up @@ -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
Expand Down
70 changes: 70 additions & 0 deletions vlib/v/tests/generic_selector_test.v
@@ -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'
}
}

0 comments on commit e996033

Please sign in to comment.