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

@@ -29,7 +29,7 @@ const hasComptimeParams = Lowering.hasComptimeParams;
pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
var c = c_in;
// A bare reserved-type-name spelling in call position parses as a
// `.type_expr` (e.g. `s2(4)`), but if a function of that name is in
// `.type_expr` (e.g. `i2(4)`), but if a function of that name is in
// scope — a backtick-declared sx fn or a `#import c` foreign fn whose C
// name collides with a reserved type spelling — it is a CALL to that
// function. `TypeName(val)` is not a cast (casts are `cast(T, val)`), so
@@ -411,7 +411,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// Check builtins first (these are handled natively by interpreter and emitter)
if (resolveBuiltin(id.name)) |bid| {
const ret_ty: TypeId = switch (bid) {
.size_of, .align_of => .s64,
.size_of, .align_of => .i64,
.sqrt, .sin, .cos, .floor => blk: {
// Math builtins: return type matches argument type ($T -> T)
if (c.args.len > 0) {
@@ -530,8 +530,8 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
const callee_ref = if (binding.is_alloca) self.builder.load(binding.ref, binding.ty) else binding.ref;
const ret_ty = if (!binding.ty.isBuiltin()) blk: {
const bti = self.module.types.get(binding.ty);
break :blk if (bti == .function) bti.function.ret else .s64;
} else .s64;
break :blk if (bti == .function) bti.function.ret else .i64;
} else .i64;
var final_args = std.ArrayList(Ref).empty;
defer final_args.deinit(self.alloc);
if (self.fnPtrTypeWantsCtx(binding.ty)) {
@@ -623,8 +623,8 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// Type constructor call: Sx(f32).user(0.5) — obj is a call that returns a type
if (fa.object.data == .call) {
const inner_call = &fa.object.data.call;
// Generic struct STATIC-METHOD head (`Box(s64).make(..)` or the
// qualified `a.Box(s64).make(..)`): the layout author is chosen
// Generic struct STATIC-METHOD head (`Box(i64).make(..)` or the
// qualified `a.Box(i64).make(..)`): the layout author is chosen
// by the single head choke-point (CP-1) and the method body by
// the instance's STAMPED author (CP-4), so layout-author ≡
// body-author for BOTH bare and qualified heads (E4 #1 / #2).
@@ -1025,7 +1025,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// call PLAN selected for the receiver's source — the SAME author
// plan typed the call's result as, so dispatch and typing can't
// disagree (without this, a string-typed winner over
// an s64 shadow boxes a raw int as a string pointer → segfault).
// an i64 shadow boxes a raw int as a string pointer → segfault).
// The plan is the single producer; lowering consumes its verdict
// (`sel_author` / `cplan.ambiguous_collision`, computed once above)
// rather than re-resolving the field name. `.ambiguous` → loud
@@ -1189,7 +1189,7 @@ pub fn lowerCall(self: *Lowering, c_in: *const ast.Call) Ref {
// Indirect call through expression
const callee_ref = self.lowerExpr(c.callee);
const owned = self.alloc.dupe(Ref, args.items) catch unreachable;
return self.builder.emit(.{ .call_indirect = .{ .callee = callee_ref, .args = owned } }, .s64);
return self.builder.emit(.{ .call_indirect = .{ .callee = callee_ref, .args = owned } }, .i64);
},
}
}
@@ -1426,7 +1426,7 @@ pub fn lowerRuntimeDispatchCall(
const type_tag_raw = self.lowerExpr(type_tag_node orelse return self.emitError("dispatch", call_node.callee.span));
const type_tag_node_ty = self.inferExprType(type_tag_node.?);
const type_tag = if (type_tag_node_ty == .any)
self.builder.emit(.{ .unbox_any = .{ .operand = type_tag_raw } }, .s64)
self.builder.emit(.{ .unbox_any = .{ .operand = type_tag_raw } }, .i64)
else
type_tag_raw;
const any_val = self.lowerExpr(any_val_node orelse return self.emitError("dispatch", call_node.callee.span));
@@ -1630,13 +1630,13 @@ pub fn lowerRuntimeDispatchCall(
@memcpy(final_call_args[1..], call_args.items);
}
}
// Coerce non-cast args (source type unknown, use s64 default).
// Coerce non-cast args (source type unknown, use i64 default).
// cast_arg_idx is in user-space (skips __sx_ctx); offset by ctx_slots.
const ctx_slots: usize = if (callee_has_ctx) 1 else 0;
for (0..@min(final_call_args.len, callee_params.len)) |ci| {
if (ci < ctx_slots) continue; // skip __sx_ctx slot
if ((ci - ctx_slots) != cast_arg_idx) {
final_call_args[ci] = self.coerceToType(final_call_args[ci], .s64, callee_params[ci].ty);
final_call_args[ci] = self.coerceToType(final_call_args[ci], .i64, callee_params[ci].ty);
}
}
const result = self.builder.call(fid, final_call_args, callee_ret);
@@ -1680,12 +1680,12 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
// size_of(T) → const_int(sizeof(T))
const ty = self.resolveTypeArg(c.args[0]);
const size: i64 = @intCast(self.typeSizeBytes(ty));
return self.builder.constInt(size, .s64);
return self.builder.constInt(size, .i64);
}
if (std.mem.eql(u8, name, "align_of")) {
const ty = self.resolveTypeArg(c.args[0]);
const a: i64 = @intCast(self.module.types.typeAlignBytes(ty));
return self.builder.constInt(a, .s64);
return self.builder.constInt(a, .i64);
}
if (std.mem.eql(u8, name, "field_count")) {
// field_count(T) → const_int(N)
@@ -1700,7 +1700,7 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
.vector => |v| @intCast(v.length),
else => 0,
};
return self.builder.constInt(count, .s64);
return self.builder.constInt(count, .i64);
}
if (std.mem.eql(u8, name, "type_name")) {
// type_name(T):
@@ -1712,8 +1712,8 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
// `callBuiltin(.type_name, [arg_ref])`. The interp's
// arm (commit 9600ba5) reads the runtime `.type_tag`
// and returns the per-position name. Without this
// split, the catch-all `else => .s64` in
// `resolveTypeArg` silently returns "s64" for every
// split, the catch-all `else => .i64` in
// `resolveTypeArg` silently returns "i64" for every
// dynamic call — exactly the silent-arm pattern the
// project's REJECTED PATTERNS forbid.
if (self.isStaticTypeArg(c.args[0])) {
@@ -1729,8 +1729,8 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
if (std.mem.eql(u8, name, "type_eq")) {
// type_eq(T1, T2) → const_bool — comptime TypeId equality.
// TypeIds are interned per structural shape so equality on
// them matches the user's intuition: `type_eq(s64, s64)` is
// true, `type_eq(*s64, *s64)` is true, distinct shapes are
// them matches the user's intuition: `type_eq(i64, i64)` is
// true, `type_eq(*i64, *i64)` is true, distinct shapes are
// false. Pack-indexed types (`$args[0]`) resolve through
// `resolveTypeArg` → `resolveTypeWithBindings`.
if (c.args.len < 2) return self.builder.constBool(false);
@@ -1745,7 +1745,7 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
// `any_to_string` — emits a `callBuiltin`: the interp reads
// the boxed TypeId, LLVM GEPs a per-type signedness table.
// Mirrors `type_name`'s static/dynamic split; the same split
// avoids `resolveTypeArg`'s silent `.s64` default lying about
// avoids `resolveTypeArg`'s silent `.i64` default lying about
// a runtime Type value.
if (c.args.len < 1) return self.builder.constBool(false);
if (self.isStaticTypeArg(c.args[0])) {
@@ -1873,7 +1873,7 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
// the returned value carries Type semantics (tag field
// says ".any" → the value field holds the type id).
const val = self.lowerExpr(c.args[0]);
const tag_val = self.builder.structGet(val, 0, .s64);
const tag_val = self.builder.structGet(val, 0, .i64);
return self.builder.boxAny(tag_val, .any);
} else {
return self.builder.constType(arg_ty);
@@ -1881,14 +1881,14 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
}
if (std.mem.eql(u8, name, "field_index")) {
// field_index(T, val) → extract tag from tagged union
if (c.args.len < 2) return self.builder.constInt(0, .s64);
if (c.args.len < 2) return self.builder.constInt(0, .i64);
const val = self.lowerExpr(c.args[1]);
// For tagged unions: extract field 0 (the tag)
return self.builder.emit(.{ .enum_tag = .{ .operand = val } }, .s64);
return self.builder.emit(.{ .enum_tag = .{ .operand = val } }, .i64);
}
if (std.mem.eql(u8, name, "field_value_int")) {
// field_value_int(T, i) → lookup enum variant value by index
if (c.args.len < 2) return self.builder.constInt(0, .s64);
if (c.args.len < 2) return self.builder.constInt(0, .i64);
const ty = self.resolveTypeArg(c.args[0]);
const idx = self.lowerExpr(c.args[1]);
// For enums with explicit values, build a global value array and index into it
@@ -1901,11 +1901,11 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
var elems = std.ArrayList(Ref).empty;
defer elems.deinit(self.alloc);
for (vals) |v| {
elems.append(self.alloc, self.builder.constInt(v, .s64)) catch unreachable;
elems.append(self.alloc, self.builder.constInt(v, .i64)) catch unreachable;
}
const arr_ty = self.module.types.arrayOf(.s64, @intCast(vals.len));
const arr_ty = self.module.types.arrayOf(.i64, @intCast(vals.len));
const arr = self.builder.structInit(elems.items, arr_ty);
return self.builder.emit(.{ .index_get = .{ .lhs = arr, .rhs = idx } }, .s64);
return self.builder.emit(.{ .index_get = .{ .lhs = arr, .rhs = idx } }, .i64);
}
}
}
@@ -1921,7 +1921,7 @@ pub fn tryLowerReflectionCall(self: *Lowering, name: []const u8, c: *const ast.C
/// shapes), or a runtime `Type` value — which is `.any`-typed at
/// runtime (`type_of(x)`, a `[]Type` element `list[i]`, a `Type`-typed
/// local / field / param). Any other expression — a value of type
/// s64 / f64 / bool / a struct — is NOT a type.
/// i64 / f64 / bool / a struct — is NOT a type.
pub fn reflectionArgIsType(self: *Lowering, arg: *const Node) bool {
if (self.isStaticTypeArg(arg)) return true;
return self.inferExprType(arg) == .any;
@@ -1986,7 +1986,7 @@ pub fn reflectionErrorSentinel(self: *Lowering, name: []const u8) Ref {
std.mem.eql(u8, name, "type_is_unsigned") or
std.mem.eql(u8, name, "is_flags"))
return self.builder.constBool(false);
return self.builder.constInt(0, .s64);
return self.builder.constInt(0, .i64);
}
/// After args have been lowered, append the lowered values of any

View File

@@ -214,7 +214,7 @@ pub fn lowerLambda(self: *Lowering, lam: *const ast.Lambda) Ref {
const env_local = self.builder.alloca(env_struct_ty);
// Compute env size
const env_byte_size_inner = self.computeEnvSize(capture_list);
const env_size_val = self.builder.constInt(@intCast(env_byte_size_inner), .s64);
const env_size_val = self.builder.constInt(@intCast(env_byte_size_inner), .i64);
// memcpy(local_alloca, env_param, size)
_ = self.callForeign("memcpy", &.{ env_local, env_param_ref, env_size_val }, self.module.types.ptrTo(.void));
@@ -247,7 +247,7 @@ pub fn lowerLambda(self: *Lowering, lam: *const ast.Lambda) Ref {
// Bind params (user args start at user_param_base_lam, shifted past ctx + env).
// Use the signature types computed above (`params`), which already
// applied contextual typing from the target closure to untyped params —
// `resolveParamType` alone would drop it and default each to s64.
// `resolveParamType` alone would drop it and default each to i64.
for (lam.params, 0..) |p, i| {
const pty = params.items[user_param_base + i].ty;
const slot = self.builder.alloca(pty);
@@ -355,7 +355,7 @@ pub fn lowerLambda(self: *Lowering, lam: *const ast.Lambda) Ref {
// `push Context.{ allocator = ... }` and a tracker / arena
// counts the env allocation alongside everything else.
const env_byte_size = self.computeEnvSize(capture_list);
const env_size = self.builder.constInt(@intCast(env_byte_size), .s64);
const env_size = self.builder.constInt(@intCast(env_byte_size), .i64);
const ptr_void = self.module.types.ptrTo(.void);
const env_heap = self.allocViaContext(env_size, ptr_void);
// memcpy(heap, stack_alloca, size)

View File

@@ -24,7 +24,7 @@ pub fn lowerXX(self: *Lowering, operand: Ref, operand_node: *const Node) Ref {
// Use the operand's *actual* lowered Ref type rather than reaching
// back through inferExprType — the latter doesn't cover every
// expression shape (notably lambdas), and a wrong src_ty here can
// route the cast through coerceToType (e.g. a bogus s64→ptr bitcast)
// route the cast through coerceToType (e.g. a bogus i64→ptr bitcast)
// and silently skip the user-space Into fallback.
const src_ty = self.builder.getRefType(operand);
const target_explicit = self.target_type != null;
@@ -83,7 +83,7 @@ pub fn lowerXX(self: *Lowering, operand: Ref, operand_node: *const Node) Ref {
const result = self.coerceExplicit(operand, src_ty, dst_ty);
// User-space fallback via `impl Into(Target) for Source`. Only fires
// when the target was explicitly named (not the .s64 default), src and
// when the target was explicitly named (not the .i64 default), src and
// dst differ, and the built-in ladder made no progress. Built-ins
// always win.
if (target_explicit and src_ty != dst_ty and result == operand) {
@@ -445,14 +445,14 @@ pub fn lowerAnyToF64Dispatch(self: *Lowering, any_val: Ref) Ref {
const result_slot = self.builder.alloca(.f64);
// Extract type tag from Any
const tag = self.builder.structGet(any_val, 0, .s64);
const tag = self.builder.structGet(any_val, 0, .i64);
const f32_bb = self.freshBlock("f32.unbox");
const f64_bb = self.freshBlock("f64.unbox");
const merge_bb = self.freshBlock("float.merge");
// Branch: tag == f32_tag ? f32_bb : f64_bb
const f32_tag = self.builder.constInt(TypeId.f32.index(), .s64);
const f32_tag = self.builder.constInt(TypeId.f32.index(), .i64);
const cond = self.builder.emit(.{ .cmp_eq = .{ .lhs = tag, .rhs = f32_tag } }, .bool);
self.builder.condBr(cond, f32_bb, &.{}, f64_bb, &.{});
@@ -479,7 +479,7 @@ pub fn lowerAnyToF64Dispatch(self: *Lowering, any_val: Ref) Ref {
}
/// Produce a default value for a type, applying struct field defaults.
/// For structs with defaults (e.g., `b: s32 = 99`), creates a struct_literal with defaults applied.
/// For structs with defaults (e.g., `b: i32 = 99`), creates a struct_literal with defaults applied.
/// For other types, returns a zero value.
pub fn buildDefaultValue(self: *Lowering, ty: TypeId) Ref {
if (ty.isBuiltin()) return self.builder.constInt(0, ty);
@@ -534,7 +534,7 @@ pub fn zeroValue(self: *Lowering, ty: TypeId) Ref {
if (ty.isBuiltin()) return self.builder.constInt(0, ty);
const info = self.module.types.get(ty);
return switch (info) {
// Arbitrary-width integer types (u1, u2, s4, ...) interned as
// Arbitrary-width integer types (u1, u2, i4, ...) interned as
// `.signed`/`.unsigned` variants — fall through `isBuiltin()`.
.signed, .unsigned => self.builder.constInt(0, ty),
.pointer, .tuple, .optional => self.builder.constNull(ty),
@@ -610,8 +610,8 @@ pub fn coerceMode(self: *Lowering, val: Ref, src_ty: TypeId, dst_ty: TypeId, mod
}
return val;
},
// Tuple → Tuple element-wise coercion (e.g. a `(s64, s64)` literal
// flowing into a `(s32, s32)` slot — the multi-value failable success
// Tuple → Tuple element-wise coercion (e.g. a `(i64, i64)` literal
// flowing into a `(i32, i32)` slot — the multi-value failable success
// tuple). Same arity: extract each slot, coerce it, rebuild.
.tuple_elementwise => {
const si = self.module.types.get(src_ty);
@@ -693,14 +693,14 @@ pub fn coerceMode(self: *Lowering, val: Ref, src_ty: TypeId, dst_ty: TypeId, mod
}
/// Apply C default argument promotion to variadic-tail args. These rules
/// (bool/s8/s16/u8/u16 → s32, f32 → f64) match the C calling convention's
/// (bool/i8/i16/u8/u16 → i32, f32 → f64) match the C calling convention's
/// implicit promotions when an argument is passed through `...`.
pub fn promoteCVariadicArgs(self: *Lowering, args: []Ref, fixed_count: usize) void {
if (args.len <= fixed_count) return;
for (args[fixed_count..]) |*arg| {
const src_ty = self.builder.getRefType(arg.*);
const promoted: TypeId = switch (src_ty) {
.bool, .s8, .s16, .u8, .u16 => .s32,
.bool, .i8, .i16, .u8, .u16 => .i32,
.f32 => .f64,
else => continue,
};
@@ -720,7 +720,7 @@ pub fn coerceCallArgs(self: *Lowering, args: []Ref, params: []const Function.Par
if (src_info == .array and dst_info == .many_pointer) {
const slot = self.builder.alloca(src_ty);
self.builder.store(slot, args[i]);
const zero = self.builder.constInt(0, .s64);
const zero = self.builder.constInt(0, .i64);
args[i] = self.builder.emit(.{ .index_gep = .{ .lhs = slot, .rhs = zero } }, dst_ty);
continue;
}

View File

@@ -287,7 +287,7 @@ pub fn evalComptimeInt(self: *Lowering, node: *const Node) ?i64 {
pub fn lowerComptimeGlobal(self: *Lowering, name: []const u8, expr: *const Node, type_ann: ?*const Node) void {
// When the user writes `NAME :: #run expr;` with no type annotation,
// infer the global's type from the comptime expression's return
// shape. `resolveType(null)` returns `.s64` for legacy reasons —
// shape. `resolveType(null)` returns `.i64` for legacy reasons —
// good for primitive helpers, silently wrong for anything else.
const expr_ty = self.inferExprType(expr);
// A failable `#run` (bare, no `catch`/`or`): the comptime function
@@ -1130,7 +1130,7 @@ pub fn foldComptimeFloatInit(self: *Lowering, node: *const Node, dst: TypeId) ?R
// `evalConstFloatExpr` only succeeds for literal / const-arithmetic
// nodes, never an unbound pack index. `inferExprType` is the primary
// signal, but it reads a const's DECLARED type — which is a placeholder
// `s64` for an untyped float-EXPRESSION const (`ME :: 4.0 + 1.0`), so
// `i64` for an untyped float-EXPRESSION const (`ME :: 4.0 + 1.0`), so
// `ME / 2` would look like integer division; `isFloatValuedExpr` (judging
// by VALUE) catches that case so it narrows under the unified rule too.
if (!isFloat(self.inferExprType(node)) and !program_index_mod.isFloatValuedExpr(node, self)) return null;

View File

@@ -61,7 +61,7 @@ pub fn lowerIfExpr(self: *Lowering, ie: *const ast.IfExpr) Ref {
// Optional binding: `if val := expr { ... }`
// Clear target_type so the ternary's result type doesn't leak into the condition
// (e.g., `if x != 0 then 1.0 else 2.0` — the `0` must be s64, not f32)
// (e.g., `if x != 0 then 1.0 else 2.0` — the `0` must be i64, not f32)
const saved_cond_target = self.target_type;
self.target_type = null;
const opt_val = self.lowerExpr(ie.condition);
@@ -273,12 +273,12 @@ pub fn listView(self: *Lowering, value: Ref, ty: TypeId) ?struct { data: Ref, da
return .{
.data = self.builder.emit(.{ .struct_get = .{ .base = value, .field_index = items_idx.? } }, items_ty),
.data_ty = items_ty,
.len = self.builder.emit(.{ .struct_get = .{ .base = value, .field_index = len_idx.? } }, .s64),
.len = self.builder.emit(.{ .struct_get = .{ .base = value, .field_index = len_idx.? } }, .i64),
};
}
/// Lowered prep for one position of a multi-iterable `for` header. Every
/// position gets its own s64 cursor slot (ranges start at their `start`,
/// position gets its own i64 cursor slot (ranges start at their `start`,
/// collections at 0); all cursors advance by 1 per iteration, and ONLY the
/// first position's bound terminates the loop (first-iterable-wins).
const IterPrep = struct {
@@ -316,13 +316,13 @@ pub fn lowerFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
for (fe.iterables, 0..) |it, i| {
if (it.is_range) {
var start_ref = self.lowerExpr(it.expr);
if (it.start_exclusive) start_ref = self.builder.add(start_ref, self.builder.constInt(1, .s64), .s64);
const slot = self.builder.alloca(.s64);
if (it.start_exclusive) start_ref = self.builder.add(start_ref, self.builder.constInt(1, .i64), .i64);
const slot = self.builder.alloca(.i64);
self.builder.store(slot, start_ref);
if (i == 0) {
// Parser guarantees the first iterable is bounded.
var end_ref = self.lowerExpr(it.range_end.?);
if (it.end_inclusive) end_ref = self.builder.add(end_ref, self.builder.constInt(1, .s64), .s64);
if (it.end_inclusive) end_ref = self.builder.add(end_ref, self.builder.constInt(1, .i64), .i64);
limit = end_ref;
}
preps.append(self.alloc, .{ .is_range = true, .slot = slot }) catch unreachable;
@@ -349,7 +349,7 @@ pub fn lowerFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
data_ty = lv.data_ty;
len = lv.len;
} else if (i == 0) {
len = self.builder.emit(.{ .length = .{ .operand = data } }, .s64);
len = self.builder.emit(.{ .length = .{ .operand = data } }, .i64);
}
const elem_ty = self.getElementType(data_ty);
@@ -367,8 +367,8 @@ pub fn lowerFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
}
const is_array = !data_ty.isBuiltin() and self.module.types.get(data_ty) == .array;
const storage = if (is_array and !was_deref) self.getExprAlloca(it.expr) else null;
const slot = self.builder.alloca(.s64);
self.builder.store(slot, self.builder.constInt(0, .s64));
const slot = self.builder.alloca(.i64);
self.builder.store(slot, self.builder.constInt(0, .i64));
if (i == 0) limit = len;
preps.append(self.alloc, .{
.is_range = false,
@@ -391,7 +391,7 @@ pub fn lowerFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
// Header: first cursor against the first bound.
self.builder.switchToBlock(header_bb);
const cur0 = self.builder.load(preps.items[0].slot, .s64);
const cur0 = self.builder.load(preps.items[0].slot, .i64);
const cmp = self.builder.cmpLt(cur0, limit);
self.builder.condBr(cmp, body_bb, &.{}, exit_bb, &.{});
@@ -404,9 +404,9 @@ pub fn lowerFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
for (fe.captures, 0..) |cap, i| {
const prep = preps.items[i];
const cur = if (i == 0) cur0 else self.builder.load(prep.slot, .s64);
const cur = if (i == 0) cur0 else self.builder.load(prep.slot, .i64);
if (prep.is_range) {
body_scope.put(cap.name, .{ .ref = cur, .ty = .s64, .is_alloca = false });
body_scope.put(cap.name, .{ .ref = cur, .ty = .i64, .is_alloca = false });
continue;
}
const bind_ty = if (cap.by_ref) self.module.types.ptrTo(prep.elem_ty) else prep.elem_ty;
@@ -453,10 +453,10 @@ pub fn lowerFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
// Increment block: advance every cursor and jump back to header.
self.builder.switchToBlock(inc_bb);
{
const one = self.builder.constInt(1, .s64);
const one = self.builder.constInt(1, .i64);
for (preps.items) |prep| {
const cur = self.builder.load(prep.slot, .s64);
const next = self.builder.add(cur, one, .s64);
const cur = self.builder.load(prep.slot, .i64);
const next = self.builder.add(cur, one, .i64);
self.builder.store(prep.slot, next);
}
self.builder.br(header_bb, &.{});
@@ -556,7 +556,7 @@ pub fn lowerInlineRangeFor(self: *Lowering, fe: *const ast.ForExpr) Ref {
// uses like `print(i)`) and as a comptime constant (for
// `xs[i]` substitution).
const v = start + i;
body_scope.put(cap.name, .{ .ref = self.builder.constInt(v, .s64), .ty = .s64, .is_alloca = false });
body_scope.put(cap.name, .{ .ref = self.builder.constInt(v, .i64), .ty = .i64, .is_alloca = false });
var save = CursorSave{ .name = cap.name, .had_prev = false, .prev = undefined };
if (self.comptime_constants.get(cap.name)) |p| {
save.had_prev = true;
@@ -796,11 +796,11 @@ pub fn lowerMatch(self: *Lowering, me: *const ast.MatchExpr) Ref {
}
// Switch on the subject (for type match, subject is either a
// bare TypeId (s64) or an Any-shaped Type value — unbox in the
// bare TypeId (i64) or an Any-shaped Type value — unbox in the
// latter case so the switch sees the i64 type id).
const tag = if (is_type_match) tag_blk: {
if (subject_ty == .any) {
break :tag_blk self.builder.emit(.{ .unbox_any = .{ .operand = subject } }, .s64);
break :tag_blk self.builder.emit(.{ .unbox_any = .{ .operand = subject } }, .i64);
}
break :tag_blk subject;
} else if (is_optional_match) self.builder.emit(.{ .optional_has_value = .{ .operand = subject } }, .bool) else if (is_error_set_match) subject else blk: {
@@ -810,7 +810,7 @@ pub fn lowerMatch(self: *Lowering, me: *const ast.MatchExpr) Ref {
const ty_info = self.module.types.get(subject_ty);
if (ty_info == .tagged_union) break :tt ty_info.tagged_union.tag_type;
}
break :tt .s32;
break :tt .i32;
};
break :blk self.builder.enumTag(subject, tag_ty);
};
@@ -836,7 +836,7 @@ pub fn lowerMatch(self: *Lowering, me: *const ast.MatchExpr) Ref {
if (is_optional_match) {
// For optional match, unwrap the optional value
const opt_info = self.module.types.get(subject_ty);
const child_ty = if (opt_info == .optional) opt_info.optional.child else .s64;
const child_ty = if (opt_info == .optional) opt_info.optional.child else .i64;
const unwrapped = self.builder.emit(.{ .optional_unwrap = .{ .operand = subject } }, child_ty);
arm_scope.put(capture_name, .{ .ref = unwrapped, .ty = child_ty, .is_alloca = false });
} else {

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);
}

View File

@@ -428,8 +428,8 @@ pub fn lowerCallerLocation(self: *Lowering, node: *const Node) Ref {
const func_name = self.currentFunctionName();
var fields = [_]Ref{
self.builder.constString(self.module.types.internString(file)),
self.builder.constInt(@intCast(loc.line), .s32),
self.builder.constInt(@intCast(loc.col), .s32),
self.builder.constInt(@intCast(loc.line), .i32),
self.builder.constInt(@intCast(loc.col), .i32),
self.builder.constString(self.module.types.internString(func_name)),
};
return self.builder.emit(.{ .struct_init = .{ .fields = self.alloc.dupe(Ref, &fields) catch unreachable } }, sl_tid);

View File

@@ -82,7 +82,7 @@ pub fn lowerStructLiteral(self: *Lowering, sl: *const ast.StructLiteral, span: a
// `.ambiguous`/`.not_visible` surface their loud diagnostic + poison.
self.resolveNominalLeaf(name, false, span)
else if (sl.type_expr) |te|
// Generic struct literal: Pair(s32).{ ... } — resolve type from type_expr
// Generic struct literal: Pair(i32).{ ... } — resolve type from type_expr
self.resolveTypeWithBindings(te)
else self.target_type orelse .unresolved;
@@ -315,7 +315,7 @@ pub fn fixupMethodReceiver(self: *Lowering, method_args: *std.ArrayList(Ref), fu
/// Get the name of a struct type (dereferencing pointers). Returns null for non-struct types.
pub fn getStructTypeName(self: *Lowering, ty: TypeId) ?[]const u8 {
if (ty.isBuiltin()) {
// Map builtin types to their names for method resolution (e.g., s64.eq)
// Map builtin types to their names for method resolution (e.g., i64.eq)
return builtinTypeName(ty);
}
var resolved = ty;
@@ -333,10 +333,10 @@ pub fn getStructTypeName(self: *Lowering, ty: TypeId) ?[]const u8 {
pub fn builtinTypeName(ty: TypeId) ?[]const u8 {
return switch (ty) {
.s8 => "s8",
.s16 => "s16",
.s32 => "s32",
.s64 => "s64",
.i8 => "i8",
.i16 => "i16",
.i32 => "i32",
.i64 => "i64",
.u8 => "u8",
.u16 => "u16",
.u32 => "u32",
@@ -351,7 +351,7 @@ pub fn builtinTypeName(ty: TypeId) ?[]const u8 {
/// Resolve the type of a named field on a given type.
pub fn resolveFieldType(self: *Lowering, ty: TypeId, field: []const u8) TypeId {
if (std.mem.eql(u8, field, "len")) return .s64;
if (std.mem.eql(u8, field, "len")) return .i64;
if (std.mem.eql(u8, field, "ptr")) {
const elem_ty = self.getElementType(ty);
return self.module.types.manyPtrTo(elem_ty);
@@ -497,7 +497,7 @@ pub fn lowerFieldAccess(self: *Lowering, fa: *const ast.FieldAccess, span: ast.S
if (self.pack_param_count) |ppc| {
if (fa.object.data == .identifier and std.mem.eql(u8, fa.field, "len")) {
if (ppc.get(fa.object.data.identifier.name)) |n| {
return self.builder.constInt(@as(i64, @intCast(n)), .s64);
return self.builder.constInt(@as(i64, @intCast(n)), .i64);
}
}
}
@@ -606,7 +606,7 @@ pub fn lowerFieldAccess(self: *Lowering, fa: *const ast.FieldAccess, span: ast.S
if (is_special) {
if (std.mem.eql(u8, fa.field, "len")) {
return self.builder.emit(.{ .length = .{ .operand = obj } }, .s64);
return self.builder.emit(.{ .length = .{ .operand = obj } }, .i64);
}
{
const elem_ty = self.getElementType(obj_ty);
@@ -658,7 +658,7 @@ pub fn identifierBindsValue(self: *Lowering, name: []const u8) bool {
/// a builtin type (a user struct → ordinary field lowering reports
/// field-not-found). Two clean diagnostics (then a placeholder, so lowering
/// finishes and `hasErrors()` aborts the build):
/// - a FLOAT-only accessor on an integer type (`s32.epsilon`, `u8.inf`);
/// - a FLOAT-only accessor on an integer type (`i32.epsilon`, `u8.inf`);
/// - any accessor on a builtin NON-numeric receiver
/// (`bool`/`string`/`void`/`Any`/`noreturn`).
pub fn lowerNumericLimit(self: *Lowering, fa: *const ast.FieldAccess, span: ast.Span) ?Ref {
@@ -704,7 +704,7 @@ pub fn lowerStructConstant(self: *Lowering, info: StructConstInfo) Ref {
return switch (val_node.data) {
.int_literal => |lit| blk: {
if (info.ty) |t| self.checkIntLiteralFits(lit.value, t, val_node.span);
break :blk self.builder.constInt(lit.value, info.ty orelse .s64);
break :blk self.builder.constInt(lit.value, info.ty orelse .i64);
},
.float_literal => |lit| self.builder.constFloat(lit.value, info.ty orelse .f64),
.bool_literal => |lit| self.builder.constBool(lit.value),
@@ -1199,9 +1199,9 @@ pub fn resolveArrayLiteralType(self: *Lowering, te: *const Node) TypeId {
return self.module.types.vectorOf(elem, length);
}
}
// Generic-struct typed-literal head (`Box(s64).[...]`): route
// Generic-struct typed-literal head (`Box(i64).[...]`): route
// through the single layout choke-point (CP-1). A qualified head
// `a.Box(s64).[...]` selects a's OWN template via the namespace edge
// `a.Box(i64).[...]` selects a's OWN template via the namespace edge
// (Counter-1: was the global last-wins map); a bare head selects the
// single bare-VISIBLE author.
if (headNameOfCallee(cl.callee)) |hn| {
@@ -1258,7 +1258,7 @@ pub fn lowerIndexExpr(self: *Lowering, ie: *const ast.IndexExpr) Ref {
// bounds" instead of the generic "unresolved 'args'" that the
// fall-through scope-lookup would produce.
if (self.diagPackIndexOOB(ie)) {
return self.builder.constInt(0, .s64);
return self.builder.constInt(0, .i64);
}
// Runtime index into a comptime-only pack (Decision 1): a pack has no
// runtime representation, so the index must be a compile-time constant.
@@ -1271,7 +1271,7 @@ pub fn lowerIndexExpr(self: *Lowering, ie: *const ast.IndexExpr) Ref {
if (self.diagnostics) |diags| {
diags.addFmt(.err, ie.index.span, "pack '{s}' must be indexed by a compile-time constant — a pack is comptime-only and has no runtime value", .{pname});
}
return self.builder.constInt(0, .s64);
return self.builder.constInt(0, .i64);
}
}
}
@@ -1306,10 +1306,10 @@ pub fn lowerIndexExpr(self: *Lowering, ie: *const ast.IndexExpr) Ref {
pub fn lowerSliceExpr(self: *Lowering, se: *const ast.SliceExpr) Ref {
const obj = self.lowerExpr(se.object);
var lo = if (se.start) |s| self.lowerExpr(s) else self.builder.constInt(0, .s64);
if (se.start_exclusive) lo = self.builder.add(lo, self.builder.constInt(1, .s64), .s64);
var hi = if (se.end) |e| self.lowerExpr(e) else self.builder.emit(.{ .length = .{ .operand = obj } }, .s64);
if (se.end_inclusive) hi = self.builder.add(hi, self.builder.constInt(1, .s64), .s64);
var lo = if (se.start) |s| self.lowerExpr(s) else self.builder.constInt(0, .i64);
if (se.start_exclusive) lo = self.builder.add(lo, self.builder.constInt(1, .i64), .i64);
var hi = if (se.end) |e| self.lowerExpr(e) else self.builder.emit(.{ .length = .{ .operand = obj } }, .i64);
if (se.end_inclusive) hi = self.builder.add(hi, self.builder.constInt(1, .i64), .i64);
// Infer result slice type from the object
const obj_ty = self.inferExprType(se.object);
// Subslice of string stays string (same {ptr, i64} layout, correct type category)
@@ -1598,8 +1598,8 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
}
}
const ty = if (self.target_type) |tt| blk: {
break :blk if (self.isIntEx(tt)) tt else .s64;
} else .s64;
break :blk if (self.isIntEx(tt)) tt else .i64;
} else .i64;
self.checkIntLiteralFits(lit.value, ty, node.span);
return self.builder.constInt(lit.value, ty);
},
@@ -1645,7 +1645,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
// Check compile-time constants (OS, ARCH, POINTER_SIZE) before globals
if (self.comptime_constants.get(id.name)) |cv| {
switch (cv) {
.int_val => |iv| break :blk self.builder.constInt(iv, .s64),
.int_val => |iv| break :blk self.builder.constInt(iv, .i64),
.enum_tag => |et| break :blk self.builder.constInt(@intCast(et.tag), et.ty),
}
}
@@ -1683,7 +1683,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
.untracked => break :blk self.builder.emit(.{ .global_get = gi.id }, gi.ty),
}
}
// Check module-level value constants (e.g. AF_INET :s32: 2)
// Check module-level value constants (e.g. AF_INET :i32: 2)
if (self.program_index.module_const_map.get(id.name)) |ci_global| {
if (!self.isNameVisible(id.name)) {
if (self.diagnostics) |d|
@@ -1820,7 +1820,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
// examples/50-smoke.sx has both shapes.
}
}
break :blk self.builder.emit(.{ .func_ref = fid }, .s64);
break :blk self.builder.emit(.{ .func_ref = fid }, .i64);
}
}
// Type-as-value: a name that resolves to a TypeId
@@ -1927,7 +1927,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
break :blk self.builder.constFloat(@floatFromInt(v), tt);
}
}
const nty = if (self.target_type) |tt| (if (self.isIntEx(tt)) tt else TypeId.s64) else TypeId.s64;
const nty = if (self.target_type) |tt| (if (self.isIntEx(tt)) tt else TypeId.i64) else TypeId.i64;
self.checkIntLiteralFits(v, nty, node.span);
break :blk self.builder.constInt(v, nty);
}
@@ -2031,7 +2031,7 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
},
// type_expr can appear as a variable reference when the name collides
// with a builtin type name (e.g. s2, u8). Check scope first.
// with a builtin type name (e.g. i2, u8). Check scope first.
.type_expr => |te| blk: {
if (self.scope) |scope| {
if (scope.lookup(te.name)) |binding| {
@@ -2057,8 +2057,8 @@ pub fn lowerExpr(self: *Lowering, node: *const Node) Ref {
// Compound type literals (`*T`, `[]T`, `[*]T`, `?T`, `[N]T`, fn types)
// in expression position are first-class `Type` values, exactly like
// the named form above (`t : Type = *s64;` ↔ `t : Type = f64;`). Also
// the path a static `cast(*s64) v` type argument takes — call args are
// the named form above (`t : Type = *i64;` ↔ `t : Type = f64;`). Also
// the path a static `cast(*i64) v` type argument takes — call args are
// lowered before the cast handler inspects the AST (issue 0118).
.pointer_type_expr,
.many_pointer_type_expr,
@@ -2128,7 +2128,7 @@ pub fn lowerBinaryOp(self: *Lowering, bop: *const ast.BinaryOp) Ref {
}
// Type-literal comparison fold: when both sides are type-shaped
// AST nodes (`s64`, `*u8`, `?T`, `[3]f64`, etc.) OR resolve to
// AST nodes (`i64`, `*u8`, `?T`, `[3]f64`, etc.) OR resolve to
// a static TypeId at lower time (`type_of(x)` for any
// statically-typed `x`), resolve each and emit a `const_bool`.
// Same semantic as `type_eq(A, B)` but using the standard `==`
@@ -2144,11 +2144,11 @@ pub fn lowerBinaryOp(self: *Lowering, bop: *const ast.BinaryOp) Ref {
}
}
// Any-shaped `==` (e.g. `t == s64` where `t: Type`): both
// Any-shaped `==` (e.g. `t == i64` where `t: Type`): both
// operands are 16-byte `{tag, value}` aggregates. LLVM
// doesn't accept `icmp` on aggregates directly. Decompose
// via `unbox_any` (which extracts the value field at
// `.s64`) and compare the i64s. Tag fields are stable
// `.i64`) and compare the i64s. Tag fields are stable
// across compilations of the same source so value-only
// identity is enough.
if (bop.op == .eq or bop.op == .neq) {
@@ -2157,8 +2157,8 @@ pub fn lowerBinaryOp(self: *Lowering, bop: *const ast.BinaryOp) Ref {
if (lhs_ty == .any and rhs_ty == .any) {
const lhs = self.lowerExpr(bop.lhs);
const rhs = self.lowerExpr(bop.rhs);
const lhs_val = self.builder.emit(.{ .unbox_any = .{ .operand = lhs } }, .s64);
const rhs_val = self.builder.emit(.{ .unbox_any = .{ .operand = rhs } }, .s64);
const lhs_val = self.builder.emit(.{ .unbox_any = .{ .operand = lhs } }, .i64);
const rhs_val = self.builder.emit(.{ .unbox_any = .{ .operand = rhs } }, .i64);
if (bop.op == .eq) {
return self.builder.emit(.{ .cmp_eq = .{ .lhs = lhs_val, .rhs = rhs_val } }, .bool);
} else {
@@ -2249,7 +2249,7 @@ pub fn lowerBinaryOp(self: *Lowering, bop: *const ast.BinaryOp) Ref {
if (rhs_ref_pointee) |p| rhs = self.builder.load(rhs, p);
self.target_type = saved_tt;
// Result type follows the shared promotion rule: an int LHS with a
// float RHS promotes to the float (`s64 * f32` → `f32`); vectors /
// float RHS promotes to the float (`i64 * f32` → `f32`); vectors /
// structs keep the LHS type. `inferExprType` reuses the same helper
// so static typing agrees with the value produced here.
const rhs_inferred = rhs_ref_pointee orelse self.inferExprType(bop.rhs);
@@ -2298,7 +2298,7 @@ pub fn lowerBinaryOp(self: *Lowering, bop: *const ast.BinaryOp) Ref {
}
// Reject scalar ops on incompatible operand types (e.g.
// `s64 + string`, `s64 < string`, `s64 & string`). The result type
// `i64 + string`, `i64 < string`, `i64 & string`). The result type
// `ty` is derived from the LHS, so without this the op lowers as
// `<op> : <lhs>` and either reinterprets the RHS bytes (arithmetic
// / bitwise → garbage) or feeds mismatched LLVM types to `icmp`
@@ -2448,7 +2448,7 @@ pub fn lowerTupleOp(self: *Lowering, bop: *const ast.BinaryOp, lhs: Ref, rhs: Re
// Lexicographic comparison
return self.lowerTupleLexCompare(bop.op, lhs, rhs, lhs_fields);
},
else => return self.builder.constInt(0, .s64),
else => return self.builder.constInt(0, .i64),
}
}

View File

@@ -318,14 +318,14 @@ pub fn lowerForeignMethodCall(
const ret_ty = if (method.return_type) |rt| self.resolveType(rt) else .void;
// Reject return types the JNI emit path can't dispatch — emit_llvm's
// Call<T>Method switch only covers void / bool / s32 / s64 / f32 / f64
// / pointer-returning. Anything else (s8 / s16 / u8 / u16 / aggregates)
// Call<T>Method switch only covers void / bool / i32 / i64 / f32 / f64
// / pointer-returning. Anything else (i8 / i16 / u8 / u16 / aggregates)
// would silently lower to LLVMGetUndef and produce wrong arguments at
// the call site (chess Android touch shipped broken because s32→s32+
// the call site (chess Android touch shipped broken because i32→i32+
// f32 returns hit the undef path before .f32 was wired up).
if (!jni_descriptor.isJniReturnTypeSupported(&self.module.types, ret_ty)) {
if (self.diagnostics) |d| {
d.addFmt(.err, span, "JNI method '{s}.{s}' returns '{s}', which isn't supported by the JNI call-method lowering yet — only void/bool/s32/s64/f32/f64 and pointers are wired up", .{ fcd.name, method.name, self.module.types.typeName(ret_ty) });
d.addFmt(.err, span, "JNI method '{s}.{s}' returns '{s}', which isn't supported by the JNI call-method lowering yet — only void/bool/i32/i64/f32/f64 and pointers are wired up", .{ fcd.name, method.name, self.module.types.typeName(ret_ty) });
}
return Ref.none;
}

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);

View File

@@ -102,7 +102,7 @@ pub fn reserveShadowEnumSlot(self: *Lowering, ed: *const ast.EnumDecl) void {
const name_id = table.internString(ed.name);
const nominal_id = self.shadowNominalId(name_id);
const empty: types.TypeInfo = if (ed.variant_types.len > 0)
.{ .tagged_union = .{ .name = name_id, .fields = &.{}, .tag_type = .s64 } }
.{ .tagged_union = .{ .name = name_id, .fields = &.{}, .tag_type = .i64 } }
else
.{ .@"enum" = .{ .name = name_id, .variants = &.{} } };
const reserved = table.internNominal(empty, nominal_id);
@@ -534,7 +534,7 @@ pub fn bareVisibleStructTemplate(self: *Lowering, name: []const u8) ?StructTempl
}
/// Instantiate a generic struct template and register the result under an
/// alias name (`Vec3 :: Vec(3, f32)` / `ABox :: a.Box(s64)`). Shared by the
/// alias name (`Vec3 :: Vec(3, f32)` / `ABox :: a.Box(i64)`). Shared by the
/// `.call` and `.parameterized_type_expr` const-decl alias branches and the
/// qualified-head selection that precedes the bare `struct_template_map`
/// fallback in each.

View File

@@ -906,10 +906,10 @@ pub fn emitObjcDefinedAllocAndInit(
// (3) memset(state, 0, STATE_SIZE) — zero everything including the
// allocator slot; the next store re-writes the allocator slot.
const memset_fid = self.ensureCRuntimeDecl("memset", &.{ ptr_void, .s32, .u64 }, ptr_void);
const memset_fid = self.ensureCRuntimeDecl("memset", &.{ ptr_void, .i32, .u64 }, ptr_void);
const memset_args = self.alloc.alloc(Ref, 3) catch return null;
memset_args[0] = state;
memset_args[1] = self.builder.constInt(0, .s32);
memset_args[1] = self.builder.constInt(0, .i32);
memset_args[2] = size_const;
_ = self.builder.emit(.{ .call = .{ .callee = memset_fid, .args = memset_args } }, ptr_void);

View File

@@ -176,10 +176,10 @@ pub fn lowerPackToSlice(self: *Lowering, pack_name: []const u8, slice_ty: TypeId
};
const slice_slot = self.builder.alloca(slice_ty);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, self.module.types.ptrTo(elem_ty), slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, slice_ty);
if (arg_nodes.len == 0) {
self.builder.store(ptr_gep, self.builder.constNull(self.module.types.ptrTo(elem_ty)));
self.builder.store(len_gep, self.builder.constInt(0, .s64));
self.builder.store(len_gep, self.builder.constInt(0, .i64));
return self.builder.load(slice_slot, slice_ty);
}
const array_ty = self.module.types.arrayOf(elem_ty, @intCast(arg_nodes.len));
@@ -193,12 +193,12 @@ pub fn lowerPackToSlice(self: *Lowering, pack_name: []const u8, slice_ty: TypeId
} else if (elem_is_protocol) {
if (source_ty != elem_ty) val = self.buildProtocolErasure(val, arg, source_ty, elem_ty);
}
const ep = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = self.builder.constInt(@intCast(i), .s64) } }, self.module.types.ptrTo(elem_ty));
const ep = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = self.builder.constInt(@intCast(i), .i64) } }, self.module.types.ptrTo(elem_ty));
self.builder.store(ep, val);
}
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = self.builder.constInt(0, .s64) } }, self.module.types.ptrTo(elem_ty));
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = self.builder.constInt(0, .i64) } }, self.module.types.ptrTo(elem_ty));
self.builder.store(ptr_gep, data_ptr);
self.builder.store(len_gep, self.builder.constInt(@intCast(arg_nodes.len), .s64));
self.builder.store(len_gep, self.builder.constInt(@intCast(arg_nodes.len), .i64));
return self.builder.load(slice_slot, slice_ty);
}
@@ -211,12 +211,12 @@ pub fn lowerVariadicArgs(self: *Lowering, param_name: []const u8, call_args: []c
if (n == 0) {
// Empty slice: {null, 0}
const null_ptr = self.builder.constNull(self.module.types.ptrTo(.any));
const zero_len = self.builder.constInt(0, .s64);
const zero_len = self.builder.constInt(0, .i64);
const slice_slot = self.builder.alloca(any_slice_ty);
// Store ptr (field 0) and len (field 1) into the slice alloca
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, self.module.types.ptrTo(.any), any_slice_ty);
self.builder.store(ptr_gep, null_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, any_slice_ty);
self.builder.store(len_gep, zero_len);
if (self.scope) |scope| {
scope.put(param_name, .{ .ref = slice_slot, .ty = any_slice_ty, .is_alloca = true });
@@ -232,7 +232,7 @@ pub fn lowerVariadicArgs(self: *Lowering, param_name: []const u8, call_args: []c
for (call_args[start_idx..], 0..) |arg, i| {
var val = self.lowerExpr(arg);
var source_ty = self.inferExprType(arg);
// If AST-based inference falls back to .s64 but the lowered ref is a string/struct, use that
// If AST-based inference falls back to .i64 but the lowered ref is a string/struct, use that
if (source_ty == .unresolved) {
const ref_ty = self.builder.getRefType(val);
if (ref_ty == .string or ref_ty == .f32 or ref_ty == .f64 or ref_ty == .bool) {
@@ -270,7 +270,7 @@ pub fn lowerVariadicArgs(self: *Lowering, param_name: []const u8, call_args: []c
}
const boxed = if (source_ty == .any) val else self.builder.boxAny(val, source_ty);
// GEP to array[i] and store
const idx_ref = self.builder.constInt(@intCast(i), .s64);
const idx_ref = self.builder.constInt(@intCast(i), .i64);
const elem_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = idx_ref } }, self.module.types.ptrTo(.any));
self.builder.store(elem_ptr, boxed);
}
@@ -278,13 +278,13 @@ pub fn lowerVariadicArgs(self: *Lowering, param_name: []const u8, call_args: []c
// Build slice {ptr_to_first_element, len}
const slice_slot = self.builder.alloca(any_slice_ty);
// Get pointer to first element (array_slot is *[N x Any], GEP to element 0 gives *Any)
const zero = self.builder.constInt(0, .s64);
const zero = self.builder.constInt(0, .i64);
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = zero } }, self.module.types.ptrTo(.any));
const len_ref = self.builder.constInt(@intCast(n), .s64);
const len_ref = self.builder.constInt(@intCast(n), .i64);
// Store into slice fields
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, self.module.types.ptrTo(.any), any_slice_ty);
self.builder.store(ptr_gep, data_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, any_slice_ty);
self.builder.store(len_gep, len_ref);
if (self.scope) |scope| {
@@ -351,11 +351,11 @@ pub fn packVariadicCallArgs(self: *Lowering, fd: *const ast.FnDecl, c: *const as
if (variadic_count == 0) {
// Empty slice
const null_ptr = self.builder.constNull(self.module.types.ptrTo(elem_ty));
const zero_len = self.builder.constInt(0, .s64);
const zero_len = self.builder.constInt(0, .i64);
const slice_slot = self.builder.alloca(slice_ty);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, self.module.types.ptrTo(elem_ty), slice_ty);
self.builder.store(ptr_gep, null_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, slice_ty);
self.builder.store(len_gep, zero_len);
const slice_val = self.builder.load(slice_slot, slice_ty);
// Replace args: keep fixed args, append slice
@@ -385,7 +385,7 @@ pub fn packVariadicCallArgs(self: *Lowering, fd: *const ast.FnDecl, c: *const as
var val = args.items[fixed_count + i];
if (is_any) {
var source_ty = self.inferExprType(c.args[fixed_count + i]);
// If AST-based inference falls back to .s64 but the lowered ref has a richer type, use that
// If AST-based inference falls back to .i64 but the lowered ref has a richer type, use that
if (source_ty == .unresolved) {
const ref_ty = self.builder.getRefType(val);
if (ref_ty != .unresolved and ref_ty != .void) source_ty = ref_ty;
@@ -432,19 +432,19 @@ pub fn packVariadicCallArgs(self: *Lowering, fd: *const ast.FnDecl, c: *const as
val = self.buildProtocolErasure(val, arg_node, source_ty, elem_ty);
}
}
const idx_ref = self.builder.constInt(@intCast(i), .s64);
const idx_ref = self.builder.constInt(@intCast(i), .i64);
const elem_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = idx_ref } }, self.module.types.ptrTo(array_elem));
self.builder.store(elem_ptr, val);
}
// Build slice {ptr, len}
const slice_slot = self.builder.alloca(slice_ty);
const zero = self.builder.constInt(0, .s64);
const zero = self.builder.constInt(0, .i64);
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = zero } }, self.module.types.ptrTo(array_elem));
const len_ref = self.builder.constInt(@intCast(variadic_count), .s64);
const len_ref = self.builder.constInt(@intCast(variadic_count), .i64);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, self.module.types.ptrTo(array_elem), slice_ty);
self.builder.store(ptr_gep, data_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, slice_ty);
self.builder.store(len_gep, len_ref);
const slice_val = self.builder.load(slice_slot, slice_ty);
@@ -476,11 +476,11 @@ pub fn buildPackSliceValue(self: *Lowering, arg_types: []const TypeId) Ref {
if (arg_types.len == 0) {
const null_ptr = self.builder.constNull(any_ptr_ty);
const zero_len = self.builder.constInt(0, .s64);
const zero_len = self.builder.constInt(0, .i64);
const slice_slot = self.builder.alloca(any_slice_ty);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, any_ptr_ty, any_slice_ty);
self.builder.store(ptr_gep, null_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, any_slice_ty);
self.builder.store(len_gep, zero_len);
return self.builder.load(slice_slot, any_slice_ty);
}
@@ -493,18 +493,18 @@ pub fn buildPackSliceValue(self: *Lowering, arg_types: []const TypeId) Ref {
// (`{tag=.any, value=tid}`) — already the canonical Any
// shape, so no re-box needed.
const type_val = self.builder.constType(ty);
const idx_ref = self.builder.constInt(@intCast(i), .s64);
const idx_ref = self.builder.constInt(@intCast(i), .i64);
const elem_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = idx_ref } }, any_ptr_ty);
self.builder.store(elem_ptr, type_val);
}
const slice_slot = self.builder.alloca(any_slice_ty);
const zero = self.builder.constInt(0, .s64);
const zero = self.builder.constInt(0, .i64);
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = zero } }, any_ptr_ty);
const len_ref = self.builder.constInt(@intCast(arg_types.len), .s64);
const len_ref = self.builder.constInt(@intCast(arg_types.len), .i64);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, any_ptr_ty, any_slice_ty);
self.builder.store(ptr_gep, data_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, any_slice_ty);
self.builder.store(len_gep, len_ref);
return self.builder.load(slice_slot, any_slice_ty);
}
@@ -521,11 +521,11 @@ pub fn materialisePackSlice(
if (arg_types.len == 0) {
const null_ptr = self.builder.constNull(any_ptr_ty);
const zero_len = self.builder.constInt(0, .s64);
const zero_len = self.builder.constInt(0, .i64);
const slice_slot = self.builder.alloca(any_slice_ty);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, any_ptr_ty, any_slice_ty);
self.builder.store(ptr_gep, null_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, any_slice_ty);
self.builder.store(len_gep, zero_len);
scope.put(pack_name, .{ .ref = slice_slot, .ty = any_slice_ty, .is_alloca = true });
return;
@@ -537,18 +537,18 @@ pub fn materialisePackSlice(
for (slot_refs, arg_types, 0..) |slot, ty, i| {
const val = self.builder.load(slot, ty);
const boxed = if (ty == .any) val else self.builder.boxAny(val, ty);
const idx_ref = self.builder.constInt(@intCast(i), .s64);
const idx_ref = self.builder.constInt(@intCast(i), .i64);
const elem_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = idx_ref } }, any_ptr_ty);
self.builder.store(elem_ptr, boxed);
}
const slice_slot = self.builder.alloca(any_slice_ty);
const zero = self.builder.constInt(0, .s64);
const zero = self.builder.constInt(0, .i64);
const data_ptr = self.builder.emit(.{ .index_gep = .{ .lhs = array_slot, .rhs = zero } }, any_ptr_ty);
const len_ref = self.builder.constInt(@intCast(arg_types.len), .s64);
const len_ref = self.builder.constInt(@intCast(arg_types.len), .i64);
const ptr_gep = self.builder.structGepTyped(slice_slot, 0, any_ptr_ty, any_slice_ty);
self.builder.store(ptr_gep, data_ptr);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .s64, any_slice_ty);
const len_gep = self.builder.structGepTyped(slice_slot, 1, .i64, any_slice_ty);
self.builder.store(len_gep, len_ref);
scope.put(pack_name, .{ .ref = slice_slot, .ty = any_slice_ty, .is_alloca = true });
}
@@ -558,8 +558,8 @@ pub fn materialisePackSlice(
/// type: a `return X;` statement's value type, or — failing that —
/// the tail expression of an arrow-form body. Caller must have
/// `pack_arg_nodes` installed so `args[<lit>]` substitutes during
/// inference. Falls back to `.s64` if nothing concrete is found
/// (matches the broader "default to .s64" convention elsewhere).
/// inference. Falls back to `.i64` if nothing concrete is found
/// (matches the broader "default to .i64" convention elsewhere).
pub fn inferPackBodyReturnType(self: *Lowering, body: *const Node) TypeId {
// First try explicit `return X;` — walks past structured
// control flow but stops at nested fn / lambda bodies.

View File

@@ -67,10 +67,10 @@ pub fn registerProtocolDecl(self: *Lowering, pd: *const ast.ProtocolDecl) void {
}
/// Instantiate a parameterized protocol as a runtime VALUE type:
/// `VL(s64)` → a 16-byte `{ctx, __vtable}` protocol value (`is_protocol`),
/// `VL(i64)` → a 16-byte `{ctx, __vtable}` protocol value (`is_protocol`),
/// with method infos resolved under the type-arg binding (so `get -> T`
/// becomes `get -> s64`) and the binding recorded for projection. Cached by
/// the mangled name `VL__s64`. Mirrors the non-parameterized path in
/// becomes `get -> i64`) and the binding recorded for projection. Cached by
/// the mangled name `VL__i64`. Mirrors the non-parameterized path in
/// `registerProtocolDecl`.
pub fn instantiateParamProtocol(self: *Lowering, pd: *const ast.ProtocolDecl, args: []const *const Node) TypeId {
const table = &self.module.types;
@@ -105,7 +105,7 @@ pub fn instantiateParamProtocol(self: *Lowering, pd: *const ast.ProtocolDecl, ar
const id = if (table.findByName(name_id)) |existing| existing else table.intern(struct_info);
table.updatePreservingKey(id, struct_info);
// Method infos resolved with the type-arg binding (T → s64), pinned to
// Method infos resolved with the type-arg binding (T → i64), pinned to
// the protocol's OWN module (E4) so a method-signature type visible only
// there resolves correctly when instantiated cross-module. `Self` and the
// bound type-args short-circuit before the leaf; a concrete library type
@@ -332,10 +332,10 @@ pub fn createProtocolThunk(self: *Lowering, proto_name: []const u8, concrete_typ
if (self.program_index.fn_ast_map.contains(qualified)) {
self.lazyLowerFunction(qualified);
} else if (self.genericInstanceMethod(concrete_type_name, method.name)) |gm| {
// Generic-struct instance (`Combined__s64_s64`): the impl method is
// Generic-struct instance (`Combined__i64_i64`): the impl method is
// authored on the instance's STAMPED decl (CP-4). Monomorphize it
// for this instance's bindings so the thunk has a concrete
// `Combined__s64_s64.get` to call.
// `Combined__i64_i64.get` to call.
self.monomorphizeFunction(gm.fd, qualified, gm.bindings);
}
}
@@ -441,7 +441,7 @@ pub fn buildProtocolValue(self: *Lowering, concrete_ptr: Ref, proto_name: []cons
var ctx_ptr = concrete_ptr;
if (heap_copy) {
const concrete_size = self.module.types.typeSizeBytes(concrete_ty);
const size_ref = self.builder.constInt(@intCast(concrete_size), .s64);
const size_ref = self.builder.constInt(@intCast(concrete_size), .i64);
const heap_ptr = self.allocViaContext(size_ref, void_ptr_ty);
_ = self.callForeign("memcpy", &.{ heap_ptr, concrete_ptr, size_ref }, void_ptr_ty);
ctx_ptr = heap_ptr;
@@ -591,7 +591,7 @@ pub fn emitProtocolDispatch(self: *Lowering, receiver: Ref, proto_info: Protocol
/// Handles both direct types and pointer-to-types.
pub fn resolveConcreteTypeName(self: *Lowering, ty: TypeId) ?[]const u8 {
if (ty.isBuiltin()) {
// Primitive types like s64 — check if they have toName()
// Primitive types like i64 — check if they have toName()
return self.module.types.typeName(ty);
}
const info = self.module.types.get(ty);

View File

@@ -329,7 +329,7 @@ pub fn lowerVarDecl(self: *Lowering, vd: *const ast.VarDecl) void {
}
}
}
// Coerce value to match target type (e.g. u8 → s64 widening)
// Coerce value to match target type (e.g. u8 → i64 widening)
{
const ref_ty = self.builder.getRefType(ref);
if (ref_ty != ty and ref_ty != .void and ty != .void) {
@@ -354,7 +354,7 @@ pub fn lowerVarDecl(self: *Lowering, vd: *const ast.VarDecl) void {
self.force_block_value = true;
// An unannotated decl provides no target type: clear the ambient one
// (the enclosing fn's implicit-return target) so literal initializers
// take their spec defaults (s64/f64) instead of adopting it.
// take their spec defaults (i64/f64) instead of adopting it.
self.target_type = null;
const ref = self.lowerExpr(val);
self.force_block_value = saved_fbv;
@@ -366,7 +366,7 @@ pub fn lowerVarDecl(self: *Lowering, vd: *const ast.VarDecl) void {
scope.put(vd.name, .{ .ref = slot, .ty = ty, .is_alloca = true });
}
} else {
const ty = TypeId.s64;
const ty = TypeId.i64;
const slot = self.builder.alloca(ty);
self.builder.store(slot, self.zeroValue(ty));
if (self.scope) |scope| {
@@ -390,7 +390,7 @@ pub fn lowerLocalFnDecl(self: *Lowering, fd: *const ast.FnDecl) void {
}
pub fn lowerConstDecl(self: *Lowering, cd: *const ast.ConstDecl) void {
// Handle local function declarations: fx :: (s:s3) -> s3 { ... }
// Handle local function declarations: fx :: (s:i3) -> i3 { ... }
if (cd.value.data == .fn_decl) {
const fd = &cd.value.data.fn_decl;
// Use mangled name for local functions to support block-scoped shadowing
@@ -448,15 +448,15 @@ pub fn lowerReturn(self: *Lowering, rs: *const ast.ReturnStmt) void {
}
// Set target_type to function return type so null_literal etc. get the right type.
// When inlining a comptime body, the *inlined* fn's declared return type wins
// over the caller's — otherwise `return 42` inside a `-> s64` body lowered into
// a `-> s32` caller would coerce 42 to s32 before storing into the s64 slot.
// over the caller's — otherwise `return 42` inside a `-> i64` body lowered into
// a `-> i32` caller would coerce 42 to i32 before storing into the i64 slot.
const old_target = self.target_type;
const ret_ty_for_target: TypeId = if (self.inline_return_target) |iri|
iri.ret_ty
else if (self.builder.func) |fid|
self.module.functions.items[@intFromEnum(fid)].ret
else
TypeId.s64;
TypeId.i64;
// A value-carrying failable (`-> (T..., !)`) returns its VALUE part and
// the success error slot (0) is appended by lowerFailableSuccessReturn.
// Resolve a BARE returned value against that value type, NOT the failable
@@ -523,7 +523,7 @@ pub fn lowerReturn(self: *Lowering, rs: *const ast.ReturnStmt) void {
const ret_ty = if (self.builder.func) |fid|
self.module.functions.items[@intFromEnum(fid)].ret
else
TypeId.s64;
TypeId.i64;
if (ret_ty == .void) {
// Void function — just return void (the value expression was evaluated for side effects)
self.builder.retVoid();
@@ -532,7 +532,7 @@ pub fn lowerReturn(self: *Lowering, rs: *const ast.ReturnStmt) void {
// value part; the compiler appends the success error slot (0).
self.lowerFailableSuccessReturn(ref, ret_ty, rs.value.?.span);
} else {
// Coerce return value to match function return type (e.g., ?s32 → s32)
// Coerce return value to match function return type (e.g., ?i32 → i32)
const val_ty = self.builder.getRefType(ref);
const coerced = self.coerceToType(ref, val_ty, ret_ty);
self.builder.ret(coerced, ret_ty);
@@ -748,11 +748,11 @@ pub fn lowerAssignment(self: *Lowering, asgn: *const ast.Assignment) void {
} else false);
if (is_special_container and std.mem.eql(u8, fa.field, "len")) {
const gep = self.builder.structGepTyped(obj_ptr, 1, .s64, obj_ty);
self.storeOrCompound(gep, val, asgn.op, .s64);
const gep = self.builder.structGepTyped(obj_ptr, 1, .i64, obj_ty);
self.storeOrCompound(gep, val, asgn.op, .i64);
} else if (is_special_container and std.mem.eql(u8, fa.field, "ptr")) {
const gep = self.builder.structGepTyped(obj_ptr, 0, .s64, obj_ty);
self.storeOrCompound(gep, val, asgn.op, .s64);
const gep = self.builder.structGepTyped(obj_ptr, 0, .i64, obj_ty);
self.storeOrCompound(gep, val, asgn.op, .i64);
} else if (self.fieldLvaluePtr(obj_ptr, obj_ty, fa.field)) |fl| {
// Resolve the target field (struct / union direct / promoted
// anonymous-struct member / tuple element / vector lane) via
@@ -986,7 +986,7 @@ pub fn lowerExprAsPtr(self: *Lowering, node: *const Node) Ref {
// resolver so address-of and the multi-target store path never
// disagree on the slot. No match → emit the read path's
// field-not-found diagnostic (lowerFieldAccessOnType →
// emitFieldError) instead of silently GEPing field 0 as .s64;
// emitFieldError) instead of silently GEPing field 0 as .i64;
// that bogus pointer reaches LLVM emission as ptrTo(.unresolved)
// and panics.
if (self.fieldLvaluePtr(obj_ptr, obj_ty, fa.field)) |r| return r.ptr;