| author | |
| committer | |
| log | 91930a4ff08d275ec16507aed58a73a02742f831 |
| tree | 462147ea4e9b7f77b87188173381ea1ab6a42c29 |
| parent | cf654b52d68f20a403965e70371a9ad193370d8c |
3 files changed, 93 insertions(+), 11 deletions(-)
src-self-hosted/Module.zig+26-9| ... | ... | @@ -576,6 +576,8 @@ pub fn update(self: *Module) !void { |
| 576 | 576 | // TODO Use the cache hash file system to detect which source files changed. |
| 577 | 577 | // Here we simulate a full cache miss. |
| 578 | 578 | // Analyze the root source file now. |
| 579 | // Source files could have been loaded for any reason; to force a refresh we unload now. | |
| 580 | self.root_scope.unload(self.allocator); | |
| 579 | 581 | self.analyzeRoot(self.root_scope) catch |err| switch (err) { |
| 580 | 582 | error.AnalysisFail => { |
| 581 | 583 | assert(self.totalErrorCount() != 0); |
| ... | ... | @@ -594,8 +596,11 @@ pub fn update(self: *Module) !void { |
| 594 | 596 | try self.deleteDecl(decl); |
| 595 | 597 | } |
| 596 | 598 | |
| 597 | // Unload all the source files from memory. | |
| 598 | self.root_scope.unload(self.allocator); | |
| 599 | // If there are any errors, we anticipate the source files being loaded | |
| 600 | // to report error messages. Otherwise we unload all source files to save memory. | |
| 601 | if (self.totalErrorCount() == 0) { | |
| 602 | self.root_scope.unload(self.allocator); | |
| 603 | } | |
| 599 | 604 | |
| 600 | 605 | try self.bin_file.flush(); |
| 601 | 606 | self.link_error_flags = self.bin_file.error_flags; |
| ... | ... | @@ -878,11 +883,11 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 878 | 883 | const decl = kv.value; |
| 879 | 884 | deleted_decls.removeAssertDiscard(decl); |
| 880 | 885 | const new_contents_hash = Decl.hashSimpleName(src_decl.contents); |
| 886 | //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents }); | |
| 881 | 887 | if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) { |
| 882 | //std.debug.warn("noticed '{}' source changed\n", .{src_decl.name}); | |
| 883 | decl.analysis = .outdated; | |
| 888 | //std.debug.warn("'{}' {x} => {x}\n", .{ src_decl.name, decl.contents_hash, new_contents_hash }); | |
| 889 | try self.markOutdatedDecl(decl); | |
| 884 | 890 | decl.contents_hash = new_contents_hash; |
| 885 | try self.work_queue.writeItem(.{ .re_analyze_decl = decl }); | |
| 886 | 891 | } |
| 887 | 892 | } else if (src_decl.cast(zir.Inst.Export)) |export_inst| { |
| 888 | 893 | try exports_to_resolve.append(&export_inst.base); |
| ... | ... | @@ -923,8 +928,7 @@ fn deleteDecl(self: *Module, decl: *Decl) !void { |
| 923 | 928 | for (decl.dependants.items) |dep| { |
| 924 | 929 | dep.removeDependency(decl); |
| 925 | 930 | if (dep.analysis != .outdated) { |
| 926 | dep.analysis = .outdated; | |
| 927 | try self.work_queue.writeItem(.{ .re_analyze_decl = dep }); | |
| 931 | try self.markOutdatedDecl(dep); | |
| 928 | 932 | } |
| 929 | 933 | } |
| 930 | 934 | self.deleteDeclExports(decl); |
| ... | ... | @@ -1083,14 +1087,22 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi |
| 1083 | 1087 | .codegen_failure_retryable, |
| 1084 | 1088 | .complete, |
| 1085 | 1089 | => if (dep.generation != self.generation) { |
| 1086 | dep.analysis = .outdated; | |
| 1087 | try self.work_queue.writeItem(.{ .re_analyze_decl = dep }); | |
| 1090 | try self.markOutdatedDecl(dep); | |
| 1088 | 1091 | }, |
| 1089 | 1092 | } |
| 1090 | 1093 | } |
| 1091 | 1094 | } |
| 1092 | 1095 | } |
| 1093 | 1096 | |
| 1097 | fn markOutdatedDecl(self: *Module, decl: *Decl) !void { | |
| 1098 | //std.debug.warn("mark {} outdated\n", .{decl.name}); | |
| 1099 | try self.work_queue.writeItem(.{ .re_analyze_decl = decl }); | |
| 1100 | if (self.failed_decls.remove(decl)) |entry| { | |
| 1101 | self.allocator.destroy(entry.value); | |
| 1102 | } | |
| 1103 | decl.analysis = .outdated; | |
| 1104 | } | |
| 1105 | ||
| 1094 | 1106 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl { |
| 1095 | 1107 | const hash = Decl.hashSimpleName(old_inst.name); |
| 1096 | 1108 | if (self.decl_table.get(hash)) |kv| { |
| ... | ... | @@ -1445,6 +1457,7 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In |
| 1445 | 1457 | switch (old_inst.tag) { |
| 1446 | 1458 | .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?), |
| 1447 | 1459 | .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?), |
| 1460 | .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?), | |
| 1448 | 1461 | .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?), |
| 1449 | 1462 | .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?), |
| 1450 | 1463 | .str => { |
| ... | ... | @@ -1484,6 +1497,10 @@ fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In |
| 1484 | 1497 | } |
| 1485 | 1498 | } |
| 1486 | 1499 | |
| 1500 | fn analyzeInstCompileError(self: *Module, scope: *Scope, inst: *zir.Inst.CompileError) InnerError!*Inst { | |
| 1501 | return self.fail(scope, inst.base.src, "{}", .{inst.positionals.msg}); | |
| 1502 | } | |
| 1503 | ||
| 1487 | 1504 | fn analyzeInstBreakpoint(self: *Module, scope: *Scope, inst: *zir.Inst.Breakpoint) InnerError!*Inst { |
| 1488 | 1505 | const b = try self.requireRuntimeBlock(scope, inst.base.src); |
| 1489 | 1506 | return self.addNewInstArgs(b, inst.base.src, Type.initTag(.void), Inst.Breakpoint, Inst.Args(Inst.Breakpoint){}); |
src-self-hosted/main.zig+15-1| ... | ... | @@ -407,7 +407,21 @@ fn buildOutputType( |
| 407 | 407 | std.debug.warn("-fno-emit-bin not supported yet", .{}); |
| 408 | 408 | process.exit(1); |
| 409 | 409 | }, |
| 410 | .yes_default_path => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }), | |
| 410 | .yes_default_path => switch (output_mode) { | |
| 411 | .Exe => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.exeFileExt() }), | |
| 412 | .Lib => blk: { | |
| 413 | const suffix = switch (link_mode orelse .Static) { | |
| 414 | .Static => target_info.target.staticLibSuffix(), | |
| 415 | .Dynamic => target_info.target.dynamicLibSuffix(), | |
| 416 | }; | |
| 417 | break :blk try std.fmt.allocPrint(arena, "{}{}{}", .{ | |
| 418 | target_info.target.libPrefix(), | |
| 419 | root_name, | |
| 420 | suffix, | |
| 421 | }); | |
| 422 | }, | |
| 423 | .Obj => try std.fmt.allocPrint(arena, "{}{}", .{ root_name, target_info.target.oFileExt() }), | |
| 424 | }, | |
| 411 | 425 | .yes => |p| p, |
| 412 | 426 | }; |
| 413 | 427 |
src-self-hosted/zir.zig+52-1| ... | ... | @@ -27,6 +27,7 @@ pub const Inst = struct { |
| 27 | 27 | pub const Tag = enum { |
| 28 | 28 | breakpoint, |
| 29 | 29 | call, |
| 30 | compileerror, | |
| 30 | 31 | /// Represents a pointer to a global decl by name. |
| 31 | 32 | declref, |
| 32 | 33 | /// The syntax `@foo` is equivalent to `declval("foo")`. |
| ... | ... | @@ -62,6 +63,7 @@ pub const Inst = struct { |
| 62 | 63 | .call => Call, |
| 63 | 64 | .declref => DeclRef, |
| 64 | 65 | .declval => DeclVal, |
| 66 | .compileerror => CompileError, | |
| 65 | 67 | .str => Str, |
| 66 | 68 | .int => Int, |
| 67 | 69 | .ptrtoint => PtrToInt, |
| ... | ... | @@ -135,6 +137,16 @@ pub const Inst = struct { |
| 135 | 137 | kw_args: struct {}, |
| 136 | 138 | }; |
| 137 | 139 | |
| 140 | pub const CompileError = struct { | |
| 141 | pub const base_tag = Tag.compileerror; | |
| 142 | base: Inst, | |
| 143 | ||
| 144 | positionals: struct { | |
| 145 | msg: []const u8, | |
| 146 | }, | |
| 147 | kw_args: struct {}, | |
| 148 | }; | |
| 149 | ||
| 138 | 150 | pub const Str = struct { |
| 139 | 151 | pub const base_tag = Tag.str; |
| 140 | 152 | base: Inst, |
| ... | ... | @@ -513,6 +525,7 @@ pub const Module = struct { |
| 513 | 525 | .call => return self.writeInstToStreamGeneric(stream, .call, decl, inst_table), |
| 514 | 526 | .declref => return self.writeInstToStreamGeneric(stream, .declref, decl, inst_table), |
| 515 | 527 | .declval => return self.writeInstToStreamGeneric(stream, .declval, decl, inst_table), |
| 528 | .compileerror => return self.writeInstToStreamGeneric(stream, .compileerror, decl, inst_table), | |
| 516 | 529 | .str => return self.writeInstToStreamGeneric(stream, .str, decl, inst_table), |
| 517 | 530 | .int => return self.writeInstToStreamGeneric(stream, .int, decl, inst_table), |
| 518 | 531 | .ptrtoint => return self.writeInstToStreamGeneric(stream, .ptrtoint, decl, inst_table), |
| ... | ... | @@ -917,6 +930,7 @@ const Parser = struct { |
| 917 | 930 | try requireEatBytes(self, ")"); |
| 918 | 931 | |
| 919 | 932 | inst_specific.base.contents = self.source[contents_start..self.i]; |
| 933 | //std.debug.warn("parsed {} = '{}'\n", .{ inst_specific.base.name, inst_specific.base.contents }); | |
| 920 | 934 | |
| 921 | 935 | return &inst_specific.base; |
| 922 | 936 | } |
| ... | ... | @@ -1230,7 +1244,44 @@ const EmitZIR = struct { |
| 1230 | 1244 | var instructions = std.ArrayList(*Inst).init(self.allocator); |
| 1231 | 1245 | defer instructions.deinit(); |
| 1232 | 1246 | |
| 1233 | try self.emitBody(module_fn.analysis.success, &inst_table, &instructions); | |
| 1247 | switch (module_fn.analysis) { | |
| 1248 | .queued => unreachable, | |
| 1249 | .in_progress => unreachable, | |
| 1250 | .success => |body| { | |
| 1251 | try self.emitBody(body, &inst_table, &instructions); | |
| 1252 | }, | |
| 1253 | .sema_failure => { | |
| 1254 | const err_msg = self.old_module.failed_decls.getValue(module_fn.owner_decl).?; | |
| 1255 | const fail_inst = try self.arena.allocator.create(Inst.CompileError); | |
| 1256 | fail_inst.* = .{ | |
| 1257 | .base = .{ | |
| 1258 | .name = try self.autoName(), | |
| 1259 | .src = src, | |
| 1260 | .tag = Inst.CompileError.base_tag, | |
| 1261 | }, | |
| 1262 | .positionals = .{ | |
| 1263 | .msg = try self.arena.allocator.dupe(u8, err_msg.msg), | |
| 1264 | }, | |
| 1265 | .kw_args = .{}, | |
| 1266 | }; | |
| 1267 | try instructions.append(&fail_inst.base); | |
| 1268 | }, | |
| 1269 | .dependency_failure => { | |
| 1270 | const fail_inst = try self.arena.allocator.create(Inst.CompileError); | |
| 1271 | fail_inst.* = .{ | |
| 1272 | .base = .{ | |
| 1273 | .name = try self.autoName(), | |
| 1274 | .src = src, | |
| 1275 | .tag = Inst.CompileError.base_tag, | |
| 1276 | }, | |
| 1277 | .positionals = .{ | |
| 1278 | .msg = try self.arena.allocator.dupe(u8, "depends on another failed Decl"), | |
| 1279 | }, | |
| 1280 | .kw_args = .{}, | |
| 1281 | }; | |
| 1282 | try instructions.append(&fail_inst.base); | |
| 1283 | }, | |
| 1284 | } | |
| 1234 | 1285 | |
| 1235 | 1286 | const fn_type = try self.emitType(src, module_fn.fn_type); |
| 1236 | 1287 |