Skip to content

Commit 039c9b2

Browse files
authored
cgen, checker: fix comptimeselector resolution + if comptime branching improvement + comptimeselector cleanup (#17302)
1 parent 5a8c433 commit 039c9b2

File tree

12 files changed

+88
-62
lines changed

12 files changed

+88
-62
lines changed

vlib/v/ast/str.v

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -385,7 +385,7 @@ pub fn (x Expr) str() string {
385385
}
386386
}
387387
ComptimeSelector {
388-
return '${x.left}.$${x.field_expr}'
388+
return '${x.left}.$(${x.field_expr})'
389389
}
390390
ConcatExpr {
391391
return x.vals.map(it.str()).join(',')

vlib/v/checker/assign.v

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -296,6 +296,7 @@ fn (mut c Checker) assign_stmt(mut node ast.AssignStmt) {
296296
}
297297
if right is ast.ComptimeSelector {
298298
left.obj.is_comptime_field = true
299+
left.obj.typ = c.comptime_fields_default_type
299300
}
300301
}
301302
ast.GlobalField {

vlib/v/checker/check_types.v

Lines changed: 6 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -873,19 +873,12 @@ fn (mut c Checker) infer_fn_generic_types(func ast.Fn, mut node ast.CallExpr) {
873873
typ = ast.new_type(idx).derive(arg.typ)
874874
} else if c.inside_comptime_for_field && sym.kind in [.struct_, .any]
875875
&& arg.expr is ast.ComptimeSelector {
876-
compselector := arg.expr as ast.ComptimeSelector
877-
if compselector.field_expr is ast.SelectorExpr {
878-
selectorexpr := compselector.field_expr as ast.SelectorExpr
879-
if selectorexpr.expr is ast.Ident {
880-
ident := selectorexpr.expr as ast.Ident
881-
if ident.name == c.comptime_for_field_var {
882-
typ = c.comptime_fields_default_type
883-
884-
if func.return_type.has_flag(.generic)
885-
&& gt_name == c.table.type_to_str(func.return_type) {
886-
node.comptime_ret_val = true
887-
}
888-
}
876+
comptime_typ := c.get_comptime_selector_type(arg.expr, ast.void_type)
877+
if comptime_typ != ast.void_type {
878+
typ = comptime_typ
879+
if func.return_type.has_flag(.generic)
880+
&& gt_name == c.table.type_to_str(func.return_type) {
881+
node.comptime_ret_val = true
889882
}
890883
}
891884
}

vlib/v/checker/checker.v

Lines changed: 0 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -2688,15 +2688,6 @@ pub fn (mut c Checker) expr(node_ ast.Expr) ast.Type {
26882688
// return ast.void_type
26892689
// }
26902690

2691-
fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type {
2692-
if node.field_expr is ast.SelectorExpr
2693-
&& c.check_comptime_is_field_selector(node.field_expr as ast.SelectorExpr)
2694-
&& (node.field_expr as ast.SelectorExpr).field_name == 'name' {
2695-
return c.comptime_fields_default_type
2696-
}
2697-
return default_type
2698-
}
2699-
27002691
fn (mut c Checker) cast_expr(mut node ast.CastExpr) ast.Type {
27012692
// Given: `Outside( Inside(xyz) )`,
27022693
// node.expr_type: `Inside`

vlib/v/checker/comptime.v

Lines changed: 19 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -146,7 +146,7 @@ fn (mut c Checker) comptime_call(mut node ast.ComptimeCall) ast.Type {
146146

147147
fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
148148
node.left_type = c.expr(node.left)
149-
expr_type := c.unwrap_generic(c.expr(node.field_expr))
149+
mut expr_type := c.unwrap_generic(c.expr(node.field_expr))
150150
expr_sym := c.table.sym(expr_type)
151151
if expr_type != ast.string_type {
152152
c.error('expected `string` instead of `${expr_sym.name}` (e.g. `field.name`)',
@@ -158,6 +158,10 @@ fn (mut c Checker) comptime_selector(mut node ast.ComptimeSelector) ast.Type {
158158
c.error('compile time field access can only be used when iterating over `T.fields`',
159159
left_pos)
160160
}
161+
expr_type = c.get_comptime_selector_type(node, ast.void_type)
162+
if expr_type != ast.void_type {
163+
return expr_type
164+
}
161165
expr_name := node.field_expr.expr.str()
162166
if expr_name in c.comptime_fields_type {
163167
return c.comptime_fields_type[expr_name]
@@ -755,6 +759,18 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
755759
return .unknown
756760
}
757761

762+
// get_comptime_selector_type retrieves the var.$(field.name) type when field_name is 'name' otherwise default_type is returned
763+
[inline]
764+
fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default_type ast.Type) ast.Type {
765+
if node.field_expr is ast.SelectorExpr
766+
&& c.check_comptime_is_field_selector(node.field_expr as ast.SelectorExpr)
767+
&& (node.field_expr as ast.SelectorExpr).field_name == 'name' {
768+
return c.unwrap_generic(c.comptime_fields_default_type)
769+
}
770+
return default_type
771+
}
772+
773+
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable
758774
[inline]
759775
fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool {
760776
if c.inside_comptime_for_field && node.expr is ast.Ident {
@@ -763,6 +779,7 @@ fn (mut c Checker) check_comptime_is_field_selector(node ast.SelectorExpr) bool
763779
return false
764780
}
765781

782+
// check_comptime_is_field_selector_bool checks if the SelectorExpr is related to field.is_* boolean fields
766783
[inline]
767784
fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr) bool {
768785
if c.check_comptime_is_field_selector(node) {
@@ -772,6 +789,7 @@ fn (mut c Checker) check_comptime_is_field_selector_bool(node ast.SelectorExpr)
772789
return false
773790
}
774791

792+
// get_comptime_selector_bool_field evaluates the bool value for field.is_* fields
775793
fn (mut c Checker) get_comptime_selector_bool_field(field_name string) bool {
776794
field := c.comptime_for_field_value
777795
field_typ := c.comptime_fields_default_type

vlib/v/checker/for.v

Lines changed: 4 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -37,15 +37,6 @@ fn (mut c Checker) for_c_stmt(node ast.ForCStmt) {
3737
c.in_for_count--
3838
}
3939

40-
fn (mut c Checker) get_compselector_type_from_selector_name(node ast.ComptimeSelector) (bool, ast.Type) {
41-
if c.inside_comptime_for_field && node.field_expr is ast.SelectorExpr
42-
&& (node.field_expr as ast.SelectorExpr).expr.str() in c.comptime_fields_type
43-
&& (node.field_expr as ast.SelectorExpr).field_name == 'name' {
44-
return true, c.unwrap_generic(c.comptime_fields_default_type)
45-
}
46-
return false, ast.void_type
47-
}
48-
4940
fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
5041
c.in_for_count++
5142
prev_loop_label := c.loop_label
@@ -97,10 +88,10 @@ fn (mut c Checker) for_in_stmt(mut node ast.ForInStmt) {
9788
node.val_is_ref = node.cond.op == .amp
9889
}
9990
ast.ComptimeSelector {
100-
found, selector_type := c.get_compselector_type_from_selector_name(node.cond)
101-
if found {
102-
sym = c.table.final_sym(selector_type)
103-
typ = selector_type
91+
comptime_typ := c.get_comptime_selector_type(node.cond, ast.void_type)
92+
if comptime_typ != ast.void_type {
93+
sym = c.table.final_sym(comptime_typ)
94+
typ = comptime_typ
10495
}
10596
}
10697
ast.Ident {

vlib/v/checker/if.v

Lines changed: 31 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,22 @@ import v.ast
66
import v.pref
77
import v.token
88

9+
fn (mut c Checker) check_compatible_types(left_type ast.Type, right ast.TypeNode) ComptimeBranchSkipState {
10+
right_type := c.unwrap_generic(right.typ)
11+
sym := c.table.sym(right_type)
12+
13+
if sym.kind == .interface_ {
14+
checked_type := c.unwrap_generic(left_type)
15+
return if c.table.does_type_implement_interface(checked_type, right_type) {
16+
.eval
17+
} else {
18+
.skip
19+
}
20+
} else {
21+
return if left_type == right_type { .eval } else { .skip }
22+
}
23+
}
24+
925
fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
1026
if_kind := if node.is_comptime { '\$if' } else { 'if' }
1127
mut node_is_expr := false
@@ -121,22 +137,25 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
121137
comptime_field_name = left.expr.str()
122138
c.comptime_fields_type[comptime_field_name] = got_type
123139
is_comptime_type_is_expr = true
124-
} else if right is ast.TypeNode && left is ast.TypeNode
125-
&& sym.kind == .interface_ {
126-
is_comptime_type_is_expr = true
127-
// is interface
128-
checked_type := c.unwrap_generic(left.typ)
129-
skip_state = if c.table.does_type_implement_interface(checked_type,
130-
got_type)
131-
{
132-
.eval
133-
} else {
134-
.skip
140+
if comptime_field_name == c.comptime_for_field_var {
141+
left_type := c.unwrap_generic(c.comptime_fields_default_type)
142+
if left.field_name == 'typ' {
143+
skip_state = c.check_compatible_types(left_type, right as ast.TypeNode)
144+
} else if left.field_name == 'unaliased_typ' {
145+
skip_state = c.check_compatible_types(c.table.unaliased_type(left_type),
146+
right as ast.TypeNode)
147+
}
148+
} else if c.check_comptime_is_field_selector_bool(left) {
149+
skip_state = if c.get_comptime_selector_bool_field(left.field_name) {
150+
.eval
151+
} else {
152+
.skip
153+
}
135154
}
136155
} else if left is ast.TypeNode {
137156
is_comptime_type_is_expr = true
138157
left_type := c.unwrap_generic(left.typ)
139-
skip_state = if left_type == got_type { .eval } else { .skip }
158+
skip_state = c.check_compatible_types(left_type, right as ast.TypeNode)
140159
}
141160
}
142161
}

vlib/v/checker/postfix.v

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -24,9 +24,7 @@ fn (mut c Checker) postfix_expr(mut node ast.PostfixExpr) ast.Type {
2424
}
2525
if !(typ_sym.is_number() || ((c.inside_unsafe || c.pref.translated) && is_non_void_pointer)) {
2626
if c.inside_comptime_for_field {
27-
if c.is_comptime_var(node.expr) {
28-
return c.comptime_fields_default_type
29-
} else if node.expr is ast.ComptimeSelector {
27+
if c.is_comptime_var(node.expr) || node.expr is ast.ComptimeSelector {
3028
return c.comptime_fields_default_type
3129
}
3230
}

vlib/v/checker/struct.v

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -647,8 +647,7 @@ fn (mut c Checker) struct_init(mut node ast.StructInit, is_field_zero_struct_ini
647647
node.update_expr_type = update_type
648648
if node.update_expr is ast.ComptimeSelector {
649649
c.error('cannot use struct update syntax in compile time expressions', node.update_expr_pos)
650-
}
651-
if c.table.final_sym(update_type).kind != .struct_ {
650+
} else if c.table.final_sym(update_type).kind != .struct_ {
652651
s := c.table.type_to_str(update_type)
653652
c.error('expected struct, found `${s}`', node.update_expr.pos())
654653
} else if update_type != node.typ {
Lines changed: 5 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
1-
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: c
2-
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: d
3-
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: 1
4-
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: 0
5-
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$field.name: struct {
1+
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): c
2+
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): d
3+
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): 1
4+
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): 0
5+
[vlib/v/checker/tests/comptime_dump_fields_var_test.vv:13] val.$(field.name): struct {
66
i: 100
77
}
88
ok

0 commit comments

Comments
 (0)