1
0
mirror of https://github.com/vlang/v.git synced 2023-08-10 21:13:21 +03:00

checker: implement infering generic struct types (#17717)

This commit is contained in:
yuyi 2023-03-21 02:42:53 +08:00 committed by GitHub
parent 977cd0d8df
commit 968b519be5
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
5 changed files with 46 additions and 33 deletions

View File

@ -297,11 +297,8 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
}
if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0
&& !node.is_short_syntax {
if c.table.cur_concrete_types.len == 0 {
c.error('generic struct init must specify type parameter, e.g. Foo[int]',
node.pos)
} else if node.generic_types.len == 0 {
&& !node.is_short_syntax && c.table.cur_concrete_types.len != 0 {
if node.generic_types.len == 0 {
c.error('generic struct init must specify type parameter, e.g. Foo[T]',
node.pos)
} else if node.generic_types.len > 0
@ -691,13 +688,12 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
}
}
if struct_sym.info is ast.Struct {
if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 {
if node.is_short_syntax {
concrete_types := c.infer_struct_generic_types(node.typ, node)
if concrete_types.len > 0 {
generic_names := struct_sym.info.generic_types.map(c.table.sym(it).name)
node.typ = c.table.unwrap_generic_type(node.typ, generic_names, concrete_types)
}
if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0
&& c.table.cur_concrete_types.len == 0 {
concrete_types := c.infer_struct_generic_types(node.typ, node)
if concrete_types.len > 0 {
generic_names := struct_sym.info.generic_types.map(c.table.sym(it).name)
node.typ = c.table.unwrap_generic_type(node.typ, generic_names, concrete_types)
}
}
}

View File

@ -3,12 +3,6 @@ vlib/v/checker/tests/generic_interface_err.vv:10:1: warning: unused variable: `i
9 | s := Struct{7}
10 | i := Interface(s)
| ^
vlib/v/checker/tests/generic_interface_err.vv:9:6: error: generic struct init must specify type parameter, e.g. Foo[int]
7 | }
8 |
9 | s := Struct{7}
| ~~~~~~~~~
10 | i := Interface(s)
vlib/v/checker/tests/generic_interface_err.vv:10:6: error: can not find method `method` on `Struct`, needed for interface: `Interface`
8 |
9 | s := Struct{7}

View File

@ -1,15 +1,8 @@
vlib/v/checker/tests/generics_struct_init_err.vv:58:8: error: generic struct init must specify type parameter, e.g. Foo[int]
56 | ret = holder_call_12(neg, 3)
57 | assert ret == -3
58 | ret = FnHolder1{neg}.call(4)
| ~~~~~~~~~~~~~~
59 | assert ret == -4
60 |
vlib/v/checker/tests/generics_struct_init_err.vv:67:8: error: generic struct init must specify type parameter, e.g. Foo[int]
vlib/v/checker/tests/generics_struct_init_err.vv:67:23: error: could not infer generic type `T` in call to `call`
65 | ret = holder_call_22(neg, 5)
66 | assert ret == -5
67 | ret = FnHolder2{neg}.call(6)
| ~~~~~~~~~~~~~~
| ~~~~~~~
68 | assert ret == -6
69 | }
vlib/v/checker/tests/generics_struct_init_err.vv:22:7: error: generic struct init must specify type parameter, e.g. Foo[T]

View File

@ -3,12 +3,6 @@ vlib/v/checker/tests/interface_generic_err.vv:8:1: warning: unused variable: `wh
7 | what := What{}
8 | why := Why(what)
| ~~~
vlib/v/checker/tests/interface_generic_err.vv:7:9: error: generic struct init must specify type parameter, e.g. Foo[int]
5 |
6 | // no segfault without generic
7 | what := What{}
| ~~~~~~
8 | why := Why(what)
vlib/v/checker/tests/interface_generic_err.vv:8:8: error: could not infer generic type `T` in interface `Why`
6 | // no segfault without generic
7 | what := What{}

View File

@ -0,0 +1,36 @@
struct Foo[T, U] {
a T
b U
}
fn test_generic_struct_types_infer() {
st11 := Foo{'two', 2}
println(st11.a)
println(st11.b)
assert st11.a == 'two'
assert st11.b == 2
st12 := Foo{
a: 'two'
b: 2
}
println(st12.a)
println(st12.b)
assert st12.a == 'two'
assert st12.b == 2
st21 := Foo{1, 'one'}
println(st21.a)
println(st21.b)
assert st21.a == 1
assert st21.b == 'one'
st22 := Foo{
a: 1
b: 'one'
}
println(st22.a)
println(st22.b)
assert st22.a == 1
assert st22.b == 'one'
}