| author | |
| committer | |
| log | 1826ba69d81e182f6bd7cf4ea9b944bd6c713a28 |
| tree | 0e57f2a535deaf0ffbc01aa66948971dc594802c |
| parent | a9bfc94ee65f1dafe5c67bb8fbd58cd2372cfd28 |
| signature |
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 width | 254 | // 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 caret | 256 | // -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); |
| 4443 | 4443 | ||
| 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 | }; |
| 4450 | 4449 | 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 | } |
| 4505 | 4451 | ||
| 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); |
| 4566 | 4512 | ||
| 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 | } |
| 4571 | 4517 | ||
| 4572 | fn 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 | |||
| 4605 | fn addWholeFileError( | 4518 | fn 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 |
| 5243 | 5156 | ||
| 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; |
| 3261 | 3261 | ||
| 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 | } |
| 3330 | 3330 | ||
| ... | @@ -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); |
| 3759 | 3759 | ||
| 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); |
| 3791 | 3791 | ||
| 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 | } |
| 4154 | 4154 | ||
| ... | @@ -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 | } |
| 4652 | 4652 | ||
| 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); |
| 4655 | 4655 | ||
| 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( |
| 7037 | 7037 | ||
| 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); |
| 7041 | 7041 | ||
| 7042 | // If we've discovered after evaluating arguments that a generic function instantiation is | 7042 | // 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 | }; |
| 7170 | 7169 | ||
| 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); |
| 7182 | 7181 | ||
| 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 | } |
| 7186 | 7187 | ||
| 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 | } |
| 7210 | 7197 | ||
| 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 | } |
| 7218 | 7222 | ||
| ... | @@ -7279,11 +7283,6 @@ fn analyzeCall( | ... | @@ -7279,11 +7283,6 @@ fn analyzeCall( |
| 7279 | } | 7283 | } |
| 7280 | } | 7284 | } |
| 7281 | 7285 | ||
| 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 }); |
| 7289 | 7288 | ||
| ... | @@ -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); |
| 8056 | 8055 | ||
| 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( |
| 8114 | 8113 | ||
| 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); |
| 8118 | 8117 | ||
| 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( |
| 8311 | 8310 | ||
| 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); |
| 8315 | 8314 | ||
| 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; |
| 9022 | 9021 | ||
| 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 }); |
| 9026 | 9024 | ||
| ... | @@ -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 | } |
| 9096 | 9094 | ||
| ... | @@ -9105,7 +9103,7 @@ fn funcCommon( | ... | @@ -9105,7 +9103,7 @@ fn funcCommon( |
| 9105 | }); | 9103 | }); |
| 9106 | 9104 | ||
| 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 | } |
| 9767 | 9765 | ||
| ... | @@ -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); | ||
| 9986 | 9985 | ||
| 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); | ||
| 11289 | 11289 | ||
| 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; |
| 12849 | 12849 | ||
| 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 | } |
| 15196 | 15196 | ||
| 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 | }; |
| 15248 | 15249 | ||
| 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 | } |
| 15940 | 15941 | ||
| ... | @@ -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).?; |
| 16187 | 16188 | ||
| 16188 | try sema.ensureLayoutResolved(ty, src); | 16189 | try sema.ensureLayoutResolved(ty, src, .type_info); |
| 16189 | 16190 | ||
| 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 | }); |
| 16351 | 16352 | ||
| ... | @@ -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; |
| 18304 | 18305 | ||
| 18305 | try sema.ensureLayoutResolved(obj_ty, ty_src); | 18306 | try sema.ensureLayoutResolved(obj_ty, ty_src, .init); |
| 18306 | 18307 | ||
| 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; |
| 18369 | 18370 | ||
| 18370 | try sema.ensureLayoutResolved(init_ty, src); | 18371 | try sema.ensureLayoutResolved(init_ty, src, .init); |
| 18371 | 18372 | ||
| 18372 | const obj_ty = init_ty.optEuBaseType(zcu); | 18373 | const obj_ty = init_ty.optEuBaseType(zcu); |
| 18373 | 18374 | ||
| ... | @@ -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); |
| 18491 | 18492 | ||
| 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); |
| 18955 | 18956 | ||
| 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 | } |
| 19276 | 19277 | ||
| ... | @@ -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 | } |
| 19296 | 19297 | ||
| ... | @@ -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 }); |
| 19875 | 19876 | ||
| 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); | ||
| 19878 | 19878 | ||
| 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! |
| 20811 | 20807 | ||
| 20812 | const elem_ty = ptr_ty.nullablePtrElem(zcu); | 20808 | const elem_ty = ptr_ty.nullablePtrElem(zcu); |
| 20813 | 20809 | ||
| 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); |
| 20817 | 20812 | ||
| 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); |
| 21157 | 21152 | ||
| 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); |
| 21160 | 21155 | ||
| 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 }); |
| 21929 | 21924 | ||
| 21930 | try sema.ensureLayoutResolved(ty, ty_src); | 21925 | try sema.ensureLayoutResolved(ty, ty_src, .field_queried); |
| 21931 | 21926 | ||
| 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 }); |
| 23012 | 23007 | ||
| 23013 | try sema.ensureLayoutResolved(elem_ty, elem_ty_src); | 23008 | try sema.ensureLayoutResolved(elem_ty, elem_ty_src, .ptr_access); |
| 23014 | 23009 | ||
| 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); |
| 23940 | 23935 | ||
| 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); |
| 23943 | 23938 | ||
| 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) orelse | 25618 | 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 that | 25642 | // 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 that | 25650 | // 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 | else | 25869 | 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 | else | 25879 | 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); |
| 26518 | 26513 | ||
| 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(); |
| 27193 | 27188 | ||
| 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); |
| 27196 | 27191 | ||
| 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 | } |
| 28554 | 28549 | ||
| 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); |
| 29190 | 29184 | ||
| 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); |
| 29193 | 29187 | ||
| 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 }); |
| 29839 | 29833 | ||
| 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 | } |
| 29845 | 29840 | ||
| 29846 | pub fn ensureNavResolved(sema: *Sema, block: *Block, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void { | 29841 | pub 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 | } |
| 29856 | 29851 | ||
| 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. |
| 29864 | 29854 | ||
| ... | @@ -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 }; | ||
| 29870 | 29866 | ||
| 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 | } |
| 29877 | 29870 | ||
| 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 | } |
| 29886 | 29879 | ||
| ... | @@ -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 | } |
| 30067 | 30060 | ||
| 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); |
| 30070 | 30063 | ||
| 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 function | 30242 | // 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 | } |
| 30452 | 30445 | ||
| 30453 | try sema.ensureLayoutResolved(elem_ty, src); | 30446 | try sema.ensureLayoutResolved(elem_ty, src, .ptr_access); |
| 30454 | 30447 | ||
| 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 })); |
| 32833 | 32826 | ||
| 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 | } |
| 32837 | 32832 | ||
| 32838 | try pt.ensureFuncBodyUpToDate(func_index); | 32833 | try pt.ensureFuncBodyUpToDate(func_index, &reason); |
| 32839 | } | 32834 | } |
| 32840 | 32835 | ||
| 32841 | pub fn resolveInferredErrorSetPtr( | 32836 | pub 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 performs | 33745 | // 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( |
| 34370 | 34367 | ||
| 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`. | ||
| 34373 | pub 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; |
| 771 | 771 | ||
| 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).?; |
| 774 | 774 | ||
| 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); |
| 925 | 925 |
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"); |
| 14 | const Alignment = InternPool.Alignment; | 14 | const Alignment = InternPool.Alignment; |
| 15 | const arith = @import("arith.zig"); | 15 | const arith = @import("arith.zig"); |
| 16 | 16 | ||
| 17 | pub 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). | 68 | pub 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 PRing | 69 | return ensureLayoutResolvedInner(sema, ty, ty, &.{ |
| 22 | pub fn ensureLayoutResolved(sema: *Sema, ty: Type, src: LazySrcLoc) SemaError!void { | 70 | .src = src, |
| 71 | .type_layout_reason = reason, | ||
| 72 | }); | ||
| 73 | } | ||
| 74 | fn 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 |
| 35 | 87 | ||
| 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 | }, |
| 42 | 94 | ||
| 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 message | 106 | 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 | }, |
| 63 | 110 | ||
| 64 | // values, not types | 111 | // 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); |
| 232 | 279 | ||
| 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 | }; |
| 559 | 606 | ||
| 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()); |
| 562 | 609 | ||
| 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 resolved | 120 | /// Always accessed through `ImportTableAdapter`, where keys are fully resolved |
| 121 | /// file paths in order to ensure files are properly deduplicated. This table owns | 121 | /// 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. |
| 178 | intern_pool: InternPool = .empty, | 178 | intern_pool: InternPool = .empty, |
| 179 | 179 | ||
| 180 | analysis_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. | ||
| 182 | analysis_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. |
| 182 | failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .empty, | 184 | failed_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. |
| 190 | failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty, | 192 | failed_codegen: std.AutoArrayHashMapUnmanaged(InternPool.Nav.Index, *ErrorMsg) = .empty, |
| 191 | failed_types: std.AutoArrayHashMapUnmanaged(InternPool.Index, *ErrorMsg) = .empty, | 193 | failed_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. | ||
| 199 | dependency_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`. | ||
| 202 | dependency_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, |
| 321 | 336 | ||
| 322 | generation: u32 = 0, | 337 | generation: u32 = 0, |
| 323 | 338 | ||
| 339 | pub 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 | |||
| 324 | pub const IncrementalDebugState = struct { | 345 | pub 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); |
| 2783 | 2806 | ||
| ... | @@ -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 | } |
| 3538 | 3561 | ||
| 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. |
| 3541 | pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { | 3570 | pub 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 | } | ||
| 3543 | 3582 | ||
| 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 | } | ||
| 3545 | 3595 | ||
| 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; |
| 3549 | 3604 | ||
| 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; |
| 3579 | 3633 | ||
| 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 | } |
| 3590 | 3644 | ||
| 3591 | /// Delete all compile logs performed by this `AnalUnit`. | ||
| 3592 | /// Re-analysis of the `AnalUnit` will cause logs to be rediscovered. | ||
| 3593 | pub 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 | |||
| 3607 | pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index { | 3645 | pub 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 | } |
| 4254 | 4292 | ||
| 4255 | const FormatAnalUnit = struct { | 4293 | const FormatAnalUnit = struct { unit: AnalUnit, zcu: *const Zcu }; |
| 4256 | unit: AnalUnit, | ||
| 4257 | zcu: *Zcu, | ||
| 4258 | }; | ||
| 4259 | |||
| 4260 | fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void { | 4294 | fn 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 | } |
| 4282 | 4316 | ||
| 4283 | const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *Zcu }; | 4317 | const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *const Zcu }; |
| 4284 | |||
| 4285 | fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void { | 4318 | fn 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 | } |
| 4668 | 4701 | ||
| 4702 | pub 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 | } | ||
| 4786 | fn 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 | } | ||
| 4850 | fn 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 | |||
| 4870 | pub 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 | } | ||
| 4936 | fn 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 | |||
| 4669 | const TrackedUnitSema = struct { | 4969 | const 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 ignore | 729 | /// 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. |
| 731 | pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.SemaError!void { | 731 | pub 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(); |
| 734 | 739 | ||
| ... | @@ -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 | } |
| 774 | 774 | ||
| 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 | } |
| 807 | 807 | ||
| 808 | fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.CompileError!bool { | 808 | fn 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; |
| 812 | 816 | ||
| 813 | const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); | 817 | const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); |
| 814 | 818 | ||
| 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)); |
| 817 | 821 | ||
| 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.?; |
| 945 | 943 | ||
| 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)); |
| 948 | 946 | ||
| 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. Returns | 1007 | /// 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 is | 1008 | /// `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. |
| 1012 | pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void { | 1010 | pub 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(); |
| 1015 | 1018 | ||
| ... | @@ -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); |
| 1060 | 1057 | ||
| 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)); |
| 1063 | 1060 | ||
| 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-analysis | 1111 | /// 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 is | 1112 | /// 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. |
| 1117 | pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void { | 1114 | pub 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(); |
| 1120 | 1122 | ||
| ... | @@ -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); |
| 1175 | 1171 | ||
| 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 | } |
| 1219 | 1215 | ||
| 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 | } |
| 1251 | 1218 | ||
| 1252 | fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { val_changed: bool } { | 1219 | fn 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); |
| 1268 | 1239 | ||
| 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); |
| 1271 | 1242 | ||
| 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(); |
| 1282 | 1245 | ||
| ... | @@ -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 |
| 1352 | 1315 | ||
| 1353 | const nav_ty: Type = maybe_ty orelse final_val.?.typeOf(zcu); | 1316 | const nav_ty: Type = maybe_ty orelse final_val.?.typeOf(zcu); |
| 1354 | 1317 | ||
| 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 Nav | 1319 | .@"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 |
| 1441 | 1401 | ||
| 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); |
| 1445 | 1405 | ||
| 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 codegen | 1407 | .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 | } |
| 1477 | 1437 | ||
| ... | @@ -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 | }); |
| 1485 | 1445 | ||
| 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 | } | ||
| 1491 | 1449 | ||
| 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 | } |
| 1518 | 1476 | ||
| 1519 | pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.SemaError!void { | 1477 | pub 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(); |
| 1522 | 1485 | ||
| ... | @@ -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 |
| 1533 | 1496 | ||
| 1534 | try zcu.ensureNavValAnalysisQueued(nav_id); | 1497 | try zcu.ensureNavValAnalysisQueued(nav_id); |
| 1535 | 1498 | ||
| 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 the | 1499 | // 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); |
| 1589 | 1534 | ||
| 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 | } |
| 1636 | 1581 | ||
| 1637 | fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileError!struct { type_changed: bool } { | 1582 | fn 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.?; |
| 1652 | 1601 | ||
| 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)); |
| 1655 | 1604 | ||
| 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.?; | ||
| 1658 | 1606 | ||
| 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); |
| 1697 | 1645 | ||
| 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 | }; | ||
| 1699 | 1658 | ||
| 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 | }; |
| 1710 | 1669 | ||
| 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); |
| 1712 | 1671 | ||
| 1713 | // In the case where the type is specified, this function is also responsible for resolving | 1672 | // 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 | } |
| 1760 | 1719 | ||
| 1761 | pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!void { | 1720 | pub 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); |
| 1763 | 1727 | ||
| 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); |
| 1815 | 1774 | ||
| 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 |
| 1854 | fn analyzeFuncBody( | 1813 | fn 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( |
| 1868 | 1828 | ||
| 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( |
| 1894 | 1854 | ||
| 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)}); |
| 1896 | 1856 | ||
| 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); |
| 1899 | 1859 | ||
| 1900 | const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or | 1860 | 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 | }; |
| 2844 | 2804 | ||
| 2845 | fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air { | 2805 | fn 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(); |
| 2848 | 2812 | ||
| ... | @@ -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.?; |
| 2860 | 2824 | ||
| 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)); |
| 2863 | 2827 | ||
| 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 |
| 2879 | 2843 | ||
| 2880 | const func_nav = ip.getNav(func.owner_nav); | 2844 | const func_nav = ip.getNav(func.owner_nav); |
| 2881 | 2845 | ||
| 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(); |
| 2886 | 2848 | ||
| ... | @@ -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; |
| 2980 | 2942 | ||
| 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 | } |
| 2997 | 2959 | ||
| 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); |
| 2999 | 2961 | ||
| 3000 | const last_arg_index = inner_block.instructions.items.len; | 2962 | const last_arg_index = inner_block.instructions.items.len; |
| 3001 | 2963 | ||
| ... | @@ -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 | }, |
| 4207 | 4169 | ||
| 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 | }, |
| 4218 | 4180 | ||
| 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 | } |
| 4223 | pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void { | 4185 | pub 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 | ||
| 8 | pub const A = struct { b: B }; | ||
| 9 | pub const B = struct { a: A }; | ||
| 10 | pub 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 | ||
| 20 | pub const A = struct { b: B }; | ||
| 21 | pub const B = struct { a: A }; | ||
| 22 | pub fn main() void { | ||
| 23 | _ = B; | ||
| 24 | } | ||
| 25 | #expect_stdout="" | ||
| 26 | |||
| 27 | #update=change dependency loop without fixing it | ||
| 28 | #file=main.zig | ||
| 29 | pub const A = struct { b: B }; | ||
| 30 | pub const B = struct { a: *align(@alignOf(A)) A }; | ||
| 31 | pub fn main() void { | ||
| 32 | _ = B; | ||
| 33 | } | ||
| 34 | #expect_stdout="" | ||
| 35 | |||
| 36 | #update=reference dependency loop again | ||
| 37 | #file=main.zig | ||
| 38 | pub const A = struct { b: B }; | ||
| 39 | pub const B = struct { a: *align(@alignOf(A)) A }; | ||
| 40 | pub 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 | ||
| 50 | pub const A = struct { b: B }; | ||
| 51 | pub const B = struct { a: *A }; | ||
| 52 | pub 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; |
| 426 | 426 | if (!std.mem.eql(u8, expected.msg, msg)) break :matches false; | |
| 427 | const io = eval.io; | 427 | if (err.src_loc == .none) { |
| 428 | 428 | 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 | }; |
| 436 | 445 | 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 { |
| 714 | 717 | ||
| 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 | }; |
| 722 | 727 | ||
| 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 { |
| 930 | 935 | ||
| 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 | false | 949 | 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 | else | 952 | 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 }); |
| 949 | 954 | ||
| 950 | const line = std.fmt.parseInt(u32, line_str, 10) catch | 955 | 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 }); | ||
| 955 | 957 | ||
| 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 | } |
| 964 | 970 |