Skip to content

Commit 52cd627

Browse files
authored
checker: add checking for comptime assign without comptime if checking (fix #23796) (#23848)
1 parent b60966c commit 52cd627

File tree

6 files changed

+58
-0
lines changed

6 files changed

+58
-0
lines changed

vlib/v/checker/assign.v

+5
Original file line numberDiff line numberDiff line change
@@ -187,6 +187,11 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
187187
&& c.table.sym(left_type).kind in [.array, .map, .struct]
188188
}
189189
if c.comptime.comptime_for_field_var != '' && mut left is ast.ComptimeSelector {
190+
if c.comptime.has_different_types && node.right[i].is_literal()
191+
&& !c.comptime.inside_comptime_if {
192+
c.error('mismatched types: check field type with \$if to avoid this problem',
193+
node.right[i].pos())
194+
}
190195
left_type = c.comptime.comptime_for_field_type
191196
c.expected_type = c.unwrap_generic(left_type)
192197
}

vlib/v/checker/comptime.v

+8
Original file line numberDiff line numberDiff line change
@@ -271,6 +271,8 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
271271
return
272272
}
273273
}
274+
has_different_types := fields.len > 1
275+
&& !fields.all(c.check_basic(it.typ, fields[0].typ))
274276
for field in fields {
275277
c.push_new_comptime_info()
276278
c.comptime.inside_comptime_for = true
@@ -283,6 +285,7 @@ fn (mut c Checker) comptime_for(mut node ast.ComptimeFor) {
283285
c.type_resolver.update_ct_type(node.val_var, c.field_data_type)
284286
c.type_resolver.update_ct_type('${node.val_var}.typ', node.typ)
285287
c.comptime.comptime_for_field_type = field.typ
288+
c.comptime.has_different_types = has_different_types
286289
c.stmts(mut node.stmts)
287290

288291
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
809812
} else if cond.left in [ast.Ident, ast.SelectorExpr, ast.TypeNode] {
810813
// `$if method.type is string`
811814
c.expr(mut cond.left)
815+
c.comptime.inside_comptime_if = true
812816
if mut cond.left is ast.SelectorExpr && cond.right is ast.ComptimeType {
813817
comptime_type := cond.right as ast.ComptimeType
814818
if c.comptime.is_comptime_selector_type(cond.left) {
@@ -1075,6 +1079,8 @@ fn (mut c Checker) push_new_comptime_info() {
10751079
c.type_resolver.info_stack << type_resolver.ResolverInfo{
10761080
saved_type_map: c.type_resolver.type_map.clone()
10771081
inside_comptime_for: c.comptime.inside_comptime_for
1082+
inside_comptime_if: c.comptime.inside_comptime_if
1083+
has_different_types: c.comptime.has_different_types
10781084
comptime_for_variant_var: c.comptime.comptime_for_variant_var
10791085
comptime_for_field_var: c.comptime.comptime_for_field_var
10801086
comptime_for_field_type: c.comptime.comptime_for_field_type
@@ -1091,6 +1097,8 @@ fn (mut c Checker) pop_comptime_info() {
10911097
old := c.type_resolver.info_stack.pop()
10921098
c.type_resolver.type_map = old.saved_type_map.clone()
10931099
c.comptime.inside_comptime_for = old.inside_comptime_for
1100+
c.comptime.inside_comptime_if = old.inside_comptime_if
1101+
c.comptime.has_different_types = old.has_different_types
10941102
c.comptime.comptime_for_variant_var = old.comptime_for_variant_var
10951103
c.comptime.comptime_for_field_var = old.comptime_for_field_var
10961104
c.comptime.comptime_for_field_type = old.comptime_for_field_type

vlib/v/checker/if.v

+4
Original file line numberDiff line numberDiff line change
@@ -53,6 +53,10 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
5353
mut skip_state := ComptimeBranchSkipState.unknown
5454
mut found_branch := false // Whether a matching branch was found- skip the rest
5555
mut is_comptime_type_is_expr := false // if `$if T is string`
56+
last_in_comptime_if := c.comptime.inside_comptime_if
57+
defer {
58+
c.comptime.inside_comptime_if = last_in_comptime_if
59+
}
5660
for i in 0 .. node.branches.len {
5761
mut branch := node.branches[i]
5862
if branch.cond is ast.ParExpr && !c.pref.translated && !c.file.is_translated {
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
vlib/v/checker/tests/comptime_selector_assign.vv:18:24: error: mismatched types: check field type with $if to avoid this problem
2+
16 | typ.$(field.name) = 2
3+
17 | }
4+
18 | typ.$(field.name) = 3
5+
| ^
6+
19 | }
7+
20 | }
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,31 @@
1+
import x.json2 { Any, raw_decode }
2+
3+
struct Income {
4+
mut:
5+
email string
6+
code int
7+
}
8+
9+
pub fn structuring[T](res Any) T {
10+
mut typ := T{}
11+
res_map := res.as_map()
12+
13+
$for field in T.fields {
14+
if field.name in res_map {
15+
$if field.typ is int {
16+
typ.$(field.name) = 2
17+
}
18+
typ.$(field.name) = 3
19+
}
20+
}
21+
return typ
22+
}
23+
24+
fn main() {
25+
res := raw_decode('{
26+
"email": ["sdvsdv", "sds"],
27+
"code": 12
28+
}')!.as_map()
29+
30+
structuring[Income](res)
31+
}

vlib/v/type_resolver/type_resolver.v

+3
Original file line numberDiff line numberDiff line change
@@ -15,6 +15,9 @@ pub mut:
1515
comptime_loop_id int
1616
// $for
1717
inside_comptime_for bool
18+
// $if
19+
inside_comptime_if bool
20+
has_different_types bool
1821
// .variants
1922
comptime_for_variant_var string
2023
// .fields

0 commit comments

Comments
 (0)