| ... | @@ -75,7 +75,7 @@ next_anon_name_index: usize = 0, | ... | @@ -75,7 +75,7 @@ next_anon_name_index: usize = 0, |
| 75 | | 75 | |
| 76 | /// Candidates for deletion. After a semantic analysis update completes, this list | 76 | /// Candidates for deletion. After a semantic analysis update completes, this list |
| 77 | /// contains Decls that need to be deleted if they end up having no references to them. | 77 | /// contains Decls that need to be deleted if they end up having no references to them. |
| 78 | deletion_set: ArrayListUnmanaged(*Decl) = .{}, | 78 | deletion_set: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, |
| 79 | | 79 | |
| 80 | /// Error tags and their values, tag names are duped with mod.gpa. | 80 | /// Error tags and their values, tag names are duped with mod.gpa. |
| 81 | /// Corresponds with `error_name_list`. | 81 | /// Corresponds with `error_name_list`. |
| ... | @@ -192,7 +192,7 @@ pub const Decl = struct { | ... | @@ -192,7 +192,7 @@ pub const Decl = struct { |
| 192 | /// to require re-analysis. | 192 | /// to require re-analysis. |
| 193 | outdated, | 193 | outdated, |
| 194 | }, | 194 | }, |
| 195 | /// This flag is set when this Decl is added to a check_for_deletion set, and cleared | 195 | /// This flag is set when this Decl is added to `Module.deletion_set`, and cleared |
| 196 | /// when removed. | 196 | /// when removed. |
| 197 | deletion_flag: bool, | 197 | deletion_flag: bool, |
| 198 | /// Whether the corresponding AST decl has a `pub` keyword. | 198 | /// Whether the corresponding AST decl has a `pub` keyword. |
| ... | @@ -2393,7 +2393,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void { | ... | @@ -2393,7 +2393,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl: *Decl) InnerError!void { |
| 2393 | // We don't perform a deletion here, because this Decl or another one | 2393 | // We don't perform a deletion here, because this Decl or another one |
| 2394 | // may end up referencing it before the update is complete. | 2394 | // may end up referencing it before the update is complete. |
| 2395 | dep.deletion_flag = true; | 2395 | dep.deletion_flag = true; |
| 2396 | try mod.deletion_set.append(mod.gpa, dep); | 2396 | try mod.deletion_set.put(mod.gpa, dep, {}); |
| 2397 | } | 2397 | } |
| 2398 | } | 2398 | } |
| 2399 | decl.dependencies.clearRetainingCapacity(); | 2399 | decl.dependencies.clearRetainingCapacity(); |
| ... | @@ -3197,6 +3197,11 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3 | ... | @@ -3197,6 +3197,11 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3 |
| 3197 | try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1); | 3197 | try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.count() + 1); |
| 3198 | try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1); | 3198 | try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.count() + 1); |
| 3199 | | 3199 | |
| | 3200 | if (dependee.deletion_flag) { |
| | 3201 | dependee.deletion_flag = false; |
| | 3202 | mod.deletion_set.removeAssertDiscard(dependee); |
| | 3203 | } |
| | 3204 | |
| 3200 | dependee.dependants.putAssumeCapacity(depender, {}); | 3205 | dependee.dependants.putAssumeCapacity(depender, {}); |
| 3201 | const gop = depender.dependencies.getOrPutAssumeCapacity(dependee); | 3206 | const gop = depender.dependencies.getOrPutAssumeCapacity(dependee); |
| 3202 | return @intCast(u32, gop.index); | 3207 | return @intCast(u32, gop.index); |
| ... | @@ -3224,12 +3229,14 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree { | ... | @@ -3224,12 +3229,14 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree { |
| 3224 | var msg = std.ArrayList(u8).init(mod.gpa); | 3229 | var msg = std.ArrayList(u8).init(mod.gpa); |
| 3225 | defer msg.deinit(); | 3230 | defer msg.deinit(); |
| 3226 | | 3231 | |
| | 3232 | const token_starts = tree.tokens.items(.start); |
| | 3233 | |
| 3227 | try tree.renderError(parse_err, msg.writer()); | 3234 | try tree.renderError(parse_err, msg.writer()); |
| 3228 | const err_msg = try mod.gpa.create(ErrorMsg); | 3235 | const err_msg = try mod.gpa.create(ErrorMsg); |
| 3229 | err_msg.* = .{ | 3236 | err_msg.* = .{ |
| 3230 | .src_loc = .{ | 3237 | .src_loc = .{ |
| 3231 | .container = .{ .file_scope = root_scope }, | 3238 | .container = .{ .file_scope = root_scope }, |
| 3232 | .lazy = .{ .token_abs = parse_err.token }, | 3239 | .lazy = .{ .byte_abs = token_starts[parse_err.token] }, |
| 3233 | }, | 3240 | }, |
| 3234 | .msg = msg.toOwnedSlice(), | 3241 | .msg = msg.toOwnedSlice(), |
| 3235 | }; | 3242 | }; |
| ... | @@ -3274,6 +3281,14 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3274,6 +3281,14 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3274 | deleted_decls.putAssumeCapacityNoClobber(entry.key, {}); | 3281 | deleted_decls.putAssumeCapacityNoClobber(entry.key, {}); |
| 3275 | } | 3282 | } |
| 3276 | | 3283 | |
| | 3284 | // Keep track of decls that are invalidated from the update. Ultimately, |
| | 3285 | // the goal is to queue up `analyze_decl` tasks in the work queue for |
| | 3286 | // the outdated decls, but we cannot queue up the tasks until after |
| | 3287 | // we find out which ones have been deleted, otherwise there would be |
| | 3288 | // deleted Decl pointers in the work queue. |
| | 3289 | var outdated_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa); |
| | 3290 | defer outdated_decls.deinit(); |
| | 3291 | |
| 3277 | for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) { | 3292 | for (decls) |decl_node, decl_i| switch (node_tags[decl_node]) { |
| 3278 | .fn_decl => { | 3293 | .fn_decl => { |
| 3279 | const fn_proto = node_datas[decl_node].lhs; | 3294 | const fn_proto = node_datas[decl_node].lhs; |
| ... | @@ -3284,6 +3299,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3284,6 +3299,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3284 | try mod.semaContainerFn( | 3299 | try mod.semaContainerFn( |
| 3285 | container_scope, | 3300 | container_scope, |
| 3286 | &deleted_decls, | 3301 | &deleted_decls, |
| | 3302 | &outdated_decls, |
| 3287 | decl_node, | 3303 | decl_node, |
| 3288 | decl_i, | 3304 | decl_i, |
| 3289 | tree.*, | 3305 | tree.*, |
| ... | @@ -3294,6 +3310,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3294,6 +3310,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3294 | .fn_proto_multi => try mod.semaContainerFn( | 3310 | .fn_proto_multi => try mod.semaContainerFn( |
| 3295 | container_scope, | 3311 | container_scope, |
| 3296 | &deleted_decls, | 3312 | &deleted_decls, |
| | 3313 | &outdated_decls, |
| 3297 | decl_node, | 3314 | decl_node, |
| 3298 | decl_i, | 3315 | decl_i, |
| 3299 | tree.*, | 3316 | tree.*, |
| ... | @@ -3305,6 +3322,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3305,6 +3322,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3305 | try mod.semaContainerFn( | 3322 | try mod.semaContainerFn( |
| 3306 | container_scope, | 3323 | container_scope, |
| 3307 | &deleted_decls, | 3324 | &deleted_decls, |
| | 3325 | &outdated_decls, |
| 3308 | decl_node, | 3326 | decl_node, |
| 3309 | decl_i, | 3327 | decl_i, |
| 3310 | tree.*, | 3328 | tree.*, |
| ... | @@ -3315,6 +3333,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3315,6 +3333,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3315 | .fn_proto => try mod.semaContainerFn( | 3333 | .fn_proto => try mod.semaContainerFn( |
| 3316 | container_scope, | 3334 | container_scope, |
| 3317 | &deleted_decls, | 3335 | &deleted_decls, |
| | 3336 | &outdated_decls, |
| 3318 | decl_node, | 3337 | decl_node, |
| 3319 | decl_i, | 3338 | decl_i, |
| 3320 | tree.*, | 3339 | tree.*, |
| ... | @@ -3329,6 +3348,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3329,6 +3348,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3329 | try mod.semaContainerFn( | 3348 | try mod.semaContainerFn( |
| 3330 | container_scope, | 3349 | container_scope, |
| 3331 | &deleted_decls, | 3350 | &deleted_decls, |
| | 3351 | &outdated_decls, |
| 3332 | decl_node, | 3352 | decl_node, |
| 3333 | decl_i, | 3353 | decl_i, |
| 3334 | tree.*, | 3354 | tree.*, |
| ... | @@ -3339,6 +3359,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3339,6 +3359,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3339 | .fn_proto_multi => try mod.semaContainerFn( | 3359 | .fn_proto_multi => try mod.semaContainerFn( |
| 3340 | container_scope, | 3360 | container_scope, |
| 3341 | &deleted_decls, | 3361 | &deleted_decls, |
| | 3362 | &outdated_decls, |
| 3342 | decl_node, | 3363 | decl_node, |
| 3343 | decl_i, | 3364 | decl_i, |
| 3344 | tree.*, | 3365 | tree.*, |
| ... | @@ -3350,6 +3371,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3350,6 +3371,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3350 | try mod.semaContainerFn( | 3371 | try mod.semaContainerFn( |
| 3351 | container_scope, | 3372 | container_scope, |
| 3352 | &deleted_decls, | 3373 | &deleted_decls, |
| | 3374 | &outdated_decls, |
| 3353 | decl_node, | 3375 | decl_node, |
| 3354 | decl_i, | 3376 | decl_i, |
| 3355 | tree.*, | 3377 | tree.*, |
| ... | @@ -3360,6 +3382,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3360,6 +3382,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3360 | .fn_proto => try mod.semaContainerFn( | 3382 | .fn_proto => try mod.semaContainerFn( |
| 3361 | container_scope, | 3383 | container_scope, |
| 3362 | &deleted_decls, | 3384 | &deleted_decls, |
| | 3385 | &outdated_decls, |
| 3363 | decl_node, | 3386 | decl_node, |
| 3364 | decl_i, | 3387 | decl_i, |
| 3365 | tree.*, | 3388 | tree.*, |
| ... | @@ -3370,6 +3393,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3370,6 +3393,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3370 | .global_var_decl => try mod.semaContainerVar( | 3393 | .global_var_decl => try mod.semaContainerVar( |
| 3371 | container_scope, | 3394 | container_scope, |
| 3372 | &deleted_decls, | 3395 | &deleted_decls, |
| | 3396 | &outdated_decls, |
| 3373 | decl_node, | 3397 | decl_node, |
| 3374 | decl_i, | 3398 | decl_i, |
| 3375 | tree.*, | 3399 | tree.*, |
| ... | @@ -3378,6 +3402,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3378,6 +3402,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3378 | .local_var_decl => try mod.semaContainerVar( | 3402 | .local_var_decl => try mod.semaContainerVar( |
| 3379 | container_scope, | 3403 | container_scope, |
| 3380 | &deleted_decls, | 3404 | &deleted_decls, |
| | 3405 | &outdated_decls, |
| 3381 | decl_node, | 3406 | decl_node, |
| 3382 | decl_i, | 3407 | decl_i, |
| 3383 | tree.*, | 3408 | tree.*, |
| ... | @@ -3386,6 +3411,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3386,6 +3411,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3386 | .simple_var_decl => try mod.semaContainerVar( | 3411 | .simple_var_decl => try mod.semaContainerVar( |
| 3387 | container_scope, | 3412 | container_scope, |
| 3388 | &deleted_decls, | 3413 | &deleted_decls, |
| | 3414 | &outdated_decls, |
| 3389 | decl_node, | 3415 | decl_node, |
| 3390 | decl_i, | 3416 | decl_i, |
| 3391 | tree.*, | 3417 | tree.*, |
| ... | @@ -3394,6 +3420,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3394,6 +3420,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3394 | .aligned_var_decl => try mod.semaContainerVar( | 3420 | .aligned_var_decl => try mod.semaContainerVar( |
| 3395 | container_scope, | 3421 | container_scope, |
| 3396 | &deleted_decls, | 3422 | &deleted_decls, |
| | 3423 | &outdated_decls, |
| 3397 | decl_node, | 3424 | decl_node, |
| 3398 | decl_i, | 3425 | decl_i, |
| 3399 | tree.*, | 3426 | tree.*, |
| ... | @@ -3446,11 +3473,27 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { | ... | @@ -3446,11 +3473,27 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3446 | }, | 3473 | }, |
| 3447 | else => unreachable, | 3474 | else => unreachable, |
| 3448 | }; | 3475 | }; |
| 3449 | // Handle explicitly deleted decls from the source code. Not to be confused | 3476 | // Handle explicitly deleted decls from the source code. This is one of two |
| 3450 | // with when we delete decls because they are no longer referenced. | 3477 | // places that Decl deletions happen. The other is in `Compilation`, after |
| | 3478 | // `performAllTheWork`, where we iterate over `Module.deletion_set` and |
| | 3479 | // delete Decls which are no longer referenced. |
| | 3480 | // If a Decl is explicitly deleted from source, and also no longer referenced, |
| | 3481 | // it may be both in this `deleted_decls` set, as well as in the |
| | 3482 | // `Module.deletion_set`. To avoid deleting it twice, we remove it from the |
| | 3483 | // deletion set at this time. |
| 3451 | for (deleted_decls.items()) |entry| { | 3484 | for (deleted_decls.items()) |entry| { |
| 3452 | log.debug("noticed '{s}' deleted from source", .{entry.key.name}); | 3485 | const decl = entry.key; |
| 3453 | try mod.deleteDecl(entry.key); | 3486 | log.debug("'{s}' deleted from source", .{decl.name}); |
| | 3487 | if (decl.deletion_flag) { |
| | 3488 | log.debug("'{s}' redundantly in deletion set; removing", .{decl.name}); |
| | 3489 | mod.deletion_set.removeAssertDiscard(decl); |
| | 3490 | } |
| | 3491 | try mod.deleteDecl(decl, &outdated_decls); |
| | 3492 | } |
| | 3493 | // Finally we can queue up re-analysis tasks after we have processed |
| | 3494 | // the deleted decls. |
| | 3495 | for (outdated_decls.items()) |entry| { |
| | 3496 | try mod.markOutdatedDecl(entry.key); |
| 3454 | } | 3497 | } |
| 3455 | } | 3498 | } |
| 3456 | | 3499 | |
| ... | @@ -3458,6 +3501,7 @@ fn semaContainerFn( | ... | @@ -3458,6 +3501,7 @@ fn semaContainerFn( |
| 3458 | mod: *Module, | 3501 | mod: *Module, |
| 3459 | container_scope: *Scope.Container, | 3502 | container_scope: *Scope.Container, |
| 3460 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), | 3503 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), |
| | 3504 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), |
| 3461 | decl_node: ast.Node.Index, | 3505 | decl_node: ast.Node.Index, |
| 3462 | decl_i: usize, | 3506 | decl_i: usize, |
| 3463 | tree: ast.Tree, | 3507 | tree: ast.Tree, |
| ... | @@ -3489,7 +3533,7 @@ fn semaContainerFn( | ... | @@ -3489,7 +3533,7 @@ fn semaContainerFn( |
| 3489 | try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); | 3533 | try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); |
| 3490 | } else { | 3534 | } else { |
| 3491 | if (!srcHashEql(decl.contents_hash, contents_hash)) { | 3535 | if (!srcHashEql(decl.contents_hash, contents_hash)) { |
| 3492 | try mod.markOutdatedDecl(decl); | 3536 | try outdated_decls.put(decl, {}); |
| 3493 | decl.contents_hash = contents_hash; | 3537 | decl.contents_hash = contents_hash; |
| 3494 | } else switch (mod.comp.bin_file.tag) { | 3538 | } else switch (mod.comp.bin_file.tag) { |
| 3495 | .coff => { | 3539 | .coff => { |
| ... | @@ -3524,6 +3568,7 @@ fn semaContainerVar( | ... | @@ -3524,6 +3568,7 @@ fn semaContainerVar( |
| 3524 | mod: *Module, | 3568 | mod: *Module, |
| 3525 | container_scope: *Scope.Container, | 3569 | container_scope: *Scope.Container, |
| 3526 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), | 3570 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), |
| | 3571 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), |
| 3527 | decl_node: ast.Node.Index, | 3572 | decl_node: ast.Node.Index, |
| 3528 | decl_i: usize, | 3573 | decl_i: usize, |
| 3529 | tree: ast.Tree, | 3574 | tree: ast.Tree, |
| ... | @@ -3549,7 +3594,7 @@ fn semaContainerVar( | ... | @@ -3549,7 +3594,7 @@ fn semaContainerVar( |
| 3549 | errdefer err_msg.destroy(mod.gpa); | 3594 | errdefer err_msg.destroy(mod.gpa); |
| 3550 | try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg); | 3595 | try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg); |
| 3551 | } else if (!srcHashEql(decl.contents_hash, contents_hash)) { | 3596 | } else if (!srcHashEql(decl.contents_hash, contents_hash)) { |
| 3552 | try mod.markOutdatedDecl(decl); | 3597 | try outdated_decls.put(decl, {}); |
| 3553 | decl.contents_hash = contents_hash; | 3598 | decl.contents_hash = contents_hash; |
| 3554 | } | 3599 | } |
| 3555 | } else { | 3600 | } else { |
| ... | @@ -3579,17 +3624,27 @@ fn semaContainerField( | ... | @@ -3579,17 +3624,27 @@ fn semaContainerField( |
| 3579 | log.err("TODO: analyze container field", .{}); | 3624 | log.err("TODO: analyze container field", .{}); |
| 3580 | } | 3625 | } |
| 3581 | | 3626 | |
| 3582 | pub fn deleteDecl(mod: *Module, decl: *Decl) !void { | 3627 | pub fn deleteDecl( |
| | 3628 | mod: *Module, |
| | 3629 | decl: *Decl, |
| | 3630 | outdated_decls: ?*std.AutoArrayHashMap(*Decl, void), |
| | 3631 | ) !void { |
| 3583 | const tracy = trace(@src()); | 3632 | const tracy = trace(@src()); |
| 3584 | defer tracy.end(); | 3633 | defer tracy.end(); |
| 3585 | | 3634 | |
| 3586 | try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.items.len + decl.dependencies.items().len); | 3635 | log.debug("deleting decl '{s}'", .{decl.name}); |
| | 3636 | |
| | 3637 | if (outdated_decls) |map| { |
| | 3638 | _ = map.swapRemove(decl); |
| | 3639 | try map.ensureCapacity(map.count() + decl.dependants.count()); |
| | 3640 | } |
| | 3641 | try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.count() + |
| | 3642 | decl.dependencies.count()); |
| 3587 | | 3643 | |
| 3588 | // Remove from the namespace it resides in. In the case of an anonymous Decl it will | 3644 | // Remove from the namespace it resides in. In the case of an anonymous Decl it will |
| 3589 | // not be present in the set, and this does nothing. | 3645 | // not be present in the set, and this does nothing. |
| 3590 | decl.container.removeDecl(decl); | 3646 | decl.container.removeDecl(decl); |
| 3591 | | 3647 | |
| 3592 | log.debug("deleting decl '{s}'", .{decl.name}); | | |
| 3593 | const name_hash = decl.fullyQualifiedNameHash(); | 3648 | const name_hash = decl.fullyQualifiedNameHash(); |
| 3594 | mod.decl_table.removeAssertDiscard(name_hash); | 3649 | mod.decl_table.removeAssertDiscard(name_hash); |
| 3595 | // Remove itself from its dependencies, because we are about to destroy the decl pointer. | 3650 | // Remove itself from its dependencies, because we are about to destroy the decl pointer. |
| ... | @@ -3600,16 +3655,22 @@ pub fn deleteDecl(mod: *Module, decl: *Decl) !void { | ... | @@ -3600,16 +3655,22 @@ pub fn deleteDecl(mod: *Module, decl: *Decl) !void { |
| 3600 | // We don't recursively perform a deletion here, because during the update, | 3655 | // We don't recursively perform a deletion here, because during the update, |
| 3601 | // another reference to it may turn up. | 3656 | // another reference to it may turn up. |
| 3602 | dep.deletion_flag = true; | 3657 | dep.deletion_flag = true; |
| 3603 | mod.deletion_set.appendAssumeCapacity(dep); | 3658 | mod.deletion_set.putAssumeCapacity(dep, {}); |
| 3604 | } | 3659 | } |
| 3605 | } | 3660 | } |
| 3606 | // Anything that depends on this deleted decl certainly needs to be re-analyzed. | 3661 | // Anything that depends on this deleted decl needs to be re-analyzed. |
| 3607 | for (decl.dependants.items()) |entry| { | 3662 | for (decl.dependants.items()) |entry| { |
| 3608 | const dep = entry.key; | 3663 | const dep = entry.key; |
| 3609 | dep.removeDependency(decl); | 3664 | dep.removeDependency(decl); |
| 3610 | if (dep.analysis != .outdated) { | 3665 | if (outdated_decls) |map| { |
| 3611 | // TODO Move this failure possibility to the top of the function. | 3666 | map.putAssumeCapacity(dep, {}); |
| 3612 | try mod.markOutdatedDecl(dep); | 3667 | } else if (std.debug.runtime_safety) { |
| | 3668 | // If `outdated_decls` is `null`, it means we're being called from |
| | 3669 | // `Compilation` after `performAllTheWork` and we cannot queue up any |
| | 3670 | // more work. `dep` must necessarily be another Decl that is no longer |
| | 3671 | // being referenced, and will be in the `deletion_set`. Otherwise, |
| | 3672 | // something has gone wrong. |
| | 3673 | assert(mod.deletion_set.contains(dep)); |
| 3613 | } | 3674 | } |
| 3614 | } | 3675 | } |
| 3615 | if (mod.failed_decls.swapRemove(decl)) |entry| { | 3676 | if (mod.failed_decls.swapRemove(decl)) |entry| { |