comptime: fix T.indirections comparison (fix #24630) (#24636)

This commit is contained in:
Felipe Pena 2025-06-02 04:17:24 -03:00 committed by GitHub
parent 73ebf42015
commit bfc6d5469f
No known key found for this signature in database
GPG key ID: B5690EEEBB952194
5 changed files with 58 additions and 13 deletions

View file

@ -404,8 +404,8 @@ fn (mut vt Vet) const_decl(stmt ast.ConstDecl) {
fn (mut vt Vet) vet_empty_str(expr ast.InfixExpr) { fn (mut vt Vet) vet_empty_str(expr ast.InfixExpr) {
if expr.left is ast.SelectorExpr && expr.right is ast.IntegerLiteral { if expr.left is ast.SelectorExpr && expr.right is ast.IntegerLiteral {
operand := (expr.left as ast.SelectorExpr) // TODO: remove as-casts when multiple conds can be smart-casted. operand := (expr.left as ast.SelectorExpr) // TODO: remove as-casts when multiple conds can be smart-casted.
if operand.expr is ast.Ident && operand.expr.info.typ == ast.string_type_idx if operand.expr is ast.Ident && operand.field_name == 'len'
&& operand.field_name == 'len' { && operand.expr.info.typ == ast.string_type_idx {
if expr.op != .lt && expr.right.val == '0' { if expr.op != .lt && expr.right.val == '0' {
// Case: `var.len > 0`, `var.len == 0`, `var.len != 0` // Case: `var.len > 0`, `var.len == 0`, `var.len != 0`
op := if expr.op == .gt { '!=' } else { expr.op.str() } op := if expr.op == .gt { '!=' } else { expr.op.str() }

View file

@ -846,10 +846,14 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr
} }
} }
.eq, .ne { .eq, .ne {
if cond.left is ast.SelectorExpr if mut cond.left is ast.SelectorExpr
&& cond.right in [ast.IntegerLiteral, ast.StringLiteral] { && cond.right in [ast.IntegerLiteral, ast.StringLiteral] {
// $if field.indirections == 1 // $if field.indirections == 1
// $if method.args.len == 1 // $if method.args.len == 1
if cond.left.typ == 0 && cond.left.name_type == 0
&& (cond.left.expr is ast.Ident && cond.left.expr.name.len == 1) {
c.expr(mut cond.left)
}
return .unknown return .unknown
} else if cond.left is ast.SelectorExpr } else if cond.left is ast.SelectorExpr
&& c.comptime.check_comptime_is_field_selector_bool(cond.left) { && c.comptime.check_comptime_is_field_selector_bool(cond.left) {
@ -908,6 +912,11 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr
} }
} }
.gt, .lt, .ge, .le { .gt, .lt, .ge, .le {
if cond.left is ast.SelectorExpr && cond.left.typ == 0
&& cond.left.name_type == 0
&& (cond.left.expr is ast.Ident && cond.left.expr.name.len == 1) {
c.expr(mut cond.left)
}
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral
&& c.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { && c.comptime.is_comptime_selector_field_name(cond.left, 'indirections') {
return .unknown return .unknown

View file

@ -612,7 +612,8 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
.eq, .ne { .eq, .ne {
// TODO: Implement `$if method.args.len == 1` // TODO: Implement `$if method.args.len == 1`
if cond.left is ast.SelectorExpr && (g.comptime.comptime_for_field_var.len > 0 if cond.left is ast.SelectorExpr && (g.comptime.comptime_for_field_var.len > 0
|| g.comptime.comptime_for_method != unsafe { nil }) { || g.comptime.comptime_for_method != unsafe { nil }
|| cond.left.name_type != 0) {
if cond.right is ast.StringLiteral { if cond.right is ast.StringLiteral {
if cond.left.expr is ast.Ident && cond.left.field_name == 'name' { if cond.left.expr is ast.Ident && cond.left.field_name == 'name' {
if g.comptime.comptime_for_method_var.len > 0 if g.comptime.comptime_for_method_var.len > 0
@ -645,9 +646,14 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
} }
} else if cond.right is ast.IntegerLiteral { } else if cond.right is ast.IntegerLiteral {
if g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { if g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') {
left_muls := if cond.left.name_type != 0 {
g.unwrap_generic(cond.left.name_type).nr_muls()
} else {
g.comptime.comptime_for_field_type.nr_muls()
}
is_true := match cond.op { is_true := match cond.op {
.eq { g.comptime.comptime_for_field_type.nr_muls() == cond.right.val.i64() } .eq { left_muls == cond.right.val.i64() }
.ne { g.comptime.comptime_for_field_type.nr_muls() != cond.right.val.i64() } .ne { left_muls != cond.right.val.i64() }
else { false } else { false }
} }
if is_true { if is_true {
@ -723,11 +729,17 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
.gt, .lt, .ge, .le { .gt, .lt, .ge, .le {
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral
&& g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') { && g.comptime.is_comptime_selector_field_name(cond.left, 'indirections') {
left := cond.left as ast.SelectorExpr
left_muls := if left.name_type != 0 {
g.unwrap_generic(left.name_type).nr_muls()
} else {
g.comptime.comptime_for_field_type.nr_muls()
}
is_true := match cond.op { is_true := match cond.op {
.gt { g.comptime.comptime_for_field_type.nr_muls() > cond.right.val.i64() } .gt { left_muls > cond.right.val.i64() }
.lt { g.comptime.comptime_for_field_type.nr_muls() < cond.right.val.i64() } .lt { left_muls < cond.right.val.i64() }
.ge { g.comptime.comptime_for_field_type.nr_muls() >= cond.right.val.i64() } .ge { left_muls >= cond.right.val.i64() }
.le { g.comptime.comptime_for_field_type.nr_muls() <= cond.right.val.i64() } .le { left_muls <= cond.right.val.i64() }
else { false } else { false }
} }
if is_true { if is_true {

View file

@ -0,0 +1,23 @@
fn count_muls[T](val T) int {
mut nr_muls := 0
dump(T.indirections)
dump(typeof(val).indirections)
$if T.indirections > 0 {
nr_muls = (int(typeof(val).idx) >> 16) & 0xff
}
assert nr_muls == T.indirections
$if T.indirections != 0 {
nr_muls = (int(typeof(val).idx) >> 16) & 0xff
}
assert nr_muls == T.indirections
return nr_muls
}
fn test_main() {
val := ''
pval := &val
ppval := &pval
assert count_muls(val) == 0
assert count_muls(pval) == 1
assert count_muls(ppval) == 2
}

View file

@ -177,11 +177,12 @@ pub fn (mut t TypeResolver) get_comptime_selector_type(node ast.ComptimeSelector
return default_type return default_type
} }
// is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable accessing specific field name provided by `field_name` // is_comptime_selector_field_name checks if the SelectorExpr is related to $for variable or generic letter accessing specific field name provided by `field_name`
@[inline] @[inline]
pub fn (t &ResolverInfo) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool { pub fn (t &ResolverInfo) is_comptime_selector_field_name(node ast.SelectorExpr, field_name string) bool {
return t.comptime_for_field_var != '' && node.expr is ast.Ident return ((t.comptime_for_field_var != '' && node.expr is ast.Ident
&& node.expr.name == t.comptime_for_field_var && node.field_name == field_name && node.expr.name == t.comptime_for_field_var) || node.name_type != 0)
&& node.field_name == field_name
} }
// is_comptime_selector_type checks if the SelectorExpr is related to $for variable accessing .typ field // is_comptime_selector_type checks if the SelectorExpr is related to $for variable accessing .typ field