feat(lang): integer numeric-limit accessors (s64.max, u8.min, s3.max) [NL.1]
A field-like access on a builtin INTEGER type name folds to a compile-time
constant of the queried type, driven by (width, signedness) arithmetic:
sN: min=-(2^(N-1)), max=2^(N-1)-1; uN: min=0, max=2^N-1
for every width s1..s64 / u1..u64 (not just power-of-two), plus usize/isize.
- type_resolver.zig: extract the single width parser (parseWidthInt) reused by
resolveNamed AND the new accessors (no second parser — issue-0083 class);
add resolveBuiltinName / integerWidthSign / integerLimitBits / integerLimitFor.
- lower.zig: lowerNumericLimit intercept beside the error.X / Struct.CONST /
pack-arity identifier-receiver intercepts; folds ints via constInt, emits a
clean diagnostic for a non-numeric receiver (bool/string/void/Any/noreturn),
falls through for floats (NL.2).
- expr_typer.zig: mirror the result type so inferExprType reports the queried type.
- program_index.zig: recognize the accessors in the comptime-int / array-dim path
so [u8.max]T (255) / [s16.max]T (32767) work; [u64.max]T is rejected oversized.
- u64.max / usize.max stored as the all-ones bit pattern with TYPE u64 (i64 -1),
asserted via union { u: u64; s: s64 } reinterpret.
Docs: specs.md numeric-limits subsection (formulas + result-type + u64 note);
readme.md language overview. Examples 0148 (positive) / 0149 (negative-receiver).
Unit tests for the value computation in type_resolver.test.zig.
Gate: zig build, zig build test (359/359), tests/run_examples.sh (416 ok, 0 failed).
This commit is contained in:
@@ -4823,6 +4823,13 @@ pub const Lowering = struct {
|
||||
}
|
||||
}
|
||||
|
||||
// Numeric-limit accessor: `<IntType>.min` / `.max` folds to a comptime
|
||||
// const of the queried type (sibling of the identifier-receiver
|
||||
// intercepts above). Placed AFTER `Struct.CONST` so a user const named
|
||||
// `min`/`max` wins on its own struct; a builtin type name can never
|
||||
// name a user struct (reserved — issue 0076), so they never collide.
|
||||
if (self.lowerNumericLimit(fa, span)) |ref| return ref;
|
||||
|
||||
// M1.3 — `obj.class` on any Obj-C-class pointer lowers to
|
||||
// `object_getClass(obj)`. Sugar; the receiver is opaque so
|
||||
// we don't auto-deref. Returns `Class` (alias for *void;
|
||||
@@ -4897,6 +4904,37 @@ pub const Lowering = struct {
|
||||
return self.lowerFieldAccessOnType(obj, obj_ty, fa.field, span);
|
||||
}
|
||||
|
||||
/// Numeric-limit accessor intercept (`<IntType>.min` / `.max`), a sibling of
|
||||
/// the `error.X` / `Struct.CONST` / pack-arity identifier-receiver intercepts
|
||||
/// in `lowerFieldAccess`. Folds an integer type's `.min`/`.max` to a comptime
|
||||
/// const of that type via the shared `TypeResolver` width logic (no second
|
||||
/// width parser) + the existing `constInt` const path. Returns null when this
|
||||
/// is not an integer-limit access, so the caller continues normal field
|
||||
/// lowering. A `.min`/`.max` on a builtin NON-numeric receiver
|
||||
/// (`bool`/`string`/`void`/`Any`/`noreturn`) is a clean diagnostic here (then
|
||||
/// a placeholder, so lowering finishes and `hasErrors()` aborts the build); a
|
||||
/// float receiver falls through (float limits are NL.2).
|
||||
fn lowerNumericLimit(self: *Lowering, fa: *const ast.FieldAccess, span: ast.Span) ?Ref {
|
||||
const name = switch (fa.object.data) {
|
||||
.identifier => |id| id.name,
|
||||
.type_expr => |te| te.name,
|
||||
else => return null,
|
||||
};
|
||||
if (!std.mem.eql(u8, fa.field, "min") and !std.mem.eql(u8, fa.field, "max")) return null;
|
||||
const ty = TypeResolver.resolveBuiltinName(name, &self.module.types) orelse return null;
|
||||
if (TypeResolver.integerLimitFor(name, fa.field)) |value| {
|
||||
return self.builder.constInt(value, ty);
|
||||
}
|
||||
// A builtin receiver that is not an integer: floats are NL.2 (fall
|
||||
// through), every other builtin (bool/string/void/Any/noreturn) has no
|
||||
// numeric limit.
|
||||
if (ty == .f32 or ty == .f64) return null;
|
||||
if (self.diagnostics) |d| {
|
||||
d.addFmt(.err, span, "type '{s}' has no '.{s}' — numeric limits apply only to integer and float types", .{ name, fa.field });
|
||||
}
|
||||
return self.emitPlaceholder(fa.field);
|
||||
}
|
||||
|
||||
/// Lower each pack element to a Ref: `pack_name[i]` when `method` is null,
|
||||
/// or `pack_name[i].method()` when given. Synthesizes the index/field/call
|
||||
/// AST per element and lowers it (substitution turns `xs[i]` into the
|
||||
|
||||
Reference in New Issue
Block a user