Skip to content

Commit c339ea2

Browse files
authored
checker, cgen: make comptime field.indirections working with logical operators (#17990)
1 parent 59d91e0 commit c339ea2

File tree

3 files changed

+137
-18
lines changed

3 files changed

+137
-18
lines changed

vlib/v/checker/comptime.v

Lines changed: 42 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -655,6 +655,19 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
655655
.eq, .ne {
656656
if cond.left is ast.SelectorExpr
657657
&& cond.right in [ast.IntegerLiteral, ast.StringLiteral] {
658+
if cond.right is ast.IntegerLiteral
659+
&& c.is_comptime_selector_field_name(cond.left as ast.SelectorExpr, 'indirections') {
660+
ret := match cond.op {
661+
.eq { c.comptime_fields_default_type.nr_muls() == cond.right.val.i64() }
662+
.ne { c.comptime_fields_default_type.nr_muls() != cond.right.val.i64() }
663+
else { false }
664+
}
665+
return if ret {
666+
ComptimeBranchSkipState.eval
667+
} else {
668+
ComptimeBranchSkipState.skip
669+
}
670+
}
658671
return .unknown
659672
// $if method.args.len == 1
660673
} else if cond.left is ast.SelectorExpr
@@ -711,6 +724,27 @@ fn (mut c Checker) comptime_if_branch(cond ast.Expr, pos token.Pos) ComptimeBran
711724
c.error('invalid `\$if` condition', cond.pos)
712725
}
713726
}
727+
.gt, .lt, .ge, .le {
728+
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral {
729+
if c.is_comptime_selector_field_name(cond.left as ast.SelectorExpr,
730+
'indirections')
731+
{
732+
ret := match cond.op {
733+
.gt { c.comptime_fields_default_type.nr_muls() > cond.right.val.i64() }
734+
.lt { c.comptime_fields_default_type.nr_muls() < cond.right.val.i64() }
735+
.ge { c.comptime_fields_default_type.nr_muls() >= cond.right.val.i64() }
736+
.le { c.comptime_fields_default_type.nr_muls() <= cond.right.val.i64() }
737+
else { false }
738+
}
739+
return if ret {
740+
ComptimeBranchSkipState.eval
741+
} else {
742+
ComptimeBranchSkipState.skip
743+
}
744+
}
745+
}
746+
c.error('invalid `\$if` condition', cond.pos)
747+
}
714748
else {
715749
c.error('invalid `\$if` condition', cond.pos)
716750
}
@@ -858,7 +892,14 @@ fn (mut c Checker) get_comptime_selector_type(node ast.ComptimeSelector, default
858892
return default_type
859893
}
860894

