authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-15 23:38:38-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-16 00:03:22-07:00
logaef3e534f5bc59b2572afdb74178d8c8b3fa4481
tree525a4119fc49d3a5c2f38fe45a2c92455c112148
parentf16f25047c511cc5f468da57292a968555c4b791

stage2: *WIP*: rework ZIR memory layout; overhaul source locations

The memory layout for ZIR instructions is completely reworked. See zir.zig for those changes. Some new types: * `zir.Code`: a "finished" set of ZIR instructions. Instead of allocating each instruction independently, there is now a Tag and 8 bytes of data available for all ZIR instructions. Small instructions fit within these 8 bytes; larger ones use 4 bytes for an index into `extra`. There is also `string_bytes` so that we can have 4 byte references to strings. `zir.Inst.Tag` describes how to interpret those 8 bytes of data. - This is shared by all `Block` scopes. * `Module.WipZirCode`: represents an in-progress `zir.Code`. In this structure, the arrays are mutable, and get resized as we add/delete things. There is extra state to keep track of things. This struct is stored on the stack. Once it is finished, it produces an immutable `zir.Code`, which will remain on the heap for the duration of a function's existence. - This is shared by all `GenZir` scopes. * `Sema`: represents in-progress semantic analysis of a `zir.Code`. This data is stored on the stack and is shared among all `Block` scopes. It is now the main "self" argument to everything in the file that was previously named `zir_sema.zig`. Additionally, I moved some logic that was in `Module` into here. `Module.Fn` now stores its parameter names inside the `zir.Code`, instead of inside ZIR instructions. When the TZIR memory layout reworking time comes, codegen will be able to reference this data directly instead of duplicating it. astgen.zig is (so far) almost entirely untouched, but nearly all of it will need to be reworked to adhere to this new memory layout structure. I have no benchmarks to report yet, as I am still working through compile errors and fixing various things that I broke in this branch. Overhaul of Source Locations: Previously we used `usize` everywhere to mean byte offset, but sometimes also mean other stuff. This was error prone and also made us do unnecessary work, and store unnecessary bytes in memory. Now there are more types involved into source locations, and more ways to describe a source location. * AllErrors.Message: embrace the assumption that files always have less than 2 << 32 bytes. * SrcLoc gets more complicated, to model more complicated source locations. * Introduce LazySrcLoc, which can model interesting source locations with very little stored state. Useful for avoiding doing unnecessary work when no compile errors occur. Also, previously, we had `src: usize` on every ZIR instruction. This is no longer the case. Each instruction now determines whether it even cares about source location, and if so, how that source location is stored. This requires more careful work inside `Sema`, but it results in fewer bytes stored on the heap, without compromising accuracy and power of compile error messages. Miscellaneous: * std.zig: string literals have more helpful result values for reporting errors. There is now a lower level API and a higher level API. - side note: I noticed that the string literal logic needs some love. There is some unnecessarily hacky code there. * cut & pasted some TZIR logic that was in zir.zig to ir.zig. This probably broke stuff and needs to get fixed. * Removed type/Enum.zig, type/Union.zig, and type/Struct.zig. I don't think this quite how this code will be organized. Need some more careful planning about how to implement structs, unions, enums. They need to be independent Decls, just like a top level function.

14 files changed, 4822 insertions(+), 4796 deletions(-)

BRANCH_TODO created+126
......@@ -0,0 +1,126 @@
1this is my WIP branch scratch pad, to be deleted before merging into master
2
3Merge TODO list:
4 * fix discrepancy between TZIR wanting src: usize (byte offset) and Sema
5 now providing LazySrcLoc
6 * fix compile errors
7 * don't have an explicit dbg_stmt zir instruction - instead merge it with
8 var decl and assignment instructions, etc.
9 - make it set sema.src where appropriate
10 * remove the LazySrcLoc.todo tag
11 * update astgen.zig
12 * finish updating Sema.zig
13 * finish implementing SrcLoc byteOffset function
14
15
16Performance optimizations to look into:
17 * don't store end index for blocks; rely on last instruction being noreturn
18 * introduce special form for function call statement with 0 or 1 parameters
19 * look into not storing the field name of field access as a string in zir
20 instructions. or, look into introducing interning to string_bytes (local
21 to the owner Decl), or, look into allowing field access based on a token/node
22 and have it reference source code bytes. Another idea: null terminated
23 string variants which avoid having to store the length.
24 - Look into this for enum literals too
25
26
27Random snippets of code that I deleted and need to make sure get
28re-integrated appropriately:
29
30
31fn zirArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
32 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
33 const param_index = b.instructions.items.len;
34 const param_count = fn_ty.fnParamLen();
35 if (param_index >= param_count) {
36 return mod.fail(scope, inst.base.src, "parameter index {d} outside list of length {d}", .{
37 param_index,
38 param_count,
39 });
40 }
41 const param_type = fn_ty.fnParamType(param_index);
42 const name = try scope.arena().dupeZ(u8, inst.positionals.name);
43 return mod.addArg(b, inst.base.src, param_type, name);
44}
45
46
47fn zirReturnVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
48 const tracy = trace(@src());
49 defer tracy.end();
50 const b = try mod.requireFunctionBlock(scope, inst.base.src);
51 if (b.inlining) |inlining| {
52 // We are inlining a function call; rewrite the `retvoid` as a `breakvoid`.
53 const void_inst = try mod.constVoid(scope, inst.base.src);
54 try inlining.merges.results.append(mod.gpa, void_inst);
55 const br = try mod.addBr(b, inst.base.src, inlining.merges.block_inst, void_inst);
56 return &br.base;
57 }
58
59 if (b.func) |func| {
60 // Need to emit a compile error if returning void is not allowed.
61 const void_inst = try mod.constVoid(scope, inst.base.src);
62 const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty;
63 const casted_void = try mod.coerce(scope, fn_ty.fnReturnType(), void_inst);
64 if (casted_void.ty.zigTypeTag() != .Void) {
65 return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, casted_void);
66 }
67 }
68 return mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid);
69}
70
71
72fn zirReturn(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
73 const tracy = trace(@src());
74 defer tracy.end();
75 const operand = try resolveInst(mod, scope, inst.positionals.operand);
76 const b = try mod.requireFunctionBlock(scope, inst.base.src);
77
78 if (b.inlining) |inlining| {
79 // We are inlining a function call; rewrite the `ret` as a `break`.
80 try inlining.merges.results.append(mod.gpa, operand);
81 const br = try mod.addBr(b, inst.base.src, inlining.merges.block_inst, operand);
82 return &br.base;
83 }
84
85 return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, operand);
86}
87
88fn zirPrimitive(mod: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst {
89 const tracy = trace(@src());
90 defer tracy.end();
91 return mod.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue());
92}
93
94
95
96
97 /// Each Decl gets its own string interning, in order to avoid contention when
98 /// using multiple threads to analyze Decls in parallel. Any particular Decl will only
99 /// be touched by a single thread at one time.
100 strings: StringTable = .{},
101
102 /// The string memory referenced here is stored inside the Decl's arena.
103 pub const StringTable = std.StringArrayHashMapUnmanaged(void);
104
105
106
107
108pub fn errSrcLoc(mod: *Module, scope: *Scope, src: LazySrcLoc) SrcLoc {
109 const file_scope = scope.getFileScope();
110 switch (src) {
111 .byte_offset => |off| return .{
112 .file_scope = file_scope,
113 .byte_offset = off,
114 },
115 .token_offset => |off| {
116 @panic("TODO errSrcLoc for token_offset");
117 },
118 .node_offset => |off| {
119 @panic("TODO errSrcLoc for node_offset");
120 },
121 .node_offset_var_decl_ty => |off| {
122 @panic("TODO errSrcLoc for node_offset_var_decl_ty");
123 },
124 }
125}
126
lib/std/zig.zig+1-1
......@@ -11,7 +11,7 @@ pub const Tokenizer = tokenizer.Tokenizer;
1111pub const fmtId = @import("zig/fmt.zig").fmtId;
1212pub const fmtEscapes = @import("zig/fmt.zig").fmtEscapes;
1313pub const parse = @import("zig/parse.zig").parse;
14pub const parseStringLiteral = @import("zig/string_literal.zig").parse;
14pub const string_literal = @import("zig/string_literal.zig");
1515pub const ast = @import("zig/ast.zig");
1616pub const system = @import("zig/system.zig");
1717pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
lib/std/zig/string_literal.zig+82-52
......@@ -6,112 +6,143 @@
66const std = @import("../std.zig");
77const assert = std.debug.assert;
88
9const State = enum {
10 Start,
11 Backslash,
12};
13
149pub const ParseError = error{
1510 OutOfMemory,
11 InvalidStringLiteral,
12};
1613
17 /// When this is returned, index will be the position of the character.
18 InvalidCharacter,
14pub const Result = union(enum) {
15 success,
16 /// Found an invalid character at this index.
17 invalid_character: usize,
18 /// Expected hex digits at this index.
19 expected_hex_digits: usize,
20 /// Invalid hex digits at this index.
21 invalid_hex_escape: usize,
22 /// Invalid unicode escape at this index.
23 invalid_unicode_escape: usize,
24 /// The left brace at this index is missing a matching right brace.
25 missing_matching_brace: usize,
26 /// Expected unicode digits at this index.
27 expected_unicode_digits: usize,
1928};
2029
21/// caller owns returned memory
22pub fn parse(
23 allocator: *std.mem.Allocator,
24 bytes: []const u8,
25 bad_index: *usize, // populated if error.InvalidCharacter is returned
26) ParseError![]u8 {
30/// Parses `bytes` as a Zig string literal and appends the result to `buf`.
31/// Asserts `bytes` has '"' at beginning and end.
32pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory}!Result {
2733 assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"');
34 const slice = bytes[1..];
2835
29 var list = std.ArrayList(u8).init(allocator);
30 errdefer list.deinit();
36 const prev_len = buf.items.len;
37 try buf.ensureCapacity(prev_len + slice.len - 1);
38 errdefer buf.shrinkRetainingCapacity(prev_len);
3139
32 const slice = bytes[1..];
33 try list.ensureCapacity(slice.len - 1);
40 const State = enum {
41 Start,
42 Backslash,
43 };
3444
3545 var state = State.Start;
3646 var index: usize = 0;
37 while (index < slice.len) : (index += 1) {
47 while (true) : (index += 1) {
3848 const b = slice[index];
3949
4050 switch (state) {
4151 State.Start => switch (b) {
4252 '\\' => state = State.Backslash,
4353 '\n' => {
44 bad_index.* = index;
45 return error.InvalidCharacter;
54 return Result{ .invalid_character = index };
4655 },
47 '"' => return list.toOwnedSlice(),
48 else => try list.append(b),
56 '"' => return Result.success,
57 else => try buf.append(b),
4958 },
5059 State.Backslash => switch (b) {
5160 'n' => {
52 try list.append('\n');
61 try buf.append('\n');
5362 state = State.Start;
5463 },
5564 'r' => {
56 try list.append('\r');
65 try buf.append('\r');
5766 state = State.Start;
5867 },
5968 '\\' => {
60 try list.append('\\');
69 try buf.append('\\');
6170 state = State.Start;
6271 },
6372 't' => {
64 try list.append('\t');
73 try buf.append('\t');
6574 state = State.Start;
6675 },
6776 '\'' => {
68 try list.append('\'');
77 try buf.append('\'');
6978 state = State.Start;
7079 },
7180 '"' => {
72 try list.append('"');
81 try buf.append('"');
7382 state = State.Start;
7483 },
7584 'x' => {
7685 // TODO: add more/better/broader tests for this.
7786 const index_continue = index + 3;
78 if (slice.len >= index_continue)
79 if (std.fmt.parseUnsigned(u8, slice[index + 1 .. index_continue], 16)) |char| {
80 try list.append(char);
81 state = State.Start;
82 index = index_continue - 1; // loop-header increments again
83 continue;
84 } else |_| {};
85
86 bad_index.* = index;
87 return error.InvalidCharacter;
87 if (slice.len < index_continue) {
88 return Result{ .expected_hex_digits = index };
89 }
90 if (std.fmt.parseUnsigned(u8, slice[index + 1 .. index_continue], 16)) |byte| {
91 try buf.append(byte);
92 state = State.Start;
93 index = index_continue - 1; // loop-header increments again
94 } else |err| switch (err) {
95 error.Overflow => unreachable, // 2 digits base 16 fits in a u8.
96 error.InvalidCharacter => {
97 return Result{ .invalid_hex_escape = index + 1 };
98 },
99 }
88100 },
89101 'u' => {
90102 // TODO: add more/better/broader tests for this.
91 if (slice.len > index + 2 and slice[index + 1] == '{')
103 // TODO: we are already inside a nice, clean state machine... use it
104 // instead of this hacky code.
105 if (slice.len > index + 2 and slice[index + 1] == '{') {
92106 if (std.mem.indexOfScalarPos(u8, slice[0..std.math.min(index + 9, slice.len)], index + 3, '}')) |index_end| {
93107 const hex_str = slice[index + 2 .. index_end];
94108 if (std.fmt.parseUnsigned(u32, hex_str, 16)) |uint| {
95109 if (uint <= 0x10ffff) {
96 try list.appendSlice(std.mem.toBytes(uint)[0..]);
110 try buf.appendSlice(std.mem.toBytes(uint)[0..]);
97111 state = State.Start;
98112 index = index_end; // loop-header increments
99113 continue;
100114 }
101 } else |_| {}
102 };
103
104 bad_index.* = index;
105 return error.InvalidCharacter;
115 } else |err| switch (err) {
116 error.Overflow => unreachable,
117 error.InvalidCharacter => {
118 return Result{ .invalid_unicode_escape = index + 1 };
119 },
120 }
121 } else {
122 return Result{ .missing_matching_rbrace = index + 1 };
123 }
124 } else {
125 return Result{ .expected_unicode_digits = index };
126 }
106127 },
107128 else => {
108 bad_index.* = index;
109 return error.InvalidCharacter;
129 return Result{ .invalid_character = index };
110130 },
111131 },
112132 }
133 } else unreachable; // TODO should not need else unreachable on while(true)
134}
135
136/// Higher level API. Does not return extra info about parse errors.
137/// Caller owns returned memory.
138pub fn parseAlloc(allocator: *std.mem.Allocator, bytes: []const u8) ParseError![]u8 {
139 var buf = std.ArrayList(u8).init(allocator);
140 defer buf.deinit();
141
142 switch (try parseAppend(&buf, bytes)) {
143 .success => return buf.toOwnedSlice(),
144 else => return error.InvalidStringLiteral,
113145 }
114 unreachable;
115146}
116147
117148test "parse" {
......@@ -121,9 +152,8 @@ test "parse" {
121152 var fixed_buf_mem: [32]u8 = undefined;
122153 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buf_mem[0..]);
123154 var alloc = &fixed_buf_alloc.allocator;
124 var bad_index: usize = undefined;
125155
126 expect(eql(u8, "foo", try parse(alloc, "\"foo\"", &bad_index)));
127 expect(eql(u8, "foo", try parse(alloc, "\"f\x6f\x6f\"", &bad_index)));
128 expect(eql(u8, "f💯", try parse(alloc, "\"f\u{1f4af}\"", &bad_index)));
156 expect(eql(u8, "foo", try parseAlloc(alloc, "\"foo\"")));
157 expect(eql(u8, "foo", try parseAlloc(alloc, "\"f\x6f\x6f\"")));
158 expect(eql(u8, "f💯", try parseAlloc(alloc, "\"f\u{1f4af}\"")));
129159}
src/Compilation.zig+19-17
......@@ -259,7 +259,7 @@ pub const CObject = struct {
259259/// To support incremental compilation, errors are stored in various places
260260/// so that they can be created and destroyed appropriately. This structure
261261/// is used to collect all the errors from the various places into one
262/// convenient place for API users to consume. It is allocated into 1 heap
262/// convenient place for API users to consume. It is allocated into 1 arena
263263/// and freed all at once.
264264pub const AllErrors = struct {
265265 arena: std.heap.ArenaAllocator.State,
......@@ -267,11 +267,11 @@ pub const AllErrors = struct {
267267
268268 pub const Message = union(enum) {
269269 src: struct {
270 src_path: []const u8,
271 line: usize,
272 column: usize,
273 byte_offset: usize,
274270 msg: []const u8,
271 src_path: []const u8,
272 line: u32,
273 column: u32,
274 byte_offset: u32,
275275 notes: []Message = &.{},
276276 },
277277 plain: struct {
......@@ -316,29 +316,31 @@ pub const AllErrors = struct {
316316 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
317317 for (notes) |*note, i| {
318318 const module_note = module_err_msg.notes[i];
319 const source = try module_note.src_loc.file_scope.getSource(module);
320 const loc = std.zig.findLineColumn(source, module_note.src_loc.byte_offset);
321 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;
319 const source = try module_note.src_loc.fileScope().getSource(module);
320 const byte_offset = try module_note.src_loc.byteOffset(module);
321 const loc = std.zig.findLineColumn(source, byte_offset);
322 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
322323 note.* = .{
323324 .src = .{
324325 .src_path = try arena.allocator.dupe(u8, sub_file_path),
325326 .msg = try arena.allocator.dupe(u8, module_note.msg),
326 .byte_offset = module_note.src_loc.byte_offset,
327 .line = loc.line,
328 .column = loc.column,
327 .byte_offset = byte_offset,
328 .line = @intCast(u32, loc.line),
329 .column = @intCast(u32, loc.column),
329330 },
330331 };
331332 }
332 const source = try module_err_msg.src_loc.file_scope.getSource(module);
333 const loc = std.zig.findLineColumn(source, module_err_msg.src_loc.byte_offset);
334 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;
333 const source = try module_err_msg.src_loc.fileScope().getSource(module);
334 const byte_offset = try module_err_msg.src_loc.byteOffset(module);
335 const loc = std.zig.findLineColumn(source, byte_offset);
336 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
335337 try errors.append(.{
336338 .src = .{
337339 .src_path = try arena.allocator.dupe(u8, sub_file_path),
338340 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),
339 .byte_offset = module_err_msg.src_loc.byte_offset,
340 .line = loc.line,
341 .column = loc.column,
341 .byte_offset = byte_offset,
342 .line = @intCast(u32, loc.line),
343 .column = @intCast(u32, loc.column),
342344 .notes = notes,
343345 },
344346 });
src/Module.zig+1074-1729
......@@ -1,31 +1,32 @@
1const Module = @This();
1//! Compilation of all Zig source code is represented by one `Module`.
2//! Each `Compilation` has exactly one or zero `Module`, depending on whether
3//! there is or is not any zig source code, respectively.
4
25const std = @import("std");
3const Compilation = @import("Compilation.zig");
46const mem = std.mem;
57const Allocator = std.mem.Allocator;
68const ArrayListUnmanaged = std.ArrayListUnmanaged;
7const Value = @import("value.zig").Value;
8const Type = @import("type.zig").Type;
9const TypedValue = @import("TypedValue.zig");
109const assert = std.debug.assert;
1110const log = std.log.scoped(.module);
1211const BigIntConst = std.math.big.int.Const;
1312const BigIntMutable = std.math.big.int.Mutable;
1413const Target = std.Target;
14const ast = std.zig.ast;
15
16const Module = @This();
17const Compilation = @import("Compilation.zig");
18const Value = @import("value.zig").Value;
19const Type = @import("type.zig").Type;
20const TypedValue = @import("TypedValue.zig");
1521const Package = @import("Package.zig");
1622const link = @import("link.zig");
1723const ir = @import("ir.zig");
1824const zir = @import("zir.zig");
19const Inst = ir.Inst;
20const Body = ir.Body;
21const ast = std.zig.ast;
2225const trace = @import("tracy.zig").trace;
2326const astgen = @import("astgen.zig");
24const zir_sema = @import("zir_sema.zig");
27const Sema = @import("zir_sema.zig"); // TODO rename this file
2528const target_util = @import("target.zig");
2629
27const default_eval_branch_quota = 1000;
28
2930/// General-purpose allocator. Used for both temporary and long-term storage.
3031gpa: *Allocator,
3132comp: *Compilation,
......@@ -106,8 +107,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .{},
106107
107108pub const Export = struct {
108109 options: std.builtin.ExportOptions,
109 /// Byte offset into the file that contains the export directive.
110 src: usize,
110 src: LazySrcLoc,
111111 /// Represents the position of the export, if any, in the output file.
112112 link: link.File.Export,
113113 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
......@@ -132,11 +132,12 @@ pub const DeclPlusEmitH = struct {
132132};
133133
134134pub const Decl = struct {
135 /// This name is relative to the containing namespace of the decl. It uses a null-termination
136 /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed
137 /// in symbol names, because executable file formats use null-terminated strings for symbol names.
138 /// All Decls have names, even values that are not bound to a zig namespace. This is necessary for
139 /// mapping them to an address in the output file.
135 /// This name is relative to the containing namespace of the decl. It uses
136 /// null-termination to save bytes, since there can be a lot of decls in a
137 /// compilation. The null byte is not allowed in symbol names, because
138 /// executable file formats use null-terminated strings for symbol names.
139 /// All Decls have names, even values that are not bound to a zig namespace.
140 /// This is necessary for mapping them to an address in the output file.
140141 /// Memory owned by this decl, using Module's allocator.
141142 name: [*:0]const u8,
142143 /// The direct parent container of the Decl.
......@@ -219,73 +220,82 @@ pub const Decl = struct {
219220 /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself`
220221 pub const DepsTable = std.ArrayHashMapUnmanaged(*Decl, void, std.array_hash_map.getAutoHashFn(*Decl), std.array_hash_map.getAutoEqlFn(*Decl), false);
221222
222 pub fn destroy(self: *Decl, module: *Module) void {
223 pub fn destroy(decl: *Decl, module: *Module) void {
223224 const gpa = module.gpa;
224 gpa.free(mem.spanZ(self.name));
225 if (self.typedValueManaged()) |tvm| {
225 gpa.free(mem.spanZ(decl.name));
226 if (decl.typedValueManaged()) |tvm| {
226227 tvm.deinit(gpa);
227228 }
228 self.dependants.deinit(gpa);
229 self.dependencies.deinit(gpa);
229 decl.dependants.deinit(gpa);
230 decl.dependencies.deinit(gpa);
230231 if (module.emit_h != null) {
231 const decl_plus_emit_h = @fieldParentPtr(DeclPlusEmitH, "decl", self);
232 const decl_plus_emit_h = @fieldParentPtr(DeclPlusEmitH, "decl", decl);
232233 decl_plus_emit_h.emit_h.fwd_decl.deinit(gpa);
233234 gpa.destroy(decl_plus_emit_h);
234235 } else {
235 gpa.destroy(self);
236 gpa.destroy(decl);
236237 }
237238 }
238239
239 pub fn srcLoc(self: Decl) SrcLoc {
240 pub fn srcLoc(decl: *const Decl) SrcLoc {
240241 return .{
241 .byte_offset = self.src(),
242 .file_scope = self.getFileScope(),
242 .decl = decl,
243 .byte_offset = 0,
243244 };
244245 }
245246
246 pub fn src(self: Decl) usize {
247 const tree = &self.container.file_scope.tree;
248 const decl_node = tree.rootDecls()[self.src_index];
249 return tree.tokens.items(.start)[tree.firstToken(decl_node)];
247 pub fn srcNode(decl: Decl) u32 {
248 const tree = &decl.container.file_scope.tree;
249 return tree.rootDecls()[decl.src_index];
250 }
251
252 pub fn srcToken(decl: Decl) u32 {
253 const tree = &decl.container.file_scope.tree;
254 return tree.firstToken(decl.srcNode());
255 }
256
257 pub fn srcByteOffset(decl: Decl) u32 {
258 const tree = &decl.container.file_scope.tree;
259 return tree.tokens.items(.start)[decl.srcToken()];
250260 }
251261
252 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {
253 return self.container.fullyQualifiedNameHash(mem.spanZ(self.name));
262 pub fn fullyQualifiedNameHash(decl: Decl) Scope.NameHash {
263 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
254264 }
255265
256 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {
257 const tvm = self.typedValueManaged() orelse return error.AnalysisFail;
266 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
267 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
258268 return tvm.typed_value;
259269 }
260270
261 pub fn value(self: *Decl) error{AnalysisFail}!Value {
262 return (try self.typedValue()).val;
271 pub fn value(decl: *Decl) error{AnalysisFail}!Value {
272 return (try decl.typedValue()).val;
263273 }
264274
265 pub fn dump(self: *Decl) void {
266 const loc = std.zig.findLineColumn(self.scope.source.bytes, self.src);
275 pub fn dump(decl: *Decl) void {
276 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src);
267277 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{
268 self.scope.sub_file_path,
278 decl.scope.sub_file_path,
269279 loc.line + 1,
270280 loc.column + 1,
271 mem.spanZ(self.name),
272 @tagName(self.analysis),
281 mem.spanZ(decl.name),
282 @tagName(decl.analysis),
273283 });
274 if (self.typedValueManaged()) |tvm| {
284 if (decl.typedValueManaged()) |tvm| {
275285 std.debug.print(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });
276286 }
277287 std.debug.print("\n", .{});
278288 }
279289
280 pub fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {
281 switch (self.typed_value) {
290 pub fn typedValueManaged(decl: *Decl) ?*TypedValue.Managed {
291 switch (decl.typed_value) {
282292 .most_recent => |*x| return x,
283293 .never_succeeded => return null,
284294 }
285295 }
286296
287 pub fn getFileScope(self: Decl) *Scope.File {
288 return self.container.file_scope;
297 pub fn getFileScope(decl: Decl) *Scope.File {
298 return decl.container.file_scope;
289299 }
290300
291301 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {
......@@ -294,12 +304,12 @@ pub const Decl = struct {
294304 return &decl_plus_emit_h.emit_h;
295305 }
296306
297 fn removeDependant(self: *Decl, other: *Decl) void {
298 self.dependants.removeAssertDiscard(other);
307 fn removeDependant(decl: *Decl, other: *Decl) void {
308 decl.dependants.removeAssertDiscard(other);
299309 }
300310
301 fn removeDependency(self: *Decl, other: *Decl) void {
302 self.dependencies.removeAssertDiscard(other);
311 fn removeDependency(decl: *Decl, other: *Decl) void {
312 decl.dependencies.removeAssertDiscard(other);
303313 }
304314};
305315
......@@ -316,9 +326,14 @@ pub const Fn = struct {
316326 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
317327 /// Even after we finish analysis, the ZIR is kept in memory, so that
318328 /// comptime and inline function calls can happen.
319 zir: zir.Body,
329 /// Parameter names are stored here so that they may be referenced for debug info,
330 /// without having source code bytes loaded into memory.
331 /// The number of parameters is determined by referring to the type.
332 /// The first N elements of `extra` are indexes into `string_bytes` to
333 /// a null-terminated string.
334 zir: zir.Code,
320335 /// undefined unless analysis state is `success`.
321 body: Body,
336 body: ir.Body,
322337 state: Analysis,
323338
324339 pub const Analysis = enum {
......@@ -336,8 +351,8 @@ pub const Fn = struct {
336351 };
337352
338353 /// For debugging purposes.
339 pub fn dump(self: *Fn, mod: Module) void {
340 zir.dumpFn(mod, self);
354 pub fn dump(func: *Fn, mod: Module) void {
355 zir.dumpFn(mod, func);
341356 }
342357};
343358
......@@ -364,68 +379,68 @@ pub const Scope = struct {
364379 }
365380
366381 /// Returns the arena Allocator associated with the Decl of the Scope.
367 pub fn arena(self: *Scope) *Allocator {
368 switch (self.tag) {
369 .block => return self.cast(Block).?.arena,
370 .gen_zir => return self.cast(GenZIR).?.arena,
371 .local_val => return self.cast(LocalVal).?.gen_zir.arena,
372 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,
373 .gen_suspend => return self.cast(GenZIR).?.arena,
374 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.arena,
382 pub fn arena(scope: *Scope) *Allocator {
383 switch (scope.tag) {
384 .block => return scope.cast(Block).?.arena,
385 .gen_zir => return scope.cast(GenZir).?.arena,
386 .local_val => return scope.cast(LocalVal).?.gen_zir.arena,
387 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.arena,
388 .gen_suspend => return scope.cast(GenZir).?.arena,
389 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.arena,
375390 .file => unreachable,
376391 .container => unreachable,
377392 }
378393 }
379394
380 pub fn isComptime(self: *Scope) bool {
381 return self.getGenZIR().force_comptime;
395 pub fn isComptime(scope: *Scope) bool {
396 return scope.getGenZir().force_comptime;
382397 }
383398
384 pub fn ownerDecl(self: *Scope) ?*Decl {
385 return switch (self.tag) {
386 .block => self.cast(Block).?.owner_decl,
387 .gen_zir => self.cast(GenZIR).?.decl,
388 .local_val => self.cast(LocalVal).?.gen_zir.decl,
389 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
390 .gen_suspend => return self.cast(GenZIR).?.decl,
391 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl,
399 pub fn ownerDecl(scope: *Scope) ?*Decl {
400 return switch (scope.tag) {
401 .block => scope.cast(Block).?.owner_decl,
402 .gen_zir => scope.cast(GenZir).?.zir_code.decl,
403 .local_val => scope.cast(LocalVal).?.gen_zir.decl,
404 .local_ptr => scope.cast(LocalPtr).?.gen_zir.decl,
405 .gen_suspend => return scope.cast(GenZir).?.decl,
406 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.decl,
392407 .file => null,
393408 .container => null,
394409 };
395410 }
396411
397 pub fn srcDecl(self: *Scope) ?*Decl {
398 return switch (self.tag) {
399 .block => self.cast(Block).?.src_decl,
400 .gen_zir => self.cast(GenZIR).?.decl,
401 .local_val => self.cast(LocalVal).?.gen_zir.decl,
402 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,
403 .gen_suspend => return self.cast(GenZIR).?.decl,
404 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl,
412 pub fn srcDecl(scope: *Scope) ?*Decl {
413 return switch (scope.tag) {
414 .block => scope.cast(Block).?.src_decl,
415 .gen_zir => scope.cast(GenZir).?.zir_code.decl,
416 .local_val => scope.cast(LocalVal).?.gen_zir.decl,
417 .local_ptr => scope.cast(LocalPtr).?.gen_zir.decl,
418 .gen_suspend => return scope.cast(GenZir).?.decl,
419 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.decl,
405420 .file => null,
406421 .container => null,
407422 };
408423 }
409424
410425 /// Asserts the scope has a parent which is a Container and returns it.
411 pub fn namespace(self: *Scope) *Container {
412 switch (self.tag) {
413 .block => return self.cast(Block).?.owner_decl.container,
414 .gen_zir => return self.cast(GenZIR).?.decl.container,
415 .local_val => return self.cast(LocalVal).?.gen_zir.decl.container,
416 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container,
417 .file => return &self.cast(File).?.root_container,
418 .container => return self.cast(Container).?,
419 .gen_suspend => return self.cast(GenZIR).?.decl.container,
420 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl.container,
426 pub fn namespace(scope: *Scope) *Container {
427 switch (scope.tag) {
428 .block => return scope.cast(Block).?.sema.owner_decl.container,
429 .gen_zir => return scope.cast(GenZir).?.zir_code.decl.container,
430 .local_val => return scope.cast(LocalVal).?.gen_zir.zir_code.decl.container,
431 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.zir_code.decl.container,
432 .file => return &scope.cast(File).?.root_container,
433 .container => return scope.cast(Container).?,
434 .gen_suspend => return scope.cast(GenZir).?.zir_code.decl.container,
435 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.zir_code.decl.container,
421436 }
422437 }
423438
424439 /// Must generate unique bytes with no collisions with other decls.
425440 /// The point of hashing here is only to limit the number of bytes of
426441 /// the unique identifier to a fixed size (16 bytes).
427 pub fn fullyQualifiedNameHash(self: *Scope, name: []const u8) NameHash {
428 switch (self.tag) {
442 pub fn fullyQualifiedNameHash(scope: *Scope, name: []const u8) NameHash {
443 switch (scope.tag) {
429444 .block => unreachable,
430445 .gen_zir => unreachable,
431446 .local_val => unreachable,
......@@ -433,32 +448,32 @@ pub const Scope = struct {
433448 .gen_suspend => unreachable,
434449 .gen_nosuspend => unreachable,
435450 .file => unreachable,
436 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),
451 .container => return scope.cast(Container).?.fullyQualifiedNameHash(name),
437452 }
438453 }
439454
440455 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.
441 pub fn tree(self: *Scope) *const ast.Tree {
442 switch (self.tag) {
443 .file => return &self.cast(File).?.tree,
444 .block => return &self.cast(Block).?.src_decl.container.file_scope.tree,
445 .gen_zir => return &self.cast(GenZIR).?.decl.container.file_scope.tree,
446 .local_val => return &self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
447 .local_ptr => return &self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
448 .container => return &self.cast(Container).?.file_scope.tree,
449 .gen_suspend => return &self.cast(GenZIR).?.decl.container.file_scope.tree,
450 .gen_nosuspend => return &self.cast(Nosuspend).?.gen_zir.decl.container.file_scope.tree,
451 }
452 }
453
454 /// Asserts the scope is a child of a `GenZIR` and returns it.
455 pub fn getGenZIR(self: *Scope) *GenZIR {
456 return switch (self.tag) {
456 pub fn tree(scope: *Scope) *const ast.Tree {
457 switch (scope.tag) {
458 .file => return &scope.cast(File).?.tree,
459 .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree,
460 .gen_zir => return &scope.cast(GenZir).?.decl.container.file_scope.tree,
461 .local_val => return &scope.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
462 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
463 .container => return &scope.cast(Container).?.file_scope.tree,
464 .gen_suspend => return &scope.cast(GenZir).?.decl.container.file_scope.tree,
465 .gen_nosuspend => return &scope.cast(Nosuspend).?.gen_zir.decl.container.file_scope.tree,
466 }
467 }
468
469 /// Asserts the scope is a child of a `GenZir` and returns it.
470 pub fn getGenZir(scope: *Scope) *GenZir {
471 return switch (scope.tag) {
457472 .block => unreachable,
458 .gen_zir, .gen_suspend => self.cast(GenZIR).?,
459 .local_val => return self.cast(LocalVal).?.gen_zir,
460 .local_ptr => return self.cast(LocalPtr).?.gen_zir,
461 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir,
473 .gen_zir, .gen_suspend => scope.cast(GenZir).?,
474 .local_val => return scope.cast(LocalVal).?.gen_zir,
475 .local_ptr => return scope.cast(LocalPtr).?.gen_zir,
476 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir,
462477 .file => unreachable,
463478 .container => unreachable,
464479 };
......@@ -499,25 +514,25 @@ pub const Scope = struct {
499514 cur = switch (cur.tag) {
500515 .container => return @fieldParentPtr(Container, "base", cur).file_scope,
501516 .file => return @fieldParentPtr(File, "base", cur),
502 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
517 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
503518 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
504519 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
505520 .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope,
506 .gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent,
521 .gen_suspend => @fieldParentPtr(GenZir, "base", cur).parent,
507522 .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,
508523 };
509524 }
510525 }
511526
512 pub fn getSuspend(base: *Scope) ?*Scope.GenZIR {
527 pub fn getSuspend(base: *Scope) ?*Scope.GenZir {
513528 var cur = base;
514529 while (true) {
515530 cur = switch (cur.tag) {
516 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
531 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
517532 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
518533 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
519534 .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,
520 .gen_suspend => return @fieldParentPtr(GenZIR, "base", cur),
535 .gen_suspend => return @fieldParentPtr(GenZir, "base", cur),
521536 else => return null,
522537 };
523538 }
......@@ -527,10 +542,10 @@ pub const Scope = struct {
527542 var cur = base;
528543 while (true) {
529544 cur = switch (cur.tag) {
530 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,
545 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
531546 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
532547 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
533 .gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent,
548 .gen_suspend => @fieldParentPtr(GenZir, "base", cur).parent,
534549 .gen_nosuspend => return @fieldParentPtr(Nosuspend, "base", cur),
535550 else => return null,
536551 };
......@@ -568,19 +583,19 @@ pub const Scope = struct {
568583 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
569584 ty: Type,
570585
571 pub fn deinit(self: *Container, gpa: *Allocator) void {
572 self.decls.deinit(gpa);
586 pub fn deinit(cont: *Container, gpa: *Allocator) void {
587 cont.decls.deinit(gpa);
573588 // TODO either Container of File should have an arena for sub_file_path and ty
574 gpa.destroy(self.ty.castTag(.empty_struct).?);
575 gpa.free(self.file_scope.sub_file_path);
576 self.* = undefined;
589 gpa.destroy(cont.ty.castTag(.empty_struct).?);
590 gpa.free(cont.file_scope.sub_file_path);
591 cont.* = undefined;
577592 }
578593
579 pub fn removeDecl(self: *Container, child: *Decl) void {
580 _ = self.decls.swapRemove(child);
594 pub fn removeDecl(cont: *Container, child: *Decl) void {
595 _ = cont.decls.swapRemove(child);
581596 }
582597
583 pub fn fullyQualifiedNameHash(self: *Container, name: []const u8) NameHash {
598 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
584599 // TODO container scope qualified names.
585600 return std.zig.hashSrc(name);
586601 }
......@@ -610,55 +625,55 @@ pub const Scope = struct {
610625
611626 root_container: Container,
612627
613 pub fn unload(self: *File, gpa: *Allocator) void {
614 switch (self.status) {
628 pub fn unload(file: *File, gpa: *Allocator) void {
629 switch (file.status) {
615630 .never_loaded,
616631 .unloaded_parse_failure,
617632 .unloaded_success,
618633 => {},
619634
620635 .loaded_success => {
621 self.tree.deinit(gpa);
622 self.status = .unloaded_success;
636 file.tree.deinit(gpa);
637 file.status = .unloaded_success;
623638 },
624639 }
625 switch (self.source) {
640 switch (file.source) {
626641 .bytes => |bytes| {
627642 gpa.free(bytes);
628 self.source = .{ .unloaded = {} };
643 file.source = .{ .unloaded = {} };
629644 },
630645 .unloaded => {},
631646 }
632647 }
633648
634 pub fn deinit(self: *File, gpa: *Allocator) void {
635 self.root_container.deinit(gpa);
636 self.unload(gpa);
637 self.* = undefined;
649 pub fn deinit(file: *File, gpa: *Allocator) void {
650 file.root_container.deinit(gpa);
651 file.unload(gpa);
652 file.* = undefined;
638653 }
639654
640 pub fn destroy(self: *File, gpa: *Allocator) void {
641 self.deinit(gpa);
642 gpa.destroy(self);
655 pub fn destroy(file: *File, gpa: *Allocator) void {
656 file.deinit(gpa);
657 gpa.destroy(file);
643658 }
644659
645 pub fn dumpSrc(self: *File, src: usize) void {
646 const loc = std.zig.findLineColumn(self.source.bytes, src);
647 std.debug.print("{s}:{d}:{d}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });
660 pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
661 const loc = std.zig.findLineColumn(file.source.bytes, src);
662 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
648663 }
649664
650 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {
651 switch (self.source) {
665 pub fn getSource(file: *File, module: *Module) ![:0]const u8 {
666 switch (file.source) {
652667 .unloaded => {
653 const source = try self.pkg.root_src_directory.handle.readFileAllocOptions(
668 const source = try file.pkg.root_src_directory.handle.readFileAllocOptions(
654669 module.gpa,
655 self.sub_file_path,
670 file.sub_file_path,
656671 std.math.maxInt(u32),
657672 null,
658673 1,
659674 0,
660675 );
661 self.source = .{ .bytes = source };
676 file.source = .{ .bytes = source };
662677 return source;
663678 },
664679 .bytes => |bytes| return bytes,
......@@ -666,37 +681,30 @@ pub const Scope = struct {
666681 }
667682 };
668683
669 /// This is a temporary structure, references to it are valid only
684 /// This is the context needed to semantically analyze ZIR instructions and
685 /// produce TZIR instructions.
686 /// This is a temporary structure stored on the stack; references to it are valid only
670687 /// during semantic analysis of the block.
671688 pub const Block = struct {
672689 pub const base_tag: Tag = .block;
673690
674691 base: Scope = Scope{ .tag = base_tag },
675692 parent: ?*Block,
676 /// Maps ZIR to TZIR. Shared to sub-blocks.
677 inst_table: *InstTable,
678 func: ?*Fn,
679 /// When analyzing an inline function call, owner_decl is the Decl of the caller
680 /// and src_decl is the Decl of the callee.
681 /// This Decl owns the arena memory of this Block.
682 owner_decl: *Decl,
693 /// Shared among all child blocks.
694 sema: *Sema,
683695 /// This Decl is the Decl according to the Zig source code corresponding to this Block.
696 /// This can vary during inline or comptime function calls. See `Sema.owner_decl`
697 /// for the one that will be the same for all Block instances.
684698 src_decl: *Decl,
685 instructions: ArrayListUnmanaged(*Inst),
686 /// Points to the arena allocator of the Decl.
687 arena: *Allocator,
699 instructions: ArrayListUnmanaged(*ir.Inst),
688700 label: ?Label = null,
689701 inlining: ?*Inlining,
690702 is_comptime: bool,
691 /// Shared to sub-blocks.
692 branch_quota: *u32,
693
694 pub const InstTable = std.AutoHashMap(*zir.Inst, *Inst);
695703
696704 /// This `Block` maps a block ZIR instruction to the corresponding
697705 /// TZIR instruction for break instruction analysis.
698706 pub const Label = struct {
699 zir_block: *zir.Inst.Block,
707 zir_block: zir.Inst.Index,
700708 merges: Merges,
701709 };
702710
......@@ -712,7 +720,7 @@ pub const Scope = struct {
712720 /// which parameter index they are, without having to store
713721 /// a parameter index with each arg instruction.
714722 param_index: usize,
715 casted_args: []*Inst,
723 casted_args: []*ir.Inst,
716724 merges: Merges,
717725
718726 pub const Shared = struct {
......@@ -722,25 +730,25 @@ pub const Scope = struct {
722730 };
723731
724732 pub const Merges = struct {
725 block_inst: *Inst.Block,
733 block_inst: *ir.Inst.Block,
726734 /// Separate array list from break_inst_list so that it can be passed directly
727735 /// to resolvePeerTypes.
728 results: ArrayListUnmanaged(*Inst),
736 results: ArrayListUnmanaged(*ir.Inst),
729737 /// Keeps track of the break instructions so that the operand can be replaced
730738 /// if we need to add type coercion at the end of block analysis.
731739 /// Same indexes, capacity, length as `results`.
732 br_list: ArrayListUnmanaged(*Inst.Br),
740 br_list: ArrayListUnmanaged(*ir.Inst.Br),
733741 };
734742
735743 /// For debugging purposes.
736 pub fn dump(self: *Block, mod: Module) void {
737 zir.dumpBlock(mod, self);
744 pub fn dump(block: *Block, mod: Module) void {
745 zir.dumpBlock(mod, block);
738746 }
739747
740748 pub fn makeSubBlock(parent: *Block) Block {
741749 return .{
742750 .parent = parent,
743 .inst_table = parent.inst_table,
751 .inst_map = parent.inst_map,
744752 .func = parent.func,
745753 .owner_decl = parent.owner_decl,
746754 .src_decl = parent.src_decl,
......@@ -752,27 +760,186 @@ pub const Scope = struct {
752760 .branch_quota = parent.branch_quota,
753761 };
754762 }
763
764 pub fn wantSafety(block: *const Block) bool {
765 // TODO take into account scope's safety overrides
766 return switch (block.sema.mod.optimizeMode()) {
767 .Debug => true,
768 .ReleaseSafe => true,
769 .ReleaseFast => false,
770 .ReleaseSmall => false,
771 };
772 }
773
774 pub fn getFileScope(block: *Block) *Scope.File {
775 return block.src_decl.container.file_scope;
776 }
777
778 pub fn addNoOp(
779 block: *Scope.Block,
780 src: LazySrcLoc,
781 ty: Type,
782 comptime tag: ir.Inst.Tag,
783 ) !*ir.Inst {
784 const inst = try block.arena.create(tag.Type());
785 inst.* = .{
786 .base = .{
787 .tag = tag,
788 .ty = ty,
789 .src = src,
790 },
791 };
792 try block.instructions.append(block.sema.gpa, &inst.base);
793 return &inst.base;
794 }
795
796 pub fn addUnOp(
797 block: *Scope.Block,
798 src: LazySrcLoc,
799 ty: Type,
800 tag: ir.Inst.Tag,
801 operand: *ir.Inst,
802 ) !*ir.Inst {
803 const inst = try block.arena.create(ir.Inst.UnOp);
804 inst.* = .{
805 .base = .{
806 .tag = tag,
807 .ty = ty,
808 .src = src,
809 },
810 .operand = operand,
811 };
812 try block.instructions.append(block.sema.gpa, &inst.base);
813 return &inst.base;
814 }
815
816 pub fn addBinOp(
817 block: *Scope.Block,
818 src: LazySrcLoc,
819 ty: Type,
820 tag: ir.Inst.Tag,
821 lhs: *ir.Inst,
822 rhs: *ir.Inst,
823 ) !*ir.Inst {
824 const inst = try block.arena.create(ir.Inst.BinOp);
825 inst.* = .{
826 .base = .{
827 .tag = tag,
828 .ty = ty,
829 .src = src,
830 },
831 .lhs = lhs,
832 .rhs = rhs,
833 };
834 try block.instructions.append(block.sema.gpa, &inst.base);
835 return &inst.base;
836 }
837 pub fn addBr(
838 scope_block: *Scope.Block,
839 src: LazySrcLoc,
840 target_block: *ir.Inst.Block,
841 operand: *ir.Inst,
842 ) !*ir.Inst.Br {
843 const inst = try scope_block.arena.create(ir.Inst.Br);
844 inst.* = .{
845 .base = .{
846 .tag = .br,
847 .ty = Type.initTag(.noreturn),
848 .src = src,
849 },
850 .operand = operand,
851 .block = target_block,
852 };
853 try scope_block.instructions.append(scope_block.sema.gpa, &inst.base);
854 return inst;
855 }
856
857 pub fn addCondBr(
858 block: *Scope.Block,
859 src: LazySrcLoc,
860 condition: *ir.Inst,
861 then_body: ir.Body,
862 else_body: ir.Body,
863 ) !*ir.Inst {
864 const inst = try block.arena.create(ir.Inst.CondBr);
865 inst.* = .{
866 .base = .{
867 .tag = .condbr,
868 .ty = Type.initTag(.noreturn),
869 .src = src,
870 },
871 .condition = condition,
872 .then_body = then_body,
873 .else_body = else_body,
874 };
875 try block.instructions.append(block.sema.gpa, &inst.base);
876 return &inst.base;
877 }
878
879 pub fn addCall(
880 block: *Scope.Block,
881 src: LazySrcLoc,
882 ty: Type,
883 func: *ir.Inst,
884 args: []const *ir.Inst,
885 ) !*ir.Inst {
886 const inst = try block.arena.create(ir.Inst.Call);
887 inst.* = .{
888 .base = .{
889 .tag = .call,
890 .ty = ty,
891 .src = src,
892 },
893 .func = func,
894 .args = args,
895 };
896 try block.instructions.append(block.sema.gpa, &inst.base);
897 return &inst.base;
898 }
899
900 pub fn addSwitchBr(
901 block: *Scope.Block,
902 src: LazySrcLoc,
903 target: *ir.Inst,
904 cases: []ir.Inst.SwitchBr.Case,
905 else_body: ir.Body,
906 ) !*ir.Inst {
907 const inst = try block.arena.create(ir.Inst.SwitchBr);
908 inst.* = .{
909 .base = .{
910 .tag = .switchbr,
911 .ty = Type.initTag(.noreturn),
912 .src = src,
913 },
914 .target = target,
915 .cases = cases,
916 .else_body = else_body,
917 };
918 try block.instructions.append(block.sema.gpa, &inst.base);
919 return &inst.base;
920 }
755921 };
756922
757 /// This is a temporary structure, references to it are valid only
758 /// during semantic analysis of the decl.
759 pub const GenZIR = struct {
923 /// This is a temporary structure; references to it are valid only
924 /// while constructing a `zir.Code`.
925 pub const GenZir = struct {
760926 pub const base_tag: Tag = .gen_zir;
761927 base: Scope = Scope{ .tag = base_tag },
762 /// Parents can be: `GenZIR`, `File`
763 parent: *Scope,
764 decl: *Decl,
765 arena: *Allocator,
766928 force_comptime: bool,
767 /// The first N instructions in a function body ZIR are arg instructions.
768 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},
929 /// Parents can be: `GenZir`, `File`
930 parent: *Scope,
931 /// All `GenZir` scopes for the same ZIR share this.
932 zir_code: *WipZirCode,
933 /// Keeps track of the list of instructions in this scope only. References
934 /// to instructions in `zir_code`.
935 instructions: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
769936 label: ?Label = null,
770 break_block: ?*zir.Inst.Block = null,
771 continue_block: ?*zir.Inst.Block = null,
937 break_block: zir.Inst.Index = 0,
938 continue_block: zir.Inst.Index = 0,
772939 /// Only valid when setBlockResultLoc is called.
773940 break_result_loc: astgen.ResultLoc = undefined,
774941 /// When a block has a pointer result location, here it is.
775 rl_ptr: ?*zir.Inst = null,
942 rl_ptr: zir.Inst.Index = 0,
776943 /// Keeps track of how many branches of a block did not actually
777944 /// consume the result location. astgen uses this to figure out
778945 /// whether to rely on break instructions or writing to the result
......@@ -784,19 +951,95 @@ pub const Scope = struct {
784951 break_count: usize = 0,
785952 /// Tracks `break :foo bar` instructions so they can possibly be elided later if
786953 /// the labeled block ends up not needing a result location pointer.
787 labeled_breaks: std.ArrayListUnmanaged(*zir.Inst.Break) = .{},
954 labeled_breaks: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
788955 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
789956 /// so they can possibly be elided later if the labeled block ends up not needing
790957 /// a result location pointer.
791 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(*zir.Inst.BinOp) = .{},
792 /// for suspend error notes
793 src: usize = 0,
958 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
794959
795960 pub const Label = struct {
796961 token: ast.TokenIndex,
797 block_inst: *zir.Inst.Block,
962 block_inst: zir.Inst.Index,
798963 used: bool = false,
799964 };
965
966 pub fn addFnTypeCc(gz: *GenZir, args: struct {
967 param_types: []const zir.Inst.Index,
968 ret_ty: zir.Inst.Index,
969 cc: zir.Inst.Index,
970 }) !zir.Inst.Index {
971 const gpa = gz.zir_code.gpa;
972 try gz.instructions.ensureCapacity(gpa, gz.instructions.items + 1);
973 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
974 try gz.zir_code.extra.ensureCapacity(gpa, gz.zir_code.extra.len +
975 @typeInfo(zir.Inst.FnTypeCc).Struct.fields.len + args.param_types.len);
976
977 const payload_index = gz.addExtra(zir.Inst.FnTypeCc, .{
978 .cc = args.cc,
979 .param_types_len = @intCast(u32, args.param_types.len),
980 }) catch unreachable; // Capacity is ensured above.
981 gz.zir_code.extra.appendSliceAssumeCapacity(args.param_types);
982
983 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
984 gz.zir_code.instructions.appendAssumeCapacity(.{
985 .tag = .fn_type_cc,
986 .data = .{ .fn_type = .{
987 .return_type = ret_ty,
988 .payload_index = payload_index,
989 } },
990 });
991 gz.instructions.appendAssumeCapacity(new_index);
992 return new_index;
993 }
994
995 pub fn addFnType(
996 gz: *GenZir,
997 ret_ty: zir.Inst.Index,
998 param_types: []const zir.Inst.Index,
999 ) !zir.Inst.Index {
1000 const gpa = gz.zir_code.gpa;
1001 try gz.instructions.ensureCapacity(gpa, gz.instructions.items + 1);
1002 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
1003 try gz.zir_code.extra.ensureCapacity(gpa, gz.zir_code.extra.len +
1004 @typeInfo(zir.Inst.FnType).Struct.fields.len + param_types.len);
1005
1006 const payload_index = gz.addExtra(zir.Inst.FnTypeCc, .{
1007 .param_types_len = @intCast(u32, param_types.len),
1008 }) catch unreachable; // Capacity is ensured above.
1009 gz.zir_code.extra.appendSliceAssumeCapacity(param_types);
1010
1011 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1012 gz.zir_code.instructions.appendAssumeCapacity(.{
1013 .tag = .fn_type_cc,
1014 .data = .{ .fn_type = .{
1015 .return_type = ret_ty,
1016 .payload_index = payload_index,
1017 } },
1018 });
1019 gz.instructions.appendAssumeCapacity(new_index);
1020 return new_index;
1021 }
1022
1023 pub fn addRetTok(
1024 gz: *GenZir,
1025 operand: zir.Inst.Index,
1026 src_tok: ast.TokenIndex,
1027 ) !zir.Inst.Index {
1028 const gpa = gz.zir_code.gpa;
1029 try gz.instructions.ensureCapacity(gpa, gz.instructions.items + 1);
1030 try gz.zir_code.instructions.ensureCapacity(gpa, gz.zir_code.instructions.len + 1);
1031
1032 const new_index = @intCast(zir.Inst.Index, gz.zir_code.instructions.len);
1033 gz.zir_code.instructions.appendAssumeCapacity(.{
1034 .tag = .ret_tok,
1035 .data = .{ .fn_type = .{
1036 .operand = operand,
1037 .src_tok = src_tok,
1038 } },
1039 });
1040 gz.instructions.appendAssumeCapacity(new_index);
1041 return new_index;
1042 }
8001043 };
8011044
8021045 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.
......@@ -805,11 +1048,11 @@ pub const Scope = struct {
8051048 pub const LocalVal = struct {
8061049 pub const base_tag: Tag = .local_val;
8071050 base: Scope = Scope{ .tag = base_tag },
808 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
1051 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
8091052 parent: *Scope,
810 gen_zir: *GenZIR,
1053 gen_zir: *GenZir,
8111054 name: []const u8,
812 inst: *zir.Inst,
1055 inst: zir.Inst.Index,
8131056 };
8141057
8151058 /// This could be a `const` or `var` local. It has a pointer instead of a value.
......@@ -818,24 +1061,42 @@ pub const Scope = struct {
8181061 pub const LocalPtr = struct {
8191062 pub const base_tag: Tag = .local_ptr;
8201063 base: Scope = Scope{ .tag = base_tag },
821 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
1064 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
8221065 parent: *Scope,
823 gen_zir: *GenZIR,
1066 gen_zir: *GenZir,
8241067 name: []const u8,
825 ptr: *zir.Inst,
1068 ptr: zir.Inst.Index,
8261069 };
8271070
8281071 pub const Nosuspend = struct {
8291072 pub const base_tag: Tag = .gen_nosuspend;
8301073
8311074 base: Scope = Scope{ .tag = base_tag },
832 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.
1075 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
8331076 parent: *Scope,
834 gen_zir: *GenZIR,
835 src: usize,
1077 gen_zir: *GenZir,
1078 src: LazySrcLoc,
8361079 };
8371080};
8381081
1082/// A Work-In-Progress `zir.Code`. This is a shared parent of all
1083/// `GenZir` scopes. Once the `zir.Code` is produced, this struct
1084/// is deinitialized.
1085pub const WipZirCode = struct {
1086 instructions: std.MultiArrayList(zir.Inst) = .{},
1087 string_bytes: std.ArrayListUnmanaged(u8) = .{},
1088 extra: std.ArrayListUnmanaged(u32) = .{},
1089 arg_count: usize = 0,
1090 decl: *Decl,
1091 gpa: *Allocator,
1092 arena: *Allocator,
1093
1094 fn deinit(wip_zir_code: *WipZirCode) void {
1095 wip_zir_code.instructions.deinit(wip_zir_code.gpa);
1096 wip_zir_code.extra.deinit(wip_zir_code.gpa);
1097 }
1098};
1099
8391100/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
8401101/// Its memory is managed with the general purpose allocator so that they
8411102/// can be created and destroyed in response to incremental updates.
......@@ -855,17 +1116,17 @@ pub const ErrorMsg = struct {
8551116 comptime format: []const u8,
8561117 args: anytype,
8571118 ) !*ErrorMsg {
858 const self = try gpa.create(ErrorMsg);
859 errdefer gpa.destroy(self);
860 self.* = try init(gpa, src_loc, format, args);
861 return self;
1119 const err_msg = try gpa.create(ErrorMsg);
1120 errdefer gpa.destroy(err_msg);
1121 err_msg.* = try init(gpa, src_loc, format, args);
1122 return err_msg;
8621123 }
8631124
8641125 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,
8651126 /// as well as all notes.
866 pub fn destroy(self: *ErrorMsg, gpa: *Allocator) void {
867 self.deinit(gpa);
868 gpa.destroy(self);
1127 pub fn destroy(err_msg: *ErrorMsg, gpa: *Allocator) void {
1128 err_msg.deinit(gpa);
1129 gpa.destroy(err_msg);
8691130 }
8701131
8711132 pub fn init(
......@@ -880,84 +1141,231 @@ pub const ErrorMsg = struct {
8801141 };
8811142 }
8821143
883 pub fn deinit(self: *ErrorMsg, gpa: *Allocator) void {
884 for (self.notes) |*note| {
1144 pub fn deinit(err_msg: *ErrorMsg, gpa: *Allocator) void {
1145 for (err_msg.notes) |*note| {
8851146 note.deinit(gpa);
8861147 }
887 gpa.free(self.notes);
888 gpa.free(self.msg);
889 self.* = undefined;
1148 gpa.free(err_msg.notes);
1149 gpa.free(err_msg.msg);
1150 err_msg.* = undefined;
8901151 }
8911152};
8921153
8931154/// Canonical reference to a position within a source file.
8941155pub const SrcLoc = struct {
895 file_scope: *Scope.File,
896 byte_offset: usize,
1156 /// The active field is determined by tag of `lazy`.
1157 container: union {
1158 /// The containing `Decl` according to the source code.
1159 decl: *Decl,
1160 file_scope: *Scope.File,
1161 },
1162 /// Relative to `decl`.
1163 lazy: LazySrcLoc,
1164
1165 pub fn fileScope(src_loc: SrcLoc) *Scope.File {
1166 return switch (src_loc.lazy) {
1167 .unneeded => unreachable,
1168 .todo => unreachable,
1169
1170 .byte_abs,
1171 .token_abs,
1172 => src_loc.container.file_scope,
1173
1174 .byte_offset,
1175 .token_offset,
1176 .node_offset,
1177 .node_offset_var_decl_ty,
1178 .node_offset_for_cond,
1179 .node_offset_builtin_call_arg0,
1180 .node_offset_builtin_call_arg1,
1181 .node_offset_builtin_call_argn,
1182 .node_offset_array_access_index,
1183 .node_offset_slice_sentinel,
1184 => src_loc.container.decl.container.file_scope,
1185 };
1186 }
1187
1188 pub fn byteOffset(src_loc: SrcLoc, mod: *Module) !u32 {
1189 switch (src_loc.lazy) {
1190 .unneeded => unreachable,
1191 .todo => unreachable,
1192
1193 .byte_abs => |byte_index| return byte_index,
1194
1195 .token_abs => |tok_index| {
1196 const file_scope = src_loc.container.file_scope;
1197 const tree = try mod.getAstTree(file_scope);
1198 const token_starts = tree.tokens.items(.start);
1199 return token_starts[tok_index];
1200 },
1201 .byte_offset => |byte_off| {
1202 const decl = src_loc.container.decl;
1203 return decl.srcByteOffset() + byte_off;
1204 },
1205 .token_offset => |tok_off| {
1206 const decl = src_loc.container.decl;
1207 const tok_index = decl.srcToken() + tok_off;
1208 const tree = try mod.getAstTree(decl.container.file_scope);
1209 const token_starts = tree.tokens.items(.start);
1210 return token_starts[tok_index];
1211 },
1212 .node_offset => |node_off| {
1213 const decl = src_loc.container.decl;
1214 const node_index = decl.srcNode() + node_off;
1215 const tree = try mod.getAstTree(decl.container.file_scope);
1216 const tok_index = tree.firstToken(node_index);
1217 const token_starts = tree.tokens.items(.start);
1218 return token_starts[tok_index];
1219 },
1220 .node_offset_var_decl_ty => @panic("TODO"),
1221 .node_offset_for_cond => @panic("TODO"),
1222 .node_offset_builtin_call_arg0 => @panic("TODO"),
1223 .node_offset_builtin_call_arg1 => @panic("TODO"),
1224 .node_offset_builtin_call_argn => unreachable, // Handled specially in `Sema`.
1225 .node_offset_array_access_index => @panic("TODO"),
1226 .node_offset_slice_sentinel => @panic("TODO"),
1227 }
1228 }
1229};
1230
1231/// Resolving a source location into a byte offset may require doing work
1232/// that we would rather not do unless the error actually occurs.
1233/// Therefore we need a data structure that contains the information necessary
1234/// to lazily produce a `SrcLoc` as required.
1235/// Most of the offsets in this data structure are relative to the containing Decl.
1236/// This makes the source location resolve properly even when a Decl gets
1237/// shifted up or down in the file, as long as the Decl's contents itself
1238/// do not change.
1239pub const LazySrcLoc = union(enum) {
1240 /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting
1241 /// that all code paths which would need to resolve the source location are
1242 /// unreachable. If you are debugging this tag incorrectly being this value,
1243 /// look into using reverse-continue with a memory watchpoint to see where the
1244 /// value is being set to this tag.
1245 unneeded,
1246 /// Same as `unneeded`, except the code setting up this tag knew that actually
1247 /// the source location was needed, and I wanted to get other stuff compiling
1248 /// and working before coming back to messing with source locations.
1249 /// TODO delete this tag before merging the zir-memory-layout branch.
1250 todo,
1251 /// The source location points to a byte offset within a source file,
1252 /// offset from 0. The source file is determined contextually.
1253 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
1254 byte_abs: u32,
1255 /// The source location points to a token within a source file,
1256 /// offset from 0. The source file is determined contextually.
1257 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
1258 token_abs: u32,
1259 /// The source location points to a byte offset within a source file,
1260 /// offset from the byte offset of the Decl within the file.
1261 /// The Decl is determined contextually.
1262 byte_offset: u32,
1263 /// This data is the offset into the token list from the Decl token.
1264 /// The Decl is determined contextually.
1265 token_offset: u32,
1266 /// The source location points to an AST node, which is this value offset
1267 /// from its containing Decl node AST index.
1268 /// The Decl is determined contextually.
1269 node_offset: u32,
1270 /// The source location points to a variable declaration type expression,
1271 /// found by taking this AST node index offset from the containing
1272 /// Decl AST node, which points to a variable declaration AST node. Next, navigate
1273 /// to the type expression.
1274 /// The Decl is determined contextually.
1275 node_offset_var_decl_ty: u32,
1276 /// The source location points to a for loop condition expression,
1277 /// found by taking this AST node index offset from the containing
1278 /// Decl AST node, which points to a for loop AST node. Next, navigate
1279 /// to the condition expression.
1280 /// The Decl is determined contextually.
1281 node_offset_for_cond: u32,
1282 /// The source location points to the first parameter of a builtin
1283 /// function call, found by taking this AST node index offset from the containing
1284 /// Decl AST node, which points to a builtin call AST node. Next, navigate
1285 /// to the first parameter.
1286 /// The Decl is determined contextually.
1287 node_offset_builtin_call_arg0: u32,
1288 /// Same as `node_offset_builtin_call_arg0` except arg index 1.
1289 node_offset_builtin_call_arg1: u32,
1290 /// Same as `node_offset_builtin_call_arg0` except the arg index is contextually
1291 /// determined.
1292 node_offset_builtin_call_argn: u32,
1293 /// The source location points to the index expression of an array access
1294 /// expression, found by taking this AST node index offset from the containing
1295 /// Decl AST node, which points to an array access AST node. Next, navigate
1296 /// to the index expression.
1297 /// The Decl is determined contextually.
1298 node_offset_array_access_index: u32,
1299 /// The source location points to the sentinel expression of a slice
1300 /// expression, found by taking this AST node index offset from the containing
1301 /// Decl AST node, which points to a slice AST node. Next, navigate
1302 /// to the sentinel expression.
1303 /// The Decl is determined contextually.
1304 node_offset_slice_sentinel: u32,
8971305};
8981306
8991307pub const InnerError = error{ OutOfMemory, AnalysisFail };
9001308
901pub fn deinit(self: *Module) void {
902 const gpa = self.gpa;
1309pub fn deinit(mod: *Module) void {
1310 const gpa = mod.gpa;
9031311
904 self.compile_log_text.deinit(gpa);
1312 mod.compile_log_text.deinit(gpa);
9051313
906 self.zig_cache_artifact_directory.handle.close();
1314 mod.zig_cache_artifact_directory.handle.close();
9071315
908 self.deletion_set.deinit(gpa);
1316 mod.deletion_set.deinit(gpa);
9091317
910 for (self.decl_table.items()) |entry| {
911 entry.value.destroy(self);
1318 for (mod.decl_table.items()) |entry| {
1319 entry.value.destroy(mod);
9121320 }
913 self.decl_table.deinit(gpa);
1321 mod.decl_table.deinit(gpa);
9141322
915 for (self.failed_decls.items()) |entry| {
1323 for (mod.failed_decls.items()) |entry| {
9161324 entry.value.destroy(gpa);
9171325 }
918 self.failed_decls.deinit(gpa);
1326 mod.failed_decls.deinit(gpa);
9191327
920 for (self.emit_h_failed_decls.items()) |entry| {
1328 for (mod.emit_h_failed_decls.items()) |entry| {
9211329 entry.value.destroy(gpa);
9221330 }
923 self.emit_h_failed_decls.deinit(gpa);
1331 mod.emit_h_failed_decls.deinit(gpa);
9241332
925 for (self.failed_files.items()) |entry| {
1333 for (mod.failed_files.items()) |entry| {
9261334 entry.value.destroy(gpa);
9271335 }
928 self.failed_files.deinit(gpa);
1336 mod.failed_files.deinit(gpa);
9291337
930 for (self.failed_exports.items()) |entry| {
1338 for (mod.failed_exports.items()) |entry| {
9311339 entry.value.destroy(gpa);
9321340 }
933 self.failed_exports.deinit(gpa);
1341 mod.failed_exports.deinit(gpa);
9341342
935 self.compile_log_decls.deinit(gpa);
1343 mod.compile_log_decls.deinit(gpa);
9361344
937 for (self.decl_exports.items()) |entry| {
1345 for (mod.decl_exports.items()) |entry| {
9381346 const export_list = entry.value;
9391347 gpa.free(export_list);
9401348 }
941 self.decl_exports.deinit(gpa);
1349 mod.decl_exports.deinit(gpa);
9421350
943 for (self.export_owners.items()) |entry| {
1351 for (mod.export_owners.items()) |entry| {
9441352 freeExportList(gpa, entry.value);
9451353 }
946 self.export_owners.deinit(gpa);
1354 mod.export_owners.deinit(gpa);
9471355
948 self.symbol_exports.deinit(gpa);
949 self.root_scope.destroy(gpa);
1356 mod.symbol_exports.deinit(gpa);
1357 mod.root_scope.destroy(gpa);
9501358
951 var it = self.global_error_set.iterator();
1359 var it = mod.global_error_set.iterator();
9521360 while (it.next()) |entry| {
9531361 gpa.free(entry.key);
9541362 }
955 self.global_error_set.deinit(gpa);
1363 mod.global_error_set.deinit(gpa);
9561364
957 for (self.import_table.items()) |entry| {
1365 for (mod.import_table.items()) |entry| {
9581366 entry.value.destroy(gpa);
9591367 }
960 self.import_table.deinit(gpa);
1368 mod.import_table.deinit(gpa);
9611369}
9621370
9631371fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
......@@ -1102,28 +1510,37 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
11021510 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
11031511 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
11041512 defer analysis_arena.deinit();
1105 var gen_scope: Scope.GenZIR = .{
1106 .decl = decl,
1107 .arena = &analysis_arena.allocator,
1108 .parent = &decl.container.base,
1109 .force_comptime = true,
1110 };
1111 defer gen_scope.instructions.deinit(mod.gpa);
11121513
1113 const block_expr = node_datas[decl_node].lhs;
1114 _ = try astgen.comptimeExpr(mod, &gen_scope.base, .none, block_expr);
1115 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
1116 zir.dumpZir(mod.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {};
1117 }
1514 const code: zir.Code = blk: {
1515 var wip_zir_code: WipZirCode = .{
1516 .decl = decl,
1517 .arena = &analysis_arena.allocator,
1518 .gpa = mod.gpa,
1519 };
1520 defer wip_zir_code.deinit();
1521 var gen_scope: Scope.GenZir = .{
1522 .force_comptime = true,
1523 .parent = &decl.container.base,
1524 .zir_code = &wip_zir_code,
1525 };
11181526
1119 var inst_table = Scope.Block.InstTable.init(mod.gpa);
1120 defer inst_table.deinit();
1527 const block_expr = node_datas[decl_node].lhs;
1528 _ = try astgen.comptimeExpr(mod, &gen_scope.base, .none, block_expr);
1529 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
1530 zir.dumpZir(mod.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {};
1531 }
1532 break :blk wip_zir_code.finish();
1533 };
11211534
1122 var branch_quota: u32 = default_eval_branch_quota;
1535 var sema: Sema = .{
1536 .mod = mod,
1537 .code = code,
1538 .inst_map = try mod.gpa.alloc(*ir.Inst, code.instructions.len),
1539 };
1540 defer mod.gpa.free(sema.inst_map);
11231541
11241542 var block_scope: Scope.Block = .{
11251543 .parent = null,
1126 .inst_table = &inst_table,
11271544 .func = null,
11281545 .owner_decl = decl,
11291546 .src_decl = decl,
......@@ -1131,13 +1548,10 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
11311548 .arena = &analysis_arena.allocator,
11321549 .inlining = null,
11331550 .is_comptime = true,
1134 .branch_quota = &branch_quota,
11351551 };
11361552 defer block_scope.instructions.deinit(mod.gpa);
11371553
1138 _ = try zir_sema.analyzeBody(mod, &block_scope, .{
1139 .instructions = gen_scope.instructions.items,
1140 });
1554 try sema.root(mod, &block_scope);
11411555
11421556 decl.analysis = .complete;
11431557 decl.generation = mod.generation;
......@@ -1160,7 +1574,6 @@ fn astgenAndSemaFn(
11601574
11611575 decl.analysis = .in_progress;
11621576
1163 const token_starts = tree.tokens.items(.start);
11641577 const token_tags = tree.tokens.items(.tag);
11651578
11661579 // This arena allocator's memory is discarded at the end of this function. It is used
......@@ -1168,13 +1581,18 @@ fn astgenAndSemaFn(
11681581 // to complete the Decl analysis.
11691582 var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
11701583 defer fn_type_scope_arena.deinit();
1171 var fn_type_scope: Scope.GenZIR = .{
1584
1585 var fn_type_wip_zir_exec: WipZirCode = .{
11721586 .decl = decl,
11731587 .arena = &fn_type_scope_arena.allocator,
1174 .parent = &decl.container.base,
1588 .gpa = mod.gpa,
1589 };
1590 defer fn_type_wip_zir_exec.deinit();
1591 var fn_type_scope: Scope.GenZir = .{
11751592 .force_comptime = true,
1593 .parent = &decl.container.base,
1594 .zir_code = &fn_type_wip_zir_exec,
11761595 };
1177 defer fn_type_scope.instructions.deinit(mod.gpa);
11781596
11791597 decl.is_pub = fn_proto.visib_token != null;
11801598
......@@ -1189,13 +1607,8 @@ fn astgenAndSemaFn(
11891607 }
11901608 break :blk count;
11911609 };
1192 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_count);
1193 const fn_src = token_starts[fn_proto.ast.fn_token];
1194 const type_type = try astgen.addZIRInstConst(mod, &fn_type_scope.base, fn_src, .{
1195 .ty = Type.initTag(.type),
1196 .val = Value.initTag(.type_type),
1197 });
1198 const type_type_rl: astgen.ResultLoc = .{ .ty = type_type };
1610 const param_types = try fn_type_scope_arena.allocator.alloc(zir.Inst.Index, param_count);
1611 const type_type_rl: astgen.ResultLoc = .{ .ty = @enumToInt(zir.Const.type_type) };
11991612
12001613 var is_var_args = false;
12011614 {
......@@ -1301,39 +1714,31 @@ fn astgenAndSemaFn(
13011714 else
13021715 false;
13031716
1304 const cc_inst = if (fn_proto.ast.callconv_expr != 0) cc: {
1717 const cc: zir.Inst.Index = if (fn_proto.ast.callconv_expr != 0)
13051718 // TODO instead of enum literal type, this needs to be the
13061719 // std.builtin.CallingConvention enum. We need to implement importing other files
13071720 // and enums in order to fix this.
1308 const src = token_starts[tree.firstToken(fn_proto.ast.callconv_expr)];
1309 const enum_lit_ty = try astgen.addZIRInstConst(mod, &fn_type_scope.base, src, .{
1310 .ty = Type.initTag(.type),
1311 .val = Value.initTag(.enum_literal_type),
1312 });
1313 break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
1314 .ty = enum_lit_ty,
1315 }, fn_proto.ast.callconv_expr);
1316 } else if (is_extern) cc: {
1317 // note: https://github.com/ziglang/zig/issues/5269
1318 const src = token_starts[fn_proto.extern_export_token.?];
1319 break :cc try astgen.addZIRInst(mod, &fn_type_scope.base, src, zir.Inst.EnumLiteral, .{ .name = "C" }, .{});
1320 } else null;
1321
1322 const fn_type_inst = if (cc_inst) |cc| fn_type: {
1323 var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type_cc, .{
1324 .return_type = return_type_inst,
1721 try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
1722 .ty = @enumToInt(zir.Const.enum_literal_type),
1723 }, fn_proto.ast.callconv_expr)
1724 else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
1725 try fn_type_scope.addStrBytes(.enum_literal, "C")
1726 else
1727 0;
1728
1729 const fn_type_inst: zir.Inst.Index = if (cc != 0) fn_type: {
1730 const tag: zir.Inst.Tag = if (is_var_args) .fn_type_cc_var_args else .fn_type_cc;
1731 break :fn_type try fn_type_scope.addFnTypeCc(.{
1732 .ret_ty = return_type_inst,
13251733 .param_types = param_types,
13261734 .cc = cc,
13271735 });
1328 if (is_var_args) fn_type.tag = .fn_type_cc_var_args;
1329 break :fn_type fn_type;
13301736 } else fn_type: {
1331 var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{
1332 .return_type = return_type_inst,
1737 const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type;
1738 break :fn_type try fn_type_scope.addFnType(.{
1739 .ret_ty = return_type_inst,
13331740 .param_types = param_types,
13341741 });
1335 if (is_var_args) fn_type.tag = .fn_type_var_args;
1336 break :fn_type fn_type;
13371742 };
13381743
13391744 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
......@@ -1345,14 +1750,17 @@ fn astgenAndSemaFn(
13451750 errdefer decl_arena.deinit();
13461751 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
13471752
1348 var inst_table = Scope.Block.InstTable.init(mod.gpa);
1349 defer inst_table.deinit();
1350
1351 var branch_quota: u32 = default_eval_branch_quota;
1753 const fn_type_code = fn_type_wip_zir_exec.finish();
1754 var fn_type_sema: Sema = .{
1755 .mod = mod,
1756 .code = fn_type_code,
1757 .inst_map = try mod.gpa.alloc(*ir.Inst, fn_type_code.instructions.len),
1758 };
1759 defer mod.gpa.free(fn_type_sema.inst_map);
13521760
13531761 var block_scope: Scope.Block = .{
13541762 .parent = null,
1355 .inst_table = &inst_table,
1763 .sema = &fn_type_sema,
13561764 .func = null,
13571765 .owner_decl = decl,
13581766 .src_decl = decl,
......@@ -1360,14 +1768,10 @@ fn astgenAndSemaFn(
13601768 .arena = &decl_arena.allocator,
13611769 .inlining = null,
13621770 .is_comptime = false,
1363 .branch_quota = &branch_quota,
13641771 };
13651772 defer block_scope.instructions.deinit(mod.gpa);
13661773
1367 const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{
1368 .instructions = fn_type_scope.instructions.items,
1369 });
1370
1774 const fn_type = try fn_type_sema.rootAsType(mod, &block_scope, fn_type_inst);
13711775 if (body_node == 0) {
13721776 if (!is_extern) {
13731777 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
......@@ -1411,43 +1815,47 @@ fn astgenAndSemaFn(
14111815
14121816 const fn_zir: zir.Body = blk: {
14131817 // We put the ZIR inside the Decl arena.
1414 var gen_scope: Scope.GenZIR = .{
1818 var wip_zir_code: WipZirCode = .{
14151819 .decl = decl,
14161820 .arena = &decl_arena.allocator,
1417 .parent = &decl.container.base,
1821 .gpa = mod.gpa,
1822 .arg_count = param_count,
1823 };
1824 defer wip_zir_code.deinit();
1825
1826 var gen_scope: Scope.GenZir = .{
14181827 .force_comptime = false,
1828 .parent = &decl.container.base,
1829 .zir_code = &wip_zir_code,
14191830 };
1420 defer gen_scope.instructions.deinit(mod.gpa);
1831 // Iterate over the parameters. We put the param names as the first N
1832 // items inside `extra` so that debug info later can refer to the parameter names
1833 // even while the respective source code is unloaded.
1834 try wip_zir_code.extra.ensureCapacity(mod.gpa, param_count);
14211835
1422 // We need an instruction for each parameter, and they must be first in the body.
1423 try gen_scope.instructions.resize(mod.gpa, param_count);
14241836 var params_scope = &gen_scope.base;
14251837 var i: usize = 0;
14261838 var it = fn_proto.iterate(tree);
14271839 while (it.next()) |param| : (i += 1) {
14281840 const name_token = param.name_token.?;
1429 const src = token_starts[name_token];
14301841 const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);
1431 const arg = try decl_arena.allocator.create(zir.Inst.Arg);
1432 arg.* = .{
1433 .base = .{
1434 .tag = .arg,
1435 .src = src,
1436 },
1437 .positionals = .{
1438 .name = param_name,
1439 },
1440 .kw_args = .{},
1441 };
1442 gen_scope.instructions.items[i] = &arg.base;
14431842 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
14441843 sub_scope.* = .{
14451844 .parent = params_scope,
14461845 .gen_zir = &gen_scope,
14471846 .name = param_name,
1448 .inst = &arg.base,
1847 // Implicit const list first, then implicit arg list.
1848 .inst = zir.const_inst_list.len + i,
14491849 };
14501850 params_scope = &sub_scope.base;
1851
1852 // Additionally put the param name into `string_bytes` and reference it with
1853 // `extra` so that we have access to the data in codegen, for debug info.
1854 const str_index = @intCast(u32, wip_zir_code.string_bytes.items.len);
1855 wip_zir_code.extra.appendAssumeCapacity(str_index);
1856 try wip_zir_code.string_bytes.ensureCapacity(mod.gpa, param_name.len + 1);
1857 wip_zir_code.string_bytes.appendSliceAssumeCapacity(param_name);
1858 wip_zir_code.string_bytes.appendAssumeCapacity(0);
14511859 }
14521860
14531861 _ = try astgen.expr(mod, params_scope, .none, body_node);
......@@ -1455,8 +1863,7 @@ fn astgenAndSemaFn(
14551863 if (gen_scope.instructions.items.len == 0 or
14561864 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
14571865 {
1458 const src = token_starts[tree.lastToken(body_node)];
1459 _ = try astgen.addZIRNoOp(mod, &gen_scope.base, src, .return_void);
1866 _ = try gen_scope.addRetTok(@enumToInt(zir.Const.void_value), tree.lastToken(body_node));
14601867 }
14611868
14621869 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
......@@ -1626,7 +2033,7 @@ fn astgenAndSemaVarDecl(
16262033 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
16272034 var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
16282035 defer gen_scope_arena.deinit();
1629 var gen_scope: Scope.GenZIR = .{
2036 var gen_scope: Scope.GenZir = .{
16302037 .decl = decl,
16312038 .arena = &gen_scope_arena.allocator,
16322039 .parent = &decl.container.base,
......@@ -1698,7 +2105,7 @@ fn astgenAndSemaVarDecl(
16982105 // Temporary arena for the zir instructions.
16992106 var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
17002107 defer type_scope_arena.deinit();
1701 var type_scope: Scope.GenZIR = .{
2108 var type_scope: Scope.GenZir = .{
17022109 .decl = decl,
17032110 .arena = &type_scope_arena.allocator,
17042111 .parent = &decl.container.base,
......@@ -1778,47 +2185,47 @@ fn astgenAndSemaVarDecl(
17782185 return type_changed;
17792186}
17802187
1781fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {
1782 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);
1783 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);
2188fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
2189 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);
2190 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);
17842191
17852192 depender.dependencies.putAssumeCapacity(dependee, {});
17862193 dependee.dependants.putAssumeCapacity(depender, {});
17872194}
17882195
1789pub fn getAstTree(self: *Module, root_scope: *Scope.File) !*const ast.Tree {
2196pub fn getAstTree(mod: *Module, root_scope: *Scope.File) !*const ast.Tree {
17902197 const tracy = trace(@src());
17912198 defer tracy.end();
17922199
17932200 switch (root_scope.status) {
17942201 .never_loaded, .unloaded_success => {
1795 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
2202 try mod.failed_files.ensureCapacity(mod.gpa, mod.failed_files.items().len + 1);
17962203
1797 const source = try root_scope.getSource(self);
2204 const source = try root_scope.getSource(mod);
17982205
17992206 var keep_tree = false;
1800 root_scope.tree = try std.zig.parse(self.gpa, source);
1801 defer if (!keep_tree) root_scope.tree.deinit(self.gpa);
2207 root_scope.tree = try std.zig.parse(mod.gpa, source);
2208 defer if (!keep_tree) root_scope.tree.deinit(mod.gpa);
18022209
18032210 const tree = &root_scope.tree;
18042211
18052212 if (tree.errors.len != 0) {
18062213 const parse_err = tree.errors[0];
18072214
1808 var msg = std.ArrayList(u8).init(self.gpa);
2215 var msg = std.ArrayList(u8).init(mod.gpa);
18092216 defer msg.deinit();
18102217
18112218 try tree.renderError(parse_err, msg.writer());
1812 const err_msg = try self.gpa.create(ErrorMsg);
2219 const err_msg = try mod.gpa.create(ErrorMsg);
18132220 err_msg.* = .{
18142221 .src_loc = .{
1815 .file_scope = root_scope,
1816 .byte_offset = tree.tokens.items(.start)[parse_err.token],
2222 .container = .{ .file_scope = root_scope },
2223 .lazy = .{ .token_abs = parse_err.token },
18172224 },
18182225 .msg = msg.toOwnedSlice(),
18192226 };
18202227
1821 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
2228 mod.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
18222229 root_scope.status = .unloaded_parse_failure;
18232230 return error.AnalysisFail;
18242231 }
......@@ -2051,11 +2458,9 @@ fn semaContainerFn(
20512458 const tracy = trace(@src());
20522459 defer tracy.end();
20532460
2054 const token_starts = tree.tokens.items(.start);
2055 const token_tags = tree.tokens.items(.tag);
2056
20572461 // We will create a Decl for it regardless of analysis status.
20582462 const name_tok = fn_proto.name_token orelse {
2463 // This problem will go away with #1717.
20592464 @panic("TODO missing function name");
20602465 };
20612466 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString
......@@ -2068,8 +2473,8 @@ fn semaContainerFn(
20682473 if (deleted_decls.swapRemove(decl) == null) {
20692474 decl.analysis = .sema_failure;
20702475 const msg = try ErrorMsg.create(mod.gpa, .{
2071 .file_scope = container_scope.file_scope,
2072 .byte_offset = token_starts[name_tok],
2476 .container = .{ .file_scope = container_scope.file_scope },
2477 .lazy = .{ .token_abs = name_tok },
20732478 }, "redefinition of '{s}'", .{decl.name});
20742479 errdefer msg.destroy(mod.gpa);
20752480 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
......@@ -2098,6 +2503,7 @@ fn semaContainerFn(
20982503 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
20992504 container_scope.decls.putAssumeCapacity(new_decl, {});
21002505 if (fn_proto.extern_export_token) |maybe_export_token| {
2506 const token_tags = tree.tokens.items(.tag);
21012507 if (token_tags[maybe_export_token] == .keyword_export) {
21022508 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
21032509 }
......@@ -2117,11 +2523,7 @@ fn semaContainerVar(
21172523 const tracy = trace(@src());
21182524 defer tracy.end();
21192525
2120 const token_starts = tree.tokens.items(.start);
2121 const token_tags = tree.tokens.items(.tag);
2122
21232526 const name_token = var_decl.ast.mut_token + 1;
2124 const name_src = token_starts[name_token];
21252527 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
21262528 const name_hash = container_scope.fullyQualifiedNameHash(name);
21272529 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
......@@ -2132,8 +2534,8 @@ fn semaContainerVar(
21322534 if (deleted_decls.swapRemove(decl) == null) {
21332535 decl.analysis = .sema_failure;
21342536 const err_msg = try ErrorMsg.create(mod.gpa, .{
2135 .file_scope = container_scope.file_scope,
2136 .byte_offset = name_src,
2537 .container = .{ .file_scope = container_scope.file_scope },
2538 .lazy = .{ .token_abs = name_token },
21372539 }, "redefinition of '{s}'", .{decl.name});
21382540 errdefer err_msg.destroy(mod.gpa);
21392541 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
......@@ -2145,6 +2547,7 @@ fn semaContainerVar(
21452547 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
21462548 container_scope.decls.putAssumeCapacity(new_decl, {});
21472549 if (var_decl.extern_export_token) |maybe_export_token| {
2550 const token_tags = tree.tokens.items(.tag);
21482551 if (token_tags[maybe_export_token] == .keyword_export) {
21492552 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
21502553 }
......@@ -2167,11 +2570,11 @@ fn semaContainerField(
21672570 log.err("TODO: analyze container field", .{});
21682571}
21692572
2170pub fn deleteDecl(self: *Module, decl: *Decl) !void {
2573pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
21712574 const tracy = trace(@src());
21722575 defer tracy.end();
21732576
2174 try self.deletion_set.ensureCapacity(self.gpa, self.deletion_set.items.len + decl.dependencies.items().len);
2577 try mod.deletion_set.ensureCapacity(mod.gpa, mod.deletion_set.items.len + decl.dependencies.items().len);
21752578
21762579 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
21772580 // not be present in the set, and this does nothing.
......@@ -2179,7 +2582,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
21792582
21802583 log.debug("deleting decl '{s}'", .{decl.name});
21812584 const name_hash = decl.fullyQualifiedNameHash();
2182 self.decl_table.removeAssertDiscard(name_hash);
2585 mod.decl_table.removeAssertDiscard(name_hash);
21832586 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
21842587 for (decl.dependencies.items()) |entry| {
21852588 const dep = entry.key;
......@@ -2188,7 +2591,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
21882591 // We don't recursively perform a deletion here, because during the update,
21892592 // another reference to it may turn up.
21902593 dep.deletion_flag = true;
2191 self.deletion_set.appendAssumeCapacity(dep);
2594 mod.deletion_set.appendAssumeCapacity(dep);
21922595 }
21932596 }
21942597 // Anything that depends on this deleted decl certainly needs to be re-analyzed.
......@@ -2197,29 +2600,29 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
21972600 dep.removeDependency(decl);
21982601 if (dep.analysis != .outdated) {
21992602 // TODO Move this failure possibility to the top of the function.
2200 try self.markOutdatedDecl(dep);
2603 try mod.markOutdatedDecl(dep);
22012604 }
22022605 }
2203 if (self.failed_decls.swapRemove(decl)) |entry| {
2204 entry.value.destroy(self.gpa);
2606 if (mod.failed_decls.swapRemove(decl)) |entry| {
2607 entry.value.destroy(mod.gpa);
22052608 }
2206 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {
2207 entry.value.destroy(self.gpa);
2609 if (mod.emit_h_failed_decls.swapRemove(decl)) |entry| {
2610 entry.value.destroy(mod.gpa);
22082611 }
2209 _ = self.compile_log_decls.swapRemove(decl);
2210 self.deleteDeclExports(decl);
2211 self.comp.bin_file.freeDecl(decl);
2612 _ = mod.compile_log_decls.swapRemove(decl);
2613 mod.deleteDeclExports(decl);
2614 mod.comp.bin_file.freeDecl(decl);
22122615
2213 decl.destroy(self);
2616 decl.destroy(mod);
22142617}
22152618
22162619/// Delete all the Export objects that are caused by this Decl. Re-analysis of
22172620/// this Decl will cause them to be re-created (or not).
2218fn deleteDeclExports(self: *Module, decl: *Decl) void {
2219 const kv = self.export_owners.swapRemove(decl) orelse return;
2621fn deleteDeclExports(mod: *Module, decl: *Decl) void {
2622 const kv = mod.export_owners.swapRemove(decl) orelse return;
22202623
22212624 for (kv.value) |exp| {
2222 if (self.decl_exports.getEntry(exp.exported_decl)) |decl_exports_kv| {
2625 if (mod.decl_exports.getEntry(exp.exported_decl)) |decl_exports_kv| {
22232626 // Remove exports with owner_decl matching the regenerating decl.
22242627 const list = decl_exports_kv.value;
22252628 var i: usize = 0;
......@@ -2232,73 +2635,100 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
22322635 i += 1;
22332636 }
22342637 }
2235 decl_exports_kv.value = self.gpa.shrink(list, new_len);
2638 decl_exports_kv.value = mod.gpa.shrink(list, new_len);
22362639 if (new_len == 0) {
2237 self.decl_exports.removeAssertDiscard(exp.exported_decl);
2640 mod.decl_exports.removeAssertDiscard(exp.exported_decl);
22382641 }
22392642 }
2240 if (self.comp.bin_file.cast(link.File.Elf)) |elf| {
2643 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
22412644 elf.deleteExport(exp.link.elf);
22422645 }
2243 if (self.comp.bin_file.cast(link.File.MachO)) |macho| {
2646 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
22442647 macho.deleteExport(exp.link.macho);
22452648 }
2246 if (self.failed_exports.swapRemove(exp)) |entry| {
2247 entry.value.destroy(self.gpa);
2649 if (mod.failed_exports.swapRemove(exp)) |entry| {
2650 entry.value.destroy(mod.gpa);
22482651 }
2249 _ = self.symbol_exports.swapRemove(exp.options.name);
2250 self.gpa.free(exp.options.name);
2251 self.gpa.destroy(exp);
2652 _ = mod.symbol_exports.swapRemove(exp.options.name);
2653 mod.gpa.free(exp.options.name);
2654 mod.gpa.destroy(exp);
22522655 }
2253 self.gpa.free(kv.value);
2656 mod.gpa.free(kv.value);
22542657}
22552658
2256pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {
2659pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {
22572660 const tracy = trace(@src());
22582661 defer tracy.end();
22592662
22602663 // Use the Decl's arena for function memory.
2261 var arena = decl.typed_value.most_recent.arena.?.promote(self.gpa);
2664 var arena = decl.typed_value.most_recent.arena.?.promote(mod.gpa);
22622665 defer decl.typed_value.most_recent.arena.?.* = arena.state;
2263 var inst_table = Scope.Block.InstTable.init(self.gpa);
2264 defer inst_table.deinit();
2265 var branch_quota: u32 = default_eval_branch_quota;
2666
2667 const inst_map = try mod.gpa.alloc(*ir.Inst, func.zir.instructions.len);
2668 defer mod.gpa.free(inst_map);
2669
2670 const fn_ty = decl.typed_value.most_recent.typed_value.ty;
2671 const param_inst_list = try mod.gpa.alloc(*ir.Inst, fn_ty.fnParamLen());
2672 defer mod.gpa.free(param_inst_list);
2673
2674 for (param_inst_list) |*param_inst, param_index| {
2675 const param_type = fn_ty.fnParamType(param_index);
2676 const name = func.zir.nullTerminatedString(func.zir.extra[param_index]);
2677 const arg_inst = try arena.allocator.create(ir.Inst.Arg);
2678 arg_inst.* = .{
2679 .base = .{
2680 .tag = .arg,
2681 .ty = param_type,
2682 .src = .unneeded,
2683 },
2684 .name = name,
2685 };
2686 param_inst.* = &arg_inst.base;
2687 }
2688
2689 var sema: Sema = .{
2690 .mod = mod,
2691 .gpa = mod.gpa,
2692 .arena = &arena.allocator,
2693 .code = func.zir,
2694 .inst_map = inst_map,
2695 .owner_decl = decl,
2696 .func = func,
2697 .param_inst_list = param_inst_list,
2698 };
22662699
22672700 var inner_block: Scope.Block = .{
22682701 .parent = null,
2269 .inst_table = &inst_table,
2270 .func = func,
2271 .owner_decl = decl,
2702 .sema = &sema,
22722703 .src_decl = decl,
22732704 .instructions = .{},
22742705 .arena = &arena.allocator,
22752706 .inlining = null,
22762707 .is_comptime = false,
2277 .branch_quota = &branch_quota,
22782708 };
2279 defer inner_block.instructions.deinit(self.gpa);
2709 defer inner_block.instructions.deinit(mod.gpa);
22802710
22812711 func.state = .in_progress;
22822712 log.debug("set {s} to in_progress", .{decl.name});
22832713
2284 try zir_sema.analyzeBody(self, &inner_block, func.zir);
2714 try sema.root(&inner_block);
22852715
2286 const instructions = try arena.allocator.dupe(*Inst, inner_block.instructions.items);
2716 const instructions = try arena.allocator.dupe(*ir.Inst, inner_block.instructions.items);
22872717 func.state = .success;
22882718 func.body = .{ .instructions = instructions };
22892719 log.debug("set {s} to success", .{decl.name});
22902720}
22912721
2292fn markOutdatedDecl(self: *Module, decl: *Decl) !void {
2722fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
22932723 log.debug("mark {s} outdated", .{decl.name});
2294 try self.comp.work_queue.writeItem(.{ .analyze_decl = decl });
2295 if (self.failed_decls.swapRemove(decl)) |entry| {
2296 entry.value.destroy(self.gpa);
2724 try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl });
2725 if (mod.failed_decls.swapRemove(decl)) |entry| {
2726 entry.value.destroy(mod.gpa);
22972727 }
2298 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {
2299 entry.value.destroy(self.gpa);
2728 if (mod.emit_h_failed_decls.swapRemove(decl)) |entry| {
2729 entry.value.destroy(mod.gpa);
23002730 }
2301 _ = self.compile_log_decls.swapRemove(decl);
2731 _ = mod.compile_log_decls.swapRemove(decl);
23022732 decl.analysis = .outdated;
23032733}
23042734
......@@ -2349,65 +2779,37 @@ fn allocateNewDecl(
23492779}
23502780
23512781fn createNewDecl(
2352 self: *Module,
2782 mod: *Module,
23532783 scope: *Scope,
23542784 decl_name: []const u8,
23552785 src_index: usize,
23562786 name_hash: Scope.NameHash,
23572787 contents_hash: std.zig.SrcHash,
23582788) !*Decl {
2359 try self.decl_table.ensureCapacity(self.gpa, self.decl_table.items().len + 1);
2360 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);
2361 errdefer self.gpa.destroy(new_decl);
2362 new_decl.name = try mem.dupeZ(self.gpa, u8, decl_name);
2363 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
2789 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);
2790 const new_decl = try mod.allocateNewDecl(scope, src_index, contents_hash);
2791 errdefer mod.gpa.destroy(new_decl);
2792 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
2793 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
23642794 return new_decl;
23652795}
23662796
23672797/// Get error value for error tag `name`.
2368pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
2369 const gop = try self.global_error_set.getOrPut(self.gpa, name);
2798pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
2799 const gop = try mod.global_error_set.getOrPut(mod.gpa, name);
23702800 if (gop.found_existing)
23712801 return gop.entry.*;
2372 errdefer self.global_error_set.removeAssertDiscard(name);
2802 errdefer mod.global_error_set.removeAssertDiscard(name);
23732803
2374 gop.entry.key = try self.gpa.dupe(u8, name);
2375 gop.entry.value = @intCast(u16, self.global_error_set.count() - 1);
2804 gop.entry.key = try mod.gpa.dupe(u8, name);
2805 gop.entry.value = @intCast(u16, mod.global_error_set.count() - 1);
23762806 return gop.entry.*;
23772807}
23782808
2379pub fn requireFunctionBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
2380 return scope.cast(Scope.Block) orelse
2381 return self.fail(scope, src, "instruction illegal outside function body", .{});
2382}
2383
2384pub fn requireRuntimeBlock(self: *Module, scope: *Scope, src: usize) !*Scope.Block {
2385 const block = try self.requireFunctionBlock(scope, src);
2386 if (block.is_comptime) {
2387 return self.fail(scope, src, "unable to resolve comptime value", .{});
2388 }
2389 return block;
2390}
2391
2392pub fn resolveConstValue(self: *Module, scope: *Scope, base: *Inst) !Value {
2393 return (try self.resolveDefinedValue(scope, base)) orelse
2394 return self.fail(scope, base.src, "unable to resolve comptime value", .{});
2395}
2396
2397pub fn resolveDefinedValue(self: *Module, scope: *Scope, base: *Inst) !?Value {
2398 if (base.value()) |val| {
2399 if (val.isUndef()) {
2400 return self.fail(scope, base.src, "use of undefined value here causes undefined behavior", .{});
2401 }
2402 return val;
2403 }
2404 return null;
2405}
2406
24072809pub fn analyzeExport(
24082810 mod: *Module,
24092811 scope: *Scope,
2410 src: usize,
2812 src: LazySrcLoc,
24112813 borrowed_symbol_name: []const u8,
24122814 exported_decl: *Decl,
24132815) !void {
......@@ -2496,178 +2898,11 @@ pub fn analyzeExport(
24962898 },
24972899 };
24982900}
2499
2500pub fn addNoOp(
2501 self: *Module,
2502 block: *Scope.Block,
2503 src: usize,
2504 ty: Type,
2505 comptime tag: Inst.Tag,
2506) !*Inst {
2507 const inst = try block.arena.create(tag.Type());
2508 inst.* = .{
2509 .base = .{
2510 .tag = tag,
2511 .ty = ty,
2512 .src = src,
2513 },
2514 };
2515 try block.instructions.append(self.gpa, &inst.base);
2516 return &inst.base;
2517}
2518
2519pub fn addUnOp(
2520 self: *Module,
2521 block: *Scope.Block,
2522 src: usize,
2523 ty: Type,
2524 tag: Inst.Tag,
2525 operand: *Inst,
2526) !*Inst {
2527 const inst = try block.arena.create(Inst.UnOp);
2528 inst.* = .{
2529 .base = .{
2530 .tag = tag,
2531 .ty = ty,
2532 .src = src,
2533 },
2534 .operand = operand,
2535 };
2536 try block.instructions.append(self.gpa, &inst.base);
2537 return &inst.base;
2538}
2539
2540pub fn addBinOp(
2541 self: *Module,
2542 block: *Scope.Block,
2543 src: usize,
2544 ty: Type,
2545 tag: Inst.Tag,
2546 lhs: *Inst,
2547 rhs: *Inst,
2548) !*Inst {
2549 const inst = try block.arena.create(Inst.BinOp);
2550 inst.* = .{
2551 .base = .{
2552 .tag = tag,
2553 .ty = ty,
2554 .src = src,
2555 },
2556 .lhs = lhs,
2557 .rhs = rhs,
2558 };
2559 try block.instructions.append(self.gpa, &inst.base);
2560 return &inst.base;
2561}
2562
2563pub fn addArg(self: *Module, block: *Scope.Block, src: usize, ty: Type, name: [*:0]const u8) !*Inst {
2564 const inst = try block.arena.create(Inst.Arg);
2565 inst.* = .{
2566 .base = .{
2567 .tag = .arg,
2568 .ty = ty,
2569 .src = src,
2570 },
2571 .name = name,
2572 };
2573 try block.instructions.append(self.gpa, &inst.base);
2574 return &inst.base;
2575}
2576
2577pub fn addBr(
2578 self: *Module,
2579 scope_block: *Scope.Block,
2580 src: usize,
2581 target_block: *Inst.Block,
2582 operand: *Inst,
2583) !*Inst.Br {
2584 const inst = try scope_block.arena.create(Inst.Br);
2585 inst.* = .{
2586 .base = .{
2587 .tag = .br,
2588 .ty = Type.initTag(.noreturn),
2589 .src = src,
2590 },
2591 .operand = operand,
2592 .block = target_block,
2593 };
2594 try scope_block.instructions.append(self.gpa, &inst.base);
2595 return inst;
2596}
2597
2598pub fn addCondBr(
2599 self: *Module,
2600 block: *Scope.Block,
2601 src: usize,
2602 condition: *Inst,
2603 then_body: ir.Body,
2604 else_body: ir.Body,
2605) !*Inst {
2606 const inst = try block.arena.create(Inst.CondBr);
2607 inst.* = .{
2608 .base = .{
2609 .tag = .condbr,
2610 .ty = Type.initTag(.noreturn),
2611 .src = src,
2612 },
2613 .condition = condition,
2614 .then_body = then_body,
2615 .else_body = else_body,
2616 };
2617 try block.instructions.append(self.gpa, &inst.base);
2618 return &inst.base;
2619}
2620
2621pub fn addCall(
2622 self: *Module,
2623 block: *Scope.Block,
2624 src: usize,
2625 ty: Type,
2626 func: *Inst,
2627 args: []const *Inst,
2628) !*Inst {
2629 const inst = try block.arena.create(Inst.Call);
2630 inst.* = .{
2631 .base = .{
2632 .tag = .call,
2633 .ty = ty,
2634 .src = src,
2635 },
2636 .func = func,
2637 .args = args,
2638 };
2639 try block.instructions.append(self.gpa, &inst.base);
2640 return &inst.base;
2641}
2642
2643pub fn addSwitchBr(
2644 self: *Module,
2645 block: *Scope.Block,
2646 src: usize,
2647 target: *Inst,
2648 cases: []Inst.SwitchBr.Case,
2649 else_body: ir.Body,
2650) !*Inst {
2651 const inst = try block.arena.create(Inst.SwitchBr);
2652 inst.* = .{
2653 .base = .{
2654 .tag = .switchbr,
2655 .ty = Type.initTag(.noreturn),
2656 .src = src,
2657 },
2658 .target = target,
2659 .cases = cases,
2660 .else_body = else_body,
2661 };
2662 try block.instructions.append(self.gpa, &inst.base);
2663 return &inst.base;
2664}
2665
2666pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedValue) !*Inst {
2667 const const_inst = try scope.arena().create(Inst.Constant);
2901pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst {
2902 const const_inst = try arena.create(ir.Inst.Constant);
26682903 const_inst.* = .{
26692904 .base = .{
2670 .tag = Inst.Constant.base_tag,
2905 .tag = ir.Inst.Constant.base_tag,
26712906 .ty = typed_value.ty,
26722907 .src = src,
26732908 },
......@@ -2676,94 +2911,94 @@ pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedVal
26762911 return &const_inst.base;
26772912}
26782913
2679pub fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
2680 return self.constInst(scope, src, .{
2914pub fn constType(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type) !*ir.Inst {
2915 return mod.constInst(arena, src, .{
26812916 .ty = Type.initTag(.type),
2682 .val = try ty.toValue(scope.arena()),
2917 .val = try ty.toValue(arena),
26832918 });
26842919}
26852920
2686pub fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {
2687 return self.constInst(scope, src, .{
2921pub fn constVoid(mod: *Module, arena: *Allocator, src: LazySrcLoc) !*ir.Inst {
2922 return mod.constInst(arena, src, .{
26882923 .ty = Type.initTag(.void),
26892924 .val = Value.initTag(.void_value),
26902925 });
26912926}
26922927
2693pub fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {
2694 return self.constInst(scope, src, .{
2928pub fn constNoReturn(mod: *Module, arena: *Allocator, src: LazySrcLoc) !*ir.Inst {
2929 return mod.constInst(arena, src, .{
26952930 .ty = Type.initTag(.noreturn),
26962931 .val = Value.initTag(.unreachable_value),
26972932 });
26982933}
26992934
2700pub fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {
2701 return self.constInst(scope, src, .{
2935pub fn constUndef(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type) !*ir.Inst {
2936 return mod.constInst(arena, src, .{
27022937 .ty = ty,
27032938 .val = Value.initTag(.undef),
27042939 });
27052940}
27062941
2707pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst {
2708 return self.constInst(scope, src, .{
2942pub fn constBool(mod: *Module, arena: *Allocator, src: LazySrcLoc, v: bool) !*ir.Inst {
2943 return mod.constInst(arena, src, .{
27092944 .ty = Type.initTag(.bool),
27102945 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],
27112946 });
27122947}
27132948
2714pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst {
2715 return self.constInst(scope, src, .{
2949pub fn constIntUnsigned(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, int: u64) !*ir.Inst {
2950 return mod.constInst(arena, src, .{
27162951 .ty = ty,
2717 .val = try Value.Tag.int_u64.create(scope.arena(), int),
2952 .val = try Value.Tag.int_u64.create(arena, int),
27182953 });
27192954}
27202955
2721pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst {
2722 return self.constInst(scope, src, .{
2956pub fn constIntSigned(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, int: i64) !*ir.Inst {
2957 return mod.constInst(arena, src, .{
27232958 .ty = ty,
2724 .val = try Value.Tag.int_i64.create(scope.arena(), int),
2959 .val = try Value.Tag.int_i64.create(arena, int),
27252960 });
27262961}
27272962
2728pub fn constIntBig(self: *Module, scope: *Scope, src: usize, ty: Type, big_int: BigIntConst) !*Inst {
2963pub fn constIntBig(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, big_int: BigIntConst) !*ir.Inst {
27292964 if (big_int.positive) {
27302965 if (big_int.to(u64)) |x| {
2731 return self.constIntUnsigned(scope, src, ty, x);
2966 return mod.constIntUnsigned(arena, src, ty, x);
27322967 } else |err| switch (err) {
27332968 error.NegativeIntoUnsigned => unreachable,
27342969 error.TargetTooSmall => {}, // handled below
27352970 }
2736 return self.constInst(scope, src, .{
2971 return mod.constInst(arena, src, .{
27372972 .ty = ty,
2738 .val = try Value.Tag.int_big_positive.create(scope.arena(), big_int.limbs),
2973 .val = try Value.Tag.int_big_positive.create(arena, big_int.limbs),
27392974 });
27402975 } else {
27412976 if (big_int.to(i64)) |x| {
2742 return self.constIntSigned(scope, src, ty, x);
2977 return mod.constIntSigned(arena, src, ty, x);
27432978 } else |err| switch (err) {
27442979 error.NegativeIntoUnsigned => unreachable,
27452980 error.TargetTooSmall => {}, // handled below
27462981 }
2747 return self.constInst(scope, src, .{
2982 return mod.constInst(arena, src, .{
27482983 .ty = ty,
2749 .val = try Value.Tag.int_big_negative.create(scope.arena(), big_int.limbs),
2984 .val = try Value.Tag.int_big_negative.create(arena, big_int.limbs),
27502985 });
27512986 }
27522987}
27532988
27542989pub fn createAnonymousDecl(
2755 self: *Module,
2990 mod: *Module,
27562991 scope: *Scope,
27572992 decl_arena: *std.heap.ArenaAllocator,
27582993 typed_value: TypedValue,
27592994) !*Decl {
2760 const name_index = self.getNextAnonNameIndex();
2995 const name_index = mod.getNextAnonNameIndex();
27612996 const scope_decl = scope.ownerDecl().?;
2762 const name = try std.fmt.allocPrint(self.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
2763 defer self.gpa.free(name);
2997 const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
2998 defer mod.gpa.free(name);
27642999 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
27653000 const src_hash: std.zig.SrcHash = undefined;
2766 const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
3001 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
27673002 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
27683003
27693004 decl_arena_state.* = decl_arena.state;
......@@ -2774,32 +3009,32 @@ pub fn createAnonymousDecl(
27743009 },
27753010 };
27763011 new_decl.analysis = .complete;
2777 new_decl.generation = self.generation;
3012 new_decl.generation = mod.generation;
27783013
27793014 // TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.
27803015 // We should be able to further improve the compiler to not omit Decls which are only referenced at
27813016 // compile-time and not runtime.
27823017 if (typed_value.ty.hasCodeGenBits()) {
2783 try self.comp.bin_file.allocateDeclIndexes(new_decl);
2784 try self.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });
3018 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
3019 try mod.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });
27853020 }
27863021
27873022 return new_decl;
27883023}
27893024
27903025pub fn createContainerDecl(
2791 self: *Module,
3026 mod: *Module,
27923027 scope: *Scope,
27933028 base_token: std.zig.ast.TokenIndex,
27943029 decl_arena: *std.heap.ArenaAllocator,
27953030 typed_value: TypedValue,
27963031) !*Decl {
27973032 const scope_decl = scope.ownerDecl().?;
2798 const name = try self.getAnonTypeName(scope, base_token);
2799 defer self.gpa.free(name);
3033 const name = try mod.getAnonTypeName(scope, base_token);
3034 defer mod.gpa.free(name);
28003035 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
28013036 const src_hash: std.zig.SrcHash = undefined;
2802 const new_decl = try self.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
3037 const new_decl = try mod.createNewDecl(scope, name, scope_decl.src_index, name_hash, src_hash);
28033038 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
28043039
28053040 decl_arena_state.* = decl_arena.state;
......@@ -2810,12 +3045,12 @@ pub fn createContainerDecl(
28103045 },
28113046 };
28123047 new_decl.analysis = .complete;
2813 new_decl.generation = self.generation;
3048 new_decl.generation = mod.generation;
28143049
28153050 return new_decl;
28163051}
28173052
2818fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
3053fn getAnonTypeName(mod: *Module, scope: *Scope, base_token: std.zig.ast.TokenIndex) ![]u8 {
28193054 // TODO add namespaces, generic function signatrues
28203055 const tree = scope.tree();
28213056 const token_tags = tree.tokens.items(.tag);
......@@ -2827,845 +3062,125 @@ fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIn
28273062 else => unreachable,
28283063 };
28293064 const loc = tree.tokenLocation(0, base_token);
2830 return std.fmt.allocPrint(self.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column });
3065 return std.fmt.allocPrint(mod.gpa, "{s}:{d}:{d}", .{ base_name, loc.line, loc.column });
28313066}
28323067
2833fn getNextAnonNameIndex(self: *Module) usize {
2834 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);
3068fn getNextAnonNameIndex(mod: *Module) usize {
3069 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
28353070}
28363071
2837pub fn lookupDeclName(self: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
3072pub fn lookupDeclName(mod: *Module, scope: *Scope, ident_name: []const u8) ?*Decl {
28383073 const namespace = scope.namespace();
28393074 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2840 return self.decl_table.get(name_hash);
2841}
2842
2843pub fn analyzeDeclVal(mod: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2844 const decl_ref = try mod.analyzeDeclRef(scope, src, decl);
2845 return mod.analyzeDeref(scope, src, decl_ref, src);
3075 return mod.decl_table.get(name_hash);
28463076}
28473077
2848pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {
2849 const scope_decl = scope.ownerDecl().?;
2850 try self.declareDeclDependency(scope_decl, decl);
2851 self.ensureDeclAnalyzed(decl) catch |err| {
2852 if (scope.cast(Scope.Block)) |block| {
2853 if (block.func) |func| {
2854 func.state = .dependency_failure;
2855 } else {
2856 block.owner_decl.analysis = .dependency_failure;
2857 }
2858 } else {
2859 scope_decl.analysis = .dependency_failure;
2860 }
2861 return err;
3078fn makeIntType(mod: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
3079 const int_payload = try scope.arena().create(Type.Payload.Bits);
3080 int_payload.* = .{
3081 .base = .{
3082 .tag = if (signed) .int_signed else .int_unsigned,
3083 },
3084 .data = bits,
28623085 };
2863
2864 const decl_tv = try decl.typedValue();
2865 if (decl_tv.val.tag() == .variable) {
2866 return self.analyzeVarRef(scope, src, decl_tv);
2867 }
2868 return self.constInst(scope, src, .{
2869 .ty = try self.simplePtrType(scope, src, decl_tv.ty, false, .One),
2870 .val = try Value.Tag.decl_ref.create(scope.arena(), decl),
2871 });
3086 return Type.initPayload(&int_payload.base);
28723087}
28733088
2874fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {
2875 const variable = tv.val.castTag(.variable).?.data;
2876
2877 const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);
2878 if (!variable.is_mutable and !variable.is_extern) {
2879 return self.constInst(scope, src, .{
2880 .ty = ty,
2881 .val = try Value.Tag.ref_val.create(scope.arena(), variable.init),
2882 });
2883 }
3089/// We don't return a pointer to the new error note because the pointer
3090/// becomes invalid when you add another one.
3091pub fn errNote(
3092 mod: *Module,
3093 scope: *Scope,
3094 src: LazySrcLoc,
3095 parent: *ErrorMsg,
3096 comptime format: []const u8,
3097 args: anytype,
3098) error{OutOfMemory}!void {
3099 const msg = try std.fmt.allocPrint(mod.gpa, format, args);
3100 errdefer mod.gpa.free(msg);
28843101
2885 const b = try self.requireRuntimeBlock(scope, src);
2886 const inst = try b.arena.create(Inst.VarPtr);
2887 inst.* = .{
2888 .base = .{
2889 .tag = .varptr,
2890 .ty = ty,
2891 .src = src,
3102 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
3103 parent.notes[parent.notes.len - 1] = .{
3104 .src_loc = .{
3105 .file_scope = scope.getFileScope(),
3106 .byte_offset = src,
28923107 },
2893 .variable = variable,
2894 };
2895 try b.instructions.append(self.gpa, &inst.base);
2896 return &inst.base;
2897}
2898
2899pub fn analyzeRef(mod: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
2900 const ptr_type = try mod.simplePtrType(scope, src, operand.ty, false, .One);
2901
2902 if (operand.value()) |val| {
2903 return mod.constInst(scope, src, .{
2904 .ty = ptr_type,
2905 .val = try Value.Tag.ref_val.create(scope.arena(), val),
2906 });
2907 }
2908
2909 const b = try mod.requireRuntimeBlock(scope, src);
2910 return mod.addUnOp(b, src, ptr_type, .ref, operand);
2911}
2912
2913pub fn analyzeDeref(self: *Module, scope: *Scope, src: usize, ptr: *Inst, ptr_src: usize) InnerError!*Inst {
2914 const elem_ty = switch (ptr.ty.zigTypeTag()) {
2915 .Pointer => ptr.ty.elemType(),
2916 else => return self.fail(scope, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
2917 };
2918 if (ptr.value()) |val| {
2919 return self.constInst(scope, src, .{
2920 .ty = elem_ty,
2921 .val = try val.pointerDeref(scope.arena()),
2922 });
2923 }
2924
2925 const b = try self.requireRuntimeBlock(scope, src);
2926 return self.addUnOp(b, src, elem_ty, .load, ptr);
2927}
2928
2929pub fn analyzeDeclRefByName(self: *Module, scope: *Scope, src: usize, decl_name: []const u8) InnerError!*Inst {
2930 const decl = self.lookupDeclName(scope, decl_name) orelse
2931 return self.fail(scope, src, "decl '{s}' not found", .{decl_name});
2932 return self.analyzeDeclRef(scope, src, decl);
2933}
2934
2935pub fn wantSafety(self: *Module, scope: *Scope) bool {
2936 // TODO take into account scope's safety overrides
2937 return switch (self.optimizeMode()) {
2938 .Debug => true,
2939 .ReleaseSafe => true,
2940 .ReleaseFast => false,
2941 .ReleaseSmall => false,
2942 };
2943}
2944
2945pub fn analyzeIsNull(
2946 self: *Module,
2947 scope: *Scope,
2948 src: usize,
2949 operand: *Inst,
2950 invert_logic: bool,
2951) InnerError!*Inst {
2952 if (operand.value()) |opt_val| {
2953 const is_null = opt_val.isNull();
2954 const bool_value = if (invert_logic) !is_null else is_null;
2955 return self.constBool(scope, src, bool_value);
2956 }
2957 const b = try self.requireRuntimeBlock(scope, src);
2958 const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null;
2959 return self.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand);
2960}
2961
2962pub fn analyzeIsErr(self: *Module, scope: *Scope, src: usize, operand: *Inst) InnerError!*Inst {
2963 const ot = operand.ty.zigTypeTag();
2964 if (ot != .ErrorSet and ot != .ErrorUnion) return self.constBool(scope, src, false);
2965 if (ot == .ErrorSet) return self.constBool(scope, src, true);
2966 assert(ot == .ErrorUnion);
2967 if (operand.value()) |err_union| {
2968 return self.constBool(scope, src, err_union.getError() != null);
2969 }
2970 const b = try self.requireRuntimeBlock(scope, src);
2971 return self.addUnOp(b, src, Type.initTag(.bool), .is_err, operand);
2972}
2973
2974pub fn analyzeSlice(self: *Module, scope: *Scope, src: usize, array_ptr: *Inst, start: *Inst, end_opt: ?*Inst, sentinel_opt: ?*Inst) InnerError!*Inst {
2975 const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
2976 .Pointer => array_ptr.ty.elemType(),
2977 else => return self.fail(scope, src, "expected pointer, found '{}'", .{array_ptr.ty}),
2978 };
2979
2980 var array_type = ptr_child;
2981 const elem_type = switch (ptr_child.zigTypeTag()) {
2982 .Array => ptr_child.elemType(),
2983 .Pointer => blk: {
2984 if (ptr_child.isSinglePointer()) {
2985 if (ptr_child.elemType().zigTypeTag() == .Array) {
2986 array_type = ptr_child.elemType();
2987 break :blk ptr_child.elemType().elemType();
2988 }
2989
2990 return self.fail(scope, src, "slice of single-item pointer", .{});
2991 }
2992 break :blk ptr_child.elemType();
2993 },
2994 else => return self.fail(scope, src, "slice of non-array type '{}'", .{ptr_child}),
2995 };
2996
2997 const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
2998 const casted = try self.coerce(scope, elem_type, sentinel);
2999 break :blk try self.resolveConstValue(scope, casted);
3000 } else null;
3001
3002 var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
3003 var return_elem_type = elem_type;
3004 if (end_opt) |end| {
3005 if (end.value()) |end_val| {
3006 if (start.value()) |start_val| {
3007 const start_u64 = start_val.toUnsignedInt();
3008 const end_u64 = end_val.toUnsignedInt();
3009 if (start_u64 > end_u64) {
3010 return self.fail(scope, src, "out of bounds slice", .{});
3011 }
3012
3013 const len = end_u64 - start_u64;
3014 const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
3015 array_type.sentinel()
3016 else
3017 slice_sentinel;
3018 return_elem_type = try self.arrayType(scope, len, array_sentinel, elem_type);
3019 return_ptr_size = .One;
3020 }
3021 }
3022 }
3023 const return_type = try self.ptrType(
3024 scope,
3025 src,
3026 return_elem_type,
3027 if (end_opt == null) slice_sentinel else null,
3028 0, // TODO alignment
3029 0,
3030 0,
3031 !ptr_child.isConstPtr(),
3032 ptr_child.isAllowzeroPtr(),
3033 ptr_child.isVolatilePtr(),
3034 return_ptr_size,
3035 );
3036
3037 return self.fail(scope, src, "TODO implement analysis of slice", .{});
3038}
3039
3040pub fn analyzeImport(self: *Module, scope: *Scope, src: usize, target_string: []const u8) !*Scope.File {
3041 const cur_pkg = scope.getFileScope().pkg;
3042 const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
3043 const found_pkg = cur_pkg.table.get(target_string);
3044
3045 const resolved_path = if (found_pkg) |pkg|
3046 try std.fs.path.resolve(self.gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
3047 else
3048 try std.fs.path.resolve(self.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
3049 errdefer self.gpa.free(resolved_path);
3050
3051 if (self.import_table.get(resolved_path)) |some| {
3052 self.gpa.free(resolved_path);
3053 return some;
3054 }
3055
3056 if (found_pkg == null) {
3057 const resolved_root_path = try std.fs.path.resolve(self.gpa, &[_][]const u8{cur_pkg_dir_path});
3058 defer self.gpa.free(resolved_root_path);
3059
3060 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
3061 return error.ImportOutsidePkgPath;
3062 }
3063 }
3064
3065 // TODO Scope.Container arena for ty and sub_file_path
3066 const file_scope = try self.gpa.create(Scope.File);
3067 errdefer self.gpa.destroy(file_scope);
3068 const struct_ty = try Type.Tag.empty_struct.create(self.gpa, &file_scope.root_container);
3069 errdefer self.gpa.destroy(struct_ty.castTag(.empty_struct).?);
3070
3071 file_scope.* = .{
3072 .sub_file_path = resolved_path,
3073 .source = .{ .unloaded = {} },
3074 .tree = undefined,
3075 .status = .never_loaded,
3076 .pkg = found_pkg orelse cur_pkg,
3077 .root_container = .{
3078 .file_scope = file_scope,
3079 .decls = .{},
3080 .ty = struct_ty,
3081 },
3082 };
3083 self.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
3084 error.AnalysisFail => {
3085 assert(self.comp.totalErrorCount() != 0);
3086 },
3087 else => |e| return e,
3088 };
3089 try self.import_table.put(self.gpa, file_scope.sub_file_path, file_scope);
3090 return file_scope;
3091}
3092
3093/// Asserts that lhs and rhs types are both numeric.
3094pub fn cmpNumeric(
3095 self: *Module,
3096 scope: *Scope,
3097 src: usize,
3098 lhs: *Inst,
3099 rhs: *Inst,
3100 op: std.math.CompareOperator,
3101) InnerError!*Inst {
3102 assert(lhs.ty.isNumeric());
3103 assert(rhs.ty.isNumeric());
3104
3105 const lhs_ty_tag = lhs.ty.zigTypeTag();
3106 const rhs_ty_tag = rhs.ty.zigTypeTag();
3107
3108 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
3109 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
3110 return self.fail(scope, src, "vector length mismatch: {d} and {d}", .{
3111 lhs.ty.arrayLen(),
3112 rhs.ty.arrayLen(),
3113 });
3114 }
3115 return self.fail(scope, src, "TODO implement support for vectors in cmpNumeric", .{});
3116 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
3117 return self.fail(scope, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
3118 lhs.ty,
3119 rhs.ty,
3120 });
3121 }
3122
3123 if (lhs.value()) |lhs_val| {
3124 if (rhs.value()) |rhs_val| {
3125 return self.constBool(scope, src, Value.compare(lhs_val, op, rhs_val));
3126 }
3127 }
3128
3129 // TODO handle comparisons against lazy zero values
3130 // Some values can be compared against zero without being runtime known or without forcing
3131 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
3132 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
3133 // of this function if we don't need to.
3134
3135 // It must be a runtime comparison.
3136 const b = try self.requireRuntimeBlock(scope, src);
3137 // For floats, emit a float comparison instruction.
3138 const lhs_is_float = switch (lhs_ty_tag) {
3139 .Float, .ComptimeFloat => true,
3140 else => false,
3141 };
3142 const rhs_is_float = switch (rhs_ty_tag) {
3143 .Float, .ComptimeFloat => true,
3144 else => false,
3145 };
3146 if (lhs_is_float and rhs_is_float) {
3147 // Implicit cast the smaller one to the larger one.
3148 const dest_type = x: {
3149 if (lhs_ty_tag == .ComptimeFloat) {
3150 break :x rhs.ty;
3151 } else if (rhs_ty_tag == .ComptimeFloat) {
3152 break :x lhs.ty;
3153 }
3154 if (lhs.ty.floatBits(self.getTarget()) >= rhs.ty.floatBits(self.getTarget())) {
3155 break :x lhs.ty;
3156 } else {
3157 break :x rhs.ty;
3158 }
3159 };
3160 const casted_lhs = try self.coerce(scope, dest_type, lhs);
3161 const casted_rhs = try self.coerce(scope, dest_type, rhs);
3162 return self.addBinOp(b, src, dest_type, Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
3163 }
3164 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
3165 // For mixed signed and unsigned integers, implicit cast both operands to a signed
3166 // integer with + 1 bit.
3167 // For mixed floats and integers, extract the integer part from the float, cast that to
3168 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
3169 // add/subtract 1.
3170 const lhs_is_signed = if (lhs.value()) |lhs_val|
3171 lhs_val.compareWithZero(.lt)
3172 else
3173 (lhs.ty.isFloat() or lhs.ty.isSignedInt());
3174 const rhs_is_signed = if (rhs.value()) |rhs_val|
3175 rhs_val.compareWithZero(.lt)
3176 else
3177 (rhs.ty.isFloat() or rhs.ty.isSignedInt());
3178 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
3179
3180 var dest_float_type: ?Type = null;
3181
3182 var lhs_bits: usize = undefined;
3183 if (lhs.value()) |lhs_val| {
3184 if (lhs_val.isUndef())
3185 return self.constUndef(scope, src, Type.initTag(.bool));
3186 const is_unsigned = if (lhs_is_float) x: {
3187 var bigint_space: Value.BigIntSpace = undefined;
3188 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(self.gpa);
3189 defer bigint.deinit();
3190 const zcmp = lhs_val.orderAgainstZero();
3191 if (lhs_val.floatHasFraction()) {
3192 switch (op) {
3193 .eq => return self.constBool(scope, src, false),
3194 .neq => return self.constBool(scope, src, true),
3195 else => {},
3196 }
3197 if (zcmp == .lt) {
3198 try bigint.addScalar(bigint.toConst(), -1);
3199 } else {
3200 try bigint.addScalar(bigint.toConst(), 1);
3201 }
3202 }
3203 lhs_bits = bigint.toConst().bitCountTwosComp();
3204 break :x (zcmp != .lt);
3205 } else x: {
3206 lhs_bits = lhs_val.intBitCountTwosComp();
3207 break :x (lhs_val.orderAgainstZero() != .lt);
3208 };
3209 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
3210 } else if (lhs_is_float) {
3211 dest_float_type = lhs.ty;
3212 } else {
3213 const int_info = lhs.ty.intInfo(self.getTarget());
3214 lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
3215 }
3216
3217 var rhs_bits: usize = undefined;
3218 if (rhs.value()) |rhs_val| {
3219 if (rhs_val.isUndef())
3220 return self.constUndef(scope, src, Type.initTag(.bool));
3221 const is_unsigned = if (rhs_is_float) x: {
3222 var bigint_space: Value.BigIntSpace = undefined;
3223 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(self.gpa);
3224 defer bigint.deinit();
3225 const zcmp = rhs_val.orderAgainstZero();
3226 if (rhs_val.floatHasFraction()) {
3227 switch (op) {
3228 .eq => return self.constBool(scope, src, false),
3229 .neq => return self.constBool(scope, src, true),
3230 else => {},
3231 }
3232 if (zcmp == .lt) {
3233 try bigint.addScalar(bigint.toConst(), -1);
3234 } else {
3235 try bigint.addScalar(bigint.toConst(), 1);
3236 }
3237 }
3238 rhs_bits = bigint.toConst().bitCountTwosComp();
3239 break :x (zcmp != .lt);
3240 } else x: {
3241 rhs_bits = rhs_val.intBitCountTwosComp();
3242 break :x (rhs_val.orderAgainstZero() != .lt);
3243 };
3244 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
3245 } else if (rhs_is_float) {
3246 dest_float_type = rhs.ty;
3247 } else {
3248 const int_info = rhs.ty.intInfo(self.getTarget());
3249 rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
3250 }
3251
3252 const dest_type = if (dest_float_type) |ft| ft else blk: {
3253 const max_bits = std.math.max(lhs_bits, rhs_bits);
3254 const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {
3255 error.Overflow => return self.fail(scope, src, "{d} exceeds maximum integer bit count", .{max_bits}),
3256 };
3257 break :blk try self.makeIntType(scope, dest_int_is_signed, casted_bits);
3258 };
3259 const casted_lhs = try self.coerce(scope, dest_type, lhs);
3260 const casted_rhs = try self.coerce(scope, dest_type, rhs);
3261
3262 return self.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
3263}
3264
3265fn wrapOptional(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3266 if (inst.value()) |val| {
3267 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3268 }
3269
3270 const b = try self.requireRuntimeBlock(scope, inst.src);
3271 return self.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
3272}
3273
3274fn wrapErrorUnion(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3275 // TODO deal with inferred error sets
3276 const err_union = dest_type.castTag(.error_union).?;
3277 if (inst.value()) |val| {
3278 const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: {
3279 _ = try self.coerce(scope, err_union.data.payload, inst);
3280 break :blk val;
3281 } else switch (err_union.data.error_set.tag()) {
3282 .anyerror => val,
3283 .error_set_single => blk: {
3284 const n = err_union.data.error_set.castTag(.error_set_single).?.data;
3285 if (!mem.eql(u8, val.castTag(.@"error").?.data.name, n))
3286 return self.fail(scope, inst.src, "expected type '{}', found type '{}'", .{ err_union.data.error_set, inst.ty });
3287 break :blk val;
3288 },
3289 .error_set => blk: {
3290 const f = err_union.data.error_set.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
3291 if (f.get(val.castTag(.@"error").?.data.name) == null)
3292 return self.fail(scope, inst.src, "expected type '{}', found type '{}'", .{ err_union.data.error_set, inst.ty });
3293 break :blk val;
3294 },
3295 else => unreachable,
3296 };
3297
3298 return self.constInst(scope, inst.src, .{
3299 .ty = dest_type,
3300 // creating a SubValue for the error_union payload
3301 .val = try Value.Tag.error_union.create(
3302 scope.arena(),
3303 to_wrap,
3304 ),
3305 });
3306 }
3307
3308 const b = try self.requireRuntimeBlock(scope, inst.src);
3309
3310 // we are coercing from E to E!T
3311 if (inst.ty.zigTypeTag() == .ErrorSet) {
3312 var coerced = try self.coerce(scope, err_union.data.error_set, inst);
3313 return self.addUnOp(b, inst.src, dest_type, .wrap_errunion_err, coerced);
3314 } else {
3315 var coerced = try self.coerce(scope, err_union.data.payload, inst);
3316 return self.addUnOp(b, inst.src, dest_type, .wrap_errunion_payload, coerced);
3317 }
3318}
3319
3320fn makeIntType(self: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
3321 const int_payload = try scope.arena().create(Type.Payload.Bits);
3322 int_payload.* = .{
3323 .base = .{
3324 .tag = if (signed) .int_signed else .int_unsigned,
3325 },
3326 .data = bits,
3327 };
3328 return Type.initPayload(&int_payload.base);
3329}
3330
3331pub fn resolvePeerTypes(self: *Module, scope: *Scope, instructions: []*Inst) !Type {
3332 if (instructions.len == 0)
3333 return Type.initTag(.noreturn);
3334
3335 if (instructions.len == 1)
3336 return instructions[0].ty;
3337
3338 var chosen = instructions[0];
3339 for (instructions[1..]) |candidate| {
3340 if (candidate.ty.eql(chosen.ty))
3341 continue;
3342 if (candidate.ty.zigTypeTag() == .NoReturn)
3343 continue;
3344 if (chosen.ty.zigTypeTag() == .NoReturn) {
3345 chosen = candidate;
3346 continue;
3347 }
3348 if (candidate.ty.zigTypeTag() == .Undefined)
3349 continue;
3350 if (chosen.ty.zigTypeTag() == .Undefined) {
3351 chosen = candidate;
3352 continue;
3353 }
3354 if (chosen.ty.isInt() and
3355 candidate.ty.isInt() and
3356 chosen.ty.isSignedInt() == candidate.ty.isSignedInt())
3357 {
3358 if (chosen.ty.intInfo(self.getTarget()).bits < candidate.ty.intInfo(self.getTarget()).bits) {
3359 chosen = candidate;
3360 }
3361 continue;
3362 }
3363 if (chosen.ty.isFloat() and candidate.ty.isFloat()) {
3364 if (chosen.ty.floatBits(self.getTarget()) < candidate.ty.floatBits(self.getTarget())) {
3365 chosen = candidate;
3366 }
3367 continue;
3368 }
3369
3370 if (chosen.ty.zigTypeTag() == .ComptimeInt and candidate.ty.isInt()) {
3371 chosen = candidate;
3372 continue;
3373 }
3374
3375 if (chosen.ty.isInt() and candidate.ty.zigTypeTag() == .ComptimeInt) {
3376 continue;
3377 }
3378
3379 // TODO error notes pointing out each type
3380 return self.fail(scope, candidate.src, "incompatible types: '{}' and '{}'", .{ chosen.ty, candidate.ty });
3381 }
3382
3383 return chosen.ty;
3384}
3385
3386pub fn coerce(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!*Inst {
3387 if (dest_type.tag() == .var_args_param) {
3388 return self.coerceVarArgParam(scope, inst);
3389 }
3390 // If the types are the same, we can return the operand.
3391 if (dest_type.eql(inst.ty))
3392 return inst;
3393
3394 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
3395 if (in_memory_result == .ok) {
3396 return self.bitcast(scope, dest_type, inst);
3397 }
3398
3399 // undefined to anything
3400 if (inst.value()) |val| {
3401 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
3402 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3403 }
3404 }
3405 assert(inst.ty.zigTypeTag() != .Undefined);
3406
3407 // null to ?T
3408 if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
3409 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
3410 }
3411
3412 // T to ?T
3413 if (dest_type.zigTypeTag() == .Optional) {
3414 var buf: Type.Payload.ElemType = undefined;
3415 const child_type = dest_type.optionalChild(&buf);
3416 if (child_type.eql(inst.ty)) {
3417 return self.wrapOptional(scope, dest_type, inst);
3418 } else if (try self.coerceNum(scope, child_type, inst)) |some| {
3419 return self.wrapOptional(scope, dest_type, some);
3420 }
3421 }
3422
3423 // T to E!T or E to E!T
3424 if (dest_type.tag() == .error_union) {
3425 return try self.wrapErrorUnion(scope, dest_type, inst);
3426 }
3427
3428 // Coercions where the source is a single pointer to an array.
3429 src_array_ptr: {
3430 if (!inst.ty.isSinglePointer()) break :src_array_ptr;
3431 const array_type = inst.ty.elemType();
3432 if (array_type.zigTypeTag() != .Array) break :src_array_ptr;
3433 const array_elem_type = array_type.elemType();
3434 if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr;
3435 if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr;
3436
3437 const dst_elem_type = dest_type.elemType();
3438 switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) {
3439 .ok => {},
3440 .no_match => break :src_array_ptr,
3441 }
3442
3443 switch (dest_type.ptrSize()) {
3444 .Slice => {
3445 // *[N]T to []T
3446 return self.coerceArrayPtrToSlice(scope, dest_type, inst);
3447 },
3448 .C => {
3449 // *[N]T to [*c]T
3450 return self.coerceArrayPtrToMany(scope, dest_type, inst);
3451 },
3452 .Many => {
3453 // *[N]T to [*]T
3454 // *[N:s]T to [*:s]T
3455 const src_sentinel = array_type.sentinel();
3456 const dst_sentinel = dest_type.sentinel();
3457 if (src_sentinel == null and dst_sentinel == null)
3458 return self.coerceArrayPtrToMany(scope, dest_type, inst);
3459
3460 if (src_sentinel) |src_s| {
3461 if (dst_sentinel) |dst_s| {
3462 if (src_s.eql(dst_s)) {
3463 return self.coerceArrayPtrToMany(scope, dest_type, inst);
3464 }
3465 }
3466 }
3467 },
3468 .One => {},
3469 }
3470 }
3471
3472 // comptime known number to other number
3473 if (try self.coerceNum(scope, dest_type, inst)) |some|
3474 return some;
3475
3476 // integer widening
3477 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
3478 assert(inst.value() == null); // handled above
3479
3480 const src_info = inst.ty.intInfo(self.getTarget());
3481 const dst_info = dest_type.intInfo(self.getTarget());
3482 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
3483 // small enough unsigned ints can get casted to large enough signed ints
3484 (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits))
3485 {
3486 const b = try self.requireRuntimeBlock(scope, inst.src);
3487 return self.addUnOp(b, inst.src, dest_type, .intcast, inst);
3488 }
3489 }
3490
3491 // float widening
3492 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
3493 assert(inst.value() == null); // handled above
3494
3495 const src_bits = inst.ty.floatBits(self.getTarget());
3496 const dst_bits = dest_type.floatBits(self.getTarget());
3497 if (dst_bits >= src_bits) {
3498 const b = try self.requireRuntimeBlock(scope, inst.src);
3499 return self.addUnOp(b, inst.src, dest_type, .floatcast, inst);
3500 }
3501 }
3502
3503 return self.fail(scope, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
3504}
3505
3506pub fn coerceNum(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) InnerError!?*Inst {
3507 const val = inst.value() orelse return null;
3508 const src_zig_tag = inst.ty.zigTypeTag();
3509 const dst_zig_tag = dest_type.zigTypeTag();
3510
3511 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
3512 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3513 if (val.floatHasFraction()) {
3514 return self.fail(scope, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
3515 }
3516 return self.fail(scope, inst.src, "TODO float to int", .{});
3517 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3518 if (!val.intFitsInType(dest_type, self.getTarget())) {
3519 return self.fail(scope, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
3520 }
3521 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3522 }
3523 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
3524 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3525 const res = val.floatCast(scope.arena(), dest_type, self.getTarget()) catch |err| switch (err) {
3526 error.Overflow => return self.fail(
3527 scope,
3528 inst.src,
3529 "cast of value {} to type '{}' loses information",
3530 .{ val, dest_type },
3531 ),
3532 error.OutOfMemory => return error.OutOfMemory,
3533 };
3534 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
3535 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3536 return self.fail(scope, inst.src, "TODO int to float", .{});
3537 }
3538 }
3539 return null;
3540}
3541
3542pub fn coerceVarArgParam(mod: *Module, scope: *Scope, inst: *Inst) !*Inst {
3543 switch (inst.ty.zigTypeTag()) {
3544 .ComptimeInt, .ComptimeFloat => return mod.fail(scope, inst.src, "integer and float literals in var args function must be casted", .{}),
3545 else => {},
3546 }
3547 // TODO implement more of this function.
3548 return inst;
3549}
3550
3551pub fn storePtr(self: *Module, scope: *Scope, src: usize, ptr: *Inst, uncasted_value: *Inst) !*Inst {
3552 if (ptr.ty.isConstPtr())
3553 return self.fail(scope, src, "cannot assign to constant", .{});
3554
3555 const elem_ty = ptr.ty.elemType();
3556 const value = try self.coerce(scope, elem_ty, uncasted_value);
3557 if (elem_ty.onePossibleValue() != null)
3558 return self.constVoid(scope, src);
3559
3560 // TODO handle comptime pointer writes
3561 // TODO handle if the element type requires comptime
3562
3563 const b = try self.requireRuntimeBlock(scope, src);
3564 return self.addBinOp(b, src, Type.initTag(.void), .store, ptr, value);
3565}
3566
3567pub fn bitcast(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3568 if (inst.value()) |val| {
3569 // Keep the comptime Value representation; take the new type.
3570 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3571 }
3572 // TODO validate the type size and other compile errors
3573 const b = try self.requireRuntimeBlock(scope, inst.src);
3574 return self.addUnOp(b, inst.src, dest_type, .bitcast, inst);
3575}
3576
3577fn coerceArrayPtrToSlice(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3578 if (inst.value()) |val| {
3579 // The comptime Value representation is compatible with both types.
3580 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3581 }
3582 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
3583}
3584
3585fn coerceArrayPtrToMany(self: *Module, scope: *Scope, dest_type: Type, inst: *Inst) !*Inst {
3586 if (inst.value()) |val| {
3587 // The comptime Value representation is compatible with both types.
3588 return self.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3589 }
3590 return self.fail(scope, inst.src, "TODO implement coerceArrayPtrToMany runtime instruction", .{});
3591}
3592
3593/// We don't return a pointer to the new error note because the pointer
3594/// becomes invalid when you add another one.
3595pub fn errNote(
3596 mod: *Module,
3597 scope: *Scope,
3598 src: usize,
3599 parent: *ErrorMsg,
3600 comptime format: []const u8,
3601 args: anytype,
3602) error{OutOfMemory}!void {
3603 const msg = try std.fmt.allocPrint(mod.gpa, format, args);
3604 errdefer mod.gpa.free(msg);
3605
3606 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
3607 parent.notes[parent.notes.len - 1] = .{
3608 .src_loc = .{
3609 .file_scope = scope.getFileScope(),
3610 .byte_offset = src,
3611 },
3612 .msg = msg,
3108 .msg = msg,
36133109 };
36143110}
36153111
36163112pub fn errMsg(
36173113 mod: *Module,
36183114 scope: *Scope,
3619 src_byte_offset: usize,
3115 src: LazySrcLoc,
36203116 comptime format: []const u8,
36213117 args: anytype,
36223118) error{OutOfMemory}!*ErrorMsg {
36233119 return ErrorMsg.create(mod.gpa, .{
3624 .file_scope = scope.getFileScope(),
3625 .byte_offset = src_byte_offset,
3120 .decl = scope.srcDecl().?,
3121 .lazy = src,
36263122 }, format, args);
36273123}
36283124
36293125pub fn fail(
36303126 mod: *Module,
36313127 scope: *Scope,
3632 src_byte_offset: usize,
3128 src: LazySrcLoc,
36333129 comptime format: []const u8,
36343130 args: anytype,
36353131) InnerError {
3636 const err_msg = try mod.errMsg(scope, src_byte_offset, format, args);
3132 const err_msg = try mod.errMsg(scope, src, format, args);
36373133 return mod.failWithOwnedErrorMsg(scope, err_msg);
36383134}
36393135
3136/// Same as `fail`, except given an absolute byte offset, and the function sets up the `LazySrcLoc`
3137/// for pointing at it relatively by subtracting from the containing `Decl`.
3138pub fn failOff(
3139 mod: *Module,
3140 scope: *Scope,
3141 byte_offset: u32,
3142 comptime format: []const u8,
3143 args: anytype,
3144) InnerError {
3145 const decl_byte_offset = scope.srcDecl().?.srcByteOffset();
3146 const src: LazySrcLoc = .{ .byte_offset = byte_offset - decl_byte_offset };
3147 return mod.fail(scope, src, format, args);
3148}
3149
3150/// Same as `fail`, except given a token index, and the function sets up the `LazySrcLoc`
3151/// for pointing at it relatively by subtracting from the containing `Decl`.
36403152pub fn failTok(
3641 self: *Module,
3153 mod: *Module,
36423154 scope: *Scope,
36433155 token_index: ast.TokenIndex,
36443156 comptime format: []const u8,
36453157 args: anytype,
36463158) InnerError {
3647 const src = scope.tree().tokens.items(.start)[token_index];
3648 return self.fail(scope, src, format, args);
3159 const decl_token = scope.srcDecl().?.srcToken();
3160 const src: LazySrcLoc = .{ .token_offset = token_index - decl_token };
3161 return mod.fail(scope, src, format, args);
36493162}
36503163
3164/// Same as `fail`, except given an AST node index, and the function sets up the `LazySrcLoc`
3165/// for pointing at it relatively by subtracting from the containing `Decl`.
36513166pub fn failNode(
3652 self: *Module,
3167 mod: *Module,
36533168 scope: *Scope,
3654 ast_node: ast.Node.Index,
3169 node_index: ast.Node.Index,
36553170 comptime format: []const u8,
36563171 args: anytype,
36573172) InnerError {
3658 const tree = scope.tree();
3659 const src = tree.tokens.items(.start)[tree.firstToken(ast_node)];
3660 return self.fail(scope, src, format, args);
3173 const decl_node = scope.srcDecl().?.srcNode();
3174 const src: LazySrcLoc = .{ .node_offset = node_index - decl_node };
3175 return mod.fail(scope, src, format, args);
36613176}
36623177
3663pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
3178pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
36643179 @setCold(true);
36653180 {
3666 errdefer err_msg.destroy(self.gpa);
3667 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);
3668 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);
3181 errdefer err_msg.destroy(mod.gpa);
3182 try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);
3183 try mod.failed_files.ensureCapacity(mod.gpa, mod.failed_files.items().len + 1);
36693184 }
36703185 switch (scope.tag) {
36713186 .block => {
......@@ -3675,41 +3190,41 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
36753190 func.state = .sema_failure;
36763191 } else {
36773192 block.owner_decl.analysis = .sema_failure;
3678 block.owner_decl.generation = self.generation;
3193 block.owner_decl.generation = mod.generation;
36793194 }
36803195 } else {
36813196 if (block.func) |func| {
36823197 func.state = .sema_failure;
36833198 } else {
36843199 block.owner_decl.analysis = .sema_failure;
3685 block.owner_decl.generation = self.generation;
3200 block.owner_decl.generation = mod.generation;
36863201 }
36873202 }
3688 self.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);
3203 mod.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);
36893204 },
36903205 .gen_zir, .gen_suspend => {
3691 const gen_zir = scope.cast(Scope.GenZIR).?;
3206 const gen_zir = scope.cast(Scope.GenZir).?;
36923207 gen_zir.decl.analysis = .sema_failure;
3693 gen_zir.decl.generation = self.generation;
3694 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3208 gen_zir.decl.generation = mod.generation;
3209 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
36953210 },
36963211 .local_val => {
36973212 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
36983213 gen_zir.decl.analysis = .sema_failure;
3699 gen_zir.decl.generation = self.generation;
3700 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3214 gen_zir.decl.generation = mod.generation;
3215 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
37013216 },
37023217 .local_ptr => {
37033218 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
37043219 gen_zir.decl.analysis = .sema_failure;
3705 gen_zir.decl.generation = self.generation;
3706 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3220 gen_zir.decl.generation = mod.generation;
3221 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
37073222 },
37083223 .gen_nosuspend => {
37093224 const gen_zir = scope.cast(Scope.Nosuspend).?.gen_zir;
37103225 gen_zir.decl.analysis = .sema_failure;
3711 gen_zir.decl.generation = self.generation;
3712 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3226 gen_zir.decl.generation = mod.generation;
3227 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
37133228 },
37143229 .file => unreachable,
37153230 .container => unreachable,
......@@ -3717,20 +3232,6 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
37173232 return error.AnalysisFail;
37183233}
37193234
3720const InMemoryCoercionResult = enum {
3721 ok,
3722 no_match,
3723};
3724
3725fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
3726 if (dest_type.eql(src_type))
3727 return .ok;
3728
3729 // TODO: implement more of this function
3730
3731 return .no_match;
3732}
3733
37343235fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {
37353236 return @bitCast(u128, a) == @bitCast(u128, b);
37363237}
......@@ -3780,10 +3281,10 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
37803281}
37813282
37823283pub fn floatAdd(
3783 self: *Module,
3284 mod: *Module,
37843285 scope: *Scope,
37853286 float_type: Type,
3786 src: usize,
3287 src: LazySrcLoc,
37873288 lhs: Value,
37883289 rhs: Value,
37893290) !Value {
......@@ -3815,10 +3316,10 @@ pub fn floatAdd(
38153316}
38163317
38173318pub fn floatSub(
3818 self: *Module,
3319 mod: *Module,
38193320 scope: *Scope,
38203321 float_type: Type,
3821 src: usize,
3322 src: LazySrcLoc,
38223323 lhs: Value,
38233324 rhs: Value,
38243325) !Value {
......@@ -3850,9 +3351,8 @@ pub fn floatSub(
38503351}
38513352
38523353pub fn simplePtrType(
3853 self: *Module,
3854 scope: *Scope,
3855 src: usize,
3354 mod: *Module,
3355 arena: *Allocator,
38563356 elem_ty: Type,
38573357 mutable: bool,
38583358 size: std.builtin.TypeInfo.Pointer.Size,
......@@ -3863,7 +3363,7 @@ pub fn simplePtrType(
38633363 // TODO stage1 type inference bug
38643364 const T = Type.Tag;
38653365
3866 const type_payload = try scope.arena().create(Type.Payload.ElemType);
3366 const type_payload = try arena.create(Type.Payload.ElemType);
38673367 type_payload.* = .{
38683368 .base = .{
38693369 .tag = switch (size) {
......@@ -3879,9 +3379,8 @@ pub fn simplePtrType(
38793379}
38803380
38813381pub fn ptrType(
3882 self: *Module,
3883 scope: *Scope,
3884 src: usize,
3382 mod: *Module,
3383 arena: *Allocator,
38853384 elem_ty: Type,
38863385 sentinel: ?Value,
38873386 @"align": u32,
......@@ -3895,7 +3394,7 @@ pub fn ptrType(
38953394 assert(host_size == 0 or bit_offset < host_size * 8);
38963395
38973396 // TODO check if type can be represented by simplePtrType
3898 return Type.Tag.pointer.create(scope.arena(), .{
3397 return Type.Tag.pointer.create(arena, .{
38993398 .pointee_type = elem_ty,
39003399 .sentinel = sentinel,
39013400 .@"align" = @"align",
......@@ -3908,23 +3407,23 @@ pub fn ptrType(
39083407 });
39093408}
39103409
3911pub fn optionalType(self: *Module, scope: *Scope, child_type: Type) Allocator.Error!Type {
3410pub fn optionalType(mod: *Module, arena: *Allocator, child_type: Type) Allocator.Error!Type {
39123411 switch (child_type.tag()) {
39133412 .single_const_pointer => return Type.Tag.optional_single_const_pointer.create(
3914 scope.arena(),
3413 arena,
39153414 child_type.elemType(),
39163415 ),
39173416 .single_mut_pointer => return Type.Tag.optional_single_mut_pointer.create(
3918 scope.arena(),
3417 arena,
39193418 child_type.elemType(),
39203419 ),
3921 else => return Type.Tag.optional.create(scope.arena(), child_type),
3420 else => return Type.Tag.optional.create(arena, child_type),
39223421 }
39233422}
39243423
39253424pub fn arrayType(
3926 self: *Module,
3927 scope: *Scope,
3425 mod: *Module,
3426 arena: *Allocator,
39283427 len: u64,
39293428 sentinel: ?Value,
39303429 elem_type: Type,
......@@ -3932,30 +3431,30 @@ pub fn arrayType(
39323431 if (elem_type.eql(Type.initTag(.u8))) {
39333432 if (sentinel) |some| {
39343433 if (some.eql(Value.initTag(.zero))) {
3935 return Type.Tag.array_u8_sentinel_0.create(scope.arena(), len);
3434 return Type.Tag.array_u8_sentinel_0.create(arena, len);
39363435 }
39373436 } else {
3938 return Type.Tag.array_u8.create(scope.arena(), len);
3437 return Type.Tag.array_u8.create(arena, len);
39393438 }
39403439 }
39413440
39423441 if (sentinel) |some| {
3943 return Type.Tag.array_sentinel.create(scope.arena(), .{
3442 return Type.Tag.array_sentinel.create(arena, .{
39443443 .len = len,
39453444 .sentinel = some,
39463445 .elem_type = elem_type,
39473446 });
39483447 }
39493448
3950 return Type.Tag.array.create(scope.arena(), .{
3449 return Type.Tag.array.create(arena, .{
39513450 .len = len,
39523451 .elem_type = elem_type,
39533452 });
39543453}
39553454
39563455pub fn errorUnionType(
3957 self: *Module,
3958 scope: *Scope,
3456 mod: *Module,
3457 arena: *Allocator,
39593458 error_set: Type,
39603459 payload: Type,
39613460) Allocator.Error!Type {
......@@ -3964,19 +3463,19 @@ pub fn errorUnionType(
39643463 return Type.initTag(.anyerror_void_error_union);
39653464 }
39663465
3967 return Type.Tag.error_union.create(scope.arena(), .{
3466 return Type.Tag.error_union.create(arena, .{
39683467 .error_set = error_set,
39693468 .payload = payload,
39703469 });
39713470}
39723471
3973pub fn anyframeType(self: *Module, scope: *Scope, return_type: Type) Allocator.Error!Type {
3974 return Type.Tag.anyframe_T.create(scope.arena(), return_type);
3472pub fn anyframeType(mod: *Module, arena: *Allocator, return_type: Type) Allocator.Error!Type {
3473 return Type.Tag.anyframe_T.create(arena, return_type);
39753474}
39763475
3977pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
3476pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
39783477 const zir_module = scope.namespace();
3979 const source = zir_module.getSource(self) catch @panic("dumpInst failed to get source");
3478 const source = zir_module.getSource(mod) catch @panic("dumpInst failed to get source");
39803479 const loc = std.zig.findLineColumn(source, inst.src);
39813480 if (inst.tag == .constant) {
39823481 std.debug.print("constant ty={} val={} src={s}:{d}:{d}\n", .{
......@@ -4006,267 +3505,113 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
40063505 }
40073506}
40083507
4009pub const PanicId = enum {
4010 unreach,
4011 unwrap_null,
4012 unwrap_errunion,
4013};
4014
4015pub fn addSafetyCheck(mod: *Module, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {
4016 const block_inst = try parent_block.arena.create(Inst.Block);
4017 block_inst.* = .{
4018 .base = .{
4019 .tag = Inst.Block.base_tag,
4020 .ty = Type.initTag(.void),
4021 .src = ok.src,
4022 },
4023 .body = .{
4024 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the condbr.
4025 },
4026 };
4027
4028 const ok_body: ir.Body = .{
4029 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the br_void.
4030 };
4031 const br_void = try parent_block.arena.create(Inst.BrVoid);
4032 br_void.* = .{
4033 .base = .{
4034 .tag = .br_void,
4035 .ty = Type.initTag(.noreturn),
4036 .src = ok.src,
4037 },
4038 .block = block_inst,
4039 };
4040 ok_body.instructions[0] = &br_void.base;
4041
4042 var fail_block: Scope.Block = .{
4043 .parent = parent_block,
4044 .inst_table = parent_block.inst_table,
4045 .func = parent_block.func,
4046 .owner_decl = parent_block.owner_decl,
4047 .src_decl = parent_block.src_decl,
4048 .instructions = .{},
4049 .arena = parent_block.arena,
4050 .inlining = parent_block.inlining,
4051 .is_comptime = parent_block.is_comptime,
4052 .branch_quota = parent_block.branch_quota,
4053 };
4054
4055 defer fail_block.instructions.deinit(mod.gpa);
4056
4057 _ = try mod.safetyPanic(&fail_block, ok.src, panic_id);
4058
4059 const fail_body: ir.Body = .{ .instructions = try parent_block.arena.dupe(*Inst, fail_block.instructions.items) };
4060
4061 const condbr = try parent_block.arena.create(Inst.CondBr);
4062 condbr.* = .{
4063 .base = .{
4064 .tag = .condbr,
4065 .ty = Type.initTag(.noreturn),
4066 .src = ok.src,
4067 },
4068 .condition = ok,
4069 .then_body = ok_body,
4070 .else_body = fail_body,
4071 };
4072 block_inst.body.instructions[0] = &condbr.base;
4073
4074 try parent_block.instructions.append(mod.gpa, &block_inst.base);
4075}
4076
4077pub fn safetyPanic(mod: *Module, block: *Scope.Block, src: usize, panic_id: PanicId) !*Inst {
4078 // TODO Once we have a panic function to call, call it here instead of breakpoint.
4079 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);
4080 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);
4081}
4082
4083pub fn getTarget(self: Module) Target {
4084 return self.comp.bin_file.options.target;
3508pub fn getTarget(mod: Module) Target {
3509 return mod.comp.bin_file.options.target;
40853510}
40863511
4087pub fn optimizeMode(self: Module) std.builtin.Mode {
4088 return self.comp.bin_file.options.optimize_mode;
3512pub fn optimizeMode(mod: Module) std.builtin.Mode {
3513 return mod.comp.bin_file.options.optimize_mode;
40893514}
40903515
4091pub fn validateVarType(mod: *Module, scope: *Scope, src: usize, ty: Type) !void {
4092 if (!ty.isValidVarType(false)) {
4093 return mod.fail(scope, src, "variable of type '{}' must be const or comptime", .{ty});
4094 }
4095}
4096
4097/// Identifier token -> String (allocated in scope.arena())
3516/// Given an identifier token, obtain the string for it.
3517/// If the token uses @"" syntax, parses as a string, reports errors if applicable,
3518/// and allocates the result within `scope.arena()`.
3519/// Otherwise, returns a reference to the source code bytes directly.
3520/// See also `appendIdentStr` and `parseStrLit`.
40983521pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
40993522 const tree = scope.tree();
41003523 const token_tags = tree.tokens.items(.tag);
41013524 const token_starts = tree.tokens.items(.start);
41023525 assert(token_tags[token] == .identifier);
4103
41043526 const ident_name = tree.tokenSlice(token);
4105 if (mem.startsWith(u8, ident_name, "@")) {
4106 const raw_string = ident_name[1..];
4107 var bad_index: usize = undefined;
4108 return std.zig.parseStringLiteral(scope.arena(), raw_string, &bad_index) catch |err| switch (err) {
4109 error.InvalidCharacter => {
4110 const bad_byte = raw_string[bad_index];
4111 const src = token_starts[token];
4112 return mod.fail(scope, src + 1 + bad_index, "invalid string literal character: '{c}'\n", .{bad_byte});
4113 },
4114 else => |e| return e,
4115 };
3527 if (!mem.startsWith(u8, ident_name, "@")) {
3528 return ident_name;
41163529 }
4117 return ident_name;
3530 var buf = std.ArrayList(u8).init(mod.gpa);
3531 defer buf.deinit();
3532 try parseStrLit(mod, scope, buf, ident_name, 1);
3533 return buf.toOwnedSlice();
41183534}
41193535
4120pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void {
4121 const shared = block.inlining.?.shared;
4122 shared.branch_count += 1;
4123 if (shared.branch_count > block.branch_quota.*) {
4124 // TODO show the "called from here" stack
4125 return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{
4126 block.branch_quota.*,
4127 });
3536/// Given an identifier token, obtain the string for it (possibly parsing as a string
3537/// literal if it is @"" syntax), and append the string to `buf`.
3538/// See also `identifierTokenString` and `parseStrLit`.
3539pub fn appendIdentStr(
3540 mod: *Module,
3541 scope: *Scope,
3542 token: ast.TokenIndex,
3543 buf: *ArrayList(u8),
3544) InnerError!void {
3545 const tree = scope.tree();
3546 const token_tags = tree.tokens.items(.tag);
3547 const token_starts = tree.tokens.items(.start);
3548 assert(token_tags[token] == .identifier);
3549 const ident_name = tree.tokenSlice(token);
3550 if (!mem.startsWith(u8, ident_name, "@")) {
3551 return buf.appendSlice(ident_name);
3552 } else {
3553 return parseStrLit(scope, buf, ident_name, 1);
41283554 }
41293555}
41303556
4131pub fn namedFieldPtr(
3557/// Appends the result to `buf`.
3558pub fn parseStrLit(
41323559 mod: *Module,
41333560 scope: *Scope,
4134 src: usize,
4135 object_ptr: *Inst,
4136 field_name: []const u8,
4137 field_name_src: usize,
4138) InnerError!*Inst {
4139 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
4140 .Pointer => object_ptr.ty.elemType(),
4141 else => return mod.fail(scope, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
4142 };
4143 switch (elem_ty.zigTypeTag()) {
4144 .Array => {
4145 if (mem.eql(u8, field_name, "len")) {
4146 return mod.constInst(scope, src, .{
4147 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
4148 .val = try Value.Tag.ref_val.create(
4149 scope.arena(),
4150 try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()),
4151 ),
4152 });
4153 } else {
4154 return mod.fail(
4155 scope,
4156 field_name_src,
4157 "no member named '{s}' in '{}'",
4158 .{ field_name, elem_ty },
4159 );
4160 }
3561 buf: *ArrayList(u8),
3562 bytes: []const u8,
3563 offset: usize,
3564) InnerError!void {
3565 const raw_string = bytes[offset..];
3566 switch (try std.zig.string_literal.parseAppend(buf, raw_string)) {
3567 .success => return,
3568 .invalid_character => |bad_index| {
3569 return mod.fail(
3570 scope,
3571 token_starts[token] + offset + bad_index,
3572 "invalid string literal character: '{c}'",
3573 .{raw_string[bad_index]},
3574 );
41613575 },
4162 .Pointer => {
4163 const ptr_child = elem_ty.elemType();
4164 switch (ptr_child.zigTypeTag()) {
4165 .Array => {
4166 if (mem.eql(u8, field_name, "len")) {
4167 return mod.constInst(scope, src, .{
4168 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
4169 .val = try Value.Tag.ref_val.create(
4170 scope.arena(),
4171 try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()),
4172 ),
4173 });
4174 } else {
4175 return mod.fail(
4176 scope,
4177 field_name_src,
4178 "no member named '{s}' in '{}'",
4179 .{ field_name, elem_ty },
4180 );
4181 }
4182 },
4183 else => {},
4184 }
3576 .expected_hex_digits => |bad_index| {
3577 return mod.fail(
3578 scope,
3579 token_starts[token] + offset + bad_index,
3580 "expected hex digits after '\\x'",
3581 .{},
3582 );
41853583 },
4186 .Type => {
4187 _ = try mod.resolveConstValue(scope, object_ptr);
4188 const result = try mod.analyzeDeref(scope, src, object_ptr, object_ptr.src);
4189 const val = result.value().?;
4190 const child_type = try val.toType(scope.arena());
4191 switch (child_type.zigTypeTag()) {
4192 .ErrorSet => {
4193 var name: []const u8 = undefined;
4194 // TODO resolve inferred error sets
4195 if (val.castTag(.error_set)) |payload|
4196 name = (payload.data.fields.getEntry(field_name) orelse return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).key
4197 else
4198 name = (try mod.getErrorValue(field_name)).key;
4199
4200 const result_type = if (child_type.tag() == .anyerror)
4201 try Type.Tag.error_set_single.create(scope.arena(), name)
4202 else
4203 child_type;
4204
4205 return mod.constInst(scope, src, .{
4206 .ty = try mod.simplePtrType(scope, src, result_type, false, .One),
4207 .val = try Value.Tag.ref_val.create(
4208 scope.arena(),
4209 try Value.Tag.@"error".create(scope.arena(), .{
4210 .name = name,
4211 }),
4212 ),
4213 });
4214 },
4215 .Struct => {
4216 const container_scope = child_type.getContainerScope();
4217 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
4218 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
4219 return mod.analyzeDeclRef(scope, src, decl);
4220 }
4221
4222 if (container_scope.file_scope == mod.root_scope) {
4223 return mod.fail(scope, src, "root source file has no member called '{s}'", .{field_name});
4224 } else {
4225 return mod.fail(scope, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
4226 }
4227 },
4228 else => return mod.fail(scope, src, "type '{}' does not support field access", .{child_type}),
4229 }
3584 .invalid_hex_escape => |bad_index| {
3585 return mod.fail(
3586 scope,
3587 token_starts[token] + offset + bad_index,
3588 "invalid hex digit: '{c}'",
3589 .{raw_string[bad_index]},
3590 );
3591 },
3592 .invalid_unicode_escape => |bad_index| {
3593 return mod.fail(
3594 scope,
3595 token_starts[token] + offset + bad_index,
3596 "invalid unicode digit: '{c}'",
3597 .{raw_string[bad_index]},
3598 );
3599 },
3600 .missing_matching_brace => |bad_index| {
3601 return mod.fail(
3602 scope,
3603 token_starts[token] + offset + bad_index,
3604 "missing matching '}}' character",
3605 .{},
3606 );
3607 },
3608 .expected_unicode_digits => |bad_index| {
3609 return mod.fail(
3610 scope,
3611 token_starts[token] + offset + bad_index,
3612 "expected unicode digits after '\\u'",
3613 .{},
3614 );
42303615 },
4231 else => {},
4232 }
4233 return mod.fail(scope, src, "type '{}' does not support field access", .{elem_ty});
4234}
4235
4236pub fn elemPtr(
4237 mod: *Module,
4238 scope: *Scope,
4239 src: usize,
4240 array_ptr: *Inst,
4241 elem_index: *Inst,
4242) InnerError!*Inst {
4243 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
4244 .Pointer => array_ptr.ty.elemType(),
4245 else => return mod.fail(scope, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
4246 };
4247 if (!elem_ty.isIndexable()) {
4248 return mod.fail(scope, src, "array access of non-array type '{}'", .{elem_ty});
4249 }
4250
4251 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
4252 // we have to deref the ptr operand to get the actual array pointer
4253 const array_ptr_deref = try mod.analyzeDeref(scope, src, array_ptr, array_ptr.src);
4254 if (array_ptr_deref.value()) |array_ptr_val| {
4255 if (elem_index.value()) |index_val| {
4256 // Both array pointer and index are compile-time known.
4257 const index_u64 = index_val.toUnsignedInt();
4258 // @intCast here because it would have been impossible to construct a value that
4259 // required a larger index.
4260 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
4261 const pointee_type = elem_ty.elemType().elemType();
4262
4263 return mod.constInst(scope, src, .{
4264 .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type),
4265 .val = elem_ptr,
4266 });
4267 }
4268 }
42693616 }
4270
4271 return mod.fail(scope, src, "TODO implement more analyze elemptr", .{});
42723617}
src/astgen.zig+125-311
......@@ -25,21 +25,22 @@ pub const ResultLoc = union(enum) {
2525 /// of an assignment uses this kind of result location.
2626 ref,
2727 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.
28 ty: *zir.Inst,
28 ty: zir.Inst.Index,
2929 /// The expression must store its result into this typed pointer. The result instruction
3030 /// from the expression must be ignored.
31 ptr: *zir.Inst,
31 ptr: zir.Inst.Index,
3232 /// The expression must store its result into this allocation, which has an inferred type.
3333 /// The result instruction from the expression must be ignored.
34 inferred_ptr: *zir.Inst.Tag.alloc_inferred.Type(),
34 /// Always an instruction with tag `alloc_inferred`.
35 inferred_ptr: zir.Inst.Index,
3536 /// The expression must store its result into this pointer, which is a typed pointer that
3637 /// has been bitcasted to whatever the expression's type is.
3738 /// The result instruction from the expression must be ignored.
38 bitcasted_ptr: *zir.Inst.UnOp,
39 bitcasted_ptr: zir.Inst.Index,
3940 /// There is a pointer for the expression to store its result into, however, its type
4041 /// is inferred based on peer type resolution for a `zir.Inst.Block`.
4142 /// The result instruction from the expression must be ignored.
42 block_ptr: *Module.Scope.GenZIR,
43 block_ptr: *Module.Scope.GenZir,
4344
4445 pub const Strategy = struct {
4546 elide_store_to_block_ptr_instructions: bool,
......@@ -369,10 +370,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
369370
370371 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
371372 var params: [1]ast.Node.Index = undefined;
372 return callExpr(mod, scope, rl, tree.callOne(&params, node));
373 return callExpr(mod, scope, rl, node, tree.callOne(&params, node));
373374 },
374375 .call, .call_comma, .async_call, .async_call_comma => {
375 return callExpr(mod, scope, rl, tree.callFull(node));
376 return callExpr(mod, scope, rl, node, tree.callFull(node));
376377 },
377378
378379 .unreachable_literal => {
......@@ -487,9 +488,12 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
487488 },
488489 .enum_literal => {
489490 const ident_token = main_tokens[node];
490 const name = try mod.identifierTokenString(scope, ident_token);
491 const src = token_starts[ident_token];
492 const result = try addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});
491 const gen_zir = scope.getGenZir();
492 const string_bytes = &gen_zir.zir_exec.string_bytes;
493 const str_index = string_bytes.items.len;
494 try mod.appendIdentStr(scope, ident_token, string_bytes);
495 const str_len = string_bytes.items.len - str_index;
496 const result = try gen_zir.addStr(.enum_literal, str_index, str_len);
493497 return rvalue(mod, scope, rl, result);
494498 },
495499 .error_value => {
......@@ -679,7 +683,7 @@ pub fn comptimeExpr(
679683 const token_starts = tree.tokens.items(.start);
680684
681685 // Make a scope to collect generated instructions in the sub-expression.
682 var block_scope: Scope.GenZIR = .{
686 var block_scope: Scope.GenZir = .{
683687 .parent = parent_scope,
684688 .decl = parent_scope.ownerDecl().?,
685689 .arena = parent_scope.arena(),
......@@ -720,7 +724,7 @@ fn breakExpr(
720724 while (true) {
721725 switch (scope.tag) {
722726 .gen_zir => {
723 const gen_zir = scope.cast(Scope.GenZIR).?;
727 const gen_zir = scope.cast(Scope.GenZir).?;
724728
725729 const block_inst = blk: {
726730 if (break_label != 0) {
......@@ -755,7 +759,7 @@ fn breakExpr(
755759 try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?);
756760
757761 if (have_store_to_block) {
758 const inst_list = parent_scope.getGenZIR().instructions.items;
762 const inst_list = parent_scope.getGenZir().instructions.items;
759763 const last_inst = inst_list[inst_list.len - 2];
760764 const store_inst = last_inst.castTag(.store_to_block_ptr).?;
761765 assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?);
......@@ -797,7 +801,7 @@ fn continueExpr(
797801 while (true) {
798802 switch (scope.tag) {
799803 .gen_zir => {
800 const gen_zir = scope.cast(Scope.GenZIR).?;
804 const gen_zir = scope.cast(Scope.GenZir).?;
801805 const continue_block = gen_zir.continue_block orelse {
802806 scope = gen_zir.parent;
803807 continue;
......@@ -864,7 +868,7 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
864868 while (true) {
865869 switch (scope.tag) {
866870 .gen_zir => {
867 const gen_zir = scope.cast(Scope.GenZIR).?;
871 const gen_zir = scope.cast(Scope.GenZir).?;
868872 if (gen_zir.label) |prev_label| {
869873 if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) {
870874 const tree = parent_scope.tree();
......@@ -931,9 +935,9 @@ fn labeledBlockExpr(
931935
932936 try checkLabelRedefinition(mod, parent_scope, label_token);
933937
934 // Create the Block ZIR instruction so that we can put it into the GenZIR struct
938 // Create the Block ZIR instruction so that we can put it into the GenZir struct
935939 // so that break statements can reference it.
936 const gen_zir = parent_scope.getGenZIR();
940 const gen_zir = parent_scope.getGenZir();
937941 const block_inst = try gen_zir.arena.create(zir.Inst.Block);
938942 block_inst.* = .{
939943 .base = .{
......@@ -946,14 +950,14 @@ fn labeledBlockExpr(
946950 .kw_args = .{},
947951 };
948952
949 var block_scope: Scope.GenZIR = .{
953 var block_scope: Scope.GenZir = .{
950954 .parent = parent_scope,
951955 .decl = parent_scope.ownerDecl().?,
952956 .arena = gen_zir.arena,
953957 .force_comptime = parent_scope.isComptime(),
954958 .instructions = .{},
955959 // TODO @as here is working around a stage1 miscompilation bug :(
956 .label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
960 .label = @as(?Scope.GenZir.Label, Scope.GenZir.Label{
957961 .token = label_token,
958962 .block_inst = block_inst,
959963 }),
......@@ -1107,8 +1111,8 @@ fn varDecl(
11071111 }
11081112 s = local_ptr.parent;
11091113 },
1110 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,
1111 .gen_suspend => s = s.cast(Scope.GenZIR).?.parent,
1114 .gen_zir => s = s.cast(Scope.GenZir).?.parent,
1115 .gen_suspend => s = s.cast(Scope.GenZir).?.parent,
11121116 .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,
11131117 else => break,
11141118 };
......@@ -1137,7 +1141,7 @@ fn varDecl(
11371141 const sub_scope = try block_arena.create(Scope.LocalVal);
11381142 sub_scope.* = .{
11391143 .parent = scope,
1140 .gen_zir = scope.getGenZIR(),
1144 .gen_zir = scope.getGenZir(),
11411145 .name = ident_name,
11421146 .inst = init_inst,
11431147 };
......@@ -1146,7 +1150,7 @@ fn varDecl(
11461150
11471151 // Detect whether the initialization expression actually uses the
11481152 // result location pointer.
1149 var init_scope: Scope.GenZIR = .{
1153 var init_scope: Scope.GenZir = .{
11501154 .parent = scope,
11511155 .decl = scope.ownerDecl().?,
11521156 .arena = scope.arena(),
......@@ -1168,7 +1172,7 @@ fn varDecl(
11681172 }
11691173 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
11701174 const init_inst = try expr(mod, &init_scope.base, init_result_loc, var_decl.ast.init_node);
1171 const parent_zir = &scope.getGenZIR().instructions;
1175 const parent_zir = &scope.getGenZir().instructions;
11721176 if (init_scope.rvalue_rl_count == 1) {
11731177 // Result location pointer not used. We don't need an alloc for this
11741178 // const local, and type inference becomes trivial.
......@@ -1192,7 +1196,7 @@ fn varDecl(
11921196 const sub_scope = try block_arena.create(Scope.LocalVal);
11931197 sub_scope.* = .{
11941198 .parent = scope,
1195 .gen_zir = scope.getGenZIR(),
1199 .gen_zir = scope.getGenZir(),
11961200 .name = ident_name,
11971201 .inst = casted_init,
11981202 };
......@@ -1219,7 +1223,7 @@ fn varDecl(
12191223 const sub_scope = try block_arena.create(Scope.LocalPtr);
12201224 sub_scope.* = .{
12211225 .parent = scope,
1222 .gen_zir = scope.getGenZIR(),
1226 .gen_zir = scope.getGenZir(),
12231227 .name = ident_name,
12241228 .ptr = init_scope.rl_ptr.?,
12251229 };
......@@ -1246,7 +1250,7 @@ fn varDecl(
12461250 const sub_scope = try block_arena.create(Scope.LocalPtr);
12471251 sub_scope.* = .{
12481252 .parent = scope,
1249 .gen_zir = scope.getGenZIR(),
1253 .gen_zir = scope.getGenZir(),
12501254 .name = ident_name,
12511255 .ptr = var_data.alloc,
12521256 };
......@@ -1446,203 +1450,13 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.
14461450 return rvalue(mod, scope, rl, result);
14471451}
14481452
1449fn containerField(
1450 mod: *Module,
1451 scope: *Scope,
1452 field: ast.full.ContainerField,
1453) InnerError!*zir.Inst {
1454 const tree = scope.tree();
1455 const token_starts = tree.tokens.items(.start);
1456
1457 const src = token_starts[field.ast.name_token];
1458 const name = try mod.identifierTokenString(scope, field.ast.name_token);
1459
1460 if (field.comptime_token == null and field.ast.value_expr == 0 and field.ast.align_expr == 0) {
1461 if (field.ast.type_expr != 0) {
1462 const ty = try typeExpr(mod, scope, field.ast.type_expr);
1463 return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldTyped, .{
1464 .bytes = name,
1465 .ty = ty,
1466 }, .{});
1467 } else {
1468 return addZIRInst(mod, scope, src, zir.Inst.ContainerFieldNamed, .{
1469 .bytes = name,
1470 }, .{});
1471 }
1472 }
1473
1474 const ty = if (field.ast.type_expr != 0) try typeExpr(mod, scope, field.ast.type_expr) else null;
1475 // TODO result location should be alignment type
1476 const alignment = if (field.ast.align_expr != 0) try expr(mod, scope, .none, field.ast.align_expr) else null;
1477 // TODO result location should be the field type
1478 const init = if (field.ast.value_expr != 0) try expr(mod, scope, .none, field.ast.value_expr) else null;
1479
1480 return addZIRInst(mod, scope, src, zir.Inst.ContainerField, .{
1481 .bytes = name,
1482 }, .{
1483 .ty = ty,
1484 .init = init,
1485 .alignment = alignment,
1486 .is_comptime = field.comptime_token != null,
1487 });
1488}
1489
14901453fn containerDecl(
14911454 mod: *Module,
14921455 scope: *Scope,
14931456 rl: ResultLoc,
14941457 container_decl: ast.full.ContainerDecl,
14951458) InnerError!*zir.Inst {
1496 const tree = scope.tree();
1497 const token_starts = tree.tokens.items(.start);
1498 const node_tags = tree.nodes.items(.tag);
1499 const token_tags = tree.tokens.items(.tag);
1500
1501 const src = token_starts[container_decl.ast.main_token];
1502
1503 var gen_scope: Scope.GenZIR = .{
1504 .parent = scope,
1505 .decl = scope.ownerDecl().?,
1506 .arena = scope.arena(),
1507 .force_comptime = scope.isComptime(),
1508 .instructions = .{},
1509 };
1510 defer gen_scope.instructions.deinit(mod.gpa);
1511
1512 var fields = std.ArrayList(*zir.Inst).init(mod.gpa);
1513 defer fields.deinit();
1514
1515 for (container_decl.ast.members) |member| {
1516 // TODO just handle these cases differently since they end up with different ZIR
1517 // instructions anyway. It will be simpler & have fewer branches.
1518 const field = switch (node_tags[member]) {
1519 .container_field_init => try containerField(mod, &gen_scope.base, tree.containerFieldInit(member)),
1520 .container_field_align => try containerField(mod, &gen_scope.base, tree.containerFieldAlign(member)),
1521 .container_field => try containerField(mod, &gen_scope.base, tree.containerField(member)),
1522 else => continue,
1523 };
1524 try fields.append(field);
1525 }
1526
1527 var decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1528 errdefer decl_arena.deinit();
1529 const arena = &decl_arena.allocator;
1530
1531 var layout: std.builtin.TypeInfo.ContainerLayout = .Auto;
1532 if (container_decl.layout_token) |some| switch (token_tags[some]) {
1533 .keyword_extern => layout = .Extern,
1534 .keyword_packed => layout = .Packed,
1535 else => unreachable,
1536 };
1537
1538 // TODO this implementation is incorrect. The types must be created in semantic
1539 // analysis, not astgen, because the same ZIR is re-used for multiple inline function calls,
1540 // comptime function calls, and generic function instantiations, and these
1541 // must result in different instances of container types.
1542 const container_type = switch (token_tags[container_decl.ast.main_token]) {
1543 .keyword_enum => blk: {
1544 const tag_type: ?*zir.Inst = if (container_decl.ast.arg != 0)
1545 try typeExpr(mod, &gen_scope.base, container_decl.ast.arg)
1546 else
1547 null;
1548 const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.EnumType, .{
1549 .fields = try arena.dupe(*zir.Inst, fields.items),
1550 }, .{
1551 .layout = layout,
1552 .tag_type = tag_type,
1553 });
1554 const enum_type = try arena.create(Type.Payload.Enum);
1555 enum_type.* = .{
1556 .analysis = .{
1557 .queued = .{
1558 .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) },
1559 .inst = inst,
1560 },
1561 },
1562 .scope = .{
1563 .file_scope = scope.getFileScope(),
1564 .ty = Type.initPayload(&enum_type.base),
1565 },
1566 };
1567 break :blk Type.initPayload(&enum_type.base);
1568 },
1569 .keyword_struct => blk: {
1570 assert(container_decl.ast.arg == 0);
1571 const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.StructType, .{
1572 .fields = try arena.dupe(*zir.Inst, fields.items),
1573 }, .{
1574 .layout = layout,
1575 });
1576 const struct_type = try arena.create(Type.Payload.Struct);
1577 struct_type.* = .{
1578 .analysis = .{
1579 .queued = .{
1580 .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) },
1581 .inst = inst,
1582 },
1583 },
1584 .scope = .{
1585 .file_scope = scope.getFileScope(),
1586 .ty = Type.initPayload(&struct_type.base),
1587 },
1588 };
1589 break :blk Type.initPayload(&struct_type.base);
1590 },
1591 .keyword_union => blk: {
1592 const init_inst: ?*zir.Inst = if (container_decl.ast.arg != 0)
1593 try typeExpr(mod, &gen_scope.base, container_decl.ast.arg)
1594 else
1595 null;
1596 const has_enum_token = container_decl.ast.enum_token != null;
1597 const inst = try addZIRInst(mod, &gen_scope.base, src, zir.Inst.UnionType, .{
1598 .fields = try arena.dupe(*zir.Inst, fields.items),
1599 }, .{
1600 .layout = layout,
1601 .has_enum_token = has_enum_token,
1602 .init_inst = init_inst,
1603 });
1604 const union_type = try arena.create(Type.Payload.Union);
1605 union_type.* = .{
1606 .analysis = .{
1607 .queued = .{
1608 .body = .{ .instructions = try arena.dupe(*zir.Inst, gen_scope.instructions.items) },
1609 .inst = inst,
1610 },
1611 },
1612 .scope = .{
1613 .file_scope = scope.getFileScope(),
1614 .ty = Type.initPayload(&union_type.base),
1615 },
1616 };
1617 break :blk Type.initPayload(&union_type.base);
1618 },
1619 .keyword_opaque => blk: {
1620 if (fields.items.len > 0) {
1621 return mod.fail(scope, fields.items[0].src, "opaque types cannot have fields", .{});
1622 }
1623 const opaque_type = try arena.create(Type.Payload.Opaque);
1624 opaque_type.* = .{
1625 .scope = .{
1626 .file_scope = scope.getFileScope(),
1627 .ty = Type.initPayload(&opaque_type.base),
1628 },
1629 };
1630 break :blk Type.initPayload(&opaque_type.base);
1631 },
1632 else => unreachable,
1633 };
1634 const val = try Value.Tag.ty.create(arena, container_type);
1635 const decl = try mod.createContainerDecl(scope, container_decl.ast.main_token, &decl_arena, .{
1636 .ty = Type.initTag(.type),
1637 .val = val,
1638 });
1639 if (rl == .ref) {
1640 return addZIRInst(mod, scope, src, zir.Inst.DeclRef, .{ .decl = decl }, .{});
1641 } else {
1642 return rvalue(mod, scope, rl, try addZIRInst(mod, scope, src, zir.Inst.DeclVal, .{
1643 .decl = decl,
1644 }, .{}));
1645 }
1459 return mod.failTok(scope, container_decl.ast.main_token, "TODO implement container decls", .{});
16461460}
16471461
16481462fn errorSetDecl(
......@@ -1709,7 +1523,7 @@ fn orelseCatchExpr(
17091523
17101524 const src = token_starts[op_token];
17111525
1712 var block_scope: Scope.GenZIR = .{
1526 var block_scope: Scope.GenZir = .{
17131527 .parent = scope,
17141528 .decl = scope.ownerDecl().?,
17151529 .arena = scope.arena(),
......@@ -1738,7 +1552,7 @@ fn orelseCatchExpr(
17381552 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
17391553 });
17401554
1741 var then_scope: Scope.GenZIR = .{
1555 var then_scope: Scope.GenZir = .{
17421556 .parent = &block_scope.base,
17431557 .decl = block_scope.decl,
17441558 .arena = block_scope.arena,
......@@ -1766,7 +1580,7 @@ fn orelseCatchExpr(
17661580 block_scope.break_count += 1;
17671581 const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, rhs);
17681582
1769 var else_scope: Scope.GenZIR = .{
1583 var else_scope: Scope.GenZir = .{
17701584 .parent = &block_scope.base,
17711585 .decl = block_scope.decl,
17721586 .arena = block_scope.arena,
......@@ -1804,9 +1618,9 @@ fn finishThenElseBlock(
18041618 mod: *Module,
18051619 parent_scope: *Scope,
18061620 rl: ResultLoc,
1807 block_scope: *Scope.GenZIR,
1808 then_scope: *Scope.GenZIR,
1809 else_scope: *Scope.GenZIR,
1621 block_scope: *Scope.GenZir,
1622 then_scope: *Scope.GenZir,
1623 else_scope: *Scope.GenZir,
18101624 then_body: *zir.Body,
18111625 else_body: *zir.Body,
18121626 then_src: usize,
......@@ -2023,7 +1837,7 @@ fn boolBinOp(
20231837 .val = Value.initTag(.bool_type),
20241838 });
20251839
2026 var block_scope: Scope.GenZIR = .{
1840 var block_scope: Scope.GenZir = .{
20271841 .parent = scope,
20281842 .decl = scope.ownerDecl().?,
20291843 .arena = scope.arena(),
......@@ -2043,7 +1857,7 @@ fn boolBinOp(
20431857 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
20441858 });
20451859
2046 var rhs_scope: Scope.GenZIR = .{
1860 var rhs_scope: Scope.GenZir = .{
20471861 .parent = scope,
20481862 .decl = block_scope.decl,
20491863 .arena = block_scope.arena,
......@@ -2058,7 +1872,7 @@ fn boolBinOp(
20581872 .operand = rhs,
20591873 }, .{});
20601874
2061 var const_scope: Scope.GenZIR = .{
1875 var const_scope: Scope.GenZir = .{
20621876 .parent = scope,
20631877 .decl = block_scope.decl,
20641878 .arena = block_scope.arena,
......@@ -2100,7 +1914,7 @@ fn ifExpr(
21001914 rl: ResultLoc,
21011915 if_full: ast.full.If,
21021916) InnerError!*zir.Inst {
2103 var block_scope: Scope.GenZIR = .{
1917 var block_scope: Scope.GenZir = .{
21041918 .parent = scope,
21051919 .decl = scope.ownerDecl().?,
21061920 .arena = scope.arena(),
......@@ -2142,7 +1956,7 @@ fn ifExpr(
21421956 });
21431957
21441958 const then_src = token_starts[tree.lastToken(if_full.ast.then_expr)];
2145 var then_scope: Scope.GenZIR = .{
1959 var then_scope: Scope.GenZir = .{
21461960 .parent = scope,
21471961 .decl = block_scope.decl,
21481962 .arena = block_scope.arena,
......@@ -2160,7 +1974,7 @@ fn ifExpr(
21601974 // instructions into place until we know whether to keep store_to_block_ptr
21611975 // instructions or not.
21621976
2163 var else_scope: Scope.GenZIR = .{
1977 var else_scope: Scope.GenZir = .{
21641978 .parent = scope,
21651979 .decl = block_scope.decl,
21661980 .arena = block_scope.arena,
......@@ -2201,7 +2015,7 @@ fn ifExpr(
22012015}
22022016
22032017/// Expects to find exactly 1 .store_to_block_ptr instruction.
2204fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZIR) !void {
2018fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZir) !void {
22052019 body.* = .{
22062020 .instructions = try scope.arena.alloc(*zir.Inst, scope.instructions.items.len - 1),
22072021 };
......@@ -2215,7 +2029,7 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZIR)
22152029 assert(dst_index == body.instructions.len);
22162030}
22172031
2218fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZIR) !void {
2032fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZir) !void {
22192033 body.* = .{
22202034 .instructions = try scope.arena.dupe(*zir.Inst, scope.instructions.items),
22212035 };
......@@ -2234,7 +2048,7 @@ fn whileExpr(
22342048 return mod.failTok(scope, inline_token, "TODO inline while", .{});
22352049 }
22362050
2237 var loop_scope: Scope.GenZIR = .{
2051 var loop_scope: Scope.GenZir = .{
22382052 .parent = scope,
22392053 .decl = scope.ownerDecl().?,
22402054 .arena = scope.arena(),
......@@ -2244,7 +2058,7 @@ fn whileExpr(
22442058 setBlockResultLoc(&loop_scope, rl);
22452059 defer loop_scope.instructions.deinit(mod.gpa);
22462060
2247 var continue_scope: Scope.GenZIR = .{
2061 var continue_scope: Scope.GenZir = .{
22482062 .parent = &loop_scope.base,
22492063 .decl = loop_scope.decl,
22502064 .arena = loop_scope.arena,
......@@ -2311,14 +2125,14 @@ fn whileExpr(
23112125 loop_scope.break_block = while_block;
23122126 loop_scope.continue_block = cond_block;
23132127 if (while_full.label_token) |label_token| {
2314 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
2128 loop_scope.label = @as(?Scope.GenZir.Label, Scope.GenZir.Label{
23152129 .token = label_token,
23162130 .block_inst = while_block,
23172131 });
23182132 }
23192133
23202134 const then_src = token_starts[tree.lastToken(while_full.ast.then_expr)];
2321 var then_scope: Scope.GenZIR = .{
2135 var then_scope: Scope.GenZir = .{
23222136 .parent = &continue_scope.base,
23232137 .decl = continue_scope.decl,
23242138 .arena = continue_scope.arena,
......@@ -2332,7 +2146,7 @@ fn whileExpr(
23322146 loop_scope.break_count += 1;
23332147 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);
23342148
2335 var else_scope: Scope.GenZIR = .{
2149 var else_scope: Scope.GenZir = .{
23362150 .parent = &continue_scope.base,
23372151 .decl = continue_scope.decl,
23382152 .arena = continue_scope.arena,
......@@ -2416,7 +2230,7 @@ fn forExpr(
24162230 const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];
24172231 const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);
24182232
2419 var loop_scope: Scope.GenZIR = .{
2233 var loop_scope: Scope.GenZir = .{
24202234 .parent = scope,
24212235 .decl = scope.ownerDecl().?,
24222236 .arena = scope.arena(),
......@@ -2426,7 +2240,7 @@ fn forExpr(
24262240 setBlockResultLoc(&loop_scope, rl);
24272241 defer loop_scope.instructions.deinit(mod.gpa);
24282242
2429 var cond_scope: Scope.GenZIR = .{
2243 var cond_scope: Scope.GenZir = .{
24302244 .parent = &loop_scope.base,
24312245 .decl = loop_scope.decl,
24322246 .arena = loop_scope.arena,
......@@ -2476,7 +2290,7 @@ fn forExpr(
24762290 loop_scope.break_block = for_block;
24772291 loop_scope.continue_block = cond_block;
24782292 if (for_full.label_token) |label_token| {
2479 loop_scope.label = @as(?Scope.GenZIR.Label, Scope.GenZIR.Label{
2293 loop_scope.label = @as(?Scope.GenZir.Label, Scope.GenZir.Label{
24802294 .token = label_token,
24812295 .block_inst = for_block,
24822296 });
......@@ -2484,7 +2298,7 @@ fn forExpr(
24842298
24852299 // while body
24862300 const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)];
2487 var then_scope: Scope.GenZIR = .{
2301 var then_scope: Scope.GenZir = .{
24882302 .parent = &cond_scope.base,
24892303 .decl = cond_scope.decl,
24902304 .arena = cond_scope.arena,
......@@ -2529,7 +2343,7 @@ fn forExpr(
25292343 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
25302344
25312345 // else branch
2532 var else_scope: Scope.GenZIR = .{
2346 var else_scope: Scope.GenZir = .{
25332347 .parent = &cond_scope.base,
25342348 .decl = cond_scope.decl,
25352349 .arena = cond_scope.arena,
......@@ -2609,7 +2423,7 @@ fn switchExpr(
26092423
26102424 const switch_src = token_starts[switch_token];
26112425
2612 var block_scope: Scope.GenZIR = .{
2426 var block_scope: Scope.GenZir = .{
26132427 .parent = scope,
26142428 .decl = scope.ownerDecl().?,
26152429 .arena = scope.arena(),
......@@ -2748,7 +2562,7 @@ fn switchExpr(
27482562 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
27492563 });
27502564
2751 var case_scope: Scope.GenZIR = .{
2565 var case_scope: Scope.GenZir = .{
27522566 .parent = scope,
27532567 .decl = block_scope.decl,
27542568 .arena = block_scope.arena,
......@@ -2757,7 +2571,7 @@ fn switchExpr(
27572571 };
27582572 defer case_scope.instructions.deinit(mod.gpa);
27592573
2760 var else_scope: Scope.GenZIR = .{
2574 var else_scope: Scope.GenZir = .{
27612575 .parent = scope,
27622576 .decl = case_scope.decl,
27632577 .arena = case_scope.arena,
......@@ -2966,12 +2780,8 @@ fn identifier(
29662780 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
29672781 }
29682782
2969 if (simple_types.get(ident_name)) |val_tag| {
2970 const result = try addZIRInstConst(mod, scope, src, TypedValue{
2971 .ty = Type.initTag(.type),
2972 .val = Value.initTag(val_tag),
2973 });
2974 return rvalue(mod, scope, rl, result);
2783 if (simple_types.get(ident_name)) |zir_const_tag| {
2784 return rvalue(mod, scope, rl, @enumToInt(zir_const_tag));
29752785 }
29762786
29772787 if (ident_name.len >= 2) integer: {
......@@ -3030,8 +2840,8 @@ fn identifier(
30302840 }
30312841 s = local_ptr.parent;
30322842 },
3033 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,
3034 .gen_suspend => s = s.cast(Scope.GenZIR).?.parent,
2843 .gen_zir => s = s.cast(Scope.GenZir).?.parent,
2844 .gen_suspend => s = s.cast(Scope.GenZir).?.parent,
30352845 .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,
30362846 else => break,
30372847 };
......@@ -3166,33 +2976,16 @@ fn integerLiteral(
31662976 rl: ResultLoc,
31672977 int_lit: ast.Node.Index,
31682978) InnerError!*zir.Inst {
3169 const arena = scope.arena();
31702979 const tree = scope.tree();
31712980 const main_tokens = tree.nodes.items(.main_token);
3172 const token_starts = tree.tokens.items(.start);
3173
31742981 const int_token = main_tokens[int_lit];
31752982 const prefixed_bytes = tree.tokenSlice(int_token);
3176 const base: u8 = if (mem.startsWith(u8, prefixed_bytes, "0x"))
3177 16
3178 else if (mem.startsWith(u8, prefixed_bytes, "0o"))
3179 8
3180 else if (mem.startsWith(u8, prefixed_bytes, "0b"))
3181 2
3182 else
3183 @as(u8, 10);
3184
3185 const bytes = if (base == 10)
3186 prefixed_bytes
3187 else
3188 prefixed_bytes[2..];
3189
3190 if (std.fmt.parseInt(u64, bytes, base)) |small_int| {
3191 const src = token_starts[int_token];
3192 const result = try addZIRInstConst(mod, scope, src, .{
3193 .ty = Type.initTag(.comptime_int),
3194 .val = try Value.Tag.int_u64.create(arena, small_int),
3195 });
2983 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {
2984 const result: zir.Inst.Index = switch (small_int) {
2985 0 => @enumToInt(zir.Const.zero),
2986 1 => @enumToInt(zir.Const.one),
2987 else => try addZirInt(small_int),
2988 };
31962989 return rvalue(mod, scope, rl, result);
31972990 } else |err| {
31982991 return mod.failTok(scope, int_token, "TODO implement int literals that don't fit in a u64", .{});
......@@ -3316,7 +3109,7 @@ fn asRlPtr(
33163109 // Detect whether this expr() call goes into rvalue() to store the result into the
33173110 // result location. If it does, elide the coerce_result_ptr instruction
33183111 // as well as the store instruction, instead passing the result as an rvalue.
3319 var as_scope: Scope.GenZIR = .{
3112 var as_scope: Scope.GenZir = .{
33203113 .parent = scope,
33213114 .decl = scope.ownerDecl().?,
33223115 .arena = scope.arena(),
......@@ -3327,7 +3120,7 @@ fn asRlPtr(
33273120
33283121 as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr);
33293122 const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);
3330 const parent_zir = &scope.getGenZIR().instructions;
3123 const parent_zir = &scope.getGenZir().instructions;
33313124 if (as_scope.rvalue_rl_count == 1) {
33323125 // Busted! This expression didn't actually need a pointer.
33333126 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
......@@ -3622,39 +3415,47 @@ fn callExpr(
36223415 mod: *Module,
36233416 scope: *Scope,
36243417 rl: ResultLoc,
3418 node: ast.Node.Index,
36253419 call: ast.full.Call,
36263420) InnerError!*zir.Inst {
36273421 if (call.async_token) |async_token| {
36283422 return mod.failTok(scope, async_token, "TODO implement async fn call", .{});
36293423 }
3630
3631 const tree = scope.tree();
3632 const main_tokens = tree.nodes.items(.main_token);
3633 const token_starts = tree.tokens.items(.start);
3634
36353424 const lhs = try expr(mod, scope, .none, call.ast.fn_expr);
36363425
3637 const args = try scope.getGenZIR().arena.alloc(*zir.Inst, call.ast.params.len);
3426 const args = try mod.gpa.alloc(zir.Inst.Index, call.ast.params.len);
3427 defer mod.gpa.free(args);
3428
3429 const gen_zir = scope.getGenZir();
36383430 for (call.ast.params) |param_node, i| {
3639 const param_src = token_starts[tree.firstToken(param_node)];
3640 const param_type = try addZIRInst(mod, scope, param_src, zir.Inst.ParamType, .{
3641 .func = lhs,
3642 .arg_index = i,
3643 }, .{});
3431 const param_type = try gen_zir.addParamType(.{
3432 .callee = lhs,
3433 .param_index = i,
3434 });
36443435 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);
36453436 }
36463437
3647 const src = token_starts[call.ast.lparen];
3648 var modifier: std.builtin.CallOptions.Modifier = .auto;
3649 if (call.async_token) |_| modifier = .async_kw;
3650
3651 const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{
3652 .func = lhs,
3653 .args = args,
3654 .modifier = modifier,
3655 }, .{});
3656 // TODO function call with result location
3657 return rvalue(mod, scope, rl, result);
3438 const modifier: std.builtin.CallOptions.Modifier = switch (call.async_token != null) {
3439 true => .async_kw,
3440 false => .auto,
3441 };
3442 const result: zir.Inst.Index = res: {
3443 const tag: zir.Inst.Tag = switch (modifier) {
3444 .auto => switch (args.len == 0) {
3445 true => break :res try gen_zir.addCallNone(lhs, node),
3446 false => .call,
3447 },
3448 .async_kw => .call_async_kw,
3449 .never_tail => unreachable,
3450 .never_inline => unreachable,
3451 .no_async => .call_no_async,
3452 .always_tail => unreachable,
3453 .always_inline => unreachable,
3454 .compile_time => .call_compile_time,
3455 };
3456 break :res try gen_zir.addCall(tag, lhs, args, node);
3457 };
3458 return rvalue(mod, scope, rl, result); // TODO function call with result location
36583459}
36593460
36603461fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {
......@@ -3748,11 +3549,17 @@ fn resumeExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir
37483549 return addZIRUnOp(mod, scope, src, .@"resume", operand);
37493550}
37503551
3751pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
3552pub const simple_types = std.ComptimeStringMap(zir.Const, .{
37523553 .{ "u8", .u8_type },
37533554 .{ "i8", .i8_type },
3754 .{ "isize", .isize_type },
3555 .{ "u16", .u16_type },
3556 .{ "i16", .i16_type },
3557 .{ "u32", .u32_type },
3558 .{ "i32", .i32_type },
3559 .{ "u64", .u64_type },
3560 .{ "i64", .i64_type },
37553561 .{ "usize", .usize_type },
3562 .{ "isize", .isize_type },
37563563 .{ "c_short", .c_short_type },
37573564 .{ "c_ushort", .c_ushort_type },
37583565 .{ "c_int", .c_int_type },
......@@ -3774,6 +3581,13 @@ pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
37743581 .{ "comptime_int", .comptime_int_type },
37753582 .{ "comptime_float", .comptime_float_type },
37763583 .{ "noreturn", .noreturn_type },
3584 .{ "null", .null_type },
3585 .{ "undefined", .undefined_type },
3586 .{ "anyframe", .anyframe_type },
3587 .{ "undefined", .undef },
3588 .{ "null", .null_value },
3589 .{ "true", .bool_true },
3590 .{ "false", .bool_false },
37773591});
37783592
37793593fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {
......@@ -4045,7 +3859,7 @@ fn rvalueVoid(
40453859 return rvalue(mod, scope, rl, void_inst);
40463860}
40473861
4048fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy {
3862fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZir) ResultLoc.Strategy {
40493863 var elide_store_to_block_ptr_instructions = false;
40503864 switch (rl) {
40513865 // In this branch there will not be any store_to_block_ptr instructions.
......@@ -4099,7 +3913,7 @@ fn makeOptionalTypeResultLoc(mod: *Module, scope: *Scope, src: usize, rl: Result
40993913 }
41003914}
41013915
4102fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void {
3916fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {
41033917 // Depending on whether the result location is a pointer or value, different
41043918 // ZIR needs to be generated. In the former case we rely on storing to the
41053919 // pointer to communicate the result, and use breakvoid; in the latter case
......@@ -4137,7 +3951,7 @@ pub fn addZirInstTag(
41373951 comptime tag: zir.Inst.Tag,
41383952 positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,
41393953) !*zir.Inst {
4140 const gen_zir = scope.getGenZIR();
3954 const gen_zir = scope.getGenZir();
41413955 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
41423956 const inst = try gen_zir.arena.create(tag.Type());
41433957 inst.* = .{
......@@ -4160,7 +3974,7 @@ pub fn addZirInstT(
41603974 tag: zir.Inst.Tag,
41613975 positionals: std.meta.fieldInfo(T, .positionals).field_type,
41623976) !*T {
4163 const gen_zir = scope.getGenZIR();
3977 const gen_zir = scope.getGenZir();
41643978 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
41653979 const inst = try gen_zir.arena.create(T);
41663980 inst.* = .{
......@@ -4183,7 +3997,7 @@ pub fn addZIRInstSpecial(
41833997 positionals: std.meta.fieldInfo(T, .positionals).field_type,
41843998 kw_args: std.meta.fieldInfo(T, .kw_args).field_type,
41853999) !*T {
4186 const gen_zir = scope.getGenZIR();
4000 const gen_zir = scope.getGenZir();
41874001 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
41884002 const inst = try gen_zir.arena.create(T);
41894003 inst.* = .{
......@@ -4199,7 +4013,7 @@ pub fn addZIRInstSpecial(
41994013}
42004014
42014015pub fn addZIRNoOpT(mod: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst.NoOp {
4202 const gen_zir = scope.getGenZIR();
4016 const gen_zir = scope.getGenZir();
42034017 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
42044018 const inst = try gen_zir.arena.create(zir.Inst.NoOp);
42054019 inst.* = .{
......@@ -4226,7 +4040,7 @@ pub fn addZIRUnOp(
42264040 tag: zir.Inst.Tag,
42274041 operand: *zir.Inst,
42284042) !*zir.Inst {
4229 const gen_zir = scope.getGenZIR();
4043 const gen_zir = scope.getGenZir();
42304044 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
42314045 const inst = try gen_zir.arena.create(zir.Inst.UnOp);
42324046 inst.* = .{
......@@ -4251,7 +4065,7 @@ pub fn addZIRBinOp(
42514065 lhs: *zir.Inst,
42524066 rhs: *zir.Inst,
42534067) !*zir.Inst {
4254 const gen_zir = scope.getGenZIR();
4068 const gen_zir = scope.getGenZir();
42554069 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
42564070 const inst = try gen_zir.arena.create(zir.Inst.BinOp);
42574071 inst.* = .{
......@@ -4276,7 +4090,7 @@ pub fn addZIRInstBlock(
42764090 tag: zir.Inst.Tag,
42774091 body: zir.Body,
42784092) !*zir.Inst.Block {
4279 const gen_zir = scope.getGenZIR();
4093 const gen_zir = scope.getGenZir();
42804094 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
42814095 const inst = try gen_zir.arena.create(zir.Inst.Block);
42824096 inst.* = .{
src/ir.zig+444-1
......@@ -360,7 +360,8 @@ pub const Inst = struct {
360360 base: Inst,
361361 asm_source: []const u8,
362362 is_volatile: bool,
363 output: ?[]const u8,
363 output: ?*Inst,
364 output_name: ?[]const u8,
364365 inputs: []const []const u8,
365366 clobbers: []const []const u8,
366367 args: []const *Inst,
......@@ -589,3 +590,445 @@ pub const Inst = struct {
589590pub const Body = struct {
590591 instructions: []*Inst,
591592};
593
594/// For debugging purposes, prints a function representation to stderr.
595pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
596 const allocator = old_module.gpa;
597 var ctx: DumpTzir = .{
598 .allocator = allocator,
599 .arena = std.heap.ArenaAllocator.init(allocator),
600 .old_module = &old_module,
601 .module_fn = module_fn,
602 .indent = 2,
603 .inst_table = DumpTzir.InstTable.init(allocator),
604 .partial_inst_table = DumpTzir.InstTable.init(allocator),
605 .const_table = DumpTzir.InstTable.init(allocator),
606 };
607 defer ctx.inst_table.deinit();
608 defer ctx.partial_inst_table.deinit();
609 defer ctx.const_table.deinit();
610 defer ctx.arena.deinit();
611
612 switch (module_fn.state) {
613 .queued => std.debug.print("(queued)", .{}),
614 .inline_only => std.debug.print("(inline_only)", .{}),
615 .in_progress => std.debug.print("(in_progress)", .{}),
616 .sema_failure => std.debug.print("(sema_failure)", .{}),
617 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
618 .success => {
619 const writer = std.io.getStdErr().writer();
620 ctx.dump(module_fn.body, writer) catch @panic("failed to dump TZIR");
621 },
622 }
623}
624
625const DumpTzir = struct {
626 allocator: *Allocator,
627 arena: std.heap.ArenaAllocator,
628 old_module: *const IrModule,
629 module_fn: *IrModule.Fn,
630 indent: usize,
631 inst_table: InstTable,
632 partial_inst_table: InstTable,
633 const_table: InstTable,
634 next_index: usize = 0,
635 next_partial_index: usize = 0,
636 next_const_index: usize = 0,
637
638 const InstTable = std.AutoArrayHashMap(*ir.Inst, usize);
639
640 /// TODO: Improve this code to include a stack of ir.Body and store the instructions
641 /// in there. Now we are putting all the instructions in a function local table,
642 /// however instructions that are in a Body can be thown away when the Body ends.
643 fn dump(dtz: *DumpTzir, body: ir.Body, writer: std.fs.File.Writer) !void {
644 // First pass to pre-populate the table so that we can show even invalid references.
645 // Must iterate the same order we iterate the second time.
646 // We also look for constants and put them in the const_table.
647 try dtz.fetchInstsAndResolveConsts(body);
648
649 std.debug.print("Module.Function(name={s}):\n", .{dtz.module_fn.owner_decl.name});
650
651 for (dtz.const_table.items()) |entry| {
652 const constant = entry.key.castTag(.constant).?;
653 try writer.print(" @{d}: {} = {};\n", .{
654 entry.value, constant.base.ty, constant.val,
655 });
656 }
657
658 return dtz.dumpBody(body, writer);
659 }
660
661 fn fetchInstsAndResolveConsts(dtz: *DumpTzir, body: ir.Body) error{OutOfMemory}!void {
662 for (body.instructions) |inst| {
663 try dtz.inst_table.put(inst, dtz.next_index);
664 dtz.next_index += 1;
665 switch (inst.tag) {
666 .alloc,
667 .retvoid,
668 .unreach,
669 .breakpoint,
670 .dbg_stmt,
671 .arg,
672 => {},
673
674 .ref,
675 .ret,
676 .bitcast,
677 .not,
678 .is_non_null,
679 .is_non_null_ptr,
680 .is_null,
681 .is_null_ptr,
682 .is_err,
683 .is_err_ptr,
684 .ptrtoint,
685 .floatcast,
686 .intcast,
687 .load,
688 .optional_payload,
689 .optional_payload_ptr,
690 .wrap_optional,
691 .wrap_errunion_payload,
692 .wrap_errunion_err,
693 .unwrap_errunion_payload,
694 .unwrap_errunion_err,
695 .unwrap_errunion_payload_ptr,
696 .unwrap_errunion_err_ptr,
697 => {
698 const un_op = inst.cast(ir.Inst.UnOp).?;
699 try dtz.findConst(un_op.operand);
700 },
701
702 .add,
703 .sub,
704 .mul,
705 .cmp_lt,
706 .cmp_lte,
707 .cmp_eq,
708 .cmp_gte,
709 .cmp_gt,
710 .cmp_neq,
711 .store,
712 .bool_and,
713 .bool_or,
714 .bit_and,
715 .bit_or,
716 .xor,
717 => {
718 const bin_op = inst.cast(ir.Inst.BinOp).?;
719 try dtz.findConst(bin_op.lhs);
720 try dtz.findConst(bin_op.rhs);
721 },
722
723 .br => {
724 const br = inst.castTag(.br).?;
725 try dtz.findConst(&br.block.base);
726 try dtz.findConst(br.operand);
727 },
728
729 .br_block_flat => {
730 const br_block_flat = inst.castTag(.br_block_flat).?;
731 try dtz.findConst(&br_block_flat.block.base);
732 try dtz.fetchInstsAndResolveConsts(br_block_flat.body);
733 },
734
735 .br_void => {
736 const br_void = inst.castTag(.br_void).?;
737 try dtz.findConst(&br_void.block.base);
738 },
739
740 .block => {
741 const block = inst.castTag(.block).?;
742 try dtz.fetchInstsAndResolveConsts(block.body);
743 },
744
745 .condbr => {
746 const condbr = inst.castTag(.condbr).?;
747 try dtz.findConst(condbr.condition);
748 try dtz.fetchInstsAndResolveConsts(condbr.then_body);
749 try dtz.fetchInstsAndResolveConsts(condbr.else_body);
750 },
751
752 .loop => {
753 const loop = inst.castTag(.loop).?;
754 try dtz.fetchInstsAndResolveConsts(loop.body);
755 },
756 .call => {
757 const call = inst.castTag(.call).?;
758 try dtz.findConst(call.func);
759 for (call.args) |arg| {
760 try dtz.findConst(arg);
761 }
762 },
763
764 // TODO fill out this debug printing
765 .assembly,
766 .constant,
767 .varptr,
768 .switchbr,
769 => {},
770 }
771 }
772 }
773
774 fn dumpBody(dtz: *DumpTzir, body: ir.Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {
775 for (body.instructions) |inst| {
776 const my_index = dtz.next_partial_index;
777 try dtz.partial_inst_table.put(inst, my_index);
778 dtz.next_partial_index += 1;
779
780 try writer.writeByteNTimes(' ', dtz.indent);
781 try writer.print("%{d}: {} = {s}(", .{
782 my_index, inst.ty, @tagName(inst.tag),
783 });
784 switch (inst.tag) {
785 .alloc,
786 .retvoid,
787 .unreach,
788 .breakpoint,
789 .dbg_stmt,
790 => try writer.writeAll(")\n"),
791
792 .ref,
793 .ret,
794 .bitcast,
795 .not,
796 .is_non_null,
797 .is_null,
798 .is_non_null_ptr,
799 .is_null_ptr,
800 .is_err,
801 .is_err_ptr,
802 .ptrtoint,
803 .floatcast,
804 .intcast,
805 .load,
806 .optional_payload,
807 .optional_payload_ptr,
808 .wrap_optional,
809 .wrap_errunion_err,
810 .wrap_errunion_payload,
811 .unwrap_errunion_err,
812 .unwrap_errunion_payload,
813 .unwrap_errunion_payload_ptr,
814 .unwrap_errunion_err_ptr,
815 => {
816 const un_op = inst.cast(ir.Inst.UnOp).?;
817 const kinky = try dtz.writeInst(writer, un_op.operand);
818 if (kinky != null) {
819 try writer.writeAll(") // Instruction does not dominate all uses!\n");
820 } else {
821 try writer.writeAll(")\n");
822 }
823 },
824
825 .add,
826 .sub,
827 .mul,
828 .cmp_lt,
829 .cmp_lte,
830 .cmp_eq,
831 .cmp_gte,
832 .cmp_gt,
833 .cmp_neq,
834 .store,
835 .bool_and,
836 .bool_or,
837 .bit_and,
838 .bit_or,
839 .xor,
840 => {
841 const bin_op = inst.cast(ir.Inst.BinOp).?;
842
843 const lhs_kinky = try dtz.writeInst(writer, bin_op.lhs);
844 try writer.writeAll(", ");
845 const rhs_kinky = try dtz.writeInst(writer, bin_op.rhs);
846
847 if (lhs_kinky != null or rhs_kinky != null) {
848 try writer.writeAll(") // Instruction does not dominate all uses!");
849 if (lhs_kinky) |lhs| {
850 try writer.print(" %{d}", .{lhs});
851 }
852 if (rhs_kinky) |rhs| {
853 try writer.print(" %{d}", .{rhs});
854 }
855 try writer.writeAll("\n");
856 } else {
857 try writer.writeAll(")\n");
858 }
859 },
860
861 .arg => {
862 const arg = inst.castTag(.arg).?;
863 try writer.print("{s})\n", .{arg.name});
864 },
865
866 .br => {
867 const br = inst.castTag(.br).?;
868
869 const lhs_kinky = try dtz.writeInst(writer, &br.block.base);
870 try writer.writeAll(", ");
871 const rhs_kinky = try dtz.writeInst(writer, br.operand);
872
873 if (lhs_kinky != null or rhs_kinky != null) {
874 try writer.writeAll(") // Instruction does not dominate all uses!");
875 if (lhs_kinky) |lhs| {
876 try writer.print(" %{d}", .{lhs});
877 }
878 if (rhs_kinky) |rhs| {
879 try writer.print(" %{d}", .{rhs});
880 }
881 try writer.writeAll("\n");
882 } else {
883 try writer.writeAll(")\n");
884 }
885 },
886
887 .br_block_flat => {
888 const br_block_flat = inst.castTag(.br_block_flat).?;
889 const block_kinky = try dtz.writeInst(writer, &br_block_flat.block.base);
890 if (block_kinky != null) {
891 try writer.writeAll(", { // Instruction does not dominate all uses!\n");
892 } else {
893 try writer.writeAll(", {\n");
894 }
895
896 const old_indent = dtz.indent;
897 dtz.indent += 2;
898 try dtz.dumpBody(br_block_flat.body, writer);
899 dtz.indent = old_indent;
900
901 try writer.writeByteNTimes(' ', dtz.indent);
902 try writer.writeAll("})\n");
903 },
904
905 .br_void => {
906 const br_void = inst.castTag(.br_void).?;
907 const kinky = try dtz.writeInst(writer, &br_void.block.base);
908 if (kinky) |_| {
909 try writer.writeAll(") // Instruction does not dominate all uses!\n");
910 } else {
911 try writer.writeAll(")\n");
912 }
913 },
914
915 .block => {
916 const block = inst.castTag(.block).?;
917
918 try writer.writeAll("{\n");
919
920 const old_indent = dtz.indent;
921 dtz.indent += 2;
922 try dtz.dumpBody(block.body, writer);
923 dtz.indent = old_indent;
924
925 try writer.writeByteNTimes(' ', dtz.indent);
926 try writer.writeAll("})\n");
927 },
928
929 .condbr => {
930 const condbr = inst.castTag(.condbr).?;
931
932 const condition_kinky = try dtz.writeInst(writer, condbr.condition);
933 if (condition_kinky != null) {
934 try writer.writeAll(", { // Instruction does not dominate all uses!\n");
935 } else {
936 try writer.writeAll(", {\n");
937 }
938
939 const old_indent = dtz.indent;
940 dtz.indent += 2;
941 try dtz.dumpBody(condbr.then_body, writer);
942
943 try writer.writeByteNTimes(' ', old_indent);
944 try writer.writeAll("}, {\n");
945
946 try dtz.dumpBody(condbr.else_body, writer);
947 dtz.indent = old_indent;
948
949 try writer.writeByteNTimes(' ', old_indent);
950 try writer.writeAll("})\n");
951 },
952
953 .loop => {
954 const loop = inst.castTag(.loop).?;
955
956 try writer.writeAll("{\n");
957
958 const old_indent = dtz.indent;
959 dtz.indent += 2;
960 try dtz.dumpBody(loop.body, writer);
961 dtz.indent = old_indent;
962
963 try writer.writeByteNTimes(' ', dtz.indent);
964 try writer.writeAll("})\n");
965 },
966
967 .call => {
968 const call = inst.castTag(.call).?;
969
970 const args_kinky = try dtz.allocator.alloc(?usize, call.args.len);
971 defer dtz.allocator.free(args_kinky);
972 std.mem.set(?usize, args_kinky, null);
973 var any_kinky_args = false;
974
975 const func_kinky = try dtz.writeInst(writer, call.func);
976
977 for (call.args) |arg, i| {
978 try writer.writeAll(", ");
979
980 args_kinky[i] = try dtz.writeInst(writer, arg);
981 any_kinky_args = any_kinky_args or args_kinky[i] != null;
982 }
983
984 if (func_kinky != null or any_kinky_args) {
985 try writer.writeAll(") // Instruction does not dominate all uses!");
986 if (func_kinky) |func_index| {
987 try writer.print(" %{d}", .{func_index});
988 }
989 for (args_kinky) |arg_kinky| {
990 if (arg_kinky) |arg_index| {
991 try writer.print(" %{d}", .{arg_index});
992 }
993 }
994 try writer.writeAll("\n");
995 } else {
996 try writer.writeAll(")\n");
997 }
998 },
999
1000 // TODO fill out this debug printing
1001 .assembly,
1002 .constant,
1003 .varptr,
1004 .switchbr,
1005 => {
1006 try writer.writeAll("!TODO!)\n");
1007 },
1008 }
1009 }
1010 }
1011
1012 fn writeInst(dtz: *DumpTzir, writer: std.fs.File.Writer, inst: *ir.Inst) !?usize {
1013 if (dtz.partial_inst_table.get(inst)) |operand_index| {
1014 try writer.print("%{d}", .{operand_index});
1015 return null;
1016 } else if (dtz.const_table.get(inst)) |operand_index| {
1017 try writer.print("@{d}", .{operand_index});
1018 return null;
1019 } else if (dtz.inst_table.get(inst)) |operand_index| {
1020 try writer.print("%{d}", .{operand_index});
1021 return operand_index;
1022 } else {
1023 try writer.writeAll("!BADREF!");
1024 return null;
1025 }
1026 }
1027
1028 fn findConst(dtz: *DumpTzir, operand: *ir.Inst) !void {
1029 if (operand.tag == .constant) {
1030 try dtz.const_table.put(operand, dtz.next_const_index);
1031 dtz.next_const_index += 1;
1032 }
1033 }
1034};
src/type.zig+12-12
......@@ -863,7 +863,10 @@ pub const Type = extern union {
863863 }
864864
865865 pub fn isNoReturn(self: Type) bool {
866 return self.zigTypeTag() == .NoReturn;
866 const definitely_correct_result = self.zigTypeTag() == .NoReturn;
867 const fast_result = self.tag_if_small_enough == Tag.noreturn;
868 assert(fast_result == definitely_correct_result);
869 return fast_result;
867870 }
868871
869872 /// Asserts that hasCodeGenBits() is true.
......@@ -3464,18 +3467,20 @@ pub const Type = extern union {
34643467 .int_unsigned,
34653468 => Payload.Bits,
34663469
3470 .error_set,
3471 .@"enum",
3472 .@"struct",
3473 .@"union",
3474 => Payload.Decl,
3475
34673476 .array => Payload.Array,
34683477 .array_sentinel => Payload.ArraySentinel,
34693478 .pointer => Payload.Pointer,
34703479 .function => Payload.Function,
34713480 .error_union => Payload.ErrorUnion,
3472 .error_set => Payload.Decl,
34733481 .error_set_single => Payload.Name,
3474 .empty_struct => Payload.ContainerScope,
3475 .@"enum" => Payload.Enum,
3476 .@"struct" => Payload.Struct,
3477 .@"union" => Payload.Union,
34783482 .@"opaque" => Payload.Opaque,
3483 .empty_struct => Payload.ContainerScope,
34793484 };
34803485 }
34813486
......@@ -3598,13 +3603,8 @@ pub const Type = extern union {
35983603
35993604 pub const Opaque = struct {
36003605 base: Payload = .{ .tag = .@"opaque" },
3601
3602 scope: Module.Scope.Container,
3606 data: Module.Scope.Container,
36033607 };
3604
3605 pub const Enum = @import("type/Enum.zig");
3606 pub const Struct = @import("type/Struct.zig");
3607 pub const Union = @import("type/Union.zig");
36083608 };
36093609};
36103610
src/type/Enum.zig deleted-55
......@@ -1,55 +0,0 @@
1const std = @import("std");
2const zir = @import("../zir.zig");
3const Value = @import("../value.zig").Value;
4const Type = @import("../type.zig").Type;
5const Module = @import("../Module.zig");
6const Scope = Module.Scope;
7const Enum = @This();
8
9base: Type.Payload = .{ .tag = .@"enum" },
10
11analysis: union(enum) {
12 queued: Zir,
13 in_progress,
14 resolved: Size,
15 failed,
16},
17scope: Scope.Container,
18
19pub const Field = struct {
20 value: Value,
21};
22
23pub const Zir = struct {
24 body: zir.Body,
25 inst: *zir.Inst,
26};
27
28pub const Size = struct {
29 tag_type: Type,
30 fields: std.StringArrayHashMapUnmanaged(Field),
31};
32
33pub fn resolve(self: *Enum, mod: *Module, scope: *Scope) !void {
34 const zir = switch (self.analysis) {
35 .failed => return error.AnalysisFail,
36 .resolved => return,
37 .in_progress => {
38 return mod.fail(scope, src, "enum '{}' depends on itself", .{enum_name});
39 },
40 .queued => |zir| zir,
41 };
42 self.analysis = .in_progress;
43
44 // TODO
45}
46
47// TODO should this resolve the type or assert that it has already been resolved?
48pub fn abiAlignment(self: *Enum, target: std.Target) u32 {
49 switch (self.analysis) {
50 .queued => unreachable, // alignment has not been resolved
51 .in_progress => unreachable, // alignment has not been resolved
52 .failed => unreachable, // type resolution failed
53 .resolved => |r| return r.tag_type.abiAlignment(target),
54 }
55}
src/type/Struct.zig deleted-56
......@@ -1,56 +0,0 @@
1const std = @import("std");
2const zir = @import("../zir.zig");
3const Value = @import("../value.zig").Value;
4const Type = @import("../type.zig").Type;
5const Module = @import("../Module.zig");
6const Scope = Module.Scope;
7const Struct = @This();
8
9base: Type.Payload = .{ .tag = .@"struct" },
10
11analysis: union(enum) {
12 queued: Zir,
13 zero_bits_in_progress,
14 zero_bits: Zero,
15 in_progress,
16 // alignment: Align,
17 resolved: Size,
18 failed,
19},
20scope: Scope.Container,
21
22pub const Field = struct {
23 value: Value,
24};
25
26pub const Zir = struct {
27 body: zir.Body,
28 inst: *zir.Inst,
29};
30
31pub const Zero = struct {
32 is_zero_bits: bool,
33 fields: std.StringArrayHashMapUnmanaged(Field),
34};
35
36pub const Size = struct {
37 is_zero_bits: bool,
38 alignment: u32,
39 size: u32,
40 fields: std.StringArrayHashMapUnmanaged(Field),
41};
42
43pub fn resolveZeroBits(self: *Struct, mod: *Module, scope: *Scope) !void {
44 const zir = switch (self.analysis) {
45 .failed => return error.AnalysisFail,
46 .zero_bits_in_progress => {
47 return mod.fail(scope, src, "struct '{}' depends on itself", .{});
48 },
49 .queued => |zir| zir,
50 else => return,
51 };
52
53 self.analysis = .zero_bits_in_progress;
54
55 // TODO
56}
src/type/Union.zig deleted-56
......@@ -1,56 +0,0 @@
1const std = @import("std");
2const zir = @import("../zir.zig");
3const Value = @import("../value.zig").Value;
4const Type = @import("../type.zig").Type;
5const Module = @import("../Module.zig");
6const Scope = Module.Scope;
7const Union = @This();
8
9base: Type.Payload = .{ .tag = .@"struct" },
10
11analysis: union(enum) {
12 queued: Zir,
13 zero_bits_in_progress,
14 zero_bits: Zero,
15 in_progress,
16 // alignment: Align,
17 resolved: Size,
18 failed,
19},
20scope: Scope.Container,
21
22pub const Field = struct {
23 value: Value,
24};
25
26pub const Zir = struct {
27 body: zir.Body,
28 inst: *zir.Inst,
29};
30
31pub const Zero = struct {
32 is_zero_bits: bool,
33 fields: std.StringArrayHashMapUnmanaged(Field),
34};
35
36pub const Size = struct {
37 is_zero_bits: bool,
38 alignment: u32,
39 size: u32,
40 fields: std.StringArrayHashMapUnmanaged(Field),
41};
42
43pub fn resolveZeroBits(self: *Union, mod: *Module, scope: *Scope) !void {
44 const zir = switch (self.analysis) {
45 .failed => return error.AnalysisFail,
46 .zero_bits_in_progress => {
47 return mod.fail(scope, src, "union '{}' depends on itself", .{});
48 },
49 .queued => |zir| zir,
50 else => return,
51 };
52
53 self.analysis = .zero_bits_in_progress;
54
55 // TODO
56}
src/value.zig+5-4
......@@ -69,11 +69,12 @@ pub const Value = extern union {
6969 one,
7070 void_value,
7171 unreachable_value,
72 empty_struct_value,
73 empty_array,
7472 null_value,
7573 bool_true,
76 bool_false, // See last_no_payload_tag below.
74 bool_false,
75
76 empty_struct_value,
77 empty_array, // See last_no_payload_tag below.
7778 // After this, the tag requires a payload.
7879
7980 ty,
......@@ -107,7 +108,7 @@ pub const Value = extern union {
107108 /// to an inferred allocation. It does not support any of the normal value queries.
108109 inferred_alloc,
109110
110 pub const last_no_payload_tag = Tag.bool_false;
111 pub const last_no_payload_tag = Tag.empty_array;
111112 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
112113
113114 pub fn Type(comptime t: Tag) type {
src/zir.zig+713-1553
......@@ -10,17 +10,338 @@ 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("Module.zig");
13const Module = @import("Module.zig");
14const ast = std.zig.ast;
15
16/// The minimum amount of information needed to represent a list of ZIR instructions.
17/// Once this structure is completed, it can be used to generate TZIR, followed by
18/// machine code, without any memory access into the AST tree token list, node list,
19/// or source bytes. Exceptions include:
20/// * Compile errors, which may need to reach into these data structures to
21/// create a useful report.
22/// * In the future, possibly inline assembly, which needs to get parsed and
23/// handled by the codegen backend, and errors reported there. However for now,
24/// inline assembly is not an exception.
25pub const Code = struct {
26 instructions: std.MultiArrayList(Inst).Slice,
27 /// In order to store references to strings in fewer bytes, we copy all
28 /// string bytes into here. String bytes can be null. It is up to whomever
29 /// is referencing the data here whether they want to store both index and length,
30 /// thus allowing null bytes, or store only index, and use null-termination. The
31 /// `string_bytes` array is agnostic to either usage.
32 string_bytes: []u8,
33 /// The meaning of this data is determined by `Inst.Tag` value.
34 extra: []u32,
35 /// First ZIR instruction in this `Code`.
36 root_start: Inst.Index,
37 /// Number of ZIR instructions in the implicit root block of the `Code`.
38 root_len: u32,
39
40 /// Returns the requested data, as well as the new index which is at the start of the
41 /// trailers for the object.
42 pub fn extraData(code: Code, comptime T: type, index: usize) struct { data: T, end: usize } {
43 const fields = std.meta.fields(T);
44 var i: usize = index;
45 var result: T = undefined;
46 inline for (fields) |field| {
47 comptime assert(field.field_type == u32);
48 @field(result, field.name) = code.extra[i];
49 i += 1;
50 }
51 return .{
52 .data = result,
53 .end = i,
54 };
55 }
56
57 /// Given an index into `string_bytes` returns the null-terminated string found there.
58 pub fn nullTerminatedString(code: Code, index: usize) [:0]const u8 {
59 var end: usize = index;
60 while (code.string_bytes[end] != 0) {
61 end += 1;
62 }
63 return code.string_bytes[index..end :0];
64 }
65};
1466
15/// These are instructions that correspond to the ZIR text format. See `ir.Inst` for
16/// in-memory, analyzed instructions with types and values.
17/// We use a table to map these instruction to their respective semantically analyzed
18/// instructions because it is possible to have multiple analyses on the same ZIR
19/// happening at the same time.
67/// These correspond to the first N tags of Value.
68/// A ZIR instruction refers to another one by index. However the first N indexes
69/// correspond to this enum, and the next M indexes correspond to the parameters
70/// of the current function. After that, they refer to other instructions in the
71/// instructions array for the function.
72/// When adding to this, consider adding a corresponding entry o `simple_types`
73/// in astgen.
74pub const Const = enum {
75 /// The 0 value is reserved so that ZIR instruction indexes can use it to
76 /// mean "null".
77 unused,
78
79 u8_type,
80 i8_type,
81 u16_type,
82 i16_type,
83 u32_type,
84 i32_type,
85 u64_type,
86 i64_type,
87 usize_type,
88 isize_type,
89 c_short_type,
90 c_ushort_type,
91 c_int_type,
92 c_uint_type,
93 c_long_type,
94 c_ulong_type,
95 c_longlong_type,
96 c_ulonglong_type,
97 c_longdouble_type,
98 f16_type,
99 f32_type,
100 f64_type,
101 f128_type,
102 c_void_type,
103 bool_type,
104 void_type,
105 type_type,
106 anyerror_type,
107 comptime_int_type,
108 comptime_float_type,
109 noreturn_type,
110 null_type,
111 undefined_type,
112 fn_noreturn_no_args_type,
113 fn_void_no_args_type,
114 fn_naked_noreturn_no_args_type,
115 fn_ccc_void_no_args_type,
116 single_const_pointer_to_comptime_int_type,
117 const_slice_u8_type,
118 enum_literal_type,
119 anyframe_type,
120
121 /// `undefined` (untyped)
122 undef,
123 /// `0` (comptime_int)
124 zero,
125 /// `1` (comptime_int)
126 one,
127 /// `{}`
128 void_value,
129 /// `unreachable` (noreturn type)
130 unreachable_value,
131 /// `null` (untyped)
132 null_value,
133 /// `true`
134 bool_true,
135 /// `false`
136 bool_false,
137};
138
139pub const const_inst_list = enumArray(Const, .{
140 .u8_type = @as(TypedValue, .{
141 .ty = Type.initTag(.type),
142 .val = Value.initTag(.u8_type),
143 }),
144 .i8_type = @as(TypedValue, .{
145 .ty = Type.initTag(.type),
146 .val = Value.initTag(.i8_type),
147 }),
148 .u16_type = @as(TypedValue, .{
149 .ty = Type.initTag(.type),
150 .val = Value.initTag(.u16_type),
151 }),
152 .i16_type = @as(TypedValue, .{
153 .ty = Type.initTag(.type),
154 .val = Value.initTag(.i16_type),
155 }),
156 .u32_type = @as(TypedValue, .{
157 .ty = Type.initTag(.type),
158 .val = Value.initTag(.u32_type),
159 }),
160 .i32_type = @as(TypedValue, .{
161 .ty = Type.initTag(.type),
162 .val = Value.initTag(.i32_type),
163 }),
164 .u64_type = @as(TypedValue, .{
165 .ty = Type.initTag(.type),
166 .val = Value.initTag(.u64_type),
167 }),
168 .i64_type = @as(TypedValue, .{
169 .ty = Type.initTag(.type),
170 .val = Value.initTag(.i64_type),
171 }),
172 .usize_type = @as(TypedValue, .{
173 .ty = Type.initTag(.type),
174 .val = Value.initTag(.usize_type),
175 }),
176 .isize_type = @as(TypedValue, .{
177 .ty = Type.initTag(.type),
178 .val = Value.initTag(.isize_type),
179 }),
180 .c_short_type = @as(TypedValue, .{
181 .ty = Type.initTag(.type),
182 .val = Value.initTag(.c_short_type),
183 }),
184 .c_ushort_type = @as(TypedValue, .{
185 .ty = Type.initTag(.type),
186 .val = Value.initTag(.c_ushort_type),
187 }),
188 .c_int_type = @as(TypedValue, .{
189 .ty = Type.initTag(.type),
190 .val = Value.initTag(.c_int_type),
191 }),
192 .c_uint_type = @as(TypedValue, .{
193 .ty = Type.initTag(.type),
194 .val = Value.initTag(.c_uint_type),
195 }),
196 .c_long_type = @as(TypedValue, .{
197 .ty = Type.initTag(.type),
198 .val = Value.initTag(.c_long_type),
199 }),
200 .c_ulong_type = @as(TypedValue, .{
201 .ty = Type.initTag(.type),
202 .val = Value.initTag(.c_ulong_type),
203 }),
204 .c_longlong_type = @as(TypedValue, .{
205 .ty = Type.initTag(.type),
206 .val = Value.initTag(.c_longlong_type),
207 }),
208 .c_ulonglong_type = @as(TypedValue, .{
209 .ty = Type.initTag(.type),
210 .val = Value.initTag(.c_ulonglong_type),
211 }),
212 .c_longdouble_type = @as(TypedValue, .{
213 .ty = Type.initTag(.type),
214 .val = Value.initTag(.c_longdouble_type),
215 }),
216 .f16_type = @as(TypedValue, .{
217 .ty = Type.initTag(.type),
218 .val = Value.initTag(.f16_type),
219 }),
220 .f32_type = @as(TypedValue, .{
221 .ty = Type.initTag(.type),
222 .val = Value.initTag(.f32_type),
223 }),
224 .f64_type = @as(TypedValue, .{
225 .ty = Type.initTag(.type),
226 .val = Value.initTag(.f64_type),
227 }),
228 .f128_type = @as(TypedValue, .{
229 .ty = Type.initTag(.type),
230 .val = Value.initTag(.f128_type),
231 }),
232 .c_void_type = @as(TypedValue, .{
233 .ty = Type.initTag(.type),
234 .val = Value.initTag(.c_void_type),
235 }),
236 .bool_type = @as(TypedValue, .{
237 .ty = Type.initTag(.type),
238 .val = Value.initTag(.bool_type),
239 }),
240 .void_type = @as(TypedValue, .{
241 .ty = Type.initTag(.type),
242 .val = Value.initTag(.void_type),
243 }),
244 .type_type = @as(TypedValue, .{
245 .ty = Type.initTag(.type),
246 .val = Value.initTag(.type_type),
247 }),
248 .anyerror_type = @as(TypedValue, .{
249 .ty = Type.initTag(.type),
250 .val = Value.initTag(.anyerror_type),
251 }),
252 .comptime_int_type = @as(TypedValue, .{
253 .ty = Type.initTag(.type),
254 .val = Value.initTag(.comptime_int_type),
255 }),
256 .comptime_float_type = @as(TypedValue, .{
257 .ty = Type.initTag(.type),
258 .val = Value.initTag(.comptime_float_type),
259 }),
260 .noreturn_type = @as(TypedValue, .{
261 .ty = Type.initTag(.type),
262 .val = Value.initTag(.noreturn_type),
263 }),
264 .null_type = @as(TypedValue, .{
265 .ty = Type.initTag(.type),
266 .val = Value.initTag(.null_type),
267 }),
268 .undefined_type = @as(TypedValue, .{
269 .ty = Type.initTag(.type),
270 .val = Value.initTag(.undefined_type),
271 }),
272 .fn_noreturn_no_args_type = @as(TypedValue, .{
273 .ty = Type.initTag(.type),
274 .val = Value.initTag(.fn_noreturn_no_args_type),
275 }),
276 .fn_void_no_args_type = @as(TypedValue, .{
277 .ty = Type.initTag(.type),
278 .val = Value.initTag(.fn_void_no_args_type),
279 }),
280 .fn_naked_noreturn_no_args_type = @as(TypedValue, .{
281 .ty = Type.initTag(.type),
282 .val = Value.initTag(.fn_naked_noreturn_no_args_type),
283 }),
284 .fn_ccc_void_no_args_type = @as(TypedValue, .{
285 .ty = Type.initTag(.type),
286 .val = Value.initTag(.fn_ccc_void_no_args_type),
287 }),
288 .single_const_pointer_to_comptime_int_type = @as(TypedValue, .{
289 .ty = Type.initTag(.type),
290 .val = Value.initTag(.single_const_pointer_to_comptime_int_type),
291 }),
292 .const_slice_u8_type = @as(TypedValue, .{
293 .ty = Type.initTag(.type),
294 .val = Value.initTag(.const_slice_u8_type),
295 }),
296 .enum_literal_type = @as(TypedValue, .{
297 .ty = Type.initTag(.type),
298 .val = Value.initTag(.enum_literal_type),
299 }),
300 .anyframe_type = @as(TypedValue, .{
301 .ty = Type.initTag(.type),
302 .val = Value.initTag(.anyframe_type),
303 }),
304
305 .undef = @as(TypedValue, .{
306 .ty = Type.initTag(.@"undefined"),
307 .val = Value.initTag(.undef),
308 }),
309 .zero = @as(TypedValue, .{
310 .ty = Type.initTag(.comptime_int),
311 .val = Value.initTag(.zero),
312 }),
313 .one = @as(TypedValue, .{
314 .ty = Type.initTag(.comptime_int),
315 .val = Value.initTag(.one),
316 }),
317 .void_value = @as(TypedValue, .{
318 .ty = Type.initTag(.void),
319 .val = Value.initTag(.void_value),
320 }),
321 .unreachable_value = @as(TypedValue, .{
322 .ty = Type.initTag(.noreturn),
323 .val = Value.initTag(.unreachable_value),
324 }),
325 .null_value = @as(TypedValue, .{
326 .ty = Type.initTag(.@"null"),
327 .val = Value.initTag(.null_value),
328 }),
329 .bool_true = @as(TypedValue, .{
330 .ty = Type.initTag(.bool),
331 .val = Value.initTag(.bool_true),
332 }),
333 .bool_false = @as(TypedValue, .{
334 .ty = Type.initTag(.bool),
335 .val = Value.initTag(.bool_false),
336 }),
337});
338
339/// These are untyped instructions generated from an Abstract Syntax Tree.
340/// The data here is immutable because it is possible to have multiple
341/// analyses on the same ZIR happening at the same time.
20342pub const Inst = struct {
21343 tag: Tag,
22 /// Byte offset into the source.
23 src: usize,
344 data: Data,
24345
25346 /// These names are used directly as the instruction names in the text format.
26347 pub const Tag = enum {
......@@ -28,40 +349,45 @@ pub const Inst = struct {
28349 add,
29350 /// Twos complement wrapping integer addition.
30351 addwrap,
31 /// Allocates stack local memory. Its lifetime ends when the block ends that contains
32 /// this instruction. The operand is the type of the allocated object.
352 /// Allocates stack local memory.
353 /// Uses the `un_node` union field. The operand is the type of the allocated object.
354 /// The node source location points to a var decl node.
355 /// Indicates the beginning of a new statement in debug info.
33356 alloc,
34357 /// Same as `alloc` except mutable.
35358 alloc_mut,
36359 /// Same as `alloc` except the type is inferred.
360 /// lhs and rhs unused.
37361 alloc_inferred,
38362 /// Same as `alloc_inferred` except mutable.
363 /// lhs and rhs unused.
39364 alloc_inferred_mut,
40365 /// Create an `anyframe->T`.
366 /// Uses the `un_node` field. AST node is the `anyframe->T` syntax. Operand is the type.
41367 anyframe_type,
42368 /// Array concatenation. `a ++ b`
43369 array_cat,
44370 /// Array multiplication `a ** b`
45371 array_mul,
46 /// Create an array type
372 /// lhs is length, rhs is element type.
47373 array_type,
48 /// Create an array type with sentinel
374 /// lhs is length, ArrayTypeSentinel[rhs]
49375 array_type_sentinel,
50376 /// Given a pointer to an indexable object, returns the len property. This is
51 /// used by for loops. This instruction also emits a for-loop specific instruction
52 /// if the indexable object is not indexable.
377 /// used by for loops. This instruction also emits a for-loop specific compile
378 /// error if the indexable object is not indexable.
379 /// Uses the `un_node` field. The AST node is the for loop node.
53380 indexable_ptr_len,
54 /// Function parameter value. These must be first in a function's main block,
55 /// in respective order with the parameters.
56 /// TODO make this instruction implicit; after we transition to having ZIR
57 /// instructions be same sized and referenced by index, the first N indexes
58 /// will implicitly be references to the parameters of the function.
59 arg,
60381 /// Type coercion.
382 /// Uses the `bin` field.
61383 as,
62 /// Inline assembly.
384 /// Inline assembly. Non-volatile.
385 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
63386 @"asm",
64 /// Await an async function.
387 /// Inline assembly with the volatile attribute.
388 /// Uses the `pl_node` union field. Payload is `Asm`. AST node is the assembly node.
389 asm_volatile,
390 /// `await x` syntax. Uses the `un_node` union field.
65391 @"await",
66392 /// Bitwise AND. `&`
67393 bit_and,
......@@ -80,6 +406,7 @@ pub const Inst = struct {
80406 /// Bitwise OR. `|`
81407 bit_or,
82408 /// A labeled block of code, which can return a value.
409 /// Uses the `pl_node` union field.
83410 block,
84411 /// A block of code, which can return a value. There are no instructions that break out of
85412 /// this block; it is implied that the final instruction is the result.
......@@ -89,18 +416,36 @@ pub const Inst = struct {
89416 /// Same as `block_flat` but additionally makes the inner instructions execute at comptime.
90417 block_comptime_flat,
91418 /// Boolean AND. See also `bit_and`.
419 /// Uses the `bin` field.
92420 bool_and,
93421 /// Boolean NOT. See also `bit_not`.
422 /// Uses the `un_tok` field.
94423 bool_not,
95424 /// Boolean OR. See also `bit_or`.
425 /// Uses the `bin` field.
96426 bool_or,
97 /// Return a value from a `Block`.
427 /// Return a value from a block.
428 /// Uses the `bin` union field: `lhs` is `Ref` to the block, `rhs` is operand.
429 /// Uses the source information from previous instruction.
98430 @"break",
431 /// Same as `break` but has source information in the form of a token, and
432 /// the operand is assumed to be the void value.
433 /// Uses the `un_tok` union field.
434 break_void_tok,
435 /// lhs and rhs unused.
99436 breakpoint,
100 /// Same as `break` but without an operand; the operand is assumed to be the void value.
101 break_void,
102 /// Function call.
437 /// Function call with modifier `.auto`.
438 /// Uses `pl_node`. AST node is the function call. Payload is `Call`.
103439 call,
440 /// Same as `call` but with modifier `.async_kw`.
441 call_async_kw,
442 /// Same as `call` but with modifier `.no_async`.
443 call_no_async,
444 /// Same as `call` but with modifier `.compile_time`.
445 call_compile_time,
446 /// Function call with modifier `.auto`, empty parameter list.
447 /// Uses the `un_node` field. Operand is callee. AST node is the function call.
448 call_none,
104449 /// `<`
105450 cmp_lt,
106451 /// `<=`
......@@ -118,95 +463,117 @@ pub const Inst = struct {
118463 /// LHS is destination element type, RHS is result pointer.
119464 coerce_result_ptr,
120465 /// Emit an error message and fail compilation.
466 /// Uses the `un_node` field.
121467 compile_error,
122468 /// Log compile time variables and emit an error message.
469 /// Uses the `pl_node` union field. The AST node is the compile log builtin call.
470 /// The payload is `MultiOp`.
123471 compile_log,
124472 /// Conditional branch. Splits control flow based on a boolean condition value.
125473 condbr,
126474 /// Special case, has no textual representation.
127475 @"const",
128 /// Container field with just the name.
129 container_field_named,
130 /// Container field with a type and a name,
131 container_field_typed,
132 /// Container field with all the bells and whistles.
133 container_field,
134476 /// Declares the beginning of a statement. Used for debug info.
135 dbg_stmt,
477 /// Uses the `node` union field.
478 dbg_stmt_node,
136479 /// Represents a pointer to a global decl.
480 /// Uses the `decl` union field.
137481 decl_ref,
138 /// Represents a pointer to a global decl by string name.
139 decl_ref_str,
140482 /// Equivalent to a decl_ref followed by deref.
483 /// Uses the `decl` union field.
141484 decl_val,
142 /// Load the value from a pointer.
143 deref,
485 /// Load the value from a pointer. Assumes `x.*` syntax.
486 /// Uses `un_node` field. AST node is the `x.*` syntax.
487 deref_node,
144488 /// Arithmetic division. Asserts no integer overflow.
145489 div,
146490 /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at
147 /// the provided index.
491 /// the provided index. Uses the `bin` union field. Source location is implied
492 /// to be the same as the previous instruction.
148493 elem_ptr,
494 /// Same as `elem_ptr` except also stores a source location node.
495 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
496 elem_ptr_node,
149497 /// Given an array, slice, or pointer, returns the element at the provided index.
498 /// Uses the `bin` union field. Source location is implied to be the same
499 /// as the previous instruction.
150500 elem_val,
501 /// Same as `elem_val` except also stores a source location node.
502 /// Uses the `pl_node` union field. AST node is a[b] syntax. Payload is `Bin`.
503 elem_val_node,
151504 /// Emits a compile error if the operand is not `void`.
505 /// Uses the `un_node` field.
152506 ensure_result_used,
153507 /// Emits a compile error if an error is ignored.
508 /// Uses the `un_node` field.
154509 ensure_result_non_error,
155510 /// Create a `E!T` type.
156511 error_union_type,
157 /// Create an error set.
512 /// Create an error set. extra[lhs..rhs]. The values are token index offsets.
158513 error_set,
159 /// `error.Foo` syntax.
514 /// `error.Foo` syntax. uses the `tok` field of the Data union.
160515 error_value,
161 /// Export the provided Decl as the provided name in the compilation's output object file.
162 @"export",
163516 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
164 /// to the named field. The field name is a []const u8. Used by a.b syntax.
517 /// to the named field. The field name is stored in string_bytes. Used by a.b syntax.
518 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
165519 field_ptr,
166520 /// Given a struct or object that contains virtual fields, returns the named field.
167 /// The field name is a []const u8. Used by a.b syntax.
521 /// The field name is stored in string_bytes. Used by a.b syntax.
522 /// Uses `pl_node` field. The AST node is the a.b syntax. Payload is Field.
168523 field_val,
169524 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
170525 /// to the named field. The field name is a comptime instruction. Used by @field.
526 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
171527 field_ptr_named,
172528 /// Given a struct or object that contains virtual fields, returns the named field.
173529 /// The field name is a comptime instruction. Used by @field.
530 /// Uses `pl_node` field. The AST node is the builtin call. Payload is FieldNamed.
174531 field_val_named,
175 /// Convert a larger float type to any other float type, possibly causing a loss of precision.
532 /// Convert a larger float type to any other float type, possibly causing
533 /// a loss of precision.
176534 floatcast,
177 /// Declare a function body.
178 @"fn",
179535 /// Returns a function type, assuming unspecified calling convention.
536 /// Uses the `fn_type` union field. `payload_index` points to a `FnType`.
180537 fn_type,
181538 /// Same as `fn_type` but the function is variadic.
182539 fn_type_var_args,
183540 /// Returns a function type, with a calling convention instruction operand.
541 /// Uses the `fn_type` union field. `payload_index` points to a `FnTypeCc`.
184542 fn_type_cc,
185543 /// Same as `fn_type_cc` but the function is variadic.
186544 fn_type_cc_var_args,
187 /// @import(operand)
545 /// `@import(operand)`.
546 /// Uses the `un_node` field.
188547 import,
189 /// Integer literal.
548 /// Integer literal that fits in a u64. Uses the int union value.
190549 int,
191550 /// Convert an integer value to another integer type, asserting that the destination type
192551 /// can hold the same mathematical value.
193552 intcast,
194553 /// Make an integer type out of signedness and bit count.
554 /// lhs is signedness, rhs is bit count.
195555 int_type,
196556 /// Return a boolean false if an optional is null. `x != null`
557 /// Uses the `un_tok` field.
197558 is_non_null,
198559 /// Return a boolean true if an optional is null. `x == null`
560 /// Uses the `un_tok` field.
199561 is_null,
200562 /// Return a boolean false if an optional is null. `x.* != null`
563 /// Uses the `un_tok` field.
201564 is_non_null_ptr,
202565 /// Return a boolean true if an optional is null. `x.* == null`
566 /// Uses the `un_tok` field.
203567 is_null_ptr,
204568 /// Return a boolean true if value is an error
569 /// Uses the `un_tok` field.
205570 is_err,
206571 /// Return a boolean true if dereferenced pointer is an error
572 /// Uses the `un_tok` field.
207573 is_err_ptr,
208574 /// A labeled block of code that loops forever. At the end of the body it is implied
209575 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
576 /// SubRange[lhs..rhs]
210577 loop,
211578 /// Merge two error sets into one, `E1 || E2`.
212579 merge_error_sets,
......@@ -221,63 +588,70 @@ pub const Inst = struct {
221588 /// An await inside a nosuspend scope.
222589 nosuspend_await,
223590 /// Given a reference to a function and a parameter index, returns the
224 /// type of the parameter. TODO what happens when the parameter is `anytype`?
591 /// type of the parameter. The only usage of this instruction is for the
592 /// result location of parameters of function calls. In the case of a function's
593 /// parameter type being `anytype`, it is the type coercion's job to detect this
594 /// scenario and skip the coercion, so that semantic analysis of this instruction
595 /// is not in a position where it must create an invalid type.
596 /// Uses the `param_type` union field.
225597 param_type,
226 /// An alternative to using `const` for simple primitive values such as `true` or `u8`.
227 /// TODO flatten so that each primitive has its own ZIR Inst Tag.
228 primitive,
229598 /// Convert a pointer to a `usize` integer.
599 /// Uses the `un_node` field. The AST node is the builtin fn call node.
230600 ptrtoint,
231601 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
232602 /// stores it in a memory location, and returns a const pointer to it. If the value
233603 /// is `comptime`, the memory location is global static constant data. Otherwise,
234604 /// the memory location is in the stack frame, local to the scope containing the
235605 /// instruction.
606 /// Uses the `un_tok` union field.
236607 ref,
237608 /// Resume an async function.
238609 @"resume",
239610 /// Obtains a pointer to the return value.
611 /// lhs and rhs unused.
240612 ret_ptr,
241613 /// Obtains the return type of the in-scope function.
614 /// lhs and rhs unused.
242615 ret_type,
243 /// Sends control flow back to the function's callee. Takes an operand as the return value.
244 @"return",
245 /// Same as `return` but there is no operand; the operand is implicitly the void value.
246 return_void,
616 /// Sends control flow back to the function's callee.
617 /// Includes an operand as the return value.
618 /// Includes an AST node source location.
619 /// Uses the `un_node` union field.
620 ret_node,
621 /// Sends control flow back to the function's callee.
622 /// Includes an operand as the return value.
623 /// Includes a token source location.
624 /// Uses the un_tok union field.
625 ret_tok,
247626 /// Changes the maximum number of backwards branches that compile-time
248627 /// code execution can use before giving up and making a compile error.
628 /// Uses the `un_node` union field.
249629 set_eval_branch_quota,
250630 /// Integer shift-left. Zeroes are shifted in from the right hand side.
251631 shl,
252632 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
253633 shr,
254 /// Create a const pointer type with element type T. `*const T`
255 single_const_ptr_type,
256 /// Create a mutable pointer type with element type T. `*T`
257 single_mut_ptr_type,
258 /// Create a const pointer type with element type T. `[*]const T`
259 many_const_ptr_type,
260 /// Create a mutable pointer type with element type T. `[*]T`
261 many_mut_ptr_type,
262 /// Create a const pointer type with element type T. `[*c]const T`
263 c_const_ptr_type,
264 /// Create a mutable pointer type with element type T. `[*c]T`
265 c_mut_ptr_type,
266 /// Create a mutable slice type with element type T. `[]T`
267 mut_slice_type,
268 /// Create a const slice type with element type T. `[]T`
269 const_slice_type,
270 /// Create a pointer type with attributes
634 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
635 /// Uses the `ptr_type_simple` union field.
636 ptr_type_simple,
637 /// Create a pointer type which can have a sentinel, alignment, and/or bit range.
638 /// Uses the `ptr_type` union field.
271639 ptr_type,
272640 /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
273641 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
274642 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
275643 /// is the allocation that needs to have its type inferred.
644 /// Uses the `un_node` field. The AST node is the var decl.
276645 resolve_inferred_alloc,
277 /// Slice operation `array_ptr[start..end:sentinel]`
278 slice,
279 /// Slice operation with just start `lhs[rhs..]`
646 /// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
647 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`.
280648 slice_start,
649 /// Slice operation `array_ptr[start..end]`. No sentinel.
650 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceEnd`.
651 slice_end,
652 /// Slice operation `array_ptr[start..end:sentinel]`.
653 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceSentinel`.
654 slice_sentinel,
281655 /// Write a value to a pointer. For loading, see `deref`.
282656 store,
283657 /// Same as `store` but the type of the value being stored will be used to infer
......@@ -287,242 +661,130 @@ pub const Inst = struct {
287661 /// the pointer type.
288662 store_to_inferred_ptr,
289663 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
664 /// Uses the `str` union field.
290665 str,
291 /// Create a struct type.
292 struct_type,
293666 /// Arithmetic subtraction. Asserts no integer overflow.
294667 sub,
295668 /// Twos complement wrapping integer subtraction.
296669 subwrap,
297670 /// Returns the type of a value.
671 /// Uses the `un_tok` field.
298672 typeof,
299 /// Is the builtin @TypeOf which returns the type after peertype resolution of one or more params
673 /// The builtin `@TypeOf` which returns the type after Peer Type Resolution
674 /// of one or more params.
675 /// Uses the `pl_node` field. AST node is the `@TypeOf` call. Payload is `MultiOp`.
300676 typeof_peer,
301677 /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler
302678 /// will assume the correctness of this instruction.
679 /// lhs and rhs unused.
303680 unreachable_unsafe,
304681 /// Asserts control-flow will not reach this instruction. In safety-checked modes,
305682 /// this will generate a call to the panic function unless it can be proven unreachable
306683 /// by the compiler.
684 /// lhs and rhs unused.
307685 unreachable_safe,
308686 /// Bitwise XOR. `^`
309687 xor,
310688 /// Create an optional type '?T'
689 /// Uses the `un_tok` field.
311690 optional_type,
312691 /// Create an optional type '?T'. The operand is a pointer value. The optional type will
313692 /// be the type of the pointer element, wrapped in an optional.
693 /// Uses the `un_tok` field.
314694 optional_type_from_ptr_elem,
315 /// Create a union type.
316 union_type,
317695 /// ?T => T with safety.
318696 /// Given an optional value, returns the payload value, with a safety check that
319697 /// the value is non-null. Used for `orelse`, `if` and `while`.
698 /// Uses the `un_tok` field.
320699 optional_payload_safe,
321700 /// ?T => T without safety.
322701 /// Given an optional value, returns the payload value. No safety checks.
702 /// Uses the `un_tok` field.
323703 optional_payload_unsafe,
324704 /// *?T => *T with safety.
325705 /// Given a pointer to an optional value, returns a pointer to the payload value,
326706 /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`.
707 /// Uses the `un_tok` field.
327708 optional_payload_safe_ptr,
328709 /// *?T => *T without safety.
329710 /// Given a pointer to an optional value, returns a pointer to the payload value.
330711 /// No safety checks.
712 /// Uses the `un_tok` field.
331713 optional_payload_unsafe_ptr,
332714 /// E!T => T with safety.
333715 /// Given an error union value, returns the payload value, with a safety check
334716 /// that the value is not an error. Used for catch, if, and while.
717 /// Uses the `un_tok` field.
335718 err_union_payload_safe,
336719 /// E!T => T without safety.
337720 /// Given an error union value, returns the payload value. No safety checks.
721 /// Uses the `un_tok` field.
338722 err_union_payload_unsafe,
339723 /// *E!T => *T with safety.
340724 /// Given a pointer to an error union value, returns a pointer to the payload value,
341725 /// with a safety check that the value is not an error. Used for catch, if, and while.
726 /// Uses the `un_tok` field.
342727 err_union_payload_safe_ptr,
343728 /// *E!T => *T without safety.
344729 /// Given a pointer to a error union value, returns a pointer to the payload value.
345730 /// No safety checks.
731 /// Uses the `un_tok` field.
346732 err_union_payload_unsafe_ptr,
347733 /// E!T => E without safety.
348734 /// Given an error union value, returns the error code. No safety checks.
735 /// Uses the `un_tok` field.
349736 err_union_code,
350737 /// *E!T => E without safety.
351738 /// Given a pointer to an error union value, returns the error code. No safety checks.
739 /// Uses the `un_tok` field.
352740 err_union_code_ptr,
353741 /// Takes a *E!T and raises a compiler error if T != void
742 /// Uses the `un_tok` field.
354743 ensure_err_payload_void,
355 /// Create a enum literal,
744 /// An enum literal. Uses the `str` union field.
356745 enum_literal,
357 /// Create an enum type.
358 enum_type,
359 /// Does nothing; returns a void value.
360 void_value,
361 /// Suspend an async function.
362 @"suspend",
363 /// Suspend an async function.
364 /// Same as .suspend but with a block.
746 /// Suspend an async function. The suspend block has 0 or 1 statements in it.
747 /// Uses the `un_node` union field.
748 suspend_block_one,
749 /// Suspend an async function. The suspend block has any number of statements in it.
750 /// Uses the `block` union field.
365751 suspend_block,
366752 /// A switch expression.
367 switchbr,
368 /// Same as `switchbr` but the target is a pointer to the value being switched on.
369 switchbr_ref,
753 /// lhs is target, SwitchBr[rhs]
754 /// All prongs of target handled.
755 switch_br,
756 /// Same as switch_br, except has a range field.
757 switch_br_range,
758 /// Same as switch_br, except has an else prong.
759 switch_br_else,
760 /// Same as switch_br_else, except has a range field.
761 switch_br_else_range,
762 /// Same as switch_br, except has an underscore prong.
763 switch_br_underscore,
764 /// Same as switch_br, except has a range field.
765 switch_br_underscore_range,
766 /// Same as `switch_br` but the target is a pointer to the value being switched on.
767 switch_br_ref,
768 /// Same as `switch_br_range` but the target is a pointer to the value being switched on.
769 switch_br_ref_range,
770 /// Same as `switch_br_else` but the target is a pointer to the value being switched on.
771 switch_br_ref_else,
772 /// Same as `switch_br_else_range` but the target is a pointer to the
773 /// value being switched on.
774 switch_br_ref_else_range,
775 /// Same as `switch_br_underscore` but the target is a pointer to the value
776 /// being switched on.
777 switch_br_ref_underscore,
778 /// Same as `switch_br_underscore_range` but the target is a pointer to
779 /// the value being switched on.
780 switch_br_ref_underscore_range,
370781 /// A range in a switch case, `lhs...rhs`.
371782 /// Only checks that `lhs >= rhs` if they are ints, everything else is
372 /// validated by the .switch instruction.
783 /// validated by the switch_br instruction.
373784 switch_range,
374785
375 pub fn Type(tag: Tag) type {
376 return switch (tag) {
377 .alloc_inferred,
378 .alloc_inferred_mut,
379 .breakpoint,
380 .dbg_stmt,
381 .return_void,
382 .ret_ptr,
383 .ret_type,
384 .unreachable_unsafe,
385 .unreachable_safe,
386 .void_value,
387 .@"suspend",
388 => NoOp,
389
390 .alloc,
391 .alloc_mut,
392 .bool_not,
393 .compile_error,
394 .deref,
395 .@"return",
396 .is_null,
397 .is_non_null,
398 .is_null_ptr,
399 .is_non_null_ptr,
400 .is_err,
401 .is_err_ptr,
402 .ptrtoint,
403 .ensure_result_used,
404 .ensure_result_non_error,
405 .bitcast_result_ptr,
406 .ref,
407 .bitcast_ref,
408 .typeof,
409 .resolve_inferred_alloc,
410 .single_const_ptr_type,
411 .single_mut_ptr_type,
412 .many_const_ptr_type,
413 .many_mut_ptr_type,
414 .c_const_ptr_type,
415 .c_mut_ptr_type,
416 .mut_slice_type,
417 .const_slice_type,
418 .optional_type,
419 .optional_type_from_ptr_elem,
420 .optional_payload_safe,
421 .optional_payload_unsafe,
422 .optional_payload_safe_ptr,
423 .optional_payload_unsafe_ptr,
424 .err_union_payload_safe,
425 .err_union_payload_unsafe,
426 .err_union_payload_safe_ptr,
427 .err_union_payload_unsafe_ptr,
428 .err_union_code,
429 .err_union_code_ptr,
430 .ensure_err_payload_void,
431 .anyframe_type,
432 .bit_not,
433 .import,
434 .set_eval_branch_quota,
435 .indexable_ptr_len,
436 .@"resume",
437 .@"await",
438 .nosuspend_await,
439 => UnOp,
440
441 .add,
442 .addwrap,
443 .array_cat,
444 .array_mul,
445 .array_type,
446 .bit_and,
447 .bit_or,
448 .bool_and,
449 .bool_or,
450 .div,
451 .mod_rem,
452 .mul,
453 .mulwrap,
454 .shl,
455 .shr,
456 .store,
457 .store_to_block_ptr,
458 .store_to_inferred_ptr,
459 .sub,
460 .subwrap,
461 .cmp_lt,
462 .cmp_lte,
463 .cmp_eq,
464 .cmp_gte,
465 .cmp_gt,
466 .cmp_neq,
467 .as,
468 .floatcast,
469 .intcast,
470 .bitcast,
471 .coerce_result_ptr,
472 .xor,
473 .error_union_type,
474 .merge_error_sets,
475 .slice_start,
476 .switch_range,
477 => BinOp,
478
479 .block,
480 .block_flat,
481 .block_comptime,
482 .block_comptime_flat,
483 .suspend_block,
484 => Block,
485
486 .switchbr, .switchbr_ref => SwitchBr,
487
488 .arg => Arg,
489 .array_type_sentinel => ArrayTypeSentinel,
490 .@"break" => Break,
491 .break_void => BreakVoid,
492 .call => Call,
493 .decl_ref => DeclRef,
494 .decl_ref_str => DeclRefStr,
495 .decl_val => DeclVal,
496 .compile_log => CompileLog,
497 .loop => Loop,
498 .@"const" => Const,
499 .str => Str,
500 .int => Int,
501 .int_type => IntType,
502 .field_ptr, .field_val => Field,
503 .field_ptr_named, .field_val_named => FieldNamed,
504 .@"asm" => Asm,
505 .@"fn" => Fn,
506 .@"export" => Export,
507 .param_type => ParamType,
508 .primitive => Primitive,
509 .fn_type, .fn_type_var_args => FnType,
510 .fn_type_cc, .fn_type_cc_var_args => FnTypeCc,
511 .elem_ptr, .elem_val => Elem,
512 .condbr => CondBr,
513 .ptr_type => PtrType,
514 .enum_literal => EnumLiteral,
515 .error_set => ErrorSet,
516 .error_value => ErrorValue,
517 .slice => Slice,
518 .typeof_peer => TypeOfPeer,
519 .container_field_named => ContainerFieldNamed,
520 .container_field_typed => ContainerFieldTyped,
521 .container_field => ContainerField,
522 .enum_type => EnumType,
523 .union_type => UnionType,
524 .struct_type => StructType,
525 };
786 comptime {
787 assert(@sizeOf(Tag) == 1);
526788 }
527789
528790 /// Returns whether the instruction is one of the control flow "noreturn" types.
......@@ -540,7 +802,6 @@ pub const Inst = struct {
540802 .array_type,
541803 .array_type_sentinel,
542804 .indexable_ptr_len,
543 .arg,
544805 .as,
545806 .@"asm",
546807 .bit_and,
......@@ -557,6 +818,13 @@ pub const Inst = struct {
557818 .bool_or,
558819 .breakpoint,
559820 .call,
821 .call_async_kw,
822 .call_never_tail,
823 .call_never_inline,
824 .call_no_async,
825 .call_always_tail,
826 .call_always_inline,
827 .call_compile_time,
560828 .cmp_lt,
561829 .cmp_lte,
562830 .cmp_eq,
......@@ -567,21 +835,18 @@ pub const Inst = struct {
567835 .@"const",
568836 .dbg_stmt,
569837 .decl_ref,
570 .decl_ref_str,
571838 .decl_val,
572 .deref,
839 .deref_node,
573840 .div,
574841 .elem_ptr,
575842 .elem_val,
576843 .ensure_result_used,
577844 .ensure_result_non_error,
578 .@"export",
579845 .floatcast,
580846 .field_ptr,
581847 .field_val,
582848 .field_ptr_named,
583849 .field_val_named,
584 .@"fn",
585850 .fn_type,
586851 .fn_type_var_args,
587852 .fn_type_cc,
......@@ -599,7 +864,6 @@ pub const Inst = struct {
599864 .mul,
600865 .mulwrap,
601866 .param_type,
602 .primitive,
603867 .ptrtoint,
604868 .ref,
605869 .ret_ptr,
......@@ -635,6 +899,7 @@ pub const Inst = struct {
635899 .err_union_code,
636900 .err_union_code_ptr,
637901 .ptr_type,
902 .ptr_type_simple,
638903 .ensure_err_payload_void,
639904 .enum_literal,
640905 .merge_error_sets,
......@@ -650,9 +915,6 @@ pub const Inst = struct {
650915 .resolve_inferred_alloc,
651916 .set_eval_branch_quota,
652917 .compile_log,
653 .enum_type,
654 .union_type,
655 .struct_type,
656918 .void_value,
657919 .switch_range,
658920 .@"resume",
......@@ -661,19 +923,19 @@ pub const Inst = struct {
661923 => false,
662924
663925 .@"break",
664 .break_void,
926 .break_void_tok,
665927 .condbr,
666928 .compile_error,
667 .@"return",
668 .return_void,
929 .ret_node,
930 .ret_tok,
669931 .unreachable_unsafe,
670932 .unreachable_safe,
671933 .loop,
672934 .container_field_named,
673935 .container_field_typed,
674936 .container_field,
675 .switchbr,
676 .switchbr_ref,
937 .switch_br,
938 .switch_br_ref,
677939 .@"suspend",
678940 .suspend_block,
679941 => true,
......@@ -681,1346 +943,244 @@ pub const Inst = struct {
681943 }
682944 };
683945
684 /// Prefer `castTag` to this.
685 pub fn cast(base: *Inst, comptime T: type) ?*T {
686 if (@hasField(T, "base_tag")) {
687 return base.castTag(T.base_tag);
688 }
689 inline for (@typeInfo(Tag).Enum.fields) |field| {
690 const tag = @intToEnum(Tag, field.value);
691 if (base.tag == tag) {
692 if (T == tag.Type()) {
693 return @fieldParentPtr(T, "base", base);
694 }
695 return null;
946 /// The position of a ZIR instruction within the `Code` instructions array.
947 pub const Index = u32;
948
949 /// A reference to another ZIR instruction. If this value is below a certain
950 /// threshold, it implicitly refers to a constant-known value from the `Const` enum.
951 /// Below a second threshold, it implicitly refers to a parameter of the current
952 /// function.
953 /// Finally, after subtracting that offset, it refers to another instruction in
954 /// the instruction array.
955 /// This logic is implemented in `Sema.resolveRef`.
956 pub const Ref = u32;
957
958 /// For instructions whose payload fits into 8 bytes, this is used.
959 /// When an instruction's payload does not fit, bin_op is used, and
960 /// lhs and rhs refer to `Tag`-specific values, with one of the operands
961 /// used to index into a separate array specific to that instruction.
962 pub const Data = union {
963 /// Used for unary operators, with an AST node source location.
964 un_node: struct {
965 /// Offset from Decl AST node index.
966 src_node: ast.Node.Index,
967 /// The meaning of this operand depends on the corresponding `Tag`.
968 operand: Ref,
969
970 fn src(self: @This()) LazySrcLoc {
971 return .{ .node_offset = self.src_node };
696972 }
697 }
698 unreachable;
699 }
700
701 pub fn castTag(base: *Inst, comptime tag: Tag) ?*tag.Type() {
702 if (base.tag == tag) {
703 return @fieldParentPtr(tag.Type(), "base", base);
704 }
705 return null;
706 }
707
708 pub const NoOp = struct {
709 base: Inst,
710
711 positionals: struct {},
712 kw_args: struct {},
713 };
714
715 pub const UnOp = struct {
716 base: Inst,
717
718 positionals: struct {
719 operand: *Inst,
720 },
721 kw_args: struct {},
722 };
723
724 pub const BinOp = struct {
725 base: Inst,
726
727 positionals: struct {
728 lhs: *Inst,
729 rhs: *Inst,
730 },
731 kw_args: struct {},
732 };
733
734 pub const Arg = struct {
735 pub const base_tag = Tag.arg;
736 base: Inst,
737
738 positionals: struct {
739 /// This exists to be passed to the arg TZIR instruction, which
740 /// needs it for debug info.
741 name: []const u8,
742 },
743 kw_args: struct {},
744 };
745
746 pub const Block = struct {
747 pub const base_tag = Tag.block;
748 base: Inst,
749
750 positionals: struct {
751 body: Body,
752 },
753 kw_args: struct {},
754 };
755
756 pub const Break = struct {
757 pub const base_tag = Tag.@"break";
758 base: Inst,
759
760 positionals: struct {
761 block: *Block,
762 operand: *Inst,
763 },
764 kw_args: struct {},
765 };
766
767 pub const BreakVoid = struct {
768 pub const base_tag = Tag.break_void;
769 base: Inst,
770
771 positionals: struct {
772 block: *Block,
773 },
774 kw_args: struct {},
775 };
776
777 // TODO break this into multiple call instructions to avoid paying the cost
778 // of the calling convention field most of the time.
779 pub const Call = struct {
780 pub const base_tag = Tag.call;
781 base: Inst,
782
783 positionals: struct {
784 func: *Inst,
785 args: []*Inst,
786 modifier: std.builtin.CallOptions.Modifier = .auto,
787973 },
788 kw_args: struct {},
789 };
790
791 pub const DeclRef = struct {
792 pub const base_tag = Tag.decl_ref;
793 base: Inst,
794
795 positionals: struct {
796 decl: *IrModule.Decl,
974 /// Used for unary operators, with a token source location.
975 un_tok: struct {
976 /// Offset from Decl AST token index.
977 src_tok: ast.TokenIndex,
978 /// The meaning of this operand depends on the corresponding `Tag`.
979 operand: Ref,
980
981 fn src(self: @This()) LazySrcLoc {
982 return .{ .token_offset = self.src_tok };
983 }
797984 },
798 kw_args: struct {},
799 };
800
801 pub const DeclRefStr = struct {
802 pub const base_tag = Tag.decl_ref_str;
803 base: Inst,
804
805 positionals: struct {
806 name: *Inst,
985 pl_node: struct {
986 /// Offset from Decl AST node index.
987 /// `Tag` determines which kind of AST node this points to.
988 src_node: ast.Node.Index,
989 /// index into extra.
990 /// `Tag` determines what lives there.
991 payload_index: u32,
992
993 fn src(self: @This()) LazySrcLoc {
994 return .{ .node_offset = self.src_node };
995 }
807996 },
808 kw_args: struct {},
809 };
810
811 pub const DeclVal = struct {
812 pub const base_tag = Tag.decl_val;
813 base: Inst,
814
815 positionals: struct {
816 decl: *IrModule.Decl,
997 bin: Bin,
998 decl: *Module.Decl,
999 @"const": *TypedValue,
1000 str: struct {
1001 /// Offset into `string_bytes`.
1002 start: u32,
1003 /// Number of bytes in the string.
1004 len: u32,
1005
1006 pub fn get(self: @This(), code: Code) []const u8 {
1007 return code.string_bytes[self.start..][0..self.len];
1008 }
8171009 },
818 kw_args: struct {},
819 };
820
821 pub const CompileLog = struct {
822 pub const base_tag = Tag.compile_log;
823 base: Inst,
824
825 positionals: struct {
826 to_log: []*Inst,
1010 /// Offset from Decl AST token index.
1011 tok: ast.TokenIndex,
1012 /// Offset from Decl AST node index.
1013 node: ast.Node.Index,
1014 int: u64,
1015 condbr: struct {
1016 condition: Ref,
1017 /// index into extra.
1018 payload_index: u32,
8271019 },
828 kw_args: struct {},
829 };
830
831 pub const Const = struct {
832 pub const base_tag = Tag.@"const";
833 base: Inst,
834
835 positionals: struct {
836 typed_value: TypedValue,
1020 ptr_type_simple: struct {
1021 is_allowzero: bool,
1022 is_mutable: bool,
1023 is_volatile: bool,
1024 size: std.builtin.TypeInfo.Pointer.Size,
1025 elem_type: Ref,
8371026 },
838 kw_args: struct {},
839 };
840
841 pub const Str = struct {
842 pub const base_tag = Tag.str;
843 base: Inst,
844
845 positionals: struct {
846 bytes: []const u8,
1027 ptr_type: struct {
1028 flags: packed struct {
1029 is_allowzero: bool,
1030 is_mutable: bool,
1031 is_volatile: bool,
1032 has_sentinel: bool,
1033 has_align: bool,
1034 has_bit_start: bool,
1035 has_bit_end: bool,
1036 _: u1 = undefined,
1037 },
1038 size: std.builtin.TypeInfo.Pointer.Size,
1039 /// Index into extra. See `PtrType`.
1040 payload_index: u32,
8471041 },
848 kw_args: struct {},
849 };
850
851 pub const Int = struct {
852 pub const base_tag = Tag.int;
853 base: Inst,
854
855 positionals: struct {
856 int: BigIntConst,
1042 fn_type: struct {
1043 return_type: Ref,
1044 /// For `fn_type` this points to a `FnType` in `extra`.
1045 /// For `fn_type_cc` this points to `FnTypeCc` in `extra`.
1046 payload_index: u32,
8571047 },
858 kw_args: struct {},
859 };
860
861 pub const Loop = struct {
862 pub const base_tag = Tag.loop;
863 base: Inst,
864
865 positionals: struct {
866 body: Body,
1048 param_type: struct {
1049 callee: Ref,
1050 param_index: u32,
8671051 },
868 kw_args: struct {},
869 };
8701052
871 pub const Field = struct {
872 base: Inst,
873
874 positionals: struct {
875 object: *Inst,
876 field_name: []const u8,
877 },
878 kw_args: struct {},
879 };
880
881 pub const FieldNamed = struct {
882 base: Inst,
883
884 positionals: struct {
885 object: *Inst,
886 field_name: *Inst,
887 },
888 kw_args: struct {},
1053 // Make sure we don't accidentally add a field to make this union
1054 // bigger than expected. Note that in Debug builds, Zig is allowed
1055 // to insert a secret field for safety checks.
1056 comptime {
1057 if (std.builtin.mode != .Debug) {
1058 assert(@sizeOf(Data) == 8);
1059 }
1060 }
8891061 };
8901062
1063 /// Stored in extra. Trailing is:
1064 /// * output_name: u32 // index into string_bytes (null terminated) if output is present
1065 /// * arg: Ref // for every args_len.
1066 /// * arg_name: u32 // index into string_bytes (null terminated) for every args_len.
1067 /// * clobber: u32 // index into string_bytes (null terminated) for every clobbers_len.
8911068 pub const Asm = struct {
892 pub const base_tag = Tag.@"asm";
893 base: Inst,
894
895 positionals: struct {
896 asm_source: *Inst,
897 return_type: *Inst,
898 },
899 kw_args: struct {
900 @"volatile": bool = false,
901 output: ?*Inst = null,
902 inputs: []const []const u8 = &.{},
903 clobbers: []const []const u8 = &.{},
904 args: []*Inst = &[0]*Inst{},
905 },
906 };
907
908 pub const Fn = struct {
909 pub const base_tag = Tag.@"fn";
910 base: Inst,
911
912 positionals: struct {
913 fn_type: *Inst,
914 body: Body,
915 },
916 kw_args: struct {},
917 };
918
919 pub const FnType = struct {
920 pub const base_tag = Tag.fn_type;
921 base: Inst,
922
923 positionals: struct {
924 param_types: []*Inst,
925 return_type: *Inst,
926 },
927 kw_args: struct {},
1069 asm_source: Ref,
1070 return_type: Ref,
1071 /// May be omitted.
1072 output: Ref,
1073 args_len: u32,
1074 clobbers_len: u32,
9281075 };
9291076
1077 /// This data is stored inside extra, with trailing parameter type indexes
1078 /// according to `param_types_len`.
1079 /// Each param type is a `Ref`.
9301080 pub const FnTypeCc = struct {
931 pub const base_tag = Tag.fn_type_cc;
932 base: Inst,
933
934 positionals: struct {
935 param_types: []*Inst,
936 return_type: *Inst,
937 cc: *Inst,
938 },
939 kw_args: struct {},
1081 cc: Ref,
1082 param_types_len: u32,
9401083 };
9411084
942 pub const IntType = struct {
943 pub const base_tag = Tag.int_type;
944 base: Inst,
945
946 positionals: struct {
947 signed: *Inst,
948 bits: *Inst,
949 },
950 kw_args: struct {},
951 };
952
953 pub const Export = struct {
954 pub const base_tag = Tag.@"export";
955 base: Inst,
956
957 positionals: struct {
958 symbol_name: *Inst,
959 decl_name: []const u8,
960 },
961 kw_args: struct {},
1085 /// This data is stored inside extra, with trailing parameter type indexes
1086 /// according to `param_types_len`.
1087 /// Each param type is a `Ref`.
1088 pub const FnType = struct {
1089 param_types_len: u32,
9621090 };
9631091
964 pub const ParamType = struct {
965 pub const base_tag = Tag.param_type;
966 base: Inst,
967
968 positionals: struct {
969 func: *Inst,
970 arg_index: usize,
971 },
972 kw_args: struct {},
1092 /// This data is stored inside extra, with trailing operands according to `operands_len`.
1093 /// Each operand is a `Ref`.
1094 pub const MultiOp = struct {
1095 operands_len: u32,
9731096 };
9741097
975 pub const Primitive = struct {
976 pub const base_tag = Tag.primitive;
977 base: Inst,
978
979 positionals: struct {
980 tag: Builtin,
981 },
982 kw_args: struct {},
983
984 pub const Builtin = enum {
985 i8,
986 u8,
987 i16,
988 u16,
989 i32,
990 u32,
991 i64,
992 u64,
993 isize,
994 usize,
995 c_short,
996 c_ushort,
997 c_int,
998 c_uint,
999 c_long,
1000 c_ulong,
1001 c_longlong,
1002 c_ulonglong,
1003 c_longdouble,
1004 c_void,
1005 f16,
1006 f32,
1007 f64,
1008 f128,
1009 bool,
1010 void,
1011 noreturn,
1012 type,
1013 anyerror,
1014 comptime_int,
1015 comptime_float,
1016 @"true",
1017 @"false",
1018 @"null",
1019 @"undefined",
1020 void_value,
1021
1022 pub fn toTypedValue(self: Builtin) TypedValue {
1023 return switch (self) {
1024 .i8 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i8_type) },
1025 .u8 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u8_type) },
1026 .i16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i16_type) },
1027 .u16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u16_type) },
1028 .i32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i32_type) },
1029 .u32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u32_type) },
1030 .i64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.i64_type) },
1031 .u64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.u64_type) },
1032 .isize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.isize_type) },
1033 .usize => .{ .ty = Type.initTag(.type), .val = Value.initTag(.usize_type) },
1034 .c_short => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_short_type) },
1035 .c_ushort => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_ushort_type) },
1036 .c_int => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_int_type) },
1037 .c_uint => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_uint_type) },
1038 .c_long => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_long_type) },
1039 .c_ulong => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_ulong_type) },
1040 .c_longlong => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_longlong_type) },
1041 .c_ulonglong => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_ulonglong_type) },
1042 .c_longdouble => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_longdouble_type) },
1043 .c_void => .{ .ty = Type.initTag(.type), .val = Value.initTag(.c_void_type) },
1044 .f16 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f16_type) },
1045 .f32 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f32_type) },
1046 .f64 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f64_type) },
1047 .f128 => .{ .ty = Type.initTag(.type), .val = Value.initTag(.f128_type) },
1048 .bool => .{ .ty = Type.initTag(.type), .val = Value.initTag(.bool_type) },
1049 .void => .{ .ty = Type.initTag(.type), .val = Value.initTag(.void_type) },
1050 .noreturn => .{ .ty = Type.initTag(.type), .val = Value.initTag(.noreturn_type) },
1051 .type => .{ .ty = Type.initTag(.type), .val = Value.initTag(.type_type) },
1052 .anyerror => .{ .ty = Type.initTag(.type), .val = Value.initTag(.anyerror_type) },
1053 .comptime_int => .{ .ty = Type.initTag(.type), .val = Value.initTag(.comptime_int_type) },
1054 .comptime_float => .{ .ty = Type.initTag(.type), .val = Value.initTag(.comptime_float_type) },
1055 .@"true" => .{ .ty = Type.initTag(.bool), .val = Value.initTag(.bool_true) },
1056 .@"false" => .{ .ty = Type.initTag(.bool), .val = Value.initTag(.bool_false) },
1057 .@"null" => .{ .ty = Type.initTag(.@"null"), .val = Value.initTag(.null_value) },
1058 .@"undefined" => .{ .ty = Type.initTag(.@"undefined"), .val = Value.initTag(.undef) },
1059 .void_value => .{ .ty = Type.initTag(.void), .val = Value.initTag(.void_value) },
1060 };
1061 }
1062 };
1063 };
1064
1065 pub const Elem = struct {
1066 base: Inst,
1067
1068 positionals: struct {
1069 array: *Inst,
1070 index: *Inst,
1071 },
1072 kw_args: struct {},
1098 /// Stored inside extra, with trailing arguments according to `args_len`.
1099 /// Each argument is a `Ref`.
1100 pub const Call = struct {
1101 callee: Ref,
1102 args_len: u32,
10731103 };
10741104
1105 /// This data is stored inside extra, with two sets of trailing indexes:
1106 /// * 0. the then body, according to `then_body_len`.
1107 /// * 1. the else body, according to `else_body_len`.
10751108 pub const CondBr = struct {
1076 pub const base_tag = Tag.condbr;
1077 base: Inst,
1078
1079 positionals: struct {
1080 condition: *Inst,
1081 then_body: Body,
1082 else_body: Body,
1083 },
1084 kw_args: struct {},
1109 then_body_len: u32,
1110 else_body_len: u32,
10851111 };
10861112
1113 /// Stored in extra. Depending on the flags in Data, there will be up to 4
1114 /// trailing Ref fields:
1115 /// 0. sentinel: Ref // if `has_sentinel` flag is set
1116 /// 1. align: Ref // if `has_align` flag is set
1117 /// 2. bit_start: Ref // if `has_bit_start` flag is set
1118 /// 3. bit_end: Ref // if `has_bit_end` flag is set
10871119 pub const PtrType = struct {
1088 pub const base_tag = Tag.ptr_type;
1089 base: Inst,
1090
1091 positionals: struct {
1092 child_type: *Inst,
1093 },
1094 kw_args: struct {
1095 @"allowzero": bool = false,
1096 @"align": ?*Inst = null,
1097 align_bit_start: ?*Inst = null,
1098 align_bit_end: ?*Inst = null,
1099 mutable: bool = true,
1100 @"volatile": bool = false,
1101 sentinel: ?*Inst = null,
1102 size: std.builtin.TypeInfo.Pointer.Size = .One,
1103 },
1120 elem_type: Ref,
11041121 };
11051122
11061123 pub const ArrayTypeSentinel = struct {
1107 pub const base_tag = Tag.array_type_sentinel;
1108 base: Inst,
1109
1110 positionals: struct {
1111 len: *Inst,
1112 sentinel: *Inst,
1113 elem_type: *Inst,
1114 },
1115 kw_args: struct {},
1116 };
1117
1118 pub const EnumLiteral = struct {
1119 pub const base_tag = Tag.enum_literal;
1120 base: Inst,
1121
1122 positionals: struct {
1123 name: []const u8,
1124 },
1125 kw_args: struct {},
1126 };
1127
1128 pub const ErrorSet = struct {
1129 pub const base_tag = Tag.error_set;
1130 base: Inst,
1131
1132 positionals: struct {
1133 fields: [][]const u8,
1134 },
1135 kw_args: struct {},
1124 sentinel: Ref,
1125 elem_type: Ref,
11361126 };
11371127
1138 pub const ErrorValue = struct {
1139 pub const base_tag = Tag.error_value;
1140 base: Inst,
1141
1142 positionals: struct {
1143 name: []const u8,
1144 },
1145 kw_args: struct {},
1146 };
1147
1148 pub const Slice = struct {
1149 pub const base_tag = Tag.slice;
1150 base: Inst,
1151
1152 positionals: struct {
1153 array_ptr: *Inst,
1154 start: *Inst,
1155 },
1156 kw_args: struct {
1157 end: ?*Inst = null,
1158 sentinel: ?*Inst = null,
1159 },
1160 };
1161
1162 pub const TypeOfPeer = struct {
1163 pub const base_tag = .typeof_peer;
1164 base: Inst,
1165 positionals: struct {
1166 items: []*Inst,
1167 },
1168 kw_args: struct {},
1169 };
1170
1171 pub const ContainerFieldNamed = struct {
1172 pub const base_tag = Tag.container_field_named;
1173 base: Inst,
1174
1175 positionals: struct {
1176 bytes: []const u8,
1177 },
1178 kw_args: struct {},
1179 };
1180
1181 pub const ContainerFieldTyped = struct {
1182 pub const base_tag = Tag.container_field_typed;
1183 base: Inst,
1184
1185 positionals: struct {
1186 bytes: []const u8,
1187 ty: *Inst,
1188 },
1189 kw_args: struct {},
1128 pub const SliceStart = struct {
1129 lhs: Ref,
1130 start: Ref,
11901131 };
11911132
1192 pub const ContainerField = struct {
1193 pub const base_tag = Tag.container_field;
1194 base: Inst,
1195
1196 positionals: struct {
1197 bytes: []const u8,
1198 },
1199 kw_args: struct {
1200 ty: ?*Inst = null,
1201 init: ?*Inst = null,
1202 alignment: ?*Inst = null,
1203 is_comptime: bool = false,
1204 },
1133 pub const SliceEnd = struct {
1134 lhs: Ref,
1135 start: Ref,
1136 end: Ref,
12051137 };
12061138
1207 pub const EnumType = struct {
1208 pub const base_tag = Tag.enum_type;
1209 base: Inst,
1210
1211 positionals: struct {
1212 fields: []*Inst,
1213 },
1214 kw_args: struct {
1215 tag_type: ?*Inst = null,
1216 layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
1217 },
1139 pub const SliceSentinel = struct {
1140 lhs: Ref,
1141 start: Ref,
1142 end: Ref,
1143 sentinel: Ref,
12181144 };
12191145
1220 pub const StructType = struct {
1221 pub const base_tag = Tag.struct_type;
1222 base: Inst,
1223
1224 positionals: struct {
1225 fields: []*Inst,
1226 },
1227 kw_args: struct {
1228 layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
1229 },
1230 };
1231
1232 pub const UnionType = struct {
1233 pub const base_tag = Tag.union_type;
1234 base: Inst,
1235
1236 positionals: struct {
1237 fields: []*Inst,
1238 },
1239 kw_args: struct {
1240 init_inst: ?*Inst = null,
1241 has_enum_token: bool,
1242 layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
1243 },
1146 /// The meaning of these operands depends on the corresponding `Tag`.
1147 pub const Bin = struct {
1148 lhs: Ref,
1149 rhs: Ref,
12441150 };
12451151
1152 /// Stored in extra. Depending on zir tag and len fields, extra fields trail
1153 /// this one in the extra array.
1154 /// 0. range: Ref // If the tag has "_range" in it.
1155 /// 1. else_body: Ref // If the tag has "_else" or "_underscore" in it.
1156 /// 2. items: list of all individual items and ranges.
1157 /// 3. cases: {
1158 /// item: Ref,
1159 /// body_len: u32,
1160 /// body member Ref for every body_len
1161 /// } for every cases_len
12461162 pub const SwitchBr = struct {
1247 base: Inst,
1248
1249 positionals: struct {
1250 target: *Inst,
1251 /// List of all individual items and ranges
1252 items: []*Inst,
1253 cases: []Case,
1254 else_body: Body,
1255 /// Pointer to first range if such exists.
1256 range: ?*Inst = null,
1257 special_prong: SpecialProng = .none,
1258 },
1259 kw_args: struct {},
1260
1261 pub const SpecialProng = enum {
1262 none,
1263 @"else",
1264 underscore,
1265 };
1266
1267 pub const Case = struct {
1268 item: *Inst,
1269 body: Body,
1270 };
1271 };
1272};
1273
1274pub const ErrorMsg = struct {
1275 byte_offset: usize,
1276 msg: []const u8,
1277};
1278
1279pub const Body = struct {
1280 instructions: []*Inst,
1281};
1282
1283pub const Module = struct {
1284 decls: []*Decl,
1285 arena: std.heap.ArenaAllocator,
1286 error_msg: ?ErrorMsg = null,
1287 metadata: std.AutoHashMap(*Inst, MetaData),
1288 body_metadata: std.AutoHashMap(*Body, BodyMetaData),
1289
1290 pub const Decl = struct {
1291 name: []const u8,
1292
1293 /// Hash of slice into the source of the part after the = and before the next instruction.
1294 contents_hash: std.zig.SrcHash,
1295
1296 inst: *Inst,
1297 };
1298
1299 pub const MetaData = struct {
1300 deaths: ir.Inst.DeathsInt,
1301 addr: usize,
1302 };
1303
1304 pub const BodyMetaData = struct {
1305 deaths: []*Inst,
1163 /// TODO investigate, why do we need to store this? is it redundant?
1164 items_len: u32,
1165 cases_len: u32,
13061166 };
13071167
1308 pub fn deinit(self: *Module, allocator: *Allocator) void {
1309 self.metadata.deinit();
1310 self.body_metadata.deinit();
1311 allocator.free(self.decls);
1312 self.arena.deinit();
1313 self.* = undefined;
1314 }
1315
1316 /// This is a debugging utility for rendering the tree to stderr.
1317 pub fn dump(self: Module) void {
1318 self.writeToStream(std.heap.page_allocator, std.io.getStdErr().writer()) catch {};
1319 }
1320
1321 const DeclAndIndex = struct {
1322 decl: *Decl,
1323 index: usize,
1168 pub const Field = struct {
1169 lhs: Ref,
1170 /// Offset into `string_bytes`.
1171 field_name_start: u32,
1172 /// Number of bytes in the string.
1173 field_name_len: u32,
13241174 };
13251175
1326 /// TODO Look into making a table to speed this up.
1327 pub fn findDecl(self: Module, name: []const u8) ?DeclAndIndex {
1328 for (self.decls) |decl, i| {
1329 if (mem.eql(u8, decl.name, name)) {
1330 return DeclAndIndex{
1331 .decl = decl,
1332 .index = i,
1333 };
1334 }
1335 }
1336 return null;
1337 }
1338
1339 pub fn findInstDecl(self: Module, inst: *Inst) ?DeclAndIndex {
1340 for (self.decls) |decl, i| {
1341 if (decl.inst == inst) {
1342 return DeclAndIndex{
1343 .decl = decl,
1344 .index = i,
1345 };
1346 }
1347 }
1348 return null;
1349 }
1350
1351 /// The allocator is used for temporary storage, but this function always returns
1352 /// with no resources allocated.
1353 pub fn writeToStream(self: Module, allocator: *Allocator, stream: anytype) !void {
1354 var write = Writer{
1355 .module = &self,
1356 .inst_table = InstPtrTable.init(allocator),
1357 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator),
1358 .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(allocator),
1359 .arena = std.heap.ArenaAllocator.init(allocator),
1360 .indent = 2,
1361 .next_instr_index = undefined,
1362 };
1363 defer write.arena.deinit();
1364 defer write.inst_table.deinit();
1365 defer write.block_table.deinit();
1366 defer write.loop_table.deinit();
1367
1368 // First, build a map of *Inst to @ or % indexes
1369 try write.inst_table.ensureCapacity(@intCast(u32, self.decls.len));
1370
1371 for (self.decls) |decl, decl_i| {
1372 try write.inst_table.putNoClobber(decl.inst, .{ .inst = decl.inst, .index = null, .name = decl.name });
1373 }
1374
1375 for (self.decls) |decl, i| {
1376 write.next_instr_index = 0;
1377 try stream.print("@{s} ", .{decl.name});
1378 try write.writeInstToStream(stream, decl.inst);
1379 try stream.writeByte('\n');
1380 }
1381 }
1382};
1383
1384const InstPtrTable = std.AutoHashMap(*Inst, struct { inst: *Inst, index: ?usize, name: []const u8 });
1385
1386const Writer = struct {
1387 module: *const Module,
1388 inst_table: InstPtrTable,
1389 block_table: std.AutoHashMap(*Inst.Block, []const u8),
1390 loop_table: std.AutoHashMap(*Inst.Loop, []const u8),
1391 arena: std.heap.ArenaAllocator,
1392 indent: usize,
1393 next_instr_index: usize,
1394
1395 fn writeInstToStream(
1396 self: *Writer,
1397 stream: anytype,
1398 inst: *Inst,
1399 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1400 inline for (@typeInfo(Inst.Tag).Enum.fields) |enum_field| {
1401 const expected_tag = @field(Inst.Tag, enum_field.name);
1402 if (inst.tag == expected_tag) {
1403 return self.writeInstToStreamGeneric(stream, expected_tag, inst);
1404 }
1405 }
1406 unreachable; // all tags handled
1407 }
1408
1409 fn writeInstToStreamGeneric(
1410 self: *Writer,
1411 stream: anytype,
1412 comptime inst_tag: Inst.Tag,
1413 base: *Inst,
1414 ) (@TypeOf(stream).Error || error{OutOfMemory})!void {
1415 const SpecificInst = inst_tag.Type();
1416 const inst = @fieldParentPtr(SpecificInst, "base", base);
1417 const Positionals = @TypeOf(inst.positionals);
1418 try stream.writeAll("= " ++ @tagName(inst_tag) ++ "(");
1419 const pos_fields = @typeInfo(Positionals).Struct.fields;
1420 inline for (pos_fields) |arg_field, i| {
1421 if (i != 0) {
1422 try stream.writeAll(", ");
1423 }
1424 try self.writeParamToStream(stream, &@field(inst.positionals, arg_field.name));
1425 }
1426
1427 comptime var need_comma = pos_fields.len != 0;
1428 const KW_Args = @TypeOf(inst.kw_args);
1429 inline for (@typeInfo(KW_Args).Struct.fields) |arg_field, i| {
1430 if (@typeInfo(arg_field.field_type) == .Optional) {
1431 if (@field(inst.kw_args, arg_field.name)) |non_optional| {
1432 if (need_comma) try stream.writeAll(", ");
1433 try stream.print("{s}=", .{arg_field.name});
1434 try self.writeParamToStream(stream, &non_optional);
1435 need_comma = true;
1436 }
1437 } else {
1438 if (need_comma) try stream.writeAll(", ");
1439 try stream.print("{s}=", .{arg_field.name});
1440 try self.writeParamToStream(stream, &@field(inst.kw_args, arg_field.name));
1441 need_comma = true;
1442 }
1443 }
1444
1445 try stream.writeByte(')');
1446 }
1447
1448 fn writeParamToStream(self: *Writer, stream: anytype, param_ptr: anytype) !void {
1449 const param = param_ptr.*;
1450 if (@typeInfo(@TypeOf(param)) == .Enum) {
1451 return stream.writeAll(@tagName(param));
1452 }
1453 switch (@TypeOf(param)) {
1454 *Inst => return self.writeInstParamToStream(stream, param),
1455 ?*Inst => return self.writeInstParamToStream(stream, param.?),
1456 []*Inst => {
1457 try stream.writeByte('[');
1458 for (param) |inst, i| {
1459 if (i != 0) {
1460 try stream.writeAll(", ");
1461 }
1462 try self.writeInstParamToStream(stream, inst);
1463 }
1464 try stream.writeByte(']');
1465 },
1466 Body => {
1467 try stream.writeAll("{\n");
1468 if (self.module.body_metadata.get(param_ptr)) |metadata| {
1469 if (metadata.deaths.len > 0) {
1470 try stream.writeByteNTimes(' ', self.indent);
1471 try stream.writeAll("; deaths={");
1472 for (metadata.deaths) |death, i| {
1473 if (i != 0) try stream.writeAll(", ");
1474 try self.writeInstParamToStream(stream, death);
1475 }
1476 try stream.writeAll("}\n");
1477 }
1478 }
1479
1480 for (param.instructions) |inst| {
1481 const my_i = self.next_instr_index;
1482 self.next_instr_index += 1;
1483 try self.inst_table.putNoClobber(inst, .{ .inst = inst, .index = my_i, .name = undefined });
1484 try stream.writeByteNTimes(' ', self.indent);
1485 try stream.print("%{d} ", .{my_i});
1486 if (inst.cast(Inst.Block)) |block| {
1487 const name = try std.fmt.allocPrint(&self.arena.allocator, "label_{d}", .{my_i});
1488 try self.block_table.put(block, name);
1489 } else if (inst.cast(Inst.Loop)) |loop| {
1490 const name = try std.fmt.allocPrint(&self.arena.allocator, "loop_{d}", .{my_i});
1491 try self.loop_table.put(loop, name);
1492 }
1493 self.indent += 2;
1494 try self.writeInstToStream(stream, inst);
1495 if (self.module.metadata.get(inst)) |metadata| {
1496 try stream.print(" ; deaths=0b{b}", .{metadata.deaths});
1497 // This is conditionally compiled in because addresses mess up the tests due
1498 // to Address Space Layout Randomization. It's super useful when debugging
1499 // codegen.zig though.
1500 if (!std.builtin.is_test) {
1501 try stream.print(" 0x{x}", .{metadata.addr});
1502 }
1503 }
1504 self.indent -= 2;
1505 try stream.writeByte('\n');
1506 }
1507 try stream.writeByteNTimes(' ', self.indent - 2);
1508 try stream.writeByte('}');
1509 },
1510 bool => return stream.writeByte("01"[@boolToInt(param)]),
1511 []u8, []const u8 => return stream.print("\"{}\"", .{std.zig.fmtEscapes(param)}),
1512 BigIntConst, usize => return stream.print("{}", .{param}),
1513 TypedValue => return stream.print("TypedValue{{ .ty = {}, .val = {}}}", .{ param.ty, param.val }),
1514 *IrModule.Decl => return stream.print("Decl({s})", .{param.name}),
1515 *Inst.Block => {
1516 const name = self.block_table.get(param) orelse "!BADREF!";
1517 return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)});
1518 },
1519 *Inst.Loop => {
1520 const name = self.loop_table.get(param).?;
1521 return stream.print("\"{}\"", .{std.zig.fmtEscapes(name)});
1522 },
1523 [][]const u8, []const []const u8 => {
1524 try stream.writeByte('[');
1525 for (param) |str, i| {
1526 if (i != 0) {
1527 try stream.writeAll(", ");
1528 }
1529 try stream.print("\"{}\"", .{std.zig.fmtEscapes(str)});
1530 }
1531 try stream.writeByte(']');
1532 },
1533 []Inst.SwitchBr.Case => {
1534 if (param.len == 0) {
1535 return stream.writeAll("{}");
1536 }
1537 try stream.writeAll("{\n");
1538 for (param) |*case, i| {
1539 if (i != 0) {
1540 try stream.writeAll(",\n");
1541 }
1542 try stream.writeByteNTimes(' ', self.indent);
1543 self.indent += 2;
1544 try self.writeParamToStream(stream, &case.item);
1545 try stream.writeAll(" => ");
1546 try self.writeParamToStream(stream, &case.body);
1547 self.indent -= 2;
1548 }
1549 try stream.writeByte('\n');
1550 try stream.writeByteNTimes(' ', self.indent - 2);
1551 try stream.writeByte('}');
1552 },
1553 else => |T| @compileError("unimplemented: rendering parameter of type " ++ @typeName(T)),
1554 }
1555 }
1556
1557 fn writeInstParamToStream(self: *Writer, stream: anytype, inst: *Inst) !void {
1558 if (self.inst_table.get(inst)) |info| {
1559 if (info.index) |i| {
1560 try stream.print("%{d}", .{info.index});
1561 } else {
1562 try stream.print("@{s}", .{info.name});
1563 }
1564 } else if (inst.cast(Inst.DeclVal)) |decl_val| {
1565 try stream.print("@{s}", .{decl_val.positionals.decl.name});
1566 } else {
1567 // This should be unreachable in theory, but since ZIR is used for debugging the compiler
1568 // we output some debug text instead.
1569 try stream.print("?{s}?", .{@tagName(inst.tag)});
1570 }
1571 }
1572};
1573
1574/// For debugging purposes, prints a function representation to stderr.
1575pub fn dumpFn(old_module: IrModule, module_fn: *IrModule.Fn) void {
1576 const allocator = old_module.gpa;
1577 var ctx: DumpTzir = .{
1578 .allocator = allocator,
1579 .arena = std.heap.ArenaAllocator.init(allocator),
1580 .old_module = &old_module,
1581 .module_fn = module_fn,
1582 .indent = 2,
1583 .inst_table = DumpTzir.InstTable.init(allocator),
1584 .partial_inst_table = DumpTzir.InstTable.init(allocator),
1585 .const_table = DumpTzir.InstTable.init(allocator),
1176 pub const FieldNamed = struct {
1177 lhs: Ref,
1178 field_name: Ref,
15861179 };
1587 defer ctx.inst_table.deinit();
1588 defer ctx.partial_inst_table.deinit();
1589 defer ctx.const_table.deinit();
1590 defer ctx.arena.deinit();
1591
1592 switch (module_fn.state) {
1593 .queued => std.debug.print("(queued)", .{}),
1594 .inline_only => std.debug.print("(inline_only)", .{}),
1595 .in_progress => std.debug.print("(in_progress)", .{}),
1596 .sema_failure => std.debug.print("(sema_failure)", .{}),
1597 .dependency_failure => std.debug.print("(dependency_failure)", .{}),
1598 .success => {
1599 const writer = std.io.getStdErr().writer();
1600 ctx.dump(module_fn.body, writer) catch @panic("failed to dump TZIR");
1601 },
1602 }
1603}
1604
1605const DumpTzir = struct {
1606 allocator: *Allocator,
1607 arena: std.heap.ArenaAllocator,
1608 old_module: *const IrModule,
1609 module_fn: *IrModule.Fn,
1610 indent: usize,
1611 inst_table: InstTable,
1612 partial_inst_table: InstTable,
1613 const_table: InstTable,
1614 next_index: usize = 0,
1615 next_partial_index: usize = 0,
1616 next_const_index: usize = 0,
1617
1618 const InstTable = std.AutoArrayHashMap(*ir.Inst, usize);
1619
1620 /// TODO: Improve this code to include a stack of ir.Body and store the instructions
1621 /// in there. Now we are putting all the instructions in a function local table,
1622 /// however instructions that are in a Body can be thown away when the Body ends.
1623 fn dump(dtz: *DumpTzir, body: ir.Body, writer: std.fs.File.Writer) !void {
1624 // First pass to pre-populate the table so that we can show even invalid references.
1625 // Must iterate the same order we iterate the second time.
1626 // We also look for constants and put them in the const_table.
1627 try dtz.fetchInstsAndResolveConsts(body);
1628
1629 std.debug.print("Module.Function(name={s}):\n", .{dtz.module_fn.owner_decl.name});
1630
1631 for (dtz.const_table.items()) |entry| {
1632 const constant = entry.key.castTag(.constant).?;
1633 try writer.print(" @{d}: {} = {};\n", .{
1634 entry.value, constant.base.ty, constant.val,
1635 });
1636 }
1637
1638 return dtz.dumpBody(body, writer);
1639 }
1640
1641 fn fetchInstsAndResolveConsts(dtz: *DumpTzir, body: ir.Body) error{OutOfMemory}!void {
1642 for (body.instructions) |inst| {
1643 try dtz.inst_table.put(inst, dtz.next_index);
1644 dtz.next_index += 1;
1645 switch (inst.tag) {
1646 .alloc,
1647 .retvoid,
1648 .unreach,
1649 .breakpoint,
1650 .dbg_stmt,
1651 .arg,
1652 => {},
1653
1654 .ref,
1655 .ret,
1656 .bitcast,
1657 .not,
1658 .is_non_null,
1659 .is_non_null_ptr,
1660 .is_null,
1661 .is_null_ptr,
1662 .is_err,
1663 .is_err_ptr,
1664 .ptrtoint,
1665 .floatcast,
1666 .intcast,
1667 .load,
1668 .optional_payload,
1669 .optional_payload_ptr,
1670 .wrap_optional,
1671 .wrap_errunion_payload,
1672 .wrap_errunion_err,
1673 .unwrap_errunion_payload,
1674 .unwrap_errunion_err,
1675 .unwrap_errunion_payload_ptr,
1676 .unwrap_errunion_err_ptr,
1677 => {
1678 const un_op = inst.cast(ir.Inst.UnOp).?;
1679 try dtz.findConst(un_op.operand);
1680 },
1681
1682 .add,
1683 .addwrap,
1684 .sub,
1685 .subwrap,
1686 .mul,
1687 .mulwrap,
1688 .cmp_lt,
1689 .cmp_lte,
1690 .cmp_eq,
1691 .cmp_gte,
1692 .cmp_gt,
1693 .cmp_neq,
1694 .store,
1695 .bool_and,
1696 .bool_or,
1697 .bit_and,
1698 .bit_or,
1699 .xor,
1700 => {
1701 const bin_op = inst.cast(ir.Inst.BinOp).?;
1702 try dtz.findConst(bin_op.lhs);
1703 try dtz.findConst(bin_op.rhs);
1704 },
1705
1706 .br => {
1707 const br = inst.castTag(.br).?;
1708 try dtz.findConst(&br.block.base);
1709 try dtz.findConst(br.operand);
1710 },
1711
1712 .br_block_flat => {
1713 const br_block_flat = inst.castTag(.br_block_flat).?;
1714 try dtz.findConst(&br_block_flat.block.base);
1715 try dtz.fetchInstsAndResolveConsts(br_block_flat.body);
1716 },
1717
1718 .br_void => {
1719 const br_void = inst.castTag(.br_void).?;
1720 try dtz.findConst(&br_void.block.base);
1721 },
1722
1723 .block => {
1724 const block = inst.castTag(.block).?;
1725 try dtz.fetchInstsAndResolveConsts(block.body);
1726 },
1727
1728 .condbr => {
1729 const condbr = inst.castTag(.condbr).?;
1730 try dtz.findConst(condbr.condition);
1731 try dtz.fetchInstsAndResolveConsts(condbr.then_body);
1732 try dtz.fetchInstsAndResolveConsts(condbr.else_body);
1733 },
1734
1735 .loop => {
1736 const loop = inst.castTag(.loop).?;
1737 try dtz.fetchInstsAndResolveConsts(loop.body);
1738 },
1739 .call => {
1740 const call = inst.castTag(.call).?;
1741 try dtz.findConst(call.func);
1742 for (call.args) |arg| {
1743 try dtz.findConst(arg);
1744 }
1745 },
1746
1747 // TODO fill out this debug printing
1748 .assembly,
1749 .constant,
1750 .varptr,
1751 .switchbr,
1752 => {},
1753 }
1754 }
1755 }
1756
1757 fn dumpBody(dtz: *DumpTzir, body: ir.Body, writer: std.fs.File.Writer) (std.fs.File.WriteError || error{OutOfMemory})!void {
1758 for (body.instructions) |inst| {
1759 const my_index = dtz.next_partial_index;
1760 try dtz.partial_inst_table.put(inst, my_index);
1761 dtz.next_partial_index += 1;
1762
1763 try writer.writeByteNTimes(' ', dtz.indent);
1764 try writer.print("%{d}: {} = {s}(", .{
1765 my_index, inst.ty, @tagName(inst.tag),
1766 });
1767 switch (inst.tag) {
1768 .alloc,
1769 .retvoid,
1770 .unreach,
1771 .breakpoint,
1772 .dbg_stmt,
1773 => try writer.writeAll(")\n"),
1774
1775 .ref,
1776 .ret,
1777 .bitcast,
1778 .not,
1779 .is_non_null,
1780 .is_null,
1781 .is_non_null_ptr,
1782 .is_null_ptr,
1783 .is_err,
1784 .is_err_ptr,
1785 .ptrtoint,
1786 .floatcast,
1787 .intcast,
1788 .load,
1789 .optional_payload,
1790 .optional_payload_ptr,
1791 .wrap_optional,
1792 .wrap_errunion_err,
1793 .wrap_errunion_payload,
1794 .unwrap_errunion_err,
1795 .unwrap_errunion_payload,
1796 .unwrap_errunion_payload_ptr,
1797 .unwrap_errunion_err_ptr,
1798 => {
1799 const un_op = inst.cast(ir.Inst.UnOp).?;
1800 const kinky = try dtz.writeInst(writer, un_op.operand);
1801 if (kinky != null) {
1802 try writer.writeAll(") // Instruction does not dominate all uses!\n");
1803 } else {
1804 try writer.writeAll(")\n");
1805 }
1806 },
1807
1808 .add,
1809 .addwrap,
1810 .sub,
1811 .subwrap,
1812 .mul,
1813 .mulwrap,
1814 .cmp_lt,
1815 .cmp_lte,
1816 .cmp_eq,
1817 .cmp_gte,
1818 .cmp_gt,
1819 .cmp_neq,
1820 .store,
1821 .bool_and,
1822 .bool_or,
1823 .bit_and,
1824 .bit_or,
1825 .xor,
1826 => {
1827 const bin_op = inst.cast(ir.Inst.BinOp).?;
1828
1829 const lhs_kinky = try dtz.writeInst(writer, bin_op.lhs);
1830 try writer.writeAll(", ");
1831 const rhs_kinky = try dtz.writeInst(writer, bin_op.rhs);
1832
1833 if (lhs_kinky != null or rhs_kinky != null) {
1834 try writer.writeAll(") // Instruction does not dominate all uses!");
1835 if (lhs_kinky) |lhs| {
1836 try writer.print(" %{d}", .{lhs});
1837 }
1838 if (rhs_kinky) |rhs| {
1839 try writer.print(" %{d}", .{rhs});
1840 }
1841 try writer.writeAll("\n");
1842 } else {
1843 try writer.writeAll(")\n");
1844 }
1845 },
1846
1847 .arg => {
1848 const arg = inst.castTag(.arg).?;
1849 try writer.print("{s})\n", .{arg.name});
1850 },
1851
1852 .br => {
1853 const br = inst.castTag(.br).?;
1854
1855 const lhs_kinky = try dtz.writeInst(writer, &br.block.base);
1856 try writer.writeAll(", ");
1857 const rhs_kinky = try dtz.writeInst(writer, br.operand);
1858
1859 if (lhs_kinky != null or rhs_kinky != null) {
1860 try writer.writeAll(") // Instruction does not dominate all uses!");
1861 if (lhs_kinky) |lhs| {
1862 try writer.print(" %{d}", .{lhs});
1863 }
1864 if (rhs_kinky) |rhs| {
1865 try writer.print(" %{d}", .{rhs});
1866 }
1867 try writer.writeAll("\n");
1868 } else {
1869 try writer.writeAll(")\n");
1870 }
1871 },
1872
1873 .br_block_flat => {
1874 const br_block_flat = inst.castTag(.br_block_flat).?;
1875 const block_kinky = try dtz.writeInst(writer, &br_block_flat.block.base);
1876 if (block_kinky != null) {
1877 try writer.writeAll(", { // Instruction does not dominate all uses!\n");
1878 } else {
1879 try writer.writeAll(", {\n");
1880 }
1881
1882 const old_indent = dtz.indent;
1883 dtz.indent += 2;
1884 try dtz.dumpBody(br_block_flat.body, writer);
1885 dtz.indent = old_indent;
1886
1887 try writer.writeByteNTimes(' ', dtz.indent);
1888 try writer.writeAll("})\n");
1889 },
1890
1891 .br_void => {
1892 const br_void = inst.castTag(.br_void).?;
1893 const kinky = try dtz.writeInst(writer, &br_void.block.base);
1894 if (kinky) |_| {
1895 try writer.writeAll(") // Instruction does not dominate all uses!\n");
1896 } else {
1897 try writer.writeAll(")\n");
1898 }
1899 },
1900
1901 .block => {
1902 const block = inst.castTag(.block).?;
1903
1904 try writer.writeAll("{\n");
1905
1906 const old_indent = dtz.indent;
1907 dtz.indent += 2;
1908 try dtz.dumpBody(block.body, writer);
1909 dtz.indent = old_indent;
1910
1911 try writer.writeByteNTimes(' ', dtz.indent);
1912 try writer.writeAll("})\n");
1913 },
1914
1915 .condbr => {
1916 const condbr = inst.castTag(.condbr).?;
1917
1918 const condition_kinky = try dtz.writeInst(writer, condbr.condition);
1919 if (condition_kinky != null) {
1920 try writer.writeAll(", { // Instruction does not dominate all uses!\n");
1921 } else {
1922 try writer.writeAll(", {\n");
1923 }
1924
1925 const old_indent = dtz.indent;
1926 dtz.indent += 2;
1927 try dtz.dumpBody(condbr.then_body, writer);
1928
1929 try writer.writeByteNTimes(' ', old_indent);
1930 try writer.writeAll("}, {\n");
1931
1932 try dtz.dumpBody(condbr.else_body, writer);
1933 dtz.indent = old_indent;
1934
1935 try writer.writeByteNTimes(' ', old_indent);
1936 try writer.writeAll("})\n");
1937 },
1938
1939 .loop => {
1940 const loop = inst.castTag(.loop).?;
1941
1942 try writer.writeAll("{\n");
1943
1944 const old_indent = dtz.indent;
1945 dtz.indent += 2;
1946 try dtz.dumpBody(loop.body, writer);
1947 dtz.indent = old_indent;
1948
1949 try writer.writeByteNTimes(' ', dtz.indent);
1950 try writer.writeAll("})\n");
1951 },
1952
1953 .call => {
1954 const call = inst.castTag(.call).?;
1955
1956 const args_kinky = try dtz.allocator.alloc(?usize, call.args.len);
1957 defer dtz.allocator.free(args_kinky);
1958 std.mem.set(?usize, args_kinky, null);
1959 var any_kinky_args = false;
1960
1961 const func_kinky = try dtz.writeInst(writer, call.func);
1962
1963 for (call.args) |arg, i| {
1964 try writer.writeAll(", ");
1965
1966 args_kinky[i] = try dtz.writeInst(writer, arg);
1967 any_kinky_args = any_kinky_args or args_kinky[i] != null;
1968 }
1969
1970 if (func_kinky != null or any_kinky_args) {
1971 try writer.writeAll(") // Instruction does not dominate all uses!");
1972 if (func_kinky) |func_index| {
1973 try writer.print(" %{d}", .{func_index});
1974 }
1975 for (args_kinky) |arg_kinky| {
1976 if (arg_kinky) |arg_index| {
1977 try writer.print(" %{d}", .{arg_index});
1978 }
1979 }
1980 try writer.writeAll("\n");
1981 } else {
1982 try writer.writeAll(")\n");
1983 }
1984 },
1985
1986 // TODO fill out this debug printing
1987 .assembly,
1988 .constant,
1989 .varptr,
1990 .switchbr,
1991 => {
1992 try writer.writeAll("!TODO!)\n");
1993 },
1994 }
1995 }
1996 }
1997
1998 fn writeInst(dtz: *DumpTzir, writer: std.fs.File.Writer, inst: *ir.Inst) !?usize {
1999 if (dtz.partial_inst_table.get(inst)) |operand_index| {
2000 try writer.print("%{d}", .{operand_index});
2001 return null;
2002 } else if (dtz.const_table.get(inst)) |operand_index| {
2003 try writer.print("@{d}", .{operand_index});
2004 return null;
2005 } else if (dtz.inst_table.get(inst)) |operand_index| {
2006 try writer.print("%{d}", .{operand_index});
2007 return operand_index;
2008 } else {
2009 try writer.writeAll("!BADREF!");
2010 return null;
2011 }
2012 }
2013
2014 fn findConst(dtz: *DumpTzir, operand: *ir.Inst) !void {
2015 if (operand.tag == .constant) {
2016 try dtz.const_table.put(operand, dtz.next_const_index);
2017 dtz.next_const_index += 1;
2018 }
2019 }
20201180};
20211181
20221182/// For debugging purposes, like dumpFn but for unanalyzed zir blocks
2023pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8, instructions: []*Inst) !void {
1183pub fn dumpZir(gpa: *Allocator, kind: []const u8, decl_name: [*:0]const u8, instructions: []*Inst) !void {
20241184 var fib = std.heap.FixedBufferAllocator.init(&[_]u8{});
20251185 var module = Module{
20261186 .decls = &[_]*Module.Decl{},
......@@ -2030,10 +1190,10 @@ pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8
20301190 };
20311191 var write = Writer{
20321192 .module = &module,
2033 .inst_table = InstPtrTable.init(allocator),
2034 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator),
2035 .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(allocator),
2036 .arena = std.heap.ArenaAllocator.init(allocator),
1193 .inst_table = InstPtrTable.init(gpa),
1194 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(gpa),
1195 .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(gpa),
1196 .arena = std.heap.ArenaAllocator.init(gpa),
20371197 .indent = 4,
20381198 .next_instr_index = 0,
20391199 };
src/zir_sema.zig+2221-949
......@@ -1,11 +1,36 @@
11//! Semantic analysis of ZIR instructions.
2//! This file operates on a `Module` instance, transforming untyped ZIR
3//! instructions into semantically-analyzed IR instructions. It does type
4//! checking, comptime control flow, and safety-check generation. This is the
5//! the heart of the Zig compiler.
6//! When deciding if something goes into this file or into Module, here is a
7//! guiding principle: if it has to do with (untyped) ZIR instructions, it goes
8//! here. If the analysis operates on typed IR instructions, it goes in Module.
2//! Shared to every Block. Stored on the stack.
3//! State used for compiling a `zir.Code` into TZIR.
4//! Transforms untyped ZIR instructions into semantically-analyzed TZIR instructions.
5//! Does type checking, comptime control flow, and safety-check generation.
6//! This is the the heart of the Zig compiler.
7
8mod: *Module,
9/// Same as `mod.gpa`.
10gpa: *Allocator,
11/// Points to the arena allocator of the Decl.
12arena: *Allocator,
13code: zir.Code,
14/// Maps ZIR to TZIR.
15inst_map: []*const Inst,
16/// When analyzing an inline function call, owner_decl is the Decl of the caller
17/// and `src_decl` of `Scope.Block` is the `Decl` of the callee.
18/// This `Decl` owns the arena memory of this `Sema`.
19owner_decl: *Decl,
20func: ?*Module.Fn,
21/// For now, TZIR requires arg instructions to be the first N instructions in the
22/// TZIR code. We store references here for the purpose of `resolveInst`.
23/// This can get reworked with TZIR memory layout changes, into simply:
24/// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function,
25/// > otherwise it is the number of parameters of the function.
26/// > param_count: u32
27param_inst_list: []const *ir.Inst,
28branch_quota: u32 = 1000,
29/// This field is updated when a new source location becomes active, so that
30/// instructions which do not have explicitly mapped source locations still have
31/// access to the source location set by the previous instruction which did
32/// contain a mapped source location.
33src: LazySrcLoc = .{ .token_offset = 0 },
934
1035const std = @import("std");
1136const mem = std.mem;
......@@ -13,6 +38,7 @@ const Allocator = std.mem.Allocator;
1338const assert = std.debug.assert;
1439const log = std.log.scoped(.sema);
1540
41const Sema = @This();
1642const Value = @import("value.zig").Value;
1743const Type = @import("type.zig").Type;
1844const TypedValue = @import("TypedValue.zig");
......@@ -25,340 +51,408 @@ const trace = @import("tracy.zig").trace;
2551const Scope = Module.Scope;
2652const InnerError = Module.InnerError;
2753const Decl = Module.Decl;
54const LazySrcLoc = Module.LazySrcLoc;
2855
29pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {
30 switch (old_inst.tag) {
31 .alloc => return zirAlloc(mod, scope, old_inst.castTag(.alloc).?),
32 .alloc_mut => return zirAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?),
33 .alloc_inferred => return zirAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?, .inferred_alloc_const),
34 .alloc_inferred_mut => return zirAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred_mut).?, .inferred_alloc_mut),
35 .arg => return zirArg(mod, scope, old_inst.castTag(.arg).?),
36 .bitcast_ref => return zirBitcastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),
37 .bitcast_result_ptr => return zirBitcastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),
38 .block => return zirBlock(mod, scope, old_inst.castTag(.block).?, false),
39 .block_comptime => return zirBlock(mod, scope, old_inst.castTag(.block_comptime).?, true),
40 .block_flat => return zirBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false),
41 .block_comptime_flat => return zirBlockFlat(mod, scope, old_inst.castTag(.block_comptime_flat).?, true),
42 .@"break" => return zirBreak(mod, scope, old_inst.castTag(.@"break").?),
43 .breakpoint => return zirBreakpoint(mod, scope, old_inst.castTag(.breakpoint).?),
44 .break_void => return zirBreakVoid(mod, scope, old_inst.castTag(.break_void).?),
45 .call => return zirCall(mod, scope, old_inst.castTag(.call).?),
46 .coerce_result_ptr => return zirCoerceResultPtr(mod, scope, old_inst.castTag(.coerce_result_ptr).?),
47 .compile_error => return zirCompileError(mod, scope, old_inst.castTag(.compile_error).?),
48 .compile_log => return zirCompileLog(mod, scope, old_inst.castTag(.compile_log).?),
49 .@"const" => return zirConst(mod, scope, old_inst.castTag(.@"const").?),
50 .dbg_stmt => return zirDbgStmt(mod, scope, old_inst.castTag(.dbg_stmt).?),
51 .decl_ref => return zirDeclRef(mod, scope, old_inst.castTag(.decl_ref).?),
52 .decl_ref_str => return zirDeclRefStr(mod, scope, old_inst.castTag(.decl_ref_str).?),
53 .decl_val => return zirDeclVal(mod, scope, old_inst.castTag(.decl_val).?),
54 .ensure_result_used => return zirEnsureResultUsed(mod, scope, old_inst.castTag(.ensure_result_used).?),
55 .ensure_result_non_error => return zirEnsureResultNonError(mod, scope, old_inst.castTag(.ensure_result_non_error).?),
56 .indexable_ptr_len => return zirIndexablePtrLen(mod, scope, old_inst.castTag(.indexable_ptr_len).?),
57 .ref => return zirRef(mod, scope, old_inst.castTag(.ref).?),
58 .resolve_inferred_alloc => return zirResolveInferredAlloc(mod, scope, old_inst.castTag(.resolve_inferred_alloc).?),
59 .ret_ptr => return zirRetPtr(mod, scope, old_inst.castTag(.ret_ptr).?),
60 .ret_type => return zirRetType(mod, scope, old_inst.castTag(.ret_type).?),
61 .store_to_block_ptr => return zirStoreToBlockPtr(mod, scope, old_inst.castTag(.store_to_block_ptr).?),
62 .store_to_inferred_ptr => return zirStoreToInferredPtr(mod, scope, old_inst.castTag(.store_to_inferred_ptr).?),
63 .single_const_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.single_const_ptr_type).?, false, .One),
64 .single_mut_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.single_mut_ptr_type).?, true, .One),
65 .many_const_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.many_const_ptr_type).?, false, .Many),
66 .many_mut_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.many_mut_ptr_type).?, true, .Many),
67 .c_const_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.c_const_ptr_type).?, false, .C),
68 .c_mut_ptr_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.c_mut_ptr_type).?, true, .C),
69 .const_slice_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.const_slice_type).?, false, .Slice),
70 .mut_slice_type => return zirSimplePtrType(mod, scope, old_inst.castTag(.mut_slice_type).?, true, .Slice),
71 .ptr_type => return zirPtrType(mod, scope, old_inst.castTag(.ptr_type).?),
72 .store => return zirStore(mod, scope, old_inst.castTag(.store).?),
73 .set_eval_branch_quota => return zirSetEvalBranchQuota(mod, scope, old_inst.castTag(.set_eval_branch_quota).?),
74 .str => return zirStr(mod, scope, old_inst.castTag(.str).?),
75 .int => return zirInt(mod, scope, old_inst.castTag(.int).?),
76 .int_type => return zirIntType(mod, scope, old_inst.castTag(.int_type).?),
77 .loop => return zirLoop(mod, scope, old_inst.castTag(.loop).?),
78 .param_type => return zirParamType(mod, scope, old_inst.castTag(.param_type).?),
79 .ptrtoint => return zirPtrtoint(mod, scope, old_inst.castTag(.ptrtoint).?),
80 .field_ptr => return zirFieldPtr(mod, scope, old_inst.castTag(.field_ptr).?),
81 .field_val => return zirFieldVal(mod, scope, old_inst.castTag(.field_val).?),
82 .field_ptr_named => return zirFieldPtrNamed(mod, scope, old_inst.castTag(.field_ptr_named).?),
83 .field_val_named => return zirFieldValNamed(mod, scope, old_inst.castTag(.field_val_named).?),
84 .deref => return zirDeref(mod, scope, old_inst.castTag(.deref).?),
85 .as => return zirAs(mod, scope, old_inst.castTag(.as).?),
86 .@"asm" => return zirAsm(mod, scope, old_inst.castTag(.@"asm").?),
87 .unreachable_safe => return zirUnreachable(mod, scope, old_inst.castTag(.unreachable_safe).?, true),
88 .unreachable_unsafe => return zirUnreachable(mod, scope, old_inst.castTag(.unreachable_unsafe).?, false),
89 .@"return" => return zirReturn(mod, scope, old_inst.castTag(.@"return").?),
90 .return_void => return zirReturnVoid(mod, scope, old_inst.castTag(.return_void).?),
91 .@"fn" => return zirFn(mod, scope, old_inst.castTag(.@"fn").?),
92 .@"export" => return zirExport(mod, scope, old_inst.castTag(.@"export").?),
93 .primitive => return zirPrimitive(mod, scope, old_inst.castTag(.primitive).?),
94 .fn_type => return zirFnType(mod, scope, old_inst.castTag(.fn_type).?, false),
95 .fn_type_cc => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc).?, false),
96 .fn_type_var_args => return zirFnType(mod, scope, old_inst.castTag(.fn_type_var_args).?, true),
97 .fn_type_cc_var_args => return zirFnTypeCc(mod, scope, old_inst.castTag(.fn_type_cc_var_args).?, true),
98 .intcast => return zirIntcast(mod, scope, old_inst.castTag(.intcast).?),
99 .bitcast => return zirBitcast(mod, scope, old_inst.castTag(.bitcast).?),
100 .floatcast => return zirFloatcast(mod, scope, old_inst.castTag(.floatcast).?),
101 .elem_ptr => return zirElemPtr(mod, scope, old_inst.castTag(.elem_ptr).?),
102 .elem_val => return zirElemVal(mod, scope, old_inst.castTag(.elem_val).?),
103 .add => return zirArithmetic(mod, scope, old_inst.castTag(.add).?),
104 .addwrap => return zirArithmetic(mod, scope, old_inst.castTag(.addwrap).?),
105 .sub => return zirArithmetic(mod, scope, old_inst.castTag(.sub).?),
106 .subwrap => return zirArithmetic(mod, scope, old_inst.castTag(.subwrap).?),
107 .mul => return zirArithmetic(mod, scope, old_inst.castTag(.mul).?),
108 .mulwrap => return zirArithmetic(mod, scope, old_inst.castTag(.mulwrap).?),
109 .div => return zirArithmetic(mod, scope, old_inst.castTag(.div).?),
110 .mod_rem => return zirArithmetic(mod, scope, old_inst.castTag(.mod_rem).?),
111 .array_cat => return zirArrayCat(mod, scope, old_inst.castTag(.array_cat).?),
112 .array_mul => return zirArrayMul(mod, scope, old_inst.castTag(.array_mul).?),
113 .bit_and => return zirBitwise(mod, scope, old_inst.castTag(.bit_and).?),
114 .bit_not => return zirBitNot(mod, scope, old_inst.castTag(.bit_not).?),
115 .bit_or => return zirBitwise(mod, scope, old_inst.castTag(.bit_or).?),
116 .xor => return zirBitwise(mod, scope, old_inst.castTag(.xor).?),
117 .shl => return zirShl(mod, scope, old_inst.castTag(.shl).?),
118 .shr => return zirShr(mod, scope, old_inst.castTag(.shr).?),
119 .cmp_lt => return zirCmp(mod, scope, old_inst.castTag(.cmp_lt).?, .lt),
120 .cmp_lte => return zirCmp(mod, scope, old_inst.castTag(.cmp_lte).?, .lte),
121 .cmp_eq => return zirCmp(mod, scope, old_inst.castTag(.cmp_eq).?, .eq),
122 .cmp_gte => return zirCmp(mod, scope, old_inst.castTag(.cmp_gte).?, .gte),
123 .cmp_gt => return zirCmp(mod, scope, old_inst.castTag(.cmp_gt).?, .gt),
124 .cmp_neq => return zirCmp(mod, scope, old_inst.castTag(.cmp_neq).?, .neq),
125 .condbr => return zirCondbr(mod, scope, old_inst.castTag(.condbr).?),
126 .is_null => return zirIsNull(mod, scope, old_inst.castTag(.is_null).?, false),
127 .is_non_null => return zirIsNull(mod, scope, old_inst.castTag(.is_non_null).?, true),
128 .is_null_ptr => return zirIsNullPtr(mod, scope, old_inst.castTag(.is_null_ptr).?, false),
129 .is_non_null_ptr => return zirIsNullPtr(mod, scope, old_inst.castTag(.is_non_null_ptr).?, true),
130 .is_err => return zirIsErr(mod, scope, old_inst.castTag(.is_err).?),
131 .is_err_ptr => return zirIsErrPtr(mod, scope, old_inst.castTag(.is_err_ptr).?),
132 .bool_not => return zirBoolNot(mod, scope, old_inst.castTag(.bool_not).?),
133 .typeof => return zirTypeof(mod, scope, old_inst.castTag(.typeof).?),
134 .typeof_peer => return zirTypeofPeer(mod, scope, old_inst.castTag(.typeof_peer).?),
135 .optional_type => return zirOptionalType(mod, scope, old_inst.castTag(.optional_type).?),
136 .optional_type_from_ptr_elem => return zirOptionalTypeFromPtrElem(mod, scope, old_inst.castTag(.optional_type_from_ptr_elem).?),
137 .optional_payload_safe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_safe).?, true),
138 .optional_payload_unsafe => return zirOptionalPayload(mod, scope, old_inst.castTag(.optional_payload_unsafe).?, false),
139 .optional_payload_safe_ptr => return zirOptionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_safe_ptr).?, true),
140 .optional_payload_unsafe_ptr => return zirOptionalPayloadPtr(mod, scope, old_inst.castTag(.optional_payload_unsafe_ptr).?, false),
141 .err_union_payload_safe => return zirErrUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_safe).?, true),
142 .err_union_payload_unsafe => return zirErrUnionPayload(mod, scope, old_inst.castTag(.err_union_payload_unsafe).?, false),
143 .err_union_payload_safe_ptr => return zirErrUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_safe_ptr).?, true),
144 .err_union_payload_unsafe_ptr => return zirErrUnionPayloadPtr(mod, scope, old_inst.castTag(.err_union_payload_unsafe_ptr).?, false),
145 .err_union_code => return zirErrUnionCode(mod, scope, old_inst.castTag(.err_union_code).?),
146 .err_union_code_ptr => return zirErrUnionCodePtr(mod, scope, old_inst.castTag(.err_union_code_ptr).?),
147 .ensure_err_payload_void => return zirEnsureErrPayloadVoid(mod, scope, old_inst.castTag(.ensure_err_payload_void).?),
148 .array_type => return zirArrayType(mod, scope, old_inst.castTag(.array_type).?),
149 .array_type_sentinel => return zirArrayTypeSentinel(mod, scope, old_inst.castTag(.array_type_sentinel).?),
150 .enum_literal => return zirEnumLiteral(mod, scope, old_inst.castTag(.enum_literal).?),
151 .merge_error_sets => return zirMergeErrorSets(mod, scope, old_inst.castTag(.merge_error_sets).?),
152 .error_union_type => return zirErrorUnionType(mod, scope, old_inst.castTag(.error_union_type).?),
153 .anyframe_type => return zirAnyframeType(mod, scope, old_inst.castTag(.anyframe_type).?),
154 .error_set => return zirErrorSet(mod, scope, old_inst.castTag(.error_set).?),
155 .error_value => return zirErrorValue(mod, scope, old_inst.castTag(.error_value).?),
156 .slice => return zirSlice(mod, scope, old_inst.castTag(.slice).?),
157 .slice_start => return zirSliceStart(mod, scope, old_inst.castTag(.slice_start).?),
158 .import => return zirImport(mod, scope, old_inst.castTag(.import).?),
159 .bool_and => return zirBoolOp(mod, scope, old_inst.castTag(.bool_and).?),
160 .bool_or => return zirBoolOp(mod, scope, old_inst.castTag(.bool_or).?),
161 .void_value => return mod.constVoid(scope, old_inst.src),
162 .switchbr => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr).?, false),
163 .switchbr_ref => return zirSwitchBr(mod, scope, old_inst.castTag(.switchbr_ref).?, true),
164 .switch_range => return zirSwitchRange(mod, scope, old_inst.castTag(.switch_range).?),
165 .@"await" => return zirAwait(mod, scope, old_inst.castTag(.@"await").?),
166 .nosuspend_await => return zirAwait(mod, scope, old_inst.castTag(.nosuspend_await).?),
167 .@"resume" => return zirResume(mod, scope, old_inst.castTag(.@"resume").?),
168 .@"suspend" => return zirSuspend(mod, scope, old_inst.castTag(.@"suspend").?),
169 .suspend_block => return zirSuspendBlock(mod, scope, old_inst.castTag(.suspend_block).?),
170
171 .container_field_named,
172 .container_field_typed,
173 .container_field,
174 .enum_type,
175 .union_type,
176 .struct_type,
177 => return mod.fail(scope, old_inst.src, "TODO analyze container instructions", .{}),
178 }
179}
180
181pub fn analyzeBody(mod: *Module, block: *Scope.Block, body: zir.Body) !void {
182 const tracy = trace(@src());
183 defer tracy.end();
184
185 for (body.instructions) |src_inst| {
186 const analyzed_inst = try analyzeInst(mod, &block.base, src_inst);
187 try block.inst_table.putNoClobber(src_inst, analyzed_inst);
188 if (analyzed_inst.ty.zigTypeTag() == .NoReturn) {
189 break;
190 }
56// TODO when memory layout of TZIR is reworked, this can be simplified.
57const const_tzir_inst_list = blk: {
58 var result: [zir.const_inst_list.len]ir.Inst.Const = undefined;
59 for (result) |*tzir_const, i| {
60 tzir_const.* = .{
61 .base = .{
62 .tag = .constant,
63 .ty = zir.const_inst_list[i].ty,
64 .src = 0,
65 },
66 .val = zir.const_inst_list[i].val,
67 };
19168 }
69 break :blk result;
70};
71
72pub fn root(sema: *Sema, root_block: *Scope.Block) !void {
73 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];
74 return sema.body(root_block, root_body);
19275}
19376
194pub fn analyzeBodyValueAsType(
195 mod: *Module,
196 block_scope: *Scope.Block,
197 zir_result_inst: *zir.Inst,
77pub fn rootAsType(
78 sema: *Sema,
79 root_block: *Scope.Block,
80 zir_result_inst: zir.Inst.Index,
19881 body: zir.Body,
19982) !Type {
200 try analyzeBody(mod, block_scope, body);
201 const result_inst = block_scope.inst_table.get(zir_result_inst).?;
202 const val = try mod.resolveConstValue(&block_scope.base, result_inst);
203 return val.toType(block_scope.base.arena());
83 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];
84 try sema.body(root_block, root_body);
85
86 const result_inst = sema.inst_map[zir_result_inst];
87 // Source location is unneeded because resolveConstValue must have already
88 // been successfully called when coercing the value to a type, from the
89 // result location.
90 const val = try sema.resolveConstValue(root_block, .unneeded, result_inst);
91 return val.toType(root_block.arena);
92}
93
94pub fn body(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !void {
95 const tracy = trace(@src());
96 defer tracy.end();
97
98 const map = block.sema.inst_map;
99 const tags = block.sema.code.instructions.items(.tag);
100
101 // TODO: As an optimization, look into making these switch prongs directly jump
102 // to the next one, rather than detouring through the loop condition.
103 // Also, look into leaving only the "noreturn" loop break condition, and removing
104 // the iteration based one. Better yet, have an extra entry in the tags array as a
105 // sentinel, so that exiting the loop is just another jump table prong.
106 // Related: https://github.com/ziglang/zig/issues/8220
107 for (body) |zir_inst| {
108 map[zir_inst] = switch (tags[zir_inst]) {
109 .alloc => try sema.zirAlloc(block, zir_inst),
110 .alloc_mut => try sema.zirAllocMut(block, zir_inst),
111 .alloc_inferred => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_const)),
112 .alloc_inferred_mut => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_mut)),
113 .bitcast_ref => try sema.zirBitcastRef(block, zir_inst),
114 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, zir_inst),
115 .block => try sema.zirBlock(block, zir_inst, false),
116 .block_comptime => try sema.zirBlock(block, zir_inst, true),
117 .block_flat => try sema.zirBlockFlat(block, zir_inst, false),
118 .block_comptime_flat => try sema.zirBlockFlat(block, zir_inst, true),
119 .@"break" => try sema.zirBreak(block, zir_inst),
120 .break_void_tok => try sema.zirBreakVoidTok(block, zir_inst),
121 .breakpoint => try sema.zirBreakpoint(block, zir_inst),
122 .call => try sema.zirCall(block, zir_inst, .auto),
123 .call_async_kw => try sema.zirCall(block, zir_inst, .async_kw),
124 .call_no_async => try sema.zirCall(block, zir_inst, .no_async),
125 .call_compile_time => try sema.zirCall(block, zir_inst, .compile_time),
126 .call_none => try sema.zirCallNone(block, zir_inst),
127 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, zir_inst),
128 .compile_error => try sema.zirCompileError(block, zir_inst),
129 .compile_log => try sema.zirCompileLog(block, zir_inst),
130 .@"const" => try sema.zirConst(block, zir_inst),
131 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),
132 .decl_ref => try sema.zirDeclRef(block, zir_inst),
133 .decl_val => try sema.zirDeclVal(block, zir_inst),
134 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),
135 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),
136 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, zir_inst),
137 .ref => try sema.zirRef(block, zir_inst),
138 .resolve_inferred_alloc => try sema.zirResolveInferredAlloc(block, zir_inst),
139 .ret_ptr => try sema.zirRetPtr(block, zir_inst),
140 .ret_type => try sema.zirRetType(block, zir_inst),
141 .store_to_block_ptr => try sema.zirStoreToBlockPtr(block, zir_inst),
142 .store_to_inferred_ptr => try sema.zirStoreToInferredPtr(block, zir_inst),
143 .ptr_type_simple => try sema.zirPtrTypeSimple(block, zir_inst),
144 .ptr_type => try sema.zirPtrType(block, zir_inst),
145 .store => try sema.zirStore(block, zir_inst),
146 .set_eval_branch_quota => try sema.zirSetEvalBranchQuota(block, zir_inst),
147 .str => try sema.zirStr(block, zir_inst),
148 .int => try sema.zirInt(block, zir_inst),
149 .int_type => try sema.zirIntType(block, zir_inst),
150 .loop => try sema.zirLoop(block, zir_inst),
151 .param_type => try sema.zirParamType(block, zir_inst),
152 .ptrtoint => try sema.zirPtrtoint(block, zir_inst),
153 .field_ptr => try sema.zirFieldPtr(block, zir_inst),
154 .field_val => try sema.zirFieldVal(block, zir_inst),
155 .field_ptr_named => try sema.zirFieldPtrNamed(block, zir_inst),
156 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),
157 .deref => try sema.zirDeref(block, zir_inst),
158 .as => try sema.zirAs(block, zir_inst),
159 .@"asm" => try sema.zirAsm(block, zir_inst, false),
160 .asm_volatile => try sema.zirAsm(block, zir_inst, true),
161 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
162 .unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),
163 .ret_tok => try sema.zirRetTok(block, zir_inst),
164 .ret_node => try sema.zirRetNode(block, zir_inst),
165 .fn_type => try sema.zirFnType(block, zir_inst),
166 .fn_type_cc => try sema.zirFnTypeCc(block, zir_inst),
167 .intcast => try sema.zirIntcast(block, zir_inst),
168 .bitcast => try sema.zirBitcast(block, zir_inst),
169 .floatcast => try sema.zirFloatcast(block, zir_inst),
170 .elem_ptr => try sema.zirElemPtr(block, zir_inst),
171 .elem_ptr_node => try sema.zirElemPtrNode(block, zir_inst),
172 .elem_val => try sema.zirElemVal(block, zir_inst),
173 .elem_val_node => try sema.zirElemValNode(block, zir_inst),
174 .add => try sema.zirArithmetic(block, zir_inst),
175 .addwrap => try sema.zirArithmetic(block, zir_inst),
176 .sub => try sema.zirArithmetic(block, zir_inst),
177 .subwrap => try sema.zirArithmetic(block, zir_inst),
178 .mul => try sema.zirArithmetic(block, zir_inst),
179 .mulwrap => try sema.zirArithmetic(block, zir_inst),
180 .div => try sema.zirArithmetic(block, zir_inst),
181 .mod_rem => try sema.zirArithmetic(block, zir_inst),
182 .array_cat => try sema.zirArrayCat(block, zir_inst),
183 .array_mul => try sema.zirArrayMul(block, zir_inst),
184 .bit_and => try sema.zirBitwise(block, zir_inst),
185 .bit_not => try sema.zirBitNot(block, zir_inst),
186 .bit_or => try sema.zirBitwise(block, zir_inst),
187 .xor => try sema.zirBitwise(block, zir_inst),
188 .shl => try sema.zirShl(block, zir_inst),
189 .shr => try sema.zirShr(block, zir_inst),
190 .cmp_lt => try sema.zirCmp(block, zir_inst, .lt),
191 .cmp_lte => try sema.zirCmp(block, zir_inst, .lte),
192 .cmp_eq => try sema.zirCmp(block, zir_inst, .eq),
193 .cmp_gte => try sema.zirCmp(block, zir_inst, .gte),
194 .cmp_gt => try sema.zirCmp(block, zir_inst, .gt),
195 .cmp_neq => try sema.zirCmp(block, zir_inst, .neq),
196 .condbr => try sema.zirCondbr(block, zir_inst),
197 .is_null => try sema.zirIsNull(block, zir_inst, false),
198 .is_non_null => try sema.zirIsNull(block, zir_inst, true),
199 .is_null_ptr => try sema.zirIsNullPtr(block, zir_inst, false),
200 .is_non_null_ptr => try sema.zirIsNullPtr(block, zir_inst, true),
201 .is_err => try sema.zirIsErr(block, zir_inst),
202 .is_err_ptr => try sema.zirIsErrPtr(block, zir_inst),
203 .bool_not => try sema.zirBoolNot(block, zir_inst),
204 .typeof => try sema.zirTypeof(block, zir_inst),
205 .typeof_peer => try sema.zirTypeofPeer(block, zir_inst),
206 .optional_type => try sema.zirOptionalType(block, zir_inst),
207 .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, zir_inst),
208 .optional_payload_safe => try sema.zirOptionalPayload(block, zir_inst, true),
209 .optional_payload_unsafe => try sema.zirOptionalPayload(block, zir_inst, false),
210 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, true),
211 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, false),
212 .err_union_payload_safe => try sema.zirErrUnionPayload(block, zir_inst, true),
213 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, zir_inst, false),
214 .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, true),
215 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, false),
216 .err_union_code => try sema.zirErrUnionCode(block, zir_inst),
217 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, zir_inst),
218 .ensure_err_payload_void => try sema.zirEnsureErrPayloadVoid(block, zir_inst),
219 .array_type => try sema.zirArrayType(block, zir_inst),
220 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, zir_inst),
221 .enum_literal => try sema.zirEnumLiteral(block, zir_inst),
222 .merge_error_sets => try sema.zirMergeErrorSets(block, zir_inst),
223 .error_union_type => try sema.zirErrorUnionType(block, zir_inst),
224 .anyframe_type => try sema.zirAnyframeType(block, zir_inst),
225 .error_set => try sema.zirErrorSet(block, zir_inst),
226 .error_value => try sema.zirErrorValue(block, zir_inst),
227 .slice_start => try sema.zirSliceStart(block, zir_inst),
228 .slice_end => try sema.zirSliceEnd(block, zir_inst),
229 .slice_sentinel => try sema.zirSliceSentinel(block, zir_inst),
230 .import => try sema.zirImport(block, zir_inst),
231 .bool_and => try sema.zirBoolOp(block, zir_inst, false),
232 .bool_or => try sema.zirBoolOp(block, zir_inst, true),
233 .void_value => try sema.mod.constVoid(block.arena, .unneeded),
234 .switchbr => try sema.zirSwitchBr(block, zir_inst, false),
235 .switchbr_ref => try sema.zirSwitchBr(block, zir_inst, true),
236 .switch_range => try sema.zirSwitchRange(block, zir_inst),
237 };
238 if (map[zir_inst].ty.isNoReturn()) {
239 break;
240 }
241 }
204242}
205243
206pub fn resolveInst(mod: *Module, scope: *Scope, zir_inst: *zir.Inst) InnerError!*Inst {
207 const block = scope.cast(Scope.Block).?;
208 return block.inst_table.get(zir_inst).?; // Instruction does not dominate all uses!
244fn resolveInst(sema: *Sema, block: *Scope.Block, zir_ref: zir.Inst.Ref) *const ir.Inst {
245 var i = zir_ref;
246
247 // First section of indexes correspond to a set number of constant values.
248 if (i < const_tzir_inst_list.len) {
249 return &const_tzir_inst_list[i];
250 }
251 i -= const_tzir_inst_list.len;
252
253 // Next section of indexes correspond to function parameters, if any.
254 if (block.inlining) |inlining| {
255 if (i < inlining.casted_args.len) {
256 return inlining.casted_args[i];
257 }
258 i -= inlining.casted_args.len;
259 } else {
260 if (i < sema.param_inst_list.len) {
261 return sema.param_inst_list[i];
262 }
263 i -= sema.param_inst_list.len;
264 }
265
266 // Finally, the last section of indexes refers to the map of ZIR=>TZIR.
267 return sema.inst_map[i];
209268}
210269
211fn resolveConstString(mod: *Module, scope: *Scope, old_inst: *zir.Inst) ![]u8 {
212 const new_inst = try resolveInst(mod, scope, old_inst);
270fn resolveConstString(
271 sema: *Sema,
272 block: *Scope.Block,
273 src: LazySrcLoc,
274 zir_ref: zir.Inst.Ref,
275) ![]u8 {
276 const tzir_inst = sema.resolveInst(block, zir_ref);
213277 const wanted_type = Type.initTag(.const_slice_u8);
214 const coerced_inst = try mod.coerce(scope, wanted_type, new_inst);
215 const val = try mod.resolveConstValue(scope, coerced_inst);
216 return val.toAllocatedBytes(scope.arena());
278 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
279 const val = try sema.resolveConstValue(block, src, coerced_inst);
280 return val.toAllocatedBytes(block.arena);
217281}
218282
219fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {
220 const new_inst = try resolveInst(mod, scope, old_inst);
283fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.Inst.Ref) !Type {
284 const tzir_inst = sema.resolveInt(block, zir_ref);
221285 const wanted_type = Type.initTag(.@"type");
222 const coerced_inst = try mod.coerce(scope, wanted_type, new_inst);
223 const val = try mod.resolveConstValue(scope, coerced_inst);
224 return val.toType(scope.arena());
286 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
287 const val = try sema.resolveConstValue(block, src, coerced_inst);
288 return val.toType(sema.arena);
289}
290
291fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !Value {
292 return (try sema.resolveDefinedValue(block, src, base)) orelse
293 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
294}
295
296fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value {
297 if (base.value()) |val| {
298 if (val.isUndef()) {
299 return sema.mod.fail(&block.base, src, "use of undefined value here causes undefined behavior", .{});
300 }
301 return val;
302 }
303 return null;
225304}
226305
227306/// Appropriate to call when the coercion has already been done by result
228307/// location semantics. Asserts the value fits in the provided `Int` type.
229308/// Only supports `Int` types 64 bits or less.
230309fn resolveAlreadyCoercedInt(
231 mod: *Module,
232 scope: *Scope,
233 old_inst: *zir.Inst,
310 sema: *Sema,
311 block: *Scope.Block,
312 src: LazySrcLoc,
313 zir_ref: zir.Inst.Ref,
234314 comptime Int: type,
235315) !Int {
236316 comptime assert(@typeInfo(Int).Int.bits <= 64);
237 const new_inst = try resolveInst(mod, scope, old_inst);
238 const val = try mod.resolveConstValue(scope, new_inst);
317 const tzir_inst = sema.resolveInst(block, zir_ref);
318 const val = try sema.resolveConstValue(block, src, tzir_inst);
239319 switch (@typeInfo(Int).Int.signedness) {
240320 .signed => return @intCast(Int, val.toSignedInt()),
241321 .unsigned => return @intCast(Int, val.toUnsignedInt()),
242322 }
243323}
244324
245fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 {
246 const new_inst = try resolveInst(mod, scope, old_inst);
247 const coerced = try mod.coerce(scope, dest_type, new_inst);
248 const val = try mod.resolveConstValue(scope, coerced);
325fn resolveInt(
326 sema: *Sema,
327 block: *Scope.Block,
328 src: LazySrcLoc,
329 zir_ref: zir.Inst.Ref,
330 dest_type: Type,
331) !u64 {
332 const tzir_inst = sema.resolveInst(block, zir_ref);
333 const coerced = try sema.coerce(scope, dest_type, tzir_inst);
334 const val = try sema.resolveConstValue(block, src, coerced);
249335
250336 return val.toUnsignedInt();
251337}
252338
253pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
254 const new_inst = try resolveInst(mod, scope, old_inst);
255 const val = try mod.resolveConstValue(scope, new_inst);
339fn resolveInstConst(
340 sema: *Sema,
341 block: *Scope.Block,
342 src: LazySrcLoc,
343 zir_ref: zir.Inst.Ref,
344) InnerError!TypedValue {
345 const tzir_inst = sema.resolveInst(block, zir_ref);
346 const val = try sema.resolveConstValue(block, src, tzir_inst);
256347 return TypedValue{
257 .ty = new_inst.ty,
348 .ty = tzir_inst.ty,
258349 .val = val,
259350 };
260351}
261352
262fn zirConst(mod: *Module, scope: *Scope, const_inst: *zir.Inst.Const) InnerError!*Inst {
353fn zirConst(sema: *Sema, block: *Scope.Block, const_inst: zir.Inst.Index) InnerError!*Inst {
263354 const tracy = trace(@src());
264355 defer tracy.end();
265356 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
266357 // after analysis.
267 const typed_value_copy = try const_inst.positionals.typed_value.copy(scope.arena());
268 return mod.constInst(scope, const_inst.base.src, typed_value_copy);
358 const typed_value_copy = try const_inst.positionals.typed_value.copy(block.arena);
359 return sema.mod.constInst(scope, const_inst.base.src, typed_value_copy);
269360}
270361
271fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {
272 const new_inst = try analyzeInst(mod, scope, old_inst);
273 return TypedValue{
274 .ty = new_inst.ty,
275 .val = try mod.resolveConstValue(scope, new_inst),
276 };
277}
278
279fn zirBitcastRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
362fn zirBitcastRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
280363 const tracy = trace(@src());
281364 defer tracy.end();
282 return mod.fail(scope, inst.base.src, "TODO implement zir_sema.zirBitcastRef", .{});
365 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zir_sema.zirBitcastRef", .{});
283366}
284367
285fn zirBitcastResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
368fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
286369 const tracy = trace(@src());
287370 defer tracy.end();
288 return mod.fail(scope, inst.base.src, "TODO implement zir_sema.zirBitcastResultPtr", .{});
371 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zir_sema.zirBitcastResultPtr", .{});
289372}
290373
291fn zirCoerceResultPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
374fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
292375 const tracy = trace(@src());
293376 defer tracy.end();
294 return mod.fail(scope, inst.base.src, "TODO implement zirCoerceResultPtr", .{});
377 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirCoerceResultPtr", .{});
295378}
296379
297fn zirRetPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
380fn zirRetPtr(sema: *Module, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
298381 const tracy = trace(@src());
299382 defer tracy.end();
300 const b = try mod.requireFunctionBlock(scope, inst.base.src);
301 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
383
384 try sema.requireFunctionBlock(block, inst.base.src);
385 const fn_ty = block.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
302386 const ret_type = fn_ty.fnReturnType();
303 const ptr_type = try mod.simplePtrType(scope, inst.base.src, ret_type, true, .One);
304 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
387 const ptr_type = try sema.mod.simplePtrType(block.arena, ret_type, true, .One);
388 return block.addNoOp(inst.base.src, ptr_type, .alloc);
305389}
306390
307fn zirRef(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
391fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
308392 const tracy = trace(@src());
309393 defer tracy.end();
310394
311 const operand = try resolveInst(mod, scope, inst.positionals.operand);
312 return mod.analyzeRef(scope, inst.base.src, operand);
395 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
396 const operand = sema.resolveInst(block, inst_data.operand);
397 return sema.analyzeRef(block, inst_data.src(), operand);
313398}
314399
315fn zirRetType(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
400fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
316401 const tracy = trace(@src());
317402 defer tracy.end();
318 const b = try mod.requireFunctionBlock(scope, inst.base.src);
403 try sema.requireFunctionBlock(block, inst.base.src);
319404 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
320405 const ret_type = fn_ty.fnReturnType();
321 return mod.constType(scope, inst.base.src, ret_type);
406 return sema.mod.constType(block.arena, inst.base.src, ret_type);
322407}
323408
324fn zirEnsureResultUsed(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
409fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
325410 const tracy = trace(@src());
326411 defer tracy.end();
327 const operand = try resolveInst(mod, scope, inst.positionals.operand);
412
413 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
414 const operand = sema.resolveInst(block, inst_data.operand);
415 const src = inst_data.src();
328416 switch (operand.ty.zigTypeTag()) {
329 .Void, .NoReturn => return mod.constVoid(scope, operand.src),
330 else => return mod.fail(scope, operand.src, "expression value is ignored", .{}),
417 .Void, .NoReturn => return sema.mod.constVoid(block.arena, .unneeded),
418 else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),
331419 }
332420}
333421
334fn zirEnsureResultNonError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
422fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
335423 const tracy = trace(@src());
336424 defer tracy.end();
337 const operand = try resolveInst(mod, scope, inst.positionals.operand);
425
426 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
427 const operand = sema.resolveInst(block, inst_data.operand);
428 const src = inst_data.src();
338429 switch (operand.ty.zigTypeTag()) {
339 .ErrorSet, .ErrorUnion => return mod.fail(scope, operand.src, "error is discarded", .{}),
340 else => return mod.constVoid(scope, operand.src),
430 .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),
431 else => return sema.mod.constVoid(block.arena, .unneeded),
341432 }
342433}
343434
344fn zirIndexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
435fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
345436 const tracy = trace(@src());
346437 defer tracy.end();
347438
348 const array_ptr = try resolveInst(mod, scope, inst.positionals.operand);
439 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
440 const array_ptr = sema.resolveInst(block, inst_data.operand);
441
349442 const elem_ty = array_ptr.ty.elemType();
350443 if (!elem_ty.isIndexable()) {
444 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
351445 const msg = msg: {
352 const msg = try mod.errMsg(
353 scope,
354 inst.base.src,
446 const msg = try sema.mod.errMsg(
447 &block.base,
448 cond_src,
355449 "type '{}' does not support indexing",
356450 .{elem_ty},
357451 );
358452 errdefer msg.destroy(mod.gpa);
359 try mod.errNote(
360 scope,
361 inst.base.src,
453 try sema.mod.errNote(
454 &block.base,
455 cond_src,
362456 msg,
363457 "for loop operand must be an array, slice, tuple, or vector",
364458 .{},
......@@ -367,38 +461,46 @@ fn zirIndexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerEr
367461 };
368462 return mod.failWithOwnedErrorMsg(scope, msg);
369463 }
370 const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, array_ptr, "len", inst.base.src);
371 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
464 const result_ptr = try sema.namedFieldPtr(block, inst.base.src, array_ptr, "len", inst.base.src);
465 return sema.analyzeDeref(block, inst.base.src, result_ptr, result_ptr.src);
372466}
373467
374fn zirAlloc(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
468fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
375469 const tracy = trace(@src());
376470 defer tracy.end();
377 const var_type = try resolveType(mod, scope, inst.positionals.operand);
378 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);
379 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
380 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
471
472 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
473 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
474 const var_decl_src = inst_data.src();
475 const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
476 const ptr_type = try sema.mod.simplePtrType(block.arena, var_type, true, .One);
477 try sema.requireRuntimeBlock(block, var_decl_src);
478 return block.addNoOp(var_decl_src, ptr_type, .alloc);
381479}
382480
383fn zirAllocMut(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
481fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
384482 const tracy = trace(@src());
385483 defer tracy.end();
386 const var_type = try resolveType(mod, scope, inst.positionals.operand);
387 try mod.validateVarType(scope, inst.base.src, var_type);
388 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);
389 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
390 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);
484
485 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
486 const var_decl_src = inst_data.src();
487 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
488 const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
489 try sema.validateVarType(block, ty_src, var_type);
490 const ptr_type = try sema.mod.simplePtrType(block.arena, var_type, true, .One);
491 try sema.requireRuntimeBlock(block, var_decl_src);
492 return block.addNoOp(var_decl_src, ptr_type, .alloc);
391493}
392494
393495fn zirAllocInferred(
394 mod: *Module,
395 scope: *Scope,
396 inst: *zir.Inst.NoOp,
397 mut_tag: Type.Tag,
496 sema: *Sema,
497 block: *Scope.Block,
498 inst: zir.Inst.Index,
499 inferred_alloc_ty: Type,
398500) InnerError!*Inst {
399501 const tracy = trace(@src());
400502 defer tracy.end();
401 const val_payload = try scope.arena().create(Value.Payload.InferredAlloc);
503 const val_payload = try block.arena.create(Value.Payload.InferredAlloc);
402504 val_payload.* = .{
403505 .data = .{},
404506 };
......@@ -406,193 +508,197 @@ fn zirAllocInferred(
406508 // not needed in the case of constant values. However here, we plan to "downgrade"
407509 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
408510 // to the block even though it is currently a `.constant`.
409 const result = try mod.constInst(scope, inst.base.src, .{
410 .ty = switch (mut_tag) {
411 .inferred_alloc_const => Type.initTag(.inferred_alloc_const),
412 .inferred_alloc_mut => Type.initTag(.inferred_alloc_mut),
413 else => unreachable,
414 },
511 const result = try sema.mod.constInst(scope, inst.base.src, .{
512 .ty = inferred_alloc_ty,
415513 .val = Value.initPayload(&val_payload.base),
416514 });
417 const block = try mod.requireFunctionBlock(scope, inst.base.src);
418 try block.instructions.append(mod.gpa, result);
515 try sema.requireFunctionBlock(block, inst.base.src);
516 try block.instructions.append(sema.gpa, result);
419517 return result;
420518}
421519
422520fn zirResolveInferredAlloc(
423 mod: *Module,
424 scope: *Scope,
425 inst: *zir.Inst.UnOp,
521 sema: *Sema,
522 block: *Scope.Block,
523 inst: zir.Inst.Index,
426524) InnerError!*Inst {
427525 const tracy = trace(@src());
428526 defer tracy.end();
429 const ptr = try resolveInst(mod, scope, inst.positionals.operand);
527
528 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
529 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
530 const ptr = sema.resolveInst(block, inst_data.operand);
430531 const ptr_val = ptr.castTag(.constant).?.val;
431532 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
432533 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
433 const final_elem_ty = try mod.resolvePeerTypes(scope, peer_inst_list);
534 const final_elem_ty = try sema.resolvePeerTypes(block, peer_inst_list);
434535 const var_is_mut = switch (ptr.ty.tag()) {
435536 .inferred_alloc_const => false,
436537 .inferred_alloc_mut => true,
437538 else => unreachable,
438539 };
439540 if (var_is_mut) {
440 try mod.validateVarType(scope, inst.base.src, final_elem_ty);
541 try sema.validateVarType(block, ty_src, final_elem_ty);
441542 }
442 const final_ptr_ty = try mod.simplePtrType(scope, inst.base.src, final_elem_ty, true, .One);
543 const final_ptr_ty = try sema.mod.simplePtrType(block.arena, final_elem_ty, true, .One);
443544
444545 // Change it to a normal alloc.
445546 ptr.ty = final_ptr_ty;
446547 ptr.tag = .alloc;
447548
448 return mod.constVoid(scope, inst.base.src);
549 return sema.mod.constVoid(block.arena, .unneeded);
449550}
450551
451552fn zirStoreToBlockPtr(
452 mod: *Module,
453 scope: *Scope,
454 inst: *zir.Inst.BinOp,
553 sema: *Sema,
554 block: *Scope.Block,
555 inst: zir.Inst.Index,
455556) InnerError!*Inst {
456557 const tracy = trace(@src());
457558 defer tracy.end();
458559
459 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);
460 const value = try resolveInst(mod, scope, inst.positionals.rhs);
461 const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One);
560 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
561 const ptr = sema.resolveInst(bin_inst.lhs);
562 const value = sema.resolveInst(bin_inst.rhs);
563 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
462564 // TODO detect when this store should be done at compile-time. For example,
463565 // if expressions should force it when the condition is compile-time known.
464 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
465 const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr);
566 try sema.requireRuntimeBlock(block, src);
567 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
466568 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
467569}
468570
469571fn zirStoreToInferredPtr(
470 mod: *Module,
471 scope: *Scope,
472 inst: *zir.Inst.BinOp,
572 sema: *Sema,
573 block: *Scope.Block,
574 inst: zir.Inst.Index,
473575) InnerError!*Inst {
474576 const tracy = trace(@src());
475577 defer tracy.end();
476578
477 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);
478 const value = try resolveInst(mod, scope, inst.positionals.rhs);
579 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
580 const ptr = sema.resolveInst(bin_inst.lhs);
581 const value = sema.resolveInst(bin_inst.rhs);
479582 const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;
480583 // Add the stored instruction to the set we will use to resolve peer types
481584 // for the inferred allocation.
482 try inferred_alloc.data.stored_inst_list.append(scope.arena(), value);
585 try inferred_alloc.data.stored_inst_list.append(block.arena, value);
483586 // Create a runtime bitcast instruction with exactly the type the pointer wants.
484 const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One);
485 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
486 const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr);
587 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
588 try sema.requireRuntimeBlock(block, src);
589 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
487590 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
488591}
489592
490593fn zirSetEvalBranchQuota(
491 mod: *Module,
492 scope: *Scope,
493 inst: *zir.Inst.UnOp,
594 sema: *Sema,
595 block: *Scope.Block,
596 inst: zir.Inst.Index,
494597) InnerError!*Inst {
495 const b = try mod.requireFunctionBlock(scope, inst.base.src);
496 const quota = try resolveAlreadyCoercedInt(mod, scope, inst.positionals.operand, u32);
598 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
599 const src = inst_data.src();
600 try sema.requireFunctionBlock(block, src);
601 const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);
497602 if (b.branch_quota.* < quota)
498603 b.branch_quota.* = quota;
499 return mod.constVoid(scope, inst.base.src);
604 return sema.mod.constVoid(block.arena, .unneeded);
500605}
501606
502fn zirStore(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
607fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
503608 const tracy = trace(@src());
504609 defer tracy.end();
505610
506 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);
507 const value = try resolveInst(mod, scope, inst.positionals.rhs);
611 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
612 const ptr = sema.resolveInst(bin_inst.lhs);
613 const value = sema.resolveInst(bin_inst.rhs);
508614 return mod.storePtr(scope, inst.base.src, ptr, value);
509615}
510616
511fn zirParamType(mod: *Module, scope: *Scope, inst: *zir.Inst.ParamType) InnerError!*Inst {
617fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
512618 const tracy = trace(@src());
513619 defer tracy.end();
514 const fn_inst = try resolveInst(mod, scope, inst.positionals.func);
515 const arg_index = inst.positionals.arg_index;
620
621 const inst_data = sema.code.instructions.items(.data)[inst].param_type;
622 const fn_inst = sema.resolveInst(inst_data.callee);
623 const param_index = inst_data.param_index;
516624
517625 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
518626 .Fn => fn_inst.ty,
519627 .BoundFn => {
520 return mod.fail(scope, fn_inst.src, "TODO implement zirParamType for method call syntax", .{});
628 return sema.mod.fail(&block.base, fn_inst.src, "TODO implement zirParamType for method call syntax", .{});
521629 },
522630 else => {
523 return mod.fail(scope, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
631 return sema.mod.fail(&block.base, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
524632 },
525633 };
526634
527635 const param_count = fn_ty.fnParamLen();
528 if (arg_index >= param_count) {
636 if (param_index >= param_count) {
529637 if (fn_ty.fnIsVarArgs()) {
530 return mod.constType(scope, inst.base.src, Type.initTag(.var_args_param));
638 return sema.mod.constType(block.arena, inst.base.src, Type.initTag(.var_args_param));
531639 }
532 return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
533 arg_index,
640 return sema.mod.fail(&block.base, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
641 param_index,
534642 fn_ty,
535643 param_count,
536644 });
537645 }
538646
539647 // TODO support generic functions
540 const param_type = fn_ty.fnParamType(arg_index);
541 return mod.constType(scope, inst.base.src, param_type);
648 const param_type = fn_ty.fnParamType(param_index);
649 return sema.mod.constType(block.arena, inst.base.src, param_type);
542650}
543651
544fn zirStr(mod: *Module, scope: *Scope, str_inst: *zir.Inst.Str) InnerError!*Inst {
652fn zirStr(sema: *Sema, block: *Scope.Block, str_inst: zir.Inst.Index) InnerError!*Inst {
545653 const tracy = trace(@src());
546654 defer tracy.end();
547 // The bytes references memory inside the ZIR module, which can get deallocated
548 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.
549 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
655
656 // The bytes references memory inside the ZIR module, which is fine. Multiple
657 // anonymous Decls may have strings which point to within the same ZIR module.
658 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
659
660 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
550661 errdefer new_decl_arena.deinit();
551 const arena_bytes = try new_decl_arena.allocator.dupe(u8, str_inst.positionals.bytes);
552662
553 const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, arena_bytes.len);
554 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, arena_bytes);
663 const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
664 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes);
555665
556 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
666 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
557667 .ty = decl_ty,
558668 .val = decl_val,
559669 });
560 return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl);
670 return sema.analyzeDeclRef(block, .unneeded, new_decl);
561671}
562672
563fn zirInt(mod: *Module, scope: *Scope, inst: *zir.Inst.Int) InnerError!*Inst {
673fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
564674 const tracy = trace(@src());
565675 defer tracy.end();
566676
567677 return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int);
568678}
569679
570fn zirExport(mod: *Module, scope: *Scope, export_inst: *zir.Inst.Export) InnerError!*Inst {
680fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
571681 const tracy = trace(@src());
572682 defer tracy.end();
573 const symbol_name = try resolveConstString(mod, scope, export_inst.positionals.symbol_name);
574 const exported_decl = mod.lookupDeclName(scope, export_inst.positionals.decl_name) orelse
575 return mod.fail(scope, export_inst.base.src, "decl '{s}' not found", .{export_inst.positionals.decl_name});
576 try mod.analyzeExport(scope, export_inst.base.src, symbol_name, exported_decl);
577 return mod.constVoid(scope, export_inst.base.src);
578}
579683
580fn zirCompileError(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
581 const tracy = trace(@src());
582 defer tracy.end();
583 const msg = try resolveConstString(mod, scope, inst.positionals.operand);
584 return mod.fail(scope, inst.base.src, "{s}", .{msg});
684 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
685 const src = inst_data.src();
686 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
687 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand);
688 return sema.mod.fail(&block.base, src, "{s}", .{msg});
585689}
586690
587fn zirCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerError!*Inst {
691fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
588692 var managed = mod.compile_log_text.toManaged(mod.gpa);
589693 defer mod.compile_log_text = managed.moveToUnmanaged();
590694 const writer = managed.writer();
591695
592 for (inst.positionals.to_log) |arg_inst, i| {
696 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
697 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
698 for (sema.code.extra[extra.end..][0..extra.data.operands_len]) |arg_ref, i| {
593699 if (i != 0) try writer.print(", ", .{});
594700
595 const arg = try resolveInst(mod, scope, arg_inst);
701 const arg = sema.resolveInst(block, arg_ref);
596702 if (arg.value()) |val| {
597703 try writer.print("@as({}, {})", .{ arg.ty, val });
598704 } else {
......@@ -604,40 +710,16 @@ fn zirCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerE
604710 const gop = try mod.compile_log_decls.getOrPut(mod.gpa, scope.ownerDecl().?);
605711 if (!gop.found_existing) {
606712 gop.entry.value = .{
607 .file_scope = scope.getFileScope(),
608 .byte_offset = inst.base.src,
713 .file_scope = block.getFileScope(),
714 .lazy = inst_data.src(),
609715 };
610716 }
611 return mod.constVoid(scope, inst.base.src);
717 return sema.mod.constVoid(block.arena, .unneeded);
612718}
613719
614fn zirArg(mod: *Module, scope: *Scope, inst: *zir.Inst.Arg) InnerError!*Inst {
720fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
615721 const tracy = trace(@src());
616722 defer tracy.end();
617 const b = try mod.requireFunctionBlock(scope, inst.base.src);
618 if (b.inlining) |inlining| {
619 const param_index = inlining.param_index;
620 inlining.param_index += 1;
621 return inlining.casted_args[param_index];
622 }
623 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
624 const param_index = b.instructions.items.len;
625 const param_count = fn_ty.fnParamLen();
626 if (param_index >= param_count) {
627 return mod.fail(scope, inst.base.src, "parameter index {d} outside list of length {d}", .{
628 param_index,
629 param_count,
630 });
631 }
632 const param_type = fn_ty.fnParamType(param_index);
633 const name = try scope.arena().dupeZ(u8, inst.positionals.name);
634 return mod.addArg(b, inst.base.src, param_type, name);
635}
636
637fn zirLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
638 const tracy = trace(@src());
639 defer tracy.end();
640 const parent_block = scope.cast(Scope.Block).?;
641723
642724 // Reserve space for a Loop instruction so that generated Break instructions can
643725 // point to it, even if it doesn't end up getting used because the code ends up being
......@@ -666,7 +748,7 @@ fn zirLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
666748 };
667749 defer child_block.instructions.deinit(mod.gpa);
668750
669 try analyzeBody(mod, &child_block, inst.positionals.body);
751 try sema.body(&child_block, inst.positionals.body);
670752
671753 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
672754
......@@ -675,16 +757,15 @@ fn zirLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
675757 return &loop_inst.base;
676758}
677759
678fn zirBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime: bool) InnerError!*Inst {
760fn zirBlockFlat(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index, is_comptime: bool) InnerError!*Inst {
679761 const tracy = trace(@src());
680762 defer tracy.end();
681 const parent_block = scope.cast(Scope.Block).?;
682763
683764 var child_block = parent_block.makeSubBlock();
684765 defer child_block.instructions.deinit(mod.gpa);
685766 child_block.is_comptime = child_block.is_comptime or is_comptime;
686767
687 try analyzeBody(mod, &child_block, inst.positionals.body);
768 try sema.body(&child_block, inst.positionals.body);
688769
689770 // Move the analyzed instructions into the parent block arena.
690771 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
......@@ -693,20 +774,18 @@ fn zirBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime:
693774 // The result of a flat block is the last instruction.
694775 const zir_inst_list = inst.positionals.body.instructions;
695776 const last_zir_inst = zir_inst_list[zir_inst_list.len - 1];
696 return resolveInst(mod, scope, last_zir_inst);
777 return sema.inst_map[last_zir_inst];
697778}
698779
699780fn zirBlock(
700 mod: *Module,
701 scope: *Scope,
702 inst: *zir.Inst.Block,
781 sema: *Sema,
782 parent_block: *Scope.Block,
783 inst: zir.Inst.Index,
703784 is_comptime: bool,
704785) InnerError!*Inst {
705786 const tracy = trace(@src());
706787 defer tracy.end();
707788
708 const parent_block = scope.cast(Scope.Block).?;
709
710789 // Reserve space for a Block instruction so that generated Break instructions can
711790 // point to it, even if it doesn't end up getting used because the code ends up being
712791 // comptime evaluated.
......@@ -747,22 +826,20 @@ fn zirBlock(
747826 defer merges.results.deinit(mod.gpa);
748827 defer merges.br_list.deinit(mod.gpa);
749828
750 try analyzeBody(mod, &child_block, inst.positionals.body);
829 try sema.body(&child_block, inst.positionals.body);
751830
752831 return analyzeBlockBody(mod, scope, &child_block, merges);
753832}
754833
755834fn analyzeBlockBody(
756 mod: *Module,
757 scope: *Scope,
835 sema: *Sema,
836 parent_block: *Scope.Block,
758837 child_block: *Scope.Block,
759838 merges: *Scope.Block.Merges,
760839) InnerError!*Inst {
761840 const tracy = trace(@src());
762841 defer tracy.end();
763842
764 const parent_block = scope.cast(Scope.Block).?;
765
766843 // Blocks must terminate with noreturn instruction.
767844 assert(child_block.instructions.items.len != 0);
768845 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
......@@ -793,7 +870,7 @@ fn analyzeBlockBody(
793870 // Need to set the type and emit the Block instruction. This allows machine code generation
794871 // to emit a jump instruction to after the block when it encounters the break.
795872 try parent_block.instructions.append(mod.gpa, &merges.block_inst.base);
796 const resolved_ty = try mod.resolvePeerTypes(scope, merges.results.items);
873 const resolved_ty = try sema.resolvePeerTypes(parent_block, merges.results.items);
797874 merges.block_inst.base.ty = resolved_ty;
798875 merges.block_inst.body = .{
799876 .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items),
......@@ -807,7 +884,7 @@ fn analyzeBlockBody(
807884 }
808885 var coerce_block = parent_block.makeSubBlock();
809886 defer coerce_block.instructions.deinit(mod.gpa);
810 const coerced_operand = try mod.coerce(&coerce_block.base, resolved_ty, br.operand);
887 const coerced_operand = try sema.coerce(&coerce_block.base, resolved_ty, br.operand);
811888 // If no instructions were produced, such as in the case of a coercion of a
812889 // constant value to a new type, we can simply point the br operand to it.
813890 if (coerce_block.instructions.items.len == 0) {
......@@ -835,43 +912,46 @@ fn analyzeBlockBody(
835912 return &merges.block_inst.base;
836913}
837914
838fn zirBreakpoint(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
915fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
839916 const tracy = trace(@src());
840917 defer tracy.end();
841 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
842 return mod.addNoOp(b, inst.base.src, Type.initTag(.void), .breakpoint);
918
919 try sema.requireRuntimeBlock(block, src);
920 return block.addNoOp(inst.base.src, Type.initTag(.void), .breakpoint);
843921}
844922
845fn zirBreak(mod: *Module, scope: *Scope, inst: *zir.Inst.Break) InnerError!*Inst {
923fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
846924 const tracy = trace(@src());
847925 defer tracy.end();
848926
849 const operand = try resolveInst(mod, scope, inst.positionals.operand);
850 const block = inst.positionals.block;
851 return analyzeBreak(mod, scope, inst.base.src, block, operand);
927 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
928 const operand = sema.resolveInst(block, bin_inst.rhs);
929 const zir_block = bin_inst.lhs;
930 return analyzeBreak(mod, block, sema.src, zir_block, operand);
852931}
853932
854fn zirBreakVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.BreakVoid) InnerError!*Inst {
933fn zirBreakVoidTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
855934 const tracy = trace(@src());
856935 defer tracy.end();
857936
858 const block = inst.positionals.block;
859 const void_inst = try mod.constVoid(scope, inst.base.src);
860 return analyzeBreak(mod, scope, inst.base.src, block, void_inst);
937 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
938 const zir_block = inst_data.operand;
939 const void_inst = try sema.mod.constVoid(block.arena, .unneeded);
940 return analyzeBreak(mod, block, inst_data.src(), zir_block, void_inst);
861941}
862942
863943fn analyzeBreak(
864 mod: *Module,
865 scope: *Scope,
866 src: usize,
867 zir_block: *zir.Inst.Block,
944 sema: *Sema,
945 block: *Scope.Block,
946 src: LazySrcLoc,
947 zir_block: zir.Inst.Index,
868948 operand: *Inst,
869949) InnerError!*Inst {
870950 var opt_block = scope.cast(Scope.Block);
871951 while (opt_block) |block| {
872952 if (block.label) |*label| {
873953 if (label.zir_block == zir_block) {
874 const b = try mod.requireFunctionBlock(scope, src);
954 try sema.requireFunctionBlock(block, src);
875955 // Here we add a br instruction, but we over-allocate a little bit
876956 // (if necessary) to make it possible to convert the instruction into
877957 // a br_block_flat instruction later.
......@@ -899,102 +979,134 @@ fn analyzeBreak(
899979 } else unreachable;
900980}
901981
902fn zirDbgStmt(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
982fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
903983 const tracy = trace(@src());
904984 defer tracy.end();
905 if (scope.cast(Scope.Block)) |b| {
906 if (!b.is_comptime) {
907 return mod.addNoOp(b, inst.base.src, Type.initTag(.void), .dbg_stmt);
908 }
985
986 if (b.is_comptime) {
987 return sema.mod.constVoid(block.arena, .unneeded);
909988 }
910 return mod.constVoid(scope, inst.base.src);
989
990 const src_node = sema.code.instructions.items(.data)[inst].node;
991 const src: LazySrcLoc = .{ .node_offset = src_node };
992 return block.addNoOp(src, Type.initTag(.void), .dbg_stmt);
911993}
912994
913fn zirDeclRefStr(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRefStr) InnerError!*Inst {
995fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
914996 const tracy = trace(@src());
915997 defer tracy.end();
916 const decl_name = try resolveConstString(mod, scope, inst.positionals.name);
917 return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name);
998
999 const decl = sema.code.instructions.items(.data)[inst].decl;
1000 return sema.analyzeDeclRef(block, .unneeded, decl);
9181001}
9191002
920fn zirDeclRef(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclRef) InnerError!*Inst {
1003fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
9211004 const tracy = trace(@src());
9221005 defer tracy.end();
923 return mod.analyzeDeclRef(scope, inst.base.src, inst.positionals.decl);
1006
1007 const decl = sema.code.instructions.items(.data)[inst].decl;
1008 return sema.analyzeDeclVal(block, .unneeded, decl);
9241009}
9251010
926fn zirDeclVal(mod: *Module, scope: *Scope, inst: *zir.Inst.DeclVal) InnerError!*Inst {
1011fn zirCallNone(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
9271012 const tracy = trace(@src());
9281013 defer tracy.end();
929 return mod.analyzeDeclVal(scope, inst.base.src, inst.positionals.decl);
1014
1015 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1016 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
1017
1018 return sema.analyzeCall(block, inst_data.operand, func_src, inst_data.src(), .auto, &.{});
9301019}
9311020
932fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
1021fn zirCall(
1022 sema: *Sema,
1023 block: *Scope.Block,
1024 inst: zir.Inst.Index,
1025 modifier: std.builtin.CallOptions.Modifier,
1026) InnerError!*Inst {
9331027 const tracy = trace(@src());
9341028 defer tracy.end();
9351029
936 const func = try resolveInst(mod, scope, inst.positionals.func);
1030 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1031 const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
1032 const call_src = inst_data.src();
1033 const extra = sema.code.extraData(zir.Inst.Call, inst_data.payload_index);
1034 const args = sema.code.extra[extra.end..][0..extra.data.args_len];
1035
1036 return sema.analyzeCall(block, extra.data.callee, func_src, call_src, modifier, args);
1037}
1038
1039fn analyzeCall(
1040 sema: *Sema,
1041 block: *Scope.Block,
1042 zir_func: zir.Inst.Ref,
1043 func_src: LazySrcLoc,
1044 call_src: LazySrcLoc,
1045 modifier: std.builtin.CallOptions.Modifier,
1046 zir_args: []const Ref,
1047) InnerError!*ir.Inst {
1048 const func = sema.resolveInst(zir_func);
1049
9371050 if (func.ty.zigTypeTag() != .Fn)
938 return mod.fail(scope, inst.positionals.func.src, "type '{}' not a function", .{func.ty});
1051 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
9391052
9401053 const cc = func.ty.fnCallingConvention();
9411054 if (cc == .Naked) {
9421055 // TODO add error note: declared here
943 return mod.fail(
944 scope,
945 inst.positionals.func.src,
1056 return sema.mod.fail(
1057 &block.base,
1058 func_src,
9461059 "unable to call function with naked calling convention",
9471060 .{},
9481061 );
9491062 }
950 const call_params_len = inst.positionals.args.len;
9511063 const fn_params_len = func.ty.fnParamLen();
9521064 if (func.ty.fnIsVarArgs()) {
9531065 assert(cc == .C);
954 if (call_params_len < fn_params_len) {
1066 if (zir_args.len < fn_params_len) {
9551067 // TODO add error note: declared here
956 return mod.fail(
957 scope,
958 inst.positionals.func.src,
1068 return sema.mod.fail(
1069 &block.base,
1070 func_src,
9591071 "expected at least {d} argument(s), found {d}",
960 .{ fn_params_len, call_params_len },
1072 .{ fn_params_len, zir_args.len },
9611073 );
9621074 }
963 } else if (fn_params_len != call_params_len) {
1075 } else if (fn_params_len != zir_args.len) {
9641076 // TODO add error note: declared here
965 return mod.fail(
966 scope,
967 inst.positionals.func.src,
1077 return sema.mod.fail(
1078 &block.base,
1079 func_src,
9681080 "expected {d} argument(s), found {d}",
969 .{ fn_params_len, call_params_len },
1081 .{ fn_params_len, zir_args.len },
9701082 );
9711083 }
9721084
973 if (inst.positionals.modifier == .compile_time) {
974 return mod.fail(scope, inst.base.src, "TODO implement comptime function calls", .{});
1085 if (modifier == .compile_time) {
1086 return sema.mod.fail(&block.base, call_src, "TODO implement comptime function calls", .{});
9751087 }
976 if (inst.positionals.modifier != .auto) {
977 return mod.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.positionals.modifier});
1088 if (modifier != .auto) {
1089 return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{inst.positionals.modifier});
9781090 }
9791091
9801092 // TODO handle function calls of generic functions
981 const casted_args = try scope.arena().alloc(*Inst, call_params_len);
982 for (inst.positionals.args) |src_arg, i| {
1093 const casted_args = try block.arena.alloc(*Inst, zir_args.len);
1094 for (zir_args) |zir_arg, i| {
9831095 // the args are already casted to the result of a param type instruction.
984 casted_args[i] = try resolveInst(mod, scope, src_arg);
1096 casted_args[i] = sema.resolveInst(block, zir_arg);
9851097 }
9861098
9871099 const ret_type = func.ty.fnReturnType();
9881100
989 const b = try mod.requireFunctionBlock(scope, inst.base.src);
990 const is_comptime_call = b.is_comptime or inst.positionals.modifier == .compile_time;
991 const is_inline_call = is_comptime_call or inst.positionals.modifier == .always_inline or
1101 try sema.requireFunctionBlock(block, call_src);
1102 const is_comptime_call = b.is_comptime or modifier == .compile_time;
1103 const is_inline_call = is_comptime_call or modifier == .always_inline or
9921104 func.ty.fnCallingConvention() == .Inline;
9931105 if (is_inline_call) {
994 const func_val = try mod.resolveConstValue(scope, func);
1106 const func_val = try sema.resolveConstValue(block, func_src, func);
9951107 const module_fn = switch (func_val.tag()) {
9961108 .function => func_val.castTag(.function).?.data,
997 .extern_fn => return mod.fail(scope, inst.base.src, "{s} call of extern function", .{
1109 .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{
9981110 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
9991111 }),
10001112 else => unreachable,
......@@ -1005,24 +1117,24 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
10051117 // set to in the `Scope.Block`.
10061118 // This block instruction will be used to capture the return value from the
10071119 // inlined function.
1008 const block_inst = try scope.arena().create(Inst.Block);
1120 const block_inst = try block.arena.create(Inst.Block);
10091121 block_inst.* = .{
10101122 .base = .{
10111123 .tag = Inst.Block.base_tag,
10121124 .ty = ret_type,
1013 .src = inst.base.src,
1125 .src = call_src,
10141126 },
10151127 .body = undefined,
10161128 };
10171129 // If this is the top of the inline/comptime call stack, we use this data.
10181130 // Otherwise we pass on the shared data from the parent scope.
1019 var shared_inlining = Scope.Block.Inlining.Shared{
1131 var shared_inlining: Scope.Block.Inlining.Shared = .{
10201132 .branch_count = 0,
10211133 .caller = b.func,
10221134 };
10231135 // This one is shared among sub-blocks within the same callee, but not
10241136 // shared among the entire inline/comptime call stack.
1025 var inlining = Scope.Block.Inlining{
1137 var inlining: Scope.Block.Inlining = .{
10261138 .shared = if (b.inlining) |inlining| inlining.shared else &shared_inlining,
10271139 .param_index = 0,
10281140 .casted_args = casted_args,
......@@ -1042,7 +1154,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
10421154 .owner_decl = scope.ownerDecl().?,
10431155 .src_decl = module_fn.owner_decl,
10441156 .instructions = .{},
1045 .arena = scope.arena(),
1157 .arena = block.arena,
10461158 .label = null,
10471159 .inlining = &inlining,
10481160 .is_comptime = is_comptime_call,
......@@ -1055,121 +1167,101 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
10551167 defer merges.results.deinit(mod.gpa);
10561168 defer merges.br_list.deinit(mod.gpa);
10571169
1058 try mod.emitBackwardBranch(&child_block, inst.base.src);
1170 try mod.emitBackwardBranch(&child_block, call_src);
10591171
10601172 // This will have return instructions analyzed as break instructions to
10611173 // the block_inst above.
1062 try analyzeBody(mod, &child_block, module_fn.zir);
1174 try sema.body(&child_block, module_fn.zir);
10631175
10641176 return analyzeBlockBody(mod, scope, &child_block, merges);
10651177 }
10661178
1067 return mod.addCall(b, inst.base.src, ret_type, func, casted_args);
1179 return block.addCall(call_src, ret_type, func, casted_args);
10681180}
10691181
1070fn zirFn(mod: *Module, scope: *Scope, fn_inst: *zir.Inst.Fn) InnerError!*Inst {
1182fn zirIntType(sema: *Sema, block: *Scope.Block, inttype: zir.Inst.Index) InnerError!*Inst {
10711183 const tracy = trace(@src());
10721184 defer tracy.end();
1073 const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type);
1074 const new_func = try scope.arena().create(Module.Fn);
1075 new_func.* = .{
1076 .state = if (fn_type.fnCallingConvention() == .Inline) .inline_only else .queued,
1077 .zir = fn_inst.positionals.body,
1078 .body = undefined,
1079 .owner_decl = scope.ownerDecl().?,
1080 };
1081 return mod.constInst(scope, fn_inst.base.src, .{
1082 .ty = fn_type,
1083 .val = try Value.Tag.function.create(scope.arena(), new_func),
1084 });
1085}
1086
1087fn zirAwait(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1088 return mod.fail(scope, inst.base.src, "TODO implement await", .{});
1089}
1090
1091fn zirResume(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1092 return mod.fail(scope, inst.base.src, "TODO implement resume", .{});
1093}
1094
1095fn zirSuspend(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
1096 return mod.fail(scope, inst.base.src, "TODO implement suspend", .{});
1097}
1098
1099fn zirSuspendBlock(mod: *Module, scope: *Scope, inst: *zir.Inst.Block) InnerError!*Inst {
1100 return mod.fail(scope, inst.base.src, "TODO implement suspend", .{});
1185 return sema.mod.fail(&block.base, inttype.base.src, "TODO implement inttype", .{});
11011186}
11021187
1103fn zirIntType(mod: *Module, scope: *Scope, inttype: *zir.Inst.IntType) InnerError!*Inst {
1188fn zirOptionalType(sema: *Sema, block: *Scope.Block, optional: zir.Inst.Index) InnerError!*Inst {
11041189 const tracy = trace(@src());
11051190 defer tracy.end();
1106 return mod.fail(scope, inttype.base.src, "TODO implement inttype", .{});
1107}
11081191
1109fn zirOptionalType(mod: *Module, scope: *Scope, optional: *zir.Inst.UnOp) InnerError!*Inst {
1110 const tracy = trace(@src());
1111 defer tracy.end();
1112 const child_type = try resolveType(mod, scope, optional.positionals.operand);
1192 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1193 const child_type = try sema.resolveType(block, inst_data.operand);
1194 const opt_type = try mod.optionalType(block.arena, child_type);
11131195
1114 return mod.constType(scope, optional.base.src, try mod.optionalType(scope, child_type));
1196 return sema.mod.constType(block.arena, inst_data.src(), opt_type);
11151197}
11161198
1117fn zirOptionalTypeFromPtrElem(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1199fn zirOptionalTypeFromPtrElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
11181200 const tracy = trace(@src());
11191201 defer tracy.end();
11201202
1121 const ptr = try resolveInst(mod, scope, inst.positionals.operand);
1203 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1204 const ptr = sema.resolveInst(block, inst_data.operand);
11221205 const elem_ty = ptr.ty.elemType();
1206 const opt_ty = try mod.optionalType(block.arena, elem_ty);
11231207
1124 return mod.constType(scope, inst.base.src, try mod.optionalType(scope, elem_ty));
1208 return sema.mod.constType(block.arena, inst_data.src(), opt_ty);
11251209}
11261210
1127fn zirArrayType(mod: *Module, scope: *Scope, array: *zir.Inst.BinOp) InnerError!*Inst {
1211fn zirArrayType(sema: *Sema, block: *Scope.Block, array: zir.Inst.Index) InnerError!*Inst {
11281212 const tracy = trace(@src());
11291213 defer tracy.end();
11301214 // TODO these should be lazily evaluated
11311215 const len = try resolveInstConst(mod, scope, array.positionals.lhs);
1132 const elem_type = try resolveType(mod, scope, array.positionals.rhs);
1216 const elem_type = try sema.resolveType(block, array.positionals.rhs);
11331217
1134 return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
1218 return sema.mod.constType(block.arena, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
11351219}
11361220
1137fn zirArrayTypeSentinel(mod: *Module, scope: *Scope, array: *zir.Inst.ArrayTypeSentinel) InnerError!*Inst {
1221fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, array: zir.Inst.Index) InnerError!*Inst {
11381222 const tracy = trace(@src());
11391223 defer tracy.end();
11401224 // TODO these should be lazily evaluated
11411225 const len = try resolveInstConst(mod, scope, array.positionals.len);
11421226 const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
1143 const elem_type = try resolveType(mod, scope, array.positionals.elem_type);
1227 const elem_type = try sema.resolveType(block, array.positionals.elem_type);
11441228
1145 return mod.constType(scope, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
1229 return sema.mod.constType(block.arena, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
11461230}
11471231
1148fn zirErrorUnionType(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1232fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
11491233 const tracy = trace(@src());
11501234 defer tracy.end();
1151 const error_union = try resolveType(mod, scope, inst.positionals.lhs);
1152 const payload = try resolveType(mod, scope, inst.positionals.rhs);
1235
1236 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1237 const error_union = try sema.resolveType(block, bin_inst.lhs);
1238 const payload = try sema.resolveType(block, bin_inst.rhs);
11531239
11541240 if (error_union.zigTypeTag() != .ErrorSet) {
1155 return mod.fail(scope, inst.base.src, "expected error set type, found {}", .{error_union.elemType()});
1241 return sema.mod.fail(&block.base, inst.base.src, "expected error set type, found {}", .{error_union.elemType()});
11561242 }
11571243
1158 return mod.constType(scope, inst.base.src, try mod.errorUnionType(scope, error_union, payload));
1244 return sema.mod.constType(block.arena, inst.base.src, try mod.errorUnionType(scope, error_union, payload));
11591245}
11601246
1161fn zirAnyframeType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
1247fn zirAnyframeType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
11621248 const tracy = trace(@src());
11631249 defer tracy.end();
1164 const return_type = try resolveType(mod, scope, inst.positionals.operand);
11651250
1166 return mod.constType(scope, inst.base.src, try mod.anyframeType(scope, return_type));
1251 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1252 const src = inst_data.src();
1253 const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
1254 const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
1255 const anyframe_type = try sema.mod.anyframeType(block.arena, return_type);
1256
1257 return sema.mod.constType(block.arena, src, anyframe_type);
11671258}
11681259
1169fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError!*Inst {
1260fn zirErrorSet(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
11701261 const tracy = trace(@src());
11711262 defer tracy.end();
1172 // The declarations arena will store the hashmap.
1263
1264 // The owner Decl arena will store the hashmap.
11731265 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
11741266 errdefer new_decl_arena.deinit();
11751267
......@@ -1186,7 +1278,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
11861278 for (inst.positionals.fields) |field_name| {
11871279 const entry = try mod.getErrorValue(field_name);
11881280 if (payload.data.fields.fetchPutAssumeCapacity(entry.key, {})) |_| {
1189 return mod.fail(scope, inst.base.src, "duplicate error: '{s}'", .{field_name});
1281 return sema.mod.fail(&block.base, inst.base.src, "duplicate error: '{s}'", .{field_name});
11901282 }
11911283 }
11921284 // TODO create name in format "error:line:column"
......@@ -1198,35 +1290,36 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
11981290 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
11991291}
12001292
1201fn zirErrorValue(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorValue) InnerError!*Inst {
1293fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
12021294 const tracy = trace(@src());
12031295 defer tracy.end();
12041296
12051297 // Create an anonymous error set type with only this error value, and return the value.
12061298 const entry = try mod.getErrorValue(inst.positionals.name);
1207 const result_type = try Type.Tag.error_set_single.create(scope.arena(), entry.key);
1208 return mod.constInst(scope, inst.base.src, .{
1299 const result_type = try Type.Tag.error_set_single.create(block.arena, entry.key);
1300 return sema.mod.constInst(scope, inst.base.src, .{
12091301 .ty = result_type,
1210 .val = try Value.Tag.@"error".create(scope.arena(), .{
1302 .val = try Value.Tag.@"error".create(block.arena, .{
12111303 .name = entry.key,
12121304 }),
12131305 });
12141306}
12151307
1216fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1308fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
12171309 const tracy = trace(@src());
12181310 defer tracy.end();
12191311
1220 const rhs_ty = try resolveType(mod, scope, inst.positionals.rhs);
1221 const lhs_ty = try resolveType(mod, scope, inst.positionals.lhs);
1312 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1313 const lhs_ty = try sema.resolveType(block, bin_inst.lhs);
1314 const rhs_ty = try sema.resolveType(block, bin_inst.rhs);
12221315 if (rhs_ty.zigTypeTag() != .ErrorSet)
1223 return mod.fail(scope, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
1316 return sema.mod.fail(&block.base, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
12241317 if (lhs_ty.zigTypeTag() != .ErrorSet)
1225 return mod.fail(scope, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
1318 return sema.mod.fail(&block.base, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
12261319
12271320 // anything merged with anyerror is anyerror
12281321 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)
1229 return mod.constInst(scope, inst.base.src, .{
1322 return sema.mod.constInst(scope, inst.base.src, .{
12301323 .ty = Type.initTag(.type),
12311324 .val = Value.initTag(.anyerror_type),
12321325 });
......@@ -1291,218 +1384,243 @@ fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr
12911384 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
12921385}
12931386
1294fn zirEnumLiteral(mod: *Module, scope: *Scope, inst: *zir.Inst.EnumLiteral) InnerError!*Inst {
1387fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
12951388 const tracy = trace(@src());
12961389 defer tracy.end();
1297 const duped_name = try scope.arena().dupe(u8, inst.positionals.name);
1298 return mod.constInst(scope, inst.base.src, .{
1390
1391 const duped_name = try block.arena.dupe(u8, inst.positionals.name);
1392 return sema.mod.constInst(scope, inst.base.src, .{
12991393 .ty = Type.initTag(.enum_literal),
1300 .val = try Value.Tag.enum_literal.create(scope.arena(), duped_name),
1394 .val = try Value.Tag.enum_literal.create(block.arena, duped_name),
13011395 });
13021396}
13031397
13041398/// Pointer in, pointer out.
13051399fn zirOptionalPayloadPtr(
1306 mod: *Module,
1307 scope: *Scope,
1308 unwrap: *zir.Inst.UnOp,
1400 sema: *Sema,
1401 block: *Scope.Block,
1402 inst: zir.Inst.Index,
13091403 safety_check: bool,
13101404) InnerError!*Inst {
13111405 const tracy = trace(@src());
13121406 defer tracy.end();
13131407
1314 const optional_ptr = try resolveInst(mod, scope, unwrap.positionals.operand);
1408 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1409 const optional_ptr = sema.resolveInst(block, inst_data.operand);
13151410 assert(optional_ptr.ty.zigTypeTag() == .Pointer);
1411 const src = inst_data.src();
13161412
13171413 const opt_type = optional_ptr.ty.elemType();
13181414 if (opt_type.zigTypeTag() != .Optional) {
1319 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{opt_type});
1415 return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
13201416 }
13211417
1322 const child_type = try opt_type.optionalChildAlloc(scope.arena());
1323 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, !optional_ptr.ty.isConstPtr(), .One);
1418 const child_type = try opt_type.optionalChildAlloc(block.arena);
1419 const child_pointer = try sema.mod.simplePtrType(block.arena, child_type, !optional_ptr.ty.isConstPtr(), .One);
13241420
13251421 if (optional_ptr.value()) |pointer_val| {
1326 const val = try pointer_val.pointerDeref(scope.arena());
1422 const val = try pointer_val.pointerDeref(block.arena);
13271423 if (val.isNull()) {
1328 return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{});
1424 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
13291425 }
13301426 // The same Value represents the pointer to the optional and the payload.
1331 return mod.constInst(scope, unwrap.base.src, .{
1427 return sema.mod.constInst(scope, src, .{
13321428 .ty = child_pointer,
13331429 .val = pointer_val,
13341430 });
13351431 }
13361432
1337 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
1338 if (safety_check and mod.wantSafety(scope)) {
1339 const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);
1433 try sema.requireRuntimeBlock(block, src);
1434 if (safety_check and block.wantSafety()) {
1435 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);
13401436 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
13411437 }
1342 return mod.addUnOp(b, unwrap.base.src, child_pointer, .optional_payload_ptr, optional_ptr);
1438 return block.addUnOp(src, child_pointer, .optional_payload_ptr, optional_ptr);
13431439}
13441440
13451441/// Value in, value out.
13461442fn zirOptionalPayload(
1347 mod: *Module,
1348 scope: *Scope,
1349 unwrap: *zir.Inst.UnOp,
1443 sema: *Sema,
1444 block: *Scope.Block,
1445 inst: zir.Inst.Index,
13501446 safety_check: bool,
13511447) InnerError!*Inst {
13521448 const tracy = trace(@src());
13531449 defer tracy.end();
13541450
1355 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
1451 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1452 const src = inst_data.src();
1453 const operand = sema.resolveInst(block, inst_data.operand);
13561454 const opt_type = operand.ty;
13571455 if (opt_type.zigTypeTag() != .Optional) {
1358 return mod.fail(scope, unwrap.base.src, "expected optional type, found {}", .{opt_type});
1456 return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
13591457 }
13601458
1361 const child_type = try opt_type.optionalChildAlloc(scope.arena());
1459 const child_type = try opt_type.optionalChildAlloc(block.arena);
13621460
13631461 if (operand.value()) |val| {
13641462 if (val.isNull()) {
1365 return mod.fail(scope, unwrap.base.src, "unable to unwrap null", .{});
1463 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
13661464 }
1367 return mod.constInst(scope, unwrap.base.src, .{
1465 return sema.mod.constInst(scope, src, .{
13681466 .ty = child_type,
13691467 .val = val,
13701468 });
13711469 }
13721470
1373 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
1374 if (safety_check and mod.wantSafety(scope)) {
1375 const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_non_null, operand);
1471 try sema.requireRuntimeBlock(block, src);
1472 if (safety_check and block.wantSafety()) {
1473 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null, operand);
13761474 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
13771475 }
1378 return mod.addUnOp(b, unwrap.base.src, child_type, .optional_payload, operand);
1476 return block.addUnOp(src, child_type, .optional_payload, operand);
13791477}
13801478
13811479/// Value in, value out
1382fn zirErrUnionPayload(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
1480fn zirErrUnionPayload(
1481 sema: *Sema,
1482 block: *Scope.Block,
1483 inst: zir.Inst.Index,
1484 safety_check: bool,
1485) InnerError!*Inst {
13831486 const tracy = trace(@src());
13841487 defer tracy.end();
13851488
1386 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
1489 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1490 const src = inst_data.src();
1491 const operand = sema.resolveInst(block, inst_data.operand);
13871492 if (operand.ty.zigTypeTag() != .ErrorUnion)
1388 return mod.fail(scope, operand.src, "expected error union type, found '{}'", .{operand.ty});
1493 return sema.mod.fail(&block.base, operand.src, "expected error union type, found '{}'", .{operand.ty});
13891494
13901495 if (operand.value()) |val| {
13911496 if (val.getError()) |name| {
1392 return mod.fail(scope, unwrap.base.src, "caught unexpected error '{s}'", .{name});
1497 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
13931498 }
13941499 const data = val.castTag(.error_union).?.data;
1395 return mod.constInst(scope, unwrap.base.src, .{
1500 return sema.mod.constInst(scope, src, .{
13961501 .ty = operand.ty.castTag(.error_union).?.data.payload,
13971502 .val = data,
13981503 });
13991504 }
1400 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
1401 if (safety_check and mod.wantSafety(scope)) {
1402 const is_non_err = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_err, operand);
1505 try sema.requireRuntimeBlock(block, src);
1506 if (safety_check and block.wantSafety()) {
1507 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
14031508 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
14041509 }
1405 return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_payload, operand);
1510 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_payload, operand);
14061511}
14071512
1408/// Pointer in, pointer out
1409fn zirErrUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {
1513/// Pointer in, pointer out.
1514fn zirErrUnionPayloadPtr(
1515 sema: *Sema,
1516 block: *Scope.Block,
1517 inst: zir.Inst.Index,
1518 safety_check: bool,
1519) InnerError!*Inst {
14101520 const tracy = trace(@src());
14111521 defer tracy.end();
14121522
1413 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
1523 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1524 const src = inst_data.src();
1525 const operand = sema.resolveInst(block, inst_data.operand);
14141526 assert(operand.ty.zigTypeTag() == .Pointer);
14151527
14161528 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
1417 return mod.fail(scope, unwrap.base.src, "expected error union type, found {}", .{operand.ty.elemType()});
1529 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
14181530
1419 const operand_pointer_ty = try mod.simplePtrType(scope, unwrap.base.src, operand.ty.elemType().castTag(.error_union).?.data.payload, !operand.ty.isConstPtr(), .One);
1531 const operand_pointer_ty = try sema.mod.simplePtrType(block.arena, operand.ty.elemType().castTag(.error_union).?.data.payload, !operand.ty.isConstPtr(), .One);
14201532
14211533 if (operand.value()) |pointer_val| {
1422 const val = try pointer_val.pointerDeref(scope.arena());
1534 const val = try pointer_val.pointerDeref(block.arena);
14231535 if (val.getError()) |name| {
1424 return mod.fail(scope, unwrap.base.src, "caught unexpected error '{s}'", .{name});
1536 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
14251537 }
14261538 const data = val.castTag(.error_union).?.data;
14271539 // The same Value represents the pointer to the error union and the payload.
1428 return mod.constInst(scope, unwrap.base.src, .{
1540 return sema.mod.constInst(scope, src, .{
14291541 .ty = operand_pointer_ty,
14301542 .val = try Value.Tag.ref_val.create(
1431 scope.arena(),
1543 block.arena,
14321544 data,
14331545 ),
14341546 });
14351547 }
14361548
1437 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
1438 if (safety_check and mod.wantSafety(scope)) {
1439 const is_non_err = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_err, operand);
1549 try sema.requireRuntimeBlock(block, src);
1550 if (safety_check and block.wantSafety()) {
1551 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
14401552 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
14411553 }
1442 return mod.addUnOp(b, unwrap.base.src, operand_pointer_ty, .unwrap_errunion_payload_ptr, operand);
1554 return block.addUnOp(src, operand_pointer_ty, .unwrap_errunion_payload_ptr, operand);
14431555}
14441556
14451557/// Value in, value out
1446fn zirErrUnionCode(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
1558fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
14471559 const tracy = trace(@src());
14481560 defer tracy.end();
14491561
1450 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
1562 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1563 const src = inst_data.src();
1564 const operand = sema.resolveInst(block, inst_data.operand);
14511565 if (operand.ty.zigTypeTag() != .ErrorUnion)
1452 return mod.fail(scope, unwrap.base.src, "expected error union type, found '{}'", .{operand.ty});
1566 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
14531567
14541568 if (operand.value()) |val| {
14551569 assert(val.getError() != null);
14561570 const data = val.castTag(.error_union).?.data;
1457 return mod.constInst(scope, unwrap.base.src, .{
1571 return sema.mod.constInst(scope, src, .{
14581572 .ty = operand.ty.castTag(.error_union).?.data.error_set,
14591573 .val = data,
14601574 });
14611575 }
14621576
1463 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
1464 return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);
1577 try sema.requireRuntimeBlock(block, src);
1578 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);
14651579}
14661580
14671581/// Pointer in, value out
1468fn zirErrUnionCodePtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
1582fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
14691583 const tracy = trace(@src());
14701584 defer tracy.end();
14711585
1472 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
1586 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1587 const src = inst_data.src();
1588 const operand = sema.resolveInst(block, inst_data.operand);
14731589 assert(operand.ty.zigTypeTag() == .Pointer);
14741590
14751591 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
1476 return mod.fail(scope, unwrap.base.src, "expected error union type, found {}", .{operand.ty.elemType()});
1592 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
14771593
14781594 if (operand.value()) |pointer_val| {
1479 const val = try pointer_val.pointerDeref(scope.arena());
1595 const val = try pointer_val.pointerDeref(block.arena);
14801596 assert(val.getError() != null);
14811597 const data = val.castTag(.error_union).?.data;
1482 return mod.constInst(scope, unwrap.base.src, .{
1598 return sema.mod.constInst(scope, src, .{
14831599 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,
14841600 .val = data,
14851601 });
14861602 }
14871603
1488 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);
1489 return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
1604 try sema.requireRuntimeBlock(block, src);
1605 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
14901606}
14911607
1492fn zirEnsureErrPayloadVoid(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp) InnerError!*Inst {
1608fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
14931609 const tracy = trace(@src());
14941610 defer tracy.end();
14951611
1496 const operand = try resolveInst(mod, scope, unwrap.positionals.operand);
1612 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1613 const src = inst_data.src();
1614 const operand = sema.resolveInst(block, inst_data.operand);
14971615 if (operand.ty.zigTypeTag() != .ErrorUnion)
1498 return mod.fail(scope, unwrap.base.src, "expected error union type, found '{}'", .{operand.ty});
1616 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
14991617 if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {
1500 return mod.fail(scope, unwrap.base.src, "expression value is ignored", .{});
1618 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});
15011619 }
1502 return mod.constVoid(scope, unwrap.base.src);
1620 return sema.mod.constVoid(block.arena, .unneeded);
15031621}
15041622
1505fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bool) InnerError!*Inst {
1623fn zirFnType(sema: *Sema, block: *Scope.Block, fntype: zir.Inst.Index, var_args: bool) InnerError!*Inst {
15061624 const tracy = trace(@src());
15071625 defer tracy.end();
15081626
......@@ -1517,7 +1635,7 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bo
15171635 );
15181636}
15191637
1520fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args: bool) InnerError!*Inst {
1638fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, fntype: zir.Inst.Index, var_args: bool) InnerError!*Inst {
15211639 const tracy = trace(@src());
15221640 defer tracy.end();
15231641
......@@ -1526,7 +1644,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args
15261644 // std.builtin, this needs to change
15271645 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
15281646 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
1529 return mod.fail(scope, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str});
1647 return sema.mod.fail(&block.base, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str});
15301648 return fnTypeCommon(
15311649 mod,
15321650 scope,
......@@ -1539,129 +1657,144 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args
15391657}
15401658
15411659fn fnTypeCommon(
1542 mod: *Module,
1543 scope: *Scope,
1544 zir_inst: *zir.Inst,
1545 zir_param_types: []*zir.Inst,
1546 zir_return_type: *zir.Inst,
1660 sema: *Sema,
1661 block: *Scope.Block,
1662 zir_inst: zir.Inst.Index,
1663 zir_param_types: []zir.Inst.Index,
1664 zir_return_type: zir.Inst.Index,
15471665 cc: std.builtin.CallingConvention,
15481666 var_args: bool,
15491667) InnerError!*Inst {
1550 const return_type = try resolveType(mod, scope, zir_return_type);
1668 const return_type = try sema.resolveType(block, zir_return_type);
15511669
15521670 // Hot path for some common function types.
15531671 if (zir_param_types.len == 0 and !var_args) {
15541672 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
1555 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
1673 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
15561674 }
15571675
15581676 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {
1559 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_void_no_args));
1677 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_void_no_args));
15601678 }
15611679
15621680 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
1563 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_naked_noreturn_no_args));
1681 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_naked_noreturn_no_args));
15641682 }
15651683
15661684 if (return_type.zigTypeTag() == .Void and cc == .C) {
1567 return mod.constType(scope, zir_inst.src, Type.initTag(.fn_ccc_void_no_args));
1685 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_ccc_void_no_args));
15681686 }
15691687 }
15701688
1571 const arena = scope.arena();
1572 const param_types = try arena.alloc(Type, zir_param_types.len);
1689 const param_types = try block.arena.alloc(Type, zir_param_types.len);
15731690 for (zir_param_types) |param_type, i| {
1574 const resolved = try resolveType(mod, scope, param_type);
1691 const resolved = try sema.resolveType(block, param_type);
15751692 // TODO skip for comptime params
15761693 if (!resolved.isValidVarType(false)) {
1577 return mod.fail(scope, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
1694 return sema.mod.fail(&block.base, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
15781695 }
15791696 param_types[i] = resolved;
15801697 }
15811698
1582 const fn_ty = try Type.Tag.function.create(arena, .{
1699 const fn_ty = try Type.Tag.function.create(block.arena, .{
15831700 .param_types = param_types,
15841701 .return_type = return_type,
15851702 .cc = cc,
15861703 .is_var_args = var_args,
15871704 });
1588 return mod.constType(scope, zir_inst.src, fn_ty);
1705 return sema.mod.constType(block.arena, zir_inst.src, fn_ty);
15891706}
15901707
1591fn zirPrimitive(mod: *Module, scope: *Scope, primitive: *zir.Inst.Primitive) InnerError!*Inst {
1708fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
15921709 const tracy = trace(@src());
15931710 defer tracy.end();
1594 return mod.constInst(scope, primitive.base.src, primitive.positionals.tag.toTypedValue());
1595}
15961711
1597fn zirAs(mod: *Module, scope: *Scope, as: *zir.Inst.BinOp) InnerError!*Inst {
1598 const tracy = trace(@src());
1599 defer tracy.end();
1600 const dest_type = try resolveType(mod, scope, as.positionals.lhs);
1601 const new_inst = try resolveInst(mod, scope, as.positionals.rhs);
1602 return mod.coerce(scope, dest_type, new_inst);
1712 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1713 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1714 const tzir_inst = sema.resolveInst(block, bin_inst.rhs);
1715 return sema.coerce(scope, dest_type, tzir_inst);
16031716}
16041717
1605fn zirPtrtoint(mod: *Module, scope: *Scope, ptrtoint: *zir.Inst.UnOp) InnerError!*Inst {
1718fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16061719 const tracy = trace(@src());
16071720 defer tracy.end();
1608 const ptr = try resolveInst(mod, scope, ptrtoint.positionals.operand);
1721
1722 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1723 const ptr = sema.resolveInst(block, inst_data.operand);
16091724 if (ptr.ty.zigTypeTag() != .Pointer) {
1610 return mod.fail(scope, ptrtoint.positionals.operand.src, "expected pointer, found '{}'", .{ptr.ty});
1725 const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
1726 return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty});
16111727 }
16121728 // TODO handle known-pointer-address
1613 const b = try mod.requireRuntimeBlock(scope, ptrtoint.base.src);
1729 const src = inst_data.src();
1730 try sema.requireRuntimeBlock(block, src);
16141731 const ty = Type.initTag(.usize);
1615 return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr);
1732 return block.addUnOp(src, ty, .ptrtoint, ptr);
16161733}
16171734
1618fn zirFieldVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst {
1735fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16191736 const tracy = trace(@src());
16201737 defer tracy.end();
16211738
1622 const object = try resolveInst(mod, scope, inst.positionals.object);
1623 const field_name = inst.positionals.field_name;
1624 const object_ptr = try mod.analyzeRef(scope, inst.base.src, object);
1625 const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src);
1626 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
1739 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1740 const src = inst_data.src();
1741 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1742 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1743 const field_name = sema.code.string_bytes[extra.field_name_start..][0..extra.field_name_len];
1744 const object = sema.resolveInst(block, extra.lhs);
1745 const object_ptr = try sema.analyzeRef(block, src, object);
1746 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1747 return sema.analyzeDeref(block, src, result_ptr, result_ptr.src);
16271748}
16281749
1629fn zirFieldPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Field) InnerError!*Inst {
1750fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16301751 const tracy = trace(@src());
16311752 defer tracy.end();
16321753
1633 const object_ptr = try resolveInst(mod, scope, inst.positionals.object);
1634 const field_name = inst.positionals.field_name;
1635 return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src);
1754 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1755 const src = inst_data.src();
1756 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1757 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1758 const field_name = sema.code.string_bytes[extra.field_name_start..][0..extra.field_name_len];
1759 const object_ptr = sema.resolveInst(block, extra.lhs);
1760 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
16361761}
16371762
1638fn zirFieldValNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst {
1763fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16391764 const tracy = trace(@src());
16401765 defer tracy.end();
16411766
1642 const object = try resolveInst(mod, scope, inst.positionals.object);
1643 const field_name = try resolveConstString(mod, scope, inst.positionals.field_name);
1644 const fsrc = inst.positionals.field_name.src;
1645 const object_ptr = try mod.analyzeRef(scope, inst.base.src, object);
1646 const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc);
1647 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
1767 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1768 const src = inst_data.src();
1769 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1770 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1771 const object = sema.resolveInst(block, extra.lhs);
1772 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
1773 const object_ptr = try sema.analyzeRef(block, src, object);
1774 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1775 return sema.analyzeDeref(block, src, result_ptr, src);
16481776}
16491777
1650fn zirFieldPtrNamed(mod: *Module, scope: *Scope, inst: *zir.Inst.FieldNamed) InnerError!*Inst {
1778fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16511779 const tracy = trace(@src());
16521780 defer tracy.end();
16531781
1654 const object_ptr = try resolveInst(mod, scope, inst.positionals.object);
1655 const field_name = try resolveConstString(mod, scope, inst.positionals.field_name);
1656 const fsrc = inst.positionals.field_name.src;
1657 return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc);
1782 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1783 const src = inst_data.src();
1784 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1785 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1786 const object_ptr = sema.resolveInst(block, extra.lhs);
1787 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
1788 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
16581789}
16591790
1660fn zirIntcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1791fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16611792 const tracy = trace(@src());
16621793 defer tracy.end();
1663 const dest_type = try resolveType(mod, scope, inst.positionals.lhs);
1664 const operand = try resolveInst(mod, scope, inst.positionals.rhs);
1794
1795 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1796 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1797 const operand = sema.resolveInst(bin_inst.rhs);
16651798
16661799 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
16671800 .ComptimeInt => true,
......@@ -1687,27 +1820,31 @@ fn zirIntcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
16871820 }
16881821
16891822 if (operand.value() != null) {
1690 return mod.coerce(scope, dest_type, operand);
1823 return sema.coerce(scope, dest_type, operand);
16911824 } else if (dest_is_comptime_int) {
1692 return mod.fail(scope, inst.base.src, "unable to cast runtime value to 'comptime_int'", .{});
1825 return sema.mod.fail(&block.base, inst.base.src, "unable to cast runtime value to 'comptime_int'", .{});
16931826 }
16941827
1695 return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten int", .{});
1828 return sema.mod.fail(&block.base, inst.base.src, "TODO implement analyze widen or shorten int", .{});
16961829}
16971830
1698fn zirBitcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1831fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
16991832 const tracy = trace(@src());
17001833 defer tracy.end();
1701 const dest_type = try resolveType(mod, scope, inst.positionals.lhs);
1702 const operand = try resolveInst(mod, scope, inst.positionals.rhs);
1834
1835 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1836 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1837 const operand = sema.resolveInst(bin_inst.rhs);
17031838 return mod.bitcast(scope, dest_type, operand);
17041839}
17051840
1706fn zirFloatcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1841fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
17071842 const tracy = trace(@src());
17081843 defer tracy.end();
1709 const dest_type = try resolveType(mod, scope, inst.positionals.lhs);
1710 const operand = try resolveInst(mod, scope, inst.positionals.rhs);
1844
1845 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1846 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1847 const operand = sema.resolveInst(bin_inst.rhs);
17111848
17121849 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
17131850 .ComptimeFloat => true,
......@@ -1733,110 +1870,172 @@ fn zirFloatcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*
17331870 }
17341871
17351872 if (operand.value() != null) {
1736 return mod.coerce(scope, dest_type, operand);
1873 return sema.coerce(scope, dest_type, operand);
17371874 } else if (dest_is_comptime_float) {
1738 return mod.fail(scope, inst.base.src, "unable to cast runtime value to 'comptime_float'", .{});
1875 return sema.mod.fail(&block.base, inst.base.src, "unable to cast runtime value to 'comptime_float'", .{});
17391876 }
17401877
1741 return mod.fail(scope, inst.base.src, "TODO implement analyze widen or shorten float", .{});
1878 return sema.mod.fail(&block.base, inst.base.src, "TODO implement analyze widen or shorten float", .{});
17421879}
17431880
1744fn zirElemVal(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst {
1881fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
17451882 const tracy = trace(@src());
17461883 defer tracy.end();
17471884
1748 const array = try resolveInst(mod, scope, inst.positionals.array);
1749 const array_ptr = try mod.analyzeRef(scope, inst.base.src, array);
1750 const elem_index = try resolveInst(mod, scope, inst.positionals.index);
1751 const result_ptr = try mod.elemPtr(scope, inst.base.src, array_ptr, elem_index);
1752 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);
1885 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1886 const array = sema.resolveInst(block, bin_inst.lhs);
1887 const array_ptr = try sema.analyzeRef(block, sema.src, array);
1888 const elem_index = sema.resolveInst(block, bin_inst.rhs);
1889 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
1890 return sema.analyzeDeref(block, sema.src, result_ptr, sema.src);
17531891}
17541892
1755fn zirElemPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.Elem) InnerError!*Inst {
1893fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
17561894 const tracy = trace(@src());
17571895 defer tracy.end();
17581896
1759 const array_ptr = try resolveInst(mod, scope, inst.positionals.array);
1760 const elem_index = try resolveInst(mod, scope, inst.positionals.index);
1761 return mod.elemPtr(scope, inst.base.src, array_ptr, elem_index);
1897 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1898 const src = inst_data.src();
1899 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
1900 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1901 const array = sema.resolveInst(block, extra.lhs);
1902 const array_ptr = try sema.analyzeRef(block, src, array);
1903 const elem_index = sema.resolveInst(block, extra.rhs);
1904 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
1905 return sema.analyzeDeref(block, src, result_ptr, src);
17621906}
17631907
1764fn zirSlice(mod: *Module, scope: *Scope, inst: *zir.Inst.Slice) InnerError!*Inst {
1908fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
17651909 const tracy = trace(@src());
17661910 defer tracy.end();
1767 const array_ptr = try resolveInst(mod, scope, inst.positionals.array_ptr);
1768 const start = try resolveInst(mod, scope, inst.positionals.start);
1769 const end = if (inst.kw_args.end) |end| try resolveInst(mod, scope, end) else null;
1770 const sentinel = if (inst.kw_args.sentinel) |sentinel| try resolveInst(mod, scope, sentinel) else null;
17711911
1772 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, end, sentinel);
1912 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1913 const array_ptr = sema.resolveInst(block, bin_inst.lhs);
1914 const elem_index = sema.resolveInst(block, bin_inst.rhs);
1915 return sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
17731916}
17741917
1775fn zirSliceStart(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1918fn zirElemPtrNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
17761919 const tracy = trace(@src());
17771920 defer tracy.end();
1778 const array_ptr = try resolveInst(mod, scope, inst.positionals.lhs);
1779 const start = try resolveInst(mod, scope, inst.positionals.rhs);
17801921
1781 return mod.analyzeSlice(scope, inst.base.src, array_ptr, start, null, null);
1922 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1923 const src = inst_data.src();
1924 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
1925 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1926 const array_ptr = sema.resolveInst(block, extra.lhs);
1927 const elem_index = sema.resolveInst(block, extra.rhs);
1928 return sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
17821929}
17831930
1784fn zirSwitchRange(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
1931fn zirSliceStart(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
17851932 const tracy = trace(@src());
17861933 defer tracy.end();
1787 const start = try resolveInst(mod, scope, inst.positionals.lhs);
1788 const end = try resolveInst(mod, scope, inst.positionals.rhs);
1934
1935 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1936 const src = inst_data.src();
1937 const extra = sema.code.extraData(zir.Inst.SliceStart, inst_data.payload_index).data;
1938 const array_ptr = sema.resolveInst(extra.lhs);
1939 const start = sema.resolveInst(extra.start);
1940
1941 return sema.analyzeSlice(block, src, array_ptr, start, null, null, .unneeded);
1942}
1943
1944fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1945 const tracy = trace(@src());
1946 defer tracy.end();
1947
1948 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1949 const src = inst_data.src();
1950 const extra = sema.code.extraData(zir.Inst.SliceEnd, inst_data.payload_index).data;
1951 const array_ptr = sema.resolveInst(extra.lhs);
1952 const start = sema.resolveInst(extra.start);
1953 const end = sema.resolveInst(extra.end);
1954
1955 return sema.analyzeSlice(block, src, array_ptr, start, end, null, .unneeded);
1956}
1957
1958fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1959 const tracy = trace(@src());
1960 defer tracy.end();
1961
1962 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1963 const src = inst_data.src();
1964 const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node };
1965 const extra = sema.code.extraData(zir.Inst.SliceSentinel, inst_data.payload_index).data;
1966 const array_ptr = sema.resolveInst(extra.lhs);
1967 const start = sema.resolveInst(extra.start);
1968 const end = sema.resolveInst(extra.end);
1969 const sentinel = sema.resolveInst(extra.sentinel);
1970
1971 return sema.analyzeSlice(block, inst.base.src, array_ptr, start, end, sentinel, sentinel_src);
1972}
1973
1974fn zirSwitchRange(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1975 const tracy = trace(@src());
1976 defer tracy.end();
1977
1978 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1979 const start = sema.resolveInst(bin_inst.lhs);
1980 const end = sema.resolveInst(bin_inst.rhs);
17891981
17901982 switch (start.ty.zigTypeTag()) {
17911983 .Int, .ComptimeInt => {},
1792 else => return mod.constVoid(scope, inst.base.src),
1984 else => return sema.mod.constVoid(block.arena, .unneeded),
17931985 }
17941986 switch (end.ty.zigTypeTag()) {
17951987 .Int, .ComptimeInt => {},
1796 else => return mod.constVoid(scope, inst.base.src),
1988 else => return sema.mod.constVoid(block.arena, .unneeded),
17971989 }
17981990 // .switch_range must be inside a comptime scope
17991991 const start_val = start.value().?;
18001992 const end_val = end.value().?;
18011993 if (start_val.compare(.gte, end_val)) {
1802 return mod.fail(scope, inst.base.src, "range start value must be smaller than the end value", .{});
1994 return sema.mod.fail(&block.base, inst.base.src, "range start value must be smaller than the end value", .{});
18031995 }
1804 return mod.constVoid(scope, inst.base.src);
1996 return sema.mod.constVoid(block.arena, .unneeded);
18051997}
18061998
1807fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool) InnerError!*Inst {
1999fn zirSwitchBr(
2000 sema: *Sema,
2001 parent_block: *Scope.Block,
2002 inst: zir.Inst.Index,
2003 ref: bool,
2004) InnerError!*Inst {
18082005 const tracy = trace(@src());
18092006 defer tracy.end();
18102007
1811 const target_ptr = try resolveInst(mod, scope, inst.positionals.target);
2008 if (true) @panic("TODO rework with zir-memory-layout in mind");
2009
2010 const target_ptr = sema.resolveInst(block, inst.positionals.target);
18122011 const target = if (ref)
1813 try mod.analyzeDeref(scope, inst.base.src, target_ptr, inst.positionals.target.src)
2012 try sema.analyzeDeref(block, inst.base.src, target_ptr, inst.positionals.target.src)
18142013 else
18152014 target_ptr;
18162015 try validateSwitch(mod, scope, target, inst);
18172016
18182017 if (try mod.resolveDefinedValue(scope, target)) |target_val| {
18192018 for (inst.positionals.cases) |case| {
1820 const resolved = try resolveInst(mod, scope, case.item);
1821 const casted = try mod.coerce(scope, target.ty, resolved);
1822 const item = try mod.resolveConstValue(scope, casted);
2019 const resolved = sema.resolveInst(block, case.item);
2020 const casted = try sema.coerce(scope, target.ty, resolved);
2021 const item = try sema.resolveConstValue(parent_block, case_src, casted);
18232022
18242023 if (target_val.eql(item)) {
1825 try analyzeBody(mod, scope.cast(Scope.Block).?, case.body);
2024 try sema.body(scope.cast(Scope.Block).?, case.body);
18262025 return mod.constNoReturn(scope, inst.base.src);
18272026 }
18282027 }
1829 try analyzeBody(mod, scope.cast(Scope.Block).?, inst.positionals.else_body);
2028 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
18302029 return mod.constNoReturn(scope, inst.base.src);
18312030 }
18322031
18332032 if (inst.positionals.cases.len == 0) {
18342033 // no cases just analyze else_branch
1835 try analyzeBody(mod, scope.cast(Scope.Block).?, inst.positionals.else_body);
2034 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
18362035 return mod.constNoReturn(scope, inst.base.src);
18372036 }
18382037
1839 const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);
2038 try sema.requireRuntimeBlock(parent_block, inst.base.src);
18402039 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);
18412040
18422041 var case_block: Scope.Block = .{
......@@ -1857,11 +2056,11 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)
18572056 // Reset without freeing.
18582057 case_block.instructions.items.len = 0;
18592058
1860 const resolved = try resolveInst(mod, scope, case.item);
1861 const casted = try mod.coerce(scope, target.ty, resolved);
1862 const item = try mod.resolveConstValue(scope, casted);
2059 const resolved = sema.resolveInst(block, case.item);
2060 const casted = try sema.coerce(scope, target.ty, resolved);
2061 const item = try sema.resolveConstValue(parent_block, case_src, casted);
18632062
1864 try analyzeBody(mod, &case_block, case.body);
2063 try sema.body(&case_block, case.body);
18652064
18662065 cases[i] = .{
18672066 .item = item,
......@@ -1870,7 +2069,7 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)
18702069 }
18712070
18722071 case_block.instructions.items.len = 0;
1873 try analyzeBody(mod, &case_block, inst.positionals.else_body);
2072 try sema.body(&case_block, inst.positionals.else_body);
18742073
18752074 const else_body: ir.Body = .{
18762075 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
......@@ -1879,10 +2078,10 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)
18792078 return mod.addSwitchBr(parent_block, inst.base.src, target, cases, else_body);
18802079}
18812080
1882fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.SwitchBr) InnerError!void {
2081fn validateSwitch(sema: *Sema, block: *Scope.Block, target: *Inst, inst: zir.Inst.Index) InnerError!void {
18832082 // validate usage of '_' prongs
18842083 if (inst.positionals.special_prong == .underscore and target.ty.zigTypeTag() != .Enum) {
1885 return mod.fail(scope, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
2084 return sema.mod.fail(&block.base, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
18862085 // TODO notes "'_' prong here" inst.positionals.cases[last].src
18872086 }
18882087
......@@ -1891,7 +2090,7 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
18912090 switch (target.ty.zigTypeTag()) {
18922091 .Int, .ComptimeInt => {},
18932092 else => {
1894 return mod.fail(scope, target.src, "ranges not allowed when switching on type {}", .{target.ty});
2093 return sema.mod.fail(&block.base, target.src, "ranges not allowed when switching on type {}", .{target.ty});
18952094 // TODO notes "range used here" range_inst.src
18962095 },
18972096 }
......@@ -1899,34 +2098,34 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
18992098
19002099 // validate for duplicate items/missing else prong
19012100 switch (target.ty.zigTypeTag()) {
1902 .Enum => return mod.fail(scope, inst.base.src, "TODO validateSwitch .Enum", .{}),
1903 .ErrorSet => return mod.fail(scope, inst.base.src, "TODO validateSwitch .ErrorSet", .{}),
1904 .Union => return mod.fail(scope, inst.base.src, "TODO validateSwitch .Union", .{}),
2101 .Enum => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Enum", .{}),
2102 .ErrorSet => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .ErrorSet", .{}),
2103 .Union => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Union", .{}),
19052104 .Int, .ComptimeInt => {
19062105 var range_set = @import("RangeSet.zig").init(mod.gpa);
19072106 defer range_set.deinit();
19082107
19092108 for (inst.positionals.items) |item| {
19102109 const maybe_src = if (item.castTag(.switch_range)) |range| blk: {
1911 const start_resolved = try resolveInst(mod, scope, range.positionals.lhs);
1912 const start_casted = try mod.coerce(scope, target.ty, start_resolved);
1913 const end_resolved = try resolveInst(mod, scope, range.positionals.rhs);
1914 const end_casted = try mod.coerce(scope, target.ty, end_resolved);
2110 const start_resolved = sema.resolveInst(block, range.positionals.lhs);
2111 const start_casted = try sema.coerce(scope, target.ty, start_resolved);
2112 const end_resolved = sema.resolveInst(block, range.positionals.rhs);
2113 const end_casted = try sema.coerce(scope, target.ty, end_resolved);
19152114
19162115 break :blk try range_set.add(
1917 try mod.resolveConstValue(scope, start_casted),
1918 try mod.resolveConstValue(scope, end_casted),
2116 try sema.resolveConstValue(block, range_start_src, start_casted),
2117 try sema.resolveConstValue(block, range_end_src, end_casted),
19192118 item.src,
19202119 );
19212120 } else blk: {
1922 const resolved = try resolveInst(mod, scope, item);
1923 const casted = try mod.coerce(scope, target.ty, resolved);
1924 const value = try mod.resolveConstValue(scope, casted);
2121 const resolved = sema.resolveInst(block, item);
2122 const casted = try sema.coerce(scope, target.ty, resolved);
2123 const value = try sema.resolveConstValue(block, item_src, casted);
19252124 break :blk try range_set.add(value, value, item.src);
19262125 };
19272126
19282127 if (maybe_src) |previous_src| {
1929 return mod.fail(scope, item.src, "duplicate switch value", .{});
2128 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
19302129 // TODO notes "previous value is here" previous_src
19312130 }
19322131 }
......@@ -1939,54 +2138,54 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
19392138 const end = try target.ty.maxInt(&arena, mod.getTarget());
19402139 if (try range_set.spans(start, end)) {
19412140 if (inst.positionals.special_prong == .@"else") {
1942 return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{});
2141 return sema.mod.fail(&block.base, inst.base.src, "unreachable else prong, all cases already handled", .{});
19432142 }
19442143 return;
19452144 }
19462145 }
19472146
19482147 if (inst.positionals.special_prong != .@"else") {
1949 return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{});
2148 return sema.mod.fail(&block.base, inst.base.src, "switch must handle all possibilities", .{});
19502149 }
19512150 },
19522151 .Bool => {
19532152 var true_count: u8 = 0;
19542153 var false_count: u8 = 0;
19552154 for (inst.positionals.items) |item| {
1956 const resolved = try resolveInst(mod, scope, item);
1957 const casted = try mod.coerce(scope, Type.initTag(.bool), resolved);
1958 if ((try mod.resolveConstValue(scope, casted)).toBool()) {
2155 const resolved = sema.resolveInst(block, item);
2156 const casted = try sema.coerce(scope, Type.initTag(.bool), resolved);
2157 if ((try sema.resolveConstValue(block, item_src, casted)).toBool()) {
19592158 true_count += 1;
19602159 } else {
19612160 false_count += 1;
19622161 }
19632162
19642163 if (true_count + false_count > 2) {
1965 return mod.fail(scope, item.src, "duplicate switch value", .{});
2164 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
19662165 }
19672166 }
19682167 if ((true_count + false_count < 2) and inst.positionals.special_prong != .@"else") {
1969 return mod.fail(scope, inst.base.src, "switch must handle all possibilities", .{});
2168 return sema.mod.fail(&block.base, inst.base.src, "switch must handle all possibilities", .{});
19702169 }
19712170 if ((true_count + false_count == 2) and inst.positionals.special_prong == .@"else") {
1972 return mod.fail(scope, inst.base.src, "unreachable else prong, all cases already handled", .{});
2171 return sema.mod.fail(&block.base, inst.base.src, "unreachable else prong, all cases already handled", .{});
19732172 }
19742173 },
19752174 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
19762175 if (inst.positionals.special_prong != .@"else") {
1977 return mod.fail(scope, inst.base.src, "else prong required when switching on type '{}'", .{target.ty});
2176 return sema.mod.fail(&block.base, inst.base.src, "else prong required when switching on type '{}'", .{target.ty});
19782177 }
19792178
19802179 var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa);
19812180 defer seen_values.deinit();
19822181
19832182 for (inst.positionals.items) |item| {
1984 const resolved = try resolveInst(mod, scope, item);
1985 const casted = try mod.coerce(scope, target.ty, resolved);
1986 const val = try mod.resolveConstValue(scope, casted);
2183 const resolved = sema.resolveInst(block, item);
2184 const casted = try sema.coerce(scope, target.ty, resolved);
2185 const val = try sema.resolveConstValue(block, item_src, casted);
19872186
19882187 if (try seen_values.fetchPut(val, item.src)) |prev| {
1989 return mod.fail(scope, item.src, "duplicate switch value", .{});
2188 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
19902189 // TODO notes "previous value here" prev.value
19912190 }
19922191 }
......@@ -2007,54 +2206,59 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
20072206 .ComptimeFloat,
20082207 .Float,
20092208 => {
2010 return mod.fail(scope, target.src, "invalid switch target type '{}'", .{target.ty});
2209 return sema.mod.fail(&block.base, target.src, "invalid switch target type '{}'", .{target.ty});
20112210 },
20122211 }
20132212}
20142213
2015fn zirImport(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2214fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
20162215 const tracy = trace(@src());
20172216 defer tracy.end();
2018 const operand = try resolveConstString(mod, scope, inst.positionals.operand);
20192217
2020 const file_scope = mod.analyzeImport(scope, inst.base.src, operand) catch |err| switch (err) {
2218 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2219 const src = inst_data.src();
2220 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
2221 const operand = try sema.resolveConstString(block, operand_src, inst_data.operand);
2222
2223 const file_scope = sema.analyzeImport(block, src, operand) catch |err| switch (err) {
20212224 error.ImportOutsidePkgPath => {
2022 return mod.fail(scope, inst.base.src, "import of file outside package path: '{s}'", .{operand});
2225 return sema.mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
20232226 },
20242227 error.FileNotFound => {
2025 return mod.fail(scope, inst.base.src, "unable to find '{s}'", .{operand});
2228 return sema.mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
20262229 },
20272230 else => {
20282231 // TODO: make sure this gets retried and not cached
2029 return mod.fail(scope, inst.base.src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
2232 return sema.mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
20302233 },
20312234 };
2032 return mod.constType(scope, inst.base.src, file_scope.root_container.ty);
2235 return sema.mod.constType(block.arena, src, file_scope.root_container.ty);
20332236}
20342237
2035fn zirShl(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2238fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
20362239 const tracy = trace(@src());
20372240 defer tracy.end();
2038 return mod.fail(scope, inst.base.src, "TODO implement zirShl", .{});
2241 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirShl", .{});
20392242}
20402243
2041fn zirShr(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2244fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
20422245 const tracy = trace(@src());
20432246 defer tracy.end();
2044 return mod.fail(scope, inst.base.src, "TODO implement zirShr", .{});
2247 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirShr", .{});
20452248}
20462249
2047fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2250fn zirBitwise(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
20482251 const tracy = trace(@src());
20492252 defer tracy.end();
20502253
2051 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);
2052 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);
2254 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2255 const lhs = sema.resolveInst(bin_inst.lhs);
2256 const rhs = sema.resolveInst(bin_inst.rhs);
20532257
20542258 const instructions = &[_]*Inst{ lhs, rhs };
2055 const resolved_type = try mod.resolvePeerTypes(scope, instructions);
2056 const casted_lhs = try mod.coerce(scope, resolved_type, lhs);
2057 const casted_rhs = try mod.coerce(scope, resolved_type, rhs);
2259 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2260 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2261 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
20582262
20592263 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
20602264 resolved_type.elemType()
......@@ -2065,14 +2269,14 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
20652269
20662270 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
20672271 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2068 return mod.fail(scope, inst.base.src, "vector length mismatch: {d} and {d}", .{
2272 return sema.mod.fail(&block.base, inst.base.src, "vector length mismatch: {d} and {d}", .{
20692273 lhs.ty.arrayLen(),
20702274 rhs.ty.arrayLen(),
20712275 });
20722276 }
2073 return mod.fail(scope, inst.base.src, "TODO implement support for vectors in zirBitwise", .{});
2277 return sema.mod.fail(&block.base, inst.base.src, "TODO implement support for vectors in zirBitwise", .{});
20742278 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
2075 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
2279 return sema.mod.fail(&block.base, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
20762280 lhs.ty,
20772281 rhs.ty,
20782282 });
......@@ -2081,22 +2285,22 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
20812285 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
20822286
20832287 if (!is_int) {
2084 return mod.fail(scope, inst.base.src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
2288 return sema.mod.fail(&block.base, inst.base.src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
20852289 }
20862290
20872291 if (casted_lhs.value()) |lhs_val| {
20882292 if (casted_rhs.value()) |rhs_val| {
20892293 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2090 return mod.constInst(scope, inst.base.src, .{
2294 return sema.mod.constInst(scope, inst.base.src, .{
20912295 .ty = resolved_type,
20922296 .val = Value.initTag(.undef),
20932297 });
20942298 }
2095 return mod.fail(scope, inst.base.src, "TODO implement comptime bitwise operations", .{});
2299 return sema.mod.fail(&block.base, inst.base.src, "TODO implement comptime bitwise operations", .{});
20962300 }
20972301 }
20982302
2099 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
2303 try sema.requireRuntimeBlock(block, inst.base.src);
21002304 const ir_tag = switch (inst.base.tag) {
21012305 .bit_and => Inst.Tag.bit_and,
21022306 .bit_or => Inst.Tag.bit_or,
......@@ -2107,35 +2311,36 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
21072311 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
21082312}
21092313
2110fn zirBitNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2314fn zirBitNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
21112315 const tracy = trace(@src());
21122316 defer tracy.end();
2113 return mod.fail(scope, inst.base.src, "TODO implement zirBitNot", .{});
2317 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirBitNot", .{});
21142318}
21152319
2116fn zirArrayCat(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2320fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
21172321 const tracy = trace(@src());
21182322 defer tracy.end();
2119 return mod.fail(scope, inst.base.src, "TODO implement zirArrayCat", .{});
2323 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirArrayCat", .{});
21202324}
21212325
2122fn zirArrayMul(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2326fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
21232327 const tracy = trace(@src());
21242328 defer tracy.end();
2125 return mod.fail(scope, inst.base.src, "TODO implement zirArrayMul", .{});
2329 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirArrayMul", .{});
21262330}
21272331
2128fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2332fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
21292333 const tracy = trace(@src());
21302334 defer tracy.end();
21312335
2132 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);
2133 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);
2336 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2337 const lhs = sema.resolveInst(bin_inst.lhs);
2338 const rhs = sema.resolveInst(bin_inst.rhs);
21342339
21352340 const instructions = &[_]*Inst{ lhs, rhs };
2136 const resolved_type = try mod.resolvePeerTypes(scope, instructions);
2137 const casted_lhs = try mod.coerce(scope, resolved_type, lhs);
2138 const casted_rhs = try mod.coerce(scope, resolved_type, rhs);
2341 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2342 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2343 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
21392344
21402345 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
21412346 resolved_type.elemType()
......@@ -2146,14 +2351,14 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
21462351
21472352 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
21482353 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2149 return mod.fail(scope, inst.base.src, "vector length mismatch: {d} and {d}", .{
2354 return sema.mod.fail(&block.base, inst.base.src, "vector length mismatch: {d} and {d}", .{
21502355 lhs.ty.arrayLen(),
21512356 rhs.ty.arrayLen(),
21522357 });
21532358 }
2154 return mod.fail(scope, inst.base.src, "TODO implement support for vectors in zirBinOp", .{});
2359 return sema.mod.fail(&block.base, inst.base.src, "TODO implement support for vectors in zirBinOp", .{});
21552360 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
2156 return mod.fail(scope, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
2361 return sema.mod.fail(&block.base, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
21572362 lhs.ty,
21582363 rhs.ty,
21592364 });
......@@ -2163,13 +2368,13 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
21632368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
21642369
21652370 if (!is_int and !(is_float and floatOpAllowed(inst.base.tag))) {
2166 return mod.fail(scope, inst.base.src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
2371 return sema.mod.fail(&block.base, inst.base.src, "invalid operands to binary expression: '{s}' and '{s}'", .{ @tagName(lhs.ty.zigTypeTag()), @tagName(rhs.ty.zigTypeTag()) });
21672372 }
21682373
21692374 if (casted_lhs.value()) |lhs_val| {
21702375 if (casted_rhs.value()) |rhs_val| {
21712376 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2172 return mod.constInst(scope, inst.base.src, .{
2377 return sema.mod.constInst(scope, inst.base.src, .{
21732378 .ty = resolved_type,
21742379 .val = Value.initTag(.undef),
21752380 });
......@@ -2178,7 +2383,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
21782383 }
21792384 }
21802385
2181 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
2386 try sema.requireRuntimeBlock(block, inst.base.src);
21822387 const ir_tag: Inst.Tag = switch (inst.base.tag) {
21832388 .add => .add,
21842389 .addwrap => .addwrap,
......@@ -2186,18 +2391,18 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
21862391 .subwrap => .subwrap,
21872392 .mul => .mul,
21882393 .mulwrap => .mulwrap,
2189 else => return mod.fail(scope, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
2394 else => return sema.mod.fail(&block.base, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
21902395 };
21912396
21922397 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
21932398}
21942399
21952400/// Analyzes operands that are known at comptime
2196fn analyzeInstComptimeOp(mod: *Module, scope: *Scope, res_type: Type, inst: *zir.Inst.BinOp, lhs_val: Value, rhs_val: Value) InnerError!*Inst {
2401fn analyzeInstComptimeOp(sema: *Sema, block: *Scope.Block, res_type: Type, inst: zir.Inst.Index, lhs_val: Value, rhs_val: Value) InnerError!*Inst {
21972402 // incase rhs is 0, simply return lhs without doing any calculations
21982403 // TODO Once division is implemented we should throw an error when dividing by 0.
21992404 if (rhs_val.compareWithZero(.eq)) {
2200 return mod.constInst(scope, inst.base.src, .{
2405 return sema.mod.constInst(scope, inst.base.src, .{
22012406 .ty = res_type,
22022407 .val = lhs_val,
22032408 });
......@@ -2207,89 +2412,117 @@ fn analyzeInstComptimeOp(mod: *Module, scope: *Scope, res_type: Type, inst: *zir
22072412 const value = switch (inst.base.tag) {
22082413 .add => blk: {
22092414 const val = if (is_int)
2210 try Module.intAdd(scope.arena(), lhs_val, rhs_val)
2415 try Module.intAdd(block.arena, lhs_val, rhs_val)
22112416 else
22122417 try mod.floatAdd(scope, res_type, inst.base.src, lhs_val, rhs_val);
22132418 break :blk val;
22142419 },
22152420 .sub => blk: {
22162421 const val = if (is_int)
2217 try Module.intSub(scope.arena(), lhs_val, rhs_val)
2422 try Module.intSub(block.arena, lhs_val, rhs_val)
22182423 else
22192424 try mod.floatSub(scope, res_type, inst.base.src, lhs_val, rhs_val);
22202425 break :blk val;
22212426 },
2222 else => return mod.fail(scope, inst.base.src, "TODO Implement arithmetic operand '{s}'", .{@tagName(inst.base.tag)}),
2427 else => return sema.mod.fail(&block.base, inst.base.src, "TODO Implement arithmetic operand '{s}'", .{@tagName(inst.base.tag)}),
22232428 };
22242429
22252430 log.debug("{s}({}, {}) result: {}", .{ @tagName(inst.base.tag), lhs_val, rhs_val, value });
22262431
2227 return mod.constInst(scope, inst.base.src, .{
2432 return sema.mod.constInst(scope, inst.base.src, .{
22282433 .ty = res_type,
22292434 .val = value,
22302435 });
22312436}
22322437
2233fn zirDeref(mod: *Module, scope: *Scope, deref: *zir.Inst.UnOp) InnerError!*Inst {
2438fn zirDeref(sema: *Sema, block: *Scope.Block, deref: zir.Inst.Index) InnerError!*Inst {
22342439 const tracy = trace(@src());
22352440 defer tracy.end();
2236 const ptr = try resolveInst(mod, scope, deref.positionals.operand);
2237 return mod.analyzeDeref(scope, deref.base.src, ptr, deref.positionals.operand.src);
2441
2442 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2443 const src = inst_data.src();
2444 const ptr_src: LazySrcLoc = .{ .node_offset_deref_ptr = inst_data.src_node };
2445 const ptr = sema.resolveInst(block, inst_data.operand);
2446 return sema.analyzeDeref(block, src, ptr, ptr_src);
22382447}
22392448
2240fn zirAsm(mod: *Module, scope: *Scope, assembly: *zir.Inst.Asm) InnerError!*Inst {
2449fn zirAsm(
2450 sema: *Sema,
2451 block: *Scope.Block,
2452 assembly: zir.Inst.Index,
2453 is_volatile: bool,
2454) InnerError!*Inst {
22412455 const tracy = trace(@src());
22422456 defer tracy.end();
22432457
2244 const return_type = try resolveType(mod, scope, assembly.positionals.return_type);
2245 const asm_source = try resolveConstString(mod, scope, assembly.positionals.asm_source);
2246 const output = if (assembly.kw_args.output) |o| try resolveConstString(mod, scope, o) else null;
2458 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2459 const src = inst_data.src();
2460 const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = inst_data.src_node };
2461 const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = inst_data.src_node };
2462 const extra = sema.code.extraData(zir.Inst.Asm, inst_data.payload_index);
2463 const return_type = try sema.resolveType(block, ret_ty_src, extra.data.return_type);
2464 const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source);
2465
2466 var extra_i = extra.end;
2467 const output = if (extra.data.output != 0) blk: {
2468 const name = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2469 extra_i += 1;
2470 break :blk .{
2471 .name = name,
2472 .inst = try sema.resolveInst(block, extra.data.output),
2473 };
2474 } else null;
22472475
2248 const arena = scope.arena();
2249 const inputs = try arena.alloc([]const u8, assembly.kw_args.inputs.len);
2250 const clobbers = try arena.alloc([]const u8, assembly.kw_args.clobbers.len);
2251 const args = try arena.alloc(*Inst, assembly.kw_args.args.len);
2476 const args = try block.arena.alloc(*Inst, extra.data.args.len);
2477 const inputs = try block.arena.alloc([]const u8, extra.data.args_len);
2478 const clobbers = try block.arena.alloc([]const u8, extra.data.clobbers_len);
22522479
2253 for (inputs) |*elem, i| {
2254 elem.* = try arena.dupe(u8, assembly.kw_args.inputs[i]);
2480 for (args) |*arg| {
2481 const uncasted = sema.resolveInst(block, sema.code.extra[extra_i]);
2482 extra_i += 1;
2483 arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted);
22552484 }
2256 for (clobbers) |*elem, i| {
2257 elem.* = try arena.dupe(u8, assembly.kw_args.clobbers[i]);
2485 for (inputs) |*name| {
2486 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2487 extra_i += 1;
22582488 }
2259 for (args) |*elem, i| {
2260 const arg = try resolveInst(mod, scope, assembly.kw_args.args[i]);
2261 elem.* = try mod.coerce(scope, Type.initTag(.usize), arg);
2489 for (clobbers) |*name| {
2490 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2491 extra_i += 1;
22622492 }
22632493
2264 const b = try mod.requireRuntimeBlock(scope, assembly.base.src);
2265 const inst = try b.arena.create(Inst.Assembly);
2494 try sema.requireRuntimeBlock(block, src);
2495 const inst = try block.arena.create(Inst.Assembly);
22662496 inst.* = .{
22672497 .base = .{
22682498 .tag = .assembly,
22692499 .ty = return_type,
2270 .src = assembly.base.src,
2500 .src = src,
22712501 },
22722502 .asm_source = asm_source,
2273 .is_volatile = assembly.kw_args.@"volatile",
2274 .output = output,
2503 .is_volatile = is_volatile,
2504 .output = if (output) |o| o.inst else null,
2505 .output_name = if (output) |o| o.name else null,
22752506 .inputs = inputs,
22762507 .clobbers = clobbers,
22772508 .args = args,
22782509 };
2279 try b.instructions.append(mod.gpa, &inst.base);
2510 try block.instructions.append(mod.gpa, &inst.base);
22802511 return &inst.base;
22812512}
22822513
22832514fn zirCmp(
2284 mod: *Module,
2285 scope: *Scope,
2286 inst: *zir.Inst.BinOp,
2515 sema: *Sema,
2516 block: *Scope.Block,
2517 inst: zir.Inst.Index,
22872518 op: std.math.CompareOperator,
22882519) InnerError!*Inst {
22892520 const tracy = trace(@src());
22902521 defer tracy.end();
2291 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);
2292 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);
2522
2523 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2524 const lhs = sema.resolveInst(bin_inst.lhs);
2525 const rhs = sema.resolveInst(bin_inst.rhs);
22932526
22942527 const is_equality_cmp = switch (op) {
22952528 .eq, .neq => true,
......@@ -2299,37 +2532,37 @@ fn zirCmp(
22992532 const rhs_ty_tag = rhs.ty.zigTypeTag();
23002533 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
23012534 // null == null, null != null
2302 return mod.constBool(scope, inst.base.src, op == .eq);
2535 return mod.constBool(block.arena, inst.base.src, op == .eq);
23032536 } else if (is_equality_cmp and
23042537 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
23052538 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
23062539 {
23072540 // comparing null with optionals
23082541 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
2309 return mod.analyzeIsNull(scope, inst.base.src, opt_operand, op == .neq);
2542 return sema.analyzeIsNull(block, inst.base.src, opt_operand, op == .neq);
23102543 } else if (is_equality_cmp and
23112544 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
23122545 {
2313 return mod.fail(scope, inst.base.src, "TODO implement C pointer cmp", .{});
2546 return sema.mod.fail(&block.base, inst.base.src, "TODO implement C pointer cmp", .{});
23142547 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
23152548 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
2316 return mod.fail(scope, inst.base.src, "comparison of '{}' with null", .{non_null_type});
2549 return sema.mod.fail(&block.base, inst.base.src, "comparison of '{}' with null", .{non_null_type});
23172550 } else if (is_equality_cmp and
23182551 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
23192552 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
23202553 {
2321 return mod.fail(scope, inst.base.src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
2554 return sema.mod.fail(&block.base, inst.base.src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
23222555 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
23232556 if (!is_equality_cmp) {
2324 return mod.fail(scope, inst.base.src, "{s} operator not allowed for errors", .{@tagName(op)});
2557 return sema.mod.fail(&block.base, inst.base.src, "{s} operator not allowed for errors", .{@tagName(op)});
23252558 }
23262559 if (rhs.value()) |rval| {
23272560 if (lhs.value()) |lval| {
23282561 // TODO optimisation oppurtunity: evaluate if std.mem.eql is faster with the names, or calling to Module.getErrorValue to get the values and then compare them is faster
2329 return mod.constBool(scope, inst.base.src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
2562 return mod.constBool(block.arena, inst.base.src, std.mem.eql(u8, lval.castTag(.@"error").?.data.name, rval.castTag(.@"error").?.data.name) == (op == .eq));
23302563 }
23312564 }
2332 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
2565 try sema.requireRuntimeBlock(block, inst.base.src);
23332566 return mod.addBinOp(b, inst.base.src, Type.initTag(.bool), if (op == .eq) .cmp_eq else .cmp_neq, lhs, rhs);
23342567 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {
23352568 // This operation allows any combination of integer and float types, regardless of the
......@@ -2338,110 +2571,153 @@ fn zirCmp(
23382571 return mod.cmpNumeric(scope, inst.base.src, lhs, rhs, op);
23392572 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
23402573 if (!is_equality_cmp) {
2341 return mod.fail(scope, inst.base.src, "{s} operator not allowed for types", .{@tagName(op)});
2574 return sema.mod.fail(&block.base, inst.base.src, "{s} operator not allowed for types", .{@tagName(op)});
23422575 }
2343 return mod.constBool(scope, inst.base.src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
2576 return mod.constBool(block.arena, inst.base.src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
23442577 }
2345 return mod.fail(scope, inst.base.src, "TODO implement more cmp analysis", .{});
2578 return sema.mod.fail(&block.base, inst.base.src, "TODO implement more cmp analysis", .{});
23462579}
23472580
2348fn zirTypeof(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2581fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
23492582 const tracy = trace(@src());
23502583 defer tracy.end();
2351 const operand = try resolveInst(mod, scope, inst.positionals.operand);
2352 return mod.constType(scope, inst.base.src, operand.ty);
2584
2585 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2586 const operand = sema.resolveInst(block, inst_data.operand);
2587 return sema.mod.constType(block.arena, inst_data.src(), operand.ty);
23532588}
23542589
2355fn zirTypeofPeer(mod: *Module, scope: *Scope, inst: *zir.Inst.TypeOfPeer) InnerError!*Inst {
2590fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
23562591 const tracy = trace(@src());
23572592 defer tracy.end();
2358 var insts_to_res = try mod.gpa.alloc(*ir.Inst, inst.positionals.items.len);
2359 defer mod.gpa.free(insts_to_res);
2360 for (inst.positionals.items) |item, i| {
2361 insts_to_res[i] = try resolveInst(mod, scope, item);
2593
2594 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2595 const src = inst_data.src();
2596 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
2597
2598 const inst_list = try mod.gpa.alloc(*ir.Inst, extra.data.operands_len);
2599 defer mod.gpa.free(inst_list);
2600
2601 const src_list = try mod.gpa.alloc(LazySrcLoc, extra.data.operands_len);
2602 defer mod.gpa.free(src_list);
2603
2604 for (sema.code.extra[extra.end..][0..extra.data.operands_len]) |arg_ref, i| {
2605 inst_list[i] = sema.resolveInst(block, arg_ref);
2606 src_list[i] = .{ .node_offset_builtin_call_argn = inst_data.src_node };
23622607 }
2363 const pt_res = try mod.resolvePeerTypes(scope, insts_to_res);
2364 return mod.constType(scope, inst.base.src, pt_res);
2608
2609 const result_type = try sema.resolvePeerTypes(block, inst_list, src_list);
2610 return sema.mod.constType(block.arena, src, result_type);
23652611}
23662612
2367fn zirBoolNot(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2613fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
23682614 const tracy = trace(@src());
23692615 defer tracy.end();
2370 const uncasted_operand = try resolveInst(mod, scope, inst.positionals.operand);
2616
2617 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2618 const src = inst_data.src();
2619 const uncasted_operand = sema.resolveInst(block, inst_data.operand);
2620
23712621 const bool_type = Type.initTag(.bool);
2372 const operand = try mod.coerce(scope, bool_type, uncasted_operand);
2622 const operand = try sema.coerce(scope, bool_type, uncasted_operand);
23732623 if (try mod.resolveDefinedValue(scope, operand)) |val| {
2374 return mod.constBool(scope, inst.base.src, !val.toBool());
2624 return mod.constBool(block.arena, src, !val.toBool());
23752625 }
2376 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
2377 return mod.addUnOp(b, inst.base.src, bool_type, .not, operand);
2626 try sema.requireRuntimeBlock(block, src);
2627 return block.addUnOp(src, bool_type, .not, operand);
23782628}
23792629
2380fn zirBoolOp(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*Inst {
2630fn zirBoolOp(
2631 sema: *Sema,
2632 block: *Scope.Block,
2633 inst: zir.Inst.Index,
2634 comptime is_bool_or: bool,
2635) InnerError!*Inst {
23812636 const tracy = trace(@src());
23822637 defer tracy.end();
2383 const bool_type = Type.initTag(.bool);
2384 const uncasted_lhs = try resolveInst(mod, scope, inst.positionals.lhs);
2385 const lhs = try mod.coerce(scope, bool_type, uncasted_lhs);
2386 const uncasted_rhs = try resolveInst(mod, scope, inst.positionals.rhs);
2387 const rhs = try mod.coerce(scope, bool_type, uncasted_rhs);
23882638
2389 const is_bool_or = inst.base.tag == .bool_or;
2639 const bool_type = Type.initTag(.bool);
2640 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2641 const uncasted_lhs = sema.resolveInst(bin_inst.lhs);
2642 const lhs = try sema.coerce(scope, bool_type, uncasted_lhs);
2643 const uncasted_rhs = sema.resolveInst(bin_inst.rhs);
2644 const rhs = try sema.coerce(scope, bool_type, uncasted_rhs);
23902645
23912646 if (lhs.value()) |lhs_val| {
23922647 if (rhs.value()) |rhs_val| {
23932648 if (is_bool_or) {
2394 return mod.constBool(scope, inst.base.src, lhs_val.toBool() or rhs_val.toBool());
2649 return mod.constBool(block.arena, inst.base.src, lhs_val.toBool() or rhs_val.toBool());
23952650 } else {
2396 return mod.constBool(scope, inst.base.src, lhs_val.toBool() and rhs_val.toBool());
2651 return mod.constBool(block.arena, inst.base.src, lhs_val.toBool() and rhs_val.toBool());
23972652 }
23982653 }
23992654 }
2400 const b = try mod.requireRuntimeBlock(scope, inst.base.src);
2401 return mod.addBinOp(b, inst.base.src, bool_type, if (is_bool_or) .bool_or else .bool_and, lhs, rhs);
2655 try sema.requireRuntimeBlock(block, inst.base.src);
2656 const tag: ir.Inst.Tag = if (is_bool_or) .bool_or else .bool_and;
2657 return mod.addBinOp(b, inst.base.src, bool_type, tag, lhs, rhs);
24022658}
24032659
2404fn zirIsNull(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {
2660fn zirIsNull(
2661 sema: *Sema,
2662 block: *Scope.Block,
2663 inst: zir.Inst.Index,
2664 invert_logic: bool,
2665) InnerError!*Inst {
24052666 const tracy = trace(@src());
24062667 defer tracy.end();
2407 const operand = try resolveInst(mod, scope, inst.positionals.operand);
2408 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);
2668
2669 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2670 const src = inst_data.src();
2671 const operand = sema.resolveInst(block, inst_data.operand);
2672 return sema.analyzeIsNull(block, src, operand, invert_logic);
24092673}
24102674
2411fn zirIsNullPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, invert_logic: bool) InnerError!*Inst {
2675fn zirIsNullPtr(
2676 sema: *Sema,
2677 block: *Scope.Block,
2678 inst: zir.Inst.Index,
2679 invert_logic: bool,
2680) InnerError!*Inst {
24122681 const tracy = trace(@src());
24132682 defer tracy.end();
2414 const ptr = try resolveInst(mod, scope, inst.positionals.operand);
2415 const loaded = try mod.analyzeDeref(scope, inst.base.src, ptr, ptr.src);
2416 return mod.analyzeIsNull(scope, inst.base.src, loaded, invert_logic);
2683
2684 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2685 const src = inst_data.src();
2686 const ptr = sema.resolveInst(block, inst_data.operand);
2687 const loaded = try sema.analyzeDeref(block, src, ptr, src);
2688 return sema.analyzeIsNull(block, src, loaded, invert_logic);
24172689}
24182690
2419fn zirIsErr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2691fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
24202692 const tracy = trace(@src());
24212693 defer tracy.end();
2422 const operand = try resolveInst(mod, scope, inst.positionals.operand);
2423 return mod.analyzeIsErr(scope, inst.base.src, operand);
2694
2695 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2696 const operand = sema.resolveInst(block, inst_data.operand);
2697 return mod.analyzeIsErr(scope, inst_data.src(), operand);
24242698}
24252699
2426fn zirIsErrPtr(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2700fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
24272701 const tracy = trace(@src());
24282702 defer tracy.end();
2429 const ptr = try resolveInst(mod, scope, inst.positionals.operand);
2430 const loaded = try mod.analyzeDeref(scope, inst.base.src, ptr, ptr.src);
2431 return mod.analyzeIsErr(scope, inst.base.src, loaded);
2703
2704 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2705 const src = inst_data.src();
2706 const ptr = sema.resolveInst(block, inst_data.operand);
2707 const loaded = try sema.analyzeDeref(block, src, ptr, src);
2708 return mod.analyzeIsErr(scope, src, loaded);
24322709}
24332710
2434fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*Inst {
2711fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
24352712 const tracy = trace(@src());
24362713 defer tracy.end();
2437 const uncasted_cond = try resolveInst(mod, scope, inst.positionals.condition);
2438 const cond = try mod.coerce(scope, Type.initTag(.bool), uncasted_cond);
24392714
2440 const parent_block = scope.cast(Scope.Block).?;
2715 const uncasted_cond = sema.resolveInst(block, inst.positionals.condition);
2716 const cond = try sema.coerce(scope, Type.initTag(.bool), uncasted_cond);
24412717
24422718 if (try mod.resolveDefinedValue(scope, cond)) |cond_val| {
24432719 const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body;
2444 try analyzeBody(mod, parent_block, body.*);
2720 try sema.body(parent_block, body.*);
24452721 return mod.constNoReturn(scope, inst.base.src);
24462722 }
24472723
......@@ -2458,7 +2734,7 @@ fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*In
24582734 .branch_quota = parent_block.branch_quota,
24592735 };
24602736 defer true_block.instructions.deinit(mod.gpa);
2461 try analyzeBody(mod, &true_block, inst.positionals.then_body);
2737 try sema.body(&true_block, inst.positionals.then_body);
24622738
24632739 var false_block: Scope.Block = .{
24642740 .parent = parent_block,
......@@ -2473,68 +2749,37 @@ fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*In
24732749 .branch_quota = parent_block.branch_quota,
24742750 };
24752751 defer false_block.instructions.deinit(mod.gpa);
2476 try analyzeBody(mod, &false_block, inst.positionals.else_body);
2752 try sema.body(&false_block, inst.positionals.else_body);
24772753
2478 const then_body: ir.Body = .{ .instructions = try scope.arena().dupe(*Inst, true_block.instructions.items) };
2479 const else_body: ir.Body = .{ .instructions = try scope.arena().dupe(*Inst, false_block.instructions.items) };
2754 const then_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, true_block.instructions.items) };
2755 const else_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, false_block.instructions.items) };
24802756 return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body);
24812757}
24822758
24832759fn zirUnreachable(
2484 mod: *Module,
2485 scope: *Scope,
2486 unreach: *zir.Inst.NoOp,
2760 sema: *Sema,
2761 block: *Scope.Block,
2762 zir_index: zir.Inst.Index,
24872763 safety_check: bool,
24882764) InnerError!*Inst {
24892765 const tracy = trace(@src());
24902766 defer tracy.end();
2491 const b = try mod.requireRuntimeBlock(scope, unreach.base.src);
2767
2768 try sema.requireRuntimeBlock(block, zir_index.base.src);
24922769 // TODO Add compile error for @optimizeFor occurring too late in a scope.
2493 if (safety_check and mod.wantSafety(scope)) {
2494 return mod.safetyPanic(b, unreach.base.src, .unreach);
2770 if (safety_check and block.wantSafety()) {
2771 return mod.safetyPanic(b, zir_index.base.src, .unreach);
24952772 } else {
2496 return mod.addNoOp(b, unreach.base.src, Type.initTag(.noreturn), .unreach);
2773 return block.addNoOp(zir_index.base.src, Type.initTag(.noreturn), .unreach);
24972774 }
24982775}
24992776
2500fn zirReturn(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {
2501 const tracy = trace(@src());
2502 defer tracy.end();
2503 const operand = try resolveInst(mod, scope, inst.positionals.operand);
2504 const b = try mod.requireFunctionBlock(scope, inst.base.src);
2505
2506 if (b.inlining) |inlining| {
2507 // We are inlining a function call; rewrite the `ret` as a `break`.
2508 try inlining.merges.results.append(mod.gpa, operand);
2509 const br = try mod.addBr(b, inst.base.src, inlining.merges.block_inst, operand);
2510 return &br.base;
2511 }
2512
2513 return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, operand);
2777fn zirRetTok(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2778 @compileError("TODO");
25142779}
25152780
2516fn zirReturnVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {
2517 const tracy = trace(@src());
2518 defer tracy.end();
2519 const b = try mod.requireFunctionBlock(scope, inst.base.src);
2520 if (b.inlining) |inlining| {
2521 // We are inlining a function call; rewrite the `retvoid` as a `breakvoid`.
2522 const void_inst = try mod.constVoid(scope, inst.base.src);
2523 try inlining.merges.results.append(mod.gpa, void_inst);
2524 const br = try mod.addBr(b, inst.base.src, inlining.merges.block_inst, void_inst);
2525 return &br.base;
2526 }
2527
2528 if (b.func) |func| {
2529 // Need to emit a compile error if returning void is not allowed.
2530 const void_inst = try mod.constVoid(scope, inst.base.src);
2531 const fn_ty = func.owner_decl.typed_value.most_recent.typed_value.ty;
2532 const casted_void = try mod.coerce(scope, fn_ty.fnReturnType(), void_inst);
2533 if (casted_void.ty.zigTypeTag() != .Void) {
2534 return mod.addUnOp(b, inst.base.src, Type.initTag(.noreturn), .ret, casted_void);
2535 }
2536 }
2537 return mod.addNoOp(b, inst.base.src, Type.initTag(.noreturn), .retvoid);
2781fn zirRetNode(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2782 @compileError("TODO");
25382783}
25392784
25402785fn floatOpAllowed(tag: zir.Inst.Tag) bool {
......@@ -2545,53 +2790,1080 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool {
25452790 };
25462791}
25472792
2548fn zirSimplePtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp, mutable: bool, size: std.builtin.TypeInfo.Pointer.Size) InnerError!*Inst {
2793fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
25492794 const tracy = trace(@src());
25502795 defer tracy.end();
2551 const elem_type = try resolveType(mod, scope, inst.positionals.operand);
2552 const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size);
2553 return mod.constType(scope, inst.base.src, ty);
2796
2797 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
2798 const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type);
2799 const ty = try sema.mod.ptrType(
2800 block.arena,
2801 elem_type,
2802 null,
2803 0,
2804 0,
2805 0,
2806 inst_data.is_mutable,
2807 inst_data.is_allowzero,
2808 inst_data.is_volatile,
2809 inst_data.size,
2810 );
2811 return sema.mod.constType(block.arena, .unneeded, ty);
25542812}
25552813
2556fn zirPtrType(mod: *Module, scope: *Scope, inst: *zir.Inst.PtrType) InnerError!*Inst {
2814fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
25572815 const tracy = trace(@src());
25582816 defer tracy.end();
2559 // TODO lazy values
2560 const @"align" = if (inst.kw_args.@"align") |some|
2561 @truncate(u32, try resolveInt(mod, scope, some, Type.initTag(.u32)))
2562 else
2563 0;
2564 const bit_offset = if (inst.kw_args.align_bit_start) |some|
2565 @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16)))
2566 else
2567 0;
2568 const host_size = if (inst.kw_args.align_bit_end) |some|
2569 @truncate(u16, try resolveInt(mod, scope, some, Type.initTag(.u16)))
2570 else
2571 0;
25722817
2573 if (host_size != 0 and bit_offset >= host_size * 8)
2574 return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{});
2818 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
2819 const extra = sema.code.extraData(zir.Inst.PtrType, inst_data.payload_index);
25752820
2576 const sentinel = if (inst.kw_args.sentinel) |some|
2577 (try resolveInstConst(mod, scope, some)).val
2578 else
2579 null;
2821 var extra_i = extra.end;
2822
2823 const sentinel = if (inst_data.flags.has_sentinel) blk: {
2824 const ref = sema.code.extra[extra_i];
2825 extra_i += 1;
2826 break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
2827 } else null;
2828
2829 const abi_align = if (inst_data.flags.has_align) blk: {
2830 const ref = sema.code.extra[extra_i];
2831 extra_i += 1;
2832 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32);
2833 } else 0;
2834
2835 const bit_start = if (inst_data.flags.has_bit_start) blk: {
2836 const ref = sema.code.extra[extra_i];
2837 extra_i += 1;
2838 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
2839 } else 0;
25802840
2581 const elem_type = try resolveType(mod, scope, inst.positionals.child_type);
2841 const bit_end = if (inst_data.flags.has_bit_end) blk: {
2842 const ref = sema.code.extra[extra_i];
2843 extra_i += 1;
2844 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
2845 } else 0;
2846
2847 if (bit_end != 0 and bit_offset >= bit_end * 8)
2848 return sema.mod.fail(&block.base, inst.base.src, "bit offset starts after end of host integer", .{});
2849
2850 const elem_type = try sema.resolveType(block, extra.data.elem_type);
25822851
25832852 const ty = try mod.ptrType(
25842853 scope,
2585 inst.base.src,
25862854 elem_type,
25872855 sentinel,
2588 @"align",
2589 bit_offset,
2590 host_size,
2591 inst.kw_args.mutable,
2592 inst.kw_args.@"allowzero",
2593 inst.kw_args.@"volatile",
2594 inst.kw_args.size,
2856 abi_align,
2857 bit_start,
2858 bit_end,
2859 inst_data.flags.is_mutable,
2860 inst_data.flags.is_allowzero,
2861 inst_data.flags.is_volatile,
2862 inst_data.size,
25952863 );
2596 return mod.constType(scope, inst.base.src, ty);
2864 return sema.mod.constType(block.arena, .unneeded, ty);
2865}
2866
2867fn requireFunctionBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
2868 if (sema.func == null) {
2869 return sema.mod.fail(&block.base, src, "instruction illegal outside function body", .{});
2870 }
2871}
2872
2873fn requireRuntimeBlock(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
2874 try sema.requireFunctionBlock(scope, src);
2875 if (block.is_comptime) {
2876 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
2877 }
2878}
2879
2880fn validateVarType(sema: *Module, block: *Scope.Block, src: LazySrcLoc, ty: Type) !void {
2881 if (!ty.isValidVarType(false)) {
2882 return mod.fail(&block.base, src, "variable of type '{}' must be const or comptime", .{ty});
2883 }
2884}
2885
2886pub const PanicId = enum {
2887 unreach,
2888 unwrap_null,
2889 unwrap_errunion,
2890};
2891
2892fn addSafetyCheck(sema: *Sema, parent_block: *Scope.Block, ok: *Inst, panic_id: PanicId) !void {
2893 const block_inst = try parent_block.arena.create(Inst.Block);
2894 block_inst.* = .{
2895 .base = .{
2896 .tag = Inst.Block.base_tag,
2897 .ty = Type.initTag(.void),
2898 .src = ok.src,
2899 },
2900 .body = .{
2901 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the condbr.
2902 },
2903 };
2904
2905 const ok_body: ir.Body = .{
2906 .instructions = try parent_block.arena.alloc(*Inst, 1), // Only need space for the br_void.
2907 };
2908 const br_void = try parent_block.arena.create(Inst.BrVoid);
2909 br_void.* = .{
2910 .base = .{
2911 .tag = .br_void,
2912 .ty = Type.initTag(.noreturn),
2913 .src = ok.src,
2914 },
2915 .block = block_inst,
2916 };
2917 ok_body.instructions[0] = &br_void.base;
2918
2919 var fail_block: Scope.Block = .{
2920 .parent = parent_block,
2921 .inst_map = parent_block.inst_map,
2922 .func = parent_block.func,
2923 .owner_decl = parent_block.owner_decl,
2924 .src_decl = parent_block.src_decl,
2925 .instructions = .{},
2926 .arena = parent_block.arena,
2927 .inlining = parent_block.inlining,
2928 .is_comptime = parent_block.is_comptime,
2929 .branch_quota = parent_block.branch_quota,
2930 };
2931
2932 defer fail_block.instructions.deinit(mod.gpa);
2933
2934 _ = try mod.safetyPanic(&fail_block, ok.src, panic_id);
2935
2936 const fail_body: ir.Body = .{ .instructions = try parent_block.arena.dupe(*Inst, fail_block.instructions.items) };
2937
2938 const condbr = try parent_block.arena.create(Inst.CondBr);
2939 condbr.* = .{
2940 .base = .{
2941 .tag = .condbr,
2942 .ty = Type.initTag(.noreturn),
2943 .src = ok.src,
2944 },
2945 .condition = ok,
2946 .then_body = ok_body,
2947 .else_body = fail_body,
2948 };
2949 block_inst.body.instructions[0] = &condbr.base;
2950
2951 try parent_block.instructions.append(mod.gpa, &block_inst.base);
2952}
2953
2954fn safetyPanic(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, panic_id: PanicId) !*Inst {
2955 // TODO Once we have a panic function to call, call it here instead of breakpoint.
2956 _ = try mod.addNoOp(block, src, Type.initTag(.void), .breakpoint);
2957 return mod.addNoOp(block, src, Type.initTag(.noreturn), .unreach);
2958}
2959
2960fn emitBackwardBranch(sema: *Sema, block: *Scope.Block, src: LazySrcLoc) !void {
2961 const shared = block.inlining.?.shared;
2962 shared.branch_count += 1;
2963 if (shared.branch_count > block.branch_quota.*) {
2964 // TODO show the "called from here" stack
2965 return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{
2966 block.branch_quota.*,
2967 });
2968 }
2969}
2970
2971fn namedFieldPtr(
2972 sema: *Sema,
2973 block: *Scope.Block,
2974 src: LazySrcLoc,
2975 object_ptr: *Inst,
2976 field_name: []const u8,
2977 field_name_src: LazySrcLoc,
2978) InnerError!*Inst {
2979 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {
2980 .Pointer => object_ptr.ty.elemType(),
2981 else => return sema.mod.fail(&block.base, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),
2982 };
2983 switch (elem_ty.zigTypeTag()) {
2984 .Array => {
2985 if (mem.eql(u8, field_name, "len")) {
2986 return mod.constInst(scope, src, .{
2987 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
2988 .val = try Value.Tag.ref_val.create(
2989 scope.arena(),
2990 try Value.Tag.int_u64.create(scope.arena(), elem_ty.arrayLen()),
2991 ),
2992 });
2993 } else {
2994 return mod.fail(
2995 scope,
2996 field_name_src,
2997 "no member named '{s}' in '{}'",
2998 .{ field_name, elem_ty },
2999 );
3000 }
3001 },
3002 .Pointer => {
3003 const ptr_child = elem_ty.elemType();
3004 switch (ptr_child.zigTypeTag()) {
3005 .Array => {
3006 if (mem.eql(u8, field_name, "len")) {
3007 return mod.constInst(scope, src, .{
3008 .ty = Type.initTag(.single_const_pointer_to_comptime_int),
3009 .val = try Value.Tag.ref_val.create(
3010 scope.arena(),
3011 try Value.Tag.int_u64.create(scope.arena(), ptr_child.arrayLen()),
3012 ),
3013 });
3014 } else {
3015 return mod.fail(
3016 scope,
3017 field_name_src,
3018 "no member named '{s}' in '{}'",
3019 .{ field_name, elem_ty },
3020 );
3021 }
3022 },
3023 else => {},
3024 }
3025 },
3026 .Type => {
3027 _ = try sema.resolveConstValue(scope, object_ptr.src, object_ptr);
3028 const result = try sema.analyzeDeref(block, src, object_ptr, object_ptr.src);
3029 const val = result.value().?;
3030 const child_type = try val.toType(scope.arena());
3031 switch (child_type.zigTypeTag()) {
3032 .ErrorSet => {
3033 var name: []const u8 = undefined;
3034 // TODO resolve inferred error sets
3035 if (val.castTag(.error_set)) |payload|
3036 name = (payload.data.fields.getEntry(field_name) orelse return sema.mod.fail(&block.base, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).key
3037 else
3038 name = (try mod.getErrorValue(field_name)).key;
3039
3040 const result_type = if (child_type.tag() == .anyerror)
3041 try Type.Tag.error_set_single.create(scope.arena(), name)
3042 else
3043 child_type;
3044
3045 return mod.constInst(scope, src, .{
3046 .ty = try mod.simplePtrType(scope.arena(), result_type, false, .One),
3047 .val = try Value.Tag.ref_val.create(
3048 scope.arena(),
3049 try Value.Tag.@"error".create(scope.arena(), .{
3050 .name = name,
3051 }),
3052 ),
3053 });
3054 },
3055 .Struct => {
3056 const container_scope = child_type.getContainerScope();
3057 if (mod.lookupDeclName(&container_scope.base, field_name)) |decl| {
3058 // TODO if !decl.is_pub and inDifferentFiles() "{} is private"
3059 return sema.analyzeDeclRef(block, src, decl);
3060 }
3061
3062 if (container_scope.file_scope == mod.root_scope) {
3063 return sema.mod.fail(&block.base, src, "root source file has no member called '{s}'", .{field_name});
3064 } else {
3065 return sema.mod.fail(&block.base, src, "container '{}' has no member called '{s}'", .{ child_type, field_name });
3066 }
3067 },
3068 else => return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{child_type}),
3069 }
3070 },
3071 else => {},
3072 }
3073 return sema.mod.fail(&block.base, src, "type '{}' does not support field access", .{elem_ty});
3074}
3075
3076fn elemPtr(
3077 sema: *Sema,
3078 block: *Scope.Block,
3079 src: LazySrcLoc,
3080 array_ptr: *Inst,
3081 elem_index: *Inst,
3082 elem_index_src: LazySrcLoc,
3083) InnerError!*Inst {
3084 const elem_ty = switch (array_ptr.ty.zigTypeTag()) {
3085 .Pointer => array_ptr.ty.elemType(),
3086 else => return sema.mod.fail(&block.base, array_ptr.src, "expected pointer, found '{}'", .{array_ptr.ty}),
3087 };
3088 if (!elem_ty.isIndexable()) {
3089 return sema.mod.fail(&block.base, src, "array access of non-array type '{}'", .{elem_ty});
3090 }
3091
3092 if (elem_ty.isSinglePointer() and elem_ty.elemType().zigTypeTag() == .Array) {
3093 // we have to deref the ptr operand to get the actual array pointer
3094 const array_ptr_deref = try sema.analyzeDeref(block, src, array_ptr, array_ptr.src);
3095 if (array_ptr_deref.value()) |array_ptr_val| {
3096 if (elem_index.value()) |index_val| {
3097 // Both array pointer and index are compile-time known.
3098 const index_u64 = index_val.toUnsignedInt();
3099 // @intCast here because it would have been impossible to construct a value that
3100 // required a larger index.
3101 const elem_ptr = try array_ptr_val.elemPtr(scope.arena(), @intCast(usize, index_u64));
3102 const pointee_type = elem_ty.elemType().elemType();
3103
3104 return mod.constInst(scope, src, .{
3105 .ty = try Type.Tag.single_const_pointer.create(scope.arena(), pointee_type),
3106 .val = elem_ptr,
3107 });
3108 }
3109 }
3110 }
3111
3112 return sema.mod.fail(&block.base, src, "TODO implement more analyze elemptr", .{});
3113}
3114
3115fn coerce(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) InnerError!*Inst {
3116 if (dest_type.tag() == .var_args_param) {
3117 return sema.coerceVarArgParam(scope, inst);
3118 }
3119 // If the types are the same, we can return the operand.
3120 if (dest_type.eql(inst.ty))
3121 return inst;
3122
3123 const in_memory_result = coerceInMemoryAllowed(dest_type, inst.ty);
3124 if (in_memory_result == .ok) {
3125 return sema.bitcast(scope, dest_type, inst);
3126 }
3127
3128 // undefined to anything
3129 if (inst.value()) |val| {
3130 if (val.isUndef() or inst.ty.zigTypeTag() == .Undefined) {
3131 return mod.constInst(scope.arena(), inst.src, .{ .ty = dest_type, .val = val });
3132 }
3133 }
3134 assert(inst.ty.zigTypeTag() != .Undefined);
3135
3136 // null to ?T
3137 if (dest_type.zigTypeTag() == .Optional and inst.ty.zigTypeTag() == .Null) {
3138 return mod.constInst(scope.arena(), inst.src, .{ .ty = dest_type, .val = Value.initTag(.null_value) });
3139 }
3140
3141 // T to ?T
3142 if (dest_type.zigTypeTag() == .Optional) {
3143 var buf: Type.Payload.ElemType = undefined;
3144 const child_type = dest_type.optionalChild(&buf);
3145 if (child_type.eql(inst.ty)) {
3146 return mod.wrapOptional(scope, dest_type, inst);
3147 } else if (try sema.coerceNum(scope, child_type, inst)) |some| {
3148 return mod.wrapOptional(scope, dest_type, some);
3149 }
3150 }
3151
3152 // T to E!T or E to E!T
3153 if (dest_type.tag() == .error_union) {
3154 return try mod.wrapErrorUnion(scope, dest_type, inst);
3155 }
3156
3157 // Coercions where the source is a single pointer to an array.
3158 src_array_ptr: {
3159 if (!inst.ty.isSinglePointer()) break :src_array_ptr;
3160 const array_type = inst.ty.elemType();
3161 if (array_type.zigTypeTag() != .Array) break :src_array_ptr;
3162 const array_elem_type = array_type.elemType();
3163 if (inst.ty.isConstPtr() and !dest_type.isConstPtr()) break :src_array_ptr;
3164 if (inst.ty.isVolatilePtr() and !dest_type.isVolatilePtr()) break :src_array_ptr;
3165
3166 const dst_elem_type = dest_type.elemType();
3167 switch (coerceInMemoryAllowed(dst_elem_type, array_elem_type)) {
3168 .ok => {},
3169 .no_match => break :src_array_ptr,
3170 }
3171
3172 switch (dest_type.ptrSize()) {
3173 .Slice => {
3174 // *[N]T to []T
3175 return sema.coerceArrayPtrToSlice(scope, dest_type, inst);
3176 },
3177 .C => {
3178 // *[N]T to [*c]T
3179 return sema.coerceArrayPtrToMany(scope, dest_type, inst);
3180 },
3181 .Many => {
3182 // *[N]T to [*]T
3183 // *[N:s]T to [*:s]T
3184 const src_sentinel = array_type.sentinel();
3185 const dst_sentinel = dest_type.sentinel();
3186 if (src_sentinel == null and dst_sentinel == null)
3187 return sema.coerceArrayPtrToMany(scope, dest_type, inst);
3188
3189 if (src_sentinel) |src_s| {
3190 if (dst_sentinel) |dst_s| {
3191 if (src_s.eql(dst_s)) {
3192 return sema.coerceArrayPtrToMany(scope, dest_type, inst);
3193 }
3194 }
3195 }
3196 },
3197 .One => {},
3198 }
3199 }
3200
3201 // comptime known number to other number
3202 if (try sema.coerceNum(scope, dest_type, inst)) |some|
3203 return some;
3204
3205 // integer widening
3206 if (inst.ty.zigTypeTag() == .Int and dest_type.zigTypeTag() == .Int) {
3207 assert(inst.value() == null); // handled above
3208
3209 const src_info = inst.ty.intInfo(mod.getTarget());
3210 const dst_info = dest_type.intInfo(mod.getTarget());
3211 if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
3212 // small enough unsigned ints can get casted to large enough signed ints
3213 (src_info.signedness == .signed and dst_info.signedness == .unsigned and dst_info.bits > src_info.bits))
3214 {
3215 try sema.requireRuntimeBlock(block, inst.src);
3216 return mod.addUnOp(b, inst.src, dest_type, .intcast, inst);
3217 }
3218 }
3219
3220 // float widening
3221 if (inst.ty.zigTypeTag() == .Float and dest_type.zigTypeTag() == .Float) {
3222 assert(inst.value() == null); // handled above
3223
3224 const src_bits = inst.ty.floatBits(mod.getTarget());
3225 const dst_bits = dest_type.floatBits(mod.getTarget());
3226 if (dst_bits >= src_bits) {
3227 try sema.requireRuntimeBlock(block, inst.src);
3228 return mod.addUnOp(b, inst.src, dest_type, .floatcast, inst);
3229 }
3230 }
3231
3232 return sema.mod.fail(&block.base, inst.src, "expected {}, found {}", .{ dest_type, inst.ty });
3233}
3234
3235const InMemoryCoercionResult = enum {
3236 ok,
3237 no_match,
3238};
3239
3240fn coerceInMemoryAllowed(dest_type: Type, src_type: Type) InMemoryCoercionResult {
3241 if (dest_type.eql(src_type))
3242 return .ok;
3243
3244 // TODO: implement more of this function
3245
3246 return .no_match;
3247}
3248
3249fn coerceNum(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) InnerError!?*Inst {
3250 const val = inst.value() orelse return null;
3251 const src_zig_tag = inst.ty.zigTypeTag();
3252 const dst_zig_tag = dest_type.zigTypeTag();
3253
3254 if (dst_zig_tag == .ComptimeInt or dst_zig_tag == .Int) {
3255 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3256 if (val.floatHasFraction()) {
3257 return sema.mod.fail(&block.base, inst.src, "fractional component prevents float value {} from being casted to type '{}'", .{ val, inst.ty });
3258 }
3259 return sema.mod.fail(&block.base, inst.src, "TODO float to int", .{});
3260 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3261 if (!val.intFitsInType(dest_type, mod.getTarget())) {
3262 return sema.mod.fail(&block.base, inst.src, "type {} cannot represent integer value {}", .{ inst.ty, val });
3263 }
3264 return mod.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3265 }
3266 } else if (dst_zig_tag == .ComptimeFloat or dst_zig_tag == .Float) {
3267 if (src_zig_tag == .Float or src_zig_tag == .ComptimeFloat) {
3268 const res = val.floatCast(scope.arena(), dest_type, mod.getTarget()) catch |err| switch (err) {
3269 error.Overflow => return mod.fail(
3270 scope,
3271 inst.src,
3272 "cast of value {} to type '{}' loses information",
3273 .{ val, dest_type },
3274 ),
3275 error.OutOfMemory => return error.OutOfMemory,
3276 };
3277 return mod.constInst(scope, inst.src, .{ .ty = dest_type, .val = res });
3278 } else if (src_zig_tag == .Int or src_zig_tag == .ComptimeInt) {
3279 return sema.mod.fail(&block.base, inst.src, "TODO int to float", .{});
3280 }
3281 }
3282 return null;
3283}
3284
3285fn coerceVarArgParam(sema: *Sema, block: *Scope.Block, inst: *Inst) !*Inst {
3286 switch (inst.ty.zigTypeTag()) {
3287 .ComptimeInt, .ComptimeFloat => return sema.mod.fail(&block.base, inst.src, "integer and float literals in var args function must be casted", .{}),
3288 else => {},
3289 }
3290 // TODO implement more of this function.
3291 return inst;
3292}
3293
3294fn storePtr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, ptr: *Inst, uncasted_value: *Inst) !*Inst {
3295 if (ptr.ty.isConstPtr())
3296 return sema.mod.fail(&block.base, src, "cannot assign to constant", .{});
3297
3298 const elem_ty = ptr.ty.elemType();
3299 const value = try sema.coerce(scope, elem_ty, uncasted_value);
3300 if (elem_ty.onePossibleValue() != null)
3301 return sema.mod.constVoid(block.arena, .unneeded);
3302
3303 // TODO handle comptime pointer writes
3304 // TODO handle if the element type requires comptime
3305
3306 try sema.requireRuntimeBlock(block, src);
3307 return mod.addBinOp(b, src, Type.initTag(.void), .store, ptr, value);
3308}
3309
3310fn bitcast(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
3311 if (inst.value()) |val| {
3312 // Keep the comptime Value representation; take the new type.
3313 return mod.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3314 }
3315 // TODO validate the type size and other compile errors
3316 try sema.requireRuntimeBlock(block, inst.src);
3317 return mod.addUnOp(b, inst.src, dest_type, .bitcast, inst);
3318}
3319
3320fn coerceArrayPtrToSlice(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
3321 if (inst.value()) |val| {
3322 // The comptime Value representation is compatible with both types.
3323 return mod.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3324 }
3325 return sema.mod.fail(&block.base, inst.src, "TODO implement coerceArrayPtrToSlice runtime instruction", .{});
3326}
3327
3328fn coerceArrayPtrToMany(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
3329 if (inst.value()) |val| {
3330 // The comptime Value representation is compatible with both types.
3331 return mod.constInst(scope, inst.src, .{ .ty = dest_type, .val = val });
3332 }
3333 return sema.mod.fail(&block.base, inst.src, "TODO implement coerceArrayPtrToMany runtime instruction", .{});
3334}
3335
3336fn analyzeDeclVal(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
3337 const decl_ref = try sema.analyzeDeclRef(block, src, decl);
3338 return sema.analyzeDeref(block, src, decl_ref, src);
3339}
3340
3341fn analyzeDeclRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, decl: *Decl) InnerError!*Inst {
3342 const scope_decl = scope.ownerDecl().?;
3343 try mod.declareDeclDependency(scope_decl, decl);
3344 mod.ensureDeclAnalyzed(decl) catch |err| {
3345 if (scope.cast(Scope.Block)) |block| {
3346 if (block.func) |func| {
3347 func.state = .dependency_failure;
3348 } else {
3349 block.owner_decl.analysis = .dependency_failure;
3350 }
3351 } else {
3352 scope_decl.analysis = .dependency_failure;
3353 }
3354 return err;
3355 };
3356
3357 const decl_tv = try decl.typedValue();
3358 if (decl_tv.val.tag() == .variable) {
3359 return mod.analyzeVarRef(scope, src, decl_tv);
3360 }
3361 return mod.constInst(scope.arena(), src, .{
3362 .ty = try mod.simplePtrType(scope.arena(), decl_tv.ty, false, .One),
3363 .val = try Value.Tag.decl_ref.create(scope.arena(), decl),
3364 });
3365}
3366
3367fn analyzeVarRef(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, tv: TypedValue) InnerError!*Inst {
3368 const variable = tv.val.castTag(.variable).?.data;
3369
3370 const ty = try mod.simplePtrType(scope.arena(), tv.ty, variable.is_mutable, .One);
3371 if (!variable.is_mutable and !variable.is_extern) {
3372 return mod.constInst(scope.arena(), src, .{
3373 .ty = ty,
3374 .val = try Value.Tag.ref_val.create(scope.arena(), variable.init),
3375 });
3376 }
3377
3378 try sema.requireRuntimeBlock(block, src);
3379 const inst = try b.arena.create(Inst.VarPtr);
3380 inst.* = .{
3381 .base = .{
3382 .tag = .varptr,
3383 .ty = ty,
3384 .src = src,
3385 },
3386 .variable = variable,
3387 };
3388 try b.instructions.append(mod.gpa, &inst.base);
3389 return &inst.base;
3390}
3391
3392fn analyzeRef(
3393 sema: *Sema,
3394 block: *Scope.Block,
3395 src: LazySrcLoc,
3396 operand: *Inst,
3397) InnerError!*Inst {
3398 const ptr_type = try mod.simplePtrType(scope.arena(), operand.ty, false, .One);
3399
3400 if (operand.value()) |val| {
3401 return mod.constInst(scope.arena(), src, .{
3402 .ty = ptr_type,
3403 .val = try Value.Tag.ref_val.create(scope.arena(), val),
3404 });
3405 }
3406
3407 try sema.requireRuntimeBlock(block, src);
3408 return block.addUnOp(src, ptr_type, .ref, operand);
3409}
3410
3411fn analyzeDeref(
3412 sema: *Sema,
3413 block: *Scope.Block,
3414 src: LazySrcLoc,
3415 ptr: *Inst,
3416 ptr_src: LazySrcLoc,
3417) InnerError!*Inst {
3418 const elem_ty = switch (ptr.ty.zigTypeTag()) {
3419 .Pointer => ptr.ty.elemType(),
3420 else => return sema.mod.fail(&block.base, ptr_src, "expected pointer, found '{}'", .{ptr.ty}),
3421 };
3422 if (ptr.value()) |val| {
3423 return mod.constInst(scope.arena(), src, .{
3424 .ty = elem_ty,
3425 .val = try val.pointerDeref(scope.arena()),
3426 });
3427 }
3428
3429 try sema.requireRuntimeBlock(block, src);
3430 return mod.addUnOp(b, src, elem_ty, .load, ptr);
3431}
3432
3433fn analyzeIsNull(
3434 sema: *Sema,
3435 block: *Scope.Block,
3436 src: LazySrcLoc,
3437 operand: *Inst,
3438 invert_logic: bool,
3439) InnerError!*Inst {
3440 if (operand.value()) |opt_val| {
3441 const is_null = opt_val.isNull();
3442 const bool_value = if (invert_logic) !is_null else is_null;
3443 return mod.constBool(block.arena, src, bool_value);
3444 }
3445 try sema.requireRuntimeBlock(block, src);
3446 const inst_tag: Inst.Tag = if (invert_logic) .is_non_null else .is_null;
3447 return mod.addUnOp(b, src, Type.initTag(.bool), inst_tag, operand);
3448}
3449
3450fn analyzeIsErr(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, operand: *Inst) InnerError!*Inst {
3451 const ot = operand.ty.zigTypeTag();
3452 if (ot != .ErrorSet and ot != .ErrorUnion) return mod.constBool(block.arena, src, false);
3453 if (ot == .ErrorSet) return mod.constBool(block.arena, src, true);
3454 assert(ot == .ErrorUnion);
3455 if (operand.value()) |err_union| {
3456 return mod.constBool(block.arena, src, err_union.getError() != null);
3457 }
3458 try sema.requireRuntimeBlock(block, src);
3459 return mod.addUnOp(b, src, Type.initTag(.bool), .is_err, operand);
3460}
3461
3462fn analyzeSlice(
3463 sema: *Sema,
3464 block: *Scope.Block,
3465 src: LazySrcLoc,
3466 array_ptr: *Inst,
3467 start: *Inst,
3468 end_opt: ?*Inst,
3469 sentinel_opt: ?*Inst,
3470 sentinel_src: LazySrcLoc,
3471) InnerError!*Inst {
3472 const ptr_child = switch (array_ptr.ty.zigTypeTag()) {
3473 .Pointer => array_ptr.ty.elemType(),
3474 else => return sema.mod.fail(&block.base, src, "expected pointer, found '{}'", .{array_ptr.ty}),
3475 };
3476
3477 var array_type = ptr_child;
3478 const elem_type = switch (ptr_child.zigTypeTag()) {
3479 .Array => ptr_child.elemType(),
3480 .Pointer => blk: {
3481 if (ptr_child.isSinglePointer()) {
3482 if (ptr_child.elemType().zigTypeTag() == .Array) {
3483 array_type = ptr_child.elemType();
3484 break :blk ptr_child.elemType().elemType();
3485 }
3486
3487 return sema.mod.fail(&block.base, src, "slice of single-item pointer", .{});
3488 }
3489 break :blk ptr_child.elemType();
3490 },
3491 else => return sema.mod.fail(&block.base, src, "slice of non-array type '{}'", .{ptr_child}),
3492 };
3493
3494 const slice_sentinel = if (sentinel_opt) |sentinel| blk: {
3495 const casted = try sema.coerce(scope, elem_type, sentinel);
3496 break :blk try sema.resolveConstValue(block, sentinel_src, casted);
3497 } else null;
3498
3499 var return_ptr_size: std.builtin.TypeInfo.Pointer.Size = .Slice;
3500 var return_elem_type = elem_type;
3501 if (end_opt) |end| {
3502 if (end.value()) |end_val| {
3503 if (start.value()) |start_val| {
3504 const start_u64 = start_val.toUnsignedInt();
3505 const end_u64 = end_val.toUnsignedInt();
3506 if (start_u64 > end_u64) {
3507 return sema.mod.fail(&block.base, src, "out of bounds slice", .{});
3508 }
3509
3510 const len = end_u64 - start_u64;
3511 const array_sentinel = if (array_type.zigTypeTag() == .Array and end_u64 == array_type.arrayLen())
3512 array_type.sentinel()
3513 else
3514 slice_sentinel;
3515 return_elem_type = try mod.arrayType(scope, len, array_sentinel, elem_type);
3516 return_ptr_size = .One;
3517 }
3518 }
3519 }
3520 const return_type = try mod.ptrType(
3521 scope,
3522 return_elem_type,
3523 if (end_opt == null) slice_sentinel else null,
3524 0, // TODO alignment
3525 0,
3526 0,
3527 !ptr_child.isConstPtr(),
3528 ptr_child.isAllowzeroPtr(),
3529 ptr_child.isVolatilePtr(),
3530 return_ptr_size,
3531 );
3532
3533 return sema.mod.fail(&block.base, src, "TODO implement analysis of slice", .{});
3534}
3535
3536fn analyzeImport(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, target_string: []const u8) !*Scope.File {
3537 const cur_pkg = scope.getFileScope().pkg;
3538 const cur_pkg_dir_path = cur_pkg.root_src_directory.path orelse ".";
3539 const found_pkg = cur_pkg.table.get(target_string);
3540
3541 const resolved_path = if (found_pkg) |pkg|
3542 try std.fs.path.resolve(mod.gpa, &[_][]const u8{ pkg.root_src_directory.path orelse ".", pkg.root_src_path })
3543 else
3544 try std.fs.path.resolve(mod.gpa, &[_][]const u8{ cur_pkg_dir_path, target_string });
3545 errdefer mod.gpa.free(resolved_path);
3546
3547 if (mod.import_table.get(resolved_path)) |some| {
3548 mod.gpa.free(resolved_path);
3549 return some;
3550 }
3551
3552 if (found_pkg == null) {
3553 const resolved_root_path = try std.fs.path.resolve(mod.gpa, &[_][]const u8{cur_pkg_dir_path});
3554 defer mod.gpa.free(resolved_root_path);
3555
3556 if (!mem.startsWith(u8, resolved_path, resolved_root_path)) {
3557 return error.ImportOutsidePkgPath;
3558 }
3559 }
3560
3561 // TODO Scope.Container arena for ty and sub_file_path
3562 const file_scope = try mod.gpa.create(Scope.File);
3563 errdefer mod.gpa.destroy(file_scope);
3564 const struct_ty = try Type.Tag.empty_struct.create(mod.gpa, &file_scope.root_container);
3565 errdefer mod.gpa.destroy(struct_ty.castTag(.empty_struct).?);
3566
3567 file_scope.* = .{
3568 .sub_file_path = resolved_path,
3569 .source = .{ .unloaded = {} },
3570 .tree = undefined,
3571 .status = .never_loaded,
3572 .pkg = found_pkg orelse cur_pkg,
3573 .root_container = .{
3574 .file_scope = file_scope,
3575 .decls = .{},
3576 .ty = struct_ty,
3577 },
3578 };
3579 mod.analyzeContainer(&file_scope.root_container) catch |err| switch (err) {
3580 error.AnalysisFail => {
3581 assert(mod.comp.totalErrorCount() != 0);
3582 },
3583 else => |e| return e,
3584 };
3585 try mod.import_table.put(mod.gpa, file_scope.sub_file_path, file_scope);
3586 return file_scope;
3587}
3588
3589/// Asserts that lhs and rhs types are both numeric.
3590fn cmpNumeric(
3591 sema: *Sema,
3592 block: *Scope.Block,
3593 src: LazySrcLoc,
3594 lhs: *Inst,
3595 rhs: *Inst,
3596 op: std.math.CompareOperator,
3597) InnerError!*Inst {
3598 assert(lhs.ty.isNumeric());
3599 assert(rhs.ty.isNumeric());
3600
3601 const lhs_ty_tag = lhs.ty.zigTypeTag();
3602 const rhs_ty_tag = rhs.ty.zigTypeTag();
3603
3604 if (lhs_ty_tag == .Vector and rhs_ty_tag == .Vector) {
3605 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
3606 return sema.mod.fail(&block.base, src, "vector length mismatch: {d} and {d}", .{
3607 lhs.ty.arrayLen(),
3608 rhs.ty.arrayLen(),
3609 });
3610 }
3611 return sema.mod.fail(&block.base, src, "TODO implement support for vectors in cmpNumeric", .{});
3612 } else if (lhs_ty_tag == .Vector or rhs_ty_tag == .Vector) {
3613 return sema.mod.fail(&block.base, src, "mixed scalar and vector operands to comparison operator: '{}' and '{}'", .{
3614 lhs.ty,
3615 rhs.ty,
3616 });
3617 }
3618
3619 if (lhs.value()) |lhs_val| {
3620 if (rhs.value()) |rhs_val| {
3621 return mod.constBool(block.arena, src, Value.compare(lhs_val, op, rhs_val));
3622 }
3623 }
3624
3625 // TODO handle comparisons against lazy zero values
3626 // Some values can be compared against zero without being runtime known or without forcing
3627 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
3628 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
3629 // of this function if we don't need to.
3630
3631 // It must be a runtime comparison.
3632 try sema.requireRuntimeBlock(block, src);
3633 // For floats, emit a float comparison instruction.
3634 const lhs_is_float = switch (lhs_ty_tag) {
3635 .Float, .ComptimeFloat => true,
3636 else => false,
3637 };
3638 const rhs_is_float = switch (rhs_ty_tag) {
3639 .Float, .ComptimeFloat => true,
3640 else => false,
3641 };
3642 if (lhs_is_float and rhs_is_float) {
3643 // Implicit cast the smaller one to the larger one.
3644 const dest_type = x: {
3645 if (lhs_ty_tag == .ComptimeFloat) {
3646 break :x rhs.ty;
3647 } else if (rhs_ty_tag == .ComptimeFloat) {
3648 break :x lhs.ty;
3649 }
3650 if (lhs.ty.floatBits(mod.getTarget()) >= rhs.ty.floatBits(mod.getTarget())) {
3651 break :x lhs.ty;
3652 } else {
3653 break :x rhs.ty;
3654 }
3655 };
3656 const casted_lhs = try sema.coerce(scope, dest_type, lhs);
3657 const casted_rhs = try sema.coerce(scope, dest_type, rhs);
3658 return mod.addBinOp(b, src, dest_type, Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
3659 }
3660 // For mixed unsigned integer sizes, implicit cast both operands to the larger integer.
3661 // For mixed signed and unsigned integers, implicit cast both operands to a signed
3662 // integer with + 1 bit.
3663 // For mixed floats and integers, extract the integer part from the float, cast that to
3664 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
3665 // add/subtract 1.
3666 const lhs_is_signed = if (lhs.value()) |lhs_val|
3667 lhs_val.compareWithZero(.lt)
3668 else
3669 (lhs.ty.isFloat() or lhs.ty.isSignedInt());
3670 const rhs_is_signed = if (rhs.value()) |rhs_val|
3671 rhs_val.compareWithZero(.lt)
3672 else
3673 (rhs.ty.isFloat() or rhs.ty.isSignedInt());
3674 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
3675
3676 var dest_float_type: ?Type = null;
3677
3678 var lhs_bits: usize = undefined;
3679 if (lhs.value()) |lhs_val| {
3680 if (lhs_val.isUndef())
3681 return mod.constUndef(scope, src, Type.initTag(.bool));
3682 const is_unsigned = if (lhs_is_float) x: {
3683 var bigint_space: Value.BigIntSpace = undefined;
3684 var bigint = try lhs_val.toBigInt(&bigint_space).toManaged(mod.gpa);
3685 defer bigint.deinit();
3686 const zcmp = lhs_val.orderAgainstZero();
3687 if (lhs_val.floatHasFraction()) {
3688 switch (op) {
3689 .eq => return mod.constBool(block.arena, src, false),
3690 .neq => return mod.constBool(block.arena, src, true),
3691 else => {},
3692 }
3693 if (zcmp == .lt) {
3694 try bigint.addScalar(bigint.toConst(), -1);
3695 } else {
3696 try bigint.addScalar(bigint.toConst(), 1);
3697 }
3698 }
3699 lhs_bits = bigint.toConst().bitCountTwosComp();
3700 break :x (zcmp != .lt);
3701 } else x: {
3702 lhs_bits = lhs_val.intBitCountTwosComp();
3703 break :x (lhs_val.orderAgainstZero() != .lt);
3704 };
3705 lhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
3706 } else if (lhs_is_float) {
3707 dest_float_type = lhs.ty;
3708 } else {
3709 const int_info = lhs.ty.intInfo(mod.getTarget());
3710 lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
3711 }
3712
3713 var rhs_bits: usize = undefined;
3714 if (rhs.value()) |rhs_val| {
3715 if (rhs_val.isUndef())
3716 return mod.constUndef(scope, src, Type.initTag(.bool));
3717 const is_unsigned = if (rhs_is_float) x: {
3718 var bigint_space: Value.BigIntSpace = undefined;
3719 var bigint = try rhs_val.toBigInt(&bigint_space).toManaged(mod.gpa);
3720 defer bigint.deinit();
3721 const zcmp = rhs_val.orderAgainstZero();
3722 if (rhs_val.floatHasFraction()) {
3723 switch (op) {
3724 .eq => return mod.constBool(block.arena, src, false),
3725 .neq => return mod.constBool(block.arena, src, true),
3726 else => {},
3727 }
3728 if (zcmp == .lt) {
3729 try bigint.addScalar(bigint.toConst(), -1);
3730 } else {
3731 try bigint.addScalar(bigint.toConst(), 1);
3732 }
3733 }
3734 rhs_bits = bigint.toConst().bitCountTwosComp();
3735 break :x (zcmp != .lt);
3736 } else x: {
3737 rhs_bits = rhs_val.intBitCountTwosComp();
3738 break :x (rhs_val.orderAgainstZero() != .lt);
3739 };
3740 rhs_bits += @boolToInt(is_unsigned and dest_int_is_signed);
3741 } else if (rhs_is_float) {
3742 dest_float_type = rhs.ty;
3743 } else {
3744 const int_info = rhs.ty.intInfo(mod.getTarget());
3745 rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
3746 }
3747
3748 const dest_type = if (dest_float_type) |ft| ft else blk: {
3749 const max_bits = std.math.max(lhs_bits, rhs_bits);
3750 const casted_bits = std.math.cast(u16, max_bits) catch |err| switch (err) {
3751 error.Overflow => return sema.mod.fail(&block.base, src, "{d} exceeds maximum integer bit count", .{max_bits}),
3752 };
3753 break :blk try mod.makeIntType(scope, dest_int_is_signed, casted_bits);
3754 };
3755 const casted_lhs = try sema.coerce(scope, dest_type, lhs);
3756 const casted_rhs = try sema.coerce(scope, dest_type, rhs);
3757
3758 return mod.addBinOp(b, src, Type.initTag(.bool), Inst.Tag.fromCmpOp(op), casted_lhs, casted_rhs);
3759}
3760
3761fn wrapOptional(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
3762 if (inst.value()) |val| {
3763 return mod.constInst(scope.arena(), inst.src, .{ .ty = dest_type, .val = val });
3764 }
3765
3766 try sema.requireRuntimeBlock(block, inst.src);
3767 return mod.addUnOp(b, inst.src, dest_type, .wrap_optional, inst);
3768}
3769
3770fn wrapErrorUnion(sema: *Sema, block: *Scope.Block, dest_type: Type, inst: *Inst) !*Inst {
3771 // TODO deal with inferred error sets
3772 const err_union = dest_type.castTag(.error_union).?;
3773 if (inst.value()) |val| {
3774 const to_wrap = if (inst.ty.zigTypeTag() != .ErrorSet) blk: {
3775 _ = try sema.coerce(scope, err_union.data.payload, inst);
3776 break :blk val;
3777 } else switch (err_union.data.error_set.tag()) {
3778 .anyerror => val,
3779 .error_set_single => blk: {
3780 const n = err_union.data.error_set.castTag(.error_set_single).?.data;
3781 if (!mem.eql(u8, val.castTag(.@"error").?.data.name, n))
3782 return sema.mod.fail(&block.base, inst.src, "expected type '{}', found type '{}'", .{ err_union.data.error_set, inst.ty });
3783 break :blk val;
3784 },
3785 .error_set => blk: {
3786 const f = err_union.data.error_set.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
3787 if (f.get(val.castTag(.@"error").?.data.name) == null)
3788 return sema.mod.fail(&block.base, inst.src, "expected type '{}', found type '{}'", .{ err_union.data.error_set, inst.ty });
3789 break :blk val;
3790 },
3791 else => unreachable,
3792 };
3793
3794 return mod.constInst(scope.arena(), inst.src, .{
3795 .ty = dest_type,
3796 // creating a SubValue for the error_union payload
3797 .val = try Value.Tag.error_union.create(
3798 scope.arena(),
3799 to_wrap,
3800 ),
3801 });
3802 }
3803
3804 try sema.requireRuntimeBlock(block, inst.src);
3805
3806 // we are coercing from E to E!T
3807 if (inst.ty.zigTypeTag() == .ErrorSet) {
3808 var coerced = try sema.coerce(scope, err_union.data.error_set, inst);
3809 return mod.addUnOp(b, inst.src, dest_type, .wrap_errunion_err, coerced);
3810 } else {
3811 var coerced = try sema.coerce(scope, err_union.data.payload, inst);
3812 return mod.addUnOp(b, inst.src, dest_type, .wrap_errunion_payload, coerced);
3813 }
3814}
3815
3816fn resolvePeerTypes(sema: *Sema, block: *Scope.Block, instructions: []*Inst) !Type {
3817 if (instructions.len == 0)
3818 return Type.initTag(.noreturn);
3819
3820 if (instructions.len == 1)
3821 return instructions[0].ty;
3822
3823 var chosen = instructions[0];
3824 for (instructions[1..]) |candidate| {
3825 if (candidate.ty.eql(chosen.ty))
3826 continue;
3827 if (candidate.ty.zigTypeTag() == .NoReturn)
3828 continue;
3829 if (chosen.ty.zigTypeTag() == .NoReturn) {
3830 chosen = candidate;
3831 continue;
3832 }
3833 if (candidate.ty.zigTypeTag() == .Undefined)
3834 continue;
3835 if (chosen.ty.zigTypeTag() == .Undefined) {
3836 chosen = candidate;
3837 continue;
3838 }
3839 if (chosen.ty.isInt() and
3840 candidate.ty.isInt() and
3841 chosen.ty.isSignedInt() == candidate.ty.isSignedInt())
3842 {
3843 if (chosen.ty.intInfo(mod.getTarget()).bits < candidate.ty.intInfo(mod.getTarget()).bits) {
3844 chosen = candidate;
3845 }
3846 continue;
3847 }
3848 if (chosen.ty.isFloat() and candidate.ty.isFloat()) {
3849 if (chosen.ty.floatBits(mod.getTarget()) < candidate.ty.floatBits(mod.getTarget())) {
3850 chosen = candidate;
3851 }
3852 continue;
3853 }
3854
3855 if (chosen.ty.zigTypeTag() == .ComptimeInt and candidate.ty.isInt()) {
3856 chosen = candidate;
3857 continue;
3858 }
3859
3860 if (chosen.ty.isInt() and candidate.ty.zigTypeTag() == .ComptimeInt) {
3861 continue;
3862 }
3863
3864 // TODO error notes pointing out each type
3865 return sema.mod.fail(&block.base, candidate.src, "incompatible types: '{}' and '{}'", .{ chosen.ty, candidate.ty });
3866 }
3867
3868 return chosen.ty;
25973869}