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