authorgravatar for andrew@ziglang.orgAndrew Kelley <andrew@ziglang.org> 2024-07-04 20:12:05-04:00
committergravatar for noreply@github.comGitHub <noreply@github.com> 2024-07-04 20:12:05-04:00
log790b8428a26457e7ed9ea20485b9d3085011b989
tree3d27f81e31d73af526e8a972504325fa1cb0d9e1
parentde61540c2d049b0774dd9c5e14aa8f65ed1c25ed
parentcda6f552d5d4a996df69981dac7c9d9b3c066537
signaturebadge-check Signed by PGP key B5690EEEBB952194

Merge pull request #20494 from mlugg/the-great-decl-split

refactors ad infinitum

71 files changed, 6753 insertions(+), 6819 deletions(-)

CMakeLists.txt+1-1
......@@ -522,6 +522,7 @@ set(ZIG_STAGE2_SOURCES
522522 src/Sema.zig
523523 src/Sema/bitcast.zig
524524 src/Sema/comptime_ptr_access.zig
525 src/Type.zig
525526 src/Value.zig
526527 src/Zcu.zig
527528 src/arch/aarch64/CodeGen.zig
......@@ -673,7 +674,6 @@ set(ZIG_STAGE2_SOURCES
673674 src/target.zig
674675 src/tracy.zig
675676 src/translate_c.zig
676 src/type.zig
677677 src/wasi_libc.zig
678678)
679679
build.zig+6-22
......@@ -82,15 +82,6 @@ pub fn build(b: *std.Build) !void {
8282 docs_step.dependOn(langref_step);
8383 docs_step.dependOn(std_docs_step);
8484
85 const check_case_exe = b.addExecutable(.{
86 .name = "check-case",
87 .root_source_file = b.path("test/src/Cases.zig"),
88 .target = b.graph.host,
89 .optimize = optimize,
90 .single_threaded = single_threaded,
91 });
92 check_case_exe.stack_size = stack_size;
93
9485 const skip_debug = b.option(bool, "skip-debug", "Main test suite skips debug builds") orelse false;
9586 const skip_release = b.option(bool, "skip-release", "Main test suite skips release builds") orelse false;
9687 const skip_release_small = b.option(bool, "skip-release-small", "Main test suite skips release-small builds") orelse skip_release;
......@@ -222,7 +213,6 @@ pub fn build(b: *std.Build) !void {
222213 if (target.result.os.tag == .windows and target.result.abi == .gnu) {
223214 // LTO is currently broken on mingw, this can be removed when it's fixed.
224215 exe.want_lto = false;
225 check_case_exe.want_lto = false;
226216 }
227217
228218 const use_llvm = b.option(bool, "use-llvm", "Use the llvm backend");
......@@ -245,7 +235,6 @@ pub fn build(b: *std.Build) !void {
245235
246236 if (link_libc) {
247237 exe.linkLibC();
248 check_case_exe.linkLibC();
249238 }
250239
251240 const is_debug = optimize == .Debug;
......@@ -339,21 +328,17 @@ pub fn build(b: *std.Build) !void {
339328 }
340329
341330 try addCmakeCfgOptionsToExe(b, cfg, exe, use_zig_libcxx);
342 try addCmakeCfgOptionsToExe(b, cfg, check_case_exe, use_zig_libcxx);
343331 } else {
344332 // Here we are -Denable-llvm but no cmake integration.
345333 try addStaticLlvmOptionsToExe(exe);
346 try addStaticLlvmOptionsToExe(check_case_exe);
347334 }
348335 if (target.result.os.tag == .windows) {
349 inline for (.{ exe, check_case_exe }) |artifact| {
350 // LLVM depends on networking as of version 18.
351 artifact.linkSystemLibrary("ws2_32");
336 // LLVM depends on networking as of version 18.
337 exe.linkSystemLibrary("ws2_32");
352338
353 artifact.linkSystemLibrary("version");
354 artifact.linkSystemLibrary("uuid");
355 artifact.linkSystemLibrary("ole32");
356 }
339 exe.linkSystemLibrary("version");
340 exe.linkSystemLibrary("uuid");
341 exe.linkSystemLibrary("ole32");
357342 }
358343 }
359344
......@@ -394,7 +379,6 @@ pub fn build(b: *std.Build) !void {
394379 const test_filters = b.option([]const []const u8, "test-filter", "Skip tests that do not match any filter") orelse &[0][]const u8{};
395380
396381 const test_cases_options = b.addOptions();
397 check_case_exe.root_module.addOptions("build_options", test_cases_options);
398382
399383 test_cases_options.addOption(bool, "enable_tracy", false);
400384 test_cases_options.addOption(bool, "enable_debug_extensions", enable_debug_extensions);
......@@ -458,7 +442,7 @@ pub fn build(b: *std.Build) !void {
458442 test_step.dependOn(check_fmt);
459443
460444 const test_cases_step = b.step("test-cases", "Run the main compiler test cases");
461 try tests.addCases(b, test_cases_step, test_filters, check_case_exe, target, .{
445 try tests.addCases(b, test_cases_step, test_filters, target, .{
462446 .skip_translate_c = skip_translate_c,
463447 .skip_run_translated_c = skip_run_translated_c,
464448 }, .{
lib/std/dynamic_library.zig+31-16
......@@ -17,12 +17,15 @@ pub const DynLib = struct {
1717 DlDynLib,
1818 .windows => WindowsDynLib,
1919 .macos, .tvos, .watchos, .ios, .visionos, .freebsd, .netbsd, .openbsd, .dragonfly, .solaris, .illumos => DlDynLib,
20 else => @compileError("unsupported platform"),
20 else => struct {
21 const open = @compileError("unsupported platform");
22 const openZ = @compileError("unsupported platform");
23 },
2124 };
2225
2326 inner: InnerType,
2427
25 pub const Error = ElfDynLib.Error || DlDynLib.Error || WindowsDynLib.Error;
28 pub const Error = ElfDynLibError || DlDynLibError || WindowsDynLibError;
2629
2730 /// Trusts the file. Malicious file will be able to execute arbitrary code.
2831 pub fn open(path: []const u8) Error!DynLib {
......@@ -122,6 +125,18 @@ pub fn linkmap_iterator(phdrs: []elf.Phdr) error{InvalidExe}!LinkMap.Iterator {
122125 return .{ .current = link_map_ptr };
123126}
124127
128/// Separated to avoid referencing `ElfDynLib`, because its field types may not
129/// be valid on other targets.
130const ElfDynLibError = error{
131 FileTooBig,
132 NotElfFile,
133 NotDynamicLibrary,
134 MissingDynamicLinkingInformation,
135 ElfStringSectionNotFound,
136 ElfSymSectionNotFound,
137 ElfHashTableNotFound,
138} || posix.OpenError || posix.MMapError;
139
125140pub const ElfDynLib = struct {
126141 strings: [*:0]u8,
127142 syms: [*]elf.Sym,
......@@ -130,15 +145,7 @@ pub const ElfDynLib = struct {
130145 verdef: ?*elf.Verdef,
131146 memory: []align(mem.page_size) u8,
132147
133 pub const Error = error{
134 FileTooBig,
135 NotElfFile,
136 NotDynamicLibrary,
137 MissingDynamicLinkingInformation,
138 ElfStringSectionNotFound,
139 ElfSymSectionNotFound,
140 ElfHashTableNotFound,
141 } || posix.OpenError || posix.MMapError;
148 pub const Error = ElfDynLibError;
142149
143150 /// Trusts the file. Malicious file will be able to execute arbitrary code.
144151 pub fn open(path: []const u8) Error!ElfDynLib {
......@@ -350,11 +357,15 @@ test "ElfDynLib" {
350357 try testing.expectError(error.FileNotFound, ElfDynLib.open("invalid_so.so"));
351358}
352359
360/// Separated to avoid referencing `WindowsDynLib`, because its field types may not
361/// be valid on other targets.
362const WindowsDynLibError = error{
363 FileNotFound,
364 InvalidPath,
365} || windows.LoadLibraryError;
366
353367pub const WindowsDynLib = struct {
354 pub const Error = error{
355 FileNotFound,
356 InvalidPath,
357 } || windows.LoadLibraryError;
368 pub const Error = WindowsDynLibError;
358369
359370 dll: windows.HMODULE,
360371
......@@ -413,8 +424,12 @@ pub const WindowsDynLib = struct {
413424 }
414425};
415426
427/// Separated to avoid referencing `DlDynLib`, because its field types may not
428/// be valid on other targets.
429const DlDynLibError = error{ FileNotFound, NameTooLong };
430
416431pub const DlDynLib = struct {
417 pub const Error = error{ FileNotFound, NameTooLong };
432 pub const Error = DlDynLibError;
418433
419434 handle: *anyopaque,
420435
lib/std/http.zig+6-6
......@@ -311,13 +311,13 @@ const builtin = @import("builtin");
311311const std = @import("std.zig");
312312
313313test {
314 _ = Client;
315 _ = Method;
316 _ = Server;
317 _ = Status;
318 _ = HeadParser;
319 _ = ChunkParser;
320314 if (builtin.os.tag != .wasi) {
315 _ = Client;
316 _ = Method;
317 _ = Server;
318 _ = Status;
319 _ = HeadParser;
320 _ = ChunkParser;
321321 _ = @import("http/test.zig");
322322 }
323323}
lib/std/net.zig+6-4
......@@ -1930,8 +1930,10 @@ pub const Server = struct {
19301930};
19311931
19321932test {
1933 _ = @import("net/test.zig");
1934 _ = Server;
1935 _ = Stream;
1936 _ = Address;
1933 if (builtin.os.tag != .wasi) {
1934 _ = Server;
1935 _ = Stream;
1936 _ = Address;
1937 _ = @import("net/test.zig");
1938 }
19371939}
lib/zig.h+4-4
......@@ -207,16 +207,16 @@ typedef char bool;
207207 __asm(zig_mangle_c(name) " = " zig_mangle_c(symbol))
208208#endif
209209
210#define zig_mangled_tentative zig_mangled
211#define zig_mangled_final zig_mangled
210212#if _MSC_VER
211#define zig_mangled_tentative(mangled, unmangled)
212#define zig_mangled_final(mangled, unmangled) ; \
213#define zig_mangled(mangled, unmangled) ; \
213214 zig_export(#mangled, unmangled)
214215#define zig_mangled_export(mangled, unmangled, symbol) \
215216 zig_export(unmangled, #mangled) \
216217 zig_export(symbol, unmangled)
217218#else /* _MSC_VER */
218#define zig_mangled_tentative(mangled, unmangled) __asm(zig_mangle_c(unmangled))
219#define zig_mangled_final(mangled, unmangled) zig_mangled_tentative(mangled, unmangled)
219#define zig_mangled(mangled, unmangled) __asm(zig_mangle_c(unmangled))
220220#define zig_mangled_export(mangled, unmangled, symbol) \
221221 zig_mangled_final(mangled, unmangled) \
222222 zig_export(symbol, unmangled)
src/Air.zig+3-1
......@@ -9,7 +9,7 @@ const assert = std.debug.assert;
99
1010const Air = @This();
1111const Value = @import("Value.zig");
12const Type = @import("type.zig").Type;
12const Type = @import("Type.zig");
1313const InternPool = @import("InternPool.zig");
1414const Zcu = @import("Zcu.zig");
1515/// Deprecated.
......@@ -1801,3 +1801,5 @@ pub fn mustLower(air: Air, inst: Air.Inst.Index, ip: *const InternPool) bool {
18011801 .atomic_load => air.typeOf(data.atomic_load.ptr, ip).isVolatilePtrIp(ip),
18021802 };
18031803}
1804
1805pub const typesFullyResolved = @import("Air/types_resolved.zig").typesFullyResolved;
src/Air/types_resolved.zig created+521
......@@ -0,0 +1,521 @@
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 .atomic_store_unordered,
87 .atomic_store_monotonic,
88 .atomic_store_release,
89 .atomic_store_seq_cst,
90 => {
91 if (!checkRef(data.bin_op.lhs, zcu)) return false;
92 if (!checkRef(data.bin_op.rhs, zcu)) return false;
93 },
94
95 .not,
96 .bitcast,
97 .clz,
98 .ctz,
99 .popcount,
100 .byte_swap,
101 .bit_reverse,
102 .abs,
103 .load,
104 .fptrunc,
105 .fpext,
106 .intcast,
107 .trunc,
108 .optional_payload,
109 .optional_payload_ptr,
110 .optional_payload_ptr_set,
111 .wrap_optional,
112 .unwrap_errunion_payload,
113 .unwrap_errunion_err,
114 .unwrap_errunion_payload_ptr,
115 .unwrap_errunion_err_ptr,
116 .errunion_payload_ptr_set,
117 .wrap_errunion_payload,
118 .wrap_errunion_err,
119 .struct_field_ptr_index_0,
120 .struct_field_ptr_index_1,
121 .struct_field_ptr_index_2,
122 .struct_field_ptr_index_3,
123 .get_union_tag,
124 .slice_len,
125 .slice_ptr,
126 .ptr_slice_len_ptr,
127 .ptr_slice_ptr_ptr,
128 .array_to_slice,
129 .int_from_float,
130 .int_from_float_optimized,
131 .float_from_int,
132 .splat,
133 .error_set_has_value,
134 .addrspace_cast,
135 .c_va_arg,
136 .c_va_copy,
137 => {
138 if (!checkType(data.ty_op.ty.toType(), zcu)) return false;
139 if (!checkRef(data.ty_op.operand, zcu)) return false;
140 },
141
142 .alloc,
143 .ret_ptr,
144 .c_va_start,
145 => {
146 if (!checkType(data.ty, zcu)) return false;
147 },
148
149 .ptr_add,
150 .ptr_sub,
151 .add_with_overflow,
152 .sub_with_overflow,
153 .mul_with_overflow,
154 .shl_with_overflow,
155 .slice,
156 .slice_elem_ptr,
157 .ptr_elem_ptr,
158 => {
159 const bin = air.extraData(Air.Bin, data.ty_pl.payload).data;
160 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
161 if (!checkRef(bin.lhs, zcu)) return false;
162 if (!checkRef(bin.rhs, zcu)) return false;
163 },
164
165 .block,
166 .loop,
167 => {
168 const extra = air.extraData(Air.Block, data.ty_pl.payload);
169 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
170 if (!checkBody(
171 air,
172 @ptrCast(air.extra[extra.end..][0..extra.data.body_len]),
173 zcu,
174 )) return false;
175 },
176
177 .dbg_inline_block => {
178 const extra = air.extraData(Air.DbgInlineBlock, data.ty_pl.payload);
179 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
180 if (!checkBody(
181 air,
182 @ptrCast(air.extra[extra.end..][0..extra.data.body_len]),
183 zcu,
184 )) return false;
185 },
186
187 .sqrt,
188 .sin,
189 .cos,
190 .tan,
191 .exp,
192 .exp2,
193 .log,
194 .log2,
195 .log10,
196 .floor,
197 .ceil,
198 .round,
199 .trunc_float,
200 .neg,
201 .neg_optimized,
202 .is_null,
203 .is_non_null,
204 .is_null_ptr,
205 .is_non_null_ptr,
206 .is_err,
207 .is_non_err,
208 .is_err_ptr,
209 .is_non_err_ptr,
210 .int_from_ptr,
211 .int_from_bool,
212 .ret,
213 .ret_safe,
214 .ret_load,
215 .is_named_enum_value,
216 .tag_name,
217 .error_name,
218 .cmp_lt_errors_len,
219 .c_va_end,
220 .set_err_return_trace,
221 => {
222 if (!checkRef(data.un_op, zcu)) return false;
223 },
224
225 .br => {
226 if (!checkRef(data.br.operand, zcu)) return false;
227 },
228
229 .cmp_vector,
230 .cmp_vector_optimized,
231 => {
232 const extra = air.extraData(Air.VectorCmp, data.ty_pl.payload).data;
233 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
234 if (!checkRef(extra.lhs, zcu)) return false;
235 if (!checkRef(extra.rhs, zcu)) return false;
236 },
237
238 .reduce,
239 .reduce_optimized,
240 => {
241 if (!checkRef(data.reduce.operand, zcu)) return false;
242 },
243
244 .struct_field_ptr,
245 .struct_field_val,
246 => {
247 const extra = air.extraData(Air.StructField, data.ty_pl.payload).data;
248 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
249 if (!checkRef(extra.struct_operand, zcu)) return false;
250 },
251
252 .shuffle => {
253 const extra = air.extraData(Air.Shuffle, data.ty_pl.payload).data;
254 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
255 if (!checkRef(extra.a, zcu)) return false;
256 if (!checkRef(extra.b, zcu)) return false;
257 if (!checkVal(Value.fromInterned(extra.mask), zcu)) return false;
258 },
259
260 .cmpxchg_weak,
261 .cmpxchg_strong,
262 => {
263 const extra = air.extraData(Air.Cmpxchg, data.ty_pl.payload).data;
264 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
265 if (!checkRef(extra.ptr, zcu)) return false;
266 if (!checkRef(extra.expected_value, zcu)) return false;
267 if (!checkRef(extra.new_value, zcu)) return false;
268 },
269
270 .aggregate_init => {
271 const ty = data.ty_pl.ty.toType();
272 const elems_len: usize = @intCast(ty.arrayLen(zcu));
273 const elems: []const Air.Inst.Ref = @ptrCast(air.extra[data.ty_pl.payload..][0..elems_len]);
274 if (!checkType(ty, zcu)) return false;
275 if (ty.zigTypeTag(zcu) == .Struct) {
276 for (elems, 0..) |elem, elem_idx| {
277 if (ty.structFieldIsComptime(elem_idx, zcu)) continue;
278 if (!checkRef(elem, zcu)) return false;
279 }
280 } else {
281 for (elems) |elem| {
282 if (!checkRef(elem, zcu)) return false;
283 }
284 }
285 },
286
287 .union_init => {
288 const extra = air.extraData(Air.UnionInit, data.ty_pl.payload).data;
289 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
290 if (!checkRef(extra.init, zcu)) return false;
291 },
292
293 .field_parent_ptr => {
294 const extra = air.extraData(Air.FieldParentPtr, data.ty_pl.payload).data;
295 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
296 if (!checkRef(extra.field_ptr, zcu)) return false;
297 },
298
299 .atomic_load => {
300 if (!checkRef(data.atomic_load.ptr, zcu)) return false;
301 },
302
303 .prefetch => {
304 if (!checkRef(data.prefetch.ptr, zcu)) return false;
305 },
306
307 .vector_store_elem => {
308 const bin = air.extraData(Air.Bin, data.vector_store_elem.payload).data;
309 if (!checkRef(data.vector_store_elem.vector_ptr, zcu)) return false;
310 if (!checkRef(bin.lhs, zcu)) return false;
311 if (!checkRef(bin.rhs, zcu)) return false;
312 },
313
314 .select,
315 .mul_add,
316 => {
317 const bin = air.extraData(Air.Bin, data.pl_op.payload).data;
318 if (!checkRef(data.pl_op.operand, zcu)) return false;
319 if (!checkRef(bin.lhs, zcu)) return false;
320 if (!checkRef(bin.rhs, zcu)) return false;
321 },
322
323 .atomic_rmw => {
324 const extra = air.extraData(Air.AtomicRmw, data.pl_op.payload).data;
325 if (!checkRef(data.pl_op.operand, zcu)) return false;
326 if (!checkRef(extra.operand, zcu)) return false;
327 },
328
329 .call,
330 .call_always_tail,
331 .call_never_tail,
332 .call_never_inline,
333 => {
334 const extra = air.extraData(Air.Call, data.pl_op.payload);
335 const args: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.args_len]);
336 if (!checkRef(data.pl_op.operand, zcu)) return false;
337 for (args) |arg| if (!checkRef(arg, zcu)) return false;
338 },
339
340 .dbg_var_ptr,
341 .dbg_var_val,
342 => {
343 if (!checkRef(data.pl_op.operand, zcu)) return false;
344 },
345
346 .@"try" => {
347 const extra = air.extraData(Air.Try, data.pl_op.payload);
348 if (!checkRef(data.pl_op.operand, zcu)) return false;
349 if (!checkBody(
350 air,
351 @ptrCast(air.extra[extra.end..][0..extra.data.body_len]),
352 zcu,
353 )) return false;
354 },
355
356 .try_ptr => {
357 const extra = air.extraData(Air.TryPtr, data.ty_pl.payload);
358 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
359 if (!checkRef(extra.data.ptr, zcu)) return false;
360 if (!checkBody(
361 air,
362 @ptrCast(air.extra[extra.end..][0..extra.data.body_len]),
363 zcu,
364 )) return false;
365 },
366
367 .cond_br => {
368 const extra = air.extraData(Air.CondBr, data.pl_op.payload);
369 if (!checkRef(data.pl_op.operand, zcu)) return false;
370 if (!checkBody(
371 air,
372 @ptrCast(air.extra[extra.end..][0..extra.data.then_body_len]),
373 zcu,
374 )) return false;
375 if (!checkBody(
376 air,
377 @ptrCast(air.extra[extra.end + extra.data.then_body_len ..][0..extra.data.else_body_len]),
378 zcu,
379 )) return false;
380 },
381
382 .switch_br => {
383 const extra = air.extraData(Air.SwitchBr, data.pl_op.payload);
384 if (!checkRef(data.pl_op.operand, zcu)) return false;
385 var extra_index = extra.end;
386 for (0..extra.data.cases_len) |_| {
387 const case = air.extraData(Air.SwitchBr.Case, extra_index);
388 extra_index = case.end;
389 const items: []const Air.Inst.Ref = @ptrCast(air.extra[extra_index..][0..case.data.items_len]);
390 extra_index += case.data.items_len;
391 for (items) |item| if (!checkRef(item, zcu)) return false;
392 if (!checkBody(
393 air,
394 @ptrCast(air.extra[extra_index..][0..case.data.body_len]),
395 zcu,
396 )) return false;
397 extra_index += case.data.body_len;
398 }
399 if (!checkBody(
400 air,
401 @ptrCast(air.extra[extra_index..][0..extra.data.else_body_len]),
402 zcu,
403 )) return false;
404 },
405
406 .assembly => {
407 const extra = air.extraData(Air.Asm, data.ty_pl.payload);
408 if (!checkType(data.ty_pl.ty.toType(), zcu)) return false;
409 // Luckily, we only care about the inputs and outputs, so we don't have to do
410 // the whole null-terminated string dance.
411 const outputs: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end..][0..extra.data.outputs_len]);
412 const inputs: []const Air.Inst.Ref = @ptrCast(air.extra[extra.end + extra.data.outputs_len ..][0..extra.data.inputs_len]);
413 for (outputs) |output| if (output != .none and !checkRef(output, zcu)) return false;
414 for (inputs) |input| if (input != .none and !checkRef(input, zcu)) return false;
415 },
416
417 .trap,
418 .breakpoint,
419 .ret_addr,
420 .frame_addr,
421 .unreach,
422 .wasm_memory_size,
423 .wasm_memory_grow,
424 .work_item_id,
425 .work_group_size,
426 .work_group_id,
427 .fence,
428 .dbg_stmt,
429 .err_return_trace,
430 .save_err_return_trace_index,
431 => {},
432 }
433 }
434 return true;
435}
436
437fn checkRef(ref: Air.Inst.Ref, zcu: *Zcu) bool {
438 const ip_index = ref.toInterned() orelse {
439 // This operand refers back to a previous instruction.
440 // We have already checked that instruction's type.
441 // So, there's no need to check this operand's type.
442 return true;
443 };
444 return checkVal(Value.fromInterned(ip_index), zcu);
445}
446
447fn checkVal(val: Value, zcu: *Zcu) bool {
448 if (!checkType(val.typeOf(zcu), zcu)) return false;
449 // Check for lazy values
450 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
451 .int => |int| switch (int.storage) {
452 .u64, .i64, .big_int => return true,
453 .lazy_align, .lazy_size => |ty_index| {
454 return checkType(Type.fromInterned(ty_index), zcu);
455 },
456 },
457 else => return true,
458 }
459}
460
461fn checkType(ty: Type, zcu: *Zcu) bool {
462 const ip = &zcu.intern_pool;
463 return switch (ty.zigTypeTag(zcu)) {
464 .Type,
465 .Void,
466 .Bool,
467 .NoReturn,
468 .Int,
469 .Float,
470 .ErrorSet,
471 .Enum,
472 .Opaque,
473 .Vector,
474 // These types can appear due to some dummy instructions Sema introduces and expects to be omitted by Liveness.
475 // It's a little silly -- but fine, we'll return `true`.
476 .ComptimeFloat,
477 .ComptimeInt,
478 .Undefined,
479 .Null,
480 .EnumLiteral,
481 => true,
482
483 .Frame,
484 .AnyFrame,
485 => @panic("TODO Air.types_resolved.checkType async frames"),
486
487 .Optional => checkType(ty.childType(zcu), zcu),
488 .ErrorUnion => checkType(ty.errorUnionPayload(zcu), zcu),
489 .Pointer => checkType(ty.childType(zcu), zcu),
490 .Array => checkType(ty.childType(zcu), zcu),
491
492 .Fn => {
493 const info = zcu.typeToFunc(ty).?;
494 for (0..info.param_types.len) |i| {
495 const param_ty = info.param_types.get(ip)[i];
496 if (!checkType(Type.fromInterned(param_ty), zcu)) return false;
497 }
498 return checkType(Type.fromInterned(info.return_type), zcu);
499 },
500 .Struct => switch (ip.indexToKey(ty.toIntern())) {
501 .struct_type => {
502 const struct_obj = zcu.typeToStruct(ty).?;
503 return switch (struct_obj.layout) {
504 .@"packed" => struct_obj.backingIntType(ip).* != .none,
505 .auto, .@"extern" => struct_obj.flagsPtr(ip).fully_resolved,
506 };
507 },
508 .anon_struct_type => |tuple| {
509 for (0..tuple.types.len) |i| {
510 const field_is_comptime = tuple.values.get(ip)[i] != .none;
511 if (field_is_comptime) continue;
512 const field_ty = tuple.types.get(ip)[i];
513 if (!checkType(Type.fromInterned(field_ty), zcu)) return false;
514 }
515 return true;
516 },
517 else => unreachable,
518 },
519 .Union => return zcu.typeToUnion(ty).?.flagsPtr(ip).status == .fully_resolved,
520 };
521}
src/Compilation.zig+207-137
......@@ -12,7 +12,7 @@ const WaitGroup = std.Thread.WaitGroup;
1212const ErrorBundle = std.zig.ErrorBundle;
1313
1414const Value = @import("Value.zig");
15const Type = @import("type.zig").Type;
15const Type = @import("Type.zig");
1616const target_util = @import("target.zig");
1717const Package = @import("Package.zig");
1818const link = @import("link.zig");
......@@ -31,11 +31,13 @@ const clangMain = @import("main.zig").clangMain;
3131const Zcu = @import("Zcu.zig");
3232/// Deprecated; use `Zcu`.
3333const Module = Zcu;
34const Sema = @import("Sema.zig");
3435const InternPool = @import("InternPool.zig");
3536const Cache = std.Build.Cache;
3637const c_codegen = @import("codegen/c.zig");
3738const libtsan = @import("libtsan.zig");
3839const Zir = std.zig.Zir;
40const Air = @import("Air.zig");
3941const Builtin = @import("Builtin.zig");
4042const LlvmObject = @import("codegen/llvm.zig").Object;
4143
......@@ -315,18 +317,29 @@ const Job = union(enum) {
315317 codegen_decl: InternPool.DeclIndex,
316318 /// Write the machine code for a function to the output file.
317319 /// This will either be a non-generic `func_decl` or a `func_instance`.
318 codegen_func: InternPool.Index,
320 codegen_func: struct {
321 func: InternPool.Index,
322 /// This `Air` is owned by the `Job` and allocated with `gpa`.
323 /// It must be deinited when the job is processed.
324 air: Air,
325 },
319326 /// Render the .h file snippet for the Decl.
320327 emit_h_decl: InternPool.DeclIndex,
321328 /// The Decl needs to be analyzed and possibly export itself.
322329 /// It may have already be analyzed, or it may have been determined
323330 /// to be outdated; in this case perform semantic analysis again.
324331 analyze_decl: InternPool.DeclIndex,
332 /// Analyze the body of a runtime function.
333 /// After analysis, a `codegen_func` job will be queued.
334 /// These must be separate jobs to ensure any needed type resolution occurs *before* codegen.
335 analyze_func: InternPool.Index,
325336 /// The source file containing the Decl has been updated, and so the
326337 /// Decl may need its line number information updated in the debug info.
327338 update_line_number: InternPool.DeclIndex,
328339 /// The main source file for the module needs to be analyzed.
329340 analyze_mod: *Package.Module,
341 /// Fully resolve the given `struct` or `union` type.
342 resolve_type_fully: InternPool.Index,
330343
331344 /// one of the glibc static objects
332345 glibc_crt_file: glibc.CRTFile,
......@@ -2628,22 +2641,24 @@ fn reportMultiModuleErrors(mod: *Module) !void {
26282641 for (notes[0..num_notes], file.references.items[0..num_notes], 0..) |*note, ref, i| {
26292642 errdefer for (notes[0..i]) |*n| n.deinit(mod.gpa);
26302643 note.* = switch (ref) {
2631 .import => |loc| blk: {
2632 break :blk try Module.ErrorMsg.init(
2633 mod.gpa,
2634 loc,
2635 "imported from module {s}",
2636 .{loc.file_scope.mod.fully_qualified_name},
2637 );
2638 },
2639 .root => |pkg| blk: {
2640 break :blk try Module.ErrorMsg.init(
2641 mod.gpa,
2642 .{ .file_scope = file, .base_node = 0, .lazy = .entire_file },
2643 "root of module {s}",
2644 .{pkg.fully_qualified_name},
2645 );
2646 },
2644 .import => |import| try Module.ErrorMsg.init(
2645 mod.gpa,
2646 .{
2647 .base_node_inst = try mod.intern_pool.trackZir(mod.gpa, import.file, .main_struct_inst),
2648 .offset = .{ .token_abs = import.token },
2649 },
2650 "imported from module {s}",
2651 .{import.file.mod.fully_qualified_name},
2652 ),
2653 .root => |pkg| try Module.ErrorMsg.init(
2654 mod.gpa,
2655 .{
2656 .base_node_inst = try mod.intern_pool.trackZir(mod.gpa, file, .main_struct_inst),
2657 .offset = .entire_file,
2658 },
2659 "root of module {s}",
2660 .{pkg.fully_qualified_name},
2661 ),
26472662 };
26482663 }
26492664 errdefer for (notes[0..num_notes]) |*n| n.deinit(mod.gpa);
......@@ -2651,7 +2666,10 @@ fn reportMultiModuleErrors(mod: *Module) !void {
26512666 if (omitted > 0) {
26522667 notes[num_notes] = try Module.ErrorMsg.init(
26532668 mod.gpa,
2654 .{ .file_scope = file, .base_node = 0, .lazy = .entire_file },
2669 .{
2670 .base_node_inst = try mod.intern_pool.trackZir(mod.gpa, file, .main_struct_inst),
2671 .offset = .entire_file,
2672 },
26552673 "{} more references omitted",
26562674 .{omitted},
26572675 );
......@@ -2660,7 +2678,10 @@ fn reportMultiModuleErrors(mod: *Module) !void {
26602678
26612679 const err = try Module.ErrorMsg.create(
26622680 mod.gpa,
2663 .{ .file_scope = file, .base_node = 0, .lazy = .entire_file },
2681 .{
2682 .base_node_inst = try mod.intern_pool.trackZir(mod.gpa, file, .main_struct_inst),
2683 .offset = .entire_file,
2684 },
26642685 "file exists in multiple modules",
26652686 .{},
26662687 );
......@@ -2831,11 +2852,11 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
28312852 }
28322853 }
28332854
2834 if (comp.module) |module| {
2835 total += module.failed_exports.count();
2836 total += module.failed_embed_files.count();
2855 if (comp.module) |zcu| {
2856 total += zcu.failed_exports.count();
2857 total += zcu.failed_embed_files.count();
28372858
2838 for (module.failed_files.keys(), module.failed_files.values()) |file, error_msg| {
2859 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
28392860 if (error_msg) |_| {
28402861 total += 1;
28412862 } else {
......@@ -2851,23 +2872,27 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
28512872 // When a parse error is introduced, we keep all the semantic analysis for
28522873 // the previous parse success, including compile errors, but we cannot
28532874 // emit them until the file succeeds parsing.
2854 for (module.failed_decls.keys()) |key| {
2855 if (module.declFileScope(key).okToReportErrors()) {
2875 for (zcu.failed_analysis.keys()) |key| {
2876 const decl_index = switch (key.unwrap()) {
2877 .decl => |d| d,
2878 .func => |ip_index| zcu.funcInfo(ip_index).owner_decl,
2879 };
2880 if (zcu.declFileScope(decl_index).okToReportErrors()) {
28562881 total += 1;
2857 if (module.cimport_errors.get(key)) |errors| {
2882 if (zcu.cimport_errors.get(key)) |errors| {
28582883 total += errors.errorMessageCount();
28592884 }
28602885 }
28612886 }
2862 if (module.emit_h) |emit_h| {
2887 if (zcu.emit_h) |emit_h| {
28632888 for (emit_h.failed_decls.keys()) |key| {
2864 if (module.declFileScope(key).okToReportErrors()) {
2889 if (zcu.declFileScope(key).okToReportErrors()) {
28652890 total += 1;
28662891 }
28672892 }
28682893 }
28692894
2870 if (module.global_error_set.entries.len - 1 > module.error_limit) {
2895 if (zcu.global_error_set.entries.len - 1 > zcu.error_limit) {
28712896 total += 1;
28722897 }
28732898 }
......@@ -2882,8 +2907,8 @@ pub fn totalErrorCount(comp: *Compilation) u32 {
28822907
28832908 // Compile log errors only count if there are no other errors.
28842909 if (total == 0) {
2885 if (comp.module) |module| {
2886 total += @intFromBool(module.compile_log_decls.count() != 0);
2910 if (comp.module) |zcu| {
2911 total += @intFromBool(zcu.compile_log_sources.count() != 0);
28872912 }
28882913 }
28892914
......@@ -2934,10 +2959,13 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
29342959 .msg = try bundle.addString("memory allocation failure"),
29352960 });
29362961 }
2937 if (comp.module) |module| {
2938 for (module.failed_files.keys(), module.failed_files.values()) |file, error_msg| {
2962 if (comp.module) |zcu| {
2963 var all_references = try zcu.resolveReferences();
2964 defer all_references.deinit(gpa);
2965
2966 for (zcu.failed_files.keys(), zcu.failed_files.values()) |file, error_msg| {
29392967 if (error_msg) |msg| {
2940 try addModuleErrorMsg(module, &bundle, msg.*);
2968 try addModuleErrorMsg(zcu, &bundle, msg.*, &all_references);
29412969 } else {
29422970 // Must be ZIR errors. Note that this may include AST errors.
29432971 // addZirErrorMessages asserts that the tree is loaded.
......@@ -2945,54 +2973,59 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
29452973 try addZirErrorMessages(&bundle, file);
29462974 }
29472975 }
2948 for (module.failed_embed_files.values()) |error_msg| {
2949 try addModuleErrorMsg(module, &bundle, error_msg.*);
2976 for (zcu.failed_embed_files.values()) |error_msg| {
2977 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
29502978 }
2951 for (module.failed_decls.keys(), module.failed_decls.values()) |decl_index, error_msg| {
2979 for (zcu.failed_analysis.keys(), zcu.failed_analysis.values()) |anal_unit, error_msg| {
2980 const decl_index = switch (anal_unit.unwrap()) {
2981 .decl => |d| d,
2982 .func => |ip_index| zcu.funcInfo(ip_index).owner_decl,
2983 };
2984
29522985 // Skip errors for Decls within files that had a parse failure.
29532986 // We'll try again once parsing succeeds.
2954 if (module.declFileScope(decl_index).okToReportErrors()) {
2955 try addModuleErrorMsg(module, &bundle, error_msg.*);
2956 if (module.cimport_errors.get(decl_index)) |errors| {
2957 for (errors.getMessages()) |err_msg_index| {
2958 const err_msg = errors.getErrorMessage(err_msg_index);
2959 try bundle.addRootErrorMessage(.{
2960 .msg = try bundle.addString(errors.nullTerminatedString(err_msg.msg)),
2961 .src_loc = if (err_msg.src_loc != .none) blk: {
2962 const src_loc = errors.getSourceLocation(err_msg.src_loc);
2963 break :blk try bundle.addSourceLocation(.{
2964 .src_path = try bundle.addString(errors.nullTerminatedString(src_loc.src_path)),
2965 .span_start = src_loc.span_start,
2966 .span_main = src_loc.span_main,
2967 .span_end = src_loc.span_end,
2968 .line = src_loc.line,
2969 .column = src_loc.column,
2970 .source_line = if (src_loc.source_line != 0) try bundle.addString(errors.nullTerminatedString(src_loc.source_line)) else 0,
2971 });
2972 } else .none,
2973 });
2974 }
2987 if (!zcu.declFileScope(decl_index).okToReportErrors()) continue;
2988
2989 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
2990 if (zcu.cimport_errors.get(anal_unit)) |errors| {
2991 for (errors.getMessages()) |err_msg_index| {
2992 const err_msg = errors.getErrorMessage(err_msg_index);
2993 try bundle.addRootErrorMessage(.{
2994 .msg = try bundle.addString(errors.nullTerminatedString(err_msg.msg)),
2995 .src_loc = if (err_msg.src_loc != .none) blk: {
2996 const src_loc = errors.getSourceLocation(err_msg.src_loc);
2997 break :blk try bundle.addSourceLocation(.{
2998 .src_path = try bundle.addString(errors.nullTerminatedString(src_loc.src_path)),
2999 .span_start = src_loc.span_start,
3000 .span_main = src_loc.span_main,
3001 .span_end = src_loc.span_end,
3002 .line = src_loc.line,
3003 .column = src_loc.column,
3004 .source_line = if (src_loc.source_line != 0) try bundle.addString(errors.nullTerminatedString(src_loc.source_line)) else 0,
3005 });
3006 } else .none,
3007 });
29753008 }
29763009 }
29773010 }
2978 if (module.emit_h) |emit_h| {
3011 if (zcu.emit_h) |emit_h| {
29793012 for (emit_h.failed_decls.keys(), emit_h.failed_decls.values()) |decl_index, error_msg| {
29803013 // Skip errors for Decls within files that had a parse failure.
29813014 // We'll try again once parsing succeeds.
2982 if (module.declFileScope(decl_index).okToReportErrors()) {
2983 try addModuleErrorMsg(module, &bundle, error_msg.*);
3015 if (zcu.declFileScope(decl_index).okToReportErrors()) {
3016 try addModuleErrorMsg(zcu, &bundle, error_msg.*, &all_references);
29843017 }
29853018 }
29863019 }
2987 for (module.failed_exports.values()) |value| {
2988 try addModuleErrorMsg(module, &bundle, value.*);
3020 for (zcu.failed_exports.values()) |value| {
3021 try addModuleErrorMsg(zcu, &bundle, value.*, &all_references);
29893022 }
29903023
2991 const actual_error_count = module.global_error_set.entries.len - 1;
2992 if (actual_error_count > module.error_limit) {
3024 const actual_error_count = zcu.global_error_set.entries.len - 1;
3025 if (actual_error_count > zcu.error_limit) {
29933026 try bundle.addRootErrorMessage(.{
2994 .msg = try bundle.printString("module used more errors than possible: used {d}, max {d}", .{
2995 actual_error_count, module.error_limit,
3027 .msg = try bundle.printString("ZCU used more errors than possible: used {d}, max {d}", .{
3028 actual_error_count, zcu.error_limit,
29963029 }),
29973030 .notes_len = 1,
29983031 });
......@@ -3041,25 +3074,28 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
30413074 }
30423075
30433076 if (comp.module) |zcu| {
3044 if (bundle.root_list.items.len == 0 and zcu.compile_log_decls.count() != 0) {
3045 const values = zcu.compile_log_decls.values();
3077 if (bundle.root_list.items.len == 0 and zcu.compile_log_sources.count() != 0) {
3078 var all_references = try zcu.resolveReferences();
3079 defer all_references.deinit(gpa);
3080
3081 const values = zcu.compile_log_sources.values();
30463082 // First one will be the error; subsequent ones will be notes.
3047 const src_loc = values[0].src().upgrade(zcu);
3083 const src_loc = values[0].src();
30483084 const err_msg: Module.ErrorMsg = .{
30493085 .src_loc = src_loc,
30503086 .msg = "found compile log statement",
3051 .notes = try gpa.alloc(Module.ErrorMsg, zcu.compile_log_decls.count() - 1),
3087 .notes = try gpa.alloc(Module.ErrorMsg, zcu.compile_log_sources.count() - 1),
30523088 };
30533089 defer gpa.free(err_msg.notes);
30543090
30553091 for (values[1..], err_msg.notes) |src_info, *note| {
30563092 note.* = .{
3057 .src_loc = src_info.src().upgrade(zcu),
3093 .src_loc = src_info.src(),
30583094 .msg = "also here",
30593095 };
30603096 }
30613097
3062 try addModuleErrorMsg(zcu, &bundle, err_msg);
3098 try addModuleErrorMsg(zcu, &bundle, err_msg, &all_references);
30633099 }
30643100 }
30653101
......@@ -3115,11 +3151,17 @@ pub const ErrorNoteHashContext = struct {
31153151 }
31163152};
31173153
3118pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Module.ErrorMsg) !void {
3154pub fn addModuleErrorMsg(
3155 mod: *Module,
3156 eb: *ErrorBundle.Wip,
3157 module_err_msg: Module.ErrorMsg,
3158 all_references: *const std.AutoHashMapUnmanaged(InternPool.AnalUnit, Zcu.ResolvedReference),
3159) !void {
31193160 const gpa = eb.gpa;
31203161 const ip = &mod.intern_pool;
3121 const err_source = module_err_msg.src_loc.file_scope.getSource(gpa) catch |err| {
3122 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
3162 const err_src_loc = module_err_msg.src_loc.upgrade(mod);
3163 const err_source = err_src_loc.file_scope.getSource(gpa) catch |err| {
3164 const file_path = try err_src_loc.file_scope.fullPath(gpa);
31233165 defer gpa.free(file_path);
31243166 try eb.addRootErrorMessage(.{
31253167 .msg = try eb.printString("unable to load '{s}': {s}", .{
......@@ -3128,47 +3170,57 @@ pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Mod
31283170 });
31293171 return;
31303172 };
3131 const err_span = try module_err_msg.src_loc.span(gpa);
3173 const err_span = try err_src_loc.span(gpa);
31323174 const err_loc = std.zig.findLineColumn(err_source.bytes, err_span.main);
3133 const file_path = try module_err_msg.src_loc.file_scope.fullPath(gpa);
3175 const file_path = try err_src_loc.file_scope.fullPath(gpa);
31343176 defer gpa.free(file_path);
31353177
31363178 var ref_traces: std.ArrayListUnmanaged(ErrorBundle.ReferenceTrace) = .{};
31373179 defer ref_traces.deinit(gpa);
31383180
3139 const remaining_references: ?u32 = remaining: {
3140 if (mod.comp.reference_trace) |_| {
3141 if (module_err_msg.hidden_references > 0) break :remaining module_err_msg.hidden_references;
3142 } else {
3143 if (module_err_msg.reference_trace.len > 0) break :remaining 0;
3181 if (module_err_msg.reference_trace_root.unwrap()) |rt_root| {
3182 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .{};
3183 defer seen.deinit(gpa);
3184
3185 const max_references = mod.comp.reference_trace orelse Sema.default_reference_trace_len;
3186
3187 var referenced_by = rt_root;
3188 while (all_references.get(referenced_by)) |ref| {
3189 const gop = try seen.getOrPut(gpa, ref.referencer);
3190 if (gop.found_existing) break;
3191 if (ref_traces.items.len < max_references) {
3192 const src = ref.src.upgrade(mod);
3193 const source = try src.file_scope.getSource(gpa);
3194 const span = try src.span(gpa);
3195 const loc = std.zig.findLineColumn(source.bytes, span.main);
3196 const rt_file_path = try src.file_scope.fullPath(gpa);
3197 const name = switch (ref.referencer.unwrap()) {
3198 .decl => |d| mod.declPtr(d).name,
3199 .func => |f| mod.funcOwnerDeclPtr(f).name,
3200 };
3201 try ref_traces.append(gpa, .{
3202 .decl_name = try eb.addString(name.toSlice(ip)),
3203 .src_loc = try eb.addSourceLocation(.{
3204 .src_path = try eb.addString(rt_file_path),
3205 .span_start = span.start,
3206 .span_main = span.main,
3207 .span_end = span.end,
3208 .line = @intCast(loc.line),
3209 .column = @intCast(loc.column),
3210 .source_line = 0,
3211 }),
3212 });
3213 }
3214 referenced_by = ref.referencer;
31443215 }
3145 break :remaining null;
3146 };
3147 try ref_traces.ensureTotalCapacityPrecise(gpa, module_err_msg.reference_trace.len +
3148 @intFromBool(remaining_references != null));
31493216
3150 for (module_err_msg.reference_trace) |module_reference| {
3151 const source = try module_reference.src_loc.file_scope.getSource(gpa);
3152 const span = try module_reference.src_loc.span(gpa);
3153 const loc = std.zig.findLineColumn(source.bytes, span.main);
3154 const rt_file_path = try module_reference.src_loc.file_scope.fullPath(gpa);
3155 defer gpa.free(rt_file_path);
3156 ref_traces.appendAssumeCapacity(.{
3157 .decl_name = try eb.addString(module_reference.decl.toSlice(ip)),
3158 .src_loc = try eb.addSourceLocation(.{
3159 .src_path = try eb.addString(rt_file_path),
3160 .span_start = span.start,
3161 .span_main = span.main,
3162 .span_end = span.end,
3163 .line = @intCast(loc.line),
3164 .column = @intCast(loc.column),
3165 .source_line = 0,
3166 }),
3167 });
3217 if (seen.count() > ref_traces.items.len) {
3218 try ref_traces.append(gpa, .{
3219 .decl_name = @intCast(seen.count() - ref_traces.items.len),
3220 .src_loc = .none,
3221 });
3222 }
31683223 }
3169 if (remaining_references) |remaining| ref_traces.appendAssumeCapacity(
3170 .{ .decl_name = remaining, .src_loc = .none },
3171 );
31723224
31733225 const src_loc = try eb.addSourceLocation(.{
31743226 .src_path = try eb.addString(file_path),
......@@ -3177,7 +3229,7 @@ pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Mod
31773229 .span_end = err_span.end,
31783230 .line = @intCast(err_loc.line),
31793231 .column = @intCast(err_loc.column),
3180 .source_line = if (module_err_msg.src_loc.lazy == .entire_file)
3232 .source_line = if (err_src_loc.lazy == .entire_file)
31813233 0
31823234 else
31833235 try eb.addString(err_loc.source_line),
......@@ -3194,10 +3246,11 @@ pub fn addModuleErrorMsg(mod: *Module, eb: *ErrorBundle.Wip, module_err_msg: Mod
31943246 defer notes.deinit(gpa);
31953247
31963248 for (module_err_msg.notes) |module_note| {
3197 const source = try module_note.src_loc.file_scope.getSource(gpa);
3198 const span = try module_note.src_loc.span(gpa);
3249 const note_src_loc = module_note.src_loc.upgrade(mod);
3250 const source = try note_src_loc.file_scope.getSource(gpa);
3251 const span = try note_src_loc.span(gpa);
31993252 const loc = std.zig.findLineColumn(source.bytes, span.main);
3200 const note_file_path = try module_note.src_loc.file_scope.fullPath(gpa);
3253 const note_file_path = try note_src_loc.file_scope.fullPath(gpa);
32013254 defer gpa.free(note_file_path);
32023255
32033256 const gop = try notes.getOrPutContext(gpa, .{
......@@ -3348,7 +3401,7 @@ pub fn performAllTheWork(
33483401 if (try zcu.findOutdatedToAnalyze()) |outdated| {
33493402 switch (outdated.unwrap()) {
33503403 .decl => |decl| try comp.work_queue.writeItem(.{ .analyze_decl = decl }),
3351 .func => |func| try comp.work_queue.writeItem(.{ .codegen_func = func }),
3404 .func => |func| try comp.work_queue.writeItem(.{ .analyze_func = func }),
33523405 }
33533406 continue;
33543407 }
......@@ -3398,6 +3451,14 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
33983451 const named_frame = tracy.namedFrame("codegen_func");
33993452 defer named_frame.end();
34003453
3454 const module = comp.module.?;
3455 // This call takes ownership of `func.air`.
3456 try module.linkerUpdateFunc(func.func, func.air);
3457 },
3458 .analyze_func => |func| {
3459 const named_frame = tracy.namedFrame("analyze_func");
3460 defer named_frame.end();
3461
34013462 const module = comp.module.?;
34023463 module.ensureFuncBodyAnalyzed(func) catch |err| switch (err) {
34033464 error.OutOfMemory => return error.OutOfMemory,
......@@ -3405,6 +3466,9 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
34053466 };
34063467 },
34073468 .emit_h_decl => |decl_index| {
3469 if (true) @panic("regressed compiler feature: emit-h should hook into updateExports, " ++
3470 "not decl analysis, which is too early to know about @export calls");
3471
34083472 const module = comp.module.?;
34093473 const decl = module.declPtr(decl_index);
34103474
......@@ -3477,6 +3541,16 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
34773541 try module.ensureFuncBodyAnalysisQueued(decl.val.toIntern());
34783542 }
34793543 },
3544 .resolve_type_fully => |ty| {
3545 const named_frame = tracy.namedFrame("resolve_type_fully");
3546 defer named_frame.end();
3547
3548 const zcu = comp.module.?;
3549 Type.fromInterned(ty).resolveFully(zcu) catch |err| switch (err) {
3550 error.OutOfMemory => return error.OutOfMemory,
3551 error.AnalysisFail => return,
3552 };
3553 },
34803554 .update_line_number => |decl_index| {
34813555 const named_frame = tracy.namedFrame("update_line_number");
34823556 defer named_frame.end();
......@@ -3486,15 +3560,18 @@ fn processOneJob(comp: *Compilation, job: Job, prog_node: std.Progress.Node) !vo
34863560 const decl = module.declPtr(decl_index);
34873561 const lf = comp.bin_file.?;
34883562 lf.updateDeclLineNumber(module, decl_index) catch |err| {
3489 try module.failed_decls.ensureUnusedCapacity(gpa, 1);
3490 module.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
3491 gpa,
3492 decl.navSrcLoc(module).upgrade(module),
3493 "unable to update line number: {s}",
3494 .{@errorName(err)},
3495 ));
3563 try module.failed_analysis.ensureUnusedCapacity(gpa, 1);
3564 module.failed_analysis.putAssumeCapacityNoClobber(
3565 InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
3566 try Module.ErrorMsg.create(
3567 gpa,
3568 decl.navSrcLoc(module),
3569 "unable to update line number: {s}",
3570 .{@errorName(err)},
3571 ),
3572 );
34963573 decl.analysis = .codegen_failure;
3497 try module.retryable_failures.append(gpa, InternPool.AnalSubject.wrap(.{ .decl = decl_index }));
3574 try module.retryable_failures.append(gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }));
34983575 };
34993576 },
35003577 .analyze_mod => |pkg| {
......@@ -3989,9 +4066,8 @@ fn workerAstGenFile(
39894066 const res = mod.importFile(file, import_path) catch continue;
39904067 if (!res.is_pkg) {
39914068 res.file.addReference(mod.*, .{ .import = .{
3992 .file_scope = file,
3993 .base_node = 0,
3994 .lazy = .{ .token_abs = item.data.token },
4069 .file = file,
4070 .token = item.data.token,
39954071 } }) catch continue;
39964072 }
39974073 break :blk res;
......@@ -4364,20 +4440,14 @@ fn reportRetryableAstGenError(
43644440
43654441 file.status = .retryable_failure;
43664442
4367 const src_loc: Module.SrcLoc = switch (src) {
4443 const src_loc: Module.LazySrcLoc = switch (src) {
43684444 .root => .{
4369 .file_scope = file,
4370 .base_node = 0,
4371 .lazy = .entire_file,
4445 .base_node_inst = try mod.intern_pool.trackZir(gpa, file, .main_struct_inst),
4446 .offset = .entire_file,
43724447 },
4373 .import => |info| blk: {
4374 const importing_file = info.importing_file;
4375
4376 break :blk .{
4377 .file_scope = importing_file,
4378 .base_node = 0,
4379 .lazy = .{ .token_abs = info.import_tok },
4380 };
4448 .import => |info| .{
4449 .base_node_inst = try mod.intern_pool.trackZir(gpa, info.importing_file, .main_struct_inst),
4450 .offset = .{ .token_abs = info.import_tok },
43814451 },
43824452 };
43834453
src/InternPool.zig+11-11
......@@ -81,7 +81,7 @@ namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.In
8181/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
8282/// matches. The `next_dependee` field can be used to iterate all such entries
8383/// and remove them from the corresponding lists.
84first_dependency: std.AutoArrayHashMapUnmanaged(AnalSubject, DepEntry.Index) = .{},
84first_dependency: std.AutoArrayHashMapUnmanaged(AnalUnit, DepEntry.Index) = .{},
8585
8686/// Stores dependency information. The hashmaps declared above are used to look
8787/// up entries in this list as required. This is not stored in `extra` so that
......@@ -132,36 +132,36 @@ pub fn trackZir(ip: *InternPool, gpa: Allocator, file: *Module.File, inst: Zir.I
132132 return @enumFromInt(gop.index);
133133}
134134
135/// Analysis Subject. Represents a single entity which undergoes semantic analysis.
135/// Analysis Unit. Represents a single entity which undergoes semantic analysis.
136136/// This is either a `Decl` (in future `Cau`) or a runtime function.
137137/// The LSB is used as a tag bit.
138138/// This is the "source" of an incremental dependency edge.
139pub const AnalSubject = packed struct(u32) {
139pub const AnalUnit = packed struct(u32) {
140140 kind: enum(u1) { decl, func },
141141 index: u31,
142142 pub const Unwrapped = union(enum) {
143143 decl: DeclIndex,
144144 func: InternPool.Index,
145145 };
146 pub fn unwrap(as: AnalSubject) Unwrapped {
146 pub fn unwrap(as: AnalUnit) Unwrapped {
147147 return switch (as.kind) {
148148 .decl => .{ .decl = @enumFromInt(as.index) },
149149 .func => .{ .func = @enumFromInt(as.index) },
150150 };
151151 }
152 pub fn wrap(raw: Unwrapped) AnalSubject {
152 pub fn wrap(raw: Unwrapped) AnalUnit {
153153 return switch (raw) {
154154 .decl => |decl| .{ .kind = .decl, .index = @intCast(@intFromEnum(decl)) },
155155 .func => |func| .{ .kind = .func, .index = @intCast(@intFromEnum(func)) },
156156 };
157157 }
158 pub fn toOptional(as: AnalSubject) Optional {
158 pub fn toOptional(as: AnalUnit) Optional {
159159 return @enumFromInt(@as(u32, @bitCast(as)));
160160 }
161161 pub const Optional = enum(u32) {
162162 none = std.math.maxInt(u32),
163163 _,
164 pub fn unwrap(opt: Optional) ?AnalSubject {
164 pub fn unwrap(opt: Optional) ?AnalUnit {
165165 return switch (opt) {
166166 .none => null,
167167 _ => @bitCast(@intFromEnum(opt)),
......@@ -178,7 +178,7 @@ pub const Dependee = union(enum) {
178178 namespace_name: NamespaceNameKey,
179179};
180180
181pub fn removeDependenciesForDepender(ip: *InternPool, gpa: Allocator, depender: AnalSubject) void {
181pub fn removeDependenciesForDepender(ip: *InternPool, gpa: Allocator, depender: AnalUnit) void {
182182 var opt_idx = (ip.first_dependency.fetchSwapRemove(depender) orelse return).value.toOptional();
183183
184184 while (opt_idx.unwrap()) |idx| {
......@@ -207,7 +207,7 @@ pub fn removeDependenciesForDepender(ip: *InternPool, gpa: Allocator, depender:
207207pub const DependencyIterator = struct {
208208 ip: *const InternPool,
209209 next_entry: DepEntry.Index.Optional,
210 pub fn next(it: *DependencyIterator) ?AnalSubject {
210 pub fn next(it: *DependencyIterator) ?AnalUnit {
211211 const idx = it.next_entry.unwrap() orelse return null;
212212 const entry = it.ip.dep_entries.items[@intFromEnum(idx)];
213213 it.next_entry = entry.next;
......@@ -236,7 +236,7 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
236236 };
237237}
238238
239pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalSubject, dependee: Dependee) Allocator.Error!void {
239pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, dependee: Dependee) Allocator.Error!void {
240240 const first_depender_dep: DepEntry.Index.Optional = if (ip.first_dependency.get(depender)) |idx| dep: {
241241 // The entry already exists, so there is capacity to overwrite it later.
242242 break :dep idx.toOptional();
......@@ -300,7 +300,7 @@ pub const DepEntry = extern struct {
300300 /// the first and only entry in one of `intern_pool.*_deps`, and does not
301301 /// appear in any list by `first_dependency`, but is not in
302302 /// `free_dep_entries` since `*_deps` stores a reference to it.
303 depender: AnalSubject.Optional,
303 depender: AnalUnit.Optional,
304304 /// Index into `dep_entries` forming a doubly linked list of all dependencies on this dependee.
305305 /// Used to iterate all dependers for a given dependee during an update.
306306 /// null if this is the end of the list.
src/RangeSet.zig+1-1
......@@ -3,7 +3,7 @@ const assert = std.debug.assert;
33const Order = std.math.Order;
44
55const InternPool = @import("InternPool.zig");
6const Type = @import("type.zig").Type;
6const Type = @import("Type.zig");
77const Value = @import("Value.zig");
88const Zcu = @import("Zcu.zig");
99/// Deprecated.
src/Sema.zig+591-1178
......@@ -64,14 +64,6 @@ generic_owner: InternPool.Index = .none,
6464/// instantiation can point back to the instantiation site in addition to the
6565/// declaration site.
6666generic_call_src: LazySrcLoc = LazySrcLoc.unneeded,
67/// The key is types that must be fully resolved prior to machine code
68/// generation pass. Types are added to this set when resolving them
69/// immediately could cause a dependency loop, but they do need to be resolved
70/// before machine code generation passes process the AIR.
71/// It would work fine if this were an array list instead of an array hash map.
72/// I chose array hash map with the intention to save time by omitting
73/// duplicates.
74types_to_resolve: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
7567/// These are lazily created runtime blocks from block_inline instructions.
7668/// They are created when an break_inline passes through a runtime condition, because
7769/// Sema must convert comptime control flow to runtime control flow, which means
......@@ -117,6 +109,15 @@ maybe_comptime_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, MaybeComptimeAll
117109/// Backed by gpa.
118110comptime_allocs: std.ArrayListUnmanaged(ComptimeAlloc) = .{},
119111
112/// A list of exports performed by this analysis. After this `Sema` terminates,
113/// these are flushed to `Zcu.single_exports` or `Zcu.multi_exports`.
114exports: std.ArrayListUnmanaged(Zcu.Export) = .{},
115
116/// All references registered so far by this `Sema`. This is a temporary duplicate
117/// of data stored in `Zcu.all_references`. It exists to avoid adding references to
118/// a given `AnalUnit` multiple times.
119references: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
120
120121const MaybeComptimeAlloc = struct {
121122 /// The runtime index of the `alloc` instruction.
122123 runtime_index: Value.RuntimeIndex,
......@@ -167,7 +168,7 @@ const log = std.log.scoped(.sema);
167168const Sema = @This();
168169const Value = @import("Value.zig");
169170const MutableValue = @import("mutable_value.zig").MutableValue;
170const Type = @import("type.zig").Type;
171const Type = @import("Type.zig");
171172const Air = @import("Air.zig");
172173const Zir = std.zig.Zir;
173174const Zcu = @import("Zcu.zig");
......@@ -186,6 +187,7 @@ const build_options = @import("build_options");
186187const Compilation = @import("Compilation.zig");
187188const InternPool = @import("InternPool.zig");
188189const Alignment = InternPool.Alignment;
190const AnalUnit = InternPool.AnalUnit;
189191const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
190192
191193pub const default_branch_quota = 1000;
......@@ -862,7 +864,6 @@ pub fn deinit(sema: *Sema) void {
862864 sema.air_extra.deinit(gpa);
863865 sema.inst_map.deinit(gpa);
864866 sema.decl_val_table.deinit(gpa);
865 sema.types_to_resolve.deinit(gpa);
866867 {
867868 var it = sema.post_hoc_blocks.iterator();
868869 while (it.next()) |entry| {
......@@ -875,6 +876,8 @@ pub fn deinit(sema: *Sema) void {
875876 sema.base_allocs.deinit(gpa);
876877 sema.maybe_comptime_allocs.deinit(gpa);
877878 sema.comptime_allocs.deinit(gpa);
879 sema.exports.deinit(gpa);
880 sema.references.deinit(gpa);
878881 sema.* = undefined;
879882}
880883
......@@ -2067,8 +2070,8 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
20672070 const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty));
20682071
20692072 // var st: StackTrace = undefined;
2070 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
2071 try sema.resolveTypeFields(stack_trace_ty);
2073 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
2074 try stack_trace_ty.resolveFields(mod);
20722075 const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty));
20732076
20742077 // st.instruction_addresses = &addrs;
......@@ -2414,8 +2417,7 @@ pub fn errNote(
24142417 comptime format: []const u8,
24152418 args: anytype,
24162419) error{OutOfMemory}!void {
2417 const zcu = sema.mod;
2418 return zcu.errNoteNonLazy(src.upgrade(zcu), parent, format, args);
2420 return sema.mod.errNote(src, parent, format, args);
24192421}
24202422
24212423fn addFieldErrNote(
......@@ -2443,7 +2445,7 @@ pub fn errMsg(
24432445 args: anytype,
24442446) Allocator.Error!*Module.ErrorMsg {
24452447 assert(src.offset != .unneeded);
2446 return Module.ErrorMsg.create(sema.gpa, src.upgrade(sema.mod), format, args);
2448 return Module.ErrorMsg.create(sema.gpa, src, format, args);
24472449}
24482450
24492451pub fn fail(
......@@ -2466,87 +2468,57 @@ pub fn failWithOwnedErrorMsg(sema: *Sema, block: ?*Block, err_msg: *Module.Error
24662468 @setCold(true);
24672469 const gpa = sema.gpa;
24682470 const mod = sema.mod;
2471 const ip = &mod.intern_pool;
24692472
2470 ref: {
2471 errdefer err_msg.destroy(gpa);
2473 if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) {
2474 var all_references = mod.resolveReferences() catch @panic("out of memory");
2475 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
2476 wip_errors.init(gpa) catch @panic("out of memory");
2477 Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*, &all_references) catch unreachable;
2478 std.debug.print("compile error during Sema:\n", .{});
2479 var error_bundle = wip_errors.toOwnedBundle("") catch unreachable;
2480 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
2481 crash_report.compilerPanic("unexpected compile error occurred", null, null);
2482 }
24722483
2473 if (build_options.enable_debug_extensions and mod.comp.debug_compile_errors) {
2474 var wip_errors: std.zig.ErrorBundle.Wip = undefined;
2475 wip_errors.init(gpa) catch unreachable;
2476 Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*) catch unreachable;
2477 std.debug.print("compile error during Sema:\n", .{});
2478 var error_bundle = wip_errors.toOwnedBundle("") catch unreachable;
2479 error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
2480 crash_report.compilerPanic("unexpected compile error occurred", null, null);
2484 if (block) |start_block| {
2485 var block_it = start_block;
2486 while (block_it.inlining) |inlining| {
2487 try sema.errNote(
2488 inlining.call_src,
2489 err_msg,
2490 "called from here",
2491 .{},
2492 );
2493 block_it = inlining.call_block;
24812494 }
2495 }
24822496
2483 try mod.failed_decls.ensureUnusedCapacity(gpa, 1);
2484 try mod.failed_files.ensureUnusedCapacity(gpa, 1);
2485
2486 if (block) |start_block| {
2487 var block_it = start_block;
2488 while (block_it.inlining) |inlining| {
2489 try sema.errNote(
2490 inlining.call_src,
2491 err_msg,
2492 "called from here",
2493 .{},
2494 );
2495 block_it = inlining.call_block;
2496 }
2497
2498 const max_references = refs: {
2499 if (mod.comp.reference_trace) |num| break :refs num;
2500 // Do not add multiple traces without explicit request.
2501 if (mod.failed_decls.count() > 0) break :ref;
2502 break :refs default_reference_trace_len;
2503 };
2497 const use_ref_trace = if (mod.comp.reference_trace) |n| n > 0 else mod.failed_analysis.count() == 0;
2498 if (use_ref_trace) {
2499 err_msg.reference_trace_root = sema.ownerUnit().toOptional();
2500 }
25042501
2505 var referenced_by = if (sema.owner_func_index != .none)
2506 mod.funcOwnerDeclIndex(sema.owner_func_index)
2507 else
2508 sema.owner_decl_index;
2509 var reference_stack = std.ArrayList(Module.ErrorMsg.Trace).init(gpa);
2510 defer reference_stack.deinit();
2511
2512 // Avoid infinite loops.
2513 var seen = std.AutoHashMap(InternPool.DeclIndex, void).init(gpa);
2514 defer seen.deinit();
2515
2516 while (mod.reference_table.get(referenced_by)) |ref| {
2517 const gop = try seen.getOrPut(ref.referencer);
2518 if (gop.found_existing) break;
2519 if (reference_stack.items.len < max_references) {
2520 const decl = mod.declPtr(ref.referencer);
2521 try reference_stack.append(.{
2522 .decl = decl.name,
2523 .src_loc = ref.src.upgrade(mod),
2524 });
2525 }
2526 referenced_by = ref.referencer;
2527 }
2528 err_msg.reference_trace = try reference_stack.toOwnedSlice();
2529 err_msg.hidden_references = @intCast(seen.count() -| max_references);
2530 }
2502 const gop = try mod.failed_analysis.getOrPut(gpa, sema.ownerUnit());
2503 if (gop.found_existing) {
2504 // If there are multiple errors for the same Decl, prefer the first one added.
2505 sema.err = null;
2506 err_msg.destroy(gpa);
2507 } else {
2508 sema.err = err_msg;
2509 gop.value_ptr.* = err_msg;
25312510 }
2532 const ip = &mod.intern_pool;
2511
25332512 if (sema.owner_func_index != .none) {
25342513 ip.funcAnalysis(sema.owner_func_index).state = .sema_failure;
25352514 } else {
25362515 sema.owner_decl.analysis = .sema_failure;
25372516 }
2517
25382518 if (sema.func_index != .none) {
25392519 ip.funcAnalysis(sema.func_index).state = .sema_failure;
25402520 }
2541 const gop = mod.failed_decls.getOrPutAssumeCapacity(sema.owner_decl_index);
2542 if (gop.found_existing) {
2543 // If there are multiple errors for the same Decl, prefer the first one added.
2544 sema.err = null;
2545 err_msg.destroy(gpa);
2546 } else {
2547 sema.err = err_msg;
2548 gop.value_ptr.* = err_msg;
2549 }
2521
25502522 return error.AnalysisFail;
25512523}
25522524
......@@ -2561,7 +2533,6 @@ fn reparentOwnedErrorMsg(
25612533 args: anytype,
25622534) !void {
25632535 const mod = sema.mod;
2564 const resolved_src = src.upgrade(mod);
25652536 const msg_str = try std.fmt.allocPrint(mod.gpa, format, args);
25662537
25672538 const orig_notes = msg.notes.len;
......@@ -2572,7 +2543,7 @@ fn reparentOwnedErrorMsg(
25722543 .msg = msg.msg,
25732544 };
25742545
2575 msg.src_loc = resolved_src;
2546 msg.src_loc = src;
25762547 msg.msg = msg_str;
25772548}
25782549
......@@ -2649,7 +2620,7 @@ fn analyzeAsInt(
26492620 const mod = sema.mod;
26502621 const coerced = try sema.coerce(block, dest_ty, air_ref, src);
26512622 const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
2652 return (try val.getUnsignedIntAdvanced(mod, sema)).?;
2623 return (try val.getUnsignedIntAdvanced(mod, .sema)).?;
26532624}
26542625
26552626/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
......@@ -2735,12 +2706,12 @@ fn maybeRemoveOutdatedType(sema: *Sema, ty: InternPool.Index) !bool {
27352706 if (!zcu.comp.debug_incremental) return false;
27362707
27372708 const decl_index = Type.fromInterned(ty).getOwnerDecl(zcu);
2738 const decl_as_depender = InternPool.AnalSubject.wrap(.{ .decl = decl_index });
2709 const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
27392710 const was_outdated = zcu.outdated.swapRemove(decl_as_depender) or
27402711 zcu.potentially_outdated.swapRemove(decl_as_depender);
27412712 if (!was_outdated) return false;
27422713 _ = zcu.outdated_ready.swapRemove(decl_as_depender);
2743 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalSubject.wrap(.{ .decl = decl_index }));
2714 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
27442715 zcu.intern_pool.remove(ty);
27452716 zcu.declPtr(decl_index).analysis = .dependency_failure;
27462717 try zcu.markDependeeOutdated(.{ .decl_val = decl_index });
......@@ -2834,7 +2805,7 @@ fn zirStructDecl(
28342805 if (sema.mod.comp.debug_incremental) {
28352806 try ip.addDependency(
28362807 sema.gpa,
2837 InternPool.AnalSubject.wrap(.{ .decl = new_decl_index }),
2808 AnalUnit.wrap(.{ .decl = new_decl_index }),
28382809 .{ .src_hash = try ip.trackZir(sema.gpa, block.getFileScope(mod), inst) },
28392810 );
28402811 }
......@@ -2853,6 +2824,8 @@ fn zirStructDecl(
28532824 }
28542825
28552826 try mod.finalizeAnonDecl(new_decl_index);
2827 try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index });
2828 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index }));
28562829 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
28572830}
28582831
......@@ -3068,7 +3041,7 @@ fn zirEnumDecl(
30683041 if (sema.mod.comp.debug_incremental) {
30693042 try mod.intern_pool.addDependency(
30703043 sema.gpa,
3071 InternPool.AnalSubject.wrap(.{ .decl = new_decl_index }),
3044 AnalUnit.wrap(.{ .decl = new_decl_index }),
30723045 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
30733046 );
30743047 }
......@@ -3334,7 +3307,7 @@ fn zirUnionDecl(
33343307 if (sema.mod.comp.debug_incremental) {
33353308 try mod.intern_pool.addDependency(
33363309 sema.gpa,
3337 InternPool.AnalSubject.wrap(.{ .decl = new_decl_index }),
3310 AnalUnit.wrap(.{ .decl = new_decl_index }),
33383311 .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
33393312 );
33403313 }
......@@ -3353,7 +3326,8 @@ fn zirUnionDecl(
33533326 }
33543327
33553328 try mod.finalizeAnonDecl(new_decl_index);
3356
3329 try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index });
3330 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index }));
33573331 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
33583332}
33593333
......@@ -3422,7 +3396,7 @@ fn zirOpaqueDecl(
34223396 if (sema.mod.comp.debug_incremental) {
34233397 try ip.addDependency(
34243398 gpa,
3425 InternPool.AnalSubject.wrap(.{ .decl = new_decl_index }),
3399 AnalUnit.wrap(.{ .decl = new_decl_index }),
34263400 .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
34273401 );
34283402 }
......@@ -3478,12 +3452,12 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
34783452 defer tracy.end();
34793453
34803454 if (block.is_comptime or try sema.typeRequiresComptime(sema.fn_ret_ty)) {
3481 try sema.resolveTypeFields(sema.fn_ret_ty);
3455 try sema.fn_ret_ty.resolveFields(sema.mod);
34823456 return sema.analyzeComptimeAlloc(block, sema.fn_ret_ty, .none);
34833457 }
34843458
34853459 const target = sema.mod.getTarget();
3486 const ptr_type = try sema.ptrType(.{
3460 const ptr_type = try sema.mod.ptrTypeSema(.{
34873461 .child = sema.fn_ret_ty.toIntern(),
34883462 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
34893463 });
......@@ -3492,7 +3466,6 @@ fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
34923466 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr.
34933467 // TODO when functions gain result location support, the inlining struct in
34943468 // Block should contain the return pointer, and we would pass that through here.
3495 try sema.queueFullTypeResolution(sema.fn_ret_ty);
34963469 return block.addTy(.alloc, ptr_type);
34973470 }
34983471
......@@ -3688,8 +3661,8 @@ fn zirAllocExtended(
36883661 try sema.validateVarType(block, ty_src, var_ty, false);
36893662 }
36903663 const target = sema.mod.getTarget();
3691 try sema.resolveTypeLayout(var_ty);
3692 const ptr_type = try sema.ptrType(.{
3664 try var_ty.resolveLayout(sema.mod);
3665 const ptr_type = try sema.mod.ptrTypeSema(.{
36933666 .child = var_ty.toIntern(),
36943667 .flags = .{
36953668 .alignment = alignment,
......@@ -3923,7 +3896,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
39233896 const idx_val = (try sema.resolveValue(data.rhs)).?;
39243897 break :blk .{
39253898 data.lhs,
3926 .{ .elem = try idx_val.toUnsignedIntAdvanced(sema) },
3899 .{ .elem = try idx_val.toUnsignedIntSema(zcu) },
39273900 };
39283901 },
39293902 .bitcast => .{
......@@ -3961,7 +3934,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
39613934 .val = payload_val.toIntern(),
39623935 } });
39633936 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(opt_val), opt_ty);
3964 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(sema)).toIntern();
3937 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(zcu)).toIntern();
39653938 },
39663939 .eu_payload => ptr: {
39673940 // Set the error union to non-error at comptime.
......@@ -3974,7 +3947,7 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
39743947 .val = .{ .payload = payload_val.toIntern() },
39753948 } });
39763949 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(eu_val), eu_ty);
3977 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrEuPayload(sema)).toIntern();
3950 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrEuPayload(zcu)).toIntern();
39783951 },
39793952 .field => |idx| ptr: {
39803953 const maybe_union_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu);
......@@ -3988,9 +3961,9 @@ fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref,
39883961 const store_val = try zcu.unionValue(maybe_union_ty, tag_val, payload_val);
39893962 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), store_val, maybe_union_ty);
39903963 }
3991 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, sema)).toIntern();
3964 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, zcu)).toIntern();
39923965 },
3993 .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, sema)).toIntern(),
3966 .elem => |idx| (try Value.fromInterned(decl_parent_ptr).ptrElem(idx, zcu)).toIntern(),
39943967 };
39953968 try ptr_mapping.put(air_ptr, new_ptr);
39963969 }
......@@ -4081,7 +4054,7 @@ fn finishResolveComptimeKnownAllocPtr(
40814054fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type {
40824055 var ptr_info = ptr_ty.ptrInfo(sema.mod);
40834056 ptr_info.flags.is_const = true;
4084 return sema.ptrType(ptr_info);
4057 return sema.mod.ptrTypeSema(ptr_info);
40854058}
40864059
40874060fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref {
......@@ -4124,11 +4097,10 @@ fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
41244097 return sema.analyzeComptimeAlloc(block, var_ty, .none);
41254098 }
41264099 const target = sema.mod.getTarget();
4127 const ptr_type = try sema.ptrType(.{
4100 const ptr_type = try sema.mod.ptrTypeSema(.{
41284101 .child = var_ty.toIntern(),
41294102 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
41304103 });
4131 try sema.queueFullTypeResolution(var_ty);
41324104 const ptr = try block.addTy(.alloc, ptr_type);
41334105 const ptr_inst = ptr.toIndex().?;
41344106 try sema.maybe_comptime_allocs.put(sema.gpa, ptr_inst, .{ .runtime_index = block.runtime_index });
......@@ -4148,11 +4120,10 @@ fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
41484120 }
41494121 try sema.validateVarType(block, ty_src, var_ty, false);
41504122 const target = sema.mod.getTarget();
4151 const ptr_type = try sema.ptrType(.{
4123 const ptr_type = try sema.mod.ptrTypeSema(.{
41524124 .child = var_ty.toIntern(),
41534125 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
41544126 });
4155 try sema.queueFullTypeResolution(var_ty);
41564127 return block.addTy(.alloc, ptr_type);
41574128}
41584129
......@@ -4229,6 +4200,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42294200 if (mod.intern_pool.isFuncBody(val)) {
42304201 const ty = Type.fromInterned(mod.intern_pool.typeOf(val));
42314202 if (try sema.fnHasRuntimeBits(ty)) {
4203 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = val }));
42324204 try mod.ensureFuncBodyAnalysisQueued(val);
42334205 }
42344206 }
......@@ -4247,7 +4219,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42474219 }
42484220 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none);
42494221
4250 const final_ptr_ty = try sema.ptrType(.{
4222 const final_ptr_ty = try mod.ptrTypeSema(.{
42514223 .child = final_elem_ty.toIntern(),
42524224 .flags = .{
42534225 .alignment = ia1.alignment,
......@@ -4267,7 +4239,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42674239 // Unless the block is comptime, `alloc_inferred` always produces
42684240 // a runtime constant. The final inferred type needs to be
42694241 // fully resolved so it can be lowered in codegen.
4270 try sema.resolveTypeFully(final_elem_ty);
4242 try final_elem_ty.resolveFully(mod);
42714243
42724244 return;
42734245 }
......@@ -4279,8 +4251,6 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
42794251 return sema.fail(block, src, "value with comptime-only type '{}' depends on runtime control flow", .{final_elem_ty.fmt(mod)});
42804252 }
42814253
4282 try sema.queueFullTypeResolution(final_elem_ty);
4283
42844254 // Change it to a normal alloc.
42854255 sema.air_instructions.set(@intFromEnum(ptr_inst), .{
42864256 .tag = .alloc,
......@@ -4653,7 +4623,7 @@ fn validateArrayInitTy(
46534623 return;
46544624 },
46554625 .Struct => if (ty.isTuple(mod)) {
4656 try sema.resolveTypeFields(ty);
4626 try ty.resolveFields(mod);
46574627 const array_len = ty.arrayLen(mod);
46584628 if (init_count > array_len) {
46594629 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
......@@ -4931,7 +4901,7 @@ fn validateStructInit(
49314901 if (block.is_comptime and
49324902 (try sema.resolveDefinedValue(block, init_src, struct_ptr)) != null)
49334903 {
4934 try sema.resolveStructLayout(struct_ty);
4904 try struct_ty.resolveLayout(mod);
49354905 // In this case the only thing we need to do is evaluate the implicit
49364906 // store instructions for default field values, and report any missing fields.
49374907 // Avoid the cost of the extra machinery for detecting a comptime struct init value.
......@@ -4939,7 +4909,7 @@ fn validateStructInit(
49394909 const i: u32 = @intCast(i_usize);
49404910 if (field_ptr != .none) continue;
49414911
4942 try sema.resolveStructFieldInits(struct_ty);
4912 try struct_ty.resolveStructFieldInits(mod);
49434913 const default_val = struct_ty.structFieldDefaultValue(i, mod);
49444914 if (default_val.toIntern() == .unreachable_value) {
49454915 const field_name = struct_ty.structFieldName(i, mod).unwrap() orelse {
......@@ -4988,7 +4958,7 @@ fn validateStructInit(
49884958 const air_tags = sema.air_instructions.items(.tag);
49894959 const air_datas = sema.air_instructions.items(.data);
49904960
4991 try sema.resolveStructFieldInits(struct_ty);
4961 try struct_ty.resolveStructFieldInits(mod);
49924962
49934963 // We collect the comptime field values in case the struct initialization
49944964 // ends up being comptime-known.
......@@ -5147,7 +5117,7 @@ fn validateStructInit(
51475117 try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
51485118 return;
51495119 }
5150 try sema.resolveStructLayout(struct_ty);
5120 try struct_ty.resolveLayout(mod);
51515121
51525122 // Our task is to insert `store` instructions for all the default field values.
51535123 for (found_fields, 0..) |field_ptr, i| {
......@@ -5192,7 +5162,7 @@ fn zirValidatePtrArrayInit(
51925162 var root_msg: ?*Module.ErrorMsg = null;
51935163 errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
51945164
5195 try sema.resolveStructFieldInits(array_ty);
5165 try array_ty.resolveStructFieldInits(mod);
51965166 var i = instrs.len;
51975167 while (i < array_len) : (i += 1) {
51985168 const default_val = array_ty.structFieldDefaultValue(i, mod).toIntern();
......@@ -5261,7 +5231,7 @@ fn zirValidatePtrArrayInit(
52615231
52625232 if (array_ty.isTuple(mod)) {
52635233 if (array_ty.structFieldIsComptime(i, mod))
5264 try sema.resolveStructFieldInits(array_ty);
5234 try array_ty.resolveStructFieldInits(mod);
52655235 if (try array_ty.structFieldValueComptime(mod, i)) |opv| {
52665236 element_vals[i] = opv.toIntern();
52675237 continue;
......@@ -5601,7 +5571,7 @@ fn storeToInferredAllocComptime(
56015571 .needed_comptime_reason = "value being stored to a comptime variable must be comptime-known",
56025572 });
56035573 };
5604 const alloc_ty = try sema.ptrType(.{
5574 const alloc_ty = try zcu.ptrTypeSema(.{
56055575 .child = operand_ty.toIntern(),
56065576 .flags = .{
56075577 .alignment = iac.alignment,
......@@ -5708,7 +5678,7 @@ fn anonDeclRef(sema: *Sema, val: InternPool.Index) CompileError!Air.Inst.Ref {
57085678
57095679fn refValue(sema: *Sema, val: InternPool.Index) CompileError!InternPool.Index {
57105680 const mod = sema.mod;
5711 const ptr_ty = (try sema.ptrType(.{
5681 const ptr_ty = (try mod.ptrTypeSema(.{
57125682 .child = mod.intern_pool.typeOf(val),
57135683 .flags = .{
57145684 .alignment = .none,
......@@ -5817,11 +5787,7 @@ fn zirCompileLog(
58175787 }
58185788 try writer.print("\n", .{});
58195789
5820 const decl_index = if (sema.func_index != .none)
5821 mod.funcOwnerDeclIndex(sema.func_index)
5822 else
5823 sema.owner_decl_index;
5824 const gop = try mod.compile_log_decls.getOrPut(sema.gpa, decl_index);
5790 const gop = try mod.compile_log_sources.getOrPut(sema.gpa, sema.ownerUnit());
58255791 if (!gop.found_existing) gop.value_ptr.* = .{
58265792 .base_node_inst = block.src_base_inst,
58275793 .node_offset = src_node,
......@@ -5974,7 +5940,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
59745940 if (!comp.config.link_libc)
59755941 try sema.errNote(src, msg, "libc headers not available; compilation does not link against libc", .{});
59765942
5977 const gop = try mod.cimport_errors.getOrPut(gpa, sema.owner_decl_index);
5943 const gop = try mod.cimport_errors.getOrPut(gpa, sema.ownerUnit());
59785944 if (!gop.found_existing) {
59795945 gop.value_ptr.* = c_import_res.errors;
59805946 c_import_res.errors = std.zig.ErrorBundle.empty;
......@@ -6393,6 +6359,7 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
63936359 } else try sema.lookupIdentifier(block, operand_src, decl_name);
63946360 const options = try sema.resolveExportOptions(block, options_src, extra.options);
63956361 {
6362 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = decl_index }));
63966363 try sema.ensureDeclAnalyzed(decl_index);
63976364 const exported_decl = mod.declPtr(decl_index);
63986365 if (exported_decl.val.getFunction(mod)) |function| {
......@@ -6423,10 +6390,9 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
64236390 return sema.analyzeExport(block, src, options, decl_index);
64246391 }
64256392
6426 try addExport(mod, .{
6393 try sema.exports.append(mod.gpa, .{
64276394 .opts = options,
64286395 .src = src,
6429 .owner_decl = sema.owner_decl_index,
64306396 .exported = .{ .value = operand.toIntern() },
64316397 .status = .in_progress,
64326398 });
......@@ -6445,6 +6411,7 @@ pub fn analyzeExport(
64456411 if (options.linkage == .internal)
64466412 return;
64476413
6414 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = exported_decl_index }));
64486415 try sema.ensureDeclAnalyzed(exported_decl_index);
64496416 const exported_decl = mod.declPtr(exported_decl_index);
64506417 const export_ty = exported_decl.typeOf(mod);
......@@ -6467,48 +6434,16 @@ pub fn analyzeExport(
64676434 return sema.fail(block, src, "export target cannot be extern", .{});
64686435 }
64696436
6470 try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
6437 try sema.maybeQueueFuncBodyAnalysis(src, exported_decl_index);
64716438
6472 try addExport(mod, .{
6439 try sema.exports.append(gpa, .{
64736440 .opts = options,
64746441 .src = src,
6475 .owner_decl = sema.owner_decl_index,
64766442 .exported = .{ .decl_index = exported_decl_index },
64776443 .status = .in_progress,
64786444 });
64796445}
64806446
6481fn addExport(mod: *Module, export_init: Module.Export) error{OutOfMemory}!void {
6482 const gpa = mod.gpa;
6483
6484 try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
6485 try mod.value_exports.ensureUnusedCapacity(gpa, 1);
6486 try mod.export_owners.ensureUnusedCapacity(gpa, 1);
6487
6488 const new_export = try gpa.create(Module.Export);
6489 errdefer gpa.destroy(new_export);
6490
6491 new_export.* = export_init;
6492
6493 const eo_gop = mod.export_owners.getOrPutAssumeCapacity(export_init.owner_decl);
6494 if (!eo_gop.found_existing) eo_gop.value_ptr.* = .{};
6495 try eo_gop.value_ptr.append(gpa, new_export);
6496 errdefer _ = eo_gop.value_ptr.pop();
6497
6498 switch (export_init.exported) {
6499 .decl_index => |decl_index| {
6500 const de_gop = mod.decl_exports.getOrPutAssumeCapacity(decl_index);
6501 if (!de_gop.found_existing) de_gop.value_ptr.* = .{};
6502 try de_gop.value_ptr.append(gpa, new_export);
6503 },
6504 .value => |value| {
6505 const ve_gop = mod.value_exports.getOrPutAssumeCapacity(value);
6506 if (!ve_gop.found_existing) ve_gop.value_ptr.* = .{};
6507 try ve_gop.value_ptr.append(gpa, new_export);
6508 },
6509 }
6510}
6511
65126447fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
65136448 const mod = sema.mod;
65146449 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
......@@ -6700,8 +6635,6 @@ fn addDbgVar(
67006635 // real `block` instruction.
67016636 if (block.need_debug_scope) |ptr| ptr.* = true;
67026637
6703 try sema.queueFullTypeResolution(operand_ty);
6704
67056638 // Add the name to the AIR.
67066639 const name_extra_index: u32 = @intCast(sema.air_extra.items.len);
67076640 const elements_used = name.len / 4 + 1;
......@@ -6730,8 +6663,7 @@ fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
67306663 .no_embedded_nulls,
67316664 );
67326665 const decl_index = try sema.lookupIdentifier(block, src, decl_name);
6733 try sema.addReferencedBy(src, decl_index);
6734 return sema.analyzeDeclRef(decl_index);
6666 return sema.analyzeDeclRef(src, decl_index);
67356667}
67366668
67376669fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
......@@ -6888,14 +6820,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
68886820
68896821 if (!block.ownerModule().error_tracing) return .none;
68906822
6891 const stack_trace_ty = sema.getBuiltinType("StackTrace") catch |err| switch (err) {
6892 error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
6893 else => |e| return e,
6894 };
6895 sema.resolveTypeFields(stack_trace_ty) catch |err| switch (err) {
6896 error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
6897 else => |e| return e,
6898 };
6823 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
6824 try stack_trace_ty.resolveFields(mod);
68996825 const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls);
69006826 const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {
69016827 error.AnalysisFail => @panic("std.builtin.StackTrace is corrupt"),
......@@ -6935,8 +6861,8 @@ fn popErrorReturnTrace(
69356861 // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or
69366862 // the result is comptime-known to be a non-error. Either way, pop unconditionally.
69376863
6938 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
6939 try sema.resolveTypeFields(stack_trace_ty);
6864 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
6865 try stack_trace_ty.resolveFields(mod);
69406866 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
69416867 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
69426868 const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls);
......@@ -6961,8 +6887,8 @@ fn popErrorReturnTrace(
69616887 defer then_block.instructions.deinit(gpa);
69626888
69636889 // If non-error, then pop the error return trace by restoring the index.
6964 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
6965 try sema.resolveTypeFields(stack_trace_ty);
6890 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
6891 try stack_trace_ty.resolveFields(mod);
69666892 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
69676893 const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
69686894 const field_name = try mod.intern_pool.getOrPutString(gpa, "index", .no_embedded_nulls);
......@@ -7088,8 +7014,8 @@ fn zirCall(
70887014 // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only
70897015 // need to clean-up our own trace if we were passed to a non-error-handling expression.
70907016 if (input_is_error or (pop_error_return_trace and return_ty.isError(mod))) {
7091 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
7092 try sema.resolveTypeFields(stack_trace_ty);
7017 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
7018 try stack_trace_ty.resolveFields(mod);
70937019 const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index", .no_embedded_nulls);
70947020 const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
70957021
......@@ -7320,10 +7246,6 @@ const CallArgsInfo = union(enum) {
73207246 ) CompileError!Air.Inst.Ref {
73217247 const mod = sema.mod;
73227248 const param_count = func_ty_info.param_types.len;
7323 if (maybe_param_ty) |param_ty| switch (param_ty.toIntern()) {
7324 .generic_poison_type => {},
7325 else => try sema.queueFullTypeResolution(param_ty),
7326 };
73277249 const uncoerced_arg: Air.Inst.Ref = switch (cai) {
73287250 inline .resolved, .call_builtin => |resolved| resolved.args[arg_index],
73297251 .zir_call => |zir_call| arg_val: {
......@@ -7550,24 +7472,19 @@ fn analyzeCall(
75507472
75517473 const gpa = sema.gpa;
75527474
7553 var is_generic_call = func_ty_info.is_generic;
7475 const is_generic_call = func_ty_info.is_generic;
75547476 var is_comptime_call = block.is_comptime or modifier == .compile_time;
75557477 var is_inline_call = is_comptime_call or modifier == .always_inline or func_ty_info.cc == .Inline;
75567478 var comptime_reason: ?*const Block.ComptimeReason = null;
75577479 if (!is_inline_call and !is_comptime_call) {
7558 if (sema.typeRequiresComptime(Type.fromInterned(func_ty_info.return_type))) |ct| {
7559 is_comptime_call = ct;
7560 is_inline_call = ct;
7561 if (ct) {
7562 comptime_reason = &.{ .comptime_ret_ty = .{
7563 .func = func,
7564 .func_src = func_src,
7565 .return_ty = Type.fromInterned(func_ty_info.return_type),
7566 } };
7567 }
7568 } else |err| switch (err) {
7569 error.GenericPoison => is_generic_call = true,
7570 else => |e| return e,
7480 if (try sema.typeRequiresComptime(Type.fromInterned(func_ty_info.return_type))) {
7481 is_comptime_call = true;
7482 is_inline_call = true;
7483 comptime_reason = &.{ .comptime_ret_ty = .{
7484 .func = func,
7485 .func_src = func_src,
7486 .return_ty = Type.fromInterned(func_ty_info.return_type),
7487 } };
75717488 }
75727489 }
75737490
......@@ -7927,13 +7844,13 @@ fn analyzeCall(
79277844
79287845 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
79297846
7930 try sema.queueFullTypeResolution(Type.fromInterned(func_ty_info.return_type));
79317847 if (sema.owner_func_index != .none and Type.fromInterned(func_ty_info.return_type).isError(mod)) {
79327848 ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn = true;
79337849 }
79347850
79357851 if (try sema.resolveValue(func)) |func_val| {
79367852 if (mod.intern_pool.isFuncBody(func_val.toIntern())) {
7853 try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = func_val.toIntern() }));
79377854 try mod.ensureFuncBodyAnalysisQueued(func_val.toIntern());
79387855 }
79397856 }
......@@ -8336,7 +8253,6 @@ fn instantiateGenericCall(
83368253 }
83378254 } else {
83388255 // The parameter is runtime-known.
8339 try sema.queueFullTypeResolution(arg_ty);
83408256 child_sema.inst_map.putAssumeCapacityNoClobber(param_inst, try child_block.addInst(.{
83418257 .tag = .arg,
83428258 .data = .{ .arg = .{
......@@ -8370,8 +8286,6 @@ fn instantiateGenericCall(
83708286 const callee = mod.funcInfo(callee_index);
83718287 callee.branchQuota(ip).* = @max(callee.branchQuota(ip).*, sema.branch_quota);
83728288
8373 try sema.addReferencedBy(call_src, callee.owner_decl);
8374
83758289 // Make a runtime call to the new function, making sure to omit the comptime args.
83768290 const func_ty = Type.fromInterned(callee.ty);
83778291 const func_ty_info = mod.typeToFunc(func_ty).?;
......@@ -8387,8 +8301,6 @@ fn instantiateGenericCall(
83878301 return error.GenericPoison;
83888302 }
83898303
8390 try sema.queueFullTypeResolution(Type.fromInterned(func_ty_info.return_type));
8391
83928304 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
83938305
83948306 if (sema.owner_func_index != .none and
......@@ -8397,6 +8309,7 @@ fn instantiateGenericCall(
83978309 ip.funcAnalysis(sema.owner_func_index).calls_or_awaits_errorable_fn = true;
83988310 }
83998311
8312 try sema.addReferenceEntry(call_src, AnalUnit.wrap(.{ .func = callee_index }));
84008313 try mod.ensureFuncBodyAnalysisQueued(callee_index);
84018314
84028315 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len + runtime_args.items.len);
......@@ -8411,6 +8324,9 @@ fn instantiateGenericCall(
84118324 });
84128325 sema.appendRefsAssumeCapacity(runtime_args.items);
84138326
8327 // `child_sema` is owned by us, so just take its exports.
8328 try sema.exports.appendSlice(sema.gpa, child_sema.exports.items);
8329
84148330 if (ensure_result_used) {
84158331 try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
84168332 }
......@@ -8476,7 +8392,7 @@ fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
84768392 else => |e| return e,
84778393 };
84788394 const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(mod);
8479 try sema.resolveTypeFields(indexable_ty);
8395 try indexable_ty.resolveFields(mod);
84808396 assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction
84818397 if (indexable_ty.zigTypeTag(mod) == .Struct) {
84828398 const elem_type = indexable_ty.structFieldType(@intFromEnum(bin.rhs), mod);
......@@ -8740,7 +8656,7 @@ fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
87408656 const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src);
87418657
87428658 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
8743 const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntAdvanced(sema));
8659 const int = try sema.usizeCast(block, operand_src, try value.toUnsignedIntSema(mod));
87448660 if (int > mod.global_error_set.count() or int == 0)
87458661 return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
87468662 return Air.internedToRef((try mod.intern(.{ .err = .{
......@@ -8844,7 +8760,7 @@ fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
88448760 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) {
88458761 .Enum => operand,
88468762 .Union => blk: {
8847 try sema.resolveTypeFields(operand_ty);
8763 try operand_ty.resolveFields(mod);
88488764 const tag_ty = operand_ty.unionTagType(mod) orelse {
88498765 return sema.fail(
88508766 block,
......@@ -8986,7 +8902,7 @@ fn analyzeOptionalPayloadPtr(
89868902 }
89878903
89888904 const child_type = opt_type.optionalChild(zcu);
8989 const child_pointer = try sema.ptrType(.{
8905 const child_pointer = try zcu.ptrTypeSema(.{
89908906 .child = child_type.toIntern(),
89918907 .flags = .{
89928908 .is_const = optional_ptr_ty.isConstPtr(zcu),
......@@ -9010,13 +8926,13 @@ fn analyzeOptionalPayloadPtr(
90108926 const opt_payload_ptr = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
90118927 try sema.checkKnownAllocPtr(block, optional_ptr, opt_payload_ptr);
90128928 }
9013 return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern());
8929 return Air.internedToRef((try ptr_val.ptrOptPayload(zcu)).toIntern());
90148930 }
90158931 if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
90168932 if (val.isNull(zcu)) {
90178933 return sema.fail(block, src, "unable to unwrap null", .{});
90188934 }
9019 return Air.internedToRef((try ptr_val.ptrOptPayload(sema)).toIntern());
8935 return Air.internedToRef((try ptr_val.ptrOptPayload(zcu)).toIntern());
90208936 }
90218937 }
90228938
......@@ -9059,7 +8975,7 @@ fn zirOptionalPayload(
90598975 // TODO https://github.com/ziglang/zig/issues/6597
90608976 if (true) break :t operand_ty;
90618977 const ptr_info = operand_ty.ptrInfo(mod);
9062 break :t try sema.ptrType(.{
8978 break :t try mod.ptrTypeSema(.{
90638979 .child = ptr_info.child,
90648980 .flags = .{
90658981 .alignment = ptr_info.flags.alignment,
......@@ -9177,7 +9093,7 @@ fn analyzeErrUnionPayloadPtr(
91779093
91789094 const err_union_ty = operand_ty.childType(zcu);
91799095 const payload_ty = err_union_ty.errorUnionPayload(zcu);
9180 const operand_pointer_ty = try sema.ptrType(.{
9096 const operand_pointer_ty = try zcu.ptrTypeSema(.{
91819097 .child = payload_ty.toIntern(),
91829098 .flags = .{
91839099 .is_const = operand_ty.isConstPtr(zcu),
......@@ -9202,13 +9118,13 @@ fn analyzeErrUnionPayloadPtr(
92029118 const eu_payload_ptr = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
92039119 try sema.checkKnownAllocPtr(block, operand, eu_payload_ptr);
92049120 }
9205 return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern());
9121 return Air.internedToRef((try ptr_val.ptrEuPayload(zcu)).toIntern());
92069122 }
92079123 if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {
92089124 if (val.getErrorName(zcu).unwrap()) |name| {
92099125 return sema.failWithComptimeErrorRetTrace(block, src, name);
92109126 }
9211 return Air.internedToRef((try ptr_val.ptrEuPayload(sema)).toIntern());
9127 return Air.internedToRef((try ptr_val.ptrEuPayload(zcu)).toIntern());
92129128 }
92139129 }
92149130
......@@ -9656,17 +9572,8 @@ fn funcCommon(
96569572 }
96579573 }
96589574
9659 var ret_ty_requires_comptime = false;
9660 const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: {
9661 ret_ty_requires_comptime = ret_comptime;
9662 break :rp bare_return_type.isGenericPoison();
9663 } else |err| switch (err) {
9664 error.GenericPoison => rp: {
9665 is_generic = true;
9666 break :rp true;
9667 },
9668 else => |e| return e,
9669 };
9575 const ret_ty_requires_comptime = try sema.typeRequiresComptime(bare_return_type);
9576 const ret_poison = bare_return_type.isGenericPoison();
96709577 const final_is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime;
96719578
96729579 const param_types = block.params.items(.ty);
......@@ -10014,8 +9921,8 @@ fn finishFunc(
100149921 if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) {
100159922 // Make sure that StackTrace's fields are resolved so that the backend can
100169923 // lower this fn type.
10017 const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
10018 try sema.resolveTypeFields(unresolved_stack_trace_ty);
9924 const unresolved_stack_trace_ty = try mod.getBuiltinType("StackTrace");
9925 try unresolved_stack_trace_ty.resolveFields(mod);
100199926 }
100209927
100219928 return Air.internedToRef(if (opt_func_index != .none) opt_func_index else func_ty);
......@@ -10074,21 +9981,7 @@ fn zirParam(
100749981 }
100759982 };
100769983
10077 const is_comptime = sema.typeRequiresComptime(param_ty) catch |err| switch (err) {
10078 error.GenericPoison => {
10079 // The type is not available until the generic instantiation.
10080 // We result the param instruction with a poison value and
10081 // insert an anytype parameter.
10082 try block.params.append(sema.arena, .{
10083 .ty = .generic_poison_type,
10084 .is_comptime = comptime_syntax,
10085 .name = param_name,
10086 });
10087 sema.inst_map.putAssumeCapacity(inst, .generic_poison);
10088 return;
10089 },
10090 else => |e| return e,
10091 } or comptime_syntax;
9984 const is_comptime = try sema.typeRequiresComptime(param_ty) or comptime_syntax;
100929985
100939986 try block.params.append(sema.arena, .{
100949987 .ty = param_ty.toIntern(),
......@@ -10215,7 +10108,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1021510108 }
1021610109 return Air.internedToRef((try zcu.intValue(
1021710110 Type.usize,
10218 (try operand_val.getUnsignedIntAdvanced(zcu, sema)).?,
10111 (try operand_val.getUnsignedIntAdvanced(zcu, .sema)).?,
1021910112 )).toIntern());
1022010113 }
1022110114 const len = operand_ty.vectorLen(zcu);
......@@ -10227,7 +10120,7 @@ fn zirIntFromPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
1022710120 new_elem.* = (try zcu.undefValue(Type.usize)).toIntern();
1022810121 continue;
1022910122 }
10230 const addr = try ptr_val.getUnsignedIntAdvanced(zcu, sema) orelse {
10123 const addr = try ptr_val.getUnsignedIntAdvanced(zcu, .sema) orelse {
1023110124 // A vector element wasn't an integer pointer. This is a runtime operation.
1023210125 break :ct;
1023310126 };
......@@ -11100,7 +10993,7 @@ const SwitchProngAnalysis = struct {
1110010993 const union_obj = zcu.typeToUnion(operand_ty).?;
1110110994 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
1110210995 if (capture_byref) {
11103 const ptr_field_ty = try sema.ptrType(.{
10996 const ptr_field_ty = try zcu.ptrTypeSema(.{
1110410997 .child = field_ty.toIntern(),
1110510998 .flags = .{
1110610999 .is_const = !operand_ptr_ty.ptrIsMutable(zcu),
......@@ -11109,7 +11002,7 @@ const SwitchProngAnalysis = struct {
1110911002 },
1111011003 });
1111111004 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |union_ptr| {
11112 return Air.internedToRef((try union_ptr.ptrField(field_index, sema)).toIntern());
11005 return Air.internedToRef((try union_ptr.ptrField(field_index, zcu)).toIntern());
1111311006 }
1111411007 return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
1111511008 } else {
......@@ -11203,7 +11096,7 @@ const SwitchProngAnalysis = struct {
1120311096 const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
1120411097 for (field_indices, dummy_captures) |field_idx, *dummy| {
1120511098 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_idx]);
11206 const field_ptr_ty = try sema.ptrType(.{
11099 const field_ptr_ty = try zcu.ptrTypeSema(.{
1120711100 .child = field_ty.toIntern(),
1120811101 .flags = .{
1120911102 .is_const = operand_ptr_info.flags.is_const,
......@@ -11239,7 +11132,7 @@ const SwitchProngAnalysis = struct {
1123911132
1124011133 if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| {
1124111134 if (op_ptr_val.isUndef(zcu)) return zcu.undefRef(capture_ptr_ty);
11242 const field_ptr_val = try op_ptr_val.ptrField(first_field_index, sema);
11135 const field_ptr_val = try op_ptr_val.ptrField(first_field_index, zcu);
1124311136 return Air.internedToRef((try zcu.getCoerced(field_ptr_val, capture_ptr_ty)).toIntern());
1124411137 }
1124511138
......@@ -11452,7 +11345,7 @@ fn switchCond(
1145211345 },
1145311346
1145411347 .Union => {
11455 try sema.resolveTypeFields(operand_ty);
11348 try operand_ty.resolveFields(mod);
1145611349 const enum_ty = operand_ty.unionTagType(mod) orelse {
1145711350 const msg = msg: {
1145811351 const msg = try sema.errMsg(src, "switch on union with no attached enum", .{});
......@@ -13744,7 +13637,7 @@ fn maybeErrorUnwrap(
1374413637 return true;
1374513638 }
1374613639
13747 const panic_fn = try sema.getBuiltin("panicUnwrapError");
13640 const panic_fn = try mod.getBuiltin("panicUnwrapError");
1374813641 const err_return_trace = try sema.getErrorReturnTrace(block);
1374913642 const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };
1375013643 try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check");
......@@ -13754,7 +13647,7 @@ fn maybeErrorUnwrap(
1375413647 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
1375513648 const msg_inst = try sema.resolveInst(inst_data.operand);
1375613649
13757 const panic_fn = try sema.getBuiltin("panic");
13650 const panic_fn = try mod.getBuiltin("panic");
1375813651 const err_return_trace = try sema.getErrorReturnTrace(block);
1375913652 const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
1376013653 try sema.callBuiltin(block, operand_src, panic_fn, .auto, &args, .@"safety check");
......@@ -13819,7 +13712,7 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1381913712 const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, .{
1382013713 .needed_comptime_reason = "field name must be comptime-known",
1382113714 });
13822 try sema.resolveTypeFields(ty);
13715 try ty.resolveFields(mod);
1382313716 const ip = &mod.intern_pool;
1382413717
1382513718 const has_field = hf: {
......@@ -13934,7 +13827,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1393413827 return sema.fail(block, operand_src, "file path name cannot be empty", .{});
1393513828 }
1393613829
13937 const val = mod.embedFile(block.getFileScope(mod), name, operand_src.upgrade(mod)) catch |err| switch (err) {
13830 const val = mod.embedFile(block.getFileScope(mod), name, operand_src) catch |err| switch (err) {
1393813831 error.ImportOutsideModulePath => {
1393913832 return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
1394013833 },
......@@ -13999,7 +13892,7 @@ fn zirShl(
1399913892 return mod.undefRef(sema.typeOf(lhs));
1400013893 }
1400113894 // If rhs is 0, return lhs without doing any calculations.
14002 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
13895 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1400313896 return lhs;
1400413897 }
1400513898 if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) {
......@@ -14164,7 +14057,7 @@ fn zirShr(
1416414057 return mod.undefRef(lhs_ty);
1416514058 }
1416614059 // If rhs is 0, return lhs without doing any calculations.
14167 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
14060 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1416814061 return lhs;
1416914062 }
1417014063 if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) {
......@@ -14211,7 +14104,7 @@ fn zirShr(
1421114104 if (air_tag == .shr_exact) {
1421214105 // Detect if any ones would be shifted out.
1421314106 const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, mod);
14214 if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) {
14107 if (!(try truncated.compareAllWithZeroSema(.eq, mod))) {
1421514108 return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
1421614109 }
1421714110 }
......@@ -14635,12 +14528,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1463514528 try sema.requireRuntimeBlock(block, src, runtime_src);
1463614529
1463714530 if (ptr_addrspace) |ptr_as| {
14638 const alloc_ty = try sema.ptrType(.{
14531 const alloc_ty = try mod.ptrTypeSema(.{
1463914532 .child = result_ty.toIntern(),
1464014533 .flags = .{ .address_space = ptr_as },
1464114534 });
1464214535 const alloc = try block.addTy(.alloc, alloc_ty);
14643 const elem_ptr_ty = try sema.ptrType(.{
14536 const elem_ptr_ty = try mod.ptrTypeSema(.{
1464414537 .child = resolved_elem_ty.toIntern(),
1464514538 .flags = .{ .address_space = ptr_as },
1464614539 });
......@@ -14723,7 +14616,7 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
1472314616 .none => null,
1472414617 else => Value.fromInterned(ptr_info.sentinel),
1472514618 },
14726 .len = try val.sliceLen(sema),
14619 .len = try val.sliceLen(mod),
1472714620 };
1472814621 },
1472914622 .One => {
......@@ -14965,12 +14858,12 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1496514858 }
1496614859
1496714860 if (ptr_addrspace) |ptr_as| {
14968 const alloc_ty = try sema.ptrType(.{
14861 const alloc_ty = try mod.ptrTypeSema(.{
1496914862 .child = result_ty.toIntern(),
1497014863 .flags = .{ .address_space = ptr_as },
1497114864 });
1497214865 const alloc = try block.addTy(.alloc, alloc_ty);
14973 const elem_ptr_ty = try sema.ptrType(.{
14866 const elem_ptr_ty = try mod.ptrTypeSema(.{
1497414867 .child = lhs_info.elem_type.toIntern(),
1497514868 .flags = .{ .address_space = ptr_as },
1497614869 });
......@@ -15158,7 +15051,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1515815051 .Int, .ComptimeInt, .ComptimeFloat => {
1515915052 if (maybe_lhs_val) |lhs_val| {
1516015053 if (!lhs_val.isUndef(mod)) {
15161 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
15054 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1516215055 const scalar_zero = switch (scalar_tag) {
1516315056 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
1516415057 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
......@@ -15173,7 +15066,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1517315066 if (rhs_val.isUndef(mod)) {
1517415067 return sema.failWithUseOfUndef(block, rhs_src);
1517515068 }
15176 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15069 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1517715070 return sema.failWithDivideByZero(block, rhs_src);
1517815071 }
1517915072 // TODO: if the RHS is one, return the LHS directly
......@@ -15294,7 +15187,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1529415187 if (lhs_val.isUndef(mod)) {
1529515188 return sema.failWithUseOfUndef(block, rhs_src);
1529615189 } else {
15297 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
15190 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1529815191 const scalar_zero = switch (scalar_tag) {
1529915192 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
1530015193 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
......@@ -15309,7 +15202,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1530915202 if (rhs_val.isUndef(mod)) {
1531015203 return sema.failWithUseOfUndef(block, rhs_src);
1531115204 }
15312 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15205 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1531315206 return sema.failWithDivideByZero(block, rhs_src);
1531415207 }
1531515208 // TODO: if the RHS is one, return the LHS directly
......@@ -15461,7 +15354,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1546115354 // If the lhs is undefined, result is undefined.
1546215355 if (maybe_lhs_val) |lhs_val| {
1546315356 if (!lhs_val.isUndef(mod)) {
15464 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
15357 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1546515358 const scalar_zero = switch (scalar_tag) {
1546615359 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
1546715360 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
......@@ -15476,7 +15369,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1547615369 if (rhs_val.isUndef(mod)) {
1547715370 return sema.failWithUseOfUndef(block, rhs_src);
1547815371 }
15479 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15372 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1548015373 return sema.failWithDivideByZero(block, rhs_src);
1548115374 }
1548215375 // TODO: if the RHS is one, return the LHS directly
......@@ -15571,7 +15464,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1557115464 // If the lhs is undefined, result is undefined.
1557215465 if (maybe_lhs_val) |lhs_val| {
1557315466 if (!lhs_val.isUndef(mod)) {
15574 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
15467 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1557515468 const scalar_zero = switch (scalar_tag) {
1557615469 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
1557715470 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
......@@ -15586,7 +15479,7 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1558615479 if (rhs_val.isUndef(mod)) {
1558715480 return sema.failWithUseOfUndef(block, rhs_src);
1558815481 }
15589 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15482 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1559015483 return sema.failWithDivideByZero(block, rhs_src);
1559115484 }
1559215485 }
......@@ -15811,7 +15704,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1581115704 if (lhs_val.isUndef(mod)) {
1581215705 return sema.failWithUseOfUndef(block, lhs_src);
1581315706 }
15814 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
15707 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1581515708 const scalar_zero = switch (scalar_tag) {
1581615709 .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
1581715710 .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
......@@ -15830,18 +15723,18 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1583015723 if (rhs_val.isUndef(mod)) {
1583115724 return sema.failWithUseOfUndef(block, rhs_src);
1583215725 }
15833 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15726 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1583415727 return sema.failWithDivideByZero(block, rhs_src);
1583515728 }
15836 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
15729 if (!(try rhs_val.compareAllWithZeroSema(.gte, mod))) {
1583715730 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
1583815731 }
1583915732 if (maybe_lhs_val) |lhs_val| {
1584015733 const rem_result = try sema.intRem(resolved_type, lhs_val, rhs_val);
1584115734 // If this answer could possibly be different by doing `intMod`,
1584215735 // we must emit a compile error. Otherwise, it's OK.
15843 if (!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema)) and
15844 !(try rem_result.compareAllWithZeroAdvanced(.eq, sema)))
15736 if (!(try lhs_val.compareAllWithZeroSema(.gte, mod)) and
15737 !(try rem_result.compareAllWithZeroSema(.eq, mod)))
1584515738 {
1584615739 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
1584715740 }
......@@ -15859,14 +15752,14 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1585915752 if (rhs_val.isUndef(mod)) {
1586015753 return sema.failWithUseOfUndef(block, rhs_src);
1586115754 }
15862 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15755 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1586315756 return sema.failWithDivideByZero(block, rhs_src);
1586415757 }
15865 if (!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
15758 if (!(try rhs_val.compareAllWithZeroSema(.gte, mod))) {
1586615759 return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
1586715760 }
1586815761 if (maybe_lhs_val) |lhs_val| {
15869 if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
15762 if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroSema(.gte, mod))) {
1587015763 return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
1587115764 }
1587215765 return Air.internedToRef((try lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod)).toIntern());
......@@ -15917,8 +15810,8 @@ fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileErr
1591715810 // resorting to BigInt first.
1591815811 var lhs_space: Value.BigIntSpace = undefined;
1591915812 var rhs_space: Value.BigIntSpace = undefined;
15920 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
15921 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
15813 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema);
15814 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema);
1592215815 const limbs_q = try sema.arena.alloc(
1592315816 math.big.Limb,
1592415817 lhs_bigint.limbs.len,
......@@ -15994,7 +15887,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1599415887 if (rhs_val.isUndef(mod)) {
1599515888 return sema.failWithUseOfUndef(block, rhs_src);
1599615889 }
15997 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15890 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1599815891 return sema.failWithDivideByZero(block, rhs_src);
1599915892 }
1600015893 if (maybe_lhs_val) |lhs_val| {
......@@ -16010,7 +15903,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1601015903 if (rhs_val.isUndef(mod)) {
1601115904 return sema.failWithUseOfUndef(block, rhs_src);
1601215905 }
16013 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15906 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1601415907 return sema.failWithDivideByZero(block, rhs_src);
1601515908 }
1601615909 }
......@@ -16089,7 +15982,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1608915982 if (rhs_val.isUndef(mod)) {
1609015983 return sema.failWithUseOfUndef(block, rhs_src);
1609115984 }
16092 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
15985 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1609315986 return sema.failWithDivideByZero(block, rhs_src);
1609415987 }
1609515988 if (maybe_lhs_val) |lhs_val| {
......@@ -16105,7 +15998,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
1610515998 if (rhs_val.isUndef(mod)) {
1610615999 return sema.failWithUseOfUndef(block, rhs_src);
1610716000 }
16108 if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
16001 if (!(try rhs_val.compareAllWithZeroSema(.neq, mod))) {
1610916002 return sema.failWithDivideByZero(block, rhs_src);
1611016003 }
1611116004 }
......@@ -16192,12 +16085,12 @@ fn zirOverflowArithmetic(
1619216085 // to the result, even if it is undefined..
1619316086 // Otherwise, if either of the argument is undefined, undefined is returned.
1619416087 if (maybe_lhs_val) |lhs_val| {
16195 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16088 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) {
1619616089 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
1619716090 }
1619816091 }
1619916092 if (maybe_rhs_val) |rhs_val| {
16200 if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16093 if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroSema(.eq, mod))) {
1620116094 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
1620216095 }
1620316096 }
......@@ -16218,7 +16111,7 @@ fn zirOverflowArithmetic(
1621816111 if (maybe_rhs_val) |rhs_val| {
1621916112 if (rhs_val.isUndef(mod)) {
1622016113 break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
16221 } else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16114 } else if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1622216115 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
1622316116 } else if (maybe_lhs_val) |lhs_val| {
1622416117 if (lhs_val.isUndef(mod)) {
......@@ -16237,7 +16130,7 @@ fn zirOverflowArithmetic(
1623716130 const scalar_one = try mod.intValue(dest_ty.scalarType(mod), 1);
1623816131 if (maybe_lhs_val) |lhs_val| {
1623916132 if (!lhs_val.isUndef(mod)) {
16240 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16133 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1624116134 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
1624216135 } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
1624316136 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
......@@ -16247,7 +16140,7 @@ fn zirOverflowArithmetic(
1624716140
1624816141 if (maybe_rhs_val) |rhs_val| {
1624916142 if (!rhs_val.isUndef(mod)) {
16250 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16143 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1625116144 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
1625216145 } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
1625316146 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
......@@ -16271,12 +16164,12 @@ fn zirOverflowArithmetic(
1627116164 // If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
1627216165 // Oterhwise if either of the arguments is undefined, both results are undefined.
1627316166 if (maybe_lhs_val) |lhs_val| {
16274 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16167 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) {
1627516168 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
1627616169 }
1627716170 }
1627816171 if (maybe_rhs_val) |rhs_val| {
16279 if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16172 if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroSema(.eq, mod))) {
1628016173 break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
1628116174 }
1628216175 }
......@@ -16427,7 +16320,7 @@ fn analyzeArithmetic(
1642716320 // overflow (max_int), causing illegal behavior.
1642816321 // For floats: either operand being undef makes the result undef.
1642916322 if (maybe_lhs_val) |lhs_val| {
16430 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16323 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) {
1643116324 return casted_rhs;
1643216325 }
1643316326 }
......@@ -16439,7 +16332,7 @@ fn analyzeArithmetic(
1643916332 return mod.undefRef(resolved_type);
1644016333 }
1644116334 }
16442 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16335 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1644316336 return casted_lhs;
1644416337 }
1644516338 }
......@@ -16471,7 +16364,7 @@ fn analyzeArithmetic(
1647116364 // If either of the operands are zero, the other operand is returned.
1647216365 // If either of the operands are undefined, the result is undefined.
1647316366 if (maybe_lhs_val) |lhs_val| {
16474 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16367 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) {
1647516368 return casted_rhs;
1647616369 }
1647716370 }
......@@ -16479,7 +16372,7 @@ fn analyzeArithmetic(
1647916372 if (rhs_val.isUndef(mod)) {
1648016373 return mod.undefRef(resolved_type);
1648116374 }
16482 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16375 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1648316376 return casted_lhs;
1648416377 }
1648516378 if (maybe_lhs_val) |lhs_val| {
......@@ -16492,7 +16385,7 @@ fn analyzeArithmetic(
1649216385 // If either of the operands are zero, then the other operand is returned.
1649316386 // If either of the operands are undefined, the result is undefined.
1649416387 if (maybe_lhs_val) |lhs_val| {
16495 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
16388 if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroSema(.eq, mod))) {
1649616389 return casted_rhs;
1649716390 }
1649816391 }
......@@ -16500,7 +16393,7 @@ fn analyzeArithmetic(
1650016393 if (rhs_val.isUndef(mod)) {
1650116394 return mod.undefRef(resolved_type);
1650216395 }
16503 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16396 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1650416397 return casted_lhs;
1650516398 }
1650616399 if (maybe_lhs_val) |lhs_val| {
......@@ -16541,7 +16434,7 @@ fn analyzeArithmetic(
1654116434 return mod.undefRef(resolved_type);
1654216435 }
1654316436 }
16544 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16437 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1654516438 return casted_lhs;
1654616439 }
1654716440 }
......@@ -16576,7 +16469,7 @@ fn analyzeArithmetic(
1657616469 if (rhs_val.isUndef(mod)) {
1657716470 return mod.undefRef(resolved_type);
1657816471 }
16579 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16472 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1658016473 return casted_lhs;
1658116474 }
1658216475 }
......@@ -16597,7 +16490,7 @@ fn analyzeArithmetic(
1659716490 if (rhs_val.isUndef(mod)) {
1659816491 return mod.undefRef(resolved_type);
1659916492 }
16600 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16493 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1660116494 return casted_lhs;
1660216495 }
1660316496 }
......@@ -16644,7 +16537,7 @@ fn analyzeArithmetic(
1664416537 if (lhs_val.isNan(mod)) {
1664516538 return Air.internedToRef(lhs_val.toIntern());
1664616539 }
16647 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: {
16540 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) lz: {
1664816541 if (maybe_rhs_val) |rhs_val| {
1664916542 if (rhs_val.isNan(mod)) {
1665016543 return Air.internedToRef(rhs_val.toIntern());
......@@ -16675,7 +16568,7 @@ fn analyzeArithmetic(
1667516568 if (rhs_val.isNan(mod)) {
1667616569 return Air.internedToRef(rhs_val.toIntern());
1667716570 }
16678 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: {
16571 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) rz: {
1667916572 if (maybe_lhs_val) |lhs_val| {
1668016573 if (lhs_val.isInf(mod)) {
1668116574 return Air.internedToRef((try mod.floatValue(resolved_type, std.math.nan(f128))).toIntern());
......@@ -16727,7 +16620,7 @@ fn analyzeArithmetic(
1672716620 };
1672816621 if (maybe_lhs_val) |lhs_val| {
1672916622 if (!lhs_val.isUndef(mod)) {
16730 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16623 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1673116624 const zero_val = try sema.splat(resolved_type, scalar_zero);
1673216625 return Air.internedToRef(zero_val.toIntern());
1673316626 }
......@@ -16740,7 +16633,7 @@ fn analyzeArithmetic(
1674016633 if (rhs_val.isUndef(mod)) {
1674116634 return mod.undefRef(resolved_type);
1674216635 }
16743 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16636 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1674416637 const zero_val = try sema.splat(resolved_type, scalar_zero);
1674516638 return Air.internedToRef(zero_val.toIntern());
1674616639 }
......@@ -16772,7 +16665,7 @@ fn analyzeArithmetic(
1677216665 };
1677316666 if (maybe_lhs_val) |lhs_val| {
1677416667 if (!lhs_val.isUndef(mod)) {
16775 if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16668 if (try lhs_val.compareAllWithZeroSema(.eq, mod)) {
1677616669 const zero_val = try sema.splat(resolved_type, scalar_zero);
1677716670 return Air.internedToRef(zero_val.toIntern());
1677816671 }
......@@ -16785,7 +16678,7 @@ fn analyzeArithmetic(
1678516678 if (rhs_val.isUndef(mod)) {
1678616679 return mod.undefRef(resolved_type);
1678716680 }
16788 if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
16681 if (try rhs_val.compareAllWithZeroSema(.eq, mod)) {
1678916682 const zero_val = try sema.splat(resolved_type, scalar_zero);
1679016683 return Air.internedToRef(zero_val.toIntern());
1679116684 }
......@@ -16881,7 +16774,7 @@ fn analyzePtrArithmetic(
1688116774
1688216775 const new_ptr_ty = t: {
1688316776 // Calculate the new pointer alignment.
16884 // This code is duplicated in `elemPtrType`.
16777 // This code is duplicated in `Type.elemPtrType`.
1688516778 if (ptr_info.flags.alignment == .none) {
1688616779 // ABI-aligned pointer. Any pointer arithmetic maintains the same ABI-alignedness.
1688716780 break :t ptr_ty;
......@@ -16890,7 +16783,7 @@ fn analyzePtrArithmetic(
1689016783 // it being a multiple of the type size.
1689116784 const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child));
1689216785 const addend = if (opt_off_val) |off_val| a: {
16893 const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntAdvanced(sema));
16786 const off_int = try sema.usizeCast(block, offset_src, try off_val.toUnsignedIntSema(mod));
1689416787 break :a elem_size * off_int;
1689516788 } else elem_size;
1689616789
......@@ -16903,7 +16796,7 @@ fn analyzePtrArithmetic(
1690316796 ));
1690416797 assert(new_align != .none);
1690516798
16906 break :t try sema.ptrType(.{
16799 break :t try mod.ptrTypeSema(.{
1690716800 .child = ptr_info.child,
1690816801 .sentinel = ptr_info.sentinel,
1690916802 .flags = .{
......@@ -16922,14 +16815,14 @@ fn analyzePtrArithmetic(
1692216815 if (opt_off_val) |offset_val| {
1692316816 if (ptr_val.isUndef(mod)) return mod.undefRef(new_ptr_ty);
1692416817
16925 const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntAdvanced(sema));
16818 const offset_int = try sema.usizeCast(block, offset_src, try offset_val.toUnsignedIntSema(mod));
1692616819 if (offset_int == 0) return ptr;
1692716820 if (air_tag == .ptr_sub) {
1692816821 const elem_size = try sema.typeAbiSize(Type.fromInterned(ptr_info.child));
1692916822 const new_ptr_val = try sema.ptrSubtract(block, op_src, ptr_val, offset_int * elem_size, new_ptr_ty);
1693016823 return Air.internedToRef(new_ptr_val.toIntern());
1693116824 } else {
16932 const new_ptr_val = try mod.getCoerced(try ptr_val.ptrElem(offset_int, sema), new_ptr_ty);
16825 const new_ptr_val = try mod.getCoerced(try ptr_val.ptrElem(offset_int, mod), new_ptr_ty);
1693316826 return Air.internedToRef(new_ptr_val.toIntern());
1693416827 }
1693516828 } else break :rs offset_src;
......@@ -17028,7 +16921,6 @@ fn zirAsm(
1702816921 // Indicate the output is the asm instruction return value.
1702916922 arg.* = .none;
1703016923 const out_ty = try sema.resolveType(block, ret_ty_src, output.data.operand);
17031 try sema.queueFullTypeResolution(out_ty);
1703216924 expr_ty = Air.internedToRef(out_ty.toIntern());
1703316925 } else {
1703416926 arg.* = try sema.resolveInst(output.data.operand);
......@@ -17063,7 +16955,6 @@ fn zirAsm(
1706316955 .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src),
1706416956 else => {
1706516957 arg.* = uncasted_arg;
17066 try sema.queueFullTypeResolution(uncasted_arg_ty);
1706716958 },
1706816959 }
1706916960
......@@ -17222,7 +17113,7 @@ fn analyzeCmpUnionTag(
1722217113) CompileError!Air.Inst.Ref {
1722317114 const mod = sema.mod;
1722417115 const union_ty = sema.typeOf(un);
17225 try sema.resolveTypeFields(union_ty);
17116 try union_ty.resolveFields(mod);
1722617117 const union_tag_ty = union_ty.unionTagType(mod) orelse {
1722717118 const msg = msg: {
1722817119 const msg = try sema.errMsg(un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
......@@ -17438,9 +17329,6 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
1743817329 => {},
1743917330 }
1744017331 const val = try ty.lazyAbiSize(mod);
17441 if (val.isLazySize(mod)) {
17442 try sema.queueFullTypeResolution(ty);
17443 }
1744417332 return Air.internedToRef(val.toIntern());
1744517333}
1744617334
......@@ -17480,7 +17368,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
1748017368 .AnyFrame,
1748117369 => {},
1748217370 }
17483 const bit_size = try operand_ty.bitSizeAdvanced(mod, sema);
17371 const bit_size = try operand_ty.bitSizeAdvanced(mod, .sema);
1748417372 return mod.intRef(Type.comptime_int, bit_size);
1748517373}
1748617374
......@@ -17507,7 +17395,7 @@ fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
1750717395 .@"comptime" => |index| return Air.internedToRef(index),
1750817396 .runtime => |index| index,
1750917397 .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index),
17510 .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index),
17398 .decl_ref => |decl_index| return sema.analyzeDeclRef(src, decl_index),
1751117399 };
1751217400
1751317401 // The comptime case is handled already above. Runtime case below.
......@@ -17666,7 +17554,7 @@ fn zirBuiltinSrc(
1766617554 } });
1766717555 };
1766817556
17669 const src_loc_ty = try sema.getBuiltinType("SourceLocation");
17557 const src_loc_ty = try mod.getBuiltinType("SourceLocation");
1767017558 const fields = .{
1767117559 // file: [:0]const u8,
1767217560 file_name_val,
......@@ -17690,7 +17578,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1769017578 const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
1769117579 const src = block.nodeOffset(inst_data.src_node);
1769217580 const ty = try sema.resolveType(block, src, inst_data.operand);
17693 const type_info_ty = try sema.getBuiltinType("Type");
17581 const type_info_ty = try mod.getBuiltinType("Type");
1769417582 const type_info_tag_ty = type_info_ty.unionTagType(mod).?;
1769517583
1769617584 if (ty.typeDeclInst(mod)) |type_decl_inst| {
......@@ -17771,7 +17659,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1777117659 .ty = new_decl_ty.toIntern(),
1777217660 .storage = .{ .elems = param_vals },
1777317661 } });
17774 const slice_ty = (try sema.ptrType(.{
17662 const slice_ty = (try mod.ptrTypeSema(.{
1777517663 .child = param_info_ty.toIntern(),
1777617664 .flags = .{
1777717665 .size = .Slice,
......@@ -17801,7 +17689,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1780117689 func_ty_info.return_type,
1780217690 } });
1780317691
17804 const callconv_ty = try sema.getBuiltinType("CallingConvention");
17692 const callconv_ty = try mod.getBuiltinType("CallingConvention");
1780517693
1780617694 const field_values = .{
1780717695 // calling_convention: CallingConvention,
......@@ -17835,7 +17723,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1783517723 const int_info_decl = mod.declPtr(int_info_decl_index);
1783617724 const int_info_ty = int_info_decl.val.toType();
1783717725
17838 const signedness_ty = try sema.getBuiltinType("Signedness");
17726 const signedness_ty = try mod.getBuiltinType("Signedness");
1783917727 const info = ty.intInfo(mod);
1784017728 const field_values = .{
1784117729 // signedness: Signedness,
......@@ -17883,12 +17771,12 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1788317771 else
1788417772 try Type.fromInterned(info.child).lazyAbiAlignment(mod);
1788517773
17886 const addrspace_ty = try sema.getBuiltinType("AddressSpace");
17774 const addrspace_ty = try mod.getBuiltinType("AddressSpace");
1788717775 const pointer_ty = t: {
1788817776 const decl_index = (try sema.namespaceLookup(
1788917777 block,
1789017778 src,
17891 (try sema.getBuiltinType("Type")).getNamespaceIndex(mod),
17779 (try mod.getBuiltinType("Type")).getNamespaceIndex(mod),
1789217780 try ip.getOrPutString(gpa, "Pointer", .no_embedded_nulls),
1789317781 )).?;
1789417782 try sema.ensureDeclAnalyzed(decl_index);
......@@ -18037,8 +17925,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1803717925 break :t set_field_ty_decl.val.toType();
1803817926 };
1803917927
18040 try sema.queueFullTypeResolution(error_field_ty);
18041
1804217928 // Build our list of Error values
1804317929 // Optional value is only null if anyerror
1804417930 // Value can be zero-length slice otherwise
......@@ -18089,7 +17975,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1808917975 };
1809017976
1809117977 // Build our ?[]const Error value
18092 const slice_errors_ty = try sema.ptrType(.{
17978 const slice_errors_ty = try mod.ptrTypeSema(.{
1809317979 .child = error_field_ty.toIntern(),
1809417980 .flags = .{
1809517981 .size = .Slice,
......@@ -18235,7 +18121,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1823518121 .ty = fields_array_ty.toIntern(),
1823618122 .storage = .{ .elems = enum_field_vals },
1823718123 } });
18238 const slice_ty = (try sema.ptrType(.{
18124 const slice_ty = (try mod.ptrTypeSema(.{
1823918125 .child = enum_field_ty.toIntern(),
1824018126 .flags = .{
1824118127 .size = .Slice,
......@@ -18315,7 +18201,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1831518201 break :t union_field_ty_decl.val.toType();
1831618202 };
1831718203
18318 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
18204 try ty.resolveLayout(mod); // Getting alignment requires type layout
1831918205 const union_obj = mod.typeToUnion(ty).?;
1832018206 const tag_type = union_obj.loadTagType(ip);
1832118207 const layout = union_obj.getLayout(ip);
......@@ -18351,7 +18237,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1835118237 };
1835218238
1835318239 const alignment = switch (layout) {
18354 .auto, .@"extern" => try sema.unionFieldAlignment(union_obj, @intCast(field_index)),
18240 .auto, .@"extern" => try mod.unionFieldNormalAlignmentAdvanced(union_obj, @intCast(field_index), .sema),
1835518241 .@"packed" => .none,
1835618242 };
1835718243
......@@ -18379,7 +18265,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1837918265 .ty = array_fields_ty.toIntern(),
1838018266 .storage = .{ .elems = union_field_vals },
1838118267 } });
18382 const slice_ty = (try sema.ptrType(.{
18268 const slice_ty = (try mod.ptrTypeSema(.{
1838318269 .child = union_field_ty.toIntern(),
1838418270 .flags = .{
1838518271 .size = .Slice,
......@@ -18412,7 +18298,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1841218298 const decl_index = (try sema.namespaceLookup(
1841318299 block,
1841418300 src,
18415 (try sema.getBuiltinType("Type")).getNamespaceIndex(mod),
18301 (try mod.getBuiltinType("Type")).getNamespaceIndex(mod),
1841618302 try ip.getOrPutString(gpa, "ContainerLayout", .no_embedded_nulls),
1841718303 )).?;
1841818304 try sema.ensureDeclAnalyzed(decl_index);
......@@ -18465,7 +18351,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1846518351 break :t struct_field_ty_decl.val.toType();
1846618352 };
1846718353
18468 try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
18354 try ty.resolveLayout(mod); // Getting alignment requires type layout
1846918355
1847018356 var struct_field_vals: []InternPool.Index = &.{};
1847118357 defer gpa.free(struct_field_vals);
......@@ -18505,7 +18391,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1850518391 } });
1850618392 };
1850718393
18508 try sema.resolveTypeLayout(Type.fromInterned(field_ty));
18394 try Type.fromInterned(field_ty).resolveLayout(mod);
1850918395
1851018396 const is_comptime = field_val != .none;
1851118397 const opt_default_val = if (is_comptime) Value.fromInterned(field_val) else null;
......@@ -18534,7 +18420,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1853418420 };
1853518421 struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
1853618422
18537 try sema.resolveStructFieldInits(ty);
18423 try ty.resolveStructFieldInits(mod);
1853818424
1853918425 for (struct_field_vals, 0..) |*field_val, field_index| {
1854018426 const field_name = if (struct_type.fieldName(ip, field_index).unwrap()) |field_name|
......@@ -18573,10 +18459,11 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1857318459 const default_val_ptr = try sema.optRefValue(opt_default_val);
1857418460 const alignment = switch (struct_type.layout) {
1857518461 .@"packed" => .none,
18576 else => try sema.structFieldAlignment(
18462 else => try mod.structFieldAlignmentAdvanced(
1857718463 struct_type.fieldAlign(ip, field_index),
1857818464 field_ty,
1857918465 struct_type.layout,
18466 .sema,
1858018467 ),
1858118468 };
1858218469
......@@ -18608,7 +18495,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1860818495 .ty = array_fields_ty.toIntern(),
1860918496 .storage = .{ .elems = struct_field_vals },
1861018497 } });
18611 const slice_ty = (try sema.ptrType(.{
18498 const slice_ty = (try mod.ptrTypeSema(.{
1861218499 .child = struct_field_ty.toIntern(),
1861318500 .flags = .{
1861418501 .size = .Slice,
......@@ -18644,7 +18531,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1864418531 const decl_index = (try sema.namespaceLookup(
1864518532 block,
1864618533 src,
18647 (try sema.getBuiltinType("Type")).getNamespaceIndex(mod),
18534 (try mod.getBuiltinType("Type")).getNamespaceIndex(mod),
1864818535 try ip.getOrPutString(gpa, "ContainerLayout", .no_embedded_nulls),
1864918536 )).?;
1865018537 try sema.ensureDeclAnalyzed(decl_index);
......@@ -18688,7 +18575,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
1868818575 break :t type_opaque_ty_decl.val.toType();
1868918576 };
1869018577
18691 try sema.resolveTypeFields(ty);
18578 try ty.resolveFields(mod);
1869218579 const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(mod));
1869318580
1869418581 const field_values = .{
......@@ -18730,7 +18617,6 @@ fn typeInfoDecls(
1873018617 const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index);
1873118618 break :t declaration_ty_decl.val.toType();
1873218619 };
18733 try sema.queueFullTypeResolution(declaration_ty);
1873418620
1873518621 var decl_vals = std.ArrayList(InternPool.Index).init(gpa);
1873618622 defer decl_vals.deinit();
......@@ -18748,7 +18634,7 @@ fn typeInfoDecls(
1874818634 .ty = array_decl_ty.toIntern(),
1874918635 .storage = .{ .elems = decl_vals.items },
1875018636 } });
18751 const slice_ty = (try sema.ptrType(.{
18637 const slice_ty = (try mod.ptrTypeSema(.{
1875218638 .child = declaration_ty.toIntern(),
1875318639 .flags = .{
1875418640 .size = .Slice,
......@@ -19348,7 +19234,7 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
1934819234
1934919235 const operand_ty = sema.typeOf(operand);
1935019236 const ptr_info = operand_ty.ptrInfo(mod);
19351 const res_ty = try sema.ptrType(.{
19237 const res_ty = try mod.ptrTypeSema(.{
1935219238 .child = err_union_ty.errorUnionPayload(mod).toIntern(),
1935319239 .flags = .{
1935419240 .is_const = ptr_info.flags.is_const,
......@@ -19581,11 +19467,11 @@ fn retWithErrTracing(
1958119467 else => true,
1958219468 };
1958319469 const gpa = sema.gpa;
19584 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
19585 try sema.resolveTypeFields(stack_trace_ty);
19470 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
19471 try stack_trace_ty.resolveFields(mod);
1958619472 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
1958719473 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
19588 const return_err_fn = try sema.getBuiltin("returnError");
19474 const return_err_fn = try mod.getBuiltin("returnError");
1958919475 const args: [1]Air.Inst.Ref = .{err_return_trace};
1959019476
1959119477 if (!need_check) {
......@@ -19788,7 +19674,7 @@ fn analyzeRet(
1978819674 return sema.failWithOwnedErrorMsg(block, msg);
1978919675 }
1979019676
19791 try sema.resolveTypeLayout(sema.fn_ret_ty);
19677 try sema.fn_ret_ty.resolveLayout(mod);
1979219678
1979319679 try sema.validateRuntimeValue(block, operand_src, operand);
1979419680
......@@ -19870,7 +19756,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1987019756 },
1987119757 else => {},
1987219758 }
19873 const align_bytes = (try val.getUnsignedIntAdvanced(mod, sema)).?;
19759 const align_bytes = (try val.getUnsignedIntAdvanced(mod, .sema)).?;
1987419760 break :blk try sema.validateAlignAllowZero(block, align_src, align_bytes);
1987519761 } else .none;
1987619762
......@@ -19904,7 +19790,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1990419790 elem_ty.fmt(mod), bit_offset, bit_offset - host_size * 8, host_size,
1990519791 });
1990619792 }
19907 const elem_bit_size = try elem_ty.bitSizeAdvanced(mod, sema);
19793 const elem_bit_size = try elem_ty.bitSizeAdvanced(mod, .sema);
1990819794 if (elem_bit_size > host_size * 8 - bit_offset) {
1990919795 return sema.fail(block, bitoffset_src, "packed type '{}' at bit offset {} ends {} bits after the end of a {} byte host integer", .{
1991019796 elem_ty.fmt(mod), bit_offset, elem_bit_size - (host_size * 8 - bit_offset), host_size,
......@@ -19945,7 +19831,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
1994519831 });
1994619832 }
1994719833
19948 const ty = try sema.ptrType(.{
19834 const ty = try mod.ptrTypeSema(.{
1994919835 .child = elem_ty.toIntern(),
1995019836 .sentinel = sentinel,
1995119837 .flags = .{
......@@ -20036,7 +19922,7 @@ fn structInitEmpty(
2003619922 const mod = sema.mod;
2003719923 const gpa = sema.gpa;
2003819924 // This logic must be synchronized with that in `zirStructInit`.
20039 try sema.resolveTypeFields(struct_ty);
19925 try struct_ty.resolveFields(mod);
2004019926
2004119927 // The init values to use for the struct instance.
2004219928 const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod));
......@@ -20107,7 +19993,6 @@ fn unionInit(
2010719993
2010819994 try sema.requireRuntimeBlock(block, init_src, null);
2010919995 _ = union_ty_src;
20110 try sema.queueFullTypeResolution(union_ty);
2011119996 return block.addUnionInit(union_ty, field_index, init);
2011219997}
2011319998
......@@ -20136,7 +20021,7 @@ fn zirStructInit(
2013620021 else => |e| return e,
2013720022 };
2013820023 const resolved_ty = result_ty.optEuBaseType(mod);
20139 try sema.resolveTypeLayout(resolved_ty);
20024 try resolved_ty.resolveLayout(mod);
2014020025
2014120026 if (resolved_ty.zigTypeTag(mod) == .Struct) {
2014220027 // This logic must be synchronized with that in `zirStructInitEmpty`.
......@@ -20177,7 +20062,7 @@ fn zirStructInit(
2017720062 const field_ty = resolved_ty.structFieldType(field_index, mod);
2017820063 field_inits[field_index] = try sema.coerce(block, field_ty, uncoerced_init, field_src);
2017920064 if (!is_packed) {
20180 try sema.resolveStructFieldInits(resolved_ty);
20065 try resolved_ty.resolveStructFieldInits(mod);
2018120066 if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| {
2018220067 const init_val = (try sema.resolveValue(field_inits[field_index])) orelse {
2018320068 return sema.failWithNeededComptime(block, field_src, .{
......@@ -20250,7 +20135,7 @@ fn zirStructInit(
2025020135
2025120136 if (is_ref) {
2025220137 const target = mod.getTarget();
20253 const alloc_ty = try sema.ptrType(.{
20138 const alloc_ty = try mod.ptrTypeSema(.{
2025420139 .child = result_ty.toIntern(),
2025520140 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2025620141 });
......@@ -20264,7 +20149,6 @@ fn zirStructInit(
2026420149 }
2026520150
2026620151 try sema.requireRuntimeBlock(block, src, null);
20267 try sema.queueFullTypeResolution(resolved_ty);
2026820152 const union_val = try block.addUnionInit(resolved_ty, field_index, init_inst);
2026920153 return sema.coerce(block, result_ty, union_val, src);
2027020154 }
......@@ -20341,7 +20225,7 @@ fn finishStructInit(
2034120225 continue;
2034220226 }
2034320227
20344 try sema.resolveStructFieldInits(struct_ty);
20228 try struct_ty.resolveStructFieldInits(mod);
2034520229
2034620230 const field_init = struct_type.fieldInit(ip, i);
2034720231 if (field_init == .none) {
......@@ -20411,9 +20295,9 @@ fn finishStructInit(
2041120295 }
2041220296
2041320297 if (is_ref) {
20414 try sema.resolveStructLayout(struct_ty);
20298 try struct_ty.resolveLayout(mod);
2041520299 const target = sema.mod.getTarget();
20416 const alloc_ty = try sema.ptrType(.{
20300 const alloc_ty = try mod.ptrTypeSema(.{
2041720301 .child = result_ty.toIntern(),
2041820302 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2041920303 });
......@@ -20433,8 +20317,7 @@ fn finishStructInit(
2043320317 .init_node_offset = init_src.offset.node_offset.x,
2043420318 .elem_index = @intCast(runtime_index),
2043520319 } }));
20436 try sema.resolveStructFieldInits(struct_ty);
20437 try sema.queueFullTypeResolution(struct_ty);
20320 try struct_ty.resolveStructFieldInits(mod);
2043820321 const struct_val = try block.addAggregateInit(struct_ty, field_inits);
2043920322 return sema.coerce(block, result_ty, struct_val, init_src);
2044020323}
......@@ -20543,7 +20426,7 @@ fn structInitAnon(
2054320426
2054420427 if (is_ref) {
2054520428 const target = mod.getTarget();
20546 const alloc_ty = try sema.ptrType(.{
20429 const alloc_ty = try mod.ptrTypeSema(.{
2054720430 .child = tuple_ty,
2054820431 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2054920432 });
......@@ -20557,7 +20440,7 @@ fn structInitAnon(
2055720440 };
2055820441 extra_index = item.end;
2055920442
20560 const field_ptr_ty = try sema.ptrType(.{
20443 const field_ptr_ty = try mod.ptrTypeSema(.{
2056120444 .child = field_ty,
2056220445 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2056320446 });
......@@ -20650,7 +20533,7 @@ fn zirArrayInit(
2065020533 dest.* = try sema.coerce(block, elem_ty, resolved_arg, elem_src);
2065120534 if (is_tuple) {
2065220535 if (array_ty.structFieldIsComptime(i, mod))
20653 try sema.resolveStructFieldInits(array_ty);
20536 try array_ty.resolveStructFieldInits(mod);
2065420537 if (try array_ty.structFieldValueComptime(mod, i)) |field_val| {
2065520538 const init_val = try sema.resolveValue(dest.*) orelse {
2065620539 return sema.failWithNeededComptime(block, elem_src, .{
......@@ -20694,11 +20577,10 @@ fn zirArrayInit(
2069420577 .init_node_offset = src.offset.node_offset.x,
2069520578 .elem_index = runtime_index,
2069620579 } }));
20697 try sema.queueFullTypeResolution(array_ty);
2069820580
2069920581 if (is_ref) {
2070020582 const target = mod.getTarget();
20701 const alloc_ty = try sema.ptrType(.{
20583 const alloc_ty = try mod.ptrTypeSema(.{
2070220584 .child = result_ty.toIntern(),
2070320585 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2070420586 });
......@@ -20707,7 +20589,7 @@ fn zirArrayInit(
2070720589
2070820590 if (is_tuple) {
2070920591 for (resolved_args, 0..) |arg, i| {
20710 const elem_ptr_ty = try sema.ptrType(.{
20592 const elem_ptr_ty = try mod.ptrTypeSema(.{
2071120593 .child = array_ty.structFieldType(i, mod).toIntern(),
2071220594 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2071320595 });
......@@ -20720,7 +20602,7 @@ fn zirArrayInit(
2072020602 return sema.makePtrConst(block, alloc);
2072120603 }
2072220604
20723 const elem_ptr_ty = try sema.ptrType(.{
20605 const elem_ptr_ty = try mod.ptrTypeSema(.{
2072420606 .child = array_ty.elemType2(mod).toIntern(),
2072520607 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2072620608 });
......@@ -20808,14 +20690,14 @@ fn arrayInitAnon(
2080820690
2080920691 if (is_ref) {
2081020692 const target = sema.mod.getTarget();
20811 const alloc_ty = try sema.ptrType(.{
20693 const alloc_ty = try mod.ptrTypeSema(.{
2081220694 .child = tuple_ty,
2081320695 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2081420696 });
2081520697 const alloc = try block.addTy(.alloc, alloc_ty);
2081620698 for (operands, 0..) |operand, i_usize| {
2081720699 const i: u32 = @intCast(i_usize);
20818 const field_ptr_ty = try sema.ptrType(.{
20700 const field_ptr_ty = try mod.ptrTypeSema(.{
2081920701 .child = types[i],
2082020702 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) },
2082120703 });
......@@ -20885,7 +20767,7 @@ fn fieldType(
2088520767 const ip = &mod.intern_pool;
2088620768 var cur_ty = aggregate_ty;
2088720769 while (true) {
20888 try sema.resolveTypeFields(cur_ty);
20770 try cur_ty.resolveFields(mod);
2088920771 switch (cur_ty.zigTypeTag(mod)) {
2089020772 .Struct => switch (ip.indexToKey(cur_ty.toIntern())) {
2089120773 .anon_struct_type => |anon_struct| {
......@@ -20936,8 +20818,8 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
2093620818fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
2093720819 const mod = sema.mod;
2093820820 const ip = &mod.intern_pool;
20939 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
20940 try sema.resolveTypeFields(stack_trace_ty);
20821 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
20822 try stack_trace_ty.resolveFields(mod);
2094120823 const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
2094220824 const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
2094320825
......@@ -20971,9 +20853,6 @@ fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2097120853 return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)});
2097220854 }
2097320855 const val = try ty.lazyAbiAlignment(mod);
20974 if (val.isLazyAlign(mod)) {
20975 try sema.queueFullTypeResolution(ty);
20976 }
2097720856 return Air.internedToRef(val.toIntern());
2097820857}
2097920858
......@@ -21148,7 +21027,7 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
2114821027 const mod = sema.mod;
2114921028 const ip = &mod.intern_pool;
2115021029
21151 try sema.resolveTypeLayout(operand_ty);
21030 try operand_ty.resolveLayout(mod);
2115221031 const enum_ty = switch (operand_ty.zigTypeTag(mod)) {
2115321032 .EnumLiteral => {
2115421033 const val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, operand, undefined);
......@@ -21224,7 +21103,7 @@ fn zirReify(
2122421103 },
2122521104 },
2122621105 };
21227 const type_info_ty = try sema.getBuiltinType("Type");
21106 const type_info_ty = try mod.getBuiltinType("Type");
2122821107 const uncasted_operand = try sema.resolveInst(extra.operand);
2122921108 const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
2123021109 const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{
......@@ -21258,7 +21137,7 @@ fn zirReify(
2125821137 );
2125921138
2126021139 const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
21261 const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema));
21140 const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(mod));
2126221141 const ty = try mod.intType(signedness, bits);
2126321142 return Air.internedToRef(ty.toIntern());
2126421143 },
......@@ -21273,7 +21152,7 @@ fn zirReify(
2127321152 try ip.getOrPutString(gpa, "child", .no_embedded_nulls),
2127421153 ).?);
2127521154
21276 const len: u32 = @intCast(try len_val.toUnsignedIntAdvanced(sema));
21155 const len: u32 = @intCast(try len_val.toUnsignedIntSema(mod));
2127721156 const child_ty = child_val.toType();
2127821157
2127921158 try sema.checkVectorElemType(block, src, child_ty);
......@@ -21291,7 +21170,7 @@ fn zirReify(
2129121170 try ip.getOrPutString(gpa, "bits", .no_embedded_nulls),
2129221171 ).?);
2129321172
21294 const bits: u16 = @intCast(try bits_val.toUnsignedIntAdvanced(sema));
21173 const bits: u16 = @intCast(try bits_val.toUnsignedIntSema(mod));
2129521174 const ty = switch (bits) {
2129621175 16 => Type.f16,
2129721176 32 => Type.f32,
......@@ -21341,7 +21220,7 @@ fn zirReify(
2134121220 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
2134221221 }
2134321222
21344 const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
21223 const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, .sema)).?;
2134521224 if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
2134621225 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{alignment_val_int});
2134721226 }
......@@ -21349,7 +21228,7 @@ fn zirReify(
2134921228
2135021229 const elem_ty = child_val.toType();
2135121230 if (abi_align != .none) {
21352 try sema.resolveTypeLayout(elem_ty);
21231 try elem_ty.resolveLayout(mod);
2135321232 }
2135421233
2135521234 const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val);
......@@ -21393,7 +21272,7 @@ fn zirReify(
2139321272 }
2139421273 }
2139521274
21396 const ty = try sema.ptrType(.{
21275 const ty = try mod.ptrTypeSema(.{
2139721276 .child = elem_ty.toIntern(),
2139821277 .sentinel = actual_sentinel,
2139921278 .flags = .{
......@@ -21422,7 +21301,7 @@ fn zirReify(
2142221301 try ip.getOrPutString(gpa, "sentinel", .no_embedded_nulls),
2142321302 ).?);
2142421303
21425 const len = try len_val.toUnsignedIntAdvanced(sema);
21304 const len = try len_val.toUnsignedIntSema(mod);
2142621305 const child_ty = child_val.toType();
2142721306 const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: {
2142821307 const ptr_ty = try mod.singleMutPtrType(child_ty);
......@@ -21529,7 +21408,7 @@ fn zirReify(
2152921408 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
2153021409
2153121410 // Decls
21532 if (try decls_val.sliceLen(sema) > 0) {
21411 if (try decls_val.sliceLen(mod) > 0) {
2153321412 return sema.fail(block, src, "reified structs must have no decls", .{});
2153421413 }
2153521414
......@@ -21562,7 +21441,7 @@ fn zirReify(
2156221441 try ip.getOrPutString(gpa, "is_exhaustive", .no_embedded_nulls),
2156321442 ).?);
2156421443
21565 if (try decls_val.sliceLen(sema) > 0) {
21444 if (try decls_val.sliceLen(mod) > 0) {
2156621445 return sema.fail(block, src, "reified enums must have no decls", .{});
2156721446 }
2156821447
......@@ -21580,7 +21459,7 @@ fn zirReify(
2158021459 ).?);
2158121460
2158221461 // Decls
21583 if (try decls_val.sliceLen(sema) > 0) {
21462 if (try decls_val.sliceLen(mod) > 0) {
2158421463 return sema.fail(block, src, "reified opaque must have no decls", .{});
2158521464 }
2158621465
......@@ -21628,7 +21507,7 @@ fn zirReify(
2162821507 try ip.getOrPutString(gpa, "decls", .no_embedded_nulls),
2162921508 ).?);
2163021509
21631 if (try decls_val.sliceLen(sema) > 0) {
21510 if (try decls_val.sliceLen(mod) > 0) {
2163221511 return sema.fail(block, src, "reified unions must have no decls", .{});
2163321512 }
2163421513 const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
......@@ -21987,7 +21866,7 @@ fn reifyUnion(
2198721866
2198821867 field_ty.* = field_type_val.toIntern();
2198921868 if (any_aligns) {
21990 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
21869 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntSema(mod);
2199121870 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
2199221871 // TODO: better source location
2199321872 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
......@@ -22032,7 +21911,7 @@ fn reifyUnion(
2203221911
2203321912 field_ty.* = field_type_val.toIntern();
2203421913 if (any_aligns) {
22035 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
21914 const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntSema(mod);
2203621915 if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
2203721916 // TODO: better source location
2203821917 return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
......@@ -22089,6 +21968,8 @@ fn reifyUnion(
2208921968 loaded_union.flagsPtr(ip).status = .have_field_types;
2209021969
2209121970 try mod.finalizeAnonDecl(new_decl_index);
21971 try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index });
21972 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index }));
2209221973 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
2209321974}
2209421975
......@@ -22162,7 +22043,7 @@ fn reifyStruct(
2216222043
2216322044 if (field_is_comptime) any_comptime_fields = true;
2216422045 if (field_default_value != .none) any_default_inits = true;
22165 switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, sema)) {
22046 switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, .sema)) {
2216622047 .eq => {},
2216722048 .gt => any_aligned_fields = true,
2216822049 .lt => unreachable,
......@@ -22245,7 +22126,7 @@ fn reifyStruct(
2224522126 return sema.fail(block, src, "alignment must fit in 'u32'", .{});
2224622127 }
2224722128
22248 const byte_align = try field_alignment_val.toUnsignedIntAdvanced(sema);
22129 const byte_align = try field_alignment_val.toUnsignedIntSema(mod);
2224922130 if (byte_align == 0) {
2225022131 if (layout != .@"packed") {
2225122132 struct_type.field_aligns.get(ip)[field_idx] = .none;
......@@ -22331,7 +22212,7 @@ fn reifyStruct(
2233122212 var fields_bit_sum: u64 = 0;
2233222213 for (0..struct_type.field_types.len) |field_idx| {
2233322214 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_idx]);
22334 sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
22215 field_ty.resolveLayout(mod) catch |err| switch (err) {
2233522216 error.AnalysisFail => {
2233622217 const msg = sema.err orelse return err;
2233722218 try sema.errNote(src, msg, "while checking a field of this struct", .{});
......@@ -22353,11 +22234,13 @@ fn reifyStruct(
2235322234 }
2235422235
2235522236 try mod.finalizeAnonDecl(new_decl_index);
22237 try mod.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index });
22238 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = new_decl_index }));
2235622239 return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
2235722240}
2235822241
2235922242fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
22360 const va_list_ty = try sema.getBuiltinType("VaList");
22243 const va_list_ty = try sema.mod.getBuiltinType("VaList");
2236122244 const va_list_ptr = try sema.mod.singleMutPtrType(va_list_ty);
2236222245
2236322246 const inst = try sema.resolveInst(zir_ref);
......@@ -22396,7 +22279,7 @@ fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
2239622279 const va_list_src = block.builtinCallArgSrc(extra.node, 0);
2239722280
2239822281 const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
22399 const va_list_ty = try sema.getBuiltinType("VaList");
22282 const va_list_ty = try sema.mod.getBuiltinType("VaList");
2240022283
2240122284 try sema.requireRuntimeBlock(block, src, null);
2240222285 return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref);
......@@ -22416,7 +22299,7 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
2241622299fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
2241722300 const src = block.nodeOffset(@bitCast(extended.operand));
2241822301
22419 const va_list_ty = try sema.getBuiltinType("VaList");
22302 const va_list_ty = try sema.mod.getBuiltinType("VaList");
2242022303 try sema.requireRuntimeBlock(block, src, null);
2242122304 return block.addInst(.{
2242222305 .tag = .c_va_start,
......@@ -22550,7 +22433,7 @@ fn zirFloatFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
2255022433 _ = try sema.checkIntType(block, operand_src, operand_scalar_ty);
2255122434
2255222435 if (try sema.resolveValue(operand)) |operand_val| {
22553 const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, mod, sema);
22436 const result_val = try operand_val.floatFromIntAdvanced(sema.arena, operand_ty, dest_ty, mod, .sema);
2255422437 return Air.internedToRef(result_val.toIntern());
2255522438 } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeFloat) {
2255622439 return sema.failWithNeededComptime(block, operand_src, .{
......@@ -22598,7 +22481,7 @@ fn zirPtrFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
2259822481 try sema.checkPtrType(block, src, ptr_ty, true);
2259922482
2260022483 const elem_ty = ptr_ty.elemType2(mod);
22601 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
22484 const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, .sema);
2260222485
2260322486 if (ptr_ty.isSlice(mod)) {
2260422487 const msg = msg: {
......@@ -22697,7 +22580,7 @@ fn ptrFromIntVal(
2269722580 }
2269822581 return sema.failWithUseOfUndef(block, operand_src);
2269922582 }
22700 const addr = try operand_val.toUnsignedIntAdvanced(sema);
22583 const addr = try operand_val.toUnsignedIntSema(zcu);
2270122584 if (!ptr_ty.isAllowzeroPtr(zcu) and addr == 0)
2270222585 return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(zcu)});
2270322586 if (addr != 0 and ptr_align != .none and !ptr_align.check(addr))
......@@ -22895,8 +22778,8 @@ fn ptrCastFull(
2289522778 const src_info = operand_ty.ptrInfo(mod);
2289622779 const dest_info = dest_ty.ptrInfo(mod);
2289722780
22898 try sema.resolveTypeLayout(Type.fromInterned(src_info.child));
22899 try sema.resolveTypeLayout(Type.fromInterned(dest_info.child));
22781 try Type.fromInterned(src_info.child).resolveLayout(mod);
22782 try Type.fromInterned(dest_info.child).resolveLayout(mod);
2290022783
2290122784 const src_slice_like = src_info.flags.size == .Slice or
2290222785 (src_info.flags.size == .One and Type.fromInterned(src_info.child).zigTypeTag(mod) == .Array);
......@@ -23144,7 +23027,7 @@ fn ptrCastFull(
2314423027 // Only convert to a many-pointer at first
2314523028 var info = dest_info;
2314623029 info.flags.size = .Many;
23147 const ty = try sema.ptrType(info);
23030 const ty = try mod.ptrTypeSema(info);
2314823031 if (dest_ty.zigTypeTag(mod) == .Optional) {
2314923032 break :blk try mod.optionalType(ty.toIntern());
2315023033 } else {
......@@ -23162,7 +23045,7 @@ fn ptrCastFull(
2316223045 return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
2316323046 }
2316423047 if (dest_align.compare(.gt, src_align)) {
23165 if (try ptr_val.getUnsignedIntAdvanced(mod, null)) |addr| {
23048 if (try ptr_val.getUnsignedIntAdvanced(mod, .sema)) |addr| {
2316623049 if (!dest_align.check(addr)) {
2316723050 return sema.fail(block, operand_src, "pointer address 0x{X} is not aligned to {d} bytes", .{
2316823051 addr,
......@@ -23229,7 +23112,7 @@ fn ptrCastFull(
2322923112 // We can't change address spaces with a bitcast, so this requires two instructions
2323023113 var intermediate_info = src_info;
2323123114 intermediate_info.flags.address_space = dest_info.flags.address_space;
23232 const intermediate_ptr_ty = try sema.ptrType(intermediate_info);
23115 const intermediate_ptr_ty = try mod.ptrTypeSema(intermediate_info);
2323323116 const intermediate_ty = if (dest_ptr_ty.zigTypeTag(mod) == .Optional) blk: {
2323423117 break :blk try mod.optionalType(intermediate_ptr_ty.toIntern());
2323523118 } else intermediate_ptr_ty;
......@@ -23286,7 +23169,7 @@ fn zirPtrCastNoDest(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
2328623169 if (flags.volatile_cast) ptr_info.flags.is_volatile = false;
2328723170
2328823171 const dest_ty = blk: {
23289 const dest_ty = try sema.ptrType(ptr_info);
23172 const dest_ty = try mod.ptrTypeSema(ptr_info);
2329023173 if (operand_ty.zigTypeTag(mod) == .Optional) {
2329123174 break :blk try mod.optionalType(dest_ty.toIntern());
2329223175 }
......@@ -23576,7 +23459,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
2357623459
2357723460 const mod = sema.mod;
2357823461 const ip = &mod.intern_pool;
23579 try sema.resolveTypeLayout(ty);
23462 try ty.resolveLayout(mod);
2358023463 switch (ty.zigTypeTag(mod)) {
2358123464 .Struct => {},
2358223465 else => return sema.fail(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(mod)}),
......@@ -23819,7 +23702,7 @@ fn checkAtomicPtrOperand(
2381923702 const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) {
2382023703 .Pointer => ptr_ty.ptrInfo(mod),
2382123704 else => {
23822 const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data);
23705 const wanted_ptr_ty = try mod.ptrTypeSema(wanted_ptr_data);
2382323706 _ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
2382423707 unreachable;
2382523708 },
......@@ -23829,7 +23712,7 @@ fn checkAtomicPtrOperand(
2382923712 wanted_ptr_data.flags.is_allowzero = ptr_data.flags.is_allowzero;
2383023713 wanted_ptr_data.flags.is_volatile = ptr_data.flags.is_volatile;
2383123714
23832 const wanted_ptr_ty = try sema.ptrType(wanted_ptr_data);
23715 const wanted_ptr_ty = try mod.ptrTypeSema(wanted_ptr_data);
2383323716 const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
2383423717
2383523718 return casted_ptr;
......@@ -24006,7 +23889,7 @@ fn resolveExportOptions(
2400623889 const mod = sema.mod;
2400723890 const gpa = sema.gpa;
2400823891 const ip = &mod.intern_pool;
24009 const export_options_ty = try sema.getBuiltinType("ExportOptions");
23892 const export_options_ty = try mod.getBuiltinType("ExportOptions");
2401023893 const air_ref = try sema.resolveInst(zir_ref);
2401123894 const options = try sema.coerce(block, export_options_ty, air_ref, src);
2401223895
......@@ -24070,7 +23953,7 @@ fn resolveBuiltinEnum(
2407023953 reason: NeededComptimeReason,
2407123954) CompileError!@field(std.builtin, name) {
2407223955 const mod = sema.mod;
24073 const ty = try sema.getBuiltinType(name);
23956 const ty = try mod.getBuiltinType(name);
2407423957 const air_ref = try sema.resolveInst(zir_ref);
2407523958 const coerced = try sema.coerce(block, ty, air_ref, src);
2407623959 const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
......@@ -24830,7 +24713,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
2483024713 const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
2483124714 const func = try sema.resolveInst(extra.callee);
2483224715
24833 const modifier_ty = try sema.getBuiltinType("CallModifier");
24716 const modifier_ty = try mod.getBuiltinType("CallModifier");
2483424717 const air_ref = try sema.resolveInst(extra.modifier);
2483524718 const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src);
2483624719 const modifier_val = try sema.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{
......@@ -24934,7 +24817,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2493424817 .Struct, .Union => {},
2493524818 else => return sema.fail(block, inst_src, "expected pointer to struct or union type, found '{}'", .{parent_ptr_ty.fmt(zcu)}),
2493624819 }
24937 try sema.resolveTypeLayout(parent_ty);
24820 try parent_ty.resolveLayout(zcu);
2493824821
2493924822 const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, .{
2494024823 .needed_comptime_reason = "field name must be comptime-known",
......@@ -24965,7 +24848,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2496524848 var actual_parent_ptr_info: InternPool.Key.PtrType = .{
2496624849 .child = parent_ty.toIntern(),
2496724850 .flags = .{
24968 .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema),
24851 .alignment = try parent_ptr_ty.ptrAlignmentAdvanced(zcu, .sema),
2496924852 .is_const = field_ptr_info.flags.is_const,
2497024853 .is_volatile = field_ptr_info.flags.is_volatile,
2497124854 .is_allowzero = field_ptr_info.flags.is_allowzero,
......@@ -24977,7 +24860,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2497724860 var actual_field_ptr_info: InternPool.Key.PtrType = .{
2497824861 .child = field_ty.toIntern(),
2497924862 .flags = .{
24980 .alignment = try field_ptr_ty.ptrAlignmentAdvanced(zcu, sema),
24863 .alignment = try field_ptr_ty.ptrAlignmentAdvanced(zcu, .sema),
2498124864 .is_const = field_ptr_info.flags.is_const,
2498224865 .is_volatile = field_ptr_info.flags.is_volatile,
2498324866 .is_allowzero = field_ptr_info.flags.is_allowzero,
......@@ -24988,12 +24871,13 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2498824871 switch (parent_ty.containerLayout(zcu)) {
2498924872 .auto => {
2499024873 actual_parent_ptr_info.flags.alignment = actual_field_ptr_info.flags.alignment.minStrict(
24991 if (zcu.typeToStruct(parent_ty)) |struct_obj| try sema.structFieldAlignment(
24874 if (zcu.typeToStruct(parent_ty)) |struct_obj| try zcu.structFieldAlignmentAdvanced(
2499224875 struct_obj.fieldAlign(ip, field_index),
2499324876 field_ty,
2499424877 struct_obj.layout,
24878 .sema,
2499524879 ) else if (zcu.typeToUnion(parent_ty)) |union_obj|
24996 try sema.unionFieldAlignment(union_obj, field_index)
24880 try zcu.unionFieldNormalAlignmentAdvanced(union_obj, field_index, .sema)
2499724881 else
2499824882 actual_field_ptr_info.flags.alignment,
2499924883 );
......@@ -25023,9 +24907,9 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2502324907 },
2502424908 }
2502524909
25026 const actual_field_ptr_ty = try sema.ptrType(actual_field_ptr_info);
24910 const actual_field_ptr_ty = try zcu.ptrTypeSema(actual_field_ptr_info);
2502724911 const casted_field_ptr = try sema.coerce(block, actual_field_ptr_ty, field_ptr, field_ptr_src);
25028 const actual_parent_ptr_ty = try sema.ptrType(actual_parent_ptr_info);
24912 const actual_parent_ptr_ty = try zcu.ptrTypeSema(actual_parent_ptr_info);
2502924913
2503024914 const result = if (try sema.resolveDefinedValue(block, field_ptr_src, casted_field_ptr)) |field_ptr_val| result: {
2503124915 switch (parent_ty.zigTypeTag(zcu)) {
......@@ -25085,7 +24969,6 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Ins
2508524969 break :result try sema.coerce(block, actual_parent_ptr_ty, Air.internedToRef(field.base), inst_src);
2508624970 } else result: {
2508724971 try sema.requireRuntimeBlock(block, inst_src, field_ptr_src);
25088 try sema.queueFullTypeResolution(parent_ty);
2508924972 break :result try block.addInst(.{
2509024973 .tag = .field_parent_ptr,
2509124974 .data = .{ .ty_pl = .{
......@@ -25398,7 +25281,7 @@ fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !A
2539825281 // Already an array pointer.
2539925282 return ptr;
2540025283 }
25401 const new_ty = try sema.ptrType(.{
25284 const new_ty = try mod.ptrTypeSema(.{
2540225285 .child = (try mod.arrayType(.{
2540325286 .len = len,
2540425287 .sentinel = info.sentinel,
......@@ -25497,7 +25380,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2549725380 const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
2549825381 if (!sema.isComptimeMutablePtr(dest_ptr_val)) break :rs dest_src;
2549925382 if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {
25500 const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?;
25383 const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, .sema)).?;
2550125384 const len = try sema.usizeCast(block, dest_src, len_u64);
2550225385 for (0..len) |i| {
2550325386 const elem_index = try mod.intRef(Type.usize, i);
......@@ -25556,7 +25439,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2555625439 var new_dest_ptr = dest_ptr;
2555725440 var new_src_ptr = src_ptr;
2555825441 if (len_val) |val| {
25559 const len = try val.toUnsignedIntAdvanced(sema);
25442 const len = try val.toUnsignedIntSema(mod);
2556025443 if (len == 0) {
2556125444 // This AIR instruction guarantees length > 0 if it is comptime-known.
2556225445 return;
......@@ -25603,7 +25486,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2560325486 assert(dest_manyptr_ty_key.flags.size == .One);
2560425487 dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
2560525488 dest_manyptr_ty_key.flags.size = .Many;
25606 break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
25489 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrTypeSema(dest_manyptr_ty_key), new_dest_ptr, dest_src);
2560725490 } else new_dest_ptr;
2560825491
2560925492 const new_src_ptr_ty = sema.typeOf(new_src_ptr);
......@@ -25614,7 +25497,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2561425497 assert(src_manyptr_ty_key.flags.size == .One);
2561525498 src_manyptr_ty_key.child = src_elem_ty.toIntern();
2561625499 src_manyptr_ty_key.flags.size = .Many;
25617 break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
25500 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrTypeSema(src_manyptr_ty_key), new_src_ptr, src_src);
2561825501 } else new_src_ptr;
2561925502
2562025503 // ok1: dest >= src + len
......@@ -25681,7 +25564,7 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
2568125564 const ptr_val = try sema.resolveDefinedValue(block, dest_src, dest_ptr) orelse break :rs dest_src;
2568225565 const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len", .no_embedded_nulls), dest_src);
2568325566 const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse break :rs dest_src;
25684 const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?;
25567 const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, .sema)).?;
2568525568 const len = try sema.usizeCast(block, dest_src, len_u64);
2568625569 if (len == 0) {
2568725570 // This AIR instruction guarantees length > 0 if it is comptime-known.
......@@ -25861,7 +25744,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2586125744 if (val.isGenericPoison()) {
2586225745 break :blk null;
2586325746 }
25864 const alignment = try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntAdvanced(sema));
25747 const alignment = try sema.validateAlignAllowZero(block, align_src, try val.toUnsignedIntSema(mod));
2586525748 const default = target_util.defaultFunctionAlignment(target);
2586625749 break :blk if (alignment == default) .none else alignment;
2586725750 } else if (extra.data.bits.has_align_ref) blk: {
......@@ -25881,7 +25764,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2588125764 error.GenericPoison => break :blk null,
2588225765 else => |e| return e,
2588325766 };
25884 const alignment = try sema.validateAlignAllowZero(block, align_src, try align_val.toUnsignedIntAdvanced(sema));
25767 const alignment = try sema.validateAlignAllowZero(block, align_src, try align_val.toUnsignedIntSema(mod));
2588525768 const default = target_util.defaultFunctionAlignment(target);
2588625769 break :blk if (alignment == default) .none else alignment;
2588725770 } else .none;
......@@ -25957,7 +25840,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
2595725840 const body = sema.code.bodySlice(extra_index, body_len);
2595825841 extra_index += body.len;
2595925842
25960 const cc_ty = try sema.getBuiltinType("CallingConvention");
25843 const cc_ty = try mod.getBuiltinType("CallingConvention");
2596125844 const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, .{
2596225845 .needed_comptime_reason = "calling convention must be comptime-known",
2596325846 });
......@@ -26170,7 +26053,7 @@ fn resolvePrefetchOptions(
2617026053 const mod = sema.mod;
2617126054 const gpa = sema.gpa;
2617226055 const ip = &mod.intern_pool;
26173 const options_ty = try sema.getBuiltinType("PrefetchOptions");
26056 const options_ty = try mod.getBuiltinType("PrefetchOptions");
2617426057 const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
2617526058
2617626059 const rw_src = block.src(.{ .init_field_rw = src.offset.node_offset_builtin_call_arg.builtin_call_node });
......@@ -26194,7 +26077,7 @@ fn resolvePrefetchOptions(
2619426077
2619526078 return std.builtin.PrefetchOptions{
2619626079 .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val),
26197 .locality = @intCast(try locality_val.toUnsignedIntAdvanced(sema)),
26080 .locality = @intCast(try locality_val.toUnsignedIntSema(mod)),
2619826081 .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val),
2619926082 };
2620026083}
......@@ -26242,7 +26125,7 @@ fn resolveExternOptions(
2624226125 const gpa = sema.gpa;
2624326126 const ip = &mod.intern_pool;
2624426127 const options_inst = try sema.resolveInst(zir_ref);
26245 const extern_options_ty = try sema.getBuiltinType("ExternOptions");
26128 const extern_options_ty = try mod.getBuiltinType("ExternOptions");
2624626129 const options = try sema.coerce(block, extern_options_ty, options_inst, src);
2624726130
2624826131 const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
......@@ -26493,7 +26376,7 @@ fn explainWhyTypeIsComptime(
2649326376 var type_set = TypeSet{};
2649426377 defer type_set.deinit(sema.gpa);
2649526378
26496 try sema.resolveTypeFully(ty);
26379 try ty.resolveFully(sema.mod);
2649726380 return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set);
2649826381}
2649926382
......@@ -26620,7 +26503,7 @@ const ExternPosition = enum {
2662026503
2662126504/// Returns true if `ty` is allowed in extern types.
2662226505/// Does *NOT* require `ty` to be resolved in any way.
26623/// Calls `resolveTypeLayout` for packed containers.
26506/// Calls `resolveLayout` for packed containers.
2662426507fn validateExternType(
2662526508 sema: *Sema,
2662626509 ty: Type,
......@@ -26671,7 +26554,7 @@ fn validateExternType(
2667126554 .Struct, .Union => switch (ty.containerLayout(mod)) {
2667226555 .@"extern" => return true,
2667326556 .@"packed" => {
26674 const bit_size = try ty.bitSizeAdvanced(mod, sema);
26557 const bit_size = try ty.bitSizeAdvanced(mod, .sema);
2667526558 switch (bit_size) {
2667626559 0, 8, 16, 32, 64, 128 => return true,
2667726560 else => return false,
......@@ -26849,11 +26732,11 @@ fn explainWhyTypeIsNotPacked(
2684926732 }
2685026733}
2685126734
26852fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
26735fn prepareSimplePanic(sema: *Sema) !void {
2685326736 const mod = sema.mod;
2685426737
2685526738 if (mod.panic_func_index == .none) {
26856 const decl_index = (try sema.getBuiltinDecl(block, "panic"));
26739 const decl_index = (try mod.getBuiltinDecl("panic"));
2685726740 // decl_index may be an alias; we must find the decl that actually
2685826741 // owns the function.
2685926742 try sema.ensureDeclAnalyzed(decl_index);
......@@ -26866,10 +26749,10 @@ fn prepareSimplePanic(sema: *Sema, block: *Block) !void {
2686626749 }
2686726750
2686826751 if (mod.null_stack_trace == .none) {
26869 const stack_trace_ty = try sema.getBuiltinType("StackTrace");
26870 try sema.resolveTypeFields(stack_trace_ty);
26752 const stack_trace_ty = try mod.getBuiltinType("StackTrace");
26753 try stack_trace_ty.resolveFields(mod);
2687126754 const target = mod.getTarget();
26872 const ptr_stack_trace_ty = try sema.ptrType(.{
26755 const ptr_stack_trace_ty = try mod.ptrTypeSema(.{
2687326756 .child = stack_trace_ty.toIntern(),
2687426757 .flags = .{
2687526758 .address_space = target_util.defaultAddressSpace(target, .global_constant),
......@@ -26891,9 +26774,9 @@ fn preparePanicId(sema: *Sema, block: *Block, panic_id: Module.PanicId) !InternP
2689126774 const gpa = sema.gpa;
2689226775 if (mod.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x;
2689326776
26894 try sema.prepareSimplePanic(block);
26777 try sema.prepareSimplePanic();
2689526778
26896 const panic_messages_ty = try sema.getBuiltinType("panic_messages");
26779 const panic_messages_ty = try mod.getBuiltinType("panic_messages");
2689726780 const msg_decl_index = (sema.namespaceLookup(
2689826781 block,
2689926782 LazySrcLoc.unneeded,
......@@ -26999,7 +26882,7 @@ fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.
2699926882 return;
2700026883 }
2700126884
27002 try sema.prepareSimplePanic(block);
26885 try sema.prepareSimplePanic();
2700326886
2700426887 const panic_func = mod.funcInfo(mod.panic_func_index);
2700526888 const panic_fn = try sema.analyzeDeclVal(block, src, panic_func.owner_decl);
......@@ -27045,7 +26928,7 @@ fn panicUnwrapError(
2704526928 if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
2704626929 _ = try fail_block.addNoOp(.trap);
2704726930 } else {
27048 const panic_fn = try sema.getBuiltin("panicUnwrapError");
26931 const panic_fn = try sema.mod.getBuiltin("panicUnwrapError");
2704926932 const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
2705026933 const err_return_trace = try sema.getErrorReturnTrace(&fail_block);
2705126934 const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
......@@ -27104,7 +26987,7 @@ fn panicSentinelMismatch(
2710426987 const actual_sentinel = if (ptr_ty.isSlice(mod))
2710526988 try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
2710626989 else blk: {
27107 const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
26990 const elem_ptr_ty = try ptr_ty.elemPtrType(null, mod);
2710826991 const sentinel_ptr = try parent_block.addPtrElemPtr(ptr, sentinel_index, elem_ptr_ty);
2710926992 break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
2711026993 };
......@@ -27122,7 +27005,7 @@ fn panicSentinelMismatch(
2712227005 } else if (sentinel_ty.isSelfComparable(mod, true))
2712327006 try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel)
2712427007 else {
27125 const panic_fn = try sema.getBuiltin("checkNonScalarSentinel");
27008 const panic_fn = try mod.getBuiltin("checkNonScalarSentinel");
2712627009 const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
2712727010 try sema.callBuiltin(parent_block, src, panic_fn, .auto, &args, .@"safety check");
2712827011 return;
......@@ -27161,7 +27044,7 @@ fn safetyCheckFormatted(
2716127044 if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
2716227045 _ = try fail_block.addNoOp(.trap);
2716327046 } else {
27164 const panic_fn = try sema.getBuiltin(func);
27047 const panic_fn = try sema.mod.getBuiltin(func);
2716527048 try sema.callBuiltin(&fail_block, src, panic_fn, .auto, args, .@"safety check");
2716627049 }
2716727050 try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
......@@ -27223,7 +27106,7 @@ fn fieldVal(
2722327106 return Air.internedToRef((try mod.intValue(Type.usize, inner_ty.arrayLen(mod))).toIntern());
2722427107 } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
2722527108 const ptr_info = object_ty.ptrInfo(mod);
27226 const result_ty = try sema.ptrType(.{
27109 const result_ty = try mod.ptrTypeSema(.{
2722727110 .child = Type.fromInterned(ptr_info.child).childType(mod).toIntern(),
2722827111 .sentinel = if (inner_ty.sentinel(mod)) |s| s.toIntern() else .none,
2722927112 .flags = .{
......@@ -27320,7 +27203,7 @@ fn fieldVal(
2732027203 if (try sema.namespaceLookupVal(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| {
2732127204 return inst;
2732227205 }
27323 try sema.resolveTypeFields(child_type);
27206 try child_type.resolveFields(mod);
2732427207 if (child_type.unionTagType(mod)) |enum_ty| {
2732527208 if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| {
2732627209 const field_index: u32 = @intCast(field_index_usize);
......@@ -27414,7 +27297,7 @@ fn fieldPtr(
2741427297 return anonDeclRef(sema, int_val.toIntern());
2741527298 } else if (field_name.eqlSlice("ptr", ip) and is_pointer_to) {
2741627299 const ptr_info = object_ty.ptrInfo(mod);
27417 const new_ptr_ty = try sema.ptrType(.{
27300 const new_ptr_ty = try mod.ptrTypeSema(.{
2741827301 .child = Type.fromInterned(ptr_info.child).childType(mod).toIntern(),
2741927302 .sentinel = if (object_ty.sentinel(mod)) |s| s.toIntern() else .none,
2742027303 .flags = .{
......@@ -27429,7 +27312,7 @@ fn fieldPtr(
2742927312 .packed_offset = ptr_info.packed_offset,
2743027313 });
2743127314 const ptr_ptr_info = object_ptr_ty.ptrInfo(mod);
27432 const result_ty = try sema.ptrType(.{
27315 const result_ty = try mod.ptrTypeSema(.{
2743327316 .child = new_ptr_ty.toIntern(),
2743427317 .sentinel = if (object_ptr_ty.sentinel(mod)) |s| s.toIntern() else .none,
2743527318 .flags = .{
......@@ -27463,7 +27346,7 @@ fn fieldPtr(
2746327346 if (field_name.eqlSlice("ptr", ip)) {
2746427347 const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);
2746527348
27466 const result_ty = try sema.ptrType(.{
27349 const result_ty = try mod.ptrTypeSema(.{
2746727350 .child = slice_ptr_ty.toIntern(),
2746827351 .flags = .{
2746927352 .is_const = !attr_ptr_ty.ptrIsMutable(mod),
......@@ -27473,7 +27356,7 @@ fn fieldPtr(
2747327356 });
2747427357
2747527358 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
27476 return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, sema)).toIntern());
27359 return Air.internedToRef((try val.ptrField(Value.slice_ptr_index, mod)).toIntern());
2747727360 }
2747827361 try sema.requireRuntimeBlock(block, src, null);
2747927362
......@@ -27481,7 +27364,7 @@ fn fieldPtr(
2748127364 try sema.checkKnownAllocPtr(block, inner_ptr, field_ptr);
2748227365 return field_ptr;
2748327366 } else if (field_name.eqlSlice("len", ip)) {
27484 const result_ty = try sema.ptrType(.{
27367 const result_ty = try mod.ptrTypeSema(.{
2748527368 .child = .usize_type,
2748627369 .flags = .{
2748727370 .is_const = !attr_ptr_ty.ptrIsMutable(mod),
......@@ -27491,7 +27374,7 @@ fn fieldPtr(
2749127374 });
2749227375
2749327376 if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
27494 return Air.internedToRef((try val.ptrField(Value.slice_len_index, sema)).toIntern());
27377 return Air.internedToRef((try val.ptrField(Value.slice_len_index, mod)).toIntern());
2749527378 }
2749627379 try sema.requireRuntimeBlock(block, src, null);
2749727380
......@@ -27559,7 +27442,7 @@ fn fieldPtr(
2755927442 if (try sema.namespaceLookupRef(block, src, child_type.getNamespaceIndex(mod), field_name)) |inst| {
2756027443 return inst;
2756127444 }
27562 try sema.resolveTypeFields(child_type);
27445 try child_type.resolveFields(mod);
2756327446 if (child_type.unionTagType(mod)) |enum_ty| {
2756427447 if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| {
2756527448 const field_index_u32: u32 = @intCast(field_index);
......@@ -27654,7 +27537,7 @@ fn fieldCallBind(
2765427537 find_field: {
2765527538 switch (concrete_ty.zigTypeTag(mod)) {
2765627539 .Struct => {
27657 try sema.resolveTypeFields(concrete_ty);
27540 try concrete_ty.resolveFields(mod);
2765827541 if (mod.typeToStruct(concrete_ty)) |struct_type| {
2765927542 const field_index = struct_type.nameIndex(ip, field_name) orelse
2766027543 break :find_field;
......@@ -27680,7 +27563,7 @@ fn fieldCallBind(
2768027563 }
2768127564 },
2768227565 .Union => {
27683 try sema.resolveTypeFields(concrete_ty);
27566 try concrete_ty.resolveFields(mod);
2768427567 const union_obj = mod.typeToUnion(concrete_ty).?;
2768527568 _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field;
2768627569 const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);
......@@ -27701,7 +27584,6 @@ fn fieldCallBind(
2770127584 const decl_idx = (try sema.namespaceLookup(block, src, namespace, field_name)) orelse
2770227585 break :found_decl null;
2770327586
27704 try sema.addReferencedBy(src, decl_idx);
2770527587 const decl_val = try sema.analyzeDeclVal(block, src, decl_idx);
2770627588 const decl_type = sema.typeOf(decl_val);
2770727589 if (mod.typeToFunc(decl_type)) |func_type| f: {
......@@ -27791,7 +27673,7 @@ fn finishFieldCallBind(
2779127673 object_ptr: Air.Inst.Ref,
2779227674) CompileError!ResolvedFieldCallee {
2779327675 const mod = sema.mod;
27794 const ptr_field_ty = try sema.ptrType(.{
27676 const ptr_field_ty = try mod.ptrTypeSema(.{
2779527677 .child = field_ty.toIntern(),
2779627678 .flags = .{
2779727679 .is_const = !ptr_ty.ptrIsMutable(mod),
......@@ -27802,14 +27684,14 @@ fn finishFieldCallBind(
2780227684 const container_ty = ptr_ty.childType(mod);
2780327685 if (container_ty.zigTypeTag(mod) == .Struct) {
2780427686 if (container_ty.structFieldIsComptime(field_index, mod)) {
27805 try sema.resolveStructFieldInits(container_ty);
27687 try container_ty.resolveStructFieldInits(mod);
2780627688 const default_val = (try container_ty.structFieldValueComptime(mod, field_index)).?;
2780727689 return .{ .direct = Air.internedToRef(default_val.toIntern()) };
2780827690 }
2780927691 }
2781027692
2781127693 if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
27812 const ptr_val = try struct_ptr_val.ptrField(field_index, sema);
27694 const ptr_val = try struct_ptr_val.ptrField(field_index, mod);
2781327695 const pointer = Air.internedToRef(ptr_val.toIntern());
2781427696 return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
2781527697 }
......@@ -27857,8 +27739,7 @@ fn namespaceLookupRef(
2785727739 decl_name: InternPool.NullTerminatedString,
2785827740) CompileError!?Air.Inst.Ref {
2785927741 const decl = (try sema.namespaceLookup(block, src, opt_namespace, decl_name)) orelse return null;
27860 try sema.addReferencedBy(src, decl);
27861 return try sema.analyzeDeclRef(decl);
27742 return try sema.analyzeDeclRef(src, decl);
2786227743}
2786327744
2786427745fn namespaceLookupVal(
......@@ -27886,8 +27767,8 @@ fn structFieldPtr(
2788627767 const ip = &mod.intern_pool;
2788727768 assert(struct_ty.zigTypeTag(mod) == .Struct);
2788827769
27889 try sema.resolveTypeFields(struct_ty);
27890 try sema.resolveStructLayout(struct_ty);
27770 try struct_ty.resolveFields(mod);
27771 try struct_ty.resolveLayout(mod);
2789127772
2789227773 if (struct_ty.isTuple(mod)) {
2789327774 if (field_name.eqlSlice("len", ip)) {
......@@ -27926,7 +27807,7 @@ fn structFieldPtrByIndex(
2792627807 }
2792727808
2792827809 if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
27929 const val = try struct_ptr_val.ptrField(field_index, sema);
27810 const val = try struct_ptr_val.ptrField(field_index, mod);
2793027811 return Air.internedToRef(val.toIntern());
2793127812 }
2793227813
......@@ -27970,10 +27851,11 @@ fn structFieldPtrByIndex(
2797027851 @enumFromInt(@min(@intFromEnum(parent_align), @ctz(field_offset)));
2797127852 } else {
2797227853 // Our alignment is capped at the field alignment.
27973 const field_align = try sema.structFieldAlignment(
27854 const field_align = try mod.structFieldAlignmentAdvanced(
2797427855 struct_type.fieldAlign(ip, field_index),
2797527856 Type.fromInterned(field_ty),
2797627857 struct_type.layout,
27858 .sema,
2797727859 );
2797827860 ptr_ty_data.flags.alignment = if (struct_ptr_ty_info.flags.alignment == .none)
2797927861 field_align
......@@ -27981,10 +27863,10 @@ fn structFieldPtrByIndex(
2798127863 field_align.min(parent_align);
2798227864 }
2798327865
27984 const ptr_field_ty = try sema.ptrType(ptr_ty_data);
27866 const ptr_field_ty = try mod.ptrTypeSema(ptr_ty_data);
2798527867
2798627868 if (struct_type.fieldIsComptime(ip, field_index)) {
27987 try sema.resolveStructFieldInits(struct_ty);
27869 try struct_ty.resolveStructFieldInits(mod);
2798827870 const val = try mod.intern(.{ .ptr = .{
2798927871 .ty = ptr_field_ty.toIntern(),
2799027872 .base_addr = .{ .comptime_field = struct_type.field_inits.get(ip)[field_index] },
......@@ -28010,7 +27892,7 @@ fn structFieldVal(
2801027892 const ip = &mod.intern_pool;
2801127893 assert(struct_ty.zigTypeTag(mod) == .Struct);
2801227894
28013 try sema.resolveTypeFields(struct_ty);
27895 try struct_ty.resolveFields(mod);
2801427896
2801527897 switch (ip.indexToKey(struct_ty.toIntern())) {
2801627898 .struct_type => {
......@@ -28021,7 +27903,7 @@ fn structFieldVal(
2802127903 const field_index = struct_type.nameIndex(ip, field_name) orelse
2802227904 return sema.failWithBadStructFieldAccess(block, struct_ty, struct_type, field_name_src, field_name);
2802327905 if (struct_type.fieldIsComptime(ip, field_index)) {
28024 try sema.resolveStructFieldInits(struct_ty);
27906 try struct_ty.resolveStructFieldInits(mod);
2802527907 return Air.internedToRef(struct_type.field_inits.get(ip)[field_index]);
2802627908 }
2802727909
......@@ -28038,7 +27920,7 @@ fn structFieldVal(
2803827920 }
2803927921
2804027922 try sema.requireRuntimeBlock(block, src, null);
28041 try sema.resolveTypeLayout(field_ty);
27923 try field_ty.resolveLayout(mod);
2804227924 return block.addStructFieldVal(struct_byval, field_index, field_ty);
2804327925 },
2804427926 .anon_struct_type => |anon_struct| {
......@@ -28105,7 +27987,7 @@ fn tupleFieldValByIndex(
2810527987 const field_ty = tuple_ty.structFieldType(field_index, mod);
2810627988
2810727989 if (tuple_ty.structFieldIsComptime(field_index, mod))
28108 try sema.resolveStructFieldInits(tuple_ty);
27990 try tuple_ty.resolveStructFieldInits(mod);
2810927991 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| {
2811027992 return Air.internedToRef(default_value.toIntern());
2811127993 }
......@@ -28126,7 +28008,7 @@ fn tupleFieldValByIndex(
2812628008 }
2812728009
2812828010 try sema.requireRuntimeBlock(block, src, null);
28129 try sema.resolveTypeLayout(field_ty);
28011 try field_ty.resolveLayout(mod);
2813028012 return block.addStructFieldVal(tuple_byval, field_index, field_ty);
2813128013}
2813228014
......@@ -28147,11 +28029,11 @@ fn unionFieldPtr(
2814728029
2814828030 const union_ptr_ty = sema.typeOf(union_ptr);
2814928031 const union_ptr_info = union_ptr_ty.ptrInfo(mod);
28150 try sema.resolveTypeFields(union_ty);
28032 try union_ty.resolveFields(mod);
2815128033 const union_obj = mod.typeToUnion(union_ty).?;
2815228034 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2815328035 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
28154 const ptr_field_ty = try sema.ptrType(.{
28036 const ptr_field_ty = try mod.ptrTypeSema(.{
2815528037 .child = field_ty.toIntern(),
2815628038 .flags = .{
2815728039 .is_const = union_ptr_info.flags.is_const,
......@@ -28162,7 +28044,7 @@ fn unionFieldPtr(
2816228044 union_ptr_info.flags.alignment
2816328045 else
2816428046 try sema.typeAbiAlignment(union_ty);
28165 const field_align = try sema.unionFieldAlignment(union_obj, field_index);
28047 const field_align = try mod.unionFieldNormalAlignmentAdvanced(union_obj, field_index, .sema);
2816628048 break :blk union_align.min(field_align);
2816728049 } else union_ptr_info.flags.alignment,
2816828050 },
......@@ -28218,7 +28100,7 @@ fn unionFieldPtr(
2821828100 },
2821928101 .@"packed", .@"extern" => {},
2822028102 }
28221 const field_ptr_val = try union_ptr_val.ptrField(field_index, sema);
28103 const field_ptr_val = try union_ptr_val.ptrField(field_index, mod);
2822228104 return Air.internedToRef(field_ptr_val.toIntern());
2822328105 }
2822428106
......@@ -28253,7 +28135,7 @@ fn unionFieldVal(
2825328135 const ip = &zcu.intern_pool;
2825428136 assert(union_ty.zigTypeTag(zcu) == .Union);
2825528137
28256 try sema.resolveTypeFields(union_ty);
28138 try union_ty.resolveFields(zcu);
2825728139 const union_obj = zcu.typeToUnion(union_ty).?;
2825828140 const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
2825928141 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
......@@ -28292,7 +28174,7 @@ fn unionFieldVal(
2829228174 .@"packed" => if (tag_matches) {
2829328175 // Fast path - no need to use bitcast logic.
2829428176 return Air.internedToRef(un.val);
28295 } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeAdvanced(zcu, sema), 0)) |field_val| {
28177 } else if (try sema.bitCastVal(union_val, field_ty, 0, try union_ty.bitSizeAdvanced(zcu, .sema), 0)) |field_val| {
2829628178 return Air.internedToRef(field_val.toIntern());
2829728179 },
2829828180 }
......@@ -28311,7 +28193,7 @@ fn unionFieldVal(
2831128193 _ = try block.addNoOp(.unreach);
2831228194 return .unreachable_value;
2831328195 }
28314 try sema.resolveTypeLayout(field_ty);
28196 try field_ty.resolveLayout(zcu);
2831528197 return block.addStructFieldVal(union_byval, field_index, field_ty);
2831628198}
2831728199
......@@ -28342,7 +28224,7 @@ fn elemPtr(
2834228224 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{
2834328225 .needed_comptime_reason = "tuple field access index must be comptime-known",
2834428226 });
28345 const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28227 const index: u32 = @intCast(try index_val.toUnsignedIntSema(mod));
2834628228 break :blk try sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
2834728229 },
2834828230 else => {
......@@ -28380,11 +28262,11 @@ fn elemPtrOneLayerOnly(
2838028262 const runtime_src = rs: {
2838128263 const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
2838228264 const index_val = maybe_index_val orelse break :rs elem_index_src;
28383 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28384 const elem_ptr = try ptr_val.ptrElem(index, sema);
28265 const index: usize = @intCast(try index_val.toUnsignedIntSema(mod));
28266 const elem_ptr = try ptr_val.ptrElem(index, mod);
2838528267 return Air.internedToRef(elem_ptr.toIntern());
2838628268 };
28387 const result_ty = try sema.elemPtrType(indexable_ty, null);
28269 const result_ty = try indexable_ty.elemPtrType(null, mod);
2838828270
2838928271 try sema.requireRuntimeBlock(block, src, runtime_src);
2839028272 return block.addPtrElemPtr(indexable, elem_index, result_ty);
......@@ -28398,7 +28280,7 @@ fn elemPtrOneLayerOnly(
2839828280 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{
2839928281 .needed_comptime_reason = "tuple field access index must be comptime-known",
2840028282 });
28401 const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28283 const index: u32 = @intCast(try index_val.toUnsignedIntSema(mod));
2840228284 break :blk try sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);
2840328285 },
2840428286 else => unreachable, // Guaranteed by checkIndexable
......@@ -28438,12 +28320,12 @@ fn elemVal(
2843828320 const runtime_src = rs: {
2843928321 const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
2844028322 const index_val = maybe_index_val orelse break :rs elem_index_src;
28441 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28323 const index: usize = @intCast(try index_val.toUnsignedIntSema(mod));
2844228324 const elem_ty = indexable_ty.elemType2(mod);
2844328325 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
2844428326 const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
2844528327 const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
28446 const elem_ptr_val = try many_ptr_val.ptrElem(index, sema);
28328 const elem_ptr_val = try many_ptr_val.ptrElem(index, mod);
2844728329 if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
2844828330 return Air.internedToRef((try mod.getCoerced(elem_val, elem_ty)).toIntern());
2844928331 }
......@@ -28459,7 +28341,7 @@ fn elemVal(
2845928341 if (inner_ty.zigTypeTag(mod) != .Array) break :arr_sent;
2846028342 const sentinel = inner_ty.sentinel(mod) orelse break :arr_sent;
2846128343 const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;
28462 const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntAdvanced(sema));
28344 const index = try sema.usizeCast(block, src, try index_val.toUnsignedIntSema(mod));
2846328345 if (index != inner_ty.arrayLen(mod)) break :arr_sent;
2846428346 return Air.internedToRef(sentinel.toIntern());
2846528347 }
......@@ -28477,7 +28359,7 @@ fn elemVal(
2847728359 const index_val = try sema.resolveConstDefinedValue(block, elem_index_src, elem_index, .{
2847828360 .needed_comptime_reason = "tuple field access index must be comptime-known",
2847928361 });
28480 const index: u32 = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28362 const index: u32 = @intCast(try index_val.toUnsignedIntSema(mod));
2848128363 return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);
2848228364 },
2848328365 else => unreachable,
......@@ -28522,7 +28404,7 @@ fn tupleFieldPtr(
2852228404 const mod = sema.mod;
2852328405 const tuple_ptr_ty = sema.typeOf(tuple_ptr);
2852428406 const tuple_ty = tuple_ptr_ty.childType(mod);
28525 try sema.resolveTypeFields(tuple_ty);
28407 try tuple_ty.resolveFields(mod);
2852628408 const field_count = tuple_ty.structFieldCount(mod);
2852728409
2852828410 if (field_count == 0) {
......@@ -28536,7 +28418,7 @@ fn tupleFieldPtr(
2853628418 }
2853728419
2853828420 const field_ty = tuple_ty.structFieldType(field_index, mod);
28539 const ptr_field_ty = try sema.ptrType(.{
28421 const ptr_field_ty = try mod.ptrTypeSema(.{
2854028422 .child = field_ty.toIntern(),
2854128423 .flags = .{
2854228424 .is_const = !tuple_ptr_ty.ptrIsMutable(mod),
......@@ -28546,7 +28428,7 @@ fn tupleFieldPtr(
2854628428 });
2854728429
2854828430 if (tuple_ty.structFieldIsComptime(field_index, mod))
28549 try sema.resolveStructFieldInits(tuple_ty);
28431 try tuple_ty.resolveStructFieldInits(mod);
2855028432
2855128433 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
2855228434 return Air.internedToRef((try mod.intern(.{ .ptr = .{
......@@ -28557,7 +28439,7 @@ fn tupleFieldPtr(
2855728439 }
2855828440
2855928441 if (try sema.resolveValue(tuple_ptr)) |tuple_ptr_val| {
28560 const field_ptr_val = try tuple_ptr_val.ptrField(field_index, sema);
28442 const field_ptr_val = try tuple_ptr_val.ptrField(field_index, mod);
2856128443 return Air.internedToRef(field_ptr_val.toIntern());
2856228444 }
2856328445
......@@ -28579,7 +28461,7 @@ fn tupleField(
2857928461) CompileError!Air.Inst.Ref {
2858028462 const mod = sema.mod;
2858128463 const tuple_ty = sema.typeOf(tuple);
28582 try sema.resolveTypeFields(tuple_ty);
28464 try tuple_ty.resolveFields(mod);
2858328465 const field_count = tuple_ty.structFieldCount(mod);
2858428466
2858528467 if (field_count == 0) {
......@@ -28595,7 +28477,7 @@ fn tupleField(
2859528477 const field_ty = tuple_ty.structFieldType(field_index, mod);
2859628478
2859728479 if (tuple_ty.structFieldIsComptime(field_index, mod))
28598 try sema.resolveStructFieldInits(tuple_ty);
28480 try tuple_ty.resolveStructFieldInits(mod);
2859928481 if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| {
2860028482 return Air.internedToRef(default_value.toIntern()); // comptime field
2860128483 }
......@@ -28608,7 +28490,7 @@ fn tupleField(
2860828490 try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
2860928491
2861028492 try sema.requireRuntimeBlock(block, tuple_src, null);
28611 try sema.resolveTypeLayout(field_ty);
28493 try field_ty.resolveLayout(mod);
2861228494 return block.addStructFieldVal(tuple, field_index, field_ty);
2861328495}
2861428496
......@@ -28638,7 +28520,7 @@ fn elemValArray(
2863828520 const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
2863928521
2864028522 if (maybe_index_val) |index_val| {
28641 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28523 const index: usize = @intCast(try index_val.toUnsignedIntSema(mod));
2864228524 if (array_sent) |s| {
2864328525 if (index == array_len) {
2864428526 return Air.internedToRef(s.toIntern());
......@@ -28654,7 +28536,7 @@ fn elemValArray(
2865428536 return mod.undefRef(elem_ty);
2865528537 }
2865628538 if (maybe_index_val) |index_val| {
28657 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28539 const index: usize = @intCast(try index_val.toUnsignedIntSema(mod));
2865828540 const elem_val = try array_val.elemValue(mod, index);
2865928541 return Air.internedToRef(elem_val.toIntern());
2866028542 }
......@@ -28676,7 +28558,6 @@ fn elemValArray(
2867628558 return Air.internedToRef(elem_val.toIntern());
2867728559
2867828560 try sema.requireRuntimeBlock(block, src, runtime_src);
28679 try sema.queueFullTypeResolution(array_ty);
2868028561 return block.addBinOp(.array_elem_val, array, elem_index);
2868128562}
2868228563
......@@ -28705,7 +28586,7 @@ fn elemPtrArray(
2870528586 const maybe_undef_array_ptr_val = try sema.resolveValue(array_ptr);
2870628587 // The index must not be undefined since it can be out of bounds.
2870728588 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
28708 const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntAdvanced(sema));
28589 const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(mod));
2870928590 if (index >= array_len_s) {
2871028591 const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
2871128592 return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
......@@ -28713,14 +28594,14 @@ fn elemPtrArray(
2871328594 break :o index;
2871428595 } else null;
2871528596
28716 const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset);
28597 const elem_ptr_ty = try array_ptr_ty.elemPtrType(offset, mod);
2871728598
2871828599 if (maybe_undef_array_ptr_val) |array_ptr_val| {
2871928600 if (array_ptr_val.isUndef(mod)) {
2872028601 return mod.undefRef(elem_ptr_ty);
2872128602 }
2872228603 if (offset) |index| {
28723 const elem_ptr = try array_ptr_val.ptrElem(index, sema);
28604 const elem_ptr = try array_ptr_val.ptrElem(index, mod);
2872428605 return Air.internedToRef(elem_ptr.toIntern());
2872528606 }
2872628607 }
......@@ -28765,19 +28646,19 @@ fn elemValSlice(
2876528646
2876628647 if (maybe_slice_val) |slice_val| {
2876728648 runtime_src = elem_index_src;
28768 const slice_len = try slice_val.sliceLen(sema);
28649 const slice_len = try slice_val.sliceLen(mod);
2876928650 const slice_len_s = slice_len + @intFromBool(slice_sent);
2877028651 if (slice_len_s == 0) {
2877128652 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
2877228653 }
2877328654 if (maybe_index_val) |index_val| {
28774 const index: usize = @intCast(try index_val.toUnsignedIntAdvanced(sema));
28655 const index: usize = @intCast(try index_val.toUnsignedIntSema(mod));
2877528656 if (index >= slice_len_s) {
2877628657 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
2877728658 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
2877828659 }
28779 const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);
28780 const elem_ptr_val = try slice_val.ptrElem(index, sema);
28660 const elem_ptr_ty = try slice_ty.elemPtrType(index, mod);
28661 const elem_ptr_val = try slice_val.ptrElem(index, mod);
2878128662 if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
2878228663 return Air.internedToRef(elem_val.toIntern());
2878328664 }
......@@ -28790,13 +28671,12 @@ fn elemValSlice(
2879028671 try sema.requireRuntimeBlock(block, src, runtime_src);
2879128672 if (oob_safety and block.wantSafety()) {
2879228673 const len_inst = if (maybe_slice_val) |slice_val|
28793 try mod.intRef(Type.usize, try slice_val.sliceLen(sema))
28674 try mod.intRef(Type.usize, try slice_val.sliceLen(mod))
2879428675 else
2879528676 try block.addTyOp(.slice_len, Type.usize, slice);
2879628677 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
2879728678 try sema.panicIndexOutOfBounds(block, src, elem_index, len_inst, cmp_op);
2879828679 }
28799 try sema.queueFullTypeResolution(sema.typeOf(slice));
2880028680 return block.addBinOp(.slice_elem_val, slice, elem_index);
2880128681}
2880228682
......@@ -28817,17 +28697,17 @@ fn elemPtrSlice(
2881728697 const maybe_undef_slice_val = try sema.resolveValue(slice);
2881828698 // The index must not be undefined since it can be out of bounds.
2881928699 const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
28820 const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntAdvanced(sema));
28700 const index = try sema.usizeCast(block, elem_index_src, try index_val.toUnsignedIntSema(mod));
2882128701 break :o index;
2882228702 } else null;
2882328703
28824 const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset);
28704 const elem_ptr_ty = try slice_ty.elemPtrType(offset, mod);
2882528705
2882628706 if (maybe_undef_slice_val) |slice_val| {
2882728707 if (slice_val.isUndef(mod)) {
2882828708 return mod.undefRef(elem_ptr_ty);
2882928709 }
28830 const slice_len = try slice_val.sliceLen(sema);
28710 const slice_len = try slice_val.sliceLen(mod);
2883128711 const slice_len_s = slice_len + @intFromBool(slice_sent);
2883228712 if (slice_len_s == 0) {
2883328713 return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
......@@ -28837,7 +28717,7 @@ fn elemPtrSlice(
2883728717 const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
2883828718 return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
2883928719 }
28840 const elem_ptr_val = try slice_val.ptrElem(index, sema);
28720 const elem_ptr_val = try slice_val.ptrElem(index, mod);
2884128721 return Air.internedToRef(elem_ptr_val.toIntern());
2884228722 }
2884328723 }
......@@ -28850,7 +28730,7 @@ fn elemPtrSlice(
2885028730 const len_inst = len: {
2885128731 if (maybe_undef_slice_val) |slice_val|
2885228732 if (!slice_val.isUndef(mod))
28853 break :len try mod.intRef(Type.usize, try slice_val.sliceLen(sema));
28733 break :len try mod.intRef(Type.usize, try slice_val.sliceLen(mod));
2885428734 break :len try block.addTyOp(.slice_len, Type.usize, slice);
2885528735 };
2885628736 const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
......@@ -28915,9 +28795,9 @@ fn coerceExtra(
2891528795 if (dest_ty.isGenericPoison()) return inst;
2891628796 const zcu = sema.mod;
2891728797 const dest_ty_src = inst_src; // TODO better source location
28918 try sema.resolveTypeFields(dest_ty);
28798 try dest_ty.resolveFields(zcu);
2891928799 const inst_ty = sema.typeOf(inst);
28920 try sema.resolveTypeFields(inst_ty);
28800 try inst_ty.resolveFields(zcu);
2892128801 const target = zcu.getTarget();
2892228802 // If the types are the same, we can return the operand.
2892328803 if (dest_ty.eql(inst_ty, zcu))
......@@ -28931,7 +28811,6 @@ fn coerceExtra(
2893128811 return sema.coerceInMemory(val, dest_ty);
2893228812 }
2893328813 try sema.requireRuntimeBlock(block, inst_src, null);
28934 try sema.queueFullTypeResolution(dest_ty);
2893528814 const new_val = try block.addBitCast(dest_ty, inst);
2893628815 try sema.checkKnownAllocPtr(block, inst, new_val);
2893728816 return new_val;
......@@ -28996,7 +28875,7 @@ fn coerceExtra(
2899628875 if (inst_ty.zigTypeTag(zcu) == .Fn) {
2899728876 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
2899828877 const fn_decl = fn_val.pointerDecl(zcu).?;
28999 const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
28878 const inst_as_ptr = try sema.analyzeDeclRef(inst_src, fn_decl);
2900028879 return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
2900128880 }
2900228881
......@@ -29227,7 +29106,7 @@ fn coerceExtra(
2922729106 // empty tuple to zero-length slice
2922829107 // note that this allows coercing to a mutable slice.
2922929108 if (inst_child_ty.structFieldCount(zcu) == 0) {
29230 const align_val = try dest_ty.ptrAlignmentAdvanced(zcu, sema);
29109 const align_val = try dest_ty.ptrAlignmentAdvanced(zcu, .sema);
2923129110 return Air.internedToRef(try zcu.intern(.{ .slice = .{
2923229111 .ty = dest_ty.toIntern(),
2923329112 .ptr = try zcu.intern(.{ .ptr = .{
......@@ -29372,7 +29251,7 @@ fn coerceExtra(
2937229251 }
2937329252 break :int;
2937429253 };
29375 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, zcu, sema);
29254 const result_val = try val.floatFromIntAdvanced(sema.arena, inst_ty, dest_ty, zcu, .sema);
2937629255 // TODO implement this compile error
2937729256 //const int_again_val = try result_val.intFromFloat(sema.arena, inst_ty);
2937829257 //if (!int_again_val.eql(val, inst_ty, zcu)) {
......@@ -30549,7 +30428,7 @@ fn coerceVarArgParam(
3054930428 .Fn => fn_ptr: {
3055030429 const fn_val = try sema.resolveConstDefinedValue(block, LazySrcLoc.unneeded, inst, undefined);
3055130430 const fn_decl = fn_val.pointerDecl(mod).?;
30552 break :fn_ptr try sema.analyzeDeclRef(fn_decl);
30431 break :fn_ptr try sema.analyzeDeclRef(inst_src, fn_decl);
3055330432 },
3055430433 .Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
3055530434 .Float => float: {
......@@ -30704,7 +30583,6 @@ fn storePtr2(
3070430583 }
3070530584
3070630585 try sema.requireRuntimeBlock(block, src, runtime_src);
30707 try sema.queueFullTypeResolution(elem_ty);
3070830586
3070930587 if (ptr_ty.ptrInfo(mod).flags.vector_index == .runtime) {
3071030588 const ptr_inst = ptr.toIndex().?;
......@@ -30926,10 +30804,10 @@ fn bitCast(
3092630804 operand_src: ?LazySrcLoc,
3092730805) CompileError!Air.Inst.Ref {
3092830806 const zcu = sema.mod;
30929 try sema.resolveTypeLayout(dest_ty);
30807 try dest_ty.resolveLayout(zcu);
3093030808
3093130809 const old_ty = sema.typeOf(inst);
30932 try sema.resolveTypeLayout(old_ty);
30810 try old_ty.resolveLayout(zcu);
3093330811
3093430812 const dest_bits = dest_ty.bitSize(zcu);
3093530813 const old_bits = old_ty.bitSize(zcu);
......@@ -31111,7 +30989,7 @@ fn coerceEnumToUnion(
3111130989
3111230990 const union_obj = mod.typeToUnion(union_ty).?;
3111330991 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
31114 try sema.resolveTypeFields(field_ty);
30992 try field_ty.resolveFields(mod);
3111530993 if (field_ty.zigTypeTag(mod) == .NoReturn) {
3111630994 const msg = msg: {
3111730995 const msg = try sema.errMsg(inst_src, "cannot initialize 'noreturn' field of union", .{});
......@@ -31524,8 +31402,8 @@ fn coerceTupleToStruct(
3152431402) !Air.Inst.Ref {
3152531403 const mod = sema.mod;
3152631404 const ip = &mod.intern_pool;
31527 try sema.resolveTypeFields(struct_ty);
31528 try sema.resolveStructFieldInits(struct_ty);
31405 try struct_ty.resolveFields(mod);
31406 try struct_ty.resolveStructFieldInits(mod);
3152931407
3153031408 if (struct_ty.isTupleOrAnonStruct(mod)) {
3153131409 return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
......@@ -31776,11 +31654,10 @@ fn analyzeDeclVal(
3177631654 src: LazySrcLoc,
3177731655 decl_index: InternPool.DeclIndex,
3177831656) CompileError!Air.Inst.Ref {
31779 try sema.addReferencedBy(src, decl_index);
3178031657 if (sema.decl_val_table.get(decl_index)) |result| {
3178131658 return result;
3178231659 }
31783 const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);
31660 const decl_ref = try sema.analyzeDeclRefInner(src, decl_index, false);
3178431661 const result = try sema.analyzeLoad(block, src, decl_ref, src);
3178531662 if (result.toInterned() != null) {
3178631663 if (!block.is_typeof) {
......@@ -31790,18 +31667,18 @@ fn analyzeDeclVal(
3179031667 return result;
3179131668}
3179231669
31793fn addReferencedBy(
31670fn addReferenceEntry(
3179431671 sema: *Sema,
3179531672 src: LazySrcLoc,
31796 decl_index: InternPool.DeclIndex,
31673 referenced_unit: AnalUnit,
3179731674) !void {
3179831675 if (sema.mod.comp.reference_trace == 0) return;
31799 try sema.mod.reference_table.put(sema.gpa, decl_index, .{
31800 // TODO: this can make the reference trace suboptimal. This will be fixed
31801 // once the reference table is reworked for incremental compilation.
31802 .referencer = sema.owner_decl_index,
31803 .src = src,
31804 });
31676 const gop = try sema.references.getOrPut(sema.gpa, referenced_unit);
31677 if (gop.found_existing) return;
31678 // TODO: we need to figure out how to model inline calls here.
31679 // They aren't references in the analysis sense, but ought to show up in the reference trace!
31680 // Would representing inline calls in the reference table cause excessive memory usage?
31681 try sema.mod.addUnitReference(sema.ownerUnit(), referenced_unit, src);
3180531682}
3180631683
3180731684pub fn ensureDeclAnalyzed(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!void {
......@@ -31851,16 +31728,17 @@ fn optRefValue(sema: *Sema, opt_val: ?Value) !Value {
3185131728 } })));
3185231729}
3185331730
31854fn analyzeDeclRef(sema: *Sema, decl_index: InternPool.DeclIndex) CompileError!Air.Inst.Ref {
31855 return sema.analyzeDeclRefInner(decl_index, true);
31731fn analyzeDeclRef(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex) CompileError!Air.Inst.Ref {
31732 return sema.analyzeDeclRefInner(src, decl_index, true);
3185631733}
3185731734
3185831735/// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but
3185931736/// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a
3186031737/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps
3186131738/// this function with `analyze_fn_body` set to true.
31862fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
31739fn analyzeDeclRefInner(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
3186331740 const mod = sema.mod;
31741 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .decl = decl_index }));
3186431742 try sema.ensureDeclAnalyzed(decl_index);
3186531743
3186631744 const decl_val = try mod.declPtr(decl_index).valueOrFail();
......@@ -31872,7 +31750,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3187231750 });
3187331751 // TODO: if this is a `decl_ref` of a non-variable decl, only depend on decl type
3187431752 try sema.declareDependency(.{ .decl_val = decl_index });
31875 const ptr_ty = try sema.ptrType(.{
31753 const ptr_ty = try mod.ptrTypeSema(.{
3187631754 .child = decl_val.typeOf(mod).toIntern(),
3187731755 .flags = .{
3187831756 .alignment = owner_decl.alignment,
......@@ -31881,7 +31759,7 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3188131759 },
3188231760 });
3188331761 if (analyze_fn_body) {
31884 try sema.maybeQueueFuncBodyAnalysis(decl_index);
31762 try sema.maybeQueueFuncBodyAnalysis(src, decl_index);
3188531763 }
3188631764 return Air.internedToRef((try mod.intern(.{ .ptr = .{
3188731765 .ty = ptr_ty.toIntern(),
......@@ -31890,12 +31768,13 @@ fn analyzeDeclRefInner(sema: *Sema, decl_index: InternPool.DeclIndex, analyze_fn
3189031768 } })));
3189131769}
3189231770
31893fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: InternPool.DeclIndex) !void {
31771fn maybeQueueFuncBodyAnalysis(sema: *Sema, src: LazySrcLoc, decl_index: InternPool.DeclIndex) !void {
3189431772 const mod = sema.mod;
3189531773 const decl = mod.declPtr(decl_index);
3189631774 const decl_val = try decl.valueOrFail();
3189731775 if (!mod.intern_pool.isFuncBody(decl_val.toIntern())) return;
3189831776 if (!try sema.fnHasRuntimeBits(decl_val.typeOf(mod))) return;
31777 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = decl_val.toIntern() }));
3189931778 try mod.ensureFuncBodyAnalysisQueued(decl_val.toIntern());
3190031779}
3190131780
......@@ -31910,22 +31789,22 @@ fn analyzeRef(
3191031789
3191131790 if (try sema.resolveValue(operand)) |val| {
3191231791 switch (mod.intern_pool.indexToKey(val.toIntern())) {
31913 .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl),
31914 .func => |func| return sema.analyzeDeclRef(func.owner_decl),
31792 .extern_func => |extern_func| return sema.analyzeDeclRef(src, extern_func.decl),
31793 .func => |func| return sema.analyzeDeclRef(src, func.owner_decl),
3191531794 else => return anonDeclRef(sema, val.toIntern()),
3191631795 }
3191731796 }
3191831797
3191931798 try sema.requireRuntimeBlock(block, src, null);
3192031799 const address_space = target_util.defaultAddressSpace(mod.getTarget(), .local);
31921 const ptr_type = try sema.ptrType(.{
31800 const ptr_type = try mod.ptrTypeSema(.{
3192231801 .child = operand_ty.toIntern(),
3192331802 .flags = .{
3192431803 .is_const = true,
3192531804 .address_space = address_space,
3192631805 },
3192731806 });
31928 const mut_ptr_type = try sema.ptrType(.{
31807 const mut_ptr_type = try mod.ptrTypeSema(.{
3192931808 .child = operand_ty.toIntern(),
3193031809 .flags = .{ .address_space = address_space },
3193131810 });
......@@ -32033,7 +31912,7 @@ fn analyzeSliceLen(
3203331912 if (slice_val.isUndef(mod)) {
3203431913 return mod.undefRef(Type.usize);
3203531914 }
32036 return mod.intRef(Type.usize, try slice_val.sliceLen(sema));
31915 return mod.intRef(Type.usize, try slice_val.sliceLen(mod));
3203731916 }
3203831917 try sema.requireRuntimeBlock(block, src, null);
3203931918 return block.addTyOp(.slice_len, Type.usize, slice_inst);
......@@ -32401,7 +32280,7 @@ fn analyzeSlice(
3240132280 assert(manyptr_ty_key.flags.size == .One);
3240232281 manyptr_ty_key.child = elem_ty.toIntern();
3240332282 manyptr_ty_key.flags.size = .Many;
32404 break :ptr try sema.coerceCompatiblePtrs(block, try sema.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
32283 break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrTypeSema(manyptr_ty_key), ptr_or_slice, ptr_src);
3240532284 } else ptr_or_slice;
3240632285
3240732286 const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);
......@@ -32470,7 +32349,7 @@ fn analyzeSlice(
3247032349 return sema.fail(block, src, "slice of undefined", .{});
3247132350 }
3247232351 const has_sentinel = slice_ty.sentinel(mod) != null;
32473 const slice_len = try slice_val.sliceLen(sema);
32352 const slice_len = try slice_val.sliceLen(mod);
3247432353 const len_plus_sent = slice_len + @intFromBool(has_sentinel);
3247532354 const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent);
3247632355 if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) {
......@@ -32485,7 +32364,7 @@ fn analyzeSlice(
3248532364 "end index {} out of bounds for slice of length {d}{s}",
3248632365 .{
3248732366 end_val.fmtValue(mod, sema),
32488 try slice_val.sliceLen(sema),
32367 try slice_val.sliceLen(mod),
3248932368 sentinel_label,
3249032369 },
3249132370 );
......@@ -32558,7 +32437,7 @@ fn analyzeSlice(
3255832437
3255932438 const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
3256032439 const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);
32561 const elem_ptr = try many_ptr_val.ptrElem(sentinel_index, sema);
32440 const elem_ptr = try many_ptr_val.ptrElem(sentinel_index, mod);
3256232441 const res = try sema.pointerDerefExtra(block, src, elem_ptr);
3256332442 const actual_sentinel = switch (res) {
3256432443 .runtime_load => break :sentinel_check,
......@@ -32621,9 +32500,9 @@ fn analyzeSlice(
3262132500 const new_allowzero = new_ptr_ty_info.flags.is_allowzero and sema.typeOf(ptr).ptrSize(mod) != .C;
3262232501
3262332502 if (opt_new_len_val) |new_len_val| {
32624 const new_len_int = try new_len_val.toUnsignedIntAdvanced(sema);
32503 const new_len_int = try new_len_val.toUnsignedIntSema(mod);
3262532504
32626 const return_ty = try sema.ptrType(.{
32505 const return_ty = try mod.ptrTypeSema(.{
3262732506 .child = (try mod.arrayType(.{
3262832507 .len = new_len_int,
3262932508 .sentinel = if (sentinel) |s| s.toIntern() else .none,
......@@ -32685,7 +32564,7 @@ fn analyzeSlice(
3268532564 return sema.fail(block, src, "non-zero length slice of undefined pointer", .{});
3268632565 }
3268732566
32688 const return_ty = try sema.ptrType(.{
32567 const return_ty = try mod.ptrTypeSema(.{
3268932568 .child = elem_ty.toIntern(),
3269032569 .sentinel = if (sentinel) |s| s.toIntern() else .none,
3269132570 .flags = .{
......@@ -32713,7 +32592,7 @@ fn analyzeSlice(
3271332592 if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
3271432593 // we don't need to add one for sentinels because the
3271532594 // underlying value data includes the sentinel
32716 break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(sema));
32595 break :blk try mod.intRef(Type.usize, try slice_val.sliceLen(mod));
3271732596 }
3271832597
3271932598 const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
......@@ -32805,7 +32684,7 @@ fn cmpNumeric(
3280532684 if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) {
3280632685 return if (op == std.math.CompareOperator.neq) .bool_true else .bool_false;
3280732686 }
32808 return if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, sema))
32687 return if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, .sema))
3280932688 .bool_true
3281032689 else
3281132690 .bool_false;
......@@ -32874,11 +32753,11 @@ fn cmpNumeric(
3287432753 // a signed integer with mantissa bits + 1, and if there was any non-integral part of the float,
3287532754 // add/subtract 1.
3287632755 const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|
32877 !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))
32756 !(try lhs_val.compareAllWithZeroSema(.gte, mod))
3287832757 else
3287932758 (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod));
3288032759 const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|
32881 !(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))
32760 !(try rhs_val.compareAllWithZeroSema(.gte, mod))
3288232761 else
3288332762 (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod));
3288432763 const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
......@@ -33026,7 +32905,7 @@ fn compareIntsOnlyPossibleResult(
3302632905) Allocator.Error!?bool {
3302732906 const mod = sema.mod;
3302832907 const rhs_info = rhs_ty.intInfo(mod);
33029 const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, sema) catch unreachable;
32908 const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, .sema) catch unreachable;
3303032909 const is_zero = vs_zero == .eq;
3303132910 const is_negative = vs_zero == .lt;
3303232911 const is_positive = vs_zero == .gt;
......@@ -33190,7 +33069,6 @@ fn wrapErrorUnionPayload(
3319033069 } })));
3319133070 }
3319233071 try sema.requireRuntimeBlock(block, inst_src, null);
33193 try sema.queueFullTypeResolution(dest_payload_ty);
3319433072 return block.addTyOp(.wrap_errunion_payload, dest_ty, coerced);
3319533073}
3319633074
......@@ -33993,7 +33871,7 @@ fn resolvePeerTypesInner(
3399333871
3399433872 opt_ptr_info = ptr_info;
3399533873 }
33996 return .{ .success = try sema.ptrType(opt_ptr_info.?) };
33874 return .{ .success = try mod.ptrTypeSema(opt_ptr_info.?) };
3399733875 },
3399833876
3399933877 .ptr => {
......@@ -34303,7 +34181,7 @@ fn resolvePeerTypesInner(
3430334181 },
3430434182 }
3430534183
34306 return .{ .success = try sema.ptrType(opt_ptr_info.?) };
34184 return .{ .success = try mod.ptrTypeSema(opt_ptr_info.?) };
3430734185 },
3430834186
3430934187 .func => {
......@@ -34660,7 +34538,7 @@ fn resolvePeerTypesInner(
3466034538 var comptime_val: ?Value = null;
3466134539 for (peer_tys) |opt_ty| {
3466234540 const struct_ty = opt_ty orelse continue;
34663 try sema.resolveStructFieldInits(struct_ty);
34541 try struct_ty.resolveStructFieldInits(mod);
3466434542
3466534543 const uncoerced_field_val = try struct_ty.structFieldValueComptime(mod, field_index) orelse {
3466634544 comptime_val = null;
......@@ -34796,181 +34674,22 @@ pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void {
3479634674 const ip = &mod.intern_pool;
3479734675 const fn_ty_info = mod.typeToFunc(fn_ty).?;
3479834676
34799 try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.return_type));
34677 try Type.fromInterned(fn_ty_info.return_type).resolveFully(mod);
3480034678
3480134679 if (mod.comp.config.any_error_tracing and
3480234680 Type.fromInterned(fn_ty_info.return_type).isError(mod))
3480334681 {
3480434682 // Ensure the type exists so that backends can assume that.
34805 _ = try sema.getBuiltinType("StackTrace");
34683 _ = try mod.getBuiltinType("StackTrace");
3480634684 }
3480734685
3480834686 for (0..fn_ty_info.param_types.len) |i| {
34809 try sema.resolveTypeFully(Type.fromInterned(fn_ty_info.param_types.get(ip)[i]));
34687 try Type.fromInterned(fn_ty_info.param_types.get(ip)[i]).resolveFully(mod);
3481034688 }
3481134689}
3481234690
34813/// Make it so that calling hash() and eql() on `val` will not assert due
34814/// to a type not having its layout resolved.
3481534691fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
34816 const mod = sema.mod;
34817 switch (mod.intern_pool.indexToKey(val.toIntern())) {
34818 .int => |int| switch (int.storage) {
34819 .u64, .i64, .big_int => return val,
34820 .lazy_align, .lazy_size => return mod.intValue(
34821 Type.fromInterned(int.ty),
34822 (try val.getUnsignedIntAdvanced(mod, sema)).?,
34823 ),
34824 },
34825 .slice => |slice| {
34826 const ptr = try sema.resolveLazyValue(Value.fromInterned(slice.ptr));
34827 const len = try sema.resolveLazyValue(Value.fromInterned(slice.len));
34828 if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val;
34829 return Value.fromInterned(try mod.intern(.{ .slice = .{
34830 .ty = slice.ty,
34831 .ptr = ptr.toIntern(),
34832 .len = len.toIntern(),
34833 } }));
34834 },
34835 .ptr => |ptr| {
34836 switch (ptr.base_addr) {
34837 .decl, .comptime_alloc, .anon_decl, .int => return val,
34838 .comptime_field => |field_val| {
34839 const resolved_field_val =
34840 (try sema.resolveLazyValue(Value.fromInterned(field_val))).toIntern();
34841 return if (resolved_field_val == field_val)
34842 val
34843 else
34844 Value.fromInterned((try mod.intern(.{ .ptr = .{
34845 .ty = ptr.ty,
34846 .base_addr = .{ .comptime_field = resolved_field_val },
34847 .byte_offset = ptr.byte_offset,
34848 } })));
34849 },
34850 .eu_payload, .opt_payload => |base| {
34851 const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base))).toIntern();
34852 return if (resolved_base == base)
34853 val
34854 else
34855 Value.fromInterned((try mod.intern(.{ .ptr = .{
34856 .ty = ptr.ty,
34857 .base_addr = switch (ptr.base_addr) {
34858 .eu_payload => .{ .eu_payload = resolved_base },
34859 .opt_payload => .{ .opt_payload = resolved_base },
34860 else => unreachable,
34861 },
34862 .byte_offset = ptr.byte_offset,
34863 } })));
34864 },
34865 .arr_elem, .field => |base_index| {
34866 const resolved_base = (try sema.resolveLazyValue(Value.fromInterned(base_index.base))).toIntern();
34867 return if (resolved_base == base_index.base)
34868 val
34869 else
34870 Value.fromInterned((try mod.intern(.{ .ptr = .{
34871 .ty = ptr.ty,
34872 .base_addr = switch (ptr.base_addr) {
34873 .arr_elem => .{ .arr_elem = .{
34874 .base = resolved_base,
34875 .index = base_index.index,
34876 } },
34877 .field => .{ .field = .{
34878 .base = resolved_base,
34879 .index = base_index.index,
34880 } },
34881 else => unreachable,
34882 },
34883 .byte_offset = ptr.byte_offset,
34884 } })));
34885 },
34886 }
34887 },
34888 .aggregate => |aggregate| switch (aggregate.storage) {
34889 .bytes => return val,
34890 .elems => |elems| {
34891 var resolved_elems: []InternPool.Index = &.{};
34892 for (elems, 0..) |elem, i| {
34893 const resolved_elem = (try sema.resolveLazyValue(Value.fromInterned(elem))).toIntern();
34894 if (resolved_elems.len == 0 and resolved_elem != elem) {
34895 resolved_elems = try sema.arena.alloc(InternPool.Index, elems.len);
34896 @memcpy(resolved_elems[0..i], elems[0..i]);
34897 }
34898 if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem;
34899 }
34900 return if (resolved_elems.len == 0) val else Value.fromInterned((try mod.intern(.{ .aggregate = .{
34901 .ty = aggregate.ty,
34902 .storage = .{ .elems = resolved_elems },
34903 } })));
34904 },
34905 .repeated_elem => |elem| {
34906 const resolved_elem = (try sema.resolveLazyValue(Value.fromInterned(elem))).toIntern();
34907 return if (resolved_elem == elem) val else Value.fromInterned((try mod.intern(.{ .aggregate = .{
34908 .ty = aggregate.ty,
34909 .storage = .{ .repeated_elem = resolved_elem },
34910 } })));
34911 },
34912 },
34913 .un => |un| {
34914 const resolved_tag = if (un.tag == .none)
34915 .none
34916 else
34917 (try sema.resolveLazyValue(Value.fromInterned(un.tag))).toIntern();
34918 const resolved_val = (try sema.resolveLazyValue(Value.fromInterned(un.val))).toIntern();
34919 return if (resolved_tag == un.tag and resolved_val == un.val)
34920 val
34921 else
34922 Value.fromInterned((try mod.intern(.{ .un = .{
34923 .ty = un.ty,
34924 .tag = resolved_tag,
34925 .val = resolved_val,
34926 } })));
34927 },
34928 else => return val,
34929 }
34930}
34931
34932pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
34933 const mod = sema.mod;
34934 switch (mod.intern_pool.indexToKey(ty.toIntern())) {
34935 .simple_type => |simple_type| return sema.resolveSimpleType(simple_type),
34936 else => {},
34937 }
34938 switch (ty.zigTypeTag(mod)) {
34939 .Struct => return sema.resolveStructLayout(ty),
34940 .Union => return sema.resolveUnionLayout(ty),
34941 .Array => {
34942 if (ty.arrayLenIncludingSentinel(mod) == 0) return;
34943 const elem_ty = ty.childType(mod);
34944 return sema.resolveTypeLayout(elem_ty);
34945 },
34946 .Optional => {
34947 const payload_ty = ty.optionalChild(mod);
34948 // In case of querying the ABI alignment of this optional, we will ask
34949 // for hasRuntimeBits() of the payload type, so we need "requires comptime"
34950 // to be known already before this function returns.
34951 _ = try sema.typeRequiresComptime(payload_ty);
34952 return sema.resolveTypeLayout(payload_ty);
34953 },
34954 .ErrorUnion => {
34955 const payload_ty = ty.errorUnionPayload(mod);
34956 return sema.resolveTypeLayout(payload_ty);
34957 },
34958 .Fn => {
34959 const info = mod.typeToFunc(ty).?;
34960 if (info.is_generic) {
34961 // Resolving of generic function types is deferred to when
34962 // the function is instantiated.
34963 return;
34964 }
34965 const ip = &mod.intern_pool;
34966 for (0..info.param_types.len) |i| {
34967 const param_ty = info.param_types.get(ip)[i];
34968 try sema.resolveTypeLayout(Type.fromInterned(param_ty));
34969 }
34970 try sema.resolveTypeLayout(Type.fromInterned(info.return_type));
34971 },
34972 else => {},
34973 }
34692 return val.resolveLazy(sema.arena, sema.mod);
3497434693}
3497534694
3497634695/// Resolve a struct's alignment only without triggering resolution of its layout.
......@@ -34979,11 +34698,13 @@ pub fn resolveStructAlignment(
3497934698 sema: *Sema,
3498034699 ty: InternPool.Index,
3498134700 struct_type: InternPool.LoadedStructType,
34982) CompileError!Alignment {
34701) SemaError!void {
3498334702 const mod = sema.mod;
3498434703 const ip = &mod.intern_pool;
3498534704 const target = mod.getTarget();
3498634705
34706 assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?);
34707
3498734708 assert(struct_type.flagsPtr(ip).alignment == .none);
3498834709 assert(struct_type.layout != .@"packed");
3498934710
......@@ -34994,7 +34715,7 @@ pub fn resolveStructAlignment(
3499434715 struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
3499534716 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
3499634717 struct_type.flagsPtr(ip).alignment = result;
34997 return result;
34718 return;
3499834719 }
3499934720
3500034721 try sema.resolveTypeFieldsStruct(ty, struct_type);
......@@ -35006,7 +34727,7 @@ pub fn resolveStructAlignment(
3500634727 struct_type.flagsPtr(ip).assumed_pointer_aligned = true;
3500734728 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
3500834729 struct_type.flagsPtr(ip).alignment = result;
35009 return result;
34730 return;
3501034731 }
3501134732 defer struct_type.clearAlignmentWip(ip);
3501234733
......@@ -35016,30 +34737,35 @@ pub fn resolveStructAlignment(
3501634737 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
3501734738 if (struct_type.fieldIsComptime(ip, i) or try sema.typeRequiresComptime(field_ty))
3501834739 continue;
35019 const field_align = try sema.structFieldAlignment(
34740 const field_align = try mod.structFieldAlignmentAdvanced(
3502034741 struct_type.fieldAlign(ip, i),
3502134742 field_ty,
3502234743 struct_type.layout,
34744 .sema,
3502334745 );
3502434746 result = result.maxStrict(field_align);
3502534747 }
3502634748
3502734749 struct_type.flagsPtr(ip).alignment = result;
35028 return result;
3502934750}
3503034751
35031fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
34752pub fn resolveStructLayout(sema: *Sema, ty: Type) SemaError!void {
3503234753 const zcu = sema.mod;
3503334754 const ip = &zcu.intern_pool;
3503434755 const struct_type = zcu.typeToStruct(ty) orelse return;
3503534756
34757 assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?);
34758
3503634759 if (struct_type.haveLayout(ip))
3503734760 return;
3503834761
35039 try sema.resolveTypeFields(ty);
34762 try ty.resolveFields(zcu);
3504034763
3504134764 if (struct_type.layout == .@"packed") {
35042 try semaBackingIntType(zcu, struct_type);
34765 semaBackingIntType(zcu, struct_type) catch |err| switch (err) {
34766 error.OutOfMemory, error.AnalysisFail => |e| return e,
34767 error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable,
34768 };
3504334769 return;
3504434770 }
3504534771
......@@ -35075,10 +34801,11 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
3507534801 },
3507634802 else => return err,
3507734803 };
35078 field_align.* = try sema.structFieldAlignment(
34804 field_align.* = try zcu.structFieldAlignmentAdvanced(
3507934805 struct_type.fieldAlign(ip, i),
3508034806 field_ty,
3508134807 struct_type.layout,
34808 .sema,
3508234809 );
3508334810 big_align = big_align.maxStrict(field_align.*);
3508434811 }
......@@ -35214,7 +34941,7 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
3521434941 var accumulator: u64 = 0;
3521534942 for (0..struct_type.field_types.len) |i| {
3521634943 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
35217 accumulator += try field_ty.bitSizeAdvanced(mod, &sema);
34944 accumulator += try field_ty.bitSizeAdvanced(mod, .sema);
3521834945 }
3521934946 break :blk accumulator;
3522034947 };
......@@ -35263,6 +34990,8 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) Co
3526334990 const backing_int_ty = try mod.intType(.unsigned, @intCast(fields_bit_sum));
3526434991 struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
3526534992 }
34993
34994 try sema.flushExports();
3526634995}
3526734996
3526834997fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
......@@ -35322,11 +35051,13 @@ pub fn resolveUnionAlignment(
3532235051 sema: *Sema,
3532335052 ty: Type,
3532435053 union_type: InternPool.LoadedUnionType,
35325) CompileError!Alignment {
35054) SemaError!void {
3532635055 const mod = sema.mod;
3532735056 const ip = &mod.intern_pool;
3532835057 const target = mod.getTarget();
3532935058
35059 assert(sema.ownerUnit().unwrap().decl == union_type.decl);
35060
3533035061 assert(!union_type.haveLayout(ip));
3533135062
3533235063 if (union_type.flagsPtr(ip).status == .field_types_wip) {
......@@ -35336,7 +35067,7 @@ pub fn resolveUnionAlignment(
3533635067 union_type.flagsPtr(ip).assumed_pointer_aligned = true;
3533735068 const result = Alignment.fromByteUnits(@divExact(target.ptrBitWidth(), 8));
3533835069 union_type.flagsPtr(ip).alignment = result;
35339 return result;
35070 return;
3534035071 }
3534135072
3534235073 try sema.resolveTypeFieldsUnion(ty, union_type);
......@@ -35356,11 +35087,10 @@ pub fn resolveUnionAlignment(
3535635087 }
3535735088
3535835089 union_type.flagsPtr(ip).alignment = max_align;
35359 return max_align;
3536035090}
3536135091
3536235092/// This logic must be kept in sync with `Module.getUnionLayout`.
35363fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
35093pub fn resolveUnionLayout(sema: *Sema, ty: Type) SemaError!void {
3536435094 const zcu = sema.mod;
3536535095 const ip = &zcu.intern_pool;
3536635096
......@@ -35369,6 +35099,8 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3536935099 // Load again, since the tag type might have changed due to resolution.
3537035100 const union_type = ip.loadUnionType(ty.ip_index);
3537135101
35102 assert(sema.ownerUnit().unwrap().decl == union_type.decl);
35103
3537235104 switch (union_type.flagsPtr(ip).status) {
3537335105 .none, .have_field_types => {},
3537435106 .field_types_wip, .layout_wip => {
......@@ -35477,53 +35209,15 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
3547735209
3547835210/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
3547935211/// be resolved.
35480pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void {
35481 const mod = sema.mod;
35482 const ip = &mod.intern_pool;
35483 switch (ty.zigTypeTag(mod)) {
35484 .Pointer => {
35485 return sema.resolveTypeFully(ty.childType(mod));
35486 },
35487 .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
35488 .struct_type => try sema.resolveStructFully(ty),
35489 .anon_struct_type => |tuple| {
35490 for (tuple.types.get(ip)) |field_ty| {
35491 try sema.resolveTypeFully(Type.fromInterned(field_ty));
35492 }
35493 },
35494 .simple_type => |simple_type| try sema.resolveSimpleType(simple_type),
35495 else => {},
35496 },
35497 .Union => return sema.resolveUnionFully(ty),
35498 .Array => return sema.resolveTypeFully(ty.childType(mod)),
35499 .Optional => {
35500 return sema.resolveTypeFully(ty.optionalChild(mod));
35501 },
35502 .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)),
35503 .Fn => {
35504 const info = mod.typeToFunc(ty).?;
35505 if (info.is_generic) {
35506 // Resolving of generic function types is deferred to when
35507 // the function is instantiated.
35508 return;
35509 }
35510 for (0..info.param_types.len) |i| {
35511 const param_ty = info.param_types.get(ip)[i];
35512 try sema.resolveTypeFully(Type.fromInterned(param_ty));
35513 }
35514 try sema.resolveTypeFully(Type.fromInterned(info.return_type));
35515 },
35516 else => {},
35517 }
35518}
35519
35520fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
35212pub fn resolveStructFully(sema: *Sema, ty: Type) SemaError!void {
3552135213 try sema.resolveStructLayout(ty);
3552235214
3552335215 const mod = sema.mod;
3552435216 const ip = &mod.intern_pool;
3552535217 const struct_type = mod.typeToStruct(ty).?;
3552635218
35219 assert(sema.ownerUnit().unwrap().decl == struct_type.decl.unwrap().?);
35220
3552735221 if (struct_type.setFullyResolved(ip)) return;
3552835222 errdefer struct_type.clearFullyResolved(ip);
3552935223
......@@ -35533,16 +35227,19 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
3553335227
3553435228 for (0..struct_type.field_types.len) |i| {
3553535229 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
35536 try sema.resolveTypeFully(field_ty);
35230 try field_ty.resolveFully(mod);
3553735231 }
3553835232}
3553935233
35540fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
35234pub fn resolveUnionFully(sema: *Sema, ty: Type) SemaError!void {
3554135235 try sema.resolveUnionLayout(ty);
3554235236
3554335237 const mod = sema.mod;
3554435238 const ip = &mod.intern_pool;
3554535239 const union_obj = mod.typeToUnion(ty).?;
35240
35241 assert(sema.ownerUnit().unwrap().decl == union_obj.decl);
35242
3554635243 switch (union_obj.flagsPtr(ip).status) {
3554735244 .none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
3554835245 .fully_resolved_wip, .fully_resolved => return,
......@@ -35558,7 +35255,7 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
3555835255 union_obj.flagsPtr(ip).status = .fully_resolved_wip;
3555935256 for (0..union_obj.field_types.len) |field_index| {
3556035257 const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
35561 try sema.resolveTypeFully(field_ty);
35258 try field_ty.resolveFully(mod);
3556235259 }
3556335260 union_obj.flagsPtr(ip).status = .fully_resolved;
3556435261 }
......@@ -35567,135 +35264,18 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
3556735264 _ = try sema.typeRequiresComptime(ty);
3556835265}
3556935266
35570pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
35571 const mod = sema.mod;
35572 const ip = &mod.intern_pool;
35573 const ty_ip = ty.toIntern();
35574
35575 switch (ty_ip) {
35576 .none => unreachable,
35577
35578 .u0_type,
35579 .i0_type,
35580 .u1_type,
35581 .u8_type,
35582 .i8_type,
35583 .u16_type,
35584 .i16_type,
35585 .u29_type,
35586 .u32_type,
35587 .i32_type,
35588 .u64_type,
35589 .i64_type,
35590 .u80_type,
35591 .u128_type,
35592 .i128_type,
35593 .usize_type,
35594 .isize_type,
35595 .c_char_type,
35596 .c_short_type,
35597 .c_ushort_type,
35598 .c_int_type,
35599 .c_uint_type,
35600 .c_long_type,
35601 .c_ulong_type,
35602 .c_longlong_type,
35603 .c_ulonglong_type,
35604 .c_longdouble_type,
35605 .f16_type,
35606 .f32_type,
35607 .f64_type,
35608 .f80_type,
35609 .f128_type,
35610 .anyopaque_type,
35611 .bool_type,
35612 .void_type,
35613 .type_type,
35614 .anyerror_type,
35615 .adhoc_inferred_error_set_type,
35616 .comptime_int_type,
35617 .comptime_float_type,
35618 .noreturn_type,
35619 .anyframe_type,
35620 .null_type,
35621 .undefined_type,
35622 .enum_literal_type,
35623 .manyptr_u8_type,
35624 .manyptr_const_u8_type,
35625 .manyptr_const_u8_sentinel_0_type,
35626 .single_const_pointer_to_comptime_int_type,
35627 .slice_const_u8_type,
35628 .slice_const_u8_sentinel_0_type,
35629 .optional_noreturn_type,
35630 .anyerror_void_error_union_type,
35631 .generic_poison_type,
35632 .empty_struct_type,
35633 => {},
35634
35635 .undef => unreachable,
35636 .zero => unreachable,
35637 .zero_usize => unreachable,
35638 .zero_u8 => unreachable,
35639 .one => unreachable,
35640 .one_usize => unreachable,
35641 .one_u8 => unreachable,
35642 .four_u8 => unreachable,
35643 .negative_one => unreachable,
35644 .calling_convention_c => unreachable,
35645 .calling_convention_inline => unreachable,
35646 .void_value => unreachable,
35647 .unreachable_value => unreachable,
35648 .null_value => unreachable,
35649 .bool_true => unreachable,
35650 .bool_false => unreachable,
35651 .empty_struct => unreachable,
35652 .generic_poison => unreachable,
35653
35654 else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
35655 .type_struct,
35656 .type_struct_packed,
35657 .type_struct_packed_inits,
35658 => try sema.resolveTypeFieldsStruct(ty_ip, ip.loadStructType(ty_ip)),
35659
35660 .type_union => try sema.resolveTypeFieldsUnion(Type.fromInterned(ty_ip), ip.loadUnionType(ty_ip)),
35661 .simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
35662 else => {},
35663 },
35664 }
35665}
35666
35667/// Fully resolves a simple type. This is usually a nop, but for builtin types with
35668/// special InternPool indices (such as std.builtin.Type) it will analyze and fully
35669/// resolve the container type.
35670fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileError!void {
35671 const builtin_type_name: []const u8 = switch (simple_type) {
35672 .atomic_order => "AtomicOrder",
35673 .atomic_rmw_op => "AtomicRmwOp",
35674 .calling_convention => "CallingConvention",
35675 .address_space => "AddressSpace",
35676 .float_mode => "FloatMode",
35677 .reduce_op => "ReduceOp",
35678 .call_modifier => "CallModifer",
35679 .prefetch_options => "PrefetchOptions",
35680 .export_options => "ExportOptions",
35681 .extern_options => "ExternOptions",
35682 .type_info => "Type",
35683 else => return,
35684 };
35685 // This will fully resolve the type.
35686 _ = try sema.getBuiltinType(builtin_type_name);
35687}
35688
3568935267pub fn resolveTypeFieldsStruct(
3569035268 sema: *Sema,
3569135269 ty: InternPool.Index,
3569235270 struct_type: InternPool.LoadedStructType,
35693) CompileError!void {
35271) SemaError!void {
3569435272 const zcu = sema.mod;
3569535273 const ip = &zcu.intern_pool;
3569635274 // If there is no owner decl it means the struct has no fields.
3569735275 const owner_decl = struct_type.decl.unwrap() orelse return;
3569835276
35277 assert(sema.ownerUnit().unwrap().decl == owner_decl);
35278
3569935279 switch (zcu.declPtr(owner_decl).analysis) {
3570035280 .file_failure,
3570135281 .dependency_failure,
......@@ -35726,16 +35306,19 @@ pub fn resolveTypeFieldsStruct(
3572635306 }
3572735307 return error.AnalysisFail;
3572835308 },
35729 else => |e| return e,
35309 error.OutOfMemory => return error.OutOfMemory,
35310 error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable,
3573035311 };
3573135312}
3573235313
35733pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
35314pub fn resolveStructFieldInits(sema: *Sema, ty: Type) SemaError!void {
3573435315 const zcu = sema.mod;
3573535316 const ip = &zcu.intern_pool;
3573635317 const struct_type = zcu.typeToStruct(ty) orelse return;
3573735318 const owner_decl = struct_type.decl.unwrap() orelse return;
3573835319
35320 assert(sema.ownerUnit().unwrap().decl == owner_decl);
35321
3573935322 // Inits can start as resolved
3574035323 if (struct_type.haveFieldInits(ip)) return;
3574135324
......@@ -35758,15 +35341,19 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
3575835341 }
3575935342 return error.AnalysisFail;
3576035343 },
35761 else => |e| return e,
35344 error.OutOfMemory => return error.OutOfMemory,
35345 error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable,
3576235346 };
3576335347 struct_type.setHaveFieldInits(ip);
3576435348}
3576535349
35766pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) CompileError!void {
35350pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) SemaError!void {
3576735351 const zcu = sema.mod;
3576835352 const ip = &zcu.intern_pool;
3576935353 const owner_decl = zcu.declPtr(union_type.decl);
35354
35355 assert(sema.ownerUnit().unwrap().decl == union_type.decl);
35356
3577035357 switch (owner_decl.analysis) {
3577135358 .file_failure,
3577235359 .dependency_failure,
......@@ -35804,7 +35391,8 @@ pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Load
3580435391 }
3580535392 return error.AnalysisFail;
3580635393 },
35807 else => |e| return e,
35394 error.OutOfMemory => return error.OutOfMemory,
35395 error.ComptimeBreak, error.ComptimeReturn, error.GenericPoison => unreachable,
3580835396 };
3580935397 union_type.flagsPtr(ip).status = .have_field_types;
3581035398}
......@@ -35860,6 +35448,7 @@ fn resolveInferredErrorSet(
3586035448 }
3586135449 // In this case we are dealing with the actual InferredErrorSet object that
3586235450 // corresponds to the function, not one created to track an inline/comptime call.
35451 try sema.addReferenceEntry(src, AnalUnit.wrap(.{ .func = func_index }));
3586335452 try sema.ensureFuncBodyAnalyzed(func_index);
3586435453 }
3586535454
......@@ -36225,6 +35814,8 @@ fn semaStructFields(
3622535814
3622635815 struct_type.clearTypesWip(ip);
3622735816 if (!any_inits) struct_type.setHaveFieldInits(ip);
35817
35818 try sema.flushExports();
3622835819}
3622935820
3623035821// This logic must be kept in sync with `semaStructFields`
......@@ -36365,6 +35956,8 @@ fn semaStructFieldInits(
3636535956 struct_type.field_inits.get(ip)[field_i] = default_val.toIntern();
3636635957 }
3636735958 }
35959
35960 try sema.flushExports();
3636835961}
3636935962
3637035963fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {
......@@ -36738,6 +36331,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Loaded
3673836331 const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
3673936332 union_type.tagTypePtr(ip).* = enum_ty;
3674036333 }
36334
36335 try sema.flushExports();
3674136336}
3674236337
3674336338fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Type, tag_ref: Air.Inst.Ref) CompileError!Value {
......@@ -36846,106 +36441,6 @@ fn generateUnionTagTypeSimple(
3684636441 return enum_ty;
3684736442}
3684836443
36849fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
36850 const zcu = sema.mod;
36851
36852 var block: Block = .{
36853 .parent = null,
36854 .sema = sema,
36855 .namespace = sema.owner_decl.src_namespace,
36856 .instructions = .{},
36857 .inlining = null,
36858 .is_comptime = true,
36859 .src_base_inst = sema.owner_decl.zir_decl_index.unwrap() orelse owner: {
36860 assert(sema.owner_decl.has_tv);
36861 assert(sema.owner_decl.owns_tv);
36862 switch (sema.owner_decl.typeOf(zcu).zigTypeTag(zcu)) {
36863 .Type => break :owner sema.owner_decl.val.toType().typeDeclInst(zcu).?,
36864 .Fn => {
36865 const owner = zcu.funcInfo(sema.owner_decl.val.toIntern()).generic_owner;
36866 const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl);
36867 break :owner generic_owner_decl.zir_decl_index.unwrap().?;
36868 },
36869 else => unreachable,
36870 }
36871 },
36872 .type_name_ctx = sema.owner_decl.name,
36873 };
36874 defer block.instructions.deinit(sema.gpa);
36875
36876 const src = block.nodeOffset(0);
36877
36878 const decl_index = try getBuiltinDecl(sema, &block, name);
36879 return sema.analyzeDeclVal(&block, src, decl_index);
36880}
36881
36882fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!InternPool.DeclIndex {
36883 const gpa = sema.gpa;
36884
36885 const src = block.nodeOffset(0);
36886
36887 const mod = sema.mod;
36888 const ip = &mod.intern_pool;
36889 const std_mod = mod.std_mod;
36890 const std_file = (mod.importPkg(std_mod) catch unreachable).file;
36891 const opt_builtin_inst = (try sema.namespaceLookupRef(
36892 block,
36893 src,
36894 mod.declPtr(std_file.root_decl.unwrap().?).src_namespace.toOptional(),
36895 try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls),
36896 )) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
36897 const builtin_inst = try sema.analyzeLoad(block, src, opt_builtin_inst, src);
36898 const builtin_ty = sema.analyzeAsType(block, src, builtin_inst) catch |err| switch (err) {
36899 error.AnalysisFail => std.debug.panic("std.builtin is corrupt", .{}),
36900 else => |e| return e,
36901 };
36902 const decl_index = (try sema.namespaceLookup(
36903 block,
36904 src,
36905 builtin_ty.getNamespaceIndex(mod),
36906 try ip.getOrPutString(gpa, name, .no_embedded_nulls),
36907 )) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name});
36908 return decl_index;
36909}
36910
36911fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
36912 const zcu = sema.mod;
36913 const ty_inst = try sema.getBuiltin(name);
36914
36915 var block: Block = .{
36916 .parent = null,
36917 .sema = sema,
36918 .namespace = sema.owner_decl.src_namespace,
36919 .instructions = .{},
36920 .inlining = null,
36921 .is_comptime = true,
36922 .src_base_inst = sema.owner_decl.zir_decl_index.unwrap() orelse owner: {
36923 assert(sema.owner_decl.has_tv);
36924 assert(sema.owner_decl.owns_tv);
36925 switch (sema.owner_decl.typeOf(zcu).zigTypeTag(zcu)) {
36926 .Type => break :owner sema.owner_decl.val.toType().typeDeclInst(zcu).?,
36927 .Fn => {
36928 const owner = zcu.funcInfo(sema.owner_decl.val.toIntern()).generic_owner;
36929 const generic_owner_decl = zcu.declPtr(zcu.funcInfo(owner).owner_decl);
36930 break :owner generic_owner_decl.zir_decl_index.unwrap().?;
36931 },
36932 else => unreachable,
36933 }
36934 },
36935 .type_name_ctx = sema.owner_decl.name,
36936 };
36937 defer block.instructions.deinit(sema.gpa);
36938
36939 const src = block.nodeOffset(0);
36940
36941 const result_ty = sema.analyzeAsType(&block, src, ty_inst) catch |err| switch (err) {
36942 error.AnalysisFail => std.debug.panic("std.builtin.{s} is corrupt", .{name}),
36943 else => |e| return e,
36944 };
36945 try sema.resolveTypeFully(result_ty); // Should not fail
36946 return result_ty;
36947}
36948
3694936444/// There is another implementation of this in `Type.onePossibleValue`. This one
3695036445/// in `Sema` is for calling during semantic analysis, and performs field resolution
3695136446/// to get the answer. The one in `Type` is for calling during codegen and asserts
......@@ -37149,8 +36644,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3714936644 },
3715036645
3715136646 .struct_type => {
36647 // Resolving the layout first helps to avoid loops.
36648 // If the type has a coherent layout, we can recurse through fields safely.
36649 try ty.resolveLayout(zcu);
36650
3715236651 const struct_type = ip.loadStructType(ty.toIntern());
37153 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
3715436652
3715536653 if (struct_type.field_types.len == 0) {
3715636654 // In this case the struct has no fields at all and
......@@ -37167,20 +36665,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3716736665 );
3716836666 for (field_vals, 0..) |*field_val, i| {
3716936667 if (struct_type.fieldIsComptime(ip, i)) {
37170 try sema.resolveStructFieldInits(ty);
36668 try ty.resolveStructFieldInits(zcu);
3717136669 field_val.* = struct_type.field_inits.get(ip)[i];
3717236670 continue;
3717336671 }
3717436672 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
37175 if (field_ty.eql(ty, zcu)) {
37176 const msg = try sema.errMsg(
37177 ty.srcLoc(zcu),
37178 "struct '{}' depends on itself",
37179 .{ty.fmt(zcu)},
37180 );
37181 try sema.addFieldErrNote(ty, i, msg, "while checking this field", .{});
37182 return sema.failWithOwnedErrorMsg(null, msg);
37183 }
3718436673 if (try sema.typeHasOnePossibleValue(field_ty)) |field_opv| {
3718536674 field_val.* = field_opv.toIntern();
3718636675 } else return null;
......@@ -37208,8 +36697,11 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3720836697 },
3720936698
3721036699 .union_type => {
36700 // Resolving the layout first helps to avoid loops.
36701 // If the type has a coherent layout, we can recurse through fields safely.
36702 try ty.resolveLayout(zcu);
36703
3721136704 const union_obj = ip.loadUnionType(ty.toIntern());
37212 try sema.resolveTypeFieldsUnion(ty, union_obj);
3721336705 const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.tagTypePtr(ip).*))) orelse
3721436706 return null;
3721536707 if (union_obj.field_types.len == 0) {
......@@ -37217,15 +36709,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
3721736709 return Value.fromInterned(only);
3721836710 }
3721936711 const only_field_ty = Type.fromInterned(union_obj.field_types.get(ip)[0]);
37220 if (only_field_ty.eql(ty, zcu)) {
37221 const msg = try sema.errMsg(
37222 ty.srcLoc(zcu),
37223 "union '{}' depends on itself",
37224 .{ty.fmt(zcu)},
37225 );
37226 try sema.addFieldErrNote(ty, 0, msg, "while checking this field", .{});
37227 return sema.failWithOwnedErrorMsg(null, msg);
37228 }
3722936712 const val_val = (try sema.typeHasOnePossibleValue(only_field_ty)) orelse
3723036713 return null;
3723136714 const only = try zcu.intern(.{ .un = .{
......@@ -37343,7 +36826,7 @@ fn analyzeComptimeAlloc(
3734336826 // Needed to make an anon decl with type `var_type` (the `finish()` call below).
3734436827 _ = try sema.typeHasOnePossibleValue(var_type);
3734536828
37346 const ptr_type = try sema.ptrType(.{
36829 const ptr_type = try mod.ptrTypeSema(.{
3734736830 .child = var_type.toIntern(),
3734836831 .flags = .{
3734936832 .alignment = alignment,
......@@ -37530,64 +37013,28 @@ fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
3753037013
3753137014/// `generic_poison` will return false.
3753237015/// May return false negatives when structs and unions are having their field types resolved.
37533pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
37534 return ty.comptimeOnlyAdvanced(sema.mod, sema);
37016pub fn typeRequiresComptime(sema: *Sema, ty: Type) SemaError!bool {
37017 return ty.comptimeOnlyAdvanced(sema.mod, .sema);
3753537018}
3753637019
37537pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
37538 const mod = sema.mod;
37539 return ty.hasRuntimeBitsAdvanced(mod, false, .{ .sema = sema }) catch |err| switch (err) {
37020pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) SemaError!bool {
37021 return ty.hasRuntimeBitsAdvanced(sema.mod, false, .sema) catch |err| switch (err) {
3754037022 error.NeedLazy => unreachable,
3754137023 else => |e| return e,
3754237024 };
3754337025}
3754437026
37545pub fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
37546 try sema.resolveTypeLayout(ty);
37027pub fn typeAbiSize(sema: *Sema, ty: Type) SemaError!u64 {
37028 try ty.resolveLayout(sema.mod);
3754737029 return ty.abiSize(sema.mod);
3754837030}
3754937031
37550pub fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
37551 return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
37552}
37553
37554/// Not valid to call for packed unions.
37555/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
37556pub fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment {
37557 const mod = sema.mod;
37558 const ip = &mod.intern_pool;
37559 const field_align = u.fieldAlign(ip, field_index);
37560 if (field_align != .none) return field_align;
37561 const field_ty = Type.fromInterned(u.field_types.get(ip)[field_index]);
37562 if (field_ty.isNoReturn(sema.mod)) return .none;
37563 return sema.typeAbiAlignment(field_ty);
37564}
37565
37566/// Keep implementation in sync with `Module.structFieldAlignment`.
37567pub fn structFieldAlignment(
37568 sema: *Sema,
37569 explicit_alignment: InternPool.Alignment,
37570 field_ty: Type,
37571 layout: std.builtin.Type.ContainerLayout,
37572) !Alignment {
37573 if (explicit_alignment != .none)
37574 return explicit_alignment;
37575 const mod = sema.mod;
37576 switch (layout) {
37577 .@"packed" => return .none,
37578 .auto => if (mod.getTarget().ofmt != .c) return sema.typeAbiAlignment(field_ty),
37579 .@"extern" => {},
37580 }
37581 // extern
37582 const ty_abi_align = try sema.typeAbiAlignment(field_ty);
37583 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
37584 return ty_abi_align.maxStrict(.@"16");
37585 }
37586 return ty_abi_align;
37032pub fn typeAbiAlignment(sema: *Sema, ty: Type) SemaError!Alignment {
37033 return (try ty.abiAlignmentAdvanced(sema.mod, .sema)).scalar;
3758737034}
3758837035
3758937036pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
37590 return ty.fnHasRuntimeBitsAdvanced(sema.mod, sema);
37037 return ty.fnHasRuntimeBitsAdvanced(sema.mod, .sema);
3759137038}
3759237039
3759337040fn unionFieldIndex(
......@@ -37599,7 +37046,7 @@ fn unionFieldIndex(
3759937046) !u32 {
3760037047 const mod = sema.mod;
3760137048 const ip = &mod.intern_pool;
37602 try sema.resolveTypeFields(union_ty);
37049 try union_ty.resolveFields(mod);
3760337050 const union_obj = mod.typeToUnion(union_ty).?;
3760437051 const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
3760537052 return sema.failWithBadUnionFieldAccess(block, union_ty, union_obj, field_src, field_name);
......@@ -37615,7 +37062,7 @@ fn structFieldIndex(
3761537062) !u32 {
3761637063 const mod = sema.mod;
3761737064 const ip = &mod.intern_pool;
37618 try sema.resolveTypeFields(struct_ty);
37065 try struct_ty.resolveFields(mod);
3761937066 if (struct_ty.isAnonStruct(mod)) {
3762037067 return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
3762137068 } else {
......@@ -37646,10 +37093,6 @@ fn anonStructFieldIndex(
3764637093 });
3764737094}
3764837095
37649fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
37650 try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {});
37651}
37652
3765337096/// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting
3765437097/// overflow_idx to the vector index the overflow was at (or 0 for a scalar).
3765537098fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value {
......@@ -37707,8 +37150,8 @@ fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value {
3770737150 // resorting to BigInt first.
3770837151 var lhs_space: Value.BigIntSpace = undefined;
3770937152 var rhs_space: Value.BigIntSpace = undefined;
37710 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
37711 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
37153 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema);
37154 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema);
3771237155 const limbs = try sema.arena.alloc(
3771337156 std.math.big.Limb,
3771437157 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
......@@ -37797,8 +37240,8 @@ fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value {
3779737240 // resorting to BigInt first.
3779837241 var lhs_space: Value.BigIntSpace = undefined;
3779937242 var rhs_space: Value.BigIntSpace = undefined;
37800 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
37801 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
37243 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema);
37244 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema);
3780237245 const limbs = try sema.arena.alloc(
3780337246 std.math.big.Limb,
3780437247 @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
......@@ -37881,8 +37324,8 @@ fn intSubWithOverflowScalar(
3788137324
3788237325 var lhs_space: Value.BigIntSpace = undefined;
3788337326 var rhs_space: Value.BigIntSpace = undefined;
37884 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
37885 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
37327 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema);
37328 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema);
3788637329 const limbs = try sema.arena.alloc(
3788737330 std.math.big.Limb,
3788837331 std.math.big.int.calcTwosCompLimbCount(info.bits),
......@@ -38069,7 +37512,7 @@ fn intFitsInType(
3806937512
3807037513fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
3807137514 const mod = sema.mod;
38072 if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false;
37515 if (!(try int_val.compareAllWithZeroSema(.gte, mod))) return false;
3807337516 const end_val = try mod.intValue(tag_ty, end);
3807437517 if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false;
3807537518 return true;
......@@ -38139,8 +37582,8 @@ fn intAddWithOverflowScalar(
3813937582
3814037583 var lhs_space: Value.BigIntSpace = undefined;
3814137584 var rhs_space: Value.BigIntSpace = undefined;
38142 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
38143 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
37585 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, .sema);
37586 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, .sema);
3814437587 const limbs = try sema.arena.alloc(
3814537588 std.math.big.Limb,
3814637589 std.math.big.int.calcTwosCompLimbCount(info.bits),
......@@ -38194,7 +37637,7 @@ fn compareScalar(
3819437637 switch (op) {
3819537638 .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty),
3819637639 .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)),
38197 else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, sema),
37640 else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, .sema),
3819837641 }
3819937642}
3820037643
......@@ -38230,80 +37673,6 @@ fn compareVector(
3823037673 } })));
3823137674}
3823237675
38233/// Returns the type of a pointer to an element.
38234/// Asserts that the type is a pointer, and that the element type is indexable.
38235/// If the element index is comptime-known, it must be passed in `offset`.
38236/// For *@Vector(n, T), return *align(a:b:h:v) T
38237/// For *[N]T, return *T
38238/// For [*]T, returns *T
38239/// For []T, returns *T
38240/// Handles const-ness and address spaces in particular.
38241/// This code is duplicated in `analyzePtrArithmetic`.
38242pub fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
38243 const mod = sema.mod;
38244 const ptr_info = ptr_ty.ptrInfo(mod);
38245 const elem_ty = ptr_ty.elemType2(mod);
38246 const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0;
38247 const parent_ty = ptr_ty.childType(mod);
38248
38249 const VI = InternPool.Key.PtrType.VectorIndex;
38250
38251 const vector_info: struct {
38252 host_size: u16 = 0,
38253 alignment: Alignment = .none,
38254 vector_index: VI = .none,
38255 } = if (parent_ty.isVector(mod) and ptr_info.flags.size == .One) blk: {
38256 const elem_bits = elem_ty.bitSize(mod);
38257 if (elem_bits == 0) break :blk .{};
38258 const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);
38259 if (!is_packed) break :blk .{};
38260
38261 break :blk .{
38262 .host_size = @intCast(parent_ty.arrayLen(mod)),
38263 .alignment = parent_ty.abiAlignment(mod),
38264 .vector_index = if (offset) |some| @enumFromInt(some) else .runtime,
38265 };
38266 } else .{};
38267
38268 const alignment: Alignment = a: {
38269 // Calculate the new pointer alignment.
38270 if (ptr_info.flags.alignment == .none) {
38271 // In case of an ABI-aligned pointer, any pointer arithmetic
38272 // maintains the same ABI-alignedness.
38273 break :a vector_info.alignment;
38274 }
38275 // If the addend is not a comptime-known value we can still count on
38276 // it being a multiple of the type size.
38277 const elem_size = try sema.typeAbiSize(elem_ty);
38278 const addend = if (offset) |off| elem_size * off else elem_size;
38279
38280 // The resulting pointer is aligned to the lcd between the offset (an
38281 // arbitrary number) and the alignment factor (always a power of two,
38282 // non zero).
38283 const new_align: Alignment = @enumFromInt(@min(
38284 @ctz(addend),
38285 ptr_info.flags.alignment.toLog2Units(),
38286 ));
38287 assert(new_align != .none);
38288 break :a new_align;
38289 };
38290 return sema.ptrType(.{
38291 .child = elem_ty.toIntern(),
38292 .flags = .{
38293 .alignment = alignment,
38294 .is_const = ptr_info.flags.is_const,
38295 .is_volatile = ptr_info.flags.is_volatile,
38296 .is_allowzero = is_allowzero,
38297 .address_space = ptr_info.flags.address_space,
38298 .vector_index = vector_info.vector_index,
38299 },
38300 .packed_offset = .{
38301 .host_size = vector_info.host_size,
38302 .bit_offset = 0,
38303 },
38304 });
38305}
38306
3830737676/// Merge lhs with rhs.
3830837677/// Asserts that lhs and rhs are both error sets and are resolved.
3830937678fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type {
......@@ -38344,13 +37713,6 @@ fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool
3834437713 return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
3834537714}
3834637715
38347pub fn ptrType(sema: *Sema, info: InternPool.Key.PtrType) CompileError!Type {
38348 if (info.flags.alignment != .none) {
38349 _ = try sema.typeAbiAlignment(Type.fromInterned(info.child));
38350 }
38351 return sema.mod.ptrType(info);
38352}
38353
3835437716pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3835537717 if (!sema.mod.comp.debug_incremental) return;
3835637718
......@@ -38362,7 +37724,7 @@ pub fn declareDependency(sema: *Sema, dependee: InternPool.Dependee) !void {
3836237724 return;
3836337725 }
3836437726
38365 const depender = InternPool.AnalSubject.wrap(
37727 const depender = AnalUnit.wrap(
3836637728 if (sema.owner_func_index != .none)
3836737729 .{ .func = sema.owner_func_index }
3836837730 else
......@@ -38470,12 +37832,12 @@ fn maybeDerefSliceAsArray(
3847037832 else => unreachable,
3847137833 };
3847237834 const elem_ty = Type.fromInterned(slice.ty).childType(zcu);
38473 const len = try Value.fromInterned(slice.len).toUnsignedIntAdvanced(sema);
37835 const len = try Value.fromInterned(slice.len).toUnsignedIntSema(zcu);
3847437836 const array_ty = try zcu.arrayType(.{
3847537837 .child = elem_ty.toIntern(),
3847637838 .len = len,
3847737839 });
38478 const ptr_ty = try sema.ptrType(p: {
37840 const ptr_ty = try zcu.ptrTypeSema(p: {
3847937841 var p = Type.fromInterned(slice.ty).ptrInfo(zcu);
3848037842 p.flags.size = .One;
3848137843 p.child = array_ty.toIntern();
......@@ -38494,6 +37856,57 @@ fn analyzeUnreachable(sema: *Sema, block: *Block, src: LazySrcLoc, safety_check:
3849437856 }
3849537857}
3849637858
37859/// This should be called exactly once, at the end of a `Sema`'s lifetime.
37860/// It takes the exports stored in `sema.export` and flushes them to the `Zcu`
37861/// to be processed by the linker after the update.
37862pub fn flushExports(sema: *Sema) !void {
37863 if (sema.exports.items.len == 0) return;
37864
37865 const zcu = sema.mod;
37866 const gpa = zcu.gpa;
37867
37868 const unit = sema.ownerUnit();
37869
37870 // There may be existing exports. For instance, a struct may export
37871 // things during both field type resolution and field default resolution.
37872 //
37873 // So, pick up and delete any existing exports. This strategy performs
37874 // redundant work, but that's okay, because this case is exceedingly rare.
37875 if (zcu.single_exports.get(unit)) |export_idx| {
37876 try sema.exports.append(gpa, zcu.all_exports.items[export_idx]);
37877 } else if (zcu.multi_exports.get(unit)) |info| {
37878 try sema.exports.appendSlice(gpa, zcu.all_exports.items[info.index..][0..info.len]);
37879 }
37880 zcu.deleteUnitExports(unit);
37881
37882 // `sema.exports` is completed; store the data into the `Zcu`.
37883 if (sema.exports.items.len == 1) {
37884 try zcu.single_exports.ensureUnusedCapacity(gpa, 1);
37885 const export_idx = zcu.free_exports.popOrNull() orelse idx: {
37886 _ = try zcu.all_exports.addOne(gpa);
37887 break :idx zcu.all_exports.items.len - 1;
37888 };
37889 zcu.all_exports.items[export_idx] = sema.exports.items[0];
37890 zcu.single_exports.putAssumeCapacityNoClobber(unit, @intCast(export_idx));
37891 } else {
37892 try zcu.multi_exports.ensureUnusedCapacity(gpa, 1);
37893 const exports_base = zcu.all_exports.items.len;
37894 try zcu.all_exports.appendSlice(gpa, sema.exports.items);
37895 zcu.multi_exports.putAssumeCapacityNoClobber(unit, .{
37896 .index = @intCast(exports_base),
37897 .len = @intCast(sema.exports.items.len),
37898 });
37899 }
37900}
37901
37902pub fn ownerUnit(sema: Sema) AnalUnit {
37903 if (sema.owner_func_index != .none) {
37904 return AnalUnit.wrap(.{ .func = sema.owner_func_index });
37905 } else {
37906 return AnalUnit.wrap(.{ .decl = sema.owner_decl_index });
37907 }
37908}
37909
3849737910pub const bitCastVal = @import("Sema/bitcast.zig").bitCast;
3849837911pub const bitCastSpliceVal = @import("Sema/bitcast.zig").bitCastSplice;
3849937912
src/Sema/bitcast.zig+5-5
......@@ -78,8 +78,8 @@ fn bitCastInner(
7878
7979 const val_ty = val.typeOf(zcu);
8080
81 try sema.resolveTypeLayout(val_ty);
82 try sema.resolveTypeLayout(dest_ty);
81 try val_ty.resolveLayout(zcu);
82 try dest_ty.resolveLayout(zcu);
8383
8484 assert(val_ty.hasWellDefinedLayout(zcu));
8585
......@@ -136,8 +136,8 @@ fn bitCastSpliceInner(
136136 const val_ty = val.typeOf(zcu);
137137 const splice_val_ty = splice_val.typeOf(zcu);
138138
139 try sema.resolveTypeLayout(val_ty);
140 try sema.resolveTypeLayout(splice_val_ty);
139 try val_ty.resolveLayout(zcu);
140 try splice_val_ty.resolveLayout(zcu);
141141
142142 const splice_bits = splice_val_ty.bitSize(zcu);
143143
......@@ -767,6 +767,6 @@ const assert = std.debug.assert;
767767const Sema = @import("../Sema.zig");
768768const Zcu = @import("../Zcu.zig");
769769const InternPool = @import("../InternPool.zig");
770const Type = @import("../type.zig").Type;
770const Type = @import("../Type.zig");
771771const Value = @import("../Value.zig");
772772const CompileError = Zcu.CompileError;
src/Sema/comptime_ptr_access.zig+1-1
......@@ -1054,7 +1054,7 @@ const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
10541054const Sema = @import("../Sema.zig");
10551055const Block = Sema.Block;
10561056const MutableValue = @import("../mutable_value.zig").MutableValue;
1057const Type = @import("../type.zig").Type;
1057const Type = @import("../Type.zig");
10581058const Value = @import("../Value.zig");
10591059const Zcu = @import("../Zcu.zig");
10601060const LazySrcLoc = Zcu.LazySrcLoc;
src/Type.zig created+4009
......@@ -0,0 +1,4009 @@
1//! Both types and values are canonically represented by a single 32-bit integer
2//! which is an index into an `InternPool` data structure.
3//! This struct abstracts around this storage by providing methods only
4//! applicable to types rather than values in general.
5
6const std = @import("std");
7const builtin = @import("builtin");
8const Allocator = std.mem.Allocator;
9const Value = @import("Value.zig");
10const assert = std.debug.assert;
11const Target = std.Target;
12const Zcu = @import("Zcu.zig");
13/// Deprecated.
14const Module = Zcu;
15const log = std.log.scoped(.Type);
16const target_util = @import("target.zig");
17const Sema = @import("Sema.zig");
18const InternPool = @import("InternPool.zig");
19const Alignment = InternPool.Alignment;
20const Zir = std.zig.Zir;
21const Type = @This();
22const SemaError = Zcu.SemaError;
23
24ip_index: InternPool.Index,
25
26pub fn zigTypeTag(ty: Type, mod: *const Module) std.builtin.TypeId {
27 return ty.zigTypeTagOrPoison(mod) catch unreachable;
28}
29
30pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId {
31 return mod.intern_pool.zigTypeTagOrPoison(ty.toIntern());
32}
33
34pub fn baseZigTypeTag(self: Type, mod: *Module) std.builtin.TypeId {
35 return switch (self.zigTypeTag(mod)) {
36 .ErrorUnion => self.errorUnionPayload(mod).baseZigTypeTag(mod),
37 .Optional => {
38 return self.optionalChild(mod).baseZigTypeTag(mod);
39 },
40 else => |t| t,
41 };
42}
43
44pub fn isSelfComparable(ty: Type, mod: *const Module, is_equality_cmp: bool) bool {
45 return switch (ty.zigTypeTag(mod)) {
46 .Int,
47 .Float,
48 .ComptimeFloat,
49 .ComptimeInt,
50 => true,
51
52 .Vector => ty.elemType2(mod).isSelfComparable(mod, is_equality_cmp),
53
54 .Bool,
55 .Type,
56 .Void,
57 .ErrorSet,
58 .Fn,
59 .Opaque,
60 .AnyFrame,
61 .Enum,
62 .EnumLiteral,
63 => is_equality_cmp,
64
65 .NoReturn,
66 .Array,
67 .Struct,
68 .Undefined,
69 .Null,
70 .ErrorUnion,
71 .Union,
72 .Frame,
73 => false,
74
75 .Pointer => !ty.isSlice(mod) and (is_equality_cmp or ty.isCPtr(mod)),
76 .Optional => {
77 if (!is_equality_cmp) return false;
78 return ty.optionalChild(mod).isSelfComparable(mod, is_equality_cmp);
79 },
80 };
81}
82
83/// If it is a function pointer, returns the function type. Otherwise returns null.
84pub fn castPtrToFn(ty: Type, mod: *const Module) ?Type {
85 if (ty.zigTypeTag(mod) != .Pointer) return null;
86 const elem_ty = ty.childType(mod);
87 if (elem_ty.zigTypeTag(mod) != .Fn) return null;
88 return elem_ty;
89}
90
91/// Asserts the type is a pointer.
92pub fn ptrIsMutable(ty: Type, mod: *const Module) bool {
93 return !mod.intern_pool.indexToKey(ty.toIntern()).ptr_type.flags.is_const;
94}
95
96pub const ArrayInfo = struct {
97 elem_type: Type,
98 sentinel: ?Value = null,
99 len: u64,
100};
101
102pub fn arrayInfo(self: Type, mod: *const Module) ArrayInfo {
103 return .{
104 .len = self.arrayLen(mod),
105 .sentinel = self.sentinel(mod),
106 .elem_type = self.childType(mod),
107 };
108}
109
110pub fn ptrInfo(ty: Type, mod: *const Module) InternPool.Key.PtrType {
111 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
112 .ptr_type => |p| p,
113 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
114 .ptr_type => |p| p,
115 else => unreachable,
116 },
117 else => unreachable,
118 };
119}
120
121pub fn eql(a: Type, b: Type, mod: *const Module) bool {
122 _ = mod; // TODO: remove this parameter
123 // The InternPool data structure hashes based on Key to make interned objects
124 // unique. An Index can be treated simply as u32 value for the
125 // purpose of Type/Value hashing and equality.
126 return a.toIntern() == b.toIntern();
127}
128
129pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
130 _ = ty;
131 _ = unused_fmt_string;
132 _ = options;
133 _ = writer;
134 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
135}
136
137pub const Formatter = std.fmt.Formatter(format2);
138
139pub fn fmt(ty: Type, module: *Module) Formatter {
140 return .{ .data = .{
141 .ty = ty,
142 .module = module,
143 } };
144}
145
146const FormatContext = struct {
147 ty: Type,
148 module: *Module,
149};
150
151fn format2(
152 ctx: FormatContext,
153 comptime unused_format_string: []const u8,
154 options: std.fmt.FormatOptions,
155 writer: anytype,
156) !void {
157 comptime assert(unused_format_string.len == 0);
158 _ = options;
159 return print(ctx.ty, writer, ctx.module);
160}
161
162pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
163 return .{ .data = ty };
164}
165
166/// This is a debug function. In order to print types in a meaningful way
167/// we also need access to the module.
168pub fn dump(
169 start_type: Type,
170 comptime unused_format_string: []const u8,
171 options: std.fmt.FormatOptions,
172 writer: anytype,
173) @TypeOf(writer).Error!void {
174 _ = options;
175 comptime assert(unused_format_string.len == 0);
176 return writer.print("{any}", .{start_type.ip_index});
177}
178
179/// Prints a name suitable for `@typeName`.
180/// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels.
181pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void {
182 const ip = &mod.intern_pool;
183 switch (ip.indexToKey(ty.toIntern())) {
184 .int_type => |int_type| {
185 const sign_char: u8 = switch (int_type.signedness) {
186 .signed => 'i',
187 .unsigned => 'u',
188 };
189 return writer.print("{c}{d}", .{ sign_char, int_type.bits });
190 },
191 .ptr_type => {
192 const info = ty.ptrInfo(mod);
193
194 if (info.sentinel != .none) switch (info.flags.size) {
195 .One, .C => unreachable,
196 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
197 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
198 } else switch (info.flags.size) {
199 .One => try writer.writeAll("*"),
200 .Many => try writer.writeAll("[*]"),
201 .C => try writer.writeAll("[*c]"),
202 .Slice => try writer.writeAll("[]"),
203 }
204 if (info.flags.alignment != .none or
205 info.packed_offset.host_size != 0 or
206 info.flags.vector_index != .none)
207 {
208 const alignment = if (info.flags.alignment != .none)
209 info.flags.alignment
210 else
211 Type.fromInterned(info.child).abiAlignment(mod);
212 try writer.print("align({d}", .{alignment.toByteUnits() orelse 0});
213
214 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
215 try writer.print(":{d}:{d}", .{
216 info.packed_offset.bit_offset, info.packed_offset.host_size,
217 });
218 }
219 if (info.flags.vector_index == .runtime) {
220 try writer.writeAll(":?");
221 } else if (info.flags.vector_index != .none) {
222 try writer.print(":{d}", .{@intFromEnum(info.flags.vector_index)});
223 }
224 try writer.writeAll(") ");
225 }
226 if (info.flags.address_space != .generic) {
227 try writer.print("addrspace(.{s}) ", .{@tagName(info.flags.address_space)});
228 }
229 if (info.flags.is_const) try writer.writeAll("const ");
230 if (info.flags.is_volatile) try writer.writeAll("volatile ");
231 if (info.flags.is_allowzero and info.flags.size != .C) try writer.writeAll("allowzero ");
232
233 try print(Type.fromInterned(info.child), writer, mod);
234 return;
235 },
236 .array_type => |array_type| {
237 if (array_type.sentinel == .none) {
238 try writer.print("[{d}]", .{array_type.len});
239 try print(Type.fromInterned(array_type.child), writer, mod);
240 } else {
241 try writer.print("[{d}:{}]", .{
242 array_type.len,
243 Value.fromInterned(array_type.sentinel).fmtValue(mod, null),
244 });
245 try print(Type.fromInterned(array_type.child), writer, mod);
246 }
247 return;
248 },
249 .vector_type => |vector_type| {
250 try writer.print("@Vector({d}, ", .{vector_type.len});
251 try print(Type.fromInterned(vector_type.child), writer, mod);
252 try writer.writeAll(")");
253 return;
254 },
255 .opt_type => |child| {
256 try writer.writeByte('?');
257 return print(Type.fromInterned(child), writer, mod);
258 },
259 .error_union_type => |error_union_type| {
260 try print(Type.fromInterned(error_union_type.error_set_type), writer, mod);
261 try writer.writeByte('!');
262 if (error_union_type.payload_type == .generic_poison_type) {
263 try writer.writeAll("anytype");
264 } else {
265 try print(Type.fromInterned(error_union_type.payload_type), writer, mod);
266 }
267 return;
268 },
269 .inferred_error_set_type => |func_index| {
270 try writer.writeAll("@typeInfo(@typeInfo(@TypeOf(");
271 const owner_decl = mod.funcOwnerDeclPtr(func_index);
272 try owner_decl.renderFullyQualifiedName(mod, writer);
273 try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set");
274 },
275 .error_set_type => |error_set_type| {
276 const names = error_set_type.names;
277 try writer.writeAll("error{");
278 for (names.get(ip), 0..) |name, i| {
279 if (i != 0) try writer.writeByte(',');
280 try writer.print("{}", .{name.fmt(ip)});
281 }
282 try writer.writeAll("}");
283 },
284 .simple_type => |s| switch (s) {
285 .f16,
286 .f32,
287 .f64,
288 .f80,
289 .f128,
290 .usize,
291 .isize,
292 .c_char,
293 .c_short,
294 .c_ushort,
295 .c_int,
296 .c_uint,
297 .c_long,
298 .c_ulong,
299 .c_longlong,
300 .c_ulonglong,
301 .c_longdouble,
302 .anyopaque,
303 .bool,
304 .void,
305 .type,
306 .anyerror,
307 .comptime_int,
308 .comptime_float,
309 .noreturn,
310 .adhoc_inferred_error_set,
311 => return writer.writeAll(@tagName(s)),
312
313 .null,
314 .undefined,
315 => try writer.print("@TypeOf({s})", .{@tagName(s)}),
316
317 .enum_literal => try writer.print("@TypeOf(.{s})", .{@tagName(s)}),
318 .atomic_order => try writer.writeAll("std.builtin.AtomicOrder"),
319 .atomic_rmw_op => try writer.writeAll("std.builtin.AtomicRmwOp"),
320 .calling_convention => try writer.writeAll("std.builtin.CallingConvention"),
321 .address_space => try writer.writeAll("std.builtin.AddressSpace"),
322 .float_mode => try writer.writeAll("std.builtin.FloatMode"),
323 .reduce_op => try writer.writeAll("std.builtin.ReduceOp"),
324 .call_modifier => try writer.writeAll("std.builtin.CallModifier"),
325 .prefetch_options => try writer.writeAll("std.builtin.PrefetchOptions"),
326 .export_options => try writer.writeAll("std.builtin.ExportOptions"),
327 .extern_options => try writer.writeAll("std.builtin.ExternOptions"),
328 .type_info => try writer.writeAll("std.builtin.Type"),
329
330 .generic_poison => unreachable,
331 },
332 .struct_type => {
333 const struct_type = ip.loadStructType(ty.toIntern());
334 if (struct_type.decl.unwrap()) |decl_index| {
335 const decl = mod.declPtr(decl_index);
336 try decl.renderFullyQualifiedName(mod, writer);
337 } else if (ip.loadStructType(ty.toIntern()).namespace.unwrap()) |namespace_index| {
338 const namespace = mod.namespacePtr(namespace_index);
339 try namespace.renderFullyQualifiedName(mod, .empty, writer);
340 } else {
341 try writer.writeAll("@TypeOf(.{})");
342 }
343 },
344 .anon_struct_type => |anon_struct| {
345 if (anon_struct.types.len == 0) {
346 return writer.writeAll("@TypeOf(.{})");
347 }
348 try writer.writeAll("struct{");
349 for (anon_struct.types.get(ip), anon_struct.values.get(ip), 0..) |field_ty, val, i| {
350 if (i != 0) try writer.writeAll(", ");
351 if (val != .none) {
352 try writer.writeAll("comptime ");
353 }
354 if (anon_struct.names.len != 0) {
355 try writer.print("{}: ", .{anon_struct.names.get(ip)[i].fmt(&mod.intern_pool)});
356 }
357
358 try print(Type.fromInterned(field_ty), writer, mod);
359
360 if (val != .none) {
361 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod, null)});
362 }
363 }
364 try writer.writeAll("}");
365 },
366
367 .union_type => {
368 const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
369 try decl.renderFullyQualifiedName(mod, writer);
370 },
371 .opaque_type => {
372 const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
373 try decl.renderFullyQualifiedName(mod, writer);
374 },
375 .enum_type => {
376 const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
377 try decl.renderFullyQualifiedName(mod, writer);
378 },
379 .func_type => |fn_info| {
380 if (fn_info.is_noinline) {
381 try writer.writeAll("noinline ");
382 }
383 try writer.writeAll("fn (");
384 const param_types = fn_info.param_types.get(&mod.intern_pool);
385 for (param_types, 0..) |param_ty, i| {
386 if (i != 0) try writer.writeAll(", ");
387 if (std.math.cast(u5, i)) |index| {
388 if (fn_info.paramIsComptime(index)) {
389 try writer.writeAll("comptime ");
390 }
391 if (fn_info.paramIsNoalias(index)) {
392 try writer.writeAll("noalias ");
393 }
394 }
395 if (param_ty == .generic_poison_type) {
396 try writer.writeAll("anytype");
397 } else {
398 try print(Type.fromInterned(param_ty), writer, mod);
399 }
400 }
401 if (fn_info.is_var_args) {
402 if (param_types.len != 0) {
403 try writer.writeAll(", ");
404 }
405 try writer.writeAll("...");
406 }
407 try writer.writeAll(") ");
408 if (fn_info.cc != .Unspecified) {
409 try writer.writeAll("callconv(.");
410 try writer.writeAll(@tagName(fn_info.cc));
411 try writer.writeAll(") ");
412 }
413 if (fn_info.return_type == .generic_poison_type) {
414 try writer.writeAll("anytype");
415 } else {
416 try print(Type.fromInterned(fn_info.return_type), writer, mod);
417 }
418 },
419 .anyframe_type => |child| {
420 if (child == .none) return writer.writeAll("anyframe");
421 try writer.writeAll("anyframe->");
422 return print(Type.fromInterned(child), writer, mod);
423 },
424
425 // values, not types
426 .undef,
427 .simple_value,
428 .variable,
429 .extern_func,
430 .func,
431 .int,
432 .err,
433 .error_union,
434 .enum_literal,
435 .enum_tag,
436 .empty_enum_value,
437 .float,
438 .ptr,
439 .slice,
440 .opt,
441 .aggregate,
442 .un,
443 // memoization, not types
444 .memoized_call,
445 => unreachable,
446 }
447}
448
449pub fn fromInterned(i: InternPool.Index) Type {
450 assert(i != .none);
451 return .{ .ip_index = i };
452}
453
454pub fn toIntern(ty: Type) InternPool.Index {
455 assert(ty.ip_index != .none);
456 return ty.ip_index;
457}
458
459pub fn toValue(self: Type) Value {
460 return Value.fromInterned(self.toIntern());
461}
462
463const RuntimeBitsError = SemaError || error{NeedLazy};
464
465/// true if and only if the type takes up space in memory at runtime.
466/// There are two reasons a type will return false:
467/// * the type is a comptime-only type. For example, the type `type` itself.
468/// - note, however, that a struct can have mixed fields and only the non-comptime-only
469/// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
470/// hasRuntimeBits()=true and abiSize()=4
471/// * the type has only one possible value, making its ABI size 0.
472/// - an enum with an explicit tag type has the ABI size of the integer tag type,
473/// making it one-possible-value only if the integer tag type has 0 bits.
474/// When `ignore_comptime_only` is true, then types that are comptime-only
475/// may return false positives.
476pub fn hasRuntimeBitsAdvanced(
477 ty: Type,
478 mod: *Module,
479 ignore_comptime_only: bool,
480 strat: ResolveStratLazy,
481) RuntimeBitsError!bool {
482 const ip = &mod.intern_pool;
483 return switch (ty.toIntern()) {
484 // False because it is a comptime-only type.
485 .empty_struct_type => false,
486 else => switch (ip.indexToKey(ty.toIntern())) {
487 .int_type => |int_type| int_type.bits != 0,
488 .ptr_type => {
489 // Pointers to zero-bit types still have a runtime address; however, pointers
490 // to comptime-only types do not, with the exception of function pointers.
491 if (ignore_comptime_only) return true;
492 return switch (strat) {
493 .sema => !try ty.comptimeOnlyAdvanced(mod, .sema),
494 .eager => !ty.comptimeOnly(mod),
495 .lazy => error.NeedLazy,
496 };
497 },
498 .anyframe_type => true,
499 .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and
500 try Type.fromInterned(array_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
501 .vector_type => |vector_type| return vector_type.len > 0 and
502 try Type.fromInterned(vector_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
503 .opt_type => |child| {
504 const child_ty = Type.fromInterned(child);
505 if (child_ty.isNoReturn(mod)) {
506 // Then the optional is comptime-known to be null.
507 return false;
508 }
509 if (ignore_comptime_only) return true;
510 return switch (strat) {
511 .sema => !try child_ty.comptimeOnlyAdvanced(mod, .sema),
512 .eager => !child_ty.comptimeOnly(mod),
513 .lazy => error.NeedLazy,
514 };
515 },
516 .error_union_type,
517 .error_set_type,
518 .inferred_error_set_type,
519 => true,
520
521 // These are function *bodies*, not pointers.
522 // They return false here because they are comptime-only types.
523 // Special exceptions have to be made when emitting functions due to
524 // this returning false.
525 .func_type => false,
526
527 .simple_type => |t| switch (t) {
528 .f16,
529 .f32,
530 .f64,
531 .f80,
532 .f128,
533 .usize,
534 .isize,
535 .c_char,
536 .c_short,
537 .c_ushort,
538 .c_int,
539 .c_uint,
540 .c_long,
541 .c_ulong,
542 .c_longlong,
543 .c_ulonglong,
544 .c_longdouble,
545 .bool,
546 .anyerror,
547 .adhoc_inferred_error_set,
548 .anyopaque,
549 .atomic_order,
550 .atomic_rmw_op,
551 .calling_convention,
552 .address_space,
553 .float_mode,
554 .reduce_op,
555 .call_modifier,
556 .prefetch_options,
557 .export_options,
558 .extern_options,
559 => true,
560
561 // These are false because they are comptime-only types.
562 .void,
563 .type,
564 .comptime_int,
565 .comptime_float,
566 .noreturn,
567 .null,
568 .undefined,
569 .enum_literal,
570 .type_info,
571 => false,
572
573 .generic_poison => unreachable,
574 },
575 .struct_type => {
576 const struct_type = ip.loadStructType(ty.toIntern());
577 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
578 // In this case, we guess that hasRuntimeBits() for this type is true,
579 // and then later if our guess was incorrect, we emit a compile error.
580 return true;
581 }
582 switch (strat) {
583 .sema => try ty.resolveFields(mod),
584 .eager => assert(struct_type.haveFieldTypes(ip)),
585 .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
586 }
587 for (0..struct_type.field_types.len) |i| {
588 if (struct_type.comptime_bits.getBit(ip, i)) continue;
589 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
590 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
591 return true;
592 } else {
593 return false;
594 }
595 },
596 .anon_struct_type => |tuple| {
597 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
598 if (val != .none) continue; // comptime field
599 if (try Type.fromInterned(field_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true;
600 }
601 return false;
602 },
603
604 .union_type => {
605 const union_type = ip.loadUnionType(ty.toIntern());
606 switch (union_type.flagsPtr(ip).runtime_tag) {
607 .none => {
608 if (union_type.flagsPtr(ip).status == .field_types_wip) {
609 // In this case, we guess that hasRuntimeBits() for this type is true,
610 // and then later if our guess was incorrect, we emit a compile error.
611 union_type.flagsPtr(ip).assumed_runtime_bits = true;
612 return true;
613 }
614 },
615 .safety, .tagged => {
616 const tag_ty = union_type.tagTypePtr(ip).*;
617 // tag_ty will be `none` if this union's tag type is not resolved yet,
618 // in which case we want control flow to continue down below.
619 if (tag_ty != .none and
620 try Type.fromInterned(tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
621 {
622 return true;
623 }
624 },
625 }
626 switch (strat) {
627 .sema => try ty.resolveFields(mod),
628 .eager => assert(union_type.flagsPtr(ip).status.haveFieldTypes()),
629 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())
630 return error.NeedLazy,
631 }
632 for (0..union_type.field_types.len) |field_index| {
633 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
634 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
635 return true;
636 } else {
637 return false;
638 }
639 },
640
641 .opaque_type => true,
642 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
643
644 // values, not types
645 .undef,
646 .simple_value,
647 .variable,
648 .extern_func,
649 .func,
650 .int,
651 .err,
652 .error_union,
653 .enum_literal,
654 .enum_tag,
655 .empty_enum_value,
656 .float,
657 .ptr,
658 .slice,
659 .opt,
660 .aggregate,
661 .un,
662 // memoization, not types
663 .memoized_call,
664 => unreachable,
665 },
666 };
667}
668
669/// true if and only if the type has a well-defined memory layout
670/// readFrom/writeToMemory are supported only for types with a well-
671/// defined memory layout
672pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool {
673 const ip = &mod.intern_pool;
674 return switch (ip.indexToKey(ty.toIntern())) {
675 .int_type,
676 .vector_type,
677 => true,
678
679 .error_union_type,
680 .error_set_type,
681 .inferred_error_set_type,
682 .anon_struct_type,
683 .opaque_type,
684 .anyframe_type,
685 // These are function bodies, not function pointers.
686 .func_type,
687 => false,
688
689 .array_type => |array_type| Type.fromInterned(array_type.child).hasWellDefinedLayout(mod),
690 .opt_type => ty.isPtrLikeOptional(mod),
691 .ptr_type => |ptr_type| ptr_type.flags.size != .Slice,
692
693 .simple_type => |t| switch (t) {
694 .f16,
695 .f32,
696 .f64,
697 .f80,
698 .f128,
699 .usize,
700 .isize,
701 .c_char,
702 .c_short,
703 .c_ushort,
704 .c_int,
705 .c_uint,
706 .c_long,
707 .c_ulong,
708 .c_longlong,
709 .c_ulonglong,
710 .c_longdouble,
711 .bool,
712 .void,
713 => true,
714
715 .anyerror,
716 .adhoc_inferred_error_set,
717 .anyopaque,
718 .atomic_order,
719 .atomic_rmw_op,
720 .calling_convention,
721 .address_space,
722 .float_mode,
723 .reduce_op,
724 .call_modifier,
725 .prefetch_options,
726 .export_options,
727 .extern_options,
728 .type,
729 .comptime_int,
730 .comptime_float,
731 .noreturn,
732 .null,
733 .undefined,
734 .enum_literal,
735 .type_info,
736 .generic_poison,
737 => false,
738 },
739 .struct_type => {
740 const struct_type = ip.loadStructType(ty.toIntern());
741 // Struct with no fields have a well-defined layout of no bits.
742 return struct_type.layout != .auto or struct_type.field_types.len == 0;
743 },
744 .union_type => {
745 const union_type = ip.loadUnionType(ty.toIntern());
746 return switch (union_type.flagsPtr(ip).runtime_tag) {
747 .none, .safety => union_type.flagsPtr(ip).layout != .auto,
748 .tagged => false,
749 };
750 },
751 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
752 .auto => false,
753 .explicit, .nonexhaustive => true,
754 },
755
756 // values, not types
757 .undef,
758 .simple_value,
759 .variable,
760 .extern_func,
761 .func,
762 .int,
763 .err,
764 .error_union,
765 .enum_literal,
766 .enum_tag,
767 .empty_enum_value,
768 .float,
769 .ptr,
770 .slice,
771 .opt,
772 .aggregate,
773 .un,
774 // memoization, not types
775 .memoized_call,
776 => unreachable,
777 };
778}
779
780pub fn hasRuntimeBits(ty: Type, mod: *Module) bool {
781 return hasRuntimeBitsAdvanced(ty, mod, false, .eager) catch unreachable;
782}
783
784pub fn hasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool {
785 return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable;
786}
787
788pub fn fnHasRuntimeBits(ty: Type, mod: *Module) bool {
789 return ty.fnHasRuntimeBitsAdvanced(mod, .normal) catch unreachable;
790}
791
792/// Determines whether a function type has runtime bits, i.e. whether a
793/// function with this type can exist at runtime.
794/// Asserts that `ty` is a function type.
795pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, strat: ResolveStrat) SemaError!bool {
796 const fn_info = mod.typeToFunc(ty).?;
797 if (fn_info.is_generic) return false;
798 if (fn_info.is_var_args) return true;
799 if (fn_info.cc == .Inline) return false;
800 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyAdvanced(mod, strat);
801}
802
803pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {
804 switch (ty.zigTypeTag(mod)) {
805 .Fn => return ty.fnHasRuntimeBits(mod),
806 else => return ty.hasRuntimeBits(mod),
807 }
808}
809
810/// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
811pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool {
812 return switch (ty.zigTypeTag(mod)) {
813 .Fn => true,
814 else => return ty.hasRuntimeBitsIgnoreComptime(mod),
815 };
816}
817
818pub fn isNoReturn(ty: Type, mod: *Module) bool {
819 return mod.intern_pool.isNoReturn(ty.toIntern());
820}
821
822/// Returns `none` if the pointer is naturally aligned and the element type is 0-bit.
823pub fn ptrAlignment(ty: Type, mod: *Module) Alignment {
824 return ptrAlignmentAdvanced(ty, mod, .normal) catch unreachable;
825}
826
827pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, strat: ResolveStrat) !Alignment {
828 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
829 .ptr_type => |ptr_type| {
830 if (ptr_type.flags.alignment != .none)
831 return ptr_type.flags.alignment;
832
833 if (strat == .sema) {
834 const res = try Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .sema);
835 return res.scalar;
836 }
837
838 return (Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
839 },
840 .opt_type => |child| Type.fromInterned(child).ptrAlignmentAdvanced(mod, strat),
841 else => unreachable,
842 };
843}
844
845pub fn ptrAddressSpace(ty: Type, mod: *const Module) std.builtin.AddressSpace {
846 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
847 .ptr_type => |ptr_type| ptr_type.flags.address_space,
848 .opt_type => |child| mod.intern_pool.indexToKey(child).ptr_type.flags.address_space,
849 else => unreachable,
850 };
851}
852
853/// Never returns `none`. Asserts that all necessary type resolution is already done.
854pub fn abiAlignment(ty: Type, mod: *Module) Alignment {
855 return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
856}
857
858/// May capture a reference to `ty`.
859/// Returned value has type `comptime_int`.
860pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
861 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
862 .val => |val| return val,
863 .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
864 }
865}
866
867pub const AbiAlignmentAdvanced = union(enum) {
868 scalar: Alignment,
869 val: Value,
870};
871
872pub const ResolveStratLazy = enum {
873 /// Return a `lazy_size` or `lazy_align` value if necessary.
874 /// This value can be resolved later using `Value.resolveLazy`.
875 lazy,
876 /// Return a scalar result, expecting all necessary type resolution to be completed.
877 /// Backends should typically use this, since they must not perform type resolution.
878 eager,
879 /// Return a scalar result, performing type resolution as necessary.
880 /// This should typically be used from semantic analysis.
881 sema,
882};
883
884/// The chosen strategy can be easily optimized away in release builds.
885/// However, in debug builds, it helps to avoid acceidentally resolving types in backends.
886pub const ResolveStrat = enum {
887 /// Assert that all necessary resolution is completed.
888 /// Backends should typically use this, since they must not perform type resolution.
889 normal,
890 /// Perform type resolution as necessary using `Zcu`.
891 /// This should typically be used from semantic analysis.
892 sema,
893
894 pub fn toLazy(strat: ResolveStrat) ResolveStratLazy {
895 return switch (strat) {
896 .normal => .eager,
897 .sema => .sema,
898 };
899 }
900};
901
902/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
903/// In this case there will be no error, guaranteed.
904/// If you pass `lazy` you may get back `scalar` or `val`.
905/// If `val` is returned, a reference to `ty` has been captured.
906/// If you pass `sema` you will get back `scalar` and resolve the type if
907/// necessary, possibly returning a CompileError.
908pub fn abiAlignmentAdvanced(
909 ty: Type,
910 mod: *Module,
911 strat: ResolveStratLazy,
912) SemaError!AbiAlignmentAdvanced {
913 const target = mod.getTarget();
914 const use_llvm = mod.comp.config.use_llvm;
915 const ip = &mod.intern_pool;
916
917 switch (ty.toIntern()) {
918 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"1" },
919 else => switch (ip.indexToKey(ty.toIntern())) {
920 .int_type => |int_type| {
921 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
922 return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) };
923 },
924 .ptr_type, .anyframe_type => {
925 return .{ .scalar = ptrAbiAlignment(target) };
926 },
927 .array_type => |array_type| {
928 return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
929 },
930 .vector_type => |vector_type| {
931 if (vector_type.len == 0) return .{ .scalar = .@"1" };
932 switch (mod.comp.getZigBackend()) {
933 else => {
934 const elem_bits: u32 = @intCast(try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, .sema));
935 if (elem_bits == 0) return .{ .scalar = .@"1" };
936 const bytes = ((elem_bits * vector_type.len) + 7) / 8;
937 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
938 return .{ .scalar = Alignment.fromByteUnits(alignment) };
939 },
940 .stage2_c => {
941 return Type.fromInterned(vector_type.child).abiAlignmentAdvanced(mod, strat);
942 },
943 .stage2_x86_64 => {
944 if (vector_type.child == .bool_type) {
945 if (vector_type.len > 256 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
946 if (vector_type.len > 128 and std.Target.x86.featureSetHas(target.cpu.features, .avx2)) return .{ .scalar = .@"32" };
947 if (vector_type.len > 64) return .{ .scalar = .@"16" };
948 const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
949 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
950 return .{ .scalar = Alignment.fromByteUnits(alignment) };
951 }
952 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
953 if (elem_bytes == 0) return .{ .scalar = .@"1" };
954 const bytes = elem_bytes * vector_type.len;
955 if (bytes > 32 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
956 if (bytes > 16 and std.Target.x86.featureSetHas(target.cpu.features, .avx)) return .{ .scalar = .@"32" };
957 return .{ .scalar = .@"16" };
958 },
959 }
960 },
961
962 .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),
963 .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, Type.fromInterned(info.payload_type)),
964
965 .error_set_type, .inferred_error_set_type => {
966 const bits = mod.errorSetBits();
967 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
968 return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
969 },
970
971 // represents machine code; not a pointer
972 .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
973
974 .simple_type => |t| switch (t) {
975 .bool,
976 .atomic_order,
977 .atomic_rmw_op,
978 .calling_convention,
979 .address_space,
980 .float_mode,
981 .reduce_op,
982 .call_modifier,
983 .prefetch_options,
984 .anyopaque,
985 => return .{ .scalar = .@"1" },
986
987 .usize,
988 .isize,
989 => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) },
990
991 .export_options,
992 .extern_options,
993 .type_info,
994 => return .{ .scalar = ptrAbiAlignment(target) },
995
996 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
997 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
998 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
999 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
1000 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
1001 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
1002 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
1003 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
1004 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
1005 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
1006
1007 .f16 => return .{ .scalar = .@"2" },
1008 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
1009 .f64 => switch (target.c_type_bit_size(.double)) {
1010 64 => return .{ .scalar = cTypeAlign(target, .double) },
1011 else => return .{ .scalar = .@"8" },
1012 },
1013 .f80 => switch (target.c_type_bit_size(.longdouble)) {
1014 80 => return .{ .scalar = cTypeAlign(target, .longdouble) },
1015 else => {
1016 const u80_ty: Type = .{ .ip_index = .u80_type };
1017 return .{ .scalar = abiAlignment(u80_ty, mod) };
1018 },
1019 },
1020 .f128 => switch (target.c_type_bit_size(.longdouble)) {
1021 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
1022 else => return .{ .scalar = .@"16" },
1023 },
1024
1025 .anyerror, .adhoc_inferred_error_set => {
1026 const bits = mod.errorSetBits();
1027 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
1028 return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
1029 },
1030
1031 .void,
1032 .type,
1033 .comptime_int,
1034 .comptime_float,
1035 .null,
1036 .undefined,
1037 .enum_literal,
1038 => return .{ .scalar = .@"1" },
1039
1040 .noreturn => unreachable,
1041 .generic_poison => unreachable,
1042 },
1043 .struct_type => {
1044 const struct_type = ip.loadStructType(ty.toIntern());
1045 if (struct_type.layout == .@"packed") {
1046 switch (strat) {
1047 .sema => try ty.resolveLayout(mod),
1048 .lazy => if (struct_type.backingIntType(ip).* == .none) return .{
1049 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1050 .ty = .comptime_int_type,
1051 .storage = .{ .lazy_align = ty.toIntern() },
1052 } }))),
1053 },
1054 .eager => {},
1055 }
1056 return .{ .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiAlignment(mod) };
1057 }
1058
1059 if (struct_type.flagsPtr(ip).alignment == .none) switch (strat) {
1060 .eager => unreachable, // struct alignment not resolved
1061 .sema => try ty.resolveStructAlignment(mod),
1062 .lazy => return .{ .val = Value.fromInterned(try mod.intern(.{ .int = .{
1063 .ty = .comptime_int_type,
1064 .storage = .{ .lazy_align = ty.toIntern() },
1065 } })) },
1066 };
1067
1068 return .{ .scalar = struct_type.flagsPtr(ip).alignment };
1069 },
1070 .anon_struct_type => |tuple| {
1071 var big_align: Alignment = .@"1";
1072 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
1073 if (val != .none) continue; // comptime field
1074 switch (try Type.fromInterned(field_ty).abiAlignmentAdvanced(mod, strat)) {
1075 .scalar => |field_align| big_align = big_align.max(field_align),
1076 .val => switch (strat) {
1077 .eager => unreachable, // field type alignment not resolved
1078 .sema => unreachable, // passed to abiAlignmentAdvanced above
1079 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1080 .ty = .comptime_int_type,
1081 .storage = .{ .lazy_align = ty.toIntern() },
1082 } }))) },
1083 },
1084 }
1085 }
1086 return .{ .scalar = big_align };
1087 },
1088 .union_type => {
1089 const union_type = ip.loadUnionType(ty.toIntern());
1090
1091 if (union_type.flagsPtr(ip).alignment == .none) switch (strat) {
1092 .eager => unreachable, // union layout not resolved
1093 .sema => try ty.resolveUnionAlignment(mod),
1094 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1095 .ty = .comptime_int_type,
1096 .storage = .{ .lazy_align = ty.toIntern() },
1097 } }))) },
1098 };
1099
1100 return .{ .scalar = union_type.flagsPtr(ip).alignment };
1101 },
1102 .opaque_type => return .{ .scalar = .@"1" },
1103 .enum_type => return .{
1104 .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(mod),
1105 },
1106
1107 // values, not types
1108 .undef,
1109 .simple_value,
1110 .variable,
1111 .extern_func,
1112 .func,
1113 .int,
1114 .err,
1115 .error_union,
1116 .enum_literal,
1117 .enum_tag,
1118 .empty_enum_value,
1119 .float,
1120 .ptr,
1121 .slice,
1122 .opt,
1123 .aggregate,
1124 .un,
1125 // memoization, not types
1126 .memoized_call,
1127 => unreachable,
1128 },
1129 }
1130}
1131
1132fn abiAlignmentAdvancedErrorUnion(
1133 ty: Type,
1134 mod: *Module,
1135 strat: ResolveStratLazy,
1136 payload_ty: Type,
1137) SemaError!AbiAlignmentAdvanced {
1138 // This code needs to be kept in sync with the equivalent switch prong
1139 // in abiSizeAdvanced.
1140 const code_align = abiAlignment(Type.anyerror, mod);
1141 switch (strat) {
1142 .eager, .sema => {
1143 if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1144 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1145 .ty = .comptime_int_type,
1146 .storage = .{ .lazy_align = ty.toIntern() },
1147 } }))) },
1148 else => |e| return e,
1149 })) {
1150 return .{ .scalar = code_align };
1151 }
1152 return .{ .scalar = code_align.max(
1153 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,
1154 ) };
1155 },
1156 .lazy => {
1157 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {
1158 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
1159 .val => {},
1160 }
1161 return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1162 .ty = .comptime_int_type,
1163 .storage = .{ .lazy_align = ty.toIntern() },
1164 } }))) };
1165 },
1166 }
1167}
1168
1169fn abiAlignmentAdvancedOptional(
1170 ty: Type,
1171 mod: *Module,
1172 strat: ResolveStratLazy,
1173) SemaError!AbiAlignmentAdvanced {
1174 const target = mod.getTarget();
1175 const child_type = ty.optionalChild(mod);
1176
1177 switch (child_type.zigTypeTag(mod)) {
1178 .Pointer => return .{ .scalar = ptrAbiAlignment(target) },
1179 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1180 .NoReturn => return .{ .scalar = .@"1" },
1181 else => {},
1182 }
1183
1184 switch (strat) {
1185 .eager, .sema => {
1186 if (!(child_type.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1187 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1188 .ty = .comptime_int_type,
1189 .storage = .{ .lazy_align = ty.toIntern() },
1190 } }))) },
1191 else => |e| return e,
1192 })) {
1193 return .{ .scalar = .@"1" };
1194 }
1195 return child_type.abiAlignmentAdvanced(mod, strat);
1196 },
1197 .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) {
1198 .scalar => |x| return .{ .scalar = x.max(.@"1") },
1199 .val => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1200 .ty = .comptime_int_type,
1201 .storage = .{ .lazy_align = ty.toIntern() },
1202 } }))) },
1203 },
1204 }
1205}
1206
1207/// May capture a reference to `ty`.
1208pub fn lazyAbiSize(ty: Type, mod: *Module) !Value {
1209 switch (try ty.abiSizeAdvanced(mod, .lazy)) {
1210 .val => |val| return val,
1211 .scalar => |x| return mod.intValue(Type.comptime_int, x),
1212 }
1213}
1214
1215/// Asserts the type has the ABI size already resolved.
1216/// Types that return false for hasRuntimeBits() return 0.
1217pub fn abiSize(ty: Type, mod: *Module) u64 {
1218 return (abiSizeAdvanced(ty, mod, .eager) catch unreachable).scalar;
1219}
1220
1221const AbiSizeAdvanced = union(enum) {
1222 scalar: u64,
1223 val: Value,
1224};
1225
1226/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
1227/// In this case there will be no error, guaranteed.
1228/// If you pass `lazy` you may get back `scalar` or `val`.
1229/// If `val` is returned, a reference to `ty` has been captured.
1230/// If you pass `sema` you will get back `scalar` and resolve the type if
1231/// necessary, possibly returning a CompileError.
1232pub fn abiSizeAdvanced(
1233 ty: Type,
1234 mod: *Module,
1235 strat: ResolveStratLazy,
1236) SemaError!AbiSizeAdvanced {
1237 const target = mod.getTarget();
1238 const use_llvm = mod.comp.config.use_llvm;
1239 const ip = &mod.intern_pool;
1240
1241 switch (ty.toIntern()) {
1242 .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 },
1243
1244 else => switch (ip.indexToKey(ty.toIntern())) {
1245 .int_type => |int_type| {
1246 if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1247 return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target, use_llvm) };
1248 },
1249 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1250 .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
1251 else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1252 },
1253 .anyframe_type => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1254
1255 .array_type => |array_type| {
1256 const len = array_type.lenIncludingSentinel();
1257 if (len == 0) return .{ .scalar = 0 };
1258 switch (try Type.fromInterned(array_type.child).abiSizeAdvanced(mod, strat)) {
1259 .scalar => |elem_size| return .{ .scalar = len * elem_size },
1260 .val => switch (strat) {
1261 .sema, .eager => unreachable,
1262 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1263 .ty = .comptime_int_type,
1264 .storage = .{ .lazy_size = ty.toIntern() },
1265 } }))) },
1266 },
1267 }
1268 },
1269 .vector_type => |vector_type| {
1270 const sub_strat: ResolveStrat = switch (strat) {
1271 .sema => .sema,
1272 .eager => .normal,
1273 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1274 .ty = .comptime_int_type,
1275 .storage = .{ .lazy_size = ty.toIntern() },
1276 } }))) },
1277 };
1278 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {
1279 .scalar => |x| x,
1280 .val => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1281 .ty = .comptime_int_type,
1282 .storage = .{ .lazy_size = ty.toIntern() },
1283 } }))) },
1284 };
1285 const total_bytes = switch (mod.comp.getZigBackend()) {
1286 else => total_bytes: {
1287 const elem_bits = try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, sub_strat);
1288 const total_bits = elem_bits * vector_type.len;
1289 break :total_bytes (total_bits + 7) / 8;
1290 },
1291 .stage2_c => total_bytes: {
1292 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1293 break :total_bytes elem_bytes * vector_type.len;
1294 },
1295 .stage2_x86_64 => total_bytes: {
1296 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
1297 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1298 break :total_bytes elem_bytes * vector_type.len;
1299 },
1300 };
1301 return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) };
1302 },
1303
1304 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
1305
1306 .error_set_type, .inferred_error_set_type => {
1307 const bits = mod.errorSetBits();
1308 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1309 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
1310 },
1311
1312 .error_union_type => |error_union_type| {
1313 const payload_ty = Type.fromInterned(error_union_type.payload_type);
1314 // This code needs to be kept in sync with the equivalent switch prong
1315 // in abiAlignmentAdvanced.
1316 const code_size = abiSize(Type.anyerror, mod);
1317 if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1318 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1319 .ty = .comptime_int_type,
1320 .storage = .{ .lazy_size = ty.toIntern() },
1321 } }))) },
1322 else => |e| return e,
1323 })) {
1324 // Same as anyerror.
1325 return AbiSizeAdvanced{ .scalar = code_size };
1326 }
1327 const code_align = abiAlignment(Type.anyerror, mod);
1328 const payload_align = abiAlignment(payload_ty, mod);
1329 const payload_size = switch (try payload_ty.abiSizeAdvanced(mod, strat)) {
1330 .scalar => |elem_size| elem_size,
1331 .val => switch (strat) {
1332 .sema => unreachable,
1333 .eager => unreachable,
1334 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1335 .ty = .comptime_int_type,
1336 .storage = .{ .lazy_size = ty.toIntern() },
1337 } }))) },
1338 },
1339 };
1340
1341 var size: u64 = 0;
1342 if (code_align.compare(.gt, payload_align)) {
1343 size += code_size;
1344 size = payload_align.forward(size);
1345 size += payload_size;
1346 size = code_align.forward(size);
1347 } else {
1348 size += payload_size;
1349 size = code_align.forward(size);
1350 size += code_size;
1351 size = payload_align.forward(size);
1352 }
1353 return AbiSizeAdvanced{ .scalar = size };
1354 },
1355 .func_type => unreachable, // represents machine code; not a pointer
1356 .simple_type => |t| switch (t) {
1357 .bool,
1358 .atomic_order,
1359 .atomic_rmw_op,
1360 .calling_convention,
1361 .address_space,
1362 .float_mode,
1363 .reduce_op,
1364 .call_modifier,
1365 => return AbiSizeAdvanced{ .scalar = 1 },
1366
1367 .f16 => return AbiSizeAdvanced{ .scalar = 2 },
1368 .f32 => return AbiSizeAdvanced{ .scalar = 4 },
1369 .f64 => return AbiSizeAdvanced{ .scalar = 8 },
1370 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
1371 .f80 => switch (target.c_type_bit_size(.longdouble)) {
1372 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) },
1373 else => {
1374 const u80_ty: Type = .{ .ip_index = .u80_type };
1375 return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, mod) };
1376 },
1377 },
1378
1379 .usize,
1380 .isize,
1381 => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1382
1383 .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) },
1384 .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) },
1385 .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) },
1386 .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) },
1387 .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) },
1388 .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) },
1389 .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) },
1390 .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) },
1391 .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) },
1392 .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) },
1393
1394 .anyopaque,
1395 .void,
1396 .type,
1397 .comptime_int,
1398 .comptime_float,
1399 .null,
1400 .undefined,
1401 .enum_literal,
1402 => return AbiSizeAdvanced{ .scalar = 0 },
1403
1404 .anyerror, .adhoc_inferred_error_set => {
1405 const bits = mod.errorSetBits();
1406 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1407 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
1408 },
1409
1410 .prefetch_options => unreachable, // missing call to resolveTypeFields
1411 .export_options => unreachable, // missing call to resolveTypeFields
1412 .extern_options => unreachable, // missing call to resolveTypeFields
1413
1414 .type_info => unreachable,
1415 .noreturn => unreachable,
1416 .generic_poison => unreachable,
1417 },
1418 .struct_type => {
1419 const struct_type = ip.loadStructType(ty.toIntern());
1420 switch (strat) {
1421 .sema => try ty.resolveLayout(mod),
1422 .lazy => switch (struct_type.layout) {
1423 .@"packed" => {
1424 if (struct_type.backingIntType(ip).* == .none) return .{
1425 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1426 .ty = .comptime_int_type,
1427 .storage = .{ .lazy_size = ty.toIntern() },
1428 } }))),
1429 };
1430 },
1431 .auto, .@"extern" => {
1432 if (!struct_type.haveLayout(ip)) return .{
1433 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1434 .ty = .comptime_int_type,
1435 .storage = .{ .lazy_size = ty.toIntern() },
1436 } }))),
1437 };
1438 },
1439 },
1440 .eager => {},
1441 }
1442 switch (struct_type.layout) {
1443 .@"packed" => return .{
1444 .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiSize(mod),
1445 },
1446 .auto, .@"extern" => {
1447 assert(struct_type.haveLayout(ip));
1448 return .{ .scalar = struct_type.size(ip).* };
1449 },
1450 }
1451 },
1452 .anon_struct_type => |tuple| {
1453 switch (strat) {
1454 .sema => try ty.resolveLayout(mod),
1455 .lazy, .eager => {},
1456 }
1457 const field_count = tuple.types.len;
1458 if (field_count == 0) {
1459 return AbiSizeAdvanced{ .scalar = 0 };
1460 }
1461 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
1462 },
1463
1464 .union_type => {
1465 const union_type = ip.loadUnionType(ty.toIntern());
1466 switch (strat) {
1467 .sema => try ty.resolveLayout(mod),
1468 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{
1469 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1470 .ty = .comptime_int_type,
1471 .storage = .{ .lazy_size = ty.toIntern() },
1472 } }))),
1473 },
1474 .eager => {},
1475 }
1476
1477 assert(union_type.haveLayout(ip));
1478 return .{ .scalar = union_type.size(ip).* };
1479 },
1480 .opaque_type => unreachable, // no size available
1481 .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(mod) },
1482
1483 // values, not types
1484 .undef,
1485 .simple_value,
1486 .variable,
1487 .extern_func,
1488 .func,
1489 .int,
1490 .err,
1491 .error_union,
1492 .enum_literal,
1493 .enum_tag,
1494 .empty_enum_value,
1495 .float,
1496 .ptr,
1497 .slice,
1498 .opt,
1499 .aggregate,
1500 .un,
1501 // memoization, not types
1502 .memoized_call,
1503 => unreachable,
1504 },
1505 }
1506}
1507
1508fn abiSizeAdvancedOptional(
1509 ty: Type,
1510 mod: *Module,
1511 strat: ResolveStratLazy,
1512) SemaError!AbiSizeAdvanced {
1513 const child_ty = ty.optionalChild(mod);
1514
1515 if (child_ty.isNoReturn(mod)) {
1516 return AbiSizeAdvanced{ .scalar = 0 };
1517 }
1518
1519 if (!(child_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1520 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1521 .ty = .comptime_int_type,
1522 .storage = .{ .lazy_size = ty.toIntern() },
1523 } }))) },
1524 else => |e| return e,
1525 })) return AbiSizeAdvanced{ .scalar = 1 };
1526
1527 if (ty.optionalReprIsPayload(mod)) {
1528 return abiSizeAdvanced(child_ty, mod, strat);
1529 }
1530
1531 const payload_size = switch (try child_ty.abiSizeAdvanced(mod, strat)) {
1532 .scalar => |elem_size| elem_size,
1533 .val => switch (strat) {
1534 .sema => unreachable,
1535 .eager => unreachable,
1536 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1537 .ty = .comptime_int_type,
1538 .storage = .{ .lazy_size = ty.toIntern() },
1539 } }))) },
1540 },
1541 };
1542
1543 // Optional types are represented as a struct with the child type as the first
1544 // field and a boolean as the second. Since the child type's abi alignment is
1545 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1546 // to the child type's ABI alignment.
1547 return AbiSizeAdvanced{
1548 .scalar = (child_ty.abiAlignment(mod).toByteUnits() orelse 0) + payload_size,
1549 };
1550}
1551
1552pub fn ptrAbiAlignment(target: Target) Alignment {
1553 return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
1554}
1555
1556pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 {
1557 return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
1558}
1559
1560pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
1561 return switch (target.cpu.arch) {
1562 .x86 => switch (bits) {
1563 0 => .none,
1564 1...8 => .@"1",
1565 9...16 => .@"2",
1566 17...64 => .@"4",
1567 else => .@"16",
1568 },
1569 .x86_64 => switch (bits) {
1570 0 => .none,
1571 1...8 => .@"1",
1572 9...16 => .@"2",
1573 17...32 => .@"4",
1574 33...64 => .@"8",
1575 else => switch (target_util.zigBackend(target, use_llvm)) {
1576 .stage2_x86_64 => .@"8",
1577 else => .@"16",
1578 },
1579 },
1580 else => return Alignment.fromByteUnits(@min(
1581 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
1582 maxIntAlignment(target, use_llvm),
1583 )),
1584 };
1585}
1586
1587pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
1588 return switch (target.cpu.arch) {
1589 .avr => 1,
1590 .msp430 => 2,
1591 .xcore => 4,
1592
1593 .arm,
1594 .armeb,
1595 .thumb,
1596 .thumbeb,
1597 .hexagon,
1598 .mips,
1599 .mipsel,
1600 .powerpc,
1601 .powerpcle,
1602 .r600,
1603 .amdgcn,
1604 .riscv32,
1605 .sparc,
1606 .sparcel,
1607 .s390x,
1608 .lanai,
1609 .wasm32,
1610 .wasm64,
1611 => 8,
1612
1613 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1614 // is a relevant number in three cases:
1615 // 1. Different machine code instruction when loading into SIMD register.
1616 // 2. The C ABI wants 16 for extern structs.
1617 // 3. 16-byte cmpxchg needs 16-byte alignment.
1618 // Same logic for powerpc64, mips64, sparc64.
1619 .powerpc64,
1620 .powerpc64le,
1621 .mips64,
1622 .mips64el,
1623 .sparc64,
1624 => switch (target.ofmt) {
1625 .c => 16,
1626 else => 8,
1627 },
1628
1629 .x86_64 => switch (target_util.zigBackend(target, use_llvm)) {
1630 .stage2_x86_64 => 8,
1631 else => 16,
1632 },
1633
1634 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
1635 .x86,
1636 .aarch64,
1637 .aarch64_be,
1638 .aarch64_32,
1639 .riscv64,
1640 .bpfel,
1641 .bpfeb,
1642 .nvptx,
1643 .nvptx64,
1644 => 16,
1645
1646 // Below this comment are unverified but based on the fact that C requires
1647 // int128_t to be 16 bytes aligned, it's a safe default.
1648 .spu_2,
1649 .csky,
1650 .arc,
1651 .m68k,
1652 .tce,
1653 .tcele,
1654 .le32,
1655 .amdil,
1656 .hsail,
1657 .spir,
1658 .kalimba,
1659 .renderscript32,
1660 .spirv,
1661 .spirv32,
1662 .shave,
1663 .le64,
1664 .amdil64,
1665 .hsail64,
1666 .spir64,
1667 .renderscript64,
1668 .ve,
1669 .spirv64,
1670 .dxil,
1671 .loongarch32,
1672 .loongarch64,
1673 .xtensa,
1674 => 16,
1675 };
1676}
1677
1678pub fn bitSize(ty: Type, mod: *Module) u64 {
1679 return bitSizeAdvanced(ty, mod, .normal) catch unreachable;
1680}
1681
1682pub fn bitSizeAdvanced(
1683 ty: Type,
1684 mod: *Module,
1685 strat: ResolveStrat,
1686) SemaError!u64 {
1687 const target = mod.getTarget();
1688 const ip = &mod.intern_pool;
1689
1690 const strat_lazy: ResolveStratLazy = strat.toLazy();
1691
1692 switch (ip.indexToKey(ty.toIntern())) {
1693 .int_type => |int_type| return int_type.bits,
1694 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1695 .Slice => return target.ptrBitWidth() * 2,
1696 else => return target.ptrBitWidth(),
1697 },
1698 .anyframe_type => return target.ptrBitWidth(),
1699
1700 .array_type => |array_type| {
1701 const len = array_type.lenIncludingSentinel();
1702 if (len == 0) return 0;
1703 const elem_ty = Type.fromInterned(array_type.child);
1704 const elem_size = @max(
1705 (try elem_ty.abiAlignmentAdvanced(mod, strat_lazy)).scalar.toByteUnits() orelse 0,
1706 (try elem_ty.abiSizeAdvanced(mod, strat_lazy)).scalar,
1707 );
1708 if (elem_size == 0) return 0;
1709 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, strat);
1710 return (len - 1) * 8 * elem_size + elem_bit_size;
1711 },
1712 .vector_type => |vector_type| {
1713 const child_ty = Type.fromInterned(vector_type.child);
1714 const elem_bit_size = try bitSizeAdvanced(child_ty, mod, strat);
1715 return elem_bit_size * vector_type.len;
1716 },
1717 .opt_type => {
1718 // Optionals and error unions are not packed so their bitsize
1719 // includes padding bits.
1720 return (try abiSizeAdvanced(ty, mod, strat_lazy)).scalar * 8;
1721 },
1722
1723 .error_set_type, .inferred_error_set_type => return mod.errorSetBits(),
1724
1725 .error_union_type => {
1726 // Optionals and error unions are not packed so their bitsize
1727 // includes padding bits.
1728 return (try abiSizeAdvanced(ty, mod, strat_lazy)).scalar * 8;
1729 },
1730 .func_type => unreachable, // represents machine code; not a pointer
1731 .simple_type => |t| switch (t) {
1732 .f16 => return 16,
1733 .f32 => return 32,
1734 .f64 => return 64,
1735 .f80 => return 80,
1736 .f128 => return 128,
1737
1738 .usize,
1739 .isize,
1740 => return target.ptrBitWidth(),
1741
1742 .c_char => return target.c_type_bit_size(.char),
1743 .c_short => return target.c_type_bit_size(.short),
1744 .c_ushort => return target.c_type_bit_size(.ushort),
1745 .c_int => return target.c_type_bit_size(.int),
1746 .c_uint => return target.c_type_bit_size(.uint),
1747 .c_long => return target.c_type_bit_size(.long),
1748 .c_ulong => return target.c_type_bit_size(.ulong),
1749 .c_longlong => return target.c_type_bit_size(.longlong),
1750 .c_ulonglong => return target.c_type_bit_size(.ulonglong),
1751 .c_longdouble => return target.c_type_bit_size(.longdouble),
1752
1753 .bool => return 1,
1754 .void => return 0,
1755
1756 .anyerror,
1757 .adhoc_inferred_error_set,
1758 => return mod.errorSetBits(),
1759
1760 .anyopaque => unreachable,
1761 .type => unreachable,
1762 .comptime_int => unreachable,
1763 .comptime_float => unreachable,
1764 .noreturn => unreachable,
1765 .null => unreachable,
1766 .undefined => unreachable,
1767 .enum_literal => unreachable,
1768 .generic_poison => unreachable,
1769
1770 .atomic_order => unreachable,
1771 .atomic_rmw_op => unreachable,
1772 .calling_convention => unreachable,
1773 .address_space => unreachable,
1774 .float_mode => unreachable,
1775 .reduce_op => unreachable,
1776 .call_modifier => unreachable,
1777 .prefetch_options => unreachable,
1778 .export_options => unreachable,
1779 .extern_options => unreachable,
1780 .type_info => unreachable,
1781 },
1782 .struct_type => {
1783 const struct_type = ip.loadStructType(ty.toIntern());
1784 const is_packed = struct_type.layout == .@"packed";
1785 if (strat == .sema) {
1786 try ty.resolveFields(mod);
1787 if (is_packed) try ty.resolveLayout(mod);
1788 }
1789 if (is_packed) {
1790 return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, strat);
1791 }
1792 return (try ty.abiSizeAdvanced(mod, strat_lazy)).scalar * 8;
1793 },
1794
1795 .anon_struct_type => {
1796 if (strat == .sema) try ty.resolveFields(mod);
1797 return (try ty.abiSizeAdvanced(mod, strat_lazy)).scalar * 8;
1798 },
1799
1800 .union_type => {
1801 const union_type = ip.loadUnionType(ty.toIntern());
1802 const is_packed = ty.containerLayout(mod) == .@"packed";
1803 if (strat == .sema) {
1804 try ty.resolveFields(mod);
1805 if (is_packed) try ty.resolveLayout(mod);
1806 }
1807 if (!is_packed) {
1808 return (try ty.abiSizeAdvanced(mod, strat_lazy)).scalar * 8;
1809 }
1810 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1811
1812 var size: u64 = 0;
1813 for (0..union_type.field_types.len) |field_index| {
1814 const field_ty = union_type.field_types.get(ip)[field_index];
1815 size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, strat));
1816 }
1817
1818 return size;
1819 },
1820 .opaque_type => unreachable,
1821 .enum_type => return bitSizeAdvanced(Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), mod, strat),
1822
1823 // values, not types
1824 .undef,
1825 .simple_value,
1826 .variable,
1827 .extern_func,
1828 .func,
1829 .int,
1830 .err,
1831 .error_union,
1832 .enum_literal,
1833 .enum_tag,
1834 .empty_enum_value,
1835 .float,
1836 .ptr,
1837 .slice,
1838 .opt,
1839 .aggregate,
1840 .un,
1841 // memoization, not types
1842 .memoized_call,
1843 => unreachable,
1844 }
1845}
1846
1847/// Returns true if the type's layout is already resolved and it is safe
1848/// to use `abiSize`, `abiAlignment` and `bitSize` on it.
1849pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
1850 const ip = &mod.intern_pool;
1851 return switch (ip.indexToKey(ty.toIntern())) {
1852 .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
1853 .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
1854 .array_type => |array_type| {
1855 if (array_type.lenIncludingSentinel() == 0) return true;
1856 return Type.fromInterned(array_type.child).layoutIsResolved(mod);
1857 },
1858 .opt_type => |child| Type.fromInterned(child).layoutIsResolved(mod),
1859 .error_union_type => |k| Type.fromInterned(k.payload_type).layoutIsResolved(mod),
1860 else => true,
1861 };
1862}
1863
1864pub fn isSinglePointer(ty: Type, mod: *const Module) bool {
1865 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1866 .ptr_type => |ptr_info| ptr_info.flags.size == .One,
1867 else => false,
1868 };
1869}
1870
1871/// Asserts `ty` is a pointer.
1872pub fn ptrSize(ty: Type, mod: *const Module) std.builtin.Type.Pointer.Size {
1873 return ptrSizeOrNull(ty, mod).?;
1874}
1875
1876/// Returns `null` if `ty` is not a pointer.
1877pub fn ptrSizeOrNull(ty: Type, mod: *const Module) ?std.builtin.Type.Pointer.Size {
1878 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1879 .ptr_type => |ptr_info| ptr_info.flags.size,
1880 else => null,
1881 };
1882}
1883
1884pub fn isSlice(ty: Type, mod: *const Module) bool {
1885 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1886 .ptr_type => |ptr_type| ptr_type.flags.size == .Slice,
1887 else => false,
1888 };
1889}
1890
1891pub fn slicePtrFieldType(ty: Type, mod: *const Module) Type {
1892 return Type.fromInterned(mod.intern_pool.slicePtrType(ty.toIntern()));
1893}
1894
1895pub fn isConstPtr(ty: Type, mod: *const Module) bool {
1896 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1897 .ptr_type => |ptr_type| ptr_type.flags.is_const,
1898 else => false,
1899 };
1900}
1901
1902pub fn isVolatilePtr(ty: Type, mod: *const Module) bool {
1903 return isVolatilePtrIp(ty, &mod.intern_pool);
1904}
1905
1906pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool {
1907 return switch (ip.indexToKey(ty.toIntern())) {
1908 .ptr_type => |ptr_type| ptr_type.flags.is_volatile,
1909 else => false,
1910 };
1911}
1912
1913pub fn isAllowzeroPtr(ty: Type, mod: *const Module) bool {
1914 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1915 .ptr_type => |ptr_type| ptr_type.flags.is_allowzero,
1916 .opt_type => true,
1917 else => false,
1918 };
1919}
1920
1921pub fn isCPtr(ty: Type, mod: *const Module) bool {
1922 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1923 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1924 else => false,
1925 };
1926}
1927
1928pub fn isPtrAtRuntime(ty: Type, mod: *const Module) bool {
1929 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1930 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1931 .Slice => false,
1932 .One, .Many, .C => true,
1933 },
1934 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
1935 .ptr_type => |p| switch (p.flags.size) {
1936 .Slice, .C => false,
1937 .Many, .One => !p.flags.is_allowzero,
1938 },
1939 else => false,
1940 },
1941 else => false,
1942 };
1943}
1944
1945/// For pointer-like optionals, returns true, otherwise returns the allowzero property
1946/// of pointers.
1947pub fn ptrAllowsZero(ty: Type, mod: *const Module) bool {
1948 if (ty.isPtrLikeOptional(mod)) {
1949 return true;
1950 }
1951 return ty.ptrInfo(mod).flags.is_allowzero;
1952}
1953
1954/// See also `isPtrLikeOptional`.
1955pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool {
1956 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1957 .opt_type => |child_type| child_type == .anyerror_type or switch (mod.intern_pool.indexToKey(child_type)) {
1958 .ptr_type => |ptr_type| ptr_type.flags.size != .C and !ptr_type.flags.is_allowzero,
1959 .error_set_type, .inferred_error_set_type => true,
1960 else => false,
1961 },
1962 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1963 else => false,
1964 };
1965}
1966
1967/// Returns true if the type is optional and would be lowered to a single pointer
1968/// address value, using 0 for null. Note that this returns true for C pointers.
1969/// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`.
1970pub fn isPtrLikeOptional(ty: Type, mod: *const Module) bool {
1971 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1972 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1973 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
1974 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1975 .Slice, .C => false,
1976 .Many, .One => !ptr_type.flags.is_allowzero,
1977 },
1978 else => false,
1979 },
1980 else => false,
1981 };
1982}
1983
1984/// For *[N]T, returns [N]T.
1985/// For *T, returns T.
1986/// For [*]T, returns T.
1987pub fn childType(ty: Type, mod: *const Module) Type {
1988 return childTypeIp(ty, &mod.intern_pool);
1989}
1990
1991pub fn childTypeIp(ty: Type, ip: *const InternPool) Type {
1992 return Type.fromInterned(ip.childType(ty.toIntern()));
1993}
1994
1995/// For *[N]T, returns T.
1996/// For ?*T, returns T.
1997/// For ?*[N]T, returns T.
1998/// For ?[*]T, returns T.
1999/// For *T, returns T.
2000/// For [*]T, returns T.
2001/// For [N]T, returns T.
2002/// For []T, returns T.
2003/// For anyframe->T, returns T.
2004pub fn elemType2(ty: Type, mod: *const Module) Type {
2005 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2006 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
2007 .One => Type.fromInterned(ptr_type.child).shallowElemType(mod),
2008 .Many, .C, .Slice => Type.fromInterned(ptr_type.child),
2009 },
2010 .anyframe_type => |child| {
2011 assert(child != .none);
2012 return Type.fromInterned(child);
2013 },
2014 .vector_type => |vector_type| Type.fromInterned(vector_type.child),
2015 .array_type => |array_type| Type.fromInterned(array_type.child),
2016 .opt_type => |child| Type.fromInterned(mod.intern_pool.childType(child)),
2017 else => unreachable,
2018 };
2019}
2020
2021fn shallowElemType(child_ty: Type, mod: *const Module) Type {
2022 return switch (child_ty.zigTypeTag(mod)) {
2023 .Array, .Vector => child_ty.childType(mod),
2024 else => child_ty,
2025 };
2026}
2027
2028/// For vectors, returns the element type. Otherwise returns self.
2029pub fn scalarType(ty: Type, mod: *Module) Type {
2030 return switch (ty.zigTypeTag(mod)) {
2031 .Vector => ty.childType(mod),
2032 else => ty,
2033 };
2034}
2035
2036/// Asserts that the type is an optional.
2037/// Note that for C pointers this returns the type unmodified.
2038pub fn optionalChild(ty: Type, mod: *const Module) Type {
2039 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2040 .opt_type => |child| Type.fromInterned(child),
2041 .ptr_type => |ptr_type| b: {
2042 assert(ptr_type.flags.size == .C);
2043 break :b ty;
2044 },
2045 else => unreachable,
2046 };
2047}
2048
2049/// Returns the tag type of a union, if the type is a union and it has a tag type.
2050/// Otherwise, returns `null`.
2051pub fn unionTagType(ty: Type, mod: *Module) ?Type {
2052 const ip = &mod.intern_pool;
2053 switch (ip.indexToKey(ty.toIntern())) {
2054 .union_type => {},
2055 else => return null,
2056 }
2057 const union_type = ip.loadUnionType(ty.toIntern());
2058 switch (union_type.flagsPtr(ip).runtime_tag) {
2059 .tagged => {
2060 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
2061 return Type.fromInterned(union_type.enum_tag_ty);
2062 },
2063 else => return null,
2064 }
2065}
2066
2067/// Same as `unionTagType` but includes safety tag.
2068/// Codegen should use this version.
2069pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
2070 const ip = &mod.intern_pool;
2071 return switch (ip.indexToKey(ty.toIntern())) {
2072 .union_type => {
2073 const union_type = ip.loadUnionType(ty.toIntern());
2074 if (!union_type.hasTag(ip)) return null;
2075 assert(union_type.haveFieldTypes(ip));
2076 return Type.fromInterned(union_type.enum_tag_ty);
2077 },
2078 else => null,
2079 };
2080}
2081
2082/// Asserts the type is a union; returns the tag type, even if the tag will
2083/// not be stored at runtime.
2084pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {
2085 const union_obj = mod.typeToUnion(ty).?;
2086 return Type.fromInterned(union_obj.enum_tag_ty);
2087}
2088
2089pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) ?Type {
2090 const ip = &mod.intern_pool;
2091 const union_obj = mod.typeToUnion(ty).?;
2092 const union_fields = union_obj.field_types.get(ip);
2093 const index = mod.unionTagFieldIndex(union_obj, enum_tag) orelse return null;
2094 return Type.fromInterned(union_fields[index]);
2095}
2096
2097pub fn unionFieldTypeByIndex(ty: Type, index: usize, mod: *Module) Type {
2098 const ip = &mod.intern_pool;
2099 const union_obj = mod.typeToUnion(ty).?;
2100 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
2101}
2102
2103pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
2104 const union_obj = mod.typeToUnion(ty).?;
2105 return mod.unionTagFieldIndex(union_obj, enum_tag);
2106}
2107
2108pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
2109 const ip = &mod.intern_pool;
2110 const union_obj = mod.typeToUnion(ty).?;
2111 for (union_obj.field_types.get(ip)) |field_ty| {
2112 if (Type.fromInterned(field_ty).hasRuntimeBits(mod)) return false;
2113 }
2114 return true;
2115}
2116
2117/// Returns the type used for backing storage of this union during comptime operations.
2118/// Asserts the type is either an extern or packed union.
2119pub fn unionBackingType(ty: Type, mod: *Module) !Type {
2120 return switch (ty.containerLayout(mod)) {
2121 .@"extern" => try mod.arrayType(.{ .len = ty.abiSize(mod), .child = .u8_type }),
2122 .@"packed" => try mod.intType(.unsigned, @intCast(ty.bitSize(mod))),
2123 .auto => unreachable,
2124 };
2125}
2126
2127pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {
2128 const ip = &mod.intern_pool;
2129 const union_obj = ip.loadUnionType(ty.toIntern());
2130 return mod.getUnionLayout(union_obj);
2131}
2132
2133pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
2134 const ip = &mod.intern_pool;
2135 return switch (ip.indexToKey(ty.toIntern())) {
2136 .struct_type => ip.loadStructType(ty.toIntern()).layout,
2137 .anon_struct_type => .auto,
2138 .union_type => ip.loadUnionType(ty.toIntern()).flagsPtr(ip).layout,
2139 else => unreachable,
2140 };
2141}
2142
2143/// Asserts that the type is an error union.
2144pub fn errorUnionPayload(ty: Type, mod: *Module) Type {
2145 return Type.fromInterned(mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type);
2146}
2147
2148/// Asserts that the type is an error union.
2149pub fn errorUnionSet(ty: Type, mod: *Module) Type {
2150 return Type.fromInterned(mod.intern_pool.errorUnionSet(ty.toIntern()));
2151}
2152
2153/// Returns false for unresolved inferred error sets.
2154pub fn errorSetIsEmpty(ty: Type, mod: *Module) bool {
2155 const ip = &mod.intern_pool;
2156 return switch (ty.toIntern()) {
2157 .anyerror_type, .adhoc_inferred_error_set_type => false,
2158 else => switch (ip.indexToKey(ty.toIntern())) {
2159 .error_set_type => |error_set_type| error_set_type.names.len == 0,
2160 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2161 .none, .anyerror_type => false,
2162 else => |t| ip.indexToKey(t).error_set_type.names.len == 0,
2163 },
2164 else => unreachable,
2165 },
2166 };
2167}
2168
2169/// Returns true if it is an error set that includes anyerror, false otherwise.
2170/// Note that the result may be a false negative if the type did not get error set
2171/// resolution prior to this call.
2172pub fn isAnyError(ty: Type, mod: *Module) bool {
2173 const ip = &mod.intern_pool;
2174 return switch (ty.toIntern()) {
2175 .anyerror_type => true,
2176 .adhoc_inferred_error_set_type => false,
2177 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2178 .inferred_error_set_type => |i| ip.funcIesResolved(i).* == .anyerror_type,
2179 else => false,
2180 },
2181 };
2182}
2183
2184pub fn isError(ty: Type, mod: *const Module) bool {
2185 return switch (ty.zigTypeTag(mod)) {
2186 .ErrorUnion, .ErrorSet => true,
2187 else => false,
2188 };
2189}
2190
2191/// Returns whether ty, which must be an error set, includes an error `name`.
2192/// Might return a false negative if `ty` is an inferred error set and not fully
2193/// resolved yet.
2194pub fn errorSetHasFieldIp(
2195 ip: *const InternPool,
2196 ty: InternPool.Index,
2197 name: InternPool.NullTerminatedString,
2198) bool {
2199 return switch (ty) {
2200 .anyerror_type => true,
2201 else => switch (ip.indexToKey(ty)) {
2202 .error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null,
2203 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2204 .anyerror_type => true,
2205 .none => false,
2206 else => |t| ip.indexToKey(t).error_set_type.nameIndex(ip, name) != null,
2207 },
2208 else => unreachable,
2209 },
2210 };
2211}
2212
2213/// Returns whether ty, which must be an error set, includes an error `name`.
2214/// Might return a false negative if `ty` is an inferred error set and not fully
2215/// resolved yet.
2216pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool {
2217 const ip = &mod.intern_pool;
2218 return switch (ty.toIntern()) {
2219 .anyerror_type => true,
2220 else => switch (ip.indexToKey(ty.toIntern())) {
2221 .error_set_type => |error_set_type| {
2222 // If the string is not interned, then the field certainly is not present.
2223 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2224 return error_set_type.nameIndex(ip, field_name_interned) != null;
2225 },
2226 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2227 .anyerror_type => true,
2228 .none => false,
2229 else => |t| {
2230 // If the string is not interned, then the field certainly is not present.
2231 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2232 return ip.indexToKey(t).error_set_type.nameIndex(ip, field_name_interned) != null;
2233 },
2234 },
2235 else => unreachable,
2236 },
2237 };
2238}
2239
2240/// Asserts the type is an array or vector or struct.
2241pub fn arrayLen(ty: Type, mod: *const Module) u64 {
2242 return ty.arrayLenIp(&mod.intern_pool);
2243}
2244
2245pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 {
2246 return ip.aggregateTypeLen(ty.toIntern());
2247}
2248
2249pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 {
2250 return mod.intern_pool.aggregateTypeLenIncludingSentinel(ty.toIntern());
2251}
2252
2253pub fn vectorLen(ty: Type, mod: *const Module) u32 {
2254 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2255 .vector_type => |vector_type| vector_type.len,
2256 .anon_struct_type => |tuple| @intCast(tuple.types.len),
2257 else => unreachable,
2258 };
2259}
2260
2261/// Asserts the type is an array, pointer or vector.
2262pub fn sentinel(ty: Type, mod: *const Module) ?Value {
2263 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2264 .vector_type,
2265 .struct_type,
2266 .anon_struct_type,
2267 => null,
2268
2269 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
2270 .ptr_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
2271
2272 else => unreachable,
2273 };
2274}
2275
2276/// Returns true if and only if the type is a fixed-width integer.
2277pub fn isInt(self: Type, mod: *const Module) bool {
2278 return self.toIntern() != .comptime_int_type and
2279 mod.intern_pool.isIntegerType(self.toIntern());
2280}
2281
2282/// Returns true if and only if the type is a fixed-width, signed integer.
2283pub fn isSignedInt(ty: Type, mod: *const Module) bool {
2284 return switch (ty.toIntern()) {
2285 .c_char_type => mod.getTarget().charSignedness() == .signed,
2286 .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,
2287 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2288 .int_type => |int_type| int_type.signedness == .signed,
2289 else => false,
2290 },
2291 };
2292}
2293
2294/// Returns true if and only if the type is a fixed-width, unsigned integer.
2295pub fn isUnsignedInt(ty: Type, mod: *const Module) bool {
2296 return switch (ty.toIntern()) {
2297 .c_char_type => mod.getTarget().charSignedness() == .unsigned,
2298 .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true,
2299 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2300 .int_type => |int_type| int_type.signedness == .unsigned,
2301 else => false,
2302 },
2303 };
2304}
2305
2306/// Returns true for integers, enums, error sets, and packed structs.
2307/// If this function returns true, then intInfo() can be called on the type.
2308pub fn isAbiInt(ty: Type, mod: *Module) bool {
2309 return switch (ty.zigTypeTag(mod)) {
2310 .Int, .Enum, .ErrorSet => true,
2311 .Struct => ty.containerLayout(mod) == .@"packed",
2312 else => false,
2313 };
2314}
2315
2316/// Asserts the type is an integer, enum, error set, or vector of one of them.
2317pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
2318 const ip = &mod.intern_pool;
2319 const target = mod.getTarget();
2320 var ty = starting_ty;
2321
2322 while (true) switch (ty.toIntern()) {
2323 .anyerror_type, .adhoc_inferred_error_set_type => {
2324 return .{ .signedness = .unsigned, .bits = mod.errorSetBits() };
2325 },
2326 .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() },
2327 .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() },
2328 .c_char_type => return .{ .signedness = mod.getTarget().charSignedness(), .bits = target.c_type_bit_size(.char) },
2329 .c_short_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) },
2330 .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) },
2331 .c_int_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) },
2332 .c_uint_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.uint) },
2333 .c_long_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.long) },
2334 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },
2335 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },
2336 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },
2337 else => switch (ip.indexToKey(ty.toIntern())) {
2338 .int_type => |int_type| return int_type,
2339 .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntType(ip).*),
2340 .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
2341 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
2342
2343 .error_set_type, .inferred_error_set_type => {
2344 return .{ .signedness = .unsigned, .bits = mod.errorSetBits() };
2345 },
2346
2347 .anon_struct_type => unreachable,
2348
2349 .ptr_type => unreachable,
2350 .anyframe_type => unreachable,
2351 .array_type => unreachable,
2352
2353 .opt_type => unreachable,
2354 .error_union_type => unreachable,
2355 .func_type => unreachable,
2356 .simple_type => unreachable, // handled via Index enum tag above
2357
2358 .union_type => unreachable,
2359 .opaque_type => unreachable,
2360
2361 // values, not types
2362 .undef,
2363 .simple_value,
2364 .variable,
2365 .extern_func,
2366 .func,
2367 .int,
2368 .err,
2369 .error_union,
2370 .enum_literal,
2371 .enum_tag,
2372 .empty_enum_value,
2373 .float,
2374 .ptr,
2375 .slice,
2376 .opt,
2377 .aggregate,
2378 .un,
2379 // memoization, not types
2380 .memoized_call,
2381 => unreachable,
2382 },
2383 };
2384}
2385
2386pub fn isNamedInt(ty: Type) bool {
2387 return switch (ty.toIntern()) {
2388 .usize_type,
2389 .isize_type,
2390 .c_char_type,
2391 .c_short_type,
2392 .c_ushort_type,
2393 .c_int_type,
2394 .c_uint_type,
2395 .c_long_type,
2396 .c_ulong_type,
2397 .c_longlong_type,
2398 .c_ulonglong_type,
2399 => true,
2400
2401 else => false,
2402 };
2403}
2404
2405/// Returns `false` for `comptime_float`.
2406pub fn isRuntimeFloat(ty: Type) bool {
2407 return switch (ty.toIntern()) {
2408 .f16_type,
2409 .f32_type,
2410 .f64_type,
2411 .f80_type,
2412 .f128_type,
2413 .c_longdouble_type,
2414 => true,
2415
2416 else => false,
2417 };
2418}
2419
2420/// Returns `true` for `comptime_float`.
2421pub fn isAnyFloat(ty: Type) bool {
2422 return switch (ty.toIntern()) {
2423 .f16_type,
2424 .f32_type,
2425 .f64_type,
2426 .f80_type,
2427 .f128_type,
2428 .c_longdouble_type,
2429 .comptime_float_type,
2430 => true,
2431
2432 else => false,
2433 };
2434}
2435
2436/// Asserts the type is a fixed-size float or comptime_float.
2437/// Returns 128 for comptime_float types.
2438pub fn floatBits(ty: Type, target: Target) u16 {
2439 return switch (ty.toIntern()) {
2440 .f16_type => 16,
2441 .f32_type => 32,
2442 .f64_type => 64,
2443 .f80_type => 80,
2444 .f128_type, .comptime_float_type => 128,
2445 .c_longdouble_type => target.c_type_bit_size(.longdouble),
2446
2447 else => unreachable,
2448 };
2449}
2450
2451/// Asserts the type is a function or a function pointer.
2452pub fn fnReturnType(ty: Type, mod: *Module) Type {
2453 return Type.fromInterned(mod.intern_pool.funcTypeReturnType(ty.toIntern()));
2454}
2455
2456/// Asserts the type is a function.
2457pub fn fnCallingConvention(ty: Type, mod: *Module) std.builtin.CallingConvention {
2458 return mod.intern_pool.indexToKey(ty.toIntern()).func_type.cc;
2459}
2460
2461pub fn isValidParamType(self: Type, mod: *const Module) bool {
2462 return switch (self.zigTypeTagOrPoison(mod) catch return true) {
2463 .Opaque, .NoReturn => false,
2464 else => true,
2465 };
2466}
2467
2468pub fn isValidReturnType(self: Type, mod: *const Module) bool {
2469 return switch (self.zigTypeTagOrPoison(mod) catch return true) {
2470 .Opaque => false,
2471 else => true,
2472 };
2473}
2474
2475/// Asserts the type is a function.
2476pub fn fnIsVarArgs(ty: Type, mod: *Module) bool {
2477 return mod.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args;
2478}
2479
2480pub fn isNumeric(ty: Type, mod: *const Module) bool {
2481 return switch (ty.toIntern()) {
2482 .f16_type,
2483 .f32_type,
2484 .f64_type,
2485 .f80_type,
2486 .f128_type,
2487 .c_longdouble_type,
2488 .comptime_int_type,
2489 .comptime_float_type,
2490 .usize_type,
2491 .isize_type,
2492 .c_char_type,
2493 .c_short_type,
2494 .c_ushort_type,
2495 .c_int_type,
2496 .c_uint_type,
2497 .c_long_type,
2498 .c_ulong_type,
2499 .c_longlong_type,
2500 .c_ulonglong_type,
2501 => true,
2502
2503 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2504 .int_type => true,
2505 else => false,
2506 },
2507 };
2508}
2509
2510/// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which
2511/// resolves field types rather than asserting they are already resolved.
2512pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value {
2513 var ty = starting_type;
2514 const ip = &mod.intern_pool;
2515 while (true) switch (ty.toIntern()) {
2516 .empty_struct_type => return Value.empty_struct,
2517
2518 else => switch (ip.indexToKey(ty.toIntern())) {
2519 .int_type => |int_type| {
2520 if (int_type.bits == 0) {
2521 return try mod.intValue(ty, 0);
2522 } else {
2523 return null;
2524 }
2525 },
2526
2527 .ptr_type,
2528 .error_union_type,
2529 .func_type,
2530 .anyframe_type,
2531 .error_set_type,
2532 .inferred_error_set_type,
2533 => return null,
2534
2535 inline .array_type, .vector_type => |seq_type, seq_tag| {
2536 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
2537 if (seq_type.len + @intFromBool(has_sentinel) == 0) return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2538 .ty = ty.toIntern(),
2539 .storage = .{ .elems = &.{} },
2540 } })));
2541 if (try Type.fromInterned(seq_type.child).onePossibleValue(mod)) |opv| {
2542 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2543 .ty = ty.toIntern(),
2544 .storage = .{ .repeated_elem = opv.toIntern() },
2545 } })));
2546 }
2547 return null;
2548 },
2549 .opt_type => |child| {
2550 if (child == .noreturn_type) {
2551 return try mod.nullValue(ty);
2552 } else {
2553 return null;
2554 }
2555 },
2556
2557 .simple_type => |t| switch (t) {
2558 .f16,
2559 .f32,
2560 .f64,
2561 .f80,
2562 .f128,
2563 .usize,
2564 .isize,
2565 .c_char,
2566 .c_short,
2567 .c_ushort,
2568 .c_int,
2569 .c_uint,
2570 .c_long,
2571 .c_ulong,
2572 .c_longlong,
2573 .c_ulonglong,
2574 .c_longdouble,
2575 .anyopaque,
2576 .bool,
2577 .type,
2578 .anyerror,
2579 .comptime_int,
2580 .comptime_float,
2581 .enum_literal,
2582 .atomic_order,
2583 .atomic_rmw_op,
2584 .calling_convention,
2585 .address_space,
2586 .float_mode,
2587 .reduce_op,
2588 .call_modifier,
2589 .prefetch_options,
2590 .export_options,
2591 .extern_options,
2592 .type_info,
2593 .adhoc_inferred_error_set,
2594 => return null,
2595
2596 .void => return Value.void,
2597 .noreturn => return Value.@"unreachable",
2598 .null => return Value.null,
2599 .undefined => return Value.undef,
2600
2601 .generic_poison => unreachable,
2602 },
2603 .struct_type => {
2604 const struct_type = ip.loadStructType(ty.toIntern());
2605 assert(struct_type.haveFieldTypes(ip));
2606 if (struct_type.knownNonOpv(ip))
2607 return null;
2608 const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len);
2609 defer mod.gpa.free(field_vals);
2610 for (field_vals, 0..) |*field_val, i_usize| {
2611 const i: u32 = @intCast(i_usize);
2612 if (struct_type.fieldIsComptime(ip, i)) {
2613 assert(struct_type.haveFieldInits(ip));
2614 field_val.* = struct_type.field_inits.get(ip)[i];
2615 continue;
2616 }
2617 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
2618 if (try field_ty.onePossibleValue(mod)) |field_opv| {
2619 field_val.* = field_opv.toIntern();
2620 } else return null;
2621 }
2622
2623 // In this case the struct has no runtime-known fields and
2624 // therefore has one possible value.
2625 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2626 .ty = ty.toIntern(),
2627 .storage = .{ .elems = field_vals },
2628 } })));
2629 },
2630
2631 .anon_struct_type => |tuple| {
2632 for (tuple.values.get(ip)) |val| {
2633 if (val == .none) return null;
2634 }
2635 // In this case the struct has all comptime-known fields and
2636 // therefore has one possible value.
2637 // TODO: write something like getCoercedInts to avoid needing to dupe
2638 const duped_values = try mod.gpa.dupe(InternPool.Index, tuple.values.get(ip));
2639 defer mod.gpa.free(duped_values);
2640 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2641 .ty = ty.toIntern(),
2642 .storage = .{ .elems = duped_values },
2643 } })));
2644 },
2645
2646 .union_type => {
2647 const union_obj = ip.loadUnionType(ty.toIntern());
2648 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(mod)) orelse
2649 return null;
2650 if (union_obj.field_types.len == 0) {
2651 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2652 return Value.fromInterned(only);
2653 }
2654 const only_field_ty = union_obj.field_types.get(ip)[0];
2655 const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(mod)) orelse
2656 return null;
2657 const only = try mod.intern(.{ .un = .{
2658 .ty = ty.toIntern(),
2659 .tag = tag_val.toIntern(),
2660 .val = val_val.toIntern(),
2661 } });
2662 return Value.fromInterned(only);
2663 },
2664 .opaque_type => return null,
2665 .enum_type => {
2666 const enum_type = ip.loadEnumType(ty.toIntern());
2667 switch (enum_type.tag_mode) {
2668 .nonexhaustive => {
2669 if (enum_type.tag_ty == .comptime_int_type) return null;
2670
2671 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {
2672 const only = try mod.intern(.{ .enum_tag = .{
2673 .ty = ty.toIntern(),
2674 .int = int_opv.toIntern(),
2675 } });
2676 return Value.fromInterned(only);
2677 }
2678
2679 return null;
2680 },
2681 .auto, .explicit => {
2682 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
2683
2684 switch (enum_type.names.len) {
2685 0 => {
2686 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2687 return Value.fromInterned(only);
2688 },
2689 1 => {
2690 if (enum_type.values.len == 0) {
2691 const only = try mod.intern(.{ .enum_tag = .{
2692 .ty = ty.toIntern(),
2693 .int = try mod.intern(.{ .int = .{
2694 .ty = enum_type.tag_ty,
2695 .storage = .{ .u64 = 0 },
2696 } }),
2697 } });
2698 return Value.fromInterned(only);
2699 } else {
2700 return Value.fromInterned(enum_type.values.get(ip)[0]);
2701 }
2702 },
2703 else => return null,
2704 }
2705 },
2706 }
2707 },
2708
2709 // values, not types
2710 .undef,
2711 .simple_value,
2712 .variable,
2713 .extern_func,
2714 .func,
2715 .int,
2716 .err,
2717 .error_union,
2718 .enum_literal,
2719 .enum_tag,
2720 .empty_enum_value,
2721 .float,
2722 .ptr,
2723 .slice,
2724 .opt,
2725 .aggregate,
2726 .un,
2727 // memoization, not types
2728 .memoized_call,
2729 => unreachable,
2730 },
2731 };
2732}
2733
2734/// During semantic analysis, instead call `Sema.typeRequiresComptime` which
2735/// resolves field types rather than asserting they are already resolved.
2736pub fn comptimeOnly(ty: Type, mod: *Module) bool {
2737 return ty.comptimeOnlyAdvanced(mod, .normal) catch unreachable;
2738}
2739
2740/// `generic_poison` will return false.
2741/// May return false negatives when structs and unions are having their field types resolved.
2742pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, strat: ResolveStrat) SemaError!bool {
2743 const ip = &mod.intern_pool;
2744 return switch (ty.toIntern()) {
2745 .empty_struct_type => false,
2746
2747 else => switch (ip.indexToKey(ty.toIntern())) {
2748 .int_type => false,
2749 .ptr_type => |ptr_type| {
2750 const child_ty = Type.fromInterned(ptr_type.child);
2751 switch (child_ty.zigTypeTag(mod)) {
2752 .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, strat),
2753 .Opaque => return false,
2754 else => return child_ty.comptimeOnlyAdvanced(mod, strat),
2755 }
2756 },
2757 .anyframe_type => |child| {
2758 if (child == .none) return false;
2759 return Type.fromInterned(child).comptimeOnlyAdvanced(mod, strat);
2760 },
2761 .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyAdvanced(mod, strat),
2762 .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyAdvanced(mod, strat),
2763 .opt_type => |child| return Type.fromInterned(child).comptimeOnlyAdvanced(mod, strat),
2764 .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyAdvanced(mod, strat),
2765
2766 .error_set_type,
2767 .inferred_error_set_type,
2768 => false,
2769
2770 // These are function bodies, not function pointers.
2771 .func_type => true,
2772
2773 .simple_type => |t| switch (t) {
2774 .f16,
2775 .f32,
2776 .f64,
2777 .f80,
2778 .f128,
2779 .usize,
2780 .isize,
2781 .c_char,
2782 .c_short,
2783 .c_ushort,
2784 .c_int,
2785 .c_uint,
2786 .c_long,
2787 .c_ulong,
2788 .c_longlong,
2789 .c_ulonglong,
2790 .c_longdouble,
2791 .anyopaque,
2792 .bool,
2793 .void,
2794 .anyerror,
2795 .adhoc_inferred_error_set,
2796 .noreturn,
2797 .generic_poison,
2798 .atomic_order,
2799 .atomic_rmw_op,
2800 .calling_convention,
2801 .address_space,
2802 .float_mode,
2803 .reduce_op,
2804 .call_modifier,
2805 .prefetch_options,
2806 .export_options,
2807 .extern_options,
2808 => false,
2809
2810 .type,
2811 .comptime_int,
2812 .comptime_float,
2813 .null,
2814 .undefined,
2815 .enum_literal,
2816 .type_info,
2817 => true,
2818 },
2819 .struct_type => {
2820 const struct_type = ip.loadStructType(ty.toIntern());
2821 // packed structs cannot be comptime-only because they have a well-defined
2822 // memory layout and every field has a well-defined bit pattern.
2823 if (struct_type.layout == .@"packed")
2824 return false;
2825
2826 // A struct with no fields is not comptime-only.
2827 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2828 .no, .wip => false,
2829 .yes => true,
2830 .unknown => {
2831 assert(strat == .sema);
2832
2833 if (struct_type.flagsPtr(ip).field_types_wip)
2834 return false;
2835
2836 struct_type.flagsPtr(ip).requires_comptime = .wip;
2837 errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown;
2838
2839 try ty.resolveFields(mod);
2840
2841 for (0..struct_type.field_types.len) |i_usize| {
2842 const i: u32 = @intCast(i_usize);
2843 if (struct_type.fieldIsComptime(ip, i)) continue;
2844 const field_ty = struct_type.field_types.get(ip)[i];
2845 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, strat)) {
2846 // Note that this does not cause the layout to
2847 // be considered resolved. Comptime-only types
2848 // still maintain a layout of their
2849 // runtime-known fields.
2850 struct_type.flagsPtr(ip).requires_comptime = .yes;
2851 return true;
2852 }
2853 }
2854
2855 struct_type.flagsPtr(ip).requires_comptime = .no;
2856 return false;
2857 },
2858 };
2859 },
2860
2861 .anon_struct_type => |tuple| {
2862 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2863 const have_comptime_val = val != .none;
2864 if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, strat)) return true;
2865 }
2866 return false;
2867 },
2868
2869 .union_type => {
2870 const union_type = ip.loadUnionType(ty.toIntern());
2871 switch (union_type.flagsPtr(ip).requires_comptime) {
2872 .no, .wip => return false,
2873 .yes => return true,
2874 .unknown => {
2875 assert(strat == .sema);
2876
2877 if (union_type.flagsPtr(ip).status == .field_types_wip)
2878 return false;
2879
2880 union_type.flagsPtr(ip).requires_comptime = .wip;
2881 errdefer union_type.flagsPtr(ip).requires_comptime = .unknown;
2882
2883 try ty.resolveFields(mod);
2884
2885 for (0..union_type.field_types.len) |field_idx| {
2886 const field_ty = union_type.field_types.get(ip)[field_idx];
2887 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, strat)) {
2888 union_type.flagsPtr(ip).requires_comptime = .yes;
2889 return true;
2890 }
2891 }
2892
2893 union_type.flagsPtr(ip).requires_comptime = .no;
2894 return false;
2895 },
2896 }
2897 },
2898
2899 .opaque_type => false,
2900
2901 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyAdvanced(mod, strat),
2902
2903 // values, not types
2904 .undef,
2905 .simple_value,
2906 .variable,
2907 .extern_func,
2908 .func,
2909 .int,
2910 .err,
2911 .error_union,
2912 .enum_literal,
2913 .enum_tag,
2914 .empty_enum_value,
2915 .float,
2916 .ptr,
2917 .slice,
2918 .opt,
2919 .aggregate,
2920 .un,
2921 // memoization, not types
2922 .memoized_call,
2923 => unreachable,
2924 },
2925 };
2926}
2927
2928pub fn isVector(ty: Type, mod: *const Module) bool {
2929 return ty.zigTypeTag(mod) == .Vector;
2930}
2931
2932/// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len.
2933pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 {
2934 if (!ty.isVector(zcu)) return 0;
2935 const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type;
2936 return v.len * Type.fromInterned(v.child).bitSize(zcu);
2937}
2938
2939pub fn isArrayOrVector(ty: Type, mod: *const Module) bool {
2940 return switch (ty.zigTypeTag(mod)) {
2941 .Array, .Vector => true,
2942 else => false,
2943 };
2944}
2945
2946pub fn isIndexable(ty: Type, mod: *Module) bool {
2947 return switch (ty.zigTypeTag(mod)) {
2948 .Array, .Vector => true,
2949 .Pointer => switch (ty.ptrSize(mod)) {
2950 .Slice, .Many, .C => true,
2951 .One => switch (ty.childType(mod).zigTypeTag(mod)) {
2952 .Array, .Vector => true,
2953 .Struct => ty.childType(mod).isTuple(mod),
2954 else => false,
2955 },
2956 },
2957 .Struct => ty.isTuple(mod),
2958 else => false,
2959 };
2960}
2961
2962pub fn indexableHasLen(ty: Type, mod: *Module) bool {
2963 return switch (ty.zigTypeTag(mod)) {
2964 .Array, .Vector => true,
2965 .Pointer => switch (ty.ptrSize(mod)) {
2966 .Many, .C => false,
2967 .Slice => true,
2968 .One => switch (ty.childType(mod).zigTypeTag(mod)) {
2969 .Array, .Vector => true,
2970 .Struct => ty.childType(mod).isTuple(mod),
2971 else => false,
2972 },
2973 },
2974 .Struct => ty.isTuple(mod),
2975 else => false,
2976 };
2977}
2978
2979/// Asserts that the type can have a namespace.
2980pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
2981 return ty.getNamespace(zcu).?;
2982}
2983
2984/// Returns null if the type has no namespace.
2985pub fn getNamespace(ty: Type, zcu: *Zcu) ?InternPool.OptionalNamespaceIndex {
2986 const ip = &zcu.intern_pool;
2987 return switch (ip.indexToKey(ty.toIntern())) {
2988 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
2989 .struct_type => ip.loadStructType(ty.toIntern()).namespace,
2990 .union_type => ip.loadUnionType(ty.toIntern()).namespace,
2991 .enum_type => ip.loadEnumType(ty.toIntern()).namespace,
2992
2993 .anon_struct_type => .none,
2994 .simple_type => |s| switch (s) {
2995 .anyopaque,
2996 .atomic_order,
2997 .atomic_rmw_op,
2998 .calling_convention,
2999 .address_space,
3000 .float_mode,
3001 .reduce_op,
3002 .call_modifier,
3003 .prefetch_options,
3004 .export_options,
3005 .extern_options,
3006 .type_info,
3007 => .none,
3008 else => null,
3009 },
3010
3011 else => null,
3012 };
3013}
3014
3015// Works for vectors and vectors of integers.
3016pub fn minInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
3017 const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
3018 return if (ty.zigTypeTag(mod) == .Vector) Value.fromInterned((try mod.intern(.{ .aggregate = .{
3019 .ty = dest_ty.toIntern(),
3020 .storage = .{ .repeated_elem = scalar.toIntern() },
3021 } }))) else scalar;
3022}
3023
3024/// Asserts that the type is an integer.
3025pub fn minIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
3026 const info = ty.intInfo(mod);
3027 if (info.signedness == .unsigned) return mod.intValue(dest_ty, 0);
3028 if (info.bits == 0) return mod.intValue(dest_ty, -1);
3029
3030 if (std.math.cast(u6, info.bits - 1)) |shift| {
3031 const n = @as(i64, std.math.minInt(i64)) >> (63 - shift);
3032 return mod.intValue(dest_ty, n);
3033 }
3034
3035 var res = try std.math.big.int.Managed.init(mod.gpa);
3036 defer res.deinit();
3037
3038 try res.setTwosCompIntLimit(.min, info.signedness, info.bits);
3039
3040 return mod.intValue_big(dest_ty, res.toConst());
3041}
3042
3043// Works for vectors and vectors of integers.
3044/// The returned Value will have type dest_ty.
3045pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
3046 const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
3047 return if (ty.zigTypeTag(mod) == .Vector) Value.fromInterned((try mod.intern(.{ .aggregate = .{
3048 .ty = dest_ty.toIntern(),
3049 .storage = .{ .repeated_elem = scalar.toIntern() },
3050 } }))) else scalar;
3051}
3052
3053/// The returned Value will have type dest_ty.
3054pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
3055 const info = ty.intInfo(mod);
3056
3057 switch (info.bits) {
3058 0 => return switch (info.signedness) {
3059 .signed => try mod.intValue(dest_ty, -1),
3060 .unsigned => try mod.intValue(dest_ty, 0),
3061 },
3062 1 => return switch (info.signedness) {
3063 .signed => try mod.intValue(dest_ty, 0),
3064 .unsigned => try mod.intValue(dest_ty, 1),
3065 },
3066 else => {},
3067 }
3068
3069 if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) {
3070 .signed => {
3071 const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift);
3072 return mod.intValue(dest_ty, n);
3073 },
3074 .unsigned => {
3075 const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift);
3076 return mod.intValue(dest_ty, n);
3077 },
3078 };
3079
3080 var res = try std.math.big.int.Managed.init(mod.gpa);
3081 defer res.deinit();
3082
3083 try res.setTwosCompIntLimit(.max, info.signedness, info.bits);
3084
3085 return mod.intValue_big(dest_ty, res.toConst());
3086}
3087
3088/// Asserts the type is an enum or a union.
3089pub fn intTagType(ty: Type, mod: *Module) Type {
3090 const ip = &mod.intern_pool;
3091 return switch (ip.indexToKey(ty.toIntern())) {
3092 .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(mod),
3093 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
3094 else => unreachable,
3095 };
3096}
3097
3098pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
3099 const ip = &mod.intern_pool;
3100 return switch (ip.indexToKey(ty.toIntern())) {
3101 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
3102 .nonexhaustive => true,
3103 .auto, .explicit => false,
3104 },
3105 else => false,
3106 };
3107}
3108
3109// Asserts that `ty` is an error set and not `anyerror`.
3110// Asserts that `ty` is resolved if it is an inferred error set.
3111pub fn errorSetNames(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
3112 const ip = &mod.intern_pool;
3113 return switch (ip.indexToKey(ty.toIntern())) {
3114 .error_set_type => |x| x.names,
3115 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
3116 .none => unreachable, // unresolved inferred error set
3117 .anyerror_type => unreachable,
3118 else => |t| ip.indexToKey(t).error_set_type.names,
3119 },
3120 else => unreachable,
3121 };
3122}
3123
3124pub fn enumFields(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
3125 return mod.intern_pool.loadEnumType(ty.toIntern()).names;
3126}
3127
3128pub fn enumFieldCount(ty: Type, mod: *Module) usize {
3129 return mod.intern_pool.loadEnumType(ty.toIntern()).names.len;
3130}
3131
3132pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
3133 const ip = &mod.intern_pool;
3134 return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index];
3135}
3136
3137pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {
3138 const ip = &mod.intern_pool;
3139 const enum_type = ip.loadEnumType(ty.toIntern());
3140 return enum_type.nameIndex(ip, field_name);
3141}
3142
3143/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
3144/// an integer which represents the enum value. Returns the field index in
3145/// declaration order, or `null` if `enum_tag` does not match any field.
3146pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
3147 const ip = &mod.intern_pool;
3148 const enum_type = ip.loadEnumType(ty.toIntern());
3149 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
3150 .int => enum_tag.toIntern(),
3151 .enum_tag => |info| info.int,
3152 else => unreachable,
3153 };
3154 assert(ip.typeOf(int_tag) == enum_type.tag_ty);
3155 return enum_type.tagValueIndex(ip, int_tag);
3156}
3157
3158/// Returns none in the case of a tuple which uses the integer index as the field name.
3159pub fn structFieldName(ty: Type, index: usize, mod: *Module) InternPool.OptionalNullTerminatedString {
3160 const ip = &mod.intern_pool;
3161 return switch (ip.indexToKey(ty.toIntern())) {
3162 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
3163 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index),
3164 else => unreachable,
3165 };
3166}
3167
3168pub fn structFieldCount(ty: Type, mod: *Module) u32 {
3169 const ip = &mod.intern_pool;
3170 return switch (ip.indexToKey(ty.toIntern())) {
3171 .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
3172 .anon_struct_type => |anon_struct| anon_struct.types.len,
3173 else => unreachable,
3174 };
3175}
3176
3177/// Supports structs and unions.
3178pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
3179 const ip = &mod.intern_pool;
3180 return switch (ip.indexToKey(ty.toIntern())) {
3181 .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),
3182 .union_type => {
3183 const union_obj = ip.loadUnionType(ty.toIntern());
3184 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
3185 },
3186 .anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]),
3187 else => unreachable,
3188 };
3189}
3190
3191pub fn structFieldAlign(ty: Type, index: usize, zcu: *Zcu) Alignment {
3192 return ty.structFieldAlignAdvanced(index, zcu, .normal) catch unreachable;
3193}
3194
3195pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, strat: ResolveStrat) !Alignment {
3196 const ip = &zcu.intern_pool;
3197 switch (ip.indexToKey(ty.toIntern())) {
3198 .struct_type => {
3199 const struct_type = ip.loadStructType(ty.toIntern());
3200 assert(struct_type.layout != .@"packed");
3201 const explicit_align = struct_type.fieldAlign(ip, index);
3202 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
3203 return zcu.structFieldAlignmentAdvanced(explicit_align, field_ty, struct_type.layout, strat);
3204 },
3205 .anon_struct_type => |anon_struct| {
3206 return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentAdvanced(zcu, strat.toLazy())).scalar;
3207 },
3208 .union_type => {
3209 const union_obj = ip.loadUnionType(ty.toIntern());
3210 return zcu.unionFieldNormalAlignmentAdvanced(union_obj, @intCast(index), strat);
3211 },
3212 else => unreachable,
3213 }
3214}
3215
3216pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value {
3217 const ip = &mod.intern_pool;
3218 switch (ip.indexToKey(ty.toIntern())) {
3219 .struct_type => {
3220 const struct_type = ip.loadStructType(ty.toIntern());
3221 const val = struct_type.fieldInit(ip, index);
3222 // TODO: avoid using `unreachable` to indicate this.
3223 if (val == .none) return Value.@"unreachable";
3224 return Value.fromInterned(val);
3225 },
3226 .anon_struct_type => |anon_struct| {
3227 const val = anon_struct.values.get(ip)[index];
3228 // TODO: avoid using `unreachable` to indicate this.
3229 if (val == .none) return Value.@"unreachable";
3230 return Value.fromInterned(val);
3231 },
3232 else => unreachable,
3233 }
3234}
3235
3236pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value {
3237 const ip = &mod.intern_pool;
3238 switch (ip.indexToKey(ty.toIntern())) {
3239 .struct_type => {
3240 const struct_type = ip.loadStructType(ty.toIntern());
3241 if (struct_type.fieldIsComptime(ip, index)) {
3242 assert(struct_type.haveFieldInits(ip));
3243 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);
3244 } else {
3245 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(mod);
3246 }
3247 },
3248 .anon_struct_type => |tuple| {
3249 const val = tuple.values.get(ip)[index];
3250 if (val == .none) {
3251 return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(mod);
3252 } else {
3253 return Value.fromInterned(val);
3254 }
3255 },
3256 else => unreachable,
3257 }
3258}
3259
3260pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
3261 const ip = &mod.intern_pool;
3262 return switch (ip.indexToKey(ty.toIntern())) {
3263 .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),
3264 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
3265 else => unreachable,
3266 };
3267}
3268
3269pub const FieldOffset = struct {
3270 field: usize,
3271 offset: u64,
3272};
3273
3274/// Supports structs and unions.
3275pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
3276 const ip = &mod.intern_pool;
3277 switch (ip.indexToKey(ty.toIntern())) {
3278 .struct_type => {
3279 const struct_type = ip.loadStructType(ty.toIntern());
3280 assert(struct_type.haveLayout(ip));
3281 assert(struct_type.layout != .@"packed");
3282 return struct_type.offsets.get(ip)[index];
3283 },
3284
3285 .anon_struct_type => |tuple| {
3286 var offset: u64 = 0;
3287 var big_align: Alignment = .none;
3288
3289 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
3290 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(mod)) {
3291 // comptime field
3292 if (i == index) return offset;
3293 continue;
3294 }
3295
3296 const field_align = Type.fromInterned(field_ty).abiAlignment(mod);
3297 big_align = big_align.max(field_align);
3298 offset = field_align.forward(offset);
3299 if (i == index) return offset;
3300 offset += Type.fromInterned(field_ty).abiSize(mod);
3301 }
3302 offset = big_align.max(.@"1").forward(offset);
3303 return offset;
3304 },
3305
3306 .union_type => {
3307 const union_type = ip.loadUnionType(ty.toIntern());
3308 if (!union_type.hasTag(ip))
3309 return 0;
3310 const layout = mod.getUnionLayout(union_type);
3311 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3312 // {Tag, Payload}
3313 return layout.payload_align.forward(layout.tag_size);
3314 } else {
3315 // {Payload, Tag}
3316 return 0;
3317 }
3318 },
3319
3320 else => unreachable,
3321 }
3322}
3323
3324pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
3325 return ty.getOwnerDeclOrNull(mod) orelse unreachable;
3326}
3327
3328pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
3329 const ip = &mod.intern_pool;
3330 return switch (ip.indexToKey(ty.toIntern())) {
3331 .struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
3332 .union_type => ip.loadUnionType(ty.toIntern()).decl,
3333 .opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
3334 .enum_type => ip.loadEnumType(ty.toIntern()).decl,
3335 else => null,
3336 };
3337}
3338
3339pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Module.LazySrcLoc {
3340 const ip = &zcu.intern_pool;
3341 return .{
3342 .base_node_inst = switch (ip.indexToKey(ty.toIntern())) {
3343 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3344 .declared => |d| d.zir_index,
3345 .reified => |r| r.zir_index,
3346 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
3347 .empty_struct => return null,
3348 },
3349 else => return null,
3350 },
3351 .offset = Module.LazySrcLoc.Offset.nodeOffset(0),
3352 };
3353}
3354
3355pub fn srcLoc(ty: Type, zcu: *Zcu) Module.LazySrcLoc {
3356 return ty.srcLocOrNull(zcu).?;
3357}
3358
3359pub fn isGenericPoison(ty: Type) bool {
3360 return ty.toIntern() == .generic_poison_type;
3361}
3362
3363pub fn isTuple(ty: Type, mod: *Module) bool {
3364 const ip = &mod.intern_pool;
3365 return switch (ip.indexToKey(ty.toIntern())) {
3366 .struct_type => {
3367 const struct_type = ip.loadStructType(ty.toIntern());
3368 if (struct_type.layout == .@"packed") return false;
3369 if (struct_type.decl == .none) return false;
3370 return struct_type.flagsPtr(ip).is_tuple;
3371 },
3372 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,
3373 else => false,
3374 };
3375}
3376
3377pub fn isAnonStruct(ty: Type, mod: *Module) bool {
3378 if (ty.toIntern() == .empty_struct_type) return true;
3379 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3380 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0,
3381 else => false,
3382 };
3383}
3384
3385pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3386 const ip = &mod.intern_pool;
3387 return switch (ip.indexToKey(ty.toIntern())) {
3388 .struct_type => {
3389 const struct_type = ip.loadStructType(ty.toIntern());
3390 if (struct_type.layout == .@"packed") return false;
3391 if (struct_type.decl == .none) return false;
3392 return struct_type.flagsPtr(ip).is_tuple;
3393 },
3394 .anon_struct_type => true,
3395 else => false,
3396 };
3397}
3398
3399pub fn isSimpleTuple(ty: Type, mod: *Module) bool {
3400 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3401 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0,
3402 else => false,
3403 };
3404}
3405
3406pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3407 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3408 .anon_struct_type => true,
3409 else => false,
3410 };
3411}
3412
3413/// Traverses optional child types and error union payloads until the type
3414/// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
3415pub fn optEuBaseType(ty: Type, mod: *Module) Type {
3416 var cur = ty;
3417 while (true) switch (cur.zigTypeTag(mod)) {
3418 .Optional => cur = cur.optionalChild(mod),
3419 .ErrorUnion => cur = cur.errorUnionPayload(mod),
3420 else => return cur,
3421 };
3422}
3423
3424pub fn toUnsigned(ty: Type, mod: *Module) !Type {
3425 return switch (ty.zigTypeTag(mod)) {
3426 .Int => mod.intType(.unsigned, ty.intInfo(mod).bits),
3427 .Vector => try mod.vectorType(.{
3428 .len = ty.vectorLen(mod),
3429 .child = (try ty.childType(mod).toUnsigned(mod)).toIntern(),
3430 }),
3431 else => unreachable,
3432 };
3433}
3434
3435pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3436 const ip = &zcu.intern_pool;
3437 return switch (ip.indexToKey(ty.toIntern())) {
3438 .struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
3439 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
3440 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
3441 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
3442 else => null,
3443 };
3444}
3445
3446pub fn typeDeclSrcLine(ty: Type, zcu: *const Zcu) ?u32 {
3447 const ip = &zcu.intern_pool;
3448 const tracked = switch (ip.indexToKey(ty.toIntern())) {
3449 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3450 .declared => |d| d.zir_index,
3451 .reified => |r| r.zir_index,
3452 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
3453 .empty_struct => return null,
3454 },
3455 else => return null,
3456 };
3457 const info = tracked.resolveFull(&zcu.intern_pool);
3458 const file = zcu.import_table.values()[zcu.path_digest_map.getIndex(info.path_digest).?];
3459 assert(file.zir_loaded);
3460 const zir = file.zir;
3461 const inst = zir.instructions.get(@intFromEnum(info.inst));
3462 assert(inst.tag == .extended);
3463 return switch (inst.data.extended.opcode) {
3464 .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line,
3465 .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
3466 .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
3467 .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
3468 .reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line,
3469 else => unreachable,
3470 };
3471}
3472
3473/// Given a namespace type, returns its list of caotured values.
3474pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
3475 const ip = &zcu.intern_pool;
3476 return switch (ip.indexToKey(ty.toIntern())) {
3477 .struct_type => ip.loadStructType(ty.toIntern()).captures,
3478 .union_type => ip.loadUnionType(ty.toIntern()).captures,
3479 .enum_type => ip.loadEnumType(ty.toIntern()).captures,
3480 .opaque_type => ip.loadOpaqueType(ty.toIntern()).captures,
3481 else => unreachable,
3482 };
3483}
3484
3485pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
3486 var cur_ty: Type = ty;
3487 var cur_len: u64 = 1;
3488 while (cur_ty.zigTypeTag(zcu) == .Array) {
3489 cur_len *= cur_ty.arrayLenIncludingSentinel(zcu);
3490 cur_ty = cur_ty.childType(zcu);
3491 }
3492 return .{ cur_ty, cur_len };
3493}
3494
3495pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: u32, zcu: *Zcu) union(enum) {
3496 /// The result is a bit-pointer with the same value and a new packed offset.
3497 bit_ptr: InternPool.Key.PtrType.PackedOffset,
3498 /// The result is a standard pointer.
3499 byte_ptr: struct {
3500 /// The byte offset of the field pointer from the parent pointer value.
3501 offset: u64,
3502 /// The alignment of the field pointer type.
3503 alignment: InternPool.Alignment,
3504 },
3505} {
3506 comptime assert(Type.packed_struct_layout_version == 2);
3507
3508 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
3509 const field_ty = struct_ty.structFieldType(field_idx, zcu);
3510
3511 var bit_offset: u16 = 0;
3512 var running_bits: u16 = 0;
3513 for (0..struct_ty.structFieldCount(zcu)) |i| {
3514 const f_ty = struct_ty.structFieldType(i, zcu);
3515 if (i == field_idx) {
3516 bit_offset = running_bits;
3517 }
3518 running_bits += @intCast(f_ty.bitSize(zcu));
3519 }
3520
3521 const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0)
3522 .{ parent_ptr_info.packed_offset.host_size, parent_ptr_info.packed_offset.bit_offset + bit_offset }
3523 else
3524 .{ (running_bits + 7) / 8, bit_offset };
3525
3526 // If the field happens to be byte-aligned, simplify the pointer type.
3527 // We can only do this if the pointee's bit size matches its ABI byte size,
3528 // so that loads and stores do not interfere with surrounding packed bits.
3529 //
3530 // TODO: we do not attempt this with big-endian targets yet because of nested
3531 // structs and floats. I need to double-check the desired behavior for big endian
3532 // targets before adding the necessary complications to this code. This will not
3533 // cause miscompilations; it only means the field pointer uses bit masking when it
3534 // might not be strictly necessary.
3535 if (res_bit_offset % 8 == 0 and field_ty.bitSize(zcu) == field_ty.abiSize(zcu) * 8 and zcu.getTarget().cpu.arch.endian() == .little) {
3536 const byte_offset = res_bit_offset / 8;
3537 const new_align = Alignment.fromLog2Units(@ctz(byte_offset | parent_ptr_ty.ptrAlignment(zcu).toByteUnits().?));
3538 return .{ .byte_ptr = .{
3539 .offset = byte_offset,
3540 .alignment = new_align,
3541 } };
3542 }
3543
3544 return .{ .bit_ptr = .{
3545 .host_size = res_host_size,
3546 .bit_offset = res_bit_offset,
3547 } };
3548}
3549
3550pub fn resolveLayout(ty: Type, zcu: *Zcu) SemaError!void {
3551 const ip = &zcu.intern_pool;
3552 switch (ip.indexToKey(ty.toIntern())) {
3553 .simple_type => |simple_type| return resolveSimpleType(simple_type, zcu),
3554 else => {},
3555 }
3556 switch (ty.zigTypeTag(zcu)) {
3557 .Struct => switch (ip.indexToKey(ty.toIntern())) {
3558 .anon_struct_type => |anon_struct_type| for (0..anon_struct_type.types.len) |i| {
3559 const field_ty = Type.fromInterned(anon_struct_type.types.get(ip)[i]);
3560 try field_ty.resolveLayout(zcu);
3561 },
3562 .struct_type => return ty.resolveStructInner(zcu, .layout),
3563 else => unreachable,
3564 },
3565 .Union => return ty.resolveUnionInner(zcu, .layout),
3566 .Array => {
3567 if (ty.arrayLenIncludingSentinel(zcu) == 0) return;
3568 const elem_ty = ty.childType(zcu);
3569 return elem_ty.resolveLayout(zcu);
3570 },
3571 .Optional => {
3572 const payload_ty = ty.optionalChild(zcu);
3573 return payload_ty.resolveLayout(zcu);
3574 },
3575 .ErrorUnion => {
3576 const payload_ty = ty.errorUnionPayload(zcu);
3577 return payload_ty.resolveLayout(zcu);
3578 },
3579 .Fn => {
3580 const info = zcu.typeToFunc(ty).?;
3581 if (info.is_generic) {
3582 // Resolving of generic function types is deferred to when
3583 // the function is instantiated.
3584 return;
3585 }
3586 for (0..info.param_types.len) |i| {
3587 const param_ty = info.param_types.get(ip)[i];
3588 try Type.fromInterned(param_ty).resolveLayout(zcu);
3589 }
3590 try Type.fromInterned(info.return_type).resolveLayout(zcu);
3591 },
3592 else => {},
3593 }
3594}
3595
3596pub fn resolveFields(ty: Type, zcu: *Zcu) SemaError!void {
3597 const ip = &zcu.intern_pool;
3598 const ty_ip = ty.toIntern();
3599
3600 switch (ty_ip) {
3601 .none => unreachable,
3602
3603 .u0_type,
3604 .i0_type,
3605 .u1_type,
3606 .u8_type,
3607 .i8_type,
3608 .u16_type,
3609 .i16_type,
3610 .u29_type,
3611 .u32_type,
3612 .i32_type,
3613 .u64_type,
3614 .i64_type,
3615 .u80_type,
3616 .u128_type,
3617 .i128_type,
3618 .usize_type,
3619 .isize_type,
3620 .c_char_type,
3621 .c_short_type,
3622 .c_ushort_type,
3623 .c_int_type,
3624 .c_uint_type,
3625 .c_long_type,
3626 .c_ulong_type,
3627 .c_longlong_type,
3628 .c_ulonglong_type,
3629 .c_longdouble_type,
3630 .f16_type,
3631 .f32_type,
3632 .f64_type,
3633 .f80_type,
3634 .f128_type,
3635 .anyopaque_type,
3636 .bool_type,
3637 .void_type,
3638 .type_type,
3639 .anyerror_type,
3640 .adhoc_inferred_error_set_type,
3641 .comptime_int_type,
3642 .comptime_float_type,
3643 .noreturn_type,
3644 .anyframe_type,
3645 .null_type,
3646 .undefined_type,
3647 .enum_literal_type,
3648 .manyptr_u8_type,
3649 .manyptr_const_u8_type,
3650 .manyptr_const_u8_sentinel_0_type,
3651 .single_const_pointer_to_comptime_int_type,
3652 .slice_const_u8_type,
3653 .slice_const_u8_sentinel_0_type,
3654 .optional_noreturn_type,
3655 .anyerror_void_error_union_type,
3656 .generic_poison_type,
3657 .empty_struct_type,
3658 => {},
3659
3660 .undef => unreachable,
3661 .zero => unreachable,
3662 .zero_usize => unreachable,
3663 .zero_u8 => unreachable,
3664 .one => unreachable,
3665 .one_usize => unreachable,
3666 .one_u8 => unreachable,
3667 .four_u8 => unreachable,
3668 .negative_one => unreachable,
3669 .calling_convention_c => unreachable,
3670 .calling_convention_inline => unreachable,
3671 .void_value => unreachable,
3672 .unreachable_value => unreachable,
3673 .null_value => unreachable,
3674 .bool_true => unreachable,
3675 .bool_false => unreachable,
3676 .empty_struct => unreachable,
3677 .generic_poison => unreachable,
3678
3679 else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
3680 .type_struct,
3681 .type_struct_packed,
3682 .type_struct_packed_inits,
3683 => return ty.resolveStructInner(zcu, .fields),
3684
3685 .type_union => return ty.resolveUnionInner(zcu, .fields),
3686
3687 .simple_type => return resolveSimpleType(ip.indexToKey(ty_ip).simple_type, zcu),
3688
3689 else => {},
3690 },
3691 }
3692}
3693
3694pub fn resolveFully(ty: Type, zcu: *Zcu) SemaError!void {
3695 const ip = &zcu.intern_pool;
3696
3697 switch (ip.indexToKey(ty.toIntern())) {
3698 .simple_type => |simple_type| return resolveSimpleType(simple_type, zcu),
3699 else => {},
3700 }
3701
3702 switch (ty.zigTypeTag(zcu)) {
3703 .Type,
3704 .Void,
3705 .Bool,
3706 .NoReturn,
3707 .Int,
3708 .Float,
3709 .ComptimeFloat,
3710 .ComptimeInt,
3711 .Undefined,
3712 .Null,
3713 .ErrorSet,
3714 .Enum,
3715 .Opaque,
3716 .Frame,
3717 .AnyFrame,
3718 .Vector,
3719 .EnumLiteral,
3720 => {},
3721
3722 .Pointer => return ty.childType(zcu).resolveFully(zcu),
3723 .Array => return ty.childType(zcu).resolveFully(zcu),
3724 .Optional => return ty.optionalChild(zcu).resolveFully(zcu),
3725 .ErrorUnion => return ty.errorUnionPayload(zcu).resolveFully(zcu),
3726 .Fn => {
3727 const info = zcu.typeToFunc(ty).?;
3728 if (info.is_generic) return;
3729 for (0..info.param_types.len) |i| {
3730 const param_ty = info.param_types.get(ip)[i];
3731 try Type.fromInterned(param_ty).resolveFully(zcu);
3732 }
3733 try Type.fromInterned(info.return_type).resolveFully(zcu);
3734 },
3735
3736 .Struct => switch (ip.indexToKey(ty.toIntern())) {
3737 .anon_struct_type => |anon_struct_type| for (0..anon_struct_type.types.len) |i| {
3738 const field_ty = Type.fromInterned(anon_struct_type.types.get(ip)[i]);
3739 try field_ty.resolveFully(zcu);
3740 },
3741 .struct_type => return ty.resolveStructInner(zcu, .full),
3742 else => unreachable,
3743 },
3744 .Union => return ty.resolveUnionInner(zcu, .full),
3745 }
3746}
3747
3748pub fn resolveStructFieldInits(ty: Type, zcu: *Zcu) SemaError!void {
3749 // TODO: stop calling this for tuples!
3750 _ = zcu.typeToStruct(ty) orelse return;
3751 return ty.resolveStructInner(zcu, .inits);
3752}
3753
3754pub fn resolveStructAlignment(ty: Type, zcu: *Zcu) SemaError!void {
3755 return ty.resolveStructInner(zcu, .alignment);
3756}
3757
3758pub fn resolveUnionAlignment(ty: Type, zcu: *Zcu) SemaError!void {
3759 return ty.resolveUnionInner(zcu, .alignment);
3760}
3761
3762/// `ty` must be a struct.
3763fn resolveStructInner(
3764 ty: Type,
3765 zcu: *Zcu,
3766 resolution: enum { fields, inits, alignment, layout, full },
3767) SemaError!void {
3768 const gpa = zcu.gpa;
3769
3770 const struct_obj = zcu.typeToStruct(ty).?;
3771 const owner_decl_index = struct_obj.decl.unwrap() orelse return;
3772
3773 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3774 defer analysis_arena.deinit();
3775
3776 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
3777 defer comptime_err_ret_trace.deinit();
3778
3779 var sema: Sema = .{
3780 .mod = zcu,
3781 .gpa = gpa,
3782 .arena = analysis_arena.allocator(),
3783 .code = undefined, // This ZIR will not be used.
3784 .owner_decl = zcu.declPtr(owner_decl_index),
3785 .owner_decl_index = owner_decl_index,
3786 .func_index = .none,
3787 .func_is_naked = false,
3788 .fn_ret_ty = Type.void,
3789 .fn_ret_ty_ies = null,
3790 .owner_func_index = .none,
3791 .comptime_err_ret_trace = &comptime_err_ret_trace,
3792 };
3793 defer sema.deinit();
3794
3795 switch (resolution) {
3796 .fields => return sema.resolveTypeFieldsStruct(ty.toIntern(), struct_obj),
3797 .inits => return sema.resolveStructFieldInits(ty),
3798 .alignment => return sema.resolveStructAlignment(ty.toIntern(), struct_obj),
3799 .layout => return sema.resolveStructLayout(ty),
3800 .full => return sema.resolveStructFully(ty),
3801 }
3802}
3803
3804/// `ty` must be a union.
3805fn resolveUnionInner(
3806 ty: Type,
3807 zcu: *Zcu,
3808 resolution: enum { fields, alignment, layout, full },
3809) SemaError!void {
3810 const gpa = zcu.gpa;
3811
3812 const union_obj = zcu.typeToUnion(ty).?;
3813 const owner_decl_index = union_obj.decl;
3814
3815 var analysis_arena = std.heap.ArenaAllocator.init(gpa);
3816 defer analysis_arena.deinit();
3817
3818 var comptime_err_ret_trace = std.ArrayList(Zcu.LazySrcLoc).init(gpa);
3819 defer comptime_err_ret_trace.deinit();
3820
3821 var sema: Sema = .{
3822 .mod = zcu,
3823 .gpa = gpa,
3824 .arena = analysis_arena.allocator(),
3825 .code = undefined, // This ZIR will not be used.
3826 .owner_decl = zcu.declPtr(owner_decl_index),
3827 .owner_decl_index = owner_decl_index,
3828 .func_index = .none,
3829 .func_is_naked = false,
3830 .fn_ret_ty = Type.void,
3831 .fn_ret_ty_ies = null,
3832 .owner_func_index = .none,
3833 .comptime_err_ret_trace = &comptime_err_ret_trace,
3834 };
3835 defer sema.deinit();
3836
3837 switch (resolution) {
3838 .fields => return sema.resolveTypeFieldsUnion(ty, union_obj),
3839 .alignment => return sema.resolveUnionAlignment(ty, union_obj),
3840 .layout => return sema.resolveUnionLayout(ty),
3841 .full => return sema.resolveUnionFully(ty),
3842 }
3843}
3844
3845/// Fully resolves a simple type. This is usually a nop, but for builtin types with
3846/// special InternPool indices (such as std.builtin.Type) it will analyze and fully
3847/// resolve the type.
3848fn resolveSimpleType(simple_type: InternPool.SimpleType, zcu: *Zcu) Allocator.Error!void {
3849 const builtin_type_name: []const u8 = switch (simple_type) {
3850 .atomic_order => "AtomicOrder",
3851 .atomic_rmw_op => "AtomicRmwOp",
3852 .calling_convention => "CallingConvention",
3853 .address_space => "AddressSpace",
3854 .float_mode => "FloatMode",
3855 .reduce_op => "ReduceOp",
3856 .call_modifier => "CallModifer",
3857 .prefetch_options => "PrefetchOptions",
3858 .export_options => "ExportOptions",
3859 .extern_options => "ExternOptions",
3860 .type_info => "Type",
3861 else => return,
3862 };
3863 // This will fully resolve the type.
3864 _ = try zcu.getBuiltinType(builtin_type_name);
3865}
3866
3867/// Returns the type of a pointer to an element.
3868/// Asserts that the type is a pointer, and that the element type is indexable.
3869/// If the element index is comptime-known, it must be passed in `offset`.
3870/// For *@Vector(n, T), return *align(a:b:h:v) T
3871/// For *[N]T, return *T
3872/// For [*]T, returns *T
3873/// For []T, returns *T
3874/// Handles const-ness and address spaces in particular.
3875/// This code is duplicated in `Sema.analyzePtrArithmetic`.
3876/// May perform type resolution and return a transitive `error.AnalysisFail`.
3877pub fn elemPtrType(ptr_ty: Type, offset: ?usize, zcu: *Zcu) !Type {
3878 const ptr_info = ptr_ty.ptrInfo(zcu);
3879 const elem_ty = ptr_ty.elemType2(zcu);
3880 const is_allowzero = ptr_info.flags.is_allowzero and (offset orelse 0) == 0;
3881 const parent_ty = ptr_ty.childType(zcu);
3882
3883 const VI = InternPool.Key.PtrType.VectorIndex;
3884
3885 const vector_info: struct {
3886 host_size: u16 = 0,
3887 alignment: Alignment = .none,
3888 vector_index: VI = .none,
3889 } = if (parent_ty.isVector(zcu) and ptr_info.flags.size == .One) blk: {
3890 const elem_bits = elem_ty.bitSize(zcu);
3891 if (elem_bits == 0) break :blk .{};
3892 const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);
3893 if (!is_packed) break :blk .{};
3894
3895 break :blk .{
3896 .host_size = @intCast(parent_ty.arrayLen(zcu)),
3897 .alignment = parent_ty.abiAlignment(zcu),
3898 .vector_index = if (offset) |some| @enumFromInt(some) else .runtime,
3899 };
3900 } else .{};
3901
3902 const alignment: Alignment = a: {
3903 // Calculate the new pointer alignment.
3904 if (ptr_info.flags.alignment == .none) {
3905 // In case of an ABI-aligned pointer, any pointer arithmetic
3906 // maintains the same ABI-alignedness.
3907 break :a vector_info.alignment;
3908 }
3909 // If the addend is not a comptime-known value we can still count on
3910 // it being a multiple of the type size.
3911 const elem_size = (try elem_ty.abiSizeAdvanced(zcu, .sema)).scalar;
3912 const addend = if (offset) |off| elem_size * off else elem_size;
3913
3914 // The resulting pointer is aligned to the lcd between the offset (an
3915 // arbitrary number) and the alignment factor (always a power of two,
3916 // non zero).
3917 const new_align: Alignment = @enumFromInt(@min(
3918 @ctz(addend),
3919 ptr_info.flags.alignment.toLog2Units(),
3920 ));
3921 assert(new_align != .none);
3922 break :a new_align;
3923 };
3924 return zcu.ptrTypeSema(.{
3925 .child = elem_ty.toIntern(),
3926 .flags = .{
3927 .alignment = alignment,
3928 .is_const = ptr_info.flags.is_const,
3929 .is_volatile = ptr_info.flags.is_volatile,
3930 .is_allowzero = is_allowzero,
3931 .address_space = ptr_info.flags.address_space,
3932 .vector_index = vector_info.vector_index,
3933 },
3934 .packed_offset = .{
3935 .host_size = vector_info.host_size,
3936 .bit_offset = 0,
3937 },
3938 });
3939}
3940
3941pub const @"u1": Type = .{ .ip_index = .u1_type };
3942pub const @"u8": Type = .{ .ip_index = .u8_type };
3943pub const @"u16": Type = .{ .ip_index = .u16_type };
3944pub const @"u29": Type = .{ .ip_index = .u29_type };
3945pub const @"u32": Type = .{ .ip_index = .u32_type };
3946pub const @"u64": Type = .{ .ip_index = .u64_type };
3947pub const @"u128": Type = .{ .ip_index = .u128_type };
3948
3949pub const @"i8": Type = .{ .ip_index = .i8_type };
3950pub const @"i16": Type = .{ .ip_index = .i16_type };
3951pub const @"i32": Type = .{ .ip_index = .i32_type };
3952pub const @"i64": Type = .{ .ip_index = .i64_type };
3953pub const @"i128": Type = .{ .ip_index = .i128_type };
3954
3955pub const @"f16": Type = .{ .ip_index = .f16_type };
3956pub const @"f32": Type = .{ .ip_index = .f32_type };
3957pub const @"f64": Type = .{ .ip_index = .f64_type };
3958pub const @"f80": Type = .{ .ip_index = .f80_type };
3959pub const @"f128": Type = .{ .ip_index = .f128_type };
3960
3961pub const @"bool": Type = .{ .ip_index = .bool_type };
3962pub const @"usize": Type = .{ .ip_index = .usize_type };
3963pub const @"isize": Type = .{ .ip_index = .isize_type };
3964pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type };
3965pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type };
3966pub const @"void": Type = .{ .ip_index = .void_type };
3967pub const @"type": Type = .{ .ip_index = .type_type };
3968pub const @"anyerror": Type = .{ .ip_index = .anyerror_type };
3969pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type };
3970pub const @"anyframe": Type = .{ .ip_index = .anyframe_type };
3971pub const @"null": Type = .{ .ip_index = .null_type };
3972pub const @"undefined": Type = .{ .ip_index = .undefined_type };
3973pub const @"noreturn": Type = .{ .ip_index = .noreturn_type };
3974
3975pub const @"c_char": Type = .{ .ip_index = .c_char_type };
3976pub const @"c_short": Type = .{ .ip_index = .c_short_type };
3977pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type };
3978pub const @"c_int": Type = .{ .ip_index = .c_int_type };
3979pub const @"c_uint": Type = .{ .ip_index = .c_uint_type };
3980pub const @"c_long": Type = .{ .ip_index = .c_long_type };
3981pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type };
3982pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type };
3983pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type };
3984pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type };
3985
3986pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type };
3987pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type };
3988pub const single_const_pointer_to_comptime_int: Type = .{
3989 .ip_index = .single_const_pointer_to_comptime_int_type,
3990};
3991pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type };
3992pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type };
3993
3994pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };
3995
3996pub fn smallestUnsignedBits(max: u64) u16 {
3997 if (max == 0) return 0;
3998 const base = std.math.log2(max);
3999 const upper = (@as(u64, 1) << @as(u6, @intCast(base))) - 1;
4000 return @as(u16, @intCast(base + @intFromBool(upper < max)));
4001}
4002
4003/// This is only used for comptime asserts. Bump this number when you make a change
4004/// to packed struct layout to find out all the places in the codebase you need to edit!
4005pub const packed_struct_layout_version = 2;
4006
4007fn cTypeAlign(target: Target, c_type: Target.CType) Alignment {
4008 return Alignment.fromByteUnits(target.c_type_alignment(c_type));
4009}
src/Value.zig+199-109
......@@ -1,6 +1,6 @@
11const std = @import("std");
22const builtin = @import("builtin");
3const Type = @import("type.zig").Type;
3const Type = @import("Type.zig");
44const assert = std.debug.assert;
55const BigIntConst = std.math.big.int.Const;
66const BigIntMutable = std.math.big.int.Mutable;
......@@ -161,9 +161,11 @@ pub fn intFromEnum(val: Value, ty: Type, mod: *Module) Allocator.Error!Value {
161161 };
162162}
163163
164pub const ResolveStrat = Type.ResolveStrat;
165
164166/// Asserts the value is an integer.
165167pub fn toBigInt(val: Value, space: *BigIntSpace, mod: *Module) BigIntConst {
166 return val.toBigIntAdvanced(space, mod, null) catch unreachable;
168 return val.toBigIntAdvanced(space, mod, .normal) catch unreachable;
167169}
168170
169171/// Asserts the value is an integer.
......@@ -171,7 +173,7 @@ pub fn toBigIntAdvanced(
171173 val: Value,
172174 space: *BigIntSpace,
173175 mod: *Module,
174 opt_sema: ?*Sema,
176 strat: ResolveStrat,
175177) Module.CompileError!BigIntConst {
176178 return switch (val.toIntern()) {
177179 .bool_false => BigIntMutable.init(&space.limbs, 0).toConst(),
......@@ -181,7 +183,7 @@ pub fn toBigIntAdvanced(
181183 .int => |int| switch (int.storage) {
182184 .u64, .i64, .big_int => int.storage.toBigInt(space),
183185 .lazy_align, .lazy_size => |ty| {
184 if (opt_sema) |sema| try sema.resolveTypeLayout(Type.fromInterned(ty));
186 if (strat == .sema) try Type.fromInterned(ty).resolveLayout(mod);
185187 const x = switch (int.storage) {
186188 else => unreachable,
187189 .lazy_align => Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
......@@ -190,10 +192,10 @@ pub fn toBigIntAdvanced(
190192 return BigIntMutable.init(&space.limbs, x).toConst();
191193 },
192194 },
193 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, mod, opt_sema),
195 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).toBigIntAdvanced(space, mod, strat),
194196 .opt, .ptr => BigIntMutable.init(
195197 &space.limbs,
196 (try val.getUnsignedIntAdvanced(mod, opt_sema)).?,
198 (try val.getUnsignedIntAdvanced(mod, strat)).?,
197199 ).toConst(),
198200 else => unreachable,
199201 },
......@@ -228,12 +230,12 @@ pub fn getVariable(val: Value, mod: *Module) ?InternPool.Key.Variable {
228230/// If the value fits in a u64, return it, otherwise null.
229231/// Asserts not undefined.
230232pub fn getUnsignedInt(val: Value, mod: *Module) ?u64 {
231 return getUnsignedIntAdvanced(val, mod, null) catch unreachable;
233 return getUnsignedIntAdvanced(val, mod, .normal) catch unreachable;
232234}
233235
234236/// If the value fits in a u64, return it, otherwise null.
235237/// Asserts not undefined.
236pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64 {
238pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, strat: ResolveStrat) !?u64 {
237239 return switch (val.toIntern()) {
238240 .undef => unreachable,
239241 .bool_false => 0,
......@@ -244,28 +246,22 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
244246 .big_int => |big_int| big_int.to(u64) catch null,
245247 .u64 => |x| x,
246248 .i64 => |x| std.math.cast(u64, x),
247 .lazy_align => |ty| if (opt_sema) |sema|
248 (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0
249 else
250 Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0,
251 .lazy_size => |ty| if (opt_sema) |sema|
252 (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar
253 else
254 Type.fromInterned(ty).abiSize(mod),
249 .lazy_align => |ty| (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, strat.toLazy())).scalar.toByteUnits() orelse 0,
250 .lazy_size => |ty| (try Type.fromInterned(ty).abiSizeAdvanced(mod, strat.toLazy())).scalar,
255251 },
256252 .ptr => |ptr| switch (ptr.base_addr) {
257253 .int => ptr.byte_offset,
258254 .field => |field| {
259 const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, opt_sema)) orelse return null;
255 const base_addr = (try Value.fromInterned(field.base).getUnsignedIntAdvanced(mod, strat)) orelse return null;
260256 const struct_ty = Value.fromInterned(field.base).typeOf(mod).childType(mod);
261 if (opt_sema) |sema| try sema.resolveTypeLayout(struct_ty);
257 if (strat == .sema) try struct_ty.resolveLayout(mod);
262258 return base_addr + struct_ty.structFieldOffset(@intCast(field.index), mod) + ptr.byte_offset;
263259 },
264260 else => null,
265261 },
266262 .opt => |opt| switch (opt.val) {
267263 .none => 0,
268 else => |payload| Value.fromInterned(payload).getUnsignedIntAdvanced(mod, opt_sema),
264 else => |payload| Value.fromInterned(payload).getUnsignedIntAdvanced(mod, strat),
269265 },
270266 else => null,
271267 },
......@@ -273,13 +269,13 @@ pub fn getUnsignedIntAdvanced(val: Value, mod: *Module, opt_sema: ?*Sema) !?u64
273269}
274270
275271/// Asserts the value is an integer and it fits in a u64
276pub fn toUnsignedInt(val: Value, mod: *Module) u64 {
277 return getUnsignedInt(val, mod).?;
272pub fn toUnsignedInt(val: Value, zcu: *Zcu) u64 {
273 return getUnsignedInt(val, zcu).?;
278274}
279275
280276/// Asserts the value is an integer and it fits in a u64
281pub fn toUnsignedIntAdvanced(val: Value, sema: *Sema) !u64 {
282 return (try getUnsignedIntAdvanced(val, sema.mod, sema)).?;
277pub fn toUnsignedIntSema(val: Value, zcu: *Zcu) !u64 {
278 return (try getUnsignedIntAdvanced(val, zcu, .sema)).?;
283279}
284280
285281/// Asserts the value is an integer and it fits in a i64
......@@ -1028,13 +1024,13 @@ pub fn floatHasFraction(self: Value, mod: *const Module) bool {
10281024}
10291025
10301026pub fn orderAgainstZero(lhs: Value, mod: *Module) std.math.Order {
1031 return orderAgainstZeroAdvanced(lhs, mod, null) catch unreachable;
1027 return orderAgainstZeroAdvanced(lhs, mod, .normal) catch unreachable;
10321028}
10331029
10341030pub fn orderAgainstZeroAdvanced(
10351031 lhs: Value,
10361032 mod: *Module,
1037 opt_sema: ?*Sema,
1033 strat: ResolveStrat,
10381034) Module.CompileError!std.math.Order {
10391035 return switch (lhs.toIntern()) {
10401036 .bool_false => .eq,
......@@ -1052,13 +1048,13 @@ pub fn orderAgainstZeroAdvanced(
10521048 .lazy_size => |ty| return if (Type.fromInterned(ty).hasRuntimeBitsAdvanced(
10531049 mod,
10541050 false,
1055 if (opt_sema) |sema| .{ .sema = sema } else .eager,
1051 strat.toLazy(),
10561052 ) catch |err| switch (err) {
10571053 error.NeedLazy => unreachable,
10581054 else => |e| return e,
10591055 }) .gt else .eq,
10601056 },
1061 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroAdvanced(mod, opt_sema),
1057 .enum_tag => |enum_tag| Value.fromInterned(enum_tag.int).orderAgainstZeroAdvanced(mod, strat),
10621058 .float => |float| switch (float.storage) {
10631059 inline else => |x| std.math.order(x, 0),
10641060 },
......@@ -1069,14 +1065,13 @@ pub fn orderAgainstZeroAdvanced(
10691065
10701066/// Asserts the value is comparable.
10711067pub fn order(lhs: Value, rhs: Value, mod: *Module) std.math.Order {
1072 return orderAdvanced(lhs, rhs, mod, null) catch unreachable;
1068 return orderAdvanced(lhs, rhs, mod, .normal) catch unreachable;
10731069}
10741070
10751071/// Asserts the value is comparable.
1076/// If opt_sema is null then this function asserts things are resolved and cannot fail.
1077pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, opt_sema: ?*Sema) !std.math.Order {
1078 const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(mod, opt_sema);
1079 const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(mod, opt_sema);
1072pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, strat: ResolveStrat) !std.math.Order {
1073 const lhs_against_zero = try lhs.orderAgainstZeroAdvanced(mod, strat);
1074 const rhs_against_zero = try rhs.orderAgainstZeroAdvanced(mod, strat);
10801075 switch (lhs_against_zero) {
10811076 .lt => if (rhs_against_zero != .lt) return .lt,
10821077 .eq => return rhs_against_zero.invert(),
......@@ -1096,15 +1091,15 @@ pub fn orderAdvanced(lhs: Value, rhs: Value, mod: *Module, opt_sema: ?*Sema) !st
10961091
10971092 var lhs_bigint_space: BigIntSpace = undefined;
10981093 var rhs_bigint_space: BigIntSpace = undefined;
1099 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, mod, opt_sema);
1100 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, mod, opt_sema);
1094 const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_bigint_space, mod, strat);
1095 const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_bigint_space, mod, strat);
11011096 return lhs_bigint.order(rhs_bigint);
11021097}
11031098
11041099/// Asserts the value is comparable. Does not take a type parameter because it supports
11051100/// comparisons between heterogeneous types.
11061101pub fn compareHetero(lhs: Value, op: std.math.CompareOperator, rhs: Value, mod: *Module) bool {
1107 return compareHeteroAdvanced(lhs, op, rhs, mod, null) catch unreachable;
1102 return compareHeteroAdvanced(lhs, op, rhs, mod, .normal) catch unreachable;
11081103}
11091104
11101105pub fn compareHeteroAdvanced(
......@@ -1112,7 +1107,7 @@ pub fn compareHeteroAdvanced(
11121107 op: std.math.CompareOperator,
11131108 rhs: Value,
11141109 mod: *Module,
1115 opt_sema: ?*Sema,
1110 strat: ResolveStrat,
11161111) !bool {
11171112 if (lhs.pointerDecl(mod)) |lhs_decl| {
11181113 if (rhs.pointerDecl(mod)) |rhs_decl| {
......@@ -1135,7 +1130,7 @@ pub fn compareHeteroAdvanced(
11351130 else => {},
11361131 }
11371132 }
1138 return (try orderAdvanced(lhs, rhs, mod, opt_sema)).compare(op);
1133 return (try orderAdvanced(lhs, rhs, mod, strat)).compare(op);
11391134}
11401135
11411136/// Asserts the values are comparable. Both operands have type `ty`.
......@@ -1176,22 +1171,22 @@ pub fn compareScalar(
11761171///
11771172/// Note that `!compareAllWithZero(.eq, ...) != compareAllWithZero(.neq, ...)`
11781173pub fn compareAllWithZero(lhs: Value, op: std.math.CompareOperator, mod: *Module) bool {
1179 return compareAllWithZeroAdvancedExtra(lhs, op, mod, null) catch unreachable;
1174 return compareAllWithZeroAdvancedExtra(lhs, op, mod, .normal) catch unreachable;
11801175}
11811176
1182pub fn compareAllWithZeroAdvanced(
1177pub fn compareAllWithZeroSema(
11831178 lhs: Value,
11841179 op: std.math.CompareOperator,
1185 sema: *Sema,
1180 zcu: *Zcu,
11861181) Module.CompileError!bool {
1187 return compareAllWithZeroAdvancedExtra(lhs, op, sema.mod, sema);
1182 return compareAllWithZeroAdvancedExtra(lhs, op, zcu, .sema);
11881183}
11891184
11901185pub fn compareAllWithZeroAdvancedExtra(
11911186 lhs: Value,
11921187 op: std.math.CompareOperator,
11931188 mod: *Module,
1194 opt_sema: ?*Sema,
1189 strat: ResolveStrat,
11951190) Module.CompileError!bool {
11961191 if (lhs.isInf(mod)) {
11971192 switch (op) {
......@@ -1211,14 +1206,14 @@ pub fn compareAllWithZeroAdvancedExtra(
12111206 if (!std.math.order(byte, 0).compare(op)) break false;
12121207 } else true,
12131208 .elems => |elems| for (elems) |elem| {
1214 if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema)) break false;
1209 if (!try Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, strat)) break false;
12151210 } else true,
1216 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, opt_sema),
1211 .repeated_elem => |elem| Value.fromInterned(elem).compareAllWithZeroAdvancedExtra(op, mod, strat),
12171212 },
12181213 .undef => return false,
12191214 else => {},
12201215 }
1221 return (try orderAgainstZeroAdvanced(lhs, mod, opt_sema)).compare(op);
1216 return (try orderAgainstZeroAdvanced(lhs, mod, strat)).compare(op);
12221217}
12231218
12241219pub fn eql(a: Value, b: Value, ty: Type, mod: *Module) bool {
......@@ -1279,9 +1274,9 @@ pub fn slicePtr(val: Value, mod: *Module) Value {
12791274}
12801275
12811276/// Gets the `len` field of a slice value as a `u64`.
1282/// Resolves the length using the provided `Sema` if necessary.
1283pub fn sliceLen(val: Value, sema: *Sema) !u64 {
1284 return Value.fromInterned(sema.mod.intern_pool.sliceLen(val.toIntern())).toUnsignedIntAdvanced(sema);
1277/// Resolves the length using `Sema` if necessary.
1278pub fn sliceLen(val: Value, zcu: *Zcu) !u64 {
1279 return Value.fromInterned(zcu.intern_pool.sliceLen(val.toIntern())).toUnsignedIntSema(zcu);
12851280}
12861281
12871282/// Asserts the value is an aggregate, and returns the element value at the given index.
......@@ -1482,29 +1477,29 @@ pub fn isFloat(self: Value, mod: *const Module) bool {
14821477}
14831478
14841479pub fn floatFromInt(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module) !Value {
1485 return floatFromIntAdvanced(val, arena, int_ty, float_ty, mod, null) catch |err| switch (err) {
1480 return floatFromIntAdvanced(val, arena, int_ty, float_ty, mod, .normal) catch |err| switch (err) {
14861481 error.OutOfMemory => return error.OutOfMemory,
14871482 else => unreachable,
14881483 };
14891484}
14901485
1491pub fn floatFromIntAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
1486pub fn floatFromIntAdvanced(val: Value, arena: Allocator, int_ty: Type, float_ty: Type, mod: *Module, strat: ResolveStrat) !Value {
14921487 if (int_ty.zigTypeTag(mod) == .Vector) {
14931488 const result_data = try arena.alloc(InternPool.Index, int_ty.vectorLen(mod));
14941489 const scalar_ty = float_ty.scalarType(mod);
14951490 for (result_data, 0..) |*scalar, i| {
14961491 const elem_val = try val.elemValue(mod, i);
1497 scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, mod, opt_sema)).toIntern();
1492 scalar.* = (try floatFromIntScalar(elem_val, scalar_ty, mod, strat)).toIntern();
14981493 }
14991494 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
15001495 .ty = float_ty.toIntern(),
15011496 .storage = .{ .elems = result_data },
15021497 } })));
15031498 }
1504 return floatFromIntScalar(val, float_ty, mod, opt_sema);
1499 return floatFromIntScalar(val, float_ty, mod, strat);
15051500}
15061501
1507pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*Sema) !Value {
1502pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, strat: ResolveStrat) !Value {
15081503 return switch (mod.intern_pool.indexToKey(val.toIntern())) {
15091504 .undef => try mod.undefValue(float_ty),
15101505 .int => |int| switch (int.storage) {
......@@ -1513,16 +1508,8 @@ pub fn floatFromIntScalar(val: Value, float_ty: Type, mod: *Module, opt_sema: ?*
15131508 return mod.floatValue(float_ty, float);
15141509 },
15151510 inline .u64, .i64 => |x| floatFromIntInner(x, float_ty, mod),
1516 .lazy_align => |ty| if (opt_sema) |sema| {
1517 return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar.toByteUnits() orelse 0, float_ty, mod);
1518 } else {
1519 return floatFromIntInner(Type.fromInterned(ty).abiAlignment(mod).toByteUnits() orelse 0, float_ty, mod);
1520 },
1521 .lazy_size => |ty| if (opt_sema) |sema| {
1522 return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar, float_ty, mod);
1523 } else {
1524 return floatFromIntInner(Type.fromInterned(ty).abiSize(mod), float_ty, mod);
1525 },
1511 .lazy_align => |ty| return floatFromIntInner((try Type.fromInterned(ty).abiAlignmentAdvanced(mod, strat.toLazy())).scalar.toByteUnits() orelse 0, float_ty, mod),
1512 .lazy_size => |ty| return floatFromIntInner((try Type.fromInterned(ty).abiSizeAdvanced(mod, strat.toLazy())).scalar, float_ty, mod),
15261513 },
15271514 else => unreachable,
15281515 };
......@@ -3616,17 +3603,15 @@ pub const RuntimeIndex = InternPool.RuntimeIndex;
36163603
36173604/// `parent_ptr` must be a single-pointer to some optional.
36183605/// Returns a pointer to the payload of the optional.
3619/// This takes a `Sema` because it may need to perform type resolution.
3620pub fn ptrOptPayload(parent_ptr: Value, sema: *Sema) !Value {
3621 const zcu = sema.mod;
3622
3606/// May perform type resolution.
3607pub fn ptrOptPayload(parent_ptr: Value, zcu: *Zcu) !Value {
36233608 const parent_ptr_ty = parent_ptr.typeOf(zcu);
36243609 const opt_ty = parent_ptr_ty.childType(zcu);
36253610
36263611 assert(parent_ptr_ty.ptrSize(zcu) == .One);
36273612 assert(opt_ty.zigTypeTag(zcu) == .Optional);
36283613
3629 const result_ty = try sema.ptrType(info: {
3614 const result_ty = try zcu.ptrTypeSema(info: {
36303615 var new = parent_ptr_ty.ptrInfo(zcu);
36313616 // We can correctly preserve alignment `.none`, since an optional has the same
36323617 // natural alignment as its child type.
......@@ -3651,17 +3636,15 @@ pub fn ptrOptPayload(parent_ptr: Value, sema: *Sema) !Value {
36513636
36523637/// `parent_ptr` must be a single-pointer to some error union.
36533638/// Returns a pointer to the payload of the error union.
3654/// This takes a `Sema` because it may need to perform type resolution.
3655pub fn ptrEuPayload(parent_ptr: Value, sema: *Sema) !Value {
3656 const zcu = sema.mod;
3657
3639/// May perform type resolution.
3640pub fn ptrEuPayload(parent_ptr: Value, zcu: *Zcu) !Value {
36583641 const parent_ptr_ty = parent_ptr.typeOf(zcu);
36593642 const eu_ty = parent_ptr_ty.childType(zcu);
36603643
36613644 assert(parent_ptr_ty.ptrSize(zcu) == .One);
36623645 assert(eu_ty.zigTypeTag(zcu) == .ErrorUnion);
36633646
3664 const result_ty = try sema.ptrType(info: {
3647 const result_ty = try zcu.ptrTypeSema(info: {
36653648 var new = parent_ptr_ty.ptrInfo(zcu);
36663649 // We can correctly preserve alignment `.none`, since an error union has a
36673650 // natural alignment greater than or equal to that of its payload type.
......@@ -3682,10 +3665,8 @@ pub fn ptrEuPayload(parent_ptr: Value, sema: *Sema) !Value {
36823665/// `parent_ptr` must be a single-pointer to a struct, union, or slice.
36833666/// Returns a pointer to the aggregate field at the specified index.
36843667/// For slices, uses `slice_ptr_index` and `slice_len_index`.
3685/// This takes a `Sema` because it may need to perform type resolution.
3686pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
3687 const zcu = sema.mod;
3688
3668/// May perform type resolution.
3669pub fn ptrField(parent_ptr: Value, field_idx: u32, zcu: *Zcu) !Value {
36893670 const parent_ptr_ty = parent_ptr.typeOf(zcu);
36903671 const aggregate_ty = parent_ptr_ty.childType(zcu);
36913672
......@@ -3698,17 +3679,17 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
36983679 .Struct => field: {
36993680 const field_ty = aggregate_ty.structFieldType(field_idx, zcu);
37003681 switch (aggregate_ty.containerLayout(zcu)) {
3701 .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) },
3682 .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, .sema) },
37023683 .@"extern" => {
37033684 // Well-defined layout, so just offset the pointer appropriately.
37043685 const byte_off = aggregate_ty.structFieldOffset(field_idx, zcu);
37053686 const field_align = a: {
37063687 const parent_align = if (parent_ptr_info.flags.alignment == .none) pa: {
3707 break :pa try sema.typeAbiAlignment(aggregate_ty);
3688 break :pa (try aggregate_ty.abiAlignmentAdvanced(zcu, .sema)).scalar;
37083689 } else parent_ptr_info.flags.alignment;
37093690 break :a InternPool.Alignment.fromLog2Units(@min(parent_align.toLog2Units(), @ctz(byte_off)));
37103691 };
3711 const result_ty = try sema.ptrType(info: {
3692 const result_ty = try zcu.ptrTypeSema(info: {
37123693 var new = parent_ptr_info;
37133694 new.child = field_ty.toIntern();
37143695 new.flags.alignment = field_align;
......@@ -3723,14 +3704,14 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
37233704 new.packed_offset = packed_offset;
37243705 new.child = field_ty.toIntern();
37253706 if (new.flags.alignment == .none) {
3726 new.flags.alignment = try sema.typeAbiAlignment(aggregate_ty);
3707 new.flags.alignment = (try aggregate_ty.abiAlignmentAdvanced(zcu, .sema)).scalar;
37273708 }
37283709 break :info new;
37293710 });
37303711 return zcu.getCoerced(parent_ptr, result_ty);
37313712 },
37323713 .byte_ptr => |ptr_info| {
3733 const result_ty = try sema.ptrType(info: {
3714 const result_ty = try zcu.ptrTypeSema(info: {
37343715 var new = parent_ptr_info;
37353716 new.child = field_ty.toIntern();
37363717 new.packed_offset = .{
......@@ -3749,10 +3730,10 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
37493730 const union_obj = zcu.typeToUnion(aggregate_ty).?;
37503731 const field_ty = Type.fromInterned(union_obj.field_types.get(&zcu.intern_pool)[field_idx]);
37513732 switch (aggregate_ty.containerLayout(zcu)) {
3752 .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, sema) },
3733 .auto => break :field .{ field_ty, try aggregate_ty.structFieldAlignAdvanced(@intCast(field_idx), zcu, .sema) },
37533734 .@"extern" => {
37543735 // Point to the same address.
3755 const result_ty = try sema.ptrType(info: {
3736 const result_ty = try zcu.ptrTypeSema(info: {
37563737 var new = parent_ptr_info;
37573738 new.child = field_ty.toIntern();
37583739 break :info new;
......@@ -3762,28 +3743,28 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
37623743 .@"packed" => {
37633744 // If the field has an ABI size matching its bit size, then we can continue to use a
37643745 // non-bit pointer if the parent pointer is also a non-bit pointer.
3765 if (parent_ptr_info.packed_offset.host_size == 0 and try sema.typeAbiSize(field_ty) * 8 == try field_ty.bitSizeAdvanced(zcu, sema)) {
3746 if (parent_ptr_info.packed_offset.host_size == 0 and (try field_ty.abiSizeAdvanced(zcu, .sema)).scalar * 8 == try field_ty.bitSizeAdvanced(zcu, .sema)) {
37663747 // We must offset the pointer on big-endian targets, since the bits of packed memory don't align nicely.
37673748 const byte_offset = switch (zcu.getTarget().cpu.arch.endian()) {
37683749 .little => 0,
3769 .big => try sema.typeAbiSize(aggregate_ty) - try sema.typeAbiSize(field_ty),
3750 .big => (try aggregate_ty.abiSizeAdvanced(zcu, .sema)).scalar - (try field_ty.abiSizeAdvanced(zcu, .sema)).scalar,
37703751 };
3771 const result_ty = try sema.ptrType(info: {
3752 const result_ty = try zcu.ptrTypeSema(info: {
37723753 var new = parent_ptr_info;
37733754 new.child = field_ty.toIntern();
37743755 new.flags.alignment = InternPool.Alignment.fromLog2Units(
3775 @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentAdvanced(zcu, sema)).toByteUnits().?),
3756 @ctz(byte_offset | (try parent_ptr_ty.ptrAlignmentAdvanced(zcu, .sema)).toByteUnits().?),
37763757 );
37773758 break :info new;
37783759 });
37793760 return parent_ptr.getOffsetPtr(byte_offset, result_ty, zcu);
37803761 } else {
37813762 // The result must be a bit-pointer if it is not already.
3782 const result_ty = try sema.ptrType(info: {
3763 const result_ty = try zcu.ptrTypeSema(info: {
37833764 var new = parent_ptr_info;
37843765 new.child = field_ty.toIntern();
37853766 if (new.packed_offset.host_size == 0) {
3786 new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeAdvanced(zcu, sema)) + 7) / 8);
3767 new.packed_offset.host_size = @intCast(((try aggregate_ty.bitSizeAdvanced(zcu, .sema)) + 7) / 8);
37873768 assert(new.packed_offset.bit_offset == 0);
37883769 }
37893770 break :info new;
......@@ -3805,14 +3786,14 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
38053786 };
38063787
38073788 const new_align: InternPool.Alignment = if (parent_ptr_info.flags.alignment != .none) a: {
3808 const ty_align = try sema.typeAbiAlignment(field_ty);
3789 const ty_align = (try field_ty.abiAlignmentAdvanced(zcu, .sema)).scalar;
38093790 const true_field_align = if (field_align == .none) ty_align else field_align;
38103791 const new_align = true_field_align.min(parent_ptr_info.flags.alignment);
38113792 if (new_align == ty_align) break :a .none;
38123793 break :a new_align;
38133794 } else field_align;
38143795
3815 const result_ty = try sema.ptrType(info: {
3796 const result_ty = try zcu.ptrTypeSema(info: {
38163797 var new = parent_ptr_info;
38173798 new.child = field_ty.toIntern();
38183799 new.flags.alignment = new_align;
......@@ -3834,10 +3815,8 @@ pub fn ptrField(parent_ptr: Value, field_idx: u32, sema: *Sema) !Value {
38343815
38353816/// `orig_parent_ptr` must be either a single-pointer to an array or vector, or a many-pointer or C-pointer or slice.
38363817/// Returns a pointer to the element at the specified index.
3837/// This takes a `Sema` because it may need to perform type resolution.
3838pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value {
3839 const zcu = sema.mod;
3840
3818/// May perform type resolution.
3819pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, zcu: *Zcu) !Value {
38413820 const parent_ptr = switch (orig_parent_ptr.typeOf(zcu).ptrSize(zcu)) {
38423821 .One, .Many, .C => orig_parent_ptr,
38433822 .Slice => orig_parent_ptr.slicePtr(zcu),
......@@ -3845,7 +3824,7 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value {
38453824
38463825 const parent_ptr_ty = parent_ptr.typeOf(zcu);
38473826 const elem_ty = parent_ptr_ty.childType(zcu);
3848 const result_ty = try sema.elemPtrType(parent_ptr_ty, @intCast(field_idx));
3827 const result_ty = try parent_ptr_ty.elemPtrType(@intCast(field_idx), zcu);
38493828
38503829 if (parent_ptr.isUndef(zcu)) return zcu.undefValue(result_ty);
38513830
......@@ -3862,21 +3841,21 @@ pub fn ptrElem(orig_parent_ptr: Value, field_idx: u64, sema: *Sema) !Value {
38623841
38633842 const strat: PtrStrat = switch (parent_ptr_ty.ptrSize(zcu)) {
38643843 .One => switch (elem_ty.zigTypeTag(zcu)) {
3865 .Vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeAdvanced(zcu, sema), 8) },
3844 .Vector => .{ .offset = field_idx * @divExact(try elem_ty.childType(zcu).bitSizeAdvanced(zcu, .sema), 8) },
38663845 .Array => strat: {
38673846 const arr_elem_ty = elem_ty.childType(zcu);
3868 if (try sema.typeRequiresComptime(arr_elem_ty)) {
3847 if (try arr_elem_ty.comptimeOnlyAdvanced(zcu, .sema)) {
38693848 break :strat .{ .elem_ptr = arr_elem_ty };
38703849 }
3871 break :strat .{ .offset = field_idx * try sema.typeAbiSize(arr_elem_ty) };
3850 break :strat .{ .offset = field_idx * (try arr_elem_ty.abiSizeAdvanced(zcu, .sema)).scalar };
38723851 },
38733852 else => unreachable,
38743853 },
38753854
3876 .Many, .C => if (try sema.typeRequiresComptime(elem_ty))
3855 .Many, .C => if (try elem_ty.comptimeOnlyAdvanced(zcu, .sema))
38773856 .{ .elem_ptr = elem_ty }
38783857 else
3879 .{ .offset = field_idx * try sema.typeAbiSize(elem_ty) },
3858 .{ .offset = field_idx * (try elem_ty.abiSizeAdvanced(zcu, .sema)).scalar },
38803859
38813860 .Slice => unreachable,
38823861 };
......@@ -4014,11 +3993,7 @@ pub const PointerDeriveStep = union(enum) {
40143993pub fn pointerDerivation(ptr_val: Value, arena: Allocator, zcu: *Zcu) Allocator.Error!PointerDeriveStep {
40153994 return ptr_val.pointerDerivationAdvanced(arena, zcu, null) catch |err| switch (err) {
40163995 error.OutOfMemory => |e| return e,
4017 error.AnalysisFail,
4018 error.GenericPoison,
4019 error.ComptimeReturn,
4020 error.ComptimeBreak,
4021 => unreachable,
3996 error.AnalysisFail => unreachable,
40223997 };
40233998}
40243999
......@@ -4087,8 +4062,8 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, zcu: *Zcu, op
40874062 const base_ptr_ty = base_ptr.typeOf(zcu);
40884063 const agg_ty = base_ptr_ty.childType(zcu);
40894064 const field_ty, const field_align = switch (agg_ty.zigTypeTag(zcu)) {
4090 .Struct => .{ agg_ty.structFieldType(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) },
4091 .Union => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, opt_sema) },
4065 .Struct => .{ agg_ty.structFieldType(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, .sema) },
4066 .Union => .{ agg_ty.unionFieldTypeByIndex(@intCast(field.index), zcu), try agg_ty.structFieldAlignAdvanced(@intCast(field.index), zcu, .sema) },
40924067 .Pointer => .{ switch (field.index) {
40934068 Value.slice_ptr_index => agg_ty.slicePtrFieldType(zcu),
40944069 Value.slice_len_index => Type.usize,
......@@ -4269,3 +4244,118 @@ pub fn pointerDerivationAdvanced(ptr_val: Value, arena: Allocator, zcu: *Zcu, op
42694244 .new_ptr_ty = Type.fromInterned(ptr.ty),
42704245 } };
42714246}
4247
4248pub fn resolveLazy(val: Value, arena: Allocator, zcu: *Zcu) Zcu.SemaError!Value {
4249 switch (zcu.intern_pool.indexToKey(val.toIntern())) {
4250 .int => |int| switch (int.storage) {
4251 .u64, .i64, .big_int => return val,
4252 .lazy_align, .lazy_size => return zcu.intValue(
4253 Type.fromInterned(int.ty),
4254 (try val.getUnsignedIntAdvanced(zcu, .sema)).?,
4255 ),
4256 },
4257 .slice => |slice| {
4258 const ptr = try Value.fromInterned(slice.ptr).resolveLazy(arena, zcu);
4259 const len = try Value.fromInterned(slice.len).resolveLazy(arena, zcu);
4260 if (ptr.toIntern() == slice.ptr and len.toIntern() == slice.len) return val;
4261 return Value.fromInterned(try zcu.intern(.{ .slice = .{
4262 .ty = slice.ty,
4263 .ptr = ptr.toIntern(),
4264 .len = len.toIntern(),
4265 } }));
4266 },
4267 .ptr => |ptr| {
4268 switch (ptr.base_addr) {
4269 .decl, .comptime_alloc, .anon_decl, .int => return val,
4270 .comptime_field => |field_val| {
4271 const resolved_field_val = (try Value.fromInterned(field_val).resolveLazy(arena, zcu)).toIntern();
4272 return if (resolved_field_val == field_val)
4273 val
4274 else
4275 Value.fromInterned((try zcu.intern(.{ .ptr = .{
4276 .ty = ptr.ty,
4277 .base_addr = .{ .comptime_field = resolved_field_val },
4278 .byte_offset = ptr.byte_offset,
4279 } })));
4280 },
4281 .eu_payload, .opt_payload => |base| {
4282 const resolved_base = (try Value.fromInterned(base).resolveLazy(arena, zcu)).toIntern();
4283 return if (resolved_base == base)
4284 val
4285 else
4286 Value.fromInterned((try zcu.intern(.{ .ptr = .{
4287 .ty = ptr.ty,
4288 .base_addr = switch (ptr.base_addr) {
4289 .eu_payload => .{ .eu_payload = resolved_base },
4290 .opt_payload => .{ .opt_payload = resolved_base },
4291 else => unreachable,
4292 },
4293 .byte_offset = ptr.byte_offset,
4294 } })));
4295 },
4296 .arr_elem, .field => |base_index| {
4297 const resolved_base = (try Value.fromInterned(base_index.base).resolveLazy(arena, zcu)).toIntern();
4298 return if (resolved_base == base_index.base)
4299 val
4300 else
4301 Value.fromInterned((try zcu.intern(.{ .ptr = .{
4302 .ty = ptr.ty,
4303 .base_addr = switch (ptr.base_addr) {
4304 .arr_elem => .{ .arr_elem = .{
4305 .base = resolved_base,
4306 .index = base_index.index,
4307 } },
4308 .field => .{ .field = .{
4309 .base = resolved_base,
4310 .index = base_index.index,
4311 } },
4312 else => unreachable,
4313 },
4314 .byte_offset = ptr.byte_offset,
4315 } })));
4316 },
4317 }
4318 },
4319 .aggregate => |aggregate| switch (aggregate.storage) {
4320 .bytes => return val,
4321 .elems => |elems| {
4322 var resolved_elems: []InternPool.Index = &.{};
4323 for (elems, 0..) |elem, i| {
4324 const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, zcu)).toIntern();
4325 if (resolved_elems.len == 0 and resolved_elem != elem) {
4326 resolved_elems = try arena.alloc(InternPool.Index, elems.len);
4327 @memcpy(resolved_elems[0..i], elems[0..i]);
4328 }
4329 if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem;
4330 }
4331 return if (resolved_elems.len == 0) val else Value.fromInterned((try zcu.intern(.{ .aggregate = .{
4332 .ty = aggregate.ty,
4333 .storage = .{ .elems = resolved_elems },
4334 } })));
4335 },
4336 .repeated_elem => |elem| {
4337 const resolved_elem = (try Value.fromInterned(elem).resolveLazy(arena, zcu)).toIntern();
4338 return if (resolved_elem == elem) val else Value.fromInterned((try zcu.intern(.{ .aggregate = .{
4339 .ty = aggregate.ty,
4340 .storage = .{ .repeated_elem = resolved_elem },
4341 } })));
4342 },
4343 },
4344 .un => |un| {
4345 const resolved_tag = if (un.tag == .none)
4346 .none
4347 else
4348 (try Value.fromInterned(un.tag).resolveLazy(arena, zcu)).toIntern();
4349 const resolved_val = (try Value.fromInterned(un.val).resolveLazy(arena, zcu)).toIntern();
4350 return if (resolved_tag == un.tag and resolved_val == un.val)
4351 val
4352 else
4353 Value.fromInterned((try zcu.intern(.{ .un = .{
4354 .ty = un.ty,
4355 .tag = resolved_tag,
4356 .val = resolved_val,
4357 } })));
4358 },
4359 else => return val,
4360 }
4361}
src/Zcu.zig+442-338
......@@ -20,7 +20,7 @@ const Zcu = @This();
2020const Compilation = @import("Compilation.zig");
2121const Cache = std.Build.Cache;
2222const Value = @import("Value.zig");
23const Type = @import("type.zig").Type;
23const Type = @import("Type.zig");
2424const Package = @import("Package.zig");
2525const link = @import("link.zig");
2626const Air = @import("Air.zig");
......@@ -35,6 +35,7 @@ const isUpDir = @import("introspect.zig").isUpDir;
3535const clang = @import("clang.zig");
3636const InternPool = @import("InternPool.zig");
3737const Alignment = InternPool.Alignment;
38const AnalUnit = InternPool.AnalUnit;
3839const BuiltinFn = std.zig.BuiltinFn;
3940const LlvmObject = @import("codegen/llvm.zig").Object;
4041
......@@ -71,18 +72,22 @@ codegen_prog_node: std.Progress.Node = undefined,
7172global_zir_cache: Compilation.Directory,
7273/// Used by AstGen worker to load and store ZIR cache.
7374local_zir_cache: Compilation.Directory,
74/// It's rare for a decl to be exported, so we save memory by having a sparse
75/// map of Decl indexes to details about them being exported.
76/// The Export memory is owned by the `export_owners` table; the slice itself
77/// is owned by this table. The slice is guaranteed to not be empty.
78decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
79/// Same as `decl_exports` but for exported constant values.
80value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(*Export)) = .{},
81/// This models the Decls that perform exports, so that `decl_exports` can be updated when a Decl
82/// is modified. Note that the key of this table is not the Decl being exported, but the Decl that
83/// is performing the export of another Decl.
84/// This table owns the Export memory.
85export_owners: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(*Export)) = .{},
75/// This is where all `Export` values are stored. Not all values here are necessarily valid exports;
76/// to enumerate all exports, `single_exports` and `multi_exports` must be consulted.
77all_exports: ArrayListUnmanaged(Export) = .{},
78/// This is a list of free indices in `all_exports`. These indices may be reused by exports from
79/// future semantic analysis.
80free_exports: ArrayListUnmanaged(u32) = .{},
81/// Maps from an `AnalUnit` which performs a single export, to the index into `all_exports` of
82/// the export it performs. Note that the key is not the `Decl` being exported, but the `AnalUnit`
83/// whose analysis triggered the export.
84single_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
85/// Like `single_exports`, but for `AnalUnit`s which perform multiple exports.
86/// The exports are `all_exports.items[index..][0..len]`.
87multi_exports: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
88 index: u32,
89 len: u32,
90}) = .{},
8691/// The set of all the Zig source files in the Module. We keep track of this in order
8792/// to iterate over it and check which source files have been modified on the file system when
8893/// an update is requested, as well as to cache `@import` results.
......@@ -103,15 +108,11 @@ embed_table: std.StringArrayHashMapUnmanaged(*EmbedFile) = .{},
103108/// is not yet implemented.
104109intern_pool: InternPool = .{},
105110
106/// We optimize memory usage for a compilation with no compile errors by storing the
107/// error messages and mapping outside of `Decl`.
108/// The ErrorMsg memory is owned by the decl, using Module's general purpose allocator.
109/// Note that a Decl can succeed but the Fn it represents can fail. In this case,
110/// a Decl can have a failed_decls entry but have analysis status of success.
111failed_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, *ErrorMsg) = .{},
112/// Keep track of one `@compileLog` callsite per owner Decl.
111/// The ErrorMsg memory is owned by the `AnalUnit`, using Module's general purpose allocator.
112failed_analysis: std.AutoArrayHashMapUnmanaged(AnalUnit, *ErrorMsg) = .{},
113/// Keep track of one `@compileLog` callsite per `AnalUnit`.
113114/// The value is the source location of the `@compileLog` call, convertible to a `LazySrcLoc`.
114compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {
115compile_log_sources: std.AutoArrayHashMapUnmanaged(AnalUnit, extern struct {
115116 base_node_inst: InternPool.TrackedInst.Index,
116117 node_offset: i32,
117118 pub fn src(self: @This()) LazySrcLoc {
......@@ -126,12 +127,11 @@ compile_log_decls: std.AutoArrayHashMapUnmanaged(Decl.Index, extern struct {
126127failed_files: std.AutoArrayHashMapUnmanaged(*File, ?*ErrorMsg) = .{},
127128/// The ErrorMsg memory is owned by the `EmbedFile`, using Module's general purpose allocator.
128129failed_embed_files: std.AutoArrayHashMapUnmanaged(*EmbedFile, *ErrorMsg) = .{},
129/// Using a map here for consistency with the other fields here.
130/// The ErrorMsg memory is owned by the `Export`, using Module's general purpose allocator.
131failed_exports: std.AutoArrayHashMapUnmanaged(*Export, *ErrorMsg) = .{},
132/// If a decl failed due to a cimport error, the corresponding Clang errors
130/// Key is index into `all_exports`.
131failed_exports: std.AutoArrayHashMapUnmanaged(u32, *ErrorMsg) = .{},
132/// If analysis failed due to a cimport error, the corresponding Clang errors
133133/// are stored here.
134cimport_errors: std.AutoArrayHashMapUnmanaged(Decl.Index, std.zig.ErrorBundle) = .{},
134cimport_errors: std.AutoArrayHashMapUnmanaged(AnalUnit, std.zig.ErrorBundle) = .{},
135135
136136/// Key is the error name, index is the error tag value. Index 0 has a length-0 string.
137137global_error_set: GlobalErrorSet = .{},
......@@ -139,26 +139,26 @@ global_error_set: GlobalErrorSet = .{},
139139/// Maximum amount of distinct error values, set by --error-limit
140140error_limit: ErrorInt,
141141
142/// Value is the number of PO or outdated Decls which this AnalSubject depends on.
143potentially_outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalSubject, u32) = .{},
144/// Value is the number of PO or outdated Decls which this AnalSubject depends on.
145/// Once this value drops to 0, the AnalSubject is a candidate for re-analysis.
146outdated: std.AutoArrayHashMapUnmanaged(InternPool.AnalSubject, u32) = .{},
147/// This contains all `AnalSubject`s in `outdated` whose PO dependency count is 0.
148/// Such `AnalSubject`s are ready for immediate re-analysis.
142/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
143potentially_outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
144/// Value is the number of PO or outdated Decls which this AnalUnit depends on.
145/// Once this value drops to 0, the AnalUnit is a candidate for re-analysis.
146outdated: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
147/// This contains all `AnalUnit`s in `outdated` whose PO dependency count is 0.
148/// Such `AnalUnit`s are ready for immediate re-analysis.
149149/// See `findOutdatedToAnalyze` for details.
150outdated_ready: std.AutoArrayHashMapUnmanaged(InternPool.AnalSubject, void) = .{},
150outdated_ready: std.AutoArrayHashMapUnmanaged(AnalUnit, void) = .{},
151151/// This contains a set of Decls which may not be in `outdated`, but are the
152152/// root Decls of files which have updated source and thus must be re-analyzed.
153153/// If such a Decl is only in this set, the struct type index may be preserved
154154/// (only the namespace might change). If such a Decl is also `outdated`, the
155155/// struct type index must be recreated.
156156outdated_file_root: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
157/// This contains a list of AnalSubject whose analysis or codegen failed, but the
157/// This contains a list of AnalUnit whose analysis or codegen failed, but the
158158/// failure was something like running out of disk space, and trying again may
159159/// succeed. On the next update, we will flush this list, marking all members of
160160/// it as outdated.
161retryable_failures: std.ArrayListUnmanaged(InternPool.AnalSubject) = .{},
161retryable_failures: std.ArrayListUnmanaged(AnalUnit) = .{},
162162
163163stage1_flags: packed struct {
164164 have_winmain: bool = false,
......@@ -176,12 +176,18 @@ emit_h: ?*GlobalEmitH,
176176
177177test_functions: std.AutoArrayHashMapUnmanaged(Decl.Index, void) = .{},
178178
179/// TODO: the key here will be a `Cau.Index`.
179180global_assembly: std.AutoArrayHashMapUnmanaged(Decl.Index, []u8) = .{},
180181
181reference_table: std.AutoHashMapUnmanaged(Decl.Index, struct {
182 referencer: Decl.Index,
183 src: LazySrcLoc,
184}) = .{},
182/// Key is the `AnalUnit` *performing* the reference. This representation allows
183/// incremental updates to quickly delete references caused by a specific `AnalUnit`.
184/// Value is index into `all_reference` of the first reference triggered by the unit.
185/// The `next` field on the `Reference` forms a linked list of all references
186/// triggered by the key `AnalUnit`.
187reference_table: std.AutoArrayHashMapUnmanaged(AnalUnit, u32) = .{},
188all_references: std.ArrayListUnmanaged(Reference) = .{},
189/// Freelist of indices in `all_references`.
190free_references: std.ArrayListUnmanaged(u32) = .{},
185191
186192panic_messages: [PanicId.len]Decl.OptionalIndex = .{.none} ** PanicId.len,
187193/// The panic function body.
......@@ -262,13 +268,25 @@ pub const Exported = union(enum) {
262268 decl_index: Decl.Index,
263269 /// Constant value being exported.
264270 value: InternPool.Index,
271
272 pub fn getValue(exported: Exported, zcu: *Zcu) Value {
273 return switch (exported) {
274 .decl_index => |decl_index| zcu.declPtr(decl_index).val,
275 .value => |value| Value.fromInterned(value),
276 };
277 }
278
279 pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment {
280 return switch (exported) {
281 .decl_index => |decl_index| zcu.declPtr(decl_index).alignment,
282 .value => .none,
283 };
284 }
265285};
266286
267287pub const Export = struct {
268288 opts: Options,
269289 src: LazySrcLoc,
270 /// The Decl that performs the export. Note that this is *not* the Decl being exported.
271 owner_decl: Decl.Index,
272290 exported: Exported,
273291 status: enum {
274292 in_progress,
......@@ -285,50 +303,16 @@ pub const Export = struct {
285303 section: InternPool.OptionalNullTerminatedString = .none,
286304 visibility: std.builtin.SymbolVisibility = .default,
287305 };
288
289 pub fn getSrcLoc(exp: Export, mod: *Module) SrcLoc {
290 return exp.src.upgrade(mod);
291 }
292306};
293307
294const ValueArena = struct {
295 state: std.heap.ArenaAllocator.State,
296 state_acquired: ?*std.heap.ArenaAllocator.State = null,
297
298 /// If this ValueArena replaced an existing one during re-analysis, this is the previous instance
299 prev: ?*ValueArena = null,
300
301 /// Returns an allocator backed by either promoting `state`, or by the existing ArenaAllocator
302 /// that has already promoted `state`. `out_arena_allocator` provides storage for the initial promotion,
303 /// and must live until the matching call to release().
304 pub fn acquire(self: *ValueArena, child_allocator: Allocator, out_arena_allocator: *std.heap.ArenaAllocator) Allocator {
305 if (self.state_acquired) |state_acquired| {
306 return @as(*std.heap.ArenaAllocator, @fieldParentPtr("state", state_acquired)).allocator();
307 }
308
309 out_arena_allocator.* = self.state.promote(child_allocator);
310 self.state_acquired = &out_arena_allocator.state;
311 return out_arena_allocator.allocator();
312 }
313
314 /// Releases the allocator acquired by `acquire. `arena_allocator` must match the one passed to `acquire`.
315 pub fn release(self: *ValueArena, arena_allocator: *std.heap.ArenaAllocator) void {
316 if (@as(*std.heap.ArenaAllocator, @fieldParentPtr("state", self.state_acquired.?)) == arena_allocator) {
317 self.state = self.state_acquired.?.*;
318 self.state_acquired = null;
319 }
320 }
321
322 pub fn deinit(self: ValueArena, child_allocator: Allocator) void {
323 assert(self.state_acquired == null);
324
325 const prev = self.prev;
326 self.state.promote(child_allocator).deinit();
327
328 if (prev) |p| {
329 p.deinit(child_allocator);
330 }
331 }
308pub const Reference = struct {
309 /// The `AnalUnit` whose semantic analysis was triggered by this reference.
310 referenced: AnalUnit,
311 /// Index into `all_references` of the next `Reference` triggered by the same `AnalUnit`.
312 /// `std.math.maxInt(u32)` is the sentinel.
313 next: u32,
314 /// The source location of the reference.
315 src: LazySrcLoc,
332316};
333317
334318pub const Decl = struct {
......@@ -369,9 +353,9 @@ pub const Decl = struct {
369353 /// successfully complete semantic analysis.
370354 dependency_failure,
371355 /// Semantic analysis failure.
372 /// There will be a corresponding ErrorMsg in Zcu.failed_decls.
356 /// There will be a corresponding ErrorMsg in Zcu.failed_analysis.
373357 sema_failure,
374 /// There will be a corresponding ErrorMsg in Zcu.failed_decls.
358 /// There will be a corresponding ErrorMsg in Zcu.failed_analysis.
375359 codegen_failure,
376360 /// Sematic analysis and constant value codegen of this Decl has
377361 /// succeeded. However, the Decl may be outdated due to an in-progress
......@@ -759,7 +743,7 @@ pub const File = struct {
759743 /// Whether this file is a part of multiple packages. This is an error condition which will be reported after AstGen.
760744 multi_pkg: bool = false,
761745 /// List of references to this file, used for multi-package errors.
762 references: std.ArrayListUnmanaged(Reference) = .{},
746 references: std.ArrayListUnmanaged(File.Reference) = .{},
763747 /// The hash of the path to this file, used to store `InternPool.TrackedInst`.
764748 path_digest: Cache.BinDigest,
765749
......@@ -772,7 +756,10 @@ pub const File = struct {
772756 /// A single reference to a file.
773757 pub const Reference = union(enum) {
774758 /// The file is imported directly (i.e. not as a package) with @import.
775 import: SrcLoc,
759 import: struct {
760 file: *File,
761 token: Ast.TokenIndex,
762 },
776763 /// The file is the root of a module.
777764 root: *Package.Module,
778765 };
......@@ -926,7 +913,7 @@ pub const File = struct {
926913 }
927914
928915 /// Add a reference to this file during AstGen.
929 pub fn addReference(file: *File, mod: Module, ref: Reference) !void {
916 pub fn addReference(file: *File, zcu: Zcu, ref: File.Reference) !void {
930917 // Don't add the same module root twice. Note that since we always add module roots at the
931918 // front of the references array (see below), this loop is actually O(1) on valid code.
932919 if (ref == .root) {
......@@ -943,17 +930,17 @@ pub const File = struct {
943930 // to make multi-module errors more helpful (since "root-of" notes are generally more
944931 // informative than "imported-from" notes). This path is hit very rarely, so the speed
945932 // of the insert operation doesn't matter too much.
946 .root => try file.references.insert(mod.gpa, 0, ref),
933 .root => try file.references.insert(zcu.gpa, 0, ref),
947934
948935 // Other references we'll just put at the end.
949 else => try file.references.append(mod.gpa, ref),
936 else => try file.references.append(zcu.gpa, ref),
950937 }
951938
952 const pkg = switch (ref) {
953 .import => |loc| loc.file_scope.mod,
954 .root => |pkg| pkg,
939 const mod = switch (ref) {
940 .import => |import| import.file.mod,
941 .root => |mod| mod,
955942 };
956 if (pkg != file.mod) file.multi_pkg = true;
943 if (mod != file.mod) file.multi_pkg = true;
957944 }
958945
959946 /// Mark this file and every file referenced by it as multi_pkg and report an
......@@ -993,36 +980,25 @@ pub const EmbedFile = struct {
993980 owner: *Package.Module,
994981 stat: Cache.File.Stat,
995982 val: InternPool.Index,
996 src_loc: SrcLoc,
983 src_loc: LazySrcLoc,
997984};
998985
999986/// This struct holds data necessary to construct API-facing `AllErrors.Message`.
1000987/// Its memory is managed with the general purpose allocator so that they
1001988/// can be created and destroyed in response to incremental updates.
1002/// In some cases, the File could have been inferred from where the ErrorMsg
1003/// is stored. For example, if it is stored in Module.failed_decls, then the File
1004/// would be determined by the Decl Scope. However, the data structure contains the field
1005/// anyway so that `ErrorMsg` can be reused for error notes, which may be in a different
1006/// file than the parent error message. It also simplifies processing of error messages.
1007989pub const ErrorMsg = struct {
1008 src_loc: SrcLoc,
990 src_loc: LazySrcLoc,
1009991 msg: []const u8,
1010992 notes: []ErrorMsg = &.{},
1011 reference_trace: []Trace = &.{},
1012 hidden_references: u32 = 0,
1013
1014 pub const Trace = struct {
1015 decl: InternPool.NullTerminatedString,
1016 src_loc: SrcLoc,
1017 };
993 reference_trace_root: AnalUnit.Optional = .none,
1018994
1019995 pub fn create(
1020996 gpa: Allocator,
1021 src_loc: SrcLoc,
997 src_loc: LazySrcLoc,
1022998 comptime format: []const u8,
1023999 args: anytype,
10241000 ) !*ErrorMsg {
1025 assert(src_loc.lazy != .unneeded);
1001 assert(src_loc.offset != .unneeded);
10261002 const err_msg = try gpa.create(ErrorMsg);
10271003 errdefer gpa.destroy(err_msg);
10281004 err_msg.* = try ErrorMsg.init(gpa, src_loc, format, args);
......@@ -1038,7 +1014,7 @@ pub const ErrorMsg = struct {
10381014
10391015 pub fn init(
10401016 gpa: Allocator,
1041 src_loc: SrcLoc,
1017 src_loc: LazySrcLoc,
10421018 comptime format: []const u8,
10431019 args: anytype,
10441020 ) !ErrorMsg {
......@@ -1054,7 +1030,6 @@ pub const ErrorMsg = struct {
10541030 }
10551031 gpa.free(err_msg.notes);
10561032 gpa.free(err_msg.msg);
1057 gpa.free(err_msg.reference_trace);
10581033 err_msg.* = undefined;
10591034 }
10601035};
......@@ -2027,15 +2002,12 @@ pub const LazySrcLoc = struct {
20272002 entire_file,
20282003 /// The source location points to a byte offset within a source file,
20292004 /// offset from 0. The source file is determined contextually.
2030 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
20312005 byte_abs: u32,
20322006 /// The source location points to a token within a source file,
20332007 /// offset from 0. The source file is determined contextually.
2034 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
20352008 token_abs: u32,
20362009 /// The source location points to an AST node within a source file,
20372010 /// offset from 0. The source file is determined contextually.
2038 /// Inside a `SrcLoc`, the `file_scope` union field will be active.
20392011 node_abs: u32,
20402012 /// The source location points to a byte offset within a source file,
20412013 /// offset from the byte offset of the base node within the file.
......@@ -2406,8 +2378,7 @@ pub const LazySrcLoc = struct {
24062378 }
24072379
24082380 /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`.
2409 /// TODO: it is incorrect to store a `SrcLoc` anywhere due to incremental compilation.
2410 /// Probably the type should be removed entirely and this resolution performed on-the-fly when needed.
2381 /// The resulting `SrcLoc` should only be used ephemerally, as it is not correct across incremental updates.
24112382 pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc {
24122383 const file, const base_node = resolveBaseNode(lazy.base_node_inst, zcu);
24132384 return .{
......@@ -2452,8 +2423,6 @@ pub fn deinit(zcu: *Zcu) void {
24522423 for (zcu.import_table.keys()) |key| {
24532424 gpa.free(key);
24542425 }
2455 var failed_decls = zcu.failed_decls;
2456 zcu.failed_decls = .{};
24572426 for (zcu.import_table.values()) |value| {
24582427 value.destroy(zcu);
24592428 }
......@@ -2471,10 +2440,10 @@ pub fn deinit(zcu: *Zcu) void {
24712440 zcu.local_zir_cache.handle.close();
24722441 zcu.global_zir_cache.handle.close();
24732442
2474 for (failed_decls.values()) |value| {
2443 for (zcu.failed_analysis.values()) |value| {
24752444 value.destroy(gpa);
24762445 }
2477 failed_decls.deinit(gpa);
2446 zcu.failed_analysis.deinit(gpa);
24782447
24792448 if (zcu.emit_h) |emit_h| {
24802449 for (emit_h.failed_decls.values()) |value| {
......@@ -2505,22 +2474,12 @@ pub fn deinit(zcu: *Zcu) void {
25052474 }
25062475 zcu.cimport_errors.deinit(gpa);
25072476
2508 zcu.compile_log_decls.deinit(gpa);
2477 zcu.compile_log_sources.deinit(gpa);
25092478
2510 for (zcu.decl_exports.values()) |*export_list| {
2511 export_list.deinit(gpa);
2512 }
2513 zcu.decl_exports.deinit(gpa);
2514
2515 for (zcu.value_exports.values()) |*export_list| {
2516 export_list.deinit(gpa);
2517 }
2518 zcu.value_exports.deinit(gpa);
2519
2520 for (zcu.export_owners.values()) |*value| {
2521 freeExportList(gpa, value);
2522 }
2523 zcu.export_owners.deinit(gpa);
2479 zcu.all_exports.deinit(gpa);
2480 zcu.free_exports.deinit(gpa);
2481 zcu.single_exports.deinit(gpa);
2482 zcu.multi_exports.deinit(gpa);
25242483
25252484 zcu.global_error_set.deinit(gpa);
25262485
......@@ -2538,6 +2497,8 @@ pub fn deinit(zcu: *Zcu) void {
25382497 zcu.global_assembly.deinit(gpa);
25392498
25402499 zcu.reference_table.deinit(gpa);
2500 zcu.all_references.deinit(gpa);
2501 zcu.free_references.deinit(gpa);
25412502
25422503 {
25432504 var it = zcu.intern_pool.allocated_namespaces.iterator(0);
......@@ -2590,11 +2551,6 @@ pub fn declIsRoot(mod: *Module, decl_index: Decl.Index) bool {
25902551 return decl_index == namespace.decl_index;
25912552}
25922553
2593fn freeExportList(gpa: Allocator, export_list: *ArrayListUnmanaged(*Export)) void {
2594 for (export_list.items) |exp| gpa.destroy(exp);
2595 export_list.deinit(gpa);
2596}
2597
25982554// TODO https://github.com/ziglang/zig/issues/8643
25992555const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8;
26002556const HackDataLayout = extern struct {
......@@ -3137,9 +3093,9 @@ fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
31373093 }
31383094}
31393095
3140/// Given a AnalSubject which is newly outdated or PO, mark all AnalSubjects which may
3141/// in turn be PO, due to a dependency on the original AnalSubject's tyval or IES.
3142fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternPool.AnalSubject) !void {
3096/// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may
3097/// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES.
3098fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) !void {
31433099 var it = zcu.intern_pool.dependencyIterator(switch (maybe_outdated.unwrap()) {
31443100 .decl => |decl_index| .{ .decl_val = decl_index }, // TODO: also `decl_ref` deps when introduced
31453101 .func => |func_index| .{ .func_ies = func_index },
......@@ -3161,12 +3117,12 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: InternP
31613117 continue;
31623118 }
31633119 try zcu.potentially_outdated.putNoClobber(zcu.gpa, po, 1);
3164 // This AnalSubject was not already PO, so we must recursively mark its dependers as also PO.
3120 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO.
31653121 try zcu.markTransitiveDependersPotentiallyOutdated(po);
31663122 }
31673123}
31683124
3169pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalSubject {
3125pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
31703126 if (!zcu.comp.debug_incremental) return null;
31713127
31723128 if (zcu.outdated.count() == 0 and zcu.potentially_outdated.count() == 0) {
......@@ -3174,8 +3130,8 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalSubject
31743130 return null;
31753131 }
31763132
3177 // Our goal is to find an outdated AnalSubject which itself has no outdated or
3178 // PO dependencies. Most of the time, such an AnalSubject will exist - we track
3133 // Our goal is to find an outdated AnalUnit which itself has no outdated or
3134 // PO dependencies. Most of the time, such an AnalUnit will exist - we track
31793135 // them in the `outdated_ready` set for efficiency. However, this is not
31803136 // necessarily the case, since the Decl dependency graph may contain loops
31813137 // via mutually recursive definitions:
......@@ -3197,7 +3153,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalSubject
31973153 // `outdated`. This set will be small (number of files changed in this
31983154 // update), so it's alright for us to just iterate here.
31993155 for (zcu.outdated_file_root.keys()) |file_decl| {
3200 const decl_depender = InternPool.AnalSubject.wrap(.{ .decl = file_decl });
3156 const decl_depender = AnalUnit.wrap(.{ .decl = file_decl });
32013157 if (zcu.outdated.contains(decl_depender)) {
32023158 // Since we didn't hit this in the first loop, this Decl must have
32033159 // pending dependencies, so is ineligible.
......@@ -3213,7 +3169,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalSubject
32133169 return decl_depender;
32143170 }
32153171
3216 // There is no single AnalSubject which is ready for re-analysis. Instead, we
3172 // There is no single AnalUnit which is ready for re-analysis. Instead, we
32173173 // must assume that some Decl with PO dependencies is outdated - e.g. in the
32183174 // above example we arbitrarily pick one of A or B. We should select a Decl,
32193175 // since a Decl is definitely responsible for the loop in the dependency
......@@ -3221,7 +3177,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalSubject
32213177
32223178 // The choice of this Decl could have a big impact on how much total
32233179 // analysis we perform, since if analysis concludes its tyval is unchanged,
3224 // then other PO AnalSubject may be resolved as up-to-date. To hopefully avoid
3180 // then other PO AnalUnit may be resolved as up-to-date. To hopefully avoid
32253181 // doing too much work, let's find a Decl which the most things depend on -
32263182 // the idea is that this will resolve a lot of loops (but this is only a
32273183 // heuristic).
......@@ -3271,7 +3227,7 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?InternPool.AnalSubject
32713227 chosen_decl_dependers,
32723228 });
32733229
3274 return InternPool.AnalSubject.wrap(.{ .decl = chosen_decl_idx.? });
3230 return AnalUnit.wrap(.{ .decl = chosen_decl_idx.? });
32753231}
32763232
32773233/// During an incremental update, before semantic analysis, call this to flush all values from
......@@ -3281,12 +3237,12 @@ pub fn flushRetryableFailures(zcu: *Zcu) !void {
32813237 for (zcu.retryable_failures.items) |depender| {
32823238 if (zcu.outdated.contains(depender)) continue;
32833239 if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| {
3284 // This AnalSubject was already PO, but we now consider it outdated.
3240 // This AnalUnit was already PO, but we now consider it outdated.
32853241 // Any transitive dependencies are already marked PO.
32863242 try zcu.outdated.put(gpa, depender, kv.value);
32873243 continue;
32883244 }
3289 // This AnalSubject was not marked PO, but is now outdated. Mark it as
3245 // This AnalUnit was not marked PO, but is now outdated. Mark it as
32903246 // such, then recursively mark transitive dependencies as PO.
32913247 try zcu.outdated.put(gpa, depender, 0);
32923248 try zcu.markTransitiveDependersPotentiallyOutdated(depender);
......@@ -3456,7 +3412,7 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
34563412 // which tries to limit re-analysis to Decls whose previously listed
34573413 // dependencies are all up-to-date.
34583414
3459 const decl_as_depender = InternPool.AnalSubject.wrap(.{ .decl = decl_index });
3415 const decl_as_depender = AnalUnit.wrap(.{ .decl = decl_index });
34603416 const decl_was_outdated = mod.outdated.swapRemove(decl_as_depender) or
34613417 mod.potentially_outdated.swapRemove(decl_as_depender);
34623418
......@@ -3485,7 +3441,8 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
34853441 // The exports this Decl performs will be re-discovered, so we remove them here
34863442 // prior to re-analysis.
34873443 if (build_options.only_c) unreachable;
3488 try mod.deleteDeclExports(decl_index);
3444 mod.deleteUnitExports(decl_as_depender);
3445 mod.deleteUnitReferences(decl_as_depender);
34893446 }
34903447
34913448 const sema_result: SemaDeclResult = blk: {
......@@ -3521,11 +3478,11 @@ pub fn ensureDeclAnalyzed(mod: *Module, decl_index: Decl.Index) SemaError!void {
35213478 error.GenericPoison => unreachable,
35223479 else => |e| {
35233480 decl.analysis = .sema_failure;
3524 try mod.failed_decls.ensureUnusedCapacity(mod.gpa, 1);
3525 try mod.retryable_failures.append(mod.gpa, InternPool.AnalSubject.wrap(.{ .decl = decl_index }));
3526 mod.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
3481 try mod.failed_analysis.ensureUnusedCapacity(mod.gpa, 1);
3482 try mod.retryable_failures.append(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
3483 mod.failed_analysis.putAssumeCapacityNoClobber(AnalUnit.wrap(.{ .decl = decl_index }), try ErrorMsg.create(
35273484 mod.gpa,
3528 decl.navSrcLoc(mod).upgrade(mod),
3485 decl.navSrcLoc(mod),
35293486 "unable to analyze: {s}",
35303487 .{@errorName(e)},
35313488 ));
......@@ -3581,7 +3538,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
35813538 // that's the case, we should remove this function from the binary.
35823539 if (decl.val.ip_index != func_index) {
35833540 try zcu.markDependeeOutdated(.{ .func_ies = func_index });
3584 ip.removeDependenciesForDepender(gpa, InternPool.AnalSubject.wrap(.{ .func = func_index }));
3541 ip.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
35853542 ip.remove(func_index);
35863543 @panic("TODO: remove orphaned function from binary");
35873544 }
......@@ -3607,12 +3564,15 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
36073564 .complete => {},
36083565 }
36093566
3610 const func_as_depender = InternPool.AnalSubject.wrap(.{ .func = func_index });
3567 const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
36113568 const was_outdated = zcu.outdated.swapRemove(func_as_depender) or
36123569 zcu.potentially_outdated.swapRemove(func_as_depender);
36133570
36143571 if (was_outdated) {
3572 if (build_options.only_c) unreachable;
36153573 _ = zcu.outdated_ready.swapRemove(func_as_depender);
3574 zcu.deleteUnitExports(func_as_depender);
3575 zcu.deleteUnitReferences(func_as_depender);
36163576 }
36173577
36183578 switch (func.analysis(ip).state) {
......@@ -3647,7 +3607,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
36473607 },
36483608 error.OutOfMemory => return error.OutOfMemory,
36493609 };
3650 defer air.deinit(gpa);
3610 errdefer air.deinit(gpa);
36513611
36523612 const invalidate_ies_deps = i: {
36533613 if (!was_outdated) break :i false;
......@@ -3669,13 +3629,36 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
36693629 const dump_llvm_ir = build_options.enable_debug_extensions and (comp.verbose_llvm_ir != null or comp.verbose_llvm_bc != null);
36703630
36713631 if (comp.bin_file == null and zcu.llvm_object == null and !dump_air and !dump_llvm_ir) {
3632 air.deinit(gpa);
36723633 return;
36733634 }
36743635
3636 try comp.work_queue.writeItem(.{ .codegen_func = .{
3637 .func = func_index,
3638 .air = air,
3639 } });
3640}
3641
3642/// Takes ownership of `air`, even on error.
3643/// If any types referenced by `air` are unresolved, marks the codegen as failed.
3644pub fn linkerUpdateFunc(zcu: *Zcu, func_index: InternPool.Index, air: Air) Allocator.Error!void {
3645 const gpa = zcu.gpa;
3646 const ip = &zcu.intern_pool;
3647 const comp = zcu.comp;
3648
3649 defer {
3650 var air_mut = air;
3651 air_mut.deinit(gpa);
3652 }
3653
3654 const func = zcu.funcInfo(func_index);
3655 const decl_index = func.owner_decl;
3656 const decl = zcu.declPtr(decl_index);
3657
36753658 var liveness = try Liveness.analyze(gpa, air, ip);
36763659 defer liveness.deinit(gpa);
36773660
3678 if (dump_air) {
3661 if (build_options.enable_debug_extensions and comp.verbose_air) {
36793662 const fqn = try decl.fullyQualifiedName(zcu);
36803663 std.debug.print("# Begin Function AIR: {}:\n", .{fqn.fmt(ip)});
36813664 @import("print_air.zig").dump(zcu, air, liveness);
......@@ -3683,7 +3666,7 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
36833666 }
36843667
36853668 if (std.debug.runtime_safety) {
3686 var verify = Liveness.Verify{
3669 var verify: Liveness.Verify = .{
36873670 .gpa = gpa,
36883671 .air = air,
36893672 .liveness = liveness,
......@@ -3694,12 +3677,12 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
36943677 verify.verify() catch |err| switch (err) {
36953678 error.OutOfMemory => return error.OutOfMemory,
36963679 else => {
3697 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3698 zcu.failed_decls.putAssumeCapacityNoClobber(
3699 decl_index,
3680 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
3681 zcu.failed_analysis.putAssumeCapacityNoClobber(
3682 AnalUnit.wrap(.{ .func = func_index }),
37003683 try Module.ErrorMsg.create(
37013684 gpa,
3702 decl.navSrcLoc(zcu).upgrade(zcu),
3685 decl.navSrcLoc(zcu),
37033686 "invalid liveness: {s}",
37043687 .{@errorName(err)},
37053688 ),
......@@ -3713,31 +3696,34 @@ pub fn ensureFuncBodyAnalyzed(zcu: *Zcu, maybe_coerced_func_index: InternPool.In
37133696 const codegen_prog_node = zcu.codegen_prog_node.start((try decl.fullyQualifiedName(zcu)).toSlice(ip), 0);
37143697 defer codegen_prog_node.end();
37153698
3716 if (comp.bin_file) |lf| {
3699 if (!air.typesFullyResolved(zcu)) {
3700 // A type we depend on failed to resolve. This is a transitive failure.
3701 // Correcting this failure will involve changing a type this function
3702 // depends on, hence triggering re-analysis of this function, so this
3703 // interacts correctly with incremental compilation.
3704 func.analysis(ip).state = .codegen_failure;
3705 } else if (comp.bin_file) |lf| {
37173706 lf.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
37183707 error.OutOfMemory => return error.OutOfMemory,
37193708 error.AnalysisFail => {
37203709 func.analysis(ip).state = .codegen_failure;
37213710 },
37223711 else => {
3723 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
3724 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try Module.ErrorMsg.create(
3712 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
3713 zcu.failed_analysis.putAssumeCapacityNoClobber(AnalUnit.wrap(.{ .func = func_index }), try Module.ErrorMsg.create(
37253714 gpa,
3726 decl.navSrcLoc(zcu).upgrade(zcu),
3715 decl.navSrcLoc(zcu),
37273716 "unable to codegen: {s}",
37283717 .{@errorName(err)},
37293718 ));
37303719 func.analysis(ip).state = .codegen_failure;
3731 try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalSubject.wrap(.{ .func = func_index }));
3720 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .func = func_index }));
37323721 },
37333722 };
37343723 } else if (zcu.llvm_object) |llvm_object| {
37353724 if (build_options.only_c) unreachable;
37363725 llvm_object.updateFunc(zcu, func_index, air, liveness) catch |err| switch (err) {
37373726 error.OutOfMemory => return error.OutOfMemory,
3738 error.AnalysisFail => {
3739 func.analysis(ip).state = .codegen_failure;
3740 },
37413727 };
37423728 }
37433729}
......@@ -3773,7 +3759,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
37733759
37743760 assert(decl.has_tv);
37753761
3776 const func_as_depender = InternPool.AnalSubject.wrap(.{ .func = func_index });
3762 const func_as_depender = AnalUnit.wrap(.{ .func = func_index });
37773763 const is_outdated = mod.outdated.contains(func_as_depender) or
37783764 mod.potentially_outdated.contains(func_as_depender);
37793765
......@@ -3792,7 +3778,7 @@ pub fn ensureFuncBodyAnalysisQueued(mod: *Module, func_index: InternPool.Index)
37923778
37933779 // Decl itself is safely analyzed, and body analysis is not yet queued
37943780
3795 try mod.comp.work_queue.writeItem(.{ .codegen_func = func_index });
3781 try mod.comp.work_queue.writeItem(.{ .analyze_func = func_index });
37963782 if (mod.emit_h != null) {
37973783 // TODO: we ideally only want to do this if the function's type changed
37983784 // since the last update
......@@ -3857,7 +3843,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
38573843 if (zcu.comp.debug_incremental) {
38583844 try ip.addDependency(
38593845 gpa,
3860 InternPool.AnalSubject.wrap(.{ .decl = decl_index }),
3846 AnalUnit.wrap(.{ .decl = decl_index }),
38613847 .{ .src_hash = tracked_inst },
38623848 );
38633849 }
......@@ -3869,7 +3855,7 @@ fn getFileRootStruct(zcu: *Zcu, decl_index: Decl.Index, namespace_index: Namespa
38693855 decl.analysis = .complete;
38703856
38713857 try zcu.scanNamespace(namespace_index, decls, decl);
3872
3858 try zcu.comp.work_queue.writeItem(.{ .resolve_type_fully = wip_ty.index });
38733859 return wip_ty.finish(ip, decl_index, namespace_index.toOptional());
38743860}
38753861
......@@ -3906,7 +3892,7 @@ fn semaFileUpdate(zcu: *Zcu, file: *File, type_outdated: bool) SemaError!bool {
39063892
39073893 if (type_outdated) {
39083894 // Invalidate the existing type, reusing the decl and namespace.
3909 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalSubject.wrap(.{ .decl = file.root_decl.unwrap().? }));
3895 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = file.root_decl.unwrap().? }));
39103896 zcu.intern_pool.remove(decl.val.toIntern());
39113897 decl.val = undefined;
39123898 _ = try zcu.getFileRootStruct(file.root_decl.unwrap().?, decl.src_namespace, file);
......@@ -4097,7 +4083,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
40974083 break :ip_index .none;
40984084 };
40994085
4100 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalSubject.wrap(.{ .decl = decl_index }));
4086 mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .decl = decl_index }));
41014087
41024088 decl.analysis = .in_progress;
41034089
......@@ -4160,7 +4146,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
41604146 // Note this resolves the type of the Decl, not the value; if this Decl
41614147 // is a struct, for example, this resolves `type` (which needs no resolution),
41624148 // not the struct itself.
4163 try sema.resolveTypeLayout(decl_ty);
4149 try decl_ty.resolveLayout(mod);
41644150
41654151 if (decl.kind == .@"usingnamespace") {
41664152 if (!decl_ty.eql(Type.type, mod)) {
......@@ -4277,7 +4263,7 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
42774263 if (has_runtime_bits) {
42784264 // Needed for codegen_decl which will call updateDecl and then the
42794265 // codegen backend wants full access to the Decl Type.
4280 try sema.resolveTypeFully(decl_ty);
4266 try decl_ty.resolveFully(mod);
42814267
42824268 try mod.comp.work_queue.writeItem(.{ .codegen_decl = decl_index });
42834269
......@@ -4293,6 +4279,8 @@ fn semaDecl(mod: *Module, decl_index: Decl.Index) !SemaDeclResult {
42934279 try sema.analyzeExport(&block_scope, export_src, .{ .name = decl.name }, decl_index);
42944280 }
42954281
4282 try sema.flushExports();
4283
42964284 return result;
42974285}
42984286
......@@ -4323,7 +4311,7 @@ fn semaAnonOwnerDecl(zcu: *Zcu, decl_index: Decl.Index) !SemaDeclResult {
43234311 // with a new Decl.
43244312 //
43254313 // Yes, this does mean that any type owner Decl has a constant value for its entire lifetime.
4326 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, InternPool.AnalSubject.wrap(.{ .decl = decl_index }));
4314 zcu.intern_pool.removeDependenciesForDepender(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
43274315 zcu.intern_pool.remove(decl.val.toIntern());
43284316 decl.analysis = .dependency_failure;
43294317 return .{
......@@ -4525,7 +4513,7 @@ pub fn embedFile(
45254513 mod: *Module,
45264514 cur_file: *File,
45274515 import_string: []const u8,
4528 src_loc: SrcLoc,
4516 src_loc: LazySrcLoc,
45294517) !InternPool.Index {
45304518 const gpa = mod.gpa;
45314519
......@@ -4600,7 +4588,7 @@ fn newEmbedFile(
46004588 sub_file_path: []const u8,
46014589 resolved_path: []const u8,
46024590 result: **EmbedFile,
4603 src_loc: SrcLoc,
4591 src_loc: LazySrcLoc,
46044592) !InternPool.Index {
46054593 const gpa = mod.gpa;
46064594 const ip = &mod.intern_pool;
......@@ -4949,63 +4937,85 @@ pub fn finalizeAnonDecl(mod: *Module, decl_index: Decl.Index) Allocator.Error!vo
49494937 }
49504938}
49514939
4952/// Delete all the Export objects that are caused by this Decl. Re-analysis of
4953/// this Decl will cause them to be re-created (or not).
4954fn deleteDeclExports(mod: *Module, decl_index: Decl.Index) Allocator.Error!void {
4955 var export_owners = (mod.export_owners.fetchSwapRemove(decl_index) orelse return).value;
4956
4957 for (export_owners.items) |exp| {
4958 switch (exp.exported) {
4959 .decl_index => |exported_decl_index| {
4960 if (mod.decl_exports.getPtr(exported_decl_index)) |export_list| {
4961 // Remove exports with owner_decl matching the regenerating decl.
4962 const list = export_list.items;
4963 var i: usize = 0;
4964 var new_len = list.len;
4965 while (i < new_len) {
4966 if (list[i].owner_decl == decl_index) {
4967 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4968 new_len -= 1;
4969 } else {
4970 i += 1;
4971 }
4972 }
4973 export_list.shrinkAndFree(mod.gpa, new_len);
4974 if (new_len == 0) {
4975 assert(mod.decl_exports.swapRemove(exported_decl_index));
4976 }
4977 }
4978 },
4979 .value => |value| {
4980 if (mod.value_exports.getPtr(value)) |export_list| {
4981 // Remove exports with owner_decl matching the regenerating decl.
4982 const list = export_list.items;
4983 var i: usize = 0;
4984 var new_len = list.len;
4985 while (i < new_len) {
4986 if (list[i].owner_decl == decl_index) {
4987 mem.copyBackwards(*Export, list[i..], list[i + 1 .. new_len]);
4988 new_len -= 1;
4989 } else {
4990 i += 1;
4991 }
4992 }
4993 export_list.shrinkAndFree(mod.gpa, new_len);
4994 if (new_len == 0) {
4995 assert(mod.value_exports.swapRemove(value));
4996 }
4997 }
4998 },
4999 }
5000 if (mod.comp.bin_file) |lf| {
5001 try lf.deleteDeclExport(decl_index, exp.opts.name);
5002 }
5003 if (mod.failed_exports.fetchSwapRemove(exp)) |failed_kv| {
5004 failed_kv.value.destroy(mod.gpa);
4940/// Delete all the Export objects that are caused by this `AnalUnit`. Re-analysis of
4941/// this `AnalUnit` will cause them to be re-created (or not).
4942pub fn deleteUnitExports(zcu: *Zcu, anal_unit: AnalUnit) void {
4943 const gpa = zcu.gpa;
4944
4945 const exports_base, const exports_len = if (zcu.single_exports.fetchSwapRemove(anal_unit)) |kv|
4946 .{ kv.value, 1 }
4947 else if (zcu.multi_exports.fetchSwapRemove(anal_unit)) |info|
4948 .{ info.value.index, info.value.len }
4949 else
4950 return;
4951
4952 const exports = zcu.all_exports.items[exports_base..][0..exports_len];
4953
4954 // In an only-c build, we're guaranteed to never use incremental compilation, so there are
4955 // guaranteed not to be any exports in the output file that need deleting (since we only call
4956 // `updateExports` on flush).
4957 // This case is needed because in some rare edge cases, `Sema` wants to add and delete exports
4958 // within a single update.
4959 if (!build_options.only_c) {
4960 for (exports, exports_base..) |exp, export_idx| {
4961 if (zcu.comp.bin_file) |lf| {
4962 lf.deleteExport(exp.exported, exp.opts.name);
4963 }
4964 if (zcu.failed_exports.fetchSwapRemove(@intCast(export_idx))) |failed_kv| {
4965 failed_kv.value.destroy(gpa);
4966 }
50054967 }
5006 mod.gpa.destroy(exp);
50074968 }
5008 export_owners.deinit(mod.gpa);
4969
4970 zcu.free_exports.ensureUnusedCapacity(gpa, exports_len) catch {
4971 // This space will be reused eventually, so we need not propagate this error.
4972 // Just leak it for now, and let GC reclaim it later on.
4973 return;
4974 };
4975 for (exports_base..exports_base + exports_len) |export_idx| {
4976 zcu.free_exports.appendAssumeCapacity(@intCast(export_idx));
4977 }
4978}
4979
4980/// Delete all references in `reference_table` which are caused by this `AnalUnit`.
4981/// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated.
4982fn deleteUnitReferences(zcu: *Zcu, anal_unit: AnalUnit) void {
4983 const gpa = zcu.gpa;
4984
4985 const kv = zcu.reference_table.fetchSwapRemove(anal_unit) orelse return;
4986 var idx = kv.value;
4987
4988 while (idx != std.math.maxInt(u32)) {
4989 zcu.free_references.append(gpa, idx) catch {
4990 // This space will be reused eventually, so we need not propagate this error.
4991 // Just leak it for now, and let GC reclaim it later on.
4992 return;
4993 };
4994 idx = zcu.all_references.items[idx].next;
4995 }
4996}
4997
4998pub fn addUnitReference(zcu: *Zcu, src_unit: AnalUnit, referenced_unit: AnalUnit, ref_src: LazySrcLoc) Allocator.Error!void {
4999 const gpa = zcu.gpa;
5000
5001 try zcu.reference_table.ensureUnusedCapacity(gpa, 1);
5002
5003 const ref_idx = zcu.free_references.popOrNull() orelse idx: {
5004 _ = try zcu.all_references.addOne(gpa);
5005 break :idx zcu.all_references.items.len - 1;
5006 };
5007
5008 errdefer comptime unreachable;
5009
5010 const gop = zcu.reference_table.getOrPutAssumeCapacity(src_unit);
5011
5012 zcu.all_references.items[ref_idx] = .{
5013 .referenced = referenced_unit,
5014 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32),
5015 .src = ref_src,
5016 };
5017
5018 gop.value_ptr.* = @intCast(ref_idx);
50095019}
50105020
50115021pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocator) SemaError!Air {
......@@ -5026,7 +5036,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
50265036 const decl_prog_node = mod.sema_prog_node.start((try decl.fullyQualifiedName(mod)).toSlice(ip), 0);
50275037 defer decl_prog_node.end();
50285038
5029 mod.intern_pool.removeDependenciesForDepender(gpa, InternPool.AnalSubject.wrap(.{ .func = func_index }));
5039 mod.intern_pool.removeDependenciesForDepender(gpa, AnalUnit.wrap(.{ .func = func_index }));
50305040
50315041 var comptime_err_ret_trace = std.ArrayList(LazySrcLoc).init(gpa);
50325042 defer comptime_err_ret_trace.deinit();
......@@ -5245,22 +5255,7 @@ pub fn analyzeFnBody(mod: *Module, func_index: InternPool.Index, arena: Allocato
52455255 else => |e| return e,
52465256 };
52475257
5248 // Similarly, resolve any queued up types that were requested to be resolved for
5249 // the backends.
5250 for (sema.types_to_resolve.keys()) |ty| {
5251 sema.resolveTypeFully(Type.fromInterned(ty)) catch |err| switch (err) {
5252 error.GenericPoison => unreachable,
5253 error.ComptimeReturn => unreachable,
5254 error.ComptimeBreak => unreachable,
5255 error.AnalysisFail => {
5256 // In this case our function depends on a type that had a compile error.
5257 // We should not try to lower this function.
5258 decl.analysis = .dependency_failure;
5259 return error.AnalysisFail;
5260 },
5261 else => |e| return e,
5262 };
5263 }
5258 try sema.flushExports();
52645259
52655260 return .{
52665261 .instructions = sema.air_instructions.toOwnedSlice(),
......@@ -5341,17 +5336,13 @@ pub fn initNewAnonDecl(
53415336 new_decl.analysis = .complete;
53425337}
53435338
5344pub fn errNoteNonLazy(
5339pub fn errNote(
53455340 mod: *Module,
5346 src_loc: SrcLoc,
5341 src_loc: LazySrcLoc,
53475342 parent: *ErrorMsg,
53485343 comptime format: []const u8,
53495344 args: anytype,
53505345) error{OutOfMemory}!void {
5351 if (src_loc.lazy == .unneeded) {
5352 assert(parent.src_loc.lazy == .unneeded);
5353 return;
5354 }
53555346 const msg = try std.fmt.allocPrint(mod.gpa, format, args);
53565347 errdefer mod.gpa.free(msg);
53575348
......@@ -5392,76 +5383,130 @@ fn lockAndClearFileCompileError(mod: *Module, file: *File) void {
53925383/// Called from `Compilation.update`, after everything is done, just before
53935384/// reporting compile errors. In this function we emit exported symbol collision
53945385/// errors and communicate exported symbols to the linker backend.
5395pub fn processExports(mod: *Module) !void {
5386pub fn processExports(zcu: *Zcu) !void {
5387 const gpa = zcu.gpa;
5388
5389 // First, construct a mapping of every exported value and Decl to the indices of all its different exports.
5390 var decl_exports: std.AutoArrayHashMapUnmanaged(Decl.Index, ArrayListUnmanaged(u32)) = .{};
5391 var value_exports: std.AutoArrayHashMapUnmanaged(InternPool.Index, ArrayListUnmanaged(u32)) = .{};
5392 defer {
5393 for (decl_exports.values()) |*exports| {
5394 exports.deinit(gpa);
5395 }
5396 decl_exports.deinit(gpa);
5397 for (value_exports.values()) |*exports| {
5398 exports.deinit(gpa);
5399 }
5400 value_exports.deinit(gpa);
5401 }
5402
5403 // We note as a heuristic:
5404 // * It is rare to export a value.
5405 // * It is rare for one Decl to be exported multiple times.
5406 // So, this ensureTotalCapacity serves as a reasonable (albeit very approximate) optimization.
5407 try decl_exports.ensureTotalCapacity(gpa, zcu.single_exports.count() + zcu.multi_exports.count());
5408
5409 for (zcu.single_exports.values()) |export_idx| {
5410 const exp = zcu.all_exports.items[export_idx];
5411 const value_ptr, const found_existing = switch (exp.exported) {
5412 .decl_index => |i| gop: {
5413 const gop = try decl_exports.getOrPut(gpa, i);
5414 break :gop .{ gop.value_ptr, gop.found_existing };
5415 },
5416 .value => |i| gop: {
5417 const gop = try value_exports.getOrPut(gpa, i);
5418 break :gop .{ gop.value_ptr, gop.found_existing };
5419 },
5420 };
5421 if (!found_existing) value_ptr.* = .{};
5422 try value_ptr.append(gpa, export_idx);
5423 }
5424
5425 for (zcu.multi_exports.values()) |info| {
5426 for (zcu.all_exports.items[info.index..][0..info.len], info.index..) |exp, export_idx| {
5427 const value_ptr, const found_existing = switch (exp.exported) {
5428 .decl_index => |i| gop: {
5429 const gop = try decl_exports.getOrPut(gpa, i);
5430 break :gop .{ gop.value_ptr, gop.found_existing };
5431 },
5432 .value => |i| gop: {
5433 const gop = try value_exports.getOrPut(gpa, i);
5434 break :gop .{ gop.value_ptr, gop.found_existing };
5435 },
5436 };
5437 if (!found_existing) value_ptr.* = .{};
5438 try value_ptr.append(gpa, @intCast(export_idx));
5439 }
5440 }
5441
53965442 // Map symbol names to `Export` for name collision detection.
53975443 var symbol_exports: SymbolExports = .{};
5398 defer symbol_exports.deinit(mod.gpa);
5444 defer symbol_exports.deinit(gpa);
53995445
5400 for (mod.decl_exports.keys(), mod.decl_exports.values()) |exported_decl, exports_list| {
5446 for (decl_exports.keys(), decl_exports.values()) |exported_decl, exports_list| {
54015447 const exported: Exported = .{ .decl_index = exported_decl };
5402 try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
5448 try processExportsInner(zcu, &symbol_exports, exported, exports_list.items);
54035449 }
54045450
5405 for (mod.value_exports.keys(), mod.value_exports.values()) |exported_value, exports_list| {
5451 for (value_exports.keys(), value_exports.values()) |exported_value, exports_list| {
54065452 const exported: Exported = .{ .value = exported_value };
5407 try processExportsInner(mod, &symbol_exports, exported, exports_list.items);
5453 try processExportsInner(zcu, &symbol_exports, exported, exports_list.items);
54085454 }
54095455}
54105456
5411const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, *Export);
5457const SymbolExports = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, u32);
54125458
54135459fn processExportsInner(
54145460 zcu: *Zcu,
54155461 symbol_exports: *SymbolExports,
54165462 exported: Exported,
5417 exports: []const *Export,
5463 export_indices: []const u32,
54185464) error{OutOfMemory}!void {
54195465 const gpa = zcu.gpa;
54205466
5421 for (exports) |new_export| {
5467 for (export_indices) |export_idx| {
5468 const new_export = &zcu.all_exports.items[export_idx];
54225469 const gop = try symbol_exports.getOrPut(gpa, new_export.opts.name);
54235470 if (gop.found_existing) {
54245471 new_export.status = .failed_retryable;
54255472 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
5426 const src_loc = new_export.getSrcLoc(zcu);
5427 const msg = try ErrorMsg.create(gpa, src_loc, "exported symbol collision: {}", .{
5473 const msg = try ErrorMsg.create(gpa, new_export.src, "exported symbol collision: {}", .{
54285474 new_export.opts.name.fmt(&zcu.intern_pool),
54295475 });
54305476 errdefer msg.destroy(gpa);
5431 const other_export = gop.value_ptr.*;
5432 const other_src_loc = other_export.getSrcLoc(zcu);
5433 try zcu.errNoteNonLazy(other_src_loc, msg, "other symbol here", .{});
5434 zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5477 const other_export = zcu.all_exports.items[gop.value_ptr.*];
5478 try zcu.errNote(other_export.src, msg, "other symbol here", .{});
5479 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
54355480 new_export.status = .failed;
54365481 } else {
5437 gop.value_ptr.* = new_export;
5482 gop.value_ptr.* = export_idx;
54385483 }
54395484 }
54405485 if (zcu.comp.bin_file) |lf| {
5441 try handleUpdateExports(zcu, exports, lf.updateExports(zcu, exported, exports));
5486 try handleUpdateExports(zcu, export_indices, lf.updateExports(zcu, exported, export_indices));
54425487 } else if (zcu.llvm_object) |llvm_object| {
54435488 if (build_options.only_c) unreachable;
5444 try handleUpdateExports(zcu, exports, llvm_object.updateExports(zcu, exported, exports));
5489 try handleUpdateExports(zcu, export_indices, llvm_object.updateExports(zcu, exported, export_indices));
54455490 }
54465491}
54475492
54485493fn handleUpdateExports(
54495494 zcu: *Zcu,
5450 exports: []const *Export,
5495 export_indices: []const u32,
54515496 result: link.File.UpdateExportsError!void,
54525497) Allocator.Error!void {
54535498 const gpa = zcu.gpa;
54545499 result catch |err| switch (err) {
54555500 error.OutOfMemory => return error.OutOfMemory,
54565501 error.AnalysisFail => {
5457 const new_export = exports[0];
5502 const export_idx = export_indices[0];
5503 const new_export = &zcu.all_exports.items[export_idx];
54585504 new_export.status = .failed_retryable;
54595505 try zcu.failed_exports.ensureUnusedCapacity(gpa, 1);
5460 const src_loc = new_export.getSrcLoc(zcu);
5461 const msg = try ErrorMsg.create(gpa, src_loc, "unable to export: {s}", .{
5506 const msg = try ErrorMsg.create(gpa, new_export.src, "unable to export: {s}", .{
54625507 @errorName(err),
54635508 });
5464 zcu.failed_exports.putAssumeCapacityNoClobber(new_export, msg);
5509 zcu.failed_exports.putAssumeCapacityNoClobber(export_idx, msg);
54655510 },
54665511 };
54675512}
......@@ -5619,24 +5664,21 @@ pub fn linkerUpdateDecl(zcu: *Zcu, decl_index: Decl.Index) !void {
56195664 },
56205665 else => {
56215666 const gpa = zcu.gpa;
5622 try zcu.failed_decls.ensureUnusedCapacity(gpa, 1);
5623 zcu.failed_decls.putAssumeCapacityNoClobber(decl_index, try ErrorMsg.create(
5667 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
5668 zcu.failed_analysis.putAssumeCapacityNoClobber(AnalUnit.wrap(.{ .decl = decl_index }), try ErrorMsg.create(
56245669 gpa,
5625 decl.navSrcLoc(zcu).upgrade(zcu),
5670 decl.navSrcLoc(zcu),
56265671 "unable to codegen: {s}",
56275672 .{@errorName(err)},
56285673 ));
56295674 decl.analysis = .codegen_failure;
5630 try zcu.retryable_failures.append(zcu.gpa, InternPool.AnalSubject.wrap(.{ .decl = decl_index }));
5675 try zcu.retryable_failures.append(zcu.gpa, AnalUnit.wrap(.{ .decl = decl_index }));
56315676 },
56325677 };
56335678 } else if (zcu.llvm_object) |llvm_object| {
56345679 if (build_options.only_c) unreachable;
56355680 llvm_object.updateDecl(zcu, decl_index) catch |err| switch (err) {
56365681 error.OutOfMemory => return error.OutOfMemory,
5637 error.AnalysisFail => {
5638 decl.analysis = .codegen_failure;
5639 },
56405682 };
56415683 }
56425684}
......@@ -5652,9 +5694,8 @@ fn reportRetryableFileError(
56525694 const err_msg = try ErrorMsg.create(
56535695 mod.gpa,
56545696 .{
5655 .file_scope = file,
5656 .base_node = 0,
5657 .lazy = .entire_file,
5697 .base_node_inst = try mod.intern_pool.trackZir(mod.gpa, file, .main_struct_inst),
5698 .offset = .entire_file,
56585699 },
56595700 format,
56605701 args,
......@@ -5684,14 +5725,6 @@ pub fn addGlobalAssembly(mod: *Module, decl_index: Decl.Index, source: []const u
56845725 }
56855726}
56865727
5687pub fn getDeclExports(mod: Module, decl_index: Decl.Index) []const *Export {
5688 if (mod.decl_exports.get(decl_index)) |l| {
5689 return l.items;
5690 } else {
5691 return &[0]*Export{};
5692 }
5693}
5694
56955728pub const Feature = enum {
56965729 panic_fn,
56975730 panic_unwrap_error,
......@@ -5786,6 +5819,16 @@ pub fn ptrType(mod: *Module, info: InternPool.Key.PtrType) Allocator.Error!Type
57865819 return Type.fromInterned((try intern(mod, .{ .ptr_type = canon_info })));
57875820}
57885821
5822/// Like `ptrType`, but if `info` specifies an `alignment`, first ensures the pointer
5823/// child type's alignment is resolved so that an invalid alignment is not used.
5824/// In general, prefer this function during semantic analysis.
5825pub fn ptrTypeSema(zcu: *Zcu, info: InternPool.Key.PtrType) SemaError!Type {
5826 if (info.flags.alignment != .none) {
5827 _ = try Type.fromInterned(info.child).abiAlignmentAdvanced(zcu, .sema);
5828 }
5829 return zcu.ptrType(info);
5830}
5831
57895832pub fn singleMutPtrType(mod: *Module, child_type: Type) Allocator.Error!Type {
57905833 return ptrType(mod, .{ .child = child_type.toIntern() });
57915834}
......@@ -6361,15 +6404,21 @@ pub fn unionAbiAlignment(mod: *Module, loaded_union: InternPool.LoadedUnionType)
63616404 return max_align;
63626405}
63636406
6364/// Returns the field alignment, assuming the union is not packed.
6365/// Keep implementation in sync with `Sema.unionFieldAlignment`.
6366/// Prefer to call that function instead of this one during Sema.
6367pub fn unionFieldNormalAlignment(mod: *Module, loaded_union: InternPool.LoadedUnionType, field_index: u32) Alignment {
6368 const ip = &mod.intern_pool;
6407/// Returns the field alignment of a non-packed union. Asserts the layout is not packed.
6408pub fn unionFieldNormalAlignment(zcu: *Zcu, loaded_union: InternPool.LoadedUnionType, field_index: u32) Alignment {
6409 return zcu.unionFieldNormalAlignmentAdvanced(loaded_union, field_index, .normal) catch unreachable;
6410}
6411
6412/// Returns the field alignment of a non-packed union. Asserts the layout is not packed.
6413/// If `strat` is `.sema`, may perform type resolution.
6414pub fn unionFieldNormalAlignmentAdvanced(zcu: *Zcu, loaded_union: InternPool.LoadedUnionType, field_index: u32, strat: Type.ResolveStrat) SemaError!Alignment {
6415 const ip = &zcu.intern_pool;
6416 assert(loaded_union.flagsPtr(ip).layout != .@"packed");
63696417 const field_align = loaded_union.fieldAlign(ip, field_index);
63706418 if (field_align != .none) return field_align;
63716419 const field_ty = Type.fromInterned(loaded_union.field_types.get(ip)[field_index]);
6372 return field_ty.abiAlignment(mod);
6420 if (field_ty.isNoReturn(zcu)) return .none;
6421 return (try field_ty.abiAlignmentAdvanced(zcu, strat.toLazy())).scalar;
63736422}
63746423
63756424/// Returns the index of the active field, given the current tag value
......@@ -6380,41 +6429,37 @@ pub fn unionTagFieldIndex(mod: *Module, loaded_union: InternPool.LoadedUnionType
63806429 return loaded_union.loadTagType(ip).tagValueIndex(ip, enum_tag.toIntern());
63816430}
63826431
6383/// Returns the field alignment of a non-packed struct in byte units.
6384/// Keep implementation in sync with `Sema.structFieldAlignment`.
6385/// asserts the layout is not packed.
6432/// Returns the field alignment of a non-packed struct. Asserts the layout is not packed.
63866433pub fn structFieldAlignment(
6387 mod: *Module,
6434 zcu: *Zcu,
63886435 explicit_alignment: InternPool.Alignment,
63896436 field_ty: Type,
63906437 layout: std.builtin.Type.ContainerLayout,
63916438) Alignment {
6439 return zcu.structFieldAlignmentAdvanced(explicit_alignment, field_ty, layout, .normal) catch unreachable;
6440}
6441
6442/// Returns the field alignment of a non-packed struct. Asserts the layout is not packed.
6443/// If `strat` is `.sema`, may perform type resolution.
6444pub fn structFieldAlignmentAdvanced(
6445 zcu: *Zcu,
6446 explicit_alignment: InternPool.Alignment,
6447 field_ty: Type,
6448 layout: std.builtin.Type.ContainerLayout,
6449 strat: Type.ResolveStrat,
6450) SemaError!Alignment {
63926451 assert(layout != .@"packed");
63936452 if (explicit_alignment != .none) return explicit_alignment;
6453 const ty_abi_align = (try field_ty.abiAlignmentAdvanced(zcu, strat.toLazy())).scalar;
63946454 switch (layout) {
63956455 .@"packed" => unreachable,
6396 .auto => {
6397 if (mod.getTarget().ofmt == .c) {
6398 return structFieldAlignmentExtern(mod, field_ty);
6399 } else {
6400 return field_ty.abiAlignment(mod);
6401 }
6402 },
6403 .@"extern" => return structFieldAlignmentExtern(mod, field_ty),
6456 .auto => if (zcu.getTarget().ofmt != .c) return ty_abi_align,
6457 .@"extern" => {},
64046458 }
6405}
6406
6407/// Returns the field alignment of an extern struct in byte units.
6408/// This logic is duplicated in Type.abiAlignmentAdvanced.
6409pub fn structFieldAlignmentExtern(mod: *Module, field_ty: Type) Alignment {
6410 const ty_abi_align = field_ty.abiAlignment(mod);
6411
6412 if (field_ty.isAbiInt(mod) and field_ty.intInfo(mod).bits >= 128) {
6413 // The C ABI requires 128 bit integer fields of structs
6414 // to be 16-bytes aligned.
6415 return ty_abi_align.max(.@"16");
6459 // extern
6460 if (field_ty.isAbiInt(zcu) and field_ty.intInfo(zcu).bits >= 128) {
6461 return ty_abi_align.maxStrict(.@"16");
64166462 }
6417
64186463 return ty_abi_align;
64196464}
64206465
......@@ -6440,3 +6485,62 @@ pub fn structPackedFieldBitOffset(
64406485 }
64416486 unreachable; // index out of bounds
64426487}
6488
6489pub const ResolvedReference = struct {
6490 referencer: AnalUnit,
6491 src: LazySrcLoc,
6492};
6493
6494/// Returns a mapping from an `AnalUnit` to where it is referenced.
6495/// TODO: in future, this must be adapted to traverse from roots of analysis. That way, we can
6496/// use the returned map to determine which units have become unreferenced in an incremental update.
6497pub fn resolveReferences(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) {
6498 const gpa = zcu.gpa;
6499
6500 var result: std.AutoHashMapUnmanaged(AnalUnit, ResolvedReference) = .{};
6501 errdefer result.deinit(gpa);
6502
6503 // This is not a sufficient size, but a lower bound.
6504 try result.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count()));
6505
6506 for (zcu.reference_table.keys(), zcu.reference_table.values()) |referencer, first_ref_idx| {
6507 assert(first_ref_idx != std.math.maxInt(u32));
6508 var ref_idx = first_ref_idx;
6509 while (ref_idx != std.math.maxInt(u32)) {
6510 const ref = zcu.all_references.items[ref_idx];
6511 const gop = try result.getOrPut(gpa, ref.referenced);
6512 if (!gop.found_existing) {
6513 gop.value_ptr.* = .{ .referencer = referencer, .src = ref.src };
6514 }
6515 ref_idx = ref.next;
6516 }
6517 }
6518
6519 return result;
6520}
6521
6522pub fn getBuiltin(zcu: *Zcu, name: []const u8) Allocator.Error!Air.Inst.Ref {
6523 const decl_index = try zcu.getBuiltinDecl(name);
6524 zcu.ensureDeclAnalyzed(decl_index) catch @panic("std.builtin is corrupt");
6525 return Air.internedToRef(zcu.declPtr(decl_index).val.toIntern());
6526}
6527
6528pub fn getBuiltinDecl(zcu: *Zcu, name: []const u8) Allocator.Error!InternPool.DeclIndex {
6529 const gpa = zcu.gpa;
6530 const ip = &zcu.intern_pool;
6531 const std_file = (zcu.importPkg(zcu.std_mod) catch @panic("failed to import lib/std.zig")).file;
6532 const std_namespace = zcu.declPtr(std_file.root_decl.unwrap().?).getOwnedInnerNamespace(zcu).?;
6533 const builtin_str = try ip.getOrPutString(gpa, "builtin", .no_embedded_nulls);
6534 const builtin_decl = std_namespace.decls.getKeyAdapted(builtin_str, Zcu.DeclAdapter{ .zcu = zcu }) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
6535 zcu.ensureDeclAnalyzed(builtin_decl) catch @panic("std.builtin is corrupt");
6536 const builtin_namespace = zcu.declPtr(builtin_decl).getInnerNamespace(zcu) orelse @panic("std.builtin is corrupt");
6537 const name_str = try ip.getOrPutString(gpa, name, .no_embedded_nulls);
6538 return builtin_namespace.decls.getKeyAdapted(name_str, Zcu.DeclAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt");
6539}
6540
6541pub fn getBuiltinType(zcu: *Zcu, name: []const u8) Allocator.Error!Type {
6542 const ty_inst = try zcu.getBuiltin(name);
6543 const ty = Type.fromInterned(ty_inst.toInterned() orelse @panic("std.builtin is corrupt"));
6544 ty.resolveFully(zcu) catch @panic("std.builtin is corrupt");
6545 return ty;
6546}
src/arch/aarch64/CodeGen.zig+3-3
......@@ -8,7 +8,7 @@ const Air = @import("../../Air.zig");
88const Mir = @import("Mir.zig");
99const Emit = @import("Emit.zig");
1010const Liveness = @import("../../Liveness.zig");
11const Type = @import("../../type.zig").Type;
11const Type = @import("../../Type.zig");
1212const Value = @import("../../Value.zig");
1313const link = @import("../../link.zig");
1414const Zcu = @import("../../Zcu.zig");
......@@ -59,7 +59,7 @@ args: []MCValue,
5959ret_mcv: MCValue,
6060fn_type: Type,
6161arg_index: u32,
62src_loc: Module.SrcLoc,
62src_loc: Module.LazySrcLoc,
6363stack_align: u32,
6464
6565/// MIR Instructions
......@@ -331,7 +331,7 @@ const Self = @This();
331331
332332pub fn generate(
333333 lf: *link.File,
334 src_loc: Module.SrcLoc,
334 src_loc: Module.LazySrcLoc,
335335 func_index: InternPool.Index,
336336 air: Air,
337337 liveness: Liveness,
src/arch/aarch64/Emit.zig+1-1
......@@ -22,7 +22,7 @@ bin_file: *link.File,
2222debug_output: DebugInfoOutput,
2323target: *const std.Target,
2424err_msg: ?*ErrorMsg = null,
25src_loc: Module.SrcLoc,
25src_loc: Module.LazySrcLoc,
2626code: *std.ArrayList(u8),
2727
2828prev_di_line: u32,
src/arch/aarch64/abi.zig+1-1
......@@ -3,7 +3,7 @@ const builtin = @import("builtin");
33const bits = @import("bits.zig");
44const Register = bits.Register;
55const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
6const Type = @import("../../type.zig").Type;
6const Type = @import("../../Type.zig");
77const Zcu = @import("../../Zcu.zig");
88/// Deprecated.
99const Module = Zcu;
src/arch/arm/CodeGen.zig+3-3
......@@ -8,7 +8,7 @@ const Air = @import("../../Air.zig");
88const Mir = @import("Mir.zig");
99const Emit = @import("Emit.zig");
1010const Liveness = @import("../../Liveness.zig");
11const Type = @import("../../type.zig").Type;
11const Type = @import("../../Type.zig");
1212const Value = @import("../../Value.zig");
1313const link = @import("../../link.zig");
1414const Zcu = @import("../../Zcu.zig");
......@@ -59,7 +59,7 @@ args: []MCValue,
5959ret_mcv: MCValue,
6060fn_type: Type,
6161arg_index: u32,
62src_loc: Module.SrcLoc,
62src_loc: Module.LazySrcLoc,
6363stack_align: u32,
6464
6565/// MIR Instructions
......@@ -338,7 +338,7 @@ const Self = @This();
338338
339339pub fn generate(
340340 lf: *link.File,
341 src_loc: Module.SrcLoc,
341 src_loc: Module.LazySrcLoc,
342342 func_index: InternPool.Index,
343343 air: Air,
344344 liveness: Liveness,
src/arch/arm/Emit.zig+2-2
......@@ -11,7 +11,7 @@ const link = @import("../../link.zig");
1111const Zcu = @import("../../Zcu.zig");
1212/// Deprecated.
1313const Module = Zcu;
14const Type = @import("../../type.zig").Type;
14const Type = @import("../../Type.zig");
1515const ErrorMsg = Module.ErrorMsg;
1616const Target = std.Target;
1717const assert = std.debug.assert;
......@@ -26,7 +26,7 @@ bin_file: *link.File,
2626debug_output: DebugInfoOutput,
2727target: *const std.Target,
2828err_msg: ?*ErrorMsg = null,
29src_loc: Module.SrcLoc,
29src_loc: Module.LazySrcLoc,
3030code: *std.ArrayList(u8),
3131
3232prev_di_line: u32,
src/arch/arm/abi.zig+1-1
......@@ -3,7 +3,7 @@ const assert = std.debug.assert;
33const bits = @import("bits.zig");
44const Register = bits.Register;
55const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
6const Type = @import("../../type.zig").Type;
6const Type = @import("../../Type.zig");
77const Zcu = @import("../../Zcu.zig");
88/// Deprecated.
99const Module = Zcu;
src/arch/riscv64/CodeGen.zig+3-3
......@@ -7,7 +7,7 @@ const Air = @import("../../Air.zig");
77const Mir = @import("Mir.zig");
88const Emit = @import("Emit.zig");
99const Liveness = @import("../../Liveness.zig");
10const Type = @import("../../type.zig").Type;
10const Type = @import("../../Type.zig");
1111const Value = @import("../../Value.zig");
1212const link = @import("../../link.zig");
1313const Zcu = @import("../../Zcu.zig");
......@@ -59,7 +59,7 @@ args: []MCValue,
5959ret_mcv: InstTracking,
6060fn_type: Type,
6161arg_index: usize,
62src_loc: Zcu.SrcLoc,
62src_loc: Zcu.LazySrcLoc,
6363
6464/// MIR Instructions
6565mir_instructions: std.MultiArrayList(Mir.Inst) = .{},
......@@ -696,7 +696,7 @@ const CallView = enum(u1) {
696696
697697pub fn generate(
698698 bin_file: *link.File,
699 src_loc: Zcu.SrcLoc,
699 src_loc: Zcu.LazySrcLoc,
700700 func_index: InternPool.Index,
701701 air: Air,
702702 liveness: Liveness,
src/arch/riscv64/Lower.zig+1-1
......@@ -8,7 +8,7 @@ allocator: Allocator,
88mir: Mir,
99cc: std.builtin.CallingConvention,
1010err_msg: ?*ErrorMsg = null,
11src_loc: Zcu.SrcLoc,
11src_loc: Zcu.LazySrcLoc,
1212result_insts_len: u8 = undefined,
1313result_relocs_len: u8 = undefined,
1414result_insts: [
src/arch/riscv64/Mir.zig+1-1
......@@ -431,7 +431,7 @@ pub const RegisterList = struct {
431431const Mir = @This();
432432const std = @import("std");
433433const builtin = @import("builtin");
434const Type = @import("../../type.zig").Type;
434const Type = @import("../../Type.zig");
435435
436436const assert = std.debug.assert;
437437
src/arch/riscv64/abi.zig+1-1
......@@ -2,7 +2,7 @@ const std = @import("std");
22const bits = @import("bits.zig");
33const Register = bits.Register;
44const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
5const Type = @import("../../type.zig").Type;
5const Type = @import("../../Type.zig");
66const InternPool = @import("../../InternPool.zig");
77const Zcu = @import("../../Zcu.zig");
88const assert = std.debug.assert;
src/arch/sparc64/CodeGen.zig+3-3
......@@ -21,7 +21,7 @@ const Air = @import("../../Air.zig");
2121const Mir = @import("Mir.zig");
2222const Emit = @import("Emit.zig");
2323const Liveness = @import("../../Liveness.zig");
24const Type = @import("../../type.zig").Type;
24const Type = @import("../../Type.zig");
2525const CodeGenError = codegen.CodeGenError;
2626const Result = @import("../../codegen.zig").Result;
2727const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
......@@ -64,7 +64,7 @@ args: []MCValue,
6464ret_mcv: MCValue,
6565fn_type: Type,
6666arg_index: usize,
67src_loc: Module.SrcLoc,
67src_loc: Module.LazySrcLoc,
6868stack_align: Alignment,
6969
7070/// MIR Instructions
......@@ -263,7 +263,7 @@ const BigTomb = struct {
263263
264264pub fn generate(
265265 lf: *link.File,
266 src_loc: Module.SrcLoc,
266 src_loc: Module.LazySrcLoc,
267267 func_index: InternPool.Index,
268268 air: Air,
269269 liveness: Liveness,
src/arch/sparc64/Emit.zig+1-1
......@@ -24,7 +24,7 @@ bin_file: *link.File,
2424debug_output: DebugInfoOutput,
2525target: *const std.Target,
2626err_msg: ?*ErrorMsg = null,
27src_loc: Module.SrcLoc,
27src_loc: Module.LazySrcLoc,
2828code: *std.ArrayList(u8),
2929
3030prev_di_line: u32,
src/arch/wasm/CodeGen.zig+4-4
......@@ -13,7 +13,7 @@ const codegen = @import("../../codegen.zig");
1313const Zcu = @import("../../Zcu.zig");
1414const InternPool = @import("../../InternPool.zig");
1515const Decl = Zcu.Decl;
16const Type = @import("../../type.zig").Type;
16const Type = @import("../../Type.zig");
1717const Value = @import("../../Value.zig");
1818const Compilation = @import("../../Compilation.zig");
1919const link = @import("../../link.zig");
......@@ -765,7 +765,7 @@ pub fn deinit(func: *CodeGen) void {
765765/// Sets `err_msg` on `CodeGen` and returns `error.CodegenFail` which is caught in link/Wasm.zig
766766fn fail(func: *CodeGen, comptime fmt: []const u8, args: anytype) InnerError {
767767 const mod = func.bin_file.base.comp.module.?;
768 const src_loc = func.decl.navSrcLoc(mod).upgrade(mod);
768 const src_loc = func.decl.navSrcLoc(mod);
769769 func.err_msg = try Zcu.ErrorMsg.create(func.gpa, src_loc, fmt, args);
770770 return error.CodegenFail;
771771}
......@@ -1202,7 +1202,7 @@ fn genFunctype(
12021202
12031203pub fn generate(
12041204 bin_file: *link.File,
1205 src_loc: Zcu.SrcLoc,
1205 src_loc: Zcu.LazySrcLoc,
12061206 func_index: InternPool.Index,
12071207 air: Air,
12081208 liveness: Liveness,
......@@ -3162,7 +3162,7 @@ fn lowerAnonDeclRef(
31623162 }
31633163
31643164 const decl_align = mod.intern_pool.indexToKey(anon_decl.orig_ty).ptr_type.flags.alignment;
3165 const res = try func.bin_file.lowerAnonDecl(decl_val, decl_align, func.decl.navSrcLoc(mod).upgrade(mod));
3165 const res = try func.bin_file.lowerAnonDecl(decl_val, decl_align, func.decl.navSrcLoc(mod));
31663166 switch (res) {
31673167 .ok => {},
31683168 .fail => |em| {
src/arch/wasm/Emit.zig+1-1
......@@ -257,7 +257,7 @@ fn fail(emit: *Emit, comptime format: []const u8, args: anytype) InnerError {
257257 const comp = emit.bin_file.base.comp;
258258 const zcu = comp.module.?;
259259 const gpa = comp.gpa;
260 emit.error_msg = try Zcu.ErrorMsg.create(gpa, zcu.declPtr(emit.decl_index).navSrcLoc(zcu).upgrade(zcu), format, args);
260 emit.error_msg = try Zcu.ErrorMsg.create(gpa, zcu.declPtr(emit.decl_index).navSrcLoc(zcu), format, args);
261261 return error.EmitFail;
262262}
263263
src/arch/wasm/abi.zig+1-1
......@@ -8,7 +8,7 @@ const std = @import("std");
88const Target = std.Target;
99const assert = std.debug.assert;
1010
11const Type = @import("../../type.zig").Type;
11const Type = @import("../../Type.zig");
1212const Zcu = @import("../../Zcu.zig");
1313
1414/// Defines how to pass a type as part of a function signature,
src/arch/x86_64/CodeGen.zig+4-4
......@@ -32,7 +32,7 @@ const Module = Zcu;
3232const InternPool = @import("../../InternPool.zig");
3333const Alignment = InternPool.Alignment;
3434const Target = std.Target;
35const Type = @import("../../type.zig").Type;
35const Type = @import("../../Type.zig");
3636const Value = @import("../../Value.zig");
3737const Instruction = @import("encoder.zig").Instruction;
3838
......@@ -74,7 +74,7 @@ va_info: union {
7474ret_mcv: InstTracking,
7575fn_type: Type,
7676arg_index: u32,
77src_loc: Module.SrcLoc,
77src_loc: Module.LazySrcLoc,
7878
7979eflags_inst: ?Air.Inst.Index = null,
8080
......@@ -795,7 +795,7 @@ const Self = @This();
795795
796796pub fn generate(
797797 bin_file: *link.File,
798 src_loc: Module.SrcLoc,
798 src_loc: Module.LazySrcLoc,
799799 func_index: InternPool.Index,
800800 air: Air,
801801 liveness: Liveness,
......@@ -971,7 +971,7 @@ pub fn generate(
971971
972972pub fn generateLazy(
973973 bin_file: *link.File,
974 src_loc: Module.SrcLoc,
974 src_loc: Module.LazySrcLoc,
975975 lazy_sym: link.File.LazySymbol,
976976 code: *std.ArrayList(u8),
977977 debug_output: DebugInfoOutput,
src/arch/x86_64/Lower.zig+1-1
......@@ -8,7 +8,7 @@ allocator: Allocator,
88mir: Mir,
99cc: std.builtin.CallingConvention,
1010err_msg: ?*ErrorMsg = null,
11src_loc: Module.SrcLoc,
11src_loc: Module.LazySrcLoc,
1212result_insts_len: u8 = undefined,
1313result_relocs_len: u8 = undefined,
1414result_insts: [
src/arch/x86_64/abi.zig+1-1
......@@ -537,6 +537,6 @@ const testing = std.testing;
537537const InternPool = @import("../../InternPool.zig");
538538const Register = @import("bits.zig").Register;
539539const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
540const Type = @import("../../type.zig").Type;
540const Type = @import("../../Type.zig");
541541const Value = @import("../../Value.zig");
542542const Zcu = @import("../../Zcu.zig");
src/codegen.zig+12-12
......@@ -20,7 +20,7 @@ const Zcu = @import("Zcu.zig");
2020/// Deprecated.
2121const Module = Zcu;
2222const Target = std.Target;
23const Type = @import("type.zig").Type;
23const Type = @import("Type.zig");
2424const Value = @import("Value.zig");
2525const Zir = std.zig.Zir;
2626const Alignment = InternPool.Alignment;
......@@ -47,7 +47,7 @@ pub const DebugInfoOutput = union(enum) {
4747
4848pub fn generateFunction(
4949 lf: *link.File,
50 src_loc: Module.SrcLoc,
50 src_loc: Module.LazySrcLoc,
5151 func_index: InternPool.Index,
5252 air: Air,
5353 liveness: Liveness,
......@@ -79,7 +79,7 @@ pub fn generateFunction(
7979
8080pub fn generateLazyFunction(
8181 lf: *link.File,
82 src_loc: Module.SrcLoc,
82 src_loc: Module.LazySrcLoc,
8383 lazy_sym: link.File.LazySymbol,
8484 code: *std.ArrayList(u8),
8585 debug_output: DebugInfoOutput,
......@@ -105,7 +105,7 @@ fn writeFloat(comptime F: type, f: F, target: Target, endian: std.builtin.Endian
105105
106106pub fn generateLazySymbol(
107107 bin_file: *link.File,
108 src_loc: Module.SrcLoc,
108 src_loc: Module.LazySrcLoc,
109109 lazy_sym: link.File.LazySymbol,
110110 // TODO don't use an "out" parameter like this; put it in the result instead
111111 alignment: *Alignment,
......@@ -171,7 +171,7 @@ pub fn generateLazySymbol(
171171
172172pub fn generateSymbol(
173173 bin_file: *link.File,
174 src_loc: Module.SrcLoc,
174 src_loc: Module.LazySrcLoc,
175175 val: Value,
176176 code: *std.ArrayList(u8),
177177 debug_output: DebugInfoOutput,
......@@ -618,7 +618,7 @@ pub fn generateSymbol(
618618
619619fn lowerPtr(
620620 bin_file: *link.File,
621 src_loc: Module.SrcLoc,
621 src_loc: Module.LazySrcLoc,
622622 ptr_val: InternPool.Index,
623623 code: *std.ArrayList(u8),
624624 debug_output: DebugInfoOutput,
......@@ -683,7 +683,7 @@ const RelocInfo = struct {
683683
684684fn lowerAnonDeclRef(
685685 lf: *link.File,
686 src_loc: Module.SrcLoc,
686 src_loc: Module.LazySrcLoc,
687687 anon_decl: InternPool.Key.Ptr.BaseAddr.AnonDecl,
688688 code: *std.ArrayList(u8),
689689 debug_output: DebugInfoOutput,
......@@ -730,7 +730,7 @@ fn lowerAnonDeclRef(
730730
731731fn lowerDeclRef(
732732 lf: *link.File,
733 src_loc: Module.SrcLoc,
733 src_loc: Module.LazySrcLoc,
734734 decl_index: InternPool.DeclIndex,
735735 code: *std.ArrayList(u8),
736736 debug_output: DebugInfoOutput,
......@@ -814,7 +814,7 @@ pub const GenResult = union(enum) {
814814
815815 fn fail(
816816 gpa: Allocator,
817 src_loc: Module.SrcLoc,
817 src_loc: Module.LazySrcLoc,
818818 comptime format: []const u8,
819819 args: anytype,
820820 ) Allocator.Error!GenResult {
......@@ -825,7 +825,7 @@ pub const GenResult = union(enum) {
825825
826826fn genDeclRef(
827827 lf: *link.File,
828 src_loc: Module.SrcLoc,
828 src_loc: Module.LazySrcLoc,
829829 val: Value,
830830 ptr_decl_index: InternPool.DeclIndex,
831831) CodeGenError!GenResult {
......@@ -931,7 +931,7 @@ fn genDeclRef(
931931
932932fn genUnnamedConst(
933933 lf: *link.File,
934 src_loc: Module.SrcLoc,
934 src_loc: Module.LazySrcLoc,
935935 val: Value,
936936 owner_decl_index: InternPool.DeclIndex,
937937) CodeGenError!GenResult {
......@@ -970,7 +970,7 @@ fn genUnnamedConst(
970970
971971pub fn genTypedValue(
972972 lf: *link.File,
973 src_loc: Module.SrcLoc,
973 src_loc: Module.LazySrcLoc,
974974 val: Value,
975975 owner_decl_index: InternPool.DeclIndex,
976976) CodeGenError!GenResult {
src/codegen/c.zig+148-232
......@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");
99const Module = @import("../Package/Module.zig");
1010const Compilation = @import("../Compilation.zig");
1111const Value = @import("../Value.zig");
12const Type = @import("../type.zig").Type;
12const Type = @import("../Type.zig");
1313const C = link.File.C;
1414const Decl = Zcu.Decl;
1515const trace = @import("../tracy.zig").trace;
......@@ -637,7 +637,7 @@ pub const DeclGen = struct {
637637 const zcu = dg.zcu;
638638 const decl_index = dg.pass.decl;
639639 const decl = zcu.declPtr(decl_index);
640 const src_loc = decl.navSrcLoc(zcu).upgrade(zcu);
640 const src_loc = decl.navSrcLoc(zcu);
641641 dg.error_msg = try Zcu.ErrorMsg.create(dg.gpa, src_loc, format, args);
642642 return error.AnalysisFail;
643643 }
......@@ -731,8 +731,6 @@ pub const DeclGen = struct {
731731 if (decl.val.getExternFunc(zcu)) |extern_func| if (extern_func.decl != decl_index)
732732 return dg.renderDeclValue(writer, extern_func.decl, location);
733733
734 if (decl.val.getVariable(zcu)) |variable| try dg.renderFwdDecl(decl_index, variable, .tentative);
735
736734 // We shouldn't cast C function pointers as this is UB (when you call
737735 // them). The analysis until now should ensure that the C function
738736 // pointers are compatible. If they are not, then there is a bug
......@@ -748,7 +746,7 @@ pub const DeclGen = struct {
748746 try writer.writeByte(')');
749747 }
750748 try writer.writeByte('&');
751 try dg.renderDeclName(writer, decl_index, 0);
749 try dg.renderDeclName(writer, decl_index);
752750 if (need_cast) try writer.writeByte(')');
753751 }
754752
......@@ -1765,19 +1763,22 @@ pub const DeclGen = struct {
17651763 fn renderFunctionSignature(
17661764 dg: *DeclGen,
17671765 w: anytype,
1768 fn_decl_index: InternPool.DeclIndex,
1766 fn_val: Value,
1767 fn_align: InternPool.Alignment,
17691768 kind: CType.Kind,
17701769 name: union(enum) {
1771 export_index: u32,
1772 ident: []const u8,
1770 decl: InternPool.DeclIndex,
17731771 fmt_ctype_pool_string: std.fmt.Formatter(formatCTypePoolString),
1772 @"export": struct {
1773 main_name: InternPool.NullTerminatedString,
1774 extern_name: InternPool.NullTerminatedString,
1775 },
17741776 },
17751777 ) !void {
17761778 const zcu = dg.zcu;
17771779 const ip = &zcu.intern_pool;
17781780
1779 const fn_decl = zcu.declPtr(fn_decl_index);
1780 const fn_ty = fn_decl.typeOf(zcu);
1781 const fn_ty = fn_val.typeOf(zcu);
17811782 const fn_ctype = try dg.ctypeFromType(fn_ty, kind);
17821783
17831784 const fn_info = zcu.typeToFunc(fn_ty).?;
......@@ -1788,7 +1789,7 @@ pub const DeclGen = struct {
17881789 else => unreachable,
17891790 }
17901791 }
1791 if (fn_decl.val.getFunction(zcu)) |func| if (func.analysis(ip).is_cold)
1792 if (fn_val.getFunction(zcu)) |func| if (func.analysis(ip).is_cold)
17921793 try w.writeAll("zig_cold ");
17931794 if (fn_info.return_type == .noreturn_type) try w.writeAll("zig_noreturn ");
17941795
......@@ -1799,22 +1800,11 @@ pub const DeclGen = struct {
17991800 trailing = .maybe_space;
18001801 }
18011802
1802 switch (kind) {
1803 .forward => {},
1804 .complete => if (fn_decl.alignment.toByteUnits()) |a| {
1805 try w.print("{}zig_align_fn({})", .{ trailing, a });
1806 trailing = .maybe_space;
1807 },
1808 else => unreachable,
1809 }
1810
1803 try w.print("{}", .{trailing});
18111804 switch (name) {
1812 .export_index => |export_index| {
1813 try w.print("{}", .{trailing});
1814 try dg.renderDeclName(w, fn_decl_index, export_index);
1815 },
1816 .ident => |ident| try w.print("{}{ }", .{ trailing, fmtIdent(ident) }),
1817 .fmt_ctype_pool_string => |fmt| try w.print("{}{ }", .{ trailing, fmt }),
1805 .decl => |decl_index| try dg.renderDeclName(w, decl_index),
1806 .fmt_ctype_pool_string => |fmt| try w.print("{ }", .{fmt}),
1807 .@"export" => |@"export"| try w.print("{ }", .{fmtIdent(@"export".extern_name.toSlice(ip))}),
18181808 }
18191809
18201810 try renderTypeSuffix(
......@@ -1833,44 +1823,30 @@ pub const DeclGen = struct {
18331823
18341824 switch (kind) {
18351825 .forward => {
1836 if (fn_decl.alignment.toByteUnits()) |a| {
1837 try w.print(" zig_align_fn({})", .{a});
1838 }
1826 if (fn_align.toByteUnits()) |a| try w.print(" zig_align_fn({})", .{a});
18391827 switch (name) {
1840 .export_index => |export_index| mangled: {
1841 const maybe_exports = zcu.decl_exports.get(fn_decl_index);
1842 const external_name = (if (maybe_exports) |exports|
1843 exports.items[export_index].opts.name
1844 else if (fn_decl.isExtern(zcu))
1845 fn_decl.name
1846 else
1847 break :mangled).toSlice(ip);
1848 const is_mangled = isMangledIdent(external_name, true);
1849 const is_export = export_index > 0;
1828 .decl, .fmt_ctype_pool_string => {},
1829 .@"export" => |@"export"| {
1830 const extern_name = @"export".extern_name.toSlice(ip);
1831 const is_mangled = isMangledIdent(extern_name, true);
1832 const is_export = @"export".extern_name != @"export".main_name;
18501833 if (is_mangled and is_export) {
18511834 try w.print(" zig_mangled_export({ }, {s}, {s})", .{
1852 fmtIdent(external_name),
1853 fmtStringLiteral(external_name, null),
1854 fmtStringLiteral(
1855 maybe_exports.?.items[0].opts.name.toSlice(ip),
1856 null,
1857 ),
1835 fmtIdent(extern_name),
1836 fmtStringLiteral(extern_name, null),
1837 fmtStringLiteral(@"export".main_name.toSlice(ip), null),
18581838 });
18591839 } else if (is_mangled) {
1860 try w.print(" zig_mangled_final({ }, {s})", .{
1861 fmtIdent(external_name), fmtStringLiteral(external_name, null),
1840 try w.print(" zig_mangled({ }, {s})", .{
1841 fmtIdent(extern_name), fmtStringLiteral(extern_name, null),
18621842 });
18631843 } else if (is_export) {
18641844 try w.print(" zig_export({s}, {s})", .{
1865 fmtStringLiteral(
1866 maybe_exports.?.items[0].opts.name.toSlice(ip),
1867 null,
1868 ),
1869 fmtStringLiteral(external_name, null),
1845 fmtStringLiteral(@"export".main_name.toSlice(ip), null),
1846 fmtStringLiteral(extern_name, null),
18701847 });
18711848 }
18721849 },
1873 .ident, .fmt_ctype_pool_string => {},
18741850 }
18751851 },
18761852 .complete => {},
......@@ -2085,21 +2061,11 @@ pub const DeclGen = struct {
20852061 try renderTypeSuffix(dg.pass, &dg.ctype_pool, dg.zcu, w, ctype, .suffix, .{});
20862062 }
20872063
2088 fn declIsGlobal(dg: *DeclGen, val: Value) bool {
2089 const zcu = dg.zcu;
2090 return switch (zcu.intern_pool.indexToKey(val.toIntern())) {
2091 .variable => |variable| zcu.decl_exports.contains(variable.decl),
2092 .extern_func => true,
2093 .func => |func| zcu.decl_exports.contains(func.owner_decl),
2094 else => unreachable,
2095 };
2096 }
2097
20982064 fn writeName(dg: *DeclGen, w: anytype, c_value: CValue) !void {
20992065 switch (c_value) {
21002066 .new_local, .local => |i| try w.print("t{d}", .{i}),
21012067 .constant => |val| try renderAnonDeclName(w, val),
2102 .decl => |decl| try dg.renderDeclName(w, decl, 0),
2068 .decl => |decl| try dg.renderDeclName(w, decl),
21032069 .identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
21042070 else => unreachable,
21052071 }
......@@ -2111,10 +2077,10 @@ pub const DeclGen = struct {
21112077 .constant => |val| try renderAnonDeclName(w, val),
21122078 .arg, .arg_array => unreachable,
21132079 .field => |i| try w.print("f{d}", .{i}),
2114 .decl => |decl| try dg.renderDeclName(w, decl, 0),
2080 .decl => |decl| try dg.renderDeclName(w, decl),
21152081 .decl_ref => |decl| {
21162082 try w.writeByte('&');
2117 try dg.renderDeclName(w, decl, 0);
2083 try dg.renderDeclName(w, decl);
21182084 },
21192085 .undef => |ty| try dg.renderUndefValue(w, ty, .Other),
21202086 .identifier => |ident| try w.print("{ }", .{fmtIdent(ident)}),
......@@ -2142,10 +2108,10 @@ pub const DeclGen = struct {
21422108 .field => |i| try w.print("f{d}", .{i}),
21432109 .decl => |decl| {
21442110 try w.writeAll("(*");
2145 try dg.renderDeclName(w, decl, 0);
2111 try dg.renderDeclName(w, decl);
21462112 try w.writeByte(')');
21472113 },
2148 .decl_ref => |decl| try dg.renderDeclName(w, decl, 0),
2114 .decl_ref => |decl| try dg.renderDeclName(w, decl),
21492115 .undef => unreachable,
21502116 .identifier => |ident| try w.print("(*{ })", .{fmtIdent(ident)}),
21512117 .payload_identifier => |ident| try w.print("(*{ }.{ })", .{
......@@ -2195,19 +2161,12 @@ pub const DeclGen = struct {
21952161 dg: *DeclGen,
21962162 decl_index: InternPool.DeclIndex,
21972163 variable: InternPool.Key.Variable,
2198 fwd_kind: enum { tentative, final },
21992164 ) !void {
22002165 const zcu = dg.zcu;
22012166 const decl = zcu.declPtr(decl_index);
22022167 const fwd = dg.fwdDeclWriter();
2203 const is_global = variable.is_extern or dg.declIsGlobal(decl.val);
2204 try fwd.writeAll(if (is_global) "zig_extern " else "static ");
2205 const maybe_exports = zcu.decl_exports.get(decl_index);
2206 const export_weak_linkage = if (maybe_exports) |exports|
2207 exports.items[0].opts.linkage == .weak
2208 else
2209 false;
2210 if (variable.is_weak_linkage or export_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
2168 try fwd.writeAll(if (variable.is_extern) "zig_extern " else "static ");
2169 if (variable.is_weak_linkage) try fwd.writeAll("zig_weak_linkage ");
22112170 if (variable.is_threadlocal and !dg.mod.single_threaded) try fwd.writeAll("zig_threadlocal ");
22122171 try dg.renderTypeAndName(
22132172 fwd,
......@@ -2217,38 +2176,17 @@ pub const DeclGen = struct {
22172176 decl.alignment,
22182177 .complete,
22192178 );
2220 mangled: {
2221 const external_name = (if (maybe_exports) |exports|
2222 exports.items[0].opts.name
2223 else if (variable.is_extern)
2224 decl.name
2225 else
2226 break :mangled).toSlice(&zcu.intern_pool);
2227 if (isMangledIdent(external_name, true)) {
2228 try fwd.print(" zig_mangled_{s}({ }, {s})", .{
2229 @tagName(fwd_kind),
2230 fmtIdent(external_name),
2231 fmtStringLiteral(external_name, null),
2232 });
2233 }
2234 }
22352179 try fwd.writeAll(";\n");
22362180 }
22372181
2238 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex, export_index: u32) !void {
2182 fn renderDeclName(dg: *DeclGen, writer: anytype, decl_index: InternPool.DeclIndex) !void {
22392183 const zcu = dg.zcu;
22402184 const ip = &zcu.intern_pool;
22412185 const decl = zcu.declPtr(decl_index);
22422186
2243 if (zcu.decl_exports.get(decl_index)) |exports| {
2244 try writer.print("{ }", .{
2245 fmtIdent(exports.items[export_index].opts.name.toSlice(ip)),
2246 });
2247 } else if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| {
2248 try writer.print("{ }", .{
2249 fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
2250 });
2251 } else {
2187 if (decl.getExternDecl(zcu).unwrap()) |extern_decl_index| try writer.print("{ }", .{
2188 fmtIdent(zcu.declPtr(extern_decl_index).name.toSlice(ip)),
2189 }) else {
22522190 // MSVC has a limit of 4095 character token length limit, and fmtIdent can (worst case),
22532191 // expand to 3x the length of its input, but let's cut it off at a much shorter limit.
22542192 var name: [100]u8 = undefined;
......@@ -2761,69 +2699,6 @@ pub fn genErrDecls(o: *Object) !void {
27612699 try writer.writeAll("};\n");
27622700}
27632701
2764fn genExports(o: *Object) !void {
2765 const tracy = trace(@src());
2766 defer tracy.end();
2767
2768 const zcu = o.dg.zcu;
2769 const ip = &zcu.intern_pool;
2770 const decl_index = switch (o.dg.pass) {
2771 .decl => |decl| decl,
2772 .anon, .flush => return,
2773 };
2774 const decl = zcu.declPtr(decl_index);
2775 const fwd = o.dg.fwdDeclWriter();
2776
2777 const exports = zcu.decl_exports.get(decl_index) orelse return;
2778 if (exports.items.len < 2) return;
2779
2780 const is_variable_const = switch (ip.indexToKey(decl.val.toIntern())) {
2781 .func => return for (exports.items[1..], 1..) |@"export", i| {
2782 try fwd.writeAll("zig_extern ");
2783 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
2784 try o.dg.renderFunctionSignature(
2785 fwd,
2786 decl_index,
2787 .forward,
2788 .{ .export_index = @intCast(i) },
2789 );
2790 try fwd.writeAll(";\n");
2791 },
2792 .extern_func => {
2793 // TODO: when sema allows re-exporting extern decls
2794 unreachable;
2795 },
2796 .variable => |variable| variable.is_const,
2797 else => true,
2798 };
2799 for (exports.items[1..]) |@"export"| {
2800 try fwd.writeAll("zig_extern ");
2801 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
2802 const export_name = @"export".opts.name.toSlice(ip);
2803 try o.dg.renderTypeAndName(
2804 fwd,
2805 decl.typeOf(zcu),
2806 .{ .identifier = export_name },
2807 CQualifiers.init(.{ .@"const" = is_variable_const }),
2808 decl.alignment,
2809 .complete,
2810 );
2811 if (isMangledIdent(export_name, true)) {
2812 try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{
2813 fmtIdent(export_name),
2814 fmtStringLiteral(export_name, null),
2815 fmtStringLiteral(exports.items[0].opts.name.toSlice(ip), null),
2816 });
2817 } else {
2818 try fwd.print(" zig_export({s}, {s})", .{
2819 fmtStringLiteral(exports.items[0].opts.name.toSlice(ip), null),
2820 fmtStringLiteral(export_name, null),
2821 });
2822 }
2823 try fwd.writeAll(";\n");
2824 }
2825}
2826
28272702pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFnMap.Entry) !void {
28282703 const zcu = o.dg.zcu;
28292704 const ip = &zcu.intern_pool;
......@@ -2885,19 +2760,19 @@ pub fn genLazyFn(o: *Object, lazy_ctype_pool: *const CType.Pool, lazy_fn: LazyFn
28852760 const fn_info = fn_ctype.info(ctype_pool).function;
28862761 const fn_name = fmtCTypePoolString(val.fn_name, lazy_ctype_pool);
28872762
2888 const fwd_decl_writer = o.dg.fwdDeclWriter();
2889 try fwd_decl_writer.print("static zig_{s} ", .{@tagName(key)});
2890 try o.dg.renderFunctionSignature(fwd_decl_writer, fn_decl_index, .forward, .{
2763 const fwd = o.dg.fwdDeclWriter();
2764 try fwd.print("static zig_{s} ", .{@tagName(key)});
2765 try o.dg.renderFunctionSignature(fwd, fn_decl.val, fn_decl.alignment, .forward, .{
28912766 .fmt_ctype_pool_string = fn_name,
28922767 });
2893 try fwd_decl_writer.writeAll(";\n");
2768 try fwd.writeAll(";\n");
28942769
2895 try w.print("static zig_{s} ", .{@tagName(key)});
2896 try o.dg.renderFunctionSignature(w, fn_decl_index, .complete, .{
2770 try w.print("zig_{s} ", .{@tagName(key)});
2771 try o.dg.renderFunctionSignature(w, fn_decl.val, .none, .complete, .{
28972772 .fmt_ctype_pool_string = fn_name,
28982773 });
28992774 try w.writeAll(" {\n return ");
2900 try o.dg.renderDeclName(w, fn_decl_index, 0);
2775 try o.dg.renderDeclName(w, fn_decl_index);
29012776 try w.writeByte('(');
29022777 for (0..fn_info.param_ctypes.len) |arg| {
29032778 if (arg > 0) try w.writeAll(", ");
......@@ -2921,21 +2796,26 @@ pub fn genFunc(f: *Function) !void {
29212796 o.code_header = std.ArrayList(u8).init(gpa);
29222797 defer o.code_header.deinit();
29232798
2924 const is_global = o.dg.declIsGlobal(decl.val);
2925 const fwd_decl_writer = o.dg.fwdDeclWriter();
2926 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
2927
2928 if (zcu.decl_exports.get(decl_index)) |exports|
2929 if (exports.items[0].opts.linkage == .weak) try fwd_decl_writer.writeAll("zig_weak_linkage_fn ");
2930 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
2931 try fwd_decl_writer.writeAll(";\n");
2932 try genExports(o);
2799 const fwd = o.dg.fwdDeclWriter();
2800 try fwd.writeAll("static ");
2801 try o.dg.renderFunctionSignature(
2802 fwd,
2803 decl.val,
2804 decl.alignment,
2805 .forward,
2806 .{ .decl = decl_index },
2807 );
2808 try fwd.writeAll(";\n");
29332809
2934 try o.indent_writer.insertNewline();
2935 if (!is_global) try o.writer().writeAll("static ");
29362810 if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
29372811 try o.writer().print("zig_linksection_fn({s}) ", .{fmtStringLiteral(s, null)});
2938 try o.dg.renderFunctionSignature(o.writer(), decl_index, .complete, .{ .export_index = 0 });
2812 try o.dg.renderFunctionSignature(
2813 o.writer(),
2814 decl.val,
2815 .none,
2816 .complete,
2817 .{ .decl = decl_index },
2818 );
29392819 try o.writer().writeByte(' ');
29402820
29412821 // In case we need to use the header, populate it with a copy of the function
......@@ -2949,7 +2829,6 @@ pub fn genFunc(f: *Function) !void {
29492829
29502830 const main_body = f.air.getMainBody();
29512831 try genBodyResolveState(f, undefined, &.{}, main_body, false);
2952
29532832 try o.indent_writer.insertNewline();
29542833
29552834 // Take advantage of the free_locals map to bucket locals per type. All
......@@ -3007,20 +2886,25 @@ pub fn genDecl(o: *Object) !void {
30072886
30082887 if (!decl_ty.isFnOrHasRuntimeBitsIgnoreComptime(zcu)) return;
30092888 if (decl.val.getExternFunc(zcu)) |_| {
3010 const fwd_decl_writer = o.dg.fwdDeclWriter();
3011 try fwd_decl_writer.writeAll("zig_extern ");
3012 try o.dg.renderFunctionSignature(fwd_decl_writer, decl_index, .forward, .{ .export_index = 0 });
3013 try fwd_decl_writer.writeAll(";\n");
3014 try genExports(o);
2889 const fwd = o.dg.fwdDeclWriter();
2890 try fwd.writeAll("zig_extern ");
2891 try o.dg.renderFunctionSignature(
2892 fwd,
2893 decl.val,
2894 decl.alignment,
2895 .forward,
2896 .{ .@"export" = .{
2897 .main_name = decl.name,
2898 .extern_name = decl.name,
2899 } },
2900 );
2901 try fwd.writeAll(";\n");
30152902 } else if (decl.val.getVariable(zcu)) |variable| {
3016 try o.dg.renderFwdDecl(decl_index, variable, .final);
3017 try genExports(o);
2903 try o.dg.renderFwdDecl(decl_index, variable);
30182904
30192905 if (variable.is_extern) return;
30202906
3021 const is_global = variable.is_extern or o.dg.declIsGlobal(decl.val);
30222907 const w = o.writer();
3023 if (!is_global) try w.writeAll("static ");
30242908 if (variable.is_weak_linkage) try w.writeAll("zig_weak_linkage ");
30252909 if (variable.is_threadlocal and !o.dg.mod.single_threaded) try w.writeAll("zig_threadlocal ");
30262910 if (decl.@"linksection".toSlice(&zcu.intern_pool)) |s|
......@@ -3032,46 +2916,27 @@ pub fn genDecl(o: *Object) !void {
30322916 try w.writeByte(';');
30332917 try o.indent_writer.insertNewline();
30342918 } else {
3035 const is_global = o.dg.zcu.decl_exports.contains(decl_index);
30362919 const decl_c_value = .{ .decl = decl_index };
3037 try genDeclValue(o, decl.val, is_global, decl_c_value, decl.alignment, decl.@"linksection");
2920 try genDeclValue(o, decl.val, decl_c_value, decl.alignment, decl.@"linksection");
30382921 }
30392922}
30402923
30412924pub fn genDeclValue(
30422925 o: *Object,
30432926 val: Value,
3044 is_global: bool,
30452927 decl_c_value: CValue,
30462928 alignment: Alignment,
30472929 @"linksection": InternPool.OptionalNullTerminatedString,
30482930) !void {
30492931 const zcu = o.dg.zcu;
3050 const fwd_decl_writer = o.dg.fwdDeclWriter();
3051
30522932 const ty = val.typeOf(zcu);
30532933
3054 try fwd_decl_writer.writeAll(if (is_global) "zig_extern " else "static ");
3055 try o.dg.renderTypeAndName(fwd_decl_writer, ty, decl_c_value, Const, alignment, .complete);
3056 switch (o.dg.pass) {
3057 .decl => |decl_index| {
3058 if (zcu.decl_exports.get(decl_index)) |exports| {
3059 const export_name = exports.items[0].opts.name.toSlice(&zcu.intern_pool);
3060 if (isMangledIdent(export_name, true)) {
3061 try fwd_decl_writer.print(" zig_mangled_final({ }, {s})", .{
3062 fmtIdent(export_name), fmtStringLiteral(export_name, null),
3063 });
3064 }
3065 }
3066 },
3067 .anon => {},
3068 .flush => unreachable,
3069 }
3070 try fwd_decl_writer.writeAll(";\n");
3071 try genExports(o);
2934 const fwd = o.dg.fwdDeclWriter();
2935 try fwd.writeAll("static ");
2936 try o.dg.renderTypeAndName(fwd, ty, decl_c_value, Const, alignment, .complete);
2937 try fwd.writeAll(";\n");
30722938
30732939 const w = o.writer();
3074 if (!is_global) try w.writeAll("static ");
30752940 if (@"linksection".toSlice(&zcu.intern_pool)) |s|
30762941 try w.print("zig_linksection({s}) ", .{fmtStringLiteral(s, null)});
30772942 try o.dg.renderTypeAndName(w, ty, decl_c_value, Const, alignment, .complete);
......@@ -3080,22 +2945,73 @@ pub fn genDeclValue(
30802945 try w.writeAll(";\n");
30812946}
30822947
3083pub fn genHeader(dg: *DeclGen) error{ AnalysisFail, OutOfMemory }!void {
3084 const tracy = trace(@src());
3085 defer tracy.end();
3086
2948pub fn genExports(dg: *DeclGen, exported: Zcu.Exported, export_indices: []const u32) !void {
30872949 const zcu = dg.zcu;
3088 const decl_index = dg.pass.decl;
3089 const decl = zcu.declPtr(decl_index);
3090 const writer = dg.fwdDeclWriter();
2950 const ip = &zcu.intern_pool;
2951 const fwd = dg.fwdDeclWriter();
30912952
3092 switch (decl.typeOf(zcu).zigTypeTag(zcu)) {
3093 .Fn => if (dg.declIsGlobal(decl.val)) {
3094 try writer.writeAll("zig_extern ");
3095 try dg.renderFunctionSignature(writer, dg.pass.decl, .complete, .{ .export_index = 0 });
3096 try dg.fwd_decl.appendSlice(";\n");
2953 const main_name = zcu.all_exports.items[export_indices[0]].opts.name;
2954 try fwd.writeAll("#define ");
2955 switch (exported) {
2956 .decl_index => |decl_index| try dg.renderDeclName(fwd, decl_index),
2957 .value => |value| try DeclGen.renderAnonDeclName(fwd, Value.fromInterned(value)),
2958 }
2959 try fwd.writeByte(' ');
2960 try fwd.print("{ }", .{fmtIdent(main_name.toSlice(ip))});
2961 try fwd.writeByte('\n');
2962
2963 const is_const = switch (ip.indexToKey(exported.getValue(zcu).toIntern())) {
2964 .func, .extern_func => return for (export_indices) |export_index| {
2965 const @"export" = &zcu.all_exports.items[export_index];
2966 try fwd.writeAll("zig_extern ");
2967 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage_fn ");
2968 try dg.renderFunctionSignature(
2969 fwd,
2970 exported.getValue(zcu),
2971 exported.getAlign(zcu),
2972 .forward,
2973 .{ .@"export" = .{
2974 .main_name = main_name,
2975 .extern_name = @"export".opts.name,
2976 } },
2977 );
2978 try fwd.writeAll(";\n");
30972979 },
3098 else => {},
2980 .variable => |variable| variable.is_const,
2981 else => true,
2982 };
2983 for (export_indices) |export_index| {
2984 const @"export" = &zcu.all_exports.items[export_index];
2985 try fwd.writeAll("zig_extern ");
2986 if (@"export".opts.linkage == .weak) try fwd.writeAll("zig_weak_linkage ");
2987 const extern_name = @"export".opts.name.toSlice(ip);
2988 const is_mangled = isMangledIdent(extern_name, true);
2989 const is_export = @"export".opts.name != main_name;
2990 try dg.renderTypeAndName(
2991 fwd,
2992 exported.getValue(zcu).typeOf(zcu),
2993 .{ .identifier = extern_name },
2994 CQualifiers.init(.{ .@"const" = is_const }),
2995 exported.getAlign(zcu),
2996 .complete,
2997 );
2998 if (is_mangled and is_export) {
2999 try fwd.print(" zig_mangled_export({ }, {s}, {s})", .{
3000 fmtIdent(extern_name),
3001 fmtStringLiteral(extern_name, null),
3002 fmtStringLiteral(main_name.toSlice(ip), null),
3003 });
3004 } else if (is_mangled) {
3005 try fwd.print(" zig_mangled({ }, {s})", .{
3006 fmtIdent(extern_name), fmtStringLiteral(extern_name, null),
3007 });
3008 } else if (is_export) {
3009 try fwd.print(" zig_export({s}, {s})", .{
3010 fmtStringLiteral(main_name.toSlice(ip), null),
3011 fmtStringLiteral(extern_name, null),
3012 });
3013 }
3014 try fwd.writeAll(";\n");
30993015 }
31003016}
31013017
......@@ -4552,7 +4468,7 @@ fn airCall(
45524468 };
45534469 };
45544470 switch (modifier) {
4555 .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl, 0),
4471 .auto, .always_tail => try f.object.dg.renderDeclName(writer, fn_decl),
45564472 inline .never_tail, .never_inline => |m| try writer.writeAll(try f.getLazyFnName(
45574473 @unionInit(LazyFnKey, @tagName(m), fn_decl),
45584474 @unionInit(LazyFnValue.Data, @tagName(m), {}),
src/codegen/c/Type.zig+1-1
......@@ -2583,6 +2583,6 @@ const assert = std.debug.assert;
25832583const CType = @This();
25842584const Module = @import("../../Package/Module.zig");
25852585const std = @import("std");
2586const Type = @import("../../type.zig").Type;
2586const Type = @import("../../Type.zig");
25872587const Zcu = @import("../../Zcu.zig");
25882588const DeclIndex = @import("../../InternPool.zig").DeclIndex;
src/codegen/llvm.zig+117-159
......@@ -22,7 +22,7 @@ const Package = @import("../Package.zig");
2222const Air = @import("../Air.zig");
2323const Liveness = @import("../Liveness.zig");
2424const Value = @import("../Value.zig");
25const Type = @import("../type.zig").Type;
25const Type = @import("../Type.zig");
2626const x86_64_abi = @import("../arch/x86_64/abi.zig");
2727const wasm_c_abi = @import("../arch/wasm/abi.zig");
2828const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
......@@ -848,10 +848,6 @@ pub const Object = struct {
848848 /// Note that the values are not added until `emit`, when all errors in
849849 /// the compilation are known.
850850 error_name_table: Builder.Variable.Index,
851 /// This map is usually very close to empty. It tracks only the cases when a
852 /// second extern Decl could not be emitted with the correct name due to a
853 /// name collision.
854 extern_collisions: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, void),
855851
856852 /// Memoizes a null `?usize` value.
857853 null_opt_usize: Builder.Constant,
......@@ -1011,7 +1007,6 @@ pub const Object = struct {
10111007 .named_enum_map = .{},
10121008 .type_map = .{},
10131009 .error_name_table = .none,
1014 .extern_collisions = .{},
10151010 .null_opt_usize = .no_init,
10161011 .struct_field_map = .{},
10171012 };
......@@ -1029,7 +1024,6 @@ pub const Object = struct {
10291024 self.anon_decl_map.deinit(gpa);
10301025 self.named_enum_map.deinit(gpa);
10311026 self.type_map.deinit(gpa);
1032 self.extern_collisions.deinit(gpa);
10331027 self.builder.deinit();
10341028 self.struct_field_map.deinit(gpa);
10351029 self.* = undefined;
......@@ -1121,61 +1115,6 @@ pub const Object = struct {
11211115 try object.builder.finishModuleAsm();
11221116 }
11231117
1124 fn resolveExportExternCollisions(object: *Object) !void {
1125 const mod = object.module;
1126
1127 // This map has externs with incorrect symbol names.
1128 for (object.extern_collisions.keys()) |decl_index| {
1129 const global = object.decl_map.get(decl_index) orelse continue;
1130 // Same logic as below but for externs instead of exports.
1131 const decl_name = object.builder.strtabStringIfExists(mod.declPtr(decl_index).name.toSlice(&mod.intern_pool)) orelse continue;
1132 const other_global = object.builder.getGlobal(decl_name) orelse continue;
1133 if (other_global.toConst().getBase(&object.builder) ==
1134 global.toConst().getBase(&object.builder)) continue;
1135
1136 try global.replace(other_global, &object.builder);
1137 }
1138 object.extern_collisions.clearRetainingCapacity();
1139
1140 for (mod.decl_exports.keys(), mod.decl_exports.values()) |decl_index, export_list| {
1141 const global = object.decl_map.get(decl_index) orelse continue;
1142 try resolveGlobalCollisions(object, global, export_list.items);
1143 }
1144
1145 for (mod.value_exports.keys(), mod.value_exports.values()) |val, export_list| {
1146 const global = object.anon_decl_map.get(val) orelse continue;
1147 try resolveGlobalCollisions(object, global, export_list.items);
1148 }
1149 }
1150
1151 fn resolveGlobalCollisions(
1152 object: *Object,
1153 global: Builder.Global.Index,
1154 export_list: []const *Module.Export,
1155 ) !void {
1156 const mod = object.module;
1157 const global_base = global.toConst().getBase(&object.builder);
1158 for (export_list) |exp| {
1159 // Detect if the LLVM global has already been created as an extern. In such
1160 // case, we need to replace all uses of it with this exported global.
1161 const exp_name = object.builder.strtabStringIfExists(exp.opts.name.toSlice(&mod.intern_pool)) orelse continue;
1162
1163 const other_global = object.builder.getGlobal(exp_name) orelse continue;
1164 if (other_global.toConst().getBase(&object.builder) == global_base) continue;
1165
1166 try global.takeName(other_global, &object.builder);
1167 try other_global.replace(global, &object.builder);
1168 // Problem: now we need to replace in the decl_map that
1169 // the extern decl index points to this new global. However we don't
1170 // know the decl index.
1171 // Even if we did, a future incremental update to the extern would then
1172 // treat the LLVM global as an extern rather than an export, so it would
1173 // need a way to check that.
1174 // This is a TODO that needs to be solved when making
1175 // the LLVM backend support incremental compilation.
1176 }
1177 }
1178
11791118 pub const EmitOptions = struct {
11801119 pre_ir_path: ?[]const u8,
11811120 pre_bc_path: ?[]const u8,
......@@ -1193,7 +1132,6 @@ pub const Object = struct {
11931132
11941133 pub fn emit(self: *Object, options: EmitOptions) !void {
11951134 {
1196 try self.resolveExportExternCollisions();
11971135 try self.genErrorNameTable();
11981136 try self.genCmpLtErrorsLenFunction();
11991137 try self.genModuleLevelAssembly();
......@@ -1698,8 +1636,7 @@ pub const Object = struct {
16981636 const file = try o.getDebugFile(namespace.file_scope);
16991637
17001638 const line_number = decl.navSrcLine(zcu) + 1;
1701 const is_internal_linkage = decl.val.getExternFunc(zcu) == null and
1702 !zcu.decl_exports.contains(decl_index);
1639 const is_internal_linkage = decl.val.getExternFunc(zcu) == null;
17031640 const debug_decl_type = try o.lowerDebugType(decl.typeOf(zcu));
17041641
17051642 const subprogram = try o.builder.debugSubprogram(
......@@ -1752,7 +1689,7 @@ pub const Object = struct {
17521689 fg.genBody(air.getMainBody()) catch |err| switch (err) {
17531690 error.CodegenFail => {
17541691 decl.analysis = .codegen_failure;
1755 try zcu.failed_decls.put(zcu.gpa, decl_index, dg.err_msg.?);
1692 try zcu.failed_analysis.put(zcu.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }), dg.err_msg.?);
17561693 dg.err_msg = null;
17571694 return;
17581695 },
......@@ -1760,8 +1697,6 @@ pub const Object = struct {
17601697 };
17611698
17621699 try fg.wip.finish();
1763
1764 try o.updateExports(zcu, .{ .decl_index = decl_index }, zcu.getDeclExports(decl_index));
17651700 }
17661701
17671702 pub fn updateDecl(self: *Object, module: *Module, decl_index: InternPool.DeclIndex) !void {
......@@ -1775,72 +1710,31 @@ pub const Object = struct {
17751710 dg.genDecl() catch |err| switch (err) {
17761711 error.CodegenFail => {
17771712 decl.analysis = .codegen_failure;
1778 try module.failed_decls.put(module.gpa, decl_index, dg.err_msg.?);
1713 try module.failed_analysis.put(module.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }), dg.err_msg.?);
17791714 dg.err_msg = null;
17801715 return;
17811716 },
17821717 else => |e| return e,
17831718 };
1784 try self.updateExports(module, .{ .decl_index = decl_index }, module.getDeclExports(decl_index));
17851719 }
17861720
17871721 pub fn updateExports(
17881722 self: *Object,
17891723 mod: *Module,
17901724 exported: Module.Exported,
1791 exports: []const *Module.Export,
1725 export_indices: []const u32,
17921726 ) link.File.UpdateExportsError!void {
17931727 const decl_index = switch (exported) {
17941728 .decl_index => |i| i,
1795 .value => |val| return updateExportedValue(self, mod, val, exports),
1729 .value => |val| return updateExportedValue(self, mod, val, export_indices),
17961730 };
1797 const gpa = mod.gpa;
17981731 const ip = &mod.intern_pool;
1799 // If the module does not already have the function, we ignore this function call
1800 // because we call `updateExports` at the end of `updateFunc` and `updateDecl`.
1801 const global_index = self.decl_map.get(decl_index) orelse return;
1732 const global_index = self.decl_map.get(decl_index).?;
18021733 const decl = mod.declPtr(decl_index);
18031734 const comp = mod.comp;
1804 if (decl.isExtern(mod)) {
1805 const decl_name = decl_name: {
1806 if (mod.getTarget().isWasm() and decl.val.typeOf(mod).zigTypeTag(mod) == .Fn) {
1807 if (decl.getOwnedExternFunc(mod).?.lib_name.toSlice(ip)) |lib_name| {
1808 if (!std.mem.eql(u8, lib_name, "c")) {
1809 break :decl_name try self.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
1810 }
1811 }
1812 }
1813 break :decl_name try self.builder.strtabString(decl.name.toSlice(ip));
1814 };
18151735
1816 if (self.builder.getGlobal(decl_name)) |other_global| {
1817 if (other_global != global_index) {
1818 try self.extern_collisions.put(gpa, decl_index, {});
1819 }
1820 }
1821
1822 try global_index.rename(decl_name, &self.builder);
1823 global_index.setLinkage(.external, &self.builder);
1824 global_index.setUnnamedAddr(.default, &self.builder);
1825 if (comp.config.dll_export_fns)
1826 global_index.setDllStorageClass(.default, &self.builder);
1827
1828 if (decl.val.getVariable(mod)) |decl_var| {
1829 global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
1830 if (decl_var.is_threadlocal) .generaldynamic else .default,
1831 &self.builder,
1832 );
1833 if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &self.builder);
1834 }
1835 } else if (exports.len != 0) {
1836 const main_exp_name = try self.builder.strtabString(exports[0].opts.name.toSlice(ip));
1837 try global_index.rename(main_exp_name, &self.builder);
1838
1839 if (decl.val.getVariable(mod)) |decl_var| if (decl_var.is_threadlocal)
1840 global_index.ptrConst(&self.builder).kind
1841 .variable.setThreadLocal(.generaldynamic, &self.builder);
1842
1843 return updateExportedGlobal(self, mod, global_index, exports);
1736 if (export_indices.len != 0) {
1737 return updateExportedGlobal(self, mod, global_index, export_indices);
18441738 } else {
18451739 const fqn = try self.builder.strtabString((try decl.fullyQualifiedName(mod)).toSlice(ip));
18461740 try global_index.rename(fqn, &self.builder);
......@@ -1848,17 +1742,6 @@ pub const Object = struct {
18481742 if (comp.config.dll_export_fns)
18491743 global_index.setDllStorageClass(.default, &self.builder);
18501744 global_index.setUnnamedAddr(.unnamed_addr, &self.builder);
1851 if (decl.val.getVariable(mod)) |decl_var| {
1852 const decl_namespace = mod.namespacePtr(decl.src_namespace);
1853 const single_threaded = decl_namespace.file_scope.mod.single_threaded;
1854 global_index.ptrConst(&self.builder).kind.variable.setThreadLocal(
1855 if (decl_var.is_threadlocal and !single_threaded)
1856 .generaldynamic
1857 else
1858 .default,
1859 &self.builder,
1860 );
1861 }
18621745 }
18631746 }
18641747
......@@ -1866,11 +1749,11 @@ pub const Object = struct {
18661749 o: *Object,
18671750 mod: *Module,
18681751 exported_value: InternPool.Index,
1869 exports: []const *Module.Export,
1752 export_indices: []const u32,
18701753 ) link.File.UpdateExportsError!void {
18711754 const gpa = mod.gpa;
18721755 const ip = &mod.intern_pool;
1873 const main_exp_name = try o.builder.strtabString(exports[0].opts.name.toSlice(ip));
1756 const main_exp_name = try o.builder.strtabString(mod.all_exports.items[export_indices[0]].opts.name.toSlice(ip));
18741757 const global_index = i: {
18751758 const gop = try o.anon_decl_map.getOrPut(gpa, exported_value);
18761759 if (gop.found_existing) {
......@@ -1894,32 +1777,57 @@ pub const Object = struct {
18941777 try variable_index.setInitializer(init_val, &o.builder);
18951778 break :i global_index;
18961779 };
1897 return updateExportedGlobal(o, mod, global_index, exports);
1780 return updateExportedGlobal(o, mod, global_index, export_indices);
18981781 }
18991782
19001783 fn updateExportedGlobal(
19011784 o: *Object,
19021785 mod: *Module,
19031786 global_index: Builder.Global.Index,
1904 exports: []const *Module.Export,
1787 export_indices: []const u32,
19051788 ) link.File.UpdateExportsError!void {
19061789 const comp = mod.comp;
19071790 const ip = &mod.intern_pool;
1791 const first_export = mod.all_exports.items[export_indices[0]];
1792
1793 // We will rename this global to have a name matching `first_export`.
1794 // Successive exports become aliases.
1795 // If the first export name already exists, then there is a corresponding
1796 // extern global - we replace it with this global.
1797 const first_exp_name = try o.builder.strtabString(first_export.opts.name.toSlice(ip));
1798 if (o.builder.getGlobal(first_exp_name)) |other_global| replace: {
1799 if (other_global.toConst().getBase(&o.builder) == global_index.toConst().getBase(&o.builder)) {
1800 break :replace; // this global already has the name we want
1801 }
1802 try global_index.takeName(other_global, &o.builder);
1803 try other_global.replace(global_index, &o.builder);
1804 // Problem: now we need to replace in the decl_map that
1805 // the extern decl index points to this new global. However we don't
1806 // know the decl index.
1807 // Even if we did, a future incremental update to the extern would then
1808 // treat the LLVM global as an extern rather than an export, so it would
1809 // need a way to check that.
1810 // This is a TODO that needs to be solved when making
1811 // the LLVM backend support incremental compilation.
1812 } else {
1813 try global_index.rename(first_exp_name, &o.builder);
1814 }
1815
19081816 global_index.setUnnamedAddr(.default, &o.builder);
19091817 if (comp.config.dll_export_fns)
19101818 global_index.setDllStorageClass(.dllexport, &o.builder);
1911 global_index.setLinkage(switch (exports[0].opts.linkage) {
1819 global_index.setLinkage(switch (first_export.opts.linkage) {
19121820 .internal => unreachable,
19131821 .strong => .external,
19141822 .weak => .weak_odr,
19151823 .link_once => .linkonce_odr,
19161824 }, &o.builder);
1917 global_index.setVisibility(switch (exports[0].opts.visibility) {
1825 global_index.setVisibility(switch (first_export.opts.visibility) {
19181826 .default => .default,
19191827 .hidden => .hidden,
19201828 .protected => .protected,
19211829 }, &o.builder);
1922 if (exports[0].opts.section.toSlice(ip)) |section|
1830 if (first_export.opts.section.toSlice(ip)) |section|
19231831 switch (global_index.ptrConst(&o.builder).kind) {
19241832 .variable => |impl_index| impl_index.setSection(
19251833 try o.builder.string(section),
......@@ -1936,7 +1844,8 @@ pub const Object = struct {
19361844 // The planned solution to this is https://github.com/ziglang/zig/issues/13265
19371845 // Until then we iterate over existing aliases and make them point
19381846 // to the correct decl, or otherwise add a new alias. Old aliases are leaked.
1939 for (exports[1..]) |exp| {
1847 for (export_indices[1..]) |export_idx| {
1848 const exp = mod.all_exports.items[export_idx];
19401849 const exp_name = try o.builder.strtabString(exp.opts.name.toSlice(ip));
19411850 if (o.builder.getGlobal(exp_name)) |global| {
19421851 switch (global.ptrConst(&o.builder).kind) {
......@@ -1944,7 +1853,13 @@ pub const Object = struct {
19441853 alias.setAliasee(global_index.toConst(), &o.builder);
19451854 continue;
19461855 },
1947 .variable, .function => {},
1856 .variable, .function => {
1857 // This existing global is an `extern` corresponding to this export.
1858 // Replace it with the global being exported.
1859 // This existing global must be replaced with the alias.
1860 try global.rename(.empty, &o.builder);
1861 try global.replace(global_index, &o.builder);
1862 },
19481863 .replaced => unreachable,
19491864 }
19501865 }
......@@ -2688,7 +2603,10 @@ pub const Object = struct {
26882603 if (!Type.fromInterned(field_ty).hasRuntimeBitsIgnoreComptime(mod)) continue;
26892604
26902605 const field_size = Type.fromInterned(field_ty).abiSize(mod);
2691 const field_align = mod.unionFieldNormalAlignment(union_type, @intCast(field_index));
2606 const field_align: InternPool.Alignment = switch (union_type.flagsPtr(ip).layout) {
2607 .@"packed" => .none,
2608 .auto, .@"extern" => mod.unionFieldNormalAlignment(union_type, @intCast(field_index)),
2609 };
26922610
26932611 const field_name = tag_type.names.get(ip)[field_index];
26942612 fields.appendAssumeCapacity(try o.builder.debugMemberType(
......@@ -4729,7 +4647,7 @@ pub const DeclGen = struct {
47294647 const o = dg.object;
47304648 const gpa = o.gpa;
47314649 const mod = o.module;
4732 const src_loc = dg.decl.navSrcLoc(mod).upgrade(mod);
4650 const src_loc = dg.decl.navSrcLoc(mod);
47334651 dg.err_msg = try Module.ErrorMsg.create(gpa, src_loc, "TODO (LLVM): " ++ format, args);
47344652 return error.CodegenFail;
47354653 }
......@@ -4762,36 +4680,77 @@ pub const DeclGen = struct {
47624680 else => try o.lowerValue(init_val),
47634681 }, &o.builder);
47644682
4683 if (decl.val.getVariable(zcu)) |decl_var| {
4684 const decl_namespace = zcu.namespacePtr(decl.src_namespace);
4685 const single_threaded = decl_namespace.file_scope.mod.single_threaded;
4686 variable_index.setThreadLocal(
4687 if (decl_var.is_threadlocal and !single_threaded) .generaldynamic else .default,
4688 &o.builder,
4689 );
4690 }
4691
47654692 const line_number = decl.navSrcLine(zcu) + 1;
4766 const is_internal_linkage = !o.module.decl_exports.contains(decl_index);
47674693
47684694 const namespace = zcu.namespacePtr(decl.src_namespace);
47694695 const owner_mod = namespace.file_scope.mod;
47704696
4771 if (owner_mod.strip) return;
4697 if (!owner_mod.strip) {
4698 const debug_file = try o.getDebugFile(namespace.file_scope);
4699
4700 const debug_global_var = try o.builder.debugGlobalVar(
4701 try o.builder.metadataString(decl.name.toSlice(ip)), // Name
4702 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
4703 debug_file, // File
4704 debug_file, // Scope
4705 line_number,
4706 try o.lowerDebugType(decl.typeOf(zcu)),
4707 variable_index,
4708 .{ .local = !decl.isExtern(zcu) },
4709 );
47724710
4773 const debug_file = try o.getDebugFile(namespace.file_scope);
4711 const debug_expression = try o.builder.debugExpression(&.{});
47744712
4775 const debug_global_var = try o.builder.debugGlobalVar(
4776 try o.builder.metadataString(decl.name.toSlice(ip)), // Name
4777 try o.builder.metadataStringFromStrtabString(variable_index.name(&o.builder)), // Linkage name
4778 debug_file, // File
4779 debug_file, // Scope
4780 line_number,
4781 try o.lowerDebugType(decl.typeOf(zcu)),
4782 variable_index,
4783 .{ .local = is_internal_linkage },
4784 );
4713 const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
4714 debug_global_var,
4715 debug_expression,
4716 );
47854717
4786 const debug_expression = try o.builder.debugExpression(&.{});
4718 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
4719 try o.debug_globals.append(o.gpa, debug_global_var_expression);
4720 }
4721 }
47874722
4788 const debug_global_var_expression = try o.builder.debugGlobalVarExpression(
4789 debug_global_var,
4790 debug_expression,
4791 );
4723 if (decl.isExtern(zcu)) {
4724 const global_index = o.decl_map.get(decl_index).?;
47924725
4793 variable_index.setGlobalVariableExpression(debug_global_var_expression, &o.builder);
4794 try o.debug_globals.append(o.gpa, debug_global_var_expression);
4726 const decl_name = decl_name: {
4727 if (zcu.getTarget().isWasm() and decl.typeOf(zcu).zigTypeTag(zcu) == .Fn) {
4728 if (decl.getOwnedExternFunc(zcu).?.lib_name.toSlice(ip)) |lib_name| {
4729 if (!std.mem.eql(u8, lib_name, "c")) {
4730 break :decl_name try o.builder.strtabStringFmt("{}|{s}", .{ decl.name.fmt(ip), lib_name });
4731 }
4732 }
4733 }
4734 break :decl_name try o.builder.strtabString(decl.name.toSlice(ip));
4735 };
4736
4737 if (o.builder.getGlobal(decl_name)) |other_global| {
4738 if (other_global != global_index) {
4739 // Another global already has this name; just use it in place of this global.
4740 try global_index.replace(other_global, &o.builder);
4741 return;
4742 }
4743 }
4744
4745 try global_index.rename(decl_name, &o.builder);
4746 global_index.setLinkage(.external, &o.builder);
4747 global_index.setUnnamedAddr(.default, &o.builder);
4748 if (zcu.comp.config.dll_export_fns)
4749 global_index.setDllStorageClass(.default, &o.builder);
4750
4751 if (decl.val.getVariable(zcu)) |decl_var| {
4752 if (decl_var.is_weak_linkage) global_index.setLinkage(.extern_weak, &o.builder);
4753 }
47954754 }
47964755 }
47974756};
......@@ -5193,7 +5152,6 @@ pub const FuncGen = struct {
51935152
51945153 const fqn = try decl.fullyQualifiedName(zcu);
51955154
5196 const is_internal_linkage = !zcu.decl_exports.contains(decl_index);
51975155 const fn_ty = try zcu.funcType(.{
51985156 .param_types = &.{},
51995157 .return_type = .void_type,
......@@ -5211,7 +5169,7 @@ pub const FuncGen = struct {
52115169 .sp_flags = .{
52125170 .Optimized = owner_mod.optimize_mode != .Debug,
52135171 .Definition = true,
5214 .LocalToUnit = is_internal_linkage,
5172 .LocalToUnit = true, // TODO: we can't know this at this point, since the function could be exported later!
52155173 },
52165174 },
52175175 o.debug_compile_unit,
src/codegen/spirv.zig+4-4
......@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");
99/// Deprecated.
1010const Module = Zcu;
1111const Decl = Module.Decl;
12const Type = @import("../type.zig").Type;
12const Type = @import("../Type.zig");
1313const Value = @import("../Value.zig");
1414const Air = @import("../Air.zig");
1515const Liveness = @import("../Liveness.zig");
......@@ -218,7 +218,7 @@ pub const Object = struct {
218218
219219 decl_gen.genDecl() catch |err| switch (err) {
220220 error.CodegenFail => {
221 try mod.failed_decls.put(mod.gpa, decl_index, decl_gen.error_msg.?);
221 try mod.failed_analysis.put(mod.gpa, InternPool.AnalUnit.wrap(.{ .decl = decl_index }), decl_gen.error_msg.?);
222222 },
223223 else => |other| {
224224 // There might be an error that happened *after* self.error_msg
......@@ -415,7 +415,7 @@ const DeclGen = struct {
415415 pub fn fail(self: *DeclGen, comptime format: []const u8, args: anytype) Error {
416416 @setCold(true);
417417 const mod = self.module;
418 const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod).upgrade(mod);
418 const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod);
419419 assert(self.error_msg == null);
420420 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, format, args);
421421 return error.CodegenFail;
......@@ -6439,7 +6439,7 @@ const DeclGen = struct {
64396439 // TODO: Translate proper error locations.
64406440 assert(as.errors.items.len != 0);
64416441 assert(self.error_msg == null);
6442 const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod).upgrade(mod);
6442 const src_loc = self.module.declPtr(self.decl_index).navSrcLoc(mod);
64436443 self.error_msg = try Module.ErrorMsg.create(self.module.gpa, src_loc, "failed to assemble SPIR-V inline assembly", .{});
64446444 const notes = try self.module.gpa.alloc(Module.ErrorMsg, as.errors.items.len);
64456445
src/link.zig+8-9
......@@ -18,7 +18,7 @@ const Zcu = @import("Zcu.zig");
1818/// Deprecated.
1919const Module = Zcu;
2020const InternPool = @import("InternPool.zig");
21const Type = @import("type.zig").Type;
21const Type = @import("Type.zig");
2222const Value = @import("Value.zig");
2323const LlvmObject = @import("codegen/llvm.zig").Object;
2424const lldMain = @import("main.zig").lldMain;
......@@ -606,12 +606,12 @@ pub const File = struct {
606606 base: *File,
607607 module: *Module,
608608 exported: Module.Exported,
609 exports: []const *Module.Export,
609 export_indices: []const u32,
610610 ) UpdateExportsError!void {
611611 switch (base.tag) {
612612 inline else => |tag| {
613613 if (tag != .c and build_options.only_c) unreachable;
614 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(module, exported, exports);
614 return @as(*tag.Type(), @fieldParentPtr("base", base)).updateExports(module, exported, export_indices);
615615 },
616616 }
617617 }
......@@ -646,7 +646,7 @@ pub const File = struct {
646646 base: *File,
647647 decl_val: InternPool.Index,
648648 decl_align: InternPool.Alignment,
649 src_loc: Module.SrcLoc,
649 src_loc: Module.LazySrcLoc,
650650 ) !LowerResult {
651651 if (build_options.only_c) @compileError("unreachable");
652652 switch (base.tag) {
......@@ -671,21 +671,20 @@ pub const File = struct {
671671 }
672672 }
673673
674 pub fn deleteDeclExport(
674 pub fn deleteExport(
675675 base: *File,
676 decl_index: InternPool.DeclIndex,
676 exported: Zcu.Exported,
677677 name: InternPool.NullTerminatedString,
678 ) !void {
678 ) void {
679679 if (build_options.only_c) @compileError("unreachable");
680680 switch (base.tag) {
681681 .plan9,
682 .c,
683682 .spirv,
684683 .nvptx,
685684 => {},
686685
687686 inline else => |tag| {
688 return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteDeclExport(decl_index, name);
687 return @as(*tag.Type(), @fieldParentPtr("base", base)).deleteExport(exported, name);
689688 },
690689 }
691690 }
src/link/C.zig+141-31
......@@ -14,7 +14,7 @@ const Compilation = @import("../Compilation.zig");
1414const codegen = @import("../codegen/c.zig");
1515const link = @import("../link.zig");
1616const trace = @import("../tracy.zig").trace;
17const Type = @import("../type.zig").Type;
17const Type = @import("../Type.zig");
1818const Value = @import("../Value.zig");
1919const Air = @import("../Air.zig");
2020const Liveness = @import("../Liveness.zig");
......@@ -39,6 +39,9 @@ anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, DeclBlock) = .{},
3939/// the keys of `anon_decls`.
4040aligned_anon_decls: std.AutoArrayHashMapUnmanaged(InternPool.Index, Alignment) = .{},
4141
42exported_decls: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, ExportedBlock) = .{},
43exported_values: std.AutoArrayHashMapUnmanaged(InternPool.Index, ExportedBlock) = .{},
44
4245/// Optimization, `updateDecl` reuses this buffer rather than creating a new
4346/// one with every call.
4447fwd_decl_buf: std.ArrayListUnmanaged(u8) = .{},
......@@ -80,6 +83,11 @@ pub const DeclBlock = struct {
8083 }
8184};
8285
86/// Per-exported-symbol data.
87pub const ExportedBlock = struct {
88 fwd_decl: String = String.empty,
89};
90
8391pub fn getString(this: C, s: String) []const u8 {
8492 return this.string_bytes.items[s.start..][0..s.len];
8593}
......@@ -238,9 +246,13 @@ pub fn updateFunc(
238246 function.deinit();
239247 }
240248
249 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
241250 codegen.genFunc(&function) catch |err| switch (err) {
242251 error.AnalysisFail => {
243 try zcu.failed_decls.put(gpa, decl_index, function.object.dg.error_msg.?);
252 zcu.failed_analysis.putAssumeCapacityNoClobber(
253 InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
254 function.object.dg.error_msg.?,
255 );
244256 return;
245257 },
246258 else => |e| return e,
......@@ -288,7 +300,7 @@ fn updateAnonDecl(self: *C, zcu: *Zcu, i: usize) !void {
288300
289301 const c_value: codegen.CValue = .{ .constant = Value.fromInterned(anon_decl) };
290302 const alignment: Alignment = self.aligned_anon_decls.get(anon_decl) orelse .none;
291 codegen.genDeclValue(&object, c_value.constant, false, c_value, alignment, .none) catch |err| switch (err) {
303 codegen.genDeclValue(&object, c_value.constant, c_value, alignment, .none) catch |err| switch (err) {
292304 error.AnalysisFail => {
293305 @panic("TODO: C backend AnalysisFail on anonymous decl");
294306 //try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
......@@ -351,9 +363,13 @@ pub fn updateDecl(self: *C, zcu: *Zcu, decl_index: InternPool.DeclIndex) !void {
351363 code.* = object.code.moveToUnmanaged();
352364 }
353365
366 try zcu.failed_analysis.ensureUnusedCapacity(gpa, 1);
354367 codegen.genDecl(&object) catch |err| switch (err) {
355368 error.AnalysisFail => {
356 try zcu.failed_decls.put(gpa, decl_index, object.dg.error_msg.?);
369 zcu.failed_analysis.putAssumeCapacityNoClobber(
370 InternPool.AnalUnit.wrap(.{ .decl = decl_index }),
371 object.dg.error_msg.?,
372 );
357373 return;
358374 },
359375 else => |e| return e,
......@@ -451,20 +467,40 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
451467 {
452468 var export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
453469 defer export_names.deinit(gpa);
454 try export_names.ensureTotalCapacity(gpa, @intCast(zcu.decl_exports.entries.len));
455 for (zcu.decl_exports.values()) |exports| for (exports.items) |@"export"|
456 try export_names.put(gpa, @"export".opts.name, {});
457
458 for (self.anon_decls.values()) |*decl_block| {
459 try self.flushDeclBlock(zcu, zcu.root_mod, &f, decl_block, export_names, .none);
470 try export_names.ensureTotalCapacity(gpa, @intCast(zcu.single_exports.count()));
471 for (zcu.single_exports.values()) |export_index| {
472 export_names.putAssumeCapacity(zcu.all_exports.items[export_index].opts.name, {});
473 }
474 for (zcu.multi_exports.values()) |info| {
475 try export_names.ensureUnusedCapacity(gpa, info.len);
476 for (zcu.all_exports.items[info.index..][0..info.len]) |@"export"| {
477 export_names.putAssumeCapacity(@"export".opts.name, {});
478 }
460479 }
461480
481 for (self.anon_decls.keys(), self.anon_decls.values()) |value, *decl_block| try self.flushDeclBlock(
482 zcu,
483 zcu.root_mod,
484 &f,
485 decl_block,
486 self.exported_values.getPtr(value),
487 export_names,
488 .none,
489 );
490
462491 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, *decl_block| {
463492 const decl = zcu.declPtr(decl_index);
464 assert(decl.has_tv);
465 const extern_symbol_name = if (decl.isExtern(zcu)) decl.name.toOptional() else .none;
493 const extern_name = if (decl.isExtern(zcu)) decl.name.toOptional() else .none;
466494 const mod = zcu.namespacePtr(decl.src_namespace).file_scope.mod;
467 try self.flushDeclBlock(zcu, mod, &f, decl_block, export_names, extern_symbol_name);
495 try self.flushDeclBlock(
496 zcu,
497 mod,
498 &f,
499 decl_block,
500 self.exported_decls.getPtr(decl_index),
501 export_names,
502 extern_name,
503 );
468504 }
469505 }
470506
......@@ -497,12 +533,27 @@ pub fn flushModule(self: *C, arena: Allocator, prog_node: std.Progress.Node) !vo
497533 f.file_size += lazy_fwd_decl_len;
498534
499535 // Now the code.
500 const anon_decl_values = self.anon_decls.values();
501 const decl_values = self.decl_table.values();
502 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + anon_decl_values.len + decl_values.len);
536 try f.all_buffers.ensureUnusedCapacity(gpa, 1 + (self.anon_decls.count() + self.decl_table.count()) * 2);
503537 f.appendBufAssumeCapacity(self.lazy_code_buf.items);
504 for (anon_decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
505 for (decl_values) |db| f.appendBufAssumeCapacity(self.getString(db.code));
538 for (self.anon_decls.keys(), self.anon_decls.values()) |anon_decl, decl_block| f.appendCodeAssumeCapacity(
539 if (self.exported_values.contains(anon_decl))
540 .default
541 else switch (zcu.intern_pool.indexToKey(anon_decl)) {
542 .extern_func => .zig_extern,
543 .variable => |variable| if (variable.is_extern) .zig_extern else .static,
544 else => .static,
545 },
546 self.getString(decl_block.code),
547 );
548 for (self.decl_table.keys(), self.decl_table.values()) |decl_index, decl_block| f.appendCodeAssumeCapacity(
549 if (self.exported_decls.contains(decl_index))
550 .default
551 else if (zcu.declPtr(decl_index).isExtern(zcu))
552 .zig_extern
553 else
554 .static,
555 self.getString(decl_block.code),
556 );
506557
507558 const file = self.base.file.?;
508559 try file.setEndPos(f.file_size);
......@@ -532,6 +583,16 @@ const Flush = struct {
532583 f.file_size += buf.len;
533584 }
534585
586 fn appendCodeAssumeCapacity(f: *Flush, storage: enum { default, zig_extern, static }, code: []const u8) void {
587 if (code.len == 0) return;
588 f.appendBufAssumeCapacity(switch (storage) {
589 .default => "\n",
590 .zig_extern => "\nzig_extern ",
591 .static => "\nstatic ",
592 });
593 f.appendBufAssumeCapacity(code);
594 }
595
535596 fn deinit(f: *Flush, gpa: Allocator) void {
536597 f.all_buffers.deinit(gpa);
537598 f.asm_buf.deinit(gpa);
......@@ -719,19 +780,20 @@ fn flushDeclBlock(
719780 zcu: *Zcu,
720781 mod: *Module,
721782 f: *Flush,
722 decl_block: *DeclBlock,
783 decl_block: *const DeclBlock,
784 exported_block: ?*const ExportedBlock,
723785 export_names: std.AutoHashMapUnmanaged(InternPool.NullTerminatedString, void),
724 extern_symbol_name: InternPool.OptionalNullTerminatedString,
786 extern_name: InternPool.OptionalNullTerminatedString,
725787) FlushDeclError!void {
726788 const gpa = self.base.comp.gpa;
727789 try self.flushLazyFns(zcu, mod, f, &decl_block.ctype_pool, decl_block.lazy_fns);
728790 try f.all_buffers.ensureUnusedCapacity(gpa, 1);
729 fwd_decl: {
730 if (extern_symbol_name.unwrap()) |name| {
731 if (export_names.contains(name)) break :fwd_decl;
732 }
733 f.appendBufAssumeCapacity(self.getString(decl_block.fwd_decl));
734 }
791 // avoid emitting extern decls that are already exported
792 if (extern_name.unwrap()) |name| if (export_names.contains(name)) return;
793 f.appendBufAssumeCapacity(self.getString(if (exported_block) |exported|
794 exported.fwd_decl
795 else
796 decl_block.fwd_decl));
735797}
736798
737799pub fn flushEmitH(zcu: *Zcu) !void {
......@@ -781,10 +843,58 @@ pub fn updateExports(
781843 self: *C,
782844 zcu: *Zcu,
783845 exported: Zcu.Exported,
784 exports: []const *Zcu.Export,
846 export_indices: []const u32,
785847) !void {
786 _ = exports;
787 _ = exported;
788 _ = zcu;
789 _ = self;
848 const gpa = self.base.comp.gpa;
849 const mod, const pass: codegen.DeclGen.Pass, const decl_block, const exported_block = switch (exported) {
850 .decl_index => |decl_index| .{
851 zcu.namespacePtr(zcu.declPtr(decl_index).src_namespace).file_scope.mod,
852 .{ .decl = decl_index },
853 self.decl_table.getPtr(decl_index).?,
854 (try self.exported_decls.getOrPut(gpa, decl_index)).value_ptr,
855 },
856 .value => |value| .{
857 zcu.root_mod,
858 .{ .anon = value },
859 self.anon_decls.getPtr(value).?,
860 (try self.exported_values.getOrPut(gpa, value)).value_ptr,
861 },
862 };
863 const ctype_pool = &decl_block.ctype_pool;
864 const fwd_decl = &self.fwd_decl_buf;
865 fwd_decl.clearRetainingCapacity();
866 var dg: codegen.DeclGen = .{
867 .gpa = gpa,
868 .zcu = zcu,
869 .mod = mod,
870 .error_msg = null,
871 .pass = pass,
872 .is_naked_fn = false,
873 .fwd_decl = fwd_decl.toManaged(gpa),
874 .ctype_pool = decl_block.ctype_pool,
875 .scratch = .{},
876 .anon_decl_deps = .{},
877 .aligned_anon_decls = .{},
878 };
879 defer {
880 assert(dg.anon_decl_deps.count() == 0);
881 assert(dg.aligned_anon_decls.count() == 0);
882 fwd_decl.* = dg.fwd_decl.moveToUnmanaged();
883 ctype_pool.* = dg.ctype_pool.move();
884 ctype_pool.freeUnusedCapacity(gpa);
885 dg.scratch.deinit(gpa);
886 }
887 try codegen.genExports(&dg, exported, export_indices);
888 exported_block.* = .{ .fwd_decl = try self.addString(dg.fwd_decl.items) };
889}
890
891pub fn deleteExport(
892 self: *C,
893 exported: Zcu.Exported,
894 _: InternPool.NullTerminatedString,
895) void {
896 switch (exported) {
897 .decl_index => |decl_index| _ = self.exported_decls.swapRemove(decl_index),
898 .value => |value| _ = self.exported_values.swapRemove(value),
899 }
790900}
src/link/Coff.zig+32-37
......@@ -1144,7 +1144,7 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
11441144
11451145 const res = try codegen.generateFunction(
11461146 &self.base,
1147 decl.navSrcLoc(mod).upgrade(mod),
1147 decl.navSrcLoc(mod),
11481148 func_index,
11491149 air,
11501150 liveness,
......@@ -1155,16 +1155,14 @@ pub fn updateFunc(self: *Coff, mod: *Module, func_index: InternPool.Index, air:
11551155 .ok => code_buffer.items,
11561156 .fail => |em| {
11571157 func.analysis(&mod.intern_pool).state = .codegen_failure;
1158 try mod.failed_decls.put(mod.gpa, decl_index, em);
1158 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
11591159 return;
11601160 },
11611161 };
11621162
11631163 try self.updateDeclCode(decl_index, code, .FUNCTION);
11641164
1165 // Since we updated the vaddr and the size, each corresponding export
1166 // symbol also needs to be updated.
1167 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1165 // Exports will be updated by `Zcu.processExports` after the update.
11681166}
11691167
11701168pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclIndex) !u32 {
......@@ -1181,11 +1179,11 @@ pub fn lowerUnnamedConst(self: *Coff, val: Value, decl_index: InternPool.DeclInd
11811179 const sym_name = try std.fmt.allocPrint(gpa, "__unnamed_{}_{d}", .{ decl_name.fmt(&mod.intern_pool), index });
11821180 defer gpa.free(sym_name);
11831181 const ty = val.typeOf(mod);
1184 const atom_index = switch (try self.lowerConst(sym_name, val, ty.abiAlignment(mod), self.rdata_section_index.?, decl.navSrcLoc(mod).upgrade(mod))) {
1182 const atom_index = switch (try self.lowerConst(sym_name, val, ty.abiAlignment(mod), self.rdata_section_index.?, decl.navSrcLoc(mod))) {
11851183 .ok => |atom_index| atom_index,
11861184 .fail => |em| {
11871185 decl.analysis = .codegen_failure;
1188 try mod.failed_decls.put(mod.gpa, decl_index, em);
1186 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
11891187 log.err("{s}", .{em.msg});
11901188 return error.CodegenFail;
11911189 },
......@@ -1199,7 +1197,7 @@ const LowerConstResult = union(enum) {
11991197 fail: *Module.ErrorMsg,
12001198};
12011199
1202fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.SrcLoc) !LowerConstResult {
1200fn lowerConst(self: *Coff, name: []const u8, val: Value, required_alignment: InternPool.Alignment, sect_id: u16, src_loc: Module.LazySrcLoc) !LowerConstResult {
12031201 const gpa = self.base.comp.gpa;
12041202
12051203 var code_buffer = std.ArrayList(u8).init(gpa);
......@@ -1272,23 +1270,21 @@ pub fn updateDecl(
12721270 defer code_buffer.deinit();
12731271
12741272 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
1275 const res = try codegen.generateSymbol(&self.base, decl.navSrcLoc(mod).upgrade(mod), decl_val, &code_buffer, .none, .{
1273 const res = try codegen.generateSymbol(&self.base, decl.navSrcLoc(mod), decl_val, &code_buffer, .none, .{
12761274 .parent_atom_index = atom.getSymbolIndex().?,
12771275 });
12781276 const code = switch (res) {
12791277 .ok => code_buffer.items,
12801278 .fail => |em| {
12811279 decl.analysis = .codegen_failure;
1282 try mod.failed_decls.put(mod.gpa, decl_index, em);
1280 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
12831281 return;
12841282 },
12851283 };
12861284
12871285 try self.updateDeclCode(decl_index, code, .NULL);
12881286
1289 // Since we updated the vaddr and the size, each corresponding export
1290 // symbol also needs to be updated.
1291 return self.updateExports(mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1287 // Exports will be updated by `Zcu.processExports` after the update.
12921288}
12931289
12941290fn updateLazySymbolAtom(
......@@ -1313,14 +1309,7 @@ fn updateLazySymbolAtom(
13131309 const atom = self.getAtomPtr(atom_index);
13141310 const local_sym_index = atom.getSymbolIndex().?;
13151311
1316 const src = if (sym.ty.srcLocOrNull(mod)) |src|
1317 src.upgrade(mod)
1318 else
1319 Module.SrcLoc{
1320 .file_scope = undefined,
1321 .base_node = undefined,
1322 .lazy = .unneeded,
1323 };
1312 const src = sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
13241313 const res = try codegen.generateLazySymbol(
13251314 &self.base,
13261315 src,
......@@ -1509,7 +1498,7 @@ pub fn updateExports(
15091498 self: *Coff,
15101499 mod: *Module,
15111500 exported: Module.Exported,
1512 exports: []const *Module.Export,
1501 export_indices: []const u32,
15131502) link.File.UpdateExportsError!void {
15141503 if (build_options.skip_non_native and builtin.object_format != .coff) {
15151504 @panic("Attempted to compile for object format that was disabled by build configuration");
......@@ -1522,7 +1511,8 @@ pub fn updateExports(
15221511 if (comp.config.use_llvm) {
15231512 // Even in the case of LLVM, we need to notice certain exported symbols in order to
15241513 // detect the default subsystem.
1525 for (exports) |exp| {
1514 for (export_indices) |export_idx| {
1515 const exp = mod.all_exports.items[export_idx];
15261516 const exported_decl_index = switch (exp.exported) {
15271517 .decl_index => |i| i,
15281518 .value => continue,
......@@ -1552,7 +1542,7 @@ pub fn updateExports(
15521542 }
15531543 }
15541544
1555 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
1545 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
15561546
15571547 const gpa = comp.gpa;
15581548
......@@ -1562,15 +1552,15 @@ pub fn updateExports(
15621552 break :blk self.decls.getPtr(decl_index).?;
15631553 },
15641554 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1565 const first_exp = exports[0];
1566 const res = try self.lowerAnonDecl(value, .none, first_exp.getSrcLoc(mod));
1555 const first_exp = mod.all_exports.items[export_indices[0]];
1556 const res = try self.lowerAnonDecl(value, .none, first_exp.src);
15671557 switch (res) {
15681558 .ok => {},
15691559 .fail => |em| {
15701560 // TODO maybe it's enough to return an error here and let Module.processExportsInner
15711561 // handle the error?
15721562 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1573 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1563 mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
15741564 return;
15751565 },
15761566 }
......@@ -1580,14 +1570,15 @@ pub fn updateExports(
15801570 const atom_index = metadata.atom;
15811571 const atom = self.getAtom(atom_index);
15821572
1583 for (exports) |exp| {
1573 for (export_indices) |export_idx| {
1574 const exp = mod.all_exports.items[export_idx];
15841575 log.debug("adding new export '{}'", .{exp.opts.name.fmt(&mod.intern_pool)});
15851576
15861577 if (exp.opts.section.toSlice(&mod.intern_pool)) |section_name| {
15871578 if (!mem.eql(u8, section_name, ".text")) {
1588 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1579 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
15891580 gpa,
1590 exp.getSrcLoc(mod),
1581 exp.src,
15911582 "Unimplemented: ExportOptions.section",
15921583 .{},
15931584 ));
......@@ -1596,9 +1587,9 @@ pub fn updateExports(
15961587 }
15971588
15981589 if (exp.opts.linkage == .link_once) {
1599 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
1590 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
16001591 gpa,
1601 exp.getSrcLoc(mod),
1592 exp.src,
16021593 "Unimplemented: GlobalLinkage.link_once",
16031594 .{},
16041595 ));
......@@ -1641,13 +1632,16 @@ pub fn updateExports(
16411632 }
16421633}
16431634
1644pub fn deleteDeclExport(
1635pub fn deleteExport(
16451636 self: *Coff,
1646 decl_index: InternPool.DeclIndex,
1637 exported: Zcu.Exported,
16471638 name: InternPool.NullTerminatedString,
16481639) void {
16491640 if (self.llvm_object) |_| return;
1650 const metadata = self.decls.getPtr(decl_index) orelse return;
1641 const metadata = switch (exported) {
1642 .decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
1643 .value => |value| self.anon_decls.getPtr(value) orelse return,
1644 };
16511645 const mod = self.base.comp.module.?;
16521646 const name_slice = name.toSlice(&mod.intern_pool);
16531647 const sym_index = metadata.getExportPtr(self, name_slice) orelse return;
......@@ -1866,7 +1860,7 @@ pub fn lowerAnonDecl(
18661860 self: *Coff,
18671861 decl_val: InternPool.Index,
18681862 explicit_alignment: InternPool.Alignment,
1869 src_loc: Module.SrcLoc,
1863 src_loc: Module.LazySrcLoc,
18701864) !codegen.Result {
18711865 const gpa = self.base.comp.gpa;
18721866 const mod = self.base.comp.module.?;
......@@ -2748,8 +2742,9 @@ const Object = @import("Coff/Object.zig");
27482742const Relocation = @import("Coff/Relocation.zig");
27492743const TableSection = @import("table_section.zig").TableSection;
27502744const StringTable = @import("StringTable.zig");
2751const Type = @import("../type.zig").Type;
2745const Type = @import("../Type.zig");
27522746const Value = @import("../Value.zig");
2747const AnalUnit = InternPool.AnalUnit;
27532748
27542749pub const base_tag: link.File.Tag = .coff;
27552750
src/link/Dwarf.zig+1-1
......@@ -2969,5 +2969,5 @@ const Zcu = @import("../Zcu.zig");
29692969const Module = Zcu;
29702970const InternPool = @import("../InternPool.zig");
29712971const StringTable = @import("StringTable.zig");
2972const Type = @import("../type.zig").Type;
2972const Type = @import("../Type.zig");
29732973const Value = @import("../Value.zig");
src/link/Elf.zig+7-7
......@@ -552,7 +552,7 @@ pub fn lowerAnonDecl(
552552 self: *Elf,
553553 decl_val: InternPool.Index,
554554 explicit_alignment: InternPool.Alignment,
555 src_loc: Module.SrcLoc,
555 src_loc: Module.LazySrcLoc,
556556) !codegen.Result {
557557 return self.zigObjectPtr().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
558558}
......@@ -3011,13 +3011,13 @@ pub fn updateExports(
30113011 self: *Elf,
30123012 mod: *Module,
30133013 exported: Module.Exported,
3014 exports: []const *Module.Export,
3014 export_indices: []const u32,
30153015) link.File.UpdateExportsError!void {
30163016 if (build_options.skip_non_native and builtin.object_format != .elf) {
30173017 @panic("Attempted to compile for object format that was disabled by build configuration");
30183018 }
3019 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3020 return self.zigObjectPtr().?.updateExports(self, mod, exported, exports);
3019 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
3020 return self.zigObjectPtr().?.updateExports(self, mod, exported, export_indices);
30213021}
30223022
30233023pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: InternPool.DeclIndex) !void {
......@@ -3025,13 +3025,13 @@ pub fn updateDeclLineNumber(self: *Elf, mod: *Module, decl_index: InternPool.Dec
30253025 return self.zigObjectPtr().?.updateDeclLineNumber(mod, decl_index);
30263026}
30273027
3028pub fn deleteDeclExport(
3028pub fn deleteExport(
30293029 self: *Elf,
3030 decl_index: InternPool.DeclIndex,
3030 exported: Zcu.Exported,
30313031 name: InternPool.NullTerminatedString,
30323032) void {
30333033 if (self.llvm_object) |_| return;
3034 return self.zigObjectPtr().?.deleteDeclExport(self, decl_index, name);
3034 return self.zigObjectPtr().?.deleteExport(self, exported, name);
30353035}
30363036
30373037fn addLinkerDefinedSymbols(self: *Elf) !void {
src/link/Elf/ZigObject.zig+31-37
......@@ -686,7 +686,7 @@ pub fn lowerAnonDecl(
686686 elf_file: *Elf,
687687 decl_val: InternPool.Index,
688688 explicit_alignment: InternPool.Alignment,
689 src_loc: Module.SrcLoc,
689 src_loc: Module.LazySrcLoc,
690690) !codegen.Result {
691691 const gpa = elf_file.base.comp.gpa;
692692 const mod = elf_file.base.comp.module.?;
......@@ -1074,7 +1074,7 @@ pub fn updateFunc(
10741074 const res = if (decl_state) |*ds|
10751075 try codegen.generateFunction(
10761076 &elf_file.base,
1077 decl.navSrcLoc(mod).upgrade(mod),
1077 decl.navSrcLoc(mod),
10781078 func_index,
10791079 air,
10801080 liveness,
......@@ -1084,7 +1084,7 @@ pub fn updateFunc(
10841084 else
10851085 try codegen.generateFunction(
10861086 &elf_file.base,
1087 decl.navSrcLoc(mod).upgrade(mod),
1087 decl.navSrcLoc(mod),
10881088 func_index,
10891089 air,
10901090 liveness,
......@@ -1096,7 +1096,7 @@ pub fn updateFunc(
10961096 .ok => code_buffer.items,
10971097 .fail => |em| {
10981098 func.analysis(&mod.intern_pool).state = .codegen_failure;
1099 try mod.failed_decls.put(mod.gpa, decl_index, em);
1099 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
11001100 return;
11011101 },
11021102 };
......@@ -1115,9 +1115,7 @@ pub fn updateFunc(
11151115 );
11161116 }
11171117
1118 // Since we updated the vaddr and the size, each corresponding export
1119 // symbol also needs to be updated.
1120 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1118 // Exports will be updated by `Zcu.processExports` after the update.
11211119}
11221120
11231121pub fn updateDecl(
......@@ -1158,13 +1156,13 @@ pub fn updateDecl(
11581156 // TODO implement .debug_info for global variables
11591157 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
11601158 const res = if (decl_state) |*ds|
1161 try codegen.generateSymbol(&elf_file.base, decl.navSrcLoc(mod).upgrade(mod), decl_val, &code_buffer, .{
1159 try codegen.generateSymbol(&elf_file.base, decl.navSrcLoc(mod), decl_val, &code_buffer, .{
11621160 .dwarf = ds,
11631161 }, .{
11641162 .parent_atom_index = sym_index,
11651163 })
11661164 else
1167 try codegen.generateSymbol(&elf_file.base, decl.navSrcLoc(mod).upgrade(mod), decl_val, &code_buffer, .none, .{
1165 try codegen.generateSymbol(&elf_file.base, decl.navSrcLoc(mod), decl_val, &code_buffer, .none, .{
11681166 .parent_atom_index = sym_index,
11691167 });
11701168
......@@ -1172,7 +1170,7 @@ pub fn updateDecl(
11721170 .ok => code_buffer.items,
11731171 .fail => |em| {
11741172 decl.analysis = .codegen_failure;
1175 try mod.failed_decls.put(mod.gpa, decl_index, em);
1173 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
11761174 return;
11771175 },
11781176 };
......@@ -1194,9 +1192,7 @@ pub fn updateDecl(
11941192 );
11951193 }
11961194
1197 // Since we updated the vaddr and the size, each corresponding export
1198 // symbol also needs to be updated.
1199 return self.updateExports(elf_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
1195 // Exports will be updated by `Zcu.processExports` after the update.
12001196}
12011197
12021198fn updateLazySymbol(
......@@ -1221,14 +1217,7 @@ fn updateLazySymbol(
12211217 break :blk try self.strtab.insert(gpa, name);
12221218 };
12231219
1224 const src = if (sym.ty.srcLocOrNull(mod)) |src|
1225 src.upgrade(mod)
1226 else
1227 Module.SrcLoc{
1228 .file_scope = undefined,
1229 .base_node = undefined,
1230 .lazy = .unneeded,
1231 };
1220 const src = sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
12321221 const res = try codegen.generateLazySymbol(
12331222 &elf_file.base,
12341223 src,
......@@ -1306,12 +1295,12 @@ pub fn lowerUnnamedConst(
13061295 val,
13071296 ty.abiAlignment(mod),
13081297 elf_file.zig_data_rel_ro_section_index.?,
1309 decl.navSrcLoc(mod).upgrade(mod),
1298 decl.navSrcLoc(mod),
13101299 )) {
13111300 .ok => |sym_index| sym_index,
13121301 .fail => |em| {
13131302 decl.analysis = .codegen_failure;
1314 try mod.failed_decls.put(mod.gpa, decl_index, em);
1303 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
13151304 log.err("{s}", .{em.msg});
13161305 return error.CodegenFail;
13171306 },
......@@ -1333,7 +1322,7 @@ fn lowerConst(
13331322 val: Value,
13341323 required_alignment: InternPool.Alignment,
13351324 output_section_index: u32,
1336 src_loc: Module.SrcLoc,
1325 src_loc: Module.LazySrcLoc,
13371326) !LowerConstResult {
13381327 const gpa = elf_file.base.comp.gpa;
13391328
......@@ -1386,7 +1375,7 @@ pub fn updateExports(
13861375 elf_file: *Elf,
13871376 mod: *Module,
13881377 exported: Module.Exported,
1389 exports: []const *Module.Export,
1378 export_indices: []const u32,
13901379) link.File.UpdateExportsError!void {
13911380 const tracy = trace(@src());
13921381 defer tracy.end();
......@@ -1398,15 +1387,15 @@ pub fn updateExports(
13981387 break :blk self.decls.getPtr(decl_index).?;
13991388 },
14001389 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1401 const first_exp = exports[0];
1402 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.getSrcLoc(mod));
1390 const first_exp = mod.all_exports.items[export_indices[0]];
1391 const res = try self.lowerAnonDecl(elf_file, value, .none, first_exp.src);
14031392 switch (res) {
14041393 .ok => {},
14051394 .fail => |em| {
14061395 // TODO maybe it's enough to return an error here and let Module.processExportsInner
14071396 // handle the error?
14081397 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1409 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1398 mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
14101399 return;
14111400 },
14121401 }
......@@ -1418,13 +1407,14 @@ pub fn updateExports(
14181407 const esym = self.local_esyms.items(.elf_sym)[esym_index];
14191408 const esym_shndx = self.local_esyms.items(.shndx)[esym_index];
14201409
1421 for (exports) |exp| {
1410 for (export_indices) |export_idx| {
1411 const exp = mod.all_exports.items[export_idx];
14221412 if (exp.opts.section.unwrap()) |section_name| {
14231413 if (!section_name.eqlSlice(".text", &mod.intern_pool)) {
14241414 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1425 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1415 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
14261416 gpa,
1427 exp.getSrcLoc(mod),
1417 exp.src,
14281418 "Unimplemented: ExportOptions.section",
14291419 .{},
14301420 ));
......@@ -1437,9 +1427,9 @@ pub fn updateExports(
14371427 .weak => elf.STB_WEAK,
14381428 .link_once => {
14391429 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1440 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1430 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
14411431 gpa,
1442 exp.getSrcLoc(mod),
1432 exp.src,
14431433 "Unimplemented: GlobalLinkage.LinkOnce",
14441434 .{},
14451435 ));
......@@ -1487,13 +1477,16 @@ pub fn updateDeclLineNumber(
14871477 }
14881478}
14891479
1490pub fn deleteDeclExport(
1480pub fn deleteExport(
14911481 self: *ZigObject,
14921482 elf_file: *Elf,
1493 decl_index: InternPool.DeclIndex,
1483 exported: Zcu.Exported,
14941484 name: InternPool.NullTerminatedString,
14951485) void {
1496 const metadata = self.decls.getPtr(decl_index) orelse return;
1486 const metadata = switch (exported) {
1487 .decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
1488 .value => |value| self.anon_decls.getPtr(value) orelse return,
1489 };
14971490 const mod = elf_file.base.comp.module.?;
14981491 const exp_name = name.toSlice(&mod.intern_pool);
14991492 const esym_index = metadata.@"export"(self, exp_name) orelse return;
......@@ -1654,6 +1647,7 @@ const Module = Zcu;
16541647const Object = @import("Object.zig");
16551648const Symbol = @import("Symbol.zig");
16561649const StringTable = @import("../StringTable.zig");
1657const Type = @import("../../type.zig").Type;
1650const Type = @import("../../Type.zig");
16581651const Value = @import("../../Value.zig");
1652const AnalUnit = InternPool.AnalUnit;
16591653const ZigObject = @This();
src/link/MachO.zig+8-8
......@@ -3207,22 +3207,22 @@ pub fn updateExports(
32073207 self: *MachO,
32083208 mod: *Module,
32093209 exported: Module.Exported,
3210 exports: []const *Module.Export,
3210 export_indices: []const u32,
32113211) link.File.UpdateExportsError!void {
32123212 if (build_options.skip_non_native and builtin.object_format != .macho) {
32133213 @panic("Attempted to compile for object format that was disabled by build configuration");
32143214 }
3215 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
3216 return self.getZigObject().?.updateExports(self, mod, exported, exports);
3215 if (self.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
3216 return self.getZigObject().?.updateExports(self, mod, exported, export_indices);
32173217}
32183218
3219pub fn deleteDeclExport(
3219pub fn deleteExport(
32203220 self: *MachO,
3221 decl_index: InternPool.DeclIndex,
3221 exported: Zcu.Exported,
32223222 name: InternPool.NullTerminatedString,
3223) Allocator.Error!void {
3223) void {
32243224 if (self.llvm_object) |_| return;
3225 return self.getZigObject().?.deleteDeclExport(self, decl_index, name);
3225 return self.getZigObject().?.deleteExport(self, exported, name);
32263226}
32273227
32283228pub fn freeDecl(self: *MachO, decl_index: InternPool.DeclIndex) void {
......@@ -3239,7 +3239,7 @@ pub fn lowerAnonDecl(
32393239 self: *MachO,
32403240 decl_val: InternPool.Index,
32413241 explicit_alignment: InternPool.Alignment,
3242 src_loc: Module.SrcLoc,
3242 src_loc: Module.LazySrcLoc,
32433243) !codegen.Result {
32443244 return self.getZigObject().?.lowerAnonDecl(self, decl_val, explicit_alignment, src_loc);
32453245}
src/link/MachO/DebugSymbols.zig+1-1
......@@ -459,4 +459,4 @@ const trace = @import("../../tracy.zig").trace;
459459const Allocator = mem.Allocator;
460460const MachO = @import("../MachO.zig");
461461const StringTable = @import("../StringTable.zig");
462const Type = @import("../../type.zig").Type;
462const Type = @import("../../Type.zig");
src/link/MachO/ZigObject.zig+29-35
......@@ -572,7 +572,7 @@ pub fn lowerAnonDecl(
572572 macho_file: *MachO,
573573 decl_val: InternPool.Index,
574574 explicit_alignment: Atom.Alignment,
575 src_loc: Module.SrcLoc,
575 src_loc: Module.LazySrcLoc,
576576) !codegen.Result {
577577 const gpa = macho_file.base.comp.gpa;
578578 const mod = macho_file.base.comp.module.?;
......@@ -682,7 +682,7 @@ pub fn updateFunc(
682682 const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
683683 const res = try codegen.generateFunction(
684684 &macho_file.base,
685 decl.navSrcLoc(mod).upgrade(mod),
685 decl.navSrcLoc(mod),
686686 func_index,
687687 air,
688688 liveness,
......@@ -694,7 +694,7 @@ pub fn updateFunc(
694694 .ok => code_buffer.items,
695695 .fail => |em| {
696696 func.analysis(&mod.intern_pool).state = .codegen_failure;
697 try mod.failed_decls.put(mod.gpa, decl_index, em);
697 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
698698 return;
699699 },
700700 };
......@@ -713,9 +713,7 @@ pub fn updateFunc(
713713 );
714714 }
715715
716 // Since we updated the vaddr and the size, each corresponding export
717 // symbol also needs to be updated.
718 return self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
716 // Exports will be updated by `Zcu.processExports` after the update.
719717}
720718
721719pub fn updateDecl(
......@@ -756,7 +754,7 @@ pub fn updateDecl(
756754
757755 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
758756 const dio: codegen.DebugInfoOutput = if (decl_state) |*ds| .{ .dwarf = ds } else .none;
759 const res = try codegen.generateSymbol(&macho_file.base, decl.navSrcLoc(mod).upgrade(mod), decl_val, &code_buffer, dio, .{
757 const res = try codegen.generateSymbol(&macho_file.base, decl.navSrcLoc(mod), decl_val, &code_buffer, dio, .{
760758 .parent_atom_index = sym_index,
761759 });
762760
......@@ -764,7 +762,7 @@ pub fn updateDecl(
764762 .ok => code_buffer.items,
765763 .fail => |em| {
766764 decl.analysis = .codegen_failure;
767 try mod.failed_decls.put(mod.gpa, decl_index, em);
765 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
768766 return;
769767 },
770768 };
......@@ -790,9 +788,7 @@ pub fn updateDecl(
790788 );
791789 }
792790
793 // Since we updated the vaddr and the size, each corresponding export symbol also
794 // needs to be updated.
795 try self.updateExports(macho_file, mod, .{ .decl_index = decl_index }, mod.getDeclExports(decl_index));
791 // Exports will be updated by `Zcu.processExports` after the update.
796792}
797793
798794fn updateDeclCode(
......@@ -1104,12 +1100,12 @@ pub fn lowerUnnamedConst(
11041100 val,
11051101 val.typeOf(mod).abiAlignment(mod),
11061102 macho_file.zig_const_sect_index.?,
1107 decl.navSrcLoc(mod).upgrade(mod),
1103 decl.navSrcLoc(mod),
11081104 )) {
11091105 .ok => |sym_index| sym_index,
11101106 .fail => |em| {
11111107 decl.analysis = .codegen_failure;
1112 try mod.failed_decls.put(mod.gpa, decl_index, em);
1108 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
11131109 log.err("{s}", .{em.msg});
11141110 return error.CodegenFail;
11151111 },
......@@ -1131,7 +1127,7 @@ fn lowerConst(
11311127 val: Value,
11321128 required_alignment: Atom.Alignment,
11331129 output_section_index: u8,
1134 src_loc: Module.SrcLoc,
1130 src_loc: Module.LazySrcLoc,
11351131) !LowerConstResult {
11361132 const gpa = macho_file.base.comp.gpa;
11371133
......@@ -1187,7 +1183,7 @@ pub fn updateExports(
11871183 macho_file: *MachO,
11881184 mod: *Module,
11891185 exported: Module.Exported,
1190 exports: []const *Module.Export,
1186 export_indices: []const u32,
11911187) link.File.UpdateExportsError!void {
11921188 const tracy = trace(@src());
11931189 defer tracy.end();
......@@ -1199,15 +1195,15 @@ pub fn updateExports(
11991195 break :blk self.decls.getPtr(decl_index).?;
12001196 },
12011197 .value => |value| self.anon_decls.getPtr(value) orelse blk: {
1202 const first_exp = exports[0];
1203 const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.getSrcLoc(mod));
1198 const first_exp = mod.all_exports.items[export_indices[0]];
1199 const res = try self.lowerAnonDecl(macho_file, value, .none, first_exp.src);
12041200 switch (res) {
12051201 .ok => {},
12061202 .fail => |em| {
12071203 // TODO maybe it's enough to return an error here and let Module.processExportsInner
12081204 // handle the error?
12091205 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1210 mod.failed_exports.putAssumeCapacityNoClobber(first_exp, em);
1206 mod.failed_exports.putAssumeCapacityNoClobber(export_indices[0], em);
12111207 return;
12121208 },
12131209 }
......@@ -1218,13 +1214,14 @@ pub fn updateExports(
12181214 const nlist_idx = macho_file.getSymbol(sym_index).nlist_idx;
12191215 const nlist = self.symtab.items(.nlist)[nlist_idx];
12201216
1221 for (exports) |exp| {
1217 for (export_indices) |export_idx| {
1218 const exp = mod.all_exports.items[export_idx];
12221219 if (exp.opts.section.unwrap()) |section_name| {
12231220 if (!section_name.eqlSlice("__text", &mod.intern_pool)) {
12241221 try mod.failed_exports.ensureUnusedCapacity(mod.gpa, 1);
1225 mod.failed_exports.putAssumeCapacityNoClobber(exp, try Module.ErrorMsg.create(
1222 mod.failed_exports.putAssumeCapacityNoClobber(export_idx, try Module.ErrorMsg.create(
12261223 gpa,
1227 exp.getSrcLoc(mod),
1224 exp.src,
12281225 "Unimplemented: ExportOptions.section",
12291226 .{},
12301227 ));
......@@ -1232,9 +1229,9 @@ pub fn updateExports(
12321229 }
12331230 }
12341231 if (exp.opts.linkage == .link_once) {
1235 try mod.failed_exports.putNoClobber(mod.gpa, exp, try Module.ErrorMsg.create(
1232 try mod.failed_exports.putNoClobber(mod.gpa, export_idx, try Module.ErrorMsg.create(
12361233 gpa,
1237 exp.getSrcLoc(mod),
1234 exp.src,
12381235 "Unimplemented: GlobalLinkage.link_once",
12391236 .{},
12401237 ));
......@@ -1294,14 +1291,7 @@ fn updateLazySymbol(
12941291 break :blk try self.strtab.insert(gpa, name);
12951292 };
12961293
1297 const src = if (lazy_sym.ty.srcLocOrNull(mod)) |src|
1298 src.upgrade(mod)
1299 else
1300 Module.SrcLoc{
1301 .file_scope = undefined,
1302 .base_node = undefined,
1303 .lazy = .unneeded,
1304 };
1294 const src = lazy_sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
13051295 const res = try codegen.generateLazySymbol(
13061296 &macho_file.base,
13071297 src,
......@@ -1364,15 +1354,18 @@ pub fn updateDeclLineNumber(self: *ZigObject, mod: *Module, decl_index: InternPo
13641354 }
13651355}
13661356
1367pub fn deleteDeclExport(
1357pub fn deleteExport(
13681358 self: *ZigObject,
13691359 macho_file: *MachO,
1370 decl_index: InternPool.DeclIndex,
1360 exported: Zcu.Exported,
13711361 name: InternPool.NullTerminatedString,
13721362) void {
13731363 const mod = macho_file.base.comp.module.?;
13741364
1375 const metadata = self.decls.getPtr(decl_index) orelse return;
1365 const metadata = switch (exported) {
1366 .decl_index => |decl_index| self.decls.getPtr(decl_index) orelse return,
1367 .value => |value| self.anon_decls.getPtr(value) orelse return,
1368 };
13761369 const nlist_index = metadata.@"export"(self, name.toSlice(&mod.intern_pool)) orelse return;
13771370
13781371 log.debug("deleting export '{}'", .{name.fmt(&mod.intern_pool)});
......@@ -1594,6 +1587,7 @@ const Object = @import("Object.zig");
15941587const Relocation = @import("Relocation.zig");
15951588const Symbol = @import("Symbol.zig");
15961589const StringTable = @import("../StringTable.zig");
1597const Type = @import("../../type.zig").Type;
1590const Type = @import("../../Type.zig");
15981591const Value = @import("../../Value.zig");
1592const AnalUnit = InternPool.AnalUnit;
15991593const ZigObject = @This();
src/link/NvPtx.zig+2-2
......@@ -96,12 +96,12 @@ pub fn updateExports(
9696 self: *NvPtx,
9797 module: *Module,
9898 exported: Module.Exported,
99 exports: []const *Module.Export,
99 export_indices: []const u32,
100100) !void {
101101 if (build_options.skip_non_native and builtin.object_format != .nvptx)
102102 @panic("Attempted to compile for object format that was disabled by build configuration");
103103
104 return self.llvm_object.updateExports(module, exported, exports);
104 return self.llvm_object.updateExports(module, exported, export_indices);
105105}
106106
107107pub fn freeDecl(self: *NvPtx, decl_index: InternPool.DeclIndex) void {
src/link/Plan9.zig+55-39
......@@ -15,8 +15,9 @@ const File = link.File;
1515const build_options = @import("build_options");
1616const Air = @import("../Air.zig");
1717const Liveness = @import("../Liveness.zig");
18const Type = @import("../type.zig").Type;
18const Type = @import("../Type.zig");
1919const Value = @import("../Value.zig");
20const AnalUnit = InternPool.AnalUnit;
2021
2122const std = @import("std");
2223const builtin = @import("builtin");
......@@ -60,6 +61,9 @@ fn_decl_table: std.AutoArrayHashMapUnmanaged(
6061) = .{},
6162/// the code is modified when relocated, so that is why it is mutable
6263data_decl_table: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u8) = .{},
64/// When `updateExports` is called, we store the export indices here, to be used
65/// during flush.
66decl_exports: std.AutoArrayHashMapUnmanaged(InternPool.DeclIndex, []u32) = .{},
6367
6468/// Table of unnamed constants associated with a parent `Decl`.
6569/// We store them here so that we can free the constants whenever the `Decl`
......@@ -435,7 +439,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
435439
436440 const res = try codegen.generateFunction(
437441 &self.base,
438 decl.navSrcLoc(mod).upgrade(mod),
442 decl.navSrcLoc(mod),
439443 func_index,
440444 air,
441445 liveness,
......@@ -446,7 +450,7 @@ pub fn updateFunc(self: *Plan9, mod: *Module, func_index: InternPool.Index, air:
446450 .ok => try code_buffer.toOwnedSlice(),
447451 .fail => |em| {
448452 func.analysis(&mod.intern_pool).state = .codegen_failure;
449 try mod.failed_decls.put(mod.gpa, decl_index, em);
453 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
450454 return;
451455 },
452456 };
......@@ -501,7 +505,7 @@ pub fn lowerUnnamedConst(self: *Plan9, val: Value, decl_index: InternPool.DeclIn
501505 };
502506 self.syms.items[info.sym_index.?] = sym;
503507
504 const res = try codegen.generateSymbol(&self.base, decl.navSrcLoc(mod).upgrade(mod), val, &code_buffer, .{
508 const res = try codegen.generateSymbol(&self.base, decl.navSrcLoc(mod), val, &code_buffer, .{
505509 .none = {},
506510 }, .{
507511 .parent_atom_index = new_atom_idx,
......@@ -510,7 +514,7 @@ pub fn lowerUnnamedConst(self: *Plan9, val: Value, decl_index: InternPool.DeclIn
510514 .ok => code_buffer.items,
511515 .fail => |em| {
512516 decl.analysis = .codegen_failure;
513 try mod.failed_decls.put(mod.gpa, decl_index, em);
517 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
514518 log.err("{s}", .{em.msg});
515519 return error.CodegenFail;
516520 },
......@@ -540,14 +544,14 @@ pub fn updateDecl(self: *Plan9, mod: *Module, decl_index: InternPool.DeclIndex)
540544 defer code_buffer.deinit();
541545 const decl_val = if (decl.val.getVariable(mod)) |variable| Value.fromInterned(variable.init) else decl.val;
542546 // TODO we need the symbol index for symbol in the table of locals for the containing atom
543 const res = try codegen.generateSymbol(&self.base, decl.navSrcLoc(mod).upgrade(mod), decl_val, &code_buffer, .{ .none = {} }, .{
547 const res = try codegen.generateSymbol(&self.base, decl.navSrcLoc(mod), decl_val, &code_buffer, .{ .none = {} }, .{
544548 .parent_atom_index = @as(Atom.Index, @intCast(atom_idx)),
545549 });
546550 const code = switch (res) {
547551 .ok => code_buffer.items,
548552 .fail => |em| {
549553 decl.analysis = .codegen_failure;
550 try mod.failed_decls.put(mod.gpa, decl_index, em);
554 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
551555 return;
552556 },
553557 };
......@@ -770,8 +774,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
770774 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
771775 }
772776 self.syms.items[atom.sym_index.?].value = off;
773 if (mod.decl_exports.get(decl_index)) |exports| {
774 try self.addDeclExports(mod, decl_index, exports.items);
777 if (self.decl_exports.get(decl_index)) |export_indices| {
778 try self.addDeclExports(mod, decl_index, export_indices);
775779 }
776780 }
777781 }
......@@ -836,8 +840,8 @@ pub fn flushModule(self: *Plan9, arena: Allocator, prog_node: std.Progress.Node)
836840 mem.writeInt(u64, got_table[atom.got_index.? * 8 ..][0..8], off, target.cpu.arch.endian());
837841 }
838842 self.syms.items[atom.sym_index.?].value = off;
839 if (mod.decl_exports.get(decl_index)) |exports| {
840 try self.addDeclExports(mod, decl_index, exports.items);
843 if (self.decl_exports.get(decl_index)) |export_indices| {
844 try self.addDeclExports(mod, decl_index, export_indices);
841845 }
842846 }
843847 // write the unnamed constants after the other data decls
......@@ -1007,22 +1011,23 @@ fn addDeclExports(
10071011 self: *Plan9,
10081012 mod: *Module,
10091013 decl_index: InternPool.DeclIndex,
1010 exports: []const *Module.Export,
1014 export_indices: []const u32,
10111015) !void {
10121016 const gpa = self.base.comp.gpa;
10131017 const metadata = self.decls.getPtr(decl_index).?;
10141018 const atom = self.getAtom(metadata.index);
10151019
1016 for (exports) |exp| {
1020 for (export_indices) |export_idx| {
1021 const exp = mod.all_exports.items[export_idx];
10171022 const exp_name = exp.opts.name.toSlice(&mod.intern_pool);
10181023 // plan9 does not support custom sections
10191024 if (exp.opts.section.unwrap()) |section_name| {
10201025 if (!section_name.eqlSlice(".text", &mod.intern_pool) and
10211026 !section_name.eqlSlice(".data", &mod.intern_pool))
10221027 {
1023 try mod.failed_exports.put(mod.gpa, exp, try Module.ErrorMsg.create(
1028 try mod.failed_exports.put(mod.gpa, export_idx, try Module.ErrorMsg.create(
10241029 gpa,
1025 mod.declPtr(decl_index).navSrcLoc(mod).upgrade(mod),
1030 mod.declPtr(decl_index).navSrcLoc(mod),
10261031 "plan9 does not support extra sections",
10271032 .{},
10281033 ));
......@@ -1152,15 +1157,23 @@ pub fn updateExports(
11521157 self: *Plan9,
11531158 module: *Module,
11541159 exported: Module.Exported,
1155 exports: []const *Module.Export,
1160 export_indices: []const u32,
11561161) !void {
1162 const gpa = self.base.comp.gpa;
11571163 switch (exported) {
11581164 .value => @panic("TODO: plan9 updateExports handling values"),
1159 .decl_index => |decl_index| _ = try self.seeDecl(decl_index),
1165 .decl_index => |decl_index| {
1166 _ = try self.seeDecl(decl_index);
1167 if (self.decl_exports.fetchSwapRemove(decl_index)) |kv| {
1168 gpa.free(kv.value);
1169 }
1170 try self.decl_exports.ensureUnusedCapacity(gpa, 1);
1171 const duped_indices = try gpa.dupe(u32, export_indices);
1172 self.decl_exports.putAssumeCapacityNoClobber(decl_index, duped_indices);
1173 },
11601174 }
1161 // we do all the things in flush
1175 // all proper work is done in flush
11621176 _ = module;
1163 _ = exports;
11641177}
11651178
11661179pub fn getOrCreateAtomForLazySymbol(self: *Plan9, sym: File.LazySymbol) !Atom.Index {
......@@ -1212,14 +1225,7 @@ fn updateLazySymbolAtom(self: *Plan9, sym: File.LazySymbol, atom_index: Atom.Ind
12121225 self.syms.items[self.getAtomPtr(atom_index).sym_index.?] = symbol;
12131226
12141227 // generate the code
1215 const src = if (sym.ty.srcLocOrNull(mod)) |src|
1216 src.upgrade(mod)
1217 else
1218 Module.SrcLoc{
1219 .file_scope = undefined,
1220 .base_node = undefined,
1221 .lazy = .unneeded,
1222 };
1228 const src = sym.ty.srcLocOrNull(mod) orelse Module.LazySrcLoc.unneeded;
12231229 const res = try codegen.generateLazySymbol(
12241230 &self.base,
12251231 src,
......@@ -1290,6 +1296,10 @@ pub fn deinit(self: *Plan9) void {
12901296 gpa.free(self.syms.items[sym_index].name);
12911297 }
12921298 self.data_decl_table.deinit(gpa);
1299 for (self.decl_exports.values()) |export_indices| {
1300 gpa.free(export_indices);
1301 }
1302 self.decl_exports.deinit(gpa);
12931303 self.syms.deinit(gpa);
12941304 self.got_index_free_list.deinit(gpa);
12951305 self.syms_index_free_list.deinit(gpa);
......@@ -1395,10 +1405,13 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
13951405 const atom = self.getAtom(decl_metadata.index);
13961406 const sym = self.syms.items[atom.sym_index.?];
13971407 try self.writeSym(writer, sym);
1398 if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
1399 for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
1400 try self.writeSym(writer, self.syms.items[exp_i]);
1401 };
1408 if (self.decl_exports.get(decl_index)) |export_indices| {
1409 for (export_indices) |export_idx| {
1410 const exp = mod.all_exports.items[export_idx];
1411 if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
1412 try self.writeSym(writer, self.syms.items[exp_i]);
1413 }
1414 }
14021415 }
14031416 }
14041417 }
......@@ -1442,13 +1455,16 @@ pub fn writeSyms(self: *Plan9, buf: *std.ArrayList(u8)) !void {
14421455 const atom = self.getAtom(decl_metadata.index);
14431456 const sym = self.syms.items[atom.sym_index.?];
14441457 try self.writeSym(writer, sym);
1445 if (self.base.comp.module.?.decl_exports.get(decl_index)) |exports| {
1446 for (exports.items) |e| if (decl_metadata.getExport(self, e.opts.name.toSlice(ip))) |exp_i| {
1447 const s = self.syms.items[exp_i];
1448 if (mem.eql(u8, s.name, "_start"))
1449 self.entry_val = s.value;
1450 try self.writeSym(writer, s);
1451 };
1458 if (self.decl_exports.get(decl_index)) |export_indices| {
1459 for (export_indices) |export_idx| {
1460 const exp = mod.all_exports.items[export_idx];
1461 if (decl_metadata.getExport(self, exp.opts.name.toSlice(ip))) |exp_i| {
1462 const s = self.syms.items[exp_i];
1463 if (mem.eql(u8, s.name, "_start"))
1464 self.entry_val = s.value;
1465 try self.writeSym(writer, s);
1466 }
1467 }
14521468 }
14531469 }
14541470 }
......@@ -1530,7 +1546,7 @@ pub fn lowerAnonDecl(
15301546 self: *Plan9,
15311547 decl_val: InternPool.Index,
15321548 explicit_alignment: InternPool.Alignment,
1533 src_loc: Module.SrcLoc,
1549 src_loc: Module.LazySrcLoc,
15341550) !codegen.Result {
15351551 _ = explicit_alignment;
15361552 // This is basically the same as lowerUnnamedConst.
src/link/SpirV.zig+3-2
......@@ -152,7 +152,7 @@ pub fn updateExports(
152152 self: *SpirV,
153153 mod: *Module,
154154 exported: Module.Exported,
155 exports: []const *Module.Export,
155 export_indices: []const u32,
156156) !void {
157157 const decl_index = switch (exported) {
158158 .decl_index => |i| i,
......@@ -177,7 +177,8 @@ pub fn updateExports(
177177 if ((!is_vulkan and execution_model == .Kernel) or
178178 (is_vulkan and (execution_model == .Fragment or execution_model == .Vertex)))
179179 {
180 for (exports) |exp| {
180 for (export_indices) |export_idx| {
181 const exp = mod.all_exports.items[export_idx];
181182 try self.object.spv.declareEntryPoint(
182183 spv_decl_index,
183184 exp.opts.name.toSlice(&mod.intern_pool),
src/link/Wasm.zig+8-8
......@@ -33,7 +33,7 @@ const Zcu = @import("../Zcu.zig");
3333const Module = Zcu;
3434const Object = @import("Wasm/Object.zig");
3535const Symbol = @import("Wasm/Symbol.zig");
36const Type = @import("../type.zig").Type;
36const Type = @import("../Type.zig");
3737const Value = @import("../Value.zig");
3838const ZigObject = @import("Wasm/ZigObject.zig");
3939
......@@ -1533,7 +1533,7 @@ pub fn lowerAnonDecl(
15331533 wasm: *Wasm,
15341534 decl_val: InternPool.Index,
15351535 explicit_alignment: Alignment,
1536 src_loc: Module.SrcLoc,
1536 src_loc: Module.LazySrcLoc,
15371537) !codegen.Result {
15381538 return wasm.zigObjectPtr().?.lowerAnonDecl(wasm, decl_val, explicit_alignment, src_loc);
15391539}
......@@ -1542,26 +1542,26 @@ pub fn getAnonDeclVAddr(wasm: *Wasm, decl_val: InternPool.Index, reloc_info: lin
15421542 return wasm.zigObjectPtr().?.getAnonDeclVAddr(wasm, decl_val, reloc_info);
15431543}
15441544
1545pub fn deleteDeclExport(
1545pub fn deleteExport(
15461546 wasm: *Wasm,
1547 decl_index: InternPool.DeclIndex,
1547 exported: Zcu.Exported,
15481548 name: InternPool.NullTerminatedString,
15491549) void {
15501550 if (wasm.llvm_object) |_| return;
1551 return wasm.zigObjectPtr().?.deleteDeclExport(wasm, decl_index, name);
1551 return wasm.zigObjectPtr().?.deleteExport(wasm, exported, name);
15521552}
15531553
15541554pub fn updateExports(
15551555 wasm: *Wasm,
15561556 mod: *Module,
15571557 exported: Module.Exported,
1558 exports: []const *Module.Export,
1558 export_indices: []const u32,
15591559) !void {
15601560 if (build_options.skip_non_native and builtin.object_format != .wasm) {
15611561 @panic("Attempted to compile for object format that was disabled by build configuration");
15621562 }
1563 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, exports);
1564 return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, exports);
1563 if (wasm.llvm_object) |llvm_object| return llvm_object.updateExports(mod, exported, export_indices);
1564 return wasm.zigObjectPtr().?.updateExports(wasm, mod, exported, export_indices);
15651565}
15661566
15671567pub fn freeDecl(wasm: *Wasm, decl_index: InternPool.DeclIndex) void {
src/link/Wasm/ZigObject.zig+23-17
......@@ -269,7 +269,7 @@ pub fn updateDecl(
269269
270270 const res = try codegen.generateSymbol(
271271 &wasm_file.base,
272 decl.navSrcLoc(mod).upgrade(mod),
272 decl.navSrcLoc(mod),
273273 val,
274274 &code_writer,
275275 .none,
......@@ -280,7 +280,7 @@ pub fn updateDecl(
280280 .ok => code_writer.items,
281281 .fail => |em| {
282282 decl.analysis = .codegen_failure;
283 try mod.failed_decls.put(mod.gpa, decl_index, em);
283 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
284284 return;
285285 },
286286 };
......@@ -308,7 +308,7 @@ pub fn updateFunc(
308308 defer code_writer.deinit();
309309 const result = try codegen.generateFunction(
310310 &wasm_file.base,
311 decl.navSrcLoc(mod).upgrade(mod),
311 decl.navSrcLoc(mod),
312312 func_index,
313313 air,
314314 liveness,
......@@ -320,7 +320,7 @@ pub fn updateFunc(
320320 .ok => code_writer.items,
321321 .fail => |em| {
322322 decl.analysis = .codegen_failure;
323 try mod.failed_decls.put(mod.gpa, decl_index, em);
323 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
324324 return;
325325 },
326326 };
......@@ -439,7 +439,7 @@ pub fn lowerAnonDecl(
439439 wasm_file: *Wasm,
440440 decl_val: InternPool.Index,
441441 explicit_alignment: InternPool.Alignment,
442 src_loc: Module.SrcLoc,
442 src_loc: Module.LazySrcLoc,
443443) !codegen.Result {
444444 const gpa = wasm_file.base.comp.gpa;
445445 const gop = try zig_object.anon_decls.getOrPut(gpa, decl_val);
......@@ -494,14 +494,14 @@ pub fn lowerUnnamedConst(zig_object: *ZigObject, wasm_file: *Wasm, val: Value, d
494494 else
495495 decl.navSrcLoc(mod);
496496
497 switch (try zig_object.lowerConst(wasm_file, name, val, decl_src.upgrade(mod))) {
497 switch (try zig_object.lowerConst(wasm_file, name, val, decl_src)) {
498498 .ok => |atom_index| {
499499 try wasm_file.getAtomPtr(parent_atom_index).locals.append(gpa, atom_index);
500500 return @intFromEnum(wasm_file.getAtom(atom_index).sym_index);
501501 },
502502 .fail => |em| {
503503 decl.analysis = .codegen_failure;
504 try mod.failed_decls.put(mod.gpa, decl_index, em);
504 try mod.failed_analysis.put(mod.gpa, AnalUnit.wrap(.{ .decl = decl_index }), em);
505505 return error.CodegenFail;
506506 },
507507 }
......@@ -512,7 +512,7 @@ const LowerConstResult = union(enum) {
512512 fail: *Module.ErrorMsg,
513513};
514514
515fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, val: Value, src_loc: Module.SrcLoc) !LowerConstResult {
515fn lowerConst(zig_object: *ZigObject, wasm_file: *Wasm, name: []const u8, val: Value, src_loc: Module.LazySrcLoc) !LowerConstResult {
516516 const gpa = wasm_file.base.comp.gpa;
517517 const mod = wasm_file.base.comp.module.?;
518518
......@@ -833,13 +833,17 @@ pub fn getAnonDeclVAddr(
833833 return target_symbol_index;
834834}
835835
836pub fn deleteDeclExport(
836pub fn deleteExport(
837837 zig_object: *ZigObject,
838838 wasm_file: *Wasm,
839 decl_index: InternPool.DeclIndex,
839 exported: Zcu.Exported,
840840 name: InternPool.NullTerminatedString,
841841) void {
842842 const mod = wasm_file.base.comp.module.?;
843 const decl_index = switch (exported) {
844 .decl_index => |decl_index| decl_index,
845 .value => @panic("TODO: implement Wasm linker code for exporting a constant value"),
846 };
843847 const decl_info = zig_object.decls_map.getPtr(decl_index) orelse return;
844848 if (decl_info.@"export"(zig_object, name.toSlice(&mod.intern_pool))) |sym_index| {
845849 const sym = zig_object.symbol(sym_index);
......@@ -856,7 +860,7 @@ pub fn updateExports(
856860 wasm_file: *Wasm,
857861 mod: *Module,
858862 exported: Module.Exported,
859 exports: []const *Module.Export,
863 export_indices: []const u32,
860864) !void {
861865 const decl_index = switch (exported) {
862866 .decl_index => |i| i,
......@@ -873,11 +877,12 @@ pub fn updateExports(
873877 const gpa = mod.gpa;
874878 log.debug("Updating exports for decl '{}'", .{decl.name.fmt(&mod.intern_pool)});
875879
876 for (exports) |exp| {
880 for (export_indices) |export_idx| {
881 const exp = mod.all_exports.items[export_idx];
877882 if (exp.opts.section.toSlice(&mod.intern_pool)) |section| {
878 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
883 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
879884 gpa,
880 decl.navSrcLoc(mod).upgrade(mod),
885 decl.navSrcLoc(mod),
881886 "Unimplemented: ExportOptions.section '{s}'",
882887 .{section},
883888 ));
......@@ -908,9 +913,9 @@ pub fn updateExports(
908913 },
909914 .strong => {}, // symbols are strong by default
910915 .link_once => {
911 try mod.failed_exports.putNoClobber(gpa, exp, try Module.ErrorMsg.create(
916 try mod.failed_exports.putNoClobber(gpa, export_idx, try Module.ErrorMsg.create(
912917 gpa,
913 decl.navSrcLoc(mod).upgrade(mod),
918 decl.navSrcLoc(mod),
914919 "Unimplemented: LinkOnce",
915920 .{},
916921 ));
......@@ -1247,7 +1252,8 @@ const Zcu = @import("../../Zcu.zig");
12471252const Module = Zcu;
12481253const StringTable = @import("../StringTable.zig");
12491254const Symbol = @import("Symbol.zig");
1250const Type = @import("../../type.zig").Type;
1255const Type = @import("../../Type.zig");
12511256const Value = @import("../../Value.zig");
12521257const Wasm = @import("../Wasm.zig");
1258const AnalUnit = InternPool.AnalUnit;
12531259const ZigObject = @This();
src/mutable_value.zig+1-1
......@@ -3,7 +3,7 @@ const assert = std.debug.assert;
33const Allocator = std.mem.Allocator;
44const Zcu = @import("Zcu.zig");
55const InternPool = @import("InternPool.zig");
6const Type = @import("type.zig").Type;
6const Type = @import("Type.zig");
77const Value = @import("Value.zig");
88
99/// We use a tagged union here because while it wastes a few bytes for some tags, having a fixed
src/print_air.zig+1-1
......@@ -4,7 +4,7 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
44
55const Zcu = @import("Zcu.zig");
66const Value = @import("Value.zig");
7const Type = @import("type.zig").Type;
7const Type = @import("Type.zig");
88const Air = @import("Air.zig");
99const Liveness = @import("Liveness.zig");
1010const InternPool = @import("InternPool.zig");
src/print_value.zig+5-5
......@@ -2,7 +2,7 @@
22//! It is a thin wrapper around a `Value` which also, redundantly, stores its `Type`.
33
44const std = @import("std");
5const Type = @import("type.zig").Type;
5const Type = @import("Type.zig");
66const Value = @import("Value.zig");
77const Zcu = @import("Zcu.zig");
88/// Deprecated.
......@@ -81,12 +81,12 @@ pub fn print(
8181 }),
8282 .int => |int| switch (int.storage) {
8383 inline .u64, .i64, .big_int => |x| try writer.print("{}", .{x}),
84 .lazy_align => |ty| if (opt_sema) |sema| {
85 const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .{ .sema = sema })).scalar;
84 .lazy_align => |ty| if (opt_sema != null) {
85 const a = (try Type.fromInterned(ty).abiAlignmentAdvanced(mod, .sema)).scalar;
8686 try writer.print("{}", .{a.toByteUnits() orelse 0});
8787 } else try writer.print("@alignOf({})", .{Type.fromInterned(ty).fmt(mod)}),
88 .lazy_size => |ty| if (opt_sema) |sema| {
89 const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .{ .sema = sema })).scalar;
88 .lazy_size => |ty| if (opt_sema != null) {
89 const s = (try Type.fromInterned(ty).abiSizeAdvanced(mod, .sema)).scalar;
9090 try writer.print("{}", .{s});
9191 } else try writer.print("@sizeOf({})", .{Type.fromInterned(ty).fmt(mod)}),
9292 },
src/register_manager.zig+1-1
......@@ -5,7 +5,7 @@ const assert = std.debug.assert;
55const Allocator = std.mem.Allocator;
66const Air = @import("Air.zig");
77const StaticBitSet = std.bit_set.StaticBitSet;
8const Type = @import("type.zig").Type;
8const Type = @import("Type.zig");
99const Zcu = @import("Zcu.zig");
1010/// Deprecated.
1111const Module = Zcu;
src/target.zig+1-1
......@@ -1,5 +1,5 @@
11const std = @import("std");
2const Type = @import("type.zig").Type;
2const Type = @import("Type.zig");
33const AddressSpace = std.builtin.AddressSpace;
44const Alignment = @import("InternPool.zig").Alignment;
55const Feature = @import("Zcu.zig").Feature;
src/type.zig deleted-3617
......@@ -1,3617 +0,0 @@
1const std = @import("std");
2const builtin = @import("builtin");
3const Value = @import("Value.zig");
4const assert = std.debug.assert;
5const Target = std.Target;
6const Zcu = @import("Zcu.zig");
7/// Deprecated.
8const Module = Zcu;
9const log = std.log.scoped(.Type);
10const target_util = @import("target.zig");
11const Sema = @import("Sema.zig");
12const InternPool = @import("InternPool.zig");
13const Alignment = InternPool.Alignment;
14const Zir = std.zig.Zir;
15
16/// Both types and values are canonically represented by a single 32-bit integer
17/// which is an index into an `InternPool` data structure.
18/// This struct abstracts around this storage by providing methods only
19/// applicable to types rather than values in general.
20pub const Type = struct {
21 ip_index: InternPool.Index,
22
23 pub fn zigTypeTag(ty: Type, mod: *const Module) std.builtin.TypeId {
24 return ty.zigTypeTagOrPoison(mod) catch unreachable;
25 }
26
27 pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId {
28 return mod.intern_pool.zigTypeTagOrPoison(ty.toIntern());
29 }
30
31 pub fn baseZigTypeTag(self: Type, mod: *Module) std.builtin.TypeId {
32 return switch (self.zigTypeTag(mod)) {
33 .ErrorUnion => self.errorUnionPayload(mod).baseZigTypeTag(mod),
34 .Optional => {
35 return self.optionalChild(mod).baseZigTypeTag(mod);
36 },
37 else => |t| t,
38 };
39 }
40
41 pub fn isSelfComparable(ty: Type, mod: *const Module, is_equality_cmp: bool) bool {
42 return switch (ty.zigTypeTag(mod)) {
43 .Int,
44 .Float,
45 .ComptimeFloat,
46 .ComptimeInt,
47 => true,
48
49 .Vector => ty.elemType2(mod).isSelfComparable(mod, is_equality_cmp),
50
51 .Bool,
52 .Type,
53 .Void,
54 .ErrorSet,
55 .Fn,
56 .Opaque,
57 .AnyFrame,
58 .Enum,
59 .EnumLiteral,
60 => is_equality_cmp,
61
62 .NoReturn,
63 .Array,
64 .Struct,
65 .Undefined,
66 .Null,
67 .ErrorUnion,
68 .Union,
69 .Frame,
70 => false,
71
72 .Pointer => !ty.isSlice(mod) and (is_equality_cmp or ty.isCPtr(mod)),
73 .Optional => {
74 if (!is_equality_cmp) return false;
75 return ty.optionalChild(mod).isSelfComparable(mod, is_equality_cmp);
76 },
77 };
78 }
79
80 /// If it is a function pointer, returns the function type. Otherwise returns null.
81 pub fn castPtrToFn(ty: Type, mod: *const Module) ?Type {
82 if (ty.zigTypeTag(mod) != .Pointer) return null;
83 const elem_ty = ty.childType(mod);
84 if (elem_ty.zigTypeTag(mod) != .Fn) return null;
85 return elem_ty;
86 }
87
88 /// Asserts the type is a pointer.
89 pub fn ptrIsMutable(ty: Type, mod: *const Module) bool {
90 return !mod.intern_pool.indexToKey(ty.toIntern()).ptr_type.flags.is_const;
91 }
92
93 pub const ArrayInfo = struct {
94 elem_type: Type,
95 sentinel: ?Value = null,
96 len: u64,
97 };
98
99 pub fn arrayInfo(self: Type, mod: *const Module) ArrayInfo {
100 return .{
101 .len = self.arrayLen(mod),
102 .sentinel = self.sentinel(mod),
103 .elem_type = self.childType(mod),
104 };
105 }
106
107 pub fn ptrInfo(ty: Type, mod: *const Module) InternPool.Key.PtrType {
108 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
109 .ptr_type => |p| p,
110 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
111 .ptr_type => |p| p,
112 else => unreachable,
113 },
114 else => unreachable,
115 };
116 }
117
118 pub fn eql(a: Type, b: Type, mod: *const Module) bool {
119 _ = mod; // TODO: remove this parameter
120 // The InternPool data structure hashes based on Key to make interned objects
121 // unique. An Index can be treated simply as u32 value for the
122 // purpose of Type/Value hashing and equality.
123 return a.toIntern() == b.toIntern();
124 }
125
126 pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
127 _ = ty;
128 _ = unused_fmt_string;
129 _ = options;
130 _ = writer;
131 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
132 }
133
134 pub const Formatter = std.fmt.Formatter(format2);
135
136 pub fn fmt(ty: Type, module: *Module) Formatter {
137 return .{ .data = .{
138 .ty = ty,
139 .module = module,
140 } };
141 }
142
143 const FormatContext = struct {
144 ty: Type,
145 module: *Module,
146 };
147
148 fn format2(
149 ctx: FormatContext,
150 comptime unused_format_string: []const u8,
151 options: std.fmt.FormatOptions,
152 writer: anytype,
153 ) !void {
154 comptime assert(unused_format_string.len == 0);
155 _ = options;
156 return print(ctx.ty, writer, ctx.module);
157 }
158
159 pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
160 return .{ .data = ty };
161 }
162
163 /// This is a debug function. In order to print types in a meaningful way
164 /// we also need access to the module.
165 pub fn dump(
166 start_type: Type,
167 comptime unused_format_string: []const u8,
168 options: std.fmt.FormatOptions,
169 writer: anytype,
170 ) @TypeOf(writer).Error!void {
171 _ = options;
172 comptime assert(unused_format_string.len == 0);
173 return writer.print("{any}", .{start_type.ip_index});
174 }
175
176 /// Prints a name suitable for `@typeName`.
177 /// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels.
178 pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void {
179 const ip = &mod.intern_pool;
180 switch (ip.indexToKey(ty.toIntern())) {
181 .int_type => |int_type| {
182 const sign_char: u8 = switch (int_type.signedness) {
183 .signed => 'i',
184 .unsigned => 'u',
185 };
186 return writer.print("{c}{d}", .{ sign_char, int_type.bits });
187 },
188 .ptr_type => {
189 const info = ty.ptrInfo(mod);
190
191 if (info.sentinel != .none) switch (info.flags.size) {
192 .One, .C => unreachable,
193 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
194 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
195 } else switch (info.flags.size) {
196 .One => try writer.writeAll("*"),
197 .Many => try writer.writeAll("[*]"),
198 .C => try writer.writeAll("[*c]"),
199 .Slice => try writer.writeAll("[]"),
200 }
201 if (info.flags.alignment != .none or
202 info.packed_offset.host_size != 0 or
203 info.flags.vector_index != .none)
204 {
205 const alignment = if (info.flags.alignment != .none)
206 info.flags.alignment
207 else
208 Type.fromInterned(info.child).abiAlignment(mod);
209 try writer.print("align({d}", .{alignment.toByteUnits() orelse 0});
210
211 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
212 try writer.print(":{d}:{d}", .{
213 info.packed_offset.bit_offset, info.packed_offset.host_size,
214 });
215 }
216 if (info.flags.vector_index == .runtime) {
217 try writer.writeAll(":?");
218 } else if (info.flags.vector_index != .none) {
219 try writer.print(":{d}", .{@intFromEnum(info.flags.vector_index)});
220 }
221 try writer.writeAll(") ");
222 }
223 if (info.flags.address_space != .generic) {
224 try writer.print("addrspace(.{s}) ", .{@tagName(info.flags.address_space)});
225 }
226 if (info.flags.is_const) try writer.writeAll("const ");
227 if (info.flags.is_volatile) try writer.writeAll("volatile ");
228 if (info.flags.is_allowzero and info.flags.size != .C) try writer.writeAll("allowzero ");
229
230 try print(Type.fromInterned(info.child), writer, mod);
231 return;
232 },
233 .array_type => |array_type| {
234 if (array_type.sentinel == .none) {
235 try writer.print("[{d}]", .{array_type.len});
236 try print(Type.fromInterned(array_type.child), writer, mod);
237 } else {
238 try writer.print("[{d}:{}]", .{
239 array_type.len,
240 Value.fromInterned(array_type.sentinel).fmtValue(mod, null),
241 });
242 try print(Type.fromInterned(array_type.child), writer, mod);
243 }
244 return;
245 },
246 .vector_type => |vector_type| {
247 try writer.print("@Vector({d}, ", .{vector_type.len});
248 try print(Type.fromInterned(vector_type.child), writer, mod);
249 try writer.writeAll(")");
250 return;
251 },
252 .opt_type => |child| {
253 try writer.writeByte('?');
254 return print(Type.fromInterned(child), writer, mod);
255 },
256 .error_union_type => |error_union_type| {
257 try print(Type.fromInterned(error_union_type.error_set_type), writer, mod);
258 try writer.writeByte('!');
259 if (error_union_type.payload_type == .generic_poison_type) {
260 try writer.writeAll("anytype");
261 } else {
262 try print(Type.fromInterned(error_union_type.payload_type), writer, mod);
263 }
264 return;
265 },
266 .inferred_error_set_type => |func_index| {
267 try writer.writeAll("@typeInfo(@typeInfo(@TypeOf(");
268 const owner_decl = mod.funcOwnerDeclPtr(func_index);
269 try owner_decl.renderFullyQualifiedName(mod, writer);
270 try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set");
271 },
272 .error_set_type => |error_set_type| {
273 const names = error_set_type.names;
274 try writer.writeAll("error{");
275 for (names.get(ip), 0..) |name, i| {
276 if (i != 0) try writer.writeByte(',');
277 try writer.print("{}", .{name.fmt(ip)});
278 }
279 try writer.writeAll("}");
280 },
281 .simple_type => |s| switch (s) {
282 .f16,
283 .f32,
284 .f64,
285 .f80,
286 .f128,
287 .usize,
288 .isize,
289 .c_char,
290 .c_short,
291 .c_ushort,
292 .c_int,
293 .c_uint,
294 .c_long,
295 .c_ulong,
296 .c_longlong,
297 .c_ulonglong,
298 .c_longdouble,
299 .anyopaque,
300 .bool,
301 .void,
302 .type,
303 .anyerror,
304 .comptime_int,
305 .comptime_float,
306 .noreturn,
307 .adhoc_inferred_error_set,
308 => return writer.writeAll(@tagName(s)),
309
310 .null,
311 .undefined,
312 => try writer.print("@TypeOf({s})", .{@tagName(s)}),
313
314 .enum_literal => try writer.print("@TypeOf(.{s})", .{@tagName(s)}),
315 .atomic_order => try writer.writeAll("std.builtin.AtomicOrder"),
316 .atomic_rmw_op => try writer.writeAll("std.builtin.AtomicRmwOp"),
317 .calling_convention => try writer.writeAll("std.builtin.CallingConvention"),
318 .address_space => try writer.writeAll("std.builtin.AddressSpace"),
319 .float_mode => try writer.writeAll("std.builtin.FloatMode"),
320 .reduce_op => try writer.writeAll("std.builtin.ReduceOp"),
321 .call_modifier => try writer.writeAll("std.builtin.CallModifier"),
322 .prefetch_options => try writer.writeAll("std.builtin.PrefetchOptions"),
323 .export_options => try writer.writeAll("std.builtin.ExportOptions"),
324 .extern_options => try writer.writeAll("std.builtin.ExternOptions"),
325 .type_info => try writer.writeAll("std.builtin.Type"),
326
327 .generic_poison => unreachable,
328 },
329 .struct_type => {
330 const struct_type = ip.loadStructType(ty.toIntern());
331 if (struct_type.decl.unwrap()) |decl_index| {
332 const decl = mod.declPtr(decl_index);
333 try decl.renderFullyQualifiedName(mod, writer);
334 } else if (ip.loadStructType(ty.toIntern()).namespace.unwrap()) |namespace_index| {
335 const namespace = mod.namespacePtr(namespace_index);
336 try namespace.renderFullyQualifiedName(mod, .empty, writer);
337 } else {
338 try writer.writeAll("@TypeOf(.{})");
339 }
340 },
341 .anon_struct_type => |anon_struct| {
342 if (anon_struct.types.len == 0) {
343 return writer.writeAll("@TypeOf(.{})");
344 }
345 try writer.writeAll("struct{");
346 for (anon_struct.types.get(ip), anon_struct.values.get(ip), 0..) |field_ty, val, i| {
347 if (i != 0) try writer.writeAll(", ");
348 if (val != .none) {
349 try writer.writeAll("comptime ");
350 }
351 if (anon_struct.names.len != 0) {
352 try writer.print("{}: ", .{anon_struct.names.get(ip)[i].fmt(&mod.intern_pool)});
353 }
354
355 try print(Type.fromInterned(field_ty), writer, mod);
356
357 if (val != .none) {
358 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod, null)});
359 }
360 }
361 try writer.writeAll("}");
362 },
363
364 .union_type => {
365 const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
366 try decl.renderFullyQualifiedName(mod, writer);
367 },
368 .opaque_type => {
369 const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
370 try decl.renderFullyQualifiedName(mod, writer);
371 },
372 .enum_type => {
373 const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
374 try decl.renderFullyQualifiedName(mod, writer);
375 },
376 .func_type => |fn_info| {
377 if (fn_info.is_noinline) {
378 try writer.writeAll("noinline ");
379 }
380 try writer.writeAll("fn (");
381 const param_types = fn_info.param_types.get(&mod.intern_pool);
382 for (param_types, 0..) |param_ty, i| {
383 if (i != 0) try writer.writeAll(", ");
384 if (std.math.cast(u5, i)) |index| {
385 if (fn_info.paramIsComptime(index)) {
386 try writer.writeAll("comptime ");
387 }
388 if (fn_info.paramIsNoalias(index)) {
389 try writer.writeAll("noalias ");
390 }
391 }
392 if (param_ty == .generic_poison_type) {
393 try writer.writeAll("anytype");
394 } else {
395 try print(Type.fromInterned(param_ty), writer, mod);
396 }
397 }
398 if (fn_info.is_var_args) {
399 if (param_types.len != 0) {
400 try writer.writeAll(", ");
401 }
402 try writer.writeAll("...");
403 }
404 try writer.writeAll(") ");
405 if (fn_info.cc != .Unspecified) {
406 try writer.writeAll("callconv(.");
407 try writer.writeAll(@tagName(fn_info.cc));
408 try writer.writeAll(") ");
409 }
410 if (fn_info.return_type == .generic_poison_type) {
411 try writer.writeAll("anytype");
412 } else {
413 try print(Type.fromInterned(fn_info.return_type), writer, mod);
414 }
415 },
416 .anyframe_type => |child| {
417 if (child == .none) return writer.writeAll("anyframe");
418 try writer.writeAll("anyframe->");
419 return print(Type.fromInterned(child), writer, mod);
420 },
421
422 // values, not types
423 .undef,
424 .simple_value,
425 .variable,
426 .extern_func,
427 .func,
428 .int,
429 .err,
430 .error_union,
431 .enum_literal,
432 .enum_tag,
433 .empty_enum_value,
434 .float,
435 .ptr,
436 .slice,
437 .opt,
438 .aggregate,
439 .un,
440 // memoization, not types
441 .memoized_call,
442 => unreachable,
443 }
444 }
445
446 pub fn fromInterned(i: InternPool.Index) Type {
447 assert(i != .none);
448 return .{ .ip_index = i };
449 }
450
451 pub fn toIntern(ty: Type) InternPool.Index {
452 assert(ty.ip_index != .none);
453 return ty.ip_index;
454 }
455
456 pub fn toValue(self: Type) Value {
457 return Value.fromInterned(self.toIntern());
458 }
459
460 const RuntimeBitsError = Module.CompileError || error{NeedLazy};
461
462 /// true if and only if the type takes up space in memory at runtime.
463 /// There are two reasons a type will return false:
464 /// * the type is a comptime-only type. For example, the type `type` itself.
465 /// - note, however, that a struct can have mixed fields and only the non-comptime-only
466 /// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
467 /// hasRuntimeBits()=true and abiSize()=4
468 /// * the type has only one possible value, making its ABI size 0.
469 /// - an enum with an explicit tag type has the ABI size of the integer tag type,
470 /// making it one-possible-value only if the integer tag type has 0 bits.
471 /// When `ignore_comptime_only` is true, then types that are comptime-only
472 /// may return false positives.
473 pub fn hasRuntimeBitsAdvanced(
474 ty: Type,
475 mod: *Module,
476 ignore_comptime_only: bool,
477 strat: AbiAlignmentAdvancedStrat,
478 ) RuntimeBitsError!bool {
479 const ip = &mod.intern_pool;
480 return switch (ty.toIntern()) {
481 // False because it is a comptime-only type.
482 .empty_struct_type => false,
483 else => switch (ip.indexToKey(ty.toIntern())) {
484 .int_type => |int_type| int_type.bits != 0,
485 .ptr_type => {
486 // Pointers to zero-bit types still have a runtime address; however, pointers
487 // to comptime-only types do not, with the exception of function pointers.
488 if (ignore_comptime_only) return true;
489 return switch (strat) {
490 .sema => |sema| !(try sema.typeRequiresComptime(ty)),
491 .eager => !comptimeOnly(ty, mod),
492 .lazy => error.NeedLazy,
493 };
494 },
495 .anyframe_type => true,
496 .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and
497 try Type.fromInterned(array_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
498 .vector_type => |vector_type| return vector_type.len > 0 and
499 try Type.fromInterned(vector_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
500 .opt_type => |child| {
501 const child_ty = Type.fromInterned(child);
502 if (child_ty.isNoReturn(mod)) {
503 // Then the optional is comptime-known to be null.
504 return false;
505 }
506 if (ignore_comptime_only) return true;
507 return switch (strat) {
508 .sema => |sema| !(try sema.typeRequiresComptime(child_ty)),
509 .eager => !comptimeOnly(child_ty, mod),
510 .lazy => error.NeedLazy,
511 };
512 },
513 .error_union_type,
514 .error_set_type,
515 .inferred_error_set_type,
516 => true,
517
518 // These are function *bodies*, not pointers.
519 // They return false here because they are comptime-only types.
520 // Special exceptions have to be made when emitting functions due to
521 // this returning false.
522 .func_type => false,
523
524 .simple_type => |t| switch (t) {
525 .f16,
526 .f32,
527 .f64,
528 .f80,
529 .f128,
530 .usize,
531 .isize,
532 .c_char,
533 .c_short,
534 .c_ushort,
535 .c_int,
536 .c_uint,
537 .c_long,
538 .c_ulong,
539 .c_longlong,
540 .c_ulonglong,
541 .c_longdouble,
542 .bool,
543 .anyerror,
544 .adhoc_inferred_error_set,
545 .anyopaque,
546 .atomic_order,
547 .atomic_rmw_op,
548 .calling_convention,
549 .address_space,
550 .float_mode,
551 .reduce_op,
552 .call_modifier,
553 .prefetch_options,
554 .export_options,
555 .extern_options,
556 => true,
557
558 // These are false because they are comptime-only types.
559 .void,
560 .type,
561 .comptime_int,
562 .comptime_float,
563 .noreturn,
564 .null,
565 .undefined,
566 .enum_literal,
567 .type_info,
568 => false,
569
570 .generic_poison => unreachable,
571 },
572 .struct_type => {
573 const struct_type = ip.loadStructType(ty.toIntern());
574 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
575 // In this case, we guess that hasRuntimeBits() for this type is true,
576 // and then later if our guess was incorrect, we emit a compile error.
577 return true;
578 }
579 switch (strat) {
580 .sema => |sema| _ = try sema.resolveTypeFields(ty),
581 .eager => assert(struct_type.haveFieldTypes(ip)),
582 .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
583 }
584 for (0..struct_type.field_types.len) |i| {
585 if (struct_type.comptime_bits.getBit(ip, i)) continue;
586 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
587 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
588 return true;
589 } else {
590 return false;
591 }
592 },
593 .anon_struct_type => |tuple| {
594 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
595 if (val != .none) continue; // comptime field
596 if (try Type.fromInterned(field_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true;
597 }
598 return false;
599 },
600
601 .union_type => {
602 const union_type = ip.loadUnionType(ty.toIntern());
603 switch (union_type.flagsPtr(ip).runtime_tag) {
604 .none => {
605 if (union_type.flagsPtr(ip).status == .field_types_wip) {
606 // In this case, we guess that hasRuntimeBits() for this type is true,
607 // and then later if our guess was incorrect, we emit a compile error.
608 union_type.flagsPtr(ip).assumed_runtime_bits = true;
609 return true;
610 }
611 },
612 .safety, .tagged => {
613 const tag_ty = union_type.tagTypePtr(ip).*;
614 // tag_ty will be `none` if this union's tag type is not resolved yet,
615 // in which case we want control flow to continue down below.
616 if (tag_ty != .none and
617 try Type.fromInterned(tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
618 {
619 return true;
620 }
621 },
622 }
623 switch (strat) {
624 .sema => |sema| _ = try sema.resolveTypeFields(ty),
625 .eager => assert(union_type.flagsPtr(ip).status.haveFieldTypes()),
626 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())
627 return error.NeedLazy,
628 }
629 for (0..union_type.field_types.len) |field_index| {
630 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
631 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
632 return true;
633 } else {
634 return false;
635 }
636 },
637
638 .opaque_type => true,
639 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
640
641 // values, not types
642 .undef,
643 .simple_value,
644 .variable,
645 .extern_func,
646 .func,
647 .int,
648 .err,
649 .error_union,
650 .enum_literal,
651 .enum_tag,
652 .empty_enum_value,
653 .float,
654 .ptr,
655 .slice,
656 .opt,
657 .aggregate,
658 .un,
659 // memoization, not types
660 .memoized_call,
661 => unreachable,
662 },
663 };
664 }
665
666 /// true if and only if the type has a well-defined memory layout
667 /// readFrom/writeToMemory are supported only for types with a well-
668 /// defined memory layout
669 pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool {
670 const ip = &mod.intern_pool;
671 return switch (ip.indexToKey(ty.toIntern())) {
672 .int_type,
673 .vector_type,
674 => true,
675
676 .error_union_type,
677 .error_set_type,
678 .inferred_error_set_type,
679 .anon_struct_type,
680 .opaque_type,
681 .anyframe_type,
682 // These are function bodies, not function pointers.
683 .func_type,
684 => false,
685
686 .array_type => |array_type| Type.fromInterned(array_type.child).hasWellDefinedLayout(mod),
687 .opt_type => ty.isPtrLikeOptional(mod),
688 .ptr_type => |ptr_type| ptr_type.flags.size != .Slice,
689
690 .simple_type => |t| switch (t) {
691 .f16,
692 .f32,
693 .f64,
694 .f80,
695 .f128,
696 .usize,
697 .isize,
698 .c_char,
699 .c_short,
700 .c_ushort,
701 .c_int,
702 .c_uint,
703 .c_long,
704 .c_ulong,
705 .c_longlong,
706 .c_ulonglong,
707 .c_longdouble,
708 .bool,
709 .void,
710 => true,
711
712 .anyerror,
713 .adhoc_inferred_error_set,
714 .anyopaque,
715 .atomic_order,
716 .atomic_rmw_op,
717 .calling_convention,
718 .address_space,
719 .float_mode,
720 .reduce_op,
721 .call_modifier,
722 .prefetch_options,
723 .export_options,
724 .extern_options,
725 .type,
726 .comptime_int,
727 .comptime_float,
728 .noreturn,
729 .null,
730 .undefined,
731 .enum_literal,
732 .type_info,
733 .generic_poison,
734 => false,
735 },
736 .struct_type => {
737 const struct_type = ip.loadStructType(ty.toIntern());
738 // Struct with no fields have a well-defined layout of no bits.
739 return struct_type.layout != .auto or struct_type.field_types.len == 0;
740 },
741 .union_type => {
742 const union_type = ip.loadUnionType(ty.toIntern());
743 return switch (union_type.flagsPtr(ip).runtime_tag) {
744 .none, .safety => union_type.flagsPtr(ip).layout != .auto,
745 .tagged => false,
746 };
747 },
748 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
749 .auto => false,
750 .explicit, .nonexhaustive => true,
751 },
752
753 // values, not types
754 .undef,
755 .simple_value,
756 .variable,
757 .extern_func,
758 .func,
759 .int,
760 .err,
761 .error_union,
762 .enum_literal,
763 .enum_tag,
764 .empty_enum_value,
765 .float,
766 .ptr,
767 .slice,
768 .opt,
769 .aggregate,
770 .un,
771 // memoization, not types
772 .memoized_call,
773 => unreachable,
774 };
775 }
776
777 pub fn hasRuntimeBits(ty: Type, mod: *Module) bool {
778 return hasRuntimeBitsAdvanced(ty, mod, false, .eager) catch unreachable;
779 }
780
781 pub fn hasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool {
782 return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable;
783 }
784
785 pub fn fnHasRuntimeBits(ty: Type, mod: *Module) bool {
786 return ty.fnHasRuntimeBitsAdvanced(mod, null) catch unreachable;
787 }
788
789 /// Determines whether a function type has runtime bits, i.e. whether a
790 /// function with this type can exist at runtime.
791 /// Asserts that `ty` is a function type.
792 /// If `opt_sema` is not provided, asserts that the return type is sufficiently resolved.
793 pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool {
794 const fn_info = mod.typeToFunc(ty).?;
795 if (fn_info.is_generic) return false;
796 if (fn_info.is_var_args) return true;
797 if (fn_info.cc == .Inline) return false;
798 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyAdvanced(mod, opt_sema);
799 }
800
801 pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {
802 switch (ty.zigTypeTag(mod)) {
803 .Fn => return ty.fnHasRuntimeBits(mod),
804 else => return ty.hasRuntimeBits(mod),
805 }
806 }
807
808 /// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
809 pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool {
810 return switch (ty.zigTypeTag(mod)) {
811 .Fn => true,
812 else => return ty.hasRuntimeBitsIgnoreComptime(mod),
813 };
814 }
815
816 pub fn isNoReturn(ty: Type, mod: *Module) bool {
817 return mod.intern_pool.isNoReturn(ty.toIntern());
818 }
819
820 /// Returns `none` if the pointer is naturally aligned and the element type is 0-bit.
821 pub fn ptrAlignment(ty: Type, mod: *Module) Alignment {
822 return ptrAlignmentAdvanced(ty, mod, null) catch unreachable;
823 }
824
825 pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !Alignment {
826 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
827 .ptr_type => |ptr_type| {
828 if (ptr_type.flags.alignment != .none)
829 return ptr_type.flags.alignment;
830
831 if (opt_sema) |sema| {
832 const res = try Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .{ .sema = sema });
833 return res.scalar;
834 }
835
836 return (Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
837 },
838 .opt_type => |child| Type.fromInterned(child).ptrAlignmentAdvanced(mod, opt_sema),
839 else => unreachable,
840 };
841 }
842
843 pub fn ptrAddressSpace(ty: Type, mod: *const Module) std.builtin.AddressSpace {
844 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
845 .ptr_type => |ptr_type| ptr_type.flags.address_space,
846 .opt_type => |child| mod.intern_pool.indexToKey(child).ptr_type.flags.address_space,
847 else => unreachable,
848 };
849 }
850
851 /// Never returns `none`. Asserts that all necessary type resolution is already done.
852 pub fn abiAlignment(ty: Type, mod: *Module) Alignment {
853 return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
854 }
855
856 /// May capture a reference to `ty`.
857 /// Returned value has type `comptime_int`.
858 pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
859 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
860 .val => |val| return val,
861 .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
862 }
863 }
864
865 pub const AbiAlignmentAdvanced = union(enum) {
866 scalar: Alignment,
867 val: Value,
868 };
869
870 pub const AbiAlignmentAdvancedStrat = union(enum) {
871 eager,
872 lazy,
873 sema: *Sema,
874 };
875
876 /// If you pass `eager` you will get back `scalar` and assert the type is resolved.
877 /// In this case there will be no error, guaranteed.
878 /// If you pass `lazy` you may get back `scalar` or `val`.
879 /// If `val` is returned, a reference to `ty` has been captured.
880 /// If you pass `sema` you will get back `scalar` and resolve the type if
881 /// necessary, possibly returning a CompileError.
882 pub fn abiAlignmentAdvanced(
883 ty: Type,
884 mod: *Module,
885 strat: AbiAlignmentAdvancedStrat,
886 ) Module.CompileError!AbiAlignmentAdvanced {
887 const target = mod.getTarget();
888 const use_llvm = mod.comp.config.use_llvm;
889 const ip = &mod.intern_pool;
890
891 const opt_sema = switch (strat) {
892 .sema => |sema| sema,
893 else => null,
894 };
895
896 switch (ty.toIntern()) {
897 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"1" },
898 else => switch (ip.indexToKey(ty.toIntern())) {
899 .int_type => |int_type| {
900 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
901 return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) };
902 },
903 .ptr_type, .anyframe_type => {
904 return .{ .scalar = ptrAbiAlignment(target) };
905 },
906 .array_type => |array_type| {
907 return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
908 },
909 .vector_type => |vector_type| {
910 if (vector_type.len == 0) return .{ .scalar = .@"1" };
911 switch (mod.comp.getZigBackend()) {
912 else => {
913 const elem_bits: u32 = @intCast(try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, opt_sema));
914 if (elem_bits == 0) return .{ .scalar = .@"1" };
915 const bytes = ((elem_bits * vector_type.len) + 7) / 8;
916 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
917 return .{ .scalar = Alignment.fromByteUnits(alignment) };
918 },
919 .stage2_c => {
920 return Type.fromInterned(vector_type.child).abiAlignmentAdvanced(mod, strat);
921 },
922 .stage2_x86_64 => {
923 if (vector_type.child == .bool_type) {
924 if (vector_type.len > 256 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
925 if (vector_type.len > 128 and std.Target.x86.featureSetHas(target.cpu.features, .avx2)) return .{ .scalar = .@"32" };
926 if (vector_type.len > 64) return .{ .scalar = .@"16" };
927 const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
928 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
929 return .{ .scalar = Alignment.fromByteUnits(alignment) };
930 }
931 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
932 if (elem_bytes == 0) return .{ .scalar = .@"1" };
933 const bytes = elem_bytes * vector_type.len;
934 if (bytes > 32 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
935 if (bytes > 16 and std.Target.x86.featureSetHas(target.cpu.features, .avx)) return .{ .scalar = .@"32" };
936 return .{ .scalar = .@"16" };
937 },
938 }
939 },
940
941 .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),
942 .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, Type.fromInterned(info.payload_type)),
943
944 .error_set_type, .inferred_error_set_type => {
945 const bits = mod.errorSetBits();
946 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
947 return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
948 },
949
950 // represents machine code; not a pointer
951 .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
952
953 .simple_type => |t| switch (t) {
954 .bool,
955 .atomic_order,
956 .atomic_rmw_op,
957 .calling_convention,
958 .address_space,
959 .float_mode,
960 .reduce_op,
961 .call_modifier,
962 .prefetch_options,
963 .anyopaque,
964 => return .{ .scalar = .@"1" },
965
966 .usize,
967 .isize,
968 => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) },
969
970 .export_options,
971 .extern_options,
972 .type_info,
973 => return .{ .scalar = ptrAbiAlignment(target) },
974
975 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
976 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
977 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
978 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
979 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
980 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
981 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
982 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
983 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
984 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
985
986 .f16 => return .{ .scalar = .@"2" },
987 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
988 .f64 => switch (target.c_type_bit_size(.double)) {
989 64 => return .{ .scalar = cTypeAlign(target, .double) },
990 else => return .{ .scalar = .@"8" },
991 },
992 .f80 => switch (target.c_type_bit_size(.longdouble)) {
993 80 => return .{ .scalar = cTypeAlign(target, .longdouble) },
994 else => {
995 const u80_ty: Type = .{ .ip_index = .u80_type };
996 return .{ .scalar = abiAlignment(u80_ty, mod) };
997 },
998 },
999 .f128 => switch (target.c_type_bit_size(.longdouble)) {
1000 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
1001 else => return .{ .scalar = .@"16" },
1002 },
1003
1004 .anyerror, .adhoc_inferred_error_set => {
1005 const bits = mod.errorSetBits();
1006 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
1007 return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
1008 },
1009
1010 .void,
1011 .type,
1012 .comptime_int,
1013 .comptime_float,
1014 .null,
1015 .undefined,
1016 .enum_literal,
1017 => return .{ .scalar = .@"1" },
1018
1019 .noreturn => unreachable,
1020 .generic_poison => unreachable,
1021 },
1022 .struct_type => {
1023 const struct_type = ip.loadStructType(ty.toIntern());
1024 if (struct_type.layout == .@"packed") {
1025 switch (strat) {
1026 .sema => |sema| try sema.resolveTypeLayout(ty),
1027 .lazy => if (struct_type.backingIntType(ip).* == .none) return .{
1028 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1029 .ty = .comptime_int_type,
1030 .storage = .{ .lazy_align = ty.toIntern() },
1031 } }))),
1032 },
1033 .eager => {},
1034 }
1035 return .{ .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiAlignment(mod) };
1036 }
1037
1038 const flags = struct_type.flagsPtr(ip).*;
1039 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
1040
1041 return switch (strat) {
1042 .eager => unreachable, // struct alignment not resolved
1043 .sema => |sema| .{
1044 .scalar = try sema.resolveStructAlignment(ty.toIntern(), struct_type),
1045 },
1046 .lazy => .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1047 .ty = .comptime_int_type,
1048 .storage = .{ .lazy_align = ty.toIntern() },
1049 } }))) },
1050 };
1051 },
1052 .anon_struct_type => |tuple| {
1053 var big_align: Alignment = .@"1";
1054 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
1055 if (val != .none) continue; // comptime field
1056 switch (try Type.fromInterned(field_ty).abiAlignmentAdvanced(mod, strat)) {
1057 .scalar => |field_align| big_align = big_align.max(field_align),
1058 .val => switch (strat) {
1059 .eager => unreachable, // field type alignment not resolved
1060 .sema => unreachable, // passed to abiAlignmentAdvanced above
1061 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1062 .ty = .comptime_int_type,
1063 .storage = .{ .lazy_align = ty.toIntern() },
1064 } }))) },
1065 },
1066 }
1067 }
1068 return .{ .scalar = big_align };
1069 },
1070 .union_type => {
1071 const union_type = ip.loadUnionType(ty.toIntern());
1072 const flags = union_type.flagsPtr(ip).*;
1073 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
1074
1075 if (!union_type.haveLayout(ip)) switch (strat) {
1076 .eager => unreachable, // union layout not resolved
1077 .sema => |sema| return .{ .scalar = try sema.resolveUnionAlignment(ty, union_type) },
1078 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1079 .ty = .comptime_int_type,
1080 .storage = .{ .lazy_align = ty.toIntern() },
1081 } }))) },
1082 };
1083
1084 return .{ .scalar = union_type.flagsPtr(ip).alignment };
1085 },
1086 .opaque_type => return .{ .scalar = .@"1" },
1087 .enum_type => return .{
1088 .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(mod),
1089 },
1090
1091 // values, not types
1092 .undef,
1093 .simple_value,
1094 .variable,
1095 .extern_func,
1096 .func,
1097 .int,
1098 .err,
1099 .error_union,
1100 .enum_literal,
1101 .enum_tag,
1102 .empty_enum_value,
1103 .float,
1104 .ptr,
1105 .slice,
1106 .opt,
1107 .aggregate,
1108 .un,
1109 // memoization, not types
1110 .memoized_call,
1111 => unreachable,
1112 },
1113 }
1114 }
1115
1116 fn abiAlignmentAdvancedErrorUnion(
1117 ty: Type,
1118 mod: *Module,
1119 strat: AbiAlignmentAdvancedStrat,
1120 payload_ty: Type,
1121 ) Module.CompileError!AbiAlignmentAdvanced {
1122 // This code needs to be kept in sync with the equivalent switch prong
1123 // in abiSizeAdvanced.
1124 const code_align = abiAlignment(Type.anyerror, mod);
1125 switch (strat) {
1126 .eager, .sema => {
1127 if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1128 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1129 .ty = .comptime_int_type,
1130 .storage = .{ .lazy_align = ty.toIntern() },
1131 } }))) },
1132 else => |e| return e,
1133 })) {
1134 return .{ .scalar = code_align };
1135 }
1136 return .{ .scalar = code_align.max(
1137 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,
1138 ) };
1139 },
1140 .lazy => {
1141 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {
1142 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
1143 .val => {},
1144 }
1145 return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1146 .ty = .comptime_int_type,
1147 .storage = .{ .lazy_align = ty.toIntern() },
1148 } }))) };
1149 },
1150 }
1151 }
1152
1153 fn abiAlignmentAdvancedOptional(
1154 ty: Type,
1155 mod: *Module,
1156 strat: AbiAlignmentAdvancedStrat,
1157 ) Module.CompileError!AbiAlignmentAdvanced {
1158 const target = mod.getTarget();
1159 const child_type = ty.optionalChild(mod);
1160
1161 switch (child_type.zigTypeTag(mod)) {
1162 .Pointer => return .{ .scalar = ptrAbiAlignment(target) },
1163 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1164 .NoReturn => return .{ .scalar = .@"1" },
1165 else => {},
1166 }
1167
1168 switch (strat) {
1169 .eager, .sema => {
1170 if (!(child_type.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1171 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1172 .ty = .comptime_int_type,
1173 .storage = .{ .lazy_align = ty.toIntern() },
1174 } }))) },
1175 else => |e| return e,
1176 })) {
1177 return .{ .scalar = .@"1" };
1178 }
1179 return child_type.abiAlignmentAdvanced(mod, strat);
1180 },
1181 .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) {
1182 .scalar => |x| return .{ .scalar = x.max(.@"1") },
1183 .val => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1184 .ty = .comptime_int_type,
1185 .storage = .{ .lazy_align = ty.toIntern() },
1186 } }))) },
1187 },
1188 }
1189 }
1190
1191 /// May capture a reference to `ty`.
1192 pub fn lazyAbiSize(ty: Type, mod: *Module) !Value {
1193 switch (try ty.abiSizeAdvanced(mod, .lazy)) {
1194 .val => |val| return val,
1195 .scalar => |x| return mod.intValue(Type.comptime_int, x),
1196 }
1197 }
1198
1199 /// Asserts the type has the ABI size already resolved.
1200 /// Types that return false for hasRuntimeBits() return 0.
1201 pub fn abiSize(ty: Type, mod: *Module) u64 {
1202 return (abiSizeAdvanced(ty, mod, .eager) catch unreachable).scalar;
1203 }
1204
1205 const AbiSizeAdvanced = union(enum) {
1206 scalar: u64,
1207 val: Value,
1208 };
1209
1210 /// If you pass `eager` you will get back `scalar` and assert the type is resolved.
1211 /// In this case there will be no error, guaranteed.
1212 /// If you pass `lazy` you may get back `scalar` or `val`.
1213 /// If `val` is returned, a reference to `ty` has been captured.
1214 /// If you pass `sema` you will get back `scalar` and resolve the type if
1215 /// necessary, possibly returning a CompileError.
1216 pub fn abiSizeAdvanced(
1217 ty: Type,
1218 mod: *Module,
1219 strat: AbiAlignmentAdvancedStrat,
1220 ) Module.CompileError!AbiSizeAdvanced {
1221 const target = mod.getTarget();
1222 const use_llvm = mod.comp.config.use_llvm;
1223 const ip = &mod.intern_pool;
1224
1225 switch (ty.toIntern()) {
1226 .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 },
1227
1228 else => switch (ip.indexToKey(ty.toIntern())) {
1229 .int_type => |int_type| {
1230 if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1231 return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target, use_llvm) };
1232 },
1233 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1234 .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
1235 else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1236 },
1237 .anyframe_type => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1238
1239 .array_type => |array_type| {
1240 const len = array_type.lenIncludingSentinel();
1241 if (len == 0) return .{ .scalar = 0 };
1242 switch (try Type.fromInterned(array_type.child).abiSizeAdvanced(mod, strat)) {
1243 .scalar => |elem_size| return .{ .scalar = len * elem_size },
1244 .val => switch (strat) {
1245 .sema, .eager => unreachable,
1246 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1247 .ty = .comptime_int_type,
1248 .storage = .{ .lazy_size = ty.toIntern() },
1249 } }))) },
1250 },
1251 }
1252 },
1253 .vector_type => |vector_type| {
1254 const opt_sema = switch (strat) {
1255 .sema => |sema| sema,
1256 .eager => null,
1257 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1258 .ty = .comptime_int_type,
1259 .storage = .{ .lazy_size = ty.toIntern() },
1260 } }))) },
1261 };
1262 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {
1263 .scalar => |x| x,
1264 .val => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1265 .ty = .comptime_int_type,
1266 .storage = .{ .lazy_size = ty.toIntern() },
1267 } }))) },
1268 };
1269 const total_bytes = switch (mod.comp.getZigBackend()) {
1270 else => total_bytes: {
1271 const elem_bits = try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, opt_sema);
1272 const total_bits = elem_bits * vector_type.len;
1273 break :total_bytes (total_bits + 7) / 8;
1274 },
1275 .stage2_c => total_bytes: {
1276 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1277 break :total_bytes elem_bytes * vector_type.len;
1278 },
1279 .stage2_x86_64 => total_bytes: {
1280 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
1281 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1282 break :total_bytes elem_bytes * vector_type.len;
1283 },
1284 };
1285 return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) };
1286 },
1287
1288 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
1289
1290 .error_set_type, .inferred_error_set_type => {
1291 const bits = mod.errorSetBits();
1292 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1293 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
1294 },
1295
1296 .error_union_type => |error_union_type| {
1297 const payload_ty = Type.fromInterned(error_union_type.payload_type);
1298 // This code needs to be kept in sync with the equivalent switch prong
1299 // in abiAlignmentAdvanced.
1300 const code_size = abiSize(Type.anyerror, mod);
1301 if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1302 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1303 .ty = .comptime_int_type,
1304 .storage = .{ .lazy_size = ty.toIntern() },
1305 } }))) },
1306 else => |e| return e,
1307 })) {
1308 // Same as anyerror.
1309 return AbiSizeAdvanced{ .scalar = code_size };
1310 }
1311 const code_align = abiAlignment(Type.anyerror, mod);
1312 const payload_align = abiAlignment(payload_ty, mod);
1313 const payload_size = switch (try payload_ty.abiSizeAdvanced(mod, strat)) {
1314 .scalar => |elem_size| elem_size,
1315 .val => switch (strat) {
1316 .sema => unreachable,
1317 .eager => unreachable,
1318 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1319 .ty = .comptime_int_type,
1320 .storage = .{ .lazy_size = ty.toIntern() },
1321 } }))) },
1322 },
1323 };
1324
1325 var size: u64 = 0;
1326 if (code_align.compare(.gt, payload_align)) {
1327 size += code_size;
1328 size = payload_align.forward(size);
1329 size += payload_size;
1330 size = code_align.forward(size);
1331 } else {
1332 size += payload_size;
1333 size = code_align.forward(size);
1334 size += code_size;
1335 size = payload_align.forward(size);
1336 }
1337 return AbiSizeAdvanced{ .scalar = size };
1338 },
1339 .func_type => unreachable, // represents machine code; not a pointer
1340 .simple_type => |t| switch (t) {
1341 .bool,
1342 .atomic_order,
1343 .atomic_rmw_op,
1344 .calling_convention,
1345 .address_space,
1346 .float_mode,
1347 .reduce_op,
1348 .call_modifier,
1349 => return AbiSizeAdvanced{ .scalar = 1 },
1350
1351 .f16 => return AbiSizeAdvanced{ .scalar = 2 },
1352 .f32 => return AbiSizeAdvanced{ .scalar = 4 },
1353 .f64 => return AbiSizeAdvanced{ .scalar = 8 },
1354 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
1355 .f80 => switch (target.c_type_bit_size(.longdouble)) {
1356 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) },
1357 else => {
1358 const u80_ty: Type = .{ .ip_index = .u80_type };
1359 return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, mod) };
1360 },
1361 },
1362
1363 .usize,
1364 .isize,
1365 => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1366
1367 .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) },
1368 .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) },
1369 .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) },
1370 .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) },
1371 .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) },
1372 .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) },
1373 .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) },
1374 .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) },
1375 .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) },
1376 .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) },
1377
1378 .anyopaque,
1379 .void,
1380 .type,
1381 .comptime_int,
1382 .comptime_float,
1383 .null,
1384 .undefined,
1385 .enum_literal,
1386 => return AbiSizeAdvanced{ .scalar = 0 },
1387
1388 .anyerror, .adhoc_inferred_error_set => {
1389 const bits = mod.errorSetBits();
1390 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1391 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
1392 },
1393
1394 .prefetch_options => unreachable, // missing call to resolveTypeFields
1395 .export_options => unreachable, // missing call to resolveTypeFields
1396 .extern_options => unreachable, // missing call to resolveTypeFields
1397
1398 .type_info => unreachable,
1399 .noreturn => unreachable,
1400 .generic_poison => unreachable,
1401 },
1402 .struct_type => {
1403 const struct_type = ip.loadStructType(ty.toIntern());
1404 switch (strat) {
1405 .sema => |sema| try sema.resolveTypeLayout(ty),
1406 .lazy => switch (struct_type.layout) {
1407 .@"packed" => {
1408 if (struct_type.backingIntType(ip).* == .none) return .{
1409 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1410 .ty = .comptime_int_type,
1411 .storage = .{ .lazy_size = ty.toIntern() },
1412 } }))),
1413 };
1414 },
1415 .auto, .@"extern" => {
1416 if (!struct_type.haveLayout(ip)) return .{
1417 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1418 .ty = .comptime_int_type,
1419 .storage = .{ .lazy_size = ty.toIntern() },
1420 } }))),
1421 };
1422 },
1423 },
1424 .eager => {},
1425 }
1426 switch (struct_type.layout) {
1427 .@"packed" => return .{
1428 .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiSize(mod),
1429 },
1430 .auto, .@"extern" => {
1431 assert(struct_type.haveLayout(ip));
1432 return .{ .scalar = struct_type.size(ip).* };
1433 },
1434 }
1435 },
1436 .anon_struct_type => |tuple| {
1437 switch (strat) {
1438 .sema => |sema| try sema.resolveTypeLayout(ty),
1439 .lazy, .eager => {},
1440 }
1441 const field_count = tuple.types.len;
1442 if (field_count == 0) {
1443 return AbiSizeAdvanced{ .scalar = 0 };
1444 }
1445 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
1446 },
1447
1448 .union_type => {
1449 const union_type = ip.loadUnionType(ty.toIntern());
1450 switch (strat) {
1451 .sema => |sema| try sema.resolveTypeLayout(ty),
1452 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{
1453 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1454 .ty = .comptime_int_type,
1455 .storage = .{ .lazy_size = ty.toIntern() },
1456 } }))),
1457 },
1458 .eager => {},
1459 }
1460
1461 assert(union_type.haveLayout(ip));
1462 return .{ .scalar = union_type.size(ip).* };
1463 },
1464 .opaque_type => unreachable, // no size available
1465 .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(mod) },
1466
1467 // values, not types
1468 .undef,
1469 .simple_value,
1470 .variable,
1471 .extern_func,
1472 .func,
1473 .int,
1474 .err,
1475 .error_union,
1476 .enum_literal,
1477 .enum_tag,
1478 .empty_enum_value,
1479 .float,
1480 .ptr,
1481 .slice,
1482 .opt,
1483 .aggregate,
1484 .un,
1485 // memoization, not types
1486 .memoized_call,
1487 => unreachable,
1488 },
1489 }
1490 }
1491
1492 fn abiSizeAdvancedOptional(
1493 ty: Type,
1494 mod: *Module,
1495 strat: AbiAlignmentAdvancedStrat,
1496 ) Module.CompileError!AbiSizeAdvanced {
1497 const child_ty = ty.optionalChild(mod);
1498
1499 if (child_ty.isNoReturn(mod)) {
1500 return AbiSizeAdvanced{ .scalar = 0 };
1501 }
1502
1503 if (!(child_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1504 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1505 .ty = .comptime_int_type,
1506 .storage = .{ .lazy_size = ty.toIntern() },
1507 } }))) },
1508 else => |e| return e,
1509 })) return AbiSizeAdvanced{ .scalar = 1 };
1510
1511 if (ty.optionalReprIsPayload(mod)) {
1512 return abiSizeAdvanced(child_ty, mod, strat);
1513 }
1514
1515 const payload_size = switch (try child_ty.abiSizeAdvanced(mod, strat)) {
1516 .scalar => |elem_size| elem_size,
1517 .val => switch (strat) {
1518 .sema => unreachable,
1519 .eager => unreachable,
1520 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1521 .ty = .comptime_int_type,
1522 .storage = .{ .lazy_size = ty.toIntern() },
1523 } }))) },
1524 },
1525 };
1526
1527 // Optional types are represented as a struct with the child type as the first
1528 // field and a boolean as the second. Since the child type's abi alignment is
1529 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1530 // to the child type's ABI alignment.
1531 return AbiSizeAdvanced{
1532 .scalar = (child_ty.abiAlignment(mod).toByteUnits() orelse 0) + payload_size,
1533 };
1534 }
1535
1536 pub fn ptrAbiAlignment(target: Target) Alignment {
1537 return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
1538 }
1539
1540 pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 {
1541 return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
1542 }
1543
1544 pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
1545 return switch (target.cpu.arch) {
1546 .x86 => switch (bits) {
1547 0 => .none,
1548 1...8 => .@"1",
1549 9...16 => .@"2",
1550 17...64 => .@"4",
1551 else => .@"16",
1552 },
1553 .x86_64 => switch (bits) {
1554 0 => .none,
1555 1...8 => .@"1",
1556 9...16 => .@"2",
1557 17...32 => .@"4",
1558 33...64 => .@"8",
1559 else => switch (target_util.zigBackend(target, use_llvm)) {
1560 .stage2_x86_64 => .@"8",
1561 else => .@"16",
1562 },
1563 },
1564 else => return Alignment.fromByteUnits(@min(
1565 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
1566 maxIntAlignment(target, use_llvm),
1567 )),
1568 };
1569 }
1570
1571 pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
1572 return switch (target.cpu.arch) {
1573 .avr => 1,
1574 .msp430 => 2,
1575 .xcore => 4,
1576
1577 .arm,
1578 .armeb,
1579 .thumb,
1580 .thumbeb,
1581 .hexagon,
1582 .mips,
1583 .mipsel,
1584 .powerpc,
1585 .powerpcle,
1586 .r600,
1587 .amdgcn,
1588 .riscv32,
1589 .sparc,
1590 .sparcel,
1591 .s390x,
1592 .lanai,
1593 .wasm32,
1594 .wasm64,
1595 => 8,
1596
1597 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1598 // is a relevant number in three cases:
1599 // 1. Different machine code instruction when loading into SIMD register.
1600 // 2. The C ABI wants 16 for extern structs.
1601 // 3. 16-byte cmpxchg needs 16-byte alignment.
1602 // Same logic for powerpc64, mips64, sparc64.
1603 .powerpc64,
1604 .powerpc64le,
1605 .mips64,
1606 .mips64el,
1607 .sparc64,
1608 => switch (target.ofmt) {
1609 .c => 16,
1610 else => 8,
1611 },
1612
1613 .x86_64 => switch (target_util.zigBackend(target, use_llvm)) {
1614 .stage2_x86_64 => 8,
1615 else => 16,
1616 },
1617
1618 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
1619 .x86,
1620 .aarch64,
1621 .aarch64_be,
1622 .aarch64_32,
1623 .riscv64,
1624 .bpfel,
1625 .bpfeb,
1626 .nvptx,
1627 .nvptx64,
1628 => 16,
1629
1630 // Below this comment are unverified but based on the fact that C requires
1631 // int128_t to be 16 bytes aligned, it's a safe default.
1632 .spu_2,
1633 .csky,
1634 .arc,
1635 .m68k,
1636 .tce,
1637 .tcele,
1638 .le32,
1639 .amdil,
1640 .hsail,
1641 .spir,
1642 .kalimba,
1643 .renderscript32,
1644 .spirv,
1645 .spirv32,
1646 .shave,
1647 .le64,
1648 .amdil64,
1649 .hsail64,
1650 .spir64,
1651 .renderscript64,
1652 .ve,
1653 .spirv64,
1654 .dxil,
1655 .loongarch32,
1656 .loongarch64,
1657 .xtensa,
1658 => 16,
1659 };
1660 }
1661
1662 pub fn bitSize(ty: Type, mod: *Module) u64 {
1663 return bitSizeAdvanced(ty, mod, null) catch unreachable;
1664 }
1665
1666 /// If you pass `opt_sema`, any recursive type resolutions will happen if
1667 /// necessary, possibly returning a CompileError. Passing `null` instead asserts
1668 /// the type is fully resolved, and there will be no error, guaranteed.
1669 pub fn bitSizeAdvanced(
1670 ty: Type,
1671 mod: *Module,
1672 opt_sema: ?*Sema,
1673 ) Module.CompileError!u64 {
1674 const target = mod.getTarget();
1675 const ip = &mod.intern_pool;
1676
1677 const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
1678
1679 switch (ip.indexToKey(ty.toIntern())) {
1680 .int_type => |int_type| return int_type.bits,
1681 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1682 .Slice => return target.ptrBitWidth() * 2,
1683 else => return target.ptrBitWidth(),
1684 },
1685 .anyframe_type => return target.ptrBitWidth(),
1686
1687 .array_type => |array_type| {
1688 const len = array_type.lenIncludingSentinel();
1689 if (len == 0) return 0;
1690 const elem_ty = Type.fromInterned(array_type.child);
1691 const elem_size = @max(
1692 (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits() orelse 0,
1693 (try elem_ty.abiSizeAdvanced(mod, strat)).scalar,
1694 );
1695 if (elem_size == 0) return 0;
1696 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);
1697 return (len - 1) * 8 * elem_size + elem_bit_size;
1698 },
1699 .vector_type => |vector_type| {
1700 const child_ty = Type.fromInterned(vector_type.child);
1701 const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema);
1702 return elem_bit_size * vector_type.len;
1703 },
1704 .opt_type => {
1705 // Optionals and error unions are not packed so their bitsize
1706 // includes padding bits.
1707 return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8;
1708 },
1709
1710 .error_set_type, .inferred_error_set_type => return mod.errorSetBits(),
1711
1712 .error_union_type => {
1713 // Optionals and error unions are not packed so their bitsize
1714 // includes padding bits.
1715 return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8;
1716 },
1717 .func_type => unreachable, // represents machine code; not a pointer
1718 .simple_type => |t| switch (t) {
1719 .f16 => return 16,
1720 .f32 => return 32,
1721 .f64 => return 64,
1722 .f80 => return 80,
1723 .f128 => return 128,
1724
1725 .usize,
1726 .isize,
1727 => return target.ptrBitWidth(),
1728
1729 .c_char => return target.c_type_bit_size(.char),
1730 .c_short => return target.c_type_bit_size(.short),
1731 .c_ushort => return target.c_type_bit_size(.ushort),
1732 .c_int => return target.c_type_bit_size(.int),
1733 .c_uint => return target.c_type_bit_size(.uint),
1734 .c_long => return target.c_type_bit_size(.long),
1735 .c_ulong => return target.c_type_bit_size(.ulong),
1736 .c_longlong => return target.c_type_bit_size(.longlong),
1737 .c_ulonglong => return target.c_type_bit_size(.ulonglong),
1738 .c_longdouble => return target.c_type_bit_size(.longdouble),
1739
1740 .bool => return 1,
1741 .void => return 0,
1742
1743 .anyerror,
1744 .adhoc_inferred_error_set,
1745 => return mod.errorSetBits(),
1746
1747 .anyopaque => unreachable,
1748 .type => unreachable,
1749 .comptime_int => unreachable,
1750 .comptime_float => unreachable,
1751 .noreturn => unreachable,
1752 .null => unreachable,
1753 .undefined => unreachable,
1754 .enum_literal => unreachable,
1755 .generic_poison => unreachable,
1756
1757 .atomic_order => unreachable,
1758 .atomic_rmw_op => unreachable,
1759 .calling_convention => unreachable,
1760 .address_space => unreachable,
1761 .float_mode => unreachable,
1762 .reduce_op => unreachable,
1763 .call_modifier => unreachable,
1764 .prefetch_options => unreachable,
1765 .export_options => unreachable,
1766 .extern_options => unreachable,
1767 .type_info => unreachable,
1768 },
1769 .struct_type => {
1770 const struct_type = ip.loadStructType(ty.toIntern());
1771 const is_packed = struct_type.layout == .@"packed";
1772 if (opt_sema) |sema| {
1773 try sema.resolveTypeFields(ty);
1774 if (is_packed) try sema.resolveTypeLayout(ty);
1775 }
1776 if (is_packed) {
1777 return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, opt_sema);
1778 }
1779 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1780 },
1781
1782 .anon_struct_type => {
1783 if (opt_sema) |sema| try sema.resolveTypeFields(ty);
1784 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1785 },
1786
1787 .union_type => {
1788 const union_type = ip.loadUnionType(ty.toIntern());
1789 const is_packed = ty.containerLayout(mod) == .@"packed";
1790 if (opt_sema) |sema| {
1791 try sema.resolveTypeFields(ty);
1792 if (is_packed) try sema.resolveTypeLayout(ty);
1793 }
1794 if (!is_packed) {
1795 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1796 }
1797 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1798
1799 var size: u64 = 0;
1800 for (0..union_type.field_types.len) |field_index| {
1801 const field_ty = union_type.field_types.get(ip)[field_index];
1802 size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, opt_sema));
1803 }
1804
1805 return size;
1806 },
1807 .opaque_type => unreachable,
1808 .enum_type => return bitSizeAdvanced(Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), mod, opt_sema),
1809
1810 // values, not types
1811 .undef,
1812 .simple_value,
1813 .variable,
1814 .extern_func,
1815 .func,
1816 .int,
1817 .err,
1818 .error_union,
1819 .enum_literal,
1820 .enum_tag,
1821 .empty_enum_value,
1822 .float,
1823 .ptr,
1824 .slice,
1825 .opt,
1826 .aggregate,
1827 .un,
1828 // memoization, not types
1829 .memoized_call,
1830 => unreachable,
1831 }
1832 }
1833
1834 /// Returns true if the type's layout is already resolved and it is safe
1835 /// to use `abiSize`, `abiAlignment` and `bitSize` on it.
1836 pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
1837 const ip = &mod.intern_pool;
1838 return switch (ip.indexToKey(ty.toIntern())) {
1839 .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
1840 .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
1841 .array_type => |array_type| {
1842 if (array_type.lenIncludingSentinel() == 0) return true;
1843 return Type.fromInterned(array_type.child).layoutIsResolved(mod);
1844 },
1845 .opt_type => |child| Type.fromInterned(child).layoutIsResolved(mod),
1846 .error_union_type => |k| Type.fromInterned(k.payload_type).layoutIsResolved(mod),
1847 else => true,
1848 };
1849 }
1850
1851 pub fn isSinglePointer(ty: Type, mod: *const Module) bool {
1852 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1853 .ptr_type => |ptr_info| ptr_info.flags.size == .One,
1854 else => false,
1855 };
1856 }
1857
1858 /// Asserts `ty` is a pointer.
1859 pub fn ptrSize(ty: Type, mod: *const Module) std.builtin.Type.Pointer.Size {
1860 return ptrSizeOrNull(ty, mod).?;
1861 }
1862
1863 /// Returns `null` if `ty` is not a pointer.
1864 pub fn ptrSizeOrNull(ty: Type, mod: *const Module) ?std.builtin.Type.Pointer.Size {
1865 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1866 .ptr_type => |ptr_info| ptr_info.flags.size,
1867 else => null,
1868 };
1869 }
1870
1871 pub fn isSlice(ty: Type, mod: *const Module) bool {
1872 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1873 .ptr_type => |ptr_type| ptr_type.flags.size == .Slice,
1874 else => false,
1875 };
1876 }
1877
1878 pub fn slicePtrFieldType(ty: Type, mod: *const Module) Type {
1879 return Type.fromInterned(mod.intern_pool.slicePtrType(ty.toIntern()));
1880 }
1881
1882 pub fn isConstPtr(ty: Type, mod: *const Module) bool {
1883 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1884 .ptr_type => |ptr_type| ptr_type.flags.is_const,
1885 else => false,
1886 };
1887 }
1888
1889 pub fn isVolatilePtr(ty: Type, mod: *const Module) bool {
1890 return isVolatilePtrIp(ty, &mod.intern_pool);
1891 }
1892
1893 pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool {
1894 return switch (ip.indexToKey(ty.toIntern())) {
1895 .ptr_type => |ptr_type| ptr_type.flags.is_volatile,
1896 else => false,
1897 };
1898 }
1899
1900 pub fn isAllowzeroPtr(ty: Type, mod: *const Module) bool {
1901 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1902 .ptr_type => |ptr_type| ptr_type.flags.is_allowzero,
1903 .opt_type => true,
1904 else => false,
1905 };
1906 }
1907
1908 pub fn isCPtr(ty: Type, mod: *const Module) bool {
1909 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1910 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1911 else => false,
1912 };
1913 }
1914
1915 pub fn isPtrAtRuntime(ty: Type, mod: *const Module) bool {
1916 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1917 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1918 .Slice => false,
1919 .One, .Many, .C => true,
1920 },
1921 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
1922 .ptr_type => |p| switch (p.flags.size) {
1923 .Slice, .C => false,
1924 .Many, .One => !p.flags.is_allowzero,
1925 },
1926 else => false,
1927 },
1928 else => false,
1929 };
1930 }
1931
1932 /// For pointer-like optionals, returns true, otherwise returns the allowzero property
1933 /// of pointers.
1934 pub fn ptrAllowsZero(ty: Type, mod: *const Module) bool {
1935 if (ty.isPtrLikeOptional(mod)) {
1936 return true;
1937 }
1938 return ty.ptrInfo(mod).flags.is_allowzero;
1939 }
1940
1941 /// See also `isPtrLikeOptional`.
1942 pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool {
1943 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1944 .opt_type => |child_type| child_type == .anyerror_type or switch (mod.intern_pool.indexToKey(child_type)) {
1945 .ptr_type => |ptr_type| ptr_type.flags.size != .C and !ptr_type.flags.is_allowzero,
1946 .error_set_type, .inferred_error_set_type => true,
1947 else => false,
1948 },
1949 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1950 else => false,
1951 };
1952 }
1953
1954 /// Returns true if the type is optional and would be lowered to a single pointer
1955 /// address value, using 0 for null. Note that this returns true for C pointers.
1956 /// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`.
1957 pub fn isPtrLikeOptional(ty: Type, mod: *const Module) bool {
1958 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1959 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1960 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
1961 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1962 .Slice, .C => false,
1963 .Many, .One => !ptr_type.flags.is_allowzero,
1964 },
1965 else => false,
1966 },
1967 else => false,
1968 };
1969 }
1970
1971 /// For *[N]T, returns [N]T.
1972 /// For *T, returns T.
1973 /// For [*]T, returns T.
1974 pub fn childType(ty: Type, mod: *const Module) Type {
1975 return childTypeIp(ty, &mod.intern_pool);
1976 }
1977
1978 pub fn childTypeIp(ty: Type, ip: *const InternPool) Type {
1979 return Type.fromInterned(ip.childType(ty.toIntern()));
1980 }
1981
1982 /// For *[N]T, returns T.
1983 /// For ?*T, returns T.
1984 /// For ?*[N]T, returns T.
1985 /// For ?[*]T, returns T.
1986 /// For *T, returns T.
1987 /// For [*]T, returns T.
1988 /// For [N]T, returns T.
1989 /// For []T, returns T.
1990 /// For anyframe->T, returns T.
1991 pub fn elemType2(ty: Type, mod: *const Module) Type {
1992 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1993 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1994 .One => Type.fromInterned(ptr_type.child).shallowElemType(mod),
1995 .Many, .C, .Slice => Type.fromInterned(ptr_type.child),
1996 },
1997 .anyframe_type => |child| {
1998 assert(child != .none);
1999 return Type.fromInterned(child);
2000 },
2001 .vector_type => |vector_type| Type.fromInterned(vector_type.child),
2002 .array_type => |array_type| Type.fromInterned(array_type.child),
2003 .opt_type => |child| Type.fromInterned(mod.intern_pool.childType(child)),
2004 else => unreachable,
2005 };
2006 }
2007
2008 fn shallowElemType(child_ty: Type, mod: *const Module) Type {
2009 return switch (child_ty.zigTypeTag(mod)) {
2010 .Array, .Vector => child_ty.childType(mod),
2011 else => child_ty,
2012 };
2013 }
2014
2015 /// For vectors, returns the element type. Otherwise returns self.
2016 pub fn scalarType(ty: Type, mod: *Module) Type {
2017 return switch (ty.zigTypeTag(mod)) {
2018 .Vector => ty.childType(mod),
2019 else => ty,
2020 };
2021 }
2022
2023 /// Asserts that the type is an optional.
2024 /// Note that for C pointers this returns the type unmodified.
2025 pub fn optionalChild(ty: Type, mod: *const Module) Type {
2026 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2027 .opt_type => |child| Type.fromInterned(child),
2028 .ptr_type => |ptr_type| b: {
2029 assert(ptr_type.flags.size == .C);
2030 break :b ty;
2031 },
2032 else => unreachable,
2033 };
2034 }
2035
2036 /// Returns the tag type of a union, if the type is a union and it has a tag type.
2037 /// Otherwise, returns `null`.
2038 pub fn unionTagType(ty: Type, mod: *Module) ?Type {
2039 const ip = &mod.intern_pool;
2040 switch (ip.indexToKey(ty.toIntern())) {
2041 .union_type => {},
2042 else => return null,
2043 }
2044 const union_type = ip.loadUnionType(ty.toIntern());
2045 switch (union_type.flagsPtr(ip).runtime_tag) {
2046 .tagged => {
2047 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
2048 return Type.fromInterned(union_type.enum_tag_ty);
2049 },
2050 else => return null,
2051 }
2052 }
2053
2054 /// Same as `unionTagType` but includes safety tag.
2055 /// Codegen should use this version.
2056 pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
2057 const ip = &mod.intern_pool;
2058 return switch (ip.indexToKey(ty.toIntern())) {
2059 .union_type => {
2060 const union_type = ip.loadUnionType(ty.toIntern());
2061 if (!union_type.hasTag(ip)) return null;
2062 assert(union_type.haveFieldTypes(ip));
2063 return Type.fromInterned(union_type.enum_tag_ty);
2064 },
2065 else => null,
2066 };
2067 }
2068
2069 /// Asserts the type is a union; returns the tag type, even if the tag will
2070 /// not be stored at runtime.
2071 pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {
2072 const union_obj = mod.typeToUnion(ty).?;
2073 return Type.fromInterned(union_obj.enum_tag_ty);
2074 }
2075
2076 pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) ?Type {
2077 const ip = &mod.intern_pool;
2078 const union_obj = mod.typeToUnion(ty).?;
2079 const union_fields = union_obj.field_types.get(ip);
2080 const index = mod.unionTagFieldIndex(union_obj, enum_tag) orelse return null;
2081 return Type.fromInterned(union_fields[index]);
2082 }
2083
2084 pub fn unionFieldTypeByIndex(ty: Type, index: usize, mod: *Module) Type {
2085 const ip = &mod.intern_pool;
2086 const union_obj = mod.typeToUnion(ty).?;
2087 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
2088 }
2089
2090 pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
2091 const union_obj = mod.typeToUnion(ty).?;
2092 return mod.unionTagFieldIndex(union_obj, enum_tag);
2093 }
2094
2095 pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
2096 const ip = &mod.intern_pool;
2097 const union_obj = mod.typeToUnion(ty).?;
2098 for (union_obj.field_types.get(ip)) |field_ty| {
2099 if (Type.fromInterned(field_ty).hasRuntimeBits(mod)) return false;
2100 }
2101 return true;
2102 }
2103
2104 /// Returns the type used for backing storage of this union during comptime operations.
2105 /// Asserts the type is either an extern or packed union.
2106 pub fn unionBackingType(ty: Type, mod: *Module) !Type {
2107 return switch (ty.containerLayout(mod)) {
2108 .@"extern" => try mod.arrayType(.{ .len = ty.abiSize(mod), .child = .u8_type }),
2109 .@"packed" => try mod.intType(.unsigned, @intCast(ty.bitSize(mod))),
2110 .auto => unreachable,
2111 };
2112 }
2113
2114 pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {
2115 const ip = &mod.intern_pool;
2116 const union_obj = ip.loadUnionType(ty.toIntern());
2117 return mod.getUnionLayout(union_obj);
2118 }
2119
2120 pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
2121 const ip = &mod.intern_pool;
2122 return switch (ip.indexToKey(ty.toIntern())) {
2123 .struct_type => ip.loadStructType(ty.toIntern()).layout,
2124 .anon_struct_type => .auto,
2125 .union_type => ip.loadUnionType(ty.toIntern()).flagsPtr(ip).layout,
2126 else => unreachable,
2127 };
2128 }
2129
2130 /// Asserts that the type is an error union.
2131 pub fn errorUnionPayload(ty: Type, mod: *Module) Type {
2132 return Type.fromInterned(mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type);
2133 }
2134
2135 /// Asserts that the type is an error union.
2136 pub fn errorUnionSet(ty: Type, mod: *Module) Type {
2137 return Type.fromInterned(mod.intern_pool.errorUnionSet(ty.toIntern()));
2138 }
2139
2140 /// Returns false for unresolved inferred error sets.
2141 pub fn errorSetIsEmpty(ty: Type, mod: *Module) bool {
2142 const ip = &mod.intern_pool;
2143 return switch (ty.toIntern()) {
2144 .anyerror_type, .adhoc_inferred_error_set_type => false,
2145 else => switch (ip.indexToKey(ty.toIntern())) {
2146 .error_set_type => |error_set_type| error_set_type.names.len == 0,
2147 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2148 .none, .anyerror_type => false,
2149 else => |t| ip.indexToKey(t).error_set_type.names.len == 0,
2150 },
2151 else => unreachable,
2152 },
2153 };
2154 }
2155
2156 /// Returns true if it is an error set that includes anyerror, false otherwise.
2157 /// Note that the result may be a false negative if the type did not get error set
2158 /// resolution prior to this call.
2159 pub fn isAnyError(ty: Type, mod: *Module) bool {
2160 const ip = &mod.intern_pool;
2161 return switch (ty.toIntern()) {
2162 .anyerror_type => true,
2163 .adhoc_inferred_error_set_type => false,
2164 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2165 .inferred_error_set_type => |i| ip.funcIesResolved(i).* == .anyerror_type,
2166 else => false,
2167 },
2168 };
2169 }
2170
2171 pub fn isError(ty: Type, mod: *const Module) bool {
2172 return switch (ty.zigTypeTag(mod)) {
2173 .ErrorUnion, .ErrorSet => true,
2174 else => false,
2175 };
2176 }
2177
2178 /// Returns whether ty, which must be an error set, includes an error `name`.
2179 /// Might return a false negative if `ty` is an inferred error set and not fully
2180 /// resolved yet.
2181 pub fn errorSetHasFieldIp(
2182 ip: *const InternPool,
2183 ty: InternPool.Index,
2184 name: InternPool.NullTerminatedString,
2185 ) bool {
2186 return switch (ty) {
2187 .anyerror_type => true,
2188 else => switch (ip.indexToKey(ty)) {
2189 .error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null,
2190 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2191 .anyerror_type => true,
2192 .none => false,
2193 else => |t| ip.indexToKey(t).error_set_type.nameIndex(ip, name) != null,
2194 },
2195 else => unreachable,
2196 },
2197 };
2198 }
2199
2200 /// Returns whether ty, which must be an error set, includes an error `name`.
2201 /// Might return a false negative if `ty` is an inferred error set and not fully
2202 /// resolved yet.
2203 pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool {
2204 const ip = &mod.intern_pool;
2205 return switch (ty.toIntern()) {
2206 .anyerror_type => true,
2207 else => switch (ip.indexToKey(ty.toIntern())) {
2208 .error_set_type => |error_set_type| {
2209 // If the string is not interned, then the field certainly is not present.
2210 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2211 return error_set_type.nameIndex(ip, field_name_interned) != null;
2212 },
2213 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2214 .anyerror_type => true,
2215 .none => false,
2216 else => |t| {
2217 // If the string is not interned, then the field certainly is not present.
2218 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2219 return ip.indexToKey(t).error_set_type.nameIndex(ip, field_name_interned) != null;
2220 },
2221 },
2222 else => unreachable,
2223 },
2224 };
2225 }
2226
2227 /// Asserts the type is an array or vector or struct.
2228 pub fn arrayLen(ty: Type, mod: *const Module) u64 {
2229 return ty.arrayLenIp(&mod.intern_pool);
2230 }
2231
2232 pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 {
2233 return ip.aggregateTypeLen(ty.toIntern());
2234 }
2235
2236 pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 {
2237 return mod.intern_pool.aggregateTypeLenIncludingSentinel(ty.toIntern());
2238 }
2239
2240 pub fn vectorLen(ty: Type, mod: *const Module) u32 {
2241 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2242 .vector_type => |vector_type| vector_type.len,
2243 .anon_struct_type => |tuple| @intCast(tuple.types.len),
2244 else => unreachable,
2245 };
2246 }
2247
2248 /// Asserts the type is an array, pointer or vector.
2249 pub fn sentinel(ty: Type, mod: *const Module) ?Value {
2250 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2251 .vector_type,
2252 .struct_type,
2253 .anon_struct_type,
2254 => null,
2255
2256 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
2257 .ptr_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
2258
2259 else => unreachable,
2260 };
2261 }
2262
2263 /// Returns true if and only if the type is a fixed-width integer.
2264 pub fn isInt(self: Type, mod: *const Module) bool {
2265 return self.toIntern() != .comptime_int_type and
2266 mod.intern_pool.isIntegerType(self.toIntern());
2267 }
2268
2269 /// Returns true if and only if the type is a fixed-width, signed integer.
2270 pub fn isSignedInt(ty: Type, mod: *const Module) bool {
2271 return switch (ty.toIntern()) {
2272 .c_char_type => mod.getTarget().charSignedness() == .signed,
2273 .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,
2274 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2275 .int_type => |int_type| int_type.signedness == .signed,
2276 else => false,
2277 },
2278 };
2279 }
2280
2281 /// Returns true if and only if the type is a fixed-width, unsigned integer.
2282 pub fn isUnsignedInt(ty: Type, mod: *const Module) bool {
2283 return switch (ty.toIntern()) {
2284 .c_char_type => mod.getTarget().charSignedness() == .unsigned,
2285 .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true,
2286 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2287 .int_type => |int_type| int_type.signedness == .unsigned,
2288 else => false,
2289 },
2290 };
2291 }
2292
2293 /// Returns true for integers, enums, error sets, and packed structs.
2294 /// If this function returns true, then intInfo() can be called on the type.
2295 pub fn isAbiInt(ty: Type, mod: *Module) bool {
2296 return switch (ty.zigTypeTag(mod)) {
2297 .Int, .Enum, .ErrorSet => true,
2298 .Struct => ty.containerLayout(mod) == .@"packed",
2299 else => false,
2300 };
2301 }
2302
2303 /// Asserts the type is an integer, enum, error set, or vector of one of them.
2304 pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
2305 const ip = &mod.intern_pool;
2306 const target = mod.getTarget();
2307 var ty = starting_ty;
2308
2309 while (true) switch (ty.toIntern()) {
2310 .anyerror_type, .adhoc_inferred_error_set_type => {
2311 return .{ .signedness = .unsigned, .bits = mod.errorSetBits() };
2312 },
2313 .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() },
2314 .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() },
2315 .c_char_type => return .{ .signedness = mod.getTarget().charSignedness(), .bits = target.c_type_bit_size(.char) },
2316 .c_short_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) },
2317 .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) },
2318 .c_int_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) },
2319 .c_uint_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.uint) },
2320 .c_long_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.long) },
2321 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },
2322 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },
2323 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },
2324 else => switch (ip.indexToKey(ty.toIntern())) {
2325 .int_type => |int_type| return int_type,
2326 .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntType(ip).*),
2327 .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
2328 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
2329
2330 .error_set_type, .inferred_error_set_type => {
2331 return .{ .signedness = .unsigned, .bits = mod.errorSetBits() };
2332 },
2333
2334 .anon_struct_type => unreachable,
2335
2336 .ptr_type => unreachable,
2337 .anyframe_type => unreachable,
2338 .array_type => unreachable,
2339
2340 .opt_type => unreachable,
2341 .error_union_type => unreachable,
2342 .func_type => unreachable,
2343 .simple_type => unreachable, // handled via Index enum tag above
2344
2345 .union_type => unreachable,
2346 .opaque_type => unreachable,
2347
2348 // values, not types
2349 .undef,
2350 .simple_value,
2351 .variable,
2352 .extern_func,
2353 .func,
2354 .int,
2355 .err,
2356 .error_union,
2357 .enum_literal,
2358 .enum_tag,
2359 .empty_enum_value,
2360 .float,
2361 .ptr,
2362 .slice,
2363 .opt,
2364 .aggregate,
2365 .un,
2366 // memoization, not types
2367 .memoized_call,
2368 => unreachable,
2369 },
2370 };
2371 }
2372
2373 pub fn isNamedInt(ty: Type) bool {
2374 return switch (ty.toIntern()) {
2375 .usize_type,
2376 .isize_type,
2377 .c_char_type,
2378 .c_short_type,
2379 .c_ushort_type,
2380 .c_int_type,
2381 .c_uint_type,
2382 .c_long_type,
2383 .c_ulong_type,
2384 .c_longlong_type,
2385 .c_ulonglong_type,
2386 => true,
2387
2388 else => false,
2389 };
2390 }
2391
2392 /// Returns `false` for `comptime_float`.
2393 pub fn isRuntimeFloat(ty: Type) bool {
2394 return switch (ty.toIntern()) {
2395 .f16_type,
2396 .f32_type,
2397 .f64_type,
2398 .f80_type,
2399 .f128_type,
2400 .c_longdouble_type,
2401 => true,
2402
2403 else => false,
2404 };
2405 }
2406
2407 /// Returns `true` for `comptime_float`.
2408 pub fn isAnyFloat(ty: Type) bool {
2409 return switch (ty.toIntern()) {
2410 .f16_type,
2411 .f32_type,
2412 .f64_type,
2413 .f80_type,
2414 .f128_type,
2415 .c_longdouble_type,
2416 .comptime_float_type,
2417 => true,
2418
2419 else => false,
2420 };
2421 }
2422
2423 /// Asserts the type is a fixed-size float or comptime_float.
2424 /// Returns 128 for comptime_float types.
2425 pub fn floatBits(ty: Type, target: Target) u16 {
2426 return switch (ty.toIntern()) {
2427 .f16_type => 16,
2428 .f32_type => 32,
2429 .f64_type => 64,
2430 .f80_type => 80,
2431 .f128_type, .comptime_float_type => 128,
2432 .c_longdouble_type => target.c_type_bit_size(.longdouble),
2433
2434 else => unreachable,
2435 };
2436 }
2437
2438 /// Asserts the type is a function or a function pointer.
2439 pub fn fnReturnType(ty: Type, mod: *Module) Type {
2440 return Type.fromInterned(mod.intern_pool.funcTypeReturnType(ty.toIntern()));
2441 }
2442
2443 /// Asserts the type is a function.
2444 pub fn fnCallingConvention(ty: Type, mod: *Module) std.builtin.CallingConvention {
2445 return mod.intern_pool.indexToKey(ty.toIntern()).func_type.cc;
2446 }
2447
2448 pub fn isValidParamType(self: Type, mod: *const Module) bool {
2449 return switch (self.zigTypeTagOrPoison(mod) catch return true) {
2450 .Opaque, .NoReturn => false,
2451 else => true,
2452 };
2453 }
2454
2455 pub fn isValidReturnType(self: Type, mod: *const Module) bool {
2456 return switch (self.zigTypeTagOrPoison(mod) catch return true) {
2457 .Opaque => false,
2458 else => true,
2459 };
2460 }
2461
2462 /// Asserts the type is a function.
2463 pub fn fnIsVarArgs(ty: Type, mod: *Module) bool {
2464 return mod.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args;
2465 }
2466
2467 pub fn isNumeric(ty: Type, mod: *const Module) bool {
2468 return switch (ty.toIntern()) {
2469 .f16_type,
2470 .f32_type,
2471 .f64_type,
2472 .f80_type,
2473 .f128_type,
2474 .c_longdouble_type,
2475 .comptime_int_type,
2476 .comptime_float_type,
2477 .usize_type,
2478 .isize_type,
2479 .c_char_type,
2480 .c_short_type,
2481 .c_ushort_type,
2482 .c_int_type,
2483 .c_uint_type,
2484 .c_long_type,
2485 .c_ulong_type,
2486 .c_longlong_type,
2487 .c_ulonglong_type,
2488 => true,
2489
2490 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2491 .int_type => true,
2492 else => false,
2493 },
2494 };
2495 }
2496
2497 /// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which
2498 /// resolves field types rather than asserting they are already resolved.
2499 pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value {
2500 var ty = starting_type;
2501 const ip = &mod.intern_pool;
2502 while (true) switch (ty.toIntern()) {
2503 .empty_struct_type => return Value.empty_struct,
2504
2505 else => switch (ip.indexToKey(ty.toIntern())) {
2506 .int_type => |int_type| {
2507 if (int_type.bits == 0) {
2508 return try mod.intValue(ty, 0);
2509 } else {
2510 return null;
2511 }
2512 },
2513
2514 .ptr_type,
2515 .error_union_type,
2516 .func_type,
2517 .anyframe_type,
2518 .error_set_type,
2519 .inferred_error_set_type,
2520 => return null,
2521
2522 inline .array_type, .vector_type => |seq_type, seq_tag| {
2523 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
2524 if (seq_type.len + @intFromBool(has_sentinel) == 0) return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2525 .ty = ty.toIntern(),
2526 .storage = .{ .elems = &.{} },
2527 } })));
2528 if (try Type.fromInterned(seq_type.child).onePossibleValue(mod)) |opv| {
2529 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2530 .ty = ty.toIntern(),
2531 .storage = .{ .repeated_elem = opv.toIntern() },
2532 } })));
2533 }
2534 return null;
2535 },
2536 .opt_type => |child| {
2537 if (child == .noreturn_type) {
2538 return try mod.nullValue(ty);
2539 } else {
2540 return null;
2541 }
2542 },
2543
2544 .simple_type => |t| switch (t) {
2545 .f16,
2546 .f32,
2547 .f64,
2548 .f80,
2549 .f128,
2550 .usize,
2551 .isize,
2552 .c_char,
2553 .c_short,
2554 .c_ushort,
2555 .c_int,
2556 .c_uint,
2557 .c_long,
2558 .c_ulong,
2559 .c_longlong,
2560 .c_ulonglong,
2561 .c_longdouble,
2562 .anyopaque,
2563 .bool,
2564 .type,
2565 .anyerror,
2566 .comptime_int,
2567 .comptime_float,
2568 .enum_literal,
2569 .atomic_order,
2570 .atomic_rmw_op,
2571 .calling_convention,
2572 .address_space,
2573 .float_mode,
2574 .reduce_op,
2575 .call_modifier,
2576 .prefetch_options,
2577 .export_options,
2578 .extern_options,
2579 .type_info,
2580 .adhoc_inferred_error_set,
2581 => return null,
2582
2583 .void => return Value.void,
2584 .noreturn => return Value.@"unreachable",
2585 .null => return Value.null,
2586 .undefined => return Value.undef,
2587
2588 .generic_poison => unreachable,
2589 },
2590 .struct_type => {
2591 const struct_type = ip.loadStructType(ty.toIntern());
2592 assert(struct_type.haveFieldTypes(ip));
2593 if (struct_type.knownNonOpv(ip))
2594 return null;
2595 const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len);
2596 defer mod.gpa.free(field_vals);
2597 for (field_vals, 0..) |*field_val, i_usize| {
2598 const i: u32 = @intCast(i_usize);
2599 if (struct_type.fieldIsComptime(ip, i)) {
2600 assert(struct_type.haveFieldInits(ip));
2601 field_val.* = struct_type.field_inits.get(ip)[i];
2602 continue;
2603 }
2604 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
2605 if (try field_ty.onePossibleValue(mod)) |field_opv| {
2606 field_val.* = field_opv.toIntern();
2607 } else return null;
2608 }
2609
2610 // In this case the struct has no runtime-known fields and
2611 // therefore has one possible value.
2612 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2613 .ty = ty.toIntern(),
2614 .storage = .{ .elems = field_vals },
2615 } })));
2616 },
2617
2618 .anon_struct_type => |tuple| {
2619 for (tuple.values.get(ip)) |val| {
2620 if (val == .none) return null;
2621 }
2622 // In this case the struct has all comptime-known fields and
2623 // therefore has one possible value.
2624 // TODO: write something like getCoercedInts to avoid needing to dupe
2625 const duped_values = try mod.gpa.dupe(InternPool.Index, tuple.values.get(ip));
2626 defer mod.gpa.free(duped_values);
2627 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2628 .ty = ty.toIntern(),
2629 .storage = .{ .elems = duped_values },
2630 } })));
2631 },
2632
2633 .union_type => {
2634 const union_obj = ip.loadUnionType(ty.toIntern());
2635 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(mod)) orelse
2636 return null;
2637 if (union_obj.field_types.len == 0) {
2638 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2639 return Value.fromInterned(only);
2640 }
2641 const only_field_ty = union_obj.field_types.get(ip)[0];
2642 const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(mod)) orelse
2643 return null;
2644 const only = try mod.intern(.{ .un = .{
2645 .ty = ty.toIntern(),
2646 .tag = tag_val.toIntern(),
2647 .val = val_val.toIntern(),
2648 } });
2649 return Value.fromInterned(only);
2650 },
2651 .opaque_type => return null,
2652 .enum_type => {
2653 const enum_type = ip.loadEnumType(ty.toIntern());
2654 switch (enum_type.tag_mode) {
2655 .nonexhaustive => {
2656 if (enum_type.tag_ty == .comptime_int_type) return null;
2657
2658 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {
2659 const only = try mod.intern(.{ .enum_tag = .{
2660 .ty = ty.toIntern(),
2661 .int = int_opv.toIntern(),
2662 } });
2663 return Value.fromInterned(only);
2664 }
2665
2666 return null;
2667 },
2668 .auto, .explicit => {
2669 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
2670
2671 switch (enum_type.names.len) {
2672 0 => {
2673 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2674 return Value.fromInterned(only);
2675 },
2676 1 => {
2677 if (enum_type.values.len == 0) {
2678 const only = try mod.intern(.{ .enum_tag = .{
2679 .ty = ty.toIntern(),
2680 .int = try mod.intern(.{ .int = .{
2681 .ty = enum_type.tag_ty,
2682 .storage = .{ .u64 = 0 },
2683 } }),
2684 } });
2685 return Value.fromInterned(only);
2686 } else {
2687 return Value.fromInterned(enum_type.values.get(ip)[0]);
2688 }
2689 },
2690 else => return null,
2691 }
2692 },
2693 }
2694 },
2695
2696 // values, not types
2697 .undef,
2698 .simple_value,
2699 .variable,
2700 .extern_func,
2701 .func,
2702 .int,
2703 .err,
2704 .error_union,
2705 .enum_literal,
2706 .enum_tag,
2707 .empty_enum_value,
2708 .float,
2709 .ptr,
2710 .slice,
2711 .opt,
2712 .aggregate,
2713 .un,
2714 // memoization, not types
2715 .memoized_call,
2716 => unreachable,
2717 },
2718 };
2719 }
2720
2721 /// During semantic analysis, instead call `Sema.typeRequiresComptime` which
2722 /// resolves field types rather than asserting they are already resolved.
2723 pub fn comptimeOnly(ty: Type, mod: *Module) bool {
2724 return ty.comptimeOnlyAdvanced(mod, null) catch unreachable;
2725 }
2726
2727 /// `generic_poison` will return false.
2728 /// May return false negatives when structs and unions are having their field types resolved.
2729 /// If `opt_sema` is not provided, asserts that the type is sufficiently resolved.
2730 pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool {
2731 const ip = &mod.intern_pool;
2732 return switch (ty.toIntern()) {
2733 .empty_struct_type => false,
2734
2735 else => switch (ip.indexToKey(ty.toIntern())) {
2736 .int_type => false,
2737 .ptr_type => |ptr_type| {
2738 const child_ty = Type.fromInterned(ptr_type.child);
2739 switch (child_ty.zigTypeTag(mod)) {
2740 .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, opt_sema),
2741 .Opaque => return false,
2742 else => return child_ty.comptimeOnlyAdvanced(mod, opt_sema),
2743 }
2744 },
2745 .anyframe_type => |child| {
2746 if (child == .none) return false;
2747 return Type.fromInterned(child).comptimeOnlyAdvanced(mod, opt_sema);
2748 },
2749 .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyAdvanced(mod, opt_sema),
2750 .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyAdvanced(mod, opt_sema),
2751 .opt_type => |child| return Type.fromInterned(child).comptimeOnlyAdvanced(mod, opt_sema),
2752 .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyAdvanced(mod, opt_sema),
2753
2754 .error_set_type,
2755 .inferred_error_set_type,
2756 => false,
2757
2758 // These are function bodies, not function pointers.
2759 .func_type => true,
2760
2761 .simple_type => |t| switch (t) {
2762 .f16,
2763 .f32,
2764 .f64,
2765 .f80,
2766 .f128,
2767 .usize,
2768 .isize,
2769 .c_char,
2770 .c_short,
2771 .c_ushort,
2772 .c_int,
2773 .c_uint,
2774 .c_long,
2775 .c_ulong,
2776 .c_longlong,
2777 .c_ulonglong,
2778 .c_longdouble,
2779 .anyopaque,
2780 .bool,
2781 .void,
2782 .anyerror,
2783 .adhoc_inferred_error_set,
2784 .noreturn,
2785 .generic_poison,
2786 .atomic_order,
2787 .atomic_rmw_op,
2788 .calling_convention,
2789 .address_space,
2790 .float_mode,
2791 .reduce_op,
2792 .call_modifier,
2793 .prefetch_options,
2794 .export_options,
2795 .extern_options,
2796 => false,
2797
2798 .type,
2799 .comptime_int,
2800 .comptime_float,
2801 .null,
2802 .undefined,
2803 .enum_literal,
2804 .type_info,
2805 => true,
2806 },
2807 .struct_type => {
2808 const struct_type = ip.loadStructType(ty.toIntern());
2809 // packed structs cannot be comptime-only because they have a well-defined
2810 // memory layout and every field has a well-defined bit pattern.
2811 if (struct_type.layout == .@"packed")
2812 return false;
2813
2814 // A struct with no fields is not comptime-only.
2815 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2816 .no, .wip => false,
2817 .yes => true,
2818 .unknown => {
2819 // The type is not resolved; assert that we have a Sema.
2820 const sema = opt_sema.?;
2821
2822 if (struct_type.flagsPtr(ip).field_types_wip)
2823 return false;
2824
2825 struct_type.flagsPtr(ip).requires_comptime = .wip;
2826 errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown;
2827
2828 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
2829
2830 for (0..struct_type.field_types.len) |i_usize| {
2831 const i: u32 = @intCast(i_usize);
2832 if (struct_type.fieldIsComptime(ip, i)) continue;
2833 const field_ty = struct_type.field_types.get(ip)[i];
2834 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2835 // Note that this does not cause the layout to
2836 // be considered resolved. Comptime-only types
2837 // still maintain a layout of their
2838 // runtime-known fields.
2839 struct_type.flagsPtr(ip).requires_comptime = .yes;
2840 return true;
2841 }
2842 }
2843
2844 struct_type.flagsPtr(ip).requires_comptime = .no;
2845 return false;
2846 },
2847 };
2848 },
2849
2850 .anon_struct_type => |tuple| {
2851 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2852 const have_comptime_val = val != .none;
2853 if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) return true;
2854 }
2855 return false;
2856 },
2857
2858 .union_type => {
2859 const union_type = ip.loadUnionType(ty.toIntern());
2860 switch (union_type.flagsPtr(ip).requires_comptime) {
2861 .no, .wip => return false,
2862 .yes => return true,
2863 .unknown => {
2864 // The type is not resolved; assert that we have a Sema.
2865 const sema = opt_sema.?;
2866
2867 if (union_type.flagsPtr(ip).status == .field_types_wip)
2868 return false;
2869
2870 union_type.flagsPtr(ip).requires_comptime = .wip;
2871 errdefer union_type.flagsPtr(ip).requires_comptime = .unknown;
2872
2873 try sema.resolveTypeFieldsUnion(ty, union_type);
2874
2875 for (0..union_type.field_types.len) |field_idx| {
2876 const field_ty = union_type.field_types.get(ip)[field_idx];
2877 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2878 union_type.flagsPtr(ip).requires_comptime = .yes;
2879 return true;
2880 }
2881 }
2882
2883 union_type.flagsPtr(ip).requires_comptime = .no;
2884 return false;
2885 },
2886 }
2887 },
2888
2889 .opaque_type => false,
2890
2891 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyAdvanced(mod, opt_sema),
2892
2893 // values, not types
2894 .undef,
2895 .simple_value,
2896 .variable,
2897 .extern_func,
2898 .func,
2899 .int,
2900 .err,
2901 .error_union,
2902 .enum_literal,
2903 .enum_tag,
2904 .empty_enum_value,
2905 .float,
2906 .ptr,
2907 .slice,
2908 .opt,
2909 .aggregate,
2910 .un,
2911 // memoization, not types
2912 .memoized_call,
2913 => unreachable,
2914 },
2915 };
2916 }
2917
2918 pub fn isVector(ty: Type, mod: *const Module) bool {
2919 return ty.zigTypeTag(mod) == .Vector;
2920 }
2921
2922 /// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len.
2923 pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 {
2924 if (!ty.isVector(zcu)) return 0;
2925 const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type;
2926 return v.len * Type.fromInterned(v.child).bitSize(zcu);
2927 }
2928
2929 pub fn isArrayOrVector(ty: Type, mod: *const Module) bool {
2930 return switch (ty.zigTypeTag(mod)) {
2931 .Array, .Vector => true,
2932 else => false,
2933 };
2934 }
2935
2936 pub fn isIndexable(ty: Type, mod: *Module) bool {
2937 return switch (ty.zigTypeTag(mod)) {
2938 .Array, .Vector => true,
2939 .Pointer => switch (ty.ptrSize(mod)) {
2940 .Slice, .Many, .C => true,
2941 .One => switch (ty.childType(mod).zigTypeTag(mod)) {
2942 .Array, .Vector => true,
2943 .Struct => ty.childType(mod).isTuple(mod),
2944 else => false,
2945 },
2946 },
2947 .Struct => ty.isTuple(mod),
2948 else => false,
2949 };
2950 }
2951
2952 pub fn indexableHasLen(ty: Type, mod: *Module) bool {
2953 return switch (ty.zigTypeTag(mod)) {
2954 .Array, .Vector => true,
2955 .Pointer => switch (ty.ptrSize(mod)) {
2956 .Many, .C => false,
2957 .Slice => true,
2958 .One => switch (ty.childType(mod).zigTypeTag(mod)) {
2959 .Array, .Vector => true,
2960 .Struct => ty.childType(mod).isTuple(mod),
2961 else => false,
2962 },
2963 },
2964 .Struct => ty.isTuple(mod),
2965 else => false,
2966 };
2967 }
2968
2969 /// Asserts that the type can have a namespace.
2970 pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
2971 return ty.getNamespace(zcu).?;
2972 }
2973
2974 /// Returns null if the type has no namespace.
2975 pub fn getNamespace(ty: Type, zcu: *Zcu) ?InternPool.OptionalNamespaceIndex {
2976 const ip = &zcu.intern_pool;
2977 return switch (ip.indexToKey(ty.toIntern())) {
2978 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
2979 .struct_type => ip.loadStructType(ty.toIntern()).namespace,
2980 .union_type => ip.loadUnionType(ty.toIntern()).namespace,
2981 .enum_type => ip.loadEnumType(ty.toIntern()).namespace,
2982
2983 .anon_struct_type => .none,
2984 .simple_type => |s| switch (s) {
2985 .anyopaque,
2986 .atomic_order,
2987 .atomic_rmw_op,
2988 .calling_convention,
2989 .address_space,
2990 .float_mode,
2991 .reduce_op,
2992 .call_modifier,
2993 .prefetch_options,
2994 .export_options,
2995 .extern_options,
2996 .type_info,
2997 => .none,
2998 else => null,
2999 },
3000
3001 else => null,
3002 };
3003 }
3004
3005 // Works for vectors and vectors of integers.
3006 pub fn minInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
3007 const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
3008 return if (ty.zigTypeTag(mod) == .Vector) Value.fromInterned((try mod.intern(.{ .aggregate = .{
3009 .ty = dest_ty.toIntern(),
3010 .storage = .{ .repeated_elem = scalar.toIntern() },
3011 } }))) else scalar;
3012 }
3013
3014 /// Asserts that the type is an integer.
3015 pub fn minIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
3016 const info = ty.intInfo(mod);
3017 if (info.signedness == .unsigned) return mod.intValue(dest_ty, 0);
3018 if (info.bits == 0) return mod.intValue(dest_ty, -1);
3019
3020 if (std.math.cast(u6, info.bits - 1)) |shift| {
3021 const n = @as(i64, std.math.minInt(i64)) >> (63 - shift);
3022 return mod.intValue(dest_ty, n);
3023 }
3024
3025 var res = try std.math.big.int.Managed.init(mod.gpa);
3026 defer res.deinit();
3027
3028 try res.setTwosCompIntLimit(.min, info.signedness, info.bits);
3029
3030 return mod.intValue_big(dest_ty, res.toConst());
3031 }
3032
3033 // Works for vectors and vectors of integers.
3034 /// The returned Value will have type dest_ty.
3035 pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
3036 const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
3037 return if (ty.zigTypeTag(mod) == .Vector) Value.fromInterned((try mod.intern(.{ .aggregate = .{
3038 .ty = dest_ty.toIntern(),
3039 .storage = .{ .repeated_elem = scalar.toIntern() },
3040 } }))) else scalar;
3041 }
3042
3043 /// The returned Value will have type dest_ty.
3044 pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
3045 const info = ty.intInfo(mod);
3046
3047 switch (info.bits) {
3048 0 => return switch (info.signedness) {
3049 .signed => try mod.intValue(dest_ty, -1),
3050 .unsigned => try mod.intValue(dest_ty, 0),
3051 },
3052 1 => return switch (info.signedness) {
3053 .signed => try mod.intValue(dest_ty, 0),
3054 .unsigned => try mod.intValue(dest_ty, 1),
3055 },
3056 else => {},
3057 }
3058
3059 if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) {
3060 .signed => {
3061 const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift);
3062 return mod.intValue(dest_ty, n);
3063 },
3064 .unsigned => {
3065 const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift);
3066 return mod.intValue(dest_ty, n);
3067 },
3068 };
3069
3070 var res = try std.math.big.int.Managed.init(mod.gpa);
3071 defer res.deinit();
3072
3073 try res.setTwosCompIntLimit(.max, info.signedness, info.bits);
3074
3075 return mod.intValue_big(dest_ty, res.toConst());
3076 }
3077
3078 /// Asserts the type is an enum or a union.
3079 pub fn intTagType(ty: Type, mod: *Module) Type {
3080 const ip = &mod.intern_pool;
3081 return switch (ip.indexToKey(ty.toIntern())) {
3082 .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(mod),
3083 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
3084 else => unreachable,
3085 };
3086 }
3087
3088 pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
3089 const ip = &mod.intern_pool;
3090 return switch (ip.indexToKey(ty.toIntern())) {
3091 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
3092 .nonexhaustive => true,
3093 .auto, .explicit => false,
3094 },
3095 else => false,
3096 };
3097 }
3098
3099 // Asserts that `ty` is an error set and not `anyerror`.
3100 // Asserts that `ty` is resolved if it is an inferred error set.
3101 pub fn errorSetNames(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
3102 const ip = &mod.intern_pool;
3103 return switch (ip.indexToKey(ty.toIntern())) {
3104 .error_set_type => |x| x.names,
3105 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
3106 .none => unreachable, // unresolved inferred error set
3107 .anyerror_type => unreachable,
3108 else => |t| ip.indexToKey(t).error_set_type.names,
3109 },
3110 else => unreachable,
3111 };
3112 }
3113
3114 pub fn enumFields(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
3115 return mod.intern_pool.loadEnumType(ty.toIntern()).names;
3116 }
3117
3118 pub fn enumFieldCount(ty: Type, mod: *Module) usize {
3119 return mod.intern_pool.loadEnumType(ty.toIntern()).names.len;
3120 }
3121
3122 pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
3123 const ip = &mod.intern_pool;
3124 return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index];
3125 }
3126
3127 pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {
3128 const ip = &mod.intern_pool;
3129 const enum_type = ip.loadEnumType(ty.toIntern());
3130 return enum_type.nameIndex(ip, field_name);
3131 }
3132
3133 /// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
3134 /// an integer which represents the enum value. Returns the field index in
3135 /// declaration order, or `null` if `enum_tag` does not match any field.
3136 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
3137 const ip = &mod.intern_pool;
3138 const enum_type = ip.loadEnumType(ty.toIntern());
3139 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
3140 .int => enum_tag.toIntern(),
3141 .enum_tag => |info| info.int,
3142 else => unreachable,
3143 };
3144 assert(ip.typeOf(int_tag) == enum_type.tag_ty);
3145 return enum_type.tagValueIndex(ip, int_tag);
3146 }
3147
3148 /// Returns none in the case of a tuple which uses the integer index as the field name.
3149 pub fn structFieldName(ty: Type, index: usize, mod: *Module) InternPool.OptionalNullTerminatedString {
3150 const ip = &mod.intern_pool;
3151 return switch (ip.indexToKey(ty.toIntern())) {
3152 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
3153 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index),
3154 else => unreachable,
3155 };
3156 }
3157
3158 pub fn structFieldCount(ty: Type, mod: *Module) u32 {
3159 const ip = &mod.intern_pool;
3160 return switch (ip.indexToKey(ty.toIntern())) {
3161 .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
3162 .anon_struct_type => |anon_struct| anon_struct.types.len,
3163 else => unreachable,
3164 };
3165 }
3166
3167 /// Supports structs and unions.
3168 pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
3169 const ip = &mod.intern_pool;
3170 return switch (ip.indexToKey(ty.toIntern())) {
3171 .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),
3172 .union_type => {
3173 const union_obj = ip.loadUnionType(ty.toIntern());
3174 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
3175 },
3176 .anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]),
3177 else => unreachable,
3178 };
3179 }
3180
3181 pub fn structFieldAlign(ty: Type, index: usize, zcu: *Zcu) Alignment {
3182 return ty.structFieldAlignAdvanced(index, zcu, null) catch unreachable;
3183 }
3184
3185 pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, opt_sema: ?*Sema) !Alignment {
3186 const ip = &zcu.intern_pool;
3187 switch (ip.indexToKey(ty.toIntern())) {
3188 .struct_type => {
3189 const struct_type = ip.loadStructType(ty.toIntern());
3190 assert(struct_type.layout != .@"packed");
3191 const explicit_align = struct_type.fieldAlign(ip, index);
3192 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
3193 if (opt_sema) |sema| {
3194 return sema.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3195 } else {
3196 return zcu.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3197 }
3198 },
3199 .anon_struct_type => |anon_struct| {
3200 return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentAdvanced(zcu, if (opt_sema) |sema| .{ .sema = sema } else .eager)).scalar;
3201 },
3202 .union_type => {
3203 const union_obj = ip.loadUnionType(ty.toIntern());
3204 if (opt_sema) |sema| {
3205 return sema.unionFieldAlignment(union_obj, @intCast(index));
3206 } else {
3207 return zcu.unionFieldNormalAlignment(union_obj, @intCast(index));
3208 }
3209 },
3210 else => unreachable,
3211 }
3212 }
3213
3214 pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value {
3215 const ip = &mod.intern_pool;
3216 switch (ip.indexToKey(ty.toIntern())) {
3217 .struct_type => {
3218 const struct_type = ip.loadStructType(ty.toIntern());
3219 const val = struct_type.fieldInit(ip, index);
3220 // TODO: avoid using `unreachable` to indicate this.
3221 if (val == .none) return Value.@"unreachable";
3222 return Value.fromInterned(val);
3223 },
3224 .anon_struct_type => |anon_struct| {
3225 const val = anon_struct.values.get(ip)[index];
3226 // TODO: avoid using `unreachable` to indicate this.
3227 if (val == .none) return Value.@"unreachable";
3228 return Value.fromInterned(val);
3229 },
3230 else => unreachable,
3231 }
3232 }
3233
3234 pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value {
3235 const ip = &mod.intern_pool;
3236 switch (ip.indexToKey(ty.toIntern())) {
3237 .struct_type => {
3238 const struct_type = ip.loadStructType(ty.toIntern());
3239 if (struct_type.fieldIsComptime(ip, index)) {
3240 assert(struct_type.haveFieldInits(ip));
3241 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);
3242 } else {
3243 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(mod);
3244 }
3245 },
3246 .anon_struct_type => |tuple| {
3247 const val = tuple.values.get(ip)[index];
3248 if (val == .none) {
3249 return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(mod);
3250 } else {
3251 return Value.fromInterned(val);
3252 }
3253 },
3254 else => unreachable,
3255 }
3256 }
3257
3258 pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
3259 const ip = &mod.intern_pool;
3260 return switch (ip.indexToKey(ty.toIntern())) {
3261 .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),
3262 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
3263 else => unreachable,
3264 };
3265 }
3266
3267 pub const FieldOffset = struct {
3268 field: usize,
3269 offset: u64,
3270 };
3271
3272 /// Supports structs and unions.
3273 pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
3274 const ip = &mod.intern_pool;
3275 switch (ip.indexToKey(ty.toIntern())) {
3276 .struct_type => {
3277 const struct_type = ip.loadStructType(ty.toIntern());
3278 assert(struct_type.haveLayout(ip));
3279 assert(struct_type.layout != .@"packed");
3280 return struct_type.offsets.get(ip)[index];
3281 },
3282
3283 .anon_struct_type => |tuple| {
3284 var offset: u64 = 0;
3285 var big_align: Alignment = .none;
3286
3287 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
3288 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(mod)) {
3289 // comptime field
3290 if (i == index) return offset;
3291 continue;
3292 }
3293
3294 const field_align = Type.fromInterned(field_ty).abiAlignment(mod);
3295 big_align = big_align.max(field_align);
3296 offset = field_align.forward(offset);
3297 if (i == index) return offset;
3298 offset += Type.fromInterned(field_ty).abiSize(mod);
3299 }
3300 offset = big_align.max(.@"1").forward(offset);
3301 return offset;
3302 },
3303
3304 .union_type => {
3305 const union_type = ip.loadUnionType(ty.toIntern());
3306 if (!union_type.hasTag(ip))
3307 return 0;
3308 const layout = mod.getUnionLayout(union_type);
3309 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3310 // {Tag, Payload}
3311 return layout.payload_align.forward(layout.tag_size);
3312 } else {
3313 // {Payload, Tag}
3314 return 0;
3315 }
3316 },
3317
3318 else => unreachable,
3319 }
3320 }
3321
3322 pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
3323 return ty.getOwnerDeclOrNull(mod) orelse unreachable;
3324 }
3325
3326 pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
3327 const ip = &mod.intern_pool;
3328 return switch (ip.indexToKey(ty.toIntern())) {
3329 .struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
3330 .union_type => ip.loadUnionType(ty.toIntern()).decl,
3331 .opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
3332 .enum_type => ip.loadEnumType(ty.toIntern()).decl,
3333 else => null,
3334 };
3335 }
3336
3337 pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Module.LazySrcLoc {
3338 const ip = &zcu.intern_pool;
3339 return .{
3340 .base_node_inst = switch (ip.indexToKey(ty.toIntern())) {
3341 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3342 .declared => |d| d.zir_index,
3343 .reified => |r| r.zir_index,
3344 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
3345 .empty_struct => return null,
3346 },
3347 else => return null,
3348 },
3349 .offset = Module.LazySrcLoc.Offset.nodeOffset(0),
3350 };
3351 }
3352
3353 pub fn srcLoc(ty: Type, zcu: *Zcu) Module.LazySrcLoc {
3354 return ty.srcLocOrNull(zcu).?;
3355 }
3356
3357 pub fn isGenericPoison(ty: Type) bool {
3358 return ty.toIntern() == .generic_poison_type;
3359 }
3360
3361 pub fn isTuple(ty: Type, mod: *Module) bool {
3362 const ip = &mod.intern_pool;
3363 return switch (ip.indexToKey(ty.toIntern())) {
3364 .struct_type => {
3365 const struct_type = ip.loadStructType(ty.toIntern());
3366 if (struct_type.layout == .@"packed") return false;
3367 if (struct_type.decl == .none) return false;
3368 return struct_type.flagsPtr(ip).is_tuple;
3369 },
3370 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,
3371 else => false,
3372 };
3373 }
3374
3375 pub fn isAnonStruct(ty: Type, mod: *Module) bool {
3376 if (ty.toIntern() == .empty_struct_type) return true;
3377 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3378 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0,
3379 else => false,
3380 };
3381 }
3382
3383 pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3384 const ip = &mod.intern_pool;
3385 return switch (ip.indexToKey(ty.toIntern())) {
3386 .struct_type => {
3387 const struct_type = ip.loadStructType(ty.toIntern());
3388 if (struct_type.layout == .@"packed") return false;
3389 if (struct_type.decl == .none) return false;
3390 return struct_type.flagsPtr(ip).is_tuple;
3391 },
3392 .anon_struct_type => true,
3393 else => false,
3394 };
3395 }
3396
3397 pub fn isSimpleTuple(ty: Type, mod: *Module) bool {
3398 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3399 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0,
3400 else => false,
3401 };
3402 }
3403
3404 pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3405 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3406 .anon_struct_type => true,
3407 else => false,
3408 };
3409 }
3410
3411 /// Traverses optional child types and error union payloads until the type
3412 /// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
3413 pub fn optEuBaseType(ty: Type, mod: *Module) Type {
3414 var cur = ty;
3415 while (true) switch (cur.zigTypeTag(mod)) {
3416 .Optional => cur = cur.optionalChild(mod),
3417 .ErrorUnion => cur = cur.errorUnionPayload(mod),
3418 else => return cur,
3419 };
3420 }
3421
3422 pub fn toUnsigned(ty: Type, mod: *Module) !Type {
3423 return switch (ty.zigTypeTag(mod)) {
3424 .Int => mod.intType(.unsigned, ty.intInfo(mod).bits),
3425 .Vector => try mod.vectorType(.{
3426 .len = ty.vectorLen(mod),
3427 .child = (try ty.childType(mod).toUnsigned(mod)).toIntern(),
3428 }),
3429 else => unreachable,
3430 };
3431 }
3432
3433 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3434 const ip = &zcu.intern_pool;
3435 return switch (ip.indexToKey(ty.toIntern())) {
3436 .struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
3437 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
3438 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
3439 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
3440 else => null,
3441 };
3442 }
3443
3444 pub fn typeDeclSrcLine(ty: Type, zcu: *const Zcu) ?u32 {
3445 const ip = &zcu.intern_pool;
3446 const tracked = switch (ip.indexToKey(ty.toIntern())) {
3447 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3448 .declared => |d| d.zir_index,
3449 .reified => |r| r.zir_index,
3450 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
3451 .empty_struct => return null,
3452 },
3453 else => return null,
3454 };
3455 const info = tracked.resolveFull(&zcu.intern_pool);
3456 const file = zcu.import_table.values()[zcu.path_digest_map.getIndex(info.path_digest).?];
3457 assert(file.zir_loaded);
3458 const zir = file.zir;
3459 const inst = zir.instructions.get(@intFromEnum(info.inst));
3460 assert(inst.tag == .extended);
3461 return switch (inst.data.extended.opcode) {
3462 .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line,
3463 .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
3464 .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
3465 .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
3466 .reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line,
3467 else => unreachable,
3468 };
3469 }
3470
3471 /// Given a namespace type, returns its list of caotured values.
3472 pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
3473 const ip = &zcu.intern_pool;
3474 return switch (ip.indexToKey(ty.toIntern())) {
3475 .struct_type => ip.loadStructType(ty.toIntern()).captures,
3476 .union_type => ip.loadUnionType(ty.toIntern()).captures,
3477 .enum_type => ip.loadEnumType(ty.toIntern()).captures,
3478 .opaque_type => ip.loadOpaqueType(ty.toIntern()).captures,
3479 else => unreachable,
3480 };
3481 }
3482
3483 pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
3484 var cur_ty: Type = ty;
3485 var cur_len: u64 = 1;
3486 while (cur_ty.zigTypeTag(zcu) == .Array) {
3487 cur_len *= cur_ty.arrayLenIncludingSentinel(zcu);
3488 cur_ty = cur_ty.childType(zcu);
3489 }
3490 return .{ cur_ty, cur_len };
3491 }
3492
3493 pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: u32, zcu: *Zcu) union(enum) {
3494 /// The result is a bit-pointer with the same value and a new packed offset.
3495 bit_ptr: InternPool.Key.PtrType.PackedOffset,
3496 /// The result is a standard pointer.
3497 byte_ptr: struct {
3498 /// The byte offset of the field pointer from the parent pointer value.
3499 offset: u64,
3500 /// The alignment of the field pointer type.
3501 alignment: InternPool.Alignment,
3502 },
3503 } {
3504 comptime assert(Type.packed_struct_layout_version == 2);
3505
3506 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
3507 const field_ty = struct_ty.structFieldType(field_idx, zcu);
3508
3509 var bit_offset: u16 = 0;
3510 var running_bits: u16 = 0;
3511 for (0..struct_ty.structFieldCount(zcu)) |i| {
3512 const f_ty = struct_ty.structFieldType(i, zcu);
3513 if (i == field_idx) {
3514 bit_offset = running_bits;
3515 }
3516 running_bits += @intCast(f_ty.bitSize(zcu));
3517 }
3518
3519 const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0)
3520 .{ parent_ptr_info.packed_offset.host_size, parent_ptr_info.packed_offset.bit_offset + bit_offset }
3521 else
3522 .{ (running_bits + 7) / 8, bit_offset };
3523
3524 // If the field happens to be byte-aligned, simplify the pointer type.
3525 // We can only do this if the pointee's bit size matches its ABI byte size,
3526 // so that loads and stores do not interfere with surrounding packed bits.
3527 //
3528 // TODO: we do not attempt this with big-endian targets yet because of nested
3529 // structs and floats. I need to double-check the desired behavior for big endian
3530 // targets before adding the necessary complications to this code. This will not
3531 // cause miscompilations; it only means the field pointer uses bit masking when it
3532 // might not be strictly necessary.
3533 if (res_bit_offset % 8 == 0 and field_ty.bitSize(zcu) == field_ty.abiSize(zcu) * 8 and zcu.getTarget().cpu.arch.endian() == .little) {
3534 const byte_offset = res_bit_offset / 8;
3535 const new_align = Alignment.fromLog2Units(@ctz(byte_offset | parent_ptr_ty.ptrAlignment(zcu).toByteUnits().?));
3536 return .{ .byte_ptr = .{
3537 .offset = byte_offset,
3538 .alignment = new_align,
3539 } };
3540 }
3541
3542 return .{ .bit_ptr = .{
3543 .host_size = res_host_size,
3544 .bit_offset = res_bit_offset,
3545 } };
3546 }
3547
3548 pub const @"u1": Type = .{ .ip_index = .u1_type };
3549 pub const @"u8": Type = .{ .ip_index = .u8_type };
3550 pub const @"u16": Type = .{ .ip_index = .u16_type };
3551 pub const @"u29": Type = .{ .ip_index = .u29_type };
3552 pub const @"u32": Type = .{ .ip_index = .u32_type };
3553 pub const @"u64": Type = .{ .ip_index = .u64_type };
3554 pub const @"u128": Type = .{ .ip_index = .u128_type };
3555
3556 pub const @"i8": Type = .{ .ip_index = .i8_type };
3557 pub const @"i16": Type = .{ .ip_index = .i16_type };
3558 pub const @"i32": Type = .{ .ip_index = .i32_type };
3559 pub const @"i64": Type = .{ .ip_index = .i64_type };
3560 pub const @"i128": Type = .{ .ip_index = .i128_type };
3561
3562 pub const @"f16": Type = .{ .ip_index = .f16_type };
3563 pub const @"f32": Type = .{ .ip_index = .f32_type };
3564 pub const @"f64": Type = .{ .ip_index = .f64_type };
3565 pub const @"f80": Type = .{ .ip_index = .f80_type };
3566 pub const @"f128": Type = .{ .ip_index = .f128_type };
3567
3568 pub const @"bool": Type = .{ .ip_index = .bool_type };
3569 pub const @"usize": Type = .{ .ip_index = .usize_type };
3570 pub const @"isize": Type = .{ .ip_index = .isize_type };
3571 pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type };
3572 pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type };
3573 pub const @"void": Type = .{ .ip_index = .void_type };
3574 pub const @"type": Type = .{ .ip_index = .type_type };
3575 pub const @"anyerror": Type = .{ .ip_index = .anyerror_type };
3576 pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type };
3577 pub const @"anyframe": Type = .{ .ip_index = .anyframe_type };
3578 pub const @"null": Type = .{ .ip_index = .null_type };
3579 pub const @"undefined": Type = .{ .ip_index = .undefined_type };
3580 pub const @"noreturn": Type = .{ .ip_index = .noreturn_type };
3581
3582 pub const @"c_char": Type = .{ .ip_index = .c_char_type };
3583 pub const @"c_short": Type = .{ .ip_index = .c_short_type };
3584 pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type };
3585 pub const @"c_int": Type = .{ .ip_index = .c_int_type };
3586 pub const @"c_uint": Type = .{ .ip_index = .c_uint_type };
3587 pub const @"c_long": Type = .{ .ip_index = .c_long_type };
3588 pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type };
3589 pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type };
3590 pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type };
3591 pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type };
3592
3593 pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type };
3594 pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type };
3595 pub const single_const_pointer_to_comptime_int: Type = .{
3596 .ip_index = .single_const_pointer_to_comptime_int_type,
3597 };
3598 pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type };
3599 pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type };
3600
3601 pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };
3602
3603 pub fn smallestUnsignedBits(max: u64) u16 {
3604 if (max == 0) return 0;
3605 const base = std.math.log2(max);
3606 const upper = (@as(u64, 1) << @as(u6, @intCast(base))) - 1;
3607 return @as(u16, @intCast(base + @intFromBool(upper < max)));
3608 }
3609
3610 /// This is only used for comptime asserts. Bump this number when you make a change
3611 /// to packed struct layout to find out all the places in the codebase you need to edit!
3612 pub const packed_struct_layout_version = 2;
3613};
3614
3615fn cTypeAlign(target: Target, c_type: Target.CType) Alignment {
3616 return Alignment.fromByteUnits(target.c_type_alignment(c_type));
3617}
test/cases/compile_errors/compileLog_of_tagged_enum_doesnt_crash_the_compiler.zig+1
......@@ -16,6 +16,7 @@ pub export fn entry() void {
1616// target=native
1717//
1818// :6:5: error: found compile log statement
19// :6:5: note: also here
1920//
2021// Compile Log Output:
2122// @as(tmp.Bar, .{ .X = 123 })
test/cases/compile_errors/compile_log.zig+1
......@@ -18,6 +18,7 @@ export fn baz() void {
1818//
1919// :6:5: error: found compile log statement
2020// :12:5: note: also here
21// :6:5: note: also here
2122//
2223// Compile Log Output:
2324// @as(*const [5:0]u8, "begin")
test/cases/compile_errors/direct_struct_loop.zig-1
......@@ -10,4 +10,3 @@ export fn entry() usize {
1010// target=native
1111//
1212// :1:11: error: struct 'tmp.A' depends on itself
13// :2:5: note: while checking this field
test/cases/compile_errors/indirect_struct_loop.zig-3
......@@ -16,6 +16,3 @@ export fn entry() usize {
1616// target=native
1717//
1818// :1:11: error: struct 'tmp.A' depends on itself
19// :8:5: note: while checking this field
20// :5:5: note: while checking this field
21// :2:5: note: while checking this field
test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_struct_that_contains_itself.zig-1
......@@ -13,4 +13,3 @@ export fn entry() usize {
1313// target=native
1414//
1515// :1:13: error: struct 'tmp.Foo' depends on itself
16// :2:5: note: while checking this field
test/cases/compile_errors/instantiating_an_undefined_value_for_an_invalid_union_that_contains_itself.zig-1
......@@ -13,4 +13,3 @@ export fn entry() usize {
1313// target=native
1414//
1515// :1:13: error: union 'tmp.Foo' depends on itself
16// :2:5: note: while checking this field
test/cases/compile_errors/invalid_dependency_on_struct_size.zig-1
......@@ -16,4 +16,3 @@ comptime {
1616// target=native
1717//
1818// :6:21: error: struct layout depends on it having runtime bits
19// :4:13: note: while checking this field
test/cases/compile_errors/struct_depends_on_itself_via_optional_field.zig-2
......@@ -15,5 +15,3 @@ export fn entry() void {
1515// target=native
1616//
1717// :1:17: error: struct 'tmp.LhsExpr' depends on itself
18// :5:5: note: while checking this field
19// :2:5: note: while checking this field
test/cases/compile_errors/struct_type_returned_from_non-generic_function.zig+1-1
......@@ -1,5 +1,5 @@
11pub export fn entry(param: usize) usize {
2 return struct { param };
2 return struct { @TypeOf(param) };
33}
44
55// error
test/src/Cases.zig+33-670
......@@ -395,10 +395,7 @@ fn addFromDirInner(
395395 if (entry.kind != .file) continue;
396396
397397 // Ignore stuff such as .swp files
398 switch (Compilation.classifyFileExt(entry.basename)) {
399 .unknown => continue,
400 else => {},
401 }
398 if (!knownFileExtension(entry.basename)) continue;
402399 try filenames.append(try ctx.arena.dupe(u8, entry.path));
403400 }
404401
......@@ -623,8 +620,6 @@ pub fn lowerToBuildSteps(
623620 b: *std.Build,
624621 parent_step: *std.Build.Step,
625622 test_filters: []const []const u8,
626 cases_dir_path: []const u8,
627 incremental_exe: *std.Build.Step.Compile,
628623) void {
629624 const host = std.zig.system.resolveTargetQuery(.{}) catch |err|
630625 std.debug.panic("unable to detect native host: {s}\n", .{@errorName(err)});
......@@ -637,20 +632,11 @@ pub fn lowerToBuildSteps(
637632 // compilation is in a happier state.
638633 continue;
639634 }
640 for (test_filters) |test_filter| {
641 if (std.mem.indexOf(u8, incr_case.base_path, test_filter)) |_| break;
642 } else if (test_filters.len > 0) continue;
643 const case_base_path_with_dir = std.fs.path.join(b.allocator, &.{
644 cases_dir_path, incr_case.base_path,
645 }) catch @panic("OOM");
646 const run = b.addRunArtifact(incremental_exe);
647 run.setName(incr_case.base_path);
648 run.addArgs(&.{
649 case_base_path_with_dir,
650 b.graph.zig_exe,
651 });
652 run.expectStdOutEqual("");
653 parent_step.dependOn(&run.step);
635 // TODO: the logic for running these was bad, so I've ripped it out. Rewrite this
636 // in a way that actually spawns the compiler, communicating with it over the
637 // compiler server protocol.
638 _ = incr_case;
639 @panic("TODO implement incremental test case executor");
654640 }
655641
656642 for (self.cases.items) |case| {
......@@ -1236,192 +1222,6 @@ const assert = std.debug.assert;
12361222const Allocator = std.mem.Allocator;
12371223const getExternalExecutor = std.zig.system.getExternalExecutor;
12381224
1239const Compilation = @import("../../src/Compilation.zig");
1240const zig_h = @import("../../src/link.zig").File.C.zig_h;
1241const introspect = @import("../../src/introspect.zig");
1242const ThreadPool = std.Thread.Pool;
1243const WaitGroup = std.Thread.WaitGroup;
1244const build_options = @import("build_options");
1245const Package = @import("../../src/Package.zig");
1246
1247pub const std_options = .{
1248 .log_level = .err,
1249};
1250
1251var general_purpose_allocator = std.heap.GeneralPurposeAllocator(.{
1252 .stack_trace_frames = build_options.mem_leak_frames,
1253}){};
1254
1255// TODO: instead of embedding the compiler in this process, spawn the compiler
1256// as a sub-process and communicate the updates using the compiler protocol.
1257pub fn main() !void {
1258 const use_gpa = build_options.force_gpa or !builtin.link_libc;
1259 const gpa = gpa: {
1260 if (use_gpa) {
1261 break :gpa general_purpose_allocator.allocator();
1262 }
1263 // We would prefer to use raw libc allocator here, but cannot
1264 // use it if it won't support the alignment we need.
1265 if (@alignOf(std.c.max_align_t) < @alignOf(i128)) {
1266 break :gpa std.heap.c_allocator;
1267 }
1268 break :gpa std.heap.raw_c_allocator;
1269 };
1270
1271 var single_threaded_arena = std.heap.ArenaAllocator.init(gpa);
1272 defer single_threaded_arena.deinit();
1273
1274 var thread_safe_arena: std.heap.ThreadSafeAllocator = .{
1275 .child_allocator = single_threaded_arena.allocator(),
1276 };
1277 const arena = thread_safe_arena.allocator();
1278
1279 const args = try std.process.argsAlloc(arena);
1280 const case_file_path = args[1];
1281 const zig_exe_path = args[2];
1282
1283 var filenames = std.ArrayList([]const u8).init(arena);
1284
1285 const case_dirname = std.fs.path.dirname(case_file_path).?;
1286 var iterable_dir = try std.fs.cwd().openDir(case_dirname, .{ .iterate = true });
1287 defer iterable_dir.close();
1288
1289 if (std.mem.endsWith(u8, case_file_path, ".0.zig")) {
1290 const stem = case_file_path[case_dirname.len + 1 .. case_file_path.len - "0.zig".len];
1291 var it = iterable_dir.iterate();
1292 while (try it.next()) |entry| {
1293 if (entry.kind != .file) continue;
1294 if (!std.mem.startsWith(u8, entry.name, stem)) continue;
1295 try filenames.append(try std.fs.path.join(arena, &.{ case_dirname, entry.name }));
1296 }
1297 } else {
1298 try filenames.append(case_file_path);
1299 }
1300
1301 if (filenames.items.len == 0) {
1302 std.debug.print("failed to find the input source file(s) from '{s}'\n", .{
1303 case_file_path,
1304 });
1305 std.process.exit(1);
1306 }
1307
1308 // Sort filenames, so that incremental tests are contiguous and in-order
1309 sortTestFilenames(filenames.items);
1310
1311 var ctx = Cases.init(gpa, arena);
1312
1313 var test_it = TestIterator{ .filenames = filenames.items };
1314 while (try test_it.next()) |batch| {
1315 const strategy: TestStrategy = if (batch.len > 1) .incremental else .independent;
1316 var cases = std.ArrayList(usize).init(arena);
1317
1318 for (batch) |filename| {
1319 const max_file_size = 10 * 1024 * 1024;
1320 const src = try iterable_dir.readFileAllocOptions(arena, filename, max_file_size, null, 1, 0);
1321
1322 // Parse the manifest
1323 var manifest = try TestManifest.parse(arena, src);
1324
1325 if (cases.items.len == 0) {
1326 const backends = try manifest.getConfigForKeyAlloc(arena, "backend", Backend);
1327 const targets = try manifest.getConfigForKeyAlloc(arena, "target", std.Target.Query);
1328 const c_frontends = try manifest.getConfigForKeyAlloc(ctx.arena, "c_frontend", CFrontend);
1329 const is_test = try manifest.getConfigForKeyAssertSingle("is_test", bool);
1330 const link_libc = try manifest.getConfigForKeyAssertSingle("link_libc", bool);
1331 const output_mode = try manifest.getConfigForKeyAssertSingle("output_mode", std.builtin.OutputMode);
1332
1333 if (manifest.type == .translate_c) {
1334 for (c_frontends) |c_frontend| {
1335 for (targets) |target_query| {
1336 const output = try manifest.trailingLinesSplit(ctx.arena);
1337 try ctx.translate.append(.{
1338 .name = std.fs.path.stem(filename),
1339 .c_frontend = c_frontend,
1340 .target = resolveTargetQuery(target_query),
1341 .is_test = is_test,
1342 .link_libc = link_libc,
1343 .input = src,
1344 .kind = .{ .translate = output },
1345 });
1346 }
1347 }
1348 continue;
1349 }
1350 if (manifest.type == .run_translated_c) {
1351 for (c_frontends) |c_frontend| {
1352 for (targets) |target_query| {
1353 const output = try manifest.trailingSplit(ctx.arena);
1354 try ctx.translate.append(.{
1355 .name = std.fs.path.stem(filename),
1356 .c_frontend = c_frontend,
1357 .target = resolveTargetQuery(target_query),
1358 .is_test = is_test,
1359 .link_libc = link_libc,
1360 .output = output,
1361 .input = src,
1362 .kind = .{ .run = output },
1363 });
1364 }
1365 }
1366 continue;
1367 }
1368
1369 // Cross-product to get all possible test combinations
1370 for (backends) |backend| {
1371 for (targets) |target| {
1372 const next = ctx.cases.items.len;
1373 try ctx.cases.append(.{
1374 .name = std.fs.path.stem(filename),
1375 .target = target,
1376 .backend = backend,
1377 .updates = std.ArrayList(Cases.Update).init(ctx.cases.allocator),
1378 .is_test = is_test,
1379 .output_mode = output_mode,
1380 .link_libc = backend == .llvm,
1381 .deps = std.ArrayList(DepModule).init(ctx.cases.allocator),
1382 });
1383 try cases.append(next);
1384 }
1385 }
1386 }
1387
1388 for (cases.items) |case_index| {
1389 const case = &ctx.cases.items[case_index];
1390 if (strategy == .incremental and case.backend == .stage2 and case.target.getCpuArch() == .x86_64 and !case.link_libc and case.target.getOsTag() != .plan9) {
1391 // https://github.com/ziglang/zig/issues/15174
1392 continue;
1393 }
1394
1395 switch (manifest.type) {
1396 .compile => {
1397 case.addCompile(src);
1398 },
1399 .@"error" => {
1400 const errors = try manifest.trailingLines(arena);
1401 switch (strategy) {
1402 .independent => {
1403 case.addError(src, errors);
1404 },
1405 .incremental => {
1406 case.addErrorNamed("update", src, errors);
1407 },
1408 }
1409 },
1410 .run => {
1411 const output = try manifest.trailingSplit(ctx.arena);
1412 case.addCompareOutput(src, output);
1413 },
1414 .translate_c => @panic("c_frontend specified for compile case"),
1415 .run_translated_c => @panic("c_frontend specified for compile case"),
1416 .cli => @panic("TODO cli tests"),
1417 }
1418 }
1419 }
1420 }
1421
1422 return runCases(&ctx, zig_exe_path);
1423}
1424
14251225fn resolveTargetQuery(query: std.Target.Query) std.Build.ResolvedTarget {
14261226 return .{
14271227 .query = query,
......@@ -1430,470 +1230,33 @@ fn resolveTargetQuery(query: std.Target.Query) std.Build.ResolvedTarget {
14301230 };
14311231}
14321232
1433fn runCases(self: *Cases, zig_exe_path: []const u8) !void {
1434 const host = try std.zig.system.resolveTargetQuery(.{});
1435
1436 var progress = std.Progress{};
1437 const root_node = progress.start("compiler", self.cases.items.len);
1438 progress.terminal = null;
1439 defer root_node.end();
1440
1441 var zig_lib_directory = try introspect.findZigLibDirFromSelfExe(self.gpa, zig_exe_path);
1442 defer zig_lib_directory.handle.close();
1443 defer self.gpa.free(zig_lib_directory.path.?);
1444
1445 var aux_thread_pool: ThreadPool = undefined;
1446 try aux_thread_pool.init(.{ .allocator = self.gpa });
1447 defer aux_thread_pool.deinit();
1448
1449 // Use the same global cache dir for all the tests, such that we for example don't have to
1450 // rebuild musl libc for every case (when LLVM backend is enabled).
1451 var global_tmp = std.testing.tmpDir(.{});
1452 defer global_tmp.cleanup();
1453
1454 var cache_dir = try global_tmp.dir.makeOpenPath(".zig-cache", .{});
1455 defer cache_dir.close();
1456 const tmp_dir_path = try std.fs.path.join(self.gpa, &[_][]const u8{ ".", ".zig-cache", "tmp", &global_tmp.sub_path });
1457 defer self.gpa.free(tmp_dir_path);
1458
1459 const global_cache_directory: Compilation.Directory = .{
1460 .handle = cache_dir,
1461 .path = try std.fs.path.join(self.gpa, &[_][]const u8{ tmp_dir_path, ".zig-cache" }),
1462 };
1463 defer self.gpa.free(global_cache_directory.path.?);
1464
1465 {
1466 for (self.cases.items) |*case| {
1467 if (build_options.skip_non_native) {
1468 if (case.target.getCpuArch() != builtin.cpu.arch)
1469 continue;
1470 if (case.target.getObjectFormat() != builtin.object_format)
1471 continue;
1472 }
1473
1474 // Skip tests that require LLVM backend when it is not available
1475 if (!build_options.have_llvm and case.backend == .llvm)
1476 continue;
1477
1478 assert(case.backend != .stage1);
1479
1480 for (build_options.test_filters) |test_filter| {
1481 if (std.mem.indexOf(u8, case.name, test_filter)) |_| break;
1482 } else if (build_options.test_filters.len > 0) continue;
1483
1484 var prg_node = root_node.start(case.name, case.updates.items.len);
1485 prg_node.activate();
1486 defer prg_node.end();
1487
1488 try runOneCase(
1489 self.gpa,
1490 &prg_node,
1491 case.*,
1492 zig_lib_directory,
1493 zig_exe_path,
1494 &aux_thread_pool,
1495 global_cache_directory,
1496 host,
1497 );
1498 }
1499
1500 for (self.translate.items) |*case| {
1501 _ = case;
1502 @panic("TODO is this even used?");
1503 }
1504 }
1505}
1506
1507fn runOneCase(
1508 allocator: Allocator,
1509 root_node: *std.Progress.Node,
1510 case: Case,
1511 zig_lib_directory: Compilation.Directory,
1512 zig_exe_path: []const u8,
1513 thread_pool: *ThreadPool,
1514 global_cache_directory: Compilation.Directory,
1515 host: std.Target,
1516) !void {
1517 const tmp_src_path = "tmp.zig";
1518 const enable_rosetta = build_options.enable_rosetta;
1519 const enable_qemu = build_options.enable_qemu;
1520 const enable_wine = build_options.enable_wine;
1521 const enable_wasmtime = build_options.enable_wasmtime;
1522 const enable_darling = build_options.enable_darling;
1523 const glibc_runtimes_dir: ?[]const u8 = build_options.glibc_runtimes_dir;
1524
1525 const target = try std.zig.system.resolveTargetQuery(case.target);
1526
1527 var arena_allocator = std.heap.ArenaAllocator.init(allocator);
1528 defer arena_allocator.deinit();
1529 const arena = arena_allocator.allocator();
1530
1531 var tmp = std.testing.tmpDir(.{});
1532 defer tmp.cleanup();
1533
1534 var cache_dir = try tmp.dir.makeOpenPath(".zig-cache", .{});
1535 defer cache_dir.close();
1536
1537 const tmp_dir_path = try std.fs.path.join(
1538 arena,
1539 &[_][]const u8{ ".", ".zig-cache", "tmp", &tmp.sub_path },
1540 );
1541 const local_cache_path = try std.fs.path.join(
1542 arena,
1543 &[_][]const u8{ tmp_dir_path, ".zig-cache" },
1544 );
1545
1546 const zig_cache_directory: Compilation.Directory = .{
1547 .handle = cache_dir,
1548 .path = local_cache_path,
1549 };
1550
1551 var main_pkg: Package = .{
1552 .root_src_directory = .{ .path = tmp_dir_path, .handle = tmp.dir },
1553 .root_src_path = tmp_src_path,
1554 };
1555 defer {
1556 var it = main_pkg.table.iterator();
1557 while (it.next()) |kv| {
1558 allocator.free(kv.key_ptr.*);
1559 kv.value_ptr.*.destroy(allocator);
1560 }
1561 main_pkg.table.deinit(allocator);
1562 }
1563
1564 for (case.deps.items) |dep| {
1565 var pkg = try Package.create(
1566 allocator,
1567 tmp_dir_path,
1568 dep.path,
1569 );
1570 errdefer pkg.destroy(allocator);
1571 try main_pkg.add(allocator, dep.name, pkg);
1233fn knownFileExtension(filename: []const u8) bool {
1234 // List taken from `Compilation.classifyFileExt` in the compiler.
1235 for ([_][]const u8{
1236 ".c", ".C", ".cc", ".cpp",
1237 ".cxx", ".stub", ".m", ".mm",
1238 ".ll", ".bc", ".s", ".S",
1239 ".h", ".zig", ".so", ".dll",
1240 ".dylib", ".tbd", ".a", ".lib",
1241 ".o", ".obj", ".cu", ".def",
1242 ".rc", ".res", ".manifest",
1243 }) |ext| {
1244 if (std.mem.endsWith(u8, filename, ext)) return true;
15721245 }
1573
1574 const bin_name = try std.zig.binNameAlloc(arena, .{
1575 .root_name = "test_case",
1576 .target = target,
1577 .output_mode = case.output_mode,
1578 });
1579
1580 const emit_directory: Compilation.Directory = .{
1581 .path = tmp_dir_path,
1582 .handle = tmp.dir,
1583 };
1584 const emit_bin: Compilation.EmitLoc = .{
1585 .directory = emit_directory,
1586 .basename = bin_name,
1587 };
1588 const emit_h: ?Compilation.EmitLoc = if (case.emit_h) .{
1589 .directory = emit_directory,
1590 .basename = "test_case.h",
1591 } else null;
1592 const use_llvm: bool = switch (case.backend) {
1593 .llvm => true,
1594 else => false,
1595 };
1596 const comp = try Compilation.create(allocator, .{
1597 .local_cache_directory = zig_cache_directory,
1598 .global_cache_directory = global_cache_directory,
1599 .zig_lib_directory = zig_lib_directory,
1600 .thread_pool = thread_pool,
1601 .root_name = "test_case",
1602 .target = target,
1603 // TODO: support tests for object file building, and library builds
1604 // and linking. This will require a rework to support multi-file
1605 // tests.
1606 .output_mode = case.output_mode,
1607 .is_test = case.is_test,
1608 .optimize_mode = case.optimize_mode,
1609 .emit_bin = emit_bin,
1610 .emit_h = emit_h,
1611 .main_pkg = &main_pkg,
1612 .keep_source_files_loaded = true,
1613 .is_native_os = case.target.isNativeOs(),
1614 .is_native_abi = case.target.isNativeAbi(),
1615 .dynamic_linker = target.dynamic_linker.get(),
1616 .link_libc = case.link_libc,
1617 .use_llvm = use_llvm,
1618 .self_exe_path = zig_exe_path,
1619 // TODO instead of turning off color, pass in a std.Progress.Node
1620 .color = .off,
1621 .reference_trace = 0,
1622 // TODO: force self-hosted linkers with stage2 backend to avoid LLD creeping in
1623 // until the auto-select mechanism deems them worthy
1624 .use_lld = switch (case.backend) {
1625 .stage2 => false,
1626 else => null,
1627 },
1628 });
1629 defer comp.destroy();
1630
1631 update: for (case.updates.items, 0..) |update, update_index| {
1632 var update_node = root_node.start(update.name, 3);
1633 update_node.activate();
1634 defer update_node.end();
1635
1636 var sync_node = update_node.start("write", 0);
1637 sync_node.activate();
1638 for (update.files.items) |file| {
1639 try tmp.dir.writeFile(.{ .sub_path = file.path, .data = file.src });
1640 }
1641 sync_node.end();
1642
1643 var module_node = update_node.start("parse/analysis/codegen", 0);
1644 module_node.activate();
1645 try comp.makeBinFileWritable();
1646 try comp.update(&module_node);
1647 module_node.end();
1648
1649 if (update.case != .Error) {
1650 var all_errors = try comp.getAllErrorsAlloc();
1651 defer all_errors.deinit(allocator);
1652 if (all_errors.errorMessageCount() > 0) {
1653 all_errors.renderToStdErr(.{
1654 .ttyconf = std.io.tty.detectConfig(std.io.getStdErr()),
1655 });
1656 // TODO print generated C code
1657 return error.UnexpectedCompileErrors;
1658 }
1659 }
1660
1661 switch (update.case) {
1662 .Header => |expected_output| {
1663 var file = try tmp.dir.openFile("test_case.h", .{ .mode = .read_only });
1664 defer file.close();
1665 const out = try file.reader().readAllAlloc(arena, 5 * 1024 * 1024);
1666
1667 try std.testing.expectEqualStrings(expected_output, out);
1668 },
1669 .CompareObjectFile => |expected_output| {
1670 var file = try tmp.dir.openFile(bin_name, .{ .mode = .read_only });
1671 defer file.close();
1672 const out = try file.reader().readAllAlloc(arena, 5 * 1024 * 1024);
1673
1674 try std.testing.expectEqualStrings(expected_output, out);
1675 },
1676 .Compile => {},
1677 .Error => |expected_errors| {
1678 var test_node = update_node.start("assert", 0);
1679 test_node.activate();
1680 defer test_node.end();
1681
1682 var error_bundle = try comp.getAllErrorsAlloc();
1683 defer error_bundle.deinit(allocator);
1684
1685 if (error_bundle.errorMessageCount() == 0) {
1686 return error.ExpectedCompilationErrors;
1687 }
1688
1689 var actual_stderr = std.ArrayList(u8).init(arena);
1690 try error_bundle.renderToWriter(.{
1691 .ttyconf = .no_color,
1692 .include_reference_trace = false,
1693 .include_source_line = false,
1694 }, actual_stderr.writer());
1695
1696 // Render the expected lines into a string that we can compare verbatim.
1697 var expected_generated = std.ArrayList(u8).init(arena);
1698
1699 var actual_line_it = std.mem.splitScalar(u8, actual_stderr.items, '\n');
1700 for (expected_errors) |expect_line| {
1701 const actual_line = actual_line_it.next() orelse {
1702 try expected_generated.appendSlice(expect_line);
1703 try expected_generated.append('\n');
1704 continue;
1705 };
1706 if (std.mem.endsWith(u8, actual_line, expect_line)) {
1707 try expected_generated.appendSlice(actual_line);
1708 try expected_generated.append('\n');
1709 continue;
1710 }
1711 if (std.mem.startsWith(u8, expect_line, ":?:?: ")) {
1712 if (std.mem.endsWith(u8, actual_line, expect_line[":?:?: ".len..])) {
1713 try expected_generated.appendSlice(actual_line);
1714 try expected_generated.append('\n');
1715 continue;
1716 }
1717 }
1718 try expected_generated.appendSlice(expect_line);
1719 try expected_generated.append('\n');
1720 }
1721
1722 try std.testing.expectEqualStrings(expected_generated.items, actual_stderr.items);
1723 },
1724 .Execution => |expected_stdout| {
1725 if (!std.process.can_spawn) {
1726 std.debug.print("Unable to spawn child processes on {s}, skipping test.\n", .{@tagName(builtin.os.tag)});
1727 continue :update; // Pass test.
1728 }
1729
1730 update_node.setEstimatedTotalItems(4);
1731
1732 var argv = std.ArrayList([]const u8).init(allocator);
1733 defer argv.deinit();
1734
1735 const exec_result = x: {
1736 var exec_node = update_node.start("execute", 0);
1737 exec_node.activate();
1738 defer exec_node.end();
1739
1740 // We go out of our way here to use the unique temporary directory name in
1741 // the exe_path so that it makes its way into the cache hash, avoiding
1742 // cache collisions from multiple threads doing `zig run` at the same time
1743 // on the same test_case.c input filename.
1744 const ss = std.fs.path.sep_str;
1745 const exe_path = try std.fmt.allocPrint(
1746 arena,
1747 ".." ++ ss ++ "{s}" ++ ss ++ "{s}",
1748 .{ &tmp.sub_path, bin_name },
1749 );
1750 if (case.target.ofmt != null and case.target.ofmt.? == .c) {
1751 if (getExternalExecutor(host, &target, .{ .link_libc = true }) != .native) {
1752 // We wouldn't be able to run the compiled C code.
1753 continue :update; // Pass test.
1754 }
1755 try argv.appendSlice(&[_][]const u8{
1756 zig_exe_path,
1757 "run",
1758 "-cflags",
1759 "-std=c99",
1760 "-pedantic",
1761 "-Werror",
1762 "-Wno-incompatible-library-redeclaration", // https://github.com/ziglang/zig/issues/875
1763 "--",
1764 "-lc",
1765 exe_path,
1766 });
1767 if (zig_lib_directory.path) |p| {
1768 try argv.appendSlice(&.{ "-I", p });
1769 }
1770 } else switch (getExternalExecutor(host, &target, .{ .link_libc = case.link_libc })) {
1771 .native => {
1772 if (case.backend == .stage2 and case.target.getCpuArch().isArmOrThumb()) {
1773 // https://github.com/ziglang/zig/issues/13623
1774 continue :update; // Pass test.
1775 }
1776 try argv.append(exe_path);
1777 },
1778 .bad_dl, .bad_os_or_cpu => continue :update, // Pass test.
1779
1780 .rosetta => if (enable_rosetta) {
1781 try argv.append(exe_path);
1782 } else {
1783 continue :update; // Rosetta not available, pass test.
1784 },
1785
1786 .qemu => |qemu_bin_name| if (enable_qemu) {
1787 const need_cross_glibc = target.isGnuLibC() and case.link_libc;
1788 const glibc_dir_arg: ?[]const u8 = if (need_cross_glibc)
1789 glibc_runtimes_dir orelse continue :update // glibc dir not available; pass test
1790 else
1791 null;
1792 try argv.append(qemu_bin_name);
1793 if (glibc_dir_arg) |dir| {
1794 const linux_triple = try target.linuxTriple(arena);
1795 const full_dir = try std.fs.path.join(arena, &[_][]const u8{
1796 dir,
1797 linux_triple,
1798 });
1799
1800 try argv.append("-L");
1801 try argv.append(full_dir);
1802 }
1803 try argv.append(exe_path);
1804 } else {
1805 continue :update; // QEMU not available; pass test.
1806 },
1807
1808 .wine => |wine_bin_name| if (enable_wine) {
1809 try argv.append(wine_bin_name);
1810 try argv.append(exe_path);
1811 } else {
1812 continue :update; // Wine not available; pass test.
1813 },
1814
1815 .wasmtime => |wasmtime_bin_name| if (enable_wasmtime) {
1816 try argv.append(wasmtime_bin_name);
1817 try argv.append("--dir=.");
1818 try argv.append(exe_path);
1819 } else {
1820 continue :update; // wasmtime not available; pass test.
1821 },
1822
1823 .darling => |darling_bin_name| if (enable_darling) {
1824 try argv.append(darling_bin_name);
1825 // Since we use relative to cwd here, we invoke darling with
1826 // "shell" subcommand.
1827 try argv.append("shell");
1828 try argv.append(exe_path);
1829 } else {
1830 continue :update; // Darling not available; pass test.
1831 },
1832 }
1833
1834 try comp.makeBinFileExecutable();
1835
1836 while (true) {
1837 break :x std.process.Child.run(.{
1838 .allocator = allocator,
1839 .argv = argv.items,
1840 .cwd_dir = tmp.dir,
1841 .cwd = tmp_dir_path,
1842 }) catch |err| switch (err) {
1843 error.FileBusy => {
1844 // There is a fundamental design flaw in Unix systems with how
1845 // ETXTBSY interacts with fork+exec.
1846 // https://github.com/golang/go/issues/22315
1847 // https://bugs.openjdk.org/browse/JDK-8068370
1848 // Unfortunately, this could be a real error, but we can't
1849 // tell the difference here.
1850 continue;
1851 },
1852 else => {
1853 std.debug.print("\n{s}.{d} The following command failed with {s}:\n", .{
1854 case.name, update_index, @errorName(err),
1855 });
1856 dumpArgs(argv.items);
1857 return error.ChildProcessExecution;
1858 },
1859 };
1860 }
1861 };
1862 var test_node = update_node.start("test", 0);
1863 test_node.activate();
1864 defer test_node.end();
1865 defer allocator.free(exec_result.stdout);
1866 defer allocator.free(exec_result.stderr);
1867 switch (exec_result.term) {
1868 .Exited => |code| {
1869 if (code != 0) {
1870 std.debug.print("\n{s}\n{s}: execution exited with code {d}:\n", .{
1871 exec_result.stderr, case.name, code,
1872 });
1873 dumpArgs(argv.items);
1874 return error.ChildProcessExecution;
1875 }
1876 },
1877 else => {
1878 std.debug.print("\n{s}\n{s}: execution crashed:\n", .{
1879 exec_result.stderr, case.name,
1880 });
1881 dumpArgs(argv.items);
1882 return error.ChildProcessExecution;
1883 },
1884 }
1885 try std.testing.expectEqualStrings(expected_stdout, exec_result.stdout);
1886 // We allow stderr to have garbage in it because wasmtime prints a
1887 // warning about --invoke even though we don't pass it.
1888 //std.testing.expectEqualStrings("", exec_result.stderr);
1889 },
1890 }
1891 }
1892}
1893
1894fn dumpArgs(argv: []const []const u8) void {
1895 for (argv) |arg| {
1896 std.debug.print("{s} ", .{arg});
1246 // Final check for .so.X, .so.X.Y, .so.X.Y.Z.
1247 // From `Compilation.hasSharedLibraryExt`.
1248 var it = std.mem.splitScalar(u8, filename, '.');
1249 _ = it.first();
1250 var so_txt = it.next() orelse return false;
1251 while (!std.mem.eql(u8, so_txt, "so")) {
1252 so_txt = it.next() orelse return false;
18971253 }
1898 std.debug.print("\n", .{});
1254 const n1 = it.next() orelse return false;
1255 const n2 = it.next();
1256 const n3 = it.next();
1257 _ = std.fmt.parseInt(u32, n1, 10) catch return false;
1258 if (n2) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
1259 if (n3) |x| _ = std.fmt.parseInt(u32, x, 10) catch return false;
1260 if (it.next() != null) return false;
1261 return false;
18991262}
test/tests.zig-4
......@@ -1250,7 +1250,6 @@ pub fn addCases(
12501250 b: *std.Build,
12511251 parent_step: *Step,
12521252 test_filters: []const []const u8,
1253 check_case_exe: *std.Build.Step.Compile,
12541253 target: std.Build.ResolvedTarget,
12551254 translate_c_options: @import("src/Cases.zig").TranslateCOptions,
12561255 build_options: @import("cases.zig").BuildOptions,
......@@ -1268,12 +1267,9 @@ pub fn addCases(
12681267
12691268 cases.lowerToTranslateCSteps(b, parent_step, test_filters, target, translate_c_options);
12701269
1271 const cases_dir_path = try b.build_root.join(b.allocator, &.{ "test", "cases" });
12721270 cases.lowerToBuildSteps(
12731271 b,
12741272 parent_step,
12751273 test_filters,
1276 cases_dir_path,
1277 check_case_exe,
12781274 );
12791275}