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