861-
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable accessing .typ field
895+
// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name`
896+
[inline]
897+
fn (mut c Checker) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool {
898+
return c.inside_comptime_for_field && node.expr is ast.Ident
899+
&& (node.expr as ast.Ident).name == c.comptime_for_field_var && node.field_name == field_name
900+
}
901+
902+
// is_comptime_selector_type checks if the SelectorExpr is related to $for variable accessing .typ field
862903
[inline]
863904
fn (mut c Checker) is_comptime_selector_type(node ast.SelectorExpr) bool {
864905
if c.inside_comptime_for_field && node.expr is ast.Ident {

vlib/v/gen/c/comptime.v

Lines changed: 63 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -537,28 +537,43 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
537537
.eq, .ne {
538538
// TODO Implement `$if method.args.len == 1`
539539
if cond.left is ast.SelectorExpr
540-
&& (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0)
541-
&& cond.right is ast.StringLiteral {
542-
selector := cond.left as ast.SelectorExpr
543-
if selector.expr is ast.Ident && selector.field_name == 'name' {
544-
if g.comptime_for_method_var.len > 0
545-
&& (selector.expr as ast.Ident).name == g.comptime_for_method_var {
546-
is_equal := g.comptime_for_method == cond.right.val
547-
if is_equal {
548-
g.write('1')
549-
} else {
550-
g.write('0')
540+
&& (g.comptime_for_field_var.len > 0 || g.comptime_for_method.len > 0) {
541+
if cond.right is ast.StringLiteral {
542+
selector := cond.left as ast.SelectorExpr
543+
if selector.expr is ast.Ident && selector.field_name == 'name' {
544+
if g.comptime_for_method_var.len > 0
545+
&& (selector.expr as ast.Ident).name == g.comptime_for_method_var {
546+
is_equal := g.comptime_for_method == cond.right.val
547+
if is_equal {
548+
g.write('1')
549+
} else {
550+
g.write('0')
551+
}
552+
return is_equal, true
553+
} else if g.comptime_for_field_var.len > 0
554+
&& (selector.expr as ast.Ident).name == g.comptime_for_field_var {
555+
is_equal := g.comptime_for_field_value.name == cond.right.val
556+
if is_equal {
557+
g.write('1')
558+
} else {
559+
g.write('0')
560+
}
561+
return is_equal, true
562+
}
563+
}
564+
} else if cond.right is ast.IntegerLiteral {
565+
if g.is_comptime_selector_field_name(cond.left, 'indirections') {
566+
is_true := match cond.op {
567+
.eq { g.comptime_for_field_type.nr_muls() == cond.right.val.i64() }
568+
.ne { g.comptime_for_field_type.nr_muls() != cond.right.val.i64() }
569+
else { false }
551570
}
552-
return is_equal, true
553-
} else if g.comptime_for_field_var.len > 0
554-
&& (selector.expr as ast.Ident).name == g.comptime_for_field_var {
555-
is_equal := g.comptime_for_field_value.name == cond.right.val
556-
if is_equal {
571+
if is_true {
557572
g.write('1')
558573
} else {
559574
g.write('0')
560575
}
561-
return is_equal, true
576+
return is_true, true
562577
}
563578
}
564579
}
@@ -611,6 +626,30 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
611626
return true, true
612627
}
613628
}
629+
.gt, .lt, .ge, .le {
630+
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral {
631+
if g.is_comptime_selector_field_name(cond.left as ast.SelectorExpr,
632+
'indirections')
633+
{
634+
is_true := match cond.op {
635+
.gt { g.comptime_for_field_type.nr_muls() > cond.right.val.i64() }
636+
.lt { g.comptime_for_field_type.nr_muls() < cond.right.val.i64() }
637+
.ge { g.comptime_for_field_type.nr_muls() >= cond.right.val.i64() }
638+
.le { g.comptime_for_field_type.nr_muls() <= cond.right.val.i64() }
639+
else { false }
640+
}
641+
if is_true {
642+
g.write('1')
643+
} else {
644+
g.write('0')
645+
}
646+
return is_true, true
647+
} else {
648+
return true, false
649+
}
650+
}
651+
return true, false
652+
}
614653
else {
615654
return true, false
616655
}
@@ -679,6 +718,13 @@ fn (mut g Gen) pop_existing_comptime_values() {
679718
g.comptime_var_type_map = old.comptime_var_type_map.clone()
680719
}
681720

721+
// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name`
722+
[inline]
723+
fn (mut g Gen) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool {
724+
return g.inside_comptime_for_field && node.expr is ast.Ident
725+
&& (node.expr as ast.Ident).name == g.comptime_for_field_var && node.field_name == field_name
726+
}
727+
682728
// check_comptime_is_field_selector checks if the SelectorExpr is related to $for variable accessing .typ field
683729
[inline]
684730
fn (mut g Gen) is_comptime_selector_type(node ast.SelectorExpr) bool {
Lines changed: 32 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,32 @@
1+
struct Encoder {}
2+
3+
struct Writer {}
4+
5+
struct StructType[T] {
6+
mut:
7+
val &T
8+
val2 T
9+
}
10+
11+
fn (e &Encoder) encode_struct[U](val U, mut wr Writer) ! {
12+
$for field in U.fields {
13+
if field.indirections == 1 {
14+
assert field.indirections == 1
15+
value := val.$(field.name)
16+
$if field.indirections == 1 {
17+
assert *value == 'ads'
18+
} $else {
19+
assert false
20+
}
21+
} else {
22+
assert field.name == 'val2'
23+
}
24+
}
25+
}
26+
27+
fn test_indirection_checking() {
28+
e := Encoder{}
29+
mut sb := Writer{}
30+
mut string_pointer := 'ads'
31+
e.encode_struct(StructType[string]{ val: &string_pointer }, mut sb)!
32+
}

0 commit comments

Comments
 (0)