| ... | ... | @@ -149,9 +149,14 @@ error_limit: ErrorInt, |
| 149 | 149 | /// previous analysis. |
| 150 | 150 | generation: u32 = 0, |
| 151 | 151 | |
| 152 | | /// Value is the number of PO dependencies of this Depender. |
| 152 | /// Value is the number of PO or outdated Decls which this Depender depends on. |
| 153 | 153 | potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{}, |
| 154 | | outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, void) = .{}, |
| 154 | /// Value is the number of PO or outdated Decls which this Depender depends on. |
| 155 | /// Once this value drops to 0, the Depender is a candidate for re-analysis. |
| 156 | outdated: std.AutoArrayHashMapUnmanaged(InternPool.Depender, u32) = .{}, |
| 157 | /// This contains all `Depender`s in `outdated` whose PO dependency count is 0. |
| 158 | /// Such `Depender`s are ready for immediate re-analysis. |
| 159 | outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.Depender, void) = .{}, |
| 155 | 160 | |
| 156 | 161 | stage1_flags: packed struct { |
| 157 | 162 | have_winmain: bool = false, |
| ... | ... | @@ -2485,6 +2490,8 @@ pub fn deinit(zcu: *Zcu) void { |
| 2485 | 2490 | zcu.global_error_set.deinit(gpa); |
| 2486 | 2491 | |
| 2487 | 2492 | zcu.potentially_outdated.deinit(gpa); |
| 2493 | zcu.outdated.deinit(gpa); |
| 2494 | zcu.outdated_ready.deinit(gpa); |
| 2488 | 2495 | |
| 2489 | 2496 | zcu.test_functions.deinit(gpa); |
| 2490 | 2497 | |
| ... | ... | @@ -2851,11 +2858,27 @@ pub fn astGenFile(mod: *Module, file: *File) !void { |
| 2851 | 2858 | file.prev_zir = null; |
| 2852 | 2859 | } |
| 2853 | 2860 | |
| 2854 | | if (file.root_decl.unwrap()) |root_decl| { |
| 2861 | if (file.root_decl.unwrap()) |root_decl| mark_outdated: { |
| 2855 | 2862 | // The root of this file must be re-analyzed, since the file has changed. |
| 2856 | 2863 | comp.mutex.lock(); |
| 2857 | 2864 | defer comp.mutex.unlock(); |
| 2858 | | try mod.outdated.put(gpa, InternPool.Depender.wrap(.{ .decl = root_decl }), {}); |
| 2865 | |
| 2866 | const root_decl_depender = InternPool.Depender.wrap(.{ .decl = root_decl }); |
| 2867 | |
| 2868 | const gop = try mod.outdated.getOrPut(gpa, root_decl_depender); |
| 2869 | // If this Decl is already marked as outdated, nothing needs to be done. |
| 2870 | if (gop.found_existing) break :mark_outdated; |
| 2871 | |
| 2872 | log.debug("outdated: {} (root Decl)", .{root_decl}); |
| 2873 | |
| 2874 | // If it's already PO, forward its existing PO dependency count. |
| 2875 | // Otherwise, it has no PO dependencies yet. |
| 2876 | if (mod.potentially_outdated.fetchSwapRemove(root_decl_depender)) |kv| { |
| 2877 | gop.value_ptr.* = kv.value; |
| 2878 | } else { |
| 2879 | gop.value_ptr.* = 0; |
| 2880 | try mod.outdated_ready.put(mod.gpa, root_decl_depender, {}); |
| 2881 | } |
| 2859 | 2882 | } |
| 2860 | 2883 | } |
| 2861 | 2884 | |
| ... | ... | @@ -2953,6 +2976,7 @@ fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void { |
| 2953 | 2976 | // Tracking failed for this instruction. Invalidate associated `src_hash` deps. |
| 2954 | 2977 | zcu.comp.mutex.lock(); |
| 2955 | 2978 | defer zcu.comp.mutex.unlock(); |
| 2979 | log.debug("tracking failed for %{d}", .{old_inst}); |
| 2956 | 2980 | try zcu.markDependeeOutdated(.{ .src_hash = ti_idx }); |
| 2957 | 2981 | continue; |
| 2958 | 2982 | }; |
| ... | ... | @@ -2962,6 +2986,12 @@ fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void { |
| 2962 | 2986 | if (std.zig.srcHashEql(old_hash, new_hash)) { |
| 2963 | 2987 | break :hash_changed; |
| 2964 | 2988 | } |
| 2989 | log.debug("hash for (%{d} -> %{d}) changed: {} -> {}", .{ |
| 2990 | old_inst, |
| 2991 | ti.inst, |
| 2992 | std.fmt.fmtSliceHexLower(&old_hash), |
| 2993 | std.fmt.fmtSliceHexLower(&new_hash), |
| 2994 | }); |
| 2965 | 2995 | } |
| 2966 | 2996 | // The source hash associated with this instruction changed - invalidate relevant dependencies. |
| 2967 | 2997 | zcu.comp.mutex.lock(); |
| ... | ... | @@ -3042,25 +3072,80 @@ fn updateZirRefs(zcu: *Module, file: *File, old_zir: Zir) !void { |
| 3042 | 3072 | } |
| 3043 | 3073 | |
| 3044 | 3074 | pub fn markDependeeOutdated(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3075 | log.debug("outdated dependee: {}", .{dependee}); |
| 3045 | 3076 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 3046 | 3077 | while (it.next()) |depender| { |
| 3047 | | if (zcu.outdated.contains(depender)) continue; |
| 3048 | | const was_po = zcu.potentially_outdated.swapRemove(depender); |
| 3049 | | try zcu.outdated.putNoClobber(zcu.gpa, depender, {}); |
| 3078 | if (zcu.outdated.contains(depender)) { |
| 3079 | // We do not need to increment the PO dep count, as if the outdated |
| 3080 | // dependee is a Decl, we had already marked this as PO. |
| 3081 | continue; |
| 3082 | } |
| 3083 | const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender); |
| 3084 | try zcu.outdated.putNoClobber( |
| 3085 | zcu.gpa, |
| 3086 | depender, |
| 3087 | // We do not need to increment this count for the same reason as above. |
| 3088 | if (opt_po_entry) |e| e.value else 0, |
| 3089 | ); |
| 3090 | log.debug("outdated: {}", .{depender}); |
| 3091 | if (opt_po_entry != null) { |
| 3092 | // This is a new entry with no PO dependencies. |
| 3093 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 3094 | } |
| 3050 | 3095 | // If this is a Decl and was not previously PO, we must recursively |
| 3051 | 3096 | // mark dependencies on its tyval as PO. |
| 3052 | | if (was_po) switch (depender.unwrap()) { |
| 3097 | if (opt_po_entry == null) switch (depender.unwrap()) { |
| 3053 | 3098 | .decl => |decl_index| try zcu.markDeclDependenciesPotentiallyOutdated(decl_index), |
| 3054 | 3099 | .func => {}, |
| 3055 | 3100 | }; |
| 3056 | 3101 | } |
| 3057 | 3102 | } |
| 3058 | 3103 | |
| 3104 | fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { |
| 3105 | var it = zcu.intern_pool.dependencyIterator(dependee); |
| 3106 | while (it.next()) |depender| { |
| 3107 | if (zcu.outdated.getPtr(depender)) |po_dep_count| { |
| 3108 | // This depender is already outdated, but it now has one |
| 3109 | // less PO dependency! |
| 3110 | po_dep_count.* -= 1; |
| 3111 | if (po_dep_count.* == 0) { |
| 3112 | try zcu.outdated_ready.put(zcu.gpa, depender, {}); |
| 3113 | } |
| 3114 | continue; |
| 3115 | } |
| 3116 | // This depender is definitely at least PO, because this Decl was just analyzed |
| 3117 | // due to being outdated. |
| 3118 | const ptr = zcu.potentially_outdated.getPtr(depender).?; |
| 3119 | if (ptr.* > 1) { |
| 3120 | ptr.* -= 1; |
| 3121 | continue; |
| 3122 | } |
| 3123 | |
| 3124 | // This dependency is no longer PO, i.e. is known to be up-to-date. |
| 3125 | assert(zcu.potentially_outdated.swapRemove(depender)); |
| 3126 | // If this is a Decl, we must recursively mark dependencies on its tyval |
| 3127 | // as no longer PO. |
| 3128 | switch (depender.unwrap()) { |
| 3129 | .decl => |decl_index| try zcu.markPoDependeeUpToDate(.{ .decl_val = decl_index }), |
| 3130 | .func => {}, |
| 3131 | } |
| 3132 | } |
| 3133 | } |
| 3134 | |
| 3059 | 3135 | /// Given a Decl which is newly outdated or PO, mark all dependers which depend |
| 3060 | 3136 | /// on its tyval as PO. |
| 3061 | 3137 | fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !void { |
| 3062 | 3138 | var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index }); |
| 3063 | 3139 | while (it.next()) |po| { |
| 3140 | if (zcu.outdated.getPtr(po)) |po_dep_count| { |
| 3141 | // This dependency is already outdated, but it now has one more PO |
| 3142 | // dependency. |
| 3143 | if (po_dep_count.* == 0) { |
| 3144 | _ = zcu.outdated_ready.swapRemove(po); |
| 3145 | } |
| 3146 | po_dep_count.* += 1; |
| 3147 | continue; |
| 3148 | } |
| 3064 | 3149 | if (zcu.potentially_outdated.getPtr(po)) |n| { |
| 3065 | 3150 | // There is now one more PO dependency. |
| 3066 | 3151 | n.* += 1; |
| ... | ... | @@ -3077,6 +3162,92 @@ fn markDeclDependenciesPotentiallyOutdated(zcu: *Zcu, decl_index: Decl.Index) !v |
| 3077 | 3162 | // TODO: repeat the above for `decl_ty` dependencies when they are introduced |
| 3078 | 3163 | } |
| 3079 | 3164 | |
| 3165 | pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.Depender { |
| 3166 | if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) { |
| 3167 | log.debug("findOutdatedToAnalyze: no outdated depender", .{}); |
| 3168 | return null; |
| 3169 | } |
| 3170 | |
| 3171 | // Our goal is to find an outdated Depender which itself has no outdated or |
| 3172 | // PO dependencies. Most of the time, such a Depender will exist - we track |
| 3173 | // them in the `outdated_ready` set for efficiency. However, this is not |
| 3174 | // necessarily the case, since the Decl dependency graph may contain loops |
| 3175 | // via mutually recursive definitions: |
| 3176 | // pub const A = struct { b: *B }; |
| 3177 | // pub const B = struct { b: *A }; |
| 3178 | // In this case, we must defer to more complex logic below. |
| 3179 | |
| 3180 | if (zcu.outdated_ready.count() > 0) { |
| 3181 | log.debug("findOutdatedToAnalyze: trivial '{s} {d}'", .{ |
| 3182 | @tagName(zcu.outdated_ready.keys()[0].unwrap()), |
| 3183 | switch (zcu.outdated_ready.keys()[0].unwrap()) { |
| 3184 | inline else => |x| @intFromEnum(x), |
| 3185 | }, |
| 3186 | }); |
| 3187 | return zcu.outdated_ready.keys()[0]; |
| 3188 | } |
| 3189 | |
| 3190 | // There is no single Depender which is ready for re-analysis. Instead, we |
| 3191 | // must assume that some Decl with PO dependencies is outdated - e.g. in the |
| 3192 | // above example we arbitrarily pick one of A or B. We should select a Decl, |
| 3193 | // since a Decl is definitely responsible for the loop in the dependency |
| 3194 | // graph (since you can't depend on a runtime function analysis!). |
| 3195 | |
| 3196 | // The choice of this Decl could have a big impact on how much total |
| 3197 | // analysis we perform, since if analysis concludes its tyval is unchanged, |
| 3198 | // then other PO Dependers may be resolved as up-to-date. To hopefully avoid |
| 3199 | // doing too much work, let's find a Decl which the most things depend on - |
| 3200 | // the idea is that this will resolve a lot of loops (but this is only a |
| 3201 | // heuristic). |
| 3202 | |
| 3203 | log.debug("findOutdatedToAnalyze: no trivial ready, using heuristic; {d} outdated, {d} PO", .{ |
| 3204 | zcu.outdated.count(), |
| 3205 | zcu.potentially_outdated.count(), |
| 3206 | }); |
| 3207 | |
| 3208 | var chosen_decl_idx: ?Decl.Index = null; |
| 3209 | var chosen_decl_dependers: u32 = undefined; |
| 3210 | |
| 3211 | for (zcu.outdated.keys()) |depender| { |
| 3212 | const decl_index = switch (depender.unwrap()) { |
| 3213 | .decl => |d| d, |
| 3214 | .func => continue, |
| 3215 | }; |
| 3216 | |
| 3217 | var n: u32 = 0; |
| 3218 | var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index }); |
| 3219 | while (it.next()) |_| n += 1; |
| 3220 | |
| 3221 | if (chosen_decl_idx == null or n > chosen_decl_dependers) { |
| 3222 | chosen_decl_idx = decl_index; |
| 3223 | chosen_decl_dependers = n; |
| 3224 | } |
| 3225 | } |
| 3226 | |
| 3227 | for (zcu.potentially_outdated.keys()) |depender| { |
| 3228 | const decl_index = switch (depender.unwrap()) { |
| 3229 | .decl => |d| d, |
| 3230 | .func => continue, |
| 3231 | }; |
| 3232 | |
| 3233 | var n: u32 = 0; |
| 3234 | var it = zcu.intern_pool.dependencyIterator(.{ .decl_val = decl_index }); |
| 3235 | while (it.next()) |_| n += 1; |
| 3236 | |
| 3237 | if (chosen_decl_idx == null or n > chosen_decl_dependers) { |
| 3238 | chosen_decl_idx = decl_index; |
| 3239 | chosen_decl_dependers = n; |
| 3240 | } |
| 3241 | } |
| 3242 | |
| 3243 | log.debug("findOutdatedToAnalyze: heuristic returned Decl {d} ({d} dependers)", .{ |
| 3244 | chosen_decl_idx.?, |
| 3245 | chosen_decl_dependers, |
| 3246 | }); |
| 3247 | |
| 3248 | return InternPool.Depender.wrap(.{ .decl = chosen_decl_idx.? }); |
| 3249 | } |
| 3250 | |
| 3080 | 3251 | pub fn mapOldZirToNew( |
| 3081 | 3252 | gpa: Allocator, |
| 3082 | 3253 | old_zir: Zir, |
| ... | ... | @@ -3204,7 +3375,7 @@ pub fn mapOldZirToNew( |
| 3204 | 3375 | } |
| 3205 | 3376 | } |
| 3206 | 3377 | |
| 3207 | | /// This ensures that the Decl will have a Type and Value populated. |
| 3378 | /// This ensures that the Decl will have an up-to-date Type and Value populated. |
| 3208 | 3379 | /// However the resolution status of the Type may not be fully resolved. |
| 3209 | 3380 | /// For example an inferred error set is not resolved until after `analyzeFnBody`. |
| 3210 | 3381 | /// is called. |
| ... | ... | @@ -3214,7 +3385,25 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3214 | 3385 | |
| 3215 | 3386 | const decl = mod.declPtr(decl_index); |
| 3216 | 3387 | |
| 3217 | | const subsequent_analysis = switch (decl.analysis) { |
| 3388 | // Determine whether or not this Decl is outdated, i.e. requires re-analysis |
| 3389 | // even if `complete`. If a Decl is PO, we pessismistically assume that it |
| 3390 | // *does* require re-analysis, to ensure that the Decl is definitely |
| 3391 | // up-to-date when this function returns. |
| 3392 | |
| 3393 | // If analysis occurs in a poor order, this could result in over-analysis. |
| 3394 | // We do our best to avoid this by the other dependency logic in this file |
| 3395 | // which tries to limit re-analysis to Decls whose previously listed |
| 3396 | // dependencies are all up-to-date. |
| 3397 | |
| 3398 | const decl_as_depender = InternPool.Depender.wrap(.{ .decl = decl_index }); |
| 3399 | const was_outdated = mod.outdated.swapRemove(decl_as_depender) or |
| 3400 | mod.potentially_outdated.swapRemove(decl_as_depender); |
| 3401 | |
| 3402 | if (was_outdated) { |
| 3403 | _ = mod.outdated_ready.swapRemove(decl_as_depender); |
| 3404 | } |
| 3405 | |
| 3406 | switch (decl.analysis) { |
| 3218 | 3407 | .in_progress => unreachable, |
| 3219 | 3408 | |
| 3220 | 3409 | .file_failure, |
| ... | ... | @@ -3226,28 +3415,29 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3226 | 3415 | .codegen_failure_retryable, |
| 3227 | 3416 | => return error.AnalysisFail, |
| 3228 | 3417 | |
| 3229 | | .complete => return, |
| 3230 | | |
| 3231 | | .outdated => blk: { |
| 3418 | .complete => if (was_outdated) { |
| 3232 | 3419 | if (build_options.only_c) unreachable; |
| 3233 | 3420 | // The exports this Decl performs will be re-discovered, so we remove them here |
| 3234 | 3421 | // prior to re-analysis. |
| 3235 | 3422 | try mod.deleteDeclExports(decl_index); |
| 3423 | } else return, |
| 3236 | 3424 | |
| 3237 | | break :blk true; |
| 3238 | | }, |
| 3425 | .outdated => unreachable, // TODO: remove this field |
| 3239 | 3426 | |
| 3240 | | .unreferenced => false, |
| 3241 | | }; |
| 3427 | .unreferenced => {}, |
| 3428 | } |
| 3242 | 3429 | |
| 3243 | 3430 | var decl_prog_node = mod.sema_prog_node.start("", 0); |
| 3244 | 3431 | decl_prog_node.activate(); |
| 3245 | 3432 | defer decl_prog_node.end(); |
| 3246 | 3433 | |
| 3247 | | const type_changed = blk: { |
| 3434 | const sema_result: SemaDeclResult = blk: { |
| 3248 | 3435 | if (decl.zir_decl_index == .none and !mod.declIsRoot(decl_index)) { |
| 3249 | 3436 | // Anonymous decl. We don't semantically analyze these. |
| 3250 | | break :blk false; // tv unchanged |
| 3437 | break :blk .{ |
| 3438 | .invalidate_decl_val = false, |
| 3439 | .invalidate_decl_ref = false, |
| 3440 | }; |
| 3251 | 3441 | } |
| 3252 | 3442 | |
| 3253 | 3443 | break :blk mod.semaDecl(decl_index) catch |err| switch (err) { |
| ... | ... | @@ -3276,9 +3466,18 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void { |
| 3276 | 3466 | }; |
| 3277 | 3467 | }; |
| 3278 | 3468 | |
| 3279 | | if (subsequent_analysis) { |
| 3280 | | _ = type_changed; |
| 3281 | | @panic("TODO re-implement incremental compilation"); |
| 3469 | // TODO: we do not yet have separate dependencies for decl values vs types. |
| 3470 | if (was_outdated) { |
| 3471 | if (sema_result.invalidate_decl_val or sema_result.invalidate_decl_ref) { |
| 3472 | // This dependency was marked as PO, meaning dependees were waiting |
| 3473 | // on its analysis result, and it has turned out to be outdated. |
| 3474 | // Update dependees accordingly. |
| 3475 | try mod.markDependeeOutdated(.{ .decl_val = decl_index }); |
| 3476 | } else { |
| 3477 | // This dependency was previously PO, but turned out to be up-to-date. |
| 3478 | // We do not need to queue successive analysis. |
| 3479 | try mod.markPoDependeeUpToDate(.{ .decl_val = decl_index }); |
| 3480 | } |
| 3282 | 3481 | } |
| 3283 | 3482 | } |
| 3284 | 3483 | |
| ... | ... | @@ -3591,12 +3790,19 @@ pub fn semaFile(mod: *Module, file: *File) SemaError!void { |
| 3591 | 3790 | }, |
| 3592 | 3791 | .incremental => {}, |
| 3593 | 3792 | } |
| 3793 | |
| 3794 | // Since this is our first time analyzing this file, there can be no dependencies on |
| 3795 | // its root Decl. Thus, we do not need to invalidate any dependencies. |
| 3594 | 3796 | } |
| 3595 | 3797 | |
| 3596 | | /// Returns `true` if the Decl type changed. |
| 3597 | | /// Returns `true` if this is the first time analyzing the Decl. |
| 3598 | | /// Returns `false` otherwise. |
| 3599 | | fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3798 | const SemaDeclResult = packed struct { |
| 3799 | /// Whether the value of a `decl_val` of this Decl changed. |
| 3800 | invalidate_decl_val: bool, |
| 3801 | /// Whether the type of a `decl_ref` of this Decl changed. |
| 3802 | invalidate_decl_ref: bool, |
| 3803 | }; |
| 3804 | |
| 3805 | fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult { |
| 3600 | 3806 | const tracy = trace(@src()); |
| 3601 | 3807 | defer tracy.end(); |
| 3602 | 3808 | |
| ... | ... | @@ -3674,8 +3880,10 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3674 | 3880 | }; |
| 3675 | 3881 | defer sema.deinit(); |
| 3676 | 3882 | |
| 3677 | | // Every Decl has a dependency on its own source. |
| 3678 | | try sema.declareDependency(.{ .src_hash = try ip.trackZir(sema.gpa, decl.getFileScope(mod), decl.zir_decl_index.unwrap().?) }); |
| 3883 | // Every Decl other (than file root Decls, which do not have a ZIR index) has a dependency on its own source. |
| 3884 | if (decl.zir_decl_index.unwrap()) |zir_decl_index| { |
| 3885 | try sema.declareDependency(.{ .src_hash = try ip.trackZir(sema.gpa, decl.getFileScope(mod), zir_decl_index) }); |
| 3886 | } |
| 3679 | 3887 | |
| 3680 | 3888 | assert(!mod.declIsRoot(decl_index)); |
| 3681 | 3889 | |
| ... | ... | @@ -3735,7 +3943,11 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3735 | 3943 | decl.analysis = .complete; |
| 3736 | 3944 | decl.generation = mod.generation; |
| 3737 | 3945 | |
| 3738 | | return true; |
| 3946 | // TODO: usingnamespace cannot currently participate in incremental compilation |
| 3947 | return .{ |
| 3948 | .invalidate_decl_val = true, |
| 3949 | .invalidate_decl_ref = true, |
| 3950 | }; |
| 3739 | 3951 | } |
| 3740 | 3952 | |
| 3741 | 3953 | switch (ip.indexToKey(decl_tv.val.toIntern())) { |
| ... | ... | @@ -3771,15 +3983,16 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3771 | 3983 | // The scope needs to have the decl in it. |
| 3772 | 3984 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 3773 | 3985 | } |
| 3774 | | return type_changed or is_inline != prev_is_inline; |
| 3986 | // TODO: align, linksection, addrspace? |
| 3987 | const changed = type_changed or is_inline != prev_is_inline; |
| 3988 | return .{ |
| 3989 | .invalidate_decl_val = changed, |
| 3990 | .invalidate_decl_ref = changed, |
| 3991 | }; |
| 3775 | 3992 | } |
| 3776 | 3993 | }, |
| 3777 | 3994 | else => {}, |
| 3778 | 3995 | } |
| 3779 | | var type_changed = true; |
| 3780 | | if (decl.has_tv) { |
| 3781 | | type_changed = !decl.ty.eql(decl_tv.ty, mod); |
| 3782 | | } |
| 3783 | 3996 | |
| 3784 | 3997 | decl.owns_tv = false; |
| 3785 | 3998 | var queue_linker_work = false; |
| ... | ... | @@ -3807,6 +4020,14 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3807 | 4020 | }, |
| 3808 | 4021 | } |
| 3809 | 4022 | |
| 4023 | const old_has_tv = decl.has_tv; |
| 4024 | // The following values are ignored if `!old_has_tv` |
| 4025 | const old_ty = decl.ty; |
| 4026 | const old_val = decl.val; |
| 4027 | const old_align = decl.alignment; |
| 4028 | const old_linksection = decl.@"linksection"; |
| 4029 | const old_addrspace = decl.@"addrspace"; |
| 4030 | |
| 3810 | 4031 | decl.ty = decl_tv.ty; |
| 3811 | 4032 | decl.val = Value.fromInterned((try decl_tv.val.intern(decl_tv.ty, mod))); |
| 3812 | 4033 | decl.alignment = blk: { |
| ... | ... | @@ -3850,6 +4071,17 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3850 | 4071 | decl.analysis = .complete; |
| 3851 | 4072 | decl.generation = mod.generation; |
| 3852 | 4073 | |
| 4074 | const result: SemaDeclResult = if (old_has_tv) .{ |
| 4075 | .invalidate_decl_val = !decl.ty.eql(old_ty, mod) or !decl.val.eql(old_val, decl.ty, mod), |
| 4076 | .invalidate_decl_ref = !decl.ty.eql(old_ty, mod) or |
| 4077 | decl.alignment != old_align or |
| 4078 | decl.@"linksection" != old_linksection or |
| 4079 | decl.@"addrspace" != old_addrspace, |
| 4080 | } else .{ |
| 4081 | .invalidate_decl_val = true, |
| 4082 | .invalidate_decl_ref = true, |
| 4083 | }; |
| 4084 | |
| 3853 | 4085 | const has_runtime_bits = is_extern or |
| 3854 | 4086 | (queue_linker_work and try sema.typeHasRuntimeBits(decl.ty)); |
| 3855 | 4087 | |
| ... | ... | @@ -3861,7 +4093,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3861 | 4093 | |
| 3862 | 4094 | try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index }); |
| 3863 | 4095 | |
| 3864 | | if (type_changed and mod.emit_h != null) { |
| 4096 | if (result.invalidate_decl_ref and mod.emit_h != null) { |
| 3865 | 4097 | try mod.comp.work_queue.writeItem(.{ .emit_h_decl = decl_index }); |
| 3866 | 4098 | } |
| 3867 | 4099 | } |
| ... | ... | @@ -3872,7 +4104,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !bool { |
| 3872 | 4104 | try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index); |
| 3873 | 4105 | } |
| 3874 | 4106 | |
| 3875 | | return type_changed; |
| 4107 | return result; |
| 3876 | 4108 | } |
| 3877 | 4109 | |
| 3878 | 4110 | pub const ImportFileResult = struct { |