aboutsummaryrefslogtreecommitdiff
path: root/src/Compilation.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2021-04-07 20:36:01 -0700
committerAndrew Kelley <andrew@ziglang.org>2021-04-07 20:36:01 -0700
commit12087d4cbaab39acadc29716e92765c92b92e28c (patch)
treebb5447848ff6bdd3477aac5ab193363fd666abcf /src/Compilation.zig
parent4996c2b6a94b042d86b50eb61c9d8d98e63415af (diff)
downloadzig-12087d4cbaab39acadc29716e92765c92b92e28c.tar.gz
zig-12087d4cbaab39acadc29716e92765c92b92e28c.zip
stage2: fix incremental compilation handling of parse errors
Before, incremental compilation would crash when trying to emit compile errors for the update after introducing a parse error. Parse errors are handled by not invalidating any existing semantic analysis. However, only the parse error must be reported, with all the other errors suppressed. Once the parse error is fixed, the new file can be treated as an update to the previously-succeeded update.
Diffstat (limited to 'src/Compilation.zig')
-rw-r--r--src/Compilation.zig38
1 files changed, 31 insertions, 7 deletions
diff --git a/src/Compilation.zig b/src/Compilation.zig
index 6bf0e004f3..080d4bddaa 100644
--- a/src/Compilation.zig
+++ b/src/Compilation.zig
@@ -1346,9 +1346,9 @@ pub fn update(self: *Compilation) !void {
module.generation += 1;
// TODO Detect which source files changed.
- // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
- // to force a refresh we unload now.
- module.root_scope.unload(module.gpa);
+ // Until then we simulate a full cache miss. Source files could have been loaded
+ // for any reason; to force a refresh we unload now.
+ module.unloadFile(module.root_scope);
module.failed_root_src_file = null;
module.analyzeContainer(&module.root_scope.root_container) catch |err| switch (err) {
error.AnalysisFail => {
@@ -1362,7 +1362,7 @@ pub fn update(self: *Compilation) !void {
// TODO only analyze imports if they are still referenced
for (module.import_table.items()) |entry| {
- entry.value.unload(module.gpa);
+ module.unloadFile(entry.value);
module.analyzeContainer(&entry.value.root_container) catch |err| switch (err) {
error.AnalysisFail => {
assert(self.totalErrorCount() != 0);
@@ -1432,11 +1432,25 @@ pub fn totalErrorCount(self: *Compilation) usize {
var total: usize = self.failed_c_objects.items().len;
if (self.bin_file.options.module) |module| {
- total += module.failed_decls.count() +
- module.emit_h_failed_decls.count() +
- module.failed_exports.items().len +
+ total += module.failed_exports.items().len +
module.failed_files.items().len +
@boolToInt(module.failed_root_src_file != null);
+ // Skip errors for Decls within files that failed parsing.
+ // When a parse error is introduced, we keep all the semantic analysis for
+ // the previous parse success, including compile errors, but we cannot
+ // emit them until the file succeeds parsing.
+ for (module.failed_decls.items()) |entry| {
+ if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
+ continue;
+ }
+ total += 1;
+ }
+ for (module.emit_h_failed_decls.items()) |entry| {
+ if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
+ continue;
+ }
+ total += 1;
+ }
}
// The "no entry point found" error only counts if there are no other errors.
@@ -1483,9 +1497,19 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
try AllErrors.add(module, &arena, &errors, entry.value.*);
}
for (module.failed_decls.items()) |entry| {
+ if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
+ // Skip errors for Decls within files that had a parse failure.
+ // We'll try again once parsing succeeds.
+ continue;
+ }
try AllErrors.add(module, &arena, &errors, entry.value.*);
}
for (module.emit_h_failed_decls.items()) |entry| {
+ if (entry.key.container.file_scope.status == .unloaded_parse_failure) {
+ // Skip errors for Decls within files that had a parse failure.
+ // We'll try again once parsing succeeds.
+ continue;
+ }
try AllErrors.add(module, &arena, &errors, entry.value.*);
}
for (module.failed_exports.items()) |entry| {