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:
@@ -321,9 +321,11 @@ pub const Builder = struct {
|
|||||||
blk.first_ref = self.inst_counter;
|
blk.first_ref = self.inst_counter;
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Get the type of a previously emitted instruction Ref.
|
/// Get the type of a previously emitted instruction Ref. A ref that can't
|
||||||
|
/// be located (no active function, or an out-of-range ref) has no knowable
|
||||||
|
/// type — return the `.unresolved` sentinel rather than a fabricated `.s64`.
|
||||||
pub fn getRefType(self: *Builder, ref: Ref) TypeId {
|
pub fn getRefType(self: *Builder, ref: Ref) TypeId {
|
||||||
if (self.func == null) return .s64;
|
if (self.func == null) return .unresolved;
|
||||||
const func = self.currentFunc();
|
const func = self.currentFunc();
|
||||||
const ref_idx = @intFromEnum(ref);
|
const ref_idx = @intFromEnum(ref);
|
||||||
// Check function parameters first (refs 0..N-1)
|
// Check function parameters first (refs 0..N-1)
|
||||||
@@ -336,7 +338,7 @@ pub const Builder = struct {
|
|||||||
return block.insts.items[ref_idx - first].ty;
|
return block.insts.items[ref_idx - first].ty;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
return .s64;
|
return .unresolved;
|
||||||
}
|
}
|
||||||
|
|
||||||
// ── Emit helpers ────────────────────────────────────────────────
|
// ── Emit helpers ────────────────────────────────────────────────
|
||||||
|
|||||||
@@ -163,6 +163,7 @@ pub fn bridgeType(ty: sx_types.Type, table: *TypeTable) TypeId {
|
|||||||
} });
|
} });
|
||||||
},
|
},
|
||||||
.meta_type => .any, // meta types map to Any for now
|
.meta_type => .any, // meta types map to Any for now
|
||||||
|
.unresolved => .unresolved,
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|||||||
35
src/sema.zig
35
src/sema.zig
@@ -136,11 +136,16 @@ pub const Analyzer = struct {
|
|||||||
var param_types = std.ArrayList(Type).empty;
|
var param_types = std.ArrayList(Type).empty;
|
||||||
var has_variadic = false;
|
var has_variadic = false;
|
||||||
for (fd.params) |param| {
|
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) {
|
if (param.is_variadic) {
|
||||||
has_variadic = true;
|
has_variadic = true;
|
||||||
// Variadic param becomes a slice type
|
// 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 } });
|
try param_types.append(self.allocator, .{ .slice_type = .{ .element_name = elem_name } });
|
||||||
} else {
|
} else {
|
||||||
try param_types.append(self.allocator, pt);
|
try param_types.append(self.allocator, pt);
|
||||||
@@ -169,7 +174,7 @@ pub const Analyzer = struct {
|
|||||||
const lam = cd.value.data.lambda;
|
const lam = cd.value.data.lambda;
|
||||||
var param_types = std.ArrayList(Type).empty;
|
var param_types = std.ArrayList(Type).empty;
|
||||||
for (lam.params) |param| {
|
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);
|
try param_types.append(self.allocator, pt);
|
||||||
}
|
}
|
||||||
const ret = if (lam.return_type) |rt|
|
const ret = if (lam.return_type) |rt|
|
||||||
@@ -222,7 +227,7 @@ pub const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
if (i < sd.field_names.len) {
|
if (i < sd.field_names.len) {
|
||||||
try all_names.append(self.allocator, sd.field_names[i]);
|
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);
|
try all_types.append(self.allocator, resolved);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@@ -233,7 +238,7 @@ pub const Analyzer = struct {
|
|||||||
} else {
|
} else {
|
||||||
var field_types = std.ArrayList(Type).empty;
|
var field_types = std.ArrayList(Type).empty;
|
||||||
for (sd.field_types) |ft| {
|
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 field_types.append(self.allocator, resolved);
|
||||||
}
|
}
|
||||||
try self.struct_types.put(sd.name, .{
|
try self.struct_types.put(sd.name, .{
|
||||||
@@ -369,11 +374,11 @@ pub const Analyzer = struct {
|
|||||||
j -= 1;
|
j -= 1;
|
||||||
const sym = self.symbols.items[indices.items[j]];
|
const sym = self.symbols.items[indices.items[j]];
|
||||||
if (sym.scope_depth <= self.scope_depth) {
|
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| {
|
.if_expr => |ie| {
|
||||||
return self.inferExprType(ie.then_branch);
|
return self.inferExprType(ie.then_branch);
|
||||||
@@ -391,7 +396,7 @@ pub const Analyzer = struct {
|
|||||||
return .void_type;
|
return .void_type;
|
||||||
},
|
},
|
||||||
.call => |call_node| {
|
.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
|
// Check fn_signatures registry
|
||||||
if (self.fn_signatures.get(callee_name)) |sig| {
|
if (self.fn_signatures.get(callee_name)) |sig| {
|
||||||
return sig.return_type;
|
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]);
|
if (call_node.args.len > 0) return self.inferExprType(call_node.args[0]);
|
||||||
return .f32;
|
return .f32;
|
||||||
}
|
}
|
||||||
return Type.s(64);
|
return Type.unresolved;
|
||||||
},
|
},
|
||||||
.unary_op => |unop| {
|
.unary_op => |unop| {
|
||||||
return self.inferExprType(unop.operand);
|
return self.inferExprType(unop.operand);
|
||||||
@@ -426,17 +431,17 @@ pub const Analyzer = struct {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (obj_ty.isArray()) {
|
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| {
|
.index_expr => |ie| {
|
||||||
const obj_ty = self.inferExprType(ie.object);
|
const obj_ty = self.inferExprType(ie.object);
|
||||||
if (obj_ty == .string_type) return Type.u(8);
|
if (obj_ty == .string_type) return Type.u(8);
|
||||||
if (obj_ty.isArray()) {
|
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| {
|
.slice_expr => |se| {
|
||||||
const obj_ty = self.inferExprType(se.object);
|
const obj_ty = self.inferExprType(se.object);
|
||||||
@@ -677,7 +682,7 @@ pub const Analyzer = struct {
|
|||||||
{
|
{
|
||||||
var param_types = std.ArrayList(Type).empty;
|
var param_types = std.ArrayList(Type).empty;
|
||||||
for (fd.params) |param| {
|
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 param_types.append(self.allocator, pt);
|
||||||
}
|
}
|
||||||
try self.fn_signatures.put(fd.name, .{
|
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 {
|
fn inferFnReturnType(self: *Analyzer, params: []const ast.Param, body: *const Node) ?Type {
|
||||||
self.pushScope() catch return null;
|
self.pushScope() catch return null;
|
||||||
for (params) |param| {
|
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 {};
|
self.addSymbol(param.name, .param, pt, param.name_span) catch {};
|
||||||
}
|
}
|
||||||
// Arrow fn_decl wraps body in block{[expr]} — unwrap to inner expression
|
// Arrow fn_decl wraps body in block{[expr]} — unwrap to inner expression
|
||||||
|
|||||||
@@ -29,6 +29,11 @@ pub const Type = union(enum) {
|
|||||||
optional_type: OptionalTypeInfo,
|
optional_type: OptionalTypeInfo,
|
||||||
meta_type: MetaTypeInfo,
|
meta_type: MetaTypeInfo,
|
||||||
tuple_type: TupleTypeInfo,
|
tuple_type: TupleTypeInfo,
|
||||||
|
/// Type resolution failed (sema couldn't infer/resolve). A dedicated
|
||||||
|
/// sentinel — never a legitimate type — so callers can't mistake it for a
|
||||||
|
/// real result the way a fabricated `s(64)` would be. Mirrors
|
||||||
|
/// `ir.TypeId.unresolved`.
|
||||||
|
unresolved,
|
||||||
|
|
||||||
pub const SliceTypeInfo = struct {
|
pub const SliceTypeInfo = struct {
|
||||||
element_name: []const u8,
|
element_name: []const u8,
|
||||||
@@ -84,7 +89,7 @@ pub const Type = union(enum) {
|
|||||||
return switch (self) {
|
return switch (self) {
|
||||||
.signed => |w| w == other.signed,
|
.signed => |w| w == other.signed,
|
||||||
.unsigned => |w| w == other.unsigned,
|
.unsigned => |w| w == other.unsigned,
|
||||||
.f32, .f64, .void_type, .boolean, .string_type, .any_type, .usize_type, .isize_type => true,
|
.f32, .f64, .void_type, .boolean, .string_type, .any_type, .usize_type, .isize_type, .unresolved => true,
|
||||||
.enum_type => |n| std.mem.eql(u8, n, other.enum_type),
|
.enum_type => |n| std.mem.eql(u8, n, other.enum_type),
|
||||||
.struct_type => |n| std.mem.eql(u8, n, other.struct_type),
|
.struct_type => |n| std.mem.eql(u8, n, other.struct_type),
|
||||||
.union_type => |n| std.mem.eql(u8, n, other.union_type),
|
.union_type => |n| std.mem.eql(u8, n, other.union_type),
|
||||||
@@ -555,6 +560,7 @@ pub const Type = union(enum) {
|
|||||||
.any_type => "Any",
|
.any_type => "Any",
|
||||||
.usize_type => "usize",
|
.usize_type => "usize",
|
||||||
.isize_type => "isize",
|
.isize_type => "isize",
|
||||||
|
.unresolved => "<unresolved>",
|
||||||
.enum_type => |name| name,
|
.enum_type => |name| name,
|
||||||
.struct_type => |name| name,
|
.struct_type => |name| name,
|
||||||
.union_type => |name| name,
|
.union_type => |name| name,
|
||||||
|
|||||||
Reference in New Issue
Block a user