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

@@ -190,7 +190,7 @@ pub fn monomorphizeFunction(self: *Lowering, fd: *const ast.FnDecl, mangled_name
/// - type_expr AST nodes
/// True iff `node` matches an AST shape that `resolveTypeArg`
/// can resolve to a concrete TypeId without falling through to
/// the silent `.s64` default. Used by `tryLowerReflectionCall`
/// the silent `.i64` default. Used by `tryLowerReflectionCall`
/// to split static-fold from dynamic-builtin-call paths.
///
/// Static-arg shapes mirror the explicit arms of `resolveTypeArg`:
@@ -206,9 +206,9 @@ pub fn monomorphizeFunction(self: *Lowering, fd: *const ast.FnDecl, mangled_name
pub fn isStaticTypeArg(self: *Lowering, node: *const Node) bool {
switch (node.data) {
.type_expr => |te| {
// A type-keyword name (e.g. `s64`) is always static.
// A type-keyword name (e.g. `i64`) is always static.
// A user-defined name that happens to be in scope as
// a runtime variable (`x: Type = s64; type_name(x)`)
// a runtime variable (`x: Type = i64; type_name(x)`)
// is NOT static — route through the dynamic builtin
// call so the runtime lookup table fires.
if (self.scope) |scope| {
@@ -245,7 +245,7 @@ pub fn isStaticTypeArg(self: *Lowering, node: *const Node) bool {
pub fn isStaticTypeRef(self: *Lowering, node: *const Node) bool {
switch (node.data) {
.type_expr => |te| {
// Compound type names (`s64`, `Point`, `Vec4`) resolve
// Compound type names (`i64`, `Point`, `Vec4`) resolve
// statically. If the name is also a runtime var in
// scope, it's a value reference, not a type ref.
if (self.scope) |scope| {
@@ -286,10 +286,10 @@ pub fn isStaticTypeRef(self: *Lowering, node: *const Node) bool {
}
}
/// Resolve a tuple LITERAL used in a type position (`(s32, s32)` reinterpreted
/// Resolve a tuple LITERAL used in a type position (`(i32, i32)` reinterpreted
/// as a tuple type at a type-demanding site such as `size_of`). Every element
/// must itself denote a type; a non-type element — e.g. the `1` in
/// `(s32, 1)` — is a user error. Emit a diagnostic pointing at the offending
/// `(i32, 1)` — is a user error. Emit a diagnostic pointing at the offending
/// element and return `.unresolved`; never fabricate a tuple with a bogus
/// field. type_bridge.resolveAstType builds the tuple only after
/// this validation passes.
@@ -297,12 +297,12 @@ pub fn resolveTupleLiteralTypeArg(self: *Lowering, node: *const Node) TypeId {
for (node.data.tuple_literal.elements) |el| {
if (!type_bridge.isTypeShapedAstNode(el.value, &self.module.types)) {
if (self.diagnostics) |diags| {
diags.addFmt(.err, el.value.span, "tuple type element is not a type (found `{s}`); a tuple used as a type must list only types, e.g. `(s32, s32)`", .{@tagName(el.value.data)});
diags.addFmt(.err, el.value.span, "tuple type element is not a type (found `{s}`); a tuple used as a type must list only types, e.g. `(i32, i32)`", .{@tagName(el.value.data)});
}
return .unresolved;
}
// E4 single-hop visibility gate: each element leaf is resolved through
// the source-aware resolver, so a 2-flat-hop inner leaf (`(COnly, s64)`)
// the source-aware resolver, so a 2-flat-hop inner leaf (`(COnly, i64)`)
// emits "not visible" + poisons rather than leaking through
// `type_bridge`'s ungated global lookup. A valid element resolves to the
// same TypeId the delegated build produces below (no diagnostic, no
@@ -314,10 +314,10 @@ pub fn resolveTupleLiteralTypeArg(self: *Lowering, node: *const Node) TypeId {
pub fn resolveTypeArg(self: *Lowering, node: *const Node) TypeId {
// Pack-index access in a type-arg slot (e.g. `type_name($args[0])`
// or `type_eq($args[i], s64)`). Same shape as the
// or `type_eq($args[i], i64)`). Same shape as the
// `resolveTypeWithBindings` arm — looks up the bound pack types
// and returns the i-th. OOB and no-active-binding emit focused
// diagnostics rather than silently defaulting to .s64 (the
// diagnostics rather than silently defaulting to .i64 (the
// catch-all `else` below) — that fall-through is exactly the
// "silent unimplemented arm" the project's REJECTED PATTERNS
// forbid.
@@ -392,8 +392,8 @@ pub fn resolveTypeArg(self: *Lowering, node: *const Node) TypeId {
// time when `x`'s type is statically known (which it
// is for any expression — type inference always
// produces a concrete TypeId). Lets
// `type_of(a) == s64` fold the same as
// `inferExprType(a) == s64`.
// `type_of(a) == i64` fold the same as
// `inferExprType(a) == i64`.
if (cl.callee.data == .identifier and
std.mem.eql(u8, cl.callee.data.identifier.name, "type_of") and
cl.args.len == 1)
@@ -407,7 +407,7 @@ pub fn resolveTypeArg(self: *Lowering, node: *const Node) TypeId {
// route through the gated `resolveTypeWithBindings`, whose
// `resolveCompound` recurses each element through the source-aware leaf
// (`resolveNominalLeaf`) — so a 2-hop inner leaf (`*COnly`, `[2]COnly`,
// `(COnly, s64)`) is rejected exactly as in a normal annotation, instead
// `(COnly, i64)`) is rejected exactly as in a normal annotation, instead
// of `type_bridge.resolveAstType`'s ungated global lookup (E4).
.tuple_literal,
.pointer_type_expr,
@@ -421,13 +421,13 @@ pub fn resolveTypeArg(self: *Lowering, node: *const Node) TypeId {
}
}
/// Format a type name for display (e.g. "*Point", "[]s32", "[3]f64").
/// Format a type name for display (e.g. "*Point", "[]i32", "[3]f64").
pub fn formatTypeName(self: *Lowering, ty: TypeId) []const u8 {
// Builtin types: use their canonical name
if (ty == .s8) return "s8";
if (ty == .s16) return "s16";
if (ty == .s32) return "s32";
if (ty == .s64) return "s64";
if (ty == .i8) return "i8";
if (ty == .i16) return "i16";
if (ty == .i32) return "i32";
if (ty == .i64) return "i64";
if (ty == .u8) return "u8";
if (ty == .u16) return "u16";
if (ty == .u32) return "u32";
@@ -463,7 +463,7 @@ pub fn formatTypeName(self: *Lowering, ty: TypeId) []const u8 {
const inner = self.formatTypeName(a.element);
break :blk std.fmt.allocPrint(self.alloc, "[{d}]{s}", .{ a.length, inner }) catch "array";
},
.signed => |w| std.fmt.allocPrint(self.alloc, "s{d}", .{w}) catch "signed",
.signed => |w| std.fmt.allocPrint(self.alloc, "i{d}", .{w}) catch "signed",
.unsigned => |w| std.fmt.allocPrint(self.alloc, "u{d}", .{w}) catch "unsigned",
.optional => |o| blk: {
const inner = self.formatTypeName(o.child);
@@ -477,7 +477,7 @@ pub fn formatTypeName(self: *Lowering, ty: TypeId) []const u8 {
};
}
/// Format a function type string like "() -> s32" or "(s32, s32) -> s32".
/// Format a function type string like "() -> i32" or "(i32, i32) -> i32".
pub fn formatFnTypeString(self: *Lowering, fd: *const ast.FnDecl) []const u8 {
var buf: [512]u8 = undefined;
var pos: usize = 0;
@@ -509,7 +509,7 @@ pub fn formatFnTypeString(self: *Lowering, fd: *const ast.FnDecl) []const u8 {
}
/// Format a type name for function name mangling (identifier-safe).
/// E.g. *Point → "ptr_Point", []s32 → "slice_s32", [3]f64 → "array_3_f64".
/// E.g. *Point → "ptr_Point", []i32 → "slice_i32", [3]f64 → "array_3_f64".
/// Check if a param type expression references a type param name (possibly nested).
pub fn matchTypeParam(_: *Lowering, type_node: *const Node, tp_name: []const u8) bool {
return switch (type_node.data) {
@@ -548,7 +548,7 @@ pub fn matchTypeParamStatic(type_node: *const Node, tp_name: []const u8) bool {
}
/// Extract the concrete type that corresponds to a type param from an arg type.
/// E.g., param type []$T with arg type []s64 → T = s64.
/// E.g., param type []$T with arg type []i64 → T = i64.
pub fn extractTypeParam(self: *Lowering, type_node: *const Node, arg_ty: TypeId, tp_name: []const u8) ?TypeId {
return switch (type_node.data) {
.type_expr => |te| if (std.mem.eql(u8, te.name, tp_name)) arg_ty else null,
@@ -635,10 +635,10 @@ pub fn resolveTypeCategoryTags(self: *Lowering, name: []const u8) []const u64 {
// Fixed builtin categories
if (std.mem.eql(u8, name, "int")) {
tags.append(self.alloc, TypeId.s8.index()) catch {};
tags.append(self.alloc, TypeId.s16.index()) catch {};
tags.append(self.alloc, TypeId.s32.index()) catch {};
tags.append(self.alloc, TypeId.s64.index()) catch {};
tags.append(self.alloc, TypeId.i8.index()) catch {};
tags.append(self.alloc, TypeId.i16.index()) catch {};
tags.append(self.alloc, TypeId.i32.index()) catch {};
tags.append(self.alloc, TypeId.i64.index()) catch {};
tags.append(self.alloc, TypeId.u8.index()) catch {};
tags.append(self.alloc, TypeId.u16.index()) catch {};
tags.append(self.alloc, TypeId.u32.index()) catch {};
@@ -823,7 +823,7 @@ pub fn isPlainFreeFn(fd: *const ast.FnDecl) bool {
/// Resolve a generic value-param argument (`$K: u32`) to its compile-time
/// integer AND verify it fits the param's declared integer type. The folded
/// value is bound and mangled into the instantiation name, so a module/generic
/// const arg (`Vec(N, f32)`), a const expression (`Make(M + 1, s64)`), an
/// const arg (`Vec(N, f32)`), a const expression (`Make(M + 1, i64)`), an
/// integral float (`Box(4.0)` → 4), and a literal (`Vec(3, f32)`) all bind the
/// same value a literal would. An out-of-range arg (`Box(5_000_000_000)` for a
/// `u32` param) or a non-const arg emits a clean diagnostic and returns null;
@@ -838,8 +838,8 @@ pub fn isPlainFreeFn(fd: *const ast.FnDecl) bool {
/// `program_index.intTypeRange`; an unrecognised type folds without bounding.
pub fn resolveValueParamArg(self: *Lowering, arg_node: *const Node, param_name: []const u8, type_name: ?[]const u8) ?i64 {
// Resolve an ALIASED integer constraint (`$K: Count` where `Count :: u32`,
// `$K: Small` where `Small :: s8`) to its underlying builtin so the range
// gate below treats it exactly like `$K: u32` / `$K: s8` (an
// `$K: Small` where `Small :: i8`) to its underlying builtin so the range
// gate below treats it exactly like `$K: u32` / `$K: i8` (an
// alias previously slipped past `intTypeRange`, so `Box(5_000_000_000)`
// with `$K: Count` bound a truncated value). A non-integer / unrecognised
// constraint yields null → no range bound (fold only), as before.
@@ -887,7 +887,7 @@ pub fn resolveValueParamArg(self: *Lowering, arg_node: *const Node, param_name:
/// Resolve a generic value-param constraint type NAME to its canonical builtin
/// integer type name, chasing a type alias (`Count :: u32` → "u32",
/// `Small :: s8` → "s8") so an ALIASED integer constraint range-checks exactly
/// `Small :: i8` → "i8") so an ALIASED integer constraint range-checks exactly
/// like the builtin it names. Returns the name unchanged when it is already a
/// builtin integer; null when it isn't an integer type (directly or via alias)
/// — the caller then folds without a range bound rather than guessing. The
@@ -914,8 +914,8 @@ pub fn diagValueParamRange(self: *Lowering, arg_node: *const Node, param_name: [
/// The poison-vs-proceed projection of `headTypeGate` for an UNQUALIFIED
/// parameterized type HEAD that names a generic STRUCT, a parameterized
/// PROTOCOL, or a type-returning function used as a head (`Box(s64)`,
/// `VL(s64)`) — and the alias-registration / type-match sites that likewise
/// PROTOCOL, or a type-returning function used as a head (`Box(i64)`,
/// `VL(i64)`) — and the alias-registration / type-match sites that likewise
/// only need "poison or proceed". Returns TRUE (the gate's loud diagnostic is
/// already emitted) when the head is `.not_visible` (a 2-flat-hop leak) or
/// `.ambiguous` (≥2 direct flat same-name authors — consistent with the leaf /
@@ -1186,7 +1186,7 @@ pub fn flatFnAuthorAmbiguous(self: *Lowering, name: []const u8, from: []const u8
/// analogue of `isNameVisible` for a type-fn head: a same-name 1-hop
/// NON-function (a value const `Make :: 123`, a named type) does NOT vouch
/// (attempt-7), and — crucially — neither does a same-name 1-hop ORDINARY
/// function (`Make :: () -> s32`, zero `$`-params), which cannot be the type
/// function (`Make :: () -> i32`, zero `$`-params), which cannot be the type
/// head being instantiated (attempt-8). So a type-fn whose only directly-
/// visible same-name author is a non-fn OR a non-type-fn — its real author 2
/// flat hops away — is correctly invisible. Mirrors `flatFnAuthorAmbiguous`'s
@@ -1290,7 +1290,7 @@ pub fn resolveParameterizedWithBindings(self: *Lowering, pt: *const ast.Paramete
}
}
// Parameterized protocol used as a value type (`VL(s64)`): materialize a
// Parameterized protocol used as a value type (`VL(i64)`): materialize a
// 16-byte protocol value with the type-arg bound (not a 0-field stub).
if (self.program_index.protocol_ast_map.get(base_name)) |pd| {
if (pd.type_params.len > 0) {
@@ -1300,7 +1300,7 @@ pub fn resolveParameterizedWithBindings(self: *Lowering, pt: *const ast.Paramete
}
// User-defined type-returning function used as a TYPE annotation
// (`b : Make(N, s64)` where `Make :: ($K: u32, $T: Type) -> Type`). The
// (`b : Make(N, i64)` where `Make :: ($K: u32, $T: Type) -> Type`). The
// `.call`-node path (`resolveTypeCallWithBindings`) already routes here;
// a `parameterized_type_expr` must too, or the function name falls through
// to the empty-struct stub below and `b.field` / `b.len` fails.
@@ -1409,7 +1409,7 @@ pub fn instantiateGenericStruct(self: *Lowering, tmpl: *const StructTemplate, ar
// A qualified `ns.Box(..)` head can select a generic template whose bare
// name also belongs to a DIFFERENT module's same-name template (the one
// that won the last-wins `struct_template_map`). Both would mangle to
// `Box__s64` and the second instantiation would alias the first's layout.
// `Box__i64` and the second instantiation would alias the first's layout.
// Tag the NON-canonical author's mangled name with its source so each
// author's instantiation is a distinct type. The canonical (bare-map)
// author keeps the untagged name — no churn for single-author generics.
@@ -1548,7 +1548,7 @@ pub fn instantiateGenericStruct(self: *Lowering, tmpl: *const StructTemplate, ar
table.updatePreservingKey(id, info);
// Bind the template name to this concrete instance so a method's
// `self: *Combined` (the template name) resolves to `*Combined__s64_s64`
// `self: *Combined` (the template name) resolves to `*Combined__i64_i64`
// — otherwise `self.field` hits the 0-field generic stub.
tb.put(tmpl.name, id) catch {};
@@ -1694,7 +1694,7 @@ pub fn instantiateTypeFunction(self: *Lowering, alias_name: []const u8, template
// struct/union/enum — `return [K]T`, `Vector(K, T)`, `*T`, an alias, etc.
// Resolve it with the value/type bindings active (so `[K]T` folds K to a
// compile-time integer). The result is interned structurally, so
// `Make(N, s64)`, `Make(3, s64)`, and `Make(M + 1, s64)` all yield the
// `Make(N, i64)`, `Make(3, i64)`, and `Make(M + 1, i64)` all yield the
// same TypeId. `.unresolved` means the return wasn't a type expression
// (e.g. a value-returning function in a type position) → fall through to
// the caller's fallback rather than fabricating a type.
@@ -1741,7 +1741,7 @@ pub fn instantiateTypeUnion(self: *Lowering, alias_name: []const u8, mangled_nam
const info: types.TypeInfo = .{ .tagged_union = .{
.name = alias_name_id,
.fields = variant_fields.items,
.tag_type = .s64,
.tag_type = .i64,
} };
const id = if (table.findByName(alias_name_id)) |existing| existing else table.intern(info);
table.updatePreservingKey(id, info);
@@ -1752,7 +1752,7 @@ pub fn instantiateTypeUnion(self: *Lowering, alias_name: []const u8, mangled_nam
const mangled_info: types.TypeInfo = .{ .tagged_union = .{
.name = mangled_name_id,
.fields = variant_fields.items,
.tag_type = .s64,
.tag_type = .i64,
} };
const mid = if (table.findByName(mangled_name_id)) |existing| existing else table.intern(mangled_info);
table.updatePreservingKey(mid, mangled_info);