parser: implement infering generic type parameters from receiver types (fix #5862) (#9870)

pull/9887/head
yuyi 2021-04-26 15:56:08 +08:00 committed by GitHub
parent f36e46bfde
commit 212b4fa089
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
11 changed files with 43 additions and 56 deletions

View File

@ -62,16 +62,28 @@ pub fn (node &FnDecl) stringify(t &Table, cur_mod string, m2a map[string]string)
if name in ['+', '-', '*', '/', '%', '<', '>', '==', '!=', '>=', '<='] {
f.write_string(' ')
}
mut add_para_types := true
if node.generic_names.len > 0 {
f.write_string('<')
for i, gname in node.generic_names {
is_last := i == node.generic_names.len - 1
f.write_string(gname)
if !is_last {
f.write_string(', ')
if node.is_method {
sym := t.get_type_symbol(node.params[0].typ)
if sym.info is Struct {
generic_names := sym.info.generic_types.map(t.get_type_symbol(it).name)
if generic_names == node.generic_names {
add_para_types = false
}
}
}
f.write_string('>')
if add_para_types {
f.write_string('<')
for i, gname in node.generic_names {
is_last := i == node.generic_names.len - 1
f.write_string(gname)
if !is_last {
f.write_string(', ')
}
}
f.write_string('>')
}
}
f.write_string('(')
for i, arg in node.params {

View File

@ -273,12 +273,13 @@ fn (mut p Parser) fn_decl() ast.FnDecl {
}
}
// <T>
generic_names := p.parse_generic_names()
// check generic receiver method has no generic names
if is_method && rec.typ.has_flag(.generic) && generic_names.len == 0
&& p.table.get_type_symbol(rec.typ).kind != .any {
p.error_with_pos('generic receiver method `$name` should add generic names, e.g. $name<T>',
name_pos)
mut generic_names := p.parse_generic_names()
// generic names can be infer with receiver's generic names
if is_method && rec.typ.has_flag(.generic) && generic_names.len == 0 {
sym := p.table.get_type_symbol(rec.typ)
if sym.info is ast.Struct {
generic_names = sym.info.generic_types.map(p.table.get_type_symbol(it).name)
}
}
// Args
args2, are_args_type_only, is_variadic := p.fn_args()

View File

@ -1,7 +0,0 @@
vlib/v/parser/tests/generic_multiple_receiver_method_has_no_generic_names_err.vv:6:20: error: generic receiver method `poll` should add generic names, e.g. poll<T>
4 | }
5 |
6 | fn (q Queue<A, B>) poll() A {
| ~~~~
7 | return q.buffer[0]
8 | }

View File

@ -1,13 +0,0 @@
struct Queue<A, B>{
buffer []A
size B
}
fn (q Queue<A, B>) poll() A {
return q.buffer[0]
}
fn main() {
q := Queue<string, int>{}
println(q)
}

View File

@ -1,7 +0,0 @@
vlib/v/parser/tests/generic_receiver_method_has_no_generic_names_err.vv:5:17: error: generic receiver method `poll` should add generic names, e.g. poll<T>
3 | }
4 |
5 | fn (q Queue<T>) poll() T {
| ~~~~
6 | return q.buffer[0]
7 | }

View File

@ -1,12 +0,0 @@
struct Queue<T>{
buffer []T
}
fn (q Queue<T>) poll() T {
return q.buffer[0]
}
fn main() {
q := Queue<int>{}
println(q)
}

View File

@ -4,7 +4,7 @@ mut:
buffer []&T
}
fn (mut s MyStruct<T>) add<T>(e &T) bool {
fn (mut s MyStruct<T>) add(e &T) bool {
s.buffer[0] = e
return true
}

View File

@ -0,0 +1,13 @@
struct Abc<T> {
value T
}
fn (s Abc<T>) get_value() T {
return s.value
}
fn test_generics_method_on_receiver_types() {
s := Abc<string>{'hello'}
println(s.get_value())
assert s.get_value() == 'hello'
}

View File

@ -18,7 +18,7 @@ fn group_new<T>(val ...T) Group<T> {
return g
}
fn (mut it Group<T>) next<T>() ?T {
fn (mut it Group<T>) next() ?T {
if it.index >= it.len {
return none
}

View File

@ -2,7 +2,7 @@ struct Num<T> {
num T
}
fn (num Num<T>) is_autom<T>() bool {
fn (num Num<T>) is_autom() bool {
return true
}

View File

@ -3,7 +3,7 @@ struct Foo<A, B> {
b B
}
fn (num Foo<A, B>) get_foo1<A, B>() (A, B) {
fn (num Foo<A, B>) get_foo1() (A, B) {
return num.a, num.b
}