fix: error reporting for global variables

This commit is contained in:
Brett Broadhurst 2026-03-25 23:50:42 -06:00
parent 2dfa6cd842
commit 9ca2200448
Failed to generate hash of commit
5 changed files with 80 additions and 55 deletions

View file

@ -12,6 +12,7 @@ gpa: std.mem.Allocator,
arena: std.mem.Allocator,
module: *compile.Module,
ir: Ir,
inst_map: std.AutoHashMapUnmanaged(Ir.Inst.Index, Ref) = .empty,
errors: *std.ArrayListUnmanaged(Module.Error),
const InnerError = error{
@ -75,14 +76,16 @@ pub fn lookupIdentifier(
sema: *Sema,
chunk: *Chunk,
ident: InternPool.Constant.Index,
src: SrcLoc,
) !Ref {
return sema.lookupInNamespace(chunk.namespace, ident);
return sema.lookupInNamespace(chunk.namespace, ident, src);
}
pub fn lookupInNamespace(
sema: *Sema,
namespace: *Module.Namespace,
ident: InternPool.Constant.Index,
src: SrcLoc,
) !Ref {
var scope: ?*Module.Namespace = namespace;
while (scope) |s| : (scope = s.parent) {
@ -95,10 +98,11 @@ pub fn lookupInNamespace(
};
}
// FIXME: This is temporary
return sema.fail(.{ .src_offset = 0 }, "unknown identifier", .{});
return sema.fail(src, "unknown identifier", .{});
}
pub fn deinit(sema: *Sema) void {
sema.inst_map.deinit(sema.gpa);
sema.* = undefined;
}
@ -106,7 +110,6 @@ pub const Chunk = struct {
sema: *Sema,
namespace: *Module.Namespace,
code: *Module.CodeChunk,
inst_map: std.AutoHashMapUnmanaged(Ir.Inst.Index, Ref) = .empty,
constants_map: std.AutoHashMapUnmanaged(InternPool.Constant.Index, u8) = .empty,
labels: std.ArrayListUnmanaged(Label) = .empty,
fixups: std.ArrayListUnmanaged(Fixup) = .empty,
@ -127,7 +130,6 @@ pub const Chunk = struct {
const dummy_address = 0xffffffff;
pub fn deinit(chunk: *Chunk, gpa: std.mem.Allocator) void {
chunk.inst_map.deinit(gpa);
chunk.constants_map.deinit(gpa);
chunk.labels.deinit(gpa);
chunk.fixups.deinit(gpa);
@ -223,7 +225,7 @@ pub const Chunk = struct {
fn resolveInst(chunk: *Chunk, ref: Ir.Inst.Ref) Ref {
if (ref.toIndex()) |index| {
return chunk.inst_map.get(index).?;
return chunk.sema.inst_map.get(index).?;
}
switch (ref) {
.bool_true => return .bool_true,
@ -511,8 +513,9 @@ fn irImplicitRet(_: *Sema, chunk: *Chunk, _: Ir.Inst.Index) InnerError!Ref {
fn irDeclRef(sema: *Sema, chunk: *Chunk, inst: Ir.Inst.Index) InnerError!Ref {
const data = sema.ir.instructions[@intFromEnum(inst)].data.str_tok;
const src_loc: SrcLoc = .{ .src_offset = data.src_offset };
const decl_name = try sema.getOrPutStr(data.start);
return sema.lookupIdentifier(chunk, decl_name.constant);
return sema.lookupIdentifier(chunk, decl_name.constant, src_loc);
}
fn irCall(_: *Sema, _: *Chunk, _: Ir.Inst.Index) !Ref {
@ -532,19 +535,22 @@ fn irDivert(
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
const extra = sema.ir.extraData(ExtraType, data.extra_index);
const body = sema.ir.extra[extra.end..];
const callee_src: SrcLoc = .{ .src_offset = data.src_offset };
switch (kind) {
.direct => {
const callee = chunk.resolveInst(extra.data.callee);
const callee_src: SrcLoc = .{ .src_offset = data.src_offset };
_ = try analyzeDivertTarget(sema, chunk, callee_src, callee);
},
.field => {
const callee = chunk.resolveInst(extra.data.obj_ptr);
const callee_src: SrcLoc = .{ .src_offset = data.src_offset };
const field_name = try sema.getOrPutStr(extra.data.field_name_start);
_ = try analyzeDivertTarget(sema, chunk, callee_src, callee);
const e = try sema.lookupInNamespace(callee.knot.namespace, field_name.constant);
const e = try sema.lookupInNamespace(
callee.knot.namespace,
field_name.constant,
callee_src,
);
switch (e) {
.knot => |knot| {
const local_index = try chunk.getOrPutConstantIndex(knot.const_index);
@ -682,7 +688,7 @@ fn analyzeBodyInner(sema: *Sema, chunk: *Chunk, body: []const Ir.Inst.Index) Inn
.field_ptr => try irFieldPtr(sema, chunk, inst),
.param => try irParam(sema, chunk, inst),
};
try chunk.inst_map.put(sema.gpa, inst, ref);
try sema.inst_map.put(sema.gpa, inst, ref);
}
}
@ -738,6 +744,21 @@ fn analyzeNestedDecl(
}
}
pub fn analyzeGlobalBlockInner(sema: *Sema, chunk: *Chunk, inst: Ir.Inst.Index) !void {
const data = sema.ir.instructions[@intFromEnum(inst)].data.payload;
const extra = sema.ir.extraData(Ir.Inst.Var, data.payload.extra_index);
const body = sema.ir.bodySlice(extra.end, extra.data.body_len);
try analyzeBodyInner(sema, chunk, body);
// FIXME: hack
{
const last_inst = body[body.len - 1].toRef();
const val = chunk.resolveInst(last_inst);
_ = try chunk.doLoad(val);
}
_ = try chunk.addConstOp(.store_global, @intCast(@intFromEnum(0)));
_ = try chunk.addByteOp(.pop);
}
pub fn analyzeTopLevelDecl(
sema: *Sema,
namespace: *Module.Namespace,
@ -747,42 +768,41 @@ pub fn analyzeTopLevelDecl(
const extra = sema.ir.extraData(Ir.Inst.Declaration, data.extra_index).data;
const decl_inst = sema.ir.instructions[@intFromEnum(extra.value)];
const decl_name = try sema.module.intern_pool.getOrPutStr(sema.gpa, extra.name);
const src_loc: SrcLoc = .{ .src_offset = data.src_offset };
switch (decl_inst.tag) {
.decl_var => {
const decl_extra = sema.ir.extraData(Ir.Inst.Var, decl_inst.data.payload.extra_index);
const body = sema.ir.bodySlice(decl_extra.end, decl_extra.data.body_len);
try namespace.decls.put(sema.gpa, decl_name, .{
.tag = .variable,
.namespace = null,
.decl_inst = extra.value,
.args_count = 0,
});
// FIXME: Broken
var chunk: *Chunk = undefined;
try analyzeBodyInner(sema, chunk, body);
// FIXME: hack
{
const last_inst = body[body.len - 1].toRef();
const val = chunk.resolveInst(last_inst);
_ = try chunk.doLoad(val);
const gop = try namespace.decls.getOrPut(sema.arena, decl_name);
if (gop.found_existing) {
return sema.fail(src_loc, "duplicate identifier", .{});
} else {
gop.value_ptr.* = .{
.tag = .variable,
.namespace = null,
.decl_inst = extra.value,
.args_count = 0,
};
}
_ = try chunk.addConstOp(.store_global, @intCast(@intFromEnum(decl_name)));
_ = try chunk.addByteOp(.pop);
},
.decl_knot => {
const _data = sema.ir.instructions[@intFromEnum(extra.value)].data.payload;
const _extra = sema.ir.extraData(Ir.Inst.Knot, _data.extra_index);
const _body = sema.ir.bodySlice(_extra.end, _extra.data.body_len);
const _stitches = sema.ir.bodySlice(_extra.end + _body.len, _extra.data.stitches_len);
const child_namespace = try sema.module.createNamespace(namespace);
try namespace.decls.put(sema.arena, decl_name, .{
.tag = .knot,
.decl_inst = extra.value,
.args_count = 0,
.namespace = child_namespace,
});
const gop = try namespace.decls.getOrPut(sema.arena, decl_name);
if (gop.found_existing) {
return sema.fail(src_loc, "duplicate identifier", .{});
} else {
gop.value_ptr.* = .{
.tag = .knot,
.decl_inst = extra.value,
.args_count = 0,
.namespace = child_namespace,
};
}
try sema.module.queueWorkItem(.{
.tag = .knot,
.decl_name = decl_name,