| ... | ... | @@ -2773,6 +2773,111 @@ fn emitOthers(comp: *Compilation) void { |
| 2773 | 2773 | } |
| 2774 | 2774 | } |
| 2775 | 2775 | |
| 2776 | fn reportMultiModuleErrors(mod: *Module) !void { |
| 2777 | // Some cases can give you a whole bunch of multi-module errors, which it's not helpful to |
| 2778 | // print all of, so we'll cap the number of these to emit. |
| 2779 | var num_errors: u32 = 0; |
| 2780 | const max_errors = 5; |
| 2781 | // Attach the "some omitted" note to the final error message |
| 2782 | var last_err: ?*Module.ErrorMsg = null; |
| 2783 | |
| 2784 | for (mod.import_table.values()) |file| { |
| 2785 | if (!file.multi_pkg) continue; |
| 2786 | |
| 2787 | num_errors += 1; |
| 2788 | if (num_errors > max_errors) continue; |
| 2789 | |
| 2790 | const err = err_blk: { |
| 2791 | // Like with errors, let's cap the number of notes to prevent a huge error spew. |
| 2792 | const max_notes = 5; |
| 2793 | const omitted = file.references.items.len -| max_notes; |
| 2794 | const num_notes = file.references.items.len - omitted; |
| 2795 | |
| 2796 | const notes = try mod.gpa.alloc(Module.ErrorMsg, if (omitted > 0) num_notes + 1 else num_notes); |
| 2797 | errdefer mod.gpa.free(notes); |
| 2798 | |
| 2799 | for (notes[0..num_notes], file.references.items[0..num_notes], 0..) |*note, ref, i| { |
| 2800 | errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa); |
| 2801 | note.* = switch (ref) { |
| 2802 | .import => |loc| blk: { |
| 2803 | const name = try loc.file_scope.pkg.getName(mod.gpa, mod.*); |
| 2804 | defer mod.gpa.free(name); |
| 2805 | break :blk try Module.ErrorMsg.init( |
| 2806 | mod.gpa, |
| 2807 | loc, |
| 2808 | "imported from module {s}", |
| 2809 | .{name}, |
| 2810 | ); |
| 2811 | }, |
| 2812 | .root => |pkg| blk: { |
| 2813 | const name = try pkg.getName(mod.gpa, mod.*); |
| 2814 | defer mod.gpa.free(name); |
| 2815 | break :blk try Module.ErrorMsg.init( |
| 2816 | mod.gpa, |
| 2817 | .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file }, |
| 2818 | "root of module {s}", |
| 2819 | .{name}, |
| 2820 | ); |
| 2821 | }, |
| 2822 | }; |
| 2823 | } |
| 2824 | errdefer for (notes[0..num_notes]) |*n| n.deinit(mod.gpa); |
| 2825 | |
| 2826 | if (omitted > 0) { |
| 2827 | notes[num_notes] = try Module.ErrorMsg.init( |
| 2828 | mod.gpa, |
| 2829 | .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file }, |
| 2830 | "{} more references omitted", |
| 2831 | .{omitted}, |
| 2832 | ); |
| 2833 | } |
| 2834 | errdefer if (omitted > 0) notes[num_notes].deinit(mod.gpa); |
| 2835 | |
| 2836 | const err = try Module.ErrorMsg.create( |
| 2837 | mod.gpa, |
| 2838 | .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file }, |
| 2839 | "file exists in multiple modules", |
| 2840 | .{}, |
| 2841 | ); |
| 2842 | err.notes = notes; |
| 2843 | break :err_blk err; |
| 2844 | }; |
| 2845 | errdefer err.destroy(mod.gpa); |
| 2846 | try mod.failed_files.putNoClobber(mod.gpa, file, err); |
| 2847 | last_err = err; |
| 2848 | } |
| 2849 | |
| 2850 | // If we omitted any errors, add a note saying that |
| 2851 | if (num_errors > max_errors) { |
| 2852 | const err = last_err.?; |
| 2853 | |
| 2854 | // There isn't really any meaningful place to put this note, so just attach it to the |
| 2855 | // last failed file |
| 2856 | var note = try Module.ErrorMsg.init( |
| 2857 | mod.gpa, |
| 2858 | err.src_loc, |
| 2859 | "{} more errors omitted", |
| 2860 | .{num_errors - max_errors}, |
| 2861 | ); |
| 2862 | errdefer note.deinit(mod.gpa); |
| 2863 | |
| 2864 | const i = err.notes.len; |
| 2865 | err.notes = try mod.gpa.realloc(err.notes, i + 1); |
| 2866 | err.notes[i] = note; |
| 2867 | } |
| 2868 | |
| 2869 | // Now that we've reported the errors, we need to deal with |
| 2870 | // dependencies. Any file referenced by a multi_pkg file should also be |
| 2871 | // marked multi_pkg and have its status set to astgen_failure, as it's |
| 2872 | // ambiguous which package they should be analyzed as a part of. We need |
| 2873 | // to add this flag after reporting the errors however, as otherwise |
| 2874 | // we'd get an error for every single downstream file, which wouldn't be |
| 2875 | // very useful. |
| 2876 | for (mod.import_table.values()) |file| { |
| 2877 | if (file.multi_pkg) file.recursiveMarkMultiPkg(mod); |
| 2878 | } |
| 2879 | } |
| 2880 | |
| 2776 | 2881 | /// Having the file open for writing is problematic as far as executing the |
| 2777 | 2882 | /// binary is concerned. This will remove the write flag, or close the file, |
| 2778 | 2883 | /// or whatever is needed so that it can be executed. |
| ... | ... | @@ -3099,62 +3204,7 @@ pub fn performAllTheWork( |
| 3099 | 3204 | } |
| 3100 | 3205 | |
| 3101 | 3206 | if (comp.bin_file.options.module) |mod| { |
| 3102 | | for (mod.import_table.values()) |file| { |
| 3103 | | if (!file.multi_pkg) continue; |
| 3104 | | const err = err_blk: { |
| 3105 | | const notes = try mod.gpa.alloc(Module.ErrorMsg, file.references.items.len); |
| 3106 | | errdefer mod.gpa.free(notes); |
| 3107 | | |
| 3108 | | for (notes, 0..) |*note, i| { |
| 3109 | | errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa); |
| 3110 | | note.* = switch (file.references.items[i]) { |
| 3111 | | .import => |loc| blk: { |
| 3112 | | const name = try loc.file_scope.pkg.getName(mod.gpa, mod.*); |
| 3113 | | defer mod.gpa.free(name); |
| 3114 | | break :blk try Module.ErrorMsg.init( |
| 3115 | | mod.gpa, |
| 3116 | | loc, |
| 3117 | | "imported from package {s}", |
| 3118 | | .{name}, |
| 3119 | | ); |
| 3120 | | }, |
| 3121 | | .root => |pkg| blk: { |
| 3122 | | const name = try pkg.getName(mod.gpa, mod.*); |
| 3123 | | defer mod.gpa.free(name); |
| 3124 | | break :blk try Module.ErrorMsg.init( |
| 3125 | | mod.gpa, |
| 3126 | | .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file }, |
| 3127 | | "root of package {s}", |
| 3128 | | .{name}, |
| 3129 | | ); |
| 3130 | | }, |
| 3131 | | }; |
| 3132 | | } |
| 3133 | | errdefer for (notes) |*n| n.deinit(mod.gpa); |
| 3134 | | |
| 3135 | | const err = try Module.ErrorMsg.create( |
| 3136 | | mod.gpa, |
| 3137 | | .{ .file_scope = file, .parent_decl_node = 0, .lazy = .entire_file }, |
| 3138 | | "file exists in multiple packages", |
| 3139 | | .{}, |
| 3140 | | ); |
| 3141 | | err.notes = notes; |
| 3142 | | break :err_blk err; |
| 3143 | | }; |
| 3144 | | errdefer err.destroy(mod.gpa); |
| 3145 | | try mod.failed_files.putNoClobber(mod.gpa, file, err); |
| 3146 | | } |
| 3147 | | |
| 3148 | | // Now that we've reported the errors, we need to deal with |
| 3149 | | // dependencies. Any file referenced by a multi_pkg file should also be |
| 3150 | | // marked multi_pkg and have its status set to astgen_failure, as it's |
| 3151 | | // ambiguous which package they should be analyzed as a part of. We need |
| 3152 | | // to add this flag after reporting the errors however, as otherwise |
| 3153 | | // we'd get an error for every single downstream file, which wouldn't be |
| 3154 | | // very useful. |
| 3155 | | for (mod.import_table.values()) |file| { |
| 3156 | | if (file.multi_pkg) file.recursiveMarkMultiPkg(mod); |
| 3157 | | } |
| 3207 | try reportMultiModuleErrors(mod); |
| 3158 | 3208 | } |
| 3159 | 3209 | |
| 3160 | 3210 | { |