Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

checker: add checking for comptime assign without comptime if checking #23848

Merged
merged 5 commits into from
Mar 5, 2025
Merged
Show file tree
Hide file tree
Changes from 2 commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
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('you should check the field type with \$if to avoid generating wrong assigning code',
node.right[i].pos())
}
left_type = c.comptime.comptime_for_field_type
c.expected_type = c.unwrap_generic(left_type)
}
Expand Down
4 changes: 4 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
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: you should check the field type with $if to avoid generating wrong assigning code
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
Loading