checker: add checking for comptime assign without comptime if checking (fix #23796) (#23848)

This commit is contained in:
Felipe Pena 2025-03-05 16:28:14 -03:00 committed by GitHub
parent b60966cd10
commit 52cd6276b3
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
6 changed files with 58 additions and 0 deletions

View file

@ -187,6 +187,11 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
&& c.table.sym(left_type).kind in [.array, .map, .struct]
}
if c.comptime.comptime_for_field_var != '' && mut left is ast.ComptimeSelector {
if c.comptime.has_different_types && node.right[i].is_literal()
&& !c.comptime.inside_comptime_if {
c.error('mismatched types: check field type with \$if to avoid this problem',
node.right[i].pos())
}
left_type = c.comptime.comptime_for_field_type
c.expected_type = c.unwrap_generic(left_type)
}

View file

@ -271,6 +271,8 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
return
}
}
has_different_types := fields.len > 1
&& !fields.all(c.check_basic(it.typ, fields[0].typ))
for field in fields {
c.push_new_comptime_info()
c.comptime.inside_comptime_for = true
@ -283,6 +285,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
c.type_resolver.update_ct_type(node.val_var, c.field_data_type)
c.type_resolver.update_ct_type('${node.val_var}.typ', node.typ)
c.comptime.comptime_for_field_type = field.typ
c.comptime.has_different_types = has_different_types
c.stmts(mut node.stmts)
unwrapped_expr_type := c.unwrap_generic(field.typ)
@ -809,6 +812,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr
} else if cond.left in [ast.Ident, ast.SelectorExpr, ast.TypeNode] {
// `$if method.type is string`
c.expr(mut cond.left)
c.comptime.inside_comptime_if = true
if mut cond.left is ast.SelectorExpr && cond.right is ast.ComptimeType {
comptime_type := cond.right as ast.ComptimeType
if c.comptime.is_comptime_selector_type(cond.left) {
@ -1075,6 +1079,8 @@ fn (mut c Checker) push_new_comptime_info() {
c.type_resolver.info_stack << type_resolver.ResolverInfo{
saved_type_map: c.type_resolver.type_map.clone()
inside_comptime_for: c.comptime.inside_comptime_for
inside_comptime_if: c.comptime.inside_comptime_if
has_different_types: c.comptime.has_different_types
comptime_for_variant_var: c.comptime.comptime_for_variant_var
comptime_for_field_var: c.comptime.comptime_for_field_var
comptime_for_field_type: c.comptime.comptime_for_field_type
@ -1091,6 +1097,8 @@ fn (mut c Checker) pop_comptime_info() {
old := c.type_resolver.info_stack.pop()
c.type_resolver.type_map = old.saved_type_map.clone()
c.comptime.inside_comptime_for = old.inside_comptime_for
c.comptime.inside_comptime_if = old.inside_comptime_if
c.comptime.has_different_types = old.has_different_types
c.comptime.comptime_for_variant_var = old.comptime_for_variant_var
c.comptime.comptime_for_field_var = old.comptime_for_field_var
c.comptime.comptime_for_field_type = old.comptime_for_field_type

View file

@ -53,6 +53,10 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
mut skip_state := ComptimeBranchSkipState.unknown
mut found_branch := false // Whether a matching branch was found- skip the rest
mut is_comptime_type_is_expr := false // if `$if T is string`
last_in_comptime_if := c.comptime.inside_comptime_if
defer {
c.comptime.inside_comptime_if = last_in_comptime_if
}
for i in 0 .. node.branches.len {
mut branch := node.branches[i]
if branch.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {

View file

@ -0,0 +1,7 @@
vlib/v/checker/tests/comptime_selector_assign.vv:18:24: error: mismatched types: check field type with $if to avoid this problem
16 | typ.$(field.name) = 2
17 | }
18 | typ.$(field.name) = 3
| ^
19 | }
20 | }

View file

@ -0,0 +1,31 @@
import x.json2 { Any, raw_decode }
struct Income {
mut:
email string
code int
}
pub fn structuring[T](res Any) T {
mut typ := T{}
res_map := res.as_map()
$for field in T.fields {
if field.name in res_map {
$if field.typ is int {
typ.$(field.name) = 2
}
typ.$(field.name) = 3
}
}
return typ
}
fn main() {
res := raw_decode('{
"email": ["sdvsdv", "sds"],
"code": 12
}')!.as_map()
structuring[Income](res)
}

View file

@ -15,6 +15,9 @@ pub mut:
comptime_loop_id int
// $for
inside_comptime_for bool
// $if
inside_comptime_if bool
has_different_types bool
// .variants
comptime_for_variant_var string
// .fields