diff --git a/src/compile/compile_build.zig b/src/compile/compile_build.zig index 3b4b51bee4c..d3e4a0a1eac 100644 --- a/src/compile/compile_build.zig +++ b/src/compile/compile_build.zig @@ -551,6 +551,11 @@ pub const BuildEnv = struct { // Multi-threaded mode: wait for global queue to drain self.global_queue.waitForIdle(); } + // Give modules stuck on external imports another chance now that all packages are scheduled. + try self.unblockExternalImports(); + if (builtin.target.cpu.arch != .wasm32 and self.mode == .multi_threaded) { + self.global_queue.waitForIdle(); + } // Note: In single-threaded mode, buildRoot() runs synchronously and blocks // until all modules are complete, so no additional waiting is needed. @@ -666,6 +671,51 @@ pub const BuildEnv = struct { } } + fn unblockExternalImports(self: *BuildEnv) !void { + var progress = true; + while (progress) { + progress = false; + + var sched_it = self.schedulers.iterator(); + while (sched_it.next()) |entry| { + const sched = entry.value_ptr.*; + + var mod_it = sched.moduleNamesIterator(); + while (mod_it.next()) |m_entry| { + const module_name = m_entry.key_ptr.*; + const st = sched.getModuleState(module_name) orelse continue; + if (st.phase != .WaitingOnImports or st.external_imports.items.len == 0) continue; + + const prev_remaining = sched.remaining_modules; + var last_phase = st.phase; + + // Drive the module forward until it either finishes or stops making progress. + while (true) { + try sched.processModuleByName(module_name); + const updated = sched.getModuleState(module_name) orelse break; + if (updated.phase == .Done) { + progress = true; + break; + } + if (updated.phase == last_phase) { + break; + } + last_phase = updated.phase; + } + + if (sched.remaining_modules < prev_remaining) { + progress = true; + } + } + } + + if (builtin.target.cpu.arch != .wasm32 and self.mode == .multi_threaded) { + // If we queued any new work onto the global scheduler, wait for it. + self.global_queue.waitForIdle(); + } + } + } + // ------------------------ // Resolver implementation // ------------------------ diff --git a/src/lsp/syntax.zig b/src/lsp/syntax.zig index c54732d5ccf..5b46962434b 100644 --- a/src/lsp/syntax.zig +++ b/src/lsp/syntax.zig @@ -114,9 +114,13 @@ pub const SyntaxChecker = struct { } for (entry.reports) |*rep| { - const diag = try self.reportToDiagnostic(rep.*); + const report = rep.*; + defer rep.deinit(); + + if (self.shouldSuppressReport(report)) continue; + + const diag = try self.reportToDiagnostic(report); try diags.append(self.allocator, diag); - rep.deinit(); } self.allocator.free(entry.reports); @@ -241,6 +245,50 @@ pub const SyntaxChecker = struct { log_file.sync() catch {}; } + /// Temporary suppression to avoid noisy undefined-variable diagnostics from BuildEnv. + fn shouldSuppressReport(_: *SyntaxChecker, rep: reporting.Report) bool { + if (!std.mem.startsWith(u8, rep.title, "UNDEFINED VARIABLE")) return false; + + const disallowed = [_][]const u8{ "Stderr", "Stdin", "Stdout" }; + return reportContainsAny(rep, &disallowed); + } + + fn reportContainsAny(rep: reporting.Report, needles: []const []const u8) bool { + var idx: usize = 0; + while (rep.document.getElement(idx)) |element| : (idx += 1) { + if (elementContainsAny(element, needles)) return true; + } + return false; + } + + fn elementContainsAny(element: reporting.DocumentElement, needles: []const []const u8) bool { + switch (element) { + .text => |t| return textHasAny(t, needles), + .annotated => |a| return textHasAny(a.content, needles), + .raw => |r| return textHasAny(r, needles), + .reflowing_text => |t| return textHasAny(t, needles), + .link => |l| return textHasAny(l, needles), + .vertical_stack => |stack| { + for (stack) |el| if (elementContainsAny(el, needles)) return true; + }, + .horizontal_concat => |concat| { + for (concat) |el| if (elementContainsAny(el, needles)) return true; + }, + .source_code_region => |region| return textHasAny(region.line_text, needles), + .source_code_multi_region => |multi| return textHasAny(multi.source, needles), + .source_code_with_underlines => |with_underlines| return textHasAny(with_underlines.display_region.line_text, needles), + else => {}, + } + return false; + } + + fn textHasAny(text: []const u8, needles: []const []const u8) bool { + for (needles) |needle| { + if (std.mem.indexOf(u8, text, needle) != null) return true; + } + return false; + } + const OverrideProvider = struct { override_path: []const u8, override_text: ?[]const u8,