authorgravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-07-02 09:51:51+01:00
committergravatar for mlugg@mlugg.co.ukMatthew Lugg <mlugg@mlugg.co.uk> 2024-07-04 21:01:42+01:00
log2f0f1efa6fa50ca27a44d5f7a0c38a6cafbbfb7c
tree0d47a70b6df13e5024f02b3bed2bc2cc1ef95d9f
parentded5c759f83a4da355a128dd4d7f5e22cbd3cabe
signaturelock-open Commit is signed but in an unrecognized format.

compiler: type.zig -> Type.zig


44 files changed, 3659 insertions(+), 3659 deletions(-)

CMakeLists.txt+1-1
...@@ -522,6 +522,7 @@ set(ZIG_STAGE2_SOURCES...@@ -522,6 +522,7 @@ set(ZIG_STAGE2_SOURCES
522 src/Sema.zig522 src/Sema.zig
523 src/Sema/bitcast.zig523 src/Sema/bitcast.zig
524 src/Sema/comptime_ptr_access.zig524 src/Sema/comptime_ptr_access.zig
525 src/Type.zig
525 src/Value.zig526 src/Value.zig
526 src/Zcu.zig527 src/Zcu.zig
527 src/arch/aarch64/CodeGen.zig528 src/arch/aarch64/CodeGen.zig
...@@ -673,7 +674,6 @@ set(ZIG_STAGE2_SOURCES...@@ -673,7 +674,6 @@ set(ZIG_STAGE2_SOURCES
673 src/target.zig674 src/target.zig
674 src/tracy.zig675 src/tracy.zig
675 src/translate_c.zig676 src/translate_c.zig
676 src/type.zig
677 src/wasi_libc.zig677 src/wasi_libc.zig
678)678)
679679
src/Air.zig+1-1
...@@ -9,7 +9,7 @@ const assert = std.debug.assert;...@@ -9,7 +9,7 @@ const assert = std.debug.assert;
99
10const Air = @This();10const Air = @This();
11const Value = @import("Value.zig");11const Value = @import("Value.zig");
12const Type = @import("type.zig").Type;12const Type = @import("Type.zig");
13const InternPool = @import("InternPool.zig");13const InternPool = @import("InternPool.zig");
14const Zcu = @import("Zcu.zig");14const Zcu = @import("Zcu.zig");
15/// Deprecated.15/// Deprecated.
src/Compilation.zig+1-1
...@@ -12,7 +12,7 @@ const WaitGroup = std.Thread.WaitGroup;...@@ -12,7 +12,7 @@ const WaitGroup = std.Thread.WaitGroup;
12const ErrorBundle = std.zig.ErrorBundle;12const ErrorBundle = std.zig.ErrorBundle;
1313
14const Value = @import("Value.zig");14const Value = @import("Value.zig");
15const Type = @import("type.zig").Type;15const Type = @import("Type.zig");
16const target_util = @import("target.zig");16const target_util = @import("target.zig");
17const Package = @import("Package.zig");17const Package = @import("Package.zig");
18const link = @import("link.zig");18const link = @import("link.zig");
src/RangeSet.zig+1-1
...@@ -3,7 +3,7 @@ const assert = std.debug.assert;...@@ -3,7 +3,7 @@ const assert = std.debug.assert;
3const Order = std.math.Order;3const Order = std.math.Order;
44
5const InternPool = @import("InternPool.zig");5const InternPool = @import("InternPool.zig");
6const Type = @import("type.zig").Type;6const Type = @import("Type.zig");
7const Value = @import("Value.zig");7const Value = @import("Value.zig");
8const Zcu = @import("Zcu.zig");8const Zcu = @import("Zcu.zig");
9/// Deprecated.9/// Deprecated.
src/Sema.zig+1-1
...@@ -176,7 +176,7 @@ const log = std.log.scoped(.sema);...@@ -176,7 +176,7 @@ const log = std.log.scoped(.sema);
176const Sema = @This();176const Sema = @This();
177const Value = @import("Value.zig");177const Value = @import("Value.zig");
178const MutableValue = @import("mutable_value.zig").MutableValue;178const MutableValue = @import("mutable_value.zig").MutableValue;
179const Type = @import("type.zig").Type;179const Type = @import("Type.zig");
180const Air = @import("Air.zig");180const Air = @import("Air.zig");
181const Zir = std.zig.Zir;181const Zir = std.zig.Zir;
182const Zcu = @import("Zcu.zig");182const Zcu = @import("Zcu.zig");
src/Sema/bitcast.zig+1-1
...@@ -767,6 +767,6 @@ const assert = std.debug.assert;...@@ -767,6 +767,6 @@ const assert = std.debug.assert;
767const Sema = @import("../Sema.zig");767const Sema = @import("../Sema.zig");
768const Zcu = @import("../Zcu.zig");768const Zcu = @import("../Zcu.zig");
769const InternPool = @import("../InternPool.zig");769const InternPool = @import("../InternPool.zig");
770const Type = @import("../type.zig").Type;770const Type = @import("../Type.zig");
771const Value = @import("../Value.zig");771const Value = @import("../Value.zig");
772const CompileError = Zcu.CompileError;772const CompileError = Zcu.CompileError;
src/Sema/comptime_ptr_access.zig+1-1
...@@ -1054,7 +1054,7 @@ const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;...@@ -1054,7 +1054,7 @@ const ComptimeAllocIndex = InternPool.ComptimeAllocIndex;
1054const Sema = @import("../Sema.zig");1054const Sema = @import("../Sema.zig");
1055const Block = Sema.Block;1055const Block = Sema.Block;
1056const MutableValue = @import("../mutable_value.zig").MutableValue;1056const MutableValue = @import("../mutable_value.zig").MutableValue;
1057const Type = @import("../type.zig").Type;1057const Type = @import("../Type.zig");
1058const Value = @import("../Value.zig");1058const Value = @import("../Value.zig");
1059const Zcu = @import("../Zcu.zig");1059const Zcu = @import("../Zcu.zig");
1060const LazySrcLoc = Zcu.LazySrcLoc;1060const LazySrcLoc = Zcu.LazySrcLoc;
src/Type.zig created+3617
...@@ -0,0 +1,3617 @@
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 Value = @import("Value.zig");
9const assert = std.debug.assert;
10const Target = std.Target;
11const Zcu = @import("Zcu.zig");
12/// Deprecated.
13const Module = Zcu;
14const log = std.log.scoped(.Type);
15const target_util = @import("target.zig");
16const Sema = @import("Sema.zig");
17const InternPool = @import("InternPool.zig");
18const Alignment = InternPool.Alignment;
19const Zir = std.zig.Zir;
20const Type = @This();
21
22ip_index: InternPool.Index,
23
24pub fn zigTypeTag(ty: Type, mod: *const Module) std.builtin.TypeId {
25 return ty.zigTypeTagOrPoison(mod) catch unreachable;
26}
27
28pub fn zigTypeTagOrPoison(ty: Type, mod: *const Module) error{GenericPoison}!std.builtin.TypeId {
29 return mod.intern_pool.zigTypeTagOrPoison(ty.toIntern());
30}
31
32pub fn baseZigTypeTag(self: Type, mod: *Module) std.builtin.TypeId {
33 return switch (self.zigTypeTag(mod)) {
34 .ErrorUnion => self.errorUnionPayload(mod).baseZigTypeTag(mod),
35 .Optional => {
36 return self.optionalChild(mod).baseZigTypeTag(mod);
37 },
38 else => |t| t,
39 };
40}
41
42pub fn isSelfComparable(ty: Type, mod: *const Module, is_equality_cmp: bool) bool {
43 return switch (ty.zigTypeTag(mod)) {
44 .Int,
45 .Float,
46 .ComptimeFloat,
47 .ComptimeInt,
48 => true,
49
50 .Vector => ty.elemType2(mod).isSelfComparable(mod, is_equality_cmp),
51
52 .Bool,
53 .Type,
54 .Void,
55 .ErrorSet,
56 .Fn,
57 .Opaque,
58 .AnyFrame,
59 .Enum,
60 .EnumLiteral,
61 => is_equality_cmp,
62
63 .NoReturn,
64 .Array,
65 .Struct,
66 .Undefined,
67 .Null,
68 .ErrorUnion,
69 .Union,
70 .Frame,
71 => false,
72
73 .Pointer => !ty.isSlice(mod) and (is_equality_cmp or ty.isCPtr(mod)),
74 .Optional => {
75 if (!is_equality_cmp) return false;
76 return ty.optionalChild(mod).isSelfComparable(mod, is_equality_cmp);
77 },
78 };
79}
80
81/// If it is a function pointer, returns the function type. Otherwise returns null.
82pub fn castPtrToFn(ty: Type, mod: *const Module) ?Type {
83 if (ty.zigTypeTag(mod) != .Pointer) return null;
84 const elem_ty = ty.childType(mod);
85 if (elem_ty.zigTypeTag(mod) != .Fn) return null;
86 return elem_ty;
87}
88
89/// Asserts the type is a pointer.
90pub fn ptrIsMutable(ty: Type, mod: *const Module) bool {
91 return !mod.intern_pool.indexToKey(ty.toIntern()).ptr_type.flags.is_const;
92}
93
94pub const ArrayInfo = struct {
95 elem_type: Type,
96 sentinel: ?Value = null,
97 len: u64,
98};
99
100pub fn arrayInfo(self: Type, mod: *const Module) ArrayInfo {
101 return .{
102 .len = self.arrayLen(mod),
103 .sentinel = self.sentinel(mod),
104 .elem_type = self.childType(mod),
105 };
106}
107
108pub fn ptrInfo(ty: Type, mod: *const Module) InternPool.Key.PtrType {
109 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
110 .ptr_type => |p| p,
111 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
112 .ptr_type => |p| p,
113 else => unreachable,
114 },
115 else => unreachable,
116 };
117}
118
119pub fn eql(a: Type, b: Type, mod: *const Module) bool {
120 _ = mod; // TODO: remove this parameter
121 // The InternPool data structure hashes based on Key to make interned objects
122 // unique. An Index can be treated simply as u32 value for the
123 // purpose of Type/Value hashing and equality.
124 return a.toIntern() == b.toIntern();
125}
126
127pub fn format(ty: Type, comptime unused_fmt_string: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
128 _ = ty;
129 _ = unused_fmt_string;
130 _ = options;
131 _ = writer;
132 @compileError("do not format types directly; use either ty.fmtDebug() or ty.fmt()");
133}
134
135pub const Formatter = std.fmt.Formatter(format2);
136
137pub fn fmt(ty: Type, module: *Module) Formatter {
138 return .{ .data = .{
139 .ty = ty,
140 .module = module,
141 } };
142}
143
144const FormatContext = struct {
145 ty: Type,
146 module: *Module,
147};
148
149fn format2(
150 ctx: FormatContext,
151 comptime unused_format_string: []const u8,
152 options: std.fmt.FormatOptions,
153 writer: anytype,
154) !void {
155 comptime assert(unused_format_string.len == 0);
156 _ = options;
157 return print(ctx.ty, writer, ctx.module);
158}
159
160pub fn fmtDebug(ty: Type) std.fmt.Formatter(dump) {
161 return .{ .data = ty };
162}
163
164/// This is a debug function. In order to print types in a meaningful way
165/// we also need access to the module.
166pub fn dump(
167 start_type: Type,
168 comptime unused_format_string: []const u8,
169 options: std.fmt.FormatOptions,
170 writer: anytype,
171) @TypeOf(writer).Error!void {
172 _ = options;
173 comptime assert(unused_format_string.len == 0);
174 return writer.print("{any}", .{start_type.ip_index});
175}
176
177/// Prints a name suitable for `@typeName`.
178/// TODO: take an `opt_sema` to pass to `fmtValue` when printing sentinels.
179pub fn print(ty: Type, writer: anytype, mod: *Module) @TypeOf(writer).Error!void {
180 const ip = &mod.intern_pool;
181 switch (ip.indexToKey(ty.toIntern())) {
182 .int_type => |int_type| {
183 const sign_char: u8 = switch (int_type.signedness) {
184 .signed => 'i',
185 .unsigned => 'u',
186 };
187 return writer.print("{c}{d}", .{ sign_char, int_type.bits });
188 },
189 .ptr_type => {
190 const info = ty.ptrInfo(mod);
191
192 if (info.sentinel != .none) switch (info.flags.size) {
193 .One, .C => unreachable,
194 .Many => try writer.print("[*:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
195 .Slice => try writer.print("[:{}]", .{Value.fromInterned(info.sentinel).fmtValue(mod, null)}),
196 } else switch (info.flags.size) {
197 .One => try writer.writeAll("*"),
198 .Many => try writer.writeAll("[*]"),
199 .C => try writer.writeAll("[*c]"),
200 .Slice => try writer.writeAll("[]"),
201 }
202 if (info.flags.alignment != .none or
203 info.packed_offset.host_size != 0 or
204 info.flags.vector_index != .none)
205 {
206 const alignment = if (info.flags.alignment != .none)
207 info.flags.alignment
208 else
209 Type.fromInterned(info.child).abiAlignment(mod);
210 try writer.print("align({d}", .{alignment.toByteUnits() orelse 0});
211
212 if (info.packed_offset.bit_offset != 0 or info.packed_offset.host_size != 0) {
213 try writer.print(":{d}:{d}", .{
214 info.packed_offset.bit_offset, info.packed_offset.host_size,
215 });
216 }
217 if (info.flags.vector_index == .runtime) {
218 try writer.writeAll(":?");
219 } else if (info.flags.vector_index != .none) {
220 try writer.print(":{d}", .{@intFromEnum(info.flags.vector_index)});
221 }
222 try writer.writeAll(") ");
223 }
224 if (info.flags.address_space != .generic) {
225 try writer.print("addrspace(.{s}) ", .{@tagName(info.flags.address_space)});
226 }
227 if (info.flags.is_const) try writer.writeAll("const ");
228 if (info.flags.is_volatile) try writer.writeAll("volatile ");
229 if (info.flags.is_allowzero and info.flags.size != .C) try writer.writeAll("allowzero ");
230
231 try print(Type.fromInterned(info.child), writer, mod);
232 return;
233 },
234 .array_type => |array_type| {
235 if (array_type.sentinel == .none) {
236 try writer.print("[{d}]", .{array_type.len});
237 try print(Type.fromInterned(array_type.child), writer, mod);
238 } else {
239 try writer.print("[{d}:{}]", .{
240 array_type.len,
241 Value.fromInterned(array_type.sentinel).fmtValue(mod, null),
242 });
243 try print(Type.fromInterned(array_type.child), writer, mod);
244 }
245 return;
246 },
247 .vector_type => |vector_type| {
248 try writer.print("@Vector({d}, ", .{vector_type.len});
249 try print(Type.fromInterned(vector_type.child), writer, mod);
250 try writer.writeAll(")");
251 return;
252 },
253 .opt_type => |child| {
254 try writer.writeByte('?');
255 return print(Type.fromInterned(child), writer, mod);
256 },
257 .error_union_type => |error_union_type| {
258 try print(Type.fromInterned(error_union_type.error_set_type), writer, mod);
259 try writer.writeByte('!');
260 if (error_union_type.payload_type == .generic_poison_type) {
261 try writer.writeAll("anytype");
262 } else {
263 try print(Type.fromInterned(error_union_type.payload_type), writer, mod);
264 }
265 return;
266 },
267 .inferred_error_set_type => |func_index| {
268 try writer.writeAll("@typeInfo(@typeInfo(@TypeOf(");
269 const owner_decl = mod.funcOwnerDeclPtr(func_index);
270 try owner_decl.renderFullyQualifiedName(mod, writer);
271 try writer.writeAll(")).Fn.return_type.?).ErrorUnion.error_set");
272 },
273 .error_set_type => |error_set_type| {
274 const names = error_set_type.names;
275 try writer.writeAll("error{");
276 for (names.get(ip), 0..) |name, i| {
277 if (i != 0) try writer.writeByte(',');
278 try writer.print("{}", .{name.fmt(ip)});
279 }
280 try writer.writeAll("}");
281 },
282 .simple_type => |s| switch (s) {
283 .f16,
284 .f32,
285 .f64,
286 .f80,
287 .f128,
288 .usize,
289 .isize,
290 .c_char,
291 .c_short,
292 .c_ushort,
293 .c_int,
294 .c_uint,
295 .c_long,
296 .c_ulong,
297 .c_longlong,
298 .c_ulonglong,
299 .c_longdouble,
300 .anyopaque,
301 .bool,
302 .void,
303 .type,
304 .anyerror,
305 .comptime_int,
306 .comptime_float,
307 .noreturn,
308 .adhoc_inferred_error_set,
309 => return writer.writeAll(@tagName(s)),
310
311 .null,
312 .undefined,
313 => try writer.print("@TypeOf({s})", .{@tagName(s)}),
314
315 .enum_literal => try writer.print("@TypeOf(.{s})", .{@tagName(s)}),
316 .atomic_order => try writer.writeAll("std.builtin.AtomicOrder"),
317 .atomic_rmw_op => try writer.writeAll("std.builtin.AtomicRmwOp"),
318 .calling_convention => try writer.writeAll("std.builtin.CallingConvention"),
319 .address_space => try writer.writeAll("std.builtin.AddressSpace"),
320 .float_mode => try writer.writeAll("std.builtin.FloatMode"),
321 .reduce_op => try writer.writeAll("std.builtin.ReduceOp"),
322 .call_modifier => try writer.writeAll("std.builtin.CallModifier"),
323 .prefetch_options => try writer.writeAll("std.builtin.PrefetchOptions"),
324 .export_options => try writer.writeAll("std.builtin.ExportOptions"),
325 .extern_options => try writer.writeAll("std.builtin.ExternOptions"),
326 .type_info => try writer.writeAll("std.builtin.Type"),
327
328 .generic_poison => unreachable,
329 },
330 .struct_type => {
331 const struct_type = ip.loadStructType(ty.toIntern());
332 if (struct_type.decl.unwrap()) |decl_index| {
333 const decl = mod.declPtr(decl_index);
334 try decl.renderFullyQualifiedName(mod, writer);
335 } else if (ip.loadStructType(ty.toIntern()).namespace.unwrap()) |namespace_index| {
336 const namespace = mod.namespacePtr(namespace_index);
337 try namespace.renderFullyQualifiedName(mod, .empty, writer);
338 } else {
339 try writer.writeAll("@TypeOf(.{})");
340 }
341 },
342 .anon_struct_type => |anon_struct| {
343 if (anon_struct.types.len == 0) {
344 return writer.writeAll("@TypeOf(.{})");
345 }
346 try writer.writeAll("struct{");
347 for (anon_struct.types.get(ip), anon_struct.values.get(ip), 0..) |field_ty, val, i| {
348 if (i != 0) try writer.writeAll(", ");
349 if (val != .none) {
350 try writer.writeAll("comptime ");
351 }
352 if (anon_struct.names.len != 0) {
353 try writer.print("{}: ", .{anon_struct.names.get(ip)[i].fmt(&mod.intern_pool)});
354 }
355
356 try print(Type.fromInterned(field_ty), writer, mod);
357
358 if (val != .none) {
359 try writer.print(" = {}", .{Value.fromInterned(val).fmtValue(mod, null)});
360 }
361 }
362 try writer.writeAll("}");
363 },
364
365 .union_type => {
366 const decl = mod.declPtr(ip.loadUnionType(ty.toIntern()).decl);
367 try decl.renderFullyQualifiedName(mod, writer);
368 },
369 .opaque_type => {
370 const decl = mod.declPtr(ip.loadOpaqueType(ty.toIntern()).decl);
371 try decl.renderFullyQualifiedName(mod, writer);
372 },
373 .enum_type => {
374 const decl = mod.declPtr(ip.loadEnumType(ty.toIntern()).decl);
375 try decl.renderFullyQualifiedName(mod, writer);
376 },
377 .func_type => |fn_info| {
378 if (fn_info.is_noinline) {
379 try writer.writeAll("noinline ");
380 }
381 try writer.writeAll("fn (");
382 const param_types = fn_info.param_types.get(&mod.intern_pool);
383 for (param_types, 0..) |param_ty, i| {
384 if (i != 0) try writer.writeAll(", ");
385 if (std.math.cast(u5, i)) |index| {
386 if (fn_info.paramIsComptime(index)) {
387 try writer.writeAll("comptime ");
388 }
389 if (fn_info.paramIsNoalias(index)) {
390 try writer.writeAll("noalias ");
391 }
392 }
393 if (param_ty == .generic_poison_type) {
394 try writer.writeAll("anytype");
395 } else {
396 try print(Type.fromInterned(param_ty), writer, mod);
397 }
398 }
399 if (fn_info.is_var_args) {
400 if (param_types.len != 0) {
401 try writer.writeAll(", ");
402 }
403 try writer.writeAll("...");
404 }
405 try writer.writeAll(") ");
406 if (fn_info.cc != .Unspecified) {
407 try writer.writeAll("callconv(.");
408 try writer.writeAll(@tagName(fn_info.cc));
409 try writer.writeAll(") ");
410 }
411 if (fn_info.return_type == .generic_poison_type) {
412 try writer.writeAll("anytype");
413 } else {
414 try print(Type.fromInterned(fn_info.return_type), writer, mod);
415 }
416 },
417 .anyframe_type => |child| {
418 if (child == .none) return writer.writeAll("anyframe");
419 try writer.writeAll("anyframe->");
420 return print(Type.fromInterned(child), writer, mod);
421 },
422
423 // values, not types
424 .undef,
425 .simple_value,
426 .variable,
427 .extern_func,
428 .func,
429 .int,
430 .err,
431 .error_union,
432 .enum_literal,
433 .enum_tag,
434 .empty_enum_value,
435 .float,
436 .ptr,
437 .slice,
438 .opt,
439 .aggregate,
440 .un,
441 // memoization, not types
442 .memoized_call,
443 => unreachable,
444 }
445}
446
447pub fn fromInterned(i: InternPool.Index) Type {
448 assert(i != .none);
449 return .{ .ip_index = i };
450}
451
452pub fn toIntern(ty: Type) InternPool.Index {
453 assert(ty.ip_index != .none);
454 return ty.ip_index;
455}
456
457pub fn toValue(self: Type) Value {
458 return Value.fromInterned(self.toIntern());
459}
460
461const RuntimeBitsError = Module.CompileError || error{NeedLazy};
462
463/// true if and only if the type takes up space in memory at runtime.
464/// There are two reasons a type will return false:
465/// * the type is a comptime-only type. For example, the type `type` itself.
466/// - note, however, that a struct can have mixed fields and only the non-comptime-only
467/// fields will count towards the ABI size. For example, `struct {T: type, x: i32}`
468/// hasRuntimeBits()=true and abiSize()=4
469/// * the type has only one possible value, making its ABI size 0.
470/// - an enum with an explicit tag type has the ABI size of the integer tag type,
471/// making it one-possible-value only if the integer tag type has 0 bits.
472/// When `ignore_comptime_only` is true, then types that are comptime-only
473/// may return false positives.
474pub fn hasRuntimeBitsAdvanced(
475 ty: Type,
476 mod: *Module,
477 ignore_comptime_only: bool,
478 strat: AbiAlignmentAdvancedStrat,
479) RuntimeBitsError!bool {
480 const ip = &mod.intern_pool;
481 return switch (ty.toIntern()) {
482 // False because it is a comptime-only type.
483 .empty_struct_type => false,
484 else => switch (ip.indexToKey(ty.toIntern())) {
485 .int_type => |int_type| int_type.bits != 0,
486 .ptr_type => {
487 // Pointers to zero-bit types still have a runtime address; however, pointers
488 // to comptime-only types do not, with the exception of function pointers.
489 if (ignore_comptime_only) return true;
490 return switch (strat) {
491 .sema => |sema| !(try sema.typeRequiresComptime(ty)),
492 .eager => !comptimeOnly(ty, mod),
493 .lazy => error.NeedLazy,
494 };
495 },
496 .anyframe_type => true,
497 .array_type => |array_type| return array_type.lenIncludingSentinel() > 0 and
498 try Type.fromInterned(array_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
499 .vector_type => |vector_type| return vector_type.len > 0 and
500 try Type.fromInterned(vector_type.child).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
501 .opt_type => |child| {
502 const child_ty = Type.fromInterned(child);
503 if (child_ty.isNoReturn(mod)) {
504 // Then the optional is comptime-known to be null.
505 return false;
506 }
507 if (ignore_comptime_only) return true;
508 return switch (strat) {
509 .sema => |sema| !(try sema.typeRequiresComptime(child_ty)),
510 .eager => !comptimeOnly(child_ty, mod),
511 .lazy => error.NeedLazy,
512 };
513 },
514 .error_union_type,
515 .error_set_type,
516 .inferred_error_set_type,
517 => true,
518
519 // These are function *bodies*, not pointers.
520 // They return false here because they are comptime-only types.
521 // Special exceptions have to be made when emitting functions due to
522 // this returning false.
523 .func_type => false,
524
525 .simple_type => |t| switch (t) {
526 .f16,
527 .f32,
528 .f64,
529 .f80,
530 .f128,
531 .usize,
532 .isize,
533 .c_char,
534 .c_short,
535 .c_ushort,
536 .c_int,
537 .c_uint,
538 .c_long,
539 .c_ulong,
540 .c_longlong,
541 .c_ulonglong,
542 .c_longdouble,
543 .bool,
544 .anyerror,
545 .adhoc_inferred_error_set,
546 .anyopaque,
547 .atomic_order,
548 .atomic_rmw_op,
549 .calling_convention,
550 .address_space,
551 .float_mode,
552 .reduce_op,
553 .call_modifier,
554 .prefetch_options,
555 .export_options,
556 .extern_options,
557 => true,
558
559 // These are false because they are comptime-only types.
560 .void,
561 .type,
562 .comptime_int,
563 .comptime_float,
564 .noreturn,
565 .null,
566 .undefined,
567 .enum_literal,
568 .type_info,
569 => false,
570
571 .generic_poison => unreachable,
572 },
573 .struct_type => {
574 const struct_type = ip.loadStructType(ty.toIntern());
575 if (struct_type.assumeRuntimeBitsIfFieldTypesWip(ip)) {
576 // In this case, we guess that hasRuntimeBits() for this type is true,
577 // and then later if our guess was incorrect, we emit a compile error.
578 return true;
579 }
580 switch (strat) {
581 .sema => |sema| _ = try sema.resolveTypeFields(ty),
582 .eager => assert(struct_type.haveFieldTypes(ip)),
583 .lazy => if (!struct_type.haveFieldTypes(ip)) return error.NeedLazy,
584 }
585 for (0..struct_type.field_types.len) |i| {
586 if (struct_type.comptime_bits.getBit(ip, i)) continue;
587 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
588 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
589 return true;
590 } else {
591 return false;
592 }
593 },
594 .anon_struct_type => |tuple| {
595 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
596 if (val != .none) continue; // comptime field
597 if (try Type.fromInterned(field_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat)) return true;
598 }
599 return false;
600 },
601
602 .union_type => {
603 const union_type = ip.loadUnionType(ty.toIntern());
604 switch (union_type.flagsPtr(ip).runtime_tag) {
605 .none => {
606 if (union_type.flagsPtr(ip).status == .field_types_wip) {
607 // In this case, we guess that hasRuntimeBits() for this type is true,
608 // and then later if our guess was incorrect, we emit a compile error.
609 union_type.flagsPtr(ip).assumed_runtime_bits = true;
610 return true;
611 }
612 },
613 .safety, .tagged => {
614 const tag_ty = union_type.tagTypePtr(ip).*;
615 // tag_ty will be `none` if this union's tag type is not resolved yet,
616 // in which case we want control flow to continue down below.
617 if (tag_ty != .none and
618 try Type.fromInterned(tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
619 {
620 return true;
621 }
622 },
623 }
624 switch (strat) {
625 .sema => |sema| _ = try sema.resolveTypeFields(ty),
626 .eager => assert(union_type.flagsPtr(ip).status.haveFieldTypes()),
627 .lazy => if (!union_type.flagsPtr(ip).status.haveFieldTypes())
628 return error.NeedLazy,
629 }
630 for (0..union_type.field_types.len) |field_index| {
631 const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
632 if (try field_ty.hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat))
633 return true;
634 } else {
635 return false;
636 }
637 },
638
639 .opaque_type => true,
640 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).hasRuntimeBitsAdvanced(mod, ignore_comptime_only, strat),
641
642 // values, not types
643 .undef,
644 .simple_value,
645 .variable,
646 .extern_func,
647 .func,
648 .int,
649 .err,
650 .error_union,
651 .enum_literal,
652 .enum_tag,
653 .empty_enum_value,
654 .float,
655 .ptr,
656 .slice,
657 .opt,
658 .aggregate,
659 .un,
660 // memoization, not types
661 .memoized_call,
662 => unreachable,
663 },
664 };
665}
666
667/// true if and only if the type has a well-defined memory layout
668/// readFrom/writeToMemory are supported only for types with a well-
669/// defined memory layout
670pub fn hasWellDefinedLayout(ty: Type, mod: *Module) bool {
671 const ip = &mod.intern_pool;
672 return switch (ip.indexToKey(ty.toIntern())) {
673 .int_type,
674 .vector_type,
675 => true,
676
677 .error_union_type,
678 .error_set_type,
679 .inferred_error_set_type,
680 .anon_struct_type,
681 .opaque_type,
682 .anyframe_type,
683 // These are function bodies, not function pointers.
684 .func_type,
685 => false,
686
687 .array_type => |array_type| Type.fromInterned(array_type.child).hasWellDefinedLayout(mod),
688 .opt_type => ty.isPtrLikeOptional(mod),
689 .ptr_type => |ptr_type| ptr_type.flags.size != .Slice,
690
691 .simple_type => |t| switch (t) {
692 .f16,
693 .f32,
694 .f64,
695 .f80,
696 .f128,
697 .usize,
698 .isize,
699 .c_char,
700 .c_short,
701 .c_ushort,
702 .c_int,
703 .c_uint,
704 .c_long,
705 .c_ulong,
706 .c_longlong,
707 .c_ulonglong,
708 .c_longdouble,
709 .bool,
710 .void,
711 => true,
712
713 .anyerror,
714 .adhoc_inferred_error_set,
715 .anyopaque,
716 .atomic_order,
717 .atomic_rmw_op,
718 .calling_convention,
719 .address_space,
720 .float_mode,
721 .reduce_op,
722 .call_modifier,
723 .prefetch_options,
724 .export_options,
725 .extern_options,
726 .type,
727 .comptime_int,
728 .comptime_float,
729 .noreturn,
730 .null,
731 .undefined,
732 .enum_literal,
733 .type_info,
734 .generic_poison,
735 => false,
736 },
737 .struct_type => {
738 const struct_type = ip.loadStructType(ty.toIntern());
739 // Struct with no fields have a well-defined layout of no bits.
740 return struct_type.layout != .auto or struct_type.field_types.len == 0;
741 },
742 .union_type => {
743 const union_type = ip.loadUnionType(ty.toIntern());
744 return switch (union_type.flagsPtr(ip).runtime_tag) {
745 .none, .safety => union_type.flagsPtr(ip).layout != .auto,
746 .tagged => false,
747 };
748 },
749 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
750 .auto => false,
751 .explicit, .nonexhaustive => true,
752 },
753
754 // values, not types
755 .undef,
756 .simple_value,
757 .variable,
758 .extern_func,
759 .func,
760 .int,
761 .err,
762 .error_union,
763 .enum_literal,
764 .enum_tag,
765 .empty_enum_value,
766 .float,
767 .ptr,
768 .slice,
769 .opt,
770 .aggregate,
771 .un,
772 // memoization, not types
773 .memoized_call,
774 => unreachable,
775 };
776}
777
778pub fn hasRuntimeBits(ty: Type, mod: *Module) bool {
779 return hasRuntimeBitsAdvanced(ty, mod, false, .eager) catch unreachable;
780}
781
782pub fn hasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool {
783 return hasRuntimeBitsAdvanced(ty, mod, true, .eager) catch unreachable;
784}
785
786pub fn fnHasRuntimeBits(ty: Type, mod: *Module) bool {
787 return ty.fnHasRuntimeBitsAdvanced(mod, null) catch unreachable;
788}
789
790/// Determines whether a function type has runtime bits, i.e. whether a
791/// function with this type can exist at runtime.
792/// Asserts that `ty` is a function type.
793/// If `opt_sema` is not provided, asserts that the return type is sufficiently resolved.
794pub fn fnHasRuntimeBitsAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool {
795 const fn_info = mod.typeToFunc(ty).?;
796 if (fn_info.is_generic) return false;
797 if (fn_info.is_var_args) return true;
798 if (fn_info.cc == .Inline) return false;
799 return !try Type.fromInterned(fn_info.return_type).comptimeOnlyAdvanced(mod, opt_sema);
800}
801
802pub fn isFnOrHasRuntimeBits(ty: Type, mod: *Module) bool {
803 switch (ty.zigTypeTag(mod)) {
804 .Fn => return ty.fnHasRuntimeBits(mod),
805 else => return ty.hasRuntimeBits(mod),
806 }
807}
808
809/// Same as `isFnOrHasRuntimeBits` but comptime-only types may return a false positive.
810pub fn isFnOrHasRuntimeBitsIgnoreComptime(ty: Type, mod: *Module) bool {
811 return switch (ty.zigTypeTag(mod)) {
812 .Fn => true,
813 else => return ty.hasRuntimeBitsIgnoreComptime(mod),
814 };
815}
816
817pub fn isNoReturn(ty: Type, mod: *Module) bool {
818 return mod.intern_pool.isNoReturn(ty.toIntern());
819}
820
821/// Returns `none` if the pointer is naturally aligned and the element type is 0-bit.
822pub fn ptrAlignment(ty: Type, mod: *Module) Alignment {
823 return ptrAlignmentAdvanced(ty, mod, null) catch unreachable;
824}
825
826pub fn ptrAlignmentAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) !Alignment {
827 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
828 .ptr_type => |ptr_type| {
829 if (ptr_type.flags.alignment != .none)
830 return ptr_type.flags.alignment;
831
832 if (opt_sema) |sema| {
833 const res = try Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .{ .sema = sema });
834 return res.scalar;
835 }
836
837 return (Type.fromInterned(ptr_type.child).abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
838 },
839 .opt_type => |child| Type.fromInterned(child).ptrAlignmentAdvanced(mod, opt_sema),
840 else => unreachable,
841 };
842}
843
844pub fn ptrAddressSpace(ty: Type, mod: *const Module) std.builtin.AddressSpace {
845 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
846 .ptr_type => |ptr_type| ptr_type.flags.address_space,
847 .opt_type => |child| mod.intern_pool.indexToKey(child).ptr_type.flags.address_space,
848 else => unreachable,
849 };
850}
851
852/// Never returns `none`. Asserts that all necessary type resolution is already done.
853pub fn abiAlignment(ty: Type, mod: *Module) Alignment {
854 return (ty.abiAlignmentAdvanced(mod, .eager) catch unreachable).scalar;
855}
856
857/// May capture a reference to `ty`.
858/// Returned value has type `comptime_int`.
859pub fn lazyAbiAlignment(ty: Type, mod: *Module) !Value {
860 switch (try ty.abiAlignmentAdvanced(mod, .lazy)) {
861 .val => |val| return val,
862 .scalar => |x| return mod.intValue(Type.comptime_int, x.toByteUnits() orelse 0),
863 }
864}
865
866pub const AbiAlignmentAdvanced = union(enum) {
867 scalar: Alignment,
868 val: Value,
869};
870
871pub const AbiAlignmentAdvancedStrat = union(enum) {
872 eager,
873 lazy,
874 sema: *Sema,
875};
876
877/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
878/// In this case there will be no error, guaranteed.
879/// If you pass `lazy` you may get back `scalar` or `val`.
880/// If `val` is returned, a reference to `ty` has been captured.
881/// If you pass `sema` you will get back `scalar` and resolve the type if
882/// necessary, possibly returning a CompileError.
883pub fn abiAlignmentAdvanced(
884 ty: Type,
885 mod: *Module,
886 strat: AbiAlignmentAdvancedStrat,
887) Module.CompileError!AbiAlignmentAdvanced {
888 const target = mod.getTarget();
889 const use_llvm = mod.comp.config.use_llvm;
890 const ip = &mod.intern_pool;
891
892 const opt_sema = switch (strat) {
893 .sema => |sema| sema,
894 else => null,
895 };
896
897 switch (ty.toIntern()) {
898 .empty_struct_type => return AbiAlignmentAdvanced{ .scalar = .@"1" },
899 else => switch (ip.indexToKey(ty.toIntern())) {
900 .int_type => |int_type| {
901 if (int_type.bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
902 return .{ .scalar = intAbiAlignment(int_type.bits, target, use_llvm) };
903 },
904 .ptr_type, .anyframe_type => {
905 return .{ .scalar = ptrAbiAlignment(target) };
906 },
907 .array_type => |array_type| {
908 return Type.fromInterned(array_type.child).abiAlignmentAdvanced(mod, strat);
909 },
910 .vector_type => |vector_type| {
911 if (vector_type.len == 0) return .{ .scalar = .@"1" };
912 switch (mod.comp.getZigBackend()) {
913 else => {
914 const elem_bits: u32 = @intCast(try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, opt_sema));
915 if (elem_bits == 0) return .{ .scalar = .@"1" };
916 const bytes = ((elem_bits * vector_type.len) + 7) / 8;
917 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
918 return .{ .scalar = Alignment.fromByteUnits(alignment) };
919 },
920 .stage2_c => {
921 return Type.fromInterned(vector_type.child).abiAlignmentAdvanced(mod, strat);
922 },
923 .stage2_x86_64 => {
924 if (vector_type.child == .bool_type) {
925 if (vector_type.len > 256 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
926 if (vector_type.len > 128 and std.Target.x86.featureSetHas(target.cpu.features, .avx2)) return .{ .scalar = .@"32" };
927 if (vector_type.len > 64) return .{ .scalar = .@"16" };
928 const bytes = std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
929 const alignment = std.math.ceilPowerOfTwoAssert(u32, bytes);
930 return .{ .scalar = Alignment.fromByteUnits(alignment) };
931 }
932 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
933 if (elem_bytes == 0) return .{ .scalar = .@"1" };
934 const bytes = elem_bytes * vector_type.len;
935 if (bytes > 32 and std.Target.x86.featureSetHas(target.cpu.features, .avx512f)) return .{ .scalar = .@"64" };
936 if (bytes > 16 and std.Target.x86.featureSetHas(target.cpu.features, .avx)) return .{ .scalar = .@"32" };
937 return .{ .scalar = .@"16" };
938 },
939 }
940 },
941
942 .opt_type => return abiAlignmentAdvancedOptional(ty, mod, strat),
943 .error_union_type => |info| return abiAlignmentAdvancedErrorUnion(ty, mod, strat, Type.fromInterned(info.payload_type)),
944
945 .error_set_type, .inferred_error_set_type => {
946 const bits = mod.errorSetBits();
947 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
948 return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
949 },
950
951 // represents machine code; not a pointer
952 .func_type => return .{ .scalar = target_util.defaultFunctionAlignment(target) },
953
954 .simple_type => |t| switch (t) {
955 .bool,
956 .atomic_order,
957 .atomic_rmw_op,
958 .calling_convention,
959 .address_space,
960 .float_mode,
961 .reduce_op,
962 .call_modifier,
963 .prefetch_options,
964 .anyopaque,
965 => return .{ .scalar = .@"1" },
966
967 .usize,
968 .isize,
969 => return .{ .scalar = intAbiAlignment(target.ptrBitWidth(), target, use_llvm) },
970
971 .export_options,
972 .extern_options,
973 .type_info,
974 => return .{ .scalar = ptrAbiAlignment(target) },
975
976 .c_char => return .{ .scalar = cTypeAlign(target, .char) },
977 .c_short => return .{ .scalar = cTypeAlign(target, .short) },
978 .c_ushort => return .{ .scalar = cTypeAlign(target, .ushort) },
979 .c_int => return .{ .scalar = cTypeAlign(target, .int) },
980 .c_uint => return .{ .scalar = cTypeAlign(target, .uint) },
981 .c_long => return .{ .scalar = cTypeAlign(target, .long) },
982 .c_ulong => return .{ .scalar = cTypeAlign(target, .ulong) },
983 .c_longlong => return .{ .scalar = cTypeAlign(target, .longlong) },
984 .c_ulonglong => return .{ .scalar = cTypeAlign(target, .ulonglong) },
985 .c_longdouble => return .{ .scalar = cTypeAlign(target, .longdouble) },
986
987 .f16 => return .{ .scalar = .@"2" },
988 .f32 => return .{ .scalar = cTypeAlign(target, .float) },
989 .f64 => switch (target.c_type_bit_size(.double)) {
990 64 => return .{ .scalar = cTypeAlign(target, .double) },
991 else => return .{ .scalar = .@"8" },
992 },
993 .f80 => switch (target.c_type_bit_size(.longdouble)) {
994 80 => return .{ .scalar = cTypeAlign(target, .longdouble) },
995 else => {
996 const u80_ty: Type = .{ .ip_index = .u80_type };
997 return .{ .scalar = abiAlignment(u80_ty, mod) };
998 },
999 },
1000 .f128 => switch (target.c_type_bit_size(.longdouble)) {
1001 128 => return .{ .scalar = cTypeAlign(target, .longdouble) },
1002 else => return .{ .scalar = .@"16" },
1003 },
1004
1005 .anyerror, .adhoc_inferred_error_set => {
1006 const bits = mod.errorSetBits();
1007 if (bits == 0) return AbiAlignmentAdvanced{ .scalar = .@"1" };
1008 return .{ .scalar = intAbiAlignment(bits, target, use_llvm) };
1009 },
1010
1011 .void,
1012 .type,
1013 .comptime_int,
1014 .comptime_float,
1015 .null,
1016 .undefined,
1017 .enum_literal,
1018 => return .{ .scalar = .@"1" },
1019
1020 .noreturn => unreachable,
1021 .generic_poison => unreachable,
1022 },
1023 .struct_type => {
1024 const struct_type = ip.loadStructType(ty.toIntern());
1025 if (struct_type.layout == .@"packed") {
1026 switch (strat) {
1027 .sema => |sema| try sema.resolveTypeLayout(ty),
1028 .lazy => if (struct_type.backingIntType(ip).* == .none) return .{
1029 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1030 .ty = .comptime_int_type,
1031 .storage = .{ .lazy_align = ty.toIntern() },
1032 } }))),
1033 },
1034 .eager => {},
1035 }
1036 return .{ .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiAlignment(mod) };
1037 }
1038
1039 const flags = struct_type.flagsPtr(ip).*;
1040 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
1041
1042 return switch (strat) {
1043 .eager => unreachable, // struct alignment not resolved
1044 .sema => |sema| .{
1045 .scalar = try sema.resolveStructAlignment(ty.toIntern(), struct_type),
1046 },
1047 .lazy => .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1048 .ty = .comptime_int_type,
1049 .storage = .{ .lazy_align = ty.toIntern() },
1050 } }))) },
1051 };
1052 },
1053 .anon_struct_type => |tuple| {
1054 var big_align: Alignment = .@"1";
1055 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
1056 if (val != .none) continue; // comptime field
1057 switch (try Type.fromInterned(field_ty).abiAlignmentAdvanced(mod, strat)) {
1058 .scalar => |field_align| big_align = big_align.max(field_align),
1059 .val => switch (strat) {
1060 .eager => unreachable, // field type alignment not resolved
1061 .sema => unreachable, // passed to abiAlignmentAdvanced above
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 }
1069 return .{ .scalar = big_align };
1070 },
1071 .union_type => {
1072 const union_type = ip.loadUnionType(ty.toIntern());
1073 const flags = union_type.flagsPtr(ip).*;
1074 if (flags.alignment != .none) return .{ .scalar = flags.alignment };
1075
1076 if (!union_type.haveLayout(ip)) switch (strat) {
1077 .eager => unreachable, // union layout not resolved
1078 .sema => |sema| return .{ .scalar = try sema.resolveUnionAlignment(ty, union_type) },
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 return .{ .scalar = union_type.flagsPtr(ip).alignment };
1086 },
1087 .opaque_type => return .{ .scalar = .@"1" },
1088 .enum_type => return .{
1089 .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiAlignment(mod),
1090 },
1091
1092 // values, not types
1093 .undef,
1094 .simple_value,
1095 .variable,
1096 .extern_func,
1097 .func,
1098 .int,
1099 .err,
1100 .error_union,
1101 .enum_literal,
1102 .enum_tag,
1103 .empty_enum_value,
1104 .float,
1105 .ptr,
1106 .slice,
1107 .opt,
1108 .aggregate,
1109 .un,
1110 // memoization, not types
1111 .memoized_call,
1112 => unreachable,
1113 },
1114 }
1115}
1116
1117fn abiAlignmentAdvancedErrorUnion(
1118 ty: Type,
1119 mod: *Module,
1120 strat: AbiAlignmentAdvancedStrat,
1121 payload_ty: Type,
1122) Module.CompileError!AbiAlignmentAdvanced {
1123 // This code needs to be kept in sync with the equivalent switch prong
1124 // in abiSizeAdvanced.
1125 const code_align = abiAlignment(Type.anyerror, mod);
1126 switch (strat) {
1127 .eager, .sema => {
1128 if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1129 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1130 .ty = .comptime_int_type,
1131 .storage = .{ .lazy_align = ty.toIntern() },
1132 } }))) },
1133 else => |e| return e,
1134 })) {
1135 return .{ .scalar = code_align };
1136 }
1137 return .{ .scalar = code_align.max(
1138 (try payload_ty.abiAlignmentAdvanced(mod, strat)).scalar,
1139 ) };
1140 },
1141 .lazy => {
1142 switch (try payload_ty.abiAlignmentAdvanced(mod, strat)) {
1143 .scalar => |payload_align| return .{ .scalar = code_align.max(payload_align) },
1144 .val => {},
1145 }
1146 return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1147 .ty = .comptime_int_type,
1148 .storage = .{ .lazy_align = ty.toIntern() },
1149 } }))) };
1150 },
1151 }
1152}
1153
1154fn abiAlignmentAdvancedOptional(
1155 ty: Type,
1156 mod: *Module,
1157 strat: AbiAlignmentAdvancedStrat,
1158) Module.CompileError!AbiAlignmentAdvanced {
1159 const target = mod.getTarget();
1160 const child_type = ty.optionalChild(mod);
1161
1162 switch (child_type.zigTypeTag(mod)) {
1163 .Pointer => return .{ .scalar = ptrAbiAlignment(target) },
1164 .ErrorSet => return abiAlignmentAdvanced(Type.anyerror, mod, strat),
1165 .NoReturn => return .{ .scalar = .@"1" },
1166 else => {},
1167 }
1168
1169 switch (strat) {
1170 .eager, .sema => {
1171 if (!(child_type.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1172 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1173 .ty = .comptime_int_type,
1174 .storage = .{ .lazy_align = ty.toIntern() },
1175 } }))) },
1176 else => |e| return e,
1177 })) {
1178 return .{ .scalar = .@"1" };
1179 }
1180 return child_type.abiAlignmentAdvanced(mod, strat);
1181 },
1182 .lazy => switch (try child_type.abiAlignmentAdvanced(mod, strat)) {
1183 .scalar => |x| return .{ .scalar = x.max(.@"1") },
1184 .val => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1185 .ty = .comptime_int_type,
1186 .storage = .{ .lazy_align = ty.toIntern() },
1187 } }))) },
1188 },
1189 }
1190}
1191
1192/// May capture a reference to `ty`.
1193pub fn lazyAbiSize(ty: Type, mod: *Module) !Value {
1194 switch (try ty.abiSizeAdvanced(mod, .lazy)) {
1195 .val => |val| return val,
1196 .scalar => |x| return mod.intValue(Type.comptime_int, x),
1197 }
1198}
1199
1200/// Asserts the type has the ABI size already resolved.
1201/// Types that return false for hasRuntimeBits() return 0.
1202pub fn abiSize(ty: Type, mod: *Module) u64 {
1203 return (abiSizeAdvanced(ty, mod, .eager) catch unreachable).scalar;
1204}
1205
1206const AbiSizeAdvanced = union(enum) {
1207 scalar: u64,
1208 val: Value,
1209};
1210
1211/// If you pass `eager` you will get back `scalar` and assert the type is resolved.
1212/// In this case there will be no error, guaranteed.
1213/// If you pass `lazy` you may get back `scalar` or `val`.
1214/// If `val` is returned, a reference to `ty` has been captured.
1215/// If you pass `sema` you will get back `scalar` and resolve the type if
1216/// necessary, possibly returning a CompileError.
1217pub fn abiSizeAdvanced(
1218 ty: Type,
1219 mod: *Module,
1220 strat: AbiAlignmentAdvancedStrat,
1221) Module.CompileError!AbiSizeAdvanced {
1222 const target = mod.getTarget();
1223 const use_llvm = mod.comp.config.use_llvm;
1224 const ip = &mod.intern_pool;
1225
1226 switch (ty.toIntern()) {
1227 .empty_struct_type => return AbiSizeAdvanced{ .scalar = 0 },
1228
1229 else => switch (ip.indexToKey(ty.toIntern())) {
1230 .int_type => |int_type| {
1231 if (int_type.bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1232 return AbiSizeAdvanced{ .scalar = intAbiSize(int_type.bits, target, use_llvm) };
1233 },
1234 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1235 .Slice => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) * 2 },
1236 else => return .{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1237 },
1238 .anyframe_type => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1239
1240 .array_type => |array_type| {
1241 const len = array_type.lenIncludingSentinel();
1242 if (len == 0) return .{ .scalar = 0 };
1243 switch (try Type.fromInterned(array_type.child).abiSizeAdvanced(mod, strat)) {
1244 .scalar => |elem_size| return .{ .scalar = len * elem_size },
1245 .val => switch (strat) {
1246 .sema, .eager => unreachable,
1247 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1248 .ty = .comptime_int_type,
1249 .storage = .{ .lazy_size = ty.toIntern() },
1250 } }))) },
1251 },
1252 }
1253 },
1254 .vector_type => |vector_type| {
1255 const opt_sema = switch (strat) {
1256 .sema => |sema| sema,
1257 .eager => null,
1258 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1259 .ty = .comptime_int_type,
1260 .storage = .{ .lazy_size = ty.toIntern() },
1261 } }))) },
1262 };
1263 const alignment = switch (try ty.abiAlignmentAdvanced(mod, strat)) {
1264 .scalar => |x| x,
1265 .val => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1266 .ty = .comptime_int_type,
1267 .storage = .{ .lazy_size = ty.toIntern() },
1268 } }))) },
1269 };
1270 const total_bytes = switch (mod.comp.getZigBackend()) {
1271 else => total_bytes: {
1272 const elem_bits = try Type.fromInterned(vector_type.child).bitSizeAdvanced(mod, opt_sema);
1273 const total_bits = elem_bits * vector_type.len;
1274 break :total_bytes (total_bits + 7) / 8;
1275 },
1276 .stage2_c => total_bytes: {
1277 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1278 break :total_bytes elem_bytes * vector_type.len;
1279 },
1280 .stage2_x86_64 => total_bytes: {
1281 if (vector_type.child == .bool_type) break :total_bytes std.math.divCeil(u32, vector_type.len, 8) catch unreachable;
1282 const elem_bytes: u32 = @intCast((try Type.fromInterned(vector_type.child).abiSizeAdvanced(mod, strat)).scalar);
1283 break :total_bytes elem_bytes * vector_type.len;
1284 },
1285 };
1286 return AbiSizeAdvanced{ .scalar = alignment.forward(total_bytes) };
1287 },
1288
1289 .opt_type => return ty.abiSizeAdvancedOptional(mod, strat),
1290
1291 .error_set_type, .inferred_error_set_type => {
1292 const bits = mod.errorSetBits();
1293 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1294 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
1295 },
1296
1297 .error_union_type => |error_union_type| {
1298 const payload_ty = Type.fromInterned(error_union_type.payload_type);
1299 // This code needs to be kept in sync with the equivalent switch prong
1300 // in abiAlignmentAdvanced.
1301 const code_size = abiSize(Type.anyerror, mod);
1302 if (!(payload_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1303 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1304 .ty = .comptime_int_type,
1305 .storage = .{ .lazy_size = ty.toIntern() },
1306 } }))) },
1307 else => |e| return e,
1308 })) {
1309 // Same as anyerror.
1310 return AbiSizeAdvanced{ .scalar = code_size };
1311 }
1312 const code_align = abiAlignment(Type.anyerror, mod);
1313 const payload_align = abiAlignment(payload_ty, mod);
1314 const payload_size = switch (try payload_ty.abiSizeAdvanced(mod, strat)) {
1315 .scalar => |elem_size| elem_size,
1316 .val => switch (strat) {
1317 .sema => unreachable,
1318 .eager => unreachable,
1319 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1320 .ty = .comptime_int_type,
1321 .storage = .{ .lazy_size = ty.toIntern() },
1322 } }))) },
1323 },
1324 };
1325
1326 var size: u64 = 0;
1327 if (code_align.compare(.gt, payload_align)) {
1328 size += code_size;
1329 size = payload_align.forward(size);
1330 size += payload_size;
1331 size = code_align.forward(size);
1332 } else {
1333 size += payload_size;
1334 size = code_align.forward(size);
1335 size += code_size;
1336 size = payload_align.forward(size);
1337 }
1338 return AbiSizeAdvanced{ .scalar = size };
1339 },
1340 .func_type => unreachable, // represents machine code; not a pointer
1341 .simple_type => |t| switch (t) {
1342 .bool,
1343 .atomic_order,
1344 .atomic_rmw_op,
1345 .calling_convention,
1346 .address_space,
1347 .float_mode,
1348 .reduce_op,
1349 .call_modifier,
1350 => return AbiSizeAdvanced{ .scalar = 1 },
1351
1352 .f16 => return AbiSizeAdvanced{ .scalar = 2 },
1353 .f32 => return AbiSizeAdvanced{ .scalar = 4 },
1354 .f64 => return AbiSizeAdvanced{ .scalar = 8 },
1355 .f128 => return AbiSizeAdvanced{ .scalar = 16 },
1356 .f80 => switch (target.c_type_bit_size(.longdouble)) {
1357 80 => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) },
1358 else => {
1359 const u80_ty: Type = .{ .ip_index = .u80_type };
1360 return AbiSizeAdvanced{ .scalar = abiSize(u80_ty, mod) };
1361 },
1362 },
1363
1364 .usize,
1365 .isize,
1366 => return AbiSizeAdvanced{ .scalar = @divExact(target.ptrBitWidth(), 8) },
1367
1368 .c_char => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.char) },
1369 .c_short => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.short) },
1370 .c_ushort => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ushort) },
1371 .c_int => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.int) },
1372 .c_uint => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.uint) },
1373 .c_long => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.long) },
1374 .c_ulong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulong) },
1375 .c_longlong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longlong) },
1376 .c_ulonglong => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.ulonglong) },
1377 .c_longdouble => return AbiSizeAdvanced{ .scalar = target.c_type_byte_size(.longdouble) },
1378
1379 .anyopaque,
1380 .void,
1381 .type,
1382 .comptime_int,
1383 .comptime_float,
1384 .null,
1385 .undefined,
1386 .enum_literal,
1387 => return AbiSizeAdvanced{ .scalar = 0 },
1388
1389 .anyerror, .adhoc_inferred_error_set => {
1390 const bits = mod.errorSetBits();
1391 if (bits == 0) return AbiSizeAdvanced{ .scalar = 0 };
1392 return AbiSizeAdvanced{ .scalar = intAbiSize(bits, target, use_llvm) };
1393 },
1394
1395 .prefetch_options => unreachable, // missing call to resolveTypeFields
1396 .export_options => unreachable, // missing call to resolveTypeFields
1397 .extern_options => unreachable, // missing call to resolveTypeFields
1398
1399 .type_info => unreachable,
1400 .noreturn => unreachable,
1401 .generic_poison => unreachable,
1402 },
1403 .struct_type => {
1404 const struct_type = ip.loadStructType(ty.toIntern());
1405 switch (strat) {
1406 .sema => |sema| try sema.resolveTypeLayout(ty),
1407 .lazy => switch (struct_type.layout) {
1408 .@"packed" => {
1409 if (struct_type.backingIntType(ip).* == .none) return .{
1410 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1411 .ty = .comptime_int_type,
1412 .storage = .{ .lazy_size = ty.toIntern() },
1413 } }))),
1414 };
1415 },
1416 .auto, .@"extern" => {
1417 if (!struct_type.haveLayout(ip)) return .{
1418 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1419 .ty = .comptime_int_type,
1420 .storage = .{ .lazy_size = ty.toIntern() },
1421 } }))),
1422 };
1423 },
1424 },
1425 .eager => {},
1426 }
1427 switch (struct_type.layout) {
1428 .@"packed" => return .{
1429 .scalar = Type.fromInterned(struct_type.backingIntType(ip).*).abiSize(mod),
1430 },
1431 .auto, .@"extern" => {
1432 assert(struct_type.haveLayout(ip));
1433 return .{ .scalar = struct_type.size(ip).* };
1434 },
1435 }
1436 },
1437 .anon_struct_type => |tuple| {
1438 switch (strat) {
1439 .sema => |sema| try sema.resolveTypeLayout(ty),
1440 .lazy, .eager => {},
1441 }
1442 const field_count = tuple.types.len;
1443 if (field_count == 0) {
1444 return AbiSizeAdvanced{ .scalar = 0 };
1445 }
1446 return AbiSizeAdvanced{ .scalar = ty.structFieldOffset(field_count, mod) };
1447 },
1448
1449 .union_type => {
1450 const union_type = ip.loadUnionType(ty.toIntern());
1451 switch (strat) {
1452 .sema => |sema| try sema.resolveTypeLayout(ty),
1453 .lazy => if (!union_type.flagsPtr(ip).status.haveLayout()) return .{
1454 .val = Value.fromInterned((try mod.intern(.{ .int = .{
1455 .ty = .comptime_int_type,
1456 .storage = .{ .lazy_size = ty.toIntern() },
1457 } }))),
1458 },
1459 .eager => {},
1460 }
1461
1462 assert(union_type.haveLayout(ip));
1463 return .{ .scalar = union_type.size(ip).* };
1464 },
1465 .opaque_type => unreachable, // no size available
1466 .enum_type => return .{ .scalar = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).abiSize(mod) },
1467
1468 // values, not types
1469 .undef,
1470 .simple_value,
1471 .variable,
1472 .extern_func,
1473 .func,
1474 .int,
1475 .err,
1476 .error_union,
1477 .enum_literal,
1478 .enum_tag,
1479 .empty_enum_value,
1480 .float,
1481 .ptr,
1482 .slice,
1483 .opt,
1484 .aggregate,
1485 .un,
1486 // memoization, not types
1487 .memoized_call,
1488 => unreachable,
1489 },
1490 }
1491}
1492
1493fn abiSizeAdvancedOptional(
1494 ty: Type,
1495 mod: *Module,
1496 strat: AbiAlignmentAdvancedStrat,
1497) Module.CompileError!AbiSizeAdvanced {
1498 const child_ty = ty.optionalChild(mod);
1499
1500 if (child_ty.isNoReturn(mod)) {
1501 return AbiSizeAdvanced{ .scalar = 0 };
1502 }
1503
1504 if (!(child_ty.hasRuntimeBitsAdvanced(mod, false, strat) catch |err| switch (err) {
1505 error.NeedLazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1506 .ty = .comptime_int_type,
1507 .storage = .{ .lazy_size = ty.toIntern() },
1508 } }))) },
1509 else => |e| return e,
1510 })) return AbiSizeAdvanced{ .scalar = 1 };
1511
1512 if (ty.optionalReprIsPayload(mod)) {
1513 return abiSizeAdvanced(child_ty, mod, strat);
1514 }
1515
1516 const payload_size = switch (try child_ty.abiSizeAdvanced(mod, strat)) {
1517 .scalar => |elem_size| elem_size,
1518 .val => switch (strat) {
1519 .sema => unreachable,
1520 .eager => unreachable,
1521 .lazy => return .{ .val = Value.fromInterned((try mod.intern(.{ .int = .{
1522 .ty = .comptime_int_type,
1523 .storage = .{ .lazy_size = ty.toIntern() },
1524 } }))) },
1525 },
1526 };
1527
1528 // Optional types are represented as a struct with the child type as the first
1529 // field and a boolean as the second. Since the child type's abi alignment is
1530 // guaranteed to be >= that of bool's (1 byte) the added size is exactly equal
1531 // to the child type's ABI alignment.
1532 return AbiSizeAdvanced{
1533 .scalar = (child_ty.abiAlignment(mod).toByteUnits() orelse 0) + payload_size,
1534 };
1535}
1536
1537pub fn ptrAbiAlignment(target: Target) Alignment {
1538 return Alignment.fromNonzeroByteUnits(@divExact(target.ptrBitWidth(), 8));
1539}
1540
1541pub fn intAbiSize(bits: u16, target: Target, use_llvm: bool) u64 {
1542 return intAbiAlignment(bits, target, use_llvm).forward(@as(u16, @intCast((@as(u17, bits) + 7) / 8)));
1543}
1544
1545pub fn intAbiAlignment(bits: u16, target: Target, use_llvm: bool) Alignment {
1546 return switch (target.cpu.arch) {
1547 .x86 => switch (bits) {
1548 0 => .none,
1549 1...8 => .@"1",
1550 9...16 => .@"2",
1551 17...64 => .@"4",
1552 else => .@"16",
1553 },
1554 .x86_64 => switch (bits) {
1555 0 => .none,
1556 1...8 => .@"1",
1557 9...16 => .@"2",
1558 17...32 => .@"4",
1559 33...64 => .@"8",
1560 else => switch (target_util.zigBackend(target, use_llvm)) {
1561 .stage2_x86_64 => .@"8",
1562 else => .@"16",
1563 },
1564 },
1565 else => return Alignment.fromByteUnits(@min(
1566 std.math.ceilPowerOfTwoPromote(u16, @as(u16, @intCast((@as(u17, bits) + 7) / 8))),
1567 maxIntAlignment(target, use_llvm),
1568 )),
1569 };
1570}
1571
1572pub fn maxIntAlignment(target: std.Target, use_llvm: bool) u16 {
1573 return switch (target.cpu.arch) {
1574 .avr => 1,
1575 .msp430 => 2,
1576 .xcore => 4,
1577
1578 .arm,
1579 .armeb,
1580 .thumb,
1581 .thumbeb,
1582 .hexagon,
1583 .mips,
1584 .mipsel,
1585 .powerpc,
1586 .powerpcle,
1587 .r600,
1588 .amdgcn,
1589 .riscv32,
1590 .sparc,
1591 .sparcel,
1592 .s390x,
1593 .lanai,
1594 .wasm32,
1595 .wasm64,
1596 => 8,
1597
1598 // For these, LLVMABIAlignmentOfType(i128) reports 8. Note that 16
1599 // is a relevant number in three cases:
1600 // 1. Different machine code instruction when loading into SIMD register.
1601 // 2. The C ABI wants 16 for extern structs.
1602 // 3. 16-byte cmpxchg needs 16-byte alignment.
1603 // Same logic for powerpc64, mips64, sparc64.
1604 .powerpc64,
1605 .powerpc64le,
1606 .mips64,
1607 .mips64el,
1608 .sparc64,
1609 => switch (target.ofmt) {
1610 .c => 16,
1611 else => 8,
1612 },
1613
1614 .x86_64 => switch (target_util.zigBackend(target, use_llvm)) {
1615 .stage2_x86_64 => 8,
1616 else => 16,
1617 },
1618
1619 // Even LLVMABIAlignmentOfType(i128) agrees on these targets.
1620 .x86,
1621 .aarch64,
1622 .aarch64_be,
1623 .aarch64_32,
1624 .riscv64,
1625 .bpfel,
1626 .bpfeb,
1627 .nvptx,
1628 .nvptx64,
1629 => 16,
1630
1631 // Below this comment are unverified but based on the fact that C requires
1632 // int128_t to be 16 bytes aligned, it's a safe default.
1633 .spu_2,
1634 .csky,
1635 .arc,
1636 .m68k,
1637 .tce,
1638 .tcele,
1639 .le32,
1640 .amdil,
1641 .hsail,
1642 .spir,
1643 .kalimba,
1644 .renderscript32,
1645 .spirv,
1646 .spirv32,
1647 .shave,
1648 .le64,
1649 .amdil64,
1650 .hsail64,
1651 .spir64,
1652 .renderscript64,
1653 .ve,
1654 .spirv64,
1655 .dxil,
1656 .loongarch32,
1657 .loongarch64,
1658 .xtensa,
1659 => 16,
1660 };
1661}
1662
1663pub fn bitSize(ty: Type, mod: *Module) u64 {
1664 return bitSizeAdvanced(ty, mod, null) catch unreachable;
1665}
1666
1667/// If you pass `opt_sema`, any recursive type resolutions will happen if
1668/// necessary, possibly returning a CompileError. Passing `null` instead asserts
1669/// the type is fully resolved, and there will be no error, guaranteed.
1670pub fn bitSizeAdvanced(
1671 ty: Type,
1672 mod: *Module,
1673 opt_sema: ?*Sema,
1674) Module.CompileError!u64 {
1675 const target = mod.getTarget();
1676 const ip = &mod.intern_pool;
1677
1678 const strat: AbiAlignmentAdvancedStrat = if (opt_sema) |sema| .{ .sema = sema } else .eager;
1679
1680 switch (ip.indexToKey(ty.toIntern())) {
1681 .int_type => |int_type| return int_type.bits,
1682 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1683 .Slice => return target.ptrBitWidth() * 2,
1684 else => return target.ptrBitWidth(),
1685 },
1686 .anyframe_type => return target.ptrBitWidth(),
1687
1688 .array_type => |array_type| {
1689 const len = array_type.lenIncludingSentinel();
1690 if (len == 0) return 0;
1691 const elem_ty = Type.fromInterned(array_type.child);
1692 const elem_size = @max(
1693 (try elem_ty.abiAlignmentAdvanced(mod, strat)).scalar.toByteUnits() orelse 0,
1694 (try elem_ty.abiSizeAdvanced(mod, strat)).scalar,
1695 );
1696 if (elem_size == 0) return 0;
1697 const elem_bit_size = try bitSizeAdvanced(elem_ty, mod, opt_sema);
1698 return (len - 1) * 8 * elem_size + elem_bit_size;
1699 },
1700 .vector_type => |vector_type| {
1701 const child_ty = Type.fromInterned(vector_type.child);
1702 const elem_bit_size = try bitSizeAdvanced(child_ty, mod, opt_sema);
1703 return elem_bit_size * vector_type.len;
1704 },
1705 .opt_type => {
1706 // Optionals and error unions are not packed so their bitsize
1707 // includes padding bits.
1708 return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8;
1709 },
1710
1711 .error_set_type, .inferred_error_set_type => return mod.errorSetBits(),
1712
1713 .error_union_type => {
1714 // Optionals and error unions are not packed so their bitsize
1715 // includes padding bits.
1716 return (try abiSizeAdvanced(ty, mod, strat)).scalar * 8;
1717 },
1718 .func_type => unreachable, // represents machine code; not a pointer
1719 .simple_type => |t| switch (t) {
1720 .f16 => return 16,
1721 .f32 => return 32,
1722 .f64 => return 64,
1723 .f80 => return 80,
1724 .f128 => return 128,
1725
1726 .usize,
1727 .isize,
1728 => return target.ptrBitWidth(),
1729
1730 .c_char => return target.c_type_bit_size(.char),
1731 .c_short => return target.c_type_bit_size(.short),
1732 .c_ushort => return target.c_type_bit_size(.ushort),
1733 .c_int => return target.c_type_bit_size(.int),
1734 .c_uint => return target.c_type_bit_size(.uint),
1735 .c_long => return target.c_type_bit_size(.long),
1736 .c_ulong => return target.c_type_bit_size(.ulong),
1737 .c_longlong => return target.c_type_bit_size(.longlong),
1738 .c_ulonglong => return target.c_type_bit_size(.ulonglong),
1739 .c_longdouble => return target.c_type_bit_size(.longdouble),
1740
1741 .bool => return 1,
1742 .void => return 0,
1743
1744 .anyerror,
1745 .adhoc_inferred_error_set,
1746 => return mod.errorSetBits(),
1747
1748 .anyopaque => unreachable,
1749 .type => unreachable,
1750 .comptime_int => unreachable,
1751 .comptime_float => unreachable,
1752 .noreturn => unreachable,
1753 .null => unreachable,
1754 .undefined => unreachable,
1755 .enum_literal => unreachable,
1756 .generic_poison => unreachable,
1757
1758 .atomic_order => unreachable,
1759 .atomic_rmw_op => unreachable,
1760 .calling_convention => unreachable,
1761 .address_space => unreachable,
1762 .float_mode => unreachable,
1763 .reduce_op => unreachable,
1764 .call_modifier => unreachable,
1765 .prefetch_options => unreachable,
1766 .export_options => unreachable,
1767 .extern_options => unreachable,
1768 .type_info => unreachable,
1769 },
1770 .struct_type => {
1771 const struct_type = ip.loadStructType(ty.toIntern());
1772 const is_packed = struct_type.layout == .@"packed";
1773 if (opt_sema) |sema| {
1774 try sema.resolveTypeFields(ty);
1775 if (is_packed) try sema.resolveTypeLayout(ty);
1776 }
1777 if (is_packed) {
1778 return try Type.fromInterned(struct_type.backingIntType(ip).*).bitSizeAdvanced(mod, opt_sema);
1779 }
1780 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1781 },
1782
1783 .anon_struct_type => {
1784 if (opt_sema) |sema| try sema.resolveTypeFields(ty);
1785 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1786 },
1787
1788 .union_type => {
1789 const union_type = ip.loadUnionType(ty.toIntern());
1790 const is_packed = ty.containerLayout(mod) == .@"packed";
1791 if (opt_sema) |sema| {
1792 try sema.resolveTypeFields(ty);
1793 if (is_packed) try sema.resolveTypeLayout(ty);
1794 }
1795 if (!is_packed) {
1796 return (try ty.abiSizeAdvanced(mod, strat)).scalar * 8;
1797 }
1798 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
1799
1800 var size: u64 = 0;
1801 for (0..union_type.field_types.len) |field_index| {
1802 const field_ty = union_type.field_types.get(ip)[field_index];
1803 size = @max(size, try bitSizeAdvanced(Type.fromInterned(field_ty), mod, opt_sema));
1804 }
1805
1806 return size;
1807 },
1808 .opaque_type => unreachable,
1809 .enum_type => return bitSizeAdvanced(Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty), mod, opt_sema),
1810
1811 // values, not types
1812 .undef,
1813 .simple_value,
1814 .variable,
1815 .extern_func,
1816 .func,
1817 .int,
1818 .err,
1819 .error_union,
1820 .enum_literal,
1821 .enum_tag,
1822 .empty_enum_value,
1823 .float,
1824 .ptr,
1825 .slice,
1826 .opt,
1827 .aggregate,
1828 .un,
1829 // memoization, not types
1830 .memoized_call,
1831 => unreachable,
1832 }
1833}
1834
1835/// Returns true if the type's layout is already resolved and it is safe
1836/// to use `abiSize`, `abiAlignment` and `bitSize` on it.
1837pub fn layoutIsResolved(ty: Type, mod: *Module) bool {
1838 const ip = &mod.intern_pool;
1839 return switch (ip.indexToKey(ty.toIntern())) {
1840 .struct_type => ip.loadStructType(ty.toIntern()).haveLayout(ip),
1841 .union_type => ip.loadUnionType(ty.toIntern()).haveLayout(ip),
1842 .array_type => |array_type| {
1843 if (array_type.lenIncludingSentinel() == 0) return true;
1844 return Type.fromInterned(array_type.child).layoutIsResolved(mod);
1845 },
1846 .opt_type => |child| Type.fromInterned(child).layoutIsResolved(mod),
1847 .error_union_type => |k| Type.fromInterned(k.payload_type).layoutIsResolved(mod),
1848 else => true,
1849 };
1850}
1851
1852pub fn isSinglePointer(ty: Type, mod: *const Module) bool {
1853 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1854 .ptr_type => |ptr_info| ptr_info.flags.size == .One,
1855 else => false,
1856 };
1857}
1858
1859/// Asserts `ty` is a pointer.
1860pub fn ptrSize(ty: Type, mod: *const Module) std.builtin.Type.Pointer.Size {
1861 return ptrSizeOrNull(ty, mod).?;
1862}
1863
1864/// Returns `null` if `ty` is not a pointer.
1865pub fn ptrSizeOrNull(ty: Type, mod: *const Module) ?std.builtin.Type.Pointer.Size {
1866 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1867 .ptr_type => |ptr_info| ptr_info.flags.size,
1868 else => null,
1869 };
1870}
1871
1872pub fn isSlice(ty: Type, mod: *const Module) bool {
1873 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1874 .ptr_type => |ptr_type| ptr_type.flags.size == .Slice,
1875 else => false,
1876 };
1877}
1878
1879pub fn slicePtrFieldType(ty: Type, mod: *const Module) Type {
1880 return Type.fromInterned(mod.intern_pool.slicePtrType(ty.toIntern()));
1881}
1882
1883pub fn isConstPtr(ty: Type, mod: *const Module) bool {
1884 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1885 .ptr_type => |ptr_type| ptr_type.flags.is_const,
1886 else => false,
1887 };
1888}
1889
1890pub fn isVolatilePtr(ty: Type, mod: *const Module) bool {
1891 return isVolatilePtrIp(ty, &mod.intern_pool);
1892}
1893
1894pub fn isVolatilePtrIp(ty: Type, ip: *const InternPool) bool {
1895 return switch (ip.indexToKey(ty.toIntern())) {
1896 .ptr_type => |ptr_type| ptr_type.flags.is_volatile,
1897 else => false,
1898 };
1899}
1900
1901pub fn isAllowzeroPtr(ty: Type, mod: *const Module) bool {
1902 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1903 .ptr_type => |ptr_type| ptr_type.flags.is_allowzero,
1904 .opt_type => true,
1905 else => false,
1906 };
1907}
1908
1909pub fn isCPtr(ty: Type, mod: *const Module) bool {
1910 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1911 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1912 else => false,
1913 };
1914}
1915
1916pub fn isPtrAtRuntime(ty: Type, mod: *const Module) bool {
1917 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1918 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1919 .Slice => false,
1920 .One, .Many, .C => true,
1921 },
1922 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
1923 .ptr_type => |p| switch (p.flags.size) {
1924 .Slice, .C => false,
1925 .Many, .One => !p.flags.is_allowzero,
1926 },
1927 else => false,
1928 },
1929 else => false,
1930 };
1931}
1932
1933/// For pointer-like optionals, returns true, otherwise returns the allowzero property
1934/// of pointers.
1935pub fn ptrAllowsZero(ty: Type, mod: *const Module) bool {
1936 if (ty.isPtrLikeOptional(mod)) {
1937 return true;
1938 }
1939 return ty.ptrInfo(mod).flags.is_allowzero;
1940}
1941
1942/// See also `isPtrLikeOptional`.
1943pub fn optionalReprIsPayload(ty: Type, mod: *const Module) bool {
1944 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1945 .opt_type => |child_type| child_type == .anyerror_type or switch (mod.intern_pool.indexToKey(child_type)) {
1946 .ptr_type => |ptr_type| ptr_type.flags.size != .C and !ptr_type.flags.is_allowzero,
1947 .error_set_type, .inferred_error_set_type => true,
1948 else => false,
1949 },
1950 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1951 else => false,
1952 };
1953}
1954
1955/// Returns true if the type is optional and would be lowered to a single pointer
1956/// address value, using 0 for null. Note that this returns true for C pointers.
1957/// This function must be kept in sync with `Sema.typePtrOrOptionalPtrTy`.
1958pub fn isPtrLikeOptional(ty: Type, mod: *const Module) bool {
1959 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1960 .ptr_type => |ptr_type| ptr_type.flags.size == .C,
1961 .opt_type => |child| switch (mod.intern_pool.indexToKey(child)) {
1962 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1963 .Slice, .C => false,
1964 .Many, .One => !ptr_type.flags.is_allowzero,
1965 },
1966 else => false,
1967 },
1968 else => false,
1969 };
1970}
1971
1972/// For *[N]T, returns [N]T.
1973/// For *T, returns T.
1974/// For [*]T, returns T.
1975pub fn childType(ty: Type, mod: *const Module) Type {
1976 return childTypeIp(ty, &mod.intern_pool);
1977}
1978
1979pub fn childTypeIp(ty: Type, ip: *const InternPool) Type {
1980 return Type.fromInterned(ip.childType(ty.toIntern()));
1981}
1982
1983/// For *[N]T, returns T.
1984/// For ?*T, returns T.
1985/// For ?*[N]T, returns T.
1986/// For ?[*]T, returns T.
1987/// For *T, returns T.
1988/// For [*]T, returns T.
1989/// For [N]T, returns T.
1990/// For []T, returns T.
1991/// For anyframe->T, returns T.
1992pub fn elemType2(ty: Type, mod: *const Module) Type {
1993 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
1994 .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
1995 .One => Type.fromInterned(ptr_type.child).shallowElemType(mod),
1996 .Many, .C, .Slice => Type.fromInterned(ptr_type.child),
1997 },
1998 .anyframe_type => |child| {
1999 assert(child != .none);
2000 return Type.fromInterned(child);
2001 },
2002 .vector_type => |vector_type| Type.fromInterned(vector_type.child),
2003 .array_type => |array_type| Type.fromInterned(array_type.child),
2004 .opt_type => |child| Type.fromInterned(mod.intern_pool.childType(child)),
2005 else => unreachable,
2006 };
2007}
2008
2009fn shallowElemType(child_ty: Type, mod: *const Module) Type {
2010 return switch (child_ty.zigTypeTag(mod)) {
2011 .Array, .Vector => child_ty.childType(mod),
2012 else => child_ty,
2013 };
2014}
2015
2016/// For vectors, returns the element type. Otherwise returns self.
2017pub fn scalarType(ty: Type, mod: *Module) Type {
2018 return switch (ty.zigTypeTag(mod)) {
2019 .Vector => ty.childType(mod),
2020 else => ty,
2021 };
2022}
2023
2024/// Asserts that the type is an optional.
2025/// Note that for C pointers this returns the type unmodified.
2026pub fn optionalChild(ty: Type, mod: *const Module) Type {
2027 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2028 .opt_type => |child| Type.fromInterned(child),
2029 .ptr_type => |ptr_type| b: {
2030 assert(ptr_type.flags.size == .C);
2031 break :b ty;
2032 },
2033 else => unreachable,
2034 };
2035}
2036
2037/// Returns the tag type of a union, if the type is a union and it has a tag type.
2038/// Otherwise, returns `null`.
2039pub fn unionTagType(ty: Type, mod: *Module) ?Type {
2040 const ip = &mod.intern_pool;
2041 switch (ip.indexToKey(ty.toIntern())) {
2042 .union_type => {},
2043 else => return null,
2044 }
2045 const union_type = ip.loadUnionType(ty.toIntern());
2046 switch (union_type.flagsPtr(ip).runtime_tag) {
2047 .tagged => {
2048 assert(union_type.flagsPtr(ip).status.haveFieldTypes());
2049 return Type.fromInterned(union_type.enum_tag_ty);
2050 },
2051 else => return null,
2052 }
2053}
2054
2055/// Same as `unionTagType` but includes safety tag.
2056/// Codegen should use this version.
2057pub fn unionTagTypeSafety(ty: Type, mod: *Module) ?Type {
2058 const ip = &mod.intern_pool;
2059 return switch (ip.indexToKey(ty.toIntern())) {
2060 .union_type => {
2061 const union_type = ip.loadUnionType(ty.toIntern());
2062 if (!union_type.hasTag(ip)) return null;
2063 assert(union_type.haveFieldTypes(ip));
2064 return Type.fromInterned(union_type.enum_tag_ty);
2065 },
2066 else => null,
2067 };
2068}
2069
2070/// Asserts the type is a union; returns the tag type, even if the tag will
2071/// not be stored at runtime.
2072pub fn unionTagTypeHypothetical(ty: Type, mod: *Module) Type {
2073 const union_obj = mod.typeToUnion(ty).?;
2074 return Type.fromInterned(union_obj.enum_tag_ty);
2075}
2076
2077pub fn unionFieldType(ty: Type, enum_tag: Value, mod: *Module) ?Type {
2078 const ip = &mod.intern_pool;
2079 const union_obj = mod.typeToUnion(ty).?;
2080 const union_fields = union_obj.field_types.get(ip);
2081 const index = mod.unionTagFieldIndex(union_obj, enum_tag) orelse return null;
2082 return Type.fromInterned(union_fields[index]);
2083}
2084
2085pub fn unionFieldTypeByIndex(ty: Type, index: usize, mod: *Module) Type {
2086 const ip = &mod.intern_pool;
2087 const union_obj = mod.typeToUnion(ty).?;
2088 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
2089}
2090
2091pub fn unionTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
2092 const union_obj = mod.typeToUnion(ty).?;
2093 return mod.unionTagFieldIndex(union_obj, enum_tag);
2094}
2095
2096pub fn unionHasAllZeroBitFieldTypes(ty: Type, mod: *Module) bool {
2097 const ip = &mod.intern_pool;
2098 const union_obj = mod.typeToUnion(ty).?;
2099 for (union_obj.field_types.get(ip)) |field_ty| {
2100 if (Type.fromInterned(field_ty).hasRuntimeBits(mod)) return false;
2101 }
2102 return true;
2103}
2104
2105/// Returns the type used for backing storage of this union during comptime operations.
2106/// Asserts the type is either an extern or packed union.
2107pub fn unionBackingType(ty: Type, mod: *Module) !Type {
2108 return switch (ty.containerLayout(mod)) {
2109 .@"extern" => try mod.arrayType(.{ .len = ty.abiSize(mod), .child = .u8_type }),
2110 .@"packed" => try mod.intType(.unsigned, @intCast(ty.bitSize(mod))),
2111 .auto => unreachable,
2112 };
2113}
2114
2115pub fn unionGetLayout(ty: Type, mod: *Module) Module.UnionLayout {
2116 const ip = &mod.intern_pool;
2117 const union_obj = ip.loadUnionType(ty.toIntern());
2118 return mod.getUnionLayout(union_obj);
2119}
2120
2121pub fn containerLayout(ty: Type, mod: *Module) std.builtin.Type.ContainerLayout {
2122 const ip = &mod.intern_pool;
2123 return switch (ip.indexToKey(ty.toIntern())) {
2124 .struct_type => ip.loadStructType(ty.toIntern()).layout,
2125 .anon_struct_type => .auto,
2126 .union_type => ip.loadUnionType(ty.toIntern()).flagsPtr(ip).layout,
2127 else => unreachable,
2128 };
2129}
2130
2131/// Asserts that the type is an error union.
2132pub fn errorUnionPayload(ty: Type, mod: *Module) Type {
2133 return Type.fromInterned(mod.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type);
2134}
2135
2136/// Asserts that the type is an error union.
2137pub fn errorUnionSet(ty: Type, mod: *Module) Type {
2138 return Type.fromInterned(mod.intern_pool.errorUnionSet(ty.toIntern()));
2139}
2140
2141/// Returns false for unresolved inferred error sets.
2142pub fn errorSetIsEmpty(ty: Type, mod: *Module) bool {
2143 const ip = &mod.intern_pool;
2144 return switch (ty.toIntern()) {
2145 .anyerror_type, .adhoc_inferred_error_set_type => false,
2146 else => switch (ip.indexToKey(ty.toIntern())) {
2147 .error_set_type => |error_set_type| error_set_type.names.len == 0,
2148 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2149 .none, .anyerror_type => false,
2150 else => |t| ip.indexToKey(t).error_set_type.names.len == 0,
2151 },
2152 else => unreachable,
2153 },
2154 };
2155}
2156
2157/// Returns true if it is an error set that includes anyerror, false otherwise.
2158/// Note that the result may be a false negative if the type did not get error set
2159/// resolution prior to this call.
2160pub fn isAnyError(ty: Type, mod: *Module) bool {
2161 const ip = &mod.intern_pool;
2162 return switch (ty.toIntern()) {
2163 .anyerror_type => true,
2164 .adhoc_inferred_error_set_type => false,
2165 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2166 .inferred_error_set_type => |i| ip.funcIesResolved(i).* == .anyerror_type,
2167 else => false,
2168 },
2169 };
2170}
2171
2172pub fn isError(ty: Type, mod: *const Module) bool {
2173 return switch (ty.zigTypeTag(mod)) {
2174 .ErrorUnion, .ErrorSet => true,
2175 else => false,
2176 };
2177}
2178
2179/// Returns whether ty, which must be an error set, includes an error `name`.
2180/// Might return a false negative if `ty` is an inferred error set and not fully
2181/// resolved yet.
2182pub fn errorSetHasFieldIp(
2183 ip: *const InternPool,
2184 ty: InternPool.Index,
2185 name: InternPool.NullTerminatedString,
2186) bool {
2187 return switch (ty) {
2188 .anyerror_type => true,
2189 else => switch (ip.indexToKey(ty)) {
2190 .error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null,
2191 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2192 .anyerror_type => true,
2193 .none => false,
2194 else => |t| ip.indexToKey(t).error_set_type.nameIndex(ip, name) != null,
2195 },
2196 else => unreachable,
2197 },
2198 };
2199}
2200
2201/// Returns whether ty, which must be an error set, includes an error `name`.
2202/// Might return a false negative if `ty` is an inferred error set and not fully
2203/// resolved yet.
2204pub fn errorSetHasField(ty: Type, name: []const u8, mod: *Module) bool {
2205 const ip = &mod.intern_pool;
2206 return switch (ty.toIntern()) {
2207 .anyerror_type => true,
2208 else => switch (ip.indexToKey(ty.toIntern())) {
2209 .error_set_type => |error_set_type| {
2210 // If the string is not interned, then the field certainly is not present.
2211 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2212 return error_set_type.nameIndex(ip, field_name_interned) != null;
2213 },
2214 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
2215 .anyerror_type => true,
2216 .none => false,
2217 else => |t| {
2218 // If the string is not interned, then the field certainly is not present.
2219 const field_name_interned = ip.getString(name).unwrap() orelse return false;
2220 return ip.indexToKey(t).error_set_type.nameIndex(ip, field_name_interned) != null;
2221 },
2222 },
2223 else => unreachable,
2224 },
2225 };
2226}
2227
2228/// Asserts the type is an array or vector or struct.
2229pub fn arrayLen(ty: Type, mod: *const Module) u64 {
2230 return ty.arrayLenIp(&mod.intern_pool);
2231}
2232
2233pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 {
2234 return ip.aggregateTypeLen(ty.toIntern());
2235}
2236
2237pub fn arrayLenIncludingSentinel(ty: Type, mod: *const Module) u64 {
2238 return mod.intern_pool.aggregateTypeLenIncludingSentinel(ty.toIntern());
2239}
2240
2241pub fn vectorLen(ty: Type, mod: *const Module) u32 {
2242 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2243 .vector_type => |vector_type| vector_type.len,
2244 .anon_struct_type => |tuple| @intCast(tuple.types.len),
2245 else => unreachable,
2246 };
2247}
2248
2249/// Asserts the type is an array, pointer or vector.
2250pub fn sentinel(ty: Type, mod: *const Module) ?Value {
2251 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2252 .vector_type,
2253 .struct_type,
2254 .anon_struct_type,
2255 => null,
2256
2257 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
2258 .ptr_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null,
2259
2260 else => unreachable,
2261 };
2262}
2263
2264/// Returns true if and only if the type is a fixed-width integer.
2265pub fn isInt(self: Type, mod: *const Module) bool {
2266 return self.toIntern() != .comptime_int_type and
2267 mod.intern_pool.isIntegerType(self.toIntern());
2268}
2269
2270/// Returns true if and only if the type is a fixed-width, signed integer.
2271pub fn isSignedInt(ty: Type, mod: *const Module) bool {
2272 return switch (ty.toIntern()) {
2273 .c_char_type => mod.getTarget().charSignedness() == .signed,
2274 .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true,
2275 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2276 .int_type => |int_type| int_type.signedness == .signed,
2277 else => false,
2278 },
2279 };
2280}
2281
2282/// Returns true if and only if the type is a fixed-width, unsigned integer.
2283pub fn isUnsignedInt(ty: Type, mod: *const Module) bool {
2284 return switch (ty.toIntern()) {
2285 .c_char_type => mod.getTarget().charSignedness() == .unsigned,
2286 .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true,
2287 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2288 .int_type => |int_type| int_type.signedness == .unsigned,
2289 else => false,
2290 },
2291 };
2292}
2293
2294/// Returns true for integers, enums, error sets, and packed structs.
2295/// If this function returns true, then intInfo() can be called on the type.
2296pub fn isAbiInt(ty: Type, mod: *Module) bool {
2297 return switch (ty.zigTypeTag(mod)) {
2298 .Int, .Enum, .ErrorSet => true,
2299 .Struct => ty.containerLayout(mod) == .@"packed",
2300 else => false,
2301 };
2302}
2303
2304/// Asserts the type is an integer, enum, error set, or vector of one of them.
2305pub fn intInfo(starting_ty: Type, mod: *Module) InternPool.Key.IntType {
2306 const ip = &mod.intern_pool;
2307 const target = mod.getTarget();
2308 var ty = starting_ty;
2309
2310 while (true) switch (ty.toIntern()) {
2311 .anyerror_type, .adhoc_inferred_error_set_type => {
2312 return .{ .signedness = .unsigned, .bits = mod.errorSetBits() };
2313 },
2314 .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() },
2315 .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() },
2316 .c_char_type => return .{ .signedness = mod.getTarget().charSignedness(), .bits = target.c_type_bit_size(.char) },
2317 .c_short_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.short) },
2318 .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ushort) },
2319 .c_int_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.int) },
2320 .c_uint_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.uint) },
2321 .c_long_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.long) },
2322 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulong) },
2323 .c_longlong_type => return .{ .signedness = .signed, .bits = target.c_type_bit_size(.longlong) },
2324 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.c_type_bit_size(.ulonglong) },
2325 else => switch (ip.indexToKey(ty.toIntern())) {
2326 .int_type => |int_type| return int_type,
2327 .struct_type => ty = Type.fromInterned(ip.loadStructType(ty.toIntern()).backingIntType(ip).*),
2328 .enum_type => ty = Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
2329 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child),
2330
2331 .error_set_type, .inferred_error_set_type => {
2332 return .{ .signedness = .unsigned, .bits = mod.errorSetBits() };
2333 },
2334
2335 .anon_struct_type => unreachable,
2336
2337 .ptr_type => unreachable,
2338 .anyframe_type => unreachable,
2339 .array_type => unreachable,
2340
2341 .opt_type => unreachable,
2342 .error_union_type => unreachable,
2343 .func_type => unreachable,
2344 .simple_type => unreachable, // handled via Index enum tag above
2345
2346 .union_type => unreachable,
2347 .opaque_type => unreachable,
2348
2349 // values, not types
2350 .undef,
2351 .simple_value,
2352 .variable,
2353 .extern_func,
2354 .func,
2355 .int,
2356 .err,
2357 .error_union,
2358 .enum_literal,
2359 .enum_tag,
2360 .empty_enum_value,
2361 .float,
2362 .ptr,
2363 .slice,
2364 .opt,
2365 .aggregate,
2366 .un,
2367 // memoization, not types
2368 .memoized_call,
2369 => unreachable,
2370 },
2371 };
2372}
2373
2374pub fn isNamedInt(ty: Type) bool {
2375 return switch (ty.toIntern()) {
2376 .usize_type,
2377 .isize_type,
2378 .c_char_type,
2379 .c_short_type,
2380 .c_ushort_type,
2381 .c_int_type,
2382 .c_uint_type,
2383 .c_long_type,
2384 .c_ulong_type,
2385 .c_longlong_type,
2386 .c_ulonglong_type,
2387 => true,
2388
2389 else => false,
2390 };
2391}
2392
2393/// Returns `false` for `comptime_float`.
2394pub fn isRuntimeFloat(ty: Type) bool {
2395 return switch (ty.toIntern()) {
2396 .f16_type,
2397 .f32_type,
2398 .f64_type,
2399 .f80_type,
2400 .f128_type,
2401 .c_longdouble_type,
2402 => true,
2403
2404 else => false,
2405 };
2406}
2407
2408/// Returns `true` for `comptime_float`.
2409pub fn isAnyFloat(ty: Type) bool {
2410 return switch (ty.toIntern()) {
2411 .f16_type,
2412 .f32_type,
2413 .f64_type,
2414 .f80_type,
2415 .f128_type,
2416 .c_longdouble_type,
2417 .comptime_float_type,
2418 => true,
2419
2420 else => false,
2421 };
2422}
2423
2424/// Asserts the type is a fixed-size float or comptime_float.
2425/// Returns 128 for comptime_float types.
2426pub fn floatBits(ty: Type, target: Target) u16 {
2427 return switch (ty.toIntern()) {
2428 .f16_type => 16,
2429 .f32_type => 32,
2430 .f64_type => 64,
2431 .f80_type => 80,
2432 .f128_type, .comptime_float_type => 128,
2433 .c_longdouble_type => target.c_type_bit_size(.longdouble),
2434
2435 else => unreachable,
2436 };
2437}
2438
2439/// Asserts the type is a function or a function pointer.
2440pub fn fnReturnType(ty: Type, mod: *Module) Type {
2441 return Type.fromInterned(mod.intern_pool.funcTypeReturnType(ty.toIntern()));
2442}
2443
2444/// Asserts the type is a function.
2445pub fn fnCallingConvention(ty: Type, mod: *Module) std.builtin.CallingConvention {
2446 return mod.intern_pool.indexToKey(ty.toIntern()).func_type.cc;
2447}
2448
2449pub fn isValidParamType(self: Type, mod: *const Module) bool {
2450 return switch (self.zigTypeTagOrPoison(mod) catch return true) {
2451 .Opaque, .NoReturn => false,
2452 else => true,
2453 };
2454}
2455
2456pub fn isValidReturnType(self: Type, mod: *const Module) bool {
2457 return switch (self.zigTypeTagOrPoison(mod) catch return true) {
2458 .Opaque => false,
2459 else => true,
2460 };
2461}
2462
2463/// Asserts the type is a function.
2464pub fn fnIsVarArgs(ty: Type, mod: *Module) bool {
2465 return mod.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args;
2466}
2467
2468pub fn isNumeric(ty: Type, mod: *const Module) bool {
2469 return switch (ty.toIntern()) {
2470 .f16_type,
2471 .f32_type,
2472 .f64_type,
2473 .f80_type,
2474 .f128_type,
2475 .c_longdouble_type,
2476 .comptime_int_type,
2477 .comptime_float_type,
2478 .usize_type,
2479 .isize_type,
2480 .c_char_type,
2481 .c_short_type,
2482 .c_ushort_type,
2483 .c_int_type,
2484 .c_uint_type,
2485 .c_long_type,
2486 .c_ulong_type,
2487 .c_longlong_type,
2488 .c_ulonglong_type,
2489 => true,
2490
2491 else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
2492 .int_type => true,
2493 else => false,
2494 },
2495 };
2496}
2497
2498/// During semantic analysis, instead call `Sema.typeHasOnePossibleValue` which
2499/// resolves field types rather than asserting they are already resolved.
2500pub fn onePossibleValue(starting_type: Type, mod: *Module) !?Value {
2501 var ty = starting_type;
2502 const ip = &mod.intern_pool;
2503 while (true) switch (ty.toIntern()) {
2504 .empty_struct_type => return Value.empty_struct,
2505
2506 else => switch (ip.indexToKey(ty.toIntern())) {
2507 .int_type => |int_type| {
2508 if (int_type.bits == 0) {
2509 return try mod.intValue(ty, 0);
2510 } else {
2511 return null;
2512 }
2513 },
2514
2515 .ptr_type,
2516 .error_union_type,
2517 .func_type,
2518 .anyframe_type,
2519 .error_set_type,
2520 .inferred_error_set_type,
2521 => return null,
2522
2523 inline .array_type, .vector_type => |seq_type, seq_tag| {
2524 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
2525 if (seq_type.len + @intFromBool(has_sentinel) == 0) return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2526 .ty = ty.toIntern(),
2527 .storage = .{ .elems = &.{} },
2528 } })));
2529 if (try Type.fromInterned(seq_type.child).onePossibleValue(mod)) |opv| {
2530 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2531 .ty = ty.toIntern(),
2532 .storage = .{ .repeated_elem = opv.toIntern() },
2533 } })));
2534 }
2535 return null;
2536 },
2537 .opt_type => |child| {
2538 if (child == .noreturn_type) {
2539 return try mod.nullValue(ty);
2540 } else {
2541 return null;
2542 }
2543 },
2544
2545 .simple_type => |t| switch (t) {
2546 .f16,
2547 .f32,
2548 .f64,
2549 .f80,
2550 .f128,
2551 .usize,
2552 .isize,
2553 .c_char,
2554 .c_short,
2555 .c_ushort,
2556 .c_int,
2557 .c_uint,
2558 .c_long,
2559 .c_ulong,
2560 .c_longlong,
2561 .c_ulonglong,
2562 .c_longdouble,
2563 .anyopaque,
2564 .bool,
2565 .type,
2566 .anyerror,
2567 .comptime_int,
2568 .comptime_float,
2569 .enum_literal,
2570 .atomic_order,
2571 .atomic_rmw_op,
2572 .calling_convention,
2573 .address_space,
2574 .float_mode,
2575 .reduce_op,
2576 .call_modifier,
2577 .prefetch_options,
2578 .export_options,
2579 .extern_options,
2580 .type_info,
2581 .adhoc_inferred_error_set,
2582 => return null,
2583
2584 .void => return Value.void,
2585 .noreturn => return Value.@"unreachable",
2586 .null => return Value.null,
2587 .undefined => return Value.undef,
2588
2589 .generic_poison => unreachable,
2590 },
2591 .struct_type => {
2592 const struct_type = ip.loadStructType(ty.toIntern());
2593 assert(struct_type.haveFieldTypes(ip));
2594 if (struct_type.knownNonOpv(ip))
2595 return null;
2596 const field_vals = try mod.gpa.alloc(InternPool.Index, struct_type.field_types.len);
2597 defer mod.gpa.free(field_vals);
2598 for (field_vals, 0..) |*field_val, i_usize| {
2599 const i: u32 = @intCast(i_usize);
2600 if (struct_type.fieldIsComptime(ip, i)) {
2601 assert(struct_type.haveFieldInits(ip));
2602 field_val.* = struct_type.field_inits.get(ip)[i];
2603 continue;
2604 }
2605 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
2606 if (try field_ty.onePossibleValue(mod)) |field_opv| {
2607 field_val.* = field_opv.toIntern();
2608 } else return null;
2609 }
2610
2611 // In this case the struct has no runtime-known fields and
2612 // therefore has one possible value.
2613 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2614 .ty = ty.toIntern(),
2615 .storage = .{ .elems = field_vals },
2616 } })));
2617 },
2618
2619 .anon_struct_type => |tuple| {
2620 for (tuple.values.get(ip)) |val| {
2621 if (val == .none) return null;
2622 }
2623 // In this case the struct has all comptime-known fields and
2624 // therefore has one possible value.
2625 // TODO: write something like getCoercedInts to avoid needing to dupe
2626 const duped_values = try mod.gpa.dupe(InternPool.Index, tuple.values.get(ip));
2627 defer mod.gpa.free(duped_values);
2628 return Value.fromInterned((try mod.intern(.{ .aggregate = .{
2629 .ty = ty.toIntern(),
2630 .storage = .{ .elems = duped_values },
2631 } })));
2632 },
2633
2634 .union_type => {
2635 const union_obj = ip.loadUnionType(ty.toIntern());
2636 const tag_val = (try Type.fromInterned(union_obj.enum_tag_ty).onePossibleValue(mod)) orelse
2637 return null;
2638 if (union_obj.field_types.len == 0) {
2639 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2640 return Value.fromInterned(only);
2641 }
2642 const only_field_ty = union_obj.field_types.get(ip)[0];
2643 const val_val = (try Type.fromInterned(only_field_ty).onePossibleValue(mod)) orelse
2644 return null;
2645 const only = try mod.intern(.{ .un = .{
2646 .ty = ty.toIntern(),
2647 .tag = tag_val.toIntern(),
2648 .val = val_val.toIntern(),
2649 } });
2650 return Value.fromInterned(only);
2651 },
2652 .opaque_type => return null,
2653 .enum_type => {
2654 const enum_type = ip.loadEnumType(ty.toIntern());
2655 switch (enum_type.tag_mode) {
2656 .nonexhaustive => {
2657 if (enum_type.tag_ty == .comptime_int_type) return null;
2658
2659 if (try Type.fromInterned(enum_type.tag_ty).onePossibleValue(mod)) |int_opv| {
2660 const only = try mod.intern(.{ .enum_tag = .{
2661 .ty = ty.toIntern(),
2662 .int = int_opv.toIntern(),
2663 } });
2664 return Value.fromInterned(only);
2665 }
2666
2667 return null;
2668 },
2669 .auto, .explicit => {
2670 if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
2671
2672 switch (enum_type.names.len) {
2673 0 => {
2674 const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
2675 return Value.fromInterned(only);
2676 },
2677 1 => {
2678 if (enum_type.values.len == 0) {
2679 const only = try mod.intern(.{ .enum_tag = .{
2680 .ty = ty.toIntern(),
2681 .int = try mod.intern(.{ .int = .{
2682 .ty = enum_type.tag_ty,
2683 .storage = .{ .u64 = 0 },
2684 } }),
2685 } });
2686 return Value.fromInterned(only);
2687 } else {
2688 return Value.fromInterned(enum_type.values.get(ip)[0]);
2689 }
2690 },
2691 else => return null,
2692 }
2693 },
2694 }
2695 },
2696
2697 // values, not types
2698 .undef,
2699 .simple_value,
2700 .variable,
2701 .extern_func,
2702 .func,
2703 .int,
2704 .err,
2705 .error_union,
2706 .enum_literal,
2707 .enum_tag,
2708 .empty_enum_value,
2709 .float,
2710 .ptr,
2711 .slice,
2712 .opt,
2713 .aggregate,
2714 .un,
2715 // memoization, not types
2716 .memoized_call,
2717 => unreachable,
2718 },
2719 };
2720}
2721
2722/// During semantic analysis, instead call `Sema.typeRequiresComptime` which
2723/// resolves field types rather than asserting they are already resolved.
2724pub fn comptimeOnly(ty: Type, mod: *Module) bool {
2725 return ty.comptimeOnlyAdvanced(mod, null) catch unreachable;
2726}
2727
2728/// `generic_poison` will return false.
2729/// May return false negatives when structs and unions are having their field types resolved.
2730/// If `opt_sema` is not provided, asserts that the type is sufficiently resolved.
2731pub fn comptimeOnlyAdvanced(ty: Type, mod: *Module, opt_sema: ?*Sema) Module.CompileError!bool {
2732 const ip = &mod.intern_pool;
2733 return switch (ty.toIntern()) {
2734 .empty_struct_type => false,
2735
2736 else => switch (ip.indexToKey(ty.toIntern())) {
2737 .int_type => false,
2738 .ptr_type => |ptr_type| {
2739 const child_ty = Type.fromInterned(ptr_type.child);
2740 switch (child_ty.zigTypeTag(mod)) {
2741 .Fn => return !try child_ty.fnHasRuntimeBitsAdvanced(mod, opt_sema),
2742 .Opaque => return false,
2743 else => return child_ty.comptimeOnlyAdvanced(mod, opt_sema),
2744 }
2745 },
2746 .anyframe_type => |child| {
2747 if (child == .none) return false;
2748 return Type.fromInterned(child).comptimeOnlyAdvanced(mod, opt_sema);
2749 },
2750 .array_type => |array_type| return Type.fromInterned(array_type.child).comptimeOnlyAdvanced(mod, opt_sema),
2751 .vector_type => |vector_type| return Type.fromInterned(vector_type.child).comptimeOnlyAdvanced(mod, opt_sema),
2752 .opt_type => |child| return Type.fromInterned(child).comptimeOnlyAdvanced(mod, opt_sema),
2753 .error_union_type => |error_union_type| return Type.fromInterned(error_union_type.payload_type).comptimeOnlyAdvanced(mod, opt_sema),
2754
2755 .error_set_type,
2756 .inferred_error_set_type,
2757 => false,
2758
2759 // These are function bodies, not function pointers.
2760 .func_type => true,
2761
2762 .simple_type => |t| switch (t) {
2763 .f16,
2764 .f32,
2765 .f64,
2766 .f80,
2767 .f128,
2768 .usize,
2769 .isize,
2770 .c_char,
2771 .c_short,
2772 .c_ushort,
2773 .c_int,
2774 .c_uint,
2775 .c_long,
2776 .c_ulong,
2777 .c_longlong,
2778 .c_ulonglong,
2779 .c_longdouble,
2780 .anyopaque,
2781 .bool,
2782 .void,
2783 .anyerror,
2784 .adhoc_inferred_error_set,
2785 .noreturn,
2786 .generic_poison,
2787 .atomic_order,
2788 .atomic_rmw_op,
2789 .calling_convention,
2790 .address_space,
2791 .float_mode,
2792 .reduce_op,
2793 .call_modifier,
2794 .prefetch_options,
2795 .export_options,
2796 .extern_options,
2797 => false,
2798
2799 .type,
2800 .comptime_int,
2801 .comptime_float,
2802 .null,
2803 .undefined,
2804 .enum_literal,
2805 .type_info,
2806 => true,
2807 },
2808 .struct_type => {
2809 const struct_type = ip.loadStructType(ty.toIntern());
2810 // packed structs cannot be comptime-only because they have a well-defined
2811 // memory layout and every field has a well-defined bit pattern.
2812 if (struct_type.layout == .@"packed")
2813 return false;
2814
2815 // A struct with no fields is not comptime-only.
2816 return switch (struct_type.flagsPtr(ip).requires_comptime) {
2817 .no, .wip => false,
2818 .yes => true,
2819 .unknown => {
2820 // The type is not resolved; assert that we have a Sema.
2821 const sema = opt_sema.?;
2822
2823 if (struct_type.flagsPtr(ip).field_types_wip)
2824 return false;
2825
2826 struct_type.flagsPtr(ip).requires_comptime = .wip;
2827 errdefer struct_type.flagsPtr(ip).requires_comptime = .unknown;
2828
2829 try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
2830
2831 for (0..struct_type.field_types.len) |i_usize| {
2832 const i: u32 = @intCast(i_usize);
2833 if (struct_type.fieldIsComptime(ip, i)) continue;
2834 const field_ty = struct_type.field_types.get(ip)[i];
2835 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2836 // Note that this does not cause the layout to
2837 // be considered resolved. Comptime-only types
2838 // still maintain a layout of their
2839 // runtime-known fields.
2840 struct_type.flagsPtr(ip).requires_comptime = .yes;
2841 return true;
2842 }
2843 }
2844
2845 struct_type.flagsPtr(ip).requires_comptime = .no;
2846 return false;
2847 },
2848 };
2849 },
2850
2851 .anon_struct_type => |tuple| {
2852 for (tuple.types.get(ip), tuple.values.get(ip)) |field_ty, val| {
2853 const have_comptime_val = val != .none;
2854 if (!have_comptime_val and try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) return true;
2855 }
2856 return false;
2857 },
2858
2859 .union_type => {
2860 const union_type = ip.loadUnionType(ty.toIntern());
2861 switch (union_type.flagsPtr(ip).requires_comptime) {
2862 .no, .wip => return false,
2863 .yes => return true,
2864 .unknown => {
2865 // The type is not resolved; assert that we have a Sema.
2866 const sema = opt_sema.?;
2867
2868 if (union_type.flagsPtr(ip).status == .field_types_wip)
2869 return false;
2870
2871 union_type.flagsPtr(ip).requires_comptime = .wip;
2872 errdefer union_type.flagsPtr(ip).requires_comptime = .unknown;
2873
2874 try sema.resolveTypeFieldsUnion(ty, union_type);
2875
2876 for (0..union_type.field_types.len) |field_idx| {
2877 const field_ty = union_type.field_types.get(ip)[field_idx];
2878 if (try Type.fromInterned(field_ty).comptimeOnlyAdvanced(mod, opt_sema)) {
2879 union_type.flagsPtr(ip).requires_comptime = .yes;
2880 return true;
2881 }
2882 }
2883
2884 union_type.flagsPtr(ip).requires_comptime = .no;
2885 return false;
2886 },
2887 }
2888 },
2889
2890 .opaque_type => false,
2891
2892 .enum_type => return Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty).comptimeOnlyAdvanced(mod, opt_sema),
2893
2894 // values, not types
2895 .undef,
2896 .simple_value,
2897 .variable,
2898 .extern_func,
2899 .func,
2900 .int,
2901 .err,
2902 .error_union,
2903 .enum_literal,
2904 .enum_tag,
2905 .empty_enum_value,
2906 .float,
2907 .ptr,
2908 .slice,
2909 .opt,
2910 .aggregate,
2911 .un,
2912 // memoization, not types
2913 .memoized_call,
2914 => unreachable,
2915 },
2916 };
2917}
2918
2919pub fn isVector(ty: Type, mod: *const Module) bool {
2920 return ty.zigTypeTag(mod) == .Vector;
2921}
2922
2923/// Returns 0 if not a vector, otherwise returns @bitSizeOf(Element) * vector_len.
2924pub fn totalVectorBits(ty: Type, zcu: *Zcu) u64 {
2925 if (!ty.isVector(zcu)) return 0;
2926 const v = zcu.intern_pool.indexToKey(ty.toIntern()).vector_type;
2927 return v.len * Type.fromInterned(v.child).bitSize(zcu);
2928}
2929
2930pub fn isArrayOrVector(ty: Type, mod: *const Module) bool {
2931 return switch (ty.zigTypeTag(mod)) {
2932 .Array, .Vector => true,
2933 else => false,
2934 };
2935}
2936
2937pub fn isIndexable(ty: Type, mod: *Module) bool {
2938 return switch (ty.zigTypeTag(mod)) {
2939 .Array, .Vector => true,
2940 .Pointer => switch (ty.ptrSize(mod)) {
2941 .Slice, .Many, .C => true,
2942 .One => switch (ty.childType(mod).zigTypeTag(mod)) {
2943 .Array, .Vector => true,
2944 .Struct => ty.childType(mod).isTuple(mod),
2945 else => false,
2946 },
2947 },
2948 .Struct => ty.isTuple(mod),
2949 else => false,
2950 };
2951}
2952
2953pub fn indexableHasLen(ty: Type, mod: *Module) bool {
2954 return switch (ty.zigTypeTag(mod)) {
2955 .Array, .Vector => true,
2956 .Pointer => switch (ty.ptrSize(mod)) {
2957 .Many, .C => false,
2958 .Slice => true,
2959 .One => switch (ty.childType(mod).zigTypeTag(mod)) {
2960 .Array, .Vector => true,
2961 .Struct => ty.childType(mod).isTuple(mod),
2962 else => false,
2963 },
2964 },
2965 .Struct => ty.isTuple(mod),
2966 else => false,
2967 };
2968}
2969
2970/// Asserts that the type can have a namespace.
2971pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex {
2972 return ty.getNamespace(zcu).?;
2973}
2974
2975/// Returns null if the type has no namespace.
2976pub fn getNamespace(ty: Type, zcu: *Zcu) ?InternPool.OptionalNamespaceIndex {
2977 const ip = &zcu.intern_pool;
2978 return switch (ip.indexToKey(ty.toIntern())) {
2979 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace,
2980 .struct_type => ip.loadStructType(ty.toIntern()).namespace,
2981 .union_type => ip.loadUnionType(ty.toIntern()).namespace,
2982 .enum_type => ip.loadEnumType(ty.toIntern()).namespace,
2983
2984 .anon_struct_type => .none,
2985 .simple_type => |s| switch (s) {
2986 .anyopaque,
2987 .atomic_order,
2988 .atomic_rmw_op,
2989 .calling_convention,
2990 .address_space,
2991 .float_mode,
2992 .reduce_op,
2993 .call_modifier,
2994 .prefetch_options,
2995 .export_options,
2996 .extern_options,
2997 .type_info,
2998 => .none,
2999 else => null,
3000 },
3001
3002 else => null,
3003 };
3004}
3005
3006// Works for vectors and vectors of integers.
3007pub fn minInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
3008 const scalar = try minIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
3009 return if (ty.zigTypeTag(mod) == .Vector) Value.fromInterned((try mod.intern(.{ .aggregate = .{
3010 .ty = dest_ty.toIntern(),
3011 .storage = .{ .repeated_elem = scalar.toIntern() },
3012 } }))) else scalar;
3013}
3014
3015/// Asserts that the type is an integer.
3016pub fn minIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
3017 const info = ty.intInfo(mod);
3018 if (info.signedness == .unsigned) return mod.intValue(dest_ty, 0);
3019 if (info.bits == 0) return mod.intValue(dest_ty, -1);
3020
3021 if (std.math.cast(u6, info.bits - 1)) |shift| {
3022 const n = @as(i64, std.math.minInt(i64)) >> (63 - shift);
3023 return mod.intValue(dest_ty, n);
3024 }
3025
3026 var res = try std.math.big.int.Managed.init(mod.gpa);
3027 defer res.deinit();
3028
3029 try res.setTwosCompIntLimit(.min, info.signedness, info.bits);
3030
3031 return mod.intValue_big(dest_ty, res.toConst());
3032}
3033
3034// Works for vectors and vectors of integers.
3035/// The returned Value will have type dest_ty.
3036pub fn maxInt(ty: Type, mod: *Module, dest_ty: Type) !Value {
3037 const scalar = try maxIntScalar(ty.scalarType(mod), mod, dest_ty.scalarType(mod));
3038 return if (ty.zigTypeTag(mod) == .Vector) Value.fromInterned((try mod.intern(.{ .aggregate = .{
3039 .ty = dest_ty.toIntern(),
3040 .storage = .{ .repeated_elem = scalar.toIntern() },
3041 } }))) else scalar;
3042}
3043
3044/// The returned Value will have type dest_ty.
3045pub fn maxIntScalar(ty: Type, mod: *Module, dest_ty: Type) !Value {
3046 const info = ty.intInfo(mod);
3047
3048 switch (info.bits) {
3049 0 => return switch (info.signedness) {
3050 .signed => try mod.intValue(dest_ty, -1),
3051 .unsigned => try mod.intValue(dest_ty, 0),
3052 },
3053 1 => return switch (info.signedness) {
3054 .signed => try mod.intValue(dest_ty, 0),
3055 .unsigned => try mod.intValue(dest_ty, 1),
3056 },
3057 else => {},
3058 }
3059
3060 if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) {
3061 .signed => {
3062 const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift);
3063 return mod.intValue(dest_ty, n);
3064 },
3065 .unsigned => {
3066 const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift);
3067 return mod.intValue(dest_ty, n);
3068 },
3069 };
3070
3071 var res = try std.math.big.int.Managed.init(mod.gpa);
3072 defer res.deinit();
3073
3074 try res.setTwosCompIntLimit(.max, info.signedness, info.bits);
3075
3076 return mod.intValue_big(dest_ty, res.toConst());
3077}
3078
3079/// Asserts the type is an enum or a union.
3080pub fn intTagType(ty: Type, mod: *Module) Type {
3081 const ip = &mod.intern_pool;
3082 return switch (ip.indexToKey(ty.toIntern())) {
3083 .union_type => Type.fromInterned(ip.loadUnionType(ty.toIntern()).enum_tag_ty).intTagType(mod),
3084 .enum_type => Type.fromInterned(ip.loadEnumType(ty.toIntern()).tag_ty),
3085 else => unreachable,
3086 };
3087}
3088
3089pub fn isNonexhaustiveEnum(ty: Type, mod: *Module) bool {
3090 const ip = &mod.intern_pool;
3091 return switch (ip.indexToKey(ty.toIntern())) {
3092 .enum_type => switch (ip.loadEnumType(ty.toIntern()).tag_mode) {
3093 .nonexhaustive => true,
3094 .auto, .explicit => false,
3095 },
3096 else => false,
3097 };
3098}
3099
3100// Asserts that `ty` is an error set and not `anyerror`.
3101// Asserts that `ty` is resolved if it is an inferred error set.
3102pub fn errorSetNames(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
3103 const ip = &mod.intern_pool;
3104 return switch (ip.indexToKey(ty.toIntern())) {
3105 .error_set_type => |x| x.names,
3106 .inferred_error_set_type => |i| switch (ip.funcIesResolved(i).*) {
3107 .none => unreachable, // unresolved inferred error set
3108 .anyerror_type => unreachable,
3109 else => |t| ip.indexToKey(t).error_set_type.names,
3110 },
3111 else => unreachable,
3112 };
3113}
3114
3115pub fn enumFields(ty: Type, mod: *Module) InternPool.NullTerminatedString.Slice {
3116 return mod.intern_pool.loadEnumType(ty.toIntern()).names;
3117}
3118
3119pub fn enumFieldCount(ty: Type, mod: *Module) usize {
3120 return mod.intern_pool.loadEnumType(ty.toIntern()).names.len;
3121}
3122
3123pub fn enumFieldName(ty: Type, field_index: usize, mod: *Module) InternPool.NullTerminatedString {
3124 const ip = &mod.intern_pool;
3125 return ip.loadEnumType(ty.toIntern()).names.get(ip)[field_index];
3126}
3127
3128pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, mod: *Module) ?u32 {
3129 const ip = &mod.intern_pool;
3130 const enum_type = ip.loadEnumType(ty.toIntern());
3131 return enum_type.nameIndex(ip, field_name);
3132}
3133
3134/// Asserts `ty` is an enum. `enum_tag` can either be `enum_field_index` or
3135/// an integer which represents the enum value. Returns the field index in
3136/// declaration order, or `null` if `enum_tag` does not match any field.
3137pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, mod: *Module) ?u32 {
3138 const ip = &mod.intern_pool;
3139 const enum_type = ip.loadEnumType(ty.toIntern());
3140 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) {
3141 .int => enum_tag.toIntern(),
3142 .enum_tag => |info| info.int,
3143 else => unreachable,
3144 };
3145 assert(ip.typeOf(int_tag) == enum_type.tag_ty);
3146 return enum_type.tagValueIndex(ip, int_tag);
3147}
3148
3149/// Returns none in the case of a tuple which uses the integer index as the field name.
3150pub fn structFieldName(ty: Type, index: usize, mod: *Module) InternPool.OptionalNullTerminatedString {
3151 const ip = &mod.intern_pool;
3152 return switch (ip.indexToKey(ty.toIntern())) {
3153 .struct_type => ip.loadStructType(ty.toIntern()).fieldName(ip, index),
3154 .anon_struct_type => |anon_struct| anon_struct.fieldName(ip, index),
3155 else => unreachable,
3156 };
3157}
3158
3159pub fn structFieldCount(ty: Type, mod: *Module) u32 {
3160 const ip = &mod.intern_pool;
3161 return switch (ip.indexToKey(ty.toIntern())) {
3162 .struct_type => ip.loadStructType(ty.toIntern()).field_types.len,
3163 .anon_struct_type => |anon_struct| anon_struct.types.len,
3164 else => unreachable,
3165 };
3166}
3167
3168/// Supports structs and unions.
3169pub fn structFieldType(ty: Type, index: usize, mod: *Module) Type {
3170 const ip = &mod.intern_pool;
3171 return switch (ip.indexToKey(ty.toIntern())) {
3172 .struct_type => Type.fromInterned(ip.loadStructType(ty.toIntern()).field_types.get(ip)[index]),
3173 .union_type => {
3174 const union_obj = ip.loadUnionType(ty.toIntern());
3175 return Type.fromInterned(union_obj.field_types.get(ip)[index]);
3176 },
3177 .anon_struct_type => |anon_struct| Type.fromInterned(anon_struct.types.get(ip)[index]),
3178 else => unreachable,
3179 };
3180}
3181
3182pub fn structFieldAlign(ty: Type, index: usize, zcu: *Zcu) Alignment {
3183 return ty.structFieldAlignAdvanced(index, zcu, null) catch unreachable;
3184}
3185
3186pub fn structFieldAlignAdvanced(ty: Type, index: usize, zcu: *Zcu, opt_sema: ?*Sema) !Alignment {
3187 const ip = &zcu.intern_pool;
3188 switch (ip.indexToKey(ty.toIntern())) {
3189 .struct_type => {
3190 const struct_type = ip.loadStructType(ty.toIntern());
3191 assert(struct_type.layout != .@"packed");
3192 const explicit_align = struct_type.fieldAlign(ip, index);
3193 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
3194 if (opt_sema) |sema| {
3195 return sema.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3196 } else {
3197 return zcu.structFieldAlignment(explicit_align, field_ty, struct_type.layout);
3198 }
3199 },
3200 .anon_struct_type => |anon_struct| {
3201 return (try Type.fromInterned(anon_struct.types.get(ip)[index]).abiAlignmentAdvanced(zcu, if (opt_sema) |sema| .{ .sema = sema } else .eager)).scalar;
3202 },
3203 .union_type => {
3204 const union_obj = ip.loadUnionType(ty.toIntern());
3205 if (opt_sema) |sema| {
3206 return sema.unionFieldAlignment(union_obj, @intCast(index));
3207 } else {
3208 return zcu.unionFieldNormalAlignment(union_obj, @intCast(index));
3209 }
3210 },
3211 else => unreachable,
3212 }
3213}
3214
3215pub fn structFieldDefaultValue(ty: Type, index: usize, mod: *Module) Value {
3216 const ip = &mod.intern_pool;
3217 switch (ip.indexToKey(ty.toIntern())) {
3218 .struct_type => {
3219 const struct_type = ip.loadStructType(ty.toIntern());
3220 const val = struct_type.fieldInit(ip, index);
3221 // TODO: avoid using `unreachable` to indicate this.
3222 if (val == .none) return Value.@"unreachable";
3223 return Value.fromInterned(val);
3224 },
3225 .anon_struct_type => |anon_struct| {
3226 const val = anon_struct.values.get(ip)[index];
3227 // TODO: avoid using `unreachable` to indicate this.
3228 if (val == .none) return Value.@"unreachable";
3229 return Value.fromInterned(val);
3230 },
3231 else => unreachable,
3232 }
3233}
3234
3235pub fn structFieldValueComptime(ty: Type, mod: *Module, index: usize) !?Value {
3236 const ip = &mod.intern_pool;
3237 switch (ip.indexToKey(ty.toIntern())) {
3238 .struct_type => {
3239 const struct_type = ip.loadStructType(ty.toIntern());
3240 if (struct_type.fieldIsComptime(ip, index)) {
3241 assert(struct_type.haveFieldInits(ip));
3242 return Value.fromInterned(struct_type.field_inits.get(ip)[index]);
3243 } else {
3244 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(mod);
3245 }
3246 },
3247 .anon_struct_type => |tuple| {
3248 const val = tuple.values.get(ip)[index];
3249 if (val == .none) {
3250 return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(mod);
3251 } else {
3252 return Value.fromInterned(val);
3253 }
3254 },
3255 else => unreachable,
3256 }
3257}
3258
3259pub fn structFieldIsComptime(ty: Type, index: usize, mod: *Module) bool {
3260 const ip = &mod.intern_pool;
3261 return switch (ip.indexToKey(ty.toIntern())) {
3262 .struct_type => ip.loadStructType(ty.toIntern()).fieldIsComptime(ip, index),
3263 .anon_struct_type => |anon_struct| anon_struct.values.get(ip)[index] != .none,
3264 else => unreachable,
3265 };
3266}
3267
3268pub const FieldOffset = struct {
3269 field: usize,
3270 offset: u64,
3271};
3272
3273/// Supports structs and unions.
3274pub fn structFieldOffset(ty: Type, index: usize, mod: *Module) u64 {
3275 const ip = &mod.intern_pool;
3276 switch (ip.indexToKey(ty.toIntern())) {
3277 .struct_type => {
3278 const struct_type = ip.loadStructType(ty.toIntern());
3279 assert(struct_type.haveLayout(ip));
3280 assert(struct_type.layout != .@"packed");
3281 return struct_type.offsets.get(ip)[index];
3282 },
3283
3284 .anon_struct_type => |tuple| {
3285 var offset: u64 = 0;
3286 var big_align: Alignment = .none;
3287
3288 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| {
3289 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(mod)) {
3290 // comptime field
3291 if (i == index) return offset;
3292 continue;
3293 }
3294
3295 const field_align = Type.fromInterned(field_ty).abiAlignment(mod);
3296 big_align = big_align.max(field_align);
3297 offset = field_align.forward(offset);
3298 if (i == index) return offset;
3299 offset += Type.fromInterned(field_ty).abiSize(mod);
3300 }
3301 offset = big_align.max(.@"1").forward(offset);
3302 return offset;
3303 },
3304
3305 .union_type => {
3306 const union_type = ip.loadUnionType(ty.toIntern());
3307 if (!union_type.hasTag(ip))
3308 return 0;
3309 const layout = mod.getUnionLayout(union_type);
3310 if (layout.tag_align.compare(.gte, layout.payload_align)) {
3311 // {Tag, Payload}
3312 return layout.payload_align.forward(layout.tag_size);
3313 } else {
3314 // {Payload, Tag}
3315 return 0;
3316 }
3317 },
3318
3319 else => unreachable,
3320 }
3321}
3322
3323pub fn getOwnerDecl(ty: Type, mod: *Module) InternPool.DeclIndex {
3324 return ty.getOwnerDeclOrNull(mod) orelse unreachable;
3325}
3326
3327pub fn getOwnerDeclOrNull(ty: Type, mod: *Module) ?InternPool.DeclIndex {
3328 const ip = &mod.intern_pool;
3329 return switch (ip.indexToKey(ty.toIntern())) {
3330 .struct_type => ip.loadStructType(ty.toIntern()).decl.unwrap(),
3331 .union_type => ip.loadUnionType(ty.toIntern()).decl,
3332 .opaque_type => ip.loadOpaqueType(ty.toIntern()).decl,
3333 .enum_type => ip.loadEnumType(ty.toIntern()).decl,
3334 else => null,
3335 };
3336}
3337
3338pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Module.LazySrcLoc {
3339 const ip = &zcu.intern_pool;
3340 return .{
3341 .base_node_inst = switch (ip.indexToKey(ty.toIntern())) {
3342 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3343 .declared => |d| d.zir_index,
3344 .reified => |r| r.zir_index,
3345 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
3346 .empty_struct => return null,
3347 },
3348 else => return null,
3349 },
3350 .offset = Module.LazySrcLoc.Offset.nodeOffset(0),
3351 };
3352}
3353
3354pub fn srcLoc(ty: Type, zcu: *Zcu) Module.LazySrcLoc {
3355 return ty.srcLocOrNull(zcu).?;
3356}
3357
3358pub fn isGenericPoison(ty: Type) bool {
3359 return ty.toIntern() == .generic_poison_type;
3360}
3361
3362pub fn isTuple(ty: Type, mod: *Module) bool {
3363 const ip = &mod.intern_pool;
3364 return switch (ip.indexToKey(ty.toIntern())) {
3365 .struct_type => {
3366 const struct_type = ip.loadStructType(ty.toIntern());
3367 if (struct_type.layout == .@"packed") return false;
3368 if (struct_type.decl == .none) return false;
3369 return struct_type.flagsPtr(ip).is_tuple;
3370 },
3371 .anon_struct_type => |anon_struct| anon_struct.names.len == 0,
3372 else => false,
3373 };
3374}
3375
3376pub fn isAnonStruct(ty: Type, mod: *Module) bool {
3377 if (ty.toIntern() == .empty_struct_type) return true;
3378 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3379 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len > 0,
3380 else => false,
3381 };
3382}
3383
3384pub fn isTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3385 const ip = &mod.intern_pool;
3386 return switch (ip.indexToKey(ty.toIntern())) {
3387 .struct_type => {
3388 const struct_type = ip.loadStructType(ty.toIntern());
3389 if (struct_type.layout == .@"packed") return false;
3390 if (struct_type.decl == .none) return false;
3391 return struct_type.flagsPtr(ip).is_tuple;
3392 },
3393 .anon_struct_type => true,
3394 else => false,
3395 };
3396}
3397
3398pub fn isSimpleTuple(ty: Type, mod: *Module) bool {
3399 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3400 .anon_struct_type => |anon_struct_type| anon_struct_type.names.len == 0,
3401 else => false,
3402 };
3403}
3404
3405pub fn isSimpleTupleOrAnonStruct(ty: Type, mod: *Module) bool {
3406 return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
3407 .anon_struct_type => true,
3408 else => false,
3409 };
3410}
3411
3412/// Traverses optional child types and error union payloads until the type
3413/// is not a pointer. For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`.
3414pub fn optEuBaseType(ty: Type, mod: *Module) Type {
3415 var cur = ty;
3416 while (true) switch (cur.zigTypeTag(mod)) {
3417 .Optional => cur = cur.optionalChild(mod),
3418 .ErrorUnion => cur = cur.errorUnionPayload(mod),
3419 else => return cur,
3420 };
3421}
3422
3423pub fn toUnsigned(ty: Type, mod: *Module) !Type {
3424 return switch (ty.zigTypeTag(mod)) {
3425 .Int => mod.intType(.unsigned, ty.intInfo(mod).bits),
3426 .Vector => try mod.vectorType(.{
3427 .len = ty.vectorLen(mod),
3428 .child = (try ty.childType(mod).toUnsigned(mod)).toIntern(),
3429 }),
3430 else => unreachable,
3431 };
3432}
3433
3434pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index {
3435 const ip = &zcu.intern_pool;
3436 return switch (ip.indexToKey(ty.toIntern())) {
3437 .struct_type => ip.loadStructType(ty.toIntern()).zir_index.unwrap(),
3438 .union_type => ip.loadUnionType(ty.toIntern()).zir_index,
3439 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(),
3440 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index,
3441 else => null,
3442 };
3443}
3444
3445pub fn typeDeclSrcLine(ty: Type, zcu: *const Zcu) ?u32 {
3446 const ip = &zcu.intern_pool;
3447 const tracked = switch (ip.indexToKey(ty.toIntern())) {
3448 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) {
3449 .declared => |d| d.zir_index,
3450 .reified => |r| r.zir_index,
3451 .generated_tag => |gt| ip.loadUnionType(gt.union_type).zir_index,
3452 .empty_struct => return null,
3453 },
3454 else => return null,
3455 };
3456 const info = tracked.resolveFull(&zcu.intern_pool);
3457 const file = zcu.import_table.values()[zcu.path_digest_map.getIndex(info.path_digest).?];
3458 assert(file.zir_loaded);
3459 const zir = file.zir;
3460 const inst = zir.instructions.get(@intFromEnum(info.inst));
3461 assert(inst.tag == .extended);
3462 return switch (inst.data.extended.opcode) {
3463 .struct_decl => zir.extraData(Zir.Inst.StructDecl, inst.data.extended.operand).data.src_line,
3464 .union_decl => zir.extraData(Zir.Inst.UnionDecl, inst.data.extended.operand).data.src_line,
3465 .enum_decl => zir.extraData(Zir.Inst.EnumDecl, inst.data.extended.operand).data.src_line,
3466 .opaque_decl => zir.extraData(Zir.Inst.OpaqueDecl, inst.data.extended.operand).data.src_line,
3467 .reify => zir.extraData(Zir.Inst.Reify, inst.data.extended.operand).data.src_line,
3468 else => unreachable,
3469 };
3470}
3471
3472/// Given a namespace type, returns its list of caotured values.
3473pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice {
3474 const ip = &zcu.intern_pool;
3475 return switch (ip.indexToKey(ty.toIntern())) {
3476 .struct_type => ip.loadStructType(ty.toIntern()).captures,
3477 .union_type => ip.loadUnionType(ty.toIntern()).captures,
3478 .enum_type => ip.loadEnumType(ty.toIntern()).captures,
3479 .opaque_type => ip.loadOpaqueType(ty.toIntern()).captures,
3480 else => unreachable,
3481 };
3482}
3483
3484pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } {
3485 var cur_ty: Type = ty;
3486 var cur_len: u64 = 1;
3487 while (cur_ty.zigTypeTag(zcu) == .Array) {
3488 cur_len *= cur_ty.arrayLenIncludingSentinel(zcu);
3489 cur_ty = cur_ty.childType(zcu);
3490 }
3491 return .{ cur_ty, cur_len };
3492}
3493
3494pub fn packedStructFieldPtrInfo(struct_ty: Type, parent_ptr_ty: Type, field_idx: u32, zcu: *Zcu) union(enum) {
3495 /// The result is a bit-pointer with the same value and a new packed offset.
3496 bit_ptr: InternPool.Key.PtrType.PackedOffset,
3497 /// The result is a standard pointer.
3498 byte_ptr: struct {
3499 /// The byte offset of the field pointer from the parent pointer value.
3500 offset: u64,
3501 /// The alignment of the field pointer type.
3502 alignment: InternPool.Alignment,
3503 },
3504} {
3505 comptime assert(Type.packed_struct_layout_version == 2);
3506
3507 const parent_ptr_info = parent_ptr_ty.ptrInfo(zcu);
3508 const field_ty = struct_ty.structFieldType(field_idx, zcu);
3509
3510 var bit_offset: u16 = 0;
3511 var running_bits: u16 = 0;
3512 for (0..struct_ty.structFieldCount(zcu)) |i| {
3513 const f_ty = struct_ty.structFieldType(i, zcu);
3514 if (i == field_idx) {
3515 bit_offset = running_bits;
3516 }
3517 running_bits += @intCast(f_ty.bitSize(zcu));
3518 }
3519
3520 const res_host_size: u16, const res_bit_offset: u16 = if (parent_ptr_info.packed_offset.host_size != 0)
3521 .{ parent_ptr_info.packed_offset.host_size, parent_ptr_info.packed_offset.bit_offset + bit_offset }
3522 else
3523 .{ (running_bits + 7) / 8, bit_offset };
3524
3525 // If the field happens to be byte-aligned, simplify the pointer type.
3526 // We can only do this if the pointee's bit size matches its ABI byte size,
3527 // so that loads and stores do not interfere with surrounding packed bits.
3528 //
3529 // TODO: we do not attempt this with big-endian targets yet because of nested
3530 // structs and floats. I need to double-check the desired behavior for big endian
3531 // targets before adding the necessary complications to this code. This will not
3532 // cause miscompilations; it only means the field pointer uses bit masking when it
3533 // might not be strictly necessary.
3534 if (res_bit_offset % 8 == 0 and field_ty.bitSize(zcu) == field_ty.abiSize(zcu) * 8 and zcu.getTarget().cpu.arch.endian() == .little) {
3535 const byte_offset = res_bit_offset / 8;
3536 const new_align = Alignment.fromLog2Units(@ctz(byte_offset | parent_ptr_ty.ptrAlignment(zcu).toByteUnits().?));
3537 return .{ .byte_ptr = .{
3538 .offset = byte_offset,
3539 .alignment = new_align,
3540 } };
3541 }
3542
3543 return .{ .bit_ptr = .{
3544 .host_size = res_host_size,
3545 .bit_offset = res_bit_offset,
3546 } };
3547}
3548
3549pub const @"u1": Type = .{ .ip_index = .u1_type };
3550pub const @"u8": Type = .{ .ip_index = .u8_type };
3551pub const @"u16": Type = .{ .ip_index = .u16_type };
3552pub const @"u29": Type = .{ .ip_index = .u29_type };
3553pub const @"u32": Type = .{ .ip_index = .u32_type };
3554pub const @"u64": Type = .{ .ip_index = .u64_type };
3555pub const @"u128": Type = .{ .ip_index = .u128_type };
3556
3557pub const @"i8": Type = .{ .ip_index = .i8_type };
3558pub const @"i16": Type = .{ .ip_index = .i16_type };
3559pub const @"i32": Type = .{ .ip_index = .i32_type };
3560pub const @"i64": Type = .{ .ip_index = .i64_type };
3561pub const @"i128": Type = .{ .ip_index = .i128_type };
3562
3563pub const @"f16": Type = .{ .ip_index = .f16_type };
3564pub const @"f32": Type = .{ .ip_index = .f32_type };
3565pub const @"f64": Type = .{ .ip_index = .f64_type };
3566pub const @"f80": Type = .{ .ip_index = .f80_type };
3567pub const @"f128": Type = .{ .ip_index = .f128_type };
3568
3569pub const @"bool": Type = .{ .ip_index = .bool_type };
3570pub const @"usize": Type = .{ .ip_index = .usize_type };
3571pub const @"isize": Type = .{ .ip_index = .isize_type };
3572pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type };
3573pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type };
3574pub const @"void": Type = .{ .ip_index = .void_type };
3575pub const @"type": Type = .{ .ip_index = .type_type };
3576pub const @"anyerror": Type = .{ .ip_index = .anyerror_type };
3577pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type };
3578pub const @"anyframe": Type = .{ .ip_index = .anyframe_type };
3579pub const @"null": Type = .{ .ip_index = .null_type };
3580pub const @"undefined": Type = .{ .ip_index = .undefined_type };
3581pub const @"noreturn": Type = .{ .ip_index = .noreturn_type };
3582
3583pub const @"c_char": Type = .{ .ip_index = .c_char_type };
3584pub const @"c_short": Type = .{ .ip_index = .c_short_type };
3585pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type };
3586pub const @"c_int": Type = .{ .ip_index = .c_int_type };
3587pub const @"c_uint": Type = .{ .ip_index = .c_uint_type };
3588pub const @"c_long": Type = .{ .ip_index = .c_long_type };
3589pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type };
3590pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type };
3591pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type };
3592pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type };
3593
3594pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type };
3595pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type };
3596pub const single_const_pointer_to_comptime_int: Type = .{
3597 .ip_index = .single_const_pointer_to_comptime_int_type,
3598};
3599pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type };
3600pub const empty_struct_literal: Type = .{ .ip_index = .empty_struct_type };
3601
3602pub const generic_poison: Type = .{ .ip_index = .generic_poison_type };
3603
3604pub fn smallestUnsignedBits(max: u64) u16 {
3605 if (max == 0) return 0;
3606 const base = std.math.log2(max);
3607 const upper = (@as(u64, 1) << @as(u6, @intCast(base))) - 1;
3608 return @as(u16, @intCast(base + @intFromBool(upper < max)));
3609}
3610
3611/// This is only used for comptime asserts. Bump this number when you make a change
3612/// to packed struct layout to find out all the places in the codebase you need to edit!
3613pub const packed_struct_layout_version = 2;
3614
3615fn cTypeAlign(target: Target, c_type: Target.CType) Alignment {
3616 return Alignment.fromByteUnits(target.c_type_alignment(c_type));
3617}
src/Value.zig+1-1
...@@ -1,6 +1,6 @@...@@ -1,6 +1,6 @@
1const std = @import("std");1const std = @import("std");
2const builtin = @import("builtin");2const builtin = @import("builtin");
3const Type = @import("type.zig").Type;3const Type = @import("Type.zig");
4const assert = std.debug.assert;4const assert = std.debug.assert;
5const BigIntConst = std.math.big.int.Const;5const BigIntConst = std.math.big.int.Const;
6const BigIntMutable = std.math.big.int.Mutable;6const BigIntMutable = std.math.big.int.Mutable;
src/Zcu.zig+1-1
...@@ -20,7 +20,7 @@ const Zcu = @This();...@@ -20,7 +20,7 @@ const Zcu = @This();
20const Compilation = @import("Compilation.zig");20const Compilation = @import("Compilation.zig");
21const Cache = std.Build.Cache;21const Cache = std.Build.Cache;
22const Value = @import("Value.zig");22const Value = @import("Value.zig");
23const Type = @import("type.zig").Type;23const Type = @import("Type.zig");
24const Package = @import("Package.zig");24const Package = @import("Package.zig");
25const link = @import("link.zig");25const link = @import("link.zig");
26const Air = @import("Air.zig");26const Air = @import("Air.zig");
src/arch/aarch64/CodeGen.zig+1-1
...@@ -8,7 +8,7 @@ const Air = @import("../../Air.zig");...@@ -8,7 +8,7 @@ const Air = @import("../../Air.zig");
8const Mir = @import("Mir.zig");8const Mir = @import("Mir.zig");
9const Emit = @import("Emit.zig");9const Emit = @import("Emit.zig");
10const Liveness = @import("../../Liveness.zig");10const Liveness = @import("../../Liveness.zig");
11const Type = @import("../../type.zig").Type;11const Type = @import("../../Type.zig");
12const Value = @import("../../Value.zig");12const Value = @import("../../Value.zig");
13const link = @import("../../link.zig");13const link = @import("../../link.zig");
14const Zcu = @import("../../Zcu.zig");14const Zcu = @import("../../Zcu.zig");
src/arch/aarch64/abi.zig+1-1
...@@ -3,7 +3,7 @@ const builtin = @import("builtin");...@@ -3,7 +3,7 @@ const builtin = @import("builtin");
3const bits = @import("bits.zig");3const bits = @import("bits.zig");
4const Register = bits.Register;4const Register = bits.Register;
5const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;5const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
6const Type = @import("../../type.zig").Type;6const Type = @import("../../Type.zig");
7const Zcu = @import("../../Zcu.zig");7const Zcu = @import("../../Zcu.zig");
8/// Deprecated.8/// Deprecated.
9const Module = Zcu;9const Module = Zcu;
src/arch/arm/CodeGen.zig+1-1
...@@ -8,7 +8,7 @@ const Air = @import("../../Air.zig");...@@ -8,7 +8,7 @@ const Air = @import("../../Air.zig");
8const Mir = @import("Mir.zig");8const Mir = @import("Mir.zig");
9const Emit = @import("Emit.zig");9const Emit = @import("Emit.zig");
10const Liveness = @import("../../Liveness.zig");10const Liveness = @import("../../Liveness.zig");
11const Type = @import("../../type.zig").Type;11const Type = @import("../../Type.zig");
12const Value = @import("../../Value.zig");12const Value = @import("../../Value.zig");
13const link = @import("../../link.zig");13const link = @import("../../link.zig");
14const Zcu = @import("../../Zcu.zig");14const Zcu = @import("../../Zcu.zig");
src/arch/arm/Emit.zig+1-1
...@@ -11,7 +11,7 @@ const link = @import("../../link.zig");...@@ -11,7 +11,7 @@ const link = @import("../../link.zig");
11const Zcu = @import("../../Zcu.zig");11const Zcu = @import("../../Zcu.zig");
12/// Deprecated.12/// Deprecated.
13const Module = Zcu;13const Module = Zcu;
14const Type = @import("../../type.zig").Type;14const Type = @import("../../Type.zig");
15const ErrorMsg = Module.ErrorMsg;15const ErrorMsg = Module.ErrorMsg;
16const Target = std.Target;16const Target = std.Target;
17const assert = std.debug.assert;17const assert = std.debug.assert;
src/arch/arm/abi.zig+1-1
...@@ -3,7 +3,7 @@ const assert = std.debug.assert;...@@ -3,7 +3,7 @@ const assert = std.debug.assert;
3const bits = @import("bits.zig");3const bits = @import("bits.zig");
4const Register = bits.Register;4const Register = bits.Register;
5const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;5const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
6const Type = @import("../../type.zig").Type;6const Type = @import("../../Type.zig");
7const Zcu = @import("../../Zcu.zig");7const Zcu = @import("../../Zcu.zig");
8/// Deprecated.8/// Deprecated.
9const Module = Zcu;9const Module = Zcu;
src/arch/riscv64/CodeGen.zig+1-1
...@@ -7,7 +7,7 @@ const Air = @import("../../Air.zig");...@@ -7,7 +7,7 @@ const Air = @import("../../Air.zig");
7const Mir = @import("Mir.zig");7const Mir = @import("Mir.zig");
8const Emit = @import("Emit.zig");8const Emit = @import("Emit.zig");
9const Liveness = @import("../../Liveness.zig");9const Liveness = @import("../../Liveness.zig");
10const Type = @import("../../type.zig").Type;10const Type = @import("../../Type.zig");
11const Value = @import("../../Value.zig");11const Value = @import("../../Value.zig");
12const link = @import("../../link.zig");12const link = @import("../../link.zig");
13const Zcu = @import("../../Zcu.zig");13const Zcu = @import("../../Zcu.zig");
src/arch/riscv64/Mir.zig+1-1
...@@ -431,7 +431,7 @@ pub const RegisterList = struct {...@@ -431,7 +431,7 @@ pub const RegisterList = struct {
431const Mir = @This();431const Mir = @This();
432const std = @import("std");432const std = @import("std");
433const builtin = @import("builtin");433const builtin = @import("builtin");
434const Type = @import("../../type.zig").Type;434const Type = @import("../../Type.zig");
435435
436const assert = std.debug.assert;436const assert = std.debug.assert;
437437
src/arch/riscv64/abi.zig+1-1
...@@ -2,7 +2,7 @@ const std = @import("std");...@@ -2,7 +2,7 @@ const std = @import("std");
2const bits = @import("bits.zig");2const bits = @import("bits.zig");
3const Register = bits.Register;3const Register = bits.Register;
4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;4const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
5const Type = @import("../../type.zig").Type;5const Type = @import("../../Type.zig");
6const InternPool = @import("../../InternPool.zig");6const InternPool = @import("../../InternPool.zig");
7const Zcu = @import("../../Zcu.zig");7const Zcu = @import("../../Zcu.zig");
8const assert = std.debug.assert;8const assert = std.debug.assert;
src/arch/sparc64/CodeGen.zig+1-1
...@@ -21,7 +21,7 @@ const Air = @import("../../Air.zig");...@@ -21,7 +21,7 @@ const Air = @import("../../Air.zig");
21const Mir = @import("Mir.zig");21const Mir = @import("Mir.zig");
22const Emit = @import("Emit.zig");22const Emit = @import("Emit.zig");
23const Liveness = @import("../../Liveness.zig");23const Liveness = @import("../../Liveness.zig");
24const Type = @import("../../type.zig").Type;24const Type = @import("../../Type.zig");
25const CodeGenError = codegen.CodeGenError;25const CodeGenError = codegen.CodeGenError;
26const Result = @import("../../codegen.zig").Result;26const Result = @import("../../codegen.zig").Result;
27const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;27const DebugInfoOutput = @import("../../codegen.zig").DebugInfoOutput;
src/arch/wasm/CodeGen.zig+1-1
...@@ -13,7 +13,7 @@ const codegen = @import("../../codegen.zig");...@@ -13,7 +13,7 @@ const codegen = @import("../../codegen.zig");
13const Zcu = @import("../../Zcu.zig");13const Zcu = @import("../../Zcu.zig");
14const InternPool = @import("../../InternPool.zig");14const InternPool = @import("../../InternPool.zig");
15const Decl = Zcu.Decl;15const Decl = Zcu.Decl;
16const Type = @import("../../type.zig").Type;16const Type = @import("../../Type.zig");
17const Value = @import("../../Value.zig");17const Value = @import("../../Value.zig");
18const Compilation = @import("../../Compilation.zig");18const Compilation = @import("../../Compilation.zig");
19const link = @import("../../link.zig");19const link = @import("../../link.zig");
src/arch/wasm/abi.zig+1-1
...@@ -8,7 +8,7 @@ const std = @import("std");...@@ -8,7 +8,7 @@ const std = @import("std");
8const Target = std.Target;8const Target = std.Target;
9const assert = std.debug.assert;9const assert = std.debug.assert;
1010
11const Type = @import("../../type.zig").Type;11const Type = @import("../../Type.zig");
12const Zcu = @import("../../Zcu.zig");12const Zcu = @import("../../Zcu.zig");
1313
14/// Defines how to pass a type as part of a function signature,14/// Defines how to pass a type as part of a function signature,
src/arch/x86_64/CodeGen.zig+1-1
...@@ -32,7 +32,7 @@ const Module = Zcu;...@@ -32,7 +32,7 @@ const Module = Zcu;
32const InternPool = @import("../../InternPool.zig");32const InternPool = @import("../../InternPool.zig");
33const Alignment = InternPool.Alignment;33const Alignment = InternPool.Alignment;
34const Target = std.Target;34const Target = std.Target;
35const Type = @import("../../type.zig").Type;35const Type = @import("../../Type.zig");
36const Value = @import("../../Value.zig");36const Value = @import("../../Value.zig");
37const Instruction = @import("encoder.zig").Instruction;37const Instruction = @import("encoder.zig").Instruction;
3838
src/arch/x86_64/abi.zig+1-1
...@@ -537,6 +537,6 @@ const testing = std.testing;...@@ -537,6 +537,6 @@ const testing = std.testing;
537const InternPool = @import("../../InternPool.zig");537const InternPool = @import("../../InternPool.zig");
538const Register = @import("bits.zig").Register;538const Register = @import("bits.zig").Register;
539const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;539const RegisterManagerFn = @import("../../register_manager.zig").RegisterManager;
540const Type = @import("../../type.zig").Type;540const Type = @import("../../Type.zig");
541const Value = @import("../../Value.zig");541const Value = @import("../../Value.zig");
542const Zcu = @import("../../Zcu.zig");542const Zcu = @import("../../Zcu.zig");
src/codegen.zig+1-1
...@@ -20,7 +20,7 @@ const Zcu = @import("Zcu.zig");...@@ -20,7 +20,7 @@ const Zcu = @import("Zcu.zig");
20/// Deprecated.20/// Deprecated.
21const Module = Zcu;21const Module = Zcu;
22const Target = std.Target;22const Target = std.Target;
23const Type = @import("type.zig").Type;23const Type = @import("Type.zig");
24const Value = @import("Value.zig");24const Value = @import("Value.zig");
25const Zir = std.zig.Zir;25const Zir = std.zig.Zir;
26const Alignment = InternPool.Alignment;26const Alignment = InternPool.Alignment;
src/codegen/c.zig+1-1
...@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");...@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");
9const Module = @import("../Package/Module.zig");9const Module = @import("../Package/Module.zig");
10const Compilation = @import("../Compilation.zig");10const Compilation = @import("../Compilation.zig");
11const Value = @import("../Value.zig");11const Value = @import("../Value.zig");
12const Type = @import("../type.zig").Type;12const Type = @import("../Type.zig");
13const C = link.File.C;13const C = link.File.C;
14const Decl = Zcu.Decl;14const Decl = Zcu.Decl;
15const trace = @import("../tracy.zig").trace;15const trace = @import("../tracy.zig").trace;
src/codegen/c/Type.zig+1-1
...@@ -2583,6 +2583,6 @@ const assert = std.debug.assert;...@@ -2583,6 +2583,6 @@ const assert = std.debug.assert;
2583const CType = @This();2583const CType = @This();
2584const Module = @import("../../Package/Module.zig");2584const Module = @import("../../Package/Module.zig");
2585const std = @import("std");2585const std = @import("std");
2586const Type = @import("../../type.zig").Type;2586const Type = @import("../../Type.zig");
2587const Zcu = @import("../../Zcu.zig");2587const Zcu = @import("../../Zcu.zig");
2588const DeclIndex = @import("../../InternPool.zig").DeclIndex;2588const DeclIndex = @import("../../InternPool.zig").DeclIndex;
src/codegen/llvm.zig+1-1
...@@ -22,7 +22,7 @@ const Package = @import("../Package.zig");...@@ -22,7 +22,7 @@ const Package = @import("../Package.zig");
22const Air = @import("../Air.zig");22const Air = @import("../Air.zig");
23const Liveness = @import("../Liveness.zig");23const Liveness = @import("../Liveness.zig");
24const Value = @import("../Value.zig");24const Value = @import("../Value.zig");
25const Type = @import("../type.zig").Type;25const Type = @import("../Type.zig");
26const x86_64_abi = @import("../arch/x86_64/abi.zig");26const x86_64_abi = @import("../arch/x86_64/abi.zig");
27const wasm_c_abi = @import("../arch/wasm/abi.zig");27const wasm_c_abi = @import("../arch/wasm/abi.zig");
28const aarch64_c_abi = @import("../arch/aarch64/abi.zig");28const aarch64_c_abi = @import("../arch/aarch64/abi.zig");
src/codegen/spirv.zig+1-1
...@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");...@@ -9,7 +9,7 @@ const Zcu = @import("../Zcu.zig");
9/// Deprecated.9/// Deprecated.
10const Module = Zcu;10const Module = Zcu;
11const Decl = Module.Decl;11const Decl = Module.Decl;
12const Type = @import("../type.zig").Type;12const Type = @import("../Type.zig");
13const Value = @import("../Value.zig");13const Value = @import("../Value.zig");
14const Air = @import("../Air.zig");14const Air = @import("../Air.zig");
15const Liveness = @import("../Liveness.zig");15const Liveness = @import("../Liveness.zig");
src/link.zig+1-1
...@@ -18,7 +18,7 @@ const Zcu = @import("Zcu.zig");...@@ -18,7 +18,7 @@ const Zcu = @import("Zcu.zig");
18/// Deprecated.18/// Deprecated.
19const Module = Zcu;19const Module = Zcu;
20const InternPool = @import("InternPool.zig");20const InternPool = @import("InternPool.zig");
21const Type = @import("type.zig").Type;21const Type = @import("Type.zig");
22const Value = @import("Value.zig");22const Value = @import("Value.zig");
23const LlvmObject = @import("codegen/llvm.zig").Object;23const LlvmObject = @import("codegen/llvm.zig").Object;
24const lldMain = @import("main.zig").lldMain;24const lldMain = @import("main.zig").lldMain;
src/link/C.zig+1-1
...@@ -14,7 +14,7 @@ const Compilation = @import("../Compilation.zig");...@@ -14,7 +14,7 @@ const Compilation = @import("../Compilation.zig");
14const codegen = @import("../codegen/c.zig");14const codegen = @import("../codegen/c.zig");
15const link = @import("../link.zig");15const link = @import("../link.zig");
16const trace = @import("../tracy.zig").trace;16const trace = @import("../tracy.zig").trace;
17const Type = @import("../type.zig").Type;17const Type = @import("../Type.zig");
18const Value = @import("../Value.zig");18const Value = @import("../Value.zig");
19const Air = @import("../Air.zig");19const Air = @import("../Air.zig");
20const Liveness = @import("../Liveness.zig");20const Liveness = @import("../Liveness.zig");
src/link/Coff.zig+1-1
...@@ -2742,7 +2742,7 @@ const Object = @import("Coff/Object.zig");...@@ -2742,7 +2742,7 @@ const Object = @import("Coff/Object.zig");
2742const Relocation = @import("Coff/Relocation.zig");2742const Relocation = @import("Coff/Relocation.zig");
2743const TableSection = @import("table_section.zig").TableSection;2743const TableSection = @import("table_section.zig").TableSection;
2744const StringTable = @import("StringTable.zig");2744const StringTable = @import("StringTable.zig");
2745const Type = @import("../type.zig").Type;2745const Type = @import("../Type.zig");
2746const Value = @import("../Value.zig");2746const Value = @import("../Value.zig");
2747const AnalUnit = InternPool.AnalUnit;2747const AnalUnit = InternPool.AnalUnit;
27482748
src/link/Dwarf.zig+1-1
...@@ -2969,5 +2969,5 @@ const Zcu = @import("../Zcu.zig");...@@ -2969,5 +2969,5 @@ const Zcu = @import("../Zcu.zig");
2969const Module = Zcu;2969const Module = Zcu;
2970const InternPool = @import("../InternPool.zig");2970const InternPool = @import("../InternPool.zig");
2971const StringTable = @import("StringTable.zig");2971const StringTable = @import("StringTable.zig");
2972const Type = @import("../type.zig").Type;2972const Type = @import("../Type.zig");
2973const Value = @import("../Value.zig");2973const Value = @import("../Value.zig");
src/link/Elf/ZigObject.zig+1-1
...@@ -1647,7 +1647,7 @@ const Module = Zcu;...@@ -1647,7 +1647,7 @@ const Module = Zcu;
1647const Object = @import("Object.zig");1647const Object = @import("Object.zig");
1648const Symbol = @import("Symbol.zig");1648const Symbol = @import("Symbol.zig");
1649const StringTable = @import("../StringTable.zig");1649const StringTable = @import("../StringTable.zig");
1650const Type = @import("../../type.zig").Type;1650const Type = @import("../../Type.zig");
1651const Value = @import("../../Value.zig");1651const Value = @import("../../Value.zig");
1652const AnalUnit = InternPool.AnalUnit;1652const AnalUnit = InternPool.AnalUnit;
1653const ZigObject = @This();1653const ZigObject = @This();
src/link/MachO/DebugSymbols.zig+1-1
...@@ -459,4 +459,4 @@ const trace = @import("../../tracy.zig").trace;...@@ -459,4 +459,4 @@ const trace = @import("../../tracy.zig").trace;
459const Allocator = mem.Allocator;459const Allocator = mem.Allocator;
460const MachO = @import("../MachO.zig");460const MachO = @import("../MachO.zig");
461const StringTable = @import("../StringTable.zig");461const StringTable = @import("../StringTable.zig");
462const Type = @import("../../type.zig").Type;462const Type = @import("../../Type.zig");
src/link/MachO/ZigObject.zig+1-1
...@@ -1587,7 +1587,7 @@ const Object = @import("Object.zig");...@@ -1587,7 +1587,7 @@ const Object = @import("Object.zig");
1587const Relocation = @import("Relocation.zig");1587const Relocation = @import("Relocation.zig");
1588const Symbol = @import("Symbol.zig");1588const Symbol = @import("Symbol.zig");
1589const StringTable = @import("../StringTable.zig");1589const StringTable = @import("../StringTable.zig");
1590const Type = @import("../../type.zig").Type;1590const Type = @import("../../Type.zig");
1591const Value = @import("../../Value.zig");1591const Value = @import("../../Value.zig");
1592const AnalUnit = InternPool.AnalUnit;1592const AnalUnit = InternPool.AnalUnit;
1593const ZigObject = @This();1593const ZigObject = @This();
src/link/Plan9.zig+1-1
...@@ -15,7 +15,7 @@ const File = link.File;...@@ -15,7 +15,7 @@ const File = link.File;
15const build_options = @import("build_options");15const build_options = @import("build_options");
16const Air = @import("../Air.zig");16const Air = @import("../Air.zig");
17const Liveness = @import("../Liveness.zig");17const Liveness = @import("../Liveness.zig");
18const Type = @import("../type.zig").Type;18const Type = @import("../Type.zig");
19const Value = @import("../Value.zig");19const Value = @import("../Value.zig");
20const AnalUnit = InternPool.AnalUnit;20const AnalUnit = InternPool.AnalUnit;
2121
src/link/Wasm.zig+1-1
...@@ -33,7 +33,7 @@ const Zcu = @import("../Zcu.zig");...@@ -33,7 +33,7 @@ const Zcu = @import("../Zcu.zig");
33const Module = Zcu;33const Module = Zcu;
34const Object = @import("Wasm/Object.zig");34const Object = @import("Wasm/Object.zig");
35const Symbol = @import("Wasm/Symbol.zig");35const Symbol = @import("Wasm/Symbol.zig");
36const Type = @import("../type.zig").Type;36const Type = @import("../Type.zig");
37const Value = @import("../Value.zig");37const Value = @import("../Value.zig");
38const ZigObject = @import("Wasm/ZigObject.zig");38const ZigObject = @import("Wasm/ZigObject.zig");
3939
src/link/Wasm/ZigObject.zig+1-1
...@@ -1252,7 +1252,7 @@ const Zcu = @import("../../Zcu.zig");...@@ -1252,7 +1252,7 @@ const Zcu = @import("../../Zcu.zig");
1252const Module = Zcu;1252const Module = Zcu;
1253const StringTable = @import("../StringTable.zig");1253const StringTable = @import("../StringTable.zig");
1254const Symbol = @import("Symbol.zig");1254const Symbol = @import("Symbol.zig");
1255const Type = @import("../../type.zig").Type;1255const Type = @import("../../Type.zig");
1256const Value = @import("../../Value.zig");1256const Value = @import("../../Value.zig");
1257const Wasm = @import("../Wasm.zig");1257const Wasm = @import("../Wasm.zig");
1258const AnalUnit = InternPool.AnalUnit;1258const AnalUnit = InternPool.AnalUnit;
src/mutable_value.zig+1-1
...@@ -3,7 +3,7 @@ const assert = std.debug.assert;...@@ -3,7 +3,7 @@ const assert = std.debug.assert;
3const Allocator = std.mem.Allocator;3const Allocator = std.mem.Allocator;
4const Zcu = @import("Zcu.zig");4const Zcu = @import("Zcu.zig");
5const InternPool = @import("InternPool.zig");5const InternPool = @import("InternPool.zig");
6const Type = @import("type.zig").Type;6const Type = @import("Type.zig");
7const Value = @import("Value.zig");7const Value = @import("Value.zig");
88
9/// We use a tagged union here because while it wastes a few bytes for some tags, having a fixed9/// 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;...@@ -4,7 +4,7 @@ const fmtIntSizeBin = std.fmt.fmtIntSizeBin;
44
5const Zcu = @import("Zcu.zig");5const Zcu = @import("Zcu.zig");
6const Value = @import("Value.zig");6const Value = @import("Value.zig");
7const Type = @import("type.zig").Type;7const Type = @import("Type.zig");
8const Air = @import("Air.zig");8const Air = @import("Air.zig");
9const Liveness = @import("Liveness.zig");9const Liveness = @import("Liveness.zig");
10const InternPool = @import("InternPool.zig");10const InternPool = @import("InternPool.zig");
src/print_value.zig+1-1
...@@ -2,7 +2,7 @@...@@ -2,7 +2,7 @@
2//! It is a thin wrapper around a `Value` which also, redundantly, stores its `Type`.2//! It is a thin wrapper around a `Value` which also, redundantly, stores its `Type`.
33
4const std = @import("std");4const std = @import("std");
5const Type = @import("type.zig").Type;5const Type = @import("Type.zig");
6const Value = @import("Value.zig");6const Value = @import("Value.zig");
7const Zcu = @import("Zcu.zig");7const Zcu = @import("Zcu.zig");
8/// Deprecated.8/// Deprecated.
src/register_manager.zig+1-1
...@@ -5,7 +5,7 @@ const assert = std.debug.assert;...@@ -5,7 +5,7 @@ const assert = std.debug.assert;
5const Allocator = std.mem.Allocator;5const Allocator = std.mem.Allocator;
6const Air = @import("Air.zig");6const Air = @import("Air.zig");
7const StaticBitSet = std.bit_set.StaticBitSet;7const StaticBitSet = std.bit_set.StaticBitSet;
8const Type = @import("type.zig").Type;8const Type = @import("Type.zig");
9const Zcu = @import("Zcu.zig");9const Zcu = @import("Zcu.zig");
10/// Deprecated.10/// Deprecated.
11const Module = Zcu;11const Module = Zcu;
src/target.zig+1-1
...@@ -1,5 +1,5 @@...@@ -1,5 +1,5 @@
1const std = @import("std");1const std = @import("std");
2const Type = @import("type.zig").Type;2const Type = @import("Type.zig");
3const AddressSpace = std.builtin.AddressSpace;3const AddressSpace = std.builtin.AddressSpace;
4const Alignment = @import("InternPool.zig").Alignment;4const Alignment = @import("InternPool.zig").Alignment;
5const Feature = @import("Zcu.zig").Feature;5const 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}