authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-01-15 14:01:15+00:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2026-03-10 10:26:07+00:00
log510ea6f61f93c722c4cb2c2b39605201cc2f9c32
tree476e4e20e0f9a872c13033c800212f7540eb06f5
parent5e8397d5e03269d8a39efb22605ea20102848084
signature Commit is signed but in an unrecognized format.

type resolution progress


29 files changed, 7266 insertions(+), 11278 deletions(-)

lib/std/math/big/int.zig+12-2
...@@ -924,7 +924,12 @@ pub const Mutable = struct {...@@ -924,7 +924,12 @@ pub const Mutable = struct {
924 /// Asserts the result fits in `r`. Upper bound on the number of limbs needed by924 /// Asserts the result fits in `r`. Upper bound on the number of limbs needed by
925 /// r is `calcTwosCompLimbCount(bit_count)`.925 /// r is `calcTwosCompLimbCount(bit_count)`.
926 pub fn bitReverse(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {926 pub fn bitReverse(r: *Mutable, a: Const, signedness: Signedness, bit_count: usize) void {
927 if (bit_count == 0) return;927 if (bit_count == 0) {
928 r.limbs[0] = 0;
929 r.len = 1;
930 r.positive = true;
931 return;
932 }
928933
929 r.copy(a);934 r.copy(a);
930935
...@@ -986,7 +991,12 @@ pub const Mutable = struct {...@@ -986,7 +991,12 @@ pub const Mutable = struct {
986 /// Asserts the result fits in `r`. Upper bound on the number of limbs needed by991 /// Asserts the result fits in `r`. Upper bound on the number of limbs needed by
987 /// r is `calcTwosCompLimbCount(8*byte_count)`.992 /// r is `calcTwosCompLimbCount(8*byte_count)`.
988 pub fn byteSwap(r: *Mutable, a: Const, signedness: Signedness, byte_count: usize) void {993 pub fn byteSwap(r: *Mutable, a: Const, signedness: Signedness, byte_count: usize) void {
989 if (byte_count == 0) return;994 if (byte_count == 0) {
995 r.limbs[0] = 0;
996 r.len = 1;
997 r.positive = true;
998 return;
999 }
9901000
991 r.copy(a);1001 r.copy(a);
992 const limbs_required = calcTwosCompLimbCount(8 * byte_count);1002 const limbs_required = calcTwosCompLimbCount(8 * byte_count);
lib/std/zig/Zir.zig+1-15
...@@ -3710,7 +3710,7 @@ pub const Inst = struct {...@@ -3710,7 +3710,7 @@ pub const Inst = struct {
3710 };3710 };
3711 }3711 }
37123712
3713 pub fn layout(k: Kind) std.builtin.ContainerLayout {3713 pub fn layout(k: Kind) std.builtin.Type.ContainerLayout {
3714 return switch (k) {3714 return switch (k) {
3715 .auto, .tagged_explicit, .tagged_enum, .tagged_enum_explicit => .auto,3715 .auto, .tagged_explicit, .tagged_enum, .tagged_enum_explicit => .auto,
3716 .@"extern" => .@"extern",3716 .@"extern" => .@"extern",
...@@ -4008,20 +4008,6 @@ pub const Inst = struct {...@@ -4008,20 +4008,6 @@ pub const Inst = struct {
4008 };4008 };
4009};4009};
40104010
4011/// MLUGG TODO: delete this!
4012pub const DeclIterator = struct {
4013 decls: []const Inst.Index,
4014 index: usize,
4015 pub fn next(it: *DeclIterator) ?Inst.Index {
4016 if (it.index == it.decls.len) return null;
4017 defer it.index += 1;
4018 return it.decls[it.index];
4019 }
4020};
4021pub fn declIterator(zir: Zir, decl_inst: Zir.Inst.Index) DeclIterator {
4022 return .{ .decls = zir.typeDecls(decl_inst), .index = 0 };
4023}
4024
4025/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.4011/// `DeclContents` contains all "interesting" instructions found within a declaration by `findTrackable`.
4026/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping4012/// These instructions are partitioned into a few different sets, since this makes ZIR instruction mapping
4027/// more effective.4013/// more effective.
lib/std/zig/target.zig+2-4
...@@ -503,8 +503,7 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 {...@@ -503,8 +503,7 @@ pub fn intByteSize(target: *const std.Target, bits: u16) u16 {
503pub fn intAlignment(target: *const std.Target, bits: u16) u16 {503pub fn intAlignment(target: *const std.Target, bits: u16) u16 {
504 return switch (target.cpu.arch) {504 return switch (target.cpu.arch) {
505 .x86 => switch (bits) {505 .x86 => switch (bits) {
506 0 => 0,506 0...8 => 1,
507 1...8 => 1,
508 9...16 => 2,507 9...16 => 2,
509 17...32 => 4,508 17...32 => 4,
510 33...64 => switch (target.os.tag) {509 33...64 => switch (target.os.tag) {
...@@ -514,8 +513,7 @@ pub fn intAlignment(target: *const std.Target, bits: u16) u16 {...@@ -514,8 +513,7 @@ pub fn intAlignment(target: *const std.Target, bits: u16) u16 {
514 else => 16,513 else => 16,
515 },514 },
516 .x86_64 => switch (bits) {515 .x86_64 => switch (bits) {
517 0 => 0,516 0...8 => 1,
518 1...8 => 1,
519 9...16 => 2,517 9...16 => 2,
520 17...32 => 4,518 17...32 => 4,
521 33...64 => 8,519 33...64 => 8,
src/Air.zig+5-8
...@@ -14,7 +14,6 @@ const Type = @import("Type.zig");...@@ -14,7 +14,6 @@ const Type = @import("Type.zig");
14const Value = @import("Value.zig");14const Value = @import("Value.zig");
15const Zcu = @import("Zcu.zig");15const Zcu = @import("Zcu.zig");
16const print = @import("Air/print.zig");16const print = @import("Air/print.zig");
17const types_resolved = @import("Air/types_resolved.zig");
1817
19pub const Legalize = @import("Air/Legalize.zig");18pub const Legalize = @import("Air/Legalize.zig");
20pub const Liveness = @import("Air/Liveness.zig");19pub const Liveness = @import("Air/Liveness.zig");
...@@ -173,8 +172,8 @@ pub const Inst = struct {...@@ -173,8 +172,8 @@ pub const Inst = struct {
173 /// outside the provenance of the operand, the result is undefined.172 /// outside the provenance of the operand, the result is undefined.
174 ///173 ///
175 /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,174 /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
176 /// rhs is the offset. Result type is the same as lhs. The operand may175 /// rhs is the offset. Result type is the same as lhs. The operand type's
177 /// be a slice.176 /// pointer size may be `.slice`, `.many`, or `.c`.
178 ptr_add,177 ptr_add,
179 /// Subtract an offset, in element type units, from a pointer,178 /// Subtract an offset, in element type units, from a pointer,
180 /// returning a new pointer. Element type may not be zero bits.179 /// returning a new pointer. Element type may not be zero bits.
...@@ -183,8 +182,8 @@ pub const Inst = struct {...@@ -183,8 +182,8 @@ pub const Inst = struct {
183 /// outside the provenance of the operand, the result is undefined.182 /// outside the provenance of the operand, the result is undefined.
184 ///183 ///
185 /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,184 /// Uses the `ty_pl` field. Payload is `Bin`. The lhs is the pointer,
186 /// rhs is the offset. Result type is the same as lhs. The operand may185 /// rhs is the offset. Result type is the same as lhs. The operand type's
187 /// be a slice.186 /// pointer size may be `.slice`, `.many`, or `.c`.
188 ptr_sub,187 ptr_sub,
189 /// Given two operands which can be floats, integers, or vectors, returns the188 /// Given two operands which can be floats, integers, or vectors, returns the
190 /// greater of the operands. For vectors it operates element-wise.189 /// greater of the operands. For vectors it operates element-wise.
...@@ -693,6 +692,7 @@ pub const Inst = struct {...@@ -693,6 +692,7 @@ pub const Inst = struct {
693 /// Uses the `ty_pl` field with payload `Bin`.692 /// Uses the `ty_pl` field with payload `Bin`.
694 slice_elem_ptr,693 slice_elem_ptr,
695 /// Given a pointer value, and element index, return the element value at that index.694 /// Given a pointer value, and element index, return the element value at that index.
695 /// The pointer size is either `.c` or `.many`.
696 /// Result type is the element type of the pointer operand.696 /// Result type is the element type of the pointer operand.
697 /// Uses the `bin_op` field.697 /// Uses the `bin_op` field.
698 ptr_elem_val,698 ptr_elem_val,
...@@ -2440,9 +2440,6 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index...@@ -2440,9 +2440,6 @@ pub fn unwrapShuffleTwo(air: *const Air, zcu: *const Zcu, inst_index: Inst.Index
2440 };2440 };
2441}2441}
24422442
2443pub const typesFullyResolved = types_resolved.typesFullyResolved;
2444pub const typeFullyResolved = types_resolved.checkType;
2445pub const valFullyResolved = types_resolved.checkVal;
2446pub const legalize = Legalize.legalize;2443pub const legalize = Legalize.legalize;
2447pub const write = print.write;2444pub const write = print.write;
2448pub const writeInst = print.writeInst;2445pub const writeInst = print.writeInst;
src/Air/types_resolved.zig deleted-536
...@@ -1,536 +0,0 @@
1const Air = @import("../Air.zig");
2const Zcu = @import("../Zcu.zig");
3const Type = @import("../Type.zig");
4const Value = @import("../Value.zig");
5const InternPool = @import("../InternPool.zig");
6
7/// Given a body of AIR instructions, returns whether all type resolution necessary for codegen is complete.
8/// If `false`, then type resolution must have failed, so codegen cannot proceed.
9pub fn typesFullyResolved(air: Air, zcu: *Zcu) bool {
10 return checkBody(air, air.getMainBody(), zcu);
11}
12
13fn checkBody(air: Air, body: []const Air.Inst.Index, zcu: *Zcu) bool {
14 const tags = air.instructions.items(.tag);
15 const datas = air.instructions.items(.data);
16
17 for (body) |inst| {
18 const data = datas[@intFromEnum(inst)];
19 switch (tags[@intFromEnum(inst)]) {
20 .inferred_alloc, .inferred_alloc_comptime => unreachable,
21
22 .arg => {
23 if (!checkType(data.arg.ty.toType(), zcu)) return false;
24 },
25
26 .add,
27 .add_safe,
28 .add_optimized,
29 .add_wrap,
30 .add_sat,
31 .sub,
32 .sub_safe,
33 .sub_optimized,
34 .sub_wrap,
35 .sub_sat,
36 .mul,
37 .mul_safe,
38 .mul_optimized,
39 .mul_wrap,
40 .mul_sat,
41 .div_float,
42 .div_float_optimized,
43 .div_trunc,
44 .div_trunc_optimized,
45 .div_floor,
46 .div_floor_optimized,
47 .div_exact,
48 .div_exact_optimized,
49 .rem,
50 .rem_optimized,
51 .mod,
52 .mod_optimized,
53 .max,
54 .min,
55 .bit_and,
56 .bit_or,
57 .shr,
58 .shr_exact,
59 .shl,
60 .shl_exact,
61 .shl_sat,
62 .xor,
63 .cmp_lt,
64 .cmp_lt_optimized,
65 .cmp_lte,
66 .cmp_lte_optimized,
67 .cmp_eq,
68 .cmp_eq_optimized,
69 .cmp_gte,
70 .cmp_gte_optimized,
71 .cmp_gt,
72 .cmp_gt_optimized,
73 .cmp_neq,
74 .cmp_neq_optimized,
75 .bool_and,
76 .bool_or,
77 .store,
78 .store_safe,
79 .set_union_tag,
80 .array_elem_val,
81 .slice_elem_val,
82 .ptr_elem_val,
83 .memset,
84 .memset_safe,
85 .memcpy,
86 .memmove,
87 .atomic_store_unordered,
88 .atomic_store_monotonic,
89 .atomic_store_release,
90 .atomic_store_seq_cst,
91 .legalize_vec_elem_val,
92 => {
93 if (!checkRef(data.bin_op.lhs, zcu)) return false;
94 if (!checkRef(data.bin_op.rhs, zcu)) return false;
95 },
96
97 .not,
98 .bitcast,
99 .clz,
100 .ctz,
101 .popcount,
102 .byte_swap,
103 .bit_reverse,
104 .abs,
105 .load,
106 .fptrunc,
107 .fpext,
108 .intcast,
109 .intcast_safe,
110 .trunc,
111 .optional_payload,
112 .optional_payload_ptr,
113 .optional_payload_ptr_set,
114 .wrap_optional,
115 .unwrap_errunion_payload,
116 .unwrap_errunion_err,
117 .unwrap_errunion_payload_ptr,
118 .unwrap_errunion_err_ptr,
119 .errunion_payload_ptr_set,
120 .wrap_errunion_payload,
121 .wrap_errunion_err,
122 .struct_field_ptr_index_0,
123 .struct_field_ptr_index_1,
124 .struct_field_ptr_index_2,
125 .struct_field_ptr_index_3,
126 .get_union_tag,
127 .slice_len,
128 .slice_ptr,
129 .ptr_slice_len_ptr,
130 .ptr_slice_ptr_ptr,
131 .array_to_slice,
132 .int_from_float,
133 .int_from_float_optimized,
134 .int_from_float_safe,
135 .int_from_float_optimized_safe,
136 .float_from_int,
137 .splat,
138 .error_set_has_value,
139 .addrspace_cast,
140 .c_va_arg,
141 .c_va_copy,
142 => {
143 if (!checkType(data.ty_op.ty.toType(), zcu)) return false;
144 if (!checkRef(data.ty_op.operand, zcu)) return false;
145 },
146
147 .alloc,
148 .ret_ptr,
149 .c_va_start,
150 => {
151 if (!checkType(data.ty, zcu)) return false;
152 },
153
154 .ptr_add,
155 .ptr_sub,
156 .add_with_overflow,
157 .sub_with_overflow,
158 .mul_with_overflow,
159 .shl_with_overflow,
160 .slice,
161 .slice_elem_ptr,
162 .ptr_elem_ptr,
163 => {
164 const bin = air.extraData(Air.Bin, data.ty_pl.payload).data;
165 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
166 if (!checkRef(bin.lhs, zcu)) return false;
167 if (!checkRef(bin.rhs, zcu)) return false;
168 },
169
170 .block,
171 .loop,
172 => {
173 const block = air.unwrapBlock(inst);
174 if (!checkType(block.ty, zcu)) return false;
175 if (!checkBody(
176 air,
177 block.body,
178 zcu,
179 )) return false;
180 },
181
182 .dbg_inline_block => {
183 const block = air.unwrapDbgBlock(inst);
184 if (!checkType(block.ty, zcu)) return false;
185 if (!checkBody(
186 air,
187 block.body,
188 zcu,
189 )) return false;
190 },
191
192 .sqrt,
193 .sin,
194 .cos,
195 .tan,
196 .exp,
197 .exp2,
198 .log,
199 .log2,
200 .log10,
201 .floor,
202 .ceil,
203 .round,
204 .trunc_float,
205 .neg,
206 .neg_optimized,
207 .is_null,
208 .is_non_null,
209 .is_null_ptr,
210 .is_non_null_ptr,
211 .is_err,
212 .is_non_err,
213 .is_err_ptr,
214 .is_non_err_ptr,
215 .ret,
216 .ret_safe,
217 .ret_load,
218 .is_named_enum_value,
219 .tag_name,
220 .error_name,
221 .cmp_lt_errors_len,
222 .c_va_end,
223 .set_err_return_trace,
224 => {
225 if (!checkRef(data.un_op, zcu)) return false;
226 },
227
228 .br, .switch_dispatch => {
229 if (!checkRef(data.br.operand, zcu)) return false;
230 },
231
232 .cmp_vector,
233 .cmp_vector_optimized,
234 => {
235 const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data;
236 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
237 if (!checkRef(extra.lhs, zcu)) return false;
238 if (!checkRef(extra.rhs, zcu)) return false;
239 },
240
241 .reduce,
242 .reduce_optimized,
243 => {
244 if (!checkRef(data.reduce.operand, zcu)) return false;
245 },
246
247 .struct_field_ptr,
248 .struct_field_val,
249 => {
250 const extra = air.extraData(Air.StructField, data.ty_pl.payload).data;
251 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
252 if (!checkRef(extra.struct_operand, zcu)) return false;
253 },
254
255 .shuffle_one => {
256 const unwrapped = air.unwrapShuffleOne(zcu, inst);
257 if (!checkType(unwrapped.result_ty, zcu)) return false;
258 if (!checkRef(unwrapped.operand, zcu)) return false;
259 for (unwrapped.mask) |m| switch (m.unwrap()) {
260 .elem => {},
261 .value => |val| if (!checkVal(.fromInterned(val), zcu)) return false,
262 };
263 },
264
265 .shuffle_two => {
266 const unwrapped = air.unwrapShuffleTwo(zcu, inst);
267 if (!checkType(unwrapped.result_ty, zcu)) return false;
268 if (!checkRef(unwrapped.operand_a, zcu)) return false;
269 if (!checkRef(unwrapped.operand_b, zcu)) return false;
270 // No values to check because there are no comptime-known values other than undef
271 },
272
273 .cmpxchg_weak,
274 .cmpxchg_strong,
275 => {
276 const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data;
277 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
278 if (!checkRef(extra.ptr, zcu)) return false;
279 if (!checkRef(extra.expected_value, zcu)) return false;
280 if (!checkRef(extra.new_value, zcu)) return false;
281 },
282
283 .aggregate_init => {
284 const ty = data.ty_pl.ty.toType();
285 const elems_len: usize = @intCast(ty.arrayLen(zcu));
286 const elems: []const Air.Inst.Ref = @ptrCast(air.extra.items[data.ty_pl.payload..][0..elems_len]);
287 if (!checkType(ty, zcu)) return false;
288 if (ty.zigTypeTag(zcu) == .@"struct") {
289 for (elems, 0..) |elem, elem_idx| {
290 if (ty.structFieldIsComptime(elem_idx, zcu)) continue;
291 if (!checkRef(elem, zcu)) return false;
292 }
293 } else {
294 for (elems) |elem| {
295 if (!checkRef(elem, zcu)) return false;
296 }
297 }
298 },
299
300 .union_init => {
301 const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data;
302 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
303 if (!checkRef(extra.init, zcu)) return false;
304 },
305
306 .field_parent_ptr => {
307 const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data;
308 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
309 if (!checkRef(extra.field_ptr, zcu)) return false;
310 },
311
312 .atomic_load => {
313 if (!checkRef(data.atomic_load.ptr, zcu)) return false;
314 },
315
316 .prefetch => {
317 if (!checkRef(data.prefetch.ptr, zcu)) return false;
318 },
319
320 .runtime_nav_ptr => {
321 if (!checkType(.fromInterned(data.ty_nav.ty), zcu)) return false;
322 },
323
324 .select,
325 .mul_add,
326 .legalize_vec_store_elem,
327 => {
328 const bin = air.extraData(Air.Bin, data.pl_op.payload).data;
329 if (!checkRef(data.pl_op.operand, zcu)) return false;
330 if (!checkRef(bin.lhs, zcu)) return false;
331 if (!checkRef(bin.rhs, zcu)) return false;
332 },
333
334 .atomic_rmw => {
335 const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data;
336 if (!checkRef(data.pl_op.operand, zcu)) return false;
337 if (!checkRef(extra.operand, zcu)) return false;
338 },
339
340 .call,
341 .call_always_tail,
342 .call_never_tail,
343 .call_never_inline,
344 => {
345 const call = air.unwrapCall(inst);
346 const args = call.args;
347 if (!checkRef(call.callee, zcu)) return false;
348 for (args) |arg| if (!checkRef(arg, zcu)) return false;
349 },
350
351 .dbg_var_ptr,
352 .dbg_var_val,
353 .dbg_arg_inline,
354 => {
355 if (!checkRef(data.pl_op.operand, zcu)) return false;
356 },
357
358 .@"try", .try_cold => {
359 const unwrapped_try = air.unwrapTry(inst);
360 if (!checkRef(unwrapped_try.error_union, zcu)) return false;
361 if (!checkBody(
362 air,
363 unwrapped_try.else_body,
364 zcu,
365 )) return false;
366 },
367
368 .try_ptr, .try_ptr_cold => {
369 const unwrapped_try = air.unwrapTryPtr(inst);
370 if (!checkType(unwrapped_try.error_union_payload_ptr_ty.toType(), zcu)) return false;
371 if (!checkRef(unwrapped_try.error_union_ptr, zcu)) return false;
372 if (!checkBody(
373 air,
374 unwrapped_try.else_body,
375 zcu,
376 )) return false;
377 },
378
379 .cond_br => {
380 const cond_br = air.unwrapCondBr(inst);
381 if (!checkRef(cond_br.condition, zcu)) return false;
382 if (!checkBody(
383 air,
384 cond_br.then_body,
385 zcu,
386 )) return false;
387 if (!checkBody(
388 air,
389 cond_br.else_body,
390 zcu,
391 )) return false;
392 },
393
394 .switch_br, .loop_switch_br => {
395 const switch_br = air.unwrapSwitch(inst);
396 if (!checkRef(switch_br.operand, zcu)) return false;
397 var it = switch_br.iterateCases();
398 while (it.next()) |case| {
399 for (case.items) |item| if (!checkRef(item, zcu)) return false;
400 for (case.ranges) |range| {
401 if (!checkRef(range[0], zcu)) return false;
402 if (!checkRef(range[1], zcu)) return false;
403 }
404 if (!checkBody(air, case.body, zcu)) return false;
405 }
406 if (!checkBody(air, it.elseBody(), zcu)) return false;
407 },
408
409 .assembly => {
410 const unwrapped_asm = air.unwrapAsm(inst);
411 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
412 // Luckily, we only care about the inputs and outputs, so we don't have to do
413 // the whole null-terminated string dance.
414 const outputs = unwrapped_asm.outputs;
415 const inputs = unwrapped_asm.inputs;
416
417 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;
418 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
419 },
420
421 .legalize_compiler_rt_call => {
422 const rt_call = air.unwrapCompilerRtCall(inst);
423 const args = rt_call.args;
424 for (args) |arg| if (!checkRef(arg, zcu)) return false;
425 },
426
427 .trap,
428 .breakpoint,
429 .ret_addr,
430 .frame_addr,
431 .unreach,
432 .wasm_memory_size,
433 .wasm_memory_grow,
434 .work_item_id,
435 .work_group_size,
436 .work_group_id,
437 .dbg_stmt,
438 .dbg_empty_stmt,
439 .err_return_trace,
440 .save_err_return_trace_index,
441 .repeat,
442 => {},
443 }
444 }
445 return true;
446}
447
448fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {
449 const ip_index = ref.toInterned() orelse {
450 // This operand refers back to a previous instruction.
451 // We have already checked that instruction's type.
452 // So, there's no need to check this operand's type.
453 return true;
454 };
455 return checkVal(Value.fromInterned(ip_index), zcu);
456}
457
458pub fn checkVal(val: Value, zcu: *Zcu) bool {
459 const ty = val.typeOf(zcu);
460 if (!checkType(ty, zcu)) return false;
461 if (val.isUndef(zcu)) return true;
462 if (ty.toIntern() == .type_type and !checkType(val.toType(), zcu)) return false;
463 // Check for lazy values
464 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
465 .int => |int| switch (int.storage) {
466 .u64, .i64, .big_int => return true,
467 .lazy_align, .lazy_size => |ty_index| {
468 return checkType(Type.fromInterned(ty_index), zcu);
469 },
470 },
471 else => return true,
472 }
473}
474
475pub fn checkType(ty: Type, zcu: *Zcu) bool {
476 const ip = &zcu.intern_pool;
477 if (ty.isGenericPoison()) return true;
478 return switch (ty.zigTypeTag(zcu)) {
479 .type,
480 .void,
481 .bool,
482 .noreturn,
483 .int,
484 .float,
485 .error_set,
486 .@"enum",
487 .@"opaque",
488 .vector,
489 // These types can appear due to some dummy instructions Sema introduces and expects to be omitted by Liveness.
490 // It's a little silly -- but fine, we'll return `true`.
491 .comptime_float,
492 .comptime_int,
493 .undefined,
494 .null,
495 .enum_literal,
496 => true,
497
498 .frame,
499 .@"anyframe",
500 => @panic("TODO Air.types_resolved.checkType async frames"),
501
502 .optional => checkType(ty.childType(zcu), zcu),
503 .error_union => checkType(ty.errorUnionPayload(zcu), zcu),
504 .pointer => checkType(ty.childType(zcu), zcu),
505 .array => checkType(ty.childType(zcu), zcu),
506
507 .@"fn" => {
508 const info = zcu.typeToFunc(ty).?;
509 for (0..info.param_types.len) |i| {
510 const param_ty = info.param_types.get(ip)[i];
511 if (!checkType(Type.fromInterned(param_ty), zcu)) return false;
512 }
513 return checkType(Type.fromInterned(info.return_type), zcu);
514 },
515 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
516 .struct_type => {
517 const struct_obj = zcu.typeToStruct(ty).?;
518 return switch (struct_obj.layout) {
519 .@"packed" => struct_obj.backingIntTypeUnordered(ip) != .none,
520 .auto, .@"extern" => struct_obj.flagsUnordered(ip).fully_resolved,
521 };
522 },
523 .tuple_type => |tuple| {
524 for (0..tuple.types.len) |i| {
525 const field_is_comptime = tuple.values.get(ip)[i] != .none;
526 if (field_is_comptime) continue;
527 const field_ty = tuple.types.get(ip)[i];
528 if (!checkType(Type.fromInterned(field_ty), zcu)) return false;
529 }
530 return true;
531 },
532 else => unreachable,
533 },
534 .@"union" => return zcu.typeToUnion(ty).?.flagsUnordered(ip).status == .fully_resolved,
535 };
536}
src/Compilation.zig+89-96
...@@ -126,15 +126,7 @@ oneshot_prelink_tasks: std.ArrayList(link.PrelinkTask),...@@ -126,15 +126,7 @@ oneshot_prelink_tasks: std.ArrayList(link.PrelinkTask),
126/// work is queued or not.126/// work is queued or not.
127queued_jobs: QueuedJobs,127queued_jobs: QueuedJobs,
128128
129work_queues: [129work_queues: [2]std.Deque(Job),
130 len: {
131 var len: usize = 0;
132 for (std.enums.values(Job.Tag)) |tag| {
133 len = @max(Job.stage(tag) + 1, len);
134 }
135 break :len len;
136 }
137]std.Deque(Job),
138130
139/// These jobs are to invoke the Clang compiler to create an object file, which131/// These jobs are to invoke the Clang compiler to create an object file, which
140/// gets linked with the Compilation.132/// gets linked with the Compilation.
...@@ -990,35 +982,27 @@ const Job = union(enum) {...@@ -990,35 +982,27 @@ const Job = union(enum) {
990 update_line_number: InternPool.TrackedInst.Index,982 update_line_number: InternPool.TrackedInst.Index,
991 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.983 /// The `AnalUnit`, which is *not* a `func`, must be semantically analyzed.
992 /// This may be its first time being analyzed, or it may be outdated.984 /// This may be its first time being analyzed, or it may be outdated.
993 /// If the unit is a test function, an `analyze_func` job will then be queued.985 /// If the unit is a function, a `codegen_func` job will be queued after analysis completes.
994 analyze_comptime_unit: InternPool.AnalUnit,986 /// If the unit is a *test* function, an `analyze_func` job will also be queued.
995 /// This function must be semantically analyzed.987 analyze_unit: InternPool.AnalUnit,
996 /// This may be its first time being analyzed, or it may be outdated.
997 /// After analysis, a `codegen_func` job will be queued.
998 /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
999 /// This job is separate from `analyze_comptime_unit` because it has a different priority.
1000 analyze_func: InternPool.Index,
1001 /// The main source file for the module needs to be analyzed.988 /// The main source file for the module needs to be analyzed.
1002 analyze_mod: *Package.Module,989 analyze_mod: *Package.Module,
1003 /// Fully resolve the given `struct` or `union` type.
1004 resolve_type_fully: InternPool.Index,
1005990
1006 /// The value is the index into `windows_libs`.991 /// The value is the index into `windows_libs`.
1007 windows_import_lib: usize,992 windows_import_lib: usize,
1008993
1009 const Tag = @typeInfo(Job).@"union".tag_type.?;994 fn stage(job: *const Job) usize {
1010 fn stage(tag: Tag) usize {995 // Prioritize functions so that codegen can get to work on them on a
1011 return switch (tag) {996 // separate thread, while Sema goes back to its own work.
1012 // Prioritize functions so that codegen can get to work on them on a997 return switch (job.*) {
1013 // separate thread, while Sema goes back to its own work.998 .codegen_func => 0,
1014 .resolve_type_fully, .analyze_func, .codegen_func => 0,999 .analyze_unit => |unit| switch (unit.unwrap()) {
1000 .func => 0,
1001 else => 1,
1002 },
1015 else => 1,1003 else => 1,
1016 };1004 };
1017 }1005 }
1018 comptime {
1019 // Job dependencies
1020 assert(stage(.resolve_type_fully) <= stage(.codegen_func));
1021 }
1022};1006};
10231007
1024pub const CObject = struct {1008pub const CObject = struct {
...@@ -3728,7 +3712,9 @@ const Header = extern struct {...@@ -3728,7 +3712,9 @@ const Header = extern struct {
3728 src_hash_deps_len: u32,3712 src_hash_deps_len: u32,
3729 nav_val_deps_len: u32,3713 nav_val_deps_len: u32,
3730 nav_ty_deps_len: u32,3714 nav_ty_deps_len: u32,
3731 interned_deps_len: u32,3715 type_layout_deps_len: u32,
3716 type_inits_deps_len: u32,
3717 func_ies_deps_len: u32,
3732 zon_file_deps_len: u32,3718 zon_file_deps_len: u32,
3733 embed_file_deps_len: u32,3719 embed_file_deps_len: u32,
3734 namespace_deps_len: u32,3720 namespace_deps_len: u32,
...@@ -3776,7 +3762,9 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3776,7 +3762,9 @@ pub fn saveState(comp: *Compilation) !void {
3776 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),3762 .src_hash_deps_len = @intCast(ip.src_hash_deps.count()),
3777 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),3763 .nav_val_deps_len = @intCast(ip.nav_val_deps.count()),
3778 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),3764 .nav_ty_deps_len = @intCast(ip.nav_ty_deps.count()),
3779 .interned_deps_len = @intCast(ip.interned_deps.count()),3765 .type_layout_deps_len = @intCast(ip.type_layout_deps.count()),
3766 .type_inits_deps_len = @intCast(ip.type_inits_deps.count()),
3767 .func_ies_deps_len = @intCast(ip.func_ies_deps.count()),
3780 .zon_file_deps_len = @intCast(ip.zon_file_deps.count()),3768 .zon_file_deps_len = @intCast(ip.zon_file_deps.count()),
3781 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()),3769 .embed_file_deps_len = @intCast(ip.embed_file_deps.count()),
3782 .namespace_deps_len = @intCast(ip.namespace_deps.count()),3770 .namespace_deps_len = @intCast(ip.namespace_deps.count()),
...@@ -3800,7 +3788,7 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3800,7 +3788,7 @@ pub fn saveState(comp: *Compilation) !void {
3800 },3788 },
3801 });3789 });
38023790
3803 try bufs.ensureTotalCapacityPrecise(22 + 9 * pt_headers.items.len);3791 try bufs.ensureTotalCapacityPrecise(26 + 9 * pt_headers.items.len);
3804 addBuf(&bufs, mem.asBytes(&header));3792 addBuf(&bufs, mem.asBytes(&header));
3805 addBuf(&bufs, @ptrCast(pt_headers.items));3793 addBuf(&bufs, @ptrCast(pt_headers.items));
38063794
...@@ -3810,8 +3798,12 @@ pub fn saveState(comp: *Compilation) !void {...@@ -3810,8 +3798,12 @@ pub fn saveState(comp: *Compilation) !void {
3810 addBuf(&bufs, @ptrCast(ip.nav_val_deps.values()));3798 addBuf(&bufs, @ptrCast(ip.nav_val_deps.values()));
3811 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys()));3799 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.keys()));
3812 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));3800 addBuf(&bufs, @ptrCast(ip.nav_ty_deps.values()));
3813 addBuf(&bufs, @ptrCast(ip.interned_deps.keys()));3801 addBuf(&bufs, @ptrCast(ip.type_layout_deps.keys()));
3814 addBuf(&bufs, @ptrCast(ip.interned_deps.values()));3802 addBuf(&bufs, @ptrCast(ip.type_layout_deps.values()));
3803 addBuf(&bufs, @ptrCast(ip.type_inits_deps.keys()));
3804 addBuf(&bufs, @ptrCast(ip.type_inits_deps.values()));
3805 addBuf(&bufs, @ptrCast(ip.func_ies_deps.keys()));
3806 addBuf(&bufs, @ptrCast(ip.func_ies_deps.values()));
3815 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));3807 addBuf(&bufs, @ptrCast(ip.zon_file_deps.keys()));
3816 addBuf(&bufs, @ptrCast(ip.zon_file_deps.values()));3808 addBuf(&bufs, @ptrCast(ip.zon_file_deps.values()));
3817 addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys()));3809 addBuf(&bufs, @ptrCast(ip.embed_file_deps.keys()));
...@@ -4489,7 +4481,7 @@ pub fn addModuleErrorMsg(...@@ -4489,7 +4481,7 @@ pub fn addModuleErrorMsg(
4489 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {4481 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) {
4490 .@"comptime" => "comptime",4482 .@"comptime" => "comptime",
4491 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),4483 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
4492 .type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),4484 .type_layout, .type_inits => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
4493 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),4485 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
4494 .memoized_state => null,4486 .memoized_state => null,
4495 };4487 };
...@@ -4900,15 +4892,7 @@ fn performAllTheWork(...@@ -4900,15 +4892,7 @@ fn performAllTheWork(
4900 // If there's no work queued, check if there's anything outdated4892 // If there's no work queued, check if there's anything outdated
4901 // which we need to work on, and queue it if so.4893 // which we need to work on, and queue it if so.
4902 if (try zcu.findOutdatedToAnalyze()) |outdated| {4894 if (try zcu.findOutdatedToAnalyze()) |outdated| {
4903 try comp.queueJob(switch (outdated.unwrap()) {4895 try comp.queueJob(.{ .analyze_unit = outdated });
4904 .func => |f| .{ .analyze_func = f },
4905 .memoized_state,
4906 .@"comptime",
4907 .nav_ty,
4908 .nav_val,
4909 .type,
4910 => .{ .analyze_comptime_unit = outdated },
4911 });
4912 continue;4896 continue;
4913 }4897 }
4914 zcu.sema_prog_node.end();4898 zcu.sema_prog_node.end();
...@@ -5151,7 +5135,7 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node...@@ -5151,7 +5135,7 @@ fn dispatchPrelinkWork(comp: *Compilation, main_progress_node: std.Progress.Node
5151const JobError = Allocator.Error || Io.Cancelable;5135const JobError = Allocator.Error || Io.Cancelable;
51525136
5153pub fn queueJob(comp: *Compilation, job: Job) !void {5137pub fn queueJob(comp: *Compilation, job: Job) !void {
5154 try comp.work_queues[Job.stage(job)].pushBack(comp.gpa, job);5138 try comp.work_queues[job.stage()].pushBack(comp.gpa, job);
5155}5139}
51565140
5157pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {5141pub fn queueJobs(comp: *Compilation, jobs: []const Job) !void {
...@@ -5166,13 +5150,24 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v...@@ -5166,13 +5150,24 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
5166 var owned_air: ?Air = func.air;5150 var owned_air: ?Air = func.air;
5167 defer if (owned_air) |*air| air.deinit(gpa);5151 defer if (owned_air) |*air| air.deinit(gpa);
51685152
5169 if (!owned_air.?.typesFullyResolved(zcu)) {5153 {
5170 // Type resolution failed in a way which affects this function. This is a transitive5154 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
5171 // failure, but it doesn't need recording, because this function semantically depends5155 defer pt.deactivate();
5172 // on the failed type, so when it is changed the function is updated.5156 pt.resolveAirTypesForCodegen(&owned_air.?) catch |err| switch (err) {
5173 zcu.codegen_prog_node.completeOne();5157 error.OutOfMemory,
5174 comp.link_prog_node.completeOne();5158 error.Canceled,
5175 return;5159 => |e| return e,
5160
5161 error.AnalysisFail => {
5162 // Type resolution failed, making codegen of this function impossible. This
5163 // is a transitive failure, but it doesn't need recording, because this
5164 // function semantically depends on the failed type, so when it is changed
5165 // the function will be updated.
5166 zcu.codegen_prog_node.completeOne();
5167 comp.link_prog_node.completeOne();
5168 return;
5169 },
5170 };
5176 }5171 }
51775172
5178 // Some linkers need to refer to the AIR. In that case, the linker is not running5173 // Some linkers need to refer to the AIR. In that case, the linker is not running
...@@ -5198,45 +5193,54 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v...@@ -5198,45 +5193,54 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
5198 }5193 }
5199 }5194 }
5200 assert(nav.status == .fully_resolved);5195 assert(nav.status == .fully_resolved);
5201 if (!Air.valFullyResolved(zcu.navValue(nav_index), zcu)) {5196 {
5202 // Type resolution failed in a way which affects this `Nav`. This is a transitive5197 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
5203 // failure, but it doesn't need recording, because this `Nav` semantically depends5198 defer pt.deactivate();
5204 // on the failed type, so when it is changed the `Nav` will be updated.5199 pt.resolveValueTypesForCodegen(zcu.navValue(nav_index)) catch |err| switch (err) {
5205 comp.link_prog_node.completeOne();5200 error.OutOfMemory,
5206 return;5201 error.Canceled,
5202 => |e| return e,
5203
5204 error.AnalysisFail => {
5205 // Type resolution failed, making codegen of this `Nav` impossible. This is
5206 // a transitive failure, but it doesn't need recording, because this `Nav`
5207 // semantically depends on the failed type, so when it is changed the value
5208 // of the `Nav` will be updated.
5209 comp.link_prog_node.completeOne();
5210 return;
5211 },
5212 };
5207 }5213 }
5208 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_nav = nav_index });5214 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_nav = nav_index });
5209 },5215 },
5210 .link_type => |ty| {5216 .link_type => |ty| {
5211 const zcu = comp.zcu.?;5217 const zcu = comp.zcu.?;
5212 if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);5218 if (zcu.failed_types.fetchSwapRemove(ty)) |*entry| entry.value.deinit(zcu.gpa);
5213 if (!Air.typeFullyResolved(.fromInterned(ty), zcu)) {5219 {
5214 // Type resolution failed in a way which affects this type. This is a transitive5220 const pt: Zcu.PerThread = .activate(zcu, @enumFromInt(tid));
5215 // failure, but it doesn't need recording, because this type semantically depends5221 defer pt.deactivate();
5216 // on the failed type, so when that is changed, this type will be updated.5222 pt.resolveTypeForCodegen(.fromInterned(ty)) catch |err| switch (err) {
5217 comp.link_prog_node.completeOne();5223 error.OutOfMemory,
5218 return;5224 error.Canceled,
5225 => |e| return e,
5226
5227 error.AnalysisFail => {
5228 // Type resolution failed, making codegen of this type impossible. This is
5229 // a transitive failure, but it doesn't need recording, because this type
5230 // semantically depends on the failed type, so when it is changed the type
5231 // will be updated appropriately.
5232 comp.link_prog_node.completeOne();
5233 return;
5234 },
5235 };
5219 }5236 }
5220 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_type = ty });5237 try comp.link_queue.enqueueZcu(comp, tid, .{ .link_type = ty });
5221 },5238 },
5222 .update_line_number => |tracked_inst| {5239 .update_line_number => |tracked_inst| {
5223 try comp.link_queue.enqueueZcu(comp, tid, .{ .update_line_number = tracked_inst });5240 try comp.link_queue.enqueueZcu(comp, tid, .{ .update_line_number = tracked_inst });
5224 },5241 },
5225 .analyze_func => |func| {5242 .analyze_unit => |unit| {
5226 const tracy_trace = traceNamed(@src(), "analyze_func");5243 const tracy_trace = traceNamed(@src(), "analyze_unit");
5227 defer tracy_trace.end();
5228
5229 const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
5230 defer pt.deactivate();
5231
5232 pt.ensureFuncBodyUpToDate(func) catch |err| switch (err) {
5233 error.OutOfMemory => |e| return e,
5234 error.Canceled => |e| return e,
5235 error.AnalysisFail => return,
5236 };
5237 },
5238 .analyze_comptime_unit => |unit| {
5239 const tracy_trace = traceNamed(@src(), "analyze_comptime_unit");
5240 defer tracy_trace.end();5244 defer tracy_trace.end();
52415245
5242 const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);5246 const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
...@@ -5246,9 +5250,10 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v...@@ -5246,9 +5250,10 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
5246 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),5250 .@"comptime" => |cu| pt.ensureComptimeUnitUpToDate(cu),
5247 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),5251 .nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
5248 .nav_val => |nav| pt.ensureNavValUpToDate(nav),5252 .nav_val => |nav| pt.ensureNavValUpToDate(nav),
5249 .type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,5253 .type_layout => |ty| pt.ensureTypeLayoutUpToDate(.fromInterned(ty)),
5254 .type_inits => |ty| pt.ensureTypeInitsUpToDate(.fromInterned(ty)),
5250 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),5255 .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),
5251 .func => unreachable,5256 .func => |func| pt.ensureFuncBodyUpToDate(func),
5252 };5257 };
5253 maybe_err catch |err| switch (err) {5258 maybe_err catch |err| switch (err) {
5254 error.OutOfMemory => |e| return e,5259 error.OutOfMemory => |e| return e,
...@@ -5275,27 +5280,15 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v...@@ -5275,27 +5280,15 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v
5275 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val);5280 try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val);
5276 }5281 }
5277 },5282 },
5278 .resolve_type_fully => |ty| {
5279 const tracy_trace = traceNamed(@src(), "resolve_type_fully");
5280 defer tracy_trace.end();
5281
5282 const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
5283 defer pt.deactivate();
5284 Type.fromInterned(ty).resolveFully(pt) catch |err| switch (err) {
5285 error.OutOfMemory, error.Canceled => |e| return e,
5286 error.AnalysisFail => return,
5287 };
5288 },
5289 .analyze_mod => |mod| {5283 .analyze_mod => |mod| {
5290 const tracy_trace = traceNamed(@src(), "analyze_mod");5284 const tracy_trace = traceNamed(@src(), "analyze_mod");
5291 defer tracy_trace.end();5285 defer tracy_trace.end();
52925286
5293 const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);5287 const pt: Zcu.PerThread = .activate(comp.zcu.?, tid);
5294 defer pt.deactivate();5288 defer pt.deactivate();
5295 pt.semaMod(mod) catch |err| switch (err) {5289
5296 error.OutOfMemory, error.Canceled => |e| return e,5290 const mod_root_file = pt.zcu.module_roots.get(mod).?.unwrap().?;
5297 error.AnalysisFail => return,5291 try pt.ensureFileAnalyzed(mod_root_file);
5298 };
5299 },5292 },
5300 .windows_import_lib => |index| {5293 .windows_import_lib => |index| {
5301 const tracy_trace = traceNamed(@src(), "windows_import_lib");5294 const tracy_trace = traceNamed(@src(), "windows_import_lib");
src/IncrementalDebugServer.zig+6-8
...@@ -306,12 +306,8 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const...@@ -306,12 +306,8 @@ fn handleCommand(zcu: *Zcu, w: *Io.Writer, cmd_str: []const u8, arg_str: []const
306 try w.print("[{d}] ", .{i});306 try w.print("[{d}] ", .{i});
307 switch (dependee) {307 switch (dependee) {
308 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),308 .src_hash, .namespace, .namespace_name, .zon_file, .embed_file => try w.print("{f}", .{zcu.fmtDependee(dependee)}),
309 .nav_val, .nav_ty => |nav| try w.print("{s} {d}", .{ @tagName(dependee), @intFromEnum(nav) }),309 .nav_val, .nav_ty => |nav| try w.print("{t} {d}", .{ dependee, @intFromEnum(nav) }),
310 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {310 .type_layout, .type_inits, .func_ies => |ip_index| try w.print("{t} {d}", .{ dependee, @intFromEnum(ip_index) }),
311 .struct_type, .union_type, .enum_type => try w.print("type {d}", .{@intFromEnum(ip_index)}),
312 .func => try w.print("func {d}", .{@intFromEnum(ip_index)}),
313 else => unreachable,
314 },
315 .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}),311 .memoized_state => |stage| try w.print("memoized_state {s}", .{@tagName(stage)}),
316 }312 }
317 try w.writeByte('\n');313 try w.writeByte('\n');
...@@ -376,8 +372,10 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit {...@@ -376,8 +372,10 @@ fn parseAnalUnit(str: []const u8) ?AnalUnit {
376 return .wrap(.{ .nav_val = @enumFromInt(parseIndex(idx_str) orelse return null) });372 return .wrap(.{ .nav_val = @enumFromInt(parseIndex(idx_str) orelse return null) });
377 } else if (std.mem.eql(u8, kind, "nav_ty")) {373 } else if (std.mem.eql(u8, kind, "nav_ty")) {
378 return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) });374 return .wrap(.{ .nav_ty = @enumFromInt(parseIndex(idx_str) orelse return null) });
379 } else if (std.mem.eql(u8, kind, "type")) {375 } else if (std.mem.eql(u8, kind, "type_layout")) {
380 return .wrap(.{ .type = @enumFromInt(parseIndex(idx_str) orelse return null) });376 return .wrap(.{ .type_layout = @enumFromInt(parseIndex(idx_str) orelse return null) });
377 } else if (std.mem.eql(u8, kind, "type_inits")) {
378 return .wrap(.{ .type_inits = @enumFromInt(parseIndex(idx_str) orelse return null) });
381 } else if (std.mem.eql(u8, kind, "func")) {379 } else if (std.mem.eql(u8, kind, "func")) {
382 return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) });380 return .wrap(.{ .func = @enumFromInt(parseIndex(idx_str) orelse return null) });
383 } else if (std.mem.eql(u8, kind, "memoized_state")) {381 } else if (std.mem.eql(u8, kind, "memoized_state")) {
src/InternPool.zig+1942-2736
...@@ -47,11 +47,15 @@ nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),...@@ -47,11 +47,15 @@ nav_val_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
47/// Dependencies on the type of a Nav.47/// Dependencies on the type of a Nav.
48/// Value is index into `dep_entries` of the first dependency on this Nav value.48/// Value is index into `dep_entries` of the first dependency on this Nav value.
49nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),49nav_ty_deps: std.AutoArrayHashMapUnmanaged(Nav.Index, DepEntry.Index),
50/// Dependencies on an interned value, either:50/// Dependencies on a function's inferred error set. Key is the function body, not the IES.
51/// * a runtime function (invalidated when its IES changes)51/// Value is index into `dep_entries` of the first dependency on this function's IES.
52/// * a container type requiring resolution (invalidated when the type must be recreated at a new index)52func_ies_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
53/// Value is index into `dep_entries` of the first dependency on this interned value.53/// Dependencies on the resolved layout of a `struct` or `union` type.
54interned_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),54/// Value is index into `dep_entries` of the first dependency on this type's layout.
55type_layout_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
56/// Dependencies on the resolved initializers of a `struct` or `enum` type.
57/// Value is index into `dep_entries` of the first dependency on this type's inits.
58type_inits_deps: std.AutoArrayHashMapUnmanaged(Index, DepEntry.Index),
55/// Dependencies on a ZON file. Triggered by `@import` of ZON.59/// Dependencies on a ZON file. Triggered by `@import` of ZON.
56/// Value is index into `dep_entries` of the first dependency on this ZON file.60/// Value is index into `dep_entries` of the first dependency on this ZON file.
57zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),61zon_file_deps: std.AutoArrayHashMapUnmanaged(FileIndex, DepEntry.Index),
...@@ -104,7 +108,9 @@ pub const empty: InternPool = .{...@@ -104,7 +108,9 @@ pub const empty: InternPool = .{
104 .src_hash_deps = .empty,108 .src_hash_deps = .empty,
105 .nav_val_deps = .empty,109 .nav_val_deps = .empty,
106 .nav_ty_deps = .empty,110 .nav_ty_deps = .empty,
107 .interned_deps = .empty,111 .func_ies_deps = .empty,
112 .type_layout_deps = .empty,
113 .type_inits_deps = .empty,
108 .zon_file_deps = .empty,114 .zon_file_deps = .empty,
109 .embed_file_deps = .empty,115 .embed_file_deps = .empty,
110 .namespace_deps = .empty,116 .namespace_deps = .empty,
...@@ -415,7 +421,8 @@ pub const AnalUnit = packed struct(u64) {...@@ -415,7 +421,8 @@ pub const AnalUnit = packed struct(u64) {
415 @"comptime",421 @"comptime",
416 nav_val,422 nav_val,
417 nav_ty,423 nav_ty,
418 type,424 type_layout,
425 type_inits,
419 func,426 func,
420 memoized_state,427 memoized_state,
421 };428 };
...@@ -427,9 +434,11 @@ pub const AnalUnit = packed struct(u64) {...@@ -427,9 +434,11 @@ pub const AnalUnit = packed struct(u64) {
427 nav_val: Nav.Index,434 nav_val: Nav.Index,
428 /// This `AnalUnit` resolves the type of the given `Nav`.435 /// This `AnalUnit` resolves the type of the given `Nav`.
429 nav_ty: Nav.Index,436 nav_ty: Nav.Index,
430 /// This `AnalUnit` resolves the given `struct`/`union`/`enum` type.437 /// This `AnalUnit` resolves the layout of the given `struct` or `union` type.
431 /// Generated tag enums are never used here (they do not undergo type resolution).438 type_layout: InternPool.Index,
432 type: InternPool.Index,439 /// This `AnalUnit` resolves the field inits of the given `struct` or `enum` type.
440 /// The type may be a union's auto-generated tag enum, if the union has explicit field values.
441 type_inits: InternPool.Index,
433 /// This `AnalUnit` analyzes the body of the given runtime function.442 /// This `AnalUnit` analyzes the body of the given runtime function.
434 func: InternPool.Index,443 func: InternPool.Index,
435 /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.444 /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.
...@@ -840,7 +849,10 @@ pub const Dependee = union(enum) {...@@ -840,7 +849,10 @@ pub const Dependee = union(enum) {
840 src_hash: TrackedInst.Index,849 src_hash: TrackedInst.Index,
841 nav_val: Nav.Index,850 nav_val: Nav.Index,
842 nav_ty: Nav.Index,851 nav_ty: Nav.Index,
843 interned: Index,852 /// Index is the function, not its IES.
853 func_ies: Index,
854 type_layout: Index,
855 type_inits: Index,
844 zon_file: FileIndex,856 zon_file: FileIndex,
845 embed_file: Zcu.EmbedFile.Index,857 embed_file: Zcu.EmbedFile.Index,
846 namespace: TrackedInst.Index,858 namespace: TrackedInst.Index,
...@@ -892,7 +904,9 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI...@@ -892,7 +904,9 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
892 .src_hash => |x| ip.src_hash_deps.get(x),904 .src_hash => |x| ip.src_hash_deps.get(x),
893 .nav_val => |x| ip.nav_val_deps.get(x),905 .nav_val => |x| ip.nav_val_deps.get(x),
894 .nav_ty => |x| ip.nav_ty_deps.get(x),906 .nav_ty => |x| ip.nav_ty_deps.get(x),
895 .interned => |x| ip.interned_deps.get(x),907 .func_ies => |x| ip.func_ies_deps.get(x),
908 .type_layout => |x| ip.type_layout_deps.get(x),
909 .type_inits => |x| ip.type_inits_deps.get(x),
896 .zon_file => |x| ip.zon_file_deps.get(x),910 .zon_file => |x| ip.zon_file_deps.get(x),
897 .embed_file => |x| ip.embed_file_deps.get(x),911 .embed_file => |x| ip.embed_file_deps.get(x),
898 .namespace => |x| ip.namespace_deps.get(x),912 .namespace => |x| ip.namespace_deps.get(x),
...@@ -965,7 +979,9 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend...@@ -965,7 +979,9 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
965 .src_hash => ip.src_hash_deps,979 .src_hash => ip.src_hash_deps,
966 .nav_val => ip.nav_val_deps,980 .nav_val => ip.nav_val_deps,
967 .nav_ty => ip.nav_ty_deps,981 .nav_ty => ip.nav_ty_deps,
968 .interned => ip.interned_deps,982 .func_ies => ip.func_ies_deps,
983 .type_layout => ip.type_layout_deps,
984 .type_inits => ip.type_inits_deps,
969 .zon_file => ip.zon_file_deps,985 .zon_file => ip.zon_file_deps,
970 .embed_file => ip.embed_file_deps,986 .embed_file => ip.embed_file_deps,
971 .namespace => ip.namespace_deps,987 .namespace => ip.namespace_deps,
...@@ -2065,15 +2081,15 @@ pub const Key = union(enum) {...@@ -2065,15 +2081,15 @@ pub const Key = union(enum) {
2065 simple_type: SimpleType,2081 simple_type: SimpleType,
2066 /// This represents a struct that has been explicitly declared in source code,2082 /// This represents a struct that has been explicitly declared in source code,
2067 /// or was created with `@Struct`. It is unique and based on a declaration.2083 /// or was created with `@Struct`. It is unique and based on a declaration.
2068 struct_type: NamespaceType,2084 struct_type: ContainerType,
2069 /// This is a tuple type. Tuples are logically similar to structs, but have some2085 /// This is a tuple type. Tuples are logically similar to structs, but have some
2070 /// important differences in semantics; they do not undergo staged type resolution,2086 /// important differences in semantics; they do not undergo staged type resolution,
2071 /// so cannot be self-referential, and they are not considered container/namespace2087 /// so cannot be self-referential, and they are not considered container/namespace
2072 /// types, so cannot have declarations and have structural equality properties.2088 /// types, so cannot have declarations and have structural equality properties.
2073 tuple_type: TupleType,2089 tuple_type: TupleType,
2074 union_type: NamespaceType,2090 union_type: ContainerType,
2075 opaque_type: NamespaceType,2091 opaque_type: ContainerType,
2076 enum_type: NamespaceType,2092 enum_type: ContainerType,
2077 func_type: FuncType,2093 func_type: FuncType,
2078 error_set_type: ErrorSetType,2094 error_set_type: ErrorSetType,
2079 /// The payload is the function body, either a `func_decl` or `func_instance`.2095 /// The payload is the function body, either a `func_decl` or `func_instance`.
...@@ -2211,16 +2227,10 @@ pub const Key = union(enum) {...@@ -2211,16 +2227,10 @@ pub const Key = union(enum) {
2211 /// * `loadUnionType`2227 /// * `loadUnionType`
2212 /// * `loadEnumType`2228 /// * `loadEnumType`
2213 /// * `loadOpaqueType`2229 /// * `loadOpaqueType`
2214 pub const NamespaceType = union(enum) {2230 pub const ContainerType = union(enum) {
2215 /// This type corresponds to an actual source declaration, e.g. `struct { ... }`.2231 /// This type corresponds to an actual source declaration, e.g. `struct { ... }`.
2216 /// It is hashed based on its ZIR instruction index and set of captures.2232 /// It is hashed based on its ZIR instruction index and set of captures.
2217 declared: Declared,2233 declared: Declared,
2218 /// This type is an automatically-generated enum tag type for a union.
2219 /// It is hashed based on the index of the union type it corresponds to.
2220 generated_tag: struct {
2221 /// The union for which this is a tag type.
2222 union_type: Index,
2223 },
2224 /// This type originates from a reification via `@Enum`, `@Struct`, `@Union` or from an anonymous initialization.2234 /// This type originates from a reification via `@Enum`, `@Struct`, `@Union` or from an anonymous initialization.
2225 /// It is hashed based on its ZIR instruction index and fields, attributes, etc.2235 /// It is hashed based on its ZIR instruction index and fields, attributes, etc.
2226 /// To avoid making this key overly complex, the type-specific data is hashed by Sema.2236 /// To avoid making this key overly complex, the type-specific data is hashed by Sema.
...@@ -2231,10 +2241,17 @@ pub const Key = union(enum) {...@@ -2231,10 +2241,17 @@ pub const Key = union(enum) {
2231 /// A hash of this type's attributes, fields, etc, generated by Sema.2241 /// A hash of this type's attributes, fields, etc, generated by Sema.
2232 type_hash: u64,2242 type_hash: u64,
2233 },2243 },
2244 /// This type is an automatically-generated enum tag type for this union type.
2245 /// It is hashed based on the index of the union type it corresponds to.
2246 generated_union_tag: Index,
22342247
2235 pub const Declared = struct {2248 pub const Declared = struct {
2236 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.2249 /// A `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl` instruction.
2237 zir_index: TrackedInst.Index,2250 zir_index: TrackedInst.Index,
2251 /// If the type declaration had an argument type (tag type or packed backing type), this
2252 /// is that type. Otherwise, this is `.none`. It is always `.none` for `opaque` types as
2253 /// `opaque(T)` does not exist.
2254 arg_ty: Index,
2238 /// The captured values of this type. These values must be fully resolved per the language spec.2255 /// The captured values of this type. These values must be fully resolved per the language spec.
2239 captures: union(enum) {2256 captures: union(enum) {
2240 owned: CaptureValue.Slice,2257 owned: CaptureValue.Slice,
...@@ -2254,7 +2271,6 @@ pub const Key = union(enum) {...@@ -2254,7 +2271,6 @@ pub const Key = union(enum) {
2254 noalias_bits: u32,2271 noalias_bits: u32,
2255 cc: std.builtin.CallingConvention,2272 cc: std.builtin.CallingConvention,
2256 is_var_args: bool,2273 is_var_args: bool,
2257 is_generic: bool,
2258 is_noinline: bool,2274 is_noinline: bool,
22592275
2260 pub fn paramIsComptime(self: @This(), i: u5) bool {2276 pub fn paramIsComptime(self: @This(), i: u5) bool {
...@@ -2273,7 +2289,6 @@ pub const Key = union(enum) {...@@ -2273,7 +2289,6 @@ pub const Key = union(enum) {
2273 a.comptime_bits == b.comptime_bits and2289 a.comptime_bits == b.comptime_bits and
2274 a.noalias_bits == b.noalias_bits and2290 a.noalias_bits == b.noalias_bits and
2275 a.is_var_args == b.is_var_args and2291 a.is_var_args == b.is_var_args and
2276 a.is_generic == b.is_generic and
2277 a.is_noinline == b.is_noinline and2292 a.is_noinline == b.is_noinline and
2278 std.meta.eql(a.cc, b.cc);2293 std.meta.eql(a.cc, b.cc);
2279 }2294 }
...@@ -2287,7 +2302,6 @@ pub const Key = union(enum) {...@@ -2287,7 +2302,6 @@ pub const Key = union(enum) {
2287 std.hash.autoHash(hasher, self.noalias_bits);2302 std.hash.autoHash(hasher, self.noalias_bits);
2288 std.hash.autoHash(hasher, self.cc);2303 std.hash.autoHash(hasher, self.cc);
2289 std.hash.autoHash(hasher, self.is_var_args);2304 std.hash.autoHash(hasher, self.is_var_args);
2290 std.hash.autoHash(hasher, self.is_generic);
2291 std.hash.autoHash(hasher, self.is_noinline);2305 std.hash.autoHash(hasher, self.is_noinline);
2292 }2306 }
2293 };2307 };
...@@ -2471,8 +2485,6 @@ pub const Key = union(enum) {...@@ -2471,8 +2485,6 @@ pub const Key = union(enum) {
2471 u64: u64,2485 u64: u64,
2472 i64: i64,2486 i64: i64,
2473 big_int: BigIntConst,2487 big_int: BigIntConst,
2474 lazy_align: Index,
2475 lazy_size: Index,
24762488
2477 /// Big enough to fit any non-BigInt value2489 /// Big enough to fit any non-BigInt value
2478 pub const BigIntSpace = struct {2490 pub const BigIntSpace = struct {
...@@ -2485,7 +2497,6 @@ pub const Key = union(enum) {...@@ -2485,7 +2497,6 @@ pub const Key = union(enum) {
2485 return switch (storage) {2497 return switch (storage) {
2486 .big_int => |x| x,2498 .big_int => |x| x,
2487 inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),2499 inline .u64, .i64 => |x| BigIntMutable.init(&space.limbs, x).toConst(),
2488 .lazy_align, .lazy_size => unreachable,
2489 };2500 };
2490 }2501 }
2491 };2502 };
...@@ -2734,6 +2745,7 @@ pub const Key = union(enum) {...@@ -2734,6 +2745,7 @@ pub const Key = union(enum) {
2734 switch (namespace_type) {2745 switch (namespace_type) {
2735 .declared => |declared| {2746 .declared => |declared| {
2736 std.hash.autoHash(&hasher, declared.zir_index);2747 std.hash.autoHash(&hasher, declared.zir_index);
2748 std.hash.autoHash(&hasher, declared.arg_ty);
2737 const captures = switch (declared.captures) {2749 const captures = switch (declared.captures) {
2738 .owned => |cvs| cvs.get(ip),2750 .owned => |cvs| cvs.get(ip),
2739 .external => |cvs| cvs,2751 .external => |cvs| cvs,
...@@ -2742,13 +2754,13 @@ pub const Key = union(enum) {...@@ -2742,13 +2754,13 @@ pub const Key = union(enum) {
2742 std.hash.autoHash(&hasher, cv);2754 std.hash.autoHash(&hasher, cv);
2743 }2755 }
2744 },2756 },
2745 .generated_tag => |generated_tag| {
2746 std.hash.autoHash(&hasher, generated_tag.union_type);
2747 },
2748 .reified => |reified| {2757 .reified => |reified| {
2749 std.hash.autoHash(&hasher, reified.zir_index);2758 std.hash.autoHash(&hasher, reified.zir_index);
2750 std.hash.autoHash(&hasher, reified.type_hash);2759 std.hash.autoHash(&hasher, reified.type_hash);
2751 },2760 },
2761 .generated_union_tag => |union_type| {
2762 std.hash.autoHash(&hasher, union_type);
2763 },
2752 }2764 }
2753 return hasher.final();2765 return hasher.final();
2754 },2766 },
...@@ -2756,23 +2768,12 @@ pub const Key = union(enum) {...@@ -2756,23 +2768,12 @@ pub const Key = union(enum) {
2756 .int => |int| {2768 .int => |int| {
2757 var hasher = Hash.init(seed);2769 var hasher = Hash.init(seed);
2758 // Canonicalize all integers by converting them to BigIntConst.2770 // Canonicalize all integers by converting them to BigIntConst.
2759 switch (int.storage) {2771 var buffer: Key.Int.Storage.BigIntSpace = undefined;
2760 .u64, .i64, .big_int => {2772 const big_int = int.storage.toBigInt(&buffer);
2761 var buffer: Key.Int.Storage.BigIntSpace = undefined;2773
2762 const big_int = int.storage.toBigInt(&buffer);2774 std.hash.autoHash(&hasher, int.ty);
27632775 std.hash.autoHash(&hasher, big_int.positive);
2764 std.hash.autoHash(&hasher, int.ty);2776 for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb);
2765 std.hash.autoHash(&hasher, big_int.positive);
2766 for (big_int.limbs) |limb| std.hash.autoHash(&hasher, limb);
2767 },
2768 .lazy_align, .lazy_size => |lazy_ty| {
2769 std.hash.autoHash(
2770 &hasher,
2771 @as(@typeInfo(Key.Int.Storage).@"union".tag_type.?, int.storage),
2772 );
2773 std.hash.autoHash(&hasher, lazy_ty);
2774 },
2775 }
2776 return hasher.final();2777 return hasher.final();
2777 },2778 },
27782779
...@@ -3102,27 +3103,16 @@ pub const Key = union(enum) {...@@ -3102,27 +3103,16 @@ pub const Key = union(enum) {
3102 .u64 => |bb| aa == bb,3103 .u64 => |bb| aa == bb,
3103 .i64 => |bb| aa == bb,3104 .i64 => |bb| aa == bb,
3104 .big_int => |bb| bb.orderAgainstScalar(aa) == .eq,3105 .big_int => |bb| bb.orderAgainstScalar(aa) == .eq,
3105 .lazy_align, .lazy_size => false,
3106 },3106 },
3107 .i64 => |aa| switch (b_info.storage) {3107 .i64 => |aa| switch (b_info.storage) {
3108 .u64 => |bb| aa == bb,3108 .u64 => |bb| aa == bb,
3109 .i64 => |bb| aa == bb,3109 .i64 => |bb| aa == bb,
3110 .big_int => |bb| bb.orderAgainstScalar(aa) == .eq,3110 .big_int => |bb| bb.orderAgainstScalar(aa) == .eq,
3111 .lazy_align, .lazy_size => false,
3112 },3111 },
3113 .big_int => |aa| switch (b_info.storage) {3112 .big_int => |aa| switch (b_info.storage) {
3114 .u64 => |bb| aa.orderAgainstScalar(bb) == .eq,3113 .u64 => |bb| aa.orderAgainstScalar(bb) == .eq,
3115 .i64 => |bb| aa.orderAgainstScalar(bb) == .eq,3114 .i64 => |bb| aa.orderAgainstScalar(bb) == .eq,
3116 .big_int => |bb| aa.eql(bb),3115 .big_int => |bb| aa.eql(bb),
3117 .lazy_align, .lazy_size => false,
3118 },
3119 .lazy_align => |aa| switch (b_info.storage) {
3120 .u64, .i64, .big_int, .lazy_size => false,
3121 .lazy_align => |bb| aa == bb,
3122 },
3123 .lazy_size => |aa| switch (b_info.storage) {
3124 .u64, .i64, .big_int, .lazy_align => false,
3125 .lazy_size => |bb| aa == bb,
3126 },3116 },
3127 };3117 };
3128 },3118 },
...@@ -3165,6 +3155,7 @@ pub const Key = union(enum) {...@@ -3165,6 +3155,7 @@ pub const Key = union(enum) {
3165 .declared => |a_d| {3155 .declared => |a_d| {
3166 const b_d = b_info.declared;3156 const b_d = b_info.declared;
3167 if (a_d.zir_index != b_d.zir_index) return false;3157 if (a_d.zir_index != b_d.zir_index) return false;
3158 if (a_d.arg_ty != b_d.arg_ty) return false;
3168 const a_captures = switch (a_d.captures) {3159 const a_captures = switch (a_d.captures) {
3169 .owned => |s| s.get(ip),3160 .owned => |s| s.get(ip),
3170 .external => |cvs| cvs,3161 .external => |cvs| cvs,
...@@ -3175,12 +3166,12 @@ pub const Key = union(enum) {...@@ -3175,12 +3166,12 @@ pub const Key = union(enum) {
3175 };3166 };
3176 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));3167 return std.mem.eql(u32, @ptrCast(a_captures), @ptrCast(b_captures));
3177 },3168 },
3178 .generated_tag => |a_gt| return a_gt.union_type == b_info.generated_tag.union_type,
3179 .reified => |a_r| {3169 .reified => |a_r| {
3180 const b_r = b_info.reified;3170 const b_r = b_info.reified;
3181 return a_r.zir_index == b_r.zir_index and3171 return a_r.zir_index == b_r.zir_index and
3182 a_r.type_hash == b_r.type_hash;3172 a_r.type_hash == b_r.type_hash;
3183 },3173 },
3174 .generated_union_tag => |a_union_ty| return a_union_ty == b_info.generated_union_tag,
3184 }3175 }
3185 },3176 },
3186 .aggregate => |a_info| {3177 .aggregate => |a_info| {
...@@ -3313,374 +3304,40 @@ pub const Key = union(enum) {...@@ -3313,374 +3304,40 @@ pub const Key = union(enum) {
3313 }3304 }
3314};3305};
33153306
3316pub const RequiresComptime = enum(u2) { no, yes, unknown, wip };3307pub const LoadedStructType = struct {
33173308 /// Index of the `struct_decl` or `reify` ZIR instruction.
3318// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
3319// minimal hashmap key, this type is a convenience type that contains info
3320// needed by semantic analysis.
3321pub const LoadedUnionType = struct {
3322 tid: Zcu.PerThread.Id,
3323 /// The index of the `Tag.TypeUnion` payload.
3324 extra_index: u32,
3325 // TODO: the non-fqn will be needed by the new dwarf structure
3326 /// The name of this union type.
3327 name: NullTerminatedString,
3328 /// Represents the declarations inside this union.
3329 namespace: NamespaceIndex,
3330 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3331 /// Otherwise, this is `.none`.
3332 name_nav: Nav.Index.Optional,
3333 /// The enum tag type.
3334 enum_tag_ty: Index,
3335 /// List of field types in declaration order.
3336 /// These are `none` until `status` is `have_field_types` or `have_layout`.
3337 field_types: Index.Slice,
3338 /// List of field alignments in declaration order.
3339 /// `none` means the ABI alignment of the type.
3340 /// If this slice has length 0 it means all elements are `none`.
3341 field_aligns: Alignment.Slice,
3342 /// Index of the union_decl or reify ZIR instruction.
3343 zir_index: TrackedInst.Index,3309 zir_index: TrackedInst.Index,
3344 captures: CaptureValue.Slice,3310 captures: CaptureValue.Slice,
33453311
3346 pub const RuntimeTag = enum(u2) {
3347 none,
3348 safety,
3349 tagged,
3350
3351 pub fn hasTag(self: RuntimeTag) bool {
3352 return switch (self) {
3353 .none => false,
3354 .tagged, .safety => true,
3355 };
3356 }
3357 };
3358
3359 pub const Status = enum(u3) {
3360 none,
3361 field_types_wip,
3362 have_field_types,
3363 layout_wip,
3364 have_layout,
3365 fully_resolved_wip,
3366 /// The types and all its fields have had their layout resolved.
3367 /// Even through pointer, which `have_layout` does not ensure.
3368 fully_resolved,
3369
3370 pub fn haveFieldTypes(status: Status) bool {
3371 return switch (status) {
3372 .none,
3373 .field_types_wip,
3374 => false,
3375 .have_field_types,
3376 .layout_wip,
3377 .have_layout,
3378 .fully_resolved_wip,
3379 .fully_resolved,
3380 => true,
3381 };
3382 }
3383
3384 pub fn haveLayout(status: Status) bool {
3385 return switch (status) {
3386 .none,
3387 .field_types_wip,
3388 .have_field_types,
3389 .layout_wip,
3390 => false,
3391 .have_layout,
3392 .fully_resolved_wip,
3393 .fully_resolved,
3394 => true,
3395 };
3396 }
3397 };
3398
3399 pub fn loadTagType(self: LoadedUnionType, ip: *const InternPool) LoadedEnumType {
3400 return ip.loadEnumType(self.enum_tag_ty);
3401 }
3402
3403 /// Pointer to an enum type which is used for the tag of the union.
3404 /// This type is created even for untagged unions, even when the memory
3405 /// layout does not store the tag.
3406 /// Whether zig chooses this type or the user specifies it, it is stored here.
3407 /// This will be set to the null type until status is `have_field_types`.
3408 /// This accessor is provided so that the tag type can be mutated, and so that
3409 /// when it is mutated, the mutations are observed.
3410 /// The returned pointer expires with any addition to the `InternPool`.
3411 fn tagTypePtr(self: LoadedUnionType, ip: *const InternPool) *Index {
3412 const extra = ip.getLocalShared(self.tid).extra.acquire();
3413 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "tag_ty").?;
3414 return @ptrCast(&extra.view().items(.@"0")[self.extra_index + field_index]);
3415 }
3416
3417 pub fn tagTypeUnordered(u: LoadedUnionType, ip: *const InternPool) Index {
3418 return @atomicLoad(Index, u.tagTypePtr(ip), .unordered);
3419 }
3420
3421 pub fn setTagType(u: LoadedUnionType, ip: *InternPool, io: Io, tag_type: Index) void {
3422 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3423 extra_mutex.lockUncancelable(io);
3424 defer extra_mutex.unlock(io);
3425
3426 @atomicStore(Index, u.tagTypePtr(ip), tag_type, .release);
3427 }
3428
3429 /// The returned pointer expires with any addition to the `InternPool`.
3430 fn flagsPtr(self: LoadedUnionType, ip: *const InternPool) *Tag.TypeUnion.Flags {
3431 const extra = ip.getLocalShared(self.tid).extra.acquire();
3432 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
3433 return @ptrCast(&extra.view().items(.@"0")[self.extra_index + field_index]);
3434 }
3435
3436 pub fn flagsUnordered(u: LoadedUnionType, ip: *const InternPool) Tag.TypeUnion.Flags {
3437 return @atomicLoad(Tag.TypeUnion.Flags, u.flagsPtr(ip), .unordered);
3438 }
3439
3440 pub fn setStatus(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void {
3441 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3442 extra_mutex.lockUncancelable(io);
3443 defer extra_mutex.unlock(io);
3444
3445 const flags_ptr = u.flagsPtr(ip);
3446 var flags = flags_ptr.*;
3447 flags.status = status;
3448 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3449 }
3450
3451 pub fn setStatusIfLayoutWip(u: LoadedUnionType, ip: *InternPool, io: Io, status: Status) void {
3452 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3453 extra_mutex.lockUncancelable(io);
3454 defer extra_mutex.unlock(io);
3455
3456 const flags_ptr = u.flagsPtr(ip);
3457 var flags = flags_ptr.*;
3458 if (flags.status == .layout_wip) flags.status = status;
3459 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3460 }
3461
3462 pub fn setAlignment(u: LoadedUnionType, ip: *InternPool, io: Io, alignment: Alignment) void {
3463 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3464 extra_mutex.lockUncancelable(io);
3465 defer extra_mutex.unlock(io);
3466
3467 const flags_ptr = u.flagsPtr(ip);
3468 var flags = flags_ptr.*;
3469 flags.alignment = alignment;
3470 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3471 }
3472
3473 pub fn assumeRuntimeBitsIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io) bool {
3474 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3475 extra_mutex.lockUncancelable(io);
3476 defer extra_mutex.unlock(io);
3477
3478 const flags_ptr = u.flagsPtr(ip);
3479 var flags = flags_ptr.*;
3480 defer if (flags.status == .field_types_wip) {
3481 flags.assumed_runtime_bits = true;
3482 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3483 };
3484 return flags.status == .field_types_wip;
3485 }
3486
3487 pub fn requiresComptime(u: LoadedUnionType, ip: *const InternPool) RequiresComptime {
3488 return u.flagsUnordered(ip).requires_comptime;
3489 }
3490
3491 pub fn setRequiresComptimeWip(u: LoadedUnionType, ip: *InternPool, io: Io) RequiresComptime {
3492 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3493 extra_mutex.lockUncancelable(io);
3494 defer extra_mutex.unlock(io);
3495
3496 const flags_ptr = u.flagsPtr(ip);
3497 var flags = flags_ptr.*;
3498 defer if (flags.requires_comptime == .unknown) {
3499 flags.requires_comptime = .wip;
3500 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3501 };
3502 return flags.requires_comptime;
3503 }
3504
3505 pub fn setRequiresComptime(u: LoadedUnionType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void {
3506 assert(requires_comptime != .wip); // see setRequiresComptimeWip
3507
3508 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3509 extra_mutex.lockUncancelable(io);
3510 defer extra_mutex.unlock(io);
3511
3512 const flags_ptr = u.flagsPtr(ip);
3513 var flags = flags_ptr.*;
3514 flags.requires_comptime = requires_comptime;
3515 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3516 }
3517
3518 pub fn assumePointerAlignedIfFieldTypesWip(u: LoadedUnionType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
3519 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3520 extra_mutex.lockUncancelable(io);
3521 defer extra_mutex.unlock(io);
3522
3523 const flags_ptr = u.flagsPtr(ip);
3524 var flags = flags_ptr.*;
3525 defer if (flags.status == .field_types_wip) {
3526 flags.alignment = ptr_align;
3527 flags.assumed_pointer_aligned = true;
3528 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3529 };
3530 return flags.status == .field_types_wip;
3531 }
3532
3533 /// The returned pointer expires with any addition to the `InternPool`.
3534 fn sizePtr(self: LoadedUnionType, ip: *const InternPool) *u32 {
3535 const extra = ip.getLocalShared(self.tid).extra.acquire();
3536 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "size").?;
3537 return &extra.view().items(.@"0")[self.extra_index + field_index];
3538 }
3539
3540 pub fn sizeUnordered(u: LoadedUnionType, ip: *const InternPool) u32 {
3541 return @atomicLoad(u32, u.sizePtr(ip), .unordered);
3542 }
3543
3544 /// The returned pointer expires with any addition to the `InternPool`.
3545 fn paddingPtr(self: LoadedUnionType, ip: *const InternPool) *u32 {
3546 const extra = ip.getLocalShared(self.tid).extra.acquire();
3547 const field_index = std.meta.fieldIndex(Tag.TypeUnion, "padding").?;
3548 return &extra.view().items(.@"0")[self.extra_index + field_index];
3549 }
3550
3551 pub fn paddingUnordered(u: LoadedUnionType, ip: *const InternPool) u32 {
3552 return @atomicLoad(u32, u.paddingPtr(ip), .unordered);
3553 }
3554
3555 pub fn hasTag(self: LoadedUnionType, ip: *const InternPool) bool {
3556 return self.flagsUnordered(ip).runtime_tag.hasTag();
3557 }
3558
3559 pub fn haveFieldTypes(self: LoadedUnionType, ip: *const InternPool) bool {
3560 return self.flagsUnordered(ip).status.haveFieldTypes();
3561 }
3562
3563 pub fn haveLayout(self: LoadedUnionType, ip: *const InternPool) bool {
3564 return self.flagsUnordered(ip).status.haveLayout();
3565 }
3566
3567 pub fn setHaveLayout(u: LoadedUnionType, ip: *InternPool, io: Io, size: u32, padding: u32, alignment: Alignment) void {
3568 const extra_mutex = &ip.getLocal(u.tid).mutate.extra.mutex;
3569 extra_mutex.lockUncancelable(io);
3570 defer extra_mutex.unlock(io);
3571
3572 @atomicStore(u32, u.sizePtr(ip), size, .unordered);
3573 @atomicStore(u32, u.paddingPtr(ip), padding, .unordered);
3574 const flags_ptr = u.flagsPtr(ip);
3575 var flags = flags_ptr.*;
3576 flags.alignment = alignment;
3577 flags.status = .have_layout;
3578 @atomicStore(Tag.TypeUnion.Flags, flags_ptr, flags, .release);
3579 }
3580
3581 pub fn fieldAlign(self: LoadedUnionType, ip: *const InternPool, field_index: usize) Alignment {
3582 if (self.field_aligns.len == 0) return .none;
3583 return self.field_aligns.get(ip)[field_index];
3584 }
3585
3586 /// This does not mutate the field of LoadedUnionType.
3587 pub fn setZirIndex(self: LoadedUnionType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
3588 const flags_field_index = std.meta.fieldIndex(Tag.TypeUnion, "flags").?;
3589 const zir_index_field_index = std.meta.fieldIndex(Tag.TypeUnion, "zir_index").?;
3590 const ptr: *TrackedInst.Index.Optional =
3591 @ptrCast(&ip.extra_.items[self.flags_index - flags_field_index + zir_index_field_index]);
3592 ptr.* = new_zir_index;
3593 }
3594
3595 pub fn setFieldTypes(self: LoadedUnionType, ip: *const InternPool, types: []const Index) void {
3596 @memcpy(self.field_types.get(ip), types);
3597 }
3598
3599 pub fn setFieldAligns(self: LoadedUnionType, ip: *const InternPool, aligns: []const Alignment) void {
3600 if (aligns.len == 0) return;
3601 assert(self.flagsUnordered(ip).any_aligned_fields);
3602 @memcpy(self.field_aligns.get(ip), aligns);
3603 }
3604};
3605
3606pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
3607 const unwrapped_index = index.unwrap(ip);
3608 const extra_list = unwrapped_index.getExtra(ip);
3609 const data = unwrapped_index.getData(ip);
3610 const type_union = extraDataTrail(extra_list, Tag.TypeUnion, data);
3611 const fields_len = type_union.data.fields_len;
3612
3613 var extra_index = type_union.end;
3614 const captures_len = if (type_union.data.flags.any_captures) c: {
3615 const len = extra_list.view().items(.@"0")[extra_index];
3616 extra_index += 1;
3617 break :c len;
3618 } else 0;
3619
3620 const captures: CaptureValue.Slice = .{
3621 .tid = unwrapped_index.tid,
3622 .start = extra_index,
3623 .len = captures_len,
3624 };
3625 extra_index += captures_len;
3626 if (type_union.data.flags.is_reified) {
3627 extra_index += 2; // PackedU64
3628 }
3629
3630 const field_types: Index.Slice = .{
3631 .tid = unwrapped_index.tid,
3632 .start = extra_index,
3633 .len = fields_len,
3634 };
3635 extra_index += fields_len;
3636
3637 const field_aligns = if (type_union.data.flags.any_aligned_fields) a: {
3638 const a: Alignment.Slice = .{
3639 .tid = unwrapped_index.tid,
3640 .start = extra_index,
3641 .len = fields_len,
3642 };
3643 extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
3644 break :a a;
3645 } else Alignment.Slice.empty;
3646
3647 return .{
3648 .tid = unwrapped_index.tid,
3649 .extra_index = data,
3650 .name = type_union.data.name,
3651 .name_nav = type_union.data.name_nav,
3652 .namespace = type_union.data.namespace,
3653 .enum_tag_ty = type_union.data.tag_ty,
3654 .field_types = field_types,
3655 .field_aligns = field_aligns,
3656 .zir_index = type_union.data.zir_index,
3657 .captures = captures,
3658 };
3659}
3660
3661pub const LoadedStructType = struct {
3662 tid: Zcu.PerThread.Id,
3663 /// The index of the `Tag.TypeStruct` or `Tag.TypeStructPacked` payload.
3664 extra_index: u32,
3665 // TODO: the non-fqn will be needed by the new dwarf structure3312 // TODO: the non-fqn will be needed by the new dwarf structure
3666 /// The name of this struct type.3313 /// The name of this struct type.
3667 name: NullTerminatedString,3314 name: NullTerminatedString,
3668 namespace: NamespaceIndex,
3669 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.3315 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3670 /// Otherwise, or if this is a file's root struct type, this is `.none`.3316 /// Otherwise, or if this is a file's root struct type, this is `.none`.
3671 name_nav: Nav.Index.Optional,3317 name_nav: Nav.Index.Optional,
3672 /// Index of the `struct_decl` or `reify` ZIR instruction.3318 namespace: NamespaceIndex,
3673 zir_index: TrackedInst.Index,3319
3674 layout: std.builtin.Type.ContainerLayout,3320 layout: std.builtin.Type.ContainerLayout,
3321 /// May be `undefined` if `layout != .@"packed"`.
3322 packed_backing_mode: PackedBackingMode,
3323 /// May be `undefined` if `layout != .@"packed",
3324 packed_backing_int_type: Index,
3325
3326 field_name_map: MapIndex,
3675 field_names: NullTerminatedString.Slice,3327 field_names: NullTerminatedString.Slice,
3676 field_types: Index.Slice,3328 field_types: Index.Slice,
3677 field_inits: Index.Slice,3329 field_defaults: Index.Slice,
3678 field_aligns: Alignment.Slice,3330 field_aligns: Alignment.Slice,
3679 runtime_order: RuntimeOrder.Slice,3331 field_is_comptime_bits: ComptimeBits,
3680 comptime_bits: ComptimeBits,3332 field_runtime_order: RuntimeOrder.Slice,
3681 offsets: Offsets,3333 field_offsets: Offsets,
3682 names_map: OptionalMapIndex,3334
3683 captures: CaptureValue.Slice,3335 // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`.
3336 has_no_possible_value: bool,
3337 has_one_possible_value: bool,
3338 comptime_only: bool,
3339 size: u32,
3340 alignment: Alignment,
36843341
3685 pub const ComptimeBits = struct {3342 pub const ComptimeBits = struct {
3686 tid: Zcu.PerThread.Id,3343 tid: Zcu.PerThread.Id,
...@@ -3690,22 +3347,14 @@ pub const LoadedStructType = struct {...@@ -3690,22 +3347,14 @@ pub const LoadedStructType = struct {
36903347
3691 pub const empty: ComptimeBits = .{ .tid = .main, .start = 0, .len = 0 };3348 pub const empty: ComptimeBits = .{ .tid = .main, .start = 0, .len = 0 };
36923349
3693 pub fn get(this: ComptimeBits, ip: *const InternPool) []u32 {3350 pub fn getAll(this: ComptimeBits, ip: *const InternPool) []u32 {
3694 const extra = ip.getLocalShared(this.tid).extra.acquire();3351 const extra = ip.getLocalShared(this.tid).extra.acquire();
3695 return extra.view().items(.@"0")[this.start..][0..this.len];3352 return extra.view().items(.@"0")[this.start..][0..this.len];
3696 }3353 }
36973354
3698 pub fn getBit(this: ComptimeBits, ip: *const InternPool, i: usize) bool {3355 pub fn get(this: ComptimeBits, ip: *const InternPool, i: usize) bool {
3699 if (this.len == 0) return false;3356 if (this.len == 0) return false;
3700 return @as(u1, @truncate(this.get(ip)[i / 32] >> @intCast(i % 32))) != 0;3357 return @as(u1, @truncate(this.getAll(ip)[i / 32] >> @intCast(i % 32))) != 0;
3701 }
3702
3703 pub fn setBit(this: ComptimeBits, ip: *const InternPool, i: usize) void {
3704 this.get(ip)[i / 32] |= @as(u32, 1) << @intCast(i % 32);
3705 }
3706
3707 pub fn clearBit(this: ComptimeBits, ip: *const InternPool, i: usize) void {
3708 this.get(ip)[i / 32] &= ~(@as(u32, 1) << @intCast(i % 32));
3709 }3358 }
3710 };3359 };
37113360
...@@ -3753,865 +3402,550 @@ pub const LoadedStructType = struct {...@@ -3753,865 +3402,550 @@ pub const LoadedStructType = struct {
37533402
3754 /// Look up field index based on field name.3403 /// Look up field index based on field name.
3755 pub fn nameIndex(s: LoadedStructType, ip: *const InternPool, name: NullTerminatedString) ?u32 {3404 pub fn nameIndex(s: LoadedStructType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
3756 const names_map = s.names_map.unwrap() orelse {3405 const map = s.field_name_map.get(ip);
3757 const i = name.toUnsigned(ip) orelse return null;
3758 if (i >= s.field_types.len) return null;
3759 return i;
3760 };
3761 const map = names_map.get(ip);
3762 const adapter: NullTerminatedString.Adapter = .{ .strings = s.field_names.get(ip) };3406 const adapter: NullTerminatedString.Adapter = .{ .strings = s.field_names.get(ip) };
3763 const field_index = map.getIndexAdapted(name, adapter) orelse return null;3407 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
3764 return @intCast(field_index);3408 return @intCast(field_index);
3765 }3409 }
37663410
3767 /// Returns the already-existing field with the same name, if any.3411 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
3768 pub fn addFieldName(3412 /// May or may not include zero-bit fields.
3769 s: LoadedStructType,
3770 ip: *InternPool,
3771 name: NullTerminatedString,
3772 ) ?u32 {
3773 const extra = ip.getLocalShared(s.tid).extra.acquire();
3774 return ip.addFieldName(extra, s.names_map.unwrap().?, s.field_names.start, name);
3775 }
3776
3777 pub fn fieldAlign(s: LoadedStructType, ip: *const InternPool, i: usize) Alignment {
3778 if (s.field_aligns.len == 0) return .none;
3779 return s.field_aligns.get(ip)[i];
3780 }
3781
3782 pub fn fieldInit(s: LoadedStructType, ip: *const InternPool, i: usize) Index {
3783 if (s.field_inits.len == 0) return .none;
3784 assert(s.haveFieldInits(ip));
3785 return s.field_inits.get(ip)[i];
3786 }
3787
3788 pub fn fieldName(s: LoadedStructType, ip: *const InternPool, i: usize) NullTerminatedString {
3789 return s.field_names.get(ip)[i];
3790 }
3791
3792 pub fn fieldIsComptime(s: LoadedStructType, ip: *const InternPool, i: usize) bool {
3793 return s.comptime_bits.getBit(ip, i);
3794 }
3795
3796 pub fn setFieldComptime(s: LoadedStructType, ip: *InternPool, i: usize) void {
3797 s.comptime_bits.setBit(ip, i);
3798 }
3799
3800 /// The returned pointer expires with any addition to the `InternPool`.
3801 /// Asserts the struct is not packed.3413 /// Asserts the struct is not packed.
3802 fn flagsPtr(s: LoadedStructType, ip: *const InternPool) *Tag.TypeStruct.Flags {3414 pub fn iterateRuntimeOrder(s: *const LoadedStructType, ip: *InternPool) RuntimeOrderIterator {
3803 assert(s.layout != .@"packed");3415 switch (s.layout) {
3804 const extra = ip.getLocalShared(s.tid).extra.acquire();3416 .auto => {
3805 const flags_field_index = std.meta.fieldIndex(Tag.TypeStruct, "flags").?;3417 const ro = std.mem.sliceTo(s.field_runtime_order.get(ip), .omitted);
3806 return @ptrCast(&extra.view().items(.@"0")[s.extra_index + flags_field_index]);3418 return .{
3807 }3419 .runtime_order = ro,
38083420 .fields_len = @intCast(ro.len),
3809 pub fn flagsUnordered(s: LoadedStructType, ip: *const InternPool) Tag.TypeStruct.Flags {3421 .next_index = 0,
3810 return @atomicLoad(Tag.TypeStruct.Flags, s.flagsPtr(ip), .unordered);3422 };
3811 }3423 },
38123424 .@"extern" => return .{
3813 /// The returned pointer expires with any addition to the `InternPool`.3425 .runtime_order = null,
3814 /// Asserts that the struct is packed.3426 .fields_len = s.field_names.len,
3815 fn packedFlagsPtr(s: LoadedStructType, ip: *const InternPool) *Tag.TypeStructPacked.Flags {3427 .next_index = 0,
3816 assert(s.layout == .@"packed");3428 },
3817 const extra = ip.getLocalShared(s.tid).extra.acquire();3429 .@"packed" => unreachable,
3818 const flags_field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?;3430 }
3819 return @ptrCast(&extra.view().items(.@"0")[s.extra_index + flags_field_index]);
3820 }
3821
3822 pub fn packedFlagsUnordered(s: LoadedStructType, ip: *const InternPool) Tag.TypeStructPacked.Flags {
3823 return @atomicLoad(Tag.TypeStructPacked.Flags, s.packedFlagsPtr(ip), .unordered);
3824 }3431 }
3432 pub const RuntimeOrderIterator = struct {
3433 runtime_order: ?[]const RuntimeOrder,
3434 fields_len: u32,
3435 next_index: u32,
3436 pub fn next(it: *RuntimeOrderIterator) ?u32 {
3437 const i = it.next_index;
3438 if (i == it.fields_len) return null;
3439 it.next_index = i + 1;
3440 const ro = it.runtime_order orelse return i;
3441 return ro[i].toInt().?;
3442 }
3443 };
38253444
3826 /// Reads the non-opv flag calculated during AstGen. Used to short-circuit more3445 pub fn iterateRuntimeOrderReverse(s: *const LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator {
3827 /// complicated logic.3446 switch (s.layout) {
3828 pub fn knownNonOpv(s: LoadedStructType, ip: *const InternPool) bool {3447 .auto => {
3829 return switch (s.layout) {3448 const ro = std.mem.sliceTo(s.field_runtime_order.get(ip), .omitted);
3830 .@"packed" => false,3449 return .{
3831 .auto, .@"extern" => s.flagsUnordered(ip).known_non_opv,3450 .runtime_order = ro,
3832 };3451 .last_index = @intCast(ro.len),
3452 };
3453 },
3454 .@"extern" => return .{
3455 .runtime_order = null,
3456 .last_index = s.field_names.len,
3457 },
3458 .@"packed" => unreachable,
3459 }
3833 }3460 }
3461 pub const ReverseRuntimeOrderIterator = struct {
3462 runtime_order: ?[]const RuntimeOrder,
3463 last_index: u32,
3464 pub fn next(it: *ReverseRuntimeOrderIterator) ?u32 {
3465 if (it.last_index == 0) return null;
3466 const i = it.last_index - 1;
3467 it.last_index = i;
3468 const ro = it.runtime_order orelse return i;
3469 return ro[i].toInt().?;
3470 }
3471 };
3472};
38343473
3835 pub fn requiresComptime(s: LoadedStructType, ip: *const InternPool) RequiresComptime {3474/// Unlike `Tag.TypeUnion` which is an encoding, and `Key.UnionType` which is a
3836 return s.flagsUnordered(ip).requires_comptime;3475/// minimal hashmap key, this type is a convenience type that contains info
3837 }3476/// needed by semantic analysis.
3477pub const LoadedUnionType = struct {
3478 /// Index of the `union_decl` or `reify` ZIR instruction.
3479 zir_index: TrackedInst.Index,
3480 captures: CaptureValue.Slice,
38383481
3839 pub fn setRequiresComptimeWip(s: LoadedStructType, ip: *InternPool, io: Io) RequiresComptime {3482 // TODO: the non-fqn will be needed by the new dwarf structure
3840 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;3483 /// The name of this union type.
3841 extra_mutex.lockUncancelable(io);3484 name: NullTerminatedString,
3842 defer extra_mutex.unlock(io);3485 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3486 /// Otherwise, this is `.none`.
3487 name_nav: Nav.Index.Optional,
3488 namespace: NamespaceIndex,
38433489
3844 const flags_ptr = s.flagsPtr(ip);3490 layout: std.builtin.Type.ContainerLayout,
3845 var flags = flags_ptr.*;3491 runtime_tag: RuntimeTag,
3846 defer if (flags.requires_comptime == .unknown) {3492 /// Even if `runtime_tag == .none`, this is populated with the union's "hypothetical" tag type.
3847 flags.requires_comptime = .wip;3493 enum_tag_type: Index,
3848 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);3494 /// May be `undefined` if `layout != .@"packed"`.
3849 };3495 packed_backing_mode: PackedBackingMode,
3850 return flags.requires_comptime;3496 /// May be `undefined` if `layout != .@"packed",
3851 }3497 packed_backing_int_type: Index,
3498
3499 // Field names are not stored here, because fields are guaranteed to map one-to-one to the
3500 // fields of the enum tag type. If you need field names, load them from `enum_tag_type`.
3501 field_types: Index.Slice,
3502 field_aligns: Alignment.Slice,
38523503
3853 pub fn setRequiresComptime(s: LoadedStructType, ip: *InternPool, io: Io, requires_comptime: RequiresComptime) void {3504 // These fields are only valid once the layout is resolved, and are never valid for `layout == .@"packed"`.
3854 assert(requires_comptime != .wip); // see setRequiresComptimeWip3505 has_no_possible_value: bool,
3506 has_one_possible_value: bool,
3507 comptime_only: bool,
3508 size: u32,
3509 padding: u32,
3510 alignment: Alignment,
38553511
3856 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;3512 pub const RuntimeTag = enum(u2) {
3857 extra_mutex.lockUncancelable(io);3513 none,
3858 defer extra_mutex.unlock(io);3514 safety,
3515 tagged,
3516 };
3517};
38593518
3860 const flags_ptr = s.flagsPtr(ip);3519pub const LoadedEnumType = struct {
3861 var flags = flags_ptr.*;3520 /// This is `none` iff this is a generated tag type.
3862 flags.requires_comptime = requires_comptime;3521 /// Otherwise, index of the `enum_decl` or `reify` ZIR instruction.
3863 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);3522 zir_index: TrackedInst.Index.Optional,
3864 }3523 captures: CaptureValue.Slice,
3524 /// If `zir_index` is `.none`, this is the union type for which this enum is the tag type.
3525 owner_union: Index,
38653526
3866 pub fn assumeRuntimeBitsIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {3527 // TODO: the non-fqn will be needed by the new dwarf structure
3867 if (s.layout == .@"packed") return false;3528 /// The name of this enum type.
3529 name: NullTerminatedString,
3530 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3531 /// Otherwise, this is `.none`.
3532 name_nav: Nav.Index.Optional,
3533 namespace: NamespaceIndex,
38683534
3869 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;3535 /// An integer type which is used for the numerical value of the enum. Populated immediately, regardless
3870 extra_mutex.lockUncancelable(io);3536 /// of whether the integer tag type was explicitly provided or inferred by the compiler.
3871 defer extra_mutex.unlock(io);3537 int_tag_type: Index,
3538 int_tag_is_explicit: bool,
3539 nonexhaustive: bool,
3540
3541 /// Uses `NullTerminatedString.Adapter` with `field_names`.
3542 field_name_map: MapIndex,
3543 /// If this is `.none`, the enum tag type is auto-generated and so the fields are auto-numbered.
3544 /// Otherwise, uses `Index.Adapter` with `field_values`.
3545 field_value_map: OptionalMapIndex,
3546 field_names: NullTerminatedString.Slice,
3547 /// Empty if `field_value_map` is `.none`.
3548 field_values: Index.Slice,
38723549
3873 const flags_ptr = s.flagsPtr(ip);3550 /// Look up field index based on field name.
3874 var flags = flags_ptr.*;3551 pub fn nameIndex(e: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
3875 defer if (flags.field_types_wip) {3552 const map = e.field_name_map.get(ip);
3876 flags.assumed_runtime_bits = true;3553 const adapter: NullTerminatedString.Adapter = .{ .strings = e.field_names.get(ip) };
3877 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);3554 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
3878 };3555 return @intCast(field_index);
3879 return flags.field_types_wip;
3880 }3556 }
38813557
3882 pub fn setFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {3558 /// Look up field index based on integer tag value.
3883 if (s.layout == .@"packed") return false;3559 /// Asserts that the type of `tag_val` is `enum_obj.int_tag_type`.
38843560 /// Asserts that `tag_val` is not `undefined`.
3885 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;3561 pub fn tagValueIndex(e: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 {
3886 extra_mutex.lockUncancelable(io);3562 assert(ip.typeOf(tag_val) == e.int_tag_type);
3887 defer extra_mutex.unlock(io);3563 assert(ip.indexToKey(tag_val) == .int);
38883564 if (e.field_value_map.unwrap()) |field_value_map| {
3889 const flags_ptr = s.flagsPtr(ip);3565 const map = field_value_map.get(ip);
3890 var flags = flags_ptr.*;3566 const adapter: Index.Adapter = .{ .indexes = e.field_values.get(ip) };
3891 defer {3567 const field_index = map.getIndexAdapted(tag_val, adapter) orelse return null;
3892 flags.field_types_wip = true;3568 return @intCast(field_index);
3893 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3894 }3569 }
3895 return flags.field_types_wip;3570 // Auto-numbered enum, so convert `tag_val` to field index
3571 const field_index = switch (ip.indexToKey(tag_val).int.storage) {
3572 inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
3573 .big_int => |x| x.toInt(u32) catch return null,
3574 };
3575 return if (field_index < e.field_names.len) field_index else null;
3896 }3576 }
3577};
38973578
3898 pub fn clearFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io) void {3579pub const LoadedOpaqueType = struct {
3899 if (s.layout == .@"packed") return;3580 /// Index of the `opaque_decl` instruction.
3581 zir_index: TrackedInst.Index,
3582 captures: CaptureValue.Slice,
39003583
3901 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;3584 // TODO: the non-fqn will be needed by the new dwarf structure
3902 extra_mutex.lockUncancelable(io);3585 /// The name of this opaque type.
3903 defer extra_mutex.unlock(io);3586 name: NullTerminatedString,
39043587 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
3905 const flags_ptr = s.flagsPtr(ip);3588 /// Otherwise, this is `.none`.
3906 var flags = flags_ptr.*;3589 name_nav: Nav.Index.Optional,
3907 flags.field_types_wip = false;3590 namespace: NamespaceIndex,
3908 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);3591};
3909 }
3910
3911 pub fn setLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
3912 if (s.layout == .@"packed") return false;
3913
3914 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3915 extra_mutex.lockUncancelable(io);
3916 defer extra_mutex.unlock(io);
3917
3918 const flags_ptr = s.flagsPtr(ip);
3919 var flags = flags_ptr.*;
3920 defer {
3921 flags.layout_wip = true;
3922 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3923 }
3924 return flags.layout_wip;
3925 }
3926
3927 pub fn clearLayoutWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
3928 if (s.layout == .@"packed") return;
3929
3930 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3931 extra_mutex.lockUncancelable(io);
3932 defer extra_mutex.unlock(io);
3933
3934 const flags_ptr = s.flagsPtr(ip);
3935 var flags = flags_ptr.*;
3936 flags.layout_wip = false;
3937 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3938 }
3939
3940 pub fn setAlignment(s: LoadedStructType, ip: *InternPool, io: Io, alignment: Alignment) void {
3941 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3942 extra_mutex.lockUncancelable(io);
3943 defer extra_mutex.unlock(io);
3944
3945 const flags_ptr = s.flagsPtr(ip);
3946 var flags = flags_ptr.*;
3947 flags.alignment = alignment;
3948 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3949 }
3950
3951 pub fn assumePointerAlignedIfFieldTypesWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
3952 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3953 extra_mutex.lockUncancelable(io);
3954 defer extra_mutex.unlock(io);
3955
3956 const flags_ptr = s.flagsPtr(ip);
3957 var flags = flags_ptr.*;
3958 defer if (flags.field_types_wip) {
3959 flags.alignment = ptr_align;
3960 flags.assumed_pointer_aligned = true;
3961 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3962 };
3963 return flags.field_types_wip;
3964 }
3965
3966 pub fn assumePointerAlignedIfWip(s: LoadedStructType, ip: *InternPool, io: Io, ptr_align: Alignment) bool {
3967 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3968 extra_mutex.lockUncancelable(io);
3969 defer extra_mutex.unlock(io);
3970
3971 const flags_ptr = s.flagsPtr(ip);
3972 var flags = flags_ptr.*;
3973 defer {
3974 if (flags.alignment_wip) {
3975 flags.alignment = ptr_align;
3976 flags.assumed_pointer_aligned = true;
3977 } else flags.alignment_wip = true;
3978 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3979 }
3980 return flags.alignment_wip;
3981 }
3982
3983 pub fn clearAlignmentWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
3984 if (s.layout == .@"packed") return;
3985
3986 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3987 extra_mutex.lockUncancelable(io);
3988 defer extra_mutex.unlock(io);
3989
3990 const flags_ptr = s.flagsPtr(ip);
3991 var flags = flags_ptr.*;
3992 flags.alignment_wip = false;
3993 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
3994 }
3995
3996 pub fn setInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) bool {
3997 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
3998 extra_mutex.lockUncancelable(io);
3999 defer extra_mutex.unlock(io);
4000
4001 switch (s.layout) {
4002 .@"packed" => {
4003 const flags_ptr = s.packedFlagsPtr(ip);
4004 var flags = flags_ptr.*;
4005 defer {
4006 flags.field_inits_wip = true;
4007 @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release);
4008 }
4009 return flags.field_inits_wip;
4010 },
4011 .auto, .@"extern" => {
4012 const flags_ptr = s.flagsPtr(ip);
4013 var flags = flags_ptr.*;
4014 defer {
4015 flags.field_inits_wip = true;
4016 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
4017 }
4018 return flags.field_inits_wip;
4019 },
4020 }
4021 }
4022
4023 pub fn clearInitsWip(s: LoadedStructType, ip: *InternPool, io: Io) void {
4024 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4025 extra_mutex.lockUncancelable(io);
4026 defer extra_mutex.unlock(io);
4027
4028 switch (s.layout) {
4029 .@"packed" => {
4030 const flags_ptr = s.packedFlagsPtr(ip);
4031 var flags = flags_ptr.*;
4032 flags.field_inits_wip = false;
4033 @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release);
4034 },
4035 .auto, .@"extern" => {
4036 const flags_ptr = s.flagsPtr(ip);
4037 var flags = flags_ptr.*;
4038 flags.field_inits_wip = false;
4039 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
4040 },
4041 }
4042 }
4043
4044 pub fn setFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) bool {
4045 if (s.layout == .@"packed") return true;
4046
4047 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4048 extra_mutex.lockUncancelable(io);
4049 defer extra_mutex.unlock(io);
4050
4051 const flags_ptr = s.flagsPtr(ip);
4052 var flags = flags_ptr.*;
4053 defer {
4054 flags.fully_resolved = true;
4055 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
4056 }
4057 return flags.fully_resolved;
4058 }
4059
4060 pub fn clearFullyResolved(s: LoadedStructType, ip: *InternPool, io: Io) void {
4061 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4062 extra_mutex.lockUncancelable(io);
4063 defer extra_mutex.unlock(io);
4064
4065 const flags_ptr = s.flagsPtr(ip);
4066 var flags = flags_ptr.*;
4067 flags.fully_resolved = false;
4068 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
4069 }
4070
4071 /// The returned pointer expires with any addition to the `InternPool`.
4072 /// Asserts the struct is not packed.
4073 fn sizePtr(s: LoadedStructType, ip: *const InternPool) *u32 {
4074 assert(s.layout != .@"packed");
4075 const extra = ip.getLocalShared(s.tid).extra.acquire();
4076 const size_field_index = std.meta.fieldIndex(Tag.TypeStruct, "size").?;
4077 return @ptrCast(&extra.view().items(.@"0")[s.extra_index + size_field_index]);
4078 }
4079
4080 pub fn sizeUnordered(s: LoadedStructType, ip: *const InternPool) u32 {
4081 return @atomicLoad(u32, s.sizePtr(ip), .unordered);
4082 }
4083
4084 /// The backing integer type of the packed struct. Whether zig chooses
4085 /// this type or the user specifies it, it is stored here. This will be
4086 /// set to `none` until the layout is resolved.
4087 /// Asserts the struct is packed.
4088 fn backingIntTypePtr(s: LoadedStructType, ip: *const InternPool) *Index {
4089 assert(s.layout == .@"packed");
4090 const extra = ip.getLocalShared(s.tid).extra.acquire();
4091 const field_index = std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_ty").?;
4092 return @ptrCast(&extra.view().items(.@"0")[s.extra_index + field_index]);
4093 }
4094
4095 pub fn backingIntTypeUnordered(s: LoadedStructType, ip: *const InternPool) Index {
4096 return @atomicLoad(Index, s.backingIntTypePtr(ip), .unordered);
4097 }
4098
4099 pub fn setBackingIntType(s: LoadedStructType, ip: *InternPool, io: Io, backing_int_ty: Index) void {
4100 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4101 extra_mutex.lockUncancelable(io);
4102 defer extra_mutex.unlock(io);
4103
4104 @atomicStore(Index, s.backingIntTypePtr(ip), backing_int_ty, .release);
4105 }
4106
4107 /// Asserts the struct is not packed.
4108 pub fn setZirIndex(s: LoadedStructType, ip: *InternPool, new_zir_index: TrackedInst.Index.Optional) void {
4109 assert(s.layout != .@"packed");
4110 const field_index = std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?;
4111 ip.extra_.items[s.extra_index + field_index] = @intFromEnum(new_zir_index);
4112 }
4113
4114 pub fn haveFieldTypes(s: LoadedStructType, ip: *const InternPool) bool {
4115 const types = s.field_types.get(ip);
4116 return types.len == 0 or types[types.len - 1] != .none;
4117 }
4118
4119 pub fn haveFieldInits(s: LoadedStructType, ip: *const InternPool) bool {
4120 return switch (s.layout) {
4121 .@"packed" => s.packedFlagsUnordered(ip).inits_resolved,
4122 .auto, .@"extern" => s.flagsUnordered(ip).inits_resolved,
4123 };
4124 }
4125
4126 pub fn setHaveFieldInits(s: LoadedStructType, ip: *InternPool, io: Io) void {
4127 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4128 extra_mutex.lockUncancelable(io);
4129 defer extra_mutex.unlock(io);
4130
4131 switch (s.layout) {
4132 .@"packed" => {
4133 const flags_ptr = s.packedFlagsPtr(ip);
4134 var flags = flags_ptr.*;
4135 flags.inits_resolved = true;
4136 @atomicStore(Tag.TypeStructPacked.Flags, flags_ptr, flags, .release);
4137 },
4138 .auto, .@"extern" => {
4139 const flags_ptr = s.flagsPtr(ip);
4140 var flags = flags_ptr.*;
4141 flags.inits_resolved = true;
4142 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
4143 },
4144 }
4145 }
4146
4147 pub fn haveLayout(s: LoadedStructType, ip: *const InternPool) bool {
4148 return switch (s.layout) {
4149 .@"packed" => s.backingIntTypeUnordered(ip) != .none,
4150 .auto, .@"extern" => s.flagsUnordered(ip).layout_resolved,
4151 };
4152 }
4153
4154 pub fn setLayoutResolved(s: LoadedStructType, ip: *InternPool, io: Io, size: u32, alignment: Alignment) void {
4155 const extra_mutex = &ip.getLocal(s.tid).mutate.extra.mutex;
4156 extra_mutex.lockUncancelable(io);
4157 defer extra_mutex.unlock(io);
4158
4159 @atomicStore(u32, s.sizePtr(ip), size, .unordered);
4160 const flags_ptr = s.flagsPtr(ip);
4161 var flags = flags_ptr.*;
4162 flags.alignment = alignment;
4163 flags.layout_resolved = true;
4164 @atomicStore(Tag.TypeStruct.Flags, flags_ptr, flags, .release);
4165 }
4166
4167 pub fn hasReorderedFields(s: LoadedStructType) bool {
4168 return s.layout == .auto;
4169 }
4170
4171 pub const RuntimeOrderIterator = struct {
4172 ip: *InternPool,
4173 field_index: u32,
4174 struct_type: InternPool.LoadedStructType,
4175
4176 pub fn next(it: *@This()) ?u32 {
4177 var i = it.field_index;
4178
4179 if (i >= it.struct_type.field_types.len)
4180 return null;
4181
4182 if (it.struct_type.hasReorderedFields()) {
4183 it.field_index += 1;
4184 return it.struct_type.runtime_order.get(it.ip)[i].toInt();
4185 }
4186
4187 while (it.struct_type.fieldIsComptime(it.ip, i)) {
4188 i += 1;
4189 if (i >= it.struct_type.field_types.len)
4190 return null;
4191 }
4192
4193 it.field_index = i + 1;
4194 return i;
4195 }
4196 };
4197
4198 /// Iterates over non-comptime fields in the order they are laid out in memory at runtime.
4199 /// May or may not include zero-bit fields.
4200 /// Asserts the struct is not packed.
4201 pub fn iterateRuntimeOrder(s: LoadedStructType, ip: *InternPool) RuntimeOrderIterator {
4202 assert(s.layout != .@"packed");
4203 return .{
4204 .ip = ip,
4205 .field_index = 0,
4206 .struct_type = s,
4207 };
4208 }
4209
4210 pub const ReverseRuntimeOrderIterator = struct {
4211 ip: *InternPool,
4212 last_index: u32,
4213 struct_type: InternPool.LoadedStructType,
4214
4215 pub fn next(it: *@This()) ?u32 {
4216 if (it.last_index == 0)
4217 return null;
4218
4219 if (it.struct_type.hasReorderedFields()) {
4220 it.last_index -= 1;
4221 const order = it.struct_type.runtime_order.get(it.ip);
4222 while (order[it.last_index] == .omitted) {
4223 it.last_index -= 1;
4224 if (it.last_index == 0)
4225 return null;
4226 }
4227 return order[it.last_index].toInt();
4228 }
4229
4230 it.last_index -= 1;
4231 while (it.struct_type.fieldIsComptime(it.ip, it.last_index)) {
4232 it.last_index -= 1;
4233 if (it.last_index == 0)
4234 return null;
4235 }
4236
4237 return it.last_index;
4238 }
4239 };
4240
4241 pub fn iterateRuntimeOrderReverse(s: LoadedStructType, ip: *InternPool) ReverseRuntimeOrderIterator {
4242 assert(s.layout != .@"packed");
4243 return .{
4244 .ip = ip,
4245 .last_index = s.field_types.len,
4246 .struct_type = s,
4247 };
4248 }
4249};
42503592
4251pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {3593pub fn loadStructType(ip: *const InternPool, index: Index) LoadedStructType {
4252 const unwrapped_index = index.unwrap(ip);3594 const unwrapped_index = index.unwrap(ip);
4253 const extra_list = unwrapped_index.getExtra(ip);3595 const extra_list = unwrapped_index.getExtra(ip);
4254 const extra_items = extra_list.view().items(.@"0");3596 const extra_items = extra_list.view().items(.@"0");
4255 const item = unwrapped_index.getItem(ip);3597 const item = unwrapped_index.getItem(ip);
4256 switch (item.tag) {3598 // Exiting this `switch` means this is a `packed struct`.
3599 const backing_mode: PackedBackingMode, const any_defaults: bool = switch (item.tag) {
3600 .type_struct_packed_auto => .{ .auto, false },
3601 .type_struct_packed_explicit => .{ .explicit, false },
3602 .type_struct_packed_auto_defaults => .{ .auto, true },
3603 .type_struct_packed_explicit_defaults => .{ .explicit, true },
4257 .type_struct => {3604 .type_struct => {
4258 const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name").?]);3605 const extra = extraDataTrail(extra_list, Tag.TypeStruct, item.data);
4259 const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?]);3606 var extra_index = extra.end;
4260 const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?]);3607 const captures: CaptureValue.Slice = switch (extra.data.flags.any_captures) {
4261 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);3608 .reified => captures: {
4262 const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "fields_len").?];3609 extra_index += 2; // type_hash: PackedU64
4263 const flags: Tag.TypeStruct.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?], .unordered));3610 break :captures .empty;
4264 var extra_index = item.data + @as(u32, @typeInfo(Tag.TypeStruct).@"struct".fields.len);3611 },
4265 const captures_len = if (flags.any_captures) c: {3612 .false => .empty,
4266 const len = extra_list.view().items(.@"0")[extra_index];3613 .true => captures: {
4267 extra_index += 1;3614 const len = extra_items[extra_index];
4268 break :c len;3615 extra_index += 1;
4269 } else 0;3616 break :captures .{
4270 const captures: CaptureValue.Slice = .{3617 .tid = unwrapped_index.tid,
3618 .start = extra_index,
3619 .len = len,
3620 };
3621 },
3622 };
3623 extra_index += captures.len;
3624 const field_names: NullTerminatedString.Slice = .{
4271 .tid = unwrapped_index.tid,3625 .tid = unwrapped_index.tid,
4272 .start = extra_index,3626 .start = extra_index,
4273 .len = captures_len,3627 .len = extra.data.fields_len,
4274 };3628 };
4275 extra_index += captures_len;3629 extra_index += field_names.len;
4276 if (flags.is_reified) {
4277 extra_index += 2; // type_hash: PackedU64
4278 }
4279 const field_types: Index.Slice = .{3630 const field_types: Index.Slice = .{
4280 .tid = unwrapped_index.tid,3631 .tid = unwrapped_index.tid,
4281 .start = extra_index,3632 .start = extra_index,
4282 .len = fields_len,3633 .len = extra.data.fields_len,
4283 };
4284 extra_index += fields_len;
4285 const names_map: OptionalMapIndex, const names = n: {
4286 const names_map: OptionalMapIndex = @enumFromInt(extra_list.view().items(.@"0")[extra_index]);
4287 extra_index += 1;
4288 const names: NullTerminatedString.Slice = .{
4289 .tid = unwrapped_index.tid,
4290 .start = extra_index,
4291 .len = fields_len,
4292 };
4293 extra_index += fields_len;
4294 break :n .{ names_map, names };
4295 };3634 };
4296 const inits: Index.Slice = if (flags.any_default_inits) i: {3635 extra_index += field_types.len;
4297 const inits: Index.Slice = .{3636 const field_defaults: Index.Slice = if (extra.data.flags.any_field_defaults) .{
4298 .tid = unwrapped_index.tid,
4299 .start = extra_index,
4300 .len = fields_len,
4301 };
4302 extra_index += fields_len;
4303 break :i inits;
4304 } else Index.Slice.empty;
4305 const aligns: Alignment.Slice = if (flags.any_aligned_fields) a: {
4306 const a: Alignment.Slice = .{
4307 .tid = unwrapped_index.tid,
4308 .start = extra_index,
4309 .len = fields_len,
4310 };
4311 extra_index += std.math.divCeil(u32, fields_len, 4) catch unreachable;
4312 break :a a;
4313 } else Alignment.Slice.empty;
4314 const comptime_bits: LoadedStructType.ComptimeBits = if (flags.any_comptime_fields) c: {
4315 const len = std.math.divCeil(u32, fields_len, 32) catch unreachable;
4316 const c: LoadedStructType.ComptimeBits = .{
4317 .tid = unwrapped_index.tid,
4318 .start = extra_index,
4319 .len = len,
4320 };
4321 extra_index += len;
4322 break :c c;
4323 } else LoadedStructType.ComptimeBits.empty;
4324 const runtime_order: LoadedStructType.RuntimeOrder.Slice = if (!flags.is_extern) ro: {
4325 const ro: LoadedStructType.RuntimeOrder.Slice = .{
4326 .tid = unwrapped_index.tid,
4327 .start = extra_index,
4328 .len = fields_len,
4329 };
4330 extra_index += fields_len;
4331 break :ro ro;
4332 } else LoadedStructType.RuntimeOrder.Slice.empty;
4333 const offsets: LoadedStructType.Offsets = o: {
4334 const o: LoadedStructType.Offsets = .{
4335 .tid = unwrapped_index.tid,
4336 .start = extra_index,
4337 .len = fields_len,
4338 };
4339 extra_index += fields_len;
4340 break :o o;
4341 };
4342 return .{
4343 .tid = unwrapped_index.tid,3637 .tid = unwrapped_index.tid,
4344 .extra_index = item.data,3638 .start = extra_index,
4345 .name = name,3639 .len = extra.data.fields_len,
4346 .name_nav = name_nav,3640 } else .empty;
4347 .namespace = namespace,3641 extra_index += field_defaults.len;
4348 .zir_index = zir_index,3642 const field_aligns: Alignment.Slice = if (extra.data.flags.any_field_aligns) .{
4349 .layout = if (flags.is_extern) .@"extern" else .auto,
4350 .field_names = names,
4351 .field_types = field_types,
4352 .field_inits = inits,
4353 .field_aligns = aligns,
4354 .runtime_order = runtime_order,
4355 .comptime_bits = comptime_bits,
4356 .offsets = offsets,
4357 .names_map = names_map,
4358 .captures = captures,
4359 };
4360 },
4361 .type_struct_packed, .type_struct_packed_inits => {
4362 const name: NullTerminatedString = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?]);
4363 const name_nav: Nav.Index.Optional = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?]);
4364 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]);
4365 const fields_len = extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "fields_len").?];
4366 const namespace: NamespaceIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?]);
4367 const names_map: MapIndex = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "names_map").?]);
4368 const flags: Tag.TypeStructPacked.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?], .unordered));
4369 var extra_index = item.data + @as(u32, @typeInfo(Tag.TypeStructPacked).@"struct".fields.len);
4370 const has_inits = item.tag == .type_struct_packed_inits;
4371 const captures_len = if (flags.any_captures) c: {
4372 const len = extra_list.view().items(.@"0")[extra_index];
4373 extra_index += 1;
4374 break :c len;
4375 } else 0;
4376 const captures: CaptureValue.Slice = .{
4377 .tid = unwrapped_index.tid,3643 .tid = unwrapped_index.tid,
4378 .start = extra_index,3644 .start = extra_index,
4379 .len = captures_len,3645 .len = extra.data.fields_len,
4380 };3646 } else .empty;
4381 extra_index += captures_len;3647 extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable;
4382 if (flags.is_reified) {3648 const field_is_comptime_bits: LoadedStructType.ComptimeBits = if (extra.data.flags.any_comptime_fields) .{
4383 extra_index += 2; // PackedU64
4384 }
4385 const field_types: Index.Slice = .{
4386 .tid = unwrapped_index.tid,3649 .tid = unwrapped_index.tid,
4387 .start = extra_index,3650 .start = extra_index,
4388 .len = fields_len,3651 .len = std.math.divCeil(u32, extra.data.fields_len, 32) catch unreachable,
4389 };3652 } else .empty;
4390 extra_index += fields_len;3653 extra_index += field_is_comptime_bits.len;
4391 const field_names: NullTerminatedString.Slice = .{3654 const field_runtime_order: LoadedStructType.RuntimeOrder.Slice = if (extra.data.flags.layout == .auto) .{
4392 .tid = unwrapped_index.tid,3655 .tid = unwrapped_index.tid,
4393 .start = extra_index,3656 .start = extra_index,
4394 .len = fields_len,3657 .len = extra.data.fields_len,
3658 } else .empty;
3659 extra_index += field_runtime_order.len;
3660 const field_offsets: LoadedStructType.Offsets = .{
3661 .tid = unwrapped_index.tid,
3662 .start = extra_index,
3663 .len = extra.data.fields_len,
4395 };3664 };
4396 extra_index += fields_len;3665 extra_index += field_offsets.len;
4397 const field_inits: Index.Slice = if (has_inits) inits: {3666
4398 const i: Index.Slice = .{
4399 .tid = unwrapped_index.tid,
4400 .start = extra_index,
4401 .len = fields_len,
4402 };
4403 extra_index += fields_len;
4404 break :inits i;
4405 } else Index.Slice.empty;
4406 return .{3667 return .{
4407 .tid = unwrapped_index.tid,3668 .zir_index = extra.data.zir_index,
4408 .extra_index = item.data,3669 .captures = captures,
4409 .name = name,3670 .name = extra.data.name,
4410 .name_nav = name_nav,3671 .name_nav = extra.data.name_nav,
4411 .namespace = namespace,3672 .namespace = extra.data.namespace,
4412 .zir_index = zir_index,3673 .layout = switch (extra.data.flags.layout) {
4413 .layout = .@"packed",3674 .auto => .auto,
3675 .@"extern" => .@"extern",
3676 },
3677 .packed_backing_mode = undefined,
3678 .packed_backing_int_type = undefined,
3679 .field_name_map = extra.data.field_name_map,
4414 .field_names = field_names,3680 .field_names = field_names,
4415 .field_types = field_types,3681 .field_types = field_types,
4416 .field_inits = field_inits,3682 .field_defaults = field_defaults,
4417 .field_aligns = Alignment.Slice.empty,3683 .field_aligns = field_aligns,
4418 .runtime_order = LoadedStructType.RuntimeOrder.Slice.empty,3684 .field_is_comptime_bits = field_is_comptime_bits,
4419 .comptime_bits = LoadedStructType.ComptimeBits.empty,3685 .field_runtime_order = field_runtime_order,
4420 .offsets = LoadedStructType.Offsets.empty,3686 .field_offsets = field_offsets,
4421 .names_map = names_map.toOptional(),3687 .has_no_possible_value = extra.data.flags.has_no_possible_value,
4422 .captures = captures,3688 .has_one_possible_value = extra.data.flags.has_one_possible_value,
3689 .comptime_only = extra.data.flags.comptime_only,
3690 .size = extra.data.size,
3691 .alignment = extra.data.flags.alignment,
4423 };3692 };
4424 },3693 },
4425 else => unreachable,3694 else => unreachable,
4426 }
4427}
4428
4429pub const LoadedEnumType = struct {
4430 // TODO: the non-fqn will be needed by the new dwarf structure
4431 /// The name of this enum type.
4432 name: NullTerminatedString,
4433 /// Represents the declarations inside this enum.
4434 namespace: NamespaceIndex,
4435 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.
4436 /// Otherwise, this is `.none`.
4437 name_nav: Nav.Index.Optional,
4438 /// An integer type which is used for the numerical value of the enum.
4439 /// This field is present regardless of whether the enum has an
4440 /// explicitly provided tag type or auto-numbered.
4441 tag_ty: Index,
4442 /// Set of field names in declaration order.
4443 names: NullTerminatedString.Slice,
4444 /// Maps integer tag value to field index.
4445 /// Entries are in declaration order, same as `fields`.
4446 /// If this is empty, it means the enum tags are auto-numbered.
4447 values: Index.Slice,
4448 tag_mode: TagMode,
4449 names_map: MapIndex,
4450 /// This is guaranteed to not be `.none` if explicit values are provided.
4451 values_map: OptionalMapIndex,
4452 /// This is `none` only if this is a generated tag type.
4453 zir_index: TrackedInst.Index.Optional,
4454 captures: CaptureValue.Slice,
4455
4456 pub const TagMode = enum {
4457 /// The integer tag type was auto-numbered by zig.
4458 auto,
4459 /// The integer tag type was provided by the enum declaration, and the enum
4460 /// is exhaustive.
4461 explicit,
4462 /// The integer tag type was provided by the enum declaration, and the enum
4463 /// is non-exhaustive.
4464 nonexhaustive,
4465 };3695 };
3696 const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, item.data);
3697 var extra_index = extra.end;
3698 const captures: CaptureValue.Slice = switch (extra.data.captures_len) {
3699 .reified => captures: {
3700 extra_index += 2; // type_hash: PackedU64
3701 break :captures .empty;
3702 },
3703 _ => .{
3704 .tid = unwrapped_index.tid,
3705 .start = extra_index,
3706 .len = @intFromEnum(extra.data.captures_len),
3707 },
3708 };
3709 extra_index += captures.len;
3710 const field_names: NullTerminatedString.Slice = .{
3711 .tid = unwrapped_index.tid,
3712 .start = extra_index,
3713 .len = extra.data.fields_len,
3714 };
3715 extra_index += field_names.len;
3716 const field_types: Index.Slice = .{
3717 .tid = unwrapped_index.tid,
3718 .start = extra_index,
3719 .len = extra.data.fields_len,
3720 };
3721 extra_index += field_types.len;
3722 const field_defaults: Index.Slice = if (any_defaults) .{
3723 .tid = unwrapped_index.tid,
3724 .start = extra_index,
3725 .len = extra.data.fields_len,
3726 } else .empty;
3727 extra_index += field_defaults.len;
3728 return .{
3729 .zir_index = extra.data.zir_index,
3730 .captures = captures,
3731 .name = extra.data.name,
3732 .name_nav = extra.data.name_nav,
3733 .namespace = extra.data.namespace,
3734 .layout = .@"packed",
3735 .packed_backing_mode = backing_mode,
3736 .packed_backing_int_type = extra.data.backing_int_type,
3737 .field_name_map = extra.data.field_name_map,
3738 .field_names = field_names,
3739 .field_types = field_types,
3740 .field_defaults = field_defaults,
3741 .field_aligns = .empty,
3742 .field_is_comptime_bits = .empty,
3743 .field_runtime_order = .empty,
3744 .field_offsets = .empty,
3745 .has_no_possible_value = undefined,
3746 .has_one_possible_value = undefined,
3747 .comptime_only = undefined,
3748 .size = undefined,
3749 .alignment = undefined,
3750 };
3751}
44663752
4467 /// Look up field index based on field name.3753pub fn loadUnionType(ip: *const InternPool, index: Index) LoadedUnionType {
4468 pub fn nameIndex(self: LoadedEnumType, ip: *const InternPool, name: NullTerminatedString) ?u32 {
4469 const map = self.names_map.get(ip);
4470 const adapter: NullTerminatedString.Adapter = .{ .strings = self.names.get(ip) };
4471 const field_index = map.getIndexAdapted(name, adapter) orelse return null;
4472 return @intCast(field_index);
4473 }
4474
4475 /// Look up field index based on tag value.
4476 /// Asserts that `values_map` is not `none`.
4477 /// This function returns `null` when `tag_val` does not have the
4478 /// integer tag type of the enum.
4479 pub fn tagValueIndex(self: LoadedEnumType, ip: *const InternPool, tag_val: Index) ?u32 {
4480 assert(tag_val != .none);
4481 // TODO: we should probably decide a single interface for this function, but currently
4482 // it's being called with both tag values and underlying ints. Fix this!
4483 const int_tag_val = switch (ip.indexToKey(tag_val)) {
4484 .enum_tag => |enum_tag| enum_tag.int,
4485 .int => tag_val,
4486 else => unreachable,
4487 };
4488 if (self.values_map.unwrap()) |values_map| {
4489 const map = values_map.get(ip);
4490 const adapter: Index.Adapter = .{ .indexes = self.values.get(ip) };
4491 const field_index = map.getIndexAdapted(int_tag_val, adapter) orelse return null;
4492 return @intCast(field_index);
4493 }
4494 // Auto-numbered enum. Convert `int_tag_val` to field index.
4495 const field_index = switch (ip.indexToKey(int_tag_val).int.storage) {
4496 inline .u64, .i64 => |x| std.math.cast(u32, x) orelse return null,
4497 .big_int => |x| x.toInt(u32) catch return null,
4498 .lazy_align, .lazy_size => unreachable,
4499 };
4500 return if (field_index < self.names.len) field_index else null;
4501 }
4502};
4503
4504pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
4505 const unwrapped_index = index.unwrap(ip);3754 const unwrapped_index = index.unwrap(ip);
4506 const extra_list = unwrapped_index.getExtra(ip);3755 const extra_list = unwrapped_index.getExtra(ip);
3756 const extra_items = extra_list.view().items(.@"0");
4507 const item = unwrapped_index.getItem(ip);3757 const item = unwrapped_index.getItem(ip);
4508 const tag_mode: LoadedEnumType.TagMode = switch (item.tag) {3758 // Exiting this `switch` means this is a `packed union`.
4509 .type_enum_auto => {3759 const backing_mode: PackedBackingMode = switch (item.tag) {
4510 const extra = extraDataTrail(extra_list, EnumAuto, item.data);3760 .type_union_packed_auto => .auto,
4511 var extra_index: u32 = @intCast(extra.end);3761 .type_union_packed_explicit => .explicit,
4512 if (extra.data.zir_index == .none) {3762 .type_union => {
4513 extra_index += 1; // owner_union3763 const extra = extraDataTrail(extra_list, Tag.TypeUnion, item.data);
4514 }3764 var extra_index = extra.end;
4515 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {3765 const captures: CaptureValue.Slice = switch (extra.data.flags.any_captures) {
4516 extra_index += 2; // type_hash: PackedU643766 .reified => captures: {
4517 break :c 0;3767 extra_index += 2; // type_hash: PackedU64
4518 } else extra.data.captures_len;3768 break :captures .empty;
3769 },
3770 .false => .empty,
3771 .true => captures: {
3772 const len = extra_items[extra_index];
3773 extra_index += 1;
3774 break :captures .{
3775 .tid = unwrapped_index.tid,
3776 .start = extra_index,
3777 .len = len,
3778 };
3779 },
3780 };
3781 extra_index += captures.len;
3782 const field_types: Index.Slice = .{
3783 .tid = unwrapped_index.tid,
3784 .start = extra_index,
3785 .len = extra.data.fields_len,
3786 };
3787 extra_index += field_types.len;
3788 const field_aligns: Alignment.Slice = if (extra.data.flags.any_field_aligns) .{
3789 .tid = unwrapped_index.tid,
3790 .start = extra_index,
3791 .len = extra.data.fields_len,
3792 } else .empty;
3793 extra_index += std.math.divCeil(u32, field_aligns.len, 4) catch unreachable;
3794
4519 return .{3795 return .{
3796 .zir_index = extra.data.zir_index,
3797 .captures = captures,
4520 .name = extra.data.name,3798 .name = extra.data.name,
4521 .name_nav = extra.data.name_nav,3799 .name_nav = extra.data.name_nav,
4522 .namespace = extra.data.namespace,3800 .namespace = extra.data.namespace,
4523 .tag_ty = extra.data.int_tag_type,3801 .layout = switch (extra.data.flags.layout) {
4524 .names = .{3802 .auto => .auto,
4525 .tid = unwrapped_index.tid,3803 .@"extern" => .@"extern",
4526 .start = extra_index + captures_len,
4527 .len = extra.data.fields_len,
4528 },
4529 .values = Index.Slice.empty,
4530 .tag_mode = .auto,
4531 .names_map = extra.data.names_map,
4532 .values_map = .none,
4533 .zir_index = extra.data.zir_index,
4534 .captures = .{
4535 .tid = unwrapped_index.tid,
4536 .start = extra_index,
4537 .len = captures_len,
4538 },3804 },
3805 .runtime_tag = extra.data.flags.runtime_tag,
3806 .enum_tag_type = extra.data.enum_tag_type,
3807 .packed_backing_mode = undefined,
3808 .packed_backing_int_type = undefined,
3809 .field_types = field_types,
3810 .field_aligns = field_aligns,
3811 .has_no_possible_value = extra.data.flags.has_no_possible_value,
3812 .has_one_possible_value = extra.data.flags.has_one_possible_value,
3813 .comptime_only = extra.data.flags.comptime_only,
3814 .size = extra.data.size,
3815 .padding = extra.data.padding,
3816 .alignment = extra.data.flags.alignment,
4539 };3817 };
4540 },3818 },
4541 .type_enum_explicit => .explicit,
4542 .type_enum_nonexhaustive => .nonexhaustive,
4543 else => unreachable,3819 else => unreachable,
4544 };3820 };
4545 const extra = extraDataTrail(extra_list, EnumExplicit, item.data);3821 const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, item.data);
4546 var extra_index: u32 = @intCast(extra.end);3822 var extra_index = extra.end;
4547 if (extra.data.zir_index == .none) {3823 const captures: CaptureValue.Slice = switch (extra.data.captures_len) {
4548 extra_index += 1; // owner_union3824 .reified => captures: {
4549 }3825 extra_index += 2; // type_hash: PackedU64
4550 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32)) c: {3826 break :captures .empty;
4551 extra_index += 2; // type_hash: PackedU64
4552 break :c 0;
4553 } else extra.data.captures_len;
4554 return .{
4555 .name = extra.data.name,
4556 .name_nav = extra.data.name_nav,
4557 .namespace = extra.data.namespace,
4558 .tag_ty = extra.data.int_tag_type,
4559 .names = .{
4560 .tid = unwrapped_index.tid,
4561 .start = extra_index + captures_len,
4562 .len = extra.data.fields_len,
4563 },
4564 .values = .{
4565 .tid = unwrapped_index.tid,
4566 .start = extra_index + captures_len + extra.data.fields_len,
4567 .len = if (extra.data.values_map != .none) extra.data.fields_len else 0,
4568 },3827 },
4569 .tag_mode = tag_mode,3828 _ => .{
4570 .names_map = extra.data.names_map,
4571 .values_map = extra.data.values_map,
4572 .zir_index = extra.data.zir_index,
4573 .captures = .{
4574 .tid = unwrapped_index.tid,3829 .tid = unwrapped_index.tid,
4575 .start = extra_index,3830 .start = extra_index,
4576 .len = captures_len,3831 .len = @intFromEnum(extra.data.captures_len),
4577 },3832 },
4578 };3833 };
4579}3834 extra_index += captures.len;
45803835 const field_types: Index.Slice = .{
4581/// Note that this type doubles as the payload for `Tag.type_opaque`.3836 .tid = unwrapped_index.tid,
4582pub const LoadedOpaqueType = struct {3837 .start = extra_index,
4583 /// Contains the declarations inside this opaque.3838 .len = extra.data.fields_len,
4584 namespace: NamespaceIndex,3839 };
4585 // TODO: the non-fqn will be needed by the new dwarf structure3840 extra_index += field_types.len;
4586 /// The name of this opaque type.3841 return .{
4587 name: NullTerminatedString,3842 .zir_index = extra.data.zir_index,
4588 /// If this is a declared type with the `.parent` name strategy, this is the `Nav` it was named after.3843 .captures = captures,
4589 /// Otherwise, this is `.none`.3844 .name = extra.data.name,
4590 name_nav: Nav.Index.Optional,3845 .name_nav = extra.data.name_nav,
4591 /// Index of the `opaque_decl` or `reify` instruction.3846 .namespace = extra.data.namespace,
4592 zir_index: TrackedInst.Index,3847 .layout = .@"packed",
4593 captures: CaptureValue.Slice,3848 .runtime_tag = .none,
4594};3849 .enum_tag_type = extra.data.enum_tag_type,
3850 .packed_backing_mode = backing_mode,
3851 .packed_backing_int_type = extra.data.backing_int_type,
3852 .field_types = field_types,
3853 .field_aligns = .empty,
3854 .has_no_possible_value = undefined,
3855 .has_one_possible_value = undefined,
3856 .comptime_only = undefined,
3857 .size = undefined,
3858 .padding = undefined,
3859 .alignment = undefined,
3860 };
3861}
45953862
4596pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {3863pub fn loadEnumType(ip: *const InternPool, index: Index) LoadedEnumType {
4597 const unwrapped_index = index.unwrap(ip);3864 const unwrapped_index = index.unwrap(ip);
3865 const extra_list = unwrapped_index.getExtra(ip);
3866 const extra_items = extra_list.view().items(.@"0");
4598 const item = unwrapped_index.getItem(ip);3867 const item = unwrapped_index.getItem(ip);
4599 assert(item.tag == .type_opaque);3868 const explicit_int_tag: bool, const nonexhaustive: bool = switch (item.tag) {
4600 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, item.data);3869 .type_enum_auto => .{ false, false },
4601 const captures_len = if (extra.data.captures_len == std.math.maxInt(u32))3870 .type_enum_explicit => .{ true, false },
4602 03871 .type_enum_nonexhaustive => .{ true, true },
4603 else3872 else => unreachable,
4604 extra.data.captures_len;3873 };
3874 const extra = extraDataTrail(extra_list, Tag.TypeEnum, item.data);
3875 var extra_index: u32 = @intCast(extra.end);
3876 const zir_index: TrackedInst.Index.Optional, const captures: CaptureValue.Slice, const owner_union: Index = switch (extra.data.captures_len) {
3877 .reified => info: {
3878 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]);
3879 extra_index += 1;
3880 extra_index += 2; // type_hash: PackedU64
3881 break :info .{ zir_index.toOptional(), .empty, .none };
3882 },
3883 .generated_union_tag => info: {
3884 const owner_union: Index = @enumFromInt(extra_items[extra_index]);
3885 extra_index += 1;
3886 break :info .{ .none, .empty, owner_union };
3887 },
3888 _ => info: {
3889 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[extra_index]);
3890 extra_index += 1;
3891 const captures: CaptureValue.Slice = .{
3892 .tid = unwrapped_index.tid,
3893 .start = extra_index,
3894 .len = @intFromEnum(extra.data.captures_len),
3895 };
3896 extra_index += captures.len;
3897 break :info .{ zir_index.toOptional(), captures, .none };
3898 },
3899 };
3900 const field_value_map: OptionalMapIndex = if (explicit_int_tag) m: {
3901 const map: MapIndex = @enumFromInt(extra_items[extra_index]);
3902 extra_index += 1;
3903 break :m map.toOptional();
3904 } else .none;
3905 const field_names: NullTerminatedString.Slice = .{
3906 .tid = unwrapped_index.tid,
3907 .start = extra_index,
3908 .len = extra.data.fields_len,
3909 };
3910 extra_index += field_names.len;
3911 const field_values: Index.Slice = if (explicit_int_tag) .{
3912 .tid = unwrapped_index.tid,
3913 .start = extra_index,
3914 .len = extra.data.fields_len,
3915 } else .empty;
3916 extra_index += field_values.len;
4605 return .{3917 return .{
3918 .zir_index = zir_index,
3919 .captures = captures,
3920 .owner_union = owner_union,
4606 .name = extra.data.name,3921 .name = extra.data.name,
4607 .name_nav = extra.data.name_nav,3922 .name_nav = extra.data.name_nav,
4608 .namespace = extra.data.namespace,3923 .namespace = extra.data.namespace,
3924 .int_tag_type = extra.data.int_tag_type,
3925 .int_tag_is_explicit = explicit_int_tag,
3926 .nonexhaustive = nonexhaustive,
3927 .field_name_map = extra.data.field_name_map,
3928 .field_value_map = field_value_map,
3929 .field_names = field_names,
3930 .field_values = field_values,
3931 };
3932}
3933
3934pub fn loadOpaqueType(ip: *const InternPool, index: Index) LoadedOpaqueType {
3935 const unwrapped_index = index.unwrap(ip);
3936 const item = unwrapped_index.getItem(ip);
3937 assert(item.tag == .type_opaque);
3938 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, item.data);
3939 return .{
4609 .zir_index = extra.data.zir_index,3940 .zir_index = extra.data.zir_index,
4610 .captures = .{3941 .captures = .{
4611 .tid = unwrapped_index.tid,3942 .tid = unwrapped_index.tid,
4612 .start = extra.end,3943 .start = extra.end,
4613 .len = captures_len,3944 .len = extra.data.captures_len,
4614 },3945 },
3946 .name = extra.data.name,
3947 .name_nav = extra.data.name_nav,
3948 .namespace = extra.data.namespace,
4615 };3949 };
4616}3950}
46173951
...@@ -4819,7 +4153,7 @@ pub const Index = enum(u32) {...@@ -4819,7 +4153,7 @@ pub const Index = enum(u32) {
4819 };4153 };
48204154
4821 /// Used for a map of `Index` values to the index within a list of `Index` values.4155 /// Used for a map of `Index` values to the index within a list of `Index` values.
4822 const Adapter = struct {4156 pub const Adapter = struct {
4823 indexes: []const Index,4157 indexes: []const Index,
48244158
4825 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {4159 pub fn eql(ctx: @This(), a: Index, b_void: void, b_map_index: usize) bool {
...@@ -4891,26 +4225,6 @@ pub const Index = enum(u32) {...@@ -4891,26 +4225,6 @@ pub const Index = enum(u32) {
4891 /// Tag to encoding mapping to facilitate fancy debug printing for this type.4225 /// Tag to encoding mapping to facilitate fancy debug printing for this type.
4892 fn dbHelper(self: *Index, tag_to_encoding_map: *struct {4226 fn dbHelper(self: *Index, tag_to_encoding_map: *struct {
4893 const DataIsIndex = struct { data: Index };4227 const DataIsIndex = struct { data: Index };
4894 const DataIsExtraIndexOfEnumExplicit = struct {
4895 const @"data.fields_len" = opaque {};
4896 data: *EnumExplicit,
4897 @"trailing.names.len": *@"data.fields_len",
4898 @"trailing.values.len": *@"data.fields_len",
4899 trailing: struct {
4900 names: []NullTerminatedString,
4901 values: []Index,
4902 },
4903 };
4904 const DataIsExtraIndexOfTypeTuple = struct {
4905 const @"data.fields_len" = opaque {};
4906 data: *TypeTuple,
4907 @"trailing.types.len": *@"data.fields_len",
4908 @"trailing.values.len": *@"data.fields_len",
4909 trailing: struct {
4910 types: []Index,
4911 values: []Index,
4912 },
4913 };
49144228
4915 removed: void,4229 removed: void,
4916 type_int_signed: struct { data: u32 },4230 type_int_signed: struct { data: u32 },
...@@ -4931,21 +4245,7 @@ pub const Index = enum(u32) {...@@ -4931,21 +4245,7 @@ pub const Index = enum(u32) {
4931 trailing: struct { names: []NullTerminatedString },4245 trailing: struct { names: []NullTerminatedString },
4932 },4246 },
4933 type_inferred_error_set: DataIsIndex,4247 type_inferred_error_set: DataIsIndex,
4934 type_enum_auto: struct {
4935 const @"data.fields_len" = opaque {};
4936 data: *EnumAuto,
4937 @"trailing.names.len": *@"data.fields_len",
4938 trailing: struct { names: []NullTerminatedString },
4939 },
4940 type_enum_explicit: DataIsExtraIndexOfEnumExplicit,
4941 type_enum_nonexhaustive: DataIsExtraIndexOfEnumExplicit,
4942 simple_type: void,4248 simple_type: void,
4943 type_opaque: struct { data: *Tag.TypeOpaque },
4944 type_struct: struct { data: *Tag.TypeStruct },
4945 type_struct_packed: struct { data: *Tag.TypeStructPacked },
4946 type_struct_packed_inits: struct { data: *Tag.TypeStructPacked },
4947 type_tuple: DataIsExtraIndexOfTypeTuple,
4948 type_union: struct { data: *Tag.TypeUnion },
4949 type_function: struct {4249 type_function: struct {
4950 const @"data.flags.has_comptime_bits" = opaque {};4250 const @"data.flags.has_comptime_bits" = opaque {};
4951 const @"data.flags.has_noalias_bits" = opaque {};4251 const @"data.flags.has_noalias_bits" = opaque {};
...@@ -4956,6 +4256,29 @@ pub const Index = enum(u32) {...@@ -4956,6 +4256,29 @@ pub const Index = enum(u32) {
4956 @"trailing.param_types.len": *@"data.params_len",4256 @"trailing.param_types.len": *@"data.params_len",
4957 trailing: struct { comptime_bits: []u32, noalias_bits: []u32, param_types: []Index },4257 trailing: struct { comptime_bits: []u32, noalias_bits: []u32, param_types: []Index },
4958 },4258 },
4259 type_tuple: struct {
4260 const @"data.fields_len" = opaque {};
4261 data: *TypeTuple,
4262 @"trailing.types.len": *@"data.fields_len",
4263 @"trailing.values.len": *@"data.fields_len",
4264 trailing: struct {
4265 types: []Index,
4266 values: []Index,
4267 },
4268 },
4269
4270 type_struct: struct { data: *Tag.TypeStruct },
4271 type_struct_packed_auto: struct { data: *Tag.TypeStructPacked },
4272 type_struct_packed_explicit: struct { data: *Tag.TypeStructPacked },
4273 type_struct_packed_auto_defaults: struct { data: *Tag.TypeStructPacked },
4274 type_struct_packed_explicit_defaults: struct { data: *Tag.TypeStructPacked },
4275 type_union: struct { data: *Tag.TypeUnion },
4276 type_union_packed_auto: struct { data: *Tag.TypeUnionPacked },
4277 type_union_packed_explicit: struct { data: *Tag.TypeUnionPacked },
4278 type_enum_auto: struct { data: *Tag.TypeEnum },
4279 type_enum_explicit: struct { data: *Tag.TypeEnum },
4280 type_enum_nonexhaustive: struct { data: *Tag.TypeEnum },
4281 type_opaque: struct { data: *Tag.TypeOpaque },
49594282
4960 undef: DataIsIndex,4283 undef: DataIsIndex,
4961 simple_value: void,4284 simple_value: void,
...@@ -4982,8 +4305,6 @@ pub const Index = enum(u32) {...@@ -4982,8 +4305,6 @@ pub const Index = enum(u32) {
4982 int_small: struct { data: *IntSmall },4305 int_small: struct { data: *IntSmall },
4983 int_positive: struct { data: u32 },4306 int_positive: struct { data: u32 },
4984 int_negative: struct { data: u32 },4307 int_negative: struct { data: u32 },
4985 int_lazy_align: struct { data: *IntLazy },
4986 int_lazy_size: struct { data: *IntLazy },
4987 error_set_error: struct { data: *Key.Error },4308 error_set_error: struct { data: *Key.Error },
4988 error_union_error: struct { data: *Key.Error },4309 error_union_error: struct { data: *Key.Error },
4989 error_union_payload: struct { data: *Tag.TypeValue },4310 error_union_payload: struct { data: *Tag.TypeValue },
...@@ -5485,6 +4806,8 @@ pub const Tag = enum(u8) {...@@ -5485,6 +4806,8 @@ pub const Tag = enum(u8) {
5485 /// assert not this tag. `data` is unused.4806 /// assert not this tag. `data` is unused.
5486 removed,4807 removed,
54874808
4809 /// A type that can be represented with only an enum tag.
4810 simple_type,
5488 /// An integer type.4811 /// An integer type.
5489 /// data is number of bits4812 /// data is number of bits
5490 type_int_signed,4813 type_int_signed,
...@@ -5524,41 +4847,68 @@ pub const Tag = enum(u8) {...@@ -5524,41 +4847,68 @@ pub const Tag = enum(u8) {
5524 /// The inferred error set type of a function.4847 /// The inferred error set type of a function.
5525 /// data is `Index` of a `func_decl` or `func_instance`.4848 /// data is `Index` of a `func_decl` or `func_instance`.
5526 type_inferred_error_set,4849 type_inferred_error_set,
5527 /// An enum type with auto-numbered tag values.4850 /// A function body type.
5528 /// The enum is exhaustive.4851 /// `data` is extra index to `TypeFunction`.
5529 /// data is payload index to `EnumAuto`.4852 type_function,
5530 type_enum_auto,4853 /// A `TupleType`.
5531 /// An enum type with an explicitly provided integer tag type.4854 /// data is extra index of `TypeTuple`.
5532 /// The enum is exhaustive.4855 type_tuple,
5533 /// data is payload index to `EnumExplicit`.4856
5534 type_enum_explicit,
5535 /// An enum type with an explicitly provided integer tag type.
5536 /// The enum is non-exhaustive.
5537 /// data is payload index to `EnumExplicit`.
5538 type_enum_nonexhaustive,
5539 /// A type that can be represented with only an enum tag.
5540 simple_type,
5541 /// An opaque type.
5542 /// data is index of Tag.TypeOpaque in extra.
5543 type_opaque,
5544 /// A non-packed struct type.4857 /// A non-packed struct type.
5545 /// data is 0 or extra index of `TypeStruct`.4858 /// data is extra index of `TypeStruct`.
5546 type_struct,4859 type_struct,
5547 /// A packed struct, no fields have any init values.4860 /// `packed struct { ... }` with no default field values.
5548 /// data is extra index of `TypeStructPacked`.4861 /// data is extra index of `TypeStructPacked`.
5549 type_struct_packed,4862 type_struct_packed_auto,
5550 /// A packed struct, one or more fields have init values.4863 /// `packed struct(T) { ... }` with no default field values.
5551 /// data is extra index of `TypeStructPacked`.4864 /// data is extra index of `TypeStructPacked`.
5552 type_struct_packed_inits,4865 type_struct_packed_explicit,
5553 /// A `TupleType`.4866 /// `packed struct { ... }` with one or more default field values.
5554 /// data is extra index of `TypeTuple`.4867 /// data is extra index of `TypeStructPacked`.
5555 type_tuple,4868 type_struct_packed_auto_defaults,
5556 /// A union type.4869 /// `packed struct(T) { ... }` with one or more default field values.
5557 /// `data` is extra index of `TypeUnion`.4870 /// data is extra index of `TypeStructPacked`.
4871 type_struct_packed_explicit_defaults,
4872
4873 /// A non-packed union type.
4874 /// data is extra index of `TypeUnion`.
5558 type_union,4875 type_union,
5559 /// A function body type.4876 /// `packed union { ... }`.
5560 /// `data` is extra index to `TypeFunction`.4877 /// data is extra index of `TypeUnionPacked`.
5561 type_function,4878 type_union_packed_auto,
4879 /// `packed union(T) { ... }`.
4880 /// data is extra index of `TypeUnionPacked`.
4881 type_union_packed_explicit,
4882
4883 /// An exhaustive enum type *without* an explicit integer tag type. The tag type is inferred.
4884 ///
4885 /// Because the tag type is inferred, there are no explicit field values.
4886 ///
4887 /// May be the generated tag type for a `union(enum)`.
4888 ///
4889 /// data is extra index of `TypeEnum`.
4890 type_enum_auto,
4891 /// An exhaustive enum type *with* an explicit integer tag type.
4892 ///
4893 /// May have explicit field values.
4894 ///
4895 /// May be the generated tag type for a `union(enum(T))`.
4896 ///
4897 /// data is extra index of `TypeEnum`.
4898 type_enum_explicit,
4899 /// An non-exhaustive enum type (with an explicit integer tag type, since it is required for
4900 /// non-exhaustive enums).
4901 ///
4902 /// May have explicit field values.
4903 ///
4904 /// This is *not* a union's generated tag type, because such types are always exhaustive.
4905 ///
4906 /// data is extra index of `TypeEnum`.
4907 type_enum_nonexhaustive,
4908
4909 /// An opaque type.
4910 /// data is extra index of `TypeOpaque`.
4911 type_opaque,
55624912
5563 /// Typed `undefined`.4913 /// Typed `undefined`.
5564 /// `data` is `Index` of the type.4914 /// `data` is `Index` of the type.
...@@ -5644,12 +4994,6 @@ pub const Tag = enum(u8) {...@@ -5644,12 +4994,6 @@ pub const Tag = enum(u8) {
5644 /// A negative integer value.4994 /// A negative integer value.
5645 /// data is a limbs index to `Int`.4995 /// data is a limbs index to `Int`.
5646 int_negative,4996 int_negative,
5647 /// The ABI alignment of a lazy type.
5648 /// data is extra index of `IntLazy`.
5649 int_lazy_align,
5650 /// The ABI size of a lazy type.
5651 /// data is extra index of `IntLazy`.
5652 int_lazy_size,
5653 /// An error value.4997 /// An error value.
5654 /// data is extra index of `Key.Error`.4998 /// data is extra index of `Key.Error`.
5655 error_set_error,4999 error_set_error,
...@@ -5747,24 +5091,77 @@ pub const Tag = enum(u8) {...@@ -5747,24 +5091,77 @@ pub const Tag = enum(u8) {
5747 const Union = Key.Union;5091 const Union = Key.Union;
5748 const TypePointer = Key.PtrType;5092 const TypePointer = Key.PtrType;
57495093
5750 const enum_explicit_encoding = .{5094 const struct_packed_encoding = .{
5095 .summary = .@"{.payload.name%summary#\"}",
5096 .payload = TypeStructPacked,
5097 .trailing = struct {
5098 type_hash: ?u64,
5099 captures: ?[]CaptureValue,
5100 field_names: []NullTerminatedString,
5101 field_types: []Index,
5102 },
5103 .config = .{
5104 .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
5105 .@"trailing.captures.?" = .@"payload.captures_len != .reified",
5106 .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
5107 .@"trailing.field_names.len" = .@"payload.fields_len",
5108 .@"trailing.field_types.len" = .@"payload.fields_len",
5109 },
5110 };
5111 const struct_packed_defaults_encoding = .{
5112 .summary = .@"{.payload.name%summary#\"}",
5113 .payload = TypeStructPacked,
5114 .trailing = struct {
5115 type_hash: ?u64,
5116 captures: ?[]CaptureValue,
5117 field_names: []NullTerminatedString,
5118 field_types: []Index,
5119 field_defaults: []Index,
5120 },
5121 .config = .{
5122 .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
5123 .@"trailing.captures.?" = .@"payload.captures_len != .reified",
5124 .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
5125 .@"trailing.field_names.len" = .@"payload.fields_len",
5126 .@"trailing.field_types.len" = .@"payload.fields_len",
5127 .@"trailing.field_defaults.len" = .@"payload.fields_len",
5128 },
5129 };
5130 const union_packed_encoding = .{
5751 .summary = .@"{.payload.name%summary#\"}",5131 .summary = .@"{.payload.name%summary#\"}",
5752 .payload = EnumExplicit,5132 .payload = TypeUnionPacked,
5753 .trailing = struct {5133 .trailing = struct {
5754 owner_union: Index,5134 type_hash: ?u64,
5755 captures: ?[]CaptureValue,5135 captures: ?[]CaptureValue,
5136 field_types: []Index,
5137 },
5138 .config = .{
5139 .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
5140 .@"trailing.captures.?" = .@"payload.captures_len != .reified",
5141 .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
5142 .@"trailing.field_types.len" = .@"payload.fields_len",
5143 },
5144 };
5145 const enum_explicit_encoding = .{
5146 .summary = .@"{.payload.name%summary#\"}",
5147 .payload = TypeEnum,
5148 .trailing = struct {
5149 owner_union: ?Index,
5150 zir_index: ?TrackedInst.Index,
5756 type_hash: ?u64,5151 type_hash: ?u64,
5152 captures: ?[]CaptureValue,
5153 field_value_map: MapIndex,
5757 field_names: []NullTerminatedString,5154 field_names: []NullTerminatedString,
5758 tag_values: []Index,5155 field_values: []Index,
5759 },5156 },
5760 .config = .{5157 .config = .{
5761 .@"trailing.owner_union.?" = .@"payload.zir_index == .none",5158 .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag",
5762 .@"trailing.cau.?" = .@"payload.zir_index != .none",5159 .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag",
5763 .@"trailing.captures.?" = .@"payload.captures_len < 0xffffffff",5160 .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
5764 .@"trailing.captures.?.len" = .@"payload.captures_len",5161 .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag",
5765 .@"trailing.type_hash.?" = .@"payload.captures_len == 0xffffffff",5162 .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
5766 .@"trailing.field_names.len" = .@"payload.fields_len",5163 .@"trailing.field_names.len" = .@"payload.fields_len",
5767 .@"trailing.tag_values.len" = .@"payload.fields_len",5164 .@"trailing.field_values.len" = .@"payload.fields_len",
5768 },5165 },
5769 };5166 };
5770 const encodings = .{5167 const encodings = .{
...@@ -5792,153 +5189,121 @@ pub const Tag = enum(u8) {...@@ -5792,153 +5189,121 @@ pub const Tag = enum(u8) {
5792 .summary = .@"@typeInfo(@typeInfo(@TypeOf({.data%summary})).@\"fn\".return_type.?).error_union.error_set",5189 .summary = .@"@typeInfo(@typeInfo(@TypeOf({.data%summary})).@\"fn\".return_type.?).error_union.error_set",
5793 .data = Index,5190 .data = Index,
5794 },5191 },
5795 .type_enum_auto = .{5192 .simple_type = .{ .summary = .@"{.index%value#.}", .index = SimpleType },
5796 .summary = .@"{.payload.name%summary#\"}",5193 .type_tuple = .{
5797 .payload = EnumAuto,5194 .summary = .@"struct {...}",
5195 .payload = TypeTuple,
5798 .trailing = struct {5196 .trailing = struct {
5799 owner_union: ?Index,5197 field_types: []Index,
5800 captures: ?[]CaptureValue,5198 field_values: []Index,
5801 type_hash: ?u64,
5802 field_names: []NullTerminatedString,
5803 },5199 },
5804 .config = .{5200 .config = .{
5805 .@"trailing.owner_union.?" = .@"payload.zir_index == .none",5201 .@"trailing.field_types.len" = .@"payload.fields_len",
5806 .@"trailing.cau.?" = .@"payload.zir_index != .none",5202 .@"trailing.field_values.len" = .@"payload.fields_len",
5807 .@"trailing.captures.?" = .@"payload.captures_len < 0xffffffff",
5808 .@"trailing.captures.?.len" = .@"payload.captures_len",
5809 .@"trailing.type_hash.?" = .@"payload.captures_len == 0xffffffff",
5810 .@"trailing.field_names.len" = .@"payload.fields_len",
5811 },5203 },
5812 },5204 },
5813 .type_enum_explicit = enum_explicit_encoding,5205 .type_function = .{
5814 .type_enum_nonexhaustive = enum_explicit_encoding,5206 .summary = .@"fn (...) ... {.payload.return_type%summary}",
5815 .simple_type = .{ .summary = .@"{.index%value#.}", .index = SimpleType },5207 .payload = TypeFunction,
5816 .type_opaque = .{5208 .trailing = struct {
5817 .summary = .@"{.payload.name%summary#\"}",5209 param_comptime_bits: ?[]u32,
5818 .payload = TypeOpaque,5210 param_noalias_bits: ?[]u32,
5819 .trailing = struct { captures: []CaptureValue },5211 param_type: []Index,
5820 .config = .{ .@"trailing.captures.len" = .@"payload.captures_len" },5212 },
5213 .config = .{
5214 .@"trailing.param_comptime_bits.?" = .@"payload.flags.has_comptime_bits",
5215 .@"trailing.param_comptime_bits.?.len" = .@"(payload.params_len + 31) / 32",
5216 .@"trailing.param_noalias_bits.?" = .@"payload.flags.has_noalias_bits",
5217 .@"trailing.param_noalias_bits.?.len" = .@"(payload.params_len + 31) / 32",
5218 .@"trailing.param_type.len" = .@"payload.params_len",
5219 },
5821 },5220 },
5221
5822 .type_struct = .{5222 .type_struct = .{
5823 .summary = .@"{.payload.name%summary#\"}",5223 .summary = .@"{.payload.name%summary#\"}",
5824 .payload = TypeStruct,5224 .payload = TypeStruct,
5825 .trailing = struct {5225 .trailing = struct {
5226 type_hash: ?u64,
5826 captures_len: ?u32,5227 captures_len: ?u32,
5827 captures: ?[]CaptureValue,5228 captures: ?[]CaptureValue,
5828 type_hash: ?u64,
5829 field_types: []Index,
5830 field_names_map: OptionalMapIndex,
5831 field_names: []NullTerminatedString,5229 field_names: []NullTerminatedString,
5832 field_inits: ?[]Index,5230 field_types: []Index,
5231 field_defaults: ?[]Index,
5833 field_aligns: ?[]Alignment,5232 field_aligns: ?[]Alignment,
5834 field_is_comptime_bits: ?[]u32,5233 field_is_comptime_bits: ?[]u32,
5835 field_index: ?[]LoadedStructType.RuntimeOrder,5234 field_runtime_order: ?[]u32,
5836 field_offset: []u32,5235 field_offsets: []u32,
5837 },5236 },
5838 .config = .{5237 .config = .{
5839 .@"trailing.captures_len.?" = .@"payload.flags.any_captures",5238 .@"trailing.type_hash.?" = .@"payload.flags.any_captures == .reified",
5840 .@"trailing.captures.?" = .@"payload.flags.any_captures",5239 .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true",
5240 .@"trailing.captures.?" = .@"payload.flags.any_captures == .true",
5841 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",5241 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
5842 .@"trailing.type_hash.?" = .@"payload.flags.is_reified",
5843 .@"trailing.field_types.len" = .@"payload.fields_len",
5844 .@"trailing.field_names.len" = .@"payload.fields_len",5242 .@"trailing.field_names.len" = .@"payload.fields_len",
5845 .@"trailing.field_inits.?" = .@"payload.flags.any_default_inits",5243 .@"trailing.field_types.len" = .@"payload.fields_len",
5846 .@"trailing.field_inits.?.len" = .@"payload.fields_len",5244 .@"trailing.field_defaults.?" = .@"payload.flags.any_field_defaults",
5847 .@"trailing.field_aligns.?" = .@"payload.flags.any_aligned_fields",5245 .@"trailing.field_defaults.?.len" = .@"payload.fields_len",
5246 .@"trailing.field_aligns.?" = .@"payload.flags.any_field_aligns",
5848 .@"trailing.field_aligns.?.len" = .@"payload.fields_len",5247 .@"trailing.field_aligns.?.len" = .@"payload.fields_len",
5849 .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields",5248 .@"trailing.field_is_comptime_bits.?" = .@"payload.flags.any_comptime_fields",
5850 .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32",5249 .@"trailing.field_is_comptime_bits.?.len" = .@"(payload.fields_len + 31) / 32",
5851 .@"trailing.field_index.?" = .@"!payload.flags.is_extern",5250 .@"trailing.field_runtime_order.?" = .@"payload.flags.layout == .auto",
5852 .@"trailing.field_index.?.len" = .@"payload.fields_len",5251 .@"trailing.field_runtime_order.?.len" = .@"payload.fields_len",
5853 .@"trailing.field_offset.len" = .@"payload.fields_len",5252 .@"trailing.field_offsets.len" = .@"payload.fields_len",
5854 },5253 },
5855 },5254 },
5856 .type_struct_packed = .{5255 .type_struct_packed_auto = struct_packed_encoding,
5256 .type_struct_packed_explicit = struct_packed_encoding,
5257 .type_struct_packed_auto_defaults = struct_packed_defaults_encoding,
5258 .type_struct_packed_explicit_defaults = struct_packed_defaults_encoding,
5259 .type_union = .{
5857 .summary = .@"{.payload.name%summary#\"}",5260 .summary = .@"{.payload.name%summary#\"}",
5858 .payload = TypeStructPacked,5261 .payload = TypeUnion,
5859 .trailing = struct {5262 .trailing = struct {
5263 type_hash: ?u64,
5860 captures_len: ?u32,5264 captures_len: ?u32,
5861 captures: ?[]CaptureValue,5265 captures: ?[]CaptureValue,
5862 type_hash: ?u64,
5863 field_types: []Index,5266 field_types: []Index,
5864 field_names: []NullTerminatedString,5267 field_aligns: ?[]Alignment,
5865 },5268 },
5866 .config = .{5269 .config = .{
5867 .@"trailing.captures_len.?" = .@"payload.flags.any_captures",5270 .@"trailing.type_hash.?" = .@"payload.flags.any_captures == .reified",
5868 .@"trailing.captures.?" = .@"payload.flags.any_captures",5271 .@"trailing.captures_len.?" = .@"payload.flags.any_captures == .true",
5272 .@"trailing.captures.?" = .@"payload.flags.any_captures == .true",
5869 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",5273 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
5870 .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified",
5871 .@"trailing.field_types.len" = .@"payload.fields_len",5274 .@"trailing.field_types.len" = .@"payload.fields_len",
5872 .@"trailing.field_names.len" = .@"payload.fields_len",5275 .@"trailing.field_aligns.?" = .@"payloads.flags.any_field_aligns",
5276 .@"trailing.field_aligns.?.len" = .@"payload.fields_len",
5873 },5277 },
5874 },5278 },
5875 .type_struct_packed_inits = .{5279 .type_union_packed_auto = union_packed_encoding,
5280 .type_union_packed_explicit = union_packed_encoding,
5281 .type_enum_auto = .{
5876 .summary = .@"{.payload.name%summary#\"}",5282 .summary = .@"{.payload.name%summary#\"}",
5877 .payload = TypeStructPacked,5283 .payload = TypeEnum,
5878 .trailing = struct {5284 .trailing = struct {
5879 captures_len: ?u32,5285 owner_union: ?Index,
5880 captures: ?[]CaptureValue,5286 zir_index: ?TrackedInst.Index,
5881 type_hash: ?u64,5287 type_hash: ?u64,
5882 field_types: []Index,5288 captures: ?[]CaptureValue,
5883 field_names: []NullTerminatedString,5289 field_names: []NullTerminatedString,
5884 field_inits: []Index,
5885 },5290 },
5886 .config = .{5291 .config = .{
5887 .@"trailing.captures_len.?" = .@"payload.flags.any_captures",5292 .@"trailing.owner_union.?" = .@"payload.captures_len == .generated_union_tag",
5888 .@"trailing.captures.?" = .@"payload.flags.any_captures",5293 .@"trailing.zir_index.?" = .@"payload.captures_len != .generated_union_tag",
5889 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",5294 .@"trailing.type_hash.?" = .@"payload.captures_len == .reified",
5890 .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified",5295 .@"trailing.captures.?" = .@"payload.captures_len != .reified and payload.captures_len != .generated_enum_tag",
5891 .@"trailing.field_types.len" = .@"payload.fields_len",5296 .@"trailing.captures.?.len" = .@"@intFromEnum(payload.captures_len)",
5892 .@"trailing.field_names.len" = .@"payload.fields_len",5297 .@"trailing.field_names.len" = .@"payload.fields_len",
5893 .@"trailing.field_inits.len" = .@"payload.fields_len",
5894 },
5895 },
5896 .type_tuple = .{
5897 .summary = .@"struct {...}",
5898 .payload = TypeTuple,
5899 .trailing = struct {
5900 field_types: []Index,
5901 field_values: []Index,
5902 },
5903 .config = .{
5904 .@"trailing.field_types.len" = .@"payload.fields_len",
5905 .@"trailing.field_values.len" = .@"payload.fields_len",
5906 },5298 },
5907 },5299 },
5908 .type_union = .{5300 .type_enum_explicit = enum_explicit_encoding,
5301 .type_enum_nonexhaustive = enum_explicit_encoding,
5302 .type_opaque = .{
5909 .summary = .@"{.payload.name%summary#\"}",5303 .summary = .@"{.payload.name%summary#\"}",
5910 .payload = TypeUnion,5304 .payload = TypeOpaque,
5911 .trailing = struct {5305 .trailing = struct { captures: []CaptureValue },
5912 captures_len: ?u32,5306 .config = .{ .@"trailing.captures.len" = .@"payload.captures_len" },
5913 captures: ?[]CaptureValue,
5914 type_hash: ?u64,
5915 field_types: []Index,
5916 field_aligns: []Alignment,
5917 },
5918 .config = .{
5919 .@"trailing.captures_len.?" = .@"payload.flags.any_captures",
5920 .@"trailing.captures.?" = .@"payload.flags.any_captures",
5921 .@"trailing.captures.?.len" = .@"trailing.captures_len.?",
5922 .@"trailing.type_hash.?" = .@"payload.is_flags.is_reified",
5923 .@"trailing.field_types.len" = .@"payload.fields_len",
5924 .@"trailing.field_aligns.len" = .@"payload.fields_len",
5925 },
5926 },
5927 .type_function = .{
5928 .summary = .@"fn (...) ... {.payload.return_type%summary}",
5929 .payload = TypeFunction,
5930 .trailing = struct {
5931 param_comptime_bits: ?[]u32,
5932 param_noalias_bits: ?[]u32,
5933 param_type: []Index,
5934 },
5935 .config = .{
5936 .@"trailing.param_comptime_bits.?" = .@"payload.flags.has_comptime_bits",
5937 .@"trailing.param_comptime_bits.?.len" = .@"(payload.params_len + 31) / 32",
5938 .@"trailing.param_noalias_bits.?" = .@"payload.flags.has_noalias_bits",
5939 .@"trailing.param_noalias_bits.?.len" = .@"(payload.params_len + 31) / 32",
5940 .@"trailing.param_type.len" = .@"payload.params_len",
5941 },
5942 },5307 },
59435308
5944 .undef = .{ .summary = .@"@as({.data%summary}, undefined)", .data = Index },5309 .undef = .{ .summary = .@"@as({.data%summary}, undefined)", .data = Index },
...@@ -5999,8 +5364,6 @@ pub const Tag = enum(u8) {...@@ -5999,8 +5364,6 @@ pub const Tag = enum(u8) {
5999 .int_small = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.value%value})", .payload = IntSmall },5364 .int_small = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.value%value})", .payload = IntSmall },
6000 .int_positive = .{},5365 .int_positive = .{},
6001 .int_negative = .{},5366 .int_negative = .{},
6002 .int_lazy_align = .{ .summary = .@"@as({.payload.ty%summary}, @alignOf({.payload.lazy_ty%summary}))", .payload = IntLazy },
6003 .int_lazy_size = .{ .summary = .@"@as({.payload.ty%summary}, @sizeOf({.payload.lazy_ty%summary}))", .payload = IntLazy },
6004 .error_set_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error },5367 .error_set_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error },
6005 .error_union_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error },5368 .error_union_error = .{ .summary = .@"@as({.payload.ty%summary}, error.@{.payload.name%summary})", .payload = Error },
6006 .error_union_payload = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.val%summary})", .payload = TypeValue },5369 .error_union_payload = .{ .summary = .@"@as({.payload.ty%summary}, {.payload.val%summary})", .payload = TypeValue },
...@@ -6166,164 +5529,242 @@ pub const Tag = enum(u8) {...@@ -6166,164 +5529,242 @@ pub const Tag = enum(u8) {
6166 pub const Flags = packed struct(u32) {5529 pub const Flags = packed struct(u32) {
6167 cc: PackedCallingConvention,5530 cc: PackedCallingConvention,
6168 is_var_args: bool,5531 is_var_args: bool,
6169 is_generic: bool,
6170 has_comptime_bits: bool,5532 has_comptime_bits: bool,
6171 has_noalias_bits: bool,5533 has_noalias_bits: bool,
6172 is_noinline: bool,5534 is_noinline: bool,
6173 _: u9 = 0,5535 _: u10 = 0,
6174 };5536 };
6175 };5537 };
61765538
5539 /// At first I thought of storing the denormalized data externally, such as...
5540 ///
5541 /// * runtime field order
5542 /// * calculated field offsets
5543 /// * size and alignment of the struct
5544 ///
5545 /// ...since these can be computed based on the other data here. However,
5546 /// this data does need to be memoized, and therefore stored in memory
5547 /// while the compiler is running, in order to avoid O(N^2) logic in many
5548 /// places. Since the data can be stored compactly in the InternPool
5549 /// representation, it is better for memory usage to store denormalized data
5550 /// here, and potentially also better for performance as well. It's also simpler
5551 /// than coming up with some other scheme for the data.
5552 ///
6177 /// Trailing:5553 /// Trailing:
6178 /// 0. captures_len: u32 // if `any_captures`5554 /// 0. type_hash: PackedU64 // if `any_captures == .reified`
6179 /// 1. capture: CaptureValue // for each `captures_len`5555 /// 1. captures_len: u32 // if `any_captures == .true`
6180 /// 2. type_hash: PackedU64 // if `is_reified`5556 /// 2. capture: CaptureValue // for each `captures_len`
6181 /// 3. field type: Index for each field; declaration order5557 /// 3. field_name: NullTerminatedString // for each `fields_len`
6182 /// 4. field align: Alignment for each field; declaration order5558 /// 4. field_type: Index // for each `fields_len`
6183 pub const TypeUnion = struct {5559 /// 5. field_default: Index // if `any_field_defaults`; for each `fields_len`
5560 /// 6. field_align: Alignment // if `any_field_aligns`; for each `fields_len`
5561 /// 7. field_is_comptime_bits: u32 // if `any_comptime_fields`; minimum `u32` for `fields_len`; LSB is field 0
5562 /// 8. field_runtime_order: RuntimeOrder // if `layout == .auto`; for each `fields_len`
5563 /// 9. field_offset: u32 // for each `fields_len`
5564 pub const TypeStruct = struct {
5565 zir_index: TrackedInst.Index,
5566
6184 name: NullTerminatedString,5567 name: NullTerminatedString,
6185 name_nav: Nav.Index.Optional,5568 name_nav: Nav.Index.Optional,
6186 flags: Flags,5569 namespace: NamespaceIndex,
6187 /// This could be provided through the tag type, but it is more convenient5570
6188 /// to store it directly. This is also necessary for `dumpStatsFallible` to
6189 /// work on unresolved types.
6190 fields_len: u32,5571 fields_len: u32,
6191 /// Only valid after .have_layout5572 field_name_map: MapIndex,
5573
5574 /// Size in bytes of the whole struct. Always 0 until layout resolved.
6192 size: u32,5575 size: u32,
6193 /// Only valid after .have_layout5576
6194 padding: u32,5577 flags: Flags,
6195 namespace: NamespaceIndex,
6196 /// The enum that provides the list of field names and values.
6197 tag_ty: Index,
6198 zir_index: TrackedInst.Index,
61995578
6200 pub const Flags = packed struct(u32) {5579 pub const Flags = packed struct(u32) {
6201 any_captures: bool,5580 any_captures: enum(u2) { true, false, reified },
6202 runtime_tag: LoadedUnionType.RuntimeTag,5581
6203 /// If false, the field alignment trailing data is omitted.5582 /// `packed` layout is represented separately by `TypeStructPacked`.
6204 any_aligned_fields: bool,5583 layout: enum(u1) { auto, @"extern" },
6205 layout: std.builtin.Type.ContainerLayout,5584
6206 status: LoadedUnionType.Status,5585 any_comptime_fields: bool,
6207 requires_comptime: RequiresComptime,5586 any_field_defaults: bool,
6208 assumed_runtime_bits: bool,5587 any_field_aligns: bool,
6209 assumed_pointer_aligned: bool,5588
5589 /// Whether the struct is an OPV type. Always `false` until layout resolved.
5590 /// The actual OPV is not cached, but caching this bit of state means we avoid
5591 /// repeatedly doing redundant checks to find that the struct is not OPV!
5592 has_one_possible_value: bool,
5593 /// Like `has_one_possible_value`, but for a "noreturn" union (where all fields are noreturn).
5594 has_no_possible_value: bool,
5595 /// Whether the struct is comptime-only. Always `false` until layout resolved.
5596 comptime_only: bool,
5597 /// Alignment of the whole struct. Always `.none` until layout resolved.
6210 alignment: Alignment,5598 alignment: Alignment,
6211 is_reified: bool,5599
6212 _: u12 = 0,5600 _: u17 = 0,
6213 };5601 };
6214 };5602 };
62155603
6216 /// Trailing:5604 /// Trailing:
6217 /// 0. captures_len: u32 // if `any_captures`5605 /// 0. type_hash: PackedU64 // if `captures_len == .reified`
6218 /// 1. capture: CaptureValue // for each `captures_len`5606 /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len`
6219 /// 2. type_hash: PackedU64 // if `is_reified`5607 /// 2. field_name: NullTerminatedString // for each `fields_len`
6220 /// 3. type: Index for each fields_len5608 /// 3. field_type: Index // for each `fields_len`
6221 /// 4. name: NullTerminatedString for each fields_len5609 /// 4. field_default: Index // if item tag implies field defaults; for each `fields_len`
6222 /// 5. init: Index for each fields_len // if tag is type_struct_packed_inits
6223 pub const TypeStructPacked = struct {5610 pub const TypeStructPacked = struct {
5611 zir_index: TrackedInst.Index,
5612 captures_len: enum(u32) {
5613 reified = std.math.maxInt(u32),
5614 _,
5615 },
5616
6224 name: NullTerminatedString,5617 name: NullTerminatedString,
6225 name_nav: Nav.Index.Optional,5618 name_nav: Nav.Index.Optional,
6226 zir_index: TrackedInst.Index,5619 namespace: NamespaceIndex,
5620
5621 /// The corresponding `PackedBackingMode` depends on the item's `Tag`.
5622 backing_int_type: Index,
5623
6227 fields_len: u32,5624 fields_len: u32,
5625 field_name_map: MapIndex,
5626 };
5627
5628 /// Field names are intentionally omitted---they are available in `enum_tag_type`.
5629 ///
5630 /// Trailing:
5631 /// 0. type_hash: PackedU64 // if `any_captures == .reified`
5632 /// 1. captures_len: u32 // if `any_captures == .true`
5633 /// 2. capture: CaptureValue // if `any_captures == .true`; for each `captures_len`
5634 /// 3. field_type: Index // for each `fields_len`
5635 /// 4. field_align: Alignment // for each `fields_len` if `any_field_aligns`
5636 pub const TypeUnion = struct {
5637 zir_index: TrackedInst.Index,
5638
5639 name: NullTerminatedString,
5640 name_nav: Nav.Index.Optional,
6228 namespace: NamespaceIndex,5641 namespace: NamespaceIndex,
6229 backing_int_ty: Index,5642 /// The enum that provides the list of field names and values.
6230 names_map: MapIndex,5643 enum_tag_type: Index,
5644
5645 /// This could be provided through the tag type, but it is more convenient
5646 /// to store it directly. This is also necessary for `dumpStatsFallible` to
5647 /// work on unresolved types.
5648 /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now.
5649 fields_len: u32,
5650
5651 /// Always 0 until layout resolved.
5652 size: u32,
5653 /// Always 0 until layout resolved.
5654 padding: u32,
5655
6231 flags: Flags,5656 flags: Flags,
62325657
6233 pub const Flags = packed struct(u32) {5658 pub const Flags = packed struct(u32) {
6234 any_captures: bool = false,5659 any_captures: enum(u2) { true, false, reified },
6235 /// Dependency loop detection when resolving field inits.5660
6236 field_inits_wip: bool = false,5661 /// Whether `enum_tag_type` was explicitly specified with `union(E)` syntax.
6237 inits_resolved: bool = false,5662 ///
6238 is_reified: bool = false,5663 /// For `union(enum(E))` syntax, this is `false`, but the generated enum tag type is
6239 _: u28 = 0,5664 /// considered to have an explicitly specified integer tag type.
5665 explicit_tag_type: bool,
5666
5667 /// `packed` layout is represented separately by `TypeStructPacked`.
5668 layout: enum(u1) { auto, @"extern" },
5669
5670 any_field_aligns: bool,
5671 runtime_tag: LoadedUnionType.RuntimeTag,
5672
5673 /// Whether the union is an OPV type. Always `false` until layout resolved.
5674 /// The actual OPV is not cached, but caching this bit of state means we avoid
5675 /// repeatedly doing redundant checks to find that the union is not OPV!
5676 has_one_possible_value: bool,
5677 /// Like `has_one_possible_value`, but for a "noreturn" union (where all fields are noreturn).
5678 has_no_possible_value: bool,
5679 /// Whether the union is comptime-only. Always `false` until layout resolved.
5680 comptime_only: bool,
5681 /// Alignment of the whole union. Always `.none` until layout resolved.
5682 alignment: Alignment,
5683
5684 _: u16 = 0,
6240 };5685 };
6241 };5686 };
62425687
6243 /// At first I thought of storing the denormalized data externally, such as...5688 /// Field names are intentionally omitted---they are available in `enum_tag_type`.
6244 ///
6245 /// * runtime field order
6246 /// * calculated field offsets
6247 /// * size and alignment of the struct
6248 ///
6249 /// ...since these can be computed based on the other data here. However,
6250 /// this data does need to be memoized, and therefore stored in memory
6251 /// while the compiler is running, in order to avoid O(N^2) logic in many
6252 /// places. Since the data can be stored compactly in the InternPool
6253 /// representation, it is better for memory usage to store denormalized data
6254 /// here, and potentially also better for performance as well. It's also simpler
6255 /// than coming up with some other scheme for the data.
6256 ///5689 ///
6257 /// Trailing:5690 /// Trailing:
6258 /// 0. captures_len: u32 // if `any_captures`5691 /// 0. type_hash: PackedU64 // if `captures_len == .reified`
6259 /// 1. capture: CaptureValue // for each `captures_len`5692 /// 1. capture: CaptureValue // if `captures_len != .reified`; for each `captures_len`
6260 /// 2. type_hash: PackedU64 // if `is_reified`5693 /// 2. field_type: Index // for each `fields_len`
6261 /// 3. type: Index for each field in declared order5694 pub const TypeUnionPacked = struct {
6262 /// 4. if any_default_inits:5695 zir_index: TrackedInst.Index,
6263 /// init: Index // for each field in declared order5696 captures_len: enum(u32) {
6264 /// 5. if any_aligned_fields:5697 reified = std.math.maxInt(u32),
6265 /// align: Alignment // for each field in declared order5698 _,
6266 /// 6. if any_comptime_fields:5699 },
6267 /// field_is_comptime_bits: u32 // minimal number of u32s needed, LSB is field 05700
6268 /// 7. if not is_extern:
6269 /// field_index: RuntimeOrder // for each field in runtime order
6270 /// 8. field_offset: u32 // for each field in declared order, undef until layout_resolved
6271 pub const TypeStruct = struct {
6272 name: NullTerminatedString,5701 name: NullTerminatedString,
6273 name_nav: Nav.Index.Optional,5702 name_nav: Nav.Index.Optional,
6274 zir_index: TrackedInst.Index,
6275 namespace: NamespaceIndex,5703 namespace: NamespaceIndex,
5704
5705 /// The corresponding `PackedBackingMode` depends on the item's `Tag`.
5706 backing_int_type: Index,
5707 /// Although packed unions do not semantically have a tag type, the compiler still assigns
5708 /// them a "hypothetical" tag type.
5709 enum_tag_type: Index,
5710
5711 /// This could be provided through the tag type, but it is more convenient
5712 /// to store it directly. This is also necessary for `dumpStatsFallible` to
5713 /// work on unresolved types.
5714 /// MLUGG TODO: reconsider, because we resolve the tag type eagerly now.
6276 fields_len: u32,5715 fields_len: u32,
6277 flags: Flags,5716 };
6278 size: u32,
62795717
6280 pub const Flags = packed struct(u32) {5718 /// Trailing:
6281 any_captures: bool = false,5719 /// 0. owner_union: Index // if `captures_len == .generated_union_tag`
6282 is_extern: bool = false,5720 /// 1. zir_index: TrackedInst.Index // if `captures_len != .generated_union_tag`
6283 known_non_opv: bool = false,5721 /// 2. type_hash: PackedU64 // if `captures_len == .reified`
6284 requires_comptime: RequiresComptime = @enumFromInt(0),5722 /// 3. capture: CaptureValue // if `captures_len` is not a named tag; for each `captures_len`
6285 assumed_runtime_bits: bool = false,5723 /// 4. field_value_map: MapIndex // if tag is not `.type_enum_auto`
6286 assumed_pointer_aligned: bool = false,5724 /// 5. field_name: NullTerminatedString // for each `fields_len`
6287 any_comptime_fields: bool = false,5725 /// 6. field_value: Index // if tag is not `.type_enum_auto`; for each `fields_len`
6288 any_default_inits: bool = false,5726 pub const TypeEnum = struct {
6289 any_aligned_fields: bool = false,5727 captures_len: enum(u32) {
6290 /// `.none` until layout_resolved5728 reified = std.math.maxInt(u32),
6291 alignment: Alignment = @enumFromInt(0),5729 generated_union_tag = std.math.maxInt(u32) - 1,
6292 /// Dependency loop detection when resolving struct alignment.5730 _,
6293 alignment_wip: bool = false,5731 },
6294 /// Dependency loop detection when resolving field types.5732
6295 field_types_wip: bool = false,5733 name: NullTerminatedString,
6296 /// Dependency loop detection when resolving struct layout.5734 name_nav: Nav.Index.Optional,
6297 layout_wip: bool = false,5735 namespace: NamespaceIndex,
6298 /// Indicates whether `size`, `alignment`, runtime field order, and5736
6299 /// field offets are populated.5737 /// An integer type which is used for the numerical value of the enum. Whether this was
6300 layout_resolved: bool = false,5738 /// user-provided or inferred by the compiler depends on the tag. Either way, the field
6301 /// Dependency loop detection when resolving field inits.5739 /// is populated immediately (i.e. does not require any type resolution).
6302 field_inits_wip: bool = false,5740 int_tag_type: Index,
6303 /// Indicates whether `field_inits` has been resolved.5741
6304 inits_resolved: bool = false,5742 fields_len: u32,
6305 // The types and all its fields have had their layout resolved. Even through pointer = false,5743 field_name_map: MapIndex,
6306 // which `layout_resolved` does not ensure.
6307 fully_resolved: bool = false,
6308 is_reified: bool = false,
6309 _: u8 = 0,
6310 };
6311 };5744 };
63125745
6313 /// Trailing:5746 /// Trailing:
6314 /// 0. capture: CaptureValue // for each `captures_len`5747 /// 0. capture: CaptureValue // for each `captures_len`
6315 pub const TypeOpaque = struct {5748 pub const TypeOpaque = struct {
5749 zir_index: TrackedInst.Index,
5750 captures_len: u32,
5751
6316 name: NullTerminatedString,5752 name: NullTerminatedString,
6317 name_nav: Nav.Index.Optional,5753 name_nav: Nav.Index.Optional,
6318 /// Contains the declarations inside this opaque.
6319 namespace: NamespaceIndex,5754 namespace: NamespaceIndex,
6320 /// The index of the `opaque_decl` instruction.
6321 zir_index: TrackedInst.Index,
6322 /// `std.math.maxInt(u32)` indicates this type is reified.
6323 captures_len: u32,
6324 };5755 };
6325};5756};
63265757
5758/// Differentiates between user-provided and compiler-generated backing types for packed aggregates.
5759pub const PackedBackingMode = enum(u1) {
5760 /// The backing type was explicitly provided by the user, i.e. `packed struct(T)` or `packed union(T)`.
5761 /// Type resolution simply *validates* that type.
5762 explicit,
5763 /// No backing type was explicitly provided by the user. Type layout resolution will populate the
5764 /// backing type based on the field types; before then it is invalid (probably `.none`).
5765 auto,
5766};
5767
6327/// State that is mutable during semantic analysis. This data is not used for5768/// State that is mutable during semantic analysis. This data is not used for
6328/// equality or hashing, except for `inferred_error_set` which is considered5769/// equality or hashing, except for `inferred_error_set` which is considered
6329/// to be part of the type of the function.5770/// to be part of the type of the function.
...@@ -6536,10 +5977,8 @@ pub const Alignment = enum(u6) {...@@ -6536,10 +5977,8 @@ pub const Alignment = enum(u6) {
6536 pub const empty: Slice = .{ .tid = .main, .start = 0, .len = 0 };5977 pub const empty: Slice = .{ .tid = .main, .start = 0, .len = 0 };
65375978
6538 pub fn get(slice: Slice, ip: *const InternPool) []Alignment {5979 pub fn get(slice: Slice, ip: *const InternPool) []Alignment {
6539 // TODO: implement @ptrCast between slices changing the length
6540 const extra = ip.getLocalShared(slice.tid).extra.acquire();5980 const extra = ip.getLocalShared(slice.tid).extra.acquire();
6541 //const bytes: []u8 = @ptrCast(extra.view().items(.@"0")[slice.start..]);5981 const bytes: []u8 = @ptrCast(extra.view().items(.@"0")[slice.start..]);
6542 const bytes: []u8 = std.mem.sliceAsBytes(extra.view().items(.@"0")[slice.start..]);
6543 return @ptrCast(bytes[0..slice.len]);5982 return @ptrCast(bytes[0..slice.len]);
6544 }5983 }
6545 };5984 };
...@@ -6596,55 +6035,6 @@ pub const Array = struct {...@@ -6596,55 +6035,6 @@ pub const Array = struct {
6596 }6035 }
6597};6036};
65986037
6599/// Trailing:
6600/// 0. owner_union: Index // if `zir_index == .none`
6601/// 1. capture: CaptureValue // for each `captures_len`
6602/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6603/// 3. field name: NullTerminatedString for each fields_len; declaration order
6604/// 4. tag value: Index for each fields_len; declaration order
6605pub const EnumExplicit = struct {
6606 name: NullTerminatedString,
6607 name_nav: Nav.Index.Optional,
6608 /// `std.math.maxInt(u32)` indicates this type is reified.
6609 captures_len: u32,
6610 namespace: NamespaceIndex,
6611 /// An integer type which is used for the numerical value of the enum, which
6612 /// has been explicitly provided by the enum declaration.
6613 int_tag_type: Index,
6614 fields_len: u32,
6615 /// Maps field names to declaration index.
6616 names_map: MapIndex,
6617 /// Maps field values to declaration index.
6618 /// If this is `none`, it means the trailing tag values are absent because
6619 /// they are auto-numbered.
6620 values_map: OptionalMapIndex,
6621 /// `none` means this is a generated tag type.
6622 /// There will be a trailing union type for which this is a tag.
6623 zir_index: TrackedInst.Index.Optional,
6624};
6625
6626/// Trailing:
6627/// 0. owner_union: Index // if `zir_index == .none`
6628/// 1. capture: CaptureValue // for each `captures_len`
6629/// 2. type_hash: PackedU64 // if reified (`captures_len == std.math.maxInt(u32)`)
6630/// 3. field name: NullTerminatedString for each fields_len; declaration order
6631pub const EnumAuto = struct {
6632 name: NullTerminatedString,
6633 name_nav: Nav.Index.Optional,
6634 /// `std.math.maxInt(u32)` indicates this type is reified.
6635 captures_len: u32,
6636 namespace: NamespaceIndex,
6637 /// An integer type which is used for the numerical value of the enum, which
6638 /// was inferred by Zig based on the number of tags.
6639 int_tag_type: Index,
6640 fields_len: u32,
6641 /// Maps field names to declaration index.
6642 names_map: MapIndex,
6643 /// `none` means this is a generated tag type.
6644 /// There will be a trailing union type for which this is a tag.
6645 zir_index: TrackedInst.Index.Optional,
6646};
6647
6648pub const PackedU64 = packed struct(u64) {6038pub const PackedU64 = packed struct(u64) {
6649 a: u32,6039 a: u32,
6650 b: u32,6040 b: u32,
...@@ -6827,11 +6217,6 @@ pub const IntSmall = struct {...@@ -6827,11 +6217,6 @@ pub const IntSmall = struct {
6827 value: u32,6217 value: u32,
6828};6218};
68296219
6830pub const IntLazy = struct {
6831 ty: Index,
6832 lazy_ty: Index,
6833};
6834
6835/// A f64 value, broken up into 2 u32 parts.6220/// A f64 value, broken up into 2 u32 parts.
6836pub const Float64 = struct {6221pub const Float64 = struct {
6837 piece0: u32,6222 piece0: u32,
...@@ -6994,7 +6379,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {...@@ -6994,7 +6379,9 @@ pub fn deinit(ip: *InternPool, gpa: Allocator, io: Io) void {
6994 ip.src_hash_deps.deinit(gpa);6379 ip.src_hash_deps.deinit(gpa);
6995 ip.nav_val_deps.deinit(gpa);6380 ip.nav_val_deps.deinit(gpa);
6996 ip.nav_ty_deps.deinit(gpa);6381 ip.nav_ty_deps.deinit(gpa);
6997 ip.interned_deps.deinit(gpa);6382 ip.func_ies_deps.deinit(gpa);
6383 ip.type_layout_deps.deinit(gpa);
6384 ip.type_inits_deps.deinit(gpa);
6998 ip.zon_file_deps.deinit(gpa);6385 ip.zon_file_deps.deinit(gpa);
6999 ip.embed_file_deps.deinit(gpa);6386 ip.embed_file_deps.deinit(gpa);
7000 ip.namespace_deps.deinit(gpa);6387 ip.namespace_deps.deinit(gpa);
...@@ -7130,132 +6517,138 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7130,132 +6517,138 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7130 .type_inferred_error_set => .{6517 .type_inferred_error_set => .{
7131 .inferred_error_set_type = @enumFromInt(data),6518 .inferred_error_set_type = @enumFromInt(data),
7132 },6519 },
71336520 .type_function => .{ .func_type = extraFuncType(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
7134 .type_opaque => .{ .opaque_type = ns: {6521 .type_tuple => .{ .tuple_type = extraTypeTuple(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
7135 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);
7136 if (extra.data.captures_len == std.math.maxInt(u32)) {
7137 break :ns .{ .reified = .{
7138 .zir_index = extra.data.zir_index,
7139 .type_hash = 0,
7140 } };
7141 }
7142 break :ns .{ .declared = .{
7143 .zir_index = extra.data.zir_index,
7144 .captures = .{ .owned = .{
7145 .tid = unwrapped_index.tid,
7146 .start = extra.end,
7147 .len = extra.data.captures_len,
7148 } },
7149 } };
7150 } },
71516522
7152 .type_struct => .{ .struct_type = ns: {6523 .type_struct => .{ .struct_type = ns: {
7153 const extra_list = unwrapped_index.getExtra(ip);6524 const extra_list = unwrapped_index.getExtra(ip);
7154 const extra_items = extra_list.view().items(.@"0");6525 const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);
7155 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "zir_index").?]);6526 break :ns switch (extra.data.flags.any_captures) {
7156 const flags: Tag.TypeStruct.Flags = @bitCast(@atomicLoad(u32, &extra_items[data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?], .unordered));6527 .reified => .{ .reified = .{
7157 const end_extra_index = data + @as(u32, @typeInfo(Tag.TypeStruct).@"struct".fields.len);6528 .zir_index = extra.data.zir_index,
7158 if (flags.is_reified) {6529 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
7159 assert(!flags.any_captures);6530 } },
7160 break :ns .{ .reified = .{6531 .false => .{ .declared = .{
7161 .zir_index = zir_index,6532 .zir_index = extra.data.zir_index,
7162 .type_hash = extraData(extra_list, PackedU64, end_extra_index).get(),6533 .arg_ty = .none,
7163 } };6534 .captures = .{ .owned = .empty },
7164 }6535 } },
7165 break :ns .{ .declared = .{6536 .true => .{ .declared = .{
7166 .zir_index = zir_index,6537 .zir_index = extra.data.zir_index,
7167 .captures = .{ .owned = if (flags.any_captures) .{6538 .arg_ty = .none,
7168 .tid = unwrapped_index.tid,6539 .captures = .{ .owned = .{
7169 .start = end_extra_index + 1,6540 .tid = unwrapped_index.tid,
7170 .len = extra_list.view().items(.@"0")[end_extra_index],6541 .start = extra.end + 1,
7171 } else CaptureValue.Slice.empty },6542 .len = extra_list.view().items(.@"0")[extra.end],
7172 } };6543 } },
6544 } },
6545 };
7173 } },6546 } },
71746547 .type_struct_packed_auto,
7175 .type_struct_packed, .type_struct_packed_inits => .{ .struct_type = ns: {6548 .type_struct_packed_explicit,
6549 .type_struct_packed_auto_defaults,
6550 .type_struct_packed_explicit_defaults,
6551 => .{ .struct_type = ns: {
7176 const extra_list = unwrapped_index.getExtra(ip);6552 const extra_list = unwrapped_index.getExtra(ip);
7177 const extra_items = extra_list.view().items(.@"0");6553 const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
7178 const zir_index: TrackedInst.Index = @enumFromInt(extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "zir_index").?]);6554 break :ns switch (extra.data.captures_len) {
7179 const flags: Tag.TypeStructPacked.Flags = @bitCast(@atomicLoad(u32, &extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "flags").?], .unordered));6555 .reified => .{ .reified = .{
7180 const end_extra_index = data + @as(u32, @typeInfo(Tag.TypeStructPacked).@"struct".fields.len);6556 .zir_index = extra.data.zir_index,
7181 if (flags.is_reified) {6557 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
7182 assert(!flags.any_captures);6558 } },
7183 break :ns .{ .reified = .{6559 _ => .{ .declared = .{
7184 .zir_index = zir_index,6560 .zir_index = extra.data.zir_index,
7185 .type_hash = extraData(extra_list, PackedU64, end_extra_index).get(),6561 .arg_ty = switch (item.tag) {
7186 } };6562 .type_struct_packed_auto, .type_struct_packed_auto_defaults => .none,
7187 }6563 .type_struct_packed_explicit, .type_struct_packed_explicit_defaults => extra.data.backing_int_type,
7188 break :ns .{ .declared = .{6564 else => unreachable,
7189 .zir_index = zir_index,6565 },
7190 .captures = .{ .owned = if (flags.any_captures) .{6566 .captures = .{ .owned = .{
7191 .tid = unwrapped_index.tid,6567 .tid = unwrapped_index.tid,
7192 .start = end_extra_index + 1,6568 .start = extra.end,
7193 .len = extra_items[end_extra_index],6569 .len = @intFromEnum(extra.data.captures_len),
7194 } else CaptureValue.Slice.empty },6570 } },
7195 } };6571 } },
6572 };
7196 } },6573 } },
7197 .type_tuple => .{ .tuple_type = extraTypeTuple(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
7198 .type_union => .{ .union_type = ns: {6574 .type_union => .{ .union_type = ns: {
7199 const extra_list = unwrapped_index.getExtra(ip);6575 const extra_list = unwrapped_index.getExtra(ip);
7200 const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);6576 const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);
7201 if (extra.data.flags.is_reified) {6577 break :ns switch (extra.data.flags.any_captures) {
7202 assert(!extra.data.flags.any_captures);6578 .reified => .{ .reified = .{
7203 break :ns .{ .reified = .{
7204 .zir_index = extra.data.zir_index,6579 .zir_index = extra.data.zir_index,
7205 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),6580 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
7206 } };6581 } },
7207 }6582 .false => .{ .declared = .{
7208 break :ns .{ .declared = .{6583 .zir_index = extra.data.zir_index,
7209 .zir_index = extra.data.zir_index,6584 .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none,
7210 .captures = .{ .owned = if (extra.data.flags.any_captures) .{6585 .captures = .{ .owned = .empty },
7211 .tid = unwrapped_index.tid,6586 } },
7212 .start = extra.end + 1,6587 .true => .{ .declared = .{
7213 .len = extra_list.view().items(.@"0")[extra.end],6588 .zir_index = extra.data.zir_index,
7214 } else CaptureValue.Slice.empty },6589 .arg_ty = if (extra.data.flags.explicit_tag_type) extra.data.enum_tag_type else .none,
7215 } };6590 .captures = .{ .owned = .{
6591 .tid = unwrapped_index.tid,
6592 .start = extra.end + 1,
6593 .len = extra_list.view().items(.@"0")[extra.end],
6594 } },
6595 } },
6596 };
7216 } },6597 } },
72176598 .type_union_packed_auto, .type_union_packed_explicit => .{ .union_type = ns: {
7218 .type_enum_auto => .{ .enum_type = ns: {
7219 const extra_list = unwrapped_index.getExtra(ip);6599 const extra_list = unwrapped_index.getExtra(ip);
7220 const extra = extraDataTrail(extra_list, EnumAuto, data);6600 const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data);
7221 const zir_index = extra.data.zir_index.unwrap() orelse {6601 break :ns switch (extra.data.captures_len) {
7222 assert(extra.data.captures_len == 0);6602 .reified => .{ .reified = .{
7223 break :ns .{ .generated_tag = .{6603 .zir_index = extra.data.zir_index,
7224 .union_type = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
7225 } };
7226 };
7227 if (extra.data.captures_len == std.math.maxInt(u32)) {
7228 break :ns .{ .reified = .{
7229 .zir_index = zir_index,
7230 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),6604 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
7231 } };
7232 }
7233 break :ns .{ .declared = .{
7234 .zir_index = zir_index,
7235 .captures = .{ .owned = .{
7236 .tid = unwrapped_index.tid,
7237 .start = extra.end,
7238 .len = extra.data.captures_len,
7239 } },6605 } },
7240 } };6606 _ => .{ .declared = .{
6607 .zir_index = extra.data.zir_index,
6608 .arg_ty = switch (item.tag) {
6609 .type_union_packed_auto => .none,
6610 .type_union_packed_explicit => extra.data.backing_int_type,
6611 else => unreachable,
6612 },
6613 .captures = .{ .owned = .{
6614 .tid = unwrapped_index.tid,
6615 .start = extra.end,
6616 .len = @intFromEnum(extra.data.captures_len),
6617 } },
6618 } },
6619 };
7241 } },6620 } },
7242 .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {6621 .type_enum_auto, .type_enum_explicit, .type_enum_nonexhaustive => .{ .enum_type = ns: {
7243 const extra_list = unwrapped_index.getExtra(ip);6622 const extra_list = unwrapped_index.getExtra(ip);
7244 const extra = extraDataTrail(extra_list, EnumExplicit, data);6623 const extra = extraDataTrail(extra_list, Tag.TypeEnum, data);
7245 const zir_index = extra.data.zir_index.unwrap() orelse {6624 break :ns switch (extra.data.captures_len) {
7246 assert(extra.data.captures_len == 0);6625 .reified => .{ .reified = .{
7247 break :ns .{ .generated_tag = .{6626 .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
7248 .union_type = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),6627 .type_hash = extraData(extra_list, PackedU64, extra.end + 1).get(),
7249 } };6628 } },
6629 .generated_union_tag => .{ .generated_union_tag = owner_union: {
6630 break :owner_union @enumFromInt(extra_list.view().items(.@"0")[extra.end]);
6631 } },
6632 _ => .{ .declared = .{
6633 .zir_index = @enumFromInt(extra_list.view().items(.@"0")[extra.end]),
6634 .arg_ty = switch (item.tag) {
6635 .type_enum_auto => .none,
6636 .type_enum_explicit, .type_enum_nonexhaustive => extra.data.int_tag_type,
6637 else => unreachable,
6638 },
6639 .captures = .{ .owned = .{
6640 .tid = unwrapped_index.tid,
6641 .start = extra.end + 1,
6642 .len = @intFromEnum(extra.data.captures_len),
6643 } },
6644 } },
7250 };6645 };
7251 if (extra.data.captures_len == std.math.maxInt(u32)) {6646 } },
7252 break :ns .{ .reified = .{6647 .type_opaque => .{ .opaque_type = ns: {
7253 .zir_index = zir_index,6648 const extra = extraDataTrail(unwrapped_index.getExtra(ip), Tag.TypeOpaque, data);
7254 .type_hash = extraData(extra_list, PackedU64, extra.end).get(),
7255 } };
7256 }
7257 break :ns .{ .declared = .{6649 break :ns .{ .declared = .{
7258 .zir_index = zir_index,6650 .zir_index = extra.data.zir_index,
6651 .arg_ty = .none,
7259 .captures = .{ .owned = .{6652 .captures = .{ .owned = .{
7260 .tid = unwrapped_index.tid,6653 .tid = unwrapped_index.tid,
7261 .start = extra.end,6654 .start = extra.end,
...@@ -7263,7 +6656,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7263,7 +6656,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7263 } },6656 } },
7264 } };6657 } };
7265 } },6658 } },
7266 .type_function => .{ .func_type = extraFuncType(unwrapped_index.tid, unwrapped_index.getExtra(ip), data) },
72676659
7268 .undef => .{ .undef = @enumFromInt(data) },6660 .undef => .{ .undef = @enumFromInt(data) },
7269 .opt_null => .{ .opt = .{6661 .opt_null => .{ .opt = .{
...@@ -7390,17 +6782,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7390,17 +6782,6 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7390 .storage = .{ .u64 = info.value },6782 .storage = .{ .u64 = info.value },
7391 } };6783 } };
7392 },6784 },
7393 .int_lazy_align, .int_lazy_size => |tag| {
7394 const info = extraData(unwrapped_index.getExtra(ip), IntLazy, data);
7395 return .{ .int = .{
7396 .ty = info.ty,
7397 .storage = switch (tag) {
7398 .int_lazy_align => .{ .lazy_align = info.lazy_ty },
7399 .int_lazy_size => .{ .lazy_size = info.lazy_ty },
7400 else => unreachable,
7401 },
7402 } };
7403 },
7404 .float_f16 => .{ .float = .{6785 .float_f16 => .{ .float = .{
7405 .ty = .f16_type,6786 .ty = .f16_type,
7406 .storage = .{ .f16 = @bitCast(@as(u16, @intCast(data))) },6787 .storage = .{ .f16 = @bitCast(@as(u16, @intCast(data))) },
...@@ -7488,7 +6869,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7488,7 +6869,9 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
7488 },6869 },
7489 .type_array_small,6870 .type_array_small,
7490 .type_vector,6871 .type_vector,
7491 .type_struct_packed,6872 // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire.
6873 .type_struct_packed_auto,
6874 .type_struct_packed_explicit,
7492 => .{ .aggregate = .{6875 => .{ .aggregate = .{
7493 .ty = ty,6876 .ty = ty,
7494 .storage = .{ .elems = &.{} },6877 .storage = .{ .elems = &.{} },
...@@ -7496,11 +6879,15 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {...@@ -7496,11 +6879,15 @@ pub fn indexToKey(ip: *const InternPool, index: Index) Key {
74966879
7497 // There is only one possible value precisely due to the6880 // There is only one possible value precisely due to the
7498 // fact that this values slice is fully populated!6881 // fact that this values slice is fully populated!
7499 .type_struct, .type_struct_packed_inits => {6882 .type_struct,
6883 // MLUGG TODO: is this still possible? also, i hate .only_possible_value, it should die in a fire.
6884 .type_struct_packed_auto_defaults,
6885 .type_struct_packed_explicit_defaults,
6886 => {
7500 const info = loadStructType(ip, ty);6887 const info = loadStructType(ip, ty);
7501 return .{ .aggregate = .{6888 return .{ .aggregate = .{
7502 .ty = ty,6889 .ty = ty,
7503 .storage = .{ .elems = @ptrCast(info.field_inits.get(ip)) },6890 .storage = .{ .elems = @ptrCast(info.field_defaults.get(ip)) },
7504 } };6891 } };
7505 },6892 },
75066893
...@@ -7634,7 +7021,6 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke...@@ -7634,7 +7021,6 @@ fn extraFuncType(tid: Zcu.PerThread.Id, extra: Local.Extra, extra_index: u32) Ke
7634 .cc = type_function.data.flags.cc.unpack(),7021 .cc = type_function.data.flags.cc.unpack(),
7635 .is_var_args = type_function.data.flags.is_var_args,7022 .is_var_args = type_function.data.flags.is_var_args,
7636 .is_noinline = type_function.data.flags.is_noinline,7023 .is_noinline = type_function.data.flags.is_noinline,
7637 .is_generic = type_function.data.flags.is_generic,
7638 };7024 };
7639}7025}
76407026
...@@ -7893,45 +7279,6 @@ fn getOrPutKeyEnsuringAdditionalCapacity(...@@ -7893,45 +7279,6 @@ fn getOrPutKeyEnsuringAdditionalCapacity(
7893 .map_index = map_index,7279 .map_index = map_index,
7894 } };7280 } };
7895}7281}
7896/// Like `getOrPutKey`, but asserts that the key already exists, and prepares to replace
7897/// its shard entry with a new `Index` anyway. After finalizing this, the old index remains
7898/// valid (in that `indexToKey` and similar queries will behave as before), but it will
7899/// never be returned from a lookup (`getOrPutKey` etc).
7900/// This is used by incremental compilation when an existing container type is outdated. In
7901/// this case, the type must be recreated at a new `InternPool.Index`, but the old index must
7902/// remain valid since now-unreferenced `AnalUnit`s may retain references to it. The old index
7903/// will be cleaned up when the `Zcu` undergoes garbage collection.
7904fn putKeyReplace(
7905 ip: *InternPool,
7906 io: Io,
7907 tid: Zcu.PerThread.Id,
7908 key: Key,
7909) GetOrPutKey {
7910 const full_hash = key.hash64(ip);
7911 const hash: u32 = @truncate(full_hash >> 32);
7912 const shard = &ip.shards[@intCast(full_hash & (ip.shards.len - 1))];
7913 shard.mutate.map.mutex.lock(io, tid);
7914 errdefer shard.mutate.map.mutex.unlock(io);
7915 const map = shard.shared.map;
7916 const map_mask = map.header().mask();
7917 var map_index = hash;
7918 while (true) : (map_index += 1) {
7919 map_index &= map_mask;
7920 const entry = &map.entries[map_index];
7921 const index = entry.value;
7922 assert(index != .none); // key not present
7923 if (entry.hash == hash and ip.indexToKey(index).eql(key, ip)) {
7924 break; // we found the entry to replace
7925 }
7926 }
7927 return .{ .new = .{
7928 .ip = ip,
7929 .tid = tid,
7930 .io = io,
7931 .shard = shard,
7932 .map_index = map_index,
7933 } };
7934}
79357282
7936pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {7283pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key: Key) Allocator.Error!Index {
7937 var gop = try ip.getOrPutKey(gpa, io, tid, key);7284 var gop = try ip.getOrPutKey(gpa, io, tid, key);
...@@ -8249,23 +7596,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8249,23 +7596,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
82497596
8250 .int => |int| b: {7597 .int => |int| b: {
8251 assert(ip.isIntegerType(int.ty));7598 assert(ip.isIntegerType(int.ty));
8252 switch (int.storage) {
8253 .u64, .i64, .big_int => {},
8254 .lazy_align, .lazy_size => |lazy_ty| {
8255 items.appendAssumeCapacity(.{
8256 .tag = switch (int.storage) {
8257 else => unreachable,
8258 .lazy_align => .int_lazy_align,
8259 .lazy_size => .int_lazy_size,
8260 },
8261 .data = try addExtra(extra, IntLazy{
8262 .ty = int.ty,
8263 .lazy_ty = lazy_ty,
8264 }),
8265 });
8266 return gop.put();
8267 },
8268 }
8269 switch (int.ty) {7599 switch (int.ty) {
8270 .u8_type => switch (int.storage) {7600 .u8_type => switch (int.storage) {
8271 .big_int => |big_int| {7601 .big_int => |big_int| {
...@@ -8282,7 +7612,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8282,7 +7612,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8282 });7612 });
8283 break :b;7613 break :b;
8284 },7614 },
8285 .lazy_align, .lazy_size => unreachable,
8286 },7615 },
8287 .u16_type => switch (int.storage) {7616 .u16_type => switch (int.storage) {
8288 .big_int => |big_int| {7617 .big_int => |big_int| {
...@@ -8299,7 +7628,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8299,7 +7628,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8299 });7628 });
8300 break :b;7629 break :b;
8301 },7630 },
8302 .lazy_align, .lazy_size => unreachable,
8303 },7631 },
8304 .u32_type => switch (int.storage) {7632 .u32_type => switch (int.storage) {
8305 .big_int => |big_int| {7633 .big_int => |big_int| {
...@@ -8316,7 +7644,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8316,7 +7644,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8316 });7644 });
8317 break :b;7645 break :b;
8318 },7646 },
8319 .lazy_align, .lazy_size => unreachable,
8320 },7647 },
8321 .i32_type => switch (int.storage) {7648 .i32_type => switch (int.storage) {
8322 .big_int => |big_int| {7649 .big_int => |big_int| {
...@@ -8334,7 +7661,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8334,7 +7661,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8334 });7661 });
8335 break :b;7662 break :b;
8336 },7663 },
8337 .lazy_align, .lazy_size => unreachable,
8338 },7664 },
8339 .usize_type => switch (int.storage) {7665 .usize_type => switch (int.storage) {
8340 .big_int => |big_int| {7666 .big_int => |big_int| {
...@@ -8355,7 +7681,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8355,7 +7681,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8355 break :b;7681 break :b;
8356 }7682 }
8357 },7683 },
8358 .lazy_align, .lazy_size => unreachable,
8359 },7684 },
8360 .comptime_int_type => switch (int.storage) {7685 .comptime_int_type => switch (int.storage) {
8361 .big_int => |big_int| {7686 .big_int => |big_int| {
...@@ -8390,7 +7715,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8390,7 +7715,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8390 break :b;7715 break :b;
8391 }7716 }
8392 },7717 },
8393 .lazy_align, .lazy_size => unreachable,
8394 },7718 },
8395 else => {},7719 else => {},
8396 }7720 }
...@@ -8427,7 +7751,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8427,7 +7751,6 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8427 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;7751 const tag: Tag = if (big_int.positive) .int_positive else .int_negative;
8428 try addInt(ip, gpa, io, tid, int.ty, tag, big_int.limbs);7752 try addInt(ip, gpa, io, tid, int.ty, tag, big_int.limbs);
8429 },7753 },
8430 .lazy_align, .lazy_size => unreachable,
8431 }7754 }
8432 },7755 },
84337756
...@@ -8468,7 +7791,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8468,7 +7791,7 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8468 assert(ip.isEnumType(enum_tag.ty));7791 assert(ip.isEnumType(enum_tag.ty));
8469 switch (ip.indexToKey(enum_tag.ty)) {7792 switch (ip.indexToKey(enum_tag.ty)) {
8470 .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),7793 .simple_type => assert(ip.isIntegerType(ip.typeOf(enum_tag.int))),
8471 .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).tag_ty),7794 .enum_type => assert(ip.typeOf(enum_tag.int) == ip.loadEnumType(enum_tag.ty).int_tag_type),
8472 else => unreachable,7795 else => unreachable,
8473 }7796 }
8474 items.appendAssumeCapacity(.{7797 items.appendAssumeCapacity(.{
...@@ -8735,465 +8058,637 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:...@@ -8735,465 +8058,637 @@ pub fn get(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, key:
8735 return gop.put();8058 return gop.put();
8736}8059}
87378060
8738pub fn getUnion(8061pub fn getStructType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8739 ip: *InternPool,
8740 gpa: Allocator,
8741 io: Io,
8742 tid: Zcu.PerThread.Id,
8743 un: Key.Union,
8744) Allocator.Error!Index {
8745 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
8746 defer gop.deinit();
8747 if (gop == .existing) return gop.existing;
8748 const local = ip.getLocal(tid);
8749 const items = local.getMutableItems(gpa, io);
8750 const extra = local.getMutableExtra(gpa, io);
8751 try items.ensureUnusedCapacity(1);
8752
8753 assert(un.ty != .none);
8754 assert(un.val != .none);
8755 items.appendAssumeCapacity(.{
8756 .tag = .union_value,
8757 .data = try addExtra(extra, un),
8758 });
8759
8760 return gop.put();
8761}
8762
8763pub const UnionTypeInit = struct {
8764 flags: packed struct {
8765 runtime_tag: LoadedUnionType.RuntimeTag,
8766 any_aligned_fields: bool,
8767 layout: std.builtin.Type.ContainerLayout,
8768 status: LoadedUnionType.Status,
8769 requires_comptime: RequiresComptime,
8770 assumed_runtime_bits: bool,
8771 assumed_pointer_aligned: bool,
8772 alignment: Alignment,
8773 },
8774 fields_len: u32,8062 fields_len: u32,
8775 enum_tag_ty: Index,8063 layout: std.builtin.Type.ContainerLayout,
8776 /// May have length 0 which leaves the values unset until later.8064 /// The following only applies if `layout == .@"packed"`; this field is ignored otherwise.
8777 field_types: []const Index,8065 ///
8778 /// May have length 0 which leaves the values unset until later.8066 /// The explicitly specified backing integer type. `.none` means the backing integer is inferred
8779 /// The logic for `any_aligned_fields` is asserted to have been done before8067 /// by the compiler. Asserts that this is an integer type.
8780 /// calling this function.8068 explicit_packed_backing_type: Index,
8781 field_aligns: []const Alignment,8069 any_comptime_fields: bool,
8070 any_field_defaults: bool,
8071 any_field_aligns: bool,
8782 key: union(enum) {8072 key: union(enum) {
8783 declared: struct {8073 declared: struct {
8784 zir_index: TrackedInst.Index,8074 zir_index: TrackedInst.Index,
8785 captures: []const CaptureValue,8075 captures: []const CaptureValue,
8786 },8076 },
8787 declared_owned_captures: struct {
8788 zir_index: TrackedInst.Index,
8789 captures: CaptureValue.Slice,
8790 },
8791 reified: struct {8077 reified: struct {
8792 zir_index: TrackedInst.Index,8078 zir_index: TrackedInst.Index,
8793 type_hash: u64,8079 type_hash: u64,
8794 },8080 },
8795 },8081 },
8796};8082}) Allocator.Error!WipContainerType.Result {
87978083 const key: Key = .{ .struct_type = switch (ini.key) {
8798pub fn getUnionType(
8799 ip: *InternPool,
8800 gpa: Allocator,
8801 io: Io,
8802 tid: Zcu.PerThread.Id,
8803 ini: UnionTypeInit,
8804 /// If it is known that there is an existing type with this key which is outdated,
8805 /// this is passed as `true`, and the type is replaced with one at a fresh index.
8806 replace_existing: bool,
8807) Allocator.Error!WipNamespaceType.Result {
8808 const key: Key = .{ .union_type = switch (ini.key) {
8809 .declared => |d| .{ .declared = .{8084 .declared => |d| .{ .declared = .{
8810 .zir_index = d.zir_index,8085 .zir_index = d.zir_index,
8086 .arg_ty = switch (ini.layout) {
8087 .auto, .@"extern" => .none,
8088 .@"packed" => ini.explicit_packed_backing_type,
8089 },
8811 .captures = .{ .external = d.captures },8090 .captures = .{ .external = d.captures },
8812 } },8091 } },
8813 .declared_owned_captures => |d| .{ .declared = .{
8814 .zir_index = d.zir_index,
8815 .captures = .{ .owned = d.captures },
8816 } },
8817 .reified => |r| .{ .reified = .{8092 .reified => |r| .{ .reified = .{
8818 .zir_index = r.zir_index,8093 .zir_index = r.zir_index,
8819 .type_hash = r.type_hash,8094 .type_hash = r.type_hash,
8820 } },8095 } },
8821 } };8096 } };
8822 var gop = if (replace_existing)8097 var gop = try ip.getOrPutKey(gpa, io, tid, key);
8823 ip.putKeyReplace(io, tid, key)
8824 else
8825 try ip.getOrPutKey(gpa, io, tid, key);
8826 defer gop.deinit();8098 defer gop.deinit();
8827 if (gop == .existing) return .{ .existing = gop.existing };8099 if (gop == .existing) return .{ .existing = gop.existing };
88288100
8829 const local = ip.getLocal(tid);8101 const local = ip.getLocal(tid);
8830 const items = local.getMutableItems(gpa, io);8102 const items = local.getMutableItems(gpa, io);
8831 try items.ensureUnusedCapacity(1);
8832 const extra = local.getMutableExtra(gpa, io);8103 const extra = local.getMutableExtra(gpa, io);
8104 try items.ensureUnusedCapacity(1);
88338105
8834 const align_elements_len = if (ini.flags.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;8106 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
8835 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);8107 errdefer local.mutate.maps.len -= 1;
8836 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
8837 // TODO: fmt bug
8838 // zig fmt: off
8839 switch (ini.key) {
8840 inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
8841 .reified => 2, // type_hash: PackedU64
8842 } +
8843 // zig fmt: on
8844 ini.fields_len + // field types
8845 align_elements_len);
88468108
8847 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{8109 const zir_index, const type_hash_captures_extra_len = switch (ini.key) {
8848 .flags = .{8110 .declared => |d| .{ d.zir_index, d.captures.len + @intFromBool(ini.layout != .@"packed") },
8849 .any_captures = switch (ini.key) {8111 .reified => |r| .{ r.zir_index, 2 },
8850 inline .declared, .declared_owned_captures => |d| d.captures.len != 0,8112 };
8851 .reified => false,8113
8852 },8114 const is_extern = switch (ini.layout) {
8853 .runtime_tag = ini.flags.runtime_tag,8115 .auto => false,
8854 .any_aligned_fields = ini.flags.any_aligned_fields,8116 .@"extern" => true,
8855 .layout = ini.flags.layout,8117 .@"packed" => {
8856 .status = ini.flags.status,8118 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +
8857 .requires_comptime = ini.flags.requires_comptime,8119 type_hash_captures_extra_len +
8858 .assumed_runtime_bits = ini.flags.assumed_runtime_bits,8120 ini.fields_len + // field_name
8859 .assumed_pointer_aligned = ini.flags.assumed_pointer_aligned,8121 ini.fields_len + // field_type
8860 .alignment = ini.flags.alignment,8122 (if (ini.any_field_defaults) ini.fields_len else 0)); // field_default
8861 .is_reified = switch (ini.key) {8123
8862 .declared, .declared_owned_captures => false,8124 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
8863 .reified => true,8125 .zir_index = zir_index,
8864 },8126 .captures_len = switch (ini.key) {
8127 .declared => |d| @enumFromInt(d.captures.len),
8128 .reified => .reified,
8129 },
8130 .name = undefined, // set by `finish`
8131 .name_nav = undefined, // set by `finish`
8132 .namespace = undefined, // set by `finish`
8133 .backing_int_type = ini.explicit_packed_backing_type,
8134 .fields_len = ini.fields_len,
8135 .field_name_map = field_name_map,
8136 });
8137 switch (ini.key) {
8138 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
8139 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8140 }
8141 const field_names_start = extra.mutate.len;
8142 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8143 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8144 if (ini.any_field_defaults) {
8145 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
8146 }
8147 items.appendAssumeCapacity(.{
8148 .tag = switch (ini.explicit_packed_backing_type) {
8149 .none => if (ini.any_field_defaults) .type_struct_packed_auto_defaults else .type_struct_packed_auto,
8150 else => if (ini.any_field_defaults) .type_struct_packed_explicit_defaults else .type_struct_packed_explicit,
8151 },
8152 .data = extra_index,
8153 });
8154 return .{ .wip = .{
8155 .index = gop.put(),
8156 .tid = tid,
8157 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
8158 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
8159 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
8160 .tag_type_index = null,
8161 .fields_len = ini.fields_len,
8162 .field_name_map = field_name_map,
8163 .field_names_start = field_names_start,
8164 .field_comptime_bits_start = null,
8165 } };
8865 },8166 },
8866 .fields_len = ini.fields_len,8167 };
8867 .size = std.math.maxInt(u32),8168
8868 .padding = std.math.maxInt(u32),8169 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +
8170 type_hash_captures_extra_len +
8171 ini.fields_len + // field_name
8172 ini.fields_len + // field_type
8173 (if (ini.any_field_defaults) ini.fields_len else 0) + // field_default
8174 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0) + // field_align
8175 (if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0) + // field_is_comptime_bits
8176 (if (!is_extern) ini.fields_len else 0) + // field_runtime_order
8177 ini.fields_len); // field_offset
8178
8179 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
8180 .zir_index = zir_index,
8869 .name = undefined, // set by `finish`8181 .name = undefined, // set by `finish`
8870 .name_nav = undefined, // set by `finish`8182 .name_nav = undefined, // set by `finish`
8871 .namespace = undefined, // set by `finish`8183 .namespace = undefined, // set by `finish`
8872 .tag_ty = ini.enum_tag_ty,8184 .fields_len = ini.fields_len,
8873 .zir_index = switch (ini.key) {8185 .field_name_map = field_name_map,
8874 inline else => |x| x.zir_index,8186 .size = 0,
8187 .flags = .{
8188 .any_captures = switch (ini.key) {
8189 .declared => |d| if (d.captures.len != 0) .true else .false,
8190 .reified => .reified,
8191 },
8192 .layout = if (is_extern) .@"extern" else .auto,
8193 .any_comptime_fields = ini.any_comptime_fields,
8194 .any_field_defaults = ini.any_field_defaults,
8195 .any_field_aligns = ini.any_field_aligns,
8196 .has_one_possible_value = false,
8197 .has_no_possible_value = false,
8198 .comptime_only = false,
8199 .alignment = .none,
8875 },8200 },
8876 });8201 });
8877
8878 items.appendAssumeCapacity(.{
8879 .tag = .type_union,
8880 .data = extra_index,
8881 });
8882
8883 switch (ini.key) {8202 switch (ini.key) {
8884 .declared => |d| if (d.captures.len != 0) {8203 .declared => |d| if (d.captures.len != 0) {
8885 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8204 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8886 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8205 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
8887 },8206 },
8888 .declared_owned_captures => |d| if (d.captures.len != 0) {
8889 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
8890 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
8891 },
8892 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),8207 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
8893 }8208 }
88948209 const field_names_start = extra.mutate.len;
8895 // field types8210 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8896 if (ini.field_types.len > 0) {8211 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
8897 assert(ini.field_types.len == ini.fields_len);8212 if (ini.any_field_defaults) {
8898 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.field_types)});8213 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_default
8899 } else {
8900 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
8901 }8214 }
89028215 if (ini.any_field_aligns) {
8903 // field alignments8216 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
8904 if (ini.flags.any_aligned_fields) {
8905 extra.appendNTimesAssumeCapacity(.{align_element}, align_elements_len);
8906 if (ini.field_aligns.len > 0) {
8907 assert(ini.field_aligns.len == ini.fields_len);
8908 @memcpy((Alignment.Slice{
8909 .tid = tid,
8910 .start = @intCast(extra.mutate.len - align_elements_len),
8911 .len = @intCast(ini.field_aligns.len),
8912 }).get(ip), ini.field_aligns);
8913 }
8914 } else {
8915 assert(ini.field_aligns.len == 0);
8916 }8217 }
89178218 const field_comptime_bits_start: ?u32 = if (ini.any_comptime_fields) start: {
8219 const start = extra.mutate.len;
8220 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 31) / 32); // field_is_comptime_bits
8221 break :start start;
8222 } else null;
8223 if (!is_extern) {
8224 extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len); // field_runtime_order
8225 }
8226 extra.appendNTimesAssumeCapacity(.{0}, ini.fields_len); // field_offset
8227 items.appendAssumeCapacity(.{
8228 .tag = .type_struct,
8229 .data = extra_index,
8230 });
8918 return .{ .wip = .{8231 return .{ .wip = .{
8919 .tid = tid,
8920 .index = gop.put(),8232 .index = gop.put(),
8921 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,8233 .tid = tid,
8922 .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,8234 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,
8923 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,8235 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,
8236 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,
8237 .tag_type_index = null,
8238 .fields_len = ini.fields_len,
8239 .field_name_map = field_name_map,
8240 .field_names_start = field_names_start,
8241 .field_comptime_bits_start = field_comptime_bits_start,
8924 } };8242 } };
8925}8243}
89268244
8927pub const WipNamespaceType = struct {8245pub fn getUnionType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8928 tid: Zcu.PerThread.Id,
8929 index: Index,
8930 type_name_extra_index: u32,
8931 namespace_extra_index: u32,
8932 name_nav_extra_index: u32,
8933
8934 pub fn setName(
8935 wip: WipNamespaceType,
8936 ip: *InternPool,
8937 type_name: NullTerminatedString,
8938 /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
8939 /// This is also `.none` if we use `.parent` because we are the root struct type for a file.
8940 name_nav: Nav.Index.Optional,
8941 ) void {
8942 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8943 const extra_items = extra.view().items(.@"0");
8944 extra_items[wip.type_name_extra_index] = @intFromEnum(type_name);
8945 extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav);
8946 }
8947
8948 pub fn finish(
8949 wip: WipNamespaceType,
8950 ip: *InternPool,
8951 namespace: NamespaceIndex,
8952 ) Index {
8953 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8954 const extra_items = extra.view().items(.@"0");
8955
8956 extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
8957
8958 return wip.index;
8959 }
8960
8961 pub fn cancel(wip: WipNamespaceType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
8962 ip.remove(tid, wip.index);
8963 }
8964
8965 pub const Result = union(enum) {
8966 wip: WipNamespaceType,
8967 existing: Index,
8968 };
8969};
8970
8971pub const StructTypeInit = struct {
8972 layout: std.builtin.Type.ContainerLayout,
8973 fields_len: u32,8246 fields_len: u32,
8974 known_non_opv: bool,8247 layout: std.builtin.Type.ContainerLayout,
8975 requires_comptime: RequiresComptime,8248 /// The explicitly specified backing integer type for a `packed union`.
8976 any_comptime_fields: bool,8249 /// `.none` means the backing integer is inferred by the compiler. If set,
8977 any_default_inits: bool,8250 /// must be an integer type. If the union is not packed, must be `.none`.
8978 inits_resolved: bool,8251 explicit_packed_backing_type: Index,
8979 any_aligned_fields: bool,8252 runtime_tag: LoadedUnionType.RuntimeTag,
8253 /// `true` for `union(T)`, but `false` for anything else, including `union(enum(T))`.
8254 have_explicit_enum_tag: bool,
8255 any_field_aligns: bool,
8980 key: union(enum) {8256 key: union(enum) {
8981 declared: struct {8257 declared: struct {
8982 zir_index: TrackedInst.Index,8258 zir_index: TrackedInst.Index,
8983 captures: []const CaptureValue,8259 captures: []const CaptureValue,
8984 },8260 /// This is the `T` in one of the following:
8985 declared_owned_captures: struct {8261 /// * `union(T)` (enum tag type)
8986 zir_index: TrackedInst.Index,8262 /// * `union(enum(T))` (int tag type)
8987 captures: CaptureValue.Slice,8263 /// * `packed union(T)` (int backing type)
8264 /// Or `.none` otherwise.
8265 arg_ty: InternPool.Index,
8988 },8266 },
8989 reified: struct {8267 reified: struct {
8990 zir_index: TrackedInst.Index,8268 zir_index: TrackedInst.Index,
8991 type_hash: u64,8269 type_hash: u64,
8992 },8270 },
8993 },8271 },
8994};8272}) Allocator.Error!WipContainerType.Result {
89958273 if (ini.explicit_packed_backing_type != .none) {
8996pub fn getStructType(8274 assert(ip.zigTypeTag(ini.explicit_packed_backing_type) == .int);
8997 ip: *InternPool,8275 if (ini.key == .declared) assert(ini.key.declared.arg_ty == ini.explicit_packed_backing_type);
8998 gpa: Allocator,8276 }
8999 io: Io,8277 const key: Key = .{ .union_type = switch (ini.key) {
9000 tid: Zcu.PerThread.Id,
9001 ini: StructTypeInit,
9002 /// If it is known that there is an existing type with this key which is outdated,
9003 /// this is passed as `true`, and the type is replaced with one at a fresh index.
9004 replace_existing: bool,
9005) Allocator.Error!WipNamespaceType.Result {
9006 const key: Key = .{ .struct_type = switch (ini.key) {
9007 .declared => |d| .{ .declared = .{8278 .declared => |d| .{ .declared = .{
9008 .zir_index = d.zir_index,8279 .zir_index = d.zir_index,
8280 .arg_ty = d.arg_ty,
9009 .captures = .{ .external = d.captures },8281 .captures = .{ .external = d.captures },
9010 } },8282 } },
9011 .declared_owned_captures => |d| .{ .declared = .{
9012 .zir_index = d.zir_index,
9013 .captures = .{ .owned = d.captures },
9014 } },
9015 .reified => |r| .{ .reified = .{8283 .reified => |r| .{ .reified = .{
9016 .zir_index = r.zir_index,8284 .zir_index = r.zir_index,
9017 .type_hash = r.type_hash,8285 .type_hash = r.type_hash,
9018 } },8286 } },
9019 } };8287 } };
9020 var gop = if (replace_existing)8288 var gop = try ip.getOrPutKey(gpa, io, tid, key);
9021 ip.putKeyReplace(io, tid, key)
9022 else
9023 try ip.getOrPutKey(gpa, io, tid, key);
9024 defer gop.deinit();8289 defer gop.deinit();
9025 if (gop == .existing) return .{ .existing = gop.existing };8290 if (gop == .existing) return .{ .existing = gop.existing };
90268291
9027 const local = ip.getLocal(tid);8292 const local = ip.getLocal(tid);
9028 const items = local.getMutableItems(gpa, io);8293 const items = local.getMutableItems(gpa, io);
9029 const extra = local.getMutableExtra(gpa, io);8294 const extra = local.getMutableExtra(gpa, io);
8295 try items.ensureUnusedCapacity(1);
90308296
9031 const names_map = try ip.addMap(gpa, io, tid, ini.fields_len);8297 const zir_index, const type_hash_captures_extra_len = switch (ini.key) {
9032 errdefer local.mutate.maps.len -= 1;8298 .declared => |d| .{ d.zir_index, d.captures.len + @intFromBool(ini.layout != .@"packed") },
90338299 .reified => |r| .{ r.zir_index, 2 },
9034 const zir_index = switch (ini.key) {
9035 inline else => |x| x.zir_index,
9036 };8300 };
90378301
9038 const is_extern = switch (ini.layout) {8302 const is_extern = switch (ini.layout) {
9039 .auto => false,8303 .auto => false,
9040 .@"extern" => true,8304 .@"extern" => true,
9041 .@"packed" => {8305 .@"packed" => {
9042 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +8306 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnionPacked).@"struct".fields.len +
9043 // TODO: fmt bug8307 type_hash_captures_extra_len +
9044 // zig fmt: off8308 ini.fields_len); // field_type
9045 switch (ini.key) {8309
9046 inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,8310 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnionPacked{
9047 .reified => 2, // type_hash: PackedU648311 .zir_index = zir_index,
9048 } +8312 .captures_len = switch (ini.key) {
9049 // zig fmt: on8313 .declared => |d| @enumFromInt(d.captures.len),
9050 ini.fields_len + // types8314 .reified => .reified,
9051 ini.fields_len + // names8315 },
9052 ini.fields_len); // inits
9053 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStructPacked{
9054 .name = undefined, // set by `finish`8316 .name = undefined, // set by `finish`
9055 .name_nav = undefined, // set by `finish`8317 .name_nav = undefined, // set by `finish`
9056 .zir_index = zir_index,
9057 .fields_len = ini.fields_len,
9058 .namespace = undefined, // set by `finish`8318 .namespace = undefined, // set by `finish`
9059 .backing_int_ty = .none,8319 .backing_int_type = ini.explicit_packed_backing_type,
9060 .names_map = names_map,8320 .enum_tag_type = .none, // set by `setTagType`
9061 .flags = .{8321 .fields_len = ini.fields_len,
9062 .any_captures = switch (ini.key) {
9063 inline .declared, .declared_owned_captures => |d| d.captures.len != 0,
9064 .reified => false,
9065 },
9066 .field_inits_wip = false,
9067 .inits_resolved = ini.inits_resolved,
9068 .is_reified = switch (ini.key) {
9069 .declared, .declared_owned_captures => false,
9070 .reified => true,
9071 },
9072 },
9073 });
9074 try items.append(.{
9075 .tag = if (ini.any_default_inits) .type_struct_packed_inits else .type_struct_packed,
9076 .data = extra_index,
9077 });8322 });
9078 switch (ini.key) {8323 switch (ini.key) {
9079 .declared => |d| if (d.captures.len != 0) {8324 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
9080 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8325 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
9081 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8326 }
9082 },8327 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
9083 .declared_owned_captures => |d| if (d.captures.len != 0) {8328 items.appendAssumeCapacity(.{
9084 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8329 .tag = switch (ini.explicit_packed_backing_type) {
9085 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});8330 .none => .type_union_packed_auto,
8331 else => .type_union_packed_explicit,
9086 },8332 },
9087 .reified => |r| {8333 .data = extra_index,
9088 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));8334 });
8335 return .{
8336 .wip = .{
8337 .index = gop.put(),
8338 .tid = tid,
8339 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name").?,
8340 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "name_nav").?,
8341 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "namespace").?,
8342 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnionPacked, "enum_tag_type").?,
8343 .fields_len = 0, // the fields come from the enum, so nothing to set
8344 .field_name_map = undefined,
8345 .field_names_start = undefined,
8346 .field_comptime_bits_start = undefined,
9089 },8347 },
9090 }8348 };
9091 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
9092 extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len);
9093 if (ini.any_default_inits) {
9094 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
9095 }
9096 return .{ .wip = .{
9097 .tid = tid,
9098 .index = gop.put(),
9099 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name").?,
9100 .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "name_nav").?,
9101 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStructPacked, "namespace").?,
9102 } };
9103 },8349 },
9104 };8350 };
91058351
9106 const align_elements_len = if (ini.any_aligned_fields) (ini.fields_len + 3) / 4 else 0;8352 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeUnion).@"struct".fields.len +
9107 const align_element: u32 = @bitCast([1]u8{@intFromEnum(Alignment.none)} ** 4);8353 type_hash_captures_extra_len +
9108 const comptime_elements_len = if (ini.any_comptime_fields) (ini.fields_len + 31) / 32 else 0;8354 ini.fields_len + // field_type
8355 (if (ini.any_field_aligns) (ini.fields_len + 3) / 4 else 0)); // field_align
91098356
9110 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeStruct).@"struct".fields.len +8357 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeUnion{
9111 // TODO: fmt bug8358 .zir_index = zir_index,
9112 // zig fmt: off
9113 switch (ini.key) {
9114 inline .declared, .declared_owned_captures => |d| @intFromBool(d.captures.len != 0) + d.captures.len,
9115 .reified => 2, // type_hash: PackedU64
9116 } +
9117 // zig fmt: on
9118 (ini.fields_len * 5) + // types, names, inits, runtime order, offsets
9119 align_elements_len + comptime_elements_len +
9120 1); // names_map
9121 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeStruct{
9122 .name = undefined, // set by `finish`8359 .name = undefined, // set by `finish`
9123 .name_nav = undefined, // set by `finish`8360 .name_nav = undefined, // set by `finish`
9124 .zir_index = zir_index,
9125 .namespace = undefined, // set by `finish`8361 .namespace = undefined, // set by `finish`
8362 .enum_tag_type = .none, // set by `setTagType`
9126 .fields_len = ini.fields_len,8363 .fields_len = ini.fields_len,
9127 .size = std.math.maxInt(u32),8364 .size = 0,
8365 .padding = 0,
9128 .flags = .{8366 .flags = .{
9129 .any_captures = switch (ini.key) {8367 .any_captures = switch (ini.key) {
9130 inline .declared, .declared_owned_captures => |d| d.captures.len != 0,8368 .declared => |d| if (d.captures.len != 0) .true else .false,
9131 .reified => false,8369 .reified => .reified,
9132 },8370 },
9133 .is_extern = is_extern,8371 .explicit_tag_type = ini.have_explicit_enum_tag,
9134 .known_non_opv = ini.known_non_opv,8372 .layout = if (is_extern) .@"extern" else .auto,
9135 .requires_comptime = ini.requires_comptime,8373 .any_field_aligns = ini.any_field_aligns,
9136 .assumed_runtime_bits = false,8374 .runtime_tag = ini.runtime_tag,
9137 .assumed_pointer_aligned = false,8375 .has_one_possible_value = false,
9138 .any_comptime_fields = ini.any_comptime_fields,8376 .has_no_possible_value = false,
9139 .any_default_inits = ini.any_default_inits,8377 .comptime_only = false,
9140 .any_aligned_fields = ini.any_aligned_fields,
9141 .alignment = .none,8378 .alignment = .none,
9142 .alignment_wip = false,
9143 .field_types_wip = false,
9144 .layout_wip = false,
9145 .layout_resolved = false,
9146 .field_inits_wip = false,
9147 .inits_resolved = ini.inits_resolved,
9148 .fully_resolved = false,
9149 .is_reified = switch (ini.key) {
9150 .declared, .declared_owned_captures => false,
9151 .reified => true,
9152 },
9153 },8379 },
9154 });8380 });
9155 try items.append(.{
9156 .tag = .type_struct,
9157 .data = extra_index,
9158 });
9159 switch (ini.key) {8381 switch (ini.key) {
9160 .declared => |d| if (d.captures.len != 0) {8382 .declared => |d| if (d.captures.len != 0) {
9161 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});8383 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
9162 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});8384 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)});
9163 },8385 },
9164 .declared_owned_captures => |d| if (d.captures.len != 0) {8386 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
9165 extra.appendAssumeCapacity(.{@intCast(d.captures.len)});
9166 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))});
9167 },
9168 .reified => |r| {
9169 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash));
9170 },
9171 }
9172 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
9173 extra.appendAssumeCapacity(.{@intFromEnum(names_map)});
9174 extra.appendNTimesAssumeCapacity(.{@intFromEnum(OptionalNullTerminatedString.none)}, ini.fields_len);
9175 if (ini.any_default_inits) {
9176 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len);
9177 }8387 }
9178 if (ini.any_aligned_fields) {8388 extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_type
9179 extra.appendNTimesAssumeCapacity(.{align_element}, align_elements_len);8389 if (ini.any_field_aligns) {
8390 extra.appendNTimesAssumeCapacity(.{0}, (ini.fields_len + 3) / 4); // field_align
9180 }8391 }
9181 if (ini.any_comptime_fields) {8392 items.appendAssumeCapacity(.{
9182 extra.appendNTimesAssumeCapacity(.{0}, comptime_elements_len);8393 .tag = .type_union,
9183 }8394 .data = extra_index,
9184 if (ini.layout == .auto) {8395 });
9185 extra.appendNTimesAssumeCapacity(.{@intFromEnum(LoadedStructType.RuntimeOrder.unresolved)}, ini.fields_len);8396 return .{
8397 .wip = .{
8398 .index = gop.put(),
8399 .tid = tid,
8400 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name").?,
8401 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "name_nav").?,
8402 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "namespace").?,
8403 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeUnion, "enum_tag_type").?,
8404 .fields_len = 0, // the fields come from the enum, so nothing to set
8405 .field_name_map = undefined,
8406 .field_names_start = undefined,
8407 .field_comptime_bits_start = undefined,
8408 },
8409 };
8410}
8411
8412pub fn getEnumType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8413 fields_len: u32,
8414 /// For `enum(T)` or `union(enum(T))`, this is `T`. Asserts `T` is an integer type.
8415 /// Otherwise, `.none`.
8416 explicit_int_tag_type: Index,
8417 nonexhaustive: bool,
8418 key: union(enum) {
8419 declared: struct {
8420 zir_index: TrackedInst.Index,
8421 captures: []const CaptureValue,
8422 },
8423 reified: struct {
8424 zir_index: TrackedInst.Index,
8425 type_hash: u64,
8426 },
8427 generated_union_tag: Index,
8428 },
8429}) Allocator.Error!WipContainerType.Result {
8430 const key: Key = .{ .enum_type = switch (ini.key) {
8431 .declared => |d| .{ .declared = .{
8432 .zir_index = d.zir_index,
8433 .arg_ty = ini.explicit_int_tag_type,
8434 .captures = .{ .external = d.captures },
8435 } },
8436 .reified => |r| .{ .reified = .{
8437 .zir_index = r.zir_index,
8438 .type_hash = r.type_hash,
8439 } },
8440 .generated_union_tag => |u| .{ .generated_union_tag = u },
8441 } };
8442 var gop = try ip.getOrPutKey(gpa, io, tid, key);
8443 defer gop.deinit();
8444 if (gop == .existing) return .{ .existing = gop.existing };
8445
8446 const local = ip.getLocal(tid);
8447 const items = local.getMutableItems(gpa, io);
8448 const extra = local.getMutableExtra(gpa, io);
8449 try items.ensureUnusedCapacity(1);
8450
8451 const tag: Tag, const have_values: bool = if (ini.nonexhaustive)
8452 .{ .type_enum_nonexhaustive, true }
8453 else if (ini.explicit_int_tag_type != .none)
8454 .{ .type_enum_explicit, true }
8455 else
8456 .{ .type_enum_auto, false };
8457
8458 const field_name_map = try ip.addMap(gpa, io, tid, ini.fields_len);
8459 errdefer local.mutate.maps.len -= 1;
8460
8461 const field_value_map = if (have_values) try ip.addMap(gpa, io, tid, ini.fields_len) else undefined;
8462 errdefer local.mutate.maps.len -= @intFromBool(have_values);
8463
8464 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeEnum).@"struct".fields.len +
8465 switch (ini.key) {
8466 .declared => |d| 1 + d.captures.len, // `zir_index` and `capture`
8467 .reified => 3, // `zir_index` and `type_hash`
8468 .generated_union_tag => 1, // owner_union
8469 } +
8470 @intFromBool(have_values) + // field_value_map
8471 ini.fields_len + // field_name
8472 (if (have_values) ini.fields_len else 0)); // field_value
8473
8474 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeEnum{
8475 .captures_len = switch (ini.key) {
8476 .declared => |d| @enumFromInt(d.captures.len),
8477 .reified => .reified,
8478 .generated_union_tag => .generated_union_tag,
8479 },
8480 .name = undefined, // set by `finish`
8481 .name_nav = undefined, // set by `finish`
8482 .namespace = undefined, // set by `finish`
8483 .int_tag_type = ini.explicit_int_tag_type,
8484 .fields_len = ini.fields_len,
8485 .field_name_map = field_name_map,
8486 });
8487 switch (ini.key) {
8488 .declared => |d| {
8489 extra.appendAssumeCapacity(.{@intFromEnum(d.zir_index)}); // zir_index
8490 extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}); // capture
8491 },
8492 .reified => |r| {
8493 extra.appendAssumeCapacity(.{@intFromEnum(r.zir_index)}); // zir_index
8494 _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)); // type_hash
8495 },
8496 .generated_union_tag => |owner_union| {
8497 extra.appendAssumeCapacity(.{@intFromEnum(owner_union)}); // owner_union
8498 },
9186 }8499 }
9187 extra.appendNTimesAssumeCapacity(.{std.math.maxInt(u32)}, ini.fields_len);8500 if (have_values) extra.appendAssumeCapacity(.{@intFromEnum(field_value_map)});
8501 const field_names_start = extra.mutate.len;
8502 extra.appendNTimesAssumeCapacity(.{@intFromEnum(NullTerminatedString.empty)}, ini.fields_len); // field_name
8503 if (have_values) extra.appendNTimesAssumeCapacity(.{@intFromEnum(Index.none)}, ini.fields_len); // field_value
8504 items.appendAssumeCapacity(.{
8505 .tag = tag,
8506 .data = extra_index,
8507 });
9188 return .{ .wip = .{8508 return .{ .wip = .{
8509 .index = gop.put(),
9189 .tid = tid,8510 .tid = tid,
8511 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name").?,
8512 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "name_nav").?,
8513 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "namespace").?,
8514 .tag_type_index = extra_index + std.meta.fieldIndex(Tag.TypeEnum, "int_tag_type").?,
8515 .fields_len = ini.fields_len,
8516 .field_name_map = field_name_map,
8517 .field_names_start = field_names_start,
8518 .field_comptime_bits_start = null,
8519 } };
8520}
8521
8522pub fn getOpaqueType(ip: *InternPool, gpa: Allocator, io: Io, tid: Zcu.PerThread.Id, ini: struct {
8523 zir_index: TrackedInst.Index,
8524 captures: []const CaptureValue,
8525}) Allocator.Error!WipContainerType.Result {
8526 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{
8527 .zir_index = ini.zir_index,
8528 .captures = .{ .external = ini.captures },
8529 .arg_ty = .none,
8530 } } });
8531 defer gop.deinit();
8532 if (gop == .existing) return .{ .existing = gop.existing };
8533
8534 const local = ip.getLocal(tid);
8535 const items = local.getMutableItems(gpa, io);
8536 const extra = local.getMutableExtra(gpa, io);
8537 try items.ensureUnusedCapacity(1);
8538
8539 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);
8540 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{
8541 .zir_index = ini.zir_index,
8542 .captures_len = @intCast(ini.captures.len),
8543 .name = undefined, // set by `finish`
8544 .name_nav = undefined, // set by `finish`
8545 .namespace = undefined, // set by `finish`
8546 });
8547 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)});
8548 items.appendAssumeCapacity(.{
8549 .tag = .type_opaque,
8550 .data = extra_index,
8551 });
8552 return .{ .wip = .{
9190 .index = gop.put(),8553 .index = gop.put(),
9191 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name").?,8554 .tid = tid,
9192 .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "name_nav").?,8555 .type_name_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
9193 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeStruct, "namespace").?,8556 .name_nav_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
8557 .namespace_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
8558 .tag_type_index = null,
8559 .fields_len = 0,
8560 .field_name_map = undefined,
8561 .field_names_start = undefined,
8562 .field_comptime_bits_start = undefined,
9194 } };8563 } };
9195}8564}
91968565
8566pub const WipContainerType = struct {
8567 index: Index,
8568 tid: Zcu.PerThread.Id,
8569 type_name_index: u32,
8570 name_nav_index: u32,
8571 namespace_index: u32,
8572
8573 tag_type_index: ?u32,
8574
8575 fields_len: u32,
8576 field_name_map: MapIndex,
8577 field_names_start: u32,
8578 field_comptime_bits_start: ?u32,
8579
8580 pub fn setName(
8581 wip: WipContainerType,
8582 ip: *InternPool,
8583 type_name: NullTerminatedString,
8584 /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
8585 /// This is also `.none` if we use `.parent` because we are the root struct type for a file.
8586 name_nav: Nav.Index.Optional,
8587 ) void {
8588 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8589 const extra_items = extra.view().items(.@"0");
8590 extra_items[wip.type_name_index] = @intFromEnum(type_name);
8591 extra_items[wip.name_nav_index] = @intFromEnum(name_nav);
8592 }
8593
8594 pub fn setTagType(
8595 wip: WipContainerType,
8596 ip: *InternPool,
8597 tag_ty: Index,
8598 ) void {
8599 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8600 const extra_items = extra.view().items(.@"0");
8601 const i = wip.tag_type_index.?;
8602 const old_val: InternPool.Index = @enumFromInt(extra_items[i]);
8603 assert(old_val == .none);
8604 assert(tag_ty != .none);
8605 extra_items[i] = @intFromEnum(tag_ty);
8606 }
8607
8608 /// Returns the already-existing field with the same name, if any.
8609 pub fn nextField(
8610 wip: WipContainerType,
8611 ip: *InternPool,
8612 name: NullTerminatedString,
8613 marked_comptime: bool,
8614 ) ?u32 {
8615 assert(wip.fields_len > 0);
8616 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8617 const extra_items = extra.view().items(.@"0");
8618 const map = wip.field_name_map.get(ip);
8619 const field_idx = map.count();
8620 assert(field_idx < wip.fields_len);
8621 const names: []NullTerminatedString = @ptrCast(extra_items[wip.field_names_start..][0..wip.fields_len]);
8622 const adapter: NullTerminatedString.Adapter = .{ .strings = names[0..field_idx] };
8623 const gop = map.getOrPutAssumeCapacityAdapted(name, adapter);
8624 if (gop.found_existing) return @intCast(gop.index);
8625 names[field_idx] = name;
8626 if (wip.field_comptime_bits_start) |start_idx| {
8627 if (marked_comptime) {
8628 extra_items[start_idx + field_idx / 32] |= @as(u32, 1) << @intCast(field_idx % 32);
8629 }
8630 } else {
8631 assert(!marked_comptime);
8632 }
8633 return null;
8634 }
8635
8636 pub fn finish(
8637 wip: WipContainerType,
8638 ip: *InternPool,
8639 namespace: NamespaceIndex,
8640 ) Index {
8641 const extra = ip.getLocalShared(wip.tid).extra.acquire();
8642 const extra_items = extra.view().items(.@"0");
8643
8644 extra_items[wip.namespace_index] = @intFromEnum(namespace);
8645
8646 if (wip.fields_len > 0) {
8647 assert(wip.field_name_map.get(ip).count() == wip.fields_len);
8648 }
8649 if (wip.tag_type_index) |i| {
8650 const tag_ty: Index = @enumFromInt(extra_items[i]);
8651 assert(tag_ty != .none);
8652 }
8653
8654 return wip.index;
8655 }
8656
8657 pub fn cancel(wip: WipContainerType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
8658 ip.remove(tid, wip.index);
8659 }
8660
8661 pub const Result = union(enum) {
8662 wip: WipContainerType,
8663 existing: Index,
8664 };
8665};
8666
8667pub fn getUnion(
8668 ip: *InternPool,
8669 gpa: Allocator,
8670 io: Io,
8671 tid: Zcu.PerThread.Id,
8672 un: Key.Union,
8673) Allocator.Error!Index {
8674 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .un = un });
8675 defer gop.deinit();
8676 if (gop == .existing) return gop.existing;
8677 const local = ip.getLocal(tid);
8678 const items = local.getMutableItems(gpa, io);
8679 const extra = local.getMutableExtra(gpa, io);
8680 try items.ensureUnusedCapacity(1);
8681
8682 assert(un.ty != .none);
8683 assert(un.val != .none);
8684 items.appendAssumeCapacity(.{
8685 .tag = .union_value,
8686 .data = try addExtra(extra, un),
8687 });
8688
8689 return gop.put();
8690}
8691
9197pub const TupleTypeInit = struct {8692pub const TupleTypeInit = struct {
9198 types: []const Index,8693 types: []const Index,
9199 /// These elements may be `none`, indicating runtime-known.8694 /// These elements may be `none`, indicating runtime-known.
...@@ -9252,10 +8747,7 @@ pub const GetFuncTypeKey = struct {...@@ -9252,10 +8747,7 @@ pub const GetFuncTypeKey = struct {
9252 /// `null` means generic.8747 /// `null` means generic.
9253 cc: ?std.builtin.CallingConvention = .auto,8748 cc: ?std.builtin.CallingConvention = .auto,
9254 is_var_args: bool = false,8749 is_var_args: bool = false,
9255 is_generic: bool = false,
9256 is_noinline: bool = false,8750 is_noinline: bool = false,
9257 section_is_generic: bool = false,
9258 addrspace_is_generic: bool = false,
9259};8751};
92608752
9261pub fn getFuncType(8753pub fn getFuncType(
...@@ -9293,7 +8785,6 @@ pub fn getFuncType(...@@ -9293,7 +8785,6 @@ pub fn getFuncType(
9293 .is_var_args = key.is_var_args,8785 .is_var_args = key.is_var_args,
9294 .has_comptime_bits = key.comptime_bits != 0,8786 .has_comptime_bits = key.comptime_bits != 0,
9295 .has_noalias_bits = key.noalias_bits != 0,8787 .has_noalias_bits = key.noalias_bits != 0,
9296 .is_generic = key.is_generic,
9297 .is_noinline = key.is_noinline,8788 .is_noinline = key.is_noinline,
9298 },8789 },
9299 });8790 });
...@@ -9480,7 +8971,6 @@ pub const GetFuncDeclIesKey = struct {...@@ -9480,7 +8971,6 @@ pub const GetFuncDeclIesKey = struct {
9480 /// null means generic.8971 /// null means generic.
9481 cc: ?std.builtin.CallingConvention,8972 cc: ?std.builtin.CallingConvention,
9482 is_var_args: bool,8973 is_var_args: bool,
9483 is_generic: bool,
9484 is_noinline: bool,8974 is_noinline: bool,
9485 zir_body_inst: TrackedInst.Index,8975 zir_body_inst: TrackedInst.Index,
9486 lbrace_line: u32,8976 lbrace_line: u32,
...@@ -9564,7 +9054,6 @@ pub fn getFuncDeclIes(...@@ -9564,7 +9054,6 @@ pub fn getFuncDeclIes(
9564 .is_var_args = key.is_var_args,9054 .is_var_args = key.is_var_args,
9565 .has_comptime_bits = key.comptime_bits != 0,9055 .has_comptime_bits = key.comptime_bits != 0,
9566 .has_noalias_bits = key.noalias_bits != 0,9056 .has_noalias_bits = key.noalias_bits != 0,
9567 .is_generic = key.is_generic,
9568 .is_noinline = key.is_noinline,9057 .is_noinline = key.is_noinline,
9569 },9058 },
9570 });9059 });
...@@ -9864,7 +9353,6 @@ fn getFuncInstanceIes(...@@ -9864,7 +9353,6 @@ fn getFuncInstanceIes(
9864 .is_var_args = false,9353 .is_var_args = false,
9865 .has_comptime_bits = false,9354 .has_comptime_bits = false,
9866 .has_noalias_bits = arg.noalias_bits != 0,9355 .has_noalias_bits = arg.noalias_bits != 0,
9867 .is_generic = false,
9868 .is_noinline = arg.is_noinline,9356 .is_noinline = arg.is_noinline,
9869 },9357 },
9870 });9358 });
...@@ -9876,538 +9364,100 @@ fn getFuncInstanceIes(...@@ -9876,538 +9364,100 @@ fn getFuncInstanceIes(
9876 .tag = &.{9364 .tag = &.{
9877 .func_instance,9365 .func_instance,
9878 .type_error_union,9366 .type_error_union,
9879 .type_inferred_error_set,9367 .type_inferred_error_set,
9880 .type_function,9368 .type_function,
9881 },
9882 .data = &.{
9883 func_extra_index,
9884 addExtraAssumeCapacity(extra, Tag.ErrorUnionType{
9885 .error_set_type = error_set_type,
9886 .payload_type = arg.bare_return_type,
9887 }),
9888 @intFromEnum(func_index),
9889 func_type_extra_index,
9890 },
9891 });
9892 errdefer {
9893 items.mutate.len -= 4;
9894 extra.mutate.len = prev_extra_len;
9895 }
9896
9897 var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
9898 .func = ip.extraFuncInstance(tid, extra.list.*, func_extra_index),
9899 }, 3);
9900 defer func_gop.deinit();
9901 if (func_gop == .existing) {
9902 // Hot path: undo the additions to our two arrays.
9903 items.mutate.len -= 4;
9904 extra.mutate.len = prev_extra_len;
9905 return func_gop.existing;
9906 }
9907 func_gop.putTentative(func_index);
9908 var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ .error_union_type = .{
9909 .error_set_type = error_set_type,
9910 .payload_type = arg.bare_return_type,
9911 } }, 2);
9912 defer error_union_type_gop.deinit();
9913 error_union_type_gop.putTentative(error_union_type);
9914 var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
9915 .inferred_error_set_type = func_index,
9916 }, 1);
9917 defer error_set_type_gop.deinit();
9918 error_set_type_gop.putTentative(error_set_type);
9919 var func_ty_gop = try ip.getOrPutKey(gpa, io, tid, .{
9920 .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index),
9921 });
9922 defer func_ty_gop.deinit();
9923 func_ty_gop.putTentative(func_ty);
9924 try finishFuncInstance(
9925 ip,
9926 gpa,
9927 io,
9928 tid,
9929 extra,
9930 generic_owner,
9931 func_index,
9932 func_extra_index,
9933 );
9934
9935 func_gop.putFinal(func_index);
9936 error_union_type_gop.putFinal(error_union_type);
9937 error_set_type_gop.putFinal(error_set_type);
9938 func_ty_gop.putFinal(func_ty);
9939 return func_index;
9940}
9941
9942fn finishFuncInstance(
9943 ip: *InternPool,
9944 gpa: Allocator,
9945 io: Io,
9946 tid: Zcu.PerThread.Id,
9947 extra: Local.Extra.Mutable,
9948 generic_owner: Index,
9949 func_index: Index,
9950 func_extra_index: u32,
9951) Allocator.Error!void {
9952 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);
9953 const fn_namespace = fn_owner_nav.analysis.?.namespace;
9954
9955 // TODO: improve this name
9956 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{
9957 fn_owner_nav.name.fmt(ip), @intFromEnum(func_index),
9958 }, .no_embedded_nulls);
9959 const nav_index = try ip.createNav(gpa, io, tid, .{
9960 .name = nav_name,
9961 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name),
9962 .val = func_index,
9963 .is_const = fn_owner_nav.status.fully_resolved.is_const,
9964 .alignment = fn_owner_nav.status.fully_resolved.alignment,
9965 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
9966 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
9967 });
9968
9969 // Populate the owner_nav field which was left undefined until now.
9970 extra.view().items(.@"0")[
9971 func_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_nav").?
9972 ] = @intFromEnum(nav_index);
9973}
9974
9975pub const EnumTypeInit = struct {
9976 has_values: bool,
9977 tag_mode: LoadedEnumType.TagMode,
9978 fields_len: u32,
9979 key: union(enum) {
9980 declared: struct {
9981 zir_index: TrackedInst.Index,
9982 captures: []const CaptureValue,
9983 },
9984 declared_owned_captures: struct {
9985 zir_index: TrackedInst.Index,
9986 captures: CaptureValue.Slice,
9987 },
9988 reified: struct {
9989 zir_index: TrackedInst.Index,
9990 type_hash: u64,
9991 },
9992 },
9993};
9994
9995pub const WipEnumType = struct {
9996 tid: Zcu.PerThread.Id,
9997 index: Index,
9998 tag_ty_index: u32,
9999 type_name_extra_index: u32,
10000 namespace_extra_index: u32,
10001 name_nav_extra_index: u32,
10002 names_map: MapIndex,
10003 names_start: u32,
10004 values_map: OptionalMapIndex,
10005 values_start: u32,
10006
10007 pub fn setName(
10008 wip: WipEnumType,
10009 ip: *InternPool,
10010 type_name: NullTerminatedString,
10011 /// This should be the `Nav` we are named after if we use the `.parent` name strategy; `.none` otherwise.
10012 name_nav: Nav.Index.Optional,
10013 ) void {
10014 const extra = ip.getLocalShared(wip.tid).extra.acquire();
10015 const extra_items = extra.view().items(.@"0");
10016 extra_items[wip.type_name_extra_index] = @intFromEnum(type_name);
10017 extra_items[wip.name_nav_extra_index] = @intFromEnum(name_nav);
10018 }
10019
10020 pub fn prepare(
10021 wip: WipEnumType,
10022 ip: *InternPool,
10023 namespace: NamespaceIndex,
10024 ) void {
10025 const extra = ip.getLocalShared(wip.tid).extra.acquire();
10026 const extra_items = extra.view().items(.@"0");
10027
10028 extra_items[wip.namespace_extra_index] = @intFromEnum(namespace);
10029 }
10030
10031 pub fn setTagTy(wip: WipEnumType, ip: *InternPool, tag_ty: Index) void {
10032 assert(ip.isIntegerType(tag_ty));
10033 const extra = ip.getLocalShared(wip.tid).extra.acquire();
10034 extra.view().items(.@"0")[wip.tag_ty_index] = @intFromEnum(tag_ty);
10035 }
10036
10037 pub const FieldConflict = struct {
10038 kind: enum { name, value },
10039 prev_field_idx: u32,
10040 };
10041
10042 /// Returns the already-existing field with the same name or value, if any.
10043 /// If the enum is automatially numbered, `value` must be `.none`.
10044 /// Otherwise, the type of `value` must be the integer tag type of the enum.
10045 pub fn nextField(wip: WipEnumType, ip: *InternPool, name: NullTerminatedString, value: Index) ?FieldConflict {
10046 const unwrapped_index = wip.index.unwrap(ip);
10047 const extra_list = ip.getLocalShared(unwrapped_index.tid).extra.acquire();
10048 const extra_items = extra_list.view().items(.@"0");
10049 if (ip.addFieldName(extra_list, wip.names_map, wip.names_start, name)) |conflict| {
10050 return .{ .kind = .name, .prev_field_idx = conflict };
10051 }
10052 if (value == .none) {
10053 assert(wip.values_map == .none);
10054 return null;
10055 }
10056 assert(ip.typeOf(value) == @as(Index, @enumFromInt(extra_items[wip.tag_ty_index])));
10057 const map = wip.values_map.unwrap().?.get(ip);
10058 const field_index = map.count();
10059 const indexes = extra_items[wip.values_start..][0..field_index];
10060 const adapter: Index.Adapter = .{ .indexes = @ptrCast(indexes) };
10061 const gop = map.getOrPutAssumeCapacityAdapted(value, adapter);
10062 if (gop.found_existing) {
10063 return .{ .kind = .value, .prev_field_idx = @intCast(gop.index) };
10064 }
10065 extra_items[wip.values_start + field_index] = @intFromEnum(value);
10066 return null;
10067 }
10068
10069 pub fn cancel(wip: WipEnumType, ip: *InternPool, tid: Zcu.PerThread.Id) void {
10070 ip.remove(tid, wip.index);
10071 }
10072
10073 pub const Result = union(enum) {
10074 wip: WipEnumType,
10075 existing: Index,
10076 };
10077};
10078
10079pub fn getEnumType(
10080 ip: *InternPool,
10081 gpa: Allocator,
10082 io: Io,
10083 tid: Zcu.PerThread.Id,
10084 ini: EnumTypeInit,
10085 /// If it is known that there is an existing type with this key which is outdated,
10086 /// this is passed as `true`, and the type is replaced with one at a fresh index.
10087 replace_existing: bool,
10088) Allocator.Error!WipEnumType.Result {
10089 const key: Key = .{ .enum_type = switch (ini.key) {
10090 .declared => |d| .{ .declared = .{
10091 .zir_index = d.zir_index,
10092 .captures = .{ .external = d.captures },
10093 } },
10094 .declared_owned_captures => |d| .{ .declared = .{
10095 .zir_index = d.zir_index,
10096 .captures = .{ .owned = d.captures },
10097 } },
10098 .reified => |r| .{ .reified = .{
10099 .zir_index = r.zir_index,
10100 .type_hash = r.type_hash,
10101 } },
10102 } };
10103 var gop = if (replace_existing)
10104 ip.putKeyReplace(io, tid, key)
10105 else
10106 try ip.getOrPutKey(gpa, io, tid, key);
10107 defer gop.deinit();
10108 if (gop == .existing) return .{ .existing = gop.existing };
10109
10110 const local = ip.getLocal(tid);
10111 const items = local.getMutableItems(gpa, io);
10112 try items.ensureUnusedCapacity(1);
10113 const extra = local.getMutableExtra(gpa, io);
10114
10115 const names_map = try ip.addMap(gpa, io, tid, ini.fields_len);
10116 errdefer local.mutate.maps.len -= 1;
10117
10118 switch (ini.tag_mode) {
10119 .auto => {
10120 assert(!ini.has_values);
10121 try extra.ensureUnusedCapacity(@typeInfo(EnumAuto).@"struct".fields.len +
10122 // TODO: fmt bug
10123 // zig fmt: off
10124 switch (ini.key) {
10125 inline .declared, .declared_owned_captures => |d| d.captures.len,
10126 .reified => 2, // type_hash: PackedU64
10127 } +
10128 // zig fmt: on
10129 ini.fields_len); // field types
10130
10131 const extra_index = addExtraAssumeCapacity(extra, EnumAuto{
10132 .name = undefined, // set by `prepare`
10133 .name_nav = undefined, // set by `prepare`
10134 .captures_len = switch (ini.key) {
10135 inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len),
10136 .reified => std.math.maxInt(u32),
10137 },
10138 .namespace = undefined, // set by `prepare`
10139 .int_tag_type = .none, // set by `prepare`
10140 .fields_len = ini.fields_len,
10141 .names_map = names_map,
10142 .zir_index = switch (ini.key) {
10143 inline else => |x| x.zir_index,
10144 }.toOptional(),
10145 });
10146 items.appendAssumeCapacity(.{
10147 .tag = .type_enum_auto,
10148 .data = extra_index,
10149 });
10150 switch (ini.key) {
10151 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
10152 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
10153 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
10154 }
10155 const names_start = extra.mutate.len;
10156 _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len);
10157 return .{ .wip = .{
10158 .tid = tid,
10159 .index = gop.put(),
10160 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumAuto, "int_tag_type").?,
10161 .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name").?,
10162 .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "name_nav").?,
10163 .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumAuto, "namespace").?,
10164 .names_map = names_map,
10165 .names_start = @intCast(names_start),
10166 .values_map = .none,
10167 .values_start = undefined,
10168 } };
10169 },
10170 .explicit, .nonexhaustive => {
10171 const values_map: OptionalMapIndex = if (!ini.has_values) .none else m: {
10172 const values_map = try ip.addMap(gpa, io, tid, ini.fields_len);
10173 break :m values_map.toOptional();
10174 };
10175 errdefer if (ini.has_values) {
10176 local.mutate.maps.len -= 1;
10177 };
10178
10179 try extra.ensureUnusedCapacity(@typeInfo(EnumExplicit).@"struct".fields.len +
10180 // TODO: fmt bug
10181 // zig fmt: off
10182 switch (ini.key) {
10183 inline .declared, .declared_owned_captures => |d| d.captures.len,
10184 .reified => 2, // type_hash: PackedU64
10185 } +
10186 // zig fmt: on
10187 ini.fields_len + // field types
10188 ini.fields_len * @intFromBool(ini.has_values)); // field values
10189
10190 const extra_index = addExtraAssumeCapacity(extra, EnumExplicit{
10191 .name = undefined, // set by `prepare`
10192 .name_nav = undefined, // set by `prepare`
10193 .captures_len = switch (ini.key) {
10194 inline .declared, .declared_owned_captures => |d| @intCast(d.captures.len),
10195 .reified => std.math.maxInt(u32),
10196 },
10197 .namespace = undefined, // set by `prepare`
10198 .int_tag_type = .none, // set by `prepare`
10199 .fields_len = ini.fields_len,
10200 .names_map = names_map,
10201 .values_map = values_map,
10202 .zir_index = switch (ini.key) {
10203 inline else => |x| x.zir_index,
10204 }.toOptional(),
10205 });
10206 items.appendAssumeCapacity(.{
10207 .tag = switch (ini.tag_mode) {
10208 .auto => unreachable,
10209 .explicit => .type_enum_explicit,
10210 .nonexhaustive => .type_enum_nonexhaustive,
10211 },
10212 .data = extra_index,
10213 });
10214 switch (ini.key) {
10215 .declared => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures)}),
10216 .declared_owned_captures => |d| extra.appendSliceAssumeCapacity(.{@ptrCast(d.captures.get(ip))}),
10217 .reified => |r| _ = addExtraAssumeCapacity(extra, PackedU64.init(r.type_hash)),
10218 }
10219 const names_start = extra.mutate.len;
10220 _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len);
10221 const values_start = extra.mutate.len;
10222 if (ini.has_values) {
10223 _ = extra.addManyAsSliceAssumeCapacity(ini.fields_len);
10224 }
10225 return .{ .wip = .{
10226 .tid = tid,
10227 .index = gop.put(),
10228 .tag_ty_index = extra_index + std.meta.fieldIndex(EnumExplicit, "int_tag_type").?,
10229 .type_name_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name").?,
10230 .name_nav_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "name_nav").?,
10231 .namespace_extra_index = extra_index + std.meta.fieldIndex(EnumExplicit, "namespace").?,
10232 .names_map = names_map,
10233 .names_start = @intCast(names_start),
10234 .values_map = values_map,
10235 .values_start = @intCast(values_start),
10236 } };
10237 },
10238 }
10239}
10240
10241const GeneratedTagEnumTypeInit = struct {
10242 name: NullTerminatedString,
10243 owner_union_ty: Index,
10244 tag_ty: Index,
10245 names: []const NullTerminatedString,
10246 values: []const Index,
10247 tag_mode: LoadedEnumType.TagMode,
10248 parent_namespace: NamespaceIndex,
10249};
10250
10251/// Creates an enum type which was automatically-generated as the tag type of a
10252/// `union` with no explicit tag type. Since this is only called once per union
10253/// type, it asserts that no matching type yet exists.
10254pub fn getGeneratedTagEnumType(
10255 ip: *InternPool,
10256 gpa: Allocator,
10257 io: Io,
10258 tid: Zcu.PerThread.Id,
10259 ini: GeneratedTagEnumTypeInit,
10260) Allocator.Error!Index {
10261 assert(ip.isUnion(ini.owner_union_ty));
10262 assert(ip.isIntegerType(ini.tag_ty));
10263 for (ini.values) |val| assert(ip.typeOf(val) == ini.tag_ty);
10264
10265 const local = ip.getLocal(tid);
10266 const items = local.getMutableItems(gpa, io);
10267 try items.ensureUnusedCapacity(1);
10268 const extra = local.getMutableExtra(gpa, io);
10269
10270 const names_map = try ip.addMap(gpa, io, tid, ini.names.len);
10271 errdefer local.mutate.maps.len -= 1;
10272 ip.addStringsToMap(names_map, ini.names);
10273
10274 const fields_len: u32 = @intCast(ini.names.len);
10275
10276 // Predict the index the enum will live at so we can construct the namespace before releasing the shard's mutex.
10277 const enum_index = Index.Unwrapped.wrap(.{
10278 .tid = tid,
10279 .index = items.mutate.len,
10280 }, ip);
10281 const parent_namespace = ip.namespacePtr(ini.parent_namespace);
10282 const namespace = try ip.createNamespace(gpa, io, tid, .{
10283 .parent = ini.parent_namespace.toOptional(),
10284 .owner_type = enum_index,
10285 .file_scope = parent_namespace.file_scope,
10286 .generation = parent_namespace.generation,
10287 });
10288 errdefer ip.destroyNamespace(tid, namespace);
10289
10290 const prev_extra_len = extra.mutate.len;
10291 switch (ini.tag_mode) {
10292 .auto => {
10293 try extra.ensureUnusedCapacity(@typeInfo(EnumAuto).@"struct".fields.len +
10294 1 + // owner_union
10295 fields_len); // field names
10296 items.appendAssumeCapacity(.{
10297 .tag = .type_enum_auto,
10298 .data = addExtraAssumeCapacity(extra, EnumAuto{
10299 .name = ini.name,
10300 .name_nav = .none,
10301 .captures_len = 0,
10302 .namespace = namespace,
10303 .int_tag_type = ini.tag_ty,
10304 .fields_len = fields_len,
10305 .names_map = names_map,
10306 .zir_index = .none,
10307 }),
10308 });
10309 extra.appendAssumeCapacity(.{@intFromEnum(ini.owner_union_ty)});
10310 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)});
10311 },
10312 .explicit, .nonexhaustive => {
10313 try extra.ensureUnusedCapacity(@typeInfo(EnumExplicit).@"struct".fields.len +
10314 1 + // owner_union
10315 fields_len + // field names
10316 ini.values.len); // field values
10317
10318 const values_map: OptionalMapIndex = if (ini.values.len != 0) m: {
10319 const map = try ip.addMap(gpa, io, tid, ini.values.len);
10320 ip.addIndexesToMap(map, ini.values);
10321 break :m map.toOptional();
10322 } else .none;
10323 // We don't clean up the values map on error!
10324 errdefer @compileError("error path leaks values_map");
10325
10326 items.appendAssumeCapacity(.{
10327 .tag = switch (ini.tag_mode) {
10328 .explicit => .type_enum_explicit,
10329 .nonexhaustive => .type_enum_nonexhaustive,
10330 .auto => unreachable,
10331 },
10332 .data = addExtraAssumeCapacity(extra, EnumExplicit{
10333 .name = ini.name,
10334 .name_nav = .none,
10335 .captures_len = 0,
10336 .namespace = namespace,
10337 .int_tag_type = ini.tag_ty,
10338 .fields_len = fields_len,
10339 .names_map = names_map,
10340 .values_map = values_map,
10341 .zir_index = .none,
10342 }),
10343 });
10344 extra.appendAssumeCapacity(.{@intFromEnum(ini.owner_union_ty)});
10345 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.names)});
10346 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.values)});
10347 },9369 },
10348 }9370 .data = &.{
10349 errdefer extra.mutate.len = prev_extra_len;9371 func_extra_index,
10350 errdefer switch (ini.tag_mode) {9372 addExtraAssumeCapacity(extra, Tag.ErrorUnionType{
10351 .auto => {},9373 .error_set_type = error_set_type,
10352 .explicit, .nonexhaustive => if (ini.values.len != 0) {9374 .payload_type = arg.bare_return_type,
10353 local.mutate.maps.len -= 1;9375 }),
9376 @intFromEnum(func_index),
9377 func_type_extra_index,
10354 },9378 },
10355 };9379 });
9380 errdefer {
9381 items.mutate.len -= 4;
9382 extra.mutate.len = prev_extra_len;
9383 }
103569384
10357 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .enum_type = .{9385 var func_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
10358 .generated_tag = .{ .union_type = ini.owner_union_ty },9386 .func = ip.extraFuncInstance(tid, extra.list.*, func_extra_index),
10359 } });9387 }, 3);
10360 defer gop.deinit();9388 defer func_gop.deinit();
10361 assert(gop.put() == enum_index);9389 if (func_gop == .existing) {
10362 return enum_index;9390 // Hot path: undo the additions to our two arrays.
10363}9391 items.mutate.len -= 4;
9392 extra.mutate.len = prev_extra_len;
9393 return func_gop.existing;
9394 }
9395 func_gop.putTentative(func_index);
9396 var error_union_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{ .error_union_type = .{
9397 .error_set_type = error_set_type,
9398 .payload_type = arg.bare_return_type,
9399 } }, 2);
9400 defer error_union_type_gop.deinit();
9401 error_union_type_gop.putTentative(error_union_type);
9402 var error_set_type_gop = try ip.getOrPutKeyEnsuringAdditionalCapacity(gpa, io, tid, .{
9403 .inferred_error_set_type = func_index,
9404 }, 1);
9405 defer error_set_type_gop.deinit();
9406 error_set_type_gop.putTentative(error_set_type);
9407 var func_ty_gop = try ip.getOrPutKey(gpa, io, tid, .{
9408 .func_type = extraFuncType(tid, extra.list.*, func_type_extra_index),
9409 });
9410 defer func_ty_gop.deinit();
9411 func_ty_gop.putTentative(func_ty);
9412 try finishFuncInstance(
9413 ip,
9414 gpa,
9415 io,
9416 tid,
9417 extra,
9418 generic_owner,
9419 func_index,
9420 func_extra_index,
9421 );
103649422
10365pub const OpaqueTypeInit = struct {9423 func_gop.putFinal(func_index);
10366 zir_index: TrackedInst.Index,9424 error_union_type_gop.putFinal(error_union_type);
10367 captures: []const CaptureValue,9425 error_set_type_gop.putFinal(error_set_type);
10368};9426 func_ty_gop.putFinal(func_ty);
9427 return func_index;
9428}
103699429
10370pub fn getOpaqueType(9430fn finishFuncInstance(
10371 ip: *InternPool,9431 ip: *InternPool,
10372 gpa: Allocator,9432 gpa: Allocator,
10373 io: Io,9433 io: Io,
10374 tid: Zcu.PerThread.Id,9434 tid: Zcu.PerThread.Id,
10375 ini: OpaqueTypeInit,9435 extra: Local.Extra.Mutable,
10376) Allocator.Error!WipNamespaceType.Result {9436 generic_owner: Index,
10377 var gop = try ip.getOrPutKey(gpa, io, tid, .{ .opaque_type = .{ .declared = .{9437 func_index: Index,
10378 .zir_index = ini.zir_index,9438 func_extra_index: u32,
10379 .captures = .{ .external = ini.captures },9439) Allocator.Error!void {
10380 } } });9440 const fn_owner_nav = ip.getNav(ip.funcDeclInfo(generic_owner).owner_nav);
10381 defer gop.deinit();9441 const fn_namespace = fn_owner_nav.analysis.?.namespace;
10382 if (gop == .existing) return .{ .existing = gop.existing };
10383
10384 const local = ip.getLocal(tid);
10385 const items = local.getMutableItems(gpa, io);
10386 const extra = local.getMutableExtra(gpa, io);
10387 try items.ensureUnusedCapacity(1);
103889442
10389 try extra.ensureUnusedCapacity(@typeInfo(Tag.TypeOpaque).@"struct".fields.len + ini.captures.len);9443 // TODO: improve this name
10390 const extra_index = addExtraAssumeCapacity(extra, Tag.TypeOpaque{9444 const nav_name = try ip.getOrPutStringFmt(gpa, io, tid, "{f}__anon_{d}", .{
10391 .name = undefined, // set by `finish`9445 fn_owner_nav.name.fmt(ip), @intFromEnum(func_index),
10392 .name_nav = undefined, // set by `finish`9446 }, .no_embedded_nulls);
10393 .namespace = undefined, // set by `finish`9447 const nav_index = try ip.createNav(gpa, io, tid, .{
10394 .zir_index = ini.zir_index,9448 .name = nav_name,
10395 .captures_len = @intCast(ini.captures.len),9449 .fqn = try ip.namespacePtr(fn_namespace).internFullyQualifiedName(ip, gpa, io, tid, nav_name),
10396 });9450 .val = func_index,
10397 items.appendAssumeCapacity(.{9451 .is_const = fn_owner_nav.status.fully_resolved.is_const,
10398 .tag = .type_opaque,9452 .alignment = fn_owner_nav.status.fully_resolved.alignment,
10399 .data = extra_index,9453 .@"linksection" = fn_owner_nav.status.fully_resolved.@"linksection",
9454 .@"addrspace" = fn_owner_nav.status.fully_resolved.@"addrspace",
10400 });9455 });
10401 extra.appendSliceAssumeCapacity(.{@ptrCast(ini.captures)});9456
10402 return .{9457 // Populate the owner_nav field which was left undefined until now.
10403 .wip = .{9458 extra.view().items(.@"0")[
10404 .tid = tid,9459 func_extra_index + std.meta.fieldIndex(Tag.FuncInstance, "owner_nav").?
10405 .index = gop.put(),9460 ] = @intFromEnum(nav_index);
10406 .type_name_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name").?,
10407 .name_nav_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "name_nav").?,
10408 .namespace_extra_index = extra_index + std.meta.fieldIndex(Tag.TypeOpaque, "namespace").?,
10409 },
10410 };
10411}9461}
104129462
10413pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {9463pub fn getIfExists(ip: *const InternPool, key: Key) ?Index {
...@@ -10534,6 +9584,9 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {...@@ -10534,6 +9584,9 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
10534 TrackedInst.Index,9584 TrackedInst.Index,
10535 TrackedInst.Index.Optional,9585 TrackedInst.Index.Optional,
10536 ComptimeAllocIndex,9586 ComptimeAllocIndex,
9587 @FieldType(Tag.TypeStructPacked, "captures_len"),
9588 @FieldType(Tag.TypeUnionPacked, "captures_len"),
9589 @FieldType(Tag.TypeEnum, "captures_len"),
10537 => @intFromEnum(@field(item, field.name)),9590 => @intFromEnum(@field(item, field.name)),
105389591
10539 u32,9592 u32,
...@@ -10545,7 +9598,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {...@@ -10545,7 +9598,6 @@ fn addExtraAssumeCapacity(extra: Local.Extra.Mutable, item: anytype) u32 {
10545 Tag.TypePointer.PackedOffset,9598 Tag.TypePointer.PackedOffset,
10546 Tag.TypeUnion.Flags,9599 Tag.TypeUnion.Flags,
10547 Tag.TypeStruct.Flags,9600 Tag.TypeStruct.Flags,
10548 Tag.TypeStructPacked.Flags,
10549 => @bitCast(@field(item, field.name)),9601 => @bitCast(@field(item, field.name)),
105509602
10551 else => @compileError("bad field type: " ++ @typeName(field.type)),9603 else => @compileError("bad field type: " ++ @typeName(field.type)),
...@@ -10597,6 +9649,9 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat...@@ -10597,6 +9649,9 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
10597 TrackedInst.Index,9649 TrackedInst.Index,
10598 TrackedInst.Index.Optional,9650 TrackedInst.Index.Optional,
10599 ComptimeAllocIndex,9651 ComptimeAllocIndex,
9652 @FieldType(Tag.TypeStructPacked, "captures_len"),
9653 @FieldType(Tag.TypeUnionPacked, "captures_len"),
9654 @FieldType(Tag.TypeEnum, "captures_len"),
10600 => @enumFromInt(extra_item),9655 => @enumFromInt(extra_item),
106019656
10602 u32,9657 u32,
...@@ -10607,7 +9662,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat...@@ -10607,7 +9662,6 @@ fn extraDataTrail(extra: Local.Extra, comptime T: type, index: u32) struct { dat
10607 Tag.TypePointer.PackedOffset,9662 Tag.TypePointer.PackedOffset,
10608 Tag.TypeUnion.Flags,9663 Tag.TypeUnion.Flags,
10609 Tag.TypeStruct.Flags,9664 Tag.TypeStruct.Flags,
10610 Tag.TypeStructPacked.Flags,
10611 FuncAnalysis,9665 FuncAnalysis,
10612 => @bitCast(extra_item),9666 => @bitCast(extra_item),
106139667
...@@ -10786,7 +9840,7 @@ pub fn getCoerced(...@@ -10786,7 +9840,7 @@ pub fn getCoerced(
10786 .int => |int| switch (ip.indexToKey(new_ty)) {9840 .int => |int| switch (ip.indexToKey(new_ty)) {
10787 .enum_type => return ip.get(gpa, io, tid, .{ .enum_tag = .{9841 .enum_type => return ip.get(gpa, io, tid, .{ .enum_tag = .{
10788 .ty = new_ty,9842 .ty = new_ty,
10789 .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).tag_ty),9843 .int = try ip.getCoerced(gpa, io, tid, val, ip.loadEnumType(new_ty).int_tag_type),
10790 } }),9844 } }),
10791 .ptr_type => switch (int.storage) {9845 .ptr_type => switch (int.storage) {
10792 inline .u64, .i64 => |int_val| return ip.get(gpa, io, tid, .{ .ptr = .{9846 inline .u64, .i64 => |int_val| return ip.get(gpa, io, tid, .{ .ptr = .{
...@@ -10795,7 +9849,6 @@ pub fn getCoerced(...@@ -10795,7 +9849,6 @@ pub fn getCoerced(
10795 .byte_offset = @intCast(int_val),9849 .byte_offset = @intCast(int_val),
10796 } }),9850 } }),
10797 .big_int => unreachable, // must be a usize9851 .big_int => unreachable, // must be a usize
10798 .lazy_align, .lazy_size => {},
10799 },9852 },
10800 else => if (ip.isIntegerType(new_ty))9853 else => if (ip.isIntegerType(new_ty))
10801 return ip.getCoercedInts(gpa, io, tid, int, new_ty),9854 return ip.getCoercedInts(gpa, io, tid, int, new_ty),
...@@ -10825,11 +9878,11 @@ pub fn getCoerced(...@@ -10825,11 +9878,11 @@ pub fn getCoerced(
10825 const index = enum_type.nameIndex(ip, enum_literal).?;9878 const index = enum_type.nameIndex(ip, enum_literal).?;
10826 return ip.get(gpa, io, tid, .{ .enum_tag = .{9879 return ip.get(gpa, io, tid, .{ .enum_tag = .{
10827 .ty = new_ty,9880 .ty = new_ty,
10828 .int = if (enum_type.values.len != 0)9881 .int = if (enum_type.field_values.len != 0)
10829 enum_type.values.get(ip)[index]9882 enum_type.field_values.get(ip)[index]
10830 else9883 else
10831 try ip.get(gpa, io, tid, .{ .int = .{9884 try ip.get(gpa, io, tid, .{ .int = .{
10832 .ty = enum_type.tag_ty,9885 .ty = enum_type.int_tag_type,
10833 .storage = .{ .u64 = index },9886 .storage = .{ .u64 = index },
10834 } }),9887 } }),
10835 } });9888 } });
...@@ -11266,98 +10319,137 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -11266,98 +10319,137 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
11266 break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);10319 break :b @sizeOf(Tag.ErrorSet) + (@sizeOf(u32) * info.names_len);
11267 },10320 },
11268 .type_inferred_error_set => 0,10321 .type_inferred_error_set => 0,
11269 .type_enum_explicit, .type_enum_nonexhaustive => b: {10322 .type_tuple => b: {
11270 const info = extraData(extra_list, EnumExplicit, data);10323 const info = extraData(extra_list, TypeTuple, data);
11271 var ints = @typeInfo(EnumExplicit).@"struct".fields.len;10324 break :b @sizeOf(TypeTuple) + (@sizeOf(u32) * 2 * info.fields_len);
11272 if (info.zir_index == .none) ints += 1;
11273 ints += if (info.captures_len != std.math.maxInt(u32))
11274 info.captures_len
11275 else
11276 @typeInfo(PackedU64).@"struct".fields.len;
11277 ints += info.fields_len;
11278 if (info.values_map != .none) ints += info.fields_len;
11279 break :b @sizeOf(u32) * ints;
11280 },
11281 .type_enum_auto => b: {
11282 const info = extraData(extra_list, EnumAuto, data);
11283 const ints = @typeInfo(EnumAuto).@"struct".fields.len + info.captures_len + info.fields_len;
11284 break :b @sizeOf(u32) * ints;
11285 },10325 },
11286 .type_opaque => b: {10326 .type_function => b: {
11287 const info = extraData(extra_list, Tag.TypeOpaque, data);10327 const info = extraData(extra_list, Tag.TypeFunction, data);
11288 const ints = @typeInfo(Tag.TypeOpaque).@"struct".fields.len + info.captures_len;10328 break :b @sizeOf(Tag.TypeFunction) +
11289 break :b @sizeOf(u32) * ints;10329 (@sizeOf(Index) * info.params_len) +
10330 (@as(u32, 4) * @intFromBool(info.flags.has_comptime_bits)) +
10331 (@as(u32, 4) * @intFromBool(info.flags.has_noalias_bits));
11290 },10332 },
10333
11291 .type_struct => b: {10334 .type_struct => b: {
10335 var n: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len;
11292 const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);10336 const extra = extraDataTrail(extra_list, Tag.TypeStruct, data);
11293 const info = extra.data;10337 switch (extra.data.flags.any_captures) {
11294 var ints: usize = @typeInfo(Tag.TypeStruct).@"struct".fields.len;10338 .reified => n += 2, // type_hash: PackedU64
11295 if (info.flags.any_captures) {10339 .true => {
11296 const captures_len = extra_items[extra.end];10340 n += 1; // captures_len: u32
11297 ints += 1 + captures_len;10341 n += extra_items[extra.end]; // capture: CaptureValue
10342 },
10343 .false => {},
10344 }
10345 n += extra.data.fields_len; // field_name: NullTerminatedString
10346 n += extra.data.fields_len; // field_type: Index
10347 if (extra.data.flags.any_field_defaults) {
10348 n += extra.data.fields_len; // field_default: Index
10349 }
10350 if (extra.data.flags.any_field_aligns) {
10351 n += (extra.data.fields_len + 3) / 4; // field_align: Alignment
10352 }
10353 if (extra.data.flags.any_comptime_fields) {
10354 n += (extra.data.fields_len + 31) / 32; // field_is_comptime_bits: u32
11298 }10355 }
11299 ints += info.fields_len; // types10356 if (extra.data.flags.layout == .auto) {
11300 ints += 1; // names_map10357 n += extra.data.fields_len; // field_runtime_order: RuntimeOrder
11301 ints += info.fields_len; // names10358 }
11302 if (info.flags.any_default_inits)10359 n += extra.data.fields_len; // field_offset: u32
11303 ints += info.fields_len; // inits10360 break :b n * @sizeOf(u32);
11304 if (info.flags.any_aligned_fields)
11305 ints += (info.fields_len + 3) / 4; // aligns
11306 if (info.flags.any_comptime_fields)
11307 ints += (info.fields_len + 31) / 32; // comptime bits
11308 if (!info.flags.is_extern)
11309 ints += info.fields_len; // runtime order
11310 ints += info.fields_len; // offsets
11311 break :b @sizeOf(u32) * ints;
11312 },10361 },
11313 .type_struct_packed => b: {10362 .type_struct_packed_auto, .type_struct_packed_explicit => b: {
10363 var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len;
11314 const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);10364 const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
11315 const captures_len = if (extra.data.flags.any_captures)10365 switch (extra.data.captures_len) {
11316 extra_items[extra.end]10366 .reified => n += 2, // type_hash: PackedU64
11317 else10367 _ => |len| n += @intFromEnum(len), // capture: CaptureValue
11318 0;10368 }
11319 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +10369 n += extra.data.fields_len; // field_name: NullTerminatedString
11320 @intFromBool(extra.data.flags.any_captures) + captures_len +10370 n += extra.data.fields_len; // field_type: Index
11321 extra.data.fields_len * 2);10371 break :b n * @sizeOf(u32);
11322 },10372 },
11323 .type_struct_packed_inits => b: {10373 .type_struct_packed_auto_defaults, .type_struct_packed_explicit_defaults => b: {
10374 var n: usize = @typeInfo(Tag.TypeStructPacked).@"struct".fields.len;
11324 const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);10375 const extra = extraDataTrail(extra_list, Tag.TypeStructPacked, data);
11325 const captures_len = if (extra.data.flags.any_captures)10376 switch (extra.data.captures_len) {
11326 extra_items[extra.end]10377 .reified => n += 2, // type_hash: PackedU64
11327 else10378 _ => |len| n += @intFromEnum(len), // capture: CaptureValue
11328 0;10379 }
11329 break :b @sizeOf(u32) * (@typeInfo(Tag.TypeStructPacked).@"struct".fields.len +10380 n += extra.data.fields_len; // field_name: NullTerminatedString
11330 @intFromBool(extra.data.flags.any_captures) + captures_len +10381 n += extra.data.fields_len; // field_type: Index
11331 extra.data.fields_len * 3);10382 n += extra.data.fields_len; // field_default: Index
11332 },10383 break :b n * @sizeOf(u32);
11333 .type_tuple => b: {
11334 const info = extraData(extra_list, TypeTuple, data);
11335 break :b @sizeOf(TypeTuple) + (@sizeOf(u32) * 2 * info.fields_len);
11336 },10384 },
11337
11338 .type_union => b: {10385 .type_union => b: {
10386 var n: usize = @typeInfo(Tag.TypeUnion).@"struct".fields.len;
11339 const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);10387 const extra = extraDataTrail(extra_list, Tag.TypeUnion, data);
11340 const captures_len = if (extra.data.flags.any_captures)10388 switch (extra.data.flags.any_captures) {
11341 extra_items[extra.end]10389 .reified => n += 2, // type_hash: PackedU64
11342 else10390 .true => {
11343 0;10391 n += 1; // captures_len: u32
11344 const per_field = @sizeOf(u32); // field type10392 n += extra_items[extra.end]; // capture: CaptureValue
11345 // 1 byte per field for alignment, rounded up to the nearest 4 bytes10393 },
11346 const alignments = if (extra.data.flags.any_aligned_fields)10394 .false => {},
11347 ((extra.data.fields_len + 3) / 4) * 410395 }
11348 else10396 n += extra.data.fields_len; // field_type: Index
11349 0;10397 if (extra.data.flags.any_field_aligns) {
11350 break :b @sizeOf(Tag.TypeUnion) +10398 n += (extra.data.fields_len + 3) / 4; // field_align: Alignment
11351 4 * (@intFromBool(extra.data.flags.any_captures) + captures_len) +10399 }
11352 (extra.data.fields_len * per_field) + alignments;10400 break :b n * @sizeOf(u32);
11353 },10401 },
1135410402 .type_union_packed_auto, .type_union_packed_explicit => b: {
11355 .type_function => b: {10403 var n: usize = @typeInfo(Tag.TypeUnionPacked).@"struct".fields.len;
11356 const info = extraData(extra_list, Tag.TypeFunction, data);10404 const extra = extraDataTrail(extra_list, Tag.TypeUnionPacked, data);
11357 break :b @sizeOf(Tag.TypeFunction) +10405 switch (extra.data.captures_len) {
11358 (@sizeOf(Index) * info.params_len) +10406 .reified => n += 2, // type_hash: PackedU64
11359 (@as(u32, 4) * @intFromBool(info.flags.has_comptime_bits)) +10407 _ => |len| n += @intFromEnum(len), // capture: CaptureValue
11360 (@as(u32, 4) * @intFromBool(info.flags.has_noalias_bits));10408 }
10409 n += extra.data.fields_len; // field_type: Index
10410 break :b n * @sizeOf(u32);
10411 },
10412 .type_enum_auto => b: {
10413 var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len;
10414 const extra = extraData(extra_list, Tag.TypeEnum, data);
10415 switch (extra.captures_len) {
10416 .generated_union_tag => n += 1, // owner_union: Index
10417 .reified => {
10418 n += 1; // zir_index: TrackedInst.Index,
10419 n += 2; // type_hash: PackedU64
10420 },
10421 _ => |len| {
10422 n += 1; // zir_index: TrackedInst.Index,
10423 n += @intFromEnum(len); // capture: CaptureValue
10424 },
10425 }
10426 n += extra.fields_len; // field_name: NullTerminatedString
10427 break :b n * @sizeOf(u32);
10428 },
10429 .type_enum_explicit, .type_enum_nonexhaustive => b: {
10430 var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len;
10431 const extra = extraData(extra_list, Tag.TypeEnum, data);
10432 switch (extra.captures_len) {
10433 .generated_union_tag => n += 1, // owner_union: Index
10434 .reified => {
10435 n += 1; // zir_index: TrackedInst.Index,
10436 n += 2; // type_hash: PackedU64
10437 },
10438 _ => |len| {
10439 n += 1; // zir_index: TrackedInst.Index,
10440 n += @intFromEnum(len); // capture: CaptureValue
10441 },
10442 }
10443 n += 1; // field_value_map: MapIndex
10444 n += extra.fields_len; // field_name: NullTerminatedString
10445 n += extra.fields_len; // field_value: Index
10446 break :b n * @sizeOf(u32);
10447 },
10448 .type_opaque => b: {
10449 var n: usize = @typeInfo(Tag.TypeEnum).@"struct".fields.len;
10450 const extra = extraData(extra_list, Tag.TypeOpaque, data);
10451 n += extra.captures_len; // capture: CaptureValue
10452 break :b n * @sizeOf(u32);
11361 },10453 },
1136210454
11363 .undef => 0,10455 .undef => 0,
...@@ -11393,8 +10485,6 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo...@@ -11393,8 +10485,6 @@ fn dumpStatsFallible(ip: *const InternPool, w: *Io.Writer, arena: Allocator) !vo
11393 break :b @sizeOf(Int) + int.limbs_len * @sizeOf(Limb);10485 break :b @sizeOf(Int) + int.limbs_len * @sizeOf(Limb);
11394 },10486 },
1139510487
11396 .int_lazy_align, .int_lazy_size => @sizeOf(IntLazy),
11397
11398 .error_set_error, .error_union_error => @sizeOf(Key.Error),10488 .error_set_error, .error_union_error => @sizeOf(Key.Error),
11399 .error_union_payload => @sizeOf(Tag.TypeValue),10489 .error_union_payload => @sizeOf(Tag.TypeValue),
11400 .enum_literal => 0,10490 .enum_literal => 0,
...@@ -11484,16 +10574,20 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {...@@ -11484,16 +10574,20 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
11484 .type_anyerror_union,10574 .type_anyerror_union,
11485 .type_error_set,10575 .type_error_set,
11486 .type_inferred_error_set,10576 .type_inferred_error_set,
10577 .type_tuple,
10578 .type_function,
10579 .type_struct,
10580 .type_struct_packed_auto,
10581 .type_struct_packed_explicit,
10582 .type_struct_packed_auto_defaults,
10583 .type_struct_packed_explicit_defaults,
10584 .type_union,
10585 .type_union_packed_auto,
10586 .type_union_packed_explicit,
10587 .type_enum_auto,
11487 .type_enum_explicit,10588 .type_enum_explicit,
11488 .type_enum_nonexhaustive,10589 .type_enum_nonexhaustive,
11489 .type_enum_auto,
11490 .type_opaque,10590 .type_opaque,
11491 .type_struct,
11492 .type_struct_packed,
11493 .type_struct_packed_inits,
11494 .type_tuple,
11495 .type_union,
11496 .type_function,
11497 .undef,10591 .undef,
11498 .ptr_nav,10592 .ptr_nav,
11499 .ptr_comptime_alloc,10593 .ptr_comptime_alloc,
...@@ -11517,8 +10611,6 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {...@@ -11517,8 +10611,6 @@ fn dumpAllFallible(ip: *const InternPool, w: *Io.Writer) anyerror!void {
11517 .int_small,10611 .int_small,
11518 .int_positive,10612 .int_positive,
11519 .int_negative,10613 .int_negative,
11520 .int_lazy_align,
11521 .int_lazy_size,
11522 .error_set_error,10614 .error_set_error,
11523 .error_union_error,10615 .error_union_error,
11524 .error_union_payload,10616 .error_union_payload,
...@@ -12245,16 +11337,20 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -12245,16 +11337,20 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
12245 .type_anyerror_union,11337 .type_anyerror_union,
12246 .type_error_set,11338 .type_error_set,
12247 .type_inferred_error_set,11339 .type_inferred_error_set,
11340 .type_tuple,
11341 .type_function,
11342 .type_struct,
11343 .type_struct_packed_auto,
11344 .type_struct_packed_explicit,
11345 .type_struct_packed_auto_defaults,
11346 .type_struct_packed_explicit_defaults,
11347 .type_union,
11348 .type_union_packed_auto,
11349 .type_union_packed_explicit,
12248 .type_enum_auto,11350 .type_enum_auto,
12249 .type_enum_explicit,11351 .type_enum_explicit,
12250 .type_enum_nonexhaustive,11352 .type_enum_nonexhaustive,
12251 .type_opaque,11353 .type_opaque,
12252 .type_struct,
12253 .type_struct_packed,
12254 .type_struct_packed_inits,
12255 .type_tuple,
12256 .type_union,
12257 .type_function,
12258 => .type_type,11354 => .type_type,
1225911355
12260 .undef,11356 .undef,
...@@ -12278,8 +11374,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {...@@ -12278,8 +11374,6 @@ pub fn typeOf(ip: *const InternPool, index: Index) Index {
12278 .opt_payload,11374 .opt_payload,
12279 .error_union_payload,11375 .error_union_payload,
12280 .int_small,11376 .int_small,
12281 .int_lazy_align,
12282 .int_lazy_size,
12283 .error_set_error,11377 .error_set_error,
12284 .error_union_error,11378 .error_union_error,
12285 .enum_tag,11379 .enum_tag,
...@@ -12613,22 +11707,26 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {...@@ -12613,22 +11707,26 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
12613 .type_inferred_error_set,11707 .type_inferred_error_set,
12614 => .error_set,11708 => .error_set,
1261511709
12616 .type_enum_auto,
12617 .type_enum_explicit,
12618 .type_enum_nonexhaustive,
12619 => .@"enum",
12620
12621 .simple_type => unreachable, // handled via Index tag above11710 .simple_type => unreachable, // handled via Index tag above
1262211711
12623 .type_opaque => .@"opaque",11712 .type_tuple => .@"struct",
1262411713
12625 .type_struct,11714 .type_struct,
12626 .type_struct_packed,11715 .type_struct_packed_auto,
12627 .type_struct_packed_inits,11716 .type_struct_packed_explicit,
12628 .type_tuple,11717 .type_struct_packed_auto_defaults,
11718 .type_struct_packed_explicit_defaults,
12629 => .@"struct",11719 => .@"struct",
1263011720 .type_union,
12631 .type_union => .@"union",11721 .type_union_packed_auto,
11722 .type_union_packed_explicit,
11723 => .@"union",
11724 .type_enum_auto,
11725 .type_enum_explicit,
11726 .type_enum_nonexhaustive,
11727 => .@"enum",
11728 .type_opaque,
11729 => .@"opaque",
1263211730
12633 .type_function => .@"fn",11731 .type_function => .@"fn",
1263411732
...@@ -12658,8 +11756,6 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {...@@ -12658,8 +11756,6 @@ pub fn zigTypeTag(ip: *const InternPool, index: Index) std.builtin.TypeId {
12658 .int_small,11756 .int_small,
12659 .int_positive,11757 .int_positive,
12660 .int_negative,11758 .int_negative,
12661 .int_lazy_align,
12662 .int_lazy_size,
12663 .error_set_error,11759 .error_set_error,
12664 .error_union_error,11760 .error_union_error,
12665 .error_union_payload,11761 .error_union_payload,
...@@ -13169,3 +12265,113 @@ const PackedCallingConvention = packed struct(u18) {...@@ -13169,3 +12265,113 @@ const PackedCallingConvention = packed struct(u18) {
13169 };12265 };
13170 }12266 }
13171};12267};
12268
12269/// Asserts that `struct_type` is a non-packed struct type.
12270/// As well as calling this function, the caller must also populate these arrays:
12271/// * `field_types`
12272/// * `field_aligns`
12273/// * `field_runtime_order`
12274/// * `field_offsets`
12275pub fn resolveStructLayout(
12276 ip: *InternPool,
12277 io: Io,
12278 struct_type: Index,
12279 size: u32,
12280 alignment: Alignment,
12281 has_no_possible_value: bool,
12282 has_one_possible_value: bool,
12283 comptime_only: bool,
12284) void {
12285 const unwrapped_index = struct_type.unwrap(ip);
12286
12287 const local = ip.getLocal(unwrapped_index.tid);
12288 local.mutate.extra.mutex.lockUncancelable(io);
12289 defer local.mutate.extra.mutex.unlock(io);
12290
12291 const extra_items = local.shared.extra.view().items(.@"0");
12292 const item = unwrapped_index.getItem(ip);
12293 assert(item.tag == .type_struct);
12294
12295 extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "size").?] = size;
12296 const flags: *Tag.TypeStruct.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeStruct, "flags").?]);
12297 flags.has_no_possible_value = has_no_possible_value;
12298 flags.has_one_possible_value = has_one_possible_value;
12299 flags.comptime_only = comptime_only;
12300 flags.alignment = alignment;
12301}
12302
12303/// Asserts that `union_type` is a non-packed union type.
12304/// As well as calling this function, the caller must also populate these arrays:
12305/// * `field_types`
12306/// * `field_aligns`
12307pub fn resolveUnionLayout(
12308 ip: *InternPool,
12309 io: Io,
12310 union_type: Index,
12311 size: u32,
12312 padding: u32,
12313 alignment: Alignment,
12314 has_no_possible_value: bool,
12315 has_one_possible_value: bool,
12316 comptime_only: bool,
12317) void {
12318 const unwrapped_index = union_type.unwrap(ip);
12319
12320 const local = ip.getLocal(unwrapped_index.tid);
12321 local.mutate.extra.mutex.lockUncancelable(io);
12322 defer local.mutate.extra.mutex.unlock(io);
12323
12324 const extra_items = local.shared.extra.view().items(.@"0");
12325 const item = unwrapped_index.getItem(ip);
12326 assert(item.tag == .type_union);
12327
12328 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "size").?] = size;
12329 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "padding").?] = padding;
12330 const flags: *Tag.TypeUnion.Flags = @ptrCast(&extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnion, "flags").?]);
12331 flags.has_no_possible_value = has_no_possible_value;
12332 flags.has_one_possible_value = has_one_possible_value;
12333 flags.comptime_only = comptime_only;
12334 flags.alignment = alignment;
12335}
12336
12337/// Asserts that `struct_type` is a packed struct type.
12338pub fn resolvePackedStructBackingInt(ip: *InternPool, io: Io, struct_type: Index, backing_int_type: Index) void {
12339 const unwrapped_index = struct_type.unwrap(ip);
12340
12341 const local = ip.getLocal(unwrapped_index.tid);
12342 local.mutate.extra.mutex.lockUncancelable(io);
12343 defer local.mutate.extra.mutex.unlock(io);
12344
12345 const extra_items = local.shared.extra.view().items(.@"0");
12346 const item = unwrapped_index.getItem(ip);
12347 switch (item.tag) {
12348 .type_struct_packed_auto,
12349 .type_struct_packed_explicit,
12350 .type_struct_packed_auto_defaults,
12351 .type_struct_packed_explicit_defaults,
12352 => {},
12353 else => unreachable,
12354 }
12355
12356 extra_items[item.data + std.meta.fieldIndex(Tag.TypeStructPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);
12357}
12358
12359/// Asserts that `union_type` is a packed union type.
12360pub fn resolvePackedUnionBackingInt(ip: *InternPool, io: Io, union_type: Index, backing_int_type: Index) void {
12361 const unwrapped_index = union_type.unwrap(ip);
12362
12363 const local = ip.getLocal(unwrapped_index.tid);
12364 local.mutate.extra.mutex.lockUncancelable(io);
12365 defer local.mutate.extra.mutex.unlock(io);
12366
12367 const extra_items = local.shared.extra.view().items(.@"0");
12368 const item = unwrapped_index.getItem(ip);
12369 switch (item.tag) {
12370 .type_union_packed_auto,
12371 .type_union_packed_explicit,
12372 => {},
12373 else => unreachable,
12374 }
12375
12376 extra_items[item.data + std.meta.fieldIndex(Tag.TypeUnionPacked, "backing_int_type").?] = @intFromEnum(backing_int_type);
12377}
src/Sema.zig+2201-4328
...@@ -173,13 +173,17 @@ const ComptimeAlloc = struct {...@@ -173,13 +173,17 @@ const ComptimeAlloc = struct {
173 runtime_index: RuntimeIndex,173 runtime_index: RuntimeIndex,
174};174};
175175
176/// Asserts that `ty` is not an OPV type.
176/// `src` may be `null` if `is_const` will be set.177/// `src` may be `null` if `is_const` will be set.
177fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {178fn newComptimeAlloc(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type, alignment: Alignment) !ComptimeAllocIndex {
178 const pt = sema.pt;179 const pt = sema.pt;
179 const init_val = try sema.typeHasOnePossibleValue(ty) orelse try pt.undefValue(ty);180
181 // Explicit guard because this call mutates the InternPool so cannot be optimized out.
182 if (std.debug.runtime_safety) assert(ty.onePossibleValue(pt) catch @panic("") == null);
183
180 const idx = sema.comptime_allocs.items.len;184 const idx = sema.comptime_allocs.items.len;
181 try sema.comptime_allocs.append(sema.gpa, .{185 try sema.comptime_allocs.append(sema.gpa, .{
182 .val = .{ .interned = init_val.toIntern() },186 .val = .{ .interned = (try pt.undefValue(ty)).toIntern() },
183 .is_const = false,187 .is_const = false,
184 .src = src,188 .src = src,
185 .alignment = alignment,189 .alignment = alignment,
...@@ -1382,10 +1386,10 @@ fn analyzeBodyInner(...@@ -1382,10 +1386,10 @@ fn analyzeBodyInner(
1382 const extended = datas[@intFromEnum(inst)].extended;1386 const extended = datas[@intFromEnum(inst)].extended;
1383 break :ext switch (extended.opcode) {1387 break :ext switch (extended.opcode) {
1384 // zig fmt: off1388 // zig fmt: off
1385 .struct_decl => try sema.zirStructDecl( block, extended, inst),1389 .struct_decl => try sema.zirStructDecl( block, inst),
1386 .enum_decl => try sema.zirEnumDecl( block, extended, inst),1390 .enum_decl => try sema.zirEnumDecl( block, inst),
1387 .union_decl => try sema.zirUnionDecl( block, extended, inst),1391 .union_decl => try sema.zirUnionDecl( block, inst),
1388 .opaque_decl => try sema.zirOpaqueDecl( block, extended, inst),1392 .opaque_decl => try sema.zirOpaqueDecl( block, inst),
1389 .tuple_decl => try sema.zirTupleDecl( block, extended),1393 .tuple_decl => try sema.zirTupleDecl( block, extended),
1390 .this => try sema.zirThis( block, extended),1394 .this => try sema.zirThis( block, extended),
1391 .ret_addr => try sema.zirRetAddr( block, extended),1395 .ret_addr => try sema.zirRetAddr( block, extended),
...@@ -1993,6 +1997,24 @@ fn analyzeBodyInner(...@@ -1993,6 +1997,24 @@ fn analyzeBodyInner(
1993 assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));1997 assert(sema.isNoReturn(block.instructions.items[block.instructions.items.len - 1].toRef()));
1994 break;1998 break;
1995 }1999 }
2000 // <MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK>
2001 if (air_inst.toIndex()) |air_inst_index| {
2002 switch (sema.air_instructions.items(.tag)[@intFromEnum(air_inst_index)]) {
2003 .inferred_alloc, .inferred_alloc_comptime => {},
2004 else => {
2005 assert(sema.typeOf(air_inst).onePossibleValue(pt) catch @panic("") == null);
2006 sema.typeOf(air_inst).assertHasLayout(zcu);
2007 },
2008 }
2009 } else {
2010 switch (tags[@intFromEnum(inst)]) {
2011 // MLUGG TODO: do we actually *want* this exception? we could arguably simplify things without it
2012 // e.g. analyzeNavVal could stop doing ensureLayoutResolved in most cases (`extern` is an exception) and instead do `assertHasLayout`
2013 .func, .func_inferred, .func_fancy => {}, // exception: we're in a func decl, layout will get resolved in a bit by `analyzeNavVal`
2014 else => sema.typeOf(air_inst).assertHasLayout(zcu),
2015 }
2016 }
2017 // </MLUGG TODO REMOVE THIS BLOCK, SILLY OPV CHECK>
1996 map.putAssumeCapacity(inst, air_inst);2018 map.putAssumeCapacity(inst, air_inst);
1997 i += 1;2019 i += 1;
1998 }2020 }
...@@ -2190,7 +2212,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi...@@ -2190,7 +2212,7 @@ fn genericPoisonReason(sema: *Sema, block: *Block, ref: Zir.Inst.Ref) GenericPoi
2190 }2212 }
2191}2213}
21922214
2193fn analyzeAsType(2215pub fn analyzeAsType(
2194 sema: *Sema,2216 sema: *Sema,
2195 block: *Block,2217 block: *Block,
2196 src: LazySrcLoc,2218 src: LazySrcLoc,
...@@ -2227,7 +2249,6 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)...@@ -2227,7 +2249,6 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
22272249
2228 // var st: StackTrace = undefined;2250 // var st: StackTrace = undefined;
2229 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);2251 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
2230 try stack_trace_ty.resolveFields(pt);
2231 const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty));2252 const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty));
22322253
2233 // st.instruction_addresses = &addrs;2254 // st.instruction_addresses = &addrs;
...@@ -2247,14 +2268,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)...@@ -2247,14 +2268,11 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
2247}2268}
22482269
2249/// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value.2270/// Return the Value corresponding to a given AIR ref, or `null` if it refers to a runtime value.
2250fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {2271/// TODO MLUGG: remove the error union return!
2272fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) error{}!?Value {
2251 const zcu = sema.pt.zcu;2273 const zcu = sema.pt.zcu;
2252 assert(inst != .none);2274 assert(inst != .none);
22532275
2254 if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
2255 return opv;
2256 }
2257
2258 if (inst.toInterned()) |ip_index| {2276 if (inst.toInterned()) |ip_index| {
2259 const val: Value = .fromInterned(ip_index);2277 const val: Value = .fromInterned(ip_index);
2260 assert(val.getVariable(zcu) == null);2278 assert(val.getVariable(zcu) == null);
...@@ -2267,12 +2285,18 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {...@@ -2267,12 +2285,18 @@ fn resolveValue(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
2267 .inferred_alloc_comptime => unreachable, // assertion failure2285 .inferred_alloc_comptime => unreachable, // assertion failure
2268 else => {},2286 else => {},
2269 }2287 }
2288 // Assert that the type is not OPV -- if it was, the value would have been comptime-known.
2289 // Explicit guard because this could add to the InternPool so cannot be optimized away.
2290 if (std.debug.runtime_safety) {
2291 const opv = sema.typeOf(inst).onePossibleValue(sema.pt) catch @panic("oom in assert");
2292 assert(opv == null);
2293 }
2270 return null;2294 return null;
2271 }2295 }
2272}2296}
22732297
2274/// Like `resolveValue`, but emits an error if the value is not comptime-known.2298/// Like `resolveValue`, but emits an error if the value is not comptime-known.
2275fn resolveConstValue(2299pub fn resolveConstValue(
2276 sema: *Sema,2300 sema: *Sema,
2277 block: *Block,2301 block: *Block,
2278 src: LazySrcLoc,2302 src: LazySrcLoc,
...@@ -2301,7 +2325,7 @@ fn resolveDefinedValue(...@@ -2301,7 +2325,7 @@ fn resolveDefinedValue(
2301}2325}
23022326
2303/// Like `resolveValue`, but emits an error if the value is not comptime-known or is undefined.2327/// Like `resolveValue`, but emits an error if the value is not comptime-known or is undefined.
2304fn resolveConstDefinedValue(2328pub fn resolveConstDefinedValue(
2305 sema: *Sema,2329 sema: *Sema,
2306 block: *Block,2330 block: *Block,
2307 src: LazySrcLoc,2331 src: LazySrcLoc,
...@@ -2315,11 +2339,6 @@ fn resolveConstDefinedValue(...@@ -2315,11 +2339,6 @@ fn resolveConstDefinedValue(
2315 return val;2339 return val;
2316}2340}
23172341
2318/// Like `resolveValue`, but recursively resolves lazy values before returning.
2319fn resolveValueResolveLazy(sema: *Sema, inst: Air.Inst.Ref) CompileError!?Value {
2320 return try sema.resolveLazyValue((try sema.resolveValue(inst)) orelse return null);
2321}
2322
2323/// Value Tag may be `undef` or `variable`.2342/// Value Tag may be `undef` or `variable`.
2324pub fn resolveFinalDeclValue(2343pub fn resolveFinalDeclValue(
2325 sema: *Sema,2344 sema: *Sema,
...@@ -2439,13 +2458,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non...@@ -2439,13 +2458,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, non
24392458
2440fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {2459fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
2441 const pt = sema.pt;2460 const pt = sema.pt;
2461 const zcu = pt.zcu;
2442 const msg = msg: {2462 const msg = msg: {
2443 const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{2463 const msg = try sema.errMsg(src, "type '{f}' does not support array initialization syntax", .{
2444 ty.fmt(pt),2464 ty.fmt(pt),
2445 });2465 });
2446 errdefer msg.destroy(sema.gpa);2466 errdefer msg.destroy(sema.gpa);
2447 if (ty.isSlice(pt.zcu)) {2467 if (ty.isSlice(zcu)) {
2448 try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.elemType2(pt.zcu).fmt(pt)});2468 try sema.errNote(src, msg, "inferred array length is specified with an underscore: '[_]{f}'", .{ty.childType(zcu).fmt(pt)});
2449 }2469 }
2450 break :msg msg;2470 break :msg msg;
2451 };2471 };
...@@ -2644,7 +2664,7 @@ pub fn fail(...@@ -2644,7 +2664,7 @@ pub fn fail(
2644 src: LazySrcLoc,2664 src: LazySrcLoc,
2645 comptime format: []const u8,2665 comptime format: []const u8,
2646 args: anytype,2666 args: anytype,
2647) CompileError {2667) SemaError {
2648 const err_msg = try sema.errMsg(src, format, args);2668 const err_msg = try sema.errMsg(src, format, args);
2649 inline for (args) |arg| {2669 inline for (args) |arg| {
2650 if (@TypeOf(arg) == Type.Formatter) {2670 if (@TypeOf(arg) == Type.Formatter) {
...@@ -2798,27 +2818,26 @@ fn analyzeAsInt(...@@ -2798,27 +2818,26 @@ fn analyzeAsInt(
2798) !u64 {2818) !u64 {
2799 const coerced = try sema.coerce(block, dest_ty, air_ref, src);2819 const coerced = try sema.coerce(block, dest_ty, air_ref, src);
2800 const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);2820 const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
2801 return try val.toUnsignedIntSema(sema.pt);2821 return val.toUnsignedInt(sema.pt.zcu);
2802}2822}
28032823
2804fn analyzeValueAsCallconv(2824fn analyzeValueAsCallconv(
2805 sema: *Sema,2825 sema: *Sema,
2806 block: *Block,2826 block: *Block,
2807 src: LazySrcLoc,2827 src: LazySrcLoc,
2808 unresolved_val: Value,2828 val: Value,
2809) !std.builtin.CallingConvention {2829) !std.builtin.CallingConvention {
2810 return interpretBuiltinType(sema, block, src, unresolved_val, std.builtin.CallingConvention);2830 return interpretBuiltinType(sema, block, src, val, std.builtin.CallingConvention);
2811}2831}
28122832
2813fn interpretBuiltinType(2833fn interpretBuiltinType(
2814 sema: *Sema,2834 sema: *Sema,
2815 block: *Block,2835 block: *Block,
2816 src: LazySrcLoc,2836 src: LazySrcLoc,
2817 unresolved_val: Value,2837 val: Value,
2818 comptime T: type,2838 comptime T: type,
2819) !T {2839) !T {
2820 const resolved_val = try sema.resolveLazyValue(unresolved_val);2840 return val.interpret(T, sema.pt) catch |err| switch (err) {
2821 return resolved_val.interpret(T, sema.pt) catch |err| switch (err) {
2822 error.OutOfMemory => |e| return e,2841 error.OutOfMemory => |e| return e,
2823 error.UndefinedValue => return sema.failWithUseOfUndef(block, src, null),2842 error.UndefinedValue => return sema.failWithUseOfUndef(block, src, null),
2824 error.TypeMismatch => @panic("std.builtin is corrupt"),2843 error.TypeMismatch => @panic("std.builtin is corrupt"),
...@@ -2913,7 +2932,13 @@ fn validateTupleFieldType(...@@ -2913,7 +2932,13 @@ fn validateTupleFieldType(
29132932
2914/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,2933/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
2915/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.2934/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
2916fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {2935fn getCaptures(
2936 sema: *Sema,
2937 block: *Block,
2938 type_src: LazySrcLoc,
2939 zir_captures: []const Zir.Inst.Capture,
2940 zir_capture_names: []const Zir.NullTerminatedString,
2941) ![]InternPool.CaptureValue {
2917 const pt = sema.pt;2942 const pt = sema.pt;
2918 const zcu = pt.zcu;2943 const zcu = pt.zcu;
2919 const comp = zcu.comp;2944 const comp = zcu.comp;
...@@ -2924,41 +2949,38 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us...@@ -2924,41 +2949,38 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
2924 const parent_ty: Type = .fromInterned(zcu.namespacePtr(block.namespace).owner_type);2949 const parent_ty: Type = .fromInterned(zcu.namespacePtr(block.namespace).owner_type);
2925 const parent_captures: InternPool.CaptureValue.Slice = parent_ty.getCaptures(zcu);2950 const parent_captures: InternPool.CaptureValue.Slice = parent_ty.getCaptures(zcu);
29262951
2927 const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);2952 const captures = try sema.arena.alloc(InternPool.CaptureValue, zir_captures.len);
29282953
2929 for (sema.code.extra[extra_index..][0..captures_len], sema.code.extra[extra_index + captures_len ..][0..captures_len], captures) |raw, raw_name, *capture| {2954 for (zir_captures, zir_capture_names, captures) |zir_capture, zir_name, *capture| {
2930 const zir_capture: Zir.Inst.Capture = @bitCast(raw);
2931 const zir_name: Zir.NullTerminatedString = @enumFromInt(raw_name);
2932 const zir_name_slice = sema.code.nullTerminatedString(zir_name);2955 const zir_name_slice = sema.code.nullTerminatedString(zir_name);
2933 capture.* = switch (zir_capture.unwrap()) {2956 capture.* = switch (zir_capture.unwrap()) {
2934 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],2957 .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
2935 .instruction_load => |ptr_inst| InternPool.CaptureValue.wrap(capture: {2958 .instruction_load => |ptr_inst| capture: {
2936 const ptr_ref = try sema.resolveInst(ptr_inst.toRef());2959 const ptr_ref = try sema.resolveInst(ptr_inst.toRef());
2937 const ptr_val = try sema.resolveValue(ptr_ref) orelse {2960 const ptr_val = try sema.resolveValue(ptr_ref) orelse {
2938 break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() };2961 break :capture .wrap(.{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() });
2939 };2962 };
2940 // TODO: better source location2963 // TODO: better source location
2941 const unresolved_loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse {2964 const loaded_val = try sema.pointerDeref(block, type_src, ptr_val, sema.typeOf(ptr_ref)) orelse {
2942 break :capture .{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() };2965 break :capture .wrap(.{ .runtime = sema.typeOf(ptr_ref).childType(zcu).toIntern() });
2943 };2966 };
2944 const loaded_val = try sema.resolveLazyValue(unresolved_loaded_val);
2945 if (loaded_val.canMutateComptimeVarState(zcu)) {2967 if (loaded_val.canMutateComptimeVarState(zcu)) {
2946 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);2968 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);
2947 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val);2969 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", loaded_val);
2948 }2970 }
2949 break :capture .{ .@"comptime" = loaded_val.toIntern() };2971 break :capture .wrap(.{ .@"comptime" = loaded_val.toIntern() });
2950 }),2972 },
2951 .instruction => |inst| InternPool.CaptureValue.wrap(capture: {2973 .instruction => |inst| capture: {
2952 const air_ref = try sema.resolveInst(inst.toRef());2974 const air_ref = try sema.resolveInst(inst.toRef());
2953 if (try sema.resolveValueResolveLazy(air_ref)) |val| {2975 if (try sema.resolveValue(air_ref)) |val| {
2954 if (val.canMutateComptimeVarState(zcu)) {2976 if (val.canMutateComptimeVarState(zcu)) {
2955 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);2977 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_name_slice, .no_embedded_nulls);
2956 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val);2978 return sema.failWithContainsReferenceToComptimeVar(block, type_src, field_name, "captured value", val);
2957 }2979 }
2958 break :capture .{ .@"comptime" = val.toIntern() };2980 break :capture .wrap(.{ .@"comptime" = val.toIntern() });
2959 }2981 }
2960 break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };2982 break :capture .wrap(.{ .runtime = sema.typeOf(air_ref).toIntern() });
2961 }),2983 },
2962 .decl_val => |str| capture: {2984 .decl_val => |str| capture: {
2963 const decl_name = try ip.getOrPutString(2985 const decl_name = try ip.getOrPutString(
2964 gpa,2986 gpa,
...@@ -2968,7 +2990,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us...@@ -2968,7 +2990,7 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
2968 .no_embedded_nulls,2990 .no_embedded_nulls,
2969 );2991 );
2970 const nav = try sema.lookupIdentifier(block, decl_name);2992 const nav = try sema.lookupIdentifier(block, decl_name);
2971 break :capture InternPool.CaptureValue.wrap(.{ .nav_val = nav });2993 break :capture .wrap(.{ .nav_val = nav });
2972 },2994 },
2973 .decl_ref => |str| capture: {2995 .decl_ref => |str| capture: {
2974 const decl_name = try ip.getOrPutString(2996 const decl_name = try ip.getOrPutString(
...@@ -2987,621 +3009,6 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us...@@ -2987,621 +3009,6 @@ fn getCaptures(sema: *Sema, block: *Block, type_src: LazySrcLoc, extra_index: us
2987 return captures;3009 return captures;
2988}3010}
29893011
2990fn zirStructDecl(
2991 sema: *Sema,
2992 block: *Block,
2993 extended: Zir.Inst.Extended.InstData,
2994 inst: Zir.Inst.Index,
2995) CompileError!Air.Inst.Ref {
2996 const pt = sema.pt;
2997 const zcu = pt.zcu;
2998 const comp = zcu.comp;
2999 const gpa = comp.gpa;
3000 const io = comp.io;
3001 const ip = &zcu.intern_pool;
3002
3003 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
3004 const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand);
3005
3006 const tracked_inst = try block.trackZir(inst);
3007 const src: LazySrcLoc = .{
3008 .base_node_inst = tracked_inst,
3009 .offset = LazySrcLoc.Offset.nodeOffset(.zero),
3010 };
3011
3012 var extra_index = extra.end;
3013
3014 const captures_len = if (small.has_captures_len) blk: {
3015 const captures_len = sema.code.extra[extra_index];
3016 extra_index += 1;
3017 break :blk captures_len;
3018 } else 0;
3019 const fields_len = if (small.has_fields_len) blk: {
3020 const fields_len = sema.code.extra[extra_index];
3021 extra_index += 1;
3022 break :blk fields_len;
3023 } else 0;
3024 const decls_len = if (small.has_decls_len) blk: {
3025 const decls_len = sema.code.extra[extra_index];
3026 extra_index += 1;
3027 break :blk decls_len;
3028 } else 0;
3029
3030 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3031 extra_index += captures_len * 2;
3032
3033 if (small.has_backing_int) {
3034 const backing_int_body_len = sema.code.extra[extra_index];
3035 extra_index += 1; // backing_int_body_len
3036 if (backing_int_body_len == 0) {
3037 extra_index += 1; // backing_int_ref
3038 } else {
3039 extra_index += backing_int_body_len; // backing_int_body_inst
3040 }
3041 }
3042
3043 const struct_init: InternPool.StructTypeInit = .{
3044 .layout = small.layout,
3045 .fields_len = fields_len,
3046 .known_non_opv = small.known_non_opv,
3047 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
3048 .any_comptime_fields = small.any_comptime_fields,
3049 .any_default_inits = small.any_default_inits,
3050 .inits_resolved = false,
3051 .any_aligned_fields = small.any_aligned_fields,
3052 .key = .{ .declared = .{
3053 .zir_index = tracked_inst,
3054 .captures = captures,
3055 } },
3056 };
3057 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, struct_init, false)) {
3058 .existing => |ty| {
3059 const new_ty = try pt.ensureTypeUpToDate(ty);
3060
3061 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3062 // up on e.g. changed comptime decls.
3063 try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu));
3064
3065 try sema.declareDependency(.{ .interned = new_ty });
3066 try sema.addTypeReferenceEntry(src, new_ty);
3067 return Air.internedToRef(new_ty);
3068 },
3069 .wip => |wip| wip,
3070 };
3071 errdefer wip_ty.cancel(ip, pt.tid);
3072
3073 const type_name = try sema.createTypeName(
3074 block,
3075 small.name_strategy,
3076 "struct",
3077 inst,
3078 wip_ty.index,
3079 );
3080 wip_ty.setName(ip, type_name.name, type_name.nav);
3081
3082 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3083 .parent = block.namespace.toOptional(),
3084 .owner_type = wip_ty.index,
3085 .file_scope = block.getFileScopeIndex(zcu),
3086 .generation = zcu.generation,
3087 });
3088 errdefer pt.destroyNamespace(new_namespace_index);
3089
3090 if (pt.zcu.comp.config.incremental) {
3091 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
3092 }
3093
3094 const decls = sema.code.bodySlice(extra_index, decls_len);
3095 try pt.scanNamespace(new_namespace_index, decls);
3096
3097 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3098 codegen_type: {
3099 if (zcu.comp.config.use_llvm) break :codegen_type;
3100 if (block.ownerModule().strip) break :codegen_type;
3101 // This job depends on any resolve_type_fully jobs queued up before it.
3102 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
3103 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3104 }
3105 try sema.declareDependency(.{ .interned = wip_ty.index });
3106 try sema.addTypeReferenceEntry(src, wip_ty.index);
3107 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
3108 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
3109}
3110
3111pub fn createTypeName(
3112 sema: *Sema,
3113 block: *Block,
3114 name_strategy: Zir.Inst.NameStrategy,
3115 anon_prefix: []const u8,
3116 inst: ?Zir.Inst.Index,
3117 /// This is used purely to give the type a unique name in the `anon` case.
3118 type_index: InternPool.Index,
3119) CompileError!struct {
3120 name: InternPool.NullTerminatedString,
3121 nav: InternPool.Nav.Index.Optional,
3122} {
3123 const pt = sema.pt;
3124 const zcu = pt.zcu;
3125 const comp = zcu.comp;
3126 const gpa = comp.gpa;
3127 const io = comp.io;
3128 const ip = &zcu.intern_pool;
3129
3130 switch (name_strategy) {
3131 .anon => {}, // handled after switch
3132 .parent => return .{
3133 .name = block.type_name_ctx,
3134 .nav = sema.owner.unwrap().nav_val.toOptional(),
3135 },
3136 .func => func_strat: {
3137 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
3138 const zir_tags = sema.code.instructions.items(.tag);
3139
3140 var aw: std.Io.Writer.Allocating = .init(gpa);
3141 defer aw.deinit();
3142 const w = &aw.writer;
3143 w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory;
3144
3145 var arg_i: usize = 0;
3146 for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
3147 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
3148 const arg = sema.inst_map.get(zir_inst).?;
3149 // If this is being called in a generic function then analyzeCall will
3150 // have already resolved the args and this will work.
3151 // If not then this is a struct type being returned from a non-generic
3152 // function and the name doesn't matter since it will later
3153 // result in a compile error.
3154 const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat
3155
3156 if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
3157
3158 // Limiting the depth here helps avoid type names getting too long, which
3159 // in turn helps to avoid unreasonably long symbol names for namespaced
3160 // symbols. Such names should ideally be human-readable, and additionally,
3161 // some tooling may not support very long symbol names.
3162 w.print("{f}", .{Value.fmtValueSemaFull(.{
3163 .val = arg_val,
3164 .pt = pt,
3165 .opt_sema = sema,
3166 .depth = 1,
3167 })}) catch return error.OutOfMemory;
3168
3169 arg_i += 1;
3170 continue;
3171 },
3172 else => continue,
3173 };
3174
3175 w.writeByte(')') catch return error.OutOfMemory;
3176 return .{
3177 .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls),
3178 .nav = .none,
3179 };
3180 },
3181 .dbg_var => {
3182 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
3183 const ref = inst.?.toRef();
3184 const zir_tags = sema.code.instructions.items(.tag);
3185 const zir_data = sema.code.instructions.items(.data);
3186 for (@intFromEnum(inst.?)..zir_tags.len) |i| switch (zir_tags[i]) {
3187 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
3188 return .{
3189 .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
3190 block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
3191 }, .no_embedded_nulls),
3192 .nav = .none,
3193 };
3194 },
3195 else => {},
3196 };
3197 // fall through to anon strat
3198 },
3199 }
3200
3201 // anon strat handling
3202
3203 // It would be neat to have "struct:line:column" but this name has
3204 // to survive incremental updates, where it may have been shifted down
3205 // or up to a different line, but unchanged, and thus not unnecessarily
3206 // semantically analyzed.
3207 // TODO: that would be possible, by detecting line number changes and renaming
3208 // types appropriately. However, `@typeName` becomes a problem then. If we remove
3209 // that builtin from the language, we can consider this.
3210
3211 return .{
3212 .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}__{s}_{d}", .{
3213 block.type_name_ctx.fmt(ip), anon_prefix, @intFromEnum(type_index),
3214 }, .no_embedded_nulls),
3215 .nav = .none,
3216 };
3217}
3218
3219fn zirEnumDecl(
3220 sema: *Sema,
3221 block: *Block,
3222 extended: Zir.Inst.Extended.InstData,
3223 inst: Zir.Inst.Index,
3224) CompileError!Air.Inst.Ref {
3225 const tracy = trace(@src());
3226 defer tracy.end();
3227
3228 const pt = sema.pt;
3229 const zcu = pt.zcu;
3230 const comp = zcu.comp;
3231 const gpa = comp.gpa;
3232 const io = comp.io;
3233 const ip = &zcu.intern_pool;
3234
3235 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
3236 const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
3237 var extra_index: usize = extra.end;
3238
3239 const tracked_inst = try block.trackZir(inst);
3240 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
3241
3242 const tag_type_ref = if (small.has_tag_type) blk: {
3243 const tag_type_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
3244 extra_index += 1;
3245 break :blk tag_type_ref;
3246 } else .none;
3247
3248 const captures_len = if (small.has_captures_len) blk: {
3249 const captures_len = sema.code.extra[extra_index];
3250 extra_index += 1;
3251 break :blk captures_len;
3252 } else 0;
3253
3254 const body_len = if (small.has_body_len) blk: {
3255 const body_len = sema.code.extra[extra_index];
3256 extra_index += 1;
3257 break :blk body_len;
3258 } else 0;
3259
3260 const fields_len = if (small.has_fields_len) blk: {
3261 const fields_len = sema.code.extra[extra_index];
3262 extra_index += 1;
3263 break :blk fields_len;
3264 } else 0;
3265
3266 const decls_len = if (small.has_decls_len) blk: {
3267 const decls_len = sema.code.extra[extra_index];
3268 extra_index += 1;
3269 break :blk decls_len;
3270 } else 0;
3271
3272 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3273 extra_index += captures_len * 2;
3274
3275 const decls = sema.code.bodySlice(extra_index, decls_len);
3276 extra_index += decls_len;
3277
3278 const body = sema.code.bodySlice(extra_index, body_len);
3279 extra_index += body.len;
3280
3281 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
3282 const body_end = extra_index;
3283 extra_index += bit_bags_count;
3284
3285 const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
3286 if (bag != 0) break true;
3287 } else false;
3288
3289 const enum_init: InternPool.EnumTypeInit = .{
3290 .has_values = any_values,
3291 .tag_mode = if (small.nonexhaustive)
3292 .nonexhaustive
3293 else if (tag_type_ref == .none)
3294 .auto
3295 else
3296 .explicit,
3297 .fields_len = fields_len,
3298 .key = .{ .declared = .{
3299 .zir_index = tracked_inst,
3300 .captures = captures,
3301 } },
3302 };
3303 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, enum_init, false)) {
3304 .existing => |ty| {
3305 const new_ty = try pt.ensureTypeUpToDate(ty);
3306
3307 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3308 // up on e.g. changed comptime decls.
3309 try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu));
3310
3311 try sema.declareDependency(.{ .interned = new_ty });
3312 try sema.addTypeReferenceEntry(src, new_ty);
3313
3314 // Since this is an enum, it has to be resolved immediately.
3315 // `ensureTypeUpToDate` has resolved the new type if necessary.
3316 // We just need to check for resolution failures.
3317 const ty_unit: AnalUnit = .wrap(.{ .type = new_ty });
3318 if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) {
3319 return error.AnalysisFail;
3320 }
3321
3322 return Air.internedToRef(new_ty);
3323 },
3324 .wip => |wip| wip,
3325 };
3326
3327 // Once this is `true`, we will not delete the decl or type even upon failure, since we
3328 // have finished constructing the type and are in the process of analyzing it.
3329 var done = false;
3330
3331 errdefer if (!done) wip_ty.cancel(ip, pt.tid);
3332
3333 const type_name = try sema.createTypeName(
3334 block,
3335 small.name_strategy,
3336 "enum",
3337 inst,
3338 wip_ty.index,
3339 );
3340 wip_ty.setName(ip, type_name.name, type_name.nav);
3341
3342 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3343 .parent = block.namespace.toOptional(),
3344 .owner_type = wip_ty.index,
3345 .file_scope = block.getFileScopeIndex(zcu),
3346 .generation = zcu.generation,
3347 });
3348 errdefer if (!done) pt.destroyNamespace(new_namespace_index);
3349
3350 try pt.scanNamespace(new_namespace_index, decls);
3351
3352 try sema.declareDependency(.{ .interned = wip_ty.index });
3353 try sema.addTypeReferenceEntry(src, wip_ty.index);
3354
3355 // We've finished the initial construction of this type, and are about to perform analysis.
3356 // Set the namespace appropriately, and don't destroy anything on failure.
3357 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
3358 wip_ty.prepare(ip, new_namespace_index);
3359 done = true;
3360
3361 {
3362 const tracked_unit = zcu.trackUnitSema(type_name.name.toSlice(ip), null);
3363 defer tracked_unit.end(zcu);
3364 try Sema.resolveDeclaredEnum(
3365 pt,
3366 wip_ty,
3367 inst,
3368 tracked_inst,
3369 new_namespace_index,
3370 type_name.name,
3371 small,
3372 body,
3373 tag_type_ref,
3374 any_values,
3375 fields_len,
3376 sema.code,
3377 body_end,
3378 );
3379 }
3380
3381 codegen_type: {
3382 if (zcu.comp.config.use_llvm) break :codegen_type;
3383 if (block.ownerModule().strip) break :codegen_type;
3384 // This job depends on any resolve_type_fully jobs queued up before it.
3385 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
3386 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3387 }
3388 return Air.internedToRef(wip_ty.index);
3389}
3390
3391fn zirUnionDecl(
3392 sema: *Sema,
3393 block: *Block,
3394 extended: Zir.Inst.Extended.InstData,
3395 inst: Zir.Inst.Index,
3396) CompileError!Air.Inst.Ref {
3397 const tracy = trace(@src());
3398 defer tracy.end();
3399
3400 const pt = sema.pt;
3401 const zcu = pt.zcu;
3402 const comp = zcu.comp;
3403 const gpa = comp.gpa;
3404 const io = comp.io;
3405 const ip = &zcu.intern_pool;
3406
3407 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
3408 const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
3409 var extra_index: usize = extra.end;
3410
3411 const tracked_inst = try block.trackZir(inst);
3412 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
3413
3414 extra_index += @intFromBool(small.has_tag_type);
3415 const captures_len = if (small.has_captures_len) blk: {
3416 const captures_len = sema.code.extra[extra_index];
3417 extra_index += 1;
3418 break :blk captures_len;
3419 } else 0;
3420 extra_index += @intFromBool(small.has_body_len);
3421 const fields_len = if (small.has_fields_len) blk: {
3422 const fields_len = sema.code.extra[extra_index];
3423 extra_index += 1;
3424 break :blk fields_len;
3425 } else 0;
3426
3427 const decls_len = if (small.has_decls_len) blk: {
3428 const decls_len = sema.code.extra[extra_index];
3429 extra_index += 1;
3430 break :blk decls_len;
3431 } else 0;
3432
3433 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3434 extra_index += captures_len * 2;
3435
3436 const union_init: InternPool.UnionTypeInit = .{
3437 .flags = .{
3438 .layout = small.layout,
3439 .status = .none,
3440 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
3441 .tagged
3442 else if (small.layout != .auto)
3443 .none
3444 else switch (block.wantSafeTypes()) {
3445 true => .safety,
3446 false => .none,
3447 },
3448 .any_aligned_fields = small.any_aligned_fields,
3449 .requires_comptime = .unknown,
3450 .assumed_runtime_bits = false,
3451 .assumed_pointer_aligned = false,
3452 .alignment = .none,
3453 },
3454 .fields_len = fields_len,
3455 .enum_tag_ty = .none, // set later
3456 .field_types = &.{}, // set later
3457 .field_aligns = &.{}, // set later
3458 .key = .{ .declared = .{
3459 .zir_index = tracked_inst,
3460 .captures = captures,
3461 } },
3462 };
3463 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, union_init, false)) {
3464 .existing => |ty| {
3465 const new_ty = try pt.ensureTypeUpToDate(ty);
3466
3467 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3468 // up on e.g. changed comptime decls.
3469 try pt.ensureNamespaceUpToDate(Type.fromInterned(new_ty).getNamespaceIndex(zcu));
3470
3471 try sema.declareDependency(.{ .interned = new_ty });
3472 try sema.addTypeReferenceEntry(src, new_ty);
3473 return Air.internedToRef(new_ty);
3474 },
3475 .wip => |wip| wip,
3476 };
3477 errdefer wip_ty.cancel(ip, pt.tid);
3478
3479 const type_name = try sema.createTypeName(
3480 block,
3481 small.name_strategy,
3482 "union",
3483 inst,
3484 wip_ty.index,
3485 );
3486 wip_ty.setName(ip, type_name.name, type_name.nav);
3487
3488 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3489 .parent = block.namespace.toOptional(),
3490 .owner_type = wip_ty.index,
3491 .file_scope = block.getFileScopeIndex(zcu),
3492 .generation = zcu.generation,
3493 });
3494 errdefer pt.destroyNamespace(new_namespace_index);
3495
3496 if (pt.zcu.comp.config.incremental) {
3497 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
3498 }
3499
3500 const decls = sema.code.bodySlice(extra_index, decls_len);
3501 try pt.scanNamespace(new_namespace_index, decls);
3502
3503 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
3504 codegen_type: {
3505 if (zcu.comp.config.use_llvm) break :codegen_type;
3506 if (block.ownerModule().strip) break :codegen_type;
3507 // This job depends on any resolve_type_fully jobs queued up before it.
3508 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
3509 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3510 }
3511 try sema.declareDependency(.{ .interned = wip_ty.index });
3512 try sema.addTypeReferenceEntry(src, wip_ty.index);
3513 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
3514 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
3515}
3516
3517fn zirOpaqueDecl(
3518 sema: *Sema,
3519 block: *Block,
3520 extended: Zir.Inst.Extended.InstData,
3521 inst: Zir.Inst.Index,
3522) CompileError!Air.Inst.Ref {
3523 const tracy = trace(@src());
3524 defer tracy.end();
3525
3526 const pt = sema.pt;
3527 const zcu = pt.zcu;
3528 const comp = zcu.comp;
3529 const gpa = comp.gpa;
3530 const io = comp.io;
3531 const ip = &zcu.intern_pool;
3532
3533 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
3534 const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
3535 var extra_index: usize = extra.end;
3536
3537 const tracked_inst = try block.trackZir(inst);
3538 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
3539
3540 const captures_len = if (small.has_captures_len) blk: {
3541 const captures_len = sema.code.extra[extra_index];
3542 extra_index += 1;
3543 break :blk captures_len;
3544 } else 0;
3545
3546 const decls_len = if (small.has_decls_len) blk: {
3547 const decls_len = sema.code.extra[extra_index];
3548 extra_index += 1;
3549 break :blk decls_len;
3550 } else 0;
3551
3552 const captures = try sema.getCaptures(block, src, extra_index, captures_len);
3553 extra_index += captures_len * 2;
3554
3555 const opaque_init: InternPool.OpaqueTypeInit = .{
3556 .zir_index = tracked_inst,
3557 .captures = captures,
3558 };
3559 const wip_ty = switch (try ip.getOpaqueType(gpa, io, pt.tid, opaque_init)) {
3560 .existing => |ty| {
3561 // Make sure we update the namespace if the declaration is re-analyzed, to pick
3562 // up on e.g. changed comptime decls.
3563 try pt.ensureNamespaceUpToDate(Type.fromInterned(ty).getNamespaceIndex(zcu));
3564
3565 try sema.declareDependency(.{ .interned = ty });
3566 try sema.addTypeReferenceEntry(src, ty);
3567 return Air.internedToRef(ty);
3568 },
3569 .wip => |wip| wip,
3570 };
3571 errdefer wip_ty.cancel(ip, pt.tid);
3572
3573 const type_name = try sema.createTypeName(
3574 block,
3575 small.name_strategy,
3576 "opaque",
3577 inst,
3578 wip_ty.index,
3579 );
3580 wip_ty.setName(ip, type_name.name, type_name.nav);
3581
3582 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
3583 .parent = block.namespace.toOptional(),
3584 .owner_type = wip_ty.index,
3585 .file_scope = block.getFileScopeIndex(zcu),
3586 .generation = zcu.generation,
3587 });
3588 errdefer pt.destroyNamespace(new_namespace_index);
3589
3590 const decls = sema.code.bodySlice(extra_index, decls_len);
3591 try pt.scanNamespace(new_namespace_index, decls);
3592
3593 codegen_type: {
3594 if (zcu.comp.config.use_llvm) break :codegen_type;
3595 if (block.ownerModule().strip) break :codegen_type;
3596 // This job depends on any resolve_type_fully jobs queued up before it.
3597 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
3598 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
3599 }
3600 try sema.addTypeReferenceEntry(src, wip_ty.index);
3601 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
3602 return Air.internedToRef(wip_ty.finish(ip, new_namespace_index));
3603}
3604
3605fn zirErrorSetDecl(3012fn zirErrorSetDecl(
3606 sema: *Sema,3013 sema: *Sema,
3607 inst: Zir.Inst.Index,3014 inst: Zir.Inst.Index,
...@@ -3640,16 +3047,16 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -3640,16 +3047,16 @@ fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
3640 defer tracy.end();3047 defer tracy.end();
36413048
3642 const pt = sema.pt;3049 const pt = sema.pt;
3050 const zcu = pt.zcu;
36433051
3644 const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node);3052 const src = block.nodeOffset(sema.code.instructions.items(.data)[@intFromEnum(inst)].node);
36453053
3646 if (block.isComptime() or try sema.fn_ret_ty.comptimeOnlySema(pt)) {3054 if (block.isComptime() or sema.fn_ret_ty.comptimeOnly(zcu)) {
3647 try sema.fn_ret_ty.resolveFields(pt);
3648 return sema.analyzeComptimeAlloc(block, src, sema.fn_ret_ty, .none);3055 return sema.analyzeComptimeAlloc(block, src, sema.fn_ret_ty, .none);
3649 }3056 }
36503057
3651 const target = pt.zcu.getTarget();3058 const target = zcu.getTarget();
3652 const ptr_type = try pt.ptrTypeSema(.{3059 const ptr_type = try pt.ptrType(.{
3653 .child = sema.fn_ret_ty.toIntern(),3060 .child = sema.fn_ret_ty.toIntern(),
3654 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },3061 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
3655 });3062 });
...@@ -3826,6 +3233,7 @@ fn zirAllocExtended(...@@ -3826,6 +3233,7 @@ fn zirAllocExtended(
3826 extended: Zir.Inst.Extended.InstData,3233 extended: Zir.Inst.Extended.InstData,
3827) CompileError!Air.Inst.Ref {3234) CompileError!Air.Inst.Ref {
3828 const pt = sema.pt;3235 const pt = sema.pt;
3236 const zcu = pt.zcu;
3829 const gpa = sema.gpa;3237 const gpa = sema.gpa;
3830 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);3238 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
3831 const var_src = block.nodeOffset(extra.data.src_node);3239 const var_src = block.nodeOffset(extra.data.src_node);
...@@ -3847,37 +3255,20 @@ fn zirAllocExtended(...@@ -3847,37 +3255,20 @@ fn zirAllocExtended(
3847 break :blk try sema.resolveAlign(block, align_src, align_ref);3255 break :blk try sema.resolveAlign(block, align_src, align_ref);
3848 } else .none;3256 } else .none;
38493257
3850 if (block.isComptime() or small.is_comptime) {3258 if (small.has_type) {
3851 if (small.has_type) {3259 try sema.ensureLayoutResolved(var_ty);
3260 if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) {
3852 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);3261 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
3853 } else {
3854 try sema.air_instructions.append(gpa, .{
3855 .tag = .inferred_alloc_comptime,
3856 .data = .{ .inferred_alloc_comptime = .{
3857 .alignment = alignment,
3858 .is_const = small.is_const,
3859 .ptr = undefined,
3860 } },
3861 });
3862 return @as(Air.Inst.Index, @enumFromInt(sema.air_instructions.len - 1)).toRef();
3863 }3262 }
3864 }
3865
3866 if (small.has_type and try var_ty.comptimeOnlySema(pt)) {
3867 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment);
3868 }
3869
3870 if (small.has_type) {
3871 if (!small.is_const) {3263 if (!small.is_const) {
3872 try sema.validateVarType(block, ty_src, var_ty, false);3264 try sema.validateVarType(block, ty_src, var_ty, false);
3873 }3265 }
3874 const target = pt.zcu.getTarget();3266 const target = pt.zcu.getTarget();
3875 try var_ty.resolveLayout(pt);3267 if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) {
3876 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {
3877 const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });3268 const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node });
3878 return sema.fail(block, store_src, "local variable in naked function", .{});3269 return sema.fail(block, store_src, "local variable in naked function", .{});
3879 }3270 }
3880 const ptr_type = try sema.pt.ptrTypeSema(.{3271 const ptr_type = try pt.ptrType(.{
3881 .child = var_ty.toIntern(),3272 .child = var_ty.toIntern(),
3882 .flags = .{3273 .flags = .{
3883 .alignment = alignment,3274 .alignment = alignment,
...@@ -3893,6 +3284,19 @@ fn zirAllocExtended(...@@ -3893,6 +3284,19 @@ fn zirAllocExtended(
3893 return ptr;3284 return ptr;
3894 }3285 }
38953286
3287 if (block.isComptime() or small.is_comptime) {
3288 const iac_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
3289 try sema.air_instructions.append(gpa, .{
3290 .tag = .inferred_alloc_comptime,
3291 .data = .{ .inferred_alloc_comptime = .{
3292 .alignment = alignment,
3293 .is_const = small.is_const,
3294 .ptr = undefined,
3295 } },
3296 });
3297 return iac_index.toRef();
3298 }
3299
3896 const result_index = try block.addInstAsIndex(.{3300 const result_index = try block.addInstAsIndex(.{
3897 .tag = .inferred_alloc,3301 .tag = .inferred_alloc,
3898 .data = .{ .inferred_alloc = .{3302 .data = .{ .inferred_alloc = .{
...@@ -3916,6 +3320,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -3916,6 +3320,7 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
3916 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });3320 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
3917 const var_src = block.nodeOffset(inst_data.src_node);3321 const var_src = block.nodeOffset(inst_data.src_node);
3918 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3322 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3323 try sema.ensureLayoutResolved(var_ty);
3919 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);3324 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
3920}3325}
39213326
...@@ -3978,7 +3383,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -3978,7 +3383,7 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
3978 return sema.makePtrConst(block, Air.internedToRef(ptr_val));3383 return sema.makePtrConst(block, Air.internedToRef(ptr_val));
3979 }3384 }
39803385
3981 if (try elem_ty.comptimeOnlySema(pt)) {3386 if (elem_ty.comptimeOnly(zcu)) {
3982 // The value was initialized through RLS, so we didn't detect the runtime condition earlier.3387 // The value was initialized through RLS, so we didn't detect the runtime condition earlier.
3983 // TODO: source location of runtime control flow3388 // TODO: source location of runtime control flow
3984 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });3389 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node });
...@@ -4001,20 +3406,23 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4001,20 +3406,23 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4001 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);3406 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc);
4002 const ptr_info = alloc_ty.ptrInfo(zcu);3407 const ptr_info = alloc_ty.ptrInfo(zcu);
4003 const elem_ty: Type = .fromInterned(ptr_info.child);3408 const elem_ty: Type = .fromInterned(ptr_info.child);
3409 elem_ty.assertHasLayout(zcu);
40043410
4005 const alloc_inst = alloc.toIndex() orelse return null;3411 const alloc_inst = alloc.toIndex() orelse return null;
4006 const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null;3412 const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null;
4007 const stores = comptime_info.value.stores.items(.inst);3413 const stores = comptime_info.value.stores.items(.inst);
40083414
3415 // If the elem type is OPV, no need to faff about with `stores`; just use the OPV.
3416 if (try elem_ty.onePossibleValue(pt)) |opv| {
3417 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, opv.toIntern(), null, alloc_inst, comptime_info.value);
3418 }
3419
3420 // Since the elem type isn't OPV, there should have been at least one store.
3421 assert(stores.len > 0);
3422
4009 // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known.3423 // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known.
4010 // We will resolve and return its value.3424 // We will resolve and return its value.
40113425
4012 // We expect to have emitted at least one store, unless the elem type is OPV.
4013 if (stores.len == 0) {
4014 const val = (try sema.typeHasOnePossibleValue(elem_ty)).?.toIntern();
4015 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value);
4016 }
4017
4018 // In general, we want to create a comptime alloc of the correct type and3426 // In general, we want to create a comptime alloc of the correct type and
4019 // apply the stores to that alloc in order. However, before going to all3427 // apply the stores to that alloc in order. However, before going to all
4020 // that effort, let's optimize for the common case of a single store.3428 // that effort, let's optimize for the common case of a single store.
...@@ -4118,7 +3526,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4118,7 +3526,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4118 const idx_val = (try sema.resolveValue(data.rhs)).?;3526 const idx_val = (try sema.resolveValue(data.rhs)).?;
4119 break :blk .{3527 break :blk .{
4120 data.lhs,3528 data.lhs,
4121 .{ .elem = try idx_val.toUnsignedIntSema(pt) },3529 .{ .elem = idx_val.toUnsignedInt(zcu) },
4122 };3530 };
4123 },3531 },
4124 .bitcast => .{3532 .bitcast => .{
...@@ -4150,7 +3558,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4150,7 +3558,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4150 // If the payload is OPV, we must use that value instead of undef.3558 // If the payload is OPV, we must use that value instead of undef.
4151 const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);3559 const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
4152 const payload_ty = opt_ty.optionalChild(zcu);3560 const payload_ty = opt_ty.optionalChild(zcu);
4153 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty);3561 const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty);
4154 const opt_val = try pt.intern(.{ .opt = .{3562 const opt_val = try pt.intern(.{ .opt = .{
4155 .ty = opt_ty.toIntern(),3563 .ty = opt_ty.toIntern(),
4156 .val = payload_val.toIntern(),3564 .val = payload_val.toIntern(),
...@@ -4163,7 +3571,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4163,7 +3571,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4163 // If the payload is OPV, we must use that value instead of undef.3571 // If the payload is OPV, we must use that value instead of undef.
4164 const eu_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);3572 const eu_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
4165 const payload_ty = eu_ty.errorUnionPayload(zcu);3573 const payload_ty = eu_ty.errorUnionPayload(zcu);
4166 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty);3574 const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty);
4167 const eu_val = try pt.intern(.{ .error_union = .{3575 const eu_val = try pt.intern(.{ .error_union = .{
4168 .ty = eu_ty.toIntern(),3576 .ty = eu_ty.toIntern(),
4169 .val = .{ .payload = payload_val.toIntern() },3577 .val = .{ .payload = payload_val.toIntern() },
...@@ -4178,7 +3586,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4178,7 +3586,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4178 // The payload value will be stored later, so undef is a sufficent payload for now.3586 // The payload value will be stored later, so undef is a sufficent payload for now.
4179 const payload_ty: Type = .fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]);3587 const payload_ty: Type = .fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]);
4180 const payload_val = try pt.undefValue(payload_ty);3588 const payload_val = try pt.undefValue(payload_ty);
4181 const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), idx);3589 const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), idx);
4182 const store_val = try pt.unionValue(maybe_union_ty, tag_val, payload_val);3590 const store_val = try pt.unionValue(maybe_union_ty, tag_val, payload_val);
4183 try sema.storePtrVal(block, .unneeded, .fromInterned(decl_parent_ptr), store_val, maybe_union_ty);3591 try sema.storePtrVal(block, .unneeded, .fromInterned(decl_parent_ptr), store_val, maybe_union_ty);
4184 }3592 }
...@@ -4207,7 +3615,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,...@@ -4207,7 +3615,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
4207 const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?);3615 const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?);
4208 const union_ty = union_ptr_val.typeOf(zcu).childType(zcu);3616 const union_ty = union_ptr_val.typeOf(zcu).childType(zcu);
4209 const field_ty = union_ty.unionFieldType(tag_val, zcu).?;3617 const field_ty = union_ty.unionFieldType(tag_val, zcu).?;
4210 if (try sema.typeHasOnePossibleValue(field_ty)) |payload_val| {3618 if (try field_ty.onePossibleValue(pt)) |payload_val| {
4211 const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val);3619 const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val);
4212 try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty);3620 try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty);
4213 }3621 }
...@@ -4289,7 +3697,7 @@ fn finishResolveComptimeKnownAllocPtr(...@@ -4289,7 +3697,7 @@ fn finishResolveComptimeKnownAllocPtr(
4289fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {3697fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {
4290 var ptr_info = ptr_ty.ptrInfo(sema.pt.zcu);3698 var ptr_info = ptr_ty.ptrInfo(sema.pt.zcu);
4291 ptr_info.flags.is_const = true;3699 ptr_info.flags.is_const = true;
4292 return sema.pt.ptrTypeSema(ptr_info);3700 return sema.pt.ptrType(ptr_info);
4293}3701}
42943702
4295fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref {3703fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref {
...@@ -4326,21 +3734,23 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -4326,21 +3734,23 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
4326 defer tracy.end();3734 defer tracy.end();
43273735
4328 const pt = sema.pt;3736 const pt = sema.pt;
3737 const zcu = pt.zcu;
43293738
4330 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;3739 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4331 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });3740 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4332 const var_src = block.nodeOffset(inst_data.src_node);3741 const var_src = block.nodeOffset(inst_data.src_node);
43333742
4334 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3743 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
4335 if (block.isComptime() or try var_ty.comptimeOnlySema(pt)) {3744 try sema.ensureLayoutResolved(var_ty);
3745 if (block.isComptime() or var_ty.comptimeOnly(zcu)) {
4336 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);3746 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
4337 }3747 }
4338 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {3748 if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) {
4339 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });3749 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4340 return sema.fail(block, mut_src, "local variable in naked function", .{});3750 return sema.fail(block, mut_src, "local variable in naked function", .{});
4341 }3751 }
4342 const target = pt.zcu.getTarget();3752 const target = zcu.getTarget();
4343 const ptr_type = try pt.ptrTypeSema(.{3753 const ptr_type = try pt.ptrType(.{
4344 .child = var_ty.toIntern(),3754 .child = var_ty.toIntern(),
4345 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },3755 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
4346 });3756 });
...@@ -4356,21 +3766,24 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -4356,21 +3766,24 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
4356 defer tracy.end();3766 defer tracy.end();
43573767
4358 const pt = sema.pt;3768 const pt = sema.pt;
3769 const zcu = pt.zcu;
43593770
4360 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;3771 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
4361 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });3772 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node });
4362 const var_src = block.nodeOffset(inst_data.src_node);3773 const var_src = block.nodeOffset(inst_data.src_node);
3774
4363 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);3775 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand);
3776 try sema.ensureLayoutResolved(var_ty);
4364 if (block.isComptime()) {3777 if (block.isComptime()) {
4365 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);3778 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none);
4366 }3779 }
4367 if (sema.func_is_naked and try var_ty.hasRuntimeBitsSema(pt)) {3780 if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) {
4368 const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });3781 const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4369 return sema.fail(block, store_src, "local variable in naked function", .{});3782 return sema.fail(block, store_src, "local variable in naked function", .{});
4370 }3783 }
4371 try sema.validateVarType(block, ty_src, var_ty, false);3784 try sema.validateVarType(block, ty_src, var_ty, false);
4372 const target = pt.zcu.getTarget();3785 const target = zcu.getTarget();
4373 const ptr_type = try pt.ptrTypeSema(.{3786 const ptr_type = try pt.ptrType(.{
4374 .child = var_ty.toIntern(),3787 .child = var_ty.toIntern(),
4375 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },3788 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
4376 });3789 });
...@@ -4430,8 +3843,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4430,8 +3843,9 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
44303843
4431 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {3844 switch (sema.air_instructions.items(.tag)[@intFromEnum(ptr_inst)]) {
4432 .inferred_alloc_comptime => {3845 .inferred_alloc_comptime => {
4433 // The work was already done for us by `Sema.storeToInferredAllocComptime`.3846 // The work was already done for us by `Sema.storeToInferredAllocComptime`. Also, since
4434 // All we need to do is return the pointer.3847 // we had a value of the exact correct type to store, the result type's layout must be
3848 // already resolved. So all we need to do here is return the pointer.
4435 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;3849 const iac = sema.air_instructions.items(.data)[@intFromEnum(ptr_inst)].inferred_alloc_comptime;
4436 const resolved_ptr = iac.ptr;3850 const resolved_ptr = iac.ptr;
44373851
...@@ -4450,7 +3864,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4450,7 +3864,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4450 };3864 };
4451 if (zcu.intern_pool.isFuncBody(val)) {3865 if (zcu.intern_pool.isFuncBody(val)) {
4452 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));3866 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val));
4453 if (try ty.fnHasRuntimeBitsSema(pt)) {3867 if (ty.fnHasRuntimeBits(zcu)) {
4454 const orig_fn_index = zcu.intern_pool.unwrapCoercedFunc(val);3868 const orig_fn_index = zcu.intern_pool.unwrapCoercedFunc(val);
4455 try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index }));3869 try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index }));
4456 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);3870 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index);
...@@ -4469,8 +3883,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4469,8 +3883,10 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4469 peer_val.* = bin_op.rhs;3883 peer_val.* = bin_op.rhs;
4470 }3884 }
4471 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none);3885 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none);
3886 // The layout of the peers is already resolved, so the layout of `final_elem_ty` is too.
3887 final_elem_ty.assertHasLayout(zcu);
44723888
4473 const final_ptr_ty = try pt.ptrTypeSema(.{3889 const final_ptr_ty = try pt.ptrType(.{
4474 .child = final_elem_ty.toIntern(),3890 .child = final_elem_ty.toIntern(),
4475 .flags = .{3891 .flags = .{
4476 .alignment = ia1.alignment,3892 .alignment = ia1.alignment,
...@@ -4484,21 +3900,16 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com...@@ -4484,21 +3900,16 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
4484 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);3900 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty);
4485 const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);3901 const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty);
44863902
4487 // Unless the block is comptime, `alloc_inferred` always produces
4488 // a runtime constant. The final inferred type needs to be
4489 // fully resolved so it can be lowered in codegen.
4490 try final_elem_ty.resolveFully(pt);
4491
4492 return Air.internedToRef(new_const_ptr.toIntern());3903 return Air.internedToRef(new_const_ptr.toIntern());
4493 }3904 }
44943905
4495 if (try final_elem_ty.comptimeOnlySema(pt)) {3906 if (final_elem_ty.comptimeOnly(zcu)) {
4496 // The alloc wasn't comptime-known per the above logic, so the3907 // The alloc wasn't comptime-known per the above logic, so the
4497 // type cannot be comptime-only.3908 // type cannot be comptime-only.
4498 // TODO: source location of runtime control flow3909 // TODO: source location of runtime control flow
4499 return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});3910 return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)});
4500 }3911 }
4501 if (sema.func_is_naked and try final_elem_ty.hasRuntimeBitsSema(pt)) {3912 if (sema.func_is_naked and final_elem_ty.hasRuntimeBits(zcu)) {
4502 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });3913 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node });
4503 return sema.fail(block, mut_src, "local variable in naked function", .{});3914 return sema.fail(block, mut_src, "local variable in naked function", .{});
4504 }3915 }
...@@ -4812,7 +4223,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo...@@ -4812,7 +4223,7 @@ fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: boo
4812 if (is_ref) {4223 if (is_ref) {
4813 var ptr_info = operand_ty.ptrInfo(zcu);4224 var ptr_info = operand_ty.ptrInfo(zcu);
4814 ptr_info.child = eu_ty.toIntern();4225 ptr_info.child = eu_ty.toIntern();
4815 const eu_ptr_ty = try pt.ptrTypeSema(ptr_info);4226 const eu_ptr_ty = try pt.ptrType(ptr_info);
4816 return Air.internedToRef(eu_ptr_ty.toIntern());4227 return Air.internedToRef(eu_ptr_ty.toIntern());
4817 } else {4228 } else {
4818 return Air.internedToRef(eu_ty.toIntern());4229 return Air.internedToRef(eu_ty.toIntern());
...@@ -4935,7 +4346,6 @@ fn validateArrayInitTy(...@@ -4935,7 +4346,6 @@ fn validateArrayInitTy(
4935 return;4346 return;
4936 },4347 },
4937 .@"struct" => if (ty.isTuple(zcu)) {4348 .@"struct" => if (ty.isTuple(zcu)) {
4938 try ty.resolveFields(pt);
4939 const array_len = ty.arrayLen(zcu);4349 const array_len = ty.arrayLen(zcu);
4940 if (init_count > array_len) {4350 if (init_count > array_len) {
4941 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{4351 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
...@@ -5097,12 +4507,16 @@ fn validateStructInit(...@@ -5097,12 +4507,16 @@ fn validateStructInit(
5097 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);4507 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
50984508
5099 for (found_fields, 0..) |explicit, i_usize| {4509 for (found_fields, 0..) |explicit, i_usize| {
5100 if (explicit) continue;
5101 const i: u32 = @intCast(i_usize);4510 const i: u32 = @intCast(i_usize);
51024511
5103 try struct_ty.resolveStructFieldInits(pt);4512 if (explicit) continue;
5104 const default_val = struct_ty.structFieldDefaultValue(i, zcu);4513 if (struct_ty.structFieldIsComptime(i, zcu)) continue;
5105 if (default_val.toIntern() == .unreachable_value) {4514
4515 if (!struct_ty.isTuple(zcu)) {
4516 try sema.ensureFieldInitsResolved(struct_ty);
4517 }
4518
4519 const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse {
5106 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {4520 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse {
5107 const template = "missing tuple field with index {d}";4521 const template = "missing tuple field with index {d}";
5108 if (root_msg) |msg| {4522 if (root_msg) |msg| {
...@@ -5120,7 +4534,7 @@ fn validateStructInit(...@@ -5120,7 +4534,7 @@ fn validateStructInit(
5120 root_msg = try sema.errMsg(init_src, template, args);4534 root_msg = try sema.errMsg(init_src, template, args);
5121 }4535 }
5122 continue;4536 continue;
5123 }4537 };
51244538
5125 const field_src = init_src; // TODO better source location4539 const field_src = init_src; // TODO better source location
5126 const default_field_ptr = if (struct_ty.isTuple(zcu))4540 const default_field_ptr = if (struct_ty.isTuple(zcu))
...@@ -5166,11 +4580,9 @@ fn zirValidatePtrArrayInit(...@@ -5166,11 +4580,9 @@ fn zirValidatePtrArrayInit(
5166 var root_msg: ?*Zcu.ErrorMsg = null;4580 var root_msg: ?*Zcu.ErrorMsg = null;
5167 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);4581 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
51684582
5169 try array_ty.resolveStructFieldInits(pt);
5170 var i = instrs.len;4583 var i = instrs.len;
5171 while (i < array_len) : (i += 1) {4584 while (i < array_len) : (i += 1) {
5172 const default_val = array_ty.structFieldDefaultValue(i, zcu).toIntern();4585 if (array_ty.structFieldDefaultValue(i, zcu) == null) {
5173 if (default_val == .unreachable_value) {
5174 const template = "missing tuple field with index {d}";4586 const template = "missing tuple field with index {d}";
5175 if (root_msg) |msg| {4587 if (root_msg) |msg| {
5176 try sema.errNote(init_src, msg, template, .{i});4588 try sema.errNote(init_src, msg, template, .{i});
...@@ -5224,17 +4636,19 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -5224,17 +4636,19 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
5224 .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}),4636 .slice => return sema.fail(block, src, "index syntax required for slice type '{f}'", .{operand_ty.fmt(pt)}),
5225 }4637 }
52264638
5227 if ((try sema.typeHasOnePossibleValue(operand_ty.childType(zcu))) != null) {4639 const elem_ty = operand_ty.childType(zcu);
4640 try sema.ensureLayoutResolved(elem_ty);
4641
4642 if (try elem_ty.onePossibleValue(pt) != null) {
5228 // No need to validate the actual pointer value, we don't need it!4643 // No need to validate the actual pointer value, we don't need it!
5229 return;4644 return;
5230 }4645 }
52314646
5232 const elem_ty = operand_ty.elemType2(zcu);
5233 if (try sema.resolveValue(operand)) |val| {4647 if (try sema.resolveValue(operand)) |val| {
5234 if (val.isUndef(zcu)) {4648 if (val.isUndef(zcu)) {
5235 return sema.fail(block, src, "cannot dereference undefined value", .{});4649 return sema.fail(block, src, "cannot dereference undefined value", .{});
5236 }4650 }
5237 } else if (try elem_ty.comptimeOnlySema(pt)) {4651 } else if (elem_ty.comptimeOnly(zcu)) {
5238 const msg = msg: {4652 const msg = msg: {
5239 const msg = try sema.errMsg(4653 const msg = try sema.errMsg(
5240 src,4654 src,
...@@ -5373,7 +4787,7 @@ fn failWithBadUnionFieldAccess(...@@ -5373,7 +4787,7 @@ fn failWithBadUnionFieldAccess(
5373 return sema.failWithOwnedErrorMsg(block, msg);4787 return sema.failWithOwnedErrorMsg(block, msg);
5374}4788}
53754789
5376fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !void {4790pub fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) !void {
5377 const zcu = sema.pt.zcu;4791 const zcu = sema.pt.zcu;
5378 const src_loc = decl_ty.srcLocOrNull(zcu) orelse return;4792 const src_loc = decl_ty.srcLocOrNull(zcu) orelse return;
5379 const category = switch (decl_ty.zigTypeTag(zcu)) {4793 const category = switch (decl_ty.zigTypeTag(zcu)) {
...@@ -5443,14 +4857,16 @@ fn storeToInferredAllocComptime(...@@ -5443,14 +4857,16 @@ fn storeToInferredAllocComptime(
5443 const operand_val = try sema.resolveValue(operand) orelse {4857 const operand_val = try sema.resolveValue(operand) orelse {
5444 return sema.failWithNeededComptime(block, src, .{ .simple = .stored_to_comptime_var });4858 return sema.failWithNeededComptime(block, src, .{ .simple = .stored_to_comptime_var });
5445 };4859 };
5446 const alloc_ty = try pt.ptrTypeSema(.{4860 const alloc_ty = try pt.ptrType(.{
5447 .child = operand_ty.toIntern(),4861 .child = operand_ty.toIntern(),
5448 .flags = .{4862 .flags = .{
5449 .alignment = iac.alignment,4863 .alignment = iac.alignment,
5450 .is_const = iac.is_const,4864 .is_const = iac.is_const,
5451 },4865 },
5452 });4866 });
5453 if (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)) {4867 if (try operand_ty.onePossibleValue(pt) != null or
4868 (iac.is_const and !operand_val.canMutateComptimeVarState(zcu)))
4869 {
5454 iac.ptr = try pt.intern(.{ .ptr = .{4870 iac.ptr = try pt.intern(.{ .ptr = .{
5455 .ty = alloc_ty.toIntern(),4871 .ty = alloc_ty.toIntern(),
5456 .base_addr = .{ .uav = .{4872 .base_addr = .{ .uav = .{
...@@ -5624,7 +5040,7 @@ fn zirCompileLog(...@@ -5624,7 +5040,7 @@ fn zirCompileLog(
56245040
5625 const arg = try sema.resolveInst(arg_ref);5041 const arg = try sema.resolveInst(arg_ref);
5626 const arg_ty = sema.typeOf(arg);5042 const arg_ty = sema.typeOf(arg);
5627 if (try sema.resolveValueResolveLazy(arg)) |val| {5043 if (try sema.resolveValue(arg)) |val| {
5628 writer.print("@as({f}, {f})", .{5044 writer.print("@as({f}, {f})", .{
5629 arg_ty.fmt(pt), val.fmtValueSema(pt, sema),5045 arg_ty.fmt(pt), val.fmtValueSema(pt, sema),
5630 }) catch return error.OutOfMemory;5046 }) catch return error.OutOfMemory;
...@@ -5928,10 +5344,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr...@@ -5928,10 +5344,9 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
5928 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});5344 return sema.fail(&child_block, src, "C import failed: {s}", .{@errorName(err)});
59295345
5930 try pt.ensureFileAnalyzed(new_file_index);5346 try pt.ensureFileAnalyzed(new_file_index);
5931 const ty = zcu.fileRootType(new_file_index);5347 const ty: Type = .fromInterned(zcu.fileRootType(new_file_index));
5932 try sema.declareDependency(.{ .interned = ty });
5933 try sema.addTypeReferenceEntry(src, ty);5348 try sema.addTypeReferenceEntry(src, ty);
5934 return Air.internedToRef(ty);5349 return .fromType(ty);
5935}5350}
59365351
5937fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {5352fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -6177,10 +5592,11 @@ fn resolveAnalyzedBlock(...@@ -6177,10 +5592,11 @@ fn resolveAnalyzedBlock(
6177 // to emit a jump instruction to after the block when it encounters the break.5592 // to emit a jump instruction to after the block when it encounters the break.
6178 try parent_block.instructions.append(gpa, merges.block_inst);5593 try parent_block.instructions.append(gpa, merges.block_inst);
6179 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items });5594 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items });
5595 resolved_ty.assertHasLayout(zcu);
6180 // TODO add note "missing else causes void value"5596 // TODO add note "missing else causes void value"
61815597
6182 const type_src = src; // TODO: better source location5598 const type_src = src; // TODO: better source location
6183 if (try resolved_ty.comptimeOnlySema(pt)) {5599 if (resolved_ty.comptimeOnly(zcu)) {
6184 const msg = msg: {5600 const msg = msg: {
6185 const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)});5601 const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)});
6186 errdefer msg.destroy(sema.gpa);5602 errdefer msg.destroy(sema.gpa);
...@@ -6274,10 +5690,7 @@ fn resolveAnalyzedBlock(...@@ -6274,10 +5690,7 @@ fn resolveAnalyzedBlock(
6274 });5690 });
6275 }5691 }
62765692
6277 if (try sema.typeHasOnePossibleValue(resolved_ty)) |block_only_value| {5693 if (try resolved_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
6278 return Air.internedToRef(block_only_value.toIntern());
6279 }
6280
6281 return merges.block_inst.toRef();5694 return merges.block_inst.toRef();
6282}5695}
62835696
...@@ -6413,7 +5826,8 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {...@@ -6413,7 +5826,8 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
6413 .@"comptime",5826 .@"comptime",
6414 .nav_val,5827 .nav_val,
6415 .nav_ty,5828 .nav_ty,
6416 .type,5829 .type_layout,
5830 .type_inits,
6417 .memoized_state,5831 .memoized_state,
6418 => return, // does nothing outside a function5832 => return, // does nothing outside a function
6419 };5833 };
...@@ -6431,7 +5845,8 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {...@@ -6431,7 +5845,8 @@ fn zirDisableIntrinsics(sema: *Sema) CompileError!void {
6431 .@"comptime",5845 .@"comptime",
6432 .nav_val,5846 .nav_val,
6433 .nav_ty,5847 .nav_ty,
6434 .type,5848 .type_layout,
5849 .type_inits,
6435 .memoized_state,5850 .memoized_state,
6436 => return, // does nothing outside a function5851 => return, // does nothing outside a function
6437 };5852 };
...@@ -6589,8 +6004,8 @@ fn addDbgVar(...@@ -6589,8 +6004,8 @@ fn addDbgVar(
6589 .dbg_var_val, .dbg_arg_inline => operand_ty,6004 .dbg_var_val, .dbg_arg_inline => operand_ty,
6590 else => unreachable,6005 else => unreachable,
6591 };6006 };
6592 if (try val_ty.comptimeOnlySema(pt)) return;6007 if (val_ty.comptimeOnly(zcu)) return;
6593 if (!(try val_ty.hasRuntimeBitsSema(pt))) return;6008 if (!val_ty.hasRuntimeBits(zcu)) return;
6594 if (try sema.resolveValue(operand)) |operand_val| {6009 if (try sema.resolveValue(operand)) |operand_val| {
6595 if (operand_val.canMutateComptimeVarState(zcu)) return;6010 if (operand_val.canMutateComptimeVarState(zcu)) return;
6596 }6011 }
...@@ -6759,7 +6174,6 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref...@@ -6759,7 +6174,6 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
6759 if (!block.ownerModule().error_tracing) return .none;6174 if (!block.ownerModule().error_tracing) return .none;
67606175
6761 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);6176 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
6762 try stack_trace_ty.resolveFields(pt);
6763 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);6177 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
6764 const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {6178 const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {
6765 error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"),6179 error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"),
...@@ -6803,7 +6217,6 @@ fn popErrorReturnTrace(...@@ -6803,7 +6217,6 @@ fn popErrorReturnTrace(
6803 // the result is comptime-known to be a non-error. Either way, pop unconditionally.6217 // the result is comptime-known to be a non-error. Either way, pop unconditionally.
68046218
6805 const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);6219 const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
6806 try stack_trace_ty.resolveFields(pt);
6807 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);6220 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
6808 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);6221 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
6809 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);6222 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
...@@ -6829,7 +6242,6 @@ fn popErrorReturnTrace(...@@ -6829,7 +6242,6 @@ fn popErrorReturnTrace(
68296242
6830 // If non-error, then pop the error return trace by restoring the index.6243 // If non-error, then pop the error return trace by restoring the index.
6831 const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);6244 const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
6832 try stack_trace_ty.resolveFields(pt);
6833 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);6245 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
6834 const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);6246 const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
6835 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);6247 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
...@@ -6969,7 +6381,6 @@ fn zirCall(...@@ -6969,7 +6381,6 @@ fn zirCall(
6969 // need to clean-up our own trace if we were passed to a non-error-handling expression.6381 // need to clean-up our own trace if we were passed to a non-error-handling expression.
6970 if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) {6382 if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) {
6971 const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace);6383 const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace);
6972 try stack_trace_ty.resolveFields(pt);
6973 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);6384 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls);
6974 const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);6385 const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
69756386
...@@ -7318,6 +6729,8 @@ fn analyzeCall(...@@ -7318,6 +6729,8 @@ fn analyzeCall(
7318 } else func_src;6729 } else func_src;
73196730
7320 const func_ty_info = zcu.typeToFunc(func_ty).?;6731 const func_ty_info = zcu.typeToFunc(func_ty).?;
6732 // MLUGG TODO: this isn't quite the check i want. this includes inline functions, which aren't *generic*...
6733 const func_is_generic = !func_ty.fnHasRuntimeBits(zcu);
7321 if (!callConvIsCallable(func_ty_info.cc)) {6734 if (!callConvIsCallable(func_ty_info.cc)) {
7322 return sema.failWithOwnedErrorMsg(block, msg: {6735 return sema.failWithOwnedErrorMsg(block, msg: {
7323 const msg = try sema.errMsg(6736 const msg = try sema.errMsg(
...@@ -7353,7 +6766,7 @@ fn analyzeCall(...@@ -7353,7 +6766,7 @@ fn analyzeCall(
7353 else => unreachable,6766 else => unreachable,
7354 } else .{ null, false };6767 } else .{ null, false };
73556768
7356 if (func_ty_info.is_generic and func_val == null) {6769 if (func_is_generic and func_val == null) {
7357 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });6770 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target });
7358 }6771 }
73596772
...@@ -7369,19 +6782,18 @@ fn analyzeCall(...@@ -7369,19 +6782,18 @@ fn analyzeCall(
7369 .src = call_src,6782 .src = call_src,
7370 .r = .{ .simple = .comptime_call_modifier },6783 .r = .{ .simple = .comptime_call_modifier },
7371 } };6784 } };
7372 } else if (!inline_requested and try Type.fromInterned(func_ty_info.return_type).comptimeOnlySema(pt)) {6785 } else if (!inline_requested) {
7373 block.comptime_reason = .{6786 const ret_ty: Type = .fromInterned(func_ty_info.return_type);
7374 .reason = .{6787 if (ret_ty.comptimeOnly(zcu)) {
6788 block.comptime_reason = .{ .reason = .{
7375 .src = call_src,6789 .src = call_src,
7376 .r = .{6790 .r = .{ .comptime_only_ret_ty = .{
7377 .comptime_only_ret_ty = .{6791 .ty = .fromInterned(func_ty_info.return_type),
7378 .ty = .fromInterned(func_ty_info.return_type),6792 .is_generic_inst = false,
7379 .is_generic_inst = false,6793 .ret_ty_src = func_ret_ty_src,
7380 .ret_ty_src = func_ret_ty_src,6794 } },
7381 },6795 } };
7382 },6796 }
7383 },
7384 };
7385 }6797 }
7386 }6798 }
73876799
...@@ -7403,13 +6815,13 @@ fn analyzeCall(...@@ -7403,13 +6815,13 @@ fn analyzeCall(
7403 // This is the `inst_map` used when evaluating generic parameters and return types.6815 // This is the `inst_map` used when evaluating generic parameters and return types.
7404 var generic_inst_map: InstMap = .{};6816 var generic_inst_map: InstMap = .{};
7405 defer generic_inst_map.deinit(gpa);6817 defer generic_inst_map.deinit(gpa);
7406 if (func_ty_info.is_generic) {6818 if (func_is_generic) {
7407 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);6819 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body);
7408 }6820 }
74096821
7410 // This exists so that `generic_block` below can include a "called from here" note back to this6822 // This exists so that `generic_block` below can include a "called from here" note back to this
7411 // call site when analyzing generic parameter/return types.6823 // call site when analyzing generic parameter/return types.
7412 var generic_inlining: Block.Inlining = if (func_ty_info.is_generic) .{6824 var generic_inlining: Block.Inlining = if (func_is_generic) .{
7413 .call_block = block,6825 .call_block = block,
7414 .call_src = call_src,6826 .call_src = call_src,
7415 .func = func_val.?.toIntern(),6827 .func = func_val.?.toIntern(),
...@@ -7422,7 +6834,7 @@ fn analyzeCall(...@@ -7422,7 +6834,7 @@ fn analyzeCall(
7422 // This is the block in which we evaluate generic function components: that is, generic parameter6834 // This is the block in which we evaluate generic function components: that is, generic parameter
7423 // types and the generic return type. This must not be used if the function is not generic.6835 // types and the generic return type. This must not be used if the function is not generic.
7424 // `comptime_reason` is set as needed.6836 // `comptime_reason` is set as needed.
7425 var generic_block: Block = if (func_ty_info.is_generic) .{6837 var generic_block: Block = if (func_is_generic) .{
7426 .parent = null,6838 .parent = null,
7427 .sema = sema,6839 .sema = sema,
7428 .namespace = fn_nav.analysis.?.namespace,6840 .namespace = fn_nav.analysis.?.namespace,
...@@ -7431,9 +6843,9 @@ fn analyzeCall(...@@ -7431,9 +6843,9 @@ fn analyzeCall(
7431 .src_base_inst = fn_nav.analysis.?.zir_index,6843 .src_base_inst = fn_nav.analysis.?.zir_index,
7432 .type_name_ctx = fn_nav.fqn,6844 .type_name_ctx = fn_nav.fqn,
7433 } else undefined;6845 } else undefined;
7434 defer if (func_ty_info.is_generic) generic_block.instructions.deinit(gpa);6846 defer if (func_is_generic) generic_block.instructions.deinit(gpa);
74356847
7436 if (func_ty_info.is_generic) {6848 if (func_is_generic) {
7437 // We certainly depend on the generic owner's signature!6849 // We certainly depend on the generic owner's signature!
7438 try sema.declareDependency(.{ .src_hash = fn_tracked_inst });6850 try sema.declareDependency(.{ .src_hash = fn_tracked_inst });
7439 }6851 }
...@@ -7445,7 +6857,7 @@ fn analyzeCall(...@@ -7445,7 +6857,7 @@ fn analyzeCall(
7445 if (raw != .generic_poison_type) break :ty .fromInterned(raw);6857 if (raw != .generic_poison_type) break :ty .fromInterned(raw);
74466858
7447 // We must discover the generic parameter type.6859 // We must discover the generic parameter type.
7448 assert(func_ty_info.is_generic);6860 assert(func_is_generic);
7449 const param_inst_idx = fn_zir_info.param_body[arg_idx];6861 const param_inst_idx = fn_zir_info.param_body[arg_idx];
7450 const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));6862 const param_inst = fn_zir.instructions.get(@intFromEnum(param_inst_idx));
7451 switch (param_inst.tag) {6863 switch (param_inst.tag) {
...@@ -7494,11 +6906,11 @@ fn analyzeCall(...@@ -7494,11 +6906,11 @@ fn analyzeCall(
7494 return arg.*; // terminate analysis here6906 return arg.*; // terminate analysis here
7495 }6907 }
74966908
7497 if (func_ty_info.is_generic) {6909 if (func_is_generic) {
7498 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it.6910 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it.
7499 const param_inst_idx = fn_zir_info.param_body[arg_idx];6911 const param_inst_idx = fn_zir_info.param_body[arg_idx];
7500 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;6912 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false;
7501 const param_is_comptime = declared_comptime or try arg_ty.comptimeOnlySema(pt);6913 const param_is_comptime = declared_comptime or arg_ty.comptimeOnly(zcu);
7502 // We allow comptime-known arguments to propagate to generic types not only for comptime6914 // We allow comptime-known arguments to propagate to generic types not only for comptime
7503 // parameters, but if the call is known to be inline.6915 // parameters, but if the call is known to be inline.
7504 if (param_is_comptime or early_known_inline) {6916 if (param_is_comptime or early_known_inline) {
...@@ -7516,6 +6928,10 @@ fn analyzeCall(...@@ -7516,6 +6928,10 @@ fn analyzeCall(
7516 );6928 );
7517 }6929 }
7518 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, arg.*);6930 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, arg.*);
6931 } else if (try arg_ty.onePossibleValue(pt)) |opv| {
6932 // The argument is comptime-known, even though this is a generic instantiation (as
6933 // opposed to an inline call), because the parameter type is OPV.
6934 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, .fromValue(opv));
7519 } else {6935 } else {
7520 // We need a dummy instruction with this type. It doesn't actually need to be in any block,6936 // We need a dummy instruction with this type. It doesn't actually need to be in any block,
7521 // since it will never be referenced at runtime!6937 // since it will never be referenced at runtime!
...@@ -7532,7 +6948,7 @@ fn analyzeCall(...@@ -7532,7 +6948,7 @@ fn analyzeCall(
7532 // calls (where it should be the IES of the instantiation). However, it's how we print this6948 // calls (where it should be the IES of the instantiation). However, it's how we print this
7533 // in error messages.6949 // in error messages.
7534 const resolved_ret_ty: Type = ret_ty: {6950 const resolved_ret_ty: Type = ret_ty: {
7535 if (!func_ty_info.is_generic) break :ret_ty .fromInterned(func_ty_info.return_type);6951 if (!func_is_generic) break :ret_ty .fromInterned(func_ty_info.return_type);
75366952
7537 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {6953 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: {
7538 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);6954 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type);
...@@ -7542,7 +6958,7 @@ fn analyzeCall(...@@ -7542,7 +6958,7 @@ fn analyzeCall(
75426958
7543 // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`.6959 // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`.
75446960
7545 assert(func_ty_info.is_generic);6961 assert(func_is_generic);
75466962
7547 const old_code = sema.code;6963 const old_code = sema.code;
7548 const old_inst_map = sema.inst_map;6964 const old_inst_map = sema.inst_map;
...@@ -7584,10 +7000,11 @@ fn analyzeCall(...@@ -7584,10 +7000,11 @@ fn analyzeCall(
75847000
7585 break :ret_ty full_ty;7001 break :ret_ty full_ty;
7586 };7002 };
7003 try sema.ensureLayoutResolved(resolved_ret_ty);
75877004
7588 // If we've discovered after evaluating arguments that a generic function instantiation is7005 // If we've discovered after evaluating arguments that a generic function instantiation is
7589 // comptime-only, then we can mark the block as comptime *now*.7006 // comptime-only, then we can mark the block as comptime *now*.
7590 if (!inline_requested and !block.isComptime() and try resolved_ret_ty.comptimeOnlySema(pt)) {7007 if (!inline_requested and !block.isComptime() and resolved_ret_ty.comptimeOnly(zcu)) {
7591 block.comptime_reason = .{7008 block.comptime_reason = .{
7592 .reason = .{7009 .reason = .{
7593 .src = call_src,7010 .src = call_src,
...@@ -7618,7 +7035,7 @@ fn analyzeCall(...@@ -7618,7 +7035,7 @@ fn analyzeCall(
7618 });7035 });
7619 if (func_ty_info.cc == .auto) {7036 if (func_ty_info.cc == .auto) {
7620 switch (sema.owner.unwrap()) {7037 switch (sema.owner.unwrap()) {
7621 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},7038 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},
7622 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),7039 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true),
7623 }7040 }
7624 }7041 }
...@@ -7626,7 +7043,7 @@ fn analyzeCall(...@@ -7626,7 +7043,7 @@ fn analyzeCall(
7626 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);7043 try sema.validateRuntimeValue(block, args_info.argSrc(block, arg_idx), arg);
7627 }7044 }
7628 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {7045 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: {
7629 if (!func_ty_info.is_generic) break :func .{ callee, args };7046 if (!func_is_generic) break :func .{ callee, args };
76307047
7631 // Instantiate the generic function!7048 // Instantiate the generic function!
76327049
...@@ -7648,7 +7065,7 @@ fn analyzeCall(...@@ -7648,7 +7065,7 @@ fn analyzeCall(
7648 break :c true;7065 break :c true;
7649 }7066 }
7650 }7067 }
7651 break :c try arg_ty.comptimeOnlySema(pt);7068 break :c arg_ty.comptimeOnly(zcu);
7652 };7069 };
7653 const is_noalias = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsNoalias(i) else false;7070 const is_noalias = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsNoalias(i) else false;
76547071
...@@ -7680,6 +7097,7 @@ fn analyzeCall(...@@ -7680,6 +7097,7 @@ fn analyzeCall(
7680 .generic_owner = func_val.?.toIntern(),7097 .generic_owner = func_val.?.toIntern(),
7681 .comptime_args = comptime_args,7098 .comptime_args = comptime_args,
7682 });7099 });
7100 try sema.ensureLayoutResolved(.fromInterned(ip.typeOf(func_instance)));
7683 if (zcu.comp.debugIncremental()) {7101 if (zcu.comp.debugIncremental()) {
7684 const nav = ip.indexToKey(func_instance).func.owner_nav;7102 const nav = ip.indexToKey(func_instance).func.owner_nav;
7685 const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav);7103 const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav);
...@@ -7753,12 +7171,12 @@ fn analyzeCall(...@@ -7753,12 +7171,12 @@ fn analyzeCall(
7753 return .unreachable_value;7171 return .unreachable_value;
7754 }7172 }
77557173
7756 const result: Air.Inst.Ref = if (try sema.typeHasOnePossibleValue(sema.typeOf(maybe_opv))) |opv|7174 try sema.ensureLayoutResolved(sema.typeOf(maybe_opv));
7757 .fromValue(opv)7175 if (try sema.typeOf(maybe_opv).onePossibleValue(pt)) |opv| {
7758 else7176 return .fromValue(opv);
7759 maybe_opv;7177 } else {
77607178 return maybe_opv;
7761 return result;7179 }
7762 }7180 }
77637181
7764 // This is an inline call. The function must be comptime-known. We will analyze its body directly using this `Sema`.7182 // This is an inline call. The function must be comptime-known. We will analyze its body directly using this `Sema`.
...@@ -7824,6 +7242,11 @@ fn analyzeCall(...@@ -7824,6 +7242,11 @@ fn analyzeCall(
7824 }7242 }
7825 }7243 }
78267244
7245 // We're about to do an inline call; if the return type expression was generic, the return type
7246 // may not be resolved yet. It's correct to resolve it because the function is going to return a
7247 // value of this type.
7248 try sema.ensureLayoutResolved(resolved_ret_ty);
7249
7827 // For an inline call, we depend on the source code of the whole function definition.7250 // For an inline call, we depend on the source code of the whole function definition.
7828 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });7251 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index });
78297252
...@@ -8000,6 +7423,10 @@ fn analyzeCall(...@@ -8000,6 +7423,10 @@ fn analyzeCall(
8000 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, &inlining.merges, need_debug_scope);7423 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, &inlining.merges, need_debug_scope);
8001 };7424 };
80027425
7426 if (sema.typeOf(result_raw).isNoReturn(zcu)) {
7427 return .unreachable_value;
7428 }
7429
8003 const maybe_opv: Air.Inst.Ref = if (try sema.resolveValue(result_raw)) |result_val| r: {7430 const maybe_opv: Air.Inst.Ref = if (try sema.resolveValue(result_raw)) |result_val| r: {
8004 const val_resolved = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());7431 const val_resolved = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern());
8005 break :r Air.internedToRef(val_resolved);7432 break :r Air.internedToRef(val_resolved);
...@@ -8080,16 +7507,16 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil...@@ -8080,16 +7507,16 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
8080 const zcu = pt.zcu;7507 const zcu = pt.zcu;
8081 const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin;7508 const bin = sema.code.instructions.items(.data)[@intFromEnum(inst)].bin;
8082 const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type;7509 const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type;
7510 try sema.ensureLayoutResolved(maybe_wrapped_indexable_ty);
8083 const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu);7511 const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu);
8084 try indexable_ty.resolveFields(pt);
8085 assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction7512 assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction
8086 if (indexable_ty.zigTypeTag(zcu) == .@"struct") {7513 const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) {
8087 const elem_type = indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu);7514 .@"struct" => indexable_ty.fieldType(@intFromEnum(bin.rhs), zcu),
8088 return Air.internedToRef(elem_type.toIntern());7515 .array, .vector => indexable_ty.childType(zcu),
8089 } else {7516 .pointer => indexable_ty.indexablePtrElem(zcu),
8090 const elem_type = indexable_ty.elemType2(zcu);7517 else => unreachable,
8091 return Air.internedToRef(elem_type.toIntern());7518 };
8092 }7519 return .fromType(elem_ty);
8093}7520}
80947521
8095fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {7522fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -8355,7 +7782,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD...@@ -8355,7 +7782,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
8355 const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src);7782 const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src);
83567783
8357 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {7784 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
8358 const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntSema(pt));7785 const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(zcu));
8359 if (int > len: {7786 if (int > len: {
8360 const mutate = &ip.global_error_set.mutate;7787 const mutate = &ip.global_error_set.mutate;
8361 mutate.map.mutex.lockUncancelable(io);7788 mutate.map.mutex.lockUncancelable(io);
...@@ -8539,7 +7966,6 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8539,7 +7966,6 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8539 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) {7966 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) {
8540 .@"enum" => operand,7967 .@"enum" => operand,
8541 .@"union" => blk: {7968 .@"union" => blk: {
8542 try operand_ty.resolveFields(pt);
8543 const tag_ty = operand_ty.unionTagType(zcu) orelse {7969 const tag_ty = operand_ty.unionTagType(zcu) orelse {
8544 return sema.fail(7970 return sema.fail(
8545 block,7971 block,
...@@ -8568,17 +7994,9 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8568,17 +7994,9 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8568 });7994 });
8569 }7995 }
85707996
8571 if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| {
8572 return Air.internedToRef((try pt.getCoerced(opv, int_tag_ty)).toIntern());
8573 }
8574
8575 if (try sema.resolveValue(enum_tag)) |enum_tag_val| {7997 if (try sema.resolveValue(enum_tag)) |enum_tag_val| {
8576 if (enum_tag_val.isUndef(zcu)) {7998 if (enum_tag_val.isUndef(zcu)) return pt.undefRef(int_tag_ty);
8577 return pt.undefRef(int_tag_ty);7999 return .fromValue(enum_tag_val.intFromEnum(zcu));
8578 }
8579
8580 const val = try enum_tag_val.intFromEnum(enum_tag_ty, pt);
8581 return Air.internedToRef(val.toIntern());
8582 }8000 }
85838001
8584 try sema.requireRuntimeBlock(block, src, operand_src);8002 try sema.requireRuntimeBlock(block, src, operand_src);
...@@ -8626,19 +8044,15 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -8626,19 +8044,15 @@ fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
8626 return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_enum });8044 return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_enum });
8627 }8045 }
86288046
8629 if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| {8047 if (try dest_ty.onePossibleValue(pt)) |opv| {
8630 if (block.wantSafety()) {8048 if (block.wantSafety()) {
8631 // The operand is runtime-known but the result is comptime-known. In8049 // The operand is runtime-known but the result is comptime-known. In
8632 // this case we still need a safety check.8050 // this case we still need a safety check.
8633 const expect_int_val = switch (zcu.intern_pool.indexToKey(opv.toIntern())) {8051 const expect_int = try pt.getCoerced(opv.intFromEnum(zcu), operand_ty);
8634 .enum_tag => |enum_tag| enum_tag.int,8052 const ok = try block.addBinOp(.cmp_eq, operand, .fromValue(expect_int));
8635 else => unreachable,
8636 };
8637 const expect_int_coerced = try pt.getCoerced(.fromInterned(expect_int_val), operand_ty);
8638 const ok = try block.addBinOp(.cmp_eq, operand, Air.internedToRef(expect_int_coerced.toIntern()));
8639 try sema.addSafetyCheck(block, src, ok, .invalid_enum_value);8053 try sema.addSafetyCheck(block, src, ok, .invalid_enum_value);
8640 }8054 }
8641 return Air.internedToRef(opv.toIntern());8055 return .fromValue(opv);
8642 }8056 }
86438057
8644 try sema.requireRuntimeBlock(block, src, operand_src);8058 try sema.requireRuntimeBlock(block, src, operand_src);
...@@ -8666,6 +8080,7 @@ fn zirOptionalPayloadPtr(...@@ -8666,6 +8080,7 @@ fn zirOptionalPayloadPtr(
8666 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);8080 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false);
8667}8081}
86688082
8083/// MLUGG TODO: pre-resolved child?
8669fn analyzeOptionalPayloadPtr(8084fn analyzeOptionalPayloadPtr(
8670 sema: *Sema,8085 sema: *Sema,
8671 block: *Block,8086 block: *Block,
...@@ -8685,7 +8100,8 @@ fn analyzeOptionalPayloadPtr(...@@ -8685,7 +8100,8 @@ fn analyzeOptionalPayloadPtr(
8685 }8100 }
86868101
8687 const child_type = opt_type.optionalChild(zcu);8102 const child_type = opt_type.optionalChild(zcu);
8688 const child_pointer = try pt.ptrTypeSema(.{8103 try sema.ensureLayoutResolved(child_type);
8104 const child_pointer = try pt.ptrType(.{
8689 .child = child_type.toIntern(),8105 .child = child_type.toIntern(),
8690 .flags = .{8106 .flags = .{
8691 .is_const = optional_ptr_ty.isConstPtr(zcu),8107 .is_const = optional_ptr_ty.isConstPtr(zcu),
...@@ -8698,7 +8114,7 @@ fn analyzeOptionalPayloadPtr(...@@ -8698,7 +8114,7 @@ fn analyzeOptionalPayloadPtr(
8698 if (sema.isComptimeMutablePtr(ptr_val)) {8114 if (sema.isComptimeMutablePtr(ptr_val)) {
8699 // Set the optional to non-null at comptime.8115 // Set the optional to non-null at comptime.
8700 // If the payload is OPV, we must use that value instead of undef.8116 // If the payload is OPV, we must use that value instead of undef.
8701 const payload_val = try sema.typeHasOnePossibleValue(child_type) orelse try pt.undefValue(child_type);8117 const payload_val = try child_type.onePossibleValue(pt) orelse try pt.undefValue(child_type);
8702 const opt_val = try pt.intern(.{ .opt = .{8118 const opt_val = try pt.intern(.{ .opt = .{
8703 .ty = opt_type.toIntern(),8119 .ty = opt_type.toIntern(),
8704 .val = payload_val.toIntern(),8120 .val = payload_val.toIntern(),
...@@ -8759,7 +8175,7 @@ fn zirOptionalPayload(...@@ -8759,7 +8175,7 @@ fn zirOptionalPayload(
8759 // TODO https://github.com/ziglang/zig/issues/65978175 // TODO https://github.com/ziglang/zig/issues/6597
8760 if (true) break :t operand_ty;8176 if (true) break :t operand_ty;
8761 const ptr_info = operand_ty.ptrInfo(zcu);8177 const ptr_info = operand_ty.ptrInfo(zcu);
8762 break :t try pt.ptrTypeSema(.{8178 break :t try pt.ptrType(.{
8763 .child = ptr_info.child,8179 .child = ptr_info.child,
8764 .flags = .{8180 .flags = .{
8765 .alignment = ptr_info.flags.alignment,8181 .alignment = ptr_info.flags.alignment,
...@@ -8784,11 +8200,14 @@ fn zirOptionalPayload(...@@ -8784,11 +8200,14 @@ fn zirOptionalPayload(
8784 return .unreachable_value;8200 return .unreachable_value;
8785 }8201 }
87868202
8787 try sema.requireRuntimeBlock(block, src, null);
8788 if (safety_check and block.wantSafety()) {8203 if (safety_check and block.wantSafety()) {
8789 const is_non_null = try block.addUnOp(.is_non_null, operand);8204 const is_non_null = try block.addUnOp(.is_non_null, operand);
8790 try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);8205 try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null);
8791 }8206 }
8207
8208 // If the payload is OPV, we need the safety check but have a comptime-known result.
8209 if (try result_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
8210
8792 return block.addTyOp(.optional_payload, result_ty, operand);8211 return block.addTyOp(.optional_payload, result_ty, operand);
8793}8212}
87948213
...@@ -8844,8 +8263,8 @@ fn analyzeErrUnionPayload(...@@ -8844,8 +8263,8 @@ fn analyzeErrUnionPayload(
8844 try sema.addSafetyCheckUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);8263 try sema.addSafetyCheckUnwrapError(block, src, operand, .unwrap_errunion_err, .is_non_err);
8845 }8264 }
88468265
8847 if (try sema.typeHasOnePossibleValue(payload_ty)) |payload_only_value| {8266 if (try payload_ty.onePossibleValue(pt)) |payload_opv| {
8848 return Air.internedToRef(payload_only_value.toIntern());8267 return .fromValue(payload_opv);
8849 }8268 }
88508269
8851 return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);8270 return block.addTyOp(.unwrap_errunion_payload, payload_ty, operand);
...@@ -8867,6 +8286,7 @@ fn zirErrUnionPayloadPtr(...@@ -8867,6 +8286,7 @@ fn zirErrUnionPayloadPtr(
8867 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);8286 return sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
8868}8287}
88698288
8289/// MLUGG TODO LAYOUT: already-resolved child?
8870fn analyzeErrUnionPayloadPtr(8290fn analyzeErrUnionPayloadPtr(
8871 sema: *Sema,8291 sema: *Sema,
8872 block: *Block,8292 block: *Block,
...@@ -8888,7 +8308,8 @@ fn analyzeErrUnionPayloadPtr(...@@ -8888,7 +8308,8 @@ fn analyzeErrUnionPayloadPtr(
88888308
8889 const err_union_ty = operand_ty.childType(zcu);8309 const err_union_ty = operand_ty.childType(zcu);
8890 const payload_ty = err_union_ty.errorUnionPayload(zcu);8310 const payload_ty = err_union_ty.errorUnionPayload(zcu);
8891 const operand_pointer_ty = try pt.ptrTypeSema(.{8311 try sema.ensureLayoutResolved(payload_ty);
8312 const operand_pointer_ty = try pt.ptrType(.{
8892 .child = payload_ty.toIntern(),8313 .child = payload_ty.toIntern(),
8893 .flags = .{8314 .flags = .{
8894 .is_const = operand_ty.isConstPtr(zcu),8315 .is_const = operand_ty.isConstPtr(zcu),
...@@ -8901,7 +8322,7 @@ fn analyzeErrUnionPayloadPtr(...@@ -8901,7 +8322,7 @@ fn analyzeErrUnionPayloadPtr(
8901 if (sema.isComptimeMutablePtr(ptr_val)) {8322 if (sema.isComptimeMutablePtr(ptr_val)) {
8902 // Set the error union to non-error at comptime.8323 // Set the error union to non-error at comptime.
8903 // If the payload is OPV, we must use that value instead of undef.8324 // If the payload is OPV, we must use that value instead of undef.
8904 const payload_val = try sema.typeHasOnePossibleValue(payload_ty) orelse try pt.undefValue(payload_ty);8325 const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty);
8905 const eu_val = try pt.intern(.{ .error_union = .{8326 const eu_val = try pt.intern(.{ .error_union = .{
8906 .ty = err_union_ty.toIntern(),8327 .ty = err_union_ty.toIntern(),
8907 .val = .{ .payload = payload_val.toIntern() },8328 .val = .{ .payload = payload_val.toIntern() },
...@@ -9571,10 +8992,6 @@ fn funcCommon(...@@ -9571,10 +8992,6 @@ fn funcCommon(
95718992
9572 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });8993 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = src_node_offset });
9573 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });8994 const cc_src = block.src(.{ .node_offset_fn_type_cc = src_node_offset });
9574 const func_src = block.nodeOffset(src_node_offset);
9575
9576 const ret_ty_requires_comptime = try bare_return_type.comptimeOnlySema(pt);
9577 var is_generic = bare_return_type.isGenericPoison() or ret_ty_requires_comptime;
95788995
9579 var comptime_bits: u32 = 0;8996 var comptime_bits: u32 = 0;
9580 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {8997 for (block.params.items(.ty), block.params.items(.is_comptime), 0..) |param_ty_ip, param_is_comptime, i| {
...@@ -9587,11 +9004,7 @@ fn funcCommon(...@@ -9587,11 +9004,7 @@ fn funcCommon(
9587 .fn_proto_node_offset = src_node_offset,9004 .fn_proto_node_offset = src_node_offset,
9588 .param_index = @intCast(i),9005 .param_index = @intCast(i),
9589 } });9006 } });
9590 const param_ty_comptime = try param_ty.comptimeOnlySema(pt);
9591 const param_ty_generic = param_ty.isGenericPoison();9007 const param_ty_generic = param_ty.isGenericPoison();
9592 if (param_is_comptime or param_ty_comptime or param_ty_generic) {
9593 is_generic = true;
9594 }
9595 if (param_is_comptime) {9008 if (param_is_comptime) {
9596 comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error9009 comptime_bits |= @as(u32, 1) << @intCast(i); // TODO: handle cast error
9597 }9010 }
...@@ -9609,24 +9022,6 @@ fn funcCommon(...@@ -9609,24 +9022,6 @@ fn funcCommon(
9609 param_src,9022 param_src,
9610 cc,9023 cc,
9611 );9024 );
9612 if (param_ty_comptime and !param_is_comptime and has_body and !block.isComptime()) {
9613 const msg = msg: {
9614 const msg = try sema.errMsg(param_src, "parameter of type '{f}' must be declared comptime", .{
9615 param_ty.fmt(pt),
9616 });
9617 errdefer msg.destroy(sema.gpa);
9618
9619 try sema.explainWhyTypeIsComptime(msg, param_src, param_ty);
9620
9621 try sema.addDeclaredHereNote(msg, param_ty);
9622 break :msg msg;
9623 };
9624 return sema.failWithOwnedErrorMsg(block, msg);
9625 }
9626 }
9627
9628 if (var_args and is_generic) {
9629 return sema.fail(block, func_src, "generic function cannot be variadic", .{});
9630 }9025 }
96319026
9632 try sema.checkReturnTypeAndCallConvCommon(9027 try sema.checkReturnTypeAndCallConvCommon(
...@@ -9643,46 +9038,6 @@ fn funcCommon(...@@ -9643,46 +9038,6 @@ fn funcCommon(
9643 is_noinline,9038 is_noinline,
9644 );9039 );
96459040
9646 // If the return type is comptime-only but not dependent on parameters then
9647 // all parameter types also need to be comptime.
9648 if (has_body and ret_ty_requires_comptime and !block.isComptime()) comptime_check: {
9649 for (block.params.items(.is_comptime)) |is_comptime| {
9650 if (!is_comptime) break;
9651 } else break :comptime_check;
9652 const ies_ret_ty_prefix: []const u8 = if (inferred_error_set) "!" else "";
9653 const msg = try sema.errMsg(
9654 ret_ty_src,
9655 "function with comptime-only return type '{s}{f}' requires all parameters to be comptime",
9656 .{ ies_ret_ty_prefix, bare_return_type.fmt(pt) },
9657 );
9658 errdefer msg.destroy(sema.gpa);
9659 try sema.explainWhyTypeIsComptime(msg, ret_ty_src, bare_return_type);
9660
9661 const tags = sema.code.instructions.items(.tag);
9662 const data = sema.code.instructions.items(.data);
9663 const param_body = sema.code.getParamBody(func_inst);
9664 for (
9665 block.params.items(.is_comptime),
9666 block.params.items(.name),
9667 param_body[0..block.params.len],
9668 ) |is_comptime, name_nts, param_index| {
9669 if (!is_comptime) {
9670 const param_src = block.tokenOffset(switch (tags[@intFromEnum(param_index)]) {
9671 .param => data[@intFromEnum(param_index)].pl_tok.src_tok,
9672 .param_anytype => data[@intFromEnum(param_index)].str_tok.src_tok,
9673 else => unreachable,
9674 });
9675 const name = sema.code.nullTerminatedString(name_nts);
9676 if (name.len != 0) {
9677 try sema.errNote(param_src, msg, "param '{s}' is required to be comptime", .{name});
9678 } else {
9679 try sema.errNote(param_src, msg, "param is required to be comptime", .{});
9680 }
9681 }
9682 }
9683 return sema.failWithOwnedErrorMsg(block, msg);
9684 }
9685
9686 const param_types = block.params.items(.ty);9041 const param_types = block.params.items(.ty);
96879042
9688 if (inferred_error_set) {9043 if (inferred_error_set) {
...@@ -9696,7 +9051,6 @@ fn funcCommon(...@@ -9696,7 +9051,6 @@ fn funcCommon(
9696 .bare_return_type = bare_return_type.toIntern(),9051 .bare_return_type = bare_return_type.toIntern(),
9697 .cc = cc,9052 .cc = cc,
9698 .is_var_args = var_args,9053 .is_var_args = var_args,
9699 .is_generic = is_generic,
9700 .is_noinline = is_noinline,9054 .is_noinline = is_noinline,
97019055
9702 .zir_body_inst = try block.trackZir(func_inst),9056 .zir_body_inst = try block.trackZir(func_inst),
...@@ -9714,7 +9068,6 @@ fn funcCommon(...@@ -9714,7 +9068,6 @@ fn funcCommon(
9714 .return_type = bare_return_type.toIntern(),9068 .return_type = bare_return_type.toIntern(),
9715 .cc = cc,9069 .cc = cc,
9716 .is_var_args = var_args,9070 .is_var_args = var_args,
9717 .is_generic = is_generic,
9718 .is_noinline = is_noinline,9071 .is_noinline = is_noinline,
9719 });9072 });
97209073
...@@ -9845,16 +9198,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -9845,16 +9198,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
9845 if (!ptr_ty.isPtrAtRuntime(zcu)) {9198 if (!ptr_ty.isPtrAtRuntime(zcu)) {
9846 return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)});9199 return sema.fail(block, ptr_src, "expected pointer, found '{f}'", .{ptr_ty.fmt(pt)});
9847 }9200 }
9848 const pointee_ty = ptr_ty.childType(zcu);9201
9849 if (try ptr_ty.comptimeOnlySema(pt)) {
9850 const msg = msg: {
9851 const msg = try sema.errMsg(ptr_src, "comptime-only type '{f}' has no pointer address", .{pointee_ty.fmt(pt)});
9852 errdefer msg.destroy(sema.gpa);
9853 try sema.explainWhyTypeIsComptime(msg, ptr_src, pointee_ty);
9854 break :msg msg;
9855 };
9856 return sema.failWithOwnedErrorMsg(block, msg);
9857 }
9858 const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;9202 const len = if (is_vector) operand_ty.vectorLen(zcu) else undefined;
9859 const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .usize_type, .len = len }) else .usize;9203 const dest_ty: Type = if (is_vector) try pt.vectorType(.{ .child = .usize_type, .len = len }) else .usize;
98609204
...@@ -9863,7 +9207,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -9863,7 +9207,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
9863 if (operand_val.isUndef(zcu)) {9207 if (operand_val.isUndef(zcu)) {
9864 return .undef_usize;9208 return .undef_usize;
9865 }9209 }
9866 const addr = try operand_val.getUnsignedIntSema(pt) orelse {9210 const addr = operand_val.getUnsignedInt(zcu) orelse {
9867 // Wasn't an integer pointer. This is a runtime operation.9211 // Wasn't an integer pointer. This is a runtime operation.
9868 break :ct;9212 break :ct;
9869 };9213 };
...@@ -9879,7 +9223,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -9879,7 +9223,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
9879 new_elem.* = .undef_usize;9223 new_elem.* = .undef_usize;
9880 continue;9224 continue;
9881 }9225 }
9882 const addr = try ptr_val.getUnsignedIntSema(pt) orelse {9226 const addr = ptr_val.getUnsignedInt(zcu) orelse {
9883 // A vector element wasn't an integer pointer. This is a runtime operation.9227 // A vector element wasn't an integer pointer. This is a runtime operation.
9884 break :ct;9228 break :ct;
9885 };9229 };
...@@ -10044,7 +9388,7 @@ fn intCast(...@@ -10044,7 +9388,7 @@ fn intCast(
10044 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);9388 try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);
10045 const is_vector = dest_ty.zigTypeTag(zcu) == .vector;9389 const is_vector = dest_ty.zigTypeTag(zcu) == .vector;
100469390
10047 if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| {9391 if (try dest_ty.onePossibleValue(pt)) |opv| {
10048 // requirement: intCast(u0, input) iff input == 09392 // requirement: intCast(u0, input) iff input == 0
10049 if (block.wantSafety()) {9393 if (block.wantSafety()) {
10050 try sema.requireRuntimeBlock(block, src, operand_src);9394 try sema.requireRuntimeBlock(block, src, operand_src);
...@@ -10382,6 +9726,8 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -10382,6 +9726,8 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
10382 };9726 };
10383 return sema.failWithOwnedErrorMsg(block, msg);9727 return sema.failWithOwnedErrorMsg(block, msg);
10384 }9728 }
9729 try sema.checkIndexable(block, src, indexable_ty);
9730 try sema.ensureLayoutResolved(indexable_ty.childType(zcu));
10385 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);9731 return sema.elemPtrOneLayerOnly(block, src, array_ptr, elem_index, src, false, false);
10386}9732}
103879733
...@@ -10764,7 +10110,8 @@ fn analyzeSwitchBlock(...@@ -10764,7 +10110,8 @@ fn analyzeSwitchBlock(
10764 .{ raw_operand, .none };10110 .{ raw_operand, .none };
1076510111
10766 const operand_ty = sema.typeOf(val);10112 const operand_ty = sema.typeOf(val);
10767 const maybe_operand_opv = try sema.typeHasOnePossibleValue(operand_ty);10113 operand_ty.assertHasLayout(zcu);
10114 const maybe_operand_opv = try operand_ty.onePossibleValue(pt);
10768 const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {10115 const init_cond: Air.Inst.Ref, const item_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {
10769 .@"union" => tag: {10116 .@"union" => tag: {
10770 const tag_ty = operand_ty.unionTagType(zcu).?;10117 const tag_ty = operand_ty.unionTagType(zcu).?;
...@@ -10776,6 +10123,7 @@ fn analyzeSwitchBlock(...@@ -10776,6 +10123,7 @@ fn analyzeSwitchBlock(
10776 operand_ty,10123 operand_ty,
10777 },10124 },
10778 };10125 };
10126 item_ty.assertHasLayout(zcu);
1077910127
10780 if (zir_switch.has_continue and !block.isComptime()) {10128 if (zir_switch.has_continue and !block.isComptime()) {
10781 const operand_alloc: Air.Inst.Ref = if (zir_switch.any_maybe_runtime_capture and10129 const operand_alloc: Air.Inst.Ref = if (zir_switch.any_maybe_runtime_capture and
...@@ -10881,7 +10229,7 @@ fn analyzeSwitchBlock(...@@ -10881,7 +10229,7 @@ fn analyzeSwitchBlock(
10881 unreachable;10229 unreachable;
10882 }10230 }
1088310231
10884 if (try sema.typeHasOnePossibleValue(item_ty)) |item_opv| {10232 if (try item_ty.onePossibleValue(pt)) |item_opv| {
10885 // We simplify conditions with OPV to either a `loop` or a `block` since10233 // We simplify conditions with OPV to either a `loop` or a `block` since
10886 // we cannot switch on a value which doesn't exist at runtime.10234 // we cannot switch on a value which doesn't exist at runtime.
10887 assert(operand == .loop); // `simple` should have already been comptime-resolved above!10235 assert(operand == .loop); // `simple` should have already been comptime-resolved above!
...@@ -11249,8 +10597,8 @@ fn finishSwitchBr(...@@ -11249,8 +10597,8 @@ fn finishSwitchBr(
11249 var item = sema.resolveConstDefinedValue(block, .unneeded, range_ref[0], undefined) catch unreachable;10597 var item = sema.resolveConstDefinedValue(block, .unneeded, range_ref[0], undefined) catch unreachable;
11250 const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_ref[1], undefined) catch unreachable;10598 const item_last = sema.resolveConstDefinedValue(block, .unneeded, range_ref[1], undefined) catch unreachable;
1125110599
11252 if (try item.getUnsignedIntSema(pt)) |first_int| {10600 if (item.getUnsignedInt(zcu)) |first_int| {
11253 if (try item_last.getUnsignedIntSema(pt)) |last_int| {10601 if (item_last.getUnsignedInt(zcu)) |last_int| {
11254 if (std.math.cast(u32, last_int - first_int)) |range_len| {10602 if (std.math.cast(u32, last_int - first_int)) |range_len| {
11255 try branch_hints.ensureUnusedCapacity(gpa, range_len);10603 try branch_hints.ensureUnusedCapacity(gpa, range_len);
11256 }10604 }
...@@ -11259,7 +10607,6 @@ fn finishSwitchBr(...@@ -11259,7 +10607,6 @@ fn finishSwitchBr(
1125910607
11260 var prev_result_overflowed = false;10608 var prev_result_overflowed = false;
11261 while (item.compareScalar(.lte, item_last, operand_ty, zcu)) : ({10609 while (item.compareScalar(.lte, item_last, operand_ty, zcu)) : ({
11262 // Previous validation has resolved any possible lazy values.
11263 const int_val: Value, const int_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {10610 const int_val: Value, const int_ty: Type = switch (operand_ty.zigTypeTag(zcu)) {
11264 .int => .{ item, operand_ty },10611 .int => .{ item, operand_ty },
11265 .@"enum" => b: {10612 .@"enum" => b: {
...@@ -11896,72 +11243,68 @@ fn validateSwitchBlock(...@@ -11896,72 +11243,68 @@ fn validateSwitchBlock(
11896 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst});11243 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst});
11897 }11244 }
1189811245
11899 const operand_ty: Type, const item_ty: Type = check_operand: {11246 const operand_ty = operand_ty: {
11900 const operand_ty = operand_ty: {11247 const raw_operand_ty = sema.typeOf(raw_operand);
11901 const raw_operand_ty = sema.typeOf(raw_operand);11248 if (operand_is_ref) {
11902 if (operand_is_ref) {11249 try sema.checkPtrType(block, operand_src, raw_operand_ty, false);
11903 try sema.checkPtrType(block, operand_src, raw_operand_ty, false);11250 break :operand_ty raw_operand_ty.childType(zcu);
11904 break :operand_ty raw_operand_ty.childType(zcu);11251 }
11905 }11252 break :operand_ty raw_operand_ty;
11906 break :operand_ty raw_operand_ty;11253 };
11907 };11254 try sema.ensureLayoutResolved(operand_ty);
11908
11909 const item_ty: Type = item_ty: {
11910 switch (operand_ty.zigTypeTag(zcu)) {
11911 .@"enum",
11912 .error_set,
11913 .int,
11914 .comptime_int,
11915 .type,
11916 .enum_literal,
11917 .@"fn",
11918 .bool,
11919 .void,
11920 => break :item_ty operand_ty,
1192111255
11922 .@"union" => {11256 const item_ty: Type = item_ty: {
11923 try operand_ty.resolveFields(pt);11257 switch (operand_ty.zigTypeTag(zcu)) {
11924 const enum_ty = operand_ty.unionTagType(zcu) orelse {11258 .@"enum",
11925 return sema.failWithOwnedErrorMsg(block, msg: {11259 .error_set,
11926 const msg = try sema.errMsg(operand_src, "switch on union with no attached enum", .{});11260 .int,
11927 errdefer msg.destroy(sema.gpa);11261 .comptime_int,
11928 if (operand_ty.srcLocOrNull(zcu)) |union_src| {11262 .type,
11929 try sema.errNote(union_src, msg, "consider 'union(enum)' here", .{});11263 .enum_literal,
11930 }11264 .@"fn",
11931 break :msg msg;11265 .bool,
11932 });11266 .void,
11933 };11267 => break :item_ty operand_ty,
11934 break :item_ty enum_ty;
11935 },
1193611268
11937 .pointer => {11269 .@"union" => {
11938 if (!operand_ty.isSlice(zcu)) {11270 const enum_ty = operand_ty.unionTagType(zcu) orelse {
11939 break :item_ty operand_ty;11271 return sema.failWithOwnedErrorMsg(block, msg: {
11940 }11272 const msg = try sema.errMsg(operand_src, "switch on union with no attached enum", .{});
11941 },11273 errdefer msg.destroy(sema.gpa);
11274 if (operand_ty.srcLocOrNull(zcu)) |union_src| {
11275 try sema.errNote(union_src, msg, "consider 'union(enum)' here", .{});
11276 }
11277 break :msg msg;
11278 });
11279 };
11280 break :item_ty enum_ty;
11281 },
1194211282
11943 else => {},11283 .pointer => {
11944 }11284 if (!operand_ty.isSlice(zcu)) {
11945 return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)});11285 break :item_ty operand_ty;
11946 };11286 }
11287 },
1194711288
11948 if (zir_switch.has_continue and !block.isComptime()) {11289 else => {},
11949 if (try operand_ty.comptimeOnlySema(pt)) {
11950 // Even if the operand is comptime-known, this `switch` is runtime.
11951 return sema.failWithOwnedErrorMsg(block, msg: {
11952 const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)});
11953 errdefer msg.destroy(gpa);
11954 try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{});
11955 try sema.explainWhyTypeIsComptime(msg, operand_src, operand_ty);
11956 break :msg msg;
11957 });
11958 }
11959 try sema.validateRuntimeValue(block, operand_src, raw_operand);
11960 }11290 }
1196111291 return sema.fail(block, operand_src, "switch on type '{f}'", .{operand_ty.fmt(pt)});
11962 break :check_operand .{ operand_ty, item_ty };
11963 };11292 };
1196411293
11294 if (zir_switch.has_continue and !block.isComptime()) {
11295 if (operand_ty.comptimeOnly(zcu)) {
11296 // Even if the operand is comptime-known, this `switch` is runtime.
11297 return sema.failWithOwnedErrorMsg(block, msg: {
11298 const msg = try sema.errMsg(operand_src, "operand of switch loop has comptime-only type '{f}'", .{operand_ty.fmt(pt)});
11299 errdefer msg.destroy(gpa);
11300 try sema.errNote(operand_src, msg, "switch loops are evaluated at runtime outside of comptime scopes", .{});
11301 try sema.explainWhyTypeIsComptime(msg, operand_src, operand_ty);
11302 break :msg msg;
11303 });
11304 }
11305 try sema.validateRuntimeValue(block, operand_src, raw_operand);
11306 }
11307
11965 const has_else = zir_switch.else_case != null;11308 const has_else = zir_switch.else_case != null;
11966 const has_under = zir_switch.has_under;11309 const has_under = zir_switch.has_under;
1196711310
...@@ -12305,7 +11648,7 @@ fn resolveSwitchBlock(...@@ -12305,7 +11648,7 @@ fn resolveSwitchBlock(
12305 child_block: *Block,11648 child_block: *Block,
12306 operand: SwitchOperand,11649 operand: SwitchOperand,
12307 raw_operand_ty: Type,11650 raw_operand_ty: Type,
12308 maybe_lazy_cond_val: Value,11651 cond_val: Value,
12309 merges: *Block.Merges,11652 merges: *Block.Merges,
12310 switch_inst: Zir.Inst.Index,11653 switch_inst: Zir.Inst.Index,
12311 zir_switch: *const Zir.UnwrappedSwitchBlock,11654 zir_switch: *const Zir.UnwrappedSwitchBlock,
...@@ -12325,9 +11668,6 @@ fn resolveSwitchBlock(...@@ -12325,9 +11668,6 @@ fn resolveSwitchBlock(
12325 const err_set = item_ty.zigTypeTag(zcu) == .error_set;11668 const err_set = item_ty.zigTypeTag(zcu) == .error_set;
1232611669
12327 const cond_ref = operand.simple.cond;11670 const cond_ref = operand.simple.cond;
12328 // We have to resolve lazy values to ensure that comparisons with switch
12329 // prong items don't produce false negatives.
12330 const cond_val = try sema.resolveLazyValue(maybe_lazy_cond_val);
1233111671
12332 const case_vals = validated_switch.case_vals;11672 const case_vals = validated_switch.case_vals;
12333 var case_val_idx: usize = 0;11673 var case_val_idx: usize = 0;
...@@ -12617,14 +11957,12 @@ fn wantSwitchProngBodyAnalysis(...@@ -12617,14 +11957,12 @@ fn wantSwitchProngBodyAnalysis(
12617) bool {11957) bool {
12618 const zcu = sema.pt.zcu;11958 const zcu = sema.pt.zcu;
12619 if (union_originally) {11959 if (union_originally) {
12620 const unresolved_item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;11960 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;
12621 const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable;
12622 const field_ty = operand_ty.unionFieldType(item_val, zcu).?;11961 const field_ty = operand_ty.unionFieldType(item_val, zcu).?;
12623 if (field_ty.isNoReturn(zcu)) return false;11962 if (field_ty.isNoReturn(zcu)) return false;
12624 }11963 }
12625 if (err_set and prong_is_comptime_unreach) {11964 if (err_set and prong_is_comptime_unreach) {
12626 const unresolved_item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;11965 const item_val = sema.resolveConstDefinedValue(block, .unneeded, item_ref, undefined) catch unreachable;
12627 const item_val = sema.resolveLazyValue(unresolved_item_val) catch unreachable;
12628 const err_name = item_val.getErrorName(zcu).unwrap().?;11966 const err_name = item_val.getErrorName(zcu).unwrap().?;
12629 if (!Type.errorSetHasFieldIp(&zcu.intern_pool, operand_ty.toIntern(), err_name)) return false;11967 if (!Type.errorSetHasFieldIp(&zcu.intern_pool, operand_ty.toIntern(), err_name)) return false;
12630 }11968 }
...@@ -12807,7 +12145,7 @@ fn analyzeSwitchPayloadCapture(...@@ -12807,7 +12145,7 @@ fn analyzeSwitchPayloadCapture(
12807 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);12145 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
12808 if (capture_by_ref) {12146 if (capture_by_ref) {
12809 const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu);12147 const operand_ptr_info = sema.typeOf(operand_ptr).ptrInfo(zcu);
12810 const ptr_field_ty = try pt.ptrTypeSema(.{12148 const ptr_field_ty = try pt.ptrType(.{
12811 .child = field_ty.toIntern(),12149 .child = field_ty.toIntern(),
12812 .flags = .{12150 .flags = .{
12813 .is_const = operand_ptr_info.flags.is_const,12151 .is_const = operand_ptr_info.flags.is_const,
...@@ -12821,6 +12159,7 @@ fn analyzeSwitchPayloadCapture(...@@ -12821,6 +12159,7 @@ fn analyzeSwitchPayloadCapture(
12821 const tag_and_val = ip.indexToKey(union_val.toIntern()).un;12159 const tag_and_val = ip.indexToKey(union_val.toIntern()).un;
12822 return .fromIntern(tag_and_val.val);12160 return .fromIntern(tag_and_val.val);
12823 }12161 }
12162 if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
12824 return case_block.addStructFieldVal(operand_val, field_index, field_ty);12163 return case_block.addStructFieldVal(operand_val, field_index, field_ty);
12825 }12164 }
12826 } else if (capture_by_ref) {12165 } else if (capture_by_ref) {
...@@ -12914,13 +12253,27 @@ fn analyzeSwitchPayloadCapture(...@@ -12914,13 +12253,27 @@ fn analyzeSwitchPayloadCapture(
12914 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);12253 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
12915 for (field_indices, dummy_captures) |field_idx, *dummy| {12254 for (field_indices, dummy_captures) |field_idx, *dummy| {
12916 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);12255 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
12917 const field_ptr_ty = try pt.ptrTypeSema(.{12256 const field_ptr_ty = try pt.ptrType(.{
12918 .child = field_ty.toIntern(),12257 .child = field_ty.toIntern(),
12919 .flags = .{12258 .flags = .{
12920 .is_const = operand_ptr_info.flags.is_const,12259 .is_const = operand_ptr_info.flags.is_const,
12921 .is_volatile = operand_ptr_info.flags.is_volatile,12260 .is_volatile = operand_ptr_info.flags.is_volatile,
12922 .address_space = operand_ptr_info.flags.address_space,12261 .address_space = operand_ptr_info.flags.address_space,
12923 .alignment = union_obj.fieldAlign(ip, field_idx),12262 // TODO MLUGG: double-check this. and, um, EVERYWHERE we do ptr alignment...
12263 .alignment = a: {
12264 if (operand_ty.explicitFieldAlignment(field_idx, zcu) == .none and
12265 operand_ptr_info.flags.alignment == .none)
12266 {
12267 break :a .none;
12268 }
12269
12270 const union_align = switch (operand_ptr_info.flags.alignment) {
12271 .none => operand_ty.abiAlignment(zcu),
12272 else => |a| a,
12273 };
12274 const field_align = operand_ty.resolvedFieldAlignment(field_idx, zcu);
12275 break :a .minStrict(union_align, field_align);
12276 },
12924 },12277 },
12925 });12278 });
12926 dummy.* = try pt.undefRef(field_ptr_ty);12279 dummy.* = try pt.undefRef(field_ptr_ty);
...@@ -12963,6 +12316,8 @@ fn analyzeSwitchPayloadCapture(...@@ -12963,6 +12316,8 @@ fn analyzeSwitchPayloadCapture(
12963 return case_block.addStructFieldPtr(operand_ptr, first_field_index, capture_ptr_ty);12316 return case_block.addStructFieldPtr(operand_ptr, first_field_index, capture_ptr_ty);
12964 }12317 }
1296512318
12319 if (try capture_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
12320
12966 if (try sema.resolveDefinedValue(case_block, operand_src, operand_val)) |operand_val_val| {12321 if (try sema.resolveDefinedValue(case_block, operand_src, operand_val)) |operand_val_val| {
12967 if (operand_val_val.isUndef(zcu)) return pt.undefRef(capture_ty);12322 if (operand_val_val.isUndef(zcu)) return pt.undefRef(capture_ty);
12968 const union_val = ip.indexToKey(operand_val_val.toIntern()).un;12323 const union_val = ip.indexToKey(operand_val_val.toIntern()).un;
...@@ -13119,7 +12474,7 @@ fn analyzeSwitchPayloadCapture(...@@ -13119,7 +12474,7 @@ fn analyzeSwitchPayloadCapture(
13119 try sema.air_instructions.append(sema.gpa, .{12474 try sema.air_instructions.append(sema.gpa, .{
13120 .tag = .get_union_tag,12475 .tag = .get_union_tag,
13121 .data = .{ .ty_op = .{12476 .data = .{ .ty_op = .{
13122 .ty = .fromIntern(union_obj.enum_tag_ty),12477 .ty = .fromIntern(union_obj.enum_tag_type),
13123 .operand = operand_val,12478 .operand = operand_val,
13124 } },12479 } },
13125 });12480 });
...@@ -13261,17 +12616,8 @@ fn resolveSwitchItem(...@@ -13261,17 +12616,8 @@ fn resolveSwitchItem(
13261 }12616 }
13262 break :item_ref try sema.coerce(block, item_ty, uncoerced, item_src);12617 break :item_ref try sema.coerce(block, item_ty, uncoerced, item_src);
13263 };12618 };
13264 const maybe_lazy = try sema.resolveConstDefinedValue(block, item_src, item_ref, .{ .simple = .switch_item });12619 const val = try sema.resolveConstDefinedValue(block, item_src, item_ref, .{ .simple = .switch_item });
1326512620 return .{ .{ .ref = item_ref, .val = val }, end };
13266 // We have to resolve lazy values here to avoid false negatives when detecting
13267 // duplicate items and comparing items to a comptime-known switch operand.
13268
13269 const val = try sema.resolveLazyValue(maybe_lazy);
13270 const ref: Air.Inst.Ref = if (val.toIntern() == maybe_lazy.toIntern())
13271 item_ref
13272 else
13273 .fromValue(val);
13274 return .{ .{ .ref = ref, .val = val }, end };
13275}12621}
1327612622
13277fn validateSwitchItemOrRange(12623fn validateSwitchItemOrRange(
...@@ -13488,7 +12834,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -13488,7 +12834,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13488 const name_src = block.builtinCallArgSrc(inst_data.src_node, 1);12834 const name_src = block.builtinCallArgSrc(inst_data.src_node, 1);
13489 const ty = try sema.resolveType(block, ty_src, extra.lhs);12835 const ty = try sema.resolveType(block, ty_src, extra.lhs);
13490 const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name });12836 const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{ .simple = .field_name });
13491 try ty.resolveFields(pt);12837 try sema.ensureLayoutResolved(ty);
13492 const ip = &zcu.intern_pool;12838 const ip = &zcu.intern_pool;
1349312839
13494 const has_field = hf: {12840 const has_field = hf: {
...@@ -13510,7 +12856,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -13510,7 +12856,8 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
13510 },12856 },
13511 .union_type => {12857 .union_type => {
13512 const union_type = ip.loadUnionType(ty.toIntern());12858 const union_type = ip.loadUnionType(ty.toIntern());
13513 break :hf union_type.loadTagType(ip).nameIndex(ip, field_name) != null;12859 const enum_type = ip.loadEnumType(union_type.enum_tag_type);
12860 break :hf enum_type.nameIndex(ip, field_name) != null;
13514 },12861 },
13515 .enum_type => {12862 .enum_type => {
13516 break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;12863 break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;
...@@ -13569,10 +12916,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -13569,10 +12916,9 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
13569 switch (file.getMode()) {12916 switch (file.getMode()) {
13570 .zig => {12917 .zig => {
13571 try pt.ensureFileAnalyzed(file_index);12918 try pt.ensureFileAnalyzed(file_index);
13572 const ty = zcu.fileRootType(file_index);12919 const ty: Type = .fromInterned(zcu.fileRootType(file_index));
13573 try sema.declareDependency(.{ .interned = ty });
13574 try sema.addTypeReferenceEntry(operand_src, ty);12920 try sema.addTypeReferenceEntry(operand_src, ty);
13575 return Air.internedToRef(ty);12921 return .fromType(ty);
13576 },12922 },
13577 .zon => {12923 .zon => {
13578 const res_ty: InternPool.Index = b: {12924 const res_ty: InternPool.Index = b: {
...@@ -13692,8 +13038,8 @@ fn zirShl(...@@ -13692,8 +13038,8 @@ fn zirShl(
13692 // we already know `scalar_rhs_ty` is valid for `.shl` -- we only need to validate for `.shl_sat`.13038 // we already know `scalar_rhs_ty` is valid for `.shl` -- we only need to validate for `.shl_sat`.
13693 if (air_tag == .shl_sat) _ = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);13039 if (air_tag == .shl_sat) _ = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
1369413040
13695 const maybe_lhs_val = try sema.resolveValueResolveLazy(lhs);13041 const maybe_lhs_val = try sema.resolveValue(lhs);
13696 const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs);13042 const maybe_rhs_val = try sema.resolveValue(rhs);
1369713043
13698 const runtime_src = rs: {13044 const runtime_src = rs: {
13699 if (maybe_rhs_val) |rhs_val| {13045 if (maybe_rhs_val) |rhs_val| {
...@@ -13713,11 +13059,11 @@ fn zirShl(...@@ -13713,11 +13059,11 @@ fn zirShl(
13713 const bits = scalar_ty.intInfo(zcu).bits;13059 const bits = scalar_ty.intInfo(zcu).bits;
13714 switch (rhs_ty.zigTypeTag(zcu)) {13060 switch (rhs_ty.zigTypeTag(zcu)) {
13715 .int, .comptime_int => {13061 .int, .comptime_int => {
13716 switch (try rhs_val.orderAgainstZeroSema(pt)) {13062 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
13717 .gt => {13063 .gt => {
13718 if (air_tag != .shl_sat) {13064 if (air_tag != .shl_sat) {
13719 var rhs_space: Value.BigIntSpace = undefined;13065 var rhs_space: Value.BigIntSpace = undefined;
13720 const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);13066 const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu);
13721 if (rhs_bigint.orderAgainstScalar(bits) != .lt) {13067 if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
13722 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);13068 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
13723 }13069 }
...@@ -13736,11 +13082,11 @@ fn zirShl(...@@ -13736,11 +13082,11 @@ fn zirShl(
13736 .shl, .shl_exact => return sema.failWithUseOfUndef(block, rhs_src, elem_idx),13082 .shl, .shl_exact => return sema.failWithUseOfUndef(block, rhs_src, elem_idx),
13737 else => unreachable,13083 else => unreachable,
13738 };13084 };
13739 switch (try rhs_elem.orderAgainstZeroSema(pt)) {13085 switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) {
13740 .gt => {13086 .gt => {
13741 if (air_tag != .shl_sat) {13087 if (air_tag != .shl_sat) {
13742 var rhs_elem_space: Value.BigIntSpace = undefined;13088 var rhs_elem_space: Value.BigIntSpace = undefined;
13743 const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);13089 const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu);
13744 if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {13090 if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
13745 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);13091 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
13746 }13092 }
...@@ -13769,7 +13115,7 @@ fn zirShl(...@@ -13769,7 +13115,7 @@ fn zirShl(
13769 .shl, .shl_exact => try sema.checkAllScalarsDefined(block, lhs_src, lhs_val),13115 .shl, .shl_exact => try sema.checkAllScalarsDefined(block, lhs_src, lhs_val),
13770 else => unreachable,13116 else => unreachable,
13771 }13117 }
13772 if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs;13118 if (lhs_val.compareAllWithZero(.eq, zcu)) return lhs;
13773 }13119 }
13774 }13120 }
13775 break :rs rhs_src;13121 break :rs rhs_src;
...@@ -13785,13 +13131,13 @@ fn zirShl(...@@ -13785,13 +13131,13 @@ fn zirShl(
13785 const rt_rhs_scalar_ty = try pt.smallestUnsignedInt(bit_count);13131 const rt_rhs_scalar_ty = try pt.smallestUnsignedInt(bit_count);
13786 if (!rhs_ty.isVector(zcu)) break :rt_rhs try pt.intValue(13132 if (!rhs_ty.isVector(zcu)) break :rt_rhs try pt.intValue(
13787 rt_rhs_scalar_ty,13133 rt_rhs_scalar_ty,
13788 @min(try rhs_val.getUnsignedIntSema(pt) orelse bit_count, bit_count),13134 @min(rhs_val.getUnsignedInt(zcu) orelse bit_count, bit_count),
13789 );13135 );
13790 const rhs_len = rhs_ty.vectorLen(zcu);13136 const rhs_len = rhs_ty.vectorLen(zcu);
13791 const rhs_elems = try sema.arena.alloc(InternPool.Index, rhs_len);13137 const rhs_elems = try sema.arena.alloc(InternPool.Index, rhs_len);
13792 for (rhs_elems, 0..) |*rhs_elem, i| rhs_elem.* = (try pt.intValue(13138 for (rhs_elems, 0..) |*rhs_elem, i| rhs_elem.* = (try pt.intValue(
13793 rt_rhs_scalar_ty,13139 rt_rhs_scalar_ty,
13794 @min(try (try rhs_val.elemValue(pt, i)).getUnsignedIntSema(pt) orelse bit_count, bit_count),13140 @min((try rhs_val.elemValue(pt, i)).getUnsignedInt(zcu) orelse bit_count, bit_count),
13795 )).toIntern();13141 )).toIntern();
13796 break :rt_rhs try pt.aggregateValue(try pt.vectorType(.{13142 break :rt_rhs try pt.aggregateValue(try pt.vectorType(.{
13797 .len = rhs_len,13143 .len = rhs_len,
...@@ -13875,8 +13221,8 @@ fn zirShr(...@@ -13875,8 +13221,8 @@ fn zirShr(
13875 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);13221 try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
13876 const scalar_ty = lhs_ty.scalarType(zcu);13222 const scalar_ty = lhs_ty.scalarType(zcu);
1387713223
13878 const maybe_lhs_val = try sema.resolveValueResolveLazy(lhs);13224 const maybe_lhs_val = try sema.resolveValue(lhs);
13879 const maybe_rhs_val = try sema.resolveValueResolveLazy(rhs);13225 const maybe_rhs_val = try sema.resolveValue(rhs);
1388013226
13881 const runtime_src = rs: {13227 const runtime_src = rs: {
13882 if (maybe_rhs_val) |rhs_val| {13228 if (maybe_rhs_val) |rhs_val| {
...@@ -13893,10 +13239,10 @@ fn zirShr(...@@ -13893,10 +13239,10 @@ fn zirShr(
13893 const bits = scalar_ty.intInfo(zcu).bits;13239 const bits = scalar_ty.intInfo(zcu).bits;
13894 switch (rhs_ty.zigTypeTag(zcu)) {13240 switch (rhs_ty.zigTypeTag(zcu)) {
13895 .int, .comptime_int => {13241 .int, .comptime_int => {
13896 switch (try rhs_val.orderAgainstZeroSema(pt)) {13242 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
13897 .gt => {13243 .gt => {
13898 var rhs_space: Value.BigIntSpace = undefined;13244 var rhs_space: Value.BigIntSpace = undefined;
13899 const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);13245 const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu);
13900 if (rhs_bigint.orderAgainstScalar(bits) != .lt) {13246 if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
13901 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);13247 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
13902 }13248 }
...@@ -13912,10 +13258,10 @@ fn zirShr(...@@ -13912,10 +13258,10 @@ fn zirShr(
13912 if (rhs_elem.isUndef(zcu)) {13258 if (rhs_elem.isUndef(zcu)) {
13913 return sema.failWithUseOfUndef(block, rhs_src, elem_idx);13259 return sema.failWithUseOfUndef(block, rhs_src, elem_idx);
13914 }13260 }
13915 switch (try rhs_elem.orderAgainstZeroSema(pt)) {13261 switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) {
13916 .gt => {13262 .gt => {
13917 var rhs_elem_space: Value.BigIntSpace = undefined;13263 var rhs_elem_space: Value.BigIntSpace = undefined;
13918 const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);13264 const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu);
13919 if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {13265 if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
13920 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);13266 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
13921 }13267 }
...@@ -13936,7 +13282,7 @@ fn zirShr(...@@ -13936,7 +13282,7 @@ fn zirShr(
13936 }13282 }
13937 if (maybe_lhs_val) |lhs_val| {13283 if (maybe_lhs_val) |lhs_val| {
13938 try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);13284 try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);
13939 if (try lhs_val.compareAllWithZeroSema(.eq, pt)) return lhs;13285 if (lhs_val.compareAllWithZero(.eq, zcu)) return lhs;
13940 }13286 }
13941 }13287 }
13942 break :rs rhs_src;13288 break :rs rhs_src;
...@@ -14011,8 +13357,8 @@ fn zirBitwise(...@@ -14011,8 +13357,8 @@ fn zirBitwise(
14011 const runtime_src = runtime: {13357 const runtime_src = runtime: {
14012 // TODO: ask the linker what kind of relocations are available, and13358 // TODO: ask the linker what kind of relocations are available, and
14013 // in some cases emit a Value that means "this decl's address AND'd with this operand".13359 // in some cases emit a Value that means "this decl's address AND'd with this operand".
14014 if (try sema.resolveValueResolveLazy(casted_lhs)) |lhs_val| {13360 if (try sema.resolveValue(casted_lhs)) |lhs_val| {
14015 if (try sema.resolveValueResolveLazy(casted_rhs)) |rhs_val| {13361 if (try sema.resolveValue(casted_rhs)) |rhs_val| {
14016 const result_val = switch (air_tag) {13362 const result_val = switch (air_tag) {
14017 // zig fmt: off13363 // zig fmt: off
14018 .bit_and => try arith.bitwiseBin(sema, resolved_type, lhs_val, rhs_val, .@"and"),13364 .bit_and => try arith.bitwiseBin(sema, resolved_type, lhs_val, rhs_val, .@"and"),
...@@ -14106,13 +13452,13 @@ fn analyzeTupleCat(...@@ -14106,13 +13452,13 @@ fn analyzeTupleCat(
14106 var i: u32 = 0;13452 var i: u32 = 0;
14107 while (i < lhs_len) : (i += 1) {13453 while (i < lhs_len) : (i += 1) {
14108 types[i] = lhs_ty.fieldType(i, zcu).toIntern();13454 types[i] = lhs_ty.fieldType(i, zcu).toIntern();
14109 const default_val = lhs_ty.structFieldDefaultValue(i, zcu);
14110 values[i] = default_val.toIntern();
14111 const operand_src = block.src(.{ .array_cat_lhs = .{13455 const operand_src = block.src(.{ .array_cat_lhs = .{
14112 .array_cat_offset = src_node,13456 .array_cat_offset = src_node,
14113 .elem_index = i,13457 .elem_index = i,
14114 } });13458 } });
14115 if (default_val.toIntern() == .unreachable_value) {13459 if (lhs_ty.structFieldDefaultValue(i, zcu)) |default_val| {
13460 values[i] = default_val.toIntern();
13461 } else {
14116 runtime_src = operand_src;13462 runtime_src = operand_src;
14117 values[i] = .none;13463 values[i] = .none;
14118 }13464 }
...@@ -14120,13 +13466,13 @@ fn analyzeTupleCat(...@@ -14120,13 +13466,13 @@ fn analyzeTupleCat(
14120 i = 0;13466 i = 0;
14121 while (i < rhs_len) : (i += 1) {13467 while (i < rhs_len) : (i += 1) {
14122 types[i + lhs_len] = rhs_ty.fieldType(i, zcu).toIntern();13468 types[i + lhs_len] = rhs_ty.fieldType(i, zcu).toIntern();
14123 const default_val = rhs_ty.structFieldDefaultValue(i, zcu);
14124 values[i + lhs_len] = default_val.toIntern();
14125 const operand_src = block.src(.{ .array_cat_rhs = .{13469 const operand_src = block.src(.{ .array_cat_rhs = .{
14126 .array_cat_offset = src_node,13470 .array_cat_offset = src_node,
14127 .elem_index = i,13471 .elem_index = i,
14128 } });13472 } });
14129 if (default_val.toIntern() == .unreachable_value) {13473 if (rhs_ty.structFieldDefaultValue(i, zcu)) |default_val| {
13474 values[i + lhs_len] = default_val.toIntern();
13475 } else {
14130 runtime_src = operand_src;13476 runtime_src = operand_src;
14131 values[i + lhs_len] = .none;13477 values[i + lhs_len] = .none;
14132 }13478 }
...@@ -14290,8 +13636,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14290,8 +13636,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14290 var elem_i: u32 = 0;13636 var elem_i: u32 = 0;
14291 while (elem_i < lhs_len) : (elem_i += 1) {13637 while (elem_i < lhs_len) : (elem_i += 1) {
14292 const lhs_elem_i = elem_i;13638 const lhs_elem_i = elem_i;
14293 const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else Value.@"unreachable";13639 const elem_default_val: ?Value = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, zcu) else null;
14294 const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(pt, lhs_elem_i) else elem_default_val;13640 const elem_val = elem_default_val orelse try lhs_sub_val.elemValue(pt, lhs_elem_i);
14295 const elem_val_inst = Air.internedToRef(elem_val.toIntern());13641 const elem_val_inst = Air.internedToRef(elem_val.toIntern());
14296 const operand_src = block.src(.{ .array_cat_lhs = .{13642 const operand_src = block.src(.{ .array_cat_lhs = .{
14297 .array_cat_offset = inst_data.src_node,13643 .array_cat_offset = inst_data.src_node,
...@@ -14303,8 +13649,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14303,8 +13649,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14303 }13649 }
14304 while (elem_i < result_len) : (elem_i += 1) {13650 while (elem_i < result_len) : (elem_i += 1) {
14305 const rhs_elem_i = elem_i - lhs_len;13651 const rhs_elem_i = elem_i - lhs_len;
14306 const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else Value.@"unreachable";13652 const elem_default_val: ?Value = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, zcu) else null;
14307 const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(pt, rhs_elem_i) else elem_default_val;13653 const elem_val = elem_default_val orelse try rhs_sub_val.elemValue(pt, rhs_elem_i);
14308 const elem_val_inst = Air.internedToRef(elem_val.toIntern());13654 const elem_val_inst = Air.internedToRef(elem_val.toIntern());
14309 const operand_src = block.src(.{ .array_cat_rhs = .{13655 const operand_src = block.src(.{ .array_cat_rhs = .{
14310 .array_cat_offset = inst_data.src_node,13656 .array_cat_offset = inst_data.src_node,
...@@ -14324,18 +13670,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14324,18 +13670,18 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14324 try sema.requireRuntimeBlock(block, src, runtime_src);13670 try sema.requireRuntimeBlock(block, src, runtime_src);
1432513671
14326 if (ptr_addrspace) |ptr_as| {13672 if (ptr_addrspace) |ptr_as| {
14327 const constant_alloc_ty = try pt.ptrTypeSema(.{13673 const constant_alloc_ty = try pt.ptrType(.{
14328 .child = result_ty.toIntern(),13674 .child = result_ty.toIntern(),
14329 .flags = .{13675 .flags = .{
14330 .address_space = ptr_as,13676 .address_space = ptr_as,
14331 .is_const = true,13677 .is_const = true,
14332 },13678 },
14333 });13679 });
14334 const alloc_ty = try pt.ptrTypeSema(.{13680 const alloc_ty = try pt.ptrType(.{
14335 .child = result_ty.toIntern(),13681 .child = result_ty.toIntern(),
14336 .flags = .{ .address_space = ptr_as },13682 .flags = .{ .address_space = ptr_as },
14337 });13683 });
14338 const elem_ptr_ty = try pt.ptrTypeSema(.{13684 const elem_ptr_ty = try pt.ptrType(.{
14339 .child = resolved_elem_ty.toIntern(),13685 .child = resolved_elem_ty.toIntern(),
14340 .flags = .{ .address_space = ptr_as },13686 .flags = .{ .address_space = ptr_as },
14341 });13687 });
...@@ -14347,7 +13693,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14347,7 +13693,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14347 if (lhs_ty.zigTypeTag(zcu) == .pointer and13693 if (lhs_ty.zigTypeTag(zcu) == .pointer and
14348 rhs_ty.zigTypeTag(zcu) == .pointer)13694 rhs_ty.zigTypeTag(zcu) == .pointer)
14349 {13695 {
14350 const slice_ty = try pt.ptrTypeSema(.{13696 const slice_ty = try pt.ptrType(.{
14351 .child = resolved_elem_ty.toIntern(),13697 .child = resolved_elem_ty.toIntern(),
14352 .flags = .{13698 .flags = .{
14353 .size = .slice,13699 .size = .slice,
...@@ -14486,7 +13832,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins...@@ -14486,7 +13832,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
14486 .none => null,13832 .none => null,
14487 else => Value.fromInterned(ptr_info.sentinel),13833 else => Value.fromInterned(ptr_info.sentinel),
14488 },13834 },
14489 .len = try val.sliceLen(pt),13835 .len = val.sliceLen(zcu),
14490 };13836 };
14491 },13837 },
14492 .one => {13838 .one => {
...@@ -14500,8 +13846,20 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins...@@ -14500,8 +13846,20 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
14500 .@"struct" => {13846 .@"struct" => {
14501 if (operand_ty.isTuple(zcu) and peer_ty.isIndexable(zcu)) {13847 if (operand_ty.isTuple(zcu) and peer_ty.isIndexable(zcu)) {
14502 assert(!peer_ty.isTuple(zcu));13848 assert(!peer_ty.isTuple(zcu));
13849 const peer_elem_ty = switch (peer_ty.zigTypeTag(zcu)) {
13850 .pointer => switch (peer_ty.ptrSize(zcu)) {
13851 .one => switch (peer_ty.childType(zcu).zigTypeTag(zcu)) {
13852 .array, .vector => peer_ty.childType(zcu).childType(zcu),
13853 .@"struct" => return null,
13854 else => unreachable,
13855 },
13856 .many, .c, .slice => peer_ty.childType(zcu),
13857 },
13858 .vector, .array => peer_ty.childType(zcu),
13859 else => unreachable,
13860 };
14503 return .{13861 return .{
14504 .elem_type = peer_ty.elemType2(zcu),13862 .elem_type = peer_elem_ty,
14505 .sentinel = null,13863 .sentinel = null,
14506 .len = operand_ty.arrayLen(zcu),13864 .len = operand_ty.arrayLen(zcu),
14507 };13865 };
...@@ -14543,12 +13901,13 @@ fn analyzeTupleMul(...@@ -14543,12 +13901,13 @@ fn analyzeTupleMul(
14543 var runtime_src: ?LazySrcLoc = null;13901 var runtime_src: ?LazySrcLoc = null;
14544 for (0..tuple_len) |i| {13902 for (0..tuple_len) |i| {
14545 types[i] = operand_ty.fieldType(i, zcu).toIntern();13903 types[i] = operand_ty.fieldType(i, zcu).toIntern();
14546 values[i] = operand_ty.structFieldDefaultValue(i, zcu).toIntern();
14547 const operand_src = block.src(.{ .array_cat_lhs = .{13904 const operand_src = block.src(.{ .array_cat_lhs = .{
14548 .array_cat_offset = src_node,13905 .array_cat_offset = src_node,
14549 .elem_index = @intCast(i),13906 .elem_index = @intCast(i),
14550 } });13907 } });
14551 if (values[i] == .unreachable_value) {13908 if (operand_ty.structFieldDefaultValue(i, zcu)) |default_val| {
13909 values[i] = default_val.toIntern();
13910 } else {
14552 runtime_src = operand_src;13911 runtime_src = operand_src;
14553 values[i] = .none; // TODO don't treat unreachable_value as special13912 values[i] = .none; // TODO don't treat unreachable_value as special
14554 }13913 }
...@@ -14714,7 +14073,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14714,7 +14073,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14714 }14073 }
1471514074
14716 if (ptr_addrspace) |ptr_as| {14075 if (ptr_addrspace) |ptr_as| {
14717 const alloc_ty = try pt.ptrTypeSema(.{14076 const alloc_ty = try pt.ptrType(.{
14718 .child = result_ty.toIntern(),14077 .child = result_ty.toIntern(),
14719 .flags = .{14078 .flags = .{
14720 .address_space = ptr_as,14079 .address_space = ptr_as,
...@@ -14722,7 +14081,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14722,7 +14081,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
14722 },14081 },
14723 });14082 });
14724 const alloc = try block.addTy(.alloc, alloc_ty);14083 const alloc = try block.addTy(.alloc, alloc_ty);
14725 const elem_ptr_ty = try pt.ptrTypeSema(.{14084 const elem_ptr_ty = try pt.ptrType(.{
14726 .child = lhs_info.elem_type.toIntern(),14085 .child = lhs_info.elem_type.toIntern(),
14727 .flags = .{ .address_space = ptr_as },14086 .flags = .{ .address_space = ptr_as },
14728 });14087 });
...@@ -14859,8 +14218,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -14859,8 +14218,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1485914218
14860 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div);14219 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div);
1486114220
14862 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14221 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
14863 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14222 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1486414223
14865 if ((lhs_ty.zigTypeTag(zcu) == .comptime_float and rhs_ty.zigTypeTag(zcu) == .comptime_int) or14224 if ((lhs_ty.zigTypeTag(zcu) == .comptime_float and rhs_ty.zigTypeTag(zcu) == .comptime_int) or
14866 (lhs_ty.zigTypeTag(zcu) == .comptime_int and rhs_ty.zigTypeTag(zcu) == .comptime_float))14225 (lhs_ty.zigTypeTag(zcu) == .comptime_int and rhs_ty.zigTypeTag(zcu) == .comptime_float))
...@@ -14968,8 +14327,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -14968,8 +14327,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1496814327
14969 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact);14328 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact);
1497014329
14971 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14330 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
14972 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14331 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1497314332
14974 // Because `@divExact` can trigger Illegal Behavior, undefined operands trigger Illegal Behavior.14333 // Because `@divExact` can trigger Illegal Behavior, undefined operands trigger Illegal Behavior.
1497514334
...@@ -15064,8 +14423,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -15064,8 +14423,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1506414423
15065 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor);14424 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor);
1506614425
15067 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14426 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
15068 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14427 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1506914428
15070 const allow_div_zero = !is_int and14429 const allow_div_zero = !is_int and
15071 resolved_type.toIntern() != .comptime_float_type and14430 resolved_type.toIntern() != .comptime_float_type and
...@@ -15129,8 +14488,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -15129,8 +14488,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1512914488
15130 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc);14489 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc);
1513114490
15132 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14491 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
15133 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14492 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1513414493
15135 const allow_div_zero = !is_int and14494 const allow_div_zero = !is_int and
15136 resolved_type.toIntern() != .comptime_float_type and14495 resolved_type.toIntern() != .comptime_float_type and
...@@ -15341,8 +14700,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -15341,8 +14700,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1534114700
15342 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);14701 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);
1534314702
15344 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14703 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
15345 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14704 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1534614705
15347 const lhs_maybe_negative = a: {14706 const lhs_maybe_negative = a: {
15348 if (lhs_scalar_ty.isUnsignedInt(zcu)) break :a false;14707 if (lhs_scalar_ty.isUnsignedInt(zcu)) break :a false;
...@@ -15440,8 +14799,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -15440,8 +14799,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1544014799
15441 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);14800 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);
1544214801
15443 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14802 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
15444 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14803 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1544514804
15446 const allow_div_zero = !is_int and14805 const allow_div_zero = !is_int and
15447 resolved_type.toIntern() != .comptime_float_type and14806 resolved_type.toIntern() != .comptime_float_type and
...@@ -15504,8 +14863,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins...@@ -15504,8 +14863,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1550414863
15505 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);14864 try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);
1550614865
15507 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);14866 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
15508 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);14867 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1550914868
15510 const allow_div_zero = !is_int and14869 const allow_div_zero = !is_int and
15511 resolved_type.toIntern() != .comptime_float_type and14870 resolved_type.toIntern() != .comptime_float_type and
...@@ -15601,12 +14960,12 @@ fn zirOverflowArithmetic(...@@ -15601,12 +14960,12 @@ fn zirOverflowArithmetic(
15601 // to the result, even if it is undefined..14960 // to the result, even if it is undefined..
15602 // Otherwise, if either of the argument is undefined, undefined is returned.14961 // Otherwise, if either of the argument is undefined, undefined is returned.
15603 if (maybe_lhs_val) |lhs_val| {14962 if (maybe_lhs_val) |lhs_val| {
15604 if (!lhs_val.isUndef(zcu) and (try lhs_val.compareAllWithZeroSema(.eq, pt))) {14963 if (!lhs_val.isUndef(zcu) and lhs_val.compareAllWithZero(.eq, zcu)) {
15605 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs };14964 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs };
15606 }14965 }
15607 }14966 }
15608 if (maybe_rhs_val) |rhs_val| {14967 if (maybe_rhs_val) |rhs_val| {
15609 if (!rhs_val.isUndef(zcu) and (try rhs_val.compareAllWithZeroSema(.eq, pt))) {14968 if (!rhs_val.isUndef(zcu) and rhs_val.compareAllWithZero(.eq, zcu)) {
15610 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };14969 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
15611 }14970 }
15612 }14971 }
...@@ -15627,7 +14986,7 @@ fn zirOverflowArithmetic(...@@ -15627,7 +14986,7 @@ fn zirOverflowArithmetic(
15627 if (maybe_rhs_val) |rhs_val| {14986 if (maybe_rhs_val) |rhs_val| {
15628 if (rhs_val.isUndef(zcu)) {14987 if (rhs_val.isUndef(zcu)) {
15629 break :result .{ .overflow_bit = .undef, .wrapped = .undef };14988 break :result .{ .overflow_bit = .undef, .wrapped = .undef };
15630 } else if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {14989 } else if (rhs_val.compareAllWithZero(.eq, zcu)) {
15631 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };14990 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
15632 } else if (maybe_lhs_val) |lhs_val| {14991 } else if (maybe_lhs_val) |lhs_val| {
15633 if (lhs_val.isUndef(zcu)) {14992 if (lhs_val.isUndef(zcu)) {
...@@ -15642,12 +15001,12 @@ fn zirOverflowArithmetic(...@@ -15642,12 +15001,12 @@ fn zirOverflowArithmetic(
15642 .mul_with_overflow => {15001 .mul_with_overflow => {
15643 // If either of the arguments is zero, the result is zero and no overflow occured.15002 // If either of the arguments is zero, the result is zero and no overflow occured.
15644 if (maybe_lhs_val) |lhs_val| {15003 if (maybe_lhs_val) |lhs_val| {
15645 if (!lhs_val.isUndef(zcu) and try lhs_val.compareAllWithZeroSema(.eq, pt)) {15004 if (!lhs_val.isUndef(zcu) and lhs_val.compareAllWithZero(.eq, zcu)) {
15646 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };15005 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
15647 }15006 }
15648 }15007 }
15649 if (maybe_rhs_val) |rhs_val| {15008 if (maybe_rhs_val) |rhs_val| {
15650 if (!rhs_val.isUndef(zcu) and try rhs_val.compareAllWithZeroSema(.eq, pt)) {15009 if (!rhs_val.isUndef(zcu) and rhs_val.compareAllWithZero(.eq, zcu)) {
15651 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs };15010 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = rhs };
15652 }15011 }
15653 }15012 }
...@@ -15694,10 +15053,10 @@ fn zirOverflowArithmetic(...@@ -15694,10 +15053,10 @@ fn zirOverflowArithmetic(
15694 const bits = scalar_ty.intInfo(zcu).bits;15053 const bits = scalar_ty.intInfo(zcu).bits;
15695 switch (rhs_ty.zigTypeTag(zcu)) {15054 switch (rhs_ty.zigTypeTag(zcu)) {
15696 .int, .comptime_int => {15055 .int, .comptime_int => {
15697 switch (try rhs_val.orderAgainstZeroSema(pt)) {15056 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
15698 .gt => {15057 .gt => {
15699 var rhs_space: Value.BigIntSpace = undefined;15058 var rhs_space: Value.BigIntSpace = undefined;
15700 const rhs_bigint = try rhs_val.toBigIntSema(&rhs_space, pt);15059 const rhs_bigint = rhs_val.toBigInt(&rhs_space, zcu);
15701 if (rhs_bigint.orderAgainstScalar(bits) != .lt) {15060 if (rhs_bigint.orderAgainstScalar(bits) != .lt) {
15702 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);15061 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_val, rhs_src, null);
15703 }15062 }
...@@ -15711,10 +15070,10 @@ fn zirOverflowArithmetic(...@@ -15711,10 +15070,10 @@ fn zirOverflowArithmetic(
15711 for (0..rhs_ty.vectorLen(zcu)) |elem_idx| {15070 for (0..rhs_ty.vectorLen(zcu)) |elem_idx| {
15712 const rhs_elem = try rhs_val.elemValue(pt, elem_idx);15071 const rhs_elem = try rhs_val.elemValue(pt, elem_idx);
15713 if (rhs_elem.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, elem_idx);15072 if (rhs_elem.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, elem_idx);
15714 switch (try rhs_elem.orderAgainstZeroSema(pt)) {15073 switch (Value.order(rhs_elem, .zero_comptime_int, zcu)) {
15715 .gt => {15074 .gt => {
15716 var rhs_elem_space: Value.BigIntSpace = undefined;15075 var rhs_elem_space: Value.BigIntSpace = undefined;
15717 const rhs_elem_bigint = try rhs_elem.toBigIntSema(&rhs_elem_space, pt);15076 const rhs_elem_bigint = rhs_elem.toBigInt(&rhs_elem_space, zcu);
15718 if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {15077 if (rhs_elem_bigint.orderAgainstScalar(bits) != .lt) {
15719 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);15078 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs_elem, rhs_src, elem_idx);
15720 }15079 }
...@@ -15728,7 +15087,7 @@ fn zirOverflowArithmetic(...@@ -15728,7 +15087,7 @@ fn zirOverflowArithmetic(
15728 },15087 },
15729 else => unreachable,15088 else => unreachable,
15730 }15089 }
15731 if (try rhs_val.compareAllWithZeroSema(.eq, pt)) {15090 if (rhs_val.compareAllWithZero(.eq, zcu)) {
15732 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };15091 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
15733 }15092 }
15734 } else {15093 } else {
...@@ -15737,7 +15096,7 @@ fn zirOverflowArithmetic(...@@ -15737,7 +15096,7 @@ fn zirOverflowArithmetic(
15737 }15096 }
15738 if (maybe_lhs_val) |lhs_val| {15097 if (maybe_lhs_val) |lhs_val| {
15739 try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);15098 try sema.checkAllScalarsDefined(block, lhs_src, lhs_val);
15740 if (try lhs_val.compareAllWithZeroSema(.eq, pt)) {15099 if (lhs_val.compareAllWithZero(.eq, zcu)) {
15741 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };15100 break :result .{ .overflow_bit = try sema.splat(overflow_ty, .zero_u1), .inst = lhs };
15742 }15101 }
15743 }15102 }
...@@ -15817,16 +15176,16 @@ fn analyzeArithmetic(...@@ -15817,16 +15176,16 @@ fn analyzeArithmetic(
15817 if (zir_tag != .sub) {15176 if (zir_tag != .sub) {
15818 return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction");15177 return sema.failWithInvalidPtrArithmetic(block, src, "pointer-pointer", "subtraction");
15819 }15178 }
15820 if (!lhs_ty.elemType2(zcu).eql(rhs_ty.elemType2(zcu), zcu)) {15179 if (!lhs_ty.childType(zcu).eql(rhs_ty.childType(zcu), zcu)) {
15821 return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{15180 return sema.fail(block, src, "incompatible pointer arithmetic operands '{f}' and '{f}'", .{
15822 lhs_ty.fmt(pt), rhs_ty.fmt(pt),15181 lhs_ty.fmt(pt), rhs_ty.fmt(pt),
15823 });15182 });
15824 }15183 }
1582515184
15826 const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);15185 const elem_size = lhs_ty.childType(zcu).abiSize(zcu);
15827 if (elem_size == 0) {15186 if (elem_size == 0) {
15828 return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{15187 return sema.fail(block, src, "pointer subtraction requires element type '{f}' to have runtime bits", .{
15829 lhs_ty.elemType2(zcu).fmt(pt),15188 lhs_ty.childType(zcu).fmt(pt),
15830 });15189 });
15831 }15190 }
1583215191
...@@ -15875,11 +15234,7 @@ fn analyzeArithmetic(...@@ -15875,11 +15234,7 @@ fn analyzeArithmetic(
15875 else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"),15234 else => return sema.failWithInvalidPtrArithmetic(block, src, "pointer-integer", "addition and subtraction"),
15876 };15235 };
1587715236
15878 if (!try lhs_ty.elemType2(zcu).hasRuntimeBitsSema(pt)) {15237 try sema.ensureLayoutResolved(lhs_ty.childType(zcu));
15879 return sema.fail(block, src, "pointer arithmetic requires element type '{f}' to have runtime bits", .{
15880 lhs_ty.elemType2(zcu).fmt(pt),
15881 });
15882 }
15883 return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);15238 return sema.analyzePtrArithmetic(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
15884 },15239 },
15885 }15240 }
...@@ -15915,8 +15270,8 @@ fn analyzeArithmetic(...@@ -15915,8 +15270,8 @@ fn analyzeArithmetic(
15915 else => unreachable,15270 else => unreachable,
15916 };15271 };
1591715272
15918 const maybe_lhs_val = try sema.resolveValueResolveLazy(casted_lhs);15273 const maybe_lhs_val = try sema.resolveValue(casted_lhs);
15919 const maybe_rhs_val = try sema.resolveValueResolveLazy(casted_rhs);15274 const maybe_rhs_val = try sema.resolveValue(casted_rhs);
1592015275
15921 if (maybe_lhs_val) |lhs_val| {15276 if (maybe_lhs_val) |lhs_val| {
15922 if (maybe_rhs_val) |rhs_val| {15277 if (maybe_rhs_val) |rhs_val| {
...@@ -15972,6 +15327,7 @@ fn analyzeArithmetic(...@@ -15972,6 +15327,7 @@ fn analyzeArithmetic(
15972 return block.addBinOp(air_tag, casted_lhs, casted_rhs);15327 return block.addBinOp(air_tag, casted_lhs, casted_rhs);
15973}15328}
1597415329
15330/// Asserts that the layout of the pointer child type is already resolved.
15975fn analyzePtrArithmetic(15331fn analyzePtrArithmetic(
15976 sema: *Sema,15332 sema: *Sema,
15977 block: *Block,15333 block: *Block,
...@@ -15993,7 +15349,10 @@ fn analyzePtrArithmetic(...@@ -15993,7 +15349,10 @@ fn analyzePtrArithmetic(
15993 const ptr_info = ptr_ty.ptrInfo(zcu);15349 const ptr_info = ptr_ty.ptrInfo(zcu);
15994 assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c);15350 assert(ptr_info.flags.size == .many or ptr_info.flags.size == .c);
1599515351
15996 if ((try sema.typeHasOnePossibleValue(.fromInterned(ptr_info.child))) != null) {15352 const elem_ty: Type = .fromInterned(ptr_info.child);
15353 elem_ty.assertHasLayout(zcu);
15354
15355 if (elem_ty.abiSize(zcu) == 0) {
15997 // Offset will be multiplied by zero, so result is the same as the base pointer.15356 // Offset will be multiplied by zero, so result is the same as the base pointer.
15998 return ptr;15357 return ptr;
15999 }15358 }
...@@ -16007,9 +15366,9 @@ fn analyzePtrArithmetic(...@@ -16007,9 +15366,9 @@ fn analyzePtrArithmetic(
16007 }15366 }
16008 // If the addend is not a comptime-known value we can still count on15367 // If the addend is not a comptime-known value we can still count on
16009 // it being a multiple of the type size.15368 // it being a multiple of the type size.
16010 const elem_size = try Type.fromInterned(ptr_info.child).abiSizeSema(pt);15369 const elem_size = elem_ty.abiSize(zcu);
16011 const addend = if (opt_off_val) |off_val| a: {15370 const addend = if (opt_off_val) |off_val| a: {
16012 const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntSema(pt));15371 const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(zcu));
16013 break :a elem_size * off_int;15372 break :a elem_size * off_int;
16014 } else elem_size;15373 } else elem_size;
1601515374
...@@ -16022,7 +15381,7 @@ fn analyzePtrArithmetic(...@@ -16022,7 +15381,7 @@ fn analyzePtrArithmetic(
16022 ));15381 ));
16023 assert(new_align != .none);15382 assert(new_align != .none);
1602415383
16025 break :t try pt.ptrTypeSema(.{15384 break :t try pt.ptrType(.{
16026 .child = ptr_info.child,15385 .child = ptr_info.child,
16027 .sentinel = ptr_info.sentinel,15386 .sentinel = ptr_info.sentinel,
16028 .flags = .{15387 .flags = .{
...@@ -16041,10 +15400,10 @@ fn analyzePtrArithmetic(...@@ -16041,10 +15400,10 @@ fn analyzePtrArithmetic(
16041 if (opt_off_val) |offset_val| {15400 if (opt_off_val) |offset_val| {
16042 if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty);15401 if (ptr_val.isUndef(zcu)) return pt.undefRef(new_ptr_ty);
1604315402
16044 const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntSema(pt));15403 const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(zcu));
16045 if (offset_int == 0) return ptr;15404 if (offset_int == 0) return ptr;
16046 if (air_tag == .ptr_sub) {15405 if (air_tag == .ptr_sub) {
16047 const elem_size = try Type.fromInterned(ptr_info.child).abiSizeSema(pt);15406 const elem_size = elem_ty.abiSize(zcu);
16048 const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty);15407 const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty);
16049 return Air.internedToRef(new_ptr_val.toIntern());15408 return Air.internedToRef(new_ptr_val.toIntern());
16050 } else {15409 } else {
...@@ -16248,6 +15607,7 @@ fn zirAsm(...@@ -16248,6 +15607,7 @@ fn zirAsm(
16248 buffer[input.c.len + 1 + input.n.len] = 0;15607 buffer[input.c.len + 1 + input.n.len] = 0;
16249 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;15608 sema.air_extra.items.len += (input.c.len + input.n.len + (2 + 3)) / 4;
16250 }15609 }
15610 if (try expr_ty.toType().onePossibleValue(pt)) |opv| return .fromValue(opv);
16251 return asm_air;15611 return asm_air;
16252}15612}
1625315613
...@@ -16343,7 +15703,6 @@ fn analyzeCmpUnionTag(...@@ -16343,7 +15703,6 @@ fn analyzeCmpUnionTag(
16343 const pt = sema.pt;15703 const pt = sema.pt;
16344 const zcu = pt.zcu;15704 const zcu = pt.zcu;
16345 const union_ty = sema.typeOf(un);15705 const union_ty = sema.typeOf(un);
16346 try union_ty.resolveFields(pt);
16347 const union_tag_ty = union_ty.unionTagType(zcu) orelse {15706 const union_tag_ty = union_ty.unionTagType(zcu) orelse {
16348 const msg = msg: {15707 const msg = msg: {
16349 const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{});15708 const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
...@@ -16534,10 +15893,11 @@ fn runtimeBoolCmp(...@@ -16534,10 +15893,11 @@ fn runtimeBoolCmp(
1653415893
16535fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {15894fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
16536 const pt = sema.pt;15895 const pt = sema.pt;
15896 const zcu = pt.zcu;
16537 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;15897 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
16538 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);15898 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
16539 const ty = try sema.resolveType(block, operand_src, inst_data.operand);15899 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
16540 switch (ty.zigTypeTag(pt.zcu)) {15900 switch (ty.zigTypeTag(zcu)) {
16541 .@"fn",15901 .@"fn",
16542 .noreturn,15902 .noreturn,
16543 .undefined,15903 .undefined,
...@@ -16568,8 +15928,8 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air....@@ -16568,8 +15928,8 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
16568 .@"anyframe",15928 .@"anyframe",
16569 => {},15929 => {},
16570 }15930 }
16571 const val = try ty.abiSizeLazy(pt);15931 try sema.ensureLayoutResolved(ty);
16572 return Air.internedToRef(val.toIntern());15932 return .fromValue(try pt.intValue(.comptime_int, ty.abiSize(zcu)));
16573}15933}
1657415934
16575fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {15935fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -16609,8 +15969,8 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -16609,8 +15969,8 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
16609 .@"anyframe",15969 .@"anyframe",
16610 => {},15970 => {},
16611 }15971 }
16612 const bit_size = try operand_ty.bitSizeSema(pt);15972 try sema.ensureLayoutResolved(operand_ty);
16613 return pt.intRef(.comptime_int, bit_size);15973 return .fromValue(try pt.intValue(.comptime_int, operand_ty.bitSize(zcu)));
16614}15974}
1661515975
16616fn zirThis(15976fn zirThis(
...@@ -16619,34 +15979,16 @@ fn zirThis(...@@ -16619,34 +15979,16 @@ fn zirThis(
16619 extended: Zir.Inst.Extended.InstData,15979 extended: Zir.Inst.Extended.InstData,
16620) CompileError!Air.Inst.Ref {15980) CompileError!Air.Inst.Ref {
16621 _ = extended;15981 _ = extended;
16622 const pt = sema.pt;15982 const zcu = sema.pt.zcu;
16623 const zcu = pt.zcu;15983 const namespace = zcu.namespacePtr(block.namespace);
16624 const namespace = pt.zcu.namespacePtr(block.namespace);
1662515984
16626 switch (pt.zcu.intern_pool.indexToKey(namespace.owner_type)) {15985 switch (zcu.intern_pool.indexToKey(namespace.owner_type)) {
16627 .opaque_type => {15986 .opaque_type, .struct_type, .union_type => {},
16628 // Opaque types are never outdated since they don't undergo type resolution, so nothing to do!15987 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol
16629 return Air.internedToRef(namespace.owner_type);15988 .enum_type => try sema.ensureFieldInitsResolved(.fromInterned(namespace.owner_type)),
16630 },
16631 .struct_type, .union_type => {
16632 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
16633 try sema.declareDependency(.{ .interned = new_ty });
16634 return Air.internedToRef(new_ty);
16635 },
16636 .enum_type => {
16637 const new_ty = try pt.ensureTypeUpToDate(namespace.owner_type);
16638 try sema.declareDependency(.{ .interned = new_ty });
16639 // Since this is an enum, it has to be resolved immediately.
16640 // `ensureTypeUpToDate` has resolved the new type if necessary.
16641 // We just need to check for resolution failures.
16642 const ty_unit: AnalUnit = .wrap(.{ .type = new_ty });
16643 if (zcu.failed_analysis.contains(ty_unit) or zcu.transitive_failed_analysis.contains(ty_unit)) {
16644 return error.AnalysisFail;
16645 }
16646 return Air.internedToRef(new_ty);
16647 },
16648 else => unreachable,15989 else => unreachable,
16649 }15990 }
15991 return .fromIntern(namespace.owner_type);
16650}15992}
1665115993
16652fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {15994fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
...@@ -16739,7 +16081,7 @@ fn zirRetAddr(...@@ -16739,7 +16081,7 @@ fn zirRetAddr(
16739 _ = sema;16081 _ = sema;
16740 _ = extended;16082 _ = extended;
16741 if (block.isComptime()) {16083 if (block.isComptime()) {
16742 // TODO: we could give a meaningful lazy value here. #1493816084 // TODO: we could give a meaningful value here. #14938
16743 return .zero_usize;16085 return .zero_usize;
16744 } else {16086 } else {
16745 return block.addNoOp(.ret_addr);16087 return block.addNoOp(.ret_addr);
...@@ -16886,6 +16228,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16886,6 +16228,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16886 try sema.declareDependency(.{ .namespace = type_decl_inst });16228 try sema.declareDependency(.{ .namespace = type_decl_inst });
16887 }16229 }
1688816230
16231 try sema.ensureLayoutResolved(ty);
16232
16889 switch (ty.zigTypeTag(zcu)) {16233 switch (ty.zigTypeTag(zcu)) {
16890 .type,16234 .type,
16891 .void,16235 .void,
...@@ -16934,7 +16278,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16934,7 +16278,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16934 .child = param_info_ty.toIntern(),16278 .child = param_info_ty.toIntern(),
16935 });16279 });
16936 const new_decl_val = (try pt.aggregateValue(new_decl_ty, param_vals)).toIntern();16280 const new_decl_val = (try pt.aggregateValue(new_decl_ty, param_vals)).toIntern();
16937 const slice_ty = (try pt.ptrTypeSema(.{16281 const slice_ty = (try pt.ptrType(.{
16938 .child = param_info_ty.toIntern(),16282 .child = param_info_ty.toIntern(),
16939 .flags = .{16283 .flags = .{
16940 .size = .slice,16284 .size = .slice,
...@@ -16976,11 +16320,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -16976,11 +16320,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
16976 error.OutOfMemory => |e| return e,16320 error.OutOfMemory => |e| return e,
16977 };16321 };
1697816322
16323 // MLUGG TODO
16324 const func_is_generic = false;
16325
16979 const field_values: [5]InternPool.Index = .{16326 const field_values: [5]InternPool.Index = .{
16980 // calling_convention: CallingConvention,16327 // calling_convention: CallingConvention,
16981 callconv_val.toIntern(),16328 callconv_val.toIntern(),
16982 // is_generic: bool,16329 // is_generic: bool,
16983 Value.makeBool(func_ty_info.is_generic).toIntern(),16330 Value.makeBool(func_is_generic).toIntern(),
16984 // is_var_args: bool,16331 // is_var_args: bool,
16985 Value.makeBool(func_ty_info.is_var_args).toIntern(),16332 Value.makeBool(func_ty_info.is_var_args).toIntern(),
16986 // return_type: ?type,16333 // return_type: ?type,
...@@ -17015,7 +16362,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17015,7 +16362,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1701516362
17016 const field_vals = .{16363 const field_vals = .{
17017 // bits: u16,16364 // bits: u16,
17018 (try pt.intValue(.u16, ty.bitSize(zcu))).toIntern(),16365 (try pt.intValue(.u16, ty.floatBits(zcu.getTarget()))).toIntern(),
17019 };16366 };
17020 return Air.internedToRef((try pt.internUnion(.{16367 return Air.internedToRef((try pt.internUnion(.{
17021 .ty = type_info_ty.toIntern(),16368 .ty = type_info_ty.toIntern(),
...@@ -17025,10 +16372,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17025,10 +16372,13 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17025 },16372 },
17026 .pointer => {16373 .pointer => {
17027 const info = ty.ptrInfo(zcu);16374 const info = ty.ptrInfo(zcu);
17028 const alignment = if (info.flags.alignment.toByteUnits()) |alignment|16375 const alignment_val = try pt.intValue(.comptime_int, bytes: {
17029 try pt.intValue(.comptime_int, alignment)16376 if (info.flags.alignment.toByteUnits()) |b| break :bytes b;
17030 else16377 const elem_ty: Type = .fromInterned(info.child);
17031 try Type.fromInterned(info.child).lazyAbiAlignment(pt);16378 // MLUGG TODO: this resolution is sus, but i doubt i'll solve it in this branch
16379 try sema.ensureLayoutResolved(elem_ty);
16380 break :bytes elem_ty.abiAlignment(zcu).toByteUnits().?;
16381 });
1703216382
17033 const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);16383 const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);
17034 const pointer_ty = try sema.getBuiltinType(src, .@"Type.Pointer");16384 const pointer_ty = try sema.getBuiltinType(src, .@"Type.Pointer");
...@@ -17042,7 +16392,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17042,7 +16392,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17042 // is_volatile: bool,16392 // is_volatile: bool,
17043 Value.makeBool(info.flags.is_volatile).toIntern(),16393 Value.makeBool(info.flags.is_volatile).toIntern(),
17044 // alignment: comptime_int,16394 // alignment: comptime_int,
17045 alignment.toIntern(),16395 alignment_val.toIntern(),
17046 // address_space: AddressSpace16396 // address_space: AddressSpace
17047 (try pt.enumValueFieldIndex(addrspace_ty, @intFromEnum(info.flags.address_space))).toIntern(),16397 (try pt.enumValueFieldIndex(addrspace_ty, @intFromEnum(info.flags.address_space))).toIntern(),
17048 // child: type,16398 // child: type,
...@@ -17159,7 +16509,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17159,7 +16509,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17159 };16509 };
1716016510
17161 // Build our ?[]const Error value16511 // Build our ?[]const Error value
17162 const slice_errors_ty = try pt.ptrTypeSema(.{16512 const slice_errors_ty = try pt.ptrType(.{
17163 .child = error_field_ty.toIntern(),16513 .child = error_field_ty.toIntern(),
17164 .flags = .{16514 .flags = .{
17165 .size = .slice,16515 .size = .slice,
...@@ -17215,19 +16565,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17215,19 +16565,19 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17215 })));16565 })));
17216 },16566 },
17217 .@"enum" => {16567 .@"enum" => {
17218 const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive);16568 const enum_obj = ip.loadEnumType(ty.toIntern());
16569 const is_exhaustive: Value = .makeBool(!enum_obj.nonexhaustive);
1721916570
17220 const enum_field_ty = try sema.getBuiltinType(src, .@"Type.EnumField");16571 const enum_field_ty = try sema.getBuiltinType(src, .@"Type.EnumField");
1722116572
17222 const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len);16573 const enum_field_vals = try sema.arena.alloc(InternPool.Index, enum_obj.field_names.len);
17223 for (enum_field_vals, 0..) |*field_val, tag_index| {16574 for (enum_field_vals, 0..) |*field_val, tag_index| {
17224 const enum_type = ip.loadEnumType(ty.toIntern());16575 const value_val = if (enum_obj.field_values.len > 0)
17225 const value_val = if (enum_type.values.len > 0)
17226 try ip.getCoercedInts(16576 try ip.getCoercedInts(
17227 gpa,16577 gpa,
17228 io,16578 io,
17229 pt.tid,16579 pt.tid,
17230 ip.indexToKey(enum_type.values.get(ip)[tag_index]).int,16580 ip.indexToKey(enum_obj.field_values.get(ip)[tag_index]).int,
17231 .comptime_int_type,16581 .comptime_int_type,
17232 )16582 )
17233 else16583 else
...@@ -17235,7 +16585,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17235,7 +16585,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1723516585
17236 // TODO: write something like getCoercedInts to avoid needing to dupe16586 // TODO: write something like getCoercedInts to avoid needing to dupe
17237 const name_val = v: {16587 const name_val = v: {
17238 const tag_name = enum_type.names.get(ip)[tag_index];16588 const tag_name = enum_obj.field_names.get(ip)[tag_index];
17239 const tag_name_len = tag_name.length(ip);16589 const tag_name_len = tag_name.length(ip);
17240 const new_decl_ty = try pt.arrayType(.{16590 const new_decl_ty = try pt.arrayType(.{
17241 .len = tag_name_len,16591 .len = tag_name_len,
...@@ -17275,7 +16625,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17275,7 +16625,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17275 .child = enum_field_ty.toIntern(),16625 .child = enum_field_ty.toIntern(),
17276 });16626 });
17277 const new_decl_val = (try pt.aggregateValue(fields_array_ty, enum_field_vals)).toIntern();16627 const new_decl_val = (try pt.aggregateValue(fields_array_ty, enum_field_vals)).toIntern();
17278 const slice_ty = (try pt.ptrTypeSema(.{16628 const slice_ty = (try pt.ptrType(.{
17279 .child = enum_field_ty.toIntern(),16629 .child = enum_field_ty.toIntern(),
17280 .flags = .{16630 .flags = .{
17281 .size = .slice,16631 .size = .slice,
...@@ -17303,7 +16653,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17303,7 +16653,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1730316653
17304 const field_values = .{16654 const field_values = .{
17305 // tag_type: type,16655 // tag_type: type,
17306 ip.loadEnumType(ty.toIntern()).tag_ty,16656 ip.loadEnumType(ty.toIntern()).int_tag_type,
17307 // fields: []const EnumField,16657 // fields: []const EnumField,
17308 fields_val,16658 fields_val,
17309 // decls: []const Declaration,16659 // decls: []const Declaration,
...@@ -17321,17 +16671,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17321,17 +16671,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17321 const type_union_ty = try sema.getBuiltinType(src, .@"Type.Union");16671 const type_union_ty = try sema.getBuiltinType(src, .@"Type.Union");
17322 const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");16672 const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");
1732316673
17324 try ty.resolveLayout(pt); // Getting alignment requires type layout16674 const union_obj = ip.loadUnionType(ty.toIntern());
17325 const union_obj = zcu.typeToUnion(ty).?;16675 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
17326 const tag_type = union_obj.loadTagType(ip);16676 const layout = union_obj.layout;
17327 const layout = union_obj.flagsUnordered(ip).layout;
1732816677
17329 const union_field_vals = try gpa.alloc(InternPool.Index, tag_type.names.len);16678 const union_field_vals = try gpa.alloc(InternPool.Index, enum_obj.field_names.len);
17330 defer gpa.free(union_field_vals);16679 defer gpa.free(union_field_vals);
1733116680
17332 for (union_field_vals, 0..) |*field_val, field_index| {16681 for (union_field_vals, 0..) |*field_val, field_index| {
17333 const name_val = v: {16682 const name_val = v: {
17334 const field_name = tag_type.names.get(ip)[field_index];16683 const field_name = enum_obj.field_names.get(ip)[field_index];
17335 const field_name_len = field_name.length(ip);16684 const field_name_len = field_name.length(ip);
17336 const new_decl_ty = try pt.arrayType(.{16685 const new_decl_ty = try pt.arrayType(.{
17337 .len = field_name_len,16686 .len = field_name_len,
...@@ -17357,7 +16706,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17357,7 +16706,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17357 };16706 };
1735816707
17359 const alignment = switch (layout) {16708 const alignment = switch (layout) {
17360 .auto, .@"extern" => try ty.fieldAlignmentSema(field_index, pt),16709 .auto, .@"extern" => ty.resolvedFieldAlignment(field_index, zcu),
17361 .@"packed" => .none,16710 .@"packed" => .none,
17362 };16711 };
1736316712
...@@ -17379,7 +16728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17379,7 +16728,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17379 .child = union_field_ty.toIntern(),16728 .child = union_field_ty.toIntern(),
17380 });16729 });
17381 const new_decl_val = (try pt.aggregateValue(array_fields_ty, union_field_vals)).toIntern();16730 const new_decl_val = (try pt.aggregateValue(array_fields_ty, union_field_vals)).toIntern();
17382 const slice_ty = (try pt.ptrTypeSema(.{16731 const slice_ty = (try pt.ptrType(.{
17383 .child = union_field_ty.toIntern(),16732 .child = union_field_ty.toIntern(),
17384 .flags = .{16733 .flags = .{
17385 .size = .slice,16734 .size = .slice,
...@@ -17431,8 +16780,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17431,8 +16780,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17431 const type_struct_ty = try sema.getBuiltinType(src, .@"Type.Struct");16780 const type_struct_ty = try sema.getBuiltinType(src, .@"Type.Struct");
17432 const struct_field_ty = try sema.getBuiltinType(src, .@"Type.StructField");16781 const struct_field_ty = try sema.getBuiltinType(src, .@"Type.StructField");
1743316782
17434 try ty.resolveLayout(pt); // Getting alignment requires type layout
17435
17436 var struct_field_vals: []InternPool.Index = &.{};16783 var struct_field_vals: []InternPool.Index = &.{};
17437 defer gpa.free(struct_field_vals);16784 defer gpa.free(struct_field_vals);
17438 fv: {16785 fv: {
...@@ -17468,8 +16815,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17468,8 +16815,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17468 } });16815 } });
17469 };16816 };
1747016817
17471 try Type.fromInterned(field_ty).resolveLayout(pt);
17472
17473 const is_comptime = field_val != .none;16818 const is_comptime = field_val != .none;
17474 const opt_default_val = if (is_comptime) Value.fromInterned(field_val) else null;16819 const opt_default_val = if (is_comptime) Value.fromInterned(field_val) else null;
17475 const default_val_ptr = try sema.optRefValue(opt_default_val);16820 const default_val_ptr = try sema.optRefValue(opt_default_val);
...@@ -17492,16 +16837,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17492,16 +16837,17 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17492 .struct_type => ip.loadStructType(ty.toIntern()),16837 .struct_type => ip.loadStructType(ty.toIntern()),
17493 else => unreachable,16838 else => unreachable,
17494 };16839 };
16840 try sema.ensureFieldInitsResolved(ty); // can't do this sooner, since it's not allowed on tuples
17495 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);16841 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
1749616842
17497 try ty.resolveStructFieldInits(pt);
17498
17499 for (struct_field_vals, 0..) |*field_val, field_index| {16843 for (struct_field_vals, 0..) |*field_val, field_index| {
17500 const field_name = struct_type.fieldName(ip, field_index);16844 const field_name = struct_type.field_names.get(ip)[field_index];
17501 const field_name_len = field_name.length(ip);16845 const field_name_len = field_name.length(ip);
17502 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);16846 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
17503 const field_init = struct_type.fieldInit(ip, field_index);16847 const field_default: InternPool.Index = if (struct_type.field_defaults.len > 0) d: {
17504 const field_is_comptime = struct_type.fieldIsComptime(ip, field_index);16848 break :d struct_type.field_defaults.get(ip)[field_index];
16849 } else .none;
16850 const field_is_comptime = struct_type.field_is_comptime_bits.get(ip, field_index);
17505 const name_val = v: {16851 const name_val = v: {
17506 const new_decl_ty = try pt.arrayType(.{16852 const new_decl_ty = try pt.arrayType(.{
17507 .len = field_name_len,16853 .len = field_name_len,
...@@ -17526,15 +16872,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17526,15 +16872,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17526 } });16872 } });
17527 };16873 };
1752816874
17529 const opt_default_val = if (field_init == .none) null else Value.fromInterned(field_init);16875 const opt_default_val: ?Value = if (field_default == .none) null else .fromInterned(field_default);
17530 const default_val_ptr = try sema.optRefValue(opt_default_val);16876 const default_val_ptr = try sema.optRefValue(opt_default_val);
17531 const alignment = switch (struct_type.layout) {16877 const alignment = switch (struct_type.layout) {
16878 .auto, .@"extern" => ty.resolvedFieldAlignment(field_index, zcu),
17532 .@"packed" => .none,16879 .@"packed" => .none,
17533 else => try field_ty.structFieldAlignmentSema(
17534 struct_type.fieldAlign(ip, field_index),
17535 struct_type.layout,
17536 pt,
17537 ),
17538 };16880 };
1753916881
17540 const struct_field_fields = .{16882 const struct_field_fields = .{
...@@ -17559,7 +16901,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17559,7 +16901,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17559 .child = struct_field_ty.toIntern(),16901 .child = struct_field_ty.toIntern(),
17560 });16902 });
17561 const new_decl_val = (try pt.aggregateValue(array_fields_ty, struct_field_vals)).toIntern();16903 const new_decl_val = (try pt.aggregateValue(array_fields_ty, struct_field_vals)).toIntern();
17562 const slice_ty = (try pt.ptrTypeSema(.{16904 const slice_ty = (try pt.ptrType(.{
17563 .child = struct_field_ty.toIntern(),16905 .child = struct_field_ty.toIntern(),
17564 .flags = .{16906 .flags = .{
17565 .size = .slice,16907 .size = .slice,
...@@ -17585,9 +16927,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17585,9 +16927,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1758516927
17586 const backing_integer_val = try pt.intern(.{ .opt = .{16928 const backing_integer_val = try pt.intern(.{ .opt = .{
17587 .ty = (try pt.optionalType(.type_type)).toIntern(),16929 .ty = (try pt.optionalType(.type_type)).toIntern(),
17588 .val = if (zcu.typeToPackedStruct(ty)) |packed_struct| val: {16930 .val = if (zcu.typeToPackedStruct(ty)) |struct_obj| val: {
17589 assert(Type.fromInterned(packed_struct.backingIntTypeUnordered(ip)).isInt(zcu));16931 assert(Type.fromInterned(struct_obj.packed_backing_int_type).isInt(zcu));
17590 break :val packed_struct.backingIntTypeUnordered(ip);16932 break :val struct_obj.packed_backing_int_type;
17591 } else .none,16933 } else .none,
17592 } });16934 } });
1759316935
...@@ -17616,7 +16958,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -17616,7 +16958,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
17616 .@"opaque" => {16958 .@"opaque" => {
17617 const type_opaque_ty = try sema.getBuiltinType(src, .@"Type.Opaque");16959 const type_opaque_ty = try sema.getBuiltinType(src, .@"Type.Opaque");
1761816960
17619 try ty.resolveFields(pt);
17620 const decls_val = try sema.typeInfoDecls(src, ty.getNamespace(zcu));16961 const decls_val = try sema.typeInfoDecls(src, ty.getNamespace(zcu));
1762116962
17622 const field_values = .{16963 const field_values = .{
...@@ -17658,7 +16999,7 @@ fn typeInfoDecls(...@@ -17658,7 +16999,7 @@ fn typeInfoDecls(
17658 .child = declaration_ty.toIntern(),16999 .child = declaration_ty.toIntern(),
17659 });17000 });
17660 const new_decl_val = (try pt.aggregateValue(array_decl_ty, decl_vals.items)).toIntern();17001 const new_decl_val = (try pt.aggregateValue(array_decl_ty, decl_vals.items)).toIntern();
17661 const slice_ty = (try pt.ptrTypeSema(.{17002 const slice_ty = (try pt.ptrType(.{
17662 .child = declaration_ty.toIntern(),17003 .child = declaration_ty.toIntern(),
17663 .flags = .{17004 .flags = .{
17664 .size = .slice,17005 .size = .slice,
...@@ -17783,22 +17124,12 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi...@@ -17783,22 +17124,12 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
17783 const zcu = pt.zcu;17124 const zcu = pt.zcu;
17784 switch (operand.zigTypeTag(zcu)) {17125 switch (operand.zigTypeTag(zcu)) {
17785 .comptime_int => return .comptime_int,17126 .comptime_int => return .comptime_int,
17786 .int => {17127 .int => return pt.intType(.unsigned, switch (operand.intInfo(zcu).bits) {
17787 const bits = operand.bitSize(zcu);17128 0 => 0,
17788 const count = if (bits == 0)17129 else => |b| std.math.log2_int_ceil(u16, b),
17789 017130 }),
17790 else blk: {
17791 var count: u16 = 0;
17792 var s = bits - 1;
17793 while (s != 0) : (s >>= 1) {
17794 count += 1;
17795 }
17796 break :blk count;
17797 };
17798 return pt.intType(.unsigned, count);
17799 },
17800 .vector => {17131 .vector => {
17801 const elem_ty = operand.elemType2(zcu);17132 const elem_ty = operand.childType(zcu);
17802 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);17133 const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
17803 return pt.vectorType(.{17134 return pt.vectorType(.{
17804 .len = operand.vectorLen(zcu),17135 .len = operand.vectorLen(zcu),
...@@ -18082,13 +17413,15 @@ fn zirIsNonNullPtr(...@@ -18082,13 +17413,15 @@ fn zirIsNonNullPtr(
18082 const src = block.nodeOffset(inst_data.src_node);17413 const src = block.nodeOffset(inst_data.src_node);
18083 const ptr = try sema.resolveInst(inst_data.operand);17414 const ptr = try sema.resolveInst(inst_data.operand);
18084 const ptr_ty = sema.typeOf(ptr);17415 const ptr_ty = sema.typeOf(ptr);
18085 try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(zcu));17416 assert(ptr_ty.zigTypeTag(zcu) == .pointer);
17417 const nullable_ty = ptr_ty.childType(zcu);
17418 try sema.checkNullableType(block, src, nullable_ty);
18086 if (try sema.resolveValue(ptr)) |ptr_val| {17419 if (try sema.resolveValue(ptr)) |ptr_val| {
18087 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |loaded_val| {17420 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |nullable_val| {
18088 return sema.analyzeIsNull(block, Air.internedToRef(loaded_val.toIntern()), true);17421 return sema.analyzeIsNull(block, .fromValue(nullable_val), true);
18089 }17422 }
18090 }17423 }
18091 if (ptr_ty.childType(zcu).isNullFromType(zcu)) |is_null| {17424 if (nullable_ty.isNullFromType(zcu)) |is_null| {
18092 return if (is_null) .bool_false else .bool_true;17425 return if (is_null) .bool_false else .bool_true;
18093 }17426 }
18094 return block.addUnOp(.is_non_null_ptr, ptr);17427 return block.addUnOp(.is_non_null_ptr, ptr);
...@@ -18125,7 +17458,10 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError...@@ -18125,7 +17458,10 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
18125 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;17458 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
18126 const src = block.nodeOffset(inst_data.src_node);17459 const src = block.nodeOffset(inst_data.src_node);
18127 const ptr = try sema.resolveInst(inst_data.operand);17460 const ptr = try sema.resolveInst(inst_data.operand);
18128 try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(zcu));17461 const ptr_ty = sema.typeOf(ptr);
17462 assert(ptr_ty.zigTypeTag(zcu) == .pointer);
17463 const error_ty = ptr_ty.childType(zcu);
17464 try sema.checkErrorType(block, src, error_ty);
18129 const loaded = try sema.analyzeLoad(block, src, ptr, src);17465 const loaded = try sema.analyzeLoad(block, src, ptr, src);
18130 return sema.analyzeIsNonErr(block, src, loaded);17466 return sema.analyzeIsNonErr(block, src, loaded);
18131}17467}
...@@ -18294,6 +17630,11 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -18294,6 +17630,11 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
18294 } },17630 } },
18295 });17631 });
18296 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));17632 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(sub_block.instructions.items));
17633
17634 // The payload type might still be OPV, in which case `try_inst` is just there for the runtime
17635 // control flow and we should return a comptime-known result.
17636 if (try err_union_ty.errorUnionPayload(zcu).onePossibleValue(pt)) |opv| return .fromValue(opv);
17637
18297 return try_inst;17638 return try_inst;
18298}17639}
1829917640
...@@ -18347,7 +17688,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr...@@ -18347,7 +17688,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
1834717688
18348 const operand_ty = sema.typeOf(operand);17689 const operand_ty = sema.typeOf(operand);
18349 const ptr_info = operand_ty.ptrInfo(zcu);17690 const ptr_info = operand_ty.ptrInfo(zcu);
18350 const res_ty = try pt.ptrTypeSema(.{17691 const res_ty = try pt.ptrType(.{
18351 .child = err_union_ty.errorUnionPayload(zcu).toIntern(),17692 .child = err_union_ty.errorUnionPayload(zcu).toIntern(),
18352 .flags = .{17693 .flags = .{
18353 .is_const = ptr_info.flags.is_const,17694 .is_const = ptr_info.flags.is_const,
...@@ -18512,7 +17853,7 @@ fn zirRetImplicit(...@@ -18512,7 +17853,7 @@ fn zirRetImplicit(
1851217853
18513 const operand = try sema.resolveInst(inst_data.operand);17854 const operand = try sema.resolveInst(inst_data.operand);
18514 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = .zero });17855 const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = .zero });
18515 const base_tag = sema.fn_ret_ty.baseZigTypeTag(zcu);17856 const base_tag = sema.fn_ret_ty.optEuBaseType(zcu).zigTypeTag(zcu);
18516 if (base_tag == .noreturn) {17857 if (base_tag == .noreturn) {
18517 const msg = msg: {17858 const msg = msg: {
18518 const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{17859 const msg = try sema.errMsg(ret_ty_src, "function declared '{f}' implicitly returns", .{
...@@ -18809,8 +18150,6 @@ fn analyzeRet(...@@ -18809,8 +18150,6 @@ fn analyzeRet(
18809 return sema.failWithOwnedErrorMsg(block, msg);18150 return sema.failWithOwnedErrorMsg(block, msg);
18810 }18151 }
1881118152
18812 try sema.fn_ret_ty.resolveLayout(pt);
18813
18814 try sema.validateRuntimeValue(block, operand_src, operand);18153 try sema.validateRuntimeValue(block, operand_src, operand);
1881518154
18816 const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret;18155 const air_tag: Air.Inst.Tag = if (block.wantSafety()) .ret_safe else .ret;
...@@ -18889,16 +18228,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18889,16 +18228,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18889 extra_i += 1;18228 extra_i += 1;
18890 const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src);18229 const coerced = try sema.coerce(block, align_ty, try sema.resolveInst(ref), align_src);
18891 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });18230 const val = try sema.resolveConstDefinedValue(block, align_src, coerced, .{ .simple = .@"align" });
18892 // Check if this happens to be the lazy alignment of our element type, in18231 const align_bytes = val.toUnsignedInt(zcu);
18893 // which case we can make this 0 without resolving it.
18894 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
18895 .int => |int| switch (int.storage) {
18896 .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none,
18897 else => {},
18898 },
18899 else => {},
18900 }
18901 const align_bytes = (try val.getUnsignedIntSema(pt)).?;
18902 break :blk try sema.validateAlign(block, align_src, align_bytes);18232 break :blk try sema.validateAlign(block, align_src, align_bytes);
18903 } else .none;18233 } else .none;
1890418234
...@@ -18928,7 +18258,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18928,7 +18258,8 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18928 elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size,18258 elem_ty.fmt(pt), bit_offset, bit_offset - host_size * 8, host_size,
18929 });18259 });
18930 }18260 }
18931 const elem_bit_size = try elem_ty.bitSizeSema(pt);18261 try sema.ensureLayoutResolved(elem_ty);
18262 const elem_bit_size = elem_ty.bitSize(zcu);
18932 if (elem_bit_size > host_size * 8 - bit_offset) {18263 if (elem_bit_size > host_size * 8 - bit_offset) {
18933 return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{18264 return sema.fail(block, bitoffset_src, "packed type '{f}' at bit offset {d} ends {d} bits after the end of a {d} byte host integer", .{
18934 elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size,18265 elem_ty.fmt(pt), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size,
...@@ -18957,16 +18288,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -18957,16 +18288,16 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
18957 }18288 }
18958 }18289 }
1895918290
18960 if (host_size != 0 and !try sema.validatePackedType(elem_ty)) {18291 if (host_size != 0 and !elem_ty.packable(zcu)) {
18961 return sema.failWithOwnedErrorMsg(block, msg: {18292 return sema.failWithOwnedErrorMsg(block, msg: {
18962 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});18293 const msg = try sema.errMsg(elem_ty_src, "bit-pointer cannot refer to value of type '{f}'", .{elem_ty.fmt(pt)});
18963 errdefer msg.destroy(sema.gpa);18294 errdefer msg.destroy(sema.gpa);
18964 try sema.explainWhyTypeIsNotPacked(msg, elem_ty_src, elem_ty);18295 try sema.explainWhyTypeIsNotPackable(msg, elem_ty_src, elem_ty);
18965 break :msg msg;18296 break :msg msg;
18966 });18297 });
18967 }18298 }
1896818299
18969 const ty = try pt.ptrTypeSema(.{18300 const ty = try pt.ptrType(.{
18970 .child = elem_ty.toIntern(),18301 .child = elem_ty.toIntern(),
18971 .sentinel = sentinel,18302 .sentinel = sentinel,
18972 .flags = .{18303 .flags = .{
...@@ -18996,6 +18327,8 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE...@@ -18996,6 +18327,8 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
18996 const pt = sema.pt;18327 const pt = sema.pt;
18997 const zcu = pt.zcu;18328 const zcu = pt.zcu;
1899818329
18330 try sema.ensureLayoutResolved(obj_ty);
18331
18999 switch (obj_ty.zigTypeTag(zcu)) {18332 switch (obj_ty.zigTypeTag(zcu)) {
19000 .@"struct" => return sema.structInitEmpty(block, obj_ty, src, src),18333 .@"struct" => return sema.structInitEmpty(block, obj_ty, src, src),
19001 .array, .vector => return sema.arrayInitEmpty(block, src, obj_ty),18334 .array, .vector => return sema.arrayInitEmpty(block, src, obj_ty),
...@@ -19058,6 +18391,9 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is...@@ -19058,6 +18391,9 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is
19058 .child = ptr_ty.childType(zcu).toIntern(),18391 .child = ptr_ty.childType(zcu).toIntern(),
19059 });18392 });
19060 } else ty_operand;18393 } else ty_operand;
18394
18395 try sema.ensureLayoutResolved(init_ty);
18396
19061 const obj_ty = init_ty.optEuBaseType(zcu);18397 const obj_ty = init_ty.optEuBaseType(zcu);
1906218398
19063 const empty_ref = switch (obj_ty.zigTypeTag(zcu)) {18399 const empty_ref = switch (obj_ty.zigTypeTag(zcu)) {
...@@ -19076,6 +18412,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is...@@ -19076,6 +18412,7 @@ fn zirStructInitEmptyResult(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is
19076 }18412 }
19077}18413}
1907818414
18415/// Asserts that the layout of `struct_ty` is already resolved.
19079fn structInitEmpty(18416fn structInitEmpty(
19080 sema: *Sema,18417 sema: *Sema,
19081 block: *Block,18418 block: *Block,
...@@ -19087,7 +18424,7 @@ fn structInitEmpty(...@@ -19087,7 +18424,7 @@ fn structInitEmpty(
19087 const zcu = pt.zcu;18424 const zcu = pt.zcu;
19088 const gpa = sema.gpa;18425 const gpa = sema.gpa;
19089 // This logic must be synchronized with that in `zirStructInit`.18426 // This logic must be synchronized with that in `zirStructInit`.
19090 try struct_ty.resolveFields(pt);18427 struct_ty.assertHasLayout(zcu);
1909118428
19092 // The init values to use for the struct instance.18429 // The init values to use for the struct instance.
19093 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(zcu));18430 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(zcu));
...@@ -19202,8 +18539,8 @@ fn zirStructInit(...@@ -19202,8 +18539,8 @@ fn zirStructInit(
19202 // The type wasn't actually known, so treat this as an anon struct init.18539 // The type wasn't actually known, so treat this as an anon struct init.
19203 return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref);18540 return sema.structInitAnon(block, src, inst, .typed_init, extra.data, extra.end, is_ref);
19204 };18541 };
18542 try sema.ensureLayoutResolved(result_ty);
19205 const resolved_ty = result_ty.optEuBaseType(zcu);18543 const resolved_ty = result_ty.optEuBaseType(zcu);
19206 try resolved_ty.resolveLayout(pt);
1920718544
19208 if (resolved_ty.zigTypeTag(zcu) == .@"struct") {18545 if (resolved_ty.zigTypeTag(zcu) == .@"struct") {
19209 // This logic must be synchronized with that in `zirStructInitEmpty`.18546 // This logic must be synchronized with that in `zirStructInitEmpty`.
...@@ -19226,7 +18563,6 @@ fn zirStructInit(...@@ -19226,7 +18563,6 @@ fn zirStructInit(
19226 var field_i: u32 = 0;18563 var field_i: u32 = 0;
19227 var extra_index = extra.end;18564 var extra_index = extra.end;
1922818565
19229 const is_packed = resolved_ty.containerLayout(zcu) == .@"packed";
19230 while (field_i < extra.data.fields_len) : (field_i += 1) {18566 while (field_i < extra.data.fields_len) : (field_i += 1) {
19231 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);18567 const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
19232 extra_index = item.end;18568 extra_index = item.end;
...@@ -19251,16 +18587,16 @@ fn zirStructInit(...@@ -19251,16 +18587,16 @@ fn zirStructInit(
19251 const uncoerced_init = try sema.resolveInst(item.data.init);18587 const uncoerced_init = try sema.resolveInst(item.data.init);
19252 const field_ty = resolved_ty.fieldType(field_index, zcu);18588 const field_ty = resolved_ty.fieldType(field_index, zcu);
19253 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);18589 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);
19254 if (!is_packed) {18590 if (resolved_ty.structFieldIsComptime(field_index, zcu)) {
19255 try resolved_ty.resolveStructFieldInits(pt);18591 if (!resolved_ty.isTuple(zcu)) {
19256 if (try resolved_ty.structFieldValueComptime(pt, field_index)) |default_value| {18592 try sema.ensureFieldInitsResolved(resolved_ty);
19257 const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {18593 }
19258 return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });18594 const default_value = (try resolved_ty.structFieldValueComptime(pt, field_index)).?;
19259 };18595 const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {
1926018596 return sema.failWithNeededComptime(block, field_src, .{ .simple = .stored_to_comptime_field });
19261 if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) {18597 };
19262 return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);18598 if (!init_val.eql(default_value, resolved_ty.fieldType(field_index, zcu), zcu)) {
19263 }18599 return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
19264 }18600 }
19265 }18601 }
19266 }18602 }
...@@ -19315,7 +18651,7 @@ fn zirStructInit(...@@ -19315,7 +18651,7 @@ fn zirStructInit(
19315 return sema.addConstantMaybeRef(final_val.toIntern(), is_ref);18651 return sema.addConstantMaybeRef(final_val.toIntern(), is_ref);
19316 }18652 }
1931718653
19318 if (try resolved_ty.comptimeOnlySema(pt)) {18654 if (resolved_ty.comptimeOnly(zcu)) {
19319 return sema.failWithNeededComptime(block, field_src, .{ .comptime_only = .{18655 return sema.failWithNeededComptime(block, field_src, .{ .comptime_only = .{
19320 .ty = resolved_ty,18656 .ty = resolved_ty,
19321 .msg = .union_init,18657 .msg = .union_init,
...@@ -19326,7 +18662,7 @@ fn zirStructInit(...@@ -19326,7 +18662,7 @@ fn zirStructInit(
1932618662
19327 if (is_ref) {18663 if (is_ref) {
19328 const target = zcu.getTarget();18664 const target = zcu.getTarget();
19329 const alloc_ty = try pt.ptrTypeSema(.{18665 const alloc_ty = try pt.ptrType(.{
19330 .child = result_ty.toIntern(),18666 .child = result_ty.toIntern(),
19331 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },18667 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19332 });18668 });
...@@ -19334,9 +18670,8 @@ fn zirStructInit(...@@ -19334,9 +18670,8 @@ fn zirStructInit(
19334 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);18670 const base_ptr = try sema.optEuBasePtrInit(block, alloc, src);
19335 const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);18671 const field_ptr = try sema.unionFieldPtr(block, field_src, base_ptr, field_name, field_src, resolved_ty, true);
19336 try sema.storePtr(block, src, field_ptr, init_inst);18672 try sema.storePtr(block, src, field_ptr, init_inst);
19337 if ((try sema.typeHasOnePossibleValue(tag_ty)) == null) {18673 if (try tag_ty.onePossibleValue(pt) == null) {
19338 const new_tag = Air.internedToRef(tag_val.toIntern());18674 _ = try block.addBinOp(.set_union_tag, base_ptr, .fromValue(tag_val));
19339 _ = try block.addBinOp(.set_union_tag, base_ptr, new_tag);
19340 }18675 }
19341 return sema.makePtrConst(block, alloc);18676 return sema.makePtrConst(block, alloc);
19342 }18677 }
...@@ -19409,20 +18744,24 @@ fn finishStructInit(...@@ -19409,20 +18744,24 @@ fn finishStructInit(
19409 continue;18744 continue;
19410 }18745 }
1941118746
19412 try struct_ty.resolveStructFieldInits(pt);18747 try sema.ensureFieldInitsResolved(struct_ty);
1941318748
19414 const field_init = struct_type.fieldInit(ip, i);18749 const field_default: InternPool.Index = d: {
19415 if (field_init == .none) {18750 if (struct_type.field_defaults.len == 0) break :d .none;
19416 const field_name = struct_type.field_names.get(ip)[i];18751 break :d struct_type.field_defaults.get(ip)[i];
19417 const template = "missing struct field: {f}";18752 };
19418 const args = .{field_name.fmt(ip)};18753 if (field_default != .none) {
19419 if (root_msg) |msg| {18754 field_inits[i] = .fromIntern(field_default);
19420 try sema.errNote(init_src, msg, template, args);18755 continue;
19421 } else {18756 }
19422 root_msg = try sema.errMsg(init_src, template, args);18757
19423 }18758 const field_name = struct_type.field_names.get(ip)[i];
18759 const template = "missing struct field: {f}";
18760 const args = .{field_name.fmt(ip)};
18761 if (root_msg) |msg| {
18762 try sema.errNote(init_src, msg, template, args);
19424 } else {18763 } else {
19425 field_inits[i] = Air.internedToRef(field_init);18764 root_msg = try sema.errMsg(init_src, template, args);
19426 }18765 }
19427 }18766 }
19428 },18767 },
...@@ -19453,7 +18792,7 @@ fn finishStructInit(...@@ -19453,7 +18792,7 @@ fn finishStructInit(
19453 return sema.addConstantMaybeRef(final_val.toIntern(), is_ref);18792 return sema.addConstantMaybeRef(final_val.toIntern(), is_ref);
19454 };18793 };
1945518794
19456 if (try struct_ty.comptimeOnlySema(pt)) {18795 if (struct_ty.comptimeOnly(zcu)) {
19457 return sema.failWithNeededComptime(block, block.src(.{ .init_elem = .{18796 return sema.failWithNeededComptime(block, block.src(.{ .init_elem = .{
19458 .init_node_offset = init_src.offset.node_offset.x,18797 .init_node_offset = init_src.offset.node_offset.x,
19459 .elem_index = @intCast(runtime_index),18798 .elem_index = @intCast(runtime_index),
...@@ -19468,9 +18807,8 @@ fn finishStructInit(...@@ -19468,9 +18807,8 @@ fn finishStructInit(
19468 }18807 }
1946918808
19470 if (is_ref) {18809 if (is_ref) {
19471 try struct_ty.resolveLayout(pt);
19472 const target = zcu.getTarget();18810 const target = zcu.getTarget();
19473 const alloc_ty = try pt.ptrTypeSema(.{18811 const alloc_ty = try pt.ptrType(.{
19474 .child = result_ty.toIntern(),18812 .child = result_ty.toIntern(),
19475 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },18813 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19476 });18814 });
...@@ -19489,7 +18827,6 @@ fn finishStructInit(...@@ -19489,7 +18827,6 @@ fn finishStructInit(
19489 .init_node_offset = init_src.offset.node_offset.x,18827 .init_node_offset = init_src.offset.node_offset.x,
19490 .elem_index = @intCast(runtime_index),18828 .elem_index = @intCast(runtime_index),
19491 } }));18829 } }));
19492 try struct_ty.resolveStructFieldInits(pt);
19493 const struct_val = try block.addAggregateInit(struct_ty, field_inits);18830 const struct_val = try block.addAggregateInit(struct_ty, field_inits);
19494 return sema.coerce(block, result_ty, struct_val, init_src);18831 return sema.coerce(block, result_ty, struct_val, init_src);
19495}18832}
...@@ -19585,12 +18922,11 @@ fn structInitAnon(...@@ -19585,12 +18922,11 @@ fn structInitAnon(
19585 break :rs runtime_index;18922 break :rs runtime_index;
19586 };18923 };
1958718924
19588 // We treat anonymous struct types as reified types, because there are similarities:18925 // We treat anonymous struct types as reified types, because there are similarities: they have
19589 // * They use a form of structural equivalence, which we can easily model using a custom hash18926 // no captures, and instead use a form of structural equivalence which we can easy represent by
19590 // * They do not have captures18927 // hashing the field names/types/values. They also perform layout resolution immediately. These
19591 // * They immediately have their fields resolved18928 // similarities mean that other code should actually treat anon struct types and reified struct
19592 // In general, other code should treat anon struct types and reified struct types identically,18929 // types identically anyway, so sharing the representation makes everything simpler.
19593 // so there's no point having a separate `InternPool.NamespaceType` field for them.
19594 const type_hash: u64 = hash: {18930 const type_hash: u64 = hash: {
19595 var hasher = std.hash.Wyhash.init(0);18931 var hasher = std.hash.Wyhash.init(0);
19596 hasher.update(std.mem.sliceAsBytes(types));18932 hasher.update(std.mem.sliceAsBytes(types));
...@@ -19599,36 +18935,36 @@ fn structInitAnon(...@@ -19599,36 +18935,36 @@ fn structInitAnon(
19599 break :hash hasher.final();18935 break :hash hasher.final();
19600 };18936 };
19601 const tracked_inst = try block.trackZir(inst);18937 const tracked_inst = try block.trackZir(inst);
19602 const struct_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{18938 const struct_ty: Type = switch (try ip.getStructType(gpa, io, pt.tid, .{
19603 .layout = .auto,
19604 .fields_len = extra_data.fields_len,18939 .fields_len = extra_data.fields_len,
19605 .known_non_opv = false,18940 .layout = .auto,
19606 .requires_comptime = .unknown,18941 .explicit_packed_backing_type = .none,
19607 .any_comptime_fields = any_values,18942 .any_comptime_fields = any_values,
19608 .any_default_inits = any_values,18943 .any_field_defaults = any_values,
19609 .inits_resolved = true,18944 .any_field_aligns = false,
19610 .any_aligned_fields = false,
19611 .key = .{ .reified = .{18945 .key = .{ .reified = .{
19612 .zir_index = tracked_inst,18946 .zir_index = tracked_inst,
19613 .type_hash = type_hash,18947 .type_hash = type_hash,
19614 } },18948 } },
19615 }, false)) {18949 })) {
19616 .wip => |wip| ty: {18950 .wip => |wip| ty: {
19617 errdefer wip.cancel(ip, pt.tid);18951 errdefer wip.cancel(ip, pt.tid);
19618 const type_name = try sema.createTypeName(block, .anon, "struct", inst, wip.index);18952 // MLUGG TODO obvs this sux
19619 wip.setName(ip, type_name.name, type_name.nav);18953 const anon_prefix = (try sema.createTypeName(block, .anon, "struct", inst)).anon_prefix;
18954 wip.setName(ip, try ip.getOrPutStringFmt(gpa, io, pt.tid, "{s}_{d}", .{ anon_prefix, @intFromEnum(wip.index) }, .no_embedded_nulls), .none);
1962018955
19621 const struct_type = ip.loadStructType(wip.index);18956 const struct_type = ip.loadStructType(wip.index);
1962218957
19623 for (names, values, 0..) |name, init_val, field_idx| {18958 for (names, values) |name, init_val| {
19624 assert(struct_type.addFieldName(ip, name) == null);18959 assert(wip.nextField(ip, name, init_val != .none) == null); // AstGen validated no duplicates for us
19625 if (init_val != .none) struct_type.setFieldComptime(ip, field_idx);
19626 }18960 }
1962718961
18962 // Populating these means the type is already resolved; we don't need to add it to `zcu.outdated` or anything.
18963 // That's important because type resolution relies on types being declared.
19628 @memcpy(struct_type.field_types.get(ip), types);18964 @memcpy(struct_type.field_types.get(ip), types);
19629 if (any_values) {18965 @memcpy(struct_type.field_defaults.get(ip), if (any_values) values else @as([]const InternPool.Index, &.{}));
19630 @memcpy(struct_type.field_inits.get(ip), values);18966
19631 }18967 try type_resolution.finishStructLayout(sema, block, src, wip.index, &struct_type);
1963218968
19633 const new_namespace_index = try pt.createNamespace(.{18969 const new_namespace_index = try pt.createNamespace(.{
19634 .parent = block.namespace.toOptional(),18970 .parent = block.namespace.toOptional(),
...@@ -19636,7 +18972,6 @@ fn structInitAnon(...@@ -19636,7 +18972,6 @@ fn structInitAnon(
19636 .file_scope = block.getFileScopeIndex(zcu),18972 .file_scope = block.getFileScopeIndex(zcu),
19637 .generation = zcu.generation,18973 .generation = zcu.generation,
19638 });18974 });
19639 try zcu.comp.queueJob(.{ .resolve_type_fully = wip.index });
19640 codegen_type: {18975 codegen_type: {
19641 if (zcu.comp.config.use_llvm) break :codegen_type;18976 if (zcu.comp.config.use_llvm) break :codegen_type;
19642 if (block.ownerModule().strip) break :codegen_type;18977 if (block.ownerModule().strip) break :codegen_type;
...@@ -19644,22 +18979,21 @@ fn structInitAnon(...@@ -19644,22 +18979,21 @@ fn structInitAnon(
19644 try zcu.comp.queueJob(.{ .link_type = wip.index });18979 try zcu.comp.queueJob(.{ .link_type = wip.index });
19645 }18980 }
19646 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);18981 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
19647 break :ty wip.finish(ip, new_namespace_index);18982 break :ty .fromInterned(wip.finish(ip, new_namespace_index));
19648 },18983 },
19649 .existing => |ty| ty,18984 .existing => |ty| .fromInterned(ty),
19650 };18985 };
19651 try sema.declareDependency(.{ .interned = struct_ty });
19652 try sema.addTypeReferenceEntry(src, struct_ty);18986 try sema.addTypeReferenceEntry(src, struct_ty);
1965318987
19654 _ = opt_runtime_index orelse {18988 _ = opt_runtime_index orelse {
19655 const struct_val = try pt.aggregateValue(.fromInterned(struct_ty), values);18989 const struct_val = try pt.aggregateValue(struct_ty, values);
19656 return sema.addConstantMaybeRef(struct_val.toIntern(), is_ref);18990 return sema.addConstantMaybeRef(struct_val.toIntern(), is_ref);
19657 };18991 };
1965818992
19659 if (is_ref) {18993 if (is_ref) {
19660 const target = zcu.getTarget();18994 const target = zcu.getTarget();
19661 const alloc_ty = try pt.ptrTypeSema(.{18995 const alloc_ty = try pt.ptrType(.{
19662 .child = struct_ty,18996 .child = struct_ty.toIntern(),
19663 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },18997 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19664 });18998 });
19665 const alloc = try block.addTy(.alloc, alloc_ty);18999 const alloc = try block.addTy(.alloc, alloc_ty);
...@@ -19672,7 +19006,7 @@ fn structInitAnon(...@@ -19672,7 +19006,7 @@ fn structInitAnon(
19672 };19006 };
19673 extra_index = item.end;19007 extra_index = item.end;
1967419008
19675 const field_ptr_ty = try pt.ptrTypeSema(.{19009 const field_ptr_ty = try pt.ptrType(.{
19676 .child = field_ty,19010 .child = field_ty,
19677 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19011 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19678 });19012 });
...@@ -19697,7 +19031,7 @@ fn structInitAnon(...@@ -19697,7 +19031,7 @@ fn structInitAnon(
19697 element_refs[i] = try sema.resolveInst(item.data.init);19031 element_refs[i] = try sema.resolveInst(item.data.init);
19698 }19032 }
1969919033
19700 return block.addAggregateInit(.fromInterned(struct_ty), element_refs);19034 return block.addAggregateInit(struct_ty, element_refs);
19701}19035}
1970219036
19703fn zirArrayInit(19037fn zirArrayInit(
...@@ -19737,17 +19071,16 @@ fn zirArrayInit(...@@ -19737,17 +19071,16 @@ fn zirArrayInit(
19737 } });19071 } });
19738 // Less inits than needed.19072 // Less inits than needed.
19739 if (i + 2 > args.len) if (is_tuple) {19073 if (i + 2 > args.len) if (is_tuple) {
19740 const default_val = array_ty.structFieldDefaultValue(i, zcu).toIntern();19074 const default_val = array_ty.structFieldDefaultValue(i, zcu) orelse {
19741 if (default_val == .unreachable_value) {
19742 const template = "missing tuple field with index {d}";19075 const template = "missing tuple field with index {d}";
19743 if (root_msg) |msg| {19076 if (root_msg) |msg| {
19744 try sema.errNote(src, msg, template, .{i});19077 try sema.errNote(src, msg, template, .{i});
19745 } else {19078 } else {
19746 root_msg = try sema.errMsg(src, template, .{i});19079 root_msg = try sema.errMsg(src, template, .{i});
19747 }19080 }
19748 } else {19081 continue;
19749 dest.* = Air.internedToRef(default_val);19082 };
19750 }19083 dest.* = .fromValue(default_val);
19751 continue;19084 continue;
19752 } else {19085 } else {
19753 dest.* = Air.internedToRef(sentinel_val.?.toIntern());19086 dest.* = Air.internedToRef(sentinel_val.?.toIntern());
...@@ -19759,11 +19092,9 @@ fn zirArrayInit(...@@ -19759,11 +19092,9 @@ fn zirArrayInit(
19759 const elem_ty = if (is_tuple)19092 const elem_ty = if (is_tuple)
19760 array_ty.fieldType(i, zcu)19093 array_ty.fieldType(i, zcu)
19761 else19094 else
19762 array_ty.elemType2(zcu);19095 array_ty.childType(zcu);
19763 dest.* = try sema.coerce(block, elem_ty, resolved_arg, elem_src);19096 dest.* = try sema.coerce(block, elem_ty, resolved_arg, elem_src);
19764 if (is_tuple) {19097 if (is_tuple) {
19765 if (array_ty.structFieldIsComptime(i, zcu))
19766 try array_ty.resolveStructFieldInits(pt);
19767 if (try array_ty.structFieldValueComptime(pt, i)) |field_val| {19098 if (try array_ty.structFieldValueComptime(pt, i)) |field_val| {
19768 const init_val = try sema.resolveConstValue(block, elem_src, dest.*, .{ .simple = .stored_to_comptime_field });19099 const init_val = try sema.resolveConstValue(block, elem_src, dest.*, .{ .simple = .stored_to_comptime_field });
19769 if (!field_val.eql(init_val, elem_ty, zcu)) {19100 if (!field_val.eql(init_val, elem_ty, zcu)) {
...@@ -19798,7 +19129,7 @@ fn zirArrayInit(...@@ -19798,7 +19129,7 @@ fn zirArrayInit(
1979819129
19799 if (is_ref) {19130 if (is_ref) {
19800 const target = zcu.getTarget();19131 const target = zcu.getTarget();
19801 const alloc_ty = try pt.ptrTypeSema(.{19132 const alloc_ty = try pt.ptrType(.{
19802 .child = result_ty.toIntern(),19133 .child = result_ty.toIntern(),
19803 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19134 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19804 });19135 });
...@@ -19807,7 +19138,7 @@ fn zirArrayInit(...@@ -19807,7 +19138,7 @@ fn zirArrayInit(
1980719138
19808 if (is_tuple) {19139 if (is_tuple) {
19809 for (resolved_args, 0..) |arg, i| {19140 for (resolved_args, 0..) |arg, i| {
19810 const elem_ptr_ty = try pt.ptrTypeSema(.{19141 const elem_ptr_ty = try pt.ptrType(.{
19811 .child = array_ty.fieldType(i, zcu).toIntern(),19142 .child = array_ty.fieldType(i, zcu).toIntern(),
19812 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19143 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19813 });19144 });
...@@ -19820,8 +19151,8 @@ fn zirArrayInit(...@@ -19820,8 +19151,8 @@ fn zirArrayInit(
19820 return sema.makePtrConst(block, alloc);19151 return sema.makePtrConst(block, alloc);
19821 }19152 }
1982219153
19823 const elem_ptr_ty = try pt.ptrTypeSema(.{19154 const elem_ptr_ty = try pt.ptrType(.{
19824 .child = array_ty.elemType2(zcu).toIntern(),19155 .child = array_ty.childType(zcu).toIntern(),
19825 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19156 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19826 });19157 });
19827 const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern());19158 const elem_ptr_ty_ref = Air.internedToRef(elem_ptr_ty.toIntern());
...@@ -19932,14 +19263,14 @@ fn arrayInitAnon(...@@ -19932,14 +19263,14 @@ fn arrayInitAnon(
1993219263
19933 if (is_ref) {19264 if (is_ref) {
19934 const target = sema.pt.zcu.getTarget();19265 const target = sema.pt.zcu.getTarget();
19935 const alloc_ty = try pt.ptrTypeSema(.{19266 const alloc_ty = try pt.ptrType(.{
19936 .child = tuple_ty.toIntern(),19267 .child = tuple_ty.toIntern(),
19937 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19268 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19938 });19269 });
19939 const alloc = try block.addTy(.alloc, alloc_ty);19270 const alloc = try block.addTy(.alloc, alloc_ty);
19940 for (operands, 0..) |operand, i_usize| {19271 for (operands, 0..) |operand, i_usize| {
19941 const i: u32 = @intCast(i_usize);19272 const i: u32 = @intCast(i_usize);
19942 const field_ptr_ty = try pt.ptrTypeSema(.{19273 const field_ptr_ty = try pt.ptrType(.{
19943 .child = types[i],19274 .child = types[i],
19944 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },19275 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
19945 });19276 });
...@@ -19971,6 +19302,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -19971,6 +19302,7 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
19971 const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);19302 const field_src = block.builtinCallArgSrc(inst_data.src_node, 1);
19972 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);19303 const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
19973 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name });19304 const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, .{ .simple = .field_name });
19305 try sema.ensureLayoutResolved(aggregate_ty);
19974 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);19306 return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
19975}19307}
1997619308
...@@ -19990,9 +19322,11 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp...@@ -19990,9 +19322,11 @@ fn zirStructInitFieldType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
19990 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu);19322 const aggregate_ty = wrapped_aggregate_ty.optEuBaseType(zcu);
19991 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);19323 const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
19992 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls);19324 const field_name = try ip.getOrPutString(gpa, io, pt.tid, zir_field_name, .no_embedded_nulls);
19325 try sema.ensureLayoutResolved(aggregate_ty);
19993 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);19326 return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
19994}19327}
1999519328
19329/// Asserts that the layout of `aggregate_ty` is resolved.
19996fn fieldType(19330fn fieldType(
19997 sema: *Sema,19331 sema: *Sema,
19998 block: *Block,19332 block: *Block,
...@@ -20006,7 +19340,6 @@ fn fieldType(...@@ -20006,7 +19340,6 @@ fn fieldType(
20006 const ip = &zcu.intern_pool;19340 const ip = &zcu.intern_pool;
20007 var cur_ty = aggregate_ty;19341 var cur_ty = aggregate_ty;
20008 while (true) {19342 while (true) {
20009 try cur_ty.resolveFields(pt);
20010 switch (cur_ty.zigTypeTag(zcu)) {19343 switch (cur_ty.zigTypeTag(zcu)) {
20011 .@"struct" => switch (ip.indexToKey(cur_ty.toIntern())) {19344 .@"struct" => switch (ip.indexToKey(cur_ty.toIntern())) {
20012 .tuple_type => |tuple| {19345 .tuple_type => |tuple| {
...@@ -20024,10 +19357,11 @@ fn fieldType(...@@ -20024,10 +19357,11 @@ fn fieldType(
20024 },19357 },
20025 .@"union" => {19358 .@"union" => {
20026 const union_obj = zcu.typeToUnion(cur_ty).?;19359 const union_obj = zcu.typeToUnion(cur_ty).?;
20027 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse19360 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
19361 const field_index = enum_obj.nameIndex(ip, field_name) orelse
20028 return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name);19362 return sema.failWithBadUnionFieldAccess(block, cur_ty, union_obj, field_src, field_name);
20029 const field_ty = union_obj.field_types.get(ip)[field_index];19363 const field_ty = union_obj.field_types.get(ip)[field_index];
20030 return Air.internedToRef(field_ty);19364 return .fromIntern(field_ty);
20031 },19365 },
20032 .optional => {19366 .optional => {
20033 // Struct/array init through optional requires the child type to not be a pointer.19367 // Struct/array init through optional requires the child type to not be a pointer.
...@@ -20056,7 +19390,6 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -20056,7 +19390,6 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
20056 const zcu = pt.zcu;19390 const zcu = pt.zcu;
20057 const ip = &zcu.intern_pool;19391 const ip = &zcu.intern_pool;
20058 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);19392 const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(.zero), .StackTrace);
20059 try stack_trace_ty.resolveFields(pt);
20060 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);19393 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
20061 const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());19394 const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
2006219395
...@@ -20064,7 +19397,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {...@@ -20064,7 +19397,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
20064 .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {19397 .func => |func| if (ip.funcAnalysisUnordered(func).has_error_trace and block.ownerModule().error_tracing) {
20065 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);19398 return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
20066 },19399 },
20067 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},19400 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},
20068 }19401 }
20069 return Air.internedToRef(try pt.intern(.{ .opt = .{19402 return Air.internedToRef(try pt.intern(.{ .opt = .{
20070 .ty = opt_ptr_stack_trace_ty.toIntern(),19403 .ty = opt_ptr_stack_trace_ty.toIntern(),
...@@ -20083,15 +19416,16 @@ fn zirFrame(...@@ -20083,15 +19416,16 @@ fn zirFrame(
20083}19416}
2008419417
20085fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {19418fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
20086 const zcu = sema.pt.zcu;19419 const pt = sema.pt;
19420 const zcu = pt.zcu;
20087 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;19421 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
20088 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);19422 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0);
20089 const ty = try sema.resolveType(block, operand_src, inst_data.operand);19423 const ty = try sema.resolveType(block, operand_src, inst_data.operand);
20090 if (ty.isNoReturn(zcu)) {19424 if (ty.isNoReturn(zcu)) {
20091 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});19425 return sema.fail(block, operand_src, "no align available for type '{f}'", .{ty.fmt(sema.pt)});
20092 }19426 }
20093 const val = try ty.lazyAbiAlignment(sema.pt);19427 try sema.ensureLayoutResolved(ty);
20094 return Air.internedToRef(val.toIntern());19428 return .fromValue(try pt.intValue(.comptime_int, ty.abiAlignment(zcu).toByteUnits().?));
20095}19429}
2009619430
20097fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {19431fn zirIntFromBool(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
...@@ -20249,7 +19583,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air...@@ -20249,7 +19583,6 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
20249 const pt = sema.pt;19583 const pt = sema.pt;
20250 const zcu = pt.zcu;19584 const zcu = pt.zcu;
20251 const ip = &zcu.intern_pool;19585 const ip = &zcu.intern_pool;
20252 try operand_ty.resolveLayout(pt);
20253 const enum_ty = switch (operand_ty.zigTypeTag(zcu)) {19586 const enum_ty = switch (operand_ty.zigTypeTag(zcu)) {
20254 .enum_literal => {19587 .enum_literal => {
20255 const val = (try sema.resolveDefinedValue(block, operand_src, operand)).?;19588 const val = (try sema.resolveDefinedValue(block, operand_src, operand)).?;
...@@ -20332,7 +19665,7 @@ fn zirReifySliceArgTy(...@@ -20332,7 +19665,7 @@ fn zirReifySliceArgTy(
20332 // zig fmt: on19665 // zig fmt: on
20333 };19666 };
2033419667
20335 const operand_ty = try pt.ptrTypeSema(.{19668 const operand_ty = try pt.ptrType(.{
20336 .child = in_scalar_ty.toIntern(),19669 .child = in_scalar_ty.toIntern(),
20337 .flags = .{ .size = .slice, .is_const = true },19670 .flags = .{ .size = .slice, .is_const = true },
20338 });19671 });
...@@ -20342,7 +19675,7 @@ fn zirReifySliceArgTy(...@@ -20342,7 +19675,7 @@ fn zirReifySliceArgTy(
20342 const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason });19675 const operand_val = try sema.resolveConstDefinedValue(block, src, operand_coerced, .{ .simple = comptime_reason });
20343 const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);19676 const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
20344 if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);19677 if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, src, null);
20345 const len = try len_val.toUnsignedIntSema(pt);19678 const len = len_val.toUnsignedInt(zcu);
2034619679
20347 return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{19680 return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
20348 .len = len,19681 .len = len,
...@@ -20370,7 +19703,7 @@ fn zirReifyEnumValueSliceTy(...@@ -20370,7 +19703,7 @@ fn zirReifyEnumValueSliceTy(
20370 const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names });19703 const operand_val = try sema.resolveConstDefinedValue(block, field_names_src, operand_coerced, .{ .simple = .enum_field_names });
20371 const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);19704 const len_val: Value = .fromInterned(zcu.intern_pool.indexToKey(operand_val.toIntern()).slice.len);
20372 if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null);19705 if (len_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, field_names_src, null);
20373 const len = try len_val.toUnsignedIntSema(pt);19706 const len = len_val.toUnsignedInt(zcu);
2037419707
20375 return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{19708 return .fromType(try pt.singleConstPtrType(try pt.arrayType(.{
20376 .len = len,19709 .len = len,
...@@ -20422,6 +19755,7 @@ fn zirReifyTuple(...@@ -20422,6 +19755,7 @@ fn zirReifyTuple(
20422 if (field_ty_val.isUndef(zcu)) {19755 if (field_ty_val.isUndef(zcu)) {
20423 return sema.failWithUseOfUndef(block, operand_src, null);19756 return sema.failWithUseOfUndef(block, operand_src, null);
20424 }19757 }
19758 try sema.validateTupleFieldType(block, field_ty_val.toType(), operand_src);
20425 field_ty.* = field_ty_val.toIntern();19759 field_ty.* = field_ty_val.toIntern();
20426 }19760 }
2042719761
...@@ -20516,7 +19850,7 @@ fn zirReifyPointer(...@@ -20516,7 +19850,7 @@ fn zirReifyPointer(
20516 }19850 }
20517 }19851 }
2051819852
20519 return .fromType(try pt.ptrTypeSema(.{19853 return .fromType(try pt.ptrType(.{
20520 .child = elem_ty.toIntern(),19854 .child = elem_ty.toIntern(),
20521 .sentinel = if (opt_sentinel) |s| s.toIntern() else .none,19855 .sentinel = if (opt_sentinel) |s| s.toIntern() else .none,
20522 .flags = .{19856 .flags = .{
...@@ -20571,6 +19905,7 @@ fn zirReifyFn(...@@ -20571,6 +19905,7 @@ fn zirReifyFn(
20571 const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });19905 const param_attrs_arr = try sema.derefSliceAsArray(block, param_attrs_src, param_attrs_slice, .{ .simple = .fn_param_attrs });
2057219906
20573 const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);19907 const ret_ty = try sema.resolveType(block, ret_ty_src, extra.ret_ty);
19908 try sema.ensureLayoutResolved(ret_ty);
2057419909
20575 const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs);19910 const fn_attrs_uncoerced = try sema.resolveInst(extra.fn_attrs);
20576 const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);19911 const fn_attrs_coerced = try sema.coerce(block, fn_attrs_ty, fn_attrs_uncoerced, fn_attrs_src);
...@@ -20595,7 +19930,8 @@ fn zirReifyFn(...@@ -20595,7 +19930,8 @@ fn zirReifyFn(
20595 param_types_src,19930 param_types_src,
20596 fn_attrs.@"callconv",19931 fn_attrs.@"callconv",
20597 );19932 );
20598 if (try param_ty.comptimeOnlySema(pt)) {19933 try sema.ensureLayoutResolved(param_ty);
19934 if (param_ty.comptimeOnly(zcu)) {
20599 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)});19935 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only parameter type '{f}'", .{param_ty.fmt(pt)});
20600 }19936 }
20601 if (param_attrs.@"noalias") {19937 if (param_attrs.@"noalias") {
...@@ -20621,7 +19957,7 @@ fn zirReifyFn(...@@ -20621,7 +19957,7 @@ fn zirReifyFn(
20621 false,19957 false,
20622 false,19958 false,
20623 );19959 );
20624 if (try ret_ty.comptimeOnlySema(pt)) {19960 if (ret_ty.comptimeOnly(zcu)) {
20625 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});19961 return sema.fail(block, param_attrs_src, "cannot reify function type with comptime-only return type '{f}'", .{ret_ty.fmt(pt)});
20626 }19962 }
2062719963
...@@ -20632,7 +19968,6 @@ fn zirReifyFn(...@@ -20632,7 +19968,6 @@ fn zirReifyFn(
20632 .return_type = ret_ty.toIntern(),19968 .return_type = ret_ty.toIntern(),
20633 .cc = fn_attrs.@"callconv",19969 .cc = fn_attrs.@"callconv",
20634 .is_var_args = fn_attrs.varargs,19970 .is_var_args = fn_attrs.varargs,
20635 .is_generic = false,
20636 .is_noinline = false,19971 .is_noinline = false,
20637 }));19972 }));
20638}19973}
...@@ -20791,8 +20126,7 @@ fn zirReifyStruct(...@@ -20791,8 +20126,7 @@ fn zirReifyStruct(
20791 field_attrs_src,20126 field_attrs_src,
20792 .{ .simple = .struct_field_default_value },20127 .{ .simple = .struct_field_default_value },
20793 );20128 );
20794 // Resolve the value so that lazy values do not create distinct types.20129 break :d deref_val.toIntern();
20795 break :d (try sema.resolveLazyValue(deref_val)).toIntern();
20796 };20130 };
2079720131
20798 std.hash.autoHash(&hasher, .{20132 std.hash.autoHash(&hasher, .{
...@@ -20823,36 +20157,31 @@ fn zirReifyStruct(...@@ -20823,36 +20157,31 @@ fn zirReifyStruct(
20823 }20157 }
2082420158
20825 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{20159 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
20826 .layout = layout,
20827 .fields_len = @intCast(fields_len),20160 .fields_len = @intCast(fields_len),
20828 .known_non_opv = false,20161 .layout = layout,
20829 .requires_comptime = .unknown,20162 .explicit_packed_backing_type = if (backing_int_ty) |t| t.toIntern() else .none,
20830 .any_comptime_fields = any_comptime_fields,20163 .any_comptime_fields = any_comptime_fields,
20831 .any_default_inits = any_default_inits,20164 .any_field_defaults = any_default_inits,
20832 .any_aligned_fields = any_aligned_fields,20165 .any_field_aligns = any_aligned_fields,
20833 .inits_resolved = true,
20834 .key = .{ .reified = .{20166 .key = .{ .reified = .{
20835 .zir_index = tracked_inst,20167 .zir_index = tracked_inst,
20836 .type_hash = hasher.final(),20168 .type_hash = hasher.final(),
20837 } },20169 } },
20838 }, false)) {20170 })) {
20839 .wip => |wip| wip,20171 .wip => |wip| wip,
20840 .existing => |ty| {20172 .existing => |ty| {
20841 try sema.declareDependency(.{ .interned = ty });20173 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
20842 try sema.addTypeReferenceEntry(src, ty);20174 return .fromIntern(ty);
20843 return Air.internedToRef(ty);
20844 },20175 },
20845 };20176 };
20846 errdefer wip_ty.cancel(ip, pt.tid);20177 errdefer wip_ty.cancel(ip, pt.tid);
2084720178
20848 const type_name = try sema.createTypeName(20179 _ = try (try sema.createTypeName(
20849 block,20180 block,
20850 name_strategy,20181 name_strategy,
20851 "struct",20182 "struct",
20852 inst,20183 inst,
20853 wip_ty.index,20184 )).apply(&wip_ty, pt);
20854 );
20855 wip_ty.setName(ip, type_name.name, type_name.nav);
2085620185
20857 const wip_struct_type = ip.loadStructType(wip_ty.index);20186 const wip_struct_type = ip.loadStructType(wip_ty.index);
2085820187
...@@ -20860,15 +20189,9 @@ fn zirReifyStruct(...@@ -20860,15 +20189,9 @@ fn zirReifyStruct(
20860 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20189 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
20861 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);20190 const field_attrs_val = try field_attrs_arr.elemValue(pt, field_idx);
2086220191
20863 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20864
20865 // Don't pass a reason; first loop acts as a check that this is valid.20192 // Don't pass a reason; first loop acts as a check that this is valid.
20866 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);20193 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
20867 if (wip_struct_type.addFieldName(ip, field_name)) |prev_index| {20194 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
20868 _ = prev_index; // TODO: better source location
20869 return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
20870 }
20871
20872 const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(20195 const field_attr_comptime = try field_attrs_val.fieldValue(pt, std.meta.fieldIndex(
20873 std.builtin.Type.StructField.Attributes,20196 std.builtin.Type.StructField.Attributes,
20874 "comptime",20197 "comptime",
...@@ -20882,14 +20205,9 @@ fn zirReifyStruct(...@@ -20882,14 +20205,9 @@ fn zirReifyStruct(
20882 "default_value_ptr",20205 "default_value_ptr",
20883 ).?);20206 ).?);
2088420207
20885 if (field_attr_align.optionalValue(zcu)) |field_align_val| {20208 if (wip_ty.nextField(ip, field_name, field_attr_comptime.toBool())) |prev_index| {
20886 assert(layout != .@"packed");20209 _ = prev_index; // TODO: better source location
20887 const bytes = try field_align_val.toUnsignedIntSema(pt);20210 return sema.fail(block, field_names_src, "duplicate struct field name {f}", .{field_name.fmt(ip)});
20888 const a = try sema.validateAlign(block, field_attrs_src, bytes);
20889 wip_struct_type.field_aligns.get(ip)[field_idx] = a;
20890 } else if (any_aligned_fields) {
20891 assert(layout != .@"packed");
20892 wip_struct_type.field_aligns.get(ip)[field_idx] = .none;
20893 }20211 }
2089420212
20895 const field_default: InternPool.Index = d: {20213 const field_default: InternPool.Index = d: {
...@@ -20902,20 +20220,11 @@ fn zirReifyStruct(...@@ -20902,20 +20220,11 @@ fn zirReifyStruct(
20902 if (deref_val.canMutateComptimeVarState(zcu)) {20220 if (deref_val.canMutateComptimeVarState(zcu)) {
20903 return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);20221 return sema.failWithContainsReferenceToComptimeVar(block, field_attrs_src, field_name, "field default value", deref_val);
20904 }20222 }
20905 break :d (try sema.resolveLazyValue(deref_val)).toIntern();20223 break :d deref_val.toIntern();
20906 };20224 };
2090720225
20908 if (field_attr_comptime.toBool()) {20226 if (field_attr_comptime.toBool() and field_default == .none) {
20909 assert(layout == .auto);20227 return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
20910 if (field_default == .none) {
20911 return sema.fail(block, field_attrs_src, "comptime field without default initialization value", .{});
20912 }
20913 wip_struct_type.setFieldComptime(ip, field_idx);
20914 }
20915
20916 wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern();
20917 if (field_default != .none) {
20918 wip_struct_type.field_inits.get(ip)[field_idx] = field_default;
20919 }20228 }
2092020229
20921 switch (field_ty.zigTypeTag(zcu)) {20230 switch (field_ty.zigTypeTag(zcu)) {
...@@ -20945,32 +20254,55 @@ fn zirReifyStruct(...@@ -20945,32 +20254,55 @@ fn zirReifyStruct(
20945 break :msg msg;20254 break :msg msg;
20946 });20255 });
20947 },20256 },
20948 .@"packed" => if (!try sema.validatePackedType(field_ty)) {20257 .@"packed" => if (!field_ty.packable(zcu)) {
20949 return sema.failWithOwnedErrorMsg(block, msg: {20258 return sema.failWithOwnedErrorMsg(block, msg: {
20950 const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});20259 const msg = try sema.errMsg(field_types_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
20951 errdefer msg.destroy(gpa);20260 errdefer msg.destroy(gpa);
20952 try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);20261 try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty);
20953 try sema.addDeclaredHereNote(msg, field_ty);20262 try sema.addDeclaredHereNote(msg, field_ty);
20954 break :msg msg;20263 break :msg msg;
20955 });20264 });
20956 },20265 },
20957 }20266 }
20267
20268 wip_struct_type.field_types.get(ip)[field_idx] = field_ty.toIntern();
20269 if (field_default != .none) {
20270 wip_struct_type.field_defaults.get(ip)[field_idx] = field_default;
20271 }
20272
20273 if (field_attr_align.optionalValue(zcu)) |field_align_val| {
20274 assert(layout != .@"packed");
20275 const bytes = field_align_val.toUnsignedInt(zcu);
20276 const a = try sema.validateAlign(block, field_attrs_src, bytes);
20277 wip_struct_type.field_aligns.get(ip)[field_idx] = a;
20278 } else if (any_aligned_fields) {
20279 assert(layout != .@"packed");
20280 wip_struct_type.field_aligns.get(ip)[field_idx] = .none;
20281 }
20958 }20282 }
2095920283
20960 if (layout == .@"packed") {20284 if (layout == .@"packed") {
20961 var fields_bit_sum: u64 = 0;20285 var field_bits: u64 = 0;
20962 for (0..wip_struct_type.field_types.len) |field_idx| {20286 for (0..fields_len) |field_idx| {
20963 const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);20287 const field_ty: Type = .fromInterned(wip_struct_type.field_types.get(ip)[field_idx]);
20964 try field_ty.resolveLayout(pt);20288 try sema.ensureLayoutResolved(field_ty);
20965 fields_bit_sum += field_ty.bitSize(zcu);20289 field_bits += field_ty.bitSize(zcu);
20966 }
20967 if (backing_int_ty) |ty| {
20968 try sema.checkBackingIntType(block, src, ty, fields_bit_sum);
20969 wip_struct_type.setBackingIntType(ip, io, ty.toIntern());
20970 } else {
20971 const ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
20972 wip_struct_type.setBackingIntType(ip, io, ty.toIntern());
20973 }20290 }
20291 try type_resolution.resolvePackedStructBackingInt(
20292 sema,
20293 block,
20294 field_bits,
20295 .fromInterned(wip_ty.index),
20296 &wip_struct_type,
20297 );
20298 } else {
20299 try type_resolution.finishStructLayout(
20300 sema,
20301 block,
20302 src,
20303 wip_ty.index,
20304 &wip_struct_type,
20305 );
20974 }20306 }
2097520307
20976 const new_namespace_index = try pt.createNamespace(.{20308 const new_namespace_index = try pt.createNamespace(.{
...@@ -20980,16 +20312,13 @@ fn zirReifyStruct(...@@ -20980,16 +20312,13 @@ fn zirReifyStruct(
20980 .generation = zcu.generation,20312 .generation = zcu.generation,
20981 });20313 });
2098220314
20983 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
20984 codegen_type: {20315 codegen_type: {
20985 if (zcu.comp.config.use_llvm) break :codegen_type;20316 if (zcu.comp.config.use_llvm) break :codegen_type;
20986 if (block.ownerModule().strip) break :codegen_type;20317 if (block.ownerModule().strip) break :codegen_type;
20987 // This job depends on any resolve_type_fully jobs queued up before it.
20988 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);20318 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
20989 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });20319 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
20990 }20320 }
20991 try sema.declareDependency(.{ .interned = wip_ty.index });20321 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));
20992 try sema.addTypeReferenceEntry(src, wip_ty.index);
20993 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);20322 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
20994 return .fromIntern(wip_ty.finish(ip, new_namespace_index));20323 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
20995}20324}
...@@ -21134,62 +20463,52 @@ fn zirReifyUnion(...@@ -21134,62 +20463,52 @@ fn zirReifyUnion(
21134 }20463 }
2113520464
21136 // Some basic validation to avoid a bogus `getUnionType` call...20465 // Some basic validation to avoid a bogus `getUnionType` call...
21137 const explicit_tag_ty: ?Type = if (arg_ty_val.optionalValue(zcu)) |arg_ty| ty: {20466 const explicit_tag_ty: ?Type, const explicit_packed_backing_type: ?Type = ty: {
20467 const arg_ty = arg_ty_val.optionalValue(zcu) orelse break :ty .{ null, null };
21138 switch (layout) {20468 switch (layout) {
21139 .@"extern", .@"packed" => return sema.fail(block, arg_ty_src, "{t} union does not support enum tag type", .{layout}),20469 .@"extern" => return sema.fail(block, arg_ty_src, "extern union does not support enum tag type", .{}),
21140 .auto => {},20470 .@"packed" => break :ty .{ null, arg_ty.toType() },
20471 .auto => break :ty .{ arg_ty.toType(), null },
21141 }20472 }
21142 break :ty arg_ty.toType();20473 };
21143 } else null;
21144 if (any_aligned_fields and layout == .@"packed") {20474 if (any_aligned_fields and layout == .@"packed") {
21145 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});20475 return sema.fail(block, field_attrs_src, "packed union fields cannot be aligned", .{});
21146 }20476 }
2114720477
21148 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{20478 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
21149 .flags = .{
21150 .layout = layout,
21151 .status = .none,
21152 .runtime_tag = rt: {
21153 if (explicit_tag_ty != null) break :rt .tagged;
21154 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
21155 break :rt .none;
21156 },
21157 .any_aligned_fields = any_aligned_fields,
21158 .requires_comptime = .unknown,
21159 .assumed_runtime_bits = false,
21160 .assumed_pointer_aligned = false,
21161 .alignment = .none,
21162 },
21163 .fields_len = @intCast(fields_len),20479 .fields_len = @intCast(fields_len),
21164 .enum_tag_ty = .none, // set later because not yet validated20480 .layout = layout,
21165 .field_types = &.{}, // set later20481 .explicit_packed_backing_type = if (explicit_packed_backing_type) |t| t.toIntern() else .none,
21166 .field_aligns = &.{}, // set later20482 .runtime_tag = rt: {
20483 if (explicit_tag_ty != null) break :rt .tagged;
20484 if (layout == .auto and block.wantSafeTypes()) break :rt .safety;
20485 break :rt .none;
20486 },
20487 .have_explicit_enum_tag = explicit_tag_ty != null,
20488 .any_field_aligns = any_aligned_fields,
21167 .key = .{ .reified = .{20489 .key = .{ .reified = .{
21168 .zir_index = tracked_inst,20490 .zir_index = tracked_inst,
21169 .type_hash = hasher.final(),20491 .type_hash = hasher.final(),
21170 } },20492 } },
21171 }, false)) {20493 })) {
21172 .wip => |wip| wip,20494 .wip => |wip| wip,
21173 .existing => |ty| {20495 .existing => |ty| {
21174 try sema.declareDependency(.{ .interned = ty });20496 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
21175 try sema.addTypeReferenceEntry(src, ty);20497 return .fromIntern(ty);
21176 return Air.internedToRef(ty);
21177 },20498 },
21178 };20499 };
21179 errdefer wip_ty.cancel(ip, pt.tid);20500 errdefer wip_ty.cancel(ip, pt.tid);
2118020501
21181 const type_name = try sema.createTypeName(20502 const type_name = try (try sema.createTypeName(
21182 block,20503 block,
21183 name_strategy,20504 name_strategy,
21184 "union",20505 "union",
21185 inst,20506 inst,
21186 wip_ty.index,20507 )).apply(&wip_ty, pt);
21187 );
21188 wip_ty.setName(ip, type_name.name, type_name.nav);
2118920508
21190 const loaded_union = ip.loadUnionType(wip_ty.index);20509 const loaded_union = ip.loadUnionType(wip_ty.index);
2119120510
21192 const enum_tag_ty, const has_explicit_tag = if (explicit_tag_ty) |enum_tag_ty| tag: {20511 const generated_tag_ty: InternPool.Index = if (explicit_tag_ty) |enum_tag_ty| generated_tag: {
21193 if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") {20512 if (enum_tag_ty.zigTypeTag(zcu) != .@"enum") {
21194 return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{});20513 return sema.fail(block, arg_ty_src, "tag type must be an enum type", .{});
21195 }20514 }
...@@ -21227,26 +20546,67 @@ fn zirReifyUnion(...@@ -21227,26 +20546,67 @@ fn zirReifyUnion(
21227 try sema.addDeclaredHereNote(msg, enum_tag_ty);20546 try sema.addDeclaredHereNote(msg, enum_tag_ty);
21228 break :msg msg;20547 break :msg msg;
21229 });20548 });
21230 break :tag .{ enum_tag_ty.toIntern(), true };20549 wip_ty.setTagType(ip, enum_tag_ty.toIntern());
21231 } else tag: {20550 break :generated_tag .none;
21232 // We must track field names and set up the tag type ourselves.20551 } else generated_tag: {
21233 var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .empty;20552 // Generate the union's hypothetical tag type.
21234 try field_names.ensureTotalCapacity(sema.arena, fields_len);20553 const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
20554 .fields_len = @intCast(fields_len),
20555 .explicit_int_tag_type = .none,
20556 .nonexhaustive = false,
20557 .key = .{ .generated_union_tag = wip_ty.index },
20558 })) {
20559 .existing => unreachable, // enum type is keyed on this union type which we're only just creating
20560 .wip => |wip_tag_ty| wip_tag_ty,
20561 };
20562 errdefer wip_tag_ty.cancel(ip, pt.tid);
2123520563
20564 // Set its name based on the union's name
20565 _ = wip_tag_ty.setName(ip, try ip.getOrPutStringFmt(
20566 gpa,
20567 io,
20568 pt.tid,
20569 "@typeInfo({f}).@\"union\".tag_type.?",
20570 .{type_name.fmt(ip)},
20571 .no_embedded_nulls,
20572 ), .none);
20573
20574 // Populate its fields (and report any duplicates)
21236 for (0..fields_len) |field_idx| {20575 for (0..fields_len) |field_idx| {
21237 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20576 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
21238 // Don't pass a reason; first loop acts as a check that this is valid.20577 // Don't pass a reason; first loop acts as a check that this is valid.
21239 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);20578 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
21240 const gop = field_names.getOrPutAssumeCapacity(field_name);20579 if (wip_tag_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: {
21241 if (gop.found_existing) {20580 const msg = try sema.errMsg(src, "duplicate union field '{f}' at index '{d}", .{ field_name.fmt(ip), field_idx });
21242 // TODO: better source location20581 errdefer msg.destroy(gpa);
21243 return sema.fail(block, field_names_src, "duplicate union field {f}", .{field_name.fmt(ip)});20582 try sema.errNote(src, msg, "previous field at index '{d}'", .{prev_field_idx});
21244 }20583 break :msg msg;
20584 });
21245 }20585 }
21246 const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), wip_ty.index, type_name.name);20586
21247 break :tag .{ enum_tag_ty, false };20587 // Populate the enum tag type's *integer* tag type
20588 wip_tag_ty.setTagType(ip, int_tag_ty: {
20589 // Infer the int tag type from the field count
20590 const bits = Type.smallestUnsignedBits(fields_len -| 1);
20591 break :int_tag_ty (try pt.intType(.unsigned, bits)).toIntern();
20592 });
20593
20594 // Lastly, it needs a dummy namespace
20595 const enum_tag_type_namespace = try pt.createNamespace(.{
20596 .parent = block.namespace.toOptional(),
20597 .owner_type = wip_tag_ty.index,
20598 .file_scope = block.getFileScopeIndex(zcu),
20599 .generation = zcu.generation,
20600 });
20601 errdefer pt.destroyNamespace(enum_tag_type_namespace);
20602
20603 wip_ty.setTagType(ip, wip_tag_ty.index);
20604
20605 break :generated_tag wip_tag_ty.finish(ip, enum_tag_type_namespace);
21248 };20606 };
21249 errdefer if (!has_explicit_tag) ip.remove(pt.tid, enum_tag_ty); // remove generated tag type on error20607 // If we fail to create the union type, we must delete the generated enum tag type, since it
20608 // would hold a reference to the deleted union.
20609 errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty);
2125020610
21251 for (0..fields_len) |field_idx| {20611 for (0..fields_len) |field_idx| {
21252 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();20612 const field_ty = (try field_types_arr.elemValue(pt, field_idx)).toType();
...@@ -21279,12 +20639,12 @@ fn zirReifyUnion(...@@ -21279,12 +20639,12 @@ fn zirReifyUnion(
21279 break :msg msg;20639 break :msg msg;
21280 });20640 });
21281 },20641 },
21282 .@"packed" => if (!try sema.validatePackedType(field_ty)) {20642 .@"packed" => if (!field_ty.packable(zcu)) {
21283 return sema.failWithOwnedErrorMsg(block, msg: {20643 return sema.failWithOwnedErrorMsg(block, msg: {
21284 const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});20644 const msg = try sema.errMsg(field_types_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
21285 errdefer msg.destroy(gpa);20645 errdefer msg.destroy(gpa);
2128620646
21287 try sema.explainWhyTypeIsNotPacked(msg, field_types_src, field_ty);20647 try sema.explainWhyTypeIsNotPackable(msg, field_types_src, field_ty);
2128820648
21289 try sema.addDeclaredHereNote(msg, field_ty);20649 try sema.addDeclaredHereNote(msg, field_ty);
21290 break :msg msg;20650 break :msg msg;
...@@ -21303,8 +20663,24 @@ fn zirReifyUnion(...@@ -21303,8 +20663,24 @@ fn zirReifyUnion(
21303 }20663 }
21304 }20664 }
2130520665
21306 loaded_union.setTagType(ip, io, enum_tag_ty);20666 if (layout == .@"packed") {
21307 loaded_union.setStatus(ip, io, .have_field_types);20667 try type_resolution.resolvePackedUnionBackingInt(
20668 sema,
20669 block,
20670 .fromInterned(wip_ty.index),
20671 &loaded_union,
20672 true,
20673 );
20674 } else {
20675 try type_resolution.finishUnionLayout(
20676 sema,
20677 block,
20678 src,
20679 wip_ty.index,
20680 &loaded_union,
20681 explicit_tag_ty orelse .fromInterned(generated_tag_ty),
20682 );
20683 }
2130820684
21309 const new_namespace_index = try pt.createNamespace(.{20685 const new_namespace_index = try pt.createNamespace(.{
21310 .parent = block.namespace.toOptional(),20686 .parent = block.namespace.toOptional(),
...@@ -21313,17 +20689,16 @@ fn zirReifyUnion(...@@ -21313,17 +20689,16 @@ fn zirReifyUnion(
21313 .generation = zcu.generation,20689 .generation = zcu.generation,
21314 });20690 });
2131520691
21316 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
21317 codegen_type: {20692 codegen_type: {
21318 if (zcu.comp.config.use_llvm) break :codegen_type;20693 if (zcu.comp.config.use_llvm) break :codegen_type;
21319 if (block.ownerModule().strip) break :codegen_type;20694 if (block.ownerModule().strip) break :codegen_type;
21320 // This job depends on any resolve_type_fully jobs queued up before it.
21321 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);20695 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
21322 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });20696 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
21323 }20697 }
21324 try sema.declareDependency(.{ .interned = wip_ty.index });20698 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));
21325 try sema.addTypeReferenceEntry(src, wip_ty.index);20699 if (zcu.comp.debugIncremental()) {
21326 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);20700 try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
20701 }
21327 return .fromIntern(wip_ty.finish(ip, new_namespace_index));20702 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
21328}20703}
2132920704
...@@ -21436,86 +20811,84 @@ fn zirReifyEnum(...@@ -21436,86 +20811,84 @@ fn zirReifyEnum(
21436 }20811 }
2143720812
21438 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{20813 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
21439 .has_values = true,
21440 .tag_mode = if (nonexhaustive) .nonexhaustive else .explicit,
21441 .fields_len = @intCast(fields_len),20814 .fields_len = @intCast(fields_len),
20815 .explicit_int_tag_type = tag_ty.toIntern(),
20816 .nonexhaustive = nonexhaustive,
21442 .key = .{ .reified = .{20817 .key = .{ .reified = .{
21443 .zir_index = tracked_inst,20818 .zir_index = tracked_inst,
21444 .type_hash = hasher.final(),20819 .type_hash = hasher.final(),
21445 } },20820 } },
21446 }, false)) {20821 })) {
21447 .wip => |wip| wip,20822 .wip => |wip| wip,
21448 .existing => |ty| {20823 .existing => |ty| {
21449 try sema.declareDependency(.{ .interned = ty });20824 try sema.addTypeReferenceEntry(src, .fromInterned(ty));
21450 try sema.addTypeReferenceEntry(src, ty);
21451 return .fromIntern(ty);20825 return .fromIntern(ty);
21452 },20826 },
21453 };20827 };
21454 var done = false;20828 errdefer wip_ty.cancel(ip, pt.tid);
21455 errdefer if (!done) wip_ty.cancel(ip, pt.tid);
2145620829
21457 const type_name = try sema.createTypeName(20830 _ = try (try sema.createTypeName(
21458 block,20831 block,
21459 name_strategy,20832 name_strategy,
21460 "enum",20833 "enum",
21461 inst,20834 inst,
21462 wip_ty.index,20835 )).apply(&wip_ty, pt);
21463 );
21464 wip_ty.setName(ip, type_name.name, type_name.nav);
21465
21466 const new_namespace_index = try pt.createNamespace(.{
21467 .parent = block.namespace.toOptional(),
21468 .owner_type = wip_ty.index,
21469 .file_scope = block.getFileScopeIndex(zcu),
21470 .generation = zcu.generation,
21471 });
21472
21473 try sema.declareDependency(.{ .interned = wip_ty.index });
21474 try sema.addTypeReferenceEntry(src, wip_ty.index);
21475 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
21476 wip_ty.prepare(ip, new_namespace_index);
21477 wip_ty.setTagTy(ip, tag_ty.toIntern());
21478 done = true;
2147920836
21480 for (0..fields_len) |field_idx| {20837 for (0..fields_len) |field_idx| {
21481 const field_name_val = try field_names_arr.elemValue(pt, field_idx);20838 const field_name_val = try field_names_arr.elemValue(pt, field_idx);
21482 // Don't pass a reason; first loop acts as a check that this is valid.20839 // Don't pass a reason; first loop acts as a check that this is valid.
21483 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);20840 const field_name = try sema.sliceToIpString(block, field_names_src, field_name_val, undefined);
20841 if (wip_ty.nextField(ip, field_name, false)) |prev_field_idx| return sema.failWithOwnedErrorMsg(block, msg: {
20842 const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}' at index '{d}'", .{ field_name.fmt(ip), field_idx });
20843 errdefer msg.destroy(gpa);
20844 try sema.errNote(field_names_src, msg, "previous field at index '{d}'", .{prev_field_idx});
20845 break :msg msg;
20846 });
20847 }
2148420848
20849 const enum_obj = ip.loadEnumType(wip_ty.index);
20850 const field_value_map = enum_obj.field_value_map.unwrap().?;
20851 for (0..fields_len) |field_idx| {
21485 const field_val = try field_values_arr.elemValue(pt, field_idx);20852 const field_val = try field_values_arr.elemValue(pt, field_idx);
2148620853 const field_values = enum_obj.field_values.get(ip);
21487 if (wip_ty.nextField(ip, field_name, field_val.toIntern())) |conflict| {20854 field_values[field_idx] = field_val.toIntern();
21488 return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {20855 const adapter: InternPool.Index.Adapter = .{ .indexes = field_values[0..field_idx] };
21489 .name => msg: {20856 const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val.toIntern(), adapter);
21490 const msg = try sema.errMsg(field_names_src, "duplicate enum field '{f}'", .{field_name.fmt(ip)});20857 if (gop.found_existing) return sema.failWithOwnedErrorMsg(block, msg: {
21491 errdefer msg.destroy(gpa);20858 const field_names = enum_obj.field_names.get(ip);
21492 _ = conflict.prev_field_idx; // TODO: this note is incorrect20859 const this_field_name = field_names[field_idx];
21493 try sema.errNote(field_names_src, msg, "other field here", .{});20860 const prev_field_name = field_names[gop.index];
21494 break :msg msg;20861 const msg = try sema.errMsg(field_names_src, "duplicate enum tag value '{f}' in field '{f}'", .{
21495 },20862 field_val.fmtValueSema(pt, sema),
21496 .value => msg: {20863 this_field_name.fmt(ip),
21497 const msg = try sema.errMsg(field_values_src, "enum tag value {f} already taken", .{field_val.fmtValueSema(pt, sema)});
21498 errdefer msg.destroy(gpa);
21499 _ = conflict.prev_field_idx; // TODO: this note is incorrect
21500 try sema.errNote(field_values_src, msg, "other enum tag value here", .{});
21501 break :msg msg;
21502 },
21503 });20864 });
21504 }20865 errdefer msg.destroy(gpa);
20866 try sema.errNote(field_names_src, msg, "previous usage in field '{f}'", .{prev_field_name.fmt(ip)});
20867 break :msg msg;
20868 });
21505 }20869 }
2150620870
21507 if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {20871 if (nonexhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(zcu)) {
21508 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});20872 return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
21509 }20873 }
2151020874
20875 const new_namespace_index = try pt.createNamespace(.{
20876 .parent = block.namespace.toOptional(),
20877 .owner_type = wip_ty.index,
20878 .file_scope = block.getFileScopeIndex(zcu),
20879 .generation = zcu.generation,
20880 });
20881
21511 codegen_type: {20882 codegen_type: {
21512 if (zcu.comp.config.use_llvm) break :codegen_type;20883 if (zcu.comp.config.use_llvm) break :codegen_type;
21513 if (block.ownerModule().strip) break :codegen_type;20884 if (block.ownerModule().strip) break :codegen_type;
21514 // This job depends on any resolve_type_fully jobs queued up before it.
21515 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);20885 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
21516 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });20886 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
21517 }20887 }
21518 return Air.internedToRef(wip_ty.index);20888
20889 try sema.addTypeReferenceEntry(src, .fromInterned(wip_ty.index));
20890 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
20891 return .fromIntern(wip_ty.finish(ip, new_namespace_index));
21519}20892}
2152020893
21521fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {20894fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
...@@ -21573,7 +20946,8 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C...@@ -21573,7 +20946,8 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
21573 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);20946 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
2157420947
21575 try sema.requireRuntimeBlock(block, src, null);20948 try sema.requireRuntimeBlock(block, src, null);
21576 return block.addUnOp(.c_va_end, va_list_ref);20949 _ = try block.addUnOp(.c_va_end, va_list_ref);
20950 return .void_value;
21577}20951}
2157820952
21579fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {20953fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
...@@ -21683,8 +21057,20 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro...@@ -21683,8 +21057,20 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
21683 _ = try sema.checkIntType(block, operand_src, operand_scalar_ty);21057 _ = try sema.checkIntType(block, operand_src, operand_scalar_ty);
2168421058
21685 if (try sema.resolveValue(operand)) |operand_val| {21059 if (try sema.resolveValue(operand)) |operand_val| {
21686 const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, pt, .sema);21060 if (operand_val.isUndef(zcu)) return .fromValue(try pt.undefValue(dest_ty));
21687 return Air.internedToRef(result_val.toIntern());21061 if (dest_ty.zigTypeTag(zcu) != .vector) {
21062 return .fromValue(try pt.floatValue(dest_ty, operand_val.toFloat(f128, zcu)));
21063 }
21064 const dest_elems = try sema.arena.alloc(InternPool.Index, dest_ty.vectorLen(zcu));
21065 for (dest_elems, 0..) |*out_elem, elem_idx| {
21066 const orig_elem = try operand_val.elemValue(pt, elem_idx);
21067 const casted_elem = if (orig_elem.isUndef(zcu))
21068 try pt.undefValue(dest_scalar_ty)
21069 else
21070 try pt.floatValue(dest_scalar_ty, orig_elem.toFloat(f128, zcu));
21071 out_elem.* = casted_elem.toIntern();
21072 }
21073 return .fromValue(try pt.aggregateValue(dest_ty, dest_elems));
21688 } else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) {21074 } else if (dest_scalar_ty.zigTypeTag(zcu) == .comptime_float) {
21689 return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_float });21075 return sema.failWithNeededComptime(block, operand_src, .{ .simple = .casted_to_comptime_float });
21690 }21076 }
...@@ -21719,8 +21105,11 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -21719,8 +21105,11 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
21719 const ptr_ty = dest_ty.scalarType(zcu);21105 const ptr_ty = dest_ty.scalarType(zcu);
21720 try sema.checkPtrType(block, src, ptr_ty, true);21106 try sema.checkPtrType(block, src, ptr_ty, true);
2172121107
21722 const elem_ty = ptr_ty.elemType2(zcu);21108 const elem_ty = ptr_ty.nullablePtrElem(zcu);
21723 const ptr_align = try ptr_ty.ptrAlignmentSema(pt);21109
21110 // We'll need to validate the pointer alignment.
21111 try sema.ensureLayoutResolved(elem_ty);
21112 const ptr_align = ptr_ty.ptrAlignment(zcu);
2172421113
21725 if (ptr_ty.isSlice(zcu)) {21114 if (ptr_ty.isSlice(zcu)) {
21726 const msg = msg: {21115 const msg = msg: {
...@@ -21746,18 +21135,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -21746,18 +21135,9 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
21746 }21135 }
21747 return Air.internedToRef((try pt.aggregateValue(dest_ty, new_elems)).toIntern());21136 return Air.internedToRef((try pt.aggregateValue(dest_ty, new_elems)).toIntern());
21748 }21137 }
21749 if (try ptr_ty.comptimeOnlySema(pt)) {
21750 return sema.failWithOwnedErrorMsg(block, msg: {
21751 const msg = try sema.errMsg(src, "pointer to comptime-only type '{f}' must be comptime-known, but operand is runtime-known", .{ptr_ty.fmt(pt)});
21752 errdefer msg.destroy(sema.gpa);
21753
21754 try sema.explainWhyTypeIsComptime(msg, src, ptr_ty);
21755 break :msg msg;
21756 });
21757 }
21758 try sema.requireRuntimeBlock(block, src, operand_src);21138 try sema.requireRuntimeBlock(block, src, operand_src);
21759 try sema.checkLogicalPtrOperation(block, src, ptr_ty);21139 try sema.checkLogicalPtrOperation(block, src, ptr_ty);
21760 if (block.wantSafety() and (try elem_ty.hasRuntimeBitsSema(pt) or elem_ty.zigTypeTag(zcu) == .@"fn")) {21140 if (block.wantSafety()) {
21761 if (!ptr_ty.isAllowzeroPtr(zcu)) {21141 if (!ptr_ty.isAllowzeroPtr(zcu)) {
21762 const is_non_zero = if (is_vector) all_non_zero: {21142 const is_non_zero = if (is_vector) all_non_zero: {
21763 const zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());21143 const zero_usize = Air.internedToRef((try sema.splat(operand_ty, .zero_usize)).toIntern());
...@@ -21804,7 +21184,7 @@ fn ptrFromIntVal(...@@ -21804,7 +21184,7 @@ fn ptrFromIntVal(
21804 }21184 }
21805 return sema.failWithUseOfUndef(block, operand_src, vec_idx);21185 return sema.failWithUseOfUndef(block, operand_src, vec_idx);
21806 }21186 }
21807 const addr = try operand_val.toUnsignedIntSema(pt);21187 const addr = operand_val.toUnsignedInt(zcu);
21808 if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)21188 if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)
21809 return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)});21189 return sema.fail(block, operand_src, "pointer type '{f}' does not allow address zero", .{ptr_ty.fmt(pt)});
21810 if (addr != 0 and ptr_align != .none) {21190 if (addr != 0 and ptr_align != .none) {
...@@ -22043,8 +21423,8 @@ fn ptrCastFull(...@@ -22043,8 +21423,8 @@ fn ptrCastFull(
22043 const src_info = operand_ty.ptrInfo(zcu);21423 const src_info = operand_ty.ptrInfo(zcu);
22044 const dest_info = dest_ty.ptrInfo(zcu);21424 const dest_info = dest_ty.ptrInfo(zcu);
2204521425
22046 try Type.fromInterned(src_info.child).resolveLayout(pt);21426 try sema.ensureLayoutResolved(.fromInterned(src_info.child));
22047 try Type.fromInterned(dest_info.child).resolveLayout(pt);21427 try sema.ensureLayoutResolved(.fromInterned(dest_info.child));
2204821428
22049 const DestSliceLen = union(enum) {21429 const DestSliceLen = union(enum) {
22050 undef,21430 undef,
...@@ -22079,9 +21459,9 @@ fn ptrCastFull(...@@ -22079,9 +21459,9 @@ fn ptrCastFull(
22079 .pointer => operand_val,21459 .pointer => operand_val,
22080 else => unreachable,21460 else => unreachable,
22081 };21461 };
22082 const slice_len_resolved = try sema.resolveLazyValue(.fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern())));21462 const slice_len: Value = .fromInterned(zcu.intern_pool.sliceLen(slice_val.toIntern()));
22083 if (slice_len_resolved.isUndef(zcu)) break :len .undef;21463 if (slice_len.isUndef(zcu)) break :len .undef;
22084 break :src .{ .fromInterned(src_info.child), slice_len_resolved.toUnsignedInt(zcu) };21464 break :src .{ .fromInterned(src_info.child), slice_len.toUnsignedInt(zcu) };
22085 },21465 },
22086 .many, .c => {21466 .many, .c => {
22087 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});21467 return sema.fail(block, src, "cannot infer length of slice from {s}", .{pointerSizeString(src_info.flags.size)});
...@@ -22395,7 +21775,7 @@ fn ptrCastFull(...@@ -22395,7 +21775,7 @@ fn ptrCastFull(
22395 };21775 };
2239621776
22397 if (dest_align.compare(.gt, src_align)) {21777 if (dest_align.compare(.gt, src_align)) {
22398 if (try ptr_val.getUnsignedIntSema(pt)) |addr| {21778 if (ptr_val.getUnsignedInt(zcu)) |addr| {
22399 const masked_addr = if (Type.fromInterned(dest_info.child).fnPtrMaskOrNull(zcu)) |mask|21779 const masked_addr = if (Type.fromInterned(dest_info.child).fnPtrMaskOrNull(zcu)) |mask|
22400 addr & mask21780 addr & mask
22401 else21781 else
...@@ -22464,7 +21844,7 @@ fn ptrCastFull(...@@ -22464,7 +21844,7 @@ fn ptrCastFull(
22464 // Now, do an addrspace cast if necessary!21844 // Now, do an addrspace cast if necessary!
22465 if (!flags.addrspace_cast) break :ptr pre_addrspace_cast;21845 if (!flags.addrspace_cast) break :ptr pre_addrspace_cast;
2246621846
22467 const intermediate_ptr_ty = try pt.ptrTypeSema(info: {21847 const intermediate_ptr_ty = try pt.ptrType(info: {
22468 var info = src_info;21848 var info = src_info;
22469 info.flags.address_space = dest_info.flags.address_space;21849 info.flags.address_space = dest_info.flags.address_space;
22470 break :info info;21850 break :info info;
...@@ -22638,7 +22018,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst...@@ -22638,7 +22018,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
22638 if (flags.volatile_cast) ptr_info.flags.is_volatile = false;22018 if (flags.volatile_cast) ptr_info.flags.is_volatile = false;
2263922019
22640 const dest_ty = blk: {22020 const dest_ty = blk: {
22641 const dest_ty = try pt.ptrTypeSema(ptr_info);22021 const dest_ty = try pt.ptrType(ptr_info);
22642 if (operand_ty.zigTypeTag(zcu) == .optional) {22022 if (operand_ty.zigTypeTag(zcu) == .optional) {
22643 break :blk try pt.optionalType(dest_ty.toIntern());22023 break :blk try pt.optionalType(dest_ty.toIntern());
22644 }22024 }
...@@ -22678,48 +22058,24 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -22678,48 +22058,24 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
22678 return sema.coerce(block, dest_ty, operand, operand_src);22058 return sema.coerce(block, dest_ty, operand, operand_src);
22679 }22059 }
2268022060
22681 const dest_info = dest_scalar_ty.intInfo(zcu);22061 if (try dest_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
2268222062
22683 if (try sema.typeHasOnePossibleValue(dest_ty)) |val| {22063 const dest_info = dest_scalar_ty.intInfo(zcu);
22684 return Air.internedToRef(val.toIntern());
22685 }
2268622064
22687 if (operand_scalar_ty.zigTypeTag(zcu) != .comptime_int) {22065 if (operand_scalar_ty.zigTypeTag(zcu) != .comptime_int) {
22688 const operand_info = operand_ty.intInfo(zcu);22066 const operand_info = operand_ty.intInfo(zcu);
22689 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
22690 return Air.internedToRef(val.toIntern());
22691 }
2269222067
22693 if (operand_info.signedness != dest_info.signedness) {22068 if (operand_info.signedness != dest_info.signedness) {
22694 return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{22069 return sema.fail(block, operand_src, "expected {s} integer type, found '{f}'", .{
22695 @tagName(dest_info.signedness), operand_ty.fmt(pt),22070 @tagName(dest_info.signedness), operand_ty.fmt(pt),
22696 });22071 });
22697 }22072 }
22698 switch (std.math.order(dest_info.bits, operand_info.bits)) {22073 if (dest_info.bits >= operand_info.bits) {
22699 .gt => {22074 return sema.coerce(block, dest_ty, operand, operand_src);
22700 const msg = msg: {
22701 const msg = try sema.errMsg(
22702 src,
22703 "destination type '{f}' has more bits than source type '{f}'",
22704 .{ dest_ty.fmt(pt), operand_ty.fmt(pt) },
22705 );
22706 errdefer msg.destroy(sema.gpa);
22707 try sema.errNote(src, msg, "destination type has {d} bits", .{
22708 dest_info.bits,
22709 });
22710 try sema.errNote(operand_src, msg, "operand type has {d} bits", .{
22711 operand_info.bits,
22712 });
22713 break :msg msg;
22714 };
22715 return sema.failWithOwnedErrorMsg(block, msg);
22716 },
22717 .eq => return operand,
22718 .lt => {},
22719 }22075 }
22720 }22076 }
2272122077
22722 if (try sema.resolveValueResolveLazy(operand)) |val| {22078 if (try sema.resolveValue(operand)) |val| {
22723 const result_val = try arith.truncate(sema, val, operand_ty, dest_ty, dest_info.signedness, dest_info.bits);22079 const result_val = try arith.truncate(sema, val, operand_ty, dest_ty, dest_info.signedness, dest_info.bits);
22724 return Air.internedToRef(result_val.toIntern());22080 return Air.internedToRef(result_val.toIntern());
22725 }22081 }
...@@ -22745,10 +22101,6 @@ fn zirBitCount(...@@ -22745,10 +22101,6 @@ fn zirBitCount(
22745 _ = try sema.checkIntOrVector(block, operand, operand_src);22101 _ = try sema.checkIntOrVector(block, operand, operand_src);
22746 const bits = operand_ty.intInfo(zcu).bits;22102 const bits = operand_ty.intInfo(zcu).bits;
2274722103
22748 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
22749 return Air.internedToRef(val.toIntern());
22750 }
22751
22752 const result_scalar_ty = try pt.smallestUnsignedInt(bits);22104 const result_scalar_ty = try pt.smallestUnsignedInt(bits);
22753 switch (operand_ty.zigTypeTag(zcu)) {22105 switch (operand_ty.zigTypeTag(zcu)) {
22754 .vector => {22106 .vector => {
...@@ -22774,7 +22126,7 @@ fn zirBitCount(...@@ -22774,7 +22126,7 @@ fn zirBitCount(
22774 }22126 }
22775 },22127 },
22776 .int => {22128 .int => {
22777 if (try sema.resolveValueResolveLazy(operand)) |val| {22129 if (try sema.resolveValue(operand)) |val| {
22778 if (val.isUndef(zcu)) return pt.undefRef(result_scalar_ty);22130 if (val.isUndef(zcu)) return pt.undefRef(result_scalar_ty);
22779 return pt.intRef(result_scalar_ty, comptimeOp(val, operand_ty, zcu));22131 return pt.intRef(result_scalar_ty, comptimeOp(val, operand_ty, zcu));
22780 } else {22132 } else {
...@@ -22803,9 +22155,6 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai...@@ -22803,9 +22155,6 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
22803 .{ scalar_ty.fmt(pt), bits },22155 .{ scalar_ty.fmt(pt), bits },
22804 );22156 );
22805 }22157 }
22806 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
22807 return .fromValue(val);
22808 }
22809 if (try sema.resolveValue(operand)) |operand_val| {22158 if (try sema.resolveValue(operand)) |operand_val| {
22810 return .fromValue(try arith.byteSwap(sema, operand_val, operand_ty));22159 return .fromValue(try arith.byteSwap(sema, operand_val, operand_ty));
22811 }22160 }
...@@ -22819,9 +22168,6 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -22819,9 +22168,6 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
22819 const operand_ty = sema.typeOf(operand);22168 const operand_ty = sema.typeOf(operand);
22820 _ = try sema.checkIntOrVector(block, operand, operand_src);22169 _ = try sema.checkIntOrVector(block, operand, operand_src);
2282122170
22822 if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
22823 return .fromValue(val);
22824 }
22825 if (try sema.resolveValue(operand)) |operand_val| {22171 if (try sema.resolveValue(operand)) |operand_val| {
22826 return .fromValue(try arith.bitReverse(sema, operand_val, operand_ty));22172 return .fromValue(try arith.bitReverse(sema, operand_val, operand_ty));
22827 }22173 }
...@@ -22849,10 +22195,11 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6...@@ -22849,10 +22195,11 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
22849 const ty = try sema.resolveType(block, ty_src, extra.lhs);22195 const ty = try sema.resolveType(block, ty_src, extra.lhs);
22850 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name });22196 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.rhs, .{ .simple = .field_name });
2285122197
22198 try sema.ensureLayoutResolved(ty);
22199
22852 const pt = sema.pt;22200 const pt = sema.pt;
22853 const zcu = pt.zcu;22201 const zcu = pt.zcu;
22854 const ip = &zcu.intern_pool;22202 const ip = &zcu.intern_pool;
22855 try ty.resolveLayout(pt);
22856 switch (ty.zigTypeTag(zcu)) {22203 switch (ty.zigTypeTag(zcu)) {
22857 .@"struct" => {},22204 .@"struct" => {},
22858 else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}),22205 else => return sema.fail(block, ty_src, "expected struct type, found '{f}'", .{ty.fmt(pt)}),
...@@ -23126,7 +22473,7 @@ fn checkAtomicPtrOperand(...@@ -23126,7 +22473,7 @@ fn checkAtomicPtrOperand(
23126 const ptr_data = switch (ptr_ty.zigTypeTag(zcu)) {22473 const ptr_data = switch (ptr_ty.zigTypeTag(zcu)) {
23127 .pointer => ptr_ty.ptrInfo(zcu),22474 .pointer => ptr_ty.ptrInfo(zcu),
23128 else => {22475 else => {
23129 const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data);22476 const wanted_ptr_ty = try pt.ptrType(wanted_ptr_data);
23130 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);22477 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
23131 unreachable;22478 unreachable;
23132 },22479 },
...@@ -23136,7 +22483,7 @@ fn checkAtomicPtrOperand(...@@ -23136,7 +22483,7 @@ fn checkAtomicPtrOperand(
23136 wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;22483 wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;
23137 wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile;22484 wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile;
2313822485
23139 const wanted_ptr_ty = try pt.ptrTypeSema(wanted_ptr_data);22486 const wanted_ptr_ty = try pt.ptrType(wanted_ptr_data);
23140 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);22487 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
2314122488
23142 return casted_ptr;22489 return casted_ptr;
...@@ -23470,11 +22817,8 @@ fn zirCmpxchg(...@@ -23470,11 +22817,8 @@ fn zirCmpxchg(
23470 const result_ty = try pt.optionalType(elem_ty.toIntern());22817 const result_ty = try pt.optionalType(elem_ty.toIntern());
2347122818
23472 // special case zero bit types22819 // special case zero bit types
23473 if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {22820 if (try elem_ty.onePossibleValue(pt) != null) {
23474 return Air.internedToRef((try pt.intern(.{ .opt = .{22821 return .fromValue(try pt.nullValue(result_ty));
23475 .ty = result_ty.toIntern(),
23476 .val = .none,
23477 } })));
23478 }22822 }
2347922823
23480 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {22824 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
...@@ -23537,11 +22881,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I...@@ -23537,11 +22881,7 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
2353722881
23538 const len = try sema.usizeCast(block, src, dest_ty.arrayLen(zcu));22882 const len = try sema.usizeCast(block, src, dest_ty.arrayLen(zcu));
2353922883
23540 if (try sema.typeHasOnePossibleValue(dest_ty)) |val| {22884 // If the length is 0, the result is comptime-known even if the operand isn't.
23541 return Air.internedToRef(val.toIntern());
23542 }
23543
23544 // We also need this case because `[0:s]T` is not OPV.
23545 if (len == 0) return .fromValue(try pt.aggregateValue(dest_ty, &.{}));22885 if (len == 0) return .fromValue(try pt.aggregateValue(dest_ty, &.{}));
2354622886
23547 const maybe_sentinel = dest_ty.sentinel(zcu);22887 const maybe_sentinel = dest_ty.sentinel(zcu);
...@@ -23733,7 +23073,7 @@ fn analyzeShuffle(...@@ -23733,7 +23073,7 @@ fn analyzeShuffle(
23733 continue;23073 continue;
23734 }23074 }
23735 // Safe because mask elements are `i32` and we already checked for undef:23075 // Safe because mask elements are `i32` and we already checked for undef:
23736 const raw = (try sema.resolveLazyValue(mask_val)).toSignedInt(zcu);23076 const raw = mask_val.toSignedInt(zcu);
23737 if (raw >= 0) {23077 if (raw >= 0) {
23738 const idx: u32 = @intCast(raw);23078 const idx: u32 = @intCast(raw);
23739 a_used = true;23079 a_used = true;
...@@ -23938,6 +23278,8 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -23938,6 +23278,8 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
23938 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);23278 const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, true);
23939 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order });23279 const order = try sema.resolveAtomicOrder(block, order_src, extra.ordering, .{ .simple = .atomic_order });
2394023280
23281 try sema.ensureLayoutResolved(elem_ty);
23282
23941 switch (order) {23283 switch (order) {
23942 .release, .acq_rel => {23284 .release, .acq_rel => {
23943 return sema.fail(23285 return sema.fail(
...@@ -23950,9 +23292,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!...@@ -23950,9 +23292,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
23950 else => {},23292 else => {},
23951 }23293 }
2395223294
23953 if (try sema.typeHasOnePossibleValue(elem_ty)) |val| {23295 if (try elem_ty.onePossibleValue(sema.pt)) |opv| return .fromValue(opv);
23954 return Air.internedToRef(val.toIntern());
23955 }
2395623296
23957 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {23297 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
23958 if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| {23298 if (try sema.pointerDeref(block, ptr_src, ptr_val, sema.typeOf(ptr))) |elem_val| {
...@@ -24009,9 +23349,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A...@@ -24009,9 +23349,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
24009 }23349 }
2401023350
24011 // special case zero bit types23351 // special case zero bit types
24012 if (try sema.typeHasOnePossibleValue(elem_ty)) |val| {23352 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
24013 return Air.internedToRef(val.toIntern());
24014 }
2401523353
24016 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {23354 const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
24017 const maybe_operand_val = try sema.resolveValue(operand);23355 const maybe_operand_val = try sema.resolveValue(operand);
...@@ -24260,11 +23598,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24260,11 +23598,11 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24260 return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)});23598 return sema.fail(block, inst_src, "expected single pointer type, found '{f}'", .{parent_ptr_ty.fmt(pt)});
24261 }23599 }
24262 const parent_ty: Type = .fromInterned(parent_ptr_info.child);23600 const parent_ty: Type = .fromInterned(parent_ptr_info.child);
23601 try sema.ensureLayoutResolved(parent_ty);
24263 switch (parent_ty.zigTypeTag(zcu)) {23602 switch (parent_ty.zigTypeTag(zcu)) {
24264 .@"struct", .@"union" => {},23603 .@"struct", .@"union" => {},
24265 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}),23604 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{f}'", .{parent_ptr_ty.fmt(pt)}),
24266 }23605 }
24267 try parent_ty.resolveLayout(pt);
2426823606
24269 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name });23607 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{ .simple = .field_name });
24270 const field_index = switch (parent_ty.zigTypeTag(zcu)) {23608 const field_index = switch (parent_ty.zigTypeTag(zcu)) {
...@@ -24293,7 +23631,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24293,7 +23631,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24293 var actual_parent_ptr_info: InternPool.Key.PtrType = .{23631 var actual_parent_ptr_info: InternPool.Key.PtrType = .{
24294 .child = parent_ty.toIntern(),23632 .child = parent_ty.toIntern(),
24295 .flags = .{23633 .flags = .{
24296 .alignment = try parent_ptr_ty.ptrAlignmentSema(pt),23634 .alignment = parent_ptr_ty.ptrAlignment(zcu),
24297 .is_const = field_ptr_info.flags.is_const,23635 .is_const = field_ptr_info.flags.is_const,
24298 .is_volatile = field_ptr_info.flags.is_volatile,23636 .is_volatile = field_ptr_info.flags.is_volatile,
24299 .is_allowzero = field_ptr_info.flags.is_allowzero,23637 .is_allowzero = field_ptr_info.flags.is_allowzero,
...@@ -24305,7 +23643,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24305,7 +23643,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24305 var actual_field_ptr_info: InternPool.Key.PtrType = .{23643 var actual_field_ptr_info: InternPool.Key.PtrType = .{
24306 .child = field_ty.toIntern(),23644 .child = field_ty.toIntern(),
24307 .flags = .{23645 .flags = .{
24308 .alignment = try field_ptr_ty.ptrAlignmentSema(pt),23646 .alignment = field_ptr_ty.ptrAlignment(zcu),
24309 .is_const = field_ptr_info.flags.is_const,23647 .is_const = field_ptr_info.flags.is_const,
24310 .is_volatile = field_ptr_info.flags.is_volatile,23648 .is_volatile = field_ptr_info.flags.is_volatile,
24311 .is_allowzero = field_ptr_info.flags.is_allowzero,23649 .is_allowzero = field_ptr_info.flags.is_allowzero,
...@@ -24315,23 +23653,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24315,23 +23653,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24315 };23653 };
24316 switch (parent_ty.containerLayout(zcu)) {23654 switch (parent_ty.containerLayout(zcu)) {
24317 .auto => {23655 .auto => {
24318 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(23656 actual_parent_ptr_info.flags.alignment = parent_ty.resolvedFieldAlignment(field_index, zcu);
24319 if (zcu.typeToStruct(parent_ty)) |struct_obj|
24320 try field_ty.structFieldAlignmentSema(
24321 struct_obj.fieldAlign(ip, field_index),
24322 struct_obj.layout,
24323 pt,
24324 )
24325 else if (zcu.typeToUnion(parent_ty)) |union_obj|
24326 try field_ty.unionFieldAlignmentSema(
24327 union_obj.fieldAlign(ip, field_index),
24328 union_obj.flagsUnordered(ip).layout,
24329 pt,
24330 )
24331 else
24332 actual_field_ptr_info.flags.alignment,
24333 );
24334
24335 actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };23657 actual_parent_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
24336 actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };23658 actual_field_ptr_info.packed_offset = .{ .bit_offset = 0, .host_size = 0 };
24337 },23659 },
...@@ -24357,9 +23679,9 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins...@@ -24357,9 +23679,9 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
24357 },23679 },
24358 }23680 }
2435923681
24360 const actual_field_ptr_ty = try pt.ptrTypeSema(actual_field_ptr_info);23682 const actual_field_ptr_ty = try pt.ptrType(actual_field_ptr_info);
24361 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);23683 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);
24362 const actual_parent_ptr_ty = try pt.ptrTypeSema(actual_parent_ptr_info);23684 const actual_parent_ptr_ty = try pt.ptrType(actual_parent_ptr_info);
2436323685
24364 const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {23686 const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {
24365 switch (parent_ty.zigTypeTag(zcu)) {23687 switch (parent_ty.zigTypeTag(zcu)) {
...@@ -24590,7 +23912,7 @@ fn analyzeMinMax(...@@ -24590,7 +23912,7 @@ fn analyzeMinMax(
24590 const operand_scalar_ty = sema.typeOf(operand).scalarType(zcu);23912 const operand_scalar_ty = sema.typeOf(operand).scalarType(zcu);
24591 const want_strat: TypeStrat = switch (operand_scalar_ty.zigTypeTag(zcu)) {23913 const want_strat: TypeStrat = switch (operand_scalar_ty.zigTypeTag(zcu)) {
24592 .comptime_int => s: {23914 .comptime_int => s: {
24593 const val = (try sema.resolveValueResolveLazy(operand)).?;23915 const val = (try sema.resolveValue(operand)).?;
24594 if (val.isUndef(zcu)) break :s .none;23916 if (val.isUndef(zcu)) break :s .none;
24595 break :s .{ .int = .{23917 break :s .{ .int = .{
24596 .all_comptime_int = true,23918 .all_comptime_int = true,
...@@ -24609,7 +23931,7 @@ fn analyzeMinMax(...@@ -24609,7 +23931,7 @@ fn analyzeMinMax(
24609 // (replaced with just the simple calls to `Type.minInt`/`Type.maxInt`) so that we only23931 // (replaced with just the simple calls to `Type.minInt`/`Type.maxInt`) so that we only
24610 // use the input *types* to determine the result type.23932 // use the input *types* to determine the result type.
24611 const min: Value, const max: Value = bounds: {23933 const min: Value, const max: Value = bounds: {
24612 if (try sema.resolveValueResolveLazy(operand)) |operand_val| {23934 if (try sema.resolveValue(operand)) |operand_val| {
24613 if (vector_len) |len| {23935 if (vector_len) |len| {
24614 var min = try operand_val.elemValue(pt, 0);23936 var min = try operand_val.elemValue(pt, 0);
24615 var max = min;23937 var max = min;
...@@ -24696,6 +24018,9 @@ fn analyzeMinMax(...@@ -24696,6 +24018,9 @@ fn analyzeMinMax(
24696 .child = intermediate_scalar_ty.toIntern(),24018 .child = intermediate_scalar_ty.toIntern(),
24697 }) else intermediate_scalar_ty;24019 }) else intermediate_scalar_ty;
2469824020
24021 // We might have refined all the way down to an OPV type---check now.
24022 if (try result_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
24023
24699 // This value, if not `null`, will have type `intermediate_ty`.24024 // This value, if not `null`, will have type `intermediate_ty`.
24700 const comptime_part: ?Value = ct: {24025 const comptime_part: ?Value = ct: {
24701 // Contains the comptime-known scalar result values.24026 // Contains the comptime-known scalar result values.
...@@ -24712,7 +24037,7 @@ fn analyzeMinMax(...@@ -24712,7 +24037,7 @@ fn analyzeMinMax(
24712 var opt_runtime_src: ?LazySrcLoc = null;24037 var opt_runtime_src: ?LazySrcLoc = null;
2471324038
24714 for (operands, operand_srcs) |operand, operand_src| {24039 for (operands, operand_srcs) |operand, operand_src| {
24715 const operand_val = try sema.resolveValueResolveLazy(operand) orelse {24040 const operand_val = try sema.resolveValue(operand) orelse {
24716 if (opt_runtime_src == null) opt_runtime_src = operand_src;24041 if (opt_runtime_src == null) opt_runtime_src = operand_src;
24717 continue;24042 continue;
24718 };24043 };
...@@ -24819,7 +24144,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A...@@ -24819,7 +24144,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A
24819 // Already an array pointer.24144 // Already an array pointer.
24820 return ptr;24145 return ptr;
24821 }24146 }
24822 const new_ty = try pt.ptrTypeSema(.{24147 const new_ty = try pt.ptrType(.{
24823 .child = (try pt.arrayType(.{24148 .child = (try pt.arrayType(.{
24824 .len = len,24149 .len = len,
24825 .sentinel = info.sentinel,24150 .sentinel = info.sentinel,
...@@ -24883,6 +24208,9 @@ fn zirMemcpy(...@@ -24883,6 +24208,9 @@ fn zirMemcpy(
24883 const dest_elem_ty = dest_ty.indexablePtrElem(zcu);24208 const dest_elem_ty = dest_ty.indexablePtrElem(zcu);
24884 const src_elem_ty = src_ty.indexablePtrElem(zcu);24209 const src_elem_ty = src_ty.indexablePtrElem(zcu);
2488524210
24211 try sema.ensureLayoutResolved(dest_elem_ty);
24212 try sema.ensureLayoutResolved(src_elem_ty);
24213
24886 const imc = try sema.coerceInMemoryAllowed(24214 const imc = try sema.coerceInMemoryAllowed(
24887 block,24215 block,
24888 dest_elem_ty,24216 dest_elem_ty,
...@@ -24946,13 +24274,13 @@ fn zirMemcpy(...@@ -24946,13 +24274,13 @@ fn zirMemcpy(
24946 }24274 }
2494724275
24948 zero_bit: {24276 zero_bit: {
24949 const src_comptime = try src_elem_ty.comptimeOnlySema(pt);24277 const src_comptime = src_elem_ty.comptimeOnly(zcu);
24950 const dest_comptime = try dest_elem_ty.comptimeOnlySema(pt);24278 const dest_comptime = dest_elem_ty.comptimeOnly(zcu);
24951 assert(src_comptime == dest_comptime); // IMC24279 assert(src_comptime == dest_comptime); // IMC
24952 if (src_comptime) break :zero_bit;24280 if (src_comptime) break :zero_bit;
2495324281
24954 const src_has_bits = try src_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt);24282 const src_has_bits = src_elem_ty.hasRuntimeBits(zcu);
24955 const dest_has_bits = try dest_elem_ty.hasRuntimeBitsIgnoreComptimeSema(pt);24283 const dest_has_bits = dest_elem_ty.hasRuntimeBits(zcu);
24956 assert(src_has_bits == dest_has_bits); // IMC24284 assert(src_has_bits == dest_has_bits); // IMC
24957 if (src_has_bits) break :zero_bit;24285 if (src_has_bits) break :zero_bit;
2495824286
...@@ -24968,7 +24296,7 @@ fn zirMemcpy(...@@ -24968,7 +24296,7 @@ fn zirMemcpy(
24968 const raw_dest_ptr = if (dest_ty.isSlice(zcu)) dest_ptr_val.slicePtr(zcu) else dest_ptr_val;24296 const raw_dest_ptr = if (dest_ty.isSlice(zcu)) dest_ptr_val.slicePtr(zcu) else dest_ptr_val;
24969 const raw_src_ptr = if (src_ty.isSlice(zcu)) src_ptr_val.slicePtr(zcu) else src_ptr_val;24297 const raw_src_ptr = if (src_ty.isSlice(zcu)) src_ptr_val.slicePtr(zcu) else src_ptr_val;
2497024298
24971 const len_u64 = try len_val.?.toUnsignedIntSema(pt);24299 const len_u64 = len_val.?.toUnsignedInt(zcu);
2497224300
24973 if (check_aliasing) {24301 if (check_aliasing) {
24974 if (Value.doPointersOverlap(24302 if (Value.doPointersOverlap(
...@@ -25018,7 +24346,7 @@ fn zirMemcpy(...@@ -25018,7 +24346,7 @@ fn zirMemcpy(
25018 var new_dest_ptr = dest_ptr;24346 var new_dest_ptr = dest_ptr;
25019 var new_src_ptr = src_ptr;24347 var new_src_ptr = src_ptr;
25020 if (len_val) |val| {24348 if (len_val) |val| {
25021 const len = try val.toUnsignedIntSema(pt);24349 const len = val.toUnsignedInt(zcu);
25022 if (len == 0) {24350 if (len == 0) {
25023 // This AIR instruction guarantees length > 0 if it is comptime-known.24351 // This AIR instruction guarantees length > 0 if it is comptime-known.
25024 return;24352 return;
...@@ -25067,7 +24395,7 @@ fn zirMemcpy(...@@ -25067,7 +24395,7 @@ fn zirMemcpy(
25067 assert(dest_manyptr_ty_key.flags.size == .one);24395 assert(dest_manyptr_ty_key.flags.size == .one);
25068 dest_manyptr_ty_key.child = dest_elem_ty.toIntern();24396 dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
25069 dest_manyptr_ty_key.flags.size = .many;24397 dest_manyptr_ty_key.flags.size = .many;
25070 break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(dest_manyptr_ty_key), new_dest_ptr, dest_src);24398 break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
25071 } else new_dest_ptr;24399 } else new_dest_ptr;
2507224400
25073 const new_src_ptr_ty = sema.typeOf(new_src_ptr);24401 const new_src_ptr_ty = sema.typeOf(new_src_ptr);
...@@ -25078,7 +24406,7 @@ fn zirMemcpy(...@@ -25078,7 +24406,7 @@ fn zirMemcpy(
25078 assert(src_manyptr_ty_key.flags.size == .one);24406 assert(src_manyptr_ty_key.flags.size == .one);
25079 src_manyptr_ty_key.child = src_elem_ty.toIntern();24407 src_manyptr_ty_key.child = src_elem_ty.toIntern();
25080 src_manyptr_ty_key.flags.size = .many;24408 src_manyptr_ty_key.flags.size = .many;
25081 break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(src_manyptr_ty_key), new_src_ptr, src_src);24409 break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
25082 } else new_src_ptr;24410 } else new_src_ptr;
2508324411
25084 // ok1: dest >= src + len24412 // ok1: dest >= src + len
...@@ -25148,7 +24476,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void...@@ -25148,7 +24476,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
25148 const runtime_src = rs: {24476 const runtime_src = rs: {
25149 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), dest_src);24477 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), dest_src);
25150 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src;24478 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src;
25151 const len_u64 = try len_val.toUnsignedIntSema(pt);24479 const len_u64 = len_val.toUnsignedInt(zcu);
25152 const len = try sema.usizeCast(block, dest_src, len_u64);24480 const len = try sema.usizeCast(block, dest_src, len_u64);
25153 if (len == 0) {24481 if (len == 0) {
25154 // This AIR instruction guarantees length > 0 if it is comptime-known.24482 // This AIR instruction guarantees length > 0 if it is comptime-known.
...@@ -25436,7 +24764,7 @@ fn resolvePrefetchOptions(...@@ -25436,7 +24764,7 @@ fn resolvePrefetchOptions(
2543624764
25437 return std.builtin.PrefetchOptions{24765 return std.builtin.PrefetchOptions{
25438 .rw = try sema.interpretBuiltinType(block, rw_src, rw_val, std.builtin.PrefetchOptions.Rw),24766 .rw = try sema.interpretBuiltinType(block, rw_src, rw_val, std.builtin.PrefetchOptions.Rw),
25439 .locality = @intCast(try locality_val.toUnsignedIntSema(pt)),24767 .locality = @intCast(locality_val.toUnsignedInt(zcu)),
25440 .cache = try sema.interpretBuiltinType(block, cache_src, cache_val, std.builtin.PrefetchOptions.Cache),24768 .cache = try sema.interpretBuiltinType(block, cache_src, cache_val, std.builtin.PrefetchOptions.Cache),
25441 };24769 };
25442}24770}
...@@ -25626,7 +24954,7 @@ fn zirBuiltinExtern(...@@ -25626,7 +24954,7 @@ fn zirBuiltinExtern(
25626 // So, for now, just use our containing `declaration`.24954 // So, for now, just use our containing `declaration`.
25627 .zir_index = switch (sema.owner.unwrap()) {24955 .zir_index = switch (sema.owner.unwrap()) {
25628 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,24956 .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
25629 .type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,24957 .type_layout, .type_inits => |owner_ty| Type.fromInterned(owner_ty).typeDeclInstAllowGeneratedTag(zcu).?,
25630 .memoized_state => unreachable,24958 .memoized_state => unreachable,
25631 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,24959 .nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
25632 .func => |func| zir_index: {24960 .func => |func| zir_index: {
...@@ -25839,7 +25167,8 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:...@@ -25839,7 +25167,8 @@ fn requireRuntimeBlock(sema: *Sema, block: *Block, src: LazySrcLoc, runtime_src:
25839 }25167 }
25840}25168}
2584125169
25842/// Emit a compile error if type cannot be used for a runtime variable.25170/// Emit a compile error if `var_ty` cannot be used for a runtime variable.
25171/// Asserts that the layout of `var_ty` is already resolved.
25843pub fn validateVarType(25172pub fn validateVarType(
25844 sema: *Sema,25173 sema: *Sema,
25845 block: *Block,25174 block: *Block,
...@@ -25849,6 +25178,7 @@ pub fn validateVarType(...@@ -25849,6 +25178,7 @@ pub fn validateVarType(
25849) CompileError!void {25178) CompileError!void {
25850 const pt = sema.pt;25179 const pt = sema.pt;
25851 const zcu = pt.zcu;25180 const zcu = pt.zcu;
25181 var_ty.assertHasLayout(zcu);
25852 if (is_extern) {25182 if (is_extern) {
25853 if (!try sema.validateExternType(var_ty, .other)) {25183 if (!try sema.validateExternType(var_ty, .other)) {
25854 const msg = msg: {25184 const msg = msg: {
...@@ -25870,7 +25200,7 @@ pub fn validateVarType(...@@ -25870,7 +25200,7 @@ pub fn validateVarType(
25870 }25200 }
25871 }25201 }
2587225202
25873 if (!try var_ty.comptimeOnlySema(pt)) return;25203 if (!var_ty.comptimeOnly(zcu)) return;
2587425204
25875 const msg = msg: {25205 const msg = msg: {
25876 const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)});25206 const msg = try sema.errMsg(src, "variable of type '{f}' must be const or comptime", .{var_ty.fmt(pt)});
...@@ -25886,49 +25216,28 @@ pub fn validateVarType(...@@ -25886,49 +25216,28 @@ pub fn validateVarType(
25886 return sema.failWithOwnedErrorMsg(block, msg);25216 return sema.failWithOwnedErrorMsg(block, msg);
25887}25217}
2588825218
25889const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void);
25890
25891fn explainWhyTypeIsComptime(25219fn explainWhyTypeIsComptime(
25892 sema: *Sema,25220 sema: *Sema,
25893 msg: *Zcu.ErrorMsg,25221 msg: *Zcu.ErrorMsg,
25894 src_loc: LazySrcLoc,25222 src: LazySrcLoc,
25895 ty: Type,
25896) CompileError!void {
25897 var type_set = TypeSet{};
25898 defer type_set.deinit(sema.gpa);
25899
25900 try ty.resolveFully(sema.pt);
25901 return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set);
25902}
25903
25904fn explainWhyTypeIsComptimeInner(
25905 sema: *Sema,
25906 msg: *Zcu.ErrorMsg,
25907 src_loc: LazySrcLoc,
25908 ty: Type,25223 ty: Type,
25909 type_set: *TypeSet,
25910) CompileError!void {25224) CompileError!void {
25911 const pt = sema.pt;25225 const pt = sema.pt;
25912 const zcu = pt.zcu;25226 const zcu = pt.zcu;
25913 const ip = &zcu.intern_pool;25227 const ip = &zcu.intern_pool;
25228 assert(ty.comptimeOnly(zcu));
25914 switch (ty.zigTypeTag(zcu)) {25229 switch (ty.zigTypeTag(zcu)) {
25915 .bool,25230 .bool,
25916 .int,25231 .int,
25917 .float,25232 .float,
25918 .error_set,25233 .error_set,
25919 .@"enum",
25920 .frame,25234 .frame,
25921 .@"anyframe",25235 .@"anyframe",
25922 .void,25236 .void,
25923 => return,25237 .@"enum",
2592425238 .@"opaque",
25925 .@"fn" => {25239 .pointer,
25926 try sema.errNote(src_loc, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)});25240 => unreachable, // not comptime-only
25927 },
25928
25929 .type => {
25930 try sema.errNote(src_loc, msg, "types are not available at runtime", .{});
25931 },
2593225241
25933 .comptime_float,25242 .comptime_float,
25934 .comptime_int,25243 .comptime_int,
...@@ -25936,78 +25245,53 @@ fn explainWhyTypeIsComptimeInner(...@@ -25936,78 +25245,53 @@ fn explainWhyTypeIsComptimeInner(
25936 .noreturn,25245 .noreturn,
25937 .undefined,25246 .undefined,
25938 .null,25247 .null,
25939 => return,25248 => return, // no explanation needed
25940
25941 .@"opaque" => {
25942 try sema.errNote(src_loc, msg, "opaque type '{f}' has undefined size", .{ty.fmt(pt)});
25943 },
25944
25945 .array, .vector => {
25946 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(zcu), type_set);
25947 },
25948 .pointer => {
25949 const elem_ty = ty.elemType2(zcu);
25950 if (elem_ty.zigTypeTag(zcu) == .@"fn") {
25951 const fn_info = zcu.typeToFunc(elem_ty).?;
25952 if (fn_info.is_generic) {
25953 try sema.errNote(src_loc, msg, "function is generic", .{});
25954 }
25955 switch (fn_info.cc) {
25956 .@"inline" => try sema.errNote(src_loc, msg, "function has inline calling convention", .{}),
25957 else => {},
25958 }
25959 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) {
25960 try sema.errNote(src_loc, msg, "function has a comptime-only return type", .{});
25961 }
25962 return;
25963 }
25964 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(zcu), type_set);
25965 },
25966
25967 .optional => {
25968 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(zcu), type_set);
25969 },
25970 .error_union => {
25971 try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(zcu), type_set);
25972 },
2597325249
25974 .@"struct" => {25250 .array, .vector => try sema.explainWhyTypeIsComptime(msg, src, ty.childType(zcu)),
25975 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;25251 .optional => try sema.explainWhyTypeIsComptime(msg, src, ty.optionalChild(zcu)),
25252 .error_union => try sema.explainWhyTypeIsComptime(msg, src, ty.errorUnionPayload(zcu)),
2597625253
25977 if (zcu.typeToStruct(ty)) |struct_type| {25254 .@"fn" => try sema.errNote(src, msg, "use '*const {f}' for a function pointer type", .{ty.fmt(pt)}),
25978 for (0..struct_type.field_types.len) |i| {25255 .type => try sema.errNote(src, msg, "types are not available at runtime", .{}),
25979 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
25980 const field_src: LazySrcLoc = .{
25981 .base_node_inst = struct_type.zir_index,
25982 .offset = .{ .container_field_type = @intCast(i) },
25983 };
2598425256
25985 if (try field_ty.comptimeOnlySema(pt)) {25257 .@"struct" => if (zcu.typeToStruct(ty)) |struct_type| {
25986 try sema.errNote(field_src, msg, "struct requires comptime because of this field", .{});25258 ty.assertHasLayout(zcu);
25987 try sema.explainWhyTypeIsComptimeInner(msg, field_src, field_ty, type_set);25259 for (0..struct_type.field_types.len) |i| {
25988 }25260 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
25989 }25261 if (!field_ty.comptimeOnly(zcu)) continue;
25262 const field_src: LazySrcLoc = .{
25263 .base_node_inst = struct_type.zir_index,
25264 .offset = .{ .container_field_type = @intCast(i) },
25265 };
25266 try sema.errNote(field_src, msg, "struct requires comptime because of this field", .{});
25267 return sema.explainWhyTypeIsComptime(msg, field_src, field_ty);
25990 }25268 }
25991 // TODO tuples25269 unreachable;
25270 } else {
25271 const tuple = ip.indexToKey(ty.toIntern()).tuple_type;
25272 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty_ip, field_val_ip| {
25273 if (field_val_ip != .none) continue;
25274 const field_ty: Type = .fromInterned(field_ty_ip);
25275 if (!field_ty.comptimeOnly(zcu)) continue;
25276 try sema.errNote(src, msg, "tuple requires comptime because of field of type '{f}'", .{field_ty.fmt(pt)});
25277 return sema.explainWhyTypeIsComptime(msg, src, field_ty);
25278 }
25279 unreachable;
25992 },25280 },
2599325281
25994 .@"union" => {25282 .@"union" => {
25995 if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;25283 const union_obj = zcu.typeToUnion(ty).?;
2599625284 for (0..union_obj.field_types.len) |i| {
25997 if (zcu.typeToUnion(ty)) |union_obj| {25285 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[i]);
25998 for (0..union_obj.field_types.len) |i| {25286 if (!field_ty.comptimeOnly(zcu)) continue;
25999 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[i]);25287 const field_src: LazySrcLoc = .{
26000 const field_src: LazySrcLoc = .{25288 .base_node_inst = union_obj.zir_index,
26001 .base_node_inst = union_obj.zir_index,25289 .offset = .{ .container_field_type = @intCast(i) },
26002 .offset = .{ .container_field_type = @intCast(i) },25290 };
26003 };25291 try sema.errNote(field_src, msg, "union requires comptime because of this field", .{});
2600425292 return sema.explainWhyTypeIsComptime(msg, field_src, field_ty);
26005 if (try field_ty.comptimeOnlySema(pt)) {
26006 try sema.errNote(field_src, msg, "union requires comptime because of this field", .{});
26007 try sema.explainWhyTypeIsComptimeInner(msg, field_src, field_ty, type_set);
26008 }
26009 }
26010 }25293 }
25294 unreachable;
26011 },25295 },
26012 }25296 }
26013}25297}
...@@ -26022,9 +25306,8 @@ const ExternPosition = enum {...@@ -26022,9 +25306,8 @@ const ExternPosition = enum {
26022};25306};
2602325307
26024/// Returns true if `ty` is allowed in extern types.25308/// Returns true if `ty` is allowed in extern types.
26025/// Does *NOT* require `ty` to be resolved in any way.25309/// Does not require `ty` to be resolved in any way.
26026/// Calls `resolveLayout` for packed containers.25310pub fn validateExternType(
26027fn validateExternType(
26028 sema: *Sema,25311 sema: *Sema,
26029 ty: Type,25312 ty: Type,
26030 position: ExternPosition,25313 position: ExternPosition,
...@@ -26042,7 +25325,16 @@ fn validateExternType(...@@ -26042,7 +25325,16 @@ fn validateExternType(
26042 .error_set,25325 .error_set,
26043 .frame,25326 .frame,
26044 => return false,25327 => return false,
26045 .void => return position == .union_field or position == .ret_ty or position == .struct_field or position == .element,25328 .void => return switch (position) {
25329 .ret_ty,
25330 .union_field,
25331 .struct_field,
25332 .element,
25333 => true,
25334 .param_ty,
25335 .other,
25336 => false,
25337 },
26046 .noreturn => return position == .ret_ty,25338 .noreturn => return position == .ret_ty,
26047 .@"opaque",25339 .@"opaque",
26048 .bool,25340 .bool,
...@@ -26050,10 +25342,12 @@ fn validateExternType(...@@ -26050,10 +25342,12 @@ fn validateExternType(
26050 .@"anyframe",25342 .@"anyframe",
26051 => return true,25343 => return true,
26052 .pointer => {25344 .pointer => {
26053 if (ty.childType(zcu).zigTypeTag(zcu) == .@"fn") {25345 if (ty.isSlice(zcu)) return false;
26054 return ty.isConstPtr(zcu) and try sema.validateExternType(ty.childType(zcu), .other);25346 const child_ty = ty.childType(zcu);
25347 if (child_ty.zigTypeTag(zcu) == .@"fn") {
25348 return ty.isConstPtr(zcu) and try sema.validateExternType(child_ty, .other);
26055 }25349 }
26056 return !(ty.isSlice(zcu) or try ty.comptimeOnlySema(pt));25350 return true;
26057 },25351 },
26058 .int => switch (ty.intInfo(zcu).bits) {25352 .int => switch (ty.intInfo(zcu).bits) {
26059 0, 8, 16, 32, 64, 128 => return true,25353 0, 8, 16, 32, 64, 128 => return true,
...@@ -26069,29 +25363,42 @@ fn validateExternType(...@@ -26069,29 +25363,42 @@ fn validateExternType(
26069 return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));25363 return !target_util.fnCallConvAllowsZigTypes(ty.fnCallingConvention(zcu));
26070 },25364 },
26071 .@"enum" => {25365 .@"enum" => {
26072 return sema.validateExternType(ty.intTagType(zcu), position);25366 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern());
26073 },25367 if (!enum_obj.int_tag_is_explicit) return false;
26074 .@"struct", .@"union" => switch (ty.containerLayout(zcu)) {25368 return sema.validateExternType(.fromInterned(enum_obj.int_tag_type), position);
26075 .@"extern" => return true,25369 },
26076 .@"packed" => {25370 .@"struct" => {
26077 const bit_size = try ty.bitSizeSema(pt);25371 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern());
26078 switch (bit_size) {25372 return switch (struct_obj.layout) {
26079 0, 8, 16, 32, 64, 128 => return true,25373 .auto => false,
26080 else => return false,25374 .@"extern" => true,
26081 }25375 .@"packed" => switch (struct_obj.packed_backing_mode) {
26082 },25376 .auto => false,
26083 .auto => return !(try ty.hasRuntimeBitsSema(pt)),25377 .explicit => try sema.validateExternType(.fromInterned(struct_obj.packed_backing_int_type), position),
25378 },
25379 };
25380 },
25381 .@"union" => {
25382 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern());
25383 return switch (union_obj.layout) {
25384 .auto => false,
25385 .@"extern" => true,
25386 .@"packed" => switch (union_obj.packed_backing_mode) {
25387 .auto => false,
25388 .explicit => try sema.validateExternType(.fromInterned(union_obj.packed_backing_int_type), position),
25389 },
25390 };
26084 },25391 },
26085 .array => {25392 .array => {
26086 if (position == .ret_ty or position == .param_ty) return false;25393 if (position == .ret_ty or position == .param_ty) return false;
26087 return sema.validateExternType(ty.elemType2(zcu), .element);25394 return sema.validateExternType(ty.childType(zcu), .element);
26088 },25395 },
26089 .vector => return sema.validateExternType(ty.elemType2(zcu), .element),25396 .vector => return sema.validateExternType(ty.childType(zcu), .element),
26090 .optional => return ty.isPtrLikeOptional(zcu),25397 .optional => return ty.isPtrLikeOptional(zcu),
26091 }25398 }
26092}25399}
2609325400
26094fn explainWhyTypeIsNotExtern(25401pub fn explainWhyTypeIsNotExtern(
26095 sema: *Sema,25402 sema: *Sema,
26096 msg: *Zcu.ErrorMsg,25403 msg: *Zcu.ErrorMsg,
26097 src_loc: LazySrcLoc,25404 src_loc: LazySrcLoc,
...@@ -26125,9 +25432,6 @@ fn explainWhyTypeIsNotExtern(...@@ -26125,9 +25432,6 @@ fn explainWhyTypeIsNotExtern(
26125 const pointee_ty = ty.childType(zcu);25432 const pointee_ty = ty.childType(zcu);
26126 if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") {25433 if (!ty.isConstPtr(zcu) and pointee_ty.zigTypeTag(zcu) == .@"fn") {
26127 try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});25434 try sema.errNote(src_loc, msg, "pointer to extern function must be 'const'", .{});
26128 } else if (try ty.comptimeOnlySema(pt)) {
26129 try sema.errNote(src_loc, msg, "pointer to comptime-only type '{f}'", .{pointee_ty.fmt(pt)});
26130 try sema.explainWhyTypeIsComptime(msg, src_loc, ty);
26131 }25435 }
26132 try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other);25436 try sema.explainWhyTypeIsNotExtern(msg, src_loc, pointee_ty, .other);
26133 }25437 }
...@@ -26157,6 +25461,7 @@ fn explainWhyTypeIsNotExtern(...@@ -26157,6 +25461,7 @@ fn explainWhyTypeIsNotExtern(
26157 try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});25461 try sema.errNote(src_loc, msg, "enum tag type '{f}' is not extern compatible", .{tag_ty.fmt(pt)});
26158 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);25462 try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
26159 },25463 },
25464 // MLUGG TODO: these notes are bad now (because ABI sized packed type also needs explicit backing type)
26160 .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),25465 .@"struct" => try sema.errNote(src_loc, msg, "only extern structs and ABI sized packed structs are extern compatible", .{}),
26161 .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),25466 .@"union" => try sema.errNote(src_loc, msg, "only extern unions and ABI sized packed unions are extern compatible", .{}),
26162 .array => {25467 .array => {
...@@ -26165,51 +25470,14 @@ fn explainWhyTypeIsNotExtern(...@@ -26165,51 +25470,14 @@ fn explainWhyTypeIsNotExtern(
26165 } else if (position == .param_ty) {25470 } else if (position == .param_ty) {
26166 return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{});25471 return sema.errNote(src_loc, msg, "arrays are not allowed as a parameter type", .{});
26167 }25472 }
26168 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(zcu), .element);25473 try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element);
26169 },25474 },
26170 .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(zcu), .element),25475 .vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.childType(zcu), .element),
26171 .optional => try sema.errNote(src_loc, msg, "only pointer like optionals are extern compatible", .{}),25476 .optional => try sema.errNote(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
26172 }25477 }
26173}25478}
2617425479
26175/// Returns true if `ty` is allowed in packed types.25480pub fn explainWhyTypeIsNotPackable(
26176/// Does not require `ty` to be resolved in any way, but may resolve whether it is comptime-only.
26177fn validatePackedType(sema: *Sema, ty: Type) !bool {
26178 const pt = sema.pt;
26179 const zcu = pt.zcu;
26180 return switch (ty.zigTypeTag(zcu)) {
26181 .type,
26182 .comptime_float,
26183 .comptime_int,
26184 .enum_literal,
26185 .undefined,
26186 .null,
26187 .error_union,
26188 .error_set,
26189 .frame,
26190 .noreturn,
26191 .@"opaque",
26192 .@"anyframe",
26193 .@"fn",
26194 .array,
26195 => false,
26196 .optional => return ty.isPtrLikeOptional(zcu),
26197 .void,
26198 .bool,
26199 .float,
26200 .int,
26201 .vector,
26202 => true,
26203 .@"enum" => switch (zcu.intern_pool.loadEnumType(ty.toIntern()).tag_mode) {
26204 .auto => false,
26205 .explicit, .nonexhaustive => true,
26206 },
26207 .pointer => !ty.isSlice(zcu) and !try ty.comptimeOnlySema(pt),
26208 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
26209 };
26210}
26211
26212fn explainWhyTypeIsNotPacked(
26213 sema: *Sema,25481 sema: *Sema,
26214 msg: *Zcu.ErrorMsg,25482 msg: *Zcu.ErrorMsg,
26215 src_loc: LazySrcLoc,25483 src_loc: LazySrcLoc,
...@@ -26250,8 +25518,8 @@ fn explainWhyTypeIsNotPacked(...@@ -26250,8 +25518,8 @@ fn explainWhyTypeIsNotPacked(
26250 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});25518 try sema.errNote(src_loc, msg, "type has no guaranteed in-memory representation", .{});
26251 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});25519 try sema.errNote(src_loc, msg, "use '*const ' to make a function pointer type", .{});
26252 },25520 },
26253 .@"struct" => try sema.errNote(src_loc, msg, "only packed structs layout are allowed in packed types", .{}),25521 .@"struct" => try sema.errNote(src_loc, msg, "struct in packed type must have packed layout", .{}),
26254 .@"union" => try sema.errNote(src_loc, msg, "only packed unions layout are allowed in packed types", .{}),25522 .@"union" => try sema.errNote(src_loc, msg, "union in packed type must have packed layout", .{}),
26255 }25523 }
26256}25524}
2625725525
...@@ -26277,7 +25545,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In...@@ -26277,7 +25545,7 @@ fn getPanicIdFunc(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.SimplePanicId) !In
26277 try sema.ensureMemoizedStateResolved(src, .panic);25545 try sema.ensureMemoizedStateResolved(src, .panic);
26278 const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());25546 const panic_fn_index = zcu.builtin_decl_values.get(panic_id.toBuiltin());
26279 switch (sema.owner.unwrap()) {25547 switch (sema.owner.unwrap()) {
26280 .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},25548 .@"comptime", .nav_ty, .nav_val, .type_layout, .type_inits, .memoized_state => {},
26281 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),25549 .func => |owner_func| zcu.intern_pool.funcSetHasErrorTrace(io, owner_func, true),
26282 }25550 }
26283 return panic_fn_index;25551 return panic_fn_index;
...@@ -26555,7 +25823,8 @@ fn fieldPtrLoad(...@@ -26555,7 +25823,8 @@ fn fieldPtrLoad(
26555 const zcu = pt.zcu;25823 const zcu = pt.zcu;
26556 const object_ptr_ty = sema.typeOf(object_ptr);25824 const object_ptr_ty = sema.typeOf(object_ptr);
26557 const pointee_ty = object_ptr_ty.childType(zcu);25825 const pointee_ty = object_ptr_ty.childType(zcu);
26558 if (try typeHasOnePossibleValue(sema, pointee_ty)) |opv| {25826 try sema.ensureLayoutResolved(pointee_ty); // MLUGG TODO
25827 if (try pointee_ty.onePossibleValue(pt)) |opv| {
26559 const object: Air.Inst.Ref = .fromValue(opv);25828 const object: Air.Inst.Ref = .fromValue(opv);
26560 return fieldVal(sema, block, src, object, field_name, field_name_src);25829 return fieldVal(sema, block, src, object, field_name, field_name_src);
26561 }25830 }
...@@ -26603,7 +25872,7 @@ fn fieldVal(...@@ -26603,7 +25872,7 @@ fn fieldVal(
26603 return Air.internedToRef((try pt.intValue(.usize, inner_ty.arrayLen(zcu))).toIntern());25872 return Air.internedToRef((try pt.intValue(.usize, inner_ty.arrayLen(zcu))).toIntern());
26604 } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {25873 } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
26605 const ptr_info = object_ty.ptrInfo(zcu);25874 const ptr_info = object_ty.ptrInfo(zcu);
26606 const result_ty = try pt.ptrTypeSema(.{25875 const result_ty = try pt.ptrType(.{
26607 .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),25876 .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),
26608 .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,25877 .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,
26609 .flags = .{25878 .flags = .{
...@@ -26693,7 +25962,6 @@ fn fieldVal(...@@ -26693,7 +25962,6 @@ fn fieldVal(
26693 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {25962 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
26694 return inst;25963 return inst;
26695 }25964 }
26696 try child_type.resolveFields(pt);
26697 if (child_type.unionTagType(zcu)) |enum_ty| {25965 if (child_type.unionTagType(zcu)) |enum_ty| {
26698 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {25966 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index_usize| {
26699 const field_index: u32 = @intCast(field_index_usize);25967 const field_index: u32 = @intCast(field_index_usize);
...@@ -26731,6 +25999,7 @@ fn fieldVal(...@@ -26731,6 +25999,7 @@ fn fieldVal(
26731 },25999 },
26732 .@"struct" => if (is_pointer_to) {26000 .@"struct" => if (is_pointer_to) {
26733 // Avoid loading the entire struct by fetching a pointer and loading that26001 // Avoid loading the entire struct by fetching a pointer and loading that
26002 try sema.ensureLayoutResolved(inner_ty);
26734 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);26003 const field_ptr = try sema.structFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
26735 return sema.analyzeLoad(block, src, field_ptr, object_src);26004 return sema.analyzeLoad(block, src, field_ptr, object_src);
26736 } else {26005 } else {
...@@ -26738,6 +26007,7 @@ fn fieldVal(...@@ -26738,6 +26007,7 @@ fn fieldVal(
26738 },26007 },
26739 .@"union" => if (is_pointer_to) {26008 .@"union" => if (is_pointer_to) {
26740 // Avoid loading the entire union by fetching a pointer and loading that26009 // Avoid loading the entire union by fetching a pointer and loading that
26010 try sema.ensureLayoutResolved(inner_ty);
26741 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);26011 const field_ptr = try sema.unionFieldPtr(block, src, object, field_name, field_name_src, inner_ty, false);
26742 return sema.analyzeLoad(block, src, field_ptr, object_src);26012 return sema.analyzeLoad(block, src, field_ptr, object_src);
26743 } else {26013 } else {
...@@ -26787,7 +26057,7 @@ fn fieldPtr(...@@ -26787,7 +26057,7 @@ fn fieldPtr(
26787 return uavRef(sema, int_val.toIntern());26057 return uavRef(sema, int_val.toIntern());
26788 } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {26058 } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
26789 const ptr_info = object_ty.ptrInfo(zcu);26059 const ptr_info = object_ty.ptrInfo(zcu);
26790 const new_ptr_ty = try pt.ptrTypeSema(.{26060 const new_ptr_ty = try pt.ptrType(.{
26791 .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),26061 .child = Type.fromInterned(ptr_info.child).childType(zcu).toIntern(),
26792 .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,26062 .sentinel = if (inner_ty.sentinel(zcu)) |s| s.toIntern() else .none,
26793 .flags = .{26063 .flags = .{
...@@ -26802,7 +26072,7 @@ fn fieldPtr(...@@ -26802,7 +26072,7 @@ fn fieldPtr(
26802 .packed_offset = ptr_info.packed_offset,26072 .packed_offset = ptr_info.packed_offset,
26803 });26073 });
26804 const ptr_ptr_info = object_ptr_ty.ptrInfo(zcu);26074 const ptr_ptr_info = object_ptr_ty.ptrInfo(zcu);
26805 const result_ty = try pt.ptrTypeSema(.{26075 const result_ty = try pt.ptrType(.{
26806 .child = new_ptr_ty.toIntern(),26076 .child = new_ptr_ty.toIntern(),
26807 .sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none,26077 .sentinel = if (object_ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none,
26808 .flags = .{26078 .flags = .{
...@@ -26836,7 +26106,7 @@ fn fieldPtr(...@@ -26836,7 +26106,7 @@ fn fieldPtr(
26836 if (field_name.eqlSlice("ptr", ip)) {26106 if (field_name.eqlSlice("ptr", ip)) {
26837 const slice_ptr_ty = inner_ty.slicePtrFieldType(zcu);26107 const slice_ptr_ty = inner_ty.slicePtrFieldType(zcu);
2683826108
26839 const result_ty = try pt.ptrTypeSema(.{26109 const result_ty = try pt.ptrType(.{
26840 .child = slice_ptr_ty.toIntern(),26110 .child = slice_ptr_ty.toIntern(),
26841 .flags = .{26111 .flags = .{
26842 .is_const = !attr_ptr_ty.ptrIsMutable(zcu),26112 .is_const = !attr_ptr_ty.ptrIsMutable(zcu),
...@@ -26854,7 +26124,7 @@ fn fieldPtr(...@@ -26854,7 +26124,7 @@ fn fieldPtr(
26854 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);26124 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
26855 return field_ptr;26125 return field_ptr;
26856 } else if (field_name.eqlSlice("len", ip)) {26126 } else if (field_name.eqlSlice("len", ip)) {
26857 const result_ty = try pt.ptrTypeSema(.{26127 const result_ty = try pt.ptrType(.{
26858 .child = .usize_type,26128 .child = .usize_type,
26859 .flags = .{26129 .flags = .{
26860 .is_const = !attr_ptr_ty.ptrIsMutable(zcu),26130 .is_const = !attr_ptr_ty.ptrIsMutable(zcu),
...@@ -26925,7 +26195,6 @@ fn fieldPtr(...@@ -26925,7 +26195,6 @@ fn fieldPtr(
26925 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {26195 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(zcu), field_name)) |inst| {
26926 return inst;26196 return inst;
26927 }26197 }
26928 try child_type.resolveFields(pt);
26929 if (child_type.unionTagType(zcu)) |enum_ty| {26198 if (child_type.unionTagType(zcu)) |enum_ty| {
26930 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {26199 if (enum_ty.enumFieldIndex(field_name, zcu)) |field_index| {
26931 const field_index_u32: u32 = @intCast(field_index);26200 const field_index_u32: u32 = @intCast(field_index);
...@@ -26960,6 +26229,7 @@ fn fieldPtr(...@@ -26960,6 +26229,7 @@ fn fieldPtr(
26960 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)26229 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
26961 else26230 else
26962 object_ptr;26231 object_ptr;
26232 try sema.ensureLayoutResolved(inner_ty);
26963 const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);26233 const field_ptr = try sema.structFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
26964 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);26234 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
26965 return field_ptr;26235 return field_ptr;
...@@ -26969,6 +26239,7 @@ fn fieldPtr(...@@ -26969,6 +26239,7 @@ fn fieldPtr(
26969 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)26239 try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
26970 else26240 else
26971 object_ptr;26241 object_ptr;
26242 try sema.ensureLayoutResolved(inner_ty);
26972 const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);26243 const field_ptr = try sema.unionFieldPtr(block, src, inner_ptr, field_name, field_name_src, inner_ty, initializing);
26973 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);26244 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
26974 return field_ptr;26245 return field_ptr;
...@@ -27012,6 +26283,7 @@ fn fieldCallBind(...@@ -27012,6 +26283,7 @@ fn fieldCallBind(
27012 // Optionally dereference a second pointer to get the concrete type.26283 // Optionally dereference a second pointer to get the concrete type.
27013 const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one;26284 const is_double_ptr = inner_ty.zigTypeTag(zcu) == .pointer and inner_ty.ptrSize(zcu) == .one;
27014 const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty;26285 const concrete_ty = if (is_double_ptr) inner_ty.childType(zcu) else inner_ty;
26286 try sema.ensureLayoutResolved(concrete_ty);
27015 const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;26287 const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;
27016 const object_ptr = if (is_double_ptr)26288 const object_ptr = if (is_double_ptr)
27017 try sema.analyzeLoad(block, src, raw_ptr, src)26289 try sema.analyzeLoad(block, src, raw_ptr, src)
...@@ -27021,10 +26293,8 @@ fn fieldCallBind(...@@ -27021,10 +26293,8 @@ fn fieldCallBind(
27021 find_field: {26293 find_field: {
27022 switch (concrete_ty.zigTypeTag(zcu)) {26294 switch (concrete_ty.zigTypeTag(zcu)) {
27023 .@"struct" => {26295 .@"struct" => {
27024 try concrete_ty.resolveFields(pt);
27025 if (zcu.typeToStruct(concrete_ty)) |struct_type| {26296 if (zcu.typeToStruct(concrete_ty)) |struct_type| {
27026 const field_index = struct_type.nameIndex(ip, field_name) orelse26297 const field_index = struct_type.nameIndex(ip, field_name) orelse break :find_field;
27027 break :find_field;
27028 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);26298 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
2702926299
27030 return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);26300 return sema.finishFieldCallBind(block, src, ptr_ty, field_ty, field_index, object_ptr);
...@@ -27047,9 +26317,9 @@ fn fieldCallBind(...@@ -27047,9 +26317,9 @@ fn fieldCallBind(
27047 }26317 }
27048 },26318 },
27049 .@"union" => {26319 .@"union" => {
27050 try concrete_ty.resolveFields(pt);
27051 const union_obj = zcu.typeToUnion(concrete_ty).?;26320 const union_obj = zcu.typeToUnion(concrete_ty).?;
27052 _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field;26321 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
26322 if (enum_obj.nameIndex(ip, field_name) == null) break :find_field;
27053 const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);26323 const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);
27054 return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };26324 return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };
27055 },26325 },
...@@ -27163,7 +26433,7 @@ fn finishFieldCallBind(...@@ -27163,7 +26433,7 @@ fn finishFieldCallBind(
27163) CompileError!ResolvedFieldCallee {26433) CompileError!ResolvedFieldCallee {
27164 const pt = sema.pt;26434 const pt = sema.pt;
27165 const zcu = pt.zcu;26435 const zcu = pt.zcu;
27166 const ptr_field_ty = try pt.ptrTypeSema(.{26436 const ptr_field_ty = try pt.ptrType(.{
27167 .child = field_ty.toIntern(),26437 .child = field_ty.toIntern(),
27168 .flags = .{26438 .flags = .{
27169 .is_const = !ptr_ty.ptrIsMutable(zcu),26439 .is_const = !ptr_ty.ptrIsMutable(zcu),
...@@ -27174,7 +26444,9 @@ fn finishFieldCallBind(...@@ -27174,7 +26444,9 @@ fn finishFieldCallBind(
27174 const container_ty = ptr_ty.childType(zcu);26444 const container_ty = ptr_ty.childType(zcu);
27175 if (container_ty.zigTypeTag(zcu) == .@"struct") {26445 if (container_ty.zigTypeTag(zcu) == .@"struct") {
27176 if (container_ty.structFieldIsComptime(field_index, zcu)) {26446 if (container_ty.structFieldIsComptime(field_index, zcu)) {
27177 try container_ty.resolveStructFieldInits(pt);26447 if (!container_ty.isTuple(zcu)) {
26448 try sema.ensureFieldInitsResolved(container_ty);
26449 }
27178 const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?;26450 const default_val = (try container_ty.structFieldValueComptime(pt, field_index)).?;
27179 return .{ .direct = Air.internedToRef(default_val.toIntern()) };26451 return .{ .direct = Air.internedToRef(default_val.toIntern()) };
27180 }26452 }
...@@ -27239,6 +26511,7 @@ fn namespaceLookupVal(...@@ -27239,6 +26511,7 @@ fn namespaceLookupVal(
27239 return try sema.analyzeNavVal(block, src, nav);26511 return try sema.analyzeNavVal(block, src, nav);
27240}26512}
2724126513
26514/// Asserts that the layout of `struct_ty` is already resolved.
27242fn structFieldPtr(26515fn structFieldPtr(
27243 sema: *Sema,26516 sema: *Sema,
27244 block: *Block,26517 block: *Block,
...@@ -27252,10 +26525,9 @@ fn structFieldPtr(...@@ -27252,10 +26525,9 @@ fn structFieldPtr(
27252 const pt = sema.pt;26525 const pt = sema.pt;
27253 const zcu = pt.zcu;26526 const zcu = pt.zcu;
27254 const ip = &zcu.intern_pool;26527 const ip = &zcu.intern_pool;
27255 assert(struct_ty.zigTypeTag(zcu) == .@"struct");
2725626528
27257 try struct_ty.resolveFields(pt);26529 assert(struct_ty.zigTypeTag(zcu) == .@"struct");
27258 try struct_ty.resolveLayout(pt);26530 struct_ty.assertHasLayout(zcu);
2725926531
27260 if (struct_ty.isTuple(zcu)) {26532 if (struct_ty.isTuple(zcu)) {
27261 if (field_name.eqlSlice("len", ip)) {26533 if (field_name.eqlSlice("len", ip)) {
...@@ -27274,6 +26546,7 @@ fn structFieldPtr(...@@ -27274,6 +26546,7 @@ fn structFieldPtr(
27274 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty);26546 return sema.structFieldPtrByIndex(block, src, struct_ptr, field_index, struct_ty);
27275}26547}
2727626548
26549/// Asserts that the layout of `struct_ty` is already resolved.
27277fn structFieldPtrByIndex(26550fn structFieldPtrByIndex(
27278 sema: *Sema,26551 sema: *Sema,
27279 block: *Block,26552 block: *Block,
...@@ -27286,8 +26559,10 @@ fn structFieldPtrByIndex(...@@ -27286,8 +26559,10 @@ fn structFieldPtrByIndex(
27286 const zcu = pt.zcu;26559 const zcu = pt.zcu;
27287 const ip = &zcu.intern_pool;26560 const ip = &zcu.intern_pool;
2728826561
26562 struct_ty.assertHasLayout(zcu);
26563
27289 const struct_type = zcu.typeToStruct(struct_ty).?;26564 const struct_type = zcu.typeToStruct(struct_ty).?;
27290 const field_is_comptime = struct_type.fieldIsComptime(ip, field_index);26565 const field_is_comptime = struct_type.field_is_comptime_bits.get(ip, field_index);
2729126566
27292 // Comptime fields are handled later26567 // Comptime fields are handled later
27293 if (!field_is_comptime) {26568 if (!field_is_comptime) {
...@@ -27300,6 +26575,7 @@ fn structFieldPtrByIndex(...@@ -27300,6 +26575,7 @@ fn structFieldPtrByIndex(
27300 const field_ty = struct_type.field_types.get(ip)[field_index];26575 const field_ty = struct_type.field_types.get(ip)[field_index];
27301 const struct_ptr_ty = sema.typeOf(struct_ptr);26576 const struct_ptr_ty = sema.typeOf(struct_ptr);
27302 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);26577 const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(zcu);
26578 assert(struct_ptr_ty_info.child == struct_ty.toIntern());
2730326579
27304 var ptr_ty_data: InternPool.Key.PtrType = .{26580 var ptr_ty_data: InternPool.Key.PtrType = .{
27305 .child = field_ty,26581 .child = field_ty,
...@@ -27313,7 +26589,7 @@ fn structFieldPtrByIndex(...@@ -27313,7 +26589,7 @@ fn structFieldPtrByIndex(
27313 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)26589 const parent_align = if (struct_ptr_ty_info.flags.alignment != .none)
27314 struct_ptr_ty_info.flags.alignment26590 struct_ptr_ty_info.flags.alignment
27315 else26591 else
27316 try Type.fromInterned(struct_ptr_ty_info.child).abiAlignmentSema(pt);26592 struct_ty.abiAlignment(zcu);
2731726593
27318 if (struct_type.layout == .@"packed") {26594 if (struct_type.layout == .@"packed") {
27319 assert(!field_is_comptime);26595 assert(!field_is_comptime);
...@@ -27325,31 +26601,32 @@ fn structFieldPtrByIndex(...@@ -27325,31 +26601,32 @@ fn structFieldPtrByIndex(
27325 // For extern structs, field alignment might be bigger than type's26601 // For extern structs, field alignment might be bigger than type's
27326 // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the26602 // natural alignment. Eg, in `extern struct { x: u32, y: u16 }` the
27327 // second field is aligned as u32.26603 // second field is aligned as u32.
27328 const field_offset = struct_ty.structFieldOffset(field_index, zcu);26604 ptr_ty_data.flags.alignment = a: {
27329 ptr_ty_data.flags.alignment = if (parent_align == .none)26605 const field_off = struct_ty.structFieldOffset(field_index, zcu);
27330 .none26606 if (field_off == 0) break :a struct_ptr_ty_info.flags.alignment;
27331 else26607 const true_field_align: Alignment = .fromLog2Units(@ctz(field_off));
27332 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));26608 if (struct_ptr_ty_info.flags.alignment == .none and
26609 true_field_align == Type.fromInterned(field_ty).abiAlignment(zcu))
26610 {
26611 break :a .none;
26612 }
26613 break :a .minStrict(true_field_align, parent_align);
26614 };
27333 } else {26615 } else {
27334 // Our alignment is capped at the field alignment.26616 // Our alignment is capped at the field alignment.
27335 const field_align = try Type.fromInterned(field_ty).structFieldAlignmentSema(
27336 struct_type.fieldAlign(ip, field_index),
27337 struct_type.layout,
27338 pt,
27339 );
27340 ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)26617 ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)
27341 field_align26618 struct_ty.explicitFieldAlignment(field_index, zcu)
27342 else26619 else
27343 field_align.min(parent_align);26620 struct_ty.resolvedFieldAlignment(field_index, zcu).min(parent_align);
27344 }26621 }
2734526622
27346 const ptr_field_ty = try pt.ptrTypeSema(ptr_ty_data);26623 const ptr_field_ty = try pt.ptrType(ptr_ty_data);
2734726624
27348 if (field_is_comptime) {26625 if (field_is_comptime) {
27349 try struct_ty.resolveStructFieldInits(pt);26626 try sema.ensureFieldInitsResolved(struct_ty);
27350 const val = try pt.intern(.{ .ptr = .{26627 const val = try pt.intern(.{ .ptr = .{
27351 .ty = ptr_field_ty.toIntern(),26628 .ty = ptr_field_ty.toIntern(),
27352 .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },26629 .base_addr = .{ .comptime_field = struct_type.field_defaults.get(ip)[field_index] },
27353 .byte_offset = 0,26630 .byte_offset = 0,
27354 } });26631 } });
27355 return Air.internedToRef(val);26632 return Air.internedToRef(val);
...@@ -27371,32 +26648,26 @@ fn structFieldVal(...@@ -27371,32 +26648,26 @@ fn structFieldVal(
27371 const ip = &zcu.intern_pool;26648 const ip = &zcu.intern_pool;
27372 assert(struct_ty.zigTypeTag(zcu) == .@"struct");26649 assert(struct_ty.zigTypeTag(zcu) == .@"struct");
2737326650
27374 try struct_ty.resolveFields(pt);
27375
27376 switch (ip.indexToKey(struct_ty.toIntern())) {26651 switch (ip.indexToKey(struct_ty.toIntern())) {
27377 .struct_type => {26652 .struct_type => {
27378 const struct_type = ip.loadStructType(struct_ty.toIntern());26653 const struct_type = ip.loadStructType(struct_ty.toIntern());
2737926654
27380 const field_index = struct_type.nameIndex(ip, field_name) orelse26655 const field_index = struct_type.nameIndex(ip, field_name) orelse
27381 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);26656 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
27382 if (struct_type.fieldIsComptime(ip, field_index)) {26657 if (struct_type.field_is_comptime_bits.get(ip, field_index)) {
27383 try struct_ty.resolveStructFieldInits(pt);26658 try sema.ensureFieldInitsResolved(struct_ty);
27384 return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]);26659 return .fromIntern(struct_type.field_defaults.get(ip)[field_index]);
27385 }26660 }
2738626661
27387 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);26662 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_index]);
27388 if (try sema.typeHasOnePossibleValue(field_ty)) |field_val|26663 if (try field_ty.onePossibleValue(pt)) |field_val|
27389 return Air.internedToRef(field_val.toIntern());26664 return .fromValue(field_val);
2739026665
27391 if (try sema.resolveValue(struct_byval)) |struct_val| {26666 if (try sema.resolveValue(struct_byval)) |struct_val| {
27392 if (struct_val.isUndef(zcu)) return pt.undefRef(field_ty);26667 if (struct_val.isUndef(zcu)) return pt.undefRef(field_ty);
27393 if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {26668 return .fromValue(try struct_val.fieldValue(pt, field_index));
27394 return Air.internedToRef(opv.toIntern());
27395 }
27396 return Air.internedToRef((try struct_val.fieldValue(pt, field_index)).toIntern());
27397 }26669 }
2739826670
27399 try field_ty.resolveLayout(pt);
27400 return block.addStructFieldVal(struct_byval, field_index, field_ty);26671 return block.addStructFieldVal(struct_byval, field_index, field_ty);
27401 },26672 },
27402 .tuple_type => {26673 .tuple_type => {
...@@ -27457,16 +26728,13 @@ fn tupleFieldValByIndex(...@@ -27457,16 +26728,13 @@ fn tupleFieldValByIndex(
27457 const zcu = pt.zcu;26728 const zcu = pt.zcu;
27458 const field_ty = tuple_ty.fieldType(field_index, zcu);26729 const field_ty = tuple_ty.fieldType(field_index, zcu);
2745926730
27460 if (tuple_ty.structFieldIsComptime(field_index, zcu))
27461 try tuple_ty.resolveStructFieldInits(pt);
27462 if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| {26731 if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| {
27463 return Air.internedToRef(default_value.toIntern());26732 return Air.internedToRef(default_value.toIntern());
27464 }26733 }
2746526734
26735 if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
26736
27466 if (try sema.resolveValue(tuple_byval)) |tuple_val| {26737 if (try sema.resolveValue(tuple_byval)) |tuple_val| {
27467 if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
27468 return Air.internedToRef(opv.toIntern());
27469 }
27470 return switch (zcu.intern_pool.indexToKey(tuple_val.toIntern())) {26738 return switch (zcu.intern_pool.indexToKey(tuple_val.toIntern())) {
27471 .undef => pt.undefRef(field_ty),26739 .undef => pt.undefRef(field_ty),
27472 .aggregate => |aggregate| Air.internedToRef(switch (aggregate.storage) {26740 .aggregate => |aggregate| Air.internedToRef(switch (aggregate.storage) {
...@@ -27478,10 +26746,10 @@ fn tupleFieldValByIndex(...@@ -27478,10 +26746,10 @@ fn tupleFieldValByIndex(
27478 };26746 };
27479 }26747 }
2748026748
27481 try field_ty.resolveLayout(pt);
27482 return block.addStructFieldVal(tuple_byval, field_index, field_ty);26749 return block.addStructFieldVal(tuple_byval, field_index, field_ty);
27483}26750}
2748426751
26752/// Asserts that the layout of `union_ty` is already resolved.
27485fn unionFieldPtr(26753fn unionFieldPtr(
27486 sema: *Sema,26754 sema: *Sema,
27487 block: *Block,26755 block: *Block,
...@@ -27497,31 +26765,31 @@ fn unionFieldPtr(...@@ -27497,31 +26765,31 @@ fn unionFieldPtr(
27497 const ip = &zcu.intern_pool;26765 const ip = &zcu.intern_pool;
2749826766
27499 assert(union_ty.zigTypeTag(zcu) == .@"union");26767 assert(union_ty.zigTypeTag(zcu) == .@"union");
26768 union_ty.assertHasLayout(zcu);
2750026769
27501 const union_ptr_ty = sema.typeOf(union_ptr);26770 const union_ptr_ty = sema.typeOf(union_ptr);
27502 const union_ptr_info = union_ptr_ty.ptrInfo(zcu);26771 const union_ptr_info = union_ptr_ty.ptrInfo(zcu);
27503 try union_ty.resolveFields(pt);
27504 const union_obj = zcu.typeToUnion(union_ty).?;26772 const union_obj = zcu.typeToUnion(union_ty).?;
27505 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26773 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
27506 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);26774 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
27507 const ptr_field_ty = try pt.ptrTypeSema(.{26775 const ptr_field_ty = try pt.ptrType(.{
27508 .child = field_ty.toIntern(),26776 .child = field_ty.toIntern(),
27509 .flags = .{26777 .flags = .{
27510 .is_const = union_ptr_info.flags.is_const,26778 .is_const = union_ptr_info.flags.is_const,
27511 .is_volatile = union_ptr_info.flags.is_volatile,26779 .is_volatile = union_ptr_info.flags.is_volatile,
27512 .address_space = union_ptr_info.flags.address_space,26780 .address_space = union_ptr_info.flags.address_space,
27513 .alignment = if (union_obj.flagsUnordered(ip).layout == .auto) blk: {26781 .alignment = a: {
27514 const union_align = if (union_ptr_info.flags.alignment != .none)26782 if (union_obj.layout != .auto) break :a union_ptr_info.flags.alignment;
27515 union_ptr_info.flags.alignment26783 if (union_ptr_info.flags.alignment == .none) {
27516 else26784 break :a union_ty.explicitFieldAlignment(field_index, zcu);
27517 try union_ty.abiAlignmentSema(pt);26785 }
27518 const field_align = try union_ty.fieldAlignmentSema(field_index, pt);26786 const field_align = union_ty.resolvedFieldAlignment(field_index, zcu);
27519 break :blk union_align.min(field_align);26787 break :a union_ptr_info.flags.alignment.min(field_align);
27520 } else union_ptr_info.flags.alignment,26788 },
27521 },26789 },
27522 .packed_offset = union_ptr_info.packed_offset,26790 .packed_offset = union_ptr_info.packed_offset,
27523 });26791 });
27524 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?);26792 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?);
2752526793
27526 if (initializing and field_ty.zigTypeTag(zcu) == .noreturn) {26794 if (initializing and field_ty.zigTypeTag(zcu) == .noreturn) {
27527 const msg = msg: {26795 const msg = msg: {
...@@ -27538,16 +26806,16 @@ fn unionFieldPtr(...@@ -27538,16 +26806,16 @@ fn unionFieldPtr(
27538 }26806 }
2753926807
27540 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {26808 if (try sema.resolveDefinedValue(block, src, union_ptr)) |union_ptr_val| ct: {
27541 switch (union_obj.flagsUnordered(ip).layout) {26809 switch (union_obj.layout) {
27542 .auto => if (initializing) {26810 .auto => if (initializing) {
27543 if (!sema.isComptimeMutablePtr(union_ptr_val)) {26811 if (!sema.isComptimeMutablePtr(union_ptr_val)) {
27544 // The initialization is a runtime operation.26812 // The initialization is a runtime operation.
27545 break :ct;26813 break :ct;
27546 }26814 }
27547 // Store to the union to initialize the tag.26815 // Store to the union to initialize the tag.
27548 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);26816 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);
27549 const payload_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);26817 const payload_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
27550 const new_union_val = try pt.unionValue(union_ty, field_tag, try pt.undefValue(payload_ty));26818 const new_union_val = try pt.unionValue(union_ty, field_tag, try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty));
27551 try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);26819 try sema.storePtrVal(block, src, union_ptr_val, new_union_val, union_ty);
27552 } else {26820 } else {
27553 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse26821 const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
...@@ -27556,12 +26824,12 @@ fn unionFieldPtr(...@@ -27556,12 +26824,12 @@ fn unionFieldPtr(
27556 return sema.failWithUseOfUndef(block, src, null);26824 return sema.failWithUseOfUndef(block, src, null);
27557 }26825 }
27558 const un = ip.indexToKey(union_val.toIntern()).un;26826 const un = ip.indexToKey(union_val.toIntern()).un;
27559 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);26827 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);
27560 const tag_matches = un.tag == field_tag.toIntern();26828 const tag_matches = un.tag == field_tag.toIntern();
27561 if (!tag_matches) {26829 if (!tag_matches) {
27562 const msg = msg: {26830 const msg = msg: {
27563 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;26831 const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
27564 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);26832 const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu);
27565 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{26833 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
27566 field_name.fmt(ip),26834 field_name.fmt(ip),
27567 active_field_name.fmt(ip),26835 active_field_name.fmt(ip),
...@@ -27582,15 +26850,15 @@ fn unionFieldPtr(...@@ -27582,15 +26850,15 @@ fn unionFieldPtr(
27582 // If the union has a tag, we must either set or or safety check it depending on `initializing`.26850 // If the union has a tag, we must either set or or safety check it depending on `initializing`.
27583 tag: {26851 tag: {
27584 if (union_ty.containerLayout(zcu) != .auto) break :tag;26852 if (union_ty.containerLayout(zcu) != .auto) break :tag;
27585 const tag_ty: Type = .fromInterned(union_obj.enum_tag_ty);26853 const tag_ty: Type = .fromInterned(union_obj.enum_tag_type);
27586 if (try sema.typeHasOnePossibleValue(tag_ty) != null) break :tag;26854 if (try tag_ty.onePossibleValue(pt) != null) break :tag;
27587 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but26855 // There is a hypothetical non-trivial tag. We must set it even if not there at runtime, but
27588 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).26856 // only emit a safety check if it's available at runtime (i.e. it's safety-tagged).
27589 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);26857 const want_tag = try pt.enumValueFieldIndex(tag_ty, enum_field_index);
27590 if (initializing) {26858 if (initializing) {
27591 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));26859 const set_tag_inst = try block.addBinOp(.set_union_tag, union_ptr, .fromValue(want_tag));
27592 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store26860 try sema.checkComptimeKnownStore(block, set_tag_inst, .unneeded); // `unneeded` since this isn't a "proper" store
27593 } else if (block.wantSafety() and union_obj.hasTag(ip)) {26861 } else if (block.wantSafety() and union_obj.runtime_tag != .none) {
27594 // The tag exists at runtime (safety tag), so emit a safety check.26862 // The tag exists at runtime (safety tag), so emit a safety check.
27595 // TODO would it be better if get_union_tag supported pointers to unions?26863 // TODO would it be better if get_union_tag supported pointers to unions?
27596 const union_val = try block.addTyOp(.load, union_ty, union_ptr);26864 const union_val = try block.addTyOp(.load, union_ty, union_ptr);
...@@ -27619,26 +26887,25 @@ fn unionFieldVal(...@@ -27619,26 +26887,25 @@ fn unionFieldVal(
27619 const ip = &zcu.intern_pool;26887 const ip = &zcu.intern_pool;
27620 assert(union_ty.zigTypeTag(zcu) == .@"union");26888 assert(union_ty.zigTypeTag(zcu) == .@"union");
2762126889
27622 try union_ty.resolveFields(pt);
27623 const union_obj = zcu.typeToUnion(union_ty).?;26890 const union_obj = zcu.typeToUnion(union_ty).?;
27624 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);26891 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
27625 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);26892 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
27626 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_ty).enumFieldIndex(field_name, zcu).?);26893 const enum_field_index: u32 = @intCast(Type.fromInterned(union_obj.enum_tag_type).enumFieldIndex(field_name, zcu).?);
2762726894
27628 if (try sema.resolveValue(union_byval)) |union_val| {26895 if (try sema.resolveValue(union_byval)) |union_val| {
27629 if (union_val.isUndef(zcu)) return pt.undefRef(field_ty);26896 if (union_val.isUndef(zcu)) return pt.undefRef(field_ty);
2763026897
27631 const un = ip.indexToKey(union_val.toIntern()).un;26898 const un = ip.indexToKey(union_val.toIntern()).un;
27632 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);26899 const field_tag = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);
27633 const tag_matches = un.tag == field_tag.toIntern();26900 const tag_matches = un.tag == field_tag.toIntern();
27634 switch (union_obj.flagsUnordered(ip).layout) {26901 switch (union_obj.layout) {
27635 .auto => {26902 .auto => {
27636 if (tag_matches) {26903 if (tag_matches) {
27637 return Air.internedToRef(un.val);26904 return Air.internedToRef(un.val);
27638 } else {26905 } else {
27639 const msg = msg: {26906 const msg = msg: {
27640 const active_index = Type.fromInterned(union_obj.enum_tag_ty).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;26907 const active_index = Type.fromInterned(union_obj.enum_tag_type).enumTagFieldIndex(Value.fromInterned(un.tag), zcu).?;
27641 const active_field_name = Type.fromInterned(union_obj.enum_tag_ty).enumFieldName(active_index, zcu);26908 const active_field_name = Type.fromInterned(union_obj.enum_tag_type).enumFieldName(active_index, zcu);
27642 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{26909 const msg = try sema.errMsg(src, "access of union field '{f}' while field '{f}' is active", .{
27643 field_name.fmt(ip), active_field_name.fmt(ip),26910 field_name.fmt(ip), active_field_name.fmt(ip),
27644 });26911 });
...@@ -27658,18 +26925,18 @@ fn unionFieldVal(...@@ -27658,18 +26925,18 @@ fn unionFieldVal(
27658 .@"packed" => if (tag_matches) {26925 .@"packed" => if (tag_matches) {
27659 // Fast path - no need to use bitcast logic.26926 // Fast path - no need to use bitcast logic.
27660 return Air.internedToRef(un.val);26927 return Air.internedToRef(un.val);
27661 } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeSema(pt), 0)) |field_val| {26928 } else if (try sema.bitCastVal(union_val, field_ty, 0, union_ty.bitSize(zcu), 0)) |field_val| {
27662 return Air.internedToRef(field_val.toIntern());26929 return Air.internedToRef(field_val.toIntern());
27663 },26930 },
27664 }26931 }
27665 }26932 }
2766626933
27667 if (union_obj.flagsUnordered(ip).layout == .auto and block.wantSafety() and26934 if (union_obj.layout == .auto and block.wantSafety() and
27668 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)26935 union_ty.unionTagTypeSafety(zcu) != null and union_obj.field_types.len > 1)
27669 {26936 {
27670 const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_ty), enum_field_index);26937 const wanted_tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), enum_field_index);
27671 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());26938 const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
27672 const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_ty), union_byval);26939 const active_tag = try block.addTyOp(.get_union_tag, .fromInterned(union_obj.enum_tag_type), union_byval);
27673 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);26940 try sema.addSafetyCheckInactiveUnionField(block, src, active_tag, wanted_tag);
27674 }26941 }
2767526942
...@@ -27678,11 +26945,8 @@ fn unionFieldVal(...@@ -27678,11 +26945,8 @@ fn unionFieldVal(
27678 return .unreachable_value;26945 return .unreachable_value;
27679 }26946 }
2768026947
27681 if (try sema.typeHasOnePossibleValue(field_ty)) |field_only_value| {26948 if (try field_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
27682 return Air.internedToRef(field_only_value.toIntern());
27683 }
2768426949
27685 try field_ty.resolveLayout(pt);
27686 return block.addStructFieldVal(union_byval, field_index, field_ty);26950 return block.addStructFieldVal(union_byval, field_index, field_ty);
27687}26951}
2768826952
...@@ -27706,17 +26970,19 @@ fn elemPtr(...@@ -27706,17 +26970,19 @@ fn elemPtr(
27706 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}),26970 else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{f}'", .{indexable_ptr_ty.fmt(pt)}),
27707 };26971 };
27708 try sema.checkIndexable(block, src, indexable_ty);26972 try sema.checkIndexable(block, src, indexable_ty);
26973 try sema.ensureLayoutResolved(indexable_ty);
2770926974
27710 const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {26975 const elem_ptr = switch (indexable_ty.zigTypeTag(zcu)) {
27711 .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),26976 .array, .vector => try sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
27712 .@"struct" => blk: {26977 .@"struct" => blk: {
27713 // Tuple field access.26978 // Tuple field access.
27714 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });26979 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
27715 const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt));26980 const index: u32 = @intCast(index_val.toUnsignedInt(zcu));
27716 break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);26981 break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
27717 },26982 },
27718 else => {26983 else => {
27719 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);26984 const indexable = try sema.analyzeLoad(block, indexable_ptr_src, indexable_ptr, indexable_ptr_src);
26985 try sema.ensureLayoutResolved(sema.typeOf(indexable).childType(zcu));
27720 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);26986 return elemPtrOneLayerOnly(sema, block, src, indexable, elem_index, elem_index_src, init, oob_safety);
27721 },26987 },
27722 };26988 };
...@@ -27725,7 +26991,7 @@ fn elemPtr(...@@ -27725,7 +26991,7 @@ fn elemPtr(
27725 return elem_ptr;26991 return elem_ptr;
27726}26992}
2772726993
27728/// Asserts that the type of indexable is pointer.26994/// Asserts that `indexable` is an indexable pointer whose child type has its layout already resolved.
27729fn elemPtrOneLayerOnly(26995fn elemPtrOneLayerOnly(
27730 sema: *Sema,26996 sema: *Sema,
27731 block: *Block,26997 block: *Block,
...@@ -27741,7 +27007,10 @@ fn elemPtrOneLayerOnly(...@@ -27741,7 +27007,10 @@ fn elemPtrOneLayerOnly(
27741 const pt = sema.pt;27007 const pt = sema.pt;
27742 const zcu = pt.zcu;27008 const zcu = pt.zcu;
2774327009
27744 try sema.checkIndexable(block, src, indexable_ty);27010 assert(indexable_ty.isIndexable(zcu));
27011 assert(indexable_ty.zigTypeTag(zcu) == .pointer);
27012 const child_ty = indexable_ty.childType(zcu);
27013 child_ty.assertHasLayout(zcu);
2774527014
27746 switch (indexable_ty.ptrSize(zcu)) {27015 switch (indexable_ty.ptrSize(zcu)) {
27747 .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),27016 .slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
...@@ -27751,7 +27020,7 @@ fn elemPtrOneLayerOnly(...@@ -27751,7 +27020,7 @@ fn elemPtrOneLayerOnly(
27751 ct: {27020 ct: {
27752 const ptr_val = maybe_ptr_val orelse break :ct;27021 const ptr_val = maybe_ptr_val orelse break :ct;
27753 const index_val = maybe_index_val orelse break :ct;27022 const index_val = maybe_index_val orelse break :ct;
27754 const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));27023 const index: usize = @intCast(index_val.toUnsignedInt(zcu));
27755 const elem_ptr = try ptr_val.ptrElem(index, pt);27024 const elem_ptr = try ptr_val.ptrElem(index, pt);
27756 return Air.internedToRef(elem_ptr.toIntern());27025 return Air.internedToRef(elem_ptr.toIntern());
27757 }27026 }
...@@ -27762,7 +27031,7 @@ fn elemPtrOneLayerOnly(...@@ -27762,7 +27031,7 @@ fn elemPtrOneLayerOnly(
27762 try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src);27031 try sema.validateRuntimeElemAccess(block, elem_index_src, result_ty, indexable_ty, indexable_src);
27763 try sema.validateRuntimeValue(block, indexable_src, indexable);27032 try sema.validateRuntimeValue(block, indexable_src, indexable);
2776427033
27765 if (!try result_ty.childType(zcu).hasRuntimeBitsIgnoreComptimeSema(pt)) {27034 if (result_ty.childType(zcu).abiSize(zcu) == 0) {
27766 // zero-bit child type; just bitcast the pointer27035 // zero-bit child type; just bitcast the pointer
27767 return block.addBitCast(result_ty, indexable);27036 return block.addBitCast(result_ty, indexable);
27768 }27037 }
...@@ -27770,13 +27039,12 @@ fn elemPtrOneLayerOnly(...@@ -27770,13 +27039,12 @@ fn elemPtrOneLayerOnly(
27770 return block.addPtrElemPtr(indexable, elem_index, result_ty);27039 return block.addPtrElemPtr(indexable, elem_index, result_ty);
27771 },27040 },
27772 .one => {27041 .one => {
27773 const child_ty = indexable_ty.childType(zcu);
27774 const elem_ptr = switch (child_ty.zigTypeTag(zcu)) {27042 const elem_ptr = switch (child_ty.zigTypeTag(zcu)) {
27775 .array, .vector => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety),27043 .array, .vector => try sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety),
27776 .@"struct" => blk: {27044 .@"struct" => blk: {
27777 assert(child_ty.isTuple(zcu));27045 assert(child_ty.isTuple(zcu));
27778 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });27046 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
27779 const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt));27047 const index: u32 = @intCast(index_val.toUnsignedInt(zcu));
27780 break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);27048 break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);
27781 },27049 },
27782 else => unreachable, // Guaranteed by checkIndexable27050 else => unreachable, // Guaranteed by checkIndexable
...@@ -27808,45 +27076,45 @@ fn elemVal(...@@ -27808,45 +27076,45 @@ fn elemVal(
27808 const elem_index = try sema.coerce(block, .usize, elem_index_uncasted, elem_index_src);27076 const elem_index = try sema.coerce(block, .usize, elem_index_uncasted, elem_index_src);
2780927077
27810 switch (indexable_ty.zigTypeTag(zcu)) {27078 switch (indexable_ty.zigTypeTag(zcu)) {
27811 .pointer => switch (indexable_ty.ptrSize(zcu)) {27079 .pointer => {
27812 .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),27080 const child_ty = indexable_ty.childType(zcu);
27813 .many, .c => {27081 try sema.ensureLayoutResolved(child_ty);
27814 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);27082 switch (indexable_ty.ptrSize(zcu)) {
27815 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);27083 .slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
27816 const elem_ty = indexable_ty.elemType2(zcu);27084 .many, .c => {
2781727085 const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
27818 ct: {27086 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
27819 const indexable_val = maybe_indexable_val orelse break :ct;27087
27820 const index_val = maybe_index_val orelse break :ct;27088 ct: {
27821 const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));27089 const indexable_val = maybe_indexable_val orelse break :ct;
27822 const many_ptr_ty = try pt.manyConstPtrType(elem_ty);27090 const index_val = maybe_index_val orelse break :ct;
27823 const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty);27091 const index: usize = @intCast(index_val.toUnsignedInt(zcu));
27824 const elem_ptr_ty = try pt.singleConstPtrType(elem_ty);27092 const many_ptr_ty = try pt.manyConstPtrType(child_ty);
27825 const elem_ptr_val = try many_ptr_val.ptrElem(index, pt);27093 const many_ptr_val = try pt.getCoerced(indexable_val, many_ptr_ty);
27826 const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct;27094 const elem_ptr_ty = try pt.singleConstPtrType(child_ty);
27827 return Air.internedToRef((try pt.getCoerced(elem_val, elem_ty)).toIntern());27095 const elem_ptr_val = try many_ptr_val.ptrElem(index, pt);
27828 }27096 const elem_val = try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty) orelse break :ct;
27097 return Air.internedToRef((try pt.getCoerced(elem_val, child_ty)).toIntern());
27098 }
2782927099
27830 if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_only_value| {27100 if (try child_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
27831 return Air.internedToRef(elem_only_value.toIntern());
27832 }
2783327101
27834 try sema.checkLogicalPtrOperation(block, src, indexable_ty);27102 try sema.checkLogicalPtrOperation(block, src, indexable_ty);
27835 return block.addBinOp(.ptr_elem_val, indexable, elem_index);27103 return block.addBinOp(.ptr_elem_val, indexable, elem_index);
27836 },27104 },
27837 .one => {27105 .one => {
27838 arr_sent: {27106 arr_sent: {
27839 const inner_ty = indexable_ty.childType(zcu);27107 if (child_ty.zigTypeTag(zcu) != .array) break :arr_sent;
27840 if (inner_ty.zigTypeTag(zcu) != .array) break :arr_sent;27108 const sentinel = child_ty.sentinel(zcu) orelse break :arr_sent;
27841 const sentinel = inner_ty.sentinel(zcu) orelse break :arr_sent;27109 const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;
27842 const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;27110 const index = try sema.usizeCast(block, src, index_val.toUnsignedInt(zcu));
27843 const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntSema(pt));27111 if (index != child_ty.arrayLen(zcu)) break :arr_sent;
27844 if (index != inner_ty.arrayLen(zcu)) break :arr_sent;27112 return .fromValue(sentinel);
27845 return Air.internedToRef(sentinel.toIntern());27113 }
27846 }27114 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
27847 const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);27115 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
27848 return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);27116 },
27849 },27117 }
27850 },27118 },
27851 .array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),27119 .array => return sema.elemValArray(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
27852 .vector => {27120 .vector => {
...@@ -27856,7 +27124,7 @@ fn elemVal(...@@ -27856,7 +27124,7 @@ fn elemVal(
27856 .@"struct" => {27124 .@"struct" => {
27857 // Tuple field access.27125 // Tuple field access.
27858 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });27126 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{ .simple = .tuple_field_index });
27859 const index: u32 = @intCast(try index_val.toUnsignedIntSema(pt));27127 const index: u32 = @intCast(index_val.toUnsignedInt(zcu));
27860 return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);27128 return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);
27861 },27129 },
27862 else => unreachable,27130 else => unreachable,
...@@ -27864,6 +27132,7 @@ fn elemVal(...@@ -27864,6 +27132,7 @@ fn elemVal(
27864}27132}
2786527133
27866/// Called when the index or indexable is runtime known.27134/// Called when the index or indexable is runtime known.
27135/// Asserts that the layout of `elem_ty` is already resolved.
27867fn validateRuntimeElemAccess(27136fn validateRuntimeElemAccess(
27868 sema: *Sema,27137 sema: *Sema,
27869 block: *Block,27138 block: *Block,
...@@ -27875,7 +27144,7 @@ fn validateRuntimeElemAccess(...@@ -27875,7 +27144,7 @@ fn validateRuntimeElemAccess(
27875 const pt = sema.pt;27144 const pt = sema.pt;
27876 const zcu = pt.zcu;27145 const zcu = pt.zcu;
2787727146
27878 if (try elem_ty.comptimeOnlySema(sema.pt)) {27147 if (elem_ty.comptimeOnly(zcu)) {
27879 const msg = msg: {27148 const msg = msg: {
27880 const msg = try sema.errMsg(27149 const msg = try sema.errMsg(
27881 elem_index_src,27150 elem_index_src,
...@@ -27900,6 +27169,7 @@ fn validateRuntimeElemAccess(...@@ -27900,6 +27169,7 @@ fn validateRuntimeElemAccess(
27900 }27169 }
27901}27170}
2790227171
27172/// Asserts that the layout of the tuple type is already resolved.
27903fn tupleFieldPtr(27173fn tupleFieldPtr(
27904 sema: *Sema,27174 sema: *Sema,
27905 block: *Block,27175 block: *Block,
...@@ -27914,9 +27184,10 @@ fn tupleFieldPtr(...@@ -27914,9 +27184,10 @@ fn tupleFieldPtr(
27914 const tuple_ptr_ty = sema.typeOf(tuple_ptr);27184 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
27915 const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu);27185 const tuple_ptr_info = tuple_ptr_ty.ptrInfo(zcu);
27916 const tuple_ty: Type = .fromInterned(tuple_ptr_info.child);27186 const tuple_ty: Type = .fromInterned(tuple_ptr_info.child);
27917 try tuple_ty.resolveFields(pt);
27918 const field_count = tuple_ty.structFieldCount(zcu);27187 const field_count = tuple_ty.structFieldCount(zcu);
2791927188
27189 tuple_ty.assertHasLayout(zcu);
27190
27920 if (field_count == 0) {27191 if (field_count == 0) {
27921 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});27192 return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
27922 }27193 }
...@@ -27928,7 +27199,7 @@ fn tupleFieldPtr(...@@ -27928,7 +27199,7 @@ fn tupleFieldPtr(
27928 }27199 }
2792927200
27930 const field_ty = tuple_ty.fieldType(field_index, zcu);27201 const field_ty = tuple_ty.fieldType(field_index, zcu);
27931 const ptr_field_ty = try pt.ptrTypeSema(.{27202 const ptr_field_ty = try pt.ptrType(.{
27932 .child = field_ty.toIntern(),27203 .child = field_ty.toIntern(),
27933 .flags = .{27204 .flags = .{
27934 .is_const = tuple_ptr_info.flags.is_const,27205 .is_const = tuple_ptr_info.flags.is_const,
...@@ -27938,15 +27209,12 @@ fn tupleFieldPtr(...@@ -27938,15 +27209,12 @@ fn tupleFieldPtr(
27938 if (tuple_ptr_info.flags.alignment == .none) break :a .none;27209 if (tuple_ptr_info.flags.alignment == .none) break :a .none;
27939 // The tuple pointer isn't naturally aligned, so the field pointer might be underaligned.27210 // The tuple pointer isn't naturally aligned, so the field pointer might be underaligned.
27940 const tuple_align = tuple_ptr_info.flags.alignment;27211 const tuple_align = tuple_ptr_info.flags.alignment;
27941 const field_align = try field_ty.abiAlignmentSema(pt);27212 const field_align = field_ty.abiAlignment(zcu);
27942 break :a tuple_align.min(field_align);27213 break :a tuple_align.min(field_align);
27943 },27214 },
27944 },27215 },
27945 });27216 });
2794627217
27947 if (tuple_ty.structFieldIsComptime(field_index, zcu))
27948 try tuple_ty.resolveStructFieldInits(pt);
27949
27950 if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_val| {27218 if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_val| {
27951 return Air.internedToRef((try pt.intern(.{ .ptr = .{27219 return Air.internedToRef((try pt.intern(.{ .ptr = .{
27952 .ty = ptr_field_ty.toIntern(),27220 .ty = ptr_field_ty.toIntern(),
...@@ -27978,7 +27246,6 @@ fn tupleField(...@@ -27978,7 +27246,6 @@ fn tupleField(
27978 const pt = sema.pt;27246 const pt = sema.pt;
27979 const zcu = pt.zcu;27247 const zcu = pt.zcu;
27980 const tuple_ty = sema.typeOf(tuple);27248 const tuple_ty = sema.typeOf(tuple);
27981 try tuple_ty.resolveFields(pt);
27982 const field_count = tuple_ty.structFieldCount(zcu);27249 const field_count = tuple_ty.structFieldCount(zcu);
2798327250
27984 if (field_count == 0) {27251 if (field_count == 0) {
...@@ -27993,8 +27260,6 @@ fn tupleField(...@@ -27993,8 +27260,6 @@ fn tupleField(
2799327260
27994 const field_ty = tuple_ty.fieldType(field_index, zcu);27261 const field_ty = tuple_ty.fieldType(field_index, zcu);
2799527262
27996 if (tuple_ty.structFieldIsComptime(field_index, zcu))
27997 try tuple_ty.resolveStructFieldInits(pt);
27998 if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| {27263 if (try tuple_ty.structFieldValueComptime(pt, field_index)) |default_value| {
27999 return Air.internedToRef(default_value.toIntern()); // comptime field27264 return Air.internedToRef(default_value.toIntern()); // comptime field
28000 }27265 }
...@@ -28006,7 +27271,6 @@ fn tupleField(...@@ -28006,7 +27271,6 @@ fn tupleField(
2800627271
28007 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);27272 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
2800827273
28009 try field_ty.resolveLayout(pt);
28010 return block.addStructFieldVal(tuple, field_index, field_ty);27274 return block.addStructFieldVal(tuple, field_index, field_ty);
28011}27275}
2801227276
...@@ -28037,7 +27301,7 @@ fn elemValArray(...@@ -28037,7 +27301,7 @@ fn elemValArray(
28037 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);27301 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
2803827302
28039 if (maybe_index_val) |index_val| {27303 if (maybe_index_val) |index_val| {
28040 const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));27304 const index: usize = @intCast(index_val.toUnsignedInt(zcu));
28041 if (array_sent) |s| {27305 if (array_sent) |s| {
28042 if (index == array_len) {27306 if (index == array_len) {
28043 return Air.internedToRef(s.toIntern());27307 return Air.internedToRef(s.toIntern());
...@@ -28053,10 +27317,11 @@ fn elemValArray(...@@ -28053,10 +27317,11 @@ fn elemValArray(
28053 return pt.undefRef(elem_ty);27317 return pt.undefRef(elem_ty);
28054 }27318 }
28055 if (maybe_index_val) |index_val| {27319 if (maybe_index_val) |index_val| {
28056 const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));27320 const index: usize = @intCast(index_val.toUnsignedInt(zcu));
28057 const elem_val = try array_val.elemValue(pt, index);27321 return .fromValue(try array_val.elemValue(pt, index));
28058 return Air.internedToRef(elem_val.toIntern());
28059 }27322 }
27323 // Since the array is comptime-known, it might be OPV, in which case the index is irrelevant.
27324 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
28060 }27325 }
2806127326
28062 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);27327 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, array_ty, array_src);
...@@ -28071,12 +27336,10 @@ fn elemValArray(...@@ -28071,12 +27336,10 @@ fn elemValArray(
28071 }27336 }
28072 }27337 }
2807327338
28074 if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_val|
28075 return Air.internedToRef(elem_val.toIntern());
28076
28077 return block.addBinOp(.array_elem_val, array, elem_index);27339 return block.addBinOp(.array_elem_val, array, elem_index);
28078}27340}
2807927341
27342/// Asserts that the layout of the array or vector is already resolved.
28080fn elemPtrArray(27343fn elemPtrArray(
28081 sema: *Sema,27344 sema: *Sema,
28082 block: *Block,27345 block: *Block,
...@@ -28103,7 +27366,7 @@ fn elemPtrArray(...@@ -28103,7 +27366,7 @@ fn elemPtrArray(
28103 const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr);27366 const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr);
28104 // The index must not be undefined since it can be out of bounds.27367 // The index must not be undefined since it can be out of bounds.
28105 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {27368 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
28106 const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(pt));27369 const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(zcu));
28107 if (index >= array_len_s) {27370 if (index >= array_len_s) {
28108 const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";27371 const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
28109 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });27372 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
...@@ -28115,6 +27378,7 @@ fn elemPtrArray(...@@ -28115,6 +27378,7 @@ fn elemPtrArray(
28115 return sema.fail(block, elem_index_src, "vector index not comptime known", .{});27378 return sema.fail(block, elem_index_src, "vector index not comptime known", .{});
28116 }27379 }
2811727380
27381 array_ty.assertHasLayout(zcu);
28118 const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, pt);27382 const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, pt);
2811927383
28120 if (maybe_undef_array_ptr_val) |array_ptr_val| {27384 if (maybe_undef_array_ptr_val) |array_ptr_val| {
...@@ -28128,7 +27392,7 @@ fn elemPtrArray(...@@ -28128,7 +27392,7 @@ fn elemPtrArray(
28128 }27392 }
2812927393
28130 if (!init) {27394 if (!init) {
28131 try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(zcu), array_ty, array_ptr_src);27395 try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.childType(zcu), array_ty, array_ptr_src);
28132 try sema.validateRuntimeValue(block, array_ptr_src, array_ptr);27396 try sema.validateRuntimeValue(block, array_ptr_src, array_ptr);
28133 }27397 }
2813427398
...@@ -28142,6 +27406,7 @@ fn elemPtrArray(...@@ -28142,6 +27406,7 @@ fn elemPtrArray(
28142 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);27406 return block.addPtrElemPtr(array_ptr, elem_index, elem_ptr_ty);
28143}27407}
2814427408
27409/// Asserts that the layout of the slice element type is already resolved.
28145fn elemValSlice(27410fn elemValSlice(
28146 sema: *Sema,27411 sema: *Sema,
28147 block: *Block,27412 block: *Block,
...@@ -28156,9 +27421,11 @@ fn elemValSlice(...@@ -28156,9 +27421,11 @@ fn elemValSlice(
28156 const zcu = pt.zcu;27421 const zcu = pt.zcu;
28157 const slice_ty = sema.typeOf(slice);27422 const slice_ty = sema.typeOf(slice);
28158 const slice_sent = slice_ty.sentinel(zcu) != null;27423 const slice_sent = slice_ty.sentinel(zcu) != null;
28159 const elem_ty = slice_ty.elemType2(zcu);27424 const elem_ty = slice_ty.childType(zcu);
28160 var runtime_src = slice_src;27425 var runtime_src = slice_src;
2816127426
27427 elem_ty.assertHasLayout(zcu);
27428
28162 // slice must be defined since it can dereferenced as null27429 // slice must be defined since it can dereferenced as null
28163 const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice);27430 const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice);
28164 // index must be defined since it can index out of bounds27431 // index must be defined since it can index out of bounds
...@@ -28166,13 +27433,13 @@ fn elemValSlice(...@@ -28166,13 +27433,13 @@ fn elemValSlice(
2816627433
28167 if (maybe_slice_val) |slice_val| {27434 if (maybe_slice_val) |slice_val| {
28168 runtime_src = elem_index_src;27435 runtime_src = elem_index_src;
28169 const slice_len = try slice_val.sliceLen(pt);27436 const slice_len = slice_val.sliceLen(zcu);
28170 const slice_len_s = slice_len + @intFromBool(slice_sent);27437 const slice_len_s = slice_len + @intFromBool(slice_sent);
28171 if (slice_len_s == 0) {27438 if (slice_len_s == 0) {
28172 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});27439 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
28173 }27440 }
28174 if (maybe_index_val) |index_val| {27441 if (maybe_index_val) |index_val| {
28175 const index: usize = @intCast(try index_val.toUnsignedIntSema(pt));27442 const index: usize = @intCast(index_val.toUnsignedInt(zcu));
28176 if (index >= slice_len_s) {27443 if (index >= slice_len_s) {
28177 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";27444 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
28178 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });27445 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
...@@ -28186,16 +27453,14 @@ fn elemValSlice(...@@ -28186,16 +27453,14 @@ fn elemValSlice(
28186 }27453 }
28187 }27454 }
2818827455
28189 if (try sema.typeHasOnePossibleValue(elem_ty)) |elem_only_value| {27456 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
28190 return Air.internedToRef(elem_only_value.toIntern());
28191 }
2819227457
28193 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);27458 try sema.validateRuntimeElemAccess(block, elem_index_src, elem_ty, slice_ty, slice_src);
28194 try sema.validateRuntimeValue(block, slice_src, slice);27459 try sema.validateRuntimeValue(block, slice_src, slice);
2819527460
28196 if (oob_safety and block.wantSafety()) {27461 if (oob_safety and block.wantSafety()) {
28197 const len_inst = if (maybe_slice_val) |slice_val|27462 const len_inst = if (maybe_slice_val) |slice_val|
28198 try pt.intRef(.usize, try slice_val.sliceLen(pt))27463 try pt.intRef(.usize, slice_val.sliceLen(zcu))
28199 else27464 else
28200 try block.addTyOp(.slice_len, .usize, slice);27465 try block.addTyOp(.slice_len, .usize, slice);
28201 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;27466 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
...@@ -28204,6 +27469,7 @@ fn elemValSlice(...@@ -28204,6 +27469,7 @@ fn elemValSlice(
28204 return block.addBinOp(.slice_elem_val, slice, elem_index);27469 return block.addBinOp(.slice_elem_val, slice, elem_index);
28205}27470}
2820627471
27472/// Asserts that the layout of the slice element type is already resolved.
28207fn elemPtrSlice(27473fn elemPtrSlice(
28208 sema: *Sema,27474 sema: *Sema,
28209 block: *Block,27475 block: *Block,
...@@ -28219,11 +27485,12 @@ fn elemPtrSlice(...@@ -28219,11 +27485,12 @@ fn elemPtrSlice(
28219 const slice_ty = sema.typeOf(slice);27485 const slice_ty = sema.typeOf(slice);
28220 const slice_sent = slice_ty.sentinel(zcu) != null;27486 const slice_sent = slice_ty.sentinel(zcu) != null;
2822127487
27488 slice_ty.childType(zcu).assertHasLayout(zcu);
27489
28222 const maybe_undef_slice_val = try sema.resolveValue(slice);27490 const maybe_undef_slice_val = try sema.resolveValue(slice);
28223 // The index must not be undefined since it can be out of bounds.27491 // The index must not be undefined since it can be out of bounds.
28224 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {27492 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
28225 const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(pt));27493 break :o try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(zcu));
28226 break :o index;
28227 } else null;27494 } else null;
2822827495
28229 const elem_ptr_ty = try slice_ty.elemPtrType(offset, pt);27496 const elem_ptr_ty = try slice_ty.elemPtrType(offset, pt);
...@@ -28232,7 +27499,7 @@ fn elemPtrSlice(...@@ -28232,7 +27499,7 @@ fn elemPtrSlice(
28232 if (slice_val.isUndef(zcu)) {27499 if (slice_val.isUndef(zcu)) {
28233 return pt.undefRef(elem_ptr_ty);27500 return pt.undefRef(elem_ptr_ty);
28234 }27501 }
28235 const slice_len = try slice_val.sliceLen(pt);27502 const slice_len = slice_val.sliceLen(zcu);
28236 const slice_len_s = slice_len + @intFromBool(slice_sent);27503 const slice_len_s = slice_len + @intFromBool(slice_sent);
28237 if (slice_len_s == 0) {27504 if (slice_len_s == 0) {
28238 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});27505 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
...@@ -28254,13 +27521,13 @@ fn elemPtrSlice(...@@ -28254,13 +27521,13 @@ fn elemPtrSlice(
28254 const len_inst = len: {27521 const len_inst = len: {
28255 if (maybe_undef_slice_val) |slice_val|27522 if (maybe_undef_slice_val) |slice_val|
28256 if (!slice_val.isUndef(zcu))27523 if (!slice_val.isUndef(zcu))
28257 break :len try pt.intRef(.usize, try slice_val.sliceLen(pt));27524 break :len try pt.intRef(.usize, slice_val.sliceLen(zcu));
28258 break :len try block.addTyOp(.slice_len, .usize, slice);27525 break :len try block.addTyOp(.slice_len, .usize, slice);
28259 };27526 };
28260 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;27527 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
28261 try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op);27528 try sema.addSafetyCheckIndexOob(block, src, elem_index, len_inst, cmp_op);
28262 }27529 }
28263 if (!try slice_ty.childType(zcu).hasRuntimeBitsIgnoreComptimeSema(pt)) {27530 if (slice_ty.childType(zcu).abiSize(zcu) == 0) {
28264 // zero-bit child type; just extract the pointer and bitcast it27531 // zero-bit child type; just extract the pointer and bitcast it
28265 const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice);27532 const slice_ptr = try block.addTyOp(.slice_ptr, slice_ty.slicePtrFieldType(zcu), slice);
28266 return block.addBitCast(elem_ptr_ty, slice_ptr);27533 return block.addBitCast(elem_ptr_ty, slice_ptr);
...@@ -28331,10 +27598,12 @@ fn coerceExtra(...@@ -28331,10 +27598,12 @@ fn coerceExtra(
28331 if (dest_ty.isGenericPoison()) return inst;27598 if (dest_ty.isGenericPoison()) return inst;
2833227599
28333 const dest_ty_src = inst_src; // TODO better source location27600 const dest_ty_src = inst_src; // TODO better source location
28334 try dest_ty.resolveFields(pt);
28335 const inst_ty = sema.typeOf(inst);27601 const inst_ty = sema.typeOf(inst);
28336 try inst_ty.resolveFields(pt);
28337 const target = zcu.getTarget();27602 const target = zcu.getTarget();
27603
27604 inst_ty.assertHasLayout(zcu);
27605 try sema.ensureLayoutResolved(dest_ty);
27606
28338 // If the types are the same, we can return the operand.27607 // If the types are the same, we can return the operand.
28339 if (dest_ty.eql(inst_ty, zcu))27608 if (dest_ty.eql(inst_ty, zcu))
28340 return inst;27609 return inst;
...@@ -28357,7 +27626,7 @@ fn coerceExtra(...@@ -28357,7 +27626,7 @@ fn coerceExtra(
28357 if (maybe_inst_val) |val| {27626 if (maybe_inst_val) |val| {
28358 // undefined sets the optional bit also to undefined.27627 // undefined sets the optional bit also to undefined.
28359 if (val.toIntern() == .undef) {27628 if (val.toIntern() == .undef) {
28360 return pt.undefRef(dest_ty);27629 return .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty));
28361 }27630 }
2836227631
28363 // null to ?T27632 // null to ?T
...@@ -28372,11 +27641,11 @@ fn coerceExtra(...@@ -28372,11 +27641,11 @@ fn coerceExtra(
28372 // cast from ?*T and ?[*]T to ?*anyopaque27641 // cast from ?*T and ?[*]T to ?*anyopaque
28373 // but don't do it if the source type is a double pointer27642 // but don't do it if the source type is a double pointer
28374 if (dest_ty.isPtrLikeOptional(zcu) and27643 if (dest_ty.isPtrLikeOptional(zcu) and
28375 dest_ty.elemType2(zcu).toIntern() == .anyopaque_type and27644 dest_ty.nullablePtrElem(zcu).toIntern() == .anyopaque_type and
28376 inst_ty.isPtrAtRuntime(zcu))27645 inst_ty.isPtrAtRuntime(zcu))
28377 anyopaque_check: {27646 anyopaque_check: {
28378 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;27647 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
28379 const elem_ty = inst_ty.elemType2(zcu);27648 const elem_ty = inst_ty.nullablePtrElem(zcu);
28380 if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) {27649 if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) {
28381 in_memory_result = .{ .double_ptr_to_anyopaque = .{27650 in_memory_result = .{ .double_ptr_to_anyopaque = .{
28382 .actual = inst_ty,27651 .actual = inst_ty,
...@@ -28520,7 +27789,7 @@ fn coerceExtra(...@@ -28520,7 +27789,7 @@ fn coerceExtra(
28520 // but don't do it if the source type is a double pointer27789 // but don't do it if the source type is a double pointer
28521 if (dest_info.child == .anyopaque_type and inst_ty.zigTypeTag(zcu) == .pointer) to_anyopaque: {27790 if (dest_info.child == .anyopaque_type and inst_ty.zigTypeTag(zcu) == .pointer) to_anyopaque: {
28522 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;27791 if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
28523 const elem_ty = inst_ty.elemType2(zcu);27792 const elem_ty = inst_ty.childType(zcu);
28524 if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) {27793 if (elem_ty.zigTypeTag(zcu) == .pointer or elem_ty.isPtrLikeOptional(zcu)) {
28525 in_memory_result = .{ .double_ptr_to_anyopaque = .{27794 in_memory_result = .{ .double_ptr_to_anyopaque = .{
28526 .actual = inst_ty,27795 .actual = inst_ty,
...@@ -28616,7 +27885,9 @@ fn coerceExtra(...@@ -28616,7 +27885,9 @@ fn coerceExtra(
28616 // empty tuple to zero-length slice27885 // empty tuple to zero-length slice
28617 // note that this allows coercing to a mutable slice.27886 // note that this allows coercing to a mutable slice.
28618 if (inst_child_ty.structFieldCount(zcu) == 0) {27887 if (inst_child_ty.structFieldCount(zcu) == 0) {
28619 const align_val = try dest_ty.ptrAlignmentSema(pt);27888 // TODO MLUGG: this is *unacceptably* stupid. we're resolving the child for the alignment value
27889 try sema.ensureLayoutResolved(dest_ty.childType(zcu));
27890 const align_val = dest_ty.ptrAlignment(zcu);
28620 return Air.internedToRef(try pt.intern(.{ .slice = .{27891 return Air.internedToRef(try pt.intern(.{ .slice = .{
28621 .ty = dest_ty.toIntern(),27892 .ty = dest_ty.toIntern(),
28622 .ptr = try pt.intern(.{ .ptr = .{27893 .ptr = try pt.intern(.{ .ptr = .{
...@@ -28689,7 +27960,7 @@ fn coerceExtra(...@@ -28689,7 +27960,7 @@ fn coerceExtra(
28689 return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });27960 return sema.fail(block, inst_src, "type '{f}' cannot represent integer value '{f}'", .{ dest_ty.fmt(pt), val.fmtValueSema(pt, sema) });
28690 }27961 }
28691 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {27962 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
28692 .undef => try pt.undefRef(dest_ty),27963 .undef => .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty)),
28693 .int => |int| Air.internedToRef(27964 .int => |int| Air.internedToRef(
28694 try zcu.intern_pool.getCoercedInts(gpa, io, pt.tid, int, dest_ty.toIntern()),27965 try zcu.intern_pool.getCoercedInts(gpa, io, pt.tid, int, dest_ty.toIntern()),
28695 ),27966 ),
...@@ -28768,7 +28039,7 @@ fn coerceExtra(...@@ -28768,7 +28039,7 @@ fn coerceExtra(
28768 }28039 }
28769 break :int;28040 break :int;
28770 };28041 };
28771 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, pt, .sema);28042 const result_val = try pt.floatValue(dest_ty, val.toFloat(f128, zcu));
28772 const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {28043 const fits: bool = switch (ip.indexToKey(result_val.toIntern())) {
28773 else => unreachable,28044 else => unreachable,
28774 .undef => true,28045 .undef => true,
...@@ -28905,11 +28176,11 @@ fn coerceExtra(...@@ -28905,11 +28176,11 @@ fn coerceExtra(
28905 else => true,28176 else => true,
28906 };28177 };
2890728178
28908 if (can_coerce_to) {28179 if (can_coerce_to and inst == .undef) {
28909 // undefined to anything. We do this after the big switch above so that28180 // undefined to anything. We do this after the big switch above so that
28910 // special logic has a chance to run first, such as `*[N]T` to `[]T` which28181 // special logic has a chance to run first, such as `*[N]T` to `[]T` which
28911 // should initialize the length field of the slice.28182 // should initialize the length field of the slice.
28912 if (maybe_inst_val) |val| if (val.toIntern() == .undef) return pt.undefRef(dest_ty);28183 return .fromValue(try dest_ty.onePossibleValue(pt) orelse try pt.undefValue(dest_ty));
28913 }28184 }
2891428185
28915 if (!opts.report_err) return error.NotCoercible;28186 if (!opts.report_err) return error.NotCoercible;
...@@ -29444,17 +28715,13 @@ pub fn coerceInMemoryAllowed(...@@ -29444,17 +28715,13 @@ pub fn coerceInMemoryAllowed(
29444 }28715 }
2944528716
29446 // Pointers / Pointer-like Optionals28717 // Pointers / Pointer-like Optionals
29447 const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty);28718 if (dest_ty.isPtrAtRuntime(zcu) and src_ty.isPtrAtRuntime(zcu)) {
29448 const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);28719 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
29449 if (maybe_dest_ptr_ty) |dest_ptr_ty| {
29450 if (maybe_src_ptr_ty) |src_ptr_ty| {
29451 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
29452 }
29453 }28720 }
2945428721
29455 // Slices28722 // Slices
29456 if (dest_ty.isSlice(zcu) and src_ty.isSlice(zcu)) {28723 if (dest_ty.isSlice(zcu) and src_ty.isSlice(zcu)) {
29457 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);28724 return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
29458 }28725 }
2945928726
29460 // Functions28727 // Functions
...@@ -29554,7 +28821,8 @@ pub fn coerceInMemoryAllowed(...@@ -29554,7 +28821,8 @@ pub fn coerceInMemoryAllowed(
2955428821
29555 // Optionals28822 // Optionals
29556 if (dest_tag == .optional and src_tag == .optional) {28823 if (dest_tag == .optional and src_tag == .optional) {
29557 if ((maybe_dest_ptr_ty != null) != (maybe_src_ptr_ty != null)) {28824 if (dest_ty.isPtrAtRuntime(zcu) or src_ty.isPtrAtRuntime(zcu)) {
28825 // Only one is, because we already handled when both are.
29558 return .{ .optional_shape = .{28826 return .{ .optional_shape = .{
29559 .actual = src_ty,28827 .actual = src_ty,
29560 .wanted = dest_ty,28828 .wanted = dest_ty,
...@@ -29581,7 +28849,7 @@ pub fn coerceInMemoryAllowed(...@@ -29581,7 +28849,7 @@ pub fn coerceInMemoryAllowed(
29581 const field_count = dest_ty.structFieldCount(zcu);28849 const field_count = dest_ty.structFieldCount(zcu);
29582 for (0..field_count) |field_idx| {28850 for (0..field_count) |field_idx| {
29583 if (dest_ty.structFieldIsComptime(field_idx, zcu) != src_ty.structFieldIsComptime(field_idx, zcu)) break :tuple;28851 if (dest_ty.structFieldIsComptime(field_idx, zcu) != src_ty.structFieldIsComptime(field_idx, zcu)) break :tuple;
29584 if (dest_ty.fieldAlignment(field_idx, zcu) != src_ty.fieldAlignment(field_idx, zcu)) break :tuple;28852 if (dest_ty.resolvedFieldAlignment(field_idx, zcu) != src_ty.resolvedFieldAlignment(field_idx, zcu)) break :tuple;
29585 const dest_field_ty = dest_ty.fieldType(field_idx, zcu);28853 const dest_field_ty = dest_ty.fieldType(field_idx, zcu);
29586 const src_field_ty = src_ty.fieldType(field_idx, zcu);28854 const src_field_ty = src_ty.fieldType(field_idx, zcu);
29587 const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null);28855 const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src, null);
...@@ -29714,11 +28982,7 @@ fn coerceInMemoryAllowedFns(...@@ -29714,11 +28982,7 @@ fn coerceInMemoryAllowedFns(
2971428982
29715 {28983 {
29716 if (dest_info.is_var_args != src_info.is_var_args) {28984 if (dest_info.is_var_args != src_info.is_var_args) {
29717 return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };28985 return .{ .fn_var_args = dest_info.is_var_args };
29718 }
29719
29720 if (dest_info.is_generic != src_info.is_generic) {
29721 return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
29722 }28986 }
2972328987
29724 const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and28988 const callconv_ok = callconvCoerceAllowed(target, src_info.cc, dest_info.cc) and
...@@ -29731,6 +28995,12 @@ fn coerceInMemoryAllowedFns(...@@ -29731,6 +28995,12 @@ fn coerceInMemoryAllowedFns(
29731 } };28995 } };
29732 }28996 }
2973328997
28998 try sema.ensureLayoutResolved(src_ty);
28999 try sema.ensureLayoutResolved(dest_ty);
29000 const src_is_runtime = src_ty.fnHasRuntimeBits(zcu);
29001 const dest_is_runtime = dest_ty.fnHasRuntimeBits(zcu);
29002 if (src_is_runtime != dest_is_runtime) return .{ .fn_generic = !dest_is_runtime };
29003
29734 if (!switch (src_info.return_type) {29004 if (!switch (src_info.return_type) {
29735 .generic_poison_type => true,29005 .generic_poison_type => true,
29736 .noreturn_type => !dest_is_mut,29006 .noreturn_type => !dest_is_mut,
...@@ -29780,7 +29050,8 @@ fn coerceInMemoryAllowedFns(...@@ -29780,7 +29050,8 @@ fn coerceInMemoryAllowedFns(
29780 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));29050 const src_is_comptime = src_info.paramIsComptime(@intCast(param_i));
29781 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));29051 const dest_is_comptime = dest_info.paramIsComptime(@intCast(param_i));
29782 if (src_is_comptime == dest_is_comptime) break :comptime_param;29052 if (src_is_comptime == dest_is_comptime) break :comptime_param;
29783 if (!dest_is_mut and src_is_comptime and !dest_is_comptime and try dest_param_ty.comptimeOnlySema(pt)) {29053 try sema.ensureLayoutResolved(dest_param_ty);
29054 if (!dest_is_mut and src_is_comptime and !dest_is_comptime and dest_param_ty.comptimeOnly(zcu)) {
29784 // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only.29055 // A parameter which is marked `comptime` can drop that annotation if the type is comptime-only.
29785 // The function remains generic, and the parameter is going to be comptime-resolved either way,29056 // The function remains generic, and the parameter is going to be comptime-resolved either way,
29786 // so this just affects whether or not the argument is comptime-evaluated at the call site.29057 // so this just affects whether or not the argument is comptime-evaluated at the call site.
...@@ -29861,8 +29132,6 @@ fn coerceInMemoryAllowedPtrs(...@@ -29861,8 +29132,6 @@ fn coerceInMemoryAllowedPtrs(
29861 block: *Block,29132 block: *Block,
29862 dest_ty: Type,29133 dest_ty: Type,
29863 src_ty: Type,29134 src_ty: Type,
29864 dest_ptr_ty: Type,
29865 src_ptr_ty: Type,
29866 /// If set, the coercion must be valid in both directions.29135 /// If set, the coercion must be valid in both directions.
29867 dest_is_mut: bool,29136 dest_is_mut: bool,
29868 target: *const std.Target,29137 target: *const std.Target,
...@@ -29875,8 +29144,8 @@ fn coerceInMemoryAllowedPtrs(...@@ -29875,8 +29144,8 @@ fn coerceInMemoryAllowedPtrs(
29875 const gpa = comp.gpa;29144 const gpa = comp.gpa;
29876 const io = comp.io;29145 const io = comp.io;
2987729146
29878 const dest_info = dest_ptr_ty.ptrInfo(zcu);29147 const dest_info = dest_ty.ptrInfo(zcu);
29879 const src_info = src_ptr_ty.ptrInfo(zcu);29148 const src_info = src_ty.ptrInfo(zcu);
2988029149
29881 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or29150 const ok_ptr_size = src_info.flags.size == dest_info.flags.size or
29882 src_info.flags.size == .c or dest_info.flags.size == .c;29151 src_info.flags.size == .c or dest_info.flags.size == .c;
...@@ -30008,16 +29277,14 @@ fn coerceInMemoryAllowedPtrs(...@@ -30008,16 +29277,14 @@ fn coerceInMemoryAllowedPtrs(
30008 if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or29277 if (src_info.flags.alignment != .none or dest_info.flags.alignment != .none or
30009 dest_info.child != src_info.child)29278 dest_info.child != src_info.child)
30010 {29279 {
30011 const src_align = if (src_info.flags.alignment != .none)29280 const src_align = if (src_info.flags.alignment == .none) a: {
30012 src_info.flags.alignment29281 try sema.ensureLayoutResolved(src_child);
30013 else29282 break :a src_child.abiAlignment(zcu);
30014 try Type.fromInterned(src_info.child).abiAlignmentSema(pt);29283 } else src_info.flags.alignment;
3001529284 const dest_align = if (dest_info.flags.alignment == .none) a: {
30016 const dest_align = if (dest_info.flags.alignment != .none)29285 try sema.ensureLayoutResolved(dest_child);
30017 dest_info.flags.alignment29286 break :a dest_child.abiAlignment(zcu);
30018 else29287 } else dest_info.flags.alignment;
30019 try Type.fromInterned(dest_info.child).abiAlignmentSema(pt);
30020
30021 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {29288 if (dest_align.compare(if (dest_is_mut) .neq else .gt, src_align)) {
30022 return InMemoryCoercionResult{ .ptr_alignment = .{29289 return InMemoryCoercionResult{ .ptr_alignment = .{
30023 .actual = src_align,29290 .actual = src_align,
...@@ -30180,9 +29447,16 @@ fn storePtr2(...@@ -30180,9 +29447,16 @@ fn storePtr2(
30180 return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);29447 return sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
30181 };29448 };
3018229449
29450 // We do this after the possible comptime store above, for the case of field_ptr stores
29451 // to unions because we want the comptime tag to be set, even if the field type is void.
29452 // MLUGG TODO: that's insane, the runtime and comptime sematics should be the same. just set the tag at the same damn time
29453 if (try elem_ty.onePossibleValue(pt) != null) {
29454 return;
29455 }
29456
30183 // We're performing the store at runtime; as such, we need to make sure the pointee type29457 // We're performing the store at runtime; as such, we need to make sure the pointee type
30184 // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.29458 // is not comptime-only. We can hit this case with a `@ptrFromInt` pointer.
30185 if (try elem_ty.comptimeOnlySema(pt)) {29459 if (elem_ty.comptimeOnly(zcu)) {
30186 return sema.failWithOwnedErrorMsg(block, msg: {29460 return sema.failWithOwnedErrorMsg(block, msg: {
30187 const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});29461 const msg = try sema.errMsg(src, "cannot store comptime-only type '{f}' at runtime", .{elem_ty.fmt(pt)});
30188 errdefer msg.destroy(sema.gpa);29462 errdefer msg.destroy(sema.gpa);
...@@ -30191,12 +29465,6 @@ fn storePtr2(...@@ -30191,12 +29465,6 @@ fn storePtr2(
30191 });29465 });
30192 }29466 }
3019329467
30194 // We do this after the possible comptime store above, for the case of field_ptr stores
30195 // to unions because we want the comptime tag to be set, even if the field type is void.
30196 if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {
30197 return;
30198 }
30199
30200 try sema.requireRuntimeBlock(block, src, runtime_src);29468 try sema.requireRuntimeBlock(block, src, runtime_src);
3020129469
30202 const store_inst = if (is_ret)29470 const store_inst = if (is_ret)
...@@ -30361,10 +29629,10 @@ fn bitCast(...@@ -30361,10 +29629,10 @@ fn bitCast(
30361) CompileError!Air.Inst.Ref {29629) CompileError!Air.Inst.Ref {
30362 const pt = sema.pt;29630 const pt = sema.pt;
30363 const zcu = pt.zcu;29631 const zcu = pt.zcu;
30364 try dest_ty.resolveLayout(pt);
30365
30366 const old_ty = sema.typeOf(inst);29632 const old_ty = sema.typeOf(inst);
30367 try old_ty.resolveLayout(pt);29633
29634 old_ty.assertHasLayout(zcu);
29635 try sema.ensureLayoutResolved(dest_ty);
3036829636
30369 const dest_bits = dest_ty.bitSize(zcu);29637 const dest_bits = dest_ty.bitSize(zcu);
30370 const old_bits = old_ty.bitSize(zcu);29638 const old_bits = old_ty.bitSize(zcu);
...@@ -30510,9 +29778,7 @@ fn coerceCompatiblePtrs(...@@ -30510,9 +29778,7 @@ fn coerceCompatiblePtrs(
30510 }29778 }
30511 try sema.requireRuntimeBlock(block, inst_src, null);29779 try sema.requireRuntimeBlock(block, inst_src, null);
30512 const inst_allows_zero = inst_ty.zigTypeTag(zcu) != .pointer or inst_ty.ptrAllowsZero(zcu);29780 const inst_allows_zero = inst_ty.zigTypeTag(zcu) != .pointer or inst_ty.ptrAllowsZero(zcu);
30513 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu) and29781 if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(zcu)) {
30514 (try dest_ty.elemType2(zcu).hasRuntimeBitsSema(pt) or dest_ty.elemType2(zcu).zigTypeTag(zcu) == .@"fn"))
30515 {
30516 try sema.checkLogicalPtrOperation(block, inst_src, inst_ty);29782 try sema.checkLogicalPtrOperation(block, inst_src, inst_ty);
30517 const actual_ptr = if (inst_ty.isSlice(zcu))29783 const actual_ptr = if (inst_ty.isSlice(zcu))
30518 try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)29784 try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
...@@ -30532,6 +29798,7 @@ fn coerceCompatiblePtrs(...@@ -30532,6 +29798,7 @@ fn coerceCompatiblePtrs(
30532 return new_ptr;29798 return new_ptr;
30533}29799}
3053429800
29801/// Asserts that the layout of `union_ty` is already resolved.
30535fn coerceEnumToUnion(29802fn coerceEnumToUnion(
30536 sema: *Sema,29803 sema: *Sema,
30537 block: *Block,29804 block: *Block,
...@@ -30545,18 +29812,21 @@ fn coerceEnumToUnion(...@@ -30545,18 +29812,21 @@ fn coerceEnumToUnion(
30545 const ip = &zcu.intern_pool;29812 const ip = &zcu.intern_pool;
30546 const inst_ty = sema.typeOf(inst);29813 const inst_ty = sema.typeOf(inst);
3054729814
30548 const tag_ty = union_ty.unionTagType(zcu) orelse {29815 union_ty.assertHasLayout(zcu);
30549 const msg = msg: {29816
30550 const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);29817 const union_obj = zcu.typeToUnion(union_ty).?;
30551 errdefer msg.destroy(sema.gpa);29818 const enum_ty: Type = .fromInterned(union_obj.enum_tag_type);
30552 try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});29819 const enum_obj = ip.loadEnumType(enum_ty.toIntern());
30553 try sema.addDeclaredHereNote(msg, union_ty);29820
30554 break :msg msg;29821 if (union_obj.runtime_tag != .tagged) return sema.failWithOwnedErrorMsg(block, msg: {
30555 };29822 const msg = try sema.typeMismatchErrMsg(inst_src, union_ty, inst_ty);
30556 return sema.failWithOwnedErrorMsg(block, msg);29823 errdefer msg.destroy(sema.gpa);
30557 };29824 try sema.errNote(union_ty_src, msg, "cannot coerce enum to untagged union", .{});
29825 try sema.addDeclaredHereNote(msg, union_ty);
29826 break :msg msg;
29827 });
3055829828
30559 const enum_tag = try sema.coerce(block, tag_ty, inst, inst_src);29829 const enum_tag = try sema.coerce(block, enum_ty, inst, inst_src);
30560 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {29830 if (try sema.resolveDefinedValue(block, inst_src, enum_tag)) |val| {
30561 const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse {29831 const field_index = union_ty.unionTagFieldIndex(val, pt.zcu) orelse {
30562 return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{29832 return sema.fail(block, inst_src, "union '{f}' has no tag with value '{f}'", .{
...@@ -30564,15 +29834,12 @@ fn coerceEnumToUnion(...@@ -30564,15 +29834,12 @@ fn coerceEnumToUnion(
30564 });29834 });
30565 };29835 };
3056629836
30567 const union_obj = zcu.typeToUnion(union_ty).?;29837 const field_name = enum_obj.field_names.get(ip)[field_index];
30568 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);29838 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
30569 try field_ty.resolveFields(pt);
30570 if (field_ty.zigTypeTag(zcu) == .noreturn) {29839 if (field_ty.zigTypeTag(zcu) == .noreturn) {
30571 const msg = msg: {29840 const msg = msg: {
30572 const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{});29841 const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{});
30573 errdefer msg.destroy(sema.gpa);29842 errdefer msg.destroy(sema.gpa);
30574
30575 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
30576 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{29843 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{
30577 field_name.fmt(ip),29844 field_name.fmt(ip),
30578 });29845 });
...@@ -30581,42 +29848,35 @@ fn coerceEnumToUnion(...@@ -30581,42 +29848,35 @@ fn coerceEnumToUnion(
30581 };29848 };
30582 return sema.failWithOwnedErrorMsg(block, msg);29849 return sema.failWithOwnedErrorMsg(block, msg);
30583 }29850 }
30584 const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {29851 const opv = try field_ty.onePossibleValue(pt) orelse return sema.failWithOwnedErrorMsg(block, msg: {
30585 const msg = msg: {29852 const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{
30586 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];29853 inst_ty.fmt(pt), union_ty.fmt(pt),
30587 const msg = try sema.errMsg(inst_src, "coercion from enum '{f}' to union '{f}' must initialize '{f}' field '{f}'", .{29854 field_ty.fmt(pt), field_name.fmt(ip),
30588 inst_ty.fmt(pt), union_ty.fmt(pt),29855 });
30589 field_ty.fmt(pt), field_name.fmt(ip),29856 errdefer msg.destroy(sema.gpa);
30590 });
30591 errdefer msg.destroy(sema.gpa);
3059229857
30593 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{29858 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' declared here", .{field_name.fmt(ip)});
30594 field_name.fmt(ip),29859 try sema.addDeclaredHereNote(msg, union_ty);
30595 });29860 break :msg msg;
30596 try sema.addDeclaredHereNote(msg, union_ty);29861 });
30597 break :msg msg;
30598 };
30599 return sema.failWithOwnedErrorMsg(block, msg);
30600 };
3060129862
30602 return Air.internedToRef((try pt.unionValue(union_ty, val, opv)).toIntern());29863 return Air.internedToRef((try pt.unionValue(union_ty, val, opv)).toIntern());
30603 }29864 }
3060429865
30605 try sema.requireRuntimeBlock(block, inst_src, null);29866 try sema.requireRuntimeBlock(block, inst_src, null);
3060629867
30607 if (tag_ty.isNonexhaustiveEnum(zcu)) {29868 if (enum_ty.isNonexhaustiveEnum(zcu)) {
30608 const msg = msg: {29869 const msg = msg: {
30609 const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{29870 const msg = try sema.errMsg(inst_src, "runtime coercion to union '{f}' from non-exhaustive enum", .{
30610 union_ty.fmt(pt),29871 union_ty.fmt(pt),
30611 });29872 });
30612 errdefer msg.destroy(sema.gpa);29873 errdefer msg.destroy(sema.gpa);
30613 try sema.addDeclaredHereNote(msg, tag_ty);29874 try sema.addDeclaredHereNote(msg, enum_ty);
30614 break :msg msg;29875 break :msg msg;
30615 };29876 };
30616 return sema.failWithOwnedErrorMsg(block, msg);29877 return sema.failWithOwnedErrorMsg(block, msg);
30617 }29878 }
3061829879
30619 const union_obj = zcu.typeToUnion(union_ty).?;
30620 {29880 {
30621 var msg: ?*Zcu.ErrorMsg = null;29881 var msg: ?*Zcu.ErrorMsg = null;
30622 errdefer if (msg) |some| some.destroy(sema.gpa);29882 errdefer if (msg) |some| some.destroy(sema.gpa);
...@@ -30626,7 +29886,7 @@ fn coerceEnumToUnion(...@@ -30626,7 +29886,7 @@ fn coerceEnumToUnion(
30626 const err_msg = msg orelse try sema.errMsg(29886 const err_msg = msg orelse try sema.errMsg(
30627 inst_src,29887 inst_src,
30628 "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field",29888 "runtime coercion from enum '{f}' to union '{f}' which has a 'noreturn' field",
30629 .{ tag_ty.fmt(pt), union_ty.fmt(pt) },29889 .{ enum_ty.fmt(pt), union_ty.fmt(pt) },
30630 );29890 );
30631 msg = err_msg;29891 msg = err_msg;
3063229892
...@@ -30649,14 +29909,14 @@ fn coerceEnumToUnion(...@@ -30649,14 +29909,14 @@ fn coerceEnumToUnion(
30649 const msg = try sema.errMsg(29909 const msg = try sema.errMsg(
30650 inst_src,29910 inst_src,
30651 "runtime coercion from enum '{f}' to union '{f}' which has non-void fields",29911 "runtime coercion from enum '{f}' to union '{f}' which has non-void fields",
30652 .{ tag_ty.fmt(pt), union_ty.fmt(pt) },29912 .{ enum_ty.fmt(pt), union_ty.fmt(pt) },
30653 );29913 );
30654 errdefer msg.destroy(sema.gpa);29914 errdefer msg.destroy(sema.gpa);
3065529915
30656 for (0..union_obj.field_types.len) |field_index| {29916 for (0..union_obj.field_types.len) |field_index| {
30657 const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];29917 const field_name = enum_obj.field_names.get(ip)[field_index];
30658 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);29918 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
30659 if (!(try field_ty.hasRuntimeBitsSema(pt))) continue;29919 if (try field_ty.onePossibleValue(pt) != null) continue;
30660 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{29920 try sema.addFieldErrNote(union_ty, field_index, msg, "field '{f}' has type '{f}'", .{
30661 field_name.fmt(ip),29921 field_name.fmt(ip),
30662 field_ty.fmt(pt),29922 field_ty.fmt(pt),
...@@ -30904,19 +30164,16 @@ fn coerceTupleToTuple(...@@ -30904,19 +30164,16 @@ fn coerceTupleToTuple(
30904 const field_i: u32 = @intCast(field_index_usize);30164 const field_i: u32 = @intCast(field_index_usize);
30905 const field_src = inst_src; // TODO better source location30165 const field_src = inst_src; // TODO better source location
3090630166
30907 const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
30908 .tuple_type => |tuple_type| tuple_type.types.get(ip)[field_index_usize],
30909 .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.get(ip)[field_index_usize],
30910 else => unreachable,
30911 };
30912 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
30913 .tuple_type => |tuple_type| tuple_type.values.get(ip)[field_index_usize],
30914 .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, field_index_usize),
30915 else => unreachable,
30916 };
30917
30918 const field_index: u32 = @intCast(field_index_usize);30167 const field_index: u32 = @intCast(field_index_usize);
3091930168
30169 const field_ty, const default_val = field: {
30170 const tuple_type = ip.indexToKey(tuple_ty.toIntern()).tuple_type;
30171 break :field .{
30172 tuple_type.types.get(ip)[field_index],
30173 tuple_type.values.get(ip)[field_index],
30174 };
30175 };
30176
30920 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);30177 const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
30921 const coerced = try sema.coerce(block, .fromInterned(field_ty), elem_ref, field_src);30178 const coerced = try sema.coerce(block, .fromInterned(field_ty), elem_ref, field_src);
30922 field_refs[field_index] = coerced;30179 field_refs[field_index] = coerced;
...@@ -30946,11 +30203,7 @@ fn coerceTupleToTuple(...@@ -30946,11 +30203,7 @@ fn coerceTupleToTuple(
30946 const i: u32 = @intCast(i_usize);30203 const i: u32 = @intCast(i_usize);
30947 if (field_ref.* != .none) continue;30204 if (field_ref.* != .none) continue;
3094830205
30949 const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {30206 const default_val = ip.indexToKey(tuple_ty.toIntern()).tuple_type.values.get(ip)[i];
30950 .tuple_type => |tuple_type| tuple_type.values.get(ip)[i],
30951 .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, i),
30952 else => unreachable,
30953 };
3095430207
30955 const field_src = inst_src; // TODO better source location30208 const field_src = inst_src; // TODO better source location
30956 if (default_val == .none) {30209 if (default_val == .none) {
...@@ -31019,13 +30272,13 @@ fn addReferenceEntry(...@@ -31019,13 +30272,13 @@ fn addReferenceEntry(
31019pub fn addTypeReferenceEntry(30272pub fn addTypeReferenceEntry(
31020 sema: *Sema,30273 sema: *Sema,
31021 src: LazySrcLoc,30274 src: LazySrcLoc,
31022 referenced_type: InternPool.Index,30275 referenced_type: Type,
31023) !void {30276) !void {
31024 const zcu = sema.pt.zcu;30277 const zcu = sema.pt.zcu;
31025 if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return;30278 if (!zcu.comp.config.incremental and zcu.comp.reference_trace == 0) return;
31026 const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type);30279 const gop = try sema.type_references.getOrPut(sema.gpa, referenced_type.toIntern());
31027 if (gop.found_existing) return;30280 if (gop.found_existing) return;
31028 try zcu.addTypeReference(sema.owner, referenced_type, src);30281 try zcu.addTypeReference(sema.owner, referenced_type.toIntern(), src);
31029}30282}
3103030283
31031fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.MemoizedStateStage) SemaError!void {30284fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.MemoizedStateStage) SemaError!void {
...@@ -31143,7 +30396,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde...@@ -31143,7 +30396,7 @@ fn analyzeNavRefInner(sema: *Sema, block: *Block, src: LazySrcLoc, orig_nav_inde
31143 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },30396 .type_resolved => |r| .{ r.type, r.alignment, r.@"addrspace", r.is_const },
31144 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },30397 .fully_resolved => |r| .{ ip.typeOf(r.val), r.alignment, r.@"addrspace", r.is_const },
31145 };30398 };
31146 const ptr_ty = try pt.ptrTypeSema(.{30399 const ptr_ty = try pt.ptrType(.{
31147 .child = ty,30400 .child = ty,
31148 .flags = .{30401 .flags = .{
31149 .alignment = alignment,30402 .alignment = alignment,
...@@ -31185,7 +30438,7 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_i...@@ -31185,7 +30438,7 @@ fn maybeQueueFuncBodyAnalysis(sema: *Sema, block: *Block, src: LazySrcLoc, nav_i
31185 try sema.ensureNavResolved(block, src, nav_index, .type);30438 try sema.ensureNavResolved(block, src, nav_index, .type);
31186 const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));30439 const nav_ty: Type = .fromInterned(ip.getNav(nav_index).typeOf(ip));
31187 if (nav_ty.zigTypeTag(zcu) != .@"fn") return;30440 if (nav_ty.zigTypeTag(zcu) != .@"fn") return;
31188 if (!try nav_ty.fnHasRuntimeBitsSema(pt)) return;30441 if (!nav_ty.fnHasRuntimeBits(zcu)) return;
3118930442
31190 try sema.ensureNavResolved(block, src, nav_index, .fully);30443 try sema.ensureNavResolved(block, src, nav_index, .fully);
31191 const nav_val = zcu.navValue(nav_index);30444 const nav_val = zcu.navValue(nav_index);
...@@ -31218,14 +30471,14 @@ fn analyzeRef(...@@ -31218,14 +30471,14 @@ fn analyzeRef(
31218 // it's just that we can only use the *type* of the result, since the value is runtime-known.30471 // it's just that we can only use the *type* of the result, since the value is runtime-known.
3121930472
31220 const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);30473 const address_space = target_util.defaultAddressSpace(zcu.getTarget(), .local);
31221 const ptr_type = try pt.ptrTypeSema(.{30474 const ptr_type = try pt.ptrType(.{
31222 .child = operand_ty.toIntern(),30475 .child = operand_ty.toIntern(),
31223 .flags = .{30476 .flags = .{
31224 .is_const = true,30477 .is_const = true,
31225 .address_space = address_space,30478 .address_space = address_space,
31226 },30479 },
31227 });30480 });
31228 const mut_ptr_type = try pt.ptrTypeSema(.{30481 const mut_ptr_type = try pt.ptrType(.{
31229 .child = operand_ty.toIntern(),30482 .child = operand_ty.toIntern(),
31230 .flags = .{ .address_space = address_space },30483 .flags = .{ .address_space = address_space },
31231 });30484 });
...@@ -31261,9 +30514,8 @@ fn analyzeLoad(...@@ -31261,9 +30514,8 @@ fn analyzeLoad(
31261 return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)});30514 return sema.fail(block, ptr_src, "cannot load opaque type '{f}'", .{elem_ty.fmt(pt)});
31262 }30515 }
3126330516
31264 if (try sema.typeHasOnePossibleValue(elem_ty)) |opv| {30517 try sema.ensureLayoutResolved(elem_ty);
31265 return Air.internedToRef(opv.toIntern());30518 if (try elem_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
31266 }
3126730519
31268 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {30520 if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
31269 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {30521 if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
...@@ -31271,6 +30523,13 @@ fn analyzeLoad(...@@ -31271,6 +30523,13 @@ fn analyzeLoad(
31271 }30523 }
31272 }30524 }
3127330525
30526 if (elem_ty.comptimeOnly(zcu)) return sema.failWithOwnedErrorMsg(block, msg: {
30527 const msg = try sema.errMsg(src, "cannot load comptime-only type '{f}'", .{elem_ty.fmt(pt)});
30528 errdefer msg.destroy(zcu.gpa);
30529 try sema.errNote(ptr_src, msg, "pointer of type '{f}' is runtime-known", .{ptr_ty.fmt(pt)});
30530 break :msg msg;
30531 });
30532
31274 return block.addTyOp(.load, elem_ty, ptr);30533 return block.addTyOp(.load, elem_ty, ptr);
31275}30534}
3127630535
...@@ -31332,7 +30591,7 @@ fn analyzeSliceLen(...@@ -31332,7 +30591,7 @@ fn analyzeSliceLen(
31332 if (slice_val.isUndef(zcu)) {30591 if (slice_val.isUndef(zcu)) {
31333 return .undef_usize;30592 return .undef_usize;
31334 }30593 }
31335 return pt.intRef(.usize, try slice_val.sliceLen(pt));30594 return pt.intRef(.usize, slice_val.sliceLen(zcu));
31336 }30595 }
31337 try sema.requireRuntimeBlock(block, src, null);30596 try sema.requireRuntimeBlock(block, src, null);
31338 return block.addTyOp(.slice_len, .usize, slice_inst);30597 return block.addTyOp(.slice_len, .usize, slice_inst);
...@@ -31682,6 +30941,8 @@ fn analyzeSlice(...@@ -31682,6 +30941,8 @@ fn analyzeSlice(
31682 else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}),30941 else => return sema.fail(block, src, "slice of non-array type '{f}'", .{ptr_ptr_child_ty.fmt(pt)}),
31683 }30942 }
3168430943
30944 try sema.ensureLayoutResolved(elem_ty);
30945
31685 const ptr = if (slice_ty.isSlice(zcu))30946 const ptr = if (slice_ty.isSlice(zcu))
31686 try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)30947 try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
31687 else if (array_ty.zigTypeTag(zcu) == .array) ptr: {30948 else if (array_ty.zigTypeTag(zcu) == .array) ptr: {
...@@ -31690,7 +30951,7 @@ fn analyzeSlice(...@@ -31690,7 +30951,7 @@ fn analyzeSlice(
31690 assert(manyptr_ty_key.flags.size == .one);30951 assert(manyptr_ty_key.flags.size == .one);
31691 manyptr_ty_key.child = elem_ty.toIntern();30952 manyptr_ty_key.child = elem_ty.toIntern();
31692 manyptr_ty_key.flags.size = .many;30953 manyptr_ty_key.flags.size = .many;
31693 break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrTypeSema(manyptr_ty_key), ptr_or_slice, ptr_src);30954 break :ptr try sema.coerceCompatiblePtrs(block, try pt.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
31694 } else ptr_or_slice;30955 } else ptr_or_slice;
3169530956
31696 const start = try sema.coerce(block, .usize, uncasted_start, start_src);30957 const start = try sema.coerce(block, .usize, uncasted_start, start_src);
...@@ -31759,7 +31020,7 @@ fn analyzeSlice(...@@ -31759,7 +31020,7 @@ fn analyzeSlice(
31759 return sema.fail(block, src, "slice of undefined", .{});31020 return sema.fail(block, src, "slice of undefined", .{});
31760 }31021 }
31761 const has_sentinel = slice_ty.sentinel(zcu) != null;31022 const has_sentinel = slice_ty.sentinel(zcu) != null;
31762 const slice_len = try slice_val.sliceLen(pt);31023 const slice_len = slice_val.sliceLen(zcu);
31763 const len_plus_sent = slice_len + @intFromBool(has_sentinel);31024 const len_plus_sent = slice_len + @intFromBool(has_sentinel);
31764 const slice_len_val_with_sentinel = try pt.intValue(.usize, len_plus_sent);31025 const slice_len_val_with_sentinel = try pt.intValue(.usize, len_plus_sent);
31765 if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, .usize))) {31026 if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, .usize))) {
...@@ -31774,7 +31035,7 @@ fn analyzeSlice(...@@ -31774,7 +31035,7 @@ fn analyzeSlice(
31774 "end index {f} out of bounds for slice of length {d}{s}",31035 "end index {f} out of bounds for slice of length {d}{s}",
31775 .{31036 .{
31776 end_val.fmtValueSema(pt, sema),31037 end_val.fmtValueSema(pt, sema),
31777 try slice_val.sliceLen(pt),31038 slice_val.sliceLen(zcu),
31778 sentinel_label,31039 sentinel_label,
31779 },31040 },
31780 );31041 );
...@@ -31943,9 +31204,9 @@ fn analyzeSlice(...@@ -31943,9 +31204,9 @@ fn analyzeSlice(
31943 const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(zcu) != .c;31204 const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(zcu) != .c;
3194431205
31945 if (opt_new_len_val) |new_len_val| {31206 if (opt_new_len_val) |new_len_val| {
31946 const new_len_int = try new_len_val.toUnsignedIntSema(pt);31207 const new_len_int = new_len_val.toUnsignedInt(zcu);
3194731208
31948 const return_ty = try pt.ptrTypeSema(.{31209 const return_ty = try pt.ptrType(.{
31949 .child = (try pt.arrayType(.{31210 .child = (try pt.arrayType(.{
31950 .len = new_len_int,31211 .len = new_len_int,
31951 .sentinel = if (sentinel) |s| s.toIntern() else .none,31212 .sentinel = if (sentinel) |s| s.toIntern() else .none,
...@@ -32009,7 +31270,7 @@ fn analyzeSlice(...@@ -32009,7 +31270,7 @@ fn analyzeSlice(
32009 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});31270 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
32010 }31271 }
3201131272
32012 const return_ty = try pt.ptrTypeSema(.{31273 const return_ty = try pt.ptrType(.{
32013 .child = elem_ty.toIntern(),31274 .child = elem_ty.toIntern(),
32014 .sentinel = if (sentinel) |s| s.toIntern() else .none,31275 .sentinel = if (sentinel) |s| s.toIntern() else .none,
32015 .flags = .{31276 .flags = .{
...@@ -32037,7 +31298,7 @@ fn analyzeSlice(...@@ -32037,7 +31298,7 @@ fn analyzeSlice(
32037 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {31298 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
32038 // we don't need to add one for sentinels because the31299 // we don't need to add one for sentinels because the
32039 // underlying value data includes the sentinel31300 // underlying value data includes the sentinel
32040 break :blk try pt.intRef(.usize, try slice_val.sliceLen(pt));31301 break :blk try pt.intRef(.usize, slice_val.sliceLen(zcu));
32041 }31302 }
3204231303
32043 const slice_len_inst = try block.addTyOp(.slice_len, .usize, ptr_or_slice);31304 const slice_len_inst = try block.addTyOp(.slice_len, .usize, ptr_or_slice);
...@@ -32158,16 +31419,10 @@ fn cmpNumeric(...@@ -32158,16 +31419,10 @@ fn cmpNumeric(
3215831419
32159 const runtime_src: LazySrcLoc = if (maybe_lhs_val) |lhs_val| rs: {31420 const runtime_src: LazySrcLoc = if (maybe_lhs_val) |lhs_val| rs: {
32160 if (maybe_rhs_val) |rhs_val| {31421 if (maybe_rhs_val) |rhs_val| {
32161 const res = try Value.compareHeteroSema(lhs_val, op, rhs_val, pt);31422 return .fromValue(.makeBool(Value.compareHetero(lhs_val, op, rhs_val, zcu)));
32162 return if (res) .bool_true else .bool_false;
32163 } else break :rs rhs_src;31423 } else break :rs rhs_src;
32164 } else lhs_src;31424 } else lhs_src;
3216531425
32166 // TODO handle comparisons against lazy zero values
32167 // Some values can be compared against zero without being runtime-known or without forcing
32168 // a full resolution of their value, for example `@sizeOf(@Frame(function))` is known to
32169 // always be nonzero, and we benefit from not forcing the full evaluation and stack frame layout
32170 // of this function if we don't need to.
32171 try sema.requireRuntimeBlock(block, src, runtime_src);31426 try sema.requireRuntimeBlock(block, src, runtime_src);
3217231427
32173 // For floats, emit a float comparison instruction.31428 // For floats, emit a float comparison instruction.
...@@ -32207,11 +31462,11 @@ fn cmpNumeric(...@@ -32207,11 +31462,11 @@ fn cmpNumeric(
32207 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,31462 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
32208 // add/subtract 1.31463 // add/subtract 1.
32209 const lhs_is_signed = if (maybe_lhs_val) |lhs_val|31464 const lhs_is_signed = if (maybe_lhs_val) |lhs_val|
32210 !(try lhs_val.compareAllWithZeroSema(.gte, pt))31465 !lhs_val.compareAllWithZero(.gte, zcu)
32211 else31466 else
32212 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu));31467 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(zcu));
32213 const rhs_is_signed = if (maybe_rhs_val) |rhs_val|31468 const rhs_is_signed = if (maybe_rhs_val) |rhs_val|
32214 !(try rhs_val.compareAllWithZeroSema(.gte, pt))31469 !rhs_val.compareAllWithZero(.gte, zcu)
32215 else31470 else
32216 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu));31471 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(zcu));
32217 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;31472 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
...@@ -32219,10 +31474,9 @@ fn cmpNumeric(...@@ -32219,10 +31474,9 @@ fn cmpNumeric(
32219 var dest_float_type: ?Type = null;31474 var dest_float_type: ?Type = null;
3222031475
32221 var lhs_bits: usize = undefined;31476 var lhs_bits: usize = undefined;
32222 if (maybe_lhs_val) |unresolved_lhs_val| {31477 if (maybe_lhs_val) |lhs_val| {
32223 const lhs_val = try sema.resolveLazyValue(unresolved_lhs_val);
32224 if (!rhs_is_signed) {31478 if (!rhs_is_signed) {
32225 switch (lhs_val.orderAgainstZero(zcu)) {31479 switch (Value.order(lhs_val, .zero_comptime_int, zcu)) {
32226 .gt => {},31480 .gt => {},
32227 .eq => switch (op) { // LHS = 0, RHS is unsigned31481 .eq => switch (op) { // LHS = 0, RHS is unsigned
32228 .lte => return .bool_true,31482 .lte => return .bool_true,
...@@ -32263,10 +31517,9 @@ fn cmpNumeric(...@@ -32263,10 +31517,9 @@ fn cmpNumeric(
32263 }31517 }
3226431518
32265 var rhs_bits: usize = undefined;31519 var rhs_bits: usize = undefined;
32266 if (maybe_rhs_val) |unresolved_rhs_val| {31520 if (maybe_rhs_val) |rhs_val| {
32267 const rhs_val = try sema.resolveLazyValue(unresolved_rhs_val);
32268 if (!lhs_is_signed) {31521 if (!lhs_is_signed) {
32269 switch (rhs_val.orderAgainstZero(zcu)) {31522 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
32270 .gt => {},31523 .gt => {},
32271 .eq => switch (op) { // RHS = 0, LHS is unsigned31524 .eq => switch (op) { // RHS = 0, LHS is unsigned
32272 .gte => return .bool_true,31525 .gte => return .bool_true,
...@@ -32328,7 +31581,7 @@ fn compareIntsOnlyPossibleResult(...@@ -32328,7 +31581,7 @@ fn compareIntsOnlyPossibleResult(
32328 lhs_val: Value,31581 lhs_val: Value,
32329 op: std.math.CompareOperator,31582 op: std.math.CompareOperator,
32330 rhs_ty: Type,31583 rhs_ty: Type,
32331) SemaError!?bool {31584) Allocator.Error!?bool {
32332 const pt = sema.pt;31585 const pt = sema.pt;
32333 const zcu = pt.zcu;31586 const zcu = pt.zcu;
3233431587
...@@ -32337,11 +31590,11 @@ fn compareIntsOnlyPossibleResult(...@@ -32337,11 +31590,11 @@ fn compareIntsOnlyPossibleResult(
3233731590
32338 if (min_rhs.toIntern() == max_rhs.toIntern()) {31591 if (min_rhs.toIntern() == max_rhs.toIntern()) {
32339 // RHS is effectively comptime-known.31592 // RHS is effectively comptime-known.
32340 return try Value.compareHeteroSema(lhs_val, op, min_rhs, pt);31593 return Value.compareHetero(lhs_val, op, min_rhs, zcu);
32341 }31594 }
3234231595
32343 const against_min = try lhs_val.orderAdvanced(min_rhs, .sema, zcu, pt.tid);31596 const against_min = lhs_val.order(min_rhs, zcu);
32344 const against_max = try lhs_val.orderAdvanced(max_rhs, .sema, zcu, pt.tid);31597 const against_max = lhs_val.order(max_rhs, zcu);
3234531598
32346 switch (op) {31599 switch (op) {
32347 .eq => {31600 .eq => {
...@@ -32529,9 +31782,7 @@ fn unionToTag(...@@ -32529,9 +31782,7 @@ fn unionToTag(
32529) !Air.Inst.Ref {31782) !Air.Inst.Ref {
32530 const pt = sema.pt;31783 const pt = sema.pt;
32531 const zcu = pt.zcu;31784 const zcu = pt.zcu;
32532 if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| {31785 if (try enum_ty.onePossibleValue(pt)) |opv| return .fromValue(opv);
32533 return Air.internedToRef(opv.toIntern());
32534 }
32535 if (try sema.resolveValue(un)) |un_val| {31786 if (try sema.resolveValue(un)) |un_val| {
32536 const tag_val = un_val.unionTag(zcu).?;31787 const tag_val = un_val.unionTag(zcu).?;
32537 if (tag_val.isUndef(zcu))31788 if (tag_val.isUndef(zcu))
...@@ -33240,18 +32491,24 @@ fn resolvePeerTypesInner(...@@ -33240,18 +32491,24 @@ fn resolvePeerTypesInner(
33240 ptr_info.sentinel = .none;32491 ptr_info.sentinel = .none;
33241 }32492 }
3324232493
33243 // Note that the align can be always non-zero; Zcu.ptrType will canonicalize it32494 ptr_info.flags.alignment = a: {
33244 ptr_info.flags.alignment = InternPool.Alignment.min(32495 // If both alignments are implicit, the result alignment is implicit.
33245 if (ptr_info.flags.alignment != .none)32496 // e.g. '[*c]u32' + '[*c]c_uint' -> '[*c]u32'
33246 ptr_info.flags.alignment32497 if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) {
33247 else32498 break :a .none;
33248 Type.fromInterned(ptr_info.child).abiAlignment(zcu),32499 }
3324932500 // Otherwise (if either alignment is explicit), the result alignment is explicit.
33250 if (peer_info.flags.alignment != .none)32501 // e.g. '[*c]u32' + '[*c]align(4) c_uint' -> '[*c]align(4) u32'
33251 peer_info.flags.alignment32502 const cur_align = switch (ptr_info.flags.alignment) {
33252 else32503 .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu),
33253 Type.fromInterned(peer_info.child).abiAlignment(zcu),32504 else => ptr_info.flags.alignment,
33254 );32505 };
32506 const new_align = switch (peer_info.flags.alignment) {
32507 .none => Type.fromInterned(peer_info.child).abiAlignment(zcu),
32508 else => peer_info.flags.alignment,
32509 };
32510 break :a .minStrict(cur_align, new_align);
32511 };
33255 if (ptr_info.flags.address_space != peer_info.flags.address_space) {32512 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
33256 return .{ .conflict = .{32513 return .{ .conflict = .{
33257 .peer_idx_a = first_idx,32514 .peer_idx_a = first_idx,
...@@ -33273,7 +32530,7 @@ fn resolvePeerTypesInner(...@@ -33273,7 +32530,7 @@ fn resolvePeerTypesInner(
3327332530
33274 opt_ptr_info = ptr_info;32531 opt_ptr_info = ptr_info;
33275 }32532 }
33276 return .{ .success = try pt.ptrTypeSema(opt_ptr_info.?) };32533 return .{ .success = try pt.ptrType(opt_ptr_info.?) };
33277 },32534 },
3327832535
33279 .ptr => {32536 .ptr => {
...@@ -33281,7 +32538,6 @@ fn resolvePeerTypesInner(...@@ -33281,7 +32538,6 @@ fn resolvePeerTypesInner(
33281 // if there were no actual slices. Else, we want the slice index to report a conflict.32538 // if there were no actual slices. Else, we want the slice index to report a conflict.
33282 var opt_slice_idx: ?usize = null;32539 var opt_slice_idx: ?usize = null;
3328332540
33284 var any_abi_aligned = false;
33285 var opt_ptr_info: ?InternPool.Key.PtrType = null;32541 var opt_ptr_info: ?InternPool.Key.PtrType = null;
33286 var first_idx: usize = undefined;32542 var first_idx: usize = undefined;
33287 var other_idx: usize = undefined; // We sometimes need a second peer index to report a generic error32543 var other_idx: usize = undefined; // We sometimes need a second peer index to report a generic error
...@@ -33325,15 +32581,24 @@ fn resolvePeerTypesInner(...@@ -33325,15 +32581,24 @@ fn resolvePeerTypesInner(
33325 .peer_idx_b = i,32581 .peer_idx_b = i,
33326 } };32582 } };
3332732583
33328 // Note that the align can be always non-zero; Type.ptr will canonicalize it32584 ptr_info.flags.alignment = a: {
33329 if (peer_info.flags.alignment == .none) {32585 // If both alignments are implicit, the result alignment is implicit.
33330 any_abi_aligned = true;32586 // e.g. '[*c]u32' + '[*c]c_uint' -> '[*c]u32'
33331 } else if (ptr_info.flags.alignment == .none) {32587 if (ptr_info.flags.alignment == .none and peer_info.flags.alignment == .none) {
33332 any_abi_aligned = true;32588 break :a .none;
33333 ptr_info.flags.alignment = peer_info.flags.alignment;32589 }
33334 } else {32590 // Otherwise (if either alignment is explicit), the result alignment is explicit.
33335 ptr_info.flags.alignment = ptr_info.flags.alignment.minStrict(peer_info.flags.alignment);32591 // e.g. '[*c]u32' + '[*c]align(4) c_uint' -> '[*c]align(4) u32'
33336 }32592 const cur_align = switch (ptr_info.flags.alignment) {
32593 .none => Type.fromInterned(ptr_info.child).abiAlignment(zcu),
32594 else => ptr_info.flags.alignment,
32595 };
32596 const new_align = switch (peer_info.flags.alignment) {
32597 .none => Type.fromInterned(peer_info.child).abiAlignment(zcu),
32598 else => peer_info.flags.alignment,
32599 };
32600 break :a .minStrict(cur_align, new_align);
32601 };
3333732602
33338 if (ptr_info.flags.address_space != peer_info.flags.address_space) {32603 if (ptr_info.flags.address_space != peer_info.flags.address_space) {
33339 return generic_err;32604 return generic_err;
...@@ -33582,13 +32847,7 @@ fn resolvePeerTypesInner(...@@ -33582,13 +32847,7 @@ fn resolvePeerTypesInner(
33582 },32847 },
33583 }32848 }
3358432849
33585 if (any_abi_aligned and opt_ptr_info.?.flags.alignment != .none) {32850 return .{ .success = try pt.ptrType(opt_ptr_info.?) };
33586 opt_ptr_info.?.flags.alignment = opt_ptr_info.?.flags.alignment.minStrict(
33587 try Type.fromInterned(pointee).abiAlignmentSema(pt),
33588 );
33589 }
33590
33591 return .{ .success = try pt.ptrTypeSema(opt_ptr_info.?) };
33592 },32851 },
3359332852
33594 .func => {32853 .func => {
...@@ -33731,7 +32990,7 @@ fn resolvePeerTypesInner(...@@ -33731,7 +32990,7 @@ fn resolvePeerTypesInner(
33731 .peer_idx_b = i,32990 .peer_idx_b = i,
33732 } };32991 } };
33733 any_comptime_known = true;32992 any_comptime_known = true;
33734 ptr_opt_val.* = try sema.resolveLazyValue(opt_val.?);32993 ptr_opt_val.* = opt_val.?;
33735 continue;32994 continue;
33736 },32995 },
33737 .int => {},32996 .int => {},
...@@ -33924,7 +33183,6 @@ fn resolvePeerTypesInner(...@@ -33924,7 +33183,6 @@ fn resolvePeerTypesInner(
33924 var comptime_val: ?Value = null;33183 var comptime_val: ?Value = null;
33925 for (peer_tys) |opt_ty| {33184 for (peer_tys) |opt_ty| {
33926 const struct_ty = opt_ty orelse continue;33185 const struct_ty = opt_ty orelse continue;
33927 try struct_ty.resolveStructFieldInits(pt);
3392833186
33929 const uncoerced_field_val = try struct_ty.structFieldValueComptime(pt, field_index) orelse {33187 const uncoerced_field_val = try struct_ty.structFieldValueComptime(pt, field_index) orelse {
33930 comptime_val = null;33188 comptime_val = null;
...@@ -34058,344 +33316,6 @@ pub fn resolveIes(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!void...@@ -34058,344 +33316,6 @@ pub fn resolveIes(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!void
34058 }33316 }
34059}33317}
3406033318
34061pub fn resolveFnTypes(sema: *Sema, fn_ty: Type, src: LazySrcLoc) CompileError!void {
34062 const pt = sema.pt;
34063 const zcu = pt.zcu;
34064 const ip = &zcu.intern_pool;
34065 const fn_ty_info = zcu.typeToFunc(fn_ty).?;
34066
34067 try Type.fromInterned(fn_ty_info.return_type).resolveFully(pt);
34068
34069 if (zcu.comp.config.any_error_tracing and
34070 Type.fromInterned(fn_ty_info.return_type).isError(zcu))
34071 {
34072 // Ensure the type exists so that backends can assume that.
34073 _ = try sema.getBuiltinType(src, .StackTrace);
34074 }
34075
34076 for (0..fn_ty_info.param_types.len) |i| {
34077 try Type.fromInterned(fn_ty_info.param_types.get(ip)[i]).resolveFully(pt);
34078 }
34079}
34080
34081fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
34082 return val.resolveLazy(sema.arena, sema.pt);
34083}
34084
34085/// Resolve a struct's alignment only without triggering resolution of its layout.
34086/// Asserts that the alignment is not yet resolved and the layout is non-packed.
34087pub fn resolveStructAlignment(
34088 sema: *Sema,
34089 ty: InternPool.Index,
34090 struct_type: InternPool.LoadedStructType,
34091) SemaError!void {
34092 const pt = sema.pt;
34093 const zcu = pt.zcu;
34094 const io = zcu.comp.io;
34095 const ip = &zcu.intern_pool;
34096 const target = zcu.getTarget();
34097
34098 assert(sema.owner.unwrap().type == ty);
34099
34100 assert(struct_type.layout != .@"packed");
34101 assert(struct_type.flagsUnordered(ip).alignment == .none);
34102
34103 const ptr_align = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34104
34105 // We'll guess "pointer-aligned", if the struct has an
34106 // underaligned pointer field then some allocations
34107 // might require explicit alignment.
34108 if (struct_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return;
34109
34110 try sema.resolveStructFieldTypes(ty, struct_type);
34111
34112 // We'll guess "pointer-aligned", if the struct has an
34113 // underaligned pointer field then some allocations
34114 // might require explicit alignment.
34115 if (struct_type.assumePointerAlignedIfWip(ip, io, ptr_align)) return;
34116 defer struct_type.clearAlignmentWip(ip, io);
34117
34118 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
34119 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
34120
34121 var alignment: Alignment = .@"1";
34122
34123 for (0..struct_type.field_types.len) |i| {
34124 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
34125 if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt))
34126 continue;
34127 const field_align = try field_ty.structFieldAlignmentSema(
34128 struct_type.fieldAlign(ip, i),
34129 struct_type.layout,
34130 pt,
34131 );
34132 alignment = alignment.maxStrict(field_align);
34133 }
34134
34135 struct_type.setAlignment(ip, io, alignment);
34136}
34137
34138pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
34139 const pt = sema.pt;
34140 const zcu = pt.zcu;
34141 const ip = &zcu.intern_pool;
34142 const io = zcu.comp.io;
34143 const struct_type = zcu.typeToStruct(ty) orelse return;
34144
34145 assert(sema.owner.unwrap().type == ty.toIntern());
34146
34147 if (struct_type.haveLayout(ip))
34148 return;
34149
34150 try sema.resolveStructFieldTypes(ty.toIntern(), struct_type);
34151
34152 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
34153 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
34154
34155 if (struct_type.layout == .@"packed") {
34156 sema.backingIntType(struct_type) catch |err| switch (err) {
34157 error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
34158 error.ComptimeBreak, error.ComptimeReturn => unreachable,
34159 };
34160 return;
34161 }
34162
34163 if (struct_type.setLayoutWip(ip, io)) {
34164 const msg = try sema.errMsg(
34165 ty.srcLoc(zcu),
34166 "struct '{f}' depends on itself",
34167 .{ty.fmt(pt)},
34168 );
34169 return sema.failWithOwnedErrorMsg(null, msg);
34170 }
34171 defer struct_type.clearLayoutWip(ip, io);
34172
34173 const aligns = try sema.arena.alloc(Alignment, struct_type.field_types.len);
34174 const sizes = try sema.arena.alloc(u64, struct_type.field_types.len);
34175
34176 var big_align: Alignment = .@"1";
34177
34178 for (aligns, sizes, 0..) |*field_align, *field_size, i| {
34179 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
34180 if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) {
34181 struct_type.offsets.get(ip)[i] = 0;
34182 field_size.* = 0;
34183 field_align.* = .none;
34184 continue;
34185 }
34186
34187 field_size.* = field_ty.abiSizeSema(pt) catch |err| switch (err) {
34188 error.AnalysisFail => {
34189 const msg = sema.err orelse return err;
34190 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
34191 return err;
34192 },
34193 else => return err,
34194 };
34195 field_align.* = try field_ty.structFieldAlignmentSema(
34196 struct_type.fieldAlign(ip, i),
34197 struct_type.layout,
34198 pt,
34199 );
34200 big_align = big_align.maxStrict(field_align.*);
34201 }
34202
34203 if (struct_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) {
34204 const msg = try sema.errMsg(
34205 ty.srcLoc(zcu),
34206 "struct layout depends on it having runtime bits",
34207 .{},
34208 );
34209 return sema.failWithOwnedErrorMsg(null, msg);
34210 }
34211
34212 if (struct_type.flagsUnordered(ip).assumed_pointer_aligned and
34213 big_align.compareStrict(.neq, Alignment.fromByteUnits(@divExact(zcu.getTarget().ptrBitWidth(), 8))))
34214 {
34215 const msg = try sema.errMsg(
34216 ty.srcLoc(zcu),
34217 "struct layout depends on being pointer aligned",
34218 .{},
34219 );
34220 return sema.failWithOwnedErrorMsg(null, msg);
34221 }
34222
34223 if (struct_type.hasReorderedFields()) {
34224 const runtime_order = struct_type.runtime_order.get(ip);
34225
34226 for (runtime_order, 0..) |*ro, i| {
34227 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
34228 if (struct_type.fieldIsComptime(ip, i) or try field_ty.comptimeOnlySema(pt)) {
34229 ro.* = .omitted;
34230 } else {
34231 ro.* = @enumFromInt(i);
34232 }
34233 }
34234
34235 const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
34236
34237 const AlignSortContext = struct {
34238 aligns: []const Alignment,
34239
34240 fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
34241 if (a == .omitted) return false;
34242 if (b == .omitted) return true;
34243 const a_align = ctx.aligns[@intFromEnum(a)];
34244 const b_align = ctx.aligns[@intFromEnum(b)];
34245 return a_align.compare(.gt, b_align);
34246 }
34247 };
34248 if (!zcu.backendSupportsFeature(.field_reordering)) {
34249 // TODO: we should probably also reorder tuple fields? This is a bit weird because it'll involve
34250 // mutating the `InternPool` for a non-container type.
34251 //
34252 // TODO: implement field reordering support in all the backends!
34253 //
34254 // This logic does not reorder fields; it only moves the omitted ones to the end
34255 // so that logic elsewhere does not need to special-case here.
34256 var i: usize = 0;
34257 var off: usize = 0;
34258 while (i + off < runtime_order.len) {
34259 if (runtime_order[i + off] == .omitted) {
34260 off += 1;
34261 continue;
34262 }
34263 runtime_order[i] = runtime_order[i + off];
34264 i += 1;
34265 }
34266 @memset(runtime_order[i..], .omitted);
34267 } else {
34268 mem.sortUnstable(RuntimeOrder, runtime_order, AlignSortContext{
34269 .aligns = aligns,
34270 }, AlignSortContext.lessThan);
34271 }
34272 }
34273
34274 // Calculate size, alignment, and field offsets.
34275 const offsets = struct_type.offsets.get(ip);
34276 var it = struct_type.iterateRuntimeOrder(ip);
34277 var offset: u64 = 0;
34278 while (it.next()) |i| {
34279 offsets[i] = @intCast(aligns[i].forward(offset));
34280 offset = offsets[i] + sizes[i];
34281 }
34282 const size = std.math.cast(u32, big_align.forward(offset)) orelse {
34283 const msg = try sema.errMsg(
34284 ty.srcLoc(zcu),
34285 "struct layout requires size {d}, this compiler implementation supports up to {d}",
34286 .{ big_align.forward(offset), std.math.maxInt(u32) },
34287 );
34288 return sema.failWithOwnedErrorMsg(null, msg);
34289 };
34290 struct_type.setLayoutResolved(ip, io, size, big_align);
34291 _ = try ty.comptimeOnlySema(pt);
34292}
34293
34294fn backingIntType(
34295 sema: *Sema,
34296 struct_type: InternPool.LoadedStructType,
34297) CompileError!void {
34298 const pt = sema.pt;
34299 const zcu = pt.zcu;
34300 const comp = zcu.comp;
34301 const gpa = comp.gpa;
34302 const io = comp.io;
34303 const ip = &zcu.intern_pool;
34304
34305 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
34306 defer analysis_arena.deinit();
34307
34308 var block: Block = .{
34309 .parent = null,
34310 .sema = sema,
34311 .namespace = struct_type.namespace,
34312 .instructions = .{},
34313 .inlining = null,
34314 .comptime_reason = null, // set below if needed
34315 .src_base_inst = struct_type.zir_index,
34316 .type_name_ctx = struct_type.name,
34317 };
34318 defer assert(block.instructions.items.len == 0);
34319
34320 const fields_bit_sum = blk: {
34321 var accumulator: u64 = 0;
34322 for (0..struct_type.field_types.len) |i| {
34323 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
34324 accumulator += try field_ty.bitSizeSema(pt);
34325 }
34326 break :blk accumulator;
34327 };
34328
34329 const zir = zcu.namespacePtr(struct_type.namespace).fileScope(zcu).zir.?;
34330 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
34331 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
34332 assert(extended.opcode == .struct_decl);
34333 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
34334
34335 if (small.has_backing_int) {
34336 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
34337 const captures_len = if (small.has_captures_len) blk: {
34338 const captures_len = zir.extra[extra_index];
34339 extra_index += 1;
34340 break :blk captures_len;
34341 } else 0;
34342 extra_index += @intFromBool(small.has_fields_len);
34343 extra_index += @intFromBool(small.has_decls_len);
34344
34345 extra_index += captures_len * 2;
34346
34347 const backing_int_body_len = zir.extra[extra_index];
34348 extra_index += 1;
34349
34350 const backing_int_src: LazySrcLoc = .{
34351 .base_node_inst = struct_type.zir_index,
34352 .offset = .{ .node_offset_container_tag = .zero },
34353 };
34354 block.comptime_reason = .{ .reason = .{
34355 .src = backing_int_src,
34356 .r = .{ .simple = .type },
34357 } };
34358 const backing_int_ty = blk: {
34359 if (backing_int_body_len == 0) {
34360 const backing_int_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
34361 break :blk try sema.resolveType(&block, backing_int_src, backing_int_ref);
34362 } else {
34363 const body = zir.bodySlice(extra_index, backing_int_body_len);
34364 const ty_ref = try sema.resolveInlineBody(&block, body, zir_index);
34365 break :blk try sema.analyzeAsType(&block, backing_int_src, ty_ref);
34366 }
34367 };
34368
34369 try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
34370 struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern());
34371 } else {
34372 if (fields_bit_sum > std.math.maxInt(u16)) {
34373 return sema.fail(&block, block.nodeOffset(.zero), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
34374 }
34375 const backing_int_ty = try pt.intType(.unsigned, @intCast(fields_bit_sum));
34376 struct_type.setBackingIntType(ip, io, backing_int_ty.toIntern());
34377 }
34378
34379 try sema.flushExports();
34380}
34381
34382fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
34383 const pt = sema.pt;
34384 const zcu = pt.zcu;
34385
34386 if (!backing_int_ty.isInt(zcu)) {
34387 return sema.fail(block, src, "expected backing integer type, found '{f}'", .{backing_int_ty.fmt(pt)});
34388 }
34389 if (backing_int_ty.bitSize(zcu) != fields_bit_sum) {
34390 return sema.fail(
34391 block,
34392 src,
34393 "backing integer type '{f}' has bit size {d} but the struct fields have a total bit size of {d}",
34394 .{ backing_int_ty.fmt(pt), backing_int_ty.bitSize(zcu), fields_bit_sum },
34395 );
34396 }
34397}
34398
34399fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {33319fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
34400 const pt = sema.pt;33320 const pt = sema.pt;
34401 if (!ty.isIndexable(pt.zcu)) {33321 if (!ty.isIndexable(pt.zcu)) {
...@@ -34432,358 +33352,6 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void...@@ -34432,358 +33352,6 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
34432 return sema.failWithOwnedErrorMsg(block, msg);33352 return sema.failWithOwnedErrorMsg(block, msg);
34433}33353}
3443433354
34435/// Resolve a unions's alignment only without triggering resolution of its layout.
34436/// Asserts that the alignment is not yet resolved.
34437pub fn resolveUnionAlignment(
34438 sema: *Sema,
34439 ty: Type,
34440 union_type: InternPool.LoadedUnionType,
34441) SemaError!void {
34442 const pt = sema.pt;
34443 const zcu = pt.zcu;
34444 const io = zcu.comp.io;
34445 const ip = &zcu.intern_pool;
34446 const target = zcu.getTarget();
34447
34448 assert(sema.owner.unwrap().type == ty.toIntern());
34449
34450 assert(!union_type.haveLayout(ip));
34451
34452 const ptr_align = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
34453
34454 // We'll guess "pointer-aligned", if the union has an
34455 // underaligned pointer field then some allocations
34456 // might require explicit alignment.
34457 if (union_type.assumePointerAlignedIfFieldTypesWip(ip, io, ptr_align)) return;
34458
34459 try sema.resolveUnionFieldTypes(ty, union_type);
34460
34461 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
34462 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
34463
34464 var max_align: Alignment = .@"1";
34465 for (0..union_type.field_types.len) |field_index| {
34466 const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]);
34467 if (!(try field_ty.hasRuntimeBitsSema(pt))) continue;
34468
34469 const explicit_align = union_type.fieldAlign(ip, field_index);
34470 const field_align = if (explicit_align != .none)
34471 explicit_align
34472 else
34473 try field_ty.abiAlignmentSema(sema.pt);
34474
34475 max_align = max_align.max(field_align);
34476 }
34477
34478 union_type.setAlignment(ip, io, max_align);
34479}
34480
34481/// This logic must be kept in sync with `Type.getUnionLayout`.
34482pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
34483 const pt = sema.pt;
34484 const io = pt.zcu.comp.io;
34485 const ip = &pt.zcu.intern_pool;
34486
34487 try sema.resolveUnionFieldTypes(ty, ip.loadUnionType(ty.ip_index));
34488
34489 // Load again, since the tag type might have changed due to resolution.
34490 const union_type = ip.loadUnionType(ty.ip_index);
34491
34492 assert(sema.owner.unwrap().type == ty.toIntern());
34493
34494 const old_flags = union_type.flagsUnordered(ip);
34495 switch (old_flags.status) {
34496 .none, .have_field_types => {},
34497 .field_types_wip, .layout_wip => {
34498 const msg = try sema.errMsg(
34499 ty.srcLoc(pt.zcu),
34500 "union '{f}' depends on itself",
34501 .{ty.fmt(pt)},
34502 );
34503 return sema.failWithOwnedErrorMsg(null, msg);
34504 },
34505 .have_layout, .fully_resolved_wip, .fully_resolved => return,
34506 }
34507
34508 errdefer union_type.setStatusIfLayoutWip(ip, io, old_flags.status);
34509
34510 union_type.setStatus(ip, io, .layout_wip);
34511
34512 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
34513 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
34514
34515 var max_size: u64 = 0;
34516 var max_align: Alignment = .@"1";
34517 for (0..union_type.field_types.len) |field_index| {
34518 const field_ty: Type = .fromInterned(union_type.field_types.get(ip)[field_index]);
34519 if (field_ty.isNoReturn(pt.zcu)) continue;
34520
34521 // We need to call `hasRuntimeBits` before calling `abiSize` to prevent reachable `unreachable`s,
34522 // but `hasRuntimeBits` only resolves field types and so may infinite recurse on a layout wip type,
34523 // so we must resolve the layout manually first, instead of waiting for `abiSize` to do it for us.
34524 // This is arguably just hacking around bugs in both `abiSize` for not allowing arbitrary types to
34525 // be queried, enabling failures to be handled with the emission of a compile error, and also in
34526 // `hasRuntimeBits` for ever being able to infinite recurse in the first place.
34527 try field_ty.resolveLayout(pt);
34528
34529 if (try field_ty.hasRuntimeBitsSema(pt)) {
34530 max_size = @max(max_size, field_ty.abiSizeSema(pt) catch |err| switch (err) {
34531 error.AnalysisFail => {
34532 const msg = sema.err orelse return err;
34533 try sema.addFieldErrNote(ty, field_index, msg, "while checking this field", .{});
34534 return err;
34535 },
34536 else => return err,
34537 });
34538 }
34539
34540 const explicit_align = union_type.fieldAlign(ip, field_index);
34541 const field_align = if (explicit_align != .none)
34542 explicit_align
34543 else
34544 try field_ty.abiAlignmentSema(pt);
34545 max_align = max_align.max(field_align);
34546 }
34547
34548 const has_runtime_tag = union_type.flagsUnordered(ip).runtime_tag.hasTag() and
34549 try Type.fromInterned(union_type.enum_tag_ty).hasRuntimeBitsSema(pt);
34550 const size, const alignment, const padding = if (has_runtime_tag) layout: {
34551 const enum_tag_type: Type = .fromInterned(union_type.enum_tag_ty);
34552 const tag_align = try enum_tag_type.abiAlignmentSema(pt);
34553 const tag_size = try enum_tag_type.abiSizeSema(pt);
34554
34555 // Put the tag before or after the payload depending on which one's
34556 // alignment is greater.
34557 var size: u64 = 0;
34558 var padding: u32 = 0;
34559 if (tag_align.order(max_align).compare(.gte)) {
34560 // {Tag, Payload}
34561 size += tag_size;
34562 size = max_align.forward(size);
34563 size += max_size;
34564 const prev_size = size;
34565 size = tag_align.forward(size);
34566 padding = @intCast(size - prev_size);
34567 } else {
34568 // {Payload, Tag}
34569 size += max_size;
34570 size = switch (pt.zcu.getTarget().ofmt) {
34571 .c => max_align,
34572 else => tag_align,
34573 }.forward(size);
34574 size += tag_size;
34575 const prev_size = size;
34576 size = max_align.forward(size);
34577 padding = @intCast(size - prev_size);
34578 }
34579
34580 break :layout .{ size, max_align.max(tag_align), padding };
34581 } else .{ max_align.forward(max_size), max_align, 0 };
34582
34583 const casted_size = std.math.cast(u32, size) orelse {
34584 const msg = try sema.errMsg(
34585 ty.srcLoc(pt.zcu),
34586 "union layout requires size {d}, this compiler implementation supports up to {d}",
34587 .{ size, std.math.maxInt(u32) },
34588 );
34589 return sema.failWithOwnedErrorMsg(null, msg);
34590 };
34591 union_type.setHaveLayout(ip, io, casted_size, padding, alignment);
34592
34593 if (union_type.flagsUnordered(ip).assumed_runtime_bits and !(try ty.hasRuntimeBitsSema(pt))) {
34594 const msg = try sema.errMsg(
34595 ty.srcLoc(pt.zcu),
34596 "union layout depends on it having runtime bits",
34597 .{},
34598 );
34599 return sema.failWithOwnedErrorMsg(null, msg);
34600 }
34601
34602 if (union_type.flagsUnordered(ip).assumed_pointer_aligned and
34603 alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(pt.zcu.getTarget().ptrBitWidth(), 8))))
34604 {
34605 const msg = try sema.errMsg(
34606 ty.srcLoc(pt.zcu),
34607 "union layout depends on being pointer aligned",
34608 .{},
34609 );
34610 return sema.failWithOwnedErrorMsg(null, msg);
34611 }
34612 _ = try ty.comptimeOnlySema(pt);
34613}
34614
34615/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
34616/// be resolved.
34617pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void {
34618 try sema.resolveStructLayout(ty);
34619 try sema.resolveStructFieldInits(ty);
34620
34621 const pt = sema.pt;
34622 const zcu = pt.zcu;
34623 const io = zcu.comp.io;
34624 const ip = &zcu.intern_pool;
34625 const struct_type = zcu.typeToStruct(ty).?;
34626
34627 assert(sema.owner.unwrap().type == ty.toIntern());
34628
34629 if (struct_type.setFullyResolved(ip, io)) return;
34630 errdefer struct_type.clearFullyResolved(ip, io);
34631
34632 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
34633 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
34634
34635 // After we have resolve struct layout we have to go over the fields again to
34636 // make sure pointer fields get their child types resolved as well.
34637 // See also similar code for unions.
34638
34639 for (0..struct_type.field_types.len) |i| {
34640 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
34641 try field_ty.resolveFully(pt);
34642 }
34643}
34644
34645pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
34646 try sema.resolveUnionLayout(ty);
34647
34648 const pt = sema.pt;
34649 const zcu = pt.zcu;
34650 const io = zcu.comp.io;
34651 const ip = &zcu.intern_pool;
34652 const union_obj = zcu.typeToUnion(ty).?;
34653
34654 assert(sema.owner.unwrap().type == ty.toIntern());
34655
34656 switch (union_obj.flagsUnordered(ip).status) {
34657 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
34658 .fully_resolved_wip, .fully_resolved => return,
34659 }
34660
34661 // No `zcu.trackUnitSema` calls, since this phase isn't really doing any semantic analysis.
34662 // It's just triggering *other* analysis, alongside a simple loop over already-resolved info.
34663
34664 {
34665 // After we have resolve union layout we have to go over the fields again to
34666 // make sure pointer fields get their child types resolved as well.
34667 // See also similar code for structs.
34668 const prev_status = union_obj.flagsUnordered(ip).status;
34669 errdefer union_obj.setStatus(ip, io, prev_status);
34670
34671 union_obj.setStatus(ip, io, .fully_resolved_wip);
34672 for (0..union_obj.field_types.len) |field_index| {
34673 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_index]);
34674 try field_ty.resolveFully(pt);
34675 }
34676 union_obj.setStatus(ip, io, .fully_resolved);
34677 }
34678
34679 // And let's not forget comptime-only status.
34680 _ = try ty.comptimeOnlySema(pt);
34681}
34682
34683pub fn resolveStructFieldTypes(
34684 sema: *Sema,
34685 ty: InternPool.Index,
34686 struct_type: InternPool.LoadedStructType,
34687) SemaError!void {
34688 const pt = sema.pt;
34689 const zcu = pt.zcu;
34690 const io = zcu.comp.io;
34691 const ip = &zcu.intern_pool;
34692
34693 assert(sema.owner.unwrap().type == ty);
34694
34695 if (struct_type.haveFieldTypes(ip)) return;
34696
34697 if (struct_type.setFieldTypesWip(ip, io)) {
34698 const msg = try sema.errMsg(
34699 Type.fromInterned(ty).srcLoc(zcu),
34700 "struct '{f}' depends on itself",
34701 .{Type.fromInterned(ty).fmt(pt)},
34702 );
34703 return sema.failWithOwnedErrorMsg(null, msg);
34704 }
34705 defer struct_type.clearFieldTypesWip(ip, io);
34706
34707 // can't happen earlier than this because we only want the progress node if not already resolved
34708 const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null);
34709 defer tracked_unit.end(zcu);
34710
34711 sema.structFields(struct_type) catch |err| switch (err) {
34712 error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
34713 error.ComptimeBreak, error.ComptimeReturn => unreachable,
34714 };
34715}
34716
34717pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
34718 const pt = sema.pt;
34719 const zcu = pt.zcu;
34720 const io = zcu.comp.io;
34721 const ip = &zcu.intern_pool;
34722 const struct_type = zcu.typeToStruct(ty) orelse return;
34723
34724 assert(sema.owner.unwrap().type == ty.toIntern());
34725
34726 // Inits can start as resolved
34727 if (struct_type.haveFieldInits(ip)) return;
34728
34729 try sema.resolveStructLayout(ty);
34730
34731 if (struct_type.setInitsWip(ip, io)) {
34732 const msg = try sema.errMsg(
34733 ty.srcLoc(zcu),
34734 "struct '{f}' depends on itself",
34735 .{ty.fmt(pt)},
34736 );
34737 return sema.failWithOwnedErrorMsg(null, msg);
34738 }
34739 defer struct_type.clearInitsWip(ip, io);
34740
34741 // can't happen earlier than this because we only want the progress node if not already resolved
34742 const tracked_unit = zcu.trackUnitSema(struct_type.name.toSlice(ip), null);
34743 defer tracked_unit.end(zcu);
34744
34745 sema.structFieldInits(struct_type) catch |err| switch (err) {
34746 error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
34747 error.ComptimeBreak, error.ComptimeReturn => unreachable,
34748 };
34749 struct_type.setHaveFieldInits(ip, io);
34750}
34751
34752pub fn resolveUnionFieldTypes(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) SemaError!void {
34753 const pt = sema.pt;
34754 const zcu = pt.zcu;
34755 const io = zcu.comp.io;
34756 const ip = &zcu.intern_pool;
34757
34758 assert(sema.owner.unwrap().type == ty.toIntern());
34759
34760 switch (union_type.flagsUnordered(ip).status) {
34761 .none => {},
34762 .field_types_wip => {
34763 const msg = try sema.errMsg(ty.srcLoc(zcu), "union '{f}' depends on itself", .{ty.fmt(pt)});
34764 return sema.failWithOwnedErrorMsg(null, msg);
34765 },
34766 .have_field_types,
34767 .have_layout,
34768 .layout_wip,
34769 .fully_resolved_wip,
34770 .fully_resolved,
34771 => return,
34772 }
34773
34774 // can't happen earlier than this because we only want the progress node if not already resolved
34775 const tracked_unit = zcu.trackUnitSema(union_type.name.toSlice(ip), null);
34776 defer tracked_unit.end(zcu);
34777
34778 union_type.setStatus(ip, io, .field_types_wip);
34779 errdefer union_type.setStatus(ip, io, .none);
34780 sema.unionFields(ty.toIntern(), union_type) catch |err| switch (err) {
34781 error.AnalysisFail, error.OutOfMemory, error.Canceled => |e| return e,
34782 error.ComptimeBreak, error.ComptimeReturn => unreachable,
34783 };
34784 union_type.setStatus(ip, io, .have_field_types);
34785}
34786
34787/// Returns a normal error set corresponding to the fully populated inferred33355/// Returns a normal error set corresponding to the fully populated inferred
34788/// error set.33356/// error set.
34789fn resolveInferredErrorSet(33357fn resolveInferredErrorSet(
...@@ -34798,8 +33366,9 @@ fn resolveInferredErrorSet(...@@ -34798,8 +33366,9 @@ fn resolveInferredErrorSet(
34798 const func_index = ip.iesFuncIndex(ies_index);33366 const func_index = ip.iesFuncIndex(ies_index);
34799 const func = zcu.funcInfo(func_index);33367 const func = zcu.funcInfo(func_index);
3480033368
34801 try sema.declareDependency(.{ .interned = func_index }); // resolved IES33369 try sema.declareDependency(.{ .func_ies = func_index });
3480233370
33371 // MLUGG TODO: this feels kinda bad now... instead check for outdated whenver we grab this?
34803 try zcu.maybeUnresolveIes(func_index);33372 try zcu.maybeUnresolveIes(func_index);
34804 const resolved_ty = func.resolvedErrorSetUnordered(ip);33373 const resolved_ty = func.resolvedErrorSetUnordered(ip);
34805 if (resolved_ty != .none) return resolved_ty;33374 if (resolved_ty != .none) return resolved_ty;
...@@ -34820,7 +33389,7 @@ fn resolveInferredErrorSet(...@@ -34820,7 +33389,7 @@ fn resolveInferredErrorSet(
34820 if (ies_func_info.return_type == .generic_poison_type) {33389 if (ies_func_info.return_type == .generic_poison_type) {
34821 assert(ies_func_info.cc == .@"inline");33390 assert(ies_func_info.cc == .@"inline");
34822 } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {33391 } else if (ip.errorUnionSet(ies_func_info.return_type) == ies_index) {
34823 if (ies_func_info.is_generic) {33392 if (!Type.fromInterned(func.ty).fnHasRuntimeBits(zcu)) {
34824 return sema.failWithOwnedErrorMsg(block, msg: {33393 return sema.failWithOwnedErrorMsg(block, msg: {
34825 const msg = try sema.errMsg(src, "unable to resolve inferred error set of generic function", .{});33394 const msg = try sema.errMsg(src, "unable to resolve inferred error set of generic function", .{});
34826 errdefer msg.destroy(sema.gpa);33395 errdefer msg.destroy(sema.gpa);
...@@ -34935,1248 +33504,6 @@ fn resolveInferredErrorSetTy(...@@ -34935,1248 +33504,6 @@ fn resolveInferredErrorSetTy(
34935 }33504 }
34936}33505}
3493733506
34938fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
34939 /// fields_len
34940 usize,
34941 Zir.Inst.StructDecl.Small,
34942 /// extra_index
34943 usize,
34944} {
34945 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
34946 assert(extended.opcode == .struct_decl);
34947 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
34948 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
34949
34950 const captures_len = if (small.has_captures_len) blk: {
34951 const captures_len = zir.extra[extra_index];
34952 extra_index += 1;
34953 break :blk captures_len;
34954 } else 0;
34955
34956 const fields_len = if (small.has_fields_len) blk: {
34957 const fields_len = zir.extra[extra_index];
34958 extra_index += 1;
34959 break :blk fields_len;
34960 } else 0;
34961
34962 const decls_len = if (small.has_decls_len) decls_len: {
34963 const decls_len = zir.extra[extra_index];
34964 extra_index += 1;
34965 break :decls_len decls_len;
34966 } else 0;
34967
34968 extra_index += captures_len * 2;
34969
34970 // The backing integer cannot be handled until `resolveStructLayout()`.
34971 if (small.has_backing_int) {
34972 const backing_int_body_len = zir.extra[extra_index];
34973 extra_index += 1; // backing_int_body_len
34974 if (backing_int_body_len == 0) {
34975 extra_index += 1; // backing_int_ref
34976 } else {
34977 extra_index += backing_int_body_len; // backing_int_body_inst
34978 }
34979 }
34980
34981 // Skip over decls.
34982 extra_index += decls_len;
34983
34984 return .{ fields_len, small, extra_index };
34985}
34986
34987fn structFields(
34988 sema: *Sema,
34989 struct_type: InternPool.LoadedStructType,
34990) CompileError!void {
34991 const pt = sema.pt;
34992 const zcu = pt.zcu;
34993 const comp = zcu.comp;
34994 const gpa = comp.gpa;
34995 const io = comp.io;
34996 const ip = &zcu.intern_pool;
34997
34998 const namespace_index = struct_type.namespace;
34999 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
35000 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
35001
35002 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
35003
35004 if (fields_len == 0) switch (struct_type.layout) {
35005 .@"packed" => {
35006 try sema.backingIntType(struct_type);
35007 return;
35008 },
35009 .auto, .@"extern" => {
35010 struct_type.setLayoutResolved(ip, io, 0, .none);
35011 return;
35012 },
35013 };
35014
35015 var block_scope: Block = .{
35016 .parent = null,
35017 .sema = sema,
35018 .namespace = namespace_index,
35019 .instructions = .{},
35020 .inlining = null,
35021 .comptime_reason = .{ .reason = .{
35022 .src = .{
35023 .base_node_inst = struct_type.zir_index,
35024 .offset = .nodeOffset(.zero),
35025 },
35026 .r = .{ .simple = .type },
35027 } },
35028 .src_base_inst = struct_type.zir_index,
35029 .type_name_ctx = struct_type.name,
35030 };
35031 defer assert(block_scope.instructions.items.len == 0);
35032
35033 const Field = struct {
35034 type_body_len: u32 = 0,
35035 align_body_len: u32 = 0,
35036 init_body_len: u32 = 0,
35037 type_ref: Zir.Inst.Ref = .none,
35038 };
35039 const fields = try sema.arena.alloc(Field, fields_len);
35040
35041 var any_inits = false;
35042 var any_aligned = false;
35043
35044 {
35045 const bits_per_field = 4;
35046 const fields_per_u32 = 32 / bits_per_field;
35047 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
35048 const flags_index = extra_index;
35049 var bit_bag_index: usize = flags_index;
35050 extra_index += bit_bags_count;
35051 var cur_bit_bag: u32 = undefined;
35052 var field_i: u32 = 0;
35053 while (field_i < fields_len) : (field_i += 1) {
35054 if (field_i % fields_per_u32 == 0) {
35055 cur_bit_bag = zir.extra[bit_bag_index];
35056 bit_bag_index += 1;
35057 }
35058 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
35059 cur_bit_bag >>= 1;
35060 const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
35061 cur_bit_bag >>= 1;
35062 const is_comptime = @as(u1, @truncate(cur_bit_bag)) != 0;
35063 cur_bit_bag >>= 1;
35064 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
35065 cur_bit_bag >>= 1;
35066
35067 if (is_comptime) struct_type.setFieldComptime(ip, field_i);
35068
35069 const field_name_zir: [:0]const u8 = zir.nullTerminatedString(@enumFromInt(zir.extra[extra_index]));
35070 extra_index += 1; // field_name
35071
35072 fields[field_i] = .{};
35073
35074 if (has_type_body) {
35075 fields[field_i].type_body_len = zir.extra[extra_index];
35076 } else {
35077 fields[field_i].type_ref = @enumFromInt(zir.extra[extra_index]);
35078 }
35079 extra_index += 1;
35080
35081 // This string needs to outlive the ZIR code.
35082 const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
35083 assert(struct_type.addFieldName(ip, field_name) == null);
35084
35085 if (has_align) {
35086 fields[field_i].align_body_len = zir.extra[extra_index];
35087 extra_index += 1;
35088 any_aligned = true;
35089 }
35090 if (has_init) {
35091 fields[field_i].init_body_len = zir.extra[extra_index];
35092 extra_index += 1;
35093 any_inits = true;
35094 }
35095 }
35096 }
35097
35098 // Next we do only types and alignments, saving the inits for a second pass,
35099 // so that init values may depend on type layout.
35100
35101 for (fields, 0..) |zir_field, field_i| {
35102 const ty_src: LazySrcLoc = .{
35103 .base_node_inst = struct_type.zir_index,
35104 .offset = .{ .container_field_type = @intCast(field_i) },
35105 };
35106 const field_ty: Type = ty: {
35107 if (zir_field.type_ref != .none) {
35108 break :ty try sema.resolveType(&block_scope, ty_src, zir_field.type_ref);
35109 }
35110 assert(zir_field.type_body_len != 0);
35111 const body = zir.bodySlice(extra_index, zir_field.type_body_len);
35112 extra_index += body.len;
35113 const ty_ref = try sema.resolveInlineBody(&block_scope, body, zir_index);
35114 break :ty try sema.analyzeAsType(&block_scope, ty_src, ty_ref);
35115 };
35116
35117 struct_type.field_types.get(ip)[field_i] = field_ty.toIntern();
35118
35119 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
35120 const msg = msg: {
35121 const msg = try sema.errMsg(ty_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
35122 errdefer msg.destroy(sema.gpa);
35123
35124 try sema.addDeclaredHereNote(msg, field_ty);
35125 break :msg msg;
35126 };
35127 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35128 }
35129 if (field_ty.zigTypeTag(zcu) == .noreturn) {
35130 const msg = msg: {
35131 const msg = try sema.errMsg(ty_src, "struct fields cannot be 'noreturn'", .{});
35132 errdefer msg.destroy(sema.gpa);
35133
35134 try sema.addDeclaredHereNote(msg, field_ty);
35135 break :msg msg;
35136 };
35137 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35138 }
35139 switch (struct_type.layout) {
35140 .@"extern" => if (!try sema.validateExternType(field_ty, .struct_field)) {
35141 const msg = msg: {
35142 const msg = try sema.errMsg(ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35143 errdefer msg.destroy(sema.gpa);
35144
35145 try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .struct_field);
35146
35147 try sema.addDeclaredHereNote(msg, field_ty);
35148 break :msg msg;
35149 };
35150 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35151 },
35152 .@"packed" => if (!try sema.validatePackedType(field_ty)) {
35153 const msg = msg: {
35154 const msg = try sema.errMsg(ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35155 errdefer msg.destroy(sema.gpa);
35156
35157 try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
35158
35159 try sema.addDeclaredHereNote(msg, field_ty);
35160 break :msg msg;
35161 };
35162 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35163 },
35164 else => {},
35165 }
35166
35167 if (zir_field.align_body_len > 0) {
35168 const body = zir.bodySlice(extra_index, zir_field.align_body_len);
35169 extra_index += body.len;
35170 const align_ref = try sema.resolveInlineBody(&block_scope, body, zir_index);
35171 const align_src: LazySrcLoc = .{
35172 .base_node_inst = struct_type.zir_index,
35173 .offset = .{ .container_field_align = @intCast(field_i) },
35174 };
35175 const field_align = try sema.analyzeAsAlign(&block_scope, align_src, align_ref);
35176 struct_type.field_aligns.get(ip)[field_i] = field_align;
35177 }
35178
35179 extra_index += zir_field.init_body_len;
35180 }
35181
35182 struct_type.clearFieldTypesWip(ip, io);
35183 if (!any_inits) struct_type.setHaveFieldInits(ip, io);
35184
35185 try sema.flushExports();
35186}
35187
35188// This logic must be kept in sync with `structFields`
35189fn structFieldInits(
35190 sema: *Sema,
35191 struct_type: InternPool.LoadedStructType,
35192) CompileError!void {
35193 const pt = sema.pt;
35194 const zcu = pt.zcu;
35195 const ip = &zcu.intern_pool;
35196
35197 assert(!struct_type.haveFieldInits(ip));
35198
35199 const namespace_index = struct_type.namespace;
35200 const zir = zcu.namespacePtr(namespace_index).fileScope(zcu).zir.?;
35201 const zir_index = struct_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
35202 const fields_len, _, var extra_index = structZirInfo(zir, zir_index);
35203
35204 var block_scope: Block = .{
35205 .parent = null,
35206 .sema = sema,
35207 .namespace = namespace_index,
35208 .instructions = .{},
35209 .inlining = null,
35210 .comptime_reason = undefined, // set when `block_scope` is used
35211 .src_base_inst = struct_type.zir_index,
35212 .type_name_ctx = struct_type.name,
35213 };
35214 defer assert(block_scope.instructions.items.len == 0);
35215
35216 const Field = struct {
35217 type_body_len: u32 = 0,
35218 align_body_len: u32 = 0,
35219 init_body_len: u32 = 0,
35220 };
35221 const fields = try sema.arena.alloc(Field, fields_len);
35222
35223 var any_inits = false;
35224
35225 {
35226 const bits_per_field = 4;
35227 const fields_per_u32 = 32 / bits_per_field;
35228 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
35229 const flags_index = extra_index;
35230 var bit_bag_index: usize = flags_index;
35231 extra_index += bit_bags_count;
35232 var cur_bit_bag: u32 = undefined;
35233 var field_i: u32 = 0;
35234 while (field_i < fields_len) : (field_i += 1) {
35235 if (field_i % fields_per_u32 == 0) {
35236 cur_bit_bag = zir.extra[bit_bag_index];
35237 bit_bag_index += 1;
35238 }
35239 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
35240 cur_bit_bag >>= 1;
35241 const has_init = @as(u1, @truncate(cur_bit_bag)) != 0;
35242 cur_bit_bag >>= 2;
35243 const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
35244 cur_bit_bag >>= 1;
35245
35246 extra_index += 1; // field_name
35247
35248 fields[field_i] = .{};
35249
35250 if (has_type_body) fields[field_i].type_body_len = zir.extra[extra_index];
35251 extra_index += 1;
35252
35253 if (has_align) {
35254 fields[field_i].align_body_len = zir.extra[extra_index];
35255 extra_index += 1;
35256 }
35257 if (has_init) {
35258 fields[field_i].init_body_len = zir.extra[extra_index];
35259 extra_index += 1;
35260 any_inits = true;
35261 }
35262 }
35263 }
35264
35265 if (any_inits) {
35266 for (fields, 0..) |zir_field, field_i| {
35267 extra_index += zir_field.type_body_len;
35268 extra_index += zir_field.align_body_len;
35269 const body = zir.bodySlice(extra_index, zir_field.init_body_len);
35270 extra_index += zir_field.init_body_len;
35271
35272 if (body.len == 0) continue;
35273
35274 // Pre-populate the type mapping the body expects to be there.
35275 // In init bodies, the zir index of the struct itself is used
35276 // to refer to the current field type.
35277
35278 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[field_i]);
35279 const type_ref = Air.internedToRef(field_ty.toIntern());
35280 try sema.inst_map.ensureSpaceForInstructions(sema.gpa, &.{zir_index});
35281 sema.inst_map.putAssumeCapacity(zir_index, type_ref);
35282
35283 const init_src: LazySrcLoc = .{
35284 .base_node_inst = struct_type.zir_index,
35285 .offset = .{ .container_field_value = @intCast(field_i) },
35286 };
35287
35288 block_scope.comptime_reason = .{ .reason = .{
35289 .src = init_src,
35290 .r = .{ .simple = .struct_field_default_value },
35291 } };
35292 const init = try sema.resolveInlineBody(&block_scope, body, zir_index);
35293 const coerced = try sema.coerce(&block_scope, field_ty, init, init_src);
35294 const default_val = try sema.resolveConstValue(&block_scope, init_src, coerced, null);
35295
35296 if (default_val.canMutateComptimeVarState(zcu)) {
35297 return sema.failWithContainsReferenceToComptimeVar(
35298 &block_scope,
35299 init_src,
35300 struct_type.fieldName(ip, field_i),
35301 "field default value",
35302 default_val,
35303 );
35304 }
35305 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
35306 }
35307 }
35308
35309 try sema.flushExports();
35310}
35311
35312fn unionFields(
35313 sema: *Sema,
35314 union_ty: InternPool.Index,
35315 union_type: InternPool.LoadedUnionType,
35316) CompileError!void {
35317 const tracy = trace(@src());
35318 defer tracy.end();
35319
35320 const pt = sema.pt;
35321 const zcu = pt.zcu;
35322 const comp = zcu.comp;
35323 const gpa = comp.gpa;
35324 const io = comp.io;
35325 const ip = &zcu.intern_pool;
35326
35327 const zir = zcu.namespacePtr(union_type.namespace).fileScope(zcu).zir.?;
35328 const zir_index = union_type.zir_index.resolve(ip) orelse return error.AnalysisFail;
35329 const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
35330 assert(extended.opcode == .union_decl);
35331 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
35332 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
35333 var extra_index: usize = extra.end;
35334
35335 const tag_type_ref: Zir.Inst.Ref = if (small.has_tag_type) blk: {
35336 const ty_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35337 extra_index += 1;
35338 break :blk ty_ref;
35339 } else .none;
35340
35341 const captures_len = if (small.has_captures_len) blk: {
35342 const captures_len = zir.extra[extra_index];
35343 extra_index += 1;
35344 break :blk captures_len;
35345 } else 0;
35346
35347 const body_len = if (small.has_body_len) blk: {
35348 const body_len = zir.extra[extra_index];
35349 extra_index += 1;
35350 break :blk body_len;
35351 } else 0;
35352
35353 const fields_len = if (small.has_fields_len) blk: {
35354 const fields_len = zir.extra[extra_index];
35355 extra_index += 1;
35356 break :blk fields_len;
35357 } else 0;
35358
35359 const decls_len = if (small.has_decls_len) decls_len: {
35360 const decls_len = zir.extra[extra_index];
35361 extra_index += 1;
35362 break :decls_len decls_len;
35363 } else 0;
35364
35365 // Skip over captures and decls.
35366 extra_index += captures_len * 2 + decls_len;
35367
35368 const body = zir.bodySlice(extra_index, body_len);
35369 extra_index += body.len;
35370
35371 const src: LazySrcLoc = .{
35372 .base_node_inst = union_type.zir_index,
35373 .offset = .nodeOffset(.zero),
35374 };
35375
35376 var block_scope: Block = .{
35377 .parent = null,
35378 .sema = sema,
35379 .namespace = union_type.namespace,
35380 .instructions = .{},
35381 .inlining = null,
35382 .comptime_reason = .{ .reason = .{
35383 .src = src,
35384 .r = .{ .simple = .type },
35385 } },
35386 .src_base_inst = union_type.zir_index,
35387 .type_name_ctx = union_type.name,
35388 };
35389 defer assert(block_scope.instructions.items.len == 0);
35390
35391 if (body.len != 0) {
35392 _ = try sema.analyzeInlineBody(&block_scope, body, zir_index);
35393 }
35394
35395 var int_tag_ty: Type = undefined;
35396 var enum_field_names: []InternPool.NullTerminatedString = &.{};
35397 var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .empty;
35398 var explicit_tags_seen: []bool = &.{};
35399 if (tag_type_ref != .none) {
35400 const tag_ty_src: LazySrcLoc = .{
35401 .base_node_inst = union_type.zir_index,
35402 .offset = .{ .node_offset_container_tag = .zero },
35403 };
35404 const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
35405 if (small.auto_enum_tag) {
35406 // The provided type is an integer type and we must construct the enum tag type here.
35407 int_tag_ty = provided_ty;
35408 if (int_tag_ty.zigTypeTag(zcu) != .int and int_tag_ty.zigTypeTag(zcu) != .comptime_int) {
35409 return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{f}'", .{int_tag_ty.fmt(pt)});
35410 }
35411
35412 if (fields_len > 0) {
35413 const field_count_val = try pt.intValue(.comptime_int, fields_len - 1);
35414 if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) {
35415 const msg = msg: {
35416 const msg = try sema.errMsg(tag_ty_src, "specified integer tag type cannot represent every field", .{});
35417 errdefer msg.destroy(sema.gpa);
35418 try sema.errNote(tag_ty_src, msg, "type '{f}' cannot fit values in range 0...{d}", .{
35419 int_tag_ty.fmt(pt),
35420 fields_len - 1,
35421 });
35422 break :msg msg;
35423 };
35424 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35425 }
35426 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
35427 try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len);
35428 }
35429 } else {
35430 // The provided type is the enum tag type.
35431 const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
35432 .enum_type => ip.loadEnumType(provided_ty.toIntern()),
35433 else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{f}'", .{provided_ty.fmt(pt)}),
35434 };
35435 union_type.setTagType(ip, io, provided_ty.toIntern());
35436 // The fields of the union must match the enum exactly.
35437 // A flag per field is used to check for missing and extraneous fields.
35438 explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
35439 @memset(explicit_tags_seen, false);
35440 }
35441 } else {
35442 // If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
35443 // purposes, we still auto-generate an enum tag type the same way. That the union is
35444 // untagged is represented by the Type tag (union vs union_tagged).
35445 enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
35446 }
35447
35448 var field_types: std.ArrayList(InternPool.Index) = .empty;
35449 var field_aligns: std.ArrayList(InternPool.Alignment) = .empty;
35450
35451 try field_types.ensureTotalCapacityPrecise(sema.arena, fields_len);
35452 if (small.any_aligned_fields)
35453 try field_aligns.ensureTotalCapacityPrecise(sema.arena, fields_len);
35454
35455 var max_bits: u64 = 0;
35456 var min_bits: u64 = std.math.maxInt(u64);
35457 var max_bits_src: LazySrcLoc = undefined;
35458 var min_bits_src: LazySrcLoc = undefined;
35459 var max_bits_ty: Type = undefined;
35460 var min_bits_ty: Type = undefined;
35461 const bits_per_field = 4;
35462 const fields_per_u32 = 32 / bits_per_field;
35463 const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
35464 var bit_bag_index: usize = extra_index;
35465 extra_index += bit_bags_count;
35466 var cur_bit_bag: u32 = undefined;
35467 var field_i: u32 = 0;
35468 var last_tag_val: ?Value = null;
35469 const layout = union_type.flagsUnordered(ip).layout;
35470 while (field_i < fields_len) : (field_i += 1) {
35471 if (field_i % fields_per_u32 == 0) {
35472 cur_bit_bag = zir.extra[bit_bag_index];
35473 bit_bag_index += 1;
35474 }
35475 const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;
35476 cur_bit_bag >>= 1;
35477 const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
35478 cur_bit_bag >>= 1;
35479 const has_tag = @as(u1, @truncate(cur_bit_bag)) != 0;
35480 cur_bit_bag >>= 1;
35481 const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
35482 cur_bit_bag >>= 1;
35483 _ = unused;
35484
35485 const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]);
35486 const field_name_zir = zir.nullTerminatedString(field_name_index);
35487 extra_index += 1;
35488
35489 const field_type_ref: Zir.Inst.Ref = if (has_type) blk: {
35490 const field_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35491 extra_index += 1;
35492 break :blk field_type_ref;
35493 } else .none;
35494
35495 const align_ref: Zir.Inst.Ref = if (has_align) blk: {
35496 const align_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35497 extra_index += 1;
35498 break :blk align_ref;
35499 } else .none;
35500
35501 const tag_ref: Air.Inst.Ref = if (has_tag) blk: {
35502 const tag_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
35503 extra_index += 1;
35504 break :blk try sema.resolveInst(tag_ref);
35505 } else .none;
35506
35507 const name_src: LazySrcLoc = .{
35508 .base_node_inst = union_type.zir_index,
35509 .offset = .{ .container_field_name = field_i },
35510 };
35511 const value_src: LazySrcLoc = .{
35512 .base_node_inst = union_type.zir_index,
35513 .offset = .{ .container_field_value = field_i },
35514 };
35515 const align_src: LazySrcLoc = .{
35516 .base_node_inst = union_type.zir_index,
35517 .offset = .{ .container_field_align = field_i },
35518 };
35519 const type_src: LazySrcLoc = .{
35520 .base_node_inst = union_type.zir_index,
35521 .offset = .{ .container_field_type = field_i },
35522 };
35523
35524 if (enum_field_vals.capacity() > 0) {
35525 const enum_tag_val = if (tag_ref != .none) blk: {
35526 const coerced = try sema.coerce(&block_scope, int_tag_ty, tag_ref, value_src);
35527 const val = try sema.resolveConstDefinedValue(&block_scope, value_src, coerced, .{ .simple = .enum_field_tag_value });
35528 last_tag_val = val;
35529
35530 break :blk val;
35531 } else blk: {
35532 if (last_tag_val) |last_tag| {
35533 const result = try arith.incrementDefinedInt(sema, int_tag_ty, last_tag);
35534 if (result.overflow) return sema.fail(
35535 &block_scope,
35536 value_src,
35537 "enumeration value '{f}' too large for type '{f}'",
35538 .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) },
35539 );
35540 last_tag_val = result.val;
35541 } else {
35542 last_tag_val = try pt.intValue(int_tag_ty, 0);
35543 }
35544 break :blk last_tag_val.?;
35545 };
35546 const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());
35547 if (gop.found_existing) {
35548 const other_value_src: LazySrcLoc = .{
35549 .base_node_inst = union_type.zir_index,
35550 .offset = .{ .container_field_value = @intCast(gop.index) },
35551 };
35552 const msg = msg: {
35553 const msg = try sema.errMsg(
35554 value_src,
35555 "enum tag value {f} already taken",
35556 .{enum_tag_val.fmtValueSema(pt, sema)},
35557 );
35558 errdefer msg.destroy(gpa);
35559 try sema.errNote(other_value_src, msg, "other occurrence here", .{});
35560 break :msg msg;
35561 };
35562 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35563 }
35564 }
35565
35566 // This string needs to outlive the ZIR code.
35567 const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
35568 if (enum_field_names.len != 0) {
35569 enum_field_names[field_i] = field_name;
35570 }
35571
35572 const field_ty: Type = if (!has_type)
35573 .void
35574 else if (field_type_ref == .none)
35575 .noreturn
35576 else
35577 try sema.resolveType(&block_scope, type_src, field_type_ref);
35578
35579 if (explicit_tags_seen.len > 0) {
35580 const tag_ty = union_type.tagTypeUnordered(ip);
35581 const tag_info = ip.loadEnumType(tag_ty);
35582 const enum_index = tag_info.nameIndex(ip, field_name) orelse {
35583 return sema.fail(&block_scope, name_src, "no field named '{f}' in enum '{f}'", .{
35584 field_name.fmt(ip), Type.fromInterned(tag_ty).fmt(pt),
35585 });
35586 };
35587
35588 // No check for duplicate because the check already happened in order
35589 // to create the enum type in the first place.
35590 assert(!explicit_tags_seen[enum_index]);
35591 explicit_tags_seen[enum_index] = true;
35592
35593 // Enforce the enum fields and the union fields being in the same order.
35594 if (enum_index != field_i) {
35595 const msg = msg: {
35596 const enum_field_src: LazySrcLoc = .{
35597 .base_node_inst = Type.fromInterned(tag_ty).typeDeclInstAllowGeneratedTag(zcu).?,
35598 .offset = .{ .container_field_name = enum_index },
35599 };
35600 const msg = try sema.errMsg(name_src, "union field '{f}' ordered differently than corresponding enum field", .{
35601 field_name.fmt(ip),
35602 });
35603 errdefer msg.destroy(sema.gpa);
35604 try sema.errNote(enum_field_src, msg, "enum field here", .{});
35605 break :msg msg;
35606 };
35607 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35608 }
35609 }
35610
35611 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
35612 const msg = msg: {
35613 const msg = try sema.errMsg(type_src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
35614 errdefer msg.destroy(sema.gpa);
35615
35616 try sema.addDeclaredHereNote(msg, field_ty);
35617 break :msg msg;
35618 };
35619 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35620 }
35621 switch (layout) {
35622 .@"extern" => if (!try sema.validateExternType(field_ty, .union_field)) {
35623 const msg = msg: {
35624 const msg = try sema.errMsg(type_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35625 errdefer msg.destroy(sema.gpa);
35626
35627 try sema.explainWhyTypeIsNotExtern(msg, type_src, field_ty, .union_field);
35628
35629 try sema.addDeclaredHereNote(msg, field_ty);
35630 break :msg msg;
35631 };
35632 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35633 },
35634 .@"packed" => {
35635 if (!try sema.validatePackedType(field_ty)) {
35636 const msg = msg: {
35637 const msg = try sema.errMsg(type_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
35638 errdefer msg.destroy(sema.gpa);
35639
35640 try sema.explainWhyTypeIsNotPacked(msg, type_src, field_ty);
35641
35642 try sema.addDeclaredHereNote(msg, field_ty);
35643 break :msg msg;
35644 };
35645 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35646 }
35647 const field_bits = try field_ty.bitSizeSema(pt);
35648 if (field_bits >= max_bits) {
35649 max_bits = field_bits;
35650 max_bits_src = type_src;
35651 max_bits_ty = field_ty;
35652 }
35653 if (field_bits <= min_bits) {
35654 min_bits = field_bits;
35655 min_bits_src = type_src;
35656 min_bits_ty = field_ty;
35657 }
35658 },
35659 .auto => {},
35660 }
35661
35662 field_types.appendAssumeCapacity(field_ty.toIntern());
35663
35664 if (small.any_aligned_fields) {
35665 field_aligns.appendAssumeCapacity(if (align_ref != .none)
35666 try sema.resolveAlign(&block_scope, align_src, align_ref)
35667 else
35668 .none);
35669 } else {
35670 assert(align_ref == .none);
35671 }
35672 }
35673
35674 union_type.setFieldTypes(ip, field_types.items);
35675 union_type.setFieldAligns(ip, field_aligns.items);
35676
35677 if (layout == .@"packed" and fields_len != 0 and min_bits != max_bits) {
35678 const msg = msg: {
35679 const msg = try sema.errMsg(src, "packed union has fields with mismatching bit sizes", .{});
35680 errdefer msg.destroy(sema.gpa);
35681 try sema.errNote(min_bits_src, msg, "{d} bits here", .{min_bits});
35682 try sema.addDeclaredHereNote(msg, min_bits_ty);
35683 try sema.errNote(max_bits_src, msg, "{d} bits here", .{max_bits});
35684 try sema.addDeclaredHereNote(msg, max_bits_ty);
35685 break :msg msg;
35686 };
35687 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35688 }
35689
35690 if (explicit_tags_seen.len > 0) {
35691 const tag_ty = union_type.tagTypeUnordered(ip);
35692 const tag_info = ip.loadEnumType(tag_ty);
35693 if (tag_info.names.len > fields_len) {
35694 const msg = msg: {
35695 const msg = try sema.errMsg(src, "enum field(s) missing in union", .{});
35696 errdefer msg.destroy(sema.gpa);
35697
35698 for (tag_info.names.get(ip), 0..) |field_name, field_index| {
35699 if (explicit_tags_seen[field_index]) continue;
35700 try sema.addFieldErrNote(.fromInterned(tag_ty), field_index, msg, "field '{f}' missing, declared here", .{
35701 field_name.fmt(ip),
35702 });
35703 }
35704 try sema.addDeclaredHereNote(msg, .fromInterned(tag_ty));
35705 break :msg msg;
35706 };
35707 return sema.failWithOwnedErrorMsg(&block_scope, msg);
35708 }
35709 } else if (enum_field_vals.count() > 0) {
35710 const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_ty, union_type.name);
35711 union_type.setTagType(ip, io, enum_ty);
35712 } else {
35713 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_ty, union_type.name);
35714 union_type.setTagType(ip, io, enum_ty);
35715 }
35716
35717 try sema.flushExports();
35718}
35719
35720fn generateUnionTagTypeNumbered(
35721 sema: *Sema,
35722 block: *Block,
35723 enum_field_names: []const InternPool.NullTerminatedString,
35724 enum_field_vals: []const InternPool.Index,
35725 union_type: InternPool.Index,
35726 union_name: InternPool.NullTerminatedString,
35727) !InternPool.Index {
35728 const pt = sema.pt;
35729 const zcu = pt.zcu;
35730 const comp = zcu.comp;
35731 const gpa = comp.gpa;
35732 const io = comp.io;
35733 const ip = &zcu.intern_pool;
35734
35735 const name = try ip.getOrPutStringFmt(
35736 gpa,
35737 io,
35738 pt.tid,
35739 "@typeInfo({f}).@\"union\".tag_type.?",
35740 .{union_name.fmt(ip)},
35741 .no_embedded_nulls,
35742 );
35743
35744 const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{
35745 .name = name,
35746 .owner_union_ty = union_type,
35747 .tag_ty = if (enum_field_vals.len == 0)
35748 (try pt.intType(.unsigned, 0)).toIntern()
35749 else
35750 ip.typeOf(enum_field_vals[0]),
35751 .names = enum_field_names,
35752 .values = enum_field_vals,
35753 .tag_mode = .explicit,
35754 .parent_namespace = block.namespace,
35755 });
35756
35757 return enum_ty;
35758}
35759
35760fn generateUnionTagTypeSimple(
35761 sema: *Sema,
35762 block: *Block,
35763 enum_field_names: []const InternPool.NullTerminatedString,
35764 union_type: InternPool.Index,
35765 union_name: InternPool.NullTerminatedString,
35766) !InternPool.Index {
35767 const pt = sema.pt;
35768 const zcu = pt.zcu;
35769 const comp = zcu.comp;
35770 const gpa = comp.gpa;
35771 const io = comp.io;
35772 const ip = &zcu.intern_pool;
35773
35774 const name = try ip.getOrPutStringFmt(
35775 gpa,
35776 io,
35777 pt.tid,
35778 "@typeInfo({f}).@\"union\".tag_type.?",
35779 .{union_name.fmt(ip)},
35780 .no_embedded_nulls,
35781 );
35782
35783 const enum_ty = try ip.getGeneratedTagEnumType(gpa, io, pt.tid, .{
35784 .name = name,
35785 .owner_union_ty = union_type,
35786 .tag_ty = (try pt.smallestUnsignedInt(enum_field_names.len -| 1)).toIntern(),
35787 .names = enum_field_names,
35788 .values = &.{},
35789 .tag_mode = .auto,
35790 .parent_namespace = block.namespace,
35791 });
35792
35793 return enum_ty;
35794}
35795
35796/// There is another implementation of this in `Type.onePossibleValue`. This one
35797/// in `Sema` is for calling during semantic analysis, and performs field resolution
35798/// to get the answer. The one in `Type` is for calling during codegen and asserts
35799/// that the types are already resolved.
35800/// TODO assert the return value matches `ty.onePossibleValue`
35801pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
35802 const pt = sema.pt;
35803 const zcu = pt.zcu;
35804 const comp = zcu.comp;
35805 const gpa = comp.gpa;
35806 const io = comp.io;
35807 const ip = &zcu.intern_pool;
35808
35809 return switch (ty.toIntern()) {
35810 .u0_type,
35811 .i0_type,
35812 => try pt.intValue(ty, 0),
35813 .u1_type,
35814 .u8_type,
35815 .i8_type,
35816 .u16_type,
35817 .i16_type,
35818 .u29_type,
35819 .u32_type,
35820 .i32_type,
35821 .u64_type,
35822 .i64_type,
35823 .u80_type,
35824 .u128_type,
35825 .i128_type,
35826 .u256_type,
35827 .usize_type,
35828 .isize_type,
35829 .c_char_type,
35830 .c_short_type,
35831 .c_ushort_type,
35832 .c_int_type,
35833 .c_uint_type,
35834 .c_long_type,
35835 .c_ulong_type,
35836 .c_longlong_type,
35837 .c_ulonglong_type,
35838 .c_longdouble_type,
35839 .f16_type,
35840 .f32_type,
35841 .f64_type,
35842 .f80_type,
35843 .f128_type,
35844 .anyopaque_type,
35845 .bool_type,
35846 .type_type,
35847 .anyerror_type,
35848 .adhoc_inferred_error_set_type,
35849 .comptime_int_type,
35850 .comptime_float_type,
35851 .enum_literal_type,
35852 .ptr_usize_type,
35853 .ptr_const_comptime_int_type,
35854 .manyptr_u8_type,
35855 .manyptr_const_u8_type,
35856 .manyptr_const_u8_sentinel_0_type,
35857 .manyptr_const_slice_const_u8_type,
35858 .slice_const_u8_type,
35859 .slice_const_u8_sentinel_0_type,
35860 .slice_const_slice_const_u8_type,
35861 .optional_type_type,
35862 .manyptr_const_type_type,
35863 .slice_const_type_type,
35864 .vector_8_i8_type,
35865 .vector_16_i8_type,
35866 .vector_32_i8_type,
35867 .vector_64_i8_type,
35868 .vector_1_u8_type,
35869 .vector_2_u8_type,
35870 .vector_4_u8_type,
35871 .vector_8_u8_type,
35872 .vector_16_u8_type,
35873 .vector_32_u8_type,
35874 .vector_64_u8_type,
35875 .vector_2_i16_type,
35876 .vector_4_i16_type,
35877 .vector_8_i16_type,
35878 .vector_16_i16_type,
35879 .vector_32_i16_type,
35880 .vector_4_u16_type,
35881 .vector_8_u16_type,
35882 .vector_16_u16_type,
35883 .vector_32_u16_type,
35884 .vector_2_i32_type,
35885 .vector_4_i32_type,
35886 .vector_8_i32_type,
35887 .vector_16_i32_type,
35888 .vector_4_u32_type,
35889 .vector_8_u32_type,
35890 .vector_16_u32_type,
35891 .vector_2_i64_type,
35892 .vector_4_i64_type,
35893 .vector_8_i64_type,
35894 .vector_2_u64_type,
35895 .vector_4_u64_type,
35896 .vector_8_u64_type,
35897 .vector_1_u128_type,
35898 .vector_2_u128_type,
35899 .vector_1_u256_type,
35900 .vector_4_f16_type,
35901 .vector_8_f16_type,
35902 .vector_16_f16_type,
35903 .vector_32_f16_type,
35904 .vector_2_f32_type,
35905 .vector_4_f32_type,
35906 .vector_8_f32_type,
35907 .vector_16_f32_type,
35908 .vector_2_f64_type,
35909 .vector_4_f64_type,
35910 .vector_8_f64_type,
35911 .anyerror_void_error_union_type,
35912 => null,
35913 .void_type => Value.void,
35914 .noreturn_type => Value.@"unreachable",
35915 .anyframe_type => unreachable,
35916 .null_type => Value.null,
35917 .undefined_type => Value.undef,
35918 .optional_noreturn_type => try pt.nullValue(ty),
35919 .generic_poison_type => unreachable,
35920 .empty_tuple_type => Value.empty_tuple,
35921 // values, not types
35922 .undef,
35923 .undef_bool,
35924 .undef_usize,
35925 .undef_u1,
35926 .zero,
35927 .zero_usize,
35928 .zero_u1,
35929 .zero_u8,
35930 .one,
35931 .one_usize,
35932 .one_u1,
35933 .one_u8,
35934 .four_u8,
35935 .negative_one,
35936 .void_value,
35937 .unreachable_value,
35938 .null_value,
35939 .bool_true,
35940 .bool_false,
35941 .empty_tuple,
35942 // invalid
35943 .none,
35944 => unreachable,
35945
35946 _ => switch (ty.toIntern().unwrap(ip).getTag(ip)) {
35947 .removed => unreachable,
35948
35949 .type_int_signed, // i0 handled above
35950 .type_int_unsigned, // u0 handled above
35951 .type_pointer,
35952 .type_slice,
35953 .type_anyframe,
35954 .type_error_union,
35955 .type_anyerror_union,
35956 .type_error_set,
35957 .type_inferred_error_set,
35958 .type_opaque,
35959 .type_function,
35960 => null,
35961
35962 .simple_type, // handled above
35963 // values, not types
35964 .undef,
35965 .simple_value,
35966 .ptr_nav,
35967 .ptr_uav,
35968 .ptr_uav_aligned,
35969 .ptr_comptime_alloc,
35970 .ptr_comptime_field,
35971 .ptr_int,
35972 .ptr_eu_payload,
35973 .ptr_opt_payload,
35974 .ptr_elem,
35975 .ptr_field,
35976 .ptr_slice,
35977 .opt_payload,
35978 .opt_null,
35979 .int_u8,
35980 .int_u16,
35981 .int_u32,
35982 .int_i32,
35983 .int_usize,
35984 .int_comptime_int_u32,
35985 .int_comptime_int_i32,
35986 .int_small,
35987 .int_positive,
35988 .int_negative,
35989 .int_lazy_align,
35990 .int_lazy_size,
35991 .error_set_error,
35992 .error_union_error,
35993 .error_union_payload,
35994 .enum_literal,
35995 .enum_tag,
35996 .float_f16,
35997 .float_f32,
35998 .float_f64,
35999 .float_f80,
36000 .float_f128,
36001 .float_c_longdouble_f80,
36002 .float_c_longdouble_f128,
36003 .float_comptime_float,
36004 .variable,
36005 .threadlocal_variable,
36006 .@"extern",
36007 .func_decl,
36008 .func_instance,
36009 .func_coerced,
36010 .only_possible_value,
36011 .union_value,
36012 .bytes,
36013 .aggregate,
36014 .repeated,
36015 // memoized value, not types
36016 .memoized_call,
36017 => unreachable,
36018
36019 .type_array_big,
36020 .type_array_small,
36021 .type_vector,
36022 .type_enum_auto,
36023 .type_enum_explicit,
36024 .type_enum_nonexhaustive,
36025 .type_struct,
36026 .type_struct_packed,
36027 .type_struct_packed_inits,
36028 .type_tuple,
36029 .type_union,
36030 => switch (ip.indexToKey(ty.toIntern())) {
36031 inline .array_type, .vector_type => |seq_type, seq_tag| {
36032 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
36033 if (seq_type.len + @intFromBool(has_sentinel) == 0) return try pt.aggregateValue(ty, &.{});
36034 if (try sema.typeHasOnePossibleValue(.fromInterned(seq_type.child))) |opv| {
36035 return try pt.aggregateSplatValue(ty, opv);
36036 }
36037 return null;
36038 },
36039
36040 .struct_type => {
36041 // Resolving the layout first helps to avoid loops.
36042 // If the type has a coherent layout, we can recurse through fields safely.
36043 try ty.resolveLayout(pt);
36044
36045 const struct_type = ip.loadStructType(ty.toIntern());
36046
36047 if (struct_type.field_types.len == 0) {
36048 // In this case the struct has no fields at all and
36049 // therefore has one possible value.
36050 return try pt.aggregateValue(ty, &.{});
36051 }
36052
36053 const field_vals = try sema.arena.alloc(
36054 InternPool.Index,
36055 struct_type.field_types.len,
36056 );
36057 for (field_vals, 0..) |*field_val, i| {
36058 if (struct_type.fieldIsComptime(ip, i)) {
36059 try ty.resolveStructFieldInits(pt);
36060 field_val.* = struct_type.field_inits.get(ip)[i];
36061 continue;
36062 }
36063 const field_ty: Type = .fromInterned(struct_type.field_types.get(ip)[i]);
36064 if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| {
36065 field_val.* = field_opv.toIntern();
36066 } else return null;
36067 }
36068
36069 // In this case the struct has no runtime-known fields and
36070 // therefore has one possible value.
36071 return try pt.aggregateValue(ty, field_vals);
36072 },
36073
36074 .tuple_type => |tuple| {
36075 try ty.resolveLayout(pt);
36076
36077 if (tuple.types.len == 0) {
36078 return try pt.aggregateValue(ty, &.{});
36079 }
36080
36081 const field_vals = try sema.arena.alloc(
36082 InternPool.Index,
36083 tuple.types.len,
36084 );
36085 for (
36086 field_vals,
36087 tuple.types.get(ip),
36088 tuple.values.get(ip),
36089 ) |*field_val, field_ty, field_comptime_val| {
36090 if (field_comptime_val != .none) {
36091 field_val.* = field_comptime_val;
36092 continue;
36093 }
36094 if (try sema.typeHasOnePossibleValue(.fromInterned(field_ty))) |opv| {
36095 field_val.* = opv.toIntern();
36096 } else return null;
36097 }
36098
36099 return try pt.aggregateValue(ty, field_vals);
36100 },
36101
36102 .union_type => {
36103 // Resolving the layout first helps to avoid loops.
36104 // If the type has a coherent layout, we can recurse through fields safely.
36105 try ty.resolveLayout(pt);
36106
36107 const union_obj = ip.loadUnionType(ty.toIntern());
36108 const tag_val = (try sema.typeHasOnePossibleValue(.fromInterned(union_obj.tagTypeUnordered(ip)))) orelse
36109 return null;
36110 if (union_obj.field_types.len == 0) {
36111 const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
36112 return Value.fromInterned(only);
36113 }
36114 const only_field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[0]);
36115 const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse
36116 return null;
36117 const only = try pt.internUnion(.{
36118 .ty = ty.toIntern(),
36119 .tag = tag_val.toIntern(),
36120 .val = val_val.toIntern(),
36121 });
36122 return Value.fromInterned(only);
36123 },
36124
36125 .enum_type => {
36126 const enum_type = ip.loadEnumType(ty.toIntern());
36127 switch (enum_type.tag_mode) {
36128 .nonexhaustive => {
36129 if (enum_type.tag_ty == .comptime_int_type) return null;
36130
36131 if (try sema.typeHasOnePossibleValue(.fromInterned(enum_type.tag_ty))) |int_opv| {
36132 const only = try pt.intern(.{ .enum_tag = .{
36133 .ty = ty.toIntern(),
36134 .int = int_opv.toIntern(),
36135 } });
36136 return Value.fromInterned(only);
36137 }
36138
36139 return null;
36140 },
36141 .auto, .explicit => {
36142 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null;
36143
36144 return Value.fromInterned(switch (enum_type.names.len) {
36145 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }),
36146 1 => try pt.intern(.{ .enum_tag = .{
36147 .ty = ty.toIntern(),
36148 .int = if (enum_type.values.len == 0)
36149 (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
36150 else
36151 try ip.getCoercedInts(
36152 gpa,
36153 io,
36154 pt.tid,
36155 ip.indexToKey(enum_type.values.get(ip)[0]).int,
36156 enum_type.tag_ty,
36157 ),
36158 } }),
36159 else => return null,
36160 });
36161 },
36162 }
36163 },
36164
36165 else => unreachable,
36166 },
36167
36168 .type_optional => {
36169 const payload_ip = ip.indexToKey(ty.toIntern()).opt_type;
36170 // Although ?noreturn is handled above, the element type
36171 // can be effectively noreturn for example via an empty
36172 // enum or error set.
36173 if (ip.isNoReturn(payload_ip)) return try pt.nullValue(ty);
36174 return null;
36175 },
36176 },
36177 };
36178}
36179
36180/// Returns the type of the AIR instruction.33507/// Returns the type of the AIR instruction.
36181fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {33508fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
36182 return sema.getTmpAir().typeOf(inst, &sema.pt.zcu.intern_pool);33509 return sema.getTmpAir().typeOf(inst, &sema.pt.zcu.intern_pool);
...@@ -36235,6 +33562,7 @@ fn isComptimeKnown(...@@ -36235,6 +33562,7 @@ fn isComptimeKnown(
36235 return (try sema.resolveValue(inst)) != null;33562 return (try sema.resolveValue(inst)) != null;
36236}33563}
3623733564
33565/// Asserts that the layout of `var_type` has already been resolved.
36238fn analyzeComptimeAlloc(33566fn analyzeComptimeAlloc(
36239 sema: *Sema,33567 sema: *Sema,
36240 block: *Block,33568 block: *Block,
...@@ -36245,10 +33573,9 @@ fn analyzeComptimeAlloc(...@@ -36245,10 +33573,9 @@ fn analyzeComptimeAlloc(
36245 const pt = sema.pt;33573 const pt = sema.pt;
36246 const zcu = pt.zcu;33574 const zcu = pt.zcu;
3624733575
36248 // Needed to make an anon decl with type `var_type` (the `finish()` call below).33576 var_type.assertHasLayout(zcu);
36249 _ = try sema.typeHasOnePossibleValue(var_type);
3625033577
36251 const ptr_type = try pt.ptrTypeSema(.{33578 const ptr_type = try pt.ptrType(.{
36252 .child = var_type.toIntern(),33579 .child = var_type.toIntern(),
36253 .flags = .{33580 .flags = .{
36254 .alignment = alignment,33581 .alignment = alignment,
...@@ -36256,13 +33583,23 @@ fn analyzeComptimeAlloc(...@@ -36256,13 +33583,23 @@ fn analyzeComptimeAlloc(
36256 },33583 },
36257 });33584 });
3625833585
36259 const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment);33586 if (try var_type.onePossibleValue(pt)) |opv| {
3626033587 return .fromIntern(try pt.intern(.{ .ptr = .{
36261 return Air.internedToRef((try pt.intern(.{ .ptr = .{33588 .ty = ptr_type.toIntern(),
36262 .ty = ptr_type.toIntern(),33589 .base_addr = .{ .uav = .{
36263 .base_addr = .{ .comptime_alloc = alloc },33590 .val = opv.toIntern(),
36264 .byte_offset = 0,33591 .orig_ty = ptr_type.toIntern(),
36265 } })));33592 } },
33593 .byte_offset = 0,
33594 } }));
33595 } else {
33596 const alloc = try sema.newComptimeAlloc(block, src, var_type, alignment);
33597 return .fromIntern(try pt.intern(.{ .ptr = .{
33598 .ty = ptr_type.toIntern(),
33599 .base_addr = .{ .comptime_alloc = alloc },
33600 .byte_offset = 0,
33601 } }));
33602 }
36266}33603}
3626733604
36268fn resolveAddressSpace(33605fn resolveAddressSpace(
...@@ -36363,40 +33700,6 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError...@@ -36363,40 +33700,6 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
36363 return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int});33700 return std.math.cast(usize, int) orelse return sema.fail(block, src, "expression produces integer value '{d}' which is too big for this compiler implementation to handle", .{int});
36364}33701}
3636533702
36366/// For pointer-like optionals, it returns the pointer type. For pointers,
36367/// the type is returned unmodified.
36368/// This can return `error.AnalysisFail` because it sometimes requires resolving whether
36369/// a type has zero bits, which can cause a "foo depends on itself" compile error.
36370/// This logic must be kept in sync with `Type.isPtrLikeOptional`.
36371fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
36372 const pt = sema.pt;
36373 const zcu = pt.zcu;
36374 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
36375 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
36376 .one, .many, .c => ty,
36377 .slice => null,
36378 },
36379 .opt_type => |opt_child| switch (zcu.intern_pool.indexToKey(opt_child)) {
36380 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
36381 .slice, .c => null,
36382 .many, .one => {
36383 if (ptr_type.flags.is_allowzero) return null;
36384
36385 // optionals of zero sized types behave like bools, not pointers
36386 const payload_ty: Type = .fromInterned(opt_child);
36387 if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) {
36388 return null;
36389 }
36390
36391 return payload_ty;
36392 },
36393 },
36394 else => null,
36395 },
36396 else => null,
36397 };
36398}
36399
36400fn unionFieldIndex(33703fn unionFieldIndex(
36401 sema: *Sema,33704 sema: *Sema,
36402 block: *Block,33705 block: *Block,
...@@ -36407,9 +33710,9 @@ fn unionFieldIndex(...@@ -36407,9 +33710,9 @@ fn unionFieldIndex(
36407 const pt = sema.pt;33710 const pt = sema.pt;
36408 const zcu = pt.zcu;33711 const zcu = pt.zcu;
36409 const ip = &zcu.intern_pool;33712 const ip = &zcu.intern_pool;
36410 try union_ty.resolveFields(pt);
36411 const union_obj = zcu.typeToUnion(union_ty).?;33713 const union_obj = zcu.typeToUnion(union_ty).?;
36412 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse33714 const enum_obj = ip.loadEnumType(union_obj.enum_tag_type);
33715 const field_index = enum_obj.nameIndex(ip, field_name) orelse
36413 return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);33716 return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);
36414 return @intCast(field_index);33717 return @intCast(field_index);
36415}33718}
...@@ -36424,7 +33727,6 @@ fn structFieldIndex(...@@ -36424,7 +33727,6 @@ fn structFieldIndex(
36424 const pt = sema.pt;33727 const pt = sema.pt;
36425 const zcu = pt.zcu;33728 const zcu = pt.zcu;
36426 const ip = &zcu.intern_pool;33729 const ip = &zcu.intern_pool;
36427 try struct_ty.resolveFields(pt);
36428 const struct_type = zcu.typeToStruct(struct_ty).?;33730 const struct_type = zcu.typeToStruct(struct_ty).?;
36429 return struct_type.nameIndex(ip, field_name) orelse33731 return struct_type.nameIndex(ip, field_name) orelse
36430 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_src, field_name);33732 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_src, field_name);
...@@ -36513,6 +33815,7 @@ fn intFromFloatScalar(...@@ -36513,6 +33815,7 @@ fn intFromFloatScalar(
36513/// Vectors are also accepted. Vector results are reduced with AND.33815/// Vectors are also accepted. Vector results are reduced with AND.
36514///33816///
36515/// If provided, `vector_index` reports the first element that failed the range check.33817/// If provided, `vector_index` reports the first element that failed the range check.
33818/// MLUGG TODO: move to `Value` or `Type`?
36516fn intFitsInType(33819fn intFitsInType(
36517 sema: *Sema,33820 sema: *Sema,
36518 val: Value,33821 val: Value,
...@@ -36535,30 +33838,10 @@ fn intFitsInType(...@@ -36535,30 +33838,10 @@ fn intFitsInType(
36535 .unsigned => info.bits >= ptr_bits,33838 .unsigned => info.bits >= ptr_bits,
36536 };33839 };
36537 },33840 },
36538 .int => |int| switch (int.storage) {33841 .int => |int| {
36539 .u64, .i64, .big_int => {33842 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
36540 var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;33843 const big_int = int.storage.toBigInt(&buffer);
36541 const big_int = int.storage.toBigInt(&buffer);33844 return big_int.fitsInTwosComp(info.signedness, info.bits);
36542 return big_int.fitsInTwosComp(info.signedness, info.bits);
36543 },
36544 .lazy_align => |lazy_ty| {
36545 const max_needed_bits = @as(u16, 16) + @intFromBool(info.signedness == .signed);
36546 // If it is u16 or bigger we know the alignment fits without resolving it.
36547 if (info.bits >= max_needed_bits) return true;
36548 const x = try Type.fromInterned(lazy_ty).abiAlignmentSema(pt);
36549 if (x == .none) return true;
36550 const actual_needed_bits = @as(usize, x.toLog2Units()) + 1 + @intFromBool(info.signedness == .signed);
36551 return info.bits >= actual_needed_bits;
36552 },
36553 .lazy_size => |lazy_ty| {
36554 const max_needed_bits = @as(u16, 64) + @intFromBool(info.signedness == .signed);
36555 // If it is u64 or bigger we know the size fits without resolving it.
36556 if (info.bits >= max_needed_bits) return true;
36557 const x = try Type.fromInterned(lazy_ty).abiSizeSema(pt);
36558 if (x == 0) return true;
36559 const actual_needed_bits = std.math.log2(x) + 1 + @intFromBool(info.signedness == .signed);
36560 return info.bits >= actual_needed_bits;
36561 },
36562 },33845 },
36563 .aggregate => |aggregate| {33846 .aggregate => |aggregate| {
36564 assert(ty.zigTypeTag(zcu) == .vector);33847 assert(ty.zigTypeTag(zcu) == .vector);
...@@ -36588,23 +33871,23 @@ fn intFitsInType(...@@ -36588,23 +33871,23 @@ fn intFitsInType(
3658833871
36589fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {33872fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
36590 const pt = sema.pt;33873 const pt = sema.pt;
36591 if (!(try int_val.compareAllWithZeroSema(.gte, pt))) return false;33874 if (!int_val.compareAllWithZero(.gte, pt.zcu)) return false;
36592 const end_val = try pt.intValue(tag_ty, end);33875 const end_val = try pt.intValue(tag_ty, end);
36593 if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false;33876 if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false;
36594 return true;33877 return true;
36595}33878}
3659633879
36597/// Asserts the type is an enum.33880/// Asserts the type is an exhaustive enum.
36598fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {33881fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
36599 const pt = sema.pt;33882 const pt = sema.pt;
36600 const zcu = pt.zcu;33883 const zcu = pt.zcu;
36601 const enum_type = zcu.intern_pool.loadEnumType(ty.toIntern());33884 const enum_type = zcu.intern_pool.loadEnumType(ty.toIntern());
36602 assert(enum_type.tag_mode != .nonexhaustive);33885 assert(!enum_type.nonexhaustive);
36603 // The `tagValueIndex` function call below relies on the type being the integer tag type.33886 // The `tagValueIndex` function call below relies on the type being the integer tag type.
36604 // `getCoerced` assumes the value will fit the new type.33887 // `getCoerced` assumes the value will fit the new type.
36605 if (!(try sema.intFitsInType(int, .fromInterned(enum_type.tag_ty), null))) return false;33888 const int_tag_ty: Type = .fromInterned(enum_type.int_tag_type);
36606 const int_coerced = try pt.getCoerced(int, .fromInterned(enum_type.tag_ty));33889 if (!try sema.intFitsInType(int, int_tag_ty, null)) return false;
3660733890 const int_coerced = try pt.getCoerced(int, int_tag_ty);
36608 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;33891 return enum_type.tagValueIndex(&zcu.intern_pool, int_coerced.toIntern()) != null;
36609}33892}
3661033893
...@@ -36636,6 +33919,7 @@ fn compareAll(...@@ -36636,6 +33919,7 @@ fn compareAll(
36636}33919}
3663733920
36638/// Asserts the values are comparable. Both operands have type `ty`.33921/// Asserts the values are comparable. Both operands have type `ty`.
33922/// MLUGG TODO: move to `Value`?
36639fn compareScalar(33923fn compareScalar(
36640 sema: *Sema,33924 sema: *Sema,
36641 lhs: Value,33925 lhs: Value,
...@@ -36644,17 +33928,19 @@ fn compareScalar(...@@ -36644,17 +33928,19 @@ fn compareScalar(
36644 ty: Type,33928 ty: Type,
36645) CompileError!bool {33929) CompileError!bool {
36646 const pt = sema.pt;33930 const pt = sema.pt;
33931 const zcu = pt.zcu;
33932
36647 const coerced_lhs = try pt.getCoerced(lhs, ty);33933 const coerced_lhs = try pt.getCoerced(lhs, ty);
36648 const coerced_rhs = try pt.getCoerced(rhs, ty);33934 const coerced_rhs = try pt.getCoerced(rhs, ty);
3664933935
36650 // Equality comparisons of signed zero and NaN need to use floating point semantics33936 // Equality comparisons of signed zero and NaN need to use floating point semantics
36651 if (coerced_lhs.isFloat(pt.zcu) or coerced_rhs.isFloat(pt.zcu))33937 if (coerced_lhs.isFloat(zcu) or coerced_rhs.isFloat(zcu))
36652 return Value.compareHeteroSema(coerced_lhs, op, coerced_rhs, pt);33938 return Value.compareHetero(coerced_lhs, op, coerced_rhs, zcu);
3665333939
36654 switch (op) {33940 switch (op) {
36655 .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty),33941 .eq => return Value.eql(coerced_lhs, coerced_rhs, ty, zcu),
36656 .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)),33942 .neq => return !Value.eql(coerced_lhs, coerced_rhs, ty, zcu),
36657 else => return Value.compareHeteroSema(coerced_lhs, op, coerced_rhs, pt),33943 else => return Value.compareHetero(coerced_lhs, op, coerced_rhs, zcu),
36658 }33944 }
36659}33945}
3666033946
...@@ -36799,7 +34085,7 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai...@@ -36799,7 +34085,7 @@ fn validateRuntimeValue(sema: *Sema, block: *Block, val_src: LazySrcLoc, val: Ai
36799 });34085 });
36800}34086}
3680134087
36802fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError {34088pub fn failWithContainsReferenceToComptimeVar(sema: *Sema, block: *Block, src: LazySrcLoc, value_name: InternPool.NullTerminatedString, kind_of_value: []const u8, val: ?Value) CompileError {
36803 return sema.failWithOwnedErrorMsg(block, msg: {34089 return sema.failWithOwnedErrorMsg(block, msg: {
36804 const msg = try sema.errMsg(src, "{s} contains reference to comptime var", .{kind_of_value});34090 const msg = try sema.errMsg(src, "{s} contains reference to comptime var", .{kind_of_value});
36805 errdefer msg.destroy(sema.gpa);34091 errdefer msg.destroy(sema.gpa);
...@@ -36867,11 +34153,7 @@ fn notePathToComptimeAllocPtr(...@@ -36867,11 +34153,7 @@ fn notePathToComptimeAllocPtr(
36867 else => {}, // there will be another stage34153 else => {}, // there will be another stage
36868 }34154 }
3686934155
36870 const derivation = comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema) catch |err| switch (err) {34156 const derivation = try comptime_ptr.pointerDerivationAdvanced(arena, pt, false, sema);
36871 error.OutOfMemory => |e| return e,
36872 error.Canceled => @panic("TODO"), // pls don't be cancelable mlugg
36873 error.AnalysisFail => unreachable,
36874 };
3687534157
36876 var second_path_aw: std.Io.Writer.Allocating = .init(arena);34158 var second_path_aw: std.Io.Writer.Allocating = .init(arena);
36877 defer second_path_aw.deinit();34159 defer second_path_aw.deinit();
...@@ -37058,12 +34340,12 @@ fn maybeDerefSliceAsArray(...@@ -37058,12 +34340,12 @@ fn maybeDerefSliceAsArray(
37058 else => unreachable,34340 else => unreachable,
37059 };34341 };
37060 const elem_ty = Type.fromInterned(slice.ty).childType(zcu);34342 const elem_ty = Type.fromInterned(slice.ty).childType(zcu);
37061 const len = try Value.fromInterned(slice.len).toUnsignedIntSema(pt);34343 const len = Value.fromInterned(slice.len).toUnsignedInt(zcu);
37062 const array_ty = try pt.arrayType(.{34344 const array_ty = try pt.arrayType(.{
37063 .child = elem_ty.toIntern(),34345 .child = elem_ty.toIntern(),
37064 .len = len,34346 .len = len,
37065 });34347 });
37066 const ptr_ty = try pt.ptrTypeSema(p: {34348 const ptr_ty = try pt.ptrType(p: {
37067 var p = Type.fromInterned(slice.ty).ptrInfo(zcu);34349 var p = Type.fromInterned(slice.ty).ptrInfo(zcu);
37068 p.flags.size = .one;34350 p.flags.size = .one;
37069 p.child = array_ty.toIntern();34351 p.child = array_ty.toIntern();
...@@ -37129,238 +34411,6 @@ pub fn flushExports(sema: *Sema) !void {...@@ -37129,238 +34411,6 @@ pub fn flushExports(sema: *Sema) !void {
37129 }34411 }
37130}34412}
3713134413
37132/// Called as soon as a `declared` enum type is created.
37133/// Resolves the tag type and field inits.
37134/// Marks the `src_inst` dependency on the enum's declaration, so call sites need not do this.
37135pub fn resolveDeclaredEnum(
37136 pt: Zcu.PerThread,
37137 wip_ty: InternPool.WipEnumType,
37138 inst: Zir.Inst.Index,
37139 tracked_inst: InternPool.TrackedInst.Index,
37140 namespace: InternPool.NamespaceIndex,
37141 type_name: InternPool.NullTerminatedString,
37142 small: Zir.Inst.EnumDecl.Small,
37143 body: []const Zir.Inst.Index,
37144 tag_type_ref: Zir.Inst.Ref,
37145 any_values: bool,
37146 fields_len: u32,
37147 zir: Zir,
37148 body_end: usize,
37149) Zcu.SemaError!void {
37150 const zcu = pt.zcu;
37151 const gpa = zcu.gpa;
37152
37153 const src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = LazySrcLoc.Offset.nodeOffset(.zero) };
37154
37155 var arena: std.heap.ArenaAllocator = .init(gpa);
37156 defer arena.deinit();
37157
37158 var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa);
37159 defer comptime_err_ret_trace.deinit();
37160
37161 var sema: Sema = .{
37162 .pt = pt,
37163 .gpa = gpa,
37164 .arena = arena.allocator(),
37165 .code = zir,
37166 .owner = .wrap(.{ .type = wip_ty.index }),
37167 .func_index = .none,
37168 .func_is_naked = false,
37169 .fn_ret_ty = .void,
37170 .fn_ret_ty_ies = null,
37171 .comptime_err_ret_trace = &comptime_err_ret_trace,
37172 };
37173 defer sema.deinit();
37174
37175 if (zcu.comp.debugIncremental()) {
37176 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, sema.owner);
37177 info.last_update_gen = zcu.generation;
37178 }
37179
37180 try sema.declareDependency(.{ .src_hash = tracked_inst });
37181
37182 var block: Block = .{
37183 .parent = null,
37184 .sema = &sema,
37185 .namespace = namespace,
37186 .instructions = .{},
37187 .inlining = null,
37188 .comptime_reason = .{ .reason = .{
37189 .src = src,
37190 .r = .{ .simple = .enum_field_values },
37191 } },
37192 .src_base_inst = tracked_inst,
37193 .type_name_ctx = type_name,
37194 };
37195 defer block.instructions.deinit(gpa);
37196
37197 sema.resolveDeclaredEnumInner(
37198 &block,
37199 wip_ty,
37200 inst,
37201 tracked_inst,
37202 src,
37203 small,
37204 body,
37205 tag_type_ref,
37206 any_values,
37207 fields_len,
37208 zir,
37209 body_end,
37210 ) catch |err| switch (err) {
37211 error.ComptimeBreak => unreachable,
37212 error.ComptimeReturn => unreachable,
37213 error.OutOfMemory, error.Canceled => |e| return e,
37214 error.AnalysisFail => {
37215 if (!zcu.failed_analysis.contains(sema.owner)) {
37216 try zcu.transitive_failed_analysis.put(gpa, sema.owner, {});
37217 }
37218 return error.AnalysisFail;
37219 },
37220 };
37221}
37222
37223fn resolveDeclaredEnumInner(
37224 sema: *Sema,
37225 block: *Block,
37226 wip_ty: InternPool.WipEnumType,
37227 inst: Zir.Inst.Index,
37228 tracked_inst: InternPool.TrackedInst.Index,
37229 src: LazySrcLoc,
37230 small: Zir.Inst.EnumDecl.Small,
37231 body: []const Zir.Inst.Index,
37232 tag_type_ref: Zir.Inst.Ref,
37233 any_values: bool,
37234 fields_len: u32,
37235 zir: Zir,
37236 body_end: usize,
37237) Zcu.CompileError!void {
37238 const pt = sema.pt;
37239 const zcu = pt.zcu;
37240 const comp = zcu.comp;
37241 const gpa = comp.gpa;
37242 const io = comp.io;
37243 const ip = &zcu.intern_pool;
37244
37245 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
37246
37247 const tag_ty_src: LazySrcLoc = .{ .base_node_inst = tracked_inst, .offset = .{ .node_offset_container_tag = .zero } };
37248
37249 const int_tag_ty = ty: {
37250 if (body.len != 0) {
37251 _ = try sema.analyzeInlineBody(block, body, inst);
37252 }
37253
37254 if (tag_type_ref != .none) {
37255 const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
37256 if (ty.zigTypeTag(zcu) != .int and ty.zigTypeTag(zcu) != .comptime_int) {
37257 return sema.fail(block, tag_ty_src, "expected integer tag type, found '{f}'", .{ty.fmt(pt)});
37258 }
37259 break :ty ty;
37260 } else if (fields_len == 0) {
37261 break :ty try pt.intType(.unsigned, 0);
37262 } else {
37263 const bits = std.math.log2_int_ceil(usize, fields_len);
37264 break :ty try pt.intType(.unsigned, bits);
37265 }
37266 };
37267
37268 wip_ty.setTagTy(ip, int_tag_ty.toIntern());
37269
37270 var extra_index = body_end + bit_bags_count;
37271 var bit_bag_index: usize = body_end;
37272 var cur_bit_bag: u32 = undefined;
37273 var last_tag_val: ?Value = null;
37274 for (0..fields_len) |field_i_usize| {
37275 const field_i: u32 = @intCast(field_i_usize);
37276 if (field_i % 32 == 0) {
37277 cur_bit_bag = zir.extra[bit_bag_index];
37278 bit_bag_index += 1;
37279 }
37280 const has_tag_value = @as(u1, @truncate(cur_bit_bag)) != 0;
37281 cur_bit_bag >>= 1;
37282
37283 const field_name_index: Zir.NullTerminatedString = @enumFromInt(zir.extra[extra_index]);
37284 const field_name_zir = zir.nullTerminatedString(field_name_index);
37285 extra_index += 1; // field name
37286
37287 const field_name = try ip.getOrPutString(gpa, io, pt.tid, field_name_zir, .no_embedded_nulls);
37288
37289 const value_src: LazySrcLoc = .{
37290 .base_node_inst = tracked_inst,
37291 .offset = .{ .container_field_value = field_i },
37292 };
37293
37294 const tag_overflow = if (has_tag_value) overflow: {
37295 const tag_val_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
37296 extra_index += 1;
37297 const tag_inst = try sema.resolveInst(tag_val_ref);
37298 last_tag_val = try sema.resolveConstDefinedValue(block, .{
37299 .base_node_inst = tracked_inst,
37300 .offset = .{ .container_field_name = field_i },
37301 }, tag_inst, .{ .simple = .enum_field_tag_value });
37302 if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
37303 last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
37304 if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| {
37305 assert(conflict.kind == .value); // AstGen validated names are unique
37306 const other_field_src: LazySrcLoc = .{
37307 .base_node_inst = tracked_inst,
37308 .offset = .{ .container_field_value = conflict.prev_field_idx },
37309 };
37310 const msg = msg: {
37311 const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
37312 errdefer msg.destroy(gpa);
37313 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
37314 break :msg msg;
37315 };
37316 return sema.failWithOwnedErrorMsg(block, msg);
37317 }
37318 break :overflow false;
37319 } else if (any_values) overflow: {
37320 if (last_tag_val) |last_tag| {
37321 const result = try arith.incrementDefinedInt(sema, int_tag_ty, last_tag);
37322 last_tag_val = result.val;
37323 if (result.overflow) break :overflow true;
37324 } else {
37325 last_tag_val = try pt.intValue(int_tag_ty, 0);
37326 }
37327 if (wip_ty.nextField(ip, field_name, last_tag_val.?.toIntern())) |conflict| {
37328 assert(conflict.kind == .value); // AstGen validated names are unique
37329 const other_field_src: LazySrcLoc = .{
37330 .base_node_inst = tracked_inst,
37331 .offset = .{ .container_field_value = conflict.prev_field_idx },
37332 };
37333 const msg = msg: {
37334 const msg = try sema.errMsg(value_src, "enum tag value {f} already taken", .{last_tag_val.?.fmtValueSema(pt, sema)});
37335 errdefer msg.destroy(gpa);
37336 try sema.errNote(other_field_src, msg, "other occurrence here", .{});
37337 break :msg msg;
37338 };
37339 return sema.failWithOwnedErrorMsg(block, msg);
37340 }
37341 break :overflow false;
37342 } else overflow: {
37343 assert(wip_ty.nextField(ip, field_name, .none) == null);
37344 last_tag_val = try pt.intValue(.comptime_int, field_i);
37345 if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
37346 last_tag_val = try pt.getCoerced(last_tag_val.?, int_tag_ty);
37347 break :overflow false;
37348 };
37349
37350 if (tag_overflow) {
37351 const msg = try sema.errMsg(value_src, "enumeration value '{f}' too large for type '{f}'", .{
37352 last_tag_val.?.fmtValueSema(pt, sema), int_tag_ty.fmt(pt),
37353 });
37354 return sema.failWithOwnedErrorMsg(block, msg);
37355 }
37356 }
37357 if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
37358 if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {
37359 return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
37360 }
37361 }
37362}
37363
37364pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;34414pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
37365pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;34415pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
3736634416
...@@ -37369,6 +34419,11 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR...@@ -37369,6 +34419,11 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR
37369const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;34419const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
37370const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;34420const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
3737134421
34422// MLUGG TODO: decide how to do the namespacing here
34423pub const type_resolution = @import("Sema/type_resolution.zig");
34424pub const ensureLayoutResolved = type_resolution.ensureLayoutResolved;
34425pub const ensureFieldInitsResolved = type_resolution.ensureFieldInitsResolved;
34426
37372pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {34427pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, decl: Zcu.BuiltinDecl) SemaError!Type {
37373 assert(decl.kind() == .type);34428 assert(decl.kind() == .type);
37374 try sema.ensureMemoizedStateResolved(src, decl.stage());34429 try sema.ensureMemoizedStateResolved(src, decl.stage());
...@@ -37483,11 +34538,11 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,...@@ -37483,11 +34538,11 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
37483 const result = try sema.analyzeNavVal(block, src, nav);34538 const result = try sema.analyzeNavVal(block, src, nav);
3748434539
37485 const uncoerced_val = try sema.resolveConstDefinedValue(block, src, result, null);34540 const uncoerced_val = try sema.resolveConstDefinedValue(block, src, result, null);
37486 const maybe_lazy_val: Value = switch (builtin_decl.kind()) {34541 const val: Value = switch (builtin_decl.kind()) {
37487 .type => if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .type) {34542 .type => if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .type) {
37488 return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name });34543 return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name });
37489 } else val: {34544 } else val: {
37490 try uncoerced_val.toType().resolveFully(pt);34545 try sema.ensureLayoutResolved(uncoerced_val.toType());
37491 break :val uncoerced_val;34546 break :val uncoerced_val;
37492 },34547 },
37493 .func => val: {34548 .func => val: {
...@@ -37500,7 +34555,6 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,...@@ -37500,7 +34555,6 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc,
37500 break :val .fromInterned(coerced.toInterned().?);34555 break :val .fromInterned(coerced.toInterned().?);
37501 },34556 },
37502 };34557 };
37503 const val = try sema.resolveLazyValue(maybe_lazy_val);
3750434558
37505 const prev = zcu.builtin_decl_values.get(builtin_decl);34559 const prev = zcu.builtin_decl_values.get(builtin_decl);
37506 if (val.toIntern() != prev) {34560 if (val.toIntern() != prev) {
...@@ -37539,7 +34593,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -37539,7 +34593,6 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
37539 => try pt.funcType(.{34593 => try pt.funcType(.{
37540 .param_types = &.{ .generic_poison_type, .generic_poison_type },34594 .param_types = &.{ .generic_poison_type, .generic_poison_type },
37541 .return_type = .noreturn_type,34595 .return_type = .noreturn_type,
37542 .is_generic = true,
37543 }),34596 }),
3754434597
37545 // `fn (anyerror) noreturn`34598 // `fn (anyerror) noreturn`
...@@ -37590,3 +34643,823 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ...@@ -37590,3 +34643,823 @@ fn getExpectedBuiltinFnType(sema: *Sema, decl: Zcu.BuiltinDecl) CompileError!Typ
37590 else => unreachable,34643 else => unreachable,
37591 };34644 };
37592}34645}
34646
34647/// TODO MLUGG: this is a gnarly hack
34648const PartialTypeName = union(enum) {
34649 exact: struct {
34650 name: InternPool.NullTerminatedString,
34651 nav: InternPool.Nav.Index.Optional,
34652 },
34653 anon_prefix: []const u8,
34654 fn apply(
34655 name: PartialTypeName,
34656 wip: *const InternPool.WipContainerType,
34657 pt: Zcu.PerThread,
34658 ) (Allocator.Error || std.Io.Cancelable)!InternPool.NullTerminatedString {
34659 const zcu = pt.zcu;
34660 const comp = zcu.comp;
34661 const ip = &zcu.intern_pool;
34662 switch (name) {
34663 .exact => |e| {
34664 wip.setName(ip, e.name, e.nav);
34665 return e.name;
34666 },
34667 .anon_prefix => |prefix| {
34668 const resolved_name = try ip.getOrPutStringFmt(
34669 comp.gpa,
34670 comp.io,
34671 pt.tid,
34672 "{s}_{d}",
34673 .{ prefix, @intFromEnum(wip.index) },
34674 .no_embedded_nulls,
34675 );
34676 wip.setName(ip, resolved_name, .none);
34677 return resolved_name;
34678 },
34679 }
34680 }
34681};
34682pub fn createTypeName(
34683 sema: *Sema,
34684 block: *Block,
34685 name_strategy: Zir.Inst.NameStrategy,
34686 anon_prefix: []const u8,
34687 inst: Zir.Inst.Index,
34688) CompileError!PartialTypeName {
34689 const pt = sema.pt;
34690 const zcu = pt.zcu;
34691 const comp = zcu.comp;
34692 const gpa = comp.gpa;
34693 const io = comp.io;
34694 const ip = &zcu.intern_pool;
34695
34696 switch (name_strategy) {
34697 .anon => {}, // handled after switch
34698 .parent => return .{ .exact = .{
34699 .name = block.type_name_ctx,
34700 .nav = sema.owner.unwrap().nav_val.toOptional(),
34701 } },
34702 .func => func_strat: {
34703 const fn_info = sema.code.getFnInfo(ip.funcZirBodyInst(sema.func_index).resolve(ip) orelse return error.AnalysisFail);
34704 const zir_tags = sema.code.instructions.items(.tag);
34705
34706 var aw: std.Io.Writer.Allocating = .init(gpa);
34707 defer aw.deinit();
34708 const w = &aw.writer;
34709 w.print("{f}(", .{block.type_name_ctx.fmt(ip)}) catch return error.OutOfMemory;
34710
34711 var arg_i: usize = 0;
34712 for (fn_info.param_body) |zir_inst| switch (zir_tags[@intFromEnum(zir_inst)]) {
34713 .param, .param_comptime, .param_anytype, .param_anytype_comptime => {
34714 const arg = sema.inst_map.get(zir_inst).?;
34715 // If this is being called in a generic function then analyzeCall will
34716 // have already resolved the args and this will work.
34717 // If not then this is a struct type being returned from a non-generic
34718 // function and the name doesn't matter since it will later
34719 // result in a compile error.
34720 const arg_val = try sema.resolveValue(arg) orelse break :func_strat; // fall through to anon strat
34721
34722 if (arg_i != 0) w.writeByte(',') catch return error.OutOfMemory;
34723
34724 // Limiting the depth here helps avoid type names getting too long, which
34725 // in turn helps to avoid unreasonably long symbol names for namespaced
34726 // symbols. Such names should ideally be human-readable, and additionally,
34727 // some tooling may not support very long symbol names.
34728 w.print("{f}", .{Value.fmtValueSemaFull(.{
34729 .val = arg_val,
34730 .pt = pt,
34731 .opt_sema = sema,
34732 .depth = 1,
34733 })}) catch return error.OutOfMemory;
34734
34735 arg_i += 1;
34736 continue;
34737 },
34738 else => continue,
34739 };
34740
34741 w.writeByte(')') catch return error.OutOfMemory;
34742 return .{ .exact = .{
34743 .name = try ip.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls),
34744 .nav = .none,
34745 } };
34746 },
34747 .dbg_var => {
34748 // TODO: this logic is questionable. We ideally should be traversing the `Block` rather than relying on the order of AstGen instructions.
34749 const ref = inst.toRef();
34750 const zir_tags = sema.code.instructions.items(.tag);
34751 const zir_data = sema.code.instructions.items(.data);
34752 for (@intFromEnum(inst)..zir_tags.len) |i| switch (zir_tags[i]) {
34753 .dbg_var_ptr, .dbg_var_val => if (zir_data[i].str_op.operand == ref) {
34754 return .{ .exact = .{
34755 .name = try ip.getOrPutStringFmt(gpa, io, pt.tid, "{f}.{s}", .{
34756 block.type_name_ctx.fmt(ip), zir_data[i].str_op.getStr(sema.code),
34757 }, .no_embedded_nulls),
34758 .nav = .none,
34759 } };
34760 },
34761 else => {},
34762 };
34763 // fall through to anon strat
34764 },
34765 }
34766
34767 // anon strat handling
34768
34769 // It would be neat to have "struct:line:column" but this name has
34770 // to survive incremental updates, where it may have been shifted down
34771 // or up to a different line, but unchanged, and thus not unnecessarily
34772 // semantically analyzed.
34773 // TODO: that would be possible, by detecting line number changes and renaming
34774 // types appropriately. However, `@typeName` becomes a problem then. If we remove
34775 // that builtin from the language, we can consider this.
34776
34777 return .{ .anon_prefix = try std.fmt.allocPrint(
34778 sema.arena,
34779 "{f}__{s}",
34780 .{ block.type_name_ctx.fmt(ip), anon_prefix },
34781 ) };
34782}
34783
34784pub fn analyzeStructDecl(
34785 pt: Zcu.PerThread,
34786 file_index: Zcu.File.Index,
34787 zir: *const Zir,
34788 parent_namespace: InternPool.OptionalNamespaceIndex,
34789 tracked_inst: InternPool.TrackedInst.Index,
34790 struct_decl: *const Zir.UnwrappedStructDecl,
34791 explicit_backing_type: ?Type,
34792 captures: []const InternPool.CaptureValue,
34793 type_name: PartialTypeName,
34794) (Allocator.Error || std.Io.Cancelable)!Type {
34795 const zcu = pt.zcu;
34796 const comp = zcu.comp;
34797 const gpa = comp.gpa;
34798 const io = comp.io;
34799 const ip = &zcu.intern_pool;
34800
34801 const wip = switch (try ip.getStructType(gpa, io, pt.tid, .{
34802 .fields_len = @intCast(struct_decl.field_names.len),
34803 .layout = struct_decl.layout,
34804 .explicit_packed_backing_type = if (explicit_backing_type) |ty| ty.toIntern() else .none,
34805 .any_comptime_fields = struct_decl.field_comptime_bits != null,
34806 .any_field_defaults = struct_decl.field_default_body_lens != null,
34807 .any_field_aligns = struct_decl.field_align_body_lens != null,
34808 .key = .{ .declared = .{
34809 .zir_index = tracked_inst,
34810 .captures = captures,
34811 } },
34812 })) {
34813 .existing => |ty| return .fromInterned(ty),
34814 .wip => |wip| wip,
34815 };
34816 errdefer wip.cancel(ip, pt.tid);
34817
34818 _ = try type_name.apply(&wip, pt);
34819
34820 var field_it = struct_decl.iterateFields();
34821 while (field_it.next()) |field| {
34822 const name_slice = zir.nullTerminatedString(field.name);
34823 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
34824 assert(wip.nextField(ip, name, field.is_comptime) == null); // AstGen validated this for us
34825 }
34826
34827 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
34828 .parent = parent_namespace,
34829 .owner_type = wip.index,
34830 .file_scope = file_index,
34831 .generation = zcu.generation,
34832 });
34833 errdefer pt.destroyNamespace(new_namespace_index);
34834
34835 try pt.scanNamespace(new_namespace_index, struct_decl.decls);
34836
34837 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
34838 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
34839 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = wip.index }) });
34840
34841 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
34842
34843 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
34844 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
34845 errdefer comptime unreachable; // because we don't remove the `outdated` entries
34846 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
34847 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), 0);
34848 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
34849 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), {});
34850
34851 return .fromInterned(wip.finish(ip, new_namespace_index));
34852}
34853const AnalyzeUnionDeclError = error{
34854 OutOfMemory,
34855 Canceled,
34856 /// `packed union(T)` syntax was used, but `T` was not an integer type.
34857 ExplicitBackingNotInt,
34858 /// `union(enum(T))` syntax was used, but `T` was not an integer type.
34859 ExplicitTagNotInt,
34860 /// `union(T)` syntax was used, but `T` was not an enum type.
34861 ExplicitTagNotEnum,
34862 /// `union(T)` syntax was used, but the fields of the union do not exactly
34863 /// correspond to the fields of the enum `T`.
34864 ExplicitTagFieldMismatch,
34865};
34866fn analyzeUnionDecl(
34867 pt: Zcu.PerThread,
34868 file_index: Zcu.File.Index,
34869 zir: *const Zir,
34870 parent_namespace: InternPool.OptionalNamespaceIndex,
34871 want_safe_types: bool,
34872 tracked_inst: InternPool.TrackedInst.Index,
34873 union_decl: *const Zir.UnwrappedUnionDecl,
34874 arg_type: ?Type,
34875 captures: []const InternPool.CaptureValue,
34876 type_name: PartialTypeName,
34877) AnalyzeUnionDeclError!Type {
34878 const zcu = pt.zcu;
34879 const comp = zcu.comp;
34880 const gpa = comp.gpa;
34881 const io = comp.io;
34882 const ip = &zcu.intern_pool;
34883
34884 switch (union_decl.kind) {
34885 .tagged_explicit => if (arg_type.?.zigTypeTag(zcu) != .@"enum") {
34886 return error.ExplicitTagNotEnum;
34887 },
34888 .tagged_enum_explicit => if (arg_type.?.zigTypeTag(zcu) != .int) {
34889 return error.ExplicitTagNotInt;
34890 },
34891 .packed_explicit => if (arg_type.?.zigTypeTag(zcu) != .int) {
34892 return error.ExplicitBackingNotInt;
34893 },
34894 .auto,
34895 .tagged_enum,
34896 .@"extern",
34897 .@"packed",
34898 => assert(arg_type == null),
34899 }
34900
34901 const wip = switch (try ip.getUnionType(gpa, io, pt.tid, .{
34902 .fields_len = @intCast(union_decl.field_names.len),
34903 .layout = union_decl.kind.layout(),
34904 .explicit_packed_backing_type = switch (union_decl.kind) {
34905 .packed_explicit => arg_type.?.toIntern(),
34906 else => .none,
34907 },
34908 .runtime_tag = switch (union_decl.kind) {
34909 .auto => if (want_safe_types) .safety else .none,
34910
34911 .tagged_explicit,
34912 .tagged_enum,
34913 .tagged_enum_explicit,
34914 => .tagged,
34915
34916 .@"extern",
34917 .@"packed",
34918 .packed_explicit,
34919 => .none,
34920 },
34921 .have_explicit_enum_tag = union_decl.kind == .tagged_explicit,
34922 .any_field_aligns = union_decl.field_align_body_lens != null,
34923 .key = .{ .declared = .{
34924 .zir_index = tracked_inst,
34925 .captures = captures,
34926 .arg_ty = if (arg_type) |t| t.toIntern() else .none,
34927 } },
34928 })) {
34929 .existing => |ty| return .fromInterned(ty),
34930 .wip => |wip| wip,
34931 };
34932 errdefer wip.cancel(ip, pt.tid);
34933
34934 const resolved_type_name = try type_name.apply(&wip, pt);
34935
34936 const generated_tag_ty: InternPool.Index = if (union_decl.kind == .tagged_explicit) generated_tag_ty: {
34937 const tag_type = arg_type.?;
34938 const enum_field_names = ip.loadEnumType(tag_type.toIntern()).field_names;
34939 // Check that the enum field names match the union field names
34940 if (union_decl.field_names.len != enum_field_names.len) {
34941 return error.ExplicitTagFieldMismatch;
34942 }
34943 for (union_decl.field_names, enum_field_names.get(ip)) |union_field_zir, enum_field_ip| {
34944 const union_field_name = zir.nullTerminatedString(union_field_zir);
34945 const enum_field_name = enum_field_ip.toSlice(ip);
34946 if (!std.mem.eql(u8, union_field_name, enum_field_name)) {
34947 return error.ExplicitTagFieldMismatch;
34948 }
34949 }
34950 wip.setTagType(ip, tag_type.toIntern());
34951 break :generated_tag_ty .none;
34952 } else generated_tag_ty: {
34953 // Generate a tag type. Even if the union is untagged (`.none`), we still generate a
34954 // hypothetical tag type.
34955 const wip_tag_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
34956 .fields_len = @intCast(union_decl.field_names.len),
34957 .explicit_int_tag_type = switch (union_decl.kind) {
34958 .tagged_enum_explicit => arg_type.?.toIntern(),
34959 else => .none,
34960 },
34961 .nonexhaustive = false,
34962 .key = .{ .generated_union_tag = wip.index },
34963 })) {
34964 .existing => unreachable, // enum type is keyed on this union type which we're only just creating
34965 .wip => |wip_tag_ty| wip_tag_ty,
34966 };
34967 errdefer wip_tag_ty.cancel(ip, pt.tid);
34968 // Populate the generated tag type's name
34969 const tag_type_name = try ip.getOrPutStringFmt(
34970 gpa,
34971 io,
34972 pt.tid,
34973 "@typeInfo({f}).@\"union\".tag_type.?",
34974 .{resolved_type_name.fmt(ip)},
34975 .no_embedded_nulls,
34976 );
34977 wip_tag_ty.setName(ip, tag_type_name, .none);
34978 // Populate the generated tag type's field names
34979 for (union_decl.field_names) |zir_name| {
34980 const name_slice = zir.nullTerminatedString(zir_name);
34981 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
34982 assert(wip_tag_ty.nextField(ip, name, false) == null); // AstGen validated this for us
34983 }
34984 // If not explicitly given, populate the generated tag type's *integer* tag type
34985 switch (union_decl.kind) {
34986 .tagged_enum_explicit => {}, // already set by `getEnumType`
34987 else => {
34988 // Infer the int tag type from the field count
34989 const bits = Type.smallestUnsignedBits(union_decl.field_names.len -| 1);
34990 const int_tag_type = try pt.intType(.unsigned, bits);
34991 wip_tag_ty.setTagType(ip, int_tag_type.toIntern());
34992 },
34993 }
34994 // Create a dummy namespace for the generated tag type
34995 const new_namespace_index = try pt.createNamespace(.{
34996 .parent = parent_namespace,
34997 .owner_type = wip_tag_ty.index,
34998 .file_scope = file_index,
34999 .generation = zcu.generation,
35000 });
35001 errdefer pt.destroyNamespace(new_namespace_index);
35002 wip.setTagType(ip, wip_tag_ty.index);
35003 break :generated_tag_ty wip_tag_ty.finish(ip, new_namespace_index);
35004 };
35005 // If we fail to create the union type, we must delete the generated enum tag type, since it
35006 // would hold a reference to the deleted union.
35007 errdefer if (generated_tag_ty != .none) ip.remove(pt.tid, generated_tag_ty);
35008
35009 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35010 .parent = parent_namespace,
35011 .owner_type = wip.index,
35012 .file_scope = file_index,
35013 .generation = zcu.generation,
35014 });
35015 errdefer pt.destroyNamespace(new_namespace_index);
35016
35017 try pt.scanNamespace(new_namespace_index, union_decl.decls);
35018
35019 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
35020 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_layout = wip.index }) });
35021 if (generated_tag_ty != .none) {
35022 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = generated_tag_ty }) });
35023 }
35024
35025 if (zcu.comp.debugIncremental()) {
35026 try zcu.incremental_debug_state.newType(zcu, wip.index);
35027 if (generated_tag_ty != .none) {
35028 try zcu.incremental_debug_state.newType(zcu, generated_tag_ty);
35029 }
35030 }
35031
35032 try zcu.outdated.ensureUnusedCapacity(gpa, 2);
35033 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 2);
35034 errdefer comptime unreachable; // because we don't remove the `outdated` entry
35035 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), 0);
35036 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_layout = wip.index }), {});
35037 if (generated_tag_ty != .none) {
35038 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = generated_tag_ty }), 0);
35039 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = generated_tag_ty }), {});
35040 }
35041
35042 return .fromInterned(wip.finish(ip, new_namespace_index));
35043}
35044const AnalyzeEnumDeclError = error{
35045 OutOfMemory,
35046 Canceled,
35047 /// `enum(T)` syntax was used, but `T` was not an integer type.
35048 ExplicitTagNotInt,
35049};
35050fn analyzeEnumDecl(
35051 pt: Zcu.PerThread,
35052 file_index: Zcu.File.Index,
35053 zir: *const Zir,
35054 parent_namespace: InternPool.OptionalNamespaceIndex,
35055 tracked_inst: InternPool.TrackedInst.Index,
35056 enum_decl: *const Zir.UnwrappedEnumDecl,
35057 explicit_tag_type: ?Type,
35058 captures: []const InternPool.CaptureValue,
35059 type_name: PartialTypeName,
35060) AnalyzeEnumDeclError!Type {
35061 const zcu = pt.zcu;
35062 const comp = zcu.comp;
35063 const gpa = comp.gpa;
35064 const io = comp.io;
35065 const ip = &zcu.intern_pool;
35066
35067 if (explicit_tag_type) |ty| {
35068 // MLUGG TODO: make a final call on whether comptime_int is a valid int tag type, and follow it everywhere.
35069 // i think not in the name of simplicity, but my opinion might depend on whether it's broken in practice today
35070 switch (ty.zigTypeTag(zcu)) {
35071 .int, .comptime_int => {},
35072 else => return error.ExplicitTagNotInt,
35073 }
35074 }
35075
35076 const wip = switch (try ip.getEnumType(gpa, io, pt.tid, .{
35077 .fields_len = @intCast(enum_decl.field_names.len),
35078 .explicit_int_tag_type = if (explicit_tag_type) |ty| ty.toIntern() else .none,
35079 .nonexhaustive = enum_decl.nonexhaustive,
35080 .key = .{ .declared = .{
35081 .zir_index = tracked_inst,
35082 .captures = captures,
35083 } },
35084 })) {
35085 .existing => |ty| return .fromInterned(ty),
35086 .wip => |wip| wip,
35087 };
35088 errdefer wip.cancel(ip, pt.tid);
35089
35090 _ = try type_name.apply(&wip, pt);
35091
35092 var field_it = enum_decl.iterateFields();
35093 while (field_it.next()) |field| {
35094 const name_slice = zir.nullTerminatedString(field.name);
35095 const name = try ip.getOrPutString(gpa, io, pt.tid, name_slice, .no_embedded_nulls);
35096 assert(wip.nextField(ip, name, false) == null); // AstGen validated this for us
35097 }
35098
35099 if (explicit_tag_type == null) {
35100 // Infer the int tag type from the field count
35101 const bits = Type.smallestUnsignedBits(enum_decl.field_names.len -| 1);
35102 const int_tag_ty = try pt.intType(.unsigned, bits);
35103 wip.setTagType(ip, int_tag_ty.toIntern());
35104 }
35105
35106 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35107 .parent = parent_namespace,
35108 .owner_type = wip.index,
35109 .file_scope = file_index,
35110 .generation = zcu.generation,
35111 });
35112 errdefer pt.destroyNamespace(new_namespace_index);
35113
35114 try pt.scanNamespace(new_namespace_index, enum_decl.decls);
35115
35116 // MLUGG TODO: we could potentially revert this language change if we wanted? don't mind
35117 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .type_inits = wip.index }) });
35118
35119 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
35120
35121 try zcu.outdated.ensureUnusedCapacity(gpa, 1);
35122 try zcu.outdated_ready.ensureUnusedCapacity(gpa, 1);
35123 errdefer comptime unreachable; // because we don't remove the `outdated` entry
35124 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), 0);
35125 zcu.outdated_ready.putAssumeCapacityNoClobber(.wrap(.{ .type_inits = wip.index }), {});
35126
35127 return .fromInterned(wip.finish(ip, new_namespace_index));
35128}
35129fn analyzeOpaqueDecl(
35130 pt: Zcu.PerThread,
35131 file_index: Zcu.File.Index,
35132 parent_namespace: InternPool.OptionalNamespaceIndex,
35133 tracked_inst: InternPool.TrackedInst.Index,
35134 opaque_decl: *const Zir.UnwrappedOpaqueDecl,
35135 captures: []const InternPool.CaptureValue,
35136 type_name: PartialTypeName,
35137) (Allocator.Error || std.Io.Cancelable)!Type {
35138 const zcu = pt.zcu;
35139 const comp = zcu.comp;
35140 const gpa = comp.gpa;
35141 const io = comp.io;
35142 const ip = &zcu.intern_pool;
35143
35144 const wip = switch (try ip.getOpaqueType(gpa, io, pt.tid, .{
35145 .zir_index = tracked_inst,
35146 .captures = captures,
35147 })) {
35148 .existing => |ty| return .fromInterned(ty),
35149 .wip => |wip| wip,
35150 };
35151 errdefer wip.cancel(ip, pt.tid);
35152
35153 _ = try type_name.apply(&wip, pt);
35154
35155 const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{
35156 .parent = parent_namespace,
35157 .owner_type = wip.index,
35158 .file_scope = file_index,
35159 .generation = zcu.generation,
35160 });
35161 errdefer pt.destroyNamespace(new_namespace_index);
35162
35163 try pt.scanNamespace(new_namespace_index, opaque_decl.decls);
35164
35165 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index);
35166 return .fromInterned(wip.finish(ip, new_namespace_index));
35167}
35168
35169fn zirStructDecl(
35170 sema: *Sema,
35171 block: *Block,
35172 inst: Zir.Inst.Index,
35173) CompileError!Air.Inst.Ref {
35174 const pt = sema.pt;
35175 const zcu = pt.zcu;
35176
35177 const tracked_inst = try block.trackZir(inst);
35178
35179 const src: LazySrcLoc = .{
35180 .base_node_inst = tracked_inst,
35181 .offset = .nodeOffset(.zero),
35182 };
35183 const backing_ty_src: LazySrcLoc = .{
35184 .base_node_inst = tracked_inst,
35185 .offset = .{ .node_offset_container_tag = .zero },
35186 };
35187
35188 const struct_decl = sema.code.getStructDecl(inst);
35189
35190 const captures = try sema.getCaptures(block, src, struct_decl.captures, struct_decl.capture_names);
35191
35192 const backing_int_type: ?Type = ty: {
35193 if (struct_decl.backing_int_type == .none) break :ty null;
35194 break :ty try sema.resolveType(block, backing_ty_src, struct_decl.backing_int_type);
35195 // MLUGG TODO validate it's an int!
35196 };
35197
35198 const ty = try analyzeStructDecl(
35199 pt,
35200 block.getFileScopeIndex(zcu),
35201 &sema.code,
35202 block.namespace.toOptional(),
35203 tracked_inst,
35204 &struct_decl,
35205 backing_int_type,
35206 captures,
35207 try sema.createTypeName(block, struct_decl.name_strategy, "struct", inst),
35208 );
35209
35210 try sema.addTypeReferenceEntry(src, ty);
35211
35212 // Make sure we update the namespace if the declaration is re-analyzed, to pick
35213 // up on e.g. changed comptime decls.
35214 // TODO MLUGG: me no likey, maybe model namespaces less badly idk
35215 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35216
35217 return .fromIntern(ty.toIntern());
35218}
35219fn zirUnionDecl(
35220 sema: *Sema,
35221 block: *Block,
35222 inst: Zir.Inst.Index,
35223) CompileError!Air.Inst.Ref {
35224 const pt = sema.pt;
35225 const zcu = pt.zcu;
35226 const comp = zcu.comp;
35227 const gpa = comp.gpa;
35228 const io = comp.io;
35229 const ip = &zcu.intern_pool;
35230
35231 const tracked_inst = try block.trackZir(inst);
35232
35233 const src: LazySrcLoc = .{
35234 .base_node_inst = tracked_inst,
35235 .offset = .nodeOffset(.zero),
35236 };
35237 const arg_ty_src: LazySrcLoc = .{
35238 .base_node_inst = tracked_inst,
35239 .offset = .{ .node_offset_container_tag = .zero },
35240 };
35241
35242 const union_decl = sema.code.getUnionDecl(inst);
35243
35244 const captures = try sema.getCaptures(block, src, union_decl.captures, union_decl.capture_names);
35245
35246 const arg_type: ?Type = ty: {
35247 if (union_decl.arg_type == .none) break :ty null;
35248 break :ty try sema.resolveType(block, arg_ty_src, union_decl.arg_type);
35249 };
35250
35251 const ty = analyzeUnionDecl(
35252 pt,
35253 block.getFileScopeIndex(zcu),
35254 &sema.code,
35255 block.namespace.toOptional(),
35256 block.wantSafeTypes(),
35257 tracked_inst,
35258 &union_decl,
35259 arg_type,
35260 captures,
35261 try sema.createTypeName(block, union_decl.name_strategy, "union", inst),
35262 ) catch |err| switch (err) {
35263 error.OutOfMemory,
35264 error.Canceled,
35265 => |e| return e,
35266
35267 error.ExplicitBackingNotInt => return sema.fail(
35268 block,
35269 arg_ty_src,
35270 "expected integer backing type, found '{f}'",
35271 .{arg_type.?.fmt(pt)},
35272 ),
35273 error.ExplicitTagNotInt => return sema.fail(
35274 block,
35275 arg_ty_src,
35276 "expected integer tag type, found '{f}'",
35277 .{arg_type.?.fmt(pt)},
35278 ),
35279 error.ExplicitTagNotEnum => return sema.fail(
35280 block,
35281 arg_ty_src,
35282 "expected enum tag type, found '{f}'",
35283 .{arg_type.?.fmt(pt)},
35284 ),
35285 error.ExplicitTagFieldMismatch => {
35286 const enum_obj = ip.loadEnumType(arg_type.?.toIntern());
35287 const enum_to_union_map = try sema.arena.alloc(?u32, enum_obj.field_names.len);
35288 @memset(enum_to_union_map, null);
35289 for (union_decl.field_names, 0..) |field_name_zir, union_field_idx| {
35290 const field_name_ip = try ip.getOrPutString(gpa, io, pt.tid, sema.code.nullTerminatedString(field_name_zir), .no_embedded_nulls);
35291 if (enum_obj.nameIndex(ip, field_name_ip)) |enum_field_idx| {
35292 enum_to_union_map[enum_field_idx] = @intCast(union_field_idx);
35293 continue;
35294 }
35295 const union_field_src: LazySrcLoc = .{
35296 .base_node_inst = tracked_inst,
35297 .offset = .{ .container_field_name = @intCast(union_field_idx) },
35298 };
35299 return sema.failWithOwnedErrorMsg(block, msg: {
35300 const msg = try sema.errMsg(union_field_src, "no field named '{f}' in enum '{f}'", .{ field_name_ip.fmt(ip), arg_type.?.fmt(pt) });
35301 errdefer msg.destroy(gpa);
35302 try sema.addDeclaredHereNote(msg, arg_type.?);
35303 break :msg msg;
35304 });
35305 }
35306 for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| {
35307 if (union_field_idx != null) continue;
35308 const field_name_ip = enum_obj.field_names.get(ip)[enum_field_idx];
35309 const enum_field_src: LazySrcLoc = .{
35310 .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?,
35311 .offset = .{ .container_field_name = @intCast(enum_field_idx) },
35312 };
35313 return sema.failWithOwnedErrorMsg(block, msg: {
35314 const msg = try sema.errMsg(src, "enum field '{f}' missing from union", .{field_name_ip.fmt(ip)});
35315 errdefer msg.destroy(gpa);
35316 try sema.errNote(enum_field_src, msg, "enum field here", .{});
35317 break :msg msg;
35318 });
35319 }
35320 for (enum_to_union_map, 0..) |union_field_idx, enum_field_idx| {
35321 if (union_field_idx.? == enum_field_idx) continue;
35322 const field_name = sema.code.nullTerminatedString(
35323 union_decl.field_names[union_field_idx.?],
35324 );
35325 const union_field_src: LazySrcLoc = .{
35326 .base_node_inst = tracked_inst,
35327 .offset = .{ .container_field_name = union_field_idx.? },
35328 };
35329 const enum_field_src: LazySrcLoc = .{
35330 .base_node_inst = arg_type.?.typeDeclInstAllowGeneratedTag(zcu).?,
35331 .offset = .{ .container_field_name = @intCast(enum_field_idx) },
35332 };
35333 return sema.failWithOwnedErrorMsg(block, msg: {
35334 const msg = try sema.errMsg(src, "union field order does not match tag enum field order", .{});
35335 errdefer msg.destroy(gpa);
35336 try sema.errNote(union_field_src, msg, "union field '{s}' is index {d}", .{ field_name, union_field_idx.? });
35337 try sema.errNote(enum_field_src, msg, "enum field '{s}' is index {d}", .{ field_name, enum_field_idx });
35338 break :msg msg;
35339 });
35340 }
35341 unreachable;
35342 },
35343 };
35344
35345 const enum_tag_ty = ty.unionTagTypeHypothetical(zcu);
35346 switch (ip.indexToKey(enum_tag_ty.toIntern()).enum_type) {
35347 .declared, .reified => {},
35348 .generated_union_tag => |owner_union_ty| {
35349 assert(owner_union_ty == ty.toIntern());
35350 // generated tag type [MLUGG]
35351 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol
35352 try sema.ensureFieldInitsResolved(.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type));
35353 },
35354 }
35355
35356 try sema.addTypeReferenceEntry(src, ty);
35357
35358 // Make sure we update the namespace if the declaration is re-analyzed, to pick
35359 // up on e.g. changed comptime decls.
35360 // TODO MLUGG: me no likey, maybe model namespaces less badly idk
35361 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35362
35363 return .fromIntern(ty.toIntern());
35364}
35365fn zirEnumDecl(
35366 sema: *Sema,
35367 block: *Block,
35368 inst: Zir.Inst.Index,
35369) CompileError!Air.Inst.Ref {
35370 const pt = sema.pt;
35371 const zcu = pt.zcu;
35372
35373 const tracked_inst = try block.trackZir(inst);
35374
35375 const src: LazySrcLoc = .{
35376 .base_node_inst = tracked_inst,
35377 .offset = .nodeOffset(.zero),
35378 };
35379 const tag_ty_src: LazySrcLoc = .{
35380 .base_node_inst = tracked_inst,
35381 .offset = .{ .node_offset_container_tag = .zero },
35382 };
35383
35384 const enum_decl = sema.code.getEnumDecl(inst);
35385
35386 const captures = try sema.getCaptures(block, src, enum_decl.captures, enum_decl.capture_names);
35387
35388 const tag_type: ?Type = ty: {
35389 if (enum_decl.tag_type == .none) break :ty null;
35390 break :ty try sema.resolveType(block, tag_ty_src, enum_decl.tag_type);
35391 };
35392
35393 const ty = analyzeEnumDecl(
35394 pt,
35395 block.getFileScopeIndex(zcu),
35396 &sema.code,
35397 block.namespace.toOptional(),
35398 tracked_inst,
35399 &enum_decl,
35400 tag_type,
35401 captures,
35402 try sema.createTypeName(block, enum_decl.name_strategy, "enum", inst),
35403 ) catch |err| switch (err) {
35404 error.OutOfMemory,
35405 error.Canceled,
35406 => |e| return e,
35407
35408 error.ExplicitTagNotInt => return sema.fail(
35409 block,
35410 tag_ty_src,
35411 "expected integer tag type, found '{f}'",
35412 .{tag_type.?.fmt(pt)},
35413 ),
35414 };
35415
35416 // Enum inits are resolved eagerly. TODO MLUGG: honestly i don't think they SHOULD be lol
35417 try sema.ensureFieldInitsResolved(ty);
35418
35419 try sema.addTypeReferenceEntry(src, ty);
35420
35421 // Make sure we update the namespace if the declaration is re-analyzed, to pick
35422 // up on e.g. changed comptime decls.
35423 // TODO MLUGG: me no likey, maybe model namespaces less badly idk
35424 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35425
35426 return .fromIntern(ty.toIntern());
35427}
35428fn zirOpaqueDecl(
35429 sema: *Sema,
35430 block: *Block,
35431 inst: Zir.Inst.Index,
35432) CompileError!Air.Inst.Ref {
35433 const pt = sema.pt;
35434 const zcu = pt.zcu;
35435
35436 const tracked_inst = try block.trackZir(inst);
35437
35438 const src: LazySrcLoc = .{
35439 .base_node_inst = tracked_inst,
35440 .offset = .nodeOffset(.zero),
35441 };
35442
35443 const opaque_decl = sema.code.getOpaqueDecl(inst);
35444
35445 const captures = try sema.getCaptures(block, src, opaque_decl.captures, opaque_decl.capture_names);
35446
35447 const ty = try analyzeOpaqueDecl(
35448 pt,
35449 block.getFileScopeIndex(zcu),
35450 block.namespace.toOptional(),
35451 tracked_inst,
35452 &opaque_decl,
35453 captures,
35454 try sema.createTypeName(block, opaque_decl.name_strategy, "opaque", inst),
35455 );
35456
35457 try sema.addTypeReferenceEntry(src, ty);
35458
35459 // Make sure we update the namespace if the declaration is re-analyzed, to pick
35460 // up on e.g. changed comptime decls.
35461 // TODO MLUGG: me no likey, maybe model namespaces less badly idk
35462 try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu));
35463
35464 return .fromIntern(ty.toIntern());
35465}
src/Sema/LowerZon.zig+11-10
...@@ -125,6 +125,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter...@@ -125,6 +125,7 @@ fn lowerExprAnonResTy(self: *LowerZon, node: Zoir.Node.Index) CompileError!Inter
125 return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern();125 return (try pt.aggregateValue(.fromInterned(ty), values)).toIntern();
126 },126 },
127 .struct_literal => |init| {127 .struct_literal => |init| {
128 if (true) @panic("MLUGG TODO");
128 const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len);129 const elems = try self.sema.arena.alloc(InternPool.Index, init.names.len);
129 for (0..init.names.len) |i| {130 for (0..init.names.len) |i| {
130 elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i)));131 elems[i] = try self.lowerExprAnonResTy(init.vals.at(@intCast(i)));
...@@ -299,7 +300,7 @@ fn checkTypeInner(...@@ -299,7 +300,7 @@ fn checkTypeInner(
299 } else {300 } else {
300 const gop = try visited.getOrPut(sema.arena, ty.toIntern());301 const gop = try visited.getOrPut(sema.arena, ty.toIntern());
301 if (gop.found_existing) return;302 if (gop.found_existing) return;
302 try ty.resolveFields(pt);303 try sema.ensureLayoutResolved(ty);
303 const struct_info = zcu.typeToStruct(ty).?;304 const struct_info = zcu.typeToStruct(ty).?;
304 for (struct_info.field_types.get(ip)) |field_type| {305 for (struct_info.field_types.get(ip)) |field_type| {
305 try self.checkTypeInner(.fromInterned(field_type), null, visited);306 try self.checkTypeInner(.fromInterned(field_type), null, visited);
...@@ -308,7 +309,7 @@ fn checkTypeInner(...@@ -308,7 +309,7 @@ fn checkTypeInner(
308 .@"union" => {309 .@"union" => {
309 const gop = try visited.getOrPut(sema.arena, ty.toIntern());310 const gop = try visited.getOrPut(sema.arena, ty.toIntern());
310 if (gop.found_existing) return;311 if (gop.found_existing) return;
311 try ty.resolveFields(pt);312 try sema.ensureLayoutResolved(ty);
312 const union_info = zcu.typeToUnion(ty).?;313 const union_info = zcu.typeToUnion(ty).?;
313 for (union_info.field_types.get(ip)) |field_type| {314 for (union_info.field_types.get(ip)) |field_type| {
314 if (field_type != .void_type) {315 if (field_type != .void_type) {
...@@ -767,8 +768,8 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -767,8 +768,8 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
767 const io = comp.io;768 const io = comp.io;
768 const ip = &pt.zcu.intern_pool;769 const ip = &pt.zcu.intern_pool;
769770
770 try res_ty.resolveFields(self.sema.pt);771 try self.sema.ensureLayoutResolved(res_ty);
771 try res_ty.resolveStructFieldInits(self.sema.pt);772 try self.sema.ensureFieldInitsResolved(res_ty);
772 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;773 const struct_info = self.sema.pt.zcu.typeToStruct(res_ty).?;
773774
774 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {775 const fields: @FieldType(Zoir.Node, "struct_literal") = switch (node.get(self.file.zoir.?)) {
...@@ -779,7 +780,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -779,7 +780,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
779780
780 const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len);781 const field_values = try self.sema.arena.alloc(InternPool.Index, struct_info.field_names.len);
781782
782 const field_defaults = struct_info.field_inits.get(ip);783 const field_defaults = struct_info.field_defaults.get(ip);
783 if (field_defaults.len > 0) {784 if (field_defaults.len > 0) {
784 @memcpy(field_values, field_defaults);785 @memcpy(field_values, field_defaults);
785 } else {786 } else {
...@@ -803,7 +804,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool...@@ -803,7 +804,7 @@ fn lowerStruct(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool
803 const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);804 const field_type: Type = .fromInterned(struct_info.field_types.get(ip)[name_index]);
804 field_values[name_index] = try self.lowerExprKnownResTy(field_node, field_type);805 field_values[name_index] = try self.lowerExprKnownResTy(field_node, field_type);
805806
806 if (struct_info.comptime_bits.getBit(ip, name_index)) {807 if (struct_info.field_is_comptime_bits.get(ip, name_index)) {
807 const val = ip.indexToKey(field_values[name_index]);808 const val = ip.indexToKey(field_values[name_index]);
808 const default = ip.indexToKey(field_defaults[name_index]);809 const default = ip.indexToKey(field_defaults[name_index]);
809 if (!val.eql(default, ip)) {810 if (!val.eql(default, ip)) {
...@@ -918,9 +919,9 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -918,9 +919,9 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
918 const gpa = comp.gpa;919 const gpa = comp.gpa;
919 const io = comp.io;920 const io = comp.io;
920 const ip = &pt.zcu.intern_pool;921 const ip = &pt.zcu.intern_pool;
921 try res_ty.resolveFields(self.sema.pt);922 try self.sema.ensureLayoutResolved(res_ty);
922 const union_info = self.sema.pt.zcu.typeToUnion(res_ty).?;923 const union_info = pt.zcu.typeToUnion(res_ty).?;
923 const enum_tag_info = union_info.loadTagType(ip);924 const enum_tag_info = ip.loadEnumType(union_info.enum_tag_type);
924925
925 const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {926 const field_name, const maybe_field_node = switch (node.get(self.file.zoir.?)) {
926 .enum_literal => |name| b: {927 .enum_literal => |name| b: {
...@@ -956,7 +957,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool....@@ -956,7 +957,7 @@ fn lowerUnion(self: *LowerZon, node: Zoir.Node.Index, res_ty: Type) !InternPool.
956 const name_index = enum_tag_info.nameIndex(ip, field_name) orelse {957 const name_index = enum_tag_info.nameIndex(ip, field_name) orelse {
957 return error.WrongType;958 return error.WrongType;
958 };959 };
959 const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_ty), name_index);960 const tag = try self.sema.pt.enumValueFieldIndex(.fromInterned(union_info.enum_tag_type), name_index);
960 const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]);961 const field_type: Type = .fromInterned(union_info.field_types.get(ip)[name_index]);
961 const val = if (maybe_field_node) |field_node| b: {962 const val = if (maybe_field_node) |field_node| b: {
962 if (field_type.toIntern() == .void_type) {963 if (field_type.toIntern() == .void_type) {
src/Sema/arith.zig+20-19
...@@ -1053,7 +1053,7 @@ fn shlScalar(...@@ -1053,7 +1053,7 @@ fn shlScalar(
1053 if (rhs_val.isUndef(zcu)) return rhs_val;1053 if (rhs_val.isUndef(zcu)) return rhs_val;
1054 },1054 },
1055 }1055 }
1056 switch (try rhs_val.orderAgainstZeroSema(pt)) {1056 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
1057 .gt => {},1057 .gt => {},
1058 .eq => return lhs_val,1058 .eq => return lhs_val,
1059 .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),1059 .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),
...@@ -1090,7 +1090,7 @@ fn shlWithOverflowScalar(...@@ -1090,7 +1090,7 @@ fn shlWithOverflowScalar(
1090 if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx);1090 if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx);
1091 if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx);1091 if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx);
10921092
1093 switch (try rhs_val.orderAgainstZeroSema(pt)) {1093 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
1094 .gt => {},1094 .gt => {},
1095 .eq => return .{ .overflow_bit = .zero_u1, .wrapped_result = lhs_val },1095 .eq => return .{ .overflow_bit = .zero_u1, .wrapped_result = lhs_val },
1096 .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),1096 .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),
...@@ -1169,7 +1169,7 @@ fn shrScalar(...@@ -1169,7 +1169,7 @@ fn shrScalar(
1169 if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx);1169 if (lhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, lhs_src, vec_idx);
1170 if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx);1170 if (rhs_val.isUndef(zcu)) return sema.failWithUseOfUndef(block, rhs_src, vec_idx);
11711171
1172 switch (try rhs_val.orderAgainstZeroSema(pt)) {1172 switch (Value.order(rhs_val, .zero_comptime_int, zcu)) {
1173 .gt => {},1173 .gt => {},
1174 .eq => return lhs_val,1174 .eq => return lhs_val,
1175 .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),1175 .lt => return sema.failWithNegativeShiftAmount(block, rhs_src, rhs_val, vec_idx),
...@@ -1430,8 +1430,8 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value...@@ -1430,8 +1430,8 @@ fn intAddWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
1430 const info = ty.intInfo(zcu);1430 const info = ty.intInfo(zcu);
1431 var lhs_space: Value.BigIntSpace = undefined;1431 var lhs_space: Value.BigIntSpace = undefined;
1432 var rhs_space: Value.BigIntSpace = undefined;1432 var rhs_space: Value.BigIntSpace = undefined;
1433 const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);1433 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
1434 const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt);1434 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
1435 const limbs = try sema.arena.alloc(1435 const limbs = try sema.arena.alloc(
1436 std.math.big.Limb,1436 std.math.big.Limb,
1437 std.math.big.int.calcTwosCompLimbCount(info.bits),1437 std.math.big.int.calcTwosCompLimbCount(info.bits),
...@@ -1512,8 +1512,8 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value...@@ -1512,8 +1512,8 @@ fn intSubWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
1512 const info = ty.intInfo(zcu);1512 const info = ty.intInfo(zcu);
1513 var lhs_space: Value.BigIntSpace = undefined;1513 var lhs_space: Value.BigIntSpace = undefined;
1514 var rhs_space: Value.BigIntSpace = undefined;1514 var rhs_space: Value.BigIntSpace = undefined;
1515 const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);1515 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
1516 const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt);1516 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
1517 const limbs = try sema.arena.alloc(1517 const limbs = try sema.arena.alloc(
1518 std.math.big.Limb,1518 std.math.big.Limb,
1519 std.math.big.int.calcTwosCompLimbCount(info.bits),1519 std.math.big.int.calcTwosCompLimbCount(info.bits),
...@@ -1597,8 +1597,8 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value...@@ -1597,8 +1597,8 @@ fn intMulWithOverflowInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value
1597 const info = ty.intInfo(zcu);1597 const info = ty.intInfo(zcu);
1598 var lhs_space: Value.BigIntSpace = undefined;1598 var lhs_space: Value.BigIntSpace = undefined;
1599 var rhs_space: Value.BigIntSpace = undefined;1599 var rhs_space: Value.BigIntSpace = undefined;
1600 const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);1600 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
1601 const rhs_bigint = try rhs.toBigIntSema(&rhs_space, pt);1601 const rhs_bigint = rhs.toBigInt(&rhs_space, zcu);
1602 const limbs = try sema.arena.alloc(1602 const limbs = try sema.arena.alloc(
1603 std.math.big.Limb,1603 std.math.big.Limb,
1604 lhs_bigint.limbs.len + rhs_bigint.limbs.len,1604 lhs_bigint.limbs.len + rhs_bigint.limbs.len,
...@@ -1840,7 +1840,7 @@ fn intShl(...@@ -1840,7 +1840,7 @@ fn intShl(
1840 var lhs_space: Value.BigIntSpace = undefined;1840 var lhs_space: Value.BigIntSpace = undefined;
1841 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);1841 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
18421842
1843 const shift_amt: usize = @intCast(try rhs.toUnsignedIntSema(pt));1843 const shift_amt: usize = @intCast(rhs.toUnsignedInt(zcu));
1844 if (shift_amt >= info.bits) {1844 if (shift_amt >= info.bits) {
1845 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);1845 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);
1846 }1846 }
...@@ -1862,7 +1862,7 @@ fn intShlSat(...@@ -1862,7 +1862,7 @@ fn intShlSat(
1862 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);1862 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
18631863
1864 const shift_amt: usize = amt: {1864 const shift_amt: usize = amt: {
1865 if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| {1865 if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| {
1866 if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt;1866 if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt;
1867 }1867 }
1868 // We only support ints with up to 2^16 - 1 bits, so this1868 // We only support ints with up to 2^16 - 1 bits, so this
...@@ -1895,9 +1895,9 @@ fn intShlWithOverflow(...@@ -1895,9 +1895,9 @@ fn intShlWithOverflow(
1895 const info = lhs_ty.intInfo(zcu);1895 const info = lhs_ty.intInfo(zcu);
18961896
1897 var lhs_space: Value.BigIntSpace = undefined;1897 var lhs_space: Value.BigIntSpace = undefined;
1898 const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);1898 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
18991899
1900 const shift_amt: usize = @intCast(try rhs.toUnsignedIntSema(pt));1900 const shift_amt: usize = @intCast(rhs.toUnsignedInt(zcu));
1901 if (shift_amt >= info.bits) {1901 if (shift_amt >= info.bits) {
1902 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);1902 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);
1903 }1903 }
...@@ -1924,9 +1924,10 @@ fn comptimeIntShl(...@@ -1924,9 +1924,10 @@ fn comptimeIntShl(
1924 vec_idx: ?usize,1924 vec_idx: ?usize,
1925) !Value {1925) !Value {
1926 const pt = sema.pt;1926 const pt = sema.pt;
1927 const zcu = pt.zcu;
1927 var lhs_space: Value.BigIntSpace = undefined;1928 var lhs_space: Value.BigIntSpace = undefined;
1928 const lhs_bigint = try lhs.toBigIntSema(&lhs_space, pt);1929 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
1929 if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| {1930 if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| {
1930 if (std.math.cast(usize, shift_amt_u64)) |shift_amt| {1931 if (std.math.cast(usize, shift_amt_u64)) |shift_amt| {
1931 const result_bigint = try intShlInner(sema, lhs_bigint, shift_amt);1932 const result_bigint = try intShlInner(sema, lhs_bigint, shift_amt);
1932 return pt.intValue_big(.comptime_int, result_bigint.toConst());1933 return pt.intValue_big(.comptime_int, result_bigint.toConst());
...@@ -1963,15 +1964,15 @@ fn intShr(...@@ -1963,15 +1964,15 @@ fn intShr(
1963 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);1964 const lhs_bigint = lhs.toBigInt(&lhs_space, zcu);
19641965
1965 const shift_amt: usize = if (rhs_ty.toIntern() == .comptime_int_type) amt: {1966 const shift_amt: usize = if (rhs_ty.toIntern() == .comptime_int_type) amt: {
1966 if (try rhs.getUnsignedIntSema(pt)) |shift_amt_u64| {1967 if (rhs.getUnsignedInt(zcu)) |shift_amt_u64| {
1967 if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt;1968 if (std.math.cast(usize, shift_amt_u64)) |shift_amt| break :amt shift_amt;
1968 }1969 }
1969 if (try rhs.compareAllWithZeroSema(.lt, pt)) {1970 if (rhs.compareAllWithZero(.lt, zcu)) {
1970 return sema.failWithNegativeShiftAmount(block, rhs_src, rhs, vec_idx);1971 return sema.failWithNegativeShiftAmount(block, rhs_src, rhs, vec_idx);
1971 } else {1972 } else {
1972 return sema.failWithUnsupportedComptimeShiftAmount(block, rhs_src, vec_idx);1973 return sema.failWithUnsupportedComptimeShiftAmount(block, rhs_src, vec_idx);
1973 }1974 }
1974 } else @intCast(try rhs.toUnsignedIntSema(pt));1975 } else @intCast(rhs.toUnsignedInt(zcu));
19751976
1976 if (lhs_ty.toIntern() != .comptime_int_type and shift_amt >= lhs_ty.intInfo(zcu).bits) {1977 if (lhs_ty.toIntern() != .comptime_int_type and shift_amt >= lhs_ty.intInfo(zcu).bits) {
1977 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);1978 return sema.failWithTooLargeShiftAmount(block, lhs_ty, rhs, rhs_src, vec_idx);
...@@ -2006,7 +2007,7 @@ fn intBitReverse(sema: *Sema, val: Value, ty: Type) !Value {...@@ -2006,7 +2007,7 @@ fn intBitReverse(sema: *Sema, val: Value, ty: Type) !Value {
2006 const info = ty.intInfo(zcu);2007 const info = ty.intInfo(zcu);
20072008
2008 var val_space: Value.BigIntSpace = undefined;2009 var val_space: Value.BigIntSpace = undefined;
2009 const val_bigint = try val.toBigIntSema(&val_space, pt);2010 const val_bigint = val.toBigInt(&val_space, zcu);
20102011
2011 const limbs = try sema.arena.alloc(2012 const limbs = try sema.arena.alloc(
2012 std.math.big.Limb,2013 std.math.big.Limb,
src/Sema/bitcast.zig+7-4
...@@ -79,8 +79,8 @@ fn bitCastInner(...@@ -79,8 +79,8 @@ fn bitCastInner(
7979
80 const val_ty = val.typeOf(zcu);80 const val_ty = val.typeOf(zcu);
8181
82 try val_ty.resolveLayout(pt);82 val_ty.assertHasLayout(zcu);
83 try dest_ty.resolveLayout(pt);83 try sema.ensureLayoutResolved(dest_ty);
8484
85 assert(val_ty.hasWellDefinedLayout(zcu));85 assert(val_ty.hasWellDefinedLayout(zcu));
8686
...@@ -138,8 +138,8 @@ fn bitCastSpliceInner(...@@ -138,8 +138,8 @@ fn bitCastSpliceInner(
138 const val_ty = val.typeOf(zcu);138 const val_ty = val.typeOf(zcu);
139 const splice_val_ty = splice_val.typeOf(zcu);139 const splice_val_ty = splice_val.typeOf(zcu);
140140
141 try val_ty.resolveLayout(pt);141 try sema.ensureLayoutResolved(val_ty);
142 try splice_val_ty.resolveLayout(pt);142 try sema.ensureLayoutResolved(splice_val_ty);
143143
144 const splice_bits = splice_val_ty.bitSize(zcu);144 const splice_bits = splice_val_ty.bitSize(zcu);
145145
...@@ -673,6 +673,9 @@ const PackValueBits = struct {...@@ -673,6 +673,9 @@ const PackValueBits = struct {
673 fn primitive(pack: *PackValueBits, want_ty: Type) BitCastError!Value {673 fn primitive(pack: *PackValueBits, want_ty: Type) BitCastError!Value {
674 const pt = pack.pt;674 const pt = pack.pt;
675 const zcu = pt.zcu;675 const zcu = pt.zcu;
676
677 if (try want_ty.onePossibleValue(pt)) |opv| return opv;
678
676 const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu));679 const vals, const bit_offset = pack.prepareBits(want_ty.bitSize(zcu));
677680
678 for (vals) |val| {681 for (vals) |val| {
src/Sema/comptime_ptr_access.zig+19-19
...@@ -67,7 +67,7 @@ pub fn storeComptimePtr(...@@ -67,7 +67,7 @@ pub fn storeComptimePtr(
6767
68 {68 {
69 const store_ty: Type = .fromInterned(ptr_info.child);69 const store_ty: Type = .fromInterned(ptr_info.child);
70 if (!try store_ty.comptimeOnlySema(pt) and !try store_ty.hasRuntimeBitsIgnoreComptimeSema(pt)) {70 if (!store_ty.comptimeOnly(zcu) and !store_ty.hasRuntimeBits(zcu)) {
71 // zero-bit store; nothing to do71 // zero-bit store; nothing to do
72 return .success;72 return .success;
73 }73 }
...@@ -354,8 +354,8 @@ fn loadComptimePtrInner(...@@ -354,8 +354,8 @@ fn loadComptimePtrInner(
354 const load_one_ty, const load_count = load_ty.arrayBase(zcu);354 const load_one_ty, const load_count = load_ty.arrayBase(zcu);
355355
356 const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {356 const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {
357 if (try load_one_ty.comptimeOnlySema(pt)) break :restructure_array;357 if (load_one_ty.comptimeOnly(zcu)) break :restructure_array;
358 const elem_len = try load_one_ty.abiSizeSema(pt);358 const elem_len = load_one_ty.abiSize(zcu);
359 if (ptr.byte_offset % elem_len != 0) break :restructure_array;359 if (ptr.byte_offset % elem_len != 0) break :restructure_array;
360 break :idx @divExact(ptr.byte_offset, elem_len);360 break :idx @divExact(ptr.byte_offset, elem_len);
361 };361 };
...@@ -401,12 +401,12 @@ fn loadComptimePtrInner(...@@ -401,12 +401,12 @@ fn loadComptimePtrInner(
401 var cur_offset = ptr.byte_offset;401 var cur_offset = ptr.byte_offset;
402402
403 if (load_ty.zigTypeTag(zcu) == .array and array_offset > 0) {403 if (load_ty.zigTypeTag(zcu) == .array and array_offset > 0) {
404 cur_offset += try load_ty.childType(zcu).abiSizeSema(pt) * array_offset;404 cur_offset += load_ty.childType(zcu).abiSize(zcu) * array_offset;
405 }405 }
406406
407 const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else try load_ty.abiSizeSema(pt);407 const need_bytes = if (host_bits > 0) (host_bits + 7) / 8 else load_ty.abiSize(zcu);
408408
409 if (cur_offset + need_bytes > try cur_val.typeOf(zcu).abiSizeSema(pt)) {409 if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) {
410 return .{ .out_of_bounds = cur_val.typeOf(zcu) };410 return .{ .out_of_bounds = cur_val.typeOf(zcu) };
411 }411 }
412412
...@@ -441,7 +441,7 @@ fn loadComptimePtrInner(...@@ -441,7 +441,7 @@ fn loadComptimePtrInner(
441 .optional => break, // this can only be a pointer-like optional so is terminal441 .optional => break, // this can only be a pointer-like optional so is terminal
442 .array => {442 .array => {
443 const elem_ty = cur_ty.childType(zcu);443 const elem_ty = cur_ty.childType(zcu);
444 const elem_size = try elem_ty.abiSizeSema(pt);444 const elem_size = elem_ty.abiSize(zcu);
445 const elem_idx = cur_offset / elem_size;445 const elem_idx = cur_offset / elem_size;
446 const next_elem_off = elem_size * (elem_idx + 1);446 const next_elem_off = elem_size * (elem_idx + 1);
447 if (cur_offset + need_bytes <= next_elem_off) {447 if (cur_offset + need_bytes <= next_elem_off) {
...@@ -457,7 +457,7 @@ fn loadComptimePtrInner(...@@ -457,7 +457,7 @@ fn loadComptimePtrInner(
457 .@"packed" => break, // let the bitcast logic handle this457 .@"packed" => break, // let the bitcast logic handle this
458 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {458 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
459 const start_off = cur_ty.structFieldOffset(field_idx, zcu);459 const start_off = cur_ty.structFieldOffset(field_idx, zcu);
460 const end_off = start_off + try cur_ty.fieldType(field_idx, zcu).abiSizeSema(pt);460 const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu);
461 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {461 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
462 cur_val = try cur_val.getElem(sema.pt, field_idx);462 cur_val = try cur_val.getElem(sema.pt, field_idx);
463 cur_offset -= start_off;463 cur_offset -= start_off;
...@@ -484,7 +484,7 @@ fn loadComptimePtrInner(...@@ -484,7 +484,7 @@ fn loadComptimePtrInner(
484 };484 };
485 // The payload always has offset 0. If it's big enough485 // The payload always has offset 0. If it's big enough
486 // to represent the whole load type, we can use it.486 // to represent the whole load type, we can use it.
487 if (try payload.typeOf(zcu).abiSizeSema(pt) >= need_bytes) {487 if (payload.typeOf(zcu).abiSize(zcu) >= need_bytes) {
488 cur_val = payload;488 cur_val = payload;
489 } else {489 } else {
490 break;490 break;
...@@ -753,8 +753,8 @@ fn prepareComptimePtrStore(...@@ -753,8 +753,8 @@ fn prepareComptimePtrStore(
753753
754 const store_one_ty, const store_count = store_ty.arrayBase(zcu);754 const store_one_ty, const store_count = store_ty.arrayBase(zcu);
755 const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {755 const extra_base_index: u64 = if (ptr.byte_offset == 0) 0 else idx: {
756 if (try store_one_ty.comptimeOnlySema(pt)) break :restructure_array;756 if (store_one_ty.comptimeOnly(zcu)) break :restructure_array;
757 const elem_len = try store_one_ty.abiSizeSema(pt);757 const elem_len = store_one_ty.abiSize(zcu);
758 if (ptr.byte_offset % elem_len != 0) break :restructure_array;758 if (ptr.byte_offset % elem_len != 0) break :restructure_array;
759 break :idx @divExact(ptr.byte_offset, elem_len);759 break :idx @divExact(ptr.byte_offset, elem_len);
760 };760 };
...@@ -807,11 +807,11 @@ fn prepareComptimePtrStore(...@@ -807,11 +807,11 @@ fn prepareComptimePtrStore(
807 var cur_val: *MutableValue, var cur_offset: u64 = switch (base_strat) {807 var cur_val: *MutableValue, var cur_offset: u64 = switch (base_strat) {
808 .direct => |direct| .{ direct.val, 0 },808 .direct => |direct| .{ direct.val, 0 },
809 // It's okay to do `abiSize` - the comptime-only case will be caught below.809 // It's okay to do `abiSize` - the comptime-only case will be caught below.
810 .index => |index| .{ index.val, index.elem_index * try index.val.typeOf(zcu).childType(zcu).abiSizeSema(pt) },810 .index => |index| .{ index.val, index.elem_index * index.val.typeOf(zcu).childType(zcu).abiSize(zcu) },
811 .flat_index => |flat_index| .{811 .flat_index => |flat_index| .{
812 flat_index.val,812 flat_index.val,
813 // It's okay to do `abiSize` - the comptime-only case will be caught below.813 // It's okay to do `abiSize` - the comptime-only case will be caught below.
814 flat_index.flat_elem_index * try flat_index.val.typeOf(zcu).arrayBase(zcu)[0].abiSizeSema(pt),814 flat_index.flat_elem_index * flat_index.val.typeOf(zcu).arrayBase(zcu)[0].abiSize(zcu),
815 },815 },
816 .reinterpret => |r| .{ r.val, r.byte_offset },816 .reinterpret => |r| .{ r.val, r.byte_offset },
817 else => unreachable,817 else => unreachable,
...@@ -823,12 +823,12 @@ fn prepareComptimePtrStore(...@@ -823,12 +823,12 @@ fn prepareComptimePtrStore(
823 }823 }
824824
825 if (store_ty.zigTypeTag(zcu) == .array and array_offset > 0) {825 if (store_ty.zigTypeTag(zcu) == .array and array_offset > 0) {
826 cur_offset += try store_ty.childType(zcu).abiSizeSema(pt) * array_offset;826 cur_offset += store_ty.childType(zcu).abiSize(zcu) * array_offset;
827 }827 }
828828
829 const need_bytes = try store_ty.abiSizeSema(pt);829 const need_bytes = store_ty.abiSize(zcu);
830830
831 if (cur_offset + need_bytes > try cur_val.typeOf(zcu).abiSizeSema(pt)) {831 if (cur_offset + need_bytes > cur_val.typeOf(zcu).abiSize(zcu)) {
832 return .{ .out_of_bounds = cur_val.typeOf(zcu) };832 return .{ .out_of_bounds = cur_val.typeOf(zcu) };
833 }833 }
834834
...@@ -863,7 +863,7 @@ fn prepareComptimePtrStore(...@@ -863,7 +863,7 @@ fn prepareComptimePtrStore(
863 .optional => break, // this can only be a pointer-like optional so is terminal863 .optional => break, // this can only be a pointer-like optional so is terminal
864 .array => {864 .array => {
865 const elem_ty = cur_ty.childType(zcu);865 const elem_ty = cur_ty.childType(zcu);
866 const elem_size = try elem_ty.abiSizeSema(pt);866 const elem_size = elem_ty.abiSize(zcu);
867 const elem_idx = cur_offset / elem_size;867 const elem_idx = cur_offset / elem_size;
868 const next_elem_off = elem_size * (elem_idx + 1);868 const next_elem_off = elem_size * (elem_idx + 1);
869 if (cur_offset + need_bytes <= next_elem_off) {869 if (cur_offset + need_bytes <= next_elem_off) {
...@@ -879,7 +879,7 @@ fn prepareComptimePtrStore(...@@ -879,7 +879,7 @@ fn prepareComptimePtrStore(
879 .@"packed" => break, // let the bitcast logic handle this879 .@"packed" => break, // let the bitcast logic handle this
880 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {880 .@"extern" => for (0..cur_ty.structFieldCount(zcu)) |field_idx| {
881 const start_off = cur_ty.structFieldOffset(field_idx, zcu);881 const start_off = cur_ty.structFieldOffset(field_idx, zcu);
882 const end_off = start_off + try cur_ty.fieldType(field_idx, zcu).abiSizeSema(pt);882 const end_off = start_off + cur_ty.fieldType(field_idx, zcu).abiSize(zcu);
883 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {883 if (cur_offset >= start_off and cur_offset + need_bytes <= end_off) {
884 cur_val = try cur_val.elem(pt, sema.arena, field_idx);884 cur_val = try cur_val.elem(pt, sema.arena, field_idx);
885 cur_offset -= start_off;885 cur_offset -= start_off;
...@@ -902,7 +902,7 @@ fn prepareComptimePtrStore(...@@ -902,7 +902,7 @@ fn prepareComptimePtrStore(
902 };902 };
903 // The payload always has offset 0. If it's big enough903 // The payload always has offset 0. If it's big enough
904 // to represent the whole load type, we can use it.904 // to represent the whole load type, we can use it.
905 if (try payload.typeOf(zcu).abiSizeSema(pt) >= need_bytes) {905 if (payload.typeOf(zcu).abiSize(zcu) >= need_bytes) {
906 cur_val = payload;906 cur_val = payload;
907 } else {907 } else {
908 break;908 break;
src/Sema/type_resolution.zig created+993
...@@ -0,0 +1,993 @@
1const std = @import("std");
2const assert = std.debug.assert;
3const mem = std.mem;
4
5const Sema = @import("../Sema.zig");
6const Block = Sema.Block;
7const Type = @import("../Type.zig");
8const Value = @import("../Value.zig");
9const Zcu = @import("../Zcu.zig");
10const CompileError = Zcu.CompileError;
11const SemaError = Zcu.SemaError;
12const LazySrcLoc = Zcu.LazySrcLoc;
13const InternPool = @import("../InternPool.zig");
14const Alignment = InternPool.Alignment;
15const arith = @import("arith.zig");
16
17/// Ensures that `ty` has known layout, including alignment, size, and (where relevant) field offsets.
18/// `ty` may be any type; its layout is resolved *recursively* if necessary.
19/// Adds incremental dependencies tracking any required type resolution.
20/// MLUGG TODO: to make the langspec non-stupid, we need to call this from WAY fewer places (the conditions need to be less specific).
21/// e.g. I think creating the type `fn (A, B) C` should force layout resolution of `A`,`B`,`C`, which will simplify some `analyzeCall` logic.
22/// wait i just realised that's probably a terrible idea, fns are a common cause of dep loops rn... so maybe not lol idk...
23/// perhaps "layout resolution" for a function should resolve layout of ret ty and stuff, idk. justification: the "layout" of a function is whether
24/// fnHasRuntimeBits, which depends whether the ret ty is comptime-only, i.e. the ret ty layout
25/// MLUGG TODO: to be clear, i should audit EVERY use of this before PRing
26pub fn ensureLayoutResolved(sema: *Sema, ty: Type) SemaError!void {
27 const pt = sema.pt;
28 const zcu = pt.zcu;
29 const ip = &zcu.intern_pool;
30 switch (ip.indexToKey(ty.toIntern())) {
31 .int_type,
32 .ptr_type,
33 .anyframe_type,
34 .simple_type,
35 .opaque_type,
36 .enum_type,
37 .error_set_type,
38 .inferred_error_set_type,
39 => {},
40
41 .func_type => |func_type| {
42 for (func_type.param_types.get(ip)) |param_ty| {
43 try ensureLayoutResolved(sema, .fromInterned(param_ty));
44 }
45 try ensureLayoutResolved(sema, .fromInterned(func_type.return_type));
46 },
47
48 .array_type => |arr| return ensureLayoutResolved(sema, .fromInterned(arr.child)),
49 .vector_type => |vec| return ensureLayoutResolved(sema, .fromInterned(vec.child)),
50 .opt_type => |child| return ensureLayoutResolved(sema, .fromInterned(child)),
51 .error_union_type => |eu| return ensureLayoutResolved(sema, .fromInterned(eu.payload_type)),
52 .tuple_type => |tuple| for (tuple.types.get(ip)) |field_ty| {
53 try ensureLayoutResolved(sema, .fromInterned(field_ty));
54 },
55 .struct_type, .union_type => {
56 try sema.declareDependency(.{ .type_layout = ty.toIntern() });
57 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_layout = ty.toIntern() }))) {
58 // TODO: better error message
59 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(
60 ty.srcLoc(zcu),
61 "{s} '{f}' depends on itself",
62 .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) },
63 ));
64 }
65 try pt.ensureTypeLayoutUpToDate(ty);
66 },
67
68 // values, not types
69 .undef,
70 .simple_value,
71 .variable,
72 .@"extern",
73 .func,
74 .int,
75 .err,
76 .error_union,
77 .enum_literal,
78 .enum_tag,
79 .empty_enum_value,
80 .float,
81 .ptr,
82 .slice,
83 .opt,
84 .aggregate,
85 .un,
86 // memoization, not types
87 .memoized_call,
88 => unreachable,
89 }
90}
91
92/// Asserts that `ty` is either a `struct` type, or an `enum` type.
93/// If `ty` is a struct, ensures that fields' default values are resolved.
94/// If `ty` is an enum, ensures that fields' integer tag valus are resolved.
95/// Adds incremental dependencies tracking the required type resolution.
96pub fn ensureFieldInitsResolved(sema: *Sema, ty: Type) SemaError!void {
97 const pt = sema.pt;
98 const zcu = pt.zcu;
99 const ip = &zcu.intern_pool;
100 switch (ip.indexToKey(ty.toIntern())) {
101 .struct_type, .enum_type => {},
102 else => unreachable, // assertion failure
103 }
104
105 try sema.declareDependency(.{ .type_inits = ty.toIntern() });
106 if (zcu.analysis_in_progress.contains(.wrap(.{ .type_inits = ty.toIntern() }))) {
107 // TODO: better error message
108 return sema.failWithOwnedErrorMsg(null, try sema.errMsg(
109 ty.srcLoc(zcu),
110 "{s} '{f}' depends on itself",
111 .{ @tagName(ty.zigTypeTag(zcu)), ty.fmt(pt) },
112 ));
113 }
114 try pt.ensureTypeInitsUpToDate(ty);
115}
116/// Asserts that `struct_ty` is a non-packed non-tuple struct, and that `sema.owner` is that type.
117/// This function *does* register the `src_hash` dependency on the struct.
118pub fn resolveStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
119 const pt = sema.pt;
120 const zcu = pt.zcu;
121 const comp = zcu.comp;
122 const gpa = comp.gpa;
123 const ip = &zcu.intern_pool;
124
125 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());
126
127 const struct_obj = ip.loadStructType(struct_ty.toIntern());
128 const zir_index = struct_obj.zir_index.resolve(ip).?;
129
130 assert(struct_obj.layout != .@"packed");
131
132 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
133
134 var block: Block = .{
135 .parent = null,
136 .sema = sema,
137 .namespace = struct_obj.namespace,
138 .instructions = .{},
139 .inlining = null,
140 .comptime_reason = undefined, // always set before using `block`
141 .src_base_inst = struct_obj.zir_index,
142 .type_name_ctx = struct_obj.name,
143 };
144 defer assert(block.instructions.items.len == 0);
145
146 const zir_struct = sema.code.getStructDecl(zir_index);
147 var field_it = zir_struct.iterateFields();
148 while (field_it.next()) |zir_field| {
149 const field_ty_src: LazySrcLoc = .{
150 .base_node_inst = struct_obj.zir_index,
151 .offset = .{ .container_field_type = zir_field.idx },
152 };
153 const field_align_src: LazySrcLoc = .{
154 .base_node_inst = struct_obj.zir_index,
155 .offset = .{ .container_field_align = zir_field.idx },
156 };
157
158 const field_ty: Type = field_ty: {
159 block.comptime_reason = .{ .reason = .{
160 .src = field_ty_src,
161 .r = .{ .simple = .struct_field_types },
162 } };
163 const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index);
164 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
165 };
166 assert(!field_ty.isGenericPoison());
167
168 try sema.ensureLayoutResolved(field_ty);
169
170 const explicit_field_align: Alignment = a: {
171 block.comptime_reason = .{ .reason = .{
172 .src = field_align_src,
173 .r = .{ .simple = .struct_field_attrs },
174 } };
175 const align_body = zir_field.align_body orelse break :a .none;
176 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
177 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
178 };
179
180 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
181 return sema.failWithOwnedErrorMsg(&block, msg: {
182 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
183 errdefer msg.destroy(gpa);
184 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
185 try sema.addDeclaredHereNote(msg, field_ty);
186 break :msg msg;
187 });
188 }
189 if (struct_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .struct_field)) {
190 return sema.failWithOwnedErrorMsg(&block, msg: {
191 const msg = try sema.errMsg(field_ty_src, "extern structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
192 errdefer msg.destroy(gpa);
193 try sema.explainWhyTypeIsNotExtern(msg, field_ty_src, field_ty, .struct_field);
194 try sema.addDeclaredHereNote(msg, field_ty);
195 break :msg msg;
196 });
197 }
198
199 struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
200 if (struct_obj.field_aligns.len != 0) {
201 struct_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;
202 } else {
203 assert(explicit_field_align == .none);
204 }
205 }
206
207 try finishStructLayout(sema, &block, struct_ty.srcLoc(zcu), struct_ty.toIntern(), &struct_obj);
208}
209
210/// Called after populating field types and alignments; populates field offsets, runtime order, and
211/// overall struct layout information (size, alignment, comptime-only state, etc).
212pub fn finishStructLayout(
213 sema: *Sema,
214 /// Only used to report compile errors.
215 block: *Block,
216 struct_src: LazySrcLoc,
217 struct_ty: InternPool.Index,
218 struct_obj: *const InternPool.LoadedStructType,
219) SemaError!void {
220 const pt = sema.pt;
221 const zcu = pt.zcu;
222 const comp = zcu.comp;
223 const io = comp.io;
224 const ip = &zcu.intern_pool;
225 var comptime_only = false;
226 var one_possible_value = true;
227 var struct_align: Alignment = .@"1";
228 // Unlike `struct_obj.field_aligns`, these are not `.none`.
229 const resolved_field_aligns = try sema.arena.alloc(Alignment, struct_obj.field_names.len);
230 for (resolved_field_aligns, 0..) |*align_out, field_idx| {
231 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]);
232 const field_align: Alignment = a: {
233 if (struct_obj.field_aligns.len != 0) {
234 const a = struct_obj.field_aligns.get(ip)[field_idx];
235 if (a != .none) break :a a;
236 }
237 break :a field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
238 };
239 if (!struct_obj.field_is_comptime_bits.get(ip, field_idx)) {
240 // Non-`comptime` fields contribute to the struct's layout.
241 struct_align = struct_align.maxStrict(field_align);
242 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
243 if (try field_ty.onePossibleValue(pt) == null) one_possible_value = false;
244 if (struct_obj.layout == .auto) {
245 struct_obj.field_runtime_order.get(ip)[field_idx] = @enumFromInt(field_idx);
246 }
247 } else if (struct_obj.layout == .auto) {
248 struct_obj.field_runtime_order.get(ip)[field_idx] = .omitted; // comptime fields are not in the runtime order
249 }
250 align_out.* = field_align;
251 }
252 if (struct_obj.layout == .auto) {
253 const runtime_order = struct_obj.field_runtime_order.get(ip);
254 // This logic does not reorder fields; it only moves the omitted ones to the end so that logic
255 // elsewhere does not need to special-case. TODO: support field reordering in all the backends!
256 if (!zcu.backendSupportsFeature(.field_reordering)) {
257 var i: usize = 0;
258 var off: usize = 0;
259 while (i + off < runtime_order.len) {
260 if (runtime_order[i + off] == .omitted) {
261 off += 1;
262 } else {
263 runtime_order[i] = runtime_order[i + off];
264 i += 1;
265 }
266 }
267 } else {
268 // Sort by descending alignment to minimize padding.
269 const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
270 const AlignSortCtx = struct {
271 aligns: []const Alignment,
272 fn lessThan(ctx: @This(), a: RuntimeOrder, b: RuntimeOrder) bool {
273 assert(a != .unresolved);
274 assert(b != .unresolved);
275 if (a == .omitted) return false;
276 if (b == .omitted) return true;
277 const a_align = ctx.aligns[@intFromEnum(a)];
278 const b_align = ctx.aligns[@intFromEnum(b)];
279 return a_align.compare(.gt, b_align);
280 }
281 };
282 mem.sortUnstable(
283 RuntimeOrder,
284 runtime_order,
285 @as(AlignSortCtx, .{ .aligns = resolved_field_aligns }),
286 AlignSortCtx.lessThan,
287 );
288 }
289 }
290
291 var runtime_order_it = struct_obj.iterateRuntimeOrder(ip);
292 var cur_offset: u64 = 0;
293 while (runtime_order_it.next()) |field_idx| {
294 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[field_idx]);
295 const offset = resolved_field_aligns[field_idx].forward(cur_offset);
296 struct_obj.field_offsets.get(ip)[field_idx] = @truncate(offset); // truncate because the overflow is handled below
297 cur_offset = offset + field_ty.abiSize(zcu);
298 }
299 const struct_size = std.math.cast(u32, struct_align.forward(cur_offset)) orelse return sema.fail(
300 block,
301 struct_src,
302 "struct layout requires size {d}, this compiler implementation supports up to {d}",
303 .{ struct_align.forward(cur_offset), std.math.maxInt(u32) },
304 );
305 ip.resolveStructLayout(
306 io,
307 struct_ty,
308 struct_size,
309 struct_align,
310 false, // MLUGG TODO XXX NPV
311 one_possible_value,
312 comptime_only,
313 );
314}
315
316/// Asserts that `struct_ty` is a packed struct, and that `sema.owner` is that type.
317/// This function *does* register the `src_hash` dependency on the struct.
318pub fn resolvePackedStructLayout(sema: *Sema, struct_ty: Type) CompileError!void {
319 const pt = sema.pt;
320 const zcu = pt.zcu;
321 const comp = zcu.comp;
322 const gpa = comp.gpa;
323 const ip = &zcu.intern_pool;
324
325 assert(sema.owner.unwrap().type_layout == struct_ty.toIntern());
326
327 const struct_obj = ip.loadStructType(struct_ty.toIntern());
328 const zir_index = struct_obj.zir_index.resolve(ip).?;
329
330 assert(struct_obj.layout == .@"packed");
331
332 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
333
334 var block: Block = .{
335 .parent = null,
336 .sema = sema,
337 .namespace = struct_obj.namespace,
338 .instructions = .{},
339 .inlining = null,
340 .comptime_reason = undefined, // always set before using `block`
341 .src_base_inst = struct_obj.zir_index,
342 .type_name_ctx = struct_obj.name,
343 };
344 defer assert(block.instructions.items.len == 0);
345
346 var field_bits: u64 = 0;
347 const zir_struct = sema.code.getStructDecl(zir_index);
348 var field_it = zir_struct.iterateFields();
349 while (field_it.next()) |zir_field| {
350 const field_ty_src: LazySrcLoc = .{
351 .base_node_inst = struct_obj.zir_index,
352 .offset = .{ .container_field_type = zir_field.idx },
353 };
354 const field_ty: Type = field_ty: {
355 block.comptime_reason = .{ .reason = .{
356 .src = field_ty_src,
357 .r = .{ .simple = .struct_field_types },
358 } };
359 const type_ref = try sema.resolveInlineBody(&block, zir_field.type_body, zir_index);
360 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
361 };
362 assert(!field_ty.isGenericPoison());
363 struct_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
364
365 try sema.ensureLayoutResolved(field_ty);
366
367 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
368 return sema.failWithOwnedErrorMsg(&block, msg: {
369 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in struct", .{field_ty.fmt(pt)});
370 errdefer msg.destroy(gpa);
371 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
372 try sema.addDeclaredHereNote(msg, field_ty);
373 break :msg msg;
374 });
375 }
376 if (!field_ty.packable(zcu)) {
377 return sema.failWithOwnedErrorMsg(&block, msg: {
378 const msg = try sema.errMsg(field_ty_src, "packed structs cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
379 errdefer msg.destroy(gpa);
380 try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty);
381 try sema.addDeclaredHereNote(msg, field_ty);
382 break :msg msg;
383 });
384 }
385 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
386 field_bits += field_ty.bitSize(zcu);
387 }
388
389 try resolvePackedStructBackingInt(sema, &block, field_bits, struct_ty, &struct_obj);
390}
391
392pub fn resolvePackedStructBackingInt(
393 sema: *Sema,
394 block: *Block,
395 field_bits: u64,
396 struct_ty: Type,
397 struct_obj: *const InternPool.LoadedStructType,
398) SemaError!void {
399 const pt = sema.pt;
400 const zcu = pt.zcu;
401 const comp = zcu.comp;
402 const gpa = comp.gpa;
403 const io = comp.io;
404 const ip = &zcu.intern_pool;
405
406 switch (struct_obj.packed_backing_mode) {
407 .explicit => {
408 // We only need to validate the type.
409 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
410 assert(backing_ty.zigTypeTag(zcu) == .int);
411 if (field_bits != backing_ty.intInfo(zcu).bits) return sema.failWithOwnedErrorMsg(block, msg: {
412 const src = struct_ty.srcLoc(zcu);
413 const msg = try sema.errMsg(src, "backing integer bit width does not match total bit width of fields", .{});
414 errdefer msg.destroy(gpa);
415 try sema.errNote(src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_ty.fmt(pt), backing_ty.bitSize(zcu) });
416 try sema.errNote(src, msg, "struct fields have total bit width '{d}'", .{field_bits});
417 break :msg msg;
418 });
419 },
420 .auto => {
421 // We need to generate the inferred tag.
422 const want_bits = std.math.cast(u16, field_bits) orelse return sema.fail(
423 block,
424 struct_ty.srcLoc(zcu),
425 "packed struct bit width '{d}' exceeds maximum bit width of 65535",
426 .{field_bits},
427 );
428 const backing_int = try pt.intType(.unsigned, want_bits);
429 ip.resolvePackedStructBackingInt(io, struct_ty.toIntern(), backing_int.toIntern());
430 },
431 }
432}
433
434/// Asserts that `struct_ty` is a non-tuple struct, and that `sema.owner` is that type.
435/// This function *does* register the `src_hash` dependency on the struct.
436pub fn resolveStructDefaults(sema: *Sema, struct_ty: Type) CompileError!void {
437 const pt = sema.pt;
438 const zcu = pt.zcu;
439 const comp = zcu.comp;
440 const gpa = comp.gpa;
441 const ip = &zcu.intern_pool;
442
443 assert(sema.owner.unwrap().type_inits == struct_ty.toIntern());
444
445 try sema.ensureLayoutResolved(struct_ty);
446
447 const struct_obj = ip.loadStructType(struct_ty.toIntern());
448 const zir_index = struct_obj.zir_index.resolve(ip).?;
449
450 try sema.declareDependency(.{ .src_hash = struct_obj.zir_index });
451
452 if (struct_obj.field_defaults.len == 0) {
453 // The struct has no default field values, so the slice has been omitted.
454 return;
455 }
456
457 const field_types = struct_obj.field_types.get(ip);
458
459 var block: Block = .{
460 .parent = null,
461 .sema = sema,
462 .namespace = struct_obj.namespace,
463 .instructions = .{},
464 .inlining = null,
465 .comptime_reason = undefined, // always set before using `block`
466 .src_base_inst = struct_obj.zir_index,
467 .type_name_ctx = struct_obj.name,
468 };
469 defer assert(block.instructions.items.len == 0);
470
471 // We'll need to map the struct decl instruction to provide result types
472 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
473
474 const zir_struct = sema.code.getStructDecl(zir_index);
475 var field_it = zir_struct.iterateFields();
476 while (field_it.next()) |zir_field| {
477 const default_val_src: LazySrcLoc = .{
478 .base_node_inst = struct_obj.zir_index,
479 .offset = .{ .container_field_value = zir_field.idx },
480 };
481 block.comptime_reason = .{ .reason = .{
482 .src = default_val_src,
483 .r = .{ .simple = .struct_field_default_value },
484 } };
485 const default_body = zir_field.default_body orelse {
486 struct_obj.field_defaults.get(ip)[zir_field.idx] = .none;
487 continue;
488 };
489 const field_ty: Type = .fromInterned(field_types[zir_field.idx]);
490 const uncoerced = ref: {
491 // Provide the result type
492 sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(field_ty.toIntern()));
493 defer assert(sema.inst_map.remove(zir_index));
494 break :ref try sema.resolveInlineBody(&block, default_body, zir_index);
495 };
496 const coerced = try sema.coerce(&block, field_ty, uncoerced, default_val_src);
497 const default_val = try sema.resolveConstValue(&block, default_val_src, coerced, null);
498 if (default_val.canMutateComptimeVarState(zcu)) {
499 const field_name = struct_obj.field_names.get(ip)[zir_field.idx];
500 return sema.failWithContainsReferenceToComptimeVar(&block, default_val_src, field_name, "field default value", default_val);
501 }
502 struct_obj.field_defaults.get(ip)[zir_field.idx] = default_val.toIntern();
503 }
504}
505
506/// This logic must be kept in sync with `Type.getUnionLayout`.
507pub fn resolveUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
508 const pt = sema.pt;
509 const zcu = pt.zcu;
510 const comp = zcu.comp;
511 const gpa = comp.gpa;
512 const ip = &zcu.intern_pool;
513
514 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());
515
516 const union_obj = ip.loadUnionType(union_ty.toIntern());
517 const zir_index = union_obj.zir_index.resolve(ip).?;
518
519 assert(union_obj.layout != .@"packed");
520
521 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
522
523 var block: Block = .{
524 .parent = null,
525 .sema = sema,
526 .namespace = union_obj.namespace,
527 .instructions = .{},
528 .inlining = null,
529 .comptime_reason = undefined, // always set before using `block`
530 .src_base_inst = union_obj.zir_index,
531 .type_name_ctx = union_obj.name,
532 };
533 defer assert(block.instructions.items.len == 0);
534
535 const zir_union = sema.code.getUnionDecl(zir_index);
536 var field_it = zir_union.iterateFields();
537 while (field_it.next()) |zir_field| {
538 const field_ty_src: LazySrcLoc = .{
539 .base_node_inst = union_obj.zir_index,
540 .offset = .{ .container_field_type = zir_field.idx },
541 };
542 const field_align_src: LazySrcLoc = .{
543 .base_node_inst = union_obj.zir_index,
544 .offset = .{ .container_field_align = zir_field.idx },
545 };
546
547 const field_ty: Type = field_ty: {
548 block.comptime_reason = .{ .reason = .{
549 .src = field_ty_src,
550 .r = .{ .simple = .union_field_types },
551 } };
552 const type_body = zir_field.type_body orelse break :field_ty .void;
553 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);
554 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
555 };
556 assert(!field_ty.isGenericPoison());
557 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
558
559 try sema.ensureLayoutResolved(field_ty);
560
561 const explicit_field_align: Alignment = a: {
562 block.comptime_reason = .{ .reason = .{
563 .src = field_align_src,
564 .r = .{ .simple = .union_field_attrs },
565 } };
566 const align_body = zir_field.align_body orelse break :a .none;
567 const align_ref = try sema.resolveInlineBody(&block, align_body, zir_index);
568 break :a try sema.analyzeAsAlign(&block, field_align_src, align_ref);
569 };
570
571 if (union_obj.field_aligns.len != 0) {
572 union_obj.field_aligns.get(ip)[zir_field.idx] = explicit_field_align;
573 } else {
574 assert(explicit_field_align == .none);
575 }
576
577 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
578 return sema.failWithOwnedErrorMsg(&block, msg: {
579 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
580 errdefer msg.destroy(gpa);
581 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
582 try sema.addDeclaredHereNote(msg, field_ty);
583 break :msg msg;
584 });
585 }
586 if (union_obj.layout == .@"extern" and !try sema.validateExternType(field_ty, .union_field)) {
587 return sema.failWithOwnedErrorMsg(&block, msg: {
588 const msg = try sema.errMsg(field_ty_src, "extern unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
589 errdefer msg.destroy(gpa);
590 try sema.explainWhyTypeIsNotExtern(msg, field_ty_src, field_ty, .union_field);
591 try sema.addDeclaredHereNote(msg, field_ty);
592 break :msg msg;
593 });
594 }
595 }
596
597 try finishUnionLayout(
598 sema,
599 &block,
600 union_ty.srcLoc(zcu),
601 union_ty.toIntern(),
602 &union_obj,
603 .fromInterned(union_obj.enum_tag_type),
604 );
605}
606
607/// Called after populating field types and alignments; populates overall union layout
608/// information (size, alignment, comptime-only state, etc).
609pub fn finishUnionLayout(
610 sema: *Sema,
611 /// Only used to report compile errors.
612 block: *Block,
613 union_src: LazySrcLoc,
614 union_ty: InternPool.Index,
615 union_obj: *const InternPool.LoadedUnionType,
616 enum_tag_ty: Type,
617) SemaError!void {
618 const pt = sema.pt;
619 const zcu = pt.zcu;
620 const comp = zcu.comp;
621 const io = comp.io;
622 const ip = &zcu.intern_pool;
623
624 var payload_align: Alignment = .@"1";
625 var payload_size: u64 = 0;
626 var comptime_only = false;
627 var possible_values: enum { none, one, many } = .none;
628 for (0..union_obj.field_types.len) |field_idx| {
629 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[field_idx]);
630 const field_align: Alignment = a: {
631 if (union_obj.field_aligns.len != 0) {
632 const a = union_obj.field_aligns.get(ip)[field_idx];
633 if (a != .none) break :a a;
634 }
635 break :a field_ty.abiAlignment(zcu);
636 };
637 payload_align = payload_align.maxStrict(field_align);
638 payload_size = @max(payload_size, field_ty.abiSize(zcu));
639 if (field_ty.comptimeOnly(zcu)) comptime_only = true;
640 if (!field_ty.isNoReturn(zcu)) {
641 if (try field_ty.onePossibleValue(pt) != null) {
642 possible_values = .many; // this field alone has many possible values
643 } else switch (possible_values) {
644 .none => possible_values = .one, // there were none, now there is this field's OPV
645 .one => possible_values = .many, // there was one, now there are two
646 .many => {},
647 }
648 }
649 }
650
651 const size: u64, const padding: u64, const alignment: Alignment = layout: {
652 if (union_obj.runtime_tag == .none) {
653 break :layout .{ payload_align.forward(payload_size), 0, payload_align };
654 }
655 const tag_align = enum_tag_ty.abiAlignment(zcu);
656 const tag_size = enum_tag_ty.abiSize(zcu);
657 // The layout will either be (tag, payload, padding) or (payload, tag, padding) depending on
658 // which has larger alignment. So the overall size is just the tag and payload sizes, added,
659 // and padded to the larger alignment.
660 const alignment = tag_align.maxStrict(payload_align);
661 const unpadded_size = tag_size + payload_size;
662 const size = alignment.forward(unpadded_size);
663 break :layout .{ size, size - unpadded_size, alignment };
664 };
665
666 const casted_size = std.math.cast(u32, size) orelse return sema.fail(
667 block,
668 union_src,
669 "union layout requires size {d}, this compiler implementation supports up to {d}",
670 .{ size, std.math.maxInt(u32) },
671 );
672 ip.resolveUnionLayout(
673 io,
674 union_ty,
675 casted_size,
676 @intCast(padding), // okay because padding is no greater than size
677 alignment,
678 possible_values == .none, // MLUGG TODO: make sure queries use `LoadedUnionType.has_no_possible_value`!
679 possible_values == .one,
680 comptime_only,
681 );
682}
683
684pub fn resolvePackedUnionLayout(sema: *Sema, union_ty: Type) CompileError!void {
685 const pt = sema.pt;
686 const zcu = pt.zcu;
687 const comp = zcu.comp;
688 const gpa = comp.gpa;
689 const ip = &zcu.intern_pool;
690
691 assert(sema.owner.unwrap().type_layout == union_ty.toIntern());
692
693 const union_obj = ip.loadUnionType(union_ty.toIntern());
694 const zir_index = union_obj.zir_index.resolve(ip).?;
695
696 assert(union_obj.layout == .@"packed");
697
698 try sema.declareDependency(.{ .src_hash = union_obj.zir_index });
699
700 var block: Block = .{
701 .parent = null,
702 .sema = sema,
703 .namespace = union_obj.namespace,
704 .instructions = .{},
705 .inlining = null,
706 .comptime_reason = undefined, // always set before using `block`
707 .src_base_inst = union_obj.zir_index,
708 .type_name_ctx = union_obj.name,
709 };
710 defer assert(block.instructions.items.len == 0);
711
712 const zir_union = sema.code.getUnionDecl(zir_index);
713 var field_it = zir_union.iterateFields();
714 while (field_it.next()) |zir_field| {
715 const field_ty_src: LazySrcLoc = .{
716 .base_node_inst = union_obj.zir_index,
717 .offset = .{ .container_field_type = zir_field.idx },
718 };
719 const field_ty: Type = field_ty: {
720 block.comptime_reason = .{ .reason = .{
721 .src = field_ty_src,
722 .r = .{ .simple = .union_field_types },
723 } };
724 // MLUGG TODO: i think this should probably be a compile error? (if so, it's an astgen one, right?)
725 const type_body = zir_field.type_body orelse break :field_ty .void;
726 const type_ref = try sema.resolveInlineBody(&block, type_body, zir_index);
727 break :field_ty try sema.analyzeAsType(&block, field_ty_src, type_ref);
728 };
729 assert(!field_ty.isGenericPoison());
730 union_obj.field_types.get(ip)[zir_field.idx] = field_ty.toIntern();
731
732 assert(zir_field.align_body == null); // packed union fields cannot be aligned
733 assert(zir_field.value_body == null); // packed union fields cannot have tag values
734
735 try sema.ensureLayoutResolved(field_ty);
736
737 if (field_ty.zigTypeTag(zcu) == .@"opaque") {
738 return sema.failWithOwnedErrorMsg(&block, msg: {
739 const msg = try sema.errMsg(field_ty_src, "cannot directly embed opaque type '{f}' in union", .{field_ty.fmt(pt)});
740 errdefer msg.destroy(gpa);
741 try sema.errNote(field_ty_src, msg, "opaque types have unknown size", .{});
742 try sema.addDeclaredHereNote(msg, field_ty);
743 break :msg msg;
744 });
745 }
746 if (!field_ty.packable(zcu)) {
747 return sema.failWithOwnedErrorMsg(&block, msg: {
748 const msg = try sema.errMsg(field_ty_src, "packed unions cannot contain fields of type '{f}'", .{field_ty.fmt(pt)});
749 errdefer msg.destroy(gpa);
750 try sema.explainWhyTypeIsNotPackable(msg, field_ty_src, field_ty);
751 try sema.addDeclaredHereNote(msg, field_ty);
752 break :msg msg;
753 });
754 }
755 assert(!field_ty.comptimeOnly(zcu)); // packable types are not comptime-only
756 }
757
758 try resolvePackedUnionBackingInt(sema, &block, union_ty, &union_obj, false);
759}
760
761/// MLUGG TODO doc comment; asserts all fields are resolved or whatever
762pub fn resolvePackedUnionBackingInt(
763 sema: *Sema,
764 block: *Block,
765 union_ty: Type,
766 union_obj: *const InternPool.LoadedUnionType,
767 is_reified: bool,
768) SemaError!void {
769 const pt = sema.pt;
770 const zcu = pt.zcu;
771 const comp = zcu.comp;
772 const gpa = comp.gpa;
773 const io = comp.io;
774 const ip = &zcu.intern_pool;
775 switch (union_obj.packed_backing_mode) {
776 .explicit => {
777 const backing_int_type: Type = .fromInterned(union_obj.packed_backing_int_type);
778 const backing_int_bits = backing_int_type.intInfo(zcu).bits;
779 for (union_obj.field_types.get(ip), 0..) |field_type_ip, field_idx| {
780 const field_type: Type = .fromInterned(field_type_ip);
781 const field_bits = field_type.bitSize(zcu);
782 if (field_bits != backing_int_bits) return sema.failWithOwnedErrorMsg(block, msg: {
783 const field_ty_src: LazySrcLoc = .{
784 .base_node_inst = union_obj.zir_index,
785 .offset = if (is_reified)
786 .nodeOffset(.zero)
787 else
788 .{ .container_field_type = @intCast(field_idx) },
789 };
790 const msg = try sema.errMsg(field_ty_src, "field bit width does not match backing integer", .{});
791 errdefer msg.destroy(gpa);
792 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
793 try sema.errNote(field_ty_src, msg, "backing integer '{f}' has bit width '{d}'", .{ backing_int_type.fmt(pt), backing_int_bits });
794 try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
795 break :msg msg;
796 });
797 }
798 },
799 .auto => switch (union_obj.field_types.len) {
800 0 => ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), .u0_type),
801 else => {
802 const field_types = union_obj.field_types.get(ip);
803 const first_field_type: Type = .fromInterned(field_types[0]);
804 const first_field_bits = first_field_type.bitSize(zcu);
805 for (field_types[1..], 1..) |field_type_ip, field_idx| {
806 const field_type: Type = .fromInterned(field_type_ip);
807 const field_bits = field_type.bitSize(zcu);
808 if (field_bits != first_field_bits) return sema.failWithOwnedErrorMsg(block, msg: {
809 const first_field_ty_src: LazySrcLoc = .{
810 .base_node_inst = union_obj.zir_index,
811 .offset = if (is_reified)
812 .nodeOffset(.zero)
813 else
814 .{ .container_field_type = 0 },
815 };
816 const field_ty_src: LazySrcLoc = .{
817 .base_node_inst = union_obj.zir_index,
818 .offset = if (is_reified)
819 .nodeOffset(.zero)
820 else
821 .{ .container_field_type = @intCast(field_idx) },
822 };
823 const msg = try sema.errMsg(field_ty_src, "field bit width does not match earlier field", .{});
824 errdefer msg.destroy(gpa);
825 try sema.errNote(field_ty_src, msg, "field type '{f}' has bit width '{d}'", .{ field_type.fmt(pt), field_bits });
826 try sema.errNote(first_field_ty_src, msg, "other field type '{f}' has bit width '{d}'", .{ first_field_type.fmt(pt), first_field_bits });
827 try sema.errNote(field_ty_src, msg, "all fields in a packed union must have the same bit width", .{});
828 break :msg msg;
829 });
830 }
831 const backing_int_bits = std.math.cast(u16, first_field_bits) orelse return sema.fail(
832 block,
833 block.nodeOffset(.zero),
834 "packed union bit width '{d}' exceeds maximum bit width of 65535",
835 .{first_field_bits},
836 );
837 const backing_int_type = try pt.intType(.unsigned, backing_int_bits);
838 ip.resolvePackedUnionBackingInt(io, union_ty.toIntern(), backing_int_type.toIntern());
839 },
840 },
841 }
842}
843
844/// Asserts that `enum_ty` is an enum and that `sema.owner` is that type.
845/// This function *does* register the `src_hash` dependency on the enum.
846pub fn resolveEnumValues(sema: *Sema, enum_ty: Type) CompileError!void {
847 const pt = sema.pt;
848 const zcu = pt.zcu;
849 const comp = zcu.comp;
850 const gpa = comp.gpa;
851 const ip = &zcu.intern_pool;
852
853 assert(sema.owner.unwrap().type_inits == enum_ty.toIntern());
854
855 const enum_obj = ip.loadEnumType(enum_ty.toIntern());
856
857 // We'll populate this map.
858 const field_value_map = enum_obj.field_value_map.unwrap() orelse {
859 // The enum has an automatically generated tag and is auto-numbered. We know that we have
860 // generated a suitably large type in `analyzeEnumDecl`, so we have no work to do.
861 return;
862 };
863
864 const maybe_parent_union_obj: ?InternPool.LoadedUnionType = un: {
865 if (enum_obj.owner_union == .none) break :un null;
866 break :un ip.loadUnionType(enum_obj.owner_union);
867 };
868 const tracked_inst = enum_obj.zir_index.unwrap() orelse maybe_parent_union_obj.?.zir_index;
869 const zir_index = tracked_inst.resolve(ip).?;
870
871 try sema.declareDependency(.{ .src_hash = tracked_inst });
872
873 var block: Block = .{
874 .parent = null,
875 .sema = sema,
876 .namespace = enum_obj.namespace,
877 .instructions = .{},
878 .inlining = null,
879 .comptime_reason = undefined, // always set before using `block`
880 .src_base_inst = tracked_inst,
881 .type_name_ctx = enum_obj.name,
882 };
883 defer assert(block.instructions.items.len == 0);
884
885 const int_tag_ty: Type = .fromInterned(enum_obj.int_tag_type);
886
887 // Map the enum (or union) decl instruction to provide the tag type as the result type
888 try sema.inst_map.ensureSpaceForInstructions(gpa, &.{zir_index});
889 sema.inst_map.putAssumeCapacity(zir_index, .fromIntern(int_tag_ty.toIntern()));
890 defer assert(sema.inst_map.remove(zir_index));
891
892 // First, populate any explicitly provided values. This is the part that actually depends on
893 // the ZIR, and hence depends on whether this is a declared or generated enum. If any explicit
894 // value is invalid, we'll emit an error here.
895 if (maybe_parent_union_obj) |union_obj| {
896 const zir_union = sema.code.getUnionDecl(zir_index);
897 var field_it = zir_union.iterateFields();
898 while (field_it.next()) |zir_field| {
899 const field_val_src: LazySrcLoc = .{
900 .base_node_inst = union_obj.zir_index,
901 .offset = .{ .container_field_value = zir_field.idx },
902 };
903 block.comptime_reason = .{ .reason = .{
904 .src = field_val_src,
905 .r = .{ .simple = .enum_field_values },
906 } };
907 const value_body = zir_field.value_body orelse {
908 enum_obj.field_values.get(ip)[zir_field.idx] = .none;
909 continue;
910 };
911 const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
912 const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
913 const val = try sema.resolveConstValue(&block, field_val_src, coerced, null);
914 enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();
915 }
916 } else {
917 const zir_enum = sema.code.getEnumDecl(zir_index);
918 var field_it = zir_enum.iterateFields();
919 while (field_it.next()) |zir_field| {
920 const field_val_src: LazySrcLoc = .{
921 .base_node_inst = enum_obj.zir_index.unwrap().?,
922 .offset = .{ .container_field_value = zir_field.idx },
923 };
924 block.comptime_reason = .{ .reason = .{
925 .src = field_val_src,
926 .r = .{ .simple = .enum_field_values },
927 } };
928 const value_body = zir_field.value_body orelse {
929 enum_obj.field_values.get(ip)[zir_field.idx] = .none;
930 continue;
931 };
932 const uncoerced = try sema.resolveInlineBody(&block, value_body, zir_index);
933 const coerced = try sema.coerce(&block, int_tag_ty, uncoerced, field_val_src);
934 const val = try sema.resolveConstDefinedValue(&block, field_val_src, coerced, null);
935 enum_obj.field_values.get(ip)[zir_field.idx] = val.toIntern();
936 }
937 }
938
939 // Explicit values are set. Now we'll go through the whole array and figure out the final
940 // field values. This is also where we'll detect duplicates.
941
942 for (0..enum_obj.field_names.len) |field_idx| {
943 const field_val_src: LazySrcLoc = .{
944 .base_node_inst = tracked_inst,
945 .offset = .{ .container_field_value = @intCast(field_idx) },
946 };
947 // If the field value was not specified, compute the implicit value.
948 const field_val = val: {
949 const explicit_val = enum_obj.field_values.get(ip)[field_idx];
950 if (explicit_val != .none) break :val explicit_val;
951 if (field_idx == 0) {
952 // Implicit value is 0, which is valid for every integer type.
953 const val = (try pt.intValue(int_tag_ty, 0)).toIntern();
954 enum_obj.field_values.get(ip)[field_idx] = val;
955 break :val val;
956 }
957 // Implicit non-initial value: take the previous field value and add one.
958 const prev_field_val: Value = .fromInterned(enum_obj.field_values.get(ip)[field_idx - 1]);
959 const result = try arith.incrementDefinedInt(sema, int_tag_ty, prev_field_val);
960 if (result.overflow) return sema.fail(
961 &block,
962 field_val_src,
963 "enum tag value '{f}' too large for type '{f}'",
964 .{ result.val.fmtValueSema(pt, sema), int_tag_ty.fmt(pt) },
965 );
966 const val = result.val.toIntern();
967 enum_obj.field_values.get(ip)[field_idx] = val;
968 break :val val;
969 };
970 const adapter: InternPool.Index.Adapter = .{ .indexes = enum_obj.field_values.get(ip)[0..field_idx] };
971 const gop = field_value_map.get(ip).getOrPutAssumeCapacityAdapted(field_val, adapter);
972 if (!gop.found_existing) continue;
973 const prev_field_val_src: LazySrcLoc = .{
974 .base_node_inst = tracked_inst,
975 .offset = .{ .container_field_value = @intCast(gop.index) },
976 };
977 return sema.failWithOwnedErrorMsg(&block, msg: {
978 const msg = try sema.errMsg(field_val_src, "enum tag value '{f}' already taken", .{
979 Value.fromInterned(field_val).fmtValueSema(pt, sema),
980 });
981 errdefer msg.destroy(gpa);
982 try sema.errNote(prev_field_val_src, msg, "previous occurrence here", .{});
983 break :msg msg;
984 });
985 }
986
987 if (enum_obj.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
988 const fields_len = enum_obj.field_names.len;
989 if (fields_len >= 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(zcu)) {
990 return sema.fail(&block, block.nodeOffset(.zero), "non-exhaustive enum specifies every value", .{});
991 }
992 }
993}
src/Type.zig+883-2010
...@@ -12,12 +12,10 @@ const Target = std.Target;...@@ -12,12 +12,10 @@ const Target = std.Target;
12const Zcu = @import("Zcu.zig");12const Zcu = @import("Zcu.zig");
13const log = std.log.scoped(.Type);13const log = std.log.scoped(.Type);
14const target_util = @import("target.zig");14const target_util = @import("target.zig");
15const Sema = @import("Sema.zig");
16const InternPool = @import("InternPool.zig");15const InternPool = @import("InternPool.zig");
17const Alignment = InternPool.Alignment;16const Alignment = InternPool.Alignment;
18const Zir = std.zig.Zir;17const Zir = std.zig.Zir;
19const Type = @This();18const Type = @This();
20const SemaError = Zcu.SemaError;
2119
22ip_index: InternPool.Index,20ip_index: InternPool.Index,
2321
...@@ -25,16 +23,6 @@ pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId {...@@ -25,16 +23,6 @@ pub fn zigTypeTag(ty: Type, zcu: *const Zcu) std.builtin.TypeId {
25 return zcu.intern_pool.zigTypeTag(ty.toIntern());23 return zcu.intern_pool.zigTypeTag(ty.toIntern());
26}24}
2725
28pub fn baseZigTypeTag(self: Type, mod: *Zcu) std.builtin.TypeId {
29 return switch (self.zigTypeTag(mod)) {
30 .error_union => self.errorUnionPayload(mod).baseZigTypeTag(mod),
31 .optional => {
32 return self.optionalChild(mod).baseZigTypeTag(mod);
33 },
34 else => |t| t,
35 };
36}
37
38/// Asserts the type is resolved.26/// Asserts the type is resolved.
39pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {27pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {
40 return switch (ty.zigTypeTag(zcu)) {28 return switch (ty.zigTypeTag(zcu)) {
...@@ -44,7 +32,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {...@@ -44,7 +32,7 @@ pub fn isSelfComparable(ty: Type, zcu: *const Zcu, is_equality_cmp: bool) bool {
44 .comptime_int,32 .comptime_int,
45 => true,33 => true,
4634
47 .vector => ty.elemType2(zcu).isSelfComparable(zcu, is_equality_cmp),35 .vector => ty.childType(zcu).isSelfComparable(zcu, is_equality_cmp),
4836
49 .bool,37 .bool,
50 .type,38 .type,
...@@ -121,11 +109,7 @@ pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool {...@@ -121,11 +109,7 @@ pub fn eql(a: Type, b: Type, zcu: *const Zcu) bool {
121 return a.toIntern() == b.toIntern();109 return a.toIntern() == b.toIntern();
122}110}
123111
124pub fn format(ty: Type, writer: *std.Io.Writer) !void {112pub const format = @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
125 _ = ty;
126 _ = writer;
127 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
128}
129113
130pub const Formatter = std.fmt.Alt(Format, Format.default);114pub const Formatter = std.fmt.Alt(Format, Format.default);
131115
...@@ -440,31 +424,7 @@ pub fn toIntern(ty: Type) InternPool.Index {...@@ -440,31 +424,7 @@ pub fn toIntern(ty: Type) InternPool.Index {
440}424}
441425
442pub fn toValue(self: Type) Value {426pub fn toValue(self: Type) Value {
443 return Value.fromInterned(self.toIntern());427 return .fromInterned(self.toIntern());
444}
445
446const RuntimeBitsError = SemaError || error{NeedLazy};
447
448pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
449 return hasRuntimeBitsInner(ty, false, .eager, zcu, {}) catch unreachable;
450}
451
452pub fn hasRuntimeBitsSema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
453 return hasRuntimeBitsInner(ty, false, .sema, pt.zcu, pt.tid) catch |err| switch (err) {
454 error.NeedLazy => unreachable, // this would require a resolve strat of lazy
455 else => |e| return e,
456 };
457}
458
459pub fn hasRuntimeBitsIgnoreComptime(ty: Type, zcu: *const Zcu) bool {
460 return hasRuntimeBitsInner(ty, true, .eager, zcu, {}) catch unreachable;
461}
462
463pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
464 return hasRuntimeBitsInner(ty, true, .sema, pt.zcu, pt.tid) catch |err| switch (err) {
465 error.NeedLazy => unreachable, // this would require a resolve strat of lazy
466 else => |e| return e,
467 };
468}428}
469429
470/// true if and only if the type takes up space in memory at runtime.430/// true if and only if the type takes up space in memory at runtime.
...@@ -476,205 +436,126 @@ pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!b...@@ -476,205 +436,126 @@ pub fn hasRuntimeBitsIgnoreComptimeSema(ty: Type, pt: Zcu.PerThread) SemaError!b
476/// * the type has only one possible value, making its ABI size 0.436/// * the type has only one possible value, making its ABI size 0.
477/// - an enum with an explicit tag type has the ABI size of the integer tag type,437/// - an enum with an explicit tag type has the ABI size of the integer tag type,
478/// making it one-possible-value only if the integer tag type has 0 bits.438/// making it one-possible-value only if the integer tag type has 0 bits.
479/// When `ignore_comptime_only` is true, then types that are comptime-only439pub fn hasRuntimeBits(ty: Type, zcu: *const Zcu) bool {
480/// may return false positives.
481pub fn hasRuntimeBitsInner(
482 ty: Type,
483 ignore_comptime_only: bool,
484 comptime strat: ResolveStratLazy,
485 zcu: strat.ZcuPtr(),
486 tid: strat.Tid(),
487) RuntimeBitsError!bool {
488 const ip = &zcu.intern_pool;440 const ip = &zcu.intern_pool;
489 const io = zcu.comp.io;441 return switch (ip.indexToKey(ty.toIntern())) {
490 return switch (ty.toIntern()) {442 .int_type => |int_type| int_type.bits != 0,
491 .empty_tuple_type => false,443 .ptr_type => true,
492 else => switch (ip.indexToKey(ty.toIntern())) {444 .anyframe_type => true,
493 .int_type => |int_type| int_type.bits != 0,445 .array_type => |array_type| array_type.lenIncludingSentinel() > 0 and
494 .ptr_type => {446 Type.fromInterned(array_type.child).hasRuntimeBits(zcu),
495 // Pointers to zero-bit types still have a runtime address; however, pointers447 .vector_type => |vector_type| vector_type.len > 0 and
496 // to comptime-only types do not, with the exception of function pointers.448 Type.fromInterned(vector_type.child).hasRuntimeBits(zcu),
497 if (ignore_comptime_only) return true;449 .opt_type => |child| !Type.fromInterned(child).isNoReturn(zcu),
498 return switch (strat) {
499 .sema => {
500 const pt = strat.pt(zcu, tid);
501 return !try ty.comptimeOnlySema(pt);
502 },
503 .eager => !ty.comptimeOnly(zcu),
504 .lazy => error.NeedLazy,
505 };
506 },
507 .anyframe_type => true,
508 .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and
509 try Type.fromInterned(array_type.child).hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid),
510 .vector_type => |vector_type| return vector_type.len > 0 and
511 try Type.fromInterned(vector_type.child).hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid),
512 .opt_type => |child| {
513 const child_ty = Type.fromInterned(child);
514 if (child_ty.isNoReturn(zcu)) {
515 // Then the optional is comptime-known to be null.
516 return false;
517 }
518 if (ignore_comptime_only) return true;
519 return switch (strat) {
520 .sema => !try child_ty.comptimeOnlyInner(.sema, zcu, tid),
521 .eager => !child_ty.comptimeOnly(zcu),
522 .lazy => error.NeedLazy,
523 };
524 },
525 .error_union_type,
526 .error_set_type,
527 .inferred_error_set_type,
528 => true,
529
530 // These are function *bodies*, not pointers.
531 // They return false here because they are comptime-only types.
532 // Special exceptions have to be made when emitting functions due to
533 // this returning false.
534 .func_type => false,
535
536 .simple_type => |t| switch (t) {
537 .f16,
538 .f32,
539 .f64,
540 .f80,
541 .f128,
542 .usize,
543 .isize,
544 .c_char,
545 .c_short,
546 .c_ushort,
547 .c_int,
548 .c_uint,
549 .c_long,
550 .c_ulong,
551 .c_longlong,
552 .c_ulonglong,
553 .c_longdouble,
554 .bool,
555 .anyerror,
556 .adhoc_inferred_error_set,
557 .anyopaque,
558 => true,
559450
560 // These are false because they are comptime-only types.451 .error_union_type,
561 .void,452 .error_set_type,
562 .type,453 .inferred_error_set_type,
563 .comptime_int,454 => true,
564 .comptime_float,
565 .noreturn,
566 .null,
567 .undefined,
568 .enum_literal,
569 => false,
570455
571 .generic_poison => unreachable,456 // These are function *bodies*, not pointers.
572 },457 // They return false here because they are comptime-only types.
573 .struct_type => {458 // Special exceptions have to be made when emitting functions due to
574 const struct_type = ip.loadStructType(ty.toIntern());459 // this returning false.
575 if (strat != .eager and struct_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) {460 .func_type => false,
576 // In this case, we guess that hasRuntimeBits() for this type is true,
577 // and then later if our guess was incorrect, we emit a compile error.
578 return true;
579 }
580 switch (strat) {
581 .sema => try ty.resolveFields(strat.pt(zcu, tid)),
582 .eager => assert(struct_type.haveFieldTypes(ip)),
583 .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
584 }
585 for (0..struct_type.field_types.len) |i| {
586 if (struct_type.comptime_bits.getBit(ip, i)) continue;
587 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
588 if (try field_ty.hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid))
589 return true;
590 } else {
591 return false;
592 }
593 },
594 .tuple_type => |tuple| {
595 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
596 if (val != .none) continue; // comptime field
597 if (try Type.fromInterned(field_ty).hasRuntimeBitsInner(
598 ignore_comptime_only,
599 strat,
600 zcu,
601 tid,
602 )) return true;
603 }
604 return false;
605 },
606461
607 .union_type => {462 .simple_type => |t| switch (t) {
608 const union_type = ip.loadUnionType(ty.toIntern());463 .f16,
609 const union_flags = union_type.flagsUnordered(ip);464 .f32,
610 switch (union_flags.runtime_tag) {465 .f64,
611 .none => if (strat != .eager) {466 .f80,
612 // In this case, we guess that hasRuntimeBits() for this type is true,467 .f128,
613 // and then later if our guess was incorrect, we emit a compile error.468 .usize,
614 if (union_type.assumeRuntimeBitsIfFieldTypesWip(ip, io)) return true;469 .isize,
615 },470 .c_char,
616 .safety, .tagged => {},471 .c_short,
617 }472 .c_ushort,
618 switch (strat) {473 .c_int,
619 .sema => try ty.resolveFields(strat.pt(zcu, tid)),474 .c_uint,
620 .eager => assert(union_flags.status.haveFieldTypes()),475 .c_long,
621 .lazy => if (!union_flags.status.haveFieldTypes())476 .c_ulong,
622 return error.NeedLazy,477 .c_longlong,
623 }478 .c_ulonglong,
624 switch (union_flags.runtime_tag) {479 .c_longdouble,
625 .none => {},480 .bool,
626 .safety, .tagged => {481 .anyerror,
627 const tag_ty = union_type.tagTypeUnordered(ip);482 .adhoc_inferred_error_set,
628 assert(tag_ty != .none); // tag_ty should have been resolved above483 .anyopaque,
629 if (try Type.fromInterned(tag_ty).hasRuntimeBitsInner(484 => true,
630 ignore_comptime_only,
631 strat,
632 zcu,
633 tid,
634 )) {
635 return true;
636 }
637 },
638 }
639 for (0..union_type.field_types.len) |field_index| {
640 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
641 if (try field_ty.hasRuntimeBitsInner(ignore_comptime_only, strat, zcu, tid))
642 return true;
643 } else {
644 return false;
645 }
646 },
647485
648 .opaque_type => true,486 .void,
649 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsInner(487 .noreturn,
650 ignore_comptime_only,488 => false,
651 strat,
652 zcu,
653 tid,
654 ),
655489
656 // values, not types490 // primitive comptime-only types
657 .undef,491 .type,
658 .simple_value,492 .comptime_int,
659 .variable,493 .comptime_float,
660 .@"extern",494 .null,
661 .func,495 .undefined,
662 .int,
663 .err,
664 .error_union,
665 .enum_literal,496 .enum_literal,
666 .enum_tag,497 => false,
667 .empty_enum_value,498
668 .float,499 .generic_poison => unreachable,
669 .ptr,
670 .slice,
671 .opt,
672 .aggregate,
673 .un,
674 // memoization, not types
675 .memoized_call,
676 => unreachable,
677 },500 },
501 .struct_type => {
502 // TODO MLUGG: memoize this state when resolving struct?
503 const struct_obj = ip.loadStructType(ty.toIntern());
504 for (struct_obj.field_types.get(ip), 0..) |field_ty_ip, field_idx| {
505 if (struct_obj.field_is_comptime_bits.get(ip, field_idx)) continue;
506 const field_ty: Type = .fromInterned(field_ty_ip);
507 if (field_ty.hasRuntimeBits(zcu)) return true;
508 }
509 return false;
510 },
511 .tuple_type => |tuple| {
512 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
513 if (val != .none) continue; // comptime field
514 if (Type.fromInterned(field_ty).hasRuntimeBits(zcu)) return true;
515 }
516 return false;
517 },
518 .union_type => {
519 // TODO MLUGG: memoize this state when resolving union?
520 const union_obj = ip.loadUnionType(ty.toIntern());
521 switch (union_obj.runtime_tag) {
522 .none => {},
523 .safety, .tagged => {
524 if (Type.fromInterned(union_obj.enum_tag_type).hasRuntimeBits(zcu)) return true;
525 },
526 }
527 for (union_obj.field_types.get(ip)) |field_ty_ip| {
528 const field_ty: Type = .fromInterned(field_ty_ip);
529 if (field_ty.hasRuntimeBits(zcu)) return true;
530 }
531 return false;
532 },
533
534 // MLUGG TODO: i think this can go away and the assert move to the defer?
535 .opaque_type => true,
536 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).hasRuntimeBits(zcu),
537
538 // values, not types
539 .undef,
540 .simple_value,
541 .variable,
542 .@"extern",
543 .func,
544 .int,
545 .err,
546 .error_union,
547 .enum_literal,
548 .enum_tag,
549 .empty_enum_value,
550 .float,
551 .ptr,
552 .slice,
553 .opt,
554 .aggregate,
555 .un,
556 // memoization, not types
557 .memoized_call,
558 => unreachable,
678 };559 };
679}560}
680561
...@@ -739,16 +620,15 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {...@@ -739,16 +620,15 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
739 },620 },
740 .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto,621 .struct_type => ip.loadStructType(ty.toIntern()).layout != .auto,
741 .union_type => {622 .union_type => {
742 const union_type = ip.loadUnionType(ty.toIntern());623 const union_obj = ip.loadUnionType(ty.toIntern());
743 return switch (union_type.flagsUnordered(ip).runtime_tag) {624 if (union_obj.layout == .auto) return false;
744 .none, .safety => union_type.flagsUnordered(ip).layout != .auto,625 return switch (union_obj.runtime_tag) {
626 .none => true,
745 .tagged => false,627 .tagged => false,
628 .safety => unreachable, // well-defined layout can't have a safety tag
746 };629 };
747 },630 },
748 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {631 .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_is_explicit,
749 .auto => false,
750 .explicit, .nonexhaustive => true,
751 },
752632
753 // values, not types633 // values, not types
754 .undef,634 .undef,
...@@ -774,28 +654,20 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {...@@ -774,28 +654,20 @@ pub fn hasWellDefinedLayout(ty: Type, zcu: *const Zcu) bool {
774 };654 };
775}655}
776656
777pub fn fnHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
778 return ty.fnHasRuntimeBitsInner(.normal, zcu, {}) catch unreachable;
779}
780
781pub fn fnHasRuntimeBitsSema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
782 return try ty.fnHasRuntimeBitsInner(.sema, pt.zcu, pt.tid);
783}
784
785/// Determines whether a function type has runtime bits, i.e. whether a657/// Determines whether a function type has runtime bits, i.e. whether a
786/// function with this type can exist at runtime.658/// function with this type can exist at runtime.
787/// Asserts that `ty` is a function type.659/// Asserts that `ty` is a function type.
788pub fn fnHasRuntimeBitsInner(660pub fn fnHasRuntimeBits(fn_ty: Type, zcu: *Zcu) bool {
789 ty: Type,661 const fn_info = zcu.typeToFunc(fn_ty).?;
790 comptime strat: ResolveStrat,662 if (fn_info.comptime_bits != 0) return false;
791 zcu: strat.ZcuPtr(),663 for (fn_info.param_types.get(&zcu.intern_pool)) |param_ty| {
792 tid: strat.Tid(),664 if (param_ty == .generic_poison_type) return false;
793) SemaError!bool {665 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) return false;
794 const fn_info = zcu.typeToFunc(ty).?;666 }
795 if (fn_info.is_generic) return false;667 if (fn_info.return_type == .generic_poison_type) return false;
796 if (fn_info.is_var_args) return true;668 if (Type.fromInterned(fn_info.return_type).comptimeOnly(zcu)) return false;
797 if (fn_info.cc == .@"inline") return false;669 if (fn_info.cc == .@"inline") return false;
798 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyInner(strat, zcu, tid);670 return true;
799}671}
800672
801pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {673pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
...@@ -806,10 +678,11 @@ pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {...@@ -806,10 +678,11 @@ pub fn isFnOrHasRuntimeBits(ty: Type, zcu: *Zcu) bool {
806}678}
807679
808/// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.680/// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
681/// MLUGG TODO: this function is a bit silly now...
809pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, zcu: *Zcu) bool {682pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, zcu: *Zcu) bool {
810 return switch (ty.zigTypeTag(zcu)) {683 return switch (ty.zigTypeTag(zcu)) {
811 .@"fn" => true,684 .@"fn" => true,
812 else => return ty.hasRuntimeBitsIgnoreComptime(zcu),685 else => return ty.hasRuntimeBits(zcu),
813 };686 };
814}687}
815688
...@@ -818,29 +691,15 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {...@@ -818,29 +691,15 @@ pub fn isNoReturn(ty: Type, zcu: *const Zcu) bool {
818}691}
819692
820/// Never returns `none`. Asserts that all necessary type resolution is already done.693/// Never returns `none`. Asserts that all necessary type resolution is already done.
821pub fn ptrAlignment(ty: Type, zcu: *Zcu) Alignment {694pub fn ptrAlignment(ptr_ty: Type, zcu: *Zcu) Alignment {
822 return ptrAlignmentInner(ty, .normal, zcu, {}) catch unreachable;695 const ip = &zcu.intern_pool;
823}696 const ptr_key: InternPool.Key.PtrType = switch (ip.indexToKey(ptr_ty.toIntern())) {
824697 .ptr_type => |key| key,
825pub fn ptrAlignmentSema(ty: Type, pt: Zcu.PerThread) SemaError!Alignment {698 .opt_type => |child| ip.indexToKey(child).ptr_type,
826 return try ty.ptrAlignmentInner(.sema, pt.zcu, pt.tid);
827}
828
829pub fn ptrAlignmentInner(
830 ty: Type,
831 comptime strat: ResolveStrat,
832 zcu: strat.ZcuPtr(),
833 tid: strat.Tid(),
834) !Alignment {
835 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
836 .ptr_type => |ptr_type| {
837 if (ptr_type.flags.alignment != .none) return ptr_type.flags.alignment;
838 const res = try Type.fromInterned(ptr_type.child).abiAlignmentInner(strat.toLazy(), zcu, tid);
839 return res.scalar;
840 },
841 .opt_type => |child| Type.fromInterned(child).ptrAlignmentInner(strat, zcu, tid),
842 else => unreachable,699 else => unreachable,
843 };700 };
701 if (ptr_key.flags.alignment != .none) return ptr_key.flags.alignment;
702 return Type.fromInterned(ptr_key.child).abiAlignment(zcu);
844}703}
845704
846pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {705pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
...@@ -851,861 +710,347 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {...@@ -851,861 +710,347 @@ pub fn ptrAddressSpace(ty: Type, zcu: *const Zcu) std.builtin.AddressSpace {
851 };710 };
852}711}
853712
854/// May capture a reference to `ty`.
855/// Returned value has type `comptime_int`.
856pub fn lazyAbiAlignment(ty: Type, pt: Zcu.PerThread) !Value {
857 switch (try ty.abiAlignmentInner(.lazy, pt.zcu, pt.tid)) {
858 .val => |val| return val,
859 .scalar => |x| return pt.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
860 }
861}
862
863pub const AbiAlignmentInner = union(enum) {
864 scalar: Alignment,
865 val: Value,
866};
867
868pub const ResolveStratLazy = enum {
869 /// Return a `lazy_size` or `lazy_align` value if necessary.
870 /// This value can be resolved later using `Value.resolveLazy`.
871 lazy,
872 /// Return a scalar result, expecting all necessary type resolution to be completed.
873 /// Backends should typically use this, since they must not perform type resolution.
874 eager,
875 /// Return a scalar result, performing type resolution as necessary.
876 /// This should typically be used from semantic analysis.
877 sema,
878
879 pub fn Tid(strat: ResolveStratLazy) type {
880 return switch (strat) {
881 .lazy, .sema => Zcu.PerThread.Id,
882 .eager => void,
883 };
884 }
885
886 pub fn ZcuPtr(strat: ResolveStratLazy) type {
887 return switch (strat) {
888 .eager => *const Zcu,
889 .sema, .lazy => *Zcu,
890 };
891 }
892
893 pub fn pt(
894 comptime strat: ResolveStratLazy,
895 zcu: strat.ZcuPtr(),
896 tid: strat.Tid(),
897 ) switch (strat) {
898 .lazy, .sema => Zcu.PerThread,
899 .eager => void,
900 } {
901 return switch (strat) {
902 .lazy, .sema => .{ .tid = tid, .zcu = zcu },
903 else => {},
904 };
905 }
906};
907
908/// The chosen strategy can be easily optimized away in release builds.
909/// However, in debug builds, it helps to avoid accidentally resolving types in backends.
910pub const ResolveStrat = enum {
911 /// Assert that all necessary resolution is completed.
912 /// Backends should typically use this, since they must not perform type resolution.
913 normal,
914 /// Perform type resolution as necessary using `Zcu`.
915 /// This should typically be used from semantic analysis.
916 sema,
917
918 pub fn Tid(strat: ResolveStrat) type {
919 return switch (strat) {
920 .sema => Zcu.PerThread.Id,
921 .normal => void,
922 };
923 }
924
925 pub fn ZcuPtr(strat: ResolveStrat) type {
926 return switch (strat) {
927 .normal => *const Zcu,
928 .sema => *Zcu,
929 };
930 }
931
932 pub fn pt(comptime strat: ResolveStrat, zcu: strat.ZcuPtr(), tid: strat.Tid()) switch (strat) {
933 .sema => Zcu.PerThread,
934 .normal => void,
935 } {
936 return switch (strat) {
937 .sema => .{ .tid = tid, .zcu = zcu },
938 .normal => {},
939 };
940 }
941
942 pub inline fn toLazy(strat: ResolveStrat) ResolveStratLazy {
943 return switch (strat) {
944 .normal => .eager,
945 .sema => .sema,
946 };
947 }
948};
949
950/// Never returns `none`. Asserts that all necessary type resolution is already done.713/// Never returns `none`. Asserts that all necessary type resolution is already done.
714/// MLUGG TODO: check that it really does never return `.none`
951pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {715pub fn abiAlignment(ty: Type, zcu: *const Zcu) Alignment {
952 return (ty.abiAlignmentInner(.eager, zcu, {}) catch unreachable).scalar;
953}
954
955pub fn abiAlignmentSema(ty: Type, pt: Zcu.PerThread) SemaError!Alignment {
956 return (try ty.abiAlignmentInner(.sema, pt.zcu, pt.tid)).scalar;
957}
958
959/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
960/// In this case there will be no error, guaranteed.
961/// If you pass `lazy` you may get back `scalar` or `val`.
962/// If `val` is returned, a reference to `ty` has been captured.
963/// If you pass `sema` you will get back `scalar` and resolve the type if
964/// necessary, possibly returning a CompileError.
965pub fn abiAlignmentInner(
966 ty: Type,
967 comptime strat: ResolveStratLazy,
968 zcu: strat.ZcuPtr(),
969 tid: strat.Tid(),
970) SemaError!AbiAlignmentInner {
971 const pt = strat.pt(zcu, tid);
972 const target = zcu.getTarget();
973 const ip = &zcu.intern_pool;716 const ip = &zcu.intern_pool;
974717 const target = zcu.getTarget();
975 switch (ty.toIntern()) {718 assertHasLayout(ty, zcu);
976 .empty_tuple_type => return .{ .scalar = .@"1" },719 return switch (ip.indexToKey(ty.toIntern())) {
977 else => switch (ip.indexToKey(ty.toIntern())) {720 .int_type => |int_type| {
978 .int_type => |int_type| {721 if (int_type.bits == 0) return .@"1";
979 if (int_type.bits == 0) return .{ .scalar = .@"1" };722 return .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits));
980 return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, int_type.bits)) };723 },
981 },724 .ptr_type, .anyframe_type => ptrAbiAlignment(target),
982 .ptr_type, .anyframe_type => {725 .array_type => |array_type| Type.fromInterned(array_type.child).abiAlignment(zcu),
983 return .{ .scalar = ptrAbiAlignment(target) };726 .vector_type => |vector_type| {
984 },727 if (vector_type.len == 0) return .@"1";
985 .array_type => |array_type| {728 switch (zcu.comp.getZigBackend()) {
986 return Type.fromInterned(array_type.child).abiAlignmentInner(strat, zcu, tid);729 else => {
987 },730 const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu));
988 .vector_type => |vector_type| {731 if (elem_bits == 0) return .@"1";
989 if (vector_type.len == 0) return .{ .scalar = .@"1" };732 const bytes = ((elem_bits * vector_type.len) + 7) / 8;
990 switch (zcu.comp.getZigBackend()) {733 return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes));
991 else => {
992 // This is fine because the child type of a vector always has a bit-size known
993 // without needing any type resolution.
994 const elem_bits: u32 = @intCast(Type.fromInterned(vector_type.child).bitSize(zcu));
995 if (elem_bits == 0) return .{ .scalar = .@"1" };
996 const bytes = ((elem_bits * vector_type.len) + 7) / 8;
997 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
998 return .{ .scalar = Alignment.fromByteUnits(alignment) };
999 },
1000 .stage2_c => {
1001 return Type.fromInterned(vector_type.child).abiAlignmentInner(strat, zcu, tid);
1002 },
1003 .stage2_x86_64 => {
1004 if (vector_type.child == .bool_type) {
1005 if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .{ .scalar = .@"64" };
1006 if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .{ .scalar = .@"32" };
1007 if (vector_type.len > 64) return .{ .scalar = .@"16" };
1008 const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
1009 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
1010 return .{ .scalar = Alignment.fromByteUnits(alignment) };
1011 }
1012 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar);
1013 if (elem_bytes == 0) return .{ .scalar = .@"1" };
1014 const bytes = elem_bytes * vector_type.len;
1015 if (bytes > 32 and target.cpu.has(.x86, .avx512f)) return .{ .scalar = .@"64" };
1016 if (bytes > 16 and target.cpu.has(.x86, .avx)) return .{ .scalar = .@"32" };
1017 return .{ .scalar = .@"16" };
1018 },
1019 }
1020 },
1021
1022 .opt_type => return ty.abiAlignmentInnerOptional(strat, zcu, tid),
1023 .error_union_type => |info| return ty.abiAlignmentInnerErrorUnion(
1024 strat,
1025 zcu,
1026 tid,
1027 Type.fromInterned(info.payload_type),
1028 ),
1029
1030 .error_set_type, .inferred_error_set_type => {
1031 const bits = zcu.errorSetBits();
1032 if (bits == 0) return .{ .scalar = .@"1" };
1033 return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, bits)) };
1034 },
1035
1036 // represents machine code; not a pointer
1037 .func_type => return .{ .scalar = target_util.minFunctionAlignment(target) },
1038
1039 .simple_type => |t| switch (t) {
1040 .bool,
1041 .anyopaque,
1042 => return .{ .scalar = .@"1" },
1043
1044 .usize,
1045 .isize,
1046 => return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())) },
1047
1048 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
1049 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
1050 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
1051 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
1052 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
1053 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
1054 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
1055 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
1056 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
1057 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
1058
1059 .f16 => return .{ .scalar = .@"2" },
1060 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
1061 .f64 => switch (target.cTypeBitSize(.double)) {
1062 64 => return .{ .scalar = cTypeAlign(target, .double) },
1063 else => return .{ .scalar = .@"8" },
1064 },
1065 .f80 => switch (target.cTypeBitSize(.longdouble)) {
1066 80 => return .{ .scalar = cTypeAlign(target, .longdouble) },
1067 else => return .{ .scalar = Type.u80.abiAlignment(zcu) },
1068 },
1069 .f128 => switch (target.cTypeBitSize(.longdouble)) {
1070 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
1071 else => return .{ .scalar = .@"16" },
1072 },734 },
1073735 .stage2_c => return Type.fromInterned(vector_type.child).abiAlignment(zcu),
1074 .anyerror, .adhoc_inferred_error_set => {736 .stage2_x86_64 => {
1075 const bits = zcu.errorSetBits();737 if (vector_type.child == .bool_type) {
1076 if (bits == 0) return .{ .scalar = .@"1" };738 if (vector_type.len > 256 and target.cpu.has(.x86, .avx512f)) return .@"64";
1077 return .{ .scalar = .fromByteUnits(std.zig.target.intAlignment(target, bits)) };739 if (vector_type.len > 128 and target.cpu.has(.x86, .avx)) return .@"32";
740 if (vector_type.len > 64) return .@"16";
741 const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
742 return .fromByteUnits(std.math.ceilPowerOfTwoAssert(u32, bytes));
743 }
744 const elem_bytes: u32 = @intCast(Type.fromInterned(vector_type.child).abiSize(zcu));
745 if (elem_bytes == 0) return .@"1";
746 const bytes = elem_bytes * vector_type.len;
747 if (bytes > 32 and target.cpu.has(.x86, .avx512f)) return .@"64";
748 if (bytes > 16 and target.cpu.has(.x86, .avx)) return .@"32";
749 return .@"16";
1078 },750 },
751 }
752 },
1079753
1080 .void,754 .opt_type => |child| Type.fromInterned(child).abiAlignment(zcu),
1081 .type,755 .error_union_type => |eu| Alignment.maxStrict(
1082 .comptime_int,756 Type.fromInterned(eu.payload_type).abiAlignment(zcu),
1083 .comptime_float,757 errorAbiAlignment(zcu),
1084 .null,758 ),
1085 .undefined,
1086 .enum_literal,
1087 => return .{ .scalar = .@"1" },
1088759
1089 .noreturn => unreachable,760 .error_set_type, .inferred_error_set_type => errorAbiAlignment(zcu),
1090 .generic_poison => unreachable,
1091 },
1092 .struct_type => {
1093 const struct_type = ip.loadStructType(ty.toIntern());
1094 if (struct_type.layout == .@"packed") {
1095 switch (strat) {
1096 .sema => try ty.resolveLayout(pt),
1097 .lazy => if (struct_type.backingIntTypeUnordered(ip) == .none) return .{
1098 .val = Value.fromInterned(try pt.intern(.{ .int = .{
1099 .ty = .comptime_int_type,
1100 .storage = .{ .lazy_align = ty.toIntern() },
1101 } })),
1102 },
1103 .eager => {},
1104 }
1105 return .{ .scalar = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)).abiAlignment(zcu) };
1106 }
1107761
1108 if (struct_type.flagsUnordered(ip).alignment == .none) switch (strat) {762 .func_type => target_util.minFunctionAlignment(target),
1109 .eager => unreachable, // struct alignment not resolved
1110 .sema => try ty.resolveStructAlignment(pt),
1111 .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1112 .ty = .comptime_int_type,
1113 .storage = .{ .lazy_align = ty.toIntern() },
1114 } })) },
1115 };
1116763
1117 return .{ .scalar = struct_type.flagsUnordered(ip).alignment };764 .simple_type => |t| switch (t) {
1118 },765 .bool,
1119 .tuple_type => |tuple| {766 .void,
1120 var big_align: Alignment = .@"1";767 .noreturn,
1121 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {768 .anyopaque,
1122 if (val != .none) continue; // comptime field769 .type,
1123 switch (try Type.fromInterned(field_ty).abiAlignmentInner(strat, zcu, tid)) {770 .comptime_int,
1124 .scalar => |field_align| big_align = big_align.max(field_align),771 .comptime_float,
1125 .val => switch (strat) {772 .null,
1126 .eager => unreachable, // field type alignment not resolved773 .undefined,
1127 .sema => unreachable, // passed to abiAlignmentInner above774 .enum_literal,
1128 .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{775 => .@"1",
1129 .ty = .comptime_int_type,776
1130 .storage = .{ .lazy_align = ty.toIntern() },777 .anyerror, .adhoc_inferred_error_set => errorAbiAlignment(zcu),
1131 } })) },778 .usize, .isize => .fromByteUnits(std.zig.target.intAlignment(target, target.ptrBitWidth())),
1132 },779
1133 }780 .c_char => cTypeAlign(target, .char),
1134 }781 .c_short => cTypeAlign(target, .short),
1135 return .{ .scalar = big_align };782 .c_ushort => cTypeAlign(target, .ushort),
783 .c_int => cTypeAlign(target, .int),
784 .c_uint => cTypeAlign(target, .uint),
785 .c_long => cTypeAlign(target, .long),
786 .c_ulong => cTypeAlign(target, .ulong),
787 .c_longlong => cTypeAlign(target, .longlong),
788 .c_ulonglong => cTypeAlign(target, .ulonglong),
789 .c_longdouble => cTypeAlign(target, .longdouble),
790
791 .f16 => .@"2",
792 .f32 => cTypeAlign(target, .float),
793 .f64 => switch (target.cTypeBitSize(.double)) {
794 64 => cTypeAlign(target, .double),
795 else => .@"8",
1136 },796 },
1137 .union_type => {797 .f80 => switch (target.cTypeBitSize(.longdouble)) {
1138 const union_type = ip.loadUnionType(ty.toIntern());798 80 => cTypeAlign(target, .longdouble),
1139799 else => Type.u80.abiAlignment(zcu),
1140 if (union_type.flagsUnordered(ip).alignment == .none) switch (strat) {
1141 .eager => unreachable, // union layout not resolved
1142 .sema => try ty.resolveUnionAlignment(pt),
1143 .lazy => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1144 .ty = .comptime_int_type,
1145 .storage = .{ .lazy_align = ty.toIntern() },
1146 } })) },
1147 };
1148
1149 return .{ .scalar = union_type.flagsUnordered(ip).alignment };
1150 },800 },
1151 .opaque_type => return .{ .scalar = .@"1" },801 .f128 => switch (target.cTypeBitSize(.longdouble)) {
1152 .enum_type => return .{802 128 => cTypeAlign(target, .longdouble),
1153 .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(zcu),803 else => .@"16",
1154 },804 },
1155805
1156 // values, not types806 .generic_poison => unreachable,
1157 .undef,
1158 .simple_value,
1159 .variable,
1160 .@"extern",
1161 .func,
1162 .int,
1163 .err,
1164 .error_union,
1165 .enum_literal,
1166 .enum_tag,
1167 .empty_enum_value,
1168 .float,
1169 .ptr,
1170 .slice,
1171 .opt,
1172 .aggregate,
1173 .un,
1174 // memoization, not types
1175 .memoized_call,
1176 => unreachable,
1177 },807 },
1178 }808 .tuple_type => |tuple| {
1179}809 var big_align: Alignment = .@"1";
1180810 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
1181fn abiAlignmentInnerErrorUnion(811 if (val != .none) continue; // comptime field
1182 ty: Type,812 const field_align = Type.fromInterned(field_ty).abiAlignment(zcu);
1183 comptime strat: ResolveStratLazy,813 big_align = big_align.max(field_align);
1184 zcu: strat.ZcuPtr(),
1185 tid: strat.Tid(),
1186 payload_ty: Type,
1187) SemaError!AbiAlignmentInner {
1188 // This code needs to be kept in sync with the equivalent switch prong
1189 // in abiSizeInner.
1190 const code_align = Type.anyerror.abiAlignment(zcu);
1191 switch (strat) {
1192 .eager, .sema => {
1193 if (!(payload_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
1194 error.NeedLazy => if (strat == .lazy) {
1195 const pt = strat.pt(zcu, tid);
1196 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1197 .ty = .comptime_int_type,
1198 .storage = .{ .lazy_align = ty.toIntern() },
1199 } })) };
1200 } else unreachable,
1201 else => |e| return e,
1202 })) {
1203 return .{ .scalar = code_align };
1204 }814 }
1205 return .{ .scalar = code_align.max(815 return big_align;
1206 (try payload_ty.abiAlignmentInner(strat, zcu, tid)).scalar,
1207 ) };
1208 },816 },
1209 .lazy => {817 .struct_type => {
1210 const pt = strat.pt(zcu, tid);818 const struct_obj = ip.loadStructType(ty.toIntern());
1211 switch (try payload_ty.abiAlignmentInner(strat, zcu, tid)) {819 switch (struct_obj.layout) {
1212 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },820 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiAlignment(zcu),
1213 .val => {},821 .auto, .@"extern" => return struct_obj.alignment,
1214 }822 }
1215 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1216 .ty = .comptime_int_type,
1217 .storage = .{ .lazy_align = ty.toIntern() },
1218 } })) };
1219 },823 },
1220 }824 .union_type => {
1221}825 const union_obj = ip.loadUnionType(ty.toIntern());
1222826 switch (union_obj.layout) {
1223fn abiAlignmentInnerOptional(827 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiAlignment(zcu),
1224 ty: Type,828 .auto, .@"extern" => return getUnionLayout(union_obj, zcu).abi_align,
1225 comptime strat: ResolveStratLazy,
1226 zcu: strat.ZcuPtr(),
1227 tid: strat.Tid(),
1228) SemaError!AbiAlignmentInner {
1229 const pt = strat.pt(zcu, tid);
1230 const target = zcu.getTarget();
1231 const child_type = ty.optionalChild(zcu);
1232
1233 switch (child_type.zigTypeTag(zcu)) {
1234 .pointer => return .{ .scalar = ptrAbiAlignment(target) },
1235 .error_set => return Type.anyerror.abiAlignmentInner(strat, zcu, tid),
1236 .noreturn => return .{ .scalar = .@"1" },
1237 else => {},
1238 }
1239
1240 switch (strat) {
1241 .eager, .sema => {
1242 if (!(child_type.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
1243 error.NeedLazy => if (strat == .lazy) {
1244 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1245 .ty = .comptime_int_type,
1246 .storage = .{ .lazy_align = ty.toIntern() },
1247 } })) };
1248 } else unreachable,
1249 else => |e| return e,
1250 })) {
1251 return .{ .scalar = .@"1" };
1252 }829 }
1253 return child_type.abiAlignmentInner(strat, zcu, tid);
1254 },
1255 .lazy => switch (try child_type.abiAlignmentInner(strat, zcu, tid)) {
1256 .scalar => |x| return .{ .scalar = x.max(.@"1") },
1257 .val => return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1258 .ty = .comptime_int_type,
1259 .storage = .{ .lazy_align = ty.toIntern() },
1260 } })) },
1261 },830 },
1262 }831 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiAlignment(zcu),
1263}832 .opaque_type => .@"1",
1264
1265const AbiSizeInner = union(enum) {
1266 scalar: u64,
1267 val: Value,
1268};
1269
1270/// Asserts the type has the ABI size already resolved.
1271/// Types that return false for hasRuntimeBits() return 0.
1272pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
1273 return (abiSizeInner(ty, .eager, zcu, {}) catch unreachable).scalar;
1274}
1275
1276/// May capture a reference to `ty`.
1277pub fn abiSizeLazy(ty: Type, pt: Zcu.PerThread) !Value {
1278 switch (try ty.abiSizeInner(.lazy, pt.zcu, pt.tid)) {
1279 .val => |val| return val,
1280 .scalar => |x| return pt.intValue(Type.comptime_int, x),
1281 }
1282}
1283833
1284pub fn abiSizeSema(ty: Type, pt: Zcu.PerThread) SemaError!u64 {834 // values, not types
1285 return (try abiSizeInner(ty, .sema, pt.zcu, pt.tid)).scalar;835 .undef,
836 .simple_value,
837 .variable,
838 .@"extern",
839 .func,
840 .int,
841 .err,
842 .error_union,
843 .enum_literal,
844 .enum_tag,
845 .empty_enum_value,
846 .float,
847 .ptr,
848 .slice,
849 .opt,
850 .aggregate,
851 .un,
852 // memoization, not types
853 .memoized_call,
854 => unreachable,
855 };
1286}856}
1287857
1288/// If you pass `eager` you will get back `scalar` and assert the type is resolved.858/// Asserts that `ty` is not an opaque type.
1289/// In this case there will be no error, guaranteed.859pub fn abiSize(ty: Type, zcu: *const Zcu) u64 {
1290/// If you pass `lazy` you may get back `scalar` or `val`.
1291/// If `val` is returned, a reference to `ty` has been captured.
1292/// If you pass `sema` you will get back `scalar` and resolve the type if
1293/// necessary, possibly returning a CompileError.
1294pub fn abiSizeInner(
1295 ty: Type,
1296 comptime strat: ResolveStratLazy,
1297 zcu: strat.ZcuPtr(),
1298 tid: strat.Tid(),
1299) SemaError!AbiSizeInner {
1300 const target = zcu.getTarget();
1301 const ip = &zcu.intern_pool;860 const ip = &zcu.intern_pool;
1302861 const target = zcu.getTarget();
1303 switch (ty.toIntern()) {862 assertHasLayout(ty, zcu);
1304 .empty_tuple_type => return .{ .scalar = 0 },863 return switch (ip.indexToKey(ty.toIntern())) {
1305864 .int_type => |int_type| std.zig.target.intByteSize(target, int_type.bits),
1306 else => switch (ip.indexToKey(ty.toIntern())) {865 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1307 .int_type => |int_type| {866 .slice => ptrAbiSize(target) * 2,
1308 if (int_type.bits == 0) return .{ .scalar = 0 };867 .one, .many, .c => ptrAbiSize(target),
1309 return .{ .scalar = std.zig.target.intByteSize(target, int_type.bits) };868 },
1310 },869 .anyframe_type => ptrAbiSize(target),
1311 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {870 .array_type => |arr| arr.lenIncludingSentinel() * Type.fromInterned(arr.child).abiSize(zcu),
1312 .slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },871 .vector_type => |vec| {
1313 else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },872 const elem_ty: Type = .fromInterned(vec.child);
1314 },873 const bytes = switch (zcu.comp.getZigBackend()) {
1315 .anyframe_type => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },874 else => std.math.divCeil(u64, vec.len * elem_ty.bitSize(zcu), 8) catch unreachable,
1316875 .stage2_c => vec.len * elem_ty.abiSize(zcu),
1317 .array_type => |array_type| {876 .stage2_x86_64 => switch (elem_ty.toIntern()) {
1318 const len = array_type.lenIncludingSentinel();877 .bool_type => std.math.divCeil(u64, vec.len, 8) catch unreachable,
1319 if (len == 0) return .{ .scalar = 0 };878 else => vec.len * elem_ty.abiSize(zcu),
1320 switch (try Type.fromInterned(array_type.child).abiSizeInner(strat, zcu, tid)) {
1321 .scalar => |elem_size| return .{ .scalar = len * elem_size },
1322 .val => switch (strat) {
1323 .sema, .eager => unreachable,
1324 .lazy => {
1325 const pt = strat.pt(zcu, tid);
1326 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1327 .ty = .comptime_int_type,
1328 .storage = .{ .lazy_size = ty.toIntern() },
1329 } })) };
1330 },
1331 },
1332 }
1333 },
1334 .vector_type => |vector_type| {
1335 const sub_strat: ResolveStrat = switch (strat) {
1336 .sema => .sema,
1337 .eager => .normal,
1338 .lazy => {
1339 const pt = strat.pt(zcu, tid);
1340 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1341 .ty = .comptime_int_type,
1342 .storage = .{ .lazy_size = ty.toIntern() },
1343 } })) };
1344 },
1345 };
1346 const alignment = (try ty.abiAlignmentInner(strat, zcu, tid)).scalar;
1347 const total_bytes = switch (zcu.comp.getZigBackend()) {
1348 else => total_bytes: {
1349 const elem_bits = try Type.fromInterned(vector_type.child).bitSizeInner(sub_strat, zcu, tid);
1350 const total_bits = elem_bits * vector_type.len;
1351 break :total_bytes (total_bits + 7) / 8;
1352 },
1353 .stage2_c => total_bytes: {
1354 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar);
1355 break :total_bytes elem_bytes * vector_type.len;
1356 },
1357 .stage2_x86_64 => total_bytes: {
1358 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
1359 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeInner(strat, zcu, tid)).scalar);
1360 break :total_bytes elem_bytes * vector_type.len;
1361 },
1362 };
1363 return .{ .scalar = alignment.forward(total_bytes) };
1364 },
1365
1366 .opt_type => return ty.abiSizeInnerOptional(strat, zcu, tid),
1367
1368 .error_set_type, .inferred_error_set_type => {
1369 const bits = zcu.errorSetBits();
1370 if (bits == 0) return .{ .scalar = 0 };
1371 return .{ .scalar = std.zig.target.intByteSize(target, bits) };
1372 },
1373
1374 .error_union_type => |error_union_type| {
1375 const payload_ty = Type.fromInterned(error_union_type.payload_type);
1376 // This code needs to be kept in sync with the equivalent switch prong
1377 // in abiAlignmentInner.
1378 const code_size = Type.anyerror.abiSize(zcu);
1379 if (!(payload_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
1380 error.NeedLazy => if (strat == .lazy) {
1381 const pt = strat.pt(zcu, tid);
1382 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1383 .ty = .comptime_int_type,
1384 .storage = .{ .lazy_size = ty.toIntern() },
1385 } })) };
1386 } else unreachable,
1387 else => |e| return e,
1388 })) {
1389 // Same as anyerror.
1390 return .{ .scalar = code_size };
1391 }
1392 const code_align = Type.anyerror.abiAlignment(zcu);
1393 const payload_align = (try payload_ty.abiAlignmentInner(strat, zcu, tid)).scalar;
1394 const payload_size = switch (try payload_ty.abiSizeInner(strat, zcu, tid)) {
1395 .scalar => |elem_size| elem_size,
1396 .val => switch (strat) {
1397 .sema => unreachable,
1398 .eager => unreachable,
1399 .lazy => {
1400 const pt = strat.pt(zcu, tid);
1401 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1402 .ty = .comptime_int_type,
1403 .storage = .{ .lazy_size = ty.toIntern() },
1404 } })) };
1405 },
1406 },
1407 };
1408
1409 var size: u64 = 0;
1410 if (code_align.compare(.gt, payload_align)) {
1411 size += code_size;
1412 size = payload_align.forward(size);
1413 size += payload_size;
1414 size = code_align.forward(size);
1415 } else {
1416 size += payload_size;
1417 size = code_align.forward(size);
1418 size += code_size;
1419 size = payload_align.forward(size);
1420 }
1421 return .{ .scalar = size };
1422 },
1423 .func_type => unreachable, // represents machine code; not a pointer
1424 .simple_type => |t| switch (t) {
1425 .bool => return .{ .scalar = 1 },
1426
1427 .f16 => return .{ .scalar = 2 },
1428 .f32 => return .{ .scalar = 4 },
1429 .f64 => return .{ .scalar = 8 },
1430 .f128 => return .{ .scalar = 16 },
1431 .f80 => switch (target.cTypeBitSize(.longdouble)) {
1432 80 => return .{ .scalar = target.cTypeByteSize(.longdouble) },
1433 else => return .{ .scalar = Type.u80.abiSize(zcu) },
1434 },
1435
1436 .usize,
1437 .isize,
1438 => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1439
1440 .c_char => return .{ .scalar = target.cTypeByteSize(.char) },
1441 .c_short => return .{ .scalar = target.cTypeByteSize(.short) },
1442 .c_ushort => return .{ .scalar = target.cTypeByteSize(.ushort) },
1443 .c_int => return .{ .scalar = target.cTypeByteSize(.int) },
1444 .c_uint => return .{ .scalar = target.cTypeByteSize(.uint) },
1445 .c_long => return .{ .scalar = target.cTypeByteSize(.long) },
1446 .c_ulong => return .{ .scalar = target.cTypeByteSize(.ulong) },
1447 .c_longlong => return .{ .scalar = target.cTypeByteSize(.longlong) },
1448 .c_ulonglong => return .{ .scalar = target.cTypeByteSize(.ulonglong) },
1449 .c_longdouble => return .{ .scalar = target.cTypeByteSize(.longdouble) },
1450
1451 .anyopaque,
1452 .void,
1453 .type,
1454 .comptime_int,
1455 .comptime_float,
1456 .null,
1457 .undefined,
1458 .enum_literal,
1459 => return .{ .scalar = 0 },
1460
1461 .anyerror, .adhoc_inferred_error_set => {
1462 const bits = zcu.errorSetBits();
1463 if (bits == 0) return .{ .scalar = 0 };
1464 return .{ .scalar = std.zig.target.intByteSize(target, bits) };
1465 },879 },
1466880 };
1467 .noreturn => unreachable,881 return ty.abiAlignment(zcu).forward(bytes);
1468 .generic_poison => unreachable,882 },
1469 },883 .opt_type => |child_ty_ip| {
1470 .struct_type => {884 const child_ty: Type = .fromInterned(child_ty_ip);
1471 const struct_type = ip.loadStructType(ty.toIntern());885 if (child_ty.isNoReturn(zcu)) return 0;
1472 switch (strat) {886 const child_size = child_ty.abiSize(zcu);
1473 .sema => try ty.resolveLayout(strat.pt(zcu, tid)),887 if (ty.optionalReprIsPayload(zcu)) return child_size;
1474 .lazy => {888 // Optional types are represented as a struct with the child type as the first
1475 const pt = strat.pt(zcu, tid);889 // field and a boolean as the second. Since the child type's abi alignment is
1476 switch (struct_type.layout) {890 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1477 .@"packed" => {891 // to the child type's ABI alignment.
1478 if (struct_type.backingIntTypeUnordered(ip) == .none) return .{892 return child_size + child_ty.abiAlignment(zcu).toByteUnits().?;
1479 .val = Value.fromInterned(try pt.intern(.{ .int = .{893 },
1480 .ty = .comptime_int_type,894 .error_set_type, .inferred_error_set_type => errorAbiSize(zcu),
1481 .storage = .{ .lazy_size = ty.toIntern() },895 .error_union_type => |error_union| {
1482 } })),896 const payload_ty: Type = .fromInterned(error_union.payload_type);
1483 };897 // This code needs to be kept in sync with the equivalent switch prong
1484 },898 // in abiAlignmentInner.
1485 .auto, .@"extern" => {899 const code_size = errorAbiSize(zcu);
1486 if (!struct_type.haveLayout(ip)) return .{900 const code_align = errorAbiAlignment(zcu);
1487 .val = Value.fromInterned(try pt.intern(.{ .int = .{901 const payload_size = payload_ty.abiSize(zcu);
1488 .ty = .comptime_int_type,902 const payload_align = payload_ty.abiAlignment(zcu);
1489 .storage = .{ .lazy_size = ty.toIntern() },903 // The layout will either be (code, payload, padding) or (payload, code, padding)
1490 } })),904 // depending on which has larger alignment. So the overall size is just the code
1491 };905 // and payload sizes added and padded to the larger alignment.
1492 },906 const big_align = code_align.maxStrict(payload_align);
1493 }907 return big_align.forward(payload_size + code_size);
1494 },908 },
1495 .eager => {},909 .func_type => 0,
1496 }910 .simple_type => |t| switch (t) {
1497 switch (struct_type.layout) {911 .void,
1498 .@"packed" => return .{912 .noreturn,
1499 .scalar = Type.fromInterned(struct_type.backingIntTypeUnordered(ip)).abiSize(zcu),913 .type,
1500 },914 .comptime_int,
1501 .auto, .@"extern" => {915 .comptime_float,
1502 assert(struct_type.haveLayout(ip));916 .null,
1503 return .{ .scalar = struct_type.sizeUnordered(ip) };917 .undefined,
1504 },918 .enum_literal,
1505 }919 => 0,
1506 },920
1507 .tuple_type => |tuple| {921 .bool => 1,
1508 switch (strat) {922 .anyerror, .adhoc_inferred_error_set => errorAbiSize(zcu),
1509 .sema => try ty.resolveLayout(strat.pt(zcu, tid)),923 .usize, .isize => ptrAbiSize(target),
1510 .lazy, .eager => {},924
1511 }925 .c_char => target.cTypeByteSize(.char),
1512 const field_count = tuple.types.len;926 .c_short => target.cTypeByteSize(.short),
1513 if (field_count == 0) {927 .c_ushort => target.cTypeByteSize(.ushort),
1514 return .{ .scalar = 0 };928 .c_int => target.cTypeByteSize(.int),
1515 }929 .c_uint => target.cTypeByteSize(.uint),
1516 return .{ .scalar = ty.structFieldOffset(field_count, zcu) };930 .c_long => target.cTypeByteSize(.long),
1517 },931 .c_ulong => target.cTypeByteSize(.ulong),
1518932 .c_longlong => target.cTypeByteSize(.longlong),
1519 .union_type => {933 .c_ulonglong => target.cTypeByteSize(.ulonglong),
1520 const union_type = ip.loadUnionType(ty.toIntern());934 .c_longdouble => target.cTypeByteSize(.longdouble),
1521 switch (strat) {935
1522 .sema => try ty.resolveLayout(strat.pt(zcu, tid)),936 .f16 => 2,
1523 .lazy => {937 .f32 => 4,
1524 const pt = strat.pt(zcu, tid);938 .f64 => 8,
1525 if (!union_type.flagsUnordered(ip).status.haveLayout()) return .{939 .f80 => switch (target.cTypeBitSize(.longdouble)) {
1526 .val = Value.fromInterned(try pt.intern(.{ .int = .{940 80 => target.cTypeByteSize(.longdouble),
1527 .ty = .comptime_int_type,941 else => Type.u80.abiSize(zcu),
1528 .storage = .{ .lazy_size = ty.toIntern() },
1529 } })),
1530 };
1531 },
1532 .eager => {},
1533 }
1534
1535 assert(union_type.haveLayout(ip));
1536 return .{ .scalar = union_type.sizeUnordered(ip) };
1537 },942 },
1538 .opaque_type => unreachable, // no size available943 .f128 => 16,
1539 .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(zcu) },
1540944
1541 // values, not types945 .anyopaque => unreachable,
1542 .undef,946 .generic_poison => unreachable,
1543 .simple_value,
1544 .variable,
1545 .@"extern",
1546 .func,
1547 .int,
1548 .err,
1549 .error_union,
1550 .enum_literal,
1551 .enum_tag,
1552 .empty_enum_value,
1553 .float,
1554 .ptr,
1555 .slice,
1556 .opt,
1557 .aggregate,
1558 .un,
1559 // memoization, not types
1560 .memoized_call,
1561 => unreachable,
1562 },947 },
1563 }948 .tuple_type => |tuple| ty.structFieldOffset(tuple.types.len, zcu),
1564}949 .struct_type => {
1565950 const struct_obj = ip.loadStructType(ty.toIntern());
1566fn abiSizeInnerOptional(951 switch (struct_obj.layout) {
1567 ty: Type,952 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).abiSize(zcu),
1568 comptime strat: ResolveStratLazy,953 .auto, .@"extern" => return struct_obj.size,
1569 zcu: strat.ZcuPtr(),954 }
1570 tid: strat.Tid(),
1571) SemaError!AbiSizeInner {
1572 const child_ty = ty.optionalChild(zcu);
1573
1574 if (child_ty.isNoReturn(zcu)) {
1575 return .{ .scalar = 0 };
1576 }
1577
1578 if (!(child_ty.hasRuntimeBitsInner(false, strat, zcu, tid) catch |err| switch (err) {
1579 error.NeedLazy => if (strat == .lazy) {
1580 const pt = strat.pt(zcu, tid);
1581 return .{ .val = Value.fromInterned(try pt.intern(.{ .int = .{
1582 .ty = .comptime_int_type,
1583 .storage = .{ .lazy_size = ty.toIntern() },
1584 } })) };
1585 } else unreachable,
1586 else => |e| return e,
1587 })) return .{ .scalar = 1 };
1588
1589 if (ty.optionalReprIsPayload(zcu)) {
1590 return child_ty.abiSizeInner(strat, zcu, tid);
1591 }
1592
1593 const payload_size = switch (try child_ty.abiSizeInner(strat, zcu, tid)) {
1594 .scalar => |elem_size| elem_size,
1595 .val => switch (strat) {
1596 .sema => unreachable,
1597 .eager => unreachable,
1598 .lazy => return .{ .val = Value.fromInterned(try strat.pt(zcu, tid).intern(.{ .int = .{
1599 .ty = .comptime_int_type,
1600 .storage = .{ .lazy_size = ty.toIntern() },
1601 } })) },
1602 },955 },
1603 };956 .union_type => {
957 const union_obj = ip.loadUnionType(ty.toIntern());
958 switch (union_obj.layout) {
959 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).abiSize(zcu),
960 .auto, .@"extern" => return union_obj.size,
961 }
962 },
963 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).abiSize(zcu),
964 .opaque_type => unreachable,
1604965
1605 // Optional types are represented as a struct with the child type as the first966 // values, not types
1606 // field and a boolean as the second. Since the child type's abi alignment is967 .undef,
1607 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal968 .simple_value,
1608 // to the child type's ABI alignment.969 .variable,
1609 return .{970 .@"extern",
1610 .scalar = (child_ty.abiAlignment(zcu).toByteUnits() orelse 0) + payload_size,971 .func,
972 .int,
973 .err,
974 .error_union,
975 .enum_literal,
976 .enum_tag,
977 .empty_enum_value,
978 .float,
979 .ptr,
980 .slice,
981 .opt,
982 .aggregate,
983 .un,
984 // memoization, not types
985 .memoized_call,
986 => unreachable,
1611 };987 };
1612}988}
1613989
1614pub fn ptrAbiAlignment(target: *const Target) Alignment {990pub fn ptrAbiAlignment(target: *const Target) Alignment {
1615 return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));991 return .fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
1616}992}
1617993pub fn ptrAbiSize(target: *const Target) u64 {
1618pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {994 return @divExact(target.ptrBitWidth(), 8);
1619 return bitSizeInner(ty, .normal, zcu, {}) catch unreachable;
1620}995}
1621996pub fn errorAbiAlignment(zcu: *const Zcu) Alignment {
1622pub fn bitSizeSema(ty: Type, pt: Zcu.PerThread) SemaError!u64 {997 return .fromNonzeroByteUnits(std.zig.target.intAlignment(zcu.getTarget(), zcu.errorSetBits()));
1623 return bitSizeInner(ty, .sema, pt.zcu, pt.tid);998}
999pub fn errorAbiSize(zcu: *const Zcu) u64 {
1000 return std.zig.target.intByteSize(zcu.getTarget(), zcu.errorSetBits());
1624}1001}
16251002
1626pub fn bitSizeInner(1003/// Asserts that `ty` is not an opaque or comptime-only type.
1627 ty: Type,1004/// Once #19755 is implemented, this query will only work on types with a defined bit-level representation.
1628 comptime strat: ResolveStrat,1005pub fn bitSize(ty: Type, zcu: *const Zcu) u64 {
1629 zcu: strat.ZcuPtr(),
1630 tid: strat.Tid(),
1631) SemaError!u64 {
1632 const target = zcu.getTarget();1006 const target = zcu.getTarget();
1633 const ip = &zcu.intern_pool;1007 const ip = &zcu.intern_pool;
16341008 assertHasLayout(ty, zcu);
1635 const strat_lazy: ResolveStratLazy = strat.toLazy();1009 return switch (ip.indexToKey(ty.toIntern())) {
16361010 .int_type => |int_type| int_type.bits,
1637 switch (ip.indexToKey(ty.toIntern())) {
1638 .int_type => |int_type| return int_type.bits,
1639 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {1011 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1640 .slice => return target.ptrBitWidth() * 2,1012 .slice => target.ptrBitWidth() * 2,
1641 else => return target.ptrBitWidth(),1013 else => target.ptrBitWidth(),
1642 },1014 },
1643 .anyframe_type => return target.ptrBitWidth(),1015 .anyframe_type => target.ptrBitWidth(),
1644
1645 .array_type => |array_type| {1016 .array_type => |array_type| {
1646 const len = array_type.lenIncludingSentinel();
1647 if (len == 0) return 0;
1648 const elem_ty: Type = .fromInterned(array_type.child);1017 const elem_ty: Type = .fromInterned(array_type.child);
1649 switch (zcu.comp.getZigBackend()) {1018 const len = array_type.lenIncludingSentinel();
1650 else => {1019 return switch (zcu.comp.getZigBackend()) {
1651 const elem_size = (try elem_ty.abiSizeInner(strat_lazy, zcu, tid)).scalar;1020 .stage2_x86_64 => len * elem_ty.bitSize(zcu),
1652 if (elem_size == 0) return 0;1021 // this case will be removed under #19755
1653 const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);1022 else => switch (len) {
1654 return (len - 1) * 8 * elem_size + elem_bit_size;1023 0 => 0,
1655 },1024 else => (len - 1) * 8 * elem_ty.abiSize(zcu) + elem_ty.bitSize(zcu),
1656 .stage2_x86_64 => {
1657 const elem_bit_size = try elem_ty.bitSizeInner(strat, zcu, tid);
1658 return elem_bit_size * len;
1659 },1025 },
1660 }1026 };
1661 },
1662 .vector_type => |vector_type| {
1663 const child_ty: Type = .fromInterned(vector_type.child);
1664 const elem_bit_size = try child_ty.bitSizeInner(strat, zcu, tid);
1665 return elem_bit_size * vector_type.len;
1666 },
1667 .opt_type => {
1668 // Optionals and error unions are not packed so their bitsize
1669 // includes padding bits.
1670 return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
1671 },1027 },
1028 .vector_type => |vec| vec.len * Type.fromInterned(vec.child).bitSize(zcu),
1029 .error_set_type, .inferred_error_set_type => zcu.errorSetBits(),
1030 .func_type => unreachable,
16721031
1673 .error_set_type, .inferred_error_set_type => return zcu.errorSetBits(),
1674
1675 .error_union_type => {
1676 // Optionals and error unions are not packed so their bitsize
1677 // includes padding bits.
1678 return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
1679 },
1680 .func_type => unreachable, // represents machine code; not a pointer
1681 .simple_type => |t| switch (t) {1032 .simple_type => |t| switch (t) {
1682 .f16 => return 16,1033 .void => 0,
1683 .f32 => return 32,1034 .bool => 1,
1684 .f64 => return 64,1035 .anyerror, .adhoc_inferred_error_set => zcu.errorSetBits(),
1685 .f80 => return 80,1036 .usize, .isize => target.ptrBitWidth(),
1686 .f128 => return 128,1037
16871038 .c_char => target.cTypeBitSize(.char),
1688 .usize,1039 .c_short => target.cTypeBitSize(.short),
1689 .isize,1040 .c_ushort => target.cTypeBitSize(.ushort),
1690 => return target.ptrBitWidth(),1041 .c_int => target.cTypeBitSize(.int),
16911042 .c_uint => target.cTypeBitSize(.uint),
1692 .c_char => return target.cTypeBitSize(.char),1043 .c_long => target.cTypeBitSize(.long),
1693 .c_short => return target.cTypeBitSize(.short),1044 .c_ulong => target.cTypeBitSize(.ulong),
1694 .c_ushort => return target.cTypeBitSize(.ushort),1045 .c_longlong => target.cTypeBitSize(.longlong),
1695 .c_int => return target.cTypeBitSize(.int),1046 .c_ulonglong => target.cTypeBitSize(.ulonglong),
1696 .c_uint => return target.cTypeBitSize(.uint),1047 .c_longdouble => target.cTypeBitSize(.longdouble),
1697 .c_long => return target.cTypeBitSize(.long),1048
1698 .c_ulong => return target.cTypeBitSize(.ulong),1049 .f16 => 16,
1699 .c_longlong => return target.cTypeBitSize(.longlong),1050 .f32 => 32,
1700 .c_ulonglong => return target.cTypeBitSize(.ulonglong),1051 .f64 => 64,
1701 .c_longdouble => return target.cTypeBitSize(.longdouble),1052 .f80 => 80,
17021053 .f128 => 128,
1703 .bool => return 1,
1704 .void => return 0,
1705
1706 .anyerror,
1707 .adhoc_inferred_error_set,
1708 => return zcu.errorSetBits(),
17091054
1710 .anyopaque => unreachable,1055 .anyopaque => unreachable,
1711 .type => unreachable,1056 .type => unreachable,
...@@ -1717,49 +1062,30 @@ pub fn bitSizeInner(...@@ -1717,49 +1062,30 @@ pub fn bitSizeInner(
1717 .enum_literal => unreachable,1062 .enum_literal => unreachable,
1718 .generic_poison => unreachable,1063 .generic_poison => unreachable,
1719 },1064 },
1065
1720 .struct_type => {1066 .struct_type => {
1721 const struct_type = ip.loadStructType(ty.toIntern());1067 const struct_obj = ip.loadStructType(ty.toIntern());
1722 const is_packed = struct_type.layout == .@"packed";1068 switch (struct_obj.layout) {
1723 if (strat == .sema) {1069 .@"packed" => return Type.fromInterned(struct_obj.packed_backing_int_type).bitSize(zcu),
1724 const pt = strat.pt(zcu, tid);1070 .auto, .@"extern" => return struct_obj.size * 8, // will be `unreachable` under #19755
1725 try ty.resolveFields(pt);
1726 if (is_packed) try ty.resolveLayout(pt);
1727 }
1728 if (is_packed) {
1729 return try Type.fromInterned(struct_type.backingIntTypeUnordered(ip))
1730 .bitSizeInner(strat, zcu, tid);
1731 }1071 }
1732 return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
1733 },
1734
1735 .tuple_type => {
1736 return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
1737 },1072 },
1738
1739 .union_type => {1073 .union_type => {
1740 const union_type = ip.loadUnionType(ty.toIntern());1074 const union_obj = ip.loadUnionType(ty.toIntern());
1741 const is_packed = ty.containerLayout(zcu) == .@"packed";1075 switch (union_obj.layout) {
1742 if (strat == .sema) {1076 .@"packed" => return Type.fromInterned(union_obj.packed_backing_int_type).bitSize(zcu),
1743 const pt = strat.pt(zcu, tid);1077 .auto, .@"extern" => return union_obj.size * 8, // will be `unreachable` under #19755
1744 try ty.resolveFields(pt);
1745 if (is_packed) try ty.resolveLayout(pt);
1746 }
1747 if (!is_packed) {
1748 return (try ty.abiSizeInner(strat_lazy, zcu, tid)).scalar * 8;
1749 }1078 }
1750 assert(union_type.flagsUnordered(ip).status.haveFieldTypes());1079 },
1080 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).bitSize(zcu),
17511081
1752 var size: u64 = 0;1082 // will be `unreachable` under #19755
1753 for (0..union_type.field_types.len) |field_index| {1083 .opt_type,
1754 const field_ty = union_type.field_types.get(ip)[field_index];1084 .error_union_type,
1755 size = @max(size, try Type.fromInterned(field_ty).bitSizeInner(strat, zcu, tid));1085 .tuple_type,
1756 }1086 => ty.abiSize(zcu) * 8,
17571087
1758 return size;
1759 },
1760 .opaque_type => unreachable,1088 .opaque_type => unreachable,
1761 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty)
1762 .bitSizeInner(strat, zcu, tid),
17631089
1764 // values, not types1090 // values, not types
1765 .undef,1091 .undef,
...@@ -1782,23 +1108,6 @@ pub fn bitSizeInner(...@@ -1782,23 +1108,6 @@ pub fn bitSizeInner(
1782 // memoization, not types1108 // memoization, not types
1783 .memoized_call,1109 .memoized_call,
1784 => unreachable,1110 => unreachable,
1785 }
1786}
1787
1788/// Returns true if the type's layout is already resolved and it is safe
1789/// to use `abiSize`, `abiAlignment` and `bitSize` on it.
1790pub fn layoutIsResolved(ty: Type, zcu: *const Zcu) bool {
1791 const ip = &zcu.intern_pool;
1792 return switch (ip.indexToKey(ty.toIntern())) {
1793 .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
1794 .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
1795 .array_type => |array_type| {
1796 if (array_type.lenIncludingSentinel() == 0) return true;
1797 return Type.fromInterned(array_type.child).layoutIsResolved(zcu);
1798 },
1799 .opt_type => |child| Type.fromInterned(child).layoutIsResolved(zcu),
1800 .error_union_type => |k| Type.fromInterned(k.payload_type).layoutIsResolved(zcu),
1801 else => true,
1802 };1111 };
1803}1112}
18041113
...@@ -1841,7 +1150,7 @@ pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool {...@@ -1841,7 +1150,7 @@ pub fn isSliceAtRuntime(ty: Type, zcu: *const Zcu) bool {
1841}1150}
18421151
1843pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {1152pub fn slicePtrFieldType(ty: Type, zcu: *const Zcu) Type {
1844 return Type.fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern()));1153 return .fromInterned(zcu.intern_pool.slicePtrType(ty.toIntern()));
1845}1154}
18461155
1847pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool {1156pub fn isConstPtr(ty: Type, zcu: *const Zcu) bool {
...@@ -1897,10 +1206,7 @@ pub fn isPtrAtRuntime(ty: Type, zcu: *const Zcu) bool {...@@ -1897,10 +1206,7 @@ pub fn isPtrAtRuntime(ty: Type, zcu: *const Zcu) bool {
1897/// For pointer-like optionals, returns true, otherwise returns the allowzero property1206/// For pointer-like optionals, returns true, otherwise returns the allowzero property
1898/// of pointers.1207/// of pointers.
1899pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool {1208pub fn ptrAllowsZero(ty: Type, zcu: *const Zcu) bool {
1900 if (ty.isPtrLikeOptional(zcu)) {1209 return ty.isPtrLikeOptional(zcu) or ty.ptrInfo(zcu).flags.is_allowzero;
1901 return true;
1902 }
1903 return ty.ptrInfo(zcu).flags.is_allowzero;
1904}1210}
19051211
1906/// See also `isPtrLikeOptional`.1212/// See also `isPtrLikeOptional`.
...@@ -1918,7 +1224,6 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {...@@ -1918,7 +1224,6 @@ pub fn optionalReprIsPayload(ty: Type, zcu: *const Zcu) bool {
19181224
1919/// Returns true if the type is optional and would be lowered to a single pointer1225/// Returns true if the type is optional and would be lowered to a single pointer
1920/// address value, using 0 for null. Note that this returns true for C pointers.1226/// address value, using 0 for null. Note that this returns true for C pointers.
1921/// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`.
1922pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool {1227pub fn isPtrLikeOptional(ty: Type, zcu: *const Zcu) bool {
1923 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1228 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
1924 .ptr_type => |ptr_type| ptr_type.flags.size == .c,1229 .ptr_type => |ptr_type| ptr_type.flags.size == .c,
...@@ -1947,52 +1252,75 @@ pub fn childTypeIp(ty: Type, ip: *const InternPool) Type {...@@ -1947,52 +1252,75 @@ pub fn childTypeIp(ty: Type, ip: *const InternPool) Type {
1947 return Type.fromInterned(ip.childType(ty.toIntern()));1252 return Type.fromInterned(ip.childType(ty.toIntern()));
1948}1253}
19491254
1950/// For `*[N]T`, returns `T`.1255/// Similar to `childType`, but for pointer-like (or slice-like) optionals, gets the child type
1951/// For `?*T`, returns `T`.1256/// of the *pointer* type. Asserts that `ty` is either a pointer or a pointer-like optional.
1952/// For `?*[N]T`, returns `T`.1257///
1953/// For `?[*]T`, returns `T`.1258/// Essentially, unwraps any one of the following into `T`:
1954/// For `*T`, returns `T`.1259/// ```
1955/// For `[*]T`, returns `T`.1260/// *T ?*T *allowzero T
1956/// For `[N]T`, returns `T`.1261/// [*]T ?[*]T [*]allowzero T
1957/// For `[]T`, returns `T`.1262/// []T ?[]T []allowzero T
1958/// For `anyframe->T`, returns `T`.1263/// [*c]T
1959pub fn elemType2(ty: Type, zcu: *const Zcu) Type {1264/// ```
1960 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1265/// This is primarily useful in Sema to implement operations which can act on optional pointers.
1961 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {1266pub fn nullablePtrElem(ty: Type, zcu: *const Zcu) Type {
1962 .one => Type.fromInterned(ptr_type.child).shallowElemType(zcu),1267 switch (ty.zigTypeTag(zcu)) {
1963 .many, .c, .slice => Type.fromInterned(ptr_type.child),1268 .pointer => return ty.childType(zcu),
1964 },1269 .optional => {
1965 .anyframe_type => |child| {1270 const ptr_ty = ty.childType(zcu);
1966 assert(child != .none);1271 const ptr_info = zcu.intern_pool.indexToKey(ptr_ty.toIntern()).ptr_type;
1967 return Type.fromInterned(child);1272 assert(ptr_info.flags.size != .c);
1273 assert(!ptr_info.flags.is_allowzero);
1274 return .fromInterned(ptr_info.child);
1968 },1275 },
1969 .vector_type => |vector_type| Type.fromInterned(vector_type.child),
1970 .array_type => |array_type| Type.fromInterned(array_type.child),
1971 .opt_type => |child| Type.fromInterned(zcu.intern_pool.childType(child)),
1972 else => unreachable,1276 else => unreachable,
1973 };1277 }
1974}1278}
19751279
1976/// Given that `ty` is an indexable pointer, returns its element type. Specifically:1280/// Given that `ty` is an indexable pointer, returns its element type. Specifically:
1977/// * for `*[n]T`, returns `T`1281/// * for `*[n]T`, returns `T`
1282/// * for `*@Vector(n, T)`, returns `T`
1978/// * for `[]T`, returns `T`1283/// * for `[]T`, returns `T`
1979/// * for `[*]T`, returns `T`1284/// * for `[*]T`, returns `T`
1980/// * for `[*c]T`, returns `T`1285/// * for `[*c]T`, returns `T`
1286///
1287/// Tuples are not supported because they do not have a single element type.
1288///
1289/// MLUGG TODO: should i even have this one? it's a subset of indexableElem
1981pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type {1290pub fn indexablePtrElem(ty: Type, zcu: *const Zcu) Type {
1982 const ip = &zcu.intern_pool;1291 const ip = &zcu.intern_pool;
1983 const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type;1292 const ptr_type = ip.indexToKey(ty.toIntern()).ptr_type;
1984 switch (ptr_type.flags.size) {1293 return switch (ptr_type.flags.size) {
1985 .many, .slice, .c => return .fromInterned(ptr_type.child),1294 .many, .slice, .c => return .fromInterned(ptr_type.child),
1986 .one => {},1295 .one => switch (ip.indexToKey(ptr_type.child)) {
1987 }1296 inline .array_type, .vector_type => |arr| return .fromInterned(arr.child),
1988 const array_type = ip.indexToKey(ptr_type.child).array_type;1297 else => unreachable,
1989 return .fromInterned(array_type.child);1298 },
1299 };
1990}1300}
19911301
1992fn shallowElemType(child_ty: Type, zcu: *const Zcu) Type {1302/// Given that `ty` is an indexable type, returns its element type. Specifically:
1993 return switch (child_ty.zigTypeTag(zcu)) {1303/// * for `[n]T`, returns `T`
1994 .array, .vector => child_ty.childType(zcu),1304/// * for `@Vector(n, T)`, returns `T`
1995 else => child_ty,1305/// * for `*[n]T`, returns `T`
1306/// * for `*@Vector(n, T)`, returns `T`
1307/// * for `[]T`, returns `T`
1308/// * for `[*]T`, returns `T`
1309/// * for `[*c]T`, returns `T`
1310///
1311/// Tuples are not supported because they do not have a single element type.
1312pub fn indexableElem(ty: Type, zcu: *const Zcu) Type {
1313 const ip = &zcu.intern_pool;
1314 return switch (ip.indexToKey(ty.toIntern())) {
1315 inline .array_type, .vector_type => |arr| .fromInterned(arr.child),
1316 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1317 .many, .slice, .c => .fromInterned(ptr_type.child),
1318 .one => switch (ip.indexToKey(ptr_type.child)) {
1319 inline .array_type, .vector_type => |arr| .fromInterned(arr.child),
1320 else => unreachable,
1321 },
1322 },
1323 else => unreachable,
1996 };1324 };
1997}1325}
19981326
...@@ -2004,17 +1332,17 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type {...@@ -2004,17 +1332,17 @@ pub fn scalarType(ty: Type, zcu: *const Zcu) Type {
2004 };1332 };
2005}1333}
20061334
2007/// Asserts that the type is an optional.1335/// Asserts that the type is an optional, or a C pointer.
2008/// Note that for C pointers this returns the type unmodified.1336/// For C pointers this returns the type unmodified.
2009pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {1337pub fn optionalChild(ty: Type, zcu: *const Zcu) Type {
2010 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) {1338 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
2011 .opt_type => |child| Type.fromInterned(child),1339 .opt_type => |child| return .fromInterned(child),
2012 .ptr_type => |ptr_type| b: {1340 .ptr_type => |ptr_type| {
2013 assert(ptr_type.flags.size == .c);1341 assert(ptr_type.flags.size == .c);
2014 break :b ty;1342 return ty;
2015 },1343 },
2016 else => unreachable,1344 else => unreachable,
2017 };1345 }
2018}1346}
20191347
2020/// Returns the tag type of a union, if the type is a union and it has a tag type.1348/// Returns the tag type of a union, if the type is a union and it has a tag type.
...@@ -2025,15 +1353,11 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {...@@ -2025,15 +1353,11 @@ pub fn unionTagType(ty: Type, zcu: *const Zcu) ?Type {
2025 .union_type => {},1353 .union_type => {},
2026 else => return null,1354 else => return null,
2027 }1355 }
2028 const union_type = ip.loadUnionType(ty.toIntern());1356 const union_obj = ip.loadUnionType(ty.toIntern());
2029 const union_flags = union_type.flagsUnordered(ip);1357 return switch (union_obj.runtime_tag) {
2030 switch (union_flags.runtime_tag) {1358 .tagged => .fromInterned(union_obj.enum_tag_type),
2031 .tagged => {1359 .none, .safety => null,
2032 assert(union_flags.status.haveFieldTypes());1360 };
2033 return Type.fromInterned(union_type.enum_tag_ty);
2034 },
2035 else => return null,
2036 }
2037}1361}
20381362
2039/// Same as `unionTagType` but includes safety tag.1363/// Same as `unionTagType` but includes safety tag.
...@@ -2043,9 +1367,8 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {...@@ -2043,9 +1367,8 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
2043 return switch (ip.indexToKey(ty.toIntern())) {1367 return switch (ip.indexToKey(ty.toIntern())) {
2044 .union_type => {1368 .union_type => {
2045 const union_type = ip.loadUnionType(ty.toIntern());1369 const union_type = ip.loadUnionType(ty.toIntern());
2046 if (!union_type.hasTag(ip)) return null;1370 if (union_type.runtime_tag == .none) return null;
2047 assert(union_type.haveFieldTypes(ip));1371 return Type.fromInterned(union_type.enum_tag_type);
2048 return Type.fromInterned(union_type.enum_tag_ty);
2049 },1372 },
2050 else => null,1373 else => null,
2051 };1374 };
...@@ -2055,7 +1378,7 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {...@@ -2055,7 +1378,7 @@ pub fn unionTagTypeSafety(ty: Type, zcu: *const Zcu) ?Type {
2055/// not be stored at runtime.1378/// not be stored at runtime.
2056pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {1379pub fn unionTagTypeHypothetical(ty: Type, zcu: *const Zcu) Type {
2057 const union_obj = zcu.typeToUnion(ty).?;1380 const union_obj = zcu.typeToUnion(ty).?;
2058 return Type.fromInterned(union_obj.enum_tag_ty);1381 return Type.fromInterned(union_obj.enum_tag_type);
2059}1382}
20601383
2061pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {1384pub fn unionFieldType(ty: Type, enum_tag: Value, zcu: *const Zcu) ?Type {
...@@ -2105,9 +1428,9 @@ pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {...@@ -2105,9 +1428,9 @@ pub fn unionGetLayout(ty: Type, zcu: *const Zcu) Zcu.UnionLayout {
2105pub fn containerLayout(ty: Type, zcu: *const Zcu) std.builtin.Type.ContainerLayout {1428pub fn containerLayout(ty: Type, zcu: *const Zcu) std.builtin.Type.ContainerLayout {
2106 const ip = &zcu.intern_pool;1429 const ip = &zcu.intern_pool;
2107 return switch (ip.indexToKey(ty.toIntern())) {1430 return switch (ip.indexToKey(ty.toIntern())) {
2108 .struct_type => ip.loadStructType(ty.toIntern()).layout,
2109 .tuple_type => .auto,1431 .tuple_type => .auto,
2110 .union_type => ip.loadUnionType(ty.toIntern()).flagsUnordered(ip).layout,1432 .struct_type => ip.loadStructType(ty.toIntern()).layout,
1433 .union_type => ip.loadUnionType(ty.toIntern()).layout,
2111 else => unreachable,1434 else => unreachable,
2112 };1435 };
2113}1436}
...@@ -2182,33 +1505,6 @@ pub fn errorSetHasFieldIp(...@@ -2182,33 +1505,6 @@ pub fn errorSetHasFieldIp(
2182 };1505 };
2183}1506}
21841507
2185/// Returns whether ty, which must be an error set, includes an error `name`.
2186/// Might return a false negative if `ty` is an inferred error set and not fully
2187/// resolved yet.
2188pub fn errorSetHasField(ty: Type, name: []const u8, zcu: *const Zcu) bool {
2189 const ip = &zcu.intern_pool;
2190 return switch (ty.toIntern()) {
2191 .anyerror_type => true,
2192 else => switch (ip.indexToKey(ty.toIntern())) {
2193 .error_set_type => |error_set_type| {
2194 // If the string is not interned, then the field certainly is not present.
2195 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2196 return error_set_type.nameIndex(ip, field_name_interned) != null;
2197 },
2198 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) {
2199 .anyerror_type => true,
2200 .none => false,
2201 else => |t| {
2202 // If the string is not interned, then the field certainly is not present.
2203 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2204 return ip.indexToKey(t).error_set_type.nameIndex(ip, field_name_interned) != null;
2205 },
2206 },
2207 else => unreachable,
2208 },
2209 };
2210}
2211
2212/// Asserts the type is an array or vector or struct.1508/// Asserts the type is an array or vector or struct.
2213pub fn arrayLen(ty: Type, zcu: *const Zcu) u64 {1509pub fn arrayLen(ty: Type, zcu: *const Zcu) u64 {
2214 return ty.arrayLenIp(&zcu.intern_pool);1510 return ty.arrayLenIp(&zcu.intern_pool);
...@@ -2308,8 +1604,12 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {...@@ -2308,8 +1604,12 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
2308 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) },1604 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong) },
2309 else => switch (ip.indexToKey(ty.toIntern())) {1605 else => switch (ip.indexToKey(ty.toIntern())) {
2310 .int_type => |int_type| return int_type,1606 .int_type => |int_type| return int_type,
2311 .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntTypeUnordered(ip)),1607 .struct_type => {
2312 .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),1608 const struct_obj = ip.loadStructType(ty.toIntern());
1609 assert(struct_obj.layout == .@"packed");
1610 ty = .fromInterned(struct_obj.packed_backing_int_type);
1611 },
1612 .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type),
2313 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),1613 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
23141614
2315 .error_set_type, .inferred_error_set_type => {1615 .error_set_type, .inferred_error_set_type => {
...@@ -2355,25 +1655,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {...@@ -2355,25 +1655,6 @@ pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType {
2355 };1655 };
2356}1656}
23571657
2358pub fn isNamedInt(ty: Type) bool {
2359 return switch (ty.toIntern()) {
2360 .usize_type,
2361 .isize_type,
2362 .c_char_type,
2363 .c_short_type,
2364 .c_ushort_type,
2365 .c_int_type,
2366 .c_uint_type,
2367 .c_long_type,
2368 .c_ulong_type,
2369 .c_longlong_type,
2370 .c_ulonglong_type,
2371 => true,
2372
2373 else => false,
2374 };
2375}
2376
2377/// Returns `false` for `comptime_float`.1658/// Returns `false` for `comptime_float`.
2378pub fn isRuntimeFloat(ty: Type) bool {1659pub fn isRuntimeFloat(ty: Type) bool {
2379 return switch (ty.toIntern()) {1660 return switch (ty.toIntern()) {
...@@ -2488,17 +1769,16 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {...@@ -2488,17 +1769,16 @@ pub fn isNumeric(ty: Type, zcu: *const Zcu) bool {
2488 };1769 };
2489}1770}
24901771
2491/// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which1772/// MLUGG TODO: deal with our friends structs and unions
2492/// resolves field types rather than asserting they are already resolved.
2493pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {1773pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
2494 const zcu = pt.zcu;1774 const zcu = pt.zcu;
2495 const comp = zcu.comp;1775 const comp = zcu.comp;
2496 const gpa = comp.gpa;1776 const gpa = comp.gpa;
2497 const io = comp.io;
2498 const ip = &zcu.intern_pool;1777 const ip = &zcu.intern_pool;
1778 assertHasLayout(starting_type, zcu);
2499 var ty = starting_type;1779 var ty = starting_type;
2500 while (true) switch (ty.toIntern()) {1780 while (true) switch (ty.toIntern()) {
2501 .empty_tuple_type => return Value.empty_tuple,1781 .empty_tuple_type => return .empty_tuple,
25021782
2503 else => switch (ip.indexToKey(ty.toIntern())) {1783 else => switch (ip.indexToKey(ty.toIntern())) {
2504 .int_type => |int_type| {1784 .int_type => |int_type| {
...@@ -2563,31 +1843,37 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {...@@ -2563,31 +1843,37 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
2563 .adhoc_inferred_error_set,1843 .adhoc_inferred_error_set,
2564 => return null,1844 => return null,
25651845
2566 .void => return Value.void,1846 .void => return .void,
2567 .noreturn => return Value.@"unreachable",1847 .noreturn => return .@"unreachable",
2568 .null => return Value.null,1848 .null => return .null,
2569 .undefined => return Value.undef,1849 .undefined => return .undef,
25701850
2571 .generic_poison => unreachable,1851 .generic_poison => unreachable,
2572 },1852 },
2573 .struct_type => {1853 .struct_type => {
2574 const struct_type = ip.loadStructType(ty.toIntern());1854 const struct_obj = ip.loadStructType(ty.toIntern());
2575 assert(struct_type.haveFieldTypes(ip));1855 if (struct_obj.layout == .@"packed") {
2576 if (struct_type.knownNonOpv(ip))1856 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type);
2577 return null;1857 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null;
2578 const field_vals = try zcu.gpa.alloc(InternPool.Index, struct_type.field_types.len);1858 _ = backing_val; // MLUGG TODO: represent unions as their bits!
2579 defer zcu.gpa.free(field_vals);1859 } else {
1860 if (!struct_obj.has_one_possible_value) return null;
1861 }
1862 // There is an OPV.
1863 const field_vals = try gpa.alloc(InternPool.Index, struct_obj.field_types.len);
1864 defer gpa.free(field_vals);
2580 for (field_vals, 0..) |*field_val, i_usize| {1865 for (field_vals, 0..) |*field_val, i_usize| {
2581 const i: u32 = @intCast(i_usize);1866 const i: u32 = @intCast(i_usize);
2582 if (struct_type.fieldIsComptime(ip, i)) {1867 if (struct_obj.field_is_comptime_bits.get(ip, i)) {
2583 assert(struct_type.haveFieldInits(ip));1868 // MLUGG TODO: this is kinda a problem... we don't necessarily know the opv field vals!
2584 field_val.* = struct_type.field_inits.get(ip)[i];1869 // for now i'm just not letting structs with comptime fields be opv :)
1870 if (true) return null;
1871 assertHasInits(ty, zcu);
1872 field_val.* = struct_obj.field_defaults.get(ip)[i];
2585 continue;1873 continue;
2586 }1874 }
2587 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);1875 const field_ty = Type.fromInterned(struct_obj.field_types.get(ip)[i]);
2588 if (try field_ty.onePossibleValue(pt)) |field_opv| {1876 field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern();
2589 field_val.* = field_opv.toIntern();
2590 } else return null;
2591 }1877 }
25921878
2593 // In this case the struct has no runtime-known fields and1879 // In this case the struct has no runtime-known fields and
...@@ -2623,12 +1909,13 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {...@@ -2623,12 +1909,13 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
2623 },1909 },
26241910
2625 .union_type => {1911 .union_type => {
1912 // MLUGG TODO: is this nonsensical or what!!!!!!
2626 const union_obj = ip.loadUnionType(ty.toIntern());1913 const union_obj = ip.loadUnionType(ty.toIntern());
2627 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(pt)) orelse1914 const tag_val = (try Type.fromInterned(union_obj.enum_tag_type).onePossibleValue(pt)) orelse
2628 return null;1915 return null;
2629 if (union_obj.field_types.len == 0) {1916 if (union_obj.field_types.len == 0) {
2630 const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });1917 const only = try pt.intern(.{ .empty_enum_value = ty.toIntern() });
2631 return Value.fromInterned(only);1918 return .fromInterned(only);
2632 }1919 }
2633 const only_field_ty = union_obj.field_types.get(ip)[0];1920 const only_field_ty = union_obj.field_types.get(ip)[0];
2634 const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(pt)) orelse1921 const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(pt)) orelse
...@@ -2638,47 +1925,34 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {...@@ -2638,47 +1925,34 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
2638 .tag = tag_val.toIntern(),1925 .tag = tag_val.toIntern(),
2639 .val = val_val.toIntern(),1926 .val = val_val.toIntern(),
2640 });1927 });
2641 return Value.fromInterned(only);1928 return .fromInterned(only);
2642 },1929 },
2643 .opaque_type => return null,1930 .opaque_type => return null,
2644 .enum_type => {1931 .enum_type => {
2645 const enum_type = ip.loadEnumType(ty.toIntern());1932 const enum_obj = ip.loadEnumType(ty.toIntern());
2646 switch (enum_type.tag_mode) {1933 if (enum_obj.nonexhaustive) {
2647 .nonexhaustive => {1934 const int_opv = try Type.fromInterned(enum_obj.int_tag_type).onePossibleValue(pt) orelse return null;
2648 if (enum_type.tag_ty == .comptime_int_type) return null;1935 return .fromInterned(try pt.intern(.{ .enum_tag = .{
26491936 .ty = ty.toIntern(),
2650 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(pt)) |int_opv| {1937 .int = int_opv.toIntern(),
2651 const only = try pt.intern(.{ .enum_tag = .{1938 } }));
2652 .ty = ty.toIntern(),1939 }
2653 .int = int_opv.toIntern(),1940 // MLUGG TODO: this is to preserve existing semantics, i REALLY don't fuck with it...
2654 } });1941 if (enum_obj.int_tag_type == .comptime_int_type) {
2655 return Value.fromInterned(only);1942 return switch (enum_obj.field_names.len) {
2656 }1943 0 => .fromInterned(try pt.intern(.{ .empty_enum_value = ty.toIntern() })),
26571944 1 => try pt.enumValueFieldIndex(ty, 0),
2658 return null;1945 else => null,
2659 },1946 };
2660 .auto, .explicit => {
2661 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(zcu)) return null;
2662
2663 return Value.fromInterned(switch (enum_type.names.len) {
2664 0 => try pt.intern(.{ .empty_enum_value = ty.toIntern() }),
2665 1 => try pt.intern(.{ .enum_tag = .{
2666 .ty = ty.toIntern(),
2667 .int = if (enum_type.values.len == 0)
2668 (try pt.intValue(.fromInterned(enum_type.tag_ty), 0)).toIntern()
2669 else
2670 try ip.getCoercedInts(
2671 gpa,
2672 io,
2673 pt.tid,
2674 ip.indexToKey(enum_type.values.get(ip)[0]).int,
2675 enum_type.tag_ty,
2676 ),
2677 } }),
2678 else => return null,
2679 });
2680 },
2681 }1947 }
1948 const int_tag_opv = try Type.fromInterned(enum_obj.int_tag_type).onePossibleValue(pt) orelse return null;
1949 if (enum_obj.field_names.len == 0) {
1950 return .fromInterned(try pt.intern(.{ .empty_enum_value = ty.toIntern() }));
1951 }
1952 return .fromInterned(try pt.intern(.{ .enum_tag = .{
1953 .ty = ty.toIntern(),
1954 .int = int_tag_opv.toIntern(),
1955 } }));
2682 },1956 },
26831957
2684 // values, not types1958 // values, not types
...@@ -2706,211 +1980,106 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {...@@ -2706,211 +1980,106 @@ pub fn onePossibleValue(starting_type: Type, pt: Zcu.PerThread) !?Value {
2706 };1980 };
2707}1981}
27081982
2709/// During semantic analysis, instead call `ty.comptimeOnlySema` which1983/// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`.
2710/// resolves field types rather than asserting they are already resolved.
2711pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {1984pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool {
2712 return ty.comptimeOnlyInner(.normal, zcu, {}) catch unreachable;
2713}
2714
2715pub fn comptimeOnlySema(ty: Type, pt: Zcu.PerThread) SemaError!bool {
2716 return try ty.comptimeOnlyInner(.sema, pt.zcu, pt.tid);
2717}
2718
2719/// `generic_poison` will return false.
2720/// May return false negatives when structs and unions are having their field types resolved.
2721pub fn comptimeOnlyInner(
2722 ty: Type,
2723 comptime strat: ResolveStrat,
2724 zcu: strat.ZcuPtr(),
2725 tid: strat.Tid(),
2726) SemaError!bool {
2727 const ip = &zcu.intern_pool;1985 const ip = &zcu.intern_pool;
2728 const io = zcu.comp.io;1986 return switch (ip.indexToKey(ty.toIntern())) {
2729 return switch (ty.toIntern()) {1987 .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnly(zcu),
2730 .empty_tuple_type => false,1988 .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnly(zcu),
27311989 .opt_type => |child| return Type.fromInterned(child).comptimeOnly(zcu),
2732 else => switch (ip.indexToKey(ty.toIntern())) {1990 .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnly(zcu),
2733 .int_type => false,1991 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type).comptimeOnly(zcu),
2734 .ptr_type => |ptr_type| {
2735 const child_ty = Type.fromInterned(ptr_type.child);
2736 switch (child_ty.zigTypeTag(zcu)) {
2737 .@"fn" => return !try child_ty.fnHasRuntimeBitsInner(strat, zcu, tid),
2738 .@"opaque" => return false,
2739 else => return child_ty.comptimeOnlyInner(strat, zcu, tid),
2740 }
2741 },
2742 .anyframe_type => |child| {
2743 if (child == .none) return false;
2744 return Type.fromInterned(child).comptimeOnlyInner(strat, zcu, tid);
2745 },
2746 .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyInner(strat, zcu, tid),
2747 .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyInner(strat, zcu, tid),
2748 .opt_type => |child| return Type.fromInterned(child).comptimeOnlyInner(strat, zcu, tid),
2749 .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyInner(strat, zcu, tid),
2750
2751 .error_set_type,
2752 .inferred_error_set_type,
2753 => false,
2754
2755 // These are function bodies, not function pointers.
2756 .func_type => true,
2757
2758 .simple_type => |t| switch (t) {
2759 .f16,
2760 .f32,
2761 .f64,
2762 .f80,
2763 .f128,
2764 .usize,
2765 .isize,
2766 .c_char,
2767 .c_short,
2768 .c_ushort,
2769 .c_int,
2770 .c_uint,
2771 .c_long,
2772 .c_ulong,
2773 .c_longlong,
2774 .c_ulonglong,
2775 .c_longdouble,
2776 .anyopaque,
2777 .bool,
2778 .void,
2779 .anyerror,
2780 .adhoc_inferred_error_set,
2781 .noreturn,
2782 .generic_poison,
2783 => false,
2784
2785 .type,
2786 .comptime_int,
2787 .comptime_float,
2788 .null,
2789 .undefined,
2790 .enum_literal,
2791 => true,
2792 },
2793 .struct_type => {
2794 const struct_type = ip.loadStructType(ty.toIntern());
2795 // packed structs cannot be comptime-only because they have a well-defined
2796 // memory layout and every field has a well-defined bit pattern.
2797 if (struct_type.layout == .@"packed")
2798 return false;
2799
2800 return switch (strat) {
2801 .normal => switch (struct_type.requiresComptime(ip)) {
2802 .wip => unreachable,
2803 .no => false,
2804 .yes => true,
2805 .unknown => unreachable,
2806 },
2807 .sema => switch (struct_type.setRequiresComptimeWip(ip, io)) {
2808 .no, .wip => false,
2809 .yes => true,
2810 .unknown => {
2811 if (struct_type.flagsUnordered(ip).field_types_wip) {
2812 struct_type.setRequiresComptime(ip, io, .unknown);
2813 return false;
2814 }
2815
2816 errdefer struct_type.setRequiresComptime(ip, io, .unknown);
2817
2818 const pt = strat.pt(zcu, tid);
2819 try ty.resolveFields(pt);
2820
2821 for (0..struct_type.field_types.len) |i_usize| {
2822 const i: u32 = @intCast(i_usize);
2823 if (struct_type.fieldIsComptime(ip, i)) continue;
2824 const field_ty = struct_type.field_types.get(ip)[i];
2825 if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) {
2826 // Note that this does not cause the layout to
2827 // be considered resolved. Comptime-only types
2828 // still maintain a layout of their
2829 // runtime-known fields.
2830 struct_type.setRequiresComptime(ip, io, .yes);
2831 return true;
2832 }
2833 }
2834
2835 struct_type.setRequiresComptime(ip, io, .no);
2836 return false;
2837 },
2838 },
2839 };
2840 },
2841
2842 .tuple_type => |tuple| {
2843 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2844 const have_comptime_val = val != .none;
2845 if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) return true;
2846 }
2847 return false;
2848 },
28491992
2850 .union_type => {1993 .int_type,
2851 const union_type = ip.loadUnionType(ty.toIntern());1994 .ptr_type,
2852 return switch (strat) {1995 .anyframe_type,
2853 .normal => switch (union_type.requiresComptime(ip)) {1996 .error_set_type,
2854 .wip => unreachable,1997 .inferred_error_set_type,
2855 .no => false,1998 .opaque_type,
2856 .yes => true,1999 => false,
2857 .unknown => unreachable,
2858 },
2859 .sema => switch (union_type.setRequiresComptimeWip(ip, io)) {
2860 .no, .wip => return false,
2861 .yes => return true,
2862 .unknown => {
2863 if (union_type.flagsUnordered(ip).status == .field_types_wip) {
2864 union_type.setRequiresComptime(ip, io, .unknown);
2865 return false;
2866 }
2867
2868 errdefer union_type.setRequiresComptime(ip, io, .unknown);
2869
2870 const pt = strat.pt(zcu, tid);
2871 try ty.resolveFields(pt);
2872
2873 for (0..union_type.field_types.len) |field_idx| {
2874 const field_ty = union_type.field_types.get(ip)[field_idx];
2875 if (try Type.fromInterned(field_ty).comptimeOnlyInner(strat, zcu, tid)) {
2876 union_type.setRequiresComptime(ip, io, .yes);
2877 return true;
2878 }
2879 }
2880
2881 union_type.setRequiresComptime(ip, io, .no);
2882 return false;
2883 },
2884 },
2885 };
2886 },
28872000
2888 .opaque_type => false,2001 // These are function bodies, not function pointers.
2002 .func_type => true,
28892003
2890 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyInner(strat, zcu, tid),2004 .simple_type => |t| switch (t) {
2005 .f16,
2006 .f32,
2007 .f64,
2008 .f80,
2009 .f128,
2010 .usize,
2011 .isize,
2012 .c_char,
2013 .c_short,
2014 .c_ushort,
2015 .c_int,
2016 .c_uint,
2017 .c_long,
2018 .c_ulong,
2019 .c_longlong,
2020 .c_ulonglong,
2021 .c_longdouble,
2022 .anyopaque,
2023 .bool,
2024 .void,
2025 .anyerror,
2026 .adhoc_inferred_error_set,
2027 .noreturn,
2028 .generic_poison,
2029 => false,
28912030
2892 // values, not types2031 .type,
2893 .undef,2032 .comptime_int,
2894 .simple_value,2033 .comptime_float,
2895 .variable,2034 .null,
2896 .@"extern",2035 .undefined,
2897 .func,
2898 .int,
2899 .err,
2900 .error_union,
2901 .enum_literal,2036 .enum_literal,
2902 .enum_tag,2037 => true,
2903 .empty_enum_value,2038 },
2904 .float,2039 .struct_type => {
2905 .ptr,2040 const struct_obj = ip.loadStructType(ty.toIntern());
2906 .slice,2041 return switch (struct_obj.layout) {
2907 .opt,2042 .@"packed" => false,
2908 .aggregate,2043 .auto, .@"extern" => struct_obj.comptime_only,
2909 .un,2044 };
2910 // memoization, not types2045 },
2911 .memoized_call,2046 .union_type => {
2912 => unreachable,2047 const union_obj = ip.loadUnionType(ty.toIntern());
2048 return switch (union_obj.layout) {
2049 .@"packed" => false,
2050 .auto, .@"extern" => union_obj.comptime_only,
2051 };
2913 },2052 },
2053 .tuple_type => |tuple| {
2054 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2055 if (val != .none) continue;
2056 if (!Type.fromInterned(field_ty).comptimeOnly(zcu)) continue;
2057 return true;
2058 }
2059 return false;
2060 },
2061
2062 // values, not types
2063 .undef,
2064 .simple_value,
2065 .variable,
2066 .@"extern",
2067 .func,
2068 .int,
2069 .err,
2070 .error_union,
2071 .enum_literal,
2072 .enum_tag,
2073 .empty_enum_value,
2074 .float,
2075 .ptr,
2076 .slice,
2077 .opt,
2078 .aggregate,
2079 .un,
2080 // memoization, not types
2081 .memoized_call,
2082 => unreachable,
2914 };2083 };
2915}2084}
29162085
...@@ -3056,20 +2225,18 @@ pub fn maxIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {...@@ -3056,20 +2225,18 @@ pub fn maxIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value {
3056/// Asserts the type is an enum or a union.2225/// Asserts the type is an enum or a union.
3057pub fn intTagType(ty: Type, zcu: *const Zcu) Type {2226pub fn intTagType(ty: Type, zcu: *const Zcu) Type {
3058 const ip = &zcu.intern_pool;2227 const ip = &zcu.intern_pool;
3059 return switch (ip.indexToKey(ty.toIntern())) {2228 const enum_ty: Type = switch (ip.indexToKey(ty.toIntern())) {
3060 .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(zcu),2229 .union_type => .fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_type),
3061 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),2230 .enum_type => ty,
3062 else => unreachable,2231 else => unreachable,
3063 };2232 };
2233 return .fromInterned(ip.loadEnumType(enum_ty.toIntern()).int_tag_type);
3064}2234}
30652235
3066pub fn isNonexhaustiveEnum(ty: Type, zcu: *const Zcu) bool {2236pub fn isNonexhaustiveEnum(ty: Type, zcu: *const Zcu) bool {
3067 const ip = &zcu.intern_pool;2237 const ip = &zcu.intern_pool;
3068 return switch (ip.indexToKey(ty.toIntern())) {2238 return switch (ip.indexToKey(ty.toIntern())) {
3069 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {2239 .enum_type => ip.loadEnumType(ty.toIntern()).nonexhaustive,
3070 .nonexhaustive => true,
3071 .auto, .explicit => false,
3072 },
3073 else => false,2240 else => false,
3074 };2241 };
3075}2242}
...@@ -3090,16 +2257,16 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString....@@ -3090,16 +2257,16 @@ pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.
3090}2257}
30912258
3092pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice {2259pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice {
3093 return zcu.intern_pool.loadEnumType(ty.toIntern()).names;2260 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names;
3094}2261}
30952262
3096pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize {2263pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize {
3097 return zcu.intern_pool.loadEnumType(ty.toIntern()).names.len;2264 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len;
3098}2265}
30992266
3100pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString {2267pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString {
3101 const ip = &zcu.intern_pool;2268 const ip = &zcu.intern_pool;
3102 return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index];2269 return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index];
3103}2270}
31042271
3105pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 {2272pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 {
...@@ -3119,7 +2286,7 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {...@@ -3119,7 +2286,7 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
3119 .enum_tag => |info| info.int,2286 .enum_tag => |info| info.int,
3120 else => unreachable,2287 else => unreachable,
3121 };2288 };
3122 assert(ip.typeOf(int_tag) == enum_type.tag_ty);2289 assert(ip.typeOf(int_tag) == enum_type.int_tag_type);
3123 return enum_type.tagValueIndex(ip, int_tag);2290 return enum_type.tagValueIndex(ip, int_tag);
3124}2291}
31252292
...@@ -3127,7 +2294,7 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {...@@ -3127,7 +2294,7 @@ pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 {
3127pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString {2294pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString {
3128 const ip = &zcu.intern_pool;2295 const ip = &zcu.intern_pool;
3129 return switch (ip.indexToKey(ty.toIntern())) {2296 return switch (ip.indexToKey(ty.toIntern())) {
3130 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index).toOptional(),2297 .struct_type => ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(),
3131 .tuple_type => .none,2298 .tuple_type => .none,
3132 else => unreachable,2299 else => unreachable,
3133 };2300 };
...@@ -3144,175 +2311,96 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {...@@ -3144,175 +2311,96 @@ pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 {
31442311
3145/// Returns the field type. Supports structs and unions.2312/// Returns the field type. Supports structs and unions.
3146pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {2313pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type {
2314 const ip = &zcu.intern_pool;
2315 const types = switch (ip.indexToKey(ty.toIntern())) {
2316 .struct_type => ip.loadStructType(ty.toIntern()).field_types,
2317 .union_type => ip.loadUnionType(ty.toIntern()).field_types,
2318 .tuple_type => |tuple| tuple.types,
2319 else => unreachable,
2320 };
2321 return .fromInterned(types.get(ip)[index]);
2322}
2323
2324// TODO MLUGG: clean up doc comments and usages of `{resolved,explicit}FieldAlignment`
2325
2326/// Returns the alignment of the given struct, tuple, or union field.
2327/// Asserts that the layout of `ty` is resolved. Asserts that `ty` is not packed.
2328/// Never returns `.none`, even if the field's alignment was not specified.
2329pub fn resolvedFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment {
2330 switch (ty.explicitFieldAlignment(index, zcu)) {
2331 .none => {},
2332 else => |explicit| return explicit,
2333 }
3147 const ip = &zcu.intern_pool;2334 const ip = &zcu.intern_pool;
3148 return switch (ip.indexToKey(ty.toIntern())) {2335 return switch (ip.indexToKey(ty.toIntern())) {
3149 .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),2336 .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]).abiAlignment(zcu),
2337 .struct_type => {
2338 const struct_obj = ip.loadStructType(ty.toIntern());
2339 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[index]);
2340 return field_ty.defaultStructFieldAlignment(struct_obj.layout, zcu);
2341 },
3150 .union_type => {2342 .union_type => {
3151 const union_obj = ip.loadUnionType(ty.toIntern());2343 const union_obj = ip.loadUnionType(ty.toIntern());
3152 return Type.fromInterned(union_obj.field_types.get(ip)[index]);2344 const field_ty: Type = .fromInterned(union_obj.field_types.get(ip)[index]);
2345 return field_ty.abiAlignment(zcu);
3153 },2346 },
3154 .tuple_type => |tuple| Type.fromInterned(tuple.types.get(ip)[index]),
3155 else => unreachable,2347 else => unreachable,
3156 };2348 };
3157}2349}
31582350
3159pub fn fieldAlignment(ty: Type, index: usize, zcu: *Zcu) Alignment {2351pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment {
3160 return ty.fieldAlignmentInner(index, .normal, zcu, {}) catch unreachable;
3161}
3162
3163pub fn fieldAlignmentSema(ty: Type, index: usize, pt: Zcu.PerThread) SemaError!Alignment {
3164 return try ty.fieldAlignmentInner(index, .sema, pt.zcu, pt.tid);
3165}
3166
3167/// Returns the field alignment. Supports structs and unions.
3168/// If `strat` is `.sema`, may perform type resolution.
3169/// Asserts the layout is not packed.
3170///
3171/// Provide the struct field as the `ty`.
3172pub fn fieldAlignmentInner(
3173 ty: Type,
3174 index: usize,
3175 comptime strat: ResolveStrat,
3176 zcu: strat.ZcuPtr(),
3177 tid: strat.Tid(),
3178) SemaError!Alignment {
3179 const ip = &zcu.intern_pool;2352 const ip = &zcu.intern_pool;
3180 switch (ip.indexToKey(ty.toIntern())) {2353 return switch (ip.indexToKey(ty.toIntern())) {
2354 .tuple_type => .none,
3181 .struct_type => {2355 .struct_type => {
3182 const struct_type = ip.loadStructType(ty.toIntern());2356 const struct_obj = ip.loadStructType(ty.toIntern());
3183 assert(struct_type.layout != .@"packed");2357 assert(struct_obj.layout != .@"packed");
3184 const explicit_align = struct_type.fieldAlign(ip, index);2358 if (struct_obj.field_aligns.len == 0) return .none;
3185 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);2359 return struct_obj.field_aligns.get(ip)[index];
3186 return field_ty.structFieldAlignmentInner(explicit_align, struct_type.layout, strat, zcu, tid);
3187 },
3188 .tuple_type => |tuple| {
3189 return (try Type.fromInterned(tuple.types.get(ip)[index]).abiAlignmentInner(
3190 strat.toLazy(),
3191 zcu,
3192 tid,
3193 )).scalar;
3194 },2360 },
3195 .union_type => {2361 .union_type => {
3196 const union_obj = ip.loadUnionType(ty.toIntern());2362 const union_obj = ip.loadUnionType(ty.toIntern());
3197 const layout = union_obj.flagsUnordered(ip).layout;2363 assert(union_obj.layout != .@"packed");
3198 assert(layout != .@"packed");2364 if (union_obj.field_aligns.len == 0) return .none;
3199 const explicit_align = union_obj.fieldAlign(ip, index);2365 return union_obj.field_aligns.get(ip)[index];
3200 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[index]);
3201 return field_ty.unionFieldAlignmentInner(explicit_align, layout, strat, zcu, tid);
3202 },2366 },
3203 else => unreachable,2367 else => unreachable,
3204 }2368 };
3205}2369}
32062370
3207/// Returns the alignment of a non-packed struct field. Assert the layout is not packed.2371/// Returns the alignment a struct field will have if not explicitly specified.
3208///2372/// Asserts that the layout of `field_ty` is resolved. Asserts that `layout` is not `.@"packed"`.
3209/// Asserts that all resolution needed was done.2373pub fn defaultStructFieldAlignment(
3210pub fn structFieldAlignment(
3211 field_ty: Type,2374 field_ty: Type,
3212 explicit_alignment: InternPool.Alignment,
3213 layout: std.builtin.Type.ContainerLayout,2375 layout: std.builtin.Type.ContainerLayout,
3214 zcu: *Zcu,2376 zcu: *const Zcu,
3215) Alignment {2377) Alignment {
3216 return field_ty.structFieldAlignmentInner(2378 const overalign_big_int = switch (layout) {
3217 explicit_alignment,
3218 layout,
3219 .normal,
3220 zcu,
3221 {},
3222 ) catch unreachable;
3223}
3224
3225/// Returns the alignment of a non-packed struct field. Assert the layout is not packed.
3226/// May do type resolution when needed.
3227/// Asserts that all resolution needed was done.
3228pub fn structFieldAlignmentSema(
3229 field_ty: Type,
3230 explicit_alignment: InternPool.Alignment,
3231 layout: std.builtin.Type.ContainerLayout,
3232 pt: Zcu.PerThread,
3233) SemaError!Alignment {
3234 return try field_ty.structFieldAlignmentInner(
3235 explicit_alignment,
3236 layout,
3237 .sema,
3238 pt.zcu,
3239 pt.tid,
3240 );
3241}
3242
3243/// Returns the alignment of a non-packed struct field. Asserts the layout is not packed.
3244/// If `strat` is `.sema`, may perform type resolution.
3245pub fn structFieldAlignmentInner(
3246 field_ty: Type,
3247 explicit_alignment: Alignment,
3248 layout: std.builtin.Type.ContainerLayout,
3249 comptime strat: Type.ResolveStrat,
3250 zcu: strat.ZcuPtr(),
3251 tid: strat.Tid(),
3252) SemaError!Alignment {
3253 assert(layout != .@"packed");
3254 if (explicit_alignment != .none) return explicit_alignment;
3255 const ty_abi_align = (try field_ty.abiAlignmentInner(
3256 strat.toLazy(),
3257 zcu,
3258 tid,
3259 )).scalar;
3260 switch (layout) {
3261 .@"packed" => unreachable,2379 .@"packed" => unreachable,
3262 .auto => if (zcu.getTarget().ofmt != .c) return ty_abi_align,2380 .auto => zcu.getTarget().ofmt == .c,
3263 .@"extern" => {},2381 .@"extern" => true,
3264 }2382 };
3265 // extern2383 const abi_align = field_ty.abiAlignment(zcu);
3266 if (field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) {2384 assert(abi_align != .none);
3267 return ty_abi_align.maxStrict(.@"16");2385 if (overalign_big_int and field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) {
2386 return abi_align.maxStrict(.@"16");
3268 }2387 }
3269 return ty_abi_align;2388 return abi_align;
3270}
3271
3272pub fn unionFieldAlignmentSema(
3273 field_ty: Type,
3274 explicit_alignment: Alignment,
3275 layout: std.builtin.Type.ContainerLayout,
3276 pt: Zcu.PerThread,
3277) SemaError!Alignment {
3278 return field_ty.unionFieldAlignmentInner(
3279 explicit_alignment,
3280 layout,
3281 .sema,
3282 pt.zcu,
3283 pt.tid,
3284 );
3285}2389}
32862390
3287pub fn unionFieldAlignmentInner(2391pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value {
3288 field_ty: Type,
3289 explicit_alignment: Alignment,
3290 layout: std.builtin.Type.ContainerLayout,
3291 comptime strat: Type.ResolveStrat,
3292 zcu: strat.ZcuPtr(),
3293 tid: strat.Tid(),
3294) SemaError!Alignment {
3295 assert(layout != .@"packed");
3296 if (explicit_alignment != .none) return explicit_alignment;
3297 if (field_ty.isNoReturn(zcu)) return .none;
3298 return (try field_ty.abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar;
3299}
3300
3301pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) Value {
3302 const ip = &zcu.intern_pool;2392 const ip = &zcu.intern_pool;
3303 switch (ip.indexToKey(ty.toIntern())) {2393 switch (ip.indexToKey(ty.toIntern())) {
3304 .struct_type => {2394 .struct_type => {
3305 const struct_type = ip.loadStructType(ty.toIntern());2395 const field_defaults = ip.loadStructType(ty.toIntern()).field_defaults.get(ip);
3306 const val = struct_type.fieldInit(ip, index);2396 if (field_defaults.len == 0) return null;
3307 // TODO: avoid using `unreachable` to indicate this.2397 if (field_defaults[index] == .none) return null;
3308 if (val == .none) return Value.@"unreachable";2398 return .fromInterned(field_defaults[index]);
3309 return Value.fromInterned(val);
3310 },2399 },
3311 .tuple_type => |tuple| {2400 .tuple_type => |tuple| {
3312 const val = tuple.values.get(ip)[index];2401 const val = tuple.values.get(ip)[index];
3313 // TODO: avoid using `unreachable` to indicate this.2402 if (val == .none) return null;
3314 if (val == .none) return Value.@"unreachable";2403 return .fromInterned(val);
3315 return Value.fromInterned(val);
3316 },2404 },
3317 else => unreachable,2405 else => unreachable,
3318 }2406 }
...@@ -3324,9 +2412,9 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val...@@ -3324,9 +2412,9 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
3324 switch (ip.indexToKey(ty.toIntern())) {2412 switch (ip.indexToKey(ty.toIntern())) {
3325 .struct_type => {2413 .struct_type => {
3326 const struct_type = ip.loadStructType(ty.toIntern());2414 const struct_type = ip.loadStructType(ty.toIntern());
3327 if (struct_type.fieldIsComptime(ip, index)) {2415 if (struct_type.field_is_comptime_bits.get(ip, index)) {
3328 assert(struct_type.haveFieldInits(ip));2416 assertHasInits(ty, zcu);
3329 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);2417 return .fromInterned(struct_type.field_defaults.get(ip)[index]);
3330 } else {2418 } else {
3331 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt);2419 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt);
3332 }2420 }
...@@ -3336,7 +2424,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val...@@ -3336,7 +2424,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
3336 if (val == .none) {2424 if (val == .none) {
3337 return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt);2425 return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt);
3338 } else {2426 } else {
3339 return Value.fromInterned(val);2427 return .fromInterned(val);
3340 }2428 }
3341 },2429 },
3342 else => unreachable,2430 else => unreachable,
...@@ -3346,7 +2434,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val...@@ -3346,7 +2434,7 @@ pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Val
3346pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {2434pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool {
3347 const ip = &zcu.intern_pool;2435 const ip = &zcu.intern_pool;
3348 return switch (ip.indexToKey(ty.toIntern())) {2436 return switch (ip.indexToKey(ty.toIntern())) {
3349 .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),2437 .struct_type => ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index),
3350 .tuple_type => |tuple| tuple.values.get(ip)[index] != .none,2438 .tuple_type => |tuple| tuple.values.get(ip)[index] != .none,
3351 else => unreachable,2439 else => unreachable,
3352 };2440 };
...@@ -3357,15 +2445,15 @@ pub const FieldOffset = struct {...@@ -3357,15 +2445,15 @@ pub const FieldOffset = struct {
3357 offset: u64,2445 offset: u64,
3358};2446};
33592447
3360/// Supports structs and unions.2448/// Supports structs, tuples, and unions.
3361pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {2449pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
2450 assertHasLayout(ty, zcu);
3362 const ip = &zcu.intern_pool;2451 const ip = &zcu.intern_pool;
3363 switch (ip.indexToKey(ty.toIntern())) {2452 switch (ip.indexToKey(ty.toIntern())) {
3364 .struct_type => {2453 .struct_type => {
3365 const struct_type = ip.loadStructType(ty.toIntern());2454 const struct_type = ip.loadStructType(ty.toIntern());
3366 assert(struct_type.haveLayout(ip));
3367 assert(struct_type.layout != .@"packed");2455 assert(struct_type.layout != .@"packed");
3368 return struct_type.offsets.get(ip)[index];2456 return struct_type.field_offsets.get(ip)[index];
3369 },2457 },
33702458
3371 .tuple_type => |tuple| {2459 .tuple_type => |tuple| {
...@@ -3391,7 +2479,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {...@@ -3391,7 +2479,7 @@ pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 {
33912479
3392 .union_type => {2480 .union_type => {
3393 const union_type = ip.loadUnionType(ty.toIntern());2481 const union_type = ip.loadUnionType(ty.toIntern());
3394 if (!union_type.hasTag(ip))2482 if (union_type.runtime_tag == .none)
3395 return 0;2483 return 0;
3396 const layout = Type.getUnionLayout(union_type, zcu);2484 const layout = Type.getUnionLayout(union_type, zcu);
3397 if (layout.tag_align.compare(.gte, layout.payload_align)) {2485 if (layout.tag_align.compare(.gte, layout.payload_align)) {
...@@ -3414,7 +2502,7 @@ pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Zcu.LazySrcLoc {...@@ -3414,7 +2502,7 @@ pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Zcu.LazySrcLoc {
3414 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {2502 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3415 .declared => |d| d.zir_index,2503 .declared => |d| d.zir_index,
3416 .reified => |r| r.zir_index,2504 .reified => |r| r.zir_index,
3417 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,2505 .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index,
3418 },2506 },
3419 else => return null,2507 else => return null,
3420 },2508 },
...@@ -3438,8 +2526,8 @@ pub fn isTuple(ty: Type, zcu: *const Zcu) bool {...@@ -3438,8 +2526,8 @@ pub fn isTuple(ty: Type, zcu: *const Zcu) bool {
3438 };2526 };
3439}2527}
34402528
3441/// Traverses optional child types and error union payloads until the type2529/// Traverses optional child types and error union payloads until the type is neither of those.
3442/// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.2530/// For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
3443pub fn optEuBaseType(ty: Type, zcu: *const Zcu) Type {2531pub fn optEuBaseType(ty: Type, zcu: *const Zcu) Type {
3444 var cur = ty;2532 var cur = ty;
3445 while (true) switch (cur.zigTypeTag(zcu)) {2533 while (true) switch (cur.zigTypeTag(zcu)) {
...@@ -3488,7 +2576,7 @@ pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.Trac...@@ -3488,7 +2576,7 @@ pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.Trac
3488 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,2576 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
3489 .enum_type => |e| switch (e) {2577 .enum_type => |e| switch (e) {
3490 .declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?,2578 .declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?,
3491 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,2579 .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index,
3492 },2580 },
3493 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,2581 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
3494 else => null,2582 else => null,
...@@ -3505,7 +2593,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {...@@ -3505,7 +2593,7 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
3505 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {2593 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3506 .declared => |d| d.zir_index,2594 .declared => |d| d.zir_index,
3507 .reified => |r| r.zir_index,2595 .reified => |r| r.zir_index,
3508 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,2596 .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index,
3509 },2597 },
3510 else => return null,2598 else => return null,
3511 };2599 };
...@@ -3520,10 +2608,10 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {...@@ -3520,10 +2608,10 @@ pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 {
3520 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,2608 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_line,
3521 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_line,2609 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_line,
3522 .extended => switch (inst.data.extended.opcode) {2610 .extended => switch (inst.data.extended.opcode) {
3523 .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line,2611 .struct_decl => zir.getStructDecl(info.inst).src_line,
3524 .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,2612 .union_decl => zir.getUnionDecl(info.inst).src_line,
3525 .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,2613 .enum_decl => zir.getEnumDecl(info.inst).src_line,
3526 .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,2614 .opaque_decl => zir.getOpaqueDecl(info.inst).src_line,
3527 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line,2615 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line,
3528 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line,2616 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line,
3529 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line,2617 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line,
...@@ -3594,330 +2682,8 @@ pub fn packedStructFieldPtrInfo(...@@ -3594,330 +2682,8 @@ pub fn packedStructFieldPtrInfo(
3594 };2682 };
3595}2683}
35962684
3597pub fn resolveLayout(ty: Type, pt: Zcu.PerThread) SemaError!void {
3598 const zcu = pt.zcu;
3599 const ip = &zcu.intern_pool;
3600 switch (ty.zigTypeTag(zcu)) {
3601 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
3602 .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| {
3603 const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]);
3604 try field_ty.resolveLayout(pt);
3605 },
3606 .struct_type => return ty.resolveStructInner(pt, .layout),
3607 else => unreachable,
3608 },
3609 .@"union" => return ty.resolveUnionInner(pt, .layout),
3610 .array => {
3611 if (ty.arrayLenIncludingSentinel(zcu) == 0) return;
3612 const elem_ty = ty.childType(zcu);
3613 return elem_ty.resolveLayout(pt);
3614 },
3615 .optional => {
3616 const payload_ty = ty.optionalChild(zcu);
3617 return payload_ty.resolveLayout(pt);
3618 },
3619 .error_union => {
3620 const payload_ty = ty.errorUnionPayload(zcu);
3621 return payload_ty.resolveLayout(pt);
3622 },
3623 .@"fn" => {
3624 const info = zcu.typeToFunc(ty).?;
3625 if (info.is_generic) {
3626 // Resolving of generic function types is deferred to when
3627 // the function is instantiated.
3628 return;
3629 }
3630 for (0..info.param_types.len) |i| {
3631 const param_ty = info.param_types.get(ip)[i];
3632 try Type.fromInterned(param_ty).resolveLayout(pt);
3633 }
3634 try Type.fromInterned(info.return_type).resolveLayout(pt);
3635 },
3636 else => {},
3637 }
3638}
3639
3640pub fn resolveFields(ty: Type, pt: Zcu.PerThread) SemaError!void {
3641 const ip = &pt.zcu.intern_pool;
3642 const ty_ip = ty.toIntern();
3643
3644 switch (ty_ip) {
3645 .none => unreachable,
3646
3647 .u0_type,
3648 .i0_type,
3649 .u1_type,
3650 .u8_type,
3651 .i8_type,
3652 .u16_type,
3653 .i16_type,
3654 .u29_type,
3655 .u32_type,
3656 .i32_type,
3657 .u64_type,
3658 .i64_type,
3659 .u80_type,
3660 .u128_type,
3661 .i128_type,
3662 .usize_type,
3663 .isize_type,
3664 .c_char_type,
3665 .c_short_type,
3666 .c_ushort_type,
3667 .c_int_type,
3668 .c_uint_type,
3669 .c_long_type,
3670 .c_ulong_type,
3671 .c_longlong_type,
3672 .c_ulonglong_type,
3673 .c_longdouble_type,
3674 .f16_type,
3675 .f32_type,
3676 .f64_type,
3677 .f80_type,
3678 .f128_type,
3679 .anyopaque_type,
3680 .bool_type,
3681 .void_type,
3682 .type_type,
3683 .anyerror_type,
3684 .adhoc_inferred_error_set_type,
3685 .comptime_int_type,
3686 .comptime_float_type,
3687 .noreturn_type,
3688 .anyframe_type,
3689 .null_type,
3690 .undefined_type,
3691 .enum_literal_type,
3692 .ptr_usize_type,
3693 .ptr_const_comptime_int_type,
3694 .manyptr_u8_type,
3695 .manyptr_const_u8_type,
3696 .manyptr_const_u8_sentinel_0_type,
3697 .slice_const_u8_type,
3698 .slice_const_u8_sentinel_0_type,
3699 .optional_noreturn_type,
3700 .anyerror_void_error_union_type,
3701 .generic_poison_type,
3702 .empty_tuple_type,
3703 => {},
3704
3705 .undef => unreachable,
3706 .zero => unreachable,
3707 .zero_usize => unreachable,
3708 .zero_u1 => unreachable,
3709 .zero_u8 => unreachable,
3710 .one => unreachable,
3711 .one_usize => unreachable,
3712 .one_u1 => unreachable,
3713 .one_u8 => unreachable,
3714 .four_u8 => unreachable,
3715 .negative_one => unreachable,
3716 .void_value => unreachable,
3717 .unreachable_value => unreachable,
3718 .null_value => unreachable,
3719 .bool_true => unreachable,
3720 .bool_false => unreachable,
3721 .empty_tuple => unreachable,
3722
3723 else => switch (ty_ip.unwrap(ip).getTag(ip)) {
3724 .type_struct,
3725 .type_struct_packed,
3726 .type_struct_packed_inits,
3727 => return ty.resolveStructInner(pt, .fields),
3728
3729 .type_union => return ty.resolveUnionInner(pt, .fields),
3730
3731 else => {},
3732 },
3733 }
3734}
3735
3736pub fn resolveFully(ty: Type, pt: Zcu.PerThread) SemaError!void {
3737 const zcu = pt.zcu;
3738 const ip = &zcu.intern_pool;
3739
3740 switch (ty.zigTypeTag(zcu)) {
3741 .type,
3742 .void,
3743 .bool,
3744 .noreturn,
3745 .int,
3746 .float,
3747 .comptime_float,
3748 .comptime_int,
3749 .undefined,
3750 .null,
3751 .error_set,
3752 .@"enum",
3753 .@"opaque",
3754 .frame,
3755 .@"anyframe",
3756 .vector,
3757 .enum_literal,
3758 => {},
3759
3760 .pointer => return ty.childType(zcu).resolveFully(pt),
3761 .array => return ty.childType(zcu).resolveFully(pt),
3762 .optional => return ty.optionalChild(zcu).resolveFully(pt),
3763 .error_union => return ty.errorUnionPayload(zcu).resolveFully(pt),
3764 .@"fn" => {
3765 const info = zcu.typeToFunc(ty).?;
3766 if (info.is_generic) return;
3767 for (0..info.param_types.len) |i| {
3768 const param_ty = info.param_types.get(ip)[i];
3769 try Type.fromInterned(param_ty).resolveFully(pt);
3770 }
3771 try Type.fromInterned(info.return_type).resolveFully(pt);
3772 },
3773
3774 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
3775 .tuple_type => |tuple_type| for (0..tuple_type.types.len) |i| {
3776 const field_ty = Type.fromInterned(tuple_type.types.get(ip)[i]);
3777 try field_ty.resolveFully(pt);
3778 },
3779 .struct_type => return ty.resolveStructInner(pt, .full),
3780 else => unreachable,
3781 },
3782 .@"union" => return ty.resolveUnionInner(pt, .full),
3783 }
3784}
3785
3786pub fn resolveStructFieldInits(ty: Type, pt: Zcu.PerThread) SemaError!void {
3787 // TODO: stop calling this for tuples!
3788 _ = pt.zcu.typeToStruct(ty) orelse return;
3789 return ty.resolveStructInner(pt, .inits);
3790}
3791
3792pub fn resolveStructAlignment(ty: Type, pt: Zcu.PerThread) SemaError!void {
3793 return ty.resolveStructInner(pt, .alignment);
3794}
3795
3796pub fn resolveUnionAlignment(ty: Type, pt: Zcu.PerThread) SemaError!void {
3797 return ty.resolveUnionInner(pt, .alignment);
3798}
3799
3800/// `ty` must be a struct.
3801fn resolveStructInner(
3802 ty: Type,
3803 pt: Zcu.PerThread,
3804 resolution: enum { fields, inits, alignment, layout, full },
3805) SemaError!void {
3806 const zcu = pt.zcu;
3807 const gpa = zcu.gpa;
3808
3809 const struct_obj = zcu.typeToStruct(ty).?;
3810 const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
3811
3812 if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
3813 return error.AnalysisFail;
3814 }
3815
3816 if (zcu.comp.debugIncremental()) {
3817 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, owner);
3818 info.last_update_gen = zcu.generation;
3819 }
3820
3821 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3822 defer analysis_arena.deinit();
3823
3824 var comptime_err_ret_trace = std.array_list.Managed(Zcu.LazySrcLoc).init(gpa);
3825 defer comptime_err_ret_trace.deinit();
3826
3827 const zir = zcu.namespacePtr(struct_obj.namespace).fileScope(zcu).zir.?;
3828 var sema: Sema = .{
3829 .pt = pt,
3830 .gpa = gpa,
3831 .arena = analysis_arena.allocator(),
3832 .code = zir,
3833 .owner = owner,
3834 .func_index = .none,
3835 .func_is_naked = false,
3836 .fn_ret_ty = Type.void,
3837 .fn_ret_ty_ies = null,
3838 .comptime_err_ret_trace = &comptime_err_ret_trace,
3839 };
3840 defer sema.deinit();
3841
3842 (switch (resolution) {
3843 .fields => sema.resolveStructFieldTypes(ty.toIntern(), struct_obj),
3844 .inits => sema.resolveStructFieldInits(ty),
3845 .alignment => sema.resolveStructAlignment(ty.toIntern(), struct_obj),
3846 .layout => sema.resolveStructLayout(ty),
3847 .full => sema.resolveStructFully(ty),
3848 }) catch |err| switch (err) {
3849 error.AnalysisFail => {
3850 if (!zcu.failed_analysis.contains(owner)) {
3851 try zcu.transitive_failed_analysis.put(gpa, owner, {});
3852 }
3853 return error.AnalysisFail;
3854 },
3855 error.OutOfMemory, error.Canceled => |e| return e,
3856 };
3857}
3858
3859/// `ty` must be a union.
3860fn resolveUnionInner(
3861 ty: Type,
3862 pt: Zcu.PerThread,
3863 resolution: enum { fields, alignment, layout, full },
3864) SemaError!void {
3865 const zcu = pt.zcu;
3866 const gpa = zcu.gpa;
3867
3868 const union_obj = zcu.typeToUnion(ty).?;
3869 const owner: InternPool.AnalUnit = .wrap(.{ .type = ty.toIntern() });
3870
3871 if (zcu.failed_analysis.contains(owner) or zcu.transitive_failed_analysis.contains(owner)) {
3872 return error.AnalysisFail;
3873 }
3874
3875 if (zcu.comp.debugIncremental()) {
3876 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, owner);
3877 info.last_update_gen = zcu.generation;
3878 }
3879
3880 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3881 defer analysis_arena.deinit();
3882
3883 var comptime_err_ret_trace = std.array_list.Managed(Zcu.LazySrcLoc).init(gpa);
3884 defer comptime_err_ret_trace.deinit();
3885
3886 const zir = zcu.namespacePtr(union_obj.namespace).fileScope(zcu).zir.?;
3887 var sema: Sema = .{
3888 .pt = pt,
3889 .gpa = gpa,
3890 .arena = analysis_arena.allocator(),
3891 .code = zir,
3892 .owner = owner,
3893 .func_index = .none,
3894 .func_is_naked = false,
3895 .fn_ret_ty = Type.void,
3896 .fn_ret_ty_ies = null,
3897 .comptime_err_ret_trace = &comptime_err_ret_trace,
3898 };
3899 defer sema.deinit();
3900
3901 (switch (resolution) {
3902 .fields => sema.resolveUnionFieldTypes(ty, union_obj),
3903 .alignment => sema.resolveUnionAlignment(ty, union_obj),
3904 .layout => sema.resolveUnionLayout(ty),
3905 .full => sema.resolveUnionFully(ty),
3906 }) catch |err| switch (err) {
3907 error.AnalysisFail => {
3908 if (!zcu.failed_analysis.contains(owner)) {
3909 try zcu.transitive_failed_analysis.put(gpa, owner, {});
3910 }
3911 return error.AnalysisFail;
3912 },
3913 error.OutOfMemory => |e| return e,
3914 error.Canceled => |e| return e,
3915 };
3916}
3917
3918pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {2685pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout {
3919 const ip = &zcu.intern_pool;2686 const ip = &zcu.intern_pool;
3920 assert(loaded_union.haveLayout(ip));
3921 var most_aligned_field: u32 = 0;2687 var most_aligned_field: u32 = 0;
3922 var most_aligned_field_align: InternPool.Alignment = .@"1";2688 var most_aligned_field_align: InternPool.Alignment = .@"1";
3923 var most_aligned_field_size: u64 = 0;2689 var most_aligned_field_size: u64 = 0;
...@@ -3928,11 +2694,14 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -3928,11 +2694,14 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
3928 const field_ty: Type = .fromInterned(field_ty_ip_index);2694 const field_ty: Type = .fromInterned(field_ty_ip_index);
3929 if (field_ty.isNoReturn(zcu)) continue;2695 if (field_ty.isNoReturn(zcu)) continue;
39302696
3931 const explicit_align = loaded_union.fieldAlign(ip, field_index);2697 const field_align: InternPool.Alignment = a: {
3932 const field_align = if (explicit_align != .none)2698 const explicit_aligns = loaded_union.field_aligns.get(ip);
3933 explicit_align2699 if (explicit_aligns.len > 0) {
3934 else2700 const a = explicit_aligns[field_index];
3935 field_ty.abiAlignment(zcu);2701 if (a != .none) break :a a;
2702 }
2703 break :a field_ty.abiAlignment(zcu);
2704 };
3936 if (field_ty.hasRuntimeBits(zcu)) {2705 if (field_ty.hasRuntimeBits(zcu)) {
3937 const field_size = field_ty.abiSize(zcu);2706 const field_size = field_ty.abiSize(zcu);
3938 if (field_size > payload_size) {2707 if (field_size > payload_size) {
...@@ -3947,8 +2716,9 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -3947,8 +2716,9 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
3947 }2716 }
3948 payload_align = payload_align.max(field_align);2717 payload_align = payload_align.max(field_align);
3949 }2718 }
3950 const have_tag = loaded_union.flagsUnordered(ip).runtime_tag.hasTag();2719 if (loaded_union.runtime_tag == .none or
3951 if (!have_tag or !Type.fromInterned(loaded_union.enum_tag_ty).hasRuntimeBits(zcu)) {2720 !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu))
2721 {
3952 return .{2722 return .{
3953 .abi_size = payload_align.forward(payload_size),2723 .abi_size = payload_align.forward(payload_size),
3954 .abi_align = payload_align,2724 .abi_align = payload_align,
...@@ -3963,10 +2733,10 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -3963,10 +2733,10 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
3963 };2733 };
3964 }2734 }
39652735
3966 const tag_size = Type.fromInterned(loaded_union.enum_tag_ty).abiSize(zcu);2736 const tag_size = Type.fromInterned(loaded_union.enum_tag_type).abiSize(zcu);
3967 const tag_align = Type.fromInterned(loaded_union.enum_tag_ty).abiAlignment(zcu).max(.@"1");2737 const tag_align = Type.fromInterned(loaded_union.enum_tag_type).abiAlignment(zcu).max(.@"1");
3968 return .{2738 return .{
3969 .abi_size = loaded_union.sizeUnordered(ip),2739 .abi_size = loaded_union.size,
3970 .abi_align = tag_align.max(payload_align),2740 .abi_align = tag_align.max(payload_align),
3971 .most_aligned_field = most_aligned_field,2741 .most_aligned_field = most_aligned_field,
3972 .most_aligned_field_size = most_aligned_field_size,2742 .most_aligned_field_size = most_aligned_field_size,
...@@ -3975,7 +2745,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -3975,7 +2745,7 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
3975 .payload_align = payload_align,2745 .payload_align = payload_align,
3976 .tag_align = tag_align,2746 .tag_align = tag_align,
3977 .tag_size = tag_size,2747 .tag_size = tag_size,
3978 .padding = loaded_union.paddingUnordered(ip),2748 .padding = loaded_union.padding,
3979 };2749 };
3980}2750}
39812751
...@@ -3989,10 +2759,17 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)...@@ -3989,10 +2759,17 @@ pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu)
3989/// Handles const-ness and address spaces in particular.2759/// Handles const-ness and address spaces in particular.
3990/// This code is duplicated in `Sema.analyzePtrArithmetic`.2760/// This code is duplicated in `Sema.analyzePtrArithmetic`.
3991/// May perform type resolution and return a transitive `error.AnalysisFail`.2761/// May perform type resolution and return a transitive `error.AnalysisFail`.
2762/// MLUGG TODO audit this shit
3992pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {2763pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
3993 const zcu = pt.zcu;2764 const zcu = pt.zcu;
3994 const ptr_info = ptr_ty.ptrInfo(zcu);2765 const ptr_info = ptr_ty.ptrInfo(zcu);
3995 const elem_ty = ptr_ty.elemType2(zcu);2766 const elem_ty: Type = switch (ptr_info.flags.size) {
2767 .one => switch (Type.fromInterned(ptr_info.child).zigTypeTag(zcu)) {
2768 .array, .vector => Type.fromInterned(ptr_info.child).childType(zcu),
2769 else => .fromInterned(ptr_info.child),
2770 },
2771 .many, .c, .slice => .fromInterned(ptr_info.child),
2772 };
3996 const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0;2773 const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0;
3997 const parent_ty = ptr_ty.childType(zcu);2774 const parent_ty = ptr_ty.childType(zcu);
39982775
...@@ -4024,7 +2801,7 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {...@@ -4024,7 +2801,7 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
4024 }2801 }
4025 // If the addend is not a comptime-known value we can still count on2802 // If the addend is not a comptime-known value we can still count on
4026 // it being a multiple of the type size.2803 // it being a multiple of the type size.
4027 const elem_size = (try elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar;2804 const elem_size = elem_ty.abiSize(zcu);
4028 const addend = if (offset) |off| elem_size * off else elem_size;2805 const addend = if (offset) |off| elem_size * off else elem_size;
40292806
4030 // The resulting pointer is aligned to the lcd between the offset (an2807 // The resulting pointer is aligned to the lcd between the offset (an
...@@ -4037,7 +2814,7 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {...@@ -4037,7 +2814,7 @@ pub fn elemPtrType(ptr_ty: Type, offset: ?usize, pt: Zcu.PerThread) !Type {
4037 assert(new_align != .none);2814 assert(new_align != .none);
4038 break :a new_align;2815 break :a new_align;
4039 };2816 };
4040 return pt.ptrTypeSema(.{2817 return pt.ptrType(.{
4041 .child = elem_ty.toIntern(),2818 .child = elem_ty.toIntern(),
4042 .flags = .{2819 .flags = .{
4043 .alignment = alignment,2820 .alignment = alignment,
...@@ -4069,11 +2846,107 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina...@@ -4069,11 +2846,107 @@ pub fn containerTypeName(ty: Type, ip: *const InternPool) InternPool.NullTermina
4069/// Returns `null` otherwise.2846/// Returns `null` otherwise.
4070pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {2847pub fn isNullFromType(ty: Type, zcu: *const Zcu) ?bool {
4071 if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;2848 if (ty.zigTypeTag(zcu) != .optional and !ty.isCPtr(zcu)) return false;
4072 const child = ty.optionalChild(zcu);2849 if (ty.optionalChild(zcu).isNoReturn(zcu)) return true; // `?noreturn` is always null
4073 if (child.zigTypeTag(zcu) == .noreturn) return true; // `?noreturn` is always null
4074 return null;2850 return null;
4075}2851}
40762852
2853/// Returns true if `ty` is allowed in packed types.
2854pub fn packable(ty: Type, zcu: *const Zcu) bool {
2855 return switch (ty.zigTypeTag(zcu)) {
2856 .type,
2857 .comptime_float,
2858 .comptime_int,
2859 .enum_literal,
2860 .undefined,
2861 .null,
2862 .error_union,
2863 .error_set,
2864 .frame,
2865 .noreturn,
2866 .@"opaque",
2867 .@"anyframe",
2868 .@"fn",
2869 .array,
2870 => false,
2871 .optional => return ty.isPtrLikeOptional(zcu),
2872 .void,
2873 .bool,
2874 .float,
2875 .int,
2876 .vector,
2877 => true,
2878 .@"enum" => zcu.intern_pool.loadEnumType(ty.toIntern()).int_tag_is_explicit,
2879 .pointer => !ty.isSlice(zcu),
2880 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed",
2881 };
2882}
2883
2884/// Asserts that `ty` has resolved layout.
2885pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void {
2886 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
2887 .int_type,
2888 .ptr_type,
2889 .anyframe_type,
2890 .simple_type,
2891 .opaque_type,
2892 .enum_type,
2893 .error_set_type,
2894 .inferred_error_set_type,
2895 => {},
2896 .func_type => |func_type| {
2897 for (func_type.param_types.get(&zcu.intern_pool)) |param_ty| {
2898 assertHasLayout(.fromInterned(param_ty), zcu);
2899 }
2900 assertHasLayout(.fromInterned(func_type.return_type), zcu);
2901 },
2902 .array_type => |arr| assertHasLayout(.fromInterned(arr.child), zcu),
2903 .vector_type => |vec| assertHasLayout(.fromInterned(vec.child), zcu),
2904 .opt_type => |child| assertHasLayout(.fromInterned(child), zcu),
2905 .error_union_type => |eu| assertHasLayout(.fromInterned(eu.payload_type), zcu),
2906 .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| {
2907 assertHasLayout(.fromInterned(field_ty), zcu);
2908 },
2909 .struct_type, .union_type => {
2910 const unit: InternPool.AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });
2911 assert(!zcu.outdated.contains(unit));
2912 assert(!zcu.potentially_outdated.contains(unit));
2913 },
2914 else => unreachable, // assertion failure; not a struct or union
2915
2916 // values, not types
2917 .simple_value,
2918 .variable,
2919 .@"extern",
2920 .func,
2921 .int,
2922 .err,
2923 .error_union,
2924 .enum_literal,
2925 .enum_tag,
2926 .empty_enum_value,
2927 .float,
2928 .ptr,
2929 .slice,
2930 .opt,
2931 .aggregate,
2932 .un,
2933 // memoization, not types
2934 .memoized_call,
2935 => unreachable,
2936 }
2937}
2938
2939/// Asserts that `ty` is an enum or struct type whose field values/defaults are resolved.
2940pub fn assertHasInits(ty: Type, zcu: *const Zcu) void {
2941 switch (zcu.intern_pool.indexToKey(ty.toIntern())) {
2942 .struct_type, .enum_type => {},
2943 else => unreachable,
2944 }
2945 const unit: InternPool.AnalUnit = .wrap(.{ .type_inits = ty.toIntern() });
2946 assert(!zcu.outdated.contains(unit));
2947 assert(!zcu.potentially_outdated.contains(unit));
2948}
2949
4077/// Recursively walks the type and marks for each subtype how many times it has been seen2950/// Recursively walks the type and marks for each subtype how many times it has been seen
4078fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void {2951fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.AutoArrayHashMapUnmanaged(Type, u16)) error{OutOfMemory}!void {
4079 const zcu = pt.zcu;2952 const zcu = pt.zcu;
src/Value.zig+145-642
...@@ -146,80 +146,22 @@ pub fn toType(self: Value) Type {...@@ -146,80 +146,22 @@ pub fn toType(self: Value) Type {
146 return Type.fromInterned(self.toIntern());146 return Type.fromInterned(self.toIntern());
147}147}
148148
149pub fn intFromEnum(val: Value, ty: Type, pt: Zcu.PerThread) Allocator.Error!Value {149pub fn intFromEnum(val: Value, zcu: *const Zcu) Value {
150 const ip = &pt.zcu.intern_pool;150 return .fromInterned(zcu.intern_pool.indexToKey(val.toIntern()).enum_tag.int);
151 const enum_ty = ip.typeOf(val.toIntern());
152 return switch (ip.indexToKey(enum_ty)) {
153 // Assume it is already an integer and return it directly.
154 .simple_type, .int_type => val,
155 .enum_literal => |enum_literal| {
156 const field_index = ty.enumFieldIndex(enum_literal, pt.zcu).?;
157 switch (ip.indexToKey(ty.toIntern())) {
158 // Assume it is already an integer and return it directly.
159 .simple_type, .int_type => return val,
160 .enum_type => {
161 const enum_type = ip.loadEnumType(ty.toIntern());
162 if (enum_type.values.len != 0) {
163 return Value.fromInterned(enum_type.values.get(ip)[field_index]);
164 } else {
165 // Field index and integer values are the same.
166 return pt.intValue(Type.fromInterned(enum_type.tag_ty), field_index);
167 }
168 },
169 else => unreachable,
170 }
171 },
172 .enum_type => try pt.getCoerced(val, Type.fromInterned(ip.loadEnumType(enum_ty).tag_ty)),
173 else => unreachable,
174 };
175}151}
176152
177pub const ResolveStrat = Type.ResolveStrat;153/// Asserts that `val` is an integer.
178
179/// Asserts the value is an integer.
180pub fn toBigInt(val: Value, space: *BigIntSpace, zcu: *Zcu) BigIntConst {154pub fn toBigInt(val: Value, space: *BigIntSpace, zcu: *Zcu) BigIntConst {
181 return val.toBigIntAdvanced(space, .normal, zcu, {}) catch unreachable;155 if (val.getUnsignedInt(zcu)) |x| {
182}156 return BigIntMutable.init(&space.limbs, x).toConst();
183157 }
184pub fn toBigIntSema(val: Value, space: *BigIntSpace, pt: Zcu.PerThread) !BigIntConst {
185 return try val.toBigIntAdvanced(space, .sema, pt.zcu, pt.tid);
186}
187
188/// Asserts the value is an integer.
189pub fn toBigIntAdvanced(
190 val: Value,
191 space: *BigIntSpace,
192 comptime strat: ResolveStrat,
193 zcu: *Zcu,
194 tid: strat.Tid(),
195) Zcu.SemaError!BigIntConst {
196 const ip = &zcu.intern_pool;158 const ip = &zcu.intern_pool;
197 return switch (val.toIntern()) {159 const int_key = switch (ip.indexToKey(val.toIntern())) {
198 .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),160 .enum_tag => |enum_tag| ip.indexToKey(enum_tag.int).int,
199 .bool_true => BigIntMutable.init(&space.limbs, 1).toConst(),161 .int => |int| int,
200 .null_value => BigIntMutable.init(&space.limbs, 0).toConst(),162 else => unreachable,
201 else => switch (ip.indexToKey(val.toIntern())) {
202 .int => |int| switch (int.storage) {
203 .u64, .i64, .big_int => int.storage.toBigInt(space),
204 .lazy_align, .lazy_size => |ty| {
205 if (strat == .sema) try Type.fromInterned(ty).resolveLayout(strat.pt(zcu, tid));
206 const x = switch (int.storage) {
207 else => unreachable,
208 .lazy_align => Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0,
209 .lazy_size => Type.fromInterned(ty).abiSize(zcu),
210 };
211 return BigIntMutable.init(&space.limbs, x).toConst();
212 },
213 },
214 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, strat, zcu, tid),
215 .opt, .ptr => BigIntMutable.init(
216 &space.limbs,
217 (try val.getUnsignedIntInner(strat, zcu, tid)).?,
218 ).toConst(),
219 .err => |err| BigIntMutable.init(&space.limbs, ip.getErrorValueIfExists(err.name).?).toConst(),
220 else => unreachable,
221 },
222 };163 };
164 return int_key.storage.toBigInt(space);
223}165}
224166
225pub fn isFuncBody(val: Value, zcu: *Zcu) bool {167pub fn isFuncBody(val: Value, zcu: *Zcu) bool {
...@@ -240,31 +182,17 @@ pub fn getVariable(val: Value, mod: *Zcu) ?InternPool.Key.Variable {...@@ -240,31 +182,17 @@ pub fn getVariable(val: Value, mod: *Zcu) ?InternPool.Key.Variable {
240 };182 };
241}183}
242184
243/// If the value fits in a u64, return it, otherwise null.185/// Asserts the value is a (defined) integer and it fits in a u64.
244/// Asserts not undefined.
245pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 {
246 return getUnsignedIntInner(val, .normal, zcu, {}) catch unreachable;
247}
248
249/// Asserts the value is an integer and it fits in a u64
250pub fn toUnsignedInt(val: Value, zcu: *const Zcu) u64 {186pub fn toUnsignedInt(val: Value, zcu: *const Zcu) u64 {
251 return getUnsignedInt(val, zcu).?;187 return getUnsignedInt(val, zcu).?;
252}188}
253189
254pub fn getUnsignedIntSema(val: Value, pt: Zcu.PerThread) !?u64 {
255 return try val.getUnsignedIntInner(.sema, pt.zcu, pt.tid);
256}
257
258/// If the value fits in a u64, return it, otherwise null.190/// If the value fits in a u64, return it, otherwise null.
259/// Asserts not undefined.191/// Asserts not undefined.
260pub fn getUnsignedIntInner(192pub fn getUnsignedInt(val: Value, zcu: *const Zcu) ?u64 {
261 val: Value,
262 comptime strat: ResolveStrat,
263 zcu: strat.ZcuPtr(),
264 tid: strat.Tid(),
265) !?u64 {
266 return switch (val.toIntern()) {193 return switch (val.toIntern()) {
267 .undef => unreachable,194 .undef => unreachable,
195 .null_value => 0,
268 .bool_false => 0,196 .bool_false => 0,
269 .bool_true => 1,197 .bool_true => 1,
270 else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {198 else => switch (zcu.intern_pool.indexToKey(val.toIntern())) {
...@@ -273,37 +201,27 @@ pub fn getUnsignedIntInner(...@@ -273,37 +201,27 @@ pub fn getUnsignedIntInner(
273 .big_int => |big_int| big_int.toInt(u64) catch null,201 .big_int => |big_int| big_int.toInt(u64) catch null,
274 .u64 => |x| x,202 .u64 => |x| x,
275 .i64 => |x| std.math.cast(u64, x),203 .i64 => |x| std.math.cast(u64, x),
276 .lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), zcu, tid)).scalar.toByteUnits() orelse 0,
277 .lazy_size => |ty| (try Type.fromInterned(ty).abiSizeInner(strat.toLazy(), zcu, tid)).scalar,
278 },204 },
279 .ptr => |ptr| switch (ptr.base_addr) {205 .ptr => |ptr| switch (ptr.base_addr) {
280 .int => ptr.byte_offset,206 .int => ptr.byte_offset,
281 .field => |field| {207 .field => |field| {
282 const base_addr = (try Value.fromInterned(field.base).getUnsignedIntInner(strat, zcu, tid)) orelse return null;208 const base_addr = Value.fromInterned(field.base).getUnsignedInt(zcu) orelse return null;
283 const struct_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);209 const struct_ty = Value.fromInterned(field.base).typeOf(zcu).childType(zcu);
284 if (strat == .sema) {
285 const pt = strat.pt(zcu, tid);
286 try struct_ty.resolveLayout(pt);
287 }
288 return base_addr + struct_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset;210 return base_addr + struct_ty.structFieldOffset(@intCast(field.index), zcu) + ptr.byte_offset;
289 },211 },
290 else => null,212 else => null,
291 },213 },
292 .opt => |opt| switch (opt.val) {214 .opt => |opt| switch (opt.val) {
293 .none => 0,215 .none => 0,
294 else => |payload| Value.fromInterned(payload).getUnsignedIntInner(strat, zcu, tid),216 else => |payload| Value.fromInterned(payload).getUnsignedInt(zcu),
295 },217 },
296 .enum_tag => |enum_tag| return Value.fromInterned(enum_tag.int).getUnsignedIntInner(strat, zcu, tid),218 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).getUnsignedInt(zcu),
219 .err => |err| zcu.intern_pool.getErrorValueIfExists(err.name).?,
297 else => null,220 else => null,
298 },221 },
299 };222 };
300}223}
301224
302/// Asserts the value is an integer and it fits in a u64
303pub fn toUnsignedIntSema(val: Value, pt: Zcu.PerThread) !u64 {
304 return (try getUnsignedIntInner(val, .sema, pt.zcu, pt.tid)).?;
305}
306
307/// Asserts the value is an integer and it fits in a i64225/// Asserts the value is an integer and it fits in a i64
308pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {226pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {
309 return switch (val.toIntern()) {227 return switch (val.toIntern()) {
...@@ -314,8 +232,6 @@ pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {...@@ -314,8 +232,6 @@ pub fn toSignedInt(val: Value, zcu: *const Zcu) i64 {
314 .big_int => |big_int| big_int.toInt(i64) catch unreachable,232 .big_int => |big_int| big_int.toInt(i64) catch unreachable,
315 .i64 => |x| x,233 .i64 => |x| x,
316 .u64 => |x| @intCast(x),234 .u64 => |x| @intCast(x),
317 .lazy_align => |ty| @intCast(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
318 .lazy_size => |ty| @intCast(Type.fromInterned(ty).abiSize(zcu)),
319 },235 },
320 else => unreachable,236 else => unreachable,
321 },237 },
...@@ -487,22 +403,16 @@ pub fn writeToPackedMemory(...@@ -487,22 +403,16 @@ pub fn writeToPackedMemory(
487 buffer[byte_index] &= ~(@as(u8, 1) << @as(u3, @intCast(bit_offset % 8)));403 buffer[byte_index] &= ~(@as(u8, 1) << @as(u3, @intCast(bit_offset % 8)));
488 }404 }
489 },405 },
490 .int, .@"enum" => {406 .@"enum" => {
491 if (buffer.len == 0) return;407 const int_val = val.intFromEnum(zcu);
408 return int_val.writeToPackedMemory(int_val.typeOf(zcu), pt, buffer, bit_offset);
409 },
410 .int => {
492 const bits = ty.intInfo(zcu).bits;411 const bits = ty.intInfo(zcu).bits;
493 if (bits == 0) return;412 if (bits == 0 or buffer.len == 0) return;
494413 switch (ip.indexToKey(val.toIntern()).int.storage) {
495 switch (ip.indexToKey((try val.intFromEnum(ty, pt)).toIntern()).int.storage) {
496 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),414 inline .u64, .i64 => |int| std.mem.writeVarPackedInt(buffer, bit_offset, bits, int, endian),
497 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),415 .big_int => |bigint| bigint.writePackedTwosComplement(buffer, bit_offset, bits, endian),
498 .lazy_align => |lazy_align| {
499 const num = Type.fromInterned(lazy_align).abiAlignment(zcu).toByteUnits() orelse 0;
500 std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
501 },
502 .lazy_size => |lazy_size| {
503 const num = Type.fromInterned(lazy_size).abiSize(zcu);
504 std.mem.writeVarPackedInt(buffer, bit_offset, bits, num, endian);
505 },
506 }416 }
507 },417 },
508 .float => switch (ty.floatBits(target)) {418 .float => switch (ty.floatBits(target)) {
...@@ -548,19 +458,15 @@ pub fn writeToPackedMemory(...@@ -548,19 +458,15 @@ pub fn writeToPackedMemory(
548 },458 },
549 .@"union" => {459 .@"union" => {
550 const union_obj = zcu.typeToUnion(ty).?;460 const union_obj = zcu.typeToUnion(ty).?;
551 switch (union_obj.flagsUnordered(ip).layout) {461 assert(union_obj.layout == .@"packed");
552 .auto, .@"extern" => unreachable, // Handled in non-packed writeToMemory462 if (val.unionTag(zcu)) |union_tag| {
553 .@"packed" => {463 const field_index = zcu.unionTagFieldIndex(union_obj, union_tag).?;
554 if (val.unionTag(zcu)) |union_tag| {464 const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
555 const field_index = zcu.unionTagFieldIndex(union_obj, union_tag).?;465 const field_val = try val.fieldValue(pt, field_index);
556 const field_type = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);466 return field_val.writeToPackedMemory(field_type, pt, buffer, bit_offset);
557 const field_val = try val.fieldValue(pt, field_index);467 } else {
558 return field_val.writeToPackedMemory(field_type, pt, buffer, bit_offset);468 const backing_ty = try ty.unionBackingType(pt);
559 } else {469 return val.unionValue(zcu).writeToPackedMemory(backing_ty, pt, buffer, bit_offset);
560 const backing_ty = try ty.unionBackingType(pt);
561 return val.unionValue(zcu).writeToPackedMemory(backing_ty, pt, buffer, bit_offset);
562 }
563 },
564 }470 }
565 },471 },
566 .pointer => {472 .pointer => {
...@@ -729,24 +635,15 @@ pub fn readFromPackedMemory(...@@ -729,24 +635,15 @@ pub fn readFromPackedMemory(
729 },635 },
730 .pointer => {636 .pointer => {
731 assert(!ty.isSlice(zcu)); // No well defined layout.637 assert(!ty.isSlice(zcu)); // No well defined layout.
732 const int_val = try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena);638 const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu);
733 return Value.fromInterned(try pt.intern(.{ .ptr = .{639 return pt.ptrIntValue(ty, addr);
734 .ty = ty.toIntern(),
735 .base_addr = .int,
736 .byte_offset = int_val.toUnsignedInt(zcu),
737 } }));
738 },640 },
739 .optional => {641 .optional => {
740 assert(ty.isPtrLikeOptional(zcu));642 assert(ty.isPtrLikeOptional(zcu));
741 const child_ty = ty.optionalChild(zcu);643 const addr = (try readFromPackedMemory(Type.usize, pt, buffer, bit_offset, arena)).toUnsignedInt(zcu);
742 const child_val = try readFromPackedMemory(child_ty, pt, buffer, bit_offset, arena);
743 return Value.fromInterned(try pt.intern(.{ .opt = .{644 return Value.fromInterned(try pt.intern(.{ .opt = .{
744 .ty = ty.toIntern(),645 .ty = ty.toIntern(),
745 .val = switch (child_val.orderAgainstZero(zcu)) {646 .val = (try pt.ptrIntValue(ty.childType(zcu), addr)).toIntern(),
746 .lt => unreachable,
747 .eq => .none,
748 .gt => child_val.toIntern(),
749 },
750 } }));647 } }));
751 },648 },
752 else => @panic("TODO implement readFromPackedMemory for more types"),649 else => @panic("TODO implement readFromPackedMemory for more types"),
...@@ -764,8 +661,6 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T {...@@ -764,8 +661,6 @@ pub fn toFloat(val: Value, comptime T: type, zcu: *const Zcu) T {
764 }661 }
765 return @floatFromInt(x);662 return @floatFromInt(x);
766 },663 },
767 .lazy_align => |ty| @floatFromInt(Type.fromInterned(ty).abiAlignment(zcu).toByteUnits() orelse 0),
768 .lazy_size => |ty| @floatFromInt(Type.fromInterned(ty).abiSize(zcu)),
769 },664 },
770 .float => |float| switch (float.storage) {665 .float => |float| switch (float.storage) {
771 inline else => |x| @floatCast(x),666 inline else => |x| @floatCast(x),
...@@ -819,110 +714,8 @@ pub fn floatCast(val: Value, dest_ty: Type, pt: Zcu.PerThread) !Value {...@@ -819,110 +714,8 @@ pub fn floatCast(val: Value, dest_ty: Type, pt: Zcu.PerThread) !Value {
819 } }));714 } }));
820}715}
821716
822pub fn orderAgainstZero(lhs: Value, zcu: *Zcu) std.math.Order {717/// Asserts the value is comparable. Supports comparisons between heterogeneous types.
823 return orderAgainstZeroInner(lhs, .normal, zcu, {}) catch unreachable;
824}
825
826pub fn orderAgainstZeroSema(lhs: Value, pt: Zcu.PerThread) !std.math.Order {
827 return try orderAgainstZeroInner(lhs, .sema, pt.zcu, pt.tid);
828}
829
830pub fn orderAgainstZeroInner(
831 lhs: Value,
832 comptime strat: ResolveStrat,
833 zcu: *Zcu,
834 tid: strat.Tid(),
835) Zcu.SemaError!std.math.Order {
836 return switch (lhs.toIntern()) {
837 .bool_false => .eq,
838 .bool_true => .gt,
839 else => switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
840 .ptr => |ptr| if (ptr.byte_offset > 0) .gt else switch (ptr.base_addr) {
841 .nav, .comptime_alloc, .comptime_field => .gt,
842 .int => .eq,
843 else => unreachable,
844 },
845 .int => |int| switch (int.storage) {
846 .big_int => |big_int| big_int.orderAgainstScalar(0),
847 inline .u64, .i64 => |x| std.math.order(x, 0),
848 .lazy_align => .gt, // alignment is never 0
849 .lazy_size => |ty| return if (Type.fromInterned(ty).hasRuntimeBitsInner(
850 false,
851 strat.toLazy(),
852 zcu,
853 tid,
854 ) catch |err| switch (err) {
855 error.NeedLazy => unreachable,
856 else => |e| return e,
857 }) .gt else .eq,
858 },
859 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroInner(strat, zcu, tid),
860 .float => |float| switch (float.storage) {
861 inline else => |x| std.math.order(x, 0),
862 },
863 .err => .gt, // error values cannot be 0
864 else => unreachable,
865 },
866 };
867}
868
869/// Asserts the value is comparable.
870pub fn order(lhs: Value, rhs: Value, zcu: *Zcu) std.math.Order {
871 return orderAdvanced(lhs, rhs, .normal, zcu, {}) catch unreachable;
872}
873
874/// Asserts the value is comparable.
875pub fn orderAdvanced(
876 lhs: Value,
877 rhs: Value,
878 comptime strat: ResolveStrat,
879 zcu: *Zcu,
880 tid: strat.Tid(),
881) !std.math.Order {
882 const lhs_against_zero = try lhs.orderAgainstZeroInner(strat, zcu, tid);
883 const rhs_against_zero = try rhs.orderAgainstZeroInner(strat, zcu, tid);
884 switch (lhs_against_zero) {
885 .lt => if (rhs_against_zero != .lt) return .lt,
886 .eq => return rhs_against_zero.invert(),
887 .gt => {},
888 }
889 switch (rhs_against_zero) {
890 .lt => if (lhs_against_zero != .lt) return .gt,
891 .eq => return lhs_against_zero,
892 .gt => {},
893 }
894
895 if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) {
896 const lhs_f128 = lhs.toFloat(f128, zcu);
897 const rhs_f128 = rhs.toFloat(f128, zcu);
898 return std.math.order(lhs_f128, rhs_f128);
899 }
900
901 var lhs_bigint_space: BigIntSpace = undefined;
902 var rhs_bigint_space: BigIntSpace = undefined;
903 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, strat, zcu, tid);
904 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, strat, zcu, tid);
905 return lhs_bigint.order(rhs_bigint);
906}
907
908/// Asserts the value is comparable. Does not take a type parameter because it supports
909/// comparisons between heterogeneous types.
910pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, zcu: *Zcu) bool {718pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, zcu: *Zcu) bool {
911 return compareHeteroAdvanced(lhs, op, rhs, .normal, zcu, {}) catch unreachable;
912}
913
914pub fn compareHeteroSema(lhs: Value, op: std.math.CompareOperator, rhs: Value, pt: Zcu.PerThread) !bool {
915 return try compareHeteroAdvanced(lhs, op, rhs, .sema, pt.zcu, pt.tid);
916}
917
918pub fn compareHeteroAdvanced(
919 lhs: Value,
920 op: std.math.CompareOperator,
921 rhs: Value,
922 comptime strat: ResolveStrat,
923 zcu: *Zcu,
924 tid: strat.Tid(),
925) !bool {
926 if (lhs.pointerNav(zcu)) |lhs_nav| {719 if (lhs.pointerNav(zcu)) |lhs_nav| {
927 if (rhs.pointerNav(zcu)) |rhs_nav| {720 if (rhs.pointerNav(zcu)) |rhs_nav| {
928 switch (op) {721 switch (op) {
...@@ -944,9 +737,21 @@ pub fn compareHeteroAdvanced(...@@ -944,9 +737,21 @@ pub fn compareHeteroAdvanced(
944 else => {},737 else => {},
945 }738 }
946 }739 }
947
948 if (lhs.isNan(zcu) or rhs.isNan(zcu)) return op == .neq;740 if (lhs.isNan(zcu) or rhs.isNan(zcu)) return op == .neq;
949 return (try orderAdvanced(lhs, rhs, strat, zcu, tid)).compare(op);741 return order(lhs, rhs, zcu).compare(op);
742}
743
744pub fn order(lhs: Value, rhs: Value, zcu: *Zcu) std.math.Order {
745 if (lhs.isFloat(zcu) or rhs.isFloat(zcu)) {
746 const lhs_f128 = lhs.toFloat(f128, zcu);
747 const rhs_f128 = rhs.toFloat(f128, zcu);
748 return std.math.order(lhs_f128, rhs_f128);
749 }
750 var lhs_bigint_space: BigIntSpace = undefined;
751 var rhs_bigint_space: BigIntSpace = undefined;
752 const lhs_bigint = lhs.toBigInt(&lhs_bigint_space, zcu);
753 const rhs_bigint = rhs.toBigInt(&rhs_bigint_space, zcu);
754 return lhs_bigint.order(rhs_bigint);
950}755}
951756
952/// Asserts the values are comparable. Both operands have type `ty`.757/// Asserts the values are comparable. Both operands have type `ty`.
...@@ -987,56 +792,32 @@ pub fn compareScalar(...@@ -987,56 +792,32 @@ pub fn compareScalar(
987/// Returns `false` if the value or any vector element is undefined.792/// Returns `false` if the value or any vector element is undefined.
988///793///
989/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`794/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
795/// TODO MLUGG: lowkey wanna delete this
990pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool {796pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, zcu: *Zcu) bool {
991 return compareAllWithZeroAdvancedExtra(lhs, op, .normal, zcu, {}) catch unreachable;797 return switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
992}
993
994pub fn compareAllWithZeroSema(
995 lhs: Value,
996 op: std.math.CompareOperator,
997 pt: Zcu.PerThread,
998) Zcu.CompileError!bool {
999 return compareAllWithZeroAdvancedExtra(lhs, op, .sema, pt.zcu, pt.tid);
1000}
1001
1002pub fn compareAllWithZeroAdvancedExtra(
1003 lhs: Value,
1004 op: std.math.CompareOperator,
1005 comptime strat: ResolveStrat,
1006 zcu: *Zcu,
1007 tid: strat.Tid(),
1008) Zcu.CompileError!bool {
1009 if (lhs.isInf(zcu)) {
1010 switch (op) {
1011 .neq => return true,
1012 .eq => return false,
1013 .gt, .gte => return !lhs.isNegativeInf(zcu),
1014 .lt, .lte => return lhs.isNegativeInf(zcu),
1015 }
1016 }
1017
1018 switch (zcu.intern_pool.indexToKey(lhs.toIntern())) {
1019 .float => |float| switch (float.storage) {798 .float => |float| switch (float.storage) {
1020 inline else => |x| if (std.math.isNan(x)) return op == .neq,799 inline else => |x| std.math.compare(x, op, 0),
1021 },800 },
1022 .aggregate => |aggregate| return switch (aggregate.storage) {801 .aggregate => |aggregate| switch (aggregate.storage) {
1023 .bytes => |bytes| for (bytes.toSlice(lhs.typeOf(zcu).arrayLenIncludingSentinel(zcu), &zcu.intern_pool)) |byte| {802 .bytes => |bytes| for (bytes.toSlice(
1024 if (!std.math.order(byte, 0).compare(op)) break false;803 lhs.typeOf(zcu).arrayLenIncludingSentinel(zcu),
804 &zcu.intern_pool,
805 )) |byte| {
806 if (!std.math.compare(byte, op, 0)) break false;
1025 } else true,807 } else true,
1026 .elems => |elems| for (elems) |elem| {808 .elems => |elems| for (elems) |elem| {
1027 if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, strat, zcu, tid)) break false;809 if (!Value.fromInterned(elem).compareAllWithZero(op, zcu)) break false;
1028 } else true,810 } else true,
1029 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, strat, zcu, tid),811 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZero(op, zcu),
1030 },812 },
1031 .undef => return false,813 .undef => false,
1032 else => {},814 else => order(lhs, .zero_comptime_int, zcu).compare(op),
1033 }815 };
1034 return (try orderAgainstZeroInner(lhs, strat, zcu, tid)).compare(op);
1035}816}
1036817
1037pub fn eql(a: Value, b: Value, ty: Type, zcu: *Zcu) bool {818pub fn eql(a: Value, b: Value, ty: Type, zcu: *Zcu) bool {
1038 assert(zcu.intern_pool.typeOf(a.toIntern()) == ty.toIntern());819 assert(a.typeOf(zcu).toIntern() == ty.toIntern());
1039 assert(zcu.intern_pool.typeOf(b.toIntern()) == ty.toIntern());820 assert(b.typeOf(zcu).toIntern() == ty.toIntern());
1040 return a.toIntern() == b.toIntern();821 return a.toIntern() == b.toIntern();
1041}822}
1042823
...@@ -1088,16 +869,13 @@ pub fn pointerNav(val: Value, zcu: *Zcu) ?InternPool.Nav.Index {...@@ -1088,16 +869,13 @@ pub fn pointerNav(val: Value, zcu: *Zcu) ?InternPool.Nav.Index {
1088pub const slice_ptr_index = 0;869pub const slice_ptr_index = 0;
1089pub const slice_len_index = 1;870pub const slice_len_index = 1;
1090871
872pub fn sliceLen(val: Value, zcu: *Zcu) u64 {
873 return Value.fromInterned(zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedInt(zcu);
874}
1091pub fn slicePtr(val: Value, zcu: *Zcu) Value {875pub fn slicePtr(val: Value, zcu: *Zcu) Value {
1092 return Value.fromInterned(zcu.intern_pool.slicePtr(val.toIntern()));876 return Value.fromInterned(zcu.intern_pool.slicePtr(val.toIntern()));
1093}877}
1094878
1095/// Gets the `len` field of a slice value as a `u64`.
1096/// Resolves the length using `Sema` if necessary.
1097pub fn sliceLen(val: Value, pt: Zcu.PerThread) !u64 {
1098 return Value.fromInterned(pt.zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedIntSema(pt);
1099}
1100
1101/// Asserts the value is an aggregate, and returns the element value at the given index.879/// Asserts the value is an aggregate, and returns the element value at the given index.
1102pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Value {880pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Value {
1103 const zcu = pt.zcu;881 const zcu = pt.zcu;
...@@ -1123,62 +901,6 @@ pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Va...@@ -1123,62 +901,6 @@ pub fn elemValue(val: Value, pt: Zcu.PerThread, index: usize) Allocator.Error!Va
1123 }901 }
1124}902}
1125903
1126pub fn isLazyAlign(val: Value, zcu: *Zcu) bool {
1127 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
1128 .int => |int| int.storage == .lazy_align,
1129 else => false,
1130 };
1131}
1132
1133pub fn isLazySize(val: Value, zcu: *Zcu) bool {
1134 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
1135 .int => |int| int.storage == .lazy_size,
1136 else => false,
1137 };
1138}
1139
1140// Asserts that the provided start/end are in-bounds.
1141pub fn sliceArray(
1142 val: Value,
1143 sema: *Sema,
1144 start: usize,
1145 end: usize,
1146) error{OutOfMemory}!Value {
1147 const pt = sema.pt;
1148 const ip = &pt.zcu.intern_pool;
1149 const io = pt.zcu.comp.io;
1150 return Value.fromInterned(try pt.intern(.{
1151 .aggregate = .{
1152 .ty = switch (pt.zcu.intern_pool.indexToKey(pt.zcu.intern_pool.typeOf(val.toIntern()))) {
1153 .array_type => |array_type| try pt.arrayType(.{
1154 .len = @intCast(end - start),
1155 .child = array_type.child,
1156 .sentinel = if (end == array_type.len) array_type.sentinel else .none,
1157 }),
1158 .vector_type => |vector_type| try pt.vectorType(.{
1159 .len = @intCast(end - start),
1160 .child = vector_type.child,
1161 }),
1162 else => unreachable,
1163 }.toIntern(),
1164 .storage = switch (ip.indexToKey(val.toIntern()).aggregate.storage) {
1165 .bytes => |bytes| storage: {
1166 try ip.string_bytes.ensureUnusedCapacity(sema.gpa, end - start + 1);
1167 break :storage .{ .bytes = try ip.getOrPutString(
1168 sema.gpa,
1169 io,
1170 bytes.toSlice(end, ip)[start..],
1171 .maybe_embedded_nulls,
1172 ) };
1173 },
1174 // TODO: write something like getCoercedInts to avoid needing to dupe
1175 .elems => |elems| .{ .elems = try sema.arena.dupe(InternPool.Index, elems[start..end]) },
1176 .repeated_elem => |elem| .{ .repeated_elem = elem },
1177 },
1178 },
1179 }));
1180}
1181
1182pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value {904pub fn fieldValue(val: Value, pt: Zcu.PerThread, index: usize) !Value {
1183 const zcu = pt.zcu;905 const zcu = pt.zcu;
1184 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {906 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
...@@ -1334,63 +1056,6 @@ pub fn isFloat(self: Value, zcu: *const Zcu) bool {...@@ -1334,63 +1056,6 @@ pub fn isFloat(self: Value, zcu: *const Zcu) bool {
1334 };1056 };
1335}1057}
13361058
1337pub fn floatFromInt(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, zcu: *Zcu) !Value {
1338 return floatFromIntAdvanced(val, arena, int_ty, float_ty, zcu, .normal) catch |err| switch (err) {
1339 error.OutOfMemory => return error.OutOfMemory,
1340 else => unreachable,
1341 };
1342}
1343
1344pub fn floatFromIntAdvanced(
1345 val: Value,
1346 arena: Allocator,
1347 int_ty: Type,
1348 float_ty: Type,
1349 pt: Zcu.PerThread,
1350 comptime strat: ResolveStrat,
1351) !Value {
1352 const zcu = pt.zcu;
1353 if (int_ty.zigTypeTag(zcu) == .vector) {
1354 const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(zcu));
1355 const scalar_ty = float_ty.scalarType(zcu);
1356 for (result_data, 0..) |*scalar, i| {
1357 const elem_val = try val.elemValue(pt, i);
1358 scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, pt, strat)).toIntern();
1359 }
1360 return pt.aggregateValue(float_ty, result_data);
1361 }
1362 return floatFromIntScalar(val, float_ty, pt, strat);
1363}
1364
1365pub fn floatFromIntScalar(val: Value, float_ty: Type, pt: Zcu.PerThread, comptime strat: ResolveStrat) !Value {
1366 return switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) {
1367 .undef => try pt.undefValue(float_ty),
1368 .int => |int| switch (int.storage) {
1369 .big_int => |big_int| pt.floatValue(float_ty, big_int.toFloat(f128, .nearest_even)[0]),
1370 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, pt),
1371 .lazy_align => |ty| floatFromIntInner((try Type.fromInterned(ty).abiAlignmentInner(strat.toLazy(), pt.zcu, pt.tid)).scalar.toByteUnits() orelse 0, float_ty, pt),
1372 .lazy_size => |ty| floatFromIntInner((try Type.fromInterned(ty).abiSizeInner(strat.toLazy(), pt.zcu, pt.tid)).scalar, float_ty, pt),
1373 },
1374 else => unreachable,
1375 };
1376}
1377
1378fn floatFromIntInner(x: anytype, dest_ty: Type, pt: Zcu.PerThread) !Value {
1379 const target = pt.zcu.getTarget();
1380 const storage: InternPool.Key.Float.Storage = switch (dest_ty.floatBits(target)) {
1381 16 => .{ .f16 = @floatFromInt(x) },
1382 32 => .{ .f32 = @floatFromInt(x) },
1383 64 => .{ .f64 = @floatFromInt(x) },
1384 80 => .{ .f80 = @floatFromInt(x) },
1385 128 => .{ .f128 = @floatFromInt(x) },
1386 else => unreachable,
1387 };
1388 return Value.fromInterned(try pt.intern(.{ .float = .{
1389 .ty = dest_ty.toIntern(),
1390 .storage = storage,
1391 } }));
1392}
1393
1394fn calcLimbLenFloat(scalar: anytype) usize {1059fn calcLimbLenFloat(scalar: anytype) usize {
1395 if (scalar == 0) {1060 if (scalar == 0) {
1396 return 1;1061 return 1;
...@@ -1410,11 +1075,11 @@ pub fn numberMax(lhs: Value, rhs: Value, zcu: *Zcu) Value {...@@ -1410,11 +1075,11 @@ pub fn numberMax(lhs: Value, rhs: Value, zcu: *Zcu) Value {
1410 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;1075 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;
1411 if (lhs.isNan(zcu)) return rhs;1076 if (lhs.isNan(zcu)) return rhs;
1412 if (rhs.isNan(zcu)) return lhs;1077 if (rhs.isNan(zcu)) return lhs;
14131078 if (compareHetero(lhs, .gt, rhs, zcu)) {
1414 return switch (order(lhs, rhs, zcu)) {1079 return lhs;
1415 .lt => rhs,1080 } else {
1416 .gt, .eq => lhs,1081 return rhs;
1417 };1082 }
1418}1083}
14191084
1420/// Supports both floats and ints; handles undefined.1085/// Supports both floats and ints; handles undefined.
...@@ -1422,11 +1087,11 @@ pub fn numberMin(lhs: Value, rhs: Value, zcu: *Zcu) Value {...@@ -1422,11 +1087,11 @@ pub fn numberMin(lhs: Value, rhs: Value, zcu: *Zcu) Value {
1422 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;1087 if (lhs.isUndef(zcu) or rhs.isUndef(zcu)) return undef;
1423 if (lhs.isNan(zcu)) return rhs;1088 if (lhs.isNan(zcu)) return rhs;
1424 if (rhs.isNan(zcu)) return lhs;1089 if (rhs.isNan(zcu)) return lhs;
14251090 if (compareHetero(lhs, .lt, rhs, zcu)) {
1426 return switch (order(lhs, rhs, zcu)) {1091 return lhs;
1427 .lt => lhs,1092 } else {
1428 .gt, .eq => rhs,1093 return rhs;
1429 };1094 }
1430}1095}
14311096
1432/// Returns true if the value is a floating point type and is NaN. Returns false otherwise.1097/// Returns true if the value is a floating point type and is NaN. Returns false otherwise.
...@@ -2035,6 +1700,7 @@ pub fn makeBool(x: bool) Value {...@@ -2035,6 +1700,7 @@ pub fn makeBool(x: bool) Value {
2035/// Returns a pointer to the payload of the optional.1700/// Returns a pointer to the payload of the optional.
2036///1701///
2037/// May perform type resolution.1702/// May perform type resolution.
1703/// MLUGG TODO audit
2038pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {1704pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
2039 const zcu = pt.zcu;1705 const zcu = pt.zcu;
2040 const parent_ptr_ty = parent_ptr.typeOf(zcu);1706 const parent_ptr_ty = parent_ptr.typeOf(zcu);
...@@ -2044,7 +1710,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -2044,7 +1710,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
2044 assert(ptr_size == .one or ptr_size == .c);1710 assert(ptr_size == .one or ptr_size == .c);
2045 assert(opt_ty.zigTypeTag(zcu) == .optional);1711 assert(opt_ty.zigTypeTag(zcu) == .optional);
20461712
2047 const result_ty = try pt.ptrTypeSema(info: {1713 const result_ty = try pt.ptrType(info: {
2048 var new = parent_ptr_ty.ptrInfo(zcu);1714 var new = parent_ptr_ty.ptrInfo(zcu);
2049 // We can correctly preserve alignment `.none`, since an optional has the same1715 // We can correctly preserve alignment `.none`, since an optional has the same
2050 // natural alignment as its child type.1716 // natural alignment as its child type.
...@@ -2070,6 +1736,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -2070,6 +1736,7 @@ pub fn ptrOptPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
2070/// `parent_ptr` must be a single-pointer to some error union.1736/// `parent_ptr` must be a single-pointer to some error union.
2071/// Returns a pointer to the payload of the error union.1737/// Returns a pointer to the payload of the error union.
2072/// May perform type resolution.1738/// May perform type resolution.
1739/// MLUGG TODO audit
2073pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {1740pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
2074 const zcu = pt.zcu;1741 const zcu = pt.zcu;
2075 const parent_ptr_ty = parent_ptr.typeOf(zcu);1742 const parent_ptr_ty = parent_ptr.typeOf(zcu);
...@@ -2078,7 +1745,7 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -2078,7 +1745,7 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
2078 assert(parent_ptr_ty.ptrSize(zcu) == .one);1745 assert(parent_ptr_ty.ptrSize(zcu) == .one);
2079 assert(eu_ty.zigTypeTag(zcu) == .error_union);1746 assert(eu_ty.zigTypeTag(zcu) == .error_union);
20801747
2081 const result_ty = try pt.ptrTypeSema(info: {1748 const result_ty = try pt.ptrType(info: {
2082 var new = parent_ptr_ty.ptrInfo(zcu);1749 var new = parent_ptr_ty.ptrInfo(zcu);
2083 // We can correctly preserve alignment `.none`, since an error union has a1750 // We can correctly preserve alignment `.none`, since an error union has a
2084 // natural alignment greater than or equal to that of its payload type.1751 // natural alignment greater than or equal to that of its payload type.
...@@ -2096,6 +1763,8 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {...@@ -2096,6 +1763,8 @@ pub fn ptrEuPayload(parent_ptr: Value, pt: Zcu.PerThread) !Value {
2096 } }));1763 } }));
2097}1764}
20981765
1766// MLUGG TODO: audit ptrField etc in terms of resolution, and probably move them under sema
1767
2099/// `parent_ptr` must be a single-pointer or c pointer to a struct, union, or slice.1768/// `parent_ptr` must be a single-pointer or c pointer to a struct, union, or slice.
2100///1769///
2101/// Returns a pointer to the aggregate field at the specified index.1770/// Returns a pointer to the aggregate field at the specified index.
...@@ -2112,23 +1781,34 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {...@@ -2112,23 +1781,34 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
2112 assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c);1781 assert(parent_ptr_info.flags.size == .one or parent_ptr_info.flags.size == .c);
21131782
2114 // Exiting this `switch` indicates that the `field` pointer representation should be used.1783 // Exiting this `switch` indicates that the `field` pointer representation should be used.
2115 // `field_align` may be `.none` to represent the natural alignment of `field_ty`, but is not necessarily.1784 const field_ty: Type, const new_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {
2116 const field_ty: Type, const field_align: InternPool.Alignment = switch (aggregate_ty.zigTypeTag(zcu)) {
2117 .@"struct" => field: {1785 .@"struct" => field: {
2118 const field_ty = aggregate_ty.fieldType(field_idx, zcu);1786 const field_ty = aggregate_ty.fieldType(field_idx, zcu);
2119 switch (aggregate_ty.containerLayout(zcu)) {1787 switch (aggregate_ty.containerLayout(zcu)) {
2120 .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) },1788 .auto => break :field .{ field_ty, a: {
1789 if (parent_ptr_info.flags.alignment == .none) {
1790 break :a aggregate_ty.explicitFieldAlignment(field_idx, zcu);
1791 }
1792 const field_align = aggregate_ty.resolvedFieldAlignment(field_idx, zcu);
1793 break :a field_align.min(parent_ptr_info.flags.alignment);
1794 } },
2121 .@"extern" => {1795 .@"extern" => {
2122 // Well-defined layout, so just offset the pointer appropriately.1796 // Well-defined layout, so just offset the pointer appropriately.
2123 try aggregate_ty.resolveLayout(pt);
2124 const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);1797 const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);
2125 const field_align = a: {1798 const field_align: InternPool.Alignment = a: {
1799 if (byte_off == 0) break :a parent_ptr_info.flags.alignment;
1800 const true_field_align: InternPool.Alignment = .fromLog2Units(@ctz(byte_off));
1801 if (parent_ptr_info.flags.alignment == .none and
1802 true_field_align == field_ty.abiAlignment(zcu))
1803 {
1804 break :a .none;
1805 }
2126 const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {1806 const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {
2127 break :pa try aggregate_ty.abiAlignmentSema(pt);1807 break :pa aggregate_ty.abiAlignment(zcu);
2128 } else parent_ptr_info.flags.alignment;1808 } else parent_ptr_info.flags.alignment;
2129 break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off)));1809 break :a .minStrict(true_field_align, parent_align);
2130 };1810 };
2131 const result_ty = try pt.ptrTypeSema(info: {1811 const result_ty = try pt.ptrType(info: {
2132 var new = parent_ptr_info;1812 var new = parent_ptr_info;
2133 new.child = field_ty.toIntern();1813 new.child = field_ty.toIntern();
2134 new.flags.alignment = field_align;1814 new.flags.alignment = field_align;
...@@ -2143,7 +1823,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {...@@ -2143,7 +1823,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
2143 new.packed_offset = packed_offset;1823 new.packed_offset = packed_offset;
2144 new.child = field_ty.toIntern();1824 new.child = field_ty.toIntern();
2145 if (new.flags.alignment == .none) {1825 if (new.flags.alignment == .none) {
2146 new.flags.alignment = try aggregate_ty.abiAlignmentSema(pt);1826 new.flags.alignment = aggregate_ty.abiAlignment(zcu);
2147 }1827 }
2148 break :info new;1828 break :info new;
2149 });1829 });
...@@ -2155,10 +1835,16 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {...@@ -2155,10 +1835,16 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
2155 const union_obj = zcu.typeToUnion(aggregate_ty).?;1835 const union_obj = zcu.typeToUnion(aggregate_ty).?;
2156 const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]);1836 const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]);
2157 switch (aggregate_ty.containerLayout(zcu)) {1837 switch (aggregate_ty.containerLayout(zcu)) {
2158 .auto => break :field .{ field_ty, try aggregate_ty.fieldAlignmentSema(field_idx, pt) },1838 .auto => break :field .{ field_ty, a: {
1839 if (parent_ptr_info.flags.alignment == .none) {
1840 break :a aggregate_ty.explicitFieldAlignment(field_idx, zcu);
1841 }
1842 const field_align = aggregate_ty.resolvedFieldAlignment(field_idx, zcu);
1843 break :a field_align.min(parent_ptr_info.flags.alignment);
1844 } },
2159 .@"extern" => {1845 .@"extern" => {
2160 // Point to the same address.1846 // Point to the same address.
2161 const result_ty = try pt.ptrTypeSema(info: {1847 const result_ty = try pt.ptrType(info: {
2162 var new = parent_ptr_info;1848 var new = parent_ptr_info;
2163 new.child = field_ty.toIntern();1849 new.child = field_ty.toIntern();
2164 break :info new;1850 break :info new;
...@@ -2166,59 +1852,30 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {...@@ -2166,59 +1852,30 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
2166 return pt.getCoerced(parent_ptr, result_ty);1852 return pt.getCoerced(parent_ptr, result_ty);
2167 },1853 },
2168 .@"packed" => {1854 .@"packed" => {
2169 // If the field has an ABI size matching its bit size, then we can continue to use a1855 const result_ty = try pt.ptrType(info: {
2170 // non-bit pointer if the parent pointer is also a non-bit pointer.1856 var new = parent_ptr_info;
2171 if (parent_ptr_info.packed_offset.host_size == 0 and (try field_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar * 8 == try field_ty.bitSizeSema(pt)) {1857 new.child = field_ty.toIntern();
2172 // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely.1858 break :info new;
2173 const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) {1859 });
2174 .little => 0,1860 return pt.getCoerced(parent_ptr, result_ty);
2175 .big => (try aggregate_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar - (try field_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar,
2176 };
2177 const result_ty = try pt.ptrTypeSema(info: {
2178 var new = parent_ptr_info;
2179 new.child = field_ty.toIntern();
2180 new.flags.alignment = InternPool.Alignment.fromLog2Units(
2181 @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentSema(pt)).toByteUnits().?),
2182 );
2183 break :info new;
2184 });
2185 return parent_ptr.getOffsetPtr(byte_offset, result_ty, pt);
2186 } else {
2187 // The result must be a bit-pointer if it is not already.
2188 const result_ty = try pt.ptrTypeSema(info: {
2189 var new = parent_ptr_info;
2190 new.child = field_ty.toIntern();
2191 if (new.packed_offset.host_size == 0) {
2192 new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeSema(pt)) + 7) / 8);
2193 assert(new.packed_offset.bit_offset == 0);
2194 }
2195 break :info new;
2196 });
2197 return pt.getCoerced(parent_ptr, result_ty);
2198 }
2199 },1861 },
2200 }1862 }
2201 },1863 },
2202 .pointer => field_ty: {1864 .pointer => field_ty: {
2203 assert(aggregate_ty.isSlice(zcu));1865 assert(aggregate_ty.isSlice(zcu));
2204 break :field_ty switch (field_idx) {1866 break :field_ty .{ switch (field_idx) {
2205 Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), Type.usize.abiAlignment(zcu) },1867 Value.slice_ptr_index => aggregate_ty.slicePtrFieldType(zcu),
2206 Value.slice_len_index => .{ Type.usize, Type.usize.abiAlignment(zcu) },1868 Value.slice_len_index => Type.usize,
2207 else => unreachable,1869 else => unreachable,
2208 };1870 }, switch (parent_ptr_info.flags.alignment) {
1871 .none => .none,
1872 else => Type.usize.abiAlignment(zcu).min(parent_ptr_info.flags.alignment),
1873 } };
2209 },1874 },
2210 else => unreachable,1875 else => unreachable,
2211 };1876 };
22121877
2213 const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: {1878 const result_ty = try pt.ptrType(info: {
2214 const ty_align = (try field_ty.abiAlignmentInner(.sema, zcu, pt.tid)).scalar;
2215 const true_field_align = if (field_align == .none) ty_align else field_align;
2216 const new_align = true_field_align.min(parent_ptr_info.flags.alignment);
2217 if (new_align == ty_align) break :a .none;
2218 break :a new_align;
2219 } else field_align;
2220
2221 const result_ty = try pt.ptrTypeSema(info: {
2222 var new = parent_ptr_info;1879 var new = parent_ptr_info;
2223 new.child = field_ty.toIntern();1880 new.child = field_ty.toIntern();
2224 new.flags.alignment = new_align;1881 new.flags.alignment = new_align;
...@@ -2241,6 +1898,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {...@@ -2241,6 +1898,7 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, pt: Zcu.PerThread) !Value {
2241/// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice.1898/// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice.
2242/// Returns a pointer to the element at the specified index.1899/// Returns a pointer to the element at the specified index.
2243/// May perform type resolution.1900/// May perform type resolution.
1901/// MLUGG TODO AUDIT
2244pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value {1902pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value {
2245 const zcu = pt.zcu;1903 const zcu = pt.zcu;
2246 const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {1904 const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {
...@@ -2267,21 +1925,19 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value...@@ -2267,21 +1925,19 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, pt: Zcu.PerThread) !Value
22671925
2268 const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) {1926 const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) {
2269 .one => switch (elem_ty.zigTypeTag(zcu)) {1927 .one => switch (elem_ty.zigTypeTag(zcu)) {
2270 .vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeSema(pt), 8) },1928 .vector => .{ .offset = field_idx * @divExact(elem_ty.childType(zcu).bitSize(zcu), 8) },
2271 .array => strat: {1929 .array => strat: {
2272 const arr_elem_ty = elem_ty.childType(zcu);1930 const arr_elem_ty = elem_ty.childType(zcu);
2273 if (try arr_elem_ty.comptimeOnlySema(pt)) {1931 if (arr_elem_ty.comptimeOnly(zcu)) break :strat .{ .elem_ptr = arr_elem_ty };
2274 break :strat .{ .elem_ptr = arr_elem_ty };1932 break :strat .{ .offset = field_idx * arr_elem_ty.abiSize(zcu) };
2275 }
2276 break :strat .{ .offset = field_idx * (try arr_elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar };
2277 },1933 },
2278 else => unreachable,1934 else => unreachable,
2279 },1935 },
22801936
2281 .many, .c => if (try elem_ty.comptimeOnlySema(pt))1937 .many, .c => if (elem_ty.comptimeOnly(zcu))
2282 .{ .elem_ptr = elem_ty }1938 .{ .elem_ptr = elem_ty }
2283 else1939 else
2284 .{ .offset = field_idx * (try elem_ty.abiSizeInner(.sema, zcu, pt.tid)).scalar },1940 .{ .offset = field_idx * elem_ty.abiSize(zcu) },
22851941
2286 .slice => unreachable,1942 .slice => unreachable,
2287 };1943 };
...@@ -2430,6 +2086,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al...@@ -2430,6 +2086,7 @@ pub fn pointerDerivation(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread) Al
2430/// which prefer field/elem accesses when lowering constant pointer values.2086/// which prefer field/elem accesses when lowering constant pointer values.
2431/// It is also used by the Value printing logic for pointers.2087/// It is also used by the Value printing logic for pointers.
2432pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep {2088pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerThread, comptime resolve_types: bool, opt_sema: ?*Sema) !PointerDeriveStep {
2089 // MLUGG TODO: audit tf outta this code
2433 const zcu = pt.zcu;2090 const zcu = pt.zcu;
2434 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;2091 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
2435 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {2092 const base_derive: PointerDeriveStep = switch (ptr.base_addr) {
...@@ -2454,7 +2111,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2454,7 +2111,7 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2454 .comptime_alloc => |idx| base: {2111 .comptime_alloc => |idx| base: {
2455 const sema = opt_sema.?;2112 const sema = opt_sema.?;
2456 const alloc = sema.getComptimeAlloc(idx);2113 const alloc = sema.getComptimeAlloc(idx);
2457 const val = try alloc.val.intern(pt, sema.arena);2114 const val = try alloc.val.intern(pt, arena);
2458 const ty = val.typeOf(zcu);2115 const ty = val.typeOf(zcu);
2459 break :base .{ .comptime_alloc_ptr = .{2116 break :base .{ .comptime_alloc_ptr = .{
2460 .idx = idx,2117 .idx = idx,
...@@ -2492,24 +2149,14 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2492,24 +2149,14 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2492 const base_ptr = Value.fromInterned(field.base);2149 const base_ptr = Value.fromInterned(field.base);
2493 const base_ptr_ty = base_ptr.typeOf(zcu);2150 const base_ptr_ty = base_ptr.typeOf(zcu);
2494 const agg_ty = base_ptr_ty.childType(zcu);2151 const agg_ty = base_ptr_ty.childType(zcu);
2495 const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {2152 if (resolve_types) try opt_sema.?.ensureLayoutResolved(agg_ty);
2496 .@"struct" => .{ agg_ty.fieldType(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(2153 const field_ty: Type, const field_align: InternPool.Alignment = switch (agg_ty.zigTypeTag(zcu)) {
2497 @intCast(field.index),2154 .@"struct", .@"union" => .{ agg_ty.fieldType(@intCast(field.index), zcu), agg_ty.resolvedFieldAlignment(@intCast(field.index), pt.zcu) },
2498 if (resolve_types) .sema else .normal,2155 .pointer => switch (field.index) {
2499 pt.zcu,2156 Value.slice_ptr_index => .{ agg_ty.slicePtrFieldType(zcu), Type.ptrAbiAlignment(zcu.getTarget()) },
2500 if (resolve_types) pt.tid else {},2157 Value.slice_len_index => .{ .usize, Type.abiAlignment(.usize, zcu) },
2501 ) },
2502 .@"union" => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.fieldAlignmentInner(
2503 @intCast(field.index),
2504 if (resolve_types) .sema else .normal,
2505 pt.zcu,
2506 if (resolve_types) pt.tid else {},
2507 ) },
2508 .pointer => .{ switch (field.index) {
2509 Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),
2510 Value.slice_len_index => Type.usize,
2511 else => unreachable,2158 else => unreachable,
2512 }, Type.usize.abiAlignment(zcu) },2159 },
2513 else => unreachable,2160 else => unreachable,
2514 };2161 };
2515 const base_align = base_ptr_ty.ptrAlignment(zcu);2162 const base_align = base_ptr_ty.ptrAlignment(zcu);
...@@ -2720,148 +2367,6 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh...@@ -2720,148 +2367,6 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, pt: Zcu.PerTh
2720 } };2367 } };
2721}2368}
27222369
2723pub fn resolveLazy(
2724 val: Value,
2725 arena: Allocator,
2726 pt: Zcu.PerThread,
2727) Zcu.SemaError!Value {
2728 switch (pt.zcu.intern_pool.indexToKey(val.toIntern())) {
2729 .int => |int| switch (int.storage) {
2730 .u64, .i64, .big_int => return val,
2731 .lazy_align, .lazy_size => return pt.intValue(
2732 Type.fromInterned(int.ty),
2733 try val.toUnsignedIntSema(pt),
2734 ),
2735 },
2736 .slice => |slice| {
2737 const ptr = try Value.fromInterned(slice.ptr).resolveLazy(arena, pt);
2738 const len = try Value.fromInterned(slice.len).resolveLazy(arena, pt);
2739 if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val;
2740 return Value.fromInterned(try pt.intern(.{ .slice = .{
2741 .ty = slice.ty,
2742 .ptr = ptr.toIntern(),
2743 .len = len.toIntern(),
2744 } }));
2745 },
2746 .ptr => |ptr| {
2747 switch (ptr.base_addr) {
2748 .nav, .comptime_alloc, .uav, .int => return val,
2749 .comptime_field => |field_val| {
2750 const resolved_field_val = (try Value.fromInterned(field_val).resolveLazy(arena, pt)).toIntern();
2751 return if (resolved_field_val == field_val)
2752 val
2753 else
2754 Value.fromInterned(try pt.intern(.{ .ptr = .{
2755 .ty = ptr.ty,
2756 .base_addr = .{ .comptime_field = resolved_field_val },
2757 .byte_offset = ptr.byte_offset,
2758 } }));
2759 },
2760 .eu_payload, .opt_payload => |base| {
2761 const resolved_base = (try Value.fromInterned(base).resolveLazy(arena, pt)).toIntern();
2762 return if (resolved_base == base)
2763 val
2764 else
2765 Value.fromInterned(try pt.intern(.{ .ptr = .{
2766 .ty = ptr.ty,
2767 .base_addr = switch (ptr.base_addr) {
2768 .eu_payload => .{ .eu_payload = resolved_base },
2769 .opt_payload => .{ .opt_payload = resolved_base },
2770 else => unreachable,
2771 },
2772 .byte_offset = ptr.byte_offset,
2773 } }));
2774 },
2775 .arr_elem, .field => |base_index| {
2776 const resolved_base = (try Value.fromInterned(base_index.base).resolveLazy(arena, pt)).toIntern();
2777 return if (resolved_base == base_index.base)
2778 val
2779 else
2780 Value.fromInterned(try pt.intern(.{ .ptr = .{
2781 .ty = ptr.ty,
2782 .base_addr = switch (ptr.base_addr) {
2783 .arr_elem => .{ .arr_elem = .{
2784 .base = resolved_base,
2785 .index = base_index.index,
2786 } },
2787 .field => .{ .field = .{
2788 .base = resolved_base,
2789 .index = base_index.index,
2790 } },
2791 else => unreachable,
2792 },
2793 .byte_offset = ptr.byte_offset,
2794 } }));
2795 },
2796 }
2797 },
2798 .aggregate => |aggregate| switch (aggregate.storage) {
2799 .bytes => return val,
2800 .elems => |elems| {
2801 var resolved_elems: []InternPool.Index = &.{};
2802 for (elems, 0..) |elem, i| {
2803 const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, pt)).toIntern();
2804 if (resolved_elems.len == 0 and resolved_elem != elem) {
2805 resolved_elems = try arena.alloc(InternPool.Index, elems.len);
2806 @memcpy(resolved_elems[0..i], elems[0..i]);
2807 }
2808 if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem;
2809 }
2810 return if (resolved_elems.len == 0)
2811 val
2812 else
2813 pt.aggregateValue(.fromInterned(aggregate.ty), resolved_elems);
2814 },
2815 .repeated_elem => |elem| {
2816 const resolved_elem = try Value.fromInterned(elem).resolveLazy(arena, pt);
2817 return if (resolved_elem.toIntern() == elem)
2818 val
2819 else
2820 pt.aggregateSplatValue(.fromInterned(aggregate.ty), resolved_elem);
2821 },
2822 },
2823 .un => |un| {
2824 const resolved_tag = if (un.tag == .none)
2825 .none
2826 else
2827 (try Value.fromInterned(un.tag).resolveLazy(arena, pt)).toIntern();
2828 const resolved_val = (try Value.fromInterned(un.val).resolveLazy(arena, pt)).toIntern();
2829 return if (resolved_tag == un.tag and resolved_val == un.val)
2830 val
2831 else
2832 Value.fromInterned(try pt.internUnion(.{
2833 .ty = un.ty,
2834 .tag = resolved_tag,
2835 .val = resolved_val,
2836 }));
2837 },
2838 .error_union => |eu| switch (eu.val) {
2839 .err_name => return val,
2840 .payload => |payload| {
2841 const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
2842 if (resolved_payload.toIntern() == payload) return val;
2843 return .fromInterned(try pt.intern(.{ .error_union = .{
2844 .ty = eu.ty,
2845 .val = .{ .payload = resolved_payload.toIntern() },
2846 } }));
2847 },
2848 },
2849 .opt => |opt| switch (opt.val) {
2850 .none => return val,
2851 else => |payload| {
2852 const resolved_payload = try Value.fromInterned(payload).resolveLazy(arena, pt);
2853 if (resolved_payload.toIntern() == payload) return val;
2854 return .fromInterned(try pt.intern(.{ .opt = .{
2855 .ty = opt.ty,
2856 .val = resolved_payload.toIntern(),
2857 } }));
2858 },
2859 },
2860
2861 else => return val,
2862 }
2863}
2864
2865const InterpretMode = enum {2370const InterpretMode = enum {
2866 /// In this mode, types are assumed to match what the compiler was built with in terms of field2371 /// In this mode, types are assumed to match what the compiler was built with in terms of field
2867 /// order, field types, etc. This improves compiler performance. However, it means that certain2372 /// order, field types, etc. This improves compiler performance. However, it means that certain
...@@ -2878,7 +2383,6 @@ const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_optio...@@ -2878,7 +2383,6 @@ const interpret_mode: InterpretMode = @field(InterpretMode, @tagName(build_optio
28782383
2879/// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler.2384/// Given a `Value` representing a comptime-known value of type `T`, unwrap it into an actual `T` known to the compiler.
2880/// This is useful for accessing `std.builtin` structures received from comptime logic.2385/// This is useful for accessing `std.builtin` structures received from comptime logic.
2881/// `val` must be fully resolved.
2882pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMemory, UndefinedValue, TypeMismatch }!T {2386pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMemory, UndefinedValue, TypeMismatch }!T {
2883 const zcu = pt.zcu;2387 const zcu = pt.zcu;
2884 const io = zcu.comp.io;2388 const io = zcu.comp.io;
...@@ -2917,7 +2421,6 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe...@@ -2917,7 +2421,6 @@ pub fn interpret(val: Value, comptime T: type, pt: Zcu.PerThread) error{ OutOfMe
2917 },2421 },
29182422
2919 .int => switch (ip.indexToKey(val.toIntern()).int.storage) {2423 .int => switch (ip.indexToKey(val.toIntern()).int.storage) {
2920 .lazy_align, .lazy_size => unreachable, // `val` is fully resolved
2921 inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,2424 inline .u64, .i64 => |x| std.math.cast(T, x) orelse return error.TypeMismatch,
2922 .big_int => |big| big.toInt(T) catch return error.TypeMismatch,2425 .big_int => |big| big.toInt(T) catch return error.TypeMismatch,
2923 },2426 },
src/Zcu.zig+84-79
...@@ -14,6 +14,8 @@ const mem = std.mem;...@@ -14,6 +14,8 @@ const mem = std.mem;
14const Allocator = std.mem.Allocator;14const Allocator = std.mem.Allocator;
15const assert = std.debug.assert;15const assert = std.debug.assert;
16const log = std.log.scoped(.zcu);16const log = std.log.scoped(.zcu);
17const deps_log = std.log.scoped(.zcu_deps);
18const refs_log = std.log.scoped(.zcu_refs);
17const BigIntConst = std.math.big.int.Const;19const BigIntConst = std.math.big.int.Const;
18const BigIntMutable = std.math.big.int.Mutable;20const BigIntMutable = std.math.big.int.Mutable;
19const Target = std.Target;21const Target = std.Target;
...@@ -2685,10 +2687,10 @@ pub const LazySrcLoc = struct {...@@ -2685,10 +2687,10 @@ pub const LazySrcLoc = struct {
2685 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node,2687 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node,
2686 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node,2688 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node,
2687 .extended => switch (inst.data.extended.opcode) {2689 .extended => switch (inst.data.extended.opcode) {
2688 .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_node,2690 .struct_decl => zir.getStructDecl(zir_inst).src_node,
2689 .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_node,2691 .union_decl => zir.getUnionDecl(zir_inst).src_node,
2690 .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_node,2692 .enum_decl => zir.getEnumDecl(zir_inst).src_node,
2691 .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_node,2693 .opaque_decl => zir.getOpaqueDecl(zir_inst).src_node,
2692 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node,2694 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node,
2693 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node,2695 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node,
2694 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node,2696 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node,
...@@ -3063,7 +3065,7 @@ pub fn markDependeeOutdated(...@@ -3063,7 +3065,7 @@ pub fn markDependeeOutdated(
3063 marked_po: enum { not_marked_po, marked_po },3065 marked_po: enum { not_marked_po, marked_po },
3064 dependee: InternPool.Dependee,3066 dependee: InternPool.Dependee,
3065) !void {3067) !void {
3066 log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)});3068 deps_log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
3067 var it = zcu.intern_pool.dependencyIterator(dependee);3069 var it = zcu.intern_pool.dependencyIterator(dependee);
3068 while (it.next()) |depender| {3070 while (it.next()) |depender| {
3069 if (zcu.outdated.getPtr(depender)) |po_dep_count| {3071 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
...@@ -3071,9 +3073,9 @@ pub fn markDependeeOutdated(...@@ -3071,9 +3073,9 @@ pub fn markDependeeOutdated(
3071 .not_marked_po => {},3073 .not_marked_po => {},
3072 .marked_po => {3074 .marked_po => {
3073 po_dep_count.* -= 1;3075 po_dep_count.* -= 1;
3074 log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });3076 deps_log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
3075 if (po_dep_count.* == 0) {3077 if (po_dep_count.* == 0) {
3076 log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});3078 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
3077 try zcu.outdated_ready.put(zcu.gpa, depender, {});3079 try zcu.outdated_ready.put(zcu.gpa, depender, {});
3078 }3080 }
3079 },3081 },
...@@ -3094,9 +3096,9 @@ pub fn markDependeeOutdated(...@@ -3094,9 +3096,9 @@ pub fn markDependeeOutdated(
3094 depender,3096 depender,
3095 new_po_dep_count,3097 new_po_dep_count,
3096 );3098 );
3097 log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });3099 deps_log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count });
3098 if (new_po_dep_count == 0) {3100 if (new_po_dep_count == 0) {
3099 log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});3101 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
3100 try zcu.outdated_ready.put(zcu.gpa, depender, {});3102 try zcu.outdated_ready.put(zcu.gpa, depender, {});
3101 }3103 }
3102 // If this is a Decl and was not previously PO, we must recursively3104 // If this is a Decl and was not previously PO, we must recursively
...@@ -3109,16 +3111,16 @@ pub fn markDependeeOutdated(...@@ -3109,16 +3111,16 @@ pub fn markDependeeOutdated(
3109}3111}
31103112
3111pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {3113pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3112 log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)});3114 deps_log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)});
3113 var it = zcu.intern_pool.dependencyIterator(dependee);3115 var it = zcu.intern_pool.dependencyIterator(dependee);
3114 while (it.next()) |depender| {3116 while (it.next()) |depender| {
3115 if (zcu.outdated.getPtr(depender)) |po_dep_count| {3117 if (zcu.outdated.getPtr(depender)) |po_dep_count| {
3116 // This depender is already outdated, but it now has one3118 // This depender is already outdated, but it now has one
3117 // less PO dependency!3119 // less PO dependency!
3118 po_dep_count.* -= 1;3120 po_dep_count.* -= 1;
3119 log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });3121 deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* });
3120 if (po_dep_count.* == 0) {3122 if (po_dep_count.* == 0) {
3121 log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});3123 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)});
3122 try zcu.outdated_ready.put(zcu.gpa, depender, {});3124 try zcu.outdated_ready.put(zcu.gpa, depender, {});
3123 }3125 }
3124 continue;3126 continue;
...@@ -3132,11 +3134,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -3132,11 +3134,11 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3132 };3134 };
3133 if (ptr.* > 1) {3135 if (ptr.* > 1) {
3134 ptr.* -= 1;3136 ptr.* -= 1;
3135 log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });3137 deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* });
3136 continue;3138 continue;
3137 }3139 }
31383140
3139 log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });3141 deps_log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) });
31403142
3141 // This dependency is no longer PO, i.e. is known to be up-to-date.3143 // This dependency is no longer PO, i.e. is known to be up-to-date.
3142 assert(zcu.potentially_outdated.swapRemove(depender));3144 assert(zcu.potentially_outdated.swapRemove(depender));
...@@ -3146,8 +3148,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {...@@ -3146,8 +3148,9 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
3146 .@"comptime" => {},3148 .@"comptime" => {},
3147 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),3149 .nav_val => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_val = nav }),
3148 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),3150 .nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
3149 .type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),3151 .type_layout => |ty| try zcu.markPoDependeeUpToDate(.{ .type_layout = ty }),
3150 .func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),3152 .type_inits => |ty| try zcu.markPoDependeeUpToDate(.{ .type_inits = ty }),
3153 .func => |func| try zcu.markPoDependeeUpToDate(.{ .func_ies = func }),
3151 .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),3154 .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),
3152 }3155 }
3153 }3156 }
...@@ -3161,11 +3164,12 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -3161,11 +3164,12 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
3161 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies3164 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies
3162 .nav_val => |nav| .{ .nav_val = nav },3165 .nav_val => |nav| .{ .nav_val = nav },
3163 .nav_ty => |nav| .{ .nav_ty = nav },3166 .nav_ty => |nav| .{ .nav_ty = nav },
3164 .type => |ty| .{ .interned = ty },3167 .type_layout => |ty| .{ .type_layout = ty },
3165 .func => |func_index| .{ .interned = func_index }, // IES3168 .type_inits => |ty| .{ .type_inits = ty },
3169 .func => |func_index| .{ .func_ies = func_index },
3166 .memoized_state => |stage| .{ .memoized_state = stage },3170 .memoized_state => |stage| .{ .memoized_state = stage },
3167 };3171 };
3168 log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)});3172 deps_log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)});
3169 var it = ip.dependencyIterator(dependee);3173 var it = ip.dependencyIterator(dependee);
3170 while (it.next()) |po| {3174 while (it.next()) |po| {
3171 if (zcu.outdated.getPtr(po)) |po_dep_count| {3175 if (zcu.outdated.getPtr(po)) |po_dep_count| {
...@@ -3175,17 +3179,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni...@@ -3175,17 +3179,17 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
3175 _ = zcu.outdated_ready.swapRemove(po);3179 _ = zcu.outdated_ready.swapRemove(po);
3176 }3180 }
3177 po_dep_count.* += 1;3181 po_dep_count.* += 1;
3178 log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });3182 deps_log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* });
3179 continue;3183 continue;
3180 }3184 }
3181 if (zcu.potentially_outdated.getPtr(po)) |n| {3185 if (zcu.potentially_outdated.getPtr(po)) |n| {
3182 // There is now one more PO dependency.3186 // There is now one more PO dependency.
3183 n.* += 1;3187 n.* += 1;
3184 log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });3188 deps_log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* });
3185 continue;3189 continue;
3186 }3190 }
3187 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);3191 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
3188 log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });3192 deps_log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) });
3189 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.3193 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.
3190 try zcu.markTransitiveDependersPotentiallyOutdated(po);3194 try zcu.markTransitiveDependersPotentiallyOutdated(po);
3191 }3195 }
...@@ -3240,13 +3244,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {...@@ -3240,13 +3244,15 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
3240 var chosen_unit: ?AnalUnit = null;3244 var chosen_unit: ?AnalUnit = null;
3241 var chosen_unit_dependers: u32 = undefined;3245 var chosen_unit_dependers: u32 = undefined;
32423246
3247 // MLUGG TODO: i'm 99% sure this is now impossible. check!!!
3243 inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {3248 inline for (.{ zcu.outdated.keys(), zcu.potentially_outdated.keys() }) |outdated_units| {
3244 for (outdated_units) |unit| {3249 for (outdated_units) |unit| {
3245 var n: u32 = 0;3250 var n: u32 = 0;
3246 var it = ip.dependencyIterator(switch (unit.unwrap()) {3251 var it = ip.dependencyIterator(switch (unit.unwrap()) {
3247 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice3252 .func => continue, // a `func` definitely can't be causing the loop so it is a bad choice
3248 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice3253 .@"comptime" => continue, // a `comptime` block can't even be depended on so it is a terrible choice
3249 .type => |ty| .{ .interned = ty },3254 .type_layout => |ty| .{ .type_layout = ty },
3255 .type_inits => |ty| .{ .type_inits = ty },
3250 .nav_val => |nav| .{ .nav_val = nav },3256 .nav_val => |nav| .{ .nav_val = nav },
3251 .nav_ty => |nav| .{ .nav_ty = nav },3257 .nav_ty => |nav| .{ .nav_ty = nav },
3252 .memoized_state => {3258 .memoized_state => {
...@@ -3377,25 +3383,21 @@ pub fn mapOldZirToNew(...@@ -3377,25 +3383,21 @@ pub fn mapOldZirToNew(
3377 var comptime_decls: std.ArrayList(Zir.Inst.Index) = .empty;3383 var comptime_decls: std.ArrayList(Zir.Inst.Index) = .empty;
3378 defer comptime_decls.deinit(gpa);3384 defer comptime_decls.deinit(gpa);
33793385
3380 {3386 for (old_zir.typeDecls(match_item.old_inst)) |old_decl_inst| {
3381 var old_decl_it = old_zir.declIterator(match_item.old_inst);3387 const old_decl = old_zir.getDeclaration(old_decl_inst);
3382 while (old_decl_it.next()) |old_decl_inst| {3388 switch (old_decl.kind) {
3383 const old_decl = old_zir.getDeclaration(old_decl_inst);3389 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),
3384 switch (old_decl.kind) {3390 .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),
3385 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst),3391 .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
3386 .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst),3392 .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
3387 .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),3393 .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
3388 .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
3389 .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst),
3390 }
3391 }3394 }
3392 }3395 }
33933396
3394 var unnamed_test_idx: u32 = 0;3397 var unnamed_test_idx: u32 = 0;
3395 var comptime_decl_idx: u32 = 0;3398 var comptime_decl_idx: u32 = 0;
33963399
3397 var new_decl_it = new_zir.declIterator(match_item.new_inst);3400 for (new_zir.typeDecls(match_item.new_inst)) |new_decl_inst| {
3398 while (new_decl_it.next()) |new_decl_inst| {
3399 const new_decl = new_zir.getDeclaration(new_decl_inst);3401 const new_decl = new_zir.getDeclaration(new_decl_inst);
3400 // Attempt to match this to a declaration in the old ZIR:3402 // Attempt to match this to a declaration in the old ZIR:
3401 // * For named declarations (`const`/`var`/`fn`), we match based on name.3403 // * For named declarations (`const`/`var`/`fn`), we match based on name.
...@@ -3494,7 +3496,7 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo...@@ -3494,7 +3496,7 @@ pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func_index: InternPool.Index) !vo
3494 }3496 }
34953497
3496 try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);3498 try zcu.func_body_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
3497 try zcu.comp.queueJob(.{ .analyze_func = func_index });3499 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .func = func_index }) });
3498 zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {});3500 zcu.func_body_analysis_queued.putAssumeCapacityNoClobber(func_index, {});
3499}3501}
35003502
...@@ -3513,7 +3515,7 @@ pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void...@@ -3513,7 +3515,7 @@ pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav_id: InternPool.Nav.Index) !void
3513 }3515 }
35143516
3515 try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);3517 try zcu.nav_val_analysis_queued.ensureUnusedCapacity(zcu.gpa, 1);
3516 try zcu.comp.queueJob(.{ .analyze_comptime_unit = .wrap(.{ .nav_val = nav_id }) });3518 try zcu.comp.queueJob(.{ .analyze_unit = .wrap(.{ .nav_val = nav_id }) });
3517 zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});3519 zcu.nav_val_analysis_queued.putAssumeCapacityNoClobber(nav_id, {});
3518}3520}
35193521
...@@ -3908,8 +3910,7 @@ pub fn atomicPtrAlignment(...@@ -3908,8 +3910,7 @@ pub fn atomicPtrAlignment(
3908 return error.BadType;3910 return error.BadType;
3909}3911}
39103912
3911/// Returns null in the following cases:3913/// Returns null if `ty` is not a struct.
3912/// * Not a struct.
3913pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType {3914pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType {
3914 if (ty.ip_index == .none) return null;3915 if (ty.ip_index == .none) return null;
3915 const ip = &zcu.intern_pool;3916 const ip = &zcu.intern_pool;
...@@ -3936,7 +3937,6 @@ pub fn structPackedFieldBitOffset(...@@ -3936,7 +3937,6 @@ pub fn structPackedFieldBitOffset(
3936) u16 {3937) u16 {
3937 const ip = &zcu.intern_pool;3938 const ip = &zcu.intern_pool;
3938 assert(struct_type.layout == .@"packed");3939 assert(struct_type.layout == .@"packed");
3939 assert(struct_type.haveLayout(ip));
3940 var bit_sum: u64 = 0;3940 var bit_sum: u64 = 0;
3941 for (0..struct_type.field_types.len) |i| {3941 for (0..struct_type.field_types.len) |i| {
3942 if (i == field_index) {3942 if (i == field_index) {
...@@ -3995,8 +3995,10 @@ pub const UnionLayout = struct {...@@ -3995,8 +3995,10 @@ pub const UnionLayout = struct {
3995pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {3995pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 {
3996 const ip = &zcu.intern_pool;3996 const ip = &zcu.intern_pool;
3997 if (enum_tag.toIntern() == .none) return null;3997 if (enum_tag.toIntern() == .none) return null;
3998 assert(ip.typeOf(enum_tag.toIntern()) == loaded_union.enum_tag_ty);3998 const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag;
3999 return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());3999 assert(enum_tag_key.ty == loaded_union.enum_tag_type);
4000 const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type);
4001 return loaded_enum.tagValueIndex(ip, enum_tag_key.int);
4000}4002}
40014003
4002pub const ResolvedReference = struct {4004pub const ResolvedReference = struct {
...@@ -4049,31 +4051,36 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4049,31 +4051,36 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4049 const referencer = types.values()[type_idx];4051 const referencer = types.values()[type_idx];
4050 type_idx += 1;4052 type_idx += 1;
40514053
4052 log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});4054 refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fmt(ip)});
40534055
4054 // If this type undergoes type resolution, the corresponding `AnalUnit` is automatically referenced.4056 // If this type undergoes type resolution, the corresponding `AnalUnit`s are automatically referenced.
4055 const has_resolution: bool = switch (ip.indexToKey(ty)) {4057 const has_layout: bool, const has_inits: bool = switch (ip.indexToKey(ty)) {
4056 .struct_type, .union_type => true,4058 .struct_type => .{ true, true },
4057 .enum_type => |k| k != .generated_tag,4059 .union_type => .{ true, false },
4058 .opaque_type => false,4060 .enum_type => .{ false, true },
4061 .opaque_type => .{ false, false },
4059 else => unreachable,4062 else => unreachable,
4060 };4063 };
4061 if (has_resolution) {4064 if (has_layout) {
4065 // this should only be referenced by the type
4066 const unit: AnalUnit = .wrap(.{ .type_layout = ty });
4067 try units.putNoClobber(gpa, unit, referencer);
4068 }
4069 if (has_inits) {
4062 // this should only be referenced by the type4070 // this should only be referenced by the type
4063 const unit: AnalUnit = .wrap(.{ .type = ty });4071 const unit: AnalUnit = .wrap(.{ .type_inits = ty });
4064 try units.putNoClobber(gpa, unit, referencer);4072 try units.putNoClobber(gpa, unit, referencer);
4065 }4073 }
40664074
4067 // If this is a union with a generated tag, its tag type is automatically referenced.4075 // If this is a union with a generated tag, its tag type is automatically referenced.
4068 // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location.4076 // We don't add this reference for non-generated tags, as those will already be referenced via the union's type resolution, with a better source location.
4069 if (zcu.typeToUnion(Type.fromInterned(ty))) |union_obj| {4077 implicit_tag: {
4070 const tag_ty = union_obj.enum_tag_ty;4078 const loaded_union = zcu.typeToUnion(.fromInterned(ty)) orelse break :implicit_tag;
4071 if (tag_ty != .none) {4079 const tag_ty = loaded_union.enum_tag_type;
4072 if (ip.indexToKey(tag_ty).enum_type == .generated_tag) {4080 if (ip.indexToKey(tag_ty).enum_type != .generated_union_tag) break :implicit_tag;
4073 const gop = try types.getOrPut(gpa, tag_ty);4081 const gop = try types.getOrPut(gpa, tag_ty);
4074 if (!gop.found_existing) gop.value_ptr.* = referencer;4082 if (gop.found_existing) break :implicit_tag;
4075 }4083 gop.value_ptr.* = referencer;
4076 }
4077 }4084 }
40784085
4079 // Queue any decls within this type which would be automatically analyzed.4086 // Queue any decls within this type which would be automatically analyzed.
...@@ -4084,7 +4091,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4084,7 +4091,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4084 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });4091 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu });
4085 const gop = try units.getOrPut(gpa, unit);4092 const gop = try units.getOrPut(gpa, unit);
4086 if (!gop.found_existing) {4093 if (!gop.found_existing) {
4087 log.debug("type '{f}': ref comptime %{}", .{4094 refs_log.debug("type '{f}': ref comptime %{}", .{
4088 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4095 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4089 @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),4096 @intFromEnum(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue),
4090 });4097 });
...@@ -4118,7 +4125,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4118,7 +4125,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4118 {4125 {
4119 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id }));4126 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id }));
4120 if (!gop.found_existing) {4127 if (!gop.found_existing) {
4121 log.debug("type '{f}': ref test %{}", .{4128 refs_log.debug("type '{f}': ref test %{}", .{
4122 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4129 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4123 @intFromEnum(inst_info.inst),4130 @intFromEnum(inst_info.inst),
4124 });4131 });
...@@ -4141,7 +4148,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4141,7 +4148,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4141 const unit: AnalUnit = .wrap(.{ .nav_val = nav });4148 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
4142 const gop = try units.getOrPut(gpa, unit);4149 const gop = try units.getOrPut(gpa, unit);
4143 if (!gop.found_existing) {4150 if (!gop.found_existing) {
4144 log.debug("type '{f}': ref named %{}", .{4151 refs_log.debug("type '{f}': ref named %{}", .{
4145 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4152 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4146 @intFromEnum(inst_info.inst),4153 @intFromEnum(inst_info.inst),
4147 });4154 });
...@@ -4158,7 +4165,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4158,7 +4165,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4158 const unit: AnalUnit = .wrap(.{ .nav_val = nav });4165 const unit: AnalUnit = .wrap(.{ .nav_val = nav });
4159 const gop = try units.getOrPut(gpa, unit);4166 const gop = try units.getOrPut(gpa, unit);
4160 if (!gop.found_existing) {4167 if (!gop.found_existing) {
4161 log.debug("type '{f}': ref named %{}", .{4168 refs_log.debug("type '{f}': ref named %{}", .{
4162 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),4169 Type.fromInterned(ty).containerTypeName(ip).fmt(ip),
4163 @intFromEnum(inst_info.inst),4170 @intFromEnum(inst_info.inst),
4164 });4171 });
...@@ -4177,14 +4184,14 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4177,14 +4184,14 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4177 const other: AnalUnit = .wrap(switch (unit.unwrap()) {4184 const other: AnalUnit = .wrap(switch (unit.unwrap()) {
4178 .nav_val => |n| .{ .nav_ty = n },4185 .nav_val => |n| .{ .nav_ty = n },
4179 .nav_ty => |n| .{ .nav_val = n },4186 .nav_ty => |n| .{ .nav_val = n },
4180 .@"comptime", .type, .func, .memoized_state => break :queue_paired,4187 .@"comptime", .type_layout, .type_inits, .func, .memoized_state => break :queue_paired,
4181 });4188 });
4182 const gop = try units.getOrPut(gpa, other);4189 const gop = try units.getOrPut(gpa, other);
4183 if (gop.found_existing) break :queue_paired;4190 if (gop.found_existing) break :queue_paired;
4184 gop.value_ptr.* = units.values()[unit_idx]; // same reference location4191 gop.value_ptr.* = units.values()[unit_idx]; // same reference location
4185 }4192 }
41864193
4187 log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)});4194 refs_log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)});
41884195
4189 if (zcu.reference_table.get(unit)) |first_ref_idx| {4196 if (zcu.reference_table.get(unit)) |first_ref_idx| {
4190 assert(first_ref_idx != std.math.maxInt(u32));4197 assert(first_ref_idx != std.math.maxInt(u32));
...@@ -4193,7 +4200,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4193,7 +4200,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4193 const ref = zcu.all_references.items[ref_idx];4200 const ref = zcu.all_references.items[ref_idx];
4194 const gop = try units.getOrPut(gpa, ref.referenced);4201 const gop = try units.getOrPut(gpa, ref.referenced);
4195 if (!gop.found_existing) {4202 if (!gop.found_existing) {
4196 log.debug("unit '{f}': ref unit '{f}'", .{4203 refs_log.debug("unit '{f}': ref unit '{f}'", .{
4197 zcu.fmtAnalUnit(unit),4204 zcu.fmtAnalUnit(unit),
4198 zcu.fmtAnalUnit(ref.referenced),4205 zcu.fmtAnalUnit(ref.referenced),
4199 });4206 });
...@@ -4213,7 +4220,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R...@@ -4213,7 +4220,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoArrayHashMapUnmanaged(AnalUnit, ?R
4213 const ref = zcu.all_type_references.items[ref_idx];4220 const ref = zcu.all_type_references.items[ref_idx];
4214 const gop = try types.getOrPut(gpa, ref.referenced);4221 const gop = try types.getOrPut(gpa, ref.referenced);
4215 if (!gop.found_existing) {4222 if (!gop.found_existing) {
4216 log.debug("unit '{f}': ref type '{f}'", .{4223 refs_log.debug("unit '{f}': ref type '{f}'", .{
4217 zcu.fmtAnalUnit(unit),4224 zcu.fmtAnalUnit(unit),
4218 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),4225 Type.fromInterned(ref.referenced).containerTypeName(ip).fmt(ip),
4219 });4226 });
...@@ -4323,9 +4330,8 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void...@@ -4323,9 +4330,8 @@ fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void
4323 return writer.print("comptime(inst=<lost> [{}])", .{@intFromEnum(cu_id)});4330 return writer.print("comptime(inst=<lost> [{}])", .{@intFromEnum(cu_id)});
4324 }4331 }
4325 },4332 },
4326 .nav_val => |nav| return writer.print("nav_val('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),4333 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),
4327 .nav_ty => |nav| return writer.print("nav_ty('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(nav) }),4334 .type_layout, .type_inits => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
4328 .type => |ty| return writer.print("ty('{f}' [{}])", .{ Type.fromInterned(ty).containerTypeName(ip).fmt(ip), @intFromEnum(ty) }),
4329 .func => |func| {4335 .func => |func| {
4330 const nav = zcu.funcInfo(func).owner_nav;4336 const nav = zcu.funcInfo(func).owner_nav;
4331 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });4337 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });
...@@ -4347,18 +4353,17 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void...@@ -4347,18 +4353,17 @@ fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void
4347 const file_path = zcu.fileByIndex(info.file).path;4353 const file_path = zcu.fileByIndex(info.file).path;
4348 return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });4354 return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @intFromEnum(info.inst) });
4349 },4355 },
4350 .nav_val => |nav| {4356 .nav_val, .nav_ty => |nav, tag| {
4351 const fqn = ip.getNav(nav).fqn;4357 const fqn = ip.getNav(nav).fqn;
4352 return writer.print("nav_val('{f}')", .{fqn.fmt(ip)});4358 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) });
4353 },4359 },
4354 .nav_ty => |nav| {4360 .type_layout, .type_inits => |ip_index, tag| {
4355 const fqn = ip.getNav(nav).fqn;4361 const name = Type.fromInterned(ip_index).containerTypeName(ip);
4356 return writer.print("nav_ty('{f}')", .{fqn.fmt(ip)});4362 return writer.print("{t}('{f}')", .{ tag, name.fmt(ip) });
4357 },4363 },
4358 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {4364 .func_ies => |ip_index| {
4359 .struct_type, .union_type, .enum_type => return writer.print("type('{f}')", .{Type.fromInterned(ip_index).containerTypeName(ip).fmt(ip)}),4365 const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn;
4360 .func => |f| return writer.print("ies('{f}')", .{ip.getNav(f.owner_nav).fqn.fmt(ip)}),4366 return writer.print("func_ies('{f}')", .{fqn.fmt(ip)});
4361 else => unreachable,
4362 },4367 },
4363 .zon_file => |file| {4368 .zon_file => |file| {
4364 const file_path = zcu.fileByIndex(file).path;4369 const file_path = zcu.fileByIndex(file).path;
src/Zcu/PerThread.zig+807-697
...@@ -598,44 +598,38 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -598,44 +598,38 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
598 // Value is whether the declaration is `pub`.598 // Value is whether the declaration is `pub`.
599 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, bool) = .empty;599 var old_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, bool) = .empty;
600 defer old_names.deinit(zcu.gpa);600 defer old_names.deinit(zcu.gpa);
601 {601 for (old_zir.typeDecls(old_inst)) |decl_inst| {
602 var it = old_zir.declIterator(old_inst);602 const old_decl = old_zir.getDeclaration(decl_inst);
603 while (it.next()) |decl_inst| {603 if (old_decl.name == .empty) continue;
604 const old_decl = old_zir.getDeclaration(decl_inst);604 const name_ip = try zcu.intern_pool.getOrPutString(
605 if (old_decl.name == .empty) continue;605 zcu.gpa,
606 const name_ip = try zcu.intern_pool.getOrPutString(606 io,
607 zcu.gpa,607 pt.tid,
608 io,608 old_zir.nullTerminatedString(old_decl.name),
609 pt.tid,609 .no_embedded_nulls,
610 old_zir.nullTerminatedString(old_decl.name),610 );
611 .no_embedded_nulls,611 try old_names.put(zcu.gpa, name_ip, old_decl.is_pub);
612 );
613 try old_names.put(zcu.gpa, name_ip, old_decl.is_pub);
614 }
615 }612 }
616 var any_change = false;613 var any_change = false;
617 {614 for (new_zir.typeDecls(new_inst)) |decl_inst| {
618 var it = new_zir.declIterator(new_inst);615 const new_decl = new_zir.getDeclaration(decl_inst);
619 while (it.next()) |decl_inst| {616 if (new_decl.name == .empty) continue;
620 const new_decl = new_zir.getDeclaration(decl_inst);617 const name_ip = try zcu.intern_pool.getOrPutString(
621 if (new_decl.name == .empty) continue;618 zcu.gpa,
622 const name_ip = try zcu.intern_pool.getOrPutString(619 io,
623 zcu.gpa,620 pt.tid,
624 io,621 new_zir.nullTerminatedString(new_decl.name),
625 pt.tid,622 .no_embedded_nulls,
626 new_zir.nullTerminatedString(new_decl.name),623 );
627 .no_embedded_nulls,624 if (old_names.fetchSwapRemove(name_ip)) |kv| {
628 );625 if (kv.value == new_decl.is_pub) continue;
629 if (old_names.fetchSwapRemove(name_ip)) |kv| {
630 if (kv.value == new_decl.is_pub) continue;
631 }
632 // Name added, or changed whether it's pub
633 any_change = true;
634 try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{
635 .namespace = tracked_inst_index,
636 .name = name_ip,
637 } });
638 }626 }
627 // Name added, or changed whether it's pub
628 any_change = true;
629 try zcu.markDependeeOutdated(.not_marked_po, .{ .namespace_name = .{
630 .namespace = tracked_inst_index,
631 .name = name_ip,
632 } });
639 }633 }
640 // The only elements remaining in `old_names` now are any names which were removed.634 // The only elements remaining in `old_names` now are any names which were removed.
641 for (old_names.keys()) |name_ip| {635 for (old_names.keys()) |name_ip| {
...@@ -674,24 +668,49 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {...@@ -674,24 +668,49 @@ pub fn updateZirRefs(pt: Zcu.PerThread) Allocator.Error!void {
674 }668 }
675}669}
676670
677/// Ensures that `zcu.fileRootType` on this `file_index` gives an up-to-date answer.671/// Ensures that `zcu.fileRootType` on this `file_index` is populated (not `.none`). This implies
678/// Returns `error.AnalysisFail` if the file has an error.672/// that the file's namespace is scanned, discovering declarations.
679pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {673///
680 const file_root_type = pt.zcu.fileRootType(file_index);674/// Typical Zig compilations begin by claling this function on the root source file of the standard
681 if (file_root_type != .none) {675/// library, `lib/std/std.zig`. The resulting namespace scan discovers a `comptime` declaration in
682 if (pt.ensureTypeUpToDate(file_root_type)) |_| {676/// that file, which is queued for analysis, and everything goes from there.
683 return;677pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Allocator.Error || Io.Cancelable)!void {
684 } else |err| switch (err) {678 dev.check(.sema);
685 error.AnalysisFail => {679
686 // The file's root `struct_decl` has, at some point, been lost, because the file failed AstGen.680 const tracy = trace(@src());
687 // Clear `file_root_type`, and try the `semaFile` call below, in case the instruction has since681 defer tracy.end();
688 // been discovered under a new `TrackedInst.Index`.682
689 pt.zcu.setFileRootType(file_index, .none);683 const zcu = pt.zcu;
690 },684 const comp = zcu.comp;
691 else => |e| return e,685 const io = comp.io;
692 }686 const gpa = comp.gpa;
693 }687 const ip = &zcu.intern_pool;
694 return pt.semaFile(file_index);688
689 if (zcu.fileRootType(file_index) != .none) return; // already good
690
691 const file = zcu.fileByIndex(file_index);
692 assert(file.getMode() == .zig);
693 const struct_decl = file.zir.?.getStructDecl(.main_struct_inst);
694 const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{
695 .file = file_index,
696 .inst = .main_struct_inst,
697 });
698 const file_root_type = try Sema.analyzeStructDecl(
699 pt,
700 file_index,
701 &file.zir.?,
702 .none,
703 tracked_inst,
704 &struct_decl,
705 null,
706 &.{},
707 .{ .exact = .{
708 .name = try file.internFullyQualifiedName(pt),
709 .nav = .none,
710 } },
711 );
712 zcu.setFileRootType(file_index, file_root_type.toIntern());
713 if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1;
695}714}
696715
697/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.716/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.
...@@ -1012,6 +1031,238 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu...@@ -1012,6 +1031,238 @@ fn analyzeComptimeUnit(pt: Zcu.PerThread, cu_id: InternPool.ComptimeUnit.Id) Zcu
1012 try sema.flushExports();1031 try sema.flushExports();
1013}1032}
10141033
1034/// Ensures that the layout of the given `struct` or `union` type is fully up-to-date, performing
1035/// re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or union. Returns
1036/// `error.AnalysisFail` if an analysis error is encountered during type resolution; the caller is
1037/// free to ignore this, since the error is already registered.
1038pub fn ensureTypeLayoutUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
1039 const tracy = trace(@src());
1040 defer tracy.end();
1041
1042 const zcu = pt.zcu;
1043 const gpa = zcu.gpa;
1044
1045 const anal_unit: AnalUnit = .wrap(.{ .type_layout = ty.toIntern() });
1046
1047 log.debug("ensureTypeLayoutUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
1048
1049 assert(!zcu.analysis_in_progress.contains(anal_unit));
1050
1051 // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's
1052 // the only indicator as to whether or not analysis is required; when a struct/union is
1053 // first created, it's marked as outdated.
1054 // MLUGG TODO: make that actually true, it's a good strategy here!
1055
1056 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1057 zcu.potentially_outdated.swapRemove(anal_unit);
1058
1059 if (was_outdated) {
1060 _ = zcu.outdated_ready.swapRemove(anal_unit);
1061 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
1062 if (dev.env.supports(.incremental)) {
1063 zcu.deleteUnitExports(anal_unit);
1064 zcu.deleteUnitReferences(anal_unit);
1065 zcu.deleteUnitCompileLogs(anal_unit);
1066 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1067 kv.value.destroy(gpa);
1068 }
1069 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1070 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1071 }
1072 // For types, we already know that we have to invalidate all dependees.
1073 // TODO: we actually *could* detect whether everything was the same. should we bother?
1074 try zcu.markDependeeOutdated(.marked_po, .{ .type_layout = ty.toIntern() });
1075 } else {
1076 // We can trust the current information about this unit.
1077 if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
1078 if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail;
1079 return;
1080 }
1081
1082 if (zcu.comp.debugIncremental()) {
1083 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
1084 info.last_update_gen = zcu.generation;
1085 info.deps.clearRetainingCapacity();
1086 }
1087
1088 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(&zcu.intern_pool).toSlice(&zcu.intern_pool), null);
1089 defer unit_tracking.end(zcu);
1090
1091 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1092 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1093
1094 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1095 defer analysis_arena.deinit();
1096
1097 var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa);
1098 defer comptime_err_ret_trace.deinit();
1099
1100 const file = zcu.namespacePtr(ty.getNamespaceIndex(zcu)).fileScope(zcu);
1101
1102 var sema: Sema = .{
1103 .pt = pt,
1104 .gpa = gpa,
1105 .arena = analysis_arena.allocator(),
1106 .code = file.zir.?,
1107 .owner = anal_unit,
1108 .func_index = .none,
1109 .func_is_naked = false,
1110 .fn_ret_ty = .void,
1111 .fn_ret_ty_ies = null,
1112 .comptime_err_ret_trace = &comptime_err_ret_trace,
1113 };
1114 defer sema.deinit();
1115
1116 const result = switch (ty.containerLayout(zcu)) {
1117 .auto, .@"extern" => switch (ty.zigTypeTag(zcu)) {
1118 .@"struct" => Sema.type_resolution.resolveStructLayout(&sema, ty),
1119 .@"union" => Sema.type_resolution.resolveUnionLayout(&sema, ty),
1120 else => unreachable,
1121 },
1122 .@"packed" => switch (ty.zigTypeTag(zcu)) {
1123 .@"struct" => Sema.type_resolution.resolvePackedStructLayout(&sema, ty),
1124 .@"union" => Sema.type_resolution.resolvePackedUnionLayout(&sema, ty),
1125 else => unreachable,
1126 },
1127 };
1128 result catch |err| switch (err) {
1129 error.AnalysisFail => {
1130 if (!zcu.failed_analysis.contains(anal_unit)) {
1131 // If this unit caused the error, it would have an entry in `failed_analysis`.
1132 // Since it does not, this must be a transitive failure.
1133 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1134 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1135 }
1136 return error.AnalysisFail;
1137 },
1138 error.OutOfMemory,
1139 error.Canceled,
1140 => |e| return e,
1141 error.ComptimeReturn => unreachable,
1142 error.ComptimeBreak => unreachable,
1143 };
1144
1145 sema.flushExports() catch |err| switch (err) {
1146 error.OutOfMemory => |e| return e,
1147 };
1148
1149 codegen_type: {
1150 if (zcu.comp.config.use_llvm) break :codegen_type;
1151 if (file.mod.?.strip) break :codegen_type;
1152 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
1153 try zcu.comp.queueJob(.{ .link_type = ty.toIntern() });
1154 }
1155}
1156
1157/// Ensures that the default/tag values of the given `struct` or `enum` type are fully up-to-date,
1158/// performing re-analysis if necessary. Asserts that `ty` is a struct (not a tuple!) or an enum.
1159/// Returns `error.AnalysisFail` if an analysis error is encountered during resolution; the caller
1160/// is free to ignore this, since the error is already registered.
1161pub fn ensureTypeInitsUpToDate(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
1162 const tracy = trace(@src());
1163 defer tracy.end();
1164
1165 const zcu = pt.zcu;
1166 const gpa = zcu.gpa;
1167
1168 const anal_unit: AnalUnit = .wrap(.{ .type_inits = ty.toIntern() });
1169
1170 log.debug("ensureTypeInitsUpToDate {f}", .{zcu.fmtAnalUnit(anal_unit)});
1171
1172 assert(!zcu.analysis_in_progress.contains(anal_unit));
1173
1174 // Determine whether or not this type is outdated. For this kind of `AnalUnit`, that's
1175 // the only indicator as to whether or not analysis is required; when a struct/enum is
1176 // first created, it's marked as outdated.
1177 // MLUGG TODO: make that actually true, it's a good strategy here!
1178
1179 const was_outdated = zcu.outdated.swapRemove(anal_unit) or
1180 zcu.potentially_outdated.swapRemove(anal_unit);
1181
1182 if (was_outdated) {
1183 _ = zcu.outdated_ready.swapRemove(anal_unit);
1184 // `was_outdated` can be true in the initial update for comptime units, so this isn't a `dev.check`.
1185 if (dev.env.supports(.incremental)) {
1186 zcu.deleteUnitExports(anal_unit);
1187 zcu.deleteUnitReferences(anal_unit);
1188 zcu.deleteUnitCompileLogs(anal_unit);
1189 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
1190 kv.value.destroy(gpa);
1191 }
1192 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
1193 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
1194 }
1195 // For types, we already know that we have to invalidate all dependees.
1196 // TODO: we actually *could* detect whether everything was the same. should we bother?
1197 try zcu.markDependeeOutdated(.marked_po, .{ .type_inits = ty.toIntern() });
1198 } else {
1199 // We can trust the current information about this unit.
1200 if (zcu.failed_analysis.contains(anal_unit)) return error.AnalysisFail;
1201 if (zcu.transitive_failed_analysis.contains(anal_unit)) return error.AnalysisFail;
1202 return;
1203 }
1204
1205 if (zcu.comp.debugIncremental()) {
1206 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
1207 info.last_update_gen = zcu.generation;
1208 info.deps.clearRetainingCapacity();
1209 }
1210
1211 const unit_tracking = zcu.trackUnitSema(ty.containerTypeName(&zcu.intern_pool).toSlice(&zcu.intern_pool), null);
1212 defer unit_tracking.end(zcu);
1213
1214 try zcu.analysis_in_progress.put(gpa, anal_unit, {});
1215 defer assert(zcu.analysis_in_progress.swapRemove(anal_unit));
1216
1217 var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
1218 defer analysis_arena.deinit();
1219
1220 var comptime_err_ret_trace: std.array_list.Managed(Zcu.LazySrcLoc) = .init(gpa);
1221 defer comptime_err_ret_trace.deinit();
1222
1223 const zir = zcu.namespacePtr(ty.getNamespaceIndex(zcu)).fileScope(zcu).zir.?;
1224
1225 var sema: Sema = .{
1226 .pt = pt,
1227 .gpa = gpa,
1228 .arena = analysis_arena.allocator(),
1229 .code = zir,
1230 .owner = anal_unit,
1231 .func_index = .none,
1232 .func_is_naked = false,
1233 .fn_ret_ty = .void,
1234 .fn_ret_ty_ies = null,
1235 .comptime_err_ret_trace = &comptime_err_ret_trace,
1236 };
1237 defer sema.deinit();
1238
1239 const result = switch (ty.zigTypeTag(zcu)) {
1240 .@"struct" => Sema.type_resolution.resolveStructDefaults(&sema, ty),
1241 .@"enum" => Sema.type_resolution.resolveEnumValues(&sema, ty),
1242 else => unreachable,
1243 };
1244 result catch |err| switch (err) {
1245 error.AnalysisFail => {
1246 if (!zcu.failed_analysis.contains(anal_unit)) {
1247 // If this unit caused the error, it would have an entry in `failed_analysis`.
1248 // Since it does not, this must be a transitive failure.
1249 try zcu.transitive_failed_analysis.put(gpa, anal_unit, {});
1250 log.debug("mark transitive analysis failure for {f}", .{zcu.fmtAnalUnit(anal_unit)});
1251 }
1252 return error.AnalysisFail;
1253 },
1254 error.OutOfMemory,
1255 error.Canceled,
1256 => |e| return e,
1257 error.ComptimeReturn => unreachable,
1258 error.ComptimeBreak => unreachable,
1259 };
1260
1261 sema.flushExports() catch |err| switch (err) {
1262 error.OutOfMemory => |e| return e,
1263 };
1264}
1265
1015/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis1266/// Ensures that the resolved value of the given `Nav` is fully up-to-date, performing re-analysis
1016/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is1267/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
1017/// free to ignore this, since the error is already registered.1268/// free to ignore this, since the error is already registered.
...@@ -1360,7 +1611,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1360,7 +1611,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
13601611
1361 // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,1612 // This resolves the type of the resolved value, not that value itself. If `nav_val` is a struct type,
1362 // this resolves the type `type` (which needs no resolution), not the struct itself.1613 // this resolves the type `type` (which needs no resolution), not the struct itself.
1363 try nav_ty.resolveLayout(pt);1614 try sema.ensureLayoutResolved(nav_ty);
13641615
1365 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {1616 const queue_linker_work, const is_owned_fn = switch (ip.indexToKey(nav_val.toIntern())) {
1366 .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen1617 .func => |f| .{ true, f.owner_nav == nav_id }, // note that this lets function aliases reach codegen
...@@ -1377,7 +1628,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1377,7 +1628,7 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1377 if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {1628 if (zir_decl.align_body != null and !target_util.supportsFunctionAlignment(zcu.getTarget())) {
1378 return sema.fail(&block, align_src, "target does not support function alignment", .{});1629 return sema.fail(&block, align_src, "target does not support function alignment", .{});
1379 }1630 }
1380 } else if (try nav_ty.comptimeOnlySema(pt)) {1631 } else if (nav_ty.comptimeOnly(zcu)) {
1381 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.1632 // alignment, linksection, addrspace annotations are not allowed for comptime-only types.
1382 const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {1633 const reason: []const u8 = switch (ip.indexToKey(nav_val.toIntern())) {
1383 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*1634 .func => "function alias", // slightly clearer message, since you *can* specify these on function *declarations*
...@@ -1420,12 +1671,11 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr...@@ -1420,12 +1671,11 @@ fn analyzeNavVal(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileErr
1420 queue_codegen: {1671 queue_codegen: {
1421 if (!queue_linker_work) break :queue_codegen;1672 if (!queue_linker_work) break :queue_codegen;
14221673
1423 if (!try nav_ty.hasRuntimeBitsSema(pt)) {1674 if (!nav_ty.hasRuntimeBits(zcu)) {
1424 if (zcu.comp.config.use_llvm) break :queue_codegen;1675 if (zcu.comp.config.use_llvm) break :queue_codegen;
1425 if (file.mod.?.strip) break :queue_codegen;1676 if (file.mod.?.strip) break :queue_codegen;
1426 }1677 }
14271678
1428 // This job depends on any resolve_type_fully jobs queued up before it.
1429 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);1679 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
1430 try zcu.comp.queueJob(.{ .link_nav = nav_id });1680 try zcu.comp.queueJob(.{ .link_nav = nav_id });
1431 }1681 }
...@@ -1628,7 +1878,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr...@@ -1628,7 +1878,7 @@ fn analyzeNavType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Zcu.CompileEr
1628 break :ty .fromInterned(type_ref.toInterned().?);1878 break :ty .fromInterned(type_ref.toInterned().?);
1629 };1879 };
16301880
1631 try resolved_ty.resolveLayout(pt);1881 try sema.ensureLayoutResolved(resolved_ty);
16321882
1633 // In the case where the type is specified, this function is also responsible for resolving1883 // In the case where the type is specified, this function is also responsible for resolving
1634 // the pointer modifiers, i.e. alignment, linksection, addrspace.1884 // the pointer modifiers, i.e. alignment, linksection, addrspace.
...@@ -1765,9 +2015,9 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z...@@ -1765,9 +2015,9 @@ pub fn ensureFuncBodyUpToDate(pt: Zcu.PerThread, func_index: InternPool.Index) Z
17652015
1766 if (was_outdated) {2016 if (was_outdated) {
1767 if (ies_outdated) {2017 if (ies_outdated) {
1768 try zcu.markDependeeOutdated(.marked_po, .{ .interned = func_index });2018 try zcu.markDependeeOutdated(.marked_po, .{ .func_ies = func_index });
1769 } else {2019 } else {
1770 try zcu.markPoDependeeUpToDate(.{ .interned = func_index });2020 try zcu.markPoDependeeUpToDate(.{ .func_ies = func_index });
1771 }2021 }
1772 }2022 }
17732023
...@@ -1817,7 +2067,7 @@ fn analyzeFuncBody(...@@ -1817,7 +2067,7 @@ fn analyzeFuncBody(
18172067
1818 log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)});2068 log.debug("analyze and generate fn body {f}", .{zcu.fmtAnalUnit(anal_unit)});
18192069
1820 var air = try pt.analyzeFnBodyInner(func_index);2070 var air = try pt.analyzeFuncBodyInner(func_index);
1821 errdefer air.deinit(gpa);2071 errdefer air.deinit(gpa);
18222072
1823 const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or2073 const ies_outdated = !func.analysisUnordered(ip).inferred_error_set or
...@@ -1833,7 +2083,6 @@ fn analyzeFuncBody(...@@ -1833,7 +2083,6 @@ fn analyzeFuncBody(
1833 return .{ .ies_outdated = ies_outdated };2083 return .{ .ies_outdated = ies_outdated };
1834 }2084 }
18352085
1836 // This job depends on any resolve_type_fully jobs queued up before it.
1837 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);2086 zcu.codegen_prog_node.increaseEstimatedTotalItems(1);
1838 comp.link_prog_node.increaseEstimatedTotalItems(1);2087 comp.link_prog_node.increaseEstimatedTotalItems(1);
1839 try comp.queueJob(.{ .codegen_func = .{2088 try comp.queueJob(.{ .codegen_func = .{
...@@ -1844,94 +2093,12 @@ fn analyzeFuncBody(...@@ -1844,94 +2093,12 @@ fn analyzeFuncBody(
1844 return .{ .ies_outdated = ies_outdated };2093 return .{ .ies_outdated = ies_outdated };
1845}2094}
18462095
1847pub fn semaMod(pt: Zcu.PerThread, mod: *Module) !void {
1848 dev.check(.sema);
1849 const file_index = pt.zcu.module_roots.get(mod).?.unwrap().?;
1850 const root_type = pt.zcu.fileRootType(file_index);
1851 if (root_type == .none) {
1852 return pt.semaFile(file_index);
1853 }
1854}
1855
1856fn createFileRootStruct(
1857 pt: Zcu.PerThread,
1858 file_index: Zcu.File.Index,
1859 namespace_index: Zcu.Namespace.Index,
1860 replace_existing: bool,
1861) Allocator.Error!InternPool.Index {
1862 const zcu = pt.zcu;
1863 const gpa = zcu.gpa;
1864 const io = zcu.comp.io;
1865 const ip = &zcu.intern_pool;
1866 const file = zcu.fileByIndex(file_index);
1867 const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1868 assert(extended.opcode == .struct_decl);
1869 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
1870 assert(!small.has_captures_len);
1871 assert(!small.has_backing_int);
1872 assert(small.layout == .auto);
1873 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1874 const fields_len = if (small.has_fields_len) blk: {
1875 const fields_len = file.zir.?.extra[extra_index];
1876 extra_index += 1;
1877 break :blk fields_len;
1878 } else 0;
1879 const decls_len = if (small.has_decls_len) blk: {
1880 const decls_len = file.zir.?.extra[extra_index];
1881 extra_index += 1;
1882 break :blk decls_len;
1883 } else 0;
1884 const decls = file.zir.?.bodySlice(extra_index, decls_len);
1885 extra_index += decls_len;
1886
1887 const tracked_inst = try ip.trackZir(gpa, io, pt.tid, .{
1888 .file = file_index,
1889 .inst = .main_struct_inst,
1890 });
1891 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
1892 .layout = .auto,
1893 .fields_len = fields_len,
1894 .known_non_opv = small.known_non_opv,
1895 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
1896 .any_comptime_fields = small.any_comptime_fields,
1897 .any_default_inits = small.any_default_inits,
1898 .inits_resolved = false,
1899 .any_aligned_fields = small.any_aligned_fields,
1900 .key = .{ .declared = .{
1901 .zir_index = tracked_inst,
1902 .captures = &.{},
1903 } },
1904 }, replace_existing)) {
1905 .existing => unreachable, // we wouldn't be analysing the file root if this type existed
1906 .wip => |wip| wip,
1907 };
1908 errdefer wip_ty.cancel(ip, pt.tid);
1909
1910 wip_ty.setName(ip, try file.internFullyQualifiedName(pt), .none);
1911 ip.namespacePtr(namespace_index).owner_type = wip_ty.index;
1912
1913 if (zcu.comp.config.incremental) {
1914 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = tracked_inst });
1915 }
1916
1917 try pt.scanNamespace(namespace_index, decls);
1918 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
1919 codegen_type: {
1920 if (file.mod.?.strip) break :codegen_type;
1921 // This job depends on any resolve_type_fully jobs queued up before it.
1922 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
1923 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
1924 }
1925 zcu.setFileRootType(file_index, wip_ty.index);
1926 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
1927 return wip_ty.finish(ip, namespace_index);
1928}
1929
1930/// Re-scan the namespace of a file's root struct type on an incremental update.2096/// Re-scan the namespace of a file's root struct type on an incremental update.
1931/// The file must have successfully populated ZIR.2097/// The file must have successfully populated ZIR.
1932/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.2098/// If the file's root struct type is not populated (the file is unreferenced), nothing is done.
1933/// This is called by `updateZirRefs` for all updated files before the main work loop.2099/// This is called by `updateZirRefs` for all updated files before the main work loop.
1934/// This function does not perform any semantic analysis.2100/// This function does not perform any semantic analysis.
2101/// MLUGG TODO: mmmmm i have no idea if this makes sense... tbhwy i just want to update all *changed* namespaces at the start of an update or something lol
1935fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void {2102fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void {
1936 const zcu = pt.zcu;2103 const zcu = pt.zcu;
19372104
...@@ -1945,48 +2112,11 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator....@@ -1945,48 +2112,11 @@ fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.
1945 });2112 });
19462113
1947 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);2114 const namespace_index = Type.fromInterned(file_root_type).getNamespaceIndex(zcu);
1948 const decls = decls: {2115 const decls = file.zir.?.getStructDecl(.main_struct_inst).decls;
1949 const extended = file.zir.?.instructions.items(.data)[@intFromEnum(Zir.Inst.Index.main_struct_inst)].extended;
1950 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
1951
1952 var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).@"struct".fields.len;
1953 extra_index += @intFromBool(small.has_fields_len);
1954 const decls_len = if (small.has_decls_len) blk: {
1955 const decls_len = file.zir.?.extra[extra_index];
1956 extra_index += 1;
1957 break :blk decls_len;
1958 } else 0;
1959 break :decls file.zir.?.bodySlice(extra_index, decls_len);
1960 };
1961 try pt.scanNamespace(namespace_index, decls);2116 try pt.scanNamespace(namespace_index, decls);
1962 zcu.namespacePtr(namespace_index).generation = zcu.generation;2117 zcu.namespacePtr(namespace_index).generation = zcu.generation;
1963}2118}
19642119
1965fn semaFile(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.SemaError!void {
1966 const tracy = trace(@src());
1967 defer tracy.end();
1968
1969 const zcu = pt.zcu;
1970 const file = zcu.fileByIndex(file_index);
1971 assert(file.getMode() == .zig);
1972 assert(zcu.fileRootType(file_index) == .none);
1973
1974 assert(file.zir != null);
1975
1976 const new_namespace_index = try pt.createNamespace(.{
1977 .parent = .none,
1978 .owner_type = undefined, // set in `createFileRootStruct`
1979 .file_scope = file_index,
1980 .generation = zcu.generation,
1981 });
1982 const struct_ty = try pt.createFileRootStruct(file_index, new_namespace_index, false);
1983 errdefer zcu.intern_pool.remove(pt.tid, struct_ty);
1984
1985 if (zcu.comp.time_report) |*tr| {
1986 tr.stats.n_imported_files += 1;
1987 }
1988}
1989
1990/// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is2120/// Called by AstGen worker threads when an import is seen. If `new_file` is returned, the caller is
1991/// then responsible for queueing a new AstGen job for the new file.2121/// then responsible for queueing a new AstGen job for the new file.
1992/// Assumes that `comp.mutex` is NOT locked. It will be locked by this function where necessary.2122/// Assumes that `comp.mutex` is NOT locked. It will be locked by this function where necessary.
...@@ -2878,15 +3008,15 @@ const ScanDeclIter = struct {...@@ -2878,15 +3008,15 @@ const ScanDeclIter = struct {
28783008
2879 if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) {3009 if (existing_unit == null and (want_analysis or decl.linkage == .@"export")) {
2880 log.debug(3010 log.debug(
2881 "scanDecl queue analyze_comptime_unit file='{s}' unit={f}",3011 "scanDecl queue analyze_unit file='{s}' unit={f}",
2882 .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) },3012 .{ namespace.fileScope(zcu).sub_file_path, zcu.fmtAnalUnit(unit) },
2883 );3013 );
2884 try comp.queueJob(.{ .analyze_comptime_unit = unit });3014 try comp.queueJob(.{ .analyze_unit = unit });
2885 }3015 }
2886 }3016 }
2887};3017};
28883018
2889fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {3019fn analyzeFuncBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaError!Air {
2890 const tracy = trace(@src());3020 const tracy = trace(@src());
2891 defer tracy.end();3021 defer tracy.end();
28923022
...@@ -3020,16 +3150,12 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE...@@ -3020,16 +3150,12 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
3020 const gop = sema.inst_map.getOrPutAssumeCapacity(inst);3150 const gop = sema.inst_map.getOrPutAssumeCapacity(inst);
3021 if (gop.found_existing) continue; // provided above by comptime arg3151 if (gop.found_existing) continue; // provided above by comptime arg
30223152
3023 const param_ty = fn_ty_info.param_types.get(ip)[runtime_param_index];3153 const param_ty: Type = .fromInterned(fn_ty_info.param_types.get(ip)[runtime_param_index]);
3024 runtime_param_index += 1;3154 runtime_param_index += 1;
30253155
3026 const opt_opv = sema.typeHasOnePossibleValue(Type.fromInterned(param_ty)) catch |err| switch (err) {3156 try sema.ensureLayoutResolved(param_ty);
3027 error.ComptimeReturn => unreachable,3157 if (try param_ty.onePossibleValue(pt)) |opv| {
3028 error.ComptimeBreak => unreachable,3158 gop.value_ptr.* = .fromValue(opv);
3029 else => |e| return e,
3030 };
3031 if (opt_opv) |opv| {
3032 gop.value_ptr.* = Air.internedToRef(opv.toIntern());
3033 continue;3159 continue;
3034 }3160 }
3035 const arg_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);3161 const arg_index: Air.Inst.Index = @enumFromInt(sema.air_instructions.len);
...@@ -3038,12 +3164,14 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE...@@ -3038,12 +3164,14 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
3038 sema.air_instructions.appendAssumeCapacity(.{3164 sema.air_instructions.appendAssumeCapacity(.{
3039 .tag = .arg,3165 .tag = .arg,
3040 .data = .{ .arg = .{3166 .data = .{ .arg = .{
3041 .ty = Air.internedToRef(param_ty),3167 .ty = .fromIntern(param_ty.toIntern()),
3042 .zir_param_index = @intCast(zir_param_index),3168 .zir_param_index = @intCast(zir_param_index),
3043 } },3169 } },
3044 });3170 });
3045 }3171 }
30463172
3173 try sema.ensureLayoutResolved(sema.fn_ret_ty);
3174
3047 const last_arg_index = inner_block.instructions.items.len;3175 const last_arg_index = inner_block.instructions.items.len;
30483176
3049 // Save the error trace as our first action in the function.3177 // Save the error trace as our first action in the function.
...@@ -3103,21 +3231,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE...@@ -3103,21 +3231,9 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
3103 func.setResolvedErrorSet(ip, io, ies.resolved);3231 func.setResolvedErrorSet(ip, io, ies.resolved);
3104 }3232 }
31053233
3234 // MLUGG TODO: i think this can go away and the assert move to the defer?
3106 assert(zcu.analysis_in_progress.swapRemove(anal_unit));3235 assert(zcu.analysis_in_progress.swapRemove(anal_unit));
31073236
3108 // Finally we must resolve the return type and parameter types so that backends
3109 // have full access to type information.
3110 // Crucially, this happens *after* we set the function state to success above,
3111 // so that dependencies on the function body will now be satisfied rather than
3112 // result in circular dependency errors.
3113 // TODO: this can go away once we fix backends having to resolve `StackTrace`.
3114 // The codegen timing guarantees that the parameter types will be populated.
3115 sema.resolveFnTypes(fn_ty, inner_block.nodeOffset(.zero)) catch |err| switch (err) {
3116 error.ComptimeReturn => unreachable,
3117 error.ComptimeBreak => unreachable,
3118 else => |e| return e,
3119 };
3120
3121 try sema.flushExports();3237 try sema.flushExports();
31223238
3123 defer {3239 defer {
...@@ -3605,16 +3721,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error!...@@ -3605,16 +3721,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error!
36053721
3606 if (info.flags.size == .c) canon_info.flags.is_allowzero = true;3722 if (info.flags.size == .c) canon_info.flags.is_allowzero = true;
36073723
3608 // Canonicalize non-zero alignment. If it matches the ABI alignment of the pointee
3609 // type, we change it to 0 here. If this causes an assertion trip because the
3610 // pointee type needs to be resolved more, that needs to be done before calling
3611 // this ptr() function.
3612 if (info.flags.alignment != .none and
3613 info.flags.alignment == Type.fromInterned(info.child).abiAlignment(pt.zcu))
3614 {
3615 canon_info.flags.alignment = .none;
3616 }
3617
3618 switch (info.flags.vector_index) {3724 switch (info.flags.vector_index) {
3619 // Canonicalize host_size. If it matches the bit size of the pointee type,3725 // Canonicalize host_size. If it matches the bit size of the pointee type,
3620 // we change it to 0 here. If this causes an assertion trip, the pointee type3726 // we change it to 0 here. If this causes an assertion trip, the pointee type
...@@ -3632,16 +3738,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error!...@@ -3632,16 +3738,6 @@ pub fn ptrType(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Allocator.Error!
3632 return Type.fromInterned(try pt.intern(.{ .ptr_type = canon_info }));3738 return Type.fromInterned(try pt.intern(.{ .ptr_type = canon_info }));
3633}3739}
36343740
3635/// Like `ptrType`, but if `info` specifies an `alignment`, first ensures the pointer
3636/// child type's alignment is resolved so that an invalid alignment is not used.
3637/// In general, prefer this function during semantic analysis.
3638pub fn ptrTypeSema(pt: Zcu.PerThread, info: InternPool.Key.PtrType) Zcu.SemaError!Type {
3639 if (info.flags.alignment != .none) {
3640 _ = try Type.fromInterned(info.child).abiAlignmentSema(pt);
3641 }
3642 return pt.ptrType(info);
3643}
3644
3645pub fn singleMutPtrType(pt: Zcu.PerThread, child_type: Type) Allocator.Error!Type {3741pub fn singleMutPtrType(pt: Zcu.PerThread, child_type: Type) Allocator.Error!Type {
3646 return pt.ptrType(.{ .child = child_type.toIntern() });3742 return pt.ptrType(.{ .child = child_type.toIntern() });
3647}3743}
...@@ -3739,31 +3835,37 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat...@@ -3739,31 +3835,37 @@ pub fn enumValue(pt: Zcu.PerThread, ty: Type, tag_int: InternPool.Index) Allocat
3739/// declaration order.3835/// declaration order.
3740pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value {3836pub fn enumValueFieldIndex(pt: Zcu.PerThread, ty: Type, field_index: u32) Allocator.Error!Value {
3741 const ip = &pt.zcu.intern_pool;3837 const ip = &pt.zcu.intern_pool;
3838 ty.assertHasInits(pt.zcu);
3742 const enum_type = ip.loadEnumType(ty.toIntern());3839 const enum_type = ip.loadEnumType(ty.toIntern());
37433840
3744 if (enum_type.values.len == 0) {3841 assert(field_index < enum_type.field_names.len);
3842
3843 if (enum_type.field_values.len == 0) {
3745 // Auto-numbered fields.3844 // Auto-numbered fields.
3746 return Value.fromInterned(try pt.intern(.{ .enum_tag = .{3845 return Value.fromInterned(try pt.intern(.{ .enum_tag = .{
3747 .ty = ty.toIntern(),3846 .ty = ty.toIntern(),
3748 .int = try pt.intern(.{ .int = .{3847 .int = try pt.intern(.{ .int = .{
3749 .ty = enum_type.tag_ty,3848 .ty = enum_type.int_tag_type,
3750 .storage = .{ .u64 = field_index },3849 .storage = .{ .u64 = field_index },
3751 } }),3850 } }),
3752 } }));3851 } }));
3753 }3852 }
37543853
3755 return Value.fromInterned(try pt.intern(.{ .enum_tag = .{3854 return .fromInterned(try pt.intern(.{ .enum_tag = .{
3756 .ty = ty.toIntern(),3855 .ty = ty.toIntern(),
3757 .int = enum_type.values.get(ip)[field_index],3856 .int = enum_type.field_values.get(ip)[field_index],
3758 } }));3857 } }));
3759}3858}
37603859
3761pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {3860pub fn undefValue(pt: Zcu.PerThread, ty: Type) Allocator.Error!Value {
3762 return Value.fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));3861 if (std.debug.runtime_safety) {
3862 assert(try ty.onePossibleValue(pt) == null);
3863 }
3864 return .fromInterned(try pt.intern(.{ .undef = ty.toIntern() }));
3763}3865}
37643866
3765pub fn undefRef(pt: Zcu.PerThread, ty: Type) Allocator.Error!Air.Inst.Ref {3867pub fn undefRef(pt: Zcu.PerThread, ty: Type) Allocator.Error!Air.Inst.Ref {
3766 return Air.internedToRef((try pt.undefValue(ty)).toIntern());3868 return .fromValue(try pt.undefValue(ty));
3767}3869}
37683870
3769pub fn intValue(pt: Zcu.PerThread, ty: Type, x: anytype) Allocator.Error!Value {3871pub fn intValue(pt: Zcu.PerThread, ty: Type, x: anytype) Allocator.Error!Value {
...@@ -3916,7 +4018,7 @@ pub fn intFittingRange(pt: Zcu.PerThread, min: Value, max: Value) !Type {...@@ -3916,7 +4018,7 @@ pub fn intFittingRange(pt: Zcu.PerThread, min: Value, max: Value) !Type {
3916 assert(Value.order(min, max, zcu).compare(.lte));4018 assert(Value.order(min, max, zcu).compare(.lte));
3917 }4019 }
39184020
3919 const sign = min.orderAgainstZero(zcu) == .lt;4021 const sign = min.compareHetero(.lt, .zero_comptime_int, zcu);
39204022
3921 const min_val_bits = pt.intBitsForValue(min, sign);4023 const min_val_bits = pt.intBitsForValue(min, sign);
3922 const max_val_bits = pt.intBitsForValue(max, sign);4024 const max_val_bits = pt.intBitsForValue(max, sign);
...@@ -3955,12 +4057,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {...@@ -3955,12 +4057,6 @@ pub fn intBitsForValue(pt: Zcu.PerThread, val: Value, sign: bool) u16 {
39554057
3956 return @as(u16, @intCast(big.bitCountTwosComp()));4058 return @as(u16, @intCast(big.bitCountTwosComp()));
3957 },4059 },
3958 .lazy_align => |lazy_ty| {
3959 return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiAlignment(pt.zcu).toByteUnits() orelse 0) + @intFromBool(sign);
3960 },
3961 .lazy_size => |lazy_ty| {
3962 return Type.smallestUnsignedBits(Type.fromInterned(lazy_ty).abiSize(pt.zcu)) + @intFromBool(sign);
3963 },
3964 }4060 }
3965}4061}
39664062
...@@ -3993,7 +4089,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!...@@ -3993,7 +4089,6 @@ pub fn getExtern(pt: Zcu.PerThread, key: InternPool.Key.Extern) Allocator.Error!
3993 const comp = zcu.comp;4089 const comp = zcu.comp;
3994 const result = try zcu.intern_pool.getExtern(comp.gpa, comp.io, pt.tid, key);4090 const result = try zcu.intern_pool.getExtern(comp.gpa, comp.io, pt.tid, key);
3995 if (result.new_nav.unwrap()) |nav| {4091 if (result.new_nav.unwrap()) |nav| {
3996 // This job depends on any resolve_type_fully jobs queued up before it.
3997 comp.link_prog_node.increaseEstimatedTotalItems(1);4092 comp.link_prog_node.increaseEstimatedTotalItems(1);
3998 try comp.queueJob(.{ .link_nav = nav });4093 try comp.queueJob(.{ .link_nav = nav });
3999 if (comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);4094 if (comp.debugIncremental()) try zcu.incremental_debug_state.newNav(zcu, nav);
...@@ -4013,367 +4108,6 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo...@@ -4013,367 +4108,6 @@ pub fn navAlignment(pt: Zcu.PerThread, nav_index: InternPool.Nav.Index) InternPo
4013 return ty.abiAlignment(zcu);4108 return ty.abiAlignment(zcu);
4014}4109}
40154110
4016/// `ty` is a container type requiring resolution (struct, union, or enum).
4017/// If `ty` is outdated, it is recreated at a new `InternPool.Index`, which is returned.
4018/// If the type cannot be recreated because it has been lost, `error.AnalysisFail` is returned.
4019/// If `ty` is not outdated, that same `InternPool.Index` is returned.
4020/// If `ty` has already been replaced by this function, the new index will not be returned again.
4021/// Also, if `ty` is an enum, this function will resolve the new type if needed, and the call site
4022/// is responsible for checking `[transitive_]failed_analysis` to detect resolution failures.
4023pub fn ensureTypeUpToDate(pt: Zcu.PerThread, ty: InternPool.Index) Zcu.SemaError!InternPool.Index {
4024 const zcu = pt.zcu;
4025 const gpa = zcu.gpa;
4026 const ip = &zcu.intern_pool;
4027
4028 const anal_unit: AnalUnit = .wrap(.{ .type = ty });
4029 const outdated = zcu.outdated.swapRemove(anal_unit) or
4030 zcu.potentially_outdated.swapRemove(anal_unit);
4031
4032 if (outdated) {
4033 _ = zcu.outdated_ready.swapRemove(anal_unit);
4034 try zcu.markDependeeOutdated(.marked_po, .{ .interned = ty });
4035 }
4036
4037 const ty_key = switch (ip.indexToKey(ty)) {
4038 .struct_type, .union_type, .enum_type => |key| key,
4039 else => unreachable,
4040 };
4041 const declared_ty_key = switch (ty_key) {
4042 .reified => unreachable, // never outdated
4043 .generated_tag => unreachable, // never outdated
4044 .declared => |d| d,
4045 };
4046
4047 if (declared_ty_key.zir_index.resolve(ip) == null) {
4048 // The instruction has been lost -- this type is dead.
4049 return error.AnalysisFail;
4050 }
4051
4052 if (!outdated) return ty;
4053
4054 // We will recreate the type at a new `InternPool.Index`.
4055
4056 // Delete old state which is no longer in use. Technically, this is not necessary: these exports,
4057 // references, etc, will be ignored because the type itself is unreferenced. However, it allows
4058 // reusing the memory which is currently being used to track this state.
4059 zcu.deleteUnitExports(anal_unit);
4060 zcu.deleteUnitReferences(anal_unit);
4061 zcu.deleteUnitCompileLogs(anal_unit);
4062 if (zcu.failed_analysis.fetchSwapRemove(anal_unit)) |kv| {
4063 kv.value.destroy(gpa);
4064 }
4065 _ = zcu.transitive_failed_analysis.swapRemove(anal_unit);
4066 zcu.intern_pool.removeDependenciesForDepender(gpa, anal_unit);
4067
4068 if (zcu.comp.debugIncremental()) {
4069 const info = try zcu.incremental_debug_state.getUnitInfo(gpa, anal_unit);
4070 info.last_update_gen = zcu.generation;
4071 info.deps.clearRetainingCapacity();
4072 }
4073
4074 switch (ip.indexToKey(ty)) {
4075 .struct_type => return pt.recreateStructType(ty, declared_ty_key),
4076 .union_type => return pt.recreateUnionType(ty, declared_ty_key),
4077 .enum_type => return pt.recreateEnumType(ty, declared_ty_key),
4078 else => unreachable,
4079 }
4080}
4081
4082fn recreateStructType(
4083 pt: Zcu.PerThread,
4084 old_ty: InternPool.Index,
4085 key: InternPool.Key.NamespaceType.Declared,
4086) Allocator.Error!InternPool.Index {
4087 const zcu = pt.zcu;
4088 const comp = zcu.comp;
4089 const gpa = comp.gpa;
4090 const io = comp.io;
4091 const ip = &zcu.intern_pool;
4092
4093 const inst_info = key.zir_index.resolveFull(ip).?;
4094 const file = zcu.fileByIndex(inst_info.file);
4095 const zir = file.zir.?;
4096
4097 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
4098 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
4099 assert(extended.opcode == .struct_decl);
4100 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
4101 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);
4102 var extra_index = extra.end;
4103
4104 const captures_len = if (small.has_captures_len) blk: {
4105 const captures_len = zir.extra[extra_index];
4106 extra_index += 1;
4107 break :blk captures_len;
4108 } else 0;
4109 const fields_len = if (small.has_fields_len) blk: {
4110 const fields_len = zir.extra[extra_index];
4111 extra_index += 1;
4112 break :blk fields_len;
4113 } else 0;
4114
4115 assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
4116
4117 const struct_obj = ip.loadStructType(old_ty);
4118
4119 const wip_ty = switch (try ip.getStructType(gpa, io, pt.tid, .{
4120 .layout = small.layout,
4121 .fields_len = fields_len,
4122 .known_non_opv = small.known_non_opv,
4123 .requires_comptime = if (small.known_comptime_only) .yes else .unknown,
4124 .any_comptime_fields = small.any_comptime_fields,
4125 .any_default_inits = small.any_default_inits,
4126 .inits_resolved = false,
4127 .any_aligned_fields = small.any_aligned_fields,
4128 .key = .{ .declared_owned_captures = .{
4129 .zir_index = key.zir_index,
4130 .captures = key.captures.owned,
4131 } },
4132 }, true)) {
4133 .wip => |wip| wip,
4134 .existing => unreachable, // we passed `replace_existing`
4135 };
4136 errdefer wip_ty.cancel(ip, pt.tid);
4137
4138 wip_ty.setName(ip, struct_obj.name, struct_obj.name_nav);
4139 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index });
4140 zcu.namespacePtr(struct_obj.namespace).owner_type = wip_ty.index;
4141 // No need to re-scan the namespace -- `zirStructDecl` will ultimately do that if the type is still alive.
4142 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
4143
4144 codegen_type: {
4145 if (file.mod.?.strip) break :codegen_type;
4146 // This job depends on any resolve_type_fully jobs queued up before it.
4147 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
4148 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
4149 }
4150
4151 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
4152 const new_ty = wip_ty.finish(ip, struct_obj.namespace);
4153 if (inst_info.inst == .main_struct_inst) {
4154 // This is the root type of a file! Update the reference.
4155 zcu.setFileRootType(inst_info.file, new_ty);
4156 }
4157 return new_ty;
4158}
4159
4160fn recreateUnionType(
4161 pt: Zcu.PerThread,
4162 old_ty: InternPool.Index,
4163 key: InternPool.Key.NamespaceType.Declared,
4164) Allocator.Error!InternPool.Index {
4165 const zcu = pt.zcu;
4166 const comp = zcu.comp;
4167 const gpa = comp.gpa;
4168 const io = comp.io;
4169 const ip = &zcu.intern_pool;
4170
4171 const inst_info = key.zir_index.resolveFull(ip).?;
4172 const file = zcu.fileByIndex(inst_info.file);
4173 const zir = file.zir.?;
4174
4175 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
4176 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
4177 assert(extended.opcode == .union_decl);
4178 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
4179 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
4180 var extra_index = extra.end;
4181
4182 extra_index += @intFromBool(small.has_tag_type);
4183 const captures_len = if (small.has_captures_len) blk: {
4184 const captures_len = zir.extra[extra_index];
4185 extra_index += 1;
4186 break :blk captures_len;
4187 } else 0;
4188 extra_index += @intFromBool(small.has_body_len);
4189 const fields_len = if (small.has_fields_len) blk: {
4190 const fields_len = zir.extra[extra_index];
4191 extra_index += 1;
4192 break :blk fields_len;
4193 } else 0;
4194
4195 assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
4196
4197 const union_obj = ip.loadUnionType(old_ty);
4198
4199 const namespace_index = union_obj.namespace;
4200
4201 const wip_ty = switch (try ip.getUnionType(gpa, io, pt.tid, .{
4202 .flags = .{
4203 .layout = small.layout,
4204 .status = .none,
4205 .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
4206 .tagged
4207 else if (small.layout != .auto)
4208 .none
4209 else switch (true) { // TODO
4210 true => .safety,
4211 false => .none,
4212 },
4213 .any_aligned_fields = small.any_aligned_fields,
4214 .requires_comptime = .unknown,
4215 .assumed_runtime_bits = false,
4216 .assumed_pointer_aligned = false,
4217 .alignment = .none,
4218 },
4219 .fields_len = fields_len,
4220 .enum_tag_ty = .none, // set later
4221 .field_types = &.{}, // set later
4222 .field_aligns = &.{}, // set later
4223 .key = .{ .declared_owned_captures = .{
4224 .zir_index = key.zir_index,
4225 .captures = key.captures.owned,
4226 } },
4227 }, true)) {
4228 .wip => |wip| wip,
4229 .existing => unreachable, // we passed `replace_existing`
4230 };
4231 errdefer wip_ty.cancel(ip, pt.tid);
4232
4233 wip_ty.setName(ip, union_obj.name, union_obj.name_nav);
4234 try pt.addDependency(.wrap(.{ .type = wip_ty.index }), .{ .src_hash = key.zir_index });
4235 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
4236 // No need to re-scan the namespace -- `zirUnionDecl` will ultimately do that if the type is still alive.
4237 try zcu.comp.queueJob(.{ .resolve_type_fully = wip_ty.index });
4238
4239 codegen_type: {
4240 if (file.mod.?.strip) break :codegen_type;
4241 // This job depends on any resolve_type_fully jobs queued up before it.
4242 zcu.comp.link_prog_node.increaseEstimatedTotalItems(1);
4243 try zcu.comp.queueJob(.{ .link_type = wip_ty.index });
4244 }
4245
4246 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
4247 return wip_ty.finish(ip, namespace_index);
4248}
4249
4250/// This *does* call `Sema.resolveDeclaredEnum`, but errors from it are not propagated.
4251/// Call sites are resposible for checking `[transitive_]failed_analysis` after `ensureTypeUpToDate`
4252/// returns in order to detect resolution failures.
4253fn recreateEnumType(
4254 pt: Zcu.PerThread,
4255 old_ty: InternPool.Index,
4256 key: InternPool.Key.NamespaceType.Declared,
4257) (Allocator.Error || Io.Cancelable)!InternPool.Index {
4258 const zcu = pt.zcu;
4259 const comp = zcu.comp;
4260 const gpa = comp.gpa;
4261 const io = comp.io;
4262 const ip = &zcu.intern_pool;
4263
4264 const inst_info = key.zir_index.resolveFull(ip).?;
4265 const file = zcu.fileByIndex(inst_info.file);
4266 const zir = file.zir.?;
4267
4268 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
4269 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
4270 assert(extended.opcode == .enum_decl);
4271 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
4272 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
4273 var extra_index = extra.end;
4274
4275 const tag_type_ref = if (small.has_tag_type) blk: {
4276 const tag_type_ref: Zir.Inst.Ref = @enumFromInt(zir.extra[extra_index]);
4277 extra_index += 1;
4278 break :blk tag_type_ref;
4279 } else .none;
4280
4281 const captures_len = if (small.has_captures_len) blk: {
4282 const captures_len = zir.extra[extra_index];
4283 extra_index += 1;
4284 break :blk captures_len;
4285 } else 0;
4286
4287 const body_len = if (small.has_body_len) blk: {
4288 const body_len = zir.extra[extra_index];
4289 extra_index += 1;
4290 break :blk body_len;
4291 } else 0;
4292
4293 const fields_len = if (small.has_fields_len) blk: {
4294 const fields_len = zir.extra[extra_index];
4295 extra_index += 1;
4296 break :blk fields_len;
4297 } else 0;
4298
4299 const decls_len = if (small.has_decls_len) blk: {
4300 const decls_len = zir.extra[extra_index];
4301 extra_index += 1;
4302 break :blk decls_len;
4303 } else 0;
4304
4305 assert(captures_len == key.captures.owned.len); // synchronises with logic in `Zcu.mapOldZirToNew`
4306
4307 extra_index += captures_len * 2;
4308 extra_index += decls_len;
4309
4310 const body = zir.bodySlice(extra_index, body_len);
4311 extra_index += body.len;
4312
4313 const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
4314 const body_end = extra_index;
4315 extra_index += bit_bags_count;
4316
4317 const any_values = for (zir.extra[body_end..][0..bit_bags_count]) |bag| {
4318 if (bag != 0) break true;
4319 } else false;
4320
4321 const enum_obj = ip.loadEnumType(old_ty);
4322
4323 const namespace_index = enum_obj.namespace;
4324
4325 const wip_ty = switch (try ip.getEnumType(gpa, io, pt.tid, .{
4326 .has_values = any_values,
4327 .tag_mode = if (small.nonexhaustive)
4328 .nonexhaustive
4329 else if (tag_type_ref == .none)
4330 .auto
4331 else
4332 .explicit,
4333 .fields_len = fields_len,
4334 .key = .{ .declared_owned_captures = .{
4335 .zir_index = key.zir_index,
4336 .captures = key.captures.owned,
4337 } },
4338 }, true)) {
4339 .wip => |wip| wip,
4340 .existing => unreachable, // we passed `replace_existing`
4341 };
4342 var done = true;
4343 errdefer if (!done) wip_ty.cancel(ip, pt.tid);
4344
4345 wip_ty.setName(ip, enum_obj.name, enum_obj.name_nav);
4346
4347 zcu.namespacePtr(namespace_index).owner_type = wip_ty.index;
4348 // No need to re-scan the namespace -- `zirEnumDecl` will ultimately do that if the type is still alive.
4349
4350 if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip_ty.index);
4351 wip_ty.prepare(ip, namespace_index);
4352 done = true;
4353
4354 Sema.resolveDeclaredEnum(
4355 pt,
4356 wip_ty,
4357 inst_info.inst,
4358 key.zir_index,
4359 namespace_index,
4360 enum_obj.name,
4361 small,
4362 body,
4363 tag_type_ref,
4364 any_values,
4365 fields_len,
4366 zir,
4367 body_end,
4368 ) catch |err| switch (err) {
4369 error.OutOfMemory => |e| return e,
4370 error.Canceled => |e| return e,
4371 error.AnalysisFail => {}, // call sites are responsible for checking `[transitive_]failed_analysis` to detect this
4372 };
4373
4374 return wip_ty.index;
4375}
4376
4377/// Given a namespace, re-scan its declarations from the type definition if they have not4111/// Given a namespace, re-scan its declarations from the type definition if they have not
4378/// yet been re-scanned on this update.4112/// yet been re-scanned on this update.
4379/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.4113/// If the type declaration instruction has been lost, returns `error.AnalysisFail`.
...@@ -4396,7 +4130,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4396,7 +4130,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4396 };4130 };
43974131
4398 const key = switch (full_key) {4132 const key = switch (full_key) {
4399 .reified, .generated_tag => {4133 .reified, .generated_union_tag => {
4400 // Namespace always empty, so up-to-date.4134 // Namespace always empty, so up-to-date.
4401 namespace.generation = zcu.generation;4135 namespace.generation = zcu.generation;
4402 return;4136 return;
...@@ -4408,100 +4142,13 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4408,100 +4142,13 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
44084142
4409 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;4143 const inst_info = key.zir_index.resolveFull(ip) orelse return error.AnalysisFail;
4410 const file = zcu.fileByIndex(inst_info.file);4144 const file = zcu.fileByIndex(inst_info.file);
4411 const zir = file.zir.?;4145 const zir = &file.zir.?;
4412
4413 assert(zir.instructions.items(.tag)[@intFromEnum(inst_info.inst)] == .extended);
4414 const extended = zir.instructions.items(.data)[@intFromEnum(inst_info.inst)].extended;
44154146
4416 const decls = switch (container) {4147 const decls = switch (container) {
4417 .@"struct" => decls: {4148 .@"struct" => zir.getStructDecl(inst_info.inst).decls,
4418 assert(extended.opcode == .struct_decl);4149 .@"union" => zir.getUnionDecl(inst_info.inst).decls,
4419 const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);4150 .@"enum" => zir.getEnumDecl(inst_info.inst).decls,
4420 const extra = zir.extraData(Zir.Inst.StructDecl, extended.operand);4151 .@"opaque" => zir.getOpaqueDecl(inst_info.inst).decls,
4421 var extra_index = extra.end;
4422 const captures_len = if (small.has_captures_len) blk: {
4423 const captures_len = zir.extra[extra_index];
4424 extra_index += 1;
4425 break :blk captures_len;
4426 } else 0;
4427 extra_index += @intFromBool(small.has_fields_len);
4428 const decls_len = if (small.has_decls_len) blk: {
4429 const decls_len = zir.extra[extra_index];
4430 extra_index += 1;
4431 break :blk decls_len;
4432 } else 0;
4433 extra_index += captures_len * 2;
4434 if (small.has_backing_int) {
4435 const backing_int_body_len = zir.extra[extra_index];
4436 extra_index += 1; // backing_int_body_len
4437 if (backing_int_body_len == 0) {
4438 extra_index += 1; // backing_int_ref
4439 } else {
4440 extra_index += backing_int_body_len; // backing_int_body_inst
4441 }
4442 }
4443 break :decls zir.bodySlice(extra_index, decls_len);
4444 },
4445 .@"union" => decls: {
4446 assert(extended.opcode == .union_decl);
4447 const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
4448 const extra = zir.extraData(Zir.Inst.UnionDecl, extended.operand);
4449 var extra_index = extra.end;
4450 extra_index += @intFromBool(small.has_tag_type);
4451 const captures_len = if (small.has_captures_len) blk: {
4452 const captures_len = zir.extra[extra_index];
4453 extra_index += 1;
4454 break :blk captures_len;
4455 } else 0;
4456 extra_index += @intFromBool(small.has_body_len);
4457 extra_index += @intFromBool(small.has_fields_len);
4458 const decls_len = if (small.has_decls_len) blk: {
4459 const decls_len = zir.extra[extra_index];
4460 extra_index += 1;
4461 break :blk decls_len;
4462 } else 0;
4463 extra_index += captures_len * 2;
4464 break :decls zir.bodySlice(extra_index, decls_len);
4465 },
4466 .@"enum" => decls: {
4467 assert(extended.opcode == .enum_decl);
4468 const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
4469 const extra = zir.extraData(Zir.Inst.EnumDecl, extended.operand);
4470 var extra_index = extra.end;
4471 extra_index += @intFromBool(small.has_tag_type);
4472 const captures_len = if (small.has_captures_len) blk: {
4473 const captures_len = zir.extra[extra_index];
4474 extra_index += 1;
4475 break :blk captures_len;
4476 } else 0;
4477 extra_index += @intFromBool(small.has_body_len);
4478 extra_index += @intFromBool(small.has_fields_len);
4479 const decls_len = if (small.has_decls_len) blk: {
4480 const decls_len = zir.extra[extra_index];
4481 extra_index += 1;
4482 break :blk decls_len;
4483 } else 0;
4484 extra_index += captures_len * 2;
4485 break :decls zir.bodySlice(extra_index, decls_len);
4486 },
4487 .@"opaque" => decls: {
4488 assert(extended.opcode == .opaque_decl);
4489 const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
4490 const extra = zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
4491 var extra_index = extra.end;
4492 const captures_len = if (small.has_captures_len) blk: {
4493 const captures_len = zir.extra[extra_index];
4494 extra_index += 1;
4495 break :blk captures_len;
4496 } else 0;
4497 const decls_len = if (small.has_decls_len) blk: {
4498 const decls_len = zir.extra[extra_index];
4499 extra_index += 1;
4500 break :blk decls_len;
4501 } else 0;
4502 extra_index += captures_len * 2;
4503 break :decls zir.bodySlice(extra_index, decls_len);
4504 },
4505 };4152 };
45064153
4507 try pt.scanNamespace(namespace_index, decls);4154 try pt.scanNamespace(namespace_index, decls);
...@@ -4509,7 +4156,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace...@@ -4509,7 +4156,7 @@ pub fn ensureNamespaceUpToDate(pt: Zcu.PerThread, namespace_index: Zcu.Namespace
4509}4156}
45104157
4511pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPool.Index {4158pub fn refValue(pt: Zcu.PerThread, val: InternPool.Index) Zcu.SemaError!InternPool.Index {
4512 const ptr_ty = (try pt.ptrTypeSema(.{4159 const ptr_ty = (try pt.ptrType(.{
4513 .child = pt.zcu.intern_pool.typeOf(val),4160 .child = pt.zcu.intern_pool.typeOf(val),
4514 .flags = .{4161 .flags = .{
4515 .alignment = .none,4162 .alignment = .none,
...@@ -4703,3 +4350,466 @@ fn printVerboseAir(...@@ -4703,3 +4350,466 @@ fn printVerboseAir(
4703 try air.write(w, pt, liveness);4350 try air.write(w, pt, liveness);
4704 try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)});4351 try w.print("# End Function AIR: {f}\n\n", .{fqn.fmt(ip)});
4705}4352}
4353
4354// MLUGG TODO: these functions are all blatant hacks. See if I can remove them!
4355pub fn resolveTypeForCodegen(pt: Zcu.PerThread, ty: Type) Zcu.SemaError!void {
4356 const zcu = pt.zcu;
4357 const ip = &zcu.intern_pool;
4358 if (ty.isGenericPoison()) return;
4359 switch (ty.zigTypeTag(zcu)) {
4360 .type,
4361 .void,
4362 .bool,
4363 .noreturn,
4364 .int,
4365 .float,
4366 .error_set,
4367 .@"opaque",
4368 .comptime_float,
4369 .comptime_int,
4370 .undefined,
4371 .null,
4372 .enum_literal,
4373 => {},
4374
4375 .frame, .@"anyframe" => @panic("TODO resolveTypeForCodegen async frames"),
4376
4377 .optional => try pt.resolveTypeForCodegen(ty.childType(zcu)),
4378 .error_union => try pt.resolveTypeForCodegen(ty.errorUnionPayload(zcu)),
4379 .pointer => try pt.resolveTypeForCodegen(ty.childType(zcu)),
4380 .array => try pt.resolveTypeForCodegen(ty.childType(zcu)),
4381 .vector => try pt.resolveTypeForCodegen(ty.childType(zcu)),
4382
4383 .@"fn" => {
4384 const info = zcu.typeToFunc(ty).?;
4385 for (0..info.param_types.len) |i| {
4386 const param_ty = info.param_types.get(ip)[i];
4387 try pt.resolveTypeForCodegen(.fromInterned(param_ty));
4388 }
4389 try pt.resolveTypeForCodegen(.fromInterned(info.return_type));
4390 },
4391
4392 .@"struct" => switch (ip.indexToKey(ty.toIntern())) {
4393 .struct_type => {
4394 try pt.ensureTypeLayoutUpToDate(ty);
4395 try pt.ensureTypeInitsUpToDate(ty);
4396 },
4397 .tuple_type => |tuple| for (0..tuple.types.len) |i| {
4398 const field_is_comptime = tuple.values.get(ip)[i] != .none;
4399 if (field_is_comptime) continue;
4400 const field_ty = tuple.types.get(ip)[i];
4401 try pt.resolveTypeForCodegen(.fromInterned(field_ty));
4402 },
4403 else => unreachable,
4404 },
4405
4406 .@"union" => try pt.ensureTypeLayoutUpToDate(ty),
4407 .@"enum" => try pt.ensureTypeInitsUpToDate(ty),
4408 }
4409}
4410pub fn resolveValueTypesForCodegen(pt: Zcu.PerThread, val: Value) Zcu.SemaError!void {
4411 const zcu = pt.zcu;
4412 const ty: Type = switch (val.typeOf(zcu).toIntern()) {
4413 .type_type => if (val.isUndef(zcu)) {
4414 return;
4415 } else val.toType(),
4416 else => |ty| .fromInterned(ty),
4417 };
4418 return pt.resolveTypeForCodegen(ty);
4419}
4420pub fn resolveAirTypesForCodegen(pt: Zcu.PerThread, air: *const Air) Zcu.SemaError!void {
4421 return pt.resolveBodyTypesForCodegen(air, air.getMainBody());
4422}
4423fn resolveBodyTypesForCodegen(pt: Zcu.PerThread, air: *const Air, body: []const Air.Inst.Index) Zcu.SemaError!void {
4424 const zcu = pt.zcu;
4425 const tags = air.instructions.items(.tag);
4426 const datas = air.instructions.items(.data);
4427 for (body) |inst| {
4428 const data = datas[@intFromEnum(inst)];
4429 switch (tags[@intFromEnum(inst)]) {
4430 .inferred_alloc, .inferred_alloc_comptime => unreachable,
4431
4432 .arg => try pt.resolveTypeForCodegen(data.arg.ty.toType()),
4433
4434 .add,
4435 .add_safe,
4436 .add_optimized,
4437 .add_wrap,
4438 .add_sat,
4439 .sub,
4440 .sub_safe,
4441 .sub_optimized,
4442 .sub_wrap,
4443 .sub_sat,
4444 .mul,
4445 .mul_safe,
4446 .mul_optimized,
4447 .mul_wrap,
4448 .mul_sat,
4449 .div_float,
4450 .div_float_optimized,
4451 .div_trunc,
4452 .div_trunc_optimized,
4453 .div_floor,
4454 .div_floor_optimized,
4455 .div_exact,
4456 .div_exact_optimized,
4457 .rem,
4458 .rem_optimized,
4459 .mod,
4460 .mod_optimized,
4461 .max,
4462 .min,
4463 .bit_and,
4464 .bit_or,
4465 .shr,
4466 .shr_exact,
4467 .shl,
4468 .shl_exact,
4469 .shl_sat,
4470 .xor,
4471 .cmp_lt,
4472 .cmp_lt_optimized,
4473 .cmp_lte,
4474 .cmp_lte_optimized,
4475 .cmp_eq,
4476 .cmp_eq_optimized,
4477 .cmp_gte,
4478 .cmp_gte_optimized,
4479 .cmp_gt,
4480 .cmp_gt_optimized,
4481 .cmp_neq,
4482 .cmp_neq_optimized,
4483 .bool_and,
4484 .bool_or,
4485 .store,
4486 .store_safe,
4487 .set_union_tag,
4488 .array_elem_val,
4489 .slice_elem_val,
4490 .ptr_elem_val,
4491 .memset,
4492 .memset_safe,
4493 .memcpy,
4494 .memmove,
4495 .atomic_store_unordered,
4496 .atomic_store_monotonic,
4497 .atomic_store_release,
4498 .atomic_store_seq_cst,
4499 .legalize_vec_elem_val,
4500 => {
4501 try pt.resolveRefTypesForCodegen(data.bin_op.lhs);
4502 try pt.resolveRefTypesForCodegen(data.bin_op.rhs);
4503 },
4504
4505 .not,
4506 .bitcast,
4507 .clz,
4508 .ctz,
4509 .popcount,
4510 .byte_swap,
4511 .bit_reverse,
4512 .abs,
4513 .load,
4514 .fptrunc,
4515 .fpext,
4516 .intcast,
4517 .intcast_safe,
4518 .trunc,
4519 .optional_payload,
4520 .optional_payload_ptr,
4521 .optional_payload_ptr_set,
4522 .wrap_optional,
4523 .unwrap_errunion_payload,
4524 .unwrap_errunion_err,
4525 .unwrap_errunion_payload_ptr,
4526 .unwrap_errunion_err_ptr,
4527 .errunion_payload_ptr_set,
4528 .wrap_errunion_payload,
4529 .wrap_errunion_err,
4530 .struct_field_ptr_index_0,
4531 .struct_field_ptr_index_1,
4532 .struct_field_ptr_index_2,
4533 .struct_field_ptr_index_3,
4534 .get_union_tag,
4535 .slice_len,
4536 .slice_ptr,
4537 .ptr_slice_len_ptr,
4538 .ptr_slice_ptr_ptr,
4539 .array_to_slice,
4540 .int_from_float,
4541 .int_from_float_optimized,
4542 .int_from_float_safe,
4543 .int_from_float_optimized_safe,
4544 .float_from_int,
4545 .splat,
4546 .error_set_has_value,
4547 .addrspace_cast,
4548 .c_va_arg,
4549 .c_va_copy,
4550 => {
4551 try pt.resolveTypeForCodegen(data.ty_op.ty.toType());
4552 try pt.resolveRefTypesForCodegen(data.ty_op.operand);
4553 },
4554
4555 .alloc,
4556 .ret_ptr,
4557 .c_va_start,
4558 => try pt.resolveTypeForCodegen(data.ty),
4559
4560 .ptr_add,
4561 .ptr_sub,
4562 .add_with_overflow,
4563 .sub_with_overflow,
4564 .mul_with_overflow,
4565 .shl_with_overflow,
4566 .slice,
4567 .slice_elem_ptr,
4568 .ptr_elem_ptr,
4569 => {
4570 const bin = air.extraData(Air.Bin, data.ty_pl.payload).data;
4571 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4572 try pt.resolveRefTypesForCodegen(bin.lhs);
4573 try pt.resolveRefTypesForCodegen(bin.rhs);
4574 },
4575
4576 .block,
4577 .loop,
4578 => {
4579 const block = air.unwrapBlock(inst);
4580 try pt.resolveTypeForCodegen(block.ty);
4581 try pt.resolveBodyTypesForCodegen(air, block.body);
4582 },
4583
4584 .dbg_inline_block => {
4585 const block = air.unwrapDbgBlock(inst);
4586 try pt.resolveTypeForCodegen(block.ty);
4587 try pt.resolveBodyTypesForCodegen(air, block.body);
4588 },
4589
4590 .sqrt,
4591 .sin,
4592 .cos,
4593 .tan,
4594 .exp,
4595 .exp2,
4596 .log,
4597 .log2,
4598 .log10,
4599 .floor,
4600 .ceil,
4601 .round,
4602 .trunc_float,
4603 .neg,
4604 .neg_optimized,
4605 .is_null,
4606 .is_non_null,
4607 .is_null_ptr,
4608 .is_non_null_ptr,
4609 .is_err,
4610 .is_non_err,
4611 .is_err_ptr,
4612 .is_non_err_ptr,
4613 .ret,
4614 .ret_safe,
4615 .ret_load,
4616 .is_named_enum_value,
4617 .tag_name,
4618 .error_name,
4619 .cmp_lt_errors_len,
4620 .c_va_end,
4621 .set_err_return_trace,
4622 => try pt.resolveRefTypesForCodegen(data.un_op),
4623
4624 .br, .switch_dispatch => try pt.resolveRefTypesForCodegen(data.br.operand),
4625
4626 .cmp_vector,
4627 .cmp_vector_optimized,
4628 => {
4629 const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data;
4630 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4631 try pt.resolveRefTypesForCodegen(extra.lhs);
4632 try pt.resolveRefTypesForCodegen(extra.rhs);
4633 },
4634
4635 .reduce,
4636 .reduce_optimized,
4637 => try pt.resolveRefTypesForCodegen(data.reduce.operand),
4638
4639 .struct_field_ptr,
4640 .struct_field_val,
4641 => {
4642 const extra = air.extraData(Air.StructField, data.ty_pl.payload).data;
4643 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4644 try pt.resolveRefTypesForCodegen(extra.struct_operand);
4645 },
4646
4647 .shuffle_one => {
4648 const unwrapped = air.unwrapShuffleOne(zcu, inst);
4649 try pt.resolveTypeForCodegen(unwrapped.result_ty);
4650 try pt.resolveRefTypesForCodegen(unwrapped.operand);
4651 for (unwrapped.mask) |m| switch (m.unwrap()) {
4652 .elem => {},
4653 .value => |val| try pt.resolveValueTypesForCodegen(.fromInterned(val)),
4654 };
4655 },
4656
4657 .shuffle_two => {
4658 const unwrapped = air.unwrapShuffleTwo(zcu, inst);
4659 try pt.resolveTypeForCodegen(unwrapped.result_ty);
4660 try pt.resolveRefTypesForCodegen(unwrapped.operand_a);
4661 try pt.resolveRefTypesForCodegen(unwrapped.operand_b);
4662 // No values to check because there are no comptime-known values other than undef
4663 },
4664
4665 .cmpxchg_weak,
4666 .cmpxchg_strong,
4667 => {
4668 const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data;
4669 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4670 try pt.resolveRefTypesForCodegen(extra.ptr);
4671 try pt.resolveRefTypesForCodegen(extra.expected_value);
4672 try pt.resolveRefTypesForCodegen(extra.new_value);
4673 },
4674
4675 .aggregate_init => {
4676 const ty = data.ty_pl.ty.toType();
4677 const elems_len: usize = @intCast(ty.arrayLen(zcu));
4678 const elems: []const Air.Inst.Ref = @ptrCast(air.extra.items[data.ty_pl.payload..][0..elems_len]);
4679 try pt.resolveTypeForCodegen(ty);
4680 if (ty.zigTypeTag(zcu) == .@"struct") {
4681 for (elems, 0..) |elem, elem_idx| {
4682 if (ty.structFieldIsComptime(elem_idx, zcu)) continue;
4683 try pt.resolveRefTypesForCodegen(elem);
4684 }
4685 } else {
4686 for (elems) |elem| {
4687 try pt.resolveRefTypesForCodegen(elem);
4688 }
4689 }
4690 },
4691
4692 .union_init => {
4693 const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data;
4694 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4695 try pt.resolveRefTypesForCodegen(extra.init);
4696 },
4697
4698 .field_parent_ptr => {
4699 const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data;
4700 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4701 try pt.resolveRefTypesForCodegen(extra.field_ptr);
4702 },
4703
4704 .atomic_load => try pt.resolveRefTypesForCodegen(data.atomic_load.ptr),
4705
4706 .prefetch => try pt.resolveRefTypesForCodegen(data.prefetch.ptr),
4707
4708 .runtime_nav_ptr => try pt.resolveTypeForCodegen(.fromInterned(data.ty_nav.ty)),
4709
4710 .select,
4711 .mul_add,
4712 .legalize_vec_store_elem,
4713 => {
4714 const bin = air.extraData(Air.Bin, data.pl_op.payload).data;
4715 try pt.resolveRefTypesForCodegen(data.pl_op.operand);
4716 try pt.resolveRefTypesForCodegen(bin.lhs);
4717 try pt.resolveRefTypesForCodegen(bin.rhs);
4718 },
4719
4720 .atomic_rmw => {
4721 const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data;
4722 try pt.resolveRefTypesForCodegen(data.pl_op.operand);
4723 try pt.resolveRefTypesForCodegen(extra.operand);
4724 },
4725
4726 .call,
4727 .call_always_tail,
4728 .call_never_tail,
4729 .call_never_inline,
4730 => {
4731 const call = air.unwrapCall(inst);
4732 try pt.resolveRefTypesForCodegen(call.callee);
4733 for (call.args) |arg| try pt.resolveRefTypesForCodegen(arg);
4734 },
4735
4736 .dbg_var_ptr,
4737 .dbg_var_val,
4738 .dbg_arg_inline,
4739 => try pt.resolveRefTypesForCodegen(data.pl_op.operand),
4740
4741 .@"try", .try_cold => {
4742 const @"try" = air.unwrapTry(inst);
4743 try pt.resolveRefTypesForCodegen(@"try".error_union);
4744 try pt.resolveBodyTypesForCodegen(air, @"try".else_body);
4745 },
4746
4747 .try_ptr, .try_ptr_cold => {
4748 const try_ptr = air.unwrapTryPtr(inst);
4749 try pt.resolveTypeForCodegen(try_ptr.error_union_payload_ptr_ty.toType());
4750 try pt.resolveRefTypesForCodegen(try_ptr.error_union_ptr);
4751 try pt.resolveBodyTypesForCodegen(air, try_ptr.else_body);
4752 },
4753
4754 .cond_br => {
4755 const cond_br = air.unwrapCondBr(inst);
4756 try pt.resolveRefTypesForCodegen(cond_br.condition);
4757 try pt.resolveBodyTypesForCodegen(air, cond_br.then_body);
4758 try pt.resolveBodyTypesForCodegen(air, cond_br.else_body);
4759 },
4760
4761 .switch_br, .loop_switch_br => {
4762 const switch_br = air.unwrapSwitch(inst);
4763 try pt.resolveRefTypesForCodegen(switch_br.operand);
4764 var it = switch_br.iterateCases();
4765 while (it.next()) |case| {
4766 for (case.items) |item| {
4767 try pt.resolveRefTypesForCodegen(item);
4768 }
4769 for (case.ranges) |range| {
4770 try pt.resolveRefTypesForCodegen(range[0]);
4771 try pt.resolveRefTypesForCodegen(range[1]);
4772 }
4773 try pt.resolveBodyTypesForCodegen(air, case.body);
4774 }
4775 try pt.resolveBodyTypesForCodegen(air, it.elseBody());
4776 },
4777
4778 .assembly => {
4779 const @"asm" = air.unwrapAsm(inst);
4780 try pt.resolveTypeForCodegen(data.ty_pl.ty.toType());
4781 for (@"asm".outputs) |output| if (output != .none) try pt.resolveRefTypesForCodegen(output);
4782 for (@"asm".inputs) |input| if (input != .none) try pt.resolveRefTypesForCodegen(input);
4783 },
4784
4785 .legalize_compiler_rt_call => {
4786 const compiler_rt_call = air.unwrapCompilerRtCall(inst);
4787 for (compiler_rt_call.args) |arg| try pt.resolveRefTypesForCodegen(arg);
4788 },
4789
4790 .trap,
4791 .breakpoint,
4792 .ret_addr,
4793 .frame_addr,
4794 .unreach,
4795 .wasm_memory_size,
4796 .wasm_memory_grow,
4797 .work_item_id,
4798 .work_group_size,
4799 .work_group_id,
4800 .dbg_stmt,
4801 .dbg_empty_stmt,
4802 .err_return_trace,
4803 .save_err_return_trace_index,
4804 .repeat,
4805 => {},
4806 }
4807 }
4808}
4809fn resolveRefTypesForCodegen(pt: Zcu.PerThread, ref: Air.Inst.Ref) Zcu.SemaError!void {
4810 const ip_index = ref.toInterned() orelse {
4811 // `ref` refers to a prior instruction, which we already did the resolution for.
4812 return;
4813 };
4814 return pt.resolveValueTypesForCodegen(.fromInterned(ip_index));
4815}
src/codegen.zig+1-1
...@@ -1088,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo...@@ -1088,7 +1088,7 @@ pub fn lowerValue(pt: Zcu.PerThread, val: Value, target: *const std.Target) Allo
1088 return .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? };1088 return .{ .immediate = fn_ty.abiAlignment(zcu).toByteUnits().? };
1089 }1089 }
1090 } else if (ty.zigTypeTag(zcu) == .pointer) {1090 } else if (ty.zigTypeTag(zcu) == .pointer) {
1091 const elem_ty = ty.elemType2(zcu);1091 const elem_ty = ty.childType(zcu);
1092 if (!elem_ty.hasRuntimeBits(zcu)) {1092 if (!elem_ty.hasRuntimeBits(zcu)) {
1093 return .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? };1093 return .{ .immediate = elem_ty.abiAlignment(zcu).toByteUnits().? };
1094 }1094 }
src/codegen/aarch64/Select.zig+4-4
...@@ -2464,7 +2464,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -2464,7 +2464,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
24642464
2465 const ty_pl = air.data(air.inst_index).ty_pl;2465 const ty_pl = air.data(air.inst_index).ty_pl;
2466 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;2466 const bin_op = isel.air.extraData(Air.Bin, ty_pl.payload).data;
2467 const elem_size = ty_pl.ty.toType().elemType2(zcu).abiSize(zcu);2467 const elem_size = ty_pl.ty.toType().childType(zcu).abiSize(zcu);
24682468
2469 const base_vi = try isel.use(bin_op.lhs);2469 const base_vi = try isel.use(bin_op.lhs);
2470 var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8);2470 var base_part_it = base_vi.field(ty_pl.ty.toType(), 0, 8);
...@@ -6145,7 +6145,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6145,7 +6145,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6145 } else {6145 } else {
6146 const elem_ptr_ra = try isel.allocIntReg();6146 const elem_ptr_ra = try isel.allocIntReg();
6147 defer isel.freeReg(elem_ptr_ra);6147 defer isel.freeReg(elem_ptr_ra);
6148 if (!try elem_vi.value.load(isel, slice_ty.elemType2(zcu), elem_ptr_ra, .{6148 if (!try elem_vi.value.load(isel, slice_ty.childType(zcu), elem_ptr_ra, .{
6149 .@"volatile" = ptr_info.flags.is_volatile,6149 .@"volatile" = ptr_info.flags.is_volatile,
6150 })) break :unused;6150 })) break :unused;
6151 const slice_vi = try isel.use(bin_op.lhs);6151 const slice_vi = try isel.use(bin_op.lhs);
...@@ -6253,7 +6253,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6253,7 +6253,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6253 } else {6253 } else {
6254 const elem_ptr_ra = try isel.allocIntReg();6254 const elem_ptr_ra = try isel.allocIntReg();
6255 defer isel.freeReg(elem_ptr_ra);6255 defer isel.freeReg(elem_ptr_ra);
6256 if (!try elem_vi.value.load(isel, ptr_ty.elemType2(zcu), elem_ptr_ra, .{6256 if (!try elem_vi.value.load(isel, ptr_ty.childType(zcu), elem_ptr_ra, .{
6257 .@"volatile" = ptr_info.flags.is_volatile,6257 .@"volatile" = ptr_info.flags.is_volatile,
6258 })) break :unused;6258 })) break :unused;
6259 const base_vi = try isel.use(bin_op.lhs);6259 const base_vi = try isel.use(bin_op.lhs);
...@@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,...@@ -6594,7 +6594,7 @@ pub fn body(isel: *Select, air_body: []const Air.Inst.Index) error{ OutOfMemory,
6594 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|6594 if (try isel.hasRepeatedByteRepr(.fromInterned(fill_val))) |fill_byte|
6595 break :fill_byte .{ .constant = fill_byte };6595 break :fill_byte .{ .constant = fill_byte };
6596 }6596 }
6597 switch (dst_ty.elemType2(zcu).abiSize(zcu)) {6597 switch (dst_ty.indexablePtrElem(zcu).abiSize(zcu)) {
6598 0 => unreachable,6598 0 => unreachable,
6599 1 => break :fill_byte .{ .value = bin_op.rhs },6599 1 => break :fill_byte .{ .value = bin_op.rhs },
6600 2, 4, 8 => |size| {6600 2, 4, 8 => |size| {
src/codegen/c.zig+4-4
...@@ -3676,7 +3676,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3676,7 +3676,7 @@ fn airPtrElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
36763676
3677 const inst_ty = f.typeOfIndex(inst);3677 const inst_ty = f.typeOfIndex(inst);
3678 const ptr_ty = f.typeOf(bin_op.lhs);3678 const ptr_ty = f.typeOf(bin_op.lhs);
3679 const elem_has_bits = ptr_ty.elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu);3679 const elem_has_bits = ptr_ty.indexablePtrElem(zcu).hasRuntimeBitsIgnoreComptime(zcu);
36803680
3681 const ptr = try f.resolveInst(bin_op.lhs);3681 const ptr = try f.resolveInst(bin_op.lhs);
3682 const index = try f.resolveInst(bin_op.rhs);3682 const index = try f.resolveInst(bin_op.rhs);
...@@ -3738,7 +3738,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {...@@ -3738,7 +3738,7 @@ fn airSliceElemPtr(f: *Function, inst: Air.Inst.Index) !CValue {
37383738
3739 const inst_ty = f.typeOfIndex(inst);3739 const inst_ty = f.typeOfIndex(inst);
3740 const slice_ty = f.typeOf(bin_op.lhs);3740 const slice_ty = f.typeOf(bin_op.lhs);
3741 const elem_ty = slice_ty.elemType2(zcu);3741 const elem_ty = slice_ty.childType(zcu);
3742 const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(zcu);3742 const elem_has_bits = elem_ty.hasRuntimeBitsIgnoreComptime(zcu);
37433743
3744 const slice = try f.resolveInst(bin_op.lhs);3744 const slice = try f.resolveInst(bin_op.lhs);
...@@ -4502,7 +4502,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {...@@ -4502,7 +4502,7 @@ fn airPtrAddSub(f: *Function, inst: Air.Inst.Index, operator: u8) !CValue {
45024502
4503 const inst_ty = f.typeOfIndex(inst);4503 const inst_ty = f.typeOfIndex(inst);
4504 const inst_scalar_ty = inst_ty.scalarType(zcu);4504 const inst_scalar_ty = inst_ty.scalarType(zcu);
4505 const elem_ty = inst_scalar_ty.elemType2(zcu);4505 const elem_ty = inst_scalar_ty.indexablePtrElem(zcu);
4506 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);4506 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) return f.moveCValue(inst, inst_ty, lhs);
4507 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);4507 const inst_scalar_ctype = try f.ctypeFromType(inst_scalar_ty, .complete);
45084508
...@@ -7037,7 +7037,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV...@@ -7037,7 +7037,7 @@ fn airMemcpy(f: *Function, inst: Air.Inst.Index, function_paren: []const u8) !CV
7037 try w.writeAll(", ");7037 try w.writeAll(", ");
7038 try writeArrayLen(f, dest_ptr, dest_ty);7038 try writeArrayLen(f, dest_ptr, dest_ty);
7039 try w.writeAll(" * sizeof(");7039 try w.writeAll(" * sizeof(");
7040 try f.renderType(w, dest_ty.elemType2(zcu));7040 try f.renderType(w, dest_ty.indexablePtrElem(zcu));
7041 try w.writeAll("));");7041 try w.writeAll("));");
7042 try f.object.newline();7042 try f.object.newline();
70437043
src/codegen/llvm.zig+1-1
...@@ -2112,7 +2112,7 @@ pub const Object = struct {...@@ -2112,7 +2112,7 @@ pub const Object = struct {
2112 return debug_array_type;2112 return debug_array_type;
2113 },2113 },
2114 .vector => {2114 .vector => {
2115 const elem_ty = ty.elemType2(zcu);2115 const elem_ty = ty.childType(zcu);
2116 // Vector elements cannot be padded since that would make2116 // Vector elements cannot be padded since that would make
2117 // @bitSizOf(elem) * len > @bitSizOf(vec).2117 // @bitSizOf(elem) * len > @bitSizOf(vec).
2118 // Neither gdb nor lldb seem to be able to display non-byte sized2118 // Neither gdb nor lldb seem to be able to display non-byte sized
src/codegen/mips/abi.zig+1-1
...@@ -44,7 +44,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {...@@ -44,7 +44,7 @@ pub fn classifyType(ty: Type, zcu: *Zcu, ctx: Context) Class {
44 return .byval;44 return .byval;
45 },45 },
46 .vector => {46 .vector => {
47 const elem_type = ty.elemType2(zcu);47 const elem_type = ty.childType(zcu);
48 switch (elem_type.zigTypeTag(zcu)) {48 switch (elem_type.zigTypeTag(zcu)) {
49 .bool, .int => {49 .bool, .int => {
50 const bit_size = ty.bitSize(zcu);50 const bit_size = ty.bitSize(zcu);
src/codegen/riscv64/CodeGen.zig+2-3
...@@ -2673,7 +2673,7 @@ fn genBinOp(...@@ -2673,7 +2673,7 @@ fn genBinOp(
2673 defer func.register_manager.unlockReg(tmp_lock);2673 defer func.register_manager.unlockReg(tmp_lock);
26742674
2675 // RISC-V has no immediate mul, so we copy the size to a temporary register2675 // RISC-V has no immediate mul, so we copy the size to a temporary register
2676 const elem_size = lhs_ty.elemType2(zcu).abiSize(zcu);2676 const elem_size = lhs_ty.indexablePtrElem(zcu).abiSize(zcu);
2677 const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });2677 const elem_size_reg = try func.copyToTmpRegister(Type.u64, .{ .immediate = elem_size });
26782678
2679 try func.genBinOp(2679 try func.genBinOp(
...@@ -3913,9 +3913,8 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {...@@ -3913,9 +3913,8 @@ fn airPtrElemVal(func: *Func, inst: Air.Inst.Index) !void {
3913 const base_ptr_ty = func.typeOf(bin_op.lhs);3913 const base_ptr_ty = func.typeOf(bin_op.lhs);
39143914
3915 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {3915 const result: MCValue = if (!is_volatile and func.liveness.isUnused(inst)) .unreach else result: {
3916 const elem_ty = base_ptr_ty.elemType2(zcu);3916 const elem_ty = base_ptr_ty.indexablePtrElem(zcu);
3917 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;3917 if (!elem_ty.hasRuntimeBitsIgnoreComptime(zcu)) break :result .none;
3918
3919 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);3918 const base_ptr_mcv = try func.resolveInst(bin_op.lhs);
3920 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {3919 const base_ptr_lock: ?RegisterLock = switch (base_ptr_mcv) {
3921 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),3920 .register => |reg| func.register_manager.lockRegAssumeUnused(reg),
src/codegen/spirv/CodeGen.zig+1-1
...@@ -4381,7 +4381,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {...@@ -4381,7 +4381,7 @@ fn airSliceElemVal(cg: *CodeGen, inst: Air.Inst.Index) !?Id {
4381fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {4381fn ptrElemPtr(cg: *CodeGen, ptr_ty: Type, ptr_id: Id, index_id: Id) !Id {
4382 const zcu = cg.module.zcu;4382 const zcu = cg.module.zcu;
4383 // Construct new pointer type for the resulting pointer4383 // Construct new pointer type for the resulting pointer
4384 const elem_ty = ptr_ty.elemType2(zcu); // use elemType() so that we get T for *[N]T.4384 const elem_ty = ptr_ty.indexablePtrElem(zcu);
4385 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);4385 const elem_ty_id = try cg.resolveType(elem_ty, .indirect);
4386 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));4386 const elem_ptr_ty_id = try cg.module.ptrType(elem_ty_id, cg.module.storageClass(ptr_ty.ptrAddressSpace(zcu)));
4387 if (ptr_ty.isSinglePointer(zcu)) {4387 if (ptr_ty.isSinglePointer(zcu)) {
src/codegen/x86_64/CodeGen.zig+16-21
...@@ -43261,7 +43261,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -43261,7 +43261,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
43261 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });43261 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
43262 try ops[0].toSlicePtr(cg);43262 try ops[0].toSlicePtr(cg);
43263 var res: [1]Temp = undefined;43263 var res: [1]Temp = undefined;
43264 if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{43264 if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
43265 .patterns = &.{43265 .patterns = &.{
43266 .{ .src = .{ .to_gpr, .simm32, .none } },43266 .{ .src = .{ .to_gpr, .simm32, .none } },
43267 },43267 },
...@@ -43375,7 +43375,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -43375,7 +43375,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
43375 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });43375 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
43376 try ops[0].toSlicePtr(cg);43376 try ops[0].toSlicePtr(cg);
43377 var res: [1]Temp = undefined;43377 var res: [1]Temp = undefined;
43378 if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().elemType2(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{43378 if (!hack_around_sema_opv_bugs or ty_pl.ty.toType().childType(zcu).hasRuntimeBitsIgnoreComptime(zcu)) cg.select(&res, &.{ty_pl.ty.toType()}, &ops, comptime &.{ .{
43379 .patterns = &.{43379 .patterns = &.{
43380 .{ .src = .{ .to_gpr, .simm32, .none } },43380 .{ .src = .{ .to_gpr, .simm32, .none } },
43381 },43381 },
...@@ -103926,7 +103926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -103926,7 +103926,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
103926 .array_elem_val, .legalize_vec_elem_val => {103926 .array_elem_val, .legalize_vec_elem_val => {
103927 const bin_op = air_datas[@intFromEnum(inst)].bin_op;103927 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
103928 const array_ty = cg.typeOf(bin_op.lhs);103928 const array_ty = cg.typeOf(bin_op.lhs);
103929 const res_ty = array_ty.elemType2(zcu);103929 const res_ty = array_ty.childType(zcu);
103930 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });103930 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
103931 var res: [1]Temp = undefined;103931 var res: [1]Temp = undefined;
103932 cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{103932 cg.select(&res, &.{res_ty}, &ops, comptime &.{ .{
...@@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {...@@ -104121,7 +104121,7 @@ fn genBody(cg: *CodeGen, body: []const Air.Inst.Index) InnerError!void {
104121 },104121 },
104122 .slice_elem_val, .ptr_elem_val => {104122 .slice_elem_val, .ptr_elem_val => {
104123 const bin_op = air_datas[@intFromEnum(inst)].bin_op;104123 const bin_op = air_datas[@intFromEnum(inst)].bin_op;
104124 const res_ty = cg.typeOf(bin_op.lhs).elemType2(zcu);104124 const res_ty = cg.typeOf(bin_op.lhs).indexablePtrElem(zcu);
104125 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });104125 var ops = try cg.tempsFromOperands(inst, .{ bin_op.lhs, bin_op.rhs });
104126 try ops[0].toSlicePtr(cg);104126 try ops[0].toSlicePtr(cg);
104127 var res: [1]Temp = undefined;104127 var res: [1]Temp = undefined;
...@@ -187919,7 +187919,6 @@ const Select = struct {...@@ -187919,7 +187919,6 @@ const Select = struct {
187919 unsigned_int: Memory.Size,187919 unsigned_int: Memory.Size,
187920 elem_size_is: u8,187920 elem_size_is: u8,
187921 po2_elem_size,187921 po2_elem_size,
187922 elem_int: Memory.Size,
187923187922
187924 const OfIsSizes = struct { of: Memory.Size, is: Memory.Size };187923 const OfIsSizes = struct { of: Memory.Size, is: Memory.Size };
187925187924
...@@ -188178,12 +188177,8 @@ const Select = struct {...@@ -188178,12 +188177,8 @@ const Select = struct {
188178 .signed => false,188177 .signed => false,
188179 .unsigned => size.bitSize(cg.target) >= int_info.bits,188178 .unsigned => size.bitSize(cg.target) >= int_info.bits,
188180 } else false,188179 } else false,
188181 .elem_size_is => |size| size == ty.elemType2(zcu).abiSize(zcu),188180 .elem_size_is => |size| size == ty.indexablePtrElem(zcu).abiSize(zcu),
188182 .po2_elem_size => std.math.isPowerOfTwo(ty.elemType2(zcu).abiSize(zcu)),188181 .po2_elem_size => std.math.isPowerOfTwo(ty.indexablePtrElem(zcu).abiSize(zcu)),
188183 .elem_int => |size| if (cg.intInfo(ty.elemType2(zcu))) |elem_int_info|
188184 size.bitSize(cg.target) >= elem_int_info.bits
188185 else
188186 false,
188187 };188182 };
188188 }188183 }
188189 };188184 };
...@@ -189918,20 +189913,20 @@ const Select = struct {...@@ -189918,20 +189913,20 @@ const Select = struct {
189918 .dst0_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).abiSize(s.cg.pt.zcu)),189913 .dst0_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).abiSize(s.cg.pt.zcu)),
189919 .delta_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu))) -189914 .delta_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).abiSize(s.cg.pt.zcu))) -
189920 @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).abiSize(s.cg.pt.zcu)))),189915 @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).abiSize(s.cg.pt.zcu)))),
189921 .delta_elem_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))) -189916 .delta_elem_size => @intCast(@as(SignedImm, @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))) -
189922 @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)))),189917 @as(SignedImm, @intCast(op.flags.index.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)))),
189923 .unaligned_size => @intCast(s.cg.unalignedSize(op.flags.base.ref.typeOf(s))),189918 .unaligned_size => @intCast(s.cg.unalignedSize(op.flags.base.ref.typeOf(s))),
189924 .unaligned_size_add_elem_size => {189919 .unaligned_size_add_elem_size => {
189925 const ty = op.flags.base.ref.typeOf(s);189920 const ty = op.flags.base.ref.typeOf(s);
189926 break :lhs @intCast(s.cg.unalignedSize(ty) + ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));189921 break :lhs @intCast(s.cg.unalignedSize(ty) + ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
189927 },189922 },
189928 .unaligned_size_sub_elem_size => {189923 .unaligned_size_sub_elem_size => {
189929 const ty = op.flags.base.ref.typeOf(s);189924 const ty = op.flags.base.ref.typeOf(s);
189930 break :lhs @intCast(s.cg.unalignedSize(ty) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));189925 break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu));
189931 },189926 },
189932 .unaligned_size_sub_2_elem_size => {189927 .unaligned_size_sub_2_elem_size => {
189933 const ty = op.flags.base.ref.typeOf(s);189928 const ty = op.flags.base.ref.typeOf(s);
189934 break :lhs @intCast(s.cg.unalignedSize(ty) - ty.elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2);189929 break :lhs @intCast(s.cg.unalignedSize(ty) - ty.scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) * 2);
189935 },189930 },
189936 .bit_size => @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s))),189931 .bit_size => @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s))),
189937 .src0_bit_size => @intCast(s.cg.nonBoolScalarBitSize(Select.Operand.Ref.src0.typeOf(s))),189932 .src0_bit_size => @intCast(s.cg.nonBoolScalarBitSize(Select.Operand.Ref.src0.typeOf(s))),
...@@ -189944,10 +189939,10 @@ const Select = struct {...@@ -189944,10 +189939,10 @@ const Select = struct {
189944 op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),189939 op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu),
189945 @divExact(op.flags.base.size.bitSize(s.cg.target), 8),189940 @divExact(op.flags.base.size.bitSize(s.cg.target), 8),
189946 )),189941 )),
189947 .elem_size => @intCast(op.flags.base.ref.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),189942 .elem_size => @intCast(op.flags.base.ref.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189948 .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),189943 .src0_elem_size => @intCast(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189949 .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),189944 .dst0_elem_size => @intCast(Select.Operand.Ref.dst0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu)),
189950 .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *189945 .src0_elem_size_mul_src1 => @intCast(Select.Operand.Ref.src0.typeOf(s).indexableElem(s.cg.pt.zcu).abiSize(s.cg.pt.zcu) *
189951 Select.Operand.Ref.src1.valueOf(s).immediate),189946 Select.Operand.Ref.src1.valueOf(s).immediate),
189952 .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {189947 .vector_index => switch (op.flags.base.ref.typeOf(s).ptrInfo(s.cg.pt.zcu).flags.vector_index) {
189953 .none => unreachable,189948 .none => unreachable,
...@@ -189956,7 +189951,7 @@ const Select = struct {...@@ -189956,7 +189951,7 @@ const Select = struct {
189956 .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),189951 .src1 => @intCast(Select.Operand.Ref.src1.valueOf(s).immediate),
189957 .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -189952 .src1_sub_bit_size => @as(SignedImm, @intCast(Select.Operand.Ref.src1.valueOf(s).immediate)) -
189958 @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))),189953 @as(SignedImm, @intCast(s.cg.nonBoolScalarBitSize(op.flags.base.ref.typeOf(s)))),
189959 .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).elemType2(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),189954 .log2_src0_elem_size => @intCast(std.math.log2(Select.Operand.Ref.src0.typeOf(s).scalarType(s.cg.pt.zcu).abiSize(s.cg.pt.zcu))),
189960 .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast(189955 .elem_mask => @as(u8, std.math.maxInt(u8)) >> @intCast(
189961 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) %189956 8 - ((s.cg.unalignedSize(op.flags.base.ref.typeOf(s)) - 1) %
189962 @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >>189957 @divExact(op.flags.base.size.bitSize(s.cg.target), 8) + 1 >>
src/link/Dwarf.zig+4-4
...@@ -4575,10 +4575,10 @@ fn updateContainerTypeWriterError(...@@ -4575,10 +4575,10 @@ fn updateContainerTypeWriterError(
4575 const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {4575 const name_strat: Zir.Inst.NameStrategy = switch (decl_inst.tag) {
4576 .struct_init, .struct_init_ref, .struct_init_anon => .anon,4576 .struct_init, .struct_init_ref, .struct_init_anon => .anon,
4577 .extended => switch (decl_inst.data.extended.opcode) {4577 .extended => switch (decl_inst.data.extended.opcode) {
4578 .struct_decl => @as(Zir.Inst.StructDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,4578 .struct_decl => file.zir.?.getStructDecl(inst_info.inst).name_strategy,
4579 .enum_decl => @as(Zir.Inst.EnumDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,4579 .union_decl => file.zir.?.getUnionDecl(inst_info.inst).name_strategy,
4580 .union_decl => @as(Zir.Inst.UnionDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,4580 .enum_decl => file.zir.?.getEnumDecl(inst_info.inst).name_strategy,
4581 .opaque_decl => @as(Zir.Inst.OpaqueDecl.Small, @bitCast(decl_inst.data.extended.small)).name_strategy,4581 .opaque_decl => file.zir.?.getOpaqueDecl(inst_info.inst).name_strategy,
45824582
4583 .reify_enum,4583 .reify_enum,
4584 .reify_struct,4584 .reify_struct,
src/mutable_value.zig+3-15
...@@ -18,7 +18,7 @@ pub const MutableValue = union(enum) {...@@ -18,7 +18,7 @@ pub const MutableValue = union(enum) {
18 opt_payload: SubValue,18 opt_payload: SubValue,
19 /// An aggregate consisting of a single repeated value.19 /// An aggregate consisting of a single repeated value.
20 repeated: SubValue,20 repeated: SubValue,
21 /// An aggregate of `u8` consisting of "plain" bytes (no lazy or undefined elements).21 /// An aggregate of `u8` consisting of "plain" bytes (no undefined elements).
22 bytes: Bytes,22 bytes: Bytes,
23 /// An aggregate with arbitrary sub-values.23 /// An aggregate with arbitrary sub-values.
24 aggregate: Aggregate,24 aggregate: Aggregate,
...@@ -415,16 +415,7 @@ pub const MutableValue = union(enum) {...@@ -415,16 +415,7 @@ pub const MutableValue = union(enum) {
415 } else if (!is_struct and is_trivial_int and Type.fromInterned(a.ty).childType(zcu).toIntern() == .u8_type) {415 } else if (!is_struct and is_trivial_int and Type.fromInterned(a.ty).childType(zcu).toIntern() == .u8_type) {
416 // See if we can switch to `bytes` repr416 // See if we can switch to `bytes` repr
417 for (a.elems) |e| {417 for (a.elems) |e| {
418 switch (e) {418 if (!e.isTrivialInt(zcu)) break;
419 else => break,
420 .interned => |ip_index| switch (ip.indexToKey(ip_index)) {
421 else => break,
422 .int => |int| switch (int.storage) {
423 .u64, .i64, .big_int => {},
424 .lazy_align, .lazy_size => break,
425 },
426 },
427 }
428 } else {419 } else {
429 const bytes = try arena.alloc(u8, a.elems.len);420 const bytes = try arena.alloc(u8, a.elems.len);
430 for (a.elems, bytes) |elem_val, *b| {421 for (a.elems, bytes) |elem_val, *b| {
...@@ -494,10 +485,7 @@ pub const MutableValue = union(enum) {...@@ -494,10 +485,7 @@ pub const MutableValue = union(enum) {
494 else => false,485 else => false,
495 .interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) {486 .interned => |ip_index| switch (zcu.intern_pool.indexToKey(ip_index)) {
496 else => false,487 else => false,
497 .int => |int| switch (int.storage) {488 .int => true,
498 .u64, .i64, .big_int => true,
499 .lazy_align, .lazy_size => false,
500 },
501 },489 },
502 };490 };
503 }491 }
src/print_value.zig+2-10
...@@ -81,14 +81,6 @@ pub fn print(...@@ -81,14 +81,6 @@ pub fn print(
81 .int => |int| switch (int.storage) {81 .int => |int| switch (int.storage) {
82 inline .u64, .i64 => |x| try writer.print("{d}", .{x}),82 inline .u64, .i64 => |x| try writer.print("{d}", .{x}),
83 .big_int => |x| try writer.print("{d}", .{x}),83 .big_int => |x| try writer.print("{d}", .{x}),
84 .lazy_align => |ty| if (opt_sema != null) {
85 const a = try Type.fromInterned(ty).abiAlignmentSema(pt);
86 try writer.print("{d}", .{a.toByteUnits() orelse 0});
87 } else try writer.print("@alignOf({f})", .{Type.fromInterned(ty).fmt(pt)}),
88 .lazy_size => |ty| if (opt_sema != null) {
89 const s = try Type.fromInterned(ty).abiSizeSema(pt);
90 try writer.print("{d}", .{s});
91 } else try writer.print("@sizeOf({f})", .{Type.fromInterned(ty).fmt(pt)}),
92 },84 },
93 .err => |err| try writer.print("error.{f}", .{85 .err => |err| try writer.print("error.{f}", .{
94 err.name.fmt(ip),86 err.name.fmt(ip),
...@@ -104,8 +96,8 @@ pub fn print(...@@ -104,8 +96,8 @@ pub fn print(
104 }),96 }),
105 .enum_tag => |enum_tag| {97 .enum_tag => |enum_tag| {
106 const enum_type = ip.loadEnumType(val.typeOf(zcu).toIntern());98 const enum_type = ip.loadEnumType(val.typeOf(zcu).toIntern());
107 if (enum_type.tagValueIndex(ip, val.toIntern())) |tag_index| {99 if (enum_type.tagValueIndex(ip, enum_tag.int)) |tag_index| {
108 return writer.print(".{f}", .{enum_type.names.get(ip)[tag_index].fmt(ip)});100 return writer.print(".{f}", .{enum_type.field_names.get(ip)[tag_index].fmt(ip)});
109 }101 }
110 if (level == 0) {102 if (level == 0) {
111 return writer.writeAll("@enumFromInt(...)");103 return writer.writeAll("@enumFromInt(...)");