Skip to content

Commit

Permalink
ast, parser: fix generic fntype to concrete types with later generic …
Browse files Browse the repository at this point in the history
…fn definition (fix #18156) (#18157)
  • Loading branch information
yuyi98 committed May 12, 2023
1 parent 2351856 commit 8482bc4
Show file tree
Hide file tree
Showing 3 changed files with 47 additions and 16 deletions.
2 changes: 1 addition & 1 deletion vlib/v/ast/table.v
Original file line number Diff line number Diff line change
Expand Up @@ -744,7 +744,7 @@ pub fn (mut t Table) register_anon_struct(name string, sym_idx int) {
}

pub fn (t &Table) known_type(name string) bool {
return t.find_type_idx(name) != 0 || t.parsing_type == name || name in ['i32', 'byte']
return t.type_idxs[name] != 0 || t.parsing_type == name || name in ['i32', 'byte']
}

// start_parsing_type open the scope during the parsing of a type
Expand Down
32 changes: 25 additions & 7 deletions vlib/v/parser/parser.v
Original file line number Diff line number Diff line change
Expand Up @@ -2119,6 +2119,29 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
}
}

fn (mut p Parser) is_following_concrete_types() bool {
if !(p.tok.kind == .lsbr && p.tok.pos - p.prev_tok.pos == p.prev_tok.len) {
return false
}
mut i := 1
for {
cur_tok := p.peek_token(i)
if cur_tok.kind == .eof {
return false
} else if cur_tok.kind == .rsbr {
break
} else if cur_tok.kind == .name {
if !(cur_tok.lit.len > 1 && p.is_typename(cur_tok)) {
return false
}
} else if cur_tok.kind != .comma {
return false
}
i++
}
return true
}

pub fn (mut p Parser) ident(language ast.Language) ast.Ident {
is_option := p.tok.kind == .question && p.peek_tok.kind == .lsbr
if is_option {
Expand Down Expand Up @@ -2172,12 +2195,7 @@ pub fn (mut p Parser) ident(language ast.Language) ast.Ident {
scope: p.scope
}
}
mut is_known_generic_fn := false
if func := p.table.find_fn(p.prepend_mod(name)) {
if func.generic_names.len > 0 {
is_known_generic_fn = true
}
}
is_following_concrete_types := p.is_following_concrete_types()
mut concrete_types := []ast.Type{}
if p.expr_mod.len > 0 {
name = '${p.expr_mod}.${name}'
Expand All @@ -2195,7 +2213,7 @@ pub fn (mut p Parser) ident(language ast.Language) ast.Ident {
} else if allowed_cases && p.tok.kind == .key_orelse {
or_kind = ast.OrKind.block
or_stmts, or_pos = p.or_block(.no_err_var)
} else if is_known_generic_fn && p.tok.kind == .lsbr {
} else if is_following_concrete_types {
// `generic_fn[int]`
concrete_types = p.parse_concrete_types()
}
Expand Down
29 changes: 21 additions & 8 deletions vlib/v/tests/generics_fn_variable_test.v
Original file line number Diff line number Diff line change
Expand Up @@ -4,17 +4,30 @@ fn func[T](x T, i int, f_ Fn[T]) T {
return f_(x, i)
}

fn f[T](x T, i int) T {
fn f1[T](x T, i int) T {
return x
}

fn test_generic_fn_variable() {
ff := f[int]
ret := ff(1, 11)
println(ret)
assert ret == 1
ff1 := f1[int]
ret1 := ff1(1, 11)
println(ret1)
assert ret1 == 1

x := func[f64](2.0, 3, f[f64])
println(x)
assert x == 2.0
ff2 := f2[int]
ret2 := ff2(1, 11)
println(ret2)
assert ret2 == 1

x1 := func[f64](2.0, 3, f1[f64])
println(x1)
assert x1 == 2.0

x2 := func[f64](2.0, 3, f2[f64])
println(x2)
assert x2 == 2.0
}

fn f2[T](x T, i int) T {
return x
}

0 comments on commit 8482bc4

Please sign in to comment.