fix(ir): route every comptime-int through the shared evaluator (0083)
Attempts 1–4 fixed the array-dimension paths but the same length-0 fabrication class survived on every other site that resolves a compile-time integer. Unify them all on the single shared `program_index.evalConstIntExpr` so they cannot diverge: - All three Vector lane resolvers (resolveTypeCallWithBindings, resolveParameterizedWithBindings, resolveArrayLiteralType) and both generic value-param binders (instantiateGenericStruct, instantiateTypeFunction) hand-rolled an `else => 0` switch. A module-const lane `Vector(N, f32)` fabricated a 0-lane `<0 x float>` (LLVM "huge alignment" abort); a value-param `Vec(N, f32)` fabricated a 0 binding / wrong mangled name. They now fold through the shared evaluator and emit a clean diagnostic + `.unresolved` on a non-const operand (resolveVectorLane / resolveValueParamArg) — never 0. - evalComptimeInt (inline-for bounds) delegated to the shared evaluator, so `inline for 0..M` / `0..(M+1)` fold like array dims. The `<pack>.len` leaf moved into the shared folder via a new `ctx.lookupPackLen`. - The unknown-type semantic checker no longer walks a value-param position (`Vector(N, …)` / `Vec(N, …)`) as a type name (was reporting "unknown type 'N'"). - The parameterized-type-arg parser and the function-body lookahead (hasFnBodyAfterArrow) accept a const-EXPRESSION in a value position, so `Vector(M + 1, f32)` and `[M + 1]T` parse as a return type too (the latter a pre-existing array-dim sibling that the same heuristic broke). Regressions: examples/1501 (named-const + const-expr lane, direct + alias, 3/4-lane reads), 1502 (runtime lane clean-halts, exit 1, no LLVM crash), 0207 (Vec(N)/Vec(M+1) == Vec(3) instantiation), 0610 (inline-for const bounds). Shared-evaluator unit test extended with the pack-len arm. zig build && zig build test && bash tests/run_examples.sh: 395 passed, 0 failed.
This commit is contained in:
@@ -612,6 +612,20 @@ pub const UnknownTypeChecker = struct {
|
||||
}
|
||||
}
|
||||
|
||||
/// True when arg `i` of a parameterized type `base(...)` is a VALUE
|
||||
/// parameter (a compile-time integer such as a `Vector` lane count or a
|
||||
/// generic `$N: u32` arg), not a type. Such a position must be skipped by
|
||||
/// the unknown-type walk: a module-const arg (`Vector(N, f32)`) is a value,
|
||||
/// not a type name. `Vector`'s arg 0 is always its lane count; a generic
|
||||
/// struct template's value-param positions come from its declared params.
|
||||
fn isValueParamPosition(self: UnknownTypeChecker, base: []const u8, i: usize) bool {
|
||||
if (std.mem.eql(u8, base, "Vector")) return i == 0;
|
||||
if (self.index.struct_template_map.get(base)) |tmpl| {
|
||||
if (i < tmpl.type_params.len) return !tmpl.type_params[i].is_type_param;
|
||||
}
|
||||
return false;
|
||||
}
|
||||
|
||||
/// Recurse a type-annotation node to its leaf names, reporting any unknown.
|
||||
fn checkTypeNodeForUnknown(
|
||||
self: UnknownTypeChecker,
|
||||
@@ -643,8 +657,20 @@ pub const UnknownTypeChecker = struct {
|
||||
if (ct.return_type) |rt| self.checkTypeNodeForUnknown(rt, declared, in_scope, type_vals);
|
||||
},
|
||||
// Builtin constructors (Vector) and generic templates resolve the
|
||||
// base name specially; just check the type args.
|
||||
.parameterized_type_expr => |pt| for (pt.args) |a| self.checkTypeNodeForUnknown(a, declared, in_scope, type_vals),
|
||||
// base name specially; check only the TYPE args. A value-param
|
||||
// position (a `Vector` lane count, or a generic `$N: u32` arg) holds
|
||||
// a compile-time integer — `Vector(N, f32)` / `Vec(N, f32)` with `N`
|
||||
// a module const — not a type name, so it must not be walked as one
|
||||
// (it would falsely report "unknown type 'N'"). The lowering
|
||||
// resolvers fold the value and emit the precise diagnostic if it
|
||||
// isn't a compile-time integer.
|
||||
.parameterized_type_expr => |pt| {
|
||||
const base = if (std.mem.lastIndexOfScalar(u8, pt.name, '.')) |dot| pt.name[dot + 1 ..] else pt.name;
|
||||
for (pt.args, 0..) |a, i| {
|
||||
if (self.isValueParamPosition(base, i)) continue;
|
||||
self.checkTypeNodeForUnknown(a, declared, in_scope, type_vals);
|
||||
}
|
||||
},
|
||||
else => {},
|
||||
}
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user