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:
@@ -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);
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user