| ... | @@ -564,7 +564,23 @@ pub const Decl = struct { | ... | @@ -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 | pub fn clearName(decl: *Decl, gpa: Allocator) void { | 585 | pub fn clearName(decl: *Decl, gpa: Allocator) void { |
| 570 | gpa.free(mem.sliceTo(decl.name, 0)); | 586 | gpa.free(mem.sliceTo(decl.name, 0)); |
| ... | @@ -4155,53 +4171,63 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { | ... | @@ -4155,53 +4171,63 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 4155 | decl_prog_node.activate(); | 4171 | decl_prog_node.activate(); |
| 4156 | defer decl_prog_node.end(); | 4172 | defer decl_prog_node.end(); |
| 4157 | | 4173 | |
| 4158 | const type_changed = mod.semaDecl(decl_index) catch |err| switch (err) { | 4174 | const type_changed = blk: { |
| 4159 | error.AnalysisFail => { | 4175 | if (decl.zir_decl_index == 0 and !mod.declIsRoot(decl_index)) { |
| 4160 | if (decl.analysis == .in_progress) { | 4176 | // Anonymous decl. We don't semantically analyze these. |
| 4161 | // If this decl caused the compile error, the analysis field would | 4177 | break :blk false; // tv unchanged |
| 4162 | // be changed to indicate it was this Decl's fault. Because this | 4178 | } |
| 4163 | // did not happen, we infer here that it was a dependency failure. | 4179 | |
| 4164 | decl.analysis = .dependency_failure; | 4180 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { |
| 4165 | } | 4181 | error.AnalysisFail => { |
| 4166 | return error.AnalysisFail; | 4182 | if (decl.analysis == .in_progress) { |
| 4167 | }, | 4183 | // If this decl caused the compile error, the analysis field would |
| 4168 | error.NeededSourceLocation => unreachable, | 4184 | // be changed to indicate it was this Decl's fault. Because this |
| 4169 | error.GenericPoison => unreachable, | 4185 | // did not happen, we infer here that it was a dependency failure. |
| 4170 | else => |e| { | 4186 | decl.analysis = .dependency_failure; |
| 4171 | decl.analysis = .sema_failure_retryable; | 4187 | } |
| 4172 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); | 4188 | return error.AnalysisFail; |
| 4173 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( | 4189 | }, |
| 4174 | mod.gpa, | 4190 | error.NeededSourceLocation => unreachable, |
| 4175 | decl.srcLoc(), | 4191 | error.GenericPoison => unreachable, |
| 4176 | "unable to analyze: {s}", | 4192 | else => |e| { |
| 4177 | .{@errorName(e)}, | 4193 | decl.analysis = .sema_failure_retryable; |
| 4178 | )); | 4194 | try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1); |
| 4179 | return error.AnalysisFail; | 4195 | mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create( |
| 4180 | }, | 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 | if (subsequent_analysis) { | 4206 | if (subsequent_analysis) { |
| 4184 | // We may need to chase the dependants and re-analyze them. | 4207 | // Update all dependents which have at least this level of dependency. |
| 4185 | // However, if the decl is a function, and the type is the same, we do not need to. | 4208 | // If our type remained the same and we're a function, only update |
| 4186 | if (type_changed or decl.ty.zigTypeTag() != .Fn) { | 4209 | // decls which depend on our body; otherwise, update all dependents. |
| 4187 | for (decl.dependants.keys()) |dep_index| { | 4210 | const update_level: Decl.DepType = if (!type_changed and decl.ty.zigTypeTag() == .Fn) .function_body else .normal; |
| 4188 | const dep = mod.declPtr(dep_index); | 4211 | |
| 4189 | switch (dep.analysis) { | 4212 | for (decl.dependants.keys(), decl.dependants.values()) |dep_index, dep_type| { |
| 4190 | .unreferenced => unreachable, | 4213 | if (@enumToInt(dep_type) < @enumToInt(update_level)) continue; |
| 4191 | .in_progress => continue, // already doing analysis, ok | 4214 | |
| 4192 | .outdated => continue, // already queued for update | 4215 | const dep = mod.declPtr(dep_index); |
| 4193 | | 4216 | switch (dep.analysis) { |
| 4194 | .file_failure, | 4217 | .unreferenced => unreachable, |
| 4195 | .dependency_failure, | 4218 | .in_progress => continue, // already doing analysis, ok |
| 4196 | .sema_failure, | 4219 | .outdated => continue, // already queued for update |
| 4197 | .sema_failure_retryable, | 4220 | |
| 4198 | .codegen_failure, | 4221 | .file_failure, |
| 4199 | .codegen_failure_retryable, | 4222 | .dependency_failure, |
| 4200 | .complete, | 4223 | .sema_failure, |
| 4201 | => if (dep.generation != mod.generation) { | 4224 | .sema_failure_retryable, |
| 4202 | try mod.markOutdatedDecl(dep_index); | 4225 | .codegen_failure, |
| 4203 | }, | 4226 | .codegen_failure_retryable, |
| 4204 | } | 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,25 +4768,37 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 4742 | | 4768 | |
| 4743 | /// Returns the depender's index of the dependee. | 4769 | /// Returns the depender's index of the dependee. |
| 4744 | pub fn declareDeclDependency(mod: *Module, depender_index: Decl.Index, dependee_index: Decl.Index) !void { | 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 | if (depender_index == dependee_index) return; | 4776 | if (depender_index == dependee_index) return; |
| 4746 | | 4777 | |
| 4747 | const depender = mod.declPtr(depender_index); | 4778 | const depender = mod.declPtr(depender_index); |
| 4748 | const dependee = mod.declPtr(dependee_index); | 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 | log.debug("{*} ({s}) depends on {*} ({s})", .{ | 4788 | log.debug("{*} ({s}) depends on {*} ({s})", .{ |
| 4751 | depender, depender.name, dependee, dependee.name, | 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 | if (dependee.deletion_flag) { | 4792 | if (dependee.deletion_flag) { |
| 4758 | dependee.deletion_flag = false; | 4793 | dependee.deletion_flag = false; |
| 4759 | assert(mod.deletion_set.swapRemove(dependee_index)); | 4794 | assert(mod.deletion_set.swapRemove(dependee_index)); |
| 4760 | } | 4795 | } |
| 4761 | | 4796 | |
| 4762 | dependee.dependants.putAssumeCapacity(depender_index, {}); | 4797 | try depender.dependencies.ensureUnusedCapacity(mod.gpa, 1); |
| 4763 | depender.dependencies.putAssumeCapacity(dependee_index, {}); | 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 | pub const ImportFileResult = struct { | 4804 | pub const ImportFileResult = struct { |
| ... | @@ -6342,8 +6380,8 @@ pub fn populateTestFunctions( | ... | @@ -6342,8 +6380,8 @@ pub fn populateTestFunctions( |
| 6342 | try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); | 6380 | try mod.declPtr(test_name_decl_index).finalizeNewArena(&name_decl_arena); |
| 6343 | break :n test_name_decl_index; | 6381 | break :n test_name_decl_index; |
| 6344 | }; | 6382 | }; |
| 6345 | array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, {}); | 6383 | array_decl.dependencies.putAssumeCapacityNoClobber(test_decl_index, .normal); |
| 6346 | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, {}); | 6384 | array_decl.dependencies.putAssumeCapacityNoClobber(test_name_decl_index, .normal); |
| 6347 | try mod.linkerUpdateDecl(test_name_decl_index); | 6385 | try mod.linkerUpdateDecl(test_name_decl_index); |
| 6348 | | 6386 | |
| 6349 | const field_vals = try arena.create([3]Value); | 6387 | const field_vals = try arena.create([3]Value); |