authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 15:27:00-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-07-02 15:27:00-07:00
logd979dd9b58f6d5462b009002e0a0eb79f94fb9a7
tree6cb9504f15c34fd32f732b930b8d770346576617
parent5103053977573131d8040a53d9ab3f2afd1b01b0

stage2: improve AstGen FileNotFound error message

Partially addresses #9203. It fixes the first case, but not the second one mentioned in the issue.

7 files changed, 111 insertions(+), 34 deletions(-)

lib/std/mem.zig+5-5
......@@ -2297,14 +2297,14 @@ pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, n
22972297}
22982298
22992299test "replaceOwned" {
2300 const allocator = std.heap.page_allocator;
2300 const gpa = std.testing.allocator;
23012301
2302 const base_replace = replaceOwned(u8, allocator, "All your base are belong to us", "base", "Zig") catch unreachable;
2303 defer allocator.free(base_replace);
2302 const base_replace = replaceOwned(u8, gpa, "All your base are belong to us", "base", "Zig") catch @panic("out of memory");
2303 defer gpa.free(base_replace);
23042304 try testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
23052305
2306 const zen_replace = replaceOwned(u8, allocator, "Favor reading code over writing code.", " code", "") catch unreachable;
2307 defer allocator.free(zen_replace);
2306 const zen_replace = replaceOwned(u8, gpa, "Favor reading code over writing code.", " code", "") catch @panic("out of memory");
2307 defer gpa.free(zen_replace);
23082308 try testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
23092309}
23102310
src/AstGen.zig+10-4
......@@ -34,8 +34,9 @@ string_table: std.StringHashMapUnmanaged(u32) = .{},
3434compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
3535/// The topmost block of the current function.
3636fn_block: ?*GenZir = null,
37/// String table indexes, keeps track of all `@import` operands.
38imports: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
37/// Maps string table indexes to the first `@import` ZIR instruction
38/// that uses this string as the operand.
39imports: std.AutoArrayHashMapUnmanaged(u32, Zir.Inst.Index) = .{},
3940
4041const InnerError = error{ OutOfMemory, AnalysisFail };
4142
......@@ -154,7 +155,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir {
154155 astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{
155156 .imports_len = @intCast(u32, astgen.imports.count()),
156157 });
157 astgen.extra.appendSliceAssumeCapacity(astgen.imports.keys());
158 astgen.extra.appendSliceAssumeCapacity(astgen.imports.values());
158159 }
159160
160161 return Zir{
......@@ -6863,8 +6864,13 @@ fn builtinCall(
68636864 }
68646865 const str_lit_token = main_tokens[operand_node];
68656866 const str = try astgen.strLitAsString(str_lit_token);
6866 try astgen.imports.put(astgen.gpa, str.index, {});
68676867 const result = try gz.addStrTok(.import, str.index, str_lit_token);
6868 if (gz.refToIndex(result)) |import_inst_index| {
6869 const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
6870 if (!gop.found_existing) {
6871 gop.value_ptr.* = import_inst_index;
6872 }
6873 }
68686874 return rvalue(gz, rl, result, node);
68696875 },
68706876 .compile_log => {
src/Compilation.zig+44-13
......@@ -1958,7 +1958,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
19581958 while (self.astgen_work_queue.readItem()) |file| {
19591959 self.astgen_wait_group.start();
19601960 try self.thread_pool.spawn(workerAstGenFile, .{
1961 self, file, &zir_prog_node, &self.astgen_wait_group,
1961 self, file, &zir_prog_node, &self.astgen_wait_group, .root,
19621962 });
19631963 }
19641964
......@@ -2310,11 +2310,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
23102310 };
23112311}
23122312
2313const AstGenSrc = union(enum) {
2314 root,
2315 import: struct {
2316 importing_file: *Module.Scope.File,
2317 import_inst: Zir.Inst.Index,
2318 },
2319};
2320
23132321fn workerAstGenFile(
23142322 comp: *Compilation,
23152323 file: *Module.Scope.File,
23162324 prog_node: *std.Progress.Node,
23172325 wg: *WaitGroup,
2326 src: AstGenSrc,
23182327) void {
23192328 defer wg.finish();
23202329
......@@ -2327,7 +2336,7 @@ fn workerAstGenFile(
23272336 error.AnalysisFail => return,
23282337 else => {
23292338 file.status = .retryable_failure;
2330 comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) {
2339 comp.reportRetryableAstGenError(src, file, err) catch |oom| switch (oom) {
23312340 // Swallowing this error is OK because it's implied to be OOM when
23322341 // there is a missing `failed_files` error message.
23332342 error.OutOfMemory => {},
......@@ -2344,8 +2353,9 @@ fn workerAstGenFile(
23442353 if (imports_index != 0) {
23452354 const imports_len = file.zir.extra[imports_index];
23462355
2347 for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
2348 const import_path = file.zir.nullTerminatedString(str_index);
2356 for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| {
2357 const inst_data = file.zir.instructions.items(.data)[import_inst].str_tok;
2358 const import_path = inst_data.get(file.zir);
23492359
23502360 const import_result = blk: {
23512361 const lock = comp.mutex.acquire();
......@@ -2357,9 +2367,13 @@ fn workerAstGenFile(
23572367 log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
23582368 file.sub_file_path, import_path, import_result.file.sub_file_path,
23592369 });
2370 const sub_src: AstGenSrc = .{ .import = .{
2371 .importing_file = file,
2372 .import_inst = import_inst,
2373 } };
23602374 wg.start();
23612375 comp.thread_pool.spawn(workerAstGenFile, .{
2362 comp, import_result.file, prog_node, wg,
2376 comp, import_result.file, prog_node, wg, sub_src,
23632377 }) catch {
23642378 wg.finish();
23652379 continue;
......@@ -2570,6 +2584,7 @@ fn reportRetryableCObjectError(
25702584
25712585fn reportRetryableAstGenError(
25722586 comp: *Compilation,
2587 src: AstGenSrc,
25732588 file: *Module.Scope.File,
25742589 err: anyerror,
25752590) error{OutOfMemory}!void {
......@@ -2578,22 +2593,38 @@ fn reportRetryableAstGenError(
25782593
25792594 file.status = .retryable_failure;
25802595
2581 const src_loc: Module.SrcLoc = .{
2582 .file_scope = file,
2583 .parent_decl_node = 0,
2584 .lazy = .entire_file,
2596 const src_loc: Module.SrcLoc = switch (src) {
2597 .root => .{
2598 .file_scope = file,
2599 .parent_decl_node = 0,
2600 .lazy = .entire_file,
2601 },
2602 .import => |info| blk: {
2603 const importing_file = info.importing_file;
2604 const import_inst = info.import_inst;
2605 const inst_data = importing_file.zir.instructions.items(.data)[import_inst].str_tok;
2606 break :blk .{
2607 .file_scope = importing_file,
2608 .parent_decl_node = 0,
2609 .lazy = .{ .token_offset = inst_data.src_tok },
2610 };
2611 },
25852612 };
25862613
25872614 const err_msg = if (file.pkg.root_src_directory.path) |dir_path|
25882615 try Module.ErrorMsg.create(
25892616 gpa,
25902617 src_loc,
2591 "unable to load {s}" ++ std.fs.path.sep_str ++ "{s}: {s}",
2592 .{ dir_path, file.sub_file_path, @errorName(err) },
2618 "unable to load '{'}" ++ std.fs.path.sep_str ++ "{'}': {s}",
2619 .{
2620 std.zig.fmtEscapes(dir_path),
2621 std.zig.fmtEscapes(file.sub_file_path),
2622 @errorName(err),
2623 },
25932624 )
25942625 else
2595 try Module.ErrorMsg.create(gpa, src_loc, "unable to load {s}: {s}", .{
2596 file.sub_file_path, @errorName(err),
2626 try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{'}': {s}", .{
2627 std.zig.fmtEscapes(file.sub_file_path), @errorName(err),
25972628 });
25982629 errdefer err_msg.destroy(gpa);
25992630
src/Module.zig+1-1
......@@ -2485,7 +2485,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
24852485 .file_scope = file,
24862486 .parent_decl_node = 0,
24872487 .lazy = .{ .byte_abs = byte_abs },
2488 }, err_msg, "invalid byte: '{'}'", .{ std.zig.fmtEscapes(source[byte_abs..][0..1]) });
2488 }, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
24892489 }
24902490
24912491 {
src/Zir.zig+12-5
......@@ -139,9 +139,15 @@ pub fn renderAsTextToFile(
139139 if (imports_index != 0) {
140140 try fs_file.writeAll("Imports:\n");
141141 const imports_len = scope_file.zir.extra[imports_index];
142 for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
143 const import_path = scope_file.zir.nullTerminatedString(str_index);
144 try fs_file.writer().print(" {s}\n", .{import_path});
142 for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| {
143 const inst_data = writer.code.instructions.items(.data)[import_inst].str_tok;
144 const src = inst_data.src();
145 const import_path = inst_data.get(writer.code);
146 try fs_file.writer().print(" @import(\"{}\") ", .{
147 std.zig.fmtEscapes(import_path),
148 });
149 try writer.writeSrc(fs_file.writer(), src);
150 try fs_file.writer().writeAll("\n");
145151 }
146152 }
147153}
......@@ -2767,9 +2773,10 @@ pub const Inst = struct {
27672773 };
27682774 };
27692775
2770 /// Trailing: for each `imports_len` there is a string table index.
2776 /// Trailing: for each `imports_len` there is an instruction index
2777 /// to an import instruction.
27712778 pub const Imports = struct {
2772 imports_len: u32,
2779 imports_len: Zir.Inst.Index,
27732780 };
27742781};
27752782
src/test.zig+38-4
......@@ -699,6 +699,11 @@ pub const TestContext = struct {
699699 arena,
700700 &[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path },
701701 );
702 const tmp_dir_path_plus_slash = try std.fmt.allocPrint(
703 arena,
704 "{s}" ++ std.fs.path.sep_str,
705 .{tmp_dir_path},
706 );
702707 const local_cache_path = try std.fs.path.join(
703708 arena,
704709 &[_][]const u8{ tmp_dir_path, "zig-cache" },
......@@ -773,7 +778,14 @@ pub const TestContext = struct {
773778 var i: usize = 0;
774779 ok = while (err_iter.next()) |line| : (i += 1) {
775780 if (i >= case_error_list.len) break false;
776 const expected = try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]});
781 const expected = try std.mem.replaceOwned(
782 u8,
783 arena,
784 try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]}),
785 "${DIR}",
786 tmp_dir_path_plus_slash,
787 );
788
777789 if (std.mem.indexOf(u8, line, expected) == null) break false;
778790 continue;
779791 } else true;
......@@ -789,7 +801,13 @@ pub const TestContext = struct {
789801 }
790802 } else {
791803 for (case_error_list) |msg| {
792 const expected = try std.fmt.allocPrint(arena, "{s}", .{msg});
804 const expected = try std.mem.replaceOwned(
805 u8,
806 arena,
807 try std.fmt.allocPrint(arena, "{s}", .{msg}),
808 "${DIR}",
809 tmp_dir_path_plus_slash,
810 );
793811 if (std.mem.indexOf(u8, result.stderr, expected) == null) {
794812 print(
795813 \\
......@@ -971,12 +989,20 @@ pub const TestContext = struct {
971989 const src_path_ok = case_msg.src.src_path.len == 0 or
972990 std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);
973991
992 const expected_msg = try std.mem.replaceOwned(
993 u8,
994 arena,
995 case_msg.src.msg,
996 "${DIR}",
997 tmp_dir_path_plus_slash,
998 );
999
9741000 if (src_path_ok and
9751001 (case_msg.src.line == std.math.maxInt(u32) or
9761002 actual_msg.line == case_msg.src.line) and
9771003 (case_msg.src.column == std.math.maxInt(u32) or
9781004 actual_msg.column == case_msg.src.column) and
979 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
1005 std.mem.eql(u8, expected_msg, actual_msg.msg) and
9801006 case_msg.src.kind == .@"error")
9811007 {
9821008 handled_errors[i] = true;
......@@ -1012,11 +1038,19 @@ pub const TestContext = struct {
10121038 }
10131039 if (ex_tag != .src) continue;
10141040
1041 const expected_msg = try std.mem.replaceOwned(
1042 u8,
1043 arena,
1044 case_msg.src.msg,
1045 "${DIR}",
1046 tmp_dir_path_plus_slash,
1047 );
1048
10151049 if ((case_msg.src.line == std.math.maxInt(u32) or
10161050 actual_msg.line == case_msg.src.line) and
10171051 (case_msg.src.column == std.math.maxInt(u32) or
10181052 actual_msg.column == case_msg.src.column) and
1019 std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
1053 std.mem.eql(u8, expected_msg, actual_msg.msg) and
10201054 case_msg.src.kind == .note)
10211055 {
10221056 handled_errors[i] = true;
test/compile_errors.zig+1-2
......@@ -4976,9 +4976,8 @@ pub fn addCases(ctx: *TestContext) !void {
49764976
49774977 ctx.objErrStage1("bad import",
49784978 \\const bogus = @import("bogus-does-not-exist.zig",);
4979 \\export fn entry() void { bogus.bogo(); }
49804979 , &[_][]const u8{
4981 "tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
4980 "tmp.zig:1:23: error: unable to load '${DIR}bogus-does-not-exist.zig': FileNotFound",
49824981 });
49834982
49844983 ctx.objErrStage1("undeclared identifier",