authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-08 14:20:10-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2022-06-09 15:37:16-07:00
logfd32f6890db8d338ec5cad92871035767f2e84ac
tree729ea96f00e6f4190473f7aac38eb581703e8bfe
parentaf909f6c93f06e409e98cb90a9896aa5216f1563

stage2: fold redundant error notes


3 files changed, 98 insertions(+), 7 deletions(-)

src/Compilation.zig+95-6
...@@ -338,6 +338,8 @@ pub const AllErrors = struct {...@@ -338,6 +338,8 @@ pub const AllErrors = struct {
338 line: u32,338 line: u32,
339 column: u32,339 column: u32,
340 byte_offset: u32,340 byte_offset: u32,
341 /// Usually one, but incremented for redundant messages.
342 count: u32 = 1,
341 /// Does not include the trailing newline.343 /// Does not include the trailing newline.
342 source_line: ?[]const u8,344 source_line: ?[]const u8,
343 notes: []Message = &.{},345 notes: []Message = &.{},
...@@ -345,8 +347,21 @@ pub const AllErrors = struct {...@@ -345,8 +347,21 @@ pub const AllErrors = struct {
345 plain: struct {347 plain: struct {
346 msg: []const u8,348 msg: []const u8,
347 notes: []Message = &.{},349 notes: []Message = &.{},
350 /// Usually one, but incremented for redundant messages.
351 count: u32 = 1,
348 },352 },
349353
354 pub fn incrementCount(msg: *Message) void {
355 switch (msg.*) {
356 .src => |*src| {
357 src.count += 1;
358 },
359 .plain => |*plain| {
360 plain.count += 1;
361 },
362 }
363 }
364
350 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {365 pub fn renderToStdErr(msg: Message, ttyconf: std.debug.TTY.Config) void {
351 std.debug.getStderrMutex().lock();366 std.debug.getStderrMutex().lock();
352 defer std.debug.getStderrMutex().unlock();367 defer std.debug.getStderrMutex().unlock();
...@@ -376,7 +391,13 @@ pub const AllErrors = struct {...@@ -376,7 +391,13 @@ pub const AllErrors = struct {
376 try stderr.writeAll(kind);391 try stderr.writeAll(kind);
377 ttyconf.setColor(stderr, .Reset);392 ttyconf.setColor(stderr, .Reset);
378 ttyconf.setColor(stderr, .Bold);393 ttyconf.setColor(stderr, .Bold);
379 try stderr.print(" {s}\n", .{src.msg});394 if (src.count == 1) {
395 try stderr.print(" {s}\n", .{src.msg});
396 } else {
397 try stderr.print(" {s}", .{src.msg});
398 ttyconf.setColor(stderr, .Dim);
399 try stderr.print(" ({d} times)\n", .{src.count});
400 }
380 ttyconf.setColor(stderr, .Reset);401 ttyconf.setColor(stderr, .Reset);
381 if (ttyconf != .no_color) {402 if (ttyconf != .no_color) {
382 if (src.source_line) |line| {403 if (src.source_line) |line| {
...@@ -400,7 +421,13 @@ pub const AllErrors = struct {...@@ -400,7 +421,13 @@ pub const AllErrors = struct {
400 try stderr.writeByteNTimes(' ', indent);421 try stderr.writeByteNTimes(' ', indent);
401 try stderr.writeAll(kind);422 try stderr.writeAll(kind);
402 ttyconf.setColor(stderr, .Reset);423 ttyconf.setColor(stderr, .Reset);
403 try stderr.print(" {s}\n", .{plain.msg});424 if (plain.count == 1) {
425 try stderr.print(" {s}\n", .{plain.msg});
426 } else {
427 try stderr.print(" {s}", .{plain.msg});
428 ttyconf.setColor(stderr, .Dim);
429 try stderr.print(" ({d} times)\n", .{plain.count});
430 }
404 ttyconf.setColor(stderr, .Reset);431 ttyconf.setColor(stderr, .Reset);
405 for (plain.notes) |note| {432 for (plain.notes) |note| {
406 try note.renderToStdErrInner(ttyconf, stderr_file, "error:", .Red, indent + 4);433 try note.renderToStdErrInner(ttyconf, stderr_file, "error:", .Red, indent + 4);
...@@ -408,6 +435,50 @@ pub const AllErrors = struct {...@@ -408,6 +435,50 @@ pub const AllErrors = struct {
408 },435 },
409 }436 }
410 }437 }
438
439 pub const HashContext = struct {
440 pub fn hash(ctx: HashContext, key: *Message) u64 {
441 _ = ctx;
442 var hasher = std.hash.Wyhash.init(0);
443
444 switch (key.*) {
445 .src => |src| {
446 hasher.update(src.msg);
447 hasher.update(src.src_path);
448 std.hash.autoHash(&hasher, src.line);
449 std.hash.autoHash(&hasher, src.column);
450 std.hash.autoHash(&hasher, src.byte_offset);
451 },
452 .plain => |plain| {
453 hasher.update(plain.msg);
454 },
455 }
456
457 return hasher.final();
458 }
459
460 pub fn eql(ctx: HashContext, a: *Message, b: *Message) bool {
461 _ = ctx;
462 switch (a.*) {
463 .src => |a_src| switch (b.*) {
464 .src => |b_src| {
465 return mem.eql(u8, a_src.msg, b_src.msg) and
466 mem.eql(u8, a_src.src_path, b_src.src_path) and
467 a_src.line == b_src.line and
468 a_src.column == b_src.column and
469 a_src.byte_offset == b_src.byte_offset;
470 },
471 .plain => return false,
472 },
473 .plain => |a_plain| switch (b.*) {
474 .src => return false,
475 .plain => |b_plain| {
476 return mem.eql(u8, a_plain.msg, b_plain.msg);
477 },
478 },
479 }
480 }
481 };
411 };482 };
412483
413 pub fn deinit(self: *AllErrors, gpa: Allocator) void {484 pub fn deinit(self: *AllErrors, gpa: Allocator) void {
...@@ -421,13 +492,25 @@ pub const AllErrors = struct {...@@ -421,13 +492,25 @@ pub const AllErrors = struct {
421 module_err_msg: Module.ErrorMsg,492 module_err_msg: Module.ErrorMsg,
422 ) !void {493 ) !void {
423 const allocator = arena.allocator();494 const allocator = arena.allocator();
424 const notes = try allocator.alloc(Message, module_err_msg.notes.len);495
425 for (notes) |*note, i| {496 const notes_buf = try allocator.alloc(Message, module_err_msg.notes.len);
426 const module_note = module_err_msg.notes[i];497 var note_i: usize = 0;
498
499 // De-duplicate error notes. The main use case in mind for this is
500 // too many "note: called from here" notes when eval branch quota is reached.
501 var seen_notes = std.HashMap(
502 *Message,
503 void,
504 Message.HashContext,
505 std.hash_map.default_max_load_percentage,
506 ).init(allocator);
507
508 for (module_err_msg.notes) |module_note| {
427 const source = try module_note.src_loc.file_scope.getSource(module.gpa);509 const source = try module_note.src_loc.file_scope.getSource(module.gpa);
428 const byte_offset = try module_note.src_loc.byteOffset(module.gpa);510 const byte_offset = try module_note.src_loc.byteOffset(module.gpa);
429 const loc = std.zig.findLineColumn(source.bytes, byte_offset);511 const loc = std.zig.findLineColumn(source.bytes, byte_offset);
430 const file_path = try module_note.src_loc.file_scope.fullPath(allocator);512 const file_path = try module_note.src_loc.file_scope.fullPath(allocator);
513 const note = &notes_buf[note_i];
431 note.* = .{514 note.* = .{
432 .src = .{515 .src = .{
433 .src_path = file_path,516 .src_path = file_path,
...@@ -438,6 +521,12 @@ pub const AllErrors = struct {...@@ -438,6 +521,12 @@ pub const AllErrors = struct {
438 .source_line = try allocator.dupe(u8, loc.source_line),521 .source_line = try allocator.dupe(u8, loc.source_line),
439 },522 },
440 };523 };
524 const gop = try seen_notes.getOrPut(note);
525 if (gop.found_existing) {
526 gop.key_ptr.*.incrementCount();
527 } else {
528 note_i += 1;
529 }
441 }530 }
442 if (module_err_msg.src_loc.lazy == .entire_file) {531 if (module_err_msg.src_loc.lazy == .entire_file) {
443 try errors.append(.{532 try errors.append(.{
...@@ -458,7 +547,7 @@ pub const AllErrors = struct {...@@ -458,7 +547,7 @@ pub const AllErrors = struct {
458 .byte_offset = byte_offset,547 .byte_offset = byte_offset,
459 .line = @intCast(u32, loc.line),548 .line = @intCast(u32, loc.line),
460 .column = @intCast(u32, loc.column),549 .column = @intCast(u32, loc.column),
461 .notes = notes,550 .notes = notes_buf[0..note_i],
462 .source_line = try allocator.dupe(u8, loc.source_line),551 .source_line = try allocator.dupe(u8, loc.source_line),
463 },552 },
464 });553 });
src/Sema.zig-1
...@@ -18061,7 +18061,6 @@ fn safetyPanic(...@@ -18061,7 +18061,6 @@ fn safetyPanic(
18061fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {18061fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
18062 sema.branch_count += 1;18062 sema.branch_count += 1;
18063 if (sema.branch_count > sema.branch_quota) {18063 if (sema.branch_count > sema.branch_quota) {
18064 // TODO show the "called from here" stack
18065 return sema.fail(block, src, "evaluation exceeded {d} backwards branches", .{sema.branch_quota});18064 return sema.fail(block, src, "evaluation exceeded {d} backwards branches", .{sema.branch_quota});
18066 }18065 }
18067}18066}
test/cases/recursive_inline_function.1.zig+3
...@@ -14,3 +14,6 @@ inline fn fibonacci(n: usize) usize {...@@ -14,3 +14,6 @@ inline fn fibonacci(n: usize) usize {
14// error14// error
15//15//
16// :11:21: error: evaluation exceeded 1000 backwards branches16// :11:21: error: evaluation exceeded 1000 backwards branches
17// :11:40: note: called from here (6 times)
18// :11:21: note: called from here (495 times)
19// :5:24: note: called from here