mirror of
https://github.com/vlang/v.git
synced 2023-08-10 21:13:21 +03:00
checker: fix generic fn with short generic struct init syntax (#16828)
This commit is contained in:
parent
aaf3e25c3f
commit
51bb630ea4
@ -256,37 +256,29 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||||||
c.error('unknown type `${ct_sym.name}`', node.pos)
|
c.error('unknown type `${ct_sym.name}`', node.pos)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0 {
|
if struct_sym.info.generic_types.len > 0 && struct_sym.info.concrete_types.len == 0
|
||||||
if node.is_short_syntax {
|
&& !node.is_short_syntax {
|
||||||
concrete_types := c.infer_struct_generic_types(node.typ, node)
|
if c.table.cur_concrete_types.len == 0 {
|
||||||
if concrete_types.len > 0 {
|
c.error('generic struct init must specify type parameter, e.g. Foo[int]',
|
||||||
generic_names := struct_sym.info.generic_types.map(c.table.sym(it).name)
|
node.pos)
|
||||||
node.typ = c.table.unwrap_generic_type(node.typ, generic_names, concrete_types)
|
} else if node.generic_types.len == 0 {
|
||||||
return node.typ
|
c.error('generic struct init must specify type parameter, e.g. Foo[T]',
|
||||||
}
|
node.pos)
|
||||||
} else {
|
} else if node.generic_types.len > 0
|
||||||
if c.table.cur_concrete_types.len == 0 {
|
&& node.generic_types.len != struct_sym.info.generic_types.len {
|
||||||
c.error('generic struct init must specify type parameter, e.g. Foo[int]',
|
c.error('generic struct init expects ${struct_sym.info.generic_types.len} generic parameter, but got ${node.generic_types.len}',
|
||||||
node.pos)
|
node.pos)
|
||||||
} else if node.generic_types.len == 0 {
|
} else if node.generic_types.len > 0 && c.table.cur_fn != unsafe { nil } {
|
||||||
c.error('generic struct init must specify type parameter, e.g. Foo[T]',
|
for gtyp in node.generic_types {
|
||||||
node.pos)
|
if !gtyp.has_flag(.generic) {
|
||||||
} else if node.generic_types.len > 0
|
continue
|
||||||
&& node.generic_types.len != struct_sym.info.generic_types.len {
|
}
|
||||||
c.error('generic struct init expects ${struct_sym.info.generic_types.len} generic parameter, but got ${node.generic_types.len}',
|
gtyp_name := c.table.sym(gtyp).name
|
||||||
node.pos)
|
if gtyp_name !in c.table.cur_fn.generic_names {
|
||||||
} else if node.generic_types.len > 0 && c.table.cur_fn != unsafe { nil } {
|
cur_generic_names := '(' + c.table.cur_fn.generic_names.join(',') + ')'
|
||||||
for gtyp in node.generic_types {
|
c.error('generic struct init type parameter `${gtyp_name}` must be within the parameters `${cur_generic_names}` of the current generic function',
|
||||||
if !gtyp.has_flag(.generic) {
|
node.pos)
|
||||||
continue
|
break
|
||||||
}
|
|
||||||
gtyp_name := c.table.sym(gtyp).name
|
|
||||||
if gtyp_name !in c.table.cur_fn.generic_names {
|
|
||||||
cur_generic_names := '(' + c.table.cur_fn.generic_names.join(',') + ')'
|
|
||||||
c.error('generic struct init type parameter `${gtyp_name}` must be within the parameters `${cur_generic_names}` of the current generic function',
|
|
||||||
node.pos)
|
|
||||||
break
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -615,6 +607,17 @@ fn (mut c Checker) struct_init(mut node ast.StructInit) ast.Type {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
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)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
return node.typ
|
return node.typ
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -0,0 +1,22 @@
|
|||||||
|
struct Params[T] {
|
||||||
|
a []T
|
||||||
|
b int
|
||||||
|
}
|
||||||
|
|
||||||
|
fn take_input[T](p Params[T]) []f32 {
|
||||||
|
mut res := []f32{}
|
||||||
|
for x in p.a {
|
||||||
|
res << f32(x)
|
||||||
|
}
|
||||||
|
res << f32(p.b)
|
||||||
|
return res
|
||||||
|
}
|
||||||
|
|
||||||
|
fn test_generic_fn_with_generic_struct_init_syntax() {
|
||||||
|
a_in := [int(1), 2, 4]
|
||||||
|
res := take_input(a: a_in, b: 3)
|
||||||
|
|
||||||
|
// res := take_input(Params[int]{a: a_in, b: 3}) // this works
|
||||||
|
println(res)
|
||||||
|
assert res == [f32(1.0), 2.0, 4.0, 3.0]
|
||||||
|
}
|
Loading…
Reference in New Issue
Block a user