Skip to content

Commit

Permalink
checker: add checking for comptime assign without comptime if checking (
Browse files Browse the repository at this point in the history
fix #23796) (#23848)
  • Loading branch information
felipensp authored Mar 5, 2025
1 parent b60966c commit 52cd627
Show file tree
Hide file tree
Showing 6 changed files with 58 additions and 0 deletions.
5 changes: 5 additions & 0 deletions vlib/v/checker/assign.v
Original file line number Diff line number Diff line change
Expand Up @@ -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)
}
Expand Down
8 changes: 8 additions & 0 deletions vlib/v/checker/comptime.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand All @@ -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)
Expand Down Expand Up @@ -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) {
Expand Down Expand Up @@ -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
Expand All @@ -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
Expand Down
4 changes: 4 additions & 0 deletions vlib/v/checker/if.v
Original file line number Diff line number Diff line change
Expand Up @@ -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 {
Expand Down
7 changes: 7 additions & 0 deletions vlib/v/checker/tests/comptime_selector_assign.out
Original file line number Diff line number Diff line change
@@ -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 | }
31 changes: 31 additions & 0 deletions vlib/v/checker/tests/comptime_selector_assign.vv
Original file line number Diff line number Diff line change
@@ -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)
}
3 changes: 3 additions & 0 deletions vlib/v/type_resolver/type_resolver.v
Original file line number Diff line number Diff line change
Expand Up @@ -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
Expand Down

0 comments on commit 52cd627

Please sign in to comment.