stage2: fix not re-loading source file for updates after errors
parent
cf654b52d6
commit
91930a4ff0
|
@ -576,6 +576,8 @@ pub fn update(self: *Module) !void {
|
|||
// TODO Use the cache hash file system to detect which source files changed.
|
||||
// Here we simulate a full cache miss.
|
||||
// Analyze the root source file now.
|
||||
// Source files could have been loaded for any reason; to force a refresh we unload now.
|
||||
self.root_scope.unload(self.allocator);
|
||||
self.analyzeRoot(self.root_scope) catch |err| switch (err) {
|
||||
error.AnalysisFail => {
|
||||
assert(self.totalErrorCount() != 0);
|
||||
|
@ -594,8 +596,11 @@ pub fn update(self: *Module) !void {
|
|||
try self.deleteDecl(decl);
|
||||
}
|
||||
|
||||
// Unload all the source files from memory.
|
||||
self.root_scope.unload(self.allocator);
|
||||
// If there are any errors, we anticipate the source files being loaded
|
||||
// to report error messages. Otherwise we unload all source files to save memory.
|
||||
if (self.totalErrorCount() == 0) {
|
||||
self.root_scope.unload(self.allocator);
|
||||
}
|
||||
|
||||
try self.bin_file.flush();
|
||||
self.link_error_flags = self.bin_file.error_flags;
|
||||
|
@ -878,11 +883,11 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void {
|
|||
const decl = kv.value;
|
||||
deleted_decls.removeAssertDiscard(decl);
|
||||
const new_contents_hash = Decl.hashSimpleName(src_decl.contents);
|
||||
//std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents });
|
||||
if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) {
|
||||
//std.debug.warn("noticed '{}' source changed\n", .{src_decl.name});
|
||||
decl.analysis = .outdated;
|
||||
//std.debug.warn("'{}' {x} => {x}\n", .{ src_decl.name, decl.contents_hash, new_contents_hash });
|
||||
try self.markOutdatedDecl(decl);
|
||||
decl.contents_hash = new_contents_hash;
|
||||
try self.work_queue.writeItem(.{ .re_analyze_decl = decl });
|
||||
}
|
||||
} else if (src_decl.cast(zir.Inst.Export)) |export_inst| {
|
||||
try exports_to_resolve.append(&export_inst.base);
|
||||
|
@ -923,8 +928,7 @@ fn deleteDecl(self: *Module, decl: *Decl) !void {
|
|||
for (decl.dependants.items) |dep| {
|
||||
dep.removeDependency(decl);
|
||||
if (dep.analysis != .outdated) {
|
||||
dep.analysis = .outdated;
|
||||
try self.work_queue.writeItem(.{ .re_analyze_decl = dep });
|
||||
try self.markOutdatedDecl(dep);
|
||||
}
|
||||
}
|
||||
self.deleteDeclExports(decl);
|
||||
|
@ -1083,14 +1087,22 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi
|
|||
.codegen_failure_retryable,
|
||||
.complete,
|
||||
=> if (dep.generation != self.generation) {
|
||||
dep.analysis = .outdated;
|
||||
try self.work_queue.writeItem(.{ .re_analyze_decl = dep });
|
||||
try self.markOutdatedDecl(dep);
|
||||
},
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
|
||||
//std.debug.warn("mark {} outdated\n", .{decl.name});
|
||||
try self.work_queue.writeItem(.{ .re_analyze_decl = decl });
|
||||
if (self.failed_decls.remove(decl)) |entry| {
|
||||
self.allocator.destroy(entry.value);
|
||||
}
|
||||
decl.analysis = .outdated;
|
||||
}
|
||||
|
||||
fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl {
|
||||
const hash = Decl.hashSimpleName(old_inst.name);
|
||||
if (self.decl_table.get(hash)) |kv| {
|
||||
|
@ -1445,6 +1457,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
|
|||
switch (old_inst.tag) {
|
||||
.breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?),
|
||||
.call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?),
|
||||
.compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?),
|
||||
.declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?),
|
||||
.declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?),
|
||||
.str => {
|
||||
|
@ -1484,6 +1497,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In
|
|||
}
|
||||
}
|
||||
|
||||
fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst {
|
||||
return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg});
|
||||
}
|
||||
|
||||
fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst {
|
||||
const b = try self.requireRuntimeBlock(scope, inst.base.src);
|
||||
return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){});
|
||||
|
|
|
@ -407,7 +407,21 @@ fn buildOutputType(
|
|||
std.debug.warn("-fno-emit-bin not supported yet", .{});
|
||||
process.exit(1);
|
||||
},
|
||||
.yes_default_path => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }),
|
||||
.yes_default_path => switch (output_mode) {
|
||||
.Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }),
|
||||
.Lib => blk: {
|
||||
const suffix = switch (link_mode orelse .Static) {
|
||||
.Static => target_info.target.staticLibSuffix(),
|
||||
.Dynamic => target_info.target.dynamicLibSuffix(),
|
||||
};
|
||||
break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{
|
||||
target_info.target.libPrefix(),
|
||||
root_name,
|
||||
suffix,
|
||||
});
|
||||
},
|
||||
.Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }),
|
||||
},
|
||||
.yes => |p| p,
|
||||
};
|
||||
|
||||
|
|
|
@ -27,6 +27,7 @@ pub const Inst = struct {
|
|||
pub const Tag = enum {
|
||||
breakpoint,
|
||||
call,
|
||||
compileerror,
|
||||
/// Represents a pointer to a global decl by name.
|
||||
declref,
|
||||
/// The syntax `@foo` is equivalent to `declval("foo")`.
|
||||
|
@ -62,6 +63,7 @@ pub const Inst = struct {
|
|||
.call => Call,
|
||||
.declref => DeclRef,
|
||||
.declval => DeclVal,
|
||||
.compileerror => CompileError,
|
||||
.str => Str,
|
||||
.int => Int,
|
||||
.ptrtoint => PtrToInt,
|
||||
|
@ -135,6 +137,16 @@ pub const Inst = struct {
|
|||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const CompileError = struct {
|
||||
pub const base_tag = Tag.compileerror;
|
||||
base: Inst,
|
||||
|
||||
positionals: struct {
|
||||
msg: []const u8,
|
||||
},
|
||||
kw_args: struct {},
|
||||
};
|
||||
|
||||
pub const Str = struct {
|
||||
pub const base_tag = Tag.str;
|
||||
base: Inst,
|
||||
|
@ -513,6 +525,7 @@ pub const Module = struct {
|
|||
.call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table),
|
||||
.declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table),
|
||||
.declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table),
|
||||
.compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table),
|
||||
.str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table),
|
||||
.int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table),
|
||||
.ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table),
|
||||
|
@ -917,6 +930,7 @@ const Parser = struct {
|
|||
try requireEatBytes(self, ")");
|
||||
|
||||
inst_specific.base.contents = self.source[contents_start..self.i];
|
||||
//std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents });
|
||||
|
||||
return &inst_specific.base;
|
||||
}
|
||||
|
@ -1230,7 +1244,44 @@ const EmitZIR = struct {
|
|||
var instructions = std.ArrayList(*Inst).init(self.allocator);
|
||||
defer instructions.deinit();
|
||||
|
||||
try self.emitBody(module_fn.analysis.success, &inst_table, &instructions);
|
||||
switch (module_fn.analysis) {
|
||||
.queued => unreachable,
|
||||
.in_progress => unreachable,
|
||||
.success => |body| {
|
||||
try self.emitBody(body, &inst_table, &instructions);
|
||||
},
|
||||
.sema_failure => {
|
||||
const err_msg = self.old_module.failed_decls.getValue(module_fn.owner_decl).?;
|
||||
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
|
||||
fail_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.CompileError.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.msg = try self.arena.allocator.dupe(u8, err_msg.msg),
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try instructions.append(&fail_inst.base);
|
||||
},
|
||||
.dependency_failure => {
|
||||
const fail_inst = try self.arena.allocator.create(Inst.CompileError);
|
||||
fail_inst.* = .{
|
||||
.base = .{
|
||||
.name = try self.autoName(),
|
||||
.src = src,
|
||||
.tag = Inst.CompileError.base_tag,
|
||||
},
|
||||
.positionals = .{
|
||||
.msg = try self.arena.allocator.dupe(u8, "depends on another failed Decl"),
|
||||
},
|
||||
.kw_args = .{},
|
||||
};
|
||||
try instructions.append(&fail_inst.base);
|
||||
},
|
||||
}
|
||||
|
||||
const fn_type = try self.emitType(src, module_fn.fn_type);
|
||||
|
||||
|
|
Loading…
Reference in New Issue