lang: rename signed integer types sN -> iN

Surface rename of the signed integer family: s1..s64 become i1..i64
(u1..u64, usize, isize unchanged). 'string' keeps the s-prefix arm in
name classification; width parsing moves to the i-prefix arm next to
isize.

Internal TypeId tags follow the surface (.s8/.s16/.s32/.s64 ->
.i8/.i16/.i32/.i64), as do mono-key mangle fragments (ptr_i64,
tu_i64_bool) and all display/diagnostic formatting (i{d}).

Migrated in the same sweep: stdlib + examples + issue repros + FFI C
companions (shared symbol names like ffi_id_i64), expected
stdout/stderr/ir snapshots, specs.md, readme.md, CLAUDE.md/AGENTS.md,
implementation_plan.md, docs/, issue writeups. Vendored stb_image and
historical flow state left untouched.

zig build test: 426/426; examples suite: 595/595.
This commit is contained in:
agra
2026-06-12 09:31:53 +03:00
parent 515ecebea7
commit d8076b9333
1054 changed files with 6836 additions and 6839 deletions

View File

@@ -268,7 +268,7 @@ pub fn injectComptimeConstants(self: *Lowering) void {
}
}
// POINTER_SIZE: s64 (4 for wasm32, 8 for wasm64 and other 64-bit targets)
// POINTER_SIZE: i64 (4 for wasm32, 8 for wasm64 and other 64-bit targets)
const ptr_size: i64 = if (tc.isWasm32()) 4 else 8;
self.comptime_constants.put("POINTER_SIZE", .{ .int_val = ptr_size }) catch {};
}
@@ -437,7 +437,7 @@ pub fn dropModuleConst(self: *Lowering, source: ?[]const u8, name: []const u8) v
/// Pass 1: Scan declarations — register ASTs and extern stubs, but don't lower bodies.
pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// Pass 0: register every numeric-literal module const (`N :: 16` and the
// typed `N : s64 : 16`, plus float-valued `N :: 4.0` / `N : f64 : 4.0`)
// typed `N : i64 : 16`, plus float-valued `N :: 4.0` / `N : f64 : 4.0`)
// BEFORE any type alias is resolved below. A type alias whose dimension is
// a named const (`Arr :: [N]T`) resolves its dimension eagerly here, on
// the stateless registration path; that path can only read
@@ -455,7 +455,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
const cd = decl.data.const_decl;
switch (cd.value.data) {
.int_literal => {
const info = program_index_mod.ModuleConstInfo{ .value = cd.value, .ty = .s64 };
const info = program_index_mod.ModuleConstInfo{ .value = cd.value, .ty = .i64 };
self.putModuleConst(decl.source_file, cd.name, info);
},
.float_literal => {
@@ -465,11 +465,11 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// A const whose RHS is an integer EXPRESSION over other consts
// (`M :: 2; N :: M + 1`) is itself a usable count: register it so
// `moduleConstInt` can fold the RHS through `evalConstIntExpr`
//. Placeholder `.s64` type — the count consumers read
//. Placeholder `.i64` type — the count consumers read
// only the value; if the expression doesn't fold (references a
// non-const), `moduleConstInt` yields null and the use diagnoses.
.binary_op, .unary_op => {
const info = program_index_mod.ModuleConstInfo{ .value = cd.value, .ty = .s64 };
const info = program_index_mod.ModuleConstInfo{ .value = cd.value, .ty = .i64 };
self.putModuleConst(decl.source_file, cd.name, info);
},
else => {},
@@ -565,7 +565,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
cd.value.data == .optional_type_expr or
cd.value.data == .function_type_expr)
{
// Type alias: MyFloat :: f64; Ptr :: *u8; Cb :: (s32) -> s32;
// Type alias: MyFloat :: f64; Ptr :: *u8; Cb :: (i32) -> i32;
const target_ty = type_bridge.resolveAstType(cd.value, &self.module.types, &self.program_index.type_alias_map, &self.program_index.module_const_map);
// The stateless resolver yields `.unresolved` for a shape
// it cannot build — e.g. `Arr :: [<computed>]T`, whose
@@ -651,7 +651,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// A namespaced callee (`ns.Box(..)`) is an explicit qualified
// reach, exempt from the bare-head visibility gate (E4).
const head_qualified = call_data.callee.data == .field_access;
// A qualified head `ABox :: a.Box(s64)` selects a's OWN
// A qualified head `ABox :: a.Box(i64)` selects a's OWN
// template via the namespace edge (mirrors the annotation
// head site `resolveTypeCallWithBindings`), not the bare
// last-wins `struct_template_map`.
@@ -660,8 +660,8 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
else
null;
if (callee_name.len > 0) {
// Generic-struct alias head (`ABox :: Box(s64)` /
// `a.Box(s64)`): route layout selection through the single
// Generic-struct alias head (`ABox :: Box(i64)` /
// `a.Box(i64)`): route layout selection through the single
// choke-point (CP-1); the Vector / type-fn branches stay
// as the non-generic fall-through.
switch (self.selectGenericStructHead(callee_name, qual_alias, head_qualified, call_data.callee.span)) {
@@ -698,7 +698,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
const pt = &cd.value.data.parameterized_type_expr;
const base_name = if (std.mem.lastIndexOfScalar(u8, pt.name, '.')) |dot| pt.name[dot + 1 ..] else pt.name;
const pt_qualified = std.mem.indexOfScalar(u8, pt.name, '.') != null;
// A qualified base `ABox :: a.Box(s64)` selects a's OWN
// A qualified base `ABox :: a.Box(i64)` selects a's OWN
// template via the namespace edge (mirrors the annotation
// head site `resolveParameterizedWithBindings`), not the
// bare last-wins `struct_template_map`.
@@ -723,7 +723,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
}
// comptime_expr handled in Pass 2
// Typed value constants (`AF_INET :s32: 2`) are registered in
// Typed value constants (`AF_INET :i32: 2`) are registered in
// pass 2 below — after the forward-alias fixpoint — so a
// forward identifier alias in the annotation resolves to its
// target instead of a fabricated stub. Untyped
@@ -733,7 +733,7 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
// Untyped literal constants (e.g. UI_VERT_SRC :: #string GLSL...GLSL;)
const lit_ty: ?TypeId = switch (cd.value.data) {
.string_literal => .string,
.int_literal => .s64,
.int_literal => .i64,
.float_literal => .f64,
.bool_literal => .bool,
// Complex constant expressions (e.g. COLOR_WHITE :: Color.{ r = 255, ... })
@@ -825,19 +825,19 @@ pub fn scanDecls(self: *Lowering, decls: []const *const Node) void {
.own_opaque, .ambiguous, .none => false,
};
if (!recv_is_agg) continue;
self.putModuleConst(decl.source_file, cd.name, .{ .value = cd.value, .ty = .s64 });
self.putModuleConst(decl.source_file, cd.name, .{ .value = cd.value, .ty = .i64 });
}
}
/// Register a typed module-level value constant (`AF_INET :s32: 2`). Run in
/// Register a typed module-level value constant (`AF_INET :i32: 2`). Run in
/// scanDecls pass 2 (after `resolveForwardIdentifierAliases`) so a forward
/// identifier alias in the annotation (`A :: B; B :: s32; K : A : 42;`)
/// identifier alias in the annotation (`A :: B; B :: i32; K : A : 42;`)
/// resolves to its target rather than a fabricated empty-struct stub, which
/// would otherwise mistype the constant.
pub fn registerTypedModuleConst(self: *Lowering, cd: *const ast.ConstDecl) void {
const ta = cd.type_annotation orelse return;
// Only initializer shapes that pass 0 (binary_op / unary_op → placeholder
// `.s64`) or the literal path register as a USABLE module const need
// `.i64`) or the literal path register as a USABLE module const need
// reconciling against the annotation. Every other shape (call,
// struct/array literal, bare identifier) is never registered as a
// foldable / emittable const, so it cannot manifest a
@@ -860,7 +860,7 @@ pub fn registerTypedModuleConst(self: *Lowering, cd: *const ast.ConstDecl) void
// silently-accepted const — registering it would let `emitModuleConst`
// stamp the value with the wrong IR type (an int emitted as a `string`
// const → a bogus pointer that segfaults at the use site) and let the
// count path fold it (`[N]s64` → 4). Issue 0088.
// count path fold it (`[N]i64` → 4). Issue 0088.
if (!self.typedConstInitFits(cd.value, ty)) {
// A non-integral compile-time float into an integer const is the
// same implicit-narrowing failure as a typed local/field/param —
@@ -880,7 +880,7 @@ pub fn registerTypedModuleConst(self: *Lowering, cd: *const ast.ConstDecl) void
});
}
// Evict the pass-0 placeholder (`N : string : 4` and
// `N : string : M + 2` are both pre-registered as `.s64` in scanDecls
// `N : string : M + 2` are both pre-registered as `.i64` in scanDecls
// pass 0); leaving it would let a count use still fold `N`.
self.dropModuleConst(self.current_source_file, cd.name);
return;
@@ -904,13 +904,13 @@ pub fn registerTypedModuleConst(self: *Lowering, cd: *const ast.ConstDecl) void
/// unsound as a compile-time literal-representability oracle here — a `null`
/// literal's natural type is `.void`, so `classify(.void, *T)` yields `.none`
/// and would reject the valid `P : *void : null`; `bool` is 1 bit wide, so
/// `classify(.bool, s64)` yields `.widen` and would accept the bogus
/// `B : s64 : true`.
/// `classify(.bool, i64)` yields `.widen` and would accept the bogus
/// `B : i64 : true`.
pub fn typedConstInitFits(self: *Lowering, value: *const Node, dst_ty: TypeId) bool {
// An INTEGER-annotated constant accepts a compile-time INTEGRAL float —
// a literal (`K : s64 : 4.0`), an int-leaf expression (`K : s64 : M + 2.0`
// a literal (`K : i64 : 4.0`), an int-leaf expression (`K : i64 : M + 2.0`
// → 4), or a float-const-leaf expression whose SUM is integral
// (`F : f64 : 2.5; K : s64 : F + 1.5` → 4). Integrality is judged on the
// (`F : f64 : 2.5; K : i64 : F + 1.5` → 4). Integrality is judged on the
// FLOAT fold (`evalConstFloatExpr` + `floatToIntExact`) — the SAME facility
// the typed-local path (`foldComptimeFloatInit`) uses — not the int-only
// folder, which folds leaf-by-leaf in `i64` and so misses an integral SUM
@@ -969,7 +969,7 @@ pub fn constExprInitFits(self: *Lowering, init_ty: TypeId, dst_ty: TypeId) bool
return init_ty == dst_ty;
}
/// Register an array-typed `::` constant (`K : [4]s64 : .[...]`, or the
/// Register an array-typed `::` constant (`K : [4]i64 : .[...]`, or the
/// untyped `A :: .[1, 2, 3]`) as an IMMUTABLE module global: one storage,
/// reads GEP it, the emitter marks it LLVMSetGlobalConstant, dead-global
/// elimination drops it when unused. Source-aware reads come for free via
@@ -1016,7 +1016,7 @@ pub fn registerConstArrayGlobal(self: *Lowering, cd: *const ast.ConstDecl) void
}
/// Infer `[N]T` for an untyped array-literal constant. Element types unify:
/// all ints → s64; ANY float promotes the element type to f64 (ints convert
/// all ints → i64; ANY float promotes the element type to f64 (ints convert
/// exactly — the int+float promotion rule for consts, element-wise); bool /
/// string homogeneous only. A non-numeric mix or a non-inferable element
/// shape (nested aggregate, enum literal, named const) asks for an
@@ -1024,18 +1024,18 @@ pub fn registerConstArrayGlobal(self: *Lowering, cd: *const ast.ConstDecl) void
pub fn inferConstArrayType(self: *Lowering, name: []const u8, elements: []const *const Node, span: ast.Span) ?TypeId {
if (elements.len == 0) {
if (self.diagnostics) |d|
d.addFmt(.err, span, "constant '{s}' is an empty array literal — annotate the type (e.g. `{s} : [0]s64 : .[]`)", .{ name, name });
d.addFmt(.err, span, "constant '{s}' is an empty array literal — annotate the type (e.g. `{s} : [0]i64 : .[]`)", .{ name, name });
return null;
}
var elem_ty: ?TypeId = null;
for (elements) |e| {
const leaf: ?TypeId = switch (e.data) {
.int_literal => .s64,
.int_literal => .i64,
.float_literal => .f64,
.bool_literal => .bool,
.string_literal => .string,
.unary_op => |uo| if (uo.op == .negate) switch (uo.operand.data) {
.int_literal => .s64,
.int_literal => .i64,
.float_literal => .f64,
else => null,
} else null,
@@ -1049,7 +1049,7 @@ pub fn inferConstArrayType(self: *Lowering, name: []const u8, elements: []const
if (elem_ty) |prev| {
if (prev == lt) continue;
// Numeric mix promotes to the float element type.
const numeric_pair = (prev == .s64 and lt == .f64) or (prev == .f64 and lt == .s64);
const numeric_pair = (prev == .i64 and lt == .f64) or (prev == .f64 and lt == .i64);
if (numeric_pair) {
elem_ty = .f64;
continue;
@@ -1089,7 +1089,7 @@ pub fn maybeRegisterConstStructGlobal(self: *Lowering, cd: *const ast.ConstDecl)
/// Register a top-level mutable global (e.g., `context : Context = ---;`).
/// Run AFTER `resolveForwardIdentifierAliases` so a forward identifier alias
/// in the type annotation (`A :: B; B :: s32; g : A = 7;`) resolves to its
/// in the type annotation (`A :: B; B :: i32; g : A = 7;`) resolves to its
/// target instead of a fabricated empty-struct stub, which would otherwise
/// give the global a type that mismatches its initializer at LLVM
/// verification. Globals can't be named in a type position, so
@@ -1143,7 +1143,7 @@ pub fn globalInitValue(self: *Lowering, vd: *const ast.VarDecl, var_ty: TypeId)
self.checkIntLiteralFits(il.value, var_ty, v.span);
break :blk .{ .int = il.value };
},
// A negated literal (`g : s64 = -1;`) folds through the shared
// A negated literal (`g : i64 = -1;`) folds through the shared
// const-expr serializer. The folded value follows the same rules as
// the direct literal arms: int fits-check; a float at an integer
// global narrows only when integral.
@@ -1239,8 +1239,8 @@ pub fn diagnoseNonConstGlobal(self: *Lowering, vd: *const ast.VarDecl, v: *const
/// is already resolved as a type author; a forward target isn't yet present,
/// so `A` is left unregistered and its uses get falsely flagged as an unknown
/// type. Re-resolve to a fixpoint now that every top-level name
/// has been seen, so `A :: B; B :: s32;` converges the same as the ordered
/// `B :: s32; A :: B;`. A value const is never an `.identifier` node
/// has been seen, so `A :: B; B :: i32;` converges the same as the ordered
/// `B :: i32; A :: B;`. A value const is never an `.identifier` node
/// (`NotAType :: 123` is an int literal), and an alias whose target is a value
/// const stays unresolved, so neither this pass nor the unknown-type suppression can register a
/// non-type name.
@@ -1274,8 +1274,8 @@ pub fn resolveForwardIdentifierAliases(self: *Lowering, decls: []const *const No
if (self.aliasResolvedInSource(src, cd.name)) continue;
const rhs = cd.value.data.identifier;
// Pass the backtick raw flag so a forward alias whose RHS is a raw
// identifier (`` RawAlias :: `s2 ``, target declared later) resolves
// to the nominal `` `s2 `` author, not the builtin `s2` spelling.
// identifier (`` RawAlias :: `i2 ``, target declared later) resolves
// to the nominal `` `i2 `` author, not the builtin `i2` spelling.
switch (self.selectNominalLeaf(rhs.name, src, rhs.is_raw)) {
.resolved => |tid| {
self.putTypeAlias(decl.source_file, cd.name, tid);
@@ -1934,9 +1934,9 @@ pub fn structMethodFn(sd: *const ast.StructDecl, method: []const u8) ?*const ast
/// TRUE iff `ref` is a TYPE-FUNCTION head author — a `fn_decl` (or const-
/// wrapped fn) declaring at least one `$`-parameter, i.e. instantiable as a
/// bare type head (`Make(s64)` where `Make :: ($T) -> Type`). Mirrors the
/// bare type head (`Make(i64)` where `Make :: ($T) -> Type`). Mirrors the
/// `fd.type_params.len > 0` gate every instantiation site uses to recognize a
/// type-fn head, so an ORDINARY same-name function (`Make :: () -> s32`, zero
/// type-fn head, so an ORDINARY same-name function (`Make :: () -> i32`, zero
/// type params) is NOT a type-fn author and does NOT vouch for a hidden 2-flat-
/// hop type-fn head (E4 attempt-8: a `fn_decl != null` author view let any
/// visible function — type-fn or not — authorize a type head).
@@ -2262,7 +2262,7 @@ pub fn lazyLowerFunction(self: *Lowering, name: []const u8) void {
// Defer functions with type-category matches until all types are registered.
// any_to_string uses `if type == { case slice: ... }` which compiles a switch
// with type tags from resolveTypeCategoryTags. This must happen AFTER main is
// fully lowered so all types ([]s32, List__s32, etc.) are in the TypeTable.
// fully lowered so all types ([]i32, List__i32, etc.) are in the TypeTable.
if (!self.processing_deferred and std.mem.eql(u8, name, "any_to_string")) {
self.deferred_type_fns.append(self.alloc, name) catch {};
return;
@@ -2557,8 +2557,8 @@ pub fn emitModuleConst(self: *Lowering, ci: ModuleConstInfo, author_source: ?[]c
// accepted under the unified narrowing rule — materializes as its folded
// int through the SAME `program_index.foldCountI64` the count / array-dim
// path uses, so the const's emitted VALUE and its use as a COUNT come from
// one fold (`K : s64 : 4.0` → 4; `K : s64 : M + 2.0` → 4; and a float-const-
// leaf `KF : s64 : F + 1.5` → 4, which the int-only folder could not reach).
// one fold (`K : i64 : 4.0` → 4; `K : i64 : M + 2.0` → 4; and a float-const-
// leaf `KF : i64 : F + 1.5` → 4, which the int-only folder could not reach).
// A non-integral float never arrives (it was rejected at registration); any
// other non-foldable shape falls through to the per-kind emitters below.
if (self.isIntEx(ci.ty)) {
@@ -2597,5 +2597,5 @@ pub fn emitModuleConst(self: *Lowering, ci: ModuleConstInfo, author_source: ?[]c
pub fn emitPlaceholder(self: *Lowering, name: []const u8) Ref {
const sid = self.module.types.internString(name);
return self.builder.emit(.{ .placeholder = sid }, .s64);
return self.builder.emit(.{ .placeholder = sid }, .i64);
}