| ... | @@ -2428,13 +2428,21 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node | ... | @@ -2428,13 +2428,21 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node |
| 2428 | | 2428 | |
| 2429 | mod.lockAndClearFileCompileError(file); | 2429 | mod.lockAndClearFileCompileError(file); |
| 2430 | | 2430 | |
| 2431 | // Move previous ZIR to a local variable so we can compare it with the new one. | 2431 | // If the previous ZIR does not have compile errors, keep it around |
| 2432 | var prev_zir = file.zir; | 2432 | // in case parsing or new ZIR fails. In case of successful ZIR update |
| 2433 | var prev_zir_loaded = file.zir_loaded; | 2433 | // at the end of this function we will free it. |
| 2434 | file.zir_loaded = false; | 2434 | // We keep the previous ZIR loaded so that we can use it |
| 2435 | file.zir = undefined; | 2435 | // for the update next time it does not have any compile errors. This avoids |
| 2436 | defer if (prev_zir_loaded) prev_zir.deinit(gpa); | 2436 | // needlessly tossing out semantic analysis work when an error is |
| 2437 | | 2437 | // temporarily introduced. |
| | 2438 | if (file.zir_loaded and !file.zir.hasCompileErrors()) { |
| | 2439 | assert(file.prev_zir == null); |
| | 2440 | const prev_zir_ptr = try gpa.create(Zir); |
| | 2441 | file.prev_zir = prev_zir_ptr; |
| | 2442 | prev_zir_ptr.* = file.zir; |
| | 2443 | file.zir = undefined; |
| | 2444 | file.zir_loaded = false; |
| | 2445 | } |
| 2438 | file.unload(gpa); | 2446 | file.unload(gpa); |
| 2439 | | 2447 | |
| 2440 | if (stat.size > std.math.maxInt(u32)) | 2448 | if (stat.size > std.math.maxInt(u32)) |
| ... | @@ -2546,7 +2554,17 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node | ... | @@ -2546,7 +2554,17 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node |
| 2546 | }); | 2554 | }); |
| 2547 | }; | 2555 | }; |
| 2548 | | 2556 | |
| 2549 | if (prev_zir_loaded) { | 2557 | if (file.zir.hasCompileErrors()) { |
| | 2558 | { |
| | 2559 | const lock = comp.mutex.acquire(); |
| | 2560 | defer lock.release(); |
| | 2561 | try mod.failed_files.putNoClobber(gpa, file, null); |
| | 2562 | } |
| | 2563 | file.status = .astgen_failure; |
| | 2564 | return error.AnalysisFail; |
| | 2565 | } |
| | 2566 | |
| | 2567 | if (file.prev_zir) |prev_zir| { |
| 2550 | // Iterate over all Namespace objects contained within this File, looking at the | 2568 | // Iterate over all Namespace objects contained within this File, looking at the |
| 2551 | // previous and new ZIR together and update the references to point | 2569 | // previous and new ZIR together and update the references to point |
| 2552 | // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace | 2570 | // to the new one. For example, Decl name, Decl zir_decl_index, and Namespace |
| ... | @@ -2555,47 +2573,19 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node | ... | @@ -2555,47 +2573,19 @@ pub fn astGenFile(mod: *Module, file: *Scope.File, prog_node: *std.Progress.Node |
| 2555 | // We do not need to hold any locks at this time because all the Decl and Namespace | 2573 | // We do not need to hold any locks at this time because all the Decl and Namespace |
| 2556 | // objects being touched are specific to this File, and the only other concurrent | 2574 | // objects being touched are specific to this File, and the only other concurrent |
| 2557 | // tasks are touching other File objects. | 2575 | // tasks are touching other File objects. |
| 2558 | if (file.zir.hasCompileErrors()) { | 2576 | try updateZirRefs(gpa, file, prev_zir.*); |
| 2559 | // In this case, we keep the previous ZIR loaded so that we can use it | | |
| 2560 | // for the update next time it does not have any compile errors. This avoids | | |
| 2561 | // needlessly tossing out semantic analysis work when a ZIR error is | | |
| 2562 | // temporarily introduced. | | |
| 2563 | if (!prev_zir.hasCompileErrors()) { | | |
| 2564 | assert(file.prev_zir == null); | | |
| 2565 | const prev_zir_ptr = try gpa.create(Zir); | | |
| 2566 | file.prev_zir = prev_zir_ptr; | | |
| 2567 | prev_zir_ptr.* = prev_zir; | | |
| 2568 | prev_zir_loaded = false; | | |
| 2569 | } | | |
| 2570 | } else if (prev_zir.hasCompileErrors()) { | | |
| 2571 | if (file.prev_zir) |file_prev_zir| { | | |
| 2572 | prev_zir.deinit(gpa); | | |
| 2573 | prev_zir = file_prev_zir.*; | | |
| 2574 | gpa.destroy(file_prev_zir); | | |
| 2575 | file.prev_zir = null; | | |
| 2576 | try updateZirRefs(gpa, file, prev_zir); | | |
| 2577 | } else if (file.root_decl) |root_decl| { | | |
| 2578 | // First time the File has succeeded ZIR. We must mark it outdated since | | |
| 2579 | // we have already tried to semantically analyze it. | | |
| 2580 | try file.outdated_decls.resize(gpa, 1); | | |
| 2581 | file.outdated_decls.items[0] = root_decl; | | |
| 2582 | } | | |
| 2583 | } else { | | |
| 2584 | try updateZirRefs(gpa, file, prev_zir); | | |
| 2585 | } | | |
| 2586 | // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, | 2577 | // At this point, `file.outdated_decls` and `file.deleted_decls` are populated, |
| 2587 | // and semantic analysis will deal with them properly. | 2578 | // and semantic analysis will deal with them properly. |
| 2588 | } | 2579 | // No need to keep previous ZIR. |
| 2589 | | 2580 | prev_zir.deinit(gpa); |
| 2590 | // TODO don't report compile errors until Sema @importFile | 2581 | gpa.destroy(prev_zir); |
| 2591 | if (file.zir.hasCompileErrors()) { | 2582 | file.prev_zir = null; |
| 2592 | { | 2583 | } else if (file.root_decl) |root_decl| { |
| 2593 | const lock = comp.mutex.acquire(); | 2584 | // This is an update, but it is the first time the File has succeeded |
| 2594 | defer lock.release(); | 2585 | // ZIR. We must mark it outdated since we have already tried to |
| 2595 | try mod.failed_files.putNoClobber(gpa, file, null); | 2586 | // semantically analyze it. |
| 2596 | } | 2587 | try file.outdated_decls.resize(gpa, 1); |
| 2597 | file.status = .astgen_failure; | 2588 | file.outdated_decls.items[0] = root_decl; |
| 2598 | return error.AnalysisFail; | | |
| 2599 | } | 2589 | } |
| 2600 | } | 2590 | } |
| 2601 | | 2591 | |
| ... | @@ -2640,14 +2630,26 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void { | ... | @@ -2640,14 +2630,26 @@ fn updateZirRefs(gpa: *Allocator, file: *Scope.File, old_zir: Zir) !void { |
| 2640 | // Anonymous decls should not be marked outdated. They will be re-generated | 2630 | // Anonymous decls should not be marked outdated. They will be re-generated |
| 2641 | // if their owner decl is marked outdated. | 2631 | // if their owner decl is marked outdated. |
| 2642 | if (decl.zir_decl_index != 0) { | 2632 | if (decl.zir_decl_index != 0) { |
| 2643 | const old_hash = decl.contentsHashZir(old_zir); | 2633 | const old_zir_decl_index = decl.zir_decl_index; |
| 2644 | decl.zir_decl_index = extra_map.get(decl.zir_decl_index) orelse { | 2634 | const new_zir_decl_index = extra_map.get(old_zir_decl_index) orelse { |
| | 2635 | log.debug("updateZirRefs {s}: delete {*} ({s})", .{ |
| | 2636 | file.sub_file_path, decl, decl.name, |
| | 2637 | }); |
| 2645 | try file.deleted_decls.append(gpa, decl); | 2638 | try file.deleted_decls.append(gpa, decl); |
| 2646 | continue; | 2639 | continue; |
| 2647 | }; | 2640 | }; |
| | 2641 | const old_hash = decl.contentsHashZir(old_zir); |
| | 2642 | decl.zir_decl_index = new_zir_decl_index; |
| 2648 | const new_hash = decl.contentsHashZir(new_zir); | 2643 | const new_hash = decl.contentsHashZir(new_zir); |
| 2649 | if (!std.zig.srcHashEql(old_hash, new_hash)) { | 2644 | if (!std.zig.srcHashEql(old_hash, new_hash)) { |
| | 2645 | log.debug("updateZirRefs {s}: outdated {*} ({s}) {d} => {d}", .{ |
| | 2646 | file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, |
| | 2647 | }); |
| 2650 | try file.outdated_decls.append(gpa, decl); | 2648 | try file.outdated_decls.append(gpa, decl); |
| | 2649 | } else { |
| | 2650 | log.debug("updateZirRefs {s}: unchanged {*} ({s}) {d} => {d}", .{ |
| | 2651 | file.sub_file_path, decl, decl.name, old_zir_decl_index, new_zir_decl_index, |
| | 2652 | }); |
| 2651 | } | 2653 | } |
| 2652 | } | 2654 | } |
| 2653 | | 2655 | |
| ... | @@ -3376,7 +3378,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo | ... | @@ -3376,7 +3378,7 @@ fn scanDecl(iter: *ScanDeclIter, decl_sub_index: usize, flags: u4) InnerError!vo |
| 3376 | } | 3378 | } |
| 3377 | gpa.free(decl_name); | 3379 | gpa.free(decl_name); |
| 3378 | const decl = gop.entry.value; | 3380 | const decl = gop.entry.value; |
| 3379 | log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl_name, namespace }); | 3381 | log.debug("scan existing {*} ({s}) of {*}", .{ decl, decl.name, namespace }); |
| 3380 | // Update the AST node of the decl; even if its contents are unchanged, it may | 3382 | // Update the AST node of the decl; even if its contents are unchanged, it may |
| 3381 | // have been re-ordered. | 3383 | // have been re-ordered. |
| 3382 | const prev_src_node = decl.src_node; | 3384 | const prev_src_node = decl.src_node; |