Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
50 changes: 50 additions & 0 deletions src/compile/compile_build.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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.

Expand Down Expand Up @@ -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
// ------------------------
Expand Down
52 changes: 50 additions & 2 deletions src/lsp/syntax.zig
Original file line number Diff line number Diff line change
Expand Up @@ -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);

Expand Down Expand Up @@ -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,
Expand Down
Loading