Skip to content

Commit a552a79

Browse files
authored
checker: fix comptime concrete type register (fix #17657) (#17659)
1 parent 828b809 commit a552a79

File tree

5 files changed

+125
-45
lines changed

5 files changed

+125
-45
lines changed

vlib/v/checker/checker.v

Lines changed: 0 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -73,7 +73,6 @@ pub mut:
7373
inside_ct_attr bool // true inside `[if expr]`
7474
inside_x_is_type bool // true inside the Type expression of `if x is Type {`
7575
inside_comptime_for_field bool
76-
inside_for_in_any_cond bool
7776
skip_flags bool // should `#flag` and `#include` be skipped
7877
fn_level int // 0 for the top level, 1 for `fn abc() {}`, 2 for a nested fn, etc
7978
smartcast_mut_pos token.Pos // match mut foo, if mut foo is Foo
@@ -95,7 +94,6 @@ mut:
9594
loop_label string // set when inside a labelled for loop
9695
vweb_gen_types []ast.Type // vweb route checks
9796
timers &util.Timers = util.get_timers()
98-
for_in_any_val_type ast.Type
9997
comptime_for_field_var string
10098
comptime_fields_default_type ast.Type
10199
comptime_fields_key_type ast.Type // key type on `$for k, v in val.$(field.name)`

vlib/v/checker/comptime.v

Lines changed: 11 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -10,15 +10,20 @@ import v.util
1010
import v.pkgconfig
1111
import v.checker.constants
1212

13+
[inline]
14+
fn (mut c Checker) get_comptime_var_type_from_kind(kind ast.ComptimeVarKind) ast.Type {
15+
return match kind {
16+
.key_var { c.comptime_fields_key_type }
17+
.value_var { c.comptime_fields_val_type }
18+
.field_var { c.comptime_fields_default_type }
19+
else { ast.void_type }
20+
}
21+
}
22+
1323
[inline]
1424
fn (mut c Checker) get_comptime_var_type(node ast.Expr) ast.Type {
1525
if node is ast.Ident && (node as ast.Ident).obj is ast.Var {
16-
return match (node.obj as ast.Var).ct_type_var {
17-
.key_var { c.comptime_fields_key_type }
18-
.value_var { c.comptime_fields_val_type }
19-
.field_var { c.comptime_fields_default_type }
20-
else { ast.void_type }
21-
}
26+
return c.get_comptime_var_type_from_kind((node.obj as ast.Var).ct_type_var)
2227
} else if node is ast.ComptimeSelector {
2328
return c.get_comptime_selector_type(node, ast.void_type)
2429
} else if node is ast.SelectorExpr && c.is_comptime_selector_type(node as ast.SelectorExpr) {

vlib/v/checker/fn.v

Lines changed: 35 additions & 32 deletions
Original file line numberDiff line numberDiff line change
@@ -1325,6 +1325,22 @@ fn (mut c Checker) fn_call(mut node ast.CallExpr, mut continue_check &bool) ast.
13251325
return func.return_type
13261326
}
13271327

1328+
fn (mut c Checker) get_comptime_args(node_ ast.CallExpr) map[int]ast.Type {
1329+
mut comptime_args := map[int]ast.Type{}
1330+
for i, call_arg in node_.args {
1331+
if call_arg.expr is ast.Ident {
1332+
if call_arg.expr.obj is ast.Var {
1333+
if call_arg.expr.obj.ct_type_var != .no_comptime {
1334+
comptime_args[i] = c.get_comptime_var_type_from_kind(call_arg.expr.obj.ct_type_var)
1335+
}
1336+
}
1337+
} else if call_arg.expr is ast.ComptimeSelector && c.is_comptime_var(call_arg.expr) {
1338+
comptime_args[i] = c.get_comptime_var_type(call_arg.expr)
1339+
}
1340+
}
1341+
return comptime_args
1342+
}
1343+
13281344
fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
13291345
left_type := c.expr(node.left)
13301346
if left_type == ast.void_type {
@@ -1518,8 +1534,26 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
15181534
concrete_types << concrete_type
15191535
}
15201536
}
1537+
if c.inside_comptime_for_field && concrete_types.len > 0 {
1538+
mut comptime_args := c.get_comptime_args(node)
1539+
mut comptime_types := concrete_types.clone()
1540+
for k, v in comptime_args {
1541+
arg_sym := c.table.sym(v)
1542+
if method.generic_names.len > 0 && arg_sym.kind == .array
1543+
&& method.params[k + 1].typ.has_flag(.generic)
1544+
&& c.table.final_sym(method.params[k + 1].typ).kind == .array {
1545+
comptime_types[k] = (arg_sym.info as ast.Array).elem_type
1546+
} else {
1547+
comptime_types[k] = v
1548+
}
1549+
}
1550+
if comptime_args.len > 0
1551+
&& c.table.register_fn_concrete_types(method.fkey(), comptime_types) {
1552+
c.need_recheck_generic_fns = true
1553+
}
1554+
}
15211555
if concrete_types.len > 0 {
1522-
if c.table.register_fn_concrete_types(node.fkey(), concrete_types) {
1556+
if c.table.register_fn_concrete_types(method.fkey(), concrete_types) {
15231557
c.need_recheck_generic_fns = true
15241558
}
15251559
}
@@ -1582,11 +1616,6 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
15821616
}
15831617

15841618
for i, mut arg in node.args {
1585-
param_idx := if method.is_variadic && i >= method.params.len - 1 {
1586-
method.params.len - 1
1587-
} else {
1588-
i + 1
1589-
}
15901619
if i > 0 || exp_arg_typ == ast.Type(0) {
15911620
exp_arg_typ = if method.is_variadic && i >= method.params.len - 1 {
15921621
method.params.last().typ
@@ -1601,32 +1630,6 @@ fn (mut c Checker) method_call(mut node ast.CallExpr) ast.Type {
16011630

16021631
mut got_arg_typ := c.check_expr_opt_call(arg.expr, c.expr(arg.expr))
16031632
node.args[i].typ = got_arg_typ
1604-
if c.inside_comptime_for_field && method.params[param_idx].typ.has_flag(.generic) {
1605-
arg_sym := c.table.sym(c.comptime_fields_default_type)
1606-
if arg_sym.kind == .array
1607-
&& c.table.sym(method.params[param_idx].typ).kind == .array {
1608-
if c.table.register_fn_concrete_types(method.fkey(), [
1609-
(arg_sym.info as ast.Array).elem_type,
1610-
])
1611-
{
1612-
c.need_recheck_generic_fns = true
1613-
}
1614-
} else {
1615-
if c.table.register_fn_concrete_types(method.fkey(), [
1616-
c.comptime_fields_default_type,
1617-
])
1618-
{
1619-
c.need_recheck_generic_fns = true
1620-
}
1621-
}
1622-
} else if c.inside_for_in_any_cond && method.params[param_idx].typ.has_flag(.generic) {
1623-
if c.table.register_fn_concrete_types(method.fkey(), [
1624-
c.for_in_any_val_type,
1625-
])
1626-
{
1627-
c.need_recheck_generic_fns = true
1628-
}
1629-
}
16301633
if no_type_promotion {
16311634
if got_arg_typ != exp_arg_typ {
16321635
c.error('cannot use `${c.table.sym(got_arg_typ).name}` as argument for `${method.name}` (`${exp_arg_sym.name}` expected)',

vlib/v/checker/for.v

Lines changed: 0 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -167,9 +167,6 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
167167
c.comptime_fields_val_type = value_type
168168
node.scope.update_ct_var_kind(node.val_var, .value_var)
169169
}
170-
171-
c.inside_for_in_any_cond = true
172-
c.for_in_any_val_type = value_type
173170
} else {
174171
if sym.kind == .map && !(node.key_var.len > 0 && node.val_var.len > 0) {
175172
c.error(
@@ -246,8 +243,6 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
246243
c.check_loop_label(node.label, node.pos)
247244
c.stmts(node.stmts)
248245
c.loop_label = prev_loop_label
249-
c.inside_for_in_any_cond = false
250-
c.for_in_any_val_type = 0
251246
c.in_for_count--
252247
}
253248

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
struct Encoder {}
2+
3+
struct StructType[T] {
4+
mut:
5+
val T
6+
}
7+
8+
fn encode_struct[U](val U) ! {
9+
$for field in U.fields {
10+
$if field.typ is $Map {
11+
for _, v in val.$(field.name) {
12+
encode_value_with_level(v)!
13+
}
14+
}
15+
}
16+
}
17+
18+
fn encode_value_with_level[T](val T) ! {
19+
$if T is $Struct {
20+
dump(val)
21+
println(encode_struct(val)!)
22+
} $else $if T is $Map {
23+
dump(val)
24+
} $else $if T is string {
25+
dump(val)
26+
}
27+
}
28+
29+
fn (e &Encoder) encode_struct[U](val U) ! {
30+
$for field in U.fields {
31+
$if field.typ is $Map {
32+
for _, v in val.$(field.name) {
33+
e.encode_value_with_level(v)!
34+
}
35+
}
36+
}
37+
}
38+
39+
fn (e &Encoder) encode_value_with_level[T](val T) ! {
40+
$if T is $Struct {
41+
dump(val)
42+
println(e.encode_struct(val)!)
43+
} $else $if T is $Map {
44+
dump(val)
45+
} $else $if T is string {
46+
dump(val)
47+
}
48+
}
49+
50+
fn test_method() ! {
51+
e := Encoder{}
52+
e.encode_struct(StructType[map[string]map[string]int]{
53+
val: {
54+
'1': {
55+
'val': 1
56+
}
57+
}
58+
})!
59+
e.encode_struct(StructType[map[string]string]{
60+
val: {
61+
'1': '1'
62+
}
63+
})!
64+
}
65+
66+
fn test_func() ! {
67+
encode_struct(StructType[map[string]map[string]int]{
68+
val: {
69+
'1': {
70+
'val': 1
71+
}
72+
}
73+
})!
74+
encode_struct(StructType[map[string]string]{
75+
val: {
76+
'1': '1'
77+
}
78+
})!
79+
}

0 commit comments

Comments
 (0)