From 915ff40926b53200aa2af6f34d4f308906d95cec Mon Sep 17 00:00:00 2001 From: Swastik Baranwal Date: Wed, 14 May 2025 03:48:24 +0530 Subject: [PATCH] checker: check invalid comptime field name assignment (fix #24415) (#24421) --- vlib/v/checker/assign.v | 11 ++++++++-- vlib/v/checker/checker.v | 2 ++ vlib/v/checker/comptime.v | 2 ++ vlib/v/checker/match.v | 4 ++++ .../checker/tests/assign_enum_at_comptime.out | 4 ++-- ...e_field_name_assign_incorrect_type_err.out | 7 +++++++ ...me_field_name_assign_incorrect_type_err.vv | 21 +++++++++++++++++++ .../tests/comptime_selector_assign.out | 7 +++++++ 8 files changed, 54 insertions(+), 4 deletions(-) create mode 100644 vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.out create mode 100644 vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.vv diff --git a/vlib/v/checker/assign.v b/vlib/v/checker/assign.v index 08eb112db3..ee04483558 100644 --- a/vlib/v/checker/assign.v +++ b/vlib/v/checker/assign.v @@ -876,13 +876,20 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.', node.pos) } } else { - // allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum if c.comptime.comptime_for_field_var != '' && left is ast.ComptimeSelector { - field_sym := c.table.sym(c.unwrap_generic(c.comptime.comptime_for_field_type)) + field_type := c.unwrap_generic(c.comptime.comptime_for_field_type) + field_sym := c.table.sym(field_type) + // allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum if field_sym.kind == .enum && !right_type.is_int() { c.error('enums can only be assigned `int` values', right.pos()) } + // disallow invalid `t.$(field.name)` type assignment + if !c.check_types(field_type, right_type) && !(c.inside_x_matches_type + || field_sym.kind == .enum) { + c.error('cannot assign to `${left}`: ${c.expected_msg(right_type, + field_type)}', right.pos()) + } } else { if right_type_unwrapped != ast.void_type { if !var_option || (var_option && right_type_unwrapped != ast.none_type) { diff --git a/vlib/v/checker/checker.v b/vlib/v/checker/checker.v index 472d9864fb..1ac6cf9a62 100644 --- a/vlib/v/checker/checker.v +++ b/vlib/v/checker/checker.v @@ -89,6 +89,7 @@ pub mut: inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_ct_attr bool // true inside `[if expr]` inside_x_is_type bool // true inside the Type expression of `if x is Type {` + inside_x_matches_type bool // true inside the match branch of `match x.type { Type {} }` anon_struct_should_be_mut bool // true when `mut var := struct { ... }` is used inside_generic_struct_init bool inside_integer_literal_cast bool // true inside `int(123)` @@ -192,6 +193,7 @@ fn (mut c Checker) reset_checker_state_at_start_of_new_file() { c.inside_fn_arg = false c.inside_ct_attr = false c.inside_x_is_type = false + c.inside_x_matches_type = false c.inside_integer_literal_cast = false c.skip_flags = false c.fn_level = 0 diff --git a/vlib/v/checker/comptime.v b/vlib/v/checker/comptime.v index dac0ba8d3f..4a8d110aee 100644 --- a/vlib/v/checker/comptime.v +++ b/vlib/v/checker/comptime.v @@ -274,6 +274,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { has_different_types := fields.len > 1 && !fields.all(c.check_basic(it.typ, fields[0].typ)) for field in fields { + prev_inside_x_matches_type := c.inside_x_matches_type c.push_new_comptime_info() c.comptime.inside_comptime_for = true c.table.used_features.comptime_for = true @@ -301,6 +302,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) { } } c.pop_comptime_info() + c.inside_x_matches_type = prev_inside_x_matches_type } } else if node.typ != ast.void_type && c.table.generic_type_names(node.typ).len == 0 && sym.kind != .placeholder { diff --git a/vlib/v/checker/match.v b/vlib/v/checker/match.v index cb597bd43d..59ed520a0e 100644 --- a/vlib/v/checker/match.v +++ b/vlib/v/checker/match.v @@ -414,6 +414,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym } continue } + is_type_node := expr is ast.TypeNode match mut expr { ast.TypeNode { key = c.table.type_to_str(expr.typ) @@ -438,6 +439,9 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym c.error('match case `${key}` is handled more than once', branch.pos) } c.expected_type = node.cond_type + if is_type_node { + c.inside_x_matches_type = true + } expr_type := c.expr(mut expr) if expr_type.idx() == 0 { // parser failed, stop checking diff --git a/vlib/v/checker/tests/assign_enum_at_comptime.out b/vlib/v/checker/tests/assign_enum_at_comptime.out index 7508ef78ec..c04a7dc259 100644 --- a/vlib/v/checker/tests/assign_enum_at_comptime.out +++ b/vlib/v/checker/tests/assign_enum_at_comptime.out @@ -1,7 +1,7 @@ vlib/v/checker/tests/assign_enum_at_comptime.vv:13:21: error: enums can only be assigned `int` values - 11 | + 11 | 12 | $for field in TestStruct.fields { 13 | t.$(field.name) = '1' | ~~~ 14 | } - 15 | } \ No newline at end of file + 15 | } diff --git a/vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.out b/vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.out new file mode 100644 index 0000000000..d4753585da --- /dev/null +++ b/vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.out @@ -0,0 +1,7 @@ +vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.vv:11:25: error: cannot assign to `t.$(field.name)`: expected `int`, not `string` + 9 | mut t := T{} + 10 | $for field in T.fields { + 11 | t.$(field.name) = data[field.name] + | ~~~~~~~~~~~~ + 12 | } + 13 | return t diff --git a/vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.vv b/vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.vv new file mode 100644 index 0000000000..bc908e7d09 --- /dev/null +++ b/vlib/v/checker/tests/comptime_field_name_assign_incorrect_type_err.vv @@ -0,0 +1,21 @@ +module main + +struct Record { +mut: + f1 int +} + +fn map_data[T](data map[string]string) T { + mut t := T{} + $for field in T.fields { + t.$(field.name) = data[field.name] + } + return t +} + +fn main() { + mut data := map[string]string{} + data['f1'] = '123' + t := map_data[Record](data) + println('bug1 : ${t}') +} diff --git a/vlib/v/checker/tests/comptime_selector_assign.out b/vlib/v/checker/tests/comptime_selector_assign.out index a17b7f28ca..5a01f24b39 100644 --- a/vlib/v/checker/tests/comptime_selector_assign.out +++ b/vlib/v/checker/tests/comptime_selector_assign.out @@ -5,3 +5,10 @@ vlib/v/checker/tests/comptime_selector_assign.vv:18:24: error: mismatched types: | ^ 19 | } 20 | } +vlib/v/checker/tests/comptime_selector_assign.vv:18:24: error: cannot assign to `typ.$(field.name)`: expected `string`, not `int literal` + 16 | typ.$(field.name) = 2 + 17 | } + 18 | typ.$(field.name) = 3 + | ^ + 19 | } + 20 | }