| ... | ... | @@ -26,6 +26,7 @@ const trace = @import("tracy.zig").trace; |
| 26 | 26 | const AstGen = @import("AstGen.zig"); |
| 27 | 27 | const Sema = @import("Sema.zig"); |
| 28 | 28 | const target_util = @import("target.zig"); |
| 29 | const Cache = @import("Cache.zig"); |
| 29 | 30 | |
| 30 | 31 | /// General-purpose allocator. Used for both temporary and long-term storage. |
| 31 | 32 | gpa: *Allocator, |
| ... | ... | @@ -35,8 +36,6 @@ comp: *Compilation, |
| 35 | 36 | zig_cache_artifact_directory: Compilation.Directory, |
| 36 | 37 | /// Pointer to externally managed resource. `null` if there is no zig file being compiled. |
| 37 | 38 | root_pkg: *Package, |
| 38 | | /// Module owns this resource. |
| 39 | | root_scope: *Scope.File, |
| 40 | 39 | /// It's rare for a decl to be exported, so we save memory by having a sparse map of |
| 41 | 40 | /// Decl pointers to details about them being exported. |
| 42 | 41 | /// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table. |
| ... | ... | @@ -52,6 +51,12 @@ symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{}, |
| 52 | 51 | export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{}, |
| 53 | 52 | /// Maps fully qualified namespaced names to the Decl struct for them. |
| 54 | 53 | decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{}, |
| 54 | /// The set of all the files in the Module. We keep track of this in order to iterate |
| 55 | /// over it and check which source files have been modified on the file system when |
| 56 | /// an update is requested, as well as to cache `@import` results. |
| 57 | /// Keys are fully resolved file paths. This table owns the keys and values. |
| 58 | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, |
| 59 | |
| 55 | 60 | /// We optimize memory usage for a compilation with no compile errors by storing the |
| 56 | 61 | /// error messages and mapping outside of `Decl`. |
| 57 | 62 | /// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator. |
| ... | ... | @@ -85,9 +90,6 @@ global_error_set: std.StringHashMapUnmanaged(ErrorInt) = .{}, |
| 85 | 90 | /// Corresponds with `global_error_set`. |
| 86 | 91 | error_name_list: ArrayListUnmanaged([]const u8) = .{}, |
| 87 | 92 | |
| 88 | | /// Keys are fully qualified paths |
| 89 | | import_table: std.StringArrayHashMapUnmanaged(*Scope.File) = .{}, |
| 90 | | |
| 91 | 93 | /// Incrementing integer used to compare against the corresponding Decl |
| 92 | 94 | /// field to determine whether a Decl's status applies to an ongoing update, or a |
| 93 | 95 | /// previous analysis. |
| ... | ... | @@ -147,15 +149,16 @@ pub const Decl = struct { |
| 147 | 149 | /// This is necessary for mapping them to an address in the output file. |
| 148 | 150 | /// Memory owned by this decl, using Module's allocator. |
| 149 | 151 | name: [*:0]const u8, |
| 150 | | /// The direct parent container of the Decl. |
| 152 | /// The direct parent namespace of the Decl. |
| 151 | 153 | /// Reference to externally owned memory. |
| 152 | | container: *Scope.Container, |
| 154 | /// This is `null` for the Decl that represents a `File`. |
| 155 | namespace: *Scope.Namespace, |
| 153 | 156 | |
| 154 | 157 | /// An integer that can be checked against the corresponding incrementing |
| 155 | 158 | /// generation field of Module. This is used to determine whether `complete` status |
| 156 | 159 | /// represents pre- or post- re-analysis. |
| 157 | 160 | generation: u32, |
| 158 | | /// The AST Node index or ZIR Inst index that contains this declaration. |
| 161 | /// The AST node index of this declaration. |
| 159 | 162 | /// Must be recomputed when the corresponding source file is modified. |
| 160 | 163 | src_node: ast.Node.Index, |
| 161 | 164 | |
| ... | ... | @@ -273,22 +276,22 @@ pub const Decl = struct { |
| 273 | 276 | } |
| 274 | 277 | |
| 275 | 278 | pub fn srcToken(decl: Decl) u32 { |
| 276 | | const tree = &decl.container.file_scope.tree; |
| 279 | const tree = &decl.namespace.file_scope.tree; |
| 277 | 280 | return tree.firstToken(decl.src_node); |
| 278 | 281 | } |
| 279 | 282 | |
| 280 | 283 | pub fn srcByteOffset(decl: Decl) u32 { |
| 281 | | const tree = &decl.container.file_scope.tree; |
| 284 | const tree = &decl.namespace.file_scope.tree; |
| 282 | 285 | return tree.tokens.items(.start)[decl.srcToken()]; |
| 283 | 286 | } |
| 284 | 287 | |
| 285 | 288 | pub fn fullyQualifiedNameHash(decl: Decl) Scope.NameHash { |
| 286 | | return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name)); |
| 289 | return decl.namespace.fullyQualifiedNameHash(mem.spanZ(decl.name)); |
| 287 | 290 | } |
| 288 | 291 | |
| 289 | 292 | pub fn renderFullyQualifiedName(decl: Decl, writer: anytype) !void { |
| 290 | 293 | const unqualified_name = mem.spanZ(decl.name); |
| 291 | | return decl.container.renderFullyQualifiedName(unqualified_name, writer); |
| 294 | return decl.namespace.renderFullyQualifiedName(unqualified_name, writer); |
| 292 | 295 | } |
| 293 | 296 | |
| 294 | 297 | pub fn getFullyQualifiedName(decl: Decl, gpa: *Allocator) ![]u8 { |
| ... | ... | @@ -330,7 +333,7 @@ pub const Decl = struct { |
| 330 | 333 | } |
| 331 | 334 | |
| 332 | 335 | pub fn getFileScope(decl: Decl) *Scope.File { |
| 333 | | return decl.container.file_scope; |
| 336 | return decl.namespace.file_scope; |
| 334 | 337 | } |
| 335 | 338 | |
| 336 | 339 | pub fn getEmitH(decl: *Decl, module: *Module) *EmitH { |
| ... | ... | @@ -377,7 +380,7 @@ pub const Struct = struct { |
| 377 | 380 | /// Set of field names in declaration order. |
| 378 | 381 | fields: std.StringArrayHashMapUnmanaged(Field), |
| 379 | 382 | /// Represents the declarations inside this struct. |
| 380 | | container: Scope.Container, |
| 383 | namespace: Scope.Namespace, |
| 381 | 384 | |
| 382 | 385 | /// Offset from `owner_decl`, points to the struct AST node. |
| 383 | 386 | node_offset: i32, |
| ... | ... | @@ -434,7 +437,7 @@ pub const EnumFull = struct { |
| 434 | 437 | /// If this hash map is empty, it means the enum tags are auto-numbered. |
| 435 | 438 | values: ValueMap, |
| 436 | 439 | /// Represents the declarations inside this struct. |
| 437 | | container: Scope.Container, |
| 440 | namespace: Scope.Namespace, |
| 438 | 441 | /// Offset from `owner_decl`, points to the enum decl AST node. |
| 439 | 442 | node_offset: i32, |
| 440 | 443 | |
| ... | ... | @@ -521,7 +524,7 @@ pub const Scope = struct { |
| 521 | 524 | .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.arena, |
| 522 | 525 | .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.arena, |
| 523 | 526 | .file => unreachable, |
| 524 | | .container => unreachable, |
| 527 | .namespace => unreachable, |
| 525 | 528 | .decl_ref => unreachable, |
| 526 | 529 | } |
| 527 | 530 | } |
| ... | ... | @@ -533,7 +536,7 @@ pub const Scope = struct { |
| 533 | 536 | .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl, |
| 534 | 537 | .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl, |
| 535 | 538 | .file => null, |
| 536 | | .container => null, |
| 539 | .namespace => null, |
| 537 | 540 | .decl_ref => scope.cast(DeclRef).?.decl, |
| 538 | 541 | }; |
| 539 | 542 | } |
| ... | ... | @@ -545,36 +548,21 @@ pub const Scope = struct { |
| 545 | 548 | .local_val => scope.cast(LocalVal).?.gen_zir.astgen.decl, |
| 546 | 549 | .local_ptr => scope.cast(LocalPtr).?.gen_zir.astgen.decl, |
| 547 | 550 | .file => null, |
| 548 | | .container => null, |
| 551 | .namespace => null, |
| 549 | 552 | .decl_ref => scope.cast(DeclRef).?.decl, |
| 550 | 553 | }; |
| 551 | 554 | } |
| 552 | 555 | |
| 553 | | /// Asserts the scope has a parent which is a Container and returns it. |
| 554 | | pub fn namespace(scope: *Scope) *Container { |
| 556 | /// Asserts the scope has a parent which is a Namespace and returns it. |
| 557 | pub fn namespace(scope: *Scope) *Namespace { |
| 555 | 558 | switch (scope.tag) { |
| 556 | | .block => return scope.cast(Block).?.sema.owner_decl.container, |
| 557 | | .gen_zir => return scope.cast(GenZir).?.astgen.decl.container, |
| 558 | | .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.container, |
| 559 | | .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.container, |
| 560 | | .file => return &scope.cast(File).?.root_container, |
| 561 | | .container => return scope.cast(Container).?, |
| 562 | | .decl_ref => return scope.cast(DeclRef).?.decl.container, |
| 563 | | } |
| 564 | | } |
| 565 | | |
| 566 | | /// Must generate unique bytes with no collisions with other decls. |
| 567 | | /// The point of hashing here is only to limit the number of bytes of |
| 568 | | /// the unique identifier to a fixed size (16 bytes). |
| 569 | | pub fn fullyQualifiedNameHash(scope: *Scope, name: []const u8) NameHash { |
| 570 | | switch (scope.tag) { |
| 571 | | .block => unreachable, |
| 572 | | .gen_zir => unreachable, |
| 573 | | .local_val => unreachable, |
| 574 | | .local_ptr => unreachable, |
| 575 | | .file => unreachable, |
| 576 | | .container => return scope.cast(Container).?.fullyQualifiedNameHash(name), |
| 577 | | .decl_ref => unreachable, |
| 559 | .block => return scope.cast(Block).?.sema.owner_decl.namespace, |
| 560 | .gen_zir => return scope.cast(GenZir).?.astgen.decl.namespace, |
| 561 | .local_val => return scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace, |
| 562 | .local_ptr => return scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace, |
| 563 | .file => return scope.cast(File).?.namespace, |
| 564 | .namespace => return scope.cast(Namespace).?, |
| 565 | .decl_ref => return scope.cast(DeclRef).?.decl.namespace, |
| 578 | 566 | } |
| 579 | 567 | } |
| 580 | 568 | |
| ... | ... | @@ -582,12 +570,12 @@ pub const Scope = struct { |
| 582 | 570 | pub fn tree(scope: *Scope) *const ast.Tree { |
| 583 | 571 | switch (scope.tag) { |
| 584 | 572 | .file => return &scope.cast(File).?.tree, |
| 585 | | .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree, |
| 573 | .block => return &scope.cast(Block).?.src_decl.namespace.file_scope.tree, |
| 586 | 574 | .gen_zir => return scope.cast(GenZir).?.tree(), |
| 587 | | .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.container.file_scope.tree, |
| 588 | | .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.container.file_scope.tree, |
| 589 | | .container => return &scope.cast(Container).?.file_scope.tree, |
| 590 | | .decl_ref => return &scope.cast(DeclRef).?.decl.container.file_scope.tree, |
| 575 | .local_val => return &scope.cast(LocalVal).?.gen_zir.astgen.decl.namespace.file_scope.tree, |
| 576 | .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.astgen.decl.namespace.file_scope.tree, |
| 577 | .namespace => return &scope.cast(Namespace).?.file_scope.tree, |
| 578 | .decl_ref => return &scope.cast(DeclRef).?.decl.namespace.file_scope.tree, |
| 591 | 579 | } |
| 592 | 580 | } |
| 593 | 581 | |
| ... | ... | @@ -599,16 +587,16 @@ pub const Scope = struct { |
| 599 | 587 | .local_val => return scope.cast(LocalVal).?.gen_zir, |
| 600 | 588 | .local_ptr => return scope.cast(LocalPtr).?.gen_zir, |
| 601 | 589 | .file => unreachable, |
| 602 | | .container => unreachable, |
| 590 | .namespace => unreachable, |
| 603 | 591 | .decl_ref => unreachable, |
| 604 | 592 | }; |
| 605 | 593 | } |
| 606 | 594 | |
| 607 | | /// Asserts the scope has a parent which is a Container or File and |
| 595 | /// Asserts the scope has a parent which is a Namespace or File and |
| 608 | 596 | /// returns the sub_file_path field. |
| 609 | 597 | pub fn subFilePath(base: *Scope) []const u8 { |
| 610 | 598 | switch (base.tag) { |
| 611 | | .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path, |
| 599 | .namespace => return @fieldParentPtr(Namespace, "base", base).file_scope.sub_file_path, |
| 612 | 600 | .file => return @fieldParentPtr(File, "base", base).sub_file_path, |
| 613 | 601 | .block => unreachable, |
| 614 | 602 | .gen_zir => unreachable, |
| ... | ... | @@ -618,30 +606,18 @@ pub const Scope = struct { |
| 618 | 606 | } |
| 619 | 607 | } |
| 620 | 608 | |
| 621 | | pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 { |
| 622 | | switch (base.tag) { |
| 623 | | .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module), |
| 624 | | .file => return @fieldParentPtr(File, "base", base).getSource(module), |
| 625 | | .gen_zir => unreachable, |
| 626 | | .local_val => unreachable, |
| 627 | | .local_ptr => unreachable, |
| 628 | | .block => unreachable, |
| 629 | | .decl_ref => unreachable, |
| 630 | | } |
| 631 | | } |
| 632 | | |
| 633 | 609 | /// When called from inside a Block Scope, chases the src_decl, not the owner_decl. |
| 634 | 610 | pub fn getFileScope(base: *Scope) *Scope.File { |
| 635 | 611 | var cur = base; |
| 636 | 612 | while (true) { |
| 637 | 613 | cur = switch (cur.tag) { |
| 638 | | .container => return @fieldParentPtr(Container, "base", cur).file_scope, |
| 614 | .namespace => return @fieldParentPtr(Namespace, "base", cur).file_scope, |
| 639 | 615 | .file => return @fieldParentPtr(File, "base", cur), |
| 640 | 616 | .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent, |
| 641 | 617 | .local_val => @fieldParentPtr(LocalVal, "base", cur).parent, |
| 642 | 618 | .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent, |
| 643 | | .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope, |
| 644 | | .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.container.file_scope, |
| 619 | .block => return @fieldParentPtr(Block, "base", cur).src_decl.namespace.file_scope, |
| 620 | .decl_ref => return @fieldParentPtr(DeclRef, "base", cur).decl.namespace.file_scope, |
| 645 | 621 | }; |
| 646 | 622 | } |
| 647 | 623 | } |
| ... | ... | @@ -657,8 +633,8 @@ pub const Scope = struct { |
| 657 | 633 | pub const Tag = enum { |
| 658 | 634 | /// .zig source code. |
| 659 | 635 | file, |
| 660 | | /// struct, enum or union, every .file contains one of these. |
| 661 | | container, |
| 636 | /// Namespace owned by structs, enums, unions, and opaques for decls. |
| 637 | namespace, |
| 662 | 638 | block, |
| 663 | 639 | gen_zir, |
| 664 | 640 | local_val, |
| ... | ... | @@ -669,37 +645,44 @@ pub const Scope = struct { |
| 669 | 645 | decl_ref, |
| 670 | 646 | }; |
| 671 | 647 | |
| 672 | | pub const Container = struct { |
| 673 | | pub const base_tag: Tag = .container; |
| 648 | /// The container that structs, enums, unions, and opaques have. |
| 649 | pub const Namespace = struct { |
| 650 | pub const base_tag: Tag = .namespace; |
| 674 | 651 | base: Scope = Scope{ .tag = base_tag }, |
| 675 | 652 | |
| 653 | parent: ?*Namespace, |
| 676 | 654 | file_scope: *Scope.File, |
| 677 | 655 | parent_name_hash: NameHash, |
| 678 | | |
| 679 | | /// Direct children of the file. |
| 680 | | decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, |
| 656 | /// Will be a struct, enum, union, or opaque. |
| 681 | 657 | ty: Type, |
| 658 | /// Direct children of the namespace. Used during an update to detect |
| 659 | /// which decls have been added/removed from source. |
| 660 | decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{}, |
| 682 | 661 | |
| 683 | | pub fn deinit(cont: *Container, gpa: *Allocator) void { |
| 684 | | cont.decls.deinit(gpa); |
| 685 | | // TODO either Container of File should have an arena for sub_file_path and ty |
| 686 | | gpa.destroy(cont.ty.castTag(.empty_struct).?); |
| 687 | | gpa.free(cont.file_scope.sub_file_path); |
| 688 | | cont.* = undefined; |
| 662 | pub fn deinit(ns: *Namespace, gpa: *Allocator) void { |
| 663 | ns.decls.deinit(gpa); |
| 664 | ns.* = undefined; |
| 689 | 665 | } |
| 690 | 666 | |
| 691 | | pub fn removeDecl(cont: *Container, child: *Decl) void { |
| 692 | | _ = cont.decls.swapRemove(child); |
| 667 | pub fn removeDecl(ns: *Namespace, child: *Decl) void { |
| 668 | _ = ns.decls.swapRemove(child); |
| 693 | 669 | } |
| 694 | 670 | |
| 695 | | pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash { |
| 696 | | return std.zig.hashName(cont.parent_name_hash, ".", name); |
| 671 | /// Must generate unique bytes with no collisions with other decls. |
| 672 | /// The point of hashing here is only to limit the number of bytes of |
| 673 | /// the unique identifier to a fixed size (16 bytes). |
| 674 | pub fn fullyQualifiedNameHash(ns: Namespace, name: []const u8) NameHash { |
| 675 | return std.zig.hashName(ns.parent_name_hash, ".", name); |
| 697 | 676 | } |
| 698 | 677 | |
| 699 | | pub fn renderFullyQualifiedName(cont: Container, name: []const u8, writer: anytype) !void { |
| 678 | pub fn renderFullyQualifiedName(ns: Namespace, name: []const u8, writer: anytype) !void { |
| 700 | 679 | // TODO this should render e.g. "std.fs.Dir.OpenOptions" |
| 701 | 680 | return writer.writeAll(name); |
| 702 | 681 | } |
| 682 | |
| 683 | pub fn getDecl(ns: Namespace) *Decl { |
| 684 | return ns.ty.getOwnerDecl(); |
| 685 | } |
| 703 | 686 | }; |
| 704 | 687 | |
| 705 | 688 | pub const File = struct { |
| ... | ... | @@ -711,46 +694,54 @@ pub const Scope = struct { |
| 711 | 694 | unloaded_parse_failure, |
| 712 | 695 | loaded_success, |
| 713 | 696 | }, |
| 714 | | |
| 697 | source_loaded: bool, |
| 715 | 698 | /// Relative to the owning package's root_src_dir. |
| 716 | | /// Reference to external memory, not owned by File. |
| 699 | /// Memory is stored in gpa, owned by File. |
| 717 | 700 | sub_file_path: []const u8, |
| 718 | | source: union(enum) { |
| 719 | | unloaded: void, |
| 720 | | bytes: [:0]const u8, |
| 721 | | }, |
| 701 | /// Whether this is populated depends on `source_loaded`. |
| 702 | source: [:0]const u8, |
| 703 | /// Whether this is populated depends on `status`. |
| 704 | stat_size: u64, |
| 705 | /// Whether this is populated depends on `status`. |
| 706 | stat_inode: std.fs.File.INode, |
| 707 | /// Whether this is populated depends on `status`. |
| 708 | stat_mtime: i128, |
| 709 | /// Whether this is populated depends on `status`. |
| 710 | source_hash: Cache.BinDigest, |
| 722 | 711 | /// Whether this is populated or not depends on `status`. |
| 723 | 712 | tree: ast.Tree, |
| 724 | 713 | /// Package that this file is a part of, managed externally. |
| 725 | 714 | pkg: *Package, |
| 726 | | |
| 727 | | root_container: Container, |
| 715 | /// The namespace of the struct that represents this file. |
| 716 | namespace: *Namespace, |
| 728 | 717 | |
| 729 | 718 | pub fn unload(file: *File, gpa: *Allocator) void { |
| 730 | | switch (file.status) { |
| 731 | | .unloaded_parse_failure, |
| 732 | | .never_loaded, |
| 733 | | .unloaded_success, |
| 734 | | => { |
| 735 | | file.status = .unloaded_success; |
| 736 | | }, |
| 719 | file.unloadTree(gpa); |
| 720 | file.unloadSource(gpa); |
| 721 | } |
| 737 | 722 | |
| 738 | | .loaded_success => { |
| 739 | | file.tree.deinit(gpa); |
| 740 | | file.status = .unloaded_success; |
| 741 | | }, |
| 723 | pub fn unloadTree(file: *File, gpa: *Allocator) void { |
| 724 | if (file.status == .loaded_success) { |
| 725 | file.tree.deinit(gpa); |
| 742 | 726 | } |
| 743 | | switch (file.source) { |
| 744 | | .bytes => |bytes| { |
| 745 | | gpa.free(bytes); |
| 746 | | file.source = .{ .unloaded = {} }; |
| 747 | | }, |
| 748 | | .unloaded => {}, |
| 727 | file.status = .unloaded_success; |
| 728 | } |
| 729 | |
| 730 | pub fn unloadSource(file: *File, gpa: *Allocator) void { |
| 731 | if (file.source_loaded) { |
| 732 | file.source_loaded = false; |
| 733 | gpa.free(file.source); |
| 734 | } |
| 735 | } |
| 736 | |
| 737 | pub fn updateTreeToNewSource(file: *File) void { |
| 738 | assert(file.source_loaded); |
| 739 | if (file.status == .loaded_success) { |
| 740 | file.tree.source = file.source; |
| 749 | 741 | } |
| 750 | 742 | } |
| 751 | 743 | |
| 752 | 744 | pub fn deinit(file: *File, gpa: *Allocator) void { |
| 753 | | file.root_container.deinit(gpa); |
| 754 | 745 | file.unload(gpa); |
| 755 | 746 | file.* = undefined; |
| 756 | 747 | } |
| ... | ... | @@ -765,22 +756,44 @@ pub const Scope = struct { |
| 765 | 756 | std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 }); |
| 766 | 757 | } |
| 767 | 758 | |
| 768 | | pub fn getSource(file: *File, module: *Module) ![:0]const u8 { |
| 769 | | switch (file.source) { |
| 770 | | .unloaded => { |
| 771 | | const source = try file.pkg.root_src_directory.handle.readFileAllocOptions( |
| 772 | | module.gpa, |
| 773 | | file.sub_file_path, |
| 774 | | std.math.maxInt(u32), |
| 775 | | null, |
| 776 | | 1, |
| 777 | | 0, |
| 778 | | ); |
| 779 | | file.source = .{ .bytes = source }; |
| 780 | | return source; |
| 781 | | }, |
| 782 | | .bytes => |bytes| return bytes, |
| 783 | | } |
| 759 | pub fn getSource(file: *File, gpa: *Allocator) ![:0]const u8 { |
| 760 | if (file.source_loaded) return file.source; |
| 761 | |
| 762 | // Keep track of inode, file size, mtime, hash so we can detect which files |
| 763 | // have been modified when an incremental update is requested. |
| 764 | var f = try file.pkg.root_src_directory.handle.openFile(file.sub_file_path, .{}); |
| 765 | defer f.close(); |
| 766 | |
| 767 | const stat = try f.stat(); |
| 768 | |
| 769 | try file.finishGettingSource(gpa, f, stat); |
| 770 | assert(file.source_loaded); |
| 771 | return file.source; |
| 772 | } |
| 773 | |
| 774 | pub fn finishGettingSource( |
| 775 | file: *File, |
| 776 | gpa: *Allocator, |
| 777 | f: std.fs.File, |
| 778 | stat: std.fs.File.Stat, |
| 779 | ) !void { |
| 780 | if (stat.size > std.math.maxInt(u32)) |
| 781 | return error.FileTooBig; |
| 782 | |
| 783 | const source = try gpa.allocSentinel(u8, stat.size, 0); |
| 784 | const amt = try f.readAll(source); |
| 785 | if (amt != stat.size) |
| 786 | return error.UnexpectedEndOfFile; |
| 787 | |
| 788 | var hasher = Cache.hasher_init; |
| 789 | hasher.update(source); |
| 790 | hasher.final(&file.source_hash); |
| 791 | |
| 792 | file.stat_size = stat.size; |
| 793 | file.stat_inode = stat.inode; |
| 794 | file.stat_mtime = stat.mtime; |
| 795 | file.source = source; |
| 796 | file.source_loaded = true; |
| 784 | 797 | } |
| 785 | 798 | }; |
| 786 | 799 | |
| ... | ... | @@ -859,7 +872,7 @@ pub const Scope = struct { |
| 859 | 872 | } |
| 860 | 873 | |
| 861 | 874 | pub fn getFileScope(block: *Block) *Scope.File { |
| 862 | | return block.src_decl.container.file_scope; |
| 875 | return block.src_decl.namespace.file_scope; |
| 863 | 876 | } |
| 864 | 877 | |
| 865 | 878 | pub fn addNoOp( |
| ... | ... | @@ -1110,7 +1123,7 @@ pub const Scope = struct { |
| 1110 | 1123 | } |
| 1111 | 1124 | |
| 1112 | 1125 | pub fn tree(gz: *const GenZir) *const ast.Tree { |
| 1113 | | return &gz.astgen.decl.container.file_scope.tree; |
| 1126 | return &gz.astgen.decl.namespace.file_scope.tree; |
| 1114 | 1127 | } |
| 1115 | 1128 | |
| 1116 | 1129 | pub fn setBreakResultLoc(gz: *GenZir, parent_rl: AstGen.ResultLoc) void { |
| ... | ... | @@ -1678,7 +1691,7 @@ pub const SrcLoc = struct { |
| 1678 | 1691 | .node_offset_switch_range, |
| 1679 | 1692 | .node_offset_fn_type_cc, |
| 1680 | 1693 | .node_offset_fn_type_ret_ty, |
| 1681 | | => src_loc.container.decl.container.file_scope, |
| 1694 | => src_loc.container.decl.namespace.file_scope, |
| 1682 | 1695 | }; |
| 1683 | 1696 | } |
| 1684 | 1697 | |
| ... | ... | @@ -1706,14 +1719,14 @@ pub const SrcLoc = struct { |
| 1706 | 1719 | .token_offset => |tok_off| { |
| 1707 | 1720 | const decl = src_loc.container.decl; |
| 1708 | 1721 | const tok_index = decl.srcToken() + tok_off; |
| 1709 | | const tree = decl.container.file_scope.base.tree(); |
| 1722 | const tree = decl.namespace.file_scope.base.tree(); |
| 1710 | 1723 | const token_starts = tree.tokens.items(.start); |
| 1711 | 1724 | return token_starts[tok_index]; |
| 1712 | 1725 | }, |
| 1713 | 1726 | .node_offset, .node_offset_bin_op => |node_off| { |
| 1714 | 1727 | const decl = src_loc.container.decl; |
| 1715 | 1728 | const node = decl.relativeToNodeIndex(node_off); |
| 1716 | | const tree = decl.container.file_scope.base.tree(); |
| 1729 | const tree = decl.namespace.file_scope.base.tree(); |
| 1717 | 1730 | const main_tokens = tree.nodes.items(.main_token); |
| 1718 | 1731 | const tok_index = main_tokens[node]; |
| 1719 | 1732 | const token_starts = tree.tokens.items(.start); |
| ... | ... | @@ -1722,7 +1735,7 @@ pub const SrcLoc = struct { |
| 1722 | 1735 | .node_offset_back2tok => |node_off| { |
| 1723 | 1736 | const decl = src_loc.container.decl; |
| 1724 | 1737 | const node = decl.relativeToNodeIndex(node_off); |
| 1725 | | const tree = decl.container.file_scope.base.tree(); |
| 1738 | const tree = decl.namespace.file_scope.base.tree(); |
| 1726 | 1739 | const tok_index = tree.firstToken(node) - 2; |
| 1727 | 1740 | const token_starts = tree.tokens.items(.start); |
| 1728 | 1741 | return token_starts[tok_index]; |
| ... | ... | @@ -1730,7 +1743,7 @@ pub const SrcLoc = struct { |
| 1730 | 1743 | .node_offset_var_decl_ty => |node_off| { |
| 1731 | 1744 | const decl = src_loc.container.decl; |
| 1732 | 1745 | const node = decl.relativeToNodeIndex(node_off); |
| 1733 | | const tree = decl.container.file_scope.base.tree(); |
| 1746 | const tree = decl.namespace.file_scope.base.tree(); |
| 1734 | 1747 | const node_tags = tree.nodes.items(.tag); |
| 1735 | 1748 | const full = switch (node_tags[node]) { |
| 1736 | 1749 | .global_var_decl => tree.globalVarDecl(node), |
| ... | ... | @@ -1750,7 +1763,7 @@ pub const SrcLoc = struct { |
| 1750 | 1763 | }, |
| 1751 | 1764 | .node_offset_builtin_call_arg0 => |node_off| { |
| 1752 | 1765 | const decl = src_loc.container.decl; |
| 1753 | | const tree = decl.container.file_scope.base.tree(); |
| 1766 | const tree = decl.namespace.file_scope.base.tree(); |
| 1754 | 1767 | const node_datas = tree.nodes.items(.data); |
| 1755 | 1768 | const node_tags = tree.nodes.items(.tag); |
| 1756 | 1769 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1766,7 +1779,7 @@ pub const SrcLoc = struct { |
| 1766 | 1779 | }, |
| 1767 | 1780 | .node_offset_builtin_call_arg1 => |node_off| { |
| 1768 | 1781 | const decl = src_loc.container.decl; |
| 1769 | | const tree = decl.container.file_scope.base.tree(); |
| 1782 | const tree = decl.namespace.file_scope.base.tree(); |
| 1770 | 1783 | const node_datas = tree.nodes.items(.data); |
| 1771 | 1784 | const node_tags = tree.nodes.items(.tag); |
| 1772 | 1785 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1782,7 +1795,7 @@ pub const SrcLoc = struct { |
| 1782 | 1795 | }, |
| 1783 | 1796 | .node_offset_array_access_index => |node_off| { |
| 1784 | 1797 | const decl = src_loc.container.decl; |
| 1785 | | const tree = decl.container.file_scope.base.tree(); |
| 1798 | const tree = decl.namespace.file_scope.base.tree(); |
| 1786 | 1799 | const node_datas = tree.nodes.items(.data); |
| 1787 | 1800 | const node_tags = tree.nodes.items(.tag); |
| 1788 | 1801 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1793,7 +1806,7 @@ pub const SrcLoc = struct { |
| 1793 | 1806 | }, |
| 1794 | 1807 | .node_offset_slice_sentinel => |node_off| { |
| 1795 | 1808 | const decl = src_loc.container.decl; |
| 1796 | | const tree = decl.container.file_scope.base.tree(); |
| 1809 | const tree = decl.namespace.file_scope.base.tree(); |
| 1797 | 1810 | const node_datas = tree.nodes.items(.data); |
| 1798 | 1811 | const node_tags = tree.nodes.items(.tag); |
| 1799 | 1812 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1810,7 +1823,7 @@ pub const SrcLoc = struct { |
| 1810 | 1823 | }, |
| 1811 | 1824 | .node_offset_call_func => |node_off| { |
| 1812 | 1825 | const decl = src_loc.container.decl; |
| 1813 | | const tree = decl.container.file_scope.base.tree(); |
| 1826 | const tree = decl.namespace.file_scope.base.tree(); |
| 1814 | 1827 | const node_datas = tree.nodes.items(.data); |
| 1815 | 1828 | const node_tags = tree.nodes.items(.tag); |
| 1816 | 1829 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1837,7 +1850,7 @@ pub const SrcLoc = struct { |
| 1837 | 1850 | }, |
| 1838 | 1851 | .node_offset_field_name => |node_off| { |
| 1839 | 1852 | const decl = src_loc.container.decl; |
| 1840 | | const tree = decl.container.file_scope.base.tree(); |
| 1853 | const tree = decl.namespace.file_scope.base.tree(); |
| 1841 | 1854 | const node_datas = tree.nodes.items(.data); |
| 1842 | 1855 | const node_tags = tree.nodes.items(.tag); |
| 1843 | 1856 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1850,7 +1863,7 @@ pub const SrcLoc = struct { |
| 1850 | 1863 | }, |
| 1851 | 1864 | .node_offset_deref_ptr => |node_off| { |
| 1852 | 1865 | const decl = src_loc.container.decl; |
| 1853 | | const tree = decl.container.file_scope.base.tree(); |
| 1866 | const tree = decl.namespace.file_scope.base.tree(); |
| 1854 | 1867 | const node_datas = tree.nodes.items(.data); |
| 1855 | 1868 | const node_tags = tree.nodes.items(.tag); |
| 1856 | 1869 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1860,7 +1873,7 @@ pub const SrcLoc = struct { |
| 1860 | 1873 | }, |
| 1861 | 1874 | .node_offset_asm_source => |node_off| { |
| 1862 | 1875 | const decl = src_loc.container.decl; |
| 1863 | | const tree = decl.container.file_scope.base.tree(); |
| 1876 | const tree = decl.namespace.file_scope.base.tree(); |
| 1864 | 1877 | const node_datas = tree.nodes.items(.data); |
| 1865 | 1878 | const node_tags = tree.nodes.items(.tag); |
| 1866 | 1879 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1876,7 +1889,7 @@ pub const SrcLoc = struct { |
| 1876 | 1889 | }, |
| 1877 | 1890 | .node_offset_asm_ret_ty => |node_off| { |
| 1878 | 1891 | const decl = src_loc.container.decl; |
| 1879 | | const tree = decl.container.file_scope.base.tree(); |
| 1892 | const tree = decl.namespace.file_scope.base.tree(); |
| 1880 | 1893 | const node_datas = tree.nodes.items(.data); |
| 1881 | 1894 | const node_tags = tree.nodes.items(.tag); |
| 1882 | 1895 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -1894,7 +1907,7 @@ pub const SrcLoc = struct { |
| 1894 | 1907 | .node_offset_for_cond, .node_offset_if_cond => |node_off| { |
| 1895 | 1908 | const decl = src_loc.container.decl; |
| 1896 | 1909 | const node = decl.relativeToNodeIndex(node_off); |
| 1897 | | const tree = decl.container.file_scope.base.tree(); |
| 1910 | const tree = decl.namespace.file_scope.base.tree(); |
| 1898 | 1911 | const node_tags = tree.nodes.items(.tag); |
| 1899 | 1912 | const src_node = switch (node_tags[node]) { |
| 1900 | 1913 | .if_simple => tree.ifSimple(node).ast.cond_expr, |
| ... | ... | @@ -1914,7 +1927,7 @@ pub const SrcLoc = struct { |
| 1914 | 1927 | .node_offset_bin_lhs => |node_off| { |
| 1915 | 1928 | const decl = src_loc.container.decl; |
| 1916 | 1929 | const node = decl.relativeToNodeIndex(node_off); |
| 1917 | | const tree = decl.container.file_scope.base.tree(); |
| 1930 | const tree = decl.namespace.file_scope.base.tree(); |
| 1918 | 1931 | const node_datas = tree.nodes.items(.data); |
| 1919 | 1932 | const src_node = node_datas[node].lhs; |
| 1920 | 1933 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -1925,7 +1938,7 @@ pub const SrcLoc = struct { |
| 1925 | 1938 | .node_offset_bin_rhs => |node_off| { |
| 1926 | 1939 | const decl = src_loc.container.decl; |
| 1927 | 1940 | const node = decl.relativeToNodeIndex(node_off); |
| 1928 | | const tree = decl.container.file_scope.base.tree(); |
| 1941 | const tree = decl.namespace.file_scope.base.tree(); |
| 1929 | 1942 | const node_datas = tree.nodes.items(.data); |
| 1930 | 1943 | const src_node = node_datas[node].rhs; |
| 1931 | 1944 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -1937,7 +1950,7 @@ pub const SrcLoc = struct { |
| 1937 | 1950 | .node_offset_switch_operand => |node_off| { |
| 1938 | 1951 | const decl = src_loc.container.decl; |
| 1939 | 1952 | const node = decl.relativeToNodeIndex(node_off); |
| 1940 | | const tree = decl.container.file_scope.base.tree(); |
| 1953 | const tree = decl.namespace.file_scope.base.tree(); |
| 1941 | 1954 | const node_datas = tree.nodes.items(.data); |
| 1942 | 1955 | const src_node = node_datas[node].lhs; |
| 1943 | 1956 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -1949,7 +1962,7 @@ pub const SrcLoc = struct { |
| 1949 | 1962 | .node_offset_switch_special_prong => |node_off| { |
| 1950 | 1963 | const decl = src_loc.container.decl; |
| 1951 | 1964 | const switch_node = decl.relativeToNodeIndex(node_off); |
| 1952 | | const tree = decl.container.file_scope.base.tree(); |
| 1965 | const tree = decl.namespace.file_scope.base.tree(); |
| 1953 | 1966 | const node_datas = tree.nodes.items(.data); |
| 1954 | 1967 | const node_tags = tree.nodes.items(.tag); |
| 1955 | 1968 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -1976,7 +1989,7 @@ pub const SrcLoc = struct { |
| 1976 | 1989 | .node_offset_switch_range => |node_off| { |
| 1977 | 1990 | const decl = src_loc.container.decl; |
| 1978 | 1991 | const switch_node = decl.relativeToNodeIndex(node_off); |
| 1979 | | const tree = decl.container.file_scope.base.tree(); |
| 1992 | const tree = decl.namespace.file_scope.base.tree(); |
| 1980 | 1993 | const node_datas = tree.nodes.items(.data); |
| 1981 | 1994 | const node_tags = tree.nodes.items(.tag); |
| 1982 | 1995 | const main_tokens = tree.nodes.items(.main_token); |
| ... | ... | @@ -2006,7 +2019,7 @@ pub const SrcLoc = struct { |
| 2006 | 2019 | |
| 2007 | 2020 | .node_offset_fn_type_cc => |node_off| { |
| 2008 | 2021 | const decl = src_loc.container.decl; |
| 2009 | | const tree = decl.container.file_scope.base.tree(); |
| 2022 | const tree = decl.namespace.file_scope.base.tree(); |
| 2010 | 2023 | const node_datas = tree.nodes.items(.data); |
| 2011 | 2024 | const node_tags = tree.nodes.items(.tag); |
| 2012 | 2025 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -2026,7 +2039,7 @@ pub const SrcLoc = struct { |
| 2026 | 2039 | |
| 2027 | 2040 | .node_offset_fn_type_ret_ty => |node_off| { |
| 2028 | 2041 | const decl = src_loc.container.decl; |
| 2029 | | const tree = decl.container.file_scope.base.tree(); |
| 2042 | const tree = decl.namespace.file_scope.base.tree(); |
| 2030 | 2043 | const node_datas = tree.nodes.items(.data); |
| 2031 | 2044 | const node_tags = tree.nodes.items(.tag); |
| 2032 | 2045 | const node = decl.relativeToNodeIndex(node_off); |
| ... | ... | @@ -2351,7 +2364,6 @@ pub fn deinit(mod: *Module) void { |
| 2351 | 2364 | mod.export_owners.deinit(gpa); |
| 2352 | 2365 | |
| 2353 | 2366 | mod.symbol_exports.deinit(gpa); |
| 2354 | | mod.root_scope.destroy(gpa); |
| 2355 | 2367 | |
| 2356 | 2368 | var it = mod.global_error_set.iterator(); |
| 2357 | 2369 | while (it.next()) |entry| { |
| ... | ... | @@ -2362,6 +2374,7 @@ pub fn deinit(mod: *Module) void { |
| 2362 | 2374 | mod.error_name_list.deinit(gpa); |
| 2363 | 2375 | |
| 2364 | 2376 | for (mod.import_table.items()) |entry| { |
| 2377 | gpa.free(entry.key); |
| 2365 | 2378 | entry.value.destroy(gpa); |
| 2366 | 2379 | } |
| 2367 | 2380 | mod.import_table.deinit(gpa); |
| ... | ... | @@ -2465,7 +2478,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { |
| 2465 | 2478 | const tracy = trace(@src()); |
| 2466 | 2479 | defer tracy.end(); |
| 2467 | 2480 | |
| 2468 | | const tree = try mod.getAstTree(decl.container.file_scope); |
| 2481 | const tree = try mod.getAstTree(decl.namespace.file_scope); |
| 2469 | 2482 | const node_tags = tree.nodes.items(.tag); |
| 2470 | 2483 | const node_datas = tree.nodes.items(.data); |
| 2471 | 2484 | const decl_node = decl.src_node; |
| ... | ... | @@ -2516,7 +2529,7 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool { |
| 2516 | 2529 | |
| 2517 | 2530 | var gen_scope: Scope.GenZir = .{ |
| 2518 | 2531 | .force_comptime = true, |
| 2519 | | .parent = &decl.container.base, |
| 2532 | .parent = &decl.namespace.base, |
| 2520 | 2533 | .astgen = &astgen, |
| 2521 | 2534 | }; |
| 2522 | 2535 | defer gen_scope.instructions.deinit(mod.gpa); |
| ... | ... | @@ -2590,7 +2603,7 @@ fn astgenAndSemaFn( |
| 2590 | 2603 | |
| 2591 | 2604 | var fn_type_scope: Scope.GenZir = .{ |
| 2592 | 2605 | .force_comptime = true, |
| 2593 | | .parent = &decl.container.base, |
| 2606 | .parent = &decl.namespace.base, |
| 2594 | 2607 | .astgen = &fn_type_astgen, |
| 2595 | 2608 | }; |
| 2596 | 2609 | defer fn_type_scope.instructions.deinit(mod.gpa); |
| ... | ... | @@ -2829,7 +2842,7 @@ fn astgenAndSemaFn( |
| 2829 | 2842 | |
| 2830 | 2843 | var gen_scope: Scope.GenZir = .{ |
| 2831 | 2844 | .force_comptime = false, |
| 2832 | | .parent = &decl.container.base, |
| 2845 | .parent = &decl.namespace.base, |
| 2833 | 2846 | .astgen = &astgen, |
| 2834 | 2847 | }; |
| 2835 | 2848 | defer gen_scope.instructions.deinit(mod.gpa); |
| ... | ... | @@ -3035,7 +3048,7 @@ fn astgenAndSemaVarDecl( |
| 3035 | 3048 | |
| 3036 | 3049 | var gen_scope: Scope.GenZir = .{ |
| 3037 | 3050 | .force_comptime = true, |
| 3038 | | .parent = &decl.container.base, |
| 3051 | .parent = &decl.namespace.base, |
| 3039 | 3052 | .astgen = &astgen, |
| 3040 | 3053 | }; |
| 3041 | 3054 | defer gen_scope.instructions.deinit(mod.gpa); |
| ... | ... | @@ -3104,7 +3117,7 @@ fn astgenAndSemaVarDecl( |
| 3104 | 3117 | |
| 3105 | 3118 | var type_scope: Scope.GenZir = .{ |
| 3106 | 3119 | .force_comptime = true, |
| 3107 | | .parent = &decl.container.base, |
| 3120 | .parent = &decl.namespace.base, |
| 3108 | 3121 | .astgen = &astgen, |
| 3109 | 3122 | }; |
| 3110 | 3123 | defer type_scope.instructions.deinit(mod.gpa); |
| ... | ... | @@ -3220,46 +3233,48 @@ pub fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !u3 |
| 3220 | 3233 | return @intCast(u32, gop.index); |
| 3221 | 3234 | } |
| 3222 | 3235 | |
| 3223 | | pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree { |
| 3236 | pub fn getAstTree(mod: *Module, file: *Scope.File) !*const ast.Tree { |
| 3224 | 3237 | const tracy = trace(@src()); |
| 3225 | 3238 | defer tracy.end(); |
| 3226 | 3239 | |
| 3227 | | switch (root_scope.status) { |
| 3240 | switch (file.status) { |
| 3228 | 3241 | .never_loaded, .unloaded_success => { |
| 3229 | | try mod.failed_files.ensureCapacity(mod.gpa, mod.failed_files.items().len + 1); |
| 3242 | const gpa = mod.gpa; |
| 3243 | |
| 3244 | try mod.failed_files.ensureCapacity(gpa, mod.failed_files.items().len + 1); |
| 3230 | 3245 | |
| 3231 | | const source = try root_scope.getSource(mod); |
| 3246 | const source = try file.getSource(gpa); |
| 3232 | 3247 | |
| 3233 | 3248 | var keep_tree = false; |
| 3234 | | root_scope.tree = try std.zig.parse(mod.gpa, source); |
| 3235 | | defer if (!keep_tree) root_scope.tree.deinit(mod.gpa); |
| 3249 | file.tree = try std.zig.parse(gpa, source); |
| 3250 | defer if (!keep_tree) file.tree.deinit(gpa); |
| 3236 | 3251 | |
| 3237 | | const tree = &root_scope.tree; |
| 3252 | const tree = &file.tree; |
| 3238 | 3253 | |
| 3239 | 3254 | if (tree.errors.len != 0) { |
| 3240 | 3255 | const parse_err = tree.errors[0]; |
| 3241 | 3256 | |
| 3242 | | var msg = std.ArrayList(u8).init(mod.gpa); |
| 3257 | var msg = std.ArrayList(u8).init(gpa); |
| 3243 | 3258 | defer msg.deinit(); |
| 3244 | 3259 | |
| 3245 | 3260 | const token_starts = tree.tokens.items(.start); |
| 3246 | 3261 | |
| 3247 | 3262 | try tree.renderError(parse_err, msg.writer()); |
| 3248 | | const err_msg = try mod.gpa.create(ErrorMsg); |
| 3263 | const err_msg = try gpa.create(ErrorMsg); |
| 3249 | 3264 | err_msg.* = .{ |
| 3250 | 3265 | .src_loc = .{ |
| 3251 | | .container = .{ .file_scope = root_scope }, |
| 3266 | .container = .{ .file_scope = file }, |
| 3252 | 3267 | .lazy = .{ .byte_abs = token_starts[parse_err.token] }, |
| 3253 | 3268 | }, |
| 3254 | 3269 | .msg = msg.toOwnedSlice(), |
| 3255 | 3270 | }; |
| 3256 | 3271 | |
| 3257 | | mod.failed_files.putAssumeCapacityNoClobber(root_scope, err_msg); |
| 3258 | | root_scope.status = .unloaded_parse_failure; |
| 3272 | mod.failed_files.putAssumeCapacityNoClobber(file, err_msg); |
| 3273 | file.status = .unloaded_parse_failure; |
| 3259 | 3274 | return error.AnalysisFail; |
| 3260 | 3275 | } |
| 3261 | 3276 | |
| 3262 | | root_scope.status = .loaded_success; |
| 3277 | file.status = .loaded_success; |
| 3263 | 3278 | keep_tree = true; |
| 3264 | 3279 | |
| 3265 | 3280 | return tree; |
| ... | ... | @@ -3267,30 +3282,186 @@ pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree { |
| 3267 | 3282 | |
| 3268 | 3283 | .unloaded_parse_failure => return error.AnalysisFail, |
| 3269 | 3284 | |
| 3270 | | .loaded_success => return &root_scope.tree, |
| 3285 | .loaded_success => return &file.tree, |
| 3271 | 3286 | } |
| 3272 | 3287 | } |
| 3273 | 3288 | |
| 3274 | | pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3289 | pub fn importFile(mod: *Module, cur_pkg: *Package, import_string: []const u8) !*Scope.File { |
| 3290 | const gpa = mod.gpa; |
| 3291 | |
| 3292 | const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse "."; |
| 3293 | const found_pkg = cur_pkg.table.get(import_string); |
| 3294 | |
| 3295 | const resolved_path = if (found_pkg) |pkg| |
| 3296 | try std.fs.path.resolve(gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path }) |
| 3297 | else |
| 3298 | try std.fs.path.resolve(gpa, &[_][]const u8{ cur_pkg_dir_path, import_string }); |
| 3299 | var keep_resolved_path = false; |
| 3300 | defer if (!keep_resolved_path) gpa.free(resolved_path); |
| 3301 | |
| 3302 | const gop = try mod.import_table.getOrPut(gpa, resolved_path); |
| 3303 | if (gop.found_existing) return gop.entry.value; |
| 3304 | |
| 3305 | if (found_pkg == null) { |
| 3306 | const resolved_root_path = try std.fs.path.resolve(gpa, &[_][]const u8{cur_pkg_dir_path}); |
| 3307 | defer gpa.free(resolved_root_path); |
| 3308 | |
| 3309 | if (!mem.startsWith(u8, resolved_path, resolved_root_path)) { |
| 3310 | return error.ImportOutsidePkgPath; |
| 3311 | } |
| 3312 | } |
| 3313 | |
| 3314 | const new_file = try gpa.create(Scope.File); |
| 3315 | gop.entry.value = new_file; |
| 3316 | new_file.* = .{ |
| 3317 | .sub_file_path = resolved_path, |
| 3318 | .source = undefined, |
| 3319 | .source_hash = undefined, |
| 3320 | .source_loaded = false, |
| 3321 | .stat_size = undefined, |
| 3322 | .stat_inode = undefined, |
| 3323 | .stat_mtime = undefined, |
| 3324 | .tree = undefined, |
| 3325 | .status = .never_loaded, |
| 3326 | .pkg = found_pkg orelse cur_pkg, |
| 3327 | .namespace = undefined, |
| 3328 | }; |
| 3329 | keep_resolved_path = true; |
| 3330 | |
| 3331 | const tree = try mod.getAstTree(new_file); |
| 3332 | |
| 3333 | const parent_name_hash: Scope.NameHash = if (found_pkg) |pkg| |
| 3334 | pkg.namespace_hash |
| 3335 | else |
| 3336 | std.zig.hashName(cur_pkg.namespace_hash, "/", resolved_path); |
| 3337 | |
| 3338 | // We need a Decl to pass to AstGen and collect dependencies. But ultimately we |
| 3339 | // want to pass them on to the Decl for the struct that represents the file. |
| 3340 | var tmp_namespace: Scope.Namespace = .{ |
| 3341 | .parent = null, |
| 3342 | .file_scope = new_file, |
| 3343 | .parent_name_hash = parent_name_hash, |
| 3344 | .ty = Type.initTag(.type), |
| 3345 | }; |
| 3346 | const top_decl = try mod.createNewDecl( |
| 3347 | &tmp_namespace, |
| 3348 | resolved_path, |
| 3349 | 0, |
| 3350 | parent_name_hash, |
| 3351 | new_file.source_hash, |
| 3352 | ); |
| 3353 | defer { |
| 3354 | mod.decl_table.removeAssertDiscard(parent_name_hash); |
| 3355 | top_decl.destroy(mod); |
| 3356 | } |
| 3357 | |
| 3358 | var gen_scope_arena = std.heap.ArenaAllocator.init(gpa); |
| 3359 | defer gen_scope_arena.deinit(); |
| 3360 | |
| 3361 | var astgen = try AstGen.init(mod, top_decl, &gen_scope_arena.allocator); |
| 3362 | defer astgen.deinit(); |
| 3363 | |
| 3364 | var gen_scope: Scope.GenZir = .{ |
| 3365 | .force_comptime = true, |
| 3366 | .parent = &new_file.base, |
| 3367 | .astgen = &astgen, |
| 3368 | }; |
| 3369 | defer gen_scope.instructions.deinit(gpa); |
| 3370 | |
| 3371 | const container_decl: ast.full.ContainerDecl = .{ |
| 3372 | .layout_token = null, |
| 3373 | .ast = .{ |
| 3374 | .main_token = undefined, |
| 3375 | .enum_token = null, |
| 3376 | .members = tree.rootDecls(), |
| 3377 | .arg = 0, |
| 3378 | }, |
| 3379 | }; |
| 3380 | |
| 3381 | const struct_decl_ref = try AstGen.structDeclInner( |
| 3382 | &gen_scope, |
| 3383 | &gen_scope.base, |
| 3384 | 0, |
| 3385 | container_decl, |
| 3386 | .struct_decl, |
| 3387 | ); |
| 3388 | _ = try gen_scope.addBreak(.break_inline, 0, struct_decl_ref); |
| 3389 | |
| 3390 | var code = try gen_scope.finish(); |
| 3391 | defer code.deinit(gpa); |
| 3392 | if (std.builtin.mode == .Debug and mod.comp.verbose_ir) { |
| 3393 | code.dump(gpa, "import", &gen_scope.base, 0) catch {}; |
| 3394 | } |
| 3395 | |
| 3396 | var sema: Sema = .{ |
| 3397 | .mod = mod, |
| 3398 | .gpa = gpa, |
| 3399 | .arena = &gen_scope_arena.allocator, |
| 3400 | .code = code, |
| 3401 | .inst_map = try gen_scope_arena.allocator.alloc(*ir.Inst, code.instructions.len), |
| 3402 | .owner_decl = top_decl, |
| 3403 | .func = null, |
| 3404 | .owner_func = null, |
| 3405 | .param_inst_list = &.{}, |
| 3406 | }; |
| 3407 | var block_scope: Scope.Block = .{ |
| 3408 | .parent = null, |
| 3409 | .sema = &sema, |
| 3410 | .src_decl = top_decl, |
| 3411 | .instructions = .{}, |
| 3412 | .inlining = null, |
| 3413 | .is_comptime = true, |
| 3414 | }; |
| 3415 | defer block_scope.instructions.deinit(gpa); |
| 3416 | |
| 3417 | const init_inst_zir_ref = try sema.rootAsRef(&block_scope); |
| 3418 | const analyzed_struct_inst = try sema.resolveInst(init_inst_zir_ref); |
| 3419 | assert(analyzed_struct_inst.ty.zigTypeTag() == .Type); |
| 3420 | const val = analyzed_struct_inst.value().?; |
| 3421 | const struct_ty = try val.toType(&gen_scope_arena.allocator); |
| 3422 | const struct_decl = struct_ty.getOwnerDecl(); |
| 3423 | |
| 3424 | new_file.namespace = struct_ty.getNamespace().?; |
| 3425 | new_file.namespace.parent = null; |
| 3426 | new_file.namespace.parent_name_hash = tmp_namespace.parent_name_hash; |
| 3427 | |
| 3428 | // Transfer the dependencies to `owner_decl`. |
| 3429 | assert(top_decl.dependants.count() == 0); |
| 3430 | for (top_decl.dependencies.items()) |entry| { |
| 3431 | const dep = entry.key; |
| 3432 | dep.removeDependant(top_decl); |
| 3433 | if (dep == struct_decl) continue; |
| 3434 | _ = try mod.declareDeclDependency(struct_decl, dep); |
| 3435 | } |
| 3436 | |
| 3437 | try mod.analyzeFile(new_file); |
| 3438 | return new_file; |
| 3439 | } |
| 3440 | |
| 3441 | pub fn analyzeFile(mod: *Module, file: *Scope.File) !void { |
| 3442 | return mod.analyzeNamespace(file.namespace); |
| 3443 | } |
| 3444 | |
| 3445 | pub fn analyzeNamespace(mod: *Module, namespace: *Scope.Namespace) !void { |
| 3275 | 3446 | const tracy = trace(@src()); |
| 3276 | 3447 | defer tracy.end(); |
| 3277 | 3448 | |
| 3278 | 3449 | // We may be analyzing it for the first time, or this may be |
| 3279 | 3450 | // an incremental update. This code handles both cases. |
| 3280 | | const tree = try mod.getAstTree(container_scope.file_scope); |
| 3451 | const tree = try mod.getAstTree(namespace.file_scope); |
| 3281 | 3452 | const node_tags = tree.nodes.items(.tag); |
| 3282 | 3453 | const node_datas = tree.nodes.items(.data); |
| 3283 | 3454 | const decls = tree.rootDecls(); |
| 3284 | 3455 | |
| 3285 | 3456 | try mod.comp.work_queue.ensureUnusedCapacity(decls.len); |
| 3286 | | try container_scope.decls.ensureCapacity(mod.gpa, decls.len); |
| 3457 | try namespace.decls.ensureCapacity(mod.gpa, decls.len); |
| 3287 | 3458 | |
| 3288 | | // Keep track of the decls that we expect to see in this file so that |
| 3459 | // Keep track of the decls that we expect to see in this namespace so that |
| 3289 | 3460 | // we know which ones have been deleted. |
| 3290 | 3461 | var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(mod.gpa); |
| 3291 | 3462 | defer deleted_decls.deinit(); |
| 3292 | | try deleted_decls.ensureCapacity(container_scope.decls.items().len); |
| 3293 | | for (container_scope.decls.items()) |entry| { |
| 3463 | try deleted_decls.ensureCapacity(namespace.decls.items().len); |
| 3464 | for (namespace.decls.items()) |entry| { |
| 3294 | 3465 | deleted_decls.putAssumeCapacityNoClobber(entry.key, {}); |
| 3295 | 3466 | } |
| 3296 | 3467 | |
| ... | ... | @@ -3310,7 +3481,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3310 | 3481 | .fn_proto_simple => { |
| 3311 | 3482 | var params: [1]ast.Node.Index = undefined; |
| 3312 | 3483 | try mod.semaContainerFn( |
| 3313 | | container_scope, |
| 3484 | namespace, |
| 3314 | 3485 | &deleted_decls, |
| 3315 | 3486 | &outdated_decls, |
| 3316 | 3487 | decl_node, |
| ... | ... | @@ -3320,7 +3491,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3320 | 3491 | ); |
| 3321 | 3492 | }, |
| 3322 | 3493 | .fn_proto_multi => try mod.semaContainerFn( |
| 3323 | | container_scope, |
| 3494 | namespace, |
| 3324 | 3495 | &deleted_decls, |
| 3325 | 3496 | &outdated_decls, |
| 3326 | 3497 | decl_node, |
| ... | ... | @@ -3331,7 +3502,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3331 | 3502 | .fn_proto_one => { |
| 3332 | 3503 | var params: [1]ast.Node.Index = undefined; |
| 3333 | 3504 | try mod.semaContainerFn( |
| 3334 | | container_scope, |
| 3505 | namespace, |
| 3335 | 3506 | &deleted_decls, |
| 3336 | 3507 | &outdated_decls, |
| 3337 | 3508 | decl_node, |
| ... | ... | @@ -3341,7 +3512,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3341 | 3512 | ); |
| 3342 | 3513 | }, |
| 3343 | 3514 | .fn_proto => try mod.semaContainerFn( |
| 3344 | | container_scope, |
| 3515 | namespace, |
| 3345 | 3516 | &deleted_decls, |
| 3346 | 3517 | &outdated_decls, |
| 3347 | 3518 | decl_node, |
| ... | ... | @@ -3355,7 +3526,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3355 | 3526 | .fn_proto_simple => { |
| 3356 | 3527 | var params: [1]ast.Node.Index = undefined; |
| 3357 | 3528 | try mod.semaContainerFn( |
| 3358 | | container_scope, |
| 3529 | namespace, |
| 3359 | 3530 | &deleted_decls, |
| 3360 | 3531 | &outdated_decls, |
| 3361 | 3532 | decl_node, |
| ... | ... | @@ -3365,7 +3536,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3365 | 3536 | ); |
| 3366 | 3537 | }, |
| 3367 | 3538 | .fn_proto_multi => try mod.semaContainerFn( |
| 3368 | | container_scope, |
| 3539 | namespace, |
| 3369 | 3540 | &deleted_decls, |
| 3370 | 3541 | &outdated_decls, |
| 3371 | 3542 | decl_node, |
| ... | ... | @@ -3376,7 +3547,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3376 | 3547 | .fn_proto_one => { |
| 3377 | 3548 | var params: [1]ast.Node.Index = undefined; |
| 3378 | 3549 | try mod.semaContainerFn( |
| 3379 | | container_scope, |
| 3550 | namespace, |
| 3380 | 3551 | &deleted_decls, |
| 3381 | 3552 | &outdated_decls, |
| 3382 | 3553 | decl_node, |
| ... | ... | @@ -3386,7 +3557,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3386 | 3557 | ); |
| 3387 | 3558 | }, |
| 3388 | 3559 | .fn_proto => try mod.semaContainerFn( |
| 3389 | | container_scope, |
| 3560 | namespace, |
| 3390 | 3561 | &deleted_decls, |
| 3391 | 3562 | &outdated_decls, |
| 3392 | 3563 | decl_node, |
| ... | ... | @@ -3396,7 +3567,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3396 | 3567 | ), |
| 3397 | 3568 | |
| 3398 | 3569 | .global_var_decl => try mod.semaContainerVar( |
| 3399 | | container_scope, |
| 3570 | namespace, |
| 3400 | 3571 | &deleted_decls, |
| 3401 | 3572 | &outdated_decls, |
| 3402 | 3573 | decl_node, |
| ... | ... | @@ -3404,7 +3575,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3404 | 3575 | tree.globalVarDecl(decl_node), |
| 3405 | 3576 | ), |
| 3406 | 3577 | .local_var_decl => try mod.semaContainerVar( |
| 3407 | | container_scope, |
| 3578 | namespace, |
| 3408 | 3579 | &deleted_decls, |
| 3409 | 3580 | &outdated_decls, |
| 3410 | 3581 | decl_node, |
| ... | ... | @@ -3412,7 +3583,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3412 | 3583 | tree.localVarDecl(decl_node), |
| 3413 | 3584 | ), |
| 3414 | 3585 | .simple_var_decl => try mod.semaContainerVar( |
| 3415 | | container_scope, |
| 3586 | namespace, |
| 3416 | 3587 | &deleted_decls, |
| 3417 | 3588 | &outdated_decls, |
| 3418 | 3589 | decl_node, |
| ... | ... | @@ -3420,7 +3591,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3420 | 3591 | tree.simpleVarDecl(decl_node), |
| 3421 | 3592 | ), |
| 3422 | 3593 | .aligned_var_decl => try mod.semaContainerVar( |
| 3423 | | container_scope, |
| 3594 | namespace, |
| 3424 | 3595 | &deleted_decls, |
| 3425 | 3596 | &outdated_decls, |
| 3426 | 3597 | decl_node, |
| ... | ... | @@ -3433,11 +3604,11 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3433 | 3604 | const name = try std.fmt.allocPrint(mod.gpa, "__comptime_{d}", .{name_index}); |
| 3434 | 3605 | defer mod.gpa.free(name); |
| 3435 | 3606 | |
| 3436 | | const name_hash = container_scope.fullyQualifiedNameHash(name); |
| 3607 | const name_hash = namespace.fullyQualifiedNameHash(name); |
| 3437 | 3608 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); |
| 3438 | 3609 | |
| 3439 | | const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash); |
| 3440 | | container_scope.decls.putAssumeCapacity(new_decl, {}); |
| 3610 | const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash); |
| 3611 | namespace.decls.putAssumeCapacity(new_decl, {}); |
| 3441 | 3612 | mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl }); |
| 3442 | 3613 | }, |
| 3443 | 3614 | |
| ... | ... | @@ -3483,7 +3654,7 @@ pub fn analyzeContainer(mod: *Module, container_scope: *Scope.Container) !void { |
| 3483 | 3654 | |
| 3484 | 3655 | fn semaContainerFn( |
| 3485 | 3656 | mod: *Module, |
| 3486 | | container_scope: *Scope.Container, |
| 3657 | namespace: *Scope.Namespace, |
| 3487 | 3658 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), |
| 3488 | 3659 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), |
| 3489 | 3660 | decl_node: ast.Node.Index, |
| ... | ... | @@ -3500,25 +3671,25 @@ fn semaContainerFn( |
| 3500 | 3671 | @panic("TODO missing function name"); |
| 3501 | 3672 | }; |
| 3502 | 3673 | const name = tree.tokenSlice(name_token); // TODO use identifierTokenString |
| 3503 | | const name_hash = container_scope.fullyQualifiedNameHash(name); |
| 3674 | const name_hash = namespace.fullyQualifiedNameHash(name); |
| 3504 | 3675 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); |
| 3505 | 3676 | if (mod.decl_table.get(name_hash)) |decl| { |
| 3506 | | // Update the AST Node index of the decl, even if its contents are unchanged, it may |
| 3677 | // Update the AST node of the decl; even if its contents are unchanged, it may |
| 3507 | 3678 | // have been re-ordered. |
| 3508 | 3679 | const prev_src_node = decl.src_node; |
| 3509 | 3680 | decl.src_node = decl_node; |
| 3510 | 3681 | if (deleted_decls.swapRemove(decl) == null) { |
| 3511 | 3682 | decl.analysis = .sema_failure; |
| 3512 | 3683 | const msg = try ErrorMsg.create(mod.gpa, .{ |
| 3513 | | .container = .{ .file_scope = container_scope.file_scope }, |
| 3684 | .container = .{ .file_scope = namespace.file_scope }, |
| 3514 | 3685 | .lazy = .{ .token_abs = name_token }, |
| 3515 | | }, "redefinition of '{s}'", .{decl.name}); |
| 3686 | }, "redeclaration of '{s}'", .{decl.name}); |
| 3516 | 3687 | errdefer msg.destroy(mod.gpa); |
| 3517 | 3688 | const other_src_loc: SrcLoc = .{ |
| 3518 | | .container = .{ .file_scope = decl.container.file_scope }, |
| 3689 | .container = .{ .file_scope = decl.namespace.file_scope }, |
| 3519 | 3690 | .lazy = .{ .node_abs = prev_src_node }, |
| 3520 | 3691 | }; |
| 3521 | | try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{}); |
| 3692 | try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); |
| 3522 | 3693 | try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); |
| 3523 | 3694 | } else { |
| 3524 | 3695 | if (!srcHashEql(decl.contents_hash, contents_hash)) { |
| ... | ... | @@ -3542,8 +3713,8 @@ fn semaContainerFn( |
| 3542 | 3713 | } |
| 3543 | 3714 | } |
| 3544 | 3715 | } else { |
| 3545 | | const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash); |
| 3546 | | container_scope.decls.putAssumeCapacity(new_decl, {}); |
| 3716 | const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash); |
| 3717 | namespace.decls.putAssumeCapacity(new_decl, {}); |
| 3547 | 3718 | if (fn_proto.extern_export_token) |maybe_export_token| { |
| 3548 | 3719 | const token_tags = tree.tokens.items(.tag); |
| 3549 | 3720 | if (token_tags[maybe_export_token] == .keyword_export) { |
| ... | ... | @@ -3556,7 +3727,7 @@ fn semaContainerFn( |
| 3556 | 3727 | |
| 3557 | 3728 | fn semaContainerVar( |
| 3558 | 3729 | mod: *Module, |
| 3559 | | container_scope: *Scope.Container, |
| 3730 | namespace: *Scope.Namespace, |
| 3560 | 3731 | deleted_decls: *std.AutoArrayHashMap(*Decl, void), |
| 3561 | 3732 | outdated_decls: *std.AutoArrayHashMap(*Decl, void), |
| 3562 | 3733 | decl_node: ast.Node.Index, |
| ... | ... | @@ -3568,7 +3739,7 @@ fn semaContainerVar( |
| 3568 | 3739 | |
| 3569 | 3740 | const name_token = var_decl.ast.mut_token + 1; |
| 3570 | 3741 | const name = tree.tokenSlice(name_token); // TODO identifierTokenString |
| 3571 | | const name_hash = container_scope.fullyQualifiedNameHash(name); |
| 3742 | const name_hash = namespace.fullyQualifiedNameHash(name); |
| 3572 | 3743 | const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node)); |
| 3573 | 3744 | if (mod.decl_table.get(name_hash)) |decl| { |
| 3574 | 3745 | // Update the AST Node index of the decl, even if its contents are unchanged, it may |
| ... | ... | @@ -3578,23 +3749,23 @@ fn semaContainerVar( |
| 3578 | 3749 | if (deleted_decls.swapRemove(decl) == null) { |
| 3579 | 3750 | decl.analysis = .sema_failure; |
| 3580 | 3751 | const msg = try ErrorMsg.create(mod.gpa, .{ |
| 3581 | | .container = .{ .file_scope = container_scope.file_scope }, |
| 3752 | .container = .{ .file_scope = namespace.file_scope }, |
| 3582 | 3753 | .lazy = .{ .token_abs = name_token }, |
| 3583 | | }, "redefinition of '{s}'", .{decl.name}); |
| 3754 | }, "redeclaration of '{s}'", .{decl.name}); |
| 3584 | 3755 | errdefer msg.destroy(mod.gpa); |
| 3585 | 3756 | const other_src_loc: SrcLoc = .{ |
| 3586 | | .container = .{ .file_scope = decl.container.file_scope }, |
| 3757 | .container = .{ .file_scope = decl.namespace.file_scope }, |
| 3587 | 3758 | .lazy = .{ .node_abs = prev_src_node }, |
| 3588 | 3759 | }; |
| 3589 | | try mod.errNoteNonLazy(other_src_loc, msg, "previous definition here", .{}); |
| 3760 | try mod.errNoteNonLazy(other_src_loc, msg, "previously declared here", .{}); |
| 3590 | 3761 | try mod.failed_decls.putNoClobber(mod.gpa, decl, msg); |
| 3591 | 3762 | } else if (!srcHashEql(decl.contents_hash, contents_hash)) { |
| 3592 | 3763 | try outdated_decls.put(decl, {}); |
| 3593 | 3764 | decl.contents_hash = contents_hash; |
| 3594 | 3765 | } |
| 3595 | 3766 | } else { |
| 3596 | | const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_node, name_hash, contents_hash); |
| 3597 | | container_scope.decls.putAssumeCapacity(new_decl, {}); |
| 3767 | const new_decl = try mod.createNewDecl(namespace, name, decl_node, name_hash, contents_hash); |
| 3768 | namespace.decls.putAssumeCapacity(new_decl, {}); |
| 3598 | 3769 | if (var_decl.extern_export_token) |maybe_export_token| { |
| 3599 | 3770 | const token_tags = tree.tokens.items(.tag); |
| 3600 | 3771 | if (token_tags[maybe_export_token] == .keyword_export) { |
| ... | ... | @@ -3624,7 +3795,7 @@ pub fn deleteDecl( |
| 3624 | 3795 | |
| 3625 | 3796 | // Remove from the namespace it resides in. In the case of an anonymous Decl it will |
| 3626 | 3797 | // not be present in the set, and this does nothing. |
| 3627 | | decl.container.removeDecl(decl); |
| 3798 | decl.namespace.removeDecl(decl); |
| 3628 | 3799 | |
| 3629 | 3800 | const name_hash = decl.fullyQualifiedNameHash(); |
| 3630 | 3801 | mod.decl_table.removeAssertDiscard(name_hash); |
| ... | ... | @@ -3786,7 +3957,7 @@ fn markOutdatedDecl(mod: *Module, decl: *Decl) !void { |
| 3786 | 3957 | |
| 3787 | 3958 | fn allocateNewDecl( |
| 3788 | 3959 | mod: *Module, |
| 3789 | | scope: *Scope, |
| 3960 | namespace: *Scope.Namespace, |
| 3790 | 3961 | src_node: ast.Node.Index, |
| 3791 | 3962 | contents_hash: std.zig.SrcHash, |
| 3792 | 3963 | ) !*Decl { |
| ... | ... | @@ -3802,7 +3973,7 @@ fn allocateNewDecl( |
| 3802 | 3973 | |
| 3803 | 3974 | new_decl.* = .{ |
| 3804 | 3975 | .name = "", |
| 3805 | | .container = scope.namespace(), |
| 3976 | .namespace = namespace, |
| 3806 | 3977 | .src_node = src_node, |
| 3807 | 3978 | .typed_value = .{ .never_succeeded = {} }, |
| 3808 | 3979 | .analysis = .unreferenced, |
| ... | ... | @@ -3832,14 +4003,14 @@ fn allocateNewDecl( |
| 3832 | 4003 | |
| 3833 | 4004 | fn createNewDecl( |
| 3834 | 4005 | mod: *Module, |
| 3835 | | scope: *Scope, |
| 4006 | namespace: *Scope.Namespace, |
| 3836 | 4007 | decl_name: []const u8, |
| 3837 | 4008 | src_node: ast.Node.Index, |
| 3838 | 4009 | name_hash: Scope.NameHash, |
| 3839 | 4010 | contents_hash: std.zig.SrcHash, |
| 3840 | 4011 | ) !*Decl { |
| 3841 | 4012 | try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1); |
| 3842 | | const new_decl = try mod.allocateNewDecl(scope, src_node, contents_hash); |
| 4013 | const new_decl = try mod.allocateNewDecl(namespace, src_node, contents_hash); |
| 3843 | 4014 | errdefer mod.gpa.destroy(new_decl); |
| 3844 | 4015 | new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name); |
| 3845 | 4016 | mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl); |
| ... | ... | @@ -3930,7 +4101,7 @@ pub fn analyzeExport( |
| 3930 | 4101 | ); |
| 3931 | 4102 | errdefer msg.destroy(mod.gpa); |
| 3932 | 4103 | try mod.errNote( |
| 3933 | | &other_export.owner_decl.container.base, |
| 4104 | &other_export.owner_decl.namespace.base, |
| 3934 | 4105 | other_export.src, |
| 3935 | 4106 | msg, |
| 3936 | 4107 | "other symbol here", |
| ... | ... | @@ -4050,9 +4221,10 @@ pub fn createAnonymousDecl( |
| 4050 | 4221 | const scope_decl = scope.ownerDecl().?; |
| 4051 | 4222 | const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index }); |
| 4052 | 4223 | defer mod.gpa.free(name); |
| 4053 | | const name_hash = scope.namespace().fullyQualifiedNameHash(name); |
| 4224 | const namespace = scope_decl.namespace; |
| 4225 | const name_hash = namespace.fullyQualifiedNameHash(name); |
| 4054 | 4226 | const src_hash: std.zig.SrcHash = undefined; |
| 4055 | | const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash); |
| 4227 | const new_decl = try mod.createNewDecl(namespace, name, scope_decl.src_node, name_hash, src_hash); |
| 4056 | 4228 | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); |
| 4057 | 4229 | |
| 4058 | 4230 | decl_arena_state.* = decl_arena.state; |
| ... | ... | @@ -4076,55 +4248,30 @@ pub fn createAnonymousDecl( |
| 4076 | 4248 | return new_decl; |
| 4077 | 4249 | } |
| 4078 | 4250 | |
| 4079 | | pub fn createContainerDecl( |
| 4080 | | mod: *Module, |
| 4081 | | scope: *Scope, |
| 4082 | | base_token: std.zig.ast.TokenIndex, |
| 4083 | | decl_arena: *std.heap.ArenaAllocator, |
| 4084 | | typed_value: TypedValue, |
| 4085 | | ) !*Decl { |
| 4086 | | const scope_decl = scope.ownerDecl().?; |
| 4087 | | const name = try mod.getAnonTypeName(scope, base_token); |
| 4088 | | defer mod.gpa.free(name); |
| 4089 | | const name_hash = scope.namespace().fullyQualifiedNameHash(name); |
| 4090 | | const src_hash: std.zig.SrcHash = undefined; |
| 4091 | | const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_node, name_hash, src_hash); |
| 4092 | | const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State); |
| 4093 | | |
| 4094 | | decl_arena_state.* = decl_arena.state; |
| 4095 | | new_decl.typed_value = .{ |
| 4096 | | .most_recent = .{ |
| 4097 | | .typed_value = typed_value, |
| 4098 | | .arena = decl_arena_state, |
| 4099 | | }, |
| 4100 | | }; |
| 4101 | | new_decl.analysis = .complete; |
| 4102 | | new_decl.generation = mod.generation; |
| 4103 | | |
| 4104 | | return new_decl; |
| 4105 | | } |
| 4106 | | |
| 4107 | | fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 { |
| 4108 | | // TODO add namespaces, generic function signatrues |
| 4109 | | const tree = scope.tree(); |
| 4110 | | const token_tags = tree.tokens.items(.tag); |
| 4111 | | const base_name = switch (token_tags[base_token]) { |
| 4112 | | .keyword_struct => "struct", |
| 4113 | | .keyword_enum => "enum", |
| 4114 | | .keyword_union => "union", |
| 4115 | | .keyword_opaque => "opaque", |
| 4116 | | else => unreachable, |
| 4117 | | }; |
| 4118 | | const loc = tree.tokenLocation(0, base_token); |
| 4119 | | return std.fmt.allocPrint(mod.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column }); |
| 4120 | | } |
| 4121 | | |
| 4122 | 4251 | fn getNextAnonNameIndex(mod: *Module) usize { |
| 4123 | 4252 | return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic); |
| 4124 | 4253 | } |
| 4125 | 4254 | |
| 4126 | | pub fn lookupDeclName(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl { |
| 4127 | | const namespace = scope.namespace(); |
| 4255 | /// This looks up a bare identifier in the given scope. This will walk up the tree of namespaces |
| 4256 | /// in scope and check each one for the identifier. |
| 4257 | pub fn lookupIdentifier(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl { |
| 4258 | var namespace = scope.namespace(); |
| 4259 | while (true) { |
| 4260 | if (mod.lookupInNamespace(namespace, ident_name)) |decl| { |
| 4261 | return decl; |
| 4262 | } |
| 4263 | namespace = namespace.parent orelse break; |
| 4264 | } |
| 4265 | return null; |
| 4266 | } |
| 4267 | |
| 4268 | /// This looks up a member of a specific namespace. It is affected by `usingnamespace` but |
| 4269 | /// only for ones in the specified namespace. |
| 4270 | pub fn lookupInNamespace( |
| 4271 | mod: *Module, |
| 4272 | namespace: *Scope.Namespace, |
| 4273 | ident_name: []const u8, |
| 4274 | ) ?*Decl { |
| 4128 | 4275 | const name_hash = namespace.fullyQualifiedNameHash(ident_name); |
| 4129 | 4276 | return mod.decl_table.get(name_hash); |
| 4130 | 4277 | } |
| ... | ... | @@ -4271,7 +4418,7 @@ pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) In |
| 4271 | 4418 | mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.astgen.decl, err_msg); |
| 4272 | 4419 | }, |
| 4273 | 4420 | .file => unreachable, |
| 4274 | | .container => unreachable, |
| 4421 | .namespace => unreachable, |
| 4275 | 4422 | .decl_ref => { |
| 4276 | 4423 | const decl_ref = scope.cast(Scope.DeclRef).?; |
| 4277 | 4424 | decl_ref.decl.analysis = .sema_failure; |
| ... | ... | @@ -4683,10 +4830,3 @@ pub fn parseStrLit( |
| 4683 | 4830 | }, |
| 4684 | 4831 | } |
| 4685 | 4832 | } |
| 4686 | | |
| 4687 | | pub fn unloadFile(mod: *Module, file_scope: *Scope.File) void { |
| 4688 | | if (file_scope.status == .unloaded_parse_failure) { |
| 4689 | | mod.failed_files.swapRemove(file_scope).?.value.destroy(mod.gpa); |
| 4690 | | } |
| 4691 | | file_scope.unload(mod.gpa); |
| 4692 | | } |