sema/ir: kill remaining s64 fallbacks (sema Type + getRefType)

- types.Type: add dedicated `unresolved` variant (mirrors ir.TypeId.unresolved)
  with eql/displayName arms; bridgeType maps it to TypeId.unresolved.
- sema.inferExprType + signature/field resolution: every Type.fromTypeExpr /
  fromName / symbol lookup miss and call/field/index fallthrough now yields
  Type.unresolved instead of a fabricated s(64). A variadic `..xs: []T` slice
  element is taken from T, not a guessed "s32". Genuine literal defaults
  (int=>s64, float=>f32, .len=>s64) kept.
- Builder.getRefType: an unlocatable ref (no active function / out-of-range)
  returns .unresolved, not .s64 -- this is the accurate type source the pack
  mono / binop / null-cmp fixes rely on, so it must not fabricate.

236 examples + unit tests (incl sema) green.
This commit is contained in:
agra
2026-05-30 00:38:23 +03:00
parent 8bc2ed4c49
commit f21b99c811
4 changed files with 33 additions and 19 deletions

View File

@@ -136,11 +136,16 @@ pub const Analyzer = struct {
var param_types = std.ArrayList(Type).empty;
var has_variadic = false;
for (fd.params) |param| {
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.s(64);
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.unresolved;
if (param.is_variadic) {
has_variadic = true;
// Variadic param becomes a slice type
const elem_name = if (param.type_expr.data == .type_expr) param.type_expr.data.type_expr.name else "s32";
const elem_name = switch (param.type_expr.data) {
.type_expr => |te| te.name,
// `..xs: []T` — the element is T, not a guessed s32.
.slice_type_expr => |st| if (st.element_type.data == .type_expr) st.element_type.data.type_expr.name else "<unresolved>",
else => "<unresolved>",
};
try param_types.append(self.allocator, .{ .slice_type = .{ .element_name = elem_name } });
} else {
try param_types.append(self.allocator, pt);
@@ -169,7 +174,7 @@ pub const Analyzer = struct {
const lam = cd.value.data.lambda;
var param_types = std.ArrayList(Type).empty;
for (lam.params) |param| {
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.s(64);
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.unresolved;
try param_types.append(self.allocator, pt);
}
const ret = if (lam.return_type) |rt|
@@ -222,7 +227,7 @@ pub const Analyzer = struct {
}
if (i < sd.field_names.len) {
try all_names.append(self.allocator, sd.field_names[i]);
const resolved = Type.fromTypeExpr(sd.field_types[i]) orelse Type.s(64);
const resolved = Type.fromTypeExpr(sd.field_types[i]) orelse Type.unresolved;
try all_types.append(self.allocator, resolved);
}
}
@@ -233,7 +238,7 @@ pub const Analyzer = struct {
} else {
var field_types = std.ArrayList(Type).empty;
for (sd.field_types) |ft| {
const resolved = Type.fromTypeExpr(ft) orelse Type.s(64);
const resolved = Type.fromTypeExpr(ft) orelse Type.unresolved;
try field_types.append(self.allocator, resolved);
}
try self.struct_types.put(sd.name, .{
@@ -369,11 +374,11 @@ pub const Analyzer = struct {
j -= 1;
const sym = self.symbols.items[indices.items[j]];
if (sym.scope_depth <= self.scope_depth) {
return sym.ty orelse Type.s(64);
return sym.ty orelse Type.unresolved;
}
}
}
return Type.s(64);
return Type.unresolved;
},
.if_expr => |ie| {
return self.inferExprType(ie.then_branch);
@@ -391,7 +396,7 @@ pub const Analyzer = struct {
return .void_type;
},
.call => |call_node| {
const callee_name = self.resolveCalleeName(call_node) orelse return Type.s(64);
const callee_name = self.resolveCalleeName(call_node) orelse return Type.unresolved;
// Check fn_signatures registry
if (self.fn_signatures.get(callee_name)) |sig| {
return sig.return_type;
@@ -405,7 +410,7 @@ pub const Analyzer = struct {
if (call_node.args.len > 0) return self.inferExprType(call_node.args[0]);
return .f32;
}
return Type.s(64);
return Type.unresolved;
},
.unary_op => |unop| {
return self.inferExprType(unop.operand);
@@ -426,17 +431,17 @@ pub const Analyzer = struct {
}
}
if (obj_ty.isArray()) {
return Type.fromName(obj_ty.array_type.element_name) orelse Type.s(64);
return Type.fromName(obj_ty.array_type.element_name) orelse Type.unresolved;
}
return Type.s(64);
return Type.unresolved;
},
.index_expr => |ie| {
const obj_ty = self.inferExprType(ie.object);
if (obj_ty == .string_type) return Type.u(8);
if (obj_ty.isArray()) {
return Type.fromName(obj_ty.array_type.element_name) orelse Type.s(64);
return Type.fromName(obj_ty.array_type.element_name) orelse Type.unresolved;
}
return Type.s(64);
return Type.unresolved;
},
.slice_expr => |se| {
const obj_ty = self.inferExprType(se.object);
@@ -677,7 +682,7 @@ pub const Analyzer = struct {
{
var param_types = std.ArrayList(Type).empty;
for (fd.params) |param| {
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.s(64);
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.unresolved;
try param_types.append(self.allocator, pt);
}
try self.fn_signatures.put(fd.name, .{
@@ -1026,7 +1031,7 @@ pub const Analyzer = struct {
fn inferFnReturnType(self: *Analyzer, params: []const ast.Param, body: *const Node) ?Type {
self.pushScope() catch return null;
for (params) |param| {
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.s(64);
const pt = Type.fromTypeExpr(param.type_expr) orelse Type.unresolved;
self.addSymbol(param.name, .param, pt, param.name_span) catch {};
}
// Arrow fn_decl wraps body in block{[expr]} — unwrap to inner expression