mirror of
https://github.com/ziglang/zig.git
synced 2024-11-27 07:32:44 +00:00
frontend: incremental progress
This commit makes more progress towards incremental compilation, fixing some crashes in the frontend. Notably, it fixes the regressions introduced by #20964. It also cleans up the "outdated file root" mechanism, by virtue of deleting it: we now detect outdated file roots just after updating ZIR refs, and re-scan their namespaces.
This commit is contained in:
parent
2b05e85107
commit
895267c916
@ -3081,7 +3081,7 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
|
||||
for (zcu.failed_analysis.keys()) |anal_unit| {
|
||||
const file_index = switch (anal_unit.unwrap()) {
|
||||
.cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
|
||||
.func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip).file,
|
||||
.func => |ip_index| (zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip) orelse continue).file,
|
||||
};
|
||||
if (zcu.fileByIndex(file_index).okToReportErrors()) {
|
||||
total += 1;
|
||||
@ -3091,11 +3091,13 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
|
||||
}
|
||||
}
|
||||
|
||||
if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {
|
||||
total += 1;
|
||||
for (zcu.failed_codegen.keys()) |nav| {
|
||||
if (zcu.navFileScope(nav).okToReportErrors()) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
|
||||
for (zcu.failed_codegen.keys()) |_| {
|
||||
if (zcu.intern_pool.global_error_set.getNamesFromMainThread().len > zcu.error_limit) {
|
||||
total += 1;
|
||||
}
|
||||
}
|
||||
@ -3114,7 +3116,13 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
|
||||
}
|
||||
}
|
||||
|
||||
return @as(u32, @intCast(total));
|
||||
if (comp.module) |zcu| {
|
||||
if (total == 0 and zcu.transitive_failed_analysis.count() > 0) {
|
||||
@panic("Transitive analysis errors, but none actually emitted");
|
||||
}
|
||||
}
|
||||
|
||||
return @intCast(total);
|
||||
}
|
||||
|
||||
/// This function is temporally single-threaded.
|
||||
@ -3214,7 +3222,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
|
||||
const file_index = switch (anal_unit.unwrap()) {
|
||||
.cau => |cau| zcu.namespacePtr(ip.getCau(cau).namespace).file_scope,
|
||||
.func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip).file,
|
||||
.func => |ip_index| (zcu.funcInfo(ip_index).zir_body_inst.resolveFull(ip) orelse continue).file,
|
||||
};
|
||||
|
||||
// Skip errors for AnalUnits within files that had a parse failure.
|
||||
@ -3243,7 +3251,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
|
||||
}
|
||||
}
|
||||
}
|
||||
for (zcu.failed_codegen.values()) |error_msg| {
|
||||
for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| {
|
||||
if (!zcu.navFileScope(nav).okToReportErrors()) continue;
|
||||
try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
|
||||
}
|
||||
for (zcu.failed_exports.values()) |value| {
|
||||
@ -3608,10 +3617,9 @@ fn performAllTheWorkInner(
|
||||
// Pre-load these things from our single-threaded context since they
|
||||
// will be needed by the worker threads.
|
||||
const path_digest = zcu.filePathDigest(file_index);
|
||||
const old_root_type = zcu.fileRootType(file_index);
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
comp.thread_pool.spawnWgId(&astgen_wait_group, workerAstGenFile, .{
|
||||
comp, file, file_index, path_digest, old_root_type, zir_prog_node, &astgen_wait_group, .root,
|
||||
comp, file, file_index, path_digest, zir_prog_node, &astgen_wait_group, .root,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -3649,6 +3657,7 @@ fn performAllTheWorkInner(
|
||||
}
|
||||
try reportMultiModuleErrors(pt);
|
||||
try zcu.flushRetryableFailures();
|
||||
|
||||
zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0);
|
||||
zcu.codegen_prog_node = main_progress_node.start("Code Generation", 0);
|
||||
}
|
||||
@ -4283,7 +4292,6 @@ fn workerAstGenFile(
|
||||
file: *Zcu.File,
|
||||
file_index: Zcu.File.Index,
|
||||
path_digest: Cache.BinDigest,
|
||||
old_root_type: InternPool.Index,
|
||||
prog_node: std.Progress.Node,
|
||||
wg: *WaitGroup,
|
||||
src: Zcu.AstGenSrc,
|
||||
@ -4292,7 +4300,7 @@ fn workerAstGenFile(
|
||||
defer child_prog_node.end();
|
||||
|
||||
const pt: Zcu.PerThread = .{ .zcu = comp.module.?, .tid = @enumFromInt(tid) };
|
||||
pt.astGenFile(file, path_digest, old_root_type) catch |err| switch (err) {
|
||||
pt.astGenFile(file, path_digest) catch |err| switch (err) {
|
||||
error.AnalysisFail => return,
|
||||
else => {
|
||||
file.status = .retryable_failure;
|
||||
@ -4323,7 +4331,7 @@ fn workerAstGenFile(
|
||||
// `@import("builtin")` is handled specially.
|
||||
if (mem.eql(u8, import_path, "builtin")) continue;
|
||||
|
||||
const import_result, const imported_path_digest, const imported_root_type = blk: {
|
||||
const import_result, const imported_path_digest = blk: {
|
||||
comp.mutex.lock();
|
||||
defer comp.mutex.unlock();
|
||||
|
||||
@ -4338,8 +4346,7 @@ fn workerAstGenFile(
|
||||
comp.appendFileSystemInput(fsi, res.file.mod.root, res.file.sub_file_path) catch continue;
|
||||
};
|
||||
const imported_path_digest = pt.zcu.filePathDigest(res.file_index);
|
||||
const imported_root_type = pt.zcu.fileRootType(res.file_index);
|
||||
break :blk .{ res, imported_path_digest, imported_root_type };
|
||||
break :blk .{ res, imported_path_digest };
|
||||
};
|
||||
if (import_result.is_new) {
|
||||
log.debug("AstGen of {s} has import '{s}'; queuing AstGen of {s}", .{
|
||||
@ -4350,7 +4357,7 @@ fn workerAstGenFile(
|
||||
.import_tok = item.data.token,
|
||||
} };
|
||||
comp.thread_pool.spawnWgId(wg, workerAstGenFile, .{
|
||||
comp, import_result.file, import_result.file_index, imported_path_digest, imported_root_type, prog_node, wg, sub_src,
|
||||
comp, import_result.file, import_result.file_index, imported_path_digest, prog_node, wg, sub_src,
|
||||
});
|
||||
}
|
||||
}
|
||||
@ -6443,7 +6450,8 @@ fn buildOutputFromZig(
|
||||
|
||||
try comp.updateSubCompilation(sub_compilation, misc_task_tag, prog_node);
|
||||
|
||||
assert(out.* == null);
|
||||
// Under incremental compilation, `out` may already be populated from a prior update.
|
||||
assert(out.* == null or comp.incremental);
|
||||
out.* = try sub_compilation.toCrtFile();
|
||||
}
|
||||
|
||||
|
@ -65,19 +65,49 @@ pub const single_threaded = builtin.single_threaded or !want_multi_threaded;
|
||||
pub const TrackedInst = extern struct {
|
||||
file: FileIndex,
|
||||
inst: Zir.Inst.Index,
|
||||
comptime {
|
||||
// The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`.
|
||||
assert(@sizeOf(@This()) == @sizeOf(FileIndex) + @sizeOf(Zir.Inst.Index));
|
||||
}
|
||||
|
||||
pub const MaybeLost = extern struct {
|
||||
file: FileIndex,
|
||||
inst: ZirIndex,
|
||||
pub const ZirIndex = enum(u32) {
|
||||
/// Tracking failed for this ZIR instruction. Uses of it should fail.
|
||||
lost = std.math.maxInt(u32),
|
||||
_,
|
||||
pub fn unwrap(inst: ZirIndex) ?Zir.Inst.Index {
|
||||
return switch (inst) {
|
||||
.lost => null,
|
||||
_ => @enumFromInt(@intFromEnum(inst)),
|
||||
};
|
||||
}
|
||||
pub fn wrap(inst: Zir.Inst.Index) ZirIndex {
|
||||
return @enumFromInt(@intFromEnum(inst));
|
||||
}
|
||||
};
|
||||
comptime {
|
||||
// The fields should be tightly packed. See also serialiation logic in `Compilation.saveState`.
|
||||
assert(@sizeOf(@This()) == @sizeOf(FileIndex) + @sizeOf(ZirIndex));
|
||||
}
|
||||
};
|
||||
|
||||
pub const Index = enum(u32) {
|
||||
_,
|
||||
pub fn resolveFull(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) TrackedInst {
|
||||
pub fn resolveFull(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) ?TrackedInst {
|
||||
const tracked_inst_unwrapped = tracked_inst_index.unwrap(ip);
|
||||
const tracked_insts = ip.getLocalShared(tracked_inst_unwrapped.tid).tracked_insts.acquire();
|
||||
return tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index];
|
||||
const maybe_lost = tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index];
|
||||
return .{
|
||||
.file = maybe_lost.file,
|
||||
.inst = maybe_lost.inst.unwrap() orelse return null,
|
||||
};
|
||||
}
|
||||
pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) Zir.Inst.Index {
|
||||
return i.resolveFull(ip).inst;
|
||||
pub fn resolveFile(tracked_inst_index: TrackedInst.Index, ip: *const InternPool) FileIndex {
|
||||
const tracked_inst_unwrapped = tracked_inst_index.unwrap(ip);
|
||||
const tracked_insts = ip.getLocalShared(tracked_inst_unwrapped.tid).tracked_insts.acquire();
|
||||
const maybe_lost = tracked_insts.view().items(.@"0")[tracked_inst_unwrapped.index];
|
||||
return maybe_lost.file;
|
||||
}
|
||||
pub fn resolve(i: TrackedInst.Index, ip: *const InternPool) ?Zir.Inst.Index {
|
||||
return (i.resolveFull(ip) orelse return null).inst;
|
||||
}
|
||||
|
||||
pub fn toOptional(i: TrackedInst.Index) Optional {
|
||||
@ -120,7 +150,11 @@ pub fn trackZir(
|
||||
tid: Zcu.PerThread.Id,
|
||||
key: TrackedInst,
|
||||
) Allocator.Error!TrackedInst.Index {
|
||||
const full_hash = Hash.hash(0, std.mem.asBytes(&key));
|
||||
const maybe_lost_key: TrackedInst.MaybeLost = .{
|
||||
.file = key.file,
|
||||
.inst = TrackedInst.MaybeLost.ZirIndex.wrap(key.inst),
|
||||
};
|
||||
const full_hash = Hash.hash(0, std.mem.asBytes(&maybe_lost_key));
|
||||
const hash: u32 = @truncate(full_hash >> 32);
|
||||
const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
|
||||
var map = shard.shared.tracked_inst_map.acquire();
|
||||
@ -132,12 +166,11 @@ pub fn trackZir(
|
||||
const entry = &map.entries[map_index];
|
||||
const index = entry.acquire().unwrap() orelse break;
|
||||
if (entry.hash != hash) continue;
|
||||
if (std.meta.eql(index.resolveFull(ip), key)) return index;
|
||||
if (std.meta.eql(index.resolveFull(ip) orelse continue, key)) return index;
|
||||
}
|
||||
shard.mutate.tracked_inst_map.mutex.lock();
|
||||
defer shard.mutate.tracked_inst_map.mutex.unlock();
|
||||
if (map.entries != shard.shared.tracked_inst_map.entries) {
|
||||
shard.mutate.tracked_inst_map.len += 1;
|
||||
map = shard.shared.tracked_inst_map;
|
||||
map_mask = map.header().mask();
|
||||
map_index = hash;
|
||||
@ -147,7 +180,7 @@ pub fn trackZir(
|
||||
const entry = &map.entries[map_index];
|
||||
const index = entry.acquire().unwrap() orelse break;
|
||||
if (entry.hash != hash) continue;
|
||||
if (std.meta.eql(index.resolveFull(ip), key)) return index;
|
||||
if (std.meta.eql(index.resolveFull(ip) orelse continue, key)) return index;
|
||||
}
|
||||
defer shard.mutate.tracked_inst_map.len += 1;
|
||||
const local = ip.getLocal(tid);
|
||||
@ -161,7 +194,7 @@ pub fn trackZir(
|
||||
.tid = tid,
|
||||
.index = list.mutate.len,
|
||||
}).wrap(ip);
|
||||
list.appendAssumeCapacity(.{key});
|
||||
list.appendAssumeCapacity(.{maybe_lost_key});
|
||||
entry.release(index.toOptional());
|
||||
return index;
|
||||
}
|
||||
@ -205,12 +238,91 @@ pub fn trackZir(
|
||||
.tid = tid,
|
||||
.index = list.mutate.len,
|
||||
}).wrap(ip);
|
||||
list.appendAssumeCapacity(.{key});
|
||||
list.appendAssumeCapacity(.{maybe_lost_key});
|
||||
map.entries[map_index] = .{ .value = index.toOptional(), .hash = hash };
|
||||
shard.shared.tracked_inst_map.release(new_map);
|
||||
return index;
|
||||
}
|
||||
|
||||
pub fn rehashTrackedInsts(
|
||||
ip: *InternPool,
|
||||
gpa: Allocator,
|
||||
/// TODO: maybe don't take this? it doesn't actually matter, only one thread is running at this point
|
||||
tid: Zcu.PerThread.Id,
|
||||
) Allocator.Error!void {
|
||||
// TODO: this function doesn't handle OOM well. What should it do?
|
||||
// Indeed, what should anyone do when they run out of memory?
|
||||
|
||||
// We don't lock anything, as this function assumes that no other thread is
|
||||
// accessing `tracked_insts`. This is necessary because we're going to be
|
||||
// iterating the `TrackedInst`s in each `Local`, so we have to know that
|
||||
// none will be added as we work.
|
||||
|
||||
// Figure out how big each shard need to be and store it in its mutate `len`.
|
||||
for (ip.shards) |*shard| shard.mutate.tracked_inst_map.len = 0;
|
||||
for (ip.locals) |*local| {
|
||||
// `getMutableTrackedInsts` is okay only because no other thread is currently active.
|
||||
// We need the `mutate` for the len.
|
||||
for (local.getMutableTrackedInsts(gpa).viewAllowEmpty().items(.@"0")) |tracked_inst| {
|
||||
if (tracked_inst.inst == .lost) continue; // we can ignore this one!
|
||||
const full_hash = Hash.hash(0, std.mem.asBytes(&tracked_inst));
|
||||
const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
|
||||
shard.mutate.tracked_inst_map.len += 1;
|
||||
}
|
||||
}
|
||||
|
||||
const Map = Shard.Map(TrackedInst.Index.Optional);
|
||||
|
||||
const arena_state = &ip.getLocal(tid).mutate.arena;
|
||||
|
||||
// We know how big each shard must be, so ensure we have the capacity we need.
|
||||
for (ip.shards) |*shard| {
|
||||
const want_capacity = std.math.ceilPowerOfTwo(u32, shard.mutate.tracked_inst_map.len * 5 / 3) catch unreachable;
|
||||
const have_capacity = shard.shared.tracked_inst_map.header().capacity; // no acquire because we hold the mutex
|
||||
if (have_capacity >= want_capacity) {
|
||||
@memset(shard.shared.tracked_inst_map.entries[0..have_capacity], .{ .value = .none, .hash = undefined });
|
||||
continue;
|
||||
}
|
||||
var arena = arena_state.promote(gpa);
|
||||
defer arena_state.* = arena.state;
|
||||
const new_map_buf = try arena.allocator().alignedAlloc(
|
||||
u8,
|
||||
Map.alignment,
|
||||
Map.entries_offset + want_capacity * @sizeOf(Map.Entry),
|
||||
);
|
||||
const new_map: Map = .{ .entries = @ptrCast(new_map_buf[Map.entries_offset..].ptr) };
|
||||
new_map.header().* = .{ .capacity = want_capacity };
|
||||
@memset(new_map.entries[0..want_capacity], .{ .value = .none, .hash = undefined });
|
||||
shard.shared.tracked_inst_map.release(new_map);
|
||||
}
|
||||
|
||||
// Now, actually insert the items.
|
||||
for (ip.locals, 0..) |*local, local_tid| {
|
||||
// `getMutableTrackedInsts` is okay only because no other thread is currently active.
|
||||
// We need the `mutate` for the len.
|
||||
for (local.getMutableTrackedInsts(gpa).viewAllowEmpty().items(.@"0"), 0..) |tracked_inst, local_inst_index| {
|
||||
if (tracked_inst.inst == .lost) continue; // we can ignore this one!
|
||||
const full_hash = Hash.hash(0, std.mem.asBytes(&tracked_inst));
|
||||
const hash: u32 = @truncate(full_hash >> 32);
|
||||
const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
|
||||
const map = shard.shared.tracked_inst_map; // no acquire because we hold the mutex
|
||||
const map_mask = map.header().mask();
|
||||
var map_index = hash;
|
||||
const entry = while (true) : (map_index += 1) {
|
||||
map_index &= map_mask;
|
||||
const entry = &map.entries[map_index];
|
||||
if (entry.acquire() == .none) break entry;
|
||||
};
|
||||
const index = TrackedInst.Index.Unwrapped.wrap(.{
|
||||
.tid = @enumFromInt(local_tid),
|
||||
.index = @intCast(local_inst_index),
|
||||
}, ip);
|
||||
entry.hash = hash;
|
||||
entry.release(index.toOptional());
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
/// Analysis Unit. Represents a single entity which undergoes semantic analysis.
|
||||
/// This is either a `Cau` or a runtime function.
|
||||
/// The LSB is used as a tag bit.
|
||||
@ -728,7 +840,7 @@ const Local = struct {
|
||||
else => @compileError("unsupported host"),
|
||||
};
|
||||
const Strings = List(struct { u8 });
|
||||
const TrackedInsts = List(struct { TrackedInst });
|
||||
const TrackedInsts = List(struct { TrackedInst.MaybeLost });
|
||||
const Maps = List(struct { FieldMap });
|
||||
const Caus = List(struct { Cau });
|
||||
const Navs = List(Nav.Repr);
|
||||
@ -959,6 +1071,14 @@ const Local = struct {
|
||||
mutable.list.release(new_list);
|
||||
}
|
||||
|
||||
pub fn viewAllowEmpty(mutable: Mutable) View {
|
||||
const capacity = mutable.list.header().capacity;
|
||||
return .{
|
||||
.bytes = mutable.list.bytes,
|
||||
.len = mutable.mutate.len,
|
||||
.capacity = capacity,
|
||||
};
|
||||
}
|
||||
pub fn view(mutable: Mutable) View {
|
||||
const capacity = mutable.list.header().capacity;
|
||||
assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`
|
||||
@ -996,7 +1116,6 @@ const Local = struct {
|
||||
fn header(list: ListSelf) *Header {
|
||||
return @ptrFromInt(@intFromPtr(list.bytes) - bytes_offset);
|
||||
}
|
||||
|
||||
pub fn view(list: ListSelf) View {
|
||||
const capacity = list.header().capacity;
|
||||
assert(capacity > 0); // optimizes `MultiArrayList.Slice.items`
|
||||
@ -11000,7 +11119,6 @@ pub fn getOrPutTrailingString(
|
||||
shard.mutate.string_map.mutex.lock();
|
||||
defer shard.mutate.string_map.mutex.unlock();
|
||||
if (map.entries != shard.shared.string_map.entries) {
|
||||
shard.mutate.string_map.len += 1;
|
||||
map = shard.shared.string_map;
|
||||
map_mask = map.header().mask();
|
||||
map_index = hash;
|
||||
|
29
src/Sema.zig
29
src/Sema.zig
@ -999,7 +999,7 @@ fn analyzeBodyInner(
|
||||
// The hashmap lookup in here is a little expensive, and LLVM fails to optimize it away.
|
||||
if (build_options.enable_logging) {
|
||||
std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{ sub_file_path: {
|
||||
const file_index = block.src_base_inst.resolveFull(&zcu.intern_pool).file;
|
||||
const file_index = block.src_base_inst.resolveFile(&zcu.intern_pool);
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
break :sub_file_path file.sub_file_path;
|
||||
}, inst });
|
||||
@ -2873,7 +2873,7 @@ fn createTypeName(
|
||||
.anon => {}, // handled after switch
|
||||
.parent => return block.type_name_ctx,
|
||||
.func => func_strat: {
|
||||
const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip));
|
||||
const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
|
||||
const zir_tags = sema.code.instructions.items(.tag);
|
||||
|
||||
var buf: std.ArrayListUnmanaged(u8) = .{};
|
||||
@ -5487,7 +5487,7 @@ fn failWithBadMemberAccess(
|
||||
.Enum => "enum",
|
||||
else => unreachable,
|
||||
};
|
||||
if (agg_ty.typeDeclInst(zcu)) |inst| if (inst.resolve(ip) == .main_struct_inst) {
|
||||
if (agg_ty.typeDeclInst(zcu)) |inst| if ((inst.resolve(ip) orelse return error.AnalysisFail) == .main_struct_inst) {
|
||||
return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{
|
||||
agg_ty.fmt(pt), field_name.fmt(ip),
|
||||
});
|
||||
@ -6041,8 +6041,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
|
||||
return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
|
||||
|
||||
const path_digest = zcu.filePathDigest(result.file_index);
|
||||
const old_root_type = zcu.fileRootType(result.file_index);
|
||||
pt.astGenFile(result.file, path_digest, old_root_type) catch |err|
|
||||
pt.astGenFile(result.file, path_digest) catch |err|
|
||||
return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
|
||||
|
||||
// TODO: register some kind of dependency on the file.
|
||||
@ -7778,7 +7777,7 @@ fn analyzeCall(
|
||||
// the AIR instructions of the callsite. The callee could be a generic function
|
||||
// which means its parameter type expressions must be resolved in order and used
|
||||
// to successively coerce the arguments.
|
||||
const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip));
|
||||
const fn_info = ics.callee().code.getFnInfo(module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);
|
||||
try ics.callee().inst_map.ensureSpaceForInstructions(gpa, fn_info.param_body);
|
||||
|
||||
var arg_i: u32 = 0;
|
||||
@ -7823,7 +7822,7 @@ fn analyzeCall(
|
||||
// each of the parameters, resolving the return type and providing it to the child
|
||||
// `Sema` so that it can be used for the `ret_ptr` instruction.
|
||||
const ret_ty_inst = if (fn_info.ret_ty_body.len != 0)
|
||||
try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip))
|
||||
try sema.resolveInlineBody(&child_block, fn_info.ret_ty_body, module_fn.zir_body_inst.resolve(ip) orelse return error.AnalysisFail)
|
||||
else
|
||||
try sema.resolveInst(fn_info.ret_ty_ref);
|
||||
const ret_ty_src: LazySrcLoc = .{ .base_node_inst = module_fn.zir_body_inst, .offset = .{ .node_offset_fn_type_ret_ty = 0 } };
|
||||
@ -8210,7 +8209,7 @@ fn instantiateGenericCall(
|
||||
const fn_nav = ip.getNav(generic_owner_func.owner_nav);
|
||||
const fn_cau = ip.getCau(fn_nav.analysis_owner.unwrap().?);
|
||||
const fn_zir = zcu.namespacePtr(fn_cau.namespace).fileScope(zcu).zir;
|
||||
const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip));
|
||||
const fn_info = fn_zir.getFnInfo(generic_owner_func.zir_body_inst.resolve(ip) orelse return error.AnalysisFail);
|
||||
|
||||
const comptime_args = try sema.arena.alloc(InternPool.Index, args_info.count());
|
||||
@memset(comptime_args, .none);
|
||||
@ -9416,7 +9415,7 @@ fn zirFunc(
|
||||
break :cau generic_owner_nav.analysis_owner.unwrap().?;
|
||||
} else sema.owner.unwrap().cau;
|
||||
const fn_is_exported = exported: {
|
||||
const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip);
|
||||
const decl_inst = ip.getCau(func_decl_cau).zir_index.resolve(ip) orelse return error.AnalysisFail;
|
||||
const zir_decl = sema.code.getDeclaration(decl_inst)[0];
|
||||
break :exported zir_decl.flags.is_export;
|
||||
};
|
||||
@ -26125,7 +26124,7 @@ fn zirVarExtended(
|
||||
const addrspace_src = block.src(.{ .node_offset_var_decl_addrspace = 0 });
|
||||
|
||||
const decl_inst, const decl_bodies = decl: {
|
||||
const decl_inst = sema.getOwnerCauDeclInst().resolve(ip);
|
||||
const decl_inst = sema.getOwnerCauDeclInst().resolve(ip) orelse return error.AnalysisFail;
|
||||
const zir_decl, const extra_end = sema.code.getDeclaration(decl_inst);
|
||||
break :decl .{ decl_inst, zir_decl.getBodies(extra_end, sema.code) };
|
||||
};
|
||||
@ -26354,7 +26353,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
|
||||
break :decl_inst cau.zir_index;
|
||||
} else sema.getOwnerCauDeclInst(); // not an instantiation so we're analyzing a function declaration Cau
|
||||
|
||||
const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&mod.intern_pool))[0];
|
||||
const zir_decl = sema.code.getDeclaration(decl_inst.resolve(&mod.intern_pool) orelse return error.AnalysisFail)[0];
|
||||
if (zir_decl.flags.is_export) {
|
||||
break :cc .C;
|
||||
}
|
||||
@ -35505,7 +35504,7 @@ fn semaBackingIntType(pt: Zcu.PerThread, struct_type: InternPool.LoadedStructTyp
|
||||
break :blk accumulator;
|
||||
};
|
||||
|
||||
const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
|
||||
const zir_index = struct_type.zir_index.unwrap().?.resolve(ip) orelse return error.AnalysisFail;
|
||||
const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
|
||||
assert(extended.opcode == .struct_decl);
|
||||
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
|
||||
@ -36120,7 +36119,7 @@ fn semaStructFields(
|
||||
const cau_index = struct_type.cau.unwrap().?;
|
||||
const namespace_index = ip.getCau(cau_index).namespace;
|
||||
const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;
|
||||
const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
|
||||
const zir_index = struct_type.zir_index.unwrap().?.resolve(ip) orelse return error.AnalysisFail;
|
||||
|
||||
const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
|
||||
|
||||
@ -36343,7 +36342,7 @@ fn semaStructFieldInits(
|
||||
const cau_index = struct_type.cau.unwrap().?;
|
||||
const namespace_index = ip.getCau(cau_index).namespace;
|
||||
const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir;
|
||||
const zir_index = struct_type.zir_index.unwrap().?.resolve(ip);
|
||||
const zir_index = struct_type.zir_index.unwrap().?.resolve(ip) orelse return error.AnalysisFail;
|
||||
const fields_len, const small, var extra_index = structZirInfo(zir, zir_index);
|
||||
|
||||
var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
|
||||
@ -36477,7 +36476,7 @@ fn semaUnionFields(pt: Zcu.PerThread, arena: Allocator, union_ty: InternPool.Ind
|
||||
const ip = &zcu.intern_pool;
|
||||
const cau_index = union_type.cau;
|
||||
const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir;
|
||||
const zir_index = union_type.zir_index.resolve(ip);
|
||||
const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
|
||||
const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
|
||||
assert(extended.opcode == .union_decl);
|
||||
const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
|
||||
|
@ -3437,7 +3437,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
|
||||
},
|
||||
else => return null,
|
||||
};
|
||||
const info = tracked.resolveFull(&zcu.intern_pool);
|
||||
const info = tracked.resolveFull(&zcu.intern_pool) orelse return null;
|
||||
const file = zcu.fileByIndex(info.file);
|
||||
assert(file.zir_loaded);
|
||||
const zir = file.zir;
|
||||
|
119
src/Zcu.zig
119
src/Zcu.zig
@ -162,12 +162,6 @@ outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
|
||||
/// Such `AnalUnit`s are ready for immediate re-analysis.
|
||||
/// See `findOutdatedToAnalyze` for details.
|
||||
outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
|
||||
/// This contains a set of struct types whose corresponding `Cau` may not be in
|
||||
/// `outdated`, but are the root types of files which have updated source and
|
||||
/// thus must be re-analyzed. If such a type is only in this set, the struct type
|
||||
/// index may be preserved (only the namespace might change). If its owned `Cau`
|
||||
/// is also outdated, the struct type index must be recreated.
|
||||
outdated_file_root: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
|
||||
/// This contains a list of AnalUnit whose analysis or codegen failed, but the
|
||||
/// failure was something like running out of disk space, and trying again may
|
||||
/// succeed. On the next update, we will flush this list, marking all members of
|
||||
@ -2025,7 +2019,7 @@ pub const LazySrcLoc = struct {
|
||||
pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) struct { *File, Ast.Node.Index } {
|
||||
const ip = &zcu.intern_pool;
|
||||
const file_index, const zir_inst = inst: {
|
||||
const info = base_node_inst.resolveFull(ip);
|
||||
const info = base_node_inst.resolveFull(ip) orelse @panic("TODO: resolve source location relative to lost inst");
|
||||
break :inst .{ info.file, info.inst };
|
||||
};
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
@ -2148,7 +2142,6 @@ pub fn deinit(zcu: *Zcu) void {
|
||||
zcu.potentially_outdated.deinit(gpa);
|
||||
zcu.outdated.deinit(gpa);
|
||||
zcu.outdated_ready.deinit(gpa);
|
||||
zcu.outdated_file_root.deinit(gpa);
|
||||
zcu.retryable_failures.deinit(gpa);
|
||||
|
||||
zcu.test_functions.deinit(gpa);
|
||||
@ -2355,8 +2348,6 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
|
||||
pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
|
||||
if (!zcu.comp.incremental) return null;
|
||||
|
||||
if (true) @panic("TODO: findOutdatedToAnalyze");
|
||||
|
||||
if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
|
||||
log.debug("findOutdatedToAnalyze: no outdated depender", .{});
|
||||
return null;
|
||||
@ -2381,87 +2372,57 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
|
||||
return zcu.outdated_ready.keys()[0];
|
||||
}
|
||||
|
||||
// Next, we will see if there is any outdated file root which was not in
|
||||
// `outdated`. This set will be small (number of files changed in this
|
||||
// update), so it's alright for us to just iterate here.
|
||||
for (zcu.outdated_file_root.keys()) |file_decl| {
|
||||
const decl_depender = AnalUnit.wrap(.{ .decl = file_decl });
|
||||
if (zcu.outdated.contains(decl_depender)) {
|
||||
// Since we didn't hit this in the first loop, this Decl must have
|
||||
// pending dependencies, so is ineligible.
|
||||
continue;
|
||||
}
|
||||
if (zcu.potentially_outdated.contains(decl_depender)) {
|
||||
// This Decl's struct may or may not need to be recreated depending
|
||||
// on whether it is outdated. If we analyzed it now, we would have
|
||||
// to assume it was outdated and recreate it!
|
||||
continue;
|
||||
}
|
||||
log.debug("findOutdatedToAnalyze: outdated file root decl '{d}'", .{file_decl});
|
||||
return decl_depender;
|
||||
}
|
||||
// There is no single AnalUnit which is ready for re-analysis. Instead, we must assume that some
|
||||
// Cau with PO dependencies is outdated -- e.g. in the above example we arbitrarily pick one of
|
||||
// A or B. We should select a Cau, since a Cau is definitely responsible for the loop in the
|
||||
// dependency graph (since IES dependencies can't have loops). We should also, of course, not
|
||||
// select a Cau owned by a `comptime` declaration, since you can't depend on those!
|
||||
|
||||
// There is no single AnalUnit which is ready for re-analysis. Instead, we
|
||||
// must assume that some Decl with PO dependencies is outdated - e.g. in the
|
||||
// above example we arbitrarily pick one of A or B. We should select a Decl,
|
||||
// since a Decl is definitely responsible for the loop in the dependency
|
||||
// graph (since you can't depend on a runtime function analysis!).
|
||||
|
||||
// The choice of this Decl could have a big impact on how much total
|
||||
// analysis we perform, since if analysis concludes its tyval is unchanged,
|
||||
// then other PO AnalUnit may be resolved as up-to-date. To hopefully avoid
|
||||
// doing too much work, let's find a Decl which the most things depend on -
|
||||
// the idea is that this will resolve a lot of loops (but this is only a
|
||||
// heuristic).
|
||||
// The choice of this Cau could have a big impact on how much total analysis we perform, since
|
||||
// if analysis concludes any dependencies on its result are up-to-date, then other PO AnalUnit
|
||||
// may be resolved as up-to-date. To hopefully avoid doing too much work, let's find a Decl
|
||||
// which the most things depend on - the idea is that this will resolve a lot of loops (but this
|
||||
// is only a heuristic).
|
||||
|
||||
log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{
|
||||
zcu.outdated.count(),
|
||||
zcu.potentially_outdated.count(),
|
||||
});
|
||||
|
||||
const Decl = {};
|
||||
const ip = &zcu.intern_pool;
|
||||
|
||||
var chosen_decl_idx: ?Decl.Index = null;
|
||||
var chosen_decl_dependers: u32 = undefined;
|
||||
var chosen_cau: ?InternPool.Cau.Index = null;
|
||||
var chosen_cau_dependers: u32 = undefined;
|
||||
|
||||
for (zcu.outdated.keys()) |depender| {
|
||||
const decl_index = switch (depender.unwrap()) {
|
||||
.decl => |d| d,
|
||||
.func => continue,
|
||||
};
|
||||
inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
|
||||
for (outdated_units) |unit| {
|
||||
const cau = switch (unit.unwrap()) {
|
||||
.cau => |cau| cau,
|
||||
.func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
|
||||
};
|
||||
const cau_owner = ip.getCau(cau).owner;
|
||||
|
||||
var n: u32 = 0;
|
||||
var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
|
||||
while (it.next()) |_| n += 1;
|
||||
var n: u32 = 0;
|
||||
var it = ip.dependencyIterator(switch (cau_owner.unwrap()) {
|
||||
.none => continue, // there can be no dependencies on this `Cau` so it is a terrible choice
|
||||
.type => |ty| .{ .interned = ty },
|
||||
.nav => |nav| .{ .nav_val = nav },
|
||||
});
|
||||
while (it.next()) |_| n += 1;
|
||||
|
||||
if (chosen_decl_idx == null or n > chosen_decl_dependers) {
|
||||
chosen_decl_idx = decl_index;
|
||||
chosen_decl_dependers = n;
|
||||
if (chosen_cau == null or n > chosen_cau_dependers) {
|
||||
chosen_cau = cau;
|
||||
chosen_cau_dependers = n;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (zcu.potentially_outdated.keys()) |depender| {
|
||||
const decl_index = switch (depender.unwrap()) {
|
||||
.decl => |d| d,
|
||||
.func => continue,
|
||||
};
|
||||
|
||||
var n: u32 = 0;
|
||||
var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index });
|
||||
while (it.next()) |_| n += 1;
|
||||
|
||||
if (chosen_decl_idx == null or n > chosen_decl_dependers) {
|
||||
chosen_decl_idx = decl_index;
|
||||
chosen_decl_dependers = n;
|
||||
}
|
||||
}
|
||||
|
||||
log.debug("findOutdatedToAnalyze: heuristic returned Decl {d} ({d} dependers)", .{
|
||||
chosen_decl_idx.?,
|
||||
chosen_decl_dependers,
|
||||
log.debug("findOutdatedToAnalyze: heuristic returned Cau {d} ({d} dependers)", .{
|
||||
@intFromEnum(chosen_cau.?),
|
||||
chosen_cau_dependers,
|
||||
});
|
||||
|
||||
return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
|
||||
return AnalUnit.wrap(.{ .cau = chosen_cau.? });
|
||||
}
|
||||
|
||||
/// During an incremental update, before semantic analysis, call this to flush all values from
|
||||
@ -2583,7 +2544,7 @@ pub fn mapOldZirToNew(
|
||||
break :inst unnamed_tests.items[unnamed_test_idx];
|
||||
},
|
||||
_ => inst: {
|
||||
const name_nts = new_decl.name.toString(old_zir).?;
|
||||
const name_nts = new_decl.name.toString(new_zir).?;
|
||||
const name = new_zir.nullTerminatedString(name_nts);
|
||||
if (new_decl.name.isNamedTest(new_zir)) {
|
||||
break :inst named_tests.get(name) orelse continue;
|
||||
@ -3093,7 +3054,7 @@ pub fn navSrcLoc(zcu: *const Zcu, nav_index: InternPool.Nav.Index) LazySrcLoc {
|
||||
|
||||
pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 {
|
||||
const ip = &zcu.intern_pool;
|
||||
const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip);
|
||||
const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?;
|
||||
const zir = zcu.fileByIndex(inst_info.file).zir;
|
||||
const inst = zir.instructions.get(@intFromEnum(inst_info.inst));
|
||||
assert(inst.tag == .declaration);
|
||||
@ -3106,7 +3067,7 @@ pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value {
|
||||
|
||||
pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index {
|
||||
const ip = &zcu.intern_pool;
|
||||
return ip.getNav(nav).srcInst(ip).resolveFull(ip).file;
|
||||
return ip.getNav(nav).srcInst(ip).resolveFile(ip);
|
||||
}
|
||||
|
||||
pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
|
||||
@ -3115,6 +3076,6 @@ pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File {
|
||||
|
||||
pub fn cauFileScope(zcu: *Zcu, cau: InternPool.Cau.Index) *File {
|
||||
const ip = &zcu.intern_pool;
|
||||
const file_index = ip.getCau(cau).zir_index.resolveFull(ip).file;
|
||||
const file_index = ip.getCau(cau).zir_index.resolveFile(ip);
|
||||
return zcu.fileByIndex(file_index);
|
||||
}
|
||||
|
@ -39,7 +39,6 @@ pub fn astGenFile(
|
||||
pt: Zcu.PerThread,
|
||||
file: *Zcu.File,
|
||||
path_digest: Cache.BinDigest,
|
||||
old_root_type: InternPool.Index,
|
||||
) !void {
|
||||
dev.check(.ast_gen);
|
||||
assert(!file.mod.isBuiltin());
|
||||
@ -299,25 +298,15 @@ pub fn astGenFile(
|
||||
file.status = .astgen_failure;
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
if (old_root_type != .none) {
|
||||
// The root of this file must be re-analyzed, since the file has changed.
|
||||
comp.mutex.lock();
|
||||
defer comp.mutex.unlock();
|
||||
|
||||
log.debug("outdated file root type: {}", .{old_root_type});
|
||||
try zcu.outdated_file_root.put(gpa, old_root_type, {});
|
||||
}
|
||||
}
|
||||
|
||||
const UpdatedFile = struct {
|
||||
file_index: Zcu.File.Index,
|
||||
file: *Zcu.File,
|
||||
inst_map: std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index),
|
||||
};
|
||||
|
||||
fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.ArrayListUnmanaged(UpdatedFile)) void {
|
||||
for (updated_files.items) |*elem| elem.inst_map.deinit(gpa);
|
||||
fn cleanupUpdatedFiles(gpa: Allocator, updated_files: *std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile)) void {
|
||||
for (updated_files.values()) |*elem| elem.inst_map.deinit(gpa);
|
||||
updated_files.deinit(gpa);
|
||||
}
|
||||
|
||||
@ -328,143 +317,166 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
||||
const gpa = zcu.gpa;
|
||||
|
||||
// We need to visit every updated File for every TrackedInst in InternPool.
|
||||
var updated_files: std.ArrayListUnmanaged(UpdatedFile) = .{};
|
||||
var updated_files: std.AutoArrayHashMapUnmanaged(Zcu.File.Index, UpdatedFile) = .{};
|
||||
defer cleanupUpdatedFiles(gpa, &updated_files);
|
||||
for (zcu.import_table.values()) |file_index| {
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
const old_zir = file.prev_zir orelse continue;
|
||||
const new_zir = file.zir;
|
||||
try updated_files.append(gpa, .{
|
||||
.file_index = file_index,
|
||||
const gop = try updated_files.getOrPut(gpa, file_index);
|
||||
assert(!gop.found_existing);
|
||||
gop.value_ptr.* = .{
|
||||
.file = file,
|
||||
.inst_map = .{},
|
||||
});
|
||||
const inst_map = &updated_files.items[updated_files.items.len - 1].inst_map;
|
||||
try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, inst_map);
|
||||
};
|
||||
if (!new_zir.hasCompileErrors()) {
|
||||
try Zcu.mapOldZirToNew(gpa, old_zir.*, file.zir, &gop.value_ptr.inst_map);
|
||||
}
|
||||
}
|
||||
|
||||
if (updated_files.items.len == 0)
|
||||
if (updated_files.count() == 0)
|
||||
return;
|
||||
|
||||
for (ip.locals, 0..) |*local, tid| {
|
||||
const tracked_insts_list = local.getMutableTrackedInsts(gpa);
|
||||
for (tracked_insts_list.view().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| {
|
||||
for (updated_files.items) |updated_file| {
|
||||
const file_index = updated_file.file_index;
|
||||
if (tracked_inst.file != file_index) continue;
|
||||
for (tracked_insts_list.viewAllowEmpty().items(.@"0"), 0..) |*tracked_inst, tracked_inst_unwrapped_index| {
|
||||
const file_index = tracked_inst.file;
|
||||
const updated_file = updated_files.get(file_index) orelse continue;
|
||||
|
||||
const file = updated_file.file;
|
||||
const old_zir = file.prev_zir.?.*;
|
||||
const new_zir = file.zir;
|
||||
const old_tag = old_zir.instructions.items(.tag);
|
||||
const old_data = old_zir.instructions.items(.data);
|
||||
const inst_map = &updated_file.inst_map;
|
||||
const file = updated_file.file;
|
||||
|
||||
const old_inst = tracked_inst.inst;
|
||||
const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{
|
||||
.tid = @enumFromInt(tid),
|
||||
.index = @intCast(tracked_inst_unwrapped_index),
|
||||
}).wrap(ip);
|
||||
tracked_inst.inst = inst_map.get(old_inst) orelse {
|
||||
// Tracking failed for this instruction. Invalidate associated `src_hash` deps.
|
||||
log.debug("tracking failed for %{d}", .{old_inst});
|
||||
try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
|
||||
continue;
|
||||
};
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
// If we mark this as outdated now, users of this inst will just get a transitive analysis failure.
|
||||
// Ultimately, they would end up throwing out potentially useful analysis results.
|
||||
// So, do nothing. We already have the file failure -- that's sufficient for now!
|
||||
continue;
|
||||
}
|
||||
const old_inst = tracked_inst.inst.unwrap() orelse continue; // we can't continue tracking lost insts
|
||||
const tracked_inst_index = (InternPool.TrackedInst.Index.Unwrapped{
|
||||
.tid = @enumFromInt(tid),
|
||||
.index = @intCast(tracked_inst_unwrapped_index),
|
||||
}).wrap(ip);
|
||||
const new_inst = updated_file.inst_map.get(old_inst) orelse {
|
||||
// Tracking failed for this instruction. Invalidate associated `src_hash` deps.
|
||||
log.debug("tracking failed for %{d}", .{old_inst});
|
||||
tracked_inst.inst = .lost;
|
||||
try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
|
||||
continue;
|
||||
};
|
||||
tracked_inst.inst = InternPool.TrackedInst.MaybeLost.ZirIndex.wrap(new_inst);
|
||||
|
||||
if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
|
||||
if (new_zir.getAssociatedSrcHash(tracked_inst.inst)) |new_hash| {
|
||||
if (std.zig.srcHashEql(old_hash, new_hash)) {
|
||||
break :hash_changed;
|
||||
}
|
||||
log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
|
||||
old_inst,
|
||||
tracked_inst.inst,
|
||||
std.fmt.fmtSliceHexLower(&old_hash),
|
||||
std.fmt.fmtSliceHexLower(&new_hash),
|
||||
});
|
||||
const old_zir = file.prev_zir.?.*;
|
||||
const new_zir = file.zir;
|
||||
const old_tag = old_zir.instructions.items(.tag);
|
||||
const old_data = old_zir.instructions.items(.data);
|
||||
|
||||
if (old_zir.getAssociatedSrcHash(old_inst)) |old_hash| hash_changed: {
|
||||
if (new_zir.getAssociatedSrcHash(new_inst)) |new_hash| {
|
||||
if (std.zig.srcHashEql(old_hash, new_hash)) {
|
||||
break :hash_changed;
|
||||
}
|
||||
// The source hash associated with this instruction changed - invalidate relevant dependencies.
|
||||
try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
|
||||
log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{
|
||||
old_inst,
|
||||
new_inst,
|
||||
std.fmt.fmtSliceHexLower(&old_hash),
|
||||
std.fmt.fmtSliceHexLower(&new_hash),
|
||||
});
|
||||
}
|
||||
// The source hash associated with this instruction changed - invalidate relevant dependencies.
|
||||
try zcu.markDependeeOutdated(.{ .src_hash = tracked_inst_index });
|
||||
}
|
||||
|
||||
// If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
|
||||
const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
|
||||
.extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
|
||||
.struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
|
||||
else => false,
|
||||
},
|
||||
// If this is a `struct_decl` etc, we must invalidate any outdated namespace dependencies.
|
||||
const has_namespace = switch (old_tag[@intFromEnum(old_inst)]) {
|
||||
.extended => switch (old_data[@intFromEnum(old_inst)].extended.opcode) {
|
||||
.struct_decl, .union_decl, .opaque_decl, .enum_decl => true,
|
||||
else => false,
|
||||
};
|
||||
if (!has_namespace) continue;
|
||||
},
|
||||
else => false,
|
||||
};
|
||||
if (!has_namespace) continue;
|
||||
|
||||
var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
|
||||
defer old_names.deinit(zcu.gpa);
|
||||
{
|
||||
var it = old_zir.declIterator(old_inst);
|
||||
while (it.next()) |decl_inst| {
|
||||
const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
|
||||
switch (decl_name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
|
||||
_ => if (decl_name.isNamedTest(old_zir)) continue,
|
||||
}
|
||||
const name_zir = decl_name.toString(old_zir).?;
|
||||
const name_ip = try zcu.intern_pool.getOrPutString(
|
||||
zcu.gpa,
|
||||
pt.tid,
|
||||
old_zir.nullTerminatedString(name_zir),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
try old_names.put(zcu.gpa, name_ip, {});
|
||||
var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
|
||||
defer old_names.deinit(zcu.gpa);
|
||||
{
|
||||
var it = old_zir.declIterator(old_inst);
|
||||
while (it.next()) |decl_inst| {
|
||||
const decl_name = old_zir.getDeclaration(decl_inst)[0].name;
|
||||
switch (decl_name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
|
||||
_ => if (decl_name.isNamedTest(old_zir)) continue,
|
||||
}
|
||||
const name_zir = decl_name.toString(old_zir).?;
|
||||
const name_ip = try zcu.intern_pool.getOrPutString(
|
||||
zcu.gpa,
|
||||
pt.tid,
|
||||
old_zir.nullTerminatedString(name_zir),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
try old_names.put(zcu.gpa, name_ip, {});
|
||||
}
|
||||
var any_change = false;
|
||||
{
|
||||
var it = new_zir.declIterator(tracked_inst.inst);
|
||||
while (it.next()) |decl_inst| {
|
||||
const decl_name = new_zir.getDeclaration(decl_inst)[0].name;
|
||||
switch (decl_name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
|
||||
_ => if (decl_name.isNamedTest(new_zir)) continue,
|
||||
}
|
||||
const name_zir = decl_name.toString(new_zir).?;
|
||||
const name_ip = try zcu.intern_pool.getOrPutString(
|
||||
zcu.gpa,
|
||||
pt.tid,
|
||||
new_zir.nullTerminatedString(name_zir),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
if (!old_names.swapRemove(name_ip)) continue;
|
||||
// Name added
|
||||
any_change = true;
|
||||
try zcu.markDependeeOutdated(.{ .namespace_name = .{
|
||||
.namespace = tracked_inst_index,
|
||||
.name = name_ip,
|
||||
} });
|
||||
}
|
||||
var any_change = false;
|
||||
{
|
||||
var it = new_zir.declIterator(new_inst);
|
||||
while (it.next()) |decl_inst| {
|
||||
const decl_name = new_zir.getDeclaration(decl_inst)[0].name;
|
||||
switch (decl_name) {
|
||||
.@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
|
||||
_ => if (decl_name.isNamedTest(new_zir)) continue,
|
||||
}
|
||||
}
|
||||
// The only elements remaining in `old_names` now are any names which were removed.
|
||||
for (old_names.keys()) |name_ip| {
|
||||
const name_zir = decl_name.toString(new_zir).?;
|
||||
const name_ip = try zcu.intern_pool.getOrPutString(
|
||||
zcu.gpa,
|
||||
pt.tid,
|
||||
new_zir.nullTerminatedString(name_zir),
|
||||
.no_embedded_nulls,
|
||||
);
|
||||
if (!old_names.swapRemove(name_ip)) continue;
|
||||
// Name added
|
||||
any_change = true;
|
||||
try zcu.markDependeeOutdated(.{ .namespace_name = .{
|
||||
.namespace = tracked_inst_index,
|
||||
.name = name_ip,
|
||||
} });
|
||||
}
|
||||
}
|
||||
// The only elements remaining in `old_names` now are any names which were removed.
|
||||
for (old_names.keys()) |name_ip| {
|
||||
any_change = true;
|
||||
try zcu.markDependeeOutdated(.{ .namespace_name = .{
|
||||
.namespace = tracked_inst_index,
|
||||
.name = name_ip,
|
||||
} });
|
||||
}
|
||||
|
||||
if (any_change) {
|
||||
try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index });
|
||||
}
|
||||
if (any_change) {
|
||||
try zcu.markDependeeOutdated(.{ .namespace = tracked_inst_index });
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (updated_files.items) |updated_file| {
|
||||
try ip.rehashTrackedInsts(gpa, pt.tid);
|
||||
|
||||
for (updated_files.keys(), updated_files.values()) |file_index, updated_file| {
|
||||
const file = updated_file.file;
|
||||
const prev_zir = file.prev_zir.?;
|
||||
file.prev_zir = null;
|
||||
prev_zir.deinit(gpa);
|
||||
gpa.destroy(prev_zir);
|
||||
if (file.zir.hasCompileErrors()) {
|
||||
// Keep `prev_zir` around: it's the last non-error ZIR.
|
||||
// Don't update the namespace, as we have no new data to update *to*.
|
||||
} else {
|
||||
const prev_zir = file.prev_zir.?;
|
||||
file.prev_zir = null;
|
||||
prev_zir.deinit(gpa);
|
||||
gpa.destroy(prev_zir);
|
||||
|
||||
// For every file which has changed, re-scan the namespace of the file's root struct type.
|
||||
// These types are special-cased because they don't have an enclosing declaration which will
|
||||
// be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this
|
||||
// now because this work is fast (no actual Sema work is happening, we're just updating the
|
||||
// namespace contents). We must do this after updating ZIR refs above, since `scanNamespace`
|
||||
// will track some instructions.
|
||||
try pt.updateFileNamespace(file_index);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@ -473,6 +485,8 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
|
||||
pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
||||
const file_root_type = pt.zcu.fileRootType(file_index);
|
||||
if (file_root_type != .none) {
|
||||
// The namespace is already up-to-date thanks to the `updateFileNamespace` calls at the
|
||||
// start of this update. We just have to check whether the type itself is okay!
|
||||
const file_root_type_cau = pt.zcu.intern_pool.loadStructType(file_root_type).cau.unwrap().?;
|
||||
return pt.ensureCauAnalyzed(file_root_type_cau);
|
||||
} else {
|
||||
@ -493,7 +507,6 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
|
||||
|
||||
const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index });
|
||||
const cau = ip.getCau(cau_index);
|
||||
const inst_info = cau.zir_index.resolveFull(ip);
|
||||
|
||||
log.debug("ensureCauAnalyzed {d}", .{@intFromEnum(cau_index)});
|
||||
|
||||
@ -516,12 +529,9 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
|
||||
_ = zcu.outdated_ready.swapRemove(anal_unit);
|
||||
}
|
||||
|
||||
// TODO: this only works if namespace lookups in Sema trigger `ensureCauAnalyzed`, because
|
||||
// `outdated_file_root` information is not "viral", so we need that a namespace lookup first
|
||||
// handles the case where the file root is not an outdated *type* but does have an outdated
|
||||
// *namespace*. A more logically simple alternative may be for a file's root struct to register
|
||||
// a dependency on the file's entire source code (hash). Alternatively, we could make sure that
|
||||
// these are always handled first in an update. Actually, that's probably the best option.
|
||||
const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
||||
|
||||
// TODO: document this elsewhere mlugg!
|
||||
// For my own benefit, here's how a namespace update for a normal (non-file-root) type works:
|
||||
// `const S = struct { ... };`
|
||||
// We are adding or removing a declaration within this `struct`.
|
||||
@ -535,16 +545,12 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
|
||||
// * we basically do `scanDecls`, updating the namespace as needed
|
||||
// * TODO: optimize this to make sure we only do it once a generation i guess?
|
||||
// * so everyone lived happily ever after
|
||||
const file_root_outdated = switch (cau.owner.unwrap()) {
|
||||
.type => |ty| zcu.outdated_file_root.swapRemove(ty),
|
||||
.nav, .none => false,
|
||||
};
|
||||
|
||||
if (zcu.fileByIndex(inst_info.file).status != .success_zir) {
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
if (!cau_outdated and !file_root_outdated) {
|
||||
if (!cau_outdated) {
|
||||
// We can trust the current information about this `Cau`.
|
||||
if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) {
|
||||
return error.AnalysisFail;
|
||||
@ -571,10 +577,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu
|
||||
|
||||
const sema_result: SemaCauResult = res: {
|
||||
if (inst_info.inst == .main_struct_inst) {
|
||||
const changed = try pt.semaFileUpdate(inst_info.file, cau_outdated);
|
||||
// Note that this is definitely a *recreation* due to outdated, because
|
||||
// this instruction indicates that `cau.owner` is a `type`, which only
|
||||
// reaches here if `cau_outdated`.
|
||||
try pt.recreateFileRoot(inst_info.file);
|
||||
break :res .{
|
||||
.invalidate_decl_val = changed,
|
||||
.invalidate_decl_ref = changed,
|
||||
.invalidate_decl_val = true,
|
||||
.invalidate_decl_ref = true,
|
||||
};
|
||||
}
|
||||
|
||||
@ -690,8 +699,8 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter
|
||||
zcu.potentially_outdated.swapRemove(anal_unit);
|
||||
|
||||
if (func_outdated) {
|
||||
dev.check(.incremental);
|
||||
_ = zcu.outdated_ready.swapRemove(anal_unit);
|
||||
dev.check(.incremental);
|
||||
zcu.deleteUnitExports(anal_unit);
|
||||
zcu.deleteUnitReferences(anal_unit);
|
||||
}
|
||||
@ -920,12 +929,9 @@ fn createFileRootStruct(
|
||||
return wip_ty.finish(ip, new_cau_index.toOptional(), namespace_index);
|
||||
}
|
||||
|
||||
/// Re-analyze the root type of a file on an incremental update.
|
||||
/// If `type_outdated`, the struct type itself is considered outdated and is
|
||||
/// reconstructed at a new InternPool index. Otherwise, the namespace is just
|
||||
/// re-analyzed. Returns whether the decl's tyval was invalidated.
|
||||
/// Returns `error.AnalysisFail` if the file has an error.
|
||||
fn semaFileUpdate(pt: Zcu.PerThread, file_index: Zcu.File.Index, type_outdated: bool) Zcu.SemaError!bool {
|
||||
/// Recreate the root type of a file after it becomes outdated. A new struct type
|
||||
/// is constructed at a new InternPool index, reusing the namespace for efficiency.
|
||||
fn recreateFileRoot(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
|
||||
const zcu = pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
@ -934,48 +940,58 @@ fn semaFileUpdate(pt: Zcu.PerThread, file_index: Zcu.File.Index, type_outdated:
|
||||
|
||||
assert(file_root_type != .none);
|
||||
|
||||
log.debug("semaFileUpdate mod={s} sub_file_path={s} type_outdated={}", .{
|
||||
log.debug("recreateFileRoot mod={s} sub_file_path={s}", .{
|
||||
file.mod.fully_qualified_name,
|
||||
file.sub_file_path,
|
||||
type_outdated,
|
||||
});
|
||||
|
||||
if (file.status != .success_zir) {
|
||||
return error.AnalysisFail;
|
||||
}
|
||||
|
||||
if (type_outdated) {
|
||||
// Invalidate the existing type, reusing its namespace.
|
||||
const file_root_type_cau = ip.loadStructType(file_root_type).cau.unwrap().?;
|
||||
ip.removeDependenciesForDepender(
|
||||
zcu.gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .cau = file_root_type_cau }),
|
||||
);
|
||||
ip.remove(pt.tid, file_root_type);
|
||||
_ = try pt.createFileRootStruct(file_index, namespace_index);
|
||||
return true;
|
||||
}
|
||||
// Invalidate the existing type, reusing its namespace.
|
||||
const file_root_type_cau = ip.loadStructType(file_root_type).cau.unwrap().?;
|
||||
ip.removeDependenciesForDepender(
|
||||
zcu.gpa,
|
||||
InternPool.AnalUnit.wrap(.{ .cau = file_root_type_cau }),
|
||||
);
|
||||
ip.remove(pt.tid, file_root_type);
|
||||
_ = try pt.createFileRootStruct(file_index, namespace_index);
|
||||
}
|
||||
|
||||
// Only the struct's namespace is outdated.
|
||||
// Preserve the type - just scan the namespace again.
|
||||
/// Re-scan the namespace of a file's root struct type on an incremental update.
|
||||
/// The file must have successfully populated ZIR.
|
||||
/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.
|
||||
/// This is called by `updateZirRefs` for all updated files before the main work loop.
|
||||
/// This function does not perform any semantic analysis.
|
||||
fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void {
|
||||
const zcu = pt.zcu;
|
||||
|
||||
const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
|
||||
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
|
||||
const file = zcu.fileByIndex(file_index);
|
||||
assert(file.status == .success_zir);
|
||||
const file_root_type = zcu.fileRootType(file_index);
|
||||
if (file_root_type == .none) return;
|
||||
|
||||
var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
|
||||
extra_index += @intFromBool(small.has_fields_len);
|
||||
const decls_len = if (small.has_decls_len) blk: {
|
||||
const decls_len = file.zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :blk decls_len;
|
||||
} else 0;
|
||||
const decls = file.zir.bodySlice(extra_index, decls_len);
|
||||
log.debug("updateFileNamespace mod={s} sub_file_path={s}", .{
|
||||
file.mod.fully_qualified_name,
|
||||
file.sub_file_path,
|
||||
});
|
||||
|
||||
if (!type_outdated) {
|
||||
try pt.scanNamespace(namespace_index, decls);
|
||||
}
|
||||
const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
|
||||
const decls = decls: {
|
||||
const extended = file.zir.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
|
||||
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
|
||||
|
||||
return false;
|
||||
var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
|
||||
extra_index += @intFromBool(small.has_fields_len);
|
||||
const decls_len = if (small.has_decls_len) blk: {
|
||||
const decls_len = file.zir.extra[extra_index];
|
||||
extra_index += 1;
|
||||
break :blk decls_len;
|
||||
} else 0;
|
||||
break :decls file.zir.bodySlice(extra_index, decls_len);
|
||||
};
|
||||
try pt.scanNamespace(namespace_index, decls);
|
||||
}
|
||||
|
||||
/// Regardless of the file status, will create a `Decl` if none exists so that we can track
|
||||
@ -1052,7 +1068,7 @@ fn semaCau(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) !SemaCauResult {
|
||||
const anal_unit = InternPool.AnalUnit.wrap(.{ .cau = cau_index });
|
||||
|
||||
const cau = ip.getCau(cau_index);
|
||||
const inst_info = cau.zir_index.resolveFull(ip);
|
||||
const inst_info = cau.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
const zir = file.zir;
|
||||
|
||||
@ -1944,6 +1960,9 @@ const ScanDeclIter = struct {
|
||||
const cau, const nav = if (existing_cau) |cau_index| cau_nav: {
|
||||
const nav_index = ip.getCau(cau_index).owner.unwrap().nav;
|
||||
const nav = ip.getNav(nav_index);
|
||||
if (nav.name != name) {
|
||||
std.debug.panic("'{}' vs '{}'", .{ nav.name.fmt(ip), name.fmt(ip) });
|
||||
}
|
||||
assert(nav.name == name);
|
||||
assert(nav.fqn == fqn);
|
||||
break :cau_nav .{ cau_index, nav_index };
|
||||
@ -2011,7 +2030,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
|
||||
|
||||
const anal_unit = InternPool.AnalUnit.wrap(.{ .func = func_index });
|
||||
const func = zcu.funcInfo(func_index);
|
||||
const inst_info = func.zir_body_inst.resolveFull(ip);
|
||||
const inst_info = func.zir_body_inst.resolveFull(ip) orelse return error.AnalysisFail;
|
||||
const file = zcu.fileByIndex(inst_info.file);
|
||||
const zir = file.zir;
|
||||
|
||||
@ -2097,7 +2116,7 @@ fn analyzeFnBody(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!
|
||||
};
|
||||
defer inner_block.instructions.deinit(gpa);
|
||||
|
||||
const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip));
|
||||
const fn_info = sema.code.getFnInfo(func.zirBodyInstUnordered(ip).resolve(ip) orelse return error.AnalysisFail);
|
||||
|
||||
// Here we are performing "runtime semantic analysis" for a function body, which means
|
||||
// we must map the parameter ZIR instructions to `arg` AIR instructions.
|
||||
|
@ -98,7 +98,7 @@ pub fn generateLazyFunction(
|
||||
debug_output: DebugInfoOutput,
|
||||
) CodeGenError!Result {
|
||||
const zcu = pt.zcu;
|
||||
const file = Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(&zcu.intern_pool).file;
|
||||
const file = Type.fromInterned(lazy_sym.ty).typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(&zcu.intern_pool);
|
||||
const target = zcu.fileByIndex(file).mod.resolved_target.result;
|
||||
switch (target_util.zigBackend(target, false)) {
|
||||
else => unreachable,
|
||||
|
@ -2585,7 +2585,7 @@ pub fn genTypeDecl(
|
||||
const ty = Type.fromInterned(index);
|
||||
_ = try renderTypePrefix(.flush, global_ctype_pool, zcu, writer, global_ctype, .suffix, .{});
|
||||
try writer.writeByte(';');
|
||||
const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file;
|
||||
const file_scope = ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip);
|
||||
if (!zcu.fileByIndex(file_scope).mod.strip) try writer.print(" /* {} */", .{
|
||||
ty.containerTypeName(ip).fmt(ip),
|
||||
});
|
||||
|
@ -1959,7 +1959,7 @@ pub const Object = struct {
|
||||
);
|
||||
}
|
||||
|
||||
const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file);
|
||||
const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
|
||||
const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
|
||||
try o.namespaceToDebugScope(parent_namespace)
|
||||
else
|
||||
@ -2137,7 +2137,7 @@ pub const Object = struct {
|
||||
const name = try o.allocTypeName(ty);
|
||||
defer gpa.free(name);
|
||||
|
||||
const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file);
|
||||
const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
|
||||
const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
|
||||
try o.namespaceToDebugScope(parent_namespace)
|
||||
else
|
||||
@ -2772,7 +2772,7 @@ pub const Object = struct {
|
||||
fn makeEmptyNamespaceDebugType(o: *Object, ty: Type) !Builder.Metadata {
|
||||
const zcu = o.pt.zcu;
|
||||
const ip = &zcu.intern_pool;
|
||||
const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFull(ip).file);
|
||||
const file = try o.getDebugFile(ty.typeDeclInstAllowGeneratedTag(zcu).?.resolveFile(ip));
|
||||
const scope = if (ty.getParentNamespace(zcu).unwrap()) |parent_namespace|
|
||||
try o.namespaceToDebugScope(parent_namespace)
|
||||
else
|
||||
|
Loading…
Reference in New Issue
Block a user