scanner, fmt: fix multi-level generics (#11517)

pull/11529/head
Ruofan XU 2021-09-18 02:44:31 +08:00 committed by GitHub
parent 30e53c95c7
commit 9180647f99
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
4 changed files with 47 additions and 16 deletions

View File

@ -210,13 +210,14 @@ pub fn (mut f Fmt) short_module(name string) string {
return f.mod2alias[name]
}
if name.ends_with('>') {
x := name.trim_suffix('>').split('<')
if x.len == 2 {
main := f.short_module(x[0])
genlist := x[1].split(',')
genshorts := genlist.map(f.short_module(it)).join(',')
return '$main<$genshorts>'
generic_levels := name.trim_suffix('>').split('<')
mut res := '${f.short_module(generic_levels[0])}'
for i in 1 .. generic_levels.len {
genshorts := generic_levels[i].split(',').map(f.short_module(it)).join(',')
res += '<$genshorts'
}
res += '>'
return res
}
vals := name.split('.')
if vals.len < 2 {
@ -1585,15 +1586,11 @@ fn (mut f Fmt) write_generic_call_if_require(node ast.CallExpr) {
if node.concrete_types.len > 0 {
f.write('<')
for i, concrete_type in node.concrete_types {
f.write(f.table.type_to_str_using_aliases(concrete_type, f.mod2alias))
f.write(f.short_module(f.table.type_to_str_using_aliases(concrete_type, f.mod2alias)))
if i != node.concrete_types.len - 1 {
f.write(', ')
}
}
// avoid `<Foo<int>>` => `<Foo<int> >`
if f.out.last_n(1) == '>' {
f.write(' ')
}
f.write('>')
}
}

View File

@ -23,5 +23,5 @@ fn main() {
// generic
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>{})
assert multi_generic_args<Foo<int>, Foo<int>>(Foo<int>{}, Foo<int>{})
}

View File

@ -916,9 +916,14 @@ fn (mut s Scanner) text_scan() token.Token {
s.pos++
return s.new_token(.ge, '', 2)
} else if nextc == `>` {
if s.pos + 2 < s.text.len && s.text[s.pos + 2] == `=` {
s.pos += 2
return s.new_token(.right_shift_assign, '', 3)
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.text[s.pos + 2] in [`(`, `)`, `{`, `>`, `,`] {
// multi-level generics such as Foo<Bar<baz>>{ }, func<Bar<baz>>( ), etc
return s.new_token(.gt, '', 1)
}
}
s.pos++
return s.new_token(.right_shift, '', 2)

View File

@ -481,6 +481,35 @@ fn return_one<T>(rec int, useless T) T {
return T(0)
}
struct MultiLevel<T> {
foo T
}
fn get_multilevel_foo<T>(bar MultiLevel<T>) int {
return bar.foo.foo
}
fn get_multilevel_foo_2<T, U>(bar T, baz U) int {
return bar.foo.foo + baz.foo.foo
}
fn test_multi_level_generics() {
one := MultiLevel<int>{
foo: 10
}
two := MultiLevel<MultiLevel<int>>{
foo: one
}
assert two.foo.foo == 10
three := MultiLevel<MultiLevel<MultiLevel<int>>>{
foo: two
}
assert three.foo.foo.foo == 10
assert get_multilevel_foo<MultiLevel<int>>(two) == 10
assert get_multilevel_foo_2<MultiLevel<MultiLevel<int>>, MultiLevel<MultiLevel<int>>>(two,
two) == 20
}
fn test_generic_detection() {
v1, v2 := -1, 1
@ -493,7 +522,7 @@ fn test_generic_detection() {
// generic
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>{})
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)