| ... | ... | @@ -564,7 +564,23 @@ pub const Decl = struct { |
| 564 | 564 | } |
| 565 | 565 | }; |
| 566 | 566 | |
| 567 | | pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, void); |
| 567 | pub const DepsTable = std.AutoArrayHashMapUnmanaged(Decl.Index, DepType); |
| 568 | |
| 569 | /// Later types take priority; e.g. if a dependent decl has both `normal` |
| 570 | /// and `function_body` dependencies on another decl, it will be marked as |
| 571 | /// having a `function_body` dependency. |
| 572 | pub const DepType = enum { |
| 573 | /// The dependent references or uses the dependency's value, so must be |
| 574 | /// updated whenever it is changed. However, if the dependency is a |
| 575 | /// function and its type is unchanged, the dependent does not need to |
| 576 | /// be updated. |
| 577 | normal, |
| 578 | /// The dependent performs an inline or comptime call to the dependency, |
| 579 | /// or is a generic instantiation of it. It must therefore be updated |
| 580 | /// whenever the dependency is updated, even if the function type |
| 581 | /// remained the same. |
| 582 | function_body, |
| 583 | }; |
| 568 | 584 | |
| 569 | 585 | pub fn clearName(decl: *Decl, gpa: Allocator) void { |
| 570 | 586 | gpa.free(mem.sliceTo(decl.name, 0)); |
| ... | ... | @@ -4155,53 +4171,63 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4155 | 4171 | decl_prog_node.activate(); |
| 4156 | 4172 | defer decl_prog_node.end(); |
| 4157 | 4173 | |
| 4158 | | const type_changed = mod.semaDecl(decl_index) catch |err| switch (err) { |
| 4159 | | error.AnalysisFail => { |
| 4160 | | if (decl.analysis == .in_progress) { |
| 4161 | | // If this decl caused the compile error, the analysis field would |
| 4162 | | // be changed to indicate it was this Decl's fault. Because this |
| 4163 | | // did not happen, we infer here that it was a dependency failure. |
| 4164 | | decl.analysis = .dependency_failure; |
| 4165 | | } |
| 4166 | | return error.AnalysisFail; |
| 4167 | | }, |
| 4168 | | error.NeededSourceLocation => unreachable, |
| 4169 | | error.GenericPoison => unreachable, |
| 4170 | | else => |e| { |
| 4171 | | decl.analysis = .sema_failure_retryable; |
| 4172 | | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 4173 | | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 4174 | | mod.gpa, |
| 4175 | | decl.srcLoc(), |
| 4176 | | "unable to analyze: {s}", |
| 4177 | | .{@errorName(e)}, |
| 4178 | | )); |
| 4179 | | return error.AnalysisFail; |
| 4180 | | }, |
| 4174 | const type_changed = blk: { |
| 4175 | if (decl.zir_decl_index == 0 and !mod.declIsRoot(decl_index)) { |
| 4176 | // Anonymous decl. We don't semantically analyze these. |
| 4177 | break :blk false; // tv unchanged |
| 4178 | } |
| 4179 | |
| 4180 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { |
| 4181 | error.AnalysisFail => { |
| 4182 | if (decl.analysis == .in_progress) { |
| 4183 | // If this decl caused the compile error, the analysis field would |
| 4184 | // be changed to indicate it was this Decl's fault. Because this |
| 4185 | // did not happen, we infer here that it was a dependency failure. |
| 4186 | decl.analysis = .dependency_failure; |
| 4187 | } |
| 4188 | return error.AnalysisFail; |
| 4189 | }, |
| 4190 | error.NeededSourceLocation => unreachable, |
| 4191 | error.GenericPoison => unreachable, |
| 4192 | else => |e| { |
| 4193 | decl.analysis = .sema_failure_retryable; |
| 4194 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 4195 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 4196 | mod.gpa, |
| 4197 | decl.srcLoc(), |
| 4198 | "unable to analyze: {s}", |
| 4199 | .{@errorName(e)}, |
| 4200 | )); |
| 4201 | return error.AnalysisFail; |
| 4202 | }, |
| 4203 | }; |
| 4181 | 4204 | }; |
| 4182 | 4205 | |
| 4183 | 4206 | if (subsequent_analysis) { |
| 4184 | | // We may need to chase the dependants and re-analyze them. |
| 4185 | | // However, if the decl is a function, and the type is the same, we do not need to. |
| 4186 | | if (type_changed or decl.ty.zigTypeTag() != .Fn) { |
| 4187 | | for (decl.dependants.keys()) |dep_index| { |
| 4188 | | const dep = mod.declPtr(dep_index); |
| 4189 | | switch (dep.analysis) { |
| 4190 | | .unreferenced => unreachable, |
| 4191 | | .in_progress => continue, // already doing analysis, ok |
| 4192 | | .outdated => continue, // already queued for update |
| 4193 | | |
| 4194 | | .file_failure, |
| 4195 | | .dependency_failure, |
| 4196 | | .sema_failure, |
| 4197 | | .sema_failure_retryable, |
| 4198 | | .codegen_failure, |
| 4199 | | .codegen_failure_retryable, |
| 4200 | | .complete, |
| 4201 | | => if (dep.generation != mod.generation) { |
| 4202 | | try mod.markOutdatedDecl(dep_index); |
| 4203 | | }, |
| 4204 | | } |
| 4207 | // Update all dependents which have at least this level of dependency. |
| 4208 | // If our type remained the same and we're a function, only update |
| 4209 | // decls which depend on our body; otherwise, update all dependents. |
| 4210 | const update_level: Decl.DepType = if (!type_changed and decl.ty.zigTypeTag() == .Fn) .function_body else .normal; |
| 4211 | |
| 4212 | for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| { |
| 4213 | if (@enumToInt(dep_type) < @enumToInt(update_level)) continue; |
| 4214 | |
| 4215 | const dep = mod.declPtr(dep_index); |
| 4216 | switch (dep.analysis) { |
| 4217 | .unreferenced => unreachable, |
| 4218 | .in_progress => continue, // already doing analysis, ok |
| 4219 | .outdated => continue, // already queued for update |
| 4220 | |
| 4221 | .file_failure, |
| 4222 | .dependency_failure, |
| 4223 | .sema_failure, |
| 4224 | .sema_failure_retryable, |
| 4225 | .codegen_failure, |
| 4226 | .codegen_failure_retryable, |
| 4227 | .complete, |
| 4228 | => if (dep.generation != mod.generation) { |
| 4229 | try mod.markOutdatedDecl(dep_index); |
| 4230 | }, |
| 4205 | 4231 | } |
| 4206 | 4232 | } |
| 4207 | 4233 | } |
| ... | ... | @@ -4742,25 +4768,37 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4742 | 4768 | |
| 4743 | 4769 | /// Returns the depender's index of the dependee. |
| 4744 | 4770 | pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void { |
| 4771 | return mod.declareDeclDependencyType(depender_index, dependee_index, .normal); |
| 4772 | } |
| 4773 | |
| 4774 | /// Returns the depender's index of the dependee. |
| 4775 | pub fn declareDeclDependencyType(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index, dep_type: Decl.DepType) !void { |
| 4745 | 4776 | if (depender_index == dependee_index) return; |
| 4746 | 4777 | |
| 4747 | 4778 | const depender = mod.declPtr(depender_index); |
| 4748 | 4779 | const dependee = mod.declPtr(dependee_index); |
| 4749 | 4780 | |
| 4781 | if (depender.dependencies.get(dependee_index)) |cur_type| { |
| 4782 | if (@enumToInt(cur_type) >= @enumToInt(dep_type)) { |
| 4783 | // We already have this dependency (or stricter) marked |
| 4784 | return; |
| 4785 | } |
| 4786 | } |
| 4787 | |
| 4750 | 4788 | log.debug("{*} ({s}) depends on {*} ({s})", .{ |
| 4751 | 4789 | depender, depender.name, dependee, dependee.name, |
| 4752 | 4790 | }); |
| 4753 | 4791 | |
| 4754 | | try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1); |
| 4755 | | try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1); |
| 4756 | | |
| 4757 | 4792 | if (dependee.deletion_flag) { |
| 4758 | 4793 | dependee.deletion_flag = false; |
| 4759 | 4794 | assert(mod.deletion_set.swapRemove(dependee_index)); |
| 4760 | 4795 | } |
| 4761 | 4796 | |
| 4762 | | dependee.dependants.putAssumeCapacity(depender_index, {}); |
| 4763 | | depender.dependencies.putAssumeCapacity(dependee_index, {}); |
| 4797 | try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1); |
| 4798 | try dependee.dependants.ensureUnusedCapacity(mod.gpa, 1); |
| 4799 | |
| 4800 | dependee.dependants.putAssumeCapacity(depender_index, dep_type); |
| 4801 | depender.dependencies.putAssumeCapacity(dependee_index, dep_type); |
| 4764 | 4802 | } |
| 4765 | 4803 | |
| 4766 | 4804 | pub const ImportFileResult = struct { |
| ... | ... | @@ -6342,8 +6380,8 @@ pub fn populateTestFunctions( |
| 6342 | 6380 | try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); |
| 6343 | 6381 | break :n test_name_decl_index; |
| 6344 | 6382 | }; |
| 6345 | | array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, {}); |
| 6346 | | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, {}); |
| 6383 | array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, .normal); |
| 6384 | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal); |
| 6347 | 6385 | try mod.linkerUpdateDecl(test_name_decl_index); |
| 6348 | 6386 | |
| 6349 | 6387 | const field_vals = try arena.create([3]Value); |