From 1fd0aceb42b7b3d12658cfdf0c6abe85cb693d42 Mon Sep 17 00:00:00 2001 From: zakuro Date: Sat, 27 Feb 2021 17:07:18 +0900 Subject: [PATCH] parser: imporve generics detection (#8992) --- vlib/v/parser/parser.v | 47 ++++++++++++++----- vlib/v/tests/generics_test.v | 18 +++++++ .../tests/modules/simplemodule/simplemodule.v | 2 + 3 files changed, 55 insertions(+), 12 deletions(-) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 72aa49c283..0fa59f425f 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1115,31 +1115,54 @@ pub fn (mut p Parser) parse_ident(language table.Language) ast.Ident { } } +fn (p &Parser) is_typename(t token.Token) bool { + return t.kind == .name && (t.lit.is_capital() || p.table.known_type(t.lit)) +} + +// heuristics to detect `func()` from `var < expr` +// 1. `f<[]` is generic(e.g. `f<[]int>`) because `var < []` is invalid +// 2. `f) +// 3. `f` is generic because `v1 < foo > v2` is invalid syntax +// 4. `f` is same as case 3 +// 6. `f 0 { p.tok.lit[0].is_capital() } else { false } + if lit0_is_capital || p.peek_tok.kind != .lt { + return false + } tok2 := p.peek_token(2) tok3 := p.peek_token(3) tok4 := p.peek_token(4) tok5 := p.peek_token(5) - // use heuristics to detect `func()` from `var < expr` - return !lit0_is_capital && p.peek_tok.kind == .lt && (match tok2.kind { - .name { - // (`f`, `f`, ``, assume `var < []` is invalid - tok3.kind == .rsbr + return match kind3 { + .gt { true } // case 3 + .comma { p.is_typename(tok2) } // case 4 + // case 5 and 6 + .dot { kind4 == .name && (kind5 == .gt || (kind5 == .comma && p.is_typename(tok4))) } + else { false } } - else { - false - } - }) + } + return false } pub fn (mut p Parser) name_expr() ast.Expr { diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index 21e3d3314d..e88fcfb46e 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -410,3 +410,21 @@ fn test_generic_init() { c.name = 'c' assert c.name == 'c' } + +fn test_generic_detection() { + v1, v2 := -1, 1 + + // not generic + a1, a2 := v1 v1 + assert a1 && a2 + b1, b2 := v1 v1 + assert b1 && b2 + + // generic + assert multi_generic_args(0, 's') + assert multi_generic_args(Foo1{}, Foo2{}) + assert multi_generic_args(simplemodule.Data{}, 0) + assert multi_generic_args(0, simplemodule.Data{}) + assert multi_generic_args<[]int, int>([]int{}, 0) + assert multi_generic_args(map[int]int{}, 0) +} diff --git a/vlib/v/tests/modules/simplemodule/simplemodule.v b/vlib/v/tests/modules/simplemodule/simplemodule.v index 31398309b1..8cc58ae8dc 100644 --- a/vlib/v/tests/modules/simplemodule/simplemodule.v +++ b/vlib/v/tests/modules/simplemodule/simplemodule.v @@ -16,3 +16,5 @@ pub struct Data { pub: value int } + +pub const zero = 0