checker: check invalid comptime field name assignment (fix #24415) (#24421)

This commit is contained in:
Swastik Baranwal 2025-05-14 03:48:24 +05:30 committed by GitHub
parent 3bf8f4232a
commit 915ff40926
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
8 changed files with 54 additions and 4 deletions

View file

@ -876,13 +876,20 @@ or use an explicit `unsafe{ a[..] }`, if you do not want a copy of the slice.',
node.pos) node.pos)
} }
} else { } else {
// allow `t.$(field.name) = 0` where `t.$(field.name)` is a enum
if c.comptime.comptime_for_field_var != '' && left is ast.ComptimeSelector { 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() { if field_sym.kind == .enum && !right_type.is_int() {
c.error('enums can only be assigned `int` values', right.pos()) 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 { } else {
if right_type_unwrapped != ast.void_type { if right_type_unwrapped != ast.void_type {
if !var_option || (var_option && right_type_unwrapped != ast.none_type) { if !var_option || (var_option && right_type_unwrapped != ast.none_type) {

View file

@ -89,6 +89,7 @@ pub mut:
inside_fn_arg bool // `a`, `b` in `a.f(b)` inside_fn_arg bool // `a`, `b` in `a.f(b)`
inside_ct_attr bool // true inside `[if expr]` 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_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 anon_struct_should_be_mut bool // true when `mut var := struct { ... }` is used
inside_generic_struct_init bool inside_generic_struct_init bool
inside_integer_literal_cast bool // true inside `int(123)` 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_fn_arg = false
c.inside_ct_attr = false c.inside_ct_attr = false
c.inside_x_is_type = false c.inside_x_is_type = false
c.inside_x_matches_type = false
c.inside_integer_literal_cast = false c.inside_integer_literal_cast = false
c.skip_flags = false c.skip_flags = false
c.fn_level = 0 c.fn_level = 0

View file

@ -274,6 +274,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
has_different_types := fields.len > 1 has_different_types := fields.len > 1
&& !fields.all(c.check_basic(it.typ, fields[0].typ)) && !fields.all(c.check_basic(it.typ, fields[0].typ))
for field in fields { for field in fields {
prev_inside_x_matches_type := c.inside_x_matches_type
c.push_new_comptime_info() c.push_new_comptime_info()
c.comptime.inside_comptime_for = true c.comptime.inside_comptime_for = true
c.table.used_features.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.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 } else if node.typ != ast.void_type && c.table.generic_type_names(node.typ).len == 0
&& sym.kind != .placeholder { && sym.kind != .placeholder {

View file

@ -414,6 +414,7 @@ fn (mut c Checker) match_exprs(mut node ast.MatchExpr, cond_type_sym ast.TypeSym
} }
continue continue
} }
is_type_node := expr is ast.TypeNode
match mut expr { match mut expr {
ast.TypeNode { ast.TypeNode {
key = c.table.type_to_str(expr.typ) 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.error('match case `${key}` is handled more than once', branch.pos)
} }
c.expected_type = node.cond_type c.expected_type = node.cond_type
if is_type_node {
c.inside_x_matches_type = true
}
expr_type := c.expr(mut expr) expr_type := c.expr(mut expr)
if expr_type.idx() == 0 { if expr_type.idx() == 0 {
// parser failed, stop checking // parser failed, stop checking

View file

@ -1,7 +1,7 @@
vlib/v/checker/tests/assign_enum_at_comptime.vv:13:21: error: enums can only be assigned `int` values 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 { 12 | $for field in TestStruct.fields {
13 | t.$(field.name) = '1' 13 | t.$(field.name) = '1'
| ~~~ | ~~~
14 | } 14 | }
15 | } 15 | }

View file

@ -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

View file

@ -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}')
}

View file

@ -5,3 +5,10 @@ vlib/v/checker/tests/comptime_selector_assign.vv:18:24: error: mismatched types:
| ^ | ^
19 | } 19 | }
20 | } 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 | }