parser: fix generic detection of `foo < bar<T>()` (#11434)
parent
cc8ee5fb84
commit
892971024e
|
@ -1871,13 +1871,14 @@ fn (p &Parser) is_typename(t token.Token) bool {
|
|||
// 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>` and `f<foo<` are generic because `v1 < foo > v2` and `v1 < foo < v2` are invalid syntax
|
||||
// 4. `f<Foo,` is generic when Foo is typename.
|
||||
// 3. `f<foo>` is generic because `v1 < foo > v2` is invalid syntax
|
||||
// 4. `f<foo<bar` is generic when bar is not generic T (f<foo<T>(), in contrast, is not generic!)
|
||||
// 5. `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. if there is a &, ignore the & and see if it is a type
|
||||
// 10. otherwise, it's not generic
|
||||
// 6. `f<mod.Foo>` is same as case 3
|
||||
// 7. `f<mod.Foo,` is same as case 5
|
||||
// 8. if there is a &, ignore the & and see if it is a type
|
||||
// 9. otherwise, it's not generic
|
||||
// see also test_generic_detection in vlib/v/tests/generics_test.v
|
||||
fn (p &Parser) is_generic_call() bool {
|
||||
lit0_is_capital := p.tok.kind != .eof && p.tok.lit.len > 0 && p.tok.lit[0].is_capital()
|
||||
|
@ -1911,9 +1912,10 @@ fn (p &Parser) is_generic_call() bool {
|
|||
return true
|
||||
}
|
||||
return match kind3 {
|
||||
.gt, .lt { true } // case 3
|
||||
.comma { p.is_typename(tok2) } // case 4
|
||||
// case 5 and 6
|
||||
.gt { true } // case 3
|
||||
.lt { !(tok4.lit.len == 1 && tok4.lit[0].is_capital()) } // case 4
|
||||
.comma { p.is_typename(tok2) } // case 5
|
||||
// case 6 and 7
|
||||
.dot { kind4 == .name && (kind5 == .gt || (kind5 == .comma && p.is_typename(tok4))) }
|
||||
else { false }
|
||||
}
|
||||
|
|
|
@ -65,7 +65,7 @@ fn min<T>(tree Tree<T>) T {
|
|||
1e100
|
||||
}
|
||||
Node<T> {
|
||||
if tree.value < (min<T>(tree.left)) {
|
||||
if tree.value < min<T>(tree.left) {
|
||||
tree.value
|
||||
} else {
|
||||
min<T>(tree.left)
|
||||
|
|
|
@ -68,6 +68,7 @@ fn test_postfix_expr() {
|
|||
assert minus_one(i16(-7)) == -8
|
||||
assert minus_one(int(-6)) == -7
|
||||
assert minus_one(i64(-5)) == -6
|
||||
|
||||
// the point is to see if it compiles, more than if the result
|
||||
// is correct, so 1e-6 isn't necessarily the right value to do this
|
||||
// but it's not important
|
||||
|
@ -370,6 +371,7 @@ fn test_generic_fn_with_variadics() {
|
|||
s := 'abc'
|
||||
i := 1
|
||||
abc := Abc{1, 2, 3}
|
||||
|
||||
// these calls should all compile, and print the arguments,
|
||||
// even though the arguments are all a different type and arity:
|
||||
p(s)
|
||||
|
@ -457,18 +459,28 @@ fn test_generic_init() {
|
|||
a << 'a'
|
||||
assert a.len == 1
|
||||
assert a[0] == 'a'
|
||||
|
||||
// map init
|
||||
mut b := new<map[string]string>()
|
||||
assert b.len == 0
|
||||
b['b'] = 'b'
|
||||
assert b.len == 1
|
||||
assert b['b'] == 'b'
|
||||
|
||||
// struct init
|
||||
mut c := new<User>()
|
||||
c.name = 'c'
|
||||
assert c.name == 'c'
|
||||
}
|
||||
|
||||
fn return_one<T>(rec int, useless T) T {
|
||||
// foo < bar<T>() should work
|
||||
if rec == 0 || 0 < return_one<T>(rec - 1, useless) {
|
||||
return T(1)
|
||||
}
|
||||
return T(0)
|
||||
}
|
||||
|
||||
fn test_generic_detection() {
|
||||
v1, v2 := -1, 1
|
||||
|
||||
|
@ -482,9 +494,11 @@ fn test_generic_detection() {
|
|||
assert multi_generic_args<int, string>(0, 's')
|
||||
assert multi_generic_args<Foo1, Foo2>(Foo1{}, Foo2{})
|
||||
assert multi_generic_args<Foo<int>, Foo<int> >(Foo<int>{}, Foo<int>{})
|
||||
|
||||
// TODO: assert multi_generic_args<Foo<int>, Foo<int>>(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)
|
||||
assert 0 < return_one<int>(10, 0)
|
||||
}
|
||||
|
|
Loading…
Reference in New Issue