diff --git a/vlib/v/scanner/scanner.v b/vlib/v/scanner/scanner.v index 1e0556e83f..91ef8beac9 100644 --- a/vlib/v/scanner/scanner.v +++ b/vlib/v/scanner/scanner.v @@ -919,63 +919,42 @@ fn (mut s Scanner) text_scan() token.Token { return s.new_token(.ge, '', 2) } else if nextc == `>` { if s.pos + 2 < s.text.len { - if s.text[s.pos + 2] == `=` { - s.pos += 2 - return s.new_token(.right_shift_assign, '', 3) - } else if s.last_lt >= 0 && s.pos - s.last_lt < 100 { - // an algorithm to discriminate two-level generic call and shift-right patterns - // such as `foo>(a)` vs `a, b := Foo{}>(baz)` - // @SleepyRoy if you have smarter algorithm :-) - // almost correct heuristics: 2-level generic call's last cannot be extremely long - // here we set the limit 100 which should be nice for real cases - // ...Bar> => - // int, []Foo, [20]f64, map[string][]bool => - // int, Foo, f64, bool + // an algorithm to decide it's generic or non-generic + // such as `foo>(a)` vs `a, b := Foo{}>(baz)` + // @SleepyRoy if you have smarter algorithm :-) + // almost correct heuristics: last of generic cannot be extremely long + // here we set the limit 100 which should be nice for real cases + // e.g. ...Bar, Baz_, [20]f64, map[string][]bool>> => + // int, Baz_, f64, bool + mut is_generic := true + if s.last_lt >= 0 && s.pos - s.last_lt < 100 { typs := s.text[s.last_lt + 1..s.pos].split(',').map(it.trim_space().trim_right('>').after(']')) - // if any typ is neither Type nor builtin, then the case is shift-right + // if any typ is neither Type nor builtin, then the case is non-generic for typ in typs { - // TODO: combine two ifs once logic shortcut with `.all()` is fixed - if typ.len == 0 { - if s.text[s.pos + 2] == `>` { - if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` { - s.pos += 3 - return s.new_token(.unsigned_right_shift_assign, - '', 4) - } - s.pos += 2 - return s.new_token(.unsigned_right_shift, '', - 3) - } - s.pos++ - return s.new_token(.right_shift, '', 2) - } - if !(typ[0].is_capital() && typ[1..].bytes().all(it.is_alnum())) - && typ !in ast.builtin_type_names { - if s.text[s.pos + 2] == `>` { - if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` { - s.pos += 3 - return s.new_token(.unsigned_right_shift_assign, - '', 4) - } - s.pos += 2 - return s.new_token(.unsigned_right_shift, '', - 3) - } - s.pos++ - return s.new_token(.right_shift, '', 2) + if typ.len == 0 + || (!(typ[0].is_capital() && typ[1..].bytes().all(it.is_alnum() + || it == `_`)) && typ !in ast.builtin_type_names) { + is_generic = false + break } } + } else { + is_generic = false + } + if is_generic { return s.new_token(.gt, '', 1) + } else if s.text[s.pos + 2] == `=` { + s.pos += 2 + return s.new_token(.right_shift_assign, '', 3) + } else if s.text[s.pos + 2] == `>` { + if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` { + s.pos += 3 + return s.new_token(.unsigned_right_shift_assign, '', 4) + } + s.pos += 2 + return s.new_token(.unsigned_right_shift, '', 3) } } - if s.text[s.pos + 2] == `>` { - if s.pos + 3 < s.text.len && s.text[s.pos + 3] == `=` { - s.pos += 3 - return s.new_token(.unsigned_right_shift_assign, '', 4) - } - s.pos += 2 - return s.new_token(.unsigned_right_shift, '', 3) - } s.pos++ return s.new_token(.right_shift, '', 2) } diff --git a/vlib/v/tests/generics_test.v b/vlib/v/tests/generics_test.v index 0a941bf83e..75c0ec889a 100644 --- a/vlib/v/tests/generics_test.v +++ b/vlib/v/tests/generics_test.v @@ -510,9 +510,9 @@ fn test_multi_level_generics() { two) == 20 } -struct Empty {} +struct Empty_ {} -fn (e1 Empty) < (e2 Empty) bool { +fn (e1 Empty_) < (e2 Empty_) bool { return true } @@ -551,11 +551,11 @@ fn test_generic_detection() { res1, res2 := foo < bar, baz >> (foo + 1 - 1) assert res1 assert res2 == 8 - res3, res4 := Empty{} < Empty{}, baz >> (foo + 1 - 1) + res3, res4 := Empty_{} < Empty_{}, baz >> (foo + 1 - 1) assert res3 assert res4 == 8 - assert boring_function>(TandU{ - t: Empty{} + assert boring_function>(TandU{ + t: Empty_{} u: 10 }) @@ -573,11 +573,11 @@ fn test_generic_detection() { }) // this final case challenges your scanner :-) - assert boring_function>, map[string][]int>>(TandU>, map[string][]int>{ - t: TandU>{ + assert boring_function>, map[string][]int>>(TandU>, map[string][]int>{ + t: TandU>{ t: 20 - u: MultiLevel{ - foo: Empty{} + u: MultiLevel{ + foo: Empty_{} } } u: {