| ... | ... | @@ -15,13 +15,15 @@ const ir = @import("ir.zig"); |
| 15 | 15 | const zir = @import("zir.zig"); |
| 16 | 16 | const Module = @This(); |
| 17 | 17 | const Inst = ir.Inst; |
| 18 | const ast = std.zig.ast; |
| 18 | 19 | |
| 19 | 20 | /// General-purpose allocator. |
| 20 | 21 | allocator: *Allocator, |
| 21 | 22 | /// Pointer to externally managed resource. |
| 22 | 23 | root_pkg: *Package, |
| 23 | 24 | /// Module owns this resource. |
| 24 | | root_scope: *Scope.ZIRModule, |
| 25 | /// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`. |
| 26 | root_scope: *Scope, |
| 25 | 27 | bin_file: link.ElfFile, |
| 26 | 28 | bin_file_dir: std.fs.Dir, |
| 27 | 29 | bin_file_path: []const u8, |
| ... | ... | @@ -49,8 +51,8 @@ work_queue: std.fifo.LinearFifo(WorkItem, .Dynamic), |
| 49 | 51 | /// a Decl can have a failed_decls entry but have analysis status of success. |
| 50 | 52 | failed_decls: std.AutoHashMap(*Decl, *ErrorMsg), |
| 51 | 53 | /// Using a map here for consistency with the other fields here. |
| 52 | | /// The ErrorMsg memory is owned by the `Scope.ZIRModule`, using Module's allocator. |
| 53 | | failed_files: std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg), |
| 54 | /// The ErrorMsg memory is owned by the `Scope`, using Module's allocator. |
| 55 | failed_files: std.AutoHashMap(*Scope, *ErrorMsg), |
| 54 | 56 | /// Using a map here for consistency with the other fields here. |
| 55 | 57 | /// The ErrorMsg memory is owned by the `Export`, using Module's allocator. |
| 56 | 58 | failed_exports: std.AutoHashMap(*Export, *ErrorMsg), |
| ... | ... | @@ -64,11 +66,18 @@ generation: u32 = 0, |
| 64 | 66 | /// contains Decls that need to be deleted if they end up having no references to them. |
| 65 | 67 | deletion_set: std.ArrayListUnmanaged(*Decl) = std.ArrayListUnmanaged(*Decl){}, |
| 66 | 68 | |
| 67 | | pub const WorkItem = union(enum) { |
| 69 | const WorkItem = union(enum) { |
| 68 | 70 | /// Write the machine code for a Decl to the output file. |
| 69 | 71 | codegen_decl: *Decl, |
| 70 | 72 | /// Decl has been determined to be outdated; perform semantic analysis again. |
| 71 | 73 | re_analyze_decl: *Decl, |
| 74 | /// This AST node needs to be converted to a Decl and then semantically analyzed. |
| 75 | ast_gen_decl: AstGenDecl, |
| 76 | |
| 77 | const AstGenDecl = struct { |
| 78 | ast_node: *ast.Node, |
| 79 | scope: *Scope, |
| 80 | }; |
| 72 | 81 | }; |
| 73 | 82 | |
| 74 | 83 | pub const Export = struct { |
| ... | ... | @@ -99,10 +108,9 @@ pub const Decl = struct { |
| 99 | 108 | /// mapping them to an address in the output file. |
| 100 | 109 | /// Memory owned by this decl, using Module's allocator. |
| 101 | 110 | name: [*:0]const u8, |
| 102 | | /// The direct parent container of the Decl. This field will need to get more fleshed out when |
| 103 | | /// self-hosted supports proper struct types and Zig AST => ZIR. |
| 111 | /// The direct parent container of the Decl. This is either a `Scope.File` or `Scope.ZIRModule`. |
| 104 | 112 | /// Reference to externally owned memory. |
| 105 | | scope: *Scope.ZIRModule, |
| 113 | scope: *Scope, |
| 106 | 114 | /// Byte offset into the source file that contains this declaration. |
| 107 | 115 | /// This is the base offset that src offsets within this Decl are relative to. |
| 108 | 116 | src: usize, |
| ... | ... | @@ -171,17 +179,8 @@ pub const Decl = struct { |
| 171 | 179 | |
| 172 | 180 | pub const Hash = [16]u8; |
| 173 | 181 | |
| 174 | | /// If the name is small enough, it is used directly as the hash. |
| 175 | | /// If it is long, blake3 hash is computed. |
| 176 | 182 | pub fn hashSimpleName(name: []const u8) Hash { |
| 177 | | var out: Hash = undefined; |
| 178 | | if (name.len <= Hash.len) { |
| 179 | | mem.copy(u8, &out, name); |
| 180 | | mem.set(u8, out[name.len..], 0); |
| 181 | | } else { |
| 182 | | std.crypto.Blake3.hash(name, &out); |
| 183 | | } |
| 184 | | return out; |
| 183 | return std.zig.hashSrc(name); |
| 185 | 184 | } |
| 186 | 185 | |
| 187 | 186 | /// Must generate unique bytes with no collisions with other decls. |
| ... | ... | @@ -290,6 +289,7 @@ pub const Scope = struct { |
| 290 | 289 | .block => return self.cast(Block).?.arena, |
| 291 | 290 | .decl => return &self.cast(DeclAnalysis).?.arena.allocator, |
| 292 | 291 | .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator, |
| 292 | .file => unreachable, |
| 293 | 293 | } |
| 294 | 294 | } |
| 295 | 295 | |
| ... | ... | @@ -300,16 +300,27 @@ pub const Scope = struct { |
| 300 | 300 | .block => self.cast(Block).?.decl, |
| 301 | 301 | .decl => self.cast(DeclAnalysis).?.decl, |
| 302 | 302 | .zir_module => null, |
| 303 | .file => null, |
| 303 | 304 | }; |
| 304 | 305 | } |
| 305 | 306 | |
| 306 | | /// Asserts the scope has a parent which is a ZIRModule and |
| 307 | /// Asserts the scope has a parent which is a ZIRModule or File and |
| 307 | 308 | /// returns it. |
| 308 | | pub fn namespace(self: *Scope) *ZIRModule { |
| 309 | pub fn namespace(self: *Scope) *Scope { |
| 309 | 310 | switch (self.tag) { |
| 310 | 311 | .block => return self.cast(Block).?.decl.scope, |
| 311 | 312 | .decl => return self.cast(DeclAnalysis).?.decl.scope, |
| 312 | | .zir_module => return self.cast(ZIRModule).?, |
| 313 | .zir_module, .file => return self, |
| 314 | } |
| 315 | } |
| 316 | |
| 317 | /// Asserts the scope is a child of a File and has an AST tree and returns the tree. |
| 318 | pub fn tree(self: *Scope) *ast.Tree { |
| 319 | switch (self.tag) { |
| 320 | .file => return self.cast(File).?.contents.tree, |
| 321 | .zir_module => unreachable, |
| 322 | .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(File).?.contents.tree, |
| 323 | .block => return self.cast(Block).?.decl.scope.cast(File).?.contents.tree, |
| 313 | 324 | } |
| 314 | 325 | } |
| 315 | 326 | |
| ... | ... | @@ -325,12 +336,133 @@ pub const Scope = struct { |
| 325 | 336 | }); |
| 326 | 337 | } |
| 327 | 338 | |
| 339 | /// Asserts the scope has a parent which is a ZIRModule or File and |
| 340 | /// returns the sub_file_path field. |
| 341 | pub fn subFilePath(base: *Scope) []const u8 { |
| 342 | switch (base.tag) { |
| 343 | .file => return @fieldParentPtr(File, "base", base).sub_file_path, |
| 344 | .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path, |
| 345 | .block => unreachable, |
| 346 | .decl => unreachable, |
| 347 | } |
| 348 | } |
| 349 | |
| 350 | pub fn unload(base: *Scope, allocator: *Allocator) void { |
| 351 | switch (base.tag) { |
| 352 | .file => return @fieldParentPtr(File, "base", base).unload(allocator), |
| 353 | .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(allocator), |
| 354 | .block => unreachable, |
| 355 | .decl => unreachable, |
| 356 | } |
| 357 | } |
| 358 | |
| 359 | pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 { |
| 360 | switch (base.tag) { |
| 361 | .file => return @fieldParentPtr(File, "base", base).getSource(module), |
| 362 | .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module), |
| 363 | .block => unreachable, |
| 364 | .decl => unreachable, |
| 365 | } |
| 366 | } |
| 367 | |
| 368 | /// Asserts the scope is a File or ZIRModule and deinitializes it, then deallocates it. |
| 369 | pub fn destroy(base: *Scope, allocator: *Allocator) void { |
| 370 | switch (base.tag) { |
| 371 | .file => { |
| 372 | const scope_file = @fieldParentPtr(File, "base", base); |
| 373 | scope_file.deinit(allocator); |
| 374 | allocator.destroy(scope_file); |
| 375 | }, |
| 376 | .zir_module => { |
| 377 | const scope_zir_module = @fieldParentPtr(ZIRModule, "base", base); |
| 378 | scope_zir_module.deinit(allocator); |
| 379 | allocator.destroy(scope_zir_module); |
| 380 | }, |
| 381 | .block => unreachable, |
| 382 | .decl => unreachable, |
| 383 | } |
| 384 | } |
| 385 | |
| 328 | 386 | pub const Tag = enum { |
| 387 | /// .zir source code. |
| 329 | 388 | zir_module, |
| 389 | /// .zig source code. |
| 390 | file, |
| 330 | 391 | block, |
| 331 | 392 | decl, |
| 332 | 393 | }; |
| 333 | 394 | |
| 395 | pub const File = struct { |
| 396 | pub const base_tag: Tag = .file; |
| 397 | base: Scope = Scope{ .tag = base_tag }, |
| 398 | |
| 399 | /// Relative to the owning package's root_src_dir. |
| 400 | /// Reference to external memory, not owned by File. |
| 401 | sub_file_path: []const u8, |
| 402 | source: union(enum) { |
| 403 | unloaded: void, |
| 404 | bytes: [:0]const u8, |
| 405 | }, |
| 406 | contents: union { |
| 407 | not_available: void, |
| 408 | tree: *ast.Tree, |
| 409 | }, |
| 410 | status: enum { |
| 411 | never_loaded, |
| 412 | unloaded_success, |
| 413 | unloaded_parse_failure, |
| 414 | loaded_success, |
| 415 | }, |
| 416 | |
| 417 | pub fn unload(self: *File, allocator: *Allocator) void { |
| 418 | switch (self.status) { |
| 419 | .never_loaded, |
| 420 | .unloaded_parse_failure, |
| 421 | .unloaded_success, |
| 422 | => {}, |
| 423 | |
| 424 | .loaded_success => { |
| 425 | self.contents.tree.deinit(); |
| 426 | self.status = .unloaded_success; |
| 427 | }, |
| 428 | } |
| 429 | switch (self.source) { |
| 430 | .bytes => |bytes| { |
| 431 | allocator.free(bytes); |
| 432 | self.source = .{ .unloaded = {} }; |
| 433 | }, |
| 434 | .unloaded => {}, |
| 435 | } |
| 436 | } |
| 437 | |
| 438 | pub fn deinit(self: *File, allocator: *Allocator) void { |
| 439 | self.unload(allocator); |
| 440 | self.* = undefined; |
| 441 | } |
| 442 | |
| 443 | pub fn dumpSrc(self: *File, src: usize) void { |
| 444 | const loc = std.zig.findLineColumn(self.source.bytes, src); |
| 445 | std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 }); |
| 446 | } |
| 447 | |
| 448 | pub fn getSource(self: *File, module: *Module) ![:0]const u8 { |
| 449 | switch (self.source) { |
| 450 | .unloaded => { |
| 451 | const source = try module.root_pkg.root_src_dir.readFileAllocOptions( |
| 452 | module.allocator, |
| 453 | self.sub_file_path, |
| 454 | std.math.maxInt(u32), |
| 455 | 1, |
| 456 | 0, |
| 457 | ); |
| 458 | self.source = .{ .bytes = source }; |
| 459 | return source; |
| 460 | }, |
| 461 | .bytes => |bytes| return bytes, |
| 462 | } |
| 463 | } |
| 464 | }; |
| 465 | |
| 334 | 466 | pub const ZIRModule = struct { |
| 335 | 467 | pub const base_tag: Tag = .zir_module; |
| 336 | 468 | base: Scope = Scope{ .tag = base_tag }, |
| ... | ... | @@ -392,6 +524,23 @@ pub const Scope = struct { |
| 392 | 524 | const loc = std.zig.findLineColumn(self.source.bytes, src); |
| 393 | 525 | std.debug.warn("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 }); |
| 394 | 526 | } |
| 527 | |
| 528 | pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 { |
| 529 | switch (self.source) { |
| 530 | .unloaded => { |
| 531 | const source = try module.root_pkg.root_src_dir.readFileAllocOptions( |
| 532 | module.allocator, |
| 533 | self.sub_file_path, |
| 534 | std.math.maxInt(u32), |
| 535 | 1, |
| 536 | 0, |
| 537 | ); |
| 538 | self.source = .{ .bytes = source }; |
| 539 | return source; |
| 540 | }, |
| 541 | .bytes => |bytes| return bytes, |
| 542 | } |
| 543 | } |
| 395 | 544 | }; |
| 396 | 545 | |
| 397 | 546 | /// This is a temporary structure, references to it are valid only |
| ... | ... | @@ -466,16 +615,6 @@ pub const InitOptions = struct { |
| 466 | 615 | }; |
| 467 | 616 | |
| 468 | 617 | pub fn init(gpa: *Allocator, options: InitOptions) !Module { |
| 469 | | const root_scope = try gpa.create(Scope.ZIRModule); |
| 470 | | errdefer gpa.destroy(root_scope); |
| 471 | | |
| 472 | | root_scope.* = .{ |
| 473 | | .sub_file_path = options.root_pkg.root_src_path, |
| 474 | | .source = .{ .unloaded = {} }, |
| 475 | | .contents = .{ .not_available = {} }, |
| 476 | | .status = .never_loaded, |
| 477 | | }; |
| 478 | | |
| 479 | 618 | const bin_file_dir = options.bin_file_dir orelse std.fs.cwd(); |
| 480 | 619 | var bin_file = try link.openBinFilePath(gpa, bin_file_dir, options.bin_file_path, .{ |
| 481 | 620 | .target = options.target, |
| ... | ... | @@ -485,6 +624,30 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module { |
| 485 | 624 | }); |
| 486 | 625 | errdefer bin_file.deinit(); |
| 487 | 626 | |
| 627 | const root_scope = blk: { |
| 628 | if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zig")) { |
| 629 | const root_scope = try gpa.create(Scope.File); |
| 630 | root_scope.* = .{ |
| 631 | .sub_file_path = options.root_pkg.root_src_path, |
| 632 | .source = .{ .unloaded = {} }, |
| 633 | .contents = .{ .not_available = {} }, |
| 634 | .status = .never_loaded, |
| 635 | }; |
| 636 | break :blk &root_scope.base; |
| 637 | } else if (mem.endsWith(u8, options.root_pkg.root_src_path, ".zir")) { |
| 638 | const root_scope = try gpa.create(Scope.ZIRModule); |
| 639 | root_scope.* = .{ |
| 640 | .sub_file_path = options.root_pkg.root_src_path, |
| 641 | .source = .{ .unloaded = {} }, |
| 642 | .contents = .{ .not_available = {} }, |
| 643 | .status = .never_loaded, |
| 644 | }; |
| 645 | break :blk &root_scope.base; |
| 646 | } else { |
| 647 | unreachable; |
| 648 | } |
| 649 | }; |
| 650 | |
| 488 | 651 | return Module{ |
| 489 | 652 | .allocator = gpa, |
| 490 | 653 | .root_pkg = options.root_pkg, |
| ... | ... | @@ -497,7 +660,7 @@ pub fn init(gpa: *Allocator, options: InitOptions) !Module { |
| 497 | 660 | .decl_exports = std.AutoHashMap(*Decl, []*Export).init(gpa), |
| 498 | 661 | .export_owners = std.AutoHashMap(*Decl, []*Export).init(gpa), |
| 499 | 662 | .failed_decls = std.AutoHashMap(*Decl, *ErrorMsg).init(gpa), |
| 500 | | .failed_files = std.AutoHashMap(*Scope.ZIRModule, *ErrorMsg).init(gpa), |
| 663 | .failed_files = std.AutoHashMap(*Scope, *ErrorMsg).init(gpa), |
| 501 | 664 | .failed_exports = std.AutoHashMap(*Export, *ErrorMsg).init(gpa), |
| 502 | 665 | .work_queue = std.fifo.LinearFifo(WorkItem, .Dynamic).init(gpa), |
| 503 | 666 | }; |
| ... | ... | @@ -551,10 +714,7 @@ pub fn deinit(self: *Module) void { |
| 551 | 714 | } |
| 552 | 715 | self.export_owners.deinit(); |
| 553 | 716 | } |
| 554 | | { |
| 555 | | self.root_scope.deinit(allocator); |
| 556 | | allocator.destroy(self.root_scope); |
| 557 | | } |
| 717 | self.root_scope.destroy(allocator); |
| 558 | 718 | self.* = undefined; |
| 559 | 719 | } |
| 560 | 720 | |
| ... | ... | @@ -574,16 +734,25 @@ pub fn update(self: *Module) !void { |
| 574 | 734 | self.generation += 1; |
| 575 | 735 | |
| 576 | 736 | // TODO Use the cache hash file system to detect which source files changed. |
| 577 | | // Here we simulate a full cache miss. |
| 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); |
| 581 | | self.analyzeRoot(self.root_scope) catch |err| switch (err) { |
| 582 | | error.AnalysisFail => { |
| 583 | | assert(self.totalErrorCount() != 0); |
| 584 | | }, |
| 585 | | else => |e| return e, |
| 586 | | }; |
| 737 | // Until then we simulate a full cache miss. Source files could have been loaded for any reason; |
| 738 | // to force a refresh we unload now. |
| 739 | if (self.root_scope.cast(Scope.File)) |zig_file| { |
| 740 | zig_file.unload(self.allocator); |
| 741 | self.analyzeRootSrcFile(zig_file) catch |err| switch (err) { |
| 742 | error.AnalysisFail => { |
| 743 | assert(self.totalErrorCount() != 0); |
| 744 | }, |
| 745 | else => |e| return e, |
| 746 | }; |
| 747 | } else if (self.root_scope.cast(Scope.ZIRModule)) |zir_module| { |
| 748 | zir_module.unload(self.allocator); |
| 749 | self.analyzeRootZIRModule(zir_module) catch |err| switch (err) { |
| 750 | error.AnalysisFail => { |
| 751 | assert(self.totalErrorCount() != 0); |
| 752 | }, |
| 753 | else => |e| return e, |
| 754 | }; |
| 755 | } |
| 587 | 756 | |
| 588 | 757 | try self.performAllTheWork(); |
| 589 | 758 | |
| ... | ... | @@ -619,10 +788,10 @@ pub fn makeBinFileWritable(self: *Module) !void { |
| 619 | 788 | } |
| 620 | 789 | |
| 621 | 790 | pub fn totalErrorCount(self: *Module) usize { |
| 622 | | return self.failed_decls.size + |
| 791 | const total = self.failed_decls.size + |
| 623 | 792 | self.failed_files.size + |
| 624 | | self.failed_exports.size + |
| 625 | | @boolToInt(self.link_error_flags.no_entry_point_found); |
| 793 | self.failed_exports.size; |
| 794 | return if (total == 0) @boolToInt(self.link_error_flags.no_entry_point_found) else total; |
| 626 | 795 | } |
| 627 | 796 | |
| 628 | 797 | pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| ... | ... | @@ -637,8 +806,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| 637 | 806 | while (it.next()) |kv| { |
| 638 | 807 | const scope = kv.key; |
| 639 | 808 | const err_msg = kv.value; |
| 640 | | const source = try self.getSource(scope); |
| 641 | | try AllErrors.add(&arena, &errors, scope.sub_file_path, source, err_msg.*); |
| 809 | const source = try scope.getSource(self); |
| 810 | try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*); |
| 642 | 811 | } |
| 643 | 812 | } |
| 644 | 813 | { |
| ... | ... | @@ -646,8 +815,8 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| 646 | 815 | while (it.next()) |kv| { |
| 647 | 816 | const decl = kv.key; |
| 648 | 817 | const err_msg = kv.value; |
| 649 | | const source = try self.getSource(decl.scope); |
| 650 | | try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*); |
| 818 | const source = try decl.scope.getSource(self); |
| 819 | try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*); |
| 651 | 820 | } |
| 652 | 821 | } |
| 653 | 822 | { |
| ... | ... | @@ -655,12 +824,12 @@ pub fn getAllErrorsAlloc(self: *Module) !AllErrors { |
| 655 | 824 | while (it.next()) |kv| { |
| 656 | 825 | const decl = kv.key.owner_decl; |
| 657 | 826 | const err_msg = kv.value; |
| 658 | | const source = try self.getSource(decl.scope); |
| 659 | | try AllErrors.add(&arena, &errors, decl.scope.sub_file_path, source, err_msg.*); |
| 827 | const source = try decl.scope.getSource(self); |
| 828 | try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*); |
| 660 | 829 | } |
| 661 | 830 | } |
| 662 | 831 | |
| 663 | | if (self.link_error_flags.no_entry_point_found) { |
| 832 | if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) { |
| 664 | 833 | try errors.append(.{ |
| 665 | 834 | .src_path = self.root_pkg.root_src_path, |
| 666 | 835 | .line = 0, |
| ... | ... | @@ -740,30 +909,491 @@ pub fn performAllTheWork(self: *Module) error{OutOfMemory}!void { |
| 740 | 909 | => continue, |
| 741 | 910 | |
| 742 | 911 | .outdated => { |
| 743 | | const zir_module = self.getSrcModule(decl.scope) catch |err| switch (err) { |
| 744 | | error.OutOfMemory => return error.OutOfMemory, |
| 745 | | else => { |
| 746 | | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); |
| 747 | | self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( |
| 748 | | self.allocator, |
| 749 | | decl.src, |
| 750 | | "unable to load source file '{}': {}", |
| 751 | | .{ decl.scope.sub_file_path, @errorName(err) }, |
| 752 | | )); |
| 753 | | decl.analysis = .codegen_failure_retryable; |
| 754 | | continue; |
| 755 | | }, |
| 756 | | }; |
| 757 | | const decl_name = mem.spanZ(decl.name); |
| 758 | | // We already detected deletions, so we know this will be found. |
| 759 | | const src_decl = zir_module.findDecl(decl_name).?; |
| 760 | | self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) { |
| 761 | | error.OutOfMemory => return error.OutOfMemory, |
| 762 | | error.AnalysisFail => continue, |
| 763 | | }; |
| 912 | if (decl.scope.cast(Scope.File)) |file_scope| { |
| 913 | @panic("TODO re_analyze_decl for .zig files"); |
| 914 | } else if (decl.scope.cast(Scope.ZIRModule)) |zir_scope| { |
| 915 | const zir_module = self.getSrcModule(zir_scope) catch |err| switch (err) { |
| 916 | error.OutOfMemory => return error.OutOfMemory, |
| 917 | else => { |
| 918 | try self.failed_decls.ensureCapacity(self.failed_decls.size + 1); |
| 919 | self.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create( |
| 920 | self.allocator, |
| 921 | decl.src, |
| 922 | "unable to load source file '{}': {}", |
| 923 | .{ zir_scope.sub_file_path, @errorName(err) }, |
| 924 | )); |
| 925 | decl.analysis = .codegen_failure_retryable; |
| 926 | continue; |
| 927 | }, |
| 928 | }; |
| 929 | const decl_name = mem.spanZ(decl.name); |
| 930 | // We already detected deletions, so we know this will be found. |
| 931 | const src_decl = zir_module.findDecl(decl_name).?; |
| 932 | self.reAnalyzeDecl(decl, src_decl) catch |err| switch (err) { |
| 933 | error.OutOfMemory => return error.OutOfMemory, |
| 934 | error.AnalysisFail => continue, |
| 935 | }; |
| 936 | } else { |
| 937 | unreachable; |
| 938 | } |
| 939 | }, |
| 940 | }, |
| 941 | .ast_gen_decl => |item| { |
| 942 | self.astGenDecl(item.scope, item.ast_node) catch |err| switch (err) { |
| 943 | error.OutOfMemory => return error.OutOfMemory, |
| 944 | error.AnalysisFail => continue, |
| 945 | }; |
| 946 | }, |
| 947 | }; |
| 948 | } |
| 949 | |
| 950 | fn astGenDecl(self: *Module, parent_scope: *Scope, ast_node: *ast.Node) !void { |
| 951 | switch (ast_node.id) { |
| 952 | .FnProto => { |
| 953 | const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node); |
| 954 | |
| 955 | const name_tok = fn_proto.name_token orelse |
| 956 | return self.failTok(parent_scope, fn_proto.fn_token, "missing function name", .{}); |
| 957 | const tree = parent_scope.tree(); |
| 958 | const name_loc = tree.token_locs[name_tok]; |
| 959 | const name = tree.tokenSliceLoc(name_loc); |
| 960 | const name_hash = Decl.hashSimpleName(name); |
| 961 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(ast_node)); |
| 962 | const new_decl = try self.createNewDecl(parent_scope, name, name_loc.start, name_hash, contents_hash); |
| 963 | |
| 964 | // This DeclAnalysis scope's arena memory is discarded after the ZIR generation |
| 965 | // pass completes, and semantic analysis of it completes. |
| 966 | var gen_scope: Scope.DeclAnalysis = .{ |
| 967 | .decl = new_decl, |
| 968 | .arena = std.heap.ArenaAllocator.init(self.allocator), |
| 969 | }; |
| 970 | // TODO free this memory |
| 971 | //defer gen_scope.arena.deinit(); |
| 972 | |
| 973 | const body_node = fn_proto.body_node orelse |
| 974 | return self.failTok(&gen_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{}); |
| 975 | if (fn_proto.params_len != 0) { |
| 976 | return self.failTok( |
| 977 | &gen_scope.base, |
| 978 | fn_proto.params()[0].name_token.?, |
| 979 | "TODO implement function parameters", |
| 980 | .{}, |
| 981 | ); |
| 982 | } |
| 983 | if (fn_proto.lib_name) |lib_name| { |
| 984 | return self.failNode(&gen_scope.base, lib_name, "TODO implement function library name", .{}); |
| 985 | } |
| 986 | if (fn_proto.align_expr) |align_expr| { |
| 987 | return self.failNode(&gen_scope.base, align_expr, "TODO implement function align expression", .{}); |
| 988 | } |
| 989 | if (fn_proto.section_expr) |sect_expr| { |
| 990 | return self.failNode(&gen_scope.base, sect_expr, "TODO implement function section expression", .{}); |
| 991 | } |
| 992 | if (fn_proto.callconv_expr) |callconv_expr| { |
| 993 | return self.failNode( |
| 994 | &gen_scope.base, |
| 995 | callconv_expr, |
| 996 | "TODO implement function calling convention expression", |
| 997 | .{}, |
| 998 | ); |
| 999 | } |
| 1000 | const return_type_expr = switch (fn_proto.return_type) { |
| 1001 | .Explicit => |node| node, |
| 1002 | .InferErrorSet => |node| return self.failNode(&gen_scope.base, node, "TODO implement inferred error sets", .{}), |
| 1003 | .Invalid => |tok| return self.failTok(&gen_scope.base, tok, "unable to parse return type", .{}), |
| 1004 | }; |
| 1005 | |
| 1006 | const return_type_inst = try self.astGenExpr(&gen_scope.base, return_type_expr); |
| 1007 | const body_block = body_node.cast(ast.Node.Block).?; |
| 1008 | const body = try self.astGenBlock(&gen_scope.base, body_block); |
| 1009 | const fn_type_inst = try gen_scope.arena.allocator.create(zir.Inst.FnType); |
| 1010 | fn_type_inst.* = .{ |
| 1011 | .base = .{ |
| 1012 | .tag = zir.Inst.FnType.base_tag, |
| 1013 | .name = "", |
| 1014 | .src = name_loc.start, |
| 1015 | }, |
| 1016 | .positionals = .{ |
| 1017 | .return_type = return_type_inst, |
| 1018 | .param_types = &[0]*zir.Inst{}, |
| 1019 | }, |
| 1020 | .kw_args = .{}, |
| 1021 | }; |
| 1022 | const fn_inst = try gen_scope.arena.allocator.create(zir.Inst.Fn); |
| 1023 | fn_inst.* = .{ |
| 1024 | .base = .{ |
| 1025 | .tag = zir.Inst.Fn.base_tag, |
| 1026 | .name = name, |
| 1027 | .src = name_loc.start, |
| 1028 | .contents_hash = contents_hash, |
| 1029 | }, |
| 1030 | .positionals = .{ |
| 1031 | .fn_type = &fn_type_inst.base, |
| 1032 | .body = body, |
| 1033 | }, |
| 1034 | .kw_args = .{}, |
| 1035 | }; |
| 1036 | try self.analyzeNewDecl(new_decl, &fn_inst.base); |
| 1037 | |
| 1038 | if (fn_proto.extern_export_inline_token) |maybe_export_token| { |
| 1039 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { |
| 1040 | var str_inst = zir.Inst.Str{ |
| 1041 | .base = .{ |
| 1042 | .tag = zir.Inst.Str.base_tag, |
| 1043 | .name = "", |
| 1044 | .src = name_loc.start, |
| 1045 | }, |
| 1046 | .positionals = .{ |
| 1047 | .bytes = name, |
| 1048 | }, |
| 1049 | .kw_args = .{}, |
| 1050 | }; |
| 1051 | var ref_inst = zir.Inst.Ref{ |
| 1052 | .base = .{ |
| 1053 | .tag = zir.Inst.Ref.base_tag, |
| 1054 | .name = "", |
| 1055 | .src = name_loc.start, |
| 1056 | }, |
| 1057 | .positionals = .{ |
| 1058 | .operand = &str_inst.base, |
| 1059 | }, |
| 1060 | .kw_args = .{}, |
| 1061 | }; |
| 1062 | var export_inst = zir.Inst.Export{ |
| 1063 | .base = .{ |
| 1064 | .tag = zir.Inst.Export.base_tag, |
| 1065 | .name = "", |
| 1066 | .src = name_loc.start, |
| 1067 | .contents_hash = contents_hash, |
| 1068 | }, |
| 1069 | .positionals = .{ |
| 1070 | .symbol_name = &ref_inst.base, |
| 1071 | .value = &fn_inst.base, |
| 1072 | }, |
| 1073 | .kw_args = .{}, |
| 1074 | }; |
| 1075 | // Here we analyze the export using the arena that expires at the end of this |
| 1076 | // function call. |
| 1077 | try self.analyzeExport(&gen_scope.base, &export_inst); |
| 1078 | } |
| 1079 | } |
| 1080 | }, |
| 1081 | .VarDecl => @panic("TODO var decl"), |
| 1082 | .Comptime => @panic("TODO comptime decl"), |
| 1083 | .Use => @panic("TODO usingnamespace decl"), |
| 1084 | else => unreachable, |
| 1085 | } |
| 1086 | } |
| 1087 | |
| 1088 | fn astGenExpr(self: *Module, scope: *Scope, ast_node: *ast.Node) InnerError!*zir.Inst { |
| 1089 | switch (ast_node.id) { |
| 1090 | .Identifier => return self.astGenIdent(scope, @fieldParentPtr(ast.Node.Identifier, "base", ast_node)), |
| 1091 | .Asm => return self.astGenAsm(scope, @fieldParentPtr(ast.Node.Asm, "base", ast_node)), |
| 1092 | .StringLiteral => return self.astGenStringLiteral(scope, @fieldParentPtr(ast.Node.StringLiteral, "base", ast_node)), |
| 1093 | .IntegerLiteral => return self.astGenIntegerLiteral(scope, @fieldParentPtr(ast.Node.IntegerLiteral, "base", ast_node)), |
| 1094 | .BuiltinCall => return self.astGenBuiltinCall(scope, @fieldParentPtr(ast.Node.BuiltinCall, "base", ast_node)), |
| 1095 | .Unreachable => return self.astGenUnreachable(scope, @fieldParentPtr(ast.Node.Unreachable, "base", ast_node)), |
| 1096 | else => return self.failNode(scope, ast_node, "TODO implement astGenExpr for {}", .{@tagName(ast_node.id)}), |
| 1097 | } |
| 1098 | } |
| 1099 | |
| 1100 | fn astGenIdent(self: *Module, scope: *Scope, ident: *ast.Node.Identifier) InnerError!*zir.Inst { |
| 1101 | const tree = scope.tree(); |
| 1102 | const ident_name = tree.tokenSlice(ident.token); |
| 1103 | if (mem.eql(u8, ident_name, "_")) { |
| 1104 | return self.failNode(scope, &ident.base, "TODO implement '_' identifier", .{}); |
| 1105 | } |
| 1106 | |
| 1107 | if (getSimplePrimitiveValue(ident_name)) |typed_value| { |
| 1108 | const const_inst = try scope.arena().create(zir.Inst.Const); |
| 1109 | const_inst.* = .{ |
| 1110 | .base = .{ |
| 1111 | .tag = zir.Inst.Const.base_tag, |
| 1112 | .name = "", |
| 1113 | .src = tree.token_locs[ident.token].start, |
| 1114 | }, |
| 1115 | .positionals = .{ |
| 1116 | .typed_value = typed_value, |
| 1117 | }, |
| 1118 | .kw_args = .{}, |
| 1119 | }; |
| 1120 | return &const_inst.base; |
| 1121 | } |
| 1122 | |
| 1123 | if (ident_name.len >= 2) integer: { |
| 1124 | const first_c = ident_name[0]; |
| 1125 | if (first_c == 'i' or first_c == 'u') { |
| 1126 | const is_signed = first_c == 'i'; |
| 1127 | const bit_count = std.fmt.parseInt(u16, ident_name[1..], 10) catch |err| switch (err) { |
| 1128 | error.Overflow => return self.failNode( |
| 1129 | scope, |
| 1130 | &ident.base, |
| 1131 | "primitive integer type '{}' exceeds maximum bit width of 65535", |
| 1132 | .{ident_name}, |
| 1133 | ), |
| 1134 | error.InvalidCharacter => break :integer, |
| 1135 | }; |
| 1136 | return self.failNode(scope, &ident.base, "TODO implement arbitrary integer bitwidth types", .{}); |
| 1137 | } |
| 1138 | } |
| 1139 | |
| 1140 | return self.failNode(scope, &ident.base, "TODO implement identifier lookup", .{}); |
| 1141 | } |
| 1142 | |
| 1143 | fn astGenStringLiteral(self: *Module, scope: *Scope, str_lit: *ast.Node.StringLiteral) InnerError!*zir.Inst { |
| 1144 | const tree = scope.tree(); |
| 1145 | const unparsed_bytes = tree.tokenSlice(str_lit.token); |
| 1146 | const arena = scope.arena(); |
| 1147 | |
| 1148 | var bad_index: usize = undefined; |
| 1149 | const bytes = std.zig.parseStringLiteral(arena, unparsed_bytes, &bad_index) catch |err| switch (err) { |
| 1150 | error.InvalidCharacter => { |
| 1151 | const bad_byte = unparsed_bytes[bad_index]; |
| 1152 | const src = tree.token_locs[str_lit.token].start; |
| 1153 | return self.fail(scope, src + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte}); |
| 1154 | }, |
| 1155 | else => |e| return e, |
| 1156 | }; |
| 1157 | |
| 1158 | var str_inst = try arena.create(zir.Inst.Str); |
| 1159 | str_inst.* = .{ |
| 1160 | .base = .{ |
| 1161 | .tag = zir.Inst.Str.base_tag, |
| 1162 | .name = "", |
| 1163 | .src = tree.token_locs[str_lit.token].start, |
| 1164 | }, |
| 1165 | .positionals = .{ |
| 1166 | .bytes = bytes, |
| 1167 | }, |
| 1168 | .kw_args = .{}, |
| 1169 | }; |
| 1170 | var ref_inst = try arena.create(zir.Inst.Ref); |
| 1171 | ref_inst.* = .{ |
| 1172 | .base = .{ |
| 1173 | .tag = zir.Inst.Ref.base_tag, |
| 1174 | .name = "", |
| 1175 | .src = tree.token_locs[str_lit.token].start, |
| 1176 | }, |
| 1177 | .positionals = .{ |
| 1178 | .operand = &str_inst.base, |
| 1179 | }, |
| 1180 | .kw_args = .{}, |
| 1181 | }; |
| 1182 | return &ref_inst.base; |
| 1183 | } |
| 1184 | |
| 1185 | fn astGenIntegerLiteral(self: *Module, scope: *Scope, int_lit: *ast.Node.IntegerLiteral) InnerError!*zir.Inst { |
| 1186 | const arena = scope.arena(); |
| 1187 | const tree = scope.tree(); |
| 1188 | const bytes = tree.tokenSlice(int_lit.token); |
| 1189 | |
| 1190 | if (mem.startsWith(u8, bytes, "0x")) { |
| 1191 | return self.failTok(scope, int_lit.token, "TODO implement 0x int prefix", .{}); |
| 1192 | } else if (mem.startsWith(u8, bytes, "0o")) { |
| 1193 | return self.failTok(scope, int_lit.token, "TODO implement 0o int prefix", .{}); |
| 1194 | } else if (mem.startsWith(u8, bytes, "0b")) { |
| 1195 | return self.failTok(scope, int_lit.token, "TODO implement 0b int prefix", .{}); |
| 1196 | } |
| 1197 | if (std.fmt.parseInt(u64, bytes, 10)) |small_int| { |
| 1198 | var int_payload = try arena.create(Value.Payload.Int_u64); |
| 1199 | int_payload.* = .{ |
| 1200 | .int = small_int, |
| 1201 | }; |
| 1202 | var const_inst = try arena.create(zir.Inst.Const); |
| 1203 | const_inst.* = .{ |
| 1204 | .base = .{ |
| 1205 | .tag = zir.Inst.Const.base_tag, |
| 1206 | .name = "", |
| 1207 | .src = tree.token_locs[int_lit.token].start, |
| 764 | 1208 | }, |
| 1209 | .positionals = .{ |
| 1210 | .typed_value = .{ |
| 1211 | .ty = Type.initTag(.comptime_int), |
| 1212 | .val = Value.initPayload(&int_payload.base), |
| 1213 | }, |
| 1214 | }, |
| 1215 | .kw_args = .{}, |
| 1216 | }; |
| 1217 | return &const_inst.base; |
| 1218 | } else |err| { |
| 1219 | return self.failTok(scope, int_lit.token, "TODO implement int literals that don't fit in a u64", .{}); |
| 1220 | } |
| 1221 | } |
| 1222 | |
| 1223 | fn astGenBlock(self: *Module, scope: *Scope, block_node: *ast.Node.Block) !zir.Module.Body { |
| 1224 | if (block_node.label) |label| { |
| 1225 | return self.failTok(scope, label, "TODO implement labeled blocks", .{}); |
| 1226 | } |
| 1227 | const arena = scope.arena(); |
| 1228 | var instructions = std.ArrayList(*zir.Inst).init(arena); |
| 1229 | |
| 1230 | try instructions.ensureCapacity(block_node.statements_len); |
| 1231 | |
| 1232 | for (block_node.statements()) |statement| { |
| 1233 | const inst = try self.astGenExpr(scope, statement); |
| 1234 | instructions.appendAssumeCapacity(inst); |
| 1235 | } |
| 1236 | |
| 1237 | return zir.Module.Body{ |
| 1238 | .instructions = instructions.items, |
| 1239 | }; |
| 1240 | } |
| 1241 | |
| 1242 | fn astGenAsm(self: *Module, scope: *Scope, asm_node: *ast.Node.Asm) InnerError!*zir.Inst { |
| 1243 | if (asm_node.outputs.len != 0) { |
| 1244 | return self.failNode(scope, &asm_node.base, "TODO implement asm with an output", .{}); |
| 1245 | } |
| 1246 | const arena = scope.arena(); |
| 1247 | const tree = scope.tree(); |
| 1248 | |
| 1249 | const inputs = try arena.alloc(*zir.Inst, asm_node.inputs.len); |
| 1250 | const args = try arena.alloc(*zir.Inst, asm_node.inputs.len); |
| 1251 | |
| 1252 | for (asm_node.inputs) |input, i| { |
| 1253 | // TODO semantically analyze constraints |
| 1254 | inputs[i] = try self.astGenExpr(scope, input.constraint); |
| 1255 | args[i] = try self.astGenExpr(scope, input.expr); |
| 1256 | } |
| 1257 | |
| 1258 | const return_type = try arena.create(zir.Inst.Const); |
| 1259 | return_type.* = .{ |
| 1260 | .base = .{ |
| 1261 | .tag = zir.Inst.Const.base_tag, |
| 1262 | .name = "", |
| 1263 | .src = tree.token_locs[asm_node.asm_token].start, |
| 1264 | }, |
| 1265 | .positionals = .{ |
| 1266 | .typed_value = .{ |
| 1267 | .ty = Type.initTag(.type), |
| 1268 | .val = Value.initTag(.void_type), |
| 1269 | }, |
| 1270 | }, |
| 1271 | .kw_args = .{}, |
| 1272 | }; |
| 1273 | |
| 1274 | const asm_inst = try arena.create(zir.Inst.Asm); |
| 1275 | asm_inst.* = .{ |
| 1276 | .base = .{ |
| 1277 | .tag = zir.Inst.Asm.base_tag, |
| 1278 | .name = "", |
| 1279 | .src = tree.token_locs[asm_node.asm_token].start, |
| 1280 | }, |
| 1281 | .positionals = .{ |
| 1282 | .asm_source = try self.astGenExpr(scope, asm_node.template), |
| 1283 | .return_type = &return_type.base, |
| 1284 | }, |
| 1285 | .kw_args = .{ |
| 1286 | .@"volatile" = asm_node.volatile_token != null, |
| 1287 | //.clobbers = TODO handle clobbers |
| 1288 | .inputs = inputs, |
| 1289 | .args = args, |
| 1290 | }, |
| 1291 | }; |
| 1292 | return &asm_inst.base; |
| 1293 | } |
| 1294 | |
| 1295 | fn astGenBuiltinCall(self: *Module, scope: *Scope, call: *ast.Node.BuiltinCall) InnerError!*zir.Inst { |
| 1296 | const tree = scope.tree(); |
| 1297 | const builtin_name = tree.tokenSlice(call.builtin_token); |
| 1298 | const arena = scope.arena(); |
| 1299 | |
| 1300 | if (mem.eql(u8, builtin_name, "@ptrToInt")) { |
| 1301 | if (call.params_len != 1) { |
| 1302 | return self.failTok(scope, call.builtin_token, "expected 1 parameter, found {}", .{call.params_len}); |
| 1303 | } |
| 1304 | const ptrtoint = try arena.create(zir.Inst.PtrToInt); |
| 1305 | ptrtoint.* = .{ |
| 1306 | .base = .{ |
| 1307 | .tag = zir.Inst.PtrToInt.base_tag, |
| 1308 | .name = "", |
| 1309 | .src = tree.token_locs[call.builtin_token].start, |
| 1310 | }, |
| 1311 | .positionals = .{ |
| 1312 | .ptr = try self.astGenExpr(scope, call.params()[0]), |
| 1313 | }, |
| 1314 | .kw_args = .{}, |
| 1315 | }; |
| 1316 | return &ptrtoint.base; |
| 1317 | } else { |
| 1318 | return self.failTok(scope, call.builtin_token, "TODO implement builtin call for '{}'", .{builtin_name}); |
| 1319 | } |
| 1320 | } |
| 1321 | |
| 1322 | fn astGenUnreachable(self: *Module, scope: *Scope, unreach_node: *ast.Node.Unreachable) InnerError!*zir.Inst { |
| 1323 | const tree = scope.tree(); |
| 1324 | const arena = scope.arena(); |
| 1325 | const unreach = try arena.create(zir.Inst.Unreachable); |
| 1326 | unreach.* = .{ |
| 1327 | .base = .{ |
| 1328 | .tag = zir.Inst.Unreachable.base_tag, |
| 1329 | .name = "", |
| 1330 | .src = tree.token_locs[unreach_node.token].start, |
| 765 | 1331 | }, |
| 1332 | .positionals = .{}, |
| 1333 | .kw_args = .{}, |
| 766 | 1334 | }; |
| 1335 | return &unreach.base; |
| 1336 | } |
| 1337 | |
| 1338 | fn getSimplePrimitiveValue(name: []const u8) ?TypedValue { |
| 1339 | const simple_types = std.ComptimeStringMap(Value.Tag, .{ |
| 1340 | .{ "u8", .u8_type }, |
| 1341 | .{ "i8", .i8_type }, |
| 1342 | .{ "isize", .isize_type }, |
| 1343 | .{ "usize", .usize_type }, |
| 1344 | .{ "c_short", .c_short_type }, |
| 1345 | .{ "c_ushort", .c_ushort_type }, |
| 1346 | .{ "c_int", .c_int_type }, |
| 1347 | .{ "c_uint", .c_uint_type }, |
| 1348 | .{ "c_long", .c_long_type }, |
| 1349 | .{ "c_ulong", .c_ulong_type }, |
| 1350 | .{ "c_longlong", .c_longlong_type }, |
| 1351 | .{ "c_ulonglong", .c_ulonglong_type }, |
| 1352 | .{ "c_longdouble", .c_longdouble_type }, |
| 1353 | .{ "f16", .f16_type }, |
| 1354 | .{ "f32", .f32_type }, |
| 1355 | .{ "f64", .f64_type }, |
| 1356 | .{ "f128", .f128_type }, |
| 1357 | .{ "c_void", .c_void_type }, |
| 1358 | .{ "bool", .bool_type }, |
| 1359 | .{ "void", .void_type }, |
| 1360 | .{ "type", .type_type }, |
| 1361 | .{ "anyerror", .anyerror_type }, |
| 1362 | .{ "comptime_int", .comptime_int_type }, |
| 1363 | .{ "comptime_float", .comptime_float_type }, |
| 1364 | .{ "noreturn", .noreturn_type }, |
| 1365 | }); |
| 1366 | if (simple_types.get(name)) |tag| { |
| 1367 | return TypedValue{ |
| 1368 | .ty = Type.initTag(.type), |
| 1369 | .val = Value.initTag(tag), |
| 1370 | }; |
| 1371 | } |
| 1372 | if (mem.eql(u8, name, "null")) { |
| 1373 | return TypedValue{ |
| 1374 | .ty = Type.initTag(.@"null"), |
| 1375 | .val = Value.initTag(.null_value), |
| 1376 | }; |
| 1377 | } |
| 1378 | if (mem.eql(u8, name, "undefined")) { |
| 1379 | return TypedValue{ |
| 1380 | .ty = Type.initTag(.@"undefined"), |
| 1381 | .val = Value.initTag(.undef), |
| 1382 | }; |
| 1383 | } |
| 1384 | if (mem.eql(u8, name, "true")) { |
| 1385 | return TypedValue{ |
| 1386 | .ty = Type.initTag(.bool), |
| 1387 | .val = Value.initTag(.bool_true), |
| 1388 | }; |
| 1389 | } |
| 1390 | if (mem.eql(u8, name, "false")) { |
| 1391 | return TypedValue{ |
| 1392 | .ty = Type.initTag(.bool), |
| 1393 | .val = Value.initTag(.bool_false), |
| 1394 | }; |
| 1395 | } |
| 1396 | return null; |
| 767 | 1397 | } |
| 768 | 1398 | |
| 769 | 1399 | fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void { |
| ... | ... | @@ -783,29 +1413,12 @@ fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void |
| 783 | 1413 | } |
| 784 | 1414 | } |
| 785 | 1415 | |
| 786 | | fn getSource(self: *Module, root_scope: *Scope.ZIRModule) ![:0]const u8 { |
| 787 | | switch (root_scope.source) { |
| 788 | | .unloaded => { |
| 789 | | const source = try self.root_pkg.root_src_dir.readFileAllocOptions( |
| 790 | | self.allocator, |
| 791 | | root_scope.sub_file_path, |
| 792 | | std.math.maxInt(u32), |
| 793 | | 1, |
| 794 | | 0, |
| 795 | | ); |
| 796 | | root_scope.source = .{ .bytes = source }; |
| 797 | | return source; |
| 798 | | }, |
| 799 | | .bytes => |bytes| return bytes, |
| 800 | | } |
| 801 | | } |
| 802 | | |
| 803 | 1416 | fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module { |
| 804 | 1417 | switch (root_scope.status) { |
| 805 | 1418 | .never_loaded, .unloaded_success => { |
| 806 | 1419 | try self.failed_files.ensureCapacity(self.failed_files.size + 1); |
| 807 | 1420 | |
| 808 | | const source = try self.getSource(root_scope); |
| 1421 | const source = try root_scope.getSource(self); |
| 809 | 1422 | |
| 810 | 1423 | var keep_zir_module = false; |
| 811 | 1424 | const zir_module = try self.allocator.create(zir.Module); |
| ... | ... | @@ -816,7 +1429,7 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module { |
| 816 | 1429 | |
| 817 | 1430 | if (zir_module.error_msg) |src_err_msg| { |
| 818 | 1431 | self.failed_files.putAssumeCapacityNoClobber( |
| 819 | | root_scope, |
| 1432 | &root_scope.base, |
| 820 | 1433 | try ErrorMsg.create(self.allocator, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}), |
| 821 | 1434 | ); |
| 822 | 1435 | root_scope.status = .unloaded_parse_failure; |
| ... | ... | @@ -838,7 +1451,83 @@ fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module { |
| 838 | 1451 | } |
| 839 | 1452 | } |
| 840 | 1453 | |
| 841 | | fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 1454 | fn getAstTree(self: *Module, root_scope: *Scope.File) !*ast.Tree { |
| 1455 | switch (root_scope.status) { |
| 1456 | .never_loaded, .unloaded_success => { |
| 1457 | try self.failed_files.ensureCapacity(self.failed_files.size + 1); |
| 1458 | |
| 1459 | const source = try root_scope.getSource(self); |
| 1460 | |
| 1461 | var keep_tree = false; |
| 1462 | const tree = try std.zig.parse(self.allocator, source); |
| 1463 | defer if (!keep_tree) tree.deinit(); |
| 1464 | |
| 1465 | if (tree.errors.len != 0) { |
| 1466 | const parse_err = tree.errors[0]; |
| 1467 | |
| 1468 | var msg = std.ArrayList(u8).init(self.allocator); |
| 1469 | defer msg.deinit(); |
| 1470 | |
| 1471 | try parse_err.render(tree.token_ids, msg.outStream()); |
| 1472 | const err_msg = try self.allocator.create(ErrorMsg); |
| 1473 | err_msg.* = .{ |
| 1474 | .msg = msg.toOwnedSlice(), |
| 1475 | .byte_offset = tree.token_locs[parse_err.loc()].start, |
| 1476 | }; |
| 1477 | |
| 1478 | self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg); |
| 1479 | root_scope.status = .unloaded_parse_failure; |
| 1480 | return error.AnalysisFail; |
| 1481 | } |
| 1482 | |
| 1483 | root_scope.status = .loaded_success; |
| 1484 | root_scope.contents = .{ .tree = tree }; |
| 1485 | keep_tree = true; |
| 1486 | |
| 1487 | return tree; |
| 1488 | }, |
| 1489 | |
| 1490 | .unloaded_parse_failure => return error.AnalysisFail, |
| 1491 | |
| 1492 | .loaded_success => return root_scope.contents.tree, |
| 1493 | } |
| 1494 | } |
| 1495 | |
| 1496 | fn analyzeRootSrcFile(self: *Module, root_scope: *Scope.File) !void { |
| 1497 | switch (root_scope.status) { |
| 1498 | .never_loaded => { |
| 1499 | const tree = try self.getAstTree(root_scope); |
| 1500 | const decls = tree.root_node.decls(); |
| 1501 | |
| 1502 | try self.work_queue.ensureUnusedCapacity(decls.len); |
| 1503 | |
| 1504 | for (decls) |decl| { |
| 1505 | if (decl.cast(ast.Node.FnProto)) |proto_decl| { |
| 1506 | if (proto_decl.extern_export_inline_token) |maybe_export_token| { |
| 1507 | if (tree.token_ids[maybe_export_token] == .Keyword_export) { |
| 1508 | self.work_queue.writeItemAssumeCapacity(.{ |
| 1509 | .ast_gen_decl = .{ |
| 1510 | .ast_node = decl, |
| 1511 | .scope = &root_scope.base, |
| 1512 | }, |
| 1513 | }); |
| 1514 | } |
| 1515 | } |
| 1516 | } |
| 1517 | // TODO also look for comptime blocks and exported globals |
| 1518 | } |
| 1519 | }, |
| 1520 | |
| 1521 | .unloaded_parse_failure, |
| 1522 | .unloaded_success, |
| 1523 | .loaded_success, |
| 1524 | => { |
| 1525 | @panic("TODO process update"); |
| 1526 | }, |
| 1527 | } |
| 1528 | } |
| 1529 | |
| 1530 | fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 842 | 1531 | switch (root_scope.status) { |
| 843 | 1532 | .never_loaded => { |
| 844 | 1533 | const src_module = try self.getSrcModule(root_scope); |
| ... | ... | @@ -882,12 +1571,10 @@ fn analyzeRoot(self: *Module, root_scope: *Scope.ZIRModule) !void { |
| 882 | 1571 | if (self.decl_table.get(name_hash)) |kv| { |
| 883 | 1572 | const decl = kv.value; |
| 884 | 1573 | deleted_decls.removeAssertDiscard(decl); |
| 885 | | const new_contents_hash = Decl.hashSimpleName(src_decl.contents); |
| 886 | 1574 | //std.debug.warn("'{}' contents: '{}'\n", .{ src_decl.name, src_decl.contents }); |
| 887 | | if (!mem.eql(u8, &new_contents_hash, &decl.contents_hash)) { |
| 888 | | //std.debug.warn("'{}' {x} => {x}\n", .{ src_decl.name, decl.contents_hash, new_contents_hash }); |
| 1575 | if (!mem.eql(u8, &src_decl.contents_hash, &decl.contents_hash)) { |
| 889 | 1576 | try self.markOutdatedDecl(decl); |
| 890 | | decl.contents_hash = new_contents_hash; |
| 1577 | decl.contents_hash = src_decl.contents_hash; |
| 891 | 1578 | } |
| 892 | 1579 | } else if (src_decl.cast(zir.Inst.Export)) |export_inst| { |
| 893 | 1580 | try exports_to_resolve.append(&export_inst.base); |
| ... | ... | @@ -1038,7 +1725,7 @@ fn reAnalyzeDecl(self: *Module, decl: *Decl, old_inst: *zir.Inst) InnerError!voi |
| 1038 | 1725 | }; |
| 1039 | 1726 | errdefer decl_scope.arena.deinit(); |
| 1040 | 1727 | |
| 1041 | | const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) { |
| 1728 | const typed_value = self.analyzeConstInst(&decl_scope.base, old_inst) catch |err| switch (err) { |
| 1042 | 1729 | error.OutOfMemory => return error.OutOfMemory, |
| 1043 | 1730 | error.AnalysisFail => { |
| 1044 | 1731 | switch (decl.analysis) { |
| ... | ... | @@ -1109,9 +1796,91 @@ fn markOutdatedDecl(self: *Module, decl: *Decl) !void { |
| 1109 | 1796 | decl.analysis = .outdated; |
| 1110 | 1797 | } |
| 1111 | 1798 | |
| 1799 | fn allocateNewDecl( |
| 1800 | self: *Module, |
| 1801 | scope: *Scope, |
| 1802 | src: usize, |
| 1803 | contents_hash: std.zig.SrcHash, |
| 1804 | ) !*Decl { |
| 1805 | const new_decl = try self.allocator.create(Decl); |
| 1806 | new_decl.* = .{ |
| 1807 | .name = "", |
| 1808 | .scope = scope.namespace(), |
| 1809 | .src = src, |
| 1810 | .typed_value = .{ .never_succeeded = {} }, |
| 1811 | .analysis = .in_progress, |
| 1812 | .deletion_flag = false, |
| 1813 | .contents_hash = contents_hash, |
| 1814 | .link = link.ElfFile.TextBlock.empty, |
| 1815 | .generation = 0, |
| 1816 | }; |
| 1817 | return new_decl; |
| 1818 | } |
| 1819 | |
| 1820 | fn createNewDecl( |
| 1821 | self: *Module, |
| 1822 | scope: *Scope, |
| 1823 | decl_name: []const u8, |
| 1824 | src: usize, |
| 1825 | name_hash: Decl.Hash, |
| 1826 | contents_hash: std.zig.SrcHash, |
| 1827 | ) !*Decl { |
| 1828 | try self.decl_table.ensureCapacity(self.decl_table.size + 1); |
| 1829 | const new_decl = try self.allocateNewDecl(scope, src, contents_hash); |
| 1830 | errdefer self.allocator.destroy(new_decl); |
| 1831 | new_decl.name = try mem.dupeZ(self.allocator, u8, decl_name); |
| 1832 | self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl); |
| 1833 | return new_decl; |
| 1834 | } |
| 1835 | |
| 1836 | fn analyzeNewDecl(self: *Module, new_decl: *Decl, old_inst: *zir.Inst) InnerError!void { |
| 1837 | var decl_scope: Scope.DeclAnalysis = .{ |
| 1838 | .decl = new_decl, |
| 1839 | .arena = std.heap.ArenaAllocator.init(self.allocator), |
| 1840 | }; |
| 1841 | errdefer decl_scope.arena.deinit(); |
| 1842 | |
| 1843 | const typed_value = self.analyzeConstInst(&decl_scope.base, old_inst) catch |err| switch (err) { |
| 1844 | error.OutOfMemory => return error.OutOfMemory, |
| 1845 | error.AnalysisFail => { |
| 1846 | switch (new_decl.analysis) { |
| 1847 | .in_progress => new_decl.analysis = .dependency_failure, |
| 1848 | else => {}, |
| 1849 | } |
| 1850 | new_decl.generation = self.generation; |
| 1851 | return error.AnalysisFail; |
| 1852 | }, |
| 1853 | }; |
| 1854 | const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); |
| 1855 | |
| 1856 | arena_state.* = decl_scope.arena.state; |
| 1857 | |
| 1858 | new_decl.typed_value = .{ |
| 1859 | .most_recent = .{ |
| 1860 | .typed_value = typed_value, |
| 1861 | .arena = arena_state, |
| 1862 | }, |
| 1863 | }; |
| 1864 | new_decl.analysis = .complete; |
| 1865 | new_decl.generation = self.generation; |
| 1866 | if (typed_value.ty.hasCodeGenBits()) { |
| 1867 | // We don't fully codegen the decl until later, but we do need to reserve a global |
| 1868 | // offset table index for it. This allows us to codegen decls out of dependency order, |
| 1869 | // increasing how many computations can be done in parallel. |
| 1870 | try self.bin_file.allocateDeclIndexes(new_decl); |
| 1871 | try self.work_queue.writeItem(.{ .codegen_decl = new_decl }); |
| 1872 | } |
| 1873 | } |
| 1874 | |
| 1112 | 1875 | fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Decl { |
| 1113 | | const hash = Decl.hashSimpleName(old_inst.name); |
| 1114 | | if (self.decl_table.get(hash)) |kv| { |
| 1876 | if (old_inst.name.len == 0) { |
| 1877 | // If the name is empty, then we make this an anonymous Decl. |
| 1878 | const new_decl = try self.allocateNewDecl(scope, old_inst.src, old_inst.contents_hash); |
| 1879 | try self.analyzeNewDecl(new_decl, old_inst); |
| 1880 | return new_decl; |
| 1881 | } |
| 1882 | const name_hash = Decl.hashSimpleName(old_inst.name); |
| 1883 | if (self.decl_table.get(name_hash)) |kv| { |
| 1115 | 1884 | const decl = kv.value; |
| 1116 | 1885 | try self.reAnalyzeDecl(decl, old_inst); |
| 1117 | 1886 | return decl; |
| ... | ... | @@ -1119,63 +1888,9 @@ fn resolveDecl(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*De |
| 1119 | 1888 | // This is just a named reference to another decl. |
| 1120 | 1889 | return self.analyzeDeclVal(scope, decl_val); |
| 1121 | 1890 | } else { |
| 1122 | | const new_decl = blk: { |
| 1123 | | try self.decl_table.ensureCapacity(self.decl_table.size + 1); |
| 1124 | | const new_decl = try self.allocator.create(Decl); |
| 1125 | | errdefer self.allocator.destroy(new_decl); |
| 1126 | | const name = try mem.dupeZ(self.allocator, u8, old_inst.name); |
| 1127 | | errdefer self.allocator.free(name); |
| 1128 | | new_decl.* = .{ |
| 1129 | | .name = name, |
| 1130 | | .scope = scope.namespace(), |
| 1131 | | .src = old_inst.src, |
| 1132 | | .typed_value = .{ .never_succeeded = {} }, |
| 1133 | | .analysis = .in_progress, |
| 1134 | | .deletion_flag = false, |
| 1135 | | .contents_hash = Decl.hashSimpleName(old_inst.contents), |
| 1136 | | .link = link.ElfFile.TextBlock.empty, |
| 1137 | | .generation = 0, |
| 1138 | | }; |
| 1139 | | self.decl_table.putAssumeCapacityNoClobber(hash, new_decl); |
| 1140 | | break :blk new_decl; |
| 1141 | | }; |
| 1891 | const new_decl = try self.createNewDecl(scope, old_inst.name, old_inst.src, name_hash, old_inst.contents_hash); |
| 1892 | try self.analyzeNewDecl(new_decl, old_inst); |
| 1142 | 1893 | |
| 1143 | | var decl_scope: Scope.DeclAnalysis = .{ |
| 1144 | | .decl = new_decl, |
| 1145 | | .arena = std.heap.ArenaAllocator.init(self.allocator), |
| 1146 | | }; |
| 1147 | | errdefer decl_scope.arena.deinit(); |
| 1148 | | |
| 1149 | | const typed_value = self.analyzeInstConst(&decl_scope.base, old_inst) catch |err| switch (err) { |
| 1150 | | error.OutOfMemory => return error.OutOfMemory, |
| 1151 | | error.AnalysisFail => { |
| 1152 | | switch (new_decl.analysis) { |
| 1153 | | .in_progress => new_decl.analysis = .dependency_failure, |
| 1154 | | else => {}, |
| 1155 | | } |
| 1156 | | new_decl.generation = self.generation; |
| 1157 | | return error.AnalysisFail; |
| 1158 | | }, |
| 1159 | | }; |
| 1160 | | const arena_state = try decl_scope.arena.allocator.create(std.heap.ArenaAllocator.State); |
| 1161 | | |
| 1162 | | arena_state.* = decl_scope.arena.state; |
| 1163 | | |
| 1164 | | new_decl.typed_value = .{ |
| 1165 | | .most_recent = .{ |
| 1166 | | .typed_value = typed_value, |
| 1167 | | .arena = arena_state, |
| 1168 | | }, |
| 1169 | | }; |
| 1170 | | new_decl.analysis = .complete; |
| 1171 | | new_decl.generation = self.generation; |
| 1172 | | if (typed_value.ty.hasCodeGenBits()) { |
| 1173 | | // We don't fully codegen the decl until later, but we do need to reserve a global |
| 1174 | | // offset table index for it. This allows us to codegen decls out of dependency order, |
| 1175 | | // increasing how many computations can be done in parallel. |
| 1176 | | try self.bin_file.allocateDeclIndexes(new_decl); |
| 1177 | | try self.work_queue.writeItem(.{ .codegen_decl = new_decl }); |
| 1178 | | } |
| 1179 | 1894 | return new_decl; |
| 1180 | 1895 | } |
| 1181 | 1896 | } |
| ... | ... | @@ -1208,9 +1923,13 @@ fn resolveInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*In |
| 1208 | 1923 | } |
| 1209 | 1924 | } |
| 1210 | 1925 | |
| 1211 | | const decl = try self.resolveCompleteDecl(scope, old_inst); |
| 1212 | | const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl); |
| 1213 | | return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src); |
| 1926 | if (scope.namespace().tag == .zir_module) { |
| 1927 | const decl = try self.resolveCompleteDecl(scope, old_inst); |
| 1928 | const decl_ref = try self.analyzeDeclRef(scope, old_inst.src, decl); |
| 1929 | return self.analyzeDeref(scope, old_inst.src, decl_ref, old_inst.src); |
| 1930 | } |
| 1931 | |
| 1932 | return self.analyzeInst(scope, old_inst); |
| 1214 | 1933 | } |
| 1215 | 1934 | |
| 1216 | 1935 | fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block { |
| ... | ... | @@ -1451,7 +2170,7 @@ fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigI |
| 1451 | 2170 | }); |
| 1452 | 2171 | } |
| 1453 | 2172 | |
| 1454 | | fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { |
| 2173 | fn analyzeConstInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue { |
| 1455 | 2174 | const new_inst = try self.analyzeInst(scope, old_inst); |
| 1456 | 2175 | return TypedValue{ |
| 1457 | 2176 | .ty = new_inst.ty, |
| ... | ... | @@ -1459,11 +2178,16 @@ fn analyzeInstConst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerErro |
| 1459 | 2178 | }; |
| 1460 | 2179 | } |
| 1461 | 2180 | |
| 2181 | fn analyzeInstConst(self: *Module, scope: *Scope, const_inst: *zir.Inst.Const) InnerError!*Inst { |
| 2182 | return self.constInst(scope, const_inst.base.src, const_inst.positionals.typed_value); |
| 2183 | } |
| 2184 | |
| 1462 | 2185 | fn analyzeInst(self: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst { |
| 1463 | 2186 | switch (old_inst.tag) { |
| 1464 | 2187 | .breakpoint => return self.analyzeInstBreakpoint(scope, old_inst.cast(zir.Inst.Breakpoint).?), |
| 1465 | 2188 | .call => return self.analyzeInstCall(scope, old_inst.cast(zir.Inst.Call).?), |
| 1466 | 2189 | .compileerror => return self.analyzeInstCompileError(scope, old_inst.cast(zir.Inst.CompileError).?), |
| 2190 | .@"const" => return self.analyzeInstConst(scope, old_inst.cast(zir.Inst.Const).?), |
| 1467 | 2191 | .declref => return self.analyzeInstDeclRef(scope, old_inst.cast(zir.Inst.DeclRef).?), |
| 1468 | 2192 | .declval => return self.analyzeInstDeclVal(scope, old_inst.cast(zir.Inst.DeclVal).?), |
| 1469 | 2193 | .str => { |
| ... | ... | @@ -1520,18 +2244,23 @@ fn analyzeInstRef(self: *Module, scope: *Scope, inst: *zir.Inst.Ref) InnerError! |
| 1520 | 2244 | fn analyzeInstDeclRef(self: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst { |
| 1521 | 2245 | const decl_name = try self.resolveConstString(scope, inst.positionals.name); |
| 1522 | 2246 | // This will need to get more fleshed out when there are proper structs & namespaces. |
| 1523 | | const zir_module = scope.namespace(); |
| 1524 | | const src_decl = zir_module.contents.module.findDecl(decl_name) orelse |
| 1525 | | return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name}); |
| 1526 | | |
| 1527 | | const decl = try self.resolveCompleteDecl(scope, src_decl); |
| 1528 | | return self.analyzeDeclRef(scope, inst.base.src, decl); |
| 2247 | const namespace = scope.namespace(); |
| 2248 | if (namespace.cast(Scope.File)) |scope_file| { |
| 2249 | return self.fail(scope, inst.base.src, "TODO implement declref for zig source", .{}); |
| 2250 | } else if (namespace.cast(Scope.ZIRModule)) |zir_module| { |
| 2251 | const src_decl = zir_module.contents.module.findDecl(decl_name) orelse |
| 2252 | return self.fail(scope, inst.positionals.name.src, "use of undeclared identifier '{}'", .{decl_name}); |
| 2253 | |
| 2254 | const decl = try self.resolveCompleteDecl(scope, src_decl); |
| 2255 | return self.analyzeDeclRef(scope, inst.base.src, decl); |
| 2256 | } else { |
| 2257 | unreachable; |
| 2258 | } |
| 1529 | 2259 | } |
| 1530 | 2260 | |
| 1531 | 2261 | fn analyzeDeclVal(self: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Decl { |
| 1532 | 2262 | const decl_name = inst.positionals.name; |
| 1533 | | // This will need to get more fleshed out when there are proper structs & namespaces. |
| 1534 | | const zir_module = scope.namespace(); |
| 2263 | const zir_module = scope.namespace().cast(Scope.ZIRModule).?; |
| 1535 | 2264 | const src_decl = zir_module.contents.module.findDecl(decl_name) orelse |
| 1536 | 2265 | return self.fail(scope, inst.base.src, "use of undeclared identifier '{}'", .{decl_name}); |
| 1537 | 2266 | |
| ... | ... | @@ -2316,6 +3045,30 @@ fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, a |
| 2316 | 3045 | return self.failWithOwnedErrorMsg(scope, src, err_msg); |
| 2317 | 3046 | } |
| 2318 | 3047 | |
| 3048 | fn failTok( |
| 3049 | self: *Module, |
| 3050 | scope: *Scope, |
| 3051 | token_index: ast.TokenIndex, |
| 3052 | comptime format: []const u8, |
| 3053 | args: var, |
| 3054 | ) InnerError { |
| 3055 | @setCold(true); |
| 3056 | const src = scope.tree().token_locs[token_index].start; |
| 3057 | return self.fail(scope, src, format, args); |
| 3058 | } |
| 3059 | |
| 3060 | fn failNode( |
| 3061 | self: *Module, |
| 3062 | scope: *Scope, |
| 3063 | ast_node: *ast.Node, |
| 3064 | comptime format: []const u8, |
| 3065 | args: var, |
| 3066 | ) InnerError { |
| 3067 | @setCold(true); |
| 3068 | const src = scope.tree().token_locs[ast_node.firstToken()].start; |
| 3069 | return self.fail(scope, src, format, args); |
| 3070 | } |
| 3071 | |
| 2319 | 3072 | fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *ErrorMsg) InnerError { |
| 2320 | 3073 | { |
| 2321 | 3074 | errdefer err_msg.destroy(self.allocator); |
| ... | ... | @@ -2336,8 +3089,9 @@ fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Err |
| 2336 | 3089 | .zir_module => { |
| 2337 | 3090 | const zir_module = scope.cast(Scope.ZIRModule).?; |
| 2338 | 3091 | zir_module.status = .loaded_sema_failure; |
| 2339 | | self.failed_files.putAssumeCapacityNoClobber(zir_module, err_msg); |
| 3092 | self.failed_files.putAssumeCapacityNoClobber(scope, err_msg); |
| 2340 | 3093 | }, |
| 3094 | .file => unreachable, |
| 2341 | 3095 | } |
| 2342 | 3096 | return error.AnalysisFail; |
| 2343 | 3097 | } |