aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorAndrew Kelley <andrew@ziglang.org>2024-03-07 18:41:45 -0800
committerGitHub <noreply@github.com>2024-03-07 18:41:45 -0800
commit97aa5f7b8a059f91b78ce7cd70cba0f3aa2c5118 (patch)
tree4e2dc7d8083a24bb01cf8e94e684e3256b7f0a31 /src/Sema.zig
parent377ecc6afb14a112a07c6d2c3570e2b77b12a116 (diff)
parent38331b1cabf86586bdf70c80ed98f74c60305160 (diff)
downloadzig-97aa5f7b8a059f91b78ce7cd70cba0f3aa2c5118.tar.gz
zig-97aa5f7b8a059f91b78ce7cd70cba0f3aa2c5118.zip
Merge pull request #19190 from mlugg/struct-equivalence
compiler: namespace type equivalence based on AST node + captures
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig1915
1 files changed, 993 insertions, 922 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index bf0aacabe5..cff7404a3b 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -155,7 +155,6 @@ const Namespace = Module.Namespace;
const CompileError = Module.CompileError;
const SemaError = Module.SemaError;
const Decl = Module.Decl;
-const CaptureScope = Module.CaptureScope;
const LazySrcLoc = std.zig.LazySrcLoc;
const RangeSet = @import("RangeSet.zig");
const target_util = @import("target.zig");
@@ -331,8 +330,6 @@ pub const Block = struct {
/// used to add a `func_instance` into the `InternPool`.
params: std.MultiArrayList(Param) = .{},
- wip_capture_scope: CaptureScope.Index,
-
label: ?*Label = null,
inlining: ?*Inlining,
/// If runtime_index is not 0 then one of these is guaranteed to be non null.
@@ -475,7 +472,6 @@ pub const Block = struct {
.src_decl = parent.src_decl,
.namespace = parent.namespace,
.instructions = .{},
- .wip_capture_scope = parent.wip_capture_scope,
.label = null,
.inlining = parent.inlining,
.is_comptime = parent.is_comptime,
@@ -974,12 +970,6 @@ fn analyzeBodyInner(
try sema.inst_map.ensureSpaceForInstructions(sema.gpa, body);
- // Most of the time, we don't need to construct a new capture scope for a
- // block. However, successive iterations of comptime loops can capture
- // different values for the same Zir.Inst.Index, so in those cases, we will
- // have to create nested capture scopes; see the `.repeat` case below.
- const parent_capture_scope = block.wip_capture_scope;
-
const mod = sema.mod;
const map = &sema.inst_map;
const tags = sema.code.instructions.items(.tag);
@@ -1028,7 +1018,6 @@ fn analyzeBodyInner(
.c_import => try sema.zirCImport(block, inst),
.call => try sema.zirCall(block, inst, .direct),
.field_call => try sema.zirCall(block, inst, .field),
- .closure_get => try sema.zirClosureGet(block, inst),
.cmp_lt => try sema.zirCmp(block, inst, .lt),
.cmp_lte => try sema.zirCmp(block, inst, .lte),
.cmp_eq => try sema.zirCmpEq(block, inst, .eq, Air.Inst.Tag.fromCmpOp(.eq, block.float_mode == .Optimized)),
@@ -1275,6 +1264,7 @@ fn analyzeBodyInner(
.work_group_size => try sema.zirWorkItem( block, extended, extended.opcode),
.work_group_id => try sema.zirWorkItem( block, extended, extended.opcode),
.in_comptime => try sema.zirInComptime( block),
+ .closure_get => try sema.zirClosureGet( block, extended),
// zig fmt: on
.fence => {
@@ -1453,11 +1443,6 @@ fn analyzeBodyInner(
i += 1;
continue;
},
- .closure_capture => {
- try sema.zirClosureCapture(block, inst);
- i += 1;
- continue;
- },
.memcpy => {
try sema.zirMemcpy(block, inst);
i += 1;
@@ -1534,11 +1519,6 @@ fn analyzeBodyInner(
// Send comptime control flow back to the beginning of this block.
const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);
try sema.emitBackwardBranch(block, src);
-
- // We need to construct new capture scopes for the next loop iteration so it
- // can capture values without clobbering the earlier iteration's captures.
- block.wip_capture_scope = try mod.createCaptureScope(parent_capture_scope);
-
i = 0;
continue;
} else {
@@ -1552,11 +1532,6 @@ fn analyzeBodyInner(
// Send comptime control flow back to the beginning of this block.
const src = LazySrcLoc.nodeOffset(datas[@intFromEnum(inst)].node);
try sema.emitBackwardBranch(block, src);
-
- // We need to construct new capture scopes for the next loop iteration so it
- // can capture values without clobbering the earlier iteration's captures.
- block.wip_capture_scope = try mod.createCaptureScope(parent_capture_scope);
-
i = 0;
continue;
},
@@ -1855,10 +1830,6 @@ fn analyzeBodyInner(
map.putAssumeCapacity(inst, air_inst);
i += 1;
}
-
- // We may have overwritten the capture scope due to a `repeat` instruction where
- // the body had a capture; restore it now.
- block.wip_capture_scope = parent_capture_scope;
}
pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
@@ -2698,21 +2669,61 @@ fn analyzeAsInt(
return (try val.getUnsignedIntAdvanced(mod, sema)).?;
}
-pub fn getStructType(
+/// Given a ZIR extra index which points to a list of `Zir.Inst.Capture`,
+/// resolves this into a list of `InternPool.CaptureValue` allocated by `arena`.
+fn getCaptures(sema: *Sema, block: *Block, extra_index: usize, captures_len: u32) ![]InternPool.CaptureValue {
+ const zcu = sema.mod;
+ const ip = &zcu.intern_pool;
+ const parent_captures: InternPool.CaptureValue.Slice = zcu.namespacePtr(block.namespace).getType(zcu).getCaptures(zcu);
+
+ const captures = try sema.arena.alloc(InternPool.CaptureValue, captures_len);
+
+ for (sema.code.extra[extra_index..][0..captures_len], captures) |raw, *capture| {
+ const zir_capture: Zir.Inst.Capture = @bitCast(raw);
+ capture.* = switch (zir_capture.unwrap()) {
+ .nested => |parent_idx| parent_captures.get(ip)[parent_idx],
+ .instruction => |inst| InternPool.CaptureValue.wrap(capture: {
+ const air_ref = try sema.resolveInst(inst.toRef());
+ if (try sema.resolveValueResolveLazy(air_ref)) |val| {
+ break :capture .{ .@"comptime" = val.toIntern() };
+ }
+ break :capture .{ .runtime = sema.typeOf(air_ref).toIntern() };
+ }),
+ .decl_val => |str| capture: {
+ const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
+ const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
+ break :capture InternPool.CaptureValue.wrap(.{ .decl_val = decl });
+ },
+ .decl_ref => |str| capture: {
+ const decl_name = try ip.getOrPutString(sema.gpa, sema.code.nullTerminatedString(str));
+ const decl = try sema.lookupIdentifier(block, .unneeded, decl_name); // TODO: could we need this src loc?
+ break :capture InternPool.CaptureValue.wrap(.{ .decl_ref = decl });
+ },
+ };
+ }
+
+ return captures;
+}
+
+fn zirStructDecl(
sema: *Sema,
- decl: InternPool.DeclIndex,
- namespace: InternPool.NamespaceIndex,
- tracked_inst: InternPool.TrackedInst.Index,
-) !InternPool.Index {
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+ inst: Zir.Inst.Index,
+) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const gpa = sema.gpa;
const ip = &mod.intern_pool;
- const zir_index = tracked_inst.resolve(ip);
- const extended = sema.code.instructions.items(.data)[@intFromEnum(zir_index)].extended;
- assert(extended.opcode == .struct_decl);
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
+ const extra = sema.code.extraData(Zir.Inst.StructDecl, extended.operand);
+ const src = extra.data.src();
+ var extra_index = extra.end;
- var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
const fields_len = if (small.has_fields_len) blk: {
const fields_len = sema.code.extra[extra_index];
extra_index += 1;
@@ -2724,6 +2735,9 @@ pub fn getStructType(
break :blk decls_len;
} else 0;
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
+ extra_index += captures_len;
+
if (small.has_backing_int) {
const backing_int_body_len = sema.code.extra[extra_index];
extra_index += 1; // backing_int_body_len
@@ -2734,49 +2748,38 @@ pub fn getStructType(
}
}
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try mod.scanNamespace(namespace, decls, mod.declPtr(decl));
- extra_index += decls_len;
-
- const ty = try ip.getStructType(gpa, .{
- .decl = decl,
- .namespace = namespace.toOptional(),
- .zir_index = tracked_inst.toOptional(),
+ const wip_ty = switch (try ip.getStructType(gpa, .{
.layout = small.layout,
- .known_non_opv = small.known_non_opv,
- .is_tuple = small.is_tuple,
.fields_len = fields_len,
+ .known_non_opv = small.known_non_opv,
.requires_comptime = if (small.known_comptime_only) .yes else .unknown,
- .any_default_inits = small.any_default_inits,
+ .is_tuple = small.is_tuple,
.any_comptime_fields = small.any_comptime_fields,
+ .any_default_inits = small.any_default_inits,
.inits_resolved = false,
.any_aligned_fields = small.any_aligned_fields,
- });
-
- return ty;
-}
-
-fn zirStructDecl(
- sema: *Sema,
- block: *Block,
- extended: Zir.Inst.Extended.InstData,
- inst: Zir.Inst.Index,
-) CompileError!Air.Inst.Ref {
- const mod = sema.mod;
- const ip = &mod.intern_pool;
- const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
- const src = sema.code.extraData(Zir.Inst.StructDecl, extended.operand).data.src();
-
- // Because these three things each reference each other, `undefined`
- // placeholders are used before being set after the struct type gains an
- // InternPool index.
+ .has_namespace = true or decls_len > 0, // TODO: see below
+ .key = .{ .declared = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ .captures = captures,
+ } },
+ })) {
+ .existing => |ty| return Air.internedToRef(ty),
+ .wip => |wip| wip: {
+ if (sema.builtin_type_target_index == .none) break :wip wip;
+ var new = wip;
+ new.index = sema.builtin_type_target_index;
+ ip.resolveBuiltinType(new.index, wip.index);
+ break :wip new;
+ },
+ };
+ errdefer wip_ty.cancel(ip);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
}, small.name_strategy, "struct", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
+ mod.declPtr(new_decl_index).owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
if (sema.mod.comp.debug_incremental) {
@@ -2787,31 +2790,21 @@ fn zirStructDecl(
);
}
- const new_namespace_index = try mod.createNamespace(.{
+ // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
+ const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- });
- errdefer mod.destroyNamespace(new_namespace_index);
-
- const struct_ty = ty: {
- const tracked_inst = try ip.trackZir(mod.gpa, block.getFileScope(mod), inst);
- const ty = try sema.getStructType(new_decl_index, new_namespace_index, tracked_inst);
- if (sema.builtin_type_target_index != .none) {
- ip.resolveBuiltinType(sema.builtin_type_target_index, ty);
- break :ty sema.builtin_type_target_index;
- }
- break :ty ty;
- };
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer ip.remove(struct_ty);
+ })).toOptional() else .none;
+ errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(struct_ty);
+ if (new_namespace_index.unwrap()) |ns| {
+ const decls = sema.code.bodySlice(extra_index, decls_len);
+ try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
+ }
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+ return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
}
fn createAnonymousDeclTypeNamed(
@@ -2827,10 +2820,9 @@ fn createAnonymousDeclTypeNamed(
const ip = &mod.intern_pool;
const gpa = sema.gpa;
const namespace = block.namespace;
- const src_scope = block.wip_capture_scope;
const src_decl = mod.declPtr(block.src_decl);
const src_node = src_decl.relativeToNodeIndex(src.node_offset.x);
- const new_decl_index = try mod.allocateNewDecl(namespace, src_node, src_scope);
+ const new_decl_index = try mod.allocateNewDecl(namespace, src_node);
errdefer mod.destroyDecl(new_decl_index);
switch (name_strategy) {
@@ -2922,6 +2914,7 @@ fn zirEnumDecl(
const mod = sema.mod;
const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const small: Zir.Inst.EnumDecl.Small = @bitCast(extended.small);
const extra = sema.code.extraData(Zir.Inst.EnumDecl, extended.operand);
var extra_index: usize = extra.end;
@@ -2935,6 +2928,12 @@ fn zirEnumDecl(
break :blk tag_type_ref;
} else .none;
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+
const body_len = if (small.has_body_len) blk: {
const body_len = sema.code.extra[extra_index];
extra_index += 1;
@@ -2953,14 +2952,57 @@ fn zirEnumDecl(
break :blk decls_len;
} else 0;
- // Because these three things each reference each other, `undefined`
- // placeholders are used before being set after the enum type gains an
- // InternPool index.
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
+ extra_index += captures_len;
+ const decls = sema.code.bodySlice(extra_index, decls_len);
+ extra_index += decls_len;
+
+ const body = sema.code.bodySlice(extra_index, body_len);
+ extra_index += body.len;
+
+ const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
+ const body_end = extra_index;
+ extra_index += bit_bags_count;
+
+ const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
+ if (bag != 0) break true;
+ } else false;
+
+ const wip_ty = switch (try ip.getEnumType(gpa, .{
+ .has_namespace = true or decls_len > 0, // TODO: see below
+ .has_values = any_values,
+ .tag_mode = if (small.nonexhaustive)
+ .nonexhaustive
+ else if (tag_type_ref == .none)
+ .auto
+ else
+ .explicit,
+ .fields_len = fields_len,
+ .key = .{ .declared = .{
+ .zir_index = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst),
+ .captures = captures,
+ } },
+ })) {
+ .wip => |wip| wip: {
+ if (sema.builtin_type_target_index == .none) break :wip wip;
+ var new = wip;
+ new.index = sema.builtin_type_target_index;
+ ip.resolveBuiltinType(new.index, wip.index);
+ break :wip new;
+ },
+ .existing => |ty| return Air.internedToRef(ty),
+ };
+
+ // Once this is `true`, we will not delete the decl or type even upon failure, since we
+ // have finished constructing the type and are in the process of analyzing it.
var done = false;
+
+ errdefer if (!done) wip_ty.cancel(ip);
+
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
}, small.name_strategy, "enum", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
@@ -2974,56 +3016,21 @@ fn zirEnumDecl(
);
}
- const new_namespace_index = try mod.createNamespace(.{
+ // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
+ const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- });
- errdefer if (!done) mod.destroyNamespace(new_namespace_index);
-
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try mod.scanNamespace(new_namespace_index, decls, new_decl);
- extra_index += decls_len;
-
- const body = sema.code.bodySlice(extra_index, body_len);
- extra_index += body.len;
-
- const bit_bags_count = std.math.divCeil(usize, fields_len, 32) catch unreachable;
- const body_end = extra_index;
- extra_index += bit_bags_count;
-
- const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
- if (bag != 0) break true;
- } else false;
-
- const incomplete_enum = incomplete_enum: {
- var incomplete_enum = try mod.intern_pool.getIncompleteEnum(gpa, .{
- .decl = new_decl_index,
- .namespace = new_namespace_index.toOptional(),
- .fields_len = fields_len,
- .has_values = any_values,
- .tag_mode = if (small.nonexhaustive)
- .nonexhaustive
- else if (tag_type_ref == .none)
- .auto
- else
- .explicit,
- .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
- });
- if (sema.builtin_type_target_index != .none) {
- mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, incomplete_enum.index);
- incomplete_enum.index = sema.builtin_type_target_index;
- }
- break :incomplete_enum incomplete_enum;
- };
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index);
+ })).toOptional() else .none;
+ errdefer if (!done) if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(incomplete_enum.index);
+ if (new_namespace_index.unwrap()) |ns| {
+ try mod.scanNamespace(ns, decls, new_decl);
+ }
- const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
- try mod.finalizeAnonDecl(new_decl_index);
+ // We've finished the initial construction of this type, and are about to perform analysis.
+ // Set the decl and namespace appropriately, and don't destroy anything on failure.
+ wip_ty.prepare(ip, new_decl_index, new_namespace_index);
done = true;
const int_tag_ty = ty: {
@@ -3053,8 +3060,7 @@ fn zirEnumDecl(
.parent = null,
.sema = sema,
.src_decl = new_decl_index,
- .namespace = new_namespace_index,
- .wip_capture_scope = try mod.createCaptureScope(new_decl.src_scope),
+ .namespace = new_namespace_index.unwrap() orelse block.namespace,
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -3070,7 +3076,6 @@ fn zirEnumDecl(
if (ty.zigTypeTag(mod) != .Int and ty.zigTypeTag(mod) != .ComptimeInt) {
return sema.fail(block, tag_ty_src, "expected integer tag type, found '{}'", .{ty.fmt(sema.mod)});
}
- incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern());
break :ty ty;
} else if (fields_len == 0) {
break :ty try mod.intType(.unsigned, 0);
@@ -3080,6 +3085,8 @@ fn zirEnumDecl(
}
};
+ wip_ty.setTagTy(ip, int_tag_ty.toIntern());
+
if (small.nonexhaustive and int_tag_ty.toIntern() != .comptime_int_type) {
if (fields_len > 1 and std.math.log2_int(u64, fields_len) == int_tag_ty.bitSize(mod)) {
return sema.fail(block, src, "non-exhaustive enum specifies every value", .{});
@@ -3103,7 +3110,6 @@ fn zirEnumDecl(
extra_index += 2; // field name, doc comment
const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
- assert(incomplete_enum.addFieldName(&mod.intern_pool, field_name) == null);
const tag_overflow = if (has_tag_value) overflow: {
const tag_val_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
@@ -3124,12 +3130,13 @@ fn zirEnumDecl(
};
if (!(try sema.intFitsInType(last_tag_val.?, int_tag_ty, null))) break :overflow true;
last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
- if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
+ if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
+ assert(conflict.kind == .value); // AstGen validated names are unique
const value_src = mod.fieldSrcLoc(new_decl_index, .{
.index = field_i,
.range = .value,
}).lazy;
- const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
+ const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
const msg = msg: {
const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
errdefer msg.destroy(gpa);
@@ -3146,9 +3153,10 @@ fn zirEnumDecl(
else
try mod.intValue(int_tag_ty, 0);
if (overflow != null) break :overflow true;
- if (incomplete_enum.addFieldValue(&mod.intern_pool, last_tag_val.?.toIntern())) |other_index| {
+ if (wip_ty.nextField(&mod.intern_pool, field_name, last_tag_val.?.toIntern())) |conflict| {
+ assert(conflict.kind == .value); // AstGen validated names are unique
const field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = field_i }).lazy;
- const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
+ const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = conflict.prev_field_idx }).lazy;
const msg = msg: {
const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{last_tag_val.?.fmtValue(int_tag_ty, sema.mod)});
errdefer msg.destroy(gpa);
@@ -3159,6 +3167,7 @@ fn zirEnumDecl(
}
break :overflow false;
} else overflow: {
+ assert(wip_ty.nextField(&mod.intern_pool, field_name, .none) == null);
last_tag_val = try mod.intValue(Type.comptime_int, field_i);
if (!try sema.intFitsInType(last_tag_val.?, int_tag_ty, null)) break :overflow true;
last_tag_val = try mod.getCoerced(last_tag_val.?, int_tag_ty);
@@ -3176,7 +3185,9 @@ fn zirEnumDecl(
return sema.failWithOwnedErrorMsg(block, msg);
}
}
- return decl_val;
+
+ try mod.finalizeAnonDecl(new_decl_index);
+ return Air.internedToRef(wip_ty.index);
}
fn zirUnionDecl(
@@ -3190,6 +3201,7 @@ fn zirUnionDecl(
const mod = sema.mod;
const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
const extra = sema.code.extraData(Zir.Inst.UnionDecl, extended.operand);
var extra_index: usize = extra.end;
@@ -3197,6 +3209,11 @@ fn zirUnionDecl(
const src = extra.data.src();
extra_index += @intFromBool(small.has_tag_type);
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
extra_index += @intFromBool(small.has_body_len);
const fields_len = if (small.has_fields_len) blk: {
const fields_len = sema.code.extra[extra_index];
@@ -3210,16 +3227,53 @@ fn zirUnionDecl(
break :blk decls_len;
} else 0;
- // Because these three things each reference each other, `undefined`
- // placeholders are used before being set after the union type gains an
- // InternPool index.
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
+ extra_index += captures_len;
+
+ const wip_ty = switch (try ip.getUnionType(gpa, .{
+ .flags = .{
+ .layout = small.layout,
+ .status = .none,
+ .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
+ .tagged
+ else if (small.layout != .Auto)
+ .none
+ else switch (block.wantSafety()) {
+ true => .safety,
+ false => .none,
+ },
+ .any_aligned_fields = small.any_aligned_fields,
+ .requires_comptime = .unknown,
+ .assumed_runtime_bits = false,
+ .assumed_pointer_aligned = false,
+ .alignment = .none,
+ },
+ .has_namespace = true or decls_len != 0, // TODO: see below
+ .fields_len = fields_len,
+ .enum_tag_ty = .none, // set later
+ .field_types = &.{}, // set later
+ .field_aligns = &.{}, // set later
+ .key = .{ .declared = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ .captures = captures,
+ } },
+ })) {
+ .wip => |wip| wip: {
+ if (sema.builtin_type_target_index == .none) break :wip wip;
+ var new = wip;
+ new.index = sema.builtin_type_target_index;
+ ip.resolveBuiltinType(new.index, wip.index);
+ break :wip new;
+ },
+ .existing => |ty| return Air.internedToRef(ty),
+ };
+ errdefer wip_ty.cancel(ip);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
}, small.name_strategy, "union", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
+ mod.declPtr(new_decl_index).owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
if (sema.mod.comp.debug_incremental) {
@@ -3230,58 +3284,22 @@ fn zirUnionDecl(
);
}
- const new_namespace_index = try mod.createNamespace(.{
+ // TODO: if AstGen tells us `@This` was not used in the fields, we can elide the namespace.
+ const new_namespace_index: InternPool.OptionalNamespaceIndex = if (true or decls_len > 0) (try mod.createNamespace(.{
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- });
- errdefer mod.destroyNamespace(new_namespace_index);
-
- const union_ty = ty: {
- const ty = try mod.intern_pool.getUnionType(gpa, .{
- .flags = .{
- .layout = small.layout,
- .status = .none,
- .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
- .tagged
- else if (small.layout != .Auto)
- .none
- else switch (block.wantSafety()) {
- true => .safety,
- false => .none,
- },
- .any_aligned_fields = small.any_aligned_fields,
- .requires_comptime = .unknown,
- .assumed_runtime_bits = false,
- .assumed_pointer_aligned = false,
- .alignment = .none,
- },
- .decl = new_decl_index,
- .namespace = new_namespace_index,
- .zir_index = (try mod.intern_pool.trackZir(gpa, block.getFileScope(mod), inst)).toOptional(),
- .fields_len = fields_len,
- .enum_tag_ty = .none,
- .field_types = &.{},
- .field_aligns = &.{},
- });
- if (sema.builtin_type_target_index != .none) {
- mod.intern_pool.resolveBuiltinType(sema.builtin_type_target_index, ty);
- break :ty sema.builtin_type_target_index;
- }
- break :ty ty;
- };
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer mod.intern_pool.remove(union_ty);
-
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(union_ty);
+ })).toOptional() else .none;
+ errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try mod.scanNamespace(new_namespace_index, decls, new_decl);
+ if (new_namespace_index.unwrap()) |ns| {
+ const decls = sema.code.bodySlice(extra_index, decls_len);
+ try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
+ }
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+
+ return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
}
fn zirOpaqueDecl(
@@ -3294,62 +3312,72 @@ fn zirOpaqueDecl(
defer tracy.end();
const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+
const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
const extra = sema.code.extraData(Zir.Inst.OpaqueDecl, extended.operand);
var extra_index: usize = extra.end;
const src = extra.data.src();
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = sema.code.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+
const decls_len = if (small.has_decls_len) blk: {
const decls_len = sema.code.extra[extra_index];
extra_index += 1;
break :blk decls_len;
} else 0;
- // Because these three things each reference each other, `undefined`
- // placeholders are used in two places before being set after the opaque
- // type gains an InternPool index.
+ const captures = try sema.getCaptures(block, extra_index, captures_len);
+ extra_index += captures_len;
+
+ const wip_ty = switch (try ip.getOpaqueType(gpa, .{
+ .has_namespace = decls_len != 0,
+ .key = .{ .declared = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ .captures = captures,
+ } },
+ })) {
+ .wip => |wip| wip,
+ .existing => |ty| return Air.internedToRef(ty),
+ };
+ errdefer wip_ty.cancel(ip);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
}, small.name_strategy, "opaque", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
+ mod.declPtr(new_decl_index).owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
if (sema.mod.comp.debug_incremental) {
- try mod.intern_pool.addDependency(
- sema.gpa,
+ try ip.addDependency(
+ gpa,
InternPool.Depender.wrap(.{ .decl = new_decl_index }),
- .{ .src_hash = try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst) },
+ .{ .src_hash = try ip.trackZir(gpa, block.getFileScope(mod), inst) },
);
}
- const new_namespace_index = try mod.createNamespace(.{
+ const new_namespace_index: InternPool.OptionalNamespaceIndex = if (decls_len > 0) (try mod.createNamespace(.{
.parent = block.namespace.toOptional(),
.decl_index = new_decl_index,
.file_scope = block.getFileScope(mod),
- });
- errdefer mod.destroyNamespace(new_namespace_index);
-
- const opaque_ty = try mod.intern(.{ .opaque_type = .{
- .decl = new_decl_index,
- .namespace = new_namespace_index,
- .zir_index = (try mod.intern_pool.trackZir(sema.gpa, block.getFileScope(mod), inst)).toOptional(),
- } });
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer mod.intern_pool.remove(opaque_ty);
-
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(opaque_ty);
+ })).toOptional() else .none;
+ errdefer if (new_namespace_index.unwrap()) |ns| mod.destroyNamespace(ns);
- const decls = sema.code.bodySlice(extra_index, decls_len);
- try mod.scanNamespace(new_namespace_index, decls, new_decl);
+ if (new_namespace_index.unwrap()) |ns| {
+ const decls = sema.code.bodySlice(extra_index, decls_len);
+ try mod.scanNamespace(ns, decls, mod.declPtr(new_decl_index));
+ }
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+
+ return Air.internedToRef(wip_ty.finish(ip, new_decl_index, new_namespace_index));
}
fn zirErrorSetDecl(
@@ -5333,7 +5361,7 @@ fn failWithBadMemberAccess(
fn failWithBadStructFieldAccess(
sema: *Sema,
block: *Block,
- struct_type: InternPool.Key.StructType,
+ struct_type: InternPool.LoadedStructType,
field_src: LazySrcLoc,
field_name: InternPool.NullTerminatedString,
) CompileError {
@@ -5359,7 +5387,7 @@ fn failWithBadStructFieldAccess(
fn failWithBadUnionFieldAccess(
sema: *Sema,
block: *Block,
- union_obj: InternPool.UnionType,
+ union_obj: InternPool.LoadedUnionType,
field_src: LazySrcLoc,
field_name: InternPool.NullTerminatedString,
) CompileError {
@@ -5780,7 +5808,6 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
.sema = sema,
.src_decl = parent_block.src_decl,
.namespace = parent_block.namespace,
- .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.inlining = parent_block.inlining,
.is_comptime = true,
@@ -5831,6 +5858,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
.global = comp.config,
.parent = parent_mod,
.builtin_mod = parent_mod.getBuiltinDependency(),
+ .builtin_modules = null, // `builtin_mod` is set
}) catch |err| switch (err) {
// None of these are possible because we are creating a package with
// the exact same configuration as the parent package, which already
@@ -5900,7 +5928,6 @@ fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index, force_compt
.sema = sema,
.src_decl = parent_block.src_decl,
.namespace = parent_block.namespace,
- .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.label = &label,
.inlining = parent_block.inlining,
@@ -7515,7 +7542,6 @@ fn analyzeCall(
.sema = sema,
.src_decl = module_fn.owner_decl,
.namespace = fn_owner_decl.src_namespace,
- .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
.instructions = .{},
.label = null,
.inlining = &inlining,
@@ -8036,7 +8062,6 @@ fn instantiateGenericCall(
.sema = &child_sema,
.src_decl = generic_owner_func.owner_decl,
.namespace = namespace_index,
- .wip_capture_scope = try mod.createCaptureScope(fn_owner_decl.src_scope),
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -11409,7 +11434,6 @@ fn zirSwitchBlockErrUnion(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Comp
.sema = sema,
.src_decl = block.src_decl,
.namespace = block.namespace,
- .wip_capture_scope = block.wip_capture_scope,
.instructions = .{},
.label = &label,
.inlining = block.inlining,
@@ -12117,7 +12141,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_r
.sema = sema,
.src_decl = block.src_decl,
.namespace = block.namespace,
- .wip_capture_scope = block.wip_capture_scope,
.instructions = .{},
.label = &label,
.inlining = block.inlining,
@@ -12281,7 +12304,6 @@ fn analyzeSwitchRuntimeBlock(
extra_index += info.body_len;
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
const item = case_vals.items[scalar_i];
// `item` is already guaranteed to be constant known.
@@ -12339,7 +12361,6 @@ fn analyzeSwitchRuntimeBlock(
case_val_idx += items_len;
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
// Generate all possible cases as scalar prongs.
if (info.is_inline) {
@@ -12371,7 +12392,6 @@ fn analyzeSwitchRuntimeBlock(
const item_ref = Air.internedToRef(item.toIntern());
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
error.NeededSourceLocation => {
@@ -12411,7 +12431,6 @@ fn analyzeSwitchRuntimeBlock(
cases_len += 1;
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
const analyze_body = if (union_originally) blk: {
const item_val = sema.resolveConstDefinedValue(block, .unneeded, item, undefined) catch unreachable;
@@ -12557,7 +12576,6 @@ fn analyzeSwitchRuntimeBlock(
defer gpa.free(cond_body);
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
const body = sema.code.bodySlice(extra_index, info.body_len);
extra_index += info.body_len;
@@ -12618,7 +12636,6 @@ fn analyzeSwitchRuntimeBlock(
const item_ref = Air.internedToRef(item_val.toIntern());
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
const analyze_body = if (union_originally) blk: {
const field_ty = maybe_union_ty.unionFieldType(item_val, mod).?;
@@ -12669,7 +12686,6 @@ fn analyzeSwitchRuntimeBlock(
const item_ref = Air.internedToRef(item_val);
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
@@ -12700,7 +12716,6 @@ fn analyzeSwitchRuntimeBlock(
const item_ref = Air.internedToRef(cur);
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
@@ -12728,7 +12743,6 @@ fn analyzeSwitchRuntimeBlock(
cases_len += 1;
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
@@ -12754,7 +12768,6 @@ fn analyzeSwitchRuntimeBlock(
cases_len += 1;
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = child_block.wip_capture_scope;
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
@@ -12783,7 +12796,6 @@ fn analyzeSwitchRuntimeBlock(
};
case_block.instructions.shrinkRetainingCapacity(0);
- case_block.wip_capture_scope = try mod.createCaptureScope(child_block.wip_capture_scope);
if (mod.backendSupportsFeature(.is_named_enum_value) and
special.body.len != 0 and block.wantSafety() and
@@ -13327,7 +13339,7 @@ fn validateSwitchItemEnum(
const ip = &sema.mod.intern_pool;
const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
const int = ip.indexToKey(item.val).enum_tag.int;
- const field_index = ip.indexToKey(ip.typeOf(item.val)).enum_type.tagValueIndex(ip, int) orelse {
+ const field_index = ip.loadEnumType(ip.typeOf(item.val)).tagValueIndex(ip, int) orelse {
const maybe_prev_src = try range_set.add(int, int, switch_prong_src);
try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
return item.ref;
@@ -13607,15 +13619,15 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :hf field_index < ty.structFieldCount(mod);
}
},
- .struct_type => |struct_type| {
- break :hf struct_type.nameIndex(ip, field_name) != null;
+ .struct_type => {
+ break :hf ip.loadStructType(ty.toIntern()).nameIndex(ip, field_name) != null;
},
- .union_type => |union_type| {
- const union_obj = ip.loadUnionType(union_type);
- break :hf union_obj.nameIndex(ip, field_name) != null;
+ .union_type => {
+ const union_type = ip.loadUnionType(ty.toIntern());
+ break :hf union_type.loadTagType(ip).nameIndex(ip, field_name) != null;
},
- .enum_type => |enum_type| {
- break :hf enum_type.nameIndex(ip, field_name) != null;
+ .enum_type => {
+ break :hf ip.loadEnumType(ty.toIntern()).nameIndex(ip, field_name) != null;
},
.array_type => break :hf ip.stringEqlSlice(field_name, "len"),
else => {},
@@ -17264,49 +17276,19 @@ fn zirThis(
return sema.analyzeDeclVal(block, src, this_decl_index);
}
-fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
+fn zirClosureGet(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const mod = sema.mod;
- const gpa = sema.gpa;
- const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_tok;
- // Closures are not necessarily constant values. For example, the
- // code might do something like this:
- // fn foo(x: anytype) void { const S = struct {field: @TypeOf(x)}; }
- // ...in which case the closure_capture instruction has access to a runtime
- // value only. In such case only the type is saved into the scope.
- const operand = try sema.resolveInst(inst_data.operand);
- const ty = sema.typeOf(operand);
- const key: CaptureScope.Key = .{
- .zir_index = inst,
- .index = block.wip_capture_scope,
- };
- if (try sema.resolveValue(operand)) |val| {
- try mod.comptime_capture_scopes.put(gpa, key, try val.intern(ty, mod));
- } else {
- try mod.runtime_capture_scopes.put(gpa, key, ty.toIntern());
- }
-}
+ const ip = &mod.intern_pool;
+ const captures = mod.namespacePtr(block.namespace).getType(mod).getCaptures(mod);
-fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const mod = sema.mod;
- //const ip = &mod.intern_pool;
- const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].inst_node;
- var scope: CaptureScope.Index = mod.declPtr(block.src_decl).src_scope;
- assert(scope != .none);
- // Note: The target closure must be in this scope list.
- // If it's not here, the zir is invalid, or the list is broken.
- const capture_ty = while (true) {
- // Note: We don't need to add a dependency here, because
- // decls always depend on their lexical parents.
- const key: CaptureScope.Key = .{
- .zir_index = inst_data.inst,
- .index = scope,
- };
- if (mod.comptime_capture_scopes.get(key)) |val|
- return Air.internedToRef(val);
- if (mod.runtime_capture_scopes.get(key)) |ty|
- break ty;
- scope = scope.parent(mod);
- assert(scope != .none);
+ const src_node: i32 = @bitCast(extended.operand);
+ const src = LazySrcLoc.nodeOffset(src_node);
+
+ const capture_ty = switch (captures.get(ip)[extended.small].unwrap()) {
+ .@"comptime" => |index| return Air.internedToRef(index),
+ .runtime => |index| index,
+ .decl_val => |decl_index| return sema.analyzeDeclVal(block, src, decl_index),
+ .decl_ref => |decl_index| return sema.analyzeDeclRef(decl_index),
};
// The comptime case is handled already above. Runtime case below.
@@ -17322,15 +17304,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
});
break :name null;
};
- const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
+ const node = sema.owner_decl.relativeToNodeIndex(src_node);
const token = tree.nodes.items(.main_token)[node];
break :name tree.tokenSlice(token);
};
const msg = if (name) |some|
- try sema.errMsg(block, inst_data.src(), "'{s}' not accessible outside function scope", .{some})
+ try sema.errMsg(block, src, "'{s}' not accessible outside function scope", .{some})
else
- try sema.errMsg(block, inst_data.src(), "variable not accessible outside function scope", .{});
+ try sema.errMsg(block, src, "variable not accessible outside function scope", .{});
errdefer msg.destroy(sema.gpa);
// TODO add "declared here" note
@@ -17350,15 +17332,15 @@ fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
});
break :name null;
};
- const node = sema.owner_decl.relativeToNodeIndex(inst_data.src_node);
+ const node = sema.owner_decl.relativeToNodeIndex(src_node);
const token = tree.nodes.items(.main_token)[node];
break :name tree.tokenSlice(token);
};
const msg = if (name) |some|
- try sema.errMsg(block, inst_data.src(), "'{s}' not accessible from inner function", .{some})
+ try sema.errMsg(block, src, "'{s}' not accessible from inner function", .{some})
else
- try sema.errMsg(block, inst_data.src(), "variable not accessible from inner function", .{});
+ try sema.errMsg(block, src, "variable not accessible from inner function", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, LazySrcLoc.nodeOffset(0), msg, "crossed function definition here", .{});
@@ -17954,7 +17936,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} })));
},
.Enum => {
- const is_exhaustive = Value.makeBool(ip.indexToKey(ty.toIntern()).enum_type.tag_mode != .nonexhaustive);
+ const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive);
const enum_field_ty = t: {
const enum_field_ty_decl_index = (try sema.namespaceLookup(
@@ -17968,9 +17950,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
break :t enum_field_ty_decl.val.toType();
};
- const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.indexToKey(ty.toIntern()).enum_type.names.len);
+ const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len);
for (enum_field_vals, 0..) |*field_val, i| {
- const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
+ const enum_type = ip.loadEnumType(ty.toIntern());
const value_val = if (enum_type.values.len > 0)
try mod.intern_pool.getCoercedInts(
mod.gpa,
@@ -18045,7 +18027,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.indexToKey(ty.toIntern()).enum_type.namespace);
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.loadEnumType(ty.toIntern()).namespace);
const type_enum_ty = t: {
const type_enum_ty_decl_index = (try sema.namespaceLookup(
@@ -18061,7 +18043,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const field_values = .{
// tag_type: type,
- ip.indexToKey(ty.toIntern()).enum_type.tag_ty,
+ ip.loadEnumType(ty.toIntern()).tag_ty,
// fields: []const EnumField,
fields_val,
// decls: []const Declaration,
@@ -18105,14 +18087,15 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
const union_obj = mod.typeToUnion(ty).?;
+ const tag_type = union_obj.loadTagType(ip);
const layout = union_obj.getLayout(ip);
- const union_field_vals = try gpa.alloc(InternPool.Index, union_obj.field_names.len);
+ const union_field_vals = try gpa.alloc(InternPool.Index, tag_type.names.len);
defer gpa.free(union_field_vals);
for (union_field_vals, 0..) |*field_val, i| {
// TODO: write something like getCoercedInts to avoid needing to dupe
- const name = try sema.arena.dupeZ(u8, ip.stringToSlice(union_obj.field_names.get(ip)[i]));
+ const name = try sema.arena.dupeZ(u8, ip.stringToSlice(tag_type.names.get(ip)[i]));
const name_val = v: {
const new_decl_ty = try mod.arrayType(.{
.len = name.len,
@@ -18314,7 +18297,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
break :fv;
},
- .struct_type => |s| s,
+ .struct_type => ip.loadStructType(ty.toIntern()),
else => unreachable,
};
struct_field_vals = try gpa.alloc(InternPool.Index, struct_type.field_types.len);
@@ -18631,7 +18614,6 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
.sema = sema,
.src_decl = block.src_decl,
.namespace = block.namespace,
- .wip_capture_scope = block.wip_capture_scope,
.instructions = .{},
.inlining = block.inlining,
.is_comptime = false,
@@ -18710,7 +18692,6 @@ fn zirTypeofPeer(
.sema = sema,
.src_decl = block.src_decl,
.namespace = block.namespace,
- .wip_capture_scope = block.wip_capture_scope,
.instructions = .{},
.inlining = block.inlining,
.is_comptime = false,
@@ -19186,7 +19167,6 @@ fn ensurePostHoc(sema: *Sema, block: *Block, dest_block: Zir.Inst.Index) !*Label
.sema = sema,
.src_decl = block.src_decl,
.namespace = block.namespace,
- .wip_capture_scope = block.wip_capture_scope,
.instructions = .{},
.label = &labeled_block.label,
.inlining = block.inlining,
@@ -20082,7 +20062,8 @@ fn finishStructInit(
}
}
},
- .struct_type => |struct_type| {
+ .struct_type => {
+ const struct_type = ip.loadStructType(struct_ty.toIntern());
for (0..struct_type.field_types.len) |i| {
if (field_inits[i] != .none) {
// Coerce the init value to the field type.
@@ -20683,7 +20664,8 @@ fn fieldType(
try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
return Air.internedToRef(anon_struct.types.get(ip)[field_index]);
},
- .struct_type => |struct_type| {
+ .struct_type => {
+ const struct_type = ip.loadStructType(cur_ty.toIntern());
const field_index = struct_type.nameIndex(ip, field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_type, field_src, field_name);
const field_ty = struct_type.field_types.get(ip)[field_index];
@@ -20693,7 +20675,7 @@ fn fieldType(
},
.Union => {
const union_obj = mod.typeToUnion(cur_ty).?;
- const field_index = union_obj.nameIndex(ip, field_name) orelse
+ const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
const field_ty = union_obj.field_types.get(ip)[field_index];
return Air.internedToRef(field_ty);
@@ -21022,7 +21004,7 @@ fn zirReify(
.AnyFrame => return sema.failWithUseOfAsync(block, src),
.EnumLiteral => return .enum_literal_type,
.Int => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const signedness_val = try Value.fromInterned(union_val.val).fieldValue(
mod,
struct_type.nameIndex(ip, try ip.getOrPutString(gpa, "signedness")).?,
@@ -21038,7 +21020,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.Vector => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "len"),
@@ -21060,7 +21042,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.Float => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const bits_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "bits"),
@@ -21078,7 +21060,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.Pointer => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const size_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "size"),
@@ -21190,7 +21172,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.Array => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const len_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "len"),
@@ -21219,7 +21201,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.Optional => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const child_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "child"),
@@ -21231,7 +21213,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.ErrorUnion => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const error_set_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "error_set"),
@@ -21260,7 +21242,7 @@ fn zirReify(
try names.ensureUnusedCapacity(sema.arena, len);
for (0..len) |i| {
const elem_val = try payload_val.elemValue(mod, i);
- const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
+ const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "name"),
@@ -21280,7 +21262,7 @@ fn zirReify(
return Air.internedToRef(ty.toIntern());
},
.Struct => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "layout"),
@@ -21316,7 +21298,7 @@ fn zirReify(
return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
},
.Enum => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const tag_type_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "tag_type"),
@@ -21334,105 +21316,14 @@ fn zirReify(
try ip.getOrPutString(gpa, "is_exhaustive"),
).?);
- // Decls
if (decls_val.sliceLen(mod) > 0) {
return sema.fail(block, src, "reified enums must have no decls", .{});
}
- const int_tag_ty = tag_type_val.toType();
- if (int_tag_ty.zigTypeTag(mod) != .Int) {
- return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
- }
-
- // Because these things each reference each other, `undefined`
- // placeholders are used before being set after the enum type gains
- // an InternPool index.
-
- const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
- }, name_strategy, "enum", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
- errdefer {
- new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
- mod.abortAnonDecl(new_decl_index);
- }
-
- // Define our empty enum decl
- const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
- const incomplete_enum = try ip.getIncompleteEnum(gpa, .{
- .decl = new_decl_index,
- .namespace = .none,
- .fields_len = fields_len,
- .has_values = true,
- .tag_mode = if (!is_exhaustive_val.toBool())
- .nonexhaustive
- else
- .explicit,
- .tag_ty = int_tag_ty.toIntern(),
- .zir_index = .none,
- });
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer ip.remove(incomplete_enum.index);
-
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(incomplete_enum.index);
-
- for (0..fields_len) |field_i| {
- const elem_val = try fields_val.elemValue(mod, field_i);
- const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
- const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "name"),
- ).?);
- const value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "value"),
- ).?);
-
- const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
-
- if (!try sema.intFitsInType(value_val, int_tag_ty, null)) {
- // TODO: better source location
- return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
- field_name.fmt(ip),
- value_val.fmtValue(Type.comptime_int, mod),
- int_tag_ty.fmt(mod),
- });
- }
-
- if (incomplete_enum.addFieldName(ip, field_name)) |other_index| {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{
- field_name.fmt(ip),
- });
- errdefer msg.destroy(gpa);
- _ = other_index; // TODO: this note is incorrect
- try sema.errNote(block, src, msg, "other field here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
-
- if (incomplete_enum.addFieldValue(ip, (try mod.getCoerced(value_val, int_tag_ty)).toIntern())) |other| {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{value_val.fmtValue(Type.comptime_int, mod)});
- errdefer msg.destroy(gpa);
- _ = other; // TODO: this note is incorrect
- try sema.errNote(block, src, msg, "other enum tag value here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- }
-
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
- try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+ return sema.reifyEnum(block, inst, src, tag_type_val.toType(), is_exhaustive_val.toBool(), fields_val, name_strategy);
},
.Opaque => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const decls_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "decls"),
@@ -21443,45 +21334,30 @@ fn zirReify(
return sema.fail(block, src, "reified opaque must have no decls", .{});
}
- // Because these three things each reference each other,
- // `undefined` placeholders are used in two places before being set
- // after the opaque type gains an InternPool index.
+ const wip_ty = switch (try ip.getOpaqueType(gpa, .{
+ .has_namespace = false,
+ .key = .{ .reified = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ } },
+ })) {
+ .existing => |ty| return Air.internedToRef(ty),
+ .wip => |wip| wip,
+ };
+ errdefer wip_ty.cancel(ip);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
}, name_strategy, "opaque", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
- errdefer {
- new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
- mod.abortAnonDecl(new_decl_index);
- }
-
- const new_namespace_index = try mod.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .decl_index = new_decl_index,
- .file_scope = block.getFileScope(mod),
- });
- errdefer mod.destroyNamespace(new_namespace_index);
-
- const opaque_ty = try mod.intern(.{ .opaque_type = .{
- .decl = new_decl_index,
- .namespace = new_namespace_index,
- .zir_index = .none,
- } });
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer ip.remove(opaque_ty);
+ mod.declPtr(new_decl_index).owns_tv = true;
+ errdefer mod.abortAnonDecl(new_decl_index);
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(opaque_ty);
-
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+
+ return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
},
.Union => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const layout_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "layout"),
@@ -21499,216 +21375,15 @@ fn zirReify(
try ip.getOrPutString(gpa, "decls"),
).?);
- // Decls
if (decls_val.sliceLen(mod) > 0) {
return sema.fail(block, src, "reified unions must have no decls", .{});
}
const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
- const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
-
- // Tag type
- var explicit_tags_seen: []bool = &.{};
- var enum_field_names: []InternPool.NullTerminatedString = &.{};
- var enum_tag_ty: InternPool.Index = .none;
- if (tag_type_val.optionalValue(mod)) |payload_val| {
- enum_tag_ty = payload_val.toType().toIntern();
-
- const enum_type = switch (ip.indexToKey(enum_tag_ty)) {
- .enum_type => |x| x,
- else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
- };
-
- explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
- @memset(explicit_tags_seen, false);
- } else {
- enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
- }
-
- // Fields
- var any_aligned_fields: bool = false;
- var union_fields: std.MultiArrayList(struct {
- type: InternPool.Index,
- alignment: InternPool.Alignment,
- }) = .{};
- var field_name_table: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
- try field_name_table.ensureTotalCapacity(sema.arena, fields_len);
-
- for (0..fields_len) |i| {
- const elem_val = try fields_val.elemValue(mod, i);
- const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
- const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "name"),
- ).?);
- const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "type"),
- ).?);
- const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "alignment"),
- ).?);
-
- const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
-
- if (enum_field_names.len != 0) {
- enum_field_names[i] = field_name;
- }
-
- if (enum_tag_ty != .none) {
- const tag_info = ip.indexToKey(enum_tag_ty).enum_type;
- const enum_index = tag_info.nameIndex(ip, field_name) orelse {
- return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
- field_name.fmt(ip), Type.fromInterned(enum_tag_ty).fmt(mod),
- });
- };
- assert(explicit_tags_seen.len == tag_info.names.len);
- // No check for duplicate because the check already happened in order
- // to create the enum type in the first place.
- assert(!explicit_tags_seen[enum_index]);
- explicit_tags_seen[enum_index] = true;
- }
-
- const gop = field_name_table.getOrPutAssumeCapacity(field_name);
- if (gop.found_existing) {
- // TODO: better source location
- return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
- }
-
- const field_ty = type_val.toType();
- const alignment_val_int = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
- if (alignment_val_int > 0 and !math.isPowerOfTwo(alignment_val_int)) {
- // TODO: better source location
- return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{
- alignment_val_int,
- });
- }
- const field_align = Alignment.fromByteUnits(alignment_val_int);
- any_aligned_fields = any_aligned_fields or field_align != .none;
-
- try union_fields.append(sema.arena, .{
- .type = field_ty.toIntern(),
- .alignment = field_align,
- });
-
- if (field_ty.zigTypeTag(mod) == .Opaque) {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
- errdefer msg.destroy(gpa);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
- errdefer msg.destroy(gpa);
-
- const src_decl = mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
- errdefer msg.destroy(gpa);
-
- const src_decl = mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
-
- try sema.addDeclaredHereNote(msg, field_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- }
-
- if (enum_tag_ty != .none) {
- const tag_info = ip.indexToKey(enum_tag_ty).enum_type;
- if (tag_info.names.len > fields_len) {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "enum field(s) missing in union", .{});
- errdefer msg.destroy(gpa);
- assert(explicit_tags_seen.len == tag_info.names.len);
- for (tag_info.names.get(ip), 0..) |field_name, field_index| {
- if (explicit_tags_seen[field_index]) continue;
- try sema.addFieldErrNote(Type.fromInterned(enum_tag_ty), field_index, msg, "field '{}' missing, declared here", .{
- field_name.fmt(ip),
- });
- }
- try sema.addDeclaredHereNote(msg, Type.fromInterned(enum_tag_ty));
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
- }
- } else {
- enum_tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, .none);
- }
-
- // Because these three things each reference each other, `undefined`
- // placeholders are used before being set after the union type gains an
- // InternPool index.
-
- const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
- }, name_strategy, "union", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
- errdefer {
- new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
- mod.abortAnonDecl(new_decl_index);
- }
-
- const new_namespace_index = try mod.createNamespace(.{
- .parent = block.namespace.toOptional(),
- .decl_index = new_decl_index,
- .file_scope = block.getFileScope(mod),
- });
- errdefer mod.destroyNamespace(new_namespace_index);
-
- const union_ty = try ip.getUnionType(gpa, .{
- .decl = new_decl_index,
- .namespace = new_namespace_index,
- .enum_tag_ty = enum_tag_ty,
- .fields_len = fields_len,
- .zir_index = .none,
- .flags = .{
- .layout = layout,
- .status = .have_field_types,
- .runtime_tag = if (!tag_type_val.isNull(mod))
- .tagged
- else if (layout != .Auto)
- .none
- else switch (block.wantSafety()) {
- true => .safety,
- false => .none,
- },
- .any_aligned_fields = any_aligned_fields,
- .requires_comptime = .unknown,
- .assumed_runtime_bits = false,
- .assumed_pointer_aligned = false,
- .alignment = .none,
- },
- .field_types = union_fields.items(.type),
- .field_aligns = if (any_aligned_fields) union_fields.items(.alignment) else &.{},
- });
-
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(union_ty);
-
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
- try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+ return sema.reifyUnion(block, inst, src, layout, tag_type_val, fields_val, name_strategy);
},
.Fn => {
- const struct_type = ip.indexToKey(ip.typeOf(union_val.val)).struct_type;
+ const struct_type = ip.loadStructType(ip.typeOf(union_val.val));
const calling_convention_val = try Value.fromInterned(union_val.val).fieldValue(mod, struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "calling_convention"),
@@ -21759,7 +21434,7 @@ fn zirReify(
var noalias_bits: u32 = 0;
for (param_types, 0..) |*param_type, i| {
const elem_val = try params_val.elemValue(mod, i);
- const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
+ const elem_struct_type = ip.loadStructType(ip.typeOf(elem_val.toIntern()));
const param_is_generic_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
ip,
try ip.getOrPutString(gpa, "is_generic"),
@@ -21804,126 +21479,492 @@ fn zirReify(
}
}
-fn reifyStruct(
+fn reifyEnum(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
src: LazySrcLoc,
- layout: std.builtin.Type.ContainerLayout,
- backing_int_val: Value,
+ tag_ty: Type,
+ is_exhaustive: bool,
fields_val: Value,
name_strategy: Zir.Inst.NameStrategy,
- is_tuple: bool,
) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const gpa = sema.gpa;
const ip = &mod.intern_pool;
- if (is_tuple) switch (layout) {
- .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
- .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
- .Auto => {},
+ // This logic must stay in sync with the structure of `std.builtin.Type.Enum` - search for `fieldValue`.
+
+ const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
+
+ // The validation work here is non-trivial, and it's possible the type already exists.
+ // So in this first pass, let's just construct a hash to optimize for this case. If the
+ // inputs turn out to be invalid, we can cancel the WIP type later.
+
+ // For deduplication purposes, we must create a hash including all details of this type.
+ // TODO: use a longer hash!
+ var hasher = std.hash.Wyhash.init(0);
+ std.hash.autoHash(&hasher, tag_ty.toIntern());
+ std.hash.autoHash(&hasher, is_exhaustive);
+ std.hash.autoHash(&hasher, fields_len);
+
+ for (0..fields_len) |field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
+
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
+
+ std.hash.autoHash(&hasher, .{
+ field_name,
+ field_value_val.toIntern(),
+ });
+ }
+
+ const wip_ty = switch (try ip.getEnumType(gpa, .{
+ .has_namespace = false,
+ .has_values = true,
+ .tag_mode = if (is_exhaustive) .explicit else .nonexhaustive,
+ .fields_len = fields_len,
+ .key = .{ .reified = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ .type_hash = hasher.final(),
+ } },
+ })) {
+ .wip => |wip| wip,
+ .existing => |ty| return Air.internedToRef(ty),
};
+ errdefer wip_ty.cancel(ip);
+
+ if (tag_ty.zigTypeTag(mod) != .Int) {
+ return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
+ }
+
+ const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
+ }, name_strategy, "enum", inst);
+ mod.declPtr(new_decl_index).owns_tv = true;
+ errdefer mod.abortAnonDecl(new_decl_index);
+
+ wip_ty.prepare(ip, new_decl_index, .none);
+ wip_ty.setTagTy(ip, tag_ty.toIntern());
+
+ for (0..fields_len) |field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_value_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 1));
+
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
+
+ if (!try sema.intFitsInType(field_value_val, tag_ty, null)) {
+ // TODO: better source location
+ return sema.fail(block, src, "field '{}' with enumeration value '{}' is too large for backing int type '{}'", .{
+ field_name.fmt(ip),
+ field_value_val.fmtValue(Type.comptime_int, mod),
+ tag_ty.fmt(mod),
+ });
+ }
+
+ const coerced_field_val = try mod.getCoerced(field_value_val, tag_ty);
+ if (wip_ty.nextField(ip, field_name, coerced_field_val.toIntern())) |conflict| {
+ return sema.failWithOwnedErrorMsg(block, switch (conflict.kind) {
+ .name => msg: {
+ const msg = try sema.errMsg(block, src, "duplicate enum field '{}'", .{field_name.fmt(ip)});
+ errdefer msg.destroy(gpa);
+ _ = conflict.prev_field_idx; // TODO: this note is incorrect
+ try sema.errNote(block, src, msg, "other field here", .{});
+ break :msg msg;
+ },
+ .value => msg: {
+ const msg = try sema.errMsg(block, src, "enum tag value {} already taken", .{field_value_val.fmtValue(Type.comptime_int, mod)});
+ errdefer msg.destroy(gpa);
+ _ = conflict.prev_field_idx; // TODO: this note is incorrect
+ try sema.errNote(block, src, msg, "other enum tag value here", .{});
+ break :msg msg;
+ },
+ });
+ }
+ }
- const fields_len: u32 = @intCast(try sema.usizeCast(block, src, fields_val.sliceLen(mod)));
+ if (!is_exhaustive and fields_len > 1 and std.math.log2_int(u64, fields_len) == tag_ty.bitSize(mod)) {
+ return sema.fail(block, src, "non-exhaustive enum specified every value", .{});
+ }
- // Because these three things each reference each other, `undefined`
- // placeholders are used before being set after the struct type gains an
- // InternPool index.
+ try mod.finalizeAnonDecl(new_decl_index);
+ return Air.internedToRef(wip_ty.index);
+}
+
+fn reifyUnion(
+ sema: *Sema,
+ block: *Block,
+ inst: Zir.Inst.Index,
+ src: LazySrcLoc,
+ layout: std.builtin.Type.ContainerLayout,
+ opt_tag_type_val: Value,
+ fields_val: Value,
+ name_strategy: Zir.Inst.NameStrategy,
+) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+
+ // This logic must stay in sync with the structure of `std.builtin.Type.Union` - search for `fieldValue`.
+
+ const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
+
+ // The validation work here is non-trivial, and it's possible the type already exists.
+ // So in this first pass, let's just construct a hash to optimize for this case. If the
+ // inputs turn out to be invalid, we can cancel the WIP type later.
+
+ // For deduplication purposes, we must create a hash including all details of this type.
+ // TODO: use a longer hash!
+ var hasher = std.hash.Wyhash.init(0);
+ std.hash.autoHash(&hasher, layout);
+ std.hash.autoHash(&hasher, opt_tag_type_val.toIntern());
+ std.hash.autoHash(&hasher, fields_len);
+
+ var any_aligns = false;
+
+ for (0..fields_len) |field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_type_val = try field_info.fieldValue(mod, 1);
+ const field_align_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 2));
+
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
+
+ std.hash.autoHash(&hasher, .{
+ field_name,
+ field_type_val.toIntern(),
+ field_align_val.toIntern(),
+ });
+
+ if (field_align_val.toUnsignedInt(mod) != 0) {
+ any_aligns = true;
+ }
+ }
+
+ const wip_ty = switch (try ip.getUnionType(gpa, .{
+ .flags = .{
+ .layout = layout,
+ .status = .none,
+ .runtime_tag = if (opt_tag_type_val.optionalValue(mod) != null)
+ .tagged
+ else if (layout != .Auto)
+ .none
+ else switch (block.wantSafety()) {
+ true => .safety,
+ false => .none,
+ },
+ .any_aligned_fields = any_aligns,
+ .requires_comptime = .unknown,
+ .assumed_runtime_bits = false,
+ .assumed_pointer_aligned = false,
+ .alignment = .none,
+ },
+ .has_namespace = false,
+ .fields_len = fields_len,
+ .enum_tag_ty = .none, // set later because not yet validated
+ .field_types = &.{}, // set later
+ .field_aligns = &.{}, // set later
+ .key = .{ .reified = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ .type_hash = hasher.final(),
+ } },
+ })) {
+ .wip => |wip| wip,
+ .existing => |ty| return Air.internedToRef(ty),
+ };
+ errdefer wip_ty.cancel(ip);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
- }, name_strategy, "struct", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
- errdefer {
- new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
- mod.abortAnonDecl(new_decl_index);
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
+ }, name_strategy, "union", inst);
+ mod.declPtr(new_decl_index).owns_tv = true;
+ errdefer mod.abortAnonDecl(new_decl_index);
+
+ const field_types = try sema.arena.alloc(InternPool.Index, fields_len);
+ const field_aligns = if (any_aligns) try sema.arena.alloc(InternPool.Alignment, fields_len) else undefined;
+
+ const enum_tag_ty, const has_explicit_tag = if (opt_tag_type_val.optionalValue(mod)) |tag_type_val| tag_ty: {
+ switch (ip.indexToKey(tag_type_val.toIntern())) {
+ .enum_type => {},
+ else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
+ }
+ const enum_tag_ty = tag_type_val.toType();
+
+ // We simply track which fields of the tag type have been seen.
+ const tag_ty_fields_len = enum_tag_ty.enumFieldCount(mod);
+ var seen_tags = try std.DynamicBitSetUnmanaged.initEmpty(sema.arena, tag_ty_fields_len);
+
+ for (field_types, 0..) |*field_ty, field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_type_val = try field_info.fieldValue(mod, 1);
+
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
+
+ const enum_index = enum_tag_ty.enumFieldIndex(field_name, mod) orelse {
+ // TODO: better source location
+ return sema.fail(block, src, "no field named '{}' in enum '{}'", .{
+ field_name.fmt(ip), enum_tag_ty.fmt(mod),
+ });
+ };
+ if (seen_tags.isSet(enum_index)) {
+ // TODO: better source location
+ return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
+ }
+ seen_tags.set(enum_index);
+
+ field_ty.* = field_type_val.toIntern();
+ if (any_aligns) {
+ const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
+ if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
+ // TODO: better source location
+ return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
+ }
+ field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
+ }
+ }
+
+ if (tag_ty_fields_len > fields_len) return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(block, src, "enum fields missing in union", .{});
+ errdefer msg.destroy(gpa);
+ var it = seen_tags.iterator(.{ .kind = .unset });
+ while (it.next()) |enum_index| {
+ const field_name = enum_tag_ty.enumFieldName(enum_index, mod);
+ try sema.addFieldErrNote(enum_tag_ty, enum_index, msg, "field '{}' missing, declared here", .{
+ field_name.fmt(ip),
+ });
+ }
+ try sema.addDeclaredHereNote(msg, enum_tag_ty);
+ break :msg msg;
+ });
+
+ break :tag_ty .{ enum_tag_ty.toIntern(), true };
+ } else tag_ty: {
+ // We must track field names and set up the tag type ourselves.
+ var field_names: std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void) = .{};
+ try field_names.ensureTotalCapacity(sema.arena, fields_len);
+
+ for (field_types, 0..) |*field_ty, field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_type_val = try field_info.fieldValue(mod, 1);
+
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
+ const gop = field_names.getOrPutAssumeCapacity(field_name);
+ if (gop.found_existing) {
+ // TODO: better source location
+ return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
+ }
+
+ field_ty.* = field_type_val.toIntern();
+ if (any_aligns) {
+ const byte_align = try (try field_info.fieldValue(mod, 2)).toUnsignedIntAdvanced(sema);
+ if (byte_align > 0 and !math.isPowerOfTwo(byte_align)) {
+ // TODO: better source location
+ return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
+ }
+ field_aligns[field_idx] = Alignment.fromByteUnits(byte_align);
+ }
+ }
+
+ const enum_tag_ty = try sema.generateUnionTagTypeSimple(block, field_names.keys(), mod.declPtr(new_decl_index));
+ break :tag_ty .{ enum_tag_ty, false };
+ };
+ errdefer if (!has_explicit_tag) ip.remove(enum_tag_ty); // remove generated tag type on error
+
+ for (field_types) |field_ty_ip| {
+ const field_ty = Type.fromInterned(field_ty_ip);
+ if (field_ty.zigTypeTag(mod) == .Opaque) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in unions", .{});
+ errdefer msg.destroy(gpa);
+
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
+ if (layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(block, src, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
+ errdefer msg.destroy(gpa);
+
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, src_decl.toSrcLoc(src, mod), field_ty, .union_field);
+
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ } else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
+ return sema.failWithOwnedErrorMsg(block, msg: {
+ const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
+ errdefer msg.destroy(gpa);
+
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotPacked(msg, src_decl.toSrcLoc(src, mod), field_ty);
+
+ try sema.addDeclaredHereNote(msg, field_ty);
+ break :msg msg;
+ });
+ }
}
- const ty = try ip.getStructType(gpa, .{
- .decl = new_decl_index,
- .namespace = .none,
- .zir_index = .none,
+ const loaded_union = ip.loadUnionType(wip_ty.index);
+ loaded_union.setFieldTypes(ip, field_types);
+ if (any_aligns) {
+ loaded_union.setFieldAligns(ip, field_aligns);
+ }
+ loaded_union.tagTypePtr(ip).* = enum_tag_ty;
+ loaded_union.flagsPtr(ip).status = .have_field_types;
+
+ try mod.finalizeAnonDecl(new_decl_index);
+ return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
+}
+
+fn reifyStruct(
+ sema: *Sema,
+ block: *Block,
+ inst: Zir.Inst.Index,
+ src: LazySrcLoc,
+ layout: std.builtin.Type.ContainerLayout,
+ opt_backing_int_val: Value,
+ fields_val: Value,
+ name_strategy: Zir.Inst.NameStrategy,
+ is_tuple: bool,
+) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+
+ // This logic must stay in sync with the structure of `std.builtin.Type.Struct` - search for `fieldValue`.
+
+ const fields_len: u32 = @intCast(fields_val.sliceLen(mod));
+
+ // The validation work here is non-trivial, and it's possible the type already exists.
+ // So in this first pass, let's just construct a hash to optimize for this case. If the
+ // inputs turn out to be invalid, we can cancel the WIP type later.
+
+ // For deduplication purposes, we must create a hash including all details of this type.
+ // TODO: use a longer hash!
+ var hasher = std.hash.Wyhash.init(0);
+ std.hash.autoHash(&hasher, layout);
+ std.hash.autoHash(&hasher, opt_backing_int_val.toIntern());
+ std.hash.autoHash(&hasher, is_tuple);
+ std.hash.autoHash(&hasher, fields_len);
+
+ var any_comptime_fields = false;
+ var any_default_inits = false;
+ var any_aligned_fields = false;
+
+ for (0..fields_len) |field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_type_val = try field_info.fieldValue(mod, 1);
+ const field_default_value_val = try field_info.fieldValue(mod, 2);
+ const field_is_comptime_val = try field_info.fieldValue(mod, 3);
+ const field_alignment_val = try sema.resolveLazyValue(try field_info.fieldValue(mod, 4));
+
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
+ const field_is_comptime = field_is_comptime_val.toBool();
+ const field_default_value: InternPool.Index = if (field_default_value_val.optionalValue(mod)) |ptr_val| d: {
+ const ptr_ty = try mod.singleConstPtrType(field_type_val.toType());
+ // We need to do this deref here, so we won't check for this error case later on.
+ const val = try sema.pointerDeref(block, src, ptr_val, ptr_ty) orelse return sema.failWithNeededComptime(
+ block,
+ src,
+ .{ .needed_comptime_reason = "struct field default value must be comptime-known" },
+ );
+ // Resolve the value so that lazy values do not create distinct types.
+ break :d (try sema.resolveLazyValue(val)).toIntern();
+ } else .none;
+
+ std.hash.autoHash(&hasher, .{
+ field_name,
+ field_type_val.toIntern(),
+ field_default_value,
+ field_is_comptime,
+ field_alignment_val.toIntern(),
+ });
+
+ if (field_is_comptime) any_comptime_fields = true;
+ if (field_default_value != .none) any_default_inits = true;
+ switch (try field_alignment_val.orderAgainstZeroAdvanced(mod, sema)) {
+ .eq => {},
+ .gt => any_aligned_fields = true,
+ .lt => unreachable,
+ }
+ }
+
+ const wip_ty = switch (try ip.getStructType(gpa, .{
.layout = layout,
- .known_non_opv = false,
.fields_len = fields_len,
+ .known_non_opv = false,
.requires_comptime = .unknown,
.is_tuple = is_tuple,
- // So that we don't have to scan ahead, we allocate space in the struct
- // type for alignments, comptime fields, and default inits. This might
- // result in wasted space, however, this is a permitted encoding of
- // struct types.
- .any_comptime_fields = true,
- .any_default_inits = true,
+ .any_comptime_fields = any_comptime_fields,
+ .any_default_inits = any_default_inits,
+ .any_aligned_fields = any_aligned_fields,
.inits_resolved = true,
- .any_aligned_fields = true,
- });
- // TODO: figure out InternPool removals for incremental compilation
- //errdefer ip.remove(ty);
- const struct_type = ip.indexToKey(ty).struct_type;
+ .has_namespace = false,
+ .key = .{ .reified = .{
+ .zir_index = try ip.trackZir(gpa, block.getFileScope(mod), inst),
+ .type_hash = hasher.final(),
+ } },
+ })) {
+ .wip => |wip| wip,
+ .existing => |ty| return Air.internedToRef(ty),
+ };
+ errdefer wip_ty.cancel(ip);
- new_decl.ty = Type.type;
- new_decl.val = Value.fromInterned(ty);
-
- // Fields
- for (0..fields_len) |i| {
- const elem_val = try fields_val.elemValue(mod, i);
- const elem_struct_type = ip.indexToKey(ip.typeOf(elem_val.toIntern())).struct_type;
- const name_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "name"),
- ).?);
- const type_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "type"),
- ).?);
- const default_value_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "default_value"),
- ).?);
- const is_comptime_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "is_comptime"),
- ).?);
- const alignment_val = try elem_val.fieldValue(mod, elem_struct_type.nameIndex(
- ip,
- try ip.getOrPutString(gpa, "alignment"),
- ).?);
-
- if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
- return sema.fail(block, src, "alignment must fit in 'u32'", .{});
- }
- const abi_align = (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?;
-
- if (layout == .Packed) {
- if (abi_align != 0) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
- if (is_comptime_val.toBool()) return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{});
- } else {
- if (abi_align > 0 and !math.isPowerOfTwo(abi_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{abi_align});
- struct_type.field_aligns.get(ip)[i] = Alignment.fromByteUnits(abi_align);
- }
- if (layout == .Extern and is_comptime_val.toBool()) {
- return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
- }
+ if (is_tuple) switch (layout) {
+ .Extern => return sema.fail(block, src, "extern tuples are not supported", .{}),
+ .Packed => return sema.fail(block, src, "packed tuples are not supported", .{}),
+ .Auto => {},
+ };
- const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
+ const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
+ .ty = Type.type,
+ .val = Value.fromInterned(wip_ty.index),
+ }, name_strategy, "struct", inst);
+ mod.declPtr(new_decl_index).owns_tv = true;
+ errdefer mod.abortAnonDecl(new_decl_index);
+
+ const struct_type = ip.loadStructType(wip_ty.index);
+ for (0..fields_len) |field_idx| {
+ const field_info = try fields_val.elemValue(mod, field_idx);
+
+ const field_name_val = try field_info.fieldValue(mod, 0);
+ const field_type_val = try field_info.fieldValue(mod, 1);
+ const field_default_value_val = try field_info.fieldValue(mod, 2);
+ const field_is_comptime_val = try field_info.fieldValue(mod, 3);
+ const field_alignment_val = try field_info.fieldValue(mod, 4);
+
+ const field_ty = field_type_val.toType();
+ const field_name = try field_name_val.toIpString(Type.slice_const_u8, mod);
if (is_tuple) {
- const field_index = field_name.toUnsigned(ip) orelse return sema.fail(
+ const field_name_index = field_name.toUnsigned(ip) orelse return sema.fail(
block,
src,
"tuple cannot have non-numeric field '{}'",
.{field_name.fmt(ip)},
);
-
- if (field_index >= fields_len) {
+ if (field_name_index != field_idx) {
return sema.fail(
block,
src,
- "tuple field {} exceeds tuple field count",
- .{field_index},
+ "tuple field name '{}' does not match field index {}",
+ .{ field_name_index, field_idx },
);
}
} else if (struct_type.addFieldName(ip, field_name)) |prev_index| {
@@ -21931,45 +21972,72 @@ fn reifyStruct(
return sema.fail(block, src, "duplicate struct field name {}", .{field_name.fmt(ip)});
}
- const field_ty = type_val.toType();
- const default_val = if (default_value_val.optionalValue(mod)) |opt_val|
- (try sema.pointerDeref(block, src, opt_val, try mod.singleConstPtrType(field_ty)) orelse
- return sema.failWithNeededComptime(block, src, .{
- .needed_comptime_reason = "struct field default value must be comptime-known",
- })).toIntern()
- else
- .none;
- if (is_comptime_val.toBool() and default_val == .none) {
+ if (any_aligned_fields) {
+ if (!try sema.intFitsInType(field_alignment_val, Type.u32, null)) {
+ return sema.fail(block, src, "alignment must fit in 'u32'", .{});
+ }
+
+ const byte_align = try field_alignment_val.toUnsignedIntAdvanced(sema);
+ if (byte_align == 0) {
+ if (layout != .Packed) {
+ struct_type.field_aligns.get(ip)[field_idx] = .none;
+ }
+ } else {
+ if (layout == .Packed) return sema.fail(block, src, "alignment in a packed struct field must be set to 0", .{});
+ if (!math.isPowerOfTwo(byte_align)) return sema.fail(block, src, "alignment value '{d}' is not a power of two or zero", .{byte_align});
+ struct_type.field_aligns.get(ip)[field_idx] = Alignment.fromNonzeroByteUnits(byte_align);
+ }
+ }
+
+ const field_is_comptime = field_is_comptime_val.toBool();
+ if (field_is_comptime) {
+ assert(any_comptime_fields);
+ switch (layout) {
+ .Extern => return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{}),
+ .Packed => return sema.fail(block, src, "packed struct fields cannot be marked comptime", .{}),
+ .Auto => struct_type.setFieldComptime(ip, field_idx),
+ }
+ }
+
+ const field_default: InternPool.Index = d: {
+ if (!any_default_inits) break :d .none;
+ const ptr_val = field_default_value_val.optionalValue(mod) orelse break :d .none;
+ const ptr_ty = try mod.singleConstPtrType(field_ty);
+ // Asserted comptime-dereferencable above.
+ const val = (try sema.pointerDeref(block, src, ptr_val, ptr_ty)).?;
+ // We already resolved this for deduplication, so we may as well do it now.
+ break :d (try sema.resolveLazyValue(val)).toIntern();
+ };
+
+ if (field_is_comptime and field_default == .none) {
return sema.fail(block, src, "comptime field without default initialization value", .{});
}
- struct_type.field_types.get(ip)[i] = field_ty.toIntern();
- struct_type.field_inits.get(ip)[i] = default_val;
- if (is_comptime_val.toBool())
- struct_type.setFieldComptime(ip, i);
+ struct_type.field_types.get(ip)[field_idx] = field_type_val.toIntern();
+ if (field_default != .none) {
+ struct_type.field_inits.get(ip)[field_idx] = field_default;
+ }
if (field_ty.zigTypeTag(mod) == .Opaque) {
- const msg = msg: {
+ return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(block, src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
+ });
}
if (field_ty.zigTypeTag(mod) == .NoReturn) {
- const msg = msg: {
+ return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});
errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
+ });
}
if (layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
- const msg = msg: {
+ return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
errdefer msg.destroy(gpa);
@@ -21978,10 +22046,9 @@ fn reifyStruct(
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
+ });
} else if (layout == .Packed and !try sema.validatePackedType(field_ty)) {
- const msg = msg: {
+ return sema.failWithOwnedErrorMsg(block, msg: {
const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
errdefer msg.destroy(gpa);
@@ -21990,32 +22057,27 @@ fn reifyStruct(
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(block, msg);
+ });
}
}
if (layout == .Packed) {
- for (0..struct_type.field_types.len) |index| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[index]);
+ var fields_bit_sum: u64 = 0;
+ for (0..struct_type.field_types.len) |field_idx| {
+ const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[field_idx]);
sema.resolveTypeLayout(field_ty) catch |err| switch (err) {
error.AnalysisFail => {
const msg = sema.err orelse return err;
- try sema.addFieldErrNote(Type.fromInterned(ty), index, msg, "while checking this field", .{});
+ try sema.errNote(block, src, msg, "while checking a field of this struct", .{});
return err;
},
else => return err,
};
- }
-
- var fields_bit_sum: u64 = 0;
- for (0..struct_type.field_types.len) |i| {
- const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]);
fields_bit_sum += field_ty.bitSize(mod);
}
- if (backing_int_val.optionalValue(mod)) |backing_int_ty_val| {
- const backing_int_ty = backing_int_ty_val.toType();
+ if (opt_backing_int_val.optionalValue(mod)) |backing_int_val| {
+ const backing_int_ty = backing_int_val.toType();
try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
struct_type.backingIntType(ip).* = backing_int_ty.toIntern();
} else {
@@ -22024,9 +22086,8 @@ fn reifyStruct(
}
}
- const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
try mod.finalizeAnonDecl(new_decl_index);
- return decl_val;
+ return Air.internedToRef(wip_ty.finish(ip, new_decl_index, .none));
}
fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
@@ -23241,7 +23302,7 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
switch (ty.containerLayout(mod)) {
.Packed => {
var bit_sum: u64 = 0;
- const struct_type = ip.indexToKey(ty.toIntern()).struct_type;
+ const struct_type = ip.loadStructType(ty.toIntern());
for (0..struct_type.field_types.len) |i| {
if (i == field_index) {
return bit_sum;
@@ -25919,7 +25980,7 @@ fn zirBuiltinExtern(
// TODO check duplicate extern
- const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, .none);
+ const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node);
errdefer mod.destroyDecl(new_decl_index);
const new_decl = mod.declPtr(new_decl_index);
new_decl.name = options.name;
@@ -26515,7 +26576,6 @@ fn addSafetyCheck(
.sema = sema,
.src_decl = parent_block.src_decl,
.namespace = parent_block.namespace,
- .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.inlining = parent_block.inlining,
.is_comptime = false,
@@ -26624,7 +26684,6 @@ fn panicUnwrapError(
.sema = sema,
.src_decl = parent_block.src_decl,
.namespace = parent_block.namespace,
- .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.inlining = parent_block.inlining,
.is_comptime = false,
@@ -26741,7 +26800,6 @@ fn safetyCheckFormatted(
.sema = sema,
.src_decl = parent_block.src_decl,
.namespace = parent_block.namespace,
- .wip_capture_scope = parent_block.wip_capture_scope,
.instructions = .{},
.inlining = parent_block.inlining,
.is_comptime = false,
@@ -27268,8 +27326,7 @@ fn fieldCallBind(
.Union => {
try sema.resolveTypeFields(concrete_ty);
const union_obj = mod.typeToUnion(concrete_ty).?;
- _ = union_obj.nameIndex(ip, field_name) orelse break :find_field;
-
+ _ = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse break :find_field;
const field_ptr = try unionFieldPtr(sema, block, src, object_ptr, field_name, field_name_src, concrete_ty, false);
return .{ .direct = try sema.analyzeLoad(block, src, field_ptr, src) };
},
@@ -27643,7 +27700,8 @@ fn structFieldVal(
try sema.resolveTypeFields(struct_ty);
switch (ip.indexToKey(struct_ty.toIntern())) {
- .struct_type => |struct_type| {
+ .struct_type => {
+ const struct_type = ip.loadStructType(struct_ty.toIntern());
if (struct_type.isTuple(ip))
return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
@@ -27849,7 +27907,7 @@ fn unionFieldPtr(
try sema.requireRuntimeBlock(block, src, null);
if (!initializing and union_obj.getLayout(ip) == .Auto and block.wantSafety() and
- union_ty.unionTagTypeSafety(mod) != null and union_obj.field_names.len > 1)
+ union_ty.unionTagTypeSafety(mod) != null and union_obj.field_types.len > 1)
{
const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
@@ -27927,7 +27985,7 @@ fn unionFieldVal(
try sema.requireRuntimeBlock(block, src, null);
if (union_obj.getLayout(ip) == .Auto and block.wantSafety() and
- union_ty.unionTagTypeSafety(mod) != null and union_obj.field_names.len > 1)
+ union_ty.unionTagTypeSafety(mod) != null and union_obj.field_types.len > 1)
{
const wanted_tag_val = try mod.enumValueFieldIndex(Type.fromInterned(union_obj.enum_tag_ty), enum_field_index);
const wanted_tag = Air.internedToRef(wanted_tag_val.toIntern());
@@ -31686,7 +31744,7 @@ fn coerceEnumToUnion(
const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
errdefer msg.destroy(sema.gpa);
- const field_name = union_obj.field_names.get(ip)[field_index];
+ const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
field_name.fmt(ip),
});
@@ -31697,7 +31755,7 @@ fn coerceEnumToUnion(
}
const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
const msg = msg: {
- const field_name = union_obj.field_names.get(ip)[field_index];
+ const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{}'", .{
inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod),
field_ty.fmt(sema.mod), field_name.fmt(ip),
@@ -31769,8 +31827,8 @@ fn coerceEnumToUnion(
);
errdefer msg.destroy(sema.gpa);
- for (0..union_obj.field_names.len) |field_index| {
- const field_name = union_obj.field_names.get(ip)[field_index];
+ for (0..union_obj.field_types.len) |field_index| {
+ const field_name = union_obj.loadTagType(ip).names.get(ip)[field_index];
const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{
@@ -31803,8 +31861,8 @@ fn coerceAnonStructToUnion(
.{ .name = anon_struct_type.names.get(ip)[0] }
else
.{ .count = anon_struct_type.names.len },
- .struct_type => |struct_type| name: {
- const field_names = struct_type.field_names.get(ip);
+ .struct_type => name: {
+ const field_names = ip.loadStructType(inst_ty.toIntern()).field_names.get(ip);
break :name if (field_names.len == 1)
.{ .name = field_names[0] }
else
@@ -32113,7 +32171,7 @@ fn coerceTupleToStruct(
var runtime_src: ?LazySrcLoc = null;
const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
- .struct_type => |s| s.field_types.len,
+ .struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len,
else => unreachable,
};
for (0..field_count) |field_index_usize| {
@@ -32125,7 +32183,7 @@ fn coerceTupleToStruct(
anon_struct_type.names.get(ip)[field_i]
else
try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
- .struct_type => |s| s.field_names.get(ip)[field_i],
+ .struct_type => ip.loadStructType(inst_ty.toIntern()).field_names.get(ip)[field_i],
else => unreachable,
};
const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
@@ -32213,7 +32271,7 @@ fn coerceTupleToTuple(
const ip = &mod.intern_pool;
const dest_field_count = switch (ip.indexToKey(tuple_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
- .struct_type => |struct_type| struct_type.field_types.len,
+ .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.len,
else => unreachable,
};
const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
@@ -32223,7 +32281,7 @@ fn coerceTupleToTuple(
const inst_ty = sema.typeOf(inst);
const src_field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
- .struct_type => |struct_type| struct_type.field_types.len,
+ .struct_type => ip.loadStructType(inst_ty.toIntern()).field_types.len,
else => unreachable,
};
if (src_field_count > dest_field_count) return error.NotCoercible;
@@ -32238,10 +32296,14 @@ fn coerceTupleToTuple(
anon_struct_type.names.get(ip)[field_i]
else
try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
- .struct_type => |struct_type| if (struct_type.field_names.len > 0)
- struct_type.field_names.get(ip)[field_i]
- else
- try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
+ .struct_type => s: {
+ const struct_type = ip.loadStructType(inst_ty.toIntern());
+ if (struct_type.field_names.len > 0) {
+ break :s struct_type.field_names.get(ip)[field_i];
+ } else {
+ break :s try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i});
+ }
+ },
else => unreachable,
};
@@ -32250,12 +32312,12 @@ fn coerceTupleToTuple(
const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.types.get(ip)[field_index_usize],
- .struct_type => |struct_type| struct_type.field_types.get(ip)[field_index_usize],
+ .struct_type => ip.loadStructType(tuple_ty.toIntern()).field_types.get(ip)[field_index_usize],
else => unreachable,
};
const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[field_index_usize],
- .struct_type => |struct_type| struct_type.fieldInit(ip, field_index_usize),
+ .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, field_index_usize),
else => unreachable,
};
@@ -32294,7 +32356,7 @@ fn coerceTupleToTuple(
const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
.anon_struct_type => |anon_struct_type| anon_struct_type.values.get(ip)[i],
- .struct_type => |struct_type| struct_type.fieldInit(ip, i),
+ .struct_type => ip.loadStructType(tuple_ty.toIntern()).fieldInit(ip, i),
else => unreachable,
};
@@ -35534,7 +35596,7 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
pub fn resolveStructAlignment(
sema: *Sema,
ty: InternPool.Index,
- struct_type: InternPool.Key.StructType,
+ struct_type: InternPool.LoadedStructType,
) CompileError!Alignment {
const mod = sema.mod;
const ip = &mod.intern_pool;
@@ -35674,7 +35736,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
}
}
- const RuntimeOrder = InternPool.Key.StructType.RuntimeOrder;
+ const RuntimeOrder = InternPool.LoadedStructType.RuntimeOrder;
const AlignSortContext = struct {
aligns: []const Alignment,
@@ -35726,7 +35788,7 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
_ = try sema.typeRequiresComptime(ty);
}
-fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) CompileError!void {
+fn semaBackingIntType(mod: *Module, struct_type: InternPool.LoadedStructType) CompileError!void {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
@@ -35766,7 +35828,6 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
.sema = &sema,
.src_decl = decl_index,
.namespace = struct_type.namespace.unwrap() orelse decl.src_namespace,
- .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -35789,9 +35850,16 @@ fn semaBackingIntType(mod: *Module, struct_type: InternPool.Key.StructType) Comp
if (small.has_backing_int) {
var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
extra_index += @intFromBool(small.has_fields_len);
extra_index += @intFromBool(small.has_decls_len);
+ extra_index += captures_len;
+
const backing_int_body_len = zir.extra[extra_index];
extra_index += 1;
@@ -35879,7 +35947,7 @@ fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void
pub fn resolveUnionAlignment(
sema: *Sema,
ty: Type,
- union_type: InternPool.Key.UnionType,
+ union_type: InternPool.LoadedUnionType,
) CompileError!Alignment {
const mod = sema.mod;
const ip = &mod.intern_pool;
@@ -35899,13 +35967,12 @@ pub fn resolveUnionAlignment(
try sema.resolveTypeFieldsUnion(ty, union_type);
- const union_obj = ip.loadUnionType(union_type);
var max_align: Alignment = .@"1";
- for (0..union_obj.field_names.len) |field_index| {
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
+ for (0..union_type.field_types.len) |field_index| {
+ const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
- const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index));
+ const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));
const field_align = if (explicit_align != .none)
explicit_align
else
@@ -35923,16 +35990,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
const mod = sema.mod;
const ip = &mod.intern_pool;
- const union_type = ip.indexToKey(ty.ip_index).union_type;
- try sema.resolveTypeFieldsUnion(ty, union_type);
+ try sema.resolveTypeFieldsUnion(ty, ip.loadUnionType(ty.ip_index));
- const union_obj = ip.loadUnionType(union_type);
- switch (union_obj.flagsPtr(ip).status) {
+ // Load again, since the tag type might have changed due to resolution.
+ const union_type = ip.loadUnionType(ty.ip_index);
+
+ switch (union_type.flagsPtr(ip).status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
const msg = try Module.ErrorMsg.create(
sema.gpa,
- mod.declPtr(union_obj.decl).srcLoc(mod),
+ mod.declPtr(union_type.decl).srcLoc(mod),
"union '{}' depends on itself",
.{ty.fmt(mod)},
);
@@ -35941,17 +36009,17 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
.have_layout, .fully_resolved_wip, .fully_resolved => return,
}
- const prev_status = union_obj.flagsPtr(ip).status;
- errdefer if (union_obj.flagsPtr(ip).status == .layout_wip) {
- union_obj.flagsPtr(ip).status = prev_status;
+ const prev_status = union_type.flagsPtr(ip).status;
+ errdefer if (union_type.flagsPtr(ip).status == .layout_wip) {
+ union_type.flagsPtr(ip).status = prev_status;
};
- union_obj.flagsPtr(ip).status = .layout_wip;
+ union_type.flagsPtr(ip).status = .layout_wip;
var max_size: u64 = 0;
var max_align: Alignment = .@"1";
- for (0..union_obj.field_names.len) |field_index| {
- const field_ty = Type.fromInterned(union_obj.field_types.get(ip)[field_index]);
+ for (0..union_type.field_types.len) |field_index| {
+ const field_ty = Type.fromInterned(union_type.field_types.get(ip)[field_index]);
if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
max_size = @max(max_size, sema.typeAbiSize(field_ty) catch |err| switch (err) {
@@ -35963,7 +36031,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
else => return err,
});
- const explicit_align = union_obj.fieldAlign(ip, @intCast(field_index));
+ const explicit_align = union_type.fieldAlign(ip, @intCast(field_index));
const field_align = if (explicit_align != .none)
explicit_align
else
@@ -35972,10 +36040,10 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
max_align = max_align.max(field_align);
}
- const flags = union_obj.flagsPtr(ip);
- const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(Type.fromInterned(union_obj.enum_tag_ty));
+ const flags = union_type.flagsPtr(ip);
+ const has_runtime_tag = flags.runtime_tag.hasTag() and try sema.typeHasRuntimeBits(Type.fromInterned(union_type.enum_tag_ty));
const size, const alignment, const padding = if (has_runtime_tag) layout: {
- const enum_tag_type = Type.fromInterned(union_obj.enum_tag_ty);
+ const enum_tag_type = Type.fromInterned(union_type.enum_tag_ty);
const tag_align = try sema.typeAbiAlignment(enum_tag_type);
const tag_size = try sema.typeAbiSize(enum_tag_type);
@@ -36009,22 +36077,22 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
flags.alignment = alignment;
flags.status = .have_layout;
- if (union_obj.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
+ if (union_type.flagsPtr(ip).assumed_runtime_bits and !(try sema.typeHasRuntimeBits(ty))) {
const msg = try Module.ErrorMsg.create(
sema.gpa,
- mod.declPtr(union_obj.decl).srcLoc(mod),
+ mod.declPtr(union_type.decl).srcLoc(mod),
"union layout depends on it having runtime bits",
.{},
);
return sema.failWithOwnedErrorMsg(null, msg);
}
- if (union_obj.flagsPtr(ip).assumed_pointer_aligned and
+ if (union_type.flagsPtr(ip).assumed_pointer_aligned and
alignment.compareStrict(.neq, Alignment.fromByteUnits(@divExact(mod.getTarget().ptrBitWidth(), 8))))
{
const msg = try Module.ErrorMsg.create(
sema.gpa,
- mod.declPtr(union_obj.decl).srcLoc(mod),
+ mod.declPtr(union_type.decl).srcLoc(mod),
"union layout depends on being pointer aligned",
.{},
);
@@ -36212,12 +36280,11 @@ pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!void {
else => switch (ip.items.items(.tag)[@intFromEnum(ty_ip)]) {
.type_struct,
- .type_struct_ns,
.type_struct_packed,
.type_struct_packed_inits,
- => try sema.resolveTypeFieldsStruct(ty_ip, ip.indexToKey(ty_ip).struct_type),
+ => try sema.resolveTypeFieldsStruct(ty_ip, ip.loadStructType(ty_ip)),
- .type_union => try sema.resolveTypeFieldsUnion(Type.fromInterned(ty_ip), ip.indexToKey(ty_ip).union_type),
+ .type_union => try sema.resolveTypeFieldsUnion(Type.fromInterned(ty_ip), ip.loadUnionType(ty_ip)),
.simple_type => try sema.resolveSimpleType(ip.indexToKey(ty_ip).simple_type),
else => {},
},
@@ -36249,7 +36316,7 @@ fn resolveSimpleType(sema: *Sema, simple_type: InternPool.SimpleType) CompileErr
pub fn resolveTypeFieldsStruct(
sema: *Sema,
ty: InternPool.Index,
- struct_type: InternPool.Key.StructType,
+ struct_type: InternPool.LoadedStructType,
) CompileError!void {
const mod = sema.mod;
const ip = &mod.intern_pool;
@@ -36309,7 +36376,7 @@ pub fn resolveStructFieldInits(sema: *Sema, ty: Type) CompileError!void {
struct_type.setHaveFieldInits(ip);
}
-pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.Key.UnionType) CompileError!void {
+pub fn resolveTypeFieldsUnion(sema: *Sema, ty: Type, union_type: InternPool.LoadedUnionType) CompileError!void {
const mod = sema.mod;
const ip = &mod.intern_pool;
const owner_decl = mod.declPtr(union_type.decl);
@@ -36500,6 +36567,12 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
const small: Zir.Inst.StructDecl.Small = @bitCast(extended.small);
var extra_index: usize = extended.operand + @typeInfo(Zir.Inst.StructDecl).Struct.fields.len;
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+
const fields_len = if (small.has_fields_len) blk: {
const fields_len = zir.extra[extra_index];
extra_index += 1;
@@ -36512,6 +36585,8 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
break :decls_len decls_len;
} else 0;
+ extra_index += captures_len;
+
// The backing integer cannot be handled until `resolveStructLayout()`.
if (small.has_backing_int) {
const backing_int_body_len = zir.extra[extra_index];
@@ -36532,7 +36607,7 @@ fn structZirInfo(zir: Zir, zir_index: Zir.Inst.Index) struct {
fn semaStructFields(
mod: *Module,
arena: Allocator,
- struct_type: InternPool.Key.StructType,
+ struct_type: InternPool.LoadedStructType,
) CompileError!void {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
@@ -36584,7 +36659,6 @@ fn semaStructFields(
.sema = &sema,
.src_decl = decl_index,
.namespace = namespace_index,
- .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -36800,7 +36874,7 @@ fn semaStructFields(
fn semaStructFieldInits(
mod: *Module,
arena: Allocator,
- struct_type: InternPool.Key.StructType,
+ struct_type: InternPool.LoadedStructType,
) CompileError!void {
const gpa = mod.gpa;
const ip = &mod.intern_pool;
@@ -36842,7 +36916,6 @@ fn semaStructFieldInits(
.sema = &sema,
.src_decl = decl_index,
.namespace = namespace_index,
- .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -36952,15 +37025,15 @@ fn semaStructFieldInits(
}
}
-fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.UnionType) CompileError!void {
+fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.LoadedUnionType) CompileError!void {
const tracy = trace(@src());
defer tracy.end();
const gpa = mod.gpa;
const ip = &mod.intern_pool;
const decl_index = union_type.decl;
- const zir = mod.namespacePtr(union_type.namespace).file_scope.zir;
- const zir_index = union_type.zir_index.unwrap().?.resolve(ip);
+ const zir = mod.namespacePtr(union_type.namespace.unwrap().?).file_scope.zir;
+ const zir_index = union_type.zir_index.resolve(ip);
const extended = zir.instructions.items(.data)[@intFromEnum(zir_index)].extended;
assert(extended.opcode == .union_decl);
const small: Zir.Inst.UnionDecl.Small = @bitCast(extended.small);
@@ -36974,6 +37047,12 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
break :blk ty_ref;
} else .none;
+ const captures_len = if (small.has_captures_len) blk: {
+ const captures_len = zir.extra[extra_index];
+ extra_index += 1;
+ break :blk captures_len;
+ } else 0;
+
const body_len = if (small.has_body_len) blk: {
const body_len = zir.extra[extra_index];
extra_index += 1;
@@ -36992,8 +37071,8 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
break :decls_len decls_len;
} else 0;
- // Skip over decls.
- extra_index += decls_len;
+ // Skip over captures and decls.
+ extra_index += captures_len + decls_len;
const body = zir.bodySlice(extra_index, body_len);
extra_index += body.len;
@@ -37027,8 +37106,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
.parent = null,
.sema = &sema,
.src_decl = decl_index,
- .namespace = union_type.namespace,
- .wip_capture_scope = try mod.createCaptureScope(decl.src_scope),
+ .namespace = union_type.namespace.unwrap().?,
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -37079,7 +37157,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
// The provided type is the enum tag type.
union_type.tagTypePtr(ip).* = provided_ty.toIntern();
const enum_type = switch (ip.indexToKey(provided_ty.toIntern())) {
- .enum_type => |x| x,
+ .enum_type => ip.loadEnumType(provided_ty.toIntern()),
else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{provided_ty.fmt(mod)}),
};
// The fields of the union must match the enum exactly.
@@ -37216,7 +37294,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
}
if (explicit_tags_seen.len > 0) {
- const tag_info = ip.indexToKey(union_type.tagTypePtr(ip).*).enum_type;
+ const tag_info = ip.loadEnumType(union_type.tagTypePtr(ip).*);
const enum_index = tag_info.nameIndex(ip, field_name) orelse {
const ty_src = mod.fieldSrcLoc(union_type.decl, .{
.index = field_i,
@@ -37327,7 +37405,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
union_type.setFieldAligns(ip, field_aligns.items);
if (explicit_tags_seen.len > 0) {
- const tag_info = ip.indexToKey(union_type.tagTypePtr(ip).*).enum_type;
+ const tag_info = ip.loadEnumType(union_type.tagTypePtr(ip).*);
if (tag_info.names.len > fields_len) {
const msg = msg: {
const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
@@ -37348,7 +37426,7 @@ fn semaUnionFields(mod: *Module, arena: Allocator, union_type: InternPool.Key.Un
const enum_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), mod.declPtr(union_type.decl));
union_type.tagTypePtr(ip).* = enum_ty;
} else {
- const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_type.decl.toOptional());
+ const enum_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, mod.declPtr(union_type.decl));
union_type.tagTypePtr(ip).* = enum_ty;
}
}
@@ -37365,16 +37443,16 @@ fn generateUnionTagTypeNumbered(
block: *Block,
enum_field_names: []const InternPool.NullTerminatedString,
enum_field_vals: []const InternPool.Index,
- decl: *Module.Decl,
+ union_owner_decl: *Module.Decl,
) !InternPool.Index {
const mod = sema.mod;
const gpa = sema.gpa;
const ip = &mod.intern_pool;
const src_decl = mod.declPtr(block.src_decl);
- const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
+ const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
errdefer mod.destroyDecl(new_decl_index);
- const fqn = try decl.fullyQualifiedName(mod);
+ const fqn = try union_owner_decl.fullyQualifiedName(mod);
const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
.ty = Type.noreturn,
@@ -37386,9 +37464,9 @@ fn generateUnionTagTypeNumbered(
new_decl.owns_tv = true;
new_decl.name_fully_qualified = true;
- const enum_ty = try ip.getEnum(gpa, .{
+ const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
.decl = new_decl_index,
- .namespace = .none,
+ .owner_union_ty = union_owner_decl.val.toIntern(),
.tag_ty = if (enum_field_vals.len == 0)
(try mod.intType(.unsigned, 0)).toIntern()
else
@@ -37396,7 +37474,6 @@ fn generateUnionTagTypeNumbered(
.names = enum_field_names,
.values = enum_field_vals,
.tag_mode = .explicit,
- .zir_index = .none,
});
new_decl.ty = Type.type;
@@ -37410,22 +37487,16 @@ fn generateUnionTagTypeSimple(
sema: *Sema,
block: *Block,
enum_field_names: []const InternPool.NullTerminatedString,
- maybe_decl_index: InternPool.OptionalDeclIndex,
+ union_owner_decl: *Module.Decl,
) !InternPool.Index {
const mod = sema.mod;
const ip = &mod.intern_pool;
const gpa = sema.gpa;
const new_decl_index = new_decl_index: {
- const decl_index = maybe_decl_index.unwrap() orelse {
- break :new_decl_index try mod.createAnonymousDecl(block, .{
- .ty = Type.noreturn,
- .val = Value.@"unreachable",
- });
- };
- const fqn = try mod.declPtr(decl_index).fullyQualifiedName(mod);
+ const fqn = try union_owner_decl.fullyQualifiedName(mod);
const src_decl = mod.declPtr(block.src_decl);
- const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node, block.wip_capture_scope);
+ const new_decl_index = try mod.allocateNewDecl(block.namespace, src_decl.src_node);
errdefer mod.destroyDecl(new_decl_index);
const name = try ip.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(ip)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, .{
@@ -37437,9 +37508,9 @@ fn generateUnionTagTypeSimple(
};
errdefer mod.abortAnonDecl(new_decl_index);
- const enum_ty = try ip.getEnum(gpa, .{
+ const enum_ty = try ip.getGeneratedTagEnumType(gpa, .{
.decl = new_decl_index,
- .namespace = .none,
+ .owner_union_ty = union_owner_decl.val.toIntern(),
.tag_ty = if (enum_field_names.len == 0)
(try mod.intType(.unsigned, 0)).toIntern()
else
@@ -37447,7 +37518,6 @@ fn generateUnionTagTypeSimple(
.names = enum_field_names,
.values = &.{},
.tag_mode = .auto,
- .zir_index = .none,
});
const new_decl = mod.declPtr(new_decl_index);
@@ -37460,7 +37530,6 @@ fn generateUnionTagTypeSimple(
}
fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
- const mod = sema.mod;
const gpa = sema.gpa;
const src = LazySrcLoc.nodeOffset(0);
@@ -37469,7 +37538,6 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
.sema = sema,
.src_decl = sema.owner_decl_index,
.namespace = sema.owner_decl.src_namespace,
- .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -37510,7 +37578,6 @@ fn getBuiltinDecl(sema: *Sema, block: *Block, name: []const u8) CompileError!Int
}
fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
- const mod = sema.mod;
const ty_inst = try sema.getBuiltin(name);
var block: Block = .{
@@ -37518,7 +37585,6 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
.sema = sema,
.src_decl = sema.owner_decl_index,
.namespace = sema.owner_decl.src_namespace,
- .wip_capture_scope = try mod.createCaptureScope(sema.owner_decl.src_scope),
.instructions = .{},
.inlining = null,
.is_comptime = true,
@@ -37636,6 +37702,8 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
=> unreachable,
_ => switch (ip.items.items(.tag)[@intFromEnum(ty.toIntern())]) {
+ .removed => unreachable,
+
.type_int_signed, // i0 handled above
.type_int_unsigned, // u0 handled above
.type_pointer,
@@ -37713,7 +37781,6 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
.type_enum_explicit,
.type_enum_nonexhaustive,
.type_struct,
- .type_struct_ns,
.type_struct_anon,
.type_struct_packed,
.type_struct_packed_inits,
@@ -37736,8 +37803,9 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
return null;
},
- .struct_type => |struct_type| {
- try sema.resolveTypeFields(ty);
+ .struct_type => {
+ const struct_type = ip.loadStructType(ty.toIntern());
+ try sema.resolveTypeFieldsStruct(ty.toIntern(), struct_type);
if (struct_type.field_types.len == 0) {
// In this case the struct has no fields at all and
@@ -37795,10 +37863,10 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
} })));
},
- .union_type => |union_type| {
- try sema.resolveTypeFields(ty);
- const union_obj = ip.loadUnionType(union_type);
- const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.enum_tag_ty))) orelse
+ .union_type => {
+ const union_obj = ip.loadUnionType(ty.toIntern());
+ try sema.resolveTypeFieldsUnion(ty, union_obj);
+ const tag_val = (try sema.typeHasOnePossibleValue(Type.fromInterned(union_obj.tagTypePtr(ip).*))) orelse
return null;
if (union_obj.field_types.len == 0) {
const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
@@ -37825,39 +37893,42 @@ pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
return Value.fromInterned(only);
},
- .enum_type => |enum_type| switch (enum_type.tag_mode) {
- .nonexhaustive => {
- if (enum_type.tag_ty == .comptime_int_type) return null;
+ .enum_type => {
+ const enum_type = ip.loadEnumType(ty.toIntern());
+ switch (enum_type.tag_mode) {
+ .nonexhaustive => {
+ if (enum_type.tag_ty == .comptime_int_type) return null;
- if (try sema.typeHasOnePossibleValue(Type.fromInterned(enum_type.tag_ty))) |int_opv| {
- const only = try mod.intern(.{ .enum_tag = .{
- .ty = ty.toIntern(),
- .int = int_opv.toIntern(),
- } });
- return Value.fromInterned(only);
- }
+ if (try sema.typeHasOnePossibleValue(Type.fromInterned(enum_type.tag_ty))) |int_opv| {
+ const only = try mod.intern(.{ .enum_tag = .{
+ .ty = ty.toIntern(),
+ .int = int_opv.toIntern(),
+ } });
+ return Value.fromInterned(only);
+ }
- return null;
- },
- .auto, .explicit => {
- if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
-
- return Value.fromInterned(switch (enum_type.names.len) {
- 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
- 1 => try mod.intern(.{ .enum_tag = .{
- .ty = ty.toIntern(),
- .int = if (enum_type.values.len == 0)
- (try mod.intValue(Type.fromInterned(enum_type.tag_ty), 0)).toIntern()
- else
- try mod.intern_pool.getCoercedInts(
- mod.gpa,
- mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
- enum_type.tag_ty,
- ),
- } }),
- else => return null,
- });
- },
+ return null;
+ },
+ .auto, .explicit => {
+ if (Type.fromInterned(enum_type.tag_ty).hasRuntimeBits(mod)) return null;
+
+ return Value.fromInterned(switch (enum_type.names.len) {
+ 0 => try mod.intern(.{ .empty_enum_value = ty.toIntern() }),
+ 1 => try mod.intern(.{ .enum_tag = .{
+ .ty = ty.toIntern(),
+ .int = if (enum_type.values.len == 0)
+ (try mod.intValue(Type.fromInterned(enum_type.tag_ty), 0)).toIntern()
+ else
+ try mod.intern_pool.getCoercedInts(
+ mod.gpa,
+ mod.intern_pool.indexToKey(enum_type.values.get(ip)[0]).int,
+ enum_type.tag_ty,
+ ),
+ } }),
+ else => return null,
+ });
+ },
+ }
},
else => unreachable,
@@ -38189,7 +38260,7 @@ fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!Alignment {
/// Not valid to call for packed unions.
/// Keep implementation in sync with `Module.unionFieldNormalAlignment`.
-fn unionFieldAlignment(sema: *Sema, u: InternPool.UnionType, field_index: u32) !Alignment {
+fn unionFieldAlignment(sema: *Sema, u: InternPool.LoadedUnionType, field_index: u32) !Alignment {
const mod = sema.mod;
const ip = &mod.intern_pool;
const field_align = u.fieldAlign(ip, field_index);
@@ -38237,7 +38308,7 @@ fn unionFieldIndex(
const ip = &mod.intern_pool;
try sema.resolveTypeFields(union_ty);
const union_obj = mod.typeToUnion(union_ty).?;
- const field_index = union_obj.nameIndex(ip, field_name) orelse
+ const field_index = union_obj.loadTagType(ip).nameIndex(ip, field_name) orelse
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
return @intCast(field_index);
}
@@ -38274,7 +38345,7 @@ fn anonStructFieldIndex(
.anon_struct_type => |anon_struct_type| for (anon_struct_type.names.get(ip), 0..) |name, i| {
if (name == field_name) return @intCast(i);
},
- .struct_type => |struct_type| if (struct_type.nameIndex(ip, field_name)) |i| return i,
+ .struct_type => if (ip.loadStructType(struct_ty.toIntern()).nameIndex(ip, field_name)) |i| return i,
else => unreachable,
}
return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{
@@ -38710,7 +38781,7 @@ fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
/// Asserts the type is an enum.
fn enumHasInt(sema: *Sema, ty: Type, int: Value) CompileError!bool {
const mod = sema.mod;
- const enum_type = mod.intern_pool.indexToKey(ty.toIntern()).enum_type;
+ const enum_type = mod.intern_pool.loadEnumType(ty.toIntern());
assert(enum_type.tag_mode != .nonexhaustive);
// The `tagValueIndex` function call below relies on the type being the integer tag type.
// `getCoerced` assumes the value will fit the new type.