mirror of
https://github.com/ziglang/zig.git
synced 2025-12-23 22:53:06 +00:00
compiler: don't perform semantic analysis if there are files without ZIR
This commit is contained in:
parent
5e20a47469
commit
a8e53801d0
@ -299,7 +299,7 @@ pub fn populateFile(comp: *Compilation, mod: *Module, file: *File) !void {
|
|||||||
|
|
||||||
file.zir = try AstGen.generate(comp.gpa, file.tree.?);
|
file.zir = try AstGen.generate(comp.gpa, file.tree.?);
|
||||||
assert(!file.zir.?.hasCompileErrors()); // builtin.zig must not have astgen errors
|
assert(!file.zir.?.hasCompileErrors()); // builtin.zig must not have astgen errors
|
||||||
file.status = .success_zir;
|
file.status = .success;
|
||||||
// Note that whilst we set `zir` here, we populated `path_digest`
|
// Note that whilst we set `zir` here, we populated `path_digest`
|
||||||
// all the way back in `Package.Module.create`.
|
// all the way back in `Package.Module.create`.
|
||||||
}
|
}
|
||||||
|
|||||||
@ -3203,8 +3203,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
|||||||
}
|
}
|
||||||
|
|
||||||
if (comp.zcu) |zcu| {
|
if (comp.zcu) |zcu| {
|
||||||
const ip = &zcu.intern_pool;
|
|
||||||
|
|
||||||
for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
|
for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
|
||||||
if (error_msg) |msg| {
|
if (error_msg) |msg| {
|
||||||
try addModuleErrorMsg(zcu, &bundle, msg.*);
|
try addModuleErrorMsg(zcu, &bundle, msg.*);
|
||||||
@ -3277,20 +3275,6 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
|||||||
if (!refs.contains(anal_unit)) continue;
|
if (!refs.contains(anal_unit)) continue;
|
||||||
}
|
}
|
||||||
|
|
||||||
report_ok: {
|
|
||||||
const file_index = switch (anal_unit.unwrap()) {
|
|
||||||
.@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
|
|
||||||
.nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
|
|
||||||
.type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
|
|
||||||
.func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
|
|
||||||
.memoized_state => break :report_ok, // always report std.builtin errors
|
|
||||||
};
|
|
||||||
|
|
||||||
// Skip errors for AnalUnits within files that had a parse failure.
|
|
||||||
// We'll try again once parsing succeeds.
|
|
||||||
if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
|
|
||||||
}
|
|
||||||
|
|
||||||
std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{}'", .{
|
std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{}'", .{
|
||||||
error_msg.msg,
|
error_msg.msg,
|
||||||
zcu.fmtAnalUnit(anal_unit),
|
zcu.fmtAnalUnit(anal_unit),
|
||||||
@ -3318,12 +3302,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {
|
for (zcu.failed_codegen.values()) |error_msg| {
|
||||||
if (!zcu.navFileScope(nav).okToReportErrors()) continue;
|
|
||||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
||||||
}
|
}
|
||||||
for (zcu.failed_types.keys(), zcu.failed_types.values()) |ty_index, error_msg| {
|
for (zcu.failed_types.values()) |error_msg| {
|
||||||
if (!zcu.typeFileScope(ty_index).okToReportErrors()) continue;
|
|
||||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
try addModuleErrorMsg(zcu, &bundle, error_msg.*);
|
||||||
}
|
}
|
||||||
for (zcu.failed_exports.values()) |value| {
|
for (zcu.failed_exports.values()) |value| {
|
||||||
@ -3827,12 +3809,35 @@ fn performAllTheWorkInner(
|
|||||||
if (comp.zcu) |zcu| {
|
if (comp.zcu) |zcu| {
|
||||||
const pt: Zcu.PerThread = .activate(zcu, .main);
|
const pt: Zcu.PerThread = .activate(zcu, .main);
|
||||||
defer pt.deactivate();
|
defer pt.deactivate();
|
||||||
|
|
||||||
|
try reportMultiModuleErrors(pt);
|
||||||
|
|
||||||
|
const any_fatal_files = for (zcu.import_table.values()) |file_index| {
|
||||||
|
const file = zcu.fileByIndex(file_index);
|
||||||
|
if (file.getMode() == .zon) continue;
|
||||||
|
switch (file.status) {
|
||||||
|
.never_loaded => unreachable, // everything is loaded by the workers
|
||||||
|
.retryable_failure, .astgen_failure => break true,
|
||||||
|
.success => {},
|
||||||
|
}
|
||||||
|
} else false;
|
||||||
|
|
||||||
|
if (any_fatal_files) {
|
||||||
|
// We give up right now! No updating of ZIR refs, no nothing. The idea is that this prevents
|
||||||
|
// us from invalidating lots of incremental dependencies due to files with e.g. parse errors.
|
||||||
|
// However, this means our analysis data is invalid, so we want to omit all analysis errors.
|
||||||
|
// To do that, let's just clear the analysis roots!
|
||||||
|
|
||||||
|
assert(zcu.failed_files.count() > 0); // we will get an error
|
||||||
|
zcu.analysis_roots.clear(); // no analysis happened
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
if (comp.incremental) {
|
if (comp.incremental) {
|
||||||
const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
|
const update_zir_refs_node = main_progress_node.start("Update ZIR References", 0);
|
||||||
defer update_zir_refs_node.end();
|
defer update_zir_refs_node.end();
|
||||||
try pt.updateZirRefs();
|
try pt.updateZirRefs();
|
||||||
}
|
}
|
||||||
try reportMultiModuleErrors(pt);
|
|
||||||
try zcu.flushRetryableFailures();
|
try zcu.flushRetryableFailures();
|
||||||
|
|
||||||
zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
|
zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
|
||||||
@ -4294,11 +4299,12 @@ fn workerAstGenFile(
|
|||||||
pt.astGenFile(file, path_digest) catch |err| switch (err) {
|
pt.astGenFile(file, path_digest) catch |err| switch (err) {
|
||||||
error.AnalysisFail => return,
|
error.AnalysisFail => return,
|
||||||
else => {
|
else => {
|
||||||
file.status = .retryable_failure;
|
|
||||||
pt.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {
|
pt.reportRetryableAstGenError(src, file_index, err) catch |oom| switch (oom) {
|
||||||
// Swallowing this error is OK because it's implied to be OOM when
|
error.OutOfMemory => {
|
||||||
// there is a missing `failed_files` error message.
|
comp.mutex.lock();
|
||||||
error.OutOfMemory => {},
|
defer comp.mutex.unlock();
|
||||||
|
comp.setAllocFailure();
|
||||||
|
},
|
||||||
};
|
};
|
||||||
return;
|
return;
|
||||||
},
|
},
|
||||||
|
|||||||
@ -488,7 +488,6 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module {
|
|||||||
.zir = null,
|
.zir = null,
|
||||||
.zoir = null,
|
.zoir = null,
|
||||||
.status = .never_loaded,
|
.status = .never_loaded,
|
||||||
.prev_status = .never_loaded,
|
|
||||||
.mod = new,
|
.mod = new,
|
||||||
};
|
};
|
||||||
break :b new;
|
break :b new;
|
||||||
|
|||||||
77
src/Zcu.zig
77
src/Zcu.zig
@ -658,11 +658,27 @@ pub const Namespace = struct {
|
|||||||
};
|
};
|
||||||
|
|
||||||
pub const File = struct {
|
pub const File = struct {
|
||||||
status: Status,
|
|
||||||
prev_status: Status,
|
|
||||||
/// Relative to the owning package's root source directory.
|
/// Relative to the owning package's root source directory.
|
||||||
/// Memory is stored in gpa, owned by File.
|
/// Memory is stored in gpa, owned by File.
|
||||||
sub_file_path: []const u8,
|
sub_file_path: []const u8,
|
||||||
|
|
||||||
|
status: enum {
|
||||||
|
/// We have not yet attempted to load this file.
|
||||||
|
/// `stat` is not populated and may be `undefined`.
|
||||||
|
never_loaded,
|
||||||
|
/// A filesystem access failed. It should be retried on the next update.
|
||||||
|
/// There is a `failed_files` entry containing a non-`null` message.
|
||||||
|
/// `stat` is not populated and may be `undefined`.
|
||||||
|
retryable_failure,
|
||||||
|
/// Parsing/AstGen/ZonGen of this file has failed.
|
||||||
|
/// There is an error in `zir` or `zoir`.
|
||||||
|
/// There is a `failed_files` entry (with a `null` message).
|
||||||
|
/// `stat` is populated.
|
||||||
|
astgen_failure,
|
||||||
|
/// Parsing and AstGen/ZonGen of this file has succeeded.
|
||||||
|
/// `stat` is populated.
|
||||||
|
success,
|
||||||
|
},
|
||||||
/// Whether this is populated depends on `status`.
|
/// Whether this is populated depends on `status`.
|
||||||
stat: Cache.File.Stat,
|
stat: Cache.File.Stat,
|
||||||
|
|
||||||
@ -678,19 +694,17 @@ pub const File = struct {
|
|||||||
/// List of references to this file, used for multi-package errors.
|
/// List of references to this file, used for multi-package errors.
|
||||||
references: std.ArrayListUnmanaged(File.Reference) = .empty,
|
references: std.ArrayListUnmanaged(File.Reference) = .empty,
|
||||||
|
|
||||||
/// The most recent successful ZIR for this file, with no errors.
|
/// The ZIR for this file from the last update with no file failures. As such, this ZIR is never
|
||||||
/// This is only populated when a previously successful ZIR
|
/// failed (although it may have compile errors).
|
||||||
/// newly introduces compile errors during an update. When ZIR is
|
///
|
||||||
/// successful, this field is unloaded.
|
/// Because updates with file failures do not perform ZIR mapping or semantic analysis, we keep
|
||||||
|
/// this around so we have the "old" ZIR to map when an update is ready to do so. Once such an
|
||||||
|
/// update occurs, this field is unloaded, since it is no longer necessary.
|
||||||
|
///
|
||||||
|
/// In other words, if `TrackedInst`s are tied to ZIR other than what's in the `zir` field, this
|
||||||
|
/// field is populated with that old ZIR.
|
||||||
prev_zir: ?*Zir = null,
|
prev_zir: ?*Zir = null,
|
||||||
|
|
||||||
pub const Status = enum {
|
|
||||||
never_loaded,
|
|
||||||
retryable_failure,
|
|
||||||
astgen_failure,
|
|
||||||
success_zir,
|
|
||||||
};
|
|
||||||
|
|
||||||
/// A single reference to a file.
|
/// A single reference to a file.
|
||||||
pub const Reference = union(enum) {
|
pub const Reference = union(enum) {
|
||||||
/// The file is imported directly (i.e. not as a package) with @import.
|
/// The file is imported directly (i.e. not as a package) with @import.
|
||||||
@ -763,7 +777,7 @@ pub const File = struct {
|
|||||||
return error.FileTooBig;
|
return error.FileTooBig;
|
||||||
|
|
||||||
const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
|
const source = try gpa.allocSentinel(u8, @as(usize, @intCast(stat.size)), 0);
|
||||||
defer gpa.free(source);
|
errdefer gpa.free(source);
|
||||||
|
|
||||||
const amt = try f.readAll(source);
|
const amt = try f.readAll(source);
|
||||||
if (amt != stat.size)
|
if (amt != stat.size)
|
||||||
@ -773,8 +787,9 @@ pub const File = struct {
|
|||||||
// used for error reporting. We need to keep the stat fields stale so that
|
// used for error reporting. We need to keep the stat fields stale so that
|
||||||
// astGenFile can know to regenerate ZIR.
|
// astGenFile can know to regenerate ZIR.
|
||||||
|
|
||||||
errdefer comptime unreachable; // don't error after populating `source`
|
|
||||||
file.source = source;
|
file.source = source;
|
||||||
|
errdefer comptime unreachable; // don't error after populating `source`
|
||||||
|
|
||||||
return .{
|
return .{
|
||||||
.bytes = source,
|
.bytes = source,
|
||||||
.stat = .{
|
.stat = .{
|
||||||
@ -849,13 +864,6 @@ pub const File = struct {
|
|||||||
std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
|
std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn okToReportErrors(file: File) bool {
|
|
||||||
return switch (file.status) {
|
|
||||||
.astgen_failure => false,
|
|
||||||
else => true,
|
|
||||||
};
|
|
||||||
}
|
|
||||||
|
|
||||||
/// Add a reference to this file during AstGen.
|
/// Add a reference to this file during AstGen.
|
||||||
pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {
|
pub fn addReference(file: *File, zcu: *Zcu, ref: File.Reference) !void {
|
||||||
// Don't add the same module root twice. Note that since we always add module roots at the
|
// Don't add the same module root twice. Note that since we always add module roots at the
|
||||||
@ -3295,19 +3303,6 @@ pub fn optimizeMode(zcu: *const Zcu) std.builtin.OptimizeMode {
|
|||||||
return zcu.root_mod.optimize_mode;
|
return zcu.root_mod.optimize_mode;
|
||||||
}
|
}
|
||||||
|
|
||||||
fn lockAndClearFileCompileError(zcu: *Zcu, file: *File) void {
|
|
||||||
switch (file.status) {
|
|
||||||
.success_zir, .retryable_failure => {},
|
|
||||||
.never_loaded, .astgen_failure => {
|
|
||||||
zcu.comp.mutex.lock();
|
|
||||||
defer zcu.comp.mutex.unlock();
|
|
||||||
if (zcu.failed_files.fetchSwapRemove(file)) |kv| {
|
|
||||||
if (kv.value) |msg| msg.destroy(zcu.gpa); // Delete previous error message.
|
|
||||||
}
|
|
||||||
},
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
pub fn handleUpdateExports(
|
pub fn handleUpdateExports(
|
||||||
zcu: *Zcu,
|
zcu: *Zcu,
|
||||||
export_indices: []const Export.Index,
|
export_indices: []const Export.Index,
|
||||||
@ -3662,9 +3657,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
|||||||
// `test` declarations are analyzed depending on the test filter.
|
// `test` declarations are analyzed depending on the test filter.
|
||||||
const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;
|
const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
// If the file failed AstGen, the TrackedInst refers to the old ZIR.
|
const decl = file.zir.?.getDeclaration(inst_info.inst);
|
||||||
const zir = if (file.status == .success_zir) file.zir.? else file.prev_zir.?.*;
|
|
||||||
const decl = zir.getDeclaration(inst_info.inst);
|
|
||||||
|
|
||||||
if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
|
if (!comp.config.is_test or file.mod != zcu.main_mod) continue;
|
||||||
|
|
||||||
@ -3694,9 +3687,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
|||||||
// These are named declarations. They are analyzed only if marked `export`.
|
// These are named declarations. They are analyzed only if marked `export`.
|
||||||
const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
|
const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
// If the file failed AstGen, the TrackedInst refers to the old ZIR.
|
const decl = file.zir.?.getDeclaration(inst_info.inst);
|
||||||
const zir = if (file.status == .success_zir) file.zir.? else file.prev_zir.?.*;
|
|
||||||
const decl = zir.getDeclaration(inst_info.inst);
|
|
||||||
if (decl.linkage == .@"export") {
|
if (decl.linkage == .@"export") {
|
||||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
||||||
if (!result.contains(unit)) {
|
if (!result.contains(unit)) {
|
||||||
@ -3712,9 +3703,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
|
|||||||
// These are named declarations. They are analyzed only if marked `export`.
|
// These are named declarations. They are analyzed only if marked `export`.
|
||||||
const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
|
const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
// If the file failed AstGen, the TrackedInst refers to the old ZIR.
|
const decl = file.zir.?.getDeclaration(inst_info.inst);
|
||||||
const zir = if (file.status == .success_zir) file.zir.? else file.prev_zir.?.*;
|
|
||||||
const decl = zir.getDeclaration(inst_info.inst);
|
|
||||||
if (decl.linkage == .@"export") {
|
if (decl.linkage == .@"export") {
|
||||||
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
const unit: AnalUnit = .wrap(.{ .nav_val = nav });
|
||||||
if (!result.contains(unit)) {
|
if (!result.contains(unit)) {
|
||||||
|
|||||||
@ -109,7 +109,7 @@ pub fn astGenFile(
|
|||||||
|
|
||||||
break :lock .shared;
|
break :lock .shared;
|
||||||
},
|
},
|
||||||
.astgen_failure, .success_zir => lock: {
|
.astgen_failure, .success => lock: {
|
||||||
const unchanged_metadata =
|
const unchanged_metadata =
|
||||||
stat.size == file.stat.size and
|
stat.size == file.stat.size and
|
||||||
stat.mtime == file.stat.mtime and
|
stat.mtime == file.stat.mtime and
|
||||||
@ -214,8 +214,7 @@ pub fn astGenFile(
|
|||||||
.inode = header.stat_inode,
|
.inode = header.stat_inode,
|
||||||
.mtime = header.stat_mtime,
|
.mtime = header.stat_mtime,
|
||||||
};
|
};
|
||||||
file.prev_status = file.status;
|
file.status = .success;
|
||||||
file.status = .success_zir;
|
|
||||||
log.debug("AstGen cached success: {s}", .{file.sub_file_path});
|
log.debug("AstGen cached success: {s}", .{file.sub_file_path});
|
||||||
|
|
||||||
if (file.zir.?.hasCompileErrors()) {
|
if (file.zir.?.hasCompileErrors()) {
|
||||||
@ -248,19 +247,11 @@ pub fn astGenFile(
|
|||||||
|
|
||||||
pt.lockAndClearFileCompileError(file);
|
pt.lockAndClearFileCompileError(file);
|
||||||
|
|
||||||
// Previous ZIR is kept for two reasons:
|
// If `zir` is not null, and `prev_zir` is null, then `TrackedInst`s are associated with `zir`.
|
||||||
//
|
// We need to keep it around!
|
||||||
// 1. In case an update to the file causes a Parse or AstGen failure, we
|
// As an optimization, also check `loweringFailed`; if true, but `prev_zir == null`, then this
|
||||||
// need to compare two successful ZIR files in order to proceed with an
|
// file has never passed AstGen, so we actually need not cache the old ZIR.
|
||||||
// incremental update. This avoids needlessly tossing out semantic
|
if (file.zir != null and file.prev_zir == null and !file.zir.?.loweringFailed()) {
|
||||||
// analysis work when an error is temporarily introduced.
|
|
||||||
//
|
|
||||||
// 2. In order to detect updates, we need to iterate over the intern pool
|
|
||||||
// values while comparing old ZIR to new ZIR. This is better done in a
|
|
||||||
// single-threaded context, so we need to keep both versions around
|
|
||||||
// until that point in the pipeline. Previous ZIR data is freed after
|
|
||||||
// that.
|
|
||||||
if (file.zir != null and !file.zir.?.loweringFailed()) {
|
|
||||||
assert(file.prev_zir == null);
|
assert(file.prev_zir == null);
|
||||||
const prev_zir_ptr = try gpa.create(Zir);
|
const prev_zir_ptr = try gpa.create(Zir);
|
||||||
file.prev_zir = prev_zir_ptr;
|
file.prev_zir = prev_zir_ptr;
|
||||||
@ -289,8 +280,7 @@ pub fn astGenFile(
|
|||||||
|
|
||||||
// Any potential AST errors are converted to ZIR errors here.
|
// Any potential AST errors are converted to ZIR errors here.
|
||||||
file.zir = try AstGen.generate(gpa, file.tree.?);
|
file.zir = try AstGen.generate(gpa, file.tree.?);
|
||||||
file.prev_status = file.status;
|
file.status = .success;
|
||||||
file.status = .success_zir;
|
|
||||||
log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
|
log.debug("AstGen fresh success: {s}", .{file.sub_file_path});
|
||||||
|
|
||||||
const safety_buffer = if (Zcu.data_has_safety_tag)
|
const safety_buffer = if (Zcu.data_has_safety_tag)
|
||||||
@ -383,9 +373,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
|||||||
defer cleanupUpdatedFiles(gpa, &updated_files);
|
defer cleanupUpdatedFiles(gpa, &updated_files);
|
||||||
for (zcu.import_table.values()) |file_index| {
|
for (zcu.import_table.values()) |file_index| {
|
||||||
const file = zcu.fileByIndex(file_index);
|
const file = zcu.fileByIndex(file_index);
|
||||||
if (file.prev_status != file.status and file.prev_status != .never_loaded) {
|
assert(file.status == .success);
|
||||||
try zcu.markDependeeOutdated(.not_marked_po, .{ .file = file_index });
|
|
||||||
}
|
|
||||||
const old_zir = file.prev_zir orelse continue;
|
const old_zir = file.prev_zir orelse continue;
|
||||||
const new_zir = file.zir.?;
|
const new_zir = file.zir.?;
|
||||||
const gop = try updated_files.getOrPut(gpa, file_index);
|
const gop = try updated_files.getOrPut(gpa, file_index);
|
||||||
@ -394,10 +382,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
|||||||
.file = file,
|
.file = file,
|
||||||
.inst_map = .{},
|
.inst_map = .{},
|
||||||
};
|
};
|
||||||
if (!new_zir.loweringFailed()) {
|
|
||||||
try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, &gop.value_ptr.inst_map);
|
try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, &gop.value_ptr.inst_map);
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
if (updated_files.count() == 0)
|
if (updated_files.count() == 0)
|
||||||
return;
|
return;
|
||||||
@ -416,13 +402,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
|||||||
.index = @intCast(tracked_inst_unwrapped_index),
|
.index = @intCast(tracked_inst_unwrapped_index),
|
||||||
}).wrap(ip);
|
}).wrap(ip);
|
||||||
const new_inst = updated_file.inst_map.get(old_inst) orelse {
|
const new_inst = updated_file.inst_map.get(old_inst) orelse {
|
||||||
// Tracking failed for this instruction.
|
// Tracking failed for this instruction due to changes in the ZIR.
|
||||||
// This may be due to changes in the ZIR, or AstGen might have failed due to a very broken file.
|
// Invalidate associated `src_hash` deps.
|
||||||
// Either way, invalidate associated `src_hash` deps.
|
log.debug("tracking failed for %{d}", .{old_inst});
|
||||||
log.debug("tracking failed for %{d}{s}", .{
|
|
||||||
old_inst,
|
|
||||||
if (file.zir.?.loweringFailed()) " due to AstGen failure" else "",
|
|
||||||
});
|
|
||||||
tracked_inst.inst = .lost;
|
tracked_inst.inst = .lost;
|
||||||
try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });
|
try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index });
|
||||||
continue;
|
continue;
|
||||||
@ -527,10 +509,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
|||||||
|
|
||||||
for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
|
for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
|
||||||
const file = updated_file.file;
|
const file = updated_file.file;
|
||||||
if (file.zir.?.loweringFailed()) {
|
|
||||||
// Keep `prev_zir` around: it's the last usable ZIR.
|
|
||||||
// Don't update the namespace, as we have no new data to update *to*.
|
|
||||||
} else {
|
|
||||||
const prev_zir = file.prev_zir.?;
|
const prev_zir = file.prev_zir.?;
|
||||||
file.prev_zir = null;
|
file.prev_zir = null;
|
||||||
prev_zir.deinit(gpa);
|
prev_zir.deinit(gpa);
|
||||||
@ -545,7 +524,6 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
|||||||
try pt.updateFileNamespace(file_index);
|
try pt.updateFileNamespace(file_index);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
|
||||||
|
|
||||||
/// Ensures that `zcu.fileRootType` on this `file_index` gives an up-to-date answer.
|
/// Ensures that `zcu.fileRootType` on this `file_index` gives an up-to-date answer.
|
||||||
/// Returns `error.AnalysisFail` if the file has an error.
|
/// Returns `error.AnalysisFail` if the file has an error.
|
||||||
@ -745,6 +723,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
|
|||||||
kv.value.destroy(gpa);
|
kv.value.destroy(gpa);
|
||||||
}
|
}
|
||||||
_ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
|
_ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
|
||||||
|
zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
// We can trust the current information about this unit.
|
// We can trust the current information about this unit.
|
||||||
@ -796,15 +775,8 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
|
|||||||
|
|
||||||
const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
||||||
const file = zcu.fileByIndex(inst_resolved.file);
|
const file = zcu.fileByIndex(inst_resolved.file);
|
||||||
// TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
|
|
||||||
// unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
|
|
||||||
// in `ensureComptimeUnitUpToDate`.
|
|
||||||
if (file.status != .success_zir) return error.AnalysisFail;
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
// We are about to re-analyze this unit; drop its depenndencies.
|
|
||||||
zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
|
|
||||||
|
|
||||||
try zcu.analysis_in_progress.put(gpa, anal_unit, {});
|
try zcu.analysis_in_progress.put(gpa, anal_unit, {});
|
||||||
defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
|
defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
|
||||||
|
|
||||||
@ -923,6 +895,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
|
|||||||
kv.value.destroy(gpa);
|
kv.value.destroy(gpa);
|
||||||
}
|
}
|
||||||
_ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
|
_ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
|
||||||
|
ip.removeDependenciesForDepender(gpa, anal_unit);
|
||||||
} else {
|
} else {
|
||||||
// We can trust the current information about this unit.
|
// We can trust the current information about this unit.
|
||||||
if (prev_failed) return error.AnalysisFail;
|
if (prev_failed) return error.AnalysisFail;
|
||||||
@ -993,15 +966,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
|
|||||||
|
|
||||||
const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
||||||
const file = zcu.fileByIndex(inst_resolved.file);
|
const file = zcu.fileByIndex(inst_resolved.file);
|
||||||
// TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
|
|
||||||
// unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
|
|
||||||
// in `ensureComptimeUnitUpToDate`.
|
|
||||||
if (file.status != .success_zir) return error.AnalysisFail;
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
// We are about to re-analyze this unit; drop its depenndencies.
|
|
||||||
zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
|
|
||||||
|
|
||||||
try zcu.analysis_in_progress.put(gpa, anal_unit, {});
|
try zcu.analysis_in_progress.put(gpa, anal_unit, {});
|
||||||
errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
|
errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
|
||||||
|
|
||||||
@ -1301,6 +1267,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
|
|||||||
kv.value.destroy(gpa);
|
kv.value.destroy(gpa);
|
||||||
}
|
}
|
||||||
_ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
|
_ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
|
||||||
|
ip.removeDependenciesForDepender(gpa, anal_unit);
|
||||||
} else {
|
} else {
|
||||||
// We can trust the current information about this unit.
|
// We can trust the current information about this unit.
|
||||||
if (prev_failed) return error.AnalysisFail;
|
if (prev_failed) return error.AnalysisFail;
|
||||||
@ -1371,15 +1338,8 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
|
|||||||
|
|
||||||
const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
||||||
const file = zcu.fileByIndex(inst_resolved.file);
|
const file = zcu.fileByIndex(inst_resolved.file);
|
||||||
// TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is
|
|
||||||
// unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends
|
|
||||||
// in `ensureComptimeUnitUpToDate`.
|
|
||||||
if (file.status != .success_zir) return error.AnalysisFail;
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
// We are about to re-analyze this unit; drop its depenndencies.
|
|
||||||
zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
|
|
||||||
|
|
||||||
try zcu.analysis_in_progress.put(gpa, anal_unit, {});
|
try zcu.analysis_in_progress.put(gpa, anal_unit, {});
|
||||||
defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
|
defer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
|
||||||
|
|
||||||
@ -1828,7 +1788,6 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
|
|||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
|
|
||||||
const file = zcu.fileByIndex(file_index);
|
const file = zcu.fileByIndex(file_index);
|
||||||
assert(file.status == .success_zir);
|
|
||||||
const file_root_type = zcu.fileRootType(file_index);
|
const file_root_type = zcu.fileRootType(file_index);
|
||||||
if (file_root_type == .none) return;
|
if (file_root_type == .none) return;
|
||||||
|
|
||||||
@ -1865,9 +1824,6 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
|||||||
assert(file.getMode() == .zig);
|
assert(file.getMode() == .zig);
|
||||||
assert(zcu.fileRootType(file_index) == .none);
|
assert(zcu.fileRootType(file_index) == .none);
|
||||||
|
|
||||||
if (file.status != .success_zir) {
|
|
||||||
return error.AnalysisFail;
|
|
||||||
}
|
|
||||||
assert(file.zir != null);
|
assert(file.zir != null);
|
||||||
|
|
||||||
const new_namespace_index = try pt.createNamespace(.{
|
const new_namespace_index = try pt.createNamespace(.{
|
||||||
@ -1910,7 +1866,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
|
pub fn importPkg(pt: Zcu.PerThread, mod: *Module) Allocator.Error!Zcu.ImportFileResult {
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const gpa = zcu.gpa;
|
const gpa = zcu.gpa;
|
||||||
|
|
||||||
@ -1984,7 +1940,6 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
|
|||||||
.zir = null,
|
.zir = null,
|
||||||
.zoir = null,
|
.zoir = null,
|
||||||
.status = .never_loaded,
|
.status = .never_loaded,
|
||||||
.prev_status = .never_loaded,
|
|
||||||
.mod = mod,
|
.mod = mod,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -1997,13 +1952,19 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult {
|
|||||||
};
|
};
|
||||||
}
|
}
|
||||||
|
|
||||||
/// Called from a worker thread during AstGen.
|
/// Called from a worker thread during AstGen (with the Compilation mutex held).
|
||||||
/// Also called from Sema during semantic analysis.
|
/// Also called from Sema during semantic analysis.
|
||||||
|
/// Does not attempt to load the file from disk; just returns a corresponding `*Zcu.File`.
|
||||||
pub fn importFile(
|
pub fn importFile(
|
||||||
pt: Zcu.PerThread,
|
pt: Zcu.PerThread,
|
||||||
cur_file: *Zcu.File,
|
cur_file: *Zcu.File,
|
||||||
import_string: []const u8,
|
import_string: []const u8,
|
||||||
) !Zcu.ImportFileResult {
|
) error{
|
||||||
|
OutOfMemory,
|
||||||
|
ModuleNotFound,
|
||||||
|
ImportOutsideModulePath,
|
||||||
|
CurrentWorkingDirectoryUnlinked,
|
||||||
|
}!Zcu.ImportFileResult {
|
||||||
const zcu = pt.zcu;
|
const zcu = pt.zcu;
|
||||||
const mod = cur_file.mod;
|
const mod = cur_file.mod;
|
||||||
|
|
||||||
@ -2061,7 +2022,10 @@ pub fn importFile(
|
|||||||
defer gpa.free(resolved_root_path);
|
defer gpa.free(resolved_root_path);
|
||||||
|
|
||||||
const sub_file_path = p: {
|
const sub_file_path = p: {
|
||||||
const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path);
|
const relative = std.fs.path.relative(gpa, resolved_root_path, resolved_path) catch |err| switch (err) {
|
||||||
|
error.Unexpected => unreachable,
|
||||||
|
else => |e| return e,
|
||||||
|
};
|
||||||
errdefer gpa.free(relative);
|
errdefer gpa.free(relative);
|
||||||
|
|
||||||
if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
|
if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) {
|
||||||
@ -2089,13 +2053,15 @@ pub fn importFile(
|
|||||||
gop.value_ptr.* = new_file_index;
|
gop.value_ptr.* = new_file_index;
|
||||||
new_file.* = .{
|
new_file.* = .{
|
||||||
.sub_file_path = sub_file_path,
|
.sub_file_path = sub_file_path,
|
||||||
|
|
||||||
|
.status = .never_loaded,
|
||||||
.stat = undefined,
|
.stat = undefined,
|
||||||
|
|
||||||
.source = null,
|
.source = null,
|
||||||
.tree = null,
|
.tree = null,
|
||||||
.zir = null,
|
.zir = null,
|
||||||
.zoir = null,
|
.zoir = null,
|
||||||
.status = .never_loaded,
|
|
||||||
.prev_status = .never_loaded,
|
|
||||||
.mod = mod,
|
.mod = mod,
|
||||||
};
|
};
|
||||||
|
|
||||||
@ -2835,7 +2801,7 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err
|
|||||||
/// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry.
|
/// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry.
|
||||||
fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
|
fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void {
|
||||||
const zir = file.zir orelse return;
|
const zir = file.zir orelse return;
|
||||||
if (zir.hasCompileErrors()) return;
|
if (!zir.hasCompileErrors()) return;
|
||||||
|
|
||||||
pt.zcu.comp.mutex.lock();
|
pt.zcu.comp.mutex.lock();
|
||||||
defer pt.zcu.comp.mutex.unlock();
|
defer pt.zcu.comp.mutex.unlock();
|
||||||
@ -3196,6 +3162,7 @@ pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Inde
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
/// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`.
|
||||||
pub fn reportRetryableAstGenError(
|
pub fn reportRetryableAstGenError(
|
||||||
pt: Zcu.PerThread,
|
pt: Zcu.PerThread,
|
||||||
src: Zcu.AstGenSrc,
|
src: Zcu.AstGenSrc,
|
||||||
@ -3231,13 +3198,18 @@ pub fn reportRetryableAstGenError(
|
|||||||
});
|
});
|
||||||
errdefer err_msg.destroy(gpa);
|
errdefer err_msg.destroy(gpa);
|
||||||
|
|
||||||
{
|
|
||||||
zcu.comp.mutex.lock();
|
zcu.comp.mutex.lock();
|
||||||
defer zcu.comp.mutex.unlock();
|
defer zcu.comp.mutex.unlock();
|
||||||
try zcu.failed_files.putNoClobber(gpa, file, err_msg);
|
const gop = try zcu.failed_files.getOrPut(gpa, file);
|
||||||
|
if (gop.found_existing) {
|
||||||
|
if (gop.value_ptr.*) |old_err_msg| {
|
||||||
|
old_err_msg.destroy(gpa);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
gop.value_ptr.* = err_msg;
|
||||||
|
}
|
||||||
|
|
||||||
|
/// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`.
|
||||||
pub fn reportRetryableFileError(
|
pub fn reportRetryableFileError(
|
||||||
pt: Zcu.PerThread,
|
pt: Zcu.PerThread,
|
||||||
file_index: Zcu.File.Index,
|
file_index: Zcu.File.Index,
|
||||||
@ -3771,7 +3743,6 @@ fn recreateStructType(
|
|||||||
|
|
||||||
const inst_info = key.zir_index.resolveFull(ip).?;
|
const inst_info = key.zir_index.resolveFull(ip).?;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
assert(file.status == .success_zir); // otherwise inst tracking failed
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
||||||
@ -3844,7 +3815,6 @@ fn recreateUnionType(
|
|||||||
|
|
||||||
const inst_info = key.zir_index.resolveFull(ip).?;
|
const inst_info = key.zir_index.resolveFull(ip).?;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
assert(file.status == .success_zir); // otherwise inst tracking failed
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
||||||
@ -3931,7 +3901,6 @@ fn recreateEnumType(
|
|||||||
|
|
||||||
const inst_info = key.zir_index.resolveFull(ip).?;
|
const inst_info = key.zir_index.resolveFull(ip).?;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
assert(file.status == .success_zir); // otherwise inst tracking failed
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
||||||
@ -4075,7 +4044,6 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
|
|||||||
|
|
||||||
const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
||||||
const file = zcu.fileByIndex(inst_info.file);
|
const file = zcu.fileByIndex(inst_info.file);
|
||||||
if (file.status != .success_zir) return error.AnalysisFail;
|
|
||||||
const zir = file.zir.?;
|
const zir = file.zir.?;
|
||||||
|
|
||||||
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
|
||||||
|
|||||||
@ -6134,7 +6134,6 @@ fn cmdAstCheck(
|
|||||||
|
|
||||||
var file: Zcu.File = .{
|
var file: Zcu.File = .{
|
||||||
.status = .never_loaded,
|
.status = .never_loaded,
|
||||||
.prev_status = .never_loaded,
|
|
||||||
.sub_file_path = undefined,
|
.sub_file_path = undefined,
|
||||||
.stat = undefined,
|
.stat = undefined,
|
||||||
.source = null,
|
.source = null,
|
||||||
@ -6512,7 +6511,6 @@ fn cmdDumpZir(
|
|||||||
|
|
||||||
var file: Zcu.File = .{
|
var file: Zcu.File = .{
|
||||||
.status = .never_loaded,
|
.status = .never_loaded,
|
||||||
.prev_status = .never_loaded,
|
|
||||||
.sub_file_path = undefined,
|
.sub_file_path = undefined,
|
||||||
.stat = undefined,
|
.stat = undefined,
|
||||||
.source = null,
|
.source = null,
|
||||||
@ -6578,7 +6576,6 @@ fn cmdChangelist(
|
|||||||
|
|
||||||
var file: Zcu.File = .{
|
var file: Zcu.File = .{
|
||||||
.status = .never_loaded,
|
.status = .never_loaded,
|
||||||
.prev_status = .never_loaded,
|
|
||||||
.sub_file_path = old_source_file,
|
.sub_file_path = old_source_file,
|
||||||
.stat = .{
|
.stat = .{
|
||||||
.size = stat.size,
|
.size = stat.size,
|
||||||
|
|||||||
Loading…
x
Reference in New Issue
Block a user