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)
|
||||
}
|
||||
}
|
||||
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
|
||||
}
|
||||
} else {
|
||||
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 {
|
||||
c.error('generic struct init must specify type parameter, e.g. Foo[T]',
|
||||
node.pos)
|
||||
} else if node.generic_types.len > 0
|
||||
&& 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}',
|
||||
node.pos)
|
||||
} else if node.generic_types.len > 0 && c.table.cur_fn != unsafe { nil } {
|
||||
for gtyp in node.generic_types {
|
||||
if !gtyp.has_flag(.generic) {
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
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 {
|
||||
c.error('generic struct init must specify type parameter, e.g. Foo[T]',
|
||||
node.pos)
|
||||
} else if node.generic_types.len > 0
|
||||
&& 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}',
|
||||
node.pos)
|
||||
} else if node.generic_types.len > 0 && c.table.cur_fn != unsafe { nil } {
|
||||
for gtyp in node.generic_types {
|
||||
if !gtyp.has_flag(.generic) {
|
||||
continue
|
||||
}
|
||||
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
|
||||
}
|
||||
|
||||
|
@ -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