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 @@
33//! is used to collect all the errors from the various places into one
44//! convenient place for API users to consume.
55
6string_bytes: std.ArrayListUnmanaged(u8),
7/// The first thing in this array is a ErrorMessageListIndex.
8extra: std.ArrayListUnmanaged(u32),
6string_bytes: []const u8,
7/// The first thing in this array is an `ErrorMessageList`.
8extra: []const u32,
99
1010// An index into `extra` pointing at an `ErrorMessage`.
1111pub const MessageIndex = enum(u32) {
1212 _,
1313};
1414
15/// After the header is:
16/// * string_bytes
17/// * extra (little endian)
18pub const Header = struct {
19 string_bytes_len: u32,
20 extra_len: u32,
15// An index into `extra` pointing at an `SourceLocation`.
16pub const SourceLocationIndex = enum(u32) {
17 none = 0,
18 _,
2119};
2220
23/// Trailing: ErrorMessage for each len
21/// There will be a MessageIndex for each len at start.
2422pub const ErrorMessageList = struct {
2523 len: u32,
2624 start: u32,
......@@ -46,14 +44,13 @@ pub const SourceLocation = struct {
4644};
4745
4846/// Trailing:
49/// * ErrorMessage for each notes_len.
47/// * MessageIndex for each notes_len.
5048pub const ErrorMessage = struct {
5149 /// null terminated string index
5250 msg: u32,
5351 /// Usually one, but incremented for redundant messages.
5452 count: u32 = 1,
55 /// 0 or the index into extra of a SourceLocation
56 src_loc: u32 = 0,
53 src_loc: SourceLocationIndex = .none,
5754 notes_len: u32 = 0,
5855};
5956
......@@ -65,170 +62,41 @@ pub const ReferenceTrace = struct {
6562 decl_name: u32,
6663 /// Index into extra of a SourceLocation
6764 /// If this is 0, this is the sentinel ReferenceTrace element.
68 src_loc: u32,
65 src_loc: SourceLocationIndex,
6966};
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
8668pub fn deinit(eb: *ErrorBundle, gpa: Allocator) void {
87 eb.string_bytes.deinit(gpa);
88 eb.extra.deinit(gpa);
69 gpa.free(eb.string_bytes);
70 gpa.free(eb.extra);
8971 eb.* = undefined;
9072}
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
20574pub fn errorMessageCount(eb: ErrorBundle) u32 {
206 return eb.extra.items[0];
207}
208
209pub fn setErrorMessageCount(eb: *ErrorBundle, count: u32) void {
210 eb.extra.items[0] = count;
75 return eb.getErrorMessageList().len;
21176}
21277
213pub fn incrementCount(eb: *ErrorBundle, delta: u32) void {
214 eb.extra.items[0] += delta;
78pub fn getErrorMessageList(eb: ErrorBundle) ErrorMessageList {
79 return eb.extraData(ErrorMessageList, 0).data;
21580}
21681
217pub fn getStartIndex(eb: ErrorBundle) u32 {
218 return eb.extra.items[1];
219}
220
221pub fn setStartIndex(eb: *ErrorBundle, index: u32) void {
222 eb.extra.items[1] = index;
82pub fn getMessages(eb: ErrorBundle) []const MessageIndex {
83 const list = eb.getErrorMessageList();
84 return @ptrCast([]const MessageIndex, eb.extra[list.start..][0..list.len]);
22385}
22486
22587pub fn getErrorMessage(eb: ErrorBundle, index: MessageIndex) ErrorMessage {
22688 return eb.extraData(ErrorMessage, @enumToInt(index)).data;
22789}
22890
229pub fn getSourceLocation(eb: ErrorBundle, index: u32) SourceLocation {
230 assert(index != 0);
231 return eb.extraData(SourceLocation, index).data;
91pub fn getSourceLocation(eb: ErrorBundle, index: SourceLocationIndex) SourceLocation {
92 assert(index != .none);
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]);
232100}
233101
234102/// 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,
239107 var result: T = undefined;
240108 inline for (fields) |field| {
241109 @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]),
243113 else => @compileError("bad field type"),
244114 };
245115 i += 1;
......@@ -252,7 +122,7 @@ fn extraData(eb: ErrorBundle, comptime T: type, index: usize) struct { data: T,
252122
253123/// Given an index into `string_bytes` returns the null-terminated string found there.
254124pub fn nullTerminatedString(eb: ErrorBundle, index: usize) [:0]const u8 {
255 const string_bytes = eb.string_bytes.items;
125 const string_bytes = eb.string_bytes;
256126 var end: usize = index;
257127 while (string_bytes[end] != 0) {
258128 end += 1;
......@@ -272,28 +142,25 @@ pub fn renderToWriter(
272142 ttyconf: std.debug.TTY.Config,
273143 writer: anytype,
274144) anyerror!void {
275 const list = eb.extraData(ErrorMessageList, 0).data;
276 var index: usize = list.start;
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);
145 for (eb.getMessages()) |err_msg| {
146 try renderErrorMessageToWriter(eb, err_msg, ttyconf, writer, "error", .Red, 0);
280147 }
281148}
282149
283150fn renderErrorMessageToWriter(
284151 eb: ErrorBundle,
285 err_msg: ErrorMessage,
286 end_index: usize,
152 err_msg_index: MessageIndex,
287153 ttyconf: std.debug.TTY.Config,
288154 stderr: anytype,
289155 kind: []const u8,
290156 color: std.debug.TTY.Color,
291157 indent: usize,
292) anyerror!usize {
158) anyerror!void {
293159 var counting_writer = std.io.countingWriter(stderr);
294160 const counting_stderr = counting_writer.writer();
295 if (err_msg.src_loc != 0) {
296 const src = eb.extraData(SourceLocation, err_msg.src_loc);
161 const err_msg = eb.getErrorMessage(err_msg_index);
162 if (err_msg.src_loc != .none) {
163 const src = eb.extraData(SourceLocation, @enumToInt(err_msg.src_loc));
297164 try counting_stderr.writeByteNTimes(' ', indent);
298165 try ttyconf.setColor(stderr, .Bold);
299166 try counting_stderr.print("{s}:{d}:{d}: ", .{
......@@ -337,10 +204,8 @@ fn renderErrorMessageToWriter(
337204 try stderr.writeByte('\n');
338205 try ttyconf.setColor(stderr, .Reset);
339206 }
340 var index = end_index;
341 for (0..err_msg.notes_len) |_| {
342 const note = eb.extraData(ErrorMessage, index);
343 index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent);
207 for (eb.getNotes(err_msg_index)) |note| {
208 try renderErrorMessageToWriter(eb, note, ttyconf, stderr, "note", .Cyan, indent);
344209 }
345210 if (src.data.reference_trace_len > 0) {
346211 try ttyconf.setColor(stderr, .Reset);
......@@ -350,7 +215,7 @@ fn renderErrorMessageToWriter(
350215 for (0..src.data.reference_trace_len) |_| {
351216 const ref_trace = eb.extraData(ReferenceTrace, ref_index);
352217 ref_index = ref_trace.end;
353 if (ref_trace.data.src_loc != 0) {
218 if (ref_trace.data.src_loc != .none) {
354219 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
355220 try stderr.print(" {s}: {s}:{d}:{d}\n", .{
356221 eb.nullTerminatedString(ref_trace.data.decl_name),
......@@ -374,7 +239,6 @@ fn renderErrorMessageToWriter(
374239 try stderr.writeByte('\n');
375240 try ttyconf.setColor(stderr, .Reset);
376241 }
377 return index;
378242 } else {
379243 try ttyconf.setColor(stderr, color);
380244 try stderr.writeByteNTimes(' ', indent);
......@@ -390,12 +254,9 @@ fn renderErrorMessageToWriter(
390254 try stderr.print(" ({d} times)\n", .{err_msg.count});
391255 }
392256 try ttyconf.setColor(stderr, .Reset);
393 var index = end_index;
394 for (0..err_msg.notes_len) |_| {
395 const note = eb.extraData(ErrorMessage, index);
396 index = try renderErrorMessageToWriter(eb, note.data, note.end, ttyconf, stderr, "note", .Cyan, indent + 4);
257 for (eb.getNotes(err_msg_index)) |note| {
258 try renderErrorMessageToWriter(eb, note, ttyconf, stderr, "note", .Cyan, indent + 4);
397259 }
398 return index;
399260 }
400261}
401262
......@@ -417,3 +278,186 @@ const std = @import("std");
417278const ErrorBundle = @This();
418279const Allocator = std.mem.Allocator;
419280const 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 {
25462546pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
25472547 const gpa = self.gpa;
25482548
2549 var bundle: ErrorBundle = undefined;
2549 var bundle: ErrorBundle.Wip = undefined;
25502550 try bundle.init(gpa);
2551 errdefer bundle.deinit(gpa);
2551 defer bundle.deinit();
25522552
25532553 {
25542554 var it = self.failed_c_objects.iterator();
......@@ -2557,12 +2557,10 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
25572557 const err_msg = entry.value_ptr.*;
25582558 // TODO these fields will need to be adjusted when we have proper
25592559 // C error reporting bubbling up.
2560 try bundle.addErrorMessage(gpa, .{
2561 .msg = try bundle.printString(gpa, "unable to build C object: {s}", .{
2562 err_msg.msg,
2563 }),
2564 .src_loc = try bundle.addSourceLocation(gpa, .{
2565 .src_path = try bundle.addString(gpa, c_object.src.src_path),
2560 try bundle.addRootErrorMessage(.{
2561 .msg = try bundle.printString("unable to build C object: {s}", .{err_msg.msg}),
2562 .src_loc = try bundle.addSourceLocation(.{
2563 .src_path = try bundle.addString(c_object.src.src_path),
25662564 .span_start = 0,
25672565 .span_main = 0,
25682566 .span_end = 1,
......@@ -2571,49 +2569,46 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
25712569 .source_line = 0, // TODO
25722570 }),
25732571 });
2574 bundle.incrementCount(1);
25752572 }
25762573 }
25772574
25782575 for (self.lld_errors.items) |lld_error| {
2579 try bundle.addErrorMessage(gpa, .{
2580 .msg = try bundle.addString(gpa, lld_error.msg),
2581 .notes_len = @intCast(u32, lld_error.context_lines.len),
2582 });
2583 bundle.incrementCount(1);
2576 const notes_len = @intCast(u32, lld_error.context_lines.len);
25842577
2585 for (lld_error.context_lines) |context_line| {
2586 try bundle.addErrorMessage(gpa, .{
2587 .msg = try bundle.addString(gpa, context_line),
2588 });
2578 try bundle.addRootErrorMessage(.{
2579 .msg = try bundle.addString(lld_error.msg),
2580 .notes_len = notes_len,
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 }));
25892587 }
25902588 }
25912589 for (self.misc_failures.values()) |*value| {
2592 try bundle.addErrorMessage(gpa, .{
2593 .msg = try bundle.addString(gpa, value.msg),
2590 try bundle.addRootErrorMessage(.{
2591 .msg = try bundle.addString(value.msg),
25942592 .notes_len = if (value.children) |b| b.errorMessageCount() else 0,
25952593 });
2596 if (value.children) |b| try bundle.addBundle(gpa, b);
2597 bundle.incrementCount(1);
2594 if (value.children) |b| try bundle.addBundle(b);
25982595 }
25992596 if (self.alloc_failure_occurred) {
2600 try bundle.addErrorMessage(gpa, .{
2601 .msg = try bundle.addString(gpa, "memory allocation failure"),
2597 try bundle.addRootErrorMessage(.{
2598 .msg = try bundle.addString("memory allocation failure"),
26022599 });
2603 bundle.incrementCount(1);
26042600 }
26052601 if (self.bin_file.options.module) |module| {
26062602 {
26072603 var it = module.failed_files.iterator();
26082604 while (it.next()) |entry| {
26092605 if (entry.value_ptr.*) |msg| {
2610 try addModuleErrorMsg(gpa, &bundle, msg.*);
2606 try addModuleErrorMsg(&bundle, msg.*);
26112607 } else {
2612 // Must be ZIR errors. In order for ZIR errors to exist, the parsing
2613 // must have completed successfully.
2614 const tree = try entry.key_ptr.*.getTree(module.gpa);
2615 assert(tree.errors.len == 0);
2616 try addZirErrorMessages(gpa, &bundle, entry.key_ptr.*);
2608 // Must be ZIR errors. Note that this may include AST errors.
2609 // addZirErrorMessages asserts that the tree is loaded.
2610 _ = try entry.key_ptr.*.getTree(gpa);
2611 try addZirErrorMessages(&bundle, entry.key_ptr.*);
26172612 }
26182613 }
26192614 }
......@@ -2621,7 +2616,7 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
26212616 var it = module.failed_embed_files.iterator();
26222617 while (it.next()) |entry| {
26232618 const msg = entry.value_ptr.*;
2624 try addModuleErrorMsg(gpa, &bundle, msg.*);
2619 try addModuleErrorMsg(&bundle, msg.*);
26252620 }
26262621 }
26272622 {
......@@ -2631,21 +2626,20 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
26312626 // Skip errors for Decls within files that had a parse failure.
26322627 // We'll try again once parsing succeeds.
26332628 if (decl.getFileScope().okToReportErrors()) {
2634 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
2629 try addModuleErrorMsg(&bundle, entry.value_ptr.*.*);
26352630 if (module.cimport_errors.get(entry.key_ptr.*)) |cimport_errors| for (cimport_errors) |c_error| {
2636 try bundle.addErrorMessage(gpa, .{
2637 .msg = try bundle.addString(gpa, std.mem.span(c_error.msg)),
2638 .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(gpa, .{
2639 .src_path = try bundle.addString(gpa, std.mem.span(some)),
2631 try bundle.addRootErrorMessage(.{
2632 .msg = try bundle.addString(std.mem.span(c_error.msg)),
2633 .src_loc = if (c_error.path) |some| try bundle.addSourceLocation(.{
2634 .src_path = try bundle.addString(std.mem.span(some)),
26402635 .span_start = c_error.offset,
26412636 .span_main = c_error.offset,
26422637 .span_end = c_error.offset + 1,
26432638 .line = c_error.line,
26442639 .column = c_error.column,
2645 .source_line = if (c_error.source_line) |line| try bundle.addString(gpa, std.mem.span(line)) else 0,
2646 }) else 0,
2640 .source_line = if (c_error.source_line) |line| try bundle.addString(std.mem.span(line)) else 0,
2641 }) else .none,
26472642 });
2648 bundle.incrementCount(1);
26492643 };
26502644 }
26512645 }
......@@ -2657,40 +2651,39 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
26572651 // Skip errors for Decls within files that had a parse failure.
26582652 // We'll try again once parsing succeeds.
26592653 if (decl.getFileScope().okToReportErrors()) {
2660 try addModuleErrorMsg(gpa, &bundle, entry.value_ptr.*.*);
2654 try addModuleErrorMsg(&bundle, entry.value_ptr.*.*);
26612655 }
26622656 }
26632657 }
26642658 for (module.failed_exports.values()) |value| {
2665 try addModuleErrorMsg(gpa, &bundle, value.*);
2659 try addModuleErrorMsg(&bundle, value.*);
26662660 }
26672661 }
26682662
2669 if (bundle.errorMessageCount() == 0) {
2663 if (bundle.root_list.items.len == 0) {
26702664 if (self.link_error_flags.no_entry_point_found) {
2671 try bundle.addErrorMessage(gpa, .{
2672 .msg = try bundle.addString(gpa, "no entry point found"),
2665 try bundle.addRootErrorMessage(.{
2666 .msg = try bundle.addString("no entry point found"),
26732667 });
2674 bundle.incrementCount(1);
26752668 }
26762669 }
26772670
26782671 if (self.link_error_flags.missing_libc) {
2679 try bundle.addErrorMessage(gpa, .{
2680 .msg = try bundle.addString(gpa, "libc not available"),
2672 try bundle.addRootErrorMessage(.{
2673 .msg = try bundle.addString("libc not available"),
26812674 .notes_len = 2,
26822675 });
2683 try bundle.addErrorMessage(gpa, .{
2684 .msg = try bundle.addString(gpa, "run 'zig libc -h' to learn about libc installations"),
2685 });
2686 try bundle.addErrorMessage(gpa, .{
2687 .msg = try bundle.addString(gpa, "run 'zig targets' to see the targets for which zig can always provide libc"),
2688 });
2689 bundle.incrementCount(1);
2676 const notes_start = try bundle.reserveNotes(2);
2677 bundle.extra.items[notes_start + 0] = @enumToInt(try bundle.addErrorMessage(.{
2678 .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),
2679 }));
2680 bundle.extra.items[notes_start + 1] = @enumToInt(try bundle.addErrorMessage(.{
2681 .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),
2682 }));
26902683 }
26912684
26922685 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) {
26942687 const keys = module.compile_log_decls.keys();
26952688 const values = module.compile_log_decls.values();
26962689 // First one will be the error; subsequent ones will be notes.
......@@ -2699,9 +2692,9 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
26992692 const err_msg = Module.ErrorMsg{
27002693 .src_loc = src_loc,
27012694 .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),
27032696 };
2704 defer self.gpa.free(err_msg.notes);
2697 defer gpa.free(err_msg.notes);
27052698
27062699 for (keys[1..], 0..) |key, i| {
27072700 const note_decl = module.declPtr(key);
......@@ -2711,25 +2704,26 @@ pub fn getAllErrorsAlloc(self: *Compilation) !ErrorBundle {
27112704 };
27122705 }
27132706
2714 try addModuleErrorMsg(gpa, &bundle, err_msg);
2707 try addModuleErrorMsg(&bundle, err_msg);
27152708 }
27162709 }
27172710
2718 assert(self.totalErrorCount() == bundle.errorMessageCount());
2711 assert(self.totalErrorCount() == bundle.root_list.items.len);
27192712
2720 return bundle;
2713 return bundle.toOwnedBundle();
27212714}
27222715
27232716pub const ErrorNoteHashContext = struct {
2724 eb: *const ErrorBundle,
2717 eb: *const ErrorBundle.Wip,
27252718
27262719 pub fn hash(ctx: ErrorNoteHashContext, key: ErrorBundle.ErrorMessage) u32 {
27272720 var hasher = std.hash.Wyhash.init(0);
2721 const eb = ctx.eb.tmpBundle();
27282722
2729 hasher.update(ctx.eb.nullTerminatedString(key.msg));
2730 if (key.src_loc != 0) {
2731 const src = ctx.eb.getSourceLocation(key.src_loc);
2732 hasher.update(ctx.eb.nullTerminatedString(src.src_path));
2723 hasher.update(eb.nullTerminatedString(key.msg));
2724 if (key.src_loc != .none) {
2725 const src = eb.getSourceLocation(key.src_loc);
2726 hasher.update(eb.nullTerminatedString(src.src_path));
27332727 std.hash.autoHash(&hasher, src.line);
27342728 std.hash.autoHash(&hasher, src.column);
27352729 std.hash.autoHash(&hasher, src.span_main);
......@@ -2745,17 +2739,18 @@ pub const ErrorNoteHashContext = struct {
27452739 b_index: usize,
27462740 ) bool {
27472741 _ = b_index;
2748 const msg_a = ctx.eb.nullTerminatedString(a.msg);
2749 const msg_b = ctx.eb.nullTerminatedString(b.msg);
2742 const eb = ctx.eb.tmpBundle();
2743 const msg_a = eb.nullTerminatedString(a.msg);
2744 const msg_b = eb.nullTerminatedString(b.msg);
27502745 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;
2753 if (a.src_loc == 0 or b.src_loc == 0) return false;
2754 const src_a = ctx.eb.getSourceLocation(a.src_loc);
2755 const src_b = ctx.eb.getSourceLocation(b.src_loc);
2747 if (a.src_loc == .none and b.src_loc == .none) return true;
2748 if (a.src_loc == .none or b.src_loc == .none) return false;
2749 const src_a = eb.getSourceLocation(a.src_loc);
2750 const src_b = eb.getSourceLocation(b.src_loc);
27562751
2757 const src_path_a = ctx.eb.nullTerminatedString(src_a.src_path);
2758 const src_path_b = ctx.eb.nullTerminatedString(src_b.src_path);
2752 const src_path_a = eb.nullTerminatedString(src_a.src_path);
2753 const src_path_b = eb.nullTerminatedString(src_b.src_path);
27592754
27602755 return std.mem.eql(u8, src_path_a, src_path_b) and
27612756 src_a.line == src_b.line and
......@@ -2764,16 +2759,16 @@ pub const ErrorNoteHashContext = struct {
27642759 }
27652760};
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;
27682764 const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {
27692765 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
27702766 defer gpa.free(file_path);
2771 try eb.addErrorMessage(gpa, .{
2772 .msg = try eb.printString(gpa, "unable to load '{s}': {s}", .{
2767 try eb.addRootErrorMessage(.{
2768 .msg = try eb.printString("unable to load '{s}': {s}", .{
27732769 file_path, @errorName(err),
27742770 }),
27752771 });
2776 eb.incrementCount(1);
27772772 return;
27782773 };
27792774 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
27882783 if (module_reference.hidden != 0) {
27892784 try ref_traces.append(gpa, .{
27902785 .decl_name = module_reference.hidden,
2791 .src_loc = 0,
2786 .src_loc = .none,
27922787 });
27932788 break;
27942789 } else if (module_reference.decl == null) {
27952790 try ref_traces.append(gpa, .{
27962791 .decl_name = 0,
2797 .src_loc = 0,
2792 .src_loc = .none,
27982793 });
27992794 break;
28002795 }
......@@ -2804,9 +2799,9 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
28042799 const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
28052800 defer gpa.free(rt_file_path);
28062801 try ref_traces.append(gpa, .{
2807 .decl_name = try eb.addString(gpa, std.mem.sliceTo(module_reference.decl.?, 0)),
2808 .src_loc = try eb.addSourceLocation(gpa, .{
2809 .src_path = try eb.addString(gpa, rt_file_path),
2802 .decl_name = try eb.addString(std.mem.sliceTo(module_reference.decl.?, 0)),
2803 .src_loc = try eb.addSourceLocation(.{
2804 .src_path = try eb.addString(rt_file_path),
28102805 .span_start = span.start,
28112806 .span_main = span.main,
28122807 .span_end = span.end,
......@@ -2817,8 +2812,8 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
28172812 });
28182813 }
28192814
2820 const src_loc = try eb.addSourceLocation(gpa, .{
2821 .src_path = try eb.addString(gpa, file_path),
2815 const src_loc = try eb.addSourceLocation(.{
2816 .src_path = try eb.addString(file_path),
28222817 .span_start = err_span.start,
28232818 .span_main = err_span.main,
28242819 .span_end = err_span.end,
......@@ -2827,12 +2822,12 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
28272822 .source_line = if (module_err_msg.src_loc.lazy == .entire_file)
28282823 0
28292824 else
2830 try eb.addString(gpa, err_loc.source_line),
2825 try eb.addString(err_loc.source_line),
28312826 .reference_trace_len = @intCast(u32, ref_traces.items.len),
28322827 });
28332828
28342829 for (ref_traces.items) |rt| {
2835 try eb.addReferenceTrace(gpa, rt);
2830 try eb.addReferenceTrace(rt);
28362831 }
28372832
28382833 // 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
28482843 defer gpa.free(note_file_path);
28492844
28502845 const gop = try notes.getOrPutContext(gpa, .{
2851 .msg = try eb.addString(gpa, module_note.msg),
2852 .src_loc = try eb.addSourceLocation(gpa, .{
2853 .src_path = try eb.addString(gpa, note_file_path),
2846 .msg = try eb.addString(module_note.msg),
2847 .src_loc = try eb.addSourceLocation(.{
2848 .src_path = try eb.addString(note_file_path),
28542849 .span_start = span.start,
28552850 .span_main = span.main,
28562851 .span_end = span.end,
28572852 .line = @intCast(u32, loc.line),
28582853 .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),
28602855 }),
28612856 }, .{ .eb = eb });
28622857 if (gop.found_existing) {
......@@ -2864,24 +2859,28 @@ pub fn addModuleErrorMsg(gpa: Allocator, eb: *ErrorBundle, module_err_msg: Modul
28642859 }
28652860 }
28662861
2867 try eb.addErrorMessage(gpa, .{
2868 .msg = try eb.addString(gpa, module_err_msg.msg),
2862 const notes_len = @intCast(u32, notes.entries.len);
2863
2864 try eb.addRootErrorMessage(.{
2865 .msg = try eb.addString(module_err_msg.msg),
28692866 .src_loc = src_loc,
2870 .notes_len = @intCast(u32, notes.entries.len),
2867 .notes_len = notes_len,
28712868 });
2872 eb.incrementCount(1);
28732869
2874 for (notes.keys()) |note| {
2875 try eb.addErrorMessage(gpa, note);
2870 const notes_start = try eb.reserveNotes(notes_len);
2871
2872 for (notes_start.., notes.keys()) |i, note| {
2873 eb.extra.items[i] = @enumToInt(try eb.addErrorMessage(note));
28762874 }
28772875}
28782876
2879pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File) !void {
2877pub fn addZirErrorMessages(eb: *ErrorBundle.Wip, file: *Module.File) !void {
28802878 assert(file.zir_loaded);
28812879 assert(file.tree_loaded);
28822880 assert(file.source_loaded);
28832881 const payload_index = file.zir.extra[@enumToInt(Zir.ExtraIndex.compile_errors)];
28842882 assert(payload_index != 0);
2883 const gpa = eb.gpa;
28852884
28862885 const header = file.zir.extraData(Zir.Inst.CompileErrors, payload_index);
28872886 const items_len = header.data.items_len;
......@@ -2900,14 +2899,30 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
29002899 };
29012900 const err_loc = std.zig.findLineColumn(file.source, err_span.main);
29022901
2903 var notes: []ErrorBundle.ErrorMessage = &.{};
2904 defer gpa.free(notes);
2902 {
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
29062921 if (item.data.notes != 0) {
2922 const notes_start = try eb.reserveNotes(item.data.notes);
29072923 const block = file.zir.extraData(Zir.Inst.Block, item.data.notes);
29082924 const body = file.zir.extra[block.end..][0..block.data.body_len];
2909 notes = try gpa.alloc(ErrorBundle.ErrorMessage, body.len);
2910 for (notes, body) |*note, body_elem| {
2925 for (notes_start.., body) |note_i, body_elem| {
29112926 const note_item = file.zir.extraData(Zir.Inst.CompileErrors.Item, body_elem);
29122927 const msg = file.zir.nullTerminatedString(note_item.data.msg);
29132928 const span = blk: {
......@@ -2923,10 +2938,10 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
29232938 const src_path = try file.fullPath(gpa);
29242939 defer gpa.free(src_path);
29252940
2926 note.* = .{
2927 .msg = try eb.addString(gpa, msg),
2928 .src_loc = try eb.addSourceLocation(gpa, .{
2929 .src_path = try eb.addString(gpa, src_path),
2941 eb.extra.items[note_i] = @enumToInt(try eb.addErrorMessage(.{
2942 .msg = try eb.addString(msg),
2943 .src_loc = try eb.addSourceLocation(.{
2944 .src_path = try eb.addString(src_path),
29302945 .span_start = span.start,
29312946 .span_main = span.main,
29322947 .span_end = span.end,
......@@ -2935,35 +2950,13 @@ pub fn addZirErrorMessages(gpa: Allocator, eb: *ErrorBundle, file: *Module.File)
29352950 .source_line = if (loc.eql(err_loc))
29362951 0
29372952 else
2938 try eb.addString(gpa, loc.source_line),
2953 try eb.addString(loc.source_line),
29392954 }),
29402955 .notes_len = 0, // TODO rework this function to be recursive
2941 };
2956 }));
29422957 }
29432958 }
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 }
29652959 }
2966 eb.incrementCount(items_len);
29672960}
29682961
29692962pub fn getCompileLogOutput(self: *Compilation) []const u8 {
src/Package.zig+17-19
......@@ -225,7 +225,7 @@ pub fn fetchAndAddDependencies(
225225 dependencies_source: *std.ArrayList(u8),
226226 build_roots_source: *std.ArrayList(u8),
227227 name_prefix: []const u8,
228 error_bundle: *std.zig.ErrorBundle,
228 error_bundle: *std.zig.ErrorBundle.Wip,
229229 all_modules: *AllModules,
230230) !void {
231231 const max_bytes = 10 * 1024 * 1024;
......@@ -260,13 +260,12 @@ pub fn fetchAndAddDependencies(
260260 if (manifest.errors.len > 0) {
261261 const file_path = try directory.join(arena, &.{Manifest.basename});
262262 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);
264264 }
265265 return error.PackageFetchFailed;
266266 }
267267
268268 const report: Report = .{
269 .gpa = gpa,
270269 .ast = &ast,
271270 .directory = directory,
272271 .error_bundle = error_bundle,
......@@ -343,10 +342,9 @@ pub fn createFilePkg(
343342}
344343
345344const Report = struct {
346 gpa: Allocator,
347345 ast: *const std.zig.Ast,
348346 directory: Compilation.Directory,
349 error_bundle: *std.zig.ErrorBundle,
347 error_bundle: *std.zig.ErrorBundle.Wip,
350348
351349 fn fail(
352350 report: Report,
......@@ -354,7 +352,7 @@ const Report = struct {
354352 comptime fmt_string: []const u8,
355353 fmt_args: anytype,
356354 ) error{ PackageFetchFailed, OutOfMemory } {
357 const gpa = report.gpa;
355 const gpa = report.error_bundle.gpa;
358356
359357 const file_path = try report.directory.join(gpa, &.{Manifest.basename});
360358 defer gpa.free(file_path);
......@@ -362,7 +360,7 @@ const Report = struct {
362360 const msg = try std.fmt.allocPrint(gpa, fmt_string, fmt_args);
363361 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, .{
366364 .tok = tok,
367365 .off = 0,
368366 .msg = msg,
......@@ -372,30 +370,28 @@ const Report = struct {
372370 }
373371
374372 fn addErrorMessage(
375 gpa: Allocator,
376373 ast: std.zig.Ast,
377374 file_path: []const u8,
378 eb: *std.zig.ErrorBundle,
375 eb: *std.zig.ErrorBundle.Wip,
379376 notes_len: u32,
380377 msg: Manifest.ErrorMessage,
381378 ) error{OutOfMemory}!void {
382379 const token_starts = ast.tokens.items(.start);
383380 const start_loc = ast.tokenLocation(0, msg.tok);
384381
385 try eb.addErrorMessage(gpa, .{
386 .msg = try eb.addString(gpa, msg.msg),
387 .src_loc = try eb.addSourceLocation(gpa, .{
388 .src_path = try eb.addString(gpa, file_path),
382 try eb.addRootErrorMessage(.{
383 .msg = try eb.addString(msg.msg),
384 .src_loc = try eb.addSourceLocation(.{
385 .src_path = try eb.addString(file_path),
389386 .span_start = token_starts[msg.tok],
390387 .span_end = @intCast(u32, token_starts[msg.tok] + ast.tokenSlice(msg.tok).len),
391388 .span_main = token_starts[msg.tok] + msg.off,
392389 .line = @intCast(u32, start_loc.line),
393390 .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]),
395392 }),
396393 .notes_len = notes_len,
397394 });
398 eb.incrementCount(1);
399395 }
400396};
401397
......@@ -526,14 +522,16 @@ fn fetchAndUnpack(
526522 defer gpa.free(file_path);
527523
528524 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, .{
530527 .tok = dep.url_tok,
531528 .off = 0,
532529 .msg = "url field is missing corresponding hash field",
533530 });
534 try eb.addErrorMessage(gpa, .{
535 .msg = try eb.printString(gpa, "expected .hash = \"{s}\",", .{&actual_hex}),
536 });
531 const notes_start = try eb.reserveNotes(notes_len);
532 eb.extra.items[notes_start] = @enumToInt(try eb.addErrorMessage(.{
533 .msg = try eb.printString("expected .hash = \"{s}\",", .{&actual_hex}),
534 }));
537535 return error.PackageFetchFailed;
538536 }
539537
src/Sema.zig+5-4
......@@ -2215,11 +2215,12 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
22152215
22162216 if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
22172217 if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
2218 var errors: std.zig.ErrorBundle = undefined;
2219 errors.init(gpa) catch unreachable;
2220 Compilation.addModuleErrorMsg(gpa, &errors, err_msg.*) catch unreachable;
2218 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
2219 wip_errors.init(gpa) catch unreachable;
2220 Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable;
22212221 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);
22232224 crash_report.compilerPanic("unexpected compile error occurred", null, null);
22242225 }
22252226
src/main.zig+50-36
......@@ -4436,9 +4436,9 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
44364436 var all_modules: Package.AllModules = .{};
44374437 defer all_modules.deinit(gpa);
44384438
4439 var errors: std.zig.ErrorBundle = undefined;
4440 try errors.init(gpa);
4441 defer errors.deinit(gpa);
4439 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4440 try wip_errors.init(gpa);
4441 defer wip_errors.deinit();
44424442
44434443 // Here we borrow main package's table and will replace it with a fresh
44444444 // one after this process completes.
......@@ -4453,15 +4453,17 @@ pub fn cmdBuild(gpa: Allocator, arena: Allocator, args: []const []const u8) !voi
44534453 &dependencies_source,
44544454 &build_roots_source,
44554455 "",
4456 &errors,
4456 &wip_errors,
44574457 &all_modules,
44584458 );
4459 if (errors.errorMessageCount() > 0) {
4459 if (wip_errors.root_list.items.len > 0) {
44604460 const ttyconf: std.debug.TTY.Config = switch (color) {
44614461 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
44624462 .on => .escape_codes,
44634463 .off => .no_color,
44644464 };
4465 var errors = try wip_errors.toOwnedBundle();
4466 defer errors.deinit(gpa);
44654467 errors.renderToStdErr(ttyconf);
44664468 process.exit(1);
44674469 }
......@@ -4721,16 +4723,18 @@ pub fn cmdFmt(gpa: Allocator, arena: Allocator, args: []const []const u8) !void
47214723 defer file.zir.deinit(gpa);
47224724
47234725 if (file.zir.hasCompileErrors()) {
4724 var errors: std.zig.ErrorBundle = undefined;
4725 try errors.init(gpa);
4726 defer errors.deinit(gpa);
4727 try Compilation.addZirErrorMessages(gpa, &errors, &file);
4726 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4727 try wip_errors.init(gpa);
4728 defer wip_errors.deinit();
4729 try Compilation.addZirErrorMessages(&wip_errors, &file);
47284730 const ttyconf: std.debug.TTY.Config = switch (color) {
47294731 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
47304732 .on => .escape_codes,
47314733 .off => .no_color,
47324734 };
4733 errors.renderToStdErr(ttyconf);
4735 var error_bundle = try wip_errors.toOwnedBundle();
4736 defer error_bundle.deinit(gpa);
4737 error_bundle.renderToStdErr(ttyconf);
47344738 has_ast_error = true;
47354739 }
47364740 }
......@@ -4930,16 +4934,18 @@ fn fmtPathFile(
49304934 defer file.zir.deinit(gpa);
49314935
49324936 if (file.zir.hasCompileErrors()) {
4933 var errors: std.zig.ErrorBundle = undefined;
4934 try errors.init(gpa);
4935 defer errors.deinit(gpa);
4936 try Compilation.addZirErrorMessages(gpa, &errors, &file);
4937 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4938 try wip_errors.init(gpa);
4939 defer wip_errors.deinit();
4940 try Compilation.addZirErrorMessages(&wip_errors, &file);
49374941 const ttyconf: std.debug.TTY.Config = switch (fmt.color) {
49384942 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
49394943 .on => .escape_codes,
49404944 .off => .no_color,
49414945 };
4942 errors.renderToStdErr(ttyconf);
4946 var error_bundle = try wip_errors.toOwnedBundle();
4947 defer error_bundle.deinit(gpa);
4948 error_bundle.renderToStdErr(ttyconf);
49434949 fmt.any_error = true;
49444950 }
49454951 }
......@@ -4968,17 +4974,19 @@ fn fmtPathFile(
49684974}
49694975
49704976fn printAstErrorsToStderr(gpa: Allocator, tree: Ast, path: []const u8, color: Color) !void {
4971 var error_bundle: std.zig.ErrorBundle = undefined;
4972 try error_bundle.init(gpa);
4973 defer error_bundle.deinit(gpa);
4977 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
4978 try wip_errors.init(gpa);
4979 defer wip_errors.deinit();
49744980
4975 try putAstErrorsIntoBundle(gpa, tree, path, &error_bundle);
4981 try putAstErrorsIntoBundle(gpa, tree, path, &wip_errors);
49764982
49774983 const ttyconf: std.debug.TTY.Config = switch (color) {
49784984 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
49794985 .on => .escape_codes,
49804986 .off => .no_color,
49814987 };
4988 var error_bundle = try wip_errors.toOwnedBundle();
4989 defer error_bundle.deinit(gpa);
49824990 error_bundle.renderToStdErr(ttyconf);
49834991}
49844992
......@@ -4986,7 +4994,7 @@ pub fn putAstErrorsIntoBundle(
49864994 gpa: Allocator,
49874995 tree: Ast,
49884996 path: []const u8,
4989 error_bundle: *std.zig.ErrorBundle,
4997 wip_errors: *std.zig.ErrorBundle.Wip,
49904998) !void {
49914999 var file: Module.File = .{
49925000 .status = .never_loaded,
......@@ -5013,7 +5021,7 @@ pub fn putAstErrorsIntoBundle(
50135021 file.zir_loaded = true;
50145022 defer file.zir.deinit(gpa);
50155023
5016 try Compilation.addZirErrorMessages(gpa, error_bundle, &file);
5024 try Compilation.addZirErrorMessages(wip_errors, &file);
50175025}
50185026
50195027pub const info_zen =
......@@ -5595,16 +5603,18 @@ pub fn cmdAstCheck(
55955603 defer file.zir.deinit(gpa);
55965604
55975605 if (file.zir.hasCompileErrors()) {
5598 var errors: std.zig.ErrorBundle = undefined;
5599 try errors.init(gpa);
5600 defer errors.deinit(gpa);
5601 try Compilation.addZirErrorMessages(gpa, &errors, &file);
5606 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5607 try wip_errors.init(gpa);
5608 defer wip_errors.deinit();
5609 try Compilation.addZirErrorMessages(&wip_errors, &file);
56025610 const ttyconf: std.debug.TTY.Config = switch (color) {
56035611 .auto => std.debug.detectTTYConfig(std.io.getStdErr()),
56045612 .on => .escape_codes,
56055613 .off => .no_color,
56065614 };
5607 errors.renderToStdErr(ttyconf);
5615 var error_bundle = try wip_errors.toOwnedBundle();
5616 defer error_bundle.deinit(gpa);
5617 error_bundle.renderToStdErr(ttyconf);
56085618 process.exit(1);
56095619 }
56105620
......@@ -5719,12 +5729,14 @@ pub fn cmdChangelist(
57195729 defer file.zir.deinit(gpa);
57205730
57215731 if (file.zir.hasCompileErrors()) {
5722 var errors: std.zig.ErrorBundle = undefined;
5723 try errors.init(gpa);
5724 defer errors.deinit(gpa);
5725 try Compilation.addZirErrorMessages(gpa, &errors, &file);
5732 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5733 try wip_errors.init(gpa);
5734 defer wip_errors.deinit();
5735 try Compilation.addZirErrorMessages(&wip_errors, &file);
57265736 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);
57285740 process.exit(1);
57295741 }
57305742
......@@ -5758,12 +5770,14 @@ pub fn cmdChangelist(
57585770 file.zir_loaded = true;
57595771
57605772 if (file.zir.hasCompileErrors()) {
5761 var errors: std.zig.ErrorBundle = undefined;
5762 try errors.init(gpa);
5763 defer errors.deinit(gpa);
5764 try Compilation.addZirErrorMessages(gpa, &errors, &file);
5773 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
5774 try wip_errors.init(gpa);
5775 defer wip_errors.deinit();
5776 try Compilation.addZirErrorMessages(&wip_errors, &file);
57655777 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);
57675781 process.exit(1);
57685782 }
57695783
src/test.zig+3-18
......@@ -1242,7 +1242,7 @@ pub const TestContext = struct {
12421242 defer self.gpa.free(zig_lib_directory.path.?);
12431243
12441244 var aux_thread_pool: ThreadPool = undefined;
1245 try aux_thread_pool.init(self.gpa);
1245 try aux_thread_pool.init(.{ .allocator = self.gpa });
12461246 defer aux_thread_pool.deinit();
12471247
12481248 // 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 {
16141614 if (update.case != .Error) {
16151615 var all_errors = try comp.getAllErrorsAlloc();
16161616 defer all_errors.deinit(allocator);
1617 if (all_errors.list.len != 0) {
1618 print(
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 }
1617 if (all_errors.errorMessageCount() > 0) {
1618 all_errors.renderToStdErr(std.debug.detectTTYConfig(std.io.getStdErr()));
16341619 // TODO print generated C code
16351620 return error.UnexpectedCompileErrors;
16361621 }