From df8f8ae4d1612becd70ee0d387d09f6973081802 Mon Sep 17 00:00:00 2001 From: shove Date: Tue, 16 Jan 2024 02:08:31 +0800 Subject: [PATCH] checker: fix checking give const map as default or init value to struct fields (fix #20512) (#20546) --- vlib/v/checker/struct.v | 16 ++++++++++++++++ .../struct_field_init_and_default_is_map_err.out | 14 ++++++++++++++ .../struct_field_init_and_default_is_map_err.vv | 14 ++++++++++++++ 3 files changed, 44 insertions(+) create mode 100644 vlib/v/checker/tests/struct_field_init_and_default_is_map_err.out create mode 100644 vlib/v/checker/tests/struct_field_init_and_default_is_map_err.vv diff --git a/vlib/v/checker/struct.v b/vlib/v/checker/struct.v index d2d4161b6..92d3cd63e 100644 --- a/vlib/v/checker/struct.v +++ b/vlib/v/checker/struct.v @@ -101,6 +101,15 @@ fn (mut c Checker) struct_decl(mut node ast.StructDecl) { if field.has_default_expr { c.expected_type = field.typ field.default_expr_typ = c.expr(mut field.default_expr) + // disallow map `mut a = b` + field_sym := c.table.sym(field.typ) + expr_sym := c.table.sym(field.default_expr_typ) + if field_sym.kind == .map && expr_sym.kind == .map && field.default_expr.is_lvalue() + && field.is_mut + && (!field.default_expr_typ.is_ptr() || field.default_expr is ast.Ident) { + c.error('cannot copy map: call `clone` method (or use a reference)', + field.default_expr.pos()) + } for mut symfield in struct_sym.info.fields { if symfield.name == field.name { symfield.default_expr_typ = field.default_expr_typ @@ -606,6 +615,13 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini c.error('allocate `${got_type_sym.name}` on the heap for use in other functions', init_field.pos) } + // disallow `mut a: b`, when b is const map + if exp_type_sym.kind == .map && got_type_sym.kind == .map && !got_type.is_ptr() + && field_info.is_mut + && (init_field.expr is ast.Ident && init_field.expr.obj is ast.ConstField) { + c.error('cannot assign a const map to mut struct field, call `clone` method (or use a reference)', + init_field.expr.pos()) + } if exp_type_sym.kind == .array && got_type_sym.kind == .array { if init_field.expr is ast.IndexExpr && (init_field.expr as ast.IndexExpr).left is ast.Ident diff --git a/vlib/v/checker/tests/struct_field_init_and_default_is_map_err.out b/vlib/v/checker/tests/struct_field_init_and_default_is_map_err.out new file mode 100644 index 000000000..07ddb73d2 --- /dev/null +++ b/vlib/v/checker/tests/struct_field_init_and_default_is_map_err.out @@ -0,0 +1,14 @@ +vlib/v/checker/tests/struct_field_init_and_default_is_map_err.vv:7:25: error: cannot copy map: call `clone` method (or use a reference) + 5 | struct Foo { + 6 | mut: + 7 | field map[string]int = const_map + | ~~~~~~~~~ + 8 | } + 9 | +vlib/v/checker/tests/struct_field_init_and_default_is_map_err.vv:12:10: error: cannot assign a const map to mut struct field, call `clone` method (or use a reference) + 10 | fn main() { + 11 | _ = Foo{ + 12 | field: const_map + | ~~~~~~~~~ + 13 | } + 14 | } diff --git a/vlib/v/checker/tests/struct_field_init_and_default_is_map_err.vv b/vlib/v/checker/tests/struct_field_init_and_default_is_map_err.vv new file mode 100644 index 000000000..93935ac11 --- /dev/null +++ b/vlib/v/checker/tests/struct_field_init_and_default_is_map_err.vv @@ -0,0 +1,14 @@ +const const_map = { + 'key': 4 +} + +struct Foo { +mut: + field map[string]int = const_map +} + +fn main() { + _ = Foo{ + field: const_map + } +} -- 2.39.5