lang: const-aggregate comptime folds (PLAN-CONST-AGG step 3)
An array const's '.len' and 'K[<const idx>]' element reads, and a
struct const's field ('LIT.r'), fold as compile-time integer leaves —
usable in array dimensions and other constants' initializers. All
source-aware (the SELECTED author's elements, folded in the author's
context with the cyclic-definition frame); a const out-of-range index
diagnoses at fold time, never wraps.
- evalConstIntExpr gains the three ctx hooks (lookupConstAggLen /
lookupConstArrayElem / lookupConstStructField) + an index_expr arm;
all five ctx implementations extended (stateless tiers fold null).
- Array consts dual-register in module_const_map (value = the literal
node) so the folders see elements; bare reads still hit the GLOBAL
arm first, so no double emission.
- Untyped consts whose RHS is a const-aggregate leaf ('L :: K.len',
'E :: K[1]', 'R :: LIT.r') register in a pass 2b AFTER aggregates,
gated on the receiver naming a const aggregate — a namespaced member
('F :: m.PI_ISH') is never mis-typed by the count placeholder.
Examples: 0179 (folds in dims + const exprs), 1163 (OOB diagnostic).
This commit is contained in:
@@ -113,6 +113,15 @@ const ModuleConstCtx = struct {
|
||||
pub fn lookupDimName(self: ModuleConstCtx, name: []const u8) ?i64 {
|
||||
return moduleConstIntFramed(self.consts, self.table, name, self.frame);
|
||||
}
|
||||
pub fn lookupConstAggLen(_: ModuleConstCtx, _: []const u8) ?i64 {
|
||||
return null;
|
||||
}
|
||||
pub fn lookupConstArrayElem(_: ModuleConstCtx, _: []const u8, _: i64, _: ?ast.Span) ?i64 {
|
||||
return null;
|
||||
}
|
||||
pub fn lookupConstStructField(_: ModuleConstCtx, _: []const u8, _: []const u8) ?i64 {
|
||||
return null;
|
||||
}
|
||||
pub fn lookupPackLen(_: ModuleConstCtx, _: []const u8) ?i64 {
|
||||
return null;
|
||||
}
|
||||
@@ -329,17 +338,35 @@ pub fn evalConstIntExpr(node: *const Node, ctx: anytype) ?i64 {
|
||||
};
|
||||
if (obj_name) |on| {
|
||||
// `<pack>.len` resolves to the monomorphised arity (e.g. an
|
||||
// `inline for 0..xs.len` bound).
|
||||
if (std.mem.eql(u8, fa.field, "len")) break :blk ctx.lookupPackLen(on);
|
||||
// `inline for 0..xs.len` bound); `<array const>.len` to the
|
||||
// const's element count.
|
||||
if (std.mem.eql(u8, fa.field, "len")) {
|
||||
if (ctx.lookupPackLen(on)) |n| break :blk n;
|
||||
break :blk ctx.lookupConstAggLen(on);
|
||||
}
|
||||
// `<IntType>.min` / `.max` — the same fold the value path uses
|
||||
// (type_resolver), so `[u8.max]T` agrees with `u8.max` in
|
||||
// expression position. A `u64.max` (= -1 as i64) folds here too;
|
||||
// `foldDimU32` then rejects it as a negative array dimension.
|
||||
if (type_resolver.TypeResolver.integerLimitFor(on, fa.field)) |v| break :blk v;
|
||||
// A struct const's integer field (`LIT.r`) folds to the
|
||||
// SELECTED author's field value.
|
||||
if (ctx.lookupConstStructField(on, fa.field)) |v| break :blk v;
|
||||
}
|
||||
// Any other field access is not a compile-time integer leaf.
|
||||
break :blk null;
|
||||
},
|
||||
// `K[<const idx>]` over an ARRAY const folds to the element's value
|
||||
// (bounds-checked at fold time — out of range diagnoses, never wraps).
|
||||
.index_expr => |ie| blk: {
|
||||
const on: ?[]const u8 = switch (ie.object.data) {
|
||||
.identifier => |id| if (id.is_raw) null else id.name,
|
||||
else => null,
|
||||
};
|
||||
const name = on orelse break :blk null;
|
||||
const idx = evalConstIntExpr(ie.index, ctx) orelse break :blk null;
|
||||
break :blk ctx.lookupConstArrayElem(name, idx, node.span);
|
||||
},
|
||||
.unary_op => |u| switch (u.op) {
|
||||
.negate => {
|
||||
const v = evalConstIntExpr(u.operand, ctx) orelse return null;
|
||||
|
||||
Reference in New Issue
Block a user