| ... | ... | @@ -109,7 +109,7 @@ pub fn astGenFile( |
| 109 | 109 | |
| 110 | 110 | break :lock .shared; |
| 111 | 111 | }, |
| 112 | | .astgen_failure, .success_zir => lock: { |
| 112 | .astgen_failure, .success => lock: { |
| 113 | 113 | const unchanged_metadata = |
| 114 | 114 | stat.size == file.stat.size and |
| 115 | 115 | stat.mtime == file.stat.mtime and |
| ... | ... | @@ -214,8 +214,7 @@ pub fn astGenFile( |
| 214 | 214 | .inode = header.stat_inode, |
| 215 | 215 | .mtime = header.stat_mtime, |
| 216 | 216 | }; |
| 217 | | file.prev_status = file.status; |
| 218 | | file.status = .success_zir; |
| 217 | file.status = .success; |
| 219 | 218 | log.debug("AstGen cached success: {s}", .{file.sub_file_path}); |
| 220 | 219 | |
| 221 | 220 | if (file.zir.?.hasCompileErrors()) { |
| ... | ... | @@ -248,19 +247,11 @@ pub fn astGenFile( |
| 248 | 247 | |
| 249 | 248 | pt.lockAndClearFileCompileError(file); |
| 250 | 249 | |
| 251 | | // Previous ZIR is kept for two reasons: |
| 252 | | // |
| 253 | | // 1. In case an update to the file causes a Parse or AstGen failure, we |
| 254 | | // need to compare two successful ZIR files in order to proceed with an |
| 255 | | // incremental update. This avoids needlessly tossing out semantic |
| 256 | | // analysis work when an error is temporarily introduced. |
| 257 | | // |
| 258 | | // 2. In order to detect updates, we need to iterate over the intern pool |
| 259 | | // values while comparing old ZIR to new ZIR. This is better done in a |
| 260 | | // single-threaded context, so we need to keep both versions around |
| 261 | | // until that point in the pipeline. Previous ZIR data is freed after |
| 262 | | // that. |
| 263 | | if (file.zir != null and !file.zir.?.loweringFailed()) { |
| 250 | // If `zir` is not null, and `prev_zir` is null, then `TrackedInst`s are associated with `zir`. |
| 251 | // We need to keep it around! |
| 252 | // As an optimization, also check `loweringFailed`; if true, but `prev_zir == null`, then this |
| 253 | // file has never passed AstGen, so we actually need not cache the old ZIR. |
| 254 | if (file.zir != null and file.prev_zir == null and !file.zir.?.loweringFailed()) { |
| 264 | 255 | assert(file.prev_zir == null); |
| 265 | 256 | const prev_zir_ptr = try gpa.create(Zir); |
| 266 | 257 | file.prev_zir = prev_zir_ptr; |
| ... | ... | @@ -289,8 +280,7 @@ pub fn astGenFile( |
| 289 | 280 | |
| 290 | 281 | // Any potential AST errors are converted to ZIR errors here. |
| 291 | 282 | file.zir = try AstGen.generate(gpa, file.tree.?); |
| 292 | | file.prev_status = file.status; |
| 293 | | file.status = .success_zir; |
| 283 | file.status = .success; |
| 294 | 284 | log.debug("AstGen fresh success: {s}", .{file.sub_file_path}); |
| 295 | 285 | |
| 296 | 286 | const safety_buffer = if (Zcu.data_has_safety_tag) |
| ... | ... | @@ -383,9 +373,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 383 | 373 | defer cleanupUpdatedFiles(gpa, &updated_files); |
| 384 | 374 | for (zcu.import_table.values()) |file_index| { |
| 385 | 375 | const file = zcu.fileByIndex(file_index); |
| 386 | | if (file.prev_status != file.status and file.prev_status != .never_loaded) { |
| 387 | | try zcu.markDependeeOutdated(.not_marked_po, .{ .file = file_index }); |
| 388 | | } |
| 376 | assert(file.status == .success); |
| 389 | 377 | const old_zir = file.prev_zir orelse continue; |
| 390 | 378 | const new_zir = file.zir.?; |
| 391 | 379 | const gop = try updated_files.getOrPut(gpa, file_index); |
| ... | ... | @@ -394,9 +382,7 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 394 | 382 | .file = file, |
| 395 | 383 | .inst_map = .{}, |
| 396 | 384 | }; |
| 397 | | if (!new_zir.loweringFailed()) { |
| 398 | | try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, &gop.value_ptr.inst_map); |
| 399 | | } |
| 385 | try Zcu.mapOldZirToNew(gpa, old_zir.*, new_zir, &gop.value_ptr.inst_map); |
| 400 | 386 | } |
| 401 | 387 | |
| 402 | 388 | if (updated_files.count() == 0) |
| ... | ... | @@ -416,13 +402,9 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 416 | 402 | .index = @intCast(tracked_inst_unwrapped_index), |
| 417 | 403 | }).wrap(ip); |
| 418 | 404 | const new_inst = updated_file.inst_map.get(old_inst) orelse { |
| 419 | | // Tracking failed for this instruction. |
| 420 | | // This may be due to changes in the ZIR, or AstGen might have failed due to a very broken file. |
| 421 | | // Either way, invalidate associated `src_hash` deps. |
| 422 | | log.debug("tracking failed for %{d}{s}", .{ |
| 423 | | old_inst, |
| 424 | | if (file.zir.?.loweringFailed()) " due to AstGen failure" else "", |
| 425 | | }); |
| 405 | // Tracking failed for this instruction due to changes in the ZIR. |
| 406 | // Invalidate associated `src_hash` deps. |
| 407 | log.debug("tracking failed for %{d}", .{old_inst}); |
| 426 | 408 | tracked_inst.inst = .lost; |
| 427 | 409 | try zcu.markDependeeOutdated(.not_marked_po, .{ .src_hash = tracked_inst_index }); |
| 428 | 410 | continue; |
| ... | ... | @@ -527,23 +509,19 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void { |
| 527 | 509 | |
| 528 | 510 | for (updated_files.keys(), updated_files.values()) |file_index, updated_file| { |
| 529 | 511 | const file = updated_file.file; |
| 530 | | if (file.zir.?.loweringFailed()) { |
| 531 | | // Keep `prev_zir` around: it's the last usable ZIR. |
| 532 | | // Don't update the namespace, as we have no new data to update *to*. |
| 533 | | } else { |
| 534 | | const prev_zir = file.prev_zir.?; |
| 535 | | file.prev_zir = null; |
| 536 | | prev_zir.deinit(gpa); |
| 537 | | gpa.destroy(prev_zir); |
| 538 | | |
| 539 | | // For every file which has changed, re-scan the namespace of the file's root struct type. |
| 540 | | // These types are special-cased because they don't have an enclosing declaration which will |
| 541 | | // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this |
| 542 | | // now because this work is fast (no actual Sema work is happening, we're just updating the |
| 543 | | // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace` |
| 544 | | // will track some instructions. |
| 545 | | try pt.updateFileNamespace(file_index); |
| 546 | | } |
| 512 | |
| 513 | const prev_zir = file.prev_zir.?; |
| 514 | file.prev_zir = null; |
| 515 | prev_zir.deinit(gpa); |
| 516 | gpa.destroy(prev_zir); |
| 517 | |
| 518 | // For every file which has changed, re-scan the namespace of the file's root struct type. |
| 519 | // These types are special-cased because they don't have an enclosing declaration which will |
| 520 | // be re-analyzed (causing the struct's namespace to be re-scanned). It's fine to do this |
| 521 | // now because this work is fast (no actual Sema work is happening, we're just updating the |
| 522 | // namespace contents). We must do this after updating ZIR refs above, since `scanNamespace` |
| 523 | // will track some instructions. |
| 524 | try pt.updateFileNamespace(file_index); |
| 547 | 525 | } |
| 548 | 526 | } |
| 549 | 527 | |
| ... | ... | @@ -745,6 +723,7 @@ pub fn ensureComptimeUnitUpToDate(pt: Zcu.PerThread, cu_id: InternPool.ComptimeU |
| 745 | 723 | kv.value.destroy(gpa); |
| 746 | 724 | } |
| 747 | 725 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); |
| 726 | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); |
| 748 | 727 | } |
| 749 | 728 | } else { |
| 750 | 729 | // We can trust the current information about this unit. |
| ... | ... | @@ -796,15 +775,8 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu |
| 796 | 775 | |
| 797 | 776 | const inst_resolved = comptime_unit.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 798 | 777 | const file = zcu.fileByIndex(inst_resolved.file); |
| 799 | | // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is |
| 800 | | // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends |
| 801 | | // in `ensureComptimeUnitUpToDate`. |
| 802 | | if (file.status != .success_zir) return error.AnalysisFail; |
| 803 | 778 | const zir = file.zir.?; |
| 804 | 779 | |
| 805 | | // We are about to re-analyze this unit; drop its depenndencies. |
| 806 | | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); |
| 807 | | |
| 808 | 780 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); |
| 809 | 781 | defer assert(zcu.analysis_in_progress.swapRemove(anal_unit)); |
| 810 | 782 | |
| ... | ... | @@ -923,6 +895,7 @@ pub fn ensureNavValUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu |
| 923 | 895 | kv.value.destroy(gpa); |
| 924 | 896 | } |
| 925 | 897 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); |
| 898 | ip.removeDependenciesForDepender(gpa, anal_unit); |
| 926 | 899 | } else { |
| 927 | 900 | // We can trust the current information about this unit. |
| 928 | 901 | if (prev_failed) return error.AnalysisFail; |
| ... | ... | @@ -993,15 +966,8 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr |
| 993 | 966 | |
| 994 | 967 | const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 995 | 968 | const file = zcu.fileByIndex(inst_resolved.file); |
| 996 | | // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is |
| 997 | | // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends |
| 998 | | // in `ensureComptimeUnitUpToDate`. |
| 999 | | if (file.status != .success_zir) return error.AnalysisFail; |
| 1000 | 969 | const zir = file.zir.?; |
| 1001 | 970 | |
| 1002 | | // We are about to re-analyze this unit; drop its depenndencies. |
| 1003 | | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); |
| 1004 | | |
| 1005 | 971 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); |
| 1006 | 972 | errdefer _ = zcu.analysis_in_progress.swapRemove(anal_unit); |
| 1007 | 973 | |
| ... | ... | @@ -1301,6 +1267,7 @@ pub fn ensureNavTypeUpToDate(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zc |
| 1301 | 1267 | kv.value.destroy(gpa); |
| 1302 | 1268 | } |
| 1303 | 1269 | _ = zcu.transitive_failed_analysis.swapRemove(anal_unit); |
| 1270 | ip.removeDependenciesForDepender(gpa, anal_unit); |
| 1304 | 1271 | } else { |
| 1305 | 1272 | // We can trust the current information about this unit. |
| 1306 | 1273 | if (prev_failed) return error.AnalysisFail; |
| ... | ... | @@ -1371,15 +1338,8 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr |
| 1371 | 1338 | |
| 1372 | 1339 | const inst_resolved = old_nav.analysis.?.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 1373 | 1340 | const file = zcu.fileByIndex(inst_resolved.file); |
| 1374 | | // TODO: stop the compiler ever reaching Sema if there are failed files. That way, this check is |
| 1375 | | // unnecessary, and we can move the below `removeDependenciesForDepender` call up with its friends |
| 1376 | | // in `ensureComptimeUnitUpToDate`. |
| 1377 | | if (file.status != .success_zir) return error.AnalysisFail; |
| 1378 | 1341 | const zir = file.zir.?; |
| 1379 | 1342 | |
| 1380 | | // We are about to re-analyze this unit; drop its depenndencies. |
| 1381 | | zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit); |
| 1382 | | |
| 1383 | 1343 | try zcu.analysis_in_progress.put(gpa, anal_unit, {}); |
| 1384 | 1344 | defer _ = zcu.analysis_in_progress.swapRemove(anal_unit); |
| 1385 | 1345 | |
| ... | ... | @@ -1828,7 +1788,6 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator. |
| 1828 | 1788 | const zcu = pt.zcu; |
| 1829 | 1789 | |
| 1830 | 1790 | const file = zcu.fileByIndex(file_index); |
| 1831 | | assert(file.status == .success_zir); |
| 1832 | 1791 | const file_root_type = zcu.fileRootType(file_index); |
| 1833 | 1792 | if (file_root_type == .none) return; |
| 1834 | 1793 | |
| ... | ... | @@ -1865,9 +1824,6 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 1865 | 1824 | assert(file.getMode() == .zig); |
| 1866 | 1825 | assert(zcu.fileRootType(file_index) == .none); |
| 1867 | 1826 | |
| 1868 | | if (file.status != .success_zir) { |
| 1869 | | return error.AnalysisFail; |
| 1870 | | } |
| 1871 | 1827 | assert(file.zir != null); |
| 1872 | 1828 | |
| 1873 | 1829 | const new_namespace_index = try pt.createNamespace(.{ |
| ... | ... | @@ -1910,7 +1866,7 @@ fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void { |
| 1910 | 1866 | } |
| 1911 | 1867 | } |
| 1912 | 1868 | |
| 1913 | | pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult { |
| 1869 | pub fn importPkg(pt: Zcu.PerThread, mod: *Module) Allocator.Error!Zcu.ImportFileResult { |
| 1914 | 1870 | const zcu = pt.zcu; |
| 1915 | 1871 | const gpa = zcu.gpa; |
| 1916 | 1872 | |
| ... | ... | @@ -1984,7 +1940,6 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult { |
| 1984 | 1940 | .zir = null, |
| 1985 | 1941 | .zoir = null, |
| 1986 | 1942 | .status = .never_loaded, |
| 1987 | | .prev_status = .never_loaded, |
| 1988 | 1943 | .mod = mod, |
| 1989 | 1944 | }; |
| 1990 | 1945 | |
| ... | ... | @@ -1997,13 +1952,19 @@ pub fn importPkg(pt: Zcu.PerThread, mod: *Module) !Zcu.ImportFileResult { |
| 1997 | 1952 | }; |
| 1998 | 1953 | } |
| 1999 | 1954 | |
| 2000 | | /// Called from a worker thread during AstGen. |
| 1955 | /// Called from a worker thread during AstGen (with the Compilation mutex held). |
| 2001 | 1956 | /// Also called from Sema during semantic analysis. |
| 1957 | /// Does not attempt to load the file from disk; just returns a corresponding `*Zcu.File`. |
| 2002 | 1958 | pub fn importFile( |
| 2003 | 1959 | pt: Zcu.PerThread, |
| 2004 | 1960 | cur_file: *Zcu.File, |
| 2005 | 1961 | import_string: []const u8, |
| 2006 | | ) !Zcu.ImportFileResult { |
| 1962 | ) error{ |
| 1963 | OutOfMemory, |
| 1964 | ModuleNotFound, |
| 1965 | ImportOutsideModulePath, |
| 1966 | CurrentWorkingDirectoryUnlinked, |
| 1967 | }!Zcu.ImportFileResult { |
| 2007 | 1968 | const zcu = pt.zcu; |
| 2008 | 1969 | const mod = cur_file.mod; |
| 2009 | 1970 | |
| ... | ... | @@ -2061,7 +2022,10 @@ pub fn importFile( |
| 2061 | 2022 | defer gpa.free(resolved_root_path); |
| 2062 | 2023 | |
| 2063 | 2024 | const sub_file_path = p: { |
| 2064 | | const relative = try std.fs.path.relative(gpa, resolved_root_path, resolved_path); |
| 2025 | const relative = std.fs.path.relative(gpa, resolved_root_path, resolved_path) catch |err| switch (err) { |
| 2026 | error.Unexpected => unreachable, |
| 2027 | else => |e| return e, |
| 2028 | }; |
| 2065 | 2029 | errdefer gpa.free(relative); |
| 2066 | 2030 | |
| 2067 | 2031 | if (!isUpDir(relative) and !std.fs.path.isAbsolute(relative)) { |
| ... | ... | @@ -2089,13 +2053,15 @@ pub fn importFile( |
| 2089 | 2053 | gop.value_ptr.* = new_file_index; |
| 2090 | 2054 | new_file.* = .{ |
| 2091 | 2055 | .sub_file_path = sub_file_path, |
| 2056 | |
| 2057 | .status = .never_loaded, |
| 2092 | 2058 | .stat = undefined, |
| 2059 | |
| 2093 | 2060 | .source = null, |
| 2094 | 2061 | .tree = null, |
| 2095 | 2062 | .zir = null, |
| 2096 | 2063 | .zoir = null, |
| 2097 | | .status = .never_loaded, |
| 2098 | | .prev_status = .never_loaded, |
| 2064 | |
| 2099 | 2065 | .mod = mod, |
| 2100 | 2066 | }; |
| 2101 | 2067 | |
| ... | ... | @@ -2835,7 +2801,7 @@ pub fn getErrorValueFromSlice(pt: Zcu.PerThread, name: []const u8) Allocator.Err |
| 2835 | 2801 | /// `file.zir` must be unchanged from the last update, as it is used to determine if there is such an entry. |
| 2836 | 2802 | fn lockAndClearFileCompileError(pt: Zcu.PerThread, file: *Zcu.File) void { |
| 2837 | 2803 | const zir = file.zir orelse return; |
| 2838 | | if (zir.hasCompileErrors()) return; |
| 2804 | if (!zir.hasCompileErrors()) return; |
| 2839 | 2805 | |
| 2840 | 2806 | pt.zcu.comp.mutex.lock(); |
| 2841 | 2807 | defer pt.zcu.comp.mutex.unlock(); |
| ... | ... | @@ -3196,6 +3162,7 @@ pub fn linkerUpdateLineNumber(pt: Zcu.PerThread, ti: InternPool.TrackedInst.Inde |
| 3196 | 3162 | } |
| 3197 | 3163 | } |
| 3198 | 3164 | |
| 3165 | /// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`. |
| 3199 | 3166 | pub fn reportRetryableAstGenError( |
| 3200 | 3167 | pt: Zcu.PerThread, |
| 3201 | 3168 | src: Zcu.AstGenSrc, |
| ... | ... | @@ -3231,13 +3198,18 @@ pub fn reportRetryableAstGenError( |
| 3231 | 3198 | }); |
| 3232 | 3199 | errdefer err_msg.destroy(gpa); |
| 3233 | 3200 | |
| 3234 | | { |
| 3235 | | zcu.comp.mutex.lock(); |
| 3236 | | defer zcu.comp.mutex.unlock(); |
| 3237 | | try zcu.failed_files.putNoClobber(gpa, file, err_msg); |
| 3201 | zcu.comp.mutex.lock(); |
| 3202 | defer zcu.comp.mutex.unlock(); |
| 3203 | const gop = try zcu.failed_files.getOrPut(gpa, file); |
| 3204 | if (gop.found_existing) { |
| 3205 | if (gop.value_ptr.*) |old_err_msg| { |
| 3206 | old_err_msg.destroy(gpa); |
| 3207 | } |
| 3238 | 3208 | } |
| 3209 | gop.value_ptr.* = err_msg; |
| 3239 | 3210 | } |
| 3240 | 3211 | |
| 3212 | /// Sets `File.status` of `file_index` to `retryable_failure`, and stores an error in `pt.zcu.failed_files`. |
| 3241 | 3213 | pub fn reportRetryableFileError( |
| 3242 | 3214 | pt: Zcu.PerThread, |
| 3243 | 3215 | file_index: Zcu.File.Index, |
| ... | ... | @@ -3771,7 +3743,6 @@ fn recreateStructType( |
| 3771 | 3743 | |
| 3772 | 3744 | const inst_info = key.zir_index.resolveFull(ip).?; |
| 3773 | 3745 | const file = zcu.fileByIndex(inst_info.file); |
| 3774 | | assert(file.status == .success_zir); // otherwise inst tracking failed |
| 3775 | 3746 | const zir = file.zir.?; |
| 3776 | 3747 | |
| 3777 | 3748 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); |
| ... | ... | @@ -3844,7 +3815,6 @@ fn recreateUnionType( |
| 3844 | 3815 | |
| 3845 | 3816 | const inst_info = key.zir_index.resolveFull(ip).?; |
| 3846 | 3817 | const file = zcu.fileByIndex(inst_info.file); |
| 3847 | | assert(file.status == .success_zir); // otherwise inst tracking failed |
| 3848 | 3818 | const zir = file.zir.?; |
| 3849 | 3819 | |
| 3850 | 3820 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); |
| ... | ... | @@ -3931,7 +3901,6 @@ fn recreateEnumType( |
| 3931 | 3901 | |
| 3932 | 3902 | const inst_info = key.zir_index.resolveFull(ip).?; |
| 3933 | 3903 | const file = zcu.fileByIndex(inst_info.file); |
| 3934 | | assert(file.status == .success_zir); // otherwise inst tracking failed |
| 3935 | 3904 | const zir = file.zir.?; |
| 3936 | 3905 | |
| 3937 | 3906 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); |
| ... | ... | @@ -4075,7 +4044,6 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace |
| 4075 | 4044 | |
| 4076 | 4045 | const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail; |
| 4077 | 4046 | const file = zcu.fileByIndex(inst_info.file); |
| 4078 | | if (file.status != .success_zir) return error.AnalysisFail; |
| 4079 | 4047 | const zir = file.zir.?; |
| 4080 | 4048 | |
| 4081 | 4049 | assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended); |