From 4f8a3dafb3c434d6472955187ed15cba92761a2f Mon Sep 17 00:00:00 2001 From: Felipe Pena Date: Sat, 16 Aug 2025 20:17:56 -0300 Subject: [PATCH] checker: fix missing check for struct generic init from call (fix #25084) (#25119) --- vlib/v/checker/struct.v | 9 +++++++++ .../tests/generic_field_init_with_call_err.out | 7 +++++++ .../tests/generic_field_init_with_call_err.vv | 18 ++++++++++++++++++ ...t_with_inconsistent_generic_types_3_err.out | 7 +++++++ ...t_with_inconsistent_generic_types_3_err.vv} | 2 +- 5 files changed, 42 insertions(+), 1 deletion(-) create mode 100644 vlib/v/checker/tests/generic_field_init_with_call_err.out create mode 100644 vlib/v/checker/tests/generic_field_init_with_call_err.vv create mode 100644 vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.out rename vlib/v/{tests/generics/generics_struct_init_with_inconsistent_generic_types_3_test.v => checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.vv} (87%) diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index 649cfd4d3..6e0d774bc 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -848,6 +848,15 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', c.error('cannot assign `nil` to struct field `${init_field.name}` with type `${expected_type_sym.name}`', init_field.expr.pos.extend(init_field.expr.expr.pos())) } + if mut init_field.expr is ast.CallExpr + && init_field.expr.return_type.has_flag(.generic) { + expected_type := c.unwrap_generic(init_field.expected_type) + got_type_ret := c.unwrap_generic(init_field.expr.return_type) + if expected_type != got_type_ret { + c.error('cannot assign `${c.table.type_to_str(got_type_ret)}` to struct field `${init_field.name}` with type `${c.table.type_to_str(expected_type)}`', + init_field.expr.pos) + } + } } if !node.has_update_expr { c.check_uninitialized_struct_fields_and_embeds(node, type_sym, mut info, mut diff --git a/vlib/v/checker/tests/generic_field_init_with_call_err.out b/vlib/v/checker/tests/generic_field_init_with_call_err.out new file mode 100644 index 000000000..190f4f491 --- /dev/null +++ b/vlib/v/checker/tests/generic_field_init_with_call_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generic_field_init_with_call_err.vv:12:10: error: cannot assign `map[int]int` to struct field `items` with type `map[int]u8` + 10 | pub fn CustomSet.new[T](elements []T) CustomSet[T] { + 11 | return CustomSet[T]{ + 12 | items: to_map[T, int, T, int](invert[T, int](from_array[T](elements)), fn [T](key T, _ int) (T, int) { + | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ + 13 | return key, 10000 + 14 | }) diff --git a/vlib/v/checker/tests/generic_field_init_with_call_err.vv b/vlib/v/checker/tests/generic_field_init_with_call_err.vv new file mode 100644 index 000000000..311a0bf7e --- /dev/null +++ b/vlib/v/checker/tests/generic_field_init_with_call_err.vv @@ -0,0 +1,18 @@ +module main + +import maps { from_array, invert, to_map } + +struct CustomSet[T] { +mut: + items map[T]u8 +} + +pub fn CustomSet.new[T](elements []T) CustomSet[T] { + return CustomSet[T]{ + items: to_map[T, int, T, int](invert[T, int](from_array[T](elements)), fn [T](key T, _ int) (T, int) { + return key, 10000 + }) + } +} + +dump(CustomSet.new([1])) diff --git a/vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.out b/vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.out new file mode 100644 index 000000000..9ee65c23c --- /dev/null +++ b/vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.vv:12:25: error: cannot assign `string` to struct field `val` with type `int` + 10 | pub fn (me Maybe[T]) map[T, U](f fn (T) U) Maybe[U] { + 11 | if me.present { + 12 | return Maybe[U]{true, f(me.val)} + | ~~~~~~~~~ + 13 | } + 14 | return Maybe[U]{} diff --git a/vlib/v/tests/generics/generics_struct_init_with_inconsistent_generic_types_3_test.v b/vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.vv similarity index 87% rename from vlib/v/tests/generics/generics_struct_init_with_inconsistent_generic_types_3_test.v rename to vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.vv index b6b06a23a..ba1f7ae3d 100644 --- a/vlib/v/tests/generics/generics_struct_init_with_inconsistent_generic_types_3_test.v +++ b/vlib/v/checker/tests/generics_struct_init_with_inconsistent_generic_types_3_err.vv @@ -22,7 +22,7 @@ pub fn (o Maybe[T]) get() ?T { } } -fn test_generics_struct_init_with_inconsistent_generic_types() { +fn main() { m := some[int](12) ret := m.map[int, string](fn (i int) string { return i.str() -- 2.39.5