Skip to content

Commit 8482bc4

Browse files
authored
ast, parser: fix generic fntype to concrete types with later generic fn definition (fix #18156) (#18157)
1 parent 2351856 commit 8482bc4

File tree

3 files changed

+47
-16
lines changed

3 files changed

+47
-16
lines changed

vlib/v/ast/table.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -744,7 +744,7 @@ pub fn (mut t Table) register_anon_struct(name string, sym_idx int) {
744744
}
745745

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

750750
// start_parsing_type open the scope during the parsing of a type

vlib/v/parser/parser.v

Lines changed: 25 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -2119,6 +2119,29 @@ fn (mut p Parser) parse_multi_expr(is_top_level bool) ast.Stmt {
21192119
}
21202120
}
21212121

2122+
fn (mut p Parser) is_following_concrete_types() bool {
2123+
if !(p.tok.kind == .lsbr && p.tok.pos - p.prev_tok.pos == p.prev_tok.len) {
2124+
return false
2125+
}
2126+
mut i := 1
2127+
for {
2128+
cur_tok := p.peek_token(i)
2129+
if cur_tok.kind == .eof {
2130+
return false
2131+
} else if cur_tok.kind == .rsbr {
2132+
break
2133+
} else if cur_tok.kind == .name {
2134+
if !(cur_tok.lit.len > 1 && p.is_typename(cur_tok)) {
2135+
return false
2136+
}
2137+
} else if cur_tok.kind != .comma {
2138+
return false
2139+
}
2140+
i++
2141+
}
2142+
return true
2143+
}
2144+
21222145
pub fn (mut p Parser) ident(language ast.Language) ast.Ident {
21232146
is_option := p.tok.kind == .question && p.peek_tok.kind == .lsbr
21242147
if is_option {
@@ -2172,12 +2195,7 @@ pub fn (mut p Parser) ident(language ast.Language) ast.Ident {
21722195
scope: p.scope
21732196
}
21742197
}
2175-
mut is_known_generic_fn := false
2176-
if func := p.table.find_fn(p.prepend_mod(name)) {
2177-
if func.generic_names.len > 0 {
2178-
is_known_generic_fn = true
2179-
}
2180-
}
2198+
is_following_concrete_types := p.is_following_concrete_types()
21812199
mut concrete_types := []ast.Type{}
21822200
if p.expr_mod.len > 0 {
21832201
name = '${p.expr_mod}.${name}'
@@ -2195,7 +2213,7 @@ pub fn (mut p Parser) ident(language ast.Language) ast.Ident {
21952213
} else if allowed_cases && p.tok.kind == .key_orelse {
21962214
or_kind = ast.OrKind.block
21972215
or_stmts, or_pos = p.or_block(.no_err_var)
2198-
} else if is_known_generic_fn && p.tok.kind == .lsbr {
2216+
} else if is_following_concrete_types {
21992217
// `generic_fn[int]`
22002218
concrete_types = p.parse_concrete_types()
22012219
}

vlib/v/tests/generics_fn_variable_test.v

Lines changed: 21 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -4,17 +4,30 @@ fn func[T](x T, i int, f_ Fn[T]) T {
44
return f_(x, i)
55
}
66

7-
fn f[T](x T, i int) T {
7+
fn f1[T](x T, i int) T {
88
return x
99
}
1010

1111
fn test_generic_fn_variable() {
12-
ff := f[int]
13-
ret := ff(1, 11)
14-
println(ret)
15-
assert ret == 1
12+
ff1 := f1[int]
13+
ret1 := ff1(1, 11)
14+
println(ret1)
15+
assert ret1 == 1
1616

17-
x := func[f64](2.0, 3, f[f64])
18-
println(x)
19-
assert x == 2.0
17+
ff2 := f2[int]
18+
ret2 := ff2(1, 11)
19+
println(ret2)
20+
assert ret2 == 1
21+
22+
x1 := func[f64](2.0, 3, f1[f64])
23+
println(x1)
24+
assert x1 == 2.0
25+
26+
x2 := func[f64](2.0, 3, f2[f64])
27+
println(x2)
28+
assert x2 == 2.0
29+
}
30+
31+
fn f2[T](x T, i int) T {
32+
return x
2033
}

0 commit comments

Comments
 (0)