From 892971024e78cd0b3efd4e01ab0fb927a7d76525 Mon Sep 17 00:00:00 2001 From: Ruofan XU <47302112+SleepyRoy@users.noreply.github.com> Date: Wed, 8 Sep 2021 10:54:15 +0800 Subject: [PATCH] parser: fix generic detection of `foo < bar()` (#11434) --- vlib/v/parser/parser.v | 20 +++++++++++--------- vlib/v/tests/generic_complex_sumtype_test.v | 2 +- vlib/v/tests/generics_test.v | 14 ++++++++++++++ 3 files changed, 26 insertions(+), 10 deletions(-) diff --git a/vlib/v/parser/parser.v b/vlib/v/parser/parser.v index 80fefcdde6..eff7017105 100644 --- a/vlib/v/parser/parser.v +++ b/vlib/v/parser/parser.v @@ -1871,13 +1871,14 @@ fn (p &Parser) is_typename(t token.Token) bool { // heuristics to detect `func()` from `var < expr` // 1. `f<[]` is generic(e.g. `f<[]int>`) because `var < []` is invalid // 2. `f) -// 3. `f` and `f v2` and `v1 < foo < v2` are invalid syntax -// 4. `f` is generic because `v1 < foo > v2` is invalid syntax +// 4. `f(), in contrast, is not generic!) +// 5. `f` is same as case 3 -// 6. `f` is same as case 3 +// 7. `f 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 } } diff --git a/vlib/v/tests/generic_complex_sumtype_test.v b/vlib/v/tests/generic_complex_sumtype_test.v index 06f2789701..923145b9df 100644 --- a/vlib/v/tests/generic_complex_sumtype_test.v +++ b/vlib/v/tests/generic_complex_sumtype_test.v @@ -65,7 +65,7 @@ fn min(tree Tree) T { 1e100 } Node { - if tree.value < (min(tree.left)) { + if tree.value < min(tree.left) { tree.value } else { min(tree.left) diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index 7467d56fb4..01bd47ee3d 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -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() assert b.len == 0 b['b'] = 'b' assert b.len == 1 assert b['b'] == 'b' + // struct init mut c := new() c.name = 'c' assert c.name == 'c' } +fn return_one(rec int, useless T) T { + // foo < bar() should work + if rec == 0 || 0 < return_one(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(0, 's') assert multi_generic_args(Foo1{}, Foo2{}) assert multi_generic_args, Foo >(Foo{}, Foo{}) + // TODO: assert multi_generic_args, Foo>(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) + assert 0 < return_one(10, 0) }