| ... | ... | @@ -1463,11 +1463,7 @@ pub const File = struct { |
| 1463 | 1463 | /// Whether this is populated depends on `source_loaded`. |
| 1464 | 1464 | source: [:0]const u8, |
| 1465 | 1465 | /// Whether this is populated depends on `status`. |
| 1466 | | stat_size: u64, |
| 1467 | | /// Whether this is populated depends on `status`. |
| 1468 | | stat_inode: std.fs.File.INode, |
| 1469 | | /// Whether this is populated depends on `status`. |
| 1470 | | stat_mtime: i128, |
| 1466 | stat: Cache.File.Stat, |
| 1471 | 1467 | /// Whether this is populated or not depends on `tree_loaded`. |
| 1472 | 1468 | tree: Ast, |
| 1473 | 1469 | /// Whether this is populated or not depends on `zir_loaded`. |
| ... | ... | @@ -1535,8 +1531,16 @@ pub const File = struct { |
| 1535 | 1531 | file.* = undefined; |
| 1536 | 1532 | } |
| 1537 | 1533 | |
| 1538 | | pub fn getSource(file: *File, gpa: Allocator) ![:0]const u8 { |
| 1539 | | if (file.source_loaded) return file.source; |
| 1534 | pub const Source = struct { |
| 1535 | bytes: [:0]const u8, |
| 1536 | stat: Cache.File.Stat, |
| 1537 | }; |
| 1538 | |
| 1539 | pub fn getSource(file: *File, gpa: Allocator) !Source { |
| 1540 | if (file.source_loaded) return Source{ |
| 1541 | .bytes = file.source, |
| 1542 | .stat = file.stat, |
| 1543 | }; |
| 1540 | 1544 | |
| 1541 | 1545 | const root_dir_path = file.pkg.root_src_directory.path orelse "."; |
| 1542 | 1546 | log.debug("File.getSource, not cached. pkgdir={s} sub_file_path={s}", .{ |
| ... | ... | @@ -1565,14 +1569,21 @@ pub const File = struct { |
| 1565 | 1569 | |
| 1566 | 1570 | file.source = source; |
| 1567 | 1571 | file.source_loaded = true; |
| 1568 | | return source; |
| 1572 | return Source{ |
| 1573 | .bytes = source, |
| 1574 | .stat = .{ |
| 1575 | .size = stat.size, |
| 1576 | .inode = stat.inode, |
| 1577 | .mtime = stat.mtime, |
| 1578 | }, |
| 1579 | }; |
| 1569 | 1580 | } |
| 1570 | 1581 | |
| 1571 | 1582 | pub fn getTree(file: *File, gpa: Allocator) !*const Ast { |
| 1572 | 1583 | if (file.tree_loaded) return &file.tree; |
| 1573 | 1584 | |
| 1574 | 1585 | const source = try file.getSource(gpa); |
| 1575 | | file.tree = try std.zig.parse(gpa, source); |
| 1586 | file.tree = try std.zig.parse(gpa, source.bytes); |
| 1576 | 1587 | file.tree_loaded = true; |
| 1577 | 1588 | return &file.tree; |
| 1578 | 1589 | } |
| ... | ... | @@ -1631,9 +1642,7 @@ pub const EmbedFile = struct { |
| 1631 | 1642 | /// Memory is stored in gpa, owned by EmbedFile. |
| 1632 | 1643 | sub_file_path: []const u8, |
| 1633 | 1644 | bytes: [:0]const u8, |
| 1634 | | stat_size: u64, |
| 1635 | | stat_inode: std.fs.File.INode, |
| 1636 | | stat_mtime: i128, |
| 1645 | stat: Cache.File.Stat, |
| 1637 | 1646 | /// Package that this file is a part of, managed externally. |
| 1638 | 1647 | pkg: *Package, |
| 1639 | 1648 | /// The Decl that was created from the `@embedFile` to own this resource. |
| ... | ... | @@ -2704,9 +2713,11 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 2704 | 2713 | keep_zir = true; |
| 2705 | 2714 | file.zir = zir; |
| 2706 | 2715 | file.zir_loaded = true; |
| 2707 | | file.stat_size = header.stat_size; |
| 2708 | | file.stat_inode = header.stat_inode; |
| 2709 | | file.stat_mtime = header.stat_mtime; |
| 2716 | file.stat = .{ |
| 2717 | .size = header.stat_size, |
| 2718 | .inode = header.stat_inode, |
| 2719 | .mtime = header.stat_mtime, |
| 2720 | }; |
| 2710 | 2721 | file.status = .success_zir; |
| 2711 | 2722 | log.debug("AstGen cached success: {s}", .{file.sub_file_path}); |
| 2712 | 2723 | |
| ... | ... | @@ -2724,9 +2735,9 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 2724 | 2735 | }, |
| 2725 | 2736 | .parse_failure, .astgen_failure, .success_zir => { |
| 2726 | 2737 | const unchanged_metadata = |
| 2727 | | stat.size == file.stat_size and |
| 2728 | | stat.mtime == file.stat_mtime and |
| 2729 | | stat.inode == file.stat_inode; |
| 2738 | stat.size == file.stat.size and |
| 2739 | stat.mtime == file.stat.mtime and |
| 2740 | stat.inode == file.stat.inode; |
| 2730 | 2741 | |
| 2731 | 2742 | if (unchanged_metadata) { |
| 2732 | 2743 | log.debug("unmodified metadata of file: {s}", .{file.sub_file_path}); |
| ... | ... | @@ -2787,9 +2798,11 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 2787 | 2798 | if (amt != stat.size) |
| 2788 | 2799 | return error.UnexpectedEndOfFile; |
| 2789 | 2800 | |
| 2790 | | file.stat_size = stat.size; |
| 2791 | | file.stat_inode = stat.inode; |
| 2792 | | file.stat_mtime = stat.mtime; |
| 2801 | file.stat = .{ |
| 2802 | .size = stat.size, |
| 2803 | .inode = stat.inode, |
| 2804 | .mtime = stat.mtime, |
| 2805 | }; |
| 2793 | 2806 | file.source = source; |
| 2794 | 2807 | file.source_loaded = true; |
| 2795 | 2808 | |
| ... | ... | @@ -3069,9 +3082,11 @@ pub fn populateBuiltinFile(mod: *Module) !void { |
| 3069 | 3082 | |
| 3070 | 3083 | try writeBuiltinFile(file, builtin_pkg); |
| 3071 | 3084 | } else { |
| 3072 | | file.stat_size = stat.size; |
| 3073 | | file.stat_inode = stat.inode; |
| 3074 | | file.stat_mtime = stat.mtime; |
| 3085 | file.stat = .{ |
| 3086 | .size = stat.size, |
| 3087 | .inode = stat.inode, |
| 3088 | .mtime = stat.mtime, |
| 3089 | }; |
| 3075 | 3090 | } |
| 3076 | 3091 | } else |err| switch (err) { |
| 3077 | 3092 | error.BadPathName => unreachable, // it's always "builtin.zig" |
| ... | ... | @@ -3099,9 +3114,11 @@ pub fn writeBuiltinFile(file: *File, builtin_pkg: *Package) !void { |
| 3099 | 3114 | try af.file.writeAll(file.source); |
| 3100 | 3115 | try af.finish(); |
| 3101 | 3116 | |
| 3102 | | file.stat_size = file.source.len; |
| 3103 | | file.stat_inode = 0; // dummy value |
| 3104 | | file.stat_mtime = 0; // dummy value |
| 3117 | file.stat = .{ |
| 3118 | .size = file.source.len, |
| 3119 | .inode = 0, // dummy value |
| 3120 | .mtime = 0, // dummy value |
| 3121 | }; |
| 3105 | 3122 | } |
| 3106 | 3123 | |
| 3107 | 3124 | pub fn mapOldZirToNew( |
| ... | ... | @@ -3382,16 +3399,16 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3382 | 3399 | } |
| 3383 | 3400 | |
| 3384 | 3401 | if (mod.comp.whole_cache_manifest) |man| { |
| 3385 | | assert(file.source_loaded); |
| 3402 | const source = file.getSource(gpa) catch |err| { |
| 3403 | try reportRetryableFileError(mod, file, "unable to load source: {s}", .{@errorName(err)}); |
| 3404 | return error.AnalysisFail; |
| 3405 | }; |
| 3386 | 3406 | const resolved_path = try file.pkg.root_src_directory.join(gpa, &.{ |
| 3387 | 3407 | file.sub_file_path, |
| 3388 | 3408 | }); |
| 3389 | 3409 | errdefer gpa.free(resolved_path); |
| 3390 | | try man.addFilePostContents(resolved_path, file.source, .{ |
| 3391 | | .size = file.stat_size, |
| 3392 | | .inode = file.stat_inode, |
| 3393 | | .mtime = file.stat_mtime, |
| 3394 | | }); |
| 3410 | |
| 3411 | try man.addFilePostContents(resolved_path, source.bytes, source.stat); |
| 3395 | 3412 | } |
| 3396 | 3413 | } else { |
| 3397 | 3414 | new_decl.analysis = .file_failure; |
| ... | ... | @@ -3723,9 +3740,7 @@ pub fn importPkg(mod: *Module, pkg: *Package) !ImportFileResult { |
| 3723 | 3740 | .source_loaded = false, |
| 3724 | 3741 | .tree_loaded = false, |
| 3725 | 3742 | .zir_loaded = false, |
| 3726 | | .stat_size = undefined, |
| 3727 | | .stat_inode = undefined, |
| 3728 | | .stat_mtime = undefined, |
| 3743 | .stat = undefined, |
| 3729 | 3744 | .tree = undefined, |
| 3730 | 3745 | .zir = undefined, |
| 3731 | 3746 | .status = .never_loaded, |
| ... | ... | @@ -3793,9 +3808,7 @@ pub fn importFile( |
| 3793 | 3808 | .source_loaded = false, |
| 3794 | 3809 | .tree_loaded = false, |
| 3795 | 3810 | .zir_loaded = false, |
| 3796 | | .stat_size = undefined, |
| 3797 | | .stat_inode = undefined, |
| 3798 | | .stat_mtime = undefined, |
| 3811 | .stat = undefined, |
| 3799 | 3812 | .tree = undefined, |
| 3800 | 3813 | .zir = undefined, |
| 3801 | 3814 | .status = .never_loaded, |
| ... | ... | @@ -3840,8 +3853,13 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb |
| 3840 | 3853 | var file = try cur_file.pkg.root_src_directory.handle.openFile(sub_file_path, .{}); |
| 3841 | 3854 | defer file.close(); |
| 3842 | 3855 | |
| 3843 | | const stat = try file.stat(); |
| 3844 | | const size_usize = try std.math.cast(usize, stat.size); |
| 3856 | const actual_stat = try file.stat(); |
| 3857 | const stat: Cache.File.Stat = .{ |
| 3858 | .size = actual_stat.size, |
| 3859 | .inode = actual_stat.inode, |
| 3860 | .mtime = actual_stat.mtime, |
| 3861 | }; |
| 3862 | const size_usize = try std.math.cast(usize, actual_stat.size); |
| 3845 | 3863 | const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0); |
| 3846 | 3864 | errdefer gpa.free(bytes); |
| 3847 | 3865 | |
| ... | ... | @@ -3852,11 +3870,7 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb |
| 3852 | 3870 | if (mod.comp.whole_cache_manifest) |man| { |
| 3853 | 3871 | const copied_resolved_path = try gpa.dupe(u8, resolved_path); |
| 3854 | 3872 | errdefer gpa.free(copied_resolved_path); |
| 3855 | | try man.addFilePostContents(copied_resolved_path, bytes, .{ |
| 3856 | | .size = stat.size, |
| 3857 | | .inode = stat.inode, |
| 3858 | | .mtime = stat.mtime, |
| 3859 | | }); |
| 3873 | try man.addFilePostContents(copied_resolved_path, bytes, stat); |
| 3860 | 3874 | } |
| 3861 | 3875 | |
| 3862 | 3876 | keep_resolved_path = true; // It's now owned by embed_table. |
| ... | ... | @@ -3864,9 +3878,7 @@ pub fn embedFile(mod: *Module, cur_file: *File, rel_file_path: []const u8) !*Emb |
| 3864 | 3878 | new_file.* = .{ |
| 3865 | 3879 | .sub_file_path = sub_file_path, |
| 3866 | 3880 | .bytes = bytes, |
| 3867 | | .stat_size = stat.size, |
| 3868 | | .stat_inode = stat.inode, |
| 3869 | | .stat_mtime = stat.mtime, |
| 3881 | .stat = stat, |
| 3870 | 3882 | .pkg = cur_file.pkg, |
| 3871 | 3883 | .owner_decl = undefined, // Set by Sema immediately after this function returns. |
| 3872 | 3884 | }; |
| ... | ... | @@ -3880,9 +3892,9 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { |
| 3880 | 3892 | const stat = try file.stat(); |
| 3881 | 3893 | |
| 3882 | 3894 | const unchanged_metadata = |
| 3883 | | stat.size == embed_file.stat_size and |
| 3884 | | stat.mtime == embed_file.stat_mtime and |
| 3885 | | stat.inode == embed_file.stat_inode; |
| 3895 | stat.size == embed_file.stat.size and |
| 3896 | stat.mtime == embed_file.stat.mtime and |
| 3897 | stat.inode == embed_file.stat.inode; |
| 3886 | 3898 | |
| 3887 | 3899 | if (unchanged_metadata) return; |
| 3888 | 3900 | |
| ... | ... | @@ -3891,9 +3903,11 @@ pub fn detectEmbedFileUpdate(mod: *Module, embed_file: *EmbedFile) !void { |
| 3891 | 3903 | const bytes = try file.readToEndAllocOptions(gpa, std.math.maxInt(u32), size_usize, 1, 0); |
| 3892 | 3904 | gpa.free(embed_file.bytes); |
| 3893 | 3905 | embed_file.bytes = bytes; |
| 3894 | | embed_file.stat_size = stat.size; |
| 3895 | | embed_file.stat_mtime = stat.mtime; |
| 3896 | | embed_file.stat_inode = stat.inode; |
| 3906 | embed_file.stat = .{ |
| 3907 | .size = stat.size, |
| 3908 | .mtime = stat.mtime, |
| 3909 | .inode = stat.inode, |
| 3910 | }; |
| 3897 | 3911 | |
| 3898 | 3912 | mod.comp.mutex.lock(); |
| 3899 | 3913 | defer mod.comp.mutex.unlock(); |
| ... | ... | @@ -5024,3 +5038,35 @@ pub fn linkerUpdateDecl(mod: *Module, decl: *Decl) !void { |
| 5024 | 5038 | }, |
| 5025 | 5039 | }; |
| 5026 | 5040 | } |
| 5041 | |
| 5042 | fn reportRetryableFileError( |
| 5043 | mod: *Module, |
| 5044 | file: *File, |
| 5045 | comptime format: []const u8, |
| 5046 | args: anytype, |
| 5047 | ) error{OutOfMemory}!void { |
| 5048 | file.status = .retryable_failure; |
| 5049 | |
| 5050 | const err_msg = try ErrorMsg.create( |
| 5051 | mod.gpa, |
| 5052 | .{ |
| 5053 | .file_scope = file, |
| 5054 | .parent_decl_node = 0, |
| 5055 | .lazy = .entire_file, |
| 5056 | }, |
| 5057 | format, |
| 5058 | args, |
| 5059 | ); |
| 5060 | errdefer err_msg.destroy(mod.gpa); |
| 5061 | |
| 5062 | mod.comp.mutex.lock(); |
| 5063 | defer mod.comp.mutex.unlock(); |
| 5064 | |
| 5065 | const gop = try mod.failed_files.getOrPut(mod.gpa, file); |
| 5066 | if (gop.found_existing) { |
| 5067 | if (gop.value_ptr.*) |old_err_msg| { |
| 5068 | old_err_msg.destroy(mod.gpa); |
| 5069 | } |
| 5070 | } |
| 5071 | gop.value_ptr.* = err_msg; |
| 5072 | } |