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;...@@ -11,7 +11,7 @@ pub const Tokenizer = tokenizer.Tokenizer;
11pub const fmtId = @import("zig/fmt.zig").fmtId;11pub const fmtId = @import("zig/fmt.zig").fmtId;
12pub const fmtEscapes = @import("zig/fmt.zig").fmtEscapes;12pub const fmtEscapes = @import("zig/fmt.zig").fmtEscapes;
13pub const parse = @import("zig/parse.zig").parse;13pub 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");
15pub const ast = @import("zig/ast.zig");15pub const ast = @import("zig/ast.zig");
16pub const system = @import("zig/system.zig");16pub const system = @import("zig/system.zig");
17pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;17pub const CrossTarget = @import("zig/cross_target.zig").CrossTarget;
lib/std/zig/string_literal.zig+82-52
...@@ -6,112 +6,143 @@...@@ -6,112 +6,143 @@
6const std = @import("../std.zig");6const std = @import("../std.zig");
7const assert = std.debug.assert;7const assert = std.debug.assert;
88
9const State = enum {
10 Start,
11 Backslash,
12};
13
14pub const ParseError = error{9pub const ParseError = error{
15 OutOfMemory,10 OutOfMemory,
11 InvalidStringLiteral,
12};
1613
17 /// When this is returned, index will be the position of the character.14pub const Result = union(enum) {
18 InvalidCharacter,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,
19};28};
2029
21/// caller owns returned memory30/// Parses `bytes` as a Zig string literal and appends the result to `buf`.
22pub fn parse(31/// Asserts `bytes` has '"' at beginning and end.
23 allocator: *std.mem.Allocator,32pub fn parseAppend(buf: *std.ArrayList(u8), bytes: []const u8) error{OutOfMemory}!Result {
24 bytes: []const u8,
25 bad_index: *usize, // populated if error.InvalidCharacter is returned
26) ParseError![]u8 {
27 assert(bytes.len >= 2 and bytes[0] == '"' and bytes[bytes.len - 1] == '"');33 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);36 const prev_len = buf.items.len;
30 errdefer list.deinit();37 try buf.ensureCapacity(prev_len + slice.len - 1);
38 errdefer buf.shrinkRetainingCapacity(prev_len);
3139
32 const slice = bytes[1..];40 const State = enum {
33 try list.ensureCapacity(slice.len - 1);41 Start,
42 Backslash,
43 };
3444
35 var state = State.Start;45 var state = State.Start;
36 var index: usize = 0;46 var index: usize = 0;
37 while (index < slice.len) : (index += 1) {47 while (true) : (index += 1) {
38 const b = slice[index];48 const b = slice[index];
3949
40 switch (state) {50 switch (state) {
41 State.Start => switch (b) {51 State.Start => switch (b) {
42 '\\' => state = State.Backslash,52 '\\' => state = State.Backslash,
43 '\n' => {53 '\n' => {
44 bad_index.* = index;54 return Result{ .invalid_character = index };
45 return error.InvalidCharacter;
46 },55 },
47 '"' => return list.toOwnedSlice(),56 '"' => return Result.success,
48 else => try list.append(b),57 else => try buf.append(b),
49 },58 },
50 State.Backslash => switch (b) {59 State.Backslash => switch (b) {
51 'n' => {60 'n' => {
52 try list.append('\n');61 try buf.append('\n');
53 state = State.Start;62 state = State.Start;
54 },63 },
55 'r' => {64 'r' => {
56 try list.append('\r');65 try buf.append('\r');
57 state = State.Start;66 state = State.Start;
58 },67 },
59 '\\' => {68 '\\' => {
60 try list.append('\\');69 try buf.append('\\');
61 state = State.Start;70 state = State.Start;
62 },71 },
63 't' => {72 't' => {
64 try list.append('\t');73 try buf.append('\t');
65 state = State.Start;74 state = State.Start;
66 },75 },
67 '\'' => {76 '\'' => {
68 try list.append('\'');77 try buf.append('\'');
69 state = State.Start;78 state = State.Start;
70 },79 },
71 '"' => {80 '"' => {
72 try list.append('"');81 try buf.append('"');
73 state = State.Start;82 state = State.Start;
74 },83 },
75 'x' => {84 'x' => {
76 // TODO: add more/better/broader tests for this.85 // TODO: add more/better/broader tests for this.
77 const index_continue = index + 3;86 const index_continue = index + 3;
78 if (slice.len >= index_continue)87 if (slice.len < index_continue) {
79 if (std.fmt.parseUnsigned(u8, slice[index + 1 .. index_continue], 16)) |char| {88 return Result{ .expected_hex_digits = index };
80 try list.append(char);89 }
81 state = State.Start;90 if (std.fmt.parseUnsigned(u8, slice[index + 1 .. index_continue], 16)) |byte| {
82 index = index_continue - 1; // loop-header increments again91 try buf.append(byte);
83 continue;92 state = State.Start;
84 } else |_| {};93 index = index_continue - 1; // loop-header increments again
8594 } else |err| switch (err) {
86 bad_index.* = index;95 error.Overflow => unreachable, // 2 digits base 16 fits in a u8.
87 return error.InvalidCharacter;96 error.InvalidCharacter => {
97 return Result{ .invalid_hex_escape = index + 1 };
98 },
99 }
88 },100 },
89 'u' => {101 'u' => {
90 // TODO: add more/better/broader tests for this.102 // 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] == '{') {
92 if (std.mem.indexOfScalarPos(u8, slice[0..std.math.min(index + 9, slice.len)], index + 3, '}')) |index_end| {106 if (std.mem.indexOfScalarPos(u8, slice[0..std.math.min(index + 9, slice.len)], index + 3, '}')) |index_end| {
93 const hex_str = slice[index + 2 .. index_end];107 const hex_str = slice[index + 2 .. index_end];
94 if (std.fmt.parseUnsigned(u32, hex_str, 16)) |uint| {108 if (std.fmt.parseUnsigned(u32, hex_str, 16)) |uint| {
95 if (uint <= 0x10ffff) {109 if (uint <= 0x10ffff) {
96 try list.appendSlice(std.mem.toBytes(uint)[0..]);110 try buf.appendSlice(std.mem.toBytes(uint)[0..]);
97 state = State.Start;111 state = State.Start;
98 index = index_end; // loop-header increments112 index = index_end; // loop-header increments
99 continue;113 continue;
100 }114 }
101 } else |_| {}115 } else |err| switch (err) {
102 };116 error.Overflow => unreachable,
103117 error.InvalidCharacter => {
104 bad_index.* = index;118 return Result{ .invalid_unicode_escape = index + 1 };
105 return error.InvalidCharacter;119 },
120 }
121 } else {
122 return Result{ .missing_matching_rbrace = index + 1 };
123 }
124 } else {
125 return Result{ .expected_unicode_digits = index };
126 }
106 },127 },
107 else => {128 else => {
108 bad_index.* = index;129 return Result{ .invalid_character = index };
109 return error.InvalidCharacter;
110 },130 },
111 },131 },
112 }132 }
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,
113 }145 }
114 unreachable;
115}146}
116147
117test "parse" {148test "parse" {
...@@ -121,9 +152,8 @@ test "parse" {...@@ -121,9 +152,8 @@ test "parse" {
121 var fixed_buf_mem: [32]u8 = undefined;152 var fixed_buf_mem: [32]u8 = undefined;
122 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buf_mem[0..]);153 var fixed_buf_alloc = std.heap.FixedBufferAllocator.init(fixed_buf_mem[0..]);
123 var alloc = &fixed_buf_alloc.allocator;154 var alloc = &fixed_buf_alloc.allocator;
124 var bad_index: usize = undefined;
125155
126 expect(eql(u8, "foo", try parse(alloc, "\"foo\"", &bad_index)));156 expect(eql(u8, "foo", try parseAlloc(alloc, "\"foo\"")));
127 expect(eql(u8, "foo", try parse(alloc, "\"f\x6f\x6f\"", &bad_index)));157 expect(eql(u8, "foo", try parseAlloc(alloc, "\"f\x6f\x6f\"")));
128 expect(eql(u8, "f💯", try parse(alloc, "\"f\u{1f4af}\"", &bad_index)));158 expect(eql(u8, "f💯", try parseAlloc(alloc, "\"f\u{1f4af}\"")));
129}159}
src/Compilation.zig+19-17
...@@ -259,7 +259,7 @@ pub const CObject = struct {...@@ -259,7 +259,7 @@ pub const CObject = struct {
259/// To support incremental compilation, errors are stored in various places259/// To support incremental compilation, errors are stored in various places
260/// so that they can be created and destroyed appropriately. This structure260/// so that they can be created and destroyed appropriately. This structure
261/// is used to collect all the errors from the various places into one261/// 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 heap262/// convenient place for API users to consume. It is allocated into 1 arena
263/// and freed all at once.263/// and freed all at once.
264pub const AllErrors = struct {264pub const AllErrors = struct {
265 arena: std.heap.ArenaAllocator.State,265 arena: std.heap.ArenaAllocator.State,
...@@ -267,11 +267,11 @@ pub const AllErrors = struct {...@@ -267,11 +267,11 @@ pub const AllErrors = struct {
267267
268 pub const Message = union(enum) {268 pub const Message = union(enum) {
269 src: struct {269 src: struct {
270 src_path: []const u8,
271 line: usize,
272 column: usize,
273 byte_offset: usize,
274 msg: []const u8,270 msg: []const u8,
271 src_path: []const u8,
272 line: u32,
273 column: u32,
274 byte_offset: u32,
275 notes: []Message = &.{},275 notes: []Message = &.{},
276 },276 },
277 plain: struct {277 plain: struct {
...@@ -316,29 +316,31 @@ pub const AllErrors = struct {...@@ -316,29 +316,31 @@ pub const AllErrors = struct {
316 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);316 const notes = try arena.allocator.alloc(Message, module_err_msg.notes.len);
317 for (notes) |*note, i| {317 for (notes) |*note, i| {
318 const module_note = module_err_msg.notes[i];318 const module_note = module_err_msg.notes[i];
319 const source = try module_note.src_loc.file_scope.getSource(module);319 const source = try module_note.src_loc.fileScope().getSource(module);
320 const loc = std.zig.findLineColumn(source, module_note.src_loc.byte_offset);320 const byte_offset = try module_note.src_loc.byteOffset(module);
321 const sub_file_path = module_note.src_loc.file_scope.sub_file_path;321 const loc = std.zig.findLineColumn(source, byte_offset);
322 const sub_file_path = module_note.src_loc.fileScope().sub_file_path;
322 note.* = .{323 note.* = .{
323 .src = .{324 .src = .{
324 .src_path = try arena.allocator.dupe(u8, sub_file_path),325 .src_path = try arena.allocator.dupe(u8, sub_file_path),
325 .msg = try arena.allocator.dupe(u8, module_note.msg),326 .msg = try arena.allocator.dupe(u8, module_note.msg),
326 .byte_offset = module_note.src_loc.byte_offset,327 .byte_offset = byte_offset,
327 .line = loc.line,328 .line = @intCast(u32, loc.line),
328 .column = loc.column,329 .column = @intCast(u32, loc.column),
329 },330 },
330 };331 };
331 }332 }
332 const source = try module_err_msg.src_loc.file_scope.getSource(module);333 const source = try module_err_msg.src_loc.fileScope().getSource(module);
333 const loc = std.zig.findLineColumn(source, module_err_msg.src_loc.byte_offset);334 const byte_offset = try module_err_msg.src_loc.byteOffset(module);
334 const sub_file_path = module_err_msg.src_loc.file_scope.sub_file_path;335 const loc = std.zig.findLineColumn(source, byte_offset);
336 const sub_file_path = module_err_msg.src_loc.fileScope().sub_file_path;
335 try errors.append(.{337 try errors.append(.{
336 .src = .{338 .src = .{
337 .src_path = try arena.allocator.dupe(u8, sub_file_path),339 .src_path = try arena.allocator.dupe(u8, sub_file_path),
338 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),340 .msg = try arena.allocator.dupe(u8, module_err_msg.msg),
339 .byte_offset = module_err_msg.src_loc.byte_offset,341 .byte_offset = byte_offset,
340 .line = loc.line,342 .line = @intCast(u32, loc.line),
341 .column = loc.column,343 .column = @intCast(u32, loc.column),
342 .notes = notes,344 .notes = notes,
343 },345 },
344 });346 });
src/Module.zig+1074-1729
...@@ -1,31 +1,32 @@...@@ -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
2const std = @import("std");5const std = @import("std");
3const Compilation = @import("Compilation.zig");
4const mem = std.mem;6const mem = std.mem;
5const Allocator = std.mem.Allocator;7const Allocator = std.mem.Allocator;
6const ArrayListUnmanaged = std.ArrayListUnmanaged;8const ArrayListUnmanaged = std.ArrayListUnmanaged;
7const Value = @import("value.zig").Value;
8const Type = @import("type.zig").Type;
9const TypedValue = @import("TypedValue.zig");
10const assert = std.debug.assert;9const assert = std.debug.assert;
11const log = std.log.scoped(.module);10const log = std.log.scoped(.module);
12const BigIntConst = std.math.big.int.Const;11const BigIntConst = std.math.big.int.Const;
13const BigIntMutable = std.math.big.int.Mutable;12const BigIntMutable = std.math.big.int.Mutable;
14const Target = std.Target;13const 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");
15const Package = @import("Package.zig");21const Package = @import("Package.zig");
16const link = @import("link.zig");22const link = @import("link.zig");
17const ir = @import("ir.zig");23const ir = @import("ir.zig");
18const zir = @import("zir.zig");24const zir = @import("zir.zig");
19const Inst = ir.Inst;
20const Body = ir.Body;
21const ast = std.zig.ast;
22const trace = @import("tracy.zig").trace;25const trace = @import("tracy.zig").trace;
23const astgen = @import("astgen.zig");26const astgen = @import("astgen.zig");
24const zir_sema = @import("zir_sema.zig");27const Sema = @import("zir_sema.zig"); // TODO rename this file
25const target_util = @import("target.zig");28const target_util = @import("target.zig");
2629
27const default_eval_branch_quota = 1000;
28
29/// General-purpose allocator. Used for both temporary and long-term storage.30/// General-purpose allocator. Used for both temporary and long-term storage.
30gpa: *Allocator,31gpa: *Allocator,
31comp: *Compilation,32comp: *Compilation,
...@@ -106,8 +107,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .{},...@@ -106,8 +107,7 @@ compile_log_text: std.ArrayListUnmanaged(u8) = .{},
106107
107pub const Export = struct {108pub const Export = struct {
108 options: std.builtin.ExportOptions,109 options: std.builtin.ExportOptions,
109 /// Byte offset into the file that contains the export directive.110 src: LazySrcLoc,
110 src: usize,
111 /// Represents the position of the export, if any, in the output file.111 /// Represents the position of the export, if any, in the output file.
112 link: link.File.Export,112 link: link.File.Export,
113 /// The Decl that performs the export. Note that this is *not* the Decl being exported.113 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
...@@ -132,11 +132,12 @@ pub const DeclPlusEmitH = struct {...@@ -132,11 +132,12 @@ pub const DeclPlusEmitH = struct {
132};132};
133133
134pub const Decl = struct {134pub const Decl = struct {
135 /// This name is relative to the containing namespace of the decl. It uses a null-termination135 /// This name is relative to the containing namespace of the decl. It uses
136 /// to save bytes, since there can be a lot of decls in a compilation. The null byte is not allowed136 /// null-termination to save bytes, since there can be a lot of decls in a
137 /// in symbol names, because executable file formats use null-terminated strings for symbol names.137 /// compilation. The null byte is not allowed in symbol names, because
138 /// All Decls have names, even values that are not bound to a zig namespace. This is necessary for138 /// executable file formats use null-terminated strings for symbol names.
139 /// mapping them to an address in the output file.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.
140 /// Memory owned by this decl, using Module's allocator.141 /// Memory owned by this decl, using Module's allocator.
141 name: [*:0]const u8,142 name: [*:0]const u8,
142 /// The direct parent container of the Decl.143 /// The direct parent container of the Decl.
...@@ -219,73 +220,82 @@ pub const Decl = struct {...@@ -219,73 +220,82 @@ pub const Decl = struct {
219 /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself`220 /// stage1 compiler giving me: `error: struct 'Module.Decl' depends on itself`
220 pub const DepsTable = std.ArrayHashMapUnmanaged(*Decl, void, std.array_hash_map.getAutoHashFn(*Decl), std.array_hash_map.getAutoEqlFn(*Decl), false);221 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 {
223 const gpa = module.gpa;224 const gpa = module.gpa;
224 gpa.free(mem.spanZ(self.name));225 gpa.free(mem.spanZ(decl.name));
225 if (self.typedValueManaged()) |tvm| {226 if (decl.typedValueManaged()) |tvm| {
226 tvm.deinit(gpa);227 tvm.deinit(gpa);
227 }228 }
228 self.dependants.deinit(gpa);229 decl.dependants.deinit(gpa);
229 self.dependencies.deinit(gpa);230 decl.dependencies.deinit(gpa);
230 if (module.emit_h != null) {231 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);
232 decl_plus_emit_h.emit_h.fwd_decl.deinit(gpa);233 decl_plus_emit_h.emit_h.fwd_decl.deinit(gpa);
233 gpa.destroy(decl_plus_emit_h);234 gpa.destroy(decl_plus_emit_h);
234 } else {235 } else {
235 gpa.destroy(self);236 gpa.destroy(decl);
236 }237 }
237 }238 }
238239
239 pub fn srcLoc(self: Decl) SrcLoc {240 pub fn srcLoc(decl: *const Decl) SrcLoc {
240 return .{241 return .{
241 .byte_offset = self.src(),242 .decl = decl,
242 .file_scope = self.getFileScope(),243 .byte_offset = 0,
243 };244 };
244 }245 }
245246
246 pub fn src(self: Decl) usize {247 pub fn srcNode(decl: Decl) u32 {
247 const tree = &self.container.file_scope.tree;248 const tree = &decl.container.file_scope.tree;
248 const decl_node = tree.rootDecls()[self.src_index];249 return tree.rootDecls()[decl.src_index];
249 return tree.tokens.items(.start)[tree.firstToken(decl_node)];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()];
250 }260 }
251261
252 pub fn fullyQualifiedNameHash(self: Decl) Scope.NameHash {262 pub fn fullyQualifiedNameHash(decl: Decl) Scope.NameHash {
253 return self.container.fullyQualifiedNameHash(mem.spanZ(self.name));263 return decl.container.fullyQualifiedNameHash(mem.spanZ(decl.name));
254 }264 }
255265
256 pub fn typedValue(self: *Decl) error{AnalysisFail}!TypedValue {266 pub fn typedValue(decl: *Decl) error{AnalysisFail}!TypedValue {
257 const tvm = self.typedValueManaged() orelse return error.AnalysisFail;267 const tvm = decl.typedValueManaged() orelse return error.AnalysisFail;
258 return tvm.typed_value;268 return tvm.typed_value;
259 }269 }
260270
261 pub fn value(self: *Decl) error{AnalysisFail}!Value {271 pub fn value(decl: *Decl) error{AnalysisFail}!Value {
262 return (try self.typedValue()).val;272 return (try decl.typedValue()).val;
263 }273 }
264274
265 pub fn dump(self: *Decl) void {275 pub fn dump(decl: *Decl) void {
266 const loc = std.zig.findLineColumn(self.scope.source.bytes, self.src);276 const loc = std.zig.findLineColumn(decl.scope.source.bytes, decl.src);
267 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{277 std.debug.print("{s}:{d}:{d} name={s} status={s}", .{
268 self.scope.sub_file_path,278 decl.scope.sub_file_path,
269 loc.line + 1,279 loc.line + 1,
270 loc.column + 1,280 loc.column + 1,
271 mem.spanZ(self.name),281 mem.spanZ(decl.name),
272 @tagName(self.analysis),282 @tagName(decl.analysis),
273 });283 });
274 if (self.typedValueManaged()) |tvm| {284 if (decl.typedValueManaged()) |tvm| {
275 std.debug.print(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });285 std.debug.print(" ty={} val={}", .{ tvm.typed_value.ty, tvm.typed_value.val });
276 }286 }
277 std.debug.print("\n", .{});287 std.debug.print("\n", .{});
278 }288 }
279289
280 pub fn typedValueManaged(self: *Decl) ?*TypedValue.Managed {290 pub fn typedValueManaged(decl: *Decl) ?*TypedValue.Managed {
281 switch (self.typed_value) {291 switch (decl.typed_value) {
282 .most_recent => |*x| return x,292 .most_recent => |*x| return x,
283 .never_succeeded => return null,293 .never_succeeded => return null,
284 }294 }
285 }295 }
286296
287 pub fn getFileScope(self: Decl) *Scope.File {297 pub fn getFileScope(decl: Decl) *Scope.File {
288 return self.container.file_scope;298 return decl.container.file_scope;
289 }299 }
290300
291 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {301 pub fn getEmitH(decl: *Decl, module: *Module) *EmitH {
...@@ -294,12 +304,12 @@ pub const Decl = struct {...@@ -294,12 +304,12 @@ pub const Decl = struct {
294 return &decl_plus_emit_h.emit_h;304 return &decl_plus_emit_h.emit_h;
295 }305 }
296306
297 fn removeDependant(self: *Decl, other: *Decl) void {307 fn removeDependant(decl: *Decl, other: *Decl) void {
298 self.dependants.removeAssertDiscard(other);308 decl.dependants.removeAssertDiscard(other);
299 }309 }
300310
301 fn removeDependency(self: *Decl, other: *Decl) void {311 fn removeDependency(decl: *Decl, other: *Decl) void {
302 self.dependencies.removeAssertDiscard(other);312 decl.dependencies.removeAssertDiscard(other);
303 }313 }
304};314};
305315
...@@ -316,9 +326,14 @@ pub const Fn = struct {...@@ -316,9 +326,14 @@ pub const Fn = struct {
316 /// Contains un-analyzed ZIR instructions generated from Zig source AST.326 /// Contains un-analyzed ZIR instructions generated from Zig source AST.
317 /// Even after we finish analysis, the ZIR is kept in memory, so that327 /// Even after we finish analysis, the ZIR is kept in memory, so that
318 /// comptime and inline function calls can happen.328 /// 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,
320 /// undefined unless analysis state is `success`.335 /// undefined unless analysis state is `success`.
321 body: Body,336 body: ir.Body,
322 state: Analysis,337 state: Analysis,
323338
324 pub const Analysis = enum {339 pub const Analysis = enum {
...@@ -336,8 +351,8 @@ pub const Fn = struct {...@@ -336,8 +351,8 @@ pub const Fn = struct {
336 };351 };
337352
338 /// For debugging purposes.353 /// For debugging purposes.
339 pub fn dump(self: *Fn, mod: Module) void {354 pub fn dump(func: *Fn, mod: Module) void {
340 zir.dumpFn(mod, self);355 zir.dumpFn(mod, func);
341 }356 }
342};357};
343358
...@@ -364,68 +379,68 @@ pub const Scope = struct {...@@ -364,68 +379,68 @@ pub const Scope = struct {
364 }379 }
365380
366 /// Returns the arena Allocator associated with the Decl of the Scope.381 /// Returns the arena Allocator associated with the Decl of the Scope.
367 pub fn arena(self: *Scope) *Allocator {382 pub fn arena(scope: *Scope) *Allocator {
368 switch (self.tag) {383 switch (scope.tag) {
369 .block => return self.cast(Block).?.arena,384 .block => return scope.cast(Block).?.arena,
370 .gen_zir => return self.cast(GenZIR).?.arena,385 .gen_zir => return scope.cast(GenZir).?.arena,
371 .local_val => return self.cast(LocalVal).?.gen_zir.arena,386 .local_val => return scope.cast(LocalVal).?.gen_zir.arena,
372 .local_ptr => return self.cast(LocalPtr).?.gen_zir.arena,387 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.arena,
373 .gen_suspend => return self.cast(GenZIR).?.arena,388 .gen_suspend => return scope.cast(GenZir).?.arena,
374 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.arena,389 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.arena,
375 .file => unreachable,390 .file => unreachable,
376 .container => unreachable,391 .container => unreachable,
377 }392 }
378 }393 }
379394
380 pub fn isComptime(self: *Scope) bool {395 pub fn isComptime(scope: *Scope) bool {
381 return self.getGenZIR().force_comptime;396 return scope.getGenZir().force_comptime;
382 }397 }
383398
384 pub fn ownerDecl(self: *Scope) ?*Decl {399 pub fn ownerDecl(scope: *Scope) ?*Decl {
385 return switch (self.tag) {400 return switch (scope.tag) {
386 .block => self.cast(Block).?.owner_decl,401 .block => scope.cast(Block).?.owner_decl,
387 .gen_zir => self.cast(GenZIR).?.decl,402 .gen_zir => scope.cast(GenZir).?.zir_code.decl,
388 .local_val => self.cast(LocalVal).?.gen_zir.decl,403 .local_val => scope.cast(LocalVal).?.gen_zir.decl,
389 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,404 .local_ptr => scope.cast(LocalPtr).?.gen_zir.decl,
390 .gen_suspend => return self.cast(GenZIR).?.decl,405 .gen_suspend => return scope.cast(GenZir).?.decl,
391 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl,406 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.decl,
392 .file => null,407 .file => null,
393 .container => null,408 .container => null,
394 };409 };
395 }410 }
396411
397 pub fn srcDecl(self: *Scope) ?*Decl {412 pub fn srcDecl(scope: *Scope) ?*Decl {
398 return switch (self.tag) {413 return switch (scope.tag) {
399 .block => self.cast(Block).?.src_decl,414 .block => scope.cast(Block).?.src_decl,
400 .gen_zir => self.cast(GenZIR).?.decl,415 .gen_zir => scope.cast(GenZir).?.zir_code.decl,
401 .local_val => self.cast(LocalVal).?.gen_zir.decl,416 .local_val => scope.cast(LocalVal).?.gen_zir.decl,
402 .local_ptr => self.cast(LocalPtr).?.gen_zir.decl,417 .local_ptr => scope.cast(LocalPtr).?.gen_zir.decl,
403 .gen_suspend => return self.cast(GenZIR).?.decl,418 .gen_suspend => return scope.cast(GenZir).?.decl,
404 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl,419 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.decl,
405 .file => null,420 .file => null,
406 .container => null,421 .container => null,
407 };422 };
408 }423 }
409424
410 /// Asserts the scope has a parent which is a Container and returns it.425 /// Asserts the scope has a parent which is a Container and returns it.
411 pub fn namespace(self: *Scope) *Container {426 pub fn namespace(scope: *Scope) *Container {
412 switch (self.tag) {427 switch (scope.tag) {
413 .block => return self.cast(Block).?.owner_decl.container,428 .block => return scope.cast(Block).?.sema.owner_decl.container,
414 .gen_zir => return self.cast(GenZIR).?.decl.container,429 .gen_zir => return scope.cast(GenZir).?.zir_code.decl.container,
415 .local_val => return self.cast(LocalVal).?.gen_zir.decl.container,430 .local_val => return scope.cast(LocalVal).?.gen_zir.zir_code.decl.container,
416 .local_ptr => return self.cast(LocalPtr).?.gen_zir.decl.container,431 .local_ptr => return scope.cast(LocalPtr).?.gen_zir.zir_code.decl.container,
417 .file => return &self.cast(File).?.root_container,432 .file => return &scope.cast(File).?.root_container,
418 .container => return self.cast(Container).?,433 .container => return scope.cast(Container).?,
419 .gen_suspend => return self.cast(GenZIR).?.decl.container,434 .gen_suspend => return scope.cast(GenZir).?.zir_code.decl.container,
420 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir.decl.container,435 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir.zir_code.decl.container,
421 }436 }
422 }437 }
423438
424 /// Must generate unique bytes with no collisions with other decls.439 /// Must generate unique bytes with no collisions with other decls.
425 /// The point of hashing here is only to limit the number of bytes of440 /// The point of hashing here is only to limit the number of bytes of
426 /// the unique identifier to a fixed size (16 bytes).441 /// the unique identifier to a fixed size (16 bytes).
427 pub fn fullyQualifiedNameHash(self: *Scope, name: []const u8) NameHash {442 pub fn fullyQualifiedNameHash(scope: *Scope, name: []const u8) NameHash {
428 switch (self.tag) {443 switch (scope.tag) {
429 .block => unreachable,444 .block => unreachable,
430 .gen_zir => unreachable,445 .gen_zir => unreachable,
431 .local_val => unreachable,446 .local_val => unreachable,
...@@ -433,32 +448,32 @@ pub const Scope = struct {...@@ -433,32 +448,32 @@ pub const Scope = struct {
433 .gen_suspend => unreachable,448 .gen_suspend => unreachable,
434 .gen_nosuspend => unreachable,449 .gen_nosuspend => unreachable,
435 .file => unreachable,450 .file => unreachable,
436 .container => return self.cast(Container).?.fullyQualifiedNameHash(name),451 .container => return scope.cast(Container).?.fullyQualifiedNameHash(name),
437 }452 }
438 }453 }
439454
440 /// Asserts the scope is a child of a File and has an AST tree and returns the tree.455 /// 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 {456 pub fn tree(scope: *Scope) *const ast.Tree {
442 switch (self.tag) {457 switch (scope.tag) {
443 .file => return &self.cast(File).?.tree,458 .file => return &scope.cast(File).?.tree,
444 .block => return &self.cast(Block).?.src_decl.container.file_scope.tree,459 .block => return &scope.cast(Block).?.src_decl.container.file_scope.tree,
445 .gen_zir => return &self.cast(GenZIR).?.decl.container.file_scope.tree,460 .gen_zir => return &scope.cast(GenZir).?.decl.container.file_scope.tree,
446 .local_val => return &self.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,461 .local_val => return &scope.cast(LocalVal).?.gen_zir.decl.container.file_scope.tree,
447 .local_ptr => return &self.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,462 .local_ptr => return &scope.cast(LocalPtr).?.gen_zir.decl.container.file_scope.tree,
448 .container => return &self.cast(Container).?.file_scope.tree,463 .container => return &scope.cast(Container).?.file_scope.tree,
449 .gen_suspend => return &self.cast(GenZIR).?.decl.container.file_scope.tree,464 .gen_suspend => return &scope.cast(GenZir).?.decl.container.file_scope.tree,
450 .gen_nosuspend => return &self.cast(Nosuspend).?.gen_zir.decl.container.file_scope.tree,465 .gen_nosuspend => return &scope.cast(Nosuspend).?.gen_zir.decl.container.file_scope.tree,
451 }466 }
452 }467 }
453468
454 /// Asserts the scope is a child of a `GenZIR` and returns it.469 /// Asserts the scope is a child of a `GenZir` and returns it.
455 pub fn getGenZIR(self: *Scope) *GenZIR {470 pub fn getGenZir(scope: *Scope) *GenZir {
456 return switch (self.tag) {471 return switch (scope.tag) {
457 .block => unreachable,472 .block => unreachable,
458 .gen_zir, .gen_suspend => self.cast(GenZIR).?,473 .gen_zir, .gen_suspend => scope.cast(GenZir).?,
459 .local_val => return self.cast(LocalVal).?.gen_zir,474 .local_val => return scope.cast(LocalVal).?.gen_zir,
460 .local_ptr => return self.cast(LocalPtr).?.gen_zir,475 .local_ptr => return scope.cast(LocalPtr).?.gen_zir,
461 .gen_nosuspend => return self.cast(Nosuspend).?.gen_zir,476 .gen_nosuspend => return scope.cast(Nosuspend).?.gen_zir,
462 .file => unreachable,477 .file => unreachable,
463 .container => unreachable,478 .container => unreachable,
464 };479 };
...@@ -499,25 +514,25 @@ pub const Scope = struct {...@@ -499,25 +514,25 @@ pub const Scope = struct {
499 cur = switch (cur.tag) {514 cur = switch (cur.tag) {
500 .container => return @fieldParentPtr(Container, "base", cur).file_scope,515 .container => return @fieldParentPtr(Container, "base", cur).file_scope,
501 .file => return @fieldParentPtr(File, "base", cur),516 .file => return @fieldParentPtr(File, "base", cur),
502 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,517 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
503 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,518 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
504 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,519 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
505 .block => return @fieldParentPtr(Block, "base", cur).src_decl.container.file_scope,520 .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,
507 .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,522 .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,
508 };523 };
509 }524 }
510 }525 }
511526
512 pub fn getSuspend(base: *Scope) ?*Scope.GenZIR {527 pub fn getSuspend(base: *Scope) ?*Scope.GenZir {
513 var cur = base;528 var cur = base;
514 while (true) {529 while (true) {
515 cur = switch (cur.tag) {530 cur = switch (cur.tag) {
516 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,531 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
517 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,532 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
518 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,533 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
519 .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,534 .gen_nosuspend => @fieldParentPtr(Nosuspend, "base", cur).parent,
520 .gen_suspend => return @fieldParentPtr(GenZIR, "base", cur),535 .gen_suspend => return @fieldParentPtr(GenZir, "base", cur),
521 else => return null,536 else => return null,
522 };537 };
523 }538 }
...@@ -527,10 +542,10 @@ pub const Scope = struct {...@@ -527,10 +542,10 @@ pub const Scope = struct {
527 var cur = base;542 var cur = base;
528 while (true) {543 while (true) {
529 cur = switch (cur.tag) {544 cur = switch (cur.tag) {
530 .gen_zir => @fieldParentPtr(GenZIR, "base", cur).parent,545 .gen_zir => @fieldParentPtr(GenZir, "base", cur).parent,
531 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,546 .local_val => @fieldParentPtr(LocalVal, "base", cur).parent,
532 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,547 .local_ptr => @fieldParentPtr(LocalPtr, "base", cur).parent,
533 .gen_suspend => @fieldParentPtr(GenZIR, "base", cur).parent,548 .gen_suspend => @fieldParentPtr(GenZir, "base", cur).parent,
534 .gen_nosuspend => return @fieldParentPtr(Nosuspend, "base", cur),549 .gen_nosuspend => return @fieldParentPtr(Nosuspend, "base", cur),
535 else => return null,550 else => return null,
536 };551 };
...@@ -568,19 +583,19 @@ pub const Scope = struct {...@@ -568,19 +583,19 @@ pub const Scope = struct {
568 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},583 decls: std.AutoArrayHashMapUnmanaged(*Decl, void) = .{},
569 ty: Type,584 ty: Type,
570585
571 pub fn deinit(self: *Container, gpa: *Allocator) void {586 pub fn deinit(cont: *Container, gpa: *Allocator) void {
572 self.decls.deinit(gpa);587 cont.decls.deinit(gpa);
573 // TODO either Container of File should have an arena for sub_file_path and ty588 // TODO either Container of File should have an arena for sub_file_path and ty
574 gpa.destroy(self.ty.castTag(.empty_struct).?);589 gpa.destroy(cont.ty.castTag(.empty_struct).?);
575 gpa.free(self.file_scope.sub_file_path);590 gpa.free(cont.file_scope.sub_file_path);
576 self.* = undefined;591 cont.* = undefined;
577 }592 }
578593
579 pub fn removeDecl(self: *Container, child: *Decl) void {594 pub fn removeDecl(cont: *Container, child: *Decl) void {
580 _ = self.decls.swapRemove(child);595 _ = cont.decls.swapRemove(child);
581 }596 }
582597
583 pub fn fullyQualifiedNameHash(self: *Container, name: []const u8) NameHash {598 pub fn fullyQualifiedNameHash(cont: *Container, name: []const u8) NameHash {
584 // TODO container scope qualified names.599 // TODO container scope qualified names.
585 return std.zig.hashSrc(name);600 return std.zig.hashSrc(name);
586 }601 }
...@@ -610,55 +625,55 @@ pub const Scope = struct {...@@ -610,55 +625,55 @@ pub const Scope = struct {
610625
611 root_container: Container,626 root_container: Container,
612627
613 pub fn unload(self: *File, gpa: *Allocator) void {628 pub fn unload(file: *File, gpa: *Allocator) void {
614 switch (self.status) {629 switch (file.status) {
615 .never_loaded,630 .never_loaded,
616 .unloaded_parse_failure,631 .unloaded_parse_failure,
617 .unloaded_success,632 .unloaded_success,
618 => {},633 => {},
619634
620 .loaded_success => {635 .loaded_success => {
621 self.tree.deinit(gpa);636 file.tree.deinit(gpa);
622 self.status = .unloaded_success;637 file.status = .unloaded_success;
623 },638 },
624 }639 }
625 switch (self.source) {640 switch (file.source) {
626 .bytes => |bytes| {641 .bytes => |bytes| {
627 gpa.free(bytes);642 gpa.free(bytes);
628 self.source = .{ .unloaded = {} };643 file.source = .{ .unloaded = {} };
629 },644 },
630 .unloaded => {},645 .unloaded => {},
631 }646 }
632 }647 }
633648
634 pub fn deinit(self: *File, gpa: *Allocator) void {649 pub fn deinit(file: *File, gpa: *Allocator) void {
635 self.root_container.deinit(gpa);650 file.root_container.deinit(gpa);
636 self.unload(gpa);651 file.unload(gpa);
637 self.* = undefined;652 file.* = undefined;
638 }653 }
639654
640 pub fn destroy(self: *File, gpa: *Allocator) void {655 pub fn destroy(file: *File, gpa: *Allocator) void {
641 self.deinit(gpa);656 file.deinit(gpa);
642 gpa.destroy(self);657 gpa.destroy(file);
643 }658 }
644659
645 pub fn dumpSrc(self: *File, src: usize) void {660 pub fn dumpSrc(file: *File, src: LazySrcLoc) void {
646 const loc = std.zig.findLineColumn(self.source.bytes, src);661 const loc = std.zig.findLineColumn(file.source.bytes, src);
647 std.debug.print("{s}:{d}:{d}\n", .{ self.sub_file_path, loc.line + 1, loc.column + 1 });662 std.debug.print("{s}:{d}:{d}\n", .{ file.sub_file_path, loc.line + 1, loc.column + 1 });
648 }663 }
649664
650 pub fn getSource(self: *File, module: *Module) ![:0]const u8 {665 pub fn getSource(file: *File, module: *Module) ![:0]const u8 {
651 switch (self.source) {666 switch (file.source) {
652 .unloaded => {667 .unloaded => {
653 const source = try self.pkg.root_src_directory.handle.readFileAllocOptions(668 const source = try file.pkg.root_src_directory.handle.readFileAllocOptions(
654 module.gpa,669 module.gpa,
655 self.sub_file_path,670 file.sub_file_path,
656 std.math.maxInt(u32),671 std.math.maxInt(u32),
657 null,672 null,
658 1,673 1,
659 0,674 0,
660 );675 );
661 self.source = .{ .bytes = source };676 file.source = .{ .bytes = source };
662 return source;677 return source;
663 },678 },
664 .bytes => |bytes| return bytes,679 .bytes => |bytes| return bytes,
...@@ -666,37 +681,30 @@ pub const Scope = struct {...@@ -666,37 +681,30 @@ pub const Scope = struct {
666 }681 }
667 };682 };
668683
669 /// This is a temporary structure, references to it are valid only684 /// 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
670 /// during semantic analysis of the block.687 /// during semantic analysis of the block.
671 pub const Block = struct {688 pub const Block = struct {
672 pub const base_tag: Tag = .block;689 pub const base_tag: Tag = .block;
673690
674 base: Scope = Scope{ .tag = base_tag },691 base: Scope = Scope{ .tag = base_tag },
675 parent: ?*Block,692 parent: ?*Block,
676 /// Maps ZIR to TZIR. Shared to sub-blocks.693 /// Shared among all child blocks.
677 inst_table: *InstTable,694 sema: *Sema,
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,
683 /// This Decl is the Decl according to the Zig source code corresponding to this Block.695 /// 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.
684 src_decl: *Decl,698 src_decl: *Decl,
685 instructions: ArrayListUnmanaged(*Inst),699 instructions: ArrayListUnmanaged(*ir.Inst),
686 /// Points to the arena allocator of the Decl.
687 arena: *Allocator,
688 label: ?Label = null,700 label: ?Label = null,
689 inlining: ?*Inlining,701 inlining: ?*Inlining,
690 is_comptime: bool,702 is_comptime: bool,
691 /// Shared to sub-blocks.
692 branch_quota: *u32,
693
694 pub const InstTable = std.AutoHashMap(*zir.Inst, *Inst);
695703
696 /// This `Block` maps a block ZIR instruction to the corresponding704 /// This `Block` maps a block ZIR instruction to the corresponding
697 /// TZIR instruction for break instruction analysis.705 /// TZIR instruction for break instruction analysis.
698 pub const Label = struct {706 pub const Label = struct {
699 zir_block: *zir.Inst.Block,707 zir_block: zir.Inst.Index,
700 merges: Merges,708 merges: Merges,
701 };709 };
702710
...@@ -712,7 +720,7 @@ pub const Scope = struct {...@@ -712,7 +720,7 @@ pub const Scope = struct {
712 /// which parameter index they are, without having to store720 /// which parameter index they are, without having to store
713 /// a parameter index with each arg instruction.721 /// a parameter index with each arg instruction.
714 param_index: usize,722 param_index: usize,
715 casted_args: []*Inst,723 casted_args: []*ir.Inst,
716 merges: Merges,724 merges: Merges,
717725
718 pub const Shared = struct {726 pub const Shared = struct {
...@@ -722,25 +730,25 @@ pub const Scope = struct {...@@ -722,25 +730,25 @@ pub const Scope = struct {
722 };730 };
723731
724 pub const Merges = struct {732 pub const Merges = struct {
725 block_inst: *Inst.Block,733 block_inst: *ir.Inst.Block,
726 /// Separate array list from break_inst_list so that it can be passed directly734 /// Separate array list from break_inst_list so that it can be passed directly
727 /// to resolvePeerTypes.735 /// to resolvePeerTypes.
728 results: ArrayListUnmanaged(*Inst),736 results: ArrayListUnmanaged(*ir.Inst),
729 /// Keeps track of the break instructions so that the operand can be replaced737 /// Keeps track of the break instructions so that the operand can be replaced
730 /// if we need to add type coercion at the end of block analysis.738 /// if we need to add type coercion at the end of block analysis.
731 /// Same indexes, capacity, length as `results`.739 /// Same indexes, capacity, length as `results`.
732 br_list: ArrayListUnmanaged(*Inst.Br),740 br_list: ArrayListUnmanaged(*ir.Inst.Br),
733 };741 };
734742
735 /// For debugging purposes.743 /// For debugging purposes.
736 pub fn dump(self: *Block, mod: Module) void {744 pub fn dump(block: *Block, mod: Module) void {
737 zir.dumpBlock(mod, self);745 zir.dumpBlock(mod, block);
738 }746 }
739747
740 pub fn makeSubBlock(parent: *Block) Block {748 pub fn makeSubBlock(parent: *Block) Block {
741 return .{749 return .{
742 .parent = parent,750 .parent = parent,
743 .inst_table = parent.inst_table,751 .inst_map = parent.inst_map,
744 .func = parent.func,752 .func = parent.func,
745 .owner_decl = parent.owner_decl,753 .owner_decl = parent.owner_decl,
746 .src_decl = parent.src_decl,754 .src_decl = parent.src_decl,
...@@ -752,27 +760,186 @@ pub const Scope = struct {...@@ -752,27 +760,186 @@ pub const Scope = struct {
752 .branch_quota = parent.branch_quota,760 .branch_quota = parent.branch_quota,
753 };761 };
754 }762 }
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 }
755 };921 };
756922
757 /// This is a temporary structure, references to it are valid only923 /// This is a temporary structure; references to it are valid only
758 /// during semantic analysis of the decl.924 /// while constructing a `zir.Code`.
759 pub const GenZIR = struct {925 pub const GenZir = struct {
760 pub const base_tag: Tag = .gen_zir;926 pub const base_tag: Tag = .gen_zir;
761 base: Scope = Scope{ .tag = base_tag },927 base: Scope = Scope{ .tag = base_tag },
762 /// Parents can be: `GenZIR`, `File`
763 parent: *Scope,
764 decl: *Decl,
765 arena: *Allocator,
766 force_comptime: bool,928 force_comptime: bool,
767 /// The first N instructions in a function body ZIR are arg instructions.929 /// Parents can be: `GenZir`, `File`
768 instructions: std.ArrayListUnmanaged(*zir.Inst) = .{},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) = .{},
769 label: ?Label = null,936 label: ?Label = null,
770 break_block: ?*zir.Inst.Block = null,937 break_block: zir.Inst.Index = 0,
771 continue_block: ?*zir.Inst.Block = null,938 continue_block: zir.Inst.Index = 0,
772 /// Only valid when setBlockResultLoc is called.939 /// Only valid when setBlockResultLoc is called.
773 break_result_loc: astgen.ResultLoc = undefined,940 break_result_loc: astgen.ResultLoc = undefined,
774 /// When a block has a pointer result location, here it is.941 /// When a block has a pointer result location, here it is.
775 rl_ptr: ?*zir.Inst = null,942 rl_ptr: zir.Inst.Index = 0,
776 /// Keeps track of how many branches of a block did not actually943 /// Keeps track of how many branches of a block did not actually
777 /// consume the result location. astgen uses this to figure out944 /// consume the result location. astgen uses this to figure out
778 /// whether to rely on break instructions or writing to the result945 /// whether to rely on break instructions or writing to the result
...@@ -784,19 +951,95 @@ pub const Scope = struct {...@@ -784,19 +951,95 @@ pub const Scope = struct {
784 break_count: usize = 0,951 break_count: usize = 0,
785 /// Tracks `break :foo bar` instructions so they can possibly be elided later if952 /// Tracks `break :foo bar` instructions so they can possibly be elided later if
786 /// the labeled block ends up not needing a result location pointer.953 /// 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) = .{},
788 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions955 /// Tracks `store_to_block_ptr` instructions that correspond to break instructions
789 /// so they can possibly be elided later if the labeled block ends up not needing956 /// so they can possibly be elided later if the labeled block ends up not needing
790 /// a result location pointer.957 /// a result location pointer.
791 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(*zir.Inst.BinOp) = .{},958 labeled_store_to_block_ptr_list: std.ArrayListUnmanaged(zir.Inst.Index) = .{},
792 /// for suspend error notes
793 src: usize = 0,
794959
795 pub const Label = struct {960 pub const Label = struct {
796 token: ast.TokenIndex,961 token: ast.TokenIndex,
797 block_inst: *zir.Inst.Block,962 block_inst: zir.Inst.Index,
798 used: bool = false,963 used: bool = false,
799 };964 };
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 }
800 };1043 };
8011044
802 /// This is always a `const` local and importantly the `inst` is a value type, not a pointer.1045 /// 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 {...@@ -805,11 +1048,11 @@ pub const Scope = struct {
805 pub const LocalVal = struct {1048 pub const LocalVal = struct {
806 pub const base_tag: Tag = .local_val;1049 pub const base_tag: Tag = .local_val;
807 base: Scope = Scope{ .tag = base_tag },1050 base: Scope = Scope{ .tag = base_tag },
808 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.1051 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
809 parent: *Scope,1052 parent: *Scope,
810 gen_zir: *GenZIR,1053 gen_zir: *GenZir,
811 name: []const u8,1054 name: []const u8,
812 inst: *zir.Inst,1055 inst: zir.Inst.Index,
813 };1056 };
8141057
815 /// This could be a `const` or `var` local. It has a pointer instead of a value.1058 /// This could be a `const` or `var` local. It has a pointer instead of a value.
...@@ -818,24 +1061,42 @@ pub const Scope = struct {...@@ -818,24 +1061,42 @@ pub const Scope = struct {
818 pub const LocalPtr = struct {1061 pub const LocalPtr = struct {
819 pub const base_tag: Tag = .local_ptr;1062 pub const base_tag: Tag = .local_ptr;
820 base: Scope = Scope{ .tag = base_tag },1063 base: Scope = Scope{ .tag = base_tag },
821 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.1064 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
822 parent: *Scope,1065 parent: *Scope,
823 gen_zir: *GenZIR,1066 gen_zir: *GenZir,
824 name: []const u8,1067 name: []const u8,
825 ptr: *zir.Inst,1068 ptr: zir.Inst.Index,
826 };1069 };
8271070
828 pub const Nosuspend = struct {1071 pub const Nosuspend = struct {
829 pub const base_tag: Tag = .gen_nosuspend;1072 pub const base_tag: Tag = .gen_nosuspend;
8301073
831 base: Scope = Scope{ .tag = base_tag },1074 base: Scope = Scope{ .tag = base_tag },
832 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZIR`.1075 /// Parents can be: `LocalVal`, `LocalPtr`, `GenZir`.
833 parent: *Scope,1076 parent: *Scope,
834 gen_zir: *GenZIR,1077 gen_zir: *GenZir,
835 src: usize,1078 src: LazySrcLoc,
836 };1079 };
837};1080};
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
839/// This struct holds data necessary to construct API-facing `AllErrors.Message`.1100/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
840/// Its memory is managed with the general purpose allocator so that they1101/// Its memory is managed with the general purpose allocator so that they
841/// can be created and destroyed in response to incremental updates.1102/// can be created and destroyed in response to incremental updates.
...@@ -855,17 +1116,17 @@ pub const ErrorMsg = struct {...@@ -855,17 +1116,17 @@ pub const ErrorMsg = struct {
855 comptime format: []const u8,1116 comptime format: []const u8,
856 args: anytype,1117 args: anytype,
857 ) !*ErrorMsg {1118 ) !*ErrorMsg {
858 const self = try gpa.create(ErrorMsg);1119 const err_msg = try gpa.create(ErrorMsg);
859 errdefer gpa.destroy(self);1120 errdefer gpa.destroy(err_msg);
860 self.* = try init(gpa, src_loc, format, args);1121 err_msg.* = try init(gpa, src_loc, format, args);
861 return self;1122 return err_msg;
862 }1123 }
8631124
864 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,1125 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`,
865 /// as well as all notes.1126 /// as well as all notes.
866 pub fn destroy(self: *ErrorMsg, gpa: *Allocator) void {1127 pub fn destroy(err_msg: *ErrorMsg, gpa: *Allocator) void {
867 self.deinit(gpa);1128 err_msg.deinit(gpa);
868 gpa.destroy(self);1129 gpa.destroy(err_msg);
869 }1130 }
8701131
871 pub fn init(1132 pub fn init(
...@@ -880,84 +1141,231 @@ pub const ErrorMsg = struct {...@@ -880,84 +1141,231 @@ pub const ErrorMsg = struct {
880 };1141 };
881 }1142 }
8821143
883 pub fn deinit(self: *ErrorMsg, gpa: *Allocator) void {1144 pub fn deinit(err_msg: *ErrorMsg, gpa: *Allocator) void {
884 for (self.notes) |*note| {1145 for (err_msg.notes) |*note| {
885 note.deinit(gpa);1146 note.deinit(gpa);
886 }1147 }
887 gpa.free(self.notes);1148 gpa.free(err_msg.notes);
888 gpa.free(self.msg);1149 gpa.free(err_msg.msg);
889 self.* = undefined;1150 err_msg.* = undefined;
890 }1151 }
891};1152};
8921153
893/// Canonical reference to a position within a source file.1154/// Canonical reference to a position within a source file.
894pub const SrcLoc = struct {1155pub const SrcLoc = struct {
895 file_scope: *Scope.File,1156 /// The active field is determined by tag of `lazy`.
896 byte_offset: usize,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,
897};1305};
8981306
899pub const InnerError = error{ OutOfMemory, AnalysisFail };1307pub const InnerError = error{ OutOfMemory, AnalysisFail };
9001308
901pub fn deinit(self: *Module) void {1309pub fn deinit(mod: *Module) void {
902 const gpa = self.gpa;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| {1318 for (mod.decl_table.items()) |entry| {
911 entry.value.destroy(self);1319 entry.value.destroy(mod);
912 }1320 }
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| {
916 entry.value.destroy(gpa);1324 entry.value.destroy(gpa);
917 }1325 }
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| {
921 entry.value.destroy(gpa);1329 entry.value.destroy(gpa);
922 }1330 }
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| {
926 entry.value.destroy(gpa);1334 entry.value.destroy(gpa);
927 }1335 }
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| {
931 entry.value.destroy(gpa);1339 entry.value.destroy(gpa);
932 }1340 }
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| {
938 const export_list = entry.value;1346 const export_list = entry.value;
939 gpa.free(export_list);1347 gpa.free(export_list);
940 }1348 }
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| {
944 freeExportList(gpa, entry.value);1352 freeExportList(gpa, entry.value);
945 }1353 }
946 self.export_owners.deinit(gpa);1354 mod.export_owners.deinit(gpa);
9471355
948 self.symbol_exports.deinit(gpa);1356 mod.symbol_exports.deinit(gpa);
949 self.root_scope.destroy(gpa);1357 mod.root_scope.destroy(gpa);
9501358
951 var it = self.global_error_set.iterator();1359 var it = mod.global_error_set.iterator();
952 while (it.next()) |entry| {1360 while (it.next()) |entry| {
953 gpa.free(entry.key);1361 gpa.free(entry.key);
954 }1362 }
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| {
958 entry.value.destroy(gpa);1366 entry.value.destroy(gpa);
959 }1367 }
960 self.import_table.deinit(gpa);1368 mod.import_table.deinit(gpa);
961}1369}
9621370
963fn freeExportList(gpa: *Allocator, export_list: []*Export) void {1371fn freeExportList(gpa: *Allocator, export_list: []*Export) void {
...@@ -1102,28 +1510,37 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -1102,28 +1510,37 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
1102 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.1510 // A comptime decl does not store any value so we can just deinit this arena after analysis is done.
1103 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);1511 var analysis_arena = std.heap.ArenaAllocator.init(mod.gpa);
1104 defer analysis_arena.deinit();1512 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;1514 const code: zir.Code = blk: {
1114 _ = try astgen.comptimeExpr(mod, &gen_scope.base, .none, block_expr);1515 var wip_zir_code: WipZirCode = .{
1115 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {1516 .decl = decl,
1116 zir.dumpZir(mod.gpa, "comptime_block", decl.name, gen_scope.instructions.items) catch {};1517 .arena = &analysis_arena.allocator,
1117 }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);1527 const block_expr = node_datas[decl_node].lhs;
1120 defer inst_table.deinit();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
1124 var block_scope: Scope.Block = .{1542 var block_scope: Scope.Block = .{
1125 .parent = null,1543 .parent = null,
1126 .inst_table = &inst_table,
1127 .func = null,1544 .func = null,
1128 .owner_decl = decl,1545 .owner_decl = decl,
1129 .src_decl = decl,1546 .src_decl = decl,
...@@ -1131,13 +1548,10 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {...@@ -1131,13 +1548,10 @@ fn astgenAndSemaDecl(mod: *Module, decl: *Decl) !bool {
1131 .arena = &analysis_arena.allocator,1548 .arena = &analysis_arena.allocator,
1132 .inlining = null,1549 .inlining = null,
1133 .is_comptime = true,1550 .is_comptime = true,
1134 .branch_quota = &branch_quota,
1135 };1551 };
1136 defer block_scope.instructions.deinit(mod.gpa);1552 defer block_scope.instructions.deinit(mod.gpa);
11371553
1138 _ = try zir_sema.analyzeBody(mod, &block_scope, .{1554 try sema.root(mod, &block_scope);
1139 .instructions = gen_scope.instructions.items,
1140 });
11411555
1142 decl.analysis = .complete;1556 decl.analysis = .complete;
1143 decl.generation = mod.generation;1557 decl.generation = mod.generation;
...@@ -1160,7 +1574,6 @@ fn astgenAndSemaFn(...@@ -1160,7 +1574,6 @@ fn astgenAndSemaFn(
11601574
1161 decl.analysis = .in_progress;1575 decl.analysis = .in_progress;
11621576
1163 const token_starts = tree.tokens.items(.start);
1164 const token_tags = tree.tokens.items(.tag);1577 const token_tags = tree.tokens.items(.tag);
11651578
1166 // This arena allocator's memory is discarded at the end of this function. It is used1579 // This arena allocator's memory is discarded at the end of this function. It is used
...@@ -1168,13 +1581,18 @@ fn astgenAndSemaFn(...@@ -1168,13 +1581,18 @@ fn astgenAndSemaFn(
1168 // to complete the Decl analysis.1581 // to complete the Decl analysis.
1169 var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);1582 var fn_type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
1170 defer fn_type_scope_arena.deinit();1583 defer fn_type_scope_arena.deinit();
1171 var fn_type_scope: Scope.GenZIR = .{1584
1585 var fn_type_wip_zir_exec: WipZirCode = .{
1172 .decl = decl,1586 .decl = decl,
1173 .arena = &fn_type_scope_arena.allocator,1587 .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 = .{
1175 .force_comptime = true,1592 .force_comptime = true,
1593 .parent = &decl.container.base,
1594 .zir_code = &fn_type_wip_zir_exec,
1176 };1595 };
1177 defer fn_type_scope.instructions.deinit(mod.gpa);
11781596
1179 decl.is_pub = fn_proto.visib_token != null;1597 decl.is_pub = fn_proto.visib_token != null;
11801598
...@@ -1189,13 +1607,8 @@ fn astgenAndSemaFn(...@@ -1189,13 +1607,8 @@ fn astgenAndSemaFn(
1189 }1607 }
1190 break :blk count;1608 break :blk count;
1191 };1609 };
1192 const param_types = try fn_type_scope.arena.alloc(*zir.Inst, param_count);1610 const param_types = try fn_type_scope_arena.allocator.alloc(zir.Inst.Index, param_count);
1193 const fn_src = token_starts[fn_proto.ast.fn_token];1611 const type_type_rl: astgen.ResultLoc = .{ .ty = @enumToInt(zir.Const.type_type) };
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 };
11991612
1200 var is_var_args = false;1613 var is_var_args = false;
1201 {1614 {
...@@ -1301,39 +1714,31 @@ fn astgenAndSemaFn(...@@ -1301,39 +1714,31 @@ fn astgenAndSemaFn(
1301 else1714 else
1302 false;1715 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)
1305 // TODO instead of enum literal type, this needs to be the1718 // TODO instead of enum literal type, this needs to be the
1306 // std.builtin.CallingConvention enum. We need to implement importing other files1719 // std.builtin.CallingConvention enum. We need to implement importing other files
1307 // and enums in order to fix this.1720 // and enums in order to fix this.
1308 const src = token_starts[tree.firstToken(fn_proto.ast.callconv_expr)];1721 try astgen.comptimeExpr(mod, &fn_type_scope.base, .{
1309 const enum_lit_ty = try astgen.addZIRInstConst(mod, &fn_type_scope.base, src, .{1722 .ty = @enumToInt(zir.Const.enum_literal_type),
1310 .ty = Type.initTag(.type),1723 }, fn_proto.ast.callconv_expr)
1311 .val = Value.initTag(.enum_literal_type),1724 else if (is_extern) // note: https://github.com/ziglang/zig/issues/5269
1312 });1725 try fn_type_scope.addStrBytes(.enum_literal, "C")
1313 break :cc try astgen.comptimeExpr(mod, &fn_type_scope.base, .{1726 else
1314 .ty = enum_lit_ty,1727 0;
1315 }, fn_proto.ast.callconv_expr);1728
1316 } else if (is_extern) cc: {1729 const fn_type_inst: zir.Inst.Index = if (cc != 0) fn_type: {
1317 // note: https://github.com/ziglang/zig/issues/52691730 const tag: zir.Inst.Tag = if (is_var_args) .fn_type_cc_var_args else .fn_type_cc;
1318 const src = token_starts[fn_proto.extern_export_token.?];1731 break :fn_type try fn_type_scope.addFnTypeCc(.{
1319 break :cc try astgen.addZIRInst(mod, &fn_type_scope.base, src, zir.Inst.EnumLiteral, .{ .name = "C" }, .{});1732 .ret_ty = return_type_inst,
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,
1325 .param_types = param_types,1733 .param_types = param_types,
1326 .cc = cc,1734 .cc = cc,
1327 });1735 });
1328 if (is_var_args) fn_type.tag = .fn_type_cc_var_args;
1329 break :fn_type fn_type;
1330 } else fn_type: {1736 } else fn_type: {
1331 var fn_type = try astgen.addZirInstTag(mod, &fn_type_scope.base, fn_src, .fn_type, .{1737 const tag: zir.Inst.Tag = if (is_var_args) .fn_type_var_args else .fn_type;
1332 .return_type = return_type_inst,1738 break :fn_type try fn_type_scope.addFnType(.{
1739 .ret_ty = return_type_inst,
1333 .param_types = param_types,1740 .param_types = param_types,
1334 });1741 });
1335 if (is_var_args) fn_type.tag = .fn_type_var_args;
1336 break :fn_type fn_type;
1337 };1742 };
13381743
1339 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {1744 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
...@@ -1345,14 +1750,17 @@ fn astgenAndSemaFn(...@@ -1345,14 +1750,17 @@ fn astgenAndSemaFn(
1345 errdefer decl_arena.deinit();1750 errdefer decl_arena.deinit();
1346 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);1751 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
13471752
1348 var inst_table = Scope.Block.InstTable.init(mod.gpa);1753 const fn_type_code = fn_type_wip_zir_exec.finish();
1349 defer inst_table.deinit();1754 var fn_type_sema: Sema = .{
13501755 .mod = mod,
1351 var branch_quota: u32 = default_eval_branch_quota;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
1353 var block_scope: Scope.Block = .{1761 var block_scope: Scope.Block = .{
1354 .parent = null,1762 .parent = null,
1355 .inst_table = &inst_table,1763 .sema = &fn_type_sema,
1356 .func = null,1764 .func = null,
1357 .owner_decl = decl,1765 .owner_decl = decl,
1358 .src_decl = decl,1766 .src_decl = decl,
...@@ -1360,14 +1768,10 @@ fn astgenAndSemaFn(...@@ -1360,14 +1768,10 @@ fn astgenAndSemaFn(
1360 .arena = &decl_arena.allocator,1768 .arena = &decl_arena.allocator,
1361 .inlining = null,1769 .inlining = null,
1362 .is_comptime = false,1770 .is_comptime = false,
1363 .branch_quota = &branch_quota,
1364 };1771 };
1365 defer block_scope.instructions.deinit(mod.gpa);1772 defer block_scope.instructions.deinit(mod.gpa);
13661773
1367 const fn_type = try zir_sema.analyzeBodyValueAsType(mod, &block_scope, fn_type_inst, .{1774 const fn_type = try fn_type_sema.rootAsType(mod, &block_scope, fn_type_inst);
1368 .instructions = fn_type_scope.instructions.items,
1369 });
1370
1371 if (body_node == 0) {1775 if (body_node == 0) {
1372 if (!is_extern) {1776 if (!is_extern) {
1373 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});1777 return mod.failNode(&block_scope.base, fn_proto.ast.fn_token, "non-extern function has no body", .{});
...@@ -1411,43 +1815,47 @@ fn astgenAndSemaFn(...@@ -1411,43 +1815,47 @@ fn astgenAndSemaFn(
14111815
1412 const fn_zir: zir.Body = blk: {1816 const fn_zir: zir.Body = blk: {
1413 // We put the ZIR inside the Decl arena.1817 // We put the ZIR inside the Decl arena.
1414 var gen_scope: Scope.GenZIR = .{1818 var wip_zir_code: WipZirCode = .{
1415 .decl = decl,1819 .decl = decl,
1416 .arena = &decl_arena.allocator,1820 .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 = .{
1418 .force_comptime = false,1827 .force_comptime = false,
1828 .parent = &decl.container.base,
1829 .zir_code = &wip_zir_code,
1419 };1830 };
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);
1424 var params_scope = &gen_scope.base;1836 var params_scope = &gen_scope.base;
1425 var i: usize = 0;1837 var i: usize = 0;
1426 var it = fn_proto.iterate(tree);1838 var it = fn_proto.iterate(tree);
1427 while (it.next()) |param| : (i += 1) {1839 while (it.next()) |param| : (i += 1) {
1428 const name_token = param.name_token.?;1840 const name_token = param.name_token.?;
1429 const src = token_starts[name_token];
1430 const param_name = try mod.identifierTokenString(&gen_scope.base, name_token);1841 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;
1443 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);1842 const sub_scope = try decl_arena.allocator.create(Scope.LocalVal);
1444 sub_scope.* = .{1843 sub_scope.* = .{
1445 .parent = params_scope,1844 .parent = params_scope,
1446 .gen_zir = &gen_scope,1845 .gen_zir = &gen_scope,
1447 .name = param_name,1846 .name = param_name,
1448 .inst = &arg.base,1847 // Implicit const list first, then implicit arg list.
1848 .inst = zir.const_inst_list.len + i,
1449 };1849 };
1450 params_scope = &sub_scope.base;1850 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);
1451 }1859 }
14521860
1453 _ = try astgen.expr(mod, params_scope, .none, body_node);1861 _ = try astgen.expr(mod, params_scope, .none, body_node);
...@@ -1455,8 +1863,7 @@ fn astgenAndSemaFn(...@@ -1455,8 +1863,7 @@ fn astgenAndSemaFn(
1455 if (gen_scope.instructions.items.len == 0 or1863 if (gen_scope.instructions.items.len == 0 or
1456 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())1864 !gen_scope.instructions.items[gen_scope.instructions.items.len - 1].tag.isNoReturn())
1457 {1865 {
1458 const src = token_starts[tree.lastToken(body_node)];1866 _ = try gen_scope.addRetTok(@enumToInt(zir.Const.void_value), tree.lastToken(body_node));
1459 _ = try astgen.addZIRNoOp(mod, &gen_scope.base, src, .return_void);
1460 }1867 }
14611868
1462 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {1869 if (std.builtin.mode == .Debug and mod.comp.verbose_ir) {
...@@ -1626,7 +2033,7 @@ fn astgenAndSemaVarDecl(...@@ -1626,7 +2033,7 @@ fn astgenAndSemaVarDecl(
1626 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {2033 const var_info: struct { ty: Type, val: ?Value } = if (var_decl.ast.init_node != 0) vi: {
1627 var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);2034 var gen_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
1628 defer gen_scope_arena.deinit();2035 defer gen_scope_arena.deinit();
1629 var gen_scope: Scope.GenZIR = .{2036 var gen_scope: Scope.GenZir = .{
1630 .decl = decl,2037 .decl = decl,
1631 .arena = &gen_scope_arena.allocator,2038 .arena = &gen_scope_arena.allocator,
1632 .parent = &decl.container.base,2039 .parent = &decl.container.base,
...@@ -1698,7 +2105,7 @@ fn astgenAndSemaVarDecl(...@@ -1698,7 +2105,7 @@ fn astgenAndSemaVarDecl(
1698 // Temporary arena for the zir instructions.2105 // Temporary arena for the zir instructions.
1699 var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);2106 var type_scope_arena = std.heap.ArenaAllocator.init(mod.gpa);
1700 defer type_scope_arena.deinit();2107 defer type_scope_arena.deinit();
1701 var type_scope: Scope.GenZIR = .{2108 var type_scope: Scope.GenZir = .{
1702 .decl = decl,2109 .decl = decl,
1703 .arena = &type_scope_arena.allocator,2110 .arena = &type_scope_arena.allocator,
1704 .parent = &decl.container.base,2111 .parent = &decl.container.base,
...@@ -1778,47 +2185,47 @@ fn astgenAndSemaVarDecl(...@@ -1778,47 +2185,47 @@ fn astgenAndSemaVarDecl(
1778 return type_changed;2185 return type_changed;
1779}2186}
17802187
1781fn declareDeclDependency(self: *Module, depender: *Decl, dependee: *Decl) !void {2188fn declareDeclDependency(mod: *Module, depender: *Decl, dependee: *Decl) !void {
1782 try depender.dependencies.ensureCapacity(self.gpa, depender.dependencies.items().len + 1);2189 try depender.dependencies.ensureCapacity(mod.gpa, depender.dependencies.items().len + 1);
1783 try dependee.dependants.ensureCapacity(self.gpa, dependee.dependants.items().len + 1);2190 try dependee.dependants.ensureCapacity(mod.gpa, dependee.dependants.items().len + 1);
17842191
1785 depender.dependencies.putAssumeCapacity(dependee, {});2192 depender.dependencies.putAssumeCapacity(dependee, {});
1786 dependee.dependants.putAssumeCapacity(depender, {});2193 dependee.dependants.putAssumeCapacity(depender, {});
1787}2194}
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 {
1790 const tracy = trace(@src());2197 const tracy = trace(@src());
1791 defer tracy.end();2198 defer tracy.end();
17922199
1793 switch (root_scope.status) {2200 switch (root_scope.status) {
1794 .never_loaded, .unloaded_success => {2201 .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
1799 var keep_tree = false;2206 var keep_tree = false;
1800 root_scope.tree = try std.zig.parse(self.gpa, source);2207 root_scope.tree = try std.zig.parse(mod.gpa, source);
1801 defer if (!keep_tree) root_scope.tree.deinit(self.gpa);2208 defer if (!keep_tree) root_scope.tree.deinit(mod.gpa);
18022209
1803 const tree = &root_scope.tree;2210 const tree = &root_scope.tree;
18042211
1805 if (tree.errors.len != 0) {2212 if (tree.errors.len != 0) {
1806 const parse_err = tree.errors[0];2213 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);
1809 defer msg.deinit();2216 defer msg.deinit();
18102217
1811 try tree.renderError(parse_err, msg.writer());2218 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);
1813 err_msg.* = .{2220 err_msg.* = .{
1814 .src_loc = .{2221 .src_loc = .{
1815 .file_scope = root_scope,2222 .container = .{ .file_scope = root_scope },
1816 .byte_offset = tree.tokens.items(.start)[parse_err.token],2223 .lazy = .{ .token_abs = parse_err.token },
1817 },2224 },
1818 .msg = msg.toOwnedSlice(),2225 .msg = msg.toOwnedSlice(),
1819 };2226 };
18202227
1821 self.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);2228 mod.failed_files.putAssumeCapacityNoClobber(&root_scope.base, err_msg);
1822 root_scope.status = .unloaded_parse_failure;2229 root_scope.status = .unloaded_parse_failure;
1823 return error.AnalysisFail;2230 return error.AnalysisFail;
1824 }2231 }
...@@ -2051,11 +2458,9 @@ fn semaContainerFn(...@@ -2051,11 +2458,9 @@ fn semaContainerFn(
2051 const tracy = trace(@src());2458 const tracy = trace(@src());
2052 defer tracy.end();2459 defer tracy.end();
20532460
2054 const token_starts = tree.tokens.items(.start);
2055 const token_tags = tree.tokens.items(.tag);
2056
2057 // We will create a Decl for it regardless of analysis status.2461 // We will create a Decl for it regardless of analysis status.
2058 const name_tok = fn_proto.name_token orelse {2462 const name_tok = fn_proto.name_token orelse {
2463 // This problem will go away with #1717.
2059 @panic("TODO missing function name");2464 @panic("TODO missing function name");
2060 };2465 };
2061 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString2466 const name = tree.tokenSlice(name_tok); // TODO use identifierTokenString
...@@ -2068,8 +2473,8 @@ fn semaContainerFn(...@@ -2068,8 +2473,8 @@ fn semaContainerFn(
2068 if (deleted_decls.swapRemove(decl) == null) {2473 if (deleted_decls.swapRemove(decl) == null) {
2069 decl.analysis = .sema_failure;2474 decl.analysis = .sema_failure;
2070 const msg = try ErrorMsg.create(mod.gpa, .{2475 const msg = try ErrorMsg.create(mod.gpa, .{
2071 .file_scope = container_scope.file_scope,2476 .container = .{ .file_scope = container_scope.file_scope },
2072 .byte_offset = token_starts[name_tok],2477 .lazy = .{ .token_abs = name_tok },
2073 }, "redefinition of '{s}'", .{decl.name});2478 }, "redefinition of '{s}'", .{decl.name});
2074 errdefer msg.destroy(mod.gpa);2479 errdefer msg.destroy(mod.gpa);
2075 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);2480 try mod.failed_decls.putNoClobber(mod.gpa, decl, msg);
...@@ -2098,6 +2503,7 @@ fn semaContainerFn(...@@ -2098,6 +2503,7 @@ fn semaContainerFn(
2098 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);2503 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
2099 container_scope.decls.putAssumeCapacity(new_decl, {});2504 container_scope.decls.putAssumeCapacity(new_decl, {});
2100 if (fn_proto.extern_export_token) |maybe_export_token| {2505 if (fn_proto.extern_export_token) |maybe_export_token| {
2506 const token_tags = tree.tokens.items(.tag);
2101 if (token_tags[maybe_export_token] == .keyword_export) {2507 if (token_tags[maybe_export_token] == .keyword_export) {
2102 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });2508 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
2103 }2509 }
...@@ -2117,11 +2523,7 @@ fn semaContainerVar(...@@ -2117,11 +2523,7 @@ fn semaContainerVar(
2117 const tracy = trace(@src());2523 const tracy = trace(@src());
2118 defer tracy.end();2524 defer tracy.end();
21192525
2120 const token_starts = tree.tokens.items(.start);
2121 const token_tags = tree.tokens.items(.tag);
2122
2123 const name_token = var_decl.ast.mut_token + 1;2526 const name_token = var_decl.ast.mut_token + 1;
2124 const name_src = token_starts[name_token];
2125 const name = tree.tokenSlice(name_token); // TODO identifierTokenString2527 const name = tree.tokenSlice(name_token); // TODO identifierTokenString
2126 const name_hash = container_scope.fullyQualifiedNameHash(name);2528 const name_hash = container_scope.fullyQualifiedNameHash(name);
2127 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));2529 const contents_hash = std.zig.hashSrc(tree.getNodeSource(decl_node));
...@@ -2132,8 +2534,8 @@ fn semaContainerVar(...@@ -2132,8 +2534,8 @@ fn semaContainerVar(
2132 if (deleted_decls.swapRemove(decl) == null) {2534 if (deleted_decls.swapRemove(decl) == null) {
2133 decl.analysis = .sema_failure;2535 decl.analysis = .sema_failure;
2134 const err_msg = try ErrorMsg.create(mod.gpa, .{2536 const err_msg = try ErrorMsg.create(mod.gpa, .{
2135 .file_scope = container_scope.file_scope,2537 .container = .{ .file_scope = container_scope.file_scope },
2136 .byte_offset = name_src,2538 .lazy = .{ .token_abs = name_token },
2137 }, "redefinition of '{s}'", .{decl.name});2539 }, "redefinition of '{s}'", .{decl.name});
2138 errdefer err_msg.destroy(mod.gpa);2540 errdefer err_msg.destroy(mod.gpa);
2139 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);2541 try mod.failed_decls.putNoClobber(mod.gpa, decl, err_msg);
...@@ -2145,6 +2547,7 @@ fn semaContainerVar(...@@ -2145,6 +2547,7 @@ fn semaContainerVar(
2145 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);2547 const new_decl = try mod.createNewDecl(&container_scope.base, name, decl_i, name_hash, contents_hash);
2146 container_scope.decls.putAssumeCapacity(new_decl, {});2548 container_scope.decls.putAssumeCapacity(new_decl, {});
2147 if (var_decl.extern_export_token) |maybe_export_token| {2549 if (var_decl.extern_export_token) |maybe_export_token| {
2550 const token_tags = tree.tokens.items(.tag);
2148 if (token_tags[maybe_export_token] == .keyword_export) {2551 if (token_tags[maybe_export_token] == .keyword_export) {
2149 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });2552 mod.comp.work_queue.writeItemAssumeCapacity(.{ .analyze_decl = new_decl });
2150 }2553 }
...@@ -2167,11 +2570,11 @@ fn semaContainerField(...@@ -2167,11 +2570,11 @@ fn semaContainerField(
2167 log.err("TODO: analyze container field", .{});2570 log.err("TODO: analyze container field", .{});
2168}2571}
21692572
2170pub fn deleteDecl(self: *Module, decl: *Decl) !void {2573pub fn deleteDecl(mod: *Module, decl: *Decl) !void {
2171 const tracy = trace(@src());2574 const tracy = trace(@src());
2172 defer tracy.end();2575 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
2176 // Remove from the namespace it resides in. In the case of an anonymous Decl it will2579 // Remove from the namespace it resides in. In the case of an anonymous Decl it will
2177 // not be present in the set, and this does nothing.2580 // not be present in the set, and this does nothing.
...@@ -2179,7 +2582,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {...@@ -2179,7 +2582,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
21792582
2180 log.debug("deleting decl '{s}'", .{decl.name});2583 log.debug("deleting decl '{s}'", .{decl.name});
2181 const name_hash = decl.fullyQualifiedNameHash();2584 const name_hash = decl.fullyQualifiedNameHash();
2182 self.decl_table.removeAssertDiscard(name_hash);2585 mod.decl_table.removeAssertDiscard(name_hash);
2183 // Remove itself from its dependencies, because we are about to destroy the decl pointer.2586 // Remove itself from its dependencies, because we are about to destroy the decl pointer.
2184 for (decl.dependencies.items()) |entry| {2587 for (decl.dependencies.items()) |entry| {
2185 const dep = entry.key;2588 const dep = entry.key;
...@@ -2188,7 +2591,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {...@@ -2188,7 +2591,7 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
2188 // We don't recursively perform a deletion here, because during the update,2591 // We don't recursively perform a deletion here, because during the update,
2189 // another reference to it may turn up.2592 // another reference to it may turn up.
2190 dep.deletion_flag = true;2593 dep.deletion_flag = true;
2191 self.deletion_set.appendAssumeCapacity(dep);2594 mod.deletion_set.appendAssumeCapacity(dep);
2192 }2595 }
2193 }2596 }
2194 // Anything that depends on this deleted decl certainly needs to be re-analyzed.2597 // 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 {...@@ -2197,29 +2600,29 @@ pub fn deleteDecl(self: *Module, decl: *Decl) !void {
2197 dep.removeDependency(decl);2600 dep.removeDependency(decl);
2198 if (dep.analysis != .outdated) {2601 if (dep.analysis != .outdated) {
2199 // TODO Move this failure possibility to the top of the function.2602 // TODO Move this failure possibility to the top of the function.
2200 try self.markOutdatedDecl(dep);2603 try mod.markOutdatedDecl(dep);
2201 }2604 }
2202 }2605 }
2203 if (self.failed_decls.swapRemove(decl)) |entry| {2606 if (mod.failed_decls.swapRemove(decl)) |entry| {
2204 entry.value.destroy(self.gpa);2607 entry.value.destroy(mod.gpa);
2205 }2608 }
2206 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {2609 if (mod.emit_h_failed_decls.swapRemove(decl)) |entry| {
2207 entry.value.destroy(self.gpa);2610 entry.value.destroy(mod.gpa);
2208 }2611 }
2209 _ = self.compile_log_decls.swapRemove(decl);2612 _ = mod.compile_log_decls.swapRemove(decl);
2210 self.deleteDeclExports(decl);2613 mod.deleteDeclExports(decl);
2211 self.comp.bin_file.freeDecl(decl);2614 mod.comp.bin_file.freeDecl(decl);
22122615
2213 decl.destroy(self);2616 decl.destroy(mod);
2214}2617}
22152618
2216/// Delete all the Export objects that are caused by this Decl. Re-analysis of2619/// Delete all the Export objects that are caused by this Decl. Re-analysis of
2217/// this Decl will cause them to be re-created (or not).2620/// this Decl will cause them to be re-created (or not).
2218fn deleteDeclExports(self: *Module, decl: *Decl) void {2621fn deleteDeclExports(mod: *Module, decl: *Decl) void {
2219 const kv = self.export_owners.swapRemove(decl) orelse return;2622 const kv = mod.export_owners.swapRemove(decl) orelse return;
22202623
2221 for (kv.value) |exp| {2624 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| {
2223 // Remove exports with owner_decl matching the regenerating decl.2626 // Remove exports with owner_decl matching the regenerating decl.
2224 const list = decl_exports_kv.value;2627 const list = decl_exports_kv.value;
2225 var i: usize = 0;2628 var i: usize = 0;
...@@ -2232,73 +2635,100 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {...@@ -2232,73 +2635,100 @@ fn deleteDeclExports(self: *Module, decl: *Decl) void {
2232 i += 1;2635 i += 1;
2233 }2636 }
2234 }2637 }
2235 decl_exports_kv.value = self.gpa.shrink(list, new_len);2638 decl_exports_kv.value = mod.gpa.shrink(list, new_len);
2236 if (new_len == 0) {2639 if (new_len == 0) {
2237 self.decl_exports.removeAssertDiscard(exp.exported_decl);2640 mod.decl_exports.removeAssertDiscard(exp.exported_decl);
2238 }2641 }
2239 }2642 }
2240 if (self.comp.bin_file.cast(link.File.Elf)) |elf| {2643 if (mod.comp.bin_file.cast(link.File.Elf)) |elf| {
2241 elf.deleteExport(exp.link.elf);2644 elf.deleteExport(exp.link.elf);
2242 }2645 }
2243 if (self.comp.bin_file.cast(link.File.MachO)) |macho| {2646 if (mod.comp.bin_file.cast(link.File.MachO)) |macho| {
2244 macho.deleteExport(exp.link.macho);2647 macho.deleteExport(exp.link.macho);
2245 }2648 }
2246 if (self.failed_exports.swapRemove(exp)) |entry| {2649 if (mod.failed_exports.swapRemove(exp)) |entry| {
2247 entry.value.destroy(self.gpa);2650 entry.value.destroy(mod.gpa);
2248 }2651 }
2249 _ = self.symbol_exports.swapRemove(exp.options.name);2652 _ = mod.symbol_exports.swapRemove(exp.options.name);
2250 self.gpa.free(exp.options.name);2653 mod.gpa.free(exp.options.name);
2251 self.gpa.destroy(exp);2654 mod.gpa.destroy(exp);
2252 }2655 }
2253 self.gpa.free(kv.value);2656 mod.gpa.free(kv.value);
2254}2657}
22552658
2256pub fn analyzeFnBody(self: *Module, decl: *Decl, func: *Fn) !void {2659pub fn analyzeFnBody(mod: *Module, decl: *Decl, func: *Fn) !void {
2257 const tracy = trace(@src());2660 const tracy = trace(@src());
2258 defer tracy.end();2661 defer tracy.end();
22592662
2260 // Use the Decl's arena for function memory.2663 // 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);
2262 defer decl.typed_value.most_recent.arena.?.* = arena.state;2665 defer decl.typed_value.most_recent.arena.?.* = arena.state;
2263 var inst_table = Scope.Block.InstTable.init(self.gpa);2666
2264 defer inst_table.deinit();2667 const inst_map = try mod.gpa.alloc(*ir.Inst, func.zir.instructions.len);
2265 var branch_quota: u32 = default_eval_branch_quota;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
2267 var inner_block: Scope.Block = .{2700 var inner_block: Scope.Block = .{
2268 .parent = null,2701 .parent = null,
2269 .inst_table = &inst_table,2702 .sema = &sema,
2270 .func = func,
2271 .owner_decl = decl,
2272 .src_decl = decl,2703 .src_decl = decl,
2273 .instructions = .{},2704 .instructions = .{},
2274 .arena = &arena.allocator,2705 .arena = &arena.allocator,
2275 .inlining = null,2706 .inlining = null,
2276 .is_comptime = false,2707 .is_comptime = false,
2277 .branch_quota = &branch_quota,
2278 };2708 };
2279 defer inner_block.instructions.deinit(self.gpa);2709 defer inner_block.instructions.deinit(mod.gpa);
22802710
2281 func.state = .in_progress;2711 func.state = .in_progress;
2282 log.debug("set {s} to in_progress", .{decl.name});2712 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);
2287 func.state = .success;2717 func.state = .success;
2288 func.body = .{ .instructions = instructions };2718 func.body = .{ .instructions = instructions };
2289 log.debug("set {s} to success", .{decl.name});2719 log.debug("set {s} to success", .{decl.name});
2290}2720}
22912721
2292fn markOutdatedDecl(self: *Module, decl: *Decl) !void {2722fn markOutdatedDecl(mod: *Module, decl: *Decl) !void {
2293 log.debug("mark {s} outdated", .{decl.name});2723 log.debug("mark {s} outdated", .{decl.name});
2294 try self.comp.work_queue.writeItem(.{ .analyze_decl = decl });2724 try mod.comp.work_queue.writeItem(.{ .analyze_decl = decl });
2295 if (self.failed_decls.swapRemove(decl)) |entry| {2725 if (mod.failed_decls.swapRemove(decl)) |entry| {
2296 entry.value.destroy(self.gpa);2726 entry.value.destroy(mod.gpa);
2297 }2727 }
2298 if (self.emit_h_failed_decls.swapRemove(decl)) |entry| {2728 if (mod.emit_h_failed_decls.swapRemove(decl)) |entry| {
2299 entry.value.destroy(self.gpa);2729 entry.value.destroy(mod.gpa);
2300 }2730 }
2301 _ = self.compile_log_decls.swapRemove(decl);2731 _ = mod.compile_log_decls.swapRemove(decl);
2302 decl.analysis = .outdated;2732 decl.analysis = .outdated;
2303}2733}
23042734
...@@ -2349,65 +2779,37 @@ fn allocateNewDecl(...@@ -2349,65 +2779,37 @@ fn allocateNewDecl(
2349}2779}
23502780
2351fn createNewDecl(2781fn createNewDecl(
2352 self: *Module,2782 mod: *Module,
2353 scope: *Scope,2783 scope: *Scope,
2354 decl_name: []const u8,2784 decl_name: []const u8,
2355 src_index: usize,2785 src_index: usize,
2356 name_hash: Scope.NameHash,2786 name_hash: Scope.NameHash,
2357 contents_hash: std.zig.SrcHash,2787 contents_hash: std.zig.SrcHash,
2358) !*Decl {2788) !*Decl {
2359 try self.decl_table.ensureCapacity(self.gpa, self.decl_table.items().len + 1);2789 try mod.decl_table.ensureCapacity(mod.gpa, mod.decl_table.items().len + 1);
2360 const new_decl = try self.allocateNewDecl(scope, src_index, contents_hash);2790 const new_decl = try mod.allocateNewDecl(scope, src_index, contents_hash);
2361 errdefer self.gpa.destroy(new_decl);2791 errdefer mod.gpa.destroy(new_decl);
2362 new_decl.name = try mem.dupeZ(self.gpa, u8, decl_name);2792 new_decl.name = try mem.dupeZ(mod.gpa, u8, decl_name);
2363 self.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);2793 mod.decl_table.putAssumeCapacityNoClobber(name_hash, new_decl);
2364 return new_decl;2794 return new_decl;
2365}2795}
23662796
2367/// Get error value for error tag `name`.2797/// Get error value for error tag `name`.
2368pub fn getErrorValue(self: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {2798pub fn getErrorValue(mod: *Module, name: []const u8) !std.StringHashMapUnmanaged(u16).Entry {
2369 const gop = try self.global_error_set.getOrPut(self.gpa, name);2799 const gop = try mod.global_error_set.getOrPut(mod.gpa, name);
2370 if (gop.found_existing)2800 if (gop.found_existing)
2371 return gop.entry.*;2801 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);2804 gop.entry.key = try mod.gpa.dupe(u8, name);
2375 gop.entry.value = @intCast(u16, self.global_error_set.count() - 1);2805 gop.entry.value = @intCast(u16, mod.global_error_set.count() - 1);
2376 return gop.entry.*;2806 return gop.entry.*;
2377}2807}
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
2407pub fn analyzeExport(2809pub fn analyzeExport(
2408 mod: *Module,2810 mod: *Module,
2409 scope: *Scope,2811 scope: *Scope,
2410 src: usize,2812 src: LazySrcLoc,
2411 borrowed_symbol_name: []const u8,2813 borrowed_symbol_name: []const u8,
2412 exported_decl: *Decl,2814 exported_decl: *Decl,
2413) !void {2815) !void {
...@@ -2496,178 +2898,11 @@ pub fn analyzeExport(...@@ -2496,178 +2898,11 @@ pub fn analyzeExport(
2496 },2898 },
2497 };2899 };
2498}2900}
24992901pub fn constInst(mod: *Module, arena: *Allocator, src: LazySrcLoc, typed_value: TypedValue) !*ir.Inst {
2500pub fn addNoOp(2902 const const_inst = try arena.create(ir.Inst.Constant);
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);
2668 const_inst.* = .{2903 const_inst.* = .{
2669 .base = .{2904 .base = .{
2670 .tag = Inst.Constant.base_tag,2905 .tag = ir.Inst.Constant.base_tag,
2671 .ty = typed_value.ty,2906 .ty = typed_value.ty,
2672 .src = src,2907 .src = src,
2673 },2908 },
...@@ -2676,94 +2911,94 @@ pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedVal...@@ -2676,94 +2911,94 @@ pub fn constInst(self: *Module, scope: *Scope, src: usize, typed_value: TypedVal
2676 return &const_inst.base;2911 return &const_inst.base;
2677}2912}
26782913
2679pub fn constType(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {2914pub fn constType(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type) !*ir.Inst {
2680 return self.constInst(scope, src, .{2915 return mod.constInst(arena, src, .{
2681 .ty = Type.initTag(.type),2916 .ty = Type.initTag(.type),
2682 .val = try ty.toValue(scope.arena()),2917 .val = try ty.toValue(arena),
2683 });2918 });
2684}2919}
26852920
2686pub fn constVoid(self: *Module, scope: *Scope, src: usize) !*Inst {2921pub fn constVoid(mod: *Module, arena: *Allocator, src: LazySrcLoc) !*ir.Inst {
2687 return self.constInst(scope, src, .{2922 return mod.constInst(arena, src, .{
2688 .ty = Type.initTag(.void),2923 .ty = Type.initTag(.void),
2689 .val = Value.initTag(.void_value),2924 .val = Value.initTag(.void_value),
2690 });2925 });
2691}2926}
26922927
2693pub fn constNoReturn(self: *Module, scope: *Scope, src: usize) !*Inst {2928pub fn constNoReturn(mod: *Module, arena: *Allocator, src: LazySrcLoc) !*ir.Inst {
2694 return self.constInst(scope, src, .{2929 return mod.constInst(arena, src, .{
2695 .ty = Type.initTag(.noreturn),2930 .ty = Type.initTag(.noreturn),
2696 .val = Value.initTag(.unreachable_value),2931 .val = Value.initTag(.unreachable_value),
2697 });2932 });
2698}2933}
26992934
2700pub fn constUndef(self: *Module, scope: *Scope, src: usize, ty: Type) !*Inst {2935pub fn constUndef(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type) !*ir.Inst {
2701 return self.constInst(scope, src, .{2936 return mod.constInst(arena, src, .{
2702 .ty = ty,2937 .ty = ty,
2703 .val = Value.initTag(.undef),2938 .val = Value.initTag(.undef),
2704 });2939 });
2705}2940}
27062941
2707pub fn constBool(self: *Module, scope: *Scope, src: usize, v: bool) !*Inst {2942pub fn constBool(mod: *Module, arena: *Allocator, src: LazySrcLoc, v: bool) !*ir.Inst {
2708 return self.constInst(scope, src, .{2943 return mod.constInst(arena, src, .{
2709 .ty = Type.initTag(.bool),2944 .ty = Type.initTag(.bool),
2710 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],2945 .val = ([2]Value{ Value.initTag(.bool_false), Value.initTag(.bool_true) })[@boolToInt(v)],
2711 });2946 });
2712}2947}
27132948
2714pub fn constIntUnsigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: u64) !*Inst {2949pub fn constIntUnsigned(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, int: u64) !*ir.Inst {
2715 return self.constInst(scope, src, .{2950 return mod.constInst(arena, src, .{
2716 .ty = ty,2951 .ty = ty,
2717 .val = try Value.Tag.int_u64.create(scope.arena(), int),2952 .val = try Value.Tag.int_u64.create(arena, int),
2718 });2953 });
2719}2954}
27202955
2721pub fn constIntSigned(self: *Module, scope: *Scope, src: usize, ty: Type, int: i64) !*Inst {2956pub fn constIntSigned(mod: *Module, arena: *Allocator, src: LazySrcLoc, ty: Type, int: i64) !*ir.Inst {
2722 return self.constInst(scope, src, .{2957 return mod.constInst(arena, src, .{
2723 .ty = ty,2958 .ty = ty,
2724 .val = try Value.Tag.int_i64.create(scope.arena(), int),2959 .val = try Value.Tag.int_i64.create(arena, int),
2725 });2960 });
2726}2961}
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 {
2729 if (big_int.positive) {2964 if (big_int.positive) {
2730 if (big_int.to(u64)) |x| {2965 if (big_int.to(u64)) |x| {
2731 return self.constIntUnsigned(scope, src, ty, x);2966 return mod.constIntUnsigned(arena, src, ty, x);
2732 } else |err| switch (err) {2967 } else |err| switch (err) {
2733 error.NegativeIntoUnsigned => unreachable,2968 error.NegativeIntoUnsigned => unreachable,
2734 error.TargetTooSmall => {}, // handled below2969 error.TargetTooSmall => {}, // handled below
2735 }2970 }
2736 return self.constInst(scope, src, .{2971 return mod.constInst(arena, src, .{
2737 .ty = ty,2972 .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),
2739 });2974 });
2740 } else {2975 } else {
2741 if (big_int.to(i64)) |x| {2976 if (big_int.to(i64)) |x| {
2742 return self.constIntSigned(scope, src, ty, x);2977 return mod.constIntSigned(arena, src, ty, x);
2743 } else |err| switch (err) {2978 } else |err| switch (err) {
2744 error.NegativeIntoUnsigned => unreachable,2979 error.NegativeIntoUnsigned => unreachable,
2745 error.TargetTooSmall => {}, // handled below2980 error.TargetTooSmall => {}, // handled below
2746 }2981 }
2747 return self.constInst(scope, src, .{2982 return mod.constInst(arena, src, .{
2748 .ty = ty,2983 .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),
2750 });2985 });
2751 }2986 }
2752}2987}
27532988
2754pub fn createAnonymousDecl(2989pub fn createAnonymousDecl(
2755 self: *Module,2990 mod: *Module,
2756 scope: *Scope,2991 scope: *Scope,
2757 decl_arena: *std.heap.ArenaAllocator,2992 decl_arena: *std.heap.ArenaAllocator,
2758 typed_value: TypedValue,2993 typed_value: TypedValue,
2759) !*Decl {2994) !*Decl {
2760 const name_index = self.getNextAnonNameIndex();2995 const name_index = mod.getNextAnonNameIndex();
2761 const scope_decl = scope.ownerDecl().?;2996 const scope_decl = scope.ownerDecl().?;
2762 const name = try std.fmt.allocPrint(self.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });2997 const name = try std.fmt.allocPrint(mod.gpa, "{s}__anon_{d}", .{ scope_decl.name, name_index });
2763 defer self.gpa.free(name);2998 defer mod.gpa.free(name);
2764 const name_hash = scope.namespace().fullyQualifiedNameHash(name);2999 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
2765 const src_hash: std.zig.SrcHash = undefined;3000 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);
2767 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);3002 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
27683003
2769 decl_arena_state.* = decl_arena.state;3004 decl_arena_state.* = decl_arena.state;
...@@ -2774,32 +3009,32 @@ pub fn createAnonymousDecl(...@@ -2774,32 +3009,32 @@ pub fn createAnonymousDecl(
2774 },3009 },
2775 };3010 };
2776 new_decl.analysis = .complete;3011 new_decl.analysis = .complete;
2777 new_decl.generation = self.generation;3012 new_decl.generation = mod.generation;
27783013
2779 // TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.3014 // TODO: This generates the Decl into the machine code file if it is of a type that is non-zero size.
2780 // We should be able to further improve the compiler to not omit Decls which are only referenced at3015 // We should be able to further improve the compiler to not omit Decls which are only referenced at
2781 // compile-time and not runtime.3016 // compile-time and not runtime.
2782 if (typed_value.ty.hasCodeGenBits()) {3017 if (typed_value.ty.hasCodeGenBits()) {
2783 try self.comp.bin_file.allocateDeclIndexes(new_decl);3018 try mod.comp.bin_file.allocateDeclIndexes(new_decl);
2784 try self.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });3019 try mod.comp.work_queue.writeItem(.{ .codegen_decl = new_decl });
2785 }3020 }
27863021
2787 return new_decl;3022 return new_decl;
2788}3023}
27893024
2790pub fn createContainerDecl(3025pub fn createContainerDecl(
2791 self: *Module,3026 mod: *Module,
2792 scope: *Scope,3027 scope: *Scope,
2793 base_token: std.zig.ast.TokenIndex,3028 base_token: std.zig.ast.TokenIndex,
2794 decl_arena: *std.heap.ArenaAllocator,3029 decl_arena: *std.heap.ArenaAllocator,
2795 typed_value: TypedValue,3030 typed_value: TypedValue,
2796) !*Decl {3031) !*Decl {
2797 const scope_decl = scope.ownerDecl().?;3032 const scope_decl = scope.ownerDecl().?;
2798 const name = try self.getAnonTypeName(scope, base_token);3033 const name = try mod.getAnonTypeName(scope, base_token);
2799 defer self.gpa.free(name);3034 defer mod.gpa.free(name);
2800 const name_hash = scope.namespace().fullyQualifiedNameHash(name);3035 const name_hash = scope.namespace().fullyQualifiedNameHash(name);
2801 const src_hash: std.zig.SrcHash = undefined;3036 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);
2803 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);3038 const decl_arena_state = try decl_arena.allocator.create(std.heap.ArenaAllocator.State);
28043039
2805 decl_arena_state.* = decl_arena.state;3040 decl_arena_state.* = decl_arena.state;
...@@ -2810,12 +3045,12 @@ pub fn createContainerDecl(...@@ -2810,12 +3045,12 @@ pub fn createContainerDecl(
2810 },3045 },
2811 };3046 };
2812 new_decl.analysis = .complete;3047 new_decl.analysis = .complete;
2813 new_decl.generation = self.generation;3048 new_decl.generation = mod.generation;
28143049
2815 return new_decl;3050 return new_decl;
2816}3051}
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 {
2819 // TODO add namespaces, generic function signatrues3054 // TODO add namespaces, generic function signatrues
2820 const tree = scope.tree();3055 const tree = scope.tree();
2821 const token_tags = tree.tokens.items(.tag);3056 const token_tags = tree.tokens.items(.tag);
...@@ -2827,845 +3062,125 @@ fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIn...@@ -2827,845 +3062,125 @@ fn getAnonTypeName(self: *Module, scope: *Scope, base_token: std.zig.ast.TokenIn
2827 else => unreachable,3062 else => unreachable,
2828 };3063 };
2829 const loc = tree.tokenLocation(0, base_token);3064 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 });
2831}3066}
28323067
2833fn getNextAnonNameIndex(self: *Module) usize {3068fn getNextAnonNameIndex(mod: *Module) usize {
2834 return @atomicRmw(usize, &self.next_anon_name_index, .Add, 1, .Monotonic);3069 return @atomicRmw(usize, &mod.next_anon_name_index, .Add, 1, .Monotonic);
2835}3070}
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 {
2838 const namespace = scope.namespace();3073 const namespace = scope.namespace();
2839 const name_hash = namespace.fullyQualifiedNameHash(ident_name);3074 const name_hash = namespace.fullyQualifiedNameHash(ident_name);
2840 return self.decl_table.get(name_hash);3075 return mod.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);
2846}3076}
28473077
2848pub fn analyzeDeclRef(self: *Module, scope: *Scope, src: usize, decl: *Decl) InnerError!*Inst {3078fn makeIntType(mod: *Module, scope: *Scope, signed: bool, bits: u16) !Type {
2849 const scope_decl = scope.ownerDecl().?;3079 const int_payload = try scope.arena().create(Type.Payload.Bits);
2850 try self.declareDeclDependency(scope_decl, decl);3080 int_payload.* = .{
2851 self.ensureDeclAnalyzed(decl) catch |err| {3081 .base = .{
2852 if (scope.cast(Scope.Block)) |block| {3082 .tag = if (signed) .int_signed else .int_unsigned,
2853 if (block.func) |func| {3083 },
2854 func.state = .dependency_failure;3084 .data = bits,
2855 } else {
2856 block.owner_decl.analysis = .dependency_failure;
2857 }
2858 } else {
2859 scope_decl.analysis = .dependency_failure;
2860 }
2861 return err;
2862 };3085 };
28633086 return Type.initPayload(&int_payload.base);
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 });
2872}3087}
28733088
2874fn analyzeVarRef(self: *Module, scope: *Scope, src: usize, tv: TypedValue) InnerError!*Inst {3089/// We don't return a pointer to the new error note because the pointer
2875 const variable = tv.val.castTag(.variable).?.data;3090/// becomes invalid when you add another one.
28763091pub fn errNote(
2877 const ty = try self.simplePtrType(scope, src, tv.ty, variable.is_mutable, .One);3092 mod: *Module,
2878 if (!variable.is_mutable and !variable.is_extern) {3093 scope: *Scope,
2879 return self.constInst(scope, src, .{3094 src: LazySrcLoc,
2880 .ty = ty,3095 parent: *ErrorMsg,
2881 .val = try Value.Tag.ref_val.create(scope.arena(), variable.init),3096 comptime format: []const u8,
2882 });3097 args: anytype,
2883 }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);3102 parent.notes = try mod.gpa.realloc(parent.notes, parent.notes.len + 1);
2886 const inst = try b.arena.create(Inst.VarPtr);3103 parent.notes[parent.notes.len - 1] = .{
2887 inst.* = .{3104 .src_loc = .{
2888 .base = .{3105 .file_scope = scope.getFileScope(),
2889 .tag = .varptr,3106 .byte_offset = src,
2890 .ty = ty,
2891 .src = src,
2892 },3107 },
2893 .variable = variable,3108 .msg = msg,
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,
3613 };3109 };
3614}3110}
36153111
3616pub fn errMsg(3112pub fn errMsg(
3617 mod: *Module,3113 mod: *Module,
3618 scope: *Scope,3114 scope: *Scope,
3619 src_byte_offset: usize,3115 src: LazySrcLoc,
3620 comptime format: []const u8,3116 comptime format: []const u8,
3621 args: anytype,3117 args: anytype,
3622) error{OutOfMemory}!*ErrorMsg {3118) error{OutOfMemory}!*ErrorMsg {
3623 return ErrorMsg.create(mod.gpa, .{3119 return ErrorMsg.create(mod.gpa, .{
3624 .file_scope = scope.getFileScope(),3120 .decl = scope.srcDecl().?,
3625 .byte_offset = src_byte_offset,3121 .lazy = src,
3626 }, format, args);3122 }, format, args);
3627}3123}
36283124
3629pub fn fail(3125pub fn fail(
3630 mod: *Module,3126 mod: *Module,
3631 scope: *Scope,3127 scope: *Scope,
3632 src_byte_offset: usize,3128 src: LazySrcLoc,
3633 comptime format: []const u8,3129 comptime format: []const u8,
3634 args: anytype,3130 args: anytype,
3635) InnerError {3131) 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);
3637 return mod.failWithOwnedErrorMsg(scope, err_msg);3133 return mod.failWithOwnedErrorMsg(scope, err_msg);
3638}3134}
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`.
3640pub fn failTok(3152pub fn failTok(
3641 self: *Module,3153 mod: *Module,
3642 scope: *Scope,3154 scope: *Scope,
3643 token_index: ast.TokenIndex,3155 token_index: ast.TokenIndex,
3644 comptime format: []const u8,3156 comptime format: []const u8,
3645 args: anytype,3157 args: anytype,
3646) InnerError {3158) InnerError {
3647 const src = scope.tree().tokens.items(.start)[token_index];3159 const decl_token = scope.srcDecl().?.srcToken();
3648 return self.fail(scope, src, format, args);3160 const src: LazySrcLoc = .{ .token_offset = token_index - decl_token };
3161 return mod.fail(scope, src, format, args);
3649}3162}
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`.
3651pub fn failNode(3166pub fn failNode(
3652 self: *Module,3167 mod: *Module,
3653 scope: *Scope,3168 scope: *Scope,
3654 ast_node: ast.Node.Index,3169 node_index: ast.Node.Index,
3655 comptime format: []const u8,3170 comptime format: []const u8,
3656 args: anytype,3171 args: anytype,
3657) InnerError {3172) InnerError {
3658 const tree = scope.tree();3173 const decl_node = scope.srcDecl().?.srcNode();
3659 const src = tree.tokens.items(.start)[tree.firstToken(ast_node)];3174 const src: LazySrcLoc = .{ .node_offset = node_index - decl_node };
3660 return self.fail(scope, src, format, args);3175 return mod.fail(scope, src, format, args);
3661}3176}
36623177
3663pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {3178pub fn failWithOwnedErrorMsg(mod: *Module, scope: *Scope, err_msg: *ErrorMsg) InnerError {
3664 @setCold(true);3179 @setCold(true);
3665 {3180 {
3666 errdefer err_msg.destroy(self.gpa);3181 errdefer err_msg.destroy(mod.gpa);
3667 try self.failed_decls.ensureCapacity(self.gpa, self.failed_decls.items().len + 1);3182 try mod.failed_decls.ensureCapacity(mod.gpa, mod.failed_decls.items().len + 1);
3668 try self.failed_files.ensureCapacity(self.gpa, self.failed_files.items().len + 1);3183 try mod.failed_files.ensureCapacity(mod.gpa, mod.failed_files.items().len + 1);
3669 }3184 }
3670 switch (scope.tag) {3185 switch (scope.tag) {
3671 .block => {3186 .block => {
...@@ -3675,41 +3190,41 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I...@@ -3675,41 +3190,41 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
3675 func.state = .sema_failure;3190 func.state = .sema_failure;
3676 } else {3191 } else {
3677 block.owner_decl.analysis = .sema_failure;3192 block.owner_decl.analysis = .sema_failure;
3678 block.owner_decl.generation = self.generation;3193 block.owner_decl.generation = mod.generation;
3679 }3194 }
3680 } else {3195 } else {
3681 if (block.func) |func| {3196 if (block.func) |func| {
3682 func.state = .sema_failure;3197 func.state = .sema_failure;
3683 } else {3198 } else {
3684 block.owner_decl.analysis = .sema_failure;3199 block.owner_decl.analysis = .sema_failure;
3685 block.owner_decl.generation = self.generation;3200 block.owner_decl.generation = mod.generation;
3686 }3201 }
3687 }3202 }
3688 self.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);3203 mod.failed_decls.putAssumeCapacityNoClobber(block.owner_decl, err_msg);
3689 },3204 },
3690 .gen_zir, .gen_suspend => {3205 .gen_zir, .gen_suspend => {
3691 const gen_zir = scope.cast(Scope.GenZIR).?;3206 const gen_zir = scope.cast(Scope.GenZir).?;
3692 gen_zir.decl.analysis = .sema_failure;3207 gen_zir.decl.analysis = .sema_failure;
3693 gen_zir.decl.generation = self.generation;3208 gen_zir.decl.generation = mod.generation;
3694 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3209 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3695 },3210 },
3696 .local_val => {3211 .local_val => {
3697 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;3212 const gen_zir = scope.cast(Scope.LocalVal).?.gen_zir;
3698 gen_zir.decl.analysis = .sema_failure;3213 gen_zir.decl.analysis = .sema_failure;
3699 gen_zir.decl.generation = self.generation;3214 gen_zir.decl.generation = mod.generation;
3700 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3215 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3701 },3216 },
3702 .local_ptr => {3217 .local_ptr => {
3703 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;3218 const gen_zir = scope.cast(Scope.LocalPtr).?.gen_zir;
3704 gen_zir.decl.analysis = .sema_failure;3219 gen_zir.decl.analysis = .sema_failure;
3705 gen_zir.decl.generation = self.generation;3220 gen_zir.decl.generation = mod.generation;
3706 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3221 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3707 },3222 },
3708 .gen_nosuspend => {3223 .gen_nosuspend => {
3709 const gen_zir = scope.cast(Scope.Nosuspend).?.gen_zir;3224 const gen_zir = scope.cast(Scope.Nosuspend).?.gen_zir;
3710 gen_zir.decl.analysis = .sema_failure;3225 gen_zir.decl.analysis = .sema_failure;
3711 gen_zir.decl.generation = self.generation;3226 gen_zir.decl.generation = mod.generation;
3712 self.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);3227 mod.failed_decls.putAssumeCapacityNoClobber(gen_zir.decl, err_msg);
3713 },3228 },
3714 .file => unreachable,3229 .file => unreachable,
3715 .container => unreachable,3230 .container => unreachable,
...@@ -3717,20 +3232,6 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I...@@ -3717,20 +3232,6 @@ pub fn failWithOwnedErrorMsg(self: *Module, scope: *Scope, err_msg: *ErrorMsg) I
3717 return error.AnalysisFail;3232 return error.AnalysisFail;
3718}3233}
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
3734fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {3235fn srcHashEql(a: std.zig.SrcHash, b: std.zig.SrcHash) bool {
3735 return @bitCast(u128, a) == @bitCast(u128, b);3236 return @bitCast(u128, a) == @bitCast(u128, b);
3736}3237}
...@@ -3780,10 +3281,10 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {...@@ -3780,10 +3281,10 @@ pub fn intSub(allocator: *Allocator, lhs: Value, rhs: Value) !Value {
3780}3281}
37813282
3782pub fn floatAdd(3283pub fn floatAdd(
3783 self: *Module,3284 mod: *Module,
3784 scope: *Scope,3285 scope: *Scope,
3785 float_type: Type,3286 float_type: Type,
3786 src: usize,3287 src: LazySrcLoc,
3787 lhs: Value,3288 lhs: Value,
3788 rhs: Value,3289 rhs: Value,
3789) !Value {3290) !Value {
...@@ -3815,10 +3316,10 @@ pub fn floatAdd(...@@ -3815,10 +3316,10 @@ pub fn floatAdd(
3815}3316}
38163317
3817pub fn floatSub(3318pub fn floatSub(
3818 self: *Module,3319 mod: *Module,
3819 scope: *Scope,3320 scope: *Scope,
3820 float_type: Type,3321 float_type: Type,
3821 src: usize,3322 src: LazySrcLoc,
3822 lhs: Value,3323 lhs: Value,
3823 rhs: Value,3324 rhs: Value,
3824) !Value {3325) !Value {
...@@ -3850,9 +3351,8 @@ pub fn floatSub(...@@ -3850,9 +3351,8 @@ pub fn floatSub(
3850}3351}
38513352
3852pub fn simplePtrType(3353pub fn simplePtrType(
3853 self: *Module,3354 mod: *Module,
3854 scope: *Scope,3355 arena: *Allocator,
3855 src: usize,
3856 elem_ty: Type,3356 elem_ty: Type,
3857 mutable: bool,3357 mutable: bool,
3858 size: std.builtin.TypeInfo.Pointer.Size,3358 size: std.builtin.TypeInfo.Pointer.Size,
...@@ -3863,7 +3363,7 @@ pub fn simplePtrType(...@@ -3863,7 +3363,7 @@ pub fn simplePtrType(
3863 // TODO stage1 type inference bug3363 // TODO stage1 type inference bug
3864 const T = Type.Tag;3364 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);
3867 type_payload.* = .{3367 type_payload.* = .{
3868 .base = .{3368 .base = .{
3869 .tag = switch (size) {3369 .tag = switch (size) {
...@@ -3879,9 +3379,8 @@ pub fn simplePtrType(...@@ -3879,9 +3379,8 @@ pub fn simplePtrType(
3879}3379}
38803380
3881pub fn ptrType(3381pub fn ptrType(
3882 self: *Module,3382 mod: *Module,
3883 scope: *Scope,3383 arena: *Allocator,
3884 src: usize,
3885 elem_ty: Type,3384 elem_ty: Type,
3886 sentinel: ?Value,3385 sentinel: ?Value,
3887 @"align": u32,3386 @"align": u32,
...@@ -3895,7 +3394,7 @@ pub fn ptrType(...@@ -3895,7 +3394,7 @@ pub fn ptrType(
3895 assert(host_size == 0 or bit_offset < host_size * 8);3394 assert(host_size == 0 or bit_offset < host_size * 8);
38963395
3897 // TODO check if type can be represented by simplePtrType3396 // TODO check if type can be represented by simplePtrType
3898 return Type.Tag.pointer.create(scope.arena(), .{3397 return Type.Tag.pointer.create(arena, .{
3899 .pointee_type = elem_ty,3398 .pointee_type = elem_ty,
3900 .sentinel = sentinel,3399 .sentinel = sentinel,
3901 .@"align" = @"align",3400 .@"align" = @"align",
...@@ -3908,23 +3407,23 @@ pub fn ptrType(...@@ -3908,23 +3407,23 @@ pub fn ptrType(
3908 });3407 });
3909}3408}
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 {
3912 switch (child_type.tag()) {3411 switch (child_type.tag()) {
3913 .single_const_pointer => return Type.Tag.optional_single_const_pointer.create(3412 .single_const_pointer => return Type.Tag.optional_single_const_pointer.create(
3914 scope.arena(),3413 arena,
3915 child_type.elemType(),3414 child_type.elemType(),
3916 ),3415 ),
3917 .single_mut_pointer => return Type.Tag.optional_single_mut_pointer.create(3416 .single_mut_pointer => return Type.Tag.optional_single_mut_pointer.create(
3918 scope.arena(),3417 arena,
3919 child_type.elemType(),3418 child_type.elemType(),
3920 ),3419 ),
3921 else => return Type.Tag.optional.create(scope.arena(), child_type),3420 else => return Type.Tag.optional.create(arena, child_type),
3922 }3421 }
3923}3422}
39243423
3925pub fn arrayType(3424pub fn arrayType(
3926 self: *Module,3425 mod: *Module,
3927 scope: *Scope,3426 arena: *Allocator,
3928 len: u64,3427 len: u64,
3929 sentinel: ?Value,3428 sentinel: ?Value,
3930 elem_type: Type,3429 elem_type: Type,
...@@ -3932,30 +3431,30 @@ pub fn arrayType(...@@ -3932,30 +3431,30 @@ pub fn arrayType(
3932 if (elem_type.eql(Type.initTag(.u8))) {3431 if (elem_type.eql(Type.initTag(.u8))) {
3933 if (sentinel) |some| {3432 if (sentinel) |some| {
3934 if (some.eql(Value.initTag(.zero))) {3433 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);
3936 }3435 }
3937 } else {3436 } else {
3938 return Type.Tag.array_u8.create(scope.arena(), len);3437 return Type.Tag.array_u8.create(arena, len);
3939 }3438 }
3940 }3439 }
39413440
3942 if (sentinel) |some| {3441 if (sentinel) |some| {
3943 return Type.Tag.array_sentinel.create(scope.arena(), .{3442 return Type.Tag.array_sentinel.create(arena, .{
3944 .len = len,3443 .len = len,
3945 .sentinel = some,3444 .sentinel = some,
3946 .elem_type = elem_type,3445 .elem_type = elem_type,
3947 });3446 });
3948 }3447 }
39493448
3950 return Type.Tag.array.create(scope.arena(), .{3449 return Type.Tag.array.create(arena, .{
3951 .len = len,3450 .len = len,
3952 .elem_type = elem_type,3451 .elem_type = elem_type,
3953 });3452 });
3954}3453}
39553454
3956pub fn errorUnionType(3455pub fn errorUnionType(
3957 self: *Module,3456 mod: *Module,
3958 scope: *Scope,3457 arena: *Allocator,
3959 error_set: Type,3458 error_set: Type,
3960 payload: Type,3459 payload: Type,
3961) Allocator.Error!Type {3460) Allocator.Error!Type {
...@@ -3964,19 +3463,19 @@ pub fn errorUnionType(...@@ -3964,19 +3463,19 @@ pub fn errorUnionType(
3964 return Type.initTag(.anyerror_void_error_union);3463 return Type.initTag(.anyerror_void_error_union);
3965 }3464 }
39663465
3967 return Type.Tag.error_union.create(scope.arena(), .{3466 return Type.Tag.error_union.create(arena, .{
3968 .error_set = error_set,3467 .error_set = error_set,
3969 .payload = payload,3468 .payload = payload,
3970 });3469 });
3971}3470}
39723471
3973pub fn anyframeType(self: *Module, scope: *Scope, return_type: Type) Allocator.Error!Type {3472pub fn anyframeType(mod: *Module, arena: *Allocator, return_type: Type) Allocator.Error!Type {
3974 return Type.Tag.anyframe_T.create(scope.arena(), return_type);3473 return Type.Tag.anyframe_T.create(arena, return_type);
3975}3474}
39763475
3977pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {3476pub fn dumpInst(mod: *Module, scope: *Scope, inst: *ir.Inst) void {
3978 const zir_module = scope.namespace();3477 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");
3980 const loc = std.zig.findLineColumn(source, inst.src);3479 const loc = std.zig.findLineColumn(source, inst.src);
3981 if (inst.tag == .constant) {3480 if (inst.tag == .constant) {
3982 std.debug.print("constant ty={} val={} src={s}:{d}:{d}\n", .{3481 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 {...@@ -4006,267 +3505,113 @@ pub fn dumpInst(self: *Module, scope: *Scope, inst: *Inst) void {
4006 }3505 }
4007}3506}
40083507
4009pub const PanicId = enum {3508pub fn getTarget(mod: Module) Target {
4010 unreach,3509 return mod.comp.bin_file.options.target;
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;
4085}3510}
40863511
4087pub fn optimizeMode(self: Module) std.builtin.Mode {3512pub fn optimizeMode(mod: Module) std.builtin.Mode {
4088 return self.comp.bin_file.options.optimize_mode;3513 return mod.comp.bin_file.options.optimize_mode;
4089}3514}
40903515
4091pub fn validateVarType(mod: *Module, scope: *Scope, src: usize, ty: Type) !void {3516/// Given an identifier token, obtain the string for it.
4092 if (!ty.isValidVarType(false)) {3517/// If the token uses @"" syntax, parses as a string, reports errors if applicable,
4093 return mod.fail(scope, src, "variable of type '{}' must be const or comptime", .{ty});3518/// and allocates the result within `scope.arena()`.
4094 }3519/// Otherwise, returns a reference to the source code bytes directly.
4095}3520/// See also `appendIdentStr` and `parseStrLit`.
4096
4097/// Identifier token -> String (allocated in scope.arena())
4098pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {3521pub fn identifierTokenString(mod: *Module, scope: *Scope, token: ast.TokenIndex) InnerError![]const u8 {
4099 const tree = scope.tree();3522 const tree = scope.tree();
4100 const token_tags = tree.tokens.items(.tag);3523 const token_tags = tree.tokens.items(.tag);
4101 const token_starts = tree.tokens.items(.start);3524 const token_starts = tree.tokens.items(.start);
4102 assert(token_tags[token] == .identifier);3525 assert(token_tags[token] == .identifier);
4103
4104 const ident_name = tree.tokenSlice(token);3526 const ident_name = tree.tokenSlice(token);
4105 if (mem.startsWith(u8, ident_name, "@")) {3527 if (!mem.startsWith(u8, ident_name, "@")) {
4106 const raw_string = ident_name[1..];3528 return ident_name;
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 };
4116 }3529 }
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();
4118}3534}
41193535
4120pub fn emitBackwardBranch(mod: *Module, block: *Scope.Block, src: usize) !void {3536/// Given an identifier token, obtain the string for it (possibly parsing as a string
4121 const shared = block.inlining.?.shared;3537/// literal if it is @"" syntax), and append the string to `buf`.
4122 shared.branch_count += 1;3538/// See also `identifierTokenString` and `parseStrLit`.
4123 if (shared.branch_count > block.branch_quota.*) {3539pub fn appendIdentStr(
4124 // TODO show the "called from here" stack3540 mod: *Module,
4125 return mod.fail(&block.base, src, "evaluation exceeded {d} backwards branches", .{3541 scope: *Scope,
4126 block.branch_quota.*,3542 token: ast.TokenIndex,
4127 });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);
4128 }3554 }
4129}3555}
41303556
4131pub fn namedFieldPtr(3557/// Appends the result to `buf`.
3558pub fn parseStrLit(
4132 mod: *Module,3559 mod: *Module,
4133 scope: *Scope,3560 scope: *Scope,
4134 src: usize,3561 buf: *ArrayList(u8),
4135 object_ptr: *Inst,3562 bytes: []const u8,
4136 field_name: []const u8,3563 offset: usize,
4137 field_name_src: usize,3564) InnerError!void {
4138) InnerError!*Inst {3565 const raw_string = bytes[offset..];
4139 const elem_ty = switch (object_ptr.ty.zigTypeTag()) {3566 switch (try std.zig.string_literal.parseAppend(buf, raw_string)) {
4140 .Pointer => object_ptr.ty.elemType(),3567 .success => return,
4141 else => return mod.fail(scope, object_ptr.src, "expected pointer, found '{}'", .{object_ptr.ty}),3568 .invalid_character => |bad_index| {
4142 };3569 return mod.fail(
4143 switch (elem_ty.zigTypeTag()) {3570 scope,
4144 .Array => {3571 token_starts[token] + offset + bad_index,
4145 if (mem.eql(u8, field_name, "len")) {3572 "invalid string literal character: '{c}'",
4146 return mod.constInst(scope, src, .{3573 .{raw_string[bad_index]},
4147 .ty = Type.initTag(.single_const_pointer_to_comptime_int),3574 );
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 }
4161 },3575 },
4162 .Pointer => {3576 .expected_hex_digits => |bad_index| {
4163 const ptr_child = elem_ty.elemType();3577 return mod.fail(
4164 switch (ptr_child.zigTypeTag()) {3578 scope,
4165 .Array => {3579 token_starts[token] + offset + bad_index,
4166 if (mem.eql(u8, field_name, "len")) {3580 "expected hex digits after '\\x'",
4167 return mod.constInst(scope, src, .{3581 .{},
4168 .ty = Type.initTag(.single_const_pointer_to_comptime_int),3582 );
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 }
4185 },3583 },
4186 .Type => {3584 .invalid_hex_escape => |bad_index| {
4187 _ = try mod.resolveConstValue(scope, object_ptr);3585 return mod.fail(
4188 const result = try mod.analyzeDeref(scope, src, object_ptr, object_ptr.src);3586 scope,
4189 const val = result.value().?;3587 token_starts[token] + offset + bad_index,
4190 const child_type = try val.toType(scope.arena());3588 "invalid hex digit: '{c}'",
4191 switch (child_type.zigTypeTag()) {3589 .{raw_string[bad_index]},
4192 .ErrorSet => {3590 );
4193 var name: []const u8 = undefined;3591 },
4194 // TODO resolve inferred error sets3592 .invalid_unicode_escape => |bad_index| {
4195 if (val.castTag(.error_set)) |payload|3593 return mod.fail(
4196 name = (payload.data.fields.getEntry(field_name) orelse return mod.fail(scope, src, "no error named '{s}' in '{}'", .{ field_name, child_type })).key3594 scope,
4197 else3595 token_starts[token] + offset + bad_index,
4198 name = (try mod.getErrorValue(field_name)).key;3596 "invalid unicode digit: '{c}'",
41993597 .{raw_string[bad_index]},
4200 const result_type = if (child_type.tag() == .anyerror)3598 );
4201 try Type.Tag.error_set_single.create(scope.arena(), name)3599 },
4202 else3600 .missing_matching_brace => |bad_index| {
4203 child_type;3601 return mod.fail(
42043602 scope,
4205 return mod.constInst(scope, src, .{3603 token_starts[token] + offset + bad_index,
4206 .ty = try mod.simplePtrType(scope, src, result_type, false, .One),3604 "missing matching '}}' character",
4207 .val = try Value.Tag.ref_val.create(3605 .{},
4208 scope.arena(),3606 );
4209 try Value.Tag.@"error".create(scope.arena(), .{3607 },
4210 .name = name,3608 .expected_unicode_digits => |bad_index| {
4211 }),3609 return mod.fail(
4212 ),3610 scope,
4213 });3611 token_starts[token] + offset + bad_index,
4214 },3612 "expected unicode digits after '\\u'",
4215 .Struct => {3613 .{},
4216 const container_scope = child_type.getContainerScope();3614 );
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 }
4230 },3615 },
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 }
4269 }3616 }
4270
4271 return mod.fail(scope, src, "TODO implement more analyze elemptr", .{});
4272}3617}
src/astgen.zig+125-311
...@@ -25,21 +25,22 @@ pub const ResultLoc = union(enum) {...@@ -25,21 +25,22 @@ pub const ResultLoc = union(enum) {
25 /// of an assignment uses this kind of result location.25 /// of an assignment uses this kind of result location.
26 ref,26 ref,
27 /// The expression will be coerced into this type, but it will be evaluated as an rvalue.27 /// 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,
29 /// The expression must store its result into this typed pointer. The result instruction29 /// The expression must store its result into this typed pointer. The result instruction
30 /// from the expression must be ignored.30 /// from the expression must be ignored.
31 ptr: *zir.Inst,31 ptr: zir.Inst.Index,
32 /// The expression must store its result into this allocation, which has an inferred type.32 /// The expression must store its result into this allocation, which has an inferred type.
33 /// The result instruction from the expression must be ignored.33 /// 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,
35 /// The expression must store its result into this pointer, which is a typed pointer that36 /// The expression must store its result into this pointer, which is a typed pointer that
36 /// has been bitcasted to whatever the expression's type is.37 /// has been bitcasted to whatever the expression's type is.
37 /// The result instruction from the expression must be ignored.38 /// The result instruction from the expression must be ignored.
38 bitcasted_ptr: *zir.Inst.UnOp,39 bitcasted_ptr: zir.Inst.Index,
39 /// There is a pointer for the expression to store its result into, however, its type40 /// There is a pointer for the expression to store its result into, however, its type
40 /// is inferred based on peer type resolution for a `zir.Inst.Block`.41 /// is inferred based on peer type resolution for a `zir.Inst.Block`.
41 /// The result instruction from the expression must be ignored.42 /// The result instruction from the expression must be ignored.
42 block_ptr: *Module.Scope.GenZIR,43 block_ptr: *Module.Scope.GenZir,
4344
44 pub const Strategy = struct {45 pub const Strategy = struct {
45 elide_store_to_block_ptr_instructions: bool,46 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...@@ -369,10 +370,10 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
369370
370 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {371 .call_one, .call_one_comma, .async_call_one, .async_call_one_comma => {
371 var params: [1]ast.Node.Index = undefined;372 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));
373 },374 },
374 .call, .call_comma, .async_call, .async_call_comma => {375 .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));
376 },377 },
377378
378 .unreachable_literal => {379 .unreachable_literal => {
...@@ -487,9 +488,12 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In...@@ -487,9 +488,12 @@ pub fn expr(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.Index) In
487 },488 },
488 .enum_literal => {489 .enum_literal => {
489 const ident_token = main_tokens[node];490 const ident_token = main_tokens[node];
490 const name = try mod.identifierTokenString(scope, ident_token);491 const gen_zir = scope.getGenZir();
491 const src = token_starts[ident_token];492 const string_bytes = &gen_zir.zir_exec.string_bytes;
492 const result = try addZIRInst(mod, scope, src, zir.Inst.EnumLiteral, .{ .name = name }, .{});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);
493 return rvalue(mod, scope, rl, result);497 return rvalue(mod, scope, rl, result);
494 },498 },
495 .error_value => {499 .error_value => {
...@@ -679,7 +683,7 @@ pub fn comptimeExpr(...@@ -679,7 +683,7 @@ pub fn comptimeExpr(
679 const token_starts = tree.tokens.items(.start);683 const token_starts = tree.tokens.items(.start);
680684
681 // Make a scope to collect generated instructions in the sub-expression.685 // Make a scope to collect generated instructions in the sub-expression.
682 var block_scope: Scope.GenZIR = .{686 var block_scope: Scope.GenZir = .{
683 .parent = parent_scope,687 .parent = parent_scope,
684 .decl = parent_scope.ownerDecl().?,688 .decl = parent_scope.ownerDecl().?,
685 .arena = parent_scope.arena(),689 .arena = parent_scope.arena(),
...@@ -720,7 +724,7 @@ fn breakExpr(...@@ -720,7 +724,7 @@ fn breakExpr(
720 while (true) {724 while (true) {
721 switch (scope.tag) {725 switch (scope.tag) {
722 .gen_zir => {726 .gen_zir => {
723 const gen_zir = scope.cast(Scope.GenZIR).?;727 const gen_zir = scope.cast(Scope.GenZir).?;
724728
725 const block_inst = blk: {729 const block_inst = blk: {
726 if (break_label != 0) {730 if (break_label != 0) {
...@@ -755,7 +759,7 @@ fn breakExpr(...@@ -755,7 +759,7 @@ fn breakExpr(
755 try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?);759 try gen_zir.labeled_breaks.append(mod.gpa, br.castTag(.@"break").?);
756760
757 if (have_store_to_block) {761 if (have_store_to_block) {
758 const inst_list = parent_scope.getGenZIR().instructions.items;762 const inst_list = parent_scope.getGenZir().instructions.items;
759 const last_inst = inst_list[inst_list.len - 2];763 const last_inst = inst_list[inst_list.len - 2];
760 const store_inst = last_inst.castTag(.store_to_block_ptr).?;764 const store_inst = last_inst.castTag(.store_to_block_ptr).?;
761 assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?);765 assert(store_inst.positionals.lhs == gen_zir.rl_ptr.?);
...@@ -797,7 +801,7 @@ fn continueExpr(...@@ -797,7 +801,7 @@ fn continueExpr(
797 while (true) {801 while (true) {
798 switch (scope.tag) {802 switch (scope.tag) {
799 .gen_zir => {803 .gen_zir => {
800 const gen_zir = scope.cast(Scope.GenZIR).?;804 const gen_zir = scope.cast(Scope.GenZir).?;
801 const continue_block = gen_zir.continue_block orelse {805 const continue_block = gen_zir.continue_block orelse {
802 scope = gen_zir.parent;806 scope = gen_zir.parent;
803 continue;807 continue;
...@@ -864,7 +868,7 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn...@@ -864,7 +868,7 @@ fn checkLabelRedefinition(mod: *Module, parent_scope: *Scope, label: ast.TokenIn
864 while (true) {868 while (true) {
865 switch (scope.tag) {869 switch (scope.tag) {
866 .gen_zir => {870 .gen_zir => {
867 const gen_zir = scope.cast(Scope.GenZIR).?;871 const gen_zir = scope.cast(Scope.GenZir).?;
868 if (gen_zir.label) |prev_label| {872 if (gen_zir.label) |prev_label| {
869 if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) {873 if (try tokenIdentEql(mod, parent_scope, label, prev_label.token)) {
870 const tree = parent_scope.tree();874 const tree = parent_scope.tree();
...@@ -931,9 +935,9 @@ fn labeledBlockExpr(...@@ -931,9 +935,9 @@ fn labeledBlockExpr(
931935
932 try checkLabelRedefinition(mod, parent_scope, label_token);936 try checkLabelRedefinition(mod, parent_scope, label_token);
933937
934 // Create the Block ZIR instruction so that we can put it into the GenZIR struct938 // Create the Block ZIR instruction so that we can put it into the GenZir struct
935 // so that break statements can reference it.939 // so that break statements can reference it.
936 const gen_zir = parent_scope.getGenZIR();940 const gen_zir = parent_scope.getGenZir();
937 const block_inst = try gen_zir.arena.create(zir.Inst.Block);941 const block_inst = try gen_zir.arena.create(zir.Inst.Block);
938 block_inst.* = .{942 block_inst.* = .{
939 .base = .{943 .base = .{
...@@ -946,14 +950,14 @@ fn labeledBlockExpr(...@@ -946,14 +950,14 @@ fn labeledBlockExpr(
946 .kw_args = .{},950 .kw_args = .{},
947 };951 };
948952
949 var block_scope: Scope.GenZIR = .{953 var block_scope: Scope.GenZir = .{
950 .parent = parent_scope,954 .parent = parent_scope,
951 .decl = parent_scope.ownerDecl().?,955 .decl = parent_scope.ownerDecl().?,
952 .arena = gen_zir.arena,956 .arena = gen_zir.arena,
953 .force_comptime = parent_scope.isComptime(),957 .force_comptime = parent_scope.isComptime(),
954 .instructions = .{},958 .instructions = .{},
955 // TODO @as here is working around a stage1 miscompilation bug :(959 // 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{
957 .token = label_token,961 .token = label_token,
958 .block_inst = block_inst,962 .block_inst = block_inst,
959 }),963 }),
...@@ -1107,8 +1111,8 @@ fn varDecl(...@@ -1107,8 +1111,8 @@ fn varDecl(
1107 }1111 }
1108 s = local_ptr.parent;1112 s = local_ptr.parent;
1109 },1113 },
1110 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,1114 .gen_zir => s = s.cast(Scope.GenZir).?.parent,
1111 .gen_suspend => s = s.cast(Scope.GenZIR).?.parent,1115 .gen_suspend => s = s.cast(Scope.GenZir).?.parent,
1112 .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,1116 .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,
1113 else => break,1117 else => break,
1114 };1118 };
...@@ -1137,7 +1141,7 @@ fn varDecl(...@@ -1137,7 +1141,7 @@ fn varDecl(
1137 const sub_scope = try block_arena.create(Scope.LocalVal);1141 const sub_scope = try block_arena.create(Scope.LocalVal);
1138 sub_scope.* = .{1142 sub_scope.* = .{
1139 .parent = scope,1143 .parent = scope,
1140 .gen_zir = scope.getGenZIR(),1144 .gen_zir = scope.getGenZir(),
1141 .name = ident_name,1145 .name = ident_name,
1142 .inst = init_inst,1146 .inst = init_inst,
1143 };1147 };
...@@ -1146,7 +1150,7 @@ fn varDecl(...@@ -1146,7 +1150,7 @@ fn varDecl(
11461150
1147 // Detect whether the initialization expression actually uses the1151 // Detect whether the initialization expression actually uses the
1148 // result location pointer.1152 // result location pointer.
1149 var init_scope: Scope.GenZIR = .{1153 var init_scope: Scope.GenZir = .{
1150 .parent = scope,1154 .parent = scope,
1151 .decl = scope.ownerDecl().?,1155 .decl = scope.ownerDecl().?,
1152 .arena = scope.arena(),1156 .arena = scope.arena(),
...@@ -1168,7 +1172,7 @@ fn varDecl(...@@ -1168,7 +1172,7 @@ fn varDecl(
1168 }1172 }
1169 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };1173 const init_result_loc: ResultLoc = .{ .block_ptr = &init_scope };
1170 const init_inst = try expr(mod, &init_scope.base, init_result_loc, var_decl.ast.init_node);1174 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;
1172 if (init_scope.rvalue_rl_count == 1) {1176 if (init_scope.rvalue_rl_count == 1) {
1173 // Result location pointer not used. We don't need an alloc for this1177 // Result location pointer not used. We don't need an alloc for this
1174 // const local, and type inference becomes trivial.1178 // const local, and type inference becomes trivial.
...@@ -1192,7 +1196,7 @@ fn varDecl(...@@ -1192,7 +1196,7 @@ fn varDecl(
1192 const sub_scope = try block_arena.create(Scope.LocalVal);1196 const sub_scope = try block_arena.create(Scope.LocalVal);
1193 sub_scope.* = .{1197 sub_scope.* = .{
1194 .parent = scope,1198 .parent = scope,
1195 .gen_zir = scope.getGenZIR(),1199 .gen_zir = scope.getGenZir(),
1196 .name = ident_name,1200 .name = ident_name,
1197 .inst = casted_init,1201 .inst = casted_init,
1198 };1202 };
...@@ -1219,7 +1223,7 @@ fn varDecl(...@@ -1219,7 +1223,7 @@ fn varDecl(
1219 const sub_scope = try block_arena.create(Scope.LocalPtr);1223 const sub_scope = try block_arena.create(Scope.LocalPtr);
1220 sub_scope.* = .{1224 sub_scope.* = .{
1221 .parent = scope,1225 .parent = scope,
1222 .gen_zir = scope.getGenZIR(),1226 .gen_zir = scope.getGenZir(),
1223 .name = ident_name,1227 .name = ident_name,
1224 .ptr = init_scope.rl_ptr.?,1228 .ptr = init_scope.rl_ptr.?,
1225 };1229 };
...@@ -1246,7 +1250,7 @@ fn varDecl(...@@ -1246,7 +1250,7 @@ fn varDecl(
1246 const sub_scope = try block_arena.create(Scope.LocalPtr);1250 const sub_scope = try block_arena.create(Scope.LocalPtr);
1247 sub_scope.* = .{1251 sub_scope.* = .{
1248 .parent = scope,1252 .parent = scope,
1249 .gen_zir = scope.getGenZIR(),1253 .gen_zir = scope.getGenZir(),
1250 .name = ident_name,1254 .name = ident_name,
1251 .ptr = var_data.alloc,1255 .ptr = var_data.alloc,
1252 };1256 };
...@@ -1446,203 +1450,13 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node....@@ -1446,203 +1450,13 @@ fn arrayTypeSentinel(mod: *Module, scope: *Scope, rl: ResultLoc, node: ast.Node.
1446 return rvalue(mod, scope, rl, result);1450 return rvalue(mod, scope, rl, result);
1447}1451}
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
1490fn containerDecl(1453fn containerDecl(
1491 mod: *Module,1454 mod: *Module,
1492 scope: *Scope,1455 scope: *Scope,
1493 rl: ResultLoc,1456 rl: ResultLoc,
1494 container_decl: ast.full.ContainerDecl,1457 container_decl: ast.full.ContainerDecl,
1495) InnerError!*zir.Inst {1458) InnerError!*zir.Inst {
1496 const tree = scope.tree();1459 return mod.failTok(scope, container_decl.ast.main_token, "TODO implement container decls", .{});
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 }
1646}1460}
16471461
1648fn errorSetDecl(1462fn errorSetDecl(
...@@ -1709,7 +1523,7 @@ fn orelseCatchExpr(...@@ -1709,7 +1523,7 @@ fn orelseCatchExpr(
17091523
1710 const src = token_starts[op_token];1524 const src = token_starts[op_token];
17111525
1712 var block_scope: Scope.GenZIR = .{1526 var block_scope: Scope.GenZir = .{
1713 .parent = scope,1527 .parent = scope,
1714 .decl = scope.ownerDecl().?,1528 .decl = scope.ownerDecl().?,
1715 .arena = scope.arena(),1529 .arena = scope.arena(),
...@@ -1738,7 +1552,7 @@ fn orelseCatchExpr(...@@ -1738,7 +1552,7 @@ fn orelseCatchExpr(
1738 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),1552 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
1739 });1553 });
17401554
1741 var then_scope: Scope.GenZIR = .{1555 var then_scope: Scope.GenZir = .{
1742 .parent = &block_scope.base,1556 .parent = &block_scope.base,
1743 .decl = block_scope.decl,1557 .decl = block_scope.decl,
1744 .arena = block_scope.arena,1558 .arena = block_scope.arena,
...@@ -1766,7 +1580,7 @@ fn orelseCatchExpr(...@@ -1766,7 +1580,7 @@ fn orelseCatchExpr(
1766 block_scope.break_count += 1;1580 block_scope.break_count += 1;
1767 const then_result = try expr(mod, then_sub_scope, block_scope.break_result_loc, rhs);1581 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 = .{
1770 .parent = &block_scope.base,1584 .parent = &block_scope.base,
1771 .decl = block_scope.decl,1585 .decl = block_scope.decl,
1772 .arena = block_scope.arena,1586 .arena = block_scope.arena,
...@@ -1804,9 +1618,9 @@ fn finishThenElseBlock(...@@ -1804,9 +1618,9 @@ fn finishThenElseBlock(
1804 mod: *Module,1618 mod: *Module,
1805 parent_scope: *Scope,1619 parent_scope: *Scope,
1806 rl: ResultLoc,1620 rl: ResultLoc,
1807 block_scope: *Scope.GenZIR,1621 block_scope: *Scope.GenZir,
1808 then_scope: *Scope.GenZIR,1622 then_scope: *Scope.GenZir,
1809 else_scope: *Scope.GenZIR,1623 else_scope: *Scope.GenZir,
1810 then_body: *zir.Body,1624 then_body: *zir.Body,
1811 else_body: *zir.Body,1625 else_body: *zir.Body,
1812 then_src: usize,1626 then_src: usize,
...@@ -2023,7 +1837,7 @@ fn boolBinOp(...@@ -2023,7 +1837,7 @@ fn boolBinOp(
2023 .val = Value.initTag(.bool_type),1837 .val = Value.initTag(.bool_type),
2024 });1838 });
20251839
2026 var block_scope: Scope.GenZIR = .{1840 var block_scope: Scope.GenZir = .{
2027 .parent = scope,1841 .parent = scope,
2028 .decl = scope.ownerDecl().?,1842 .decl = scope.ownerDecl().?,
2029 .arena = scope.arena(),1843 .arena = scope.arena(),
...@@ -2043,7 +1857,7 @@ fn boolBinOp(...@@ -2043,7 +1857,7 @@ fn boolBinOp(
2043 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),1857 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
2044 });1858 });
20451859
2046 var rhs_scope: Scope.GenZIR = .{1860 var rhs_scope: Scope.GenZir = .{
2047 .parent = scope,1861 .parent = scope,
2048 .decl = block_scope.decl,1862 .decl = block_scope.decl,
2049 .arena = block_scope.arena,1863 .arena = block_scope.arena,
...@@ -2058,7 +1872,7 @@ fn boolBinOp(...@@ -2058,7 +1872,7 @@ fn boolBinOp(
2058 .operand = rhs,1872 .operand = rhs,
2059 }, .{});1873 }, .{});
20601874
2061 var const_scope: Scope.GenZIR = .{1875 var const_scope: Scope.GenZir = .{
2062 .parent = scope,1876 .parent = scope,
2063 .decl = block_scope.decl,1877 .decl = block_scope.decl,
2064 .arena = block_scope.arena,1878 .arena = block_scope.arena,
...@@ -2100,7 +1914,7 @@ fn ifExpr(...@@ -2100,7 +1914,7 @@ fn ifExpr(
2100 rl: ResultLoc,1914 rl: ResultLoc,
2101 if_full: ast.full.If,1915 if_full: ast.full.If,
2102) InnerError!*zir.Inst {1916) InnerError!*zir.Inst {
2103 var block_scope: Scope.GenZIR = .{1917 var block_scope: Scope.GenZir = .{
2104 .parent = scope,1918 .parent = scope,
2105 .decl = scope.ownerDecl().?,1919 .decl = scope.ownerDecl().?,
2106 .arena = scope.arena(),1920 .arena = scope.arena(),
...@@ -2142,7 +1956,7 @@ fn ifExpr(...@@ -2142,7 +1956,7 @@ fn ifExpr(
2142 });1956 });
21431957
2144 const then_src = token_starts[tree.lastToken(if_full.ast.then_expr)];1958 const then_src = token_starts[tree.lastToken(if_full.ast.then_expr)];
2145 var then_scope: Scope.GenZIR = .{1959 var then_scope: Scope.GenZir = .{
2146 .parent = scope,1960 .parent = scope,
2147 .decl = block_scope.decl,1961 .decl = block_scope.decl,
2148 .arena = block_scope.arena,1962 .arena = block_scope.arena,
...@@ -2160,7 +1974,7 @@ fn ifExpr(...@@ -2160,7 +1974,7 @@ fn ifExpr(
2160 // instructions into place until we know whether to keep store_to_block_ptr1974 // instructions into place until we know whether to keep store_to_block_ptr
2161 // instructions or not.1975 // instructions or not.
21621976
2163 var else_scope: Scope.GenZIR = .{1977 var else_scope: Scope.GenZir = .{
2164 .parent = scope,1978 .parent = scope,
2165 .decl = block_scope.decl,1979 .decl = block_scope.decl,
2166 .arena = block_scope.arena,1980 .arena = block_scope.arena,
...@@ -2201,7 +2015,7 @@ fn ifExpr(...@@ -2201,7 +2015,7 @@ fn ifExpr(
2201}2015}
22022016
2203/// Expects to find exactly 1 .store_to_block_ptr instruction.2017/// 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 {
2205 body.* = .{2019 body.* = .{
2206 .instructions = try scope.arena.alloc(*zir.Inst, scope.instructions.items.len - 1),2020 .instructions = try scope.arena.alloc(*zir.Inst, scope.instructions.items.len - 1),
2207 };2021 };
...@@ -2215,7 +2029,7 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZIR)...@@ -2215,7 +2029,7 @@ fn copyBodyWithElidedStoreBlockPtr(body: *zir.Body, scope: Module.Scope.GenZIR)
2215 assert(dst_index == body.instructions.len);2029 assert(dst_index == body.instructions.len);
2216}2030}
22172031
2218fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZIR) !void {2032fn copyBodyNoEliding(body: *zir.Body, scope: Module.Scope.GenZir) !void {
2219 body.* = .{2033 body.* = .{
2220 .instructions = try scope.arena.dupe(*zir.Inst, scope.instructions.items),2034 .instructions = try scope.arena.dupe(*zir.Inst, scope.instructions.items),
2221 };2035 };
...@@ -2234,7 +2048,7 @@ fn whileExpr(...@@ -2234,7 +2048,7 @@ fn whileExpr(
2234 return mod.failTok(scope, inline_token, "TODO inline while", .{});2048 return mod.failTok(scope, inline_token, "TODO inline while", .{});
2235 }2049 }
22362050
2237 var loop_scope: Scope.GenZIR = .{2051 var loop_scope: Scope.GenZir = .{
2238 .parent = scope,2052 .parent = scope,
2239 .decl = scope.ownerDecl().?,2053 .decl = scope.ownerDecl().?,
2240 .arena = scope.arena(),2054 .arena = scope.arena(),
...@@ -2244,7 +2058,7 @@ fn whileExpr(...@@ -2244,7 +2058,7 @@ fn whileExpr(
2244 setBlockResultLoc(&loop_scope, rl);2058 setBlockResultLoc(&loop_scope, rl);
2245 defer loop_scope.instructions.deinit(mod.gpa);2059 defer loop_scope.instructions.deinit(mod.gpa);
22462060
2247 var continue_scope: Scope.GenZIR = .{2061 var continue_scope: Scope.GenZir = .{
2248 .parent = &loop_scope.base,2062 .parent = &loop_scope.base,
2249 .decl = loop_scope.decl,2063 .decl = loop_scope.decl,
2250 .arena = loop_scope.arena,2064 .arena = loop_scope.arena,
...@@ -2311,14 +2125,14 @@ fn whileExpr(...@@ -2311,14 +2125,14 @@ fn whileExpr(
2311 loop_scope.break_block = while_block;2125 loop_scope.break_block = while_block;
2312 loop_scope.continue_block = cond_block;2126 loop_scope.continue_block = cond_block;
2313 if (while_full.label_token) |label_token| {2127 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{
2315 .token = label_token,2129 .token = label_token,
2316 .block_inst = while_block,2130 .block_inst = while_block,
2317 });2131 });
2318 }2132 }
23192133
2320 const then_src = token_starts[tree.lastToken(while_full.ast.then_expr)];2134 const then_src = token_starts[tree.lastToken(while_full.ast.then_expr)];
2321 var then_scope: Scope.GenZIR = .{2135 var then_scope: Scope.GenZir = .{
2322 .parent = &continue_scope.base,2136 .parent = &continue_scope.base,
2323 .decl = continue_scope.decl,2137 .decl = continue_scope.decl,
2324 .arena = continue_scope.arena,2138 .arena = continue_scope.arena,
...@@ -2332,7 +2146,7 @@ fn whileExpr(...@@ -2332,7 +2146,7 @@ fn whileExpr(
2332 loop_scope.break_count += 1;2146 loop_scope.break_count += 1;
2333 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, while_full.ast.then_expr);2147 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 = .{
2336 .parent = &continue_scope.base,2150 .parent = &continue_scope.base,
2337 .decl = continue_scope.decl,2151 .decl = continue_scope.decl,
2338 .arena = continue_scope.arena,2152 .arena = continue_scope.arena,
...@@ -2416,7 +2230,7 @@ fn forExpr(...@@ -2416,7 +2230,7 @@ fn forExpr(
2416 const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];2230 const cond_src = token_starts[tree.firstToken(for_full.ast.cond_expr)];
2417 const len = try addZIRUnOp(mod, scope, cond_src, .indexable_ptr_len, array_ptr);2231 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 = .{
2420 .parent = scope,2234 .parent = scope,
2421 .decl = scope.ownerDecl().?,2235 .decl = scope.ownerDecl().?,
2422 .arena = scope.arena(),2236 .arena = scope.arena(),
...@@ -2426,7 +2240,7 @@ fn forExpr(...@@ -2426,7 +2240,7 @@ fn forExpr(
2426 setBlockResultLoc(&loop_scope, rl);2240 setBlockResultLoc(&loop_scope, rl);
2427 defer loop_scope.instructions.deinit(mod.gpa);2241 defer loop_scope.instructions.deinit(mod.gpa);
24282242
2429 var cond_scope: Scope.GenZIR = .{2243 var cond_scope: Scope.GenZir = .{
2430 .parent = &loop_scope.base,2244 .parent = &loop_scope.base,
2431 .decl = loop_scope.decl,2245 .decl = loop_scope.decl,
2432 .arena = loop_scope.arena,2246 .arena = loop_scope.arena,
...@@ -2476,7 +2290,7 @@ fn forExpr(...@@ -2476,7 +2290,7 @@ fn forExpr(
2476 loop_scope.break_block = for_block;2290 loop_scope.break_block = for_block;
2477 loop_scope.continue_block = cond_block;2291 loop_scope.continue_block = cond_block;
2478 if (for_full.label_token) |label_token| {2292 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{
2480 .token = label_token,2294 .token = label_token,
2481 .block_inst = for_block,2295 .block_inst = for_block,
2482 });2296 });
...@@ -2484,7 +2298,7 @@ fn forExpr(...@@ -2484,7 +2298,7 @@ fn forExpr(
24842298
2485 // while body2299 // while body
2486 const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)];2300 const then_src = token_starts[tree.lastToken(for_full.ast.then_expr)];
2487 var then_scope: Scope.GenZIR = .{2301 var then_scope: Scope.GenZir = .{
2488 .parent = &cond_scope.base,2302 .parent = &cond_scope.base,
2489 .decl = cond_scope.decl,2303 .decl = cond_scope.decl,
2490 .arena = cond_scope.arena,2304 .arena = cond_scope.arena,
...@@ -2529,7 +2343,7 @@ fn forExpr(...@@ -2529,7 +2343,7 @@ fn forExpr(
2529 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);2343 const then_result = try expr(mod, then_sub_scope, loop_scope.break_result_loc, for_full.ast.then_expr);
25302344
2531 // else branch2345 // else branch
2532 var else_scope: Scope.GenZIR = .{2346 var else_scope: Scope.GenZir = .{
2533 .parent = &cond_scope.base,2347 .parent = &cond_scope.base,
2534 .decl = cond_scope.decl,2348 .decl = cond_scope.decl,
2535 .arena = cond_scope.arena,2349 .arena = cond_scope.arena,
...@@ -2609,7 +2423,7 @@ fn switchExpr(...@@ -2609,7 +2423,7 @@ fn switchExpr(
26092423
2610 const switch_src = token_starts[switch_token];2424 const switch_src = token_starts[switch_token];
26112425
2612 var block_scope: Scope.GenZIR = .{2426 var block_scope: Scope.GenZir = .{
2613 .parent = scope,2427 .parent = scope,
2614 .decl = scope.ownerDecl().?,2428 .decl = scope.ownerDecl().?,
2615 .arena = scope.arena(),2429 .arena = scope.arena(),
...@@ -2748,7 +2562,7 @@ fn switchExpr(...@@ -2748,7 +2562,7 @@ fn switchExpr(
2748 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),2562 .instructions = try block_scope.arena.dupe(*zir.Inst, block_scope.instructions.items),
2749 });2563 });
27502564
2751 var case_scope: Scope.GenZIR = .{2565 var case_scope: Scope.GenZir = .{
2752 .parent = scope,2566 .parent = scope,
2753 .decl = block_scope.decl,2567 .decl = block_scope.decl,
2754 .arena = block_scope.arena,2568 .arena = block_scope.arena,
...@@ -2757,7 +2571,7 @@ fn switchExpr(...@@ -2757,7 +2571,7 @@ fn switchExpr(
2757 };2571 };
2758 defer case_scope.instructions.deinit(mod.gpa);2572 defer case_scope.instructions.deinit(mod.gpa);
27592573
2760 var else_scope: Scope.GenZIR = .{2574 var else_scope: Scope.GenZir = .{
2761 .parent = scope,2575 .parent = scope,
2762 .decl = case_scope.decl,2576 .decl = case_scope.decl,
2763 .arena = case_scope.arena,2577 .arena = case_scope.arena,
...@@ -2966,12 +2780,8 @@ fn identifier(...@@ -2966,12 +2780,8 @@ fn identifier(
2966 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});2780 return mod.failNode(scope, ident, "TODO implement '_' identifier", .{});
2967 }2781 }
29682782
2969 if (simple_types.get(ident_name)) |val_tag| {2783 if (simple_types.get(ident_name)) |zir_const_tag| {
2970 const result = try addZIRInstConst(mod, scope, src, TypedValue{2784 return rvalue(mod, scope, rl, @enumToInt(zir_const_tag));
2971 .ty = Type.initTag(.type),
2972 .val = Value.initTag(val_tag),
2973 });
2974 return rvalue(mod, scope, rl, result);
2975 }2785 }
29762786
2977 if (ident_name.len >= 2) integer: {2787 if (ident_name.len >= 2) integer: {
...@@ -3030,8 +2840,8 @@ fn identifier(...@@ -3030,8 +2840,8 @@ fn identifier(
3030 }2840 }
3031 s = local_ptr.parent;2841 s = local_ptr.parent;
3032 },2842 },
3033 .gen_zir => s = s.cast(Scope.GenZIR).?.parent,2843 .gen_zir => s = s.cast(Scope.GenZir).?.parent,
3034 .gen_suspend => s = s.cast(Scope.GenZIR).?.parent,2844 .gen_suspend => s = s.cast(Scope.GenZir).?.parent,
3035 .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,2845 .gen_nosuspend => s = s.cast(Scope.Nosuspend).?.parent,
3036 else => break,2846 else => break,
3037 };2847 };
...@@ -3166,33 +2976,16 @@ fn integerLiteral(...@@ -3166,33 +2976,16 @@ fn integerLiteral(
3166 rl: ResultLoc,2976 rl: ResultLoc,
3167 int_lit: ast.Node.Index,2977 int_lit: ast.Node.Index,
3168) InnerError!*zir.Inst {2978) InnerError!*zir.Inst {
3169 const arena = scope.arena();
3170 const tree = scope.tree();2979 const tree = scope.tree();
3171 const main_tokens = tree.nodes.items(.main_token);2980 const main_tokens = tree.nodes.items(.main_token);
3172 const token_starts = tree.tokens.items(.start);
3173
3174 const int_token = main_tokens[int_lit];2981 const int_token = main_tokens[int_lit];
3175 const prefixed_bytes = tree.tokenSlice(int_token);2982 const prefixed_bytes = tree.tokenSlice(int_token);
3176 const base: u8 = if (mem.startsWith(u8, prefixed_bytes, "0x"))2983 if (std.fmt.parseInt(u64, prefixed_bytes, 0)) |small_int| {
3177 162984 const result: zir.Inst.Index = switch (small_int) {
3178 else if (mem.startsWith(u8, prefixed_bytes, "0o"))2985 0 => @enumToInt(zir.Const.zero),
3179 82986 1 => @enumToInt(zir.Const.one),
3180 else if (mem.startsWith(u8, prefixed_bytes, "0b"))2987 else => try addZirInt(small_int),
3181 22988 };
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 });
3196 return rvalue(mod, scope, rl, result);2989 return rvalue(mod, scope, rl, result);
3197 } else |err| {2990 } else |err| {
3198 return mod.failTok(scope, int_token, "TODO implement int literals that don't fit in a u64", .{});2991 return mod.failTok(scope, int_token, "TODO implement int literals that don't fit in a u64", .{});
...@@ -3316,7 +3109,7 @@ fn asRlPtr(...@@ -3316,7 +3109,7 @@ fn asRlPtr(
3316 // Detect whether this expr() call goes into rvalue() to store the result into the3109 // Detect whether this expr() call goes into rvalue() to store the result into the
3317 // result location. If it does, elide the coerce_result_ptr instruction3110 // result location. If it does, elide the coerce_result_ptr instruction
3318 // as well as the store instruction, instead passing the result as an rvalue.3111 // 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 = .{
3320 .parent = scope,3113 .parent = scope,
3321 .decl = scope.ownerDecl().?,3114 .decl = scope.ownerDecl().?,
3322 .arena = scope.arena(),3115 .arena = scope.arena(),
...@@ -3327,7 +3120,7 @@ fn asRlPtr(...@@ -3327,7 +3120,7 @@ fn asRlPtr(
33273120
3328 as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr);3121 as_scope.rl_ptr = try addZIRBinOp(mod, &as_scope.base, src, .coerce_result_ptr, dest_type, result_ptr);
3329 const result = try expr(mod, &as_scope.base, .{ .block_ptr = &as_scope }, operand_node);3122 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;
3331 if (as_scope.rvalue_rl_count == 1) {3124 if (as_scope.rvalue_rl_count == 1) {
3332 // Busted! This expression didn't actually need a pointer.3125 // Busted! This expression didn't actually need a pointer.
3333 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;3126 const expected_len = parent_zir.items.len + as_scope.instructions.items.len - 2;
...@@ -3622,39 +3415,47 @@ fn callExpr(...@@ -3622,39 +3415,47 @@ fn callExpr(
3622 mod: *Module,3415 mod: *Module,
3623 scope: *Scope,3416 scope: *Scope,
3624 rl: ResultLoc,3417 rl: ResultLoc,
3418 node: ast.Node.Index,
3625 call: ast.full.Call,3419 call: ast.full.Call,
3626) InnerError!*zir.Inst {3420) InnerError!*zir.Inst {
3627 if (call.async_token) |async_token| {3421 if (call.async_token) |async_token| {
3628 return mod.failTok(scope, async_token, "TODO implement async fn call", .{});3422 return mod.failTok(scope, async_token, "TODO implement async fn call", .{});
3629 }3423 }
3630
3631 const tree = scope.tree();
3632 const main_tokens = tree.nodes.items(.main_token);
3633 const token_starts = tree.tokens.items(.start);
3634
3635 const lhs = try expr(mod, scope, .none, call.ast.fn_expr);3424 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();
3638 for (call.ast.params) |param_node, i| {3430 for (call.ast.params) |param_node, i| {
3639 const param_src = token_starts[tree.firstToken(param_node)];3431 const param_type = try gen_zir.addParamType(.{
3640 const param_type = try addZIRInst(mod, scope, param_src, zir.Inst.ParamType, .{3432 .callee = lhs,
3641 .func = lhs,3433 .param_index = i,
3642 .arg_index = i,3434 });
3643 }, .{});
3644 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);3435 args[i] = try expr(mod, scope, .{ .ty = param_type }, param_node);
3645 }3436 }
36463437
3647 const src = token_starts[call.ast.lparen];3438 const modifier: std.builtin.CallOptions.Modifier = switch (call.async_token != null) {
3648 var modifier: std.builtin.CallOptions.Modifier = .auto;3439 true => .async_kw,
3649 if (call.async_token) |_| modifier = .async_kw;3440 false => .auto,
36503441 };
3651 const result = try addZIRInst(mod, scope, src, zir.Inst.Call, .{3442 const result: zir.Inst.Index = res: {
3652 .func = lhs,3443 const tag: zir.Inst.Tag = switch (modifier) {
3653 .args = args,3444 .auto => switch (args.len == 0) {
3654 .modifier = modifier,3445 true => break :res try gen_zir.addCallNone(lhs, node),
3655 }, .{});3446 false => .call,
3656 // TODO function call with result location3447 },
3657 return rvalue(mod, scope, rl, result);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
3658}3459}
36593460
3660fn suspendExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir.Inst {3461fn 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...@@ -3748,11 +3549,17 @@ fn resumeExpr(mod: *Module, scope: *Scope, node: ast.Node.Index) InnerError!*zir
3748 return addZIRUnOp(mod, scope, src, .@"resume", operand);3549 return addZIRUnOp(mod, scope, src, .@"resume", operand);
3749}3550}
37503551
3751pub const simple_types = std.ComptimeStringMap(Value.Tag, .{3552pub const simple_types = std.ComptimeStringMap(zir.Const, .{
3752 .{ "u8", .u8_type },3553 .{ "u8", .u8_type },
3753 .{ "i8", .i8_type },3554 .{ "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 },
3755 .{ "usize", .usize_type },3561 .{ "usize", .usize_type },
3562 .{ "isize", .isize_type },
3756 .{ "c_short", .c_short_type },3563 .{ "c_short", .c_short_type },
3757 .{ "c_ushort", .c_ushort_type },3564 .{ "c_ushort", .c_ushort_type },
3758 .{ "c_int", .c_int_type },3565 .{ "c_int", .c_int_type },
...@@ -3774,6 +3581,13 @@ pub const simple_types = std.ComptimeStringMap(Value.Tag, .{...@@ -3774,6 +3581,13 @@ pub const simple_types = std.ComptimeStringMap(Value.Tag, .{
3774 .{ "comptime_int", .comptime_int_type },3581 .{ "comptime_int", .comptime_int_type },
3775 .{ "comptime_float", .comptime_float_type },3582 .{ "comptime_float", .comptime_float_type },
3776 .{ "noreturn", .noreturn_type },3583 .{ "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 },
3777});3591});
37783592
3779fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {3593fn nodeMayNeedMemoryLocation(scope: *Scope, start_node: ast.Node.Index) bool {
...@@ -4045,7 +3859,7 @@ fn rvalueVoid(...@@ -4045,7 +3859,7 @@ fn rvalueVoid(
4045 return rvalue(mod, scope, rl, void_inst);3859 return rvalue(mod, scope, rl, void_inst);
4046}3860}
40473861
4048fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZIR) ResultLoc.Strategy {3862fn rlStrategy(rl: ResultLoc, block_scope: *Scope.GenZir) ResultLoc.Strategy {
4049 var elide_store_to_block_ptr_instructions = false;3863 var elide_store_to_block_ptr_instructions = false;
4050 switch (rl) {3864 switch (rl) {
4051 // In this branch there will not be any store_to_block_ptr instructions.3865 // 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...@@ -4099,7 +3913,7 @@ fn makeOptionalTypeResultLoc(mod: *Module, scope: *Scope, src: usize, rl: Result
4099 }3913 }
4100}3914}
41013915
4102fn setBlockResultLoc(block_scope: *Scope.GenZIR, parent_rl: ResultLoc) void {3916fn setBlockResultLoc(block_scope: *Scope.GenZir, parent_rl: ResultLoc) void {
4103 // Depending on whether the result location is a pointer or value, different3917 // Depending on whether the result location is a pointer or value, different
4104 // ZIR needs to be generated. In the former case we rely on storing to the3918 // ZIR needs to be generated. In the former case we rely on storing to the
4105 // pointer to communicate the result, and use breakvoid; in the latter case3919 // pointer to communicate the result, and use breakvoid; in the latter case
...@@ -4137,7 +3951,7 @@ pub fn addZirInstTag(...@@ -4137,7 +3951,7 @@ pub fn addZirInstTag(
4137 comptime tag: zir.Inst.Tag,3951 comptime tag: zir.Inst.Tag,
4138 positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,3952 positionals: std.meta.fieldInfo(tag.Type(), .positionals).field_type,
4139) !*zir.Inst {3953) !*zir.Inst {
4140 const gen_zir = scope.getGenZIR();3954 const gen_zir = scope.getGenZir();
4141 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);3955 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4142 const inst = try gen_zir.arena.create(tag.Type());3956 const inst = try gen_zir.arena.create(tag.Type());
4143 inst.* = .{3957 inst.* = .{
...@@ -4160,7 +3974,7 @@ pub fn addZirInstT(...@@ -4160,7 +3974,7 @@ pub fn addZirInstT(
4160 tag: zir.Inst.Tag,3974 tag: zir.Inst.Tag,
4161 positionals: std.meta.fieldInfo(T, .positionals).field_type,3975 positionals: std.meta.fieldInfo(T, .positionals).field_type,
4162) !*T {3976) !*T {
4163 const gen_zir = scope.getGenZIR();3977 const gen_zir = scope.getGenZir();
4164 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);3978 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4165 const inst = try gen_zir.arena.create(T);3979 const inst = try gen_zir.arena.create(T);
4166 inst.* = .{3980 inst.* = .{
...@@ -4183,7 +3997,7 @@ pub fn addZIRInstSpecial(...@@ -4183,7 +3997,7 @@ pub fn addZIRInstSpecial(
4183 positionals: std.meta.fieldInfo(T, .positionals).field_type,3997 positionals: std.meta.fieldInfo(T, .positionals).field_type,
4184 kw_args: std.meta.fieldInfo(T, .kw_args).field_type,3998 kw_args: std.meta.fieldInfo(T, .kw_args).field_type,
4185) !*T {3999) !*T {
4186 const gen_zir = scope.getGenZIR();4000 const gen_zir = scope.getGenZir();
4187 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);4001 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4188 const inst = try gen_zir.arena.create(T);4002 const inst = try gen_zir.arena.create(T);
4189 inst.* = .{4003 inst.* = .{
...@@ -4199,7 +4013,7 @@ pub fn addZIRInstSpecial(...@@ -4199,7 +4013,7 @@ pub fn addZIRInstSpecial(
4199}4013}
42004014
4201pub fn addZIRNoOpT(mod: *Module, scope: *Scope, src: usize, tag: zir.Inst.Tag) !*zir.Inst.NoOp {4015pub 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();
4203 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);4017 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4204 const inst = try gen_zir.arena.create(zir.Inst.NoOp);4018 const inst = try gen_zir.arena.create(zir.Inst.NoOp);
4205 inst.* = .{4019 inst.* = .{
...@@ -4226,7 +4040,7 @@ pub fn addZIRUnOp(...@@ -4226,7 +4040,7 @@ pub fn addZIRUnOp(
4226 tag: zir.Inst.Tag,4040 tag: zir.Inst.Tag,
4227 operand: *zir.Inst,4041 operand: *zir.Inst,
4228) !*zir.Inst {4042) !*zir.Inst {
4229 const gen_zir = scope.getGenZIR();4043 const gen_zir = scope.getGenZir();
4230 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);4044 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4231 const inst = try gen_zir.arena.create(zir.Inst.UnOp);4045 const inst = try gen_zir.arena.create(zir.Inst.UnOp);
4232 inst.* = .{4046 inst.* = .{
...@@ -4251,7 +4065,7 @@ pub fn addZIRBinOp(...@@ -4251,7 +4065,7 @@ pub fn addZIRBinOp(
4251 lhs: *zir.Inst,4065 lhs: *zir.Inst,
4252 rhs: *zir.Inst,4066 rhs: *zir.Inst,
4253) !*zir.Inst {4067) !*zir.Inst {
4254 const gen_zir = scope.getGenZIR();4068 const gen_zir = scope.getGenZir();
4255 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);4069 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4256 const inst = try gen_zir.arena.create(zir.Inst.BinOp);4070 const inst = try gen_zir.arena.create(zir.Inst.BinOp);
4257 inst.* = .{4071 inst.* = .{
...@@ -4276,7 +4090,7 @@ pub fn addZIRInstBlock(...@@ -4276,7 +4090,7 @@ pub fn addZIRInstBlock(
4276 tag: zir.Inst.Tag,4090 tag: zir.Inst.Tag,
4277 body: zir.Body,4091 body: zir.Body,
4278) !*zir.Inst.Block {4092) !*zir.Inst.Block {
4279 const gen_zir = scope.getGenZIR();4093 const gen_zir = scope.getGenZir();
4280 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);4094 try gen_zir.instructions.ensureCapacity(mod.gpa, gen_zir.instructions.items.len + 1);
4281 const inst = try gen_zir.arena.create(zir.Inst.Block);4095 const inst = try gen_zir.arena.create(zir.Inst.Block);
4282 inst.* = .{4096 inst.* = .{
src/ir.zig+444-1
...@@ -360,7 +360,8 @@ pub const Inst = struct {...@@ -360,7 +360,8 @@ pub const Inst = struct {
360 base: Inst,360 base: Inst,
361 asm_source: []const u8,361 asm_source: []const u8,
362 is_volatile: bool,362 is_volatile: bool,
363 output: ?[]const u8,363 output: ?*Inst,
364 output_name: ?[]const u8,
364 inputs: []const []const u8,365 inputs: []const []const u8,
365 clobbers: []const []const u8,366 clobbers: []const []const u8,
366 args: []const *Inst,367 args: []const *Inst,
...@@ -589,3 +590,445 @@ pub const Inst = struct {...@@ -589,3 +590,445 @@ pub const Inst = struct {
589pub const Body = struct {590pub const Body = struct {
590 instructions: []*Inst,591 instructions: []*Inst,
591};592};
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 {...@@ -863,7 +863,10 @@ pub const Type = extern union {
863 }863 }
864864
865 pub fn isNoReturn(self: Type) bool {865 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;
867 }870 }
868871
869 /// Asserts that hasCodeGenBits() is true.872 /// Asserts that hasCodeGenBits() is true.
...@@ -3464,18 +3467,20 @@ pub const Type = extern union {...@@ -3464,18 +3467,20 @@ pub const Type = extern union {
3464 .int_unsigned,3467 .int_unsigned,
3465 => Payload.Bits,3468 => Payload.Bits,
34663469
3470 .error_set,
3471 .@"enum",
3472 .@"struct",
3473 .@"union",
3474 => Payload.Decl,
3475
3467 .array => Payload.Array,3476 .array => Payload.Array,
3468 .array_sentinel => Payload.ArraySentinel,3477 .array_sentinel => Payload.ArraySentinel,
3469 .pointer => Payload.Pointer,3478 .pointer => Payload.Pointer,
3470 .function => Payload.Function,3479 .function => Payload.Function,
3471 .error_union => Payload.ErrorUnion,3480 .error_union => Payload.ErrorUnion,
3472 .error_set => Payload.Decl,
3473 .error_set_single => Payload.Name,3481 .error_set_single => Payload.Name,
3474 .empty_struct => Payload.ContainerScope,
3475 .@"enum" => Payload.Enum,
3476 .@"struct" => Payload.Struct,
3477 .@"union" => Payload.Union,
3478 .@"opaque" => Payload.Opaque,3482 .@"opaque" => Payload.Opaque,
3483 .empty_struct => Payload.ContainerScope,
3479 };3484 };
3480 }3485 }
34813486
...@@ -3598,13 +3603,8 @@ pub const Type = extern union {...@@ -3598,13 +3603,8 @@ pub const Type = extern union {
35983603
3599 pub const Opaque = struct {3604 pub const Opaque = struct {
3600 base: Payload = .{ .tag = .@"opaque" },3605 base: Payload = .{ .tag = .@"opaque" },
36013606 data: Module.Scope.Container,
3602 scope: Module.Scope.Container,
3603 };3607 };
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");
3608 };3608 };
3609};3609};
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 {...@@ -69,11 +69,12 @@ pub const Value = extern union {
69 one,69 one,
70 void_value,70 void_value,
71 unreachable_value,71 unreachable_value,
72 empty_struct_value,
73 empty_array,
74 null_value,72 null_value,
75 bool_true,73 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.
77 // After this, the tag requires a payload.78 // After this, the tag requires a payload.
7879
79 ty,80 ty,
...@@ -107,7 +108,7 @@ pub const Value = extern union {...@@ -107,7 +108,7 @@ pub const Value = extern union {
107 /// to an inferred allocation. It does not support any of the normal value queries.108 /// to an inferred allocation. It does not support any of the normal value queries.
108 inferred_alloc,109 inferred_alloc,
109110
110 pub const last_no_payload_tag = Tag.bool_false;111 pub const last_no_payload_tag = Tag.empty_array;
111 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;112 pub const no_payload_count = @enumToInt(last_no_payload_tag) + 1;
112113
113 pub fn Type(comptime t: Tag) type {114 pub fn Type(comptime t: Tag) type {
src/zir.zig+713-1553
...@@ -10,17 +10,338 @@ const Type = @import("type.zig").Type;...@@ -10,17 +10,338 @@ const Type = @import("type.zig").Type;
10const Value = @import("value.zig").Value;10const Value = @import("value.zig").Value;
11const TypedValue = @import("TypedValue.zig");11const TypedValue = @import("TypedValue.zig");
12const ir = @import("ir.zig");12const 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` for67/// These correspond to the first N tags of Value.
16/// in-memory, analyzed instructions with types and values.68/// A ZIR instruction refers to another one by index. However the first N indexes
17/// We use a table to map these instruction to their respective semantically analyzed69/// correspond to this enum, and the next M indexes correspond to the parameters
18/// instructions because it is possible to have multiple analyses on the same ZIR70/// of the current function. After that, they refer to other instructions in the
19/// happening at the same time.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.
20pub const Inst = struct {342pub const Inst = struct {
21 tag: Tag,343 tag: Tag,
22 /// Byte offset into the source.344 data: Data,
23 src: usize,
24345
25 /// These names are used directly as the instruction names in the text format.346 /// These names are used directly as the instruction names in the text format.
26 pub const Tag = enum {347 pub const Tag = enum {
...@@ -28,40 +349,45 @@ pub const Inst = struct {...@@ -28,40 +349,45 @@ pub const Inst = struct {
28 add,349 add,
29 /// Twos complement wrapping integer addition.350 /// Twos complement wrapping integer addition.
30 addwrap,351 addwrap,
31 /// Allocates stack local memory. Its lifetime ends when the block ends that contains352 /// Allocates stack local memory.
32 /// this instruction. The operand is the type of the allocated object.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.
33 alloc,356 alloc,
34 /// Same as `alloc` except mutable.357 /// Same as `alloc` except mutable.
35 alloc_mut,358 alloc_mut,
36 /// Same as `alloc` except the type is inferred.359 /// Same as `alloc` except the type is inferred.
360 /// lhs and rhs unused.
37 alloc_inferred,361 alloc_inferred,
38 /// Same as `alloc_inferred` except mutable.362 /// Same as `alloc_inferred` except mutable.
363 /// lhs and rhs unused.
39 alloc_inferred_mut,364 alloc_inferred_mut,
40 /// Create an `anyframe->T`.365 /// Create an `anyframe->T`.
366 /// Uses the `un_node` field. AST node is the `anyframe->T` syntax. Operand is the type.
41 anyframe_type,367 anyframe_type,
42 /// Array concatenation. `a ++ b`368 /// Array concatenation. `a ++ b`
43 array_cat,369 array_cat,
44 /// Array multiplication `a ** b`370 /// Array multiplication `a ** b`
45 array_mul,371 array_mul,
46 /// Create an array type372 /// lhs is length, rhs is element type.
47 array_type,373 array_type,
48 /// Create an array type with sentinel374 /// lhs is length, ArrayTypeSentinel[rhs]
49 array_type_sentinel,375 array_type_sentinel,
50 /// Given a pointer to an indexable object, returns the len property. This is376 /// 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 instruction377 /// used by for loops. This instruction also emits a for-loop specific compile
52 /// if the indexable object is not indexable.378 /// error if the indexable object is not indexable.
379 /// Uses the `un_node` field. The AST node is the for loop node.
53 indexable_ptr_len,380 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,
60 /// Type coercion.381 /// Type coercion.
382 /// Uses the `bin` field.
61 as,383 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.
63 @"asm",386 @"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.
65 @"await",391 @"await",
66 /// Bitwise AND. `&`392 /// Bitwise AND. `&`
67 bit_and,393 bit_and,
...@@ -80,6 +406,7 @@ pub const Inst = struct {...@@ -80,6 +406,7 @@ pub const Inst = struct {
80 /// Bitwise OR. `|`406 /// Bitwise OR. `|`
81 bit_or,407 bit_or,
82 /// A labeled block of code, which can return a value.408 /// A labeled block of code, which can return a value.
409 /// Uses the `pl_node` union field.
83 block,410 block,
84 /// A block of code, which can return a value. There are no instructions that break out of411 /// A block of code, which can return a value. There are no instructions that break out of
85 /// this block; it is implied that the final instruction is the result.412 /// this block; it is implied that the final instruction is the result.
...@@ -89,18 +416,36 @@ pub const Inst = struct {...@@ -89,18 +416,36 @@ pub const Inst = struct {
89 /// Same as `block_flat` but additionally makes the inner instructions execute at comptime.416 /// Same as `block_flat` but additionally makes the inner instructions execute at comptime.
90 block_comptime_flat,417 block_comptime_flat,
91 /// Boolean AND. See also `bit_and`.418 /// Boolean AND. See also `bit_and`.
419 /// Uses the `bin` field.
92 bool_and,420 bool_and,
93 /// Boolean NOT. See also `bit_not`.421 /// Boolean NOT. See also `bit_not`.
422 /// Uses the `un_tok` field.
94 bool_not,423 bool_not,
95 /// Boolean OR. See also `bit_or`.424 /// Boolean OR. See also `bit_or`.
425 /// Uses the `bin` field.
96 bool_or,426 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.
98 @"break",430 @"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.
99 breakpoint,436 breakpoint,
100 /// Same as `break` but without an operand; the operand is assumed to be the void value.437 /// Function call with modifier `.auto`.
101 break_void,438 /// Uses `pl_node`. AST node is the function call. Payload is `Call`.
102 /// Function call.
103 call,439 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,
104 /// `<`449 /// `<`
105 cmp_lt,450 cmp_lt,
106 /// `<=`451 /// `<=`
...@@ -118,95 +463,117 @@ pub const Inst = struct {...@@ -118,95 +463,117 @@ pub const Inst = struct {
118 /// LHS is destination element type, RHS is result pointer.463 /// LHS is destination element type, RHS is result pointer.
119 coerce_result_ptr,464 coerce_result_ptr,
120 /// Emit an error message and fail compilation.465 /// Emit an error message and fail compilation.
466 /// Uses the `un_node` field.
121 compile_error,467 compile_error,
122 /// Log compile time variables and emit an error message.468 /// 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`.
123 compile_log,471 compile_log,
124 /// Conditional branch. Splits control flow based on a boolean condition value.472 /// Conditional branch. Splits control flow based on a boolean condition value.
125 condbr,473 condbr,
126 /// Special case, has no textual representation.474 /// Special case, has no textual representation.
127 @"const",475 @"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,
134 /// Declares the beginning of a statement. Used for debug info.476 /// Declares the beginning of a statement. Used for debug info.
135 dbg_stmt,477 /// Uses the `node` union field.
478 dbg_stmt_node,
136 /// Represents a pointer to a global decl.479 /// Represents a pointer to a global decl.
480 /// Uses the `decl` union field.
137 decl_ref,481 decl_ref,
138 /// Represents a pointer to a global decl by string name.
139 decl_ref_str,
140 /// Equivalent to a decl_ref followed by deref.482 /// Equivalent to a decl_ref followed by deref.
483 /// Uses the `decl` union field.
141 decl_val,484 decl_val,
142 /// Load the value from a pointer.485 /// Load the value from a pointer. Assumes `x.*` syntax.
143 deref,486 /// Uses `un_node` field. AST node is the `x.*` syntax.
487 deref_node,
144 /// Arithmetic division. Asserts no integer overflow.488 /// Arithmetic division. Asserts no integer overflow.
145 div,489 div,
146 /// Given a pointer to an array, slice, or pointer, returns a pointer to the element at490 /// 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.
148 elem_ptr,493 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,
149 /// Given an array, slice, or pointer, returns the element at the provided index.497 /// 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.
150 elem_val,500 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,
151 /// Emits a compile error if the operand is not `void`.504 /// Emits a compile error if the operand is not `void`.
505 /// Uses the `un_node` field.
152 ensure_result_used,506 ensure_result_used,
153 /// Emits a compile error if an error is ignored.507 /// Emits a compile error if an error is ignored.
508 /// Uses the `un_node` field.
154 ensure_result_non_error,509 ensure_result_non_error,
155 /// Create a `E!T` type.510 /// Create a `E!T` type.
156 error_union_type,511 error_union_type,
157 /// Create an error set.512 /// Create an error set. extra[lhs..rhs]. The values are token index offsets.
158 error_set,513 error_set,
159 /// `error.Foo` syntax.514 /// `error.Foo` syntax. uses the `tok` field of the Data union.
160 error_value,515 error_value,
161 /// Export the provided Decl as the provided name in the compilation's output object file.
162 @"export",
163 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer516 /// 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.
165 field_ptr,519 field_ptr,
166 /// Given a struct or object that contains virtual fields, returns the named field.520 /// 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.
168 field_val,523 field_val,
169 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer524 /// Given a pointer to a struct or object that contains virtual fields, returns a pointer
170 /// to the named field. The field name is a comptime instruction. Used by @field.525 /// 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.
171 field_ptr_named,527 field_ptr_named,
172 /// Given a struct or object that contains virtual fields, returns the named field.528 /// Given a struct or object that contains virtual fields, returns the named field.
173 /// The field name is a comptime instruction. Used by @field.529 /// 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.
174 field_val_named,531 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.
176 floatcast,534 floatcast,
177 /// Declare a function body.
178 @"fn",
179 /// Returns a function type, assuming unspecified calling convention.535 /// Returns a function type, assuming unspecified calling convention.
536 /// Uses the `fn_type` union field. `payload_index` points to a `FnType`.
180 fn_type,537 fn_type,
181 /// Same as `fn_type` but the function is variadic.538 /// Same as `fn_type` but the function is variadic.
182 fn_type_var_args,539 fn_type_var_args,
183 /// Returns a function type, with a calling convention instruction operand.540 /// Returns a function type, with a calling convention instruction operand.
541 /// Uses the `fn_type` union field. `payload_index` points to a `FnTypeCc`.
184 fn_type_cc,542 fn_type_cc,
185 /// Same as `fn_type_cc` but the function is variadic.543 /// Same as `fn_type_cc` but the function is variadic.
186 fn_type_cc_var_args,544 fn_type_cc_var_args,
187 /// @import(operand)545 /// `@import(operand)`.
546 /// Uses the `un_node` field.
188 import,547 import,
189 /// Integer literal.548 /// Integer literal that fits in a u64. Uses the int union value.
190 int,549 int,
191 /// Convert an integer value to another integer type, asserting that the destination type550 /// Convert an integer value to another integer type, asserting that the destination type
192 /// can hold the same mathematical value.551 /// can hold the same mathematical value.
193 intcast,552 intcast,
194 /// Make an integer type out of signedness and bit count.553 /// Make an integer type out of signedness and bit count.
554 /// lhs is signedness, rhs is bit count.
195 int_type,555 int_type,
196 /// Return a boolean false if an optional is null. `x != null`556 /// Return a boolean false if an optional is null. `x != null`
557 /// Uses the `un_tok` field.
197 is_non_null,558 is_non_null,
198 /// Return a boolean true if an optional is null. `x == null`559 /// Return a boolean true if an optional is null. `x == null`
560 /// Uses the `un_tok` field.
199 is_null,561 is_null,
200 /// Return a boolean false if an optional is null. `x.* != null`562 /// Return a boolean false if an optional is null. `x.* != null`
563 /// Uses the `un_tok` field.
201 is_non_null_ptr,564 is_non_null_ptr,
202 /// Return a boolean true if an optional is null. `x.* == null`565 /// Return a boolean true if an optional is null. `x.* == null`
566 /// Uses the `un_tok` field.
203 is_null_ptr,567 is_null_ptr,
204 /// Return a boolean true if value is an error568 /// Return a boolean true if value is an error
569 /// Uses the `un_tok` field.
205 is_err,570 is_err,
206 /// Return a boolean true if dereferenced pointer is an error571 /// Return a boolean true if dereferenced pointer is an error
572 /// Uses the `un_tok` field.
207 is_err_ptr,573 is_err_ptr,
208 /// A labeled block of code that loops forever. At the end of the body it is implied574 /// A labeled block of code that loops forever. At the end of the body it is implied
209 /// to repeat; no explicit "repeat" instruction terminates loop bodies.575 /// to repeat; no explicit "repeat" instruction terminates loop bodies.
576 /// SubRange[lhs..rhs]
210 loop,577 loop,
211 /// Merge two error sets into one, `E1 || E2`.578 /// Merge two error sets into one, `E1 || E2`.
212 merge_error_sets,579 merge_error_sets,
...@@ -221,63 +588,70 @@ pub const Inst = struct {...@@ -221,63 +588,70 @@ pub const Inst = struct {
221 /// An await inside a nosuspend scope.588 /// An await inside a nosuspend scope.
222 nosuspend_await,589 nosuspend_await,
223 /// Given a reference to a function and a parameter index, returns the590 /// 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.
225 param_type,597 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,
229 /// Convert a pointer to a `usize` integer.598 /// Convert a pointer to a `usize` integer.
599 /// Uses the `un_node` field. The AST node is the builtin fn call node.
230 ptrtoint,600 ptrtoint,
231 /// Turns an R-Value into a const L-Value. In other words, it takes a value,601 /// Turns an R-Value into a const L-Value. In other words, it takes a value,
232 /// stores it in a memory location, and returns a const pointer to it. If the value602 /// stores it in a memory location, and returns a const pointer to it. If the value
233 /// is `comptime`, the memory location is global static constant data. Otherwise,603 /// is `comptime`, the memory location is global static constant data. Otherwise,
234 /// the memory location is in the stack frame, local to the scope containing the604 /// the memory location is in the stack frame, local to the scope containing the
235 /// instruction.605 /// instruction.
606 /// Uses the `un_tok` union field.
236 ref,607 ref,
237 /// Resume an async function.608 /// Resume an async function.
238 @"resume",609 @"resume",
239 /// Obtains a pointer to the return value.610 /// Obtains a pointer to the return value.
611 /// lhs and rhs unused.
240 ret_ptr,612 ret_ptr,
241 /// Obtains the return type of the in-scope function.613 /// Obtains the return type of the in-scope function.
614 /// lhs and rhs unused.
242 ret_type,615 ret_type,
243 /// Sends control flow back to the function's callee. Takes an operand as the return value.616 /// Sends control flow back to the function's callee.
244 @"return",617 /// Includes an operand as the return value.
245 /// Same as `return` but there is no operand; the operand is implicitly the void value.618 /// Includes an AST node source location.
246 return_void,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,
247 /// Changes the maximum number of backwards branches that compile-time626 /// Changes the maximum number of backwards branches that compile-time
248 /// code execution can use before giving up and making a compile error.627 /// code execution can use before giving up and making a compile error.
628 /// Uses the `un_node` union field.
249 set_eval_branch_quota,629 set_eval_branch_quota,
250 /// Integer shift-left. Zeroes are shifted in from the right hand side.630 /// Integer shift-left. Zeroes are shifted in from the right hand side.
251 shl,631 shl,
252 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.632 /// Integer shift-right. Arithmetic or logical depending on the signedness of the integer type.
253 shr,633 shr,
254 /// Create a const pointer type with element type T. `*const T`634 /// Create a pointer type that does not have a sentinel, alignment, or bit range specified.
255 single_const_ptr_type,635 /// Uses the `ptr_type_simple` union field.
256 /// Create a mutable pointer type with element type T. `*T`636 ptr_type_simple,
257 single_mut_ptr_type,637 /// Create a pointer type which can have a sentinel, alignment, and/or bit range.
258 /// Create a const pointer type with element type T. `[*]const T`638 /// Uses the `ptr_type` union field.
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
271 ptr_type,639 ptr_type,
272 /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,640 /// Each `store_to_inferred_ptr` puts the type of the stored value into a set,
273 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.641 /// and then `resolve_inferred_alloc` triggers peer type resolution on the set.
274 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which642 /// The operand is a `alloc_inferred` or `alloc_inferred_mut` instruction, which
275 /// is the allocation that needs to have its type inferred.643 /// is the allocation that needs to have its type inferred.
644 /// Uses the `un_node` field. The AST node is the var decl.
276 resolve_inferred_alloc,645 resolve_inferred_alloc,
277 /// Slice operation `array_ptr[start..end:sentinel]`646 /// Slice operation `lhs[rhs..]`. No sentinel and no end offset.
278 slice,647 /// Uses the `pl_node` field. AST node is the slice syntax. Payload is `SliceStart`.
279 /// Slice operation with just start `lhs[rhs..]`
280 slice_start,648 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,
281 /// Write a value to a pointer. For loading, see `deref`.655 /// Write a value to a pointer. For loading, see `deref`.
282 store,656 store,
283 /// Same as `store` but the type of the value being stored will be used to infer657 /// Same as `store` but the type of the value being stored will be used to infer
...@@ -287,242 +661,130 @@ pub const Inst = struct {...@@ -287,242 +661,130 @@ pub const Inst = struct {
287 /// the pointer type.661 /// the pointer type.
288 store_to_inferred_ptr,662 store_to_inferred_ptr,
289 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.663 /// String Literal. Makes an anonymous Decl and then takes a pointer to it.
664 /// Uses the `str` union field.
290 str,665 str,
291 /// Create a struct type.
292 struct_type,
293 /// Arithmetic subtraction. Asserts no integer overflow.666 /// Arithmetic subtraction. Asserts no integer overflow.
294 sub,667 sub,
295 /// Twos complement wrapping integer subtraction.668 /// Twos complement wrapping integer subtraction.
296 subwrap,669 subwrap,
297 /// Returns the type of a value.670 /// Returns the type of a value.
671 /// Uses the `un_tok` field.
298 typeof,672 typeof,
299 /// Is the builtin @TypeOf which returns the type after peertype resolution of one or more params673 /// 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`.
300 typeof_peer,676 typeof_peer,
301 /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler677 /// Asserts control-flow will not reach this instruction. Not safety checked - the compiler
302 /// will assume the correctness of this instruction.678 /// will assume the correctness of this instruction.
679 /// lhs and rhs unused.
303 unreachable_unsafe,680 unreachable_unsafe,
304 /// Asserts control-flow will not reach this instruction. In safety-checked modes,681 /// Asserts control-flow will not reach this instruction. In safety-checked modes,
305 /// this will generate a call to the panic function unless it can be proven unreachable682 /// this will generate a call to the panic function unless it can be proven unreachable
306 /// by the compiler.683 /// by the compiler.
684 /// lhs and rhs unused.
307 unreachable_safe,685 unreachable_safe,
308 /// Bitwise XOR. `^`686 /// Bitwise XOR. `^`
309 xor,687 xor,
310 /// Create an optional type '?T'688 /// Create an optional type '?T'
689 /// Uses the `un_tok` field.
311 optional_type,690 optional_type,
312 /// Create an optional type '?T'. The operand is a pointer value. The optional type will691 /// Create an optional type '?T'. The operand is a pointer value. The optional type will
313 /// be the type of the pointer element, wrapped in an optional.692 /// be the type of the pointer element, wrapped in an optional.
693 /// Uses the `un_tok` field.
314 optional_type_from_ptr_elem,694 optional_type_from_ptr_elem,
315 /// Create a union type.
316 union_type,
317 /// ?T => T with safety.695 /// ?T => T with safety.
318 /// Given an optional value, returns the payload value, with a safety check that696 /// Given an optional value, returns the payload value, with a safety check that
319 /// the value is non-null. Used for `orelse`, `if` and `while`.697 /// the value is non-null. Used for `orelse`, `if` and `while`.
698 /// Uses the `un_tok` field.
320 optional_payload_safe,699 optional_payload_safe,
321 /// ?T => T without safety.700 /// ?T => T without safety.
322 /// Given an optional value, returns the payload value. No safety checks.701 /// Given an optional value, returns the payload value. No safety checks.
702 /// Uses the `un_tok` field.
323 optional_payload_unsafe,703 optional_payload_unsafe,
324 /// *?T => *T with safety.704 /// *?T => *T with safety.
325 /// Given a pointer to an optional value, returns a pointer to the payload value,705 /// Given a pointer to an optional value, returns a pointer to the payload value,
326 /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`.706 /// with a safety check that the value is non-null. Used for `orelse`, `if` and `while`.
707 /// Uses the `un_tok` field.
327 optional_payload_safe_ptr,708 optional_payload_safe_ptr,
328 /// *?T => *T without safety.709 /// *?T => *T without safety.
329 /// Given a pointer to an optional value, returns a pointer to the payload value.710 /// Given a pointer to an optional value, returns a pointer to the payload value.
330 /// No safety checks.711 /// No safety checks.
712 /// Uses the `un_tok` field.
331 optional_payload_unsafe_ptr,713 optional_payload_unsafe_ptr,
332 /// E!T => T with safety.714 /// E!T => T with safety.
333 /// Given an error union value, returns the payload value, with a safety check715 /// Given an error union value, returns the payload value, with a safety check
334 /// that the value is not an error. Used for catch, if, and while.716 /// that the value is not an error. Used for catch, if, and while.
717 /// Uses the `un_tok` field.
335 err_union_payload_safe,718 err_union_payload_safe,
336 /// E!T => T without safety.719 /// E!T => T without safety.
337 /// Given an error union value, returns the payload value. No safety checks.720 /// Given an error union value, returns the payload value. No safety checks.
721 /// Uses the `un_tok` field.
338 err_union_payload_unsafe,722 err_union_payload_unsafe,
339 /// *E!T => *T with safety.723 /// *E!T => *T with safety.
340 /// Given a pointer to an error union value, returns a pointer to the payload value,724 /// Given a pointer to an error union value, returns a pointer to the payload value,
341 /// with a safety check that the value is not an error. Used for catch, if, and while.725 /// with a safety check that the value is not an error. Used for catch, if, and while.
726 /// Uses the `un_tok` field.
342 err_union_payload_safe_ptr,727 err_union_payload_safe_ptr,
343 /// *E!T => *T without safety.728 /// *E!T => *T without safety.
344 /// Given a pointer to a error union value, returns a pointer to the payload value.729 /// Given a pointer to a error union value, returns a pointer to the payload value.
345 /// No safety checks.730 /// No safety checks.
731 /// Uses the `un_tok` field.
346 err_union_payload_unsafe_ptr,732 err_union_payload_unsafe_ptr,
347 /// E!T => E without safety.733 /// E!T => E without safety.
348 /// Given an error union value, returns the error code. No safety checks.734 /// Given an error union value, returns the error code. No safety checks.
735 /// Uses the `un_tok` field.
349 err_union_code,736 err_union_code,
350 /// *E!T => E without safety.737 /// *E!T => E without safety.
351 /// Given a pointer to an error union value, returns the error code. No safety checks.738 /// Given a pointer to an error union value, returns the error code. No safety checks.
739 /// Uses the `un_tok` field.
352 err_union_code_ptr,740 err_union_code_ptr,
353 /// Takes a *E!T and raises a compiler error if T != void741 /// Takes a *E!T and raises a compiler error if T != void
742 /// Uses the `un_tok` field.
354 ensure_err_payload_void,743 ensure_err_payload_void,
355 /// Create a enum literal,744 /// An enum literal. Uses the `str` union field.
356 enum_literal,745 enum_literal,
357 /// Create an enum type.746 /// Suspend an async function. The suspend block has 0 or 1 statements in it.
358 enum_type,747 /// Uses the `un_node` union field.
359 /// Does nothing; returns a void value.748 suspend_block_one,
360 void_value,749 /// Suspend an async function. The suspend block has any number of statements in it.
361 /// Suspend an async function.750 /// Uses the `block` union field.
362 @"suspend",
363 /// Suspend an async function.
364 /// Same as .suspend but with a block.
365 suspend_block,751 suspend_block,
366 /// A switch expression.752 /// A switch expression.
367 switchbr,753 /// lhs is target, SwitchBr[rhs]
368 /// Same as `switchbr` but the target is a pointer to the value being switched on.754 /// All prongs of target handled.
369 switchbr_ref,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,
370 /// A range in a switch case, `lhs...rhs`.781 /// A range in a switch case, `lhs...rhs`.
371 /// Only checks that `lhs >= rhs` if they are ints, everything else is782 /// 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.
373 switch_range,784 switch_range,
374785
375 pub fn Type(tag: Tag) type {786 comptime {
376 return switch (tag) {787 assert(@sizeOf(Tag) == 1);
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 };
526 }788 }
527789
528 /// Returns whether the instruction is one of the control flow "noreturn" types.790 /// Returns whether the instruction is one of the control flow "noreturn" types.
...@@ -540,7 +802,6 @@ pub const Inst = struct {...@@ -540,7 +802,6 @@ pub const Inst = struct {
540 .array_type,802 .array_type,
541 .array_type_sentinel,803 .array_type_sentinel,
542 .indexable_ptr_len,804 .indexable_ptr_len,
543 .arg,
544 .as,805 .as,
545 .@"asm",806 .@"asm",
546 .bit_and,807 .bit_and,
...@@ -557,6 +818,13 @@ pub const Inst = struct {...@@ -557,6 +818,13 @@ pub const Inst = struct {
557 .bool_or,818 .bool_or,
558 .breakpoint,819 .breakpoint,
559 .call,820 .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,
560 .cmp_lt,828 .cmp_lt,
561 .cmp_lte,829 .cmp_lte,
562 .cmp_eq,830 .cmp_eq,
...@@ -567,21 +835,18 @@ pub const Inst = struct {...@@ -567,21 +835,18 @@ pub const Inst = struct {
567 .@"const",835 .@"const",
568 .dbg_stmt,836 .dbg_stmt,
569 .decl_ref,837 .decl_ref,
570 .decl_ref_str,
571 .decl_val,838 .decl_val,
572 .deref,839 .deref_node,
573 .div,840 .div,
574 .elem_ptr,841 .elem_ptr,
575 .elem_val,842 .elem_val,
576 .ensure_result_used,843 .ensure_result_used,
577 .ensure_result_non_error,844 .ensure_result_non_error,
578 .@"export",
579 .floatcast,845 .floatcast,
580 .field_ptr,846 .field_ptr,
581 .field_val,847 .field_val,
582 .field_ptr_named,848 .field_ptr_named,
583 .field_val_named,849 .field_val_named,
584 .@"fn",
585 .fn_type,850 .fn_type,
586 .fn_type_var_args,851 .fn_type_var_args,
587 .fn_type_cc,852 .fn_type_cc,
...@@ -599,7 +864,6 @@ pub const Inst = struct {...@@ -599,7 +864,6 @@ pub const Inst = struct {
599 .mul,864 .mul,
600 .mulwrap,865 .mulwrap,
601 .param_type,866 .param_type,
602 .primitive,
603 .ptrtoint,867 .ptrtoint,
604 .ref,868 .ref,
605 .ret_ptr,869 .ret_ptr,
...@@ -635,6 +899,7 @@ pub const Inst = struct {...@@ -635,6 +899,7 @@ pub const Inst = struct {
635 .err_union_code,899 .err_union_code,
636 .err_union_code_ptr,900 .err_union_code_ptr,
637 .ptr_type,901 .ptr_type,
902 .ptr_type_simple,
638 .ensure_err_payload_void,903 .ensure_err_payload_void,
639 .enum_literal,904 .enum_literal,
640 .merge_error_sets,905 .merge_error_sets,
...@@ -650,9 +915,6 @@ pub const Inst = struct {...@@ -650,9 +915,6 @@ pub const Inst = struct {
650 .resolve_inferred_alloc,915 .resolve_inferred_alloc,
651 .set_eval_branch_quota,916 .set_eval_branch_quota,
652 .compile_log,917 .compile_log,
653 .enum_type,
654 .union_type,
655 .struct_type,
656 .void_value,918 .void_value,
657 .switch_range,919 .switch_range,
658 .@"resume",920 .@"resume",
...@@ -661,19 +923,19 @@ pub const Inst = struct {...@@ -661,19 +923,19 @@ pub const Inst = struct {
661 => false,923 => false,
662924
663 .@"break",925 .@"break",
664 .break_void,926 .break_void_tok,
665 .condbr,927 .condbr,
666 .compile_error,928 .compile_error,
667 .@"return",929 .ret_node,
668 .return_void,930 .ret_tok,
669 .unreachable_unsafe,931 .unreachable_unsafe,
670 .unreachable_safe,932 .unreachable_safe,
671 .loop,933 .loop,
672 .container_field_named,934 .container_field_named,
673 .container_field_typed,935 .container_field_typed,
674 .container_field,936 .container_field,
675 .switchbr,937 .switch_br,
676 .switchbr_ref,938 .switch_br_ref,
677 .@"suspend",939 .@"suspend",
678 .suspend_block,940 .suspend_block,
679 => true,941 => true,
...@@ -681,1346 +943,244 @@ pub const Inst = struct {...@@ -681,1346 +943,244 @@ pub const Inst = struct {
681 }943 }
682 };944 };
683945
684 /// Prefer `castTag` to this.946 /// The position of a ZIR instruction within the `Code` instructions array.
685 pub fn cast(base: *Inst, comptime T: type) ?*T {947 pub const Index = u32;
686 if (@hasField(T, "base_tag")) {948
687 return base.castTag(T.base_tag);949 /// A reference to another ZIR instruction. If this value is below a certain
688 }950 /// threshold, it implicitly refers to a constant-known value from the `Const` enum.
689 inline for (@typeInfo(Tag).Enum.fields) |field| {951 /// Below a second threshold, it implicitly refers to a parameter of the current
690 const tag = @intToEnum(Tag, field.value);952 /// function.
691 if (base.tag == tag) {953 /// Finally, after subtracting that offset, it refers to another instruction in
692 if (T == tag.Type()) {954 /// the instruction array.
693 return @fieldParentPtr(T, "base", base);955 /// This logic is implemented in `Sema.resolveRef`.
694 }956 pub const Ref = u32;
695 return null;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 };
696 }972 }
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,
787 },973 },
788 kw_args: struct {},974 /// Used for unary operators, with a token source location.
789 };975 un_tok: struct {
790976 /// Offset from Decl AST token index.
791 pub const DeclRef = struct {977 src_tok: ast.TokenIndex,
792 pub const base_tag = Tag.decl_ref;978 /// The meaning of this operand depends on the corresponding `Tag`.
793 base: Inst,979 operand: Ref,
794980
795 positionals: struct {981 fn src(self: @This()) LazySrcLoc {
796 decl: *IrModule.Decl,982 return .{ .token_offset = self.src_tok };
983 }
797 },984 },
798 kw_args: struct {},985 pl_node: struct {
799 };986 /// Offset from Decl AST node index.
800987 /// `Tag` determines which kind of AST node this points to.
801 pub const DeclRefStr = struct {988 src_node: ast.Node.Index,
802 pub const base_tag = Tag.decl_ref_str;989 /// index into extra.
803 base: Inst,990 /// `Tag` determines what lives there.
804991 payload_index: u32,
805 positionals: struct {992
806 name: *Inst,993 fn src(self: @This()) LazySrcLoc {
994 return .{ .node_offset = self.src_node };
995 }
807 },996 },
808 kw_args: struct {},997 bin: Bin,
809 };998 decl: *Module.Decl,
810999 @"const": *TypedValue,
811 pub const DeclVal = struct {1000 str: struct {
812 pub const base_tag = Tag.decl_val;1001 /// Offset into `string_bytes`.
813 base: Inst,1002 start: u32,
8141003 /// Number of bytes in the string.
815 positionals: struct {1004 len: u32,
816 decl: *IrModule.Decl,1005
1006 pub fn get(self: @This(), code: Code) []const u8 {
1007 return code.string_bytes[self.start..][0..self.len];
1008 }
817 },1009 },
818 kw_args: struct {},1010 /// Offset from Decl AST token index.
819 };1011 tok: ast.TokenIndex,
8201012 /// Offset from Decl AST node index.
821 pub const CompileLog = struct {1013 node: ast.Node.Index,
822 pub const base_tag = Tag.compile_log;1014 int: u64,
823 base: Inst,1015 condbr: struct {
8241016 condition: Ref,
825 positionals: struct {1017 /// index into extra.
826 to_log: []*Inst,1018 payload_index: u32,
827 },1019 },
828 kw_args: struct {},1020 ptr_type_simple: struct {
829 };1021 is_allowzero: bool,
8301022 is_mutable: bool,
831 pub const Const = struct {1023 is_volatile: bool,
832 pub const base_tag = Tag.@"const";1024 size: std.builtin.TypeInfo.Pointer.Size,
833 base: Inst,1025 elem_type: Ref,
834
835 positionals: struct {
836 typed_value: TypedValue,
837 },1026 },
838 kw_args: struct {},1027 ptr_type: struct {
839 };1028 flags: packed struct {
8401029 is_allowzero: bool,
841 pub const Str = struct {1030 is_mutable: bool,
842 pub const base_tag = Tag.str;1031 is_volatile: bool,
843 base: Inst,1032 has_sentinel: bool,
8441033 has_align: bool,
845 positionals: struct {1034 has_bit_start: bool,
846 bytes: []const u8,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,
847 },1041 },
848 kw_args: struct {},1042 fn_type: struct {
849 };1043 return_type: Ref,
8501044 /// For `fn_type` this points to a `FnType` in `extra`.
851 pub const Int = struct {1045 /// For `fn_type_cc` this points to `FnTypeCc` in `extra`.
852 pub const base_tag = Tag.int;1046 payload_index: u32,
853 base: Inst,
854
855 positionals: struct {
856 int: BigIntConst,
857 },1047 },
858 kw_args: struct {},1048 param_type: struct {
859 };1049 callee: Ref,
8601050 param_index: u32,
861 pub const Loop = struct {
862 pub const base_tag = Tag.loop;
863 base: Inst,
864
865 positionals: struct {
866 body: Body,
867 },1051 },
868 kw_args: struct {},
869 };
8701052
871 pub const Field = struct {1053 // Make sure we don't accidentally add a field to make this union
872 base: Inst,1054 // bigger than expected. Note that in Debug builds, Zig is allowed
8731055 // to insert a secret field for safety checks.
874 positionals: struct {1056 comptime {
875 object: *Inst,1057 if (std.builtin.mode != .Debug) {
876 field_name: []const u8,1058 assert(@sizeOf(Data) == 8);
877 },1059 }
878 kw_args: struct {},1060 }
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 {},
889 };1061 };
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.
891 pub const Asm = struct {1068 pub const Asm = struct {
892 pub const base_tag = Tag.@"asm";1069 asm_source: Ref,
893 base: Inst,1070 return_type: Ref,
8941071 /// May be omitted.
895 positionals: struct {1072 output: Ref,
896 asm_source: *Inst,1073 args_len: u32,
897 return_type: *Inst,1074 clobbers_len: u32,
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 {},
928 };1075 };
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`.
930 pub const FnTypeCc = struct {1080 pub const FnTypeCc = struct {
931 pub const base_tag = Tag.fn_type_cc;1081 cc: Ref,
932 base: Inst,1082 param_types_len: u32,
933
934 positionals: struct {
935 param_types: []*Inst,
936 return_type: *Inst,
937 cc: *Inst,
938 },
939 kw_args: struct {},
940 };1083 };
9411084
942 pub const IntType = struct {1085 /// This data is stored inside extra, with trailing parameter type indexes
943 pub const base_tag = Tag.int_type;1086 /// according to `param_types_len`.
944 base: Inst,1087 /// Each param type is a `Ref`.
9451088 pub const FnType = struct {
946 positionals: struct {1089 param_types_len: u32,
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 {},
962 };1090 };
9631091
964 pub const ParamType = struct {1092 /// This data is stored inside extra, with trailing operands according to `operands_len`.
965 pub const base_tag = Tag.param_type;1093 /// Each operand is a `Ref`.
966 base: Inst,1094 pub const MultiOp = struct {
9671095 operands_len: u32,
968 positionals: struct {
969 func: *Inst,
970 arg_index: usize,
971 },
972 kw_args: struct {},
973 };1096 };
9741097
975 pub const Primitive = struct {1098 /// Stored inside extra, with trailing arguments according to `args_len`.
976 pub const base_tag = Tag.primitive;1099 /// Each argument is a `Ref`.
977 base: Inst,1100 pub const Call = struct {
9781101 callee: Ref,
979 positionals: struct {1102 args_len: u32,
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 {},
1073 };1103 };
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`.
1075 pub const CondBr = struct {1108 pub const CondBr = struct {
1076 pub const base_tag = Tag.condbr;1109 then_body_len: u32,
1077 base: Inst,1110 else_body_len: u32,
1078
1079 positionals: struct {
1080 condition: *Inst,
1081 then_body: Body,
1082 else_body: Body,
1083 },
1084 kw_args: struct {},
1085 };1111 };
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
1087 pub const PtrType = struct {1119 pub const PtrType = struct {
1088 pub const base_tag = Tag.ptr_type;1120 elem_type: Ref,
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 },
1104 };1121 };
11051122
1106 pub const ArrayTypeSentinel = struct {1123 pub const ArrayTypeSentinel = struct {
1107 pub const base_tag = Tag.array_type_sentinel;1124 sentinel: Ref,
1108 base: Inst,1125 elem_type: Ref,
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 {},
1136 };1126 };
11371127
1138 pub const ErrorValue = struct {1128 pub const SliceStart = struct {
1139 pub const base_tag = Tag.error_value;1129 lhs: Ref,
1140 base: Inst,1130 start: Ref,
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 {},
1190 };1131 };
11911132
1192 pub const ContainerField = struct {1133 pub const SliceEnd = struct {
1193 pub const base_tag = Tag.container_field;1134 lhs: Ref,
1194 base: Inst,1135 start: Ref,
11951136 end: Ref,
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 },
1205 };1137 };
12061138
1207 pub const EnumType = struct {1139 pub const SliceSentinel = struct {
1208 pub const base_tag = Tag.enum_type;1140 lhs: Ref,
1209 base: Inst,1141 start: Ref,
12101142 end: Ref,
1211 positionals: struct {1143 sentinel: Ref,
1212 fields: []*Inst,
1213 },
1214 kw_args: struct {
1215 tag_type: ?*Inst = null,
1216 layout: std.builtin.TypeInfo.ContainerLayout = .Auto,
1217 },
1218 };1144 };
12191145
1220 pub const StructType = struct {1146 /// The meaning of these operands depends on the corresponding `Tag`.
1221 pub const base_tag = Tag.struct_type;1147 pub const Bin = struct {
1222 base: Inst,1148 lhs: Ref,
12231149 rhs: Ref,
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 },
1244 };1150 };
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
1246 pub const SwitchBr = struct {1162 pub const SwitchBr = struct {
1247 base: Inst,1163 /// TODO investigate, why do we need to store this? is it redundant?
12481164 items_len: u32,
1249 positionals: struct {1165 cases_len: u32,
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,
1306 };1166 };
13071167
1308 pub fn deinit(self: *Module, allocator: *Allocator) void {1168 pub const Field = struct {
1309 self.metadata.deinit();1169 lhs: Ref,
1310 self.body_metadata.deinit();1170 /// Offset into `string_bytes`.
1311 allocator.free(self.decls);1171 field_name_start: u32,
1312 self.arena.deinit();1172 /// Number of bytes in the string.
1313 self.* = undefined;1173 field_name_len: u32,
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,
1324 };1174 };
13251175
1326 /// TODO Look into making a table to speed this up.1176 pub const FieldNamed = struct {
1327 pub fn findDecl(self: Module, name: []const u8) ?DeclAndIndex {1177 lhs: Ref,
1328 for (self.decls) |decl, i| {1178 field_name: Ref,
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),
1586 };1179 };
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 }
2020};1180};
20211181
2022/// For debugging purposes, like dumpFn but for unanalyzed zir blocks1182/// 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 {
2024 var fib = std.heap.FixedBufferAllocator.init(&[_]u8{});1184 var fib = std.heap.FixedBufferAllocator.init(&[_]u8{});
2025 var module = Module{1185 var module = Module{
2026 .decls = &[_]*Module.Decl{},1186 .decls = &[_]*Module.Decl{},
...@@ -2030,10 +1190,10 @@ pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8...@@ -2030,10 +1190,10 @@ pub fn dumpZir(allocator: *Allocator, kind: []const u8, decl_name: [*:0]const u8
2030 };1190 };
2031 var write = Writer{1191 var write = Writer{
2032 .module = &module,1192 .module = &module,
2033 .inst_table = InstPtrTable.init(allocator),1193 .inst_table = InstPtrTable.init(gpa),
2034 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(allocator),1194 .block_table = std.AutoHashMap(*Inst.Block, []const u8).init(gpa),
2035 .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(allocator),1195 .loop_table = std.AutoHashMap(*Inst.Loop, []const u8).init(gpa),
2036 .arena = std.heap.ArenaAllocator.init(allocator),1196 .arena = std.heap.ArenaAllocator.init(gpa),
2037 .indent = 4,1197 .indent = 4,
2038 .next_instr_index = 0,1198 .next_instr_index = 0,
2039 };1199 };
src/zir_sema.zig+2221-949
...@@ -1,11 +1,36 @@...@@ -1,11 +1,36 @@
1//! Semantic analysis of ZIR instructions.1//! Semantic analysis of ZIR instructions.
2//! This file operates on a `Module` instance, transforming untyped ZIR2//! Shared to every Block. Stored on the stack.
3//! instructions into semantically-analyzed IR instructions. It does type3//! State used for compiling a `zir.Code` into TZIR.
4//! checking, comptime control flow, and safety-check generation. This is the4//! Transforms untyped ZIR instructions into semantically-analyzed TZIR instructions.
5//! the heart of the Zig compiler.5//! Does type checking, comptime control flow, and safety-check generation.
6//! When deciding if something goes into this file or into Module, here is a6//! This is the the heart of the Zig compiler.
7//! guiding principle: if it has to do with (untyped) ZIR instructions, it goes7
8//! here. If the analysis operates on typed IR instructions, it goes in Module.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
10const std = @import("std");35const std = @import("std");
11const mem = std.mem;36const mem = std.mem;
...@@ -13,6 +38,7 @@ const Allocator = std.mem.Allocator;...@@ -13,6 +38,7 @@ const Allocator = std.mem.Allocator;
13const assert = std.debug.assert;38const assert = std.debug.assert;
14const log = std.log.scoped(.sema);39const log = std.log.scoped(.sema);
1540
41const Sema = @This();
16const Value = @import("value.zig").Value;42const Value = @import("value.zig").Value;
17const Type = @import("type.zig").Type;43const Type = @import("type.zig").Type;
18const TypedValue = @import("TypedValue.zig");44const TypedValue = @import("TypedValue.zig");
...@@ -25,340 +51,408 @@ const trace = @import("tracy.zig").trace;...@@ -25,340 +51,408 @@ const trace = @import("tracy.zig").trace;
25const Scope = Module.Scope;51const Scope = Module.Scope;
26const InnerError = Module.InnerError;52const InnerError = Module.InnerError;
27const Decl = Module.Decl;53const Decl = Module.Decl;
54const LazySrcLoc = Module.LazySrcLoc;
2855
29pub fn analyzeInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!*Inst {56// TODO when memory layout of TZIR is reworked, this can be simplified.
30 switch (old_inst.tag) {57const const_tzir_inst_list = blk: {
31 .alloc => return zirAlloc(mod, scope, old_inst.castTag(.alloc).?),58 var result: [zir.const_inst_list.len]ir.Inst.Const = undefined;
32 .alloc_mut => return zirAllocMut(mod, scope, old_inst.castTag(.alloc_mut).?),59 for (result) |*tzir_const, i| {
33 .alloc_inferred => return zirAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred).?, .inferred_alloc_const),60 tzir_const.* = .{
34 .alloc_inferred_mut => return zirAllocInferred(mod, scope, old_inst.castTag(.alloc_inferred_mut).?, .inferred_alloc_mut),61 .base = .{
35 .arg => return zirArg(mod, scope, old_inst.castTag(.arg).?),62 .tag = .constant,
36 .bitcast_ref => return zirBitcastRef(mod, scope, old_inst.castTag(.bitcast_ref).?),63 .ty = zir.const_inst_list[i].ty,
37 .bitcast_result_ptr => return zirBitcastResultPtr(mod, scope, old_inst.castTag(.bitcast_result_ptr).?),64 .src = 0,
38 .block => return zirBlock(mod, scope, old_inst.castTag(.block).?, false),65 },
39 .block_comptime => return zirBlock(mod, scope, old_inst.castTag(.block_comptime).?, true),66 .val = zir.const_inst_list[i].val,
40 .block_flat => return zirBlockFlat(mod, scope, old_inst.castTag(.block_flat).?, false),67 };
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 }
191 }68 }
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);
192}75}
19376
194pub fn analyzeBodyValueAsType(77pub fn rootAsType(
195 mod: *Module,78 sema: *Sema,
196 block_scope: *Scope.Block,79 root_block: *Scope.Block,
197 zir_result_inst: *zir.Inst,80 zir_result_inst: zir.Inst.Index,
198 body: zir.Body,81 body: zir.Body,
199) !Type {82) !Type {
200 try analyzeBody(mod, block_scope, body);83 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];
201 const result_inst = block_scope.inst_table.get(zir_result_inst).?;84 try sema.body(root_block, root_body);
202 const val = try mod.resolveConstValue(&block_scope.base, result_inst);85
203 return val.toType(block_scope.base.arena());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 }
204}242}
205243
206pub fn resolveInst(mod: *Module, scope: *Scope, zir_inst: *zir.Inst) InnerError!*Inst {244fn resolveInst(sema: *Sema, block: *Scope.Block, zir_ref: zir.Inst.Ref) *const ir.Inst {
207 const block = scope.cast(Scope.Block).?;245 var i = zir_ref;
208 return block.inst_table.get(zir_inst).?; // Instruction does not dominate all uses!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];
209}268}
210269
211fn resolveConstString(mod: *Module, scope: *Scope, old_inst: *zir.Inst) ![]u8 {270fn resolveConstString(
212 const new_inst = try resolveInst(mod, scope, old_inst);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);
213 const wanted_type = Type.initTag(.const_slice_u8);277 const wanted_type = Type.initTag(.const_slice_u8);
214 const coerced_inst = try mod.coerce(scope, wanted_type, new_inst);278 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
215 const val = try mod.resolveConstValue(scope, coerced_inst);279 const val = try sema.resolveConstValue(block, src, coerced_inst);
216 return val.toAllocatedBytes(scope.arena());280 return val.toAllocatedBytes(block.arena);
217}281}
218282
219fn resolveType(mod: *Module, scope: *Scope, old_inst: *zir.Inst) !Type {283fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.Inst.Ref) !Type {
220 const new_inst = try resolveInst(mod, scope, old_inst);284 const tzir_inst = sema.resolveInt(block, zir_ref);
221 const wanted_type = Type.initTag(.@"type");285 const wanted_type = Type.initTag(.@"type");
222 const coerced_inst = try mod.coerce(scope, wanted_type, new_inst);286 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
223 const val = try mod.resolveConstValue(scope, coerced_inst);287 const val = try sema.resolveConstValue(block, src, coerced_inst);
224 return val.toType(scope.arena());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;
225}304}
226305
227/// Appropriate to call when the coercion has already been done by result306/// Appropriate to call when the coercion has already been done by result
228/// location semantics. Asserts the value fits in the provided `Int` type.307/// location semantics. Asserts the value fits in the provided `Int` type.
229/// Only supports `Int` types 64 bits or less.308/// Only supports `Int` types 64 bits or less.
230fn resolveAlreadyCoercedInt(309fn resolveAlreadyCoercedInt(
231 mod: *Module,310 sema: *Sema,
232 scope: *Scope,311 block: *Scope.Block,
233 old_inst: *zir.Inst,312 src: LazySrcLoc,
313 zir_ref: zir.Inst.Ref,
234 comptime Int: type,314 comptime Int: type,
235) !Int {315) !Int {
236 comptime assert(@typeInfo(Int).Int.bits <= 64);316 comptime assert(@typeInfo(Int).Int.bits <= 64);
237 const new_inst = try resolveInst(mod, scope, old_inst);317 const tzir_inst = sema.resolveInst(block, zir_ref);
238 const val = try mod.resolveConstValue(scope, new_inst);318 const val = try sema.resolveConstValue(block, src, tzir_inst);
239 switch (@typeInfo(Int).Int.signedness) {319 switch (@typeInfo(Int).Int.signedness) {
240 .signed => return @intCast(Int, val.toSignedInt()),320 .signed => return @intCast(Int, val.toSignedInt()),
241 .unsigned => return @intCast(Int, val.toUnsignedInt()),321 .unsigned => return @intCast(Int, val.toUnsignedInt()),
242 }322 }
243}323}
244324
245fn resolveInt(mod: *Module, scope: *Scope, old_inst: *zir.Inst, dest_type: Type) !u64 {325fn resolveInt(
246 const new_inst = try resolveInst(mod, scope, old_inst);326 sema: *Sema,
247 const coerced = try mod.coerce(scope, dest_type, new_inst);327 block: *Scope.Block,
248 const val = try mod.resolveConstValue(scope, coerced);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
250 return val.toUnsignedInt();336 return val.toUnsignedInt();
251}337}
252338
253pub fn resolveInstConst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {339fn resolveInstConst(
254 const new_inst = try resolveInst(mod, scope, old_inst);340 sema: *Sema,
255 const val = try mod.resolveConstValue(scope, new_inst);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);
256 return TypedValue{347 return TypedValue{
257 .ty = new_inst.ty,348 .ty = tzir_inst.ty,
258 .val = val,349 .val = val,
259 };350 };
260}351}
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 {
263 const tracy = trace(@src());354 const tracy = trace(@src());
264 defer tracy.end();355 defer tracy.end();
265 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions356 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
266 // after analysis.357 // after analysis.
267 const typed_value_copy = try const_inst.positionals.typed_value.copy(scope.arena());358 const typed_value_copy = try const_inst.positionals.typed_value.copy(block.arena);
268 return mod.constInst(scope, const_inst.base.src, typed_value_copy);359 return sema.mod.constInst(scope, const_inst.base.src, typed_value_copy);
269}360}
270361
271fn analyzeConstInst(mod: *Module, scope: *Scope, old_inst: *zir.Inst) InnerError!TypedValue {362fn zirBitcastRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
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 {
280 const tracy = trace(@src());363 const tracy = trace(@src());
281 defer tracy.end();364 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", .{});
283}366}
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 {
286 const tracy = trace(@src());369 const tracy = trace(@src());
287 defer tracy.end();370 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", .{});
289}372}
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 {
292 const tracy = trace(@src());375 const tracy = trace(@src());
293 defer tracy.end();376 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", .{});
295}378}
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 {
298 const tracy = trace(@src());381 const tracy = trace(@src());
299 defer tracy.end();382 defer tracy.end();
300 const b = try mod.requireFunctionBlock(scope, inst.base.src);383
301 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;384 try sema.requireFunctionBlock(block, inst.base.src);
385 const fn_ty = block.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
302 const ret_type = fn_ty.fnReturnType();386 const ret_type = fn_ty.fnReturnType();
303 const ptr_type = try mod.simplePtrType(scope, inst.base.src, ret_type, true, .One);387 const ptr_type = try sema.mod.simplePtrType(block.arena, ret_type, true, .One);
304 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);388 return block.addNoOp(inst.base.src, ptr_type, .alloc);
305}389}
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 {
308 const tracy = trace(@src());392 const tracy = trace(@src());
309 defer tracy.end();393 defer tracy.end();
310394
311 const operand = try resolveInst(mod, scope, inst.positionals.operand);395 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
312 return mod.analyzeRef(scope, inst.base.src, operand);396 const operand = sema.resolveInst(block, inst_data.operand);
397 return sema.analyzeRef(block, inst_data.src(), operand);
313}398}
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 {
316 const tracy = trace(@src());401 const tracy = trace(@src());
317 defer tracy.end();402 defer tracy.end();
318 const b = try mod.requireFunctionBlock(scope, inst.base.src);403 try sema.requireFunctionBlock(block, inst.base.src);
319 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;404 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
320 const ret_type = fn_ty.fnReturnType();405 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);
322}407}
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 {
325 const tracy = trace(@src());410 const tracy = trace(@src());
326 defer tracy.end();411 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();
328 switch (operand.ty.zigTypeTag()) {416 switch (operand.ty.zigTypeTag()) {
329 .Void, .NoReturn => return mod.constVoid(scope, operand.src),417 .Void, .NoReturn => return sema.mod.constVoid(block.arena, .unneeded),
330 else => return mod.fail(scope, operand.src, "expression value is ignored", .{}),418 else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),
331 }419 }
332}420}
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 {
335 const tracy = trace(@src());423 const tracy = trace(@src());
336 defer tracy.end();424 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();
338 switch (operand.ty.zigTypeTag()) {429 switch (operand.ty.zigTypeTag()) {
339 .ErrorSet, .ErrorUnion => return mod.fail(scope, operand.src, "error is discarded", .{}),430 .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),
340 else => return mod.constVoid(scope, operand.src),431 else => return sema.mod.constVoid(block.arena, .unneeded),
341 }432 }
342}433}
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 {
345 const tracy = trace(@src());436 const tracy = trace(@src());
346 defer tracy.end();437 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
349 const elem_ty = array_ptr.ty.elemType();442 const elem_ty = array_ptr.ty.elemType();
350 if (!elem_ty.isIndexable()) {443 if (!elem_ty.isIndexable()) {
444 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
351 const msg = msg: {445 const msg = msg: {
352 const msg = try mod.errMsg(446 const msg = try sema.mod.errMsg(
353 scope,447 &block.base,
354 inst.base.src,448 cond_src,
355 "type '{}' does not support indexing",449 "type '{}' does not support indexing",
356 .{elem_ty},450 .{elem_ty},
357 );451 );
358 errdefer msg.destroy(mod.gpa);452 errdefer msg.destroy(mod.gpa);
359 try mod.errNote(453 try sema.mod.errNote(
360 scope,454 &block.base,
361 inst.base.src,455 cond_src,
362 msg,456 msg,
363 "for loop operand must be an array, slice, tuple, or vector",457 "for loop operand must be an array, slice, tuple, or vector",
364 .{},458 .{},
...@@ -367,38 +461,46 @@ fn zirIndexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerEr...@@ -367,38 +461,46 @@ fn zirIndexablePtrLen(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerEr
367 };461 };
368 return mod.failWithOwnedErrorMsg(scope, msg);462 return mod.failWithOwnedErrorMsg(scope, msg);
369 }463 }
370 const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, array_ptr, "len", inst.base.src);464 const result_ptr = try sema.namedFieldPtr(block, inst.base.src, array_ptr, "len", inst.base.src);
371 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);465 return sema.analyzeDeref(block, inst.base.src, result_ptr, result_ptr.src);
372}466}
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 {
375 const tracy = trace(@src());469 const tracy = trace(@src());
376 defer tracy.end();470 defer tracy.end();
377 const var_type = try resolveType(mod, scope, inst.positionals.operand);471
378 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);472 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
379 const b = try mod.requireRuntimeBlock(scope, inst.base.src);473 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
380 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);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);
381}479}
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 {
384 const tracy = trace(@src());482 const tracy = trace(@src());
385 defer tracy.end();483 defer tracy.end();
386 const var_type = try resolveType(mod, scope, inst.positionals.operand);484
387 try mod.validateVarType(scope, inst.base.src, var_type);485 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
388 const ptr_type = try mod.simplePtrType(scope, inst.base.src, var_type, true, .One);486 const var_decl_src = inst_data.src();
389 const b = try mod.requireRuntimeBlock(scope, inst.base.src);487 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
390 return mod.addNoOp(b, inst.base.src, ptr_type, .alloc);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);
391}493}
392494
393fn zirAllocInferred(495fn zirAllocInferred(
394 mod: *Module,496 sema: *Sema,
395 scope: *Scope,497 block: *Scope.Block,
396 inst: *zir.Inst.NoOp,498 inst: zir.Inst.Index,
397 mut_tag: Type.Tag,499 inferred_alloc_ty: Type,
398) InnerError!*Inst {500) InnerError!*Inst {
399 const tracy = trace(@src());501 const tracy = trace(@src());
400 defer tracy.end();502 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);
402 val_payload.* = .{504 val_payload.* = .{
403 .data = .{},505 .data = .{},
404 };506 };
...@@ -406,193 +508,197 @@ fn zirAllocInferred(...@@ -406,193 +508,197 @@ fn zirAllocInferred(
406 // not needed in the case of constant values. However here, we plan to "downgrade"508 // not needed in the case of constant values. However here, we plan to "downgrade"
407 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append509 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
408 // to the block even though it is currently a `.constant`.510 // to the block even though it is currently a `.constant`.
409 const result = try mod.constInst(scope, inst.base.src, .{511 const result = try sema.mod.constInst(scope, inst.base.src, .{
410 .ty = switch (mut_tag) {512 .ty = inferred_alloc_ty,
411 .inferred_alloc_const => Type.initTag(.inferred_alloc_const),
412 .inferred_alloc_mut => Type.initTag(.inferred_alloc_mut),
413 else => unreachable,
414 },
415 .val = Value.initPayload(&val_payload.base),513 .val = Value.initPayload(&val_payload.base),
416 });514 });
417 const block = try mod.requireFunctionBlock(scope, inst.base.src);515 try sema.requireFunctionBlock(block, inst.base.src);
418 try block.instructions.append(mod.gpa, result);516 try block.instructions.append(sema.gpa, result);
419 return result;517 return result;
420}518}
421519
422fn zirResolveInferredAlloc(520fn zirResolveInferredAlloc(
423 mod: *Module,521 sema: *Sema,
424 scope: *Scope,522 block: *Scope.Block,
425 inst: *zir.Inst.UnOp,523 inst: zir.Inst.Index,
426) InnerError!*Inst {524) InnerError!*Inst {
427 const tracy = trace(@src());525 const tracy = trace(@src());
428 defer tracy.end();526 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);
430 const ptr_val = ptr.castTag(.constant).?.val;531 const ptr_val = ptr.castTag(.constant).?.val;
431 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;532 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
432 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;533 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);
434 const var_is_mut = switch (ptr.ty.tag()) {535 const var_is_mut = switch (ptr.ty.tag()) {
435 .inferred_alloc_const => false,536 .inferred_alloc_const => false,
436 .inferred_alloc_mut => true,537 .inferred_alloc_mut => true,
437 else => unreachable,538 else => unreachable,
438 };539 };
439 if (var_is_mut) {540 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);
441 }542 }
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
444 // Change it to a normal alloc.545 // Change it to a normal alloc.
445 ptr.ty = final_ptr_ty;546 ptr.ty = final_ptr_ty;
446 ptr.tag = .alloc;547 ptr.tag = .alloc;
447548
448 return mod.constVoid(scope, inst.base.src);549 return sema.mod.constVoid(block.arena, .unneeded);
449}550}
450551
451fn zirStoreToBlockPtr(552fn zirStoreToBlockPtr(
452 mod: *Module,553 sema: *Sema,
453 scope: *Scope,554 block: *Scope.Block,
454 inst: *zir.Inst.BinOp,555 inst: zir.Inst.Index,
455) InnerError!*Inst {556) InnerError!*Inst {
456 const tracy = trace(@src());557 const tracy = trace(@src());
457 defer tracy.end();558 defer tracy.end();
458559
459 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);560 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
460 const value = try resolveInst(mod, scope, inst.positionals.rhs);561 const ptr = sema.resolveInst(bin_inst.lhs);
461 const ptr_ty = try mod.simplePtrType(scope, inst.base.src, value.ty, true, .One);562 const value = sema.resolveInst(bin_inst.rhs);
563 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
462 // TODO detect when this store should be done at compile-time. For example,564 // TODO detect when this store should be done at compile-time. For example,
463 // if expressions should force it when the condition is compile-time known.565 // if expressions should force it when the condition is compile-time known.
464 const b = try mod.requireRuntimeBlock(scope, inst.base.src);566 try sema.requireRuntimeBlock(block, src);
465 const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr);567 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
466 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);568 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
467}569}
468570
469fn zirStoreToInferredPtr(571fn zirStoreToInferredPtr(
470 mod: *Module,572 sema: *Sema,
471 scope: *Scope,573 block: *Scope.Block,
472 inst: *zir.Inst.BinOp,574 inst: zir.Inst.Index,
473) InnerError!*Inst {575) InnerError!*Inst {
474 const tracy = trace(@src());576 const tracy = trace(@src());
475 defer tracy.end();577 defer tracy.end();
476578
477 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);579 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
478 const value = try resolveInst(mod, scope, inst.positionals.rhs);580 const ptr = sema.resolveInst(bin_inst.lhs);
581 const value = sema.resolveInst(bin_inst.rhs);
479 const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;582 const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;
480 // Add the stored instruction to the set we will use to resolve peer types583 // Add the stored instruction to the set we will use to resolve peer types
481 // for the inferred allocation.584 // 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);
483 // Create a runtime bitcast instruction with exactly the type the pointer wants.586 // 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);587 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
485 const b = try mod.requireRuntimeBlock(scope, inst.base.src);588 try sema.requireRuntimeBlock(block, src);
486 const bitcasted_ptr = try mod.addUnOp(b, inst.base.src, ptr_ty, .bitcast, ptr);589 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
487 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);590 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
488}591}
489592
490fn zirSetEvalBranchQuota(593fn zirSetEvalBranchQuota(
491 mod: *Module,594 sema: *Sema,
492 scope: *Scope,595 block: *Scope.Block,
493 inst: *zir.Inst.UnOp,596 inst: zir.Inst.Index,
494) InnerError!*Inst {597) InnerError!*Inst {
495 const b = try mod.requireFunctionBlock(scope, inst.base.src);598 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
496 const quota = try resolveAlreadyCoercedInt(mod, scope, inst.positionals.operand, u32);599 const src = inst_data.src();
600 try sema.requireFunctionBlock(block, src);
601 const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);
497 if (b.branch_quota.* < quota)602 if (b.branch_quota.* < quota)
498 b.branch_quota.* = quota;603 b.branch_quota.* = quota;
499 return mod.constVoid(scope, inst.base.src);604 return sema.mod.constVoid(block.arena, .unneeded);
500}605}
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 {
503 const tracy = trace(@src());608 const tracy = trace(@src());
504 defer tracy.end();609 defer tracy.end();
505610
506 const ptr = try resolveInst(mod, scope, inst.positionals.lhs);611 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
507 const value = try resolveInst(mod, scope, inst.positionals.rhs);612 const ptr = sema.resolveInst(bin_inst.lhs);
613 const value = sema.resolveInst(bin_inst.rhs);
508 return mod.storePtr(scope, inst.base.src, ptr, value);614 return mod.storePtr(scope, inst.base.src, ptr, value);
509}615}
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 {
512 const tracy = trace(@src());618 const tracy = trace(@src());
513 defer tracy.end();619 defer tracy.end();
514 const fn_inst = try resolveInst(mod, scope, inst.positionals.func);620
515 const arg_index = inst.positionals.arg_index;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
517 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {625 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
518 .Fn => fn_inst.ty,626 .Fn => fn_inst.ty,
519 .BoundFn => {627 .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", .{});
521 },629 },
522 else => {630 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});
524 },632 },
525 };633 };
526634
527 const param_count = fn_ty.fnParamLen();635 const param_count = fn_ty.fnParamLen();
528 if (arg_index >= param_count) {636 if (param_index >= param_count) {
529 if (fn_ty.fnIsVarArgs()) {637 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));
531 }639 }
532 return mod.fail(scope, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{640 return sema.mod.fail(&block.base, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
533 arg_index,641 param_index,
534 fn_ty,642 fn_ty,
535 param_count,643 param_count,
536 });644 });
537 }645 }
538646
539 // TODO support generic functions647 // TODO support generic functions
540 const param_type = fn_ty.fnParamType(arg_index);648 const param_type = fn_ty.fnParamType(param_index);
541 return mod.constType(scope, inst.base.src, param_type);649 return sema.mod.constType(block.arena, inst.base.src, param_type);
542}650}
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 {
545 const tracy = trace(@src());653 const tracy = trace(@src());
546 defer tracy.end();654 defer tracy.end();
547 // The bytes references memory inside the ZIR module, which can get deallocated655
548 // after semantic analysis is complete. We need the memory to be in the new anonymous Decl's arena.656 // The bytes references memory inside the ZIR module, which is fine. Multiple
549 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);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);
550 errdefer new_decl_arena.deinit();661 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);663 const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
554 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, arena_bytes);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, .{
557 .ty = decl_ty,667 .ty = decl_ty,
558 .val = decl_val,668 .val = decl_val,
559 });669 });
560 return mod.analyzeDeclRef(scope, str_inst.base.src, new_decl);670 return sema.analyzeDeclRef(block, .unneeded, new_decl);
561}671}
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 {
564 const tracy = trace(@src());674 const tracy = trace(@src());
565 defer tracy.end();675 defer tracy.end();
566676
567 return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int);677 return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int);
568}678}
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 {
571 const tracy = trace(@src());681 const tracy = trace(@src());
572 defer tracy.end();682 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 {684 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
581 const tracy = trace(@src());685 const src = inst_data.src();
582 defer tracy.end();686 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
583 const msg = try resolveConstString(mod, scope, inst.positionals.operand);687 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand);
584 return mod.fail(scope, inst.base.src, "{s}", .{msg});688 return sema.mod.fail(&block.base, src, "{s}", .{msg});
585}689}
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 {
588 var managed = mod.compile_log_text.toManaged(mod.gpa);692 var managed = mod.compile_log_text.toManaged(mod.gpa);
589 defer mod.compile_log_text = managed.moveToUnmanaged();693 defer mod.compile_log_text = managed.moveToUnmanaged();
590 const writer = managed.writer();694 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| {
593 if (i != 0) try writer.print(", ", .{});699 if (i != 0) try writer.print(", ", .{});
594700
595 const arg = try resolveInst(mod, scope, arg_inst);701 const arg = sema.resolveInst(block, arg_ref);
596 if (arg.value()) |val| {702 if (arg.value()) |val| {
597 try writer.print("@as({}, {})", .{ arg.ty, val });703 try writer.print("@as({}, {})", .{ arg.ty, val });
598 } else {704 } else {
...@@ -604,40 +710,16 @@ fn zirCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerE...@@ -604,40 +710,16 @@ fn zirCompileLog(mod: *Module, scope: *Scope, inst: *zir.Inst.CompileLog) InnerE
604 const gop = try mod.compile_log_decls.getOrPut(mod.gpa, scope.ownerDecl().?);710 const gop = try mod.compile_log_decls.getOrPut(mod.gpa, scope.ownerDecl().?);
605 if (!gop.found_existing) {711 if (!gop.found_existing) {
606 gop.entry.value = .{712 gop.entry.value = .{
607 .file_scope = scope.getFileScope(),713 .file_scope = block.getFileScope(),
608 .byte_offset = inst.base.src,714 .lazy = inst_data.src(),
609 };715 };
610 }716 }
611 return mod.constVoid(scope, inst.base.src);717 return sema.mod.constVoid(block.arena, .unneeded);
612}718}
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 {
615 const tracy = trace(@src());721 const tracy = trace(@src());
616 defer tracy.end();722 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
642 // Reserve space for a Loop instruction so that generated Break instructions can724 // Reserve space for a Loop instruction so that generated Break instructions can
643 // point to it, even if it doesn't end up getting used because the code ends up being725 // 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 {...@@ -666,7 +748,7 @@ fn zirLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
666 };748 };
667 defer child_block.instructions.deinit(mod.gpa);749 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
671 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.753 // 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 {...@@ -675,16 +757,15 @@ fn zirLoop(mod: *Module, scope: *Scope, inst: *zir.Inst.Loop) InnerError!*Inst {
675 return &loop_inst.base;757 return &loop_inst.base;
676}758}
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 {
679 const tracy = trace(@src());761 const tracy = trace(@src());
680 defer tracy.end();762 defer tracy.end();
681 const parent_block = scope.cast(Scope.Block).?;
682763
683 var child_block = parent_block.makeSubBlock();764 var child_block = parent_block.makeSubBlock();
684 defer child_block.instructions.deinit(mod.gpa);765 defer child_block.instructions.deinit(mod.gpa);
685 child_block.is_comptime = child_block.is_comptime or is_comptime;766 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
689 // Move the analyzed instructions into the parent block arena.770 // Move the analyzed instructions into the parent block arena.
690 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);771 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:...@@ -693,20 +774,18 @@ fn zirBlockFlat(mod: *Module, scope: *Scope, inst: *zir.Inst.Block, is_comptime:
693 // The result of a flat block is the last instruction.774 // The result of a flat block is the last instruction.
694 const zir_inst_list = inst.positionals.body.instructions;775 const zir_inst_list = inst.positionals.body.instructions;
695 const last_zir_inst = zir_inst_list[zir_inst_list.len - 1];776 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];
697}778}
698779
699fn zirBlock(780fn zirBlock(
700 mod: *Module,781 sema: *Sema,
701 scope: *Scope,782 parent_block: *Scope.Block,
702 inst: *zir.Inst.Block,783 inst: zir.Inst.Index,
703 is_comptime: bool,784 is_comptime: bool,
704) InnerError!*Inst {785) InnerError!*Inst {
705 const tracy = trace(@src());786 const tracy = trace(@src());
706 defer tracy.end();787 defer tracy.end();
707788
708 const parent_block = scope.cast(Scope.Block).?;
709
710 // Reserve space for a Block instruction so that generated Break instructions can789 // Reserve space for a Block instruction so that generated Break instructions can
711 // point to it, even if it doesn't end up getting used because the code ends up being790 // point to it, even if it doesn't end up getting used because the code ends up being
712 // comptime evaluated.791 // comptime evaluated.
...@@ -747,22 +826,20 @@ fn zirBlock(...@@ -747,22 +826,20 @@ fn zirBlock(
747 defer merges.results.deinit(mod.gpa);826 defer merges.results.deinit(mod.gpa);
748 defer merges.br_list.deinit(mod.gpa);827 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
752 return analyzeBlockBody(mod, scope, &child_block, merges);831 return analyzeBlockBody(mod, scope, &child_block, merges);
753}832}
754833
755fn analyzeBlockBody(834fn analyzeBlockBody(
756 mod: *Module,835 sema: *Sema,
757 scope: *Scope,836 parent_block: *Scope.Block,
758 child_block: *Scope.Block,837 child_block: *Scope.Block,
759 merges: *Scope.Block.Merges,838 merges: *Scope.Block.Merges,
760) InnerError!*Inst {839) InnerError!*Inst {
761 const tracy = trace(@src());840 const tracy = trace(@src());
762 defer tracy.end();841 defer tracy.end();
763842
764 const parent_block = scope.cast(Scope.Block).?;
765
766 // Blocks must terminate with noreturn instruction.843 // Blocks must terminate with noreturn instruction.
767 assert(child_block.instructions.items.len != 0);844 assert(child_block.instructions.items.len != 0);
768 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());845 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
...@@ -793,7 +870,7 @@ fn analyzeBlockBody(...@@ -793,7 +870,7 @@ fn analyzeBlockBody(
793 // Need to set the type and emit the Block instruction. This allows machine code generation870 // Need to set the type and emit the Block instruction. This allows machine code generation
794 // to emit a jump instruction to after the block when it encounters the break.871 // to emit a jump instruction to after the block when it encounters the break.
795 try parent_block.instructions.append(mod.gpa, &merges.block_inst.base);872 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);
797 merges.block_inst.base.ty = resolved_ty;874 merges.block_inst.base.ty = resolved_ty;
798 merges.block_inst.body = .{875 merges.block_inst.body = .{
799 .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items),876 .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items),
...@@ -807,7 +884,7 @@ fn analyzeBlockBody(...@@ -807,7 +884,7 @@ fn analyzeBlockBody(
807 }884 }
808 var coerce_block = parent_block.makeSubBlock();885 var coerce_block = parent_block.makeSubBlock();
809 defer coerce_block.instructions.deinit(mod.gpa);886 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);
811 // If no instructions were produced, such as in the case of a coercion of a888 // If no instructions were produced, such as in the case of a coercion of a
812 // constant value to a new type, we can simply point the br operand to it.889 // constant value to a new type, we can simply point the br operand to it.
813 if (coerce_block.instructions.items.len == 0) {890 if (coerce_block.instructions.items.len == 0) {
...@@ -835,43 +912,46 @@ fn analyzeBlockBody(...@@ -835,43 +912,46 @@ fn analyzeBlockBody(
835 return &merges.block_inst.base;912 return &merges.block_inst.base;
836}913}
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 {
839 const tracy = trace(@src());916 const tracy = trace(@src());
840 defer tracy.end();917 defer tracy.end();
841 const b = try mod.requireRuntimeBlock(scope, inst.base.src);918
842 return mod.addNoOp(b, inst.base.src, Type.initTag(.void), .breakpoint);919 try sema.requireRuntimeBlock(block, src);
920 return block.addNoOp(inst.base.src, Type.initTag(.void), .breakpoint);
843}921}
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 {
846 const tracy = trace(@src());924 const tracy = trace(@src());
847 defer tracy.end();925 defer tracy.end();
848926
849 const operand = try resolveInst(mod, scope, inst.positionals.operand);927 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
850 const block = inst.positionals.block;928 const operand = sema.resolveInst(block, bin_inst.rhs);
851 return analyzeBreak(mod, scope, inst.base.src, block, operand);929 const zir_block = bin_inst.lhs;
930 return analyzeBreak(mod, block, sema.src, zir_block, operand);
852}931}
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 {
855 const tracy = trace(@src());934 const tracy = trace(@src());
856 defer tracy.end();935 defer tracy.end();
857936
858 const block = inst.positionals.block;937 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
859 const void_inst = try mod.constVoid(scope, inst.base.src);938 const zir_block = inst_data.operand;
860 return analyzeBreak(mod, scope, inst.base.src, block, void_inst);939 const void_inst = try sema.mod.constVoid(block.arena, .unneeded);
940 return analyzeBreak(mod, block, inst_data.src(), zir_block, void_inst);
861}941}
862942
863fn analyzeBreak(943fn analyzeBreak(
864 mod: *Module,944 sema: *Sema,
865 scope: *Scope,945 block: *Scope.Block,
866 src: usize,946 src: LazySrcLoc,
867 zir_block: *zir.Inst.Block,947 zir_block: zir.Inst.Index,
868 operand: *Inst,948 operand: *Inst,
869) InnerError!*Inst {949) InnerError!*Inst {
870 var opt_block = scope.cast(Scope.Block);950 var opt_block = scope.cast(Scope.Block);
871 while (opt_block) |block| {951 while (opt_block) |block| {
872 if (block.label) |*label| {952 if (block.label) |*label| {
873 if (label.zir_block == zir_block) {953 if (label.zir_block == zir_block) {
874 const b = try mod.requireFunctionBlock(scope, src);954 try sema.requireFunctionBlock(block, src);
875 // Here we add a br instruction, but we over-allocate a little bit955 // Here we add a br instruction, but we over-allocate a little bit
876 // (if necessary) to make it possible to convert the instruction into956 // (if necessary) to make it possible to convert the instruction into
877 // a br_block_flat instruction later.957 // a br_block_flat instruction later.
...@@ -899,102 +979,134 @@ fn analyzeBreak(...@@ -899,102 +979,134 @@ fn analyzeBreak(
899 } else unreachable;979 } else unreachable;
900}980}
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 {
903 const tracy = trace(@src());983 const tracy = trace(@src());
904 defer tracy.end();984 defer tracy.end();
905 if (scope.cast(Scope.Block)) |b| {985
906 if (!b.is_comptime) {986 if (b.is_comptime) {
907 return mod.addNoOp(b, inst.base.src, Type.initTag(.void), .dbg_stmt);987 return sema.mod.constVoid(block.arena, .unneeded);
908 }
909 }988 }
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);
911}993}
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 {
914 const tracy = trace(@src());996 const tracy = trace(@src());
915 defer tracy.end();997 defer tracy.end();
916 const decl_name = try resolveConstString(mod, scope, inst.positionals.name);998
917 return mod.analyzeDeclRefByName(scope, inst.base.src, decl_name);999 const decl = sema.code.instructions.items(.data)[inst].decl;
1000 return sema.analyzeDeclRef(block, .unneeded, decl);
918}1001}
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 {
921 const tracy = trace(@src());1004 const tracy = trace(@src());
922 defer tracy.end();1005 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);
924}1009}
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 {
927 const tracy = trace(@src());1012 const tracy = trace(@src());
928 defer tracy.end();1013 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, &.{});
930}1019}
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 {
933 const tracy = trace(@src());1027 const tracy = trace(@src());
934 defer tracy.end();1028 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
937 if (func.ty.zigTypeTag() != .Fn)1050 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
940 const cc = func.ty.fnCallingConvention();1053 const cc = func.ty.fnCallingConvention();
941 if (cc == .Naked) {1054 if (cc == .Naked) {
942 // TODO add error note: declared here1055 // TODO add error note: declared here
943 return mod.fail(1056 return sema.mod.fail(
944 scope,1057 &block.base,
945 inst.positionals.func.src,1058 func_src,
946 "unable to call function with naked calling convention",1059 "unable to call function with naked calling convention",
947 .{},1060 .{},
948 );1061 );
949 }1062 }
950 const call_params_len = inst.positionals.args.len;
951 const fn_params_len = func.ty.fnParamLen();1063 const fn_params_len = func.ty.fnParamLen();
952 if (func.ty.fnIsVarArgs()) {1064 if (func.ty.fnIsVarArgs()) {
953 assert(cc == .C);1065 assert(cc == .C);
954 if (call_params_len < fn_params_len) {1066 if (zir_args.len < fn_params_len) {
955 // TODO add error note: declared here1067 // TODO add error note: declared here
956 return mod.fail(1068 return sema.mod.fail(
957 scope,1069 &block.base,
958 inst.positionals.func.src,1070 func_src,
959 "expected at least {d} argument(s), found {d}",1071 "expected at least {d} argument(s), found {d}",
960 .{ fn_params_len, call_params_len },1072 .{ fn_params_len, zir_args.len },
961 );1073 );
962 }1074 }
963 } else if (fn_params_len != call_params_len) {1075 } else if (fn_params_len != zir_args.len) {
964 // TODO add error note: declared here1076 // TODO add error note: declared here
965 return mod.fail(1077 return sema.mod.fail(
966 scope,1078 &block.base,
967 inst.positionals.func.src,1079 func_src,
968 "expected {d} argument(s), found {d}",1080 "expected {d} argument(s), found {d}",
969 .{ fn_params_len, call_params_len },1081 .{ fn_params_len, zir_args.len },
970 );1082 );
971 }1083 }
9721084
973 if (inst.positionals.modifier == .compile_time) {1085 if (modifier == .compile_time) {
974 return mod.fail(scope, inst.base.src, "TODO implement comptime function calls", .{});1086 return sema.mod.fail(&block.base, call_src, "TODO implement comptime function calls", .{});
975 }1087 }
976 if (inst.positionals.modifier != .auto) {1088 if (modifier != .auto) {
977 return mod.fail(scope, inst.base.src, "TODO implement call with modifier {}", .{inst.positionals.modifier});1089 return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{inst.positionals.modifier});
978 }1090 }
9791091
980 // TODO handle function calls of generic functions1092 // TODO handle function calls of generic functions
981 const casted_args = try scope.arena().alloc(*Inst, call_params_len);1093 const casted_args = try block.arena.alloc(*Inst, zir_args.len);
982 for (inst.positionals.args) |src_arg, i| {1094 for (zir_args) |zir_arg, i| {
983 // the args are already casted to the result of a param type instruction.1095 // 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);
985 }1097 }
9861098
987 const ret_type = func.ty.fnReturnType();1099 const ret_type = func.ty.fnReturnType();
9881100
989 const b = try mod.requireFunctionBlock(scope, inst.base.src);1101 try sema.requireFunctionBlock(block, call_src);
990 const is_comptime_call = b.is_comptime or inst.positionals.modifier == .compile_time;1102 const is_comptime_call = b.is_comptime or modifier == .compile_time;
991 const is_inline_call = is_comptime_call or inst.positionals.modifier == .always_inline or1103 const is_inline_call = is_comptime_call or modifier == .always_inline or
992 func.ty.fnCallingConvention() == .Inline;1104 func.ty.fnCallingConvention() == .Inline;
993 if (is_inline_call) {1105 if (is_inline_call) {
994 const func_val = try mod.resolveConstValue(scope, func);1106 const func_val = try sema.resolveConstValue(block, func_src, func);
995 const module_fn = switch (func_val.tag()) {1107 const module_fn = switch (func_val.tag()) {
996 .function => func_val.castTag(.function).?.data,1108 .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", .{
998 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),1110 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
999 }),1111 }),
1000 else => unreachable,1112 else => unreachable,
...@@ -1005,24 +1117,24 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {...@@ -1005,24 +1117,24 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
1005 // set to in the `Scope.Block`.1117 // set to in the `Scope.Block`.
1006 // This block instruction will be used to capture the return value from the1118 // This block instruction will be used to capture the return value from the
1007 // inlined function.1119 // inlined function.
1008 const block_inst = try scope.arena().create(Inst.Block);1120 const block_inst = try block.arena.create(Inst.Block);
1009 block_inst.* = .{1121 block_inst.* = .{
1010 .base = .{1122 .base = .{
1011 .tag = Inst.Block.base_tag,1123 .tag = Inst.Block.base_tag,
1012 .ty = ret_type,1124 .ty = ret_type,
1013 .src = inst.base.src,1125 .src = call_src,
1014 },1126 },
1015 .body = undefined,1127 .body = undefined,
1016 };1128 };
1017 // If this is the top of the inline/comptime call stack, we use this data.1129 // If this is the top of the inline/comptime call stack, we use this data.
1018 // Otherwise we pass on the shared data from the parent scope.1130 // 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 = .{
1020 .branch_count = 0,1132 .branch_count = 0,
1021 .caller = b.func,1133 .caller = b.func,
1022 };1134 };
1023 // This one is shared among sub-blocks within the same callee, but not1135 // This one is shared among sub-blocks within the same callee, but not
1024 // shared among the entire inline/comptime call stack.1136 // shared among the entire inline/comptime call stack.
1025 var inlining = Scope.Block.Inlining{1137 var inlining: Scope.Block.Inlining = .{
1026 .shared = if (b.inlining) |inlining| inlining.shared else &shared_inlining,1138 .shared = if (b.inlining) |inlining| inlining.shared else &shared_inlining,
1027 .param_index = 0,1139 .param_index = 0,
1028 .casted_args = casted_args,1140 .casted_args = casted_args,
...@@ -1042,7 +1154,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {...@@ -1042,7 +1154,7 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
1042 .owner_decl = scope.ownerDecl().?,1154 .owner_decl = scope.ownerDecl().?,
1043 .src_decl = module_fn.owner_decl,1155 .src_decl = module_fn.owner_decl,
1044 .instructions = .{},1156 .instructions = .{},
1045 .arena = scope.arena(),1157 .arena = block.arena,
1046 .label = null,1158 .label = null,
1047 .inlining = &inlining,1159 .inlining = &inlining,
1048 .is_comptime = is_comptime_call,1160 .is_comptime = is_comptime_call,
...@@ -1055,121 +1167,101 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {...@@ -1055,121 +1167,101 @@ fn zirCall(mod: *Module, scope: *Scope, inst: *zir.Inst.Call) InnerError!*Inst {
1055 defer merges.results.deinit(mod.gpa);1167 defer merges.results.deinit(mod.gpa);
1056 defer merges.br_list.deinit(mod.gpa);1168 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
1060 // This will have return instructions analyzed as break instructions to1172 // This will have return instructions analyzed as break instructions to
1061 // the block_inst above.1173 // the block_inst above.
1062 try analyzeBody(mod, &child_block, module_fn.zir);1174 try sema.body(&child_block, module_fn.zir);
10631175
1064 return analyzeBlockBody(mod, scope, &child_block, merges);1176 return analyzeBlockBody(mod, scope, &child_block, merges);
1065 }1177 }
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);
1068}1180}
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 {
1071 const tracy = trace(@src());1183 const tracy = trace(@src());
1072 defer tracy.end();1184 defer tracy.end();
1073 const fn_type = try resolveType(mod, scope, fn_inst.positionals.fn_type);1185 return sema.mod.fail(&block.base, inttype.base.src, "TODO implement inttype", .{});
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", .{});
1101}1186}
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 {
1104 const tracy = trace(@src());1189 const tracy = trace(@src());
1105 defer tracy.end();1190 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 {1192 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1110 const tracy = trace(@src());1193 const child_type = try sema.resolveType(block, inst_data.operand);
1111 defer tracy.end();1194 const opt_type = try mod.optionalType(block.arena, child_type);
1112 const child_type = try resolveType(mod, scope, optional.positionals.operand);
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);
1115}1197}
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 {
1118 const tracy = trace(@src());1200 const tracy = trace(@src());
1119 defer tracy.end();1201 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);
1122 const elem_ty = ptr.ty.elemType();1205 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);
1125}1209}
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 {
1128 const tracy = trace(@src());1212 const tracy = trace(@src());
1129 defer tracy.end();1213 defer tracy.end();
1130 // TODO these should be lazily evaluated1214 // TODO these should be lazily evaluated
1131 const len = try resolveInstConst(mod, scope, array.positionals.lhs);1215 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));
1135}1219}
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 {
1138 const tracy = trace(@src());1222 const tracy = trace(@src());
1139 defer tracy.end();1223 defer tracy.end();
1140 // TODO these should be lazily evaluated1224 // TODO these should be lazily evaluated
1141 const len = try resolveInstConst(mod, scope, array.positionals.len);1225 const len = try resolveInstConst(mod, scope, array.positionals.len);
1142 const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);1226 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));
1146}1230}
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 {
1149 const tracy = trace(@src());1233 const tracy = trace(@src());
1150 defer tracy.end();1234 defer tracy.end();
1151 const error_union = try resolveType(mod, scope, inst.positionals.lhs);1235
1152 const payload = try resolveType(mod, scope, inst.positionals.rhs);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
1154 if (error_union.zigTypeTag() != .ErrorSet) {1240 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()});
1156 }1242 }
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));
1159}1245}
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 {
1162 const tracy = trace(@src());1248 const tracy = trace(@src());
1163 defer tracy.end();1249 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);
1167}1258}
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 {
1170 const tracy = trace(@src());1261 const tracy = trace(@src());
1171 defer tracy.end();1262 defer tracy.end();
1172 // The declarations arena will store the hashmap.1263
1264 // The owner Decl arena will store the hashmap.
1173 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);1265 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1174 errdefer new_decl_arena.deinit();1266 errdefer new_decl_arena.deinit();
11751267
...@@ -1186,7 +1278,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError...@@ -1186,7 +1278,7 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
1186 for (inst.positionals.fields) |field_name| {1278 for (inst.positionals.fields) |field_name| {
1187 const entry = try mod.getErrorValue(field_name);1279 const entry = try mod.getErrorValue(field_name);
1188 if (payload.data.fields.fetchPutAssumeCapacity(entry.key, {})) |_| {1280 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});
1190 }1282 }
1191 }1283 }
1192 // TODO create name in format "error:line:column"1284 // TODO create name in format "error:line:column"
...@@ -1198,35 +1290,36 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError...@@ -1198,35 +1290,36 @@ fn zirErrorSet(mod: *Module, scope: *Scope, inst: *zir.Inst.ErrorSet) InnerError
1198 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);1290 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1199}1291}
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 {
1202 const tracy = trace(@src());1294 const tracy = trace(@src());
1203 defer tracy.end();1295 defer tracy.end();
12041296
1205 // Create an anonymous error set type with only this error value, and return the value.1297 // Create an anonymous error set type with only this error value, and return the value.
1206 const entry = try mod.getErrorValue(inst.positionals.name);1298 const entry = try mod.getErrorValue(inst.positionals.name);
1207 const result_type = try Type.Tag.error_set_single.create(scope.arena(), entry.key);1299 const result_type = try Type.Tag.error_set_single.create(block.arena, entry.key);
1208 return mod.constInst(scope, inst.base.src, .{1300 return sema.mod.constInst(scope, inst.base.src, .{
1209 .ty = result_type,1301 .ty = result_type,
1210 .val = try Value.Tag.@"error".create(scope.arena(), .{1302 .val = try Value.Tag.@"error".create(block.arena, .{
1211 .name = entry.key,1303 .name = entry.key,
1212 }),1304 }),
1213 });1305 });
1214}1306}
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 {
1217 const tracy = trace(@src());1309 const tracy = trace(@src());
1218 defer tracy.end();1310 defer tracy.end();
12191311
1220 const rhs_ty = try resolveType(mod, scope, inst.positionals.rhs);1312 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1221 const lhs_ty = try resolveType(mod, scope, inst.positionals.lhs);1313 const lhs_ty = try sema.resolveType(block, bin_inst.lhs);
1314 const rhs_ty = try sema.resolveType(block, bin_inst.rhs);
1222 if (rhs_ty.zigTypeTag() != .ErrorSet)1315 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});
1224 if (lhs_ty.zigTypeTag() != .ErrorSet)1317 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
1227 // anything merged with anyerror is anyerror1320 // anything merged with anyerror is anyerror
1228 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)1321 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, .{
1230 .ty = Type.initTag(.type),1323 .ty = Type.initTag(.type),
1231 .val = Value.initTag(.anyerror_type),1324 .val = Value.initTag(.anyerror_type),
1232 });1325 });
...@@ -1291,218 +1384,243 @@ fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr...@@ -1291,218 +1384,243 @@ fn zirMergeErrorSets(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerEr
1291 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);1384 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1292}1385}
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 {
1295 const tracy = trace(@src());1388 const tracy = trace(@src());
1296 defer tracy.end();1389 defer tracy.end();
1297 const duped_name = try scope.arena().dupe(u8, inst.positionals.name);1390
1298 return mod.constInst(scope, inst.base.src, .{1391 const duped_name = try block.arena.dupe(u8, inst.positionals.name);
1392 return sema.mod.constInst(scope, inst.base.src, .{
1299 .ty = Type.initTag(.enum_literal),1393 .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),
1301 });1395 });
1302}1396}
13031397
1304/// Pointer in, pointer out.1398/// Pointer in, pointer out.
1305fn zirOptionalPayloadPtr(1399fn zirOptionalPayloadPtr(
1306 mod: *Module,1400 sema: *Sema,
1307 scope: *Scope,1401 block: *Scope.Block,
1308 unwrap: *zir.Inst.UnOp,1402 inst: zir.Inst.Index,
1309 safety_check: bool,1403 safety_check: bool,
1310) InnerError!*Inst {1404) InnerError!*Inst {
1311 const tracy = trace(@src());1405 const tracy = trace(@src());
1312 defer tracy.end();1406 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);
1315 assert(optional_ptr.ty.zigTypeTag() == .Pointer);1410 assert(optional_ptr.ty.zigTypeTag() == .Pointer);
1411 const src = inst_data.src();
13161412
1317 const opt_type = optional_ptr.ty.elemType();1413 const opt_type = optional_ptr.ty.elemType();
1318 if (opt_type.zigTypeTag() != .Optional) {1414 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});
1320 }1416 }
13211417
1322 const child_type = try opt_type.optionalChildAlloc(scope.arena());1418 const child_type = try opt_type.optionalChildAlloc(block.arena);
1323 const child_pointer = try mod.simplePtrType(scope, unwrap.base.src, child_type, !optional_ptr.ty.isConstPtr(), .One);1419 const child_pointer = try sema.mod.simplePtrType(block.arena, child_type, !optional_ptr.ty.isConstPtr(), .One);
13241420
1325 if (optional_ptr.value()) |pointer_val| {1421 if (optional_ptr.value()) |pointer_val| {
1326 const val = try pointer_val.pointerDeref(scope.arena());1422 const val = try pointer_val.pointerDeref(block.arena);
1327 if (val.isNull()) {1423 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", .{});
1329 }1425 }
1330 // The same Value represents the pointer to the optional and the payload.1426 // 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, .{
1332 .ty = child_pointer,1428 .ty = child_pointer,
1333 .val = pointer_val,1429 .val = pointer_val,
1334 });1430 });
1335 }1431 }
13361432
1337 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);1433 try sema.requireRuntimeBlock(block, src);
1338 if (safety_check and mod.wantSafety(scope)) {1434 if (safety_check and block.wantSafety()) {
1339 const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);1435 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);
1340 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);1436 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
1341 }1437 }
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);
1343}1439}
13441440
1345/// Value in, value out.1441/// Value in, value out.
1346fn zirOptionalPayload(1442fn zirOptionalPayload(
1347 mod: *Module,1443 sema: *Sema,
1348 scope: *Scope,1444 block: *Scope.Block,
1349 unwrap: *zir.Inst.UnOp,1445 inst: zir.Inst.Index,
1350 safety_check: bool,1446 safety_check: bool,
1351) InnerError!*Inst {1447) InnerError!*Inst {
1352 const tracy = trace(@src());1448 const tracy = trace(@src());
1353 defer tracy.end();1449 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);
1356 const opt_type = operand.ty;1454 const opt_type = operand.ty;
1357 if (opt_type.zigTypeTag() != .Optional) {1455 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});
1359 }1457 }
13601458
1361 const child_type = try opt_type.optionalChildAlloc(scope.arena());1459 const child_type = try opt_type.optionalChildAlloc(block.arena);
13621460
1363 if (operand.value()) |val| {1461 if (operand.value()) |val| {
1364 if (val.isNull()) {1462 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", .{});
1366 }1464 }
1367 return mod.constInst(scope, unwrap.base.src, .{1465 return sema.mod.constInst(scope, src, .{
1368 .ty = child_type,1466 .ty = child_type,
1369 .val = val,1467 .val = val,
1370 });1468 });
1371 }1469 }
13721470
1373 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);1471 try sema.requireRuntimeBlock(block, src);
1374 if (safety_check and mod.wantSafety(scope)) {1472 if (safety_check and block.wantSafety()) {
1375 const is_non_null = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_non_null, operand);1473 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null, operand);
1376 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);1474 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
1377 }1475 }
1378 return mod.addUnOp(b, unwrap.base.src, child_type, .optional_payload, operand);1476 return block.addUnOp(src, child_type, .optional_payload, operand);
1379}1477}
13801478
1381/// Value in, value out1479/// 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 {
1383 const tracy = trace(@src());1486 const tracy = trace(@src());
1384 defer tracy.end();1487 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);
1387 if (operand.ty.zigTypeTag() != .ErrorUnion)1492 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
1390 if (operand.value()) |val| {1495 if (operand.value()) |val| {
1391 if (val.getError()) |name| {1496 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});
1393 }1498 }
1394 const data = val.castTag(.error_union).?.data;1499 const data = val.castTag(.error_union).?.data;
1395 return mod.constInst(scope, unwrap.base.src, .{1500 return sema.mod.constInst(scope, src, .{
1396 .ty = operand.ty.castTag(.error_union).?.data.payload,1501 .ty = operand.ty.castTag(.error_union).?.data.payload,
1397 .val = data,1502 .val = data,
1398 });1503 });
1399 }1504 }
1400 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);1505 try sema.requireRuntimeBlock(block, src);
1401 if (safety_check and mod.wantSafety(scope)) {1506 if (safety_check and block.wantSafety()) {
1402 const is_non_err = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_err, operand);1507 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
1403 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);1508 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
1404 }1509 }
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);
1406}1511}
14071512
1408/// Pointer in, pointer out1513/// Pointer in, pointer out.
1409fn zirErrUnionPayloadPtr(mod: *Module, scope: *Scope, unwrap: *zir.Inst.UnOp, safety_check: bool) InnerError!*Inst {1514fn zirErrUnionPayloadPtr(
1515 sema: *Sema,
1516 block: *Scope.Block,
1517 inst: zir.Inst.Index,
1518 safety_check: bool,
1519) InnerError!*Inst {
1410 const tracy = trace(@src());1520 const tracy = trace(@src());
1411 defer tracy.end();1521 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);
1414 assert(operand.ty.zigTypeTag() == .Pointer);1526 assert(operand.ty.zigTypeTag() == .Pointer);
14151527
1416 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)1528 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
1421 if (operand.value()) |pointer_val| {1533 if (operand.value()) |pointer_val| {
1422 const val = try pointer_val.pointerDeref(scope.arena());1534 const val = try pointer_val.pointerDeref(block.arena);
1423 if (val.getError()) |name| {1535 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});
1425 }1537 }
1426 const data = val.castTag(.error_union).?.data;1538 const data = val.castTag(.error_union).?.data;
1427 // The same Value represents the pointer to the error union and the payload.1539 // 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, .{
1429 .ty = operand_pointer_ty,1541 .ty = operand_pointer_ty,
1430 .val = try Value.Tag.ref_val.create(1542 .val = try Value.Tag.ref_val.create(
1431 scope.arena(),1543 block.arena,
1432 data,1544 data,
1433 ),1545 ),
1434 });1546 });
1435 }1547 }
14361548
1437 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);1549 try sema.requireRuntimeBlock(block, src);
1438 if (safety_check and mod.wantSafety(scope)) {1550 if (safety_check and block.wantSafety()) {
1439 const is_non_err = try mod.addUnOp(b, unwrap.base.src, Type.initTag(.bool), .is_err, operand);1551 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
1440 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);1552 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
1441 }1553 }
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);
1443}1555}
14441556
1445/// Value in, value out1557/// 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 {
1447 const tracy = trace(@src());1559 const tracy = trace(@src());
1448 defer tracy.end();1560 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);
1451 if (operand.ty.zigTypeTag() != .ErrorUnion)1565 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
1454 if (operand.value()) |val| {1568 if (operand.value()) |val| {
1455 assert(val.getError() != null);1569 assert(val.getError() != null);
1456 const data = val.castTag(.error_union).?.data;1570 const data = val.castTag(.error_union).?.data;
1457 return mod.constInst(scope, unwrap.base.src, .{1571 return sema.mod.constInst(scope, src, .{
1458 .ty = operand.ty.castTag(.error_union).?.data.error_set,1572 .ty = operand.ty.castTag(.error_union).?.data.error_set,
1459 .val = data,1573 .val = data,
1460 });1574 });
1461 }1575 }
14621576
1463 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);1577 try sema.requireRuntimeBlock(block, src);
1464 return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);1578 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);
1465}1579}
14661580
1467/// Pointer in, value out1581/// 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 {
1469 const tracy = trace(@src());1583 const tracy = trace(@src());
1470 defer tracy.end();1584 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);
1473 assert(operand.ty.zigTypeTag() == .Pointer);1589 assert(operand.ty.zigTypeTag() == .Pointer);
14741590
1475 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)1591 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
1478 if (operand.value()) |pointer_val| {1594 if (operand.value()) |pointer_val| {
1479 const val = try pointer_val.pointerDeref(scope.arena());1595 const val = try pointer_val.pointerDeref(block.arena);
1480 assert(val.getError() != null);1596 assert(val.getError() != null);
1481 const data = val.castTag(.error_union).?.data;1597 const data = val.castTag(.error_union).?.data;
1482 return mod.constInst(scope, unwrap.base.src, .{1598 return sema.mod.constInst(scope, src, .{
1483 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,1599 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,
1484 .val = data,1600 .val = data,
1485 });1601 });
1486 }1602 }
14871603
1488 const b = try mod.requireRuntimeBlock(scope, unwrap.base.src);1604 try sema.requireRuntimeBlock(block, src);
1489 return mod.addUnOp(b, unwrap.base.src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);1605 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
1490}1606}
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 {
1493 const tracy = trace(@src());1609 const tracy = trace(@src());
1494 defer tracy.end();1610 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);
1497 if (operand.ty.zigTypeTag() != .ErrorUnion)1615 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});
1499 if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {1617 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", .{});
1501 }1619 }
1502 return mod.constVoid(scope, unwrap.base.src);1620 return sema.mod.constVoid(block.arena, .unneeded);
1503}1621}
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 {
1506 const tracy = trace(@src());1624 const tracy = trace(@src());
1507 defer tracy.end();1625 defer tracy.end();
15081626
...@@ -1517,7 +1635,7 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bo...@@ -1517,7 +1635,7 @@ fn zirFnType(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnType, var_args: bo
1517 );1635 );
1518}1636}
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 {
1521 const tracy = trace(@src());1639 const tracy = trace(@src());
1522 defer tracy.end();1640 defer tracy.end();
15231641
...@@ -1526,7 +1644,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args...@@ -1526,7 +1644,7 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args
1526 // std.builtin, this needs to change1644 // std.builtin, this needs to change
1527 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;1645 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
1528 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse1646 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});
1530 return fnTypeCommon(1648 return fnTypeCommon(
1531 mod,1649 mod,
1532 scope,1650 scope,
...@@ -1539,129 +1657,144 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args...@@ -1539,129 +1657,144 @@ fn zirFnTypeCc(mod: *Module, scope: *Scope, fntype: *zir.Inst.FnTypeCc, var_args
1539}1657}
15401658
1541fn fnTypeCommon(1659fn fnTypeCommon(
1542 mod: *Module,1660 sema: *Sema,
1543 scope: *Scope,1661 block: *Scope.Block,
1544 zir_inst: *zir.Inst,1662 zir_inst: zir.Inst.Index,
1545 zir_param_types: []*zir.Inst,1663 zir_param_types: []zir.Inst.Index,
1546 zir_return_type: *zir.Inst,1664 zir_return_type: zir.Inst.Index,
1547 cc: std.builtin.CallingConvention,1665 cc: std.builtin.CallingConvention,
1548 var_args: bool,1666 var_args: bool,
1549) InnerError!*Inst {1667) 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
1552 // Hot path for some common function types.1670 // Hot path for some common function types.
1553 if (zir_param_types.len == 0 and !var_args) {1671 if (zir_param_types.len == 0 and !var_args) {
1554 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {1672 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));
1556 }1674 }
15571675
1558 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {1676 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));
1560 }1678 }
15611679
1562 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {1680 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));
1564 }1682 }
15651683
1566 if (return_type.zigTypeTag() == .Void and cc == .C) {1684 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));
1568 }1686 }
1569 }1687 }
15701688
1571 const arena = scope.arena();1689 const param_types = try block.arena.alloc(Type, zir_param_types.len);
1572 const param_types = try arena.alloc(Type, zir_param_types.len);
1573 for (zir_param_types) |param_type, i| {1690 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);
1575 // TODO skip for comptime params1692 // TODO skip for comptime params
1576 if (!resolved.isValidVarType(false)) {1693 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});
1578 }1695 }
1579 param_types[i] = resolved;1696 param_types[i] = resolved;
1580 }1697 }
15811698
1582 const fn_ty = try Type.Tag.function.create(arena, .{1699 const fn_ty = try Type.Tag.function.create(block.arena, .{
1583 .param_types = param_types,1700 .param_types = param_types,
1584 .return_type = return_type,1701 .return_type = return_type,
1585 .cc = cc,1702 .cc = cc,
1586 .is_var_args = var_args,1703 .is_var_args = var_args,
1587 });1704 });
1588 return mod.constType(scope, zir_inst.src, fn_ty);1705 return sema.mod.constType(block.arena, zir_inst.src, fn_ty);
1589}1706}
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 {
1592 const tracy = trace(@src());1709 const tracy = trace(@src());
1593 defer tracy.end();1710 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 {1712 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1598 const tracy = trace(@src());1713 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1599 defer tracy.end();1714 const tzir_inst = sema.resolveInst(block, bin_inst.rhs);
1600 const dest_type = try resolveType(mod, scope, as.positionals.lhs);1715 return sema.coerce(scope, dest_type, tzir_inst);
1601 const new_inst = try resolveInst(mod, scope, as.positionals.rhs);
1602 return mod.coerce(scope, dest_type, new_inst);
1603}1716}
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 {
1606 const tracy = trace(@src());1719 const tracy = trace(@src());
1607 defer tracy.end();1720 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);
1609 if (ptr.ty.zigTypeTag() != .Pointer) {1724 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});
1611 }1727 }
1612 // TODO handle known-pointer-address1728 // 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);
1614 const ty = Type.initTag(.usize);1731 const ty = Type.initTag(.usize);
1615 return mod.addUnOp(b, ptrtoint.base.src, ty, .ptrtoint, ptr);1732 return block.addUnOp(src, ty, .ptrtoint, ptr);
1616}1733}
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 {
1619 const tracy = trace(@src());1736 const tracy = trace(@src());
1620 defer tracy.end();1737 defer tracy.end();
16211738
1622 const object = try resolveInst(mod, scope, inst.positionals.object);1739 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1623 const field_name = inst.positionals.field_name;1740 const src = inst_data.src();
1624 const object_ptr = try mod.analyzeRef(scope, inst.base.src, object);1741 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1625 const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.src);1742 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1626 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);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);
1627}1748}
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 {
1630 const tracy = trace(@src());1751 const tracy = trace(@src());
1631 defer tracy.end();1752 defer tracy.end();
16321753
1633 const object_ptr = try resolveInst(mod, scope, inst.positionals.object);1754 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1634 const field_name = inst.positionals.field_name;1755 const src = inst_data.src();
1635 return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, inst.base.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);
1636}1761}
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 {
1639 const tracy = trace(@src());1764 const tracy = trace(@src());
1640 defer tracy.end();1765 defer tracy.end();
16411766
1642 const object = try resolveInst(mod, scope, inst.positionals.object);1767 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1643 const field_name = try resolveConstString(mod, scope, inst.positionals.field_name);1768 const src = inst_data.src();
1644 const fsrc = inst.positionals.field_name.src;1769 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1645 const object_ptr = try mod.analyzeRef(scope, inst.base.src, object);1770 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1646 const result_ptr = try mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc);1771 const object = sema.resolveInst(block, extra.lhs);
1647 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);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);
1648}1776}
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 {
1651 const tracy = trace(@src());1779 const tracy = trace(@src());
1652 defer tracy.end();1780 defer tracy.end();
16531781
1654 const object_ptr = try resolveInst(mod, scope, inst.positionals.object);1782 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1655 const field_name = try resolveConstString(mod, scope, inst.positionals.field_name);1783 const src = inst_data.src();
1656 const fsrc = inst.positionals.field_name.src;1784 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1657 return mod.namedFieldPtr(scope, inst.base.src, object_ptr, field_name, fsrc);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);
1658}1789}
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 {
1661 const tracy = trace(@src());1792 const tracy = trace(@src());
1662 defer tracy.end();1793 defer tracy.end();
1663 const dest_type = try resolveType(mod, scope, inst.positionals.lhs);1794
1664 const operand = try resolveInst(mod, scope, inst.positionals.rhs);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
1666 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {1799 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
1667 .ComptimeInt => true,1800 .ComptimeInt => true,
...@@ -1687,27 +1820,31 @@ fn zirIntcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In...@@ -1687,27 +1820,31 @@ fn zirIntcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
1687 }1820 }
16881821
1689 if (operand.value() != null) {1822 if (operand.value() != null) {
1690 return mod.coerce(scope, dest_type, operand);1823 return sema.coerce(scope, dest_type, operand);
1691 } else if (dest_is_comptime_int) {1824 } 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'", .{});
1693 }1826 }
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", .{});
1696}1829}
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 {
1699 const tracy = trace(@src());1832 const tracy = trace(@src());
1700 defer tracy.end();1833 defer tracy.end();
1701 const dest_type = try resolveType(mod, scope, inst.positionals.lhs);1834
1702 const operand = try resolveInst(mod, scope, inst.positionals.rhs);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);
1703 return mod.bitcast(scope, dest_type, operand);1838 return mod.bitcast(scope, dest_type, operand);
1704}1839}
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 {
1707 const tracy = trace(@src());1842 const tracy = trace(@src());
1708 defer tracy.end();1843 defer tracy.end();
1709 const dest_type = try resolveType(mod, scope, inst.positionals.lhs);1844
1710 const operand = try resolveInst(mod, scope, inst.positionals.rhs);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
1712 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {1849 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
1713 .ComptimeFloat => true,1850 .ComptimeFloat => true,
...@@ -1733,110 +1870,172 @@ fn zirFloatcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*...@@ -1733,110 +1870,172 @@ fn zirFloatcast(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*
1733 }1870 }
17341871
1735 if (operand.value() != null) {1872 if (operand.value() != null) {
1736 return mod.coerce(scope, dest_type, operand);1873 return sema.coerce(scope, dest_type, operand);
1737 } else if (dest_is_comptime_float) {1874 } 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'", .{});
1739 }1876 }
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", .{});
1742}1879}
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 {
1745 const tracy = trace(@src());1882 const tracy = trace(@src());
1746 defer tracy.end();1883 defer tracy.end();
17471884
1748 const array = try resolveInst(mod, scope, inst.positionals.array);1885 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1749 const array_ptr = try mod.analyzeRef(scope, inst.base.src, array);1886 const array = sema.resolveInst(block, bin_inst.lhs);
1750 const elem_index = try resolveInst(mod, scope, inst.positionals.index);1887 const array_ptr = try sema.analyzeRef(block, sema.src, array);
1751 const result_ptr = try mod.elemPtr(scope, inst.base.src, array_ptr, elem_index);1888 const elem_index = sema.resolveInst(block, bin_inst.rhs);
1752 return mod.analyzeDeref(scope, inst.base.src, result_ptr, result_ptr.src);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);
1753}1891}
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 {
1756 const tracy = trace(@src());1894 const tracy = trace(@src());
1757 defer tracy.end();1895 defer tracy.end();
17581896
1759 const array_ptr = try resolveInst(mod, scope, inst.positionals.array);1897 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1760 const elem_index = try resolveInst(mod, scope, inst.positionals.index);1898 const src = inst_data.src();
1761 return mod.elemPtr(scope, inst.base.src, array_ptr, elem_index);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);
1762}1906}
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 {
1765 const tracy = trace(@src());1909 const tracy = trace(@src());
1766 defer tracy.end();1910 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);
1773}1916}
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 {
1776 const tracy = trace(@src());1919 const tracy = trace(@src());
1777 defer tracy.end();1920 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);
1782}1929}
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 {
1785 const tracy = trace(@src());1932 const tracy = trace(@src());
1786 defer tracy.end();1933 defer tracy.end();
1787 const start = try resolveInst(mod, scope, inst.positionals.lhs);1934
1788 const end = try resolveInst(mod, scope, inst.positionals.rhs);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
1790 switch (start.ty.zigTypeTag()) {1982 switch (start.ty.zigTypeTag()) {
1791 .Int, .ComptimeInt => {},1983 .Int, .ComptimeInt => {},
1792 else => return mod.constVoid(scope, inst.base.src),1984 else => return sema.mod.constVoid(block.arena, .unneeded),
1793 }1985 }
1794 switch (end.ty.zigTypeTag()) {1986 switch (end.ty.zigTypeTag()) {
1795 .Int, .ComptimeInt => {},1987 .Int, .ComptimeInt => {},
1796 else => return mod.constVoid(scope, inst.base.src),1988 else => return sema.mod.constVoid(block.arena, .unneeded),
1797 }1989 }
1798 // .switch_range must be inside a comptime scope1990 // .switch_range must be inside a comptime scope
1799 const start_val = start.value().?;1991 const start_val = start.value().?;
1800 const end_val = end.value().?;1992 const end_val = end.value().?;
1801 if (start_val.compare(.gte, end_val)) {1993 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", .{});
1803 }1995 }
1804 return mod.constVoid(scope, inst.base.src);1996 return sema.mod.constVoid(block.arena, .unneeded);
1805}1997}
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 {
1808 const tracy = trace(@src());2005 const tracy = trace(@src());
1809 defer tracy.end();2006 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);
1812 const target = if (ref)2011 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)
1814 else2013 else
1815 target_ptr;2014 target_ptr;
1816 try validateSwitch(mod, scope, target, inst);2015 try validateSwitch(mod, scope, target, inst);
18172016
1818 if (try mod.resolveDefinedValue(scope, target)) |target_val| {2017 if (try mod.resolveDefinedValue(scope, target)) |target_val| {
1819 for (inst.positionals.cases) |case| {2018 for (inst.positionals.cases) |case| {
1820 const resolved = try resolveInst(mod, scope, case.item);2019 const resolved = sema.resolveInst(block, case.item);
1821 const casted = try mod.coerce(scope, target.ty, resolved);2020 const casted = try sema.coerce(scope, target.ty, resolved);
1822 const item = try mod.resolveConstValue(scope, casted);2021 const item = try sema.resolveConstValue(parent_block, case_src, casted);
18232022
1824 if (target_val.eql(item)) {2023 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);
1826 return mod.constNoReturn(scope, inst.base.src);2025 return mod.constNoReturn(scope, inst.base.src);
1827 }2026 }
1828 }2027 }
1829 try analyzeBody(mod, scope.cast(Scope.Block).?, inst.positionals.else_body);2028 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
1830 return mod.constNoReturn(scope, inst.base.src);2029 return mod.constNoReturn(scope, inst.base.src);
1831 }2030 }
18322031
1833 if (inst.positionals.cases.len == 0) {2032 if (inst.positionals.cases.len == 0) {
1834 // no cases just analyze else_branch2033 // 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);
1836 return mod.constNoReturn(scope, inst.base.src);2035 return mod.constNoReturn(scope, inst.base.src);
1837 }2036 }
18382037
1839 const parent_block = try mod.requireRuntimeBlock(scope, inst.base.src);2038 try sema.requireRuntimeBlock(parent_block, inst.base.src);
1840 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);2039 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);
18412040
1842 var case_block: Scope.Block = .{2041 var case_block: Scope.Block = .{
...@@ -1857,11 +2056,11 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)...@@ -1857,11 +2056,11 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)
1857 // Reset without freeing.2056 // Reset without freeing.
1858 case_block.instructions.items.len = 0;2057 case_block.instructions.items.len = 0;
18592058
1860 const resolved = try resolveInst(mod, scope, case.item);2059 const resolved = sema.resolveInst(block, case.item);
1861 const casted = try mod.coerce(scope, target.ty, resolved);2060 const casted = try sema.coerce(scope, target.ty, resolved);
1862 const item = try mod.resolveConstValue(scope, casted);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
1866 cases[i] = .{2065 cases[i] = .{
1867 .item = item,2066 .item = item,
...@@ -1870,7 +2069,7 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)...@@ -1870,7 +2069,7 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)
1870 }2069 }
18712070
1872 case_block.instructions.items.len = 0;2071 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
1875 const else_body: ir.Body = .{2074 const else_body: ir.Body = .{
1876 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),2075 .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)...@@ -1879,10 +2078,10 @@ fn zirSwitchBr(mod: *Module, scope: *Scope, inst: *zir.Inst.SwitchBr, ref: bool)
1879 return mod.addSwitchBr(parent_block, inst.base.src, target, cases, else_body);2078 return mod.addSwitchBr(parent_block, inst.base.src, target, cases, else_body);
1880}2079}
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 {
1883 // validate usage of '_' prongs2082 // validate usage of '_' prongs
1884 if (inst.positionals.special_prong == .underscore and target.ty.zigTypeTag() != .Enum) {2083 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", .{});
1886 // TODO notes "'_' prong here" inst.positionals.cases[last].src2085 // TODO notes "'_' prong here" inst.positionals.cases[last].src
1887 }2086 }
18882087
...@@ -1891,7 +2090,7 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw...@@ -1891,7 +2090,7 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
1891 switch (target.ty.zigTypeTag()) {2090 switch (target.ty.zigTypeTag()) {
1892 .Int, .ComptimeInt => {},2091 .Int, .ComptimeInt => {},
1893 else => {2092 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});
1895 // TODO notes "range used here" range_inst.src2094 // TODO notes "range used here" range_inst.src
1896 },2095 },
1897 }2096 }
...@@ -1899,34 +2098,34 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw...@@ -1899,34 +2098,34 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
18992098
1900 // validate for duplicate items/missing else prong2099 // validate for duplicate items/missing else prong
1901 switch (target.ty.zigTypeTag()) {2100 switch (target.ty.zigTypeTag()) {
1902 .Enum => return mod.fail(scope, inst.base.src, "TODO validateSwitch .Enum", .{}),2101 .Enum => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Enum", .{}),
1903 .ErrorSet => return mod.fail(scope, inst.base.src, "TODO validateSwitch .ErrorSet", .{}),2102 .ErrorSet => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .ErrorSet", .{}),
1904 .Union => return mod.fail(scope, inst.base.src, "TODO validateSwitch .Union", .{}),2103 .Union => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Union", .{}),
1905 .Int, .ComptimeInt => {2104 .Int, .ComptimeInt => {
1906 var range_set = @import("RangeSet.zig").init(mod.gpa);2105 var range_set = @import("RangeSet.zig").init(mod.gpa);
1907 defer range_set.deinit();2106 defer range_set.deinit();
19082107
1909 for (inst.positionals.items) |item| {2108 for (inst.positionals.items) |item| {
1910 const maybe_src = if (item.castTag(.switch_range)) |range| blk: {2109 const maybe_src = if (item.castTag(.switch_range)) |range| blk: {
1911 const start_resolved = try resolveInst(mod, scope, range.positionals.lhs);2110 const start_resolved = sema.resolveInst(block, range.positionals.lhs);
1912 const start_casted = try mod.coerce(scope, target.ty, start_resolved);2111 const start_casted = try sema.coerce(scope, target.ty, start_resolved);
1913 const end_resolved = try resolveInst(mod, scope, range.positionals.rhs);2112 const end_resolved = sema.resolveInst(block, range.positionals.rhs);
1914 const end_casted = try mod.coerce(scope, target.ty, end_resolved);2113 const end_casted = try sema.coerce(scope, target.ty, end_resolved);
19152114
1916 break :blk try range_set.add(2115 break :blk try range_set.add(
1917 try mod.resolveConstValue(scope, start_casted),2116 try sema.resolveConstValue(block, range_start_src, start_casted),
1918 try mod.resolveConstValue(scope, end_casted),2117 try sema.resolveConstValue(block, range_end_src, end_casted),
1919 item.src,2118 item.src,
1920 );2119 );
1921 } else blk: {2120 } else blk: {
1922 const resolved = try resolveInst(mod, scope, item);2121 const resolved = sema.resolveInst(block, item);
1923 const casted = try mod.coerce(scope, target.ty, resolved);2122 const casted = try sema.coerce(scope, target.ty, resolved);
1924 const value = try mod.resolveConstValue(scope, casted);2123 const value = try sema.resolveConstValue(block, item_src, casted);
1925 break :blk try range_set.add(value, value, item.src);2124 break :blk try range_set.add(value, value, item.src);
1926 };2125 };
19272126
1928 if (maybe_src) |previous_src| {2127 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", .{});
1930 // TODO notes "previous value is here" previous_src2129 // TODO notes "previous value is here" previous_src
1931 }2130 }
1932 }2131 }
...@@ -1939,54 +2138,54 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw...@@ -1939,54 +2138,54 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
1939 const end = try target.ty.maxInt(&arena, mod.getTarget());2138 const end = try target.ty.maxInt(&arena, mod.getTarget());
1940 if (try range_set.spans(start, end)) {2139 if (try range_set.spans(start, end)) {
1941 if (inst.positionals.special_prong == .@"else") {2140 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", .{});
1943 }2142 }
1944 return;2143 return;
1945 }2144 }
1946 }2145 }
19472146
1948 if (inst.positionals.special_prong != .@"else") {2147 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", .{});
1950 }2149 }
1951 },2150 },
1952 .Bool => {2151 .Bool => {
1953 var true_count: u8 = 0;2152 var true_count: u8 = 0;
1954 var false_count: u8 = 0;2153 var false_count: u8 = 0;
1955 for (inst.positionals.items) |item| {2154 for (inst.positionals.items) |item| {
1956 const resolved = try resolveInst(mod, scope, item);2155 const resolved = sema.resolveInst(block, item);
1957 const casted = try mod.coerce(scope, Type.initTag(.bool), resolved);2156 const casted = try sema.coerce(scope, Type.initTag(.bool), resolved);
1958 if ((try mod.resolveConstValue(scope, casted)).toBool()) {2157 if ((try sema.resolveConstValue(block, item_src, casted)).toBool()) {
1959 true_count += 1;2158 true_count += 1;
1960 } else {2159 } else {
1961 false_count += 1;2160 false_count += 1;
1962 }2161 }
19632162
1964 if (true_count + false_count > 2) {2163 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", .{});
1966 }2165 }
1967 }2166 }
1968 if ((true_count + false_count < 2) and inst.positionals.special_prong != .@"else") {2167 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", .{});
1970 }2169 }
1971 if ((true_count + false_count == 2) and inst.positionals.special_prong == .@"else") {2170 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", .{});
1973 }2172 }
1974 },2173 },
1975 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {2174 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
1976 if (inst.positionals.special_prong != .@"else") {2175 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});
1978 }2177 }
19792178
1980 var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa);2179 var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa);
1981 defer seen_values.deinit();2180 defer seen_values.deinit();
19822181
1983 for (inst.positionals.items) |item| {2182 for (inst.positionals.items) |item| {
1984 const resolved = try resolveInst(mod, scope, item);2183 const resolved = sema.resolveInst(block, item);
1985 const casted = try mod.coerce(scope, target.ty, resolved);2184 const casted = try sema.coerce(scope, target.ty, resolved);
1986 const val = try mod.resolveConstValue(scope, casted);2185 const val = try sema.resolveConstValue(block, item_src, casted);
19872186
1988 if (try seen_values.fetchPut(val, item.src)) |prev| {2187 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", .{});
1990 // TODO notes "previous value here" prev.value2189 // TODO notes "previous value here" prev.value
1991 }2190 }
1992 }2191 }
...@@ -2007,54 +2206,59 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw...@@ -2007,54 +2206,59 @@ fn validateSwitch(mod: *Module, scope: *Scope, target: *Inst, inst: *zir.Inst.Sw
2007 .ComptimeFloat,2206 .ComptimeFloat,
2008 .Float,2207 .Float,
2009 => {2208 => {
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});
2011 },2210 },
2012 }2211 }
2013}2212}
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 {
2016 const tracy = trace(@src());2215 const tracy = trace(@src());
2017 defer tracy.end();2216 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) {
2021 error.ImportOutsidePkgPath => {2224 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});
2023 },2226 },
2024 error.FileNotFound => {2227 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});
2026 },2229 },
2027 else => {2230 else => {
2028 // TODO: make sure this gets retried and not cached2231 // 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) });
2030 },2233 },
2031 };2234 };
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);
2033}2236}
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 {
2036 const tracy = trace(@src());2239 const tracy = trace(@src());
2037 defer tracy.end();2240 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", .{});
2039}2242}
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 {
2042 const tracy = trace(@src());2245 const tracy = trace(@src());
2043 defer tracy.end();2246 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", .{});
2045}2248}
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 {
2048 const tracy = trace(@src());2251 const tracy = trace(@src());
2049 defer tracy.end();2252 defer tracy.end();
20502253
2051 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);2254 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2052 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);2255 const lhs = sema.resolveInst(bin_inst.lhs);
2256 const rhs = sema.resolveInst(bin_inst.rhs);
20532257
2054 const instructions = &[_]*Inst{ lhs, rhs };2258 const instructions = &[_]*Inst{ lhs, rhs };
2055 const resolved_type = try mod.resolvePeerTypes(scope, instructions);2259 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2056 const casted_lhs = try mod.coerce(scope, resolved_type, lhs);2260 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2057 const casted_rhs = try mod.coerce(scope, resolved_type, rhs);2261 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
20582262
2059 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)2263 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
2060 resolved_type.elemType()2264 resolved_type.elemType()
...@@ -2065,14 +2269,14 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In...@@ -2065,14 +2269,14 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
20652269
2066 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {2270 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
2067 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {2271 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}", .{
2069 lhs.ty.arrayLen(),2273 lhs.ty.arrayLen(),
2070 rhs.ty.arrayLen(),2274 rhs.ty.arrayLen(),
2071 });2275 });
2072 }2276 }
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", .{});
2074 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {2278 } 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 '{}'", .{
2076 lhs.ty,2280 lhs.ty,
2077 rhs.ty,2281 rhs.ty,
2078 });2282 });
...@@ -2081,22 +2285,22 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In...@@ -2081,22 +2285,22 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
2081 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;2285 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
20822286
2083 if (!is_int) {2287 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()) });
2085 }2289 }
20862290
2087 if (casted_lhs.value()) |lhs_val| {2291 if (casted_lhs.value()) |lhs_val| {
2088 if (casted_rhs.value()) |rhs_val| {2292 if (casted_rhs.value()) |rhs_val| {
2089 if (lhs_val.isUndef() or rhs_val.isUndef()) {2293 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, .{
2091 .ty = resolved_type,2295 .ty = resolved_type,
2092 .val = Value.initTag(.undef),2296 .val = Value.initTag(.undef),
2093 });2297 });
2094 }2298 }
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", .{});
2096 }2300 }
2097 }2301 }
20982302
2099 const b = try mod.requireRuntimeBlock(scope, inst.base.src);2303 try sema.requireRuntimeBlock(block, inst.base.src);
2100 const ir_tag = switch (inst.base.tag) {2304 const ir_tag = switch (inst.base.tag) {
2101 .bit_and => Inst.Tag.bit_and,2305 .bit_and => Inst.Tag.bit_and,
2102 .bit_or => Inst.Tag.bit_or,2306 .bit_or => Inst.Tag.bit_or,
...@@ -2107,35 +2311,36 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In...@@ -2107,35 +2311,36 @@ fn zirBitwise(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!*In
2107 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);2311 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
2108}2312}
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 {
2111 const tracy = trace(@src());2315 const tracy = trace(@src());
2112 defer tracy.end();2316 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", .{});
2114}2318}
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 {
2117 const tracy = trace(@src());2321 const tracy = trace(@src());
2118 defer tracy.end();2322 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", .{});
2120}2324}
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 {
2123 const tracy = trace(@src());2327 const tracy = trace(@src());
2124 defer tracy.end();2328 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", .{});
2126}2330}
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 {
2129 const tracy = trace(@src());2333 const tracy = trace(@src());
2130 defer tracy.end();2334 defer tracy.end();
21312335
2132 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);2336 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2133 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);2337 const lhs = sema.resolveInst(bin_inst.lhs);
2338 const rhs = sema.resolveInst(bin_inst.rhs);
21342339
2135 const instructions = &[_]*Inst{ lhs, rhs };2340 const instructions = &[_]*Inst{ lhs, rhs };
2136 const resolved_type = try mod.resolvePeerTypes(scope, instructions);2341 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2137 const casted_lhs = try mod.coerce(scope, resolved_type, lhs);2342 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2138 const casted_rhs = try mod.coerce(scope, resolved_type, rhs);2343 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
21392344
2140 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)2345 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
2141 resolved_type.elemType()2346 resolved_type.elemType()
...@@ -2146,14 +2351,14 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!...@@ -2146,14 +2351,14 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
21462351
2147 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {2352 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
2148 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {2353 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}", .{
2150 lhs.ty.arrayLen(),2355 lhs.ty.arrayLen(),
2151 rhs.ty.arrayLen(),2356 rhs.ty.arrayLen(),
2152 });2357 });
2153 }2358 }
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", .{});
2155 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {2360 } 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 '{}'", .{
2157 lhs.ty,2362 lhs.ty,
2158 rhs.ty,2363 rhs.ty,
2159 });2364 });
...@@ -2163,13 +2368,13 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!...@@ -2163,13 +2368,13 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
2163 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;2368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
21642369
2165 if (!is_int and !(is_float and floatOpAllowed(inst.base.tag))) {2370 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()) });
2167 }2372 }
21682373
2169 if (casted_lhs.value()) |lhs_val| {2374 if (casted_lhs.value()) |lhs_val| {
2170 if (casted_rhs.value()) |rhs_val| {2375 if (casted_rhs.value()) |rhs_val| {
2171 if (lhs_val.isUndef() or rhs_val.isUndef()) {2376 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, .{
2173 .ty = resolved_type,2378 .ty = resolved_type,
2174 .val = Value.initTag(.undef),2379 .val = Value.initTag(.undef),
2175 });2380 });
...@@ -2178,7 +2383,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!...@@ -2178,7 +2383,7 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
2178 }2383 }
2179 }2384 }
21802385
2181 const b = try mod.requireRuntimeBlock(scope, inst.base.src);2386 try sema.requireRuntimeBlock(block, inst.base.src);
2182 const ir_tag: Inst.Tag = switch (inst.base.tag) {2387 const ir_tag: Inst.Tag = switch (inst.base.tag) {
2183 .add => .add,2388 .add => .add,
2184 .addwrap => .addwrap,2389 .addwrap => .addwrap,
...@@ -2186,18 +2391,18 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!...@@ -2186,18 +2391,18 @@ fn zirArithmetic(mod: *Module, scope: *Scope, inst: *zir.Inst.BinOp) InnerError!
2186 .subwrap => .subwrap,2391 .subwrap => .subwrap,
2187 .mul => .mul,2392 .mul => .mul,
2188 .mulwrap => .mulwrap,2393 .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)}),
2190 };2395 };
21912396
2192 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);2397 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
2193}2398}
21942399
2195/// Analyzes operands that are known at comptime2400/// 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 {
2197 // incase rhs is 0, simply return lhs without doing any calculations2402 // incase rhs is 0, simply return lhs without doing any calculations
2198 // TODO Once division is implemented we should throw an error when dividing by 0.2403 // TODO Once division is implemented we should throw an error when dividing by 0.
2199 if (rhs_val.compareWithZero(.eq)) {2404 if (rhs_val.compareWithZero(.eq)) {
2200 return mod.constInst(scope, inst.base.src, .{2405 return sema.mod.constInst(scope, inst.base.src, .{
2201 .ty = res_type,2406 .ty = res_type,
2202 .val = lhs_val,2407 .val = lhs_val,
2203 });2408 });
...@@ -2207,89 +2412,117 @@ fn analyzeInstComptimeOp(mod: *Module, scope: *Scope, res_type: Type, inst: *zir...@@ -2207,89 +2412,117 @@ fn analyzeInstComptimeOp(mod: *Module, scope: *Scope, res_type: Type, inst: *zir
2207 const value = switch (inst.base.tag) {2412 const value = switch (inst.base.tag) {
2208 .add => blk: {2413 .add => blk: {
2209 const val = if (is_int)2414 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)
2211 else2416 else
2212 try mod.floatAdd(scope, res_type, inst.base.src, lhs_val, rhs_val);2417 try mod.floatAdd(scope, res_type, inst.base.src, lhs_val, rhs_val);
2213 break :blk val;2418 break :blk val;
2214 },2419 },
2215 .sub => blk: {2420 .sub => blk: {
2216 const val = if (is_int)2421 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)
2218 else2423 else
2219 try mod.floatSub(scope, res_type, inst.base.src, lhs_val, rhs_val);2424 try mod.floatSub(scope, res_type, inst.base.src, lhs_val, rhs_val);
2220 break :blk val;2425 break :blk val;
2221 },2426 },
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)}),
2223 };2428 };
22242429
2225 log.debug("{s}({}, {}) result: {}", .{ @tagName(inst.base.tag), lhs_val, rhs_val, value });2430 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, .{
2228 .ty = res_type,2433 .ty = res_type,
2229 .val = value,2434 .val = value,
2230 });2435 });
2231}2436}
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 {
2234 const tracy = trace(@src());2439 const tracy = trace(@src());
2235 defer tracy.end();2440 defer tracy.end();
2236 const ptr = try resolveInst(mod, scope, deref.positionals.operand);2441
2237 return mod.analyzeDeref(scope, deref.base.src, ptr, deref.positionals.operand.src);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);
2238}2447}
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 {
2241 const tracy = trace(@src());2455 const tracy = trace(@src());
2242 defer tracy.end();2456 defer tracy.end();
22432457
2244 const return_type = try resolveType(mod, scope, assembly.positionals.return_type);2458 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2245 const asm_source = try resolveConstString(mod, scope, assembly.positionals.asm_source);2459 const src = inst_data.src();
2246 const output = if (assembly.kw_args.output) |o| try resolveConstString(mod, scope, o) else null;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();2476 const args = try block.arena.alloc(*Inst, extra.data.args.len);
2249 const inputs = try arena.alloc([]const u8, assembly.kw_args.inputs.len);2477 const inputs = try block.arena.alloc([]const u8, extra.data.args_len);
2250 const clobbers = try arena.alloc([]const u8, assembly.kw_args.clobbers.len);2478 const clobbers = try block.arena.alloc([]const u8, extra.data.clobbers_len);
2251 const args = try arena.alloc(*Inst, assembly.kw_args.args.len);
22522479
2253 for (inputs) |*elem, i| {2480 for (args) |*arg| {
2254 elem.* = try arena.dupe(u8, assembly.kw_args.inputs[i]);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);
2255 }2484 }
2256 for (clobbers) |*elem, i| {2485 for (inputs) |*name| {
2257 elem.* = try arena.dupe(u8, assembly.kw_args.clobbers[i]);2486 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2487 extra_i += 1;
2258 }2488 }
2259 for (args) |*elem, i| {2489 for (clobbers) |*name| {
2260 const arg = try resolveInst(mod, scope, assembly.kw_args.args[i]);2490 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2261 elem.* = try mod.coerce(scope, Type.initTag(.usize), arg);2491 extra_i += 1;
2262 }2492 }
22632493
2264 const b = try mod.requireRuntimeBlock(scope, assembly.base.src);2494 try sema.requireRuntimeBlock(block, src);
2265 const inst = try b.arena.create(Inst.Assembly);2495 const inst = try block.arena.create(Inst.Assembly);
2266 inst.* = .{2496 inst.* = .{
2267 .base = .{2497 .base = .{
2268 .tag = .assembly,2498 .tag = .assembly,
2269 .ty = return_type,2499 .ty = return_type,
2270 .src = assembly.base.src,2500 .src = src,
2271 },2501 },
2272 .asm_source = asm_source,2502 .asm_source = asm_source,
2273 .is_volatile = assembly.kw_args.@"volatile",2503 .is_volatile = is_volatile,
2274 .output = output,2504 .output = if (output) |o| o.inst else null,
2505 .output_name = if (output) |o| o.name else null,
2275 .inputs = inputs,2506 .inputs = inputs,
2276 .clobbers = clobbers,2507 .clobbers = clobbers,
2277 .args = args,2508 .args = args,
2278 };2509 };
2279 try b.instructions.append(mod.gpa, &inst.base);2510 try block.instructions.append(mod.gpa, &inst.base);
2280 return &inst.base;2511 return &inst.base;
2281}2512}
22822513
2283fn zirCmp(2514fn zirCmp(
2284 mod: *Module,2515 sema: *Sema,
2285 scope: *Scope,2516 block: *Scope.Block,
2286 inst: *zir.Inst.BinOp,2517 inst: zir.Inst.Index,
2287 op: std.math.CompareOperator,2518 op: std.math.CompareOperator,
2288) InnerError!*Inst {2519) InnerError!*Inst {
2289 const tracy = trace(@src());2520 const tracy = trace(@src());
2290 defer tracy.end();2521 defer tracy.end();
2291 const lhs = try resolveInst(mod, scope, inst.positionals.lhs);2522
2292 const rhs = try resolveInst(mod, scope, inst.positionals.rhs);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
2294 const is_equality_cmp = switch (op) {2527 const is_equality_cmp = switch (op) {
2295 .eq, .neq => true,2528 .eq, .neq => true,
...@@ -2299,37 +2532,37 @@ fn zirCmp(...@@ -2299,37 +2532,37 @@ fn zirCmp(
2299 const rhs_ty_tag = rhs.ty.zigTypeTag();2532 const rhs_ty_tag = rhs.ty.zigTypeTag();
2300 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {2533 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
2301 // null == null, null != null2534 // 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);
2303 } else if (is_equality_cmp and2536 } else if (is_equality_cmp and
2304 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or2537 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
2305 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))2538 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
2306 {2539 {
2307 // comparing null with optionals2540 // comparing null with optionals
2308 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;2541 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);
2310 } else if (is_equality_cmp and2543 } else if (is_equality_cmp and
2311 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))2544 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
2312 {2545 {
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", .{});
2314 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {2547 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
2315 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;2548 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});
2317 } else if (is_equality_cmp and2550 } else if (is_equality_cmp and
2318 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or2551 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
2319 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))2552 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
2320 {2553 {
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", .{});
2322 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {2555 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
2323 if (!is_equality_cmp) {2556 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)});
2325 }2558 }
2326 if (rhs.value()) |rval| {2559 if (rhs.value()) |rval| {
2327 if (lhs.value()) |lval| {2560 if (lhs.value()) |lval| {
2328 // 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 faster2561 // 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));
2330 }2563 }
2331 }2564 }
2332 const b = try mod.requireRuntimeBlock(scope, inst.base.src);2565 try sema.requireRuntimeBlock(block, inst.base.src);
2333 return mod.addBinOp(b, inst.base.src, Type.initTag(.bool), if (op == .eq) .cmp_eq else .cmp_neq, lhs, rhs);2566 return mod.addBinOp(b, inst.base.src, Type.initTag(.bool), if (op == .eq) .cmp_eq else .cmp_neq, lhs, rhs);
2334 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {2567 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {
2335 // This operation allows any combination of integer and float types, regardless of the2568 // This operation allows any combination of integer and float types, regardless of the
...@@ -2338,110 +2571,153 @@ fn zirCmp(...@@ -2338,110 +2571,153 @@ fn zirCmp(
2338 return mod.cmpNumeric(scope, inst.base.src, lhs, rhs, op);2571 return mod.cmpNumeric(scope, inst.base.src, lhs, rhs, op);
2339 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {2572 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
2340 if (!is_equality_cmp) {2573 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)});
2342 }2575 }
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));
2344 }2577 }
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", .{});
2346}2579}
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 {
2349 const tracy = trace(@src());2582 const tracy = trace(@src());
2350 defer tracy.end();2583 defer tracy.end();
2351 const operand = try resolveInst(mod, scope, inst.positionals.operand);2584
2352 return mod.constType(scope, inst.base.src, operand.ty);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);
2353}2588}
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 {
2356 const tracy = trace(@src());2591 const tracy = trace(@src());
2357 defer tracy.end();2592 defer tracy.end();
2358 var insts_to_res = try mod.gpa.alloc(*ir.Inst, inst.positionals.items.len);2593
2359 defer mod.gpa.free(insts_to_res);2594 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2360 for (inst.positionals.items) |item, i| {2595 const src = inst_data.src();
2361 insts_to_res[i] = try resolveInst(mod, scope, item);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 };
2362 }2607 }
2363 const pt_res = try mod.resolvePeerTypes(scope, insts_to_res);2608
2364 return mod.constType(scope, inst.base.src, pt_res);2609 const result_type = try sema.resolvePeerTypes(block, inst_list, src_list);
2610 return sema.mod.constType(block.arena, src, result_type);
2365}2611}
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 {
2368 const tracy = trace(@src());2614 const tracy = trace(@src());
2369 defer tracy.end();2615 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
2371 const bool_type = Type.initTag(.bool);2621 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);
2373 if (try mod.resolveDefinedValue(scope, operand)) |val| {2623 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());
2375 }2625 }
2376 const b = try mod.requireRuntimeBlock(scope, inst.base.src);2626 try sema.requireRuntimeBlock(block, src);
2377 return mod.addUnOp(b, inst.base.src, bool_type, .not, operand);2627 return block.addUnOp(src, bool_type, .not, operand);
2378}2628}
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 {
2381 const tracy = trace(@src());2636 const tracy = trace(@src());
2382 defer tracy.end();2637 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
2391 if (lhs.value()) |lhs_val| {2646 if (lhs.value()) |lhs_val| {
2392 if (rhs.value()) |rhs_val| {2647 if (rhs.value()) |rhs_val| {
2393 if (is_bool_or) {2648 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());
2395 } else {2650 } 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());
2397 }2652 }
2398 }2653 }
2399 }2654 }
2400 const b = try mod.requireRuntimeBlock(scope, inst.base.src);2655 try sema.requireRuntimeBlock(block, inst.base.src);
2401 return mod.addBinOp(b, inst.base.src, bool_type, if (is_bool_or) .bool_or else .bool_and, lhs, rhs);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);
2402}2658}
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 {
2405 const tracy = trace(@src());2666 const tracy = trace(@src());
2406 defer tracy.end();2667 defer tracy.end();
2407 const operand = try resolveInst(mod, scope, inst.positionals.operand);2668
2408 return mod.analyzeIsNull(scope, inst.base.src, operand, invert_logic);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);
2409}2673}
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 {
2412 const tracy = trace(@src());2681 const tracy = trace(@src());
2413 defer tracy.end();2682 defer tracy.end();
2414 const ptr = try resolveInst(mod, scope, inst.positionals.operand);2683
2415 const loaded = try mod.analyzeDeref(scope, inst.base.src, ptr, ptr.src);2684 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2416 return mod.analyzeIsNull(scope, inst.base.src, loaded, invert_logic);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);
2417}2689}
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 {
2420 const tracy = trace(@src());2692 const tracy = trace(@src());
2421 defer tracy.end();2693 defer tracy.end();
2422 const operand = try resolveInst(mod, scope, inst.positionals.operand);2694
2423 return mod.analyzeIsErr(scope, inst.base.src, operand);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);
2424}2698}
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 {
2427 const tracy = trace(@src());2701 const tracy = trace(@src());
2428 defer tracy.end();2702 defer tracy.end();
2429 const ptr = try resolveInst(mod, scope, inst.positionals.operand);2703
2430 const loaded = try mod.analyzeDeref(scope, inst.base.src, ptr, ptr.src);2704 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2431 return mod.analyzeIsErr(scope, inst.base.src, loaded);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);
2432}2709}
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 {
2435 const tracy = trace(@src());2712 const tracy = trace(@src());
2436 defer tracy.end();2713 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
2442 if (try mod.resolveDefinedValue(scope, cond)) |cond_val| {2718 if (try mod.resolveDefinedValue(scope, cond)) |cond_val| {
2443 const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body;2719 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.*);
2445 return mod.constNoReturn(scope, inst.base.src);2721 return mod.constNoReturn(scope, inst.base.src);
2446 }2722 }
24472723
...@@ -2458,7 +2734,7 @@ fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*In...@@ -2458,7 +2734,7 @@ fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*In
2458 .branch_quota = parent_block.branch_quota,2734 .branch_quota = parent_block.branch_quota,
2459 };2735 };
2460 defer true_block.instructions.deinit(mod.gpa);2736 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
2463 var false_block: Scope.Block = .{2739 var false_block: Scope.Block = .{
2464 .parent = parent_block,2740 .parent = parent_block,
...@@ -2473,68 +2749,37 @@ fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*In...@@ -2473,68 +2749,37 @@ fn zirCondbr(mod: *Module, scope: *Scope, inst: *zir.Inst.CondBr) InnerError!*In
2473 .branch_quota = parent_block.branch_quota,2749 .branch_quota = parent_block.branch_quota,
2474 };2750 };
2475 defer false_block.instructions.deinit(mod.gpa);2751 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) };2754 const then_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, true_block.instructions.items) };
2479 const else_body: ir.Body = .{ .instructions = try scope.arena().dupe(*Inst, false_block.instructions.items) };2755 const else_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, false_block.instructions.items) };
2480 return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body);2756 return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body);
2481}2757}
24822758
2483fn zirUnreachable(2759fn zirUnreachable(
2484 mod: *Module,2760 sema: *Sema,
2485 scope: *Scope,2761 block: *Scope.Block,
2486 unreach: *zir.Inst.NoOp,2762 zir_index: zir.Inst.Index,
2487 safety_check: bool,2763 safety_check: bool,
2488) InnerError!*Inst {2764) InnerError!*Inst {
2489 const tracy = trace(@src());2765 const tracy = trace(@src());
2490 defer tracy.end();2766 defer tracy.end();
2491 const b = try mod.requireRuntimeBlock(scope, unreach.base.src);2767
2768 try sema.requireRuntimeBlock(block, zir_index.base.src);
2492 // TODO Add compile error for @optimizeFor occurring too late in a scope.2769 // TODO Add compile error for @optimizeFor occurring too late in a scope.
2493 if (safety_check and mod.wantSafety(scope)) {2770 if (safety_check and block.wantSafety()) {
2494 return mod.safetyPanic(b, unreach.base.src, .unreach);2771 return mod.safetyPanic(b, zir_index.base.src, .unreach);
2495 } else {2772 } 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);
2497 }2774 }
2498}2775}
24992776
2500fn zirReturn(mod: *Module, scope: *Scope, inst: *zir.Inst.UnOp) InnerError!*Inst {2777fn zirRetTok(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2501 const tracy = trace(@src());2778 @compileError("TODO");
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);
2514}2779}
25152780
2516fn zirReturnVoid(mod: *Module, scope: *Scope, inst: *zir.Inst.NoOp) InnerError!*Inst {2781fn zirRetNode(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2517 const tracy = trace(@src());2782 @compileError("TODO");
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);
2538}2783}
25392784
2540fn floatOpAllowed(tag: zir.Inst.Tag) bool {2785fn floatOpAllowed(tag: zir.Inst.Tag) bool {
...@@ -2545,53 +2790,1080 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool {...@@ -2545,53 +2790,1080 @@ fn floatOpAllowed(tag: zir.Inst.Tag) bool {
2545 };2790 };
2546}2791}
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 {
2549 const tracy = trace(@src());2794 const tracy = trace(@src());
2550 defer tracy.end();2795 defer tracy.end();
2551 const elem_type = try resolveType(mod, scope, inst.positionals.operand);2796
2552 const ty = try mod.simplePtrType(scope, inst.base.src, elem_type, mutable, size);2797 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
2553 return mod.constType(scope, inst.base.src, ty);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);
2554}2812}
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 {
2557 const tracy = trace(@src());2815 const tracy = trace(@src());
2558 defer tracy.end();2816 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)2818 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
2574 return mod.fail(scope, inst.base.src, "bit offset starts after end of host integer", .{});2819 const extra = sema.code.extraData(zir.Inst.PtrType, inst_data.payload_index);
25752820
2576 const sentinel = if (inst.kw_args.sentinel) |some|2821 var extra_i = extra.end;
2577 (try resolveInstConst(mod, scope, some)).val2822
2578 else2823 const sentinel = if (inst_data.flags.has_sentinel) blk: {
2579 null;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
2583 const ty = try mod.ptrType(2852 const ty = try mod.ptrType(
2584 scope,2853 scope,
2585 inst.base.src,
2586 elem_type,2854 elem_type,
2587 sentinel,2855 sentinel,
2588 @"align",2856 abi_align,
2589 bit_offset,2857 bit_start,
2590 host_size,2858 bit_end,
2591 inst.kw_args.mutable,2859 inst_data.flags.is_mutable,
2592 inst.kw_args.@"allowzero",2860 inst_data.flags.is_allowzero,
2593 inst.kw_args.@"volatile",2861 inst_data.flags.is_volatile,
2594 inst.kw_args.size,2862 inst_data.size,
2595 );2863 );
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;
2597}3869}