std.zig.ErrorBundle: rework binary encoding
* Separate into a "WIP" struct and a "finished" struct. * Use a bit of indirection for error notes to simplify ergonomics of this data structure.
This commit is contained in:
@@ -3,24 +3,22 @@
|
||||
//! is used to collect all the errors from the various places into one
|
||||
//! convenient place for API users to consume.
|
||||
|
||||
string_bytes: std.ArrayListUnmanaged(u8),
|
||||
/// The first thing in this array is a ErrorMessageListIndex.
|
||||
extra: std.ArrayListUnmanaged(u32),
|
||||
string_bytes: []const u8,
|
||||
/// The first thing in this array is an `ErrorMessageList`.
|
||||
extra: []const u32,
|
||||
|
||||
// An index into `extra` pointing at an `ErrorMessage`.
|
||||
pub const MessageIndex = enum(u32) {
|
||||
_,
|
||||
};
|
||||
|
||||
/// After the header is:
|
||||
/// * string_bytes
|
||||
/// * extra (little endian)
|
||||
pub const Header = struct {
|
||||
string_bytes_len: u32,
|
||||
extra_len: u32,
|
||||
// An index into `extra` pointing at an `SourceLocation`.
|
||||
pub const SourceLocationIndex = enum(u32) {
|
||||
none = 0,
|
||||
_,
|
||||
};
|
||||
|
||||
/// Trailing: ErrorMessage for each len
|
||||
/// There will be a MessageIndex for each len at start.
|
||||
pub const ErrorMessageList = struct {
|
||||
len: u32,
|
||||
start: u32,
|
||||
@@ -46,14 +44,13 @@ pub const SourceLocation = struct {
|
||||
};
|
||||
|
||||
/// Trailing:
|
||||
/// * ErrorMessage for each notes_len.
|
||||
/// * MessageIndex for each notes_len.
|
||||
pub const ErrorMessage = struct {
|
||||
/// null terminated string index
|
||||
msg: u32,
|
||||
/// Usually one, but incremented for redundant messages.
|
||||
count: u32 = 1,
|
||||
/// 0 or the index into extra of a SourceLocation
|
||||
src_loc: u32 = 0,
|
||||
src_loc: SourceLocationIndex = .none,
|
||||
notes_len: u32 = 0,
|
||||
};
|
||||
|
||||
@@ -65,170 +62,41 @@ pub const ReferenceTrace = struct {
|
||||
decl_name: u32,
|
||||
/// Index into extra of a SourceLocation
|
||||
/// If this is 0, this is the sentinel ReferenceTrace element.
|
||||
src_loc: u32,
|
||||
src_loc: SourceLocationIndex,
|
||||
};
|
||||
|
||||
pub fn init(eb: *ErrorBundle, gpa: Allocator) !void {
|
||||
eb.* = .{
|
||||
.string_bytes = .{},
|
||||
.extra = .{},
|
||||
};
|
||||
|
||||
// So that 0 can be used to indicate a null string.
|
||||
try eb.string_bytes.append(gpa, 0);
|
||||
|
||||
_ = try addExtra(eb, gpa, ErrorMessageList{
|
||||
.len = 0,
|
||||
.start = 0,
|
||||
});
|
||||
}
|
||||
|
||||
pub fn deinit(eb: *ErrorBundle, gpa: Allocator) void {
|
||||
eb.string_bytes.deinit(gpa);
|
||||
eb.extra.deinit(gpa);
|
||||
gpa.free(eb.string_bytes);
|
||||
gpa.free(eb.extra);
|
||||
eb.* = undefined;
|
||||
}
|
||||
|
||||
pub fn addString(eb: *ErrorBundle, gpa: Allocator, s: []const u8) !u32 {
|
||||
const index = @intCast(u32, eb.string_bytes.items.len);
|
||||
try eb.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
|
||||
eb.string_bytes.appendSliceAssumeCapacity(s);
|
||||
eb.string_bytes.appendAssumeCapacity(0);
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn printString(eb: *ErrorBundle, gpa: Allocator, comptime fmt: []const u8, args: anytype) !u32 {
|
||||
const index = @intCast(u32, eb.string_bytes.items.len);
|
||||
try eb.string_bytes.writer(gpa).print(fmt, args);
|
||||
try eb.string_bytes.append(gpa, 0);
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn addErrorMessage(eb: *ErrorBundle, gpa: Allocator, em: ErrorMessage) !void {
|
||||
if (eb.errorMessageCount() == 0) {
|
||||
eb.setStartIndex(@intCast(u32, eb.extra.items.len));
|
||||
}
|
||||
_ = try addExtra(eb, gpa, em);
|
||||
}
|
||||
|
||||
pub fn addSourceLocation(eb: *ErrorBundle, gpa: Allocator, sl: SourceLocation) !u32 {
|
||||
return addExtra(eb, gpa, sl);
|
||||
}
|
||||
|
||||
pub fn addReferenceTrace(eb: *ErrorBundle, gpa: Allocator, rt: ReferenceTrace) !void {
|
||||
_ = try addExtra(eb, gpa, rt);
|
||||
}
|
||||
|
||||
pub fn addBundle(eb: *ErrorBundle, gpa: Allocator, other: ErrorBundle) !void {
|
||||
// Skip over the initial ErrorMessageList len field.
|
||||
const root_fields_len = @typeInfo(ErrorMessageList).Struct.fields.len;
|
||||
const other_list = other.extraData(ErrorMessageList, 0).data;
|
||||
const other_extra = other.extra.items[root_fields_len..];
|
||||
|
||||
try eb.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.items.len);
|
||||
try eb.extra.ensureUnusedCapacity(gpa, other_extra.len);
|
||||
|
||||
const new_string_base = @intCast(u32, eb.string_bytes.items.len);
|
||||
const new_data_base = @intCast(u32, eb.extra.items.len - root_fields_len);
|
||||
|
||||
eb.string_bytes.appendSliceAssumeCapacity(other.string_bytes.items);
|
||||
eb.extra.appendSliceAssumeCapacity(other_extra);
|
||||
|
||||
// Now we must offset the string indexes and extra indexes of the newly
|
||||
// added extra.
|
||||
var index = new_data_base + other_list.start;
|
||||
for (0..other_list.len) |_| {
|
||||
index = try patchMessage(eb, index, new_string_base, new_data_base);
|
||||
}
|
||||
}
|
||||
|
||||
fn patchMessage(eb: *ErrorBundle, msg_idx: usize, new_string_base: u32, new_data_base: u32) !u32 {
|
||||
var msg = eb.extraData(ErrorMessage, msg_idx);
|
||||
if (msg.data.msg != 0) msg.data.msg += new_string_base;
|
||||
if (msg.data.src_loc != 0) msg.data.src_loc += new_data_base;
|
||||
eb.setExtra(msg_idx, msg.data);
|
||||
|
||||
try patchSrcLoc(eb, msg.data.src_loc, new_string_base, new_data_base);
|
||||
|
||||
var index = @intCast(u32, msg.end);
|
||||
for (0..msg.data.notes_len) |_| {
|
||||
index = try patchMessage(eb, index, new_string_base, new_data_base);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
|
||||
fn patchSrcLoc(eb: *ErrorBundle, idx: usize, new_string_base: u32, new_data_base: u32) !void {
|
||||
if (idx == 0) return;
|
||||
|
||||
var src_loc = eb.extraData(SourceLocation, idx);
|
||||
if (src_loc.data.src_path != 0) src_loc.data.src_path += new_string_base;
|
||||
if (src_loc.data.source_line != 0) src_loc.data.source_line += new_string_base;
|
||||
eb.setExtra(idx, src_loc.data);
|
||||
|
||||
var index = src_loc.end;
|
||||
for (0..src_loc.data.reference_trace_len) |_| {
|
||||
var ref_trace = eb.extraData(ReferenceTrace, index);
|
||||
if (ref_trace.data.decl_name != 0) ref_trace.data.decl_name += new_string_base;
|
||||
if (ref_trace.data.src_loc != 0) ref_trace.data.src_loc += new_data_base;
|
||||
eb.setExtra(index, ref_trace.data);
|
||||
try patchSrcLoc(eb, ref_trace.data.src_loc, new_string_base, new_data_base);
|
||||
index = ref_trace.end;
|
||||
}
|
||||
}
|
||||
|
||||
fn addExtra(eb: *ErrorBundle, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
|
||||
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
|
||||
try eb.extra.ensureUnusedCapacity(gpa, fields.len);
|
||||
return addExtraAssumeCapacity(eb, extra);
|
||||
}
|
||||
|
||||
fn addExtraAssumeCapacity(eb: *ErrorBundle, extra: anytype) u32 {
|
||||
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
|
||||
const result = @intCast(u32, eb.extra.items.len);
|
||||
eb.extra.items.len += fields.len;
|
||||
setExtra(eb, result, extra);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn setExtra(eb: *ErrorBundle, index: usize, extra: anytype) void {
|
||||
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
|
||||
var i = index;
|
||||
inline for (fields) |field| {
|
||||
eb.extra.items[i] = switch (field.type) {
|
||||
u32 => @field(extra, field.name),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
|
||||
pub fn errorMessageCount(eb: ErrorBundle) u32 {
|
||||
return eb.extra.items[0];
|
||||
return eb.getErrorMessageList().len;
|
||||
}
|
||||
|
||||
pub fn setErrorMessageCount(eb: *ErrorBundle, count: u32) void {
|
||||
eb.extra.items[0] = count;
|
||||
pub fn getErrorMessageList(eb: ErrorBundle) ErrorMessageList {
|
||||
return eb.extraData(ErrorMessageList, 0).data;
|
||||
}
|
||||
|
||||
pub fn incrementCount(eb: *ErrorBundle, delta: u32) void {
|
||||
eb.extra.items[0] += delta;
|
||||
}
|
||||
|
||||
pub fn getStartIndex(eb: ErrorBundle) u32 {
|
||||
return eb.extra.items[1];
|
||||
}
|
||||
|
||||
pub fn setStartIndex(eb: *ErrorBundle, index: u32) void {
|
||||
eb.extra.items[1] = index;
|
||||
pub fn getMessages(eb: ErrorBundle) []const MessageIndex {
|
||||
const list = eb.getErrorMessageList();
|
||||
return @ptrCast([]const MessageIndex, eb.extra[list.start..][0..list.len]);
|
||||
}
|
||||
|
||||
pub fn getErrorMessage(eb: ErrorBundle, index: MessageIndex) ErrorMessage {
|
||||
return eb.extraData(ErrorMessage, @enumToInt(index)).data;
|
||||
}
|
||||
|
||||
pub fn getSourceLocation(eb: ErrorBundle, index: u32) SourceLocation {
|
||||
assert(index != 0);
|
||||
return eb.extraData(SourceLocation, index).data;
|
||||
pub fn getSourceLocation(eb: ErrorBundle, index: SourceLocationIndex) SourceLocation {
|
||||
assert(index != .none);
|
||||
return eb.extraData(SourceLocation, @enumToInt(index)).data;
|
||||
}
|
||||
|
||||
pub fn getNotes(eb: ErrorBundle, index: MessageIndex) []const MessageIndex {
|
||||
const notes_len = eb.getErrorMessage(index).notes_len;
|
||||
const start = @enumToInt(index) + @typeInfo(ErrorMessage).Struct.fields.len;
|
||||
return @ptrCast([]const MessageIndex, eb.extra[start..][0..notes_len]);
|
||||
}
|
||||
|
||||
/// Returns the requested data, as well as the new index which is at the start of the
|
||||
@@ -239,7 +107,9 @@ fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T,
|
||||
var result: T = undefined;
|
||||
inline for (fields) |field| {
|
||||
@field(result, field.name) = switch (field.type) {
|
||||
u32 => eb.extra.items[i],
|
||||
u32 => eb.extra[i],
|
||||
MessageIndex => @intToEnum(MessageIndex, eb.extra[i]),
|
||||
SourceLocationIndex => @intToEnum(SourceLocationIndex, eb.extra[i]),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
@@ -252,7 +122,7 @@ fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T,
|
||||
|
||||
/// Given an index into `string_bytes` returns the null-terminated string found there.
|
||||
pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
|
||||
const string_bytes = eb.string_bytes.items;
|
||||
const string_bytes = eb.string_bytes;
|
||||
var end: usize = index;
|
||||
while (string_bytes[end] != 0) {
|
||||
end += 1;
|
||||
@@ -272,28 +142,25 @@ pub fn renderToWriter(
|
||||
ttyconf: std.debug.TTY.Config,
|
||||
writer: anytype,
|
||||
) anyerror!void {
|
||||
const list = eb.extraData(ErrorMessageList, 0).data;
|
||||
var index: usize = list.start;
|
||||
for (0..list.len) |_| {
|
||||
const err_msg = eb.extraData(ErrorMessage, index);
|
||||
index = try renderErrorMessageToWriter(eb, err_msg.data, err_msg.end, ttyconf, writer, "error", .Red, 0);
|
||||
for (eb.getMessages()) |err_msg| {
|
||||
try renderErrorMessageToWriter(eb, err_msg, ttyconf, writer, "error", .Red, 0);
|
||||
}
|
||||
}
|
||||
|
||||
fn renderErrorMessageToWriter(
|
||||
eb: ErrorBundle,
|
||||
err_msg: ErrorMessage,
|
||||
end_index: usize,
|
||||
err_msg_index: MessageIndex,
|
||||
ttyconf: std.debug.TTY.Config,
|
||||
stderr: anytype,
|
||||
kind: []const u8,
|
||||
color: std.debug.TTY.Color,
|
||||
indent: usize,
|
||||
) anyerror!usize {
|
||||
) anyerror!void {
|
||||
var counting_writer = std.io.countingWriter(stderr);
|
||||
const counting_stderr = counting_writer.writer();
|
||||
if (err_msg.src_loc != 0) {
|
||||
const src = eb.extraData(SourceLocation, err_msg.src_loc);
|
||||
const err_msg = eb.getErrorMessage(err_msg_index);
|
||||
if (err_msg.src_loc != .none) {
|
||||
const src = eb.extraData(SourceLocation, @enumToInt(err_msg.src_loc));
|
||||
try counting_stderr.writeByteNTimes(' ', indent);
|
||||
try ttyconf.setColor(stderr, .Bold);
|
||||
try counting_stderr.print("{s}:{d}:{d}: ", .{
|
||||
@@ -337,10 +204,8 @@ fn renderErrorMessageToWriter(
|
||||
try stderr.writeByte('\n');
|
||||
try ttyconf.setColor(stderr, .Reset);
|
||||
}
|
||||
var index = end_index;
|
||||
for (0..err_msg.notes_len) |_| {
|
||||
const note = eb.extraData(ErrorMessage, index);
|
||||
index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent);
|
||||
for (eb.getNotes(err_msg_index)) |note| {
|
||||
try renderErrorMessageToWriter(eb, note, ttyconf, stderr, "note", .Cyan, indent);
|
||||
}
|
||||
if (src.data.reference_trace_len > 0) {
|
||||
try ttyconf.setColor(stderr, .Reset);
|
||||
@@ -350,7 +215,7 @@ fn renderErrorMessageToWriter(
|
||||
for (0..src.data.reference_trace_len) |_| {
|
||||
const ref_trace = eb.extraData(ReferenceTrace, ref_index);
|
||||
ref_index = ref_trace.end;
|
||||
if (ref_trace.data.src_loc != 0) {
|
||||
if (ref_trace.data.src_loc != .none) {
|
||||
const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
|
||||
try stderr.print(" {s}: {s}:{d}:{d}\n", .{
|
||||
eb.nullTerminatedString(ref_trace.data.decl_name),
|
||||
@@ -374,7 +239,6 @@ fn renderErrorMessageToWriter(
|
||||
try stderr.writeByte('\n');
|
||||
try ttyconf.setColor(stderr, .Reset);
|
||||
}
|
||||
return index;
|
||||
} else {
|
||||
try ttyconf.setColor(stderr, color);
|
||||
try stderr.writeByteNTimes(' ', indent);
|
||||
@@ -390,12 +254,9 @@ fn renderErrorMessageToWriter(
|
||||
try stderr.print(" ({d} times)\n", .{err_msg.count});
|
||||
}
|
||||
try ttyconf.setColor(stderr, .Reset);
|
||||
var index = end_index;
|
||||
for (0..err_msg.notes_len) |_| {
|
||||
const note = eb.extraData(ErrorMessage, index);
|
||||
index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent + 4);
|
||||
for (eb.getNotes(err_msg_index)) |note| {
|
||||
try renderErrorMessageToWriter(eb, note, ttyconf, stderr, "note", .Cyan, indent + 4);
|
||||
}
|
||||
return index;
|
||||
}
|
||||
}
|
||||
|
||||
@@ -417,3 +278,186 @@ const std = @import("std");
|
||||
const ErrorBundle = @This();
|
||||
const Allocator = std.mem.Allocator;
|
||||
const assert = std.debug.assert;
|
||||
|
||||
pub const Wip = struct {
|
||||
gpa: Allocator,
|
||||
string_bytes: std.ArrayListUnmanaged(u8),
|
||||
/// The first thing in this array is a ErrorMessageList.
|
||||
extra: std.ArrayListUnmanaged(u32),
|
||||
root_list: std.ArrayListUnmanaged(MessageIndex),
|
||||
|
||||
pub fn init(wip: *Wip, gpa: Allocator) !void {
|
||||
wip.* = .{
|
||||
.gpa = gpa,
|
||||
.string_bytes = .{},
|
||||
.extra = .{},
|
||||
.root_list = .{},
|
||||
};
|
||||
|
||||
// So that 0 can be used to indicate a null string.
|
||||
try wip.string_bytes.append(gpa, 0);
|
||||
|
||||
assert(0 == try addExtra(wip, ErrorMessageList{
|
||||
.len = 0,
|
||||
.start = 0,
|
||||
}));
|
||||
}
|
||||
|
||||
pub fn deinit(wip: *Wip) void {
|
||||
const gpa = wip.gpa;
|
||||
wip.root_list.deinit(gpa);
|
||||
wip.string_bytes.deinit(gpa);
|
||||
wip.extra.deinit(gpa);
|
||||
wip.* = undefined;
|
||||
}
|
||||
|
||||
pub fn toOwnedBundle(wip: *Wip) !ErrorBundle {
|
||||
const gpa = wip.gpa;
|
||||
wip.setExtra(0, ErrorMessageList{
|
||||
.len = @intCast(u32, wip.root_list.items.len),
|
||||
.start = @intCast(u32, wip.extra.items.len),
|
||||
});
|
||||
try wip.extra.appendSlice(gpa, @ptrCast([]const u32, wip.root_list.items));
|
||||
wip.root_list.clearAndFree(gpa);
|
||||
return .{
|
||||
.string_bytes = try wip.string_bytes.toOwnedSlice(gpa),
|
||||
.extra = try wip.extra.toOwnedSlice(gpa),
|
||||
};
|
||||
}
|
||||
|
||||
pub fn tmpBundle(wip: Wip) ErrorBundle {
|
||||
return .{
|
||||
.string_bytes = wip.string_bytes.items,
|
||||
.extra = wip.extra.items,
|
||||
};
|
||||
}
|
||||
|
||||
pub fn addString(wip: *Wip, s: []const u8) !u32 {
|
||||
const gpa = wip.gpa;
|
||||
const index = @intCast(u32, wip.string_bytes.items.len);
|
||||
try wip.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
|
||||
wip.string_bytes.appendSliceAssumeCapacity(s);
|
||||
wip.string_bytes.appendAssumeCapacity(0);
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) !u32 {
|
||||
const gpa = wip.gpa;
|
||||
const index = @intCast(u32, wip.string_bytes.items.len);
|
||||
try wip.string_bytes.writer(gpa).print(fmt, args);
|
||||
try wip.string_bytes.append(gpa, 0);
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn addRootErrorMessage(wip: *Wip, em: ErrorMessage) !void {
|
||||
try wip.root_list.ensureUnusedCapacity(wip.gpa, 1);
|
||||
wip.root_list.appendAssumeCapacity(try addErrorMessage(wip, em));
|
||||
}
|
||||
|
||||
pub fn addErrorMessage(wip: *Wip, em: ErrorMessage) !MessageIndex {
|
||||
return @intToEnum(MessageIndex, try addExtra(wip, em));
|
||||
}
|
||||
|
||||
pub fn addErrorMessageAssumeCapacity(wip: *Wip, em: ErrorMessage) MessageIndex {
|
||||
return @intToEnum(MessageIndex, addExtraAssumeCapacity(wip, em));
|
||||
}
|
||||
|
||||
pub fn addSourceLocation(wip: *Wip, sl: SourceLocation) !SourceLocationIndex {
|
||||
return @intToEnum(SourceLocationIndex, try addExtra(wip, sl));
|
||||
}
|
||||
|
||||
pub fn addReferenceTrace(wip: *Wip, rt: ReferenceTrace) !void {
|
||||
_ = try addExtra(wip, rt);
|
||||
}
|
||||
|
||||
pub fn addBundle(wip: *Wip, other: ErrorBundle) !void {
|
||||
const gpa = wip.gpa;
|
||||
|
||||
try wip.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.len);
|
||||
try wip.extra.ensureUnusedCapacity(gpa, other.extra.len);
|
||||
|
||||
const other_list = other.getMessages();
|
||||
|
||||
// The ensureUnusedCapacity call above guarantees this.
|
||||
const notes_start = wip.reserveNotes(@intCast(u32, other_list.len)) catch unreachable;
|
||||
for (notes_start.., other_list) |note, message| {
|
||||
wip.extra.items[note] = @enumToInt(wip.addOtherMessage(other, message) catch unreachable);
|
||||
}
|
||||
}
|
||||
|
||||
pub fn reserveNotes(wip: *Wip, notes_len: u32) !u32 {
|
||||
try wip.extra.ensureUnusedCapacity(wip.gpa, notes_len +
|
||||
notes_len * @typeInfo(ErrorBundle.ErrorMessage).Struct.fields.len);
|
||||
wip.extra.items.len += notes_len;
|
||||
return @intCast(u32, wip.extra.items.len - notes_len);
|
||||
}
|
||||
|
||||
fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {
|
||||
const other_msg = other.getErrorMessage(msg_index);
|
||||
const src_loc = try wip.addOtherSourceLocation(other, other_msg.src_loc);
|
||||
const msg = try wip.addErrorMessage(.{
|
||||
.msg = try wip.addString(other.nullTerminatedString(other_msg.msg)),
|
||||
.count = other_msg.count,
|
||||
.src_loc = src_loc,
|
||||
.notes_len = other_msg.notes_len,
|
||||
});
|
||||
const notes_start = try wip.reserveNotes(other_msg.notes_len);
|
||||
for (notes_start.., other.getNotes(msg_index)) |note, other_note| {
|
||||
wip.extra.items[note] = @enumToInt(try wip.addOtherMessage(other, other_note));
|
||||
}
|
||||
return msg;
|
||||
}
|
||||
|
||||
fn addOtherSourceLocation(
|
||||
wip: *Wip,
|
||||
other: ErrorBundle,
|
||||
index: SourceLocationIndex,
|
||||
) !SourceLocationIndex {
|
||||
if (index == .none) return .none;
|
||||
const other_sl = other.getSourceLocation(index);
|
||||
|
||||
const src_loc = try wip.addSourceLocation(.{
|
||||
.src_path = try wip.addString(other.nullTerminatedString(other_sl.src_path)),
|
||||
.line = other_sl.line,
|
||||
.column = other_sl.column,
|
||||
.span_start = other_sl.span_start,
|
||||
.span_main = other_sl.span_main,
|
||||
.span_end = other_sl.span_end,
|
||||
.source_line = try wip.addString(other.nullTerminatedString(other_sl.source_line)),
|
||||
.reference_trace_len = other_sl.reference_trace_len,
|
||||
});
|
||||
|
||||
// TODO: also add the reference trace
|
||||
|
||||
return src_loc;
|
||||
}
|
||||
|
||||
fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 {
|
||||
const gpa = wip.gpa;
|
||||
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
|
||||
try wip.extra.ensureUnusedCapacity(gpa, fields.len);
|
||||
return addExtraAssumeCapacity(wip, extra);
|
||||
}
|
||||
|
||||
fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 {
|
||||
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
|
||||
const result = @intCast(u32, wip.extra.items.len);
|
||||
wip.extra.items.len += fields.len;
|
||||
setExtra(wip, result, extra);
|
||||
return result;
|
||||
}
|
||||
|
||||
fn setExtra(wip: *Wip, index: usize, extra: anytype) void {
|
||||
const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
|
||||
var i = index;
|
||||
inline for (fields) |field| {
|
||||
wip.extra.items[i] = switch (field.type) {
|
||||
u32 => @field(extra, field.name),
|
||||
MessageIndex => @enumToInt(@field(extra, field.name)),
|
||||
SourceLocationIndex => @enumToInt(@field(extra, field.name)),
|
||||
else => @compileError("bad field type"),
|
||||
};
|
||||
i += 1;
|
||||
}
|
||||
}
|
||||
};
|
||||
|
||||
@@ -2546,9 +2546,9 @@ pub fn totalErrorCount(self: *Compilation) u32 {
|
||||
pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
const gpa = self.gpa;
|
||||
|
||||
var bundle: ErrorBundle = undefined;
|
||||
var bundle: ErrorBundle.Wip = undefined;
|
||||
try bundle.init(gpa);
|
||||
errdefer bundle.deinit(gpa);
|
||||
defer bundle.deinit();
|
||||
|
||||
{
|
||||
var it = self.failed_c_objects.iterator();
|
||||
@@ -2557,12 +2557,10 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
const err_msg = entry.value_ptr.*;
|
||||
// TODO these fields will need to be adjusted when we have proper
|
||||
// C error reporting bubbling up.
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.printString(gpa, "unable to build C object: {s}", .{
|
||||
err_msg.msg,
|
||||
}),
|
||||
.src_loc = try bundle.addSourceLocation(gpa, .{
|
||||
.src_path = try bundle.addString(gpa, c_object.src.src_path),
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.printString("unable to build C object: {s}", .{err_msg.msg}),
|
||||
.src_loc = try bundle.addSourceLocation(.{
|
||||
.src_path = try bundle.addString(c_object.src.src_path),
|
||||
.span_start = 0,
|
||||
.span_main = 0,
|
||||
.span_end = 1,
|
||||
@@ -2571,49 +2569,46 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
.source_line = 0, // TODO
|
||||
}),
|
||||
});
|
||||
bundle.incrementCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
for (self.lld_errors.items) |lld_error| {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, lld_error.msg),
|
||||
.notes_len = @intCast(u32, lld_error.context_lines.len),
|
||||
});
|
||||
bundle.incrementCount(1);
|
||||
const notes_len = @intCast(u32, lld_error.context_lines.len);
|
||||
|
||||
for (lld_error.context_lines) |context_line| {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, context_line),
|
||||
});
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.addString(lld_error.msg),
|
||||
.notes_len = notes_len,
|
||||
});
|
||||
const notes_start = try bundle.reserveNotes(notes_len);
|
||||
for (notes_start.., lld_error.context_lines) |note, context_line| {
|
||||
bundle.extra.items[note] = @enumToInt(bundle.addErrorMessageAssumeCapacity(.{
|
||||
.msg = try bundle.addString(context_line),
|
||||
}));
|
||||
}
|
||||
}
|
||||
for (self.misc_failures.values()) |*value| {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, value.msg),
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.addString(value.msg),
|
||||
.notes_len = if (value.children) |b| b.errorMessageCount() else 0,
|
||||
});
|
||||
if (value.children) |b| try bundle.addBundle(gpa, b);
|
||||
bundle.incrementCount(1);
|
||||
if (value.children) |b| try bundle.addBundle(b);
|
||||
}
|
||||
if (self.alloc_failure_occurred) {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, "memory allocation failure"),
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.addString("memory allocation failure"),
|
||||
});
|
||||
bundle.incrementCount(1);
|
||||
}
|
||||
if (self.bin_file.options.module) |module| {
|
||||
{
|
||||
var it = module.failed_files.iterator();
|
||||
while (it.next()) |entry| {
|
||||
if (entry.value_ptr.*) |msg| {
|
||||
try addModuleErrorMsg(gpa, &bundle, msg.*);
|
||||
try addModuleErrorMsg(&bundle, msg.*);
|
||||
} else {
|
||||
// Must be ZIR errors. In order for ZIR errors to exist, the parsing
|
||||
// must have completed successfully.
|
||||
const tree = try entry.key_ptr.*.getTree(module.gpa);
|
||||
assert(tree.errors.len == 0);
|
||||
try addZirErrorMessages(gpa, &bundle, entry.key_ptr.*);
|
||||
// Must be ZIR errors. Note that this may include AST errors.
|
||||
// addZirErrorMessages asserts that the tree is loaded.
|
||||
_ = try entry.key_ptr.*.getTree(gpa);
|
||||
try addZirErrorMessages(&bundle, entry.key_ptr.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
@@ -2621,7 +2616,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
var it = module.failed_embed_files.iterator();
|
||||
while (it.next()) |entry| {
|
||||
const msg = entry.value_ptr.*;
|
||||
try addModuleErrorMsg(gpa, &bundle, msg.*);
|
||||
try addModuleErrorMsg(&bundle, msg.*);
|
||||
}
|
||||
}
|
||||
{
|
||||
@@ -2631,21 +2626,20 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
// Skip errors for Decls within files that had a parse failure.
|
||||
// We'll try again once parsing succeeds.
|
||||
if (decl.getFileScope().okToReportErrors()) {
|
||||
try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
|
||||
try addModuleErrorMsg(&bundle, entry.value_ptr.*.*);
|
||||
if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, std.mem.span(c_error.msg)),
|
||||
.src_loc = if (c_error.path) |some| try bundle.addSourceLocation(gpa, .{
|
||||
.src_path = try bundle.addString(gpa, std.mem.span(some)),
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.addString(std.mem.span(c_error.msg)),
|
||||
.src_loc = if (c_error.path) |some| try bundle.addSourceLocation(.{
|
||||
.src_path = try bundle.addString(std.mem.span(some)),
|
||||
.span_start = c_error.offset,
|
||||
.span_main = c_error.offset,
|
||||
.span_end = c_error.offset + 1,
|
||||
.line = c_error.line,
|
||||
.column = c_error.column,
|
||||
.source_line = if (c_error.source_line) |line| try bundle.addString(gpa, std.mem.span(line)) else 0,
|
||||
}) else 0,
|
||||
.source_line = if (c_error.source_line) |line| try bundle.addString(std.mem.span(line)) else 0,
|
||||
}) else .none,
|
||||
});
|
||||
bundle.incrementCount(1);
|
||||
};
|
||||
}
|
||||
}
|
||||
@@ -2657,40 +2651,39 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
// Skip errors for Decls within files that had a parse failure.
|
||||
// We'll try again once parsing succeeds.
|
||||
if (decl.getFileScope().okToReportErrors()) {
|
||||
try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
|
||||
try addModuleErrorMsg(&bundle, entry.value_ptr.*.*);
|
||||
}
|
||||
}
|
||||
}
|
||||
for (module.failed_exports.values()) |value| {
|
||||
try addModuleErrorMsg(gpa, &bundle, value.*);
|
||||
try addModuleErrorMsg(&bundle, value.*);
|
||||
}
|
||||
}
|
||||
|
||||
if (bundle.errorMessageCount() == 0) {
|
||||
if (bundle.root_list.items.len == 0) {
|
||||
if (self.link_error_flags.no_entry_point_found) {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, "no entry point found"),
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.addString("no entry point found"),
|
||||
});
|
||||
bundle.incrementCount(1);
|
||||
}
|
||||
}
|
||||
|
||||
if (self.link_error_flags.missing_libc) {
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, "libc not available"),
|
||||
try bundle.addRootErrorMessage(.{
|
||||
.msg = try bundle.addString("libc not available"),
|
||||
.notes_len = 2,
|
||||
});
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, "run 'zig libc -h' to learn about libc installations"),
|
||||
});
|
||||
try bundle.addErrorMessage(gpa, .{
|
||||
.msg = try bundle.addString(gpa, "run 'zig targets' to see the targets for which zig can always provide libc"),
|
||||
});
|
||||
bundle.incrementCount(1);
|
||||
const notes_start = try bundle.reserveNotes(2);
|
||||
bundle.extra.items[notes_start + 0] = @enumToInt(try bundle.addErrorMessage(.{
|
||||
.msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),
|
||||
}));
|
||||
bundle.extra.items[notes_start + 1] = @enumToInt(try bundle.addErrorMessage(.{
|
||||
.msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),
|
||||
}));
|
||||
}
|
||||
|
||||
if (self.bin_file.options.module) |module| {
|
||||
if (bundle.errorMessageCount() == 0 and module.compile_log_decls.count() != 0) {
|
||||
if (bundle.root_list.items.len == 0 and module.compile_log_decls.count() != 0) {
|
||||
const keys = module.compile_log_decls.keys();
|
||||
const values = module.compile_log_decls.values();
|
||||
// First one will be the error; subsequent ones will be notes.
|
||||
@@ -2699,9 +2692,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
const err_msg = Module.ErrorMsg{
|
||||
.src_loc = src_loc,
|
||||
.msg = "found compile log statement",
|
||||
.notes = try self.gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1),
|
||||
.notes = try gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1),
|
||||
};
|
||||
defer self.gpa.free(err_msg.notes);
|
||||
defer gpa.free(err_msg.notes);
|
||||
|
||||
for (keys[1..], 0..) |key, i| {
|
||||
const note_decl = module.declPtr(key);
|
||||
@@ -2711,25 +2704,26 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
|
||||
};
|
||||
}
|
||||
|
||||
try addModuleErrorMsg(gpa, &bundle, err_msg);
|
||||
try addModuleErrorMsg(&bundle, err_msg);
|
||||
}
|
||||
}
|
||||
|
||||
assert(self.totalErrorCount() == bundle.errorMessageCount());
|
||||
assert(self.totalErrorCount() == bundle.root_list.items.len);
|
||||
|
||||
return bundle;
|
||||
return bundle.toOwnedBundle();
|
||||
}
|
||||
|
||||
pub const ErrorNoteHashContext = struct {
|
||||
eb: *const ErrorBundle,
|
||||
eb: *const ErrorBundle.Wip,
|
||||
|
||||
pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 {
|
||||
var hasher = std.hash.Wyhash.init(0);
|
||||
const eb = ctx.eb.tmpBundle();
|
||||
|
||||
hasher.update(ctx.eb.nullTerminatedString(key.msg));
|
||||
if (key.src_loc != 0) {
|
||||
const src = ctx.eb.getSourceLocation(key.src_loc);
|
||||
hasher.update(ctx.eb.nullTerminatedString(src.src_path));
|
||||
hasher.update(eb.nullTerminatedString(key.msg));
|
||||
if (key.src_loc != .none) {
|
||||
const src = eb.getSourceLocation(key.src_loc);
|
||||
hasher.update(eb.nullTerminatedString(src.src_path));
|
||||
std.hash.autoHash(&hasher, src.line);
|
||||
std.hash.autoHash(&hasher, src.column);
|
||||
std.hash.autoHash(&hasher, src.span_main);
|
||||
@@ -2745,17 +2739,18 @@ pub const ErrorNoteHashContext = struct {
|
||||
b_index: usize,
|
||||
) bool {
|
||||
_ = b_index;
|
||||
const msg_a = ctx.eb.nullTerminatedString(a.msg);
|
||||
const msg_b = ctx.eb.nullTerminatedString(b.msg);
|
||||
const eb = ctx.eb.tmpBundle();
|
||||
const msg_a = eb.nullTerminatedString(a.msg);
|
||||
const msg_b = eb.nullTerminatedString(b.msg);
|
||||
if (!std.mem.eql(u8, msg_a, msg_b)) return false;
|
||||
|
||||
if (a.src_loc == 0 and b.src_loc == 0) return true;
|
||||
if (a.src_loc == 0 or b.src_loc == 0) return false;
|
||||
const src_a = ctx.eb.getSourceLocation(a.src_loc);
|
||||
const src_b = ctx.eb.getSourceLocation(b.src_loc);
|
||||
if (a.src_loc == .none and b.src_loc == .none) return true;
|
||||
if (a.src_loc == .none or b.src_loc == .none) return false;
|
||||
const src_a = eb.getSourceLocation(a.src_loc);
|
||||
const src_b = eb.getSourceLocation(b.src_loc);
|
||||
|
||||
const src_path_a = ctx.eb.nullTerminatedString(src_a.src_path);
|
||||
const src_path_b = ctx.eb.nullTerminatedString(src_b.src_path);
|
||||
const src_path_a = eb.nullTerminatedString(src_a.src_path);
|
||||
const src_path_b = eb.nullTerminatedString(src_b.src_path);
|
||||
|
||||
return std.mem.eql(u8, src_path_a, src_path_b) and
|
||||
src_a.line == src_b.line and
|
||||
@@ -2764,16 +2759,16 @@ pub const ErrorNoteHashContext = struct {
|
||||
}
|
||||
};
|
||||
|
||||
pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Module.ErrorMsg) !void {
|
||||
pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void {
|
||||
const gpa = eb.gpa;
|
||||
const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {
|
||||
const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
|
||||
defer gpa.free(file_path);
|
||||
try eb.addErrorMessage(gpa, .{
|
||||
.msg = try eb.printString(gpa, "unable to load '{s}': {s}", .{
|
||||
try eb.addRootErrorMessage(.{
|
||||
.msg = try eb.printString("unable to load '{s}': {s}", .{
|
||||
file_path, @errorName(err),
|
||||
}),
|
||||
});
|
||||
eb.incrementCount(1);
|
||||
return;
|
||||
};
|
||||
const err_span = try module_err_msg.src_loc.span(gpa);
|
||||
@@ -2788,13 +2783,13 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
|
||||
if (module_reference.hidden != 0) {
|
||||
try ref_traces.append(gpa, .{
|
||||
.decl_name = module_reference.hidden,
|
||||
.src_loc = 0,
|
||||
.src_loc = .none,
|
||||
});
|
||||
break;
|
||||
} else if (module_reference.decl == null) {
|
||||
try ref_traces.append(gpa, .{
|
||||
.decl_name = 0,
|
||||
.src_loc = 0,
|
||||
.src_loc = .none,
|
||||
});
|
||||
break;
|
||||
}
|
||||
@@ -2804,9 +2799,9 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
|
||||
const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
|
||||
defer gpa.free(rt_file_path);
|
||||
try ref_traces.append(gpa, .{
|
||||
.decl_name = try eb.addString(gpa, std.mem.sliceTo(module_reference.decl.?, 0)),
|
||||
.src_loc = try eb.addSourceLocation(gpa, .{
|
||||
.src_path = try eb.addString(gpa, rt_file_path),
|
||||
.decl_name = try eb.addString(std.mem.sliceTo(module_reference.decl.?, 0)),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(rt_file_path),
|
||||
.span_start = span.start,
|
||||
.span_main = span.main,
|
||||
.span_end = span.end,
|
||||
@@ -2817,8 +2812,8 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
|
||||
});
|
||||
}
|
||||
|
||||
const src_loc = try eb.addSourceLocation(gpa, .{
|
||||
.src_path = try eb.addString(gpa, file_path),
|
||||
const src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(file_path),
|
||||
.span_start = err_span.start,
|
||||
.span_main = err_span.main,
|
||||
.span_end = err_span.end,
|
||||
@@ -2827,12 +2822,12 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
|
||||
.source_line = if (module_err_msg.src_loc.lazy == .entire_file)
|
||||
0
|
||||
else
|
||||
try eb.addString(gpa, err_loc.source_line),
|
||||
try eb.addString(err_loc.source_line),
|
||||
.reference_trace_len = @intCast(u32, ref_traces.items.len),
|
||||
});
|
||||
|
||||
for (ref_traces.items) |rt| {
|
||||
try eb.addReferenceTrace(gpa, rt);
|
||||
try eb.addReferenceTrace(rt);
|
||||
}
|
||||
|
||||
// De-duplicate error notes. The main use case in mind for this is
|
||||
@@ -2848,15 +2843,15 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
|
||||
defer gpa.free(note_file_path);
|
||||
|
||||
const gop = try notes.getOrPutContext(gpa, .{
|
||||
.msg = try eb.addString(gpa, module_note.msg),
|
||||
.src_loc = try eb.addSourceLocation(gpa, .{
|
||||
.src_path = try eb.addString(gpa, note_file_path),
|
||||
.msg = try eb.addString(module_note.msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(note_file_path),
|
||||
.span_start = span.start,
|
||||
.span_main = span.main,
|
||||
.span_end = span.end,
|
||||
.line = @intCast(u32, loc.line),
|
||||
.column = @intCast(u32, loc.column),
|
||||
.source_line = if (err_loc.eql(loc)) 0 else try eb.addString(gpa, loc.source_line),
|
||||
.source_line = if (err_loc.eql(loc)) 0 else try eb.addString(loc.source_line),
|
||||
}),
|
||||
}, .{ .eb = eb });
|
||||
if (gop.found_existing) {
|
||||
@@ -2864,24 +2859,28 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
|
||||
}
|
||||
}
|
||||
|
||||
try eb.addErrorMessage(gpa, .{
|
||||
.msg = try eb.addString(gpa, module_err_msg.msg),
|
||||
.src_loc = src_loc,
|
||||
.notes_len = @intCast(u32, notes.entries.len),
|
||||
});
|
||||
eb.incrementCount(1);
|
||||
const notes_len = @intCast(u32, notes.entries.len);
|
||||
|
||||
for (notes.keys()) |note| {
|
||||
try eb.addErrorMessage(gpa, note);
|
||||
try eb.addRootErrorMessage(.{
|
||||
.msg = try eb.addString(module_err_msg.msg),
|
||||
.src_loc = src_loc,
|
||||
.notes_len = notes_len,
|
||||
});
|
||||
|
||||
const notes_start = try eb.reserveNotes(notes_len);
|
||||
|
||||
for (notes_start.., notes.keys()) |i, note| {
|
||||
eb.extra.items[i] = @enumToInt(try eb.addErrorMessage(note));
|
||||
}
|
||||
}
|
||||
|
||||
pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File) !void {
|
||||
pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
|
||||
assert(file.zir_loaded);
|
||||
assert(file.tree_loaded);
|
||||
assert(file.source_loaded);
|
||||
const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
|
||||
assert(payload_index != 0);
|
||||
const gpa = eb.gpa;
|
||||
|
||||
const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
|
||||
const items_len = header.data.items_len;
|
||||
@@ -2900,14 +2899,30 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
|
||||
};
|
||||
const err_loc = std.zig.findLineColumn(file.source, err_span.main);
|
||||
|
||||
var notes: []ErrorBundle.ErrorMessage = &.{};
|
||||
defer gpa.free(notes);
|
||||
{
|
||||
const msg = file.zir.nullTerminatedString(item.data.msg);
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
try eb.addRootErrorMessage(.{
|
||||
.msg = try eb.addString(msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(src_path),
|
||||
.span_start = err_span.start,
|
||||
.span_main = err_span.main,
|
||||
.span_end = err_span.end,
|
||||
.line = @intCast(u32, err_loc.line),
|
||||
.column = @intCast(u32, err_loc.column),
|
||||
.source_line = try eb.addString(err_loc.source_line),
|
||||
}),
|
||||
.notes_len = item.data.notes,
|
||||
});
|
||||
}
|
||||
|
||||
if (item.data.notes != 0) {
|
||||
const notes_start = try eb.reserveNotes(item.data.notes);
|
||||
const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
|
||||
const body = file.zir.extra[block.end..][0..block.data.body_len];
|
||||
notes = try gpa.alloc(ErrorBundle.ErrorMessage, body.len);
|
||||
for (notes, body) |*note, body_elem| {
|
||||
for (notes_start.., body) |note_i, body_elem| {
|
||||
const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
|
||||
const msg = file.zir.nullTerminatedString(note_item.data.msg);
|
||||
const span = blk: {
|
||||
@@ -2923,10 +2938,10 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
|
||||
note.* = .{
|
||||
.msg = try eb.addString(gpa, msg),
|
||||
.src_loc = try eb.addSourceLocation(gpa, .{
|
||||
.src_path = try eb.addString(gpa, src_path),
|
||||
eb.extra.items[note_i] = @enumToInt(try eb.addErrorMessage(.{
|
||||
.msg = try eb.addString(msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(src_path),
|
||||
.span_start = span.start,
|
||||
.span_main = span.main,
|
||||
.span_end = span.end,
|
||||
@@ -2935,35 +2950,13 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
|
||||
.source_line = if (loc.eql(err_loc))
|
||||
0
|
||||
else
|
||||
try eb.addString(gpa, loc.source_line),
|
||||
try eb.addString(loc.source_line),
|
||||
}),
|
||||
.notes_len = 0, // TODO rework this function to be recursive
|
||||
};
|
||||
}));
|
||||
}
|
||||
}
|
||||
|
||||
const msg = file.zir.nullTerminatedString(item.data.msg);
|
||||
const src_path = try file.fullPath(gpa);
|
||||
defer gpa.free(src_path);
|
||||
try eb.addErrorMessage(gpa, .{
|
||||
.msg = try eb.addString(gpa, msg),
|
||||
.src_loc = try eb.addSourceLocation(gpa, .{
|
||||
.src_path = try eb.addString(gpa, src_path),
|
||||
.span_start = err_span.start,
|
||||
.span_main = err_span.main,
|
||||
.span_end = err_span.end,
|
||||
.line = @intCast(u32, err_loc.line),
|
||||
.column = @intCast(u32, err_loc.column),
|
||||
.source_line = try eb.addString(gpa, err_loc.source_line),
|
||||
}),
|
||||
.notes_len = @intCast(u32, notes.len),
|
||||
});
|
||||
|
||||
for (notes) |note| {
|
||||
try eb.addErrorMessage(gpa, note);
|
||||
}
|
||||
}
|
||||
eb.incrementCount(items_len);
|
||||
}
|
||||
|
||||
pub fn getCompileLogOutput(self: *Compilation) []const u8 {
|
||||
|
||||
@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(
|
||||
dependencies_source: *std.ArrayList(u8),
|
||||
build_roots_source: *std.ArrayList(u8),
|
||||
name_prefix: []const u8,
|
||||
error_bundle: *std.zig.ErrorBundle,
|
||||
error_bundle: *std.zig.ErrorBundle.Wip,
|
||||
all_modules: *AllModules,
|
||||
) !void {
|
||||
const max_bytes = 10 * 1024 * 1024;
|
||||
@@ -260,13 +260,12 @@ pub fn fetchAndAddDependencies(
|
||||
if (manifest.errors.len > 0) {
|
||||
const file_path = try directory.join(arena, &.{Manifest.basename});
|
||||
for (manifest.errors) |msg| {
|
||||
try Report.addErrorMessage(gpa, ast, file_path, error_bundle, 0, msg);
|
||||
try Report.addErrorMessage(ast, file_path, error_bundle, 0, msg);
|
||||
}
|
||||
return error.PackageFetchFailed;
|
||||
}
|
||||
|
||||
const report: Report = .{
|
||||
.gpa = gpa,
|
||||
.ast = &ast,
|
||||
.directory = directory,
|
||||
.error_bundle = error_bundle,
|
||||
@@ -343,10 +342,9 @@ pub fn createFilePkg(
|
||||
}
|
||||
|
||||
const Report = struct {
|
||||
gpa: Allocator,
|
||||
ast: *const std.zig.Ast,
|
||||
directory: Compilation.Directory,
|
||||
error_bundle: *std.zig.ErrorBundle,
|
||||
error_bundle: *std.zig.ErrorBundle.Wip,
|
||||
|
||||
fn fail(
|
||||
report: Report,
|
||||
@@ -354,7 +352,7 @@ const Report = struct {
|
||||
comptime fmt_string: []const u8,
|
||||
fmt_args: anytype,
|
||||
) error{ PackageFetchFailed, OutOfMemory } {
|
||||
const gpa = report.gpa;
|
||||
const gpa = report.error_bundle.gpa;
|
||||
|
||||
const file_path = try report.directory.join(gpa, &.{Manifest.basename});
|
||||
defer gpa.free(file_path);
|
||||
@@ -362,7 +360,7 @@ const Report = struct {
|
||||
const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);
|
||||
defer gpa.free(msg);
|
||||
|
||||
try addErrorMessage(report.gpa, report.ast.*, file_path, report.error_bundle, 0, .{
|
||||
try addErrorMessage(report.ast.*, file_path, report.error_bundle, 0, .{
|
||||
.tok = tok,
|
||||
.off = 0,
|
||||
.msg = msg,
|
||||
@@ -372,30 +370,28 @@ const Report = struct {
|
||||
}
|
||||
|
||||
fn addErrorMessage(
|
||||
gpa: Allocator,
|
||||
ast: std.zig.Ast,
|
||||
file_path: []const u8,
|
||||
eb: *std.zig.ErrorBundle,
|
||||
eb: *std.zig.ErrorBundle.Wip,
|
||||
notes_len: u32,
|
||||
msg: Manifest.ErrorMessage,
|
||||
) error{OutOfMemory}!void {
|
||||
const token_starts = ast.tokens.items(.start);
|
||||
const start_loc = ast.tokenLocation(0, msg.tok);
|
||||
|
||||
try eb.addErrorMessage(gpa, .{
|
||||
.msg = try eb.addString(gpa, msg.msg),
|
||||
.src_loc = try eb.addSourceLocation(gpa, .{
|
||||
.src_path = try eb.addString(gpa, file_path),
|
||||
try eb.addRootErrorMessage(.{
|
||||
.msg = try eb.addString(msg.msg),
|
||||
.src_loc = try eb.addSourceLocation(.{
|
||||
.src_path = try eb.addString(file_path),
|
||||
.span_start = token_starts[msg.tok],
|
||||
.span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
|
||||
.span_main = token_starts[msg.tok] + msg.off,
|
||||
.line = @intCast(u32, start_loc.line),
|
||||
.column = @intCast(u32, start_loc.column),
|
||||
.source_line = try eb.addString(gpa, ast.source[start_loc.line_start..start_loc.line_end]),
|
||||
.source_line = try eb.addString(ast.source[start_loc.line_start..start_loc.line_end]),
|
||||
}),
|
||||
.notes_len = notes_len,
|
||||
});
|
||||
eb.incrementCount(1);
|
||||
}
|
||||
};
|
||||
|
||||
@@ -526,14 +522,16 @@ fn fetchAndUnpack(
|
||||
defer gpa.free(file_path);
|
||||
|
||||
const eb = report.error_bundle;
|
||||
try Report.addErrorMessage(gpa, report.ast.*, file_path, eb, 1, .{
|
||||
const notes_len = 1;
|
||||
try Report.addErrorMessage(report.ast.*, file_path, eb, notes_len, .{
|
||||
.tok = dep.url_tok,
|
||||
.off = 0,
|
||||
.msg = "url field is missing corresponding hash field",
|
||||
});
|
||||
try eb.addErrorMessage(gpa, .{
|
||||
.msg = try eb.printString(gpa, "expected .hash = \"{s}\",", .{&actual_hex}),
|
||||
});
|
||||
const notes_start = try eb.reserveNotes(notes_len);
|
||||
eb.extra.items[notes_start] = @enumToInt(try eb.addErrorMessage(.{
|
||||
.msg = try eb.printString("expected .hash = \"{s}\",", .{&actual_hex}),
|
||||
}));
|
||||
return error.PackageFetchFailed;
|
||||
}
|
||||
|
||||
|
||||
@@ -2215,11 +2215,12 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
|
||||
|
||||
if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
|
||||
if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
errors.init(gpa) catch unreachable;
|
||||
Compilation.addModuleErrorMsg(gpa, &errors, err_msg.*) catch unreachable;
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
wip_errors.init(gpa) catch unreachable;
|
||||
Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable;
|
||||
std.debug.print("compile error during Sema:\n", .{});
|
||||
errors.renderToStdErr(.no_color);
|
||||
var error_bundle = wip_errors.toOwnedBundle() catch unreachable;
|
||||
error_bundle.renderToStdErr(.no_color);
|
||||
crash_report.compilerPanic("unexpected compile error occurred", null, null);
|
||||
}
|
||||
|
||||
|
||||
86
src/main.zig
86
src/main.zig
@@ -4436,9 +4436,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
|
||||
var all_modules: Package.AllModules = .{};
|
||||
defer all_modules.deinit(gpa);
|
||||
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
try errors.init(gpa);
|
||||
defer errors.deinit(gpa);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
|
||||
// Here we borrow main package's table and will replace it with a fresh
|
||||
// one after this process completes.
|
||||
@@ -4453,15 +4453,17 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
|
||||
&dependencies_source,
|
||||
&build_roots_source,
|
||||
"",
|
||||
&errors,
|
||||
&wip_errors,
|
||||
&all_modules,
|
||||
);
|
||||
if (errors.errorMessageCount() > 0) {
|
||||
if (wip_errors.root_list.items.len > 0) {
|
||||
const ttyconf: std.debug.TTY.Config = switch (color) {
|
||||
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
var errors = try wip_errors.toOwnedBundle();
|
||||
defer errors.deinit(gpa);
|
||||
errors.renderToStdErr(ttyconf);
|
||||
process.exit(1);
|
||||
}
|
||||
@@ -4721,16 +4723,18 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
try errors.init(gpa);
|
||||
defer errors.deinit(gpa);
|
||||
try Compilation.addZirErrorMessages(gpa, &errors, &file);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
const ttyconf: std.debug.TTY.Config = switch (color) {
|
||||
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
errors.renderToStdErr(ttyconf);
|
||||
var error_bundle = try wip_errors.toOwnedBundle();
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(ttyconf);
|
||||
has_ast_error = true;
|
||||
}
|
||||
}
|
||||
@@ -4930,16 +4934,18 @@ fn fmtPathFile(
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
try errors.init(gpa);
|
||||
defer errors.deinit(gpa);
|
||||
try Compilation.addZirErrorMessages(gpa, &errors, &file);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
const ttyconf: std.debug.TTY.Config = switch (fmt.color) {
|
||||
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
errors.renderToStdErr(ttyconf);
|
||||
var error_bundle = try wip_errors.toOwnedBundle();
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(ttyconf);
|
||||
fmt.any_error = true;
|
||||
}
|
||||
}
|
||||
@@ -4968,17 +4974,19 @@ fn fmtPathFile(
|
||||
}
|
||||
|
||||
fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
|
||||
var error_bundle: std.zig.ErrorBundle = undefined;
|
||||
try error_bundle.init(gpa);
|
||||
defer error_bundle.deinit(gpa);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
|
||||
try putAstErrorsIntoBundle(gpa, tree, path, &error_bundle);
|
||||
try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
|
||||
|
||||
const ttyconf: std.debug.TTY.Config = switch (color) {
|
||||
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
var error_bundle = try wip_errors.toOwnedBundle();
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(ttyconf);
|
||||
}
|
||||
|
||||
@@ -4986,7 +4994,7 @@ pub fn putAstErrorsIntoBundle(
|
||||
gpa: Allocator,
|
||||
tree: Ast,
|
||||
path: []const u8,
|
||||
error_bundle: *std.zig.ErrorBundle,
|
||||
wip_errors: *std.zig.ErrorBundle.Wip,
|
||||
) !void {
|
||||
var file: Module.File = .{
|
||||
.status = .never_loaded,
|
||||
@@ -5013,7 +5021,7 @@ pub fn putAstErrorsIntoBundle(
|
||||
file.zir_loaded = true;
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
try Compilation.addZirErrorMessages(gpa, error_bundle, &file);
|
||||
try Compilation.addZirErrorMessages(wip_errors, &file);
|
||||
}
|
||||
|
||||
pub const info_zen =
|
||||
@@ -5595,16 +5603,18 @@ pub fn cmdAstCheck(
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
try errors.init(gpa);
|
||||
defer errors.deinit(gpa);
|
||||
try Compilation.addZirErrorMessages(gpa, &errors, &file);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
const ttyconf: std.debug.TTY.Config = switch (color) {
|
||||
.auto => std.debug.detectTTYConfig(std.io.getStdErr()),
|
||||
.on => .escape_codes,
|
||||
.off => .no_color,
|
||||
};
|
||||
errors.renderToStdErr(ttyconf);
|
||||
var error_bundle = try wip_errors.toOwnedBundle();
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(ttyconf);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -5719,12 +5729,14 @@ pub fn cmdChangelist(
|
||||
defer file.zir.deinit(gpa);
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
try errors.init(gpa);
|
||||
defer errors.deinit(gpa);
|
||||
try Compilation.addZirErrorMessages(gpa, &errors, &file);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
|
||||
errors.renderToStdErr(ttyconf);
|
||||
var error_bundle = try wip_errors.toOwnedBundle();
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(ttyconf);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
@@ -5758,12 +5770,14 @@ pub fn cmdChangelist(
|
||||
file.zir_loaded = true;
|
||||
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
var errors: std.zig.ErrorBundle = undefined;
|
||||
try errors.init(gpa);
|
||||
defer errors.deinit(gpa);
|
||||
try Compilation.addZirErrorMessages(gpa, &errors, &file);
|
||||
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
|
||||
try wip_errors.init(gpa);
|
||||
defer wip_errors.deinit();
|
||||
try Compilation.addZirErrorMessages(&wip_errors, &file);
|
||||
const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
|
||||
errors.renderToStdErr(ttyconf);
|
||||
var error_bundle = try wip_errors.toOwnedBundle();
|
||||
defer error_bundle.deinit(gpa);
|
||||
error_bundle.renderToStdErr(ttyconf);
|
||||
process.exit(1);
|
||||
}
|
||||
|
||||
|
||||
21
src/test.zig
21
src/test.zig
@@ -1242,7 +1242,7 @@ pub const TestContext = struct {
|
||||
defer self.gpa.free(zig_lib_directory.path.?);
|
||||
|
||||
var aux_thread_pool: ThreadPool = undefined;
|
||||
try aux_thread_pool.init(self.gpa);
|
||||
try aux_thread_pool.init(.{ .allocator = self.gpa });
|
||||
defer aux_thread_pool.deinit();
|
||||
|
||||
// Use the same global cache dir for all the tests, such that we for example don't have to
|
||||
@@ -1614,23 +1614,8 @@ pub const TestContext = struct {
|
||||
if (update.case != .Error) {
|
||||
var all_errors = try comp.getAllErrorsAlloc();
|
||||
defer all_errors.deinit(allocator);
|
||||
if (all_errors.list.len != 0) {
|
||||
print(
|
||||
"\nCase '{s}': unexpected errors at update_index={d}:\n{s}\n",
|
||||
.{ case.name, update_index, hr },
|
||||
);
|
||||
for (all_errors.list) |err_msg| {
|
||||
switch (err_msg) {
|
||||
.src => |src| {
|
||||
print("{s}:{d}:{d}: error: {s}\n{s}\n", .{
|
||||
src.src_path, src.line + 1, src.column + 1, src.msg, hr,
|
||||
});
|
||||
},
|
||||
.plain => |plain| {
|
||||
print("error: {s}\n{s}\n", .{ plain.msg, hr });
|
||||
},
|
||||
}
|
||||
}
|
||||
if (all_errors.errorMessageCount() > 0) {
|
||||
all_errors.renderToStdErr(std.debug.detectTTYConfig(std.io.getStdErr()));
|
||||
// TODO print generated C code
|
||||
return error.UnexpectedCompileErrors;
|
||||
}
|
||||
|
||||
Reference in New Issue
Block a user