cgen,checker: add $if sizeof(T) == int_literal { support (#24831)

This commit is contained in:
kbkpbot 2025-07-03 03:29:16 +08:00 committed by GitHub
parent 35af6a8d12
commit 3eb04e346c
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
4 changed files with 225 additions and 0 deletions

View File

@ -891,6 +891,7 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr
ComptimeBranchSkipState.skip
}
}
} else if cond.left is ast.SizeOf {
} else {
c.error('invalid `\$if` condition: ${cond.left.type_name()}',
cond.pos)
@ -920,6 +921,8 @@ fn (mut c Checker) comptime_if_cond(mut cond ast.Expr, pos token.Pos) ComptimeBr
if cond.left is ast.SelectorExpr && cond.right is ast.IntegerLiteral
&& c.comptime.is_comptime_selector_field_name(cond.left, 'indirections') {
return .unknown
} else if cond.left is ast.SizeOf {
return .unknown
}
c.error('invalid `\$if` condition', cond.pos)
}

View File

@ -349,6 +349,61 @@ fn (mut c Checker) if_expr(mut node ast.IfExpr) ast.Type {
}
else {}
}
} else if left is ast.SizeOf && right is ast.IntegerLiteral {
// TODO: support struct.fieldname
typ := c.unwrap_generic(left.typ)
if typ == 0 {
c.error('invalid `\$if` condition: expected a type', branch.cond.left.pos())
} else {
s, _ := c.table.type_size(c.unwrap_generic(typ))
skip_state = match branch.cond.op {
.gt {
if s > right.val.i64() {
ComptimeBranchSkipState.eval
} else {
ComptimeBranchSkipState.skip
}
}
.lt {
if s < right.val.i64() {
ComptimeBranchSkipState.eval
} else {
ComptimeBranchSkipState.skip
}
}
.ge {
if s >= right.val.i64() {
ComptimeBranchSkipState.eval
} else {
ComptimeBranchSkipState.skip
}
}
.le {
if s <= right.val.i64() {
ComptimeBranchSkipState.eval
} else {
ComptimeBranchSkipState.skip
}
}
.ne {
if s != right.val.i64() {
ComptimeBranchSkipState.eval
} else {
ComptimeBranchSkipState.skip
}
}
.eq {
if s == right.val.i64() {
ComptimeBranchSkipState.eval
} else {
ComptimeBranchSkipState.skip
}
}
else {
ComptimeBranchSkipState.skip
}
}
}
}
}
}

View File

@ -685,6 +685,23 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
g.write(' ${cond.op} ')
r, d2 := g.comptime_if_cond(cond.right, pkg_exist)
return if cond.op == .eq { l == r } else { l != r }, d1 && d1 == d2
}
if cond.left is ast.SizeOf && cond.left.typ != 0
&& cond.right is ast.IntegerLiteral {
// TODO: support struct.fieldname
s, _ := g.table.type_size(g.unwrap_generic(cond.left.typ))
right := cond.right as ast.IntegerLiteral
is_true := match cond.op {
.eq { s == right.val.i64() }
.ne { s != right.val.i64() }
else { false }
}
if is_true {
g.write('1')
} else {
g.write('0')
}
return is_true, true
} else {
g.write('1')
return true, true
@ -748,6 +765,25 @@ fn (mut g Gen) comptime_if_cond(cond ast.Expr, pkg_exist bool) (bool, bool) {
g.write('0')
}
return is_true, true
}
if cond.left is ast.SizeOf && cond.left.typ != 0
&& cond.right is ast.IntegerLiteral {
// TODO: support struct.fieldname
s, _ := g.table.type_size(g.unwrap_generic(cond.left.typ))
right := cond.right as ast.IntegerLiteral
is_true := match cond.op {
.gt { s > right.val.i64() }
.lt { s < right.val.i64() }
.ge { s >= right.val.i64() }
.le { s <= right.val.i64() }
else { false }
}
if is_true {
g.write('1')
} else {
g.write('0')
}
return is_true, true
} else {
return true, false
}

View File

@ -0,0 +1,131 @@
struct MyStruct {
a u16
b u8
c u32
d u64
}
fn test_comptime_if_sizeof() {
f[u16]()
g[MyStruct]()
x := MyStruct{}
// TODO: support struct.fieldname
//$if sizeof(x.a) == 2 {
// assert true
//} $else {
// assert false
//}
//
//$if sizeof(x.d) != 2 {
// assert false
//} $else {
// assert true
//}
}
fn f[T]() {
$if sizeof(T) == 2 {
assert true
} $else {
assert false
}
$if sizeof(T) != 2 {
assert false
} $else {
assert true
}
$if sizeof(T) < 1 {
assert false
} $else {
assert true
}
$if sizeof(T) < 3 {
assert true
} $else {
assert false
}
$if sizeof(T) > 1 {
assert true
} $else {
assert false
}
$if sizeof(T) > 2 {
assert false
} $else {
assert true
}
$if sizeof(T) <= 2 {
assert true
} $else {
assert false
}
$if sizeof(T) <= 1 {
assert false
} $else {
assert true
}
$if sizeof(T) >= 2 {
assert true
} $else {
assert false
}
$if sizeof(T) >= 3 {
assert false
} $else {
assert true
}
}
fn g[T]() {
$if sizeof(T) == 16 {
assert true
} $else {
assert false
}
$if sizeof(T) != 16 {
assert false
} $else {
assert true
}
$if sizeof(T) < 17 {
assert true
} $else {
assert false
}
$if sizeof(T) < 15 {
assert false
} $else {
assert true
}
$if sizeof(T) > 15 {
assert true
} $else {
assert false
}
$if sizeof(T) > 16 {
assert false
} $else {
assert true
}
$if sizeof(T) <= 16 {
assert true
} $else {
assert false
}
$if sizeof(T) <= 15 {
assert false
} $else {
assert true
}
$if sizeof(T) >= 16 {
assert true
} $else {
assert false
}
$if sizeof(T) >= 17 {
assert false
} $else {
assert true
}
}