mirror of
https://codeberg.org/ziglang/zig.git
synced 2025-12-06 13:54:21 +00:00
stage2: improve AstGen FileNotFound error message
Partially addresses #9203. It fixes the first case, but not the second one mentioned in the issue.
This commit is contained in:
parent
5103053977
commit
d979dd9b58
7 changed files with 111 additions and 34 deletions
|
|
@ -2297,14 +2297,14 @@ pub fn replaceOwned(comptime T: type, allocator: *Allocator, input: []const T, n
|
||||||
}
|
}
|
||||||
|
|
||||||
test "replaceOwned" {
|
test "replaceOwned" {
|
||||||
const allocator = std.heap.page_allocator;
|
const gpa = std.testing.allocator;
|
||||||
|
|
||||||
const base_replace = replaceOwned(u8, allocator, "All your base are belong to us", "base", "Zig") catch unreachable;
|
const base_replace = replaceOwned(u8, gpa, "All your base are belong to us", "base", "Zig") catch @panic("out of memory");
|
||||||
defer allocator.free(base_replace);
|
defer gpa.free(base_replace);
|
||||||
try testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
|
try testing.expect(eql(u8, base_replace, "All your Zig are belong to us"));
|
||||||
|
|
||||||
const zen_replace = replaceOwned(u8, allocator, "Favor reading code over writing code.", " code", "") catch unreachable;
|
const zen_replace = replaceOwned(u8, gpa, "Favor reading code over writing code.", " code", "") catch @panic("out of memory");
|
||||||
defer allocator.free(zen_replace);
|
defer gpa.free(zen_replace);
|
||||||
try testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
|
try testing.expect(eql(u8, zen_replace, "Favor reading over writing."));
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -34,8 +34,9 @@ string_table: std.StringHashMapUnmanaged(u32) = .{},
|
||||||
compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
|
compile_errors: ArrayListUnmanaged(Zir.Inst.CompileErrors.Item) = .{},
|
||||||
/// The topmost block of the current function.
|
/// The topmost block of the current function.
|
||||||
fn_block: ?*GenZir = null,
|
fn_block: ?*GenZir = null,
|
||||||
/// String table indexes, keeps track of all `@import` operands.
|
/// Maps string table indexes to the first `@import` ZIR instruction
|
||||||
imports: std.AutoArrayHashMapUnmanaged(u32, void) = .{},
|
/// that uses this string as the operand.
|
||||||
|
imports: std.AutoArrayHashMapUnmanaged(u32, Zir.Inst.Index) = .{},
|
||||||
|
|
||||||
const InnerError = error{ OutOfMemory, AnalysisFail };
|
const InnerError = error{ OutOfMemory, AnalysisFail };
|
||||||
|
|
||||||
|
|
@ -154,7 +155,7 @@ pub fn generate(gpa: *Allocator, tree: ast.Tree) Allocator.Error!Zir {
|
||||||
astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{
|
astgen.extra.items[imports_index] = astgen.addExtraAssumeCapacity(Zir.Inst.Imports{
|
||||||
.imports_len = @intCast(u32, astgen.imports.count()),
|
.imports_len = @intCast(u32, astgen.imports.count()),
|
||||||
});
|
});
|
||||||
astgen.extra.appendSliceAssumeCapacity(astgen.imports.keys());
|
astgen.extra.appendSliceAssumeCapacity(astgen.imports.values());
|
||||||
}
|
}
|
||||||
|
|
||||||
return Zir{
|
return Zir{
|
||||||
|
|
@ -6863,8 +6864,13 @@ fn builtinCall(
|
||||||
}
|
}
|
||||||
const str_lit_token = main_tokens[operand_node];
|
const str_lit_token = main_tokens[operand_node];
|
||||||
const str = try astgen.strLitAsString(str_lit_token);
|
const str = try astgen.strLitAsString(str_lit_token);
|
||||||
try astgen.imports.put(astgen.gpa, str.index, {});
|
|
||||||
const result = try gz.addStrTok(.import, str.index, str_lit_token);
|
const result = try gz.addStrTok(.import, str.index, str_lit_token);
|
||||||
|
if (gz.refToIndex(result)) |import_inst_index| {
|
||||||
|
const gop = try astgen.imports.getOrPut(astgen.gpa, str.index);
|
||||||
|
if (!gop.found_existing) {
|
||||||
|
gop.value_ptr.* = import_inst_index;
|
||||||
|
}
|
||||||
|
}
|
||||||
return rvalue(gz, rl, result, node);
|
return rvalue(gz, rl, result, node);
|
||||||
},
|
},
|
||||||
.compile_log => {
|
.compile_log => {
|
||||||
|
|
|
||||||
|
|
@ -1958,7 +1958,7 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||||
while (self.astgen_work_queue.readItem()) |file| {
|
while (self.astgen_work_queue.readItem()) |file| {
|
||||||
self.astgen_wait_group.start();
|
self.astgen_wait_group.start();
|
||||||
try self.thread_pool.spawn(workerAstGenFile, .{
|
try self.thread_pool.spawn(workerAstGenFile, .{
|
||||||
self, file, &zir_prog_node, &self.astgen_wait_group,
|
self, file, &zir_prog_node, &self.astgen_wait_group, .root,
|
||||||
});
|
});
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
@ -2310,11 +2310,20 @@ pub fn performAllTheWork(self: *Compilation) error{ TimerUnsupported, OutOfMemor
|
||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
|
const AstGenSrc = union(enum) {
|
||||||
|
root,
|
||||||
|
import: struct {
|
||||||
|
importing_file: *Module.Scope.File,
|
||||||
|
import_inst: Zir.Inst.Index,
|
||||||
|
},
|
||||||
|
};
|
||||||
|
|
||||||
fn workerAstGenFile(
|
fn workerAstGenFile(
|
||||||
comp: *Compilation,
|
comp: *Compilation,
|
||||||
file: *Module.Scope.File,
|
file: *Module.Scope.File,
|
||||||
prog_node: *std.Progress.Node,
|
prog_node: *std.Progress.Node,
|
||||||
wg: *WaitGroup,
|
wg: *WaitGroup,
|
||||||
|
src: AstGenSrc,
|
||||||
) void {
|
) void {
|
||||||
defer wg.finish();
|
defer wg.finish();
|
||||||
|
|
||||||
|
|
@ -2327,7 +2336,7 @@ fn workerAstGenFile(
|
||||||
error.AnalysisFail => return,
|
error.AnalysisFail => return,
|
||||||
else => {
|
else => {
|
||||||
file.status = .retryable_failure;
|
file.status = .retryable_failure;
|
||||||
comp.reportRetryableAstGenError(file, err) catch |oom| switch (oom) {
|
comp.reportRetryableAstGenError(src, file, err) catch |oom| switch (oom) {
|
||||||
// Swallowing this error is OK because it's implied to be OOM when
|
// Swallowing this error is OK because it's implied to be OOM when
|
||||||
// there is a missing `failed_files` error message.
|
// there is a missing `failed_files` error message.
|
||||||
error.OutOfMemory => {},
|
error.OutOfMemory => {},
|
||||||
|
|
@ -2344,8 +2353,9 @@ fn workerAstGenFile(
|
||||||
if (imports_index != 0) {
|
if (imports_index != 0) {
|
||||||
const imports_len = file.zir.extra[imports_index];
|
const imports_len = file.zir.extra[imports_index];
|
||||||
|
|
||||||
for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
|
for (file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| {
|
||||||
const import_path = file.zir.nullTerminatedString(str_index);
|
const inst_data = file.zir.instructions.items(.data)[import_inst].str_tok;
|
||||||
|
const import_path = inst_data.get(file.zir);
|
||||||
|
|
||||||
const import_result = blk: {
|
const import_result = blk: {
|
||||||
const lock = comp.mutex.acquire();
|
const lock = comp.mutex.acquire();
|
||||||
|
|
@ -2357,9 +2367,13 @@ fn workerAstGenFile(
|
||||||
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
||||||
file.sub_file_path, import_path, import_result.file.sub_file_path,
|
file.sub_file_path, import_path, import_result.file.sub_file_path,
|
||||||
});
|
});
|
||||||
|
const sub_src: AstGenSrc = .{ .import = .{
|
||||||
|
.importing_file = file,
|
||||||
|
.import_inst = import_inst,
|
||||||
|
} };
|
||||||
wg.start();
|
wg.start();
|
||||||
comp.thread_pool.spawn(workerAstGenFile, .{
|
comp.thread_pool.spawn(workerAstGenFile, .{
|
||||||
comp, import_result.file, prog_node, wg,
|
comp, import_result.file, prog_node, wg, sub_src,
|
||||||
}) catch {
|
}) catch {
|
||||||
wg.finish();
|
wg.finish();
|
||||||
continue;
|
continue;
|
||||||
|
|
@ -2570,6 +2584,7 @@ fn reportRetryableCObjectError(
|
||||||
|
|
||||||
fn reportRetryableAstGenError(
|
fn reportRetryableAstGenError(
|
||||||
comp: *Compilation,
|
comp: *Compilation,
|
||||||
|
src: AstGenSrc,
|
||||||
file: *Module.Scope.File,
|
file: *Module.Scope.File,
|
||||||
err: anyerror,
|
err: anyerror,
|
||||||
) error{OutOfMemory}!void {
|
) error{OutOfMemory}!void {
|
||||||
|
|
@ -2578,22 +2593,38 @@ fn reportRetryableAstGenError(
|
||||||
|
|
||||||
file.status = .retryable_failure;
|
file.status = .retryable_failure;
|
||||||
|
|
||||||
const src_loc: Module.SrcLoc = .{
|
const src_loc: Module.SrcLoc = switch (src) {
|
||||||
.file_scope = file,
|
.root => .{
|
||||||
.parent_decl_node = 0,
|
.file_scope = file,
|
||||||
.lazy = .entire_file,
|
.parent_decl_node = 0,
|
||||||
|
.lazy = .entire_file,
|
||||||
|
},
|
||||||
|
.import => |info| blk: {
|
||||||
|
const importing_file = info.importing_file;
|
||||||
|
const import_inst = info.import_inst;
|
||||||
|
const inst_data = importing_file.zir.instructions.items(.data)[import_inst].str_tok;
|
||||||
|
break :blk .{
|
||||||
|
.file_scope = importing_file,
|
||||||
|
.parent_decl_node = 0,
|
||||||
|
.lazy = .{ .token_offset = inst_data.src_tok },
|
||||||
|
};
|
||||||
|
},
|
||||||
};
|
};
|
||||||
|
|
||||||
const err_msg = if (file.pkg.root_src_directory.path) |dir_path|
|
const err_msg = if (file.pkg.root_src_directory.path) |dir_path|
|
||||||
try Module.ErrorMsg.create(
|
try Module.ErrorMsg.create(
|
||||||
gpa,
|
gpa,
|
||||||
src_loc,
|
src_loc,
|
||||||
"unable to load {s}" ++ std.fs.path.sep_str ++ "{s}: {s}",
|
"unable to load '{'}" ++ std.fs.path.sep_str ++ "{'}': {s}",
|
||||||
.{ dir_path, file.sub_file_path, @errorName(err) },
|
.{
|
||||||
|
std.zig.fmtEscapes(dir_path),
|
||||||
|
std.zig.fmtEscapes(file.sub_file_path),
|
||||||
|
@errorName(err),
|
||||||
|
},
|
||||||
)
|
)
|
||||||
else
|
else
|
||||||
try Module.ErrorMsg.create(gpa, src_loc, "unable to load {s}: {s}", .{
|
try Module.ErrorMsg.create(gpa, src_loc, "unable to load '{'}': {s}", .{
|
||||||
file.sub_file_path, @errorName(err),
|
std.zig.fmtEscapes(file.sub_file_path), @errorName(err),
|
||||||
});
|
});
|
||||||
errdefer err_msg.destroy(gpa);
|
errdefer err_msg.destroy(gpa);
|
||||||
|
|
||||||
|
|
|
||||||
|
|
@ -2485,7 +2485,7 @@ pub fn astGenFile(mod: *Module, file: *Scope.File) !void {
|
||||||
.file_scope = file,
|
.file_scope = file,
|
||||||
.parent_decl_node = 0,
|
.parent_decl_node = 0,
|
||||||
.lazy = .{ .byte_abs = byte_abs },
|
.lazy = .{ .byte_abs = byte_abs },
|
||||||
}, err_msg, "invalid byte: '{'}'", .{ std.zig.fmtEscapes(source[byte_abs..][0..1]) });
|
}, err_msg, "invalid byte: '{'}'", .{std.zig.fmtEscapes(source[byte_abs..][0..1])});
|
||||||
}
|
}
|
||||||
|
|
||||||
{
|
{
|
||||||
|
|
|
||||||
17
src/Zir.zig
17
src/Zir.zig
|
|
@ -139,9 +139,15 @@ pub fn renderAsTextToFile(
|
||||||
if (imports_index != 0) {
|
if (imports_index != 0) {
|
||||||
try fs_file.writeAll("Imports:\n");
|
try fs_file.writeAll("Imports:\n");
|
||||||
const imports_len = scope_file.zir.extra[imports_index];
|
const imports_len = scope_file.zir.extra[imports_index];
|
||||||
for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |str_index| {
|
for (scope_file.zir.extra[imports_index + 1 ..][0..imports_len]) |import_inst| {
|
||||||
const import_path = scope_file.zir.nullTerminatedString(str_index);
|
const inst_data = writer.code.instructions.items(.data)[import_inst].str_tok;
|
||||||
try fs_file.writer().print(" {s}\n", .{import_path});
|
const src = inst_data.src();
|
||||||
|
const import_path = inst_data.get(writer.code);
|
||||||
|
try fs_file.writer().print(" @import(\"{}\") ", .{
|
||||||
|
std.zig.fmtEscapes(import_path),
|
||||||
|
});
|
||||||
|
try writer.writeSrc(fs_file.writer(), src);
|
||||||
|
try fs_file.writer().writeAll("\n");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -2767,9 +2773,10 @@ pub const Inst = struct {
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
/// Trailing: for each `imports_len` there is a string table index.
|
/// Trailing: for each `imports_len` there is an instruction index
|
||||||
|
/// to an import instruction.
|
||||||
pub const Imports = struct {
|
pub const Imports = struct {
|
||||||
imports_len: u32,
|
imports_len: Zir.Inst.Index,
|
||||||
};
|
};
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
||||||
42
src/test.zig
42
src/test.zig
|
|
@ -699,6 +699,11 @@ pub const TestContext = struct {
|
||||||
arena,
|
arena,
|
||||||
&[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path },
|
&[_][]const u8{ ".", "zig-cache", "tmp", &tmp.sub_path },
|
||||||
);
|
);
|
||||||
|
const tmp_dir_path_plus_slash = try std.fmt.allocPrint(
|
||||||
|
arena,
|
||||||
|
"{s}" ++ std.fs.path.sep_str,
|
||||||
|
.{tmp_dir_path},
|
||||||
|
);
|
||||||
const local_cache_path = try std.fs.path.join(
|
const local_cache_path = try std.fs.path.join(
|
||||||
arena,
|
arena,
|
||||||
&[_][]const u8{ tmp_dir_path, "zig-cache" },
|
&[_][]const u8{ tmp_dir_path, "zig-cache" },
|
||||||
|
|
@ -773,7 +778,14 @@ pub const TestContext = struct {
|
||||||
var i: usize = 0;
|
var i: usize = 0;
|
||||||
ok = while (err_iter.next()) |line| : (i += 1) {
|
ok = while (err_iter.next()) |line| : (i += 1) {
|
||||||
if (i >= case_error_list.len) break false;
|
if (i >= case_error_list.len) break false;
|
||||||
const expected = try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]});
|
const expected = try std.mem.replaceOwned(
|
||||||
|
u8,
|
||||||
|
arena,
|
||||||
|
try std.fmt.allocPrint(arena, "{s}", .{case_error_list[i]}),
|
||||||
|
"${DIR}",
|
||||||
|
tmp_dir_path_plus_slash,
|
||||||
|
);
|
||||||
|
|
||||||
if (std.mem.indexOf(u8, line, expected) == null) break false;
|
if (std.mem.indexOf(u8, line, expected) == null) break false;
|
||||||
continue;
|
continue;
|
||||||
} else true;
|
} else true;
|
||||||
|
|
@ -789,7 +801,13 @@ pub const TestContext = struct {
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
for (case_error_list) |msg| {
|
for (case_error_list) |msg| {
|
||||||
const expected = try std.fmt.allocPrint(arena, "{s}", .{msg});
|
const expected = try std.mem.replaceOwned(
|
||||||
|
u8,
|
||||||
|
arena,
|
||||||
|
try std.fmt.allocPrint(arena, "{s}", .{msg}),
|
||||||
|
"${DIR}",
|
||||||
|
tmp_dir_path_plus_slash,
|
||||||
|
);
|
||||||
if (std.mem.indexOf(u8, result.stderr, expected) == null) {
|
if (std.mem.indexOf(u8, result.stderr, expected) == null) {
|
||||||
print(
|
print(
|
||||||
\\
|
\\
|
||||||
|
|
@ -971,12 +989,20 @@ pub const TestContext = struct {
|
||||||
const src_path_ok = case_msg.src.src_path.len == 0 or
|
const src_path_ok = case_msg.src.src_path.len == 0 or
|
||||||
std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);
|
std.mem.eql(u8, case_msg.src.src_path, actual_msg.src_path);
|
||||||
|
|
||||||
|
const expected_msg = try std.mem.replaceOwned(
|
||||||
|
u8,
|
||||||
|
arena,
|
||||||
|
case_msg.src.msg,
|
||||||
|
"${DIR}",
|
||||||
|
tmp_dir_path_plus_slash,
|
||||||
|
);
|
||||||
|
|
||||||
if (src_path_ok and
|
if (src_path_ok and
|
||||||
(case_msg.src.line == std.math.maxInt(u32) or
|
(case_msg.src.line == std.math.maxInt(u32) or
|
||||||
actual_msg.line == case_msg.src.line) and
|
actual_msg.line == case_msg.src.line) and
|
||||||
(case_msg.src.column == std.math.maxInt(u32) or
|
(case_msg.src.column == std.math.maxInt(u32) or
|
||||||
actual_msg.column == case_msg.src.column) and
|
actual_msg.column == case_msg.src.column) and
|
||||||
std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
|
std.mem.eql(u8, expected_msg, actual_msg.msg) and
|
||||||
case_msg.src.kind == .@"error")
|
case_msg.src.kind == .@"error")
|
||||||
{
|
{
|
||||||
handled_errors[i] = true;
|
handled_errors[i] = true;
|
||||||
|
|
@ -1012,11 +1038,19 @@ pub const TestContext = struct {
|
||||||
}
|
}
|
||||||
if (ex_tag != .src) continue;
|
if (ex_tag != .src) continue;
|
||||||
|
|
||||||
|
const expected_msg = try std.mem.replaceOwned(
|
||||||
|
u8,
|
||||||
|
arena,
|
||||||
|
case_msg.src.msg,
|
||||||
|
"${DIR}",
|
||||||
|
tmp_dir_path_plus_slash,
|
||||||
|
);
|
||||||
|
|
||||||
if ((case_msg.src.line == std.math.maxInt(u32) or
|
if ((case_msg.src.line == std.math.maxInt(u32) or
|
||||||
actual_msg.line == case_msg.src.line) and
|
actual_msg.line == case_msg.src.line) and
|
||||||
(case_msg.src.column == std.math.maxInt(u32) or
|
(case_msg.src.column == std.math.maxInt(u32) or
|
||||||
actual_msg.column == case_msg.src.column) and
|
actual_msg.column == case_msg.src.column) and
|
||||||
std.mem.eql(u8, case_msg.src.msg, actual_msg.msg) and
|
std.mem.eql(u8, expected_msg, actual_msg.msg) and
|
||||||
case_msg.src.kind == .note)
|
case_msg.src.kind == .note)
|
||||||
{
|
{
|
||||||
handled_errors[i] = true;
|
handled_errors[i] = true;
|
||||||
|
|
|
||||||
|
|
@ -4976,9 +4976,8 @@ pub fn addCases(ctx: *TestContext) !void {
|
||||||
|
|
||||||
ctx.objErrStage1("bad import",
|
ctx.objErrStage1("bad import",
|
||||||
\\const bogus = @import("bogus-does-not-exist.zig",);
|
\\const bogus = @import("bogus-does-not-exist.zig",);
|
||||||
\\export fn entry() void { bogus.bogo(); }
|
|
||||||
, &[_][]const u8{
|
, &[_][]const u8{
|
||||||
"tmp.zig:1:15: error: unable to find 'bogus-does-not-exist.zig'",
|
"tmp.zig:1:23: error: unable to load '${DIR}bogus-does-not-exist.zig': FileNotFound",
|
||||||
});
|
});
|
||||||
|
|
||||||
ctx.objErrStage1("undeclared identifier",
|
ctx.objErrStage1("undeclared identifier",
|
||||||
|
|
|
||||||
Loading…
Add table
Reference in a new issue