authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-02-04 13:59:07+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:09+00:00
log1826ba69d81e182f6bd7cf4ea9b944bd6c713a28
tree0e57f2a535deaf0ffbc01aa66948971dc594802c
parenta9bfc94ee65f1dafe5c67bb8fbd58cd2372cfd28
signaturelock-open Commit is signed but in an unrecognized format.

compiler: make dependency loop errors good


9 files changed, 763 insertions(+), 440 deletions(-)

lib/std/zig/ErrorBundle.zig+4
...@@ -243,12 +243,14 @@ fn renderErrorMessage(...@@ -243,12 +243,14 @@ fn renderErrorMessage(
243 }243 }
244 try t.setColor(.reset);244 try t.setColor(.reset);
245 if (src.data.source_line != 0 and options.include_source_line) {245 if (src.data.source_line != 0 and options.include_source_line) {
246 try w.splatByteAll(' ', indent);
246 const line = eb.nullTerminatedString(src.data.source_line);247 const line = eb.nullTerminatedString(src.data.source_line);
247 for (line) |b| switch (b) {248 for (line) |b| switch (b) {
248 '\t' => try w.writeByte(' '),249 '\t' => try w.writeByte(' '),
249 else => try w.writeByte(b),250 else => try w.writeByte(b),
250 };251 };
251 try w.writeByte('\n');252 try w.writeByte('\n');
253 try w.splatByteAll(' ', indent);
252 // TODO basic unicode code point monospace width254 // TODO basic unicode code point monospace width
253 const before_caret = src.data.span_main - src.data.span_start;255 const before_caret = src.data.span_main - src.data.span_start;
254 // -1 since span.main includes the caret256 // -1 since span.main includes the caret
...@@ -267,11 +269,13 @@ fn renderErrorMessage(...@@ -267,11 +269,13 @@ fn renderErrorMessage(
267 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {269 if (src.data.reference_trace_len > 0 and options.include_reference_trace) {
268 try t.setColor(.reset);270 try t.setColor(.reset);
269 try t.setColor(.dim);271 try t.setColor(.dim);
272 try w.splatByteAll(' ', indent);
270 try w.print("referenced by:\n", .{});273 try w.print("referenced by:\n", .{});
271 var ref_index = src.end;274 var ref_index = src.end;
272 for (0..src.data.reference_trace_len) |_| {275 for (0..src.data.reference_trace_len) |_| {
273 const ref_trace = eb.extraData(ReferenceTrace, ref_index);276 const ref_trace = eb.extraData(ReferenceTrace, ref_index);
274 ref_index = ref_trace.end;277 ref_index = ref_trace.end;
278 try w.splatByteAll(' ', indent);
275 if (ref_trace.data.src_loc != .none) {279 if (ref_trace.data.src_loc != .none) {
276 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);280 const ref_src = eb.getSourceLocation(ref_trace.data.src_loc);
277 try w.print(" {s}: {s}:{d}:{d}\n", .{281 try w.print(" {s}: {s}:{d}:{d}\n", .{
src/Compilation.zig+14-101
...@@ -4189,6 +4189,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -4189,6 +4189,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
4189 }4189 }
4190 }4190 }
4191 }4191 }
4192 try zcu.addDependencyLoopErrors(&bundle);
4192 for (zcu.failed_codegen.values()) |error_msg| {4193 for (zcu.failed_codegen.values()) |error_msg| {
4193 try addModuleErrorMsg(zcu, &bundle, error_msg.*, false);4194 try addModuleErrorMsg(zcu, &bundle, error_msg.*, false);
4194 }4195 }
...@@ -4208,7 +4209,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -4208,7 +4209,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
4208 .notes_len = 1,4209 .notes_len = 1,
4209 });4210 });
4210 const notes_start = try bundle.reserveNotes(1);4211 const notes_start = try bundle.reserveNotes(1);
4211 bundle.extra.items[notes_start] = @intFromEnum(try bundle.addErrorMessage(.{4212 bundle.extra.items[notes_start] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
4212 .msg = try bundle.printString("use '--error-limit {d}' to increase limit", .{4213 .msg = try bundle.printString("use '--error-limit {d}' to increase limit", .{
4213 actual_error_count,4214 actual_error_count,
4214 }),4215 }),
...@@ -4230,10 +4231,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {...@@ -4230,10 +4231,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) error{OutOfMemory}!ErrorBundle {
4230 .notes_len = 2,4231 .notes_len = 2,
4231 });4232 });
4232 const notes_start = try bundle.reserveNotes(2);4233 const notes_start = try bundle.reserveNotes(2);
4233 bundle.extra.items[notes_start + 0] = @intFromEnum(try bundle.addErrorMessage(.{4234 bundle.extra.items[notes_start + 0] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
4234 .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),4235 .msg = try bundle.addString("run 'zig libc -h' to learn about libc installations"),
4235 }));4236 }));
4236 bundle.extra.items[notes_start + 1] = @intFromEnum(try bundle.addErrorMessage(.{4237 bundle.extra.items[notes_start + 1] = @intFromEnum(bundle.addErrorMessageAssumeCapacity(.{
4237 .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),4238 .msg = try bundle.addString("run 'zig targets' to see the targets for which zig can always provide libc"),
4238 }));4239 }));
4239 }4240 }
...@@ -4428,7 +4429,6 @@ pub fn addModuleErrorMsg(...@@ -4428,7 +4429,6 @@ pub fn addModuleErrorMsg(
4428 already_added_error: bool,4429 already_added_error: bool,
4429) Allocator.Error!void {4430) Allocator.Error!void {
4430 const gpa = eb.gpa;4431 const gpa = eb.gpa;
4431 const ip = &zcu.intern_pool;
4432 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);4432 const err_src_loc = module_err_msg.src_loc.upgrade(zcu);
4433 const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| {4433 const err_source = err_src_loc.file_scope.getSource(zcu) catch |err| {
4434 return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err);4434 return unableToLoadZcuFile(zcu, eb, err_src_loc.file_scope, err);
...@@ -4441,66 +4441,12 @@ pub fn addModuleErrorMsg(...@@ -4441,66 +4441,12 @@ pub fn addModuleErrorMsg(
4441 var ref_traces: std.ArrayList(ErrorBundle.ReferenceTrace) = .empty;4441 var ref_traces: std.ArrayList(ErrorBundle.ReferenceTrace) = .empty;
4442 defer ref_traces.deinit(gpa);4442 defer ref_traces.deinit(gpa);
44434443
4444 rt: {4444 if (module_err_msg.reference_trace_root.unwrap()) |root| {
4445 const rt_root = module_err_msg.reference_trace_root.unwrap() orelse break :rt;4445 const frame_limit: u32 = zcu.comp.reference_trace orelse refs: {
4446 const max_references = zcu.comp.reference_trace orelse refs: {4446 if (already_added_error) break :refs 0;
4447 if (already_added_error) break :rt;
4448 break :refs default_reference_trace_len;4447 break :refs default_reference_trace_len;
4449 };4448 };
44504449 try zcu.populateReferenceTrace(root, frame_limit, eb, &ref_traces);
4451 const all_references = try zcu.resolveReferences();
4452
4453 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
4454 defer seen.deinit(gpa);
4455
4456 var referenced_by = rt_root;
4457 while (all_references.get(referenced_by)) |maybe_ref| {
4458 const ref = maybe_ref orelse break;
4459 const gop = try seen.getOrPut(gpa, ref.referencer);
4460 if (gop.found_existing) break;
4461 if (ref_traces.items.len < max_references) {
4462 var last_call_src = ref.src;
4463 var opt_inline_frame = ref.inline_frame;
4464 while (opt_inline_frame.unwrap()) |inline_frame| {
4465 const f = inline_frame.ptr(zcu).*;
4466 const func_nav = ip.indexToKey(f.callee).func.owner_nav;
4467 const func_name = ip.getNav(func_nav).name.toSlice(ip);
4468 addReferenceTraceFrame(zcu, eb, &ref_traces, func_name, last_call_src, true) catch |err| switch (err) {
4469 error.OutOfMemory => |e| return e,
4470 error.AlreadyReported => {
4471 // An incomplete reference trace isn't the end of the world; just cut it off.
4472 break :rt;
4473 },
4474 };
4475 last_call_src = f.call_src;
4476 opt_inline_frame = f.parent;
4477 }
4478 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
4479 .@"comptime" => "comptime",
4480 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
4481 .type_layout => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
4482 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
4483 .memoized_state => null,
4484 };
4485 if (root_name) |n| {
4486 addReferenceTraceFrame(zcu, eb, &ref_traces, n, last_call_src, false) catch |err| switch (err) {
4487 error.OutOfMemory => |e| return e,
4488 error.AlreadyReported => {
4489 // An incomplete reference trace isn't the end of the world; just cut it off.
4490 break :rt;
4491 },
4492 };
4493 }
4494 }
4495 referenced_by = ref.referencer;
4496 }
4497
4498 if (seen.count() > ref_traces.items.len) {
4499 try ref_traces.append(gpa, .{
4500 .decl_name = @intCast(seen.count() - ref_traces.items.len),
4501 .src_loc = .none,
4502 });
4503 }
4504 }4450 }
45054451
4506 const src_loc = try eb.addSourceLocation(.{4452 const src_loc = try eb.addSourceLocation(.{
...@@ -4565,43 +4511,10 @@ pub fn addModuleErrorMsg(...@@ -4565,43 +4511,10 @@ pub fn addModuleErrorMsg(
4565 const notes_start = try eb.reserveNotes(notes_len);4511 const notes_start = try eb.reserveNotes(notes_len);
45664512
4567 for (notes_start.., notes.keys()) |i, note| {4513 for (notes_start.., notes.keys()) |i, note| {
4568 eb.extra.items[i] = @intFromEnum(try eb.addErrorMessage(note));4514 eb.extra.items[i] = @intFromEnum(eb.addErrorMessageAssumeCapacity(note));
4569 }4515 }
4570}4516}
45714517
4572fn addReferenceTraceFrame(
4573 zcu: *Zcu,
4574 eb: *ErrorBundle.Wip,
4575 ref_traces: *std.ArrayList(ErrorBundle.ReferenceTrace),
4576 name: []const u8,
4577 lazy_src: Zcu.LazySrcLoc,
4578 inlined: bool,
4579) error{ OutOfMemory, AlreadyReported }!void {
4580 const gpa = zcu.gpa;
4581 const src = lazy_src.upgrade(zcu);
4582 const source = src.file_scope.getSource(zcu) catch |err| {
4583 try unableToLoadZcuFile(zcu, eb, src.file_scope, err);
4584 return error.AlreadyReported;
4585 };
4586 const span = src.span(zcu) catch |err| {
4587 try unableToLoadZcuFile(zcu, eb, src.file_scope, err);
4588 return error.AlreadyReported;
4589 };
4590 const loc = std.zig.findLineColumn(source, span.main);
4591 try ref_traces.append(gpa, .{
4592 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
4593 .src_loc = try eb.addSourceLocation(.{
4594 .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}),
4595 .span_start = span.start,
4596 .span_main = span.main,
4597 .span_end = span.end,
4598 .line = @intCast(loc.line),
4599 .column = @intCast(loc.column),
4600 .source_line = 0,
4601 }),
4602 });
4603}
4604
4605fn addWholeFileError(4518fn addWholeFileError(
4606 zcu: *Zcu,4519 zcu: *Zcu,
4607 eb: *ErrorBundle.Wip,4520 eb: *ErrorBundle.Wip,
...@@ -5243,11 +5156,11 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v...@@ -5243,11 +5156,11 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
52435156
5244 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {5157 const maybe_err: Zcu.SemaError!void = switch (unit.unwrap()) {
5245 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),5158 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
5246 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),5159 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav, null),
5247 .nav_val => |nav| pt.ensureNavValUpToDate(nav),5160 .nav_val => |nav| pt.ensureNavValUpToDate(nav, null),
5248 .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)),5161 .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty), null),
5249 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),5162 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage, null),
5250 .func => |func| pt.ensureFuncBodyUpToDate(func),5163 .func => |func| pt.ensureFuncBodyUpToDate(func, null),
5251 };5164 };
5252 maybe_err catch |err| switch (err) {5165 maybe_err catch |err| switch (err) {
5253 error.OutOfMemory => |e| return e,5166 error.OutOfMemory => |e| return e,
src/Sema.zig+149-113
...@@ -3260,7 +3260,7 @@ fn zirAllocExtended(...@@ -3260,7 +3260,7 @@ fn zirAllocExtended(
3260 } else .none;3260 } else .none;
32613261
3262 if (small.has_type) {3262 if (small.has_type) {
3263 try sema.ensureLayoutResolved(var_ty, ty_src);3263 try sema.ensureLayoutResolved(var_ty, var_src, if (small.is_const) .constant else .variable);
3264 if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) {3264 if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) {
3265 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);3265 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
3266 }3266 }
...@@ -3324,7 +3324,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -3324,7 +3324,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
3324 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });3324 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
3325 const var_src = block.nodeOffset(inst_data.src_node);3325 const var_src = block.nodeOffset(inst_data.src_node);
3326 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3326 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3327 try sema.ensureLayoutResolved(var_ty, ty_src);3327 try sema.ensureLayoutResolved(var_ty, var_src, .variable);
3328 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);3328 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
3329}3329}
33303330
...@@ -3758,7 +3758,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -3758,7 +3758,7 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
3758 const var_src = block.nodeOffset(inst_data.src_node);3758 const var_src = block.nodeOffset(inst_data.src_node);
37593759
3760 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3760 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3761 try sema.ensureLayoutResolved(var_ty, ty_src);3761 try sema.ensureLayoutResolved(var_ty, var_src, .constant);
3762 if (block.isComptime() or var_ty.comptimeOnly(zcu)) {3762 if (block.isComptime() or var_ty.comptimeOnly(zcu)) {
3763 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);3763 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
3764 }3764 }
...@@ -3790,7 +3790,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -3790,7 +3790,7 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
3790 const var_src = block.nodeOffset(inst_data.src_node);3790 const var_src = block.nodeOffset(inst_data.src_node);
37913791
3792 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3792 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3793 try sema.ensureLayoutResolved(var_ty, ty_src);3793 try sema.ensureLayoutResolved(var_ty, var_src, .variable);
3794 if (block.isComptime()) {3794 if (block.isComptime()) {
3795 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);3795 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
3796 }3796 }
...@@ -4148,7 +4148,7 @@ fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile...@@ -4148,7 +4148,7 @@ fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compile
4148 const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;4148 const un_node = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4149 const ptr = sema.resolveInst(un_node.operand);4149 const ptr = sema.resolveInst(un_node.operand);
4150 const src = block.nodeOffset(un_node.src_node);4150 const src = block.nodeOffset(un_node.src_node);
4151 try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu), src);4151 try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu), src, .init);
4152 return sema.optEuBasePtrInit(block, ptr, src);4152 return sema.optEuBasePtrInit(block, ptr, src);
4153}4153}
41544154
...@@ -4651,7 +4651,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -4651,7 +4651,7 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
4651 }4651 }
46524652
4653 const elem_ty = operand_ty.childType(zcu);4653 const elem_ty = operand_ty.childType(zcu);
4654 try sema.ensureLayoutResolved(elem_ty, src);4654 try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);
46554655
4656 const need_comptime = switch (elem_ty.classify(zcu)) {4656 const need_comptime = switch (elem_ty.classify(zcu)) {
4657 .no_possible_value => return sema.fail(block, src, "cannot load {s} type '{f}'", .{4657 .no_possible_value => return sema.fail(block, src, "cannot load {s} type '{f}'", .{
...@@ -7037,7 +7037,7 @@ fn analyzeCall(...@@ -7037,7 +7037,7 @@ fn analyzeCall(
70377037
7038 break :ret_ty full_ty;7038 break :ret_ty full_ty;
7039 };7039 };
7040 try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src);7040 try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src, .return_type);
70417041
7042 // If we've discovered after evaluating arguments that a generic function instantiation is7042 // If we've discovered after evaluating arguments that a generic function instantiation is
7043 // comptime-only, then we can mark the block as comptime *now*.7043 // comptime-only, then we can mark the block as comptime *now*.
...@@ -7134,7 +7134,6 @@ fn analyzeCall(...@@ -7134,7 +7134,6 @@ fn analyzeCall(
7134 .generic_owner = func_val.?.toIntern(),7134 .generic_owner = func_val.?.toIntern(),
7135 .comptime_args = comptime_args,7135 .comptime_args = comptime_args,
7136 });7136 });
7137 try sema.ensureLayoutResolved(.fromInterned(ip.typeOf(func_instance)), call_src);
7138 if (zcu.comp.debugIncremental()) {7137 if (zcu.comp.debugIncremental()) {
7139 const nav = ip.indexToKey(func_instance).func.owner_nav;7138 const nav = ip.indexToKey(func_instance).func.owner_nav;
7140 const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav);7139 const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav);
...@@ -7169,7 +7168,7 @@ fn analyzeCall(...@@ -7169,7 +7168,7 @@ fn analyzeCall(
7169 };7168 };
71707169
7171 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).@"struct".fields.len + runtime_args.len);7170 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).@"struct".fields.len + runtime_args.len);
7172 const maybe_opv = try block.addInst(.{7171 const call_ref = try block.addInst(.{
7173 .tag = call_tag,7172 .tag = call_tag,
7174 .data = .{ .pl_op = .{7173 .data = .{ .pl_op = .{
7175 .operand = runtime_func,7174 .operand = runtime_func,
...@@ -7180,8 +7179,10 @@ fn analyzeCall(...@@ -7180,8 +7179,10 @@ fn analyzeCall(
7180 });7179 });
7181 sema.appendRefsAssumeCapacity(runtime_args);7180 sema.appendRefsAssumeCapacity(runtime_args);
71827181
7182 const actual_ret_ty = sema.typeOf(call_ref);
7183
7183 if (ensure_result_used) {7184 if (ensure_result_used) {
7184 try sema.ensureResultUsed(block, sema.typeOf(maybe_opv), call_src);7185 try sema.ensureResultUsed(block, actual_ret_ty, call_src);
7185 }7186 }
71867187
7187 if (call_tag == .call_always_tail) {7188 if (call_tag == .call_always_tail) {
...@@ -7191,28 +7192,31 @@ fn analyzeCall(...@@ -7191,28 +7192,31 @@ fn analyzeCall(
7191 .pointer => func_or_ptr_ty.childType(zcu),7192 .pointer => func_or_ptr_ty.childType(zcu),
7192 else => unreachable,7193 else => unreachable,
7193 };7194 };
7194 return sema.handleTailCall(block, call_src, runtime_func_ty, maybe_opv);7195 return sema.handleTailCall(block, call_src, runtime_func_ty, call_ref);
7195 }
7196
7197 if (resolved_ret_ty.isNoReturn(zcu)) {
7198 const want_check = c: {
7199 if (!block.wantSafety()) break :c false;
7200 if (func_val != null) break :c false;
7201 break :c true;
7202 };
7203 if (want_check) {
7204 try sema.safetyPanic(block, call_src, .noreturn_returned);
7205 } else {
7206 _ = try block.addNoOp(.unreach);
7207 }
7208 return .unreachable_value;
7209 }7196 }
72107197
7211 try sema.ensureLayoutResolved(sema.typeOf(maybe_opv), func_ret_ty_src);7198 switch (actual_ret_ty.classify(zcu)) {
7212 if (try sema.typeOf(maybe_opv).onePossibleValue(pt)) |opv| {7199 .no_possible_value => {
7213 return .fromValue(opv);7200 const want_check = c: {
7214 } else {7201 if (!block.wantSafety()) break :c false;
7215 return maybe_opv;7202 if (func_val != null) break :c false;
7203 break :c true;
7204 };
7205 if (want_check) {
7206 try sema.safetyPanic(block, call_src, .noreturn_returned);
7207 } else {
7208 _ = try block.addNoOp(.unreach);
7209 }
7210 return .unreachable_value;
7211 },
7212 .one_possible_value => {
7213 return .fromValue((try actual_ret_ty.onePossibleValue(pt)).?);
7214 },
7215 .runtime => {
7216 return call_ref;
7217 },
7218 .partially_comptime => unreachable,
7219 .fully_comptime => unreachable,
7216 }7220 }
7217 }7221 }
72187222
...@@ -7279,11 +7283,6 @@ fn analyzeCall(...@@ -7279,11 +7283,6 @@ fn analyzeCall(
7279 }7283 }
7280 }7284 }
72817285
7282 // We're about to do an inline call; if the return type expression was generic, the return type
7283 // may not be resolved yet. It's correct to resolve it because the function is going to return a
7284 // value of this type.
7285 try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src);
7286
7287 // For an inline call, we depend on the source code of the whole function definition.7286 // For an inline call, we depend on the source code of the whole function definition.
7288 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });7287 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });
72897288
...@@ -8051,7 +8050,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8051,7 +8050,7 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8051 if (dest_ty.zigTypeTag(zcu) != .@"enum") {8050 if (dest_ty.zigTypeTag(zcu) != .@"enum") {
8052 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});8051 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)});
8053 }8052 }
8054 try sema.ensureLayoutResolved(dest_ty, src);8053 try sema.ensureLayoutResolved(dest_ty, src, .init);
8055 _ = try sema.checkIntType(block, operand_src, operand_ty);8054 _ = try sema.checkIntType(block, operand_src, operand_ty);
80568055
8057 if (sema.resolveValue(operand)) |int_val| {8056 if (sema.resolveValue(operand)) |int_val| {
...@@ -8114,7 +8113,7 @@ fn zirOptionalPayloadPtr(...@@ -8114,7 +8113,7 @@ fn zirOptionalPayloadPtr(
81148113
8115 const ptr_ty = sema.typeOf(optional_ptr);8114 const ptr_ty = sema.typeOf(optional_ptr);
8116 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);8115 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);
8117 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src);8116 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src, .ptr_access);
81188117
8119 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);8118 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
8120}8119}
...@@ -8311,7 +8310,7 @@ fn zirErrUnionPayloadPtr(...@@ -8311,7 +8310,7 @@ fn zirErrUnionPayloadPtr(
83118310
8312 const ptr_ty = sema.typeOf(operand);8311 const ptr_ty = sema.typeOf(operand);
8313 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);8312 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer);
8314 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src);8313 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src, .ptr_access);
83158314
8316 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);8315 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
8317}8316}
...@@ -9020,7 +9019,6 @@ fn funcCommon(...@@ -9020,7 +9019,6 @@ fn funcCommon(
9020 const io = comp.io;9019 const io = comp.io;
9021 const ip = &zcu.intern_pool;9020 const ip = &zcu.intern_pool;
90229021
9023 const src = block.nodeOffset(src_node_offset);
9024 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });9022 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
9025 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });9023 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
90269024
...@@ -9090,7 +9088,7 @@ fn funcCommon(...@@ -9090,7 +9088,7 @@ fn funcCommon(
9090 .lbrace_column = @as(u16, @truncate(src_locs.columns)),9088 .lbrace_column = @as(u16, @truncate(src_locs.columns)),
9091 .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),9089 .rbrace_column = @as(u16, @truncate(src_locs.columns >> 16)),
9092 }));9090 }));
9093 try sema.ensureLayoutResolved(func_val.typeOf(zcu), src);9091 try sema.ensureLayoutResolved(func_val.typeOf(zcu), ret_ty_src, .return_type);
9094 return .fromValue(func_val);9092 return .fromValue(func_val);
9095 }9093 }
90969094
...@@ -9105,7 +9103,7 @@ fn funcCommon(...@@ -9105,7 +9103,7 @@ fn funcCommon(
9105 });9103 });
91069104
9107 if (has_body) {9105 if (has_body) {
9108 try sema.ensureLayoutResolved(.fromInterned(func_ty), src);9106 try sema.ensureLayoutResolved(.fromInterned(func_ty), ret_ty_src, .return_type);
9109 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{9107 return .fromIntern(try ip.getFuncDecl(gpa, io, pt.tid, .{
9110 .owner_nav = sema.owner.unwrap().nav_val,9108 .owner_nav = sema.owner.unwrap().nav_val,
9111 .ty = func_ty,9109 .ty = func_ty,
...@@ -9761,7 +9759,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -9761,7 +9759,7 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
9761 return sema.failWithOwnedErrorMsg(block, msg);9759 return sema.failWithOwnedErrorMsg(block, msg);
9762 }9760 }
9763 try sema.checkIndexable(block, src, indexable_ty);9761 try sema.checkIndexable(block, src, indexable_ty);
9764 try sema.ensureLayoutResolved(indexable_ty.childType(zcu), src);9762 try sema.ensureLayoutResolved(indexable_ty.childType(zcu), src, .ptr_access);
9765 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);9763 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);
9766}9764}
97679765
...@@ -9975,14 +9973,15 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp...@@ -9975,14 +9973,15 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
9975 const raw_operand_ty = sema.typeOf(eu_maybe_ptr);9973 const raw_operand_ty = sema.typeOf(eu_maybe_ptr);
9976 if (!non_err_case.operand_is_ref) break :err_union_ty raw_operand_ty;9974 if (!non_err_case.operand_is_ref) break :err_union_ty raw_operand_ty;
9977 try sema.checkPtrOperand(block, operand_src, raw_operand_ty);9975 try sema.checkPtrOperand(block, operand_src, raw_operand_ty);
9978 break :err_union_ty raw_operand_ty.childType(zcu);9976 const child_ty = raw_operand_ty.childType(zcu);
9977 try sema.ensureLayoutResolved(child_ty, operand_src, .ptr_access);
9978 break :err_union_ty child_ty;
9979 };9979 };
9980 if (err_union_ty.zigTypeTag(zcu) != .error_union) {9980 if (err_union_ty.zigTypeTag(zcu) != .error_union) {
9981 return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{9981 return sema.fail(block, operand_src, "expected error union type, found '{f}'", .{
9982 err_union_ty.fmt(pt),9982 err_union_ty.fmt(pt),
9983 });9983 });
9984 }9984 }
9985 try sema.ensureLayoutResolved(err_union_ty, operand_src);
99869985
9987 const non_err_cond = if (non_err_case.operand_is_ref)9986 const non_err_cond = if (non_err_case.operand_is_ref)
9988 try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr)9987 try sema.analyzePtrIsNonErr(block, operand_src, eu_maybe_ptr)
...@@ -11281,11 +11280,12 @@ fn validateSwitchBlock(...@@ -11281,11 +11280,12 @@ fn validateSwitchBlock(
11281 const raw_operand_ty = sema.typeOf(raw_operand);11280 const raw_operand_ty = sema.typeOf(raw_operand);
11282 if (operand_is_ref) {11281 if (operand_is_ref) {
11283 try sema.checkPtrType(block, operand_src, raw_operand_ty, false);11282 try sema.checkPtrType(block, operand_src, raw_operand_ty, false);
11284 break :operand_ty raw_operand_ty.childType(zcu);11283 const child_ty = raw_operand_ty.childType(zcu);
11284 try sema.ensureLayoutResolved(child_ty, operand_src, .ptr_access);
11285 break :operand_ty child_ty;
11285 }11286 }
11286 break :operand_ty raw_operand_ty;11287 break :operand_ty raw_operand_ty;
11287 };11288 };
11288 try sema.ensureLayoutResolved(operand_ty, operand_src);
1128911289
11290 const item_ty: Type = item_ty: {11290 const item_ty: Type = item_ty: {
11291 switch (operand_ty.zigTypeTag(zcu)) {11291 switch (operand_ty.zigTypeTag(zcu)) {
...@@ -12844,7 +12844,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -12844,7 +12844,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
12844 const name_src = block.builtinCallArgSrc(inst_data.src_node, 1);12844 const name_src = block.builtinCallArgSrc(inst_data.src_node, 1);
12845 const ty = try sema.resolveType(block, ty_src, extra.lhs);12845 const ty = try sema.resolveType(block, ty_src, extra.lhs);
12846 const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name });12846 const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name });
12847 try sema.ensureLayoutResolved(ty, ty_src);12847 try sema.ensureLayoutResolved(ty, ty_src, .field_queried);
12848 const ip = &zcu.intern_pool;12848 const ip = &zcu.intern_pool;
1284912849
12850 const has_field = hf: {12850 const has_field = hf: {
...@@ -15194,6 +15194,7 @@ fn analyzeArithmetic(...@@ -15194,6 +15194,7 @@ fn analyzeArithmetic(
15194 });15194 });
15195 }15195 }
1519615196
15197 try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src, .ptr_offset);
15197 const elem_size = lhs_ty.childType(zcu).abiSize(zcu);15198 const elem_size = lhs_ty.childType(zcu).abiSize(zcu);
15198 if (elem_size == 0) {15199 if (elem_size == 0) {
15199 return sema.fail(block, src, "pointer subtraction requires element type '{f}' to have runtime bits", .{15200 return sema.fail(block, src, "pointer subtraction requires element type '{f}' to have runtime bits", .{
...@@ -15246,7 +15247,7 @@ fn analyzeArithmetic(...@@ -15246,7 +15247,7 @@ fn analyzeArithmetic(
15246 else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"),15247 else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"),
15247 };15248 };
1524815249
15249 try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src);15250 try sema.ensureLayoutResolved(lhs_ty.childType(zcu), src, .ptr_offset);
15250 return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, rhs_src);15251 return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, rhs_src);
15251 },15252 },
15252 }15253 }
...@@ -15879,7 +15880,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -15879,7 +15880,7 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
15879 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;15880 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
15880 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);15881 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
15881 const ty = try sema.resolveType(block, operand_src, inst_data.operand);15882 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
15882 try sema.ensureLayoutResolved(ty, operand_src);15883 try sema.ensureLayoutResolved(ty, operand_src, .size_of);
15883 switch (ty.classify(zcu)) {15884 switch (ty.classify(zcu)) {
15884 .no_possible_value,15885 .no_possible_value,
15885 => return sema.fail(block, operand_src, "no size available for uninstantiable type '{f}'", .{ty.fmt(pt)}),15886 => return sema.fail(block, operand_src, "no size available for uninstantiable type '{f}'", .{ty.fmt(pt)}),
...@@ -15934,7 +15935,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -15934,7 +15935,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
15934 .@"anyframe",15935 .@"anyframe",
15935 => {},15936 => {},
15936 }15937 }
15937 try sema.ensureLayoutResolved(operand_ty, operand_src);15938 try sema.ensureLayoutResolved(operand_ty, operand_src, .size_of);
15938 return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu)));15939 return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu)));
15939}15940}
1594015941
...@@ -16185,7 +16186,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16185,7 +16186,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16185 const type_info_ty = try sema.getBuiltinType(src, .Type);16186 const type_info_ty = try sema.getBuiltinType(src, .Type);
16186 const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;16187 const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;
1618716188
16188 try sema.ensureLayoutResolved(ty, src);16189 try sema.ensureLayoutResolved(ty, src, .type_info);
1618916190
16190 if (ty.typeDeclInst(zcu)) |type_decl_inst| {16191 if (ty.typeDeclInst(zcu)) |type_decl_inst| {
16191 try sema.declareDependency(.{ .namespace = type_decl_inst });16192 try sema.declareDependency(.{ .namespace = type_decl_inst });
...@@ -16345,7 +16346,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16345,7 +16346,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16345 const alignment_val = try pt.intValue(.comptime_int, bytes: {16346 const alignment_val = try pt.intValue(.comptime_int, bytes: {
16346 if (info.flags.alignment.toByteUnits()) |b| break :bytes b;16347 if (info.flags.alignment.toByteUnits()) |b| break :bytes b;
16347 const elem_ty: Type = .fromInterned(info.child);16348 const elem_ty: Type = .fromInterned(info.child);
16348 try sema.ensureLayoutResolved(elem_ty, src);16349 try sema.ensureLayoutResolved(elem_ty, src, .type_info);
16349 break :bytes elem_ty.abiAlignment(zcu).toByteUnits().?;16350 break :bytes elem_ty.abiAlignment(zcu).toByteUnits().?;
16350 });16351 });
1635116352
...@@ -18233,7 +18234,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18233,7 +18234,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18233 elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size,18234 elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size,
18234 });18235 });
18235 }18236 }
18236 try sema.ensureLayoutResolved(elem_ty, elem_ty_src);18237 try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .bit_ptr_child);
18237 const elem_bit_size = elem_ty.bitSize(zcu);18238 const elem_bit_size = elem_ty.bitSize(zcu);
18238 if (elem_bit_size > host_size * 8 - bit_offset) {18239 if (elem_bit_size > host_size * 8 - bit_offset) {
18239 return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{18240 return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{
...@@ -18302,7 +18303,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -18302,7 +18303,7 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
18302 const pt = sema.pt;18303 const pt = sema.pt;
18303 const zcu = pt.zcu;18304 const zcu = pt.zcu;
1830418305
18305 try sema.ensureLayoutResolved(obj_ty, ty_src);18306 try sema.ensureLayoutResolved(obj_ty, ty_src, .init);
1830618307
18307 switch (obj_ty.zigTypeTag(zcu)) {18308 switch (obj_ty.zigTypeTag(zcu)) {
18308 .@"struct" => return sema.structInitEmpty(block, obj_ty, src, src),18309 .@"struct" => return sema.structInitEmpty(block, obj_ty, src, src),
...@@ -18367,7 +18368,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is...@@ -18367,7 +18368,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is
18367 });18368 });
18368 } else ty_operand;18369 } else ty_operand;
1836918370
18370 try sema.ensureLayoutResolved(init_ty, src);18371 try sema.ensureLayoutResolved(init_ty, src, .init);
1837118372
18372 const obj_ty = init_ty.optEuBaseType(zcu);18373 const obj_ty = init_ty.optEuBaseType(zcu);
1837318374
...@@ -18486,7 +18487,7 @@ fn zirStructInit(...@@ -18486,7 +18487,7 @@ fn zirStructInit(
18486 // The type wasn't actually known, so treat this as an anon struct init.18487 // The type wasn't actually known, so treat this as an anon struct init.
18487 return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref);18488 return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref);
18488 };18489 };
18489 try sema.ensureLayoutResolved(result_ty, src);18490 try sema.ensureLayoutResolved(result_ty, src, .init);
18490 const resolved_ty = result_ty.optEuBaseType(zcu);18491 const resolved_ty = result_ty.optEuBaseType(zcu);
1849118492
18492 if (resolved_ty.zigTypeTag(zcu) == .@"struct") {18493 if (resolved_ty.zigTypeTag(zcu) == .@"struct") {
...@@ -18951,7 +18952,7 @@ fn structInitAnon(...@@ -18951,7 +18952,7 @@ fn structInitAnon(
18951 };18952 };
18952 try sema.addTypeReferenceEntry(src, struct_ty);18953 try sema.addTypeReferenceEntry(src, struct_ty);
18953 // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.18954 // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty.
18954 try sema.ensureLayoutResolved(struct_ty, src);18955 try sema.ensureLayoutResolved(struct_ty, src, .init);
1895518956
18956 _ = opt_runtime_index orelse {18957 _ = opt_runtime_index orelse {
18957 const struct_val = try pt.aggregateValue(struct_ty, values);18958 const struct_val = try pt.aggregateValue(struct_ty, values);
...@@ -19270,7 +19271,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -19270,7 +19271,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
19270 const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);19271 const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);
19271 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);19272 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
19272 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name });19273 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name });
19273 try sema.ensureLayoutResolved(aggregate_ty, ty_src);19274 try sema.ensureLayoutResolved(aggregate_ty, ty_src, .field_queried);
19274 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);19275 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
19275}19276}
1927619277
...@@ -19290,7 +19291,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp...@@ -19290,7 +19291,7 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
19290 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu);19291 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu);
19291 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);19292 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
19292 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls);19293 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls);
19293 try sema.ensureLayoutResolved(aggregate_ty, ty_src);19294 try sema.ensureLayoutResolved(aggregate_ty, ty_src, .init);
19294 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);19295 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
19295}19296}
1929619297
...@@ -19390,7 +19391,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -19390,7 +19391,7 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
19390 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;19391 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
19391 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);19392 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
19392 const ty = try sema.resolveType(block, operand_src, inst_data.operand);19393 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
19393 try sema.ensureLayoutResolved(ty, operand_src);19394 try sema.ensureLayoutResolved(ty, operand_src, .align_of);
19394 if (ty.isNoReturn(zcu)) {19395 if (ty.isNoReturn(zcu)) {
19395 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});19396 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});
19396 }19397 }
...@@ -19874,7 +19875,6 @@ fn zirReifyFn(...@@ -19874,7 +19875,6 @@ fn zirReifyFn(
19874 const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });19875 const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });
1987519876
19876 const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);19877 const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);
19877 try sema.ensureLayoutResolved(ret_ty, ret_ty_src);
1987819878
19879 const fn_attrs_uncoerced = sema.resolveInst(extra.fn_attrs);19879 const fn_attrs_uncoerced = sema.resolveInst(extra.fn_attrs);
19880 const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);19880 const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);
...@@ -19899,10 +19899,6 @@ fn zirReifyFn(...@@ -19899,10 +19899,6 @@ fn zirReifyFn(
19899 param_types_src,19899 param_types_src,
19900 fn_attrs.@"callconv",19900 fn_attrs.@"callconv",
19901 );19901 );
19902 try sema.ensureLayoutResolved(param_ty, param_types_src);
19903 if (param_ty.comptimeOnly(zcu)) {
19904 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)});
19905 }
19906 if (param_attrs.@"noalias") {19902 if (param_attrs.@"noalias") {
19907 if (param_idx > 31) {19903 if (param_idx > 31) {
19908 return sema.fail(block, param_attrs_src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{});19904 return sema.fail(block, param_attrs_src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{});
...@@ -20811,8 +20807,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -20811,8 +20807,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2081120807
20812 const elem_ty = ptr_ty.nullablePtrElem(zcu);20808 const elem_ty = ptr_ty.nullablePtrElem(zcu);
2081320809
20814 // We'll need to validate the pointer alignment.20810 try sema.ensureLayoutResolved(elem_ty, src, .align_check);
20815 try sema.ensureLayoutResolved(elem_ty, src);
20816 const ptr_align = ptr_ty.ptrAlignment(zcu);20811 const ptr_align = ptr_ty.ptrAlignment(zcu);
2081720812
20818 if (ptr_ty.isSlice(zcu)) {20813 if (ptr_ty.isSlice(zcu)) {
...@@ -21155,8 +21150,8 @@ fn ptrCastFull(...@@ -21155,8 +21150,8 @@ fn ptrCastFull(
21155 const src_info = operand_ty.ptrInfo(zcu);21150 const src_info = operand_ty.ptrInfo(zcu);
21156 const dest_info = dest_ty.ptrInfo(zcu);21151 const dest_info = dest_ty.ptrInfo(zcu);
2115721152
21158 try sema.ensureLayoutResolved(.fromInterned(src_info.child), operand_src);21153 try sema.ensureLayoutResolved(.fromInterned(src_info.child), operand_src, .align_check);
21159 try sema.ensureLayoutResolved(.fromInterned(dest_info.child), src);21154 try sema.ensureLayoutResolved(.fromInterned(dest_info.child), src, .align_check);
2116021155
21161 const DestSliceLen = union(enum) {21156 const DestSliceLen = union(enum) {
21162 undef,21157 undef,
...@@ -21927,7 +21922,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6...@@ -21927,7 +21922,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
21927 const ty = try sema.resolveType(block, ty_src, extra.lhs);21922 const ty = try sema.resolveType(block, ty_src, extra.lhs);
21928 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name });21923 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name });
2192921924
21930 try sema.ensureLayoutResolved(ty, ty_src);21925 try sema.ensureLayoutResolved(ty, ty_src, .field_queried);
2193121926
21932 const pt = sema.pt;21927 const pt = sema.pt;
21933 const zcu = pt.zcu;21928 const zcu = pt.zcu;
...@@ -23010,7 +23005,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -23010,7 +23005,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
23010 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);23005 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
23011 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order });23006 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order });
2301223007
23013 try sema.ensureLayoutResolved(elem_ty, elem_ty_src);23008 try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .ptr_access);
2301423009
23015 switch (order) {23010 switch (order) {
23016 .release, .acq_rel => {23011 .release, .acq_rel => {
...@@ -23330,7 +23325,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -23330,7 +23325,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
23330 return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)});23325 return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)});
23331 }23326 }
23332 const parent_ty: Type = .fromInterned(parent_ptr_info.child);23327 const parent_ty: Type = .fromInterned(parent_ptr_info.child);
23333 try sema.ensureLayoutResolved(parent_ty, inst_src);23328 try sema.ensureLayoutResolved(parent_ty, inst_src, .field_used);
23334 switch (parent_ty.zigTypeTag(zcu)) {23329 switch (parent_ty.zigTypeTag(zcu)) {
23335 .@"struct", .@"union" => {},23330 .@"struct", .@"union" => {},
23336 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}),23331 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}),
...@@ -23938,8 +23933,8 @@ fn zirMemcpy(...@@ -23938,8 +23933,8 @@ fn zirMemcpy(
23938 const dest_elem_ty = dest_ty.indexableElem(zcu);23933 const dest_elem_ty = dest_ty.indexableElem(zcu);
23939 const src_elem_ty = src_ty.indexableElem(zcu);23934 const src_elem_ty = src_ty.indexableElem(zcu);
2394023935
23941 try sema.ensureLayoutResolved(dest_elem_ty, dest_src);23936 try sema.ensureLayoutResolved(dest_elem_ty, dest_src, .ptr_access);
23942 try sema.ensureLayoutResolved(src_elem_ty, src_src);23937 try sema.ensureLayoutResolved(src_elem_ty, src_src, .ptr_access);
2394323938
23944 const imc = try sema.coerceInMemoryAllowed(23939 const imc = try sema.coerceInMemoryAllowed(
23945 block,23940 block,
...@@ -25470,7 +25465,7 @@ fn fieldPtrLoad(...@@ -25470,7 +25465,7 @@ fn fieldPtrLoad(
25470 const object_ptr_ty = sema.typeOf(object_ptr);25465 const object_ptr_ty = sema.typeOf(object_ptr);
25471 assert(object_ptr_ty.zigTypeTag(zcu) == .pointer);25466 assert(object_ptr_ty.zigTypeTag(zcu) == .pointer);
25472 const pointee_ty = object_ptr_ty.childType(zcu);25467 const pointee_ty = object_ptr_ty.childType(zcu);
25473 try sema.ensureLayoutResolved(pointee_ty, src);25468 try sema.ensureLayoutResolved(pointee_ty, src, .ptr_access);
25474 if (try pointee_ty.onePossibleValue(pt)) |opv| {25469 if (try pointee_ty.onePossibleValue(pt)) |opv| {
25475 const object: Air.Inst.Ref = .fromValue(opv);25470 const object: Air.Inst.Ref = .fromValue(opv);
25476 return fieldVal(sema, block, src, object, field_name, field_name_src);25471 return fieldVal(sema, block, src, object, field_name, field_name_src);
...@@ -25606,7 +25601,7 @@ fn fieldVal(...@@ -25606,7 +25601,7 @@ fn fieldVal(
25606 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25601 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
25607 return inst;25602 return inst;
25608 }25603 }
25609 try sema.ensureLayoutResolved(child_type, src);25604 try sema.ensureLayoutResolved(child_type, src, .field_used);
25610 if (child_type.unionTagType(zcu)) |enum_ty| {25605 if (child_type.unionTagType(zcu)) |enum_ty| {
25611 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {25606 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {
25612 const field_index: u32 = @intCast(field_index_usize);25607 const field_index: u32 = @intCast(field_index_usize);
...@@ -25619,7 +25614,7 @@ fn fieldVal(...@@ -25619,7 +25614,7 @@ fn fieldVal(
25619 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25614 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
25620 return inst;25615 return inst;
25621 }25616 }
25622 try sema.ensureLayoutResolved(child_type, src);25617 try sema.ensureLayoutResolved(child_type, src, .field_used);
25623 const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse25618 const field_index_usize = child_type.enumFieldIndex(field_name, zcu) orelse
25624 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);25619 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
25625 const field_index: u32 = @intCast(field_index_usize);25620 const field_index: u32 = @intCast(field_index_usize);
...@@ -25645,7 +25640,7 @@ fn fieldVal(...@@ -25645,7 +25640,7 @@ fn fieldVal(
25645 },25640 },
25646 .@"struct" => if (is_pointer_to) {25641 .@"struct" => if (is_pointer_to) {
25647 // Avoid loading the entire struct by fetching a pointer and loading that25642 // Avoid loading the entire struct by fetching a pointer and loading that
25648 try sema.ensureLayoutResolved(inner_ty, src);25643 try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
25649 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty);25644 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty);
25650 return sema.analyzeLoad(block, src, field_ptr, object_src);25645 return sema.analyzeLoad(block, src, field_ptr, object_src);
25651 } else {25646 } else {
...@@ -25653,7 +25648,7 @@ fn fieldVal(...@@ -25653,7 +25648,7 @@ fn fieldVal(
25653 },25648 },
25654 .@"union" => if (is_pointer_to) {25649 .@"union" => if (is_pointer_to) {
25655 // Avoid loading the entire union by fetching a pointer and loading that25650 // Avoid loading the entire union by fetching a pointer and loading that
25656 try sema.ensureLayoutResolved(inner_ty, src);25651 try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
25657 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);25652 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
25658 return sema.analyzeLoad(block, src, field_ptr, object_src);25653 return sema.analyzeLoad(block, src, field_ptr, object_src);
25659 } else {25654 } else {
...@@ -25837,7 +25832,7 @@ fn fieldPtr(...@@ -25837,7 +25832,7 @@ fn fieldPtr(
25837 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25832 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
25838 return inst;25833 return inst;
25839 }25834 }
25840 try sema.ensureLayoutResolved(child_type, src);25835 try sema.ensureLayoutResolved(child_type, src, .field_used);
25841 if (child_type.unionTagType(zcu)) |enum_ty| {25836 if (child_type.unionTagType(zcu)) |enum_ty| {
25842 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {25837 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {
25843 const field_index_u32: u32 = @intCast(field_index);25838 const field_index_u32: u32 = @intCast(field_index);
...@@ -25851,7 +25846,7 @@ fn fieldPtr(...@@ -25851,7 +25846,7 @@ fn fieldPtr(
25851 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25846 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
25852 return inst;25847 return inst;
25853 }25848 }
25854 try sema.ensureLayoutResolved(child_type, src);25849 try sema.ensureLayoutResolved(child_type, src, .field_used);
25855 const field_index = child_type.enumFieldIndex(field_name, zcu) orelse {25850 const field_index = child_type.enumFieldIndex(field_name, zcu) orelse {
25856 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);25851 return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
25857 };25852 };
...@@ -25873,7 +25868,7 @@ fn fieldPtr(...@@ -25873,7 +25868,7 @@ fn fieldPtr(
25873 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)25868 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
25874 else25869 else
25875 object_ptr;25870 object_ptr;
25876 try sema.ensureLayoutResolved(inner_ty, src);25871 try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
25877 const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);25872 const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty);
25878 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);25873 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
25879 return field_ptr;25874 return field_ptr;
...@@ -25883,7 +25878,7 @@ fn fieldPtr(...@@ -25883,7 +25878,7 @@ fn fieldPtr(
25883 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)25878 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
25884 else25879 else
25885 object_ptr;25880 object_ptr;
25886 try sema.ensureLayoutResolved(inner_ty, src);25881 try sema.ensureLayoutResolved(inner_ty, src, .ptr_access);
25887 const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);25882 const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
25888 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);25883 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
25889 return field_ptr;25884 return field_ptr;
...@@ -25927,7 +25922,7 @@ fn fieldCallBind(...@@ -25927,7 +25922,7 @@ fn fieldCallBind(
25927 // Optionally dereference a second pointer to get the concrete type.25922 // Optionally dereference a second pointer to get the concrete type.
25928 const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one;25923 const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one;
25929 const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty;25924 const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty;
25930 try sema.ensureLayoutResolved(concrete_ty, src);25925 try sema.ensureLayoutResolved(concrete_ty, src, .ptr_access);
25931 const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;25926 const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;
25932 const object_ptr = if (is_double_ptr)25927 const object_ptr = if (is_double_ptr)
25933 try sema.analyzeLoad(block, src, raw_ptr, src)25928 try sema.analyzeLoad(block, src, raw_ptr, src)
...@@ -26514,7 +26509,7 @@ fn elemPtr(...@@ -26514,7 +26509,7 @@ fn elemPtr(
26514 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}),26509 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}),
26515 };26510 };
26516 try sema.checkIndexable(block, src, indexable_ty);26511 try sema.checkIndexable(block, src, indexable_ty);
26517 try sema.ensureLayoutResolved(indexable_ty, src);26512 try sema.ensureLayoutResolved(indexable_ty, src, .ptr_access);
2651826513
26519 const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {26514 const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {
26520 .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),26515 .vector => try sema.elemPtrVector(block, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init),
...@@ -26522,7 +26517,7 @@ fn elemPtr(...@@ -26522,7 +26517,7 @@ fn elemPtr(
26522 .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src),26517 .@"struct" => try sema.tupleElemPtr(block, src, indexable_ptr, elem_index, elem_index_src),
26523 else => {26518 else => {
26524 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);26519 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
26525 try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src);26520 try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu), src, .ptr_access);
26526 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);26521 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);
26527 },26522 },
26528 };26523 };
...@@ -26614,7 +26609,7 @@ fn elemVal(...@@ -26614,7 +26609,7 @@ fn elemVal(
26614 switch (indexable_ty.zigTypeTag(zcu)) {26609 switch (indexable_ty.zigTypeTag(zcu)) {
26615 .pointer => {26610 .pointer => {
26616 const child_ty = indexable_ty.childType(zcu);26611 const child_ty = indexable_ty.childType(zcu);
26617 try sema.ensureLayoutResolved(child_ty, src);26612 try sema.ensureLayoutResolved(child_ty, src, .ptr_access);
26618 switch (indexable_ty.ptrSize(zcu)) {26613 switch (indexable_ty.ptrSize(zcu)) {
26619 .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),26614 .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
26620 .many, .c => {26615 .many, .c => {
...@@ -27192,7 +27187,7 @@ fn coerceExtra(...@@ -27192,7 +27187,7 @@ fn coerceExtra(
27192 const target = zcu.getTarget();27187 const target = zcu.getTarget();
2719327188
27194 inst_ty.assertHasLayout(zcu);27189 inst_ty.assertHasLayout(zcu);
27195 try sema.ensureLayoutResolved(dest_ty, inst_src);27190 try sema.ensureLayoutResolved(dest_ty, inst_src, .coerce);
2719627191
27197 // If the types are the same, we can return the operand.27192 // If the types are the same, we can return the operand.
27198 if (dest_ty.eql(inst_ty, zcu))27193 if (dest_ty.eql(inst_ty, zcu))
...@@ -28552,8 +28547,8 @@ fn coerceInMemoryAllowedFns(...@@ -28552,8 +28547,8 @@ fn coerceInMemoryAllowedFns(
28552 } };28547 } };
28553 }28548 }
2855428549
28555 try sema.ensureLayoutResolved(src_ty, src_src);28550 try sema.ensureLayoutResolved(src_ty, src_src, .coerce);
28556 try sema.ensureLayoutResolved(dest_ty, dest_src);28551 try sema.ensureLayoutResolved(dest_ty, dest_src, .coerce);
28557 const src_is_runtime = src_ty.fnHasRuntimeBits(zcu);28552 const src_is_runtime = src_ty.fnHasRuntimeBits(zcu);
28558 const dest_is_runtime = dest_ty.fnHasRuntimeBits(zcu);28553 const dest_is_runtime = dest_ty.fnHasRuntimeBits(zcu);
28559 if (src_is_runtime != dest_is_runtime) return .{ .fn_generic = !dest_is_runtime };28554 if (src_is_runtime != dest_is_runtime) return .{ .fn_generic = !dest_is_runtime };
...@@ -28607,7 +28602,6 @@ fn coerceInMemoryAllowedFns(...@@ -28607,7 +28602,6 @@ fn coerceInMemoryAllowedFns(
28607 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));28602 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));
28608 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));28603 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));
28609 if (src_is_comptime == dest_is_comptime) break :comptime_param;28604 if (src_is_comptime == dest_is_comptime) break :comptime_param;
28610 try sema.ensureLayoutResolved(dest_param_ty, dest_src);
28611 if (!dest_is_mut and src_is_comptime and !dest_is_comptime and dest_param_ty.comptimeOnly(zcu)) {28605 if (!dest_is_mut and src_is_comptime and !dest_is_comptime and dest_param_ty.comptimeOnly(zcu)) {
28612 // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only.28606 // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only.
28613 // The function remains generic, and the parameter is going to be comptime-resolved either way,28607 // The function remains generic, and the parameter is going to be comptime-resolved either way,
...@@ -28835,11 +28829,11 @@ fn coerceInMemoryAllowedPtrs(...@@ -28835,11 +28829,11 @@ fn coerceInMemoryAllowedPtrs(
28835 dest_info.child != src_info.child)28829 dest_info.child != src_info.child)
28836 {28830 {
28837 const src_align = if (src_info.flags.alignment == .none) a: {28831 const src_align = if (src_info.flags.alignment == .none) a: {
28838 try sema.ensureLayoutResolved(src_child, src_src);28832 try sema.ensureLayoutResolved(src_child, src_src, .align_check);
28839 break :a src_child.abiAlignment(zcu);28833 break :a src_child.abiAlignment(zcu);
28840 } else src_info.flags.alignment;28834 } else src_info.flags.alignment;
28841 const dest_align = if (dest_info.flags.alignment == .none) a: {28835 const dest_align = if (dest_info.flags.alignment == .none) a: {
28842 try sema.ensureLayoutResolved(dest_child, dest_src);28836 try sema.ensureLayoutResolved(dest_child, dest_src, .align_check);
28843 break :a dest_child.abiAlignment(zcu);28837 break :a dest_child.abiAlignment(zcu);
28844 } else dest_info.flags.alignment;28838 } else dest_info.flags.alignment;
28845 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {28839 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {
...@@ -29189,7 +29183,7 @@ fn bitCast(...@@ -29189,7 +29183,7 @@ fn bitCast(
29189 const old_ty = sema.typeOf(inst);29183 const old_ty = sema.typeOf(inst);
2919029184
29191 old_ty.assertHasLayout(zcu);29185 old_ty.assertHasLayout(zcu);
29192 try sema.ensureLayoutResolved(dest_ty, inst_src);29186 try sema.ensureLayoutResolved(dest_ty, inst_src, .init);
2919329187
29194 const dest_bits = dest_ty.bitSize(zcu);29188 const dest_bits = dest_ty.bitSize(zcu);
29195 const old_bits = old_ty.bitSize(zcu);29189 const old_bits = old_ty.bitSize(zcu);
...@@ -29837,10 +29831,11 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M...@@ -29837,10 +29831,11 @@ fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.M
29837 try sema.addReferenceEntry(null, src, unit);29831 try sema.addReferenceEntry(null, src, unit);
29838 try sema.declareDependency(.{ .memoized_state = stage });29832 try sema.declareDependency(.{ .memoized_state = stage });
2983929833
29834 const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
29840 if (pt.zcu.analysis_in_progress.contains(unit)) {29835 if (pt.zcu.analysis_in_progress.contains(unit)) {
29841 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(src, "dependency loop detected", .{}));29836 return sema.failWithDependencyLoop(unit, &reason);
29842 }29837 }
29843 try pt.ensureMemoizedStateUpToDate(stage);29838 try pt.ensureMemoizedStateUpToDate(stage, &reason);
29844}29839}
2984529840
29846pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {29841pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
...@@ -29854,11 +29849,6 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:...@@ -29854,11 +29849,6 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:
29854 return;29849 return;
29855 }29850 }
2985629851
29857 try sema.declareDependency(switch (kind) {
29858 .type => .{ .nav_ty = nav_index },
29859 .fully => .{ .nav_val = nav_index },
29860 });
29861
29862 // Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`29852 // Note that even if `nav.status == .resolved`, we must still trigger `ensureNavValUpToDate`
29863 // to make sure the value is up-to-date on incremental updates.29853 // to make sure the value is up-to-date on incremental updates.
2986429854
...@@ -29867,20 +29857,23 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:...@@ -29867,20 +29857,23 @@ pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index:
29867 .fully => .{ .nav_val = nav_index },29857 .fully => .{ .nav_val = nav_index },
29868 });29858 });
29869 try sema.addReferenceEntry(block, src, anal_unit);29859 try sema.addReferenceEntry(block, src, anal_unit);
29860 try sema.declareDependency(switch (kind) {
29861 .type => .{ .nav_ty = nav_index },
29862 .fully => .{ .nav_val = nav_index },
29863 });
29864
29865 const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
2987029866
29871 if (zcu.analysis_in_progress.contains(anal_unit)) {29867 if (zcu.analysis_in_progress.contains(anal_unit)) {
29872 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(.{29868 return sema.failWithDependencyLoop(anal_unit, &reason);
29873 .base_node_inst = nav.analysis.?.zir_index,
29874 .offset = LazySrcLoc.Offset.nodeOffset(.zero),
29875 }, "dependency loop detected", .{}));
29876 }29869 }
2987729870
29878 switch (kind) {29871 switch (kind) {
29879 .type => {29872 .type => {
29880 try zcu.ensureNavValAnalysisQueued(nav_index);29873 try zcu.ensureNavValAnalysisQueued(nav_index);
29881 return pt.ensureNavTypeUpToDate(nav_index);29874 return pt.ensureNavTypeUpToDate(nav_index, &reason);
29882 },29875 },
29883 .fully => return pt.ensureNavValUpToDate(nav_index),29876 .fully => return pt.ensureNavValUpToDate(nav_index, &reason),
29884 }29877 }
29885}29878}
2988629879
...@@ -30065,7 +30058,7 @@ fn analyzeLoad(...@@ -30065,7 +30058,7 @@ fn analyzeLoad(
30065 return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)});30058 return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)});
30066 }30059 }
3006730060
30068 try sema.ensureLayoutResolved(elem_ty, src);30061 try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);
30069 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);30062 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
3007030063
30071 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {30064 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
...@@ -30249,7 +30242,7 @@ fn resolveIsNonErrFromType(...@@ -30249,7 +30242,7 @@ fn resolveIsNonErrFromType(
30249 // This is *our* error set; that is, we're currently analyzing the function30242 // This is *our* error set; that is, we're currently analyzing the function
30250 // which owns it. Trying to resolve it now would cause a dependency loop.30243 // which owns it. Trying to resolve it now would cause a dependency loop.
30251 // Instead, accept that we don't know.30244 // Instead, accept that we don't know.
30252 if (true) return null;30245 return null;
30253 },30246 },
30254 else => |set_ty| switch (ip.indexToKey(set_ty)) {30247 else => |set_ty| switch (ip.indexToKey(set_ty)) {
30255 .error_set_type => |error_set_type| switch (error_set_type.names.len) {30248 .error_set_type => |error_set_type| switch (error_set_type.names.len) {
...@@ -30450,7 +30443,7 @@ fn analyzeSlice(...@@ -30450,7 +30443,7 @@ fn analyzeSlice(
30450 else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}),30443 else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}),
30451 }30444 }
3045230445
30453 try sema.ensureLayoutResolved(elem_ty, src);30446 try sema.ensureLayoutResolved(elem_ty, src, .ptr_access);
3045430447
30455 const ptr = if (slice_ty.isSlice(zcu))30448 const ptr = if (slice_ty.isSlice(zcu))
30456 try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)30449 try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
...@@ -32831,11 +32824,13 @@ fn ensureFuncIesResolved(...@@ -32831,11 +32824,13 @@ fn ensureFuncIesResolved(
32831 try sema.declareDependency(.{ .func_ies = func_index });32824 try sema.declareDependency(.{ .func_ies = func_index });
32832 try sema.addReferenceEntry(block, src, .wrap(.{ .func = func_index }));32825 try sema.addReferenceEntry(block, src, .wrap(.{ .func = func_index }));
3283332826
32827 const reason: Zcu.DependencyReason = .{ .src = src, .type_layout_reason = undefined };
32828
32834 if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) {32829 if (zcu.analysis_in_progress.contains(.wrap(.{ .func = func_index }))) {
32835 return sema.fail(block, src, "unable to resolve inferred error set", .{});32830 return sema.failWithDependencyLoop(.wrap(.{ .func = func_index }), &reason);
32836 }32831 }
3283732832
32838 try pt.ensureFuncBodyUpToDate(func_index);32833 try pt.ensureFuncBodyUpToDate(func_index, &reason);
32839}32834}
3284032835
32841pub fn resolveInferredErrorSetPtr(32836pub fn resolveInferredErrorSetPtr(
...@@ -33749,6 +33744,8 @@ pub fn flushExports(sema: *Sema) !void {...@@ -33749,6 +33744,8 @@ pub fn flushExports(sema: *Sema) !void {
33749 //33744 //
33750 // So, pick up and delete any existing exports. This strategy performs33745 // So, pick up and delete any existing exports. This strategy performs
33751 // redundant work, but that's okay, because this case is exceedingly rare.33746 // redundant work, but that's okay, because this case is exceedingly rare.
33747 //
33748 // MLUGG TODO: is this still possible? if not, delete this logic and combine deleteUnitExports into resetUnit
33752 if (zcu.single_exports.get(sema.owner)) |export_idx| {33749 if (zcu.single_exports.get(sema.owner)) |export_idx| {
33753 try sema.exports.append(gpa, export_idx.ptr(zcu).*);33750 try sema.exports.append(gpa, export_idx.ptr(zcu).*);
33754 } else if (zcu.multi_exports.get(sema.owner)) |info| {33751 } else if (zcu.multi_exports.get(sema.owner)) |info| {
...@@ -33940,7 +33937,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C...@@ -33940,7 +33937,7 @@ pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) C
33940 const val: Value = switch (builtin_decl.kind()) {33937 const val: Value = switch (builtin_decl.kind()) {
33941 .type => val: {33938 .type => val: {
33942 const ty = try sema.analyzeAsType(&block, decl_src, .std_builtin_decl, uncoerced_val);33939 const ty = try sema.analyzeAsType(&block, decl_src, .std_builtin_decl, uncoerced_val);
33943 try sema.ensureLayoutResolved(ty, decl_src);33940 try sema.ensureLayoutResolved(ty, decl_src, .builtin_type);
33944 break :val ty.toValue();33941 break :val ty.toValue();
33945 },33942 },
33946 .func => val: {33943 .func => val: {
...@@ -34370,3 +34367,42 @@ fn zirOpaqueDecl(...@@ -34370,3 +34367,42 @@ fn zirOpaqueDecl(
3437034367
34371 return .fromType(ty);34368 return .fromType(ty);
34372}34369}
34370
34371/// Registers an error indicating a dependency loop: we have introduced a dependency on `want` (with
34372/// reason `want_reason`) but have learnt that `want` is already in `zcu.analysis_in_progress`.
34373pub fn failWithDependencyLoop(
34374 sema: *Sema,
34375 want: AnalUnit,
34376 want_reason: *const Zcu.DependencyReason,
34377) SemaError {
34378 const pt = sema.pt;
34379 const zcu = pt.zcu;
34380 const gpa = zcu.comp.gpa;
34381
34382 const in_progress_len = zcu.analysis_in_progress.count();
34383 var index = zcu.analysis_in_progress.getIndex(want).? + 1;
34384
34385 try zcu.dependency_loops.ensureUnusedCapacity(gpa, 1);
34386 try zcu.dependency_loop_nodes.ensureUnusedCapacity(gpa, in_progress_len - index + 1);
34387
34388 zcu.dependency_loops.putAssumeCapacityNoClobber(want, {});
34389
34390 while (index <= in_progress_len) : (index += 1) {
34391 const parent_unit = zcu.analysis_in_progress.keys()[index - 1];
34392 const unit, const reason = if (index == in_progress_len) .{
34393 want,
34394 want_reason,
34395 } else .{
34396 zcu.analysis_in_progress.keys()[index],
34397 zcu.analysis_in_progress.values()[index],
34398 };
34399
34400 zcu.dependency_loop_nodes.putAssumeCapacityNoClobber(parent_unit, .{
34401 .unit = unit,
34402 .reason = reason.?.*,
34403 });
34404 }
34405
34406 // A dependency loop error will be reported. Mark us all as transitive failures.
34407 return error.AnalysisFail;
34408}
src/Sema/LowerZon.zig+5-5
...@@ -300,7 +300,7 @@ fn checkTypeInner(...@@ -300,7 +300,7 @@ fn checkTypeInner(
300 } else {300 } else {
301 const gop = try visited.getOrPut(sema.arena, ty.toIntern());301 const gop = try visited.getOrPut(sema.arena, ty.toIntern());
302 if (gop.found_existing) return;302 if (gop.found_existing) return;
303 try sema.ensureLayoutResolved(ty, self.import_loc);303 try sema.ensureLayoutResolved(ty, self.import_loc, .init);
304 const struct_info = zcu.typeToStruct(ty).?;304 const struct_info = zcu.typeToStruct(ty).?;
305 for (struct_info.field_types.get(ip)) |field_type| {305 for (struct_info.field_types.get(ip)) |field_type| {
306 try self.checkTypeInner(.fromInterned(field_type), null, visited);306 try self.checkTypeInner(.fromInterned(field_type), null, visited);
...@@ -309,7 +309,7 @@ fn checkTypeInner(...@@ -309,7 +309,7 @@ fn checkTypeInner(
309 .@"union" => {309 .@"union" => {
310 const gop = try visited.getOrPut(sema.arena, ty.toIntern());310 const gop = try visited.getOrPut(sema.arena, ty.toIntern());
311 if (gop.found_existing) return;311 if (gop.found_existing) return;
312 try sema.ensureLayoutResolved(ty, self.import_loc);312 try sema.ensureLayoutResolved(ty, self.import_loc, .init);
313 const union_info = zcu.typeToUnion(ty).?;313 const union_info = zcu.typeToUnion(ty).?;
314 for (union_info.field_types.get(ip)) |field_type| {314 for (union_info.field_types.get(ip)) |field_type| {
315 if (field_type != .void_type) {315 if (field_type != .void_type) {
...@@ -646,7 +646,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I...@@ -646,7 +646,7 @@ fn lowerEnum(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.I
646 const gpa = comp.gpa;646 const gpa = comp.gpa;
647 const io = comp.io;647 const io = comp.io;
648 const ip = &pt.zcu.intern_pool;648 const ip = &pt.zcu.intern_pool;
649 try self.sema.ensureLayoutResolved(res_ty, self.import_loc);649 try self.sema.ensureLayoutResolved(res_ty, self.import_loc, .init);
650 switch (node.get(self.file.zoir.?)) {650 switch (node.get(self.file.zoir.?)) {
651 .enum_literal => |field_name| {651 .enum_literal => |field_name| {
652 const field_name_interned = try ip.getOrPutString(652 const field_name_interned = try ip.getOrPutString(
...@@ -769,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -769,7 +769,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
769 const io = comp.io;769 const io = comp.io;
770 const ip = &pt.zcu.intern_pool;770 const ip = &pt.zcu.intern_pool;
771771
772 try self.sema.ensureLayoutResolved(res_ty, self.import_loc);772 try self.sema.ensureLayoutResolved(res_ty, self.import_loc, .init);
773 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;773 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
774774
775 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {775 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
...@@ -919,7 +919,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -919,7 +919,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
919 const gpa = comp.gpa;919 const gpa = comp.gpa;
920 const io = comp.io;920 const io = comp.io;
921 const ip = &pt.zcu.intern_pool;921 const ip = &pt.zcu.intern_pool;
922 try self.sema.ensureLayoutResolved(res_ty, self.import_loc);922 try self.sema.ensureLayoutResolved(res_ty, self.import_loc, .init);
923 const union_info = pt.zcu.typeToUnion(res_ty).?;923 const union_info = pt.zcu.typeToUnion(res_ty).?;
924 const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type);924 const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type);
925925
src/Sema/type_resolution.zig+70-23
...@@ -14,12 +14,64 @@ const InternPool = @import("../InternPool.zig");...@@ -14,12 +14,64 @@ const InternPool = @import("../InternPool.zig");
14const Alignment = InternPool.Alignment;14const Alignment = InternPool.Alignment;
15const arith = @import("arith.zig");15const arith = @import("arith.zig");
1616
17pub const LayoutResolveReason = enum {
18 variable,
19 constant,
20 parameter,
21 return_type,
22 field,
23 backing_enum,
24 init,
25 coerce,
26 ptr_access,
27 ptr_offset,
28 field_used,
29 field_queried,
30 size_of,
31 align_of,
32 type_info,
33 align_check,
34 bit_ptr_child,
35 builtin_type,
36
37 /// Written after string: "while resolving type 'T' "
38 /// e.g. "while resolving type 'MyStruct' for variable declared here"
39 pub fn msg(r: LayoutResolveReason) []const u8 {
40 return switch (r) {
41 // zig fmt: off
42 .variable => "for variable declared here",
43 .constant => "for constant declared here",
44 .parameter => "for function parameter declared here",
45 .return_type => "for function return type declared here",
46 .field => "for field declared here",
47 .backing_enum => "for backing enum type declared here",
48 .init => "for initialization performed here",
49 .coerce => "for coercion performed here",
50 .ptr_access => "for pointer access here",
51 .ptr_offset => "for pointer offset here",
52 .field_used => "for field usage here",
53 .field_queried => "for field query here",
54 .size_of => "for size query here",
55 .align_of => "for alignment query here",
56 .type_info => "for type information query here",
57 .align_check => "for alignment check here",
58 .bit_ptr_child => "for bit size check here",
59 .builtin_type => "from 'std.builtin'",
60 // zig fmt: on
61 };
62 }
63};
64
17/// Ensures that `ty` has known layout, including alignment, size, and (where relevant) field offsets.65/// Ensures that `ty` has known layout, including alignment, size, and (where relevant) field offsets.
18/// `ty` may be any type; its layout is resolved *recursively* if necessary.66/// `ty` may be any type; its layout is resolved *recursively* if necessary.
19/// Adds incremental dependencies tracking any required type resolution.67/// Adds incremental dependencies tracking any required type resolution.
20/// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific).68pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc, reason: LayoutResolveReason) SemaError!void {
21/// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing69 return ensureLayoutResolvedInner(sema, ty, ty, &.{
22pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!void {70 .src = src,
71 .type_layout_reason = reason,
72 });
73}
74fn ensureLayoutResolvedInner(sema: *Sema, ty: Type, orig_ty: Type, reason: *const Zcu.DependencyReason) SemaError!void {
23 const pt = sema.pt;75 const pt = sema.pt;
24 const zcu = pt.zcu;76 const zcu = pt.zcu;
25 const ip = &zcu.intern_pool;77 const ip = &zcu.intern_pool;
...@@ -35,30 +87,25 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!vo...@@ -35,30 +87,25 @@ pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!vo
3587
36 .func_type => |func_type| {88 .func_type => |func_type| {
37 for (func_type.param_types.get(ip)) |param_ty| {89 for (func_type.param_types.get(ip)) |param_ty| {
38 try ensureLayoutResolved(sema, .fromInterned(param_ty), src);90 try ensureLayoutResolvedInner(sema, .fromInterned(param_ty), orig_ty, reason);
39 }91 }
40 try ensureLayoutResolved(sema, .fromInterned(func_type.return_type), src);92 try ensureLayoutResolvedInner(sema, .fromInterned(func_type.return_type), orig_ty, reason);
41 },93 },
4294
43 .array_type => |arr| return ensureLayoutResolved(sema, .fromInterned(arr.child), src),95 .array_type => |arr| return ensureLayoutResolvedInner(sema, .fromInterned(arr.child), orig_ty, reason),
44 .vector_type => |vec| return ensureLayoutResolved(sema, .fromInterned(vec.child), src),96 .vector_type => |vec| return ensureLayoutResolvedInner(sema, .fromInterned(vec.child), orig_ty, reason),
45 .opt_type => |child| return ensureLayoutResolved(sema, .fromInterned(child), src),97 .opt_type => |child| return ensureLayoutResolvedInner(sema, .fromInterned(child), orig_ty, reason),
46 .error_union_type => |eu| return ensureLayoutResolved(sema, .fromInterned(eu.payload_type), src),98 .error_union_type => |eu| return ensureLayoutResolvedInner(sema, .fromInterned(eu.payload_type), orig_ty, reason),
47 .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {99 .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {
48 try ensureLayoutResolved(sema, .fromInterned(field_ty), src);100 try ensureLayoutResolvedInner(sema, .fromInterned(field_ty), orig_ty, reason);
49 },101 },
50 .struct_type, .union_type, .enum_type => {102 .struct_type, .union_type, .enum_type => {
51 try sema.declareDependency(.{ .type_layout = ty.toIntern() });103 try sema.declareDependency(.{ .type_layout = ty.toIntern() });
52 try sema.addReferenceEntry(null, src, .wrap(.{ .type_layout = ty.toIntern() }));104 try sema.addReferenceEntry(null, reason.src, .wrap(.{ .type_layout = ty.toIntern() }));
53 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {105 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {
54 // TODO: better error message106 return sema.failWithDependencyLoop(.wrap(.{ .type_layout = ty.toIntern() }), reason);
55 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(
56 ty.srcLoc(zcu),
57 "{s} '{f}' depends on itself",
58 .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) },
59 ));
60 }107 }
61 try pt.ensureTypeLayoutUpToDate(ty);108 try pt.ensureTypeLayoutUpToDate(ty, reason);
62 },109 },
63110
64 // values, not types111 // values, not types
...@@ -228,7 +275,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {...@@ -228,7 +275,7 @@ pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
228 const field_ty: Type = .fromInterned(field_ty_ip);275 const field_ty: Type = .fromInterned(field_ty_ip);
229 assert(!field_ty.isGenericPoison());276 assert(!field_ty.isGenericPoison());
230 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });277 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
231 try sema.ensureLayoutResolved(field_ty, field_ty_src);278 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
232279
233 if (field_ty.zigTypeTag(zcu) == .@"opaque") {280 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
234 return sema.failWithOwnedErrorMsg(&block, msg: {281 return sema.failWithOwnedErrorMsg(&block, msg: {
...@@ -387,7 +434,7 @@ fn resolvePackedStructLayout(...@@ -387,7 +434,7 @@ fn resolvePackedStructLayout(
387 const field_ty: Type = .fromInterned(field_ty_ip);434 const field_ty: Type = .fromInterned(field_ty_ip);
388 assert(!field_ty.isGenericPoison());435 assert(!field_ty.isGenericPoison());
389 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });436 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
390 try sema.ensureLayoutResolved(field_ty, field_ty_src);437 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
391 if (field_ty.zigTypeTag(zcu) == .@"opaque") {438 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
392 return sema.failWithOwnedErrorMsg(block, msg: {439 return sema.failWithOwnedErrorMsg(block, msg: {
393 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});440 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
...@@ -557,7 +604,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -557,7 +604,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
557 },604 },
558 };605 };
559606
560 try sema.ensureLayoutResolved(enum_tag_ty, block.src(.container_arg));607 try sema.ensureLayoutResolved(enum_tag_ty, block.src(.container_arg), .backing_enum);
561 const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());608 const enum_obj = ip.loadEnumType(enum_tag_ty.toIntern());
562609
563 if (union_obj.is_reified) {610 if (union_obj.is_reified) {
...@@ -652,7 +699,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {...@@ -652,7 +699,7 @@ pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
652 const field_ty: Type = .fromInterned(field_ty_ip);699 const field_ty: Type = .fromInterned(field_ty_ip);
653 assert(!field_ty.isGenericPoison());700 assert(!field_ty.isGenericPoison());
654 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });701 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
655 try sema.ensureLayoutResolved(field_ty, field_ty_src);702 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
656 if (field_ty.zigTypeTag(zcu) == .@"opaque") {703 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
657 return sema.failWithOwnedErrorMsg(&block, msg: {704 return sema.failWithOwnedErrorMsg(&block, msg: {
658 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});705 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
...@@ -832,7 +879,7 @@ fn resolvePackedUnionLayout(...@@ -832,7 +879,7 @@ fn resolvePackedUnionLayout(
832 const field_ty: Type = .fromInterned(field_ty_ip);879 const field_ty: Type = .fromInterned(field_ty_ip);
833 assert(!field_ty.isGenericPoison());880 assert(!field_ty.isGenericPoison());
834 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });881 const field_ty_src = block.src(.{ .container_field_type = @intCast(field_index) });
835 try sema.ensureLayoutResolved(field_ty, field_ty_src);882 try sema.ensureLayoutResolved(field_ty, field_ty_src, .field);
836 if (field_ty.zigTypeTag(zcu) == .@"opaque") {883 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
837 return sema.failWithOwnedErrorMsg(block, msg: {884 return sema.failWithOwnedErrorMsg(block, msg: {
838 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});885 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
src/Zcu.zig+332-32
...@@ -119,7 +119,7 @@ module_roots: std.AutoArrayHashMapUnmanaged(*Package.Module, File.Index.Optional...@@ -119,7 +119,7 @@ module_roots: std.AutoArrayHashMapUnmanaged(*Package.Module, File.Index.Optional
119///119///
120/// Always accessed through `ImportTableAdapter`, where keys are fully resolved120/// Always accessed through `ImportTableAdapter`, where keys are fully resolved
121/// file paths in order to ensure files are properly deduplicated. This table owns121/// file paths in order to ensure files are properly deduplicated. This table owns
122/// the keys and values.122/// the keysand values.
123///123///
124/// Protected by Compilation's mutex.124/// Protected by Compilation's mutex.
125///125///
...@@ -177,7 +177,9 @@ embed_table: std.ArrayHashMapUnmanaged(...@@ -177,7 +177,9 @@ embed_table: std.ArrayHashMapUnmanaged(
177/// is not yet implemented.177/// is not yet implemented.
178intern_pool: InternPool = .empty,178intern_pool: InternPool = .empty,
179179
180analysis_in_progress: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,180/// Value explains why this `AnalUnit` is being analyzed. It is `null` for the topmost analysis
181/// (index 0), and non-`null` for all others.
182analysis_in_progress: std.AutoArrayHashMapUnmanaged(AnalUnit, ?*const DependencyReason) = .empty,
181/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.183/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
182failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .empty,184failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .empty,
183/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.185/// This `AnalUnit` failed semantic analysis because it required analysis of another `AnalUnit` which itself failed.
...@@ -189,6 +191,19 @@ transitive_failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .emp...@@ -189,6 +191,19 @@ transitive_failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .emp
189/// codegen and linking run on a separate thread.191/// codegen and linking run on a separate thread.
190failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty,192failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty,
191failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty,193failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty,
194
195/// Key is an `AnalUnit` which is in `dependency_loop_nodes`. For each dependency loop, exactly one
196/// unit in the loop is in this map, though the choice is arbitrary and not necessarily reproducible
197/// between compilations. So, instead of (for instance) defining where the dependency loop "starts",
198/// this map simply exists to allow easily iterating all dependency loops exactly once.
199dependency_loops: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .empty,
200/// Key is an `AnalUnit`, value is the `AnalUnit` which the key references and why it does so.
201/// All units in here form loops. To iterate loops, see `dependency_loops`.
202dependency_loop_nodes: std.AutoArrayHashMapUnmanaged(AnalUnit, struct {
203 unit: AnalUnit,
204 reason: DependencyReason,
205}) = .empty,
206
192/// Keep track of `@compileLog`s per `AnalUnit`.207/// Keep track of `@compileLog`s per `AnalUnit`.
193/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.208/// We track the source location of the first `@compileLog` call, and all logged lines as a linked list.
194/// The list is singly linked, but we do track its tail for fast appends (optimizing many logs in one unit).209/// The list is singly linked, but we do track its tail for fast appends (optimizing many logs in one unit).
...@@ -321,6 +336,12 @@ codegen_task_pool: CodegenTaskPool,...@@ -321,6 +336,12 @@ codegen_task_pool: CodegenTaskPool,
321336
322generation: u32 = 0,337generation: u32 = 0,
323338
339pub const DependencyReason = struct {
340 src: LazySrcLoc,
341 /// Only populated if this is for a `.type_layout` unit.
342 type_layout_reason: Sema.type_resolution.LayoutResolveReason,
343};
344
324pub const IncrementalDebugState = struct {345pub const IncrementalDebugState = struct {
325 /// All container types in the ZCU, even dead ones.346 /// All container types in the ZCU, even dead ones.
326 /// Value is the generation the type was created on.347 /// Value is the generation the type was created on.
...@@ -2778,6 +2799,8 @@ pub fn deinit(zcu: *Zcu) void {...@@ -2778,6 +2799,8 @@ pub fn deinit(zcu: *Zcu) void {
2778 zcu.analysis_in_progress.deinit(gpa);2799 zcu.analysis_in_progress.deinit(gpa);
2779 zcu.failed_analysis.deinit(gpa);2800 zcu.failed_analysis.deinit(gpa);
2780 zcu.transitive_failed_analysis.deinit(gpa);2801 zcu.transitive_failed_analysis.deinit(gpa);
2802 zcu.dependency_loops.deinit(gpa);
2803 zcu.dependency_loop_nodes.deinit(gpa);
2781 zcu.failed_codegen.deinit(gpa);2804 zcu.failed_codegen.deinit(gpa);
2782 zcu.failed_types.deinit(gpa);2805 zcu.failed_types.deinit(gpa);
27832806
...@@ -3536,15 +3559,47 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -3536,15 +3559,47 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
3536 }3559 }
3537}3560}
35383561
3539/// Delete all references in `reference_table` which are caused by this `AnalUnit`.3562/// Prepares `unit` for re-analysis by clearing all of the following state:
3563/// * Compile errors associated with `unit`
3564/// * Compile logs associated with `unit`
3565/// * Dependencies from `unit` on other things
3566/// * References from `unit` to other units
3567/// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it
3568/// has. Called in preparation for re-analysis, which will recreate references and dependencies.
3540/// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated.3569/// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated.
3541pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {3570pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void {
3542 const gpa = zcu.gpa;3571 const gpa = zcu.comp.gpa;
3572
3573 // Compile errors
3574 if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| {
3575 kv.value.destroy(gpa);
3576 } else if (zcu.dependency_loop_nodes.swapRemove(unit)) {
3577 _ = zcu.dependency_loops.swapRemove(unit);
3578 _ = zcu.transitive_failed_analysis.swapRemove(unit);
3579 } else {
3580 _ = zcu.transitive_failed_analysis.swapRemove(unit);
3581 }
35433582
3544 zcu.clearCachedResolvedReferences();3583 // Compile logs
3584 if (zcu.compile_logs.fetchSwapRemove(unit)) |kv| {
3585 var opt_line_idx = kv.value.first_line.toOptional();
3586 while (opt_line_idx.unwrap()) |line_idx| {
3587 zcu.free_compile_log_lines.append(gpa, line_idx) catch {
3588 // This space will be reused eventually, so we need not propagate this error.
3589 // Just leak it for now, and let GC reclaim it later on.
3590 break;
3591 };
3592 opt_line_idx = line_idx.get(zcu).next;
3593 }
3594 }
35453595
3596 // Dependencies
3597 zcu.intern_pool.removeDependenciesForDepender(gpa, unit);
3598
3599 // References
3600 zcu.clearCachedResolvedReferences();
3546 unit_refs: {3601 unit_refs: {
3547 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs;3602 const kv = zcu.reference_table.fetchSwapRemove(unit) orelse break :unit_refs;
3548 var idx = kv.value;3603 var idx = kv.value;
35493604
3550 while (idx != std.math.maxInt(u32)) {3605 while (idx != std.math.maxInt(u32)) {
...@@ -3572,9 +3627,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -3572,9 +3627,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
3572 }3627 }
3573 }3628 }
3574 }3629 }
3575
3576 type_refs: {3630 type_refs: {
3577 const kv = zcu.type_reference_table.fetchSwapRemove(anal_unit) orelse break :type_refs;3631 const kv = zcu.type_reference_table.fetchSwapRemove(unit) orelse break :type_refs;
3578 var idx = kv.value;3632 var idx = kv.value;
35793633
3580 while (idx != std.math.maxInt(u32)) {3634 while (idx != std.math.maxInt(u32)) {
...@@ -3588,22 +3642,6 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {...@@ -3588,22 +3642,6 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
3588 }3642 }
3589}3643}
35903644
3591/// Delete all compile logs performed by this `AnalUnit`.
3592/// Re-analysis of the `AnalUnit` will cause logs to be rediscovered.
3593pub fn deleteUnitCompileLogs(zcu: *Zcu, anal_unit: AnalUnit) void {
3594 const kv = zcu.compile_logs.fetchSwapRemove(anal_unit) orelse return;
3595 const gpa = zcu.gpa;
3596 var opt_line_idx = kv.value.first_line.toOptional();
3597 while (opt_line_idx.unwrap()) |line_idx| {
3598 zcu.free_compile_log_lines.append(gpa, line_idx) catch {
3599 // This space will be reused eventually, so we need not propagate this error.
3600 // Just leak it for now, and let GC reclaim it later on.
3601 return;
3602 };
3603 opt_line_idx = line_idx.get(zcu).next;
3604 }
3605}
3606
3607pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index {3645pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index {
3608 const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: {3646 const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: {
3609 _ = try zcu.inline_reference_frames.addOne(zcu.gpa);3647 _ = try zcu.inline_reference_frames.addOne(zcu.gpa);
...@@ -4252,11 +4290,7 @@ pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Alt(FormatDependee...@@ -4252,11 +4290,7 @@ pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Alt(FormatDependee
4252 return .{ .data = .{ .dependee = d, .zcu = zcu } };4290 return .{ .data = .{ .dependee = d, .zcu = zcu } };
4253}4291}
42544292
4255const FormatAnalUnit = struct {4293const FormatAnalUnit = struct { unit: AnalUnit, zcu: *const Zcu };
4256 unit: AnalUnit,
4257 zcu: *Zcu,
4258};
4259
4260fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void {4294fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void {
4261 const zcu = data.zcu;4295 const zcu = data.zcu;
4262 const ip = &zcu.intern_pool;4296 const ip = &zcu.intern_pool;
...@@ -4280,8 +4314,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void...@@ -4280,8 +4314,7 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
4280 }4314 }
4281}4315}
42824316
4283const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *Zcu };4317const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *const Zcu };
4284
4285fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void {4318fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void {
4286 const zcu = data.zcu;4319 const zcu = data.zcu;
4287 const ip = &zcu.intern_pool;4320 const ip = &zcu.intern_pool;
...@@ -4666,6 +4699,273 @@ fn explainWhyFileIsInModule(...@@ -4666,6 +4699,273 @@ fn explainWhyFileIsInModule(
4666 }4699 }
4667}4700}
46684701
4702pub fn addDependencyLoopErrors(zcu: *Zcu, eb: *std.zig.ErrorBundle.Wip) Allocator.Error!void {
4703 const gpa = zcu.comp.gpa;
4704
4705 const all_references = try zcu.resolveReferences();
4706
4707 var units: std.ArrayList(AnalUnit) = .empty;
4708 defer units.deinit(gpa);
4709
4710 // TODO: sort the dependency loops somehow to make the error bundle reproducible
4711 for (zcu.dependency_loops.keys()) |arbitrary_unit| {
4712 units.clearRetainingCapacity();
4713
4714 var cur = arbitrary_unit;
4715 while (true) {
4716 try units.append(gpa, cur);
4717 cur = zcu.dependency_loop_nodes.get(cur).?.unit;
4718 if (cur == arbitrary_unit) break;
4719 }
4720
4721 // `units` now contains all units in the loop. We need to pick a starting point somewhere
4722 // along that loop to begin. We will pick whichever node has the shortest reference trace,
4723 // because the other units may well just be referenced *by* that one! This is also likely
4724 // to match the user's intuition for where the loop "starts".
4725 var start_index: usize = 0;
4726 var start_depth: u32 = depth: {
4727 var depth: u32 = 0;
4728 var opt_ref = all_references.get(units.items[0]) orelse {
4729 // This dependency loop is actually unreferenced, so we don't need to emit a compile
4730 // error at all! Move onto the next dependency loop.
4731 continue;
4732 };
4733 while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1;
4734 break :depth depth;
4735 };
4736 for (units.items[1..], 1..) |unit, index| {
4737 var depth: u32 = 0;
4738 var opt_ref = all_references.get(unit).?;
4739 while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1;
4740 if (depth < start_depth) {
4741 start_index = index;
4742 start_depth = depth;
4743 }
4744 }
4745
4746 // Collect a reference trace for the start of the loop.
4747 var ref_trace: std.ArrayList(std.zig.ErrorBundle.ReferenceTrace) = .empty;
4748 defer ref_trace.deinit(gpa);
4749 const frame_limit = zcu.comp.reference_trace orelse 0;
4750 try zcu.populateReferenceTrace(units.items[start_index], frame_limit, eb, &ref_trace);
4751
4752 // Collect all notes first so we don't leave an incomplete root error message on `error.AlreadyReported`.
4753 const note_buf = try gpa.alloc(std.zig.ErrorBundle.MessageIndex, units.items.len + 1);
4754 defer gpa.free(note_buf);
4755 note_buf[0] = addDependencyLoopNote(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) {
4756 error.AlreadyReported => return, // give up on the dep loop error
4757 error.OutOfMemory => |e| return e,
4758 };
4759 for (units.items[start_index + 1 ..], note_buf[1 .. units.items.len - start_index]) |unit, *note| {
4760 note.* = addDependencyLoopNote(zcu, eb, unit, &.{}) catch |err| switch (err) {
4761 error.AlreadyReported => return, // give up on the dep loop error
4762 error.OutOfMemory => |e| return e,
4763 };
4764 }
4765 for (units.items[0..start_index], note_buf[units.items.len - start_index .. units.items.len]) |unit, *note| {
4766 note.* = addDependencyLoopNote(zcu, eb, unit, &.{}) catch |err| switch (err) {
4767 error.AlreadyReported => return, // give up on the dep loop error
4768 error.OutOfMemory => |e| return e,
4769 };
4770 }
4771 note_buf[units.items.len] = try eb.addErrorMessage(.{
4772 .msg = try eb.addString("eliminate any one of these dependencies to break the loop"),
4773 .src_loc = .none,
4774 });
4775
4776 try eb.addRootErrorMessage(.{
4777 .msg = try eb.printString("dependency loop with length {d}", .{units.items.len}),
4778 .src_loc = .none,
4779 .notes_len = @intCast(units.items.len + 1),
4780 });
4781 const notes_start = try eb.reserveNotes(@intCast(units.items.len + 1));
4782 const notes: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]);
4783 @memcpy(notes, note_buf);
4784 }
4785}
4786fn addDependencyLoopNote(
4787 zcu: *Zcu,
4788 eb: *std.zig.ErrorBundle.Wip,
4789 source_unit: AnalUnit,
4790 ref_trace: []const std.zig.ErrorBundle.ReferenceTrace,
4791) (Allocator.Error || error{AlreadyReported})!std.zig.ErrorBundle.MessageIndex {
4792 const ip = &zcu.intern_pool;
4793 const comp = zcu.comp;
4794
4795 const fmt_source: std.fmt.Alt(FormatAnalUnit, formatDependencyLoopSourceUnit) = .{ .data = .{
4796 .unit = source_unit,
4797 .zcu = zcu,
4798 } };
4799
4800 const dep_node = zcu.dependency_loop_nodes.get(source_unit).?;
4801
4802 const msg: std.zig.ErrorBundle.String = switch (dep_node.unit.unwrap()) {
4803 .@"comptime" => unreachable, // cannot be involved in a dependency loop
4804 .nav_val => |nav| try eb.printString("{f} uses value of declaration '{f}' here", .{
4805 fmt_source, ip.getNav(nav).fqn.fmt(ip),
4806 }),
4807 .nav_ty => |nav| try eb.printString("{f} uses type of declaration '{f}' here", .{
4808 fmt_source, ip.getNav(nav).fqn.fmt(ip),
4809 }),
4810 .memoized_state => |stage| switch (stage) {
4811 .panic => try eb.printString("{f} requires panic handler for call here", .{fmt_source}),
4812 else => try eb.printString("{f} requires 'std.builtin' declarations here", .{fmt_source}),
4813 },
4814 .func => |func| try eb.printString("{f} uses inferred error set of function '{f}' here", .{
4815 fmt_source, ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),
4816 }),
4817 .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{
4818 fmt_source,
4819 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4820 dep_node.reason.type_layout_reason.msg(),
4821 }),
4822 };
4823
4824 const src_loc = dep_node.reason.src.upgrade(zcu);
4825 const source = src_loc.file_scope.getSource(zcu) catch |err| {
4826 try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err);
4827 return error.AlreadyReported;
4828 };
4829 const span = src_loc.span(zcu) catch |err| {
4830 try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err);
4831 return error.AlreadyReported;
4832 };
4833 const loc = std.zig.findLineColumn(source, span.main);
4834 const eb_src = try eb.addSourceLocation(.{
4835 .src_path = try eb.printString("{f}", .{src_loc.file_scope.path.fmt(comp)}),
4836 .span_start = span.start,
4837 .span_main = span.main,
4838 .span_end = span.end,
4839 .line = @intCast(loc.line),
4840 .column = @intCast(loc.column),
4841 .source_line = try eb.addString(loc.source_line),
4842 .reference_trace_len = @intCast(ref_trace.len),
4843 });
4844 for (ref_trace) |rt| try eb.addReferenceTrace(rt);
4845 return eb.addErrorMessage(.{
4846 .msg = msg,
4847 .src_loc = eb_src,
4848 });
4849}
4850fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer.Error!void {
4851 const zcu = data.zcu;
4852 const ip = &zcu.intern_pool;
4853 switch (data.unit.unwrap()) {
4854 .@"comptime" => unreachable, // cannot be involved in a dependency loop
4855 .nav_val => |nav| try w.print("value of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}),
4856 .nav_ty => |nav| try w.print("type of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}),
4857 .memoized_state => |stage| switch (stage) {
4858 .panic => try w.writeAll("panic handler"),
4859 else => try w.writeAll("'std.builtin' declarations"),
4860 },
4861 .type_layout => |ty| try w.print("type '{f}'", .{
4862 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4863 }),
4864 .func => |func| try w.print("function '{f}'", .{
4865 ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip),
4866 }),
4867 }
4868}
4869
4870pub fn populateReferenceTrace(
4871 zcu: *Zcu,
4872 root: AnalUnit,
4873 frame_limit: u32,
4874 eb: *std.zig.ErrorBundle.Wip,
4875 ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace),
4876) Allocator.Error!void {
4877 const ip = &zcu.intern_pool;
4878 const gpa = zcu.comp.gpa;
4879
4880 if (frame_limit == 0) return;
4881
4882 const all_references = try zcu.resolveReferences();
4883
4884 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty;
4885 defer seen.deinit(gpa);
4886
4887 var referenced_by = root;
4888 while (all_references.get(referenced_by)) |maybe_ref| {
4889 const ref = maybe_ref orelse break;
4890 const gop = try seen.getOrPut(gpa, ref.referencer);
4891 if (gop.found_existing) break;
4892 if (ref_trace.items.len < frame_limit) {
4893 var last_call_src = ref.src;
4894 var opt_inline_frame = ref.inline_frame;
4895 while (opt_inline_frame.unwrap()) |inline_frame| {
4896 const f = inline_frame.ptr(zcu).*;
4897 const func_nav = ip.indexToKey(f.callee).func.owner_nav;
4898 const func_name = ip.getNav(func_nav).name.toSlice(ip);
4899 addReferenceTraceFrame(zcu, eb, ref_trace, func_name, last_call_src, true) catch |err| switch (err) {
4900 error.OutOfMemory => |e| return e,
4901 error.AlreadyReported => {
4902 // An incomplete reference trace isn't the end of the world; just cut it off.
4903 return;
4904 },
4905 };
4906 last_call_src = f.call_src;
4907 opt_inline_frame = f.parent;
4908 }
4909 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
4910 .@"comptime" => "comptime",
4911 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
4912 .type_layout => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
4913 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
4914 .memoized_state => null,
4915 };
4916 if (root_name) |n| {
4917 addReferenceTraceFrame(zcu, eb, ref_trace, n, last_call_src, false) catch |err| switch (err) {
4918 error.OutOfMemory => |e| return e,
4919 error.AlreadyReported => {
4920 // An incomplete reference trace isn't the end of the world; just cut it off.
4921 return;
4922 },
4923 };
4924 }
4925 }
4926 referenced_by = ref.referencer;
4927 }
4928
4929 if (seen.count() > ref_trace.items.len) {
4930 try ref_trace.append(gpa, .{
4931 .decl_name = @intCast(seen.count() - ref_trace.items.len),
4932 .src_loc = .none,
4933 });
4934 }
4935}
4936fn addReferenceTraceFrame(
4937 zcu: *Zcu,
4938 eb: *std.zig.ErrorBundle.Wip,
4939 ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace),
4940 name: []const u8,
4941 lazy_src: Zcu.LazySrcLoc,
4942 inlined: bool,
4943) error{ OutOfMemory, AlreadyReported }!void {
4944 const gpa = zcu.gpa;
4945 const src = lazy_src.upgrade(zcu);
4946 const source = src.file_scope.getSource(zcu) catch |err| {
4947 try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err);
4948 return error.AlreadyReported;
4949 };
4950 const span = src.span(zcu) catch |err| {
4951 try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err);
4952 return error.AlreadyReported;
4953 };
4954 const loc = std.zig.findLineColumn(source, span.main);
4955 try ref_trace.append(gpa, .{
4956 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }),
4957 .src_loc = try eb.addSourceLocation(.{
4958 .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}),
4959 .span_start = span.start,
4960 .span_main = span.main,
4961 .span_end = span.end,
4962 .line = @intCast(loc.line),
4963 .column = @intCast(loc.column),
4964 .source_line = 0,
4965 }),
4966 });
4967}
4968
4669const TrackedUnitSema = struct {4969const TrackedUnitSema = struct {
4670 /// `null` means we created the node, so should end it.4970 /// `null` means we created the node, so should end it.
4671 old_name: ?[std.Progress.Node.max_name_len]u8,4971 old_name: ?[std.Progress.Node.max_name_len]u8,
src/Zcu/PerThread.zig+93-131
...@@ -728,7 +728,12 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca...@@ -728,7 +728,12 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca
728/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.728/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.
729/// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore729/// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore
730/// this, since the error is already registered, but it must not use the value of memoized fields.730/// this, since the error is already registered, but it must not use the value of memoized fields.
731pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.SemaError!void {731pub fn ensureMemoizedStateUpToDate(
732 pt: Zcu.PerThread,
733 stage: InternPool.MemoizedStateStage,
734 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
735 reason: ?*const Zcu.DependencyReason,
736) Zcu.SemaError!void {
732 const tracy = trace(@src());737 const tracy = trace(@src());
733 defer tracy.end();738 defer tracy.end();
734739
...@@ -748,12 +753,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized...@@ -748,12 +753,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
748 dev.check(.incremental);753 dev.check(.incremental);
749 _ = zcu.outdated_ready.swapRemove(unit);754 _ = zcu.outdated_ready.swapRemove(unit);
750 // No need for `deleteUnitExports` because we never export anything.755 // No need for `deleteUnitExports` because we never export anything.
751 zcu.deleteUnitReferences(unit);756 zcu.resetUnit(unit);
752 zcu.deleteUnitCompileLogs(unit);
753 if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| {
754 kv.value.destroy(gpa);
755 }
756 _ = zcu.transitive_failed_analysis.swapRemove(unit);
757 } else {757 } else {
758 if (prev_failed) return error.AnalysisFail;758 if (prev_failed) return error.AnalysisFail;
759 // We use an arbitrary element to check if the state has been resolved yet.759 // We use an arbitrary element to check if the state has been resolved yet.
...@@ -772,7 +772,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized...@@ -772,7 +772,7 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
772 info.deps.clearRetainingCapacity();772 info.deps.clearRetainingCapacity();
773 }773 }
774774
775 const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage)) |any_changed|775 const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage, reason)) |any_changed|
776 .{ any_changed or prev_failed, false }776 .{ any_changed or prev_failed, false }
777 else |err| switch (err) {777 else |err| switch (err) {
778 error.AnalysisFail => res: {778 error.AnalysisFail => res: {
...@@ -805,14 +805,18 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized...@@ -805,14 +805,18 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized
805 if (new_failed) return error.AnalysisFail;805 if (new_failed) return error.AnalysisFail;
806}806}
807807
808fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.CompileError!bool {808fn analyzeMemoizedState(
809 pt: Zcu.PerThread,
810 stage: InternPool.MemoizedStateStage,
811 reason: ?*const Zcu.DependencyReason,
812) Zcu.CompileError!bool {
809 const zcu = pt.zcu;813 const zcu = pt.zcu;
810 const comp = zcu.comp;814 const comp = zcu.comp;
811 const gpa = comp.gpa;815 const gpa = comp.gpa;
812816
813 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });817 const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
814818
815 try zcu.analysis_in_progress.putNoClobber(gpa, unit, {});819 try zcu.analysis_in_progress.putNoClobber(gpa, unit, reason);
816 defer assert(zcu.analysis_in_progress.swapRemove(unit));820 defer assert(zcu.analysis_in_progress.swapRemove(unit));
817821
818 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);822 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
...@@ -871,13 +875,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU...@@ -871,13 +875,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU
871 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.875 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
872 if (dev.env.supports(.incremental)) {876 if (dev.env.supports(.incremental)) {
873 zcu.deleteUnitExports(anal_unit);877 zcu.deleteUnitExports(anal_unit);
874 zcu.deleteUnitReferences(anal_unit);878 zcu.resetUnit(anal_unit);
875 zcu.deleteUnitCompileLogs(anal_unit);
876 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
877 kv.value.destroy(gpa);
878 }
879 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
880 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
881 }879 }
882 } else {880 } else {
883 // We can trust the current information about this unit.881 // We can trust the current information about this unit.
...@@ -943,7 +941,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu...@@ -943,7 +941,7 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
943 const file = zcu.fileByIndex(inst_resolved.file);941 const file = zcu.fileByIndex(inst_resolved.file);
944 const zir = file.zir.?;942 const zir = file.zir.?;
945943
946 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});944 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, null);
947 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));945 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
948946
949 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);947 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
...@@ -1009,7 +1007,12 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu...@@ -1009,7 +1007,12 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
1009/// re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or union. Returns1007/// re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or union. Returns
1010/// `error.AnalysisFail` if an analysis error is encountered during type resolution; the caller is1008/// `error.AnalysisFail` if an analysis error is encountered during type resolution; the caller is
1011/// free to ignore this, since the error is already registered.1009/// free to ignore this, since the error is already registered.
1012pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {1010pub fn ensureTypeLayoutUpToDate(
1011 pt: Zcu.PerThread,
1012 ty: Type,
1013 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
1014 reason: ?*const Zcu.DependencyReason,
1015) Zcu.SemaError!void {
1013 const tracy = trace(@src());1016 const tracy = trace(@src());
1014 defer tracy.end();1017 defer tracy.end();
10151018
...@@ -1031,13 +1034,7 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void...@@ -1031,13 +1034,7 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
1031 // `was_outdated` is true in the initial update, so this isn't a `dev.check`.1034 // `was_outdated` is true in the initial update, so this isn't a `dev.check`.
1032 if (dev.env.supports(.incremental)) {1035 if (dev.env.supports(.incremental)) {
1033 zcu.deleteUnitExports(anal_unit);1036 zcu.deleteUnitExports(anal_unit);
1034 zcu.deleteUnitReferences(anal_unit);1037 zcu.resetUnit(anal_unit);
1035 zcu.deleteUnitCompileLogs(anal_unit);
1036 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1037 kv.value.destroy(gpa);
1038 }
1039 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1040 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1041 }1038 }
1042 // For types, we already know that we have to invalidate all dependees.1039 // For types, we already know that we have to invalidate all dependees.
1043 // TODO: we actually *could* detect whether everything was the same. should we bother?1040 // TODO: we actually *could* detect whether everything was the same. should we bother?
...@@ -1058,7 +1055,7 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void...@@ -1058,7 +1055,7 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
1058 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(&zcu.intern_pool).toSlice(&zcu.intern_pool), null);1055 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(&zcu.intern_pool).toSlice(&zcu.intern_pool), null);
1059 defer unit_tracking.end(zcu);1056 defer unit_tracking.end(zcu);
10601057
1061 try zcu.analysis_in_progress.put(gpa, anal_unit, {});1058 try zcu.analysis_in_progress.put(gpa, anal_unit, reason);
1062 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));1059 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
10631060
1064 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);1061 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
...@@ -1114,7 +1111,12 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void...@@ -1114,7 +1111,12 @@ pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void
1114/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis1111/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis
1115/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is1112/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
1116/// free to ignore this, since the error is already registered.1113/// free to ignore this, since the error is already registered.
1117pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {1114pub fn ensureNavValUpToDate(
1115 pt: Zcu.PerThread,
1116 nav_id: InternPool.Nav.Index,
1117 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
1118 reason: ?*const Zcu.DependencyReason,
1119) Zcu.SemaError!void {
1118 const tracy = trace(@src());1120 const tracy = trace(@src());
1119 defer tracy.end();1121 defer tracy.end();
11201122
...@@ -1150,13 +1152,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -1150,13 +1152,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
1150 dev.check(.incremental);1152 dev.check(.incremental);
1151 _ = zcu.outdated_ready.swapRemove(anal_unit);1153 _ = zcu.outdated_ready.swapRemove(anal_unit);
1152 zcu.deleteUnitExports(anal_unit);1154 zcu.deleteUnitExports(anal_unit);
1153 zcu.deleteUnitReferences(anal_unit);1155 zcu.resetUnit(anal_unit);
1154 zcu.deleteUnitCompileLogs(anal_unit);
1155 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1156 kv.value.destroy(gpa);
1157 }
1158 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1159 ip.removeDependenciesForDepender(gpa, anal_unit);
1160 } else {1156 } else {
1161 // We can trust the current information about this unit.1157 // We can trust the current information about this unit.
1162 if (prev_failed) return error.AnalysisFail;1158 if (prev_failed) return error.AnalysisFail;
...@@ -1173,7 +1169,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -1173,7 +1169,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
1173 const unit_tracking = zcu.trackUnitSema(nav.fqn.toSlice(ip), nav.srcInst(ip));1169 const unit_tracking = zcu.trackUnitSema(nav.fqn.toSlice(ip), nav.srcInst(ip));
1174 defer unit_tracking.end(zcu);1170 defer unit_tracking.end(zcu);
11751171
1176 const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id)) |result| res: {1172 const invalidate_value: bool, const new_failed: bool = if (pt.analyzeNavVal(nav_id, reason)) |result| res: {
1177 break :res .{1173 break :res .{
1178 // If the unit has gone from failed to success, we still need to invalidate the dependencies.1174 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
1179 result.val_changed or prev_failed,1175 result.val_changed or prev_failed,
...@@ -1217,39 +1213,14 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu...@@ -1217,39 +1213,14 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu
1217 }1213 }
1218 }1214 }
12191215
1220 // If there isn't a type annotation, then we have also just resolved the type. That means the
1221 // the type is up-to-date, so it won't have the chance to mark its own dependency on the value;
1222 // we must do that ourselves.
1223 type_deps_on_val: {
1224 const inst_resolved = nav.analysis.?.zir_index.resolveFull(ip) orelse break :type_deps_on_val;
1225 const file = zcu.fileByIndex(inst_resolved.file);
1226 const zir_decl = file.zir.?.getDeclaration(inst_resolved.inst);
1227 if (zir_decl.type_body != null) break :type_deps_on_val;
1228 // The type does indeed depend on the value. We are responsible for populating all state of
1229 // the `nav_ty`, including exports, references, errors, and dependencies.
1230 const ty_unit: AnalUnit = .wrap(.{ .nav_ty = nav_id });
1231 const ty_was_outdated = zcu.outdated.swapRemove(ty_unit) or
1232 zcu.potentially_outdated.swapRemove(ty_unit);
1233 if (ty_was_outdated) {
1234 _ = zcu.outdated_ready.swapRemove(ty_unit);
1235 zcu.deleteUnitExports(ty_unit);
1236 zcu.deleteUnitReferences(ty_unit);
1237 zcu.deleteUnitCompileLogs(ty_unit);
1238 if (zcu.failed_analysis.fetchSwapRemove(ty_unit)) |kv| {
1239 kv.value.destroy(gpa);
1240 }
1241 _ = zcu.transitive_failed_analysis.swapRemove(ty_unit);
1242 ip.removeDependenciesForDepender(gpa, ty_unit);
1243 }
1244 try pt.addDependency(ty_unit, .{ .nav_val = nav_id });
1245 if (new_failed) try zcu.transitive_failed_analysis.put(gpa, ty_unit, {});
1246 if (ty_was_outdated) try zcu.markDependeeOutdated(.marked_po, .{ .nav_ty = nav_id });
1247 }
1248
1249 if (new_failed) return error.AnalysisFail;1216 if (new_failed) return error.AnalysisFail;
1250}1217}
12511218
1252fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { val_changed: bool } {1219fn analyzeNavVal(
1220 pt: Zcu.PerThread,
1221 nav_id: InternPool.Nav.Index,
1222 reason: ?*const Zcu.DependencyReason,
1223) Zcu.CompileError!struct { val_changed: bool } {
1253 const zcu = pt.zcu;1224 const zcu = pt.zcu;
1254 const ip = &zcu.intern_pool;1225 const ip = &zcu.intern_pool;
1255 const comp = zcu.comp;1226 const comp = zcu.comp;
...@@ -1266,17 +1237,9 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1266,17 +1237,9 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1266 const zir = file.zir.?;1237 const zir = file.zir.?;
1267 const zir_decl = zir.getDeclaration(inst_resolved.inst);1238 const zir_decl = zir.getDeclaration(inst_resolved.inst);
12681239
1269 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});1240 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
1270 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);1241 errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit);
12711242
1272 // If there's no type body, we are also resolving the type here.
1273 if (zir_decl.type_body == null) {
1274 try zcu.analysis_in_progress.putNoClobber(gpa, .wrap(.{ .nav_ty = nav_id }), {});
1275 }
1276 errdefer if (zir_decl.type_body == null) {
1277 _ = zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id }));
1278 };
1279
1280 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);1243 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1281 defer analysis_arena.deinit();1244 defer analysis_arena.deinit();
12821245
...@@ -1352,9 +1315,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1352,9 +1315,6 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
13521315
1353 const nav_ty: Type = maybe_ty orelse final_val.?.typeOf(zcu);1316 const nav_ty: Type = maybe_ty orelse final_val.?.typeOf(zcu);
13541317
1355 // First, we must resolve the declaration's type. To do this, we analyze the type body if available,
1356 // or otherwise, we analyze the value body, populating `early_val` in the process.
1357
1358 const is_const = is_const: switch (zir_decl.kind) {1318 const is_const = is_const: switch (zir_decl.kind) {
1359 .@"comptime" => unreachable, // this is not a Nav1319 .@"comptime" => unreachable, // this is not a Nav
1360 .unnamed_test, .@"test", .decltest => {1320 .unnamed_test, .@"test", .decltest => {
...@@ -1441,7 +1401,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1441,7 +1401,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
14411401
1442 // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,1402 // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,
1443 // this resolves the type `type` (which needs no resolution), not the struct itself.1403 // this resolves the type `type` (which needs no resolution), not the struct itself.
1444 try sema.ensureLayoutResolved(nav_ty, init_src);1404 try sema.ensureLayoutResolved(nav_ty, block.nodeOffset(.zero), if (zir_decl.kind == .@"var") .variable else .constant);
14451405
1446 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {1406 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
1447 .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen1407 .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
...@@ -1460,18 +1420,18 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1460,18 +1420,18 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1460 }1420 }
1461 } else if (nav_ty.comptimeOnly(zcu)) {1421 } else if (nav_ty.comptimeOnly(zcu)) {
1462 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.1422 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.
1463 const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {1423 const cannot_align_reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {
1464 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*1424 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
1465 else => "comptime-only type",1425 else => "comptime-only type",
1466 };1426 };
1467 if (zir_decl.align_body != null) {1427 if (zir_decl.align_body != null) {
1468 return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{reason});1428 return sema.fail(&block, align_src, "cannot specify alignment of {s}", .{cannot_align_reason});
1469 }1429 }
1470 if (zir_decl.linksection_body != null) {1430 if (zir_decl.linksection_body != null) {
1471 return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{reason});1431 return sema.fail(&block, section_src, "cannot specify linksection of {s}", .{cannot_align_reason});
1472 }1432 }
1473 if (zir_decl.addrspace_body != null) {1433 if (zir_decl.addrspace_body != null) {
1474 return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{reason});1434 return sema.fail(&block, addrspace_src, "cannot specify addrspace of {s}", .{cannot_align_reason});
1475 }1435 }
1476 }1436 }
14771437
...@@ -1484,10 +1444,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1484,10 +1444,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1484 });1444 });
14851445
1486 // Mark the unit as completed before evaluating the export!1446 // Mark the unit as completed before evaluating the export!
1447 // MLUGG TODO: do we really need to do this?
1487 assert(zcu.analysis_in_progress.swapRemove(anal_unit));1448 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1488 if (zir_decl.type_body == null) {
1489 assert(zcu.analysis_in_progress.swapRemove(.wrap(.{ .nav_ty = nav_id })));
1490 }
14911449
1492 if (zir_decl.linkage == .@"export") {1450 if (zir_decl.linkage == .@"export") {
1493 const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });1451 const export_src = block.src(.{ .token_offset = @enumFromInt(@intFromBool(zir_decl.is_pub)) });
...@@ -1516,7 +1474,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1516,7 +1474,12 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1516 }1474 }
1517}1475}
15181476
1519pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void {1477pub fn ensureNavTypeUpToDate(
1478 pt: Zcu.PerThread,
1479 nav_id: InternPool.Nav.Index,
1480 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
1481 reason: ?*const Zcu.DependencyReason,
1482) Zcu.SemaError!void {
1520 const tracy = trace(@src());1483 const tracy = trace(@src());
1521 defer tracy.end();1484 defer tracy.end();
15221485
...@@ -1533,18 +1496,6 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc...@@ -1533,18 +1496,6 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
15331496
1534 try zcu.ensureNavValAnalysisQueued(nav_id);1497 try zcu.ensureNavValAnalysisQueued(nav_id);
15351498
1536 const type_resolved_by_value: bool = from_val: {
1537 const analysis = nav.analysis orelse break :from_val false;
1538 const inst_resolved = analysis.zir_index.resolveFull(ip) orelse break :from_val false;
1539 const file = zcu.fileByIndex(inst_resolved.file);
1540 const zir_decl = file.zir.?.getDeclaration(inst_resolved.inst);
1541 break :from_val zir_decl.type_body == null;
1542 };
1543 if (type_resolved_by_value) {
1544 // Logic at the end of `ensureNavValUpToDate` is directly responsible for populating our state.
1545 return pt.ensureNavValUpToDate(nav_id);
1546 }
1547
1548 // Determine whether or not this `Nav`'s type is outdated. This also includes checking if the1499 // Determine whether or not this `Nav`'s type is outdated. This also includes checking if the
1549 // status is `.unresolved`, which indicates that the value is outdated because it has *never*1500 // status is `.unresolved`, which indicates that the value is outdated because it has *never*
1550 // been analyzed so far.1501 // been analyzed so far.
...@@ -1564,13 +1515,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc...@@ -1564,13 +1515,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
1564 dev.check(.incremental);1515 dev.check(.incremental);
1565 _ = zcu.outdated_ready.swapRemove(anal_unit);1516 _ = zcu.outdated_ready.swapRemove(anal_unit);
1566 zcu.deleteUnitExports(anal_unit);1517 zcu.deleteUnitExports(anal_unit);
1567 zcu.deleteUnitReferences(anal_unit);1518 zcu.resetUnit(anal_unit);
1568 zcu.deleteUnitCompileLogs(anal_unit);
1569 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1570 kv.value.destroy(gpa);
1571 }
1572 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1573 ip.removeDependenciesForDepender(gpa, anal_unit);
1574 } else {1519 } else {
1575 // We can trust the current information about this unit.1520 // We can trust the current information about this unit.
1576 if (prev_failed) return error.AnalysisFail;1521 if (prev_failed) return error.AnalysisFail;
...@@ -1587,7 +1532,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc...@@ -1587,7 +1532,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
1587 const unit_tracking = zcu.trackUnitSema(nav.fqn.toSlice(ip), nav.srcInst(ip));1532 const unit_tracking = zcu.trackUnitSema(nav.fqn.toSlice(ip), nav.srcInst(ip));
1588 defer unit_tracking.end(zcu);1533 defer unit_tracking.end(zcu);
15891534
1590 const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id)) |result| res: {1535 const invalidate_type: bool, const new_failed: bool = if (pt.analyzeNavType(nav_id, reason)) |result| res: {
1591 break :res .{1536 break :res .{
1592 // If the unit has gone from failed to success, we still need to invalidate the dependencies.1537 // If the unit has gone from failed to success, we still need to invalidate the dependencies.
1593 result.type_changed or prev_failed,1538 result.type_changed or prev_failed,
...@@ -1634,7 +1579,11 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc...@@ -1634,7 +1579,11 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc
1634 if (new_failed) return error.AnalysisFail;1579 if (new_failed) return error.AnalysisFail;
1635}1580}
16361581
1637fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { type_changed: bool } {1582fn analyzeNavType(
1583 pt: Zcu.PerThread,
1584 nav_id: InternPool.Nav.Index,
1585 reason: ?*const Zcu.DependencyReason,
1586) Zcu.CompileError!struct { type_changed: bool } {
1638 const zcu = pt.zcu;1587 const zcu = pt.zcu;
1639 const comp = zcu.comp;1588 const comp = zcu.comp;
1640 const gpa = comp.gpa;1589 const gpa = comp.gpa;
...@@ -1650,11 +1599,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1650,11 +1599,10 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1650 const file = zcu.fileByIndex(inst_resolved.file);1599 const file = zcu.fileByIndex(inst_resolved.file);
1651 const zir = file.zir.?;1600 const zir = file.zir.?;
16521601
1653 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});1602 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
1654 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));1603 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
16551604
1656 const zir_decl = zir.getDeclaration(inst_resolved.inst);1605 const zir_decl = zir.getDeclaration(inst_resolved.inst);
1657 const type_body = zir_decl.type_body.?;
16581606
1659 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);1607 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1660 defer analysis_arena.deinit();1608 defer analysis_arena.deinit();
...@@ -1696,6 +1644,17 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1696,6 +1644,17 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1696 defer block.instructions.deinit(gpa);1644 defer block.instructions.deinit(gpa);
16971645
1698 const ty_src = block.src(.{ .node_offset_var_decl_ty = .zero });1646 const ty_src = block.src(.{ .node_offset_var_decl_ty = .zero });
1647 const init_src = block.src(.{ .node_offset_var_decl_init = .zero });
1648
1649 const type_body = zir_decl.type_body orelse {
1650 // There is no type annotation, so we just need to use the declaration's value.
1651 try sema.ensureNavResolved(&block, init_src, nav_id, .fully);
1652 // We don't actually know what the type of this Nav was before it was resolved, so we just
1653 // have to assume we were outdated. This isn't too bad, because assuming there was also no
1654 // type annotation last update, we should only be re-analyzed if the value changes (it's our
1655 // only dependency), or if there was a dependency loop.
1656 return .{ .type_changed = true };
1657 };
16991658
1700 block.comptime_reason = .{ .reason = .{1659 block.comptime_reason = .{ .reason = .{
1701 .src = ty_src,1660 .src = ty_src,
...@@ -1708,7 +1667,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1708,7 +1667,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1708 break :ty .fromInterned(type_ref.toInterned().?);1667 break :ty .fromInterned(type_ref.toInterned().?);
1709 };1668 };
17101669
1711 try sema.ensureLayoutResolved(resolved_ty, ty_src);1670 try sema.ensureLayoutResolved(resolved_ty, block.nodeOffset(.zero), if (zir_decl.kind == .@"var") .variable else .constant);
17121671
1713 // In the case where the type is specified, this function is also responsible for resolving1672 // In the case where the type is specified, this function is also responsible for resolving
1714 // the pointer modifiers, i.e. alignment, linksection, addrspace.1673 // the pointer modifiers, i.e. alignment, linksection, addrspace.
...@@ -1758,7 +1717,12 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1758,7 +1717,12 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1758 return .{ .type_changed = true };1717 return .{ .type_changed = true };
1759}1718}
17601719
1761pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!void {1720pub fn ensureFuncBodyUpToDate(
1721 pt: Zcu.PerThread,
1722 func_index: InternPool.Index,
1723 /// `null` is valid only for the "root" analysis, i.e. called from `Compilation.processOneJob`.
1724 reason: ?*const Zcu.DependencyReason,
1725) Zcu.SemaError!void {
1762 dev.check(.sema);1726 dev.check(.sema);
17631727
1764 const tracy = trace(@src());1728 const tracy = trace(@src());
...@@ -1788,12 +1752,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z...@@ -1788,12 +1752,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
1788 dev.check(.incremental);1752 dev.check(.incremental);
1789 _ = zcu.outdated_ready.swapRemove(anal_unit);1753 _ = zcu.outdated_ready.swapRemove(anal_unit);
1790 zcu.deleteUnitExports(anal_unit);1754 zcu.deleteUnitExports(anal_unit);
1791 zcu.deleteUnitReferences(anal_unit);1755 zcu.resetUnit(anal_unit);
1792 zcu.deleteUnitCompileLogs(anal_unit);
1793 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1794 kv.value.destroy(gpa);
1795 }
1796 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1797 } else {1756 } else {
1798 // We can trust the current information about this function.1757 // We can trust the current information about this function.
1799 if (prev_failed) return error.AnalysisFail;1758 if (prev_failed) return error.AnalysisFail;
...@@ -1813,7 +1772,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z...@@ -1813,7 +1772,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
1813 );1772 );
1814 defer unit_tracking.end(zcu);1773 defer unit_tracking.end(zcu);
18151774
1816 const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index)) |result|1775 const ies_outdated, const new_failed = if (pt.analyzeFuncBody(func_index, reason)) |result|
1817 .{ prev_failed or result.ies_outdated, false }1776 .{ prev_failed or result.ies_outdated, false }
1818 else |err| switch (err) {1777 else |err| switch (err) {
1819 error.AnalysisFail => res: {1778 error.AnalysisFail => res: {
...@@ -1854,6 +1813,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z...@@ -1854,6 +1813,7 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
1854fn analyzeFuncBody(1813fn analyzeFuncBody(
1855 pt: Zcu.PerThread,1814 pt: Zcu.PerThread,
1856 func_index: InternPool.Index,1815 func_index: InternPool.Index,
1816 reason: ?*const Zcu.DependencyReason,
1857) Zcu.SemaError!struct { ies_outdated: bool } {1817) Zcu.SemaError!struct { ies_outdated: bool } {
1858 const zcu = pt.zcu;1818 const zcu = pt.zcu;
1859 const gpa = zcu.gpa;1819 const gpa = zcu.gpa;
...@@ -1868,7 +1828,7 @@ fn analyzeFuncBody(...@@ -1868,7 +1828,7 @@ fn analyzeFuncBody(
18681828
1869 if (func.generic_owner == .none) {1829 if (func.generic_owner == .none) {
1870 // Among another things, this ensures that the function's `zir_body_inst` is correct.1830 // Among another things, this ensures that the function's `zir_body_inst` is correct.
1871 try pt.ensureNavValUpToDate(func.owner_nav);1831 try pt.ensureNavValUpToDate(func.owner_nav, reason);
1872 if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {1832 if (ip.getNav(func.owner_nav).status.fully_resolved.val != func_index) {
1873 // This function is no longer referenced! There's no point in re-analyzing it.1833 // This function is no longer referenced! There's no point in re-analyzing it.
1874 // Just mark a transitive failure and move on.1834 // Just mark a transitive failure and move on.
...@@ -1877,7 +1837,7 @@ fn analyzeFuncBody(...@@ -1877,7 +1837,7 @@ fn analyzeFuncBody(
1877 } else {1837 } else {
1878 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;1838 const go_nav = zcu.funcInfo(func.generic_owner).owner_nav;
1879 // Among another things, this ensures that the function's `zir_body_inst` is correct.1839 // Among another things, this ensures that the function's `zir_body_inst` is correct.
1880 try pt.ensureNavValUpToDate(go_nav);1840 try pt.ensureNavValUpToDate(go_nav, reason);
1881 if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {1841 if (ip.getNav(go_nav).status.fully_resolved.val != func.generic_owner) {
1882 // The generic owner is no longer referenced, so this function is also unreferenced.1842 // The generic owner is no longer referenced, so this function is also unreferenced.
1883 // There's no point in re-analyzing it. Just mark a transitive failure and move on.1843 // There's no point in re-analyzing it. Just mark a transitive failure and move on.
...@@ -1894,7 +1854,7 @@ fn analyzeFuncBody(...@@ -1894,7 +1854,7 @@ fn analyzeFuncBody(
18941854
1895 log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)});1855 log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)});
18961856
1897 var air = try pt.analyzeFuncBodyInner(func_index);1857 var air = try pt.analyzeFuncBodyInner(func_index, reason);
1898 errdefer air.deinit(gpa);1858 errdefer air.deinit(gpa);
18991859
1900 const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or1860 const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or
...@@ -2842,7 +2802,11 @@ const ScanDeclIter = struct {...@@ -2842,7 +2802,11 @@ const ScanDeclIter = struct {
2842 }2802 }
2843};2803};
28442804
2845fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {2805fn analyzeFuncBodyInner(
2806 pt: Zcu.PerThread,
2807 func_index: InternPool.Index,
2808 reason: ?*const Zcu.DependencyReason,
2809) Zcu.SemaError!Air {
2846 const tracy = trace(@src());2810 const tracy = trace(@src());
2847 defer tracy.end();2811 defer tracy.end();
28482812
...@@ -2858,7 +2822,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem...@@ -2858,7 +2822,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
2858 const file = zcu.fileByIndex(inst_info.file);2822 const file = zcu.fileByIndex(inst_info.file);
2859 const zir = file.zir.?;2823 const zir = file.zir.?;
28602824
2861 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, {});2825 try zcu.analysis_in_progress.putNoClobber(gpa, anal_unit, reason);
2862 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));2826 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
28632827
2864 if (func.analysisUnordered(ip).inferred_error_set) {2828 if (func.analysisUnordered(ip).inferred_error_set) {
...@@ -2879,8 +2843,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem...@@ -2879,8 +2843,6 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
28792843
2880 const func_nav = ip.getNav(func.owner_nav);2844 const func_nav = ip.getNav(func.owner_nav);
28812845
2882 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
2883
2884 var analysis_arena = std.heap.ArenaAllocator.init(gpa);2846 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
2885 defer analysis_arena.deinit();2847 defer analysis_arena.deinit();
28862848
...@@ -2978,7 +2940,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem...@@ -2978,7 +2940,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
2978 const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]);2940 const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]);
2979 runtime_param_index += 1;2941 runtime_param_index += 1;
29802942
2981 try sema.ensureLayoutResolved(param_ty, inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) }));2943 try sema.ensureLayoutResolved(param_ty, inner_block.src(.{ .func_decl_param_ty = @intCast(zir_param_index) }), .parameter);
2982 if (try param_ty.onePossibleValue(pt)) |opv| {2944 if (try param_ty.onePossibleValue(pt)) |opv| {
2983 gop.value_ptr.* = .fromValue(opv);2945 gop.value_ptr.* = .fromValue(opv);
2984 continue;2946 continue;
...@@ -2995,7 +2957,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem...@@ -2995,7 +2957,7 @@ fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.Sem
2995 });2957 });
2996 }2958 }
29972959
2998 try sema.ensureLayoutResolved(sema.fn_ret_ty, inner_block.src(.{ .node_offset_fn_type_ret_ty = .zero }));2960 try sema.ensureLayoutResolved(sema.fn_ret_ty, inner_block.src(.{ .node_offset_fn_type_ret_ty = .zero }), .return_type);
29992961
3000 const last_arg_index = inner_block.instructions.items.len;2962 const last_arg_index = inner_block.instructions.items.len;
30012963
...@@ -4206,7 +4168,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {...@@ -4206,7 +4168,7 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
4206 },4168 },
42074169
4208 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {4170 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
4209 .struct_type => try pt.ensureTypeLayoutUpToDate(ty),4171 .struct_type => try pt.ensureTypeLayoutUpToDate(ty, null),
4210 .tuple_type => |tuple| for (0..tuple.types.len) |i| {4172 .tuple_type => |tuple| for (0..tuple.types.len) |i| {
4211 const field_is_comptime = tuple.values.get(ip)[i] != .none;4173 const field_is_comptime = tuple.values.get(ip)[i] != .none;
4212 if (field_is_comptime) continue;4174 if (field_is_comptime) continue;
...@@ -4216,8 +4178,8 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {...@@ -4216,8 +4178,8 @@ pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
4216 else => unreachable,4178 else => unreachable,
4217 },4179 },
42184180
4219 .@"union" => try pt.ensureTypeLayoutUpToDate(ty),4181 .@"union" => try pt.ensureTypeLayoutUpToDate(ty, null),
4220 .@"enum" => try pt.ensureTypeLayoutUpToDate(ty),4182 .@"enum" => try pt.ensureTypeLayoutUpToDate(ty, null),
4221 }4183 }
4222}4184}
4223pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {4185pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {
test/incremental/type_dependency_loop created+55
...@@ -0,0 +1,55 @@
1#target=x86_64-linux-selfhosted
2#target=x86_64-windows-selfhosted
3#target=x86_64-linux-cbe
4#target=x86_64-windows-cbe
5#target=wasm32-wasi-selfhosted
6#update=initial version
7#file=main.zig
8pub const A = struct { b: B };
9pub const B = struct { a: A };
10pub fn main() void {
11 _ = @as(B, undefined);
12}
13#expect_error=:error: dependency loop with length 2
14#expect_error=main.zig:2:27: note: type 'main.B' depends on type 'main.A' for field declared here
15#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here
16#expect_error=:note: eliminate any one of these dependencies to break the loop
17
18#update=remove reference to dependency loop
19#file=main.zig
20pub const A = struct { b: B };
21pub const B = struct { a: A };
22pub fn main() void {
23 _ = B;
24}
25#expect_stdout=""
26
27#update=change dependency loop without fixing it
28#file=main.zig
29pub const A = struct { b: B };
30pub const B = struct { a: *align(@alignOf(A)) A };
31pub fn main() void {
32 _ = B;
33}
34#expect_stdout=""
35
36#update=reference dependency loop again
37#file=main.zig
38pub const A = struct { b: B };
39pub const B = struct { a: *align(@alignOf(A)) A };
40pub fn main() void {
41 _ = @as(B, undefined);
42}
43#expect_error=:error: dependency loop with length 2
44#expect_error=main.zig:2:43: note: type 'main.B' depends on type 'main.A' for alignment query here
45#expect_error=main.zig:1:27: note: type 'main.A' depends on type 'main.B' for field declared here
46#expect_error=:note: eliminate any one of these dependencies to break the loop
47
48#update=fix dependency loop
49#file=main.zig
50pub const A = struct { b: B };
51pub const B = struct { a: *A };
52pub fn main() void {
53 _ = @as(B, undefined);
54}
55#expect_stdout=""
tools/incr-check.zig+41-35
...@@ -417,29 +417,32 @@ const Eval = struct {...@@ -417,29 +417,32 @@ const Eval = struct {
417 is_note: bool,417 is_note: bool,
418 err_idx: std.zig.ErrorBundle.MessageIndex,418 err_idx: std.zig.ErrorBundle.MessageIndex,
419 ) Allocator.Error!void {419 ) Allocator.Error!void {
420 const io = eval.io;
420 const err = eb.getErrorMessage(err_idx);421 const err = eb.getErrorMessage(err_idx);
421 if (err.src_loc == .none) @panic("TODO error message with no source location");
422 if (err.count != 1) @panic("TODO error message with count>1");422 if (err.count != 1) @panic("TODO error message with count>1");
423 const msg = eb.nullTerminatedString(err.msg);423 const msg = eb.nullTerminatedString(err.msg);
424 const src = eb.getSourceLocation(err.src_loc);424 const matches = matches: {
425 const raw_filename = eb.nullTerminatedString(src.src_path);425 if (expected.is_note != is_note) break :matches false;
426426 if (!std.mem.eql(u8, expected.msg, msg)) break :matches false;
427 const io = eval.io;427 if (err.src_loc == .none) {
428428 break :matches expected.src == null;
429 // We need to replace backslashes for consistency between platforms.429 }
430 const filename = name: {430 const expected_src = expected.src orelse break :matches false;
431 if (std.mem.indexOfScalar(u8, raw_filename, '\\') == null) break :name raw_filename;431 const src = eb.getSourceLocation(err.src_loc);
432 const copied = try eval.arena.dupe(u8, raw_filename);432 const raw_filename = eb.nullTerminatedString(src.src_path);
433 std.mem.replaceScalar(u8, copied, '\\', '/');433 // We need to replace backslashes for consistency between platforms.
434 break :name copied;434 const filename = name: {
435 if (std.mem.indexOfScalar(u8, raw_filename, '\\') == null) break :name raw_filename;
436 const copied = try eval.arena.dupe(u8, raw_filename);
437 std.mem.replaceScalar(u8, copied, '\\', '/');
438 break :name copied;
439 };
440 if (!std.mem.eql(u8, expected_src.filename, filename)) break :matches false;
441 if (expected_src.line != src.line + 1) break :matches false;
442 if (expected_src.column != src.column + 1) break :matches false;
443 break :matches true;
435 };444 };
436445 if (!matches) {
437 if (expected.is_note != is_note or
438 !std.mem.eql(u8, expected.filename, filename) or
439 expected.line != src.line + 1 or
440 expected.column != src.column + 1 or
441 !std.mem.eql(u8, expected.msg, msg))
442 {
443 eb.renderToStderr(io, .{}, .auto) catch {};446 eb.renderToStderr(io, .{}, .auto) catch {};
444 eval.fatal("compile error did not match expected error", .{});447 eval.fatal("compile error did not match expected error", .{});
445 }448 }
...@@ -714,10 +717,12 @@ const Case = struct {...@@ -714,10 +717,12 @@ const Case = struct {
714717
715 const ExpectedError = struct {718 const ExpectedError = struct {
716 is_note: bool,719 is_note: bool,
717 filename: []const u8,
718 line: u32,
719 column: u32,
720 msg: []const u8,720 msg: []const u8,
721 src: ?struct {
722 filename: []const u8,
723 line: u32,
724 column: u32,
725 },
721 };726 };
722727
723 fn parse(arena: Allocator, io: Io, bytes: []const u8) !Case {728 fn parse(arena: Allocator, io: Io, bytes: []const u8) !Case {
...@@ -930,16 +935,16 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {...@@ -930,16 +935,16 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {
930935
931 var it = std.mem.splitScalar(u8, str, ':');936 var it = std.mem.splitScalar(u8, str, ':');
932 const filename = it.first();937 const filename = it.first();
933 const line_str = it.next() orelse fatal("line {d}: incomplete error specification", .{l});938 const line_str, const column_str = if (filename.len > 0) .{
934 const column_str = it.next() orelse fatal("line {d}: incomplete error specification", .{l});939 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
940 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
941 } else .{ undefined, undefined };
935 const error_or_note_str = std.mem.trim(942 const error_or_note_str = std.mem.trim(
936 u8,943 u8,
937 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),944 it.next() orelse fatal("line {d}: incomplete error specification", .{l}),
938 " ",945 " ",
939 );946 );
940 const message = std.mem.trim(u8, it.rest(), " ");947
941 if (filename.len == 0) fatal("line {d}: empty filename", .{l});
942 if (message.len == 0) fatal("line {d}: empty error message", .{l});
943 const is_note = if (std.mem.eql(u8, error_or_note_str, "error"))948 const is_note = if (std.mem.eql(u8, error_or_note_str, "error"))
944 false949 false
945 else if (std.mem.eql(u8, error_or_note_str, "note"))950 else if (std.mem.eql(u8, error_or_note_str, "note"))
...@@ -947,18 +952,19 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {...@@ -947,18 +952,19 @@ fn parseExpectedError(str: []const u8, l: usize) Case.ExpectedError {
947 else952 else
948 fatal("line {d}: expeted 'error' or 'note', found '{s}'", .{ l, error_or_note_str });953 fatal("line {d}: expeted 'error' or 'note', found '{s}'", .{ l, error_or_note_str });
949954
950 const line = std.fmt.parseInt(u32, line_str, 10) catch955 const message = std.mem.trim(u8, it.rest(), " ");
951 fatal("line {d}: invalid line number '{s}'", .{ l, line_str });956 if (message.len == 0) fatal("line {d}: empty error message", .{l});
952
953 const column = std.fmt.parseInt(u32, column_str, 10) catch
954 fatal("line {d}: invalid column number '{s}'", .{ l, column_str });
955957
956 return .{958 return .{
957 .is_note = is_note,959 .is_note = is_note,
958 .filename = filename,
959 .line = line,
960 .column = column,
961 .msg = message,960 .msg = message,
961 .src = if (filename.len == 0) null else .{
962 .filename = filename,
963 .line = std.fmt.parseInt(u32, line_str, 10) catch
964 fatal("line {d}: invalid line number '{s}'", .{ l, line_str }),
965 .column = std.fmt.parseInt(u32, column_str, 10) catch
966 fatal("line {d}: invalid column number '{s}'", .{ l, column_str }),
967 },
962 };968 };
963}969}
964970