parser: imporve generics detection (#8992)
parent
81cf6f7ea2
commit
1fd0aceb42
|
@ -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<T>()` from `var < expr`
|
||||||
|
// 1. `f<[]` is generic(e.g. `f<[]int>`) because `var < []` is invalid
|
||||||
|
// 2. `f<map[` is generic(e.g. `f<map[string]string>)
|
||||||
|
// 3. `f<foo>` is generic because `v1 < foo > v2` is invalid syntax
|
||||||
|
// 4. `f<Foo,` is generic when Foo is typename.
|
||||||
|
// otherwise it is not generic because it may be multi-value (e.g. `return f < foo, 0`).
|
||||||
|
// 5. `f<mod.Foo>` is same as case 3
|
||||||
|
// 6. `f<mod.Foo,` is same as case 4
|
||||||
|
// 7. otherwise, it's not generic
|
||||||
|
// see also test_generic_detection in vlib/v/tests/generics_test.v
|
||||||
fn (p &Parser) is_generic_call() bool {
|
fn (p &Parser) is_generic_call() bool {
|
||||||
lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 {
|
lit0_is_capital := if p.tok.kind != .eof && p.tok.lit.len > 0 {
|
||||||
p.tok.lit[0].is_capital()
|
p.tok.lit[0].is_capital()
|
||||||
} else {
|
} else {
|
||||||
false
|
false
|
||||||
}
|
}
|
||||||
|
if lit0_is_capital || p.peek_tok.kind != .lt {
|
||||||
|
return false
|
||||||
|
}
|
||||||
tok2 := p.peek_token(2)
|
tok2 := p.peek_token(2)
|
||||||
tok3 := p.peek_token(3)
|
tok3 := p.peek_token(3)
|
||||||
tok4 := p.peek_token(4)
|
tok4 := p.peek_token(4)
|
||||||
tok5 := p.peek_token(5)
|
tok5 := p.peek_token(5)
|
||||||
// use heuristics to detect `func<T>()` from `var < expr`
|
kind2, kind3, kind4, kind5 := tok2.kind, tok3.kind, tok4.kind, tok5.kind
|
||||||
return !lit0_is_capital && p.peek_tok.kind == .lt && (match tok2.kind {
|
|
||||||
.name {
|
|
||||||
// (`f<int>`, `f<string,`) || (`f<mod.Type>`, `<mod.Type,`) || `f<map[`,
|
|
||||||
|
|
||||||
tok3.kind in [.gt, .comma] || (tok3.kind == .dot && tok4.kind == .name && tok5.kind in [.gt, .comma]) || (tok2.lit == 'map' && tok3.kind == .lsbr)
|
if kind2 == .lsbr {
|
||||||
|
// case 1
|
||||||
|
return tok3.kind == .rsbr
|
||||||
|
}
|
||||||
|
|
||||||
|
if kind2 == .name {
|
||||||
|
if tok2.lit == 'map' && kind3 == .lsbr {
|
||||||
|
// case 2
|
||||||
|
return true
|
||||||
}
|
}
|
||||||
.lsbr {
|
return match kind3 {
|
||||||
// maybe `f<[]T>`, assume `var < []` is invalid
|
.gt { true } // case 3
|
||||||
tok3.kind == .rsbr
|
.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 {
|
pub fn (mut p Parser) name_expr() ast.Expr {
|
||||||
|
|
|
@ -410,3 +410,21 @@ fn test_generic_init() {
|
||||||
c.name = 'c'
|
c.name = 'c'
|
||||||
assert c.name == 'c'
|
assert c.name == 'c'
|
||||||
}
|
}
|
||||||
|
|
||||||
|
fn test_generic_detection() {
|
||||||
|
v1, v2 := -1, 1
|
||||||
|
|
||||||
|
// not generic
|
||||||
|
a1, a2 := v1<v2, v2> v1
|
||||||
|
assert a1 && a2
|
||||||
|
b1, b2 := v1 <simplemodule.zero, v2> v1
|
||||||
|
assert b1 && b2
|
||||||
|
|
||||||
|
// generic
|
||||||
|
assert multi_generic_args<int, string>(0, 's')
|
||||||
|
assert multi_generic_args<Foo1, Foo2>(Foo1{}, Foo2{})
|
||||||
|
assert multi_generic_args<simplemodule.Data, int>(simplemodule.Data{}, 0)
|
||||||
|
assert multi_generic_args<int, simplemodule.Data>(0, simplemodule.Data{})
|
||||||
|
assert multi_generic_args<[]int, int>([]int{}, 0)
|
||||||
|
assert multi_generic_args<map[int]int, int>(map[int]int{}, 0)
|
||||||
|
}
|
||||||
|
|
|
@ -16,3 +16,5 @@ pub struct Data {
|
||||||
pub:
|
pub:
|
||||||
value int
|
value int
|
||||||
}
|
}
|
||||||
|
|
||||||
|
pub const zero = 0
|
||||||
|
|
Loading…
Reference in New Issue