feat: fold field_count/size_of/align_of as comptime constants
The int-returning type-query builtins now fold to a compile-time constant in const-required positions (`inline for` bound, array dimension), like a plain `K :: 3` const — previously they evaluated only as runtime values, so `[field_count(S)]T` and `inline for 0..field_count(S)` were rejected as "not a compile-time integer". This is what lets a `($T) -> Type` builder loop `inline for 0..field_count(T)` to assemble a member list from a type's fields (the `race` result synthesis). The shared comptime-int folder `evalConstIntExpr` (program_index.zig) gained a `.call => ctx.evalConstCallInt(node)` arm. The body-lowering ctx (`Lowering`) implements it — resolve the type arg via `resolveTypeArg`, return `memberCount orelse 0` / `typeSizeBytes` / `typeAlignBytes`, matching the runtime value path in lower/call.zig exactly. `SourceConstCtx` delegates to its wrapped Lowering; the stateless ctxs (`ModuleConstCtx`, `StatelessInner`, test `DimCtx`) stub null (they cannot resolve a type-expr arg). A non-type-query call / wrong arg count / unresolved type arg folds to null (not a comptime integer). Adversarially reviewed (SHIP): the fold matches the value path across every type kind, ctx coverage is complete, recursion is AST-depth bounded, no speculative spurious diagnostics, `orelse 0` is field_count's definitional value for non-aggregates (not a silent default). Locked by examples/comptime/0648-comptime-typequery-const-fold.sx. Suite green (820/0).
This commit is contained in:
39
examples/comptime/0648-comptime-typequery-const-fold.sx
Normal file
39
examples/comptime/0648-comptime-typequery-const-fold.sx
Normal file
@@ -0,0 +1,39 @@
|
||||
// Int-returning type-query builtins (`field_count` / `size_of` / `align_of`)
|
||||
// fold as comptime CONSTANTS — usable as an `inline for` bound and an array
|
||||
// dimension, exactly like a plain `K :: 3` const. Previously
|
||||
// they evaluated only as runtime values, so `[field_count(S)]T` and
|
||||
// `inline for 0..field_count(S)` were rejected as "not a compile-time integer".
|
||||
// (This is what lets a `($T) -> Type` builder loop `inline for 0..field_count(T)`
|
||||
// to assemble a variant list from a type's members — the `race` result synthesis.)
|
||||
#import "modules/std.sx";
|
||||
|
||||
S :: struct { a: i64; b: bool; c: f64; }
|
||||
E :: enum { X; Y; Z; W; }
|
||||
|
||||
main :: () -> i32 {
|
||||
// field_count as an inline-for bound
|
||||
s := 0;
|
||||
inline for 0..field_count(S) (i) { s = s + i; } // 0+1+2 = 3
|
||||
print("field_count(S) loop sum = {}\n", s);
|
||||
|
||||
// field_count as an array dimension; fill it in a folded loop
|
||||
xs : [field_count(S)]i64 = ---;
|
||||
inline for 0..field_count(S) (i) { xs[i] = i * 10; }
|
||||
print("array[field_count(S)] len = {} xs[2] = {}\n", xs.len, xs[2]);
|
||||
|
||||
// field_count of an enum (4 variants) driving a loop
|
||||
e := 0;
|
||||
inline for 0..field_count(E) (i) { e = e + 1; }
|
||||
print("field_count(E) = {}\n", e);
|
||||
|
||||
// size_of / align_of fold too
|
||||
bytes : [size_of(i64)]u8 = ---;
|
||||
print("size_of(i64) array len = {}\n", bytes.len);
|
||||
print("align_of(f64) = {}\n", align_of(f64));
|
||||
|
||||
// composed const expression as a dim
|
||||
ys : [field_count(S) + 1]i64 = ---;
|
||||
print("[field_count(S) + 1] len = {}\n", ys.len);
|
||||
|
||||
return 0;
|
||||
}
|
||||
@@ -0,0 +1 @@
|
||||
0
|
||||
@@ -0,0 +1 @@
|
||||
|
||||
@@ -0,0 +1,6 @@
|
||||
field_count(S) loop sum = 3
|
||||
array[field_count(S)] len = 3 xs[2] = 20
|
||||
field_count(E) = 4
|
||||
size_of(i64) array len = 8
|
||||
align_of(f64) = 8
|
||||
[field_count(S) + 1] len = 4
|
||||
Reference in New Issue
Block a user