diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 6878e3bc9a..df435a069f 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -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 } diff --git a/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_test.v b/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_1_test.v similarity index 100% rename from vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_test.v rename to vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_1_test.v diff --git a/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_2_test.v b/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_2_test.v new file mode 100644 index 0000000000..9f9fda3ca4 --- /dev/null +++ b/vlib/v/tests/generic_fn_with_short_generic_struct_init_syntax_2_test.v @@ -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] +}