authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-13 19:56:35-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2020-09-13 19:56:35-07:00
log2456df5f4ebf9fef147d86736974e95403e2d40d
treef7d849a71434dceed2327e4b23a9592192e74ab8
parent4d59f775289b50a9529e801a6998dcd181945efb

stage2: rename ZigModule to Module


20 files changed, 3330 insertions(+), 3331 deletions(-)

src-self-hosted/Compilation.zig+58-58
......@@ -16,7 +16,7 @@ const build_options = @import("build_options");
1616const LibCInstallation = @import("libc_installation.zig").LibCInstallation;
1717const glibc = @import("glibc.zig");
1818const fatal = @import("main.zig").fatal;
19const ZigModule = @import("ZigModule.zig");
19const Module = @import("Module.zig");
2020
2121/// General-purpose allocator. Used for both temporary and long-term storage.
2222gpa: *Allocator,
......@@ -75,7 +75,7 @@ crt_files: std.StringHashMapUnmanaged([]const u8) = .{},
7575/// Keeping track of this possibly open resource so we can close it later.
7676owned_link_dir: ?std.fs.Dir,
7777
78pub const InnerError = ZigModule.InnerError;
78pub const InnerError = Module.InnerError;
7979
8080/// For passing to a C compiler.
8181pub const CSourceFile = struct {
......@@ -85,14 +85,14 @@ pub const CSourceFile = struct {
8585
8686const WorkItem = union(enum) {
8787 /// Write the machine code for a Decl to the output file.
88 codegen_decl: *ZigModule.Decl,
88 codegen_decl: *Module.Decl,
8989 /// The Decl needs to be analyzed and possibly export itself.
9090 /// It may have already be analyzed, or it may have been determined
9191 /// to be outdated; in this case perform semantic analysis again.
92 analyze_decl: *ZigModule.Decl,
92 analyze_decl: *Module.Decl,
9393 /// The source file containing the Decl has been updated, and so the
9494 /// Decl may need its line number information updated in the debug info.
95 update_line_number: *ZigModule.Decl,
95 update_line_number: *Module.Decl,
9696 /// Invoke the Clang compiler to create an object file, which gets linked
9797 /// with the Compilation.
9898 c_object: *CObject,
......@@ -402,7 +402,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
402402 cache.hash.add(options.output_mode);
403403 // TODO audit this and make sure everything is in it
404404
405 const zig_module: ?*ZigModule = if (options.root_pkg) |root_pkg| blk: {
405 const module: ?*Module = if (options.root_pkg) |root_pkg| blk: {
406406 // Options that are specific to zig source files, that cannot be
407407 // modified between incremental updates.
408408 var hash = cache.hash;
......@@ -442,11 +442,11 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
442442 // this is where we would load it. We have open a handle to the directory where
443443 // the output either already is, or will be.
444444 // However we currently do not have serialization of such metadata, so for now
445 // we set up an empty ZigModule that does the entire compilation fresh.
445 // we set up an empty Module that does the entire compilation fresh.
446446
447447 const root_scope = rs: {
448448 if (mem.endsWith(u8, root_pkg.root_src_path, ".zig")) {
449 const root_scope = try gpa.create(ZigModule.Scope.File);
449 const root_scope = try gpa.create(Module.Scope.File);
450450 root_scope.* = .{
451451 .sub_file_path = root_pkg.root_src_path,
452452 .source = .{ .unloaded = {} },
......@@ -459,7 +459,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
459459 };
460460 break :rs &root_scope.base;
461461 } else if (mem.endsWith(u8, root_pkg.root_src_path, ".zir")) {
462 const root_scope = try gpa.create(ZigModule.Scope.ZIRModule);
462 const root_scope = try gpa.create(Module.Scope.ZIRModule);
463463 root_scope.* = .{
464464 .sub_file_path = root_pkg.root_src_path,
465465 .source = .{ .unloaded = {} },
......@@ -473,24 +473,24 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
473473 }
474474 };
475475
476 const zig_module = try arena.create(ZigModule);
477 zig_module.* = .{
476 const module = try arena.create(Module);
477 module.* = .{
478478 .gpa = gpa,
479479 .comp = comp,
480480 .root_pkg = root_pkg,
481481 .root_scope = root_scope,
482482 .zig_cache_artifact_directory = zig_cache_artifact_directory,
483483 };
484 break :blk zig_module;
484 break :blk module;
485485 } else null;
486 errdefer if (zig_module) |zm| zm.deinit();
486 errdefer if (module) |zm| zm.deinit();
487487
488488 // For resource management purposes.
489489 var owned_link_dir: ?std.fs.Dir = null;
490490 errdefer if (owned_link_dir) |*dir| dir.close();
491491
492492 const bin_directory = emit_bin.directory orelse blk: {
493 if (zig_module) |zm| break :blk zm.zig_cache_artifact_directory;
493 if (module) |zm| break :blk zm.zig_cache_artifact_directory;
494494
495495 const digest = cache.hash.peek();
496496 const artifact_sub_dir = try std.fs.path.join(arena, &[_][]const u8{ "o", &digest });
......@@ -510,7 +510,7 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
510510 .directory = bin_directory,
511511 .sub_path = emit_bin.basename,
512512 .root_name = root_name,
513 .zig_module = zig_module,
513 .module = module,
514514 .target = options.target,
515515 .dynamic_linker = options.dynamic_linker,
516516 .output_mode = options.output_mode,
......@@ -605,9 +605,9 @@ pub fn create(gpa: *Allocator, options: InitOptions) !*Compilation {
605605}
606606
607607pub fn destroy(self: *Compilation) void {
608 const optional_zig_module = self.bin_file.options.zig_module;
608 const optional_module = self.bin_file.options.module;
609609 self.bin_file.destroy();
610 if (optional_zig_module) |zig_module| zig_module.deinit();
610 if (optional_module) |module| module.deinit();
611611
612612 const gpa = self.gpa;
613613 self.work_queue.deinit();
......@@ -655,23 +655,23 @@ pub fn update(self: *Compilation) !void {
655655 self.work_queue.writeItemAssumeCapacity(.{ .c_object = entry.key });
656656 }
657657
658 if (self.bin_file.options.zig_module) |zig_module| {
659 zig_module.generation += 1;
658 if (self.bin_file.options.module) |module| {
659 module.generation += 1;
660660
661661 // TODO Detect which source files changed.
662662 // Until then we simulate a full cache miss. Source files could have been loaded for any reason;
663663 // to force a refresh we unload now.
664 if (zig_module.root_scope.cast(ZigModule.Scope.File)) |zig_file| {
665 zig_file.unload(zig_module.gpa);
666 zig_module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
664 if (module.root_scope.cast(Module.Scope.File)) |zig_file| {
665 zig_file.unload(module.gpa);
666 module.analyzeContainer(&zig_file.root_container) catch |err| switch (err) {
667667 error.AnalysisFail => {
668668 assert(self.totalErrorCount() != 0);
669669 },
670670 else => |e| return e,
671671 };
672 } else if (zig_module.root_scope.cast(ZigModule.Scope.ZIRModule)) |zir_module| {
673 zir_module.unload(zig_module.gpa);
674 zig_module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
672 } else if (module.root_scope.cast(Module.Scope.ZIRModule)) |zir_module| {
673 zir_module.unload(module.gpa);
674 module.analyzeRootZIRModule(zir_module) catch |err| switch (err) {
675675 error.AnalysisFail => {
676676 assert(self.totalErrorCount() != 0);
677677 },
......@@ -682,14 +682,14 @@ pub fn update(self: *Compilation) !void {
682682
683683 try self.performAllTheWork();
684684
685 if (self.bin_file.options.zig_module) |zig_module| {
685 if (self.bin_file.options.module) |module| {
686686 // Process the deletion set.
687 while (zig_module.deletion_set.popOrNull()) |decl| {
687 while (module.deletion_set.popOrNull()) |decl| {
688688 if (decl.dependants.items().len != 0) {
689689 decl.deletion_flag = false;
690690 continue;
691691 }
692 try zig_module.deleteDecl(decl);
692 try module.deleteDecl(decl);
693693 }
694694 }
695695
......@@ -701,8 +701,8 @@ pub fn update(self: *Compilation) !void {
701701 // If there are any errors, we anticipate the source files being loaded
702702 // to report error messages. Otherwise we unload all source files to save memory.
703703 if (self.totalErrorCount() == 0 and !self.keep_source_files_loaded) {
704 if (self.bin_file.options.zig_module) |zig_module| {
705 zig_module.root_scope.unload(self.gpa);
704 if (self.bin_file.options.module) |module| {
705 module.root_scope.unload(self.gpa);
706706 }
707707 }
708708}
......@@ -722,10 +722,10 @@ pub fn makeBinFileWritable(self: *Compilation) !void {
722722pub fn totalErrorCount(self: *Compilation) usize {
723723 var total: usize = self.failed_c_objects.items().len;
724724
725 if (self.bin_file.options.zig_module) |zig_module| {
726 total += zig_module.failed_decls.items().len +
727 zig_module.failed_exports.items().len +
728 zig_module.failed_files.items().len;
725 if (self.bin_file.options.module) |module| {
726 total += module.failed_decls.items().len +
727 module.failed_exports.items().len +
728 module.failed_files.items().len;
729729 }
730730
731731 // The "no entry point found" error only counts if there are no other errors.
......@@ -748,30 +748,30 @@ pub fn getAllErrorsAlloc(self: *Compilation) !AllErrors {
748748 const err_msg = entry.value;
749749 try AllErrors.add(&arena, &errors, c_object.src_path, "", err_msg.*);
750750 }
751 if (self.bin_file.options.zig_module) |zig_module| {
752 for (zig_module.failed_files.items()) |entry| {
751 if (self.bin_file.options.module) |module| {
752 for (module.failed_files.items()) |entry| {
753753 const scope = entry.key;
754754 const err_msg = entry.value;
755 const source = try scope.getSource(zig_module);
755 const source = try scope.getSource(module);
756756 try AllErrors.add(&arena, &errors, scope.subFilePath(), source, err_msg.*);
757757 }
758 for (zig_module.failed_decls.items()) |entry| {
758 for (module.failed_decls.items()) |entry| {
759759 const decl = entry.key;
760760 const err_msg = entry.value;
761 const source = try decl.scope.getSource(zig_module);
761 const source = try decl.scope.getSource(module);
762762 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
763763 }
764 for (zig_module.failed_exports.items()) |entry| {
764 for (module.failed_exports.items()) |entry| {
765765 const decl = entry.key.owner_decl;
766766 const err_msg = entry.value;
767 const source = try decl.scope.getSource(zig_module);
767 const source = try decl.scope.getSource(module);
768768 try AllErrors.add(&arena, &errors, decl.scope.subFilePath(), source, err_msg.*);
769769 }
770770 }
771771
772772 if (errors.items.len == 0 and self.link_error_flags.no_entry_point_found) {
773773 const global_err_src_path = blk: {
774 if (self.bin_file.options.zig_module) |zig_module| break :blk zig_module.root_pkg.root_src_path;
774 if (self.bin_file.options.module) |module| break :blk module.root_pkg.root_src_path;
775775 if (self.c_source_files.len != 0) break :blk self.c_source_files[0].src_path;
776776 if (self.bin_file.options.objects.len != 0) break :blk self.bin_file.options.objects[0];
777777 break :blk "(no file)";
......@@ -807,10 +807,10 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
807807 => continue,
808808
809809 .complete, .codegen_failure_retryable => {
810 const zig_module = self.bin_file.options.zig_module.?;
810 const module = self.bin_file.options.module.?;
811811 if (decl.typed_value.most_recent.typed_value.val.cast(Value.Payload.Function)) |payload| {
812812 switch (payload.func.analysis) {
813 .queued => zig_module.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
813 .queued => module.analyzeFnBody(decl, payload.func) catch |err| switch (err) {
814814 error.AnalysisFail => {
815815 assert(payload.func.analysis != .in_progress);
816816 continue;
......@@ -823,23 +823,23 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
823823 }
824824 // Here we tack on additional allocations to the Decl's arena. The allocations are
825825 // lifetime annotations in the ZIR.
826 var decl_arena = decl.typed_value.most_recent.arena.?.promote(zig_module.gpa);
826 var decl_arena = decl.typed_value.most_recent.arena.?.promote(module.gpa);
827827 defer decl.typed_value.most_recent.arena.?.* = decl_arena.state;
828828 log.debug("analyze liveness of {}\n", .{decl.name});
829 try liveness.analyze(zig_module.gpa, &decl_arena.allocator, payload.func.analysis.success);
829 try liveness.analyze(module.gpa, &decl_arena.allocator, payload.func.analysis.success);
830830 }
831831
832832 assert(decl.typed_value.most_recent.typed_value.ty.hasCodeGenBits());
833833
834 self.bin_file.updateDecl(zig_module, decl) catch |err| switch (err) {
834 self.bin_file.updateDecl(module, decl) catch |err| switch (err) {
835835 error.OutOfMemory => return error.OutOfMemory,
836836 error.AnalysisFail => {
837837 decl.analysis = .dependency_failure;
838838 },
839839 else => {
840 try zig_module.failed_decls.ensureCapacity(zig_module.gpa, zig_module.failed_decls.items().len + 1);
841 zig_module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
842 zig_module.gpa,
840 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
841 module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
842 module.gpa,
843843 decl.src(),
844844 "unable to codegen: {}",
845845 .{@errorName(err)},
......@@ -850,18 +850,18 @@ pub fn performAllTheWork(self: *Compilation) error{OutOfMemory}!void {
850850 },
851851 },
852852 .analyze_decl => |decl| {
853 const zig_module = self.bin_file.options.zig_module.?;
854 zig_module.ensureDeclAnalyzed(decl) catch |err| switch (err) {
853 const module = self.bin_file.options.module.?;
854 module.ensureDeclAnalyzed(decl) catch |err| switch (err) {
855855 error.OutOfMemory => return error.OutOfMemory,
856856 error.AnalysisFail => continue,
857857 };
858858 },
859859 .update_line_number => |decl| {
860 const zig_module = self.bin_file.options.zig_module.?;
861 self.bin_file.updateDeclLineNumber(zig_module, decl) catch |err| {
862 try zig_module.failed_decls.ensureCapacity(zig_module.gpa, zig_module.failed_decls.items().len + 1);
863 zig_module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
864 zig_module.gpa,
860 const module = self.bin_file.options.module.?;
861 self.bin_file.updateDeclLineNumber(module, decl) catch |err| {
862 try module.failed_decls.ensureCapacity(module.gpa, module.failed_decls.items().len + 1);
863 module.failed_decls.putAssumeCapacityNoClobber(decl, try ErrorMsg.create(
864 module.gpa,
865865 decl.src(),
866866 "unable to update line number: {}",
867867 .{@errorName(err)},
......@@ -949,7 +949,7 @@ fn updateCObject(comp: *Compilation, c_object: *CObject) !void {
949949 // Special case when doing build-obj for just one C file. When there are more than one object
950950 // file and building an object we need to link them together, but with just one it should go
951951 // directly to the output file.
952 const direct_o = comp.c_source_files.len == 1 and comp.bin_file.options.zig_module == null and
952 const direct_o = comp.c_source_files.len == 1 and comp.bin_file.options.module == null and
953953 comp.bin_file.options.output_mode == .Obj and comp.bin_file.options.objects.len == 0;
954954 const o_basename_noext = if (direct_o)
955955 comp.bin_file.options.root_name
src-self-hosted/Module.zig created+3235
......@@ -0,0 +1,3235 @@
1const Module = @This();
2const std = @import("std");
3const Compilation = @import("Compilation.zig");
4const mem = std.mem;
5const Allocator = std.mem.Allocator;
6const ArrayListUnmanaged = std.ArrayListUnmanaged;
7const Value = @import("value.zig").Value;
8const Type = @import("type.zig").Type;
9const TypedValue = @import("TypedValue.zig");
10const assert = std.debug.assert;
11const log = std.log.scoped(.module);
12const BigIntConst = std.math.big.int.Const;
13const BigIntMutable = std.math.big.int.Mutable;
14const Target = std.Target;
15const Package = @import("Package.zig");
16const link = @import("link.zig");
17const ir = @import("ir.zig");
18const zir = @import("zir.zig");
19const Inst = ir.Inst;
20const Body = ir.Body;
21const ast = std.zig.ast;
22const trace = @import("tracy.zig").trace;
23const astgen = @import("astgen.zig");
24const zir_sema = @import("zir_sema.zig");
25
26/// General-purpose allocator. Used for both temporary and long-term storage.
27gpa: *Allocator,
28comp: *Compilation,
29
30/// Where our incremental compilation metadata serialization will go.
31zig_cache_artifact_directory: Compilation.Directory,
32/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
33root_pkg: *Package,
34/// Module owns this resource.
35/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.
36root_scope: *Scope,
37/// It's rare for a decl to be exported, so we save memory by having a sparse map of
38/// Decl pointers to details about them being exported.
39/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
40decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
41/// We track which export is associated with the given symbol name for quick
42/// detection of symbol collisions.
43symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{},
44/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
45/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
46/// is performing the export of another Decl.
47/// This table owns the Export memory.
48export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
49/// Maps fully qualified namespaced names to the Decl struct for them.
50decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{},
51/// We optimize memory usage for a compilation with no compile errors by storing the
52/// error messages and mapping outside of `Decl`.
53/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
54/// Note that a Decl can succeed but the Fn it represents can fail. In this case,
55/// a Decl can have a failed_decls entry but have analysis status of success.
56failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *Compilation.ErrorMsg) = .{},
57/// Using a map here for consistency with the other fields here.
58/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.
59failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *Compilation.ErrorMsg) = .{},
60/// Using a map here for consistency with the other fields here.
61/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
62failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *Compilation.ErrorMsg) = .{},
63
64next_anon_name_index: usize = 0,
65
66/// Candidates for deletion. After a semantic analysis update completes, this list
67/// contains Decls that need to be deleted if they end up having no references to them.
68deletion_set: ArrayListUnmanaged(*Decl) = .{},
69
70/// Error tags and their values, tag names are duped with mod.gpa.
71global_error_set: std.StringHashMapUnmanaged(u16) = .{},
72
73/// Incrementing integer used to compare against the corresponding Decl
74/// field to determine whether a Decl's status applies to an ongoing update, or a
75/// previous analysis.
76generation: u32 = 0,
77
78pub const Export = struct {
79 options: std.builtin.ExportOptions,
80 /// Byte offset into the file that contains the export directive.
81 src: usize,
82 /// Represents the position of the export, if any, in the output file.
83 link: link.File.Elf.Export,
84 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
85 owner_decl: *Decl,
86 /// The Decl being exported. Note this is *not* the Decl performing the export.
87 exported_decl: *Decl,
88 status: enum {
89 in_progress,
90 failed,
91 /// Indicates that the failure was due to a temporary issue, such as an I/O error
92 /// when writing to the output file. Retrying the export may succeed.
93 failed_retryable,
94 complete,
95 },
96};
97
98pub const Decl = struct {
99 /// This name is relative to the containing namespace of the decl. It uses a null-termination
100 /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed
101 /// in symbol names, because executable file formats use null-terminated strings for symbol names.
102 /// All Decls have names, even values that are not bound to a zig namespace. This is necessary for
103 /// mapping them to an address in the output file.
104 /// Memory owned by this decl, using Module's allocator.
105 name: [*:0]const u8,
106 /// The direct parent container of the Decl. This is either a `Scope.Container` or `Scope.ZIRModule`.
107 /// Reference to externally owned memory.
108 scope: *Scope,
109 /// The AST Node decl index or ZIR Inst index that contains this declaration.
110 /// Must be recomputed when the corresponding source file is modified.
111 src_index: usize,
112 /// The most recent value of the Decl after a successful semantic analysis.
113 typed_value: union(enum) {
114 never_succeeded: void,
115 most_recent: TypedValue.Managed,
116 },
117 /// Represents the "shallow" analysis status. For example, for decls that are functions,
118 /// the function type is analyzed with this set to `in_progress`, however, the semantic
119 /// analysis of the function body is performed with this value set to `success`. Functions
120 /// have their own analysis status field.
121 analysis: enum {
122 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
123 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
124 unreferenced,
125 /// Semantic analysis for this Decl is running right now. This state detects dependency loops.
126 in_progress,
127 /// This Decl might be OK but it depends on another one which did not successfully complete
128 /// semantic analysis.
129 dependency_failure,
130 /// Semantic analysis failure.
131 /// There will be a corresponding ErrorMsg in Module.failed_decls.
132 sema_failure,
133 /// There will be a corresponding ErrorMsg in Module.failed_decls.
134 /// This indicates the failure was something like running out of disk space,
135 /// and attempting semantic analysis again may succeed.
136 sema_failure_retryable,
137 /// There will be a corresponding ErrorMsg in Module.failed_decls.
138 codegen_failure,
139 /// There will be a corresponding ErrorMsg in Module.failed_decls.
140 /// This indicates the failure was something like running out of disk space,
141 /// and attempting codegen again may succeed.
142 codegen_failure_retryable,
143 /// Everything is done. During an update, this Decl may be out of date, depending
144 /// on its dependencies. The `generation` field can be used to determine if this
145 /// completion status occurred before or after a given update.
146 complete,
147 /// A Module update is in progress, and this Decl has been flagged as being known
148 /// to require re-analysis.
149 outdated,
150 },
151 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared
152 /// when removed.
153 deletion_flag: bool,
154 /// Whether the corresponding AST decl has a `pub` keyword.
155 is_pub: bool,
156
157 /// An integer that can be checked against the corresponding incrementing
158 /// generation field of Module. This is used to determine whether `complete` status
159 /// represents pre- or post- re-analysis.
160 generation: u32,
161
162 /// Represents the position of the code in the output file.
163 /// This is populated regardless of semantic analysis and code generation.
164 link: link.File.LinkBlock,
165
166 /// Represents the function in the linked output file, if the `Decl` is a function.
167 /// This is stored here and not in `Fn` because `Decl` survives across updates but
168 /// `Fn` does not.
169 /// TODO Look into making `Fn` a longer lived structure and moving this field there
170 /// to save on memory usage.
171 fn_link: link.File.LinkFn,
172
173 contents_hash: std.zig.SrcHash,
174
175 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
176 /// typed_value is modified.
177 dependants: DepsTable = .{},
178 /// The shallow set of other decls whose typed_value changing indicates that this Decl's
179 /// typed_value may need to be regenerated.
180 dependencies: DepsTable = .{},
181
182 /// The reason this is not `std.AutoArrayHashMapUnmanaged` is a workaround for
183 /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself`
184 pub const DepsTable = std.ArrayHashMapUnmanaged(*Decl, void, std.array_hash_map.getAutoHashFn(*Decl), std.array_hash_map.getAutoEqlFn(*Decl), false);
185
186 pub fn destroy(self: *Decl, gpa: *Allocator) void {
187 gpa.free(mem.spanZ(self.name));
188 if (self.typedValueManaged()) |tvm| {
189 tvm.deinit(gpa);
190 }
191 self.dependants.deinit(gpa);
192 self.dependencies.deinit(gpa);
193 gpa.destroy(self);
194 }
195
196 pub fn src(self: Decl) usize {
197 switch (self.scope.tag) {
198 .container => {
199 const container = @fieldParentPtr(Scope.Container, "base", self.scope);
200 const tree = container.file_scope.contents.tree;
201 // TODO Container should have it's own decls()
202 const decl_node = tree.root_node.decls()[self.src_index];
203 return tree.token_locs[decl_node.firstToken()].start;
204 },
205 .zir_module => {
206 const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
207 const module = zir_module.contents.module;
208 const src_decl = module.decls[self.src_index];
209 return src_decl.inst.src;
210 },
211 .file, .block => unreachable,
212 .gen_zir => unreachable,
213 .local_val => unreachable,
214 .local_ptr => unreachable,
215 .decl => unreachable,
216 }
217 }
218
219 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
220 return self.scope.fullyQualifiedNameHash(mem.spanZ(self.name));
221 }
222
223 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
224 const tvm = self.typedValueManaged() orelse return error.AnalysisFail;
225 return tvm.typed_value;
226 }
227
228 pub fn value(self: *Decl) error{AnalysisFail}!Value {
229 return (try self.typedValue()).val;
230 }
231
232 pub fn dump(self: *Decl) void {
233 const loc = std.zig.findLineColumn(self.scope.source.bytes, self.src);
234 std.debug.print("{}:{}:{} name={} status={}", .{
235 self.scope.sub_file_path,
236 loc.line + 1,
237 loc.column + 1,
238 mem.spanZ(self.name),
239 @tagName(self.analysis),
240 });
241 if (self.typedValueManaged()) |tvm| {
242 std.debug.print(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });
243 }
244 std.debug.print("\n", .{});
245 }
246
247 pub fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {
248 switch (self.typed_value) {
249 .most_recent => |*x| return x,
250 .never_succeeded => return null,
251 }
252 }
253
254 fn removeDependant(self: *Decl, other: *Decl) void {
255 self.dependants.removeAssertDiscard(other);
256 }
257
258 fn removeDependency(self: *Decl, other: *Decl) void {
259 self.dependencies.removeAssertDiscard(other);
260 }
261};
262
263/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
264pub const Fn = struct {
265 /// This memory owned by the Decl's TypedValue.Managed arena allocator.
266 analysis: union(enum) {
267 queued: *ZIR,
268 in_progress,
269 /// There will be a corresponding ErrorMsg in Module.failed_decls
270 sema_failure,
271 /// This Fn might be OK but it depends on another Decl which did not successfully complete
272 /// semantic analysis.
273 dependency_failure,
274 success: Body,
275 },
276 owner_decl: *Decl,
277
278 /// This memory is temporary and points to stack memory for the duration
279 /// of Fn analysis.
280 pub const Analysis = struct {
281 inner_block: Scope.Block,
282 };
283
284 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
285 pub const ZIR = struct {
286 body: zir.Module.Body,
287 arena: std.heap.ArenaAllocator.State,
288 };
289
290 /// For debugging purposes.
291 pub fn dump(self: *Fn, mod: Module) void {
292 std.debug.print("Module.Function(name={}) ", .{self.owner_decl.name});
293 switch (self.analysis) {
294 .queued => {
295 std.debug.print("queued\n", .{});
296 },
297 .in_progress => {
298 std.debug.print("in_progress\n", .{});
299 },
300 else => {
301 std.debug.print("\n", .{});
302 zir.dumpFn(mod, self);
303 },
304 }
305 }
306};
307
308pub const Var = struct {
309 /// if is_extern == true this is undefined
310 init: Value,
311 owner_decl: *Decl,
312
313 is_extern: bool,
314 is_mutable: bool,
315 is_threadlocal: bool,
316};
317
318pub const Scope = struct {
319 tag: Tag,
320
321 pub const NameHash = [16]u8;
322
323 pub fn cast(base: *Scope, comptime T: type) ?*T {
324 if (base.tag != T.base_tag)
325 return null;
326
327 return @fieldParentPtr(T, "base", base);
328 }
329
330 /// Asserts the scope has a parent which is a DeclAnalysis and
331 /// returns the arena Allocator.
332 pub fn arena(self: *Scope) *Allocator {
333 switch (self.tag) {
334 .block => return self.cast(Block).?.arena,
335 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
336 .gen_zir => return self.cast(GenZIR).?.arena,
337 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
338 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
339 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
340 .file => unreachable,
341 .container => unreachable,
342 }
343 }
344
345 /// If the scope has a parent which is a `DeclAnalysis`,
346 /// returns the `Decl`, otherwise returns `null`.
347 pub fn decl(self: *Scope) ?*Decl {
348 return switch (self.tag) {
349 .block => self.cast(Block).?.decl,
350 .gen_zir => self.cast(GenZIR).?.decl,
351 .local_val => self.cast(LocalVal).?.gen_zir.decl,
352 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
353 .decl => self.cast(DeclAnalysis).?.decl,
354 .zir_module => null,
355 .file => null,
356 .container => null,
357 };
358 }
359
360 /// Asserts the scope has a parent which is a ZIRModule or Container and
361 /// returns it.
362 pub fn namespace(self: *Scope) *Scope {
363 switch (self.tag) {
364 .block => return self.cast(Block).?.decl.scope,
365 .gen_zir => return self.cast(GenZIR).?.decl.scope,
366 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
367 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
368 .decl => return self.cast(DeclAnalysis).?.decl.scope,
369 .file => return &self.cast(File).?.root_container.base,
370 .zir_module, .container => return self,
371 }
372 }
373
374 /// Must generate unique bytes with no collisions with other decls.
375 /// The point of hashing here is only to limit the number of bytes of
376 /// the unique identifier to a fixed size (16 bytes).
377 pub fn fullyQualifiedNameHash(self: *Scope, name: []const u8) NameHash {
378 switch (self.tag) {
379 .block => unreachable,
380 .gen_zir => unreachable,
381 .local_val => unreachable,
382 .local_ptr => unreachable,
383 .decl => unreachable,
384 .file => unreachable,
385 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
386 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
387 }
388 }
389
390 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
391 pub fn tree(self: *Scope) *ast.Tree {
392 switch (self.tag) {
393 .file => return self.cast(File).?.contents.tree,
394 .zir_module => unreachable,
395 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(Container).?.file_scope.contents.tree,
396 .block => return self.cast(Block).?.decl.scope.cast(Container).?.file_scope.contents.tree,
397 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(Container).?.file_scope.contents.tree,
398 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
399 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
400 .container => return self.cast(Container).?.file_scope.contents.tree,
401 }
402 }
403
404 /// Asserts the scope is a child of a `GenZIR` and returns it.
405 pub fn getGenZIR(self: *Scope) *GenZIR {
406 return switch (self.tag) {
407 .block => unreachable,
408 .gen_zir => self.cast(GenZIR).?,
409 .local_val => return self.cast(LocalVal).?.gen_zir,
410 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
411 .decl => unreachable,
412 .zir_module => unreachable,
413 .file => unreachable,
414 .container => unreachable,
415 };
416 }
417
418 /// Asserts the scope has a parent which is a ZIRModule, Contaienr or File and
419 /// returns the sub_file_path field.
420 pub fn subFilePath(base: *Scope) []const u8 {
421 switch (base.tag) {
422 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
423 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
424 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
425 .block => unreachable,
426 .gen_zir => unreachable,
427 .local_val => unreachable,
428 .local_ptr => unreachable,
429 .decl => unreachable,
430 }
431 }
432
433 pub fn unload(base: *Scope, gpa: *Allocator) void {
434 switch (base.tag) {
435 .file => return @fieldParentPtr(File, "base", base).unload(gpa),
436 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
437 .block => unreachable,
438 .gen_zir => unreachable,
439 .local_val => unreachable,
440 .local_ptr => unreachable,
441 .decl => unreachable,
442 .container => unreachable,
443 }
444 }
445
446 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
447 switch (base.tag) {
448 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
449 .file => return @fieldParentPtr(File, "base", base).getSource(module),
450 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
451 .gen_zir => unreachable,
452 .local_val => unreachable,
453 .local_ptr => unreachable,
454 .block => unreachable,
455 .decl => unreachable,
456 }
457 }
458
459 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
460 pub fn removeDecl(base: *Scope, child: *Decl) void {
461 switch (base.tag) {
462 .container => return @fieldParentPtr(Container, "base", base).removeDecl(child),
463 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
464 .file => unreachable,
465 .block => unreachable,
466 .gen_zir => unreachable,
467 .local_val => unreachable,
468 .local_ptr => unreachable,
469 .decl => unreachable,
470 }
471 }
472
473 /// Asserts the scope is a File or ZIRModule and deinitializes it, then deallocates it.
474 pub fn destroy(base: *Scope, gpa: *Allocator) void {
475 switch (base.tag) {
476 .file => {
477 const scope_file = @fieldParentPtr(File, "base", base);
478 scope_file.deinit(gpa);
479 gpa.destroy(scope_file);
480 },
481 .zir_module => {
482 const scope_zir_module = @fieldParentPtr(ZIRModule, "base", base);
483 scope_zir_module.deinit(gpa);
484 gpa.destroy(scope_zir_module);
485 },
486 .block => unreachable,
487 .gen_zir => unreachable,
488 .local_val => unreachable,
489 .local_ptr => unreachable,
490 .decl => unreachable,
491 .container => unreachable,
492 }
493 }
494
495 fn name_hash_hash(x: NameHash) u32 {
496 return @truncate(u32, @bitCast(u128, x));
497 }
498
499 fn name_hash_eql(a: NameHash, b: NameHash) bool {
500 return @bitCast(u128, a) == @bitCast(u128, b);
501 }
502
503 pub const Tag = enum {
504 /// .zir source code.
505 zir_module,
506 /// .zig source code.
507 file,
508 /// struct, enum or union, every .file contains one of these.
509 container,
510 block,
511 decl,
512 gen_zir,
513 local_val,
514 local_ptr,
515 };
516
517 pub const Container = struct {
518 pub const base_tag: Tag = .container;
519 base: Scope = Scope{ .tag = base_tag },
520
521 file_scope: *Scope.File,
522
523 /// Direct children of the file.
524 decls: std.AutoArrayHashMapUnmanaged(*Decl, void),
525
526 // TODO implement container types and put this in a status union
527 // ty: Type
528
529 pub fn deinit(self: *Container, gpa: *Allocator) void {
530 self.decls.deinit(gpa);
531 self.* = undefined;
532 }
533
534 pub fn removeDecl(self: *Container, child: *Decl) void {
535 _ = self.decls.remove(child);
536 }
537
538 pub fn fullyQualifiedNameHash(self: *Container, name: []const u8) NameHash {
539 // TODO container scope qualified names.
540 return std.zig.hashSrc(name);
541 }
542 };
543
544 pub const File = struct {
545 pub const base_tag: Tag = .file;
546 base: Scope = Scope{ .tag = base_tag },
547
548 /// Relative to the owning package's root_src_dir.
549 /// Reference to external memory, not owned by File.
550 sub_file_path: []const u8,
551 source: union(enum) {
552 unloaded: void,
553 bytes: [:0]const u8,
554 },
555 contents: union {
556 not_available: void,
557 tree: *ast.Tree,
558 },
559 status: enum {
560 never_loaded,
561 unloaded_success,
562 unloaded_parse_failure,
563 loaded_success,
564 },
565
566 root_container: Container,
567
568 pub fn unload(self: *File, gpa: *Allocator) void {
569 switch (self.status) {
570 .never_loaded,
571 .unloaded_parse_failure,
572 .unloaded_success,
573 => {},
574
575 .loaded_success => {
576 self.contents.tree.deinit();
577 self.status = .unloaded_success;
578 },
579 }
580 switch (self.source) {
581 .bytes => |bytes| {
582 gpa.free(bytes);
583 self.source = .{ .unloaded = {} };
584 },
585 .unloaded => {},
586 }
587 }
588
589 pub fn deinit(self: *File, gpa: *Allocator) void {
590 self.root_container.deinit(gpa);
591 self.unload(gpa);
592 self.* = undefined;
593 }
594
595 pub fn dumpSrc(self: *File, src: usize) void {
596 const loc = std.zig.findLineColumn(self.source.bytes, src);
597 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
598 }
599
600 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
601 switch (self.source) {
602 .unloaded => {
603 const source = try module.root_pkg.root_src_directory.handle.readFileAllocOptions(
604 module.gpa,
605 self.sub_file_path,
606 std.math.maxInt(u32),
607 null,
608 1,
609 0,
610 );
611 self.source = .{ .bytes = source };
612 return source;
613 },
614 .bytes => |bytes| return bytes,
615 }
616 }
617 };
618
619 pub const ZIRModule = struct {
620 pub const base_tag: Tag = .zir_module;
621 base: Scope = Scope{ .tag = base_tag },
622 /// Relative to the owning package's root_src_dir.
623 /// Reference to external memory, not owned by ZIRModule.
624 sub_file_path: []const u8,
625 source: union(enum) {
626 unloaded: void,
627 bytes: [:0]const u8,
628 },
629 contents: union {
630 not_available: void,
631 module: *zir.Module,
632 },
633 status: enum {
634 never_loaded,
635 unloaded_success,
636 unloaded_parse_failure,
637 unloaded_sema_failure,
638
639 loaded_sema_failure,
640 loaded_success,
641 },
642
643 /// Even though .zir files only have 1 module, this set is still needed
644 /// because of anonymous Decls, which can exist in the global set, but
645 /// not this one.
646 decls: ArrayListUnmanaged(*Decl),
647
648 pub fn unload(self: *ZIRModule, gpa: *Allocator) void {
649 switch (self.status) {
650 .never_loaded,
651 .unloaded_parse_failure,
652 .unloaded_sema_failure,
653 .unloaded_success,
654 => {},
655
656 .loaded_success => {
657 self.contents.module.deinit(gpa);
658 gpa.destroy(self.contents.module);
659 self.contents = .{ .not_available = {} };
660 self.status = .unloaded_success;
661 },
662 .loaded_sema_failure => {
663 self.contents.module.deinit(gpa);
664 gpa.destroy(self.contents.module);
665 self.contents = .{ .not_available = {} };
666 self.status = .unloaded_sema_failure;
667 },
668 }
669 switch (self.source) {
670 .bytes => |bytes| {
671 gpa.free(bytes);
672 self.source = .{ .unloaded = {} };
673 },
674 .unloaded => {},
675 }
676 }
677
678 pub fn deinit(self: *ZIRModule, gpa: *Allocator) void {
679 self.decls.deinit(gpa);
680 self.unload(gpa);
681 self.* = undefined;
682 }
683
684 pub fn removeDecl(self: *ZIRModule, child: *Decl) void {
685 for (self.decls.items) |item, i| {
686 if (item == child) {
687 _ = self.decls.swapRemove(i);
688 return;
689 }
690 }
691 }
692
693 pub fn dumpSrc(self: *ZIRModule, src: usize) void {
694 const loc = std.zig.findLineColumn(self.source.bytes, src);
695 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
696 }
697
698 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
699 switch (self.source) {
700 .unloaded => {
701 const source = try module.root_pkg.root_src_directory.handle.readFileAllocOptions(
702 module.gpa,
703 self.sub_file_path,
704 std.math.maxInt(u32),
705 null,
706 1,
707 0,
708 );
709 self.source = .{ .bytes = source };
710 return source;
711 },
712 .bytes => |bytes| return bytes,
713 }
714 }
715
716 pub fn fullyQualifiedNameHash(self: *ZIRModule, name: []const u8) NameHash {
717 // ZIR modules only have 1 file with all decls global in the same namespace.
718 return std.zig.hashSrc(name);
719 }
720 };
721
722 /// This is a temporary structure, references to it are valid only
723 /// during semantic analysis of the block.
724 pub const Block = struct {
725 pub const base_tag: Tag = .block;
726 base: Scope = Scope{ .tag = base_tag },
727 parent: ?*Block,
728 func: ?*Fn,
729 decl: *Decl,
730 instructions: ArrayListUnmanaged(*Inst),
731 /// Points to the arena allocator of DeclAnalysis
732 arena: *Allocator,
733 label: ?Label = null,
734 is_comptime: bool,
735
736 pub const Label = struct {
737 zir_block: *zir.Inst.Block,
738 results: ArrayListUnmanaged(*Inst),
739 block_inst: *Inst.Block,
740 };
741 };
742
743 /// This is a temporary structure, references to it are valid only
744 /// during semantic analysis of the decl.
745 pub const DeclAnalysis = struct {
746 pub const base_tag: Tag = .decl;
747 base: Scope = Scope{ .tag = base_tag },
748 decl: *Decl,
749 arena: std.heap.ArenaAllocator,
750 };
751
752 /// This is a temporary structure, references to it are valid only
753 /// during semantic analysis of the decl.
754 pub const GenZIR = struct {
755 pub const base_tag: Tag = .gen_zir;
756 base: Scope = Scope{ .tag = base_tag },
757 /// Parents can be: `GenZIR`, `ZIRModule`, `File`
758 parent: *Scope,
759 decl: *Decl,
760 arena: *Allocator,
761 /// The first N instructions in a function body ZIR are arg instructions.
762 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
763 label: ?Label = null,
764
765 pub const Label = struct {
766 token: ast.TokenIndex,
767 block_inst: *zir.Inst.Block,
768 result_loc: astgen.ResultLoc,
769 };
770 };
771
772 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
773 /// This structure lives as long as the AST generation of the Block
774 /// node that contains the variable.
775 pub const LocalVal = struct {
776 pub const base_tag: Tag = .local_val;
777 base: Scope = Scope{ .tag = base_tag },
778 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
779 parent: *Scope,
780 gen_zir: *GenZIR,
781 name: []const u8,
782 inst: *zir.Inst,
783 };
784
785 /// This could be a `const` or `var` local. It has a pointer instead of a value.
786 /// This structure lives as long as the AST generation of the Block
787 /// node that contains the variable.
788 pub const LocalPtr = struct {
789 pub const base_tag: Tag = .local_ptr;
790 base: Scope = Scope{ .tag = base_tag },
791 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
792 parent: *Scope,
793 gen_zir: *GenZIR,
794 name: []const u8,
795 ptr: *zir.Inst,
796 };
797};
798
799pub const InnerError = error{ OutOfMemory, AnalysisFail };
800
801pub fn deinit(self: *Module) void {
802 const gpa = self.gpa;
803
804 self.zig_cache_artifact_directory.handle.close();
805
806 self.deletion_set.deinit(gpa);
807
808 for (self.decl_table.items()) |entry| {
809 entry.value.destroy(gpa);
810 }
811 self.decl_table.deinit(gpa);
812
813 for (self.failed_decls.items()) |entry| {
814 entry.value.destroy(gpa);
815 }
816 self.failed_decls.deinit(gpa);
817
818 for (self.failed_files.items()) |entry| {
819 entry.value.destroy(gpa);
820 }
821 self.failed_files.deinit(gpa);
822
823 for (self.failed_exports.items()) |entry| {
824 entry.value.destroy(gpa);
825 }
826 self.failed_exports.deinit(gpa);
827
828 for (self.decl_exports.items()) |entry| {
829 const export_list = entry.value;
830 gpa.free(export_list);
831 }
832 self.decl_exports.deinit(gpa);
833
834 for (self.export_owners.items()) |entry| {
835 freeExportList(gpa, entry.value);
836 }
837 self.export_owners.deinit(gpa);
838
839 self.symbol_exports.deinit(gpa);
840 self.root_scope.destroy(gpa);
841
842 var it = self.global_error_set.iterator();
843 while (it.next()) |entry| {
844 gpa.free(entry.key);
845 }
846 self.global_error_set.deinit(gpa);
847}
848
849fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
850 for (export_list) |exp| {
851 gpa.free(exp.options.name);
852 gpa.destroy(exp);
853 }
854 gpa.free(export_list);
855}
856
857pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
858 const tracy = trace(@src());
859 defer tracy.end();
860
861 const subsequent_analysis = switch (decl.analysis) {
862 .in_progress => unreachable,
863
864 .sema_failure,
865 .sema_failure_retryable,
866 .codegen_failure,
867 .dependency_failure,
868 .codegen_failure_retryable,
869 => return error.AnalysisFail,
870
871 .complete => return,
872
873 .outdated => blk: {
874 log.debug("re-analyzing {}\n", .{decl.name});
875
876 // The exports this Decl performs will be re-discovered, so we remove them here
877 // prior to re-analysis.
878 self.deleteDeclExports(decl);
879 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
880 for (decl.dependencies.items()) |entry| {
881 const dep = entry.key;
882 dep.removeDependant(decl);
883 if (dep.dependants.items().len == 0 and !dep.deletion_flag) {
884 // We don't perform a deletion here, because this Decl or another one
885 // may end up referencing it before the update is complete.
886 dep.deletion_flag = true;
887 try self.deletion_set.append(self.gpa, dep);
888 }
889 }
890 decl.dependencies.clearRetainingCapacity();
891
892 break :blk true;
893 },
894
895 .unreferenced => false,
896 };
897
898 const type_changed = if (self.root_scope.cast(Scope.ZIRModule)) |zir_module|
899 try zir_sema.analyzeZirDecl(self, decl, zir_module.contents.module.decls[decl.src_index])
900 else
901 self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) {
902 error.OutOfMemory => return error.OutOfMemory,
903 error.AnalysisFail => return error.AnalysisFail,
904 else => {
905 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
906 self.failed_decls.putAssumeCapacityNoClobber(decl, try Compilation.ErrorMsg.create(
907 self.gpa,
908 decl.src(),
909 "unable to analyze: {}",
910 .{@errorName(err)},
911 ));
912 decl.analysis = .sema_failure_retryable;
913 return error.AnalysisFail;
914 },
915 };
916
917 if (subsequent_analysis) {
918 // We may need to chase the dependants and re-analyze them.
919 // However, if the decl is a function, and the type is the same, we do not need to.
920 if (type_changed or decl.typed_value.most_recent.typed_value.val.tag() != .function) {
921 for (decl.dependants.items()) |entry| {
922 const dep = entry.key;
923 switch (dep.analysis) {
924 .unreferenced => unreachable,
925 .in_progress => unreachable,
926 .outdated => continue, // already queued for update
927
928 .dependency_failure,
929 .sema_failure,
930 .sema_failure_retryable,
931 .codegen_failure,
932 .codegen_failure_retryable,
933 .complete,
934 => if (dep.generation != self.generation) {
935 try self.markOutdatedDecl(dep);
936 },
937 }
938 }
939 }
940 }
941}
942
943fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
944 const tracy = trace(@src());
945 defer tracy.end();
946
947 const container_scope = decl.scope.cast(Scope.Container).?;
948 const tree = try self.getAstTree(container_scope);
949 const ast_node = tree.root_node.decls()[decl.src_index];
950 switch (ast_node.tag) {
951 .FnProto => {
952 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
953
954 decl.analysis = .in_progress;
955
956 // This arena allocator's memory is discarded at the end of this function. It is used
957 // to determine the type of the function, and hence the type of the decl, which is needed
958 // to complete the Decl analysis.
959 var fn_type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
960 defer fn_type_scope_arena.deinit();
961 var fn_type_scope: Scope.GenZIR = .{
962 .decl = decl,
963 .arena = &fn_type_scope_arena.allocator,
964 .parent = decl.scope,
965 };
966 defer fn_type_scope.instructions.deinit(self.gpa);
967
968 decl.is_pub = fn_proto.getVisibToken() != null;
969 const body_node = fn_proto.getBodyNode() orelse
970 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
971
972 const param_decls = fn_proto.params();
973 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);
974
975 const fn_src = tree.token_locs[fn_proto.fn_token].start;
976 const type_type = try astgen.addZIRInstConst(self, &fn_type_scope.base, fn_src, .{
977 .ty = Type.initTag(.type),
978 .val = Value.initTag(.type_type),
979 });
980 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
981 for (param_decls) |param_decl, i| {
982 const param_type_node = switch (param_decl.param_type) {
983 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
984 .type_expr => |node| node,
985 };
986 param_types[i] = try astgen.expr(self, &fn_type_scope.base, type_type_rl, param_type_node);
987 }
988 if (fn_proto.getVarArgsToken()) |var_args_token| {
989 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
990 }
991 if (fn_proto.getLibName()) |lib_name| {
992 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
993 }
994 if (fn_proto.getAlignExpr()) |align_expr| {
995 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
996 }
997 if (fn_proto.getSectionExpr()) |sect_expr| {
998 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
999 }
1000 if (fn_proto.getCallconvExpr()) |callconv_expr| {
1001 return self.failNode(
1002 &fn_type_scope.base,
1003 callconv_expr,
1004 "TODO implement function calling convention expression",
1005 .{},
1006 );
1007 }
1008 const return_type_expr = switch (fn_proto.return_type) {
1009 .Explicit => |node| node,
1010 .InferErrorSet => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement inferred error sets", .{}),
1011 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
1012 };
1013
1014 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, type_type_rl, return_type_expr);
1015 const fn_type_inst = try astgen.addZIRInst(self, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1016 .return_type = return_type_inst,
1017 .param_types = param_types,
1018 }, .{});
1019
1020 // We need the memory for the Type to go into the arena for the Decl
1021 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
1022 errdefer decl_arena.deinit();
1023 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1024
1025 var block_scope: Scope.Block = .{
1026 .parent = null,
1027 .func = null,
1028 .decl = decl,
1029 .instructions = .{},
1030 .arena = &decl_arena.allocator,
1031 .is_comptime = false,
1032 };
1033 defer block_scope.instructions.deinit(self.gpa);
1034
1035 const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{
1036 .instructions = fn_type_scope.instructions.items,
1037 });
1038 const new_func = try decl_arena.allocator.create(Fn);
1039 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
1040
1041 const fn_zir = blk: {
1042 // This scope's arena memory is discarded after the ZIR generation
1043 // pass completes, and semantic analysis of it completes.
1044 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1045 errdefer gen_scope_arena.deinit();
1046 var gen_scope: Scope.GenZIR = .{
1047 .decl = decl,
1048 .arena = &gen_scope_arena.allocator,
1049 .parent = decl.scope,
1050 };
1051 defer gen_scope.instructions.deinit(self.gpa);
1052
1053 // We need an instruction for each parameter, and they must be first in the body.
1054 try gen_scope.instructions.resize(self.gpa, fn_proto.params_len);
1055 var params_scope = &gen_scope.base;
1056 for (fn_proto.params()) |param, i| {
1057 const name_token = param.name_token.?;
1058 const src = tree.token_locs[name_token].start;
1059 const param_name = tree.tokenSlice(name_token); // TODO: call identifierTokenString
1060 const arg = try gen_scope_arena.allocator.create(zir.Inst.Arg);
1061 arg.* = .{
1062 .base = .{
1063 .tag = .arg,
1064 .src = src,
1065 },
1066 .positionals = .{
1067 .name = param_name,
1068 },
1069 .kw_args = .{},
1070 };
1071 gen_scope.instructions.items[i] = &arg.base;
1072 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVal);
1073 sub_scope.* = .{
1074 .parent = params_scope,
1075 .gen_zir = &gen_scope,
1076 .name = param_name,
1077 .inst = &arg.base,
1078 };
1079 params_scope = &sub_scope.base;
1080 }
1081
1082 const body_block = body_node.cast(ast.Node.Block).?;
1083
1084 try astgen.blockExpr(self, params_scope, body_block);
1085
1086 if (gen_scope.instructions.items.len == 0 or
1087 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
1088 {
1089 const src = tree.token_locs[body_block.rbrace].start;
1090 _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid);
1091 }
1092
1093 const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR);
1094 fn_zir.* = .{
1095 .body = .{
1096 .instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
1097 },
1098 .arena = gen_scope_arena.state,
1099 };
1100 break :blk fn_zir;
1101 };
1102
1103 new_func.* = .{
1104 .analysis = .{ .queued = fn_zir },
1105 .owner_decl = decl,
1106 };
1107 fn_payload.* = .{ .func = new_func };
1108
1109 var prev_type_has_bits = false;
1110 var type_changed = true;
1111
1112 if (decl.typedValueManaged()) |tvm| {
1113 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
1114 type_changed = !tvm.typed_value.ty.eql(fn_type);
1115
1116 tvm.deinit(self.gpa);
1117 }
1118
1119 decl_arena_state.* = decl_arena.state;
1120 decl.typed_value = .{
1121 .most_recent = .{
1122 .typed_value = .{
1123 .ty = fn_type,
1124 .val = Value.initPayload(&fn_payload.base),
1125 },
1126 .arena = decl_arena_state,
1127 },
1128 };
1129 decl.analysis = .complete;
1130 decl.generation = self.generation;
1131
1132 if (fn_type.hasCodeGenBits()) {
1133 // We don't fully codegen the decl until later, but we do need to reserve a global
1134 // offset table index for it. This allows us to codegen decls out of dependency order,
1135 // increasing how many computations can be done in parallel.
1136 try self.comp.bin_file.allocateDeclIndexes(decl);
1137 try self.comp.work_queue.writeItem(.{ .codegen_decl = decl });
1138 } else if (prev_type_has_bits) {
1139 self.comp.bin_file.freeDecl(decl);
1140 }
1141
1142 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
1143 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1144 const export_src = tree.token_locs[maybe_export_token].start;
1145 const name_loc = tree.token_locs[fn_proto.getNameToken().?];
1146 const name = tree.tokenSliceLoc(name_loc);
1147 // The scope needs to have the decl in it.
1148 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1149 }
1150 }
1151 return type_changed;
1152 },
1153 .VarDecl => {
1154 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node);
1155
1156 decl.analysis = .in_progress;
1157
1158 // We need the memory for the Type to go into the arena for the Decl
1159 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
1160 errdefer decl_arena.deinit();
1161 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1162
1163 var block_scope: Scope.Block = .{
1164 .parent = null,
1165 .func = null,
1166 .decl = decl,
1167 .instructions = .{},
1168 .arena = &decl_arena.allocator,
1169 .is_comptime = true,
1170 };
1171 defer block_scope.instructions.deinit(self.gpa);
1172
1173 decl.is_pub = var_decl.getVisibToken() != null;
1174 const is_extern = blk: {
1175 const maybe_extern_token = var_decl.getExternExportToken() orelse
1176 break :blk false;
1177 if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false;
1178 if (var_decl.getInitNode()) |some| {
1179 return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{});
1180 }
1181 break :blk true;
1182 };
1183 if (var_decl.getLibName()) |lib_name| {
1184 assert(is_extern);
1185 return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{});
1186 }
1187 const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var;
1188 const is_threadlocal = if (var_decl.getThreadLocalToken()) |some| blk: {
1189 if (!is_mutable) {
1190 return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{});
1191 }
1192 break :blk true;
1193 } else false;
1194 assert(var_decl.getComptimeToken() == null);
1195 if (var_decl.getAlignNode()) |align_expr| {
1196 return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{});
1197 }
1198 if (var_decl.getSectionNode()) |sect_expr| {
1199 return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{});
1200 }
1201
1202 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.getInitNode()) |init_node| vi: {
1203 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1204 defer gen_scope_arena.deinit();
1205 var gen_scope: Scope.GenZIR = .{
1206 .decl = decl,
1207 .arena = &gen_scope_arena.allocator,
1208 .parent = decl.scope,
1209 };
1210 defer gen_scope.instructions.deinit(self.gpa);
1211
1212 const init_result_loc: astgen.ResultLoc = if (var_decl.getTypeNode()) |type_node| rl: {
1213 const src = tree.token_locs[type_node.firstToken()].start;
1214 const type_type = try astgen.addZIRInstConst(self, &gen_scope.base, src, .{
1215 .ty = Type.initTag(.type),
1216 .val = Value.initTag(.type_type),
1217 });
1218 const var_type = try astgen.expr(self, &gen_scope.base, .{ .ty = type_type }, type_node);
1219 break :rl .{ .ty = var_type };
1220 } else .none;
1221
1222 const src = tree.token_locs[init_node.firstToken()].start;
1223 const init_inst = try astgen.expr(self, &gen_scope.base, init_result_loc, init_node);
1224
1225 var inner_block: Scope.Block = .{
1226 .parent = null,
1227 .func = null,
1228 .decl = decl,
1229 .instructions = .{},
1230 .arena = &gen_scope_arena.allocator,
1231 .is_comptime = true,
1232 };
1233 defer inner_block.instructions.deinit(self.gpa);
1234 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });
1235
1236 // The result location guarantees the type coercion.
1237 const analyzed_init_inst = init_inst.analyzed_inst.?;
1238 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
1239 const val = analyzed_init_inst.value().?;
1240
1241 const ty = try analyzed_init_inst.ty.copy(block_scope.arena);
1242 break :vi .{
1243 .ty = ty,
1244 .val = try val.copy(block_scope.arena),
1245 };
1246 } else if (!is_extern) {
1247 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});
1248 } else if (var_decl.getTypeNode()) |type_node| vi: {
1249 // Temporary arena for the zir instructions.
1250 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1251 defer type_scope_arena.deinit();
1252 var type_scope: Scope.GenZIR = .{
1253 .decl = decl,
1254 .arena = &type_scope_arena.allocator,
1255 .parent = decl.scope,
1256 };
1257 defer type_scope.instructions.deinit(self.gpa);
1258
1259 const src = tree.token_locs[type_node.firstToken()].start;
1260 const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{
1261 .ty = Type.initTag(.type),
1262 .val = Value.initTag(.type_type),
1263 });
1264 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);
1265 const ty = try zir_sema.analyzeBodyValueAsType(self, &block_scope, var_type, .{
1266 .instructions = type_scope.instructions.items,
1267 });
1268 break :vi .{
1269 .ty = ty,
1270 .val = null,
1271 };
1272 } else {
1273 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});
1274 };
1275
1276 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
1277 return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_info.ty});
1278 }
1279
1280 var type_changed = true;
1281 if (decl.typedValueManaged()) |tvm| {
1282 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
1283
1284 tvm.deinit(self.gpa);
1285 }
1286
1287 const new_variable = try decl_arena.allocator.create(Var);
1288 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
1289 new_variable.* = .{
1290 .owner_decl = decl,
1291 .init = var_info.val orelse undefined,
1292 .is_extern = is_extern,
1293 .is_mutable = is_mutable,
1294 .is_threadlocal = is_threadlocal,
1295 };
1296 var_payload.* = .{ .variable = new_variable };
1297
1298 decl_arena_state.* = decl_arena.state;
1299 decl.typed_value = .{
1300 .most_recent = .{
1301 .typed_value = .{
1302 .ty = var_info.ty,
1303 .val = Value.initPayload(&var_payload.base),
1304 },
1305 .arena = decl_arena_state,
1306 },
1307 };
1308 decl.analysis = .complete;
1309 decl.generation = self.generation;
1310
1311 if (var_decl.getExternExportToken()) |maybe_export_token| {
1312 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1313 const export_src = tree.token_locs[maybe_export_token].start;
1314 const name_loc = tree.token_locs[var_decl.name_token];
1315 const name = tree.tokenSliceLoc(name_loc);
1316 // The scope needs to have the decl in it.
1317 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1318 }
1319 }
1320 return type_changed;
1321 },
1322 .Comptime => {
1323 const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node);
1324
1325 decl.analysis = .in_progress;
1326
1327 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
1328 var analysis_arena = std.heap.ArenaAllocator.init(self.gpa);
1329 defer analysis_arena.deinit();
1330 var gen_scope: Scope.GenZIR = .{
1331 .decl = decl,
1332 .arena = &analysis_arena.allocator,
1333 .parent = decl.scope,
1334 };
1335 defer gen_scope.instructions.deinit(self.gpa);
1336
1337 _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr);
1338
1339 var block_scope: Scope.Block = .{
1340 .parent = null,
1341 .func = null,
1342 .decl = decl,
1343 .instructions = .{},
1344 .arena = &analysis_arena.allocator,
1345 .is_comptime = true,
1346 };
1347 defer block_scope.instructions.deinit(self.gpa);
1348
1349 _ = try zir_sema.analyzeBody(self, &block_scope.base, .{
1350 .instructions = gen_scope.instructions.items,
1351 });
1352
1353 decl.analysis = .complete;
1354 decl.generation = self.generation;
1355 return true;
1356 },
1357 .Use => @panic("TODO usingnamespace decl"),
1358 else => unreachable,
1359 }
1360}
1361
1362fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
1363 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);
1364 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);
1365
1366 depender.dependencies.putAssumeCapacity(dependee, {});
1367 dependee.dependants.putAssumeCapacity(depender, {});
1368}
1369
1370fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
1371 switch (root_scope.status) {
1372 .never_loaded, .unloaded_success => {
1373 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
1374
1375 const source = try root_scope.getSource(self);
1376
1377 var keep_zir_module = false;
1378 const zir_module = try self.gpa.create(zir.Module);
1379 defer if (!keep_zir_module) self.gpa.destroy(zir_module);
1380
1381 zir_module.* = try zir.parse(self.gpa, source);
1382 defer if (!keep_zir_module) zir_module.deinit(self.gpa);
1383
1384 if (zir_module.error_msg) |src_err_msg| {
1385 self.failed_files.putAssumeCapacityNoClobber(
1386 &root_scope.base,
1387 try Compilation.ErrorMsg.create(self.gpa, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),
1388 );
1389 root_scope.status = .unloaded_parse_failure;
1390 return error.AnalysisFail;
1391 }
1392
1393 root_scope.status = .loaded_success;
1394 root_scope.contents = .{ .module = zir_module };
1395 keep_zir_module = true;
1396
1397 return zir_module;
1398 },
1399
1400 .unloaded_parse_failure,
1401 .unloaded_sema_failure,
1402 => return error.AnalysisFail,
1403
1404 .loaded_success, .loaded_sema_failure => return root_scope.contents.module,
1405 }
1406}
1407
1408fn getAstTree(self: *Module, container_scope: *Scope.Container) !*ast.Tree {
1409 const tracy = trace(@src());
1410 defer tracy.end();
1411
1412 const root_scope = container_scope.file_scope;
1413
1414 switch (root_scope.status) {
1415 .never_loaded, .unloaded_success => {
1416 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
1417
1418 const source = try root_scope.getSource(self);
1419
1420 var keep_tree = false;
1421 const tree = try std.zig.parse(self.gpa, source);
1422 defer if (!keep_tree) tree.deinit();
1423
1424 if (tree.errors.len != 0) {
1425 const parse_err = tree.errors[0];
1426
1427 var msg = std.ArrayList(u8).init(self.gpa);
1428 defer msg.deinit();
1429
1430 try parse_err.render(tree.token_ids, msg.outStream());
1431 const err_msg = try self.gpa.create(Compilation.ErrorMsg);
1432 err_msg.* = .{
1433 .msg = msg.toOwnedSlice(),
1434 .byte_offset = tree.token_locs[parse_err.loc()].start,
1435 };
1436
1437 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
1438 root_scope.status = .unloaded_parse_failure;
1439 return error.AnalysisFail;
1440 }
1441
1442 root_scope.status = .loaded_success;
1443 root_scope.contents = .{ .tree = tree };
1444 keep_tree = true;
1445
1446 return tree;
1447 },
1448
1449 .unloaded_parse_failure => return error.AnalysisFail,
1450
1451 .loaded_success => return root_scope.contents.tree,
1452 }
1453}
1454
1455pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void {
1456 const tracy = trace(@src());
1457 defer tracy.end();
1458
1459 // We may be analyzing it for the first time, or this may be
1460 // an incremental update. This code handles both cases.
1461 const tree = try self.getAstTree(container_scope);
1462 const decls = tree.root_node.decls();
1463
1464 try self.comp.work_queue.ensureUnusedCapacity(decls.len);
1465 try container_scope.decls.ensureCapacity(self.gpa, decls.len);
1466
1467 // Keep track of the decls that we expect to see in this file so that
1468 // we know which ones have been deleted.
1469 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
1470 defer deleted_decls.deinit();
1471 try deleted_decls.ensureCapacity(container_scope.decls.items().len);
1472 for (container_scope.decls.items()) |entry| {
1473 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
1474 }
1475
1476 for (decls) |src_decl, decl_i| {
1477 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
1478 // We will create a Decl for it regardless of analysis status.
1479 const name_tok = fn_proto.getNameToken() orelse {
1480 @panic("TODO missing function name");
1481 };
1482
1483 const name_loc = tree.token_locs[name_tok];
1484 const name = tree.tokenSliceLoc(name_loc);
1485 const name_hash = container_scope.fullyQualifiedNameHash(name);
1486 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1487 if (self.decl_table.get(name_hash)) |decl| {
1488 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1489 // have been re-ordered.
1490 decl.src_index = decl_i;
1491 if (deleted_decls.remove(decl) == null) {
1492 decl.analysis = .sema_failure;
1493 const err_msg = try Compilation.ErrorMsg.create(self.gpa, tree.token_locs[name_tok].start, "redefinition of '{}'", .{decl.name});
1494 errdefer err_msg.destroy(self.gpa);
1495 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1496 } else {
1497 if (!srcHashEql(decl.contents_hash, contents_hash)) {
1498 try self.markOutdatedDecl(decl);
1499 decl.contents_hash = contents_hash;
1500 } else switch (self.comp.bin_file.tag) {
1501 .coff => {
1502 // TODO Implement for COFF
1503 },
1504 .elf => if (decl.fn_link.elf.len != 0) {
1505 // TODO Look into detecting when this would be unnecessary by storing enough state
1506 // in `Decl` to notice that the line number did not change.
1507 self.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
1508 },
1509 .macho => {
1510 // TODO Implement for MachO
1511 },
1512 .c, .wasm => {},
1513 }
1514 }
1515 } else {
1516 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1517 container_scope.decls.putAssumeCapacity(new_decl, {});
1518 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
1519 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1520 self.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1521 }
1522 }
1523 }
1524 } else if (src_decl.castTag(.VarDecl)) |var_decl| {
1525 const name_loc = tree.token_locs[var_decl.name_token];
1526 const name = tree.tokenSliceLoc(name_loc);
1527 const name_hash = container_scope.fullyQualifiedNameHash(name);
1528 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1529 if (self.decl_table.get(name_hash)) |decl| {
1530 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1531 // have been re-ordered.
1532 decl.src_index = decl_i;
1533 if (deleted_decls.remove(decl) == null) {
1534 decl.analysis = .sema_failure;
1535 const err_msg = try Compilation.ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name});
1536 errdefer err_msg.destroy(self.gpa);
1537 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1538 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
1539 try self.markOutdatedDecl(decl);
1540 decl.contents_hash = contents_hash;
1541 }
1542 } else {
1543 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1544 container_scope.decls.putAssumeCapacity(new_decl, {});
1545 if (var_decl.getExternExportToken()) |maybe_export_token| {
1546 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1547 self.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1548 }
1549 }
1550 }
1551 } else if (src_decl.castTag(.Comptime)) |comptime_node| {
1552 const name_index = self.getNextAnonNameIndex();
1553 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
1554 defer self.gpa.free(name);
1555
1556 const name_hash = container_scope.fullyQualifiedNameHash(name);
1557 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1558
1559 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1560 container_scope.decls.putAssumeCapacity(new_decl, {});
1561 self.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1562 } else if (src_decl.castTag(.ContainerField)) |container_field| {
1563 log.err("TODO: analyze container field", .{});
1564 } else if (src_decl.castTag(.TestDecl)) |test_decl| {
1565 log.err("TODO: analyze test decl", .{});
1566 } else if (src_decl.castTag(.Use)) |use_decl| {
1567 log.err("TODO: analyze usingnamespace decl", .{});
1568 } else {
1569 unreachable;
1570 }
1571 }
1572 // Handle explicitly deleted decls from the source code. Not to be confused
1573 // with when we delete decls because they are no longer referenced.
1574 for (deleted_decls.items()) |entry| {
1575 log.debug("noticed '{}' deleted from source\n", .{entry.key.name});
1576 try self.deleteDecl(entry.key);
1577 }
1578}
1579
1580pub fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
1581 // We may be analyzing it for the first time, or this may be
1582 // an incremental update. This code handles both cases.
1583 const src_module = try self.getSrcModule(root_scope);
1584
1585 try self.comp.work_queue.ensureUnusedCapacity(src_module.decls.len);
1586 try root_scope.decls.ensureCapacity(self.gpa, src_module.decls.len);
1587
1588 var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.gpa);
1589 defer exports_to_resolve.deinit();
1590
1591 // Keep track of the decls that we expect to see in this file so that
1592 // we know which ones have been deleted.
1593 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
1594 defer deleted_decls.deinit();
1595 try deleted_decls.ensureCapacity(self.decl_table.items().len);
1596 for (self.decl_table.items()) |entry| {
1597 deleted_decls.putAssumeCapacityNoClobber(entry.value, {});
1598 }
1599
1600 for (src_module.decls) |src_decl, decl_i| {
1601 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
1602 if (self.decl_table.get(name_hash)) |decl| {
1603 deleted_decls.removeAssertDiscard(decl);
1604 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {
1605 try self.markOutdatedDecl(decl);
1606 decl.contents_hash = src_decl.contents_hash;
1607 }
1608 } else {
1609 const new_decl = try self.createNewDecl(
1610 &root_scope.base,
1611 src_decl.name,
1612 decl_i,
1613 name_hash,
1614 src_decl.contents_hash,
1615 );
1616 root_scope.decls.appendAssumeCapacity(new_decl);
1617 if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| {
1618 try exports_to_resolve.append(src_decl);
1619 }
1620 }
1621 }
1622 for (exports_to_resolve.items) |export_decl| {
1623 _ = try zir_sema.resolveZirDecl(self, &root_scope.base, export_decl);
1624 }
1625 // Handle explicitly deleted decls from the source code. Not to be confused
1626 // with when we delete decls because they are no longer referenced.
1627 for (deleted_decls.items()) |entry| {
1628 log.debug("noticed '{}' deleted from source\n", .{entry.key.name});
1629 try self.deleteDecl(entry.key);
1630 }
1631}
1632
1633pub fn deleteDecl(self: *Module, decl: *Decl) !void {
1634 try self.deletion_set.ensureCapacity(self.gpa, self.deletion_set.items.len + decl.dependencies.items().len);
1635
1636 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
1637 // not be present in the set, and this does nothing.
1638 decl.scope.removeDecl(decl);
1639
1640 log.debug("deleting decl '{}'\n", .{decl.name});
1641 const name_hash = decl.fullyQualifiedNameHash();
1642 self.decl_table.removeAssertDiscard(name_hash);
1643 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
1644 for (decl.dependencies.items()) |entry| {
1645 const dep = entry.key;
1646 dep.removeDependant(decl);
1647 if (dep.dependants.items().len == 0 and !dep.deletion_flag) {
1648 // We don't recursively perform a deletion here, because during the update,
1649 // another reference to it may turn up.
1650 dep.deletion_flag = true;
1651 self.deletion_set.appendAssumeCapacity(dep);
1652 }
1653 }
1654 // Anything that depends on this deleted decl certainly needs to be re-analyzed.
1655 for (decl.dependants.items()) |entry| {
1656 const dep = entry.key;
1657 dep.removeDependency(decl);
1658 if (dep.analysis != .outdated) {
1659 // TODO Move this failure possibility to the top of the function.
1660 try self.markOutdatedDecl(dep);
1661 }
1662 }
1663 if (self.failed_decls.remove(decl)) |entry| {
1664 entry.value.destroy(self.gpa);
1665 }
1666 self.deleteDeclExports(decl);
1667 self.comp.bin_file.freeDecl(decl);
1668 decl.destroy(self.gpa);
1669}
1670
1671/// Delete all the Export objects that are caused by this Decl. Re-analysis of
1672/// this Decl will cause them to be re-created (or not).
1673fn deleteDeclExports(self: *Module, decl: *Decl) void {
1674 const kv = self.export_owners.remove(decl) orelse return;
1675
1676 for (kv.value) |exp| {
1677 if (self.decl_exports.getEntry(exp.exported_decl)) |decl_exports_kv| {
1678 // Remove exports with owner_decl matching the regenerating decl.
1679 const list = decl_exports_kv.value;
1680 var i: usize = 0;
1681 var new_len = list.len;
1682 while (i < new_len) {
1683 if (list[i].owner_decl == decl) {
1684 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
1685 new_len -= 1;
1686 } else {
1687 i += 1;
1688 }
1689 }
1690 decl_exports_kv.value = self.gpa.shrink(list, new_len);
1691 if (new_len == 0) {
1692 self.decl_exports.removeAssertDiscard(exp.exported_decl);
1693 }
1694 }
1695 if (self.comp.bin_file.cast(link.File.Elf)) |elf| {
1696 elf.deleteExport(exp.link);
1697 }
1698 if (self.failed_exports.remove(exp)) |entry| {
1699 entry.value.destroy(self.gpa);
1700 }
1701 _ = self.symbol_exports.remove(exp.options.name);
1702 self.gpa.free(exp.options.name);
1703 self.gpa.destroy(exp);
1704 }
1705 self.gpa.free(kv.value);
1706}
1707
1708pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
1709 const tracy = trace(@src());
1710 defer tracy.end();
1711
1712 // Use the Decl's arena for function memory.
1713 var arena = decl.typed_value.most_recent.arena.?.promote(self.gpa);
1714 defer decl.typed_value.most_recent.arena.?.* = arena.state;
1715 var inner_block: Scope.Block = .{
1716 .parent = null,
1717 .func = func,
1718 .decl = decl,
1719 .instructions = .{},
1720 .arena = &arena.allocator,
1721 .is_comptime = false,
1722 };
1723 defer inner_block.instructions.deinit(self.gpa);
1724
1725 const fn_zir = func.analysis.queued;
1726 defer fn_zir.arena.promote(self.gpa).deinit();
1727 func.analysis = .{ .in_progress = {} };
1728 log.debug("set {} to in_progress\n", .{decl.name});
1729
1730 try zir_sema.analyzeBody(self, &inner_block.base, fn_zir.body);
1731
1732 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
1733 func.analysis = .{ .success = .{ .instructions = instructions } };
1734 log.debug("set {} to success\n", .{decl.name});
1735}
1736
1737fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
1738 log.debug("mark {} outdated\n", .{decl.name});
1739 try self.comp.work_queue.writeItem(.{ .analyze_decl = decl });
1740 if (self.failed_decls.remove(decl)) |entry| {
1741 entry.value.destroy(self.gpa);
1742 }
1743 decl.analysis = .outdated;
1744}
1745
1746fn allocateNewDecl(
1747 self: *Module,
1748 scope: *Scope,
1749 src_index: usize,
1750 contents_hash: std.zig.SrcHash,
1751) !*Decl {
1752 const new_decl = try self.gpa.create(Decl);
1753 new_decl.* = .{
1754 .name = "",
1755 .scope = scope.namespace(),
1756 .src_index = src_index,
1757 .typed_value = .{ .never_succeeded = {} },
1758 .analysis = .unreferenced,
1759 .deletion_flag = false,
1760 .contents_hash = contents_hash,
1761 .link = switch (self.comp.bin_file.tag) {
1762 .coff => .{ .coff = link.File.Coff.TextBlock.empty },
1763 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
1764 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
1765 .c => .{ .c = {} },
1766 .wasm => .{ .wasm = {} },
1767 },
1768 .fn_link = switch (self.comp.bin_file.tag) {
1769 .coff => .{ .coff = {} },
1770 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
1771 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
1772 .c => .{ .c = {} },
1773 .wasm => .{ .wasm = null },
1774 },
1775 .generation = 0,
1776 .is_pub = false,
1777 };
1778 return new_decl;
1779}
1780
1781fn createNewDecl(
1782 self: *Module,
1783 scope: *Scope,
1784 decl_name: []const u8,
1785 src_index: usize,
1786 name_hash: Scope.NameHash,
1787 contents_hash: std.zig.SrcHash,
1788) !*Decl {
1789 try self.decl_table.ensureCapacity(self.gpa, self.decl_table.items().len + 1);
1790 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
1791 errdefer self.gpa.destroy(new_decl);
1792 new_decl.name = try mem.dupeZ(self.gpa, u8, decl_name);
1793 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
1794 return new_decl;
1795}
1796
1797/// Get error value for error tag `name`.
1798pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
1799 const gop = try self.global_error_set.getOrPut(self.gpa, name);
1800 if (gop.found_existing)
1801 return gop.entry.*;
1802 errdefer self.global_error_set.removeAssertDiscard(name);
1803
1804 gop.entry.key = try self.gpa.dupe(u8, name);
1805 gop.entry.value = @intCast(u16, self.global_error_set.count() - 1);
1806 return gop.entry.*;
1807}
1808
1809pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
1810 return scope.cast(Scope.Block) orelse
1811 return self.fail(scope, src, "instruction illegal outside function body", .{});
1812}
1813
1814pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
1815 const block = try self.requireFunctionBlock(scope, src);
1816 if (block.is_comptime) {
1817 return self.fail(scope, src, "unable to resolve comptime value", .{});
1818 }
1819 return block;
1820}
1821
1822pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {
1823 return (try self.resolveDefinedValue(scope, base)) orelse
1824 return self.fail(scope, base.src, "unable to resolve comptime value", .{});
1825}
1826
1827pub fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {
1828 if (base.value()) |val| {
1829 if (val.isUndef()) {
1830 return self.fail(scope, base.src, "use of undefined value here causes undefined behavior", .{});
1831 }
1832 return val;
1833 }
1834 return null;
1835}
1836
1837pub fn analyzeExport(self: *Module, scope: *Scope, src: usize, borrowed_symbol_name: []const u8, exported_decl: *Decl) !void {
1838 try self.ensureDeclAnalyzed(exported_decl);
1839 const typed_value = exported_decl.typed_value.most_recent.typed_value;
1840 switch (typed_value.ty.zigTypeTag()) {
1841 .Fn => {},
1842 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
1843 }
1844
1845 try self.decl_exports.ensureCapacity(self.gpa, self.decl_exports.items().len + 1);
1846 try self.export_owners.ensureCapacity(self.gpa, self.export_owners.items().len + 1);
1847
1848 const new_export = try self.gpa.create(Export);
1849 errdefer self.gpa.destroy(new_export);
1850
1851 const symbol_name = try self.gpa.dupe(u8, borrowed_symbol_name);
1852 errdefer self.gpa.free(symbol_name);
1853
1854 const owner_decl = scope.decl().?;
1855
1856 new_export.* = .{
1857 .options = .{ .name = symbol_name },
1858 .src = src,
1859 .link = .{},
1860 .owner_decl = owner_decl,
1861 .exported_decl = exported_decl,
1862 .status = .in_progress,
1863 };
1864
1865 // Add to export_owners table.
1866 const eo_gop = self.export_owners.getOrPutAssumeCapacity(owner_decl);
1867 if (!eo_gop.found_existing) {
1868 eo_gop.entry.value = &[0]*Export{};
1869 }
1870 eo_gop.entry.value = try self.gpa.realloc(eo_gop.entry.value, eo_gop.entry.value.len + 1);
1871 eo_gop.entry.value[eo_gop.entry.value.len - 1] = new_export;
1872 errdefer eo_gop.entry.value = self.gpa.shrink(eo_gop.entry.value, eo_gop.entry.value.len - 1);
1873
1874 // Add to exported_decl table.
1875 const de_gop = self.decl_exports.getOrPutAssumeCapacity(exported_decl);
1876 if (!de_gop.found_existing) {
1877 de_gop.entry.value = &[0]*Export{};
1878 }
1879 de_gop.entry.value = try self.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);
1880 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;
1881 errdefer de_gop.entry.value = self.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);
1882
1883 if (self.symbol_exports.get(symbol_name)) |_| {
1884 try self.failed_exports.ensureCapacity(self.gpa, self.failed_exports.items().len + 1);
1885 self.failed_exports.putAssumeCapacityNoClobber(new_export, try Compilation.ErrorMsg.create(
1886 self.gpa,
1887 src,
1888 "exported symbol collision: {}",
1889 .{symbol_name},
1890 ));
1891 // TODO: add a note
1892 new_export.status = .failed;
1893 return;
1894 }
1895
1896 try self.symbol_exports.putNoClobber(self.gpa, symbol_name, new_export);
1897 self.comp.bin_file.updateDeclExports(self, exported_decl, de_gop.entry.value) catch |err| switch (err) {
1898 error.OutOfMemory => return error.OutOfMemory,
1899 else => {
1900 try self.failed_exports.ensureCapacity(self.gpa, self.failed_exports.items().len + 1);
1901 self.failed_exports.putAssumeCapacityNoClobber(new_export, try Compilation.ErrorMsg.create(
1902 self.gpa,
1903 src,
1904 "unable to export: {}",
1905 .{@errorName(err)},
1906 ));
1907 new_export.status = .failed_retryable;
1908 },
1909 };
1910}
1911
1912pub fn addNoOp(
1913 self: *Module,
1914 block: *Scope.Block,
1915 src: usize,
1916 ty: Type,
1917 comptime tag: Inst.Tag,
1918) !*Inst {
1919 const inst = try block.arena.create(tag.Type());
1920 inst.* = .{
1921 .base = .{
1922 .tag = tag,
1923 .ty = ty,
1924 .src = src,
1925 },
1926 };
1927 try block.instructions.append(self.gpa, &inst.base);
1928 return &inst.base;
1929}
1930
1931pub fn addUnOp(
1932 self: *Module,
1933 block: *Scope.Block,
1934 src: usize,
1935 ty: Type,
1936 tag: Inst.Tag,
1937 operand: *Inst,
1938) !*Inst {
1939 const inst = try block.arena.create(Inst.UnOp);
1940 inst.* = .{
1941 .base = .{
1942 .tag = tag,
1943 .ty = ty,
1944 .src = src,
1945 },
1946 .operand = operand,
1947 };
1948 try block.instructions.append(self.gpa, &inst.base);
1949 return &inst.base;
1950}
1951
1952pub fn addBinOp(
1953 self: *Module,
1954 block: *Scope.Block,
1955 src: usize,
1956 ty: Type,
1957 tag: Inst.Tag,
1958 lhs: *Inst,
1959 rhs: *Inst,
1960) !*Inst {
1961 const inst = try block.arena.create(Inst.BinOp);
1962 inst.* = .{
1963 .base = .{
1964 .tag = tag,
1965 .ty = ty,
1966 .src = src,
1967 },
1968 .lhs = lhs,
1969 .rhs = rhs,
1970 };
1971 try block.instructions.append(self.gpa, &inst.base);
1972 return &inst.base;
1973}
1974
1975pub fn addArg(self: *Module, block: *Scope.Block, src: usize, ty: Type, name: [*:0]const u8) !*Inst {
1976 const inst = try block.arena.create(Inst.Arg);
1977 inst.* = .{
1978 .base = .{
1979 .tag = .arg,
1980 .ty = ty,
1981 .src = src,
1982 },
1983 .name = name,
1984 };
1985 try block.instructions.append(self.gpa, &inst.base);
1986 return &inst.base;
1987}
1988
1989pub fn addBr(
1990 self: *Module,
1991 scope_block: *Scope.Block,
1992 src: usize,
1993 target_block: *Inst.Block,
1994 operand: *Inst,
1995) !*Inst {
1996 const inst = try scope_block.arena.create(Inst.Br);
1997 inst.* = .{
1998 .base = .{
1999 .tag = .br,
2000 .ty = Type.initTag(.noreturn),
2001 .src = src,
2002 },
2003 .operand = operand,
2004 .block = target_block,
2005 };
2006 try scope_block.instructions.append(self.gpa, &inst.base);
2007 return &inst.base;
2008}
2009
2010pub fn addCondBr(
2011 self: *Module,
2012 block: *Scope.Block,
2013 src: usize,
2014 condition: *Inst,
2015 then_body: ir.Body,
2016 else_body: ir.Body,
2017) !*Inst {
2018 const inst = try block.arena.create(Inst.CondBr);
2019 inst.* = .{
2020 .base = .{
2021 .tag = .condbr,
2022 .ty = Type.initTag(.noreturn),
2023 .src = src,
2024 },
2025 .condition = condition,
2026 .then_body = then_body,
2027 .else_body = else_body,
2028 };
2029 try block.instructions.append(self.gpa, &inst.base);
2030 return &inst.base;
2031}
2032
2033pub fn addCall(
2034 self: *Module,
2035 block: *Scope.Block,
2036 src: usize,
2037 ty: Type,
2038 func: *Inst,
2039 args: []const *Inst,
2040) !*Inst {
2041 const inst = try block.arena.create(Inst.Call);
2042 inst.* = .{
2043 .base = .{
2044 .tag = .call,
2045 .ty = ty,
2046 .src = src,
2047 },
2048 .func = func,
2049 .args = args,
2050 };
2051 try block.instructions.append(self.gpa, &inst.base);
2052 return &inst.base;
2053}
2054
2055pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
2056 const const_inst = try scope.arena().create(Inst.Constant);
2057 const_inst.* = .{
2058 .base = .{
2059 .tag = Inst.Constant.base_tag,
2060 .ty = typed_value.ty,
2061 .src = src,
2062 },
2063 .val = typed_value.val,
2064 };
2065 return &const_inst.base;
2066}
2067
2068pub fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
2069 return self.constInst(scope, src, .{
2070 .ty = Type.initTag(.type),
2071 .val = try ty.toValue(scope.arena()),
2072 });
2073}
2074
2075pub fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
2076 return self.constInst(scope, src, .{
2077 .ty = Type.initTag(.void),
2078 .val = Value.initTag(.void_value),
2079 });
2080}
2081
2082pub fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {
2083 return self.constInst(scope, src, .{
2084 .ty = Type.initTag(.noreturn),
2085 .val = Value.initTag(.unreachable_value),
2086 });
2087}
2088
2089pub fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
2090 return self.constInst(scope, src, .{
2091 .ty = ty,
2092 .val = Value.initTag(.undef),
2093 });
2094}
2095
2096pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst {
2097 return self.constInst(scope, src, .{
2098 .ty = Type.initTag(.bool),
2099 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],
2100 });
2101}
2102
2103pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst {
2104 const int_payload = try scope.arena().create(Value.Payload.Int_u64);
2105 int_payload.* = .{ .int = int };
2106
2107 return self.constInst(scope, src, .{
2108 .ty = ty,
2109 .val = Value.initPayload(&int_payload.base),
2110 });
2111}
2112
2113pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst {
2114 const int_payload = try scope.arena().create(Value.Payload.Int_i64);
2115 int_payload.* = .{ .int = int };
2116
2117 return self.constInst(scope, src, .{
2118 .ty = ty,
2119 .val = Value.initPayload(&int_payload.base),
2120 });
2121}
2122
2123pub fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
2124 const val_payload = if (big_int.positive) blk: {
2125 if (big_int.to(u64)) |x| {
2126 return self.constIntUnsigned(scope, src, ty, x);
2127 } else |err| switch (err) {
2128 error.NegativeIntoUnsigned => unreachable,
2129 error.TargetTooSmall => {}, // handled below
2130 }
2131 const big_int_payload = try scope.arena().create(Value.Payload.IntBigPositive);
2132 big_int_payload.* = .{ .limbs = big_int.limbs };
2133 break :blk &big_int_payload.base;
2134 } else blk: {
2135 if (big_int.to(i64)) |x| {
2136 return self.constIntSigned(scope, src, ty, x);
2137 } else |err| switch (err) {
2138 error.NegativeIntoUnsigned => unreachable,
2139 error.TargetTooSmall => {}, // handled below
2140 }
2141 const big_int_payload = try scope.arena().create(Value.Payload.IntBigNegative);
2142 big_int_payload.* = .{ .limbs = big_int.limbs };
2143 break :blk &big_int_payload.base;
2144 };
2145
2146 return self.constInst(scope, src, .{
2147 .ty = ty,
2148 .val = Value.initPayload(val_payload),
2149 });
2150}
2151
2152pub fn createAnonymousDecl(
2153 self: *Module,
2154 scope: *Scope,
2155 decl_arena: *std.heap.ArenaAllocator,
2156 typed_value: TypedValue,
2157) !*Decl {
2158 const name_index = self.getNextAnonNameIndex();
2159 const scope_decl = scope.decl().?;
2160 const name = try std.fmt.allocPrint(self.gpa, "{}__anon_{}", .{ scope_decl.name, name_index });
2161 defer self.gpa.free(name);
2162 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
2163 const src_hash: std.zig.SrcHash = undefined;
2164 const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
2165 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
2166
2167 decl_arena_state.* = decl_arena.state;
2168 new_decl.typed_value = .{
2169 .most_recent = .{
2170 .typed_value = typed_value,
2171 .arena = decl_arena_state,
2172 },
2173 };
2174 new_decl.analysis = .complete;
2175 new_decl.generation = self.generation;
2176
2177 // TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.
2178 // We should be able to further improve the compiler to not omit Decls which are only referenced at
2179 // compile-time and not runtime.
2180 if (typed_value.ty.hasCodeGenBits()) {
2181 try self.comp.bin_file.allocateDeclIndexes(new_decl);
2182 try self.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });
2183 }
2184
2185 return new_decl;
2186}
2187
2188fn getNextAnonNameIndex(self: *Module) usize {
2189 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
2190}
2191
2192pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
2193 const namespace = scope.namespace();
2194 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2195 return self.decl_table.get(name_hash);
2196}
2197
2198pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2199 const scope_decl = scope.decl().?;
2200 try self.declareDeclDependency(scope_decl, decl);
2201 self.ensureDeclAnalyzed(decl) catch |err| {
2202 if (scope.cast(Scope.Block)) |block| {
2203 if (block.func) |func| {
2204 func.analysis = .dependency_failure;
2205 } else {
2206 block.decl.analysis = .dependency_failure;
2207 }
2208 } else {
2209 scope_decl.analysis = .dependency_failure;
2210 }
2211 return err;
2212 };
2213
2214 const decl_tv = try decl.typedValue();
2215 if (decl_tv.val.tag() == .variable) {
2216 return self.analyzeVarRef(scope, src, decl_tv);
2217 }
2218 const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
2219 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
2220 val_payload.* = .{ .decl = decl };
2221
2222 return self.constInst(scope, src, .{
2223 .ty = ty,
2224 .val = Value.initPayload(&val_payload.base),
2225 });
2226}
2227
2228fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
2229 const variable = tv.val.cast(Value.Payload.Variable).?.variable;
2230
2231 const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
2232 if (!variable.is_mutable and !variable.is_extern) {
2233 const val_payload = try scope.arena().create(Value.Payload.RefVal);
2234 val_payload.* = .{ .val = variable.init };
2235 return self.constInst(scope, src, .{
2236 .ty = ty,
2237 .val = Value.initPayload(&val_payload.base),
2238 });
2239 }
2240
2241 const b = try self.requireRuntimeBlock(scope, src);
2242 const inst = try b.arena.create(Inst.VarPtr);
2243 inst.* = .{
2244 .base = .{
2245 .tag = .varptr,
2246 .ty = ty,
2247 .src = src,
2248 },
2249 .variable = variable,
2250 };
2251 try b.instructions.append(self.gpa, &inst.base);
2252 return &inst.base;
2253}
2254
2255pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
2256 const elem_ty = switch (ptr.ty.zigTypeTag()) {
2257 .Pointer => ptr.ty.elemType(),
2258 else => return self.fail(scope, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
2259 };
2260 if (ptr.value()) |val| {
2261 return self.constInst(scope, src, .{
2262 .ty = elem_ty,
2263 .val = try val.pointerDeref(scope.arena()),
2264 });
2265 }
2266
2267 const b = try self.requireRuntimeBlock(scope, src);
2268 return self.addUnOp(b, src, elem_ty, .load, ptr);
2269}
2270
2271pub fn analyzeDeclRefByName(self: *Module, scope: *Scope, src: usize, decl_name: []const u8) InnerError!*Inst {
2272 const decl = self.lookupDeclName(scope, decl_name) orelse
2273 return self.fail(scope, src, "decl '{}' not found", .{decl_name});
2274 return self.analyzeDeclRef(scope, src, decl);
2275}
2276
2277pub fn wantSafety(self: *Module, scope: *Scope) bool {
2278 // TODO take into account scope's safety overrides
2279 return switch (self.optimizeMode()) {
2280 .Debug => true,
2281 .ReleaseSafe => true,
2282 .ReleaseFast => false,
2283 .ReleaseSmall => false,
2284 };
2285}
2286
2287pub fn analyzeIsNull(
2288 self: *Module,
2289 scope: *Scope,
2290 src: usize,
2291 operand: *Inst,
2292 invert_logic: bool,
2293) InnerError!*Inst {
2294 if (operand.value()) |opt_val| {
2295 const is_null = opt_val.isNull();
2296 const bool_value = if (invert_logic) !is_null else is_null;
2297 return self.constBool(scope, src, bool_value);
2298 }
2299 const b = try self.requireRuntimeBlock(scope, src);
2300 const inst_tag: Inst.Tag = if (invert_logic) .isnonnull else .isnull;
2301 return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand);
2302}
2303
2304pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
2305 return self.fail(scope, src, "TODO implement analysis of iserr", .{});
2306}
2307
2308pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
2309 const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
2310 .Pointer => array_ptr.ty.elemType(),
2311 else => return self.fail(scope, src, "expected pointer, found '{}'", .{array_ptr.ty}),
2312 };
2313
2314 var array_type = ptr_child;
2315 const elem_type = switch (ptr_child.zigTypeTag()) {
2316 .Array => ptr_child.elemType(),
2317 .Pointer => blk: {
2318 if (ptr_child.isSinglePointer()) {
2319 if (ptr_child.elemType().zigTypeTag() == .Array) {
2320 array_type = ptr_child.elemType();
2321 break :blk ptr_child.elemType().elemType();
2322 }
2323
2324 return self.fail(scope, src, "slice of single-item pointer", .{});
2325 }
2326 break :blk ptr_child.elemType();
2327 },
2328 else => return self.fail(scope, src, "slice of non-array type '{}'", .{ptr_child}),
2329 };
2330
2331 const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
2332 const casted = try self.coerce(scope, elem_type, sentinel);
2333 break :blk try self.resolveConstValue(scope, casted);
2334 } else null;
2335
2336 var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
2337 var return_elem_type = elem_type;
2338 if (end_opt) |end| {
2339 if (end.value()) |end_val| {
2340 if (start.value()) |start_val| {
2341 const start_u64 = start_val.toUnsignedInt();
2342 const end_u64 = end_val.toUnsignedInt();
2343 if (start_u64 > end_u64) {
2344 return self.fail(scope, src, "out of bounds slice", .{});
2345 }
2346
2347 const len = end_u64 - start_u64;
2348 const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
2349 array_type.sentinel()
2350 else
2351 slice_sentinel;
2352 return_elem_type = try self.arrayType(scope, len, array_sentinel, elem_type);
2353 return_ptr_size = .One;
2354 }
2355 }
2356 }
2357 const return_type = try self.ptrType(
2358 scope,
2359 src,
2360 return_elem_type,
2361 if (end_opt == null) slice_sentinel else null,
2362 0, // TODO alignment
2363 0,
2364 0,
2365 !ptr_child.isConstPtr(),
2366 ptr_child.isAllowzeroPtr(),
2367 ptr_child.isVolatilePtr(),
2368 return_ptr_size,
2369 );
2370
2371 return self.fail(scope, src, "TODO implement analysis of slice", .{});
2372}
2373
2374/// Asserts that lhs and rhs types are both numeric.
2375pub fn cmpNumeric(
2376 self: *Module,
2377 scope: *Scope,
2378 src: usize,
2379 lhs: *Inst,
2380 rhs: *Inst,
2381 op: std.math.CompareOperator,
2382) !*Inst {
2383 assert(lhs.ty.isNumeric());
2384 assert(rhs.ty.isNumeric());
2385
2386 const lhs_ty_tag = lhs.ty.zigTypeTag();
2387 const rhs_ty_tag = rhs.ty.zigTypeTag();
2388
2389 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
2390 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2391 return self.fail(scope, src, "vector length mismatch: {} and {}", .{
2392 lhs.ty.arrayLen(),
2393 rhs.ty.arrayLen(),
2394 });
2395 }
2396 return self.fail(scope, src, "TODO implement support for vectors in cmpNumeric", .{});
2397 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
2398 return self.fail(scope, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
2399 lhs.ty,
2400 rhs.ty,
2401 });
2402 }
2403
2404 if (lhs.value()) |lhs_val| {
2405 if (rhs.value()) |rhs_val| {
2406 return self.constBool(scope, src, Value.compare(lhs_val, op, rhs_val));
2407 }
2408 }
2409
2410 // TODO handle comparisons against lazy zero values
2411 // Some values can be compared against zero without being runtime known or without forcing
2412 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
2413 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
2414 // of this function if we don't need to.
2415
2416 // It must be a runtime comparison.
2417 const b = try self.requireRuntimeBlock(scope, src);
2418 // For floats, emit a float comparison instruction.
2419 const lhs_is_float = switch (lhs_ty_tag) {
2420 .Float, .ComptimeFloat => true,
2421 else => false,
2422 };
2423 const rhs_is_float = switch (rhs_ty_tag) {
2424 .Float, .ComptimeFloat => true,
2425 else => false,
2426 };
2427 if (lhs_is_float and rhs_is_float) {
2428 // Implicit cast the smaller one to the larger one.
2429 const dest_type = x: {
2430 if (lhs_ty_tag == .ComptimeFloat) {
2431 break :x rhs.ty;
2432 } else if (rhs_ty_tag == .ComptimeFloat) {
2433 break :x lhs.ty;
2434 }
2435 if (lhs.ty.floatBits(self.getTarget()) >= rhs.ty.floatBits(self.getTarget())) {
2436 break :x lhs.ty;
2437 } else {
2438 break :x rhs.ty;
2439 }
2440 };
2441 const casted_lhs = try self.coerce(scope, dest_type, lhs);
2442 const casted_rhs = try self.coerce(scope, dest_type, rhs);
2443 return self.addBinOp(b, src, dest_type, Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
2444 }
2445 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
2446 // For mixed signed and unsigned integers, implicit cast both operands to a signed
2447 // integer with + 1 bit.
2448 // For mixed floats and integers, extract the integer part from the float, cast that to
2449 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
2450 // add/subtract 1.
2451 const lhs_is_signed = if (lhs.value()) |lhs_val|
2452 lhs_val.compareWithZero(.lt)
2453 else
2454 (lhs.ty.isFloat() or lhs.ty.isSignedInt());
2455 const rhs_is_signed = if (rhs.value()) |rhs_val|
2456 rhs_val.compareWithZero(.lt)
2457 else
2458 (rhs.ty.isFloat() or rhs.ty.isSignedInt());
2459 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
2460
2461 var dest_float_type: ?Type = null;
2462
2463 var lhs_bits: usize = undefined;
2464 if (lhs.value()) |lhs_val| {
2465 if (lhs_val.isUndef())
2466 return self.constUndef(scope, src, Type.initTag(.bool));
2467 const is_unsigned = if (lhs_is_float) x: {
2468 var bigint_space: Value.BigIntSpace = undefined;
2469 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(self.gpa);
2470 defer bigint.deinit();
2471 const zcmp = lhs_val.orderAgainstZero();
2472 if (lhs_val.floatHasFraction()) {
2473 switch (op) {
2474 .eq => return self.constBool(scope, src, false),
2475 .neq => return self.constBool(scope, src, true),
2476 else => {},
2477 }
2478 if (zcmp == .lt) {
2479 try bigint.addScalar(bigint.toConst(), -1);
2480 } else {
2481 try bigint.addScalar(bigint.toConst(), 1);
2482 }
2483 }
2484 lhs_bits = bigint.toConst().bitCountTwosComp();
2485 break :x (zcmp != .lt);
2486 } else x: {
2487 lhs_bits = lhs_val.intBitCountTwosComp();
2488 break :x (lhs_val.orderAgainstZero() != .lt);
2489 };
2490 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
2491 } else if (lhs_is_float) {
2492 dest_float_type = lhs.ty;
2493 } else {
2494 const int_info = lhs.ty.intInfo(self.getTarget());
2495 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
2496 }
2497
2498 var rhs_bits: usize = undefined;
2499 if (rhs.value()) |rhs_val| {
2500 if (rhs_val.isUndef())
2501 return self.constUndef(scope, src, Type.initTag(.bool));
2502 const is_unsigned = if (rhs_is_float) x: {
2503 var bigint_space: Value.BigIntSpace = undefined;
2504 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(self.gpa);
2505 defer bigint.deinit();
2506 const zcmp = rhs_val.orderAgainstZero();
2507 if (rhs_val.floatHasFraction()) {
2508 switch (op) {
2509 .eq => return self.constBool(scope, src, false),
2510 .neq => return self.constBool(scope, src, true),
2511 else => {},
2512 }
2513 if (zcmp == .lt) {
2514 try bigint.addScalar(bigint.toConst(), -1);
2515 } else {
2516 try bigint.addScalar(bigint.toConst(), 1);
2517 }
2518 }
2519 rhs_bits = bigint.toConst().bitCountTwosComp();
2520 break :x (zcmp != .lt);
2521 } else x: {
2522 rhs_bits = rhs_val.intBitCountTwosComp();
2523 break :x (rhs_val.orderAgainstZero() != .lt);
2524 };
2525 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
2526 } else if (rhs_is_float) {
2527 dest_float_type = rhs.ty;
2528 } else {
2529 const int_info = rhs.ty.intInfo(self.getTarget());
2530 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
2531 }
2532
2533 const dest_type = if (dest_float_type) |ft| ft else blk: {
2534 const max_bits = std.math.max(lhs_bits, rhs_bits);
2535 const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {
2536 error.Overflow => return self.fail(scope, src, "{} exceeds maximum integer bit count", .{max_bits}),
2537 };
2538 break :blk try self.makeIntType(scope, dest_int_is_signed, casted_bits);
2539 };
2540 const casted_lhs = try self.coerce(scope, dest_type, lhs);
2541 const casted_rhs = try self.coerce(scope, dest_type, rhs);
2542
2543 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
2544}
2545
2546fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2547 if (inst.value()) |val| {
2548 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2549 }
2550
2551 const b = try self.requireRuntimeBlock(scope, inst.src);
2552 return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
2553}
2554
2555fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
2556 if (signed) {
2557 const int_payload = try scope.arena().create(Type.Payload.IntSigned);
2558 int_payload.* = .{ .bits = bits };
2559 return Type.initPayload(&int_payload.base);
2560 } else {
2561 const int_payload = try scope.arena().create(Type.Payload.IntUnsigned);
2562 int_payload.* = .{ .bits = bits };
2563 return Type.initPayload(&int_payload.base);
2564 }
2565}
2566
2567pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
2568 if (instructions.len == 0)
2569 return Type.initTag(.noreturn);
2570
2571 if (instructions.len == 1)
2572 return instructions[0].ty;
2573
2574 var prev_inst = instructions[0];
2575 for (instructions[1..]) |next_inst| {
2576 if (next_inst.ty.eql(prev_inst.ty))
2577 continue;
2578 if (next_inst.ty.zigTypeTag() == .NoReturn)
2579 continue;
2580 if (prev_inst.ty.zigTypeTag() == .NoReturn) {
2581 prev_inst = next_inst;
2582 continue;
2583 }
2584 if (next_inst.ty.zigTypeTag() == .Undefined)
2585 continue;
2586 if (prev_inst.ty.zigTypeTag() == .Undefined) {
2587 prev_inst = next_inst;
2588 continue;
2589 }
2590 if (prev_inst.ty.isInt() and
2591 next_inst.ty.isInt() and
2592 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())
2593 {
2594 if (prev_inst.ty.intInfo(self.getTarget()).bits < next_inst.ty.intInfo(self.getTarget()).bits) {
2595 prev_inst = next_inst;
2596 }
2597 continue;
2598 }
2599 if (prev_inst.ty.isFloat() and next_inst.ty.isFloat()) {
2600 if (prev_inst.ty.floatBits(self.getTarget()) < next_inst.ty.floatBits(self.getTarget())) {
2601 prev_inst = next_inst;
2602 }
2603 continue;
2604 }
2605
2606 // TODO error notes pointing out each type
2607 return self.fail(scope, next_inst.src, "incompatible types: '{}' and '{}'", .{ prev_inst.ty, next_inst.ty });
2608 }
2609
2610 return prev_inst.ty;
2611}
2612
2613pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2614 // If the types are the same, we can return the operand.
2615 if (dest_type.eql(inst.ty))
2616 return inst;
2617
2618 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
2619 if (in_memory_result == .ok) {
2620 return self.bitcast(scope, dest_type, inst);
2621 }
2622
2623 // undefined to anything
2624 if (inst.value()) |val| {
2625 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
2626 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2627 }
2628 }
2629 assert(inst.ty.zigTypeTag() != .Undefined);
2630
2631 // null to ?T
2632 if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
2633 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
2634 }
2635
2636 // T to ?T
2637 if (dest_type.zigTypeTag() == .Optional) {
2638 var buf: Type.Payload.PointerSimple = undefined;
2639 const child_type = dest_type.optionalChild(&buf);
2640 if (child_type.eql(inst.ty)) {
2641 return self.wrapOptional(scope, dest_type, inst);
2642 } else if (try self.coerceNum(scope, child_type, inst)) |some| {
2643 return self.wrapOptional(scope, dest_type, some);
2644 }
2645 }
2646
2647 // *[N]T to []T
2648 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
2649 (!inst.ty.isConstPtr() or dest_type.isConstPtr()))
2650 {
2651 const array_type = inst.ty.elemType();
2652 const dst_elem_type = dest_type.elemType();
2653 if (array_type.zigTypeTag() == .Array and
2654 coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok)
2655 {
2656 return self.coerceArrayPtrToSlice(scope, dest_type, inst);
2657 }
2658 }
2659
2660 // comptime known number to other number
2661 if (try self.coerceNum(scope, dest_type, inst)) |some|
2662 return some;
2663
2664 // integer widening
2665 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
2666 assert(inst.value() == null); // handled above
2667
2668 const src_info = inst.ty.intInfo(self.getTarget());
2669 const dst_info = dest_type.intInfo(self.getTarget());
2670 if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or
2671 // small enough unsigned ints can get casted to large enough signed ints
2672 (src_info.signed and !dst_info.signed and dst_info.bits > src_info.bits))
2673 {
2674 const b = try self.requireRuntimeBlock(scope, inst.src);
2675 return self.addUnOp(b, inst.src, dest_type, .intcast, inst);
2676 }
2677 }
2678
2679 // float widening
2680 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
2681 assert(inst.value() == null); // handled above
2682
2683 const src_bits = inst.ty.floatBits(self.getTarget());
2684 const dst_bits = dest_type.floatBits(self.getTarget());
2685 if (dst_bits >= src_bits) {
2686 const b = try self.requireRuntimeBlock(scope, inst.src);
2687 return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);
2688 }
2689 }
2690
2691 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
2692}
2693
2694pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*Inst {
2695 const val = inst.value() orelse return null;
2696 const src_zig_tag = inst.ty.zigTypeTag();
2697 const dst_zig_tag = dest_type.zigTypeTag();
2698
2699 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
2700 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2701 if (val.floatHasFraction()) {
2702 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
2703 }
2704 return self.fail(scope, inst.src, "TODO float to int", .{});
2705 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2706 if (!val.intFitsInType(dest_type, self.getTarget())) {
2707 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
2708 }
2709 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2710 }
2711 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
2712 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2713 const res = val.floatCast(scope.arena(), dest_type, self.getTarget()) catch |err| switch (err) {
2714 error.Overflow => return self.fail(
2715 scope,
2716 inst.src,
2717 "cast of value {} to type '{}' loses information",
2718 .{ val, dest_type },
2719 ),
2720 error.OutOfMemory => return error.OutOfMemory,
2721 };
2722 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
2723 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2724 return self.fail(scope, inst.src, "TODO int to float", .{});
2725 }
2726 }
2727 return null;
2728}
2729
2730pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
2731 if (ptr.ty.isConstPtr())
2732 return self.fail(scope, src, "cannot assign to constant", .{});
2733
2734 const elem_ty = ptr.ty.elemType();
2735 const value = try self.coerce(scope, elem_ty, uncasted_value);
2736 if (elem_ty.onePossibleValue() != null)
2737 return self.constVoid(scope, src);
2738
2739 // TODO handle comptime pointer writes
2740 // TODO handle if the element type requires comptime
2741
2742 const b = try self.requireRuntimeBlock(scope, src);
2743 return self.addBinOp(b, src, Type.initTag(.void), .store, ptr, value);
2744}
2745
2746pub fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2747 if (inst.value()) |val| {
2748 // Keep the comptime Value representation; take the new type.
2749 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2750 }
2751 // TODO validate the type size and other compile errors
2752 const b = try self.requireRuntimeBlock(scope, inst.src);
2753 return self.addUnOp(b, inst.src, dest_type, .bitcast, inst);
2754}
2755
2756fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2757 if (inst.value()) |val| {
2758 // The comptime Value representation is compatible with both types.
2759 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2760 }
2761 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
2762}
2763
2764pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
2765 @setCold(true);
2766 const err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);
2767 return self.failWithOwnedErrorMsg(scope, src, err_msg);
2768}
2769
2770pub fn failTok(
2771 self: *Module,
2772 scope: *Scope,
2773 token_index: ast.TokenIndex,
2774 comptime format: []const u8,
2775 args: anytype,
2776) InnerError {
2777 @setCold(true);
2778 const src = scope.tree().token_locs[token_index].start;
2779 return self.fail(scope, src, format, args);
2780}
2781
2782pub fn failNode(
2783 self: *Module,
2784 scope: *Scope,
2785 ast_node: *ast.Node,
2786 comptime format: []const u8,
2787 args: anytype,
2788) InnerError {
2789 @setCold(true);
2790 const src = scope.tree().token_locs[ast_node.firstToken()].start;
2791 return self.fail(scope, src, format, args);
2792}
2793
2794fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Compilation.ErrorMsg) InnerError {
2795 {
2796 errdefer err_msg.destroy(self.gpa);
2797 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
2798 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
2799 }
2800 switch (scope.tag) {
2801 .decl => {
2802 const decl = scope.cast(Scope.DeclAnalysis).?.decl;
2803 decl.analysis = .sema_failure;
2804 decl.generation = self.generation;
2805 self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);
2806 },
2807 .block => {
2808 const block = scope.cast(Scope.Block).?;
2809 if (block.func) |func| {
2810 func.analysis = .sema_failure;
2811 } else {
2812 block.decl.analysis = .sema_failure;
2813 block.decl.generation = self.generation;
2814 }
2815 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
2816 },
2817 .gen_zir => {
2818 const gen_zir = scope.cast(Scope.GenZIR).?;
2819 gen_zir.decl.analysis = .sema_failure;
2820 gen_zir.decl.generation = self.generation;
2821 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
2822 },
2823 .local_val => {
2824 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
2825 gen_zir.decl.analysis = .sema_failure;
2826 gen_zir.decl.generation = self.generation;
2827 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
2828 },
2829 .local_ptr => {
2830 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
2831 gen_zir.decl.analysis = .sema_failure;
2832 gen_zir.decl.generation = self.generation;
2833 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
2834 },
2835 .zir_module => {
2836 const zir_module = scope.cast(Scope.ZIRModule).?;
2837 zir_module.status = .loaded_sema_failure;
2838 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
2839 },
2840 .file => unreachable,
2841 .container => unreachable,
2842 }
2843 return error.AnalysisFail;
2844}
2845
2846const InMemoryCoercionResult = enum {
2847 ok,
2848 no_match,
2849};
2850
2851fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
2852 if (dest_type.eql(src_type))
2853 return .ok;
2854
2855 // TODO: implement more of this function
2856
2857 return .no_match;
2858}
2859
2860fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {
2861 return @bitCast(u128, a) == @bitCast(u128, b);
2862}
2863
2864pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
2865 // TODO is this a performance issue? maybe we should try the operation without
2866 // resorting to BigInt first.
2867 var lhs_space: Value.BigIntSpace = undefined;
2868 var rhs_space: Value.BigIntSpace = undefined;
2869 const lhs_bigint = lhs.toBigInt(&lhs_space);
2870 const rhs_bigint = rhs.toBigInt(&rhs_space);
2871 const limbs = try allocator.alloc(
2872 std.math.big.Limb,
2873 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
2874 );
2875 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2876 result_bigint.add(lhs_bigint, rhs_bigint);
2877 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2878
2879 const val_payload = if (result_bigint.positive) blk: {
2880 const val_payload = try allocator.create(Value.Payload.IntBigPositive);
2881 val_payload.* = .{ .limbs = result_limbs };
2882 break :blk &val_payload.base;
2883 } else blk: {
2884 const val_payload = try allocator.create(Value.Payload.IntBigNegative);
2885 val_payload.* = .{ .limbs = result_limbs };
2886 break :blk &val_payload.base;
2887 };
2888
2889 return Value.initPayload(val_payload);
2890}
2891
2892pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
2893 // TODO is this a performance issue? maybe we should try the operation without
2894 // resorting to BigInt first.
2895 var lhs_space: Value.BigIntSpace = undefined;
2896 var rhs_space: Value.BigIntSpace = undefined;
2897 const lhs_bigint = lhs.toBigInt(&lhs_space);
2898 const rhs_bigint = rhs.toBigInt(&rhs_space);
2899 const limbs = try allocator.alloc(
2900 std.math.big.Limb,
2901 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
2902 );
2903 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2904 result_bigint.sub(lhs_bigint, rhs_bigint);
2905 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2906
2907 const val_payload = if (result_bigint.positive) blk: {
2908 const val_payload = try allocator.create(Value.Payload.IntBigPositive);
2909 val_payload.* = .{ .limbs = result_limbs };
2910 break :blk &val_payload.base;
2911 } else blk: {
2912 const val_payload = try allocator.create(Value.Payload.IntBigNegative);
2913 val_payload.* = .{ .limbs = result_limbs };
2914 break :blk &val_payload.base;
2915 };
2916
2917 return Value.initPayload(val_payload);
2918}
2919
2920pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
2921 var bit_count = switch (float_type.tag()) {
2922 .comptime_float => 128,
2923 else => float_type.floatBits(self.getTarget()),
2924 };
2925
2926 const allocator = scope.arena();
2927 const val_payload = switch (bit_count) {
2928 16 => {
2929 return self.fail(scope, src, "TODO Implement addition for soft floats", .{});
2930 },
2931 32 => blk: {
2932 const lhs_val = lhs.toFloat(f32);
2933 const rhs_val = rhs.toFloat(f32);
2934 const val_payload = try allocator.create(Value.Payload.Float_32);
2935 val_payload.* = .{ .val = lhs_val + rhs_val };
2936 break :blk &val_payload.base;
2937 },
2938 64 => blk: {
2939 const lhs_val = lhs.toFloat(f64);
2940 const rhs_val = rhs.toFloat(f64);
2941 const val_payload = try allocator.create(Value.Payload.Float_64);
2942 val_payload.* = .{ .val = lhs_val + rhs_val };
2943 break :blk &val_payload.base;
2944 },
2945 128 => {
2946 return self.fail(scope, src, "TODO Implement addition for big floats", .{});
2947 },
2948 else => unreachable,
2949 };
2950
2951 return Value.initPayload(val_payload);
2952}
2953
2954pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
2955 var bit_count = switch (float_type.tag()) {
2956 .comptime_float => 128,
2957 else => float_type.floatBits(self.getTarget()),
2958 };
2959
2960 const allocator = scope.arena();
2961 const val_payload = switch (bit_count) {
2962 16 => {
2963 return self.fail(scope, src, "TODO Implement substraction for soft floats", .{});
2964 },
2965 32 => blk: {
2966 const lhs_val = lhs.toFloat(f32);
2967 const rhs_val = rhs.toFloat(f32);
2968 const val_payload = try allocator.create(Value.Payload.Float_32);
2969 val_payload.* = .{ .val = lhs_val - rhs_val };
2970 break :blk &val_payload.base;
2971 },
2972 64 => blk: {
2973 const lhs_val = lhs.toFloat(f64);
2974 const rhs_val = rhs.toFloat(f64);
2975 const val_payload = try allocator.create(Value.Payload.Float_64);
2976 val_payload.* = .{ .val = lhs_val - rhs_val };
2977 break :blk &val_payload.base;
2978 },
2979 128 => {
2980 return self.fail(scope, src, "TODO Implement substraction for big floats", .{});
2981 },
2982 else => unreachable,
2983 };
2984
2985 return Value.initPayload(val_payload);
2986}
2987
2988pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {
2989 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
2990 return Type.initTag(.const_slice_u8);
2991 }
2992 // TODO stage1 type inference bug
2993 const T = Type.Tag;
2994
2995 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
2996 type_payload.* = .{
2997 .base = .{
2998 .tag = switch (size) {
2999 .One => if (mutable) T.single_mut_pointer else T.single_const_pointer,
3000 .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer,
3001 .C => if (mutable) T.c_mut_pointer else T.c_const_pointer,
3002 .Slice => if (mutable) T.mut_slice else T.const_slice,
3003 },
3004 },
3005 .pointee_type = elem_ty,
3006 };
3007 return Type.initPayload(&type_payload.base);
3008}
3009
3010pub fn ptrType(
3011 self: *Module,
3012 scope: *Scope,
3013 src: usize,
3014 elem_ty: Type,
3015 sentinel: ?Value,
3016 @"align": u32,
3017 bit_offset: u16,
3018 host_size: u16,
3019 mutable: bool,
3020 @"allowzero": bool,
3021 @"volatile": bool,
3022 size: std.builtin.TypeInfo.Pointer.Size,
3023) Allocator.Error!Type {
3024 assert(host_size == 0 or bit_offset < host_size * 8);
3025
3026 // TODO check if type can be represented by simplePtrType
3027 const type_payload = try scope.arena().create(Type.Payload.Pointer);
3028 type_payload.* = .{
3029 .pointee_type = elem_ty,
3030 .sentinel = sentinel,
3031 .@"align" = @"align",
3032 .bit_offset = bit_offset,
3033 .host_size = host_size,
3034 .@"allowzero" = @"allowzero",
3035 .mutable = mutable,
3036 .@"volatile" = @"volatile",
3037 .size = size,
3038 };
3039 return Type.initPayload(&type_payload.base);
3040}
3041
3042pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
3043 return Type.initPayload(switch (child_type.tag()) {
3044 .single_const_pointer => blk: {
3045 const payload = try scope.arena().create(Type.Payload.PointerSimple);
3046 payload.* = .{
3047 .base = .{ .tag = .optional_single_const_pointer },
3048 .pointee_type = child_type.elemType(),
3049 };
3050 break :blk &payload.base;
3051 },
3052 .single_mut_pointer => blk: {
3053 const payload = try scope.arena().create(Type.Payload.PointerSimple);
3054 payload.* = .{
3055 .base = .{ .tag = .optional_single_mut_pointer },
3056 .pointee_type = child_type.elemType(),
3057 };
3058 break :blk &payload.base;
3059 },
3060 else => blk: {
3061 const payload = try scope.arena().create(Type.Payload.Optional);
3062 payload.* = .{
3063 .child_type = child_type,
3064 };
3065 break :blk &payload.base;
3066 },
3067 });
3068}
3069
3070pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type {
3071 if (elem_type.eql(Type.initTag(.u8))) {
3072 if (sentinel) |some| {
3073 if (some.eql(Value.initTag(.zero))) {
3074 const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
3075 payload.* = .{
3076 .len = len,
3077 };
3078 return Type.initPayload(&payload.base);
3079 }
3080 } else {
3081 const payload = try scope.arena().create(Type.Payload.Array_u8);
3082 payload.* = .{
3083 .len = len,
3084 };
3085 return Type.initPayload(&payload.base);
3086 }
3087 }
3088
3089 if (sentinel) |some| {
3090 const payload = try scope.arena().create(Type.Payload.ArraySentinel);
3091 payload.* = .{
3092 .len = len,
3093 .sentinel = some,
3094 .elem_type = elem_type,
3095 };
3096 return Type.initPayload(&payload.base);
3097 }
3098
3099 const payload = try scope.arena().create(Type.Payload.Array);
3100 payload.* = .{
3101 .len = len,
3102 .elem_type = elem_type,
3103 };
3104 return Type.initPayload(&payload.base);
3105}
3106
3107pub fn errorUnionType(self: *Module, scope: *Scope, error_set: Type, payload: Type) Allocator.Error!Type {
3108 assert(error_set.zigTypeTag() == .ErrorSet);
3109 if (error_set.eql(Type.initTag(.anyerror)) and payload.eql(Type.initTag(.void))) {
3110 return Type.initTag(.anyerror_void_error_union);
3111 }
3112
3113 const result = try scope.arena().create(Type.Payload.ErrorUnion);
3114 result.* = .{
3115 .error_set = error_set,
3116 .payload = payload,
3117 };
3118 return Type.initPayload(&result.base);
3119}
3120
3121pub fn anyframeType(self: *Module, scope: *Scope, return_type: Type) Allocator.Error!Type {
3122 const result = try scope.arena().create(Type.Payload.AnyFrame);
3123 result.* = .{
3124 .return_type = return_type,
3125 };
3126 return Type.initPayload(&result.base);
3127}
3128
3129pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
3130 const zir_module = scope.namespace();
3131 const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
3132 const loc = std.zig.findLineColumn(source, inst.src);
3133 if (inst.tag == .constant) {
3134 std.debug.print("constant ty={} val={} src={}:{}:{}\n", .{
3135 inst.ty,
3136 inst.castTag(.constant).?.val,
3137 zir_module.subFilePath(),
3138 loc.line + 1,
3139 loc.column + 1,
3140 });
3141 } else if (inst.deaths == 0) {
3142 std.debug.print("{} ty={} src={}:{}:{}\n", .{
3143 @tagName(inst.tag),
3144 inst.ty,
3145 zir_module.subFilePath(),
3146 loc.line + 1,
3147 loc.column + 1,
3148 });
3149 } else {
3150 std.debug.print("{} ty={} deaths={b} src={}:{}:{}\n", .{
3151 @tagName(inst.tag),
3152 inst.ty,
3153 inst.deaths,
3154 zir_module.subFilePath(),
3155 loc.line + 1,
3156 loc.column + 1,
3157 });
3158 }
3159}
3160
3161pub const PanicId = enum {
3162 unreach,
3163 unwrap_null,
3164};
3165
3166pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {
3167 const block_inst = try parent_block.arena.create(Inst.Block);
3168 block_inst.* = .{
3169 .base = .{
3170 .tag = Inst.Block.base_tag,
3171 .ty = Type.initTag(.void),
3172 .src = ok.src,
3173 },
3174 .body = .{
3175 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the condbr.
3176 },
3177 };
3178
3179 const ok_body: ir.Body = .{
3180 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the brvoid.
3181 };
3182 const brvoid = try parent_block.arena.create(Inst.BrVoid);
3183 brvoid.* = .{
3184 .base = .{
3185 .tag = .brvoid,
3186 .ty = Type.initTag(.noreturn),
3187 .src = ok.src,
3188 },
3189 .block = block_inst,
3190 };
3191 ok_body.instructions[0] = &brvoid.base;
3192
3193 var fail_block: Scope.Block = .{
3194 .parent = parent_block,
3195 .func = parent_block.func,
3196 .decl = parent_block.decl,
3197 .instructions = .{},
3198 .arena = parent_block.arena,
3199 .is_comptime = parent_block.is_comptime,
3200 };
3201 defer fail_block.instructions.deinit(mod.gpa);
3202
3203 _ = try mod.safetyPanic(&fail_block, ok.src, panic_id);
3204
3205 const fail_body: ir.Body = .{ .instructions = try parent_block.arena.dupe(*Inst, fail_block.instructions.items) };
3206
3207 const condbr = try parent_block.arena.create(Inst.CondBr);
3208 condbr.* = .{
3209 .base = .{
3210 .tag = .condbr,
3211 .ty = Type.initTag(.noreturn),
3212 .src = ok.src,
3213 },
3214 .condition = ok,
3215 .then_body = ok_body,
3216 .else_body = fail_body,
3217 };
3218 block_inst.body.instructions[0] = &condbr.base;
3219
3220 try parent_block.instructions.append(mod.gpa, &block_inst.base);
3221}
3222
3223pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: PanicId) !*Inst {
3224 // TODO Once we have a panic function to call, call it here instead of breakpoint.
3225 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);
3226 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);
3227}
3228
3229pub fn getTarget(self: Module) Target {
3230 return self.comp.bin_file.options.target;
3231}
3232
3233pub fn optimizeMode(self: Module) std.builtin.Mode {
3234 return self.comp.bin_file.options.optimize_mode;
3235}
src-self-hosted/ZigModule.zig deleted-3236
......@@ -1,3236 +0,0 @@
1//! TODO This is going to get renamed from ZigModule to Module
2const Module = @This();
3const std = @import("std");
4const Compilation = @import("Compilation.zig");
5const mem = std.mem;
6const Allocator = std.mem.Allocator;
7const ArrayListUnmanaged = std.ArrayListUnmanaged;
8const Value = @import("value.zig").Value;
9const Type = @import("type.zig").Type;
10const TypedValue = @import("TypedValue.zig");
11const assert = std.debug.assert;
12const log = std.log.scoped(.module);
13const BigIntConst = std.math.big.int.Const;
14const BigIntMutable = std.math.big.int.Mutable;
15const Target = std.Target;
16const Package = @import("Package.zig");
17const link = @import("link.zig");
18const ir = @import("ir.zig");
19const zir = @import("zir.zig");
20const Inst = ir.Inst;
21const Body = ir.Body;
22const ast = std.zig.ast;
23const trace = @import("tracy.zig").trace;
24const astgen = @import("astgen.zig");
25const zir_sema = @import("zir_sema.zig");
26
27/// General-purpose allocator. Used for both temporary and long-term storage.
28gpa: *Allocator,
29comp: *Compilation,
30
31/// Where our incremental compilation metadata serialization will go.
32zig_cache_artifact_directory: Compilation.Directory,
33/// Pointer to externally managed resource. `null` if there is no zig file being compiled.
34root_pkg: *Package,
35/// Module owns this resource.
36/// The `Scope` is either a `Scope.ZIRModule` or `Scope.File`.
37root_scope: *Scope,
38/// It's rare for a decl to be exported, so we save memory by having a sparse map of
39/// Decl pointers to details about them being exported.
40/// The Export memory is owned by the `export_owners` table; the slice itself is owned by this table.
41decl_exports: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
42/// We track which export is associated with the given symbol name for quick
43/// detection of symbol collisions.
44symbol_exports: std.StringArrayHashMapUnmanaged(*Export) = .{},
45/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
46/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
47/// is performing the export of another Decl.
48/// This table owns the Export memory.
49export_owners: std.AutoArrayHashMapUnmanaged(*Decl, []*Export) = .{},
50/// Maps fully qualified namespaced names to the Decl struct for them.
51decl_table: std.ArrayHashMapUnmanaged(Scope.NameHash, *Decl, Scope.name_hash_hash, Scope.name_hash_eql, false) = .{},
52/// We optimize memory usage for a compilation with no compile errors by storing the
53/// error messages and mapping outside of `Decl`.
54/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
55/// Note that a Decl can succeed but the Fn it represents can fail. In this case,
56/// a Decl can have a failed_decls entry but have analysis status of success.
57failed_decls: std.AutoArrayHashMapUnmanaged(*Decl, *Compilation.ErrorMsg) = .{},
58/// Using a map here for consistency with the other fields here.
59/// The ErrorMsg memory is owned by the `Scope`, using Module's general purpose allocator.
60failed_files: std.AutoArrayHashMapUnmanaged(*Scope, *Compilation.ErrorMsg) = .{},
61/// Using a map here for consistency with the other fields here.
62/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
63failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *Compilation.ErrorMsg) = .{},
64
65next_anon_name_index: usize = 0,
66
67/// Candidates for deletion. After a semantic analysis update completes, this list
68/// contains Decls that need to be deleted if they end up having no references to them.
69deletion_set: ArrayListUnmanaged(*Decl) = .{},
70
71/// Error tags and their values, tag names are duped with mod.gpa.
72global_error_set: std.StringHashMapUnmanaged(u16) = .{},
73
74/// Incrementing integer used to compare against the corresponding Decl
75/// field to determine whether a Decl's status applies to an ongoing update, or a
76/// previous analysis.
77generation: u32 = 0,
78
79pub const Export = struct {
80 options: std.builtin.ExportOptions,
81 /// Byte offset into the file that contains the export directive.
82 src: usize,
83 /// Represents the position of the export, if any, in the output file.
84 link: link.File.Elf.Export,
85 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
86 owner_decl: *Decl,
87 /// The Decl being exported. Note this is *not* the Decl performing the export.
88 exported_decl: *Decl,
89 status: enum {
90 in_progress,
91 failed,
92 /// Indicates that the failure was due to a temporary issue, such as an I/O error
93 /// when writing to the output file. Retrying the export may succeed.
94 failed_retryable,
95 complete,
96 },
97};
98
99pub const Decl = struct {
100 /// This name is relative to the containing namespace of the decl. It uses a null-termination
101 /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed
102 /// in symbol names, because executable file formats use null-terminated strings for symbol names.
103 /// All Decls have names, even values that are not bound to a zig namespace. This is necessary for
104 /// mapping them to an address in the output file.
105 /// Memory owned by this decl, using Module's allocator.
106 name: [*:0]const u8,
107 /// The direct parent container of the Decl. This is either a `Scope.Container` or `Scope.ZIRModule`.
108 /// Reference to externally owned memory.
109 scope: *Scope,
110 /// The AST Node decl index or ZIR Inst index that contains this declaration.
111 /// Must be recomputed when the corresponding source file is modified.
112 src_index: usize,
113 /// The most recent value of the Decl after a successful semantic analysis.
114 typed_value: union(enum) {
115 never_succeeded: void,
116 most_recent: TypedValue.Managed,
117 },
118 /// Represents the "shallow" analysis status. For example, for decls that are functions,
119 /// the function type is analyzed with this set to `in_progress`, however, the semantic
120 /// analysis of the function body is performed with this value set to `success`. Functions
121 /// have their own analysis status field.
122 analysis: enum {
123 /// This Decl corresponds to an AST Node that has not been referenced yet, and therefore
124 /// because of Zig's lazy declaration analysis, it will remain unanalyzed until referenced.
125 unreferenced,
126 /// Semantic analysis for this Decl is running right now. This state detects dependency loops.
127 in_progress,
128 /// This Decl might be OK but it depends on another one which did not successfully complete
129 /// semantic analysis.
130 dependency_failure,
131 /// Semantic analysis failure.
132 /// There will be a corresponding ErrorMsg in Module.failed_decls.
133 sema_failure,
134 /// There will be a corresponding ErrorMsg in Module.failed_decls.
135 /// This indicates the failure was something like running out of disk space,
136 /// and attempting semantic analysis again may succeed.
137 sema_failure_retryable,
138 /// There will be a corresponding ErrorMsg in Module.failed_decls.
139 codegen_failure,
140 /// There will be a corresponding ErrorMsg in Module.failed_decls.
141 /// This indicates the failure was something like running out of disk space,
142 /// and attempting codegen again may succeed.
143 codegen_failure_retryable,
144 /// Everything is done. During an update, this Decl may be out of date, depending
145 /// on its dependencies. The `generation` field can be used to determine if this
146 /// completion status occurred before or after a given update.
147 complete,
148 /// A Module update is in progress, and this Decl has been flagged as being known
149 /// to require re-analysis.
150 outdated,
151 },
152 /// This flag is set when this Decl is added to a check_for_deletion set, and cleared
153 /// when removed.
154 deletion_flag: bool,
155 /// Whether the corresponding AST decl has a `pub` keyword.
156 is_pub: bool,
157
158 /// An integer that can be checked against the corresponding incrementing
159 /// generation field of Module. This is used to determine whether `complete` status
160 /// represents pre- or post- re-analysis.
161 generation: u32,
162
163 /// Represents the position of the code in the output file.
164 /// This is populated regardless of semantic analysis and code generation.
165 link: link.File.LinkBlock,
166
167 /// Represents the function in the linked output file, if the `Decl` is a function.
168 /// This is stored here and not in `Fn` because `Decl` survives across updates but
169 /// `Fn` does not.
170 /// TODO Look into making `Fn` a longer lived structure and moving this field there
171 /// to save on memory usage.
172 fn_link: link.File.LinkFn,
173
174 contents_hash: std.zig.SrcHash,
175
176 /// The shallow set of other decls whose typed_value could possibly change if this Decl's
177 /// typed_value is modified.
178 dependants: DepsTable = .{},
179 /// The shallow set of other decls whose typed_value changing indicates that this Decl's
180 /// typed_value may need to be regenerated.
181 dependencies: DepsTable = .{},
182
183 /// The reason this is not `std.AutoArrayHashMapUnmanaged` is a workaround for
184 /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself`
185 pub const DepsTable = std.ArrayHashMapUnmanaged(*Decl, void, std.array_hash_map.getAutoHashFn(*Decl), std.array_hash_map.getAutoEqlFn(*Decl), false);
186
187 pub fn destroy(self: *Decl, gpa: *Allocator) void {
188 gpa.free(mem.spanZ(self.name));
189 if (self.typedValueManaged()) |tvm| {
190 tvm.deinit(gpa);
191 }
192 self.dependants.deinit(gpa);
193 self.dependencies.deinit(gpa);
194 gpa.destroy(self);
195 }
196
197 pub fn src(self: Decl) usize {
198 switch (self.scope.tag) {
199 .container => {
200 const container = @fieldParentPtr(Scope.Container, "base", self.scope);
201 const tree = container.file_scope.contents.tree;
202 // TODO Container should have it's own decls()
203 const decl_node = tree.root_node.decls()[self.src_index];
204 return tree.token_locs[decl_node.firstToken()].start;
205 },
206 .zir_module => {
207 const zir_module = @fieldParentPtr(Scope.ZIRModule, "base", self.scope);
208 const module = zir_module.contents.module;
209 const src_decl = module.decls[self.src_index];
210 return src_decl.inst.src;
211 },
212 .file, .block => unreachable,
213 .gen_zir => unreachable,
214 .local_val => unreachable,
215 .local_ptr => unreachable,
216 .decl => unreachable,
217 }
218 }
219
220 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
221 return self.scope.fullyQualifiedNameHash(mem.spanZ(self.name));
222 }
223
224 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
225 const tvm = self.typedValueManaged() orelse return error.AnalysisFail;
226 return tvm.typed_value;
227 }
228
229 pub fn value(self: *Decl) error{AnalysisFail}!Value {
230 return (try self.typedValue()).val;
231 }
232
233 pub fn dump(self: *Decl) void {
234 const loc = std.zig.findLineColumn(self.scope.source.bytes, self.src);
235 std.debug.print("{}:{}:{} name={} status={}", .{
236 self.scope.sub_file_path,
237 loc.line + 1,
238 loc.column + 1,
239 mem.spanZ(self.name),
240 @tagName(self.analysis),
241 });
242 if (self.typedValueManaged()) |tvm| {
243 std.debug.print(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });
244 }
245 std.debug.print("\n", .{});
246 }
247
248 pub fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {
249 switch (self.typed_value) {
250 .most_recent => |*x| return x,
251 .never_succeeded => return null,
252 }
253 }
254
255 fn removeDependant(self: *Decl, other: *Decl) void {
256 self.dependants.removeAssertDiscard(other);
257 }
258
259 fn removeDependency(self: *Decl, other: *Decl) void {
260 self.dependencies.removeAssertDiscard(other);
261 }
262};
263
264/// Fn struct memory is owned by the Decl's TypedValue.Managed arena allocator.
265pub const Fn = struct {
266 /// This memory owned by the Decl's TypedValue.Managed arena allocator.
267 analysis: union(enum) {
268 queued: *ZIR,
269 in_progress,
270 /// There will be a corresponding ErrorMsg in Module.failed_decls
271 sema_failure,
272 /// This Fn might be OK but it depends on another Decl which did not successfully complete
273 /// semantic analysis.
274 dependency_failure,
275 success: Body,
276 },
277 owner_decl: *Decl,
278
279 /// This memory is temporary and points to stack memory for the duration
280 /// of Fn analysis.
281 pub const Analysis = struct {
282 inner_block: Scope.Block,
283 };
284
285 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
286 pub const ZIR = struct {
287 body: zir.Module.Body,
288 arena: std.heap.ArenaAllocator.State,
289 };
290
291 /// For debugging purposes.
292 pub fn dump(self: *Fn, mod: Module) void {
293 std.debug.print("Module.Function(name={}) ", .{self.owner_decl.name});
294 switch (self.analysis) {
295 .queued => {
296 std.debug.print("queued\n", .{});
297 },
298 .in_progress => {
299 std.debug.print("in_progress\n", .{});
300 },
301 else => {
302 std.debug.print("\n", .{});
303 zir.dumpFn(mod, self);
304 },
305 }
306 }
307};
308
309pub const Var = struct {
310 /// if is_extern == true this is undefined
311 init: Value,
312 owner_decl: *Decl,
313
314 is_extern: bool,
315 is_mutable: bool,
316 is_threadlocal: bool,
317};
318
319pub const Scope = struct {
320 tag: Tag,
321
322 pub const NameHash = [16]u8;
323
324 pub fn cast(base: *Scope, comptime T: type) ?*T {
325 if (base.tag != T.base_tag)
326 return null;
327
328 return @fieldParentPtr(T, "base", base);
329 }
330
331 /// Asserts the scope has a parent which is a DeclAnalysis and
332 /// returns the arena Allocator.
333 pub fn arena(self: *Scope) *Allocator {
334 switch (self.tag) {
335 .block => return self.cast(Block).?.arena,
336 .decl => return &self.cast(DeclAnalysis).?.arena.allocator,
337 .gen_zir => return self.cast(GenZIR).?.arena,
338 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
339 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
340 .zir_module => return &self.cast(ZIRModule).?.contents.module.arena.allocator,
341 .file => unreachable,
342 .container => unreachable,
343 }
344 }
345
346 /// If the scope has a parent which is a `DeclAnalysis`,
347 /// returns the `Decl`, otherwise returns `null`.
348 pub fn decl(self: *Scope) ?*Decl {
349 return switch (self.tag) {
350 .block => self.cast(Block).?.decl,
351 .gen_zir => self.cast(GenZIR).?.decl,
352 .local_val => self.cast(LocalVal).?.gen_zir.decl,
353 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
354 .decl => self.cast(DeclAnalysis).?.decl,
355 .zir_module => null,
356 .file => null,
357 .container => null,
358 };
359 }
360
361 /// Asserts the scope has a parent which is a ZIRModule or Container and
362 /// returns it.
363 pub fn namespace(self: *Scope) *Scope {
364 switch (self.tag) {
365 .block => return self.cast(Block).?.decl.scope,
366 .gen_zir => return self.cast(GenZIR).?.decl.scope,
367 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope,
368 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope,
369 .decl => return self.cast(DeclAnalysis).?.decl.scope,
370 .file => return &self.cast(File).?.root_container.base,
371 .zir_module, .container => return self,
372 }
373 }
374
375 /// Must generate unique bytes with no collisions with other decls.
376 /// The point of hashing here is only to limit the number of bytes of
377 /// the unique identifier to a fixed size (16 bytes).
378 pub fn fullyQualifiedNameHash(self: *Scope, name: []const u8) NameHash {
379 switch (self.tag) {
380 .block => unreachable,
381 .gen_zir => unreachable,
382 .local_val => unreachable,
383 .local_ptr => unreachable,
384 .decl => unreachable,
385 .file => unreachable,
386 .zir_module => return self.cast(ZIRModule).?.fullyQualifiedNameHash(name),
387 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
388 }
389 }
390
391 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
392 pub fn tree(self: *Scope) *ast.Tree {
393 switch (self.tag) {
394 .file => return self.cast(File).?.contents.tree,
395 .zir_module => unreachable,
396 .decl => return self.cast(DeclAnalysis).?.decl.scope.cast(Container).?.file_scope.contents.tree,
397 .block => return self.cast(Block).?.decl.scope.cast(Container).?.file_scope.contents.tree,
398 .gen_zir => return self.cast(GenZIR).?.decl.scope.cast(Container).?.file_scope.contents.tree,
399 .local_val => return self.cast(LocalVal).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
400 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.scope.cast(Container).?.file_scope.contents.tree,
401 .container => return self.cast(Container).?.file_scope.contents.tree,
402 }
403 }
404
405 /// Asserts the scope is a child of a `GenZIR` and returns it.
406 pub fn getGenZIR(self: *Scope) *GenZIR {
407 return switch (self.tag) {
408 .block => unreachable,
409 .gen_zir => self.cast(GenZIR).?,
410 .local_val => return self.cast(LocalVal).?.gen_zir,
411 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
412 .decl => unreachable,
413 .zir_module => unreachable,
414 .file => unreachable,
415 .container => unreachable,
416 };
417 }
418
419 /// Asserts the scope has a parent which is a ZIRModule, Contaienr or File and
420 /// returns the sub_file_path field.
421 pub fn subFilePath(base: *Scope) []const u8 {
422 switch (base.tag) {
423 .container => return @fieldParentPtr(Container, "base", base).file_scope.sub_file_path,
424 .file => return @fieldParentPtr(File, "base", base).sub_file_path,
425 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).sub_file_path,
426 .block => unreachable,
427 .gen_zir => unreachable,
428 .local_val => unreachable,
429 .local_ptr => unreachable,
430 .decl => unreachable,
431 }
432 }
433
434 pub fn unload(base: *Scope, gpa: *Allocator) void {
435 switch (base.tag) {
436 .file => return @fieldParentPtr(File, "base", base).unload(gpa),
437 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).unload(gpa),
438 .block => unreachable,
439 .gen_zir => unreachable,
440 .local_val => unreachable,
441 .local_ptr => unreachable,
442 .decl => unreachable,
443 .container => unreachable,
444 }
445 }
446
447 pub fn getSource(base: *Scope, module: *Module) ![:0]const u8 {
448 switch (base.tag) {
449 .container => return @fieldParentPtr(Container, "base", base).file_scope.getSource(module),
450 .file => return @fieldParentPtr(File, "base", base).getSource(module),
451 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).getSource(module),
452 .gen_zir => unreachable,
453 .local_val => unreachable,
454 .local_ptr => unreachable,
455 .block => unreachable,
456 .decl => unreachable,
457 }
458 }
459
460 /// Asserts the scope is a namespace Scope and removes the Decl from the namespace.
461 pub fn removeDecl(base: *Scope, child: *Decl) void {
462 switch (base.tag) {
463 .container => return @fieldParentPtr(Container, "base", base).removeDecl(child),
464 .zir_module => return @fieldParentPtr(ZIRModule, "base", base).removeDecl(child),
465 .file => unreachable,
466 .block => unreachable,
467 .gen_zir => unreachable,
468 .local_val => unreachable,
469 .local_ptr => unreachable,
470 .decl => unreachable,
471 }
472 }
473
474 /// Asserts the scope is a File or ZIRModule and deinitializes it, then deallocates it.
475 pub fn destroy(base: *Scope, gpa: *Allocator) void {
476 switch (base.tag) {
477 .file => {
478 const scope_file = @fieldParentPtr(File, "base", base);
479 scope_file.deinit(gpa);
480 gpa.destroy(scope_file);
481 },
482 .zir_module => {
483 const scope_zir_module = @fieldParentPtr(ZIRModule, "base", base);
484 scope_zir_module.deinit(gpa);
485 gpa.destroy(scope_zir_module);
486 },
487 .block => unreachable,
488 .gen_zir => unreachable,
489 .local_val => unreachable,
490 .local_ptr => unreachable,
491 .decl => unreachable,
492 .container => unreachable,
493 }
494 }
495
496 fn name_hash_hash(x: NameHash) u32 {
497 return @truncate(u32, @bitCast(u128, x));
498 }
499
500 fn name_hash_eql(a: NameHash, b: NameHash) bool {
501 return @bitCast(u128, a) == @bitCast(u128, b);
502 }
503
504 pub const Tag = enum {
505 /// .zir source code.
506 zir_module,
507 /// .zig source code.
508 file,
509 /// struct, enum or union, every .file contains one of these.
510 container,
511 block,
512 decl,
513 gen_zir,
514 local_val,
515 local_ptr,
516 };
517
518 pub const Container = struct {
519 pub const base_tag: Tag = .container;
520 base: Scope = Scope{ .tag = base_tag },
521
522 file_scope: *Scope.File,
523
524 /// Direct children of the file.
525 decls: std.AutoArrayHashMapUnmanaged(*Decl, void),
526
527 // TODO implement container types and put this in a status union
528 // ty: Type
529
530 pub fn deinit(self: *Container, gpa: *Allocator) void {
531 self.decls.deinit(gpa);
532 self.* = undefined;
533 }
534
535 pub fn removeDecl(self: *Container, child: *Decl) void {
536 _ = self.decls.remove(child);
537 }
538
539 pub fn fullyQualifiedNameHash(self: *Container, name: []const u8) NameHash {
540 // TODO container scope qualified names.
541 return std.zig.hashSrc(name);
542 }
543 };
544
545 pub const File = struct {
546 pub const base_tag: Tag = .file;
547 base: Scope = Scope{ .tag = base_tag },
548
549 /// Relative to the owning package's root_src_dir.
550 /// Reference to external memory, not owned by File.
551 sub_file_path: []const u8,
552 source: union(enum) {
553 unloaded: void,
554 bytes: [:0]const u8,
555 },
556 contents: union {
557 not_available: void,
558 tree: *ast.Tree,
559 },
560 status: enum {
561 never_loaded,
562 unloaded_success,
563 unloaded_parse_failure,
564 loaded_success,
565 },
566
567 root_container: Container,
568
569 pub fn unload(self: *File, gpa: *Allocator) void {
570 switch (self.status) {
571 .never_loaded,
572 .unloaded_parse_failure,
573 .unloaded_success,
574 => {},
575
576 .loaded_success => {
577 self.contents.tree.deinit();
578 self.status = .unloaded_success;
579 },
580 }
581 switch (self.source) {
582 .bytes => |bytes| {
583 gpa.free(bytes);
584 self.source = .{ .unloaded = {} };
585 },
586 .unloaded => {},
587 }
588 }
589
590 pub fn deinit(self: *File, gpa: *Allocator) void {
591 self.root_container.deinit(gpa);
592 self.unload(gpa);
593 self.* = undefined;
594 }
595
596 pub fn dumpSrc(self: *File, src: usize) void {
597 const loc = std.zig.findLineColumn(self.source.bytes, src);
598 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
599 }
600
601 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
602 switch (self.source) {
603 .unloaded => {
604 const source = try module.root_pkg.root_src_directory.handle.readFileAllocOptions(
605 module.gpa,
606 self.sub_file_path,
607 std.math.maxInt(u32),
608 null,
609 1,
610 0,
611 );
612 self.source = .{ .bytes = source };
613 return source;
614 },
615 .bytes => |bytes| return bytes,
616 }
617 }
618 };
619
620 pub const ZIRModule = struct {
621 pub const base_tag: Tag = .zir_module;
622 base: Scope = Scope{ .tag = base_tag },
623 /// Relative to the owning package's root_src_dir.
624 /// Reference to external memory, not owned by ZIRModule.
625 sub_file_path: []const u8,
626 source: union(enum) {
627 unloaded: void,
628 bytes: [:0]const u8,
629 },
630 contents: union {
631 not_available: void,
632 module: *zir.Module,
633 },
634 status: enum {
635 never_loaded,
636 unloaded_success,
637 unloaded_parse_failure,
638 unloaded_sema_failure,
639
640 loaded_sema_failure,
641 loaded_success,
642 },
643
644 /// Even though .zir files only have 1 module, this set is still needed
645 /// because of anonymous Decls, which can exist in the global set, but
646 /// not this one.
647 decls: ArrayListUnmanaged(*Decl),
648
649 pub fn unload(self: *ZIRModule, gpa: *Allocator) void {
650 switch (self.status) {
651 .never_loaded,
652 .unloaded_parse_failure,
653 .unloaded_sema_failure,
654 .unloaded_success,
655 => {},
656
657 .loaded_success => {
658 self.contents.module.deinit(gpa);
659 gpa.destroy(self.contents.module);
660 self.contents = .{ .not_available = {} };
661 self.status = .unloaded_success;
662 },
663 .loaded_sema_failure => {
664 self.contents.module.deinit(gpa);
665 gpa.destroy(self.contents.module);
666 self.contents = .{ .not_available = {} };
667 self.status = .unloaded_sema_failure;
668 },
669 }
670 switch (self.source) {
671 .bytes => |bytes| {
672 gpa.free(bytes);
673 self.source = .{ .unloaded = {} };
674 },
675 .unloaded => {},
676 }
677 }
678
679 pub fn deinit(self: *ZIRModule, gpa: *Allocator) void {
680 self.decls.deinit(gpa);
681 self.unload(gpa);
682 self.* = undefined;
683 }
684
685 pub fn removeDecl(self: *ZIRModule, child: *Decl) void {
686 for (self.decls.items) |item, i| {
687 if (item == child) {
688 _ = self.decls.swapRemove(i);
689 return;
690 }
691 }
692 }
693
694 pub fn dumpSrc(self: *ZIRModule, src: usize) void {
695 const loc = std.zig.findLineColumn(self.source.bytes, src);
696 std.debug.print("{}:{}:{}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
697 }
698
699 pub fn getSource(self: *ZIRModule, module: *Module) ![:0]const u8 {
700 switch (self.source) {
701 .unloaded => {
702 const source = try module.root_pkg.root_src_directory.handle.readFileAllocOptions(
703 module.gpa,
704 self.sub_file_path,
705 std.math.maxInt(u32),
706 null,
707 1,
708 0,
709 );
710 self.source = .{ .bytes = source };
711 return source;
712 },
713 .bytes => |bytes| return bytes,
714 }
715 }
716
717 pub fn fullyQualifiedNameHash(self: *ZIRModule, name: []const u8) NameHash {
718 // ZIR modules only have 1 file with all decls global in the same namespace.
719 return std.zig.hashSrc(name);
720 }
721 };
722
723 /// This is a temporary structure, references to it are valid only
724 /// during semantic analysis of the block.
725 pub const Block = struct {
726 pub const base_tag: Tag = .block;
727 base: Scope = Scope{ .tag = base_tag },
728 parent: ?*Block,
729 func: ?*Fn,
730 decl: *Decl,
731 instructions: ArrayListUnmanaged(*Inst),
732 /// Points to the arena allocator of DeclAnalysis
733 arena: *Allocator,
734 label: ?Label = null,
735 is_comptime: bool,
736
737 pub const Label = struct {
738 zir_block: *zir.Inst.Block,
739 results: ArrayListUnmanaged(*Inst),
740 block_inst: *Inst.Block,
741 };
742 };
743
744 /// This is a temporary structure, references to it are valid only
745 /// during semantic analysis of the decl.
746 pub const DeclAnalysis = struct {
747 pub const base_tag: Tag = .decl;
748 base: Scope = Scope{ .tag = base_tag },
749 decl: *Decl,
750 arena: std.heap.ArenaAllocator,
751 };
752
753 /// This is a temporary structure, references to it are valid only
754 /// during semantic analysis of the decl.
755 pub const GenZIR = struct {
756 pub const base_tag: Tag = .gen_zir;
757 base: Scope = Scope{ .tag = base_tag },
758 /// Parents can be: `GenZIR`, `ZIRModule`, `File`
759 parent: *Scope,
760 decl: *Decl,
761 arena: *Allocator,
762 /// The first N instructions in a function body ZIR are arg instructions.
763 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
764 label: ?Label = null,
765
766 pub const Label = struct {
767 token: ast.TokenIndex,
768 block_inst: *zir.Inst.Block,
769 result_loc: astgen.ResultLoc,
770 };
771 };
772
773 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
774 /// This structure lives as long as the AST generation of the Block
775 /// node that contains the variable.
776 pub const LocalVal = struct {
777 pub const base_tag: Tag = .local_val;
778 base: Scope = Scope{ .tag = base_tag },
779 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
780 parent: *Scope,
781 gen_zir: *GenZIR,
782 name: []const u8,
783 inst: *zir.Inst,
784 };
785
786 /// This could be a `const` or `var` local. It has a pointer instead of a value.
787 /// This structure lives as long as the AST generation of the Block
788 /// node that contains the variable.
789 pub const LocalPtr = struct {
790 pub const base_tag: Tag = .local_ptr;
791 base: Scope = Scope{ .tag = base_tag },
792 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
793 parent: *Scope,
794 gen_zir: *GenZIR,
795 name: []const u8,
796 ptr: *zir.Inst,
797 };
798};
799
800pub const InnerError = error{ OutOfMemory, AnalysisFail };
801
802pub fn deinit(self: *Module) void {
803 const gpa = self.gpa;
804
805 self.zig_cache_artifact_directory.handle.close();
806
807 self.deletion_set.deinit(gpa);
808
809 for (self.decl_table.items()) |entry| {
810 entry.value.destroy(gpa);
811 }
812 self.decl_table.deinit(gpa);
813
814 for (self.failed_decls.items()) |entry| {
815 entry.value.destroy(gpa);
816 }
817 self.failed_decls.deinit(gpa);
818
819 for (self.failed_files.items()) |entry| {
820 entry.value.destroy(gpa);
821 }
822 self.failed_files.deinit(gpa);
823
824 for (self.failed_exports.items()) |entry| {
825 entry.value.destroy(gpa);
826 }
827 self.failed_exports.deinit(gpa);
828
829 for (self.decl_exports.items()) |entry| {
830 const export_list = entry.value;
831 gpa.free(export_list);
832 }
833 self.decl_exports.deinit(gpa);
834
835 for (self.export_owners.items()) |entry| {
836 freeExportList(gpa, entry.value);
837 }
838 self.export_owners.deinit(gpa);
839
840 self.symbol_exports.deinit(gpa);
841 self.root_scope.destroy(gpa);
842
843 var it = self.global_error_set.iterator();
844 while (it.next()) |entry| {
845 gpa.free(entry.key);
846 }
847 self.global_error_set.deinit(gpa);
848}
849
850fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
851 for (export_list) |exp| {
852 gpa.free(exp.options.name);
853 gpa.destroy(exp);
854 }
855 gpa.free(export_list);
856}
857
858pub fn ensureDeclAnalyzed(self: *Module, decl: *Decl) InnerError!void {
859 const tracy = trace(@src());
860 defer tracy.end();
861
862 const subsequent_analysis = switch (decl.analysis) {
863 .in_progress => unreachable,
864
865 .sema_failure,
866 .sema_failure_retryable,
867 .codegen_failure,
868 .dependency_failure,
869 .codegen_failure_retryable,
870 => return error.AnalysisFail,
871
872 .complete => return,
873
874 .outdated => blk: {
875 log.debug("re-analyzing {}\n", .{decl.name});
876
877 // The exports this Decl performs will be re-discovered, so we remove them here
878 // prior to re-analysis.
879 self.deleteDeclExports(decl);
880 // Dependencies will be re-discovered, so we remove them here prior to re-analysis.
881 for (decl.dependencies.items()) |entry| {
882 const dep = entry.key;
883 dep.removeDependant(decl);
884 if (dep.dependants.items().len == 0 and !dep.deletion_flag) {
885 // We don't perform a deletion here, because this Decl or another one
886 // may end up referencing it before the update is complete.
887 dep.deletion_flag = true;
888 try self.deletion_set.append(self.gpa, dep);
889 }
890 }
891 decl.dependencies.clearRetainingCapacity();
892
893 break :blk true;
894 },
895
896 .unreferenced => false,
897 };
898
899 const type_changed = if (self.root_scope.cast(Scope.ZIRModule)) |zir_module|
900 try zir_sema.analyzeZirDecl(self, decl, zir_module.contents.module.decls[decl.src_index])
901 else
902 self.astGenAndAnalyzeDecl(decl) catch |err| switch (err) {
903 error.OutOfMemory => return error.OutOfMemory,
904 error.AnalysisFail => return error.AnalysisFail,
905 else => {
906 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
907 self.failed_decls.putAssumeCapacityNoClobber(decl, try Compilation.ErrorMsg.create(
908 self.gpa,
909 decl.src(),
910 "unable to analyze: {}",
911 .{@errorName(err)},
912 ));
913 decl.analysis = .sema_failure_retryable;
914 return error.AnalysisFail;
915 },
916 };
917
918 if (subsequent_analysis) {
919 // We may need to chase the dependants and re-analyze them.
920 // However, if the decl is a function, and the type is the same, we do not need to.
921 if (type_changed or decl.typed_value.most_recent.typed_value.val.tag() != .function) {
922 for (decl.dependants.items()) |entry| {
923 const dep = entry.key;
924 switch (dep.analysis) {
925 .unreferenced => unreachable,
926 .in_progress => unreachable,
927 .outdated => continue, // already queued for update
928
929 .dependency_failure,
930 .sema_failure,
931 .sema_failure_retryable,
932 .codegen_failure,
933 .codegen_failure_retryable,
934 .complete,
935 => if (dep.generation != self.generation) {
936 try self.markOutdatedDecl(dep);
937 },
938 }
939 }
940 }
941 }
942}
943
944fn astGenAndAnalyzeDecl(self: *Module, decl: *Decl) !bool {
945 const tracy = trace(@src());
946 defer tracy.end();
947
948 const container_scope = decl.scope.cast(Scope.Container).?;
949 const tree = try self.getAstTree(container_scope);
950 const ast_node = tree.root_node.decls()[decl.src_index];
951 switch (ast_node.tag) {
952 .FnProto => {
953 const fn_proto = @fieldParentPtr(ast.Node.FnProto, "base", ast_node);
954
955 decl.analysis = .in_progress;
956
957 // This arena allocator's memory is discarded at the end of this function. It is used
958 // to determine the type of the function, and hence the type of the decl, which is needed
959 // to complete the Decl analysis.
960 var fn_type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
961 defer fn_type_scope_arena.deinit();
962 var fn_type_scope: Scope.GenZIR = .{
963 .decl = decl,
964 .arena = &fn_type_scope_arena.allocator,
965 .parent = decl.scope,
966 };
967 defer fn_type_scope.instructions.deinit(self.gpa);
968
969 decl.is_pub = fn_proto.getVisibToken() != null;
970 const body_node = fn_proto.getBodyNode() orelse
971 return self.failTok(&fn_type_scope.base, fn_proto.fn_token, "TODO implement extern functions", .{});
972
973 const param_decls = fn_proto.params();
974 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_decls.len);
975
976 const fn_src = tree.token_locs[fn_proto.fn_token].start;
977 const type_type = try astgen.addZIRInstConst(self, &fn_type_scope.base, fn_src, .{
978 .ty = Type.initTag(.type),
979 .val = Value.initTag(.type_type),
980 });
981 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
982 for (param_decls) |param_decl, i| {
983 const param_type_node = switch (param_decl.param_type) {
984 .any_type => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement anytype parameter", .{}),
985 .type_expr => |node| node,
986 };
987 param_types[i] = try astgen.expr(self, &fn_type_scope.base, type_type_rl, param_type_node);
988 }
989 if (fn_proto.getVarArgsToken()) |var_args_token| {
990 return self.failTok(&fn_type_scope.base, var_args_token, "TODO implement var args", .{});
991 }
992 if (fn_proto.getLibName()) |lib_name| {
993 return self.failNode(&fn_type_scope.base, lib_name, "TODO implement function library name", .{});
994 }
995 if (fn_proto.getAlignExpr()) |align_expr| {
996 return self.failNode(&fn_type_scope.base, align_expr, "TODO implement function align expression", .{});
997 }
998 if (fn_proto.getSectionExpr()) |sect_expr| {
999 return self.failNode(&fn_type_scope.base, sect_expr, "TODO implement function section expression", .{});
1000 }
1001 if (fn_proto.getCallconvExpr()) |callconv_expr| {
1002 return self.failNode(
1003 &fn_type_scope.base,
1004 callconv_expr,
1005 "TODO implement function calling convention expression",
1006 .{},
1007 );
1008 }
1009 const return_type_expr = switch (fn_proto.return_type) {
1010 .Explicit => |node| node,
1011 .InferErrorSet => |node| return self.failNode(&fn_type_scope.base, node, "TODO implement inferred error sets", .{}),
1012 .Invalid => |tok| return self.failTok(&fn_type_scope.base, tok, "unable to parse return type", .{}),
1013 };
1014
1015 const return_type_inst = try astgen.expr(self, &fn_type_scope.base, type_type_rl, return_type_expr);
1016 const fn_type_inst = try astgen.addZIRInst(self, &fn_type_scope.base, fn_src, zir.Inst.FnType, .{
1017 .return_type = return_type_inst,
1018 .param_types = param_types,
1019 }, .{});
1020
1021 // We need the memory for the Type to go into the arena for the Decl
1022 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
1023 errdefer decl_arena.deinit();
1024 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1025
1026 var block_scope: Scope.Block = .{
1027 .parent = null,
1028 .func = null,
1029 .decl = decl,
1030 .instructions = .{},
1031 .arena = &decl_arena.allocator,
1032 .is_comptime = false,
1033 };
1034 defer block_scope.instructions.deinit(self.gpa);
1035
1036 const fn_type = try zir_sema.analyzeBodyValueAsType(self, &block_scope, fn_type_inst, .{
1037 .instructions = fn_type_scope.instructions.items,
1038 });
1039 const new_func = try decl_arena.allocator.create(Fn);
1040 const fn_payload = try decl_arena.allocator.create(Value.Payload.Function);
1041
1042 const fn_zir = blk: {
1043 // This scope's arena memory is discarded after the ZIR generation
1044 // pass completes, and semantic analysis of it completes.
1045 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1046 errdefer gen_scope_arena.deinit();
1047 var gen_scope: Scope.GenZIR = .{
1048 .decl = decl,
1049 .arena = &gen_scope_arena.allocator,
1050 .parent = decl.scope,
1051 };
1052 defer gen_scope.instructions.deinit(self.gpa);
1053
1054 // We need an instruction for each parameter, and they must be first in the body.
1055 try gen_scope.instructions.resize(self.gpa, fn_proto.params_len);
1056 var params_scope = &gen_scope.base;
1057 for (fn_proto.params()) |param, i| {
1058 const name_token = param.name_token.?;
1059 const src = tree.token_locs[name_token].start;
1060 const param_name = tree.tokenSlice(name_token); // TODO: call identifierTokenString
1061 const arg = try gen_scope_arena.allocator.create(zir.Inst.Arg);
1062 arg.* = .{
1063 .base = .{
1064 .tag = .arg,
1065 .src = src,
1066 },
1067 .positionals = .{
1068 .name = param_name,
1069 },
1070 .kw_args = .{},
1071 };
1072 gen_scope.instructions.items[i] = &arg.base;
1073 const sub_scope = try gen_scope_arena.allocator.create(Scope.LocalVal);
1074 sub_scope.* = .{
1075 .parent = params_scope,
1076 .gen_zir = &gen_scope,
1077 .name = param_name,
1078 .inst = &arg.base,
1079 };
1080 params_scope = &sub_scope.base;
1081 }
1082
1083 const body_block = body_node.cast(ast.Node.Block).?;
1084
1085 try astgen.blockExpr(self, params_scope, body_block);
1086
1087 if (gen_scope.instructions.items.len == 0 or
1088 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
1089 {
1090 const src = tree.token_locs[body_block.rbrace].start;
1091 _ = try astgen.addZIRNoOp(self, &gen_scope.base, src, .returnvoid);
1092 }
1093
1094 const fn_zir = try gen_scope_arena.allocator.create(Fn.ZIR);
1095 fn_zir.* = .{
1096 .body = .{
1097 .instructions = try gen_scope.arena.dupe(*zir.Inst, gen_scope.instructions.items),
1098 },
1099 .arena = gen_scope_arena.state,
1100 };
1101 break :blk fn_zir;
1102 };
1103
1104 new_func.* = .{
1105 .analysis = .{ .queued = fn_zir },
1106 .owner_decl = decl,
1107 };
1108 fn_payload.* = .{ .func = new_func };
1109
1110 var prev_type_has_bits = false;
1111 var type_changed = true;
1112
1113 if (decl.typedValueManaged()) |tvm| {
1114 prev_type_has_bits = tvm.typed_value.ty.hasCodeGenBits();
1115 type_changed = !tvm.typed_value.ty.eql(fn_type);
1116
1117 tvm.deinit(self.gpa);
1118 }
1119
1120 decl_arena_state.* = decl_arena.state;
1121 decl.typed_value = .{
1122 .most_recent = .{
1123 .typed_value = .{
1124 .ty = fn_type,
1125 .val = Value.initPayload(&fn_payload.base),
1126 },
1127 .arena = decl_arena_state,
1128 },
1129 };
1130 decl.analysis = .complete;
1131 decl.generation = self.generation;
1132
1133 if (fn_type.hasCodeGenBits()) {
1134 // We don't fully codegen the decl until later, but we do need to reserve a global
1135 // offset table index for it. This allows us to codegen decls out of dependency order,
1136 // increasing how many computations can be done in parallel.
1137 try self.comp.bin_file.allocateDeclIndexes(decl);
1138 try self.comp.work_queue.writeItem(.{ .codegen_decl = decl });
1139 } else if (prev_type_has_bits) {
1140 self.comp.bin_file.freeDecl(decl);
1141 }
1142
1143 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
1144 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1145 const export_src = tree.token_locs[maybe_export_token].start;
1146 const name_loc = tree.token_locs[fn_proto.getNameToken().?];
1147 const name = tree.tokenSliceLoc(name_loc);
1148 // The scope needs to have the decl in it.
1149 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1150 }
1151 }
1152 return type_changed;
1153 },
1154 .VarDecl => {
1155 const var_decl = @fieldParentPtr(ast.Node.VarDecl, "base", ast_node);
1156
1157 decl.analysis = .in_progress;
1158
1159 // We need the memory for the Type to go into the arena for the Decl
1160 var decl_arena = std.heap.ArenaAllocator.init(self.gpa);
1161 errdefer decl_arena.deinit();
1162 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
1163
1164 var block_scope: Scope.Block = .{
1165 .parent = null,
1166 .func = null,
1167 .decl = decl,
1168 .instructions = .{},
1169 .arena = &decl_arena.allocator,
1170 .is_comptime = true,
1171 };
1172 defer block_scope.instructions.deinit(self.gpa);
1173
1174 decl.is_pub = var_decl.getVisibToken() != null;
1175 const is_extern = blk: {
1176 const maybe_extern_token = var_decl.getExternExportToken() orelse
1177 break :blk false;
1178 if (tree.token_ids[maybe_extern_token] != .Keyword_extern) break :blk false;
1179 if (var_decl.getInitNode()) |some| {
1180 return self.failNode(&block_scope.base, some, "extern variables have no initializers", .{});
1181 }
1182 break :blk true;
1183 };
1184 if (var_decl.getLibName()) |lib_name| {
1185 assert(is_extern);
1186 return self.failNode(&block_scope.base, lib_name, "TODO implement function library name", .{});
1187 }
1188 const is_mutable = tree.token_ids[var_decl.mut_token] == .Keyword_var;
1189 const is_threadlocal = if (var_decl.getThreadLocalToken()) |some| blk: {
1190 if (!is_mutable) {
1191 return self.failTok(&block_scope.base, some, "threadlocal variable cannot be constant", .{});
1192 }
1193 break :blk true;
1194 } else false;
1195 assert(var_decl.getComptimeToken() == null);
1196 if (var_decl.getAlignNode()) |align_expr| {
1197 return self.failNode(&block_scope.base, align_expr, "TODO implement function align expression", .{});
1198 }
1199 if (var_decl.getSectionNode()) |sect_expr| {
1200 return self.failNode(&block_scope.base, sect_expr, "TODO implement function section expression", .{});
1201 }
1202
1203 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.getInitNode()) |init_node| vi: {
1204 var gen_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1205 defer gen_scope_arena.deinit();
1206 var gen_scope: Scope.GenZIR = .{
1207 .decl = decl,
1208 .arena = &gen_scope_arena.allocator,
1209 .parent = decl.scope,
1210 };
1211 defer gen_scope.instructions.deinit(self.gpa);
1212
1213 const init_result_loc: astgen.ResultLoc = if (var_decl.getTypeNode()) |type_node| rl: {
1214 const src = tree.token_locs[type_node.firstToken()].start;
1215 const type_type = try astgen.addZIRInstConst(self, &gen_scope.base, src, .{
1216 .ty = Type.initTag(.type),
1217 .val = Value.initTag(.type_type),
1218 });
1219 const var_type = try astgen.expr(self, &gen_scope.base, .{ .ty = type_type }, type_node);
1220 break :rl .{ .ty = var_type };
1221 } else .none;
1222
1223 const src = tree.token_locs[init_node.firstToken()].start;
1224 const init_inst = try astgen.expr(self, &gen_scope.base, init_result_loc, init_node);
1225
1226 var inner_block: Scope.Block = .{
1227 .parent = null,
1228 .func = null,
1229 .decl = decl,
1230 .instructions = .{},
1231 .arena = &gen_scope_arena.allocator,
1232 .is_comptime = true,
1233 };
1234 defer inner_block.instructions.deinit(self.gpa);
1235 try zir_sema.analyzeBody(self, &inner_block.base, .{ .instructions = gen_scope.instructions.items });
1236
1237 // The result location guarantees the type coercion.
1238 const analyzed_init_inst = init_inst.analyzed_inst.?;
1239 // The is_comptime in the Scope.Block guarantees the result is comptime-known.
1240 const val = analyzed_init_inst.value().?;
1241
1242 const ty = try analyzed_init_inst.ty.copy(block_scope.arena);
1243 break :vi .{
1244 .ty = ty,
1245 .val = try val.copy(block_scope.arena),
1246 };
1247 } else if (!is_extern) {
1248 return self.failTok(&block_scope.base, var_decl.firstToken(), "variables must be initialized", .{});
1249 } else if (var_decl.getTypeNode()) |type_node| vi: {
1250 // Temporary arena for the zir instructions.
1251 var type_scope_arena = std.heap.ArenaAllocator.init(self.gpa);
1252 defer type_scope_arena.deinit();
1253 var type_scope: Scope.GenZIR = .{
1254 .decl = decl,
1255 .arena = &type_scope_arena.allocator,
1256 .parent = decl.scope,
1257 };
1258 defer type_scope.instructions.deinit(self.gpa);
1259
1260 const src = tree.token_locs[type_node.firstToken()].start;
1261 const type_type = try astgen.addZIRInstConst(self, &type_scope.base, src, .{
1262 .ty = Type.initTag(.type),
1263 .val = Value.initTag(.type_type),
1264 });
1265 const var_type = try astgen.expr(self, &type_scope.base, .{ .ty = type_type }, type_node);
1266 const ty = try zir_sema.analyzeBodyValueAsType(self, &block_scope, var_type, .{
1267 .instructions = type_scope.instructions.items,
1268 });
1269 break :vi .{
1270 .ty = ty,
1271 .val = null,
1272 };
1273 } else {
1274 return self.failTok(&block_scope.base, var_decl.firstToken(), "unable to infer variable type", .{});
1275 };
1276
1277 if (is_mutable and !var_info.ty.isValidVarType(is_extern)) {
1278 return self.failTok(&block_scope.base, var_decl.firstToken(), "variable of type '{}' must be const", .{var_info.ty});
1279 }
1280
1281 var type_changed = true;
1282 if (decl.typedValueManaged()) |tvm| {
1283 type_changed = !tvm.typed_value.ty.eql(var_info.ty);
1284
1285 tvm.deinit(self.gpa);
1286 }
1287
1288 const new_variable = try decl_arena.allocator.create(Var);
1289 const var_payload = try decl_arena.allocator.create(Value.Payload.Variable);
1290 new_variable.* = .{
1291 .owner_decl = decl,
1292 .init = var_info.val orelse undefined,
1293 .is_extern = is_extern,
1294 .is_mutable = is_mutable,
1295 .is_threadlocal = is_threadlocal,
1296 };
1297 var_payload.* = .{ .variable = new_variable };
1298
1299 decl_arena_state.* = decl_arena.state;
1300 decl.typed_value = .{
1301 .most_recent = .{
1302 .typed_value = .{
1303 .ty = var_info.ty,
1304 .val = Value.initPayload(&var_payload.base),
1305 },
1306 .arena = decl_arena_state,
1307 },
1308 };
1309 decl.analysis = .complete;
1310 decl.generation = self.generation;
1311
1312 if (var_decl.getExternExportToken()) |maybe_export_token| {
1313 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1314 const export_src = tree.token_locs[maybe_export_token].start;
1315 const name_loc = tree.token_locs[var_decl.name_token];
1316 const name = tree.tokenSliceLoc(name_loc);
1317 // The scope needs to have the decl in it.
1318 try self.analyzeExport(&block_scope.base, export_src, name, decl);
1319 }
1320 }
1321 return type_changed;
1322 },
1323 .Comptime => {
1324 const comptime_decl = @fieldParentPtr(ast.Node.Comptime, "base", ast_node);
1325
1326 decl.analysis = .in_progress;
1327
1328 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
1329 var analysis_arena = std.heap.ArenaAllocator.init(self.gpa);
1330 defer analysis_arena.deinit();
1331 var gen_scope: Scope.GenZIR = .{
1332 .decl = decl,
1333 .arena = &analysis_arena.allocator,
1334 .parent = decl.scope,
1335 };
1336 defer gen_scope.instructions.deinit(self.gpa);
1337
1338 _ = try astgen.comptimeExpr(self, &gen_scope.base, .none, comptime_decl.expr);
1339
1340 var block_scope: Scope.Block = .{
1341 .parent = null,
1342 .func = null,
1343 .decl = decl,
1344 .instructions = .{},
1345 .arena = &analysis_arena.allocator,
1346 .is_comptime = true,
1347 };
1348 defer block_scope.instructions.deinit(self.gpa);
1349
1350 _ = try zir_sema.analyzeBody(self, &block_scope.base, .{
1351 .instructions = gen_scope.instructions.items,
1352 });
1353
1354 decl.analysis = .complete;
1355 decl.generation = self.generation;
1356 return true;
1357 },
1358 .Use => @panic("TODO usingnamespace decl"),
1359 else => unreachable,
1360 }
1361}
1362
1363fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
1364 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);
1365 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);
1366
1367 depender.dependencies.putAssumeCapacity(dependee, {});
1368 dependee.dependants.putAssumeCapacity(depender, {});
1369}
1370
1371fn getSrcModule(self: *Module, root_scope: *Scope.ZIRModule) !*zir.Module {
1372 switch (root_scope.status) {
1373 .never_loaded, .unloaded_success => {
1374 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
1375
1376 const source = try root_scope.getSource(self);
1377
1378 var keep_zir_module = false;
1379 const zir_module = try self.gpa.create(zir.Module);
1380 defer if (!keep_zir_module) self.gpa.destroy(zir_module);
1381
1382 zir_module.* = try zir.parse(self.gpa, source);
1383 defer if (!keep_zir_module) zir_module.deinit(self.gpa);
1384
1385 if (zir_module.error_msg) |src_err_msg| {
1386 self.failed_files.putAssumeCapacityNoClobber(
1387 &root_scope.base,
1388 try Compilation.ErrorMsg.create(self.gpa, src_err_msg.byte_offset, "{}", .{src_err_msg.msg}),
1389 );
1390 root_scope.status = .unloaded_parse_failure;
1391 return error.AnalysisFail;
1392 }
1393
1394 root_scope.status = .loaded_success;
1395 root_scope.contents = .{ .module = zir_module };
1396 keep_zir_module = true;
1397
1398 return zir_module;
1399 },
1400
1401 .unloaded_parse_failure,
1402 .unloaded_sema_failure,
1403 => return error.AnalysisFail,
1404
1405 .loaded_success, .loaded_sema_failure => return root_scope.contents.module,
1406 }
1407}
1408
1409fn getAstTree(self: *Module, container_scope: *Scope.Container) !*ast.Tree {
1410 const tracy = trace(@src());
1411 defer tracy.end();
1412
1413 const root_scope = container_scope.file_scope;
1414
1415 switch (root_scope.status) {
1416 .never_loaded, .unloaded_success => {
1417 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
1418
1419 const source = try root_scope.getSource(self);
1420
1421 var keep_tree = false;
1422 const tree = try std.zig.parse(self.gpa, source);
1423 defer if (!keep_tree) tree.deinit();
1424
1425 if (tree.errors.len != 0) {
1426 const parse_err = tree.errors[0];
1427
1428 var msg = std.ArrayList(u8).init(self.gpa);
1429 defer msg.deinit();
1430
1431 try parse_err.render(tree.token_ids, msg.outStream());
1432 const err_msg = try self.gpa.create(Compilation.ErrorMsg);
1433 err_msg.* = .{
1434 .msg = msg.toOwnedSlice(),
1435 .byte_offset = tree.token_locs[parse_err.loc()].start,
1436 };
1437
1438 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
1439 root_scope.status = .unloaded_parse_failure;
1440 return error.AnalysisFail;
1441 }
1442
1443 root_scope.status = .loaded_success;
1444 root_scope.contents = .{ .tree = tree };
1445 keep_tree = true;
1446
1447 return tree;
1448 },
1449
1450 .unloaded_parse_failure => return error.AnalysisFail,
1451
1452 .loaded_success => return root_scope.contents.tree,
1453 }
1454}
1455
1456pub fn analyzeContainer(self: *Module, container_scope: *Scope.Container) !void {
1457 const tracy = trace(@src());
1458 defer tracy.end();
1459
1460 // We may be analyzing it for the first time, or this may be
1461 // an incremental update. This code handles both cases.
1462 const tree = try self.getAstTree(container_scope);
1463 const decls = tree.root_node.decls();
1464
1465 try self.comp.work_queue.ensureUnusedCapacity(decls.len);
1466 try container_scope.decls.ensureCapacity(self.gpa, decls.len);
1467
1468 // Keep track of the decls that we expect to see in this file so that
1469 // we know which ones have been deleted.
1470 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
1471 defer deleted_decls.deinit();
1472 try deleted_decls.ensureCapacity(container_scope.decls.items().len);
1473 for (container_scope.decls.items()) |entry| {
1474 deleted_decls.putAssumeCapacityNoClobber(entry.key, {});
1475 }
1476
1477 for (decls) |src_decl, decl_i| {
1478 if (src_decl.cast(ast.Node.FnProto)) |fn_proto| {
1479 // We will create a Decl for it regardless of analysis status.
1480 const name_tok = fn_proto.getNameToken() orelse {
1481 @panic("TODO missing function name");
1482 };
1483
1484 const name_loc = tree.token_locs[name_tok];
1485 const name = tree.tokenSliceLoc(name_loc);
1486 const name_hash = container_scope.fullyQualifiedNameHash(name);
1487 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1488 if (self.decl_table.get(name_hash)) |decl| {
1489 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1490 // have been re-ordered.
1491 decl.src_index = decl_i;
1492 if (deleted_decls.remove(decl) == null) {
1493 decl.analysis = .sema_failure;
1494 const err_msg = try Compilation.ErrorMsg.create(self.gpa, tree.token_locs[name_tok].start, "redefinition of '{}'", .{decl.name});
1495 errdefer err_msg.destroy(self.gpa);
1496 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1497 } else {
1498 if (!srcHashEql(decl.contents_hash, contents_hash)) {
1499 try self.markOutdatedDecl(decl);
1500 decl.contents_hash = contents_hash;
1501 } else switch (self.comp.bin_file.tag) {
1502 .coff => {
1503 // TODO Implement for COFF
1504 },
1505 .elf => if (decl.fn_link.elf.len != 0) {
1506 // TODO Look into detecting when this would be unnecessary by storing enough state
1507 // in `Decl` to notice that the line number did not change.
1508 self.comp.work_queue.writeItemAssumeCapacity(.{ .update_line_number = decl });
1509 },
1510 .macho => {
1511 // TODO Implement for MachO
1512 },
1513 .c, .wasm => {},
1514 }
1515 }
1516 } else {
1517 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1518 container_scope.decls.putAssumeCapacity(new_decl, {});
1519 if (fn_proto.getExternExportInlineToken()) |maybe_export_token| {
1520 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1521 self.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1522 }
1523 }
1524 }
1525 } else if (src_decl.castTag(.VarDecl)) |var_decl| {
1526 const name_loc = tree.token_locs[var_decl.name_token];
1527 const name = tree.tokenSliceLoc(name_loc);
1528 const name_hash = container_scope.fullyQualifiedNameHash(name);
1529 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1530 if (self.decl_table.get(name_hash)) |decl| {
1531 // Update the AST Node index of the decl, even if its contents are unchanged, it may
1532 // have been re-ordered.
1533 decl.src_index = decl_i;
1534 if (deleted_decls.remove(decl) == null) {
1535 decl.analysis = .sema_failure;
1536 const err_msg = try Compilation.ErrorMsg.create(self.gpa, name_loc.start, "redefinition of '{}'", .{decl.name});
1537 errdefer err_msg.destroy(self.gpa);
1538 try self.failed_decls.putNoClobber(self.gpa, decl, err_msg);
1539 } else if (!srcHashEql(decl.contents_hash, contents_hash)) {
1540 try self.markOutdatedDecl(decl);
1541 decl.contents_hash = contents_hash;
1542 }
1543 } else {
1544 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1545 container_scope.decls.putAssumeCapacity(new_decl, {});
1546 if (var_decl.getExternExportToken()) |maybe_export_token| {
1547 if (tree.token_ids[maybe_export_token] == .Keyword_export) {
1548 self.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1549 }
1550 }
1551 }
1552 } else if (src_decl.castTag(.Comptime)) |comptime_node| {
1553 const name_index = self.getNextAnonNameIndex();
1554 const name = try std.fmt.allocPrint(self.gpa, "__comptime_{}", .{name_index});
1555 defer self.gpa.free(name);
1556
1557 const name_hash = container_scope.fullyQualifiedNameHash(name);
1558 const contents_hash = std.zig.hashSrc(tree.getNodeSource(src_decl));
1559
1560 const new_decl = try self.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
1561 container_scope.decls.putAssumeCapacity(new_decl, {});
1562 self.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
1563 } else if (src_decl.castTag(.ContainerField)) |container_field| {
1564 log.err("TODO: analyze container field", .{});
1565 } else if (src_decl.castTag(.TestDecl)) |test_decl| {
1566 log.err("TODO: analyze test decl", .{});
1567 } else if (src_decl.castTag(.Use)) |use_decl| {
1568 log.err("TODO: analyze usingnamespace decl", .{});
1569 } else {
1570 unreachable;
1571 }
1572 }
1573 // Handle explicitly deleted decls from the source code. Not to be confused
1574 // with when we delete decls because they are no longer referenced.
1575 for (deleted_decls.items()) |entry| {
1576 log.debug("noticed '{}' deleted from source\n", .{entry.key.name});
1577 try self.deleteDecl(entry.key);
1578 }
1579}
1580
1581pub fn analyzeRootZIRModule(self: *Module, root_scope: *Scope.ZIRModule) !void {
1582 // We may be analyzing it for the first time, or this may be
1583 // an incremental update. This code handles both cases.
1584 const src_module = try self.getSrcModule(root_scope);
1585
1586 try self.comp.work_queue.ensureUnusedCapacity(src_module.decls.len);
1587 try root_scope.decls.ensureCapacity(self.gpa, src_module.decls.len);
1588
1589 var exports_to_resolve = std.ArrayList(*zir.Decl).init(self.gpa);
1590 defer exports_to_resolve.deinit();
1591
1592 // Keep track of the decls that we expect to see in this file so that
1593 // we know which ones have been deleted.
1594 var deleted_decls = std.AutoArrayHashMap(*Decl, void).init(self.gpa);
1595 defer deleted_decls.deinit();
1596 try deleted_decls.ensureCapacity(self.decl_table.items().len);
1597 for (self.decl_table.items()) |entry| {
1598 deleted_decls.putAssumeCapacityNoClobber(entry.value, {});
1599 }
1600
1601 for (src_module.decls) |src_decl, decl_i| {
1602 const name_hash = root_scope.fullyQualifiedNameHash(src_decl.name);
1603 if (self.decl_table.get(name_hash)) |decl| {
1604 deleted_decls.removeAssertDiscard(decl);
1605 if (!srcHashEql(src_decl.contents_hash, decl.contents_hash)) {
1606 try self.markOutdatedDecl(decl);
1607 decl.contents_hash = src_decl.contents_hash;
1608 }
1609 } else {
1610 const new_decl = try self.createNewDecl(
1611 &root_scope.base,
1612 src_decl.name,
1613 decl_i,
1614 name_hash,
1615 src_decl.contents_hash,
1616 );
1617 root_scope.decls.appendAssumeCapacity(new_decl);
1618 if (src_decl.inst.cast(zir.Inst.Export)) |export_inst| {
1619 try exports_to_resolve.append(src_decl);
1620 }
1621 }
1622 }
1623 for (exports_to_resolve.items) |export_decl| {
1624 _ = try zir_sema.resolveZirDecl(self, &root_scope.base, export_decl);
1625 }
1626 // Handle explicitly deleted decls from the source code. Not to be confused
1627 // with when we delete decls because they are no longer referenced.
1628 for (deleted_decls.items()) |entry| {
1629 log.debug("noticed '{}' deleted from source\n", .{entry.key.name});
1630 try self.deleteDecl(entry.key);
1631 }
1632}
1633
1634pub fn deleteDecl(self: *Module, decl: *Decl) !void {
1635 try self.deletion_set.ensureCapacity(self.gpa, self.deletion_set.items.len + decl.dependencies.items().len);
1636
1637 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
1638 // not be present in the set, and this does nothing.
1639 decl.scope.removeDecl(decl);
1640
1641 log.debug("deleting decl '{}'\n", .{decl.name});
1642 const name_hash = decl.fullyQualifiedNameHash();
1643 self.decl_table.removeAssertDiscard(name_hash);
1644 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
1645 for (decl.dependencies.items()) |entry| {
1646 const dep = entry.key;
1647 dep.removeDependant(decl);
1648 if (dep.dependants.items().len == 0 and !dep.deletion_flag) {
1649 // We don't recursively perform a deletion here, because during the update,
1650 // another reference to it may turn up.
1651 dep.deletion_flag = true;
1652 self.deletion_set.appendAssumeCapacity(dep);
1653 }
1654 }
1655 // Anything that depends on this deleted decl certainly needs to be re-analyzed.
1656 for (decl.dependants.items()) |entry| {
1657 const dep = entry.key;
1658 dep.removeDependency(decl);
1659 if (dep.analysis != .outdated) {
1660 // TODO Move this failure possibility to the top of the function.
1661 try self.markOutdatedDecl(dep);
1662 }
1663 }
1664 if (self.failed_decls.remove(decl)) |entry| {
1665 entry.value.destroy(self.gpa);
1666 }
1667 self.deleteDeclExports(decl);
1668 self.comp.bin_file.freeDecl(decl);
1669 decl.destroy(self.gpa);
1670}
1671
1672/// Delete all the Export objects that are caused by this Decl. Re-analysis of
1673/// this Decl will cause them to be re-created (or not).
1674fn deleteDeclExports(self: *Module, decl: *Decl) void {
1675 const kv = self.export_owners.remove(decl) orelse return;
1676
1677 for (kv.value) |exp| {
1678 if (self.decl_exports.getEntry(exp.exported_decl)) |decl_exports_kv| {
1679 // Remove exports with owner_decl matching the regenerating decl.
1680 const list = decl_exports_kv.value;
1681 var i: usize = 0;
1682 var new_len = list.len;
1683 while (i < new_len) {
1684 if (list[i].owner_decl == decl) {
1685 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
1686 new_len -= 1;
1687 } else {
1688 i += 1;
1689 }
1690 }
1691 decl_exports_kv.value = self.gpa.shrink(list, new_len);
1692 if (new_len == 0) {
1693 self.decl_exports.removeAssertDiscard(exp.exported_decl);
1694 }
1695 }
1696 if (self.comp.bin_file.cast(link.File.Elf)) |elf| {
1697 elf.deleteExport(exp.link);
1698 }
1699 if (self.failed_exports.remove(exp)) |entry| {
1700 entry.value.destroy(self.gpa);
1701 }
1702 _ = self.symbol_exports.remove(exp.options.name);
1703 self.gpa.free(exp.options.name);
1704 self.gpa.destroy(exp);
1705 }
1706 self.gpa.free(kv.value);
1707}
1708
1709pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
1710 const tracy = trace(@src());
1711 defer tracy.end();
1712
1713 // Use the Decl's arena for function memory.
1714 var arena = decl.typed_value.most_recent.arena.?.promote(self.gpa);
1715 defer decl.typed_value.most_recent.arena.?.* = arena.state;
1716 var inner_block: Scope.Block = .{
1717 .parent = null,
1718 .func = func,
1719 .decl = decl,
1720 .instructions = .{},
1721 .arena = &arena.allocator,
1722 .is_comptime = false,
1723 };
1724 defer inner_block.instructions.deinit(self.gpa);
1725
1726 const fn_zir = func.analysis.queued;
1727 defer fn_zir.arena.promote(self.gpa).deinit();
1728 func.analysis = .{ .in_progress = {} };
1729 log.debug("set {} to in_progress\n", .{decl.name});
1730
1731 try zir_sema.analyzeBody(self, &inner_block.base, fn_zir.body);
1732
1733 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
1734 func.analysis = .{ .success = .{ .instructions = instructions } };
1735 log.debug("set {} to success\n", .{decl.name});
1736}
1737
1738fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
1739 log.debug("mark {} outdated\n", .{decl.name});
1740 try self.comp.work_queue.writeItem(.{ .analyze_decl = decl });
1741 if (self.failed_decls.remove(decl)) |entry| {
1742 entry.value.destroy(self.gpa);
1743 }
1744 decl.analysis = .outdated;
1745}
1746
1747fn allocateNewDecl(
1748 self: *Module,
1749 scope: *Scope,
1750 src_index: usize,
1751 contents_hash: std.zig.SrcHash,
1752) !*Decl {
1753 const new_decl = try self.gpa.create(Decl);
1754 new_decl.* = .{
1755 .name = "",
1756 .scope = scope.namespace(),
1757 .src_index = src_index,
1758 .typed_value = .{ .never_succeeded = {} },
1759 .analysis = .unreferenced,
1760 .deletion_flag = false,
1761 .contents_hash = contents_hash,
1762 .link = switch (self.comp.bin_file.tag) {
1763 .coff => .{ .coff = link.File.Coff.TextBlock.empty },
1764 .elf => .{ .elf = link.File.Elf.TextBlock.empty },
1765 .macho => .{ .macho = link.File.MachO.TextBlock.empty },
1766 .c => .{ .c = {} },
1767 .wasm => .{ .wasm = {} },
1768 },
1769 .fn_link = switch (self.comp.bin_file.tag) {
1770 .coff => .{ .coff = {} },
1771 .elf => .{ .elf = link.File.Elf.SrcFn.empty },
1772 .macho => .{ .macho = link.File.MachO.SrcFn.empty },
1773 .c => .{ .c = {} },
1774 .wasm => .{ .wasm = null },
1775 },
1776 .generation = 0,
1777 .is_pub = false,
1778 };
1779 return new_decl;
1780}
1781
1782fn createNewDecl(
1783 self: *Module,
1784 scope: *Scope,
1785 decl_name: []const u8,
1786 src_index: usize,
1787 name_hash: Scope.NameHash,
1788 contents_hash: std.zig.SrcHash,
1789) !*Decl {
1790 try self.decl_table.ensureCapacity(self.gpa, self.decl_table.items().len + 1);
1791 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
1792 errdefer self.gpa.destroy(new_decl);
1793 new_decl.name = try mem.dupeZ(self.gpa, u8, decl_name);
1794 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
1795 return new_decl;
1796}
1797
1798/// Get error value for error tag `name`.
1799pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
1800 const gop = try self.global_error_set.getOrPut(self.gpa, name);
1801 if (gop.found_existing)
1802 return gop.entry.*;
1803 errdefer self.global_error_set.removeAssertDiscard(name);
1804
1805 gop.entry.key = try self.gpa.dupe(u8, name);
1806 gop.entry.value = @intCast(u16, self.global_error_set.count() - 1);
1807 return gop.entry.*;
1808}
1809
1810pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
1811 return scope.cast(Scope.Block) orelse
1812 return self.fail(scope, src, "instruction illegal outside function body", .{});
1813}
1814
1815pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
1816 const block = try self.requireFunctionBlock(scope, src);
1817 if (block.is_comptime) {
1818 return self.fail(scope, src, "unable to resolve comptime value", .{});
1819 }
1820 return block;
1821}
1822
1823pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {
1824 return (try self.resolveDefinedValue(scope, base)) orelse
1825 return self.fail(scope, base.src, "unable to resolve comptime value", .{});
1826}
1827
1828pub fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {
1829 if (base.value()) |val| {
1830 if (val.isUndef()) {
1831 return self.fail(scope, base.src, "use of undefined value here causes undefined behavior", .{});
1832 }
1833 return val;
1834 }
1835 return null;
1836}
1837
1838pub fn analyzeExport(self: *Module, scope: *Scope, src: usize, borrowed_symbol_name: []const u8, exported_decl: *Decl) !void {
1839 try self.ensureDeclAnalyzed(exported_decl);
1840 const typed_value = exported_decl.typed_value.most_recent.typed_value;
1841 switch (typed_value.ty.zigTypeTag()) {
1842 .Fn => {},
1843 else => return self.fail(scope, src, "unable to export type '{}'", .{typed_value.ty}),
1844 }
1845
1846 try self.decl_exports.ensureCapacity(self.gpa, self.decl_exports.items().len + 1);
1847 try self.export_owners.ensureCapacity(self.gpa, self.export_owners.items().len + 1);
1848
1849 const new_export = try self.gpa.create(Export);
1850 errdefer self.gpa.destroy(new_export);
1851
1852 const symbol_name = try self.gpa.dupe(u8, borrowed_symbol_name);
1853 errdefer self.gpa.free(symbol_name);
1854
1855 const owner_decl = scope.decl().?;
1856
1857 new_export.* = .{
1858 .options = .{ .name = symbol_name },
1859 .src = src,
1860 .link = .{},
1861 .owner_decl = owner_decl,
1862 .exported_decl = exported_decl,
1863 .status = .in_progress,
1864 };
1865
1866 // Add to export_owners table.
1867 const eo_gop = self.export_owners.getOrPutAssumeCapacity(owner_decl);
1868 if (!eo_gop.found_existing) {
1869 eo_gop.entry.value = &[0]*Export{};
1870 }
1871 eo_gop.entry.value = try self.gpa.realloc(eo_gop.entry.value, eo_gop.entry.value.len + 1);
1872 eo_gop.entry.value[eo_gop.entry.value.len - 1] = new_export;
1873 errdefer eo_gop.entry.value = self.gpa.shrink(eo_gop.entry.value, eo_gop.entry.value.len - 1);
1874
1875 // Add to exported_decl table.
1876 const de_gop = self.decl_exports.getOrPutAssumeCapacity(exported_decl);
1877 if (!de_gop.found_existing) {
1878 de_gop.entry.value = &[0]*Export{};
1879 }
1880 de_gop.entry.value = try self.gpa.realloc(de_gop.entry.value, de_gop.entry.value.len + 1);
1881 de_gop.entry.value[de_gop.entry.value.len - 1] = new_export;
1882 errdefer de_gop.entry.value = self.gpa.shrink(de_gop.entry.value, de_gop.entry.value.len - 1);
1883
1884 if (self.symbol_exports.get(symbol_name)) |_| {
1885 try self.failed_exports.ensureCapacity(self.gpa, self.failed_exports.items().len + 1);
1886 self.failed_exports.putAssumeCapacityNoClobber(new_export, try Compilation.ErrorMsg.create(
1887 self.gpa,
1888 src,
1889 "exported symbol collision: {}",
1890 .{symbol_name},
1891 ));
1892 // TODO: add a note
1893 new_export.status = .failed;
1894 return;
1895 }
1896
1897 try self.symbol_exports.putNoClobber(self.gpa, symbol_name, new_export);
1898 self.comp.bin_file.updateDeclExports(self, exported_decl, de_gop.entry.value) catch |err| switch (err) {
1899 error.OutOfMemory => return error.OutOfMemory,
1900 else => {
1901 try self.failed_exports.ensureCapacity(self.gpa, self.failed_exports.items().len + 1);
1902 self.failed_exports.putAssumeCapacityNoClobber(new_export, try Compilation.ErrorMsg.create(
1903 self.gpa,
1904 src,
1905 "unable to export: {}",
1906 .{@errorName(err)},
1907 ));
1908 new_export.status = .failed_retryable;
1909 },
1910 };
1911}
1912
1913pub fn addNoOp(
1914 self: *Module,
1915 block: *Scope.Block,
1916 src: usize,
1917 ty: Type,
1918 comptime tag: Inst.Tag,
1919) !*Inst {
1920 const inst = try block.arena.create(tag.Type());
1921 inst.* = .{
1922 .base = .{
1923 .tag = tag,
1924 .ty = ty,
1925 .src = src,
1926 },
1927 };
1928 try block.instructions.append(self.gpa, &inst.base);
1929 return &inst.base;
1930}
1931
1932pub fn addUnOp(
1933 self: *Module,
1934 block: *Scope.Block,
1935 src: usize,
1936 ty: Type,
1937 tag: Inst.Tag,
1938 operand: *Inst,
1939) !*Inst {
1940 const inst = try block.arena.create(Inst.UnOp);
1941 inst.* = .{
1942 .base = .{
1943 .tag = tag,
1944 .ty = ty,
1945 .src = src,
1946 },
1947 .operand = operand,
1948 };
1949 try block.instructions.append(self.gpa, &inst.base);
1950 return &inst.base;
1951}
1952
1953pub fn addBinOp(
1954 self: *Module,
1955 block: *Scope.Block,
1956 src: usize,
1957 ty: Type,
1958 tag: Inst.Tag,
1959 lhs: *Inst,
1960 rhs: *Inst,
1961) !*Inst {
1962 const inst = try block.arena.create(Inst.BinOp);
1963 inst.* = .{
1964 .base = .{
1965 .tag = tag,
1966 .ty = ty,
1967 .src = src,
1968 },
1969 .lhs = lhs,
1970 .rhs = rhs,
1971 };
1972 try block.instructions.append(self.gpa, &inst.base);
1973 return &inst.base;
1974}
1975
1976pub fn addArg(self: *Module, block: *Scope.Block, src: usize, ty: Type, name: [*:0]const u8) !*Inst {
1977 const inst = try block.arena.create(Inst.Arg);
1978 inst.* = .{
1979 .base = .{
1980 .tag = .arg,
1981 .ty = ty,
1982 .src = src,
1983 },
1984 .name = name,
1985 };
1986 try block.instructions.append(self.gpa, &inst.base);
1987 return &inst.base;
1988}
1989
1990pub fn addBr(
1991 self: *Module,
1992 scope_block: *Scope.Block,
1993 src: usize,
1994 target_block: *Inst.Block,
1995 operand: *Inst,
1996) !*Inst {
1997 const inst = try scope_block.arena.create(Inst.Br);
1998 inst.* = .{
1999 .base = .{
2000 .tag = .br,
2001 .ty = Type.initTag(.noreturn),
2002 .src = src,
2003 },
2004 .operand = operand,
2005 .block = target_block,
2006 };
2007 try scope_block.instructions.append(self.gpa, &inst.base);
2008 return &inst.base;
2009}
2010
2011pub fn addCondBr(
2012 self: *Module,
2013 block: *Scope.Block,
2014 src: usize,
2015 condition: *Inst,
2016 then_body: ir.Body,
2017 else_body: ir.Body,
2018) !*Inst {
2019 const inst = try block.arena.create(Inst.CondBr);
2020 inst.* = .{
2021 .base = .{
2022 .tag = .condbr,
2023 .ty = Type.initTag(.noreturn),
2024 .src = src,
2025 },
2026 .condition = condition,
2027 .then_body = then_body,
2028 .else_body = else_body,
2029 };
2030 try block.instructions.append(self.gpa, &inst.base);
2031 return &inst.base;
2032}
2033
2034pub fn addCall(
2035 self: *Module,
2036 block: *Scope.Block,
2037 src: usize,
2038 ty: Type,
2039 func: *Inst,
2040 args: []const *Inst,
2041) !*Inst {
2042 const inst = try block.arena.create(Inst.Call);
2043 inst.* = .{
2044 .base = .{
2045 .tag = .call,
2046 .ty = ty,
2047 .src = src,
2048 },
2049 .func = func,
2050 .args = args,
2051 };
2052 try block.instructions.append(self.gpa, &inst.base);
2053 return &inst.base;
2054}
2055
2056pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
2057 const const_inst = try scope.arena().create(Inst.Constant);
2058 const_inst.* = .{
2059 .base = .{
2060 .tag = Inst.Constant.base_tag,
2061 .ty = typed_value.ty,
2062 .src = src,
2063 },
2064 .val = typed_value.val,
2065 };
2066 return &const_inst.base;
2067}
2068
2069pub fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
2070 return self.constInst(scope, src, .{
2071 .ty = Type.initTag(.type),
2072 .val = try ty.toValue(scope.arena()),
2073 });
2074}
2075
2076pub fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
2077 return self.constInst(scope, src, .{
2078 .ty = Type.initTag(.void),
2079 .val = Value.initTag(.void_value),
2080 });
2081}
2082
2083pub fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {
2084 return self.constInst(scope, src, .{
2085 .ty = Type.initTag(.noreturn),
2086 .val = Value.initTag(.unreachable_value),
2087 });
2088}
2089
2090pub fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
2091 return self.constInst(scope, src, .{
2092 .ty = ty,
2093 .val = Value.initTag(.undef),
2094 });
2095}
2096
2097pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst {
2098 return self.constInst(scope, src, .{
2099 .ty = Type.initTag(.bool),
2100 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],
2101 });
2102}
2103
2104pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst {
2105 const int_payload = try scope.arena().create(Value.Payload.Int_u64);
2106 int_payload.* = .{ .int = int };
2107
2108 return self.constInst(scope, src, .{
2109 .ty = ty,
2110 .val = Value.initPayload(&int_payload.base),
2111 });
2112}
2113
2114pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst {
2115 const int_payload = try scope.arena().create(Value.Payload.Int_i64);
2116 int_payload.* = .{ .int = int };
2117
2118 return self.constInst(scope, src, .{
2119 .ty = ty,
2120 .val = Value.initPayload(&int_payload.base),
2121 });
2122}
2123
2124pub fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
2125 const val_payload = if (big_int.positive) blk: {
2126 if (big_int.to(u64)) |x| {
2127 return self.constIntUnsigned(scope, src, ty, x);
2128 } else |err| switch (err) {
2129 error.NegativeIntoUnsigned => unreachable,
2130 error.TargetTooSmall => {}, // handled below
2131 }
2132 const big_int_payload = try scope.arena().create(Value.Payload.IntBigPositive);
2133 big_int_payload.* = .{ .limbs = big_int.limbs };
2134 break :blk &big_int_payload.base;
2135 } else blk: {
2136 if (big_int.to(i64)) |x| {
2137 return self.constIntSigned(scope, src, ty, x);
2138 } else |err| switch (err) {
2139 error.NegativeIntoUnsigned => unreachable,
2140 error.TargetTooSmall => {}, // handled below
2141 }
2142 const big_int_payload = try scope.arena().create(Value.Payload.IntBigNegative);
2143 big_int_payload.* = .{ .limbs = big_int.limbs };
2144 break :blk &big_int_payload.base;
2145 };
2146
2147 return self.constInst(scope, src, .{
2148 .ty = ty,
2149 .val = Value.initPayload(val_payload),
2150 });
2151}
2152
2153pub fn createAnonymousDecl(
2154 self: *Module,
2155 scope: *Scope,
2156 decl_arena: *std.heap.ArenaAllocator,
2157 typed_value: TypedValue,
2158) !*Decl {
2159 const name_index = self.getNextAnonNameIndex();
2160 const scope_decl = scope.decl().?;
2161 const name = try std.fmt.allocPrint(self.gpa, "{}__anon_{}", .{ scope_decl.name, name_index });
2162 defer self.gpa.free(name);
2163 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
2164 const src_hash: std.zig.SrcHash = undefined;
2165 const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
2166 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
2167
2168 decl_arena_state.* = decl_arena.state;
2169 new_decl.typed_value = .{
2170 .most_recent = .{
2171 .typed_value = typed_value,
2172 .arena = decl_arena_state,
2173 },
2174 };
2175 new_decl.analysis = .complete;
2176 new_decl.generation = self.generation;
2177
2178 // TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.
2179 // We should be able to further improve the compiler to not omit Decls which are only referenced at
2180 // compile-time and not runtime.
2181 if (typed_value.ty.hasCodeGenBits()) {
2182 try self.comp.bin_file.allocateDeclIndexes(new_decl);
2183 try self.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });
2184 }
2185
2186 return new_decl;
2187}
2188
2189fn getNextAnonNameIndex(self: *Module) usize {
2190 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
2191}
2192
2193pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
2194 const namespace = scope.namespace();
2195 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2196 return self.decl_table.get(name_hash);
2197}
2198
2199pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2200 const scope_decl = scope.decl().?;
2201 try self.declareDeclDependency(scope_decl, decl);
2202 self.ensureDeclAnalyzed(decl) catch |err| {
2203 if (scope.cast(Scope.Block)) |block| {
2204 if (block.func) |func| {
2205 func.analysis = .dependency_failure;
2206 } else {
2207 block.decl.analysis = .dependency_failure;
2208 }
2209 } else {
2210 scope_decl.analysis = .dependency_failure;
2211 }
2212 return err;
2213 };
2214
2215 const decl_tv = try decl.typedValue();
2216 if (decl_tv.val.tag() == .variable) {
2217 return self.analyzeVarRef(scope, src, decl_tv);
2218 }
2219 const ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One);
2220 const val_payload = try scope.arena().create(Value.Payload.DeclRef);
2221 val_payload.* = .{ .decl = decl };
2222
2223 return self.constInst(scope, src, .{
2224 .ty = ty,
2225 .val = Value.initPayload(&val_payload.base),
2226 });
2227}
2228
2229fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
2230 const variable = tv.val.cast(Value.Payload.Variable).?.variable;
2231
2232 const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
2233 if (!variable.is_mutable and !variable.is_extern) {
2234 const val_payload = try scope.arena().create(Value.Payload.RefVal);
2235 val_payload.* = .{ .val = variable.init };
2236 return self.constInst(scope, src, .{
2237 .ty = ty,
2238 .val = Value.initPayload(&val_payload.base),
2239 });
2240 }
2241
2242 const b = try self.requireRuntimeBlock(scope, src);
2243 const inst = try b.arena.create(Inst.VarPtr);
2244 inst.* = .{
2245 .base = .{
2246 .tag = .varptr,
2247 .ty = ty,
2248 .src = src,
2249 },
2250 .variable = variable,
2251 };
2252 try b.instructions.append(self.gpa, &inst.base);
2253 return &inst.base;
2254}
2255
2256pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
2257 const elem_ty = switch (ptr.ty.zigTypeTag()) {
2258 .Pointer => ptr.ty.elemType(),
2259 else => return self.fail(scope, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
2260 };
2261 if (ptr.value()) |val| {
2262 return self.constInst(scope, src, .{
2263 .ty = elem_ty,
2264 .val = try val.pointerDeref(scope.arena()),
2265 });
2266 }
2267
2268 const b = try self.requireRuntimeBlock(scope, src);
2269 return self.addUnOp(b, src, elem_ty, .load, ptr);
2270}
2271
2272pub fn analyzeDeclRefByName(self: *Module, scope: *Scope, src: usize, decl_name: []const u8) InnerError!*Inst {
2273 const decl = self.lookupDeclName(scope, decl_name) orelse
2274 return self.fail(scope, src, "decl '{}' not found", .{decl_name});
2275 return self.analyzeDeclRef(scope, src, decl);
2276}
2277
2278pub fn wantSafety(self: *Module, scope: *Scope) bool {
2279 // TODO take into account scope's safety overrides
2280 return switch (self.optimizeMode()) {
2281 .Debug => true,
2282 .ReleaseSafe => true,
2283 .ReleaseFast => false,
2284 .ReleaseSmall => false,
2285 };
2286}
2287
2288pub fn analyzeIsNull(
2289 self: *Module,
2290 scope: *Scope,
2291 src: usize,
2292 operand: *Inst,
2293 invert_logic: bool,
2294) InnerError!*Inst {
2295 if (operand.value()) |opt_val| {
2296 const is_null = opt_val.isNull();
2297 const bool_value = if (invert_logic) !is_null else is_null;
2298 return self.constBool(scope, src, bool_value);
2299 }
2300 const b = try self.requireRuntimeBlock(scope, src);
2301 const inst_tag: Inst.Tag = if (invert_logic) .isnonnull else .isnull;
2302 return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand);
2303}
2304
2305pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
2306 return self.fail(scope, src, "TODO implement analysis of iserr", .{});
2307}
2308
2309pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
2310 const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
2311 .Pointer => array_ptr.ty.elemType(),
2312 else => return self.fail(scope, src, "expected pointer, found '{}'", .{array_ptr.ty}),
2313 };
2314
2315 var array_type = ptr_child;
2316 const elem_type = switch (ptr_child.zigTypeTag()) {
2317 .Array => ptr_child.elemType(),
2318 .Pointer => blk: {
2319 if (ptr_child.isSinglePointer()) {
2320 if (ptr_child.elemType().zigTypeTag() == .Array) {
2321 array_type = ptr_child.elemType();
2322 break :blk ptr_child.elemType().elemType();
2323 }
2324
2325 return self.fail(scope, src, "slice of single-item pointer", .{});
2326 }
2327 break :blk ptr_child.elemType();
2328 },
2329 else => return self.fail(scope, src, "slice of non-array type '{}'", .{ptr_child}),
2330 };
2331
2332 const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
2333 const casted = try self.coerce(scope, elem_type, sentinel);
2334 break :blk try self.resolveConstValue(scope, casted);
2335 } else null;
2336
2337 var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
2338 var return_elem_type = elem_type;
2339 if (end_opt) |end| {
2340 if (end.value()) |end_val| {
2341 if (start.value()) |start_val| {
2342 const start_u64 = start_val.toUnsignedInt();
2343 const end_u64 = end_val.toUnsignedInt();
2344 if (start_u64 > end_u64) {
2345 return self.fail(scope, src, "out of bounds slice", .{});
2346 }
2347
2348 const len = end_u64 - start_u64;
2349 const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
2350 array_type.sentinel()
2351 else
2352 slice_sentinel;
2353 return_elem_type = try self.arrayType(scope, len, array_sentinel, elem_type);
2354 return_ptr_size = .One;
2355 }
2356 }
2357 }
2358 const return_type = try self.ptrType(
2359 scope,
2360 src,
2361 return_elem_type,
2362 if (end_opt == null) slice_sentinel else null,
2363 0, // TODO alignment
2364 0,
2365 0,
2366 !ptr_child.isConstPtr(),
2367 ptr_child.isAllowzeroPtr(),
2368 ptr_child.isVolatilePtr(),
2369 return_ptr_size,
2370 );
2371
2372 return self.fail(scope, src, "TODO implement analysis of slice", .{});
2373}
2374
2375/// Asserts that lhs and rhs types are both numeric.
2376pub fn cmpNumeric(
2377 self: *Module,
2378 scope: *Scope,
2379 src: usize,
2380 lhs: *Inst,
2381 rhs: *Inst,
2382 op: std.math.CompareOperator,
2383) !*Inst {
2384 assert(lhs.ty.isNumeric());
2385 assert(rhs.ty.isNumeric());
2386
2387 const lhs_ty_tag = lhs.ty.zigTypeTag();
2388 const rhs_ty_tag = rhs.ty.zigTypeTag();
2389
2390 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
2391 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2392 return self.fail(scope, src, "vector length mismatch: {} and {}", .{
2393 lhs.ty.arrayLen(),
2394 rhs.ty.arrayLen(),
2395 });
2396 }
2397 return self.fail(scope, src, "TODO implement support for vectors in cmpNumeric", .{});
2398 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
2399 return self.fail(scope, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
2400 lhs.ty,
2401 rhs.ty,
2402 });
2403 }
2404
2405 if (lhs.value()) |lhs_val| {
2406 if (rhs.value()) |rhs_val| {
2407 return self.constBool(scope, src, Value.compare(lhs_val, op, rhs_val));
2408 }
2409 }
2410
2411 // TODO handle comparisons against lazy zero values
2412 // Some values can be compared against zero without being runtime known or without forcing
2413 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
2414 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
2415 // of this function if we don't need to.
2416
2417 // It must be a runtime comparison.
2418 const b = try self.requireRuntimeBlock(scope, src);
2419 // For floats, emit a float comparison instruction.
2420 const lhs_is_float = switch (lhs_ty_tag) {
2421 .Float, .ComptimeFloat => true,
2422 else => false,
2423 };
2424 const rhs_is_float = switch (rhs_ty_tag) {
2425 .Float, .ComptimeFloat => true,
2426 else => false,
2427 };
2428 if (lhs_is_float and rhs_is_float) {
2429 // Implicit cast the smaller one to the larger one.
2430 const dest_type = x: {
2431 if (lhs_ty_tag == .ComptimeFloat) {
2432 break :x rhs.ty;
2433 } else if (rhs_ty_tag == .ComptimeFloat) {
2434 break :x lhs.ty;
2435 }
2436 if (lhs.ty.floatBits(self.getTarget()) >= rhs.ty.floatBits(self.getTarget())) {
2437 break :x lhs.ty;
2438 } else {
2439 break :x rhs.ty;
2440 }
2441 };
2442 const casted_lhs = try self.coerce(scope, dest_type, lhs);
2443 const casted_rhs = try self.coerce(scope, dest_type, rhs);
2444 return self.addBinOp(b, src, dest_type, Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
2445 }
2446 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
2447 // For mixed signed and unsigned integers, implicit cast both operands to a signed
2448 // integer with + 1 bit.
2449 // For mixed floats and integers, extract the integer part from the float, cast that to
2450 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
2451 // add/subtract 1.
2452 const lhs_is_signed = if (lhs.value()) |lhs_val|
2453 lhs_val.compareWithZero(.lt)
2454 else
2455 (lhs.ty.isFloat() or lhs.ty.isSignedInt());
2456 const rhs_is_signed = if (rhs.value()) |rhs_val|
2457 rhs_val.compareWithZero(.lt)
2458 else
2459 (rhs.ty.isFloat() or rhs.ty.isSignedInt());
2460 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
2461
2462 var dest_float_type: ?Type = null;
2463
2464 var lhs_bits: usize = undefined;
2465 if (lhs.value()) |lhs_val| {
2466 if (lhs_val.isUndef())
2467 return self.constUndef(scope, src, Type.initTag(.bool));
2468 const is_unsigned = if (lhs_is_float) x: {
2469 var bigint_space: Value.BigIntSpace = undefined;
2470 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(self.gpa);
2471 defer bigint.deinit();
2472 const zcmp = lhs_val.orderAgainstZero();
2473 if (lhs_val.floatHasFraction()) {
2474 switch (op) {
2475 .eq => return self.constBool(scope, src, false),
2476 .neq => return self.constBool(scope, src, true),
2477 else => {},
2478 }
2479 if (zcmp == .lt) {
2480 try bigint.addScalar(bigint.toConst(), -1);
2481 } else {
2482 try bigint.addScalar(bigint.toConst(), 1);
2483 }
2484 }
2485 lhs_bits = bigint.toConst().bitCountTwosComp();
2486 break :x (zcmp != .lt);
2487 } else x: {
2488 lhs_bits = lhs_val.intBitCountTwosComp();
2489 break :x (lhs_val.orderAgainstZero() != .lt);
2490 };
2491 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
2492 } else if (lhs_is_float) {
2493 dest_float_type = lhs.ty;
2494 } else {
2495 const int_info = lhs.ty.intInfo(self.getTarget());
2496 lhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
2497 }
2498
2499 var rhs_bits: usize = undefined;
2500 if (rhs.value()) |rhs_val| {
2501 if (rhs_val.isUndef())
2502 return self.constUndef(scope, src, Type.initTag(.bool));
2503 const is_unsigned = if (rhs_is_float) x: {
2504 var bigint_space: Value.BigIntSpace = undefined;
2505 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(self.gpa);
2506 defer bigint.deinit();
2507 const zcmp = rhs_val.orderAgainstZero();
2508 if (rhs_val.floatHasFraction()) {
2509 switch (op) {
2510 .eq => return self.constBool(scope, src, false),
2511 .neq => return self.constBool(scope, src, true),
2512 else => {},
2513 }
2514 if (zcmp == .lt) {
2515 try bigint.addScalar(bigint.toConst(), -1);
2516 } else {
2517 try bigint.addScalar(bigint.toConst(), 1);
2518 }
2519 }
2520 rhs_bits = bigint.toConst().bitCountTwosComp();
2521 break :x (zcmp != .lt);
2522 } else x: {
2523 rhs_bits = rhs_val.intBitCountTwosComp();
2524 break :x (rhs_val.orderAgainstZero() != .lt);
2525 };
2526 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
2527 } else if (rhs_is_float) {
2528 dest_float_type = rhs.ty;
2529 } else {
2530 const int_info = rhs.ty.intInfo(self.getTarget());
2531 rhs_bits = int_info.bits + @boolToInt(!int_info.signed and dest_int_is_signed);
2532 }
2533
2534 const dest_type = if (dest_float_type) |ft| ft else blk: {
2535 const max_bits = std.math.max(lhs_bits, rhs_bits);
2536 const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {
2537 error.Overflow => return self.fail(scope, src, "{} exceeds maximum integer bit count", .{max_bits}),
2538 };
2539 break :blk try self.makeIntType(scope, dest_int_is_signed, casted_bits);
2540 };
2541 const casted_lhs = try self.coerce(scope, dest_type, lhs);
2542 const casted_rhs = try self.coerce(scope, dest_type, rhs);
2543
2544 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
2545}
2546
2547fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2548 if (inst.value()) |val| {
2549 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2550 }
2551
2552 const b = try self.requireRuntimeBlock(scope, inst.src);
2553 return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
2554}
2555
2556fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
2557 if (signed) {
2558 const int_payload = try scope.arena().create(Type.Payload.IntSigned);
2559 int_payload.* = .{ .bits = bits };
2560 return Type.initPayload(&int_payload.base);
2561 } else {
2562 const int_payload = try scope.arena().create(Type.Payload.IntUnsigned);
2563 int_payload.* = .{ .bits = bits };
2564 return Type.initPayload(&int_payload.base);
2565 }
2566}
2567
2568pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
2569 if (instructions.len == 0)
2570 return Type.initTag(.noreturn);
2571
2572 if (instructions.len == 1)
2573 return instructions[0].ty;
2574
2575 var prev_inst = instructions[0];
2576 for (instructions[1..]) |next_inst| {
2577 if (next_inst.ty.eql(prev_inst.ty))
2578 continue;
2579 if (next_inst.ty.zigTypeTag() == .NoReturn)
2580 continue;
2581 if (prev_inst.ty.zigTypeTag() == .NoReturn) {
2582 prev_inst = next_inst;
2583 continue;
2584 }
2585 if (next_inst.ty.zigTypeTag() == .Undefined)
2586 continue;
2587 if (prev_inst.ty.zigTypeTag() == .Undefined) {
2588 prev_inst = next_inst;
2589 continue;
2590 }
2591 if (prev_inst.ty.isInt() and
2592 next_inst.ty.isInt() and
2593 prev_inst.ty.isSignedInt() == next_inst.ty.isSignedInt())
2594 {
2595 if (prev_inst.ty.intInfo(self.getTarget()).bits < next_inst.ty.intInfo(self.getTarget()).bits) {
2596 prev_inst = next_inst;
2597 }
2598 continue;
2599 }
2600 if (prev_inst.ty.isFloat() and next_inst.ty.isFloat()) {
2601 if (prev_inst.ty.floatBits(self.getTarget()) < next_inst.ty.floatBits(self.getTarget())) {
2602 prev_inst = next_inst;
2603 }
2604 continue;
2605 }
2606
2607 // TODO error notes pointing out each type
2608 return self.fail(scope, next_inst.src, "incompatible types: '{}' and '{}'", .{ prev_inst.ty, next_inst.ty });
2609 }
2610
2611 return prev_inst.ty;
2612}
2613
2614pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2615 // If the types are the same, we can return the operand.
2616 if (dest_type.eql(inst.ty))
2617 return inst;
2618
2619 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
2620 if (in_memory_result == .ok) {
2621 return self.bitcast(scope, dest_type, inst);
2622 }
2623
2624 // undefined to anything
2625 if (inst.value()) |val| {
2626 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
2627 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2628 }
2629 }
2630 assert(inst.ty.zigTypeTag() != .Undefined);
2631
2632 // null to ?T
2633 if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
2634 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
2635 }
2636
2637 // T to ?T
2638 if (dest_type.zigTypeTag() == .Optional) {
2639 var buf: Type.Payload.PointerSimple = undefined;
2640 const child_type = dest_type.optionalChild(&buf);
2641 if (child_type.eql(inst.ty)) {
2642 return self.wrapOptional(scope, dest_type, inst);
2643 } else if (try self.coerceNum(scope, child_type, inst)) |some| {
2644 return self.wrapOptional(scope, dest_type, some);
2645 }
2646 }
2647
2648 // *[N]T to []T
2649 if (inst.ty.isSinglePointer() and dest_type.isSlice() and
2650 (!inst.ty.isConstPtr() or dest_type.isConstPtr()))
2651 {
2652 const array_type = inst.ty.elemType();
2653 const dst_elem_type = dest_type.elemType();
2654 if (array_type.zigTypeTag() == .Array and
2655 coerceInMemoryAllowed(dst_elem_type, array_type.elemType()) == .ok)
2656 {
2657 return self.coerceArrayPtrToSlice(scope, dest_type, inst);
2658 }
2659 }
2660
2661 // comptime known number to other number
2662 if (try self.coerceNum(scope, dest_type, inst)) |some|
2663 return some;
2664
2665 // integer widening
2666 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
2667 assert(inst.value() == null); // handled above
2668
2669 const src_info = inst.ty.intInfo(self.getTarget());
2670 const dst_info = dest_type.intInfo(self.getTarget());
2671 if ((src_info.signed == dst_info.signed and dst_info.bits >= src_info.bits) or
2672 // small enough unsigned ints can get casted to large enough signed ints
2673 (src_info.signed and !dst_info.signed and dst_info.bits > src_info.bits))
2674 {
2675 const b = try self.requireRuntimeBlock(scope, inst.src);
2676 return self.addUnOp(b, inst.src, dest_type, .intcast, inst);
2677 }
2678 }
2679
2680 // float widening
2681 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
2682 assert(inst.value() == null); // handled above
2683
2684 const src_bits = inst.ty.floatBits(self.getTarget());
2685 const dst_bits = dest_type.floatBits(self.getTarget());
2686 if (dst_bits >= src_bits) {
2687 const b = try self.requireRuntimeBlock(scope, inst.src);
2688 return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);
2689 }
2690 }
2691
2692 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
2693}
2694
2695pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !?*Inst {
2696 const val = inst.value() orelse return null;
2697 const src_zig_tag = inst.ty.zigTypeTag();
2698 const dst_zig_tag = dest_type.zigTypeTag();
2699
2700 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
2701 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2702 if (val.floatHasFraction()) {
2703 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
2704 }
2705 return self.fail(scope, inst.src, "TODO float to int", .{});
2706 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2707 if (!val.intFitsInType(dest_type, self.getTarget())) {
2708 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
2709 }
2710 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2711 }
2712 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
2713 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
2714 const res = val.floatCast(scope.arena(), dest_type, self.getTarget()) catch |err| switch (err) {
2715 error.Overflow => return self.fail(
2716 scope,
2717 inst.src,
2718 "cast of value {} to type '{}' loses information",
2719 .{ val, dest_type },
2720 ),
2721 error.OutOfMemory => return error.OutOfMemory,
2722 };
2723 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
2724 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
2725 return self.fail(scope, inst.src, "TODO int to float", .{});
2726 }
2727 }
2728 return null;
2729}
2730
2731pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
2732 if (ptr.ty.isConstPtr())
2733 return self.fail(scope, src, "cannot assign to constant", .{});
2734
2735 const elem_ty = ptr.ty.elemType();
2736 const value = try self.coerce(scope, elem_ty, uncasted_value);
2737 if (elem_ty.onePossibleValue() != null)
2738 return self.constVoid(scope, src);
2739
2740 // TODO handle comptime pointer writes
2741 // TODO handle if the element type requires comptime
2742
2743 const b = try self.requireRuntimeBlock(scope, src);
2744 return self.addBinOp(b, src, Type.initTag(.void), .store, ptr, value);
2745}
2746
2747pub fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2748 if (inst.value()) |val| {
2749 // Keep the comptime Value representation; take the new type.
2750 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2751 }
2752 // TODO validate the type size and other compile errors
2753 const b = try self.requireRuntimeBlock(scope, inst.src);
2754 return self.addUnOp(b, inst.src, dest_type, .bitcast, inst);
2755}
2756
2757fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
2758 if (inst.value()) |val| {
2759 // The comptime Value representation is compatible with both types.
2760 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
2761 }
2762 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
2763}
2764
2765pub fn fail(self: *Module, scope: *Scope, src: usize, comptime format: []const u8, args: anytype) InnerError {
2766 @setCold(true);
2767 const err_msg = try Compilation.ErrorMsg.create(self.gpa, src, format, args);
2768 return self.failWithOwnedErrorMsg(scope, src, err_msg);
2769}
2770
2771pub fn failTok(
2772 self: *Module,
2773 scope: *Scope,
2774 token_index: ast.TokenIndex,
2775 comptime format: []const u8,
2776 args: anytype,
2777) InnerError {
2778 @setCold(true);
2779 const src = scope.tree().token_locs[token_index].start;
2780 return self.fail(scope, src, format, args);
2781}
2782
2783pub fn failNode(
2784 self: *Module,
2785 scope: *Scope,
2786 ast_node: *ast.Node,
2787 comptime format: []const u8,
2788 args: anytype,
2789) InnerError {
2790 @setCold(true);
2791 const src = scope.tree().token_locs[ast_node.firstToken()].start;
2792 return self.fail(scope, src, format, args);
2793}
2794
2795fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, src: usize, err_msg: *Compilation.ErrorMsg) InnerError {
2796 {
2797 errdefer err_msg.destroy(self.gpa);
2798 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
2799 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
2800 }
2801 switch (scope.tag) {
2802 .decl => {
2803 const decl = scope.cast(Scope.DeclAnalysis).?.decl;
2804 decl.analysis = .sema_failure;
2805 decl.generation = self.generation;
2806 self.failed_decls.putAssumeCapacityNoClobber(decl, err_msg);
2807 },
2808 .block => {
2809 const block = scope.cast(Scope.Block).?;
2810 if (block.func) |func| {
2811 func.analysis = .sema_failure;
2812 } else {
2813 block.decl.analysis = .sema_failure;
2814 block.decl.generation = self.generation;
2815 }
2816 self.failed_decls.putAssumeCapacityNoClobber(block.decl, err_msg);
2817 },
2818 .gen_zir => {
2819 const gen_zir = scope.cast(Scope.GenZIR).?;
2820 gen_zir.decl.analysis = .sema_failure;
2821 gen_zir.decl.generation = self.generation;
2822 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
2823 },
2824 .local_val => {
2825 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
2826 gen_zir.decl.analysis = .sema_failure;
2827 gen_zir.decl.generation = self.generation;
2828 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
2829 },
2830 .local_ptr => {
2831 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
2832 gen_zir.decl.analysis = .sema_failure;
2833 gen_zir.decl.generation = self.generation;
2834 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
2835 },
2836 .zir_module => {
2837 const zir_module = scope.cast(Scope.ZIRModule).?;
2838 zir_module.status = .loaded_sema_failure;
2839 self.failed_files.putAssumeCapacityNoClobber(scope, err_msg);
2840 },
2841 .file => unreachable,
2842 .container => unreachable,
2843 }
2844 return error.AnalysisFail;
2845}
2846
2847const InMemoryCoercionResult = enum {
2848 ok,
2849 no_match,
2850};
2851
2852fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
2853 if (dest_type.eql(src_type))
2854 return .ok;
2855
2856 // TODO: implement more of this function
2857
2858 return .no_match;
2859}
2860
2861fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {
2862 return @bitCast(u128, a) == @bitCast(u128, b);
2863}
2864
2865pub fn intAdd(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
2866 // TODO is this a performance issue? maybe we should try the operation without
2867 // resorting to BigInt first.
2868 var lhs_space: Value.BigIntSpace = undefined;
2869 var rhs_space: Value.BigIntSpace = undefined;
2870 const lhs_bigint = lhs.toBigInt(&lhs_space);
2871 const rhs_bigint = rhs.toBigInt(&rhs_space);
2872 const limbs = try allocator.alloc(
2873 std.math.big.Limb,
2874 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
2875 );
2876 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2877 result_bigint.add(lhs_bigint, rhs_bigint);
2878 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2879
2880 const val_payload = if (result_bigint.positive) blk: {
2881 const val_payload = try allocator.create(Value.Payload.IntBigPositive);
2882 val_payload.* = .{ .limbs = result_limbs };
2883 break :blk &val_payload.base;
2884 } else blk: {
2885 const val_payload = try allocator.create(Value.Payload.IntBigNegative);
2886 val_payload.* = .{ .limbs = result_limbs };
2887 break :blk &val_payload.base;
2888 };
2889
2890 return Value.initPayload(val_payload);
2891}
2892
2893pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
2894 // TODO is this a performance issue? maybe we should try the operation without
2895 // resorting to BigInt first.
2896 var lhs_space: Value.BigIntSpace = undefined;
2897 var rhs_space: Value.BigIntSpace = undefined;
2898 const lhs_bigint = lhs.toBigInt(&lhs_space);
2899 const rhs_bigint = rhs.toBigInt(&rhs_space);
2900 const limbs = try allocator.alloc(
2901 std.math.big.Limb,
2902 std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
2903 );
2904 var result_bigint = BigIntMutable{ .limbs = limbs, .positive = undefined, .len = undefined };
2905 result_bigint.sub(lhs_bigint, rhs_bigint);
2906 const result_limbs = result_bigint.limbs[0..result_bigint.len];
2907
2908 const val_payload = if (result_bigint.positive) blk: {
2909 const val_payload = try allocator.create(Value.Payload.IntBigPositive);
2910 val_payload.* = .{ .limbs = result_limbs };
2911 break :blk &val_payload.base;
2912 } else blk: {
2913 const val_payload = try allocator.create(Value.Payload.IntBigNegative);
2914 val_payload.* = .{ .limbs = result_limbs };
2915 break :blk &val_payload.base;
2916 };
2917
2918 return Value.initPayload(val_payload);
2919}
2920
2921pub fn floatAdd(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
2922 var bit_count = switch (float_type.tag()) {
2923 .comptime_float => 128,
2924 else => float_type.floatBits(self.getTarget()),
2925 };
2926
2927 const allocator = scope.arena();
2928 const val_payload = switch (bit_count) {
2929 16 => {
2930 return self.fail(scope, src, "TODO Implement addition for soft floats", .{});
2931 },
2932 32 => blk: {
2933 const lhs_val = lhs.toFloat(f32);
2934 const rhs_val = rhs.toFloat(f32);
2935 const val_payload = try allocator.create(Value.Payload.Float_32);
2936 val_payload.* = .{ .val = lhs_val + rhs_val };
2937 break :blk &val_payload.base;
2938 },
2939 64 => blk: {
2940 const lhs_val = lhs.toFloat(f64);
2941 const rhs_val = rhs.toFloat(f64);
2942 const val_payload = try allocator.create(Value.Payload.Float_64);
2943 val_payload.* = .{ .val = lhs_val + rhs_val };
2944 break :blk &val_payload.base;
2945 },
2946 128 => {
2947 return self.fail(scope, src, "TODO Implement addition for big floats", .{});
2948 },
2949 else => unreachable,
2950 };
2951
2952 return Value.initPayload(val_payload);
2953}
2954
2955pub fn floatSub(self: *Module, scope: *Scope, float_type: Type, src: usize, lhs: Value, rhs: Value) !Value {
2956 var bit_count = switch (float_type.tag()) {
2957 .comptime_float => 128,
2958 else => float_type.floatBits(self.getTarget()),
2959 };
2960
2961 const allocator = scope.arena();
2962 const val_payload = switch (bit_count) {
2963 16 => {
2964 return self.fail(scope, src, "TODO Implement substraction for soft floats", .{});
2965 },
2966 32 => blk: {
2967 const lhs_val = lhs.toFloat(f32);
2968 const rhs_val = rhs.toFloat(f32);
2969 const val_payload = try allocator.create(Value.Payload.Float_32);
2970 val_payload.* = .{ .val = lhs_val - rhs_val };
2971 break :blk &val_payload.base;
2972 },
2973 64 => blk: {
2974 const lhs_val = lhs.toFloat(f64);
2975 const rhs_val = rhs.toFloat(f64);
2976 const val_payload = try allocator.create(Value.Payload.Float_64);
2977 val_payload.* = .{ .val = lhs_val - rhs_val };
2978 break :blk &val_payload.base;
2979 },
2980 128 => {
2981 return self.fail(scope, src, "TODO Implement substraction for big floats", .{});
2982 },
2983 else => unreachable,
2984 };
2985
2986 return Value.initPayload(val_payload);
2987}
2988
2989pub fn simplePtrType(self: *Module, scope: *Scope, src: usize, elem_ty: Type, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) Allocator.Error!Type {
2990 if (!mutable and size == .Slice and elem_ty.eql(Type.initTag(.u8))) {
2991 return Type.initTag(.const_slice_u8);
2992 }
2993 // TODO stage1 type inference bug
2994 const T = Type.Tag;
2995
2996 const type_payload = try scope.arena().create(Type.Payload.PointerSimple);
2997 type_payload.* = .{
2998 .base = .{
2999 .tag = switch (size) {
3000 .One => if (mutable) T.single_mut_pointer else T.single_const_pointer,
3001 .Many => if (mutable) T.many_mut_pointer else T.many_const_pointer,
3002 .C => if (mutable) T.c_mut_pointer else T.c_const_pointer,
3003 .Slice => if (mutable) T.mut_slice else T.const_slice,
3004 },
3005 },
3006 .pointee_type = elem_ty,
3007 };
3008 return Type.initPayload(&type_payload.base);
3009}
3010
3011pub fn ptrType(
3012 self: *Module,
3013 scope: *Scope,
3014 src: usize,
3015 elem_ty: Type,
3016 sentinel: ?Value,
3017 @"align": u32,
3018 bit_offset: u16,
3019 host_size: u16,
3020 mutable: bool,
3021 @"allowzero": bool,
3022 @"volatile": bool,
3023 size: std.builtin.TypeInfo.Pointer.Size,
3024) Allocator.Error!Type {
3025 assert(host_size == 0 or bit_offset < host_size * 8);
3026
3027 // TODO check if type can be represented by simplePtrType
3028 const type_payload = try scope.arena().create(Type.Payload.Pointer);
3029 type_payload.* = .{
3030 .pointee_type = elem_ty,
3031 .sentinel = sentinel,
3032 .@"align" = @"align",
3033 .bit_offset = bit_offset,
3034 .host_size = host_size,
3035 .@"allowzero" = @"allowzero",
3036 .mutable = mutable,
3037 .@"volatile" = @"volatile",
3038 .size = size,
3039 };
3040 return Type.initPayload(&type_payload.base);
3041}
3042
3043pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
3044 return Type.initPayload(switch (child_type.tag()) {
3045 .single_const_pointer => blk: {
3046 const payload = try scope.arena().create(Type.Payload.PointerSimple);
3047 payload.* = .{
3048 .base = .{ .tag = .optional_single_const_pointer },
3049 .pointee_type = child_type.elemType(),
3050 };
3051 break :blk &payload.base;
3052 },
3053 .single_mut_pointer => blk: {
3054 const payload = try scope.arena().create(Type.Payload.PointerSimple);
3055 payload.* = .{
3056 .base = .{ .tag = .optional_single_mut_pointer },
3057 .pointee_type = child_type.elemType(),
3058 };
3059 break :blk &payload.base;
3060 },
3061 else => blk: {
3062 const payload = try scope.arena().create(Type.Payload.Optional);
3063 payload.* = .{
3064 .child_type = child_type,
3065 };
3066 break :blk &payload.base;
3067 },
3068 });
3069}
3070
3071pub fn arrayType(self: *Module, scope: *Scope, len: u64, sentinel: ?Value, elem_type: Type) Allocator.Error!Type {
3072 if (elem_type.eql(Type.initTag(.u8))) {
3073 if (sentinel) |some| {
3074 if (some.eql(Value.initTag(.zero))) {
3075 const payload = try scope.arena().create(Type.Payload.Array_u8_Sentinel0);
3076 payload.* = .{
3077 .len = len,
3078 };
3079 return Type.initPayload(&payload.base);
3080 }
3081 } else {
3082 const payload = try scope.arena().create(Type.Payload.Array_u8);
3083 payload.* = .{
3084 .len = len,
3085 };
3086 return Type.initPayload(&payload.base);
3087 }
3088 }
3089
3090 if (sentinel) |some| {
3091 const payload = try scope.arena().create(Type.Payload.ArraySentinel);
3092 payload.* = .{
3093 .len = len,
3094 .sentinel = some,
3095 .elem_type = elem_type,
3096 };
3097 return Type.initPayload(&payload.base);
3098 }
3099
3100 const payload = try scope.arena().create(Type.Payload.Array);
3101 payload.* = .{
3102 .len = len,
3103 .elem_type = elem_type,
3104 };
3105 return Type.initPayload(&payload.base);
3106}
3107
3108pub fn errorUnionType(self: *Module, scope: *Scope, error_set: Type, payload: Type) Allocator.Error!Type {
3109 assert(error_set.zigTypeTag() == .ErrorSet);
3110 if (error_set.eql(Type.initTag(.anyerror)) and payload.eql(Type.initTag(.void))) {
3111 return Type.initTag(.anyerror_void_error_union);
3112 }
3113
3114 const result = try scope.arena().create(Type.Payload.ErrorUnion);
3115 result.* = .{
3116 .error_set = error_set,
3117 .payload = payload,
3118 };
3119 return Type.initPayload(&result.base);
3120}
3121
3122pub fn anyframeType(self: *Module, scope: *Scope, return_type: Type) Allocator.Error!Type {
3123 const result = try scope.arena().create(Type.Payload.AnyFrame);
3124 result.* = .{
3125 .return_type = return_type,
3126 };
3127 return Type.initPayload(&result.base);
3128}
3129
3130pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
3131 const zir_module = scope.namespace();
3132 const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
3133 const loc = std.zig.findLineColumn(source, inst.src);
3134 if (inst.tag == .constant) {
3135 std.debug.print("constant ty={} val={} src={}:{}:{}\n", .{
3136 inst.ty,
3137 inst.castTag(.constant).?.val,
3138 zir_module.subFilePath(),
3139 loc.line + 1,
3140 loc.column + 1,
3141 });
3142 } else if (inst.deaths == 0) {
3143 std.debug.print("{} ty={} src={}:{}:{}\n", .{
3144 @tagName(inst.tag),
3145 inst.ty,
3146 zir_module.subFilePath(),
3147 loc.line + 1,
3148 loc.column + 1,
3149 });
3150 } else {
3151 std.debug.print("{} ty={} deaths={b} src={}:{}:{}\n", .{
3152 @tagName(inst.tag),
3153 inst.ty,
3154 inst.deaths,
3155 zir_module.subFilePath(),
3156 loc.line + 1,
3157 loc.column + 1,
3158 });
3159 }
3160}
3161
3162pub const PanicId = enum {
3163 unreach,
3164 unwrap_null,
3165};
3166
3167pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {
3168 const block_inst = try parent_block.arena.create(Inst.Block);
3169 block_inst.* = .{
3170 .base = .{
3171 .tag = Inst.Block.base_tag,
3172 .ty = Type.initTag(.void),
3173 .src = ok.src,
3174 },
3175 .body = .{
3176 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the condbr.
3177 },
3178 };
3179
3180 const ok_body: ir.Body = .{
3181 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the brvoid.
3182 };
3183 const brvoid = try parent_block.arena.create(Inst.BrVoid);
3184 brvoid.* = .{
3185 .base = .{
3186 .tag = .brvoid,
3187 .ty = Type.initTag(.noreturn),
3188 .src = ok.src,
3189 },
3190 .block = block_inst,
3191 };
3192 ok_body.instructions[0] = &brvoid.base;
3193
3194 var fail_block: Scope.Block = .{
3195 .parent = parent_block,
3196 .func = parent_block.func,
3197 .decl = parent_block.decl,
3198 .instructions = .{},
3199 .arena = parent_block.arena,
3200 .is_comptime = parent_block.is_comptime,
3201 };
3202 defer fail_block.instructions.deinit(mod.gpa);
3203
3204 _ = try mod.safetyPanic(&fail_block, ok.src, panic_id);
3205
3206 const fail_body: ir.Body = .{ .instructions = try parent_block.arena.dupe(*Inst, fail_block.instructions.items) };
3207
3208 const condbr = try parent_block.arena.create(Inst.CondBr);
3209 condbr.* = .{
3210 .base = .{
3211 .tag = .condbr,
3212 .ty = Type.initTag(.noreturn),
3213 .src = ok.src,
3214 },
3215 .condition = ok,
3216 .then_body = ok_body,
3217 .else_body = fail_body,
3218 };
3219 block_inst.body.instructions[0] = &condbr.base;
3220
3221 try parent_block.instructions.append(mod.gpa, &block_inst.base);
3222}
3223
3224pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: PanicId) !*Inst {
3225 // TODO Once we have a panic function to call, call it here instead of breakpoint.
3226 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);
3227 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);
3228}
3229
3230pub fn getTarget(self: Module) Target {
3231 return self.comp.bin_file.options.target;
3232}
3233
3234pub fn optimizeMode(self: Module) std.builtin.Mode {
3235 return self.comp.bin_file.options.optimize_mode;
3236}
src-self-hosted/astgen.zig+1-1
......@@ -6,7 +6,7 @@ const Type = @import("type.zig").Type;
66const TypedValue = @import("TypedValue.zig");
77const assert = std.debug.assert;
88const zir = @import("zir.zig");
9const Module = @import("ZigModule.zig");
9const Module = @import("Module.zig");
1010const ast = std.zig.ast;
1111const trace = @import("tracy.zig").trace;
1212const Scope = Module.Scope;
src-self-hosted/codegen.zig+1-1
......@@ -7,7 +7,7 @@ const Type = @import("type.zig").Type;
77const Value = @import("value.zig").Value;
88const TypedValue = @import("TypedValue.zig");
99const link = @import("link.zig");
10const Module = @import("ZigModule.zig");
10const Module = @import("Module.zig");
1111const Compilation = @import("Compilation.zig");
1212const ErrorMsg = Compilation.ErrorMsg;
1313const Target = std.Target;
src-self-hosted/codegen/c.zig+1-1
......@@ -1,7 +1,7 @@
11const std = @import("std");
22
33const link = @import("../link.zig");
4const Module = @import("../ZigModule.zig");
4const Module = @import("../Module.zig");
55
66const Inst = @import("../ir.zig").Inst;
77const Value = @import("../value.zig").Value;
src-self-hosted/codegen/wasm.zig+1-1
......@@ -5,7 +5,7 @@ const assert = std.debug.assert;
55const leb = std.debug.leb;
66const mem = std.mem;
77
8const Module = @import("../ZigModule.zig");
8const Module = @import("../Module.zig");
99const Decl = Module.Decl;
1010const Inst = @import("../ir.zig").Inst;
1111const Type = @import("../type.zig").Type;
src-self-hosted/ir.zig+1-1
......@@ -1,7 +1,7 @@
11const std = @import("std");
22const Value = @import("value.zig").Value;
33const Type = @import("type.zig").Type;
4const Module = @import("ZigModule.zig");
4const Module = @import("Module.zig");
55const assert = std.debug.assert;
66const codegen = @import("codegen.zig");
77const ast = std.zig.ast;
src-self-hosted/link.zig+10-10
......@@ -1,7 +1,7 @@
11const std = @import("std");
22const Allocator = std.mem.Allocator;
33const Compilation = @import("Compilation.zig");
4const ZigModule = @import("ZigModule.zig");
4const Module = @import("Module.zig");
55const fs = std.fs;
66const trace = @import("tracy.zig").trace;
77const Package = @import("Package.zig");
......@@ -23,7 +23,7 @@ pub const Options = struct {
2323 optimize_mode: std.builtin.Mode,
2424 root_name: []const u8,
2525 /// Not every Compilation compiles .zig code! For example you could do `zig build-exe foo.o`.
26 zig_module: ?*ZigModule,
26 module: ?*Module,
2727 dynamic_linker: ?[]const u8 = null,
2828 /// Used for calculating how much space to reserve for symbols in case the binary file
2929 /// does not already have a symbol table.
......@@ -186,7 +186,7 @@ pub const File = struct {
186186
187187 /// May be called before or after updateDeclExports but must be called
188188 /// after allocateDeclIndexes for any given Decl.
189 pub fn updateDecl(base: *File, module: *ZigModule, decl: *ZigModule.Decl) !void {
189 pub fn updateDecl(base: *File, module: *Module, decl: *Module.Decl) !void {
190190 switch (base.tag) {
191191 .coff => return @fieldParentPtr(Coff, "base", base).updateDecl(module, decl),
192192 .elf => return @fieldParentPtr(Elf, "base", base).updateDecl(module, decl),
......@@ -196,7 +196,7 @@ pub const File = struct {
196196 }
197197 }
198198
199 pub fn updateDeclLineNumber(base: *File, module: *ZigModule, decl: *ZigModule.Decl) !void {
199 pub fn updateDeclLineNumber(base: *File, module: *Module, decl: *Module.Decl) !void {
200200 switch (base.tag) {
201201 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclLineNumber(module, decl),
202202 .elf => return @fieldParentPtr(Elf, "base", base).updateDeclLineNumber(module, decl),
......@@ -207,7 +207,7 @@ pub const File = struct {
207207
208208 /// Must be called before any call to updateDecl or updateDeclExports for
209209 /// any given Decl.
210 pub fn allocateDeclIndexes(base: *File, decl: *ZigModule.Decl) !void {
210 pub fn allocateDeclIndexes(base: *File, decl: *Module.Decl) !void {
211211 switch (base.tag) {
212212 .coff => return @fieldParentPtr(Coff, "base", base).allocateDeclIndexes(decl),
213213 .elf => return @fieldParentPtr(Elf, "base", base).allocateDeclIndexes(decl),
......@@ -271,7 +271,7 @@ pub const File = struct {
271271 };
272272 }
273273
274 pub fn freeDecl(base: *File, decl: *ZigModule.Decl) void {
274 pub fn freeDecl(base: *File, decl: *Module.Decl) void {
275275 switch (base.tag) {
276276 .coff => @fieldParentPtr(Coff, "base", base).freeDecl(decl),
277277 .elf => @fieldParentPtr(Elf, "base", base).freeDecl(decl),
......@@ -295,9 +295,9 @@ pub const File = struct {
295295 /// allocateDeclIndexes for any given Decl.
296296 pub fn updateDeclExports(
297297 base: *File,
298 module: *ZigModule,
299 decl: *const ZigModule.Decl,
300 exports: []const *ZigModule.Export,
298 module: *Module,
299 decl: *const Module.Decl,
300 exports: []const *Module.Export,
301301 ) !void {
302302 switch (base.tag) {
303303 .coff => return @fieldParentPtr(Coff, "base", base).updateDeclExports(module, decl, exports),
......@@ -308,7 +308,7 @@ pub const File = struct {
308308 }
309309 }
310310
311 pub fn getDeclVAddr(base: *File, decl: *const ZigModule.Decl) u64 {
311 pub fn getDeclVAddr(base: *File, decl: *const Module.Decl) u64 {
312312 switch (base.tag) {
313313 .coff => return @fieldParentPtr(Coff, "base", base).getDeclVAddr(decl),
314314 .elf => return @fieldParentPtr(Elf, "base", base).getDeclVAddr(decl),
src-self-hosted/link/C.zig+1-1
......@@ -2,7 +2,7 @@ const std = @import("std");
22const mem = std.mem;
33const assert = std.debug.assert;
44const Allocator = std.mem.Allocator;
5const Module = @import("../ZigModule.zig");
5const Module = @import("../Module.zig");
66const Compilation = @import("../Compilation.zig");
77const fs = std.fs;
88const codegen = @import("../codegen/c.zig");
src-self-hosted/link/Coff.zig+1-1
......@@ -7,7 +7,7 @@ const assert = std.debug.assert;
77const fs = std.fs;
88
99const trace = @import("../tracy.zig").trace;
10const Module = @import("../ZigModule.zig");
10const Module = @import("../Module.zig");
1111const Compilation = @import("../Compilation.zig");
1212const codegen = @import("../codegen.zig");
1313const link = @import("../link.zig");
src-self-hosted/link/Elf.zig+10-10
......@@ -3,7 +3,7 @@ const mem = std.mem;
33const assert = std.debug.assert;
44const Allocator = std.mem.Allocator;
55const ir = @import("../ir.zig");
6const Module = @import("../ZigModule.zig");
6const Module = @import("../Module.zig");
77const Compilation = @import("../Compilation.zig");
88const fs = std.fs;
99const elf = std.elf;
......@@ -743,7 +743,7 @@ pub fn flush(self: *Elf, comp: *Compilation) !void {
743743fn flushInner(self: *Elf, comp: *Compilation) !void {
744744 // TODO This linker code currently assumes there is only 1 compilation unit and it corresponds to the
745745 // Zig source code.
746 const zig_module = self.base.options.zig_module orelse return error.LinkingWithoutZigSourceUnimplemented;
746 const module = self.base.options.module orelse return error.LinkingWithoutZigSourceUnimplemented;
747747
748748 const target_endian = self.base.options.target.cpu.arch.endian();
749749 const foreign_endian = target_endian != std.Target.current.cpu.arch.endian();
......@@ -866,8 +866,8 @@ fn flushInner(self: *Elf, comp: *Compilation) !void {
866866 },
867867 }
868868 // Write the form for the compile unit, which must match the abbrev table above.
869 const name_strp = try self.makeDebugString(zig_module.root_pkg.root_src_path);
870 const comp_dir_strp = try self.makeDebugString(zig_module.root_pkg.root_src_directory.path.?);
869 const name_strp = try self.makeDebugString(module.root_pkg.root_src_path);
870 const comp_dir_strp = try self.makeDebugString(module.root_pkg.root_src_directory.path.?);
871871 const producer_strp = try self.makeDebugString(link.producer_string);
872872 // Currently only one compilation unit is supported, so the address range is simply
873873 // identical to the main program header virtual address and memory size.
......@@ -1036,7 +1036,7 @@ fn flushInner(self: *Elf, comp: *Compilation) !void {
10361036 0, // include_directories (none except the compilation unit cwd)
10371037 });
10381038 // file_names[0]
1039 di_buf.appendSliceAssumeCapacity(zig_module.root_pkg.root_src_path); // relative path name
1039 di_buf.appendSliceAssumeCapacity(module.root_pkg.root_src_path); // relative path name
10401040 di_buf.appendSliceAssumeCapacity(&[_]u8{
10411041 0, // null byte for the relative path name
10421042 0, // directory_index
......@@ -1230,7 +1230,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12301230
12311231 // If there is no Zig code to compile, then we should skip flushing the output file because it
12321232 // will not be part of the linker line anyway.
1233 const zig_module_obj_path: ?[]const u8 = if (self.base.options.zig_module) |module| blk: {
1233 const module_obj_path: ?[]const u8 = if (self.base.options.module) |module| blk: {
12341234 try self.flushInner(comp);
12351235
12361236 const obj_basename = self.base.intermediary_basename.?;
......@@ -1270,7 +1270,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
12701270 .failure => return error.NotAllCSourceFilesAvailableToLink,
12711271 .success => |success| _ = try ch.addFile(success.object_path, null),
12721272 };
1273 try ch.addOptionalFile(zig_module_obj_path);
1273 try ch.addOptionalFile(module_obj_path);
12741274 // We can skip hashing libc and libc++ components that we are in charge of building from Zig
12751275 // installation sources because they are always a product of the compiler version + target information.
12761276 ch.hash.addOptional(self.base.options.stack_size_override);
......@@ -1500,7 +1500,7 @@ fn linkWithLLD(self: *Elf, comp: *Compilation) !void {
15001500 .success => |success| try argv.append(success.object_path),
15011501 };
15021502
1503 if (zig_module_obj_path) |p| {
1503 if (module_obj_path) |p| {
15041504 try argv.append(p);
15051505 }
15061506
......@@ -2837,8 +2837,8 @@ fn dbgLineNeededHeaderBytes(self: Elf) u32 {
28372837 directory_count * 8 + file_name_count * 8 +
28382838 // These are encoded as DW.FORM_string rather than DW.FORM_strp as we would like
28392839 // because of a workaround for readelf and gdb failing to understand DWARFv5 correctly.
2840 self.base.options.zig_module.?.root_pkg.root_src_directory.path.?.len +
2841 self.base.options.zig_module.?.root_pkg.root_src_path.len);
2840 self.base.options.module.?.root_pkg.root_src_directory.path.?.len +
2841 self.base.options.module.?.root_pkg.root_src_path.len);
28422842}
28432843
28442844fn dbgInfoNeededHeaderBytes(self: Elf) u32 {
src-self-hosted/link/MachO.zig+1-1
......@@ -12,7 +12,7 @@ const mem = std.mem;
1212const trace = @import("../tracy.zig").trace;
1313const Type = @import("../type.zig").Type;
1414
15const Module = @import("../ZigModule.zig");
15const Module = @import("../Module.zig");
1616const Compilation = @import("../Compilation.zig");
1717const link = @import("../link.zig");
1818const File = link.File;
src-self-hosted/link/Wasm.zig+2-2
......@@ -6,7 +6,7 @@ const assert = std.debug.assert;
66const fs = std.fs;
77const leb = std.debug.leb;
88
9const Module = @import("../ZigModule.zig");
9const Module = @import("../Module.zig");
1010const Compilation = @import("../Compilation.zig");
1111const codegen = @import("../codegen/wasm.zig");
1212const link = @import("../link.zig");
......@@ -165,7 +165,7 @@ pub fn flush(self: *Wasm, comp: *Compilation) !void {
165165 }
166166
167167 // Export section
168 if (self.base.options.zig_module) |module| {
168 if (self.base.options.module) |module| {
169169 const header_offset = try reserveVecSectionHeader(file);
170170 const writer = file.writer();
171171 var count: u32 = 0;
src-self-hosted/main.zig+2-2
......@@ -1232,9 +1232,9 @@ fn updateModule(gpa: *Allocator, comp: *Compilation, zir_out_path: ?[]const u8)
12321232 }
12331233
12341234 if (zir_out_path) |zop| {
1235 const zig_module = comp.bin_file.options.zig_module orelse
1235 const module = comp.bin_file.options.module orelse
12361236 fatal("-femit-zir with no zig source code", .{});
1237 var new_zir_module = try zir.emit(gpa, zig_module);
1237 var new_zir_module = try zir.emit(gpa, module);
12381238 defer new_zir_module.deinit(gpa);
12391239
12401240 const baf = try io.BufferedAtomicFile.create(gpa, fs.cwd(), zop, .{});
src-self-hosted/test.zig+1-1
......@@ -549,7 +549,7 @@ pub const TestContext = struct {
549549 update_node.estimated_total_items = 5;
550550 var emit_node = update_node.start("emit", null);
551551 emit_node.activate();
552 var new_zir_module = try zir.emit(allocator, comp.bin_file.options.zig_module.?);
552 var new_zir_module = try zir.emit(allocator, comp.bin_file.options.module.?);
553553 defer new_zir_module.deinit(allocator);
554554 emit_node.end();
555555
src-self-hosted/type.zig+1-1
......@@ -3,7 +3,7 @@ const Value = @import("value.zig").Value;
33const assert = std.debug.assert;
44const Allocator = std.mem.Allocator;
55const Target = std.Target;
6const Module = @import("ZigModule.zig");
6const Module = @import("Module.zig");
77
88/// This is the raw data, with no bookkeeping, no memory awareness, no de-duplication.
99/// It's important for this type to be small.
src-self-hosted/value.zig+1-1
......@@ -6,7 +6,7 @@ const BigIntConst = std.math.big.int.Const;
66const BigIntMutable = std.math.big.int.Mutable;
77const Target = std.Target;
88const Allocator = std.mem.Allocator;
9const Module = @import("ZigModule.zig");
9const Module = @import("Module.zig");
1010
1111/// This is the raw data, with no bookkeeping, no memory awareness,
1212/// no de-duplication, and no type system awareness.
src-self-hosted/zir.zig+1-1
......@@ -10,7 +10,7 @@ const Type = @import("type.zig").Type;
1010const Value = @import("value.zig").Value;
1111const TypedValue = @import("TypedValue.zig");
1212const ir = @import("ir.zig");
13const IrModule = @import("ZigModule.zig");
13const IrModule = @import("Module.zig");
1414
1515/// This struct is relevent only for the ZIR Module text format. It is not used for
1616/// semantic analysis of Zig source code.
src-self-hosted/zir_sema.zig+1-1
......@@ -16,7 +16,7 @@ const TypedValue = @import("TypedValue.zig");
1616const assert = std.debug.assert;
1717const ir = @import("ir.zig");
1818const zir = @import("zir.zig");
19const Module = @import("ZigModule.zig");
19const Module = @import("Module.zig");
2020const Inst = ir.Inst;
2121const Body = ir.Body;
2222const trace = @import("tracy.zig").trace;