| author | |
| committer | |
| log | 6201031e0581c54688fdf6071a250b80f892525b |
| tree | b8fac5782647b26920756d6a805cd5d799f533ff |
| parent | bdd3bc056ee998770ea48a93b4ec99521f069aed |
| parent | 3ba4f86198267fee0f6a8d50496908794e743cbd |
| signature |
incremental compilation progress10 files changed, 181 insertions(+), 62 deletions(-)
src/Compilation.zig+29-35| ... | ... | @@ -2901,6 +2901,7 @@ pub fn makeBinFileWritable(comp: *Compilation) !void { |
| 2901 | 2901 | const Header = extern struct { |
| 2902 | 2902 | intern_pool: extern struct { |
| 2903 | 2903 | thread_count: u32, |
| 2904 | file_deps_len: u32, | |
| 2904 | 2905 | src_hash_deps_len: u32, |
| 2905 | 2906 | nav_val_deps_len: u32, |
| 2906 | 2907 | namespace_deps_len: u32, |
| ... | ... | @@ -2943,6 +2944,7 @@ pub fn saveState(comp: *Compilation) !void { |
| 2943 | 2944 | const header: Header = .{ |
| 2944 | 2945 | .intern_pool = .{ |
| 2945 | 2946 | .thread_count = @intCast(ip.locals.len), |
| 2947 | .file_deps_len = @intCast(ip.file_deps.count()), | |
| 2946 | 2948 | .src_hash_deps_len = @intCast(ip.src_hash_deps.count()), |
| 2947 | 2949 | .nav_val_deps_len = @intCast(ip.nav_val_deps.count()), |
| 2948 | 2950 | .namespace_deps_len = @intCast(ip.namespace_deps.count()), |
| ... | ... | @@ -2969,6 +2971,8 @@ pub fn saveState(comp: *Compilation) !void { |
| 2969 | 2971 | addBuf(&bufs, mem.asBytes(&header)); |
| 2970 | 2972 | addBuf(&bufs, mem.sliceAsBytes(pt_headers.items)); |
| 2971 | 2973 | |
| 2974 | addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.keys())); | |
| 2975 | addBuf(&bufs, mem.sliceAsBytes(ip.file_deps.values())); | |
| 2972 | 2976 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.keys())); |
| 2973 | 2977 | addBuf(&bufs, mem.sliceAsBytes(ip.src_hash_deps.values())); |
| 2974 | 2978 | addBuf(&bufs, mem.sliceAsBytes(ip.nav_val_deps.keys())); |
| ... | ... | @@ -3076,15 +3080,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3076 | 3080 | }); |
| 3077 | 3081 | } |
| 3078 | 3082 | |
| 3079 | var all_references: ?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference) = null; | |
| 3080 | defer if (all_references) |*a| a.deinit(gpa); | |
| 3081 | ||
| 3082 | 3083 | if (comp.zcu) |zcu| { |
| 3083 | 3084 | const ip = &zcu.intern_pool; |
| 3084 | 3085 | |
| 3085 | 3086 | for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { |
| 3086 | 3087 | if (error_msg) |msg| { |
| 3087 | try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references); | |
| 3088 | try addModuleErrorMsg(zcu, &bundle, msg.*); | |
| 3088 | 3089 | } else { |
| 3089 | 3090 | // Must be ZIR errors. Note that this may include AST errors. |
| 3090 | 3091 | // addZirErrorMessages asserts that the tree is loaded. |
| ... | ... | @@ -3093,7 +3094,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3093 | 3094 | } |
| 3094 | 3095 | } |
| 3095 | 3096 | for (zcu.failed_embed_files.values()) |error_msg| { |
| 3096 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | |
| 3097 | try addModuleErrorMsg(zcu, &bundle, error_msg.*); | |
| 3097 | 3098 | } |
| 3098 | 3099 | { |
| 3099 | 3100 | const SortOrder = struct { |
| ... | ... | @@ -3136,10 +3137,8 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3136 | 3137 | } |
| 3137 | 3138 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { |
| 3138 | 3139 | if (comp.incremental) { |
| 3139 | if (all_references == null) { | |
| 3140 | all_references = try zcu.resolveReferences(); | |
| 3141 | } | |
| 3142 | if (!all_references.?.contains(anal_unit)) continue; | |
| 3140 | const refs = try zcu.resolveReferences(); | |
| 3141 | if (!refs.contains(anal_unit)) continue; | |
| 3143 | 3142 | } |
| 3144 | 3143 | |
| 3145 | 3144 | const file_index = switch (anal_unit.unwrap()) { |
| ... | ... | @@ -3151,7 +3150,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3151 | 3150 | // We'll try again once parsing succeeds. |
| 3152 | 3151 | if (!zcu.fileByIndex(file_index).okToReportErrors()) continue; |
| 3153 | 3152 | |
| 3154 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | |
| 3153 | try addModuleErrorMsg(zcu, &bundle, error_msg.*); | |
| 3155 | 3154 | if (zcu.cimport_errors.get(anal_unit)) |errors| { |
| 3156 | 3155 | for (errors.getMessages()) |err_msg_index| { |
| 3157 | 3156 | const err_msg = errors.getErrorMessage(err_msg_index); |
| ... | ... | @@ -3175,10 +3174,10 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3175 | 3174 | } |
| 3176 | 3175 | for (zcu.failed_codegen.keys(), zcu.failed_codegen.values()) |nav, error_msg| { |
| 3177 | 3176 | if (!zcu.navFileScope(nav).okToReportErrors()) continue; |
| 3178 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); | |
| 3177 | try addModuleErrorMsg(zcu, &bundle, error_msg.*); | |
| 3179 | 3178 | } |
| 3180 | 3179 | for (zcu.failed_exports.values()) |value| { |
| 3181 | try addModuleErrorMsg(zcu, &bundle, value.*, &all_references); | |
| 3180 | try addModuleErrorMsg(zcu, &bundle, value.*); | |
| 3182 | 3181 | } |
| 3183 | 3182 | |
| 3184 | 3183 | const actual_error_count = zcu.intern_pool.global_error_set.getNamesFromMainThread().len; |
| ... | ... | @@ -3252,17 +3251,15 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3252 | 3251 | }; |
| 3253 | 3252 | } |
| 3254 | 3253 | |
| 3255 | try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references); | |
| 3254 | try addModuleErrorMsg(zcu, &bundle, err_msg); | |
| 3256 | 3255 | } |
| 3257 | 3256 | } |
| 3258 | 3257 | |
| 3259 | 3258 | if (comp.zcu) |zcu| { |
| 3260 | 3259 | if (comp.incremental and bundle.root_list.items.len == 0) { |
| 3261 | 3260 | const should_have_error = for (zcu.transitive_failed_analysis.keys()) |failed_unit| { |
| 3262 | if (all_references == null) { | |
| 3263 | all_references = try zcu.resolveReferences(); | |
| 3264 | } | |
| 3265 | if (all_references.?.contains(failed_unit)) break true; | |
| 3261 | const refs = try zcu.resolveReferences(); | |
| 3262 | if (refs.contains(failed_unit)) break true; | |
| 3266 | 3263 | } else false; |
| 3267 | 3264 | if (should_have_error) { |
| 3268 | 3265 | @panic("referenced transitive analysis errors, but none actually emitted"); |
| ... | ... | @@ -3331,14 +3328,13 @@ pub const ErrorNoteHashContext = struct { |
| 3331 | 3328 | }; |
| 3332 | 3329 | |
| 3333 | 3330 | pub fn addModuleErrorMsg( |
| 3334 | mod: *Zcu, | |
| 3331 | zcu: *Zcu, | |
| 3335 | 3332 | eb: *ErrorBundle.Wip, |
| 3336 | 3333 | module_err_msg: Zcu.ErrorMsg, |
| 3337 | all_references: *?std.AutoHashMapUnmanaged(InternPool.AnalUnit, ?Zcu.ResolvedReference), | |
| 3338 | 3334 | ) !void { |
| 3339 | 3335 | const gpa = eb.gpa; |
| 3340 | const ip = &mod.intern_pool; | |
| 3341 | const err_src_loc = module_err_msg.src_loc.upgrade(mod); | |
| 3336 | const ip = &zcu.intern_pool; | |
| 3337 | const err_src_loc = module_err_msg.src_loc.upgrade(zcu); | |
| 3342 | 3338 | const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| { |
| 3343 | 3339 | const file_path = try err_src_loc.file_scope.fullPath(gpa); |
| 3344 | 3340 | defer gpa.free(file_path); |
| ... | ... | @@ -3358,22 +3354,20 @@ pub fn addModuleErrorMsg( |
| 3358 | 3354 | defer ref_traces.deinit(gpa); |
| 3359 | 3355 | |
| 3360 | 3356 | if (module_err_msg.reference_trace_root.unwrap()) |rt_root| { |
| 3361 | if (all_references.* == null) { | |
| 3362 | all_references.* = try mod.resolveReferences(); | |
| 3363 | } | |
| 3357 | const all_references = try zcu.resolveReferences(); | |
| 3364 | 3358 | |
| 3365 | 3359 | var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty; |
| 3366 | 3360 | defer seen.deinit(gpa); |
| 3367 | 3361 | |
| 3368 | const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len; | |
| 3362 | const max_references = zcu.comp.reference_trace orelse Sema.default_reference_trace_len; | |
| 3369 | 3363 | |
| 3370 | 3364 | var referenced_by = rt_root; |
| 3371 | while (all_references.*.?.get(referenced_by)) |maybe_ref| { | |
| 3365 | while (all_references.get(referenced_by)) |maybe_ref| { | |
| 3372 | 3366 | const ref = maybe_ref orelse break; |
| 3373 | 3367 | const gop = try seen.getOrPut(gpa, ref.referencer); |
| 3374 | 3368 | if (gop.found_existing) break; |
| 3375 | 3369 | if (ref_traces.items.len < max_references) { |
| 3376 | const src = ref.src.upgrade(mod); | |
| 3370 | const src = ref.src.upgrade(zcu); | |
| 3377 | 3371 | const source = try src.file_scope.getSource(gpa); |
| 3378 | 3372 | const span = try src.span(gpa); |
| 3379 | 3373 | const loc = std.zig.findLineColumn(source.bytes, span.main); |
| ... | ... | @@ -3385,7 +3379,7 @@ pub fn addModuleErrorMsg( |
| 3385 | 3379 | .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip), |
| 3386 | 3380 | .none => "comptime", |
| 3387 | 3381 | }, |
| 3388 | .func => |f| ip.getNav(mod.funcInfo(f).owner_nav).name.toSlice(ip), | |
| 3382 | .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), | |
| 3389 | 3383 | }; |
| 3390 | 3384 | try ref_traces.append(gpa, .{ |
| 3391 | 3385 | .decl_name = try eb.addString(name), |
| ... | ... | @@ -3435,7 +3429,7 @@ pub fn addModuleErrorMsg( |
| 3435 | 3429 | defer notes.deinit(gpa); |
| 3436 | 3430 | |
| 3437 | 3431 | for (module_err_msg.notes) |module_note| { |
| 3438 | const note_src_loc = module_note.src_loc.upgrade(mod); | |
| 3432 | const note_src_loc = module_note.src_loc.upgrade(zcu); | |
| 3439 | 3433 | const source = try note_src_loc.file_scope.getSource(gpa); |
| 3440 | 3434 | const span = try note_src_loc.span(gpa); |
| 3441 | 3435 | const loc = std.zig.findLineColumn(source.bytes, span.main); |
| ... | ... | @@ -3488,13 +3482,13 @@ pub fn performAllTheWork( |
| 3488 | 3482 | comp: *Compilation, |
| 3489 | 3483 | main_progress_node: std.Progress.Node, |
| 3490 | 3484 | ) JobError!void { |
| 3491 | defer if (comp.zcu) |mod| { | |
| 3492 | mod.sema_prog_node.end(); | |
| 3493 | mod.sema_prog_node = std.Progress.Node.none; | |
| 3494 | mod.codegen_prog_node.end(); | |
| 3495 | mod.codegen_prog_node = std.Progress.Node.none; | |
| 3485 | defer if (comp.zcu) |zcu| { | |
| 3486 | zcu.sema_prog_node.end(); | |
| 3487 | zcu.sema_prog_node = std.Progress.Node.none; | |
| 3488 | zcu.codegen_prog_node.end(); | |
| 3489 | zcu.codegen_prog_node = std.Progress.Node.none; | |
| 3496 | 3490 | |
| 3497 | mod.generation += 1; | |
| 3491 | zcu.generation += 1; | |
| 3498 | 3492 | }; |
| 3499 | 3493 | try comp.performAllTheWorkInner(main_progress_node); |
| 3500 | 3494 | if (!InternPool.single_threaded) if (comp.codegen_work.job_error) |job_error| return job_error; |
src/InternPool.zig+12| ... | ... | @@ -17,6 +17,13 @@ tid_shift_31: if (single_threaded) u0 else std.math.Log2Int(u32), |
| 17 | 17 | /// Cached shift amount to put a `tid` in the top bits of a 32-bit value. |
| 18 | 18 | tid_shift_32: if (single_threaded) u0 else std.math.Log2Int(u32), |
| 19 | 19 | |
| 20 | /// Dependencies on whether an entire file gets past AstGen. | |
| 21 | /// These are triggered by `@import`, so that: | |
| 22 | /// * if a file initially fails AstGen, triggering a transitive failure, when a future update | |
| 23 | /// causes it to succeed AstGen, the `@import` is re-analyzed, allowing analysis to proceed | |
| 24 | /// * if a file initially succeds AstGen, but a future update causes the file to fail it, | |
| 25 | /// the `@import` is re-analyzed, registering a transitive failure | |
| 26 | file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index), | |
| 20 | 27 | /// Dependencies on the source code hash associated with a ZIR instruction. |
| 21 | 28 | /// * For a `declaration`, this is the entire declaration body. |
| 22 | 29 | /// * For a `struct_decl`, `union_decl`, etc, this is the source of the fields (but not declarations). |
| ... | ... | @@ -70,6 +77,7 @@ pub const empty: InternPool = .{ |
| 70 | 77 | .tid_shift_30 = if (single_threaded) 0 else 31, |
| 71 | 78 | .tid_shift_31 = if (single_threaded) 0 else 31, |
| 72 | 79 | .tid_shift_32 = if (single_threaded) 0 else 31, |
| 80 | .file_deps = .empty, | |
| 73 | 81 | .src_hash_deps = .empty, |
| 74 | 82 | .nav_val_deps = .empty, |
| 75 | 83 | .interned_deps = .empty, |
| ... | ... | @@ -656,6 +664,7 @@ pub const Nav = struct { |
| 656 | 664 | }; |
| 657 | 665 | |
| 658 | 666 | pub const Dependee = union(enum) { |
| 667 | file: FileIndex, | |
| 659 | 668 | src_hash: TrackedInst.Index, |
| 660 | 669 | nav_val: Nav.Index, |
| 661 | 670 | interned: Index, |
| ... | ... | @@ -704,6 +713,7 @@ pub const DependencyIterator = struct { |
| 704 | 713 | |
| 705 | 714 | pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyIterator { |
| 706 | 715 | const first_entry = switch (dependee) { |
| 716 | .file => |x| ip.file_deps.get(x), | |
| 707 | 717 | .src_hash => |x| ip.src_hash_deps.get(x), |
| 708 | 718 | .nav_val => |x| ip.nav_val_deps.get(x), |
| 709 | 719 | .interned => |x| ip.interned_deps.get(x), |
| ... | ... | @@ -740,6 +750,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend |
| 740 | 750 | const new_index: DepEntry.Index = switch (dependee) { |
| 741 | 751 | inline else => |dependee_payload, tag| new_index: { |
| 742 | 752 | const gop = try switch (tag) { |
| 753 | .file => ip.file_deps, | |
| 743 | 754 | .src_hash => ip.src_hash_deps, |
| 744 | 755 | .nav_val => ip.nav_val_deps, |
| 745 | 756 | .interned => ip.interned_deps, |
| ... | ... | @@ -6268,6 +6279,7 @@ pub fn init(ip: *InternPool, gpa: Allocator, available_threads: usize) !void { |
| 6268 | 6279 | } |
| 6269 | 6280 | |
| 6270 | 6281 | pub fn deinit(ip: *InternPool, gpa: Allocator) void { |
| 6282 | ip.file_deps.deinit(gpa); | |
| 6271 | 6283 | ip.src_hash_deps.deinit(gpa); |
| 6272 | 6284 | ip.nav_val_deps.deinit(gpa); |
| 6273 | 6285 | ip.interned_deps.deinit(gpa); |
src/Package/Module.zig+1| ... | ... | @@ -454,6 +454,7 @@ pub fn create(arena: Allocator, options: CreateOptions) !*Package.Module { |
| 454 | 454 | .tree = undefined, |
| 455 | 455 | .zir = undefined, |
| 456 | 456 | .status = .never_loaded, |
| 457 | .prev_status = .never_loaded, | |
| 457 | 458 | .mod = new, |
| 458 | 459 | }; |
| 459 | 460 | break :b new; |
src/Sema.zig+3-8| ... | ... | @@ -2559,10 +2559,9 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Zcu.ErrorMsg |
| 2559 | 2559 | const zcu = sema.pt.zcu; |
| 2560 | 2560 | |
| 2561 | 2561 | if (build_options.enable_debug_extensions and zcu.comp.debug_compile_errors) { |
| 2562 | var all_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?Zcu.ResolvedReference) = null; | |
| 2563 | 2562 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; |
| 2564 | 2563 | wip_errors.init(gpa) catch @panic("out of memory"); |
| 2565 | Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*, &all_references) catch @panic("out of memory"); | |
| 2564 | Compilation.addModuleErrorMsg(zcu, &wip_errors, err_msg.*) catch @panic("out of memory"); | |
| 2566 | 2565 | std.debug.print("compile error during Sema:\n", .{}); |
| 2567 | 2566 | var error_bundle = wip_errors.toOwnedBundle("") catch @panic("out of memory"); |
| 2568 | 2567 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); |
| ... | ... | @@ -6025,9 +6024,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr |
| 6025 | 6024 | pt.astGenFile(result.file, path_digest) catch |err| |
| 6026 | 6025 | return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)}); |
| 6027 | 6026 | |
| 6028 | // TODO: register some kind of dependency on the file. | |
| 6029 | // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to | |
| 6030 | // trigger re-analysis later. | |
| 6027 | try sema.declareDependency(.{ .file = result.file_index }); | |
| 6031 | 6028 | try pt.ensureFileAnalyzed(result.file_index); |
| 6032 | 6029 | const ty = zcu.fileRootType(result.file_index); |
| 6033 | 6030 | try sema.declareDependency(.{ .interned = ty }); |
| ... | ... | @@ -14348,9 +14345,7 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. |
| 14348 | 14345 | return sema.fail(block, operand_src, "unable to open '{s}': {s}", .{ operand, @errorName(err) }); |
| 14349 | 14346 | }, |
| 14350 | 14347 | }; |
| 14351 | // TODO: register some kind of dependency on the file. | |
| 14352 | // That way, if this returns `error.AnalysisFail`, we have the dependency banked ready to | |
| 14353 | // trigger re-analysis later. | |
| 14348 | try sema.declareDependency(.{ .file = result.file_index }); | |
| 14354 | 14349 | try pt.ensureFileAnalyzed(result.file_index); |
| 14355 | 14350 | const ty = zcu.fileRootType(result.file_index); |
| 14356 | 14351 | try sema.declareDependency(.{ .interned = ty }); |
src/Zcu.zig+40-8| ... | ... | @@ -173,6 +173,10 @@ retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .empty, |
| 173 | 173 | /// These are the modules which we initially queue for analysis in `Compilation.update`. |
| 174 | 174 | /// `resolveReferences` will use these as the root of its reachability traversal. |
| 175 | 175 | analysis_roots: std.BoundedArray(*Package.Module, 3) = .{}, |
| 176 | /// This is the cached result of `Zcu.resolveReferences`. It is computed on-demand, and | |
| 177 | /// reset to `null` when any semantic analysis occurs (since this invalidates the data). | |
| 178 | /// Allocated into `gpa`. | |
| 179 | resolved_references: ?std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) = null, | |
| 176 | 180 | |
| 177 | 181 | stage1_flags: packed struct { |
| 178 | 182 | have_winmain: bool = false, |
| ... | ... | @@ -420,13 +424,8 @@ pub const Namespace = struct { |
| 420 | 424 | }; |
| 421 | 425 | |
| 422 | 426 | pub const File = struct { |
| 423 | status: enum { | |
| 424 | never_loaded, | |
| 425 | retryable_failure, | |
| 426 | parse_failure, | |
| 427 | astgen_failure, | |
| 428 | success_zir, | |
| 429 | }, | |
| 427 | status: Status, | |
| 428 | prev_status: Status, | |
| 430 | 429 | source_loaded: bool, |
| 431 | 430 | tree_loaded: bool, |
| 432 | 431 | zir_loaded: bool, |
| ... | ... | @@ -454,6 +453,14 @@ pub const File = struct { |
| 454 | 453 | /// successful, this field is unloaded. |
| 455 | 454 | prev_zir: ?*Zir = null, |
| 456 | 455 | |
| 456 | pub const Status = enum { | |
| 457 | never_loaded, | |
| 458 | retryable_failure, | |
| 459 | parse_failure, | |
| 460 | astgen_failure, | |
| 461 | success_zir, | |
| 462 | }; | |
| 463 | ||
| 457 | 464 | /// A single reference to a file. |
| 458 | 465 | pub const Reference = union(enum) { |
| 459 | 466 | /// The file is imported directly (i.e. not as a package) with @import. |
| ... | ... | @@ -2192,6 +2199,8 @@ pub fn deinit(zcu: *Zcu) void { |
| 2192 | 2199 | zcu.all_type_references.deinit(gpa); |
| 2193 | 2200 | zcu.free_type_references.deinit(gpa); |
| 2194 | 2201 | |
| 2202 | if (zcu.resolved_references) |*r| r.deinit(gpa); | |
| 2203 | ||
| 2195 | 2204 | zcu.intern_pool.deinit(gpa); |
| 2196 | 2205 | } |
| 2197 | 2206 | |
| ... | ... | @@ -2760,6 +2769,8 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2760 | 2769 | pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2761 | 2770 | const gpa = zcu.gpa; |
| 2762 | 2771 | |
| 2772 | zcu.clearCachedResolvedReferences(); | |
| 2773 | ||
| 2763 | 2774 | unit_refs: { |
| 2764 | 2775 | const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse break :unit_refs; |
| 2765 | 2776 | var idx = kv.value; |
| ... | ... | @@ -2792,6 +2803,8 @@ pub fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 2792 | 2803 | pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void { |
| 2793 | 2804 | const gpa = zcu.gpa; |
| 2794 | 2805 | |
| 2806 | zcu.clearCachedResolvedReferences(); | |
| 2807 | ||
| 2795 | 2808 | try zcu.reference_table.ensureUnusedCapacity(gpa, 1); |
| 2796 | 2809 | |
| 2797 | 2810 | const ref_idx = zcu.free_references.popOrNull() orelse idx: { |
| ... | ... | @@ -2815,6 +2828,8 @@ pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit |
| 2815 | 2828 | pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void { |
| 2816 | 2829 | const gpa = zcu.gpa; |
| 2817 | 2830 | |
| 2831 | zcu.clearCachedResolvedReferences(); | |
| 2832 | ||
| 2818 | 2833 | try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1); |
| 2819 | 2834 | |
| 2820 | 2835 | const ref_idx = zcu.free_type_references.popOrNull() orelse idx: { |
| ... | ... | @@ -2835,6 +2850,11 @@ pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPo |
| 2835 | 2850 | gop.value_ptr.* = @intCast(ref_idx); |
| 2836 | 2851 | } |
| 2837 | 2852 | |
| 2853 | fn clearCachedResolvedReferences(zcu: *Zcu) void { | |
| 2854 | if (zcu.resolved_references) |*r| r.deinit(zcu.gpa); | |
| 2855 | zcu.resolved_references = null; | |
| 2856 | } | |
| 2857 | ||
| 2838 | 2858 | pub fn errorSetBits(zcu: *const Zcu) u16 { |
| 2839 | 2859 | if (zcu.error_limit == 0) return 0; |
| 2840 | 2860 | return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1; |
| ... | ... | @@ -3138,7 +3158,15 @@ pub const ResolvedReference = struct { |
| 3138 | 3158 | /// Returns a mapping from an `AnalUnit` to where it is referenced. |
| 3139 | 3159 | /// If the value is `null`, the `AnalUnit` is a root of analysis. |
| 3140 | 3160 | /// If an `AnalUnit` is not in the returned map, it is unreferenced. |
| 3141 | pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) { | |
| 3161 | /// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller. | |
| 3162 | /// This hashmap is cached, so repeated calls to this function are cheap. | |
| 3163 | pub fn resolveReferences(zcu: *Zcu) !*const std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) { | |
| 3164 | if (zcu.resolved_references == null) { | |
| 3165 | zcu.resolved_references = try zcu.resolveReferencesInner(); | |
| 3166 | } | |
| 3167 | return &zcu.resolved_references.?; | |
| 3168 | } | |
| 3169 | fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?ResolvedReference) { | |
| 3142 | 3170 | const gpa = zcu.gpa; |
| 3143 | 3171 | const comp = zcu.comp; |
| 3144 | 3172 | const ip = &zcu.intern_pool; |
| ... | ... | @@ -3449,6 +3477,10 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com |
| 3449 | 3477 | const zcu = data.zcu; |
| 3450 | 3478 | const ip = &zcu.intern_pool; |
| 3451 | 3479 | switch (data.dependee) { |
| 3480 | .file => |file| { | |
| 3481 | const file_path = zcu.fileByIndex(file).sub_file_path; | |
| 3482 | return writer.print("file('{s}')", .{file_path}); | |
| 3483 | }, | |
| 3452 | 3484 | .src_hash => |ti| { |
| 3453 | 3485 | const info = ti.resolveFull(ip) orelse { |
| 3454 | 3486 | return writer.writeAll("inst(<lost>)"); |
src/Zcu/PerThread.zig+26-10| ... | ... | @@ -179,10 +179,10 @@ pub fn astGenFile( |
| 179 | 179 | .inode = header.stat_inode, |
| 180 | 180 | .mtime = header.stat_mtime, |
| 181 | 181 | }; |
| 182 | file.prev_status = file.status; | |
| 182 | 183 | file.status = .success_zir; |
| 183 | 184 | log.debug("AstGen cached success: {s}", .{file.sub_file_path}); |
| 184 | 185 | |
| 185 | // TODO don't report compile errors until Sema @importFile | |
| 186 | 186 | if (file.zir.hasCompileErrors()) { |
| 187 | 187 | { |
| 188 | 188 | comp.mutex.lock(); |
| ... | ... | @@ -258,6 +258,7 @@ pub fn astGenFile( |
| 258 | 258 | // Any potential AST errors are converted to ZIR errors here. |
| 259 | 259 | file.zir = try AstGen.generate(gpa, file.tree); |
| 260 | 260 | file.zir_loaded = true; |
| 261 | file.prev_status = file.status; | |
| 261 | 262 | file.status = .success_zir; |
| 262 | 263 | log.debug("AstGen fresh success: {s}", .{file.sub_file_path}); |
| 263 | 264 | |
| ... | ... | @@ -350,6 +351,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 350 | 351 | defer cleanupUpdatedFiles(gpa, &updated_files); |
| 351 | 352 | for (zcu.import_table.values()) |file_index| { |
| 352 | 353 | const file = zcu.fileByIndex(file_index); |
| 354 | if (file.prev_status != file.status and file.prev_status != .never_loaded) { | |
| 355 | try zcu.markDependeeOutdated(.not_marked_po, .{ .file = file_index }); | |
| 356 | } | |
| 353 | 357 | const old_zir = file.prev_zir orelse continue; |
| 354 | 358 | const new_zir = file.zir; |
| 355 | 359 | const gop = try updated_files.getOrPut(gpa, file_index); |
| ... | ... | @@ -551,11 +555,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 551 | 555 | const cau_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 552 | 556 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 553 | 557 | |
| 558 | const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit); | |
| 559 | ||
| 554 | 560 | if (cau_outdated) { |
| 555 | 561 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 556 | 562 | } else { |
| 557 | 563 | // We can trust the current information about this `Cau`. |
| 558 | if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) { | |
| 564 | if (prev_failed) { | |
| 559 | 565 | return error.AnalysisFail; |
| 560 | 566 | } |
| 561 | 567 | // If it wasn't failed and wasn't marked outdated, then either... |
| ... | ... | @@ -578,9 +584,13 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 578 | 584 | // Since it does not, this must be a transitive failure. |
| 579 | 585 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); |
| 580 | 586 | } |
| 581 | // We treat errors as up-to-date, since those uses would just trigger a transitive error. | |
| 582 | // The exception is types, since type declarations may require re-analysis if the type, e.g. its captures, changed. | |
| 583 | const outdated = cau.owner.unwrap() == .type; | |
| 587 | // We consider this `Cau` to be outdated if: | |
| 588 | // * Previous analysis succeeded; in this case, we need to re-analyze dependants to ensure | |
| 589 | // they hit a transitive error here, rather than reporting a different error later (which | |
| 590 | // may now be invalid). | |
| 591 | // * The `Cau` is a type; in this case, the declaration site may require re-analysis to | |
| 592 | // construct a valid type. | |
| 593 | const outdated = !prev_failed or cau.owner.unwrap() == .type; | |
| 584 | 594 | break :res .{ .{ |
| 585 | 595 | .invalidate_decl_val = outdated, |
| 586 | 596 | .invalidate_decl_ref = outdated, |
| ... | ... | @@ -597,10 +607,9 @@ pub fn ensureCauAnalyzed(pt: Zcu.PerThread, cau_index: InternPool.Cau.Index) Zcu |
| 597 | 607 | ); |
| 598 | 608 | zcu.retryable_failures.appendAssumeCapacity(anal_unit); |
| 599 | 609 | zcu.failed_analysis.putAssumeCapacityNoClobber(anal_unit, msg); |
| 600 | // We treat errors as up-to-date, since those uses would just trigger a transitive error | |
| 601 | 610 | break :res .{ .{ |
| 602 | .invalidate_decl_val = false, | |
| 603 | .invalidate_decl_ref = false, | |
| 611 | .invalidate_decl_val = true, | |
| 612 | .invalidate_decl_ref = true, | |
| 604 | 613 | }, true }; |
| 605 | 614 | }, |
| 606 | 615 | }; |
| ... | ... | @@ -707,11 +716,13 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 707 | 716 | const func_outdated = zcu.outdated.swapRemove(anal_unit) or |
| 708 | 717 | zcu.potentially_outdated.swapRemove(anal_unit); |
| 709 | 718 | |
| 719 | const prev_failed = zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit); | |
| 720 | ||
| 710 | 721 | if (func_outdated) { |
| 711 | 722 | _ = zcu.outdated_ready.swapRemove(anal_unit); |
| 712 | 723 | } else { |
| 713 | 724 | // We can trust the current information about this function. |
| 714 | if (zcu.failed_analysis.contains(anal_unit) or zcu.transitive_failed_analysis.contains(anal_unit)) { | |
| 725 | if (prev_failed) { | |
| 715 | 726 | return error.AnalysisFail; |
| 716 | 727 | } |
| 717 | 728 | switch (func.analysisUnordered(ip).state) { |
| ... | ... | @@ -730,7 +741,10 @@ pub fn ensureFuncBodyAnalyzed(pt: Zcu.PerThread, maybe_coerced_func_index: Inter |
| 730 | 741 | // Since it does not, this must be a transitive failure. |
| 731 | 742 | try zcu.transitive_failed_analysis.put(gpa, anal_unit, {}); |
| 732 | 743 | } |
| 733 | break :res .{ false, true }; // we treat errors as up-to-date IES, since those uses would just trigger a transitive error | |
| 744 | // We consider the IES to be outdated if the function previously succeeded analysis; in this case, | |
| 745 | // we need to re-analyze dependants to ensure they hit a transitive error here, rather than reporting | |
| 746 | // a different error later (which may now be invalid). | |
| 747 | break :res .{ !prev_failed, true }; | |
| 734 | 748 | }, |
| 735 | 749 | error.OutOfMemory => return error.OutOfMemory, // TODO: graceful handling like `ensureCauAnalyzed` |
| 736 | 750 | }; |
| ... | ... | @@ -1445,6 +1459,7 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult { |
| 1445 | 1459 | .tree = undefined, |
| 1446 | 1460 | .zir = undefined, |
| 1447 | 1461 | .status = .never_loaded, |
| 1462 | .prev_status = .never_loaded, | |
| 1448 | 1463 | .mod = mod, |
| 1449 | 1464 | }; |
| 1450 | 1465 | |
| ... | ... | @@ -1555,6 +1570,7 @@ pub fn importFile( |
| 1555 | 1570 | .tree = undefined, |
| 1556 | 1571 | .zir = undefined, |
| 1557 | 1572 | .status = .never_loaded, |
| 1573 | .prev_status = .never_loaded, | |
| 1558 | 1574 | .mod = mod, |
| 1559 | 1575 | }; |
| 1560 | 1576 |
src/main.zig+3| ... | ... | @@ -6118,6 +6118,7 @@ fn cmdAstCheck( |
| 6118 | 6118 | |
| 6119 | 6119 | var file: Zcu.File = .{ |
| 6120 | 6120 | .status = .never_loaded, |
| 6121 | .prev_status = .never_loaded, | |
| 6121 | 6122 | .source_loaded = false, |
| 6122 | 6123 | .tree_loaded = false, |
| 6123 | 6124 | .zir_loaded = false, |
| ... | ... | @@ -6441,6 +6442,7 @@ fn cmdDumpZir( |
| 6441 | 6442 | |
| 6442 | 6443 | var file: Zcu.File = .{ |
| 6443 | 6444 | .status = .never_loaded, |
| 6445 | .prev_status = .never_loaded, | |
| 6444 | 6446 | .source_loaded = false, |
| 6445 | 6447 | .tree_loaded = false, |
| 6446 | 6448 | .zir_loaded = true, |
| ... | ... | @@ -6508,6 +6510,7 @@ fn cmdChangelist( |
| 6508 | 6510 | |
| 6509 | 6511 | var file: Zcu.File = .{ |
| 6510 | 6512 | .status = .never_loaded, |
| 6513 | .prev_status = .never_loaded, | |
| 6511 | 6514 | .source_loaded = false, |
| 6512 | 6515 | .tree_loaded = false, |
| 6513 | 6516 | .zir_loaded = false, |
test/incremental/add_decl+2-1| ... | ... | @@ -1,4 +1,5 @@ |
| 1 | #target=x86_64-linux-selfhosted | |
| 1 | // Disabled on self-hosted due to linker crash | |
| 2 | // #target=x86_64-linux-selfhosted | |
| 2 | 3 | #target=x86_64-linux-cbe |
| 3 | 4 | #target=x86_64-windows-cbe |
| 4 | 5 | #update=initial version |
test/incremental/fix_astgen_failure created+35| ... | ... | @@ -0,0 +1,35 @@ |
| 1 | #target=x86_64-linux-selfhosted | |
| 2 | #target=x86_64-linux-cbe | |
| 3 | #target=x86_64-windows-cbe | |
| 4 | #update=initial version with error | |
| 5 | #file=main.zig | |
| 6 | pub fn main() !void { | |
| 7 | try @import("foo.zig").hello(); | |
| 8 | } | |
| 9 | #file=foo.zig | |
| 10 | pub fn hello() !void { | |
| 11 | try std.io.getStdOut().writeAll("Hello, World!\n"); | |
| 12 | } | |
| 13 | #expect_error=ignored | |
| 14 | #update=fix the error | |
| 15 | #file=foo.zig | |
| 16 | const std = @import("std"); | |
| 17 | pub fn hello() !void { | |
| 18 | try std.io.getStdOut().writeAll("Hello, World!\n"); | |
| 19 | } | |
| 20 | #expect_stdout="Hello, World!\n" | |
| 21 | #update=add new error | |
| 22 | #file=foo.zig | |
| 23 | const std = @import("std"); | |
| 24 | pub fn hello() !void { | |
| 25 | try std.io.getStdOut().writeAll(hello_str); | |
| 26 | } | |
| 27 | #expect_error=ignored | |
| 28 | #update=fix the new error | |
| 29 | #file=foo.zig | |
| 30 | const std = @import("std"); | |
| 31 | const hello_str = "Hello, World! Again!\n"; | |
| 32 | pub fn hello() !void { | |
| 33 | try std.io.getStdOut().writeAll(hello_str); | |
| 34 | } | |
| 35 | #expect_stdout="Hello, World! Again!\n" |
test/incremental/remove_invalid_union_backing_enum created+30| ... | ... | @@ -0,0 +1,30 @@ |
| 1 | #target=x86_64-linux-selfhosted | |
| 2 | #target=x86_64-linux-cbe | |
| 3 | #target=x86_64-windows-cbe | |
| 4 | #update=initial version | |
| 5 | #file=main.zig | |
| 6 | const E = enum { a, b, c }; | |
| 7 | const U = union(E) { | |
| 8 | a: i32, | |
| 9 | b: f64, | |
| 10 | c: f64, | |
| 11 | d: f64, | |
| 12 | }; | |
| 13 | pub fn main() void { | |
| 14 | const u: U = .{ .a = 123 }; | |
| 15 | _ = u; | |
| 16 | } | |
| 17 | #expect_error=ignored | |
| 18 | #update=remove invalid backing enum | |
| 19 | #file=main.zig | |
| 20 | const U = union { | |
| 21 | a: i32, | |
| 22 | b: f64, | |
| 23 | c: f64, | |
| 24 | d: f64, | |
| 25 | }; | |
| 26 | pub fn main() void { | |
| 27 | const u: U = .{ .a = 123 }; | |
| 28 | _ = u; | |
| 29 | } | |
| 30 | #expect_stdout="" |