authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-02-23 19:21:44-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2023-03-15 10:48:13-07:00
log6f717b18f05ba02439603e0987e9c9551fbadedb
treec95613ef714eed338372d1947c0132808beffab4
parent572cb24d1a4f70c662ddf17df72d27dec44bc4fc

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.

6 files changed, 425 insertions(+), 390 deletions(-)

lib/std/zig/ErrorBundle.zig+227-183
...@@ -3,24 +3,22 @@...@@ -3,24 +3,22 @@
3//! is used to collect all the errors from the various places into one3//! is used to collect all the errors from the various places into one
4//! convenient place for API users to consume.4//! convenient place for API users to consume.
55
6string_bytes: std.ArrayListUnmanaged(u8),6string_bytes: []const u8,
7/// The first thing in this array is a ErrorMessageListIndex.7/// The first thing in this array is an `ErrorMessageList`.
8extra: std.ArrayListUnmanaged(u32),8extra: []const u32,
99
10// An index into `extra` pointing at an `ErrorMessage`.10// An index into `extra` pointing at an `ErrorMessage`.
11pub const MessageIndex = enum(u32) {11pub const MessageIndex = enum(u32) {
12 _,12 _,
13};13};
1414
15/// After the header is:15// An index into `extra` pointing at an `SourceLocation`.
16/// * string_bytes16pub const SourceLocationIndex = enum(u32) {
17/// * extra (little endian)17 none = 0,
18pub const Header = struct {18 _,
19 string_bytes_len: u32,
20 extra_len: u32,
21};19};
2220
23/// Trailing: ErrorMessage for each len21/// There will be a MessageIndex for each len at start.
24pub const ErrorMessageList = struct {22pub const ErrorMessageList = struct {
25 len: u32,23 len: u32,
26 start: u32,24 start: u32,
...@@ -46,14 +44,13 @@ pub const SourceLocation = struct {...@@ -46,14 +44,13 @@ pub const SourceLocation = struct {
46};44};
4745
48/// Trailing:46/// Trailing:
49/// * ErrorMessage for each notes_len.47/// * MessageIndex for each notes_len.
50pub const ErrorMessage = struct {48pub const ErrorMessage = struct {
51 /// null terminated string index49 /// null terminated string index
52 msg: u32,50 msg: u32,
53 /// Usually one, but incremented for redundant messages.51 /// Usually one, but incremented for redundant messages.
54 count: u32 = 1,52 count: u32 = 1,
55 /// 0 or the index into extra of a SourceLocation53 src_loc: SourceLocationIndex = .none,
56 src_loc: u32 = 0,
57 notes_len: u32 = 0,54 notes_len: u32 = 0,
58};55};
5956
...@@ -65,170 +62,41 @@ pub const ReferenceTrace = struct {...@@ -65,170 +62,41 @@ pub const ReferenceTrace = struct {
65 decl_name: u32,62 decl_name: u32,
66 /// Index into extra of a SourceLocation63 /// Index into extra of a SourceLocation
67 /// If this is 0, this is the sentinel ReferenceTrace element.64 /// If this is 0, this is the sentinel ReferenceTrace element.
68 src_loc: u32,65 src_loc: SourceLocationIndex,
69};66};
7067
71pub fn init(eb: *ErrorBundle, gpa: Allocator) !void {
72 eb.* = .{
73 .string_bytes = .{},
74 .extra = .{},
75 };
76
77 // So that 0 can be used to indicate a null string.
78 try eb.string_bytes.append(gpa, 0);
79
80 _ = try addExtra(eb, gpa, ErrorMessageList{
81 .len = 0,
82 .start = 0,
83 });
84}
85
86pub fn deinit(eb: *ErrorBundle, gpa: Allocator) void {68pub fn deinit(eb: *ErrorBundle, gpa: Allocator) void {
87 eb.string_bytes.deinit(gpa);69 gpa.free(eb.string_bytes);
88 eb.extra.deinit(gpa);70 gpa.free(eb.extra);
89 eb.* = undefined;71 eb.* = undefined;
90}72}
9173
92pub fn addString(eb: *ErrorBundle, gpa: Allocator, s: []const u8) !u32 {
93 const index = @intCast(u32, eb.string_bytes.items.len);
94 try eb.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
95 eb.string_bytes.appendSliceAssumeCapacity(s);
96 eb.string_bytes.appendAssumeCapacity(0);
97 return index;
98}
99
100pub fn printString(eb: *ErrorBundle, gpa: Allocator, comptime fmt: []const u8, args: anytype) !u32 {
101 const index = @intCast(u32, eb.string_bytes.items.len);
102 try eb.string_bytes.writer(gpa).print(fmt, args);
103 try eb.string_bytes.append(gpa, 0);
104 return index;
105}
106
107pub fn addErrorMessage(eb: *ErrorBundle, gpa: Allocator, em: ErrorMessage) !void {
108 if (eb.errorMessageCount() == 0) {
109 eb.setStartIndex(@intCast(u32, eb.extra.items.len));
110 }
111 _ = try addExtra(eb, gpa, em);
112}
113
114pub fn addSourceLocation(eb: *ErrorBundle, gpa: Allocator, sl: SourceLocation) !u32 {
115 return addExtra(eb, gpa, sl);
116}
117
118pub fn addReferenceTrace(eb: *ErrorBundle, gpa: Allocator, rt: ReferenceTrace) !void {
119 _ = try addExtra(eb, gpa, rt);
120}
121
122pub fn addBundle(eb: *ErrorBundle, gpa: Allocator, other: ErrorBundle) !void {
123 // Skip over the initial ErrorMessageList len field.
124 const root_fields_len = @typeInfo(ErrorMessageList).Struct.fields.len;
125 const other_list = other.extraData(ErrorMessageList, 0).data;
126 const other_extra = other.extra.items[root_fields_len..];
127
128 try eb.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.items.len);
129 try eb.extra.ensureUnusedCapacity(gpa, other_extra.len);
130
131 const new_string_base = @intCast(u32, eb.string_bytes.items.len);
132 const new_data_base = @intCast(u32, eb.extra.items.len - root_fields_len);
133
134 eb.string_bytes.appendSliceAssumeCapacity(other.string_bytes.items);
135 eb.extra.appendSliceAssumeCapacity(other_extra);
136
137 // Now we must offset the string indexes and extra indexes of the newly
138 // added extra.
139 var index = new_data_base + other_list.start;
140 for (0..other_list.len) |_| {
141 index = try patchMessage(eb, index, new_string_base, new_data_base);
142 }
143}
144
145fn patchMessage(eb: *ErrorBundle, msg_idx: usize, new_string_base: u32, new_data_base: u32) !u32 {
146 var msg = eb.extraData(ErrorMessage, msg_idx);
147 if (msg.data.msg != 0) msg.data.msg += new_string_base;
148 if (msg.data.src_loc != 0) msg.data.src_loc += new_data_base;
149 eb.setExtra(msg_idx, msg.data);
150
151 try patchSrcLoc(eb, msg.data.src_loc, new_string_base, new_data_base);
152
153 var index = @intCast(u32, msg.end);
154 for (0..msg.data.notes_len) |_| {
155 index = try patchMessage(eb, index, new_string_base, new_data_base);
156 }
157 return index;
158}
159
160fn patchSrcLoc(eb: *ErrorBundle, idx: usize, new_string_base: u32, new_data_base: u32) !void {
161 if (idx == 0) return;
162
163 var src_loc = eb.extraData(SourceLocation, idx);
164 if (src_loc.data.src_path != 0) src_loc.data.src_path += new_string_base;
165 if (src_loc.data.source_line != 0) src_loc.data.source_line += new_string_base;
166 eb.setExtra(idx, src_loc.data);
167
168 var index = src_loc.end;
169 for (0..src_loc.data.reference_trace_len) |_| {
170 var ref_trace = eb.extraData(ReferenceTrace, index);
171 if (ref_trace.data.decl_name != 0) ref_trace.data.decl_name += new_string_base;
172 if (ref_trace.data.src_loc != 0) ref_trace.data.src_loc += new_data_base;
173 eb.setExtra(index, ref_trace.data);
174 try patchSrcLoc(eb, ref_trace.data.src_loc, new_string_base, new_data_base);
175 index = ref_trace.end;
176 }
177}
178
179fn addExtra(eb: *ErrorBundle, gpa: Allocator, extra: anytype) Allocator.Error!u32 {
180 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
181 try eb.extra.ensureUnusedCapacity(gpa, fields.len);
182 return addExtraAssumeCapacity(eb, extra);
183}
184
185fn addExtraAssumeCapacity(eb: *ErrorBundle, extra: anytype) u32 {
186 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
187 const result = @intCast(u32, eb.extra.items.len);
188 eb.extra.items.len += fields.len;
189 setExtra(eb, result, extra);
190 return result;
191}
192
193fn setExtra(eb: *ErrorBundle, index: usize, extra: anytype) void {
194 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
195 var i = index;
196 inline for (fields) |field| {
197 eb.extra.items[i] = switch (field.type) {
198 u32 => @field(extra, field.name),
199 else => @compileError("bad field type"),
200 };
201 i += 1;
202 }
203}
204
205pub fn errorMessageCount(eb: ErrorBundle) u32 {74pub fn errorMessageCount(eb: ErrorBundle) u32 {
206 return eb.extra.items[0];75 return eb.getErrorMessageList().len;
207}
208
209pub fn setErrorMessageCount(eb: *ErrorBundle, count: u32) void {
210 eb.extra.items[0] = count;
211}76}
21277
213pub fn incrementCount(eb: *ErrorBundle, delta: u32) void {78pub fn getErrorMessageList(eb: ErrorBundle) ErrorMessageList {
214 eb.extra.items[0] += delta;79 return eb.extraData(ErrorMessageList, 0).data;
215}80}
21681
217pub fn getStartIndex(eb: ErrorBundle) u32 {82pub fn getMessages(eb: ErrorBundle) []const MessageIndex {
218 return eb.extra.items[1];83 const list = eb.getErrorMessageList();
219}84 return @ptrCast([]const MessageIndex, eb.extra[list.start..][0..list.len]);
220
221pub fn setStartIndex(eb: *ErrorBundle, index: u32) void {
222 eb.extra.items[1] = index;
223}85}
22486
225pub fn getErrorMessage(eb: ErrorBundle, index: MessageIndex) ErrorMessage {87pub fn getErrorMessage(eb: ErrorBundle, index: MessageIndex) ErrorMessage {
226 return eb.extraData(ErrorMessage, @enumToInt(index)).data;88 return eb.extraData(ErrorMessage, @enumToInt(index)).data;
227}89}
22890
229pub fn getSourceLocation(eb: ErrorBundle, index: u32) SourceLocation {91pub fn getSourceLocation(eb: ErrorBundle, index: SourceLocationIndex) SourceLocation {
230 assert(index != 0);92 assert(index != .none);
231 return eb.extraData(SourceLocation, index).data;93 return eb.extraData(SourceLocation, @enumToInt(index)).data;
94}
95
96pub fn getNotes(eb: ErrorBundle, index: MessageIndex) []const MessageIndex {
97 const notes_len = eb.getErrorMessage(index).notes_len;
98 const start = @enumToInt(index) + @typeInfo(ErrorMessage).Struct.fields.len;
99 return @ptrCast([]const MessageIndex, eb.extra[start..][0..notes_len]);
232}100}
233101
234/// Returns the requested data, as well as the new index which is at the start of the102/// 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,...@@ -239,7 +107,9 @@ fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T,
239 var result: T = undefined;107 var result: T = undefined;
240 inline for (fields) |field| {108 inline for (fields) |field| {
241 @field(result, field.name) = switch (field.type) {109 @field(result, field.name) = switch (field.type) {
242 u32 => eb.extra.items[i],110 u32 => eb.extra[i],
111 MessageIndex => @intToEnum(MessageIndex, eb.extra[i]),
112 SourceLocationIndex => @intToEnum(SourceLocationIndex, eb.extra[i]),
243 else => @compileError("bad field type"),113 else => @compileError("bad field type"),
244 };114 };
245 i += 1;115 i += 1;
...@@ -252,7 +122,7 @@ fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T,...@@ -252,7 +122,7 @@ fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T,
252122
253/// Given an index into `string_bytes` returns the null-terminated string found there.123/// Given an index into `string_bytes` returns the null-terminated string found there.
254pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {124pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
255 const string_bytes = eb.string_bytes.items;125 const string_bytes = eb.string_bytes;
256 var end: usize = index;126 var end: usize = index;
257 while (string_bytes[end] != 0) {127 while (string_bytes[end] != 0) {
258 end += 1;128 end += 1;
...@@ -272,28 +142,25 @@ pub fn renderToWriter(...@@ -272,28 +142,25 @@ pub fn renderToWriter(
272 ttyconf: std.debug.TTY.Config,142 ttyconf: std.debug.TTY.Config,
273 writer: anytype,143 writer: anytype,
274) anyerror!void {144) anyerror!void {
275 const list = eb.extraData(ErrorMessageList, 0).data;145 for (eb.getMessages()) |err_msg| {
276 var index: usize = list.start;146 try renderErrorMessageToWriter(eb, err_msg, ttyconf, writer, "error", .Red, 0);
277 for (0..list.len) |_| {
278 const err_msg = eb.extraData(ErrorMessage, index);
279 index = try renderErrorMessageToWriter(eb, err_msg.data, err_msg.end, ttyconf, writer, "error", .Red, 0);
280 }147 }
281}148}
282149
283fn renderErrorMessageToWriter(150fn renderErrorMessageToWriter(
284 eb: ErrorBundle,151 eb: ErrorBundle,
285 err_msg: ErrorMessage,152 err_msg_index: MessageIndex,
286 end_index: usize,
287 ttyconf: std.debug.TTY.Config,153 ttyconf: std.debug.TTY.Config,
288 stderr: anytype,154 stderr: anytype,
289 kind: []const u8,155 kind: []const u8,
290 color: std.debug.TTY.Color,156 color: std.debug.TTY.Color,
291 indent: usize,157 indent: usize,
292) anyerror!usize {158) anyerror!void {
293 var counting_writer = std.io.countingWriter(stderr);159 var counting_writer = std.io.countingWriter(stderr);
294 const counting_stderr = counting_writer.writer();160 const counting_stderr = counting_writer.writer();
295 if (err_msg.src_loc != 0) {161 const err_msg = eb.getErrorMessage(err_msg_index);
296 const src = eb.extraData(SourceLocation, err_msg.src_loc);162 if (err_msg.src_loc != .none) {
163 const src = eb.extraData(SourceLocation, @enumToInt(err_msg.src_loc));
297 try counting_stderr.writeByteNTimes(' ', indent);164 try counting_stderr.writeByteNTimes(' ', indent);
298 try ttyconf.setColor(stderr, .Bold);165 try ttyconf.setColor(stderr, .Bold);
299 try counting_stderr.print("{s}:{d}:{d}: ", .{166 try counting_stderr.print("{s}:{d}:{d}: ", .{
...@@ -337,10 +204,8 @@ fn renderErrorMessageToWriter(...@@ -337,10 +204,8 @@ fn renderErrorMessageToWriter(
337 try stderr.writeByte('\n');204 try stderr.writeByte('\n');
338 try ttyconf.setColor(stderr, .Reset);205 try ttyconf.setColor(stderr, .Reset);
339 }206 }
340 var index = end_index;207 for (eb.getNotes(err_msg_index)) |note| {
341 for (0..err_msg.notes_len) |_| {208 try renderErrorMessageToWriter(eb, note, ttyconf, stderr, "note", .Cyan, indent);
342 const note = eb.extraData(ErrorMessage, index);
343 index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent);
344 }209 }
345 if (src.data.reference_trace_len > 0) {210 if (src.data.reference_trace_len > 0) {
346 try ttyconf.setColor(stderr, .Reset);211 try ttyconf.setColor(stderr, .Reset);
...@@ -350,7 +215,7 @@ fn renderErrorMessageToWriter(...@@ -350,7 +215,7 @@ fn renderErrorMessageToWriter(
350 for (0..src.data.reference_trace_len) |_| {215 for (0..src.data.reference_trace_len) |_| {
351 const ref_trace = eb.extraData(ReferenceTrace, ref_index);216 const ref_trace = eb.extraData(ReferenceTrace, ref_index);
352 ref_index = ref_trace.end;217 ref_index = ref_trace.end;
353 if (ref_trace.data.src_loc != 0) {218 if (ref_trace.data.src_loc != .none) {
354 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);219 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
355 try stderr.print(" {s}: {s}:{d}:{d}\n", .{220 try stderr.print(" {s}: {s}:{d}:{d}\n", .{
356 eb.nullTerminatedString(ref_trace.data.decl_name),221 eb.nullTerminatedString(ref_trace.data.decl_name),
...@@ -374,7 +239,6 @@ fn renderErrorMessageToWriter(...@@ -374,7 +239,6 @@ fn renderErrorMessageToWriter(
374 try stderr.writeByte('\n');239 try stderr.writeByte('\n');
375 try ttyconf.setColor(stderr, .Reset);240 try ttyconf.setColor(stderr, .Reset);
376 }241 }
377 return index;
378 } else {242 } else {
379 try ttyconf.setColor(stderr, color);243 try ttyconf.setColor(stderr, color);
380 try stderr.writeByteNTimes(' ', indent);244 try stderr.writeByteNTimes(' ', indent);
...@@ -390,12 +254,9 @@ fn renderErrorMessageToWriter(...@@ -390,12 +254,9 @@ fn renderErrorMessageToWriter(
390 try stderr.print(" ({d} times)\n", .{err_msg.count});254 try stderr.print(" ({d} times)\n", .{err_msg.count});
391 }255 }
392 try ttyconf.setColor(stderr, .Reset);256 try ttyconf.setColor(stderr, .Reset);
393 var index = end_index;257 for (eb.getNotes(err_msg_index)) |note| {
394 for (0..err_msg.notes_len) |_| {258 try renderErrorMessageToWriter(eb, note, ttyconf, stderr, "note", .Cyan, indent + 4);
395 const note = eb.extraData(ErrorMessage, index);
396 index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent + 4);
397 }259 }
398 return index;
399 }260 }
400}261}
401262
...@@ -417,3 +278,186 @@ const std = @import("std");...@@ -417,3 +278,186 @@ const std = @import("std");
417const ErrorBundle = @This();278const ErrorBundle = @This();
418const Allocator = std.mem.Allocator;279const Allocator = std.mem.Allocator;
419const assert = std.debug.assert;280const assert = std.debug.assert;
281
282pub const Wip = struct {
283 gpa: Allocator,
284 string_bytes: std.ArrayListUnmanaged(u8),
285 /// The first thing in this array is a ErrorMessageList.
286 extra: std.ArrayListUnmanaged(u32),
287 root_list: std.ArrayListUnmanaged(MessageIndex),
288
289 pub fn init(wip: *Wip, gpa: Allocator) !void {
290 wip.* = .{
291 .gpa = gpa,
292 .string_bytes = .{},
293 .extra = .{},
294 .root_list = .{},
295 };
296
297 // So that 0 can be used to indicate a null string.
298 try wip.string_bytes.append(gpa, 0);
299
300 assert(0 == try addExtra(wip, ErrorMessageList{
301 .len = 0,
302 .start = 0,
303 }));
304 }
305
306 pub fn deinit(wip: *Wip) void {
307 const gpa = wip.gpa;
308 wip.root_list.deinit(gpa);
309 wip.string_bytes.deinit(gpa);
310 wip.extra.deinit(gpa);
311 wip.* = undefined;
312 }
313
314 pub fn toOwnedBundle(wip: *Wip) !ErrorBundle {
315 const gpa = wip.gpa;
316 wip.setExtra(0, ErrorMessageList{
317 .len = @intCast(u32, wip.root_list.items.len),
318 .start = @intCast(u32, wip.extra.items.len),
319 });
320 try wip.extra.appendSlice(gpa, @ptrCast([]const u32, wip.root_list.items));
321 wip.root_list.clearAndFree(gpa);
322 return .{
323 .string_bytes = try wip.string_bytes.toOwnedSlice(gpa),
324 .extra = try wip.extra.toOwnedSlice(gpa),
325 };
326 }
327
328 pub fn tmpBundle(wip: Wip) ErrorBundle {
329 return .{
330 .string_bytes = wip.string_bytes.items,
331 .extra = wip.extra.items,
332 };
333 }
334
335 pub fn addString(wip: *Wip, s: []const u8) !u32 {
336 const gpa = wip.gpa;
337 const index = @intCast(u32, wip.string_bytes.items.len);
338 try wip.string_bytes.ensureUnusedCapacity(gpa, s.len + 1);
339 wip.string_bytes.appendSliceAssumeCapacity(s);
340 wip.string_bytes.appendAssumeCapacity(0);
341 return index;
342 }
343
344 pub fn printString(wip: *Wip, comptime fmt: []const u8, args: anytype) !u32 {
345 const gpa = wip.gpa;
346 const index = @intCast(u32, wip.string_bytes.items.len);
347 try wip.string_bytes.writer(gpa).print(fmt, args);
348 try wip.string_bytes.append(gpa, 0);
349 return index;
350 }
351
352 pub fn addRootErrorMessage(wip: *Wip, em: ErrorMessage) !void {
353 try wip.root_list.ensureUnusedCapacity(wip.gpa, 1);
354 wip.root_list.appendAssumeCapacity(try addErrorMessage(wip, em));
355 }
356
357 pub fn addErrorMessage(wip: *Wip, em: ErrorMessage) !MessageIndex {
358 return @intToEnum(MessageIndex, try addExtra(wip, em));
359 }
360
361 pub fn addErrorMessageAssumeCapacity(wip: *Wip, em: ErrorMessage) MessageIndex {
362 return @intToEnum(MessageIndex, addExtraAssumeCapacity(wip, em));
363 }
364
365 pub fn addSourceLocation(wip: *Wip, sl: SourceLocation) !SourceLocationIndex {
366 return @intToEnum(SourceLocationIndex, try addExtra(wip, sl));
367 }
368
369 pub fn addReferenceTrace(wip: *Wip, rt: ReferenceTrace) !void {
370 _ = try addExtra(wip, rt);
371 }
372
373 pub fn addBundle(wip: *Wip, other: ErrorBundle) !void {
374 const gpa = wip.gpa;
375
376 try wip.string_bytes.ensureUnusedCapacity(gpa, other.string_bytes.len);
377 try wip.extra.ensureUnusedCapacity(gpa, other.extra.len);
378
379 const other_list = other.getMessages();
380
381 // The ensureUnusedCapacity call above guarantees this.
382 const notes_start = wip.reserveNotes(@intCast(u32, other_list.len)) catch unreachable;
383 for (notes_start.., other_list) |note, message| {
384 wip.extra.items[note] = @enumToInt(wip.addOtherMessage(other, message) catch unreachable);
385 }
386 }
387
388 pub fn reserveNotes(wip: *Wip, notes_len: u32) !u32 {
389 try wip.extra.ensureUnusedCapacity(wip.gpa, notes_len +
390 notes_len * @typeInfo(ErrorBundle.ErrorMessage).Struct.fields.len);
391 wip.extra.items.len += notes_len;
392 return @intCast(u32, wip.extra.items.len - notes_len);
393 }
394
395 fn addOtherMessage(wip: *Wip, other: ErrorBundle, msg_index: MessageIndex) !MessageIndex {
396 const other_msg = other.getErrorMessage(msg_index);
397 const src_loc = try wip.addOtherSourceLocation(other, other_msg.src_loc);
398 const msg = try wip.addErrorMessage(.{
399 .msg = try wip.addString(other.nullTerminatedString(other_msg.msg)),
400 .count = other_msg.count,
401 .src_loc = src_loc,
402 .notes_len = other_msg.notes_len,
403 });
404 const notes_start = try wip.reserveNotes(other_msg.notes_len);
405 for (notes_start.., other.getNotes(msg_index)) |note, other_note| {
406 wip.extra.items[note] = @enumToInt(try wip.addOtherMessage(other, other_note));
407 }
408 return msg;
409 }
410
411 fn addOtherSourceLocation(
412 wip: *Wip,
413 other: ErrorBundle,
414 index: SourceLocationIndex,
415 ) !SourceLocationIndex {
416 if (index == .none) return .none;
417 const other_sl = other.getSourceLocation(index);
418
419 const src_loc = try wip.addSourceLocation(.{
420 .src_path = try wip.addString(other.nullTerminatedString(other_sl.src_path)),
421 .line = other_sl.line,
422 .column = other_sl.column,
423 .span_start = other_sl.span_start,
424 .span_main = other_sl.span_main,
425 .span_end = other_sl.span_end,
426 .source_line = try wip.addString(other.nullTerminatedString(other_sl.source_line)),
427 .reference_trace_len = other_sl.reference_trace_len,
428 });
429
430 // TODO: also add the reference trace
431
432 return src_loc;
433 }
434
435 fn addExtra(wip: *Wip, extra: anytype) Allocator.Error!u32 {
436 const gpa = wip.gpa;
437 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
438 try wip.extra.ensureUnusedCapacity(gpa, fields.len);
439 return addExtraAssumeCapacity(wip, extra);
440 }
441
442 fn addExtraAssumeCapacity(wip: *Wip, extra: anytype) u32 {
443 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
444 const result = @intCast(u32, wip.extra.items.len);
445 wip.extra.items.len += fields.len;
446 setExtra(wip, result, extra);
447 return result;
448 }
449
450 fn setExtra(wip: *Wip, index: usize, extra: anytype) void {
451 const fields = @typeInfo(@TypeOf(extra)).Struct.fields;
452 var i = index;
453 inline for (fields) |field| {
454 wip.extra.items[i] = switch (field.type) {
455 u32 => @field(extra, field.name),
456 MessageIndex => @enumToInt(@field(extra, field.name)),
457 SourceLocationIndex => @enumToInt(@field(extra, field.name)),
458 else => @compileError("bad field type"),
459 };
460 i += 1;
461 }
462 }
463};
src/Compilation.zig+123-130
...@@ -2546,9 +2546,9 @@ pub fn totalErrorCount(self: *Compilation) u32 {...@@ -2546,9 +2546,9 @@ pub fn totalErrorCount(self: *Compilation) u32 {
2546pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {2546pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2547 const gpa = self.gpa;2547 const gpa = self.gpa;
25482548
2549 var bundle: ErrorBundle = undefined;2549 var bundle: ErrorBundle.Wip = undefined;
2550 try bundle.init(gpa);2550 try bundle.init(gpa);
2551 errdefer bundle.deinit(gpa);2551 defer bundle.deinit();
25522552
2553 {2553 {
2554 var it = self.failed_c_objects.iterator();2554 var it = self.failed_c_objects.iterator();
...@@ -2557,12 +2557,10 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2557,12 +2557,10 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2557 const err_msg = entry.value_ptr.*;2557 const err_msg = entry.value_ptr.*;
2558 // TODO these fields will need to be adjusted when we have proper2558 // TODO these fields will need to be adjusted when we have proper
2559 // C error reporting bubbling up.2559 // C error reporting bubbling up.
2560 try bundle.addErrorMessage(gpa, .{2560 try bundle.addRootErrorMessage(.{
2561 .msg = try bundle.printString(gpa, "unable to build C object: {s}", .{2561 .msg = try bundle.printString("unable to build C object: {s}", .{err_msg.msg}),
2562 err_msg.msg,2562 .src_loc = try bundle.addSourceLocation(.{
2563 }),2563 .src_path = try bundle.addString(c_object.src.src_path),
2564 .src_loc = try bundle.addSourceLocation(gpa, .{
2565 .src_path = try bundle.addString(gpa, c_object.src.src_path),
2566 .span_start = 0,2564 .span_start = 0,
2567 .span_main = 0,2565 .span_main = 0,
2568 .span_end = 1,2566 .span_end = 1,
...@@ -2571,49 +2569,46 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2571,49 +2569,46 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2571 .source_line = 0, // TODO2569 .source_line = 0, // TODO
2572 }),2570 }),
2573 });2571 });
2574 bundle.incrementCount(1);
2575 }2572 }
2576 }2573 }
25772574
2578 for (self.lld_errors.items) |lld_error| {2575 for (self.lld_errors.items) |lld_error| {
2579 try bundle.addErrorMessage(gpa, .{2576 const notes_len = @intCast(u32, lld_error.context_lines.len);
2580 .msg = try bundle.addString(gpa, lld_error.msg),
2581 .notes_len = @intCast(u32, lld_error.context_lines.len),
2582 });
2583 bundle.incrementCount(1);
25842577
2585 for (lld_error.context_lines) |context_line| {2578 try bundle.addRootErrorMessage(.{
2586 try bundle.addErrorMessage(gpa, .{2579 .msg = try bundle.addString(lld_error.msg),
2587 .msg = try bundle.addString(gpa, context_line),2580 .notes_len = notes_len,
2588 });2581 });
2582 const notes_start = try bundle.reserveNotes(notes_len);
2583 for (notes_start.., lld_error.context_lines) |note, context_line| {
2584 bundle.extra.items[note] = @enumToInt(bundle.addErrorMessageAssumeCapacity(.{
2585 .msg = try bundle.addString(context_line),
2586 }));
2589 }2587 }
2590 }2588 }
2591 for (self.misc_failures.values()) |*value| {2589 for (self.misc_failures.values()) |*value| {
2592 try bundle.addErrorMessage(gpa, .{2590 try bundle.addRootErrorMessage(.{
2593 .msg = try bundle.addString(gpa, value.msg),2591 .msg = try bundle.addString(value.msg),
2594 .notes_len = if (value.children) |b| b.errorMessageCount() else 0,2592 .notes_len = if (value.children) |b| b.errorMessageCount() else 0,
2595 });2593 });
2596 if (value.children) |b| try bundle.addBundle(gpa, b);2594 if (value.children) |b| try bundle.addBundle(b);
2597 bundle.incrementCount(1);
2598 }2595 }
2599 if (self.alloc_failure_occurred) {2596 if (self.alloc_failure_occurred) {
2600 try bundle.addErrorMessage(gpa, .{2597 try bundle.addRootErrorMessage(.{
2601 .msg = try bundle.addString(gpa, "memory allocation failure"),2598 .msg = try bundle.addString("memory allocation failure"),
2602 });2599 });
2603 bundle.incrementCount(1);
2604 }2600 }
2605 if (self.bin_file.options.module) |module| {2601 if (self.bin_file.options.module) |module| {
2606 {2602 {
2607 var it = module.failed_files.iterator();2603 var it = module.failed_files.iterator();
2608 while (it.next()) |entry| {2604 while (it.next()) |entry| {
2609 if (entry.value_ptr.*) |msg| {2605 if (entry.value_ptr.*) |msg| {
2610 try addModuleErrorMsg(gpa, &bundle, msg.*);2606 try addModuleErrorMsg(&bundle, msg.*);
2611 } else {2607 } else {
2612 // Must be ZIR errors. In order for ZIR errors to exist, the parsing2608 // Must be ZIR errors. Note that this may include AST errors.
2613 // must have completed successfully.2609 // addZirErrorMessages asserts that the tree is loaded.
2614 const tree = try entry.key_ptr.*.getTree(module.gpa);2610 _ = try entry.key_ptr.*.getTree(gpa);
2615 assert(tree.errors.len == 0);2611 try addZirErrorMessages(&bundle, entry.key_ptr.*);
2616 try addZirErrorMessages(gpa, &bundle, entry.key_ptr.*);
2617 }2612 }
2618 }2613 }
2619 }2614 }
...@@ -2621,7 +2616,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2621,7 +2616,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2621 var it = module.failed_embed_files.iterator();2616 var it = module.failed_embed_files.iterator();
2622 while (it.next()) |entry| {2617 while (it.next()) |entry| {
2623 const msg = entry.value_ptr.*;2618 const msg = entry.value_ptr.*;
2624 try addModuleErrorMsg(gpa, &bundle, msg.*);2619 try addModuleErrorMsg(&bundle, msg.*);
2625 }2620 }
2626 }2621 }
2627 {2622 {
...@@ -2631,21 +2626,20 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2631,21 +2626,20 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2631 // Skip errors for Decls within files that had a parse failure.2626 // Skip errors for Decls within files that had a parse failure.
2632 // We'll try again once parsing succeeds.2627 // We'll try again once parsing succeeds.
2633 if (decl.getFileScope().okToReportErrors()) {2628 if (decl.getFileScope().okToReportErrors()) {
2634 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);2629 try addModuleErrorMsg(&bundle, entry.value_ptr.*.*);
2635 if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {2630 if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
2636 try bundle.addErrorMessage(gpa, .{2631 try bundle.addRootErrorMessage(.{
2637 .msg = try bundle.addString(gpa, std.mem.span(c_error.msg)),2632 .msg = try bundle.addString(std.mem.span(c_error.msg)),
2638 .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(gpa, .{2633 .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(.{
2639 .src_path = try bundle.addString(gpa, std.mem.span(some)),2634 .src_path = try bundle.addString(std.mem.span(some)),
2640 .span_start = c_error.offset,2635 .span_start = c_error.offset,
2641 .span_main = c_error.offset,2636 .span_main = c_error.offset,
2642 .span_end = c_error.offset + 1,2637 .span_end = c_error.offset + 1,
2643 .line = c_error.line,2638 .line = c_error.line,
2644 .column = c_error.column,2639 .column = c_error.column,
2645 .source_line = if (c_error.source_line) |line| try bundle.addString(gpa, std.mem.span(line)) else 0,2640 .source_line = if (c_error.source_line) |line| try bundle.addString(std.mem.span(line)) else 0,
2646 }) else 0,2641 }) else .none,
2647 });2642 });
2648 bundle.incrementCount(1);
2649 };2643 };
2650 }2644 }
2651 }2645 }
...@@ -2657,40 +2651,39 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2657,40 +2651,39 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2657 // Skip errors for Decls within files that had a parse failure.2651 // Skip errors for Decls within files that had a parse failure.
2658 // We'll try again once parsing succeeds.2652 // We'll try again once parsing succeeds.
2659 if (decl.getFileScope().okToReportErrors()) {2653 if (decl.getFileScope().okToReportErrors()) {
2660 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);2654 try addModuleErrorMsg(&bundle, entry.value_ptr.*.*);
2661 }2655 }
2662 }2656 }
2663 }2657 }
2664 for (module.failed_exports.values()) |value| {2658 for (module.failed_exports.values()) |value| {
2665 try addModuleErrorMsg(gpa, &bundle, value.*);2659 try addModuleErrorMsg(&bundle, value.*);
2666 }2660 }
2667 }2661 }
26682662
2669 if (bundle.errorMessageCount() == 0) {2663 if (bundle.root_list.items.len == 0) {
2670 if (self.link_error_flags.no_entry_point_found) {2664 if (self.link_error_flags.no_entry_point_found) {
2671 try bundle.addErrorMessage(gpa, .{2665 try bundle.addRootErrorMessage(.{
2672 .msg = try bundle.addString(gpa, "no entry point found"),2666 .msg = try bundle.addString("no entry point found"),
2673 });2667 });
2674 bundle.incrementCount(1);
2675 }2668 }
2676 }2669 }
26772670
2678 if (self.link_error_flags.missing_libc) {2671 if (self.link_error_flags.missing_libc) {
2679 try bundle.addErrorMessage(gpa, .{2672 try bundle.addRootErrorMessage(.{
2680 .msg = try bundle.addString(gpa, "libc not available"),2673 .msg = try bundle.addString("libc not available"),
2681 .notes_len = 2,2674 .notes_len = 2,
2682 });2675 });
2683 try bundle.addErrorMessage(gpa, .{2676 const notes_start = try bundle.reserveNotes(2);
2684 .msg = try bundle.addString(gpa, "run 'zig libc -h' to learn about libc installations"),2677 bundle.extra.items[notes_start + 0] = @enumToInt(try bundle.addErrorMessage(.{
2685 });2678 .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),
2686 try bundle.addErrorMessage(gpa, .{2679 }));
2687 .msg = try bundle.addString(gpa, "run 'zig targets' to see the targets for which zig can always provide libc"),2680 bundle.extra.items[notes_start + 1] = @enumToInt(try bundle.addErrorMessage(.{
2688 });2681 .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),
2689 bundle.incrementCount(1);2682 }));
2690 }2683 }
26912684
2692 if (self.bin_file.options.module) |module| {2685 if (self.bin_file.options.module) |module| {
2693 if (bundle.errorMessageCount() == 0 and module.compile_log_decls.count() != 0) {2686 if (bundle.root_list.items.len == 0 and module.compile_log_decls.count() != 0) {
2694 const keys = module.compile_log_decls.keys();2687 const keys = module.compile_log_decls.keys();
2695 const values = module.compile_log_decls.values();2688 const values = module.compile_log_decls.values();
2696 // First one will be the error; subsequent ones will be notes.2689 // First one will be the error; subsequent ones will be notes.
...@@ -2699,9 +2692,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2699,9 +2692,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2699 const err_msg = Module.ErrorMsg{2692 const err_msg = Module.ErrorMsg{
2700 .src_loc = src_loc,2693 .src_loc = src_loc,
2701 .msg = "found compile log statement",2694 .msg = "found compile log statement",
2702 .notes = try self.gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1),2695 .notes = try gpa.alloc(Module.ErrorMsg, module.compile_log_decls.count() - 1),
2703 };2696 };
2704 defer self.gpa.free(err_msg.notes);2697 defer gpa.free(err_msg.notes);
27052698
2706 for (keys[1..], 0..) |key, i| {2699 for (keys[1..], 0..) |key, i| {
2707 const note_decl = module.declPtr(key);2700 const note_decl = module.declPtr(key);
...@@ -2711,25 +2704,26 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {...@@ -2711,25 +2704,26 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
2711 };2704 };
2712 }2705 }
27132706
2714 try addModuleErrorMsg(gpa, &bundle, err_msg);2707 try addModuleErrorMsg(&bundle, err_msg);
2715 }2708 }
2716 }2709 }
27172710
2718 assert(self.totalErrorCount() == bundle.errorMessageCount());2711 assert(self.totalErrorCount() == bundle.root_list.items.len);
27192712
2720 return bundle;2713 return bundle.toOwnedBundle();
2721}2714}
27222715
2723pub const ErrorNoteHashContext = struct {2716pub const ErrorNoteHashContext = struct {
2724 eb: *const ErrorBundle,2717 eb: *const ErrorBundle.Wip,
27252718
2726 pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 {2719 pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 {
2727 var hasher = std.hash.Wyhash.init(0);2720 var hasher = std.hash.Wyhash.init(0);
2721 const eb = ctx.eb.tmpBundle();
27282722
2729 hasher.update(ctx.eb.nullTerminatedString(key.msg));2723 hasher.update(eb.nullTerminatedString(key.msg));
2730 if (key.src_loc != 0) {2724 if (key.src_loc != .none) {
2731 const src = ctx.eb.getSourceLocation(key.src_loc);2725 const src = eb.getSourceLocation(key.src_loc);
2732 hasher.update(ctx.eb.nullTerminatedString(src.src_path));2726 hasher.update(eb.nullTerminatedString(src.src_path));
2733 std.hash.autoHash(&hasher, src.line);2727 std.hash.autoHash(&hasher, src.line);
2734 std.hash.autoHash(&hasher, src.column);2728 std.hash.autoHash(&hasher, src.column);
2735 std.hash.autoHash(&hasher, src.span_main);2729 std.hash.autoHash(&hasher, src.span_main);
...@@ -2745,17 +2739,18 @@ pub const ErrorNoteHashContext = struct {...@@ -2745,17 +2739,18 @@ pub const ErrorNoteHashContext = struct {
2745 b_index: usize,2739 b_index: usize,
2746 ) bool {2740 ) bool {
2747 _ = b_index;2741 _ = b_index;
2748 const msg_a = ctx.eb.nullTerminatedString(a.msg);2742 const eb = ctx.eb.tmpBundle();
2749 const msg_b = ctx.eb.nullTerminatedString(b.msg);2743 const msg_a = eb.nullTerminatedString(a.msg);
2744 const msg_b = eb.nullTerminatedString(b.msg);
2750 if (!std.mem.eql(u8, msg_a, msg_b)) return false;2745 if (!std.mem.eql(u8, msg_a, msg_b)) return false;
27512746
2752 if (a.src_loc == 0 and b.src_loc == 0) return true;2747 if (a.src_loc == .none and b.src_loc == .none) return true;
2753 if (a.src_loc == 0 or b.src_loc == 0) return false;2748 if (a.src_loc == .none or b.src_loc == .none) return false;
2754 const src_a = ctx.eb.getSourceLocation(a.src_loc);2749 const src_a = eb.getSourceLocation(a.src_loc);
2755 const src_b = ctx.eb.getSourceLocation(b.src_loc);2750 const src_b = eb.getSourceLocation(b.src_loc);
27562751
2757 const src_path_a = ctx.eb.nullTerminatedString(src_a.src_path);2752 const src_path_a = eb.nullTerminatedString(src_a.src_path);
2758 const src_path_b = ctx.eb.nullTerminatedString(src_b.src_path);2753 const src_path_b = eb.nullTerminatedString(src_b.src_path);
27592754
2760 return std.mem.eql(u8, src_path_a, src_path_b) and2755 return std.mem.eql(u8, src_path_a, src_path_b) and
2761 src_a.line == src_b.line and2756 src_a.line == src_b.line and
...@@ -2764,16 +2759,16 @@ pub const ErrorNoteHashContext = struct {...@@ -2764,16 +2759,16 @@ pub const ErrorNoteHashContext = struct {
2764 }2759 }
2765};2760};
27662761
2767pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Module.ErrorMsg) !void {2762pub fn addModuleErrorMsg(eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void {
2763 const gpa = eb.gpa;
2768 const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {2764 const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {
2769 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);2765 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
2770 defer gpa.free(file_path);2766 defer gpa.free(file_path);
2771 try eb.addErrorMessage(gpa, .{2767 try eb.addRootErrorMessage(.{
2772 .msg = try eb.printString(gpa, "unable to load '{s}': {s}", .{2768 .msg = try eb.printString("unable to load '{s}': {s}", .{
2773 file_path, @errorName(err),2769 file_path, @errorName(err),
2774 }),2770 }),
2775 });2771 });
2776 eb.incrementCount(1);
2777 return;2772 return;
2778 };2773 };
2779 const err_span = try module_err_msg.src_loc.span(gpa);2774 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...@@ -2788,13 +2783,13 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
2788 if (module_reference.hidden != 0) {2783 if (module_reference.hidden != 0) {
2789 try ref_traces.append(gpa, .{2784 try ref_traces.append(gpa, .{
2790 .decl_name = module_reference.hidden,2785 .decl_name = module_reference.hidden,
2791 .src_loc = 0,2786 .src_loc = .none,
2792 });2787 });
2793 break;2788 break;
2794 } else if (module_reference.decl == null) {2789 } else if (module_reference.decl == null) {
2795 try ref_traces.append(gpa, .{2790 try ref_traces.append(gpa, .{
2796 .decl_name = 0,2791 .decl_name = 0,
2797 .src_loc = 0,2792 .src_loc = .none,
2798 });2793 });
2799 break;2794 break;
2800 }2795 }
...@@ -2804,9 +2799,9 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul...@@ -2804,9 +2799,9 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
2804 const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);2799 const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
2805 defer gpa.free(rt_file_path);2800 defer gpa.free(rt_file_path);
2806 try ref_traces.append(gpa, .{2801 try ref_traces.append(gpa, .{
2807 .decl_name = try eb.addString(gpa, std.mem.sliceTo(module_reference.decl.?, 0)),2802 .decl_name = try eb.addString(std.mem.sliceTo(module_reference.decl.?, 0)),
2808 .src_loc = try eb.addSourceLocation(gpa, .{2803 .src_loc = try eb.addSourceLocation(.{
2809 .src_path = try eb.addString(gpa, rt_file_path),2804 .src_path = try eb.addString(rt_file_path),
2810 .span_start = span.start,2805 .span_start = span.start,
2811 .span_main = span.main,2806 .span_main = span.main,
2812 .span_end = span.end,2807 .span_end = span.end,
...@@ -2817,8 +2812,8 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul...@@ -2817,8 +2812,8 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
2817 });2812 });
2818 }2813 }
28192814
2820 const src_loc = try eb.addSourceLocation(gpa, .{2815 const src_loc = try eb.addSourceLocation(.{
2821 .src_path = try eb.addString(gpa, file_path),2816 .src_path = try eb.addString(file_path),
2822 .span_start = err_span.start,2817 .span_start = err_span.start,
2823 .span_main = err_span.main,2818 .span_main = err_span.main,
2824 .span_end = err_span.end,2819 .span_end = err_span.end,
...@@ -2827,12 +2822,12 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul...@@ -2827,12 +2822,12 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
2827 .source_line = if (module_err_msg.src_loc.lazy == .entire_file)2822 .source_line = if (module_err_msg.src_loc.lazy == .entire_file)
2828 02823 0
2829 else2824 else
2830 try eb.addString(gpa, err_loc.source_line),2825 try eb.addString(err_loc.source_line),
2831 .reference_trace_len = @intCast(u32, ref_traces.items.len),2826 .reference_trace_len = @intCast(u32, ref_traces.items.len),
2832 });2827 });
28332828
2834 for (ref_traces.items) |rt| {2829 for (ref_traces.items) |rt| {
2835 try eb.addReferenceTrace(gpa, rt);2830 try eb.addReferenceTrace(rt);
2836 }2831 }
28372832
2838 // De-duplicate error notes. The main use case in mind for this is2833 // 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...@@ -2848,15 +2843,15 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
2848 defer gpa.free(note_file_path);2843 defer gpa.free(note_file_path);
28492844
2850 const gop = try notes.getOrPutContext(gpa, .{2845 const gop = try notes.getOrPutContext(gpa, .{
2851 .msg = try eb.addString(gpa, module_note.msg),2846 .msg = try eb.addString(module_note.msg),
2852 .src_loc = try eb.addSourceLocation(gpa, .{2847 .src_loc = try eb.addSourceLocation(.{
2853 .src_path = try eb.addString(gpa, note_file_path),2848 .src_path = try eb.addString(note_file_path),
2854 .span_start = span.start,2849 .span_start = span.start,
2855 .span_main = span.main,2850 .span_main = span.main,
2856 .span_end = span.end,2851 .span_end = span.end,
2857 .line = @intCast(u32, loc.line),2852 .line = @intCast(u32, loc.line),
2858 .column = @intCast(u32, loc.column),2853 .column = @intCast(u32, loc.column),
2859 .source_line = if (err_loc.eql(loc)) 0 else try eb.addString(gpa, loc.source_line),2854 .source_line = if (err_loc.eql(loc)) 0 else try eb.addString(loc.source_line),
2860 }),2855 }),
2861 }, .{ .eb = eb });2856 }, .{ .eb = eb });
2862 if (gop.found_existing) {2857 if (gop.found_existing) {
...@@ -2864,24 +2859,28 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul...@@ -2864,24 +2859,28 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
2864 }2859 }
2865 }2860 }
28662861
2867 try eb.addErrorMessage(gpa, .{2862 const notes_len = @intCast(u32, notes.entries.len);
2868 .msg = try eb.addString(gpa, module_err_msg.msg),2863
2864 try eb.addRootErrorMessage(.{
2865 .msg = try eb.addString(module_err_msg.msg),
2869 .src_loc = src_loc,2866 .src_loc = src_loc,
2870 .notes_len = @intCast(u32, notes.entries.len),2867 .notes_len = notes_len,
2871 });2868 });
2872 eb.incrementCount(1);
28732869
2874 for (notes.keys()) |note| {2870 const notes_start = try eb.reserveNotes(notes_len);
2875 try eb.addErrorMessage(gpa, note);2871
2872 for (notes_start.., notes.keys()) |i, note| {
2873 eb.extra.items[i] = @enumToInt(try eb.addErrorMessage(note));
2876 }2874 }
2877}2875}
28782876
2879pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File) !void {2877pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
2880 assert(file.zir_loaded);2878 assert(file.zir_loaded);
2881 assert(file.tree_loaded);2879 assert(file.tree_loaded);
2882 assert(file.source_loaded);2880 assert(file.source_loaded);
2883 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];2881 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
2884 assert(payload_index != 0);2882 assert(payload_index != 0);
2883 const gpa = eb.gpa;
28852884
2886 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);2885 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
2887 const items_len = header.data.items_len;2886 const items_len = header.data.items_len;
...@@ -2900,14 +2899,30 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)...@@ -2900,14 +2899,30 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
2900 };2899 };
2901 const err_loc = std.zig.findLineColumn(file.source, err_span.main);2900 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
29022901
2903 var notes: []ErrorBundle.ErrorMessage = &.{};2902 {
2904 defer gpa.free(notes);2903 const msg = file.zir.nullTerminatedString(item.data.msg);
2904 const src_path = try file.fullPath(gpa);
2905 defer gpa.free(src_path);
2906 try eb.addRootErrorMessage(.{
2907 .msg = try eb.addString(msg),
2908 .src_loc = try eb.addSourceLocation(.{
2909 .src_path = try eb.addString(src_path),
2910 .span_start = err_span.start,
2911 .span_main = err_span.main,
2912 .span_end = err_span.end,
2913 .line = @intCast(u32, err_loc.line),
2914 .column = @intCast(u32, err_loc.column),
2915 .source_line = try eb.addString(err_loc.source_line),
2916 }),
2917 .notes_len = item.data.notes,
2918 });
2919 }
29052920
2906 if (item.data.notes != 0) {2921 if (item.data.notes != 0) {
2922 const notes_start = try eb.reserveNotes(item.data.notes);
2907 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);2923 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
2908 const body = file.zir.extra[block.end..][0..block.data.body_len];2924 const body = file.zir.extra[block.end..][0..block.data.body_len];
2909 notes = try gpa.alloc(ErrorBundle.ErrorMessage, body.len);2925 for (notes_start.., body) |note_i, body_elem| {
2910 for (notes, body) |*note, body_elem| {
2911 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);2926 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
2912 const msg = file.zir.nullTerminatedString(note_item.data.msg);2927 const msg = file.zir.nullTerminatedString(note_item.data.msg);
2913 const span = blk: {2928 const span = blk: {
...@@ -2923,10 +2938,10 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)...@@ -2923,10 +2938,10 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
2923 const src_path = try file.fullPath(gpa);2938 const src_path = try file.fullPath(gpa);
2924 defer gpa.free(src_path);2939 defer gpa.free(src_path);
29252940
2926 note.* = .{2941 eb.extra.items[note_i] = @enumToInt(try eb.addErrorMessage(.{
2927 .msg = try eb.addString(gpa, msg),2942 .msg = try eb.addString(msg),
2928 .src_loc = try eb.addSourceLocation(gpa, .{2943 .src_loc = try eb.addSourceLocation(.{
2929 .src_path = try eb.addString(gpa, src_path),2944 .src_path = try eb.addString(src_path),
2930 .span_start = span.start,2945 .span_start = span.start,
2931 .span_main = span.main,2946 .span_main = span.main,
2932 .span_end = span.end,2947 .span_end = span.end,
...@@ -2935,35 +2950,13 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)...@@ -2935,35 +2950,13 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
2935 .source_line = if (loc.eql(err_loc))2950 .source_line = if (loc.eql(err_loc))
2936 02951 0
2937 else2952 else
2938 try eb.addString(gpa, loc.source_line),2953 try eb.addString(loc.source_line),
2939 }),2954 }),
2940 .notes_len = 0, // TODO rework this function to be recursive2955 .notes_len = 0, // TODO rework this function to be recursive
2941 };2956 }));
2942 }2957 }
2943 }2958 }
2944
2945 const msg = file.zir.nullTerminatedString(item.data.msg);
2946 const src_path = try file.fullPath(gpa);
2947 defer gpa.free(src_path);
2948 try eb.addErrorMessage(gpa, .{
2949 .msg = try eb.addString(gpa, msg),
2950 .src_loc = try eb.addSourceLocation(gpa, .{
2951 .src_path = try eb.addString(gpa, src_path),
2952 .span_start = err_span.start,
2953 .span_main = err_span.main,
2954 .span_end = err_span.end,
2955 .line = @intCast(u32, err_loc.line),
2956 .column = @intCast(u32, err_loc.column),
2957 .source_line = try eb.addString(gpa, err_loc.source_line),
2958 }),
2959 .notes_len = @intCast(u32, notes.len),
2960 });
2961
2962 for (notes) |note| {
2963 try eb.addErrorMessage(gpa, note);
2964 }
2965 }2959 }
2966 eb.incrementCount(items_len);
2967}2960}
29682961
2969pub fn getCompileLogOutput(self: *Compilation) []const u8 {2962pub fn getCompileLogOutput(self: *Compilation) []const u8 {
src/Package.zig+17-19
...@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(...@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(
225 dependencies_source: *std.ArrayList(u8),225 dependencies_source: *std.ArrayList(u8),
226 build_roots_source: *std.ArrayList(u8),226 build_roots_source: *std.ArrayList(u8),
227 name_prefix: []const u8,227 name_prefix: []const u8,
228 error_bundle: *std.zig.ErrorBundle,228 error_bundle: *std.zig.ErrorBundle.Wip,
229 all_modules: *AllModules,229 all_modules: *AllModules,
230) !void {230) !void {
231 const max_bytes = 10 * 1024 * 1024;231 const max_bytes = 10 * 1024 * 1024;
...@@ -260,13 +260,12 @@ pub fn fetchAndAddDependencies(...@@ -260,13 +260,12 @@ pub fn fetchAndAddDependencies(
260 if (manifest.errors.len > 0) {260 if (manifest.errors.len > 0) {
261 const file_path = try directory.join(arena, &.{Manifest.basename});261 const file_path = try directory.join(arena, &.{Manifest.basename});
262 for (manifest.errors) |msg| {262 for (manifest.errors) |msg| {
263 try Report.addErrorMessage(gpa, ast, file_path, error_bundle, 0, msg);263 try Report.addErrorMessage(ast, file_path, error_bundle, 0, msg);
264 }264 }
265 return error.PackageFetchFailed;265 return error.PackageFetchFailed;
266 }266 }
267267
268 const report: Report = .{268 const report: Report = .{
269 .gpa = gpa,
270 .ast = &ast,269 .ast = &ast,
271 .directory = directory,270 .directory = directory,
272 .error_bundle = error_bundle,271 .error_bundle = error_bundle,
...@@ -343,10 +342,9 @@ pub fn createFilePkg(...@@ -343,10 +342,9 @@ pub fn createFilePkg(
343}342}
344343
345const Report = struct {344const Report = struct {
346 gpa: Allocator,
347 ast: *const std.zig.Ast,345 ast: *const std.zig.Ast,
348 directory: Compilation.Directory,346 directory: Compilation.Directory,
349 error_bundle: *std.zig.ErrorBundle,347 error_bundle: *std.zig.ErrorBundle.Wip,
350348
351 fn fail(349 fn fail(
352 report: Report,350 report: Report,
...@@ -354,7 +352,7 @@ const Report = struct {...@@ -354,7 +352,7 @@ const Report = struct {
354 comptime fmt_string: []const u8,352 comptime fmt_string: []const u8,
355 fmt_args: anytype,353 fmt_args: anytype,
356 ) error{ PackageFetchFailed, OutOfMemory } {354 ) error{ PackageFetchFailed, OutOfMemory } {
357 const gpa = report.gpa;355 const gpa = report.error_bundle.gpa;
358356
359 const file_path = try report.directory.join(gpa, &.{Manifest.basename});357 const file_path = try report.directory.join(gpa, &.{Manifest.basename});
360 defer gpa.free(file_path);358 defer gpa.free(file_path);
...@@ -362,7 +360,7 @@ const Report = struct {...@@ -362,7 +360,7 @@ const Report = struct {
362 const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);360 const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);
363 defer gpa.free(msg);361 defer gpa.free(msg);
364362
365 try addErrorMessage(report.gpa, report.ast.*, file_path, report.error_bundle, 0, .{363 try addErrorMessage(report.ast.*, file_path, report.error_bundle, 0, .{
366 .tok = tok,364 .tok = tok,
367 .off = 0,365 .off = 0,
368 .msg = msg,366 .msg = msg,
...@@ -372,30 +370,28 @@ const Report = struct {...@@ -372,30 +370,28 @@ const Report = struct {
372 }370 }
373371
374 fn addErrorMessage(372 fn addErrorMessage(
375 gpa: Allocator,
376 ast: std.zig.Ast,373 ast: std.zig.Ast,
377 file_path: []const u8,374 file_path: []const u8,
378 eb: *std.zig.ErrorBundle,375 eb: *std.zig.ErrorBundle.Wip,
379 notes_len: u32,376 notes_len: u32,
380 msg: Manifest.ErrorMessage,377 msg: Manifest.ErrorMessage,
381 ) error{OutOfMemory}!void {378 ) error{OutOfMemory}!void {
382 const token_starts = ast.tokens.items(.start);379 const token_starts = ast.tokens.items(.start);
383 const start_loc = ast.tokenLocation(0, msg.tok);380 const start_loc = ast.tokenLocation(0, msg.tok);
384381
385 try eb.addErrorMessage(gpa, .{382 try eb.addRootErrorMessage(.{
386 .msg = try eb.addString(gpa, msg.msg),383 .msg = try eb.addString(msg.msg),
387 .src_loc = try eb.addSourceLocation(gpa, .{384 .src_loc = try eb.addSourceLocation(.{
388 .src_path = try eb.addString(gpa, file_path),385 .src_path = try eb.addString(file_path),
389 .span_start = token_starts[msg.tok],386 .span_start = token_starts[msg.tok],
390 .span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),387 .span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
391 .span_main = token_starts[msg.tok] + msg.off,388 .span_main = token_starts[msg.tok] + msg.off,
392 .line = @intCast(u32, start_loc.line),389 .line = @intCast(u32, start_loc.line),
393 .column = @intCast(u32, start_loc.column),390 .column = @intCast(u32, start_loc.column),
394 .source_line = try eb.addString(gpa, ast.source[start_loc.line_start..start_loc.line_end]),391 .source_line = try eb.addString(ast.source[start_loc.line_start..start_loc.line_end]),
395 }),392 }),
396 .notes_len = notes_len,393 .notes_len = notes_len,
397 });394 });
398 eb.incrementCount(1);
399 }395 }
400};396};
401397
...@@ -526,14 +522,16 @@ fn fetchAndUnpack(...@@ -526,14 +522,16 @@ fn fetchAndUnpack(
526 defer gpa.free(file_path);522 defer gpa.free(file_path);
527523
528 const eb = report.error_bundle;524 const eb = report.error_bundle;
529 try Report.addErrorMessage(gpa, report.ast.*, file_path, eb, 1, .{525 const notes_len = 1;
526 try Report.addErrorMessage(report.ast.*, file_path, eb, notes_len, .{
530 .tok = dep.url_tok,527 .tok = dep.url_tok,
531 .off = 0,528 .off = 0,
532 .msg = "url field is missing corresponding hash field",529 .msg = "url field is missing corresponding hash field",
533 });530 });
534 try eb.addErrorMessage(gpa, .{531 const notes_start = try eb.reserveNotes(notes_len);
535 .msg = try eb.printString(gpa, "expected .hash = \"{s}\",", .{&actual_hex}),532 eb.extra.items[notes_start] = @enumToInt(try eb.addErrorMessage(.{
536 });533 .msg = try eb.printString("expected .hash = \"{s}\",", .{&actual_hex}),
534 }));
537 return error.PackageFetchFailed;535 return error.PackageFetchFailed;
538 }536 }
539537
src/Sema.zig+5-4
...@@ -2215,11 +2215,12 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {...@@ -2215,11 +2215,12 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
22152215
2216 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {2216 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
2217 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;2217 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
2218 var errors: std.zig.ErrorBundle = undefined;2218 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
2219 errors.init(gpa) catch unreachable;2219 wip_errors.init(gpa) catch unreachable;
2220 Compilation.addModuleErrorMsg(gpa, &errors, err_msg.*) catch unreachable;2220 Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable;
2221 std.debug.print("compile error during Sema:\n", .{});2221 std.debug.print("compile error during Sema:\n", .{});
2222 errors.renderToStdErr(.no_color);2222 var error_bundle = wip_errors.toOwnedBundle() catch unreachable;
2223 error_bundle.renderToStdErr(.no_color);
2223 crash_report.compilerPanic("unexpected compile error occurred", null, null);2224 crash_report.compilerPanic("unexpected compile error occurred", null, null);
2224 }2225 }
22252226
src/main.zig+50-36
...@@ -4436,9 +4436,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4436,9 +4436,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4436 var all_modules: Package.AllModules = .{};4436 var all_modules: Package.AllModules = .{};
4437 defer all_modules.deinit(gpa);4437 defer all_modules.deinit(gpa);
44384438
4439 var errors: std.zig.ErrorBundle = undefined;4439 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4440 try errors.init(gpa);4440 try wip_errors.init(gpa);
4441 defer errors.deinit(gpa);4441 defer wip_errors.deinit();
44424442
4443 // Here we borrow main package's table and will replace it with a fresh4443 // Here we borrow main package's table and will replace it with a fresh
4444 // one after this process completes.4444 // one after this process completes.
...@@ -4453,15 +4453,17 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi...@@ -4453,15 +4453,17 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
4453 &dependencies_source,4453 &dependencies_source,
4454 &build_roots_source,4454 &build_roots_source,
4455 "",4455 "",
4456 &errors,4456 &wip_errors,
4457 &all_modules,4457 &all_modules,
4458 );4458 );
4459 if (errors.errorMessageCount() > 0) {4459 if (wip_errors.root_list.items.len > 0) {
4460 const ttyconf: std.debug.TTY.Config = switch (color) {4460 const ttyconf: std.debug.TTY.Config = switch (color) {
4461 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),4461 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4462 .on => .escape_codes,4462 .on => .escape_codes,
4463 .off => .no_color,4463 .off => .no_color,
4464 };4464 };
4465 var errors = try wip_errors.toOwnedBundle();
4466 defer errors.deinit(gpa);
4465 errors.renderToStdErr(ttyconf);4467 errors.renderToStdErr(ttyconf);
4466 process.exit(1);4468 process.exit(1);
4467 }4469 }
...@@ -4721,16 +4723,18 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void...@@ -4721,16 +4723,18 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
4721 defer file.zir.deinit(gpa);4723 defer file.zir.deinit(gpa);
47224724
4723 if (file.zir.hasCompileErrors()) {4725 if (file.zir.hasCompileErrors()) {
4724 var errors: std.zig.ErrorBundle = undefined;4726 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4725 try errors.init(gpa);4727 try wip_errors.init(gpa);
4726 defer errors.deinit(gpa);4728 defer wip_errors.deinit();
4727 try Compilation.addZirErrorMessages(gpa, &errors, &file);4729 try Compilation.addZirErrorMessages(&wip_errors, &file);
4728 const ttyconf: std.debug.TTY.Config = switch (color) {4730 const ttyconf: std.debug.TTY.Config = switch (color) {
4729 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),4731 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4730 .on => .escape_codes,4732 .on => .escape_codes,
4731 .off => .no_color,4733 .off => .no_color,
4732 };4734 };
4733 errors.renderToStdErr(ttyconf);4735 var error_bundle = try wip_errors.toOwnedBundle();
4736 defer error_bundle.deinit(gpa);
4737 error_bundle.renderToStdErr(ttyconf);
4734 has_ast_error = true;4738 has_ast_error = true;
4735 }4739 }
4736 }4740 }
...@@ -4930,16 +4934,18 @@ fn fmtPathFile(...@@ -4930,16 +4934,18 @@ fn fmtPathFile(
4930 defer file.zir.deinit(gpa);4934 defer file.zir.deinit(gpa);
49314935
4932 if (file.zir.hasCompileErrors()) {4936 if (file.zir.hasCompileErrors()) {
4933 var errors: std.zig.ErrorBundle = undefined;4937 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4934 try errors.init(gpa);4938 try wip_errors.init(gpa);
4935 defer errors.deinit(gpa);4939 defer wip_errors.deinit();
4936 try Compilation.addZirErrorMessages(gpa, &errors, &file);4940 try Compilation.addZirErrorMessages(&wip_errors, &file);
4937 const ttyconf: std.debug.TTY.Config = switch (fmt.color) {4941 const ttyconf: std.debug.TTY.Config = switch (fmt.color) {
4938 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),4942 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4939 .on => .escape_codes,4943 .on => .escape_codes,
4940 .off => .no_color,4944 .off => .no_color,
4941 };4945 };
4942 errors.renderToStdErr(ttyconf);4946 var error_bundle = try wip_errors.toOwnedBundle();
4947 defer error_bundle.deinit(gpa);
4948 error_bundle.renderToStdErr(ttyconf);
4943 fmt.any_error = true;4949 fmt.any_error = true;
4944 }4950 }
4945 }4951 }
...@@ -4968,17 +4974,19 @@ fn fmtPathFile(...@@ -4968,17 +4974,19 @@ fn fmtPathFile(
4968}4974}
49694975
4970fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {4976fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
4971 var error_bundle: std.zig.ErrorBundle = undefined;4977 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4972 try error_bundle.init(gpa);4978 try wip_errors.init(gpa);
4973 defer error_bundle.deinit(gpa);4979 defer wip_errors.deinit();
49744980
4975 try putAstErrorsIntoBundle(gpa, tree, path, &error_bundle);4981 try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
49764982
4977 const ttyconf: std.debug.TTY.Config = switch (color) {4983 const ttyconf: std.debug.TTY.Config = switch (color) {
4978 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),4984 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
4979 .on => .escape_codes,4985 .on => .escape_codes,
4980 .off => .no_color,4986 .off => .no_color,
4981 };4987 };
4988 var error_bundle = try wip_errors.toOwnedBundle();
4989 defer error_bundle.deinit(gpa);
4982 error_bundle.renderToStdErr(ttyconf);4990 error_bundle.renderToStdErr(ttyconf);
4983}4991}
49844992
...@@ -4986,7 +4994,7 @@ pub fn putAstErrorsIntoBundle(...@@ -4986,7 +4994,7 @@ pub fn putAstErrorsIntoBundle(
4986 gpa: Allocator,4994 gpa: Allocator,
4987 tree: Ast,4995 tree: Ast,
4988 path: []const u8,4996 path: []const u8,
4989 error_bundle: *std.zig.ErrorBundle,4997 wip_errors: *std.zig.ErrorBundle.Wip,
4990) !void {4998) !void {
4991 var file: Module.File = .{4999 var file: Module.File = .{
4992 .status = .never_loaded,5000 .status = .never_loaded,
...@@ -5013,7 +5021,7 @@ pub fn putAstErrorsIntoBundle(...@@ -5013,7 +5021,7 @@ pub fn putAstErrorsIntoBundle(
5013 file.zir_loaded = true;5021 file.zir_loaded = true;
5014 defer file.zir.deinit(gpa);5022 defer file.zir.deinit(gpa);
50155023
5016 try Compilation.addZirErrorMessages(gpa, error_bundle, &file);5024 try Compilation.addZirErrorMessages(wip_errors, &file);
5017}5025}
50185026
5019pub const info_zen =5027pub const info_zen =
...@@ -5595,16 +5603,18 @@ pub fn cmdAstCheck(...@@ -5595,16 +5603,18 @@ pub fn cmdAstCheck(
5595 defer file.zir.deinit(gpa);5603 defer file.zir.deinit(gpa);
55965604
5597 if (file.zir.hasCompileErrors()) {5605 if (file.zir.hasCompileErrors()) {
5598 var errors: std.zig.ErrorBundle = undefined;5606 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5599 try errors.init(gpa);5607 try wip_errors.init(gpa);
5600 defer errors.deinit(gpa);5608 defer wip_errors.deinit();
5601 try Compilation.addZirErrorMessages(gpa, &errors, &file);5609 try Compilation.addZirErrorMessages(&wip_errors, &file);
5602 const ttyconf: std.debug.TTY.Config = switch (color) {5610 const ttyconf: std.debug.TTY.Config = switch (color) {
5603 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),5611 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
5604 .on => .escape_codes,5612 .on => .escape_codes,
5605 .off => .no_color,5613 .off => .no_color,
5606 };5614 };
5607 errors.renderToStdErr(ttyconf);5615 var error_bundle = try wip_errors.toOwnedBundle();
5616 defer error_bundle.deinit(gpa);
5617 error_bundle.renderToStdErr(ttyconf);
5608 process.exit(1);5618 process.exit(1);
5609 }5619 }
56105620
...@@ -5719,12 +5729,14 @@ pub fn cmdChangelist(...@@ -5719,12 +5729,14 @@ pub fn cmdChangelist(
5719 defer file.zir.deinit(gpa);5729 defer file.zir.deinit(gpa);
57205730
5721 if (file.zir.hasCompileErrors()) {5731 if (file.zir.hasCompileErrors()) {
5722 var errors: std.zig.ErrorBundle = undefined;5732 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5723 try errors.init(gpa);5733 try wip_errors.init(gpa);
5724 defer errors.deinit(gpa);5734 defer wip_errors.deinit();
5725 try Compilation.addZirErrorMessages(gpa, &errors, &file);5735 try Compilation.addZirErrorMessages(&wip_errors, &file);
5726 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());5736 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
5727 errors.renderToStdErr(ttyconf);5737 var error_bundle = try wip_errors.toOwnedBundle();
5738 defer error_bundle.deinit(gpa);
5739 error_bundle.renderToStdErr(ttyconf);
5728 process.exit(1);5740 process.exit(1);
5729 }5741 }
57305742
...@@ -5758,12 +5770,14 @@ pub fn cmdChangelist(...@@ -5758,12 +5770,14 @@ pub fn cmdChangelist(
5758 file.zir_loaded = true;5770 file.zir_loaded = true;
57595771
5760 if (file.zir.hasCompileErrors()) {5772 if (file.zir.hasCompileErrors()) {
5761 var errors: std.zig.ErrorBundle = undefined;5773 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5762 try errors.init(gpa);5774 try wip_errors.init(gpa);
5763 defer errors.deinit(gpa);5775 defer wip_errors.deinit();
5764 try Compilation.addZirErrorMessages(gpa, &errors, &file);5776 try Compilation.addZirErrorMessages(&wip_errors, &file);
5765 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());5777 const ttyconf = std.debug.detectTTYConfig(std.io.getStdErr());
5766 errors.renderToStdErr(ttyconf);5778 var error_bundle = try wip_errors.toOwnedBundle();
5779 defer error_bundle.deinit(gpa);
5780 error_bundle.renderToStdErr(ttyconf);
5767 process.exit(1);5781 process.exit(1);
5768 }5782 }
57695783
src/test.zig+3-18
...@@ -1242,7 +1242,7 @@ pub const TestContext = struct {...@@ -1242,7 +1242,7 @@ pub const TestContext = struct {
1242 defer self.gpa.free(zig_lib_directory.path.?);1242 defer self.gpa.free(zig_lib_directory.path.?);
12431243
1244 var aux_thread_pool: ThreadPool = undefined;1244 var aux_thread_pool: ThreadPool = undefined;
1245 try aux_thread_pool.init(self.gpa);1245 try aux_thread_pool.init(.{ .allocator = self.gpa });
1246 defer aux_thread_pool.deinit();1246 defer aux_thread_pool.deinit();
12471247
1248 // Use the same global cache dir for all the tests, such that we for example don't have to1248 // 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 {...@@ -1614,23 +1614,8 @@ pub const TestContext = struct {
1614 if (update.case != .Error) {1614 if (update.case != .Error) {
1615 var all_errors = try comp.getAllErrorsAlloc();1615 var all_errors = try comp.getAllErrorsAlloc();
1616 defer all_errors.deinit(allocator);1616 defer all_errors.deinit(allocator);
1617 if (all_errors.list.len != 0) {1617 if (all_errors.errorMessageCount() > 0) {
1618 print(1618 all_errors.renderToStdErr(std.debug.detectTTYConfig(std.io.getStdErr()));
1619 "\nCase '{s}': unexpected errors at update_index={d}:\n{s}\n",
1620 .{ case.name, update_index, hr },
1621 );
1622 for (all_errors.list) |err_msg| {
1623 switch (err_msg) {
1624 .src => |src| {
1625 print("{s}:{d}:{d}: error: {s}\n{s}\n", .{
1626 src.src_path, src.line + 1, src.column + 1, src.msg, hr,
1627 });
1628 },
1629 .plain => |plain| {
1630 print("error: {s}\n{s}\n", .{ plain.msg, hr });
1631 },
1632 }
1633 }
1634 // TODO print generated C code1619 // TODO print generated C code
1635 return error.UnexpectedCompileErrors;1620 return error.UnexpectedCompileErrors;
1636 }1621 }