| author | |
| committer | |
| log | 089bbd6588d82ccda0646e756006cf5787eadef2 |
| tree | e6db5043b11058300c2537b30bae4fb5ddd4ef81 |
| parent | 5f03c025058ddda09bfb3eac283bb88d30ad38cc |
| signature |
Previously, `reference_table` mapped from a `Decl` being referenced to
the `Decl` that performed the reference. This is convenient for
constructing error messages, but problematic for incremental
compilation. This is because on an incremental update, we want to
efficiently remove all references triggered by an `AnalUnit` which is
being re-analyzed.
For this reason, `reference_table` now maps the other way: from the
`AnalUnit` *performing* the reference, to the `AnalUnit` whose analysis
was triggered. As a general rule, any call to any of the following
functions should be preceded by a call to `Sema.addReferenceEntry`:
* `Zcu.ensureDeclAnalyzed`
* `Sema.ensureDeclAnalyzed`
* `Zcu.ensureFuncBodyAnalyzed`
* `Zcu.ensureFuncBodyAnalysisQueued`
This is not just important for error messages, but also more
fundamentally for incremental compilation. When an incremental update
occurs, we must determine whether any `AnalUnit` has become
unreferenced: in this case, we should ignore its associated error
messages, and perhaps even remove it from the binary. For this reason,
we no longer store only one reference to every `AnalUnit`, but every
reference. At the end of an update, `Zcu.resolveReferences` will
construct the reverse mapping, and as such identify which `AnalUnit`s
are still referenced. The current implementation doesn't quite do what
we need for incremental compilation here, but the framework is in place.
Note that `Zcu.resolveReferences` does constitute a non-trivial amount
of work on every incremental update. However, for incremental
compilation, this work -- which will effectively be a graph traversal
over all `AnalUnit` references -- seems strictly necessary. At the
moment, this work is only done if the `Zcu` has any errors, when
collecting them into the final `ErrorBundle`.
An unsolved problem here is how to represent inline function calls in
the reference trace. If `foo` performs an inline call to `bar` which
references `qux`, then ideally, `bar` would be shown on the reference
trace between `foo` and `qux`, but this is not currently the case. The
solution here is probably for `Zcu.Reference` to store information about
the source locations of active inline calls betweeen the referencer and
its reference.3 files changed, 231 insertions(+), 181 deletions(-)
src/Compilation.zig+59-37| ... | @@ -31,6 +31,7 @@ const clangMain = @import("main.zig").clangMain; | ... | @@ -31,6 +31,7 @@ const clangMain = @import("main.zig").clangMain; |
| 31 | const Zcu = @import("Zcu.zig"); | 31 | const Zcu = @import("Zcu.zig"); |
| 32 | /// Deprecated; use `Zcu`. | 32 | /// Deprecated; use `Zcu`. |
| 33 | const Module = Zcu; | 33 | const Module = Zcu; |
| 34 | const Sema = @import("Sema.zig"); | ||
| 34 | const InternPool = @import("InternPool.zig"); | 35 | const InternPool = @import("InternPool.zig"); |
| 35 | const Cache = std.Build.Cache; | 36 | const Cache = std.Build.Cache; |
| 36 | const c_codegen = @import("codegen/c.zig"); | 37 | const c_codegen = @import("codegen/c.zig"); |
| ... | @@ -2939,9 +2940,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -2939,9 +2940,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 2939 | }); | 2940 | }); |
| 2940 | } | 2941 | } |
| 2941 | if (comp.module) |zcu| { | 2942 | if (comp.module) |zcu| { |
| 2943 | var all_references = try zcu.resolveReferences(); | ||
| 2944 | defer all_references.deinit(gpa); | ||
| 2945 | |||
| 2942 | for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { | 2946 | for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| { |
| 2943 | if (error_msg) |msg| { | 2947 | if (error_msg) |msg| { |
| 2944 | try addModuleErrorMsg(zcu, &bundle, msg.*); | 2948 | try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references); |
| 2945 | } else { | 2949 | } else { |
| 2946 | // Must be ZIR errors. Note that this may include AST errors. | 2950 | // Must be ZIR errors. Note that this may include AST errors. |
| 2947 | // addZirErrorMessages asserts that the tree is loaded. | 2951 | // addZirErrorMessages asserts that the tree is loaded. |
| ... | @@ -2950,7 +2954,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -2950,7 +2954,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 2950 | } | 2954 | } |
| 2951 | } | 2955 | } |
| 2952 | for (zcu.failed_embed_files.values()) |error_msg| { | 2956 | for (zcu.failed_embed_files.values()) |error_msg| { |
| 2953 | try addModuleErrorMsg(zcu, &bundle, error_msg.*); | 2957 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); |
| 2954 | } | 2958 | } |
| 2955 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { | 2959 | for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| { |
| 2956 | const decl_index = switch (anal_unit.unwrap()) { | 2960 | const decl_index = switch (anal_unit.unwrap()) { |
| ... | @@ -2962,7 +2966,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -2962,7 +2966,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 2962 | // We'll try again once parsing succeeds. | 2966 | // We'll try again once parsing succeeds. |
| 2963 | if (!zcu.declFileScope(decl_index).okToReportErrors()) continue; | 2967 | if (!zcu.declFileScope(decl_index).okToReportErrors()) continue; |
| 2964 | 2968 | ||
| 2965 | try addModuleErrorMsg(zcu, &bundle, error_msg.*); | 2969 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); |
| 2966 | if (zcu.cimport_errors.get(anal_unit)) |errors| { | 2970 | if (zcu.cimport_errors.get(anal_unit)) |errors| { |
| 2967 | for (errors.getMessages()) |err_msg_index| { | 2971 | for (errors.getMessages()) |err_msg_index| { |
| 2968 | const err_msg = errors.getErrorMessage(err_msg_index); | 2972 | const err_msg = errors.getErrorMessage(err_msg_index); |
| ... | @@ -2989,12 +2993,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -2989,12 +2993,12 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 2989 | // Skip errors for Decls within files that had a parse failure. | 2993 | // Skip errors for Decls within files that had a parse failure. |
| 2990 | // We'll try again once parsing succeeds. | 2994 | // We'll try again once parsing succeeds. |
| 2991 | if (zcu.declFileScope(decl_index).okToReportErrors()) { | 2995 | if (zcu.declFileScope(decl_index).okToReportErrors()) { |
| 2992 | try addModuleErrorMsg(zcu, &bundle, error_msg.*); | 2996 | try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references); |
| 2993 | } | 2997 | } |
| 2994 | } | 2998 | } |
| 2995 | } | 2999 | } |
| 2996 | for (zcu.failed_exports.values()) |value| { | 3000 | for (zcu.failed_exports.values()) |value| { |
| 2997 | try addModuleErrorMsg(zcu, &bundle, value.*); | 3001 | try addModuleErrorMsg(zcu, &bundle, value.*, &all_references); |
| 2998 | } | 3002 | } |
| 2999 | 3003 | ||
| 3000 | const actual_error_count = zcu.global_error_set.entries.len - 1; | 3004 | const actual_error_count = zcu.global_error_set.entries.len - 1; |
| ... | @@ -3051,6 +3055,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3051,6 +3055,9 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3051 | 3055 | ||
| 3052 | if (comp.module) |zcu| { | 3056 | if (comp.module) |zcu| { |
| 3053 | if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) { | 3057 | if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) { |
| 3058 | var all_references = try zcu.resolveReferences(); | ||
| 3059 | defer all_references.deinit(gpa); | ||
| 3060 | |||
| 3054 | const values = zcu.compile_log_sources.values(); | 3061 | const values = zcu.compile_log_sources.values(); |
| 3055 | // First one will be the error; subsequent ones will be notes. | 3062 | // First one will be the error; subsequent ones will be notes. |
| 3056 | const src_loc = values[0].src().upgrade(zcu); | 3063 | const src_loc = values[0].src().upgrade(zcu); |
| ... | @@ -3068,7 +3075,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { | ... | @@ -3068,7 +3075,7 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle { |
| 3068 | }; | 3075 | }; |
| 3069 | } | 3076 | } |
| 3070 | 3077 | ||
| 3071 | try addModuleErrorMsg(zcu, &bundle, err_msg); | 3078 | try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references); |
| 3072 | } | 3079 | } |
| 3073 | } | 3080 | } |
| 3074 | 3081 | ||
| ... | @@ -3124,7 +3131,12 @@ pub const ErrorNoteHashContext = struct { | ... | @@ -3124,7 +3131,12 @@ pub const ErrorNoteHashContext = struct { |
| 3124 | } | 3131 | } |
| 3125 | }; | 3132 | }; |
| 3126 | 3133 | ||
| 3127 | pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void { | 3134 | pub fn addModuleErrorMsg( |
| 3135 | mod: *Module, | ||
| 3136 | eb: *ErrorBundle.Wip, | ||
| 3137 | module_err_msg: Module.ErrorMsg, | ||
| 3138 | all_references: *const std.AutoHashMapUnmanaged(InternPool.AnalUnit, Zcu.ResolvedReference), | ||
| 3139 | ) !void { | ||
| 3128 | const gpa = eb.gpa; | 3140 | const gpa = eb.gpa; |
| 3129 | const ip = &mod.intern_pool; | 3141 | const ip = &mod.intern_pool; |
| 3130 | const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| { | 3142 | const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| { |
| ... | @@ -3145,39 +3157,49 @@ pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Mod | ... | @@ -3145,39 +3157,49 @@ pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Mod |
| 3145 | var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .{}; | 3157 | var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .{}; |
| 3146 | defer ref_traces.deinit(gpa); | 3158 | defer ref_traces.deinit(gpa); |
| 3147 | 3159 | ||
| 3148 | const remaining_references: ?u32 = remaining: { | 3160 | if (module_err_msg.reference_trace_root.unwrap()) |rt_root| { |
| 3149 | if (mod.comp.reference_trace) |_| { | 3161 | var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .{}; |
| 3150 | if (module_err_msg.hidden_references > 0) break :remaining module_err_msg.hidden_references; | 3162 | defer seen.deinit(gpa); |
| 3151 | } else { | 3163 | |
| 3152 | if (module_err_msg.reference_trace.len > 0) break :remaining 0; | 3164 | const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len; |
| 3165 | |||
| 3166 | var referenced_by = rt_root; | ||
| 3167 | while (all_references.get(referenced_by)) |ref| { | ||
| 3168 | const gop = try seen.getOrPut(gpa, ref.referencer); | ||
| 3169 | if (gop.found_existing) break; | ||
| 3170 | if (ref_traces.items.len < max_references) { | ||
| 3171 | const src = ref.src.upgrade(mod); | ||
| 3172 | const source = try src.file_scope.getSource(gpa); | ||
| 3173 | const span = try src.span(gpa); | ||
| 3174 | const loc = std.zig.findLineColumn(source.bytes, span.main); | ||
| 3175 | const rt_file_path = try src.file_scope.fullPath(gpa); | ||
| 3176 | const name = switch (ref.referencer.unwrap()) { | ||
| 3177 | .decl => |d| mod.declPtr(d).name, | ||
| 3178 | .func => |f| mod.funcOwnerDeclPtr(f).name, | ||
| 3179 | }; | ||
| 3180 | try ref_traces.append(gpa, .{ | ||
| 3181 | .decl_name = try eb.addString(name.toSlice(ip)), | ||
| 3182 | .src_loc = try eb.addSourceLocation(.{ | ||
| 3183 | .src_path = try eb.addString(rt_file_path), | ||
| 3184 | .span_start = span.start, | ||
| 3185 | .span_main = span.main, | ||
| 3186 | .span_end = span.end, | ||
| 3187 | .line = @intCast(loc.line), | ||
| 3188 | .column = @intCast(loc.column), | ||
| 3189 | .source_line = 0, | ||
| 3190 | }), | ||
| 3191 | }); | ||
| 3192 | } | ||
| 3193 | referenced_by = ref.referencer; | ||
| 3153 | } | 3194 | } |
| 3154 | break :remaining null; | ||
| 3155 | }; | ||
| 3156 | try ref_traces.ensureTotalCapacityPrecise(gpa, module_err_msg.reference_trace.len + | ||
| 3157 | @intFromBool(remaining_references != null)); | ||
| 3158 | 3195 | ||
| 3159 | for (module_err_msg.reference_trace) |module_reference| { | 3196 | if (seen.count() > ref_traces.items.len) { |
| 3160 | const source = try module_reference.src_loc.file_scope.getSource(gpa); | 3197 | try ref_traces.append(gpa, .{ |
| 3161 | const span = try module_reference.src_loc.span(gpa); | 3198 | .decl_name = @intCast(seen.count() - ref_traces.items.len), |
| 3162 | const loc = std.zig.findLineColumn(source.bytes, span.main); | 3199 | .src_loc = .none, |
| 3163 | const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa); | 3200 | }); |
| 3164 | defer gpa.free(rt_file_path); | 3201 | } |
| 3165 | ref_traces.appendAssumeCapacity(.{ | ||
| 3166 | .decl_name = try eb.addString(module_reference.decl.toSlice(ip)), | ||
| 3167 | .src_loc = try eb.addSourceLocation(.{ | ||
| 3168 | .src_path = try eb.addString(rt_file_path), | ||
| 3169 | .span_start = span.start, | ||
| 3170 | .span_main = span.main, | ||
| 3171 | .span_end = span.end, | ||
| 3172 | .line = @intCast(loc.line), | ||
| 3173 | .column = @intCast(loc.column), | ||
| 3174 | .source_line = 0, | ||
| 3175 | }), | ||
| 3176 | }); | ||
| 3177 | } | 3202 | } |
| 3178 | if (remaining_references) |remaining| ref_traces.appendAssumeCapacity( | ||
| 3179 | .{ .decl_name = remaining, .src_loc = .none }, | ||
| 3180 | ); | ||
| 3181 | 3203 | ||
| 3182 | const src_loc = try eb.addSourceLocation(.{ | 3204 | const src_loc = try eb.addSourceLocation(.{ |
| 3183 | .src_path = try eb.addString(file_path), | 3205 | .src_path = try eb.addString(file_path), |
src/Sema.zig+72-95| ... | @@ -121,6 +121,11 @@ comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{}, | ... | @@ -121,6 +121,11 @@ comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{}, |
| 121 | /// these are flushed to `Zcu.single_exports` or `Zcu.multi_exports`. | 121 | /// these are flushed to `Zcu.single_exports` or `Zcu.multi_exports`. |
| 122 | exports: std.ArrayListUnmanaged(Zcu.Export) = .{}, | 122 | exports: std.ArrayListUnmanaged(Zcu.Export) = .{}, |
| 123 | 123 | ||
| 124 | /// All references registered so far by this `Sema`. This is a temporary duplicate | ||
| 125 | /// of data stored in `Zcu.all_references`. It exists to avoid adding references to | ||
| 126 | /// a given `AnalUnit` multiple times. | ||
| 127 | references: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{}, | ||
| 128 | |||
| 124 | const MaybeComptimeAlloc = struct { | 129 | const MaybeComptimeAlloc = struct { |
| 125 | /// The runtime index of the `alloc` instruction. | 130 | /// The runtime index of the `alloc` instruction. |
| 126 | runtime_index: Value.RuntimeIndex, | 131 | runtime_index: Value.RuntimeIndex, |
| ... | @@ -2472,87 +2477,57 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error | ... | @@ -2472,87 +2477,57 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error |
| 2472 | @setCold(true); | 2477 | @setCold(true); |
| 2473 | const gpa = sema.gpa; | 2478 | const gpa = sema.gpa; |
| 2474 | const mod = sema.mod; | 2479 | const mod = sema.mod; |
| 2480 | const ip = &mod.intern_pool; | ||
| 2475 | 2481 | ||
| 2476 | ref: { | 2482 | if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) { |
| 2477 | errdefer err_msg.destroy(gpa); | 2483 | var all_references = mod.resolveReferences() catch @panic("out of memory"); |
| 2484 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; | ||
| 2485 | wip_errors.init(gpa) catch @panic("out of memory"); | ||
| 2486 | Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*, &all_references) catch unreachable; | ||
| 2487 | std.debug.print("compile error during Sema:\n", .{}); | ||
| 2488 | var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; | ||
| 2489 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); | ||
| 2490 | crash_report.compilerPanic("unexpected compile error occurred", null, null); | ||
| 2491 | } | ||
| 2478 | 2492 | ||
| 2479 | if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) { | 2493 | if (block) |start_block| { |
| 2480 | var wip_errors: std.zig.ErrorBundle.Wip = undefined; | 2494 | var block_it = start_block; |
| 2481 | wip_errors.init(gpa) catch unreachable; | 2495 | while (block_it.inlining) |inlining| { |
| 2482 | Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*) catch unreachable; | 2496 | try sema.errNote( |
| 2483 | std.debug.print("compile error during Sema:\n", .{}); | 2497 | inlining.call_src, |
| 2484 | var error_bundle = wip_errors.toOwnedBundle("") catch unreachable; | 2498 | err_msg, |
| 2485 | error_bundle.renderToStdErr(.{ .ttyconf = .no_color }); | 2499 | "called from here", |
| 2486 | crash_report.compilerPanic("unexpected compile error occurred", null, null); | 2500 | .{}, |
| 2501 | ); | ||
| 2502 | block_it = inlining.call_block; | ||
| 2487 | } | 2503 | } |
| 2504 | } | ||
| 2488 | 2505 | ||
| 2489 | try mod.failed_analysis.ensureUnusedCapacity(gpa, 1); | 2506 | const use_ref_trace = if (mod.comp.reference_trace) |n| n > 0 else mod.failed_analysis.count() == 0; |
| 2490 | try mod.failed_files.ensureUnusedCapacity(gpa, 1); | 2507 | if (use_ref_trace) { |
| 2491 | 2508 | err_msg.reference_trace_root = sema.ownerUnit().toOptional(); | |
| 2492 | if (block) |start_block| { | 2509 | } |
| 2493 | var block_it = start_block; | ||
| 2494 | while (block_it.inlining) |inlining| { | ||
| 2495 | try sema.errNote( | ||
| 2496 | inlining.call_src, | ||
| 2497 | err_msg, | ||
| 2498 | "called from here", | ||
| 2499 | .{}, | ||
| 2500 | ); | ||
| 2501 | block_it = inlining.call_block; | ||
| 2502 | } | ||
| 2503 | |||
| 2504 | const max_references = refs: { | ||
| 2505 | if (mod.comp.reference_trace) |num| break :refs num; | ||
| 2506 | // Do not add multiple traces without explicit request. | ||
| 2507 | if (mod.failed_analysis.count() > 0) break :ref; | ||
| 2508 | break :refs default_reference_trace_len; | ||
| 2509 | }; | ||
| 2510 | 2510 | ||
| 2511 | var referenced_by = if (sema.owner_func_index != .none) | 2511 | const gop = try mod.failed_analysis.getOrPut(gpa, sema.ownerUnit()); |
| 2512 | mod.funcOwnerDeclIndex(sema.owner_func_index) | 2512 | if (gop.found_existing) { |
| 2513 | else | 2513 | // If there are multiple errors for the same Decl, prefer the first one added. |
| 2514 | sema.owner_decl_index; | 2514 | sema.err = null; |
| 2515 | var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(gpa); | 2515 | err_msg.destroy(gpa); |
| 2516 | defer reference_stack.deinit(); | 2516 | } else { |
| 2517 | 2517 | sema.err = err_msg; | |
| 2518 | // Avoid infinite loops. | 2518 | gop.value_ptr.* = err_msg; |
| 2519 | var seen = std.AutoHashMap(InternPool.DeclIndex, void).init(gpa); | ||
| 2520 | defer seen.deinit(); | ||
| 2521 | |||
| 2522 | while (mod.reference_table.get(referenced_by)) |ref| { | ||
| 2523 | const gop = try seen.getOrPut(ref.referencer); | ||
| 2524 | if (gop.found_existing) break; | ||
| 2525 | if (reference_stack.items.len < max_references) { | ||
| 2526 | const decl = mod.declPtr(ref.referencer); | ||
| 2527 | try reference_stack.append(.{ | ||
| 2528 | .decl = decl.name, | ||
| 2529 | .src_loc = ref.src.upgrade(mod), | ||
| 2530 | }); | ||
| 2531 | } | ||
| 2532 | referenced_by = ref.referencer; | ||
| 2533 | } | ||
| 2534 | err_msg.reference_trace = try reference_stack.toOwnedSlice(); | ||
| 2535 | err_msg.hidden_references = @intCast(seen.count() -| max_references); | ||
| 2536 | } | ||
| 2537 | } | 2519 | } |
| 2538 | const ip = &mod.intern_pool; | 2520 | |
| 2539 | if (sema.owner_func_index != .none) { | 2521 | if (sema.owner_func_index != .none) { |
| 2540 | ip.funcAnalysis(sema.owner_func_index).state = .sema_failure; | 2522 | ip.funcAnalysis(sema.owner_func_index).state = .sema_failure; |
| 2541 | } else { | 2523 | } else { |
| 2542 | sema.owner_decl.analysis = .sema_failure; | 2524 | sema.owner_decl.analysis = .sema_failure; |
| 2543 | } | 2525 | } |
| 2526 | |||
| 2544 | if (sema.func_index != .none) { | 2527 | if (sema.func_index != .none) { |
| 2545 | ip.funcAnalysis(sema.func_index).state = .sema_failure; | 2528 | ip.funcAnalysis(sema.func_index).state = .sema_failure; |
| 2546 | } | 2529 | } |
| 2547 | const gop = mod.failed_analysis.getOrPutAssumeCapacity(sema.ownerUnit()); | 2530 | |
| 2548 | if (gop.found_existing) { | ||
| 2549 | // If there are multiple errors for the same Decl, prefer the first one added. | ||
| 2550 | sema.err = null; | ||
| 2551 | err_msg.destroy(gpa); | ||
| 2552 | } else { | ||
| 2553 | sema.err = err_msg; | ||
| 2554 | gop.value_ptr.* = err_msg; | ||
| 2555 | } | ||
| 2556 | return error.AnalysisFail; | 2531 | return error.AnalysisFail; |
| 2557 | } | 2532 | } |
| 2558 | 2533 | ||
| ... | @@ -4235,6 +4210,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com | ... | @@ -4235,6 +4210,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com |
| 4235 | if (mod.intern_pool.isFuncBody(val)) { | 4210 | if (mod.intern_pool.isFuncBody(val)) { |
| 4236 | const ty = Type.fromInterned(mod.intern_pool.typeOf(val)); | 4211 | const ty = Type.fromInterned(mod.intern_pool.typeOf(val)); |
| 4237 | if (try sema.fnHasRuntimeBits(ty)) { | 4212 | if (try sema.fnHasRuntimeBits(ty)) { |
| 4213 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = val })); | ||
| 4238 | try mod.ensureFuncBodyAnalysisQueued(val); | 4214 | try mod.ensureFuncBodyAnalysisQueued(val); |
| 4239 | } | 4215 | } |
| 4240 | } | 4216 | } |
| ... | @@ -6395,6 +6371,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void | ... | @@ -6395,6 +6371,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void |
| 6395 | } else try sema.lookupIdentifier(block, operand_src, decl_name); | 6371 | } else try sema.lookupIdentifier(block, operand_src, decl_name); |
| 6396 | const options = try sema.resolveExportOptions(block, options_src, extra.options); | 6372 | const options = try sema.resolveExportOptions(block, options_src, extra.options); |
| 6397 | { | 6373 | { |
| 6374 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = decl_index })); | ||
| 6398 | try sema.ensureDeclAnalyzed(decl_index); | 6375 | try sema.ensureDeclAnalyzed(decl_index); |
| 6399 | const exported_decl = mod.declPtr(decl_index); | 6376 | const exported_decl = mod.declPtr(decl_index); |
| 6400 | if (exported_decl.val.getFunction(mod)) |function| { | 6377 | if (exported_decl.val.getFunction(mod)) |function| { |
| ... | @@ -6446,6 +6423,7 @@ pub fn analyzeExport( | ... | @@ -6446,6 +6423,7 @@ pub fn analyzeExport( |
| 6446 | if (options.linkage == .internal) | 6423 | if (options.linkage == .internal) |
| 6447 | return; | 6424 | return; |
| 6448 | 6425 | ||
| 6426 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = exported_decl_index })); | ||
| 6449 | try sema.ensureDeclAnalyzed(exported_decl_index); | 6427 | try sema.ensureDeclAnalyzed(exported_decl_index); |
| 6450 | const exported_decl = mod.declPtr(exported_decl_index); | 6428 | const exported_decl = mod.declPtr(exported_decl_index); |
| 6451 | const export_ty = exported_decl.typeOf(mod); | 6429 | const export_ty = exported_decl.typeOf(mod); |
| ... | @@ -6468,7 +6446,7 @@ pub fn analyzeExport( | ... | @@ -6468,7 +6446,7 @@ pub fn analyzeExport( |
| 6468 | return sema.fail(block, src, "export target cannot be extern", .{}); | 6446 | return sema.fail(block, src, "export target cannot be extern", .{}); |
| 6469 | } | 6447 | } |
| 6470 | 6448 | ||
| 6471 | try sema.maybeQueueFuncBodyAnalysis(exported_decl_index); | 6449 | try sema.maybeQueueFuncBodyAnalysis(src, exported_decl_index); |
| 6472 | 6450 | ||
| 6473 | try sema.exports.append(gpa, .{ | 6451 | try sema.exports.append(gpa, .{ |
| 6474 | .opts = options, | 6452 | .opts = options, |
| ... | @@ -6699,8 +6677,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air | ... | @@ -6699,8 +6677,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air |
| 6699 | .no_embedded_nulls, | 6677 | .no_embedded_nulls, |
| 6700 | ); | 6678 | ); |
| 6701 | const decl_index = try sema.lookupIdentifier(block, src, decl_name); | 6679 | const decl_index = try sema.lookupIdentifier(block, src, decl_name); |
| 6702 | try sema.addReferencedBy(src, decl_index); | 6680 | return sema.analyzeDeclRef(src, decl_index); |
| 6703 | return sema.analyzeDeclRef(decl_index); | ||
| 6704 | } | 6681 | } |
| 6705 | 6682 | ||
| 6706 | fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { | 6683 | fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { |
| ... | @@ -7903,6 +7880,7 @@ fn analyzeCall( | ... | @@ -7903,6 +7880,7 @@ fn analyzeCall( |
| 7903 | 7880 | ||
| 7904 | if (try sema.resolveValue(func)) |func_val| { | 7881 | if (try sema.resolveValue(func)) |func_val| { |
| 7905 | if (mod.intern_pool.isFuncBody(func_val.toIntern())) { | 7882 | if (mod.intern_pool.isFuncBody(func_val.toIntern())) { |
| 7883 | try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = func_val.toIntern() })); | ||
| 7906 | try mod.ensureFuncBodyAnalysisQueued(func_val.toIntern()); | 7884 | try mod.ensureFuncBodyAnalysisQueued(func_val.toIntern()); |
| 7907 | } | 7885 | } |
| 7908 | } | 7886 | } |
| ... | @@ -8339,8 +8317,6 @@ fn instantiateGenericCall( | ... | @@ -8339,8 +8317,6 @@ fn instantiateGenericCall( |
| 8339 | const callee = mod.funcInfo(callee_index); | 8317 | const callee = mod.funcInfo(callee_index); |
| 8340 | callee.branchQuota(ip).* = @max(callee.branchQuota(ip).*, sema.branch_quota); | 8318 | callee.branchQuota(ip).* = @max(callee.branchQuota(ip).*, sema.branch_quota); |
| 8341 | 8319 | ||
| 8342 | try sema.addReferencedBy(call_src, callee.owner_decl); | ||
| 8343 | |||
| 8344 | // Make a runtime call to the new function, making sure to omit the comptime args. | 8320 | // Make a runtime call to the new function, making sure to omit the comptime args. |
| 8345 | const func_ty = Type.fromInterned(callee.ty); | 8321 | const func_ty = Type.fromInterned(callee.ty); |
| 8346 | const func_ty_info = mod.typeToFunc(func_ty).?; | 8322 | const func_ty_info = mod.typeToFunc(func_ty).?; |
| ... | @@ -8366,6 +8342,7 @@ fn instantiateGenericCall( | ... | @@ -8366,6 +8342,7 @@ fn instantiateGenericCall( |
| 8366 | ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn = true; | 8342 | ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn = true; |
| 8367 | } | 8343 | } |
| 8368 | 8344 | ||
| 8345 | try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = callee_index })); | ||
| 8369 | try mod.ensureFuncBodyAnalysisQueued(callee_index); | 8346 | try mod.ensureFuncBodyAnalysisQueued(callee_index); |
| 8370 | 8347 | ||
| 8371 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + runtime_args.items.len); | 8348 | try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + runtime_args.items.len); |
| ... | @@ -17479,7 +17456,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat | ... | @@ -17479,7 +17456,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat |
| 17479 | .@"comptime" => |index| return Air.internedToRef(index), | 17456 | .@"comptime" => |index| return Air.internedToRef(index), |
| 17480 | .runtime => |index| index, | 17457 | .runtime => |index| index, |
| 17481 | .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index), | 17458 | .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index), |
| 17482 | .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index), | 17459 | .decl_ref => |decl_index| return sema.analyzeDeclRef(src, decl_index), |
| 17483 | }; | 17460 | }; |
| 17484 | 17461 | ||
| 17485 | // The comptime case is handled already above. Runtime case below. | 17462 | // The comptime case is handled already above. Runtime case below. |
| ... | @@ -27673,7 +27650,6 @@ fn fieldCallBind( | ... | @@ -27673,7 +27650,6 @@ fn fieldCallBind( |
| 27673 | const decl_idx = (try sema.namespaceLookup(block, src, namespace, field_name)) orelse | 27650 | const decl_idx = (try sema.namespaceLookup(block, src, namespace, field_name)) orelse |
| 27674 | break :found_decl null; | 27651 | break :found_decl null; |
| 27675 | 27652 | ||
| 27676 | try sema.addReferencedBy(src, decl_idx); | ||
| 27677 | const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); | 27653 | const decl_val = try sema.analyzeDeclVal(block, src, decl_idx); |
| 27678 | const decl_type = sema.typeOf(decl_val); | 27654 | const decl_type = sema.typeOf(decl_val); |
| 27679 | if (mod.typeToFunc(decl_type)) |func_type| f: { | 27655 | if (mod.typeToFunc(decl_type)) |func_type| f: { |
| ... | @@ -27829,8 +27805,7 @@ fn namespaceLookupRef( | ... | @@ -27829,8 +27805,7 @@ fn namespaceLookupRef( |
| 27829 | decl_name: InternPool.NullTerminatedString, | 27805 | decl_name: InternPool.NullTerminatedString, |
| 27830 | ) CompileError!?Air.Inst.Ref { | 27806 | ) CompileError!?Air.Inst.Ref { |
| 27831 | const decl = (try sema.namespaceLookup(block, src, opt_namespace, decl_name)) orelse return null; | 27807 | const decl = (try sema.namespaceLookup(block, src, opt_namespace, decl_name)) orelse return null; |
| 27832 | try sema.addReferencedBy(src, decl); | 27808 | return try sema.analyzeDeclRef(src, decl); |
| 27833 | return try sema.analyzeDeclRef(decl); | ||
| 27834 | } | 27809 | } |
| 27835 | 27810 | ||
| 27836 | fn namespaceLookupVal( | 27811 | fn namespaceLookupVal( |
| ... | @@ -28968,7 +28943,7 @@ fn coerceExtra( | ... | @@ -28968,7 +28943,7 @@ fn coerceExtra( |
| 28968 | if (inst_ty.zigTypeTag(zcu) == .Fn) { | 28943 | if (inst_ty.zigTypeTag(zcu) == .Fn) { |
| 28969 | const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); | 28944 | const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); |
| 28970 | const fn_decl = fn_val.pointerDecl(zcu).?; | 28945 | const fn_decl = fn_val.pointerDecl(zcu).?; |
| 28971 | const inst_as_ptr = try sema.analyzeDeclRef(fn_decl); | 28946 | const inst_as_ptr = try sema.analyzeDeclRef(inst_src, fn_decl); |
| 28972 | return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); | 28947 | return sema.coerce(block, dest_ty, inst_as_ptr, inst_src); |
| 28973 | } | 28948 | } |
| 28974 | 28949 | ||
| ... | @@ -30521,7 +30496,7 @@ fn coerceVarArgParam( | ... | @@ -30521,7 +30496,7 @@ fn coerceVarArgParam( |
| 30521 | .Fn => fn_ptr: { | 30496 | .Fn => fn_ptr: { |
| 30522 | const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); | 30497 | const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined); |
| 30523 | const fn_decl = fn_val.pointerDecl(mod).?; | 30498 | const fn_decl = fn_val.pointerDecl(mod).?; |
| 30524 | break :fn_ptr try sema.analyzeDeclRef(fn_decl); | 30499 | break :fn_ptr try sema.analyzeDeclRef(inst_src, fn_decl); |
| 30525 | }, | 30500 | }, |
| 30526 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), | 30501 | .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}), |
| 30527 | .Float => float: { | 30502 | .Float => float: { |
| ... | @@ -31748,11 +31723,10 @@ fn analyzeDeclVal( | ... | @@ -31748,11 +31723,10 @@ fn analyzeDeclVal( |
| 31748 | src: LazySrcLoc, | 31723 | src: LazySrcLoc, |
| 31749 | decl_index: InternPool.DeclIndex, | 31724 | decl_index: InternPool.DeclIndex, |
| 31750 | ) CompileError!Air.Inst.Ref { | 31725 | ) CompileError!Air.Inst.Ref { |
| 31751 | try sema.addReferencedBy(src, decl_index); | ||
| 31752 | if (sema.decl_val_table.get(decl_index)) |result| { | 31726 | if (sema.decl_val_table.get(decl_index)) |result| { |
| 31753 | return result; | 31727 | return result; |
| 31754 | } | 31728 | } |
| 31755 | const decl_ref = try sema.analyzeDeclRefInner(decl_index, false); | 31729 | const decl_ref = try sema.analyzeDeclRefInner(src, decl_index, false); |
| 31756 | const result = try sema.analyzeLoad(block, src, decl_ref, src); | 31730 | const result = try sema.analyzeLoad(block, src, decl_ref, src); |
| 31757 | if (result.toInterned() != null) { | 31731 | if (result.toInterned() != null) { |
| 31758 | if (!block.is_typeof) { | 31732 | if (!block.is_typeof) { |
| ... | @@ -31762,18 +31736,18 @@ fn analyzeDeclVal( | ... | @@ -31762,18 +31736,18 @@ fn analyzeDeclVal( |
| 31762 | return result; | 31736 | return result; |
| 31763 | } | 31737 | } |
| 31764 | 31738 | ||
| 31765 | fn addReferencedBy( | 31739 | fn addReferenceEntry( |
| 31766 | sema: *Sema, | 31740 | sema: *Sema, |
| 31767 | src: LazySrcLoc, | 31741 | src: LazySrcLoc, |
| 31768 | decl_index: InternPool.DeclIndex, | 31742 | referenced_unit: AnalUnit, |
| 31769 | ) !void { | 31743 | ) !void { |
| 31770 | if (sema.mod.comp.reference_trace == 0) return; | 31744 | if (sema.mod.comp.reference_trace == 0) return; |
| 31771 | try sema.mod.reference_table.put(sema.gpa, decl_index, .{ | 31745 | const gop = try sema.references.getOrPut(sema.gpa, referenced_unit); |
| 31772 | // TODO: this can make the reference trace suboptimal. This will be fixed | 31746 | if (gop.found_existing) return; |
| 31773 | // once the reference table is reworked for incremental compilation. | 31747 | // TODO: we need to figure out how to model inline calls here. |
| 31774 | .referencer = sema.owner_decl_index, | 31748 | // They aren't references in the analysis sense, but ought to show up in the reference trace! |
| 31775 | .src = src, | 31749 | // Would representing inline calls in the reference table cause excessive memory usage? |
| 31776 | }); | 31750 | try sema.mod.addUnitReference(sema.ownerUnit(), referenced_unit, src); |
| 31777 | } | 31751 | } |
| 31778 | 31752 | ||
| 31779 | pub fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void { | 31753 | pub fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void { |
| ... | @@ -31823,16 +31797,17 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { | ... | @@ -31823,16 +31797,17 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value { |
| 31823 | } }))); | 31797 | } }))); |
| 31824 | } | 31798 | } |
| 31825 | 31799 | ||
| 31826 | fn analyzeDeclRef(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!Air.Inst.Ref { | 31800 | fn analyzeDeclRef(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex) CompileError!Air.Inst.Ref { |
| 31827 | return sema.analyzeDeclRefInner(decl_index, true); | 31801 | return sema.analyzeDeclRefInner(src, decl_index, true); |
| 31828 | } | 31802 | } |
| 31829 | 31803 | ||
| 31830 | /// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but | 31804 | /// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but |
| 31831 | /// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a | 31805 | /// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a |
| 31832 | /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps | 31806 | /// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps |
| 31833 | /// this function with `analyze_fn_body` set to true. | 31807 | /// this function with `analyze_fn_body` set to true. |
| 31834 | fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn_body: bool) CompileError!Air.Inst.Ref { | 31808 | fn analyzeDeclRefInner(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex, analyze_fn_body: bool) CompileError!Air.Inst.Ref { |
| 31835 | const mod = sema.mod; | 31809 | const mod = sema.mod; |
| 31810 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = decl_index })); | ||
| 31836 | try sema.ensureDeclAnalyzed(decl_index); | 31811 | try sema.ensureDeclAnalyzed(decl_index); |
| 31837 | 31812 | ||
| 31838 | const decl_val = try mod.declPtr(decl_index).valueOrFail(); | 31813 | const decl_val = try mod.declPtr(decl_index).valueOrFail(); |
| ... | @@ -31853,7 +31828,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn | ... | @@ -31853,7 +31828,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn |
| 31853 | }, | 31828 | }, |
| 31854 | }); | 31829 | }); |
| 31855 | if (analyze_fn_body) { | 31830 | if (analyze_fn_body) { |
| 31856 | try sema.maybeQueueFuncBodyAnalysis(decl_index); | 31831 | try sema.maybeQueueFuncBodyAnalysis(src, decl_index); |
| 31857 | } | 31832 | } |
| 31858 | return Air.internedToRef((try mod.intern(.{ .ptr = .{ | 31833 | return Air.internedToRef((try mod.intern(.{ .ptr = .{ |
| 31859 | .ty = ptr_ty.toIntern(), | 31834 | .ty = ptr_ty.toIntern(), |
| ... | @@ -31862,12 +31837,13 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn | ... | @@ -31862,12 +31837,13 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn |
| 31862 | } }))); | 31837 | } }))); |
| 31863 | } | 31838 | } |
| 31864 | 31839 | ||
| 31865 | fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: InternPool.DeclIndex) !void { | 31840 | fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex) !void { |
| 31866 | const mod = sema.mod; | 31841 | const mod = sema.mod; |
| 31867 | const decl = mod.declPtr(decl_index); | 31842 | const decl = mod.declPtr(decl_index); |
| 31868 | const decl_val = try decl.valueOrFail(); | 31843 | const decl_val = try decl.valueOrFail(); |
| 31869 | if (!mod.intern_pool.isFuncBody(decl_val.toIntern())) return; | 31844 | if (!mod.intern_pool.isFuncBody(decl_val.toIntern())) return; |
| 31870 | if (!try sema.fnHasRuntimeBits(decl_val.typeOf(mod))) return; | 31845 | if (!try sema.fnHasRuntimeBits(decl_val.typeOf(mod))) return; |
| 31846 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = decl_val.toIntern() })); | ||
| 31871 | try mod.ensureFuncBodyAnalysisQueued(decl_val.toIntern()); | 31847 | try mod.ensureFuncBodyAnalysisQueued(decl_val.toIntern()); |
| 31872 | } | 31848 | } |
| 31873 | 31849 | ||
| ... | @@ -31882,8 +31858,8 @@ fn analyzeRef( | ... | @@ -31882,8 +31858,8 @@ fn analyzeRef( |
| 31882 | 31858 | ||
| 31883 | if (try sema.resolveValue(operand)) |val| { | 31859 | if (try sema.resolveValue(operand)) |val| { |
| 31884 | switch (mod.intern_pool.indexToKey(val.toIntern())) { | 31860 | switch (mod.intern_pool.indexToKey(val.toIntern())) { |
| 31885 | .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl), | 31861 | .extern_func => |extern_func| return sema.analyzeDeclRef(src, extern_func.decl), |
| 31886 | .func => |func| return sema.analyzeDeclRef(func.owner_decl), | 31862 | .func => |func| return sema.analyzeDeclRef(src, func.owner_decl), |
| 31887 | else => return anonDeclRef(sema, val.toIntern()), | 31863 | else => return anonDeclRef(sema, val.toIntern()), |
| 31888 | } | 31864 | } |
| 31889 | } | 31865 | } |
| ... | @@ -35834,6 +35810,7 @@ fn resolveInferredErrorSet( | ... | @@ -35834,6 +35810,7 @@ fn resolveInferredErrorSet( |
| 35834 | } | 35810 | } |
| 35835 | // In this case we are dealing with the actual InferredErrorSet object that | 35811 | // In this case we are dealing with the actual InferredErrorSet object that |
| 35836 | // corresponds to the function, not one created to track an inline/comptime call. | 35812 | // corresponds to the function, not one created to track an inline/comptime call. |
| 35813 | try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index })); | ||
| 35837 | try sema.ensureFuncBodyAnalyzed(func_index); | 35814 | try sema.ensureFuncBodyAnalyzed(func_index); |
| 35838 | } | 35815 | } |
| 35839 | 35816 |
src/Zcu.zig+100-49| ... | @@ -179,10 +179,15 @@ test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, | ... | @@ -179,10 +179,15 @@ test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{}, |
| 179 | /// TODO: the key here will be a `Cau.Index`. | 179 | /// TODO: the key here will be a `Cau.Index`. |
| 180 | global_assembly: std.AutoArrayHashMapUnmanaged(Decl.Index, []u8) = .{}, | 180 | global_assembly: std.AutoArrayHashMapUnmanaged(Decl.Index, []u8) = .{}, |
| 181 | 181 | ||
| 182 | reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct { | 182 | /// Key is the `AnalUnit` *performing* the reference. This representation allows |
| 183 | referencer: Decl.Index, | 183 | /// incremental updates to quickly delete references caused by a specific `AnalUnit`. |
| 184 | src: LazySrcLoc, | 184 | /// Value is index into `all_reference` of the first reference triggered by the unit. |
| 185 | }) = .{}, | 185 | /// The `next` field on the `Reference` forms a linked list of all references |
| 186 | /// triggered by the key `AnalUnit`. | ||
| 187 | reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{}, | ||
| 188 | all_references: std.ArrayListUnmanaged(Reference) = .{}, | ||
| 189 | /// Freelist of indices in `all_references`. | ||
| 190 | free_references: std.ArrayListUnmanaged(u32) = .{}, | ||
| 186 | 191 | ||
| 187 | panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len, | 192 | panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len, |
| 188 | /// The panic function body. | 193 | /// The panic function body. |
| ... | @@ -290,44 +295,14 @@ pub const Export = struct { | ... | @@ -290,44 +295,14 @@ pub const Export = struct { |
| 290 | } | 295 | } |
| 291 | }; | 296 | }; |
| 292 | 297 | ||
| 293 | const ValueArena = struct { | 298 | pub const Reference = struct { |
| 294 | state: std.heap.ArenaAllocator.State, | 299 | /// The `AnalUnit` whose semantic analysis was triggered by this reference. |
| 295 | state_acquired: ?*std.heap.ArenaAllocator.State = null, | 300 | referenced: AnalUnit, |
| 296 | 301 | /// Index into `all_references` of the next `Reference` triggered by the same `AnalUnit`. | |
| 297 | /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance | 302 | /// `std.math.maxInt(u32)` is the sentinel. |
| 298 | prev: ?*ValueArena = null, | 303 | next: u32, |
| 299 | 304 | /// The source location of the reference. | |
| 300 | /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator | 305 | src: LazySrcLoc, |
| 301 | /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion, | ||
| 302 | /// and must live until the matching call to release(). | ||
| 303 | pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator { | ||
| 304 | if (self.state_acquired) |state_acquired| { | ||
| 305 | return @as(*std.heap.ArenaAllocator, @fieldParentPtr("state", state_acquired)).allocator(); | ||
| 306 | } | ||
| 307 | |||
| 308 | out_arena_allocator.* = self.state.promote(child_allocator); | ||
| 309 | self.state_acquired = &out_arena_allocator.state; | ||
| 310 | return out_arena_allocator.allocator(); | ||
| 311 | } | ||
| 312 | |||
| 313 | /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`. | ||
| 314 | pub fn release(self: *ValueArena, arena_allocator: *std.heap.ArenaAllocator) void { | ||
| 315 | if (@as(*std.heap.ArenaAllocator, @fieldParentPtr("state", self.state_acquired.?)) == arena_allocator) { | ||
| 316 | self.state = self.state_acquired.?.*; | ||
| 317 | self.state_acquired = null; | ||
| 318 | } | ||
| 319 | } | ||
| 320 | |||
| 321 | pub fn deinit(self: ValueArena, child_allocator: Allocator) void { | ||
| 322 | assert(self.state_acquired == null); | ||
| 323 | |||
| 324 | const prev = self.prev; | ||
| 325 | self.state.promote(child_allocator).deinit(); | ||
| 326 | |||
| 327 | if (prev) |p| { | ||
| 328 | p.deinit(child_allocator); | ||
| 329 | } | ||
| 330 | } | ||
| 331 | }; | 306 | }; |
| 332 | 307 | ||
| 333 | pub const Decl = struct { | 308 | pub const Decl = struct { |
| ... | @@ -758,7 +733,7 @@ pub const File = struct { | ... | @@ -758,7 +733,7 @@ pub const File = struct { |
| 758 | /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen. | 733 | /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen. |
| 759 | multi_pkg: bool = false, | 734 | multi_pkg: bool = false, |
| 760 | /// List of references to this file, used for multi-package errors. | 735 | /// List of references to this file, used for multi-package errors. |
| 761 | references: std.ArrayListUnmanaged(Reference) = .{}, | 736 | references: std.ArrayListUnmanaged(File.Reference) = .{}, |
| 762 | /// The hash of the path to this file, used to store `InternPool.TrackedInst`. | 737 | /// The hash of the path to this file, used to store `InternPool.TrackedInst`. |
| 763 | path_digest: Cache.BinDigest, | 738 | path_digest: Cache.BinDigest, |
| 764 | 739 | ||
| ... | @@ -925,7 +900,7 @@ pub const File = struct { | ... | @@ -925,7 +900,7 @@ pub const File = struct { |
| 925 | } | 900 | } |
| 926 | 901 | ||
| 927 | /// Add a reference to this file during AstGen. | 902 | /// Add a reference to this file during AstGen. |
| 928 | pub fn addReference(file: *File, mod: Module, ref: Reference) !void { | 903 | pub fn addReference(file: *File, mod: Module, ref: File.Reference) !void { |
| 929 | // Don't add the same module root twice. Note that since we always add module roots at the | 904 | // Don't add the same module root twice. Note that since we always add module roots at the |
| 930 | // front of the references array (see below), this loop is actually O(1) on valid code. | 905 | // front of the references array (see below), this loop is actually O(1) on valid code. |
| 931 | if (ref == .root) { | 906 | if (ref == .root) { |
| ... | @@ -1002,8 +977,7 @@ pub const ErrorMsg = struct { | ... | @@ -1002,8 +977,7 @@ pub const ErrorMsg = struct { |
| 1002 | src_loc: SrcLoc, | 977 | src_loc: SrcLoc, |
| 1003 | msg: []const u8, | 978 | msg: []const u8, |
| 1004 | notes: []ErrorMsg = &.{}, | 979 | notes: []ErrorMsg = &.{}, |
| 1005 | reference_trace: []Trace = &.{}, | 980 | reference_trace_root: AnalUnit.Optional = .none, |
| 1006 | hidden_references: u32 = 0, | ||
| 1007 | 981 | ||
| 1008 | pub const Trace = struct { | 982 | pub const Trace = struct { |
| 1009 | decl: InternPool.NullTerminatedString, | 983 | decl: InternPool.NullTerminatedString, |
| ... | @@ -1048,7 +1022,6 @@ pub const ErrorMsg = struct { | ... | @@ -1048,7 +1022,6 @@ pub const ErrorMsg = struct { |
| 1048 | } | 1022 | } |
| 1049 | gpa.free(err_msg.notes); | 1023 | gpa.free(err_msg.notes); |
| 1050 | gpa.free(err_msg.msg); | 1024 | gpa.free(err_msg.msg); |
| 1051 | gpa.free(err_msg.reference_trace); | ||
| 1052 | err_msg.* = undefined; | 1025 | err_msg.* = undefined; |
| 1053 | } | 1026 | } |
| 1054 | }; | 1027 | }; |
| ... | @@ -2520,6 +2493,8 @@ pub fn deinit(zcu: *Zcu) void { | ... | @@ -2520,6 +2493,8 @@ pub fn deinit(zcu: *Zcu) void { |
| 2520 | zcu.global_assembly.deinit(gpa); | 2493 | zcu.global_assembly.deinit(gpa); |
| 2521 | 2494 | ||
| 2522 | zcu.reference_table.deinit(gpa); | 2495 | zcu.reference_table.deinit(gpa); |
| 2496 | zcu.all_references.deinit(gpa); | ||
| 2497 | zcu.free_references.deinit(gpa); | ||
| 2523 | 2498 | ||
| 2524 | { | 2499 | { |
| 2525 | var it = zcu.intern_pool.allocated_namespaces.iterator(0); | 2500 | var it = zcu.intern_pool.allocated_namespaces.iterator(0); |
| ... | @@ -3462,7 +3437,8 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -3462,7 +3437,8 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3462 | // The exports this Decl performs will be re-discovered, so we remove them here | 3437 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 3463 | // prior to re-analysis. | 3438 | // prior to re-analysis. |
| 3464 | if (build_options.only_c) unreachable; | 3439 | if (build_options.only_c) unreachable; |
| 3465 | mod.deleteUnitExports(AnalUnit.wrap(.{ .decl = decl_index })); | 3440 | mod.deleteUnitExports(decl_as_depender); |
| 3441 | mod.deleteUnitReferences(decl_as_depender); | ||
| 3466 | } | 3442 | } |
| 3467 | 3443 | ||
| 3468 | const sema_result: SemaDeclResult = blk: { | 3444 | const sema_result: SemaDeclResult = blk: { |
| ... | @@ -3591,7 +3567,8 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In | ... | @@ -3591,7 +3567,8 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In |
| 3591 | if (was_outdated) { | 3567 | if (was_outdated) { |
| 3592 | if (build_options.only_c) unreachable; | 3568 | if (build_options.only_c) unreachable; |
| 3593 | _ = zcu.outdated_ready.swapRemove(func_as_depender); | 3569 | _ = zcu.outdated_ready.swapRemove(func_as_depender); |
| 3594 | zcu.deleteUnitExports(AnalUnit.wrap(.{ .func = func_index })); | 3570 | zcu.deleteUnitExports(func_as_depender); |
| 3571 | zcu.deleteUnitReferences(func_as_depender); | ||
| 3595 | } | 3572 | } |
| 3596 | 3573 | ||
| 3597 | switch (func.analysis(ip).state) { | 3574 | switch (func.analysis(ip).state) { |
| ... | @@ -4967,6 +4944,47 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { | ... | @@ -4967,6 +4944,47 @@ pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void { |
| 4967 | } | 4944 | } |
| 4968 | } | 4945 | } |
| 4969 | 4946 | ||
| 4947 | /// Delete all references in `reference_table` which are caused by this `AnalUnit`. | ||
| 4948 | /// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated. | ||
| 4949 | fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void { | ||
| 4950 | const gpa = zcu.gpa; | ||
| 4951 | |||
| 4952 | const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse return; | ||
| 4953 | var idx = kv.value; | ||
| 4954 | |||
| 4955 | while (idx != std.math.maxInt(u32)) { | ||
| 4956 | zcu.free_references.append(gpa, idx) catch { | ||
| 4957 | // This space will be reused eventually, so we need not propagate this error. | ||
| 4958 | // Just leak it for now, and let GC reclaim it later on. | ||
| 4959 | return; | ||
| 4960 | }; | ||
| 4961 | idx = zcu.all_references.items[idx].next; | ||
| 4962 | } | ||
| 4963 | } | ||
| 4964 | |||
| 4965 | pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void { | ||
| 4966 | const gpa = zcu.gpa; | ||
| 4967 | |||
| 4968 | try zcu.reference_table.ensureUnusedCapacity(gpa, 1); | ||
| 4969 | |||
| 4970 | const ref_idx = zcu.free_references.popOrNull() orelse idx: { | ||
| 4971 | _ = try zcu.all_references.addOne(gpa); | ||
| 4972 | break :idx zcu.all_references.items.len - 1; | ||
| 4973 | }; | ||
| 4974 | |||
| 4975 | errdefer comptime unreachable; | ||
| 4976 | |||
| 4977 | const gop = zcu.reference_table.getOrPutAssumeCapacity(src_unit); | ||
| 4978 | |||
| 4979 | zcu.all_references.items[ref_idx] = .{ | ||
| 4980 | .referenced = referenced_unit, | ||
| 4981 | .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), | ||
| 4982 | .src = ref_src, | ||
| 4983 | }; | ||
| 4984 | |||
| 4985 | gop.value_ptr.* = @intCast(ref_idx); | ||
| 4986 | } | ||
| 4987 | |||
| 4970 | pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocator) SemaError!Air { | 4988 | pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocator) SemaError!Air { |
| 4971 | const tracy = trace(@src()); | 4989 | const tracy = trace(@src()); |
| 4972 | defer tracy.end(); | 4990 | defer tracy.end(); |
| ... | @@ -6447,3 +6465,36 @@ pub fn structPackedFieldBitOffset( | ... | @@ -6447,3 +6465,36 @@ pub fn structPackedFieldBitOffset( |
| 6447 | } | 6465 | } |
| 6448 | unreachable; // index out of bounds | 6466 | unreachable; // index out of bounds |
| 6449 | } | 6467 | } |
| 6468 | |||
| 6469 | pub const ResolvedReference = struct { | ||
| 6470 | referencer: AnalUnit, | ||
| 6471 | src: LazySrcLoc, | ||
| 6472 | }; | ||
| 6473 | |||
| 6474 | /// Returns a mapping from an `AnalUnit` to where it is referenced. | ||
| 6475 | /// TODO: in future, this must be adapted to traverse from roots of analysis. That way, we can | ||
| 6476 | /// use the returned map to determine which units have become unreferenced in an incremental update. | ||
| 6477 | pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) { | ||
| 6478 | const gpa = zcu.gpa; | ||
| 6479 | |||
| 6480 | var result: std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) = .{}; | ||
| 6481 | errdefer result.deinit(gpa); | ||
| 6482 | |||
| 6483 | // This is not a sufficient size, but a lower bound. | ||
| 6484 | try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); | ||
| 6485 | |||
| 6486 | for (zcu.reference_table.keys(), zcu.reference_table.values()) |referencer, first_ref_idx| { | ||
| 6487 | assert(first_ref_idx != std.math.maxInt(u32)); | ||
| 6488 | var ref_idx = first_ref_idx; | ||
| 6489 | while (ref_idx != std.math.maxInt(u32)) { | ||
| 6490 | const ref = zcu.all_references.items[ref_idx]; | ||
| 6491 | const gop = try result.getOrPut(gpa, ref.referenced); | ||
| 6492 | if (!gop.found_existing) { | ||
| 6493 | gop.value_ptr.* = .{ .referencer = referencer, .src = ref.src }; | ||
| 6494 | } | ||
| 6495 | ref_idx = ref.next; | ||
| 6496 | } | ||
| 6497 | } | ||
| 6498 | |||
| 6499 | return result; | ||
| 6500 | } |