authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-16 00:03:47-07:00
committergravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2021-03-16 00:04:17-07:00
log099af0e008162adf5cb7dc08946bd19b20db817b
tree56be882a2939f034f56f099023f1ff20af408d79
parentaef3e534f5bc59b2572afdb74178d8c8b3fa4481

stage2: rename zir_sema.zig to Sema.zig


4 files changed, 3871 insertions(+), 3871 deletions(-)

CMakeLists.txt+1-1
...@@ -583,7 +583,7 @@ set(ZIG_STAGE2_SOURCES...@@ -583,7 +583,7 @@ set(ZIG_STAGE2_SOURCES
583 "${CMAKE_SOURCE_DIR}/src/value.zig"583 "${CMAKE_SOURCE_DIR}/src/value.zig"
584 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"584 "${CMAKE_SOURCE_DIR}/src/windows_sdk.zig"
585 "${CMAKE_SOURCE_DIR}/src/zir.zig"585 "${CMAKE_SOURCE_DIR}/src/zir.zig"
586 "${CMAKE_SOURCE_DIR}/src/zir_sema.zig"586 "${CMAKE_SOURCE_DIR}/src/Sema.zig"
587)587)
588588
589if(MSVC)589if(MSVC)
src/Module.zig+1-1
...@@ -24,7 +24,7 @@ const ir = @import("ir.zig");...@@ -24,7 +24,7 @@ const ir = @import("ir.zig");
24const zir = @import("zir.zig");24const zir = @import("zir.zig");
25const trace = @import("tracy.zig").trace;25const trace = @import("tracy.zig").trace;
26const astgen = @import("astgen.zig");26const astgen = @import("astgen.zig");
27const Sema = @import("zir_sema.zig"); // TODO rename this file27const Sema = @import("Sema.zig");
28const target_util = @import("target.zig");28const target_util = @import("target.zig");
2929
30/// General-purpose allocator. Used for both temporary and long-term storage.30/// General-purpose allocator. Used for both temporary and long-term storage.
src/Sema.zig created+3869
...@@ -0,0 +1,3869 @@
1//! Semantic analysis of ZIR instructions.
2//! Shared to every Block. Stored on the stack.
3//! State used for compiling a `zir.Code` into TZIR.
4//! Transforms untyped ZIR instructions into semantically-analyzed TZIR instructions.
5//! Does type checking, comptime control flow, and safety-check generation.
6//! This is the the heart of the Zig compiler.
7
8mod: *Module,
9/// Same as `mod.gpa`.
10gpa: *Allocator,
11/// Points to the arena allocator of the Decl.
12arena: *Allocator,
13code: zir.Code,
14/// Maps ZIR to TZIR.
15inst_map: []*const Inst,
16/// When analyzing an inline function call, owner_decl is the Decl of the caller
17/// and `src_decl` of `Scope.Block` is the `Decl` of the callee.
18/// This `Decl` owns the arena memory of this `Sema`.
19owner_decl: *Decl,
20func: ?*Module.Fn,
21/// For now, TZIR requires arg instructions to be the first N instructions in the
22/// TZIR code. We store references here for the purpose of `resolveInst`.
23/// This can get reworked with TZIR memory layout changes, into simply:
24/// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function,
25/// > otherwise it is the number of parameters of the function.
26/// > param_count: u32
27param_inst_list: []const *ir.Inst,
28branch_quota: u32 = 1000,
29/// This field is updated when a new source location becomes active, so that
30/// instructions which do not have explicitly mapped source locations still have
31/// access to the source location set by the previous instruction which did
32/// contain a mapped source location.
33src: LazySrcLoc = .{ .token_offset = 0 },
34
35const std = @import("std");
36const mem = std.mem;
37const Allocator = std.mem.Allocator;
38const assert = std.debug.assert;
39const log = std.log.scoped(.sema);
40
41const Sema = @This();
42const Value = @import("value.zig").Value;
43const Type = @import("type.zig").Type;
44const TypedValue = @import("TypedValue.zig");
45const ir = @import("ir.zig");
46const zir = @import("zir.zig");
47const Module = @import("Module.zig");
48const Inst = ir.Inst;
49const Body = ir.Body;
50const trace = @import("tracy.zig").trace;
51const Scope = Module.Scope;
52const InnerError = Module.InnerError;
53const Decl = Module.Decl;
54const LazySrcLoc = Module.LazySrcLoc;
55
56// TODO when memory layout of TZIR is reworked, this can be simplified.
57const const_tzir_inst_list = blk: {
58 var result: [zir.const_inst_list.len]ir.Inst.Const = undefined;
59 for (result) |*tzir_const, i| {
60 tzir_const.* = .{
61 .base = .{
62 .tag = .constant,
63 .ty = zir.const_inst_list[i].ty,
64 .src = 0,
65 },
66 .val = zir.const_inst_list[i].val,
67 };
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);
75}
76
77pub fn rootAsType(
78 sema: *Sema,
79 root_block: *Scope.Block,
80 zir_result_inst: zir.Inst.Index,
81 body: zir.Body,
82) !Type {
83 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];
84 try sema.body(root_block, root_body);
85
86 const result_inst = sema.inst_map[zir_result_inst];
87 // Source location is unneeded because resolveConstValue must have already
88 // been successfully called when coercing the value to a type, from the
89 // result location.
90 const val = try sema.resolveConstValue(root_block, .unneeded, result_inst);
91 return val.toType(root_block.arena);
92}
93
94pub fn body(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !void {
95 const tracy = trace(@src());
96 defer tracy.end();
97
98 const map = block.sema.inst_map;
99 const tags = block.sema.code.instructions.items(.tag);
100
101 // TODO: As an optimization, look into making these switch prongs directly jump
102 // to the next one, rather than detouring through the loop condition.
103 // Also, look into leaving only the "noreturn" loop break condition, and removing
104 // the iteration based one. Better yet, have an extra entry in the tags array as a
105 // sentinel, so that exiting the loop is just another jump table prong.
106 // Related: https://github.com/ziglang/zig/issues/8220
107 for (body) |zir_inst| {
108 map[zir_inst] = switch (tags[zir_inst]) {
109 .alloc => try sema.zirAlloc(block, zir_inst),
110 .alloc_mut => try sema.zirAllocMut(block, zir_inst),
111 .alloc_inferred => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_const)),
112 .alloc_inferred_mut => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_mut)),
113 .bitcast_ref => try sema.zirBitcastRef(block, zir_inst),
114 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, zir_inst),
115 .block => try sema.zirBlock(block, zir_inst, false),
116 .block_comptime => try sema.zirBlock(block, zir_inst, true),
117 .block_flat => try sema.zirBlockFlat(block, zir_inst, false),
118 .block_comptime_flat => try sema.zirBlockFlat(block, zir_inst, true),
119 .@"break" => try sema.zirBreak(block, zir_inst),
120 .break_void_tok => try sema.zirBreakVoidTok(block, zir_inst),
121 .breakpoint => try sema.zirBreakpoint(block, zir_inst),
122 .call => try sema.zirCall(block, zir_inst, .auto),
123 .call_async_kw => try sema.zirCall(block, zir_inst, .async_kw),
124 .call_no_async => try sema.zirCall(block, zir_inst, .no_async),
125 .call_compile_time => try sema.zirCall(block, zir_inst, .compile_time),
126 .call_none => try sema.zirCallNone(block, zir_inst),
127 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, zir_inst),
128 .compile_error => try sema.zirCompileError(block, zir_inst),
129 .compile_log => try sema.zirCompileLog(block, zir_inst),
130 .@"const" => try sema.zirConst(block, zir_inst),
131 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),
132 .decl_ref => try sema.zirDeclRef(block, zir_inst),
133 .decl_val => try sema.zirDeclVal(block, zir_inst),
134 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),
135 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),
136 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, zir_inst),
137 .ref => try sema.zirRef(block, zir_inst),
138 .resolve_inferred_alloc => try sema.zirResolveInferredAlloc(block, zir_inst),
139 .ret_ptr => try sema.zirRetPtr(block, zir_inst),
140 .ret_type => try sema.zirRetType(block, zir_inst),
141 .store_to_block_ptr => try sema.zirStoreToBlockPtr(block, zir_inst),
142 .store_to_inferred_ptr => try sema.zirStoreToInferredPtr(block, zir_inst),
143 .ptr_type_simple => try sema.zirPtrTypeSimple(block, zir_inst),
144 .ptr_type => try sema.zirPtrType(block, zir_inst),
145 .store => try sema.zirStore(block, zir_inst),
146 .set_eval_branch_quota => try sema.zirSetEvalBranchQuota(block, zir_inst),
147 .str => try sema.zirStr(block, zir_inst),
148 .int => try sema.zirInt(block, zir_inst),
149 .int_type => try sema.zirIntType(block, zir_inst),
150 .loop => try sema.zirLoop(block, zir_inst),
151 .param_type => try sema.zirParamType(block, zir_inst),
152 .ptrtoint => try sema.zirPtrtoint(block, zir_inst),
153 .field_ptr => try sema.zirFieldPtr(block, zir_inst),
154 .field_val => try sema.zirFieldVal(block, zir_inst),
155 .field_ptr_named => try sema.zirFieldPtrNamed(block, zir_inst),
156 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),
157 .deref => try sema.zirDeref(block, zir_inst),
158 .as => try sema.zirAs(block, zir_inst),
159 .@"asm" => try sema.zirAsm(block, zir_inst, false),
160 .asm_volatile => try sema.zirAsm(block, zir_inst, true),
161 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
162 .unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),
163 .ret_tok => try sema.zirRetTok(block, zir_inst),
164 .ret_node => try sema.zirRetNode(block, zir_inst),
165 .fn_type => try sema.zirFnType(block, zir_inst),
166 .fn_type_cc => try sema.zirFnTypeCc(block, zir_inst),
167 .intcast => try sema.zirIntcast(block, zir_inst),
168 .bitcast => try sema.zirBitcast(block, zir_inst),
169 .floatcast => try sema.zirFloatcast(block, zir_inst),
170 .elem_ptr => try sema.zirElemPtr(block, zir_inst),
171 .elem_ptr_node => try sema.zirElemPtrNode(block, zir_inst),
172 .elem_val => try sema.zirElemVal(block, zir_inst),
173 .elem_val_node => try sema.zirElemValNode(block, zir_inst),
174 .add => try sema.zirArithmetic(block, zir_inst),
175 .addwrap => try sema.zirArithmetic(block, zir_inst),
176 .sub => try sema.zirArithmetic(block, zir_inst),
177 .subwrap => try sema.zirArithmetic(block, zir_inst),
178 .mul => try sema.zirArithmetic(block, zir_inst),
179 .mulwrap => try sema.zirArithmetic(block, zir_inst),
180 .div => try sema.zirArithmetic(block, zir_inst),
181 .mod_rem => try sema.zirArithmetic(block, zir_inst),
182 .array_cat => try sema.zirArrayCat(block, zir_inst),
183 .array_mul => try sema.zirArrayMul(block, zir_inst),
184 .bit_and => try sema.zirBitwise(block, zir_inst),
185 .bit_not => try sema.zirBitNot(block, zir_inst),
186 .bit_or => try sema.zirBitwise(block, zir_inst),
187 .xor => try sema.zirBitwise(block, zir_inst),
188 .shl => try sema.zirShl(block, zir_inst),
189 .shr => try sema.zirShr(block, zir_inst),
190 .cmp_lt => try sema.zirCmp(block, zir_inst, .lt),
191 .cmp_lte => try sema.zirCmp(block, zir_inst, .lte),
192 .cmp_eq => try sema.zirCmp(block, zir_inst, .eq),
193 .cmp_gte => try sema.zirCmp(block, zir_inst, .gte),
194 .cmp_gt => try sema.zirCmp(block, zir_inst, .gt),
195 .cmp_neq => try sema.zirCmp(block, zir_inst, .neq),
196 .condbr => try sema.zirCondbr(block, zir_inst),
197 .is_null => try sema.zirIsNull(block, zir_inst, false),
198 .is_non_null => try sema.zirIsNull(block, zir_inst, true),
199 .is_null_ptr => try sema.zirIsNullPtr(block, zir_inst, false),
200 .is_non_null_ptr => try sema.zirIsNullPtr(block, zir_inst, true),
201 .is_err => try sema.zirIsErr(block, zir_inst),
202 .is_err_ptr => try sema.zirIsErrPtr(block, zir_inst),
203 .bool_not => try sema.zirBoolNot(block, zir_inst),
204 .typeof => try sema.zirTypeof(block, zir_inst),
205 .typeof_peer => try sema.zirTypeofPeer(block, zir_inst),
206 .optional_type => try sema.zirOptionalType(block, zir_inst),
207 .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, zir_inst),
208 .optional_payload_safe => try sema.zirOptionalPayload(block, zir_inst, true),
209 .optional_payload_unsafe => try sema.zirOptionalPayload(block, zir_inst, false),
210 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, true),
211 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, false),
212 .err_union_payload_safe => try sema.zirErrUnionPayload(block, zir_inst, true),
213 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, zir_inst, false),
214 .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, true),
215 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, false),
216 .err_union_code => try sema.zirErrUnionCode(block, zir_inst),
217 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, zir_inst),
218 .ensure_err_payload_void => try sema.zirEnsureErrPayloadVoid(block, zir_inst),
219 .array_type => try sema.zirArrayType(block, zir_inst),
220 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, zir_inst),
221 .enum_literal => try sema.zirEnumLiteral(block, zir_inst),
222 .merge_error_sets => try sema.zirMergeErrorSets(block, zir_inst),
223 .error_union_type => try sema.zirErrorUnionType(block, zir_inst),
224 .anyframe_type => try sema.zirAnyframeType(block, zir_inst),
225 .error_set => try sema.zirErrorSet(block, zir_inst),
226 .error_value => try sema.zirErrorValue(block, zir_inst),
227 .slice_start => try sema.zirSliceStart(block, zir_inst),
228 .slice_end => try sema.zirSliceEnd(block, zir_inst),
229 .slice_sentinel => try sema.zirSliceSentinel(block, zir_inst),
230 .import => try sema.zirImport(block, zir_inst),
231 .bool_and => try sema.zirBoolOp(block, zir_inst, false),
232 .bool_or => try sema.zirBoolOp(block, zir_inst, true),
233 .void_value => try sema.mod.constVoid(block.arena, .unneeded),
234 .switchbr => try sema.zirSwitchBr(block, zir_inst, false),
235 .switchbr_ref => try sema.zirSwitchBr(block, zir_inst, true),
236 .switch_range => try sema.zirSwitchRange(block, zir_inst),
237 };
238 if (map[zir_inst].ty.isNoReturn()) {
239 break;
240 }
241 }
242}
243
244fn resolveInst(sema: *Sema, block: *Scope.Block, zir_ref: zir.Inst.Ref) *const ir.Inst {
245 var i = zir_ref;
246
247 // First section of indexes correspond to a set number of constant values.
248 if (i < const_tzir_inst_list.len) {
249 return &const_tzir_inst_list[i];
250 }
251 i -= const_tzir_inst_list.len;
252
253 // Next section of indexes correspond to function parameters, if any.
254 if (block.inlining) |inlining| {
255 if (i < inlining.casted_args.len) {
256 return inlining.casted_args[i];
257 }
258 i -= inlining.casted_args.len;
259 } else {
260 if (i < sema.param_inst_list.len) {
261 return sema.param_inst_list[i];
262 }
263 i -= sema.param_inst_list.len;
264 }
265
266 // Finally, the last section of indexes refers to the map of ZIR=>TZIR.
267 return sema.inst_map[i];
268}
269
270fn resolveConstString(
271 sema: *Sema,
272 block: *Scope.Block,
273 src: LazySrcLoc,
274 zir_ref: zir.Inst.Ref,
275) ![]u8 {
276 const tzir_inst = sema.resolveInst(block, zir_ref);
277 const wanted_type = Type.initTag(.const_slice_u8);
278 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
279 const val = try sema.resolveConstValue(block, src, coerced_inst);
280 return val.toAllocatedBytes(block.arena);
281}
282
283fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.Inst.Ref) !Type {
284 const tzir_inst = sema.resolveInt(block, zir_ref);
285 const wanted_type = Type.initTag(.@"type");
286 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
287 const val = try sema.resolveConstValue(block, src, coerced_inst);
288 return val.toType(sema.arena);
289}
290
291fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !Value {
292 return (try sema.resolveDefinedValue(block, src, base)) orelse
293 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
294}
295
296fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value {
297 if (base.value()) |val| {
298 if (val.isUndef()) {
299 return sema.mod.fail(&block.base, src, "use of undefined value here causes undefined behavior", .{});
300 }
301 return val;
302 }
303 return null;
304}
305
306/// Appropriate to call when the coercion has already been done by result
307/// location semantics. Asserts the value fits in the provided `Int` type.
308/// Only supports `Int` types 64 bits or less.
309fn resolveAlreadyCoercedInt(
310 sema: *Sema,
311 block: *Scope.Block,
312 src: LazySrcLoc,
313 zir_ref: zir.Inst.Ref,
314 comptime Int: type,
315) !Int {
316 comptime assert(@typeInfo(Int).Int.bits <= 64);
317 const tzir_inst = sema.resolveInst(block, zir_ref);
318 const val = try sema.resolveConstValue(block, src, tzir_inst);
319 switch (@typeInfo(Int).Int.signedness) {
320 .signed => return @intCast(Int, val.toSignedInt()),
321 .unsigned => return @intCast(Int, val.toUnsignedInt()),
322 }
323}
324
325fn resolveInt(
326 sema: *Sema,
327 block: *Scope.Block,
328 src: LazySrcLoc,
329 zir_ref: zir.Inst.Ref,
330 dest_type: Type,
331) !u64 {
332 const tzir_inst = sema.resolveInst(block, zir_ref);
333 const coerced = try sema.coerce(scope, dest_type, tzir_inst);
334 const val = try sema.resolveConstValue(block, src, coerced);
335
336 return val.toUnsignedInt();
337}
338
339fn resolveInstConst(
340 sema: *Sema,
341 block: *Scope.Block,
342 src: LazySrcLoc,
343 zir_ref: zir.Inst.Ref,
344) InnerError!TypedValue {
345 const tzir_inst = sema.resolveInst(block, zir_ref);
346 const val = try sema.resolveConstValue(block, src, tzir_inst);
347 return TypedValue{
348 .ty = tzir_inst.ty,
349 .val = val,
350 };
351}
352
353fn zirConst(sema: *Sema, block: *Scope.Block, const_inst: zir.Inst.Index) InnerError!*Inst {
354 const tracy = trace(@src());
355 defer tracy.end();
356 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
357 // after analysis.
358 const typed_value_copy = try const_inst.positionals.typed_value.copy(block.arena);
359 return sema.mod.constInst(scope, const_inst.base.src, typed_value_copy);
360}
361
362fn zirBitcastRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
363 const tracy = trace(@src());
364 defer tracy.end();
365 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zir_sema.zirBitcastRef", .{});
366}
367
368fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
369 const tracy = trace(@src());
370 defer tracy.end();
371 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zir_sema.zirBitcastResultPtr", .{});
372}
373
374fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
375 const tracy = trace(@src());
376 defer tracy.end();
377 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirCoerceResultPtr", .{});
378}
379
380fn zirRetPtr(sema: *Module, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
381 const tracy = trace(@src());
382 defer tracy.end();
383
384 try sema.requireFunctionBlock(block, inst.base.src);
385 const fn_ty = block.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
386 const ret_type = fn_ty.fnReturnType();
387 const ptr_type = try sema.mod.simplePtrType(block.arena, ret_type, true, .One);
388 return block.addNoOp(inst.base.src, ptr_type, .alloc);
389}
390
391fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
392 const tracy = trace(@src());
393 defer tracy.end();
394
395 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
396 const operand = sema.resolveInst(block, inst_data.operand);
397 return sema.analyzeRef(block, inst_data.src(), operand);
398}
399
400fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
401 const tracy = trace(@src());
402 defer tracy.end();
403 try sema.requireFunctionBlock(block, inst.base.src);
404 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
405 const ret_type = fn_ty.fnReturnType();
406 return sema.mod.constType(block.arena, inst.base.src, ret_type);
407}
408
409fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
410 const tracy = trace(@src());
411 defer tracy.end();
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();
416 switch (operand.ty.zigTypeTag()) {
417 .Void, .NoReturn => return sema.mod.constVoid(block.arena, .unneeded),
418 else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),
419 }
420}
421
422fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
423 const tracy = trace(@src());
424 defer tracy.end();
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();
429 switch (operand.ty.zigTypeTag()) {
430 .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),
431 else => return sema.mod.constVoid(block.arena, .unneeded),
432 }
433}
434
435fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
436 const tracy = trace(@src());
437 defer tracy.end();
438
439 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
440 const array_ptr = sema.resolveInst(block, inst_data.operand);
441
442 const elem_ty = array_ptr.ty.elemType();
443 if (!elem_ty.isIndexable()) {
444 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
445 const msg = msg: {
446 const msg = try sema.mod.errMsg(
447 &block.base,
448 cond_src,
449 "type '{}' does not support indexing",
450 .{elem_ty},
451 );
452 errdefer msg.destroy(mod.gpa);
453 try sema.mod.errNote(
454 &block.base,
455 cond_src,
456 msg,
457 "for loop operand must be an array, slice, tuple, or vector",
458 .{},
459 );
460 break :msg msg;
461 };
462 return mod.failWithOwnedErrorMsg(scope, msg);
463 }
464 const result_ptr = try sema.namedFieldPtr(block, inst.base.src, array_ptr, "len", inst.base.src);
465 return sema.analyzeDeref(block, inst.base.src, result_ptr, result_ptr.src);
466}
467
468fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
469 const tracy = trace(@src());
470 defer tracy.end();
471
472 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
473 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
474 const var_decl_src = inst_data.src();
475 const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
476 const ptr_type = try sema.mod.simplePtrType(block.arena, var_type, true, .One);
477 try sema.requireRuntimeBlock(block, var_decl_src);
478 return block.addNoOp(var_decl_src, ptr_type, .alloc);
479}
480
481fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
482 const tracy = trace(@src());
483 defer tracy.end();
484
485 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
486 const var_decl_src = inst_data.src();
487 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
488 const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
489 try sema.validateVarType(block, ty_src, var_type);
490 const ptr_type = try sema.mod.simplePtrType(block.arena, var_type, true, .One);
491 try sema.requireRuntimeBlock(block, var_decl_src);
492 return block.addNoOp(var_decl_src, ptr_type, .alloc);
493}
494
495fn zirAllocInferred(
496 sema: *Sema,
497 block: *Scope.Block,
498 inst: zir.Inst.Index,
499 inferred_alloc_ty: Type,
500) InnerError!*Inst {
501 const tracy = trace(@src());
502 defer tracy.end();
503 const val_payload = try block.arena.create(Value.Payload.InferredAlloc);
504 val_payload.* = .{
505 .data = .{},
506 };
507 // `Module.constInst` does not add the instruction to the block because it is
508 // not needed in the case of constant values. However here, we plan to "downgrade"
509 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
510 // to the block even though it is currently a `.constant`.
511 const result = try sema.mod.constInst(scope, inst.base.src, .{
512 .ty = inferred_alloc_ty,
513 .val = Value.initPayload(&val_payload.base),
514 });
515 try sema.requireFunctionBlock(block, inst.base.src);
516 try block.instructions.append(sema.gpa, result);
517 return result;
518}
519
520fn zirResolveInferredAlloc(
521 sema: *Sema,
522 block: *Scope.Block,
523 inst: zir.Inst.Index,
524) InnerError!*Inst {
525 const tracy = trace(@src());
526 defer tracy.end();
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);
531 const ptr_val = ptr.castTag(.constant).?.val;
532 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
533 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
534 const final_elem_ty = try sema.resolvePeerTypes(block, peer_inst_list);
535 const var_is_mut = switch (ptr.ty.tag()) {
536 .inferred_alloc_const => false,
537 .inferred_alloc_mut => true,
538 else => unreachable,
539 };
540 if (var_is_mut) {
541 try sema.validateVarType(block, ty_src, final_elem_ty);
542 }
543 const final_ptr_ty = try sema.mod.simplePtrType(block.arena, final_elem_ty, true, .One);
544
545 // Change it to a normal alloc.
546 ptr.ty = final_ptr_ty;
547 ptr.tag = .alloc;
548
549 return sema.mod.constVoid(block.arena, .unneeded);
550}
551
552fn zirStoreToBlockPtr(
553 sema: *Sema,
554 block: *Scope.Block,
555 inst: zir.Inst.Index,
556) InnerError!*Inst {
557 const tracy = trace(@src());
558 defer tracy.end();
559
560 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
561 const ptr = sema.resolveInst(bin_inst.lhs);
562 const value = sema.resolveInst(bin_inst.rhs);
563 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
564 // TODO detect when this store should be done at compile-time. For example,
565 // if expressions should force it when the condition is compile-time known.
566 try sema.requireRuntimeBlock(block, src);
567 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
568 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
569}
570
571fn zirStoreToInferredPtr(
572 sema: *Sema,
573 block: *Scope.Block,
574 inst: zir.Inst.Index,
575) InnerError!*Inst {
576 const tracy = trace(@src());
577 defer tracy.end();
578
579 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
580 const ptr = sema.resolveInst(bin_inst.lhs);
581 const value = sema.resolveInst(bin_inst.rhs);
582 const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;
583 // Add the stored instruction to the set we will use to resolve peer types
584 // for the inferred allocation.
585 try inferred_alloc.data.stored_inst_list.append(block.arena, value);
586 // Create a runtime bitcast instruction with exactly the type the pointer wants.
587 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
588 try sema.requireRuntimeBlock(block, src);
589 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
590 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
591}
592
593fn zirSetEvalBranchQuota(
594 sema: *Sema,
595 block: *Scope.Block,
596 inst: zir.Inst.Index,
597) InnerError!*Inst {
598 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
599 const src = inst_data.src();
600 try sema.requireFunctionBlock(block, src);
601 const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);
602 if (b.branch_quota.* < quota)
603 b.branch_quota.* = quota;
604 return sema.mod.constVoid(block.arena, .unneeded);
605}
606
607fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
608 const tracy = trace(@src());
609 defer tracy.end();
610
611 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
612 const ptr = sema.resolveInst(bin_inst.lhs);
613 const value = sema.resolveInst(bin_inst.rhs);
614 return mod.storePtr(scope, inst.base.src, ptr, value);
615}
616
617fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
618 const tracy = trace(@src());
619 defer tracy.end();
620
621 const inst_data = sema.code.instructions.items(.data)[inst].param_type;
622 const fn_inst = sema.resolveInst(inst_data.callee);
623 const param_index = inst_data.param_index;
624
625 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
626 .Fn => fn_inst.ty,
627 .BoundFn => {
628 return sema.mod.fail(&block.base, fn_inst.src, "TODO implement zirParamType for method call syntax", .{});
629 },
630 else => {
631 return sema.mod.fail(&block.base, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
632 },
633 };
634
635 const param_count = fn_ty.fnParamLen();
636 if (param_index >= param_count) {
637 if (fn_ty.fnIsVarArgs()) {
638 return sema.mod.constType(block.arena, inst.base.src, Type.initTag(.var_args_param));
639 }
640 return sema.mod.fail(&block.base, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
641 param_index,
642 fn_ty,
643 param_count,
644 });
645 }
646
647 // TODO support generic functions
648 const param_type = fn_ty.fnParamType(param_index);
649 return sema.mod.constType(block.arena, inst.base.src, param_type);
650}
651
652fn zirStr(sema: *Sema, block: *Scope.Block, str_inst: zir.Inst.Index) InnerError!*Inst {
653 const tracy = trace(@src());
654 defer tracy.end();
655
656 // The bytes references memory inside the ZIR module, which is fine. Multiple
657 // anonymous Decls may have strings which point to within the same ZIR module.
658 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
659
660 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
661 errdefer new_decl_arena.deinit();
662
663 const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
664 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes);
665
666 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
667 .ty = decl_ty,
668 .val = decl_val,
669 });
670 return sema.analyzeDeclRef(block, .unneeded, new_decl);
671}
672
673fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
674 const tracy = trace(@src());
675 defer tracy.end();
676
677 return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int);
678}
679
680fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
681 const tracy = trace(@src());
682 defer tracy.end();
683
684 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
685 const src = inst_data.src();
686 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
687 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand);
688 return sema.mod.fail(&block.base, src, "{s}", .{msg});
689}
690
691fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
692 var managed = mod.compile_log_text.toManaged(mod.gpa);
693 defer mod.compile_log_text = managed.moveToUnmanaged();
694 const writer = managed.writer();
695
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| {
699 if (i != 0) try writer.print(", ", .{});
700
701 const arg = sema.resolveInst(block, arg_ref);
702 if (arg.value()) |val| {
703 try writer.print("@as({}, {})", .{ arg.ty, val });
704 } else {
705 try writer.print("@as({}, [runtime value])", .{arg.ty});
706 }
707 }
708 try writer.print("\n", .{});
709
710 const gop = try mod.compile_log_decls.getOrPut(mod.gpa, scope.ownerDecl().?);
711 if (!gop.found_existing) {
712 gop.entry.value = .{
713 .file_scope = block.getFileScope(),
714 .lazy = inst_data.src(),
715 };
716 }
717 return sema.mod.constVoid(block.arena, .unneeded);
718}
719
720fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
721 const tracy = trace(@src());
722 defer tracy.end();
723
724 // Reserve space for a Loop instruction so that generated Break instructions can
725 // point to it, even if it doesn't end up getting used because the code ends up being
726 // comptime evaluated.
727 const loop_inst = try parent_block.arena.create(Inst.Loop);
728 loop_inst.* = .{
729 .base = .{
730 .tag = Inst.Loop.base_tag,
731 .ty = Type.initTag(.noreturn),
732 .src = inst.base.src,
733 },
734 .body = undefined,
735 };
736
737 var child_block: Scope.Block = .{
738 .parent = parent_block,
739 .inst_table = parent_block.inst_table,
740 .func = parent_block.func,
741 .owner_decl = parent_block.owner_decl,
742 .src_decl = parent_block.src_decl,
743 .instructions = .{},
744 .arena = parent_block.arena,
745 .inlining = parent_block.inlining,
746 .is_comptime = parent_block.is_comptime,
747 .branch_quota = parent_block.branch_quota,
748 };
749 defer child_block.instructions.deinit(mod.gpa);
750
751 try sema.body(&child_block, inst.positionals.body);
752
753 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
754
755 try parent_block.instructions.append(mod.gpa, &loop_inst.base);
756 loop_inst.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) };
757 return &loop_inst.base;
758}
759
760fn zirBlockFlat(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index, is_comptime: bool) InnerError!*Inst {
761 const tracy = trace(@src());
762 defer tracy.end();
763
764 var child_block = parent_block.makeSubBlock();
765 defer child_block.instructions.deinit(mod.gpa);
766 child_block.is_comptime = child_block.is_comptime or is_comptime;
767
768 try sema.body(&child_block, inst.positionals.body);
769
770 // Move the analyzed instructions into the parent block arena.
771 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
772 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
773
774 // The result of a flat block is the last instruction.
775 const zir_inst_list = inst.positionals.body.instructions;
776 const last_zir_inst = zir_inst_list[zir_inst_list.len - 1];
777 return sema.inst_map[last_zir_inst];
778}
779
780fn zirBlock(
781 sema: *Sema,
782 parent_block: *Scope.Block,
783 inst: zir.Inst.Index,
784 is_comptime: bool,
785) InnerError!*Inst {
786 const tracy = trace(@src());
787 defer tracy.end();
788
789 // Reserve space for a Block instruction so that generated Break instructions can
790 // point to it, even if it doesn't end up getting used because the code ends up being
791 // comptime evaluated.
792 const block_inst = try parent_block.arena.create(Inst.Block);
793 block_inst.* = .{
794 .base = .{
795 .tag = Inst.Block.base_tag,
796 .ty = undefined, // Set after analysis.
797 .src = inst.base.src,
798 },
799 .body = undefined,
800 };
801
802 var child_block: Scope.Block = .{
803 .parent = parent_block,
804 .inst_table = parent_block.inst_table,
805 .func = parent_block.func,
806 .owner_decl = parent_block.owner_decl,
807 .src_decl = parent_block.src_decl,
808 .instructions = .{},
809 .arena = parent_block.arena,
810 // TODO @as here is working around a stage1 miscompilation bug :(
811 .label = @as(?Scope.Block.Label, Scope.Block.Label{
812 .zir_block = inst,
813 .merges = .{
814 .results = .{},
815 .br_list = .{},
816 .block_inst = block_inst,
817 },
818 }),
819 .inlining = parent_block.inlining,
820 .is_comptime = is_comptime or parent_block.is_comptime,
821 .branch_quota = parent_block.branch_quota,
822 };
823 const merges = &child_block.label.?.merges;
824
825 defer child_block.instructions.deinit(mod.gpa);
826 defer merges.results.deinit(mod.gpa);
827 defer merges.br_list.deinit(mod.gpa);
828
829 try sema.body(&child_block, inst.positionals.body);
830
831 return analyzeBlockBody(mod, scope, &child_block, merges);
832}
833
834fn analyzeBlockBody(
835 sema: *Sema,
836 parent_block: *Scope.Block,
837 child_block: *Scope.Block,
838 merges: *Scope.Block.Merges,
839) InnerError!*Inst {
840 const tracy = trace(@src());
841 defer tracy.end();
842
843 // Blocks must terminate with noreturn instruction.
844 assert(child_block.instructions.items.len != 0);
845 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
846
847 if (merges.results.items.len == 0) {
848 // No need for a block instruction. We can put the new instructions
849 // directly into the parent block.
850 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
851 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
852 return copied_instructions[copied_instructions.len - 1];
853 }
854 if (merges.results.items.len == 1) {
855 const last_inst_index = child_block.instructions.items.len - 1;
856 const last_inst = child_block.instructions.items[last_inst_index];
857 if (last_inst.breakBlock()) |br_block| {
858 if (br_block == merges.block_inst) {
859 // No need for a block instruction. We can put the new instructions directly
860 // into the parent block. Here we omit the break instruction.
861 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]);
862 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
863 return merges.results.items[0];
864 }
865 }
866 }
867 // It is impossible to have the number of results be > 1 in a comptime scope.
868 assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
869
870 // Need to set the type and emit the Block instruction. This allows machine code generation
871 // to emit a jump instruction to after the block when it encounters the break.
872 try parent_block.instructions.append(mod.gpa, &merges.block_inst.base);
873 const resolved_ty = try sema.resolvePeerTypes(parent_block, merges.results.items);
874 merges.block_inst.base.ty = resolved_ty;
875 merges.block_inst.body = .{
876 .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items),
877 };
878 // Now that the block has its type resolved, we need to go back into all the break
879 // instructions, and insert type coercion on the operands.
880 for (merges.br_list.items) |br| {
881 if (br.operand.ty.eql(resolved_ty)) {
882 // No type coercion needed.
883 continue;
884 }
885 var coerce_block = parent_block.makeSubBlock();
886 defer coerce_block.instructions.deinit(mod.gpa);
887 const coerced_operand = try sema.coerce(&coerce_block.base, resolved_ty, br.operand);
888 // If no instructions were produced, such as in the case of a coercion of a
889 // constant value to a new type, we can simply point the br operand to it.
890 if (coerce_block.instructions.items.len == 0) {
891 br.operand = coerced_operand;
892 continue;
893 }
894 assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == coerced_operand);
895 // Here we depend on the br instruction having been over-allocated (if necessary)
896 // inide analyzeBreak so that it can be converted into a br_block_flat instruction.
897 const br_src = br.base.src;
898 const br_ty = br.base.ty;
899 const br_block_flat = @ptrCast(*Inst.BrBlockFlat, br);
900 br_block_flat.* = .{
901 .base = .{
902 .src = br_src,
903 .ty = br_ty,
904 .tag = .br_block_flat,
905 },
906 .block = merges.block_inst,
907 .body = .{
908 .instructions = try parent_block.arena.dupe(*Inst, coerce_block.instructions.items),
909 },
910 };
911 }
912 return &merges.block_inst.base;
913}
914
915fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
916 const tracy = trace(@src());
917 defer tracy.end();
918
919 try sema.requireRuntimeBlock(block, src);
920 return block.addNoOp(inst.base.src, Type.initTag(.void), .breakpoint);
921}
922
923fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
924 const tracy = trace(@src());
925 defer tracy.end();
926
927 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
928 const operand = sema.resolveInst(block, bin_inst.rhs);
929 const zir_block = bin_inst.lhs;
930 return analyzeBreak(mod, block, sema.src, zir_block, operand);
931}
932
933fn zirBreakVoidTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
934 const tracy = trace(@src());
935 defer tracy.end();
936
937 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
938 const zir_block = inst_data.operand;
939 const void_inst = try sema.mod.constVoid(block.arena, .unneeded);
940 return analyzeBreak(mod, block, inst_data.src(), zir_block, void_inst);
941}
942
943fn analyzeBreak(
944 sema: *Sema,
945 block: *Scope.Block,
946 src: LazySrcLoc,
947 zir_block: zir.Inst.Index,
948 operand: *Inst,
949) InnerError!*Inst {
950 var opt_block = scope.cast(Scope.Block);
951 while (opt_block) |block| {
952 if (block.label) |*label| {
953 if (label.zir_block == zir_block) {
954 try sema.requireFunctionBlock(block, src);
955 // Here we add a br instruction, but we over-allocate a little bit
956 // (if necessary) to make it possible to convert the instruction into
957 // a br_block_flat instruction later.
958 const br = @ptrCast(*Inst.Br, try b.arena.alignedAlloc(
959 u8,
960 Inst.convertable_br_align,
961 Inst.convertable_br_size,
962 ));
963 br.* = .{
964 .base = .{
965 .tag = .br,
966 .ty = Type.initTag(.noreturn),
967 .src = src,
968 },
969 .operand = operand,
970 .block = label.merges.block_inst,
971 };
972 try b.instructions.append(mod.gpa, &br.base);
973 try label.merges.results.append(mod.gpa, operand);
974 try label.merges.br_list.append(mod.gpa, br);
975 return &br.base;
976 }
977 }
978 opt_block = block.parent;
979 } else unreachable;
980}
981
982fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
983 const tracy = trace(@src());
984 defer tracy.end();
985
986 if (b.is_comptime) {
987 return sema.mod.constVoid(block.arena, .unneeded);
988 }
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);
993}
994
995fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
996 const tracy = trace(@src());
997 defer tracy.end();
998
999 const decl = sema.code.instructions.items(.data)[inst].decl;
1000 return sema.analyzeDeclRef(block, .unneeded, decl);
1001}
1002
1003fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1004 const tracy = trace(@src());
1005 defer tracy.end();
1006
1007 const decl = sema.code.instructions.items(.data)[inst].decl;
1008 return sema.analyzeDeclVal(block, .unneeded, decl);
1009}
1010
1011fn zirCallNone(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1012 const tracy = trace(@src());
1013 defer tracy.end();
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, &.{});
1019}
1020
1021fn zirCall(
1022 sema: *Sema,
1023 block: *Scope.Block,
1024 inst: zir.Inst.Index,
1025 modifier: std.builtin.CallOptions.Modifier,
1026) InnerError!*Inst {
1027 const tracy = trace(@src());
1028 defer tracy.end();
1029
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
1050 if (func.ty.zigTypeTag() != .Fn)
1051 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
1052
1053 const cc = func.ty.fnCallingConvention();
1054 if (cc == .Naked) {
1055 // TODO add error note: declared here
1056 return sema.mod.fail(
1057 &block.base,
1058 func_src,
1059 "unable to call function with naked calling convention",
1060 .{},
1061 );
1062 }
1063 const fn_params_len = func.ty.fnParamLen();
1064 if (func.ty.fnIsVarArgs()) {
1065 assert(cc == .C);
1066 if (zir_args.len < fn_params_len) {
1067 // TODO add error note: declared here
1068 return sema.mod.fail(
1069 &block.base,
1070 func_src,
1071 "expected at least {d} argument(s), found {d}",
1072 .{ fn_params_len, zir_args.len },
1073 );
1074 }
1075 } else if (fn_params_len != zir_args.len) {
1076 // TODO add error note: declared here
1077 return sema.mod.fail(
1078 &block.base,
1079 func_src,
1080 "expected {d} argument(s), found {d}",
1081 .{ fn_params_len, zir_args.len },
1082 );
1083 }
1084
1085 if (modifier == .compile_time) {
1086 return sema.mod.fail(&block.base, call_src, "TODO implement comptime function calls", .{});
1087 }
1088 if (modifier != .auto) {
1089 return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{inst.positionals.modifier});
1090 }
1091
1092 // TODO handle function calls of generic functions
1093 const casted_args = try block.arena.alloc(*Inst, zir_args.len);
1094 for (zir_args) |zir_arg, i| {
1095 // the args are already casted to the result of a param type instruction.
1096 casted_args[i] = sema.resolveInst(block, zir_arg);
1097 }
1098
1099 const ret_type = func.ty.fnReturnType();
1100
1101 try sema.requireFunctionBlock(block, call_src);
1102 const is_comptime_call = b.is_comptime or modifier == .compile_time;
1103 const is_inline_call = is_comptime_call or modifier == .always_inline or
1104 func.ty.fnCallingConvention() == .Inline;
1105 if (is_inline_call) {
1106 const func_val = try sema.resolveConstValue(block, func_src, func);
1107 const module_fn = switch (func_val.tag()) {
1108 .function => func_val.castTag(.function).?.data,
1109 .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{
1110 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
1111 }),
1112 else => unreachable,
1113 };
1114
1115 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
1116 // or an inlined call depending on what union tag the `label` field is
1117 // set to in the `Scope.Block`.
1118 // This block instruction will be used to capture the return value from the
1119 // inlined function.
1120 const block_inst = try block.arena.create(Inst.Block);
1121 block_inst.* = .{
1122 .base = .{
1123 .tag = Inst.Block.base_tag,
1124 .ty = ret_type,
1125 .src = call_src,
1126 },
1127 .body = undefined,
1128 };
1129 // If this is the top of the inline/comptime call stack, we use this data.
1130 // Otherwise we pass on the shared data from the parent scope.
1131 var shared_inlining: Scope.Block.Inlining.Shared = .{
1132 .branch_count = 0,
1133 .caller = b.func,
1134 };
1135 // This one is shared among sub-blocks within the same callee, but not
1136 // shared among the entire inline/comptime call stack.
1137 var inlining: Scope.Block.Inlining = .{
1138 .shared = if (b.inlining) |inlining| inlining.shared else &shared_inlining,
1139 .param_index = 0,
1140 .casted_args = casted_args,
1141 .merges = .{
1142 .results = .{},
1143 .br_list = .{},
1144 .block_inst = block_inst,
1145 },
1146 };
1147 var inst_table = Scope.Block.InstTable.init(mod.gpa);
1148 defer inst_table.deinit();
1149
1150 var child_block: Scope.Block = .{
1151 .parent = null,
1152 .inst_table = &inst_table,
1153 .func = module_fn,
1154 .owner_decl = scope.ownerDecl().?,
1155 .src_decl = module_fn.owner_decl,
1156 .instructions = .{},
1157 .arena = block.arena,
1158 .label = null,
1159 .inlining = &inlining,
1160 .is_comptime = is_comptime_call,
1161 .branch_quota = b.branch_quota,
1162 };
1163
1164 const merges = &child_block.inlining.?.merges;
1165
1166 defer child_block.instructions.deinit(mod.gpa);
1167 defer merges.results.deinit(mod.gpa);
1168 defer merges.br_list.deinit(mod.gpa);
1169
1170 try mod.emitBackwardBranch(&child_block, call_src);
1171
1172 // This will have return instructions analyzed as break instructions to
1173 // the block_inst above.
1174 try sema.body(&child_block, module_fn.zir);
1175
1176 return analyzeBlockBody(mod, scope, &child_block, merges);
1177 }
1178
1179 return block.addCall(call_src, ret_type, func, casted_args);
1180}
1181
1182fn zirIntType(sema: *Sema, block: *Scope.Block, inttype: zir.Inst.Index) InnerError!*Inst {
1183 const tracy = trace(@src());
1184 defer tracy.end();
1185 return sema.mod.fail(&block.base, inttype.base.src, "TODO implement inttype", .{});
1186}
1187
1188fn zirOptionalType(sema: *Sema, block: *Scope.Block, optional: zir.Inst.Index) InnerError!*Inst {
1189 const tracy = trace(@src());
1190 defer tracy.end();
1191
1192 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1193 const child_type = try sema.resolveType(block, inst_data.operand);
1194 const opt_type = try mod.optionalType(block.arena, child_type);
1195
1196 return sema.mod.constType(block.arena, inst_data.src(), opt_type);
1197}
1198
1199fn zirOptionalTypeFromPtrElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1200 const tracy = trace(@src());
1201 defer tracy.end();
1202
1203 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1204 const ptr = sema.resolveInst(block, inst_data.operand);
1205 const elem_ty = ptr.ty.elemType();
1206 const opt_ty = try mod.optionalType(block.arena, elem_ty);
1207
1208 return sema.mod.constType(block.arena, inst_data.src(), opt_ty);
1209}
1210
1211fn zirArrayType(sema: *Sema, block: *Scope.Block, array: zir.Inst.Index) InnerError!*Inst {
1212 const tracy = trace(@src());
1213 defer tracy.end();
1214 // TODO these should be lazily evaluated
1215 const len = try resolveInstConst(mod, scope, array.positionals.lhs);
1216 const elem_type = try sema.resolveType(block, array.positionals.rhs);
1217
1218 return sema.mod.constType(block.arena, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
1219}
1220
1221fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, array: zir.Inst.Index) InnerError!*Inst {
1222 const tracy = trace(@src());
1223 defer tracy.end();
1224 // TODO these should be lazily evaluated
1225 const len = try resolveInstConst(mod, scope, array.positionals.len);
1226 const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
1227 const elem_type = try sema.resolveType(block, array.positionals.elem_type);
1228
1229 return sema.mod.constType(block.arena, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
1230}
1231
1232fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1233 const tracy = trace(@src());
1234 defer tracy.end();
1235
1236 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1237 const error_union = try sema.resolveType(block, bin_inst.lhs);
1238 const payload = try sema.resolveType(block, bin_inst.rhs);
1239
1240 if (error_union.zigTypeTag() != .ErrorSet) {
1241 return sema.mod.fail(&block.base, inst.base.src, "expected error set type, found {}", .{error_union.elemType()});
1242 }
1243
1244 return sema.mod.constType(block.arena, inst.base.src, try mod.errorUnionType(scope, error_union, payload));
1245}
1246
1247fn zirAnyframeType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1248 const tracy = trace(@src());
1249 defer tracy.end();
1250
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);
1258}
1259
1260fn zirErrorSet(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1261 const tracy = trace(@src());
1262 defer tracy.end();
1263
1264 // The owner Decl arena will store the hashmap.
1265 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1266 errdefer new_decl_arena.deinit();
1267
1268 const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
1269 payload.* = .{
1270 .base = .{ .tag = .error_set },
1271 .data = .{
1272 .fields = .{},
1273 .decl = undefined, // populated below
1274 },
1275 };
1276 try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len));
1277
1278 for (inst.positionals.fields) |field_name| {
1279 const entry = try mod.getErrorValue(field_name);
1280 if (payload.data.fields.fetchPutAssumeCapacity(entry.key, {})) |_| {
1281 return sema.mod.fail(&block.base, inst.base.src, "duplicate error: '{s}'", .{field_name});
1282 }
1283 }
1284 // TODO create name in format "error:line:column"
1285 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1286 .ty = Type.initTag(.type),
1287 .val = Value.initPayload(&payload.base),
1288 });
1289 payload.data.decl = new_decl;
1290 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1291}
1292
1293fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1294 const tracy = trace(@src());
1295 defer tracy.end();
1296
1297 // Create an anonymous error set type with only this error value, and return the value.
1298 const entry = try mod.getErrorValue(inst.positionals.name);
1299 const result_type = try Type.Tag.error_set_single.create(block.arena, entry.key);
1300 return sema.mod.constInst(scope, inst.base.src, .{
1301 .ty = result_type,
1302 .val = try Value.Tag.@"error".create(block.arena, .{
1303 .name = entry.key,
1304 }),
1305 });
1306}
1307
1308fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1309 const tracy = trace(@src());
1310 defer tracy.end();
1311
1312 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1313 const lhs_ty = try sema.resolveType(block, bin_inst.lhs);
1314 const rhs_ty = try sema.resolveType(block, bin_inst.rhs);
1315 if (rhs_ty.zigTypeTag() != .ErrorSet)
1316 return sema.mod.fail(&block.base, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
1317 if (lhs_ty.zigTypeTag() != .ErrorSet)
1318 return sema.mod.fail(&block.base, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
1319
1320 // anything merged with anyerror is anyerror
1321 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)
1322 return sema.mod.constInst(scope, inst.base.src, .{
1323 .ty = Type.initTag(.type),
1324 .val = Value.initTag(.anyerror_type),
1325 });
1326 // The declarations arena will store the hashmap.
1327 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1328 errdefer new_decl_arena.deinit();
1329
1330 const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
1331 payload.* = .{
1332 .base = .{ .tag = .error_set },
1333 .data = .{
1334 .fields = .{},
1335 .decl = undefined, // populated below
1336 },
1337 };
1338 try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, switch (rhs_ty.tag()) {
1339 .error_set_single => 1,
1340 .error_set => rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1341 else => unreachable,
1342 } + switch (lhs_ty.tag()) {
1343 .error_set_single => 1,
1344 .error_set => lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1345 else => unreachable,
1346 }));
1347
1348 switch (lhs_ty.tag()) {
1349 .error_set_single => {
1350 const name = lhs_ty.castTag(.error_set_single).?.data;
1351 payload.data.fields.putAssumeCapacity(name, {});
1352 },
1353 .error_set => {
1354 var multiple = lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1355 var it = multiple.iterator();
1356 while (it.next()) |entry| {
1357 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1358 }
1359 },
1360 else => unreachable,
1361 }
1362
1363 switch (rhs_ty.tag()) {
1364 .error_set_single => {
1365 const name = rhs_ty.castTag(.error_set_single).?.data;
1366 payload.data.fields.putAssumeCapacity(name, {});
1367 },
1368 .error_set => {
1369 var multiple = rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1370 var it = multiple.iterator();
1371 while (it.next()) |entry| {
1372 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1373 }
1374 },
1375 else => unreachable,
1376 }
1377 // TODO create name in format "error:line:column"
1378 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1379 .ty = Type.initTag(.type),
1380 .val = Value.initPayload(&payload.base),
1381 });
1382 payload.data.decl = new_decl;
1383
1384 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1385}
1386
1387fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
1388 const tracy = trace(@src());
1389 defer tracy.end();
1390
1391 const duped_name = try block.arena.dupe(u8, inst.positionals.name);
1392 return sema.mod.constInst(scope, inst.base.src, .{
1393 .ty = Type.initTag(.enum_literal),
1394 .val = try Value.Tag.enum_literal.create(block.arena, duped_name),
1395 });
1396}
1397
1398/// Pointer in, pointer out.
1399fn zirOptionalPayloadPtr(
1400 sema: *Sema,
1401 block: *Scope.Block,
1402 inst: zir.Inst.Index,
1403 safety_check: bool,
1404) InnerError!*Inst {
1405 const tracy = trace(@src());
1406 defer tracy.end();
1407
1408 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1409 const optional_ptr = sema.resolveInst(block, inst_data.operand);
1410 assert(optional_ptr.ty.zigTypeTag() == .Pointer);
1411 const src = inst_data.src();
1412
1413 const opt_type = optional_ptr.ty.elemType();
1414 if (opt_type.zigTypeTag() != .Optional) {
1415 return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
1416 }
1417
1418 const child_type = try opt_type.optionalChildAlloc(block.arena);
1419 const child_pointer = try sema.mod.simplePtrType(block.arena, child_type, !optional_ptr.ty.isConstPtr(), .One);
1420
1421 if (optional_ptr.value()) |pointer_val| {
1422 const val = try pointer_val.pointerDeref(block.arena);
1423 if (val.isNull()) {
1424 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
1425 }
1426 // The same Value represents the pointer to the optional and the payload.
1427 return sema.mod.constInst(scope, src, .{
1428 .ty = child_pointer,
1429 .val = pointer_val,
1430 });
1431 }
1432
1433 try sema.requireRuntimeBlock(block, src);
1434 if (safety_check and block.wantSafety()) {
1435 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);
1436 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
1437 }
1438 return block.addUnOp(src, child_pointer, .optional_payload_ptr, optional_ptr);
1439}
1440
1441/// Value in, value out.
1442fn zirOptionalPayload(
1443 sema: *Sema,
1444 block: *Scope.Block,
1445 inst: zir.Inst.Index,
1446 safety_check: bool,
1447) InnerError!*Inst {
1448 const tracy = trace(@src());
1449 defer tracy.end();
1450
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);
1454 const opt_type = operand.ty;
1455 if (opt_type.zigTypeTag() != .Optional) {
1456 return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
1457 }
1458
1459 const child_type = try opt_type.optionalChildAlloc(block.arena);
1460
1461 if (operand.value()) |val| {
1462 if (val.isNull()) {
1463 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
1464 }
1465 return sema.mod.constInst(scope, src, .{
1466 .ty = child_type,
1467 .val = val,
1468 });
1469 }
1470
1471 try sema.requireRuntimeBlock(block, src);
1472 if (safety_check and block.wantSafety()) {
1473 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null, operand);
1474 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
1475 }
1476 return block.addUnOp(src, child_type, .optional_payload, operand);
1477}
1478
1479/// Value in, value out
1480fn zirErrUnionPayload(
1481 sema: *Sema,
1482 block: *Scope.Block,
1483 inst: zir.Inst.Index,
1484 safety_check: bool,
1485) InnerError!*Inst {
1486 const tracy = trace(@src());
1487 defer tracy.end();
1488
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);
1492 if (operand.ty.zigTypeTag() != .ErrorUnion)
1493 return sema.mod.fail(&block.base, operand.src, "expected error union type, found '{}'", .{operand.ty});
1494
1495 if (operand.value()) |val| {
1496 if (val.getError()) |name| {
1497 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
1498 }
1499 const data = val.castTag(.error_union).?.data;
1500 return sema.mod.constInst(scope, src, .{
1501 .ty = operand.ty.castTag(.error_union).?.data.payload,
1502 .val = data,
1503 });
1504 }
1505 try sema.requireRuntimeBlock(block, src);
1506 if (safety_check and block.wantSafety()) {
1507 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
1508 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
1509 }
1510 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_payload, operand);
1511}
1512
1513/// Pointer in, pointer out.
1514fn zirErrUnionPayloadPtr(
1515 sema: *Sema,
1516 block: *Scope.Block,
1517 inst: zir.Inst.Index,
1518 safety_check: bool,
1519) InnerError!*Inst {
1520 const tracy = trace(@src());
1521 defer tracy.end();
1522
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);
1526 assert(operand.ty.zigTypeTag() == .Pointer);
1527
1528 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
1529 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
1530
1531 const operand_pointer_ty = try sema.mod.simplePtrType(block.arena, operand.ty.elemType().castTag(.error_union).?.data.payload, !operand.ty.isConstPtr(), .One);
1532
1533 if (operand.value()) |pointer_val| {
1534 const val = try pointer_val.pointerDeref(block.arena);
1535 if (val.getError()) |name| {
1536 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
1537 }
1538 const data = val.castTag(.error_union).?.data;
1539 // The same Value represents the pointer to the error union and the payload.
1540 return sema.mod.constInst(scope, src, .{
1541 .ty = operand_pointer_ty,
1542 .val = try Value.Tag.ref_val.create(
1543 block.arena,
1544 data,
1545 ),
1546 });
1547 }
1548
1549 try sema.requireRuntimeBlock(block, src);
1550 if (safety_check and block.wantSafety()) {
1551 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
1552 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
1553 }
1554 return block.addUnOp(src, operand_pointer_ty, .unwrap_errunion_payload_ptr, operand);
1555}
1556
1557/// Value in, value out
1558fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1559 const tracy = trace(@src());
1560 defer tracy.end();
1561
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);
1565 if (operand.ty.zigTypeTag() != .ErrorUnion)
1566 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
1567
1568 if (operand.value()) |val| {
1569 assert(val.getError() != null);
1570 const data = val.castTag(.error_union).?.data;
1571 return sema.mod.constInst(scope, src, .{
1572 .ty = operand.ty.castTag(.error_union).?.data.error_set,
1573 .val = data,
1574 });
1575 }
1576
1577 try sema.requireRuntimeBlock(block, src);
1578 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);
1579}
1580
1581/// Pointer in, value out
1582fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1583 const tracy = trace(@src());
1584 defer tracy.end();
1585
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);
1589 assert(operand.ty.zigTypeTag() == .Pointer);
1590
1591 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
1592 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
1593
1594 if (operand.value()) |pointer_val| {
1595 const val = try pointer_val.pointerDeref(block.arena);
1596 assert(val.getError() != null);
1597 const data = val.castTag(.error_union).?.data;
1598 return sema.mod.constInst(scope, src, .{
1599 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,
1600 .val = data,
1601 });
1602 }
1603
1604 try sema.requireRuntimeBlock(block, src);
1605 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
1606}
1607
1608fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1609 const tracy = trace(@src());
1610 defer tracy.end();
1611
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);
1615 if (operand.ty.zigTypeTag() != .ErrorUnion)
1616 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
1617 if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {
1618 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});
1619 }
1620 return sema.mod.constVoid(block.arena, .unneeded);
1621}
1622
1623fn zirFnType(sema: *Sema, block: *Scope.Block, fntype: zir.Inst.Index, var_args: bool) InnerError!*Inst {
1624 const tracy = trace(@src());
1625 defer tracy.end();
1626
1627 return fnTypeCommon(
1628 mod,
1629 scope,
1630 &fntype.base,
1631 fntype.positionals.param_types,
1632 fntype.positionals.return_type,
1633 .Unspecified,
1634 var_args,
1635 );
1636}
1637
1638fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, fntype: zir.Inst.Index, var_args: bool) InnerError!*Inst {
1639 const tracy = trace(@src());
1640 defer tracy.end();
1641
1642 const cc_tv = try resolveInstConst(mod, scope, fntype.positionals.cc);
1643 // TODO once we're capable of importing and analyzing decls from
1644 // std.builtin, this needs to change
1645 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
1646 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
1647 return sema.mod.fail(&block.base, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str});
1648 return fnTypeCommon(
1649 mod,
1650 scope,
1651 &fntype.base,
1652 fntype.positionals.param_types,
1653 fntype.positionals.return_type,
1654 cc,
1655 var_args,
1656 );
1657}
1658
1659fn fnTypeCommon(
1660 sema: *Sema,
1661 block: *Scope.Block,
1662 zir_inst: zir.Inst.Index,
1663 zir_param_types: []zir.Inst.Index,
1664 zir_return_type: zir.Inst.Index,
1665 cc: std.builtin.CallingConvention,
1666 var_args: bool,
1667) InnerError!*Inst {
1668 const return_type = try sema.resolveType(block, zir_return_type);
1669
1670 // Hot path for some common function types.
1671 if (zir_param_types.len == 0 and !var_args) {
1672 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
1673 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
1674 }
1675
1676 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {
1677 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_void_no_args));
1678 }
1679
1680 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
1681 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_naked_noreturn_no_args));
1682 }
1683
1684 if (return_type.zigTypeTag() == .Void and cc == .C) {
1685 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_ccc_void_no_args));
1686 }
1687 }
1688
1689 const param_types = try block.arena.alloc(Type, zir_param_types.len);
1690 for (zir_param_types) |param_type, i| {
1691 const resolved = try sema.resolveType(block, param_type);
1692 // TODO skip for comptime params
1693 if (!resolved.isValidVarType(false)) {
1694 return sema.mod.fail(&block.base, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
1695 }
1696 param_types[i] = resolved;
1697 }
1698
1699 const fn_ty = try Type.Tag.function.create(block.arena, .{
1700 .param_types = param_types,
1701 .return_type = return_type,
1702 .cc = cc,
1703 .is_var_args = var_args,
1704 });
1705 return sema.mod.constType(block.arena, zir_inst.src, fn_ty);
1706}
1707
1708fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1709 const tracy = trace(@src());
1710 defer tracy.end();
1711
1712 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1713 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1714 const tzir_inst = sema.resolveInst(block, bin_inst.rhs);
1715 return sema.coerce(scope, dest_type, tzir_inst);
1716}
1717
1718fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1719 const tracy = trace(@src());
1720 defer tracy.end();
1721
1722 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1723 const ptr = sema.resolveInst(block, inst_data.operand);
1724 if (ptr.ty.zigTypeTag() != .Pointer) {
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});
1727 }
1728 // TODO handle known-pointer-address
1729 const src = inst_data.src();
1730 try sema.requireRuntimeBlock(block, src);
1731 const ty = Type.initTag(.usize);
1732 return block.addUnOp(src, ty, .ptrtoint, ptr);
1733}
1734
1735fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1736 const tracy = trace(@src());
1737 defer tracy.end();
1738
1739 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1740 const src = inst_data.src();
1741 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1742 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1743 const field_name = sema.code.string_bytes[extra.field_name_start..][0..extra.field_name_len];
1744 const object = sema.resolveInst(block, extra.lhs);
1745 const object_ptr = try sema.analyzeRef(block, src, object);
1746 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1747 return sema.analyzeDeref(block, src, result_ptr, result_ptr.src);
1748}
1749
1750fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1751 const tracy = trace(@src());
1752 defer tracy.end();
1753
1754 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1755 const src = inst_data.src();
1756 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1757 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1758 const field_name = sema.code.string_bytes[extra.field_name_start..][0..extra.field_name_len];
1759 const object_ptr = sema.resolveInst(block, extra.lhs);
1760 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1761}
1762
1763fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1764 const tracy = trace(@src());
1765 defer tracy.end();
1766
1767 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1768 const src = inst_data.src();
1769 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1770 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1771 const object = sema.resolveInst(block, extra.lhs);
1772 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
1773 const object_ptr = try sema.analyzeRef(block, src, object);
1774 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1775 return sema.analyzeDeref(block, src, result_ptr, src);
1776}
1777
1778fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1779 const tracy = trace(@src());
1780 defer tracy.end();
1781
1782 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1783 const src = inst_data.src();
1784 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1785 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1786 const object_ptr = sema.resolveInst(block, extra.lhs);
1787 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
1788 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1789}
1790
1791fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1792 const tracy = trace(@src());
1793 defer tracy.end();
1794
1795 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1796 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1797 const operand = sema.resolveInst(bin_inst.rhs);
1798
1799 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
1800 .ComptimeInt => true,
1801 .Int => false,
1802 else => return mod.fail(
1803 scope,
1804 inst.positionals.lhs.src,
1805 "expected integer type, found '{}'",
1806 .{
1807 dest_type,
1808 },
1809 ),
1810 };
1811
1812 switch (operand.ty.zigTypeTag()) {
1813 .ComptimeInt, .Int => {},
1814 else => return mod.fail(
1815 scope,
1816 inst.positionals.rhs.src,
1817 "expected integer type, found '{}'",
1818 .{operand.ty},
1819 ),
1820 }
1821
1822 if (operand.value() != null) {
1823 return sema.coerce(scope, dest_type, operand);
1824 } else if (dest_is_comptime_int) {
1825 return sema.mod.fail(&block.base, inst.base.src, "unable to cast runtime value to 'comptime_int'", .{});
1826 }
1827
1828 return sema.mod.fail(&block.base, inst.base.src, "TODO implement analyze widen or shorten int", .{});
1829}
1830
1831fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1832 const tracy = trace(@src());
1833 defer tracy.end();
1834
1835 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1836 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1837 const operand = sema.resolveInst(bin_inst.rhs);
1838 return mod.bitcast(scope, dest_type, operand);
1839}
1840
1841fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1842 const tracy = trace(@src());
1843 defer tracy.end();
1844
1845 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1846 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1847 const operand = sema.resolveInst(bin_inst.rhs);
1848
1849 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
1850 .ComptimeFloat => true,
1851 .Float => false,
1852 else => return mod.fail(
1853 scope,
1854 inst.positionals.lhs.src,
1855 "expected float type, found '{}'",
1856 .{
1857 dest_type,
1858 },
1859 ),
1860 };
1861
1862 switch (operand.ty.zigTypeTag()) {
1863 .ComptimeFloat, .Float, .ComptimeInt => {},
1864 else => return mod.fail(
1865 scope,
1866 inst.positionals.rhs.src,
1867 "expected float type, found '{}'",
1868 .{operand.ty},
1869 ),
1870 }
1871
1872 if (operand.value() != null) {
1873 return sema.coerce(scope, dest_type, operand);
1874 } else if (dest_is_comptime_float) {
1875 return sema.mod.fail(&block.base, inst.base.src, "unable to cast runtime value to 'comptime_float'", .{});
1876 }
1877
1878 return sema.mod.fail(&block.base, inst.base.src, "TODO implement analyze widen or shorten float", .{});
1879}
1880
1881fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1882 const tracy = trace(@src());
1883 defer tracy.end();
1884
1885 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1886 const array = sema.resolveInst(block, bin_inst.lhs);
1887 const array_ptr = try sema.analyzeRef(block, sema.src, array);
1888 const elem_index = sema.resolveInst(block, bin_inst.rhs);
1889 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
1890 return sema.analyzeDeref(block, sema.src, result_ptr, sema.src);
1891}
1892
1893fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1894 const tracy = trace(@src());
1895 defer tracy.end();
1896
1897 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1898 const src = inst_data.src();
1899 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
1900 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1901 const array = sema.resolveInst(block, extra.lhs);
1902 const array_ptr = try sema.analyzeRef(block, src, array);
1903 const elem_index = sema.resolveInst(block, extra.rhs);
1904 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
1905 return sema.analyzeDeref(block, src, result_ptr, src);
1906}
1907
1908fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1909 const tracy = trace(@src());
1910 defer tracy.end();
1911
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);
1916}
1917
1918fn zirElemPtrNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1919 const tracy = trace(@src());
1920 defer tracy.end();
1921
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);
1929}
1930
1931fn zirSliceStart(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1932 const tracy = trace(@src());
1933 defer tracy.end();
1934
1935 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1936 const src = inst_data.src();
1937 const extra = sema.code.extraData(zir.Inst.SliceStart, inst_data.payload_index).data;
1938 const array_ptr = sema.resolveInst(extra.lhs);
1939 const start = sema.resolveInst(extra.start);
1940
1941 return sema.analyzeSlice(block, src, array_ptr, start, null, null, .unneeded);
1942}
1943
1944fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1945 const tracy = trace(@src());
1946 defer tracy.end();
1947
1948 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1949 const src = inst_data.src();
1950 const extra = sema.code.extraData(zir.Inst.SliceEnd, inst_data.payload_index).data;
1951 const array_ptr = sema.resolveInst(extra.lhs);
1952 const start = sema.resolveInst(extra.start);
1953 const end = sema.resolveInst(extra.end);
1954
1955 return sema.analyzeSlice(block, src, array_ptr, start, end, null, .unneeded);
1956}
1957
1958fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1959 const tracy = trace(@src());
1960 defer tracy.end();
1961
1962 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1963 const src = inst_data.src();
1964 const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node };
1965 const extra = sema.code.extraData(zir.Inst.SliceSentinel, inst_data.payload_index).data;
1966 const array_ptr = sema.resolveInst(extra.lhs);
1967 const start = sema.resolveInst(extra.start);
1968 const end = sema.resolveInst(extra.end);
1969 const sentinel = sema.resolveInst(extra.sentinel);
1970
1971 return sema.analyzeSlice(block, inst.base.src, array_ptr, start, end, sentinel, sentinel_src);
1972}
1973
1974fn zirSwitchRange(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1975 const tracy = trace(@src());
1976 defer tracy.end();
1977
1978 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1979 const start = sema.resolveInst(bin_inst.lhs);
1980 const end = sema.resolveInst(bin_inst.rhs);
1981
1982 switch (start.ty.zigTypeTag()) {
1983 .Int, .ComptimeInt => {},
1984 else => return sema.mod.constVoid(block.arena, .unneeded),
1985 }
1986 switch (end.ty.zigTypeTag()) {
1987 .Int, .ComptimeInt => {},
1988 else => return sema.mod.constVoid(block.arena, .unneeded),
1989 }
1990 // .switch_range must be inside a comptime scope
1991 const start_val = start.value().?;
1992 const end_val = end.value().?;
1993 if (start_val.compare(.gte, end_val)) {
1994 return sema.mod.fail(&block.base, inst.base.src, "range start value must be smaller than the end value", .{});
1995 }
1996 return sema.mod.constVoid(block.arena, .unneeded);
1997}
1998
1999fn zirSwitchBr(
2000 sema: *Sema,
2001 parent_block: *Scope.Block,
2002 inst: zir.Inst.Index,
2003 ref: bool,
2004) InnerError!*Inst {
2005 const tracy = trace(@src());
2006 defer tracy.end();
2007
2008 if (true) @panic("TODO rework with zir-memory-layout in mind");
2009
2010 const target_ptr = sema.resolveInst(block, inst.positionals.target);
2011 const target = if (ref)
2012 try sema.analyzeDeref(block, inst.base.src, target_ptr, inst.positionals.target.src)
2013 else
2014 target_ptr;
2015 try validateSwitch(mod, scope, target, inst);
2016
2017 if (try mod.resolveDefinedValue(scope, target)) |target_val| {
2018 for (inst.positionals.cases) |case| {
2019 const resolved = sema.resolveInst(block, case.item);
2020 const casted = try sema.coerce(scope, target.ty, resolved);
2021 const item = try sema.resolveConstValue(parent_block, case_src, casted);
2022
2023 if (target_val.eql(item)) {
2024 try sema.body(scope.cast(Scope.Block).?, case.body);
2025 return mod.constNoReturn(scope, inst.base.src);
2026 }
2027 }
2028 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
2029 return mod.constNoReturn(scope, inst.base.src);
2030 }
2031
2032 if (inst.positionals.cases.len == 0) {
2033 // no cases just analyze else_branch
2034 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
2035 return mod.constNoReturn(scope, inst.base.src);
2036 }
2037
2038 try sema.requireRuntimeBlock(parent_block, inst.base.src);
2039 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);
2040
2041 var case_block: Scope.Block = .{
2042 .parent = parent_block,
2043 .inst_table = parent_block.inst_table,
2044 .func = parent_block.func,
2045 .owner_decl = parent_block.owner_decl,
2046 .src_decl = parent_block.src_decl,
2047 .instructions = .{},
2048 .arena = parent_block.arena,
2049 .inlining = parent_block.inlining,
2050 .is_comptime = parent_block.is_comptime,
2051 .branch_quota = parent_block.branch_quota,
2052 };
2053 defer case_block.instructions.deinit(mod.gpa);
2054
2055 for (inst.positionals.cases) |case, i| {
2056 // Reset without freeing.
2057 case_block.instructions.items.len = 0;
2058
2059 const resolved = sema.resolveInst(block, case.item);
2060 const casted = try sema.coerce(scope, target.ty, resolved);
2061 const item = try sema.resolveConstValue(parent_block, case_src, casted);
2062
2063 try sema.body(&case_block, case.body);
2064
2065 cases[i] = .{
2066 .item = item,
2067 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
2068 };
2069 }
2070
2071 case_block.instructions.items.len = 0;
2072 try sema.body(&case_block, inst.positionals.else_body);
2073
2074 const else_body: ir.Body = .{
2075 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
2076 };
2077
2078 return mod.addSwitchBr(parent_block, inst.base.src, target, cases, else_body);
2079}
2080
2081fn validateSwitch(sema: *Sema, block: *Scope.Block, target: *Inst, inst: zir.Inst.Index) InnerError!void {
2082 // validate usage of '_' prongs
2083 if (inst.positionals.special_prong == .underscore and target.ty.zigTypeTag() != .Enum) {
2084 return sema.mod.fail(&block.base, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
2085 // TODO notes "'_' prong here" inst.positionals.cases[last].src
2086 }
2087
2088 // check that target type supports ranges
2089 if (inst.positionals.range) |range_inst| {
2090 switch (target.ty.zigTypeTag()) {
2091 .Int, .ComptimeInt => {},
2092 else => {
2093 return sema.mod.fail(&block.base, target.src, "ranges not allowed when switching on type {}", .{target.ty});
2094 // TODO notes "range used here" range_inst.src
2095 },
2096 }
2097 }
2098
2099 // validate for duplicate items/missing else prong
2100 switch (target.ty.zigTypeTag()) {
2101 .Enum => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Enum", .{}),
2102 .ErrorSet => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .ErrorSet", .{}),
2103 .Union => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Union", .{}),
2104 .Int, .ComptimeInt => {
2105 var range_set = @import("RangeSet.zig").init(mod.gpa);
2106 defer range_set.deinit();
2107
2108 for (inst.positionals.items) |item| {
2109 const maybe_src = if (item.castTag(.switch_range)) |range| blk: {
2110 const start_resolved = sema.resolveInst(block, range.positionals.lhs);
2111 const start_casted = try sema.coerce(scope, target.ty, start_resolved);
2112 const end_resolved = sema.resolveInst(block, range.positionals.rhs);
2113 const end_casted = try sema.coerce(scope, target.ty, end_resolved);
2114
2115 break :blk try range_set.add(
2116 try sema.resolveConstValue(block, range_start_src, start_casted),
2117 try sema.resolveConstValue(block, range_end_src, end_casted),
2118 item.src,
2119 );
2120 } else blk: {
2121 const resolved = sema.resolveInst(block, item);
2122 const casted = try sema.coerce(scope, target.ty, resolved);
2123 const value = try sema.resolveConstValue(block, item_src, casted);
2124 break :blk try range_set.add(value, value, item.src);
2125 };
2126
2127 if (maybe_src) |previous_src| {
2128 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
2129 // TODO notes "previous value is here" previous_src
2130 }
2131 }
2132
2133 if (target.ty.zigTypeTag() == .Int) {
2134 var arena = std.heap.ArenaAllocator.init(mod.gpa);
2135 defer arena.deinit();
2136
2137 const start = try target.ty.minInt(&arena, mod.getTarget());
2138 const end = try target.ty.maxInt(&arena, mod.getTarget());
2139 if (try range_set.spans(start, end)) {
2140 if (inst.positionals.special_prong == .@"else") {
2141 return sema.mod.fail(&block.base, inst.base.src, "unreachable else prong, all cases already handled", .{});
2142 }
2143 return;
2144 }
2145 }
2146
2147 if (inst.positionals.special_prong != .@"else") {
2148 return sema.mod.fail(&block.base, inst.base.src, "switch must handle all possibilities", .{});
2149 }
2150 },
2151 .Bool => {
2152 var true_count: u8 = 0;
2153 var false_count: u8 = 0;
2154 for (inst.positionals.items) |item| {
2155 const resolved = sema.resolveInst(block, item);
2156 const casted = try sema.coerce(scope, Type.initTag(.bool), resolved);
2157 if ((try sema.resolveConstValue(block, item_src, casted)).toBool()) {
2158 true_count += 1;
2159 } else {
2160 false_count += 1;
2161 }
2162
2163 if (true_count + false_count > 2) {
2164 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
2165 }
2166 }
2167 if ((true_count + false_count < 2) and inst.positionals.special_prong != .@"else") {
2168 return sema.mod.fail(&block.base, inst.base.src, "switch must handle all possibilities", .{});
2169 }
2170 if ((true_count + false_count == 2) and inst.positionals.special_prong == .@"else") {
2171 return sema.mod.fail(&block.base, inst.base.src, "unreachable else prong, all cases already handled", .{});
2172 }
2173 },
2174 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
2175 if (inst.positionals.special_prong != .@"else") {
2176 return sema.mod.fail(&block.base, inst.base.src, "else prong required when switching on type '{}'", .{target.ty});
2177 }
2178
2179 var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa);
2180 defer seen_values.deinit();
2181
2182 for (inst.positionals.items) |item| {
2183 const resolved = sema.resolveInst(block, item);
2184 const casted = try sema.coerce(scope, target.ty, resolved);
2185 const val = try sema.resolveConstValue(block, item_src, casted);
2186
2187 if (try seen_values.fetchPut(val, item.src)) |prev| {
2188 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
2189 // TODO notes "previous value here" prev.value
2190 }
2191 }
2192 },
2193
2194 .ErrorUnion,
2195 .NoReturn,
2196 .Array,
2197 .Struct,
2198 .Undefined,
2199 .Null,
2200 .Optional,
2201 .BoundFn,
2202 .Opaque,
2203 .Vector,
2204 .Frame,
2205 .AnyFrame,
2206 .ComptimeFloat,
2207 .Float,
2208 => {
2209 return sema.mod.fail(&block.base, target.src, "invalid switch target type '{}'", .{target.ty});
2210 },
2211 }
2212}
2213
2214fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2215 const tracy = trace(@src());
2216 defer tracy.end();
2217
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) {
2224 error.ImportOutsidePkgPath => {
2225 return sema.mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
2226 },
2227 error.FileNotFound => {
2228 return sema.mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
2229 },
2230 else => {
2231 // TODO: make sure this gets retried and not cached
2232 return sema.mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
2233 },
2234 };
2235 return sema.mod.constType(block.arena, src, file_scope.root_container.ty);
2236}
2237
2238fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2239 const tracy = trace(@src());
2240 defer tracy.end();
2241 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirShl", .{});
2242}
2243
2244fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2245 const tracy = trace(@src());
2246 defer tracy.end();
2247 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirShr", .{});
2248}
2249
2250fn zirBitwise(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2251 const tracy = trace(@src());
2252 defer tracy.end();
2253
2254 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2255 const lhs = sema.resolveInst(bin_inst.lhs);
2256 const rhs = sema.resolveInst(bin_inst.rhs);
2257
2258 const instructions = &[_]*Inst{ lhs, rhs };
2259 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2260 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2261 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
2262
2263 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
2264 resolved_type.elemType()
2265 else
2266 resolved_type;
2267
2268 const scalar_tag = scalar_type.zigTypeTag();
2269
2270 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
2271 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2272 return sema.mod.fail(&block.base, inst.base.src, "vector length mismatch: {d} and {d}", .{
2273 lhs.ty.arrayLen(),
2274 rhs.ty.arrayLen(),
2275 });
2276 }
2277 return sema.mod.fail(&block.base, inst.base.src, "TODO implement support for vectors in zirBitwise", .{});
2278 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
2279 return sema.mod.fail(&block.base, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
2280 lhs.ty,
2281 rhs.ty,
2282 });
2283 }
2284
2285 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
2286
2287 if (!is_int) {
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()) });
2289 }
2290
2291 if (casted_lhs.value()) |lhs_val| {
2292 if (casted_rhs.value()) |rhs_val| {
2293 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2294 return sema.mod.constInst(scope, inst.base.src, .{
2295 .ty = resolved_type,
2296 .val = Value.initTag(.undef),
2297 });
2298 }
2299 return sema.mod.fail(&block.base, inst.base.src, "TODO implement comptime bitwise operations", .{});
2300 }
2301 }
2302
2303 try sema.requireRuntimeBlock(block, inst.base.src);
2304 const ir_tag = switch (inst.base.tag) {
2305 .bit_and => Inst.Tag.bit_and,
2306 .bit_or => Inst.Tag.bit_or,
2307 .xor => Inst.Tag.xor,
2308 else => unreachable,
2309 };
2310
2311 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
2312}
2313
2314fn zirBitNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2315 const tracy = trace(@src());
2316 defer tracy.end();
2317 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirBitNot", .{});
2318}
2319
2320fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2321 const tracy = trace(@src());
2322 defer tracy.end();
2323 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirArrayCat", .{});
2324}
2325
2326fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2327 const tracy = trace(@src());
2328 defer tracy.end();
2329 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirArrayMul", .{});
2330}
2331
2332fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2333 const tracy = trace(@src());
2334 defer tracy.end();
2335
2336 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2337 const lhs = sema.resolveInst(bin_inst.lhs);
2338 const rhs = sema.resolveInst(bin_inst.rhs);
2339
2340 const instructions = &[_]*Inst{ lhs, rhs };
2341 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2342 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2343 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
2344
2345 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
2346 resolved_type.elemType()
2347 else
2348 resolved_type;
2349
2350 const scalar_tag = scalar_type.zigTypeTag();
2351
2352 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
2353 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2354 return sema.mod.fail(&block.base, inst.base.src, "vector length mismatch: {d} and {d}", .{
2355 lhs.ty.arrayLen(),
2356 rhs.ty.arrayLen(),
2357 });
2358 }
2359 return sema.mod.fail(&block.base, inst.base.src, "TODO implement support for vectors in zirBinOp", .{});
2360 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
2361 return sema.mod.fail(&block.base, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
2362 lhs.ty,
2363 rhs.ty,
2364 });
2365 }
2366
2367 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
2368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
2369
2370 if (!is_int and !(is_float and floatOpAllowed(inst.base.tag))) {
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()) });
2372 }
2373
2374 if (casted_lhs.value()) |lhs_val| {
2375 if (casted_rhs.value()) |rhs_val| {
2376 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2377 return sema.mod.constInst(scope, inst.base.src, .{
2378 .ty = resolved_type,
2379 .val = Value.initTag(.undef),
2380 });
2381 }
2382 return analyzeInstComptimeOp(mod, scope, scalar_type, inst, lhs_val, rhs_val);
2383 }
2384 }
2385
2386 try sema.requireRuntimeBlock(block, inst.base.src);
2387 const ir_tag: Inst.Tag = switch (inst.base.tag) {
2388 .add => .add,
2389 .addwrap => .addwrap,
2390 .sub => .sub,
2391 .subwrap => .subwrap,
2392 .mul => .mul,
2393 .mulwrap => .mulwrap,
2394 else => return sema.mod.fail(&block.base, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
2395 };
2396
2397 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
2398}
2399
2400/// Analyzes operands that are known at comptime
2401fn analyzeInstComptimeOp(sema: *Sema, block: *Scope.Block, res_type: Type, inst: zir.Inst.Index, lhs_val: Value, rhs_val: Value) InnerError!*Inst {
2402 // incase rhs is 0, simply return lhs without doing any calculations
2403 // TODO Once division is implemented we should throw an error when dividing by 0.
2404 if (rhs_val.compareWithZero(.eq)) {
2405 return sema.mod.constInst(scope, inst.base.src, .{
2406 .ty = res_type,
2407 .val = lhs_val,
2408 });
2409 }
2410 const is_int = res_type.isInt() or res_type.zigTypeTag() == .ComptimeInt;
2411
2412 const value = switch (inst.base.tag) {
2413 .add => blk: {
2414 const val = if (is_int)
2415 try Module.intAdd(block.arena, lhs_val, rhs_val)
2416 else
2417 try mod.floatAdd(scope, res_type, inst.base.src, lhs_val, rhs_val);
2418 break :blk val;
2419 },
2420 .sub => blk: {
2421 const val = if (is_int)
2422 try Module.intSub(block.arena, lhs_val, rhs_val)
2423 else
2424 try mod.floatSub(scope, res_type, inst.base.src, lhs_val, rhs_val);
2425 break :blk val;
2426 },
2427 else => return sema.mod.fail(&block.base, inst.base.src, "TODO Implement arithmetic operand '{s}'", .{@tagName(inst.base.tag)}),
2428 };
2429
2430 log.debug("{s}({}, {}) result: {}", .{ @tagName(inst.base.tag), lhs_val, rhs_val, value });
2431
2432 return sema.mod.constInst(scope, inst.base.src, .{
2433 .ty = res_type,
2434 .val = value,
2435 });
2436}
2437
2438fn zirDeref(sema: *Sema, block: *Scope.Block, deref: zir.Inst.Index) InnerError!*Inst {
2439 const tracy = trace(@src());
2440 defer tracy.end();
2441
2442 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2443 const src = inst_data.src();
2444 const ptr_src: LazySrcLoc = .{ .node_offset_deref_ptr = inst_data.src_node };
2445 const ptr = sema.resolveInst(block, inst_data.operand);
2446 return sema.analyzeDeref(block, src, ptr, ptr_src);
2447}
2448
2449fn zirAsm(
2450 sema: *Sema,
2451 block: *Scope.Block,
2452 assembly: zir.Inst.Index,
2453 is_volatile: bool,
2454) InnerError!*Inst {
2455 const tracy = trace(@src());
2456 defer tracy.end();
2457
2458 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2459 const src = inst_data.src();
2460 const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = inst_data.src_node };
2461 const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = inst_data.src_node };
2462 const extra = sema.code.extraData(zir.Inst.Asm, inst_data.payload_index);
2463 const return_type = try sema.resolveType(block, ret_ty_src, extra.data.return_type);
2464 const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source);
2465
2466 var extra_i = extra.end;
2467 const output = if (extra.data.output != 0) blk: {
2468 const name = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2469 extra_i += 1;
2470 break :blk .{
2471 .name = name,
2472 .inst = try sema.resolveInst(block, extra.data.output),
2473 };
2474 } else null;
2475
2476 const args = try block.arena.alloc(*Inst, extra.data.args.len);
2477 const inputs = try block.arena.alloc([]const u8, extra.data.args_len);
2478 const clobbers = try block.arena.alloc([]const u8, extra.data.clobbers_len);
2479
2480 for (args) |*arg| {
2481 const uncasted = sema.resolveInst(block, sema.code.extra[extra_i]);
2482 extra_i += 1;
2483 arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted);
2484 }
2485 for (inputs) |*name| {
2486 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2487 extra_i += 1;
2488 }
2489 for (clobbers) |*name| {
2490 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2491 extra_i += 1;
2492 }
2493
2494 try sema.requireRuntimeBlock(block, src);
2495 const inst = try block.arena.create(Inst.Assembly);
2496 inst.* = .{
2497 .base = .{
2498 .tag = .assembly,
2499 .ty = return_type,
2500 .src = src,
2501 },
2502 .asm_source = asm_source,
2503 .is_volatile = is_volatile,
2504 .output = if (output) |o| o.inst else null,
2505 .output_name = if (output) |o| o.name else null,
2506 .inputs = inputs,
2507 .clobbers = clobbers,
2508 .args = args,
2509 };
2510 try block.instructions.append(mod.gpa, &inst.base);
2511 return &inst.base;
2512}
2513
2514fn zirCmp(
2515 sema: *Sema,
2516 block: *Scope.Block,
2517 inst: zir.Inst.Index,
2518 op: std.math.CompareOperator,
2519) InnerError!*Inst {
2520 const tracy = trace(@src());
2521 defer tracy.end();
2522
2523 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2524 const lhs = sema.resolveInst(bin_inst.lhs);
2525 const rhs = sema.resolveInst(bin_inst.rhs);
2526
2527 const is_equality_cmp = switch (op) {
2528 .eq, .neq => true,
2529 else => false,
2530 };
2531 const lhs_ty_tag = lhs.ty.zigTypeTag();
2532 const rhs_ty_tag = rhs.ty.zigTypeTag();
2533 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
2534 // null == null, null != null
2535 return mod.constBool(block.arena, inst.base.src, op == .eq);
2536 } else if (is_equality_cmp and
2537 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
2538 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
2539 {
2540 // comparing null with optionals
2541 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
2542 return sema.analyzeIsNull(block, inst.base.src, opt_operand, op == .neq);
2543 } else if (is_equality_cmp and
2544 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
2545 {
2546 return sema.mod.fail(&block.base, inst.base.src, "TODO implement C pointer cmp", .{});
2547 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
2548 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
2549 return sema.mod.fail(&block.base, inst.base.src, "comparison of '{}' with null", .{non_null_type});
2550 } else if (is_equality_cmp and
2551 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
2552 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
2553 {
2554 return sema.mod.fail(&block.base, inst.base.src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
2555 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
2556 if (!is_equality_cmp) {
2557 return sema.mod.fail(&block.base, inst.base.src, "{s} operator not allowed for errors", .{@tagName(op)});
2558 }
2559 if (rhs.value()) |rval| {
2560 if (lhs.value()) |lval| {
2561 // 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
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));
2563 }
2564 }
2565 try sema.requireRuntimeBlock(block, inst.base.src);
2566 return mod.addBinOp(b, inst.base.src, Type.initTag(.bool), if (op == .eq) .cmp_eq else .cmp_neq, lhs, rhs);
2567 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {
2568 // This operation allows any combination of integer and float types, regardless of the
2569 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
2570 // numeric types.
2571 return mod.cmpNumeric(scope, inst.base.src, lhs, rhs, op);
2572 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
2573 if (!is_equality_cmp) {
2574 return sema.mod.fail(&block.base, inst.base.src, "{s} operator not allowed for types", .{@tagName(op)});
2575 }
2576 return mod.constBool(block.arena, inst.base.src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
2577 }
2578 return sema.mod.fail(&block.base, inst.base.src, "TODO implement more cmp analysis", .{});
2579}
2580
2581fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2582 const tracy = trace(@src());
2583 defer tracy.end();
2584
2585 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2586 const operand = sema.resolveInst(block, inst_data.operand);
2587 return sema.mod.constType(block.arena, inst_data.src(), operand.ty);
2588}
2589
2590fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2591 const tracy = trace(@src());
2592 defer tracy.end();
2593
2594 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2595 const src = inst_data.src();
2596 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
2597
2598 const inst_list = try mod.gpa.alloc(*ir.Inst, extra.data.operands_len);
2599 defer mod.gpa.free(inst_list);
2600
2601 const src_list = try mod.gpa.alloc(LazySrcLoc, extra.data.operands_len);
2602 defer mod.gpa.free(src_list);
2603
2604 for (sema.code.extra[extra.end..][0..extra.data.operands_len]) |arg_ref, i| {
2605 inst_list[i] = sema.resolveInst(block, arg_ref);
2606 src_list[i] = .{ .node_offset_builtin_call_argn = inst_data.src_node };
2607 }
2608
2609 const result_type = try sema.resolvePeerTypes(block, inst_list, src_list);
2610 return sema.mod.constType(block.arena, src, result_type);
2611}
2612
2613fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2614 const tracy = trace(@src());
2615 defer tracy.end();
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
2621 const bool_type = Type.initTag(.bool);
2622 const operand = try sema.coerce(scope, bool_type, uncasted_operand);
2623 if (try mod.resolveDefinedValue(scope, operand)) |val| {
2624 return mod.constBool(block.arena, src, !val.toBool());
2625 }
2626 try sema.requireRuntimeBlock(block, src);
2627 return block.addUnOp(src, bool_type, .not, operand);
2628}
2629
2630fn zirBoolOp(
2631 sema: *Sema,
2632 block: *Scope.Block,
2633 inst: zir.Inst.Index,
2634 comptime is_bool_or: bool,
2635) InnerError!*Inst {
2636 const tracy = trace(@src());
2637 defer tracy.end();
2638
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);
2645
2646 if (lhs.value()) |lhs_val| {
2647 if (rhs.value()) |rhs_val| {
2648 if (is_bool_or) {
2649 return mod.constBool(block.arena, inst.base.src, lhs_val.toBool() or rhs_val.toBool());
2650 } else {
2651 return mod.constBool(block.arena, inst.base.src, lhs_val.toBool() and rhs_val.toBool());
2652 }
2653 }
2654 }
2655 try sema.requireRuntimeBlock(block, inst.base.src);
2656 const tag: ir.Inst.Tag = if (is_bool_or) .bool_or else .bool_and;
2657 return mod.addBinOp(b, inst.base.src, bool_type, tag, lhs, rhs);
2658}
2659
2660fn zirIsNull(
2661 sema: *Sema,
2662 block: *Scope.Block,
2663 inst: zir.Inst.Index,
2664 invert_logic: bool,
2665) InnerError!*Inst {
2666 const tracy = trace(@src());
2667 defer tracy.end();
2668
2669 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2670 const src = inst_data.src();
2671 const operand = sema.resolveInst(block, inst_data.operand);
2672 return sema.analyzeIsNull(block, src, operand, invert_logic);
2673}
2674
2675fn zirIsNullPtr(
2676 sema: *Sema,
2677 block: *Scope.Block,
2678 inst: zir.Inst.Index,
2679 invert_logic: bool,
2680) InnerError!*Inst {
2681 const tracy = trace(@src());
2682 defer tracy.end();
2683
2684 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2685 const src = inst_data.src();
2686 const ptr = sema.resolveInst(block, inst_data.operand);
2687 const loaded = try sema.analyzeDeref(block, src, ptr, src);
2688 return sema.analyzeIsNull(block, src, loaded, invert_logic);
2689}
2690
2691fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2692 const tracy = trace(@src());
2693 defer tracy.end();
2694
2695 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2696 const operand = sema.resolveInst(block, inst_data.operand);
2697 return mod.analyzeIsErr(scope, inst_data.src(), operand);
2698}
2699
2700fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2701 const tracy = trace(@src());
2702 defer tracy.end();
2703
2704 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2705 const src = inst_data.src();
2706 const ptr = sema.resolveInst(block, inst_data.operand);
2707 const loaded = try sema.analyzeDeref(block, src, ptr, src);
2708 return mod.analyzeIsErr(scope, src, loaded);
2709}
2710
2711fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2712 const tracy = trace(@src());
2713 defer tracy.end();
2714
2715 const uncasted_cond = sema.resolveInst(block, inst.positionals.condition);
2716 const cond = try sema.coerce(scope, Type.initTag(.bool), uncasted_cond);
2717
2718 if (try mod.resolveDefinedValue(scope, cond)) |cond_val| {
2719 const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body;
2720 try sema.body(parent_block, body.*);
2721 return mod.constNoReturn(scope, inst.base.src);
2722 }
2723
2724 var true_block: Scope.Block = .{
2725 .parent = parent_block,
2726 .inst_table = parent_block.inst_table,
2727 .func = parent_block.func,
2728 .owner_decl = parent_block.owner_decl,
2729 .src_decl = parent_block.src_decl,
2730 .instructions = .{},
2731 .arena = parent_block.arena,
2732 .inlining = parent_block.inlining,
2733 .is_comptime = parent_block.is_comptime,
2734 .branch_quota = parent_block.branch_quota,
2735 };
2736 defer true_block.instructions.deinit(mod.gpa);
2737 try sema.body(&true_block, inst.positionals.then_body);
2738
2739 var false_block: Scope.Block = .{
2740 .parent = parent_block,
2741 .inst_table = parent_block.inst_table,
2742 .func = parent_block.func,
2743 .owner_decl = parent_block.owner_decl,
2744 .src_decl = parent_block.src_decl,
2745 .instructions = .{},
2746 .arena = parent_block.arena,
2747 .inlining = parent_block.inlining,
2748 .is_comptime = parent_block.is_comptime,
2749 .branch_quota = parent_block.branch_quota,
2750 };
2751 defer false_block.instructions.deinit(mod.gpa);
2752 try sema.body(&false_block, inst.positionals.else_body);
2753
2754 const then_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, true_block.instructions.items) };
2755 const else_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, false_block.instructions.items) };
2756 return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body);
2757}
2758
2759fn zirUnreachable(
2760 sema: *Sema,
2761 block: *Scope.Block,
2762 zir_index: zir.Inst.Index,
2763 safety_check: bool,
2764) InnerError!*Inst {
2765 const tracy = trace(@src());
2766 defer tracy.end();
2767
2768 try sema.requireRuntimeBlock(block, zir_index.base.src);
2769 // TODO Add compile error for @optimizeFor occurring too late in a scope.
2770 if (safety_check and block.wantSafety()) {
2771 return mod.safetyPanic(b, zir_index.base.src, .unreach);
2772 } else {
2773 return block.addNoOp(zir_index.base.src, Type.initTag(.noreturn), .unreach);
2774 }
2775}
2776
2777fn zirRetTok(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2778 @compileError("TODO");
2779}
2780
2781fn zirRetNode(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2782 @compileError("TODO");
2783}
2784
2785fn floatOpAllowed(tag: zir.Inst.Tag) bool {
2786 // extend this swich as additional operators are implemented
2787 return switch (tag) {
2788 .add, .sub => true,
2789 else => false,
2790 };
2791}
2792
2793fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2794 const tracy = trace(@src());
2795 defer tracy.end();
2796
2797 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
2798 const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type);
2799 const ty = try sema.mod.ptrType(
2800 block.arena,
2801 elem_type,
2802 null,
2803 0,
2804 0,
2805 0,
2806 inst_data.is_mutable,
2807 inst_data.is_allowzero,
2808 inst_data.is_volatile,
2809 inst_data.size,
2810 );
2811 return sema.mod.constType(block.arena, .unneeded, ty);
2812}
2813
2814fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2815 const tracy = trace(@src());
2816 defer tracy.end();
2817
2818 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
2819 const extra = sema.code.extraData(zir.Inst.PtrType, inst_data.payload_index);
2820
2821 var extra_i = extra.end;
2822
2823 const sentinel = if (inst_data.flags.has_sentinel) blk: {
2824 const ref = sema.code.extra[extra_i];
2825 extra_i += 1;
2826 break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
2827 } else null;
2828
2829 const abi_align = if (inst_data.flags.has_align) blk: {
2830 const ref = sema.code.extra[extra_i];
2831 extra_i += 1;
2832 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32);
2833 } else 0;
2834
2835 const bit_start = if (inst_data.flags.has_bit_start) blk: {
2836 const ref = sema.code.extra[extra_i];
2837 extra_i += 1;
2838 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
2839 } else 0;
2840
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);
2851
2852 const ty = try mod.ptrType(
2853 scope,
2854 elem_type,
2855 sentinel,
2856 abi_align,
2857 bit_start,
2858 bit_end,
2859 inst_data.flags.is_mutable,
2860 inst_data.flags.is_allowzero,
2861 inst_data.flags.is_volatile,
2862 inst_data.size,
2863 );
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;
3869}
src/zir_sema.zig deleted-3869
...@@ -1,3869 +0,0 @@
1//! Semantic analysis of ZIR instructions.
2//! Shared to every Block. Stored on the stack.
3//! State used for compiling a `zir.Code` into TZIR.
4//! Transforms untyped ZIR instructions into semantically-analyzed TZIR instructions.
5//! Does type checking, comptime control flow, and safety-check generation.
6//! This is the the heart of the Zig compiler.
7
8mod: *Module,
9/// Same as `mod.gpa`.
10gpa: *Allocator,
11/// Points to the arena allocator of the Decl.
12arena: *Allocator,
13code: zir.Code,
14/// Maps ZIR to TZIR.
15inst_map: []*const Inst,
16/// When analyzing an inline function call, owner_decl is the Decl of the caller
17/// and `src_decl` of `Scope.Block` is the `Decl` of the callee.
18/// This `Decl` owns the arena memory of this `Sema`.
19owner_decl: *Decl,
20func: ?*Module.Fn,
21/// For now, TZIR requires arg instructions to be the first N instructions in the
22/// TZIR code. We store references here for the purpose of `resolveInst`.
23/// This can get reworked with TZIR memory layout changes, into simply:
24/// > Denormalized data to make `resolveInst` faster. This is 0 if not inside a function,
25/// > otherwise it is the number of parameters of the function.
26/// > param_count: u32
27param_inst_list: []const *ir.Inst,
28branch_quota: u32 = 1000,
29/// This field is updated when a new source location becomes active, so that
30/// instructions which do not have explicitly mapped source locations still have
31/// access to the source location set by the previous instruction which did
32/// contain a mapped source location.
33src: LazySrcLoc = .{ .token_offset = 0 },
34
35const std = @import("std");
36const mem = std.mem;
37const Allocator = std.mem.Allocator;
38const assert = std.debug.assert;
39const log = std.log.scoped(.sema);
40
41const Sema = @This();
42const Value = @import("value.zig").Value;
43const Type = @import("type.zig").Type;
44const TypedValue = @import("TypedValue.zig");
45const ir = @import("ir.zig");
46const zir = @import("zir.zig");
47const Module = @import("Module.zig");
48const Inst = ir.Inst;
49const Body = ir.Body;
50const trace = @import("tracy.zig").trace;
51const Scope = Module.Scope;
52const InnerError = Module.InnerError;
53const Decl = Module.Decl;
54const LazySrcLoc = Module.LazySrcLoc;
55
56// TODO when memory layout of TZIR is reworked, this can be simplified.
57const const_tzir_inst_list = blk: {
58 var result: [zir.const_inst_list.len]ir.Inst.Const = undefined;
59 for (result) |*tzir_const, i| {
60 tzir_const.* = .{
61 .base = .{
62 .tag = .constant,
63 .ty = zir.const_inst_list[i].ty,
64 .src = 0,
65 },
66 .val = zir.const_inst_list[i].val,
67 };
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);
75}
76
77pub fn rootAsType(
78 sema: *Sema,
79 root_block: *Scope.Block,
80 zir_result_inst: zir.Inst.Index,
81 body: zir.Body,
82) !Type {
83 const root_body = sema.code.extra[sema.code.root_start..][0..sema.code.root_len];
84 try sema.body(root_block, root_body);
85
86 const result_inst = sema.inst_map[zir_result_inst];
87 // Source location is unneeded because resolveConstValue must have already
88 // been successfully called when coercing the value to a type, from the
89 // result location.
90 const val = try sema.resolveConstValue(root_block, .unneeded, result_inst);
91 return val.toType(root_block.arena);
92}
93
94pub fn body(sema: *Sema, block: *Scope.Block, body: []const zir.Inst.Index) !void {
95 const tracy = trace(@src());
96 defer tracy.end();
97
98 const map = block.sema.inst_map;
99 const tags = block.sema.code.instructions.items(.tag);
100
101 // TODO: As an optimization, look into making these switch prongs directly jump
102 // to the next one, rather than detouring through the loop condition.
103 // Also, look into leaving only the "noreturn" loop break condition, and removing
104 // the iteration based one. Better yet, have an extra entry in the tags array as a
105 // sentinel, so that exiting the loop is just another jump table prong.
106 // Related: https://github.com/ziglang/zig/issues/8220
107 for (body) |zir_inst| {
108 map[zir_inst] = switch (tags[zir_inst]) {
109 .alloc => try sema.zirAlloc(block, zir_inst),
110 .alloc_mut => try sema.zirAllocMut(block, zir_inst),
111 .alloc_inferred => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_const)),
112 .alloc_inferred_mut => try sema.zirAllocInferred(block, zir_inst, Type.initTag(.inferred_alloc_mut)),
113 .bitcast_ref => try sema.zirBitcastRef(block, zir_inst),
114 .bitcast_result_ptr => try sema.zirBitcastResultPtr(block, zir_inst),
115 .block => try sema.zirBlock(block, zir_inst, false),
116 .block_comptime => try sema.zirBlock(block, zir_inst, true),
117 .block_flat => try sema.zirBlockFlat(block, zir_inst, false),
118 .block_comptime_flat => try sema.zirBlockFlat(block, zir_inst, true),
119 .@"break" => try sema.zirBreak(block, zir_inst),
120 .break_void_tok => try sema.zirBreakVoidTok(block, zir_inst),
121 .breakpoint => try sema.zirBreakpoint(block, zir_inst),
122 .call => try sema.zirCall(block, zir_inst, .auto),
123 .call_async_kw => try sema.zirCall(block, zir_inst, .async_kw),
124 .call_no_async => try sema.zirCall(block, zir_inst, .no_async),
125 .call_compile_time => try sema.zirCall(block, zir_inst, .compile_time),
126 .call_none => try sema.zirCallNone(block, zir_inst),
127 .coerce_result_ptr => try sema.zirCoerceResultPtr(block, zir_inst),
128 .compile_error => try sema.zirCompileError(block, zir_inst),
129 .compile_log => try sema.zirCompileLog(block, zir_inst),
130 .@"const" => try sema.zirConst(block, zir_inst),
131 .dbg_stmt_node => try sema.zirDbgStmtNode(block, zir_inst),
132 .decl_ref => try sema.zirDeclRef(block, zir_inst),
133 .decl_val => try sema.zirDeclVal(block, zir_inst),
134 .ensure_result_used => try sema.zirEnsureResultUsed(block, zir_inst),
135 .ensure_result_non_error => try sema.zirEnsureResultNonError(block, zir_inst),
136 .indexable_ptr_len => try sema.zirIndexablePtrLen(block, zir_inst),
137 .ref => try sema.zirRef(block, zir_inst),
138 .resolve_inferred_alloc => try sema.zirResolveInferredAlloc(block, zir_inst),
139 .ret_ptr => try sema.zirRetPtr(block, zir_inst),
140 .ret_type => try sema.zirRetType(block, zir_inst),
141 .store_to_block_ptr => try sema.zirStoreToBlockPtr(block, zir_inst),
142 .store_to_inferred_ptr => try sema.zirStoreToInferredPtr(block, zir_inst),
143 .ptr_type_simple => try sema.zirPtrTypeSimple(block, zir_inst),
144 .ptr_type => try sema.zirPtrType(block, zir_inst),
145 .store => try sema.zirStore(block, zir_inst),
146 .set_eval_branch_quota => try sema.zirSetEvalBranchQuota(block, zir_inst),
147 .str => try sema.zirStr(block, zir_inst),
148 .int => try sema.zirInt(block, zir_inst),
149 .int_type => try sema.zirIntType(block, zir_inst),
150 .loop => try sema.zirLoop(block, zir_inst),
151 .param_type => try sema.zirParamType(block, zir_inst),
152 .ptrtoint => try sema.zirPtrtoint(block, zir_inst),
153 .field_ptr => try sema.zirFieldPtr(block, zir_inst),
154 .field_val => try sema.zirFieldVal(block, zir_inst),
155 .field_ptr_named => try sema.zirFieldPtrNamed(block, zir_inst),
156 .field_val_named => try sema.zirFieldValNamed(block, zir_inst),
157 .deref => try sema.zirDeref(block, zir_inst),
158 .as => try sema.zirAs(block, zir_inst),
159 .@"asm" => try sema.zirAsm(block, zir_inst, false),
160 .asm_volatile => try sema.zirAsm(block, zir_inst, true),
161 .unreachable_safe => try sema.zirUnreachable(block, zir_inst, true),
162 .unreachable_unsafe => try sema.zirUnreachable(block, zir_inst, false),
163 .ret_tok => try sema.zirRetTok(block, zir_inst),
164 .ret_node => try sema.zirRetNode(block, zir_inst),
165 .fn_type => try sema.zirFnType(block, zir_inst),
166 .fn_type_cc => try sema.zirFnTypeCc(block, zir_inst),
167 .intcast => try sema.zirIntcast(block, zir_inst),
168 .bitcast => try sema.zirBitcast(block, zir_inst),
169 .floatcast => try sema.zirFloatcast(block, zir_inst),
170 .elem_ptr => try sema.zirElemPtr(block, zir_inst),
171 .elem_ptr_node => try sema.zirElemPtrNode(block, zir_inst),
172 .elem_val => try sema.zirElemVal(block, zir_inst),
173 .elem_val_node => try sema.zirElemValNode(block, zir_inst),
174 .add => try sema.zirArithmetic(block, zir_inst),
175 .addwrap => try sema.zirArithmetic(block, zir_inst),
176 .sub => try sema.zirArithmetic(block, zir_inst),
177 .subwrap => try sema.zirArithmetic(block, zir_inst),
178 .mul => try sema.zirArithmetic(block, zir_inst),
179 .mulwrap => try sema.zirArithmetic(block, zir_inst),
180 .div => try sema.zirArithmetic(block, zir_inst),
181 .mod_rem => try sema.zirArithmetic(block, zir_inst),
182 .array_cat => try sema.zirArrayCat(block, zir_inst),
183 .array_mul => try sema.zirArrayMul(block, zir_inst),
184 .bit_and => try sema.zirBitwise(block, zir_inst),
185 .bit_not => try sema.zirBitNot(block, zir_inst),
186 .bit_or => try sema.zirBitwise(block, zir_inst),
187 .xor => try sema.zirBitwise(block, zir_inst),
188 .shl => try sema.zirShl(block, zir_inst),
189 .shr => try sema.zirShr(block, zir_inst),
190 .cmp_lt => try sema.zirCmp(block, zir_inst, .lt),
191 .cmp_lte => try sema.zirCmp(block, zir_inst, .lte),
192 .cmp_eq => try sema.zirCmp(block, zir_inst, .eq),
193 .cmp_gte => try sema.zirCmp(block, zir_inst, .gte),
194 .cmp_gt => try sema.zirCmp(block, zir_inst, .gt),
195 .cmp_neq => try sema.zirCmp(block, zir_inst, .neq),
196 .condbr => try sema.zirCondbr(block, zir_inst),
197 .is_null => try sema.zirIsNull(block, zir_inst, false),
198 .is_non_null => try sema.zirIsNull(block, zir_inst, true),
199 .is_null_ptr => try sema.zirIsNullPtr(block, zir_inst, false),
200 .is_non_null_ptr => try sema.zirIsNullPtr(block, zir_inst, true),
201 .is_err => try sema.zirIsErr(block, zir_inst),
202 .is_err_ptr => try sema.zirIsErrPtr(block, zir_inst),
203 .bool_not => try sema.zirBoolNot(block, zir_inst),
204 .typeof => try sema.zirTypeof(block, zir_inst),
205 .typeof_peer => try sema.zirTypeofPeer(block, zir_inst),
206 .optional_type => try sema.zirOptionalType(block, zir_inst),
207 .optional_type_from_ptr_elem => try sema.zirOptionalTypeFromPtrElem(block, zir_inst),
208 .optional_payload_safe => try sema.zirOptionalPayload(block, zir_inst, true),
209 .optional_payload_unsafe => try sema.zirOptionalPayload(block, zir_inst, false),
210 .optional_payload_safe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, true),
211 .optional_payload_unsafe_ptr => try sema.zirOptionalPayloadPtr(block, zir_inst, false),
212 .err_union_payload_safe => try sema.zirErrUnionPayload(block, zir_inst, true),
213 .err_union_payload_unsafe => try sema.zirErrUnionPayload(block, zir_inst, false),
214 .err_union_payload_safe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, true),
215 .err_union_payload_unsafe_ptr => try sema.zirErrUnionPayloadPtr(block, zir_inst, false),
216 .err_union_code => try sema.zirErrUnionCode(block, zir_inst),
217 .err_union_code_ptr => try sema.zirErrUnionCodePtr(block, zir_inst),
218 .ensure_err_payload_void => try sema.zirEnsureErrPayloadVoid(block, zir_inst),
219 .array_type => try sema.zirArrayType(block, zir_inst),
220 .array_type_sentinel => try sema.zirArrayTypeSentinel(block, zir_inst),
221 .enum_literal => try sema.zirEnumLiteral(block, zir_inst),
222 .merge_error_sets => try sema.zirMergeErrorSets(block, zir_inst),
223 .error_union_type => try sema.zirErrorUnionType(block, zir_inst),
224 .anyframe_type => try sema.zirAnyframeType(block, zir_inst),
225 .error_set => try sema.zirErrorSet(block, zir_inst),
226 .error_value => try sema.zirErrorValue(block, zir_inst),
227 .slice_start => try sema.zirSliceStart(block, zir_inst),
228 .slice_end => try sema.zirSliceEnd(block, zir_inst),
229 .slice_sentinel => try sema.zirSliceSentinel(block, zir_inst),
230 .import => try sema.zirImport(block, zir_inst),
231 .bool_and => try sema.zirBoolOp(block, zir_inst, false),
232 .bool_or => try sema.zirBoolOp(block, zir_inst, true),
233 .void_value => try sema.mod.constVoid(block.arena, .unneeded),
234 .switchbr => try sema.zirSwitchBr(block, zir_inst, false),
235 .switchbr_ref => try sema.zirSwitchBr(block, zir_inst, true),
236 .switch_range => try sema.zirSwitchRange(block, zir_inst),
237 };
238 if (map[zir_inst].ty.isNoReturn()) {
239 break;
240 }
241 }
242}
243
244fn resolveInst(sema: *Sema, block: *Scope.Block, zir_ref: zir.Inst.Ref) *const ir.Inst {
245 var i = zir_ref;
246
247 // First section of indexes correspond to a set number of constant values.
248 if (i < const_tzir_inst_list.len) {
249 return &const_tzir_inst_list[i];
250 }
251 i -= const_tzir_inst_list.len;
252
253 // Next section of indexes correspond to function parameters, if any.
254 if (block.inlining) |inlining| {
255 if (i < inlining.casted_args.len) {
256 return inlining.casted_args[i];
257 }
258 i -= inlining.casted_args.len;
259 } else {
260 if (i < sema.param_inst_list.len) {
261 return sema.param_inst_list[i];
262 }
263 i -= sema.param_inst_list.len;
264 }
265
266 // Finally, the last section of indexes refers to the map of ZIR=>TZIR.
267 return sema.inst_map[i];
268}
269
270fn resolveConstString(
271 sema: *Sema,
272 block: *Scope.Block,
273 src: LazySrcLoc,
274 zir_ref: zir.Inst.Ref,
275) ![]u8 {
276 const tzir_inst = sema.resolveInst(block, zir_ref);
277 const wanted_type = Type.initTag(.const_slice_u8);
278 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
279 const val = try sema.resolveConstValue(block, src, coerced_inst);
280 return val.toAllocatedBytes(block.arena);
281}
282
283fn resolveType(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, zir_ref: zir.Inst.Ref) !Type {
284 const tzir_inst = sema.resolveInt(block, zir_ref);
285 const wanted_type = Type.initTag(.@"type");
286 const coerced_inst = try sema.coerce(block, wanted_type, tzir_inst);
287 const val = try sema.resolveConstValue(block, src, coerced_inst);
288 return val.toType(sema.arena);
289}
290
291fn resolveConstValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !Value {
292 return (try sema.resolveDefinedValue(block, src, base)) orelse
293 return sema.mod.fail(&block.base, src, "unable to resolve comptime value", .{});
294}
295
296fn resolveDefinedValue(sema: *Sema, block: *Scope.Block, src: LazySrcLoc, base: *ir.Inst) !?Value {
297 if (base.value()) |val| {
298 if (val.isUndef()) {
299 return sema.mod.fail(&block.base, src, "use of undefined value here causes undefined behavior", .{});
300 }
301 return val;
302 }
303 return null;
304}
305
306/// Appropriate to call when the coercion has already been done by result
307/// location semantics. Asserts the value fits in the provided `Int` type.
308/// Only supports `Int` types 64 bits or less.
309fn resolveAlreadyCoercedInt(
310 sema: *Sema,
311 block: *Scope.Block,
312 src: LazySrcLoc,
313 zir_ref: zir.Inst.Ref,
314 comptime Int: type,
315) !Int {
316 comptime assert(@typeInfo(Int).Int.bits <= 64);
317 const tzir_inst = sema.resolveInst(block, zir_ref);
318 const val = try sema.resolveConstValue(block, src, tzir_inst);
319 switch (@typeInfo(Int).Int.signedness) {
320 .signed => return @intCast(Int, val.toSignedInt()),
321 .unsigned => return @intCast(Int, val.toUnsignedInt()),
322 }
323}
324
325fn resolveInt(
326 sema: *Sema,
327 block: *Scope.Block,
328 src: LazySrcLoc,
329 zir_ref: zir.Inst.Ref,
330 dest_type: Type,
331) !u64 {
332 const tzir_inst = sema.resolveInst(block, zir_ref);
333 const coerced = try sema.coerce(scope, dest_type, tzir_inst);
334 const val = try sema.resolveConstValue(block, src, coerced);
335
336 return val.toUnsignedInt();
337}
338
339fn resolveInstConst(
340 sema: *Sema,
341 block: *Scope.Block,
342 src: LazySrcLoc,
343 zir_ref: zir.Inst.Ref,
344) InnerError!TypedValue {
345 const tzir_inst = sema.resolveInst(block, zir_ref);
346 const val = try sema.resolveConstValue(block, src, tzir_inst);
347 return TypedValue{
348 .ty = tzir_inst.ty,
349 .val = val,
350 };
351}
352
353fn zirConst(sema: *Sema, block: *Scope.Block, const_inst: zir.Inst.Index) InnerError!*Inst {
354 const tracy = trace(@src());
355 defer tracy.end();
356 // Move the TypedValue from old memory to new memory. This allows freeing the ZIR instructions
357 // after analysis.
358 const typed_value_copy = try const_inst.positionals.typed_value.copy(block.arena);
359 return sema.mod.constInst(scope, const_inst.base.src, typed_value_copy);
360}
361
362fn zirBitcastRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
363 const tracy = trace(@src());
364 defer tracy.end();
365 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zir_sema.zirBitcastRef", .{});
366}
367
368fn zirBitcastResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
369 const tracy = trace(@src());
370 defer tracy.end();
371 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zir_sema.zirBitcastResultPtr", .{});
372}
373
374fn zirCoerceResultPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
375 const tracy = trace(@src());
376 defer tracy.end();
377 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirCoerceResultPtr", .{});
378}
379
380fn zirRetPtr(sema: *Module, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
381 const tracy = trace(@src());
382 defer tracy.end();
383
384 try sema.requireFunctionBlock(block, inst.base.src);
385 const fn_ty = block.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
386 const ret_type = fn_ty.fnReturnType();
387 const ptr_type = try sema.mod.simplePtrType(block.arena, ret_type, true, .One);
388 return block.addNoOp(inst.base.src, ptr_type, .alloc);
389}
390
391fn zirRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
392 const tracy = trace(@src());
393 defer tracy.end();
394
395 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
396 const operand = sema.resolveInst(block, inst_data.operand);
397 return sema.analyzeRef(block, inst_data.src(), operand);
398}
399
400fn zirRetType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
401 const tracy = trace(@src());
402 defer tracy.end();
403 try sema.requireFunctionBlock(block, inst.base.src);
404 const fn_ty = b.func.?.owner_decl.typed_value.most_recent.typed_value.ty;
405 const ret_type = fn_ty.fnReturnType();
406 return sema.mod.constType(block.arena, inst.base.src, ret_type);
407}
408
409fn zirEnsureResultUsed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
410 const tracy = trace(@src());
411 defer tracy.end();
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();
416 switch (operand.ty.zigTypeTag()) {
417 .Void, .NoReturn => return sema.mod.constVoid(block.arena, .unneeded),
418 else => return sema.mod.fail(&block.base, src, "expression value is ignored", .{}),
419 }
420}
421
422fn zirEnsureResultNonError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
423 const tracy = trace(@src());
424 defer tracy.end();
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();
429 switch (operand.ty.zigTypeTag()) {
430 .ErrorSet, .ErrorUnion => return sema.mod.fail(&block.base, src, "error is discarded", .{}),
431 else => return sema.mod.constVoid(block.arena, .unneeded),
432 }
433}
434
435fn zirIndexablePtrLen(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
436 const tracy = trace(@src());
437 defer tracy.end();
438
439 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
440 const array_ptr = sema.resolveInst(block, inst_data.operand);
441
442 const elem_ty = array_ptr.ty.elemType();
443 if (!elem_ty.isIndexable()) {
444 const cond_src: LazySrcLoc = .{ .node_offset_for_cond = inst_data.src_node };
445 const msg = msg: {
446 const msg = try sema.mod.errMsg(
447 &block.base,
448 cond_src,
449 "type '{}' does not support indexing",
450 .{elem_ty},
451 );
452 errdefer msg.destroy(mod.gpa);
453 try sema.mod.errNote(
454 &block.base,
455 cond_src,
456 msg,
457 "for loop operand must be an array, slice, tuple, or vector",
458 .{},
459 );
460 break :msg msg;
461 };
462 return mod.failWithOwnedErrorMsg(scope, msg);
463 }
464 const result_ptr = try sema.namedFieldPtr(block, inst.base.src, array_ptr, "len", inst.base.src);
465 return sema.analyzeDeref(block, inst.base.src, result_ptr, result_ptr.src);
466}
467
468fn zirAlloc(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
469 const tracy = trace(@src());
470 defer tracy.end();
471
472 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
473 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
474 const var_decl_src = inst_data.src();
475 const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
476 const ptr_type = try sema.mod.simplePtrType(block.arena, var_type, true, .One);
477 try sema.requireRuntimeBlock(block, var_decl_src);
478 return block.addNoOp(var_decl_src, ptr_type, .alloc);
479}
480
481fn zirAllocMut(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
482 const tracy = trace(@src());
483 defer tracy.end();
484
485 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
486 const var_decl_src = inst_data.src();
487 const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
488 const var_type = try sema.resolveType(block, ty_src, inst_data.operand);
489 try sema.validateVarType(block, ty_src, var_type);
490 const ptr_type = try sema.mod.simplePtrType(block.arena, var_type, true, .One);
491 try sema.requireRuntimeBlock(block, var_decl_src);
492 return block.addNoOp(var_decl_src, ptr_type, .alloc);
493}
494
495fn zirAllocInferred(
496 sema: *Sema,
497 block: *Scope.Block,
498 inst: zir.Inst.Index,
499 inferred_alloc_ty: Type,
500) InnerError!*Inst {
501 const tracy = trace(@src());
502 defer tracy.end();
503 const val_payload = try block.arena.create(Value.Payload.InferredAlloc);
504 val_payload.* = .{
505 .data = .{},
506 };
507 // `Module.constInst` does not add the instruction to the block because it is
508 // not needed in the case of constant values. However here, we plan to "downgrade"
509 // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
510 // to the block even though it is currently a `.constant`.
511 const result = try sema.mod.constInst(scope, inst.base.src, .{
512 .ty = inferred_alloc_ty,
513 .val = Value.initPayload(&val_payload.base),
514 });
515 try sema.requireFunctionBlock(block, inst.base.src);
516 try block.instructions.append(sema.gpa, result);
517 return result;
518}
519
520fn zirResolveInferredAlloc(
521 sema: *Sema,
522 block: *Scope.Block,
523 inst: zir.Inst.Index,
524) InnerError!*Inst {
525 const tracy = trace(@src());
526 defer tracy.end();
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);
531 const ptr_val = ptr.castTag(.constant).?.val;
532 const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
533 const peer_inst_list = inferred_alloc.data.stored_inst_list.items;
534 const final_elem_ty = try sema.resolvePeerTypes(block, peer_inst_list);
535 const var_is_mut = switch (ptr.ty.tag()) {
536 .inferred_alloc_const => false,
537 .inferred_alloc_mut => true,
538 else => unreachable,
539 };
540 if (var_is_mut) {
541 try sema.validateVarType(block, ty_src, final_elem_ty);
542 }
543 const final_ptr_ty = try sema.mod.simplePtrType(block.arena, final_elem_ty, true, .One);
544
545 // Change it to a normal alloc.
546 ptr.ty = final_ptr_ty;
547 ptr.tag = .alloc;
548
549 return sema.mod.constVoid(block.arena, .unneeded);
550}
551
552fn zirStoreToBlockPtr(
553 sema: *Sema,
554 block: *Scope.Block,
555 inst: zir.Inst.Index,
556) InnerError!*Inst {
557 const tracy = trace(@src());
558 defer tracy.end();
559
560 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
561 const ptr = sema.resolveInst(bin_inst.lhs);
562 const value = sema.resolveInst(bin_inst.rhs);
563 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
564 // TODO detect when this store should be done at compile-time. For example,
565 // if expressions should force it when the condition is compile-time known.
566 try sema.requireRuntimeBlock(block, src);
567 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
568 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
569}
570
571fn zirStoreToInferredPtr(
572 sema: *Sema,
573 block: *Scope.Block,
574 inst: zir.Inst.Index,
575) InnerError!*Inst {
576 const tracy = trace(@src());
577 defer tracy.end();
578
579 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
580 const ptr = sema.resolveInst(bin_inst.lhs);
581 const value = sema.resolveInst(bin_inst.rhs);
582 const inferred_alloc = ptr.castTag(.constant).?.val.castTag(.inferred_alloc).?;
583 // Add the stored instruction to the set we will use to resolve peer types
584 // for the inferred allocation.
585 try inferred_alloc.data.stored_inst_list.append(block.arena, value);
586 // Create a runtime bitcast instruction with exactly the type the pointer wants.
587 const ptr_ty = try sema.mod.simplePtrType(block.arena, value.ty, true, .One);
588 try sema.requireRuntimeBlock(block, src);
589 const bitcasted_ptr = try block.addUnOp(inst.base.src, ptr_ty, .bitcast, ptr);
590 return mod.storePtr(scope, inst.base.src, bitcasted_ptr, value);
591}
592
593fn zirSetEvalBranchQuota(
594 sema: *Sema,
595 block: *Scope.Block,
596 inst: zir.Inst.Index,
597) InnerError!*Inst {
598 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
599 const src = inst_data.src();
600 try sema.requireFunctionBlock(block, src);
601 const quota = try sema.resolveAlreadyCoercedInt(block, src, inst_data.operand, u32);
602 if (b.branch_quota.* < quota)
603 b.branch_quota.* = quota;
604 return sema.mod.constVoid(block.arena, .unneeded);
605}
606
607fn zirStore(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
608 const tracy = trace(@src());
609 defer tracy.end();
610
611 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
612 const ptr = sema.resolveInst(bin_inst.lhs);
613 const value = sema.resolveInst(bin_inst.rhs);
614 return mod.storePtr(scope, inst.base.src, ptr, value);
615}
616
617fn zirParamType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
618 const tracy = trace(@src());
619 defer tracy.end();
620
621 const inst_data = sema.code.instructions.items(.data)[inst].param_type;
622 const fn_inst = sema.resolveInst(inst_data.callee);
623 const param_index = inst_data.param_index;
624
625 const fn_ty: Type = switch (fn_inst.ty.zigTypeTag()) {
626 .Fn => fn_inst.ty,
627 .BoundFn => {
628 return sema.mod.fail(&block.base, fn_inst.src, "TODO implement zirParamType for method call syntax", .{});
629 },
630 else => {
631 return sema.mod.fail(&block.base, fn_inst.src, "expected function, found '{}'", .{fn_inst.ty});
632 },
633 };
634
635 const param_count = fn_ty.fnParamLen();
636 if (param_index >= param_count) {
637 if (fn_ty.fnIsVarArgs()) {
638 return sema.mod.constType(block.arena, inst.base.src, Type.initTag(.var_args_param));
639 }
640 return sema.mod.fail(&block.base, inst.base.src, "arg index {d} out of bounds; '{}' has {d} argument(s)", .{
641 param_index,
642 fn_ty,
643 param_count,
644 });
645 }
646
647 // TODO support generic functions
648 const param_type = fn_ty.fnParamType(param_index);
649 return sema.mod.constType(block.arena, inst.base.src, param_type);
650}
651
652fn zirStr(sema: *Sema, block: *Scope.Block, str_inst: zir.Inst.Index) InnerError!*Inst {
653 const tracy = trace(@src());
654 defer tracy.end();
655
656 // The bytes references memory inside the ZIR module, which is fine. Multiple
657 // anonymous Decls may have strings which point to within the same ZIR module.
658 const bytes = sema.code.instructions.items(.data)[inst].str.get(sema.code);
659
660 var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
661 errdefer new_decl_arena.deinit();
662
663 const decl_ty = try Type.Tag.array_u8_sentinel_0.create(&new_decl_arena.allocator, bytes.len);
664 const decl_val = try Value.Tag.bytes.create(&new_decl_arena.allocator, bytes);
665
666 const new_decl = try sema.mod.createAnonymousDecl(&block.base, &new_decl_arena, .{
667 .ty = decl_ty,
668 .val = decl_val,
669 });
670 return sema.analyzeDeclRef(block, .unneeded, new_decl);
671}
672
673fn zirInt(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
674 const tracy = trace(@src());
675 defer tracy.end();
676
677 return mod.constIntBig(scope, inst.base.src, Type.initTag(.comptime_int), inst.positionals.int);
678}
679
680fn zirCompileError(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
681 const tracy = trace(@src());
682 defer tracy.end();
683
684 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
685 const src = inst_data.src();
686 const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
687 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand);
688 return sema.mod.fail(&block.base, src, "{s}", .{msg});
689}
690
691fn zirCompileLog(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
692 var managed = mod.compile_log_text.toManaged(mod.gpa);
693 defer mod.compile_log_text = managed.moveToUnmanaged();
694 const writer = managed.writer();
695
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| {
699 if (i != 0) try writer.print(", ", .{});
700
701 const arg = sema.resolveInst(block, arg_ref);
702 if (arg.value()) |val| {
703 try writer.print("@as({}, {})", .{ arg.ty, val });
704 } else {
705 try writer.print("@as({}, [runtime value])", .{arg.ty});
706 }
707 }
708 try writer.print("\n", .{});
709
710 const gop = try mod.compile_log_decls.getOrPut(mod.gpa, scope.ownerDecl().?);
711 if (!gop.found_existing) {
712 gop.entry.value = .{
713 .file_scope = block.getFileScope(),
714 .lazy = inst_data.src(),
715 };
716 }
717 return sema.mod.constVoid(block.arena, .unneeded);
718}
719
720fn zirLoop(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
721 const tracy = trace(@src());
722 defer tracy.end();
723
724 // Reserve space for a Loop instruction so that generated Break instructions can
725 // point to it, even if it doesn't end up getting used because the code ends up being
726 // comptime evaluated.
727 const loop_inst = try parent_block.arena.create(Inst.Loop);
728 loop_inst.* = .{
729 .base = .{
730 .tag = Inst.Loop.base_tag,
731 .ty = Type.initTag(.noreturn),
732 .src = inst.base.src,
733 },
734 .body = undefined,
735 };
736
737 var child_block: Scope.Block = .{
738 .parent = parent_block,
739 .inst_table = parent_block.inst_table,
740 .func = parent_block.func,
741 .owner_decl = parent_block.owner_decl,
742 .src_decl = parent_block.src_decl,
743 .instructions = .{},
744 .arena = parent_block.arena,
745 .inlining = parent_block.inlining,
746 .is_comptime = parent_block.is_comptime,
747 .branch_quota = parent_block.branch_quota,
748 };
749 defer child_block.instructions.deinit(mod.gpa);
750
751 try sema.body(&child_block, inst.positionals.body);
752
753 // Loop repetition is implied so the last instruction may or may not be a noreturn instruction.
754
755 try parent_block.instructions.append(mod.gpa, &loop_inst.base);
756 loop_inst.body = .{ .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items) };
757 return &loop_inst.base;
758}
759
760fn zirBlockFlat(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index, is_comptime: bool) InnerError!*Inst {
761 const tracy = trace(@src());
762 defer tracy.end();
763
764 var child_block = parent_block.makeSubBlock();
765 defer child_block.instructions.deinit(mod.gpa);
766 child_block.is_comptime = child_block.is_comptime or is_comptime;
767
768 try sema.body(&child_block, inst.positionals.body);
769
770 // Move the analyzed instructions into the parent block arena.
771 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
772 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
773
774 // The result of a flat block is the last instruction.
775 const zir_inst_list = inst.positionals.body.instructions;
776 const last_zir_inst = zir_inst_list[zir_inst_list.len - 1];
777 return sema.inst_map[last_zir_inst];
778}
779
780fn zirBlock(
781 sema: *Sema,
782 parent_block: *Scope.Block,
783 inst: zir.Inst.Index,
784 is_comptime: bool,
785) InnerError!*Inst {
786 const tracy = trace(@src());
787 defer tracy.end();
788
789 // Reserve space for a Block instruction so that generated Break instructions can
790 // point to it, even if it doesn't end up getting used because the code ends up being
791 // comptime evaluated.
792 const block_inst = try parent_block.arena.create(Inst.Block);
793 block_inst.* = .{
794 .base = .{
795 .tag = Inst.Block.base_tag,
796 .ty = undefined, // Set after analysis.
797 .src = inst.base.src,
798 },
799 .body = undefined,
800 };
801
802 var child_block: Scope.Block = .{
803 .parent = parent_block,
804 .inst_table = parent_block.inst_table,
805 .func = parent_block.func,
806 .owner_decl = parent_block.owner_decl,
807 .src_decl = parent_block.src_decl,
808 .instructions = .{},
809 .arena = parent_block.arena,
810 // TODO @as here is working around a stage1 miscompilation bug :(
811 .label = @as(?Scope.Block.Label, Scope.Block.Label{
812 .zir_block = inst,
813 .merges = .{
814 .results = .{},
815 .br_list = .{},
816 .block_inst = block_inst,
817 },
818 }),
819 .inlining = parent_block.inlining,
820 .is_comptime = is_comptime or parent_block.is_comptime,
821 .branch_quota = parent_block.branch_quota,
822 };
823 const merges = &child_block.label.?.merges;
824
825 defer child_block.instructions.deinit(mod.gpa);
826 defer merges.results.deinit(mod.gpa);
827 defer merges.br_list.deinit(mod.gpa);
828
829 try sema.body(&child_block, inst.positionals.body);
830
831 return analyzeBlockBody(mod, scope, &child_block, merges);
832}
833
834fn analyzeBlockBody(
835 sema: *Sema,
836 parent_block: *Scope.Block,
837 child_block: *Scope.Block,
838 merges: *Scope.Block.Merges,
839) InnerError!*Inst {
840 const tracy = trace(@src());
841 defer tracy.end();
842
843 // Blocks must terminate with noreturn instruction.
844 assert(child_block.instructions.items.len != 0);
845 assert(child_block.instructions.items[child_block.instructions.items.len - 1].ty.isNoReturn());
846
847 if (merges.results.items.len == 0) {
848 // No need for a block instruction. We can put the new instructions
849 // directly into the parent block.
850 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items);
851 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
852 return copied_instructions[copied_instructions.len - 1];
853 }
854 if (merges.results.items.len == 1) {
855 const last_inst_index = child_block.instructions.items.len - 1;
856 const last_inst = child_block.instructions.items[last_inst_index];
857 if (last_inst.breakBlock()) |br_block| {
858 if (br_block == merges.block_inst) {
859 // No need for a block instruction. We can put the new instructions directly
860 // into the parent block. Here we omit the break instruction.
861 const copied_instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items[0..last_inst_index]);
862 try parent_block.instructions.appendSlice(mod.gpa, copied_instructions);
863 return merges.results.items[0];
864 }
865 }
866 }
867 // It is impossible to have the number of results be > 1 in a comptime scope.
868 assert(!child_block.is_comptime); // Should already got a compile error in the condbr condition.
869
870 // Need to set the type and emit the Block instruction. This allows machine code generation
871 // to emit a jump instruction to after the block when it encounters the break.
872 try parent_block.instructions.append(mod.gpa, &merges.block_inst.base);
873 const resolved_ty = try sema.resolvePeerTypes(parent_block, merges.results.items);
874 merges.block_inst.base.ty = resolved_ty;
875 merges.block_inst.body = .{
876 .instructions = try parent_block.arena.dupe(*Inst, child_block.instructions.items),
877 };
878 // Now that the block has its type resolved, we need to go back into all the break
879 // instructions, and insert type coercion on the operands.
880 for (merges.br_list.items) |br| {
881 if (br.operand.ty.eql(resolved_ty)) {
882 // No type coercion needed.
883 continue;
884 }
885 var coerce_block = parent_block.makeSubBlock();
886 defer coerce_block.instructions.deinit(mod.gpa);
887 const coerced_operand = try sema.coerce(&coerce_block.base, resolved_ty, br.operand);
888 // If no instructions were produced, such as in the case of a coercion of a
889 // constant value to a new type, we can simply point the br operand to it.
890 if (coerce_block.instructions.items.len == 0) {
891 br.operand = coerced_operand;
892 continue;
893 }
894 assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1] == coerced_operand);
895 // Here we depend on the br instruction having been over-allocated (if necessary)
896 // inide analyzeBreak so that it can be converted into a br_block_flat instruction.
897 const br_src = br.base.src;
898 const br_ty = br.base.ty;
899 const br_block_flat = @ptrCast(*Inst.BrBlockFlat, br);
900 br_block_flat.* = .{
901 .base = .{
902 .src = br_src,
903 .ty = br_ty,
904 .tag = .br_block_flat,
905 },
906 .block = merges.block_inst,
907 .body = .{
908 .instructions = try parent_block.arena.dupe(*Inst, coerce_block.instructions.items),
909 },
910 };
911 }
912 return &merges.block_inst.base;
913}
914
915fn zirBreakpoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
916 const tracy = trace(@src());
917 defer tracy.end();
918
919 try sema.requireRuntimeBlock(block, src);
920 return block.addNoOp(inst.base.src, Type.initTag(.void), .breakpoint);
921}
922
923fn zirBreak(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
924 const tracy = trace(@src());
925 defer tracy.end();
926
927 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
928 const operand = sema.resolveInst(block, bin_inst.rhs);
929 const zir_block = bin_inst.lhs;
930 return analyzeBreak(mod, block, sema.src, zir_block, operand);
931}
932
933fn zirBreakVoidTok(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
934 const tracy = trace(@src());
935 defer tracy.end();
936
937 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
938 const zir_block = inst_data.operand;
939 const void_inst = try sema.mod.constVoid(block.arena, .unneeded);
940 return analyzeBreak(mod, block, inst_data.src(), zir_block, void_inst);
941}
942
943fn analyzeBreak(
944 sema: *Sema,
945 block: *Scope.Block,
946 src: LazySrcLoc,
947 zir_block: zir.Inst.Index,
948 operand: *Inst,
949) InnerError!*Inst {
950 var opt_block = scope.cast(Scope.Block);
951 while (opt_block) |block| {
952 if (block.label) |*label| {
953 if (label.zir_block == zir_block) {
954 try sema.requireFunctionBlock(block, src);
955 // Here we add a br instruction, but we over-allocate a little bit
956 // (if necessary) to make it possible to convert the instruction into
957 // a br_block_flat instruction later.
958 const br = @ptrCast(*Inst.Br, try b.arena.alignedAlloc(
959 u8,
960 Inst.convertable_br_align,
961 Inst.convertable_br_size,
962 ));
963 br.* = .{
964 .base = .{
965 .tag = .br,
966 .ty = Type.initTag(.noreturn),
967 .src = src,
968 },
969 .operand = operand,
970 .block = label.merges.block_inst,
971 };
972 try b.instructions.append(mod.gpa, &br.base);
973 try label.merges.results.append(mod.gpa, operand);
974 try label.merges.br_list.append(mod.gpa, br);
975 return &br.base;
976 }
977 }
978 opt_block = block.parent;
979 } else unreachable;
980}
981
982fn zirDbgStmtNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
983 const tracy = trace(@src());
984 defer tracy.end();
985
986 if (b.is_comptime) {
987 return sema.mod.constVoid(block.arena, .unneeded);
988 }
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);
993}
994
995fn zirDeclRef(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
996 const tracy = trace(@src());
997 defer tracy.end();
998
999 const decl = sema.code.instructions.items(.data)[inst].decl;
1000 return sema.analyzeDeclRef(block, .unneeded, decl);
1001}
1002
1003fn zirDeclVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1004 const tracy = trace(@src());
1005 defer tracy.end();
1006
1007 const decl = sema.code.instructions.items(.data)[inst].decl;
1008 return sema.analyzeDeclVal(block, .unneeded, decl);
1009}
1010
1011fn zirCallNone(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1012 const tracy = trace(@src());
1013 defer tracy.end();
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, &.{});
1019}
1020
1021fn zirCall(
1022 sema: *Sema,
1023 block: *Scope.Block,
1024 inst: zir.Inst.Index,
1025 modifier: std.builtin.CallOptions.Modifier,
1026) InnerError!*Inst {
1027 const tracy = trace(@src());
1028 defer tracy.end();
1029
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
1050 if (func.ty.zigTypeTag() != .Fn)
1051 return sema.mod.fail(&block.base, func_src, "type '{}' not a function", .{func.ty});
1052
1053 const cc = func.ty.fnCallingConvention();
1054 if (cc == .Naked) {
1055 // TODO add error note: declared here
1056 return sema.mod.fail(
1057 &block.base,
1058 func_src,
1059 "unable to call function with naked calling convention",
1060 .{},
1061 );
1062 }
1063 const fn_params_len = func.ty.fnParamLen();
1064 if (func.ty.fnIsVarArgs()) {
1065 assert(cc == .C);
1066 if (zir_args.len < fn_params_len) {
1067 // TODO add error note: declared here
1068 return sema.mod.fail(
1069 &block.base,
1070 func_src,
1071 "expected at least {d} argument(s), found {d}",
1072 .{ fn_params_len, zir_args.len },
1073 );
1074 }
1075 } else if (fn_params_len != zir_args.len) {
1076 // TODO add error note: declared here
1077 return sema.mod.fail(
1078 &block.base,
1079 func_src,
1080 "expected {d} argument(s), found {d}",
1081 .{ fn_params_len, zir_args.len },
1082 );
1083 }
1084
1085 if (modifier == .compile_time) {
1086 return sema.mod.fail(&block.base, call_src, "TODO implement comptime function calls", .{});
1087 }
1088 if (modifier != .auto) {
1089 return sema.mod.fail(&block.base, call_src, "TODO implement call with modifier {}", .{inst.positionals.modifier});
1090 }
1091
1092 // TODO handle function calls of generic functions
1093 const casted_args = try block.arena.alloc(*Inst, zir_args.len);
1094 for (zir_args) |zir_arg, i| {
1095 // the args are already casted to the result of a param type instruction.
1096 casted_args[i] = sema.resolveInst(block, zir_arg);
1097 }
1098
1099 const ret_type = func.ty.fnReturnType();
1100
1101 try sema.requireFunctionBlock(block, call_src);
1102 const is_comptime_call = b.is_comptime or modifier == .compile_time;
1103 const is_inline_call = is_comptime_call or modifier == .always_inline or
1104 func.ty.fnCallingConvention() == .Inline;
1105 if (is_inline_call) {
1106 const func_val = try sema.resolveConstValue(block, func_src, func);
1107 const module_fn = switch (func_val.tag()) {
1108 .function => func_val.castTag(.function).?.data,
1109 .extern_fn => return sema.mod.fail(&block.base, call_src, "{s} call of extern function", .{
1110 @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
1111 }),
1112 else => unreachable,
1113 };
1114
1115 // Analyze the ZIR. The same ZIR gets analyzed into a runtime function
1116 // or an inlined call depending on what union tag the `label` field is
1117 // set to in the `Scope.Block`.
1118 // This block instruction will be used to capture the return value from the
1119 // inlined function.
1120 const block_inst = try block.arena.create(Inst.Block);
1121 block_inst.* = .{
1122 .base = .{
1123 .tag = Inst.Block.base_tag,
1124 .ty = ret_type,
1125 .src = call_src,
1126 },
1127 .body = undefined,
1128 };
1129 // If this is the top of the inline/comptime call stack, we use this data.
1130 // Otherwise we pass on the shared data from the parent scope.
1131 var shared_inlining: Scope.Block.Inlining.Shared = .{
1132 .branch_count = 0,
1133 .caller = b.func,
1134 };
1135 // This one is shared among sub-blocks within the same callee, but not
1136 // shared among the entire inline/comptime call stack.
1137 var inlining: Scope.Block.Inlining = .{
1138 .shared = if (b.inlining) |inlining| inlining.shared else &shared_inlining,
1139 .param_index = 0,
1140 .casted_args = casted_args,
1141 .merges = .{
1142 .results = .{},
1143 .br_list = .{},
1144 .block_inst = block_inst,
1145 },
1146 };
1147 var inst_table = Scope.Block.InstTable.init(mod.gpa);
1148 defer inst_table.deinit();
1149
1150 var child_block: Scope.Block = .{
1151 .parent = null,
1152 .inst_table = &inst_table,
1153 .func = module_fn,
1154 .owner_decl = scope.ownerDecl().?,
1155 .src_decl = module_fn.owner_decl,
1156 .instructions = .{},
1157 .arena = block.arena,
1158 .label = null,
1159 .inlining = &inlining,
1160 .is_comptime = is_comptime_call,
1161 .branch_quota = b.branch_quota,
1162 };
1163
1164 const merges = &child_block.inlining.?.merges;
1165
1166 defer child_block.instructions.deinit(mod.gpa);
1167 defer merges.results.deinit(mod.gpa);
1168 defer merges.br_list.deinit(mod.gpa);
1169
1170 try mod.emitBackwardBranch(&child_block, call_src);
1171
1172 // This will have return instructions analyzed as break instructions to
1173 // the block_inst above.
1174 try sema.body(&child_block, module_fn.zir);
1175
1176 return analyzeBlockBody(mod, scope, &child_block, merges);
1177 }
1178
1179 return block.addCall(call_src, ret_type, func, casted_args);
1180}
1181
1182fn zirIntType(sema: *Sema, block: *Scope.Block, inttype: zir.Inst.Index) InnerError!*Inst {
1183 const tracy = trace(@src());
1184 defer tracy.end();
1185 return sema.mod.fail(&block.base, inttype.base.src, "TODO implement inttype", .{});
1186}
1187
1188fn zirOptionalType(sema: *Sema, block: *Scope.Block, optional: zir.Inst.Index) InnerError!*Inst {
1189 const tracy = trace(@src());
1190 defer tracy.end();
1191
1192 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1193 const child_type = try sema.resolveType(block, inst_data.operand);
1194 const opt_type = try mod.optionalType(block.arena, child_type);
1195
1196 return sema.mod.constType(block.arena, inst_data.src(), opt_type);
1197}
1198
1199fn zirOptionalTypeFromPtrElem(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1200 const tracy = trace(@src());
1201 defer tracy.end();
1202
1203 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1204 const ptr = sema.resolveInst(block, inst_data.operand);
1205 const elem_ty = ptr.ty.elemType();
1206 const opt_ty = try mod.optionalType(block.arena, elem_ty);
1207
1208 return sema.mod.constType(block.arena, inst_data.src(), opt_ty);
1209}
1210
1211fn zirArrayType(sema: *Sema, block: *Scope.Block, array: zir.Inst.Index) InnerError!*Inst {
1212 const tracy = trace(@src());
1213 defer tracy.end();
1214 // TODO these should be lazily evaluated
1215 const len = try resolveInstConst(mod, scope, array.positionals.lhs);
1216 const elem_type = try sema.resolveType(block, array.positionals.rhs);
1217
1218 return sema.mod.constType(block.arena, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), null, elem_type));
1219}
1220
1221fn zirArrayTypeSentinel(sema: *Sema, block: *Scope.Block, array: zir.Inst.Index) InnerError!*Inst {
1222 const tracy = trace(@src());
1223 defer tracy.end();
1224 // TODO these should be lazily evaluated
1225 const len = try resolveInstConst(mod, scope, array.positionals.len);
1226 const sentinel = try resolveInstConst(mod, scope, array.positionals.sentinel);
1227 const elem_type = try sema.resolveType(block, array.positionals.elem_type);
1228
1229 return sema.mod.constType(block.arena, array.base.src, try mod.arrayType(scope, len.val.toUnsignedInt(), sentinel.val, elem_type));
1230}
1231
1232fn zirErrorUnionType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1233 const tracy = trace(@src());
1234 defer tracy.end();
1235
1236 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1237 const error_union = try sema.resolveType(block, bin_inst.lhs);
1238 const payload = try sema.resolveType(block, bin_inst.rhs);
1239
1240 if (error_union.zigTypeTag() != .ErrorSet) {
1241 return sema.mod.fail(&block.base, inst.base.src, "expected error set type, found {}", .{error_union.elemType()});
1242 }
1243
1244 return sema.mod.constType(block.arena, inst.base.src, try mod.errorUnionType(scope, error_union, payload));
1245}
1246
1247fn zirAnyframeType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1248 const tracy = trace(@src());
1249 defer tracy.end();
1250
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);
1258}
1259
1260fn zirErrorSet(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1261 const tracy = trace(@src());
1262 defer tracy.end();
1263
1264 // The owner Decl arena will store the hashmap.
1265 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1266 errdefer new_decl_arena.deinit();
1267
1268 const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
1269 payload.* = .{
1270 .base = .{ .tag = .error_set },
1271 .data = .{
1272 .fields = .{},
1273 .decl = undefined, // populated below
1274 },
1275 };
1276 try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, inst.positionals.fields.len));
1277
1278 for (inst.positionals.fields) |field_name| {
1279 const entry = try mod.getErrorValue(field_name);
1280 if (payload.data.fields.fetchPutAssumeCapacity(entry.key, {})) |_| {
1281 return sema.mod.fail(&block.base, inst.base.src, "duplicate error: '{s}'", .{field_name});
1282 }
1283 }
1284 // TODO create name in format "error:line:column"
1285 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1286 .ty = Type.initTag(.type),
1287 .val = Value.initPayload(&payload.base),
1288 });
1289 payload.data.decl = new_decl;
1290 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1291}
1292
1293fn zirErrorValue(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1294 const tracy = trace(@src());
1295 defer tracy.end();
1296
1297 // Create an anonymous error set type with only this error value, and return the value.
1298 const entry = try mod.getErrorValue(inst.positionals.name);
1299 const result_type = try Type.Tag.error_set_single.create(block.arena, entry.key);
1300 return sema.mod.constInst(scope, inst.base.src, .{
1301 .ty = result_type,
1302 .val = try Value.Tag.@"error".create(block.arena, .{
1303 .name = entry.key,
1304 }),
1305 });
1306}
1307
1308fn zirMergeErrorSets(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1309 const tracy = trace(@src());
1310 defer tracy.end();
1311
1312 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1313 const lhs_ty = try sema.resolveType(block, bin_inst.lhs);
1314 const rhs_ty = try sema.resolveType(block, bin_inst.rhs);
1315 if (rhs_ty.zigTypeTag() != .ErrorSet)
1316 return sema.mod.fail(&block.base, inst.positionals.rhs.src, "expected error set type, found {}", .{rhs_ty});
1317 if (lhs_ty.zigTypeTag() != .ErrorSet)
1318 return sema.mod.fail(&block.base, inst.positionals.lhs.src, "expected error set type, found {}", .{lhs_ty});
1319
1320 // anything merged with anyerror is anyerror
1321 if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror)
1322 return sema.mod.constInst(scope, inst.base.src, .{
1323 .ty = Type.initTag(.type),
1324 .val = Value.initTag(.anyerror_type),
1325 });
1326 // The declarations arena will store the hashmap.
1327 var new_decl_arena = std.heap.ArenaAllocator.init(mod.gpa);
1328 errdefer new_decl_arena.deinit();
1329
1330 const payload = try new_decl_arena.allocator.create(Value.Payload.ErrorSet);
1331 payload.* = .{
1332 .base = .{ .tag = .error_set },
1333 .data = .{
1334 .fields = .{},
1335 .decl = undefined, // populated below
1336 },
1337 };
1338 try payload.data.fields.ensureCapacity(&new_decl_arena.allocator, @intCast(u32, switch (rhs_ty.tag()) {
1339 .error_set_single => 1,
1340 .error_set => rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1341 else => unreachable,
1342 } + switch (lhs_ty.tag()) {
1343 .error_set_single => 1,
1344 .error_set => lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields.size,
1345 else => unreachable,
1346 }));
1347
1348 switch (lhs_ty.tag()) {
1349 .error_set_single => {
1350 const name = lhs_ty.castTag(.error_set_single).?.data;
1351 payload.data.fields.putAssumeCapacity(name, {});
1352 },
1353 .error_set => {
1354 var multiple = lhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1355 var it = multiple.iterator();
1356 while (it.next()) |entry| {
1357 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1358 }
1359 },
1360 else => unreachable,
1361 }
1362
1363 switch (rhs_ty.tag()) {
1364 .error_set_single => {
1365 const name = rhs_ty.castTag(.error_set_single).?.data;
1366 payload.data.fields.putAssumeCapacity(name, {});
1367 },
1368 .error_set => {
1369 var multiple = rhs_ty.castTag(.error_set).?.data.typed_value.most_recent.typed_value.val.castTag(.error_set).?.data.fields;
1370 var it = multiple.iterator();
1371 while (it.next()) |entry| {
1372 payload.data.fields.putAssumeCapacity(entry.key, entry.value);
1373 }
1374 },
1375 else => unreachable,
1376 }
1377 // TODO create name in format "error:line:column"
1378 const new_decl = try mod.createAnonymousDecl(scope, &new_decl_arena, .{
1379 .ty = Type.initTag(.type),
1380 .val = Value.initPayload(&payload.base),
1381 });
1382 payload.data.decl = new_decl;
1383
1384 return mod.analyzeDeclVal(scope, inst.base.src, new_decl);
1385}
1386
1387fn zirEnumLiteral(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
1388 const tracy = trace(@src());
1389 defer tracy.end();
1390
1391 const duped_name = try block.arena.dupe(u8, inst.positionals.name);
1392 return sema.mod.constInst(scope, inst.base.src, .{
1393 .ty = Type.initTag(.enum_literal),
1394 .val = try Value.Tag.enum_literal.create(block.arena, duped_name),
1395 });
1396}
1397
1398/// Pointer in, pointer out.
1399fn zirOptionalPayloadPtr(
1400 sema: *Sema,
1401 block: *Scope.Block,
1402 inst: zir.Inst.Index,
1403 safety_check: bool,
1404) InnerError!*Inst {
1405 const tracy = trace(@src());
1406 defer tracy.end();
1407
1408 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
1409 const optional_ptr = sema.resolveInst(block, inst_data.operand);
1410 assert(optional_ptr.ty.zigTypeTag() == .Pointer);
1411 const src = inst_data.src();
1412
1413 const opt_type = optional_ptr.ty.elemType();
1414 if (opt_type.zigTypeTag() != .Optional) {
1415 return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
1416 }
1417
1418 const child_type = try opt_type.optionalChildAlloc(block.arena);
1419 const child_pointer = try sema.mod.simplePtrType(block.arena, child_type, !optional_ptr.ty.isConstPtr(), .One);
1420
1421 if (optional_ptr.value()) |pointer_val| {
1422 const val = try pointer_val.pointerDeref(block.arena);
1423 if (val.isNull()) {
1424 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
1425 }
1426 // The same Value represents the pointer to the optional and the payload.
1427 return sema.mod.constInst(scope, src, .{
1428 .ty = child_pointer,
1429 .val = pointer_val,
1430 });
1431 }
1432
1433 try sema.requireRuntimeBlock(block, src);
1434 if (safety_check and block.wantSafety()) {
1435 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null_ptr, optional_ptr);
1436 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
1437 }
1438 return block.addUnOp(src, child_pointer, .optional_payload_ptr, optional_ptr);
1439}
1440
1441/// Value in, value out.
1442fn zirOptionalPayload(
1443 sema: *Sema,
1444 block: *Scope.Block,
1445 inst: zir.Inst.Index,
1446 safety_check: bool,
1447) InnerError!*Inst {
1448 const tracy = trace(@src());
1449 defer tracy.end();
1450
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);
1454 const opt_type = operand.ty;
1455 if (opt_type.zigTypeTag() != .Optional) {
1456 return sema.mod.fail(&block.base, src, "expected optional type, found {}", .{opt_type});
1457 }
1458
1459 const child_type = try opt_type.optionalChildAlloc(block.arena);
1460
1461 if (operand.value()) |val| {
1462 if (val.isNull()) {
1463 return sema.mod.fail(&block.base, src, "unable to unwrap null", .{});
1464 }
1465 return sema.mod.constInst(scope, src, .{
1466 .ty = child_type,
1467 .val = val,
1468 });
1469 }
1470
1471 try sema.requireRuntimeBlock(block, src);
1472 if (safety_check and block.wantSafety()) {
1473 const is_non_null = try block.addUnOp(src, Type.initTag(.bool), .is_non_null, operand);
1474 try mod.addSafetyCheck(b, is_non_null, .unwrap_null);
1475 }
1476 return block.addUnOp(src, child_type, .optional_payload, operand);
1477}
1478
1479/// Value in, value out
1480fn zirErrUnionPayload(
1481 sema: *Sema,
1482 block: *Scope.Block,
1483 inst: zir.Inst.Index,
1484 safety_check: bool,
1485) InnerError!*Inst {
1486 const tracy = trace(@src());
1487 defer tracy.end();
1488
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);
1492 if (operand.ty.zigTypeTag() != .ErrorUnion)
1493 return sema.mod.fail(&block.base, operand.src, "expected error union type, found '{}'", .{operand.ty});
1494
1495 if (operand.value()) |val| {
1496 if (val.getError()) |name| {
1497 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
1498 }
1499 const data = val.castTag(.error_union).?.data;
1500 return sema.mod.constInst(scope, src, .{
1501 .ty = operand.ty.castTag(.error_union).?.data.payload,
1502 .val = data,
1503 });
1504 }
1505 try sema.requireRuntimeBlock(block, src);
1506 if (safety_check and block.wantSafety()) {
1507 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
1508 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
1509 }
1510 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_payload, operand);
1511}
1512
1513/// Pointer in, pointer out.
1514fn zirErrUnionPayloadPtr(
1515 sema: *Sema,
1516 block: *Scope.Block,
1517 inst: zir.Inst.Index,
1518 safety_check: bool,
1519) InnerError!*Inst {
1520 const tracy = trace(@src());
1521 defer tracy.end();
1522
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);
1526 assert(operand.ty.zigTypeTag() == .Pointer);
1527
1528 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
1529 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
1530
1531 const operand_pointer_ty = try sema.mod.simplePtrType(block.arena, operand.ty.elemType().castTag(.error_union).?.data.payload, !operand.ty.isConstPtr(), .One);
1532
1533 if (operand.value()) |pointer_val| {
1534 const val = try pointer_val.pointerDeref(block.arena);
1535 if (val.getError()) |name| {
1536 return sema.mod.fail(&block.base, src, "caught unexpected error '{s}'", .{name});
1537 }
1538 const data = val.castTag(.error_union).?.data;
1539 // The same Value represents the pointer to the error union and the payload.
1540 return sema.mod.constInst(scope, src, .{
1541 .ty = operand_pointer_ty,
1542 .val = try Value.Tag.ref_val.create(
1543 block.arena,
1544 data,
1545 ),
1546 });
1547 }
1548
1549 try sema.requireRuntimeBlock(block, src);
1550 if (safety_check and block.wantSafety()) {
1551 const is_non_err = try block.addUnOp(src, Type.initTag(.bool), .is_err, operand);
1552 try mod.addSafetyCheck(b, is_non_err, .unwrap_errunion);
1553 }
1554 return block.addUnOp(src, operand_pointer_ty, .unwrap_errunion_payload_ptr, operand);
1555}
1556
1557/// Value in, value out
1558fn zirErrUnionCode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1559 const tracy = trace(@src());
1560 defer tracy.end();
1561
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);
1565 if (operand.ty.zigTypeTag() != .ErrorUnion)
1566 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
1567
1568 if (operand.value()) |val| {
1569 assert(val.getError() != null);
1570 const data = val.castTag(.error_union).?.data;
1571 return sema.mod.constInst(scope, src, .{
1572 .ty = operand.ty.castTag(.error_union).?.data.error_set,
1573 .val = data,
1574 });
1575 }
1576
1577 try sema.requireRuntimeBlock(block, src);
1578 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err, operand);
1579}
1580
1581/// Pointer in, value out
1582fn zirErrUnionCodePtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1583 const tracy = trace(@src());
1584 defer tracy.end();
1585
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);
1589 assert(operand.ty.zigTypeTag() == .Pointer);
1590
1591 if (operand.ty.elemType().zigTypeTag() != .ErrorUnion)
1592 return sema.mod.fail(&block.base, src, "expected error union type, found {}", .{operand.ty.elemType()});
1593
1594 if (operand.value()) |pointer_val| {
1595 const val = try pointer_val.pointerDeref(block.arena);
1596 assert(val.getError() != null);
1597 const data = val.castTag(.error_union).?.data;
1598 return sema.mod.constInst(scope, src, .{
1599 .ty = operand.ty.elemType().castTag(.error_union).?.data.error_set,
1600 .val = data,
1601 });
1602 }
1603
1604 try sema.requireRuntimeBlock(block, src);
1605 return block.addUnOp(src, operand.ty.castTag(.error_union).?.data.payload, .unwrap_errunion_err_ptr, operand);
1606}
1607
1608fn zirEnsureErrPayloadVoid(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1609 const tracy = trace(@src());
1610 defer tracy.end();
1611
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);
1615 if (operand.ty.zigTypeTag() != .ErrorUnion)
1616 return sema.mod.fail(&block.base, src, "expected error union type, found '{}'", .{operand.ty});
1617 if (operand.ty.castTag(.error_union).?.data.payload.zigTypeTag() != .Void) {
1618 return sema.mod.fail(&block.base, src, "expression value is ignored", .{});
1619 }
1620 return sema.mod.constVoid(block.arena, .unneeded);
1621}
1622
1623fn zirFnType(sema: *Sema, block: *Scope.Block, fntype: zir.Inst.Index, var_args: bool) InnerError!*Inst {
1624 const tracy = trace(@src());
1625 defer tracy.end();
1626
1627 return fnTypeCommon(
1628 mod,
1629 scope,
1630 &fntype.base,
1631 fntype.positionals.param_types,
1632 fntype.positionals.return_type,
1633 .Unspecified,
1634 var_args,
1635 );
1636}
1637
1638fn zirFnTypeCc(sema: *Sema, block: *Scope.Block, fntype: zir.Inst.Index, var_args: bool) InnerError!*Inst {
1639 const tracy = trace(@src());
1640 defer tracy.end();
1641
1642 const cc_tv = try resolveInstConst(mod, scope, fntype.positionals.cc);
1643 // TODO once we're capable of importing and analyzing decls from
1644 // std.builtin, this needs to change
1645 const cc_str = cc_tv.val.castTag(.enum_literal).?.data;
1646 const cc = std.meta.stringToEnum(std.builtin.CallingConvention, cc_str) orelse
1647 return sema.mod.fail(&block.base, fntype.positionals.cc.src, "Unknown calling convention {s}", .{cc_str});
1648 return fnTypeCommon(
1649 mod,
1650 scope,
1651 &fntype.base,
1652 fntype.positionals.param_types,
1653 fntype.positionals.return_type,
1654 cc,
1655 var_args,
1656 );
1657}
1658
1659fn fnTypeCommon(
1660 sema: *Sema,
1661 block: *Scope.Block,
1662 zir_inst: zir.Inst.Index,
1663 zir_param_types: []zir.Inst.Index,
1664 zir_return_type: zir.Inst.Index,
1665 cc: std.builtin.CallingConvention,
1666 var_args: bool,
1667) InnerError!*Inst {
1668 const return_type = try sema.resolveType(block, zir_return_type);
1669
1670 // Hot path for some common function types.
1671 if (zir_param_types.len == 0 and !var_args) {
1672 if (return_type.zigTypeTag() == .NoReturn and cc == .Unspecified) {
1673 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_noreturn_no_args));
1674 }
1675
1676 if (return_type.zigTypeTag() == .Void and cc == .Unspecified) {
1677 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_void_no_args));
1678 }
1679
1680 if (return_type.zigTypeTag() == .NoReturn and cc == .Naked) {
1681 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_naked_noreturn_no_args));
1682 }
1683
1684 if (return_type.zigTypeTag() == .Void and cc == .C) {
1685 return sema.mod.constType(block.arena, zir_inst.src, Type.initTag(.fn_ccc_void_no_args));
1686 }
1687 }
1688
1689 const param_types = try block.arena.alloc(Type, zir_param_types.len);
1690 for (zir_param_types) |param_type, i| {
1691 const resolved = try sema.resolveType(block, param_type);
1692 // TODO skip for comptime params
1693 if (!resolved.isValidVarType(false)) {
1694 return sema.mod.fail(&block.base, param_type.src, "parameter of type '{}' must be declared comptime", .{resolved});
1695 }
1696 param_types[i] = resolved;
1697 }
1698
1699 const fn_ty = try Type.Tag.function.create(block.arena, .{
1700 .param_types = param_types,
1701 .return_type = return_type,
1702 .cc = cc,
1703 .is_var_args = var_args,
1704 });
1705 return sema.mod.constType(block.arena, zir_inst.src, fn_ty);
1706}
1707
1708fn zirAs(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1709 const tracy = trace(@src());
1710 defer tracy.end();
1711
1712 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1713 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1714 const tzir_inst = sema.resolveInst(block, bin_inst.rhs);
1715 return sema.coerce(scope, dest_type, tzir_inst);
1716}
1717
1718fn zirPtrtoint(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1719 const tracy = trace(@src());
1720 defer tracy.end();
1721
1722 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
1723 const ptr = sema.resolveInst(block, inst_data.operand);
1724 if (ptr.ty.zigTypeTag() != .Pointer) {
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});
1727 }
1728 // TODO handle known-pointer-address
1729 const src = inst_data.src();
1730 try sema.requireRuntimeBlock(block, src);
1731 const ty = Type.initTag(.usize);
1732 return block.addUnOp(src, ty, .ptrtoint, ptr);
1733}
1734
1735fn zirFieldVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1736 const tracy = trace(@src());
1737 defer tracy.end();
1738
1739 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1740 const src = inst_data.src();
1741 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1742 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1743 const field_name = sema.code.string_bytes[extra.field_name_start..][0..extra.field_name_len];
1744 const object = sema.resolveInst(block, extra.lhs);
1745 const object_ptr = try sema.analyzeRef(block, src, object);
1746 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1747 return sema.analyzeDeref(block, src, result_ptr, result_ptr.src);
1748}
1749
1750fn zirFieldPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1751 const tracy = trace(@src());
1752 defer tracy.end();
1753
1754 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1755 const src = inst_data.src();
1756 const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
1757 const extra = sema.code.extraData(zir.Inst.Field, inst_data.payload_index).data;
1758 const field_name = sema.code.string_bytes[extra.field_name_start..][0..extra.field_name_len];
1759 const object_ptr = sema.resolveInst(block, extra.lhs);
1760 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1761}
1762
1763fn zirFieldValNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1764 const tracy = trace(@src());
1765 defer tracy.end();
1766
1767 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1768 const src = inst_data.src();
1769 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1770 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1771 const object = sema.resolveInst(block, extra.lhs);
1772 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
1773 const object_ptr = try sema.analyzeRef(block, src, object);
1774 const result_ptr = try sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1775 return sema.analyzeDeref(block, src, result_ptr, src);
1776}
1777
1778fn zirFieldPtrNamed(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1779 const tracy = trace(@src());
1780 defer tracy.end();
1781
1782 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1783 const src = inst_data.src();
1784 const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
1785 const extra = sema.code.extraData(zir.Inst.FieldNamed, inst_data.payload_index).data;
1786 const object_ptr = sema.resolveInst(block, extra.lhs);
1787 const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name);
1788 return sema.namedFieldPtr(block, src, object_ptr, field_name, field_name_src);
1789}
1790
1791fn zirIntcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1792 const tracy = trace(@src());
1793 defer tracy.end();
1794
1795 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1796 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1797 const operand = sema.resolveInst(bin_inst.rhs);
1798
1799 const dest_is_comptime_int = switch (dest_type.zigTypeTag()) {
1800 .ComptimeInt => true,
1801 .Int => false,
1802 else => return mod.fail(
1803 scope,
1804 inst.positionals.lhs.src,
1805 "expected integer type, found '{}'",
1806 .{
1807 dest_type,
1808 },
1809 ),
1810 };
1811
1812 switch (operand.ty.zigTypeTag()) {
1813 .ComptimeInt, .Int => {},
1814 else => return mod.fail(
1815 scope,
1816 inst.positionals.rhs.src,
1817 "expected integer type, found '{}'",
1818 .{operand.ty},
1819 ),
1820 }
1821
1822 if (operand.value() != null) {
1823 return sema.coerce(scope, dest_type, operand);
1824 } else if (dest_is_comptime_int) {
1825 return sema.mod.fail(&block.base, inst.base.src, "unable to cast runtime value to 'comptime_int'", .{});
1826 }
1827
1828 return sema.mod.fail(&block.base, inst.base.src, "TODO implement analyze widen or shorten int", .{});
1829}
1830
1831fn zirBitcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1832 const tracy = trace(@src());
1833 defer tracy.end();
1834
1835 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1836 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1837 const operand = sema.resolveInst(bin_inst.rhs);
1838 return mod.bitcast(scope, dest_type, operand);
1839}
1840
1841fn zirFloatcast(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1842 const tracy = trace(@src());
1843 defer tracy.end();
1844
1845 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1846 const dest_type = try sema.resolveType(block, bin_inst.lhs);
1847 const operand = sema.resolveInst(bin_inst.rhs);
1848
1849 const dest_is_comptime_float = switch (dest_type.zigTypeTag()) {
1850 .ComptimeFloat => true,
1851 .Float => false,
1852 else => return mod.fail(
1853 scope,
1854 inst.positionals.lhs.src,
1855 "expected float type, found '{}'",
1856 .{
1857 dest_type,
1858 },
1859 ),
1860 };
1861
1862 switch (operand.ty.zigTypeTag()) {
1863 .ComptimeFloat, .Float, .ComptimeInt => {},
1864 else => return mod.fail(
1865 scope,
1866 inst.positionals.rhs.src,
1867 "expected float type, found '{}'",
1868 .{operand.ty},
1869 ),
1870 }
1871
1872 if (operand.value() != null) {
1873 return sema.coerce(scope, dest_type, operand);
1874 } else if (dest_is_comptime_float) {
1875 return sema.mod.fail(&block.base, inst.base.src, "unable to cast runtime value to 'comptime_float'", .{});
1876 }
1877
1878 return sema.mod.fail(&block.base, inst.base.src, "TODO implement analyze widen or shorten float", .{});
1879}
1880
1881fn zirElemVal(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1882 const tracy = trace(@src());
1883 defer tracy.end();
1884
1885 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1886 const array = sema.resolveInst(block, bin_inst.lhs);
1887 const array_ptr = try sema.analyzeRef(block, sema.src, array);
1888 const elem_index = sema.resolveInst(block, bin_inst.rhs);
1889 const result_ptr = try sema.elemPtr(block, sema.src, array_ptr, elem_index, sema.src);
1890 return sema.analyzeDeref(block, sema.src, result_ptr, sema.src);
1891}
1892
1893fn zirElemValNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1894 const tracy = trace(@src());
1895 defer tracy.end();
1896
1897 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1898 const src = inst_data.src();
1899 const elem_index_src: LazySrcLoc = .{ .node_offset_array_access_index = inst_data.src_node };
1900 const extra = sema.code.extraData(zir.Inst.Bin, inst_data.payload_index).data;
1901 const array = sema.resolveInst(block, extra.lhs);
1902 const array_ptr = try sema.analyzeRef(block, src, array);
1903 const elem_index = sema.resolveInst(block, extra.rhs);
1904 const result_ptr = try sema.elemPtr(block, src, array_ptr, elem_index, elem_index_src);
1905 return sema.analyzeDeref(block, src, result_ptr, src);
1906}
1907
1908fn zirElemPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1909 const tracy = trace(@src());
1910 defer tracy.end();
1911
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);
1916}
1917
1918fn zirElemPtrNode(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1919 const tracy = trace(@src());
1920 defer tracy.end();
1921
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);
1929}
1930
1931fn zirSliceStart(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1932 const tracy = trace(@src());
1933 defer tracy.end();
1934
1935 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1936 const src = inst_data.src();
1937 const extra = sema.code.extraData(zir.Inst.SliceStart, inst_data.payload_index).data;
1938 const array_ptr = sema.resolveInst(extra.lhs);
1939 const start = sema.resolveInst(extra.start);
1940
1941 return sema.analyzeSlice(block, src, array_ptr, start, null, null, .unneeded);
1942}
1943
1944fn zirSliceEnd(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1945 const tracy = trace(@src());
1946 defer tracy.end();
1947
1948 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1949 const src = inst_data.src();
1950 const extra = sema.code.extraData(zir.Inst.SliceEnd, inst_data.payload_index).data;
1951 const array_ptr = sema.resolveInst(extra.lhs);
1952 const start = sema.resolveInst(extra.start);
1953 const end = sema.resolveInst(extra.end);
1954
1955 return sema.analyzeSlice(block, src, array_ptr, start, end, null, .unneeded);
1956}
1957
1958fn zirSliceSentinel(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1959 const tracy = trace(@src());
1960 defer tracy.end();
1961
1962 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
1963 const src = inst_data.src();
1964 const sentinel_src: LazySrcLoc = .{ .node_offset_slice_sentinel = inst_data.src_node };
1965 const extra = sema.code.extraData(zir.Inst.SliceSentinel, inst_data.payload_index).data;
1966 const array_ptr = sema.resolveInst(extra.lhs);
1967 const start = sema.resolveInst(extra.start);
1968 const end = sema.resolveInst(extra.end);
1969 const sentinel = sema.resolveInst(extra.sentinel);
1970
1971 return sema.analyzeSlice(block, inst.base.src, array_ptr, start, end, sentinel, sentinel_src);
1972}
1973
1974fn zirSwitchRange(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
1975 const tracy = trace(@src());
1976 defer tracy.end();
1977
1978 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
1979 const start = sema.resolveInst(bin_inst.lhs);
1980 const end = sema.resolveInst(bin_inst.rhs);
1981
1982 switch (start.ty.zigTypeTag()) {
1983 .Int, .ComptimeInt => {},
1984 else => return sema.mod.constVoid(block.arena, .unneeded),
1985 }
1986 switch (end.ty.zigTypeTag()) {
1987 .Int, .ComptimeInt => {},
1988 else => return sema.mod.constVoid(block.arena, .unneeded),
1989 }
1990 // .switch_range must be inside a comptime scope
1991 const start_val = start.value().?;
1992 const end_val = end.value().?;
1993 if (start_val.compare(.gte, end_val)) {
1994 return sema.mod.fail(&block.base, inst.base.src, "range start value must be smaller than the end value", .{});
1995 }
1996 return sema.mod.constVoid(block.arena, .unneeded);
1997}
1998
1999fn zirSwitchBr(
2000 sema: *Sema,
2001 parent_block: *Scope.Block,
2002 inst: zir.Inst.Index,
2003 ref: bool,
2004) InnerError!*Inst {
2005 const tracy = trace(@src());
2006 defer tracy.end();
2007
2008 if (true) @panic("TODO rework with zir-memory-layout in mind");
2009
2010 const target_ptr = sema.resolveInst(block, inst.positionals.target);
2011 const target = if (ref)
2012 try sema.analyzeDeref(block, inst.base.src, target_ptr, inst.positionals.target.src)
2013 else
2014 target_ptr;
2015 try validateSwitch(mod, scope, target, inst);
2016
2017 if (try mod.resolveDefinedValue(scope, target)) |target_val| {
2018 for (inst.positionals.cases) |case| {
2019 const resolved = sema.resolveInst(block, case.item);
2020 const casted = try sema.coerce(scope, target.ty, resolved);
2021 const item = try sema.resolveConstValue(parent_block, case_src, casted);
2022
2023 if (target_val.eql(item)) {
2024 try sema.body(scope.cast(Scope.Block).?, case.body);
2025 return mod.constNoReturn(scope, inst.base.src);
2026 }
2027 }
2028 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
2029 return mod.constNoReturn(scope, inst.base.src);
2030 }
2031
2032 if (inst.positionals.cases.len == 0) {
2033 // no cases just analyze else_branch
2034 try sema.body(scope.cast(Scope.Block).?, inst.positionals.else_body);
2035 return mod.constNoReturn(scope, inst.base.src);
2036 }
2037
2038 try sema.requireRuntimeBlock(parent_block, inst.base.src);
2039 const cases = try parent_block.arena.alloc(Inst.SwitchBr.Case, inst.positionals.cases.len);
2040
2041 var case_block: Scope.Block = .{
2042 .parent = parent_block,
2043 .inst_table = parent_block.inst_table,
2044 .func = parent_block.func,
2045 .owner_decl = parent_block.owner_decl,
2046 .src_decl = parent_block.src_decl,
2047 .instructions = .{},
2048 .arena = parent_block.arena,
2049 .inlining = parent_block.inlining,
2050 .is_comptime = parent_block.is_comptime,
2051 .branch_quota = parent_block.branch_quota,
2052 };
2053 defer case_block.instructions.deinit(mod.gpa);
2054
2055 for (inst.positionals.cases) |case, i| {
2056 // Reset without freeing.
2057 case_block.instructions.items.len = 0;
2058
2059 const resolved = sema.resolveInst(block, case.item);
2060 const casted = try sema.coerce(scope, target.ty, resolved);
2061 const item = try sema.resolveConstValue(parent_block, case_src, casted);
2062
2063 try sema.body(&case_block, case.body);
2064
2065 cases[i] = .{
2066 .item = item,
2067 .body = .{ .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items) },
2068 };
2069 }
2070
2071 case_block.instructions.items.len = 0;
2072 try sema.body(&case_block, inst.positionals.else_body);
2073
2074 const else_body: ir.Body = .{
2075 .instructions = try parent_block.arena.dupe(*Inst, case_block.instructions.items),
2076 };
2077
2078 return mod.addSwitchBr(parent_block, inst.base.src, target, cases, else_body);
2079}
2080
2081fn validateSwitch(sema: *Sema, block: *Scope.Block, target: *Inst, inst: zir.Inst.Index) InnerError!void {
2082 // validate usage of '_' prongs
2083 if (inst.positionals.special_prong == .underscore and target.ty.zigTypeTag() != .Enum) {
2084 return sema.mod.fail(&block.base, inst.base.src, "'_' prong only allowed when switching on non-exhaustive enums", .{});
2085 // TODO notes "'_' prong here" inst.positionals.cases[last].src
2086 }
2087
2088 // check that target type supports ranges
2089 if (inst.positionals.range) |range_inst| {
2090 switch (target.ty.zigTypeTag()) {
2091 .Int, .ComptimeInt => {},
2092 else => {
2093 return sema.mod.fail(&block.base, target.src, "ranges not allowed when switching on type {}", .{target.ty});
2094 // TODO notes "range used here" range_inst.src
2095 },
2096 }
2097 }
2098
2099 // validate for duplicate items/missing else prong
2100 switch (target.ty.zigTypeTag()) {
2101 .Enum => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Enum", .{}),
2102 .ErrorSet => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .ErrorSet", .{}),
2103 .Union => return sema.mod.fail(&block.base, inst.base.src, "TODO validateSwitch .Union", .{}),
2104 .Int, .ComptimeInt => {
2105 var range_set = @import("RangeSet.zig").init(mod.gpa);
2106 defer range_set.deinit();
2107
2108 for (inst.positionals.items) |item| {
2109 const maybe_src = if (item.castTag(.switch_range)) |range| blk: {
2110 const start_resolved = sema.resolveInst(block, range.positionals.lhs);
2111 const start_casted = try sema.coerce(scope, target.ty, start_resolved);
2112 const end_resolved = sema.resolveInst(block, range.positionals.rhs);
2113 const end_casted = try sema.coerce(scope, target.ty, end_resolved);
2114
2115 break :blk try range_set.add(
2116 try sema.resolveConstValue(block, range_start_src, start_casted),
2117 try sema.resolveConstValue(block, range_end_src, end_casted),
2118 item.src,
2119 );
2120 } else blk: {
2121 const resolved = sema.resolveInst(block, item);
2122 const casted = try sema.coerce(scope, target.ty, resolved);
2123 const value = try sema.resolveConstValue(block, item_src, casted);
2124 break :blk try range_set.add(value, value, item.src);
2125 };
2126
2127 if (maybe_src) |previous_src| {
2128 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
2129 // TODO notes "previous value is here" previous_src
2130 }
2131 }
2132
2133 if (target.ty.zigTypeTag() == .Int) {
2134 var arena = std.heap.ArenaAllocator.init(mod.gpa);
2135 defer arena.deinit();
2136
2137 const start = try target.ty.minInt(&arena, mod.getTarget());
2138 const end = try target.ty.maxInt(&arena, mod.getTarget());
2139 if (try range_set.spans(start, end)) {
2140 if (inst.positionals.special_prong == .@"else") {
2141 return sema.mod.fail(&block.base, inst.base.src, "unreachable else prong, all cases already handled", .{});
2142 }
2143 return;
2144 }
2145 }
2146
2147 if (inst.positionals.special_prong != .@"else") {
2148 return sema.mod.fail(&block.base, inst.base.src, "switch must handle all possibilities", .{});
2149 }
2150 },
2151 .Bool => {
2152 var true_count: u8 = 0;
2153 var false_count: u8 = 0;
2154 for (inst.positionals.items) |item| {
2155 const resolved = sema.resolveInst(block, item);
2156 const casted = try sema.coerce(scope, Type.initTag(.bool), resolved);
2157 if ((try sema.resolveConstValue(block, item_src, casted)).toBool()) {
2158 true_count += 1;
2159 } else {
2160 false_count += 1;
2161 }
2162
2163 if (true_count + false_count > 2) {
2164 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
2165 }
2166 }
2167 if ((true_count + false_count < 2) and inst.positionals.special_prong != .@"else") {
2168 return sema.mod.fail(&block.base, inst.base.src, "switch must handle all possibilities", .{});
2169 }
2170 if ((true_count + false_count == 2) and inst.positionals.special_prong == .@"else") {
2171 return sema.mod.fail(&block.base, inst.base.src, "unreachable else prong, all cases already handled", .{});
2172 }
2173 },
2174 .EnumLiteral, .Void, .Fn, .Pointer, .Type => {
2175 if (inst.positionals.special_prong != .@"else") {
2176 return sema.mod.fail(&block.base, inst.base.src, "else prong required when switching on type '{}'", .{target.ty});
2177 }
2178
2179 var seen_values = std.HashMap(Value, usize, Value.hash, Value.eql, std.hash_map.DefaultMaxLoadPercentage).init(mod.gpa);
2180 defer seen_values.deinit();
2181
2182 for (inst.positionals.items) |item| {
2183 const resolved = sema.resolveInst(block, item);
2184 const casted = try sema.coerce(scope, target.ty, resolved);
2185 const val = try sema.resolveConstValue(block, item_src, casted);
2186
2187 if (try seen_values.fetchPut(val, item.src)) |prev| {
2188 return sema.mod.fail(&block.base, item.src, "duplicate switch value", .{});
2189 // TODO notes "previous value here" prev.value
2190 }
2191 }
2192 },
2193
2194 .ErrorUnion,
2195 .NoReturn,
2196 .Array,
2197 .Struct,
2198 .Undefined,
2199 .Null,
2200 .Optional,
2201 .BoundFn,
2202 .Opaque,
2203 .Vector,
2204 .Frame,
2205 .AnyFrame,
2206 .ComptimeFloat,
2207 .Float,
2208 => {
2209 return sema.mod.fail(&block.base, target.src, "invalid switch target type '{}'", .{target.ty});
2210 },
2211 }
2212}
2213
2214fn zirImport(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2215 const tracy = trace(@src());
2216 defer tracy.end();
2217
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) {
2224 error.ImportOutsidePkgPath => {
2225 return sema.mod.fail(&block.base, src, "import of file outside package path: '{s}'", .{operand});
2226 },
2227 error.FileNotFound => {
2228 return sema.mod.fail(&block.base, src, "unable to find '{s}'", .{operand});
2229 },
2230 else => {
2231 // TODO: make sure this gets retried and not cached
2232 return sema.mod.fail(&block.base, src, "unable to open '{s}': {s}", .{ operand, @errorName(err) });
2233 },
2234 };
2235 return sema.mod.constType(block.arena, src, file_scope.root_container.ty);
2236}
2237
2238fn zirShl(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2239 const tracy = trace(@src());
2240 defer tracy.end();
2241 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirShl", .{});
2242}
2243
2244fn zirShr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2245 const tracy = trace(@src());
2246 defer tracy.end();
2247 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirShr", .{});
2248}
2249
2250fn zirBitwise(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2251 const tracy = trace(@src());
2252 defer tracy.end();
2253
2254 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2255 const lhs = sema.resolveInst(bin_inst.lhs);
2256 const rhs = sema.resolveInst(bin_inst.rhs);
2257
2258 const instructions = &[_]*Inst{ lhs, rhs };
2259 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2260 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2261 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
2262
2263 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
2264 resolved_type.elemType()
2265 else
2266 resolved_type;
2267
2268 const scalar_tag = scalar_type.zigTypeTag();
2269
2270 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
2271 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2272 return sema.mod.fail(&block.base, inst.base.src, "vector length mismatch: {d} and {d}", .{
2273 lhs.ty.arrayLen(),
2274 rhs.ty.arrayLen(),
2275 });
2276 }
2277 return sema.mod.fail(&block.base, inst.base.src, "TODO implement support for vectors in zirBitwise", .{});
2278 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
2279 return sema.mod.fail(&block.base, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
2280 lhs.ty,
2281 rhs.ty,
2282 });
2283 }
2284
2285 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
2286
2287 if (!is_int) {
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()) });
2289 }
2290
2291 if (casted_lhs.value()) |lhs_val| {
2292 if (casted_rhs.value()) |rhs_val| {
2293 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2294 return sema.mod.constInst(scope, inst.base.src, .{
2295 .ty = resolved_type,
2296 .val = Value.initTag(.undef),
2297 });
2298 }
2299 return sema.mod.fail(&block.base, inst.base.src, "TODO implement comptime bitwise operations", .{});
2300 }
2301 }
2302
2303 try sema.requireRuntimeBlock(block, inst.base.src);
2304 const ir_tag = switch (inst.base.tag) {
2305 .bit_and => Inst.Tag.bit_and,
2306 .bit_or => Inst.Tag.bit_or,
2307 .xor => Inst.Tag.xor,
2308 else => unreachable,
2309 };
2310
2311 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
2312}
2313
2314fn zirBitNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2315 const tracy = trace(@src());
2316 defer tracy.end();
2317 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirBitNot", .{});
2318}
2319
2320fn zirArrayCat(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2321 const tracy = trace(@src());
2322 defer tracy.end();
2323 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirArrayCat", .{});
2324}
2325
2326fn zirArrayMul(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2327 const tracy = trace(@src());
2328 defer tracy.end();
2329 return sema.mod.fail(&block.base, inst.base.src, "TODO implement zirArrayMul", .{});
2330}
2331
2332fn zirArithmetic(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2333 const tracy = trace(@src());
2334 defer tracy.end();
2335
2336 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2337 const lhs = sema.resolveInst(bin_inst.lhs);
2338 const rhs = sema.resolveInst(bin_inst.rhs);
2339
2340 const instructions = &[_]*Inst{ lhs, rhs };
2341 const resolved_type = try sema.resolvePeerTypes(block, instructions);
2342 const casted_lhs = try sema.coerce(scope, resolved_type, lhs);
2343 const casted_rhs = try sema.coerce(scope, resolved_type, rhs);
2344
2345 const scalar_type = if (resolved_type.zigTypeTag() == .Vector)
2346 resolved_type.elemType()
2347 else
2348 resolved_type;
2349
2350 const scalar_tag = scalar_type.zigTypeTag();
2351
2352 if (lhs.ty.zigTypeTag() == .Vector and rhs.ty.zigTypeTag() == .Vector) {
2353 if (lhs.ty.arrayLen() != rhs.ty.arrayLen()) {
2354 return sema.mod.fail(&block.base, inst.base.src, "vector length mismatch: {d} and {d}", .{
2355 lhs.ty.arrayLen(),
2356 rhs.ty.arrayLen(),
2357 });
2358 }
2359 return sema.mod.fail(&block.base, inst.base.src, "TODO implement support for vectors in zirBinOp", .{});
2360 } else if (lhs.ty.zigTypeTag() == .Vector or rhs.ty.zigTypeTag() == .Vector) {
2361 return sema.mod.fail(&block.base, inst.base.src, "mixed scalar and vector operands to binary expression: '{}' and '{}'", .{
2362 lhs.ty,
2363 rhs.ty,
2364 });
2365 }
2366
2367 const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
2368 const is_float = scalar_tag == .Float or scalar_tag == .ComptimeFloat;
2369
2370 if (!is_int and !(is_float and floatOpAllowed(inst.base.tag))) {
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()) });
2372 }
2373
2374 if (casted_lhs.value()) |lhs_val| {
2375 if (casted_rhs.value()) |rhs_val| {
2376 if (lhs_val.isUndef() or rhs_val.isUndef()) {
2377 return sema.mod.constInst(scope, inst.base.src, .{
2378 .ty = resolved_type,
2379 .val = Value.initTag(.undef),
2380 });
2381 }
2382 return analyzeInstComptimeOp(mod, scope, scalar_type, inst, lhs_val, rhs_val);
2383 }
2384 }
2385
2386 try sema.requireRuntimeBlock(block, inst.base.src);
2387 const ir_tag: Inst.Tag = switch (inst.base.tag) {
2388 .add => .add,
2389 .addwrap => .addwrap,
2390 .sub => .sub,
2391 .subwrap => .subwrap,
2392 .mul => .mul,
2393 .mulwrap => .mulwrap,
2394 else => return sema.mod.fail(&block.base, inst.base.src, "TODO implement arithmetic for operand '{s}''", .{@tagName(inst.base.tag)}),
2395 };
2396
2397 return mod.addBinOp(b, inst.base.src, scalar_type, ir_tag, casted_lhs, casted_rhs);
2398}
2399
2400/// Analyzes operands that are known at comptime
2401fn analyzeInstComptimeOp(sema: *Sema, block: *Scope.Block, res_type: Type, inst: zir.Inst.Index, lhs_val: Value, rhs_val: Value) InnerError!*Inst {
2402 // incase rhs is 0, simply return lhs without doing any calculations
2403 // TODO Once division is implemented we should throw an error when dividing by 0.
2404 if (rhs_val.compareWithZero(.eq)) {
2405 return sema.mod.constInst(scope, inst.base.src, .{
2406 .ty = res_type,
2407 .val = lhs_val,
2408 });
2409 }
2410 const is_int = res_type.isInt() or res_type.zigTypeTag() == .ComptimeInt;
2411
2412 const value = switch (inst.base.tag) {
2413 .add => blk: {
2414 const val = if (is_int)
2415 try Module.intAdd(block.arena, lhs_val, rhs_val)
2416 else
2417 try mod.floatAdd(scope, res_type, inst.base.src, lhs_val, rhs_val);
2418 break :blk val;
2419 },
2420 .sub => blk: {
2421 const val = if (is_int)
2422 try Module.intSub(block.arena, lhs_val, rhs_val)
2423 else
2424 try mod.floatSub(scope, res_type, inst.base.src, lhs_val, rhs_val);
2425 break :blk val;
2426 },
2427 else => return sema.mod.fail(&block.base, inst.base.src, "TODO Implement arithmetic operand '{s}'", .{@tagName(inst.base.tag)}),
2428 };
2429
2430 log.debug("{s}({}, {}) result: {}", .{ @tagName(inst.base.tag), lhs_val, rhs_val, value });
2431
2432 return sema.mod.constInst(scope, inst.base.src, .{
2433 .ty = res_type,
2434 .val = value,
2435 });
2436}
2437
2438fn zirDeref(sema: *Sema, block: *Scope.Block, deref: zir.Inst.Index) InnerError!*Inst {
2439 const tracy = trace(@src());
2440 defer tracy.end();
2441
2442 const inst_data = sema.code.instructions.items(.data)[inst].un_node;
2443 const src = inst_data.src();
2444 const ptr_src: LazySrcLoc = .{ .node_offset_deref_ptr = inst_data.src_node };
2445 const ptr = sema.resolveInst(block, inst_data.operand);
2446 return sema.analyzeDeref(block, src, ptr, ptr_src);
2447}
2448
2449fn zirAsm(
2450 sema: *Sema,
2451 block: *Scope.Block,
2452 assembly: zir.Inst.Index,
2453 is_volatile: bool,
2454) InnerError!*Inst {
2455 const tracy = trace(@src());
2456 defer tracy.end();
2457
2458 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2459 const src = inst_data.src();
2460 const asm_source_src: LazySrcLoc = .{ .node_offset_asm_source = inst_data.src_node };
2461 const ret_ty_src: LazySrcLoc = .{ .node_offset_asm_ret_ty = inst_data.src_node };
2462 const extra = sema.code.extraData(zir.Inst.Asm, inst_data.payload_index);
2463 const return_type = try sema.resolveType(block, ret_ty_src, extra.data.return_type);
2464 const asm_source = try sema.resolveConstString(block, asm_source_src, extra.data.asm_source);
2465
2466 var extra_i = extra.end;
2467 const output = if (extra.data.output != 0) blk: {
2468 const name = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2469 extra_i += 1;
2470 break :blk .{
2471 .name = name,
2472 .inst = try sema.resolveInst(block, extra.data.output),
2473 };
2474 } else null;
2475
2476 const args = try block.arena.alloc(*Inst, extra.data.args.len);
2477 const inputs = try block.arena.alloc([]const u8, extra.data.args_len);
2478 const clobbers = try block.arena.alloc([]const u8, extra.data.clobbers_len);
2479
2480 for (args) |*arg| {
2481 const uncasted = sema.resolveInst(block, sema.code.extra[extra_i]);
2482 extra_i += 1;
2483 arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted);
2484 }
2485 for (inputs) |*name| {
2486 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2487 extra_i += 1;
2488 }
2489 for (clobbers) |*name| {
2490 name.* = sema.code.nullTerminatedString(sema.code.extra[extra_i]);
2491 extra_i += 1;
2492 }
2493
2494 try sema.requireRuntimeBlock(block, src);
2495 const inst = try block.arena.create(Inst.Assembly);
2496 inst.* = .{
2497 .base = .{
2498 .tag = .assembly,
2499 .ty = return_type,
2500 .src = src,
2501 },
2502 .asm_source = asm_source,
2503 .is_volatile = is_volatile,
2504 .output = if (output) |o| o.inst else null,
2505 .output_name = if (output) |o| o.name else null,
2506 .inputs = inputs,
2507 .clobbers = clobbers,
2508 .args = args,
2509 };
2510 try block.instructions.append(mod.gpa, &inst.base);
2511 return &inst.base;
2512}
2513
2514fn zirCmp(
2515 sema: *Sema,
2516 block: *Scope.Block,
2517 inst: zir.Inst.Index,
2518 op: std.math.CompareOperator,
2519) InnerError!*Inst {
2520 const tracy = trace(@src());
2521 defer tracy.end();
2522
2523 const bin_inst = sema.code.instructions.items(.data)[inst].bin;
2524 const lhs = sema.resolveInst(bin_inst.lhs);
2525 const rhs = sema.resolveInst(bin_inst.rhs);
2526
2527 const is_equality_cmp = switch (op) {
2528 .eq, .neq => true,
2529 else => false,
2530 };
2531 const lhs_ty_tag = lhs.ty.zigTypeTag();
2532 const rhs_ty_tag = rhs.ty.zigTypeTag();
2533 if (is_equality_cmp and lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
2534 // null == null, null != null
2535 return mod.constBool(block.arena, inst.base.src, op == .eq);
2536 } else if (is_equality_cmp and
2537 ((lhs_ty_tag == .Null and rhs_ty_tag == .Optional) or
2538 rhs_ty_tag == .Null and lhs_ty_tag == .Optional))
2539 {
2540 // comparing null with optionals
2541 const opt_operand = if (lhs_ty_tag == .Optional) lhs else rhs;
2542 return sema.analyzeIsNull(block, inst.base.src, opt_operand, op == .neq);
2543 } else if (is_equality_cmp and
2544 ((lhs_ty_tag == .Null and rhs.ty.isCPtr()) or (rhs_ty_tag == .Null and lhs.ty.isCPtr())))
2545 {
2546 return sema.mod.fail(&block.base, inst.base.src, "TODO implement C pointer cmp", .{});
2547 } else if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
2548 const non_null_type = if (lhs_ty_tag == .Null) rhs.ty else lhs.ty;
2549 return sema.mod.fail(&block.base, inst.base.src, "comparison of '{}' with null", .{non_null_type});
2550 } else if (is_equality_cmp and
2551 ((lhs_ty_tag == .EnumLiteral and rhs_ty_tag == .Union) or
2552 (rhs_ty_tag == .EnumLiteral and lhs_ty_tag == .Union)))
2553 {
2554 return sema.mod.fail(&block.base, inst.base.src, "TODO implement equality comparison between a union's tag value and an enum literal", .{});
2555 } else if (lhs_ty_tag == .ErrorSet and rhs_ty_tag == .ErrorSet) {
2556 if (!is_equality_cmp) {
2557 return sema.mod.fail(&block.base, inst.base.src, "{s} operator not allowed for errors", .{@tagName(op)});
2558 }
2559 if (rhs.value()) |rval| {
2560 if (lhs.value()) |lval| {
2561 // 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
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));
2563 }
2564 }
2565 try sema.requireRuntimeBlock(block, inst.base.src);
2566 return mod.addBinOp(b, inst.base.src, Type.initTag(.bool), if (op == .eq) .cmp_eq else .cmp_neq, lhs, rhs);
2567 } else if (lhs.ty.isNumeric() and rhs.ty.isNumeric()) {
2568 // This operation allows any combination of integer and float types, regardless of the
2569 // signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
2570 // numeric types.
2571 return mod.cmpNumeric(scope, inst.base.src, lhs, rhs, op);
2572 } else if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
2573 if (!is_equality_cmp) {
2574 return sema.mod.fail(&block.base, inst.base.src, "{s} operator not allowed for types", .{@tagName(op)});
2575 }
2576 return mod.constBool(block.arena, inst.base.src, lhs.value().?.eql(rhs.value().?) == (op == .eq));
2577 }
2578 return sema.mod.fail(&block.base, inst.base.src, "TODO implement more cmp analysis", .{});
2579}
2580
2581fn zirTypeof(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2582 const tracy = trace(@src());
2583 defer tracy.end();
2584
2585 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2586 const operand = sema.resolveInst(block, inst_data.operand);
2587 return sema.mod.constType(block.arena, inst_data.src(), operand.ty);
2588}
2589
2590fn zirTypeofPeer(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2591 const tracy = trace(@src());
2592 defer tracy.end();
2593
2594 const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
2595 const src = inst_data.src();
2596 const extra = sema.code.extraData(zir.Inst.MultiOp, inst_data.payload_index);
2597
2598 const inst_list = try mod.gpa.alloc(*ir.Inst, extra.data.operands_len);
2599 defer mod.gpa.free(inst_list);
2600
2601 const src_list = try mod.gpa.alloc(LazySrcLoc, extra.data.operands_len);
2602 defer mod.gpa.free(src_list);
2603
2604 for (sema.code.extra[extra.end..][0..extra.data.operands_len]) |arg_ref, i| {
2605 inst_list[i] = sema.resolveInst(block, arg_ref);
2606 src_list[i] = .{ .node_offset_builtin_call_argn = inst_data.src_node };
2607 }
2608
2609 const result_type = try sema.resolvePeerTypes(block, inst_list, src_list);
2610 return sema.mod.constType(block.arena, src, result_type);
2611}
2612
2613fn zirBoolNot(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2614 const tracy = trace(@src());
2615 defer tracy.end();
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
2621 const bool_type = Type.initTag(.bool);
2622 const operand = try sema.coerce(scope, bool_type, uncasted_operand);
2623 if (try mod.resolveDefinedValue(scope, operand)) |val| {
2624 return mod.constBool(block.arena, src, !val.toBool());
2625 }
2626 try sema.requireRuntimeBlock(block, src);
2627 return block.addUnOp(src, bool_type, .not, operand);
2628}
2629
2630fn zirBoolOp(
2631 sema: *Sema,
2632 block: *Scope.Block,
2633 inst: zir.Inst.Index,
2634 comptime is_bool_or: bool,
2635) InnerError!*Inst {
2636 const tracy = trace(@src());
2637 defer tracy.end();
2638
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);
2645
2646 if (lhs.value()) |lhs_val| {
2647 if (rhs.value()) |rhs_val| {
2648 if (is_bool_or) {
2649 return mod.constBool(block.arena, inst.base.src, lhs_val.toBool() or rhs_val.toBool());
2650 } else {
2651 return mod.constBool(block.arena, inst.base.src, lhs_val.toBool() and rhs_val.toBool());
2652 }
2653 }
2654 }
2655 try sema.requireRuntimeBlock(block, inst.base.src);
2656 const tag: ir.Inst.Tag = if (is_bool_or) .bool_or else .bool_and;
2657 return mod.addBinOp(b, inst.base.src, bool_type, tag, lhs, rhs);
2658}
2659
2660fn zirIsNull(
2661 sema: *Sema,
2662 block: *Scope.Block,
2663 inst: zir.Inst.Index,
2664 invert_logic: bool,
2665) InnerError!*Inst {
2666 const tracy = trace(@src());
2667 defer tracy.end();
2668
2669 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2670 const src = inst_data.src();
2671 const operand = sema.resolveInst(block, inst_data.operand);
2672 return sema.analyzeIsNull(block, src, operand, invert_logic);
2673}
2674
2675fn zirIsNullPtr(
2676 sema: *Sema,
2677 block: *Scope.Block,
2678 inst: zir.Inst.Index,
2679 invert_logic: bool,
2680) InnerError!*Inst {
2681 const tracy = trace(@src());
2682 defer tracy.end();
2683
2684 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2685 const src = inst_data.src();
2686 const ptr = sema.resolveInst(block, inst_data.operand);
2687 const loaded = try sema.analyzeDeref(block, src, ptr, src);
2688 return sema.analyzeIsNull(block, src, loaded, invert_logic);
2689}
2690
2691fn zirIsErr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2692 const tracy = trace(@src());
2693 defer tracy.end();
2694
2695 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2696 const operand = sema.resolveInst(block, inst_data.operand);
2697 return mod.analyzeIsErr(scope, inst_data.src(), operand);
2698}
2699
2700fn zirIsErrPtr(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2701 const tracy = trace(@src());
2702 defer tracy.end();
2703
2704 const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
2705 const src = inst_data.src();
2706 const ptr = sema.resolveInst(block, inst_data.operand);
2707 const loaded = try sema.analyzeDeref(block, src, ptr, src);
2708 return mod.analyzeIsErr(scope, src, loaded);
2709}
2710
2711fn zirCondbr(sema: *Sema, parent_block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2712 const tracy = trace(@src());
2713 defer tracy.end();
2714
2715 const uncasted_cond = sema.resolveInst(block, inst.positionals.condition);
2716 const cond = try sema.coerce(scope, Type.initTag(.bool), uncasted_cond);
2717
2718 if (try mod.resolveDefinedValue(scope, cond)) |cond_val| {
2719 const body = if (cond_val.toBool()) &inst.positionals.then_body else &inst.positionals.else_body;
2720 try sema.body(parent_block, body.*);
2721 return mod.constNoReturn(scope, inst.base.src);
2722 }
2723
2724 var true_block: Scope.Block = .{
2725 .parent = parent_block,
2726 .inst_table = parent_block.inst_table,
2727 .func = parent_block.func,
2728 .owner_decl = parent_block.owner_decl,
2729 .src_decl = parent_block.src_decl,
2730 .instructions = .{},
2731 .arena = parent_block.arena,
2732 .inlining = parent_block.inlining,
2733 .is_comptime = parent_block.is_comptime,
2734 .branch_quota = parent_block.branch_quota,
2735 };
2736 defer true_block.instructions.deinit(mod.gpa);
2737 try sema.body(&true_block, inst.positionals.then_body);
2738
2739 var false_block: Scope.Block = .{
2740 .parent = parent_block,
2741 .inst_table = parent_block.inst_table,
2742 .func = parent_block.func,
2743 .owner_decl = parent_block.owner_decl,
2744 .src_decl = parent_block.src_decl,
2745 .instructions = .{},
2746 .arena = parent_block.arena,
2747 .inlining = parent_block.inlining,
2748 .is_comptime = parent_block.is_comptime,
2749 .branch_quota = parent_block.branch_quota,
2750 };
2751 defer false_block.instructions.deinit(mod.gpa);
2752 try sema.body(&false_block, inst.positionals.else_body);
2753
2754 const then_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, true_block.instructions.items) };
2755 const else_body: ir.Body = .{ .instructions = try block.arena.dupe(*Inst, false_block.instructions.items) };
2756 return mod.addCondBr(parent_block, inst.base.src, cond, then_body, else_body);
2757}
2758
2759fn zirUnreachable(
2760 sema: *Sema,
2761 block: *Scope.Block,
2762 zir_index: zir.Inst.Index,
2763 safety_check: bool,
2764) InnerError!*Inst {
2765 const tracy = trace(@src());
2766 defer tracy.end();
2767
2768 try sema.requireRuntimeBlock(block, zir_index.base.src);
2769 // TODO Add compile error for @optimizeFor occurring too late in a scope.
2770 if (safety_check and block.wantSafety()) {
2771 return mod.safetyPanic(b, zir_index.base.src, .unreach);
2772 } else {
2773 return block.addNoOp(zir_index.base.src, Type.initTag(.noreturn), .unreach);
2774 }
2775}
2776
2777fn zirRetTok(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2778 @compileError("TODO");
2779}
2780
2781fn zirRetNode(sema: *Sema, block: *Scope.Block, zir_inst: zir.Inst.Index) InnerError!*Inst {
2782 @compileError("TODO");
2783}
2784
2785fn floatOpAllowed(tag: zir.Inst.Tag) bool {
2786 // extend this swich as additional operators are implemented
2787 return switch (tag) {
2788 .add, .sub => true,
2789 else => false,
2790 };
2791}
2792
2793fn zirPtrTypeSimple(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2794 const tracy = trace(@src());
2795 defer tracy.end();
2796
2797 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type_simple;
2798 const elem_type = try sema.resolveType(block, .unneeded, inst_data.elem_type);
2799 const ty = try sema.mod.ptrType(
2800 block.arena,
2801 elem_type,
2802 null,
2803 0,
2804 0,
2805 0,
2806 inst_data.is_mutable,
2807 inst_data.is_allowzero,
2808 inst_data.is_volatile,
2809 inst_data.size,
2810 );
2811 return sema.mod.constType(block.arena, .unneeded, ty);
2812}
2813
2814fn zirPtrType(sema: *Sema, block: *Scope.Block, inst: zir.Inst.Index) InnerError!*Inst {
2815 const tracy = trace(@src());
2816 defer tracy.end();
2817
2818 const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
2819 const extra = sema.code.extraData(zir.Inst.PtrType, inst_data.payload_index);
2820
2821 var extra_i = extra.end;
2822
2823 const sentinel = if (inst_data.flags.has_sentinel) blk: {
2824 const ref = sema.code.extra[extra_i];
2825 extra_i += 1;
2826 break :blk (try sema.resolveInstConst(block, .unneeded, ref)).val;
2827 } else null;
2828
2829 const abi_align = if (inst_data.flags.has_align) blk: {
2830 const ref = sema.code.extra[extra_i];
2831 extra_i += 1;
2832 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u32);
2833 } else 0;
2834
2835 const bit_start = if (inst_data.flags.has_bit_start) blk: {
2836 const ref = sema.code.extra[extra_i];
2837 extra_i += 1;
2838 break :blk try sema.resolveAlreadyCoercedInt(block, .unneeded, ref, u16);
2839 } else 0;
2840
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);
2851
2852 const ty = try mod.ptrType(
2853 scope,
2854 elem_type,
2855 sentinel,
2856 abi_align,
2857 bit_start,
2858 bit_end,
2859 inst_data.flags.is_mutable,
2860 inst_data.flags.is_allowzero,
2861 inst_data.flags.is_volatile,
2862 inst_data.size,
2863 );
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;
3869}