aboutsummaryrefslogtreecommitdiff
path: root/src/Sema.zig
diff options
context:
space:
mode:
authorLoris Cro <kappaloris@gmail.com>2023-06-18 09:06:40 +0200
committerGitHub <noreply@github.com>2023-06-18 09:06:40 +0200
commit216ef10dc471e4db60a30208be178d6c59efeaaf (patch)
tree8c239dab283ae9cb3b7fe099bae240bcc53f894e /src/Sema.zig
parent0fc1d396495c1ab482197021dedac8bea3f9401c (diff)
parent729a051e9e38674233190aea23c0ac8c134f2d67 (diff)
downloadzig-216ef10dc471e4db60a30208be178d6c59efeaaf.tar.gz
zig-216ef10dc471e4db60a30208be178d6c59efeaaf.zip
Merge branch 'master' into autodoc-searchkey
Diffstat (limited to 'src/Sema.zig')
-rw-r--r--src/Sema.zig20623
1 files changed, 11533 insertions, 9090 deletions
diff --git a/src/Sema.zig b/src/Sema.zig
index df199be97c..36fe5a6ee8 100644
--- a/src/Sema.zig
+++ b/src/Sema.zig
@@ -11,13 +11,9 @@ gpa: Allocator,
/// Points to the temporary arena allocator of the Sema.
/// This arena will be cleared when the sema is destroyed.
arena: Allocator,
-/// Points to the arena allocator for the owner_decl.
-/// This arena will persist until the decl is invalidated.
-perm_arena: Allocator,
code: Zir,
air_instructions: std.MultiArrayList(Air.Inst) = .{},
air_extra: std.ArrayListUnmanaged(u32) = .{},
-air_values: std.ArrayListUnmanaged(Value) = .{},
/// Maps ZIR to AIR.
inst_map: InstMap = .{},
/// When analyzing an inline function call, owner_decl is the Decl of the caller
@@ -28,10 +24,12 @@ owner_decl_index: Decl.Index,
/// For an inline or comptime function call, this will be the root parent function
/// which contains the callsite. Corresponds to `owner_decl`.
owner_func: ?*Module.Fn,
+owner_func_index: Module.Fn.OptionalIndex,
/// The function this ZIR code is the body of, according to the source code.
/// This starts out the same as `owner_func` and then diverges in the case of
/// an inline or comptime function call.
func: ?*Module.Fn,
+func_index: Module.Fn.OptionalIndex,
/// Used to restore the error return trace when returning a non-error from a function.
error_return_trace_index_on_fn_entry: Air.Inst.Ref = .none,
/// When semantic analysis needs to know the return type of the function whose body
@@ -65,12 +63,15 @@ comptime_args_fn_inst: Zir.Inst.Index = 0,
/// to use this instead of allocating a fresh one. This avoids an unnecessary
/// extra hash table lookup in the `monomorphed_funcs` set.
/// Sema will set this to null when it takes ownership.
-preallocated_new_func: ?*Module.Fn = null,
-/// The key is `constant` AIR instructions to types that must be fully resolved
-/// after the current function body analysis is done.
-/// TODO: after upgrading to use InternPool change the key here to be an
-/// InternPool value index.
-types_to_resolve: std.ArrayListUnmanaged(Air.Inst.Ref) = .{},
+preallocated_new_func: Module.Fn.OptionalIndex = .none,
+/// The key is types that must be fully resolved prior to machine code
+/// generation pass. Types are added to this set when resolving them
+/// immediately could cause a dependency loop, but they do need to be resolved
+/// before machine code generation passes process the AIR.
+/// It would work fine if this were an array list instead of an array hash map.
+/// I chose array hash map with the intention to save time by omitting
+/// duplicates.
+types_to_resolve: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{},
/// These are lazily created runtime blocks from block_inline instructions.
/// They are created when an break_inline passes through a runtime condition, because
/// Sema must convert comptime control flow to runtime control flow, which means
@@ -84,12 +85,22 @@ is_generic_instantiation: bool = false,
/// function types will emit generic poison instead of a partial type.
no_partial_func_ty: bool = false,
-unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, void) = .{},
+/// The temporary arena is used for the memory of the `InferredAlloc` values
+/// here so the values can be dropped without any cleanup.
+unresolved_inferred_allocs: std.AutoHashMapUnmanaged(Air.Inst.Index, InferredAlloc) = .{},
+
+/// Indices of comptime-mutable decls created by this Sema. These decls' values
+/// should be interned after analysis completes, as they may refer to memory in
+/// the Sema arena.
+/// TODO: this is a workaround for memory bugs triggered by the removal of
+/// Decl.value_arena. A better solution needs to be found. Probably this will
+/// involve transitioning comptime-mutable memory away from using Decls at all.
+comptime_mutable_decls: *std.ArrayList(Decl.Index),
const std = @import("std");
const math = std.math;
const mem = std.mem;
-const Allocator = std.mem.Allocator;
+const Allocator = mem.Allocator;
const assert = std.debug.assert;
const log = std.log.scoped(.sema);
@@ -114,6 +125,7 @@ const Package = @import("Package.zig");
const crash_report = @import("crash_report.zig");
const build_options = @import("build_options");
const Compilation = @import("Compilation.zig");
+const InternPool = @import("InternPool.zig");
pub const default_branch_quota = 1000;
pub const default_reference_trace_len = 2;
@@ -226,7 +238,7 @@ pub const Block = struct {
sema: *Sema,
/// The namespace to use for lookups from this source block
/// When analyzing fields, this is different from src_decl.src_namespace.
- namespace: *Namespace,
+ namespace: Namespace.Index,
/// The AIR instructions generated for this block.
instructions: std.ArrayListUnmanaged(Air.Inst.Index),
// `param` instructions are collected here to be used by the `func` instruction.
@@ -252,7 +264,6 @@ pub const Block = struct {
// TODO is_comptime and comptime_reason should probably be merged together.
is_comptime: bool,
is_typeof: bool = false,
- is_coerce_result_ptr: bool = false,
/// Keep track of the active error return trace index around blocks so that we can correctly
/// pop the error trace upon block exit.
@@ -266,12 +277,6 @@ pub const Block = struct {
c_import_buf: ?*std.ArrayList(u8) = null,
- /// type of `err` in `else => |err|`
- switch_else_err_ty: ?Type = null,
-
- /// Value for switch_capture in an inline case
- inline_case_capture: Air.Inst.Ref = .none,
-
const ComptimeReason = union(enum) {
c_import: struct {
block: *Block,
@@ -286,6 +291,7 @@ pub const Block = struct {
fn explain(cr: ComptimeReason, sema: *Sema, msg: ?*Module.ErrorMsg) !void {
const parent = msg orelse return;
+ const mod = sema.mod;
const prefix = "expression is evaluated at comptime because ";
switch (cr) {
.c_import => |ci| {
@@ -293,23 +299,23 @@ pub const Block = struct {
},
.comptime_ret_ty => |rt| {
const src_loc = if (try sema.funcDeclSrc(rt.func)) |fn_decl| blk: {
- var src_loc = fn_decl.srcLoc();
+ var src_loc = fn_decl.srcLoc(mod);
src_loc.lazy = .{ .node_offset_fn_type_ret_ty = 0 };
break :blk src_loc;
} else blk: {
- const src_decl = sema.mod.declPtr(rt.block.src_decl);
- break :blk rt.func_src.toSrcLoc(src_decl);
+ const src_decl = mod.declPtr(rt.block.src_decl);
+ break :blk rt.func_src.toSrcLoc(src_decl, mod);
};
- if (rt.return_ty.tag() == .generic_poison) {
- return sema.mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
+ if (rt.return_ty.isGenericPoison()) {
+ return mod.errNoteNonLazy(src_loc, parent, prefix ++ "the generic function was instantiated with a comptime-only return type", .{});
}
- try sema.mod.errNoteNonLazy(
+ try mod.errNoteNonLazy(
src_loc,
parent,
prefix ++ "the function returns a comptime-only type '{}'",
- .{rt.return_ty.fmt(sema.mod)},
+ .{rt.return_ty.fmt(mod)},
);
- try sema.explainWhyTypeIsComptime(rt.block, rt.func_src, parent, src_loc, rt.return_ty);
+ try sema.explainWhyTypeIsComptime(parent, src_loc, rt.return_ty);
},
}
}
@@ -385,7 +391,6 @@ pub const Block = struct {
.want_safety = parent.want_safety,
.float_mode = parent.float_mode,
.c_import_buf = parent.c_import_buf,
- .switch_else_err_ty = parent.switch_else_err_ty,
.error_return_trace_index = parent.error_return_trace_index,
};
}
@@ -399,8 +404,8 @@ pub const Block = struct {
};
}
- pub fn getFileScope(block: *Block) *Module.File {
- return block.namespace.file_scope;
+ pub fn getFileScope(block: *Block, mod: *Module) *Module.File {
+ return mod.namespacePtr(block.namespace).file_scope;
}
fn addTy(
@@ -585,13 +590,18 @@ pub const Block = struct {
}
fn addCmpVector(block: *Block, lhs: Air.Inst.Ref, rhs: Air.Inst.Ref, cmp_op: std.math.CompareOperator) !Air.Inst.Ref {
+ const sema = block.sema;
+ const mod = sema.mod;
return block.addInst(.{
.tag = if (block.float_mode == .Optimized) .cmp_vector_optimized else .cmp_vector,
.data = .{ .ty_pl = .{
- .ty = try block.sema.addType(
- try Type.vector(block.sema.arena, block.sema.typeOf(lhs).vectorLen(), Type.bool),
+ .ty = try sema.addType(
+ try mod.vectorType(.{
+ .len = sema.typeOf(lhs).vectorLen(mod),
+ .child = .bool_type,
+ }),
),
- .payload = try block.sema.addExtra(Air.VectorCmp{
+ .payload = try sema.addExtra(Air.VectorCmp{
.lhs = lhs,
.rhs = rhs,
.op = Air.VectorCmp.encodeOp(cmp_op),
@@ -685,29 +695,20 @@ pub const Block = struct {
pub fn startAnonDecl(block: *Block) !WipAnonDecl {
return WipAnonDecl{
.block = block,
- .new_decl_arena = std.heap.ArenaAllocator.init(block.sema.gpa),
.finished = false,
};
}
pub const WipAnonDecl = struct {
block: *Block,
- new_decl_arena: std.heap.ArenaAllocator,
finished: bool,
- pub fn arena(wad: *WipAnonDecl) Allocator {
- return wad.new_decl_arena.allocator();
- }
-
pub fn deinit(wad: *WipAnonDecl) void {
- if (!wad.finished) {
- wad.new_decl_arena.deinit();
- }
wad.* = undefined;
}
/// `alignment` value of 0 means to use ABI alignment.
- pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u32) !Decl.Index {
+ pub fn finish(wad: *WipAnonDecl, ty: Type, val: Value, alignment: u64) !Decl.Index {
const sema = wad.block.sema;
// Do this ahead of time because `createAnonymousDecl` depends on calling
// `type.hasRuntimeBits()`.
@@ -717,10 +718,11 @@ pub const Block = struct {
.val = val,
});
const new_decl = sema.mod.declPtr(new_decl_index);
- new_decl.@"align" = alignment;
+ // TODO: migrate Decl alignment to use `InternPool.Alignment`
+ new_decl.@"align" = @intCast(u32, alignment);
errdefer sema.mod.abortAnonDecl(new_decl_index);
- try new_decl.finalizeNewArena(&wad.new_decl_arena);
wad.finished = true;
+ try sema.mod.finalizeAnonDecl(new_decl_index);
return new_decl_index;
}
};
@@ -737,11 +739,27 @@ const LabeledBlock = struct {
}
};
+/// The value stored in the inferred allocation. This will go into
+/// peer type resolution. This is stored in a separate list so that
+/// the items are contiguous in memory and thus can be passed to
+/// `Module.resolvePeerTypes`.
+const InferredAlloc = struct {
+ prongs: std.MultiArrayList(struct {
+ /// The dummy instruction used as a peer to resolve the type.
+ /// Although this has a redundant type with placeholder, this is
+ /// needed in addition because it may be a constant value, which
+ /// affects peer type resolution.
+ stored_inst: Air.Inst.Ref,
+ /// The bitcast instruction used as a placeholder when the
+ /// new result pointer type is not yet known.
+ placeholder: Air.Inst.Index,
+ }) = .{},
+};
+
pub fn deinit(sema: *Sema) void {
const gpa = sema.gpa;
sema.air_instructions.deinit(gpa);
sema.air_extra.deinit(gpa);
- sema.air_values.deinit(gpa);
sema.inst_map.deinit(gpa);
sema.decl_val_table.deinit(gpa);
sema.types_to_resolve.deinit(gpa);
@@ -824,7 +842,7 @@ pub fn analyzeBodyBreak(
else => |e| return e,
};
if (block.instructions.items.len != 0 and
- sema.typeOf(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])).isNoReturn())
+ sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])))
return null;
const break_data = sema.code.instructions.items(.data)[break_inst].@"break";
const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data;
@@ -859,18 +877,20 @@ 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;
-
- var wip_captures = WipCaptureScope{
- .finalized = true,
+ parent_capture_scope.incRef();
+ var wip_captures: WipCaptureScope = .{
.scope = parent_capture_scope,
- .perm_arena = sema.perm_arena,
.gpa = sema.gpa,
+ .finalized = true, // don't finalize the parent scope
};
- defer if (wip_captures.scope != parent_capture_scope) {
- wip_captures.deinit();
- };
+ defer wip_captures.deinit();
+ const mod = sema.mod;
const map = &sema.inst_map;
const tags = sema.code.instructions.items(.tag);
const datas = sema.code.instructions.items(.data);
@@ -883,7 +903,7 @@ fn analyzeBodyInner(
var dbg_block_begins: u32 = 0;
- // We use a while(true) loop here to avoid a redundant way of breaking out of
+ // We use a while (true) loop here to avoid a redundant way of breaking out of
// the loop. The only way to break out of the loop is with a `noreturn`
// instruction.
var i: usize = 0;
@@ -891,15 +911,15 @@ fn analyzeBodyInner(
crash_info.setBodyIndex(i);
const inst = body[i];
std.log.scoped(.sema_zir).debug("sema ZIR {s} %{d}", .{
- sema.mod.declPtr(block.src_decl).src_namespace.file_scope.sub_file_path, inst,
+ mod.namespacePtr(mod.declPtr(block.src_decl).src_namespace).file_scope.sub_file_path, inst,
});
const air_inst: Air.Inst.Ref = switch (tags[inst]) {
// zig fmt: off
.alloc => try sema.zirAlloc(block, inst),
- .alloc_inferred => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_const)),
- .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, Type.initTag(.inferred_alloc_mut)),
- .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_const)),
- .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, Type.initTag(.inferred_alloc_mut)),
+ .alloc_inferred => try sema.zirAllocInferred(block, inst, true),
+ .alloc_inferred_mut => try sema.zirAllocInferred(block, inst, false),
+ .alloc_inferred_comptime => try sema.zirAllocInferredComptime(inst, true),
+ .alloc_inferred_comptime_mut => try sema.zirAllocInferredComptime(inst, false),
.alloc_mut => try sema.zirAllocMut(block, inst),
.alloc_comptime_mut => try sema.zirAllocComptime(block, inst),
.make_ptr_const => try sema.zirMakePtrConst(block, inst),
@@ -921,7 +941,8 @@ fn analyzeBodyInner(
.bool_br_and => try sema.zirBoolBr(block, inst, false),
.bool_br_or => try sema.zirBoolBr(block, inst, true),
.c_import => try sema.zirCImport(block, inst),
- .call => try sema.zirCall(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),
@@ -953,7 +974,6 @@ fn analyzeBodyInner(
.field_ptr_named => try sema.zirFieldPtrNamed(block, inst),
.field_val => try sema.zirFieldVal(block, inst),
.field_val_named => try sema.zirFieldValNamed(block, inst),
- .field_call_bind => try sema.zirFieldCallBind(block, inst),
.func => try sema.zirFunc(block, inst, false),
.func_inferred => try sema.zirFunc(block, inst, true),
.func_fancy => try sema.zirFuncFancy(block, inst),
@@ -963,7 +983,7 @@ fn analyzeBodyInner(
.int_big => try sema.zirIntBig(block, inst),
.float => try sema.zirFloat(block, inst),
.float128 => try sema.zirFloat128(block, inst),
- .int_type => try sema.zirIntType(block, inst),
+ .int_type => try sema.zirIntType(inst),
.is_non_err => try sema.zirIsNonErr(block, inst),
.is_non_err_ptr => try sema.zirIsNonErrPtr(block, inst),
.ret_is_non_err => try sema.zirRetIsNonErr(block, inst),
@@ -985,15 +1005,10 @@ fn analyzeBodyInner(
.slice_end => try sema.zirSliceEnd(block, inst),
.slice_sentinel => try sema.zirSliceSentinel(block, inst),
.slice_start => try sema.zirSliceStart(block, inst),
+ .slice_length => try sema.zirSliceLength(block, inst),
.str => try sema.zirStr(block, inst),
- .switch_block => try sema.zirSwitchBlock(block, inst),
- .switch_cond => try sema.zirSwitchCond(block, inst, false),
- .switch_cond_ref => try sema.zirSwitchCond(block, inst, true),
- .switch_capture => try sema.zirSwitchCapture(block, inst, false, false),
- .switch_capture_ref => try sema.zirSwitchCapture(block, inst, false, true),
- .switch_capture_multi => try sema.zirSwitchCapture(block, inst, true, false),
- .switch_capture_multi_ref => try sema.zirSwitchCapture(block, inst, true, true),
- .switch_capture_tag => try sema.zirSwitchCaptureTag(block, inst),
+ .switch_block => try sema.zirSwitchBlock(block, inst, false),
+ .switch_block_ref => try sema.zirSwitchBlock(block, inst, true),
.type_info => try sema.zirTypeInfo(block, inst),
.size_of => try sema.zirSizeOf(block, inst),
.bit_size_of => try sema.zirBitSizeOf(block, inst),
@@ -1137,6 +1152,8 @@ fn analyzeBodyInner(
.asm_expr => try sema.zirAsm( block, extended, true),
.typeof_peer => try sema.zirTypeofPeer( block, extended),
.compile_log => try sema.zirCompileLog( extended),
+ .min_multi => try sema.zirMinMaxMulti( block, extended, .min),
+ .max_multi => try sema.zirMinMaxMulti( block, extended, .max),
.add_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
.sub_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
.mul_with_overflow => try sema.zirOverflowArithmetic(block, extended, extended.opcode),
@@ -1147,7 +1164,6 @@ fn analyzeBodyInner(
.wasm_memory_size => try sema.zirWasmMemorySize( block, extended),
.wasm_memory_grow => try sema.zirWasmMemoryGrow( block, extended),
.prefetch => try sema.zirPrefetch( block, extended),
- .field_call_bind_named => try sema.zirFieldCallBindNamed(block, extended),
.err_set_cast => try sema.zirErrSetCast( block, extended),
.await_nosuspend => try sema.zirAwaitNosuspend( block, extended),
.select => try sema.zirSelect( block, extended),
@@ -1196,6 +1212,7 @@ fn analyzeBodyInner(
i += 1;
continue;
},
+ .value_placeholder => unreachable, // never appears in a body
};
},
@@ -1418,6 +1435,11 @@ fn analyzeBodyInner(
const src = LazySrcLoc.nodeOffset(datas[inst].node);
try sema.emitBackwardBranch(block, src);
if (wip_captures.scope.captures.count() != orig_captures) {
+ // We need to construct new capture scopes for the next loop iteration so it
+ // can capture values without clobbering the earlier iteration's captures.
+ // At first, we reused the parent capture scope as an optimization, but for
+ // successive scopes we have to create new ones as children of the parent
+ // scope.
try wip_captures.reset(parent_capture_scope);
block.wip_capture_scope = wip_captures.scope;
orig_captures = 0;
@@ -1433,6 +1455,11 @@ fn analyzeBodyInner(
const src = LazySrcLoc.nodeOffset(datas[inst].node);
try sema.emitBackwardBranch(block, src);
if (wip_captures.scope.captures.count() != orig_captures) {
+ // We need to construct new capture scopes for the next loop iteration so it
+ // can capture values without clobbering the earlier iteration's captures.
+ // At first, we reused the parent capture scope as an optimization, but for
+ // successive scopes we have to create new ones as children of the parent
+ // scope.
try wip_captures.reset(parent_capture_scope);
block.wip_capture_scope = wip_captures.scope;
orig_captures = 0;
@@ -1619,18 +1646,18 @@ fn analyzeBodyInner(
const inline_body = sema.code.extra[extra.end..][0..extra.data.body_len];
const err_union = try sema.resolveInst(extra.data.operand);
const err_union_ty = sema.typeOf(err_union);
- if (err_union_ty.zigTypeTag() != .ErrorUnion) {
+ if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
- err_union_ty.fmt(sema.mod),
+ err_union_ty.fmt(mod),
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
assert(is_non_err != .none);
- const is_non_err_tv = sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
+ const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
return err;
};
- if (is_non_err_tv.val.toBool()) {
+ if (is_non_err_val.toBool()) {
break :blk try sema.analyzeErrUnionPayload(block, src, err_union_ty, err_union, operand_src, false);
}
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
@@ -1652,11 +1679,11 @@ fn analyzeBodyInner(
const err_union = try sema.analyzeLoad(block, src, operand, operand_src);
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(block, operand_src, err_union);
assert(is_non_err != .none);
- const is_non_err_tv = sema.resolveInstConst(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
+ const is_non_err_val = sema.resolveConstValue(block, operand_src, is_non_err, "try operand inside comptime block must be comptime-known") catch |err| {
if (err == error.AnalysisFail and block.comptime_reason != null) try block.comptime_reason.?.explain(sema, sema.err);
return err;
};
- if (is_non_err_tv.val.toBool()) {
+ if (is_non_err_val.toBool()) {
break :blk try sema.analyzeErrUnionPayloadPtr(block, src, operand, false, false);
}
const break_data = (try sema.analyzeBodyBreak(block, inline_body)) orelse
@@ -1682,7 +1709,7 @@ fn analyzeBodyInner(
const extra = sema.code.extraData(Zir.Inst.DeferErrCode, inst_data.payload_index).data;
const defer_body = sema.code.extra[extra.index..][0..extra.len];
const err_code = try sema.resolveInst(inst_data.err_code);
- sema.inst_map.putAssumeCapacity(extra.remapped_err_code, err_code);
+ map.putAssumeCapacity(extra.remapped_err_code, err_code);
const break_inst = sema.analyzeBodyInner(block, defer_body) catch |err| switch (err) {
error.ComptimeBreak => sema.comptime_break_inst,
else => |e| return e,
@@ -1691,8 +1718,12 @@ fn analyzeBodyInner(
break :blk Air.Inst.Ref.void_value;
},
};
- if (sema.typeOf(air_inst).isNoReturn())
+ if (sema.isNoReturn(air_inst)) {
+ // We're going to assume that the body itself is noreturn, so let's ensure that now
+ assert(block.instructions.items.len > 0);
+ assert(sema.isNoReturn(Air.indexToRef(block.instructions.items[block.instructions.items.len - 1])));
break always_noreturn;
+ }
map.putAssumeCapacity(inst, air_inst);
i += 1;
};
@@ -1701,7 +1732,7 @@ fn analyzeBodyInner(
const noreturn_inst = block.instructions.popOrNull();
while (dbg_block_begins > 0) {
dbg_block_begins -= 1;
- if (block.is_comptime or sema.mod.comp.bin_file.options.strip) continue;
+ if (block.is_comptime or mod.comp.bin_file.options.strip) continue;
_ = try block.addInst(.{
.tag = .dbg_block_end,
@@ -1711,6 +1742,8 @@ fn analyzeBodyInner(
if (noreturn_inst) |some| try block.instructions.append(sema.gpa, some);
if (!wip_captures.finalized) {
+ // We've updated the capture scope due to a `repeat` instruction where
+ // the body had a capture; finalize our child scope and reset
try wip_captures.finalize();
block.wip_capture_scope = parent_capture_scope;
}
@@ -1718,20 +1751,23 @@ fn analyzeBodyInner(
return result;
}
-pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
- var i: usize = @enumToInt(zir_ref);
-
- // First section of indexes correspond to a set number of constant values.
- if (i < Zir.Inst.Ref.typed_value_map.len) {
- // We intentionally map the same indexes to the same values between ZIR and AIR.
- return zir_ref;
+pub fn resolveInstAllowNone(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
+ if (zir_ref == .none) {
+ return .none;
+ } else {
+ return resolveInst(sema, zir_ref);
}
- i -= Zir.Inst.Ref.typed_value_map.len;
+}
- // Finally, the last section of indexes refers to the map of ZIR=>AIR.
- const inst = sema.inst_map.get(@intCast(u32, i)).?;
- const ty = sema.typeOf(inst);
- if (ty.tag() == .generic_poison) return error.GenericPoison;
+pub fn resolveInst(sema: *Sema, zir_ref: Zir.Inst.Ref) !Air.Inst.Ref {
+ assert(zir_ref != .none);
+ const i = @enumToInt(zir_ref);
+ // First section of indexes correspond to a set number of constant values.
+ // We intentionally map the same indexes to the same values between ZIR and AIR.
+ if (i < InternPool.static_len) return @intToEnum(Air.Inst.Ref, i);
+ // The last section of indexes refers to the map of ZIR => AIR.
+ const inst = sema.inst_map.get(i - InternPool.static_len).?;
+ if (inst == .generic_poison) return error.GenericPoison;
return inst;
}
@@ -1757,16 +1793,31 @@ pub fn resolveConstString(
reason: []const u8,
) ![]u8 {
const air_inst = try sema.resolveInst(zir_ref);
- const wanted_type = Type.initTag(.const_slice_u8);
+ const wanted_type = Type.slice_const_u8;
const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
return val.toAllocatedBytes(wanted_type, sema.arena, sema.mod);
}
+pub fn resolveConstStringIntern(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ zir_ref: Zir.Inst.Ref,
+ reason: []const u8,
+) !InternPool.NullTerminatedString {
+ const air_inst = try sema.resolveInst(zir_ref);
+ const wanted_type = Type.slice_const_u8;
+ const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
+ const val = try sema.resolveConstValue(block, src, coerced_inst, reason);
+ return val.toIpString(wanted_type, sema.mod);
+}
+
pub fn resolveType(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) !Type {
const air_inst = try sema.resolveInst(zir_ref);
+ assert(air_inst != .var_args_param_type);
const ty = try sema.analyzeAsType(block, src, air_inst);
- if (ty.tag() == .generic_poison) return error.GenericPoison;
+ if (ty.isGenericPoison()) return error.GenericPoison;
return ty;
}
@@ -1776,45 +1827,48 @@ fn analyzeAsType(
src: LazySrcLoc,
air_inst: Air.Inst.Ref,
) !Type {
- const wanted_type = Type.initTag(.type);
+ const wanted_type = Type.type;
const coerced_inst = try sema.coerce(block, wanted_type, air_inst, src);
const val = try sema.resolveConstValue(block, src, coerced_inst, "types must be comptime-known");
- var buffer: Value.ToTypeBuffer = undefined;
- const ty = val.toType(&buffer);
- return ty.copy(sema.arena);
+ return val.toType();
}
pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize) !void {
- if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+ if (!mod.backendSupportsFeature(.error_return_trace)) return;
assert(!block.is_comptime);
var err_trace_block = block.makeSubBlock();
- defer err_trace_block.instructions.deinit(sema.gpa);
+ defer err_trace_block.instructions.deinit(gpa);
const src: LazySrcLoc = .unneeded;
// var addrs: [err_return_trace_addr_count]usize = undefined;
const err_return_trace_addr_count = 32;
- const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, sema.mod);
- const addrs_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, addr_arr_ty));
+ const addr_arr_ty = try Type.array(sema.arena, err_return_trace_addr_count, null, Type.usize, mod);
+ const addrs_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(addr_arr_ty));
// var st: StackTrace = undefined;
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
- const st_ptr = try err_trace_block.addTy(.alloc, try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty));
+ const st_ptr = try err_trace_block.addTy(.alloc, try mod.singleMutPtrType(stack_trace_ty));
// st.instruction_addresses = &addrs;
- const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "instruction_addresses", src, true);
+ const instruction_addresses_field_name = try ip.getOrPutString(gpa, "instruction_addresses");
+ const addr_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, instruction_addresses_field_name, src, true);
try sema.storePtr2(&err_trace_block, src, addr_field_ptr, src, addrs_ptr, src, .store);
// st.index = 0;
- const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, "index", src, true);
+ const index_field_name = try ip.getOrPutString(gpa, "index");
+ const index_field_ptr = try sema.fieldPtr(&err_trace_block, src, st_ptr, index_field_name, src, true);
try sema.storePtr2(&err_trace_block, src, index_field_ptr, src, .zero_usize, src, .store);
// @errorReturnTrace() = &st;
_ = try err_trace_block.addUnOp(.set_err_return_trace, st_ptr);
- try block.instructions.insertSlice(sema.gpa, last_arg_index, err_trace_block.instructions.items);
+ try block.instructions.insertSlice(gpa, last_arg_index, err_trace_block.instructions.items);
}
/// May return Value Tags: `variable`, `undef`.
@@ -1828,7 +1882,7 @@ fn resolveValue(
reason: []const u8,
) CompileError!Value {
if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
- if (val.tag() == .generic_poison) return error.GenericPoison;
+ if (val.isGenericPoison()) return error.GenericPoison;
return val;
}
return sema.failWithNeededComptime(block, src, reason);
@@ -1844,10 +1898,12 @@ fn resolveConstMaybeUndefVal(
reason: []const u8,
) CompileError!Value {
if (try sema.resolveMaybeUndefValAllowVariables(inst)) |val| {
- switch (val.tag()) {
- .variable => return sema.failWithNeededComptime(block, src, reason),
+ switch (val.toIntern()) {
.generic_poison => return error.GenericPoison,
- else => return val,
+ else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
+ .variable => return sema.failWithNeededComptime(block, src, reason),
+ else => return val,
+ },
}
}
return sema.failWithNeededComptime(block, src, reason);
@@ -1863,16 +1919,31 @@ fn resolveConstValue(
reason: []const u8,
) CompileError!Value {
if (try sema.resolveMaybeUndefValAllowVariables(air_ref)) |val| {
- switch (val.tag()) {
- .undef => return sema.failWithUseOfUndef(block, src),
- .variable => return sema.failWithNeededComptime(block, src, reason),
+ switch (val.toIntern()) {
.generic_poison => return error.GenericPoison,
- else => return val,
+ .undef => return sema.failWithUseOfUndef(block, src),
+ else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
+ .undef => return sema.failWithUseOfUndef(block, src),
+ .variable => return sema.failWithNeededComptime(block, src, reason),
+ else => return val,
+ },
}
}
return sema.failWithNeededComptime(block, src, reason);
}
+/// Will not return Value Tags: `variable`, `undef`. Instead they will emit compile errors.
+/// Lazy values are recursively resolved.
+fn resolveConstLazyValue(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ air_ref: Air.Inst.Ref,
+ reason: []const u8,
+) CompileError!Value {
+ return sema.resolveLazyValue(try sema.resolveConstValue(block, src, air_ref, reason));
+}
+
/// Value Tag `variable` causes this function to return `null`.
/// Value Tag `undef` causes this function to return a compile error.
fn resolveDefinedValue(
@@ -1881,8 +1952,9 @@ fn resolveDefinedValue(
src: LazySrcLoc,
air_ref: Air.Inst.Ref,
) CompileError!?Value {
+ const mod = sema.mod;
if (try sema.resolveMaybeUndefVal(air_ref)) |val| {
- if (val.isUndef()) {
+ if (val.isUndef(mod)) {
if (block.is_typeof) return null;
return sema.failWithUseOfUndef(block, src);
}
@@ -1899,34 +1971,53 @@ fn resolveMaybeUndefVal(
inst: Air.Inst.Ref,
) CompileError!?Value {
const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
- switch (val.tag()) {
- .variable => return null,
+ switch (val.ip_index) {
.generic_poison => return error.GenericPoison,
- else => return val,
+ .none => return val,
+ else => switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
+ .variable => return null,
+ else => return val,
+ },
}
}
+/// Value Tag `variable` causes this function to return `null`.
+/// Value Tag `undef` causes this function to return the Value.
+/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
+/// Lazy values are recursively resolved.
+fn resolveMaybeUndefLazyVal(
+ sema: *Sema,
+ inst: Air.Inst.Ref,
+) CompileError!?Value {
+ return try sema.resolveLazyValue((try sema.resolveMaybeUndefVal(inst)) orelse return null);
+}
+
/// Value Tag `variable` results in `null`.
/// Value Tag `undef` results in the Value.
/// Value Tag `generic_poison` causes `error.GenericPoison` to be returned.
/// Value Tag `decl_ref` and `decl_ref_mut` or any nested such value results in `null`.
+/// Lazy values are recursively resolved.
fn resolveMaybeUndefValIntable(
sema: *Sema,
inst: Air.Inst.Ref,
) CompileError!?Value {
const val = (try sema.resolveMaybeUndefValAllowVariables(inst)) orelse return null;
var check = val;
- while (true) switch (check.tag()) {
- .variable, .decl_ref, .decl_ref_mut, .comptime_field_ptr => return null,
- .field_ptr => check = check.castTag(.field_ptr).?.data.container_ptr,
- .elem_ptr => check = check.castTag(.elem_ptr).?.data.array_ptr,
- .eu_payload_ptr, .opt_payload_ptr => check = check.cast(Value.Payload.PayloadPtr).?.data.container_ptr,
+ while (true) switch (check.ip_index) {
.generic_poison => return error.GenericPoison,
- else => {
- try sema.resolveLazyValue(val);
- return val;
+ .none => break,
+ else => switch (sema.mod.intern_pool.indexToKey(check.toIntern())) {
+ .variable => return null,
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl, .mut_decl, .comptime_field => return null,
+ .int => break,
+ .eu_payload, .opt_payload => |base| check = base.toValue(),
+ .elem, .field => |base_index| check = base_index.base.toValue(),
+ },
+ else => break,
},
};
+ return try sema.resolveLazyValue(val);
}
/// Returns all Value tags including `variable` and `undef`.
@@ -1945,35 +2036,33 @@ fn resolveMaybeUndefValAllowVariablesMaybeRuntime(
inst: Air.Inst.Ref,
make_runtime: *bool,
) CompileError!?Value {
+ assert(inst != .none);
// First section of indexes correspond to a set number of constant values.
- var i: usize = @enumToInt(inst);
- if (i < Air.Inst.Ref.typed_value_map.len) {
- return Air.Inst.Ref.typed_value_map[i].val;
+ const int = @enumToInt(inst);
+ if (int < InternPool.static_len) {
+ return @intToEnum(InternPool.Index, int).toValue();
}
- i -= Air.Inst.Ref.typed_value_map.len;
+ const i = int - InternPool.static_len;
const air_tags = sema.air_instructions.items(.tag);
if (try sema.typeHasOnePossibleValue(sema.typeOf(inst))) |opv| {
- if (air_tags[i] == .constant) {
- const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
- const val = sema.air_values.items[ty_pl.payload];
- if (val.tag() == .variable) return val;
+ if (air_tags[i] == .interned) {
+ const interned = sema.air_instructions.items(.data)[i].interned;
+ const val = interned.toValue();
+ if (val.getVariable(sema.mod) != null) return val;
}
return opv;
}
- switch (air_tags[i]) {
- .constant => {
- const ty_pl = sema.air_instructions.items(.data)[i].ty_pl;
- const val = sema.air_values.items[ty_pl.payload];
- if (val.tag() == .runtime_value) make_runtime.* = true;
- if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
- return val;
- },
- .const_ty => {
- return try sema.air_instructions.items(.data)[i].ty.toValue(sema.arena);
- },
+ const air_datas = sema.air_instructions.items(.data);
+ const val = switch (air_tags[i]) {
+ .inferred_alloc => unreachable,
+ .inferred_alloc_comptime => unreachable,
+ .interned => air_datas[i].interned.toValue(),
else => return null,
- }
+ };
+ if (val.isRuntimeValue(sema.mod)) make_runtime.* = true;
+ if (val.isPtrToThreadLocal(sema.mod)) make_runtime.* = true;
+ return val;
}
fn failWithNeededComptime(sema: *Sema, block: *Block, src: LazySrcLoc, reason: []const u8) CompileError {
@@ -2006,13 +2095,14 @@ fn failWithExpectedOptionalType(sema: *Sema, block: *Block, src: LazySrcLoc, opt
}
fn failWithArrayInitNotSupported(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError {
+ const mod = sema.mod;
const msg = msg: {
const msg = try sema.errMsg(block, src, "type '{}' does not support array initialization syntax", .{
- ty.fmt(sema.mod),
+ ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
- if (ty.isSlice()) {
- try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2().fmt(sema.mod)});
+ if (ty.isSlice(mod)) {
+ try sema.errNote(block, src, msg, "inferred array length is specified with an underscore: '[_]{}'", .{ty.elemType2(mod).fmt(mod)});
}
break :msg msg;
};
@@ -2038,7 +2128,8 @@ fn failWithErrorSetCodeMissing(
}
fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty: Type, val: Value, vector_index: usize) CompileError {
- if (int_ty.zigTypeTag() == .Vector) {
+ const mod = sema.mod;
+ if (int_ty.zigTypeTag(mod) == .Vector) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "overflow of vector type '{}' with value '{}'", .{
int_ty.fmt(sema.mod), val.fmtValue(int_ty, sema.mod),
@@ -2055,16 +2146,17 @@ fn failWithIntegerOverflow(sema: *Sema, block: *Block, src: LazySrcLoc, int_ty:
}
fn failWithInvalidComptimeFieldStore(sema: *Sema, block: *Block, init_src: LazySrcLoc, container_ty: Type, field_index: usize) CompileError {
+ const mod = sema.mod;
const msg = msg: {
const msg = try sema.errMsg(block, init_src, "value stored in comptime field does not match the default value of the field", .{});
errdefer msg.destroy(sema.gpa);
- const struct_ty = container_ty.castTag(.@"struct") orelse break :msg msg;
- const default_value_src = struct_ty.data.fieldSrcLoc(sema.mod, .{
+ const struct_ty = mod.typeToStruct(container_ty) orelse break :msg msg;
+ const default_value_src = mod.fieldSrcLoc(struct_ty.owner_decl, .{
.index = field_index,
.range = .value,
});
- try sema.mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{});
+ try mod.errNoteNonLazy(default_value_src, msg, "default value set here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -2079,13 +2171,19 @@ fn failWithUseOfAsync(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError
return sema.failWithOwnedErrorMsg(msg);
}
-fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, object_ty: Type, field_name: []const u8) CompileError {
- const inner_ty = if (object_ty.isSinglePointer()) object_ty.childType() else object_ty;
+fn failWithInvalidFieldAccess(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ object_ty: Type,
+ field_name: InternPool.NullTerminatedString,
+) CompileError {
+ const mod = sema.mod;
+ const inner_ty = if (object_ty.isSinglePointer(mod)) object_ty.childType(mod) else object_ty;
- if (inner_ty.zigTypeTag() == .Optional) opt: {
- var buf: Type.Payload.ElemType = undefined;
- const child_ty = inner_ty.optionalChild(&buf);
- if (!typeSupportsFieldAccess(child_ty, field_name)) break :opt;
+ if (inner_ty.zigTypeTag(mod) == .Optional) opt: {
+ const child_ty = inner_ty.optionalChild(mod);
+ if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :opt;
const msg = msg: {
const msg = try sema.errMsg(block, src, "optional type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
@@ -2093,9 +2191,9 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- } else if (inner_ty.zigTypeTag() == .ErrorUnion) err: {
- const child_ty = inner_ty.errorUnionPayload();
- if (!typeSupportsFieldAccess(child_ty, field_name)) break :err;
+ } else if (inner_ty.zigTypeTag(mod) == .ErrorUnion) err: {
+ const child_ty = inner_ty.errorUnionPayload(mod);
+ if (!typeSupportsFieldAccess(mod, child_ty, field_name)) break :err;
const msg = msg: {
const msg = try sema.errMsg(block, src, "error union type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
@@ -2107,15 +2205,16 @@ fn failWithInvalidFieldAccess(sema: *Sema, block: *Block, src: LazySrcLoc, objec
return sema.fail(block, src, "type '{}' does not support field access", .{object_ty.fmt(sema.mod)});
}
-fn typeSupportsFieldAccess(ty: Type, field_name: []const u8) bool {
- switch (ty.zigTypeTag()) {
- .Array => return mem.eql(u8, field_name, "len"),
+fn typeSupportsFieldAccess(mod: *const Module, ty: Type, field_name: InternPool.NullTerminatedString) bool {
+ const ip = &mod.intern_pool;
+ switch (ty.zigTypeTag(mod)) {
+ .Array => return ip.stringEqlSlice(field_name, "len"),
.Pointer => {
- const ptr_info = ty.ptrInfo().data;
+ const ptr_info = ty.ptrInfo(mod);
if (ptr_info.size == .Slice) {
- return mem.eql(u8, field_name, "ptr") or mem.eql(u8, field_name, "len");
- } else if (ptr_info.pointee_type.zigTypeTag() == .Array) {
- return mem.eql(u8, field_name, "len");
+ return ip.stringEqlSlice(field_name, "ptr") or ip.stringEqlSlice(field_name, "len");
+ } else if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) {
+ return ip.stringEqlSlice(field_name, "len");
} else return false;
},
.Type, .Struct, .Union => return true,
@@ -2135,7 +2234,7 @@ fn errNote(
) error{OutOfMemory}!void {
const mod = sema.mod;
const src_decl = mod.declPtr(block.src_decl);
- return mod.errNoteNonLazy(src.toSrcLoc(src_decl), parent, format, args);
+ return mod.errNoteNonLazy(src.toSrcLoc(src_decl, mod), parent, format, args);
}
fn addFieldErrNote(
@@ -2148,19 +2247,19 @@ fn addFieldErrNote(
) !void {
@setCold(true);
const mod = sema.mod;
- const decl_index = container_ty.getOwnerDecl();
+ const decl_index = container_ty.getOwnerDecl(mod);
const decl = mod.declPtr(decl_index);
const field_src = blk: {
- const tree = decl.getFileScope().getTree(sema.gpa) catch |err| {
+ const tree = decl.getFileScope(mod).getTree(sema.gpa) catch |err| {
log.err("unable to load AST to report compile error: {s}", .{@errorName(err)});
- break :blk decl.srcLoc();
+ break :blk decl.srcLoc(mod);
};
const container_node = decl.relativeToNodeIndex(0);
const node_tags = tree.nodes.items(.tag);
var buf: [2]std.zig.Ast.Node.Index = undefined;
- const container_decl = tree.fullContainerDecl(&buf, container_node) orelse break :blk decl.srcLoc();
+ const container_decl = tree.fullContainerDecl(&buf, container_node) orelse break :blk decl.srcLoc(mod);
var it_index: usize = 0;
for (container_decl.ast.members) |member_node| {
@@ -2170,7 +2269,7 @@ fn addFieldErrNote(
.container_field,
=> {
if (it_index == field_index) {
- break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node));
+ break :blk decl.nodeOffsetSrcLoc(decl.nodeIndexToRelative(member_node), mod);
}
it_index += 1;
},
@@ -2191,7 +2290,7 @@ fn errMsg(
) error{OutOfMemory}!*Module.ErrorMsg {
const mod = sema.mod;
const src_decl = mod.declPtr(block.src_decl);
- return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl), format, args);
+ return Module.ErrorMsg.create(sema.gpa, src.toSrcLoc(src_decl, mod), format, args);
}
pub fn fail(
@@ -2208,19 +2307,19 @@ pub fn fail(
fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
@setCold(true);
const gpa = sema.gpa;
+ const mod = sema.mod;
- if (crash_report.is_enabled and sema.mod.comp.debug_compile_errors) {
+ if (crash_report.is_enabled and mod.comp.debug_compile_errors) {
if (err_msg.src_loc.lazy == .unneeded) return error.NeededSourceLocation;
var wip_errors: std.zig.ErrorBundle.Wip = undefined;
wip_errors.init(gpa) catch unreachable;
- Compilation.addModuleErrorMsg(&wip_errors, err_msg.*) catch unreachable;
+ Compilation.addModuleErrorMsg(mod, &wip_errors, err_msg.*) catch unreachable;
std.debug.print("compile error during Sema:\n", .{});
var error_bundle = wip_errors.toOwnedBundle("") catch unreachable;
error_bundle.renderToStdErr(.{ .ttyconf = .no_color });
crash_report.compilerPanic("unexpected compile error occurred", null, null);
}
- const mod = sema.mod;
ref: {
errdefer err_msg.destroy(gpa);
if (err_msg.src_loc.lazy == .unneeded) {
@@ -2230,9 +2329,9 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
try mod.failed_files.ensureUnusedCapacity(gpa, 1);
const max_references = blk: {
- if (sema.mod.comp.reference_trace) |num| break :blk num;
+ if (mod.comp.reference_trace) |num| break :blk num;
// Do not add multiple traces without explicit request.
- if (sema.mod.failed_decls.count() != 0) break :ref;
+ if (mod.failed_decls.count() != 0) break :ref;
break :blk default_reference_trace_len;
};
@@ -2241,7 +2340,7 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
defer reference_stack.deinit();
// Avoid infinite loops.
- var seen = std.AutoHashMap(Module.Decl.Index, void).init(gpa);
+ var seen = std.AutoHashMap(Decl.Index, void).init(gpa);
defer seen.deinit();
var cur_reference_trace: u32 = 0;
@@ -2250,13 +2349,16 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
if (gop.found_existing) break;
if (cur_reference_trace < max_references) {
const decl = sema.mod.declPtr(ref.referencer);
- try reference_stack.append(.{ .decl = decl.name, .src_loc = ref.src.toSrcLoc(decl) });
+ try reference_stack.append(.{
+ .decl = decl.name.toOptional(),
+ .src_loc = ref.src.toSrcLoc(decl, mod),
+ });
}
referenced_by = ref.referencer;
}
if (sema.mod.comp.reference_trace == null and cur_reference_trace > 0) {
try reference_stack.append(.{
- .decl = null,
+ .decl = .none,
.src_loc = undefined,
.hidden = 0,
});
@@ -2290,6 +2392,34 @@ fn failWithOwnedErrorMsg(sema: *Sema, err_msg: *Module.ErrorMsg) CompileError {
return error.AnalysisFail;
}
+/// Given an ErrorMsg, modify its message and source location to the given values, turning the
+/// original message into a note. Notes on the original message are preserved as further notes.
+/// Reference trace is preserved.
+fn reparentOwnedErrorMsg(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ msg: *Module.ErrorMsg,
+ comptime format: []const u8,
+ args: anytype,
+) !void {
+ const mod = sema.mod;
+ const src_decl = mod.declPtr(block.src_decl);
+ const resolved_src = src.toSrcLoc(src_decl, mod);
+ const msg_str = try std.fmt.allocPrint(mod.gpa, format, args);
+
+ const orig_notes = msg.notes.len;
+ msg.notes = try sema.gpa.realloc(msg.notes, orig_notes + 1);
+ std.mem.copyBackwards(Module.ErrorMsg, msg.notes[1..], msg.notes[0..orig_notes]);
+ msg.notes[0] = .{
+ .src_loc = msg.src_loc,
+ .msg = msg.msg,
+ };
+
+ msg.src_loc = resolved_src;
+ msg.msg = msg_str;
+}
+
const align_ty = Type.u29;
fn analyzeAsAlign(
@@ -2348,10 +2478,10 @@ fn analyzeAsInt(
dest_ty: Type,
reason: []const u8,
) !u64 {
+ const mod = sema.mod;
const coerced = try sema.coerce(block, dest_ty, air_ref, src);
const val = try sema.resolveConstValue(block, src, coerced, reason);
- const target = sema.mod.getTarget();
- return (try val.getUnsignedIntAdvanced(target, sema)).?;
+ return (try val.getUnsignedIntAdvanced(mod, sema)).?;
}
// Returns a compile error if the value has tag `variable`. See `resolveInstValue` for
@@ -2392,72 +2522,77 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const pointee_ty = try sema.resolveType(block, src, extra.lhs);
const ptr = try sema.resolveInst(extra.rhs);
- const target = sema.mod.getTarget();
+ const target = mod.getTarget();
const addr_space = target_util.defaultAddressSpace(target, .local);
if (Air.refToIndex(ptr)) |ptr_inst| {
- if (sema.air_instructions.items(.tag)[ptr_inst] == .constant) {
- const air_datas = sema.air_instructions.items(.data);
- const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
- switch (ptr_val.tag()) {
- .inferred_alloc => {
- const inferred_alloc = &ptr_val.castTag(.inferred_alloc).?.data;
- // Add the stored instruction to the set we will use to resolve peer types
- // for the inferred allocation.
- // This instruction will not make it to codegen; it is only to participate
- // in the `stored_inst_list` of the `inferred_alloc`.
- var trash_block = block.makeSubBlock();
- defer trash_block.instructions.deinit(sema.gpa);
- const operand = try trash_block.addBitCast(pointee_ty, .void_value);
-
- const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = pointee_ty,
- .@"align" = inferred_alloc.alignment,
- .@"addrspace" = addr_space,
- });
- const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
+ switch (sema.air_instructions.items(.tag)[ptr_inst]) {
+ .inferred_alloc => {
+ const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
+ const ia2 = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
+ // Add the stored instruction to the set we will use to resolve peer types
+ // for the inferred allocation.
+ // This instruction will not make it to codegen; it is only to participate
+ // in the `stored_inst_list` of the `inferred_alloc`.
+ var trash_block = block.makeSubBlock();
+ defer trash_block.instructions.deinit(sema.gpa);
+ const operand = try trash_block.addBitCast(pointee_ty, .void_value);
+
+ const ptr_ty = try mod.ptrType(.{
+ .child = pointee_ty.toIntern(),
+ .flags = .{
+ .alignment = ia1.alignment,
+ .address_space = addr_space,
+ },
+ });
+ const bitcasted_ptr = try block.addBitCast(ptr_ty, ptr);
- try inferred_alloc.prongs.append(sema.arena, .{
- .stored_inst = operand,
- .placeholder = Air.refToIndex(bitcasted_ptr).?,
- });
+ try ia2.prongs.append(sema.arena, .{
+ .stored_inst = operand,
+ .placeholder = Air.refToIndex(bitcasted_ptr).?,
+ });
- return bitcasted_ptr;
- },
- .inferred_alloc_comptime => {
- const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
- // There will be only one coerce_result_ptr because we are running at comptime.
- // The alloc will turn into a Decl.
- var anon_decl = try block.startAnonDecl();
- defer anon_decl.deinit();
- iac.data.decl_index = try anon_decl.finish(
- try pointee_ty.copy(anon_decl.arena()),
- Value.undef,
- iac.data.alignment,
- );
- if (iac.data.alignment != 0) {
- try sema.resolveTypeLayout(pointee_ty);
- }
- const ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = pointee_ty,
- .@"align" = iac.data.alignment,
- .@"addrspace" = addr_space,
- });
- return sema.addConstant(
- ptr_ty,
- try Value.Tag.decl_ref_mut.create(sema.arena, .{
- .decl_index = iac.data.decl_index,
- .runtime_index = block.runtime_index,
- }),
- );
- },
- else => {},
- }
+ return bitcasted_ptr;
+ },
+ .inferred_alloc_comptime => {
+ const alignment = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.alignment;
+ // There will be only one coerce_result_ptr because we are running at comptime.
+ // The alloc will turn into a Decl.
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ const decl_index = try anon_decl.finish(
+ pointee_ty,
+ (try mod.intern(.{ .undef = pointee_ty.toIntern() })).toValue(),
+ alignment.toByteUnits(0),
+ );
+ sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime.decl_index = decl_index;
+ if (alignment != .none) {
+ try sema.resolveTypeLayout(pointee_ty);
+ }
+ const ptr_ty = try mod.ptrType(.{
+ .child = pointee_ty.toIntern(),
+ .flags = .{
+ .alignment = alignment,
+ .address_space = addr_space,
+ },
+ });
+ try sema.maybeQueueFuncBodyAnalysis(decl_index);
+ try sema.comptime_mutable_decls.append(decl_index);
+ return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{
+ .ty = ptr_ty.toIntern(),
+ .addr = .{ .mut_decl = .{
+ .decl = decl_index,
+ .runtime_index = block.runtime_index,
+ } },
+ } })).toValue());
+ },
+ else => {},
}
}
@@ -2466,7 +2601,6 @@ fn zirCoerceResultPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
// kind of transformations to make on the result pointer.
var trash_block = block.makeSubBlock();
trash_block.is_comptime = false;
- trash_block.is_coerce_result_ptr = true;
defer trash_block.instructions.deinit(sema.gpa);
const dummy_ptr = try trash_block.addTy(.alloc, sema.typeOf(ptr));
@@ -2483,6 +2617,7 @@ fn coerceResultPtr(
dummy_operand: Air.Inst.Ref,
trash_block: *Block,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const target = sema.mod.getTarget();
const addr_space = target_util.defaultAddressSpace(target, .local);
const pointee_ty = sema.typeOf(dummy_operand);
@@ -2526,7 +2661,7 @@ fn coerceResultPtr(
return sema.addConstant(ptr_ty, ptr_val);
}
if (pointee_ty.eql(Type.null, sema.mod)) {
- const opt_ty = sema.typeOf(new_ptr).childType();
+ const opt_ty = sema.typeOf(new_ptr).childType(mod);
const null_inst = try sema.addConstant(opt_ty, Value.null);
_ = try block.addBinOp(.store, new_ptr, null_inst);
return Air.Inst.Ref.void_value;
@@ -2559,7 +2694,7 @@ fn coerceResultPtr(
.@"addrspace" = addr_space,
});
if (try sema.resolveDefinedValue(block, src, new_ptr)) |ptr_val| {
- new_ptr = try sema.addConstant(ptr_operand_ty, ptr_val);
+ new_ptr = try sema.addConstant(ptr_operand_ty, try mod.getCoerced(ptr_val, ptr_operand_ty));
} else {
new_ptr = try sema.bitCast(block, ptr_operand_ty, new_ptr, src, null);
}
@@ -2576,6 +2711,9 @@ fn coerceResultPtr(
.array_to_slice => {
return sema.fail(block, src, "TODO coerce_result_ptr array_to_slice", .{});
},
+ .get_union_tag => {
+ return sema.fail(block, src, "TODO coerce_result_ptr get_union_tag", .{});
+ },
else => {
if (std.debug.runtime_safety) {
std.debug.panic("unexpected AIR tag for coerce_result_ptr: {}", .{
@@ -2593,8 +2731,10 @@ pub fn analyzeStructDecl(
sema: *Sema,
new_decl: *Decl,
inst: Zir.Inst.Index,
- struct_obj: *Module.Struct,
+ struct_index: Module.Struct.Index,
) SemaError!void {
+ const mod = sema.mod;
+ const struct_obj = mod.structPtr(struct_index);
const extended = sema.code.instructions.items(.data)[inst].extended;
assert(extended.opcode == .struct_decl);
const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
@@ -2623,7 +2763,7 @@ pub fn analyzeStructDecl(
}
}
- _ = try sema.mod.scanNamespace(&struct_obj.namespace, extra_index, decls_len, new_decl);
+ _ = try mod.scanNamespace(struct_obj.namespace, extra_index, decls_len, new_decl);
}
fn zirStructDecl(
@@ -2632,28 +2772,35 @@ fn zirStructDecl(
extended: Zir.Inst.Extended.InstData,
inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
const src: LazySrcLoc = if (small.has_src_node) blk: {
const node_offset = @bitCast(i32, sema.code.extra[extended.operand]);
break :blk LazySrcLoc.nodeOffset(node_offset);
} else sema.src;
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ // Because these three things each reference each other, `undefined`
+ // placeholders are used before being set after the struct type gains an
+ // InternPool index.
- const mod = sema.mod;
- const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
- const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
- const struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = struct_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, small.name_strategy, "struct", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
- struct_obj.* = .{
+
+ const new_namespace_index = try mod.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
+ });
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer mod.destroyNamespace(new_namespace_index);
+
+ const struct_index = try mod.createStruct(.{
.owner_decl = new_decl_index,
.fields = .{},
.zir_index = inst,
@@ -2661,18 +2808,25 @@ fn zirStructDecl(
.status = .none,
.known_non_opv = undefined,
.is_tuple = small.is_tuple,
- .namespace = .{
- .parent = block.namespace,
- .ty = struct_ty,
- .file_scope = block.getFileScope(),
- },
- };
- std.log.scoped(.module).debug("create struct {*} owned by {*} ({s})", .{
- &struct_obj.namespace, new_decl, new_decl.name,
+ .namespace = new_namespace_index,
});
- try sema.analyzeStructDecl(new_decl, inst, struct_obj);
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ errdefer mod.destroyStruct(struct_index);
+
+ const struct_ty = try mod.intern_pool.get(gpa, .{ .struct_type = .{
+ .index = struct_index.toOptional(),
+ .namespace = new_namespace_index.toOptional(),
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer mod.intern_pool.remove(struct_ty);
+
+ new_decl.ty = Type.type;
+ new_decl.val = struct_ty.toValue();
+ new_namespace.ty = struct_ty.toType();
+
+ try sema.analyzeStructDecl(new_decl, inst, struct_index);
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
}
fn createAnonymousDeclTypeNamed(
@@ -2685,6 +2839,7 @@ fn createAnonymousDeclTypeNamed(
inst: ?Zir.Inst.Index,
) !Decl.Index {
const mod = sema.mod;
+ const gpa = sema.gpa;
const namespace = block.namespace;
const src_scope = block.wip_capture_scope;
const src_decl = mod.declPtr(block.src_decl);
@@ -2700,16 +2855,15 @@ fn createAnonymousDeclTypeNamed(
// semantically analyzed.
// This name is also used as the key in the parent namespace so it cannot be
// renamed.
- const name = try std.fmt.allocPrintZ(sema.gpa, "{s}__{s}_{d}", .{
- src_decl.name, anon_prefix, @enumToInt(new_decl_index),
- });
- errdefer sema.gpa.free(name);
+
+ const name = mod.intern_pool.getOrPutStringFmt(gpa, "{}__{s}_{d}", .{
+ src_decl.name.fmt(&mod.intern_pool), anon_prefix, @enumToInt(new_decl_index),
+ }) catch unreachable;
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
},
.parent => {
- const name = try sema.gpa.dupeZ(u8, mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
- errdefer sema.gpa.free(name);
+ const name = mod.declPtr(block.src_decl).name;
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
},
@@ -2717,21 +2871,26 @@ fn createAnonymousDeclTypeNamed(
const fn_info = sema.code.getFnInfo(sema.func.?.zir_body_inst);
const zir_tags = sema.code.instructions.items(.tag);
- var buf = std.ArrayList(u8).init(sema.gpa);
+ var buf = std.ArrayList(u8).init(gpa);
defer buf.deinit();
- try buf.appendSlice(mem.sliceTo(sema.mod.declPtr(block.src_decl).name, 0));
- try buf.appendSlice("(");
+
+ const writer = buf.writer();
+ try writer.print("{}(", .{mod.declPtr(block.src_decl).name.fmt(&mod.intern_pool)});
var arg_i: usize = 0;
for (fn_info.param_body) |zir_inst| switch (zir_tags[zir_inst]) {
.param, .param_comptime, .param_anytype, .param_anytype_comptime => {
const arg = sema.inst_map.get(zir_inst).?;
- // The comptime call code in analyzeCall already did this, so we're
- // just repeating it here and it's guaranteed to work.
- const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch unreachable;
+ // If this is being called in a generic function then analyzeCall will
+ // have already resolved the args and this will work.
+ // If not then this is a struct type being returned from a non-generic
+ // function and the name doesn't matter since it will later
+ // result in a compile error.
+ const arg_val = sema.resolveConstMaybeUndefVal(block, .unneeded, arg, "") catch
+ return sema.createAnonymousDeclTypeNamed(block, src, typed_value, .anon, anon_prefix, null);
- if (arg_i != 0) try buf.appendSlice(",");
- try buf.writer().print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)});
+ if (arg_i != 0) try writer.writeByte(',');
+ try writer.print("{}", .{arg_val.fmtValue(sema.typeOf(arg), sema.mod)});
arg_i += 1;
continue;
@@ -2739,9 +2898,8 @@ fn createAnonymousDeclTypeNamed(
else => continue,
};
- try buf.appendSlice(")");
- const name = try buf.toOwnedSliceSentinel(0);
- errdefer sema.gpa.free(name);
+ try writer.writeByte(')');
+ const name = try mod.intern_pool.getOrPutString(gpa, buf.items);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
},
@@ -2754,10 +2912,9 @@ fn createAnonymousDeclTypeNamed(
.dbg_var_ptr, .dbg_var_val => {
if (zir_data[i].str_op.operand != ref) continue;
- const name = try std.fmt.allocPrintZ(sema.gpa, "{s}.{s}", .{
- src_decl.name, zir_data[i].str_op.getStr(sema.code),
+ const name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}.{s}", .{
+ src_decl.name.fmt(&mod.intern_pool), zir_data[i].str_op.getStr(sema.code),
});
- errdefer sema.gpa.free(name);
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, namespace, typed_value, name);
return new_decl_index;
@@ -2814,53 +2971,28 @@ fn zirEnumDecl(
break :blk decls_len;
} else 0;
- var done = false;
-
- var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
- errdefer if (!done) new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ // Because these three things each reference each other, `undefined`
+ // placeholders are used before being set after the enum type gains an
+ // InternPool index.
- const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
- const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
- enum_ty_payload.* = .{
- .base = .{ .tag = if (small.nonexhaustive) .enum_nonexhaustive else .enum_full },
- .data = enum_obj,
- };
- const enum_ty = Type.initPayload(&enum_ty_payload.base);
- const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
+ var done = false;
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = enum_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, small.name_strategy, "enum", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer if (!done) mod.abortAnonDecl(new_decl_index);
- enum_obj.* = .{
- .owner_decl = new_decl_index,
- .tag_ty = Type.null,
- .tag_ty_inferred = true,
- .fields = .{},
- .values = .{},
- .namespace = .{
- .parent = block.namespace,
- .ty = enum_ty,
- .file_scope = block.getFileScope(),
- },
- };
- std.log.scoped(.module).debug("create enum {*} owned by {*} ({s})", .{
- &enum_obj.namespace, new_decl, new_decl.name,
+ const new_namespace_index = try mod.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
});
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer if (!done) mod.destroyNamespace(new_namespace_index);
- try new_decl.finalizeNewArena(&new_decl_arena);
- const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
- done = true;
-
- var decl_arena: std.heap.ArenaAllocator = undefined;
- const decl_arena_allocator = new_decl.value_arena.?.acquire(gpa, &decl_arena);
- defer new_decl.value_arena.?.release(&decl_arena);
-
- extra_index = try mod.scanNamespace(&enum_obj.namespace, extra_index, decls_len, new_decl);
+ extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
const body = sema.code.extra[extra_index..][0..body_len];
extra_index += body.len;
@@ -2869,7 +3001,34 @@ fn zirEnumDecl(
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 = 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,
+ });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer if (!done) mod.intern_pool.remove(incomplete_enum.index);
+
+ new_decl.ty = Type.type;
+ new_decl.val = incomplete_enum.index.toValue();
+ new_namespace.ty = incomplete_enum.index.toType();
+
+ const decl_val = try sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ done = true;
+
+ const int_tag_ty = ty: {
// We create a block for the field type instructions because they
// may need to reference Decls from inside the enum namespace.
// Within the field type, default value, and alignment expressions, the "owner decl"
@@ -2885,21 +3044,27 @@ fn zirEnumDecl(
}
const prev_owner_func = sema.owner_func;
+ const prev_owner_func_index = sema.owner_func_index;
sema.owner_func = null;
+ sema.owner_func_index = .none;
defer sema.owner_func = prev_owner_func;
+ defer sema.owner_func_index = prev_owner_func_index;
const prev_func = sema.func;
+ const prev_func_index = sema.func_index;
sema.func = null;
+ sema.func_index = .none;
defer sema.func = prev_func;
+ defer sema.func_index = prev_func_index;
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope);
defer wip_captures.deinit();
var enum_block: Block = .{
.parent = null,
.sema = sema,
.src_decl = new_decl_index,
- .namespace = &enum_obj.namespace,
+ .namespace = new_namespace_index,
.wip_capture_scope = wip_captures.scope,
.instructions = .{},
.inlining = null,
@@ -2915,43 +3080,29 @@ fn zirEnumDecl(
if (tag_type_ref != .none) {
const ty = try sema.resolveType(block, tag_ty_src, tag_type_ref);
- if (ty.zigTypeTag() != .Int and ty.zigTypeTag() != .ComptimeInt) {
+ 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)});
}
- enum_obj.tag_ty = try ty.copy(decl_arena_allocator);
- enum_obj.tag_ty_inferred = false;
+ incomplete_enum.setTagType(&mod.intern_pool, ty.toIntern());
+ break :ty ty;
} else if (fields_len == 0) {
- enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, 0);
- enum_obj.tag_ty_inferred = true;
+ break :ty try mod.intType(.unsigned, 0);
} else {
const bits = std.math.log2_int_ceil(usize, fields_len);
- enum_obj.tag_ty = try Type.Tag.int_unsigned.create(decl_arena_allocator, bits);
- enum_obj.tag_ty_inferred = true;
+ break :ty try mod.intType(.unsigned, bits);
}
- }
+ };
- if (small.nonexhaustive and enum_obj.tag_ty.zigTypeTag() != .ComptimeInt) {
- if (fields_len > 1 and std.math.log2_int(u64, fields_len) == enum_obj.tag_ty.bitSize(sema.mod.getTarget())) {
+ 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", .{});
}
}
- try enum_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
- const any_values = for (sema.code.extra[body_end..][0..bit_bags_count]) |bag| {
- if (bag != 0) break true;
- } else false;
- if (any_values) {
- try enum_obj.values.ensureTotalCapacityContext(decl_arena_allocator, fields_len, .{
- .ty = enum_obj.tag_ty,
- .mod = mod,
- });
- }
-
var bit_bag_index: usize = body_end;
var cur_bit_bag: u32 = undefined;
var field_i: u32 = 0;
var last_tag_val: ?Value = null;
- var tag_val_buf: Value.Payload.U64 = undefined;
while (field_i < fields_len) : (field_i += 1) {
if (field_i % 32 == 0) {
cur_bit_bag = sema.code.extra[bit_bag_index];
@@ -2966,15 +3117,12 @@ fn zirEnumDecl(
// doc comment
extra_index += 1;
- // This string needs to outlive the ZIR code.
- const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
-
- const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
- if (gop_field.found_existing) {
- const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
- const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_field.index }).lazy;
+ const field_name = try mod.intern_pool.getOrPutString(gpa, field_name_zir);
+ if (try incomplete_enum.addFieldName(&mod.intern_pool, gpa, field_name)) |other_index| {
+ 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 msg = msg: {
- const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name});
+ const msg = try sema.errMsg(block, field_src, "duplicate enum field '{s}'", .{field_name_zir});
errdefer msg.destroy(gpa);
try sema.errNote(block, other_field_src, msg, "other field here", .{});
break :msg msg;
@@ -2982,13 +3130,13 @@ fn zirEnumDecl(
return sema.failWithOwnedErrorMsg(msg);
}
- if (has_tag_value) {
+ const tag_overflow = if (has_tag_value) overflow: {
const tag_val_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
const tag_inst = try sema.resolveInst(tag_val_ref);
- const tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {
+ last_tag_val = sema.resolveConstValue(block, .unneeded, tag_inst, "") catch |err| switch (err) {
error.NeededSourceLocation => {
- const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
+ const value_src = mod.fieldSrcLoc(new_decl_index, .{
.index = field_i,
.range = .value,
}).lazy;
@@ -2997,63 +3145,56 @@ fn zirEnumDecl(
},
else => |e| return e,
};
- last_tag_val = tag_val;
- const copied_tag_val = try tag_val.copy(decl_arena_allocator);
- const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
- .ty = enum_obj.tag_ty,
- .mod = mod,
- });
- if (gop_val.found_existing) {
- const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
+ 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 (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| {
+ const value_src = mod.fieldSrcLoc(new_decl_index, .{
.index = field_i,
.range = .value,
}).lazy;
- const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy;
+ const other_field_src = mod.fieldSrcLoc(new_decl_index, .{ .index = other_index }).lazy;
const msg = msg: {
- const msg = try sema.errMsg(block, value_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
+ 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);
try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- } else if (any_values) {
- const tag_val = if (last_tag_val) |val|
- try sema.intAdd(val, Value.one, enum_obj.tag_ty)
+ break :overflow false;
+ } else if (any_values) overflow: {
+ var overflow: ?usize = null;
+ last_tag_val = if (last_tag_val) |val|
+ try sema.intAdd(val, try mod.intValue(int_tag_ty, 1), int_tag_ty, &overflow)
else
- Value.zero;
- last_tag_val = tag_val;
- const copied_tag_val = try tag_val.copy(decl_arena_allocator);
- const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
- .ty = enum_obj.tag_ty,
- .mod = mod,
- });
- if (gop_val.found_existing) {
- const field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
- const other_field_src = enum_obj.fieldSrcLoc(sema.mod, .{ .index = gop_val.index }).lazy;
+ try mod.intValue(int_tag_ty, 0);
+ if (overflow != null) break :overflow true;
+ if (try incomplete_enum.addFieldValue(&mod.intern_pool, gpa, last_tag_val.?.toIntern())) |other_index| {
+ 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 msg = msg: {
- const msg = try sema.errMsg(block, field_src, "enum tag value {} already taken", .{tag_val.fmtValue(enum_obj.tag_ty, sema.mod)});
+ 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);
try sema.errNote(block, other_field_src, msg, "other occurrence here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- } else {
- tag_val_buf = .{
- .base = .{ .tag = .int_u64 },
- .data = field_i,
- };
- last_tag_val = Value.initPayload(&tag_val_buf.base);
- }
+ break :overflow false;
+ } else overflow: {
+ 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);
+ break :overflow false;
+ };
- if (!(try sema.intFitsInType(last_tag_val.?, enum_obj.tag_ty, null))) {
- const value_src = enum_obj.fieldSrcLoc(sema.mod, .{
+ if (tag_overflow) {
+ const value_src = mod.fieldSrcLoc(new_decl_index, .{
.index = field_i,
.range = if (has_tag_value) .value else .name,
}).lazy;
const msg = try sema.errMsg(block, value_src, "enumeration value '{}' too large for type '{}'", .{
- last_tag_val.?.fmtValue(enum_obj.tag_ty, mod), enum_obj.tag_ty.fmt(mod),
+ last_tag_val.?.fmtValue(int_tag_ty, mod), int_tag_ty.fmt(mod),
});
return sema.failWithOwnedErrorMsg(msg);
}
@@ -3070,6 +3211,8 @@ fn zirUnionDecl(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
var extra_index: usize = extended.operand;
@@ -3089,55 +3232,60 @@ fn zirUnionDecl(
break :blk decls_len;
} else 0;
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
-
- const union_obj = try new_decl_arena_allocator.create(Module.Union);
- const type_tag = if (small.has_tag_type or small.auto_enum_tag)
- Type.Tag.union_tagged
- else if (small.layout != .Auto)
- Type.Tag.@"union"
- else switch (block.sema.mod.optimizeMode()) {
- .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
- .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
- };
- const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
- union_payload.* = .{
- .base = .{ .tag = type_tag },
- .data = union_obj,
- };
- const union_ty = Type.initPayload(&union_payload.base);
- const union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
- const mod = sema.mod;
+ // 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.type,
- .val = union_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, small.name_strategy, "union", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
- union_obj.* = .{
+
+ const new_namespace_index = try mod.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
+ });
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer mod.destroyNamespace(new_namespace_index);
+
+ const union_index = try mod.createUnion(.{
.owner_decl = new_decl_index,
- .tag_ty = Type.initTag(.null),
+ .tag_ty = Type.null,
.fields = .{},
.zir_index = inst,
.layout = small.layout,
.status = .none,
- .namespace = .{
- .parent = block.namespace,
- .ty = union_ty,
- .file_scope = block.getFileScope(),
- },
- };
- std.log.scoped(.module).debug("create union {*} owned by {*} ({s})", .{
- &union_obj.namespace, new_decl, new_decl.name,
+ .namespace = new_namespace_index,
});
-
- _ = try mod.scanNamespace(&union_obj.namespace, extra_index, decls_len, new_decl);
-
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ errdefer mod.destroyUnion(union_index);
+
+ const union_ty = try mod.intern_pool.get(gpa, .{ .union_type = .{
+ .index = union_index,
+ .runtime_tag = if (small.has_tag_type or small.auto_enum_tag)
+ .tagged
+ else if (small.layout != .Auto)
+ .none
+ else switch (block.sema.mod.optimizeMode()) {
+ .Debug, .ReleaseSafe => .safety,
+ .ReleaseFast, .ReleaseSmall => .none,
+ },
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer mod.intern_pool.remove(union_ty);
+
+ new_decl.ty = Type.type;
+ new_decl.val = union_ty.toValue();
+ new_namespace.ty = union_ty.toType();
+
+ _ = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
+
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
}
fn zirOpaqueDecl(
@@ -3150,7 +3298,6 @@ fn zirOpaqueDecl(
defer tracy.end();
const mod = sema.mod;
- const gpa = sema.gpa;
const small = @bitCast(Zir.Inst.OpaqueDecl.Small, extended.small);
var extra_index: usize = extended.operand;
@@ -3166,42 +3313,42 @@ fn zirOpaqueDecl(
break :blk decls_len;
} else 0;
- var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ // 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 opaque_obj = try new_decl_arena_allocator.create(Module.Opaque);
- const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque);
- opaque_ty_payload.* = .{
- .base = .{ .tag = .@"opaque" },
- .data = opaque_obj,
- };
- const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
- const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = opaque_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, small.name_strategy, "opaque", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
errdefer mod.abortAnonDecl(new_decl_index);
- opaque_obj.* = .{
- .owner_decl = new_decl_index,
- .namespace = .{
- .parent = block.namespace,
- .ty = opaque_ty,
- .file_scope = block.getFileScope(),
- },
- };
- std.log.scoped(.module).debug("create opaque {*} owned by {*} ({s})", .{
- &opaque_obj.namespace, new_decl, new_decl.name,
+ const new_namespace_index = try mod.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
});
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer mod.destroyNamespace(new_namespace_index);
+
+ const opaque_ty = try mod.intern(.{ .opaque_type = .{
+ .decl = new_decl_index,
+ .namespace = new_namespace_index,
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer mod.intern_pool.remove(opaque_ty);
- extra_index = try mod.scanNamespace(&opaque_obj.namespace, extra_index, decls_len, new_decl);
+ new_decl.ty = Type.type;
+ new_decl.val = opaque_ty.toValue();
+ new_namespace.ty = opaque_ty.toType();
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ extra_index = try mod.scanNamespace(new_namespace_index, extra_index, decls_len, new_decl);
+
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
}
fn zirErrorSetDecl(
@@ -3213,48 +3360,39 @@ fn zirErrorSetDecl(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const gpa = sema.gpa;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index);
- var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
-
- const error_set = try new_decl_arena_allocator.create(Module.ErrorSet);
- const error_set_ty = try Type.Tag.error_set.create(new_decl_arena_allocator, error_set);
- const error_set_val = try Value.Tag.ty.create(new_decl_arena_allocator, error_set_ty);
- const mod = sema.mod;
- const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = error_set_val,
- }, name_strategy, "error", inst);
- const new_decl = mod.declPtr(new_decl_index);
- new_decl.owns_tv = true;
- errdefer mod.abortAnonDecl(new_decl_index);
-
- var names = Module.ErrorSet.NameMap{};
- try names.ensureUnusedCapacity(new_decl_arena_allocator, extra.data.fields_len);
+ var names: Module.Fn.InferredErrorSet.NameMap = .{};
+ try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len);
var extra_index = @intCast(u32, extra.end);
const extra_index_end = extra_index + (extra.data.fields_len * 2);
while (extra_index < extra_index_end) : (extra_index += 2) { // +2 to skip over doc_string
const str_index = sema.code.extra[extra_index];
- const kv = try mod.getErrorValue(sema.code.nullTerminatedString(str_index));
- const result = names.getOrPutAssumeCapacity(kv.key);
+ const name = sema.code.nullTerminatedString(str_index);
+ const name_ip = try mod.intern_pool.getOrPutString(gpa, name);
+ _ = try mod.getErrorValue(name_ip);
+ const result = names.getOrPutAssumeCapacity(name_ip);
assert(!result.found_existing); // verified in AstGen
}
- // names must be sorted.
- Module.ErrorSet.sortNames(&names);
+ const error_set_ty = try mod.errorSetFromUnsortedNames(names.keys());
- error_set.* = .{
- .owner_decl = new_decl_index,
- .names = names,
- };
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
+ .ty = Type.type,
+ .val = error_set_ty.toValue(),
+ }, name_strategy, "error", inst);
+ const new_decl = mod.declPtr(new_decl_index);
+ new_decl.owns_tv = true;
+ errdefer mod.abortAnonDecl(new_decl_index);
+
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
}
fn zirRetPtr(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
@@ -3308,7 +3446,8 @@ fn ensureResultUsed(
ty: Type,
src: LazySrcLoc,
) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Void, .NoReturn => return,
.ErrorSet, .ErrorUnion => {
const msg = msg: {
@@ -3336,11 +3475,12 @@ fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand = try sema.resolveInst(inst_data.operand);
const src = inst_data.src();
const operand_ty = sema.typeOf(operand);
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.ErrorSet, .ErrorUnion => {
const msg = msg: {
const msg = try sema.errMsg(block, src, "error is discarded", .{});
@@ -3358,16 +3498,17 @@ fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
- const err_union_ty = if (operand_ty.zigTypeTag() == .Pointer)
- operand_ty.childType()
+ const err_union_ty = if (operand_ty.zigTypeTag(mod) == .Pointer)
+ operand_ty.childType(mod)
else
operand_ty;
- if (err_union_ty.zigTypeTag() != .ErrorUnion) return;
- const payload_ty = err_union_ty.errorUnionPayload().zigTypeTag();
+ if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) return;
+ const payload_ty = err_union_ty.errorUnionPayload(mod).zigTypeTag(mod);
if (payload_ty != .Void and payload_ty != .NoReturn) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "error union payload is ignored", .{});
@@ -3396,30 +3537,27 @@ fn indexablePtrLen(
src: LazySrcLoc,
object: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const object_ty = sema.typeOf(object);
- const is_pointer_to = object_ty.isSinglePointer();
- const array_ty = if (is_pointer_to) object_ty.childType() else object_ty;
- try checkIndexable(sema, block, src, array_ty);
- return sema.fieldVal(block, src, object, "len", src);
+ const is_pointer_to = object_ty.isSinglePointer(mod);
+ const indexable_ty = if (is_pointer_to) object_ty.childType(mod) else object_ty;
+ try checkIndexable(sema, block, src, indexable_ty);
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len");
+ return sema.fieldVal(block, src, object, field_name, src);
}
fn indexablePtrLenOrNone(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- object: Air.Inst.Ref,
+ operand: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
- const object_ty = sema.typeOf(object);
- const array_ty = t: {
- const ptr_size = object_ty.ptrSizeOrNull() orelse break :t object_ty;
- break :t switch (ptr_size) {
- .Many => return .none,
- .One => object_ty.childType(),
- else => object_ty,
- };
- };
- try checkIndexable(sema, block, src, array_ty);
- return sema.fieldVal(block, src, object, "len", src);
+ const mod = sema.mod;
+ const operand_ty = sema.typeOf(operand);
+ try checkMemOperand(sema, block, src, operand_ty);
+ if (operand_ty.ptrSize(mod) == .Many) return .none;
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "len");
+ return sema.fieldVal(block, src, operand, field_name, src);
}
fn zirAllocExtended(
@@ -3427,6 +3565,7 @@ fn zirAllocExtended(
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
+ const gpa = sema.gpa;
const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand);
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = extra.data.src_node };
const align_src: LazySrcLoc = .{ .node_offset_var_decl_align = extra.data.src_node };
@@ -3447,22 +3586,19 @@ fn zirAllocExtended(
break :blk alignment;
} else 0;
- const inferred_alloc_ty = if (small.is_const)
- Type.initTag(.inferred_alloc_const)
- else
- Type.initTag(.inferred_alloc_mut);
-
if (block.is_comptime or small.is_comptime) {
if (small.has_type) {
return sema.analyzeComptimeAlloc(block, var_ty, alignment);
} else {
- return sema.addConstant(
- inferred_alloc_ty,
- try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
+ try sema.air_instructions.append(gpa, .{
+ .tag = .inferred_alloc_comptime,
+ .data = .{ .inferred_alloc_comptime = .{
.decl_index = undefined,
- .alignment = alignment,
- }),
- );
+ .alignment = InternPool.Alignment.fromByteUnits(alignment),
+ .is_const = small.is_const,
+ } },
+ });
+ return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
}
}
@@ -3480,17 +3616,15 @@ fn zirAllocExtended(
return block.addTy(.alloc, ptr_type);
}
- // `Sema.addConstant` does not add the instruction to the block because it is
- // not needed in the case of constant values. However here, we plan to "downgrade"
- // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
- // to the block even though it is currently a `.constant`.
- const result = try sema.addConstant(
- inferred_alloc_ty,
- try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = alignment }),
- );
- try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
- try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
- return result;
+ const result_index = try block.addInstAsIndex(.{
+ .tag = .inferred_alloc,
+ .data = .{ .inferred_alloc = .{
+ .alignment = InternPool.Alignment.fromByteUnits(alignment),
+ .is_const = small.is_const,
+ } },
+ });
+ try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{});
+ return Air.indexToRef(result_index);
}
fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -3504,11 +3638,12 @@ fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
}
fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const alloc = try sema.resolveInst(inst_data.operand);
const alloc_ty = sema.typeOf(alloc);
- var ptr_info = alloc_ty.ptrInfo().data;
+ var ptr_info = alloc_ty.ptrInfo(mod);
const elem_ty = ptr_info.pointee_type;
// Detect if all stores to an `.alloc` were comptime-known.
@@ -3554,18 +3689,26 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
- try elem_ty.copy(anon_decl.arena()),
- try store_val.copy(anon_decl.arena()),
+ elem_ty,
+ store_val,
ptr_info.@"align",
));
}
+ return sema.makePtrConst(block, alloc);
+}
+
+fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const alloc_ty = sema.typeOf(alloc);
+
+ var ptr_info = alloc_ty.ptrInfo(mod);
ptr_info.mutable = false;
const const_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
// Detect if a comptime value simply needs to have its type changed.
if (try sema.resolveMaybeUndefVal(alloc)) |val| {
- return sema.addConstant(const_ptr_ty, val);
+ return sema.addConstant(const_ptr_ty, try mod.getCoerced(val, const_ptr_ty));
}
return block.addBitCast(const_ptr_ty, alloc);
@@ -3574,18 +3717,22 @@ fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
fn zirAllocInferredComptime(
sema: *Sema,
inst: Zir.Inst.Index,
- inferred_alloc_ty: Type,
+ is_const: bool,
) CompileError!Air.Inst.Ref {
+ const gpa = sema.gpa;
const src_node = sema.code.instructions.items(.data)[inst].node;
const src = LazySrcLoc.nodeOffset(src_node);
sema.src = src;
- return sema.addConstant(
- inferred_alloc_ty,
- try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
+
+ try sema.air_instructions.append(gpa, .{
+ .tag = .inferred_alloc_comptime,
+ .data = .{ .inferred_alloc_comptime = .{
.decl_index = undefined,
- .alignment = 0,
- }),
- );
+ .alignment = .none,
+ .is_const = is_const,
+ } },
+ });
+ return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
}
fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -3631,103 +3778,103 @@ fn zirAllocInferred(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
- inferred_alloc_ty: Type,
+ is_const: bool,
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const gpa = sema.gpa;
const src_node = sema.code.instructions.items(.data)[inst].node;
const src = LazySrcLoc.nodeOffset(src_node);
sema.src = src;
if (block.is_comptime) {
- return sema.addConstant(
- inferred_alloc_ty,
- try Value.Tag.inferred_alloc_comptime.create(sema.arena, .{
+ try sema.air_instructions.append(gpa, .{
+ .tag = .inferred_alloc_comptime,
+ .data = .{ .inferred_alloc_comptime = .{
.decl_index = undefined,
- .alignment = 0,
- }),
- );
+ .alignment = .none,
+ .is_const = is_const,
+ } },
+ });
+ return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
}
- // `Sema.addConstant` does not add the instruction to the block because it is
- // not needed in the case of constant values. However here, we plan to "downgrade"
- // to a normal instruction when we hit `resolve_inferred_alloc`. So we append
- // to the block even though it is currently a `.constant`.
- const result = try sema.addConstant(
- inferred_alloc_ty,
- try Value.Tag.inferred_alloc.create(sema.arena, .{ .alignment = 0 }),
- );
- try block.instructions.append(sema.gpa, Air.refToIndex(result).?);
- try sema.unresolved_inferred_allocs.putNoClobber(sema.gpa, Air.refToIndex(result).?, {});
- return result;
+ const result_index = try block.addInstAsIndex(.{
+ .tag = .inferred_alloc,
+ .data = .{ .inferred_alloc = .{
+ .alignment = .none,
+ .is_const = is_const,
+ } },
+ });
+ try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{});
+ return Air.indexToRef(result_index);
}
fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = inst_data.src_node };
const ptr = try sema.resolveInst(inst_data.operand);
const ptr_inst = Air.refToIndex(ptr).?;
- assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
- const value_index = sema.air_instructions.items(.data)[ptr_inst].ty_pl.payload;
- const ptr_val = sema.air_values.items[value_index];
- const var_is_mut = switch (sema.typeOf(ptr).tag()) {
- .inferred_alloc_const => false,
- .inferred_alloc_mut => true,
- else => unreachable,
- };
- const target = sema.mod.getTarget();
+ const target = mod.getTarget();
- switch (ptr_val.tag()) {
+ switch (sema.air_instructions.items(.tag)[ptr_inst]) {
.inferred_alloc_comptime => {
- const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
- const decl_index = iac.data.decl_index;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
-
- const decl = sema.mod.declPtr(decl_index);
- const final_elem_ty = try decl.ty.copy(sema.arena);
- const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = final_elem_ty,
- .mutable = true,
- .@"align" = iac.data.alignment,
- .@"addrspace" = target_util.defaultAddressSpace(target, .local),
+ const iac = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime;
+ const decl_index = iac.decl_index;
+ try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
+
+ const decl = mod.declPtr(decl_index);
+ if (iac.is_const) try decl.intern(mod);
+ const final_elem_ty = decl.ty;
+ const final_ptr_ty = try mod.ptrType(.{
+ .child = final_elem_ty.toIntern(),
+ .flags = .{
+ .is_const = false,
+ .alignment = iac.alignment,
+ .address_space = target_util.defaultAddressSpace(target, .local),
+ },
});
- const final_ptr_ty_inst = try sema.addType(final_ptr_ty);
- sema.air_instructions.items(.data)[ptr_inst].ty_pl.ty = final_ptr_ty_inst;
- if (var_is_mut) {
- sema.air_values.items[value_index] = try Value.Tag.decl_ref_mut.create(sema.arena, .{
- .decl_index = decl_index,
- .runtime_index = block.runtime_index,
- });
- } else {
- sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, decl_index);
- }
+ try sema.maybeQueueFuncBodyAnalysis(decl_index);
+ // Change it to an interned.
+ sema.air_instructions.set(ptr_inst, .{
+ .tag = .interned,
+ .data = .{ .interned = try mod.intern(.{ .ptr = .{
+ .ty = final_ptr_ty.toIntern(),
+ .addr = if (!iac.is_const) .{ .mut_decl = .{
+ .decl = decl_index,
+ .runtime_index = block.runtime_index,
+ } } else .{ .decl = decl_index },
+ } }) },
+ });
},
.inferred_alloc => {
- assert(sema.unresolved_inferred_allocs.remove(ptr_inst));
- const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
- const peer_inst_list = inferred_alloc.data.prongs.items(.stored_inst);
+ const ia1 = sema.air_instructions.items(.data)[ptr_inst].inferred_alloc;
+ const ia2 = sema.unresolved_inferred_allocs.fetchRemove(ptr_inst).?.value;
+ const peer_inst_list = ia2.prongs.items(.stored_inst);
const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_inst_list, .none);
- const final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = final_elem_ty,
- .mutable = true,
- .@"align" = inferred_alloc.data.alignment,
- .@"addrspace" = target_util.defaultAddressSpace(target, .local),
+ const final_ptr_ty = try mod.ptrType(.{
+ .child = final_elem_ty.toIntern(),
+ .flags = .{
+ .alignment = ia1.alignment,
+ .address_space = target_util.defaultAddressSpace(target, .local),
+ },
});
- if (var_is_mut) {
+ if (!ia1.is_const) {
try sema.validateVarType(block, ty_src, final_elem_ty, false);
} else ct: {
// Detect if the value is comptime-known. In such case, the
// last 3 AIR instructions of the block will look like this:
//
- // %a = constant
+ // %a = inferred_alloc
// %b = bitcast(%a)
// %c = store(%b, %d)
//
@@ -3767,42 +3914,46 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
}
};
- const const_inst = while (true) {
+ while (true) {
if (search_index == 0) break :ct;
search_index -= 1;
const candidate = block.instructions.items[search_index];
+ if (candidate == ptr_inst) break;
switch (air_tags[candidate]) {
.dbg_stmt, .dbg_block_begin, .dbg_block_end => continue,
- .constant => break candidate,
else => break :ct,
}
- };
+ }
const store_op = air_datas[store_inst].bin_op;
const store_val = (try sema.resolveMaybeUndefVal(store_op.rhs)) orelse break :ct;
if (store_op.lhs != Air.indexToRef(bitcast_inst)) break :ct;
- if (air_datas[bitcast_inst].ty_op.operand != Air.indexToRef(const_inst)) break :ct;
+ if (air_datas[bitcast_inst].ty_op.operand != ptr) break :ct;
const new_decl_index = d: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
const new_decl_index = try anon_decl.finish(
- try final_elem_ty.copy(anon_decl.arena()),
- try store_val.copy(anon_decl.arena()),
- inferred_alloc.data.alignment,
+ final_elem_ty,
+ store_val,
+ ia1.alignment.toByteUnits(0),
);
break :d new_decl_index;
};
- try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
// Even though we reuse the constant instruction, we still remove it from the
// block so that codegen does not see it.
block.instructions.shrinkRetainingCapacity(search_index);
- sema.air_values.items[value_index] = try Value.Tag.decl_ref.create(sema.arena, new_decl_index);
- // if bitcast ty ref needs to be made const, make_ptr_const
- // ZIR handles it later, so we can just use the ty ref here.
- air_datas[ptr_inst].ty_pl.ty = air_datas[bitcast_inst].ty_op.ty;
+ try sema.maybeQueueFuncBodyAnalysis(new_decl_index);
+ sema.air_instructions.set(ptr_inst, .{
+ .tag = .interned,
+ .data = .{ .interned = try mod.intern(.{ .ptr = .{
+ .ty = final_ptr_ty.toIntern(),
+ .addr = .{ .decl = new_decl_index },
+ } }) },
+ });
// Unless the block is comptime, `alloc_inferred` always produces
// a runtime constant. The final inferred type needs to be
@@ -3823,19 +3974,19 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
// Now we need to go back over all the coerce_result_ptr instructions, which
// previously inserted a bitcast as a placeholder, and do the logic as if
// the new result ptr type was available.
- const placeholders = inferred_alloc.data.prongs.items(.placeholder);
+ const placeholders = ia2.prongs.items(.placeholder);
const gpa = sema.gpa;
var trash_block = block.makeSubBlock();
trash_block.is_comptime = false;
- trash_block.is_coerce_result_ptr = true;
defer trash_block.instructions.deinit(gpa);
- const mut_final_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = final_elem_ty,
- .mutable = true,
- .@"align" = inferred_alloc.data.alignment,
- .@"addrspace" = target_util.defaultAddressSpace(target, .local),
+ const mut_final_ptr_ty = try mod.ptrType(.{
+ .child = final_elem_ty.toIntern(),
+ .flags = .{
+ .alignment = ia1.alignment,
+ .address_space = target_util.defaultAddressSpace(target, .local),
+ },
});
const dummy_ptr = try trash_block.addTy(.alloc, mut_final_ptr_ty);
const empty_trash_count = trash_block.instructions.items.len;
@@ -3843,7 +3994,7 @@ fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Com
for (peer_inst_list, placeholders) |peer_inst, placeholder_inst| {
const sub_ptr_ty = sema.typeOf(Air.indexToRef(placeholder_inst));
- if (mut_final_ptr_ty.eql(sub_ptr_ty, sema.mod)) {
+ if (mut_final_ptr_ty.eql(sub_ptr_ty, mod)) {
// New result location type is the same as the old one; nothing
// to do here.
continue;
@@ -3908,27 +4059,28 @@ fn zirArrayBasePtr(
block: *Block,
inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const start_ptr = try sema.resolveInst(inst_data.operand);
var base_ptr = start_ptr;
- while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
+ while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
.ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
.Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
else => break,
};
- const elem_ty = sema.typeOf(base_ptr).childType();
- switch (elem_ty.zigTypeTag()) {
+ const elem_ty = sema.typeOf(base_ptr).childType(mod);
+ switch (elem_ty.zigTypeTag(mod)) {
.Array, .Vector => return base_ptr,
- .Struct => if (elem_ty.isTuple()) {
+ .Struct => if (elem_ty.isTuple(mod)) {
// TODO validate element count
return base_ptr;
},
else => {},
}
- return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
+ return sema.failWithArrayInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod));
}
fn zirFieldBasePtr(
@@ -3936,27 +4088,30 @@ fn zirFieldBasePtr(
block: *Block,
inst: Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const start_ptr = try sema.resolveInst(inst_data.operand);
var base_ptr = start_ptr;
- while (true) switch (sema.typeOf(base_ptr).childType().zigTypeTag()) {
+ while (true) switch (sema.typeOf(base_ptr).childType(mod).zigTypeTag(mod)) {
.ErrorUnion => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true),
.Optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true),
else => break,
};
- const elem_ty = sema.typeOf(base_ptr).childType();
- switch (elem_ty.zigTypeTag()) {
+ const elem_ty = sema.typeOf(base_ptr).childType(mod);
+ switch (elem_ty.zigTypeTag(mod)) {
.Struct, .Union => return base_ptr,
else => {},
}
- return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType());
+ return sema.failWithStructInitNotSupported(block, src, sema.typeOf(start_ptr).childType(mod));
}
fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const args = sema.code.refSlice(extra.end, extra.data.operands_len);
@@ -3979,7 +4134,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const object_ty = sema.typeOf(object);
// Each arg could be an indexable, or a range, in which case the length
// is passed directly as an integer.
- const is_int = switch (object_ty.zigTypeTag()) {
+ const is_int = switch (object_ty.zigTypeTag(mod)) {
.Int, .ComptimeInt => true,
else => false,
};
@@ -3988,10 +4143,19 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
.input_index = i,
} };
const arg_len_uncoerced = if (is_int) object else l: {
- try checkIndexable(sema, block, arg_src, object_ty);
- if (!object_ty.indexableHasLen()) continue;
+ if (!object_ty.isIndexable(mod)) {
+ // Instead of using checkIndexable we customize this error.
+ const msg = msg: {
+ const msg = try sema.errMsg(block, arg_src, "type '{}' is not indexable and not a range", .{object_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ if (!object_ty.indexableHasLen(mod)) continue;
- break :l try sema.fieldVal(block, arg_src, object, "len", arg_src);
+ break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, "len"), arg_src);
};
const arg_len = try sema.coerce(block, Type.usize, arg_len_uncoerced, arg_src);
if (len == .none) {
@@ -4040,7 +4204,7 @@ fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const object_ty = sema.typeOf(object);
// Each arg could be an indexable, or a range, in which case the length
// is passed directly as an integer.
- switch (object_ty.zigTypeTag()) {
+ switch (object_ty.zigTypeTag(mod)) {
.Int, .ComptimeInt => continue,
else => {},
}
@@ -4075,15 +4239,16 @@ fn validateArrayInitTy(
block: *Block,
inst: Zir.Inst.Index,
) CompileError!void {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const ty_src: LazySrcLoc = .{ .node_offset_init_ty = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data;
const ty = try sema.resolveType(block, ty_src, extra.ty);
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Array => {
- const array_len = ty.arrayLen();
+ const array_len = ty.arrayLen(mod);
if (extra.init_count != array_len) {
return sema.fail(block, src, "expected {d} array elements; found {d}", .{
array_len, extra.init_count,
@@ -4092,7 +4257,7 @@ fn validateArrayInitTy(
return;
},
.Vector => {
- const array_len = ty.arrayLen();
+ const array_len = ty.arrayLen(mod);
if (extra.init_count != array_len) {
return sema.fail(block, src, "expected {d} vector elements; found {d}", .{
array_len, extra.init_count,
@@ -4100,9 +4265,9 @@ fn validateArrayInitTy(
}
return;
},
- .Struct => if (ty.isTuple()) {
+ .Struct => if (ty.isTuple(mod)) {
_ = try sema.resolveTypeFields(ty);
- const array_len = ty.arrayLen();
+ const array_len = ty.arrayLen(mod);
if (extra.init_count > array_len) {
return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{
array_len, extra.init_count,
@@ -4120,11 +4285,12 @@ fn validateStructInitTy(
block: *Block,
inst: Zir.Inst.Index,
) CompileError!void {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ty = try sema.resolveType(block, src, inst_data.operand);
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Struct, .Union => return,
else => {},
}
@@ -4139,6 +4305,7 @@ fn zirValidateStructInit(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
const init_src = validate_inst.src();
const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
@@ -4146,8 +4313,8 @@ fn zirValidateStructInit(
const field_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
const object_ptr = try sema.resolveInst(field_ptr_extra.lhs);
- const agg_ty = sema.typeOf(object_ptr).childType();
- switch (agg_ty.zigTypeTag()) {
+ const agg_ty = sema.typeOf(object_ptr).childType(mod);
+ switch (agg_ty.zigTypeTag(mod)) {
.Struct => return sema.validateStructInit(
block,
agg_ty,
@@ -4173,6 +4340,9 @@ fn validateUnionInit(
instrs: []const Zir.Inst.Index,
union_ptr: Air.Inst.Ref,
) CompileError!void {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+
if (instrs.len != 1) {
const msg = msg: {
const msg = try sema.errMsg(
@@ -4181,7 +4351,7 @@ fn validateUnionInit(
"cannot initialize multiple union fields at once; unions can only have one active field",
.{},
);
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
for (instrs[1..]) |inst| {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
@@ -4205,7 +4375,7 @@ fn validateUnionInit(
const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
+ const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_ptr_extra.field_name_start));
// Validate the field access but ignore the index since we want the tag enum field index.
_ = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
const air_tags = sema.air_instructions.items(.tag);
@@ -4270,21 +4440,25 @@ fn validateUnionInit(
break;
}
- const tag_ty = union_ty.unionTagTypeHypothetical();
- const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
+ const tag_ty = union_ty.unionTagTypeHypothetical(mod);
+ const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
+ const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
if (init_val) |val| {
// Our task is to delete all the `field_ptr` and `store` instructions, and insert
// instead a single `store` to the result ptr with a comptime union value.
block.instructions.shrinkRetainingCapacity(first_block_index);
- var union_val = try Value.Tag.@"union".create(sema.arena, .{
- .tag = tag_val,
- .val = val,
- });
- if (make_runtime) union_val = try Value.Tag.runtime_value.create(sema.arena, union_val);
- const union_init = try sema.addConstant(union_ty, union_val);
+ var union_val = try mod.intern(.{ .un = .{
+ .ty = union_ty.toIntern(),
+ .tag = tag_val.toIntern(),
+ .val = val.toIntern(),
+ } });
+ if (make_runtime) union_val = try mod.intern(.{ .runtime_value = .{
+ .ty = union_ty.toIntern(),
+ .val = union_val,
+ } });
+ const union_init = try sema.addConstant(union_ty, union_val.toValue());
try sema.storePtr2(block, init_src, union_ptr, init_src, union_init, init_src, .store);
return;
} else if (try sema.typeRequiresComptime(union_ty)) {
@@ -4302,10 +4476,12 @@ fn validateStructInit(
init_src: LazySrcLoc,
instrs: []const Zir.Inst.Index,
) CompileError!void {
+ const mod = sema.mod;
const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
// Maps field index to field_ptr index of where it was already initialized.
- const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount());
+ const found_fields = try gpa.alloc(Zir.Inst.Index, struct_ty.structFieldCount(mod));
defer gpa.free(found_fields);
@memset(found_fields, 0);
@@ -4316,8 +4492,11 @@ fn validateStructInit(
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_ptr_data.src_node };
const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data;
struct_ptr_zir_ref = field_ptr_extra.lhs;
- const field_name = sema.code.nullTerminatedString(field_ptr_extra.field_name_start);
- const field_index = if (struct_ty.isTuple())
+ const field_name = try ip.getOrPutString(
+ gpa,
+ sema.code.nullTerminatedString(field_ptr_extra.field_name_start),
+ );
+ const field_index = if (struct_ty.isTuple(mod))
try sema.tupleFieldIndex(block, struct_ty, field_name, field_src)
else
try sema.structFieldIndex(block, struct_ty, field_name, field_src);
@@ -4350,9 +4529,9 @@ fn validateStructInit(
for (found_fields, 0..) |field_ptr, i| {
if (field_ptr != 0) continue;
- const default_val = struct_ty.structFieldDefaultValue(i);
- if (default_val.tag() == .unreachable_value) {
- if (struct_ty.isTuple()) {
+ const default_val = struct_ty.structFieldDefaultValue(i, mod);
+ if (default_val.toIntern() == .unreachable_value) {
+ if (struct_ty.isTuple(mod)) {
const template = "missing tuple field with index {d}";
if (root_msg) |msg| {
try sema.errNote(block, init_src, msg, template, .{i});
@@ -4361,9 +4540,9 @@ fn validateStructInit(
}
continue;
}
- const field_name = struct_ty.structFieldName(i);
- const template = "missing struct field: {s}";
- const args = .{field_name};
+ const field_name = struct_ty.structFieldName(i, mod);
+ const template = "missing struct field: {}";
+ const args = .{field_name.fmt(ip)};
if (root_msg) |msg| {
try sema.errNote(block, init_src, msg, template, args);
} else {
@@ -4373,25 +4552,23 @@ fn validateStructInit(
}
const field_src = init_src; // TODO better source location
- const default_field_ptr = if (struct_ty.isTuple())
+ const default_field_ptr = if (struct_ty.isTuple(mod))
try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
else
try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
- const field_ty = sema.typeOf(default_field_ptr).childType();
+ const field_ty = sema.typeOf(default_field_ptr).childType(mod);
const init = try sema.addConstant(field_ty, default_val);
try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
}
if (root_msg) |msg| {
- if (struct_ty.castTag(.@"struct")) |struct_obj| {
- const mod = sema.mod;
- const fqn = try struct_obj.data.getFullyQualifiedName(mod);
- defer gpa.free(fqn);
+ if (mod.typeToStruct(struct_ty)) |struct_obj| {
+ const fqn = try struct_obj.getFullyQualifiedName(mod);
try mod.errNoteNonLazy(
- struct_obj.data.srcLoc(mod),
+ struct_obj.srcLoc(mod),
msg,
- "struct '{s}' declared here",
- .{fqn},
+ "struct '{}' declared here",
+ .{fqn.fmt(ip)},
);
}
root_msg = null;
@@ -4411,14 +4588,14 @@ fn validateStructInit(
// We collect the comptime field values in case the struct initialization
// ends up being comptime-known.
- const field_values = try sema.arena.alloc(Value, struct_ty.structFieldCount());
+ const field_values = try sema.arena.alloc(InternPool.Index, struct_ty.structFieldCount(mod));
field: for (found_fields, 0..) |field_ptr, i| {
if (field_ptr != 0) {
// Determine whether the value stored to this pointer is comptime-known.
- const field_ty = struct_ty.structFieldType(i);
+ const field_ty = struct_ty.structFieldType(i, mod);
if (try sema.typeHasOnePossibleValue(field_ty)) |opv| {
- field_values[i] = opv;
+ field_values[i] = opv.toIntern();
continue;
}
@@ -4483,7 +4660,7 @@ fn validateStructInit(
first_block_index = @min(first_block_index, block_index);
}
if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| {
- field_values[i] = val;
+ field_values[i] = val.toIntern();
} else if (require_comptime) {
const field_ptr_data = sema.code.instructions.items(.data)[field_ptr].pl_node;
return sema.failWithNeededComptime(block, field_ptr_data.src(), "initializer of comptime only struct must be comptime-known");
@@ -4496,9 +4673,9 @@ fn validateStructInit(
continue :field;
}
- const default_val = struct_ty.structFieldDefaultValue(i);
- if (default_val.tag() == .unreachable_value) {
- if (struct_ty.isTuple()) {
+ const default_val = struct_ty.structFieldDefaultValue(i, mod);
+ if (default_val.toIntern() == .unreachable_value) {
+ if (struct_ty.isTuple(mod)) {
const template = "missing tuple field with index {d}";
if (root_msg) |msg| {
try sema.errNote(block, init_src, msg, template, .{i});
@@ -4507,9 +4684,9 @@ fn validateStructInit(
}
continue;
}
- const field_name = struct_ty.structFieldName(i);
- const template = "missing struct field: {s}";
- const args = .{field_name};
+ const field_name = struct_ty.structFieldName(i, mod);
+ const template = "missing struct field: {}";
+ const args = .{field_name.fmt(ip)};
if (root_msg) |msg| {
try sema.errNote(block, init_src, msg, template, args);
} else {
@@ -4517,18 +4694,17 @@ fn validateStructInit(
}
continue;
}
- field_values[i] = default_val;
+ field_values[i] = default_val.toIntern();
}
if (root_msg) |msg| {
- if (struct_ty.castTag(.@"struct")) |struct_obj| {
- const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
- defer gpa.free(fqn);
- try sema.mod.errNoteNonLazy(
- struct_obj.data.srcLoc(sema.mod),
+ if (mod.typeToStruct(struct_ty)) |struct_obj| {
+ const fqn = try struct_obj.getFullyQualifiedName(mod);
+ try mod.errNoteNonLazy(
+ struct_obj.srcLoc(mod),
msg,
- "struct '{s}' declared here",
- .{fqn},
+ "struct '{}' declared here",
+ .{fqn.fmt(ip)},
);
}
root_msg = null;
@@ -4540,9 +4716,15 @@ fn validateStructInit(
// instead a single `store` to the struct_ptr with a comptime struct value.
block.instructions.shrinkRetainingCapacity(first_block_index);
- var struct_val = try Value.Tag.aggregate.create(sema.arena, field_values);
- if (make_runtime) struct_val = try Value.Tag.runtime_value.create(sema.arena, struct_val);
- const struct_init = try sema.addConstant(struct_ty, struct_val);
+ var struct_val = try mod.intern(.{ .aggregate = .{
+ .ty = struct_ty.toIntern(),
+ .storage = .{ .elems = field_values },
+ } });
+ if (make_runtime) struct_val = try mod.intern(.{ .runtime_value = .{
+ .ty = struct_ty.toIntern(),
+ .val = struct_val,
+ } });
+ const struct_init = try sema.addConstant(struct_ty, struct_val.toValue());
try sema.storePtr2(block, init_src, struct_ptr, init_src, struct_init, init_src, .store);
return;
}
@@ -4553,12 +4735,12 @@ fn validateStructInit(
if (field_ptr != 0) continue;
const field_src = init_src; // TODO better source location
- const default_field_ptr = if (struct_ty.isTuple())
+ const default_field_ptr = if (struct_ty.isTuple(mod))
try sema.tupleFieldPtr(block, init_src, struct_ptr, field_src, @intCast(u32, i), true)
else
try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(u32, i), field_src, struct_ty, true);
- const field_ty = sema.typeOf(default_field_ptr).childType();
- const init = try sema.addConstant(field_ty, field_values[i]);
+ const field_ty = sema.typeOf(default_field_ptr).childType(mod);
+ const init = try sema.addConstant(field_ty, field_values[i].toValue());
try sema.storePtr2(block, init_src, default_field_ptr, init_src, init, field_src, .store);
}
}
@@ -4568,6 +4750,7 @@ fn zirValidateArrayInit(
block: *Block,
inst: Zir.Inst.Index,
) CompileError!void {
+ const mod = sema.mod;
const validate_inst = sema.code.instructions.items(.data)[inst].pl_node;
const init_src = validate_inst.src();
const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index);
@@ -4575,18 +4758,18 @@ fn zirValidateArrayInit(
const first_elem_ptr_data = sema.code.instructions.items(.data)[instrs[0]].pl_node;
const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data;
const array_ptr = try sema.resolveInst(elem_ptr_extra.ptr);
- const array_ty = sema.typeOf(array_ptr).childType();
- const array_len = array_ty.arrayLen();
+ const array_ty = sema.typeOf(array_ptr).childType(mod);
+ const array_len = array_ty.arrayLen(mod);
- if (instrs.len != array_len) switch (array_ty.zigTypeTag()) {
+ if (instrs.len != array_len) switch (array_ty.zigTypeTag(mod)) {
.Struct => {
var root_msg: ?*Module.ErrorMsg = null;
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
var i = instrs.len;
while (i < array_len) : (i += 1) {
- const default_val = array_ty.structFieldDefaultValue(i);
- if (default_val.tag() == .unreachable_value) {
+ const default_val = array_ty.structFieldDefaultValue(i, mod);
+ if (default_val.toIntern() == .unreachable_value) {
const template = "missing tuple field with index {d}";
if (root_msg) |msg| {
try sema.errNote(block, init_src, msg, template, .{i});
@@ -4621,39 +4804,41 @@ fn zirValidateArrayInit(
// at comptime so we have almost nothing to do here. However, in case of a
// sentinel-terminated array, the sentinel will not have been populated by
// any ZIR instructions at comptime; we need to do that here.
- if (array_ty.sentinel()) |sentinel_val| {
+ if (array_ty.sentinel(mod)) |sentinel_val| {
const array_len_ref = try sema.addIntUnsigned(Type.usize, array_len);
const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true);
- const sentinel = try sema.addConstant(array_ty.childType(), sentinel_val);
+ const sentinel = try sema.addConstant(array_ty.childType(mod), sentinel_val);
try sema.storePtr2(block, init_src, sentinel_ptr, init_src, sentinel, init_src, .store);
}
return;
}
+ // If the array has one possible value, the value is always comptime-known.
+ if (try sema.typeHasOnePossibleValue(array_ty)) |array_opv| {
+ const array_init = try sema.addConstant(array_ty, array_opv);
+ try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
+ return;
+ }
+
var array_is_comptime = true;
var first_block_index = block.instructions.items.len;
var make_runtime = false;
// Collect the comptime element values in case the array literal ends up
// being comptime-known.
- const array_len_s = try sema.usizeCast(block, init_src, array_ty.arrayLenIncludingSentinel());
- const element_vals = try sema.arena.alloc(Value, array_len_s);
- const opt_opv = try sema.typeHasOnePossibleValue(array_ty);
+ const element_vals = try sema.arena.alloc(
+ InternPool.Index,
+ try sema.usizeCast(block, init_src, array_len),
+ );
const air_tags = sema.air_instructions.items(.tag);
const air_datas = sema.air_instructions.items(.data);
outer: for (instrs, 0..) |elem_ptr, i| {
// Determine whether the value stored to this pointer is comptime-known.
- if (array_ty.isTuple()) {
- if (array_ty.structFieldValueComptime(i)) |opv| {
- element_vals[i] = opv;
- continue;
- }
- } else {
- // Array has one possible value, so value is always comptime-known
- if (opt_opv) |opv| {
- element_vals[i] = opv;
+ if (array_ty.isTuple(mod)) {
+ if (try array_ty.structFieldValueComptime(mod, i)) |opv| {
+ element_vals[i] = opv.toIntern();
continue;
}
}
@@ -4714,7 +4899,7 @@ fn zirValidateArrayInit(
first_block_index = @min(first_block_index, block_index);
}
if (try sema.resolveMaybeUndefValAllowVariablesMaybeRuntime(bin_op.rhs, &make_runtime)) |val| {
- element_vals[i] = val;
+ element_vals[i] = val.toIntern();
} else {
array_is_comptime = false;
}
@@ -4726,50 +4911,55 @@ fn zirValidateArrayInit(
if (array_is_comptime) {
if (try sema.resolveDefinedValue(block, init_src, array_ptr)) |ptr_val| {
- if (ptr_val.tag() == .comptime_field_ptr) {
- // This store was validated by the individual elem ptrs.
- return;
+ switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
+ .ptr => |ptr| switch (ptr.addr) {
+ .comptime_field => return, // This store was validated by the individual elem ptrs.
+ else => {},
+ },
+ else => {},
}
}
// Our task is to delete all the `elem_ptr` and `store` instructions, and insert
// instead a single `store` to the array_ptr with a comptime struct value.
- // Also to populate the sentinel value, if any.
- if (array_ty.sentinel()) |sentinel_val| {
- element_vals[instrs.len] = sentinel_val;
- }
-
block.instructions.shrinkRetainingCapacity(first_block_index);
- var array_val = try Value.Tag.aggregate.create(sema.arena, element_vals);
- if (make_runtime) array_val = try Value.Tag.runtime_value.create(sema.arena, array_val);
- const array_init = try sema.addConstant(array_ty, array_val);
+ var array_val = try mod.intern(.{ .aggregate = .{
+ .ty = array_ty.toIntern(),
+ .storage = .{ .elems = element_vals },
+ } });
+ if (make_runtime) array_val = try mod.intern(.{ .runtime_value = .{
+ .ty = array_ty.toIntern(),
+ .val = array_val,
+ } });
+ const array_init = try sema.addConstant(array_ty, array_val.toValue());
try sema.storePtr2(block, init_src, array_ptr, init_src, array_init, init_src, .store);
}
}
fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
- if (operand_ty.zigTypeTag() != .Pointer) {
- return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(sema.mod)});
- } else switch (operand_ty.ptrSize()) {
+ if (operand_ty.zigTypeTag(mod) != .Pointer) {
+ return sema.fail(block, src, "cannot dereference non-pointer type '{}'", .{operand_ty.fmt(mod)});
+ } else switch (operand_ty.ptrSize(mod)) {
.One, .C => {},
- .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(sema.mod)}),
- .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(sema.mod)}),
+ .Many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{}'", .{operand_ty.fmt(mod)}),
+ .Slice => return sema.fail(block, src, "index syntax required for slice type '{}'", .{operand_ty.fmt(mod)}),
}
- if ((try sema.typeHasOnePossibleValue(operand_ty.childType())) != null) {
+ if ((try sema.typeHasOnePossibleValue(operand_ty.childType(mod))) != null) {
// No need to validate the actual pointer value, we don't need it!
return;
}
- const elem_ty = operand_ty.elemType2();
+ const elem_ty = operand_ty.elemType2(mod);
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) {
+ if (val.isUndef(mod)) {
return sema.fail(block, src, "cannot dereference undefined value", .{});
}
} else if (!(try sema.validateRunTimeType(elem_ty, false))) {
@@ -4778,12 +4968,12 @@ fn zirValidateDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
block,
src,
"values of type '{}' must be comptime-known, but operand value is runtime-known",
- .{elem_ty.fmt(sema.mod)},
+ .{elem_ty.fmt(mod)},
);
errdefer msg.destroy(sema.gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), elem_ty);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), elem_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -4795,23 +4985,24 @@ fn failWithBadMemberAccess(
block: *Block,
agg_ty: Type,
field_src: LazySrcLoc,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
) CompileError {
- const kw_name = switch (agg_ty.zigTypeTag()) {
+ const mod = sema.mod;
+ const kw_name = switch (agg_ty.zigTypeTag(mod)) {
.Union => "union",
.Struct => "struct",
.Opaque => "opaque",
.Enum => "enum",
else => unreachable,
};
- if (agg_ty.getOwnerDeclOrNull()) |some| if (sema.mod.declIsRoot(some)) {
- return sema.fail(block, field_src, "root struct of file '{}' has no member named '{s}'", .{
- agg_ty.fmt(sema.mod), field_name,
+ if (agg_ty.getOwnerDeclOrNull(mod)) |some| if (mod.declIsRoot(some)) {
+ return sema.fail(block, field_src, "root struct of file '{}' has no member named '{}'", .{
+ agg_ty.fmt(mod), field_name.fmt(&mod.intern_pool),
});
};
const msg = msg: {
- const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{s}'", .{
- kw_name, agg_ty.fmt(sema.mod), field_name,
+ const msg = try sema.errMsg(block, field_src, "{s} '{}' has no member named '{}'", .{
+ kw_name, agg_ty.fmt(mod), field_name.fmt(&mod.intern_pool),
});
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, agg_ty);
@@ -4825,22 +5016,22 @@ fn failWithBadStructFieldAccess(
block: *Block,
struct_obj: *Module.Struct,
field_src: LazySrcLoc,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
) CompileError {
+ const mod = sema.mod;
const gpa = sema.gpa;
- const fqn = try struct_obj.getFullyQualifiedName(sema.mod);
- defer gpa.free(fqn);
+ const fqn = try struct_obj.getFullyQualifiedName(mod);
const msg = msg: {
const msg = try sema.errMsg(
block,
field_src,
- "no field named '{s}' in struct '{s}'",
- .{ field_name, fqn },
+ "no field named '{}' in struct '{}'",
+ .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },
);
errdefer msg.destroy(gpa);
- try sema.mod.errNoteNonLazy(struct_obj.srcLoc(sema.mod), msg, "struct declared here", .{});
+ try mod.errNoteNonLazy(struct_obj.srcLoc(mod), msg, "struct declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -4851,30 +5042,31 @@ fn failWithBadUnionFieldAccess(
block: *Block,
union_obj: *Module.Union,
field_src: LazySrcLoc,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
) CompileError {
+ const mod = sema.mod;
const gpa = sema.gpa;
- const fqn = try union_obj.getFullyQualifiedName(sema.mod);
- defer gpa.free(fqn);
+ const fqn = try union_obj.getFullyQualifiedName(mod);
const msg = msg: {
const msg = try sema.errMsg(
block,
field_src,
- "no field named '{s}' in union '{s}'",
- .{ field_name, fqn },
+ "no field named '{}' in union '{}'",
+ .{ field_name.fmt(&mod.intern_pool), fqn.fmt(&mod.intern_pool) },
);
errdefer msg.destroy(gpa);
- try sema.mod.errNoteNonLazy(union_obj.srcLoc(sema.mod), msg, "union declared here", .{});
+ try mod.errNoteNonLazy(union_obj.srcLoc(mod), msg, "union declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !void {
- const src_loc = decl_ty.declSrcLocOrNull(sema.mod) orelse return;
- const category = switch (decl_ty.zigTypeTag()) {
+ const mod = sema.mod;
+ const src_loc = decl_ty.declSrcLocOrNull(mod) orelse return;
+ const category = switch (decl_ty.zigTypeTag(mod)) {
.Union => "union",
.Struct => "struct",
.Enum => "enum",
@@ -4882,7 +5074,7 @@ fn addDeclaredHereNote(sema: *Sema, parent: *Module.ErrorMsg, decl_ty: Type) !vo
.ErrorSet => "error set",
else => unreachable,
};
- try sema.mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category});
+ try mod.errNoteNonLazy(src_loc, parent, "{s} declared here", .{category});
}
fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@@ -4898,17 +5090,14 @@ fn zirStoreToBlockPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const src: LazySrcLoc = sema.src;
blk: {
const ptr_inst = Air.refToIndex(ptr) orelse break :blk;
- if (sema.air_instructions.items(.tag)[ptr_inst] != .constant) break :blk;
- const air_datas = sema.air_instructions.items(.data);
- const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
- switch (ptr_val.tag()) {
+ switch (sema.air_instructions.items(.tag)[ptr_inst]) {
.inferred_alloc_comptime => {
- const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
+ const iac = &sema.air_instructions.items(.data)[ptr_inst].inferred_alloc_comptime;
return sema.storeToInferredAllocComptime(block, src, operand, iac);
},
.inferred_alloc => {
- const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
- return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc);
+ const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
+ return sema.storeToInferredAlloc(block, ptr, operand, ia);
},
else => break :blk,
}
@@ -4926,18 +5115,16 @@ fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compi
const ptr = try sema.resolveInst(bin_inst.lhs);
const operand = try sema.resolveInst(bin_inst.rhs);
const ptr_inst = Air.refToIndex(ptr).?;
- assert(sema.air_instructions.items(.tag)[ptr_inst] == .constant);
const air_datas = sema.air_instructions.items(.data);
- const ptr_val = sema.air_values.items[air_datas[ptr_inst].ty_pl.payload];
- switch (ptr_val.tag()) {
+ switch (sema.air_instructions.items(.tag)[ptr_inst]) {
.inferred_alloc_comptime => {
- const iac = ptr_val.castTag(.inferred_alloc_comptime).?;
+ const iac = &air_datas[ptr_inst].inferred_alloc_comptime;
return sema.storeToInferredAllocComptime(block, src, operand, iac);
},
.inferred_alloc => {
- const inferred_alloc = ptr_val.castTag(.inferred_alloc).?;
- return sema.storeToInferredAlloc(block, ptr, operand, inferred_alloc);
+ const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?;
+ return sema.storeToInferredAlloc(block, ptr, operand, ia);
},
else => unreachable,
}
@@ -4948,14 +5135,14 @@ fn storeToInferredAlloc(
block: *Block,
ptr: Air.Inst.Ref,
operand: Air.Inst.Ref,
- inferred_alloc: *Value.Payload.InferredAlloc,
+ inferred_alloc: *InferredAlloc,
) CompileError!void {
// Create a store instruction as a placeholder. This will be replaced by a
// proper store sequence once we know the stored type.
const dummy_store = try block.addBinOp(.store, ptr, operand);
// Add the stored instruction to the set we will use to resolve peer types
// for the inferred allocation.
- try inferred_alloc.data.prongs.append(sema.arena, .{
+ try inferred_alloc.prongs.append(sema.arena, .{
.stored_inst = operand,
.placeholder = Air.refToIndex(dummy_store).?,
});
@@ -4966,20 +5153,21 @@ fn storeToInferredAllocComptime(
block: *Block,
src: LazySrcLoc,
operand: Air.Inst.Ref,
- iac: *Value.Payload.InferredAllocComptime,
+ iac: *Air.Inst.Data.InferredAllocComptime,
) CompileError!void {
const operand_ty = sema.typeOf(operand);
// There will be only one store_to_inferred_ptr because we are running at comptime.
// The alloc will turn into a Decl.
if (try sema.resolveMaybeUndefValAllowVariables(operand)) |operand_val| store: {
- if (operand_val.tag() == .variable) break :store;
+ if (operand_val.getVariable(sema.mod) != null) break :store;
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- iac.data.decl_index = try anon_decl.finish(
- try operand_ty.copy(anon_decl.arena()),
- try operand_val.copy(anon_decl.arena()),
- iac.data.alignment,
+ iac.decl_index = try anon_decl.finish(
+ operand_ty,
+ operand_val,
+ iac.alignment.toByteUnits(0),
);
+ try sema.comptime_mutable_decls.append(iac.decl_index);
return;
}
@@ -5007,6 +5195,7 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const zir_tags = sema.code.instructions.items(.tag);
const zir_datas = sema.code.instructions.items(.data);
const inst_data = zir_datas[inst].pl_node;
@@ -5025,9 +5214,9 @@ fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!v
// %b = store(%a, %c)
// Where %c is an error union or error set. In such case we need to add
// to the current function's inferred error set, if any.
- if (is_ret and (sema.typeOf(operand).zigTypeTag() == .ErrorUnion or
- sema.typeOf(operand).zigTypeTag() == .ErrorSet) and
- sema.fn_ret_ty.zigTypeTag() == .ErrorUnion)
+ if (is_ret and (sema.typeOf(operand).zigTypeTag(mod) == .ErrorUnion or
+ sema.typeOf(operand).zigTypeTag(mod) == .ErrorSet) and
+ sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion)
{
try sema.addToInferredErrorSet(operand);
}
@@ -5051,47 +5240,30 @@ fn zirStr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
return sema.addStrLit(block, bytes);
}
-fn addStrLit(sema: *Sema, block: *Block, zir_bytes: []const u8) CompileError!Air.Inst.Ref {
- // `zir_bytes` references memory inside the ZIR module, which can get deallocated
- // after semantic analysis is complete, for example in the case of the initialization
- // expression of a variable declaration.
+fn addStrLit(sema: *Sema, block: *Block, bytes: []const u8) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const gpa = sema.gpa;
- const string_bytes = &mod.string_literal_bytes;
- const StringLiteralAdapter = Module.StringLiteralAdapter;
- const StringLiteralContext = Module.StringLiteralContext;
- try string_bytes.ensureUnusedCapacity(gpa, zir_bytes.len);
- const gop = try mod.string_literal_table.getOrPutContextAdapted(gpa, zir_bytes, StringLiteralAdapter{
- .bytes = string_bytes,
- }, StringLiteralContext{
- .bytes = string_bytes,
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const duped_bytes = try sema.arena.dupe(u8, bytes);
+ const ty = try mod.arrayType(.{
+ .len = bytes.len,
+ .child = .u8_type,
+ .sentinel = .zero_u8,
});
+ const val = try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .bytes = duped_bytes },
+ } });
+ const gop = try mod.memoized_decls.getOrPut(gpa, val);
if (!gop.found_existing) {
- gop.key_ptr.* = .{
- .index = @intCast(u32, string_bytes.items.len),
- .len = @intCast(u32, zir_bytes.len),
- };
- string_bytes.appendSliceAssumeCapacity(zir_bytes);
- gop.value_ptr.* = .none;
+ const new_decl_index = try mod.createAnonymousDecl(block, .{
+ .ty = ty,
+ .val = val.toValue(),
+ });
+ gop.value_ptr.* = new_decl_index;
+ try mod.finalizeAnonDecl(new_decl_index);
}
- const decl_index = gop.value_ptr.unwrap() orelse di: {
- var anon_decl = try block.startAnonDecl();
- defer anon_decl.deinit();
-
- const decl_index = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), gop.key_ptr.len),
- try Value.Tag.str_lit.create(anon_decl.arena(), gop.key_ptr.*),
- 0, // default alignment
- );
-
- // Needed so that `Decl.clearValues` will additionally set the corresponding
- // string literal table value back to `Decl.OptionalIndex.none`.
- mod.declPtr(decl_index).owns_tv = true;
-
- gop.value_ptr.* = decl_index.toOptional();
- break :di decl_index;
- };
- return sema.analyzeDeclRef(decl_index);
+ return sema.analyzeDeclRef(gop.value_ptr.*);
}
fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -5100,7 +5272,7 @@ fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
defer tracy.end();
const int = sema.code.instructions.items(.data)[inst].int;
- return sema.addIntUnsigned(Type.initTag(.comptime_int), int);
+ return sema.addIntUnsigned(Type.comptime_int, int);
}
fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -5108,38 +5280,43 @@ fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const tracy = trace(@src());
defer tracy.end();
- const arena = sema.arena;
+ const mod = sema.mod;
const int = sema.code.instructions.items(.data)[inst].str;
const byte_count = int.len * @sizeOf(std.math.big.Limb);
const limb_bytes = sema.code.string_bytes[int.start..][0..byte_count];
- const limbs = try arena.alloc(std.math.big.Limb, int.len);
+
+ // TODO: this allocation and copy is only needed because the limbs may be unaligned.
+ // If ZIR is adjusted so that big int limbs are guaranteed to be aligned, these
+ // two lines can be removed.
+ const limbs = try sema.arena.alloc(std.math.big.Limb, int.len);
@memcpy(mem.sliceAsBytes(limbs), limb_bytes);
return sema.addConstant(
- Type.initTag(.comptime_int),
- try Value.Tag.int_big_positive.create(arena, limbs),
+ Type.comptime_int,
+ try mod.intValue_big(Type.comptime_int, .{
+ .limbs = limbs,
+ .positive = true,
+ }),
);
}
fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
_ = block;
- const arena = sema.arena;
const number = sema.code.instructions.items(.data)[inst].float;
return sema.addConstant(
- Type.initTag(.comptime_float),
- try Value.Tag.float_64.create(arena, number),
+ Type.comptime_float,
+ try sema.mod.floatValue(Type.comptime_float, number),
);
}
fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
_ = block;
- const arena = sema.arena;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data;
const number = extra.get();
return sema.addConstant(
- Type.initTag(.comptime_float),
- try Value.Tag.float_128.create(arena, number),
+ Type.comptime_float,
+ try sema.mod.floatValue(Type.comptime_float, number),
);
}
@@ -5158,7 +5335,9 @@ fn zirCompileLog(
sema: *Sema,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
- var managed = sema.mod.compile_log_text.toManaged(sema.gpa);
+ const mod = sema.mod;
+
+ var managed = mod.compile_log_text.toManaged(sema.gpa);
defer sema.mod.compile_log_text = managed.moveToUnmanaged();
const writer = managed.writer();
@@ -5171,19 +5350,18 @@ fn zirCompileLog(
const arg = try sema.resolveInst(arg_ref);
const arg_ty = sema.typeOf(arg);
- if (try sema.resolveMaybeUndefVal(arg)) |val| {
- try sema.resolveLazyValue(val);
+ if (try sema.resolveMaybeUndefLazyVal(arg)) |val| {
try writer.print("@as({}, {})", .{
- arg_ty.fmt(sema.mod), val.fmtValue(arg_ty, sema.mod),
+ arg_ty.fmt(mod), val.fmtValue(arg_ty, mod),
});
} else {
- try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(sema.mod)});
+ try writer.print("@as({}, [runtime value])", .{arg_ty.fmt(mod)});
}
}
try writer.print("\n", .{});
const decl_index = if (sema.func) |some| some.owner_decl else sema.owner_decl_index;
- const gop = try sema.mod.compile_log_decls.getOrPut(sema.gpa, decl_index);
+ const gop = try mod.compile_log_decls.getOrPut(sema.gpa, decl_index);
if (!gop.found_existing) {
gop.value_ptr.* = src_node;
}
@@ -5198,7 +5376,7 @@ fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir.I
if (block.is_comptime) {
return sema.fail(block, src, "encountered @panic at comptime", .{});
}
- try sema.panicWithMsg(block, src, msg_inst);
+ try sema.panicWithMsg(block, msg_inst);
return always_noreturn;
}
@@ -5214,6 +5392,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index);
@@ -5263,7 +5442,7 @@ fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError
try sema.analyzeBody(&loop_block, body);
const loop_block_len = loop_block.instructions.items.len;
- if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn()) {
+ if (loop_block_len > 0 and sema.typeOf(Air.indexToRef(loop_block.instructions.items[loop_block_len - 1])).isNoReturn(mod)) {
// If the loop ended with a noreturn terminator, then there is no way for it to loop,
// so we can just use the block instead.
try child_block.instructions.appendSlice(gpa, loop_block.instructions.items);
@@ -5290,7 +5469,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
// we check this here to avoid undefined symbols
if (!@import("build_options").have_llvm)
- return sema.fail(parent_block, src, "cannot do C import on Zig compiler not built with LLVM-extension", .{});
+ return sema.fail(parent_block, src, "C import unavailable; Zig compiler built without LLVM extensions", .{});
var c_import_buf = std.ArrayList(u8).init(sema.gpa);
defer c_import_buf.deinit();
@@ -5333,7 +5512,7 @@ fn zirCImport(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileEr
if (!mod.comp.bin_file.options.link_libc)
try sema.errNote(&child_block, src, msg, "libc headers not available; compilation does not link against libc", .{});
- const gop = try sema.mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index);
+ const gop = try mod.cimport_errors.getOrPut(sema.gpa, sema.owner_decl_index);
if (!gop.found_existing) {
var errs = try std.ArrayListUnmanaged(Module.CImportError).initCapacity(sema.gpa, c_import_res.errors.len);
errdefer {
@@ -5516,7 +5695,7 @@ fn analyzeBlockBody(
// Blocks must terminate with noreturn instruction.
assert(child_block.instructions.items.len != 0);
- assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn());
+ assert(sema.typeOf(Air.indexToRef(child_block.instructions.items[child_block.instructions.items.len - 1])).isNoReturn(mod));
if (merges.results.items.len == 0) {
// No need for a block instruction. We can put the new instructions
@@ -5557,7 +5736,7 @@ fn analyzeBlockBody(
try sema.errNote(child_block, runtime_src, msg, "runtime control flow here", .{});
const child_src_decl = mod.declPtr(child_block.src_decl);
- try sema.explainWhyTypeIsComptime(child_block, type_src, msg, type_src.toSrcLoc(child_src_decl), resolved_ty);
+ try sema.explainWhyTypeIsComptime(msg, type_src.toSrcLoc(child_src_decl, mod), resolved_ty);
break :msg msg;
};
@@ -5628,15 +5807,16 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
- const decl_name = sema.code.nullTerminatedString(extra.decl_name);
+ const decl_name = try mod.intern_pool.getOrPutString(mod.gpa, sema.code.nullTerminatedString(extra.decl_name));
const decl_index = if (extra.namespace != .none) index_blk: {
const container_ty = try sema.resolveType(block, operand_src, extra.namespace);
- const container_namespace = container_ty.getNamespace().?;
+ const container_namespace = container_ty.getNamespaceIndex(mod).unwrap().?;
const maybe_index = try sema.lookupInNamespace(block, operand_src, container_namespace, decl_name, false);
break :index_blk maybe_index orelse
@@ -5650,10 +5830,10 @@ fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
else => |e| return e,
};
{
- try sema.mod.ensureDeclAnalyzed(decl_index);
- const exported_decl = sema.mod.declPtr(decl_index);
- if (exported_decl.val.castTag(.function)) |some| {
- return sema.analyzeExport(block, src, options, some.data.owner_decl);
+ try mod.ensureDeclAnalyzed(decl_index);
+ const exported_decl = mod.declPtr(decl_index);
+ if (exported_decl.val.getFunction(mod)) |function| {
+ return sema.analyzeExport(block, src, options, function.owner_decl);
}
}
try sema.analyzeExport(block, src, options, decl_index);
@@ -5676,17 +5856,14 @@ fn zirExportValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
},
else => |e| return e,
};
- const decl_index = switch (operand.val.tag()) {
- .function => operand.val.castTag(.function).?.data.owner_decl,
- else => blk: {
- var anon_decl = try block.startAnonDecl();
- defer anon_decl.deinit();
- break :blk try anon_decl.finish(
- try operand.ty.copy(anon_decl.arena()),
- try operand.val.copy(anon_decl.arena()),
- 0,
- );
- },
+ const decl_index = if (operand.val.getFunction(sema.mod)) |function| function.owner_decl else blk: {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ break :blk try anon_decl.finish(
+ operand.ty,
+ operand.val,
+ 0,
+ );
};
try sema.analyzeExport(block, src, options, decl_index);
}
@@ -5695,13 +5872,13 @@ pub fn analyzeExport(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- borrowed_options: std.builtin.ExportOptions,
+ options: Module.Export.Options,
exported_decl_index: Decl.Index,
) !void {
const Export = Module.Export;
const mod = sema.mod;
- if (borrowed_options.linkage == .Internal) {
+ if (options.linkage == .Internal) {
return;
}
@@ -5710,11 +5887,11 @@ pub fn analyzeExport(
if (!try sema.validateExternType(exported_decl.ty, .other)) {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, src, "unable to export type '{}'", .{exported_decl.ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), exported_decl.ty, .other);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), exported_decl.ty, .other);
try sema.addDeclaredHereNote(msg, exported_decl.ty);
break :msg msg;
@@ -5723,14 +5900,15 @@ pub fn analyzeExport(
}
// TODO: some backends might support re-exporting extern decls
- if (exported_decl.isExtern()) {
+ if (exported_decl.isExtern(mod)) {
return sema.fail(block, src, "export target cannot be extern", .{});
}
// This decl is alive no matter what, since it's being exported
- mod.markDeclAlive(exported_decl);
+ try mod.markDeclAlive(exported_decl);
+ try sema.maybeQueueFuncBodyAnalysis(exported_decl_index);
- const gpa = mod.gpa;
+ const gpa = sema.gpa;
try mod.decl_exports.ensureUnusedCapacity(gpa, 1);
try mod.export_owners.ensureUnusedCapacity(gpa, 1);
@@ -5738,19 +5916,8 @@ pub fn analyzeExport(
const new_export = try gpa.create(Export);
errdefer gpa.destroy(new_export);
- const symbol_name = try gpa.dupe(u8, borrowed_options.name);
- errdefer gpa.free(symbol_name);
-
- const section: ?[]const u8 = if (borrowed_options.section) |s| try gpa.dupe(u8, s) else null;
- errdefer if (section) |s| gpa.free(s);
-
new_export.* = .{
- .options = .{
- .name = symbol_name,
- .linkage = borrowed_options.linkage,
- .section = section,
- .visibility = borrowed_options.visibility,
- },
+ .opts = options,
.src = src,
.owner_decl = sema.owner_decl_index,
.src_decl = block.src_decl,
@@ -5776,6 +5943,7 @@ pub fn analyzeExport(
}
fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const src = LazySrcLoc.nodeOffset(extra.node);
@@ -5785,11 +5953,12 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
alignment,
});
}
- const func = sema.func orelse
+ const func_index = sema.func_index.unwrap() orelse
return sema.fail(block, src, "@setAlignStack outside function body", .{});
+ const func = mod.funcPtr(func_index);
- const fn_owner_decl = sema.mod.declPtr(func.owner_decl);
- switch (fn_owner_decl.ty.fnCallingConvention()) {
+ const fn_owner_decl = mod.declPtr(func.owner_decl);
+ switch (fn_owner_decl.ty.fnCallingConvention(mod)) {
.Naked => return sema.fail(block, src, "@setAlignStack in naked function", .{}),
.Inline => return sema.fail(block, src, "@setAlignStack in inline function", .{}),
else => if (block.inlining != null) {
@@ -5797,7 +5966,7 @@ fn zirSetAlignStack(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
},
}
- const gop = try sema.mod.align_stack_fns.getOrPut(sema.mod.gpa, func);
+ const gop = try mod.align_stack_fns.getOrPut(sema.gpa, func_index);
if (gop.found_existing) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "multiple @setAlignStack in the same function body", .{});
@@ -5949,10 +6118,11 @@ fn addDbgVar(
air_tag: Air.Inst.Tag,
name: []const u8,
) CompileError!void {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
switch (air_tag) {
.dbg_var_ptr => {
- if (!(try sema.typeHasRuntimeBits(operand_ty.childType()))) return;
+ if (!(try sema.typeHasRuntimeBits(operand_ty.childType(mod)))) return;
},
.dbg_var_val => {
if (!(try sema.typeHasRuntimeBits(operand_ty))) return;
@@ -5981,29 +6151,32 @@ fn addDbgVar(
}
fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
const src = inst_data.src();
- const decl_name = inst_data.get(sema.code);
+ const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
const decl_index = try sema.lookupIdentifier(block, src, decl_name);
try sema.addReferencedBy(block, src, decl_index);
return sema.analyzeDeclRef(decl_index);
}
fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
const src = inst_data.src();
- const decl_name = inst_data.get(sema.code);
+ const decl_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
const decl = try sema.lookupIdentifier(block, src, decl_name);
return sema.analyzeDeclVal(block, src, decl);
}
-fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: []const u8) !Decl.Index {
+fn lookupIdentifier(sema: *Sema, block: *Block, src: LazySrcLoc, name: InternPool.NullTerminatedString) !Decl.Index {
+ const mod = sema.mod;
var namespace = block.namespace;
while (true) {
if (try sema.lookupInNamespace(block, src, namespace, name, false)) |decl_index| {
return decl_index;
}
- namespace = namespace.parent orelse break;
+ namespace = mod.namespacePtr(namespace).parent.unwrap() orelse break;
}
unreachable; // AstGen detects use of undeclared identifier errors.
}
@@ -6014,21 +6187,22 @@ fn lookupInNamespace(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- namespace: *Namespace,
- ident_name: []const u8,
+ namespace_index: Namespace.Index,
+ ident_name: InternPool.NullTerminatedString,
observe_usingnamespace: bool,
) CompileError!?Decl.Index {
const mod = sema.mod;
- const namespace_decl_index = namespace.getDeclIndex();
- const namespace_decl = sema.mod.declPtr(namespace_decl_index);
+ const namespace = mod.namespacePtr(namespace_index);
+ const namespace_decl_index = namespace.getDeclIndex(mod);
+ const namespace_decl = mod.declPtr(namespace_decl_index);
if (namespace_decl.analysis == .file_failure) {
try mod.declareDeclDependency(sema.owner_decl_index, namespace_decl_index);
return error.AnalysisFail;
}
if (observe_usingnamespace and namespace.usingnamespace_set.count() != 0) {
- const src_file = block.namespace.file_scope;
+ const src_file = mod.namespacePtr(block.namespace).file_scope;
const gpa = sema.gpa;
var checked_namespaces: std.AutoArrayHashMapUnmanaged(*Namespace, bool) = .{};
@@ -6047,7 +6221,7 @@ fn lookupInNamespace(
// Skip decls which are not marked pub, which are in a different
// file than the `a.b`/`@hasDecl` syntax.
const decl = mod.declPtr(decl_index);
- if (decl.is_pub or (src_file == decl.getFileScope() and checked_namespaces.values()[check_i])) {
+ if (decl.is_pub or (src_file == decl.getFileScope(mod) and checked_namespaces.values()[check_i])) {
try candidates.append(gpa, decl_index);
}
}
@@ -6058,15 +6232,15 @@ fn lookupInNamespace(
if (sub_usingnamespace_decl_index == sema.owner_decl_index) continue;
const sub_usingnamespace_decl = mod.declPtr(sub_usingnamespace_decl_index);
const sub_is_pub = entry.value_ptr.*;
- if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope()) {
+ if (!sub_is_pub and src_file != sub_usingnamespace_decl.getFileScope(mod)) {
// Skip usingnamespace decls which are not marked pub, which are in
// a different file than the `a.b`/`@hasDecl` syntax.
continue;
}
try sema.ensureDeclAnalyzed(sub_usingnamespace_decl_index);
- const ns_ty = sub_usingnamespace_decl.val.castTag(.ty).?.data;
- const sub_ns = ns_ty.getNamespace().?;
- try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope());
+ const ns_ty = sub_usingnamespace_decl.val.toType();
+ const sub_ns = ns_ty.getNamespace(mod).?;
+ try checked_namespaces.put(gpa, sub_ns, src_file == sub_usingnamespace_decl.getFileScope(mod));
}
}
@@ -6094,7 +6268,7 @@ fn lookupInNamespace(
errdefer msg.destroy(gpa);
for (candidates.items) |candidate_index| {
const candidate = mod.declPtr(candidate_index);
- const src_loc = candidate.srcLoc();
+ const src_loc = candidate.srcLoc(mod);
try mod.errNoteNonLazy(src_loc, msg, "declared here", .{});
}
break :msg msg;
@@ -6107,9 +6281,6 @@ fn lookupInNamespace(
return decl_index;
}
- log.debug("{*} ({s}) depends on non-existence of '{s}' in {*} ({s})", .{
- sema.owner_decl, sema.owner_decl.name, ident_name, namespace_decl, namespace_decl.name,
- });
// TODO This dependency is too strong. Really, it should only be a dependency
// on the non-existence of `ident_name` in the namespace. We can lessen the number of
// outdated declarations by making this dependency more sophisticated.
@@ -6118,22 +6289,28 @@ fn lookupInNamespace(
}
fn funcDeclSrc(sema: *Sema, func_inst: Air.Inst.Ref) !?*Decl {
+ const mod = sema.mod;
const func_val = (try sema.resolveMaybeUndefVal(func_inst)) orelse return null;
- if (func_val.isUndef()) return null;
- const owner_decl_index = switch (func_val.tag()) {
- .extern_fn => func_val.castTag(.extern_fn).?.data.owner_decl,
- .function => func_val.castTag(.function).?.data.owner_decl,
- .decl_ref => sema.mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data.owner_decl,
+ if (func_val.isUndef(mod)) return null;
+ const owner_decl_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
+ .extern_func => |extern_func| extern_func.decl,
+ .func => |func| mod.funcPtr(func.index).owner_decl,
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl => |decl| mod.declPtr(decl).val.getFunction(mod).?.owner_decl,
+ else => return null,
+ },
else => return null,
};
- return sema.mod.declPtr(owner_decl_index);
+ return mod.declPtr(owner_decl_index);
}
pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const src = sema.src;
- if (!sema.mod.backendSupportsFeature(.error_return_trace)) return .none;
- if (!sema.mod.comp.bin_file.options.error_return_tracing) return .none;
+ if (!mod.backendSupportsFeature(.error_return_trace)) return .none;
+ if (!mod.comp.bin_file.options.error_return_tracing) return .none;
if (block.is_comptime)
return .none;
@@ -6146,7 +6323,8 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
else => |e| return e,
};
- const field_index = sema.structFieldIndex(block, stack_trace_ty, "index", src) catch |err| switch (err) {
+ const field_name = try mod.intern_pool.getOrPutString(gpa, "index");
+ const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, src) catch |err| switch (err) {
error.NeededSourceLocation, error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
else => |e| return e,
};
@@ -6169,6 +6347,8 @@ fn popErrorReturnTrace(
operand: Air.Inst.Ref,
saved_error_trace_index: Air.Inst.Ref,
) CompileError!void {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
var is_non_error: ?bool = null;
var is_non_error_inst: Air.Inst.Ref = undefined;
if (operand != .none) {
@@ -6183,15 +6363,16 @@ fn popErrorReturnTrace(
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
- const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
+ const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
- const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, "index", src, stack_trace_ty, true);
+ const field_name = try mod.intern_pool.getOrPutString(gpa, "index");
+ const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty, true);
try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store);
} else if (is_non_error == null) {
// The result might be an error. If it is, we leave the error trace alone. If it isn't, we need
// to pop any error trace that may have been propagated from our arguments.
- try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).Struct.fields.len);
+ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).Struct.fields.len);
const cond_block_inst = try block.addInstAsIndex(.{
.tag = .block,
.data = .{
@@ -6203,28 +6384,29 @@ fn popErrorReturnTrace(
});
var then_block = block.makeSubBlock();
- defer then_block.instructions.deinit(sema.gpa);
+ defer then_block.instructions.deinit(gpa);
// If non-error, then pop the error return trace by restoring the index.
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
- const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
+ const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
- const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, "index", src, stack_trace_ty, true);
+ const field_name = try mod.intern_pool.getOrPutString(gpa, "index");
+ const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty, true);
try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store);
_ = try then_block.addBr(cond_block_inst, Air.Inst.Ref.void_value);
// Otherwise, do nothing
var else_block = block.makeSubBlock();
- defer else_block.instructions.deinit(sema.gpa);
+ defer else_block.instructions.deinit(gpa);
_ = try else_block.addBr(cond_block_inst, Air.Inst.Ref.void_value);
- try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.CondBr).Struct.fields.len +
+ try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
then_block.instructions.items.len + else_block.instructions.items.len +
@typeInfo(Air.Block).Struct.fields.len + 1); // +1 for the sole .cond_br instruction in the .block
const cond_br_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
- try sema.air_instructions.append(sema.gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{
+ try sema.air_instructions.append(gpa, .{ .tag = .cond_br, .data = .{ .pl_op = .{
.operand = is_non_error_inst,
.payload = sema.addExtraAssumeCapacity(Air.CondBr{
.then_body_len = @intCast(u32, then_block.instructions.items.len),
@@ -6243,94 +6425,63 @@ fn zirCall(
sema: *Sema,
block: *Block,
inst: Zir.Inst.Index,
+ comptime kind: enum { direct, field },
) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const func_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
+ const callee_src: LazySrcLoc = .{ .node_offset_call_func = inst_data.src_node };
const call_src = inst_data.src();
- const extra = sema.code.extraData(Zir.Inst.Call, inst_data.payload_index);
+ const ExtraType = switch (kind) {
+ .direct => Zir.Inst.Call,
+ .field => Zir.Inst.FieldCall,
+ };
+ const extra = sema.code.extraData(ExtraType, inst_data.payload_index);
const args_len = extra.data.flags.args_len;
const modifier = @intToEnum(std.builtin.CallModifier, extra.data.flags.packed_modifier);
const ensure_result_used = extra.data.flags.ensure_result_used;
const pop_error_return_trace = extra.data.flags.pop_error_return_trace;
- var func = try sema.resolveInst(extra.data.callee);
+ const callee: ResolvedFieldCallee = switch (kind) {
+ .direct => .{ .direct = try sema.resolveInst(extra.data.callee) },
+ .field => blk: {
+ const object_ptr = try sema.resolveInst(extra.data.obj_ptr);
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.data.field_name_start));
+ const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
+ break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src);
+ },
+ };
var resolved_args: []Air.Inst.Ref = undefined;
- var arg_index: u32 = 0;
-
- const func_type = sema.typeOf(func);
-
- // Desugar bound functions here
var bound_arg_src: ?LazySrcLoc = null;
- if (func_type.tag() == .bound_fn) {
- bound_arg_src = func_src;
- const bound_func = try sema.resolveValue(block, .unneeded, func, "");
- const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
- func = bound_data.func_inst;
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
- resolved_args[arg_index] = bound_data.arg0_inst;
- arg_index += 1;
- } else {
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
+ var func: Air.Inst.Ref = undefined;
+ var arg_index: u32 = 0;
+ switch (callee) {
+ .direct => |func_inst| {
+ resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len);
+ func = func_inst;
+ },
+ .method => |method| {
+ resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_len + 1);
+ func = method.func_inst;
+ resolved_args[0] = method.arg0_inst;
+ arg_index += 1;
+ bound_arg_src = callee_src;
+ },
}
- const total_args = args_len + @boolToInt(bound_arg_src != null);
const callee_ty = sema.typeOf(func);
- const func_ty = func_ty: {
- switch (callee_ty.zigTypeTag()) {
- .Fn => break :func_ty callee_ty,
- .Pointer => {
- const ptr_info = callee_ty.ptrInfo().data;
- if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
- break :func_ty ptr_info.pointee_type;
- }
- },
- else => {},
- }
- return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(sema.mod)});
- };
- const func_ty_info = func_ty.fnInfo();
-
- const fn_params_len = func_ty_info.param_types.len;
- check_args: {
- if (func_ty_info.is_var_args) {
- assert(func_ty_info.cc == .C);
- if (total_args >= fn_params_len) break :check_args;
- } else if (fn_params_len == total_args) {
- break :check_args;
- }
-
- const maybe_decl = try sema.funcDeclSrc(func);
- const member_str = if (bound_arg_src != null) "member function " else "";
- const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
- const msg = msg: {
- const msg = try sema.errMsg(
- block,
- func_src,
- "{s}expected {s}{d} argument(s), found {d}",
- .{
- member_str,
- variadic_str,
- fn_params_len - @boolToInt(bound_arg_src != null),
- args_len,
- },
- );
- errdefer msg.destroy(sema.gpa);
-
- if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{});
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(msg);
- }
+ const total_args = args_len + @boolToInt(bound_arg_src != null);
+ const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, bound_arg_src != null);
const args_body = sema.code.extra[extra.end..];
var input_is_error = false;
const block_index = @intCast(Air.Inst.Index, block.instructions.items.len);
+ const fn_params_len = mod.typeToFunc(func_ty).?.param_types.len;
const parent_comptime = block.is_comptime;
// `extra_index` and `arg_index` are separate since the bound function is passed as the first argument.
var extra_index: usize = 0;
@@ -6339,55 +6490,62 @@ fn zirCall(
extra_index += 1;
arg_index += 1;
}) {
+ const func_ty_info = mod.typeToFunc(func_ty).?;
const arg_end = sema.code.extra[extra.end + extra_index];
defer arg_start = arg_end;
- const param_ty = if (arg_index >= fn_params_len or
- func_ty_info.param_types[arg_index].tag() == .generic_poison)
- Type.initTag(.var_args_param)
- else
- func_ty_info.param_types[arg_index];
-
// Generate args to comptime params in comptime block.
defer block.is_comptime = parent_comptime;
- if (arg_index < fn_params_len and func_ty_info.comptime_params[arg_index]) {
+ if (arg_index < @min(fn_params_len, 32) and func_ty_info.paramIsComptime(@intCast(u5, arg_index))) {
block.is_comptime = true;
// TODO set comptime_reason
}
- const param_ty_inst = try sema.addType(param_ty);
- sema.inst_map.putAssumeCapacity(inst, param_ty_inst);
+ sema.inst_map.putAssumeCapacity(inst, inst: {
+ if (arg_index >= fn_params_len)
+ break :inst Air.Inst.Ref.var_args_param_type;
+
+ if (func_ty_info.param_types[arg_index] == .generic_poison_type)
+ break :inst Air.Inst.Ref.generic_poison_type;
+
+ break :inst try sema.addType(func_ty_info.param_types[arg_index].toType());
+ });
const resolved = try sema.resolveBody(block, args_body[arg_start..arg_end], inst);
const resolved_ty = sema.typeOf(resolved);
- if (resolved_ty.zigTypeTag() == .NoReturn) {
+ if (resolved_ty.zigTypeTag(mod) == .NoReturn) {
return resolved;
}
- if (resolved_ty.isError()) {
+ if (resolved_ty.isError(mod)) {
input_is_error = true;
}
resolved_args[arg_index] = resolved;
}
- if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn)
+ if (sema.owner_func == null or !sema.owner_func.?.calls_or_awaits_errorable_fn) {
input_is_error = false; // input was an error type, but no errorable fn's were actually called
+ }
+
+ // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction.
+ const call_dbg_node = inst - 1;
- if (sema.mod.backendSupportsFeature(.error_return_trace) and sema.mod.comp.bin_file.options.error_return_tracing and
+ if (mod.backendSupportsFeature(.error_return_trace) and mod.comp.bin_file.options.error_return_tracing and
!block.is_comptime and !block.is_typeof and (input_is_error or pop_error_return_trace))
{
const call_inst: Air.Inst.Ref = if (modifier == .always_tail) undefined else b: {
- break :b try sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
+ break :b try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
};
const return_ty = sema.typeOf(call_inst);
- if (modifier != .always_tail and return_ty.isNoReturn())
+ if (modifier != .always_tail and return_ty.isNoReturn(mod))
return call_inst; // call to "fn(...) noreturn", don't pop
// If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only
// need to clean-up our own trace if we were passed to a non-error-handling expression.
- if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError())) {
+ if (input_is_error or (pop_error_return_trace and modifier != .always_tail and return_ty.isError(mod))) {
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
- const field_index = try sema.structFieldIndex(block, stack_trace_ty, "index", call_src);
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, "index");
+ const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
// Insert a save instruction before the arg resolution + call instructions we just generated
const save_inst = try block.insertInst(block_index, .{
@@ -6404,113 +6562,136 @@ fn zirCall(
}
if (modifier == .always_tail) // Perform the call *after* the restore, so that a tail call is possible.
- return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
+ return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
return call_inst;
} else {
- return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
+ return sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src, call_dbg_node);
}
}
-const GenericCallAdapter = struct {
- generic_fn: *Module.Fn,
- precomputed_hash: u64,
- func_ty_info: Type.Payload.Function.Data,
- args: []const Arg,
- module: *Module,
+fn checkCallArgumentCount(
+ sema: *Sema,
+ block: *Block,
+ func: Air.Inst.Ref,
+ func_src: LazySrcLoc,
+ callee_ty: Type,
+ total_args: usize,
+ member_fn: bool,
+) !Type {
+ const mod = sema.mod;
+ const func_ty = func_ty: {
+ switch (callee_ty.zigTypeTag(mod)) {
+ .Fn => break :func_ty callee_ty,
+ .Pointer => {
+ const ptr_info = callee_ty.ptrInfo(mod);
+ if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) {
+ break :func_ty ptr_info.pointee_type;
+ }
+ },
+ .Optional => {
+ const opt_child = callee_ty.optionalChild(mod);
+ if (opt_child.zigTypeTag(mod) == .Fn or (opt_child.isSinglePointer(mod) and
+ opt_child.childType(mod).zigTypeTag(mod) == .Fn))
+ {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, func_src, "cannot call optional type '{}'", .{
+ callee_ty.fmt(mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, func_src, msg, "consider using '.?', 'orelse' or 'if'", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ },
+ else => {},
+ }
+ return sema.fail(block, func_src, "type '{}' not a function", .{callee_ty.fmt(mod)});
+ };
+
+ const func_ty_info = mod.typeToFunc(func_ty).?;
+ const fn_params_len = func_ty_info.param_types.len;
+ const args_len = total_args - @boolToInt(member_fn);
+ if (func_ty_info.is_var_args) {
+ assert(func_ty_info.cc == .C);
+ if (total_args >= fn_params_len) return func_ty;
+ } else if (fn_params_len == total_args) {
+ return func_ty;
+ }
- const Arg = struct {
- ty: Type,
- val: Value,
- is_anytype: bool,
+ const maybe_decl = try sema.funcDeclSrc(func);
+ const member_str = if (member_fn) "member function " else "";
+ const variadic_str = if (func_ty_info.is_var_args) "at least " else "";
+ const msg = msg: {
+ const msg = try sema.errMsg(
+ block,
+ func_src,
+ "{s}expected {s}{d} argument(s), found {d}",
+ .{
+ member_str,
+ variadic_str,
+ fn_params_len - @boolToInt(member_fn),
+ args_len,
+ },
+ );
+ errdefer msg.destroy(sema.gpa);
+
+ if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{});
+ break :msg msg;
};
+ return sema.failWithOwnedErrorMsg(msg);
+}
- pub fn eql(ctx: @This(), adapted_key: void, other_key: *Module.Fn) bool {
- _ = adapted_key;
- // Checking for equality may happen on an item that has been inserted
- // into the map but is not yet fully initialized. In such case, the
- // two initialized fields are `hash` and `generic_owner_decl`.
- if (ctx.generic_fn.owner_decl != other_key.generic_owner_decl.unwrap().?) return false;
-
- const other_comptime_args = other_key.comptime_args.?;
- for (other_comptime_args[0..ctx.func_ty_info.param_types.len], 0..) |other_arg, i| {
- const this_arg = ctx.args[i];
- const this_is_comptime = this_arg.val.tag() != .generic_poison;
- const other_is_comptime = other_arg.val.tag() != .generic_poison;
- const this_is_anytype = this_arg.is_anytype;
- const other_is_anytype = other_key.isAnytypeParam(ctx.module, @intCast(u32, i));
-
- if (other_is_anytype != this_is_anytype) return false;
- if (other_is_comptime != this_is_comptime) return false;
-
- if (this_is_anytype) {
- // Both are anytype parameters.
- if (!this_arg.ty.eql(other_arg.ty, ctx.module)) {
- return false;
- }
- if (this_is_comptime) {
- // Both are comptime and anytype parameters with matching types.
- if (!this_arg.val.eql(other_arg.val, other_arg.ty, ctx.module)) {
- return false;
- }
- }
- } else if (this_is_comptime) {
- // Both are comptime parameters but not anytype parameters.
- // We assert no error is possible here because any lazy values must be resolved
- // before inserting into the generic function hash map.
- const is_eql = Value.eqlAdvanced(
- this_arg.val,
- this_arg.ty,
- other_arg.val,
- other_arg.ty,
- ctx.module,
- null,
- ) catch unreachable;
- if (!is_eql) {
- return false;
+fn callBuiltin(
+ sema: *Sema,
+ block: *Block,
+ builtin_fn: Air.Inst.Ref,
+ modifier: std.builtin.CallModifier,
+ args: []const Air.Inst.Ref,
+) !void {
+ const mod = sema.mod;
+ const callee_ty = sema.typeOf(builtin_fn);
+ const func_ty = func_ty: {
+ switch (callee_ty.zigTypeTag(mod)) {
+ .Fn => break :func_ty callee_ty,
+ .Pointer => {
+ const ptr_info = callee_ty.ptrInfo(mod);
+ if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Fn) {
+ break :func_ty ptr_info.pointee_type;
}
- }
+ },
+ else => {},
}
- return true;
- }
+ std.debug.panic("type '{}' is not a function calling builtin fn", .{callee_ty.fmt(mod)});
+ };
- /// The implementation of the hash is in semantic analysis of function calls, so
- /// that any errors when computing the hash can be properly reported.
- pub fn hash(ctx: @This(), adapted_key: void) u64 {
- _ = adapted_key;
- return ctx.precomputed_hash;
+ const func_ty_info = mod.typeToFunc(func_ty).?;
+ const fn_params_len = func_ty_info.param_types.len;
+ if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) {
+ std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len });
}
-};
+ _ = try sema.analyzeCall(block, builtin_fn, func_ty, sema.src, sema.src, modifier, false, args, null, null);
+}
fn analyzeCall(
sema: *Sema,
block: *Block,
func: Air.Inst.Ref,
+ func_ty: Type,
func_src: LazySrcLoc,
call_src: LazySrcLoc,
modifier: std.builtin.CallModifier,
ensure_result_used: bool,
uncasted_args: []const Air.Inst.Ref,
bound_arg_src: ?LazySrcLoc,
+ call_dbg_node: ?Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const callee_ty = sema.typeOf(func);
- const func_ty = func_ty: {
- switch (callee_ty.zigTypeTag()) {
- .Fn => break :func_ty callee_ty,
- .Pointer => {
- const ptr_info = callee_ty.ptrInfo().data;
- if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Fn) {
- break :func_ty ptr_info.pointee_type;
- }
- },
- else => {},
- }
- return sema.fail(block, func_src, "type '{}' is not a function", .{callee_ty.fmt(sema.mod)});
- };
-
- const func_ty_info = func_ty.fnInfo();
+ const func_ty_info = mod.typeToFunc(func_ty).?;
+ const fn_params_len = func_ty_info.param_types.len;
const cc = func_ty_info.cc;
if (cc == .Naked) {
const maybe_decl = try sema.funcDeclSrc(func);
@@ -6523,32 +6704,11 @@ fn analyzeCall(
);
errdefer msg.destroy(sema.gpa);
- if (maybe_decl) |fn_decl| try sema.mod.errNoteNonLazy(fn_decl.srcLoc(), msg, "function declared here", .{});
+ if (maybe_decl) |fn_decl| try mod.errNoteNonLazy(fn_decl.srcLoc(mod), msg, "function declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- const fn_params_len = func_ty_info.param_types.len;
- if (func_ty_info.is_var_args) {
- assert(cc == .C);
- if (uncasted_args.len < fn_params_len) {
- // TODO add error note: declared here
- return sema.fail(
- block,
- func_src,
- "expected at least {d} argument(s), found {d}",
- .{ fn_params_len, uncasted_args.len },
- );
- }
- } else if (fn_params_len != uncasted_args.len) {
- // TODO add error note: declared here
- return sema.fail(
- block,
- call_src,
- "expected {d} argument(s), found {d}",
- .{ fn_params_len, uncasted_args.len },
- );
- }
const call_tag: Air.Inst.Tag = switch (modifier) {
.auto,
@@ -6565,7 +6725,10 @@ fn analyzeCall(
};
if (modifier == .never_inline and func_ty_info.cc == .Inline) {
- return sema.fail(block, call_src, "no-inline call of inline function", .{});
+ return sema.fail(block, call_src, "'never_inline' call of inline function", .{});
+ }
+ if (modifier == .always_inline and func_ty_info.is_noinline) {
+ return sema.fail(block, call_src, "'always_inline' call of noinline function", .{});
}
const gpa = sema.gpa;
@@ -6575,7 +6738,7 @@ fn analyzeCall(
var comptime_reason_buf: Block.ComptimeReason = undefined;
var comptime_reason: ?*const Block.ComptimeReason = null;
if (!is_comptime_call) {
- if (sema.typeRequiresComptime(func_ty_info.return_type)) |ct| {
+ if (sema.typeRequiresComptime(func_ty_info.return_type.toType())) |ct| {
is_comptime_call = ct;
if (ct) {
// stage1 can't handle doing this directly
@@ -6583,7 +6746,7 @@ fn analyzeCall(
.block = block,
.func = func,
.func_src = func_src,
- .return_ty = func_ty_info.return_type,
+ .return_ty = func_ty_info.return_type.toType(),
} };
comptime_reason = &comptime_reason_buf;
}
@@ -6601,11 +6764,12 @@ fn analyzeCall(
func,
func_src,
call_src,
- func_ty_info,
+ func_ty,
ensure_result_used,
uncasted_args,
call_tag,
bound_arg_src,
+ call_dbg_node,
)) |some| {
return some;
} else |err| switch (err) {
@@ -6620,7 +6784,7 @@ fn analyzeCall(
.block = block,
.func = func,
.func_src = func_src,
- .return_ty = func_ty_info.return_type,
+ .return_ty = func_ty_info.return_type.toType(),
} };
comptime_reason = &comptime_reason_buf;
},
@@ -6637,18 +6801,21 @@ fn analyzeCall(
if (err == error.AnalysisFail and comptime_reason != null) try comptime_reason.?.explain(sema, sema.err);
return err;
};
- const module_fn = switch (func_val.tag()) {
- .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
- .function => func_val.castTag(.function).?.data,
- .extern_fn => return sema.fail(block, call_src, "{s} call of extern function", .{
+ const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
+ .extern_func => return sema.fail(block, call_src, "{s} call of extern function", .{
@as([]const u8, if (is_comptime_call) "comptime" else "inline"),
}),
- else => {
- assert(callee_ty.isPtrAtRuntime());
- return sema.fail(block, call_src, "{s} call of function pointer", .{
- @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
- });
+ .func => |function| function.index,
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl => |decl| mod.declPtr(decl).val.getFunctionIndex(mod).unwrap().?,
+ else => {
+ assert(callee_ty.isPtrAtRuntime(mod));
+ return sema.fail(block, call_src, "{s} call of function pointer", .{
+ @as([]const u8, if (is_comptime_call) "comptime" else "inline"),
+ });
+ },
},
+ else => unreachable,
};
if (func_ty_info.is_var_args) {
return sema.fail(block, call_src, "{s} call of variadic function", .{
@@ -6681,8 +6848,9 @@ fn analyzeCall(
// In order to save a bit of stack space, directly modify Sema rather
// than create a child one.
const parent_zir = sema.code;
+ const module_fn = mod.funcPtr(module_fn_index);
const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
- sema.code = fn_owner_decl.getFileScope().zir;
+ sema.code = fn_owner_decl.getFileScope(mod).zir;
defer sema.code = parent_zir;
try mod.declareDeclDependencyType(sema.owner_decl_index, module_fn.owner_decl, .function_body);
@@ -6696,14 +6864,17 @@ fn analyzeCall(
}
const parent_func = sema.func;
+ const parent_func_index = sema.func_index;
sema.func = module_fn;
+ sema.func_index = module_fn_index.toOptional();
defer sema.func = parent_func;
+ defer sema.func_index = parent_func_index;
const parent_err_ret_index = sema.error_return_trace_index_on_fn_entry;
sema.error_return_trace_index_on_fn_entry = block.error_return_trace_index;
defer sema.error_return_trace_index_on_fn_entry = parent_err_ret_index;
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, fn_owner_decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, fn_owner_decl.src_scope);
defer wip_captures.deinit();
var child_block: Block = .{
@@ -6726,28 +6897,18 @@ fn analyzeCall(
defer child_block.instructions.deinit(gpa);
defer merges.deinit(gpa);
- // If it's a comptime function call, we need to memoize it as long as no external
- // comptime memory is mutated.
- var memoized_call_key: Module.MemoizedCall.Key = undefined;
- var delete_memoized_call_key = false;
- defer if (delete_memoized_call_key) gpa.free(memoized_call_key.args);
- if (is_comptime_call) {
- memoized_call_key = .{
- .func = module_fn,
- .args = try gpa.alloc(TypedValue, func_ty_info.param_types.len),
- };
- delete_memoized_call_key = true;
- }
-
try sema.emitBackwardBranch(block, call_src);
- // Whether this call should be memoized, set to false if the call can mutate
- // comptime state.
+ // Whether this call should be memoized, set to false if the call can mutate comptime state.
var should_memoize = true;
- var new_fn_info = fn_owner_decl.ty.fnInfo();
- new_fn_info.param_types = try sema.arena.alloc(Type, new_fn_info.param_types.len);
- new_fn_info.comptime_params = (try sema.arena.alloc(bool, new_fn_info.param_types.len)).ptr;
+ // If it's a comptime function call, we need to memoize it as long as no external
+ // comptime memory is mutated.
+ const memoized_arg_values = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
+
+ var new_fn_info = mod.typeToFunc(fn_owner_decl.ty).?;
+ new_fn_info.param_types = try sema.arena.alloc(InternPool.Index, new_fn_info.param_types.len);
+ new_fn_info.comptime_bits = 0;
// This will have return instructions analyzed as break instructions to
// the block_inst above. Here we are performing "comptime/inline semantic analysis"
@@ -6766,31 +6927,31 @@ fn analyzeCall(
&child_block,
.unneeded,
inst,
- new_fn_info,
+ &new_fn_info,
&arg_i,
uncasted_args,
is_comptime_call,
&should_memoize,
- memoized_call_key,
- func_ty_info.param_types,
+ memoized_arg_values,
+ mod.typeToFunc(func_ty).?.param_types,
func,
&has_comptime_args,
) catch |err| switch (err) {
error.NeededSourceLocation => {
_ = sema.inst_map.remove(inst);
- const decl = sema.mod.declPtr(block.src_decl);
+ const decl = mod.declPtr(block.src_decl);
try sema.analyzeInlineCallArg(
block,
&child_block,
- Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src),
+ mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src),
inst,
- new_fn_info,
+ &new_fn_info,
&arg_i,
uncasted_args,
is_comptime_call,
&should_memoize,
- memoized_call_key,
- func_ty_info.param_types,
+ memoized_arg_values,
+ mod.typeToFunc(func_ty).?.param_types,
func,
&has_comptime_args,
);
@@ -6826,21 +6987,15 @@ fn analyzeCall(
// Create a fresh inferred error set type for inline/comptime calls.
const fn_ret_ty = blk: {
if (module_fn.hasInferredErrorSet(mod)) {
- const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
- node.data = .{ .func = module_fn };
- if (parent_func) |some| {
- some.inferred_error_sets.prepend(node);
- }
-
- const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
- break :blk try Type.Tag.error_union.create(sema.arena, .{
- .error_set = error_set_ty,
- .payload = bare_return_type,
+ const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{
+ .func = module_fn_index,
});
+ const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index });
+ break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type);
}
break :blk bare_return_type;
};
- new_fn_info.return_type = fn_ret_ty;
+ new_fn_info.return_type = fn_ret_ty.toIntern();
const parent_fn_ret_ty = sema.fn_ret_ty;
sema.fn_ret_ty = fn_ret_ty;
defer sema.fn_ret_ty = parent_fn_ret_ty;
@@ -6849,23 +7004,22 @@ fn analyzeCall(
// bug generating invalid LLVM IR.
const res2: Air.Inst.Ref = res2: {
if (should_memoize and is_comptime_call) {
- if (mod.memoized_calls.getContext(memoized_call_key, .{ .module = mod })) |result| {
- const ty_inst = try sema.addType(fn_ret_ty);
- try sema.air_values.append(gpa, result.val);
- sema.air_instructions.set(block_inst, .{
- .tag = .constant,
- .data = .{ .ty_pl = .{
- .ty = ty_inst,
- .payload = @intCast(u32, sema.air_values.items.len - 1),
- } },
- });
- break :res2 Air.indexToRef(block_inst);
+ if (mod.intern_pool.getIfExists(.{ .memoized_call = .{
+ .func = module_fn_index,
+ .arg_values = memoized_arg_values,
+ .result = .none,
+ } })) |memoized_call_index| {
+ const memoized_call = mod.intern_pool.indexToKey(memoized_call_index).memoized_call;
+ break :res2 try sema.addConstant(
+ mod.intern_pool.typeOf(memoized_call.result).toType(),
+ memoized_call.result.toValue(),
+ );
}
}
- const new_func_resolved_ty = try Type.Tag.function.create(sema.arena, new_fn_info);
+ const new_func_resolved_ty = try mod.funcType(new_fn_info);
if (!is_comptime_call and !block.is_typeof) {
- try sema.emitDbgInline(block, parent_func.?, module_fn, new_func_resolved_ty, .dbg_inline_begin);
+ try sema.emitDbgInline(block, parent_func_index.unwrap().?, module_fn_index, new_func_resolved_ty, .dbg_inline_begin);
const zir_tags = sema.code.instructions.items(.tag);
for (fn_info.param_body) |param| switch (zir_tags[param]) {
@@ -6897,7 +7051,7 @@ fn analyzeCall(
error.ComptimeReturn => break :result inlining.comptime_result,
error.AnalysisFail => {
const err_msg = sema.err orelse return err;
- if (std.mem.eql(u8, err_msg.msg, recursive_msg)) return err;
+ if (mem.eql(u8, err_msg.msg, recursive_msg)) return err;
try sema.errNote(block, call_src, err_msg, "called from here", .{});
err_msg.clearTrace(sema.gpa);
return err;
@@ -6907,11 +7061,11 @@ fn analyzeCall(
break :result try sema.analyzeBlockBody(block, call_src, &child_block, merges);
};
- if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag() != .NoReturn) {
+ if (!is_comptime_call and !block.is_typeof and sema.typeOf(result).zigTypeTag(mod) != .NoReturn) {
try sema.emitDbgInline(
block,
- module_fn,
- parent_func.?,
+ module_fn_index,
+ parent_func_index.unwrap().?,
mod.declPtr(parent_func.?.owner_decl).ty,
.dbg_inline_end,
);
@@ -6922,23 +7076,11 @@ fn analyzeCall(
// TODO: check whether any external comptime memory was mutated by the
// comptime function call. If so, then do not memoize the call here.
- // TODO: re-evaluate whether memoized_calls needs its own arena. I think
- // it should be fine to use the Decl arena for the function.
- {
- var arena_allocator = std.heap.ArenaAllocator.init(gpa);
- errdefer arena_allocator.deinit();
- const arena = arena_allocator.allocator();
-
- for (memoized_call_key.args) |*arg| {
- arg.* = try arg.*.copy(arena);
- }
-
- try mod.memoized_calls.putContext(gpa, memoized_call_key, .{
- .val = try result_val.copy(arena),
- .arena = arena_allocator.state,
- }, .{ .module = mod });
- delete_memoized_call_key = false;
- }
+ _ = try mod.intern(.{ .memoized_call = .{
+ .func = module_fn_index,
+ .arg_values = memoized_arg_values,
+ .result = try result_val.intern(fn_ret_ty, mod),
+ } });
}
break :res2 result;
@@ -6957,7 +7099,7 @@ fn analyzeCall(
.func_inst = func,
.param_i = @intCast(u32, i),
} };
- const param_ty = func_ty.fnParamType(i);
+ const param_ty = mod.typeToFunc(func_ty).?.param_types[i].toType();
args[i] = sema.analyzeCallArg(
block,
.unneeded,
@@ -6966,10 +7108,10 @@ fn analyzeCall(
opts,
) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
+ const decl = mod.declPtr(block.src_decl);
_ = try sema.analyzeCallArg(
block,
- Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
+ mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
param_ty,
uncasted_arg,
opts,
@@ -6981,11 +7123,11 @@ fn analyzeCall(
} else {
args[i] = sema.coerceVarArgParam(block, uncasted_arg, .unneeded) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
+ const decl = mod.declPtr(block.src_decl);
_ = try sema.coerceVarArgParam(
block,
uncasted_arg,
- Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src),
+ mod.argSrc(call_src.node_offset.x, decl, i, bound_arg_src),
);
unreachable;
},
@@ -6994,11 +7136,19 @@ fn analyzeCall(
}
}
- try sema.queueFullTypeResolution(func_ty_info.return_type);
- if (sema.owner_func != null and func_ty_info.return_type.isError()) {
+ if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
+
+ try sema.queueFullTypeResolution(func_ty_info.return_type.toType());
+ if (sema.owner_func != null and func_ty_info.return_type.toType().isError(mod)) {
sema.owner_func.?.calls_or_awaits_errorable_fn = true;
}
+ if (try sema.resolveMaybeUndefVal(func)) |func_val| {
+ if (mod.intern_pool.indexToFunc(func_val.toIntern()).unwrap()) |func_index| {
+ try mod.ensureFuncBodyAnalysisQueued(func_index);
+ }
+ }
+
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).Struct.fields.len +
args.len);
const func_inst = try block.addInst(.{
@@ -7011,30 +7161,55 @@ fn analyzeCall(
} },
});
sema.appendRefsAssumeCapacity(args);
+
+ if (call_tag == .call_always_tail) {
+ if (ensure_result_used) {
+ try sema.ensureResultUsed(block, sema.typeOf(func_inst), call_src);
+ }
+ return sema.handleTailCall(block, call_src, func_ty, func_inst);
+ }
+ if (block.wantSafety() and func_ty_info.return_type == .noreturn_type) skip_safety: {
+ // Function pointers and extern functions aren't guaranteed to
+ // actually be noreturn so we add a safety check for them.
+ if (try sema.resolveMaybeUndefVal(func)) |func_val| {
+ switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
+ .func => break :skip_safety,
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl => |decl| if (!mod.declPtr(decl).isExtern(mod)) break :skip_safety,
+ else => {},
+ },
+ else => {},
+ }
+ }
+ try sema.safetyPanic(block, .noreturn_returned);
+ return Air.Inst.Ref.unreachable_value;
+ }
+ if (func_ty_info.return_type == .noreturn_type) {
+ _ = try block.addNoOp(.unreach);
+ return Air.Inst.Ref.unreachable_value;
+ }
break :res func_inst;
};
if (ensure_result_used) {
try sema.ensureResultUsed(block, sema.typeOf(result), call_src);
}
- if (call_tag == .call_always_tail) {
- return sema.handleTailCall(block, call_src, func_ty, result);
- }
return result;
}
fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref {
- const target = sema.mod.getTarget();
- const backend = sema.mod.comp.getZigBackend();
+ const mod = sema.mod;
+ const target = mod.getTarget();
+ const backend = mod.comp.getZigBackend();
if (!target_util.supportsTailCall(target, backend)) {
return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{
@tagName(backend), @tagName(target.cpu.arch),
});
}
- const func_decl = sema.mod.declPtr(sema.owner_func.?.owner_decl);
- if (!func_ty.eql(func_decl.ty, sema.mod)) {
+ const func_decl = mod.declPtr(sema.owner_func.?.owner_decl);
+ if (!func_ty.eql(func_decl.ty, mod)) {
return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{}' does not match type of calling function '{}'", .{
- func_ty.fmt(sema.mod), func_decl.ty.fmt(sema.mod),
+ func_ty.fmt(mod), func_decl.ty.fmt(mod),
});
}
_ = try block.addUnOp(.ret, result);
@@ -7047,16 +7222,17 @@ fn analyzeInlineCallArg(
param_block: *Block,
arg_src: LazySrcLoc,
inst: Zir.Inst.Index,
- new_fn_info: Type.Payload.Function.Data,
+ new_fn_info: *InternPool.Key.FuncType,
arg_i: *usize,
uncasted_args: []const Air.Inst.Ref,
is_comptime_call: bool,
should_memoize: *bool,
- memoized_call_key: Module.MemoizedCall.Key,
- raw_param_types: []const Type,
+ memoized_arg_values: []InternPool.Index,
+ raw_param_types: []const InternPool.Index,
func_inst: Air.Inst.Ref,
has_comptime_args: *bool,
) !void {
+ const mod = sema.mod;
const zir_tags = sema.code.instructions.items(.tag);
switch (zir_tags[inst]) {
.param_comptime, .param_anytype_comptime => has_comptime_args.* = true,
@@ -7072,13 +7248,14 @@ fn analyzeInlineCallArg(
const param_body = sema.code.extra[extra.end..][0..extra.data.body_len];
const param_ty = param_ty: {
const raw_param_ty = raw_param_types[arg_i.*];
- if (raw_param_ty.tag() != .generic_poison) break :param_ty raw_param_ty;
+ if (raw_param_ty != .generic_poison_type) break :param_ty raw_param_ty;
const param_ty_inst = try sema.resolveBody(param_block, param_body, inst);
- break :param_ty try sema.analyzeAsType(param_block, param_src, param_ty_inst);
+ const param_ty = try sema.analyzeAsType(param_block, param_src, param_ty_inst);
+ break :param_ty param_ty.toIntern();
};
new_fn_info.param_types[arg_i.*] = param_ty;
const uncasted_arg = uncasted_args[arg_i.*];
- if (try sema.typeRequiresComptime(param_ty)) {
+ if (try sema.typeRequiresComptime(param_ty.toType())) {
_ = sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "argument to parameter with comptime-only type must be comptime-known") catch |err| {
if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
return err;
@@ -7086,7 +7263,7 @@ fn analyzeInlineCallArg(
} else if (!is_comptime_call and zir_tags[inst] == .param_comptime) {
_ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
}
- const casted_arg = sema.coerceExtra(arg_block, param_ty, uncasted_arg, arg_src, .{ .param_src = .{
+ const casted_arg = sema.coerceExtra(arg_block, param_ty.toType(), uncasted_arg, arg_src, .{ .param_src = .{
.func_inst = func_inst,
.param_i = @intCast(u32, arg_i.*),
} }) catch |err| switch (err) {
@@ -7100,24 +7277,20 @@ fn analyzeInlineCallArg(
if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
return err;
};
- switch (arg_val.tag()) {
+ switch (arg_val.toIntern()) {
.generic_poison, .generic_poison_type => {
// This function is currently evaluated as part of an as-of-yet unresolvable
// parameter or return type.
return error.GenericPoison;
},
- else => {
- // Needed so that lazy values do not trigger
- // assertion due to type not being resolved
- // when the hash function is called.
- try sema.resolveLazyValue(arg_val);
- },
+ else => {},
}
- should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState();
- memoized_call_key.args[arg_i.*] = .{
- .ty = param_ty,
- .val = arg_val,
- };
+ // Needed so that lazy values do not trigger
+ // assertion due to type not being resolved
+ // when the hash function is called.
+ const resolved_arg_val = try sema.resolveLazyValue(arg_val);
+ should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
+ memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(param_ty.toType(), mod);
} else {
sema.inst_map.putAssumeCapacityNoClobber(inst, casted_arg);
}
@@ -7131,7 +7304,7 @@ fn analyzeInlineCallArg(
.param_anytype, .param_anytype_comptime => {
// No coercion needed.
const uncasted_arg = uncasted_args[arg_i.*];
- new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg);
+ new_fn_info.param_types[arg_i.*] = sema.typeOf(uncasted_arg).toIntern();
if (is_comptime_call) {
sema.inst_map.putAssumeCapacityNoClobber(inst, uncasted_arg);
@@ -7139,24 +7312,20 @@ fn analyzeInlineCallArg(
if (err == error.AnalysisFail and param_block.comptime_reason != null) try param_block.comptime_reason.?.explain(sema, sema.err);
return err;
};
- switch (arg_val.tag()) {
+ switch (arg_val.toIntern()) {
.generic_poison, .generic_poison_type => {
// This function is currently evaluated as part of an as-of-yet unresolvable
// parameter or return type.
return error.GenericPoison;
},
- else => {
- // Needed so that lazy values do not trigger
- // assertion due to type not being resolved
- // when the hash function is called.
- try sema.resolveLazyValue(arg_val);
- },
+ else => {},
}
- should_memoize.* = should_memoize.* and !arg_val.canMutateComptimeVarState();
- memoized_call_key.args[arg_i.*] = .{
- .ty = sema.typeOf(uncasted_arg),
- .val = arg_val,
- };
+ // Needed so that lazy values do not trigger
+ // assertion due to type not being resolved
+ // when the hash function is called.
+ const resolved_arg_val = try sema.resolveLazyValue(arg_val);
+ should_memoize.* = should_memoize.* and !resolved_arg_val.canMutateComptimeVarState(mod);
+ memoized_arg_values[arg_i.*] = try resolved_arg_val.intern(sema.typeOf(uncasted_arg), mod);
} else {
if (zir_tags[inst] == .param_anytype_comptime) {
_ = try sema.resolveConstMaybeUndefVal(arg_block, arg_src, uncasted_arg, "parameter is comptime");
@@ -7196,14 +7365,15 @@ fn analyzeGenericCallArg(
uncasted_arg: Air.Inst.Ref,
comptime_arg: TypedValue,
runtime_args: []Air.Inst.Ref,
- new_fn_info: Type.Payload.Function.Data,
+ new_fn_info: InternPool.Key.FuncType,
runtime_i: *u32,
) !void {
- const is_runtime = comptime_arg.val.tag() == .generic_poison and
- comptime_arg.ty.hasRuntimeBits() and
+ const mod = sema.mod;
+ const is_runtime = comptime_arg.val.isGenericPoison() and
+ comptime_arg.ty.hasRuntimeBits(mod) and
!(try sema.typeRequiresComptime(comptime_arg.ty));
if (is_runtime) {
- const param_ty = new_fn_info.param_types[runtime_i.*];
+ const param_ty = new_fn_info.param_types[runtime_i.*].toType();
const casted_arg = try sema.coerce(block, param_ty, uncasted_arg, arg_src);
try sema.queueFullTypeResolution(param_ty);
runtime_args[runtime_i.*] = casted_arg;
@@ -7213,10 +7383,16 @@ fn analyzeGenericCallArg(
}
}
-fn analyzeGenericCallArgVal(sema: *Sema, block: *Block, arg_src: LazySrcLoc, uncasted_arg: Air.Inst.Ref) !Value {
- const arg_val = try sema.resolveValue(block, arg_src, uncasted_arg, "parameter is comptime");
- try sema.resolveLazyValue(arg_val);
- return arg_val;
+fn analyzeGenericCallArgVal(
+ sema: *Sema,
+ block: *Block,
+ arg_src: LazySrcLoc,
+ arg_ty: Type,
+ uncasted_arg: Air.Inst.Ref,
+ reason: []const u8,
+) !Value {
+ const casted_arg = try sema.coerce(block, arg_ty, uncasted_arg, arg_src);
+ return sema.resolveLazyValue(try sema.resolveValue(block, arg_src, casted_arg, reason));
}
fn instantiateGenericCall(
@@ -7225,56 +7401,52 @@ fn instantiateGenericCall(
func: Air.Inst.Ref,
func_src: LazySrcLoc,
call_src: LazySrcLoc,
- func_ty_info: Type.Payload.Function.Data,
+ generic_func_ty: Type,
ensure_result_used: bool,
uncasted_args: []const Air.Inst.Ref,
call_tag: Air.Inst.Tag,
bound_arg_src: ?LazySrcLoc,
+ call_dbg_node: ?Zir.Inst.Index,
) CompileError!Air.Inst.Ref {
const mod = sema.mod;
const gpa = sema.gpa;
const func_val = try sema.resolveConstValue(block, func_src, func, "generic function being called must be comptime-known");
- const module_fn = switch (func_val.tag()) {
- .function => func_val.castTag(.function).?.data,
- .decl_ref => mod.declPtr(func_val.castTag(.decl_ref).?.data).val.castTag(.function).?.data,
+ const module_fn_index = switch (mod.intern_pool.indexToKey(func_val.toIntern())) {
+ .func => |function| function.index,
+ .ptr => |ptr| mod.declPtr(ptr.addr.decl).val.getFunctionIndex(mod).unwrap().?,
else => unreachable,
};
+ const module_fn = mod.funcPtr(module_fn_index);
// Check the Module's generic function map with an adapted context, so that we
// can match against `uncasted_args` rather than doing the work below to create a
// generic Scope only to junk it if it matches an existing instantiation.
const fn_owner_decl = mod.declPtr(module_fn.owner_decl);
- const namespace = fn_owner_decl.src_namespace;
+ const namespace_index = fn_owner_decl.src_namespace;
+ const namespace = mod.namespacePtr(namespace_index);
const fn_zir = namespace.file_scope.zir;
const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
const zir_tags = fn_zir.instructions.items(.tag);
- // This hash must match `Module.MonomorphedFuncsContext.hash`.
- // For parameters explicitly marked comptime and simple parameter type expressions,
- // we know whether a parameter is elided from a monomorphed function, and can
- // use it in the hash here. However, for parameter type expressions that are not
- // explicitly marked comptime and rely on previous parameter comptime values, we
- // don't find out until after generating a monomorphed function whether the parameter
- // type ended up being a "must-be-comptime-known" type.
- var hasher = std.hash.Wyhash.init(0);
- std.hash.autoHash(&hasher, module_fn.owner_decl);
-
- const generic_args = try sema.arena.alloc(GenericCallAdapter.Arg, func_ty_info.param_types.len);
- {
- var i: usize = 0;
+ const monomorphed_args = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(generic_func_ty).?.param_types.len);
+ const callee_index = callee: {
+ var arg_i: usize = 0;
+ var monomorphed_arg_i: u32 = 0;
+ var known_unique = false;
for (fn_info.param_body) |inst| {
+ const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?;
var is_comptime = false;
var is_anytype = false;
switch (zir_tags[inst]) {
.param => {
- is_comptime = func_ty_info.paramIsComptime(i);
+ is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
},
.param_comptime => {
is_comptime = true;
},
.param_anytype => {
is_anytype = true;
- is_comptime = func_ty_info.paramIsComptime(i);
+ is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
},
.param_anytype_comptime => {
is_anytype = true;
@@ -7283,87 +7455,90 @@ fn instantiateGenericCall(
else => continue,
}
- const arg_ty = sema.typeOf(uncasted_args[i]);
+ defer arg_i += 1;
+ const param_ty = generic_func_ty_info.param_types[arg_i];
+ const is_generic = !is_anytype and param_ty == .generic_poison_type;
+
+ if (known_unique) {
+ if (is_comptime or is_anytype or is_generic) {
+ monomorphed_arg_i += 1;
+ }
+ continue;
+ }
+
+ const uncasted_arg = uncasted_args[arg_i];
+ const arg_ty = if (is_generic) mod.monomorphed_funcs.getAdapted(
+ Module.MonomorphedFuncAdaptedKey{
+ .func = module_fn_index,
+ .args = monomorphed_args[0..monomorphed_arg_i],
+ },
+ Module.MonomorphedFuncsAdaptedContext{ .mod = mod },
+ ) orelse {
+ known_unique = true;
+ monomorphed_arg_i += 1;
+ continue;
+ } else if (is_anytype) sema.typeOf(uncasted_arg).toIntern() else param_ty;
+ const was_comptime = is_comptime;
+ if (!is_comptime and try sema.typeRequiresComptime(arg_ty.toType())) is_comptime = true;
if (is_comptime or is_anytype) {
// Tuple default values are a part of the type and need to be
// resolved to hash the type.
- try sema.resolveTupleLazyValues(block, call_src, arg_ty);
+ try sema.resolveTupleLazyValues(block, call_src, arg_ty.toType());
}
if (is_comptime) {
- const arg_val = sema.analyzeGenericCallArgVal(block, .unneeded, uncasted_args[i]) catch |err| switch (err) {
+ const casted_arg = sema.analyzeGenericCallArgVal(block, .unneeded, arg_ty.toType(), uncasted_arg, "") catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
- const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, i, bound_arg_src);
- _ = try sema.analyzeGenericCallArgVal(block, arg_src, uncasted_args[i]);
+ const decl = mod.declPtr(block.src_decl);
+ const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);
+ _ = try sema.analyzeGenericCallArgVal(
+ block,
+ arg_src,
+ arg_ty.toType(),
+ uncasted_arg,
+ if (was_comptime)
+ "parameter is comptime"
+ else
+ "argument to parameter with comptime-only type must be comptime-known",
+ );
unreachable;
},
else => |e| return e,
};
- arg_val.hashUncoerced(arg_ty, &hasher, mod);
- if (is_anytype) {
- arg_ty.hashWithHasher(&hasher, mod);
- generic_args[i] = .{
- .ty = arg_ty,
- .val = arg_val,
- .is_anytype = true,
- };
- } else {
- generic_args[i] = .{
- .ty = arg_ty,
- .val = arg_val,
- .is_anytype = false,
- };
- }
- } else if (is_anytype) {
- arg_ty.hashWithHasher(&hasher, mod);
- generic_args[i] = .{
- .ty = arg_ty,
- .val = Value.initTag(.generic_poison),
- .is_anytype = true,
- };
- } else {
- generic_args[i] = .{
- .ty = arg_ty,
- .val = Value.initTag(.generic_poison),
- .is_anytype = false,
- };
+ monomorphed_args[monomorphed_arg_i] = casted_arg.toIntern();
+ monomorphed_arg_i += 1;
+ } else if (is_anytype or is_generic) {
+ monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty });
+ monomorphed_arg_i += 1;
}
-
- i += 1;
}
- }
- const precomputed_hash = hasher.final();
+ if (!known_unique) {
+ if (mod.monomorphed_funcs.getAdapted(
+ Module.MonomorphedFuncAdaptedKey{
+ .func = module_fn_index,
+ .args = monomorphed_args[0..monomorphed_arg_i],
+ },
+ Module.MonomorphedFuncsAdaptedContext{ .mod = mod },
+ )) |callee_func| break :callee mod.intern_pool.indexToKey(callee_func).func.index;
+ }
- const adapter: GenericCallAdapter = .{
- .generic_fn = module_fn,
- .precomputed_hash = precomputed_hash,
- .func_ty_info = func_ty_info,
- .args = generic_args,
- .module = mod,
- };
- const gop = try mod.monomorphed_funcs.getOrPutAdapted(gpa, {}, adapter);
- const callee = if (!gop.found_existing) callee: {
- const new_module_func = try gpa.create(Module.Fn);
+ const new_module_func_index = try mod.createFunc(undefined);
+ const new_module_func = mod.funcPtr(new_module_func_index);
- // This ensures that we can operate on the hash map before the Module.Fn
- // struct is fully initialized.
- new_module_func.hash = precomputed_hash;
new_module_func.generic_owner_decl = module_fn.owner_decl.toOptional();
new_module_func.comptime_args = null;
- gop.key_ptr.* = new_module_func;
try namespace.anon_decls.ensureUnusedCapacity(gpa, 1);
// Create a Decl for the new function.
- const src_decl_index = namespace.getDeclIndex();
+ const src_decl_index = namespace.getDeclIndex(mod);
const src_decl = mod.declPtr(src_decl_index);
- const new_decl_index = try mod.allocateNewDecl(namespace, fn_owner_decl.src_node, src_decl.src_scope);
+ const new_decl_index = try mod.allocateNewDecl(namespace_index, fn_owner_decl.src_node, src_decl.src_scope);
const new_decl = mod.declPtr(new_decl_index);
// TODO better names for generic function instantiations
- const decl_name = try std.fmt.allocPrintZ(gpa, "{s}__anon_{d}", .{
- fn_owner_decl.name, @enumToInt(new_decl_index),
+ const decl_name = try mod.intern_pool.getOrPutStringFmt(gpa, "{}__anon_{d}", .{
+ fn_owner_decl.name.fmt(&mod.intern_pool), @enumToInt(new_decl_index),
});
new_decl.name = decl_name;
new_decl.src_line = fn_owner_decl.src_line;
@@ -7385,25 +7560,21 @@ fn instantiateGenericCall(
assert(new_decl.dependencies.keys().len == 0);
try mod.declareDeclDependencyType(new_decl_index, module_fn.owner_decl, .function_body);
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- const new_decl_arena_allocator = new_decl_arena.allocator();
-
const new_func = sema.resolveGenericInstantiationType(
block,
- new_decl_arena_allocator,
fn_zir,
new_decl,
new_decl_index,
uncasted_args,
- module_fn,
- new_module_func,
- namespace,
- func_ty_info,
+ monomorphed_arg_i,
+ module_fn_index,
+ new_module_func_index,
+ namespace_index,
+ generic_func_ty,
call_src,
bound_arg_src,
) catch |err| switch (err) {
error.GenericPoison, error.ComptimeReturn => {
- new_decl_arena.deinit();
// Resolving the new function type below will possibly declare more decl dependencies
// and so we remove them all here in case of error.
for (new_decl.dependencies.keys()) |dep_index| {
@@ -7412,16 +7583,10 @@ fn instantiateGenericCall(
}
assert(namespace.anon_decls.orderedRemove(new_decl_index));
mod.destroyDecl(new_decl_index);
- assert(mod.monomorphed_funcs.remove(new_module_func));
- gpa.destroy(new_module_func);
+ mod.destroyFunc(new_module_func_index);
return err;
},
else => {
- assert(mod.monomorphed_funcs.remove(new_module_func));
- {
- errdefer new_decl_arena.deinit();
- try new_decl.finalizeNewArena(&new_decl_arena);
- }
// TODO look up the compile error that happened here and attach a note to it
// pointing here, at the generic instantiation callsite.
if (sema.owner_func) |owner_func| {
@@ -7432,12 +7597,10 @@ fn instantiateGenericCall(
return err;
},
};
- errdefer new_decl_arena.deinit();
- try new_decl.finalizeNewArena(&new_decl_arena);
break :callee new_func;
- } else gop.key_ptr.*;
-
+ };
+ const callee = mod.funcPtr(callee_index);
callee.branch_quota = @max(callee.branch_quota, sema.branch_quota);
const callee_inst = try sema.analyzeDeclVal(block, func_src, callee.owner_decl);
@@ -7445,8 +7608,7 @@ fn instantiateGenericCall(
// Make a runtime call to the new function, making sure to omit the comptime args.
const comptime_args = callee.comptime_args.?;
const func_ty = mod.declPtr(callee.owner_decl).ty;
- const new_fn_info = func_ty.fnInfo();
- const runtime_args_len = @intCast(u32, new_fn_info.param_types.len);
+ const runtime_args_len = @intCast(u32, mod.typeToFunc(func_ty).?.param_types.len);
const runtime_args = try sema.arena.alloc(Air.Inst.Ref, runtime_args_len);
{
var runtime_i: u32 = 0;
@@ -7462,18 +7624,18 @@ fn instantiateGenericCall(
uncasted_args[total_i],
comptime_args[total_i],
runtime_args,
- new_fn_info,
+ mod.typeToFunc(func_ty).?,
&runtime_i,
) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
+ const decl = mod.declPtr(block.src_decl);
_ = try sema.analyzeGenericCallArg(
block,
- Module.argSrc(call_src.node_offset.x, sema.gpa, decl, total_i, bound_arg_src),
+ mod.argSrc(call_src.node_offset.x, decl, total_i, bound_arg_src),
uncasted_args[total_i],
comptime_args[total_i],
runtime_args,
- new_fn_info,
+ mod.typeToFunc(func_ty).?,
&runtime_i,
);
unreachable;
@@ -7483,13 +7645,17 @@ fn instantiateGenericCall(
total_i += 1;
}
- try sema.queueFullTypeResolution(new_fn_info.return_type);
+ try sema.queueFullTypeResolution(mod.typeToFunc(func_ty).?.return_type.toType());
}
- if (sema.owner_func != null and new_fn_info.return_type.isError()) {
+ if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
+
+ if (sema.owner_func != null and mod.typeToFunc(func_ty).?.return_type.toType().isError(mod)) {
sema.owner_func.?.calls_or_awaits_errorable_fn = true;
}
+ try mod.ensureFuncBodyAnalysisQueued(callee_index);
+
try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Call).Struct.fields.len +
runtime_args_len);
const result = try block.addInst(.{
@@ -7509,28 +7675,33 @@ fn instantiateGenericCall(
if (call_tag == .call_always_tail) {
return sema.handleTailCall(block, call_src, func_ty, result);
}
+ if (func_ty.fnReturnType(mod).isNoReturn(mod)) {
+ _ = try block.addNoOp(.unreach);
+ return Air.Inst.Ref.unreachable_value;
+ }
return result;
}
fn resolveGenericInstantiationType(
sema: *Sema,
block: *Block,
- new_decl_arena_allocator: Allocator,
fn_zir: Zir,
new_decl: *Decl,
new_decl_index: Decl.Index,
uncasted_args: []const Air.Inst.Ref,
- module_fn: *Module.Fn,
- new_module_func: *Module.Fn,
- namespace: *Namespace,
- func_ty_info: Type.Payload.Function.Data,
+ monomorphed_args_len: u32,
+ module_fn_index: Module.Fn.Index,
+ new_module_func: Module.Fn.Index,
+ namespace: Namespace.Index,
+ generic_func_ty: Type,
call_src: LazySrcLoc,
bound_arg_src: ?LazySrcLoc,
-) !*Module.Fn {
+) !Module.Fn.Index {
const mod = sema.mod;
const gpa = sema.gpa;
const zir_tags = fn_zir.instructions.items(.tag);
+ const module_fn = mod.funcPtr(module_fn_index);
const fn_info = fn_zir.getFnInfo(module_fn.zir_body_inst);
// Re-run the block that creates the function, with the comptime parameters
@@ -7541,23 +7712,26 @@ fn resolveGenericInstantiationType(
.mod = mod,
.gpa = gpa,
.arena = sema.arena,
- .perm_arena = new_decl_arena_allocator,
.code = fn_zir,
.owner_decl = new_decl,
.owner_decl_index = new_decl_index,
.func = null,
+ .func_index = .none,
.fn_ret_ty = Type.void,
.owner_func = null,
- .comptime_args = try new_decl_arena_allocator.alloc(TypedValue, uncasted_args.len),
+ .owner_func_index = .none,
+ // TODO: fully migrate functions into InternPool
+ .comptime_args = try mod.tmp_hack_arena.allocator().alloc(TypedValue, uncasted_args.len),
.comptime_args_fn_inst = module_fn.zir_body_inst,
- .preallocated_new_func = new_module_func,
+ .preallocated_new_func = new_module_func.toOptional(),
.is_generic_instantiation = true,
.branch_quota = sema.branch_quota,
.branch_count = sema.branch_count,
+ .comptime_mutable_decls = sema.comptime_mutable_decls,
};
defer child_sema.deinit();
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, new_decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, new_decl.src_scope);
defer wip_captures.deinit();
var child_block: Block = .{
@@ -7579,18 +7753,19 @@ fn resolveGenericInstantiationType(
var arg_i: usize = 0;
for (fn_info.param_body) |inst| {
+ const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?;
var is_comptime = false;
var is_anytype = false;
switch (zir_tags[inst]) {
.param => {
- is_comptime = func_ty_info.paramIsComptime(arg_i);
+ is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
},
.param_comptime => {
is_comptime = true;
},
.param_anytype => {
is_anytype = true;
- is_comptime = func_ty_info.paramIsComptime(arg_i);
+ is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
},
.param_anytype_comptime => {
is_anytype = true;
@@ -7608,8 +7783,8 @@ fn resolveGenericInstantiationType(
if (try sema.typeRequiresComptime(arg_ty)) {
const arg_val = sema.resolveConstValue(block, .unneeded, arg, "") catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
- const arg_src = Module.argSrc(call_src.node_offset.x, sema.gpa, decl, arg_i, bound_arg_src);
+ const decl = mod.declPtr(block.src_decl);
+ const arg_src = mod.argSrc(call_src.node_offset.x, decl, arg_i, bound_arg_src);
_ = try sema.resolveConstValue(block, arg_src, arg, "argument to parameter with comptime-only type must be comptime-known");
unreachable;
},
@@ -7641,50 +7816,61 @@ fn resolveGenericInstantiationType(
const new_func_inst = try child_sema.resolveBody(&child_block, fn_info.param_body, fn_info.param_body_inst);
const new_func_val = child_sema.resolveConstValue(&child_block, .unneeded, new_func_inst, undefined) catch unreachable;
- const new_func = new_func_val.castTag(.function).?.data;
- errdefer new_func.deinit(gpa);
+ const new_func = new_func_val.getFunctionIndex(mod).unwrap().?;
assert(new_func == new_module_func);
+ const monomorphed_args_index = @intCast(u32, mod.monomorphed_func_keys.items.len);
+ const monomorphed_args = try mod.monomorphed_func_keys.addManyAsSlice(gpa, monomorphed_args_len);
+ var monomorphed_arg_i: u32 = 0;
+ try mod.monomorphed_funcs.ensureUnusedCapacityContext(gpa, monomorphed_args_len + 1, .{ .mod = mod });
+
arg_i = 0;
for (fn_info.param_body) |inst| {
+ const generic_func_ty_info = mod.typeToFunc(generic_func_ty).?;
var is_comptime = false;
+ var is_anytype = false;
switch (zir_tags[inst]) {
.param => {
- is_comptime = func_ty_info.paramIsComptime(arg_i);
+ is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
},
.param_comptime => {
is_comptime = true;
},
.param_anytype => {
- is_comptime = func_ty_info.paramIsComptime(arg_i);
+ is_anytype = true;
+ is_comptime = generic_func_ty_info.paramIsComptime(@intCast(u5, arg_i));
},
.param_anytype_comptime => {
+ is_anytype = true;
is_comptime = true;
},
else => continue,
}
- // We populate the Type here regardless because it is needed by
- // `GenericCallAdapter.eql` as well as function body analysis.
- // Whether it is anytype is communicated by `isAnytypeParam`.
+ const param_ty = generic_func_ty_info.param_types[arg_i];
+ const is_generic = !is_anytype and param_ty == .generic_poison_type;
+
const arg = child_sema.inst_map.get(inst).?;
- const copied_arg_ty = try child_sema.typeOf(arg).copy(new_decl_arena_allocator);
+ const arg_ty = child_sema.typeOf(arg);
- if (try sema.typeRequiresComptime(copied_arg_ty)) {
- is_comptime = true;
- }
+ if (is_generic) if (mod.monomorphed_funcs.fetchPutAssumeCapacityContext(.{
+ .func = module_fn_index,
+ .args_index = monomorphed_args_index,
+ .args_len = monomorphed_arg_i,
+ }, arg_ty.toIntern(), .{ .mod = mod })) |kv| assert(kv.value == arg_ty.toIntern());
+ if (!is_comptime and try sema.typeRequiresComptime(arg_ty)) is_comptime = true;
if (is_comptime) {
const arg_val = (child_sema.resolveMaybeUndefValAllowVariables(arg) catch unreachable).?;
- child_sema.comptime_args[arg_i] = .{
- .ty = copied_arg_ty,
- .val = try arg_val.copy(new_decl_arena_allocator),
- };
+ monomorphed_args[monomorphed_arg_i] = arg_val.toIntern();
+ monomorphed_arg_i += 1;
+ child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = arg_val };
} else {
- child_sema.comptime_args[arg_i] = .{
- .ty = copied_arg_ty,
- .val = Value.initTag(.generic_poison),
- };
+ if (is_anytype or is_generic) {
+ monomorphed_args[monomorphed_arg_i] = try mod.intern(.{ .undef = arg_ty.toIntern() });
+ monomorphed_arg_i += 1;
+ }
+ child_sema.comptime_args[arg_i] = .{ .ty = arg_ty, .val = Value.generic_poison };
}
arg_i += 1;
@@ -7693,11 +7879,11 @@ fn resolveGenericInstantiationType(
try wip_captures.finalize();
// Populate the Decl ty/val with the function and its type.
- new_decl.ty = try child_sema.typeOf(new_func_inst).copy(new_decl_arena_allocator);
+ new_decl.ty = child_sema.typeOf(new_func_inst);
// If the call evaluated to a return type that requires comptime, never mind
// our generic instantiation. Instead we need to perform a comptime call.
- const new_fn_info = new_decl.ty.fnInfo();
- if (try sema.typeRequiresComptime(new_fn_info.return_type)) {
+ const new_fn_info = mod.typeToFunc(new_decl.ty).?;
+ if (try sema.typeRequiresComptime(new_fn_info.return_type.toType())) {
return error.ComptimeReturn;
}
// Similarly, if the call evaluated to a generic type we need to instead
@@ -7706,15 +7892,20 @@ fn resolveGenericInstantiationType(
return error.GenericPoison;
}
- new_decl.val = try Value.Tag.function.create(new_decl_arena_allocator, new_func);
+ new_decl.val = (try mod.intern(.{ .func = .{
+ .ty = new_decl.ty.toIntern(),
+ .index = new_func,
+ } })).toValue();
new_decl.@"align" = 0;
new_decl.has_tv = true;
new_decl.owns_tv = true;
new_decl.analysis = .complete;
- log.debug("generic function '{s}' instantiated with type {}", .{
- new_decl.name, new_decl.ty.fmtDebug(),
- });
+ mod.monomorphed_funcs.putAssumeCapacityNoClobberContext(.{
+ .func = module_fn_index,
+ .args_index = monomorphed_args_index,
+ .args_len = monomorphed_arg_i,
+ }, new_decl.val.toIntern(), .{ .mod = mod });
// Queue up a `codegen_func` work item for the new Fn. The `comptime_args` field
// will be populated, ensuring it will have `analyzeBody` called with the ZIR
@@ -7724,46 +7915,46 @@ fn resolveGenericInstantiationType(
}
fn resolveTupleLazyValues(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
- if (!ty.isSimpleTupleOrAnonStruct()) return;
- const tuple = ty.tupleFields();
- for (tuple.values, 0..) |field_val, i| {
- try sema.resolveTupleLazyValues(block, src, tuple.types[i]);
- if (field_val.tag() == .unreachable_value) continue;
- try sema.resolveLazyValue(field_val);
+ const mod = sema.mod;
+ const tuple = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .anon_struct_type => |tuple| tuple,
+ else => return,
+ };
+ for (tuple.types, tuple.values) |field_ty, field_val| {
+ try sema.resolveTupleLazyValues(block, src, field_ty.toType());
+ if (field_val == .none) continue;
+ // TODO: mutate in intern pool
+ _ = try sema.resolveLazyValue(field_val.toValue());
}
}
fn emitDbgInline(
sema: *Sema,
block: *Block,
- old_func: *Module.Fn,
- new_func: *Module.Fn,
+ old_func: Module.Fn.Index,
+ new_func: Module.Fn.Index,
new_func_ty: Type,
tag: Air.Inst.Tag,
) CompileError!void {
- if (sema.mod.comp.bin_file.options.strip) return;
+ const mod = sema.mod;
+ if (mod.comp.bin_file.options.strip) return;
// Recursive inline call; no dbg_inline needed.
if (old_func == new_func) return;
- try sema.air_values.append(sema.gpa, try Value.Tag.function.create(sema.arena, new_func));
_ = try block.addInst(.{
.tag = tag,
- .data = .{ .ty_pl = .{
+ .data = .{ .ty_fn = .{
.ty = try sema.addType(new_func_ty),
- .payload = @intCast(u32, sema.air_values.items.len - 1),
+ .func = new_func,
} },
});
}
-fn zirIntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- _ = block;
- const tracy = trace(@src());
- defer tracy.end();
-
+fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const int_type = sema.code.instructions.items(.data)[inst].int_type;
- const ty = try Module.makeIntType(sema.arena, int_type.signedness, int_type.bit_count);
-
+ const ty = try mod.intType(int_type.signedness, int_type.bit_count);
return sema.addType(ty);
}
@@ -7771,43 +7962,46 @@ fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
const child_type = try sema.resolveType(block, operand_src, inst_data.operand);
- if (child_type.zigTypeTag() == .Opaque) {
- return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
- } else if (child_type.zigTypeTag() == .Null) {
- return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(sema.mod)});
+ if (child_type.zigTypeTag(mod) == .Opaque) {
+ return sema.fail(block, operand_src, "opaque type '{}' cannot be optional", .{child_type.fmt(mod)});
+ } else if (child_type.zigTypeTag(mod) == .Null) {
+ return sema.fail(block, operand_src, "type '{}' cannot be optional", .{child_type.fmt(mod)});
}
- const opt_type = try Type.optional(sema.arena, child_type);
+ const opt_type = try Type.optional(sema.arena, child_type, mod);
return sema.addType(opt_type);
}
fn zirElemTypeIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const bin = sema.code.instructions.items(.data)[inst].bin;
const indexable_ty = try sema.resolveType(block, .unneeded, bin.lhs);
- assert(indexable_ty.isIndexable()); // validated by a previous instruction
- if (indexable_ty.zigTypeTag() == .Struct) {
- const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs));
+ assert(indexable_ty.isIndexable(mod)); // validated by a previous instruction
+ if (indexable_ty.zigTypeTag(mod) == .Struct) {
+ const elem_type = indexable_ty.structFieldType(@enumToInt(bin.rhs), mod);
return sema.addType(elem_type);
} else {
- const elem_type = indexable_ty.elemType2();
+ const elem_type = indexable_ty.elemType2(mod);
return sema.addType(elem_type);
}
}
fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const elem_type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const len_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
- const len = try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime-known");
+ const len = @intCast(u32, try sema.resolveInt(block, len_src, extra.lhs, Type.u32, "vector length must be comptime-known"));
const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs);
try sema.checkVectorElemType(block, elem_type_src, elem_type);
- const vector_type = try Type.Tag.vector.create(sema.arena, .{
- .len = @intCast(u32, len),
- .elem_type = elem_type,
+ const vector_type = try mod.vectorType(.{
+ .len = len,
+ .child = elem_type.toIntern(),
});
return sema.addType(vector_type);
}
@@ -7849,9 +8043,10 @@ fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
}
fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void {
- if (elem_type.zigTypeTag() == .Opaque) {
- return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(sema.mod)});
- } else if (elem_type.zigTypeTag() == .NoReturn) {
+ const mod = sema.mod;
+ if (elem_type.zigTypeTag(mod) == .Opaque) {
+ return sema.fail(block, elem_src, "array of opaque type '{}' not allowed", .{elem_type.fmt(mod)});
+ } else if (elem_type.zigTypeTag(mod) == .NoReturn) {
return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{});
}
}
@@ -7864,9 +8059,10 @@ fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
if (true) {
return sema.failWithUseOfAsync(block, inst_data.src());
}
+ const mod = sema.mod;
const operand_src: LazySrcLoc = .{ .node_offset_anyframe_type = inst_data.src_node };
const return_type = try sema.resolveType(block, operand_src, inst_data.operand);
- const anyframe_type = try Type.Tag.anyframe_T.create(sema.arena, return_type);
+ const anyframe_type = try mod.anyframeType(return_type);
return sema.addType(anyframe_type);
}
@@ -7875,6 +8071,7 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
@@ -7882,50 +8079,48 @@ fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const error_set = try sema.resolveType(block, lhs_src, extra.lhs);
const payload = try sema.resolveType(block, rhs_src, extra.rhs);
- if (error_set.zigTypeTag() != .ErrorSet) {
+ if (error_set.zigTypeTag(mod) != .ErrorSet) {
return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{
- error_set.fmt(sema.mod),
+ error_set.fmt(mod),
});
}
try sema.validateErrorUnionPayloadType(block, payload, rhs_src);
- const err_union_ty = try Type.errorUnion(sema.arena, error_set, payload, sema.mod);
+ const err_union_ty = try mod.errorUnionType(error_set, payload);
return sema.addType(err_union_ty);
}
fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void {
- if (payload_ty.zigTypeTag() == .Opaque) {
+ const mod = sema.mod;
+ if (payload_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, payload_src, "error union with payload of opaque type '{}' not allowed", .{
- payload_ty.fmt(sema.mod),
+ payload_ty.fmt(mod),
});
- } else if (payload_ty.zigTypeTag() == .ErrorSet) {
+ } else if (payload_ty.zigTypeTag(mod) == .ErrorSet) {
return sema.fail(block, payload_src, "error union with payload of error set type '{}' not allowed", .{
- payload_ty.fmt(sema.mod),
+ payload_ty.fmt(mod),
});
}
}
fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
_ = block;
- const tracy = trace(@src());
- defer tracy.end();
-
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
-
- // Create an anonymous error set type with only this error value, and return the value.
- const kv = try sema.mod.getErrorValue(inst_data.get(sema.code));
- const result_type = try Type.Tag.error_set_single.create(sema.arena, kv.key);
- return sema.addConstant(
- result_type,
- try Value.Tag.@"error".create(sema.arena, .{
- .name = kv.key,
- }),
- );
+ const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ _ = try mod.getErrorValue(name);
+ // Create an error set type with only this error value, and return the value.
+ const error_set_type = try mod.singleErrorSetType(name);
+ return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
+ .ty = error_set_type.toIntern(),
+ .name = name,
+ } })).toValue());
}
fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
@@ -7933,34 +8128,26 @@ fn zirErrorToInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
const operand = try sema.coerce(block, Type.anyerror, uncasted_operand, operand_src);
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) {
+ if (val.isUndef(mod)) {
return sema.addConstUndef(Type.err_int);
}
- switch (val.tag()) {
- .@"error" => {
- const payload = try sema.arena.create(Value.Payload.U64);
- payload.* = .{
- .base = .{ .tag = .int_u64 },
- .data = (try sema.mod.getErrorValue(val.castTag(.@"error").?.data.name)).value,
- };
- return sema.addConstant(Type.err_int, Value.initPayload(&payload.base));
- },
-
- // This is not a valid combination with the type `anyerror`.
- .the_only_possible_value => unreachable,
-
- // Assume it's already encoded as an integer.
- else => return sema.addConstant(Type.err_int, val),
- }
+ const err_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
+ return sema.addConstant(Type.err_int, try mod.intValue(
+ Type.err_int,
+ try mod.getErrorValue(err_name),
+ ));
}
const op_ty = sema.typeOf(uncasted_operand);
try sema.resolveInferredErrorSetTy(block, src, op_ty);
- if (!op_ty.isAnyError()) {
- const names = op_ty.errorSetNames();
+ if (!op_ty.isAnyError(mod)) {
+ const names = op_ty.errorSetNames(mod);
switch (names.len) {
- 0 => return sema.addConstant(Type.err_int, Value.zero),
- 1 => return sema.addIntUnsigned(Type.err_int, sema.mod.global_error_set.get(names[0]).?),
+ 0 => return sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0)),
+ 1 => {
+ const int = @intCast(Module.ErrorInt, mod.global_error_set.getIndex(names[0]).?);
+ return sema.addIntUnsigned(Type.err_int, int);
+ },
else => {},
}
}
@@ -7973,28 +8160,26 @@ fn zirIntToError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const uncasted_operand = try sema.resolveInst(extra.operand);
const operand = try sema.coerce(block, Type.err_int, uncasted_operand, operand_src);
- const target = sema.mod.getTarget();
if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| {
- const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(target));
- if (int > sema.mod.global_error_set.count() or int == 0)
+ const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(mod));
+ if (int > mod.global_error_set.count() or int == 0)
return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int});
- const payload = try sema.arena.create(Value.Payload.Error);
- payload.* = .{
- .base = .{ .tag = .@"error" },
- .data = .{ .name = sema.mod.error_name_list.items[int] },
- };
- return sema.addConstant(Type.anyerror, Value.initPayload(&payload.base));
+ return sema.addConstant(Type.anyerror, (try mod.intern(.{ .err = .{
+ .ty = .anyerror_type,
+ .name = mod.global_error_set.keys()[int],
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, src, operand_src);
if (block.wantSafety()) {
const is_lt_len = try block.addUnOp(.cmp_lt_errors_len, operand);
- const zero_val = try sema.addConstant(Type.err_int, Value.zero);
+ const zero_val = try sema.addConstant(Type.err_int, try mod.intValue(Type.err_int, 0));
const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val);
const ok = try block.addBinOp(.bit_and, is_lt_len, is_non_zero);
try sema.addSafetyCheck(block, ok, .invalid_error_code);
@@ -8012,6 +8197,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
@@ -8019,7 +8205,7 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
const lhs = try sema.resolveInst(extra.lhs);
const rhs = try sema.resolveInst(extra.rhs);
- if (sema.typeOf(lhs).zigTypeTag() == .Bool and sema.typeOf(rhs).zigTypeTag() == .Bool) {
+ if (sema.typeOf(lhs).zigTypeTag(mod) == .Bool and sema.typeOf(rhs).zigTypeTag(mod) == .Bool) {
const msg = msg: {
const msg = try sema.errMsg(block, lhs_src, "expected error set type, found 'bool'", .{});
errdefer msg.destroy(sema.gpa);
@@ -8030,32 +8216,32 @@ fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
}
const lhs_ty = try sema.analyzeAsType(block, lhs_src, lhs);
const rhs_ty = try sema.analyzeAsType(block, rhs_src, rhs);
- if (lhs_ty.zigTypeTag() != .ErrorSet)
- return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(sema.mod)});
- if (rhs_ty.zigTypeTag() != .ErrorSet)
- return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(sema.mod)});
+ if (lhs_ty.zigTypeTag(mod) != .ErrorSet)
+ return sema.fail(block, lhs_src, "expected error set type, found '{}'", .{lhs_ty.fmt(mod)});
+ if (rhs_ty.zigTypeTag(mod) != .ErrorSet)
+ return sema.fail(block, rhs_src, "expected error set type, found '{}'", .{rhs_ty.fmt(mod)});
// Anything merged with anyerror is anyerror.
- if (lhs_ty.tag() == .anyerror or rhs_ty.tag() == .anyerror) {
+ if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) {
return Air.Inst.Ref.anyerror_type;
}
- if (lhs_ty.castTag(.error_set_inferred)) |payload| {
- try sema.resolveInferredErrorSet(block, src, payload.data);
+ if (mod.typeToInferredErrorSetIndex(lhs_ty).unwrap()) |ies_index| {
+ try sema.resolveInferredErrorSet(block, src, ies_index);
// isAnyError might have changed from a false negative to a true positive after resolution.
- if (lhs_ty.isAnyError()) {
+ if (lhs_ty.isAnyError(mod)) {
return Air.Inst.Ref.anyerror_type;
}
}
- if (rhs_ty.castTag(.error_set_inferred)) |payload| {
- try sema.resolveInferredErrorSet(block, src, payload.data);
+ if (mod.typeToInferredErrorSetIndex(rhs_ty).unwrap()) |ies_index| {
+ try sema.resolveInferredErrorSet(block, src, ies_index);
// isAnyError might have changed from a false negative to a true positive after resolution.
- if (rhs_ty.isAnyError()) {
+ if (rhs_ty.isAnyError(mod)) {
return Air.Inst.Ref.anyerror_type;
}
}
- const err_set_ty = try lhs_ty.errorSetMerge(sema.arena, rhs_ty);
+ const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty);
return sema.addType(err_set_ty);
}
@@ -8064,27 +8250,27 @@ fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
- const duped_name = try sema.arena.dupe(u8, inst_data.get(sema.code));
- return sema.addConstant(
- Type.initTag(.enum_literal),
- try Value.Tag.enum_literal.create(sema.arena, duped_name),
- );
+ const name = inst_data.get(sema.code);
+ return sema.addConstant(.{ .ip_index = .enum_literal_type }, (try mod.intern(.{
+ .enum_literal = try mod.intern_pool.getOrPutString(sema.gpa, name),
+ })).toValue());
}
fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const arena = sema.arena;
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
- const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag()) {
+ const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(mod)) {
.Enum => operand,
.Union => blk: {
const union_ty = try sema.resolveTypeFields(operand_ty);
- const tag_ty = union_ty.unionTagType() orelse {
+ const tag_ty = union_ty.unionTagType(mod) orelse {
return sema.fail(
block,
operand_src,
@@ -8096,22 +8282,20 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
},
else => {
return sema.fail(block, operand_src, "expected enum or tagged union, found '{}'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
});
},
};
const enum_tag_ty = sema.typeOf(enum_tag);
- var int_tag_type_buffer: Type.Payload.Bits = undefined;
- const int_tag_ty = try enum_tag_ty.intTagType(&int_tag_type_buffer).copy(arena);
+ const int_tag_ty = enum_tag_ty.intTagType(mod);
if (try sema.typeHasOnePossibleValue(enum_tag_ty)) |opv| {
- return sema.addConstant(int_tag_ty, opv);
+ return sema.addConstant(int_tag_ty, try mod.getCoerced(opv, int_tag_ty));
}
if (try sema.resolveMaybeUndefVal(enum_tag)) |enum_tag_val| {
- var buffer: Value.Payload.U64 = undefined;
- const val = enum_tag_val.enumToInt(enum_tag_ty, &buffer);
+ const val = try enum_tag_val.enumToInt(enum_tag_ty, mod);
return sema.addConstant(int_tag_ty, try val.copy(sema.arena));
}
@@ -8120,6 +8304,7 @@ fn zirEnumToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
}
fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const src = inst_data.src();
@@ -8128,24 +8313,23 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
const operand = try sema.resolveInst(extra.rhs);
- if (dest_ty.zigTypeTag() != .Enum) {
- return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(sema.mod)});
+ if (dest_ty.zigTypeTag(mod) != .Enum) {
+ return sema.fail(block, dest_ty_src, "expected enum, found '{}'", .{dest_ty.fmt(mod)});
}
_ = try sema.checkIntType(block, operand_src, sema.typeOf(operand));
if (try sema.resolveMaybeUndefVal(operand)) |int_val| {
- if (dest_ty.isNonexhaustiveEnum()) {
- var buffer: Type.Payload.Bits = undefined;
- const int_tag_ty = dest_ty.intTagType(&buffer);
+ if (dest_ty.isNonexhaustiveEnum(mod)) {
+ const int_tag_ty = dest_ty.intTagType(mod);
if (try sema.intFitsInType(int_val, int_tag_ty, null)) {
- return sema.addConstant(dest_ty, int_val);
+ return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty));
}
const msg = msg: {
const msg = try sema.errMsg(
block,
src,
"int value '{}' out of range of non-exhaustive enum '{}'",
- .{ int_val.fmtValue(sema.typeOf(operand), sema.mod), dest_ty.fmt(sema.mod) },
+ .{ int_val.fmtValue(sema.typeOf(operand), mod), dest_ty.fmt(mod) },
);
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, dest_ty);
@@ -8153,7 +8337,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (int_val.isUndef()) {
+ if (int_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, operand_src);
}
if (!(try sema.enumHasInt(dest_ty, int_val))) {
@@ -8162,7 +8346,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
block,
src,
"enum '{}' has no tag with value '{}'",
- .{ dest_ty.fmt(sema.mod), int_val.fmtValue(sema.typeOf(operand), sema.mod) },
+ .{ dest_ty.fmt(mod), int_val.fmtValue(sema.typeOf(operand), mod) },
);
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, dest_ty);
@@ -8170,7 +8354,7 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
};
return sema.failWithOwnedErrorMsg(msg);
}
- return sema.addConstant(dest_ty, int_val);
+ return sema.addConstant(dest_ty, try mod.getCoerced(int_val, dest_ty));
}
if (try sema.typeHasOnePossibleValue(dest_ty)) |opv| {
@@ -8184,8 +8368,8 @@ fn zirIntToEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
try sema.requireRuntimeBlock(block, src, operand_src);
const result = try block.addTyOp(.intcast, dest_ty, operand);
- if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum() and
- sema.mod.backendSupportsFeature(.is_named_enum_value))
+ if (block.wantSafety() and !dest_ty.isNonexhaustiveEnum(mod) and
+ mod.backendSupportsFeature(.is_named_enum_value))
{
const ok = try block.addUnOp(.is_named_enum_value, result);
try sema.addSafetyCheck(block, ok, .invalid_enum_value);
@@ -8218,49 +8402,44 @@ fn analyzeOptionalPayloadPtr(
safety_check: bool,
initializing: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const optional_ptr_ty = sema.typeOf(optional_ptr);
- assert(optional_ptr_ty.zigTypeTag() == .Pointer);
+ assert(optional_ptr_ty.zigTypeTag(mod) == .Pointer);
- const opt_type = optional_ptr_ty.elemType();
- if (opt_type.zigTypeTag() != .Optional) {
- return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(sema.mod)});
+ const opt_type = optional_ptr_ty.childType(mod);
+ if (opt_type.zigTypeTag(mod) != .Optional) {
+ return sema.fail(block, src, "expected optional type, found '{}'", .{opt_type.fmt(mod)});
}
- const child_type = try opt_type.optionalChildAlloc(sema.arena);
- const child_pointer = try Type.ptr(sema.arena, sema.mod, .{
+ const child_type = opt_type.optionalChild(mod);
+ const child_pointer = try Type.ptr(sema.arena, mod, .{
.pointee_type = child_type,
- .mutable = !optional_ptr_ty.isConstPtr(),
- .@"addrspace" = optional_ptr_ty.ptrAddressSpace(),
+ .mutable = !optional_ptr_ty.isConstPtr(mod),
+ .@"addrspace" = optional_ptr_ty.ptrAddressSpace(mod),
});
if (try sema.resolveDefinedValue(block, src, optional_ptr)) |ptr_val| {
if (initializing) {
- if (!ptr_val.isComptimeMutablePtr()) {
+ if (!ptr_val.isComptimeMutablePtr(mod)) {
// If the pointer resulting from this function was stored at comptime,
// the optional non-null bit would be set that way. But in this case,
// we need to emit a runtime instruction to do it.
_ = try block.addTyOp(.optional_payload_ptr_set, child_pointer, optional_ptr);
}
- return sema.addConstant(
- child_pointer,
- try Value.Tag.opt_payload_ptr.create(sema.arena, .{
- .container_ptr = ptr_val,
- .container_ty = optional_ptr_ty.childType(),
- }),
- );
+ return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{
+ .ty = child_pointer.toIntern(),
+ .addr = .{ .opt_payload = ptr_val.toIntern() },
+ } })).toValue());
}
if (try sema.pointerDeref(block, src, ptr_val, optional_ptr_ty)) |val| {
- if (val.isNull()) {
+ if (val.isNull(mod)) {
return sema.fail(block, src, "unable to unwrap null", .{});
}
// The same Value represents the pointer to the optional and the payload.
- return sema.addConstant(
- child_pointer,
- try Value.Tag.opt_payload_ptr.create(sema.arena, .{
- .container_ptr = ptr_val,
- .container_ty = optional_ptr_ty.childType(),
- }),
- );
+ return sema.addConstant(child_pointer, (try mod.intern(.{ .ptr = .{
+ .ty = child_pointer.toIntern(),
+ .addr = .{ .opt_payload = ptr_val.toIntern() },
+ } })).toValue());
}
}
@@ -8286,21 +8465,22 @@ fn zirOptionalPayload(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
- const result_ty = switch (operand_ty.zigTypeTag()) {
- .Optional => try operand_ty.optionalChildAlloc(sema.arena),
+ const result_ty = switch (operand_ty.zigTypeTag(mod)) {
+ .Optional => operand_ty.optionalChild(mod),
.Pointer => t: {
- if (operand_ty.ptrSize() != .C) {
+ if (operand_ty.ptrSize(mod) != .C) {
return sema.failWithExpectedOptionalType(block, src, operand_ty);
}
// TODO https://github.com/ziglang/zig/issues/6597
if (true) break :t operand_ty;
- const ptr_info = operand_ty.ptrInfo().data;
- break :t try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = try ptr_info.pointee_type.copy(sema.arena),
+ const ptr_info = operand_ty.ptrInfo(mod);
+ break :t try Type.ptr(sema.arena, mod, .{
+ .pointee_type = ptr_info.pointee_type,
.@"align" = ptr_info.@"align",
.@"addrspace" = ptr_info.@"addrspace",
.mutable = ptr_info.mutable,
@@ -8313,13 +8493,10 @@ fn zirOptionalPayload(
};
if (try sema.resolveDefinedValue(block, src, operand)) |val| {
- if (val.isNull()) {
- return sema.fail(block, src, "unable to unwrap null", .{});
- }
- if (val.castTag(.opt_payload)) |payload| {
- return sema.addConstant(result_ty, payload.data);
- }
- return sema.addConstant(result_ty, val);
+ return if (val.optionalValue(mod)) |payload|
+ sema.addConstant(result_ty, payload)
+ else
+ sema.fail(block, src, "unable to unwrap null", .{});
}
try sema.requireRuntimeBlock(block, src, null);
@@ -8339,14 +8516,15 @@ fn zirErrUnionPayload(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
const operand_src = src;
const err_union_ty = sema.typeOf(operand);
- if (err_union_ty.zigTypeTag() != .ErrorUnion) {
+ if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(block, operand_src, "expected error union type, found '{}'", .{
- err_union_ty.fmt(sema.mod),
+ err_union_ty.fmt(mod),
});
}
return sema.analyzeErrUnionPayload(block, src, err_union_ty, operand, operand_src, false);
@@ -8357,24 +8535,27 @@ fn analyzeErrUnionPayload(
block: *Block,
src: LazySrcLoc,
err_union_ty: Type,
- operand: Zir.Inst.Ref,
+ operand: Air.Inst.Ref,
operand_src: LazySrcLoc,
safety_check: bool,
) CompileError!Air.Inst.Ref {
- const payload_ty = err_union_ty.errorUnionPayload();
+ const mod = sema.mod;
+ const payload_ty = err_union_ty.errorUnionPayload(mod);
if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
- if (val.getError()) |name| {
- return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
+ if (val.getErrorName(mod).unwrap()) |name| {
+ return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&mod.intern_pool)});
}
- const data = val.castTag(.eu_payload).?.data;
- return sema.addConstant(payload_ty, data);
+ return sema.addConstant(
+ payload_ty,
+ mod.intern_pool.indexToKey(val.toIntern()).error_union.val.payload.toValue(),
+ );
}
try sema.requireRuntimeBlock(block, src, null);
// If the error set has no fields then no safety check is needed.
if (safety_check and block.wantSafety() and
- !err_union_ty.errorUnionSet().errorSetIsEmpty())
+ !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
{
try sema.panicUnwrapError(block, operand, .unwrap_errunion_err, .is_non_err);
}
@@ -8406,52 +8587,46 @@ fn analyzeErrUnionPayloadPtr(
safety_check: bool,
initializing: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
- assert(operand_ty.zigTypeTag() == .Pointer);
+ assert(operand_ty.zigTypeTag(mod) == .Pointer);
- if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) {
+ if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(block, src, "expected error union type, found '{}'", .{
- operand_ty.elemType().fmt(sema.mod),
+ operand_ty.childType(mod).fmt(mod),
});
}
- const err_union_ty = operand_ty.elemType();
- const payload_ty = err_union_ty.errorUnionPayload();
- const operand_pointer_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const err_union_ty = operand_ty.childType(mod);
+ const payload_ty = err_union_ty.errorUnionPayload(mod);
+ const operand_pointer_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = payload_ty,
- .mutable = !operand_ty.isConstPtr(),
- .@"addrspace" = operand_ty.ptrAddressSpace(),
+ .mutable = !operand_ty.isConstPtr(mod),
+ .@"addrspace" = operand_ty.ptrAddressSpace(mod),
});
if (try sema.resolveDefinedValue(block, src, operand)) |ptr_val| {
if (initializing) {
- if (!ptr_val.isComptimeMutablePtr()) {
+ if (!ptr_val.isComptimeMutablePtr(mod)) {
// If the pointer resulting from this function was stored at comptime,
// the error union error code would be set that way. But in this case,
// we need to emit a runtime instruction to do it.
try sema.requireRuntimeBlock(block, src, null);
_ = try block.addTyOp(.errunion_payload_ptr_set, operand_pointer_ty, operand);
}
- return sema.addConstant(
- operand_pointer_ty,
- try Value.Tag.eu_payload_ptr.create(sema.arena, .{
- .container_ptr = ptr_val,
- .container_ty = operand_ty.elemType(),
- }),
- );
+ return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{
+ .ty = operand_pointer_ty.toIntern(),
+ .addr = .{ .eu_payload = ptr_val.toIntern() },
+ } })).toValue());
}
if (try sema.pointerDeref(block, src, ptr_val, operand_ty)) |val| {
- if (val.getError()) |name| {
- return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
+ if (val.getErrorName(mod).unwrap()) |name| {
+ return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&mod.intern_pool)});
}
-
- return sema.addConstant(
- operand_pointer_ty,
- try Value.Tag.eu_payload_ptr.create(sema.arena, .{
- .container_ptr = ptr_val,
- .container_ty = operand_ty.elemType(),
- }),
- );
+ return sema.addConstant(operand_pointer_ty, (try mod.intern(.{ .ptr = .{
+ .ty = operand_pointer_ty.toIntern(),
+ .addr = .{ .eu_payload = ptr_val.toIntern() },
+ } })).toValue());
}
}
@@ -8459,7 +8634,7 @@ fn analyzeErrUnionPayloadPtr(
// If the error set has no fields then no safety check is needed.
if (safety_check and block.wantSafety() and
- !err_union_ty.errorUnionSet().errorSetIsEmpty())
+ !err_union_ty.errorUnionSet(mod).errorSetIsEmpty(mod))
{
try sema.panicUnwrapError(block, operand, .unwrap_errunion_err_ptr, .is_non_err_ptr);
}
@@ -8483,18 +8658,21 @@ fn zirErrUnionCode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
}
fn analyzeErrUnionCode(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
- if (operand_ty.zigTypeTag() != .ErrorUnion) {
+ if (operand_ty.zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(block, src, "expected error union type, found '{}'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
});
}
- const result_ty = operand_ty.errorUnionSet();
+ const result_ty = operand_ty.errorUnionSet(mod);
if (try sema.resolveDefinedValue(block, src, operand)) |val| {
- assert(val.getError() != null);
- return sema.addConstant(result_ty, val);
+ return sema.addConstant(result_ty, (try mod.intern(.{ .err = .{
+ .ty = result_ty.toIntern(),
+ .name = mod.intern_pool.indexToKey(val.toIntern()).error_union.val.err_name,
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, src, null);
@@ -8506,23 +8684,24 @@ fn zirErrUnionCodePtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
- assert(operand_ty.zigTypeTag() == .Pointer);
+ assert(operand_ty.zigTypeTag(mod) == .Pointer);
- if (operand_ty.elemType().zigTypeTag() != .ErrorUnion) {
+ if (operand_ty.childType(mod).zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(block, src, "expected error union type, found '{}'", .{
- operand_ty.elemType().fmt(sema.mod),
+ operand_ty.childType(mod).fmt(mod),
});
}
- const result_ty = operand_ty.elemType().errorUnionSet();
+ const result_ty = operand_ty.childType(mod).errorUnionSet(mod);
if (try sema.resolveDefinedValue(block, src, operand)) |pointer_val| {
if (try sema.pointerDeref(block, src, pointer_val, operand_ty)) |val| {
- assert(val.getError() != null);
+ assert(val.getErrorName(mod) != .none);
return sema.addConstant(result_ty, val);
}
}
@@ -8556,7 +8735,7 @@ fn zirFunc(
break :blk ret_ty;
} else |err| switch (err) {
error.GenericPoison => {
- break :blk Type.initTag(.generic_poison);
+ break :blk Type.generic_poison;
},
else => |e| return e,
}
@@ -8566,8 +8745,7 @@ fn zirFunc(
extra_index += ret_ty_body.len;
const ret_ty_val = try sema.resolveGenericBody(block, ret_ty_src, ret_ty_body, inst, Type.type, "return type must be comptime-known");
- var buffer: Value.ToTypeBuffer = undefined;
- break :blk try ret_ty_val.toType(&buffer).copy(sema.arena);
+ break :blk ret_ty_val.toType();
},
};
@@ -8634,10 +8812,10 @@ fn resolveGenericBody(
};
switch (err) {
error.GenericPoison => {
- if (dest_ty.tag() == .type) {
- return Value.initTag(.generic_poison_type);
+ if (dest_ty.toIntern() == .type_type) {
+ return Value.generic_poison_type;
} else {
- return Value.initTag(.generic_poison);
+ return Value.generic_poison;
}
},
else => |e| return e,
@@ -8711,7 +8889,7 @@ fn handleExternLibName(
const FuncLinkSection = union(enum) {
generic,
default,
- explicit: []const u8,
+ explicit: InternPool.NullTerminatedString,
};
fn funcCommon(
@@ -8738,11 +8916,13 @@ fn funcCommon(
noalias_bits: u32,
is_noinline: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = src_node_offset };
const cc_src: LazySrcLoc = .{ .node_offset_fn_type_cc = src_node_offset };
const func_src = LazySrcLoc.nodeOffset(src_node_offset);
- var is_generic = bare_return_type.tag() == .generic_poison or
+ var is_generic = bare_return_type.isGenericPoison() or
alignment == null or
address_space == null or
section == .generic or
@@ -8758,69 +8938,42 @@ fn funcCommon(
}
var destroy_fn_on_error = false;
- const new_func: *Module.Fn = new_func: {
+ const new_func_index = new_func: {
if (!has_body) break :new_func undefined;
if (sema.comptime_args_fn_inst == func_inst) {
- const new_func = sema.preallocated_new_func.?;
- sema.preallocated_new_func = null; // take ownership
- break :new_func new_func;
+ const new_func_index = sema.preallocated_new_func.unwrap().?;
+ sema.preallocated_new_func = .none; // take ownership
+ break :new_func new_func_index;
}
destroy_fn_on_error = true;
- const new_func = try sema.gpa.create(Module.Fn);
+ var new_func: Module.Fn = undefined;
// Set this here so that the inferred return type can be printed correctly if it appears in an error.
new_func.owner_decl = sema.owner_decl_index;
- break :new_func new_func;
+ const new_func_index = try mod.createFunc(new_func);
+ break :new_func new_func_index;
};
- errdefer if (destroy_fn_on_error) sema.gpa.destroy(new_func);
+ errdefer if (destroy_fn_on_error) mod.destroyFunc(new_func_index);
- var maybe_inferred_error_set_node: ?*Module.Fn.InferredErrorSetListNode = null;
- errdefer if (maybe_inferred_error_set_node) |node| sema.gpa.destroy(node);
- // Note: no need to errdefer since this will still be in its default state at the end of the function.
-
- const target = sema.mod.getTarget();
+ const target = mod.getTarget();
const fn_ty: Type = fn_ty: {
- // Hot path for some common function types.
- // TODO can we eliminate some of these Type tag values? seems unnecessarily complicated.
- if (!is_generic and block.params.items.len == 0 and !var_args and !inferred_error_set and
- alignment.? == 0 and
- address_space.? == target_util.defaultAddressSpace(target, .function) and
- section == .default)
- {
- if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Unspecified) {
- break :fn_ty Type.initTag(.fn_noreturn_no_args);
- }
-
- if (bare_return_type.zigTypeTag() == .Void and cc.? == .Unspecified) {
- break :fn_ty Type.initTag(.fn_void_no_args);
- }
-
- if (bare_return_type.zigTypeTag() == .NoReturn and cc.? == .Naked) {
- break :fn_ty Type.initTag(.fn_naked_noreturn_no_args);
- }
-
- if (bare_return_type.zigTypeTag() == .Void and cc.? == .C) {
- break :fn_ty Type.initTag(.fn_ccc_void_no_args);
- }
- }
-
// In the case of generic calling convention, or generic alignment, we use
// default values which are only meaningful for the generic function, *not*
// the instantiation, which can depend on comptime parameters.
// Related proposal: https://github.com/ziglang/zig/issues/11834
const cc_resolved = cc orelse .Unspecified;
- const param_types = try sema.arena.alloc(Type, block.params.items.len);
- const comptime_params = try sema.arena.alloc(bool, block.params.items.len);
- for (block.params.items, 0..) |param, i| {
+ const param_types = try sema.arena.alloc(InternPool.Index, block.params.items.len);
+ var comptime_bits: u32 = 0;
+ for (param_types, block.params.items, 0..) |*dest_param_ty, param, i| {
const is_noalias = blk: {
const index = std.math.cast(u5, i) orelse break :blk false;
break :blk @truncate(u1, noalias_bits >> index) != 0;
};
- param_types[i] = param.ty;
+ dest_param_ty.* = param.ty.toIntern();
sema.analyzeParameter(
block,
.unneeded,
param,
- comptime_params,
+ &comptime_bits,
i,
&is_generic,
cc_resolved,
@@ -8828,12 +8981,12 @@ fn funcCommon(
is_noalias,
) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
+ const decl = mod.declPtr(block.src_decl);
try sema.analyzeParameter(
block,
- Module.paramSrc(src_node_offset, sema.gpa, decl, i),
+ Module.paramSrc(src_node_offset, mod, decl, i),
param,
- comptime_params,
+ &comptime_bits,
i,
&is_generic,
cc_resolved,
@@ -8849,7 +9002,7 @@ fn funcCommon(
var ret_ty_requires_comptime = false;
const ret_poison = if (sema.typeRequiresComptime(bare_return_type)) |ret_comptime| rp: {
ret_ty_requires_comptime = ret_comptime;
- break :rp bare_return_type.tag() == .generic_poison;
+ break :rp bare_return_type.isGenericPoison();
} else |err| switch (err) {
error.GenericPoison => rp: {
is_generic = true;
@@ -8858,43 +9011,41 @@ fn funcCommon(
else => |e| return e,
};
- const return_type = if (!inferred_error_set or ret_poison)
+ const return_type: Type = if (!inferred_error_set or ret_poison)
bare_return_type
else blk: {
try sema.validateErrorUnionPayloadType(block, bare_return_type, ret_ty_src);
- const node = try sema.gpa.create(Module.Fn.InferredErrorSetListNode);
- node.data = .{ .func = new_func };
- maybe_inferred_error_set_node = node;
-
- const error_set_ty = try Type.Tag.error_set_inferred.create(sema.arena, &node.data);
- break :blk try Type.Tag.error_union.create(sema.arena, .{
- .error_set = error_set_ty,
- .payload = bare_return_type,
+ const ies_index = try mod.intern_pool.createInferredErrorSet(gpa, .{
+ .func = new_func_index,
});
+ const error_set_ty = try mod.intern(.{ .inferred_error_set_type = ies_index });
+ break :blk try mod.errorUnionType(error_set_ty.toType(), bare_return_type);
};
- if (!return_type.isValidReturnType()) {
- const opaque_str = if (return_type.zigTypeTag() == .Opaque) "opaque " else "";
+ if (!return_type.isValidReturnType(mod)) {
+ const opaque_str = if (return_type.zigTypeTag(mod) == .Opaque) "opaque " else "";
const msg = msg: {
const msg = try sema.errMsg(block, ret_ty_src, "{s}return type '{}' not allowed", .{
- opaque_str, return_type.fmt(sema.mod),
+ opaque_str, return_type.fmt(mod),
});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, return_type);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (!ret_poison and !Type.fnCallingConventionAllowsZigTypes(target, cc_resolved) and !try sema.validateExternType(return_type, .ret_ty)) {
+ if (!ret_poison and !target_util.fnCallConvAllowsZigTypes(target, cc_resolved) and
+ !try sema.validateExternType(return_type, .ret_ty))
+ {
const msg = msg: {
const msg = try sema.errMsg(block, ret_ty_src, "return type '{}' not allowed in function with calling convention '{s}'", .{
- return_type.fmt(sema.mod), @tagName(cc_resolved),
+ return_type.fmt(mod), @tagName(cc_resolved),
});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl), return_type, .ret_ty);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, ret_ty_src.toSrcLoc(src_decl, mod), return_type, .ret_ty);
try sema.addDeclaredHereNote(msg, return_type);
break :msg msg;
@@ -8912,9 +9063,9 @@ fn funcCommon(
block,
ret_ty_src,
"function with comptime-only return type '{}' requires all parameters to be comptime",
- .{return_type.fmt(sema.mod)},
+ .{return_type.fmt(mod)},
);
- try sema.explainWhyTypeIsComptime(block, ret_ty_src, msg, ret_ty_src.toSrcLoc(sema.owner_decl), return_type);
+ try sema.explainWhyTypeIsComptime(msg, ret_ty_src.toSrcLoc(sema.owner_decl, mod), return_type);
const tags = sema.code.instructions.items(.tag);
const data = sema.code.instructions.items(.data);
@@ -8937,7 +9088,7 @@ fn funcCommon(
return sema.failWithOwnedErrorMsg(msg);
}
- const arch = sema.mod.getTarget().cpu.arch;
+ const arch = mod.getTarget().cpu.arch;
if (switch (cc_resolved) {
.Unspecified, .C, .Naked, .Async, .Inline => null,
.Interrupt => switch (arch) {
@@ -8980,8 +9131,7 @@ fn funcCommon(
return sema.fail(block, cc_src, "'noinline' function cannot have callconv 'Inline'", .{});
}
if (is_generic and sema.no_partial_func_ty) return error.GenericPoison;
- for (comptime_params) |ct| is_generic = is_generic or ct;
- is_generic = is_generic or ret_ty_requires_comptime;
+ is_generic = is_generic or comptime_bits != 0 or ret_ty_requires_comptime;
if (!is_generic and sema.wantErrorReturnTracing(return_type)) {
// Make sure that StackTrace's fields are resolved so that the backend can
@@ -8990,67 +9140,58 @@ fn funcCommon(
_ = try sema.resolveTypeFields(unresolved_stack_trace_ty);
}
- break :fn_ty try Type.Tag.function.create(sema.arena, .{
+ break :fn_ty try mod.funcType(.{
.param_types = param_types,
- .comptime_params = comptime_params.ptr,
- .return_type = return_type,
+ .noalias_bits = noalias_bits,
+ .comptime_bits = comptime_bits,
+ .return_type = return_type.toIntern(),
.cc = cc_resolved,
.cc_is_generic = cc == null,
- .alignment = alignment orelse 0,
+ .alignment = if (alignment) |a| InternPool.Alignment.fromByteUnits(a) else .none,
.align_is_generic = alignment == null,
.section_is_generic = section == .generic,
.addrspace_is_generic = address_space == null,
.is_var_args = var_args,
.is_generic = is_generic,
- .noalias_bits = noalias_bits,
+ .is_noinline = is_noinline,
});
};
sema.owner_decl.@"linksection" = switch (section) {
- .generic => undefined,
- .default => null,
- .explicit => |section_name| try sema.perm_arena.dupeZ(u8, section_name),
+ .generic => .none,
+ .default => .none,
+ .explicit => |section_name| section_name.toOptional(),
};
sema.owner_decl.@"align" = alignment orelse 0;
sema.owner_decl.@"addrspace" = address_space orelse .generic;
if (is_extern) {
- const new_extern_fn = try sema.gpa.create(Module.ExternFn);
- errdefer sema.gpa.destroy(new_extern_fn);
-
- new_extern_fn.* = Module.ExternFn{
- .owner_decl = sema.owner_decl_index,
- .lib_name = null,
- };
-
- if (opt_lib_name) |lib_name| {
- new_extern_fn.lib_name = try sema.handleExternLibName(block, .{
- .node_offset_lib_name = src_node_offset,
- }, lib_name);
- }
-
- const extern_fn_payload = try sema.arena.create(Value.Payload.ExternFn);
- extern_fn_payload.* = .{
- .base = .{ .tag = .extern_fn },
- .data = new_extern_fn,
- };
- return sema.addConstant(fn_ty, Value.initPayload(&extern_fn_payload.base));
+ return sema.addConstant(fn_ty, (try mod.intern(.{ .extern_func = .{
+ .ty = fn_ty.toIntern(),
+ .decl = sema.owner_decl_index,
+ .lib_name = if (opt_lib_name) |lib_name| (try mod.intern_pool.getOrPutString(
+ gpa,
+ try sema.handleExternLibName(block, .{
+ .node_offset_lib_name = src_node_offset,
+ }, lib_name),
+ )).toOptional() else .none,
+ } })).toValue());
}
if (!has_body) {
return sema.addType(fn_ty);
}
- const is_inline = fn_ty.fnCallingConvention() == .Inline;
- const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .queued;
+ const is_inline = fn_ty.fnCallingConvention(mod) == .Inline;
+ const anal_state: Module.Fn.Analysis = if (is_inline) .inline_only else .none;
const comptime_args: ?[*]TypedValue = if (sema.comptime_args_fn_inst == func_inst) blk: {
break :blk if (sema.comptime_args.len == 0) null else sema.comptime_args.ptr;
} else null;
+ const new_func = mod.funcPtr(new_func_index);
const hash = new_func.hash;
const generic_owner_decl = if (comptime_args == null) .none else new_func.generic_owner_decl;
- const fn_payload = try sema.arena.create(Value.Payload.Function);
new_func.* = .{
.state = anal_state,
.zir_body_inst = func_inst,
@@ -9065,15 +9206,10 @@ fn funcCommon(
.branch_quota = default_branch_quota,
.is_noinline = is_noinline,
};
- if (maybe_inferred_error_set_node) |node| {
- new_func.inferred_error_sets.prepend(node);
- }
- maybe_inferred_error_set_node = null;
- fn_payload.* = .{
- .base = .{ .tag = .function },
- .data = new_func,
- };
- return sema.addConstant(fn_ty, Value.initPayload(&fn_payload.base));
+ return sema.addConstant(fn_ty, (try mod.intern(.{ .func = .{
+ .ty = fn_ty.toIntern(),
+ .index = new_func_index,
+ } })).toValue());
}
fn analyzeParameter(
@@ -9081,29 +9217,32 @@ fn analyzeParameter(
block: *Block,
param_src: LazySrcLoc,
param: Block.Param,
- comptime_params: []bool,
+ comptime_bits: *u32,
i: usize,
is_generic: *bool,
cc: std.builtin.CallingConvention,
has_body: bool,
is_noalias: bool,
) !void {
+ const mod = sema.mod;
const requires_comptime = try sema.typeRequiresComptime(param.ty);
- comptime_params[i] = param.is_comptime or requires_comptime;
- const this_generic = param.ty.tag() == .generic_poison;
+ if (param.is_comptime or requires_comptime) {
+ comptime_bits.* |= @as(u32, 1) << @intCast(u5, i); // TODO: handle cast error
+ }
+ const this_generic = param.ty.isGenericPoison();
is_generic.* = is_generic.* or this_generic;
- const target = sema.mod.getTarget();
- if (param.is_comptime and !Type.fnCallingConventionAllowsZigTypes(target, cc)) {
+ const target = mod.getTarget();
+ if (param.is_comptime and !target_util.fnCallConvAllowsZigTypes(target, cc)) {
return sema.fail(block, param_src, "comptime parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
}
- if (this_generic and !sema.no_partial_func_ty and !Type.fnCallingConventionAllowsZigTypes(target, cc)) {
+ if (this_generic and !sema.no_partial_func_ty and !target_util.fnCallConvAllowsZigTypes(target, cc)) {
return sema.fail(block, param_src, "generic parameters not allowed in function with calling convention '{s}'", .{@tagName(cc)});
}
- if (!param.ty.isValidParamType()) {
- const opaque_str = if (param.ty.zigTypeTag() == .Opaque) "opaque " else "";
+ if (!param.ty.isValidParamType(mod)) {
+ const opaque_str = if (param.ty.zigTypeTag(mod) == .Opaque) "opaque " else "";
const msg = msg: {
const msg = try sema.errMsg(block, param_src, "parameter of {s}type '{}' not allowed", .{
- opaque_str, param.ty.fmt(sema.mod),
+ opaque_str, param.ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
@@ -9112,15 +9251,15 @@ fn analyzeParameter(
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (!this_generic and !Type.fnCallingConventionAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) {
+ if (!this_generic and !target_util.fnCallConvAllowsZigTypes(target, cc) and !try sema.validateExternType(param.ty, .param_ty)) {
const msg = msg: {
const msg = try sema.errMsg(block, param_src, "parameter of type '{}' not allowed in function with calling convention '{s}'", .{
- param.ty.fmt(sema.mod), @tagName(cc),
+ param.ty.fmt(mod), @tagName(cc),
});
errdefer msg.destroy(sema.gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl), param.ty, .param_ty);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, param_src.toSrcLoc(src_decl, mod), param.ty, .param_ty);
try sema.addDeclaredHereNote(msg, param.ty);
break :msg msg;
@@ -9130,12 +9269,12 @@ fn analyzeParameter(
if (!sema.is_generic_instantiation and requires_comptime and !param.is_comptime and has_body) {
const msg = msg: {
const msg = try sema.errMsg(block, param_src, "parameter of type '{}' must be declared comptime", .{
- param.ty.fmt(sema.mod),
+ param.ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsComptime(block, param_src, msg, param_src.toSrcLoc(src_decl), param.ty);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsComptime(msg, param_src.toSrcLoc(src_decl, mod), param.ty);
try sema.addDeclaredHereNote(msg, param.ty);
break :msg msg;
@@ -9143,7 +9282,7 @@ fn analyzeParameter(
return sema.failWithOwnedErrorMsg(msg);
}
if (!sema.is_generic_instantiation and !this_generic and is_noalias and
- !(param.ty.zigTypeTag() == .Pointer or param.ty.isPtrLikeOptional()))
+ !(param.ty.zigTypeTag(mod) == .Pointer or param.ty.isPtrLikeOptional(mod)))
{
return sema.fail(block, param_src, "non-pointer parameter declared noalias", .{});
}
@@ -9170,7 +9309,7 @@ fn zirParam(
const prev_preallocated_new_func = sema.preallocated_new_func;
const prev_no_partial_func_type = sema.no_partial_func_ty;
block.params = .{};
- sema.preallocated_new_func = null;
+ sema.preallocated_new_func = .none;
sema.no_partial_func_ty = true;
defer {
block.params.deinit(sema.gpa);
@@ -9196,7 +9335,7 @@ fn zirParam(
// We result the param instruction with a poison value and
// insert an anytype parameter.
try block.params.append(sema.gpa, .{
- .ty = Type.initTag(.generic_poison),
+ .ty = Type.generic_poison,
.is_comptime = comptime_syntax,
.name = param_name,
});
@@ -9217,7 +9356,7 @@ fn zirParam(
// We result the param instruction with a poison value and
// insert an anytype parameter.
try block.params.append(sema.gpa, .{
- .ty = Type.initTag(.generic_poison),
+ .ty = Type.generic_poison,
.is_comptime = comptime_syntax,
.name = param_name,
});
@@ -9227,7 +9366,7 @@ fn zirParam(
else => |e| return e,
} or comptime_syntax;
if (sema.inst_map.get(inst)) |arg| {
- if (is_comptime and sema.preallocated_new_func != null) {
+ if (is_comptime and sema.preallocated_new_func != .none) {
// We have a comptime value for this parameter so it should be elided from the
// function type of the function instruction in this block.
const coerced_arg = sema.coerce(block, param_ty, arg, .unneeded) catch |err| switch (err) {
@@ -9250,7 +9389,7 @@ fn zirParam(
assert(sema.inst_map.remove(inst));
}
- if (sema.preallocated_new_func != null) {
+ if (sema.preallocated_new_func != .none) {
if (try sema.typeHasOnePossibleValue(param_ty)) |opv| {
// In this case we are instantiating a generic function call with a non-comptime
// non-anytype parameter that ended up being a one-possible-type.
@@ -9270,7 +9409,7 @@ fn zirParam(
if (is_comptime) {
// If this is a comptime parameter we can add a constant generic_poison
// since this is also a generic parameter.
- const result = try sema.addConstant(param_ty, Value.initTag(.generic_poison));
+ const result = try sema.addConstant(Type.generic_poison, Value.generic_poison);
sema.inst_map.putAssumeCapacityNoClobber(inst, result);
} else {
// Otherwise we need a dummy runtime instruction.
@@ -9315,7 +9454,7 @@ fn zirParamAnytype(
// We are evaluating a generic function without any comptime args provided.
try block.params.append(sema.gpa, .{
- .ty = Type.initTag(.generic_poison),
+ .ty = Type.generic_poison,
.is_comptime = comptime_syntax,
.name = param_name,
});
@@ -9359,16 +9498,20 @@ fn analyzeAs(
zir_operand: Zir.Inst.Ref,
no_cast_to_comptime_int: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const operand = try sema.resolveInst(zir_operand);
+ if (zir_dest_type == .var_args_param_type) return operand;
+ const dest_ty = sema.resolveType(block, src, zir_dest_type) catch |err| switch (err) {
+ error.GenericPoison => return operand,
+ else => |e| return e,
+ };
+ if (dest_ty.zigTypeTag(mod) == .NoReturn) {
+ return sema.fail(block, src, "cannot cast to noreturn", .{});
+ }
const is_ret = if (Zir.refToIndex(zir_dest_type)) |ptr_index|
sema.code.instructions.items(.tag)[ptr_index] == .ret_type
else
false;
- const dest_ty = try sema.resolveType(block, src, zir_dest_type);
- const operand = try sema.resolveInst(zir_operand);
- if (dest_ty.tag() == .var_args_param) return operand;
- if (dest_ty.zigTypeTag() == .NoReturn) {
- return sema.fail(block, src, "cannot cast to noreturn", .{});
- }
return sema.coerceExtra(block, dest_ty, operand, src, .{ .is_ret = is_ret, .no_cast_to_comptime_int = no_cast_to_comptime_int }) catch |err| switch (err) {
error.NotCoercible => unreachable,
else => |e| return e,
@@ -9379,15 +9522,19 @@ fn zirPtrToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ptr = try sema.resolveInst(inst_data.operand);
const ptr_ty = sema.typeOf(ptr);
- if (!ptr_ty.isPtrAtRuntime()) {
- return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)});
+ if (!ptr_ty.isPtrAtRuntime(mod)) {
+ return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(mod)});
}
if (try sema.resolveMaybeUndefValIntable(ptr)) |ptr_val| {
- return sema.addConstant(Type.usize, ptr_val);
+ return sema.addConstant(
+ Type.usize,
+ try mod.intValue(Type.usize, (try ptr_val.getUnsignedIntAdvanced(mod, sema)).?),
+ );
}
try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
return block.addUnOp(.ptrtoint, ptr);
@@ -9397,11 +9544,12 @@ fn zirFieldVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(extra.field_name_start);
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
const object = try sema.resolveInst(extra.lhs);
return sema.fieldVal(block, src, object, field_name, field_name_src);
}
@@ -9410,28 +9558,16 @@ fn zirFieldPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index, initializing: b
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(extra.field_name_start);
+ const field_name = try mod.intern_pool.getOrPutString(sema.gpa, sema.code.nullTerminatedString(extra.field_name_start));
const object_ptr = try sema.resolveInst(extra.lhs);
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, initializing);
}
-fn zirFieldCallBind(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
- const src = inst_data.src();
- const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
- const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(extra.field_name_start);
- const object_ptr = try sema.resolveInst(extra.lhs);
- return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
-}
-
fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -9441,7 +9577,7 @@ fn zirFieldValNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
const object = try sema.resolveInst(extra.lhs);
- const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
+ const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, "field name must be comptime-known");
return sema.fieldVal(block, src, object, field_name, field_name_src);
}
@@ -9454,22 +9590,10 @@ fn zirFieldPtrNamed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.FieldNamed, inst_data.payload_index).data;
const object_ptr = try sema.resolveInst(extra.lhs);
- const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
+ const field_name = try sema.resolveConstStringIntern(block, field_name_src, extra.field_name, "field name must be comptime-known");
return sema.fieldPtr(block, src, object_ptr, field_name, field_name_src, false);
}
-fn zirFieldCallBindNamed(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
- const tracy = trace(@src());
- defer tracy.end();
-
- const extra = sema.code.extraData(Zir.Inst.FieldNamedNode, extended.operand).data;
- const src = LazySrcLoc.nodeOffset(extra.node);
- const field_name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
- const object_ptr = try sema.resolveInst(extra.lhs);
- const field_name = try sema.resolveConstString(block, field_name_src, extra.field_name, "field name must be comptime-known");
- return sema.fieldCallBind(block, src, object_ptr, field_name, field_name_src);
-}
-
fn zirIntCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
@@ -9495,31 +9619,31 @@ fn intCast(
operand_src: LazySrcLoc,
runtime_safety: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
const dest_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, dest_ty, dest_ty_src);
const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
if (try sema.isComptimeKnown(operand)) {
return sema.coerce(block, dest_ty, operand, operand_src);
- } else if (dest_scalar_ty.zigTypeTag() == .ComptimeInt) {
+ } else if (dest_scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_int'", .{});
}
try sema.checkVectorizableBinaryOperands(block, operand_src, dest_ty, operand_ty, dest_ty_src, operand_src);
- const is_vector = dest_ty.zigTypeTag() == .Vector;
+ const is_vector = dest_ty.zigTypeTag(mod) == .Vector;
if ((try sema.typeHasOnePossibleValue(dest_ty))) |opv| {
// requirement: intCast(u0, input) iff input == 0
if (runtime_safety and block.wantSafety()) {
try sema.requireRuntimeBlock(block, src, operand_src);
- const target = sema.mod.getTarget();
- const wanted_info = dest_scalar_ty.intInfo(target);
+ const wanted_info = dest_scalar_ty.intInfo(mod);
const wanted_bits = wanted_info.bits;
if (wanted_bits == 0) {
const ok = if (is_vector) ok: {
- const zeros = try Value.Tag.repeated.create(sema.arena, Value.zero);
- const zero_inst = try sema.addConstant(sema.typeOf(operand), zeros);
+ const zeros = try sema.splat(operand_ty, try mod.intValue(operand_scalar_ty, 0));
+ const zero_inst = try sema.addConstant(operand_ty, zeros);
const is_in_range = try block.addCmpVector(operand, zero_inst, .eq);
const all_in_range = try block.addInst(.{
.tag = .reduce,
@@ -9527,7 +9651,7 @@ fn intCast(
});
break :ok all_in_range;
} else ok: {
- const zero_inst = try sema.addConstant(sema.typeOf(operand), Value.zero);
+ const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0));
const is_in_range = try block.addBinOp(.cmp_lte, operand, zero_inst);
break :ok is_in_range;
};
@@ -9540,9 +9664,8 @@ fn intCast(
try sema.requireRuntimeBlock(block, src, operand_src);
if (runtime_safety and block.wantSafety()) {
- const target = sema.mod.getTarget();
- const actual_info = operand_scalar_ty.intInfo(target);
- const wanted_info = dest_scalar_ty.intInfo(target);
+ const actual_info = operand_scalar_ty.intInfo(mod);
+ const wanted_info = dest_scalar_ty.intInfo(mod);
const actual_bits = actual_info.bits;
const wanted_bits = wanted_info.bits;
const actual_value_bits = actual_bits - @boolToInt(actual_info.signedness == .signed);
@@ -9551,26 +9674,24 @@ fn intCast(
// range shrinkage
// requirement: int value fits into target type
if (wanted_value_bits < actual_value_bits) {
- const dest_max_val_scalar = try dest_scalar_ty.maxInt(sema.arena, target);
- const dest_max_val = if (is_vector)
- try Value.Tag.repeated.create(sema.arena, dest_max_val_scalar)
- else
- dest_max_val_scalar;
+ const dest_max_val_scalar = try dest_scalar_ty.maxIntScalar(mod, operand_scalar_ty);
+ const dest_max_val = try sema.splat(operand_ty, dest_max_val_scalar);
const dest_max = try sema.addConstant(operand_ty, dest_max_val);
const diff = try block.addBinOp(.subwrap, dest_max, operand);
if (actual_info.signedness == .signed) {
// Reinterpret the sign-bit as part of the value. This will make
// negative differences (`operand` > `dest_max`) appear too big.
- const unsigned_operand_ty = try Type.Tag.int_unsigned.create(sema.arena, actual_bits);
+ const unsigned_operand_ty = try mod.intType(.unsigned, actual_bits);
const diff_unsigned = try block.addBitCast(unsigned_operand_ty, diff);
// If the destination type is signed, then we need to double its
// range to account for negative values.
const dest_range_val = if (wanted_info.signedness == .signed) range_val: {
- const range_minus_one = try dest_max_val.shl(Value.one, unsigned_operand_ty, sema.arena, sema.mod);
- break :range_val try sema.intAdd(range_minus_one, Value.one, unsigned_operand_ty);
- } else dest_max_val;
+ const one = try mod.intValue(unsigned_operand_ty, 1);
+ const range_minus_one = try dest_max_val.shl(one, unsigned_operand_ty, sema.arena, mod);
+ break :range_val try sema.intAdd(range_minus_one, one, unsigned_operand_ty, undefined);
+ } else try mod.getCoerced(dest_max_val, unsigned_operand_ty);
const dest_range = try sema.addConstant(unsigned_operand_ty, dest_range_val);
const ok = if (is_vector) ok: {
@@ -9610,7 +9731,8 @@ fn intCast(
// no shrinkage, yes sign loss
// requirement: signed to unsigned >= 0
const ok = if (is_vector) ok: {
- const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
+ const scalar_zero = try mod.intValue(operand_scalar_ty, 0);
+ const zero_val = try sema.splat(operand_ty, scalar_zero);
const zero_inst = try sema.addConstant(operand_ty, zero_val);
const is_in_range = try block.addCmpVector(operand, zero_inst, .gte);
const all_in_range = try block.addInst(.{
@@ -9622,7 +9744,7 @@ fn intCast(
});
break :ok all_in_range;
} else ok: {
- const zero_inst = try sema.addConstant(operand_ty, Value.zero);
+ const zero_inst = try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0));
const is_in_range = try block.addBinOp(.cmp_gte, operand, zero_inst);
break :ok is_in_range;
};
@@ -9636,6 +9758,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
@@ -9644,7 +9767,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
const operand = try sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
- switch (dest_ty.zigTypeTag()) {
+ switch (dest_ty.zigTypeTag(mod)) {
.AnyFrame,
.ComptimeFloat,
.ComptimeInt,
@@ -9660,14 +9783,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.Type,
.Undefined,
.Void,
- => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)}),
+ => return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)}),
.Enum => {
const msg = msg: {
- const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- switch (operand_ty.zigTypeTag()) {
- .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
+ switch (operand_ty.zigTypeTag(mod)) {
+ .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToEnum to cast from '{}'", .{operand_ty.fmt(mod)}),
else => {},
}
@@ -9678,11 +9801,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.Pointer => {
const msg = msg: {
- const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, dest_ty_src, "cannot @bitCast to '{}'", .{dest_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- switch (operand_ty.zigTypeTag()) {
- .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
- .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(sema.mod)}),
+ switch (operand_ty.zigTypeTag(mod)) {
+ .Int, .ComptimeInt => try sema.errNote(block, dest_ty_src, msg, "use @intToPtr to cast from '{}'", .{operand_ty.fmt(mod)}),
+ .Pointer => try sema.errNote(block, dest_ty_src, msg, "use @ptrCast to cast from '{}'", .{operand_ty.fmt(mod)}),
else => {},
}
@@ -9690,14 +9813,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
};
return sema.failWithOwnedErrorMsg(msg);
},
- .Struct, .Union => if (dest_ty.containerLayout() == .Auto) {
- const container = switch (dest_ty.zigTypeTag()) {
+ .Struct, .Union => if (dest_ty.containerLayout(mod) == .Auto) {
+ const container = switch (dest_ty.zigTypeTag(mod)) {
.Struct => "struct",
.Union => "union",
else => unreachable,
};
return sema.fail(block, dest_ty_src, "cannot @bitCast to '{}'; {s} does not have a guaranteed in-memory layout", .{
- dest_ty.fmt(sema.mod), container,
+ dest_ty.fmt(mod), container,
});
},
@@ -9708,7 +9831,7 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.Vector,
=> {},
}
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.AnyFrame,
.ComptimeFloat,
.ComptimeInt,
@@ -9724,14 +9847,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
.Type,
.Undefined,
.Void,
- => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)}),
+ => return sema.fail(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(mod)}),
.Enum => {
const msg = msg: {
- const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- switch (dest_ty.zigTypeTag()) {
- .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
+ switch (dest_ty.zigTypeTag(mod)) {
+ .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @enumToInt to cast to '{}'", .{dest_ty.fmt(mod)}),
else => {},
}
@@ -9741,11 +9864,11 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
},
.Pointer => {
const msg = msg: {
- const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, operand_src, "cannot @bitCast from '{}'", .{operand_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- switch (dest_ty.zigTypeTag()) {
- .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
- .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(sema.mod)}),
+ switch (dest_ty.zigTypeTag(mod)) {
+ .Int, .ComptimeInt => try sema.errNote(block, operand_src, msg, "use @ptrToInt to cast to '{}'", .{dest_ty.fmt(mod)}),
+ .Pointer => try sema.errNote(block, operand_src, msg, "use @ptrCast to cast to '{}'", .{dest_ty.fmt(mod)}),
else => {},
}
@@ -9753,14 +9876,14 @@ fn zirBitcast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
};
return sema.failWithOwnedErrorMsg(msg);
},
- .Struct, .Union => if (operand_ty.containerLayout() == .Auto) {
- const container = switch (operand_ty.zigTypeTag()) {
+ .Struct, .Union => if (operand_ty.containerLayout(mod) == .Auto) {
+ const container = switch (operand_ty.zigTypeTag(mod)) {
.Struct => "struct",
.Union => "union",
else => unreachable,
};
return sema.fail(block, operand_src, "cannot @bitCast from '{}'; {s} does not have a guaranteed in-memory layout", .{
- operand_ty.fmt(sema.mod), container,
+ operand_ty.fmt(mod), container,
});
},
@@ -9778,6 +9901,7 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
@@ -9786,31 +9910,31 @@ fn zirFloatCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
const operand = try sema.resolveInst(extra.rhs);
- const target = sema.mod.getTarget();
- const dest_is_comptime_float = switch (dest_ty.zigTypeTag()) {
+ const target = mod.getTarget();
+ const dest_is_comptime_float = switch (dest_ty.zigTypeTag(mod)) {
.ComptimeFloat => true,
.Float => false,
else => return sema.fail(
block,
dest_ty_src,
"expected float type, found '{}'",
- .{dest_ty.fmt(sema.mod)},
+ .{dest_ty.fmt(mod)},
),
};
const operand_ty = sema.typeOf(operand);
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.ComptimeFloat, .Float, .ComptimeInt => {},
else => return sema.fail(
block,
operand_src,
"expected float type, found '{}'",
- .{operand_ty.fmt(sema.mod)},
+ .{operand_ty.fmt(mod)},
),
}
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
- return sema.addConstant(dest_ty, try operand_val.floatCast(sema.arena, dest_ty, target));
+ return sema.addConstant(dest_ty, try operand_val.floatCast(dest_ty, mod));
}
if (dest_is_comptime_float) {
return sema.fail(block, operand_src, "unable to cast runtime value to 'comptime_float'", .{});
@@ -9853,20 +9977,21 @@ fn zirElemPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const array_ptr = try sema.resolveInst(extra.lhs);
const elem_index = try sema.resolveInst(extra.rhs);
const indexable_ty = sema.typeOf(array_ptr);
- if (indexable_ty.zigTypeTag() != .Pointer) {
+ if (indexable_ty.zigTypeTag(mod) != .Pointer) {
const capture_src: LazySrcLoc = .{ .for_capture_from_input = inst_data.src_node };
const msg = msg: {
const msg = try sema.errMsg(block, capture_src, "pointer capture of non pointer type '{}'", .{
- indexable_ty.fmt(sema.mod),
+ indexable_ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
- if (indexable_ty.zigTypeTag() == .Array) {
+ if (indexable_ty.isIndexable(mod)) {
try sema.errNote(block, src, msg, "consider using '&' here", .{});
}
break :msg msg;
@@ -9914,7 +10039,7 @@ fn zirSliceStart(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
- return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src);
+ return sema.analyzeSlice(block, src, array_ptr, start, .none, .none, .unneeded, ptr_src, start_src, end_src, false);
}
fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -9931,7 +10056,7 @@ fn zirSliceEnd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
- return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src);
+ return sema.analyzeSlice(block, src, array_ptr, start, end, .none, .unneeded, ptr_src, start_src, end_src, false);
}
fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -9944,261 +10069,576 @@ fn zirSliceSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const extra = sema.code.extraData(Zir.Inst.SliceSentinel, inst_data.payload_index).data;
const array_ptr = try sema.resolveInst(extra.lhs);
const start = try sema.resolveInst(extra.start);
- const end = try sema.resolveInst(extra.end);
+ const end: Air.Inst.Ref = if (extra.end == .none) .none else try sema.resolveInst(extra.end);
const sentinel = try sema.resolveInst(extra.sentinel);
const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
const start_src: LazySrcLoc = .{ .node_offset_slice_start = inst_data.src_node };
const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
- return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src);
+ return sema.analyzeSlice(block, src, array_ptr, start, end, sentinel, sentinel_src, ptr_src, start_src, end_src, false);
}
-fn zirSwitchCapture(
- sema: *Sema,
- block: *Block,
- inst: Zir.Inst.Index,
- is_multi: bool,
- is_ref: bool,
-) CompileError!Air.Inst.Ref {
+fn zirSliceLength(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
- const zir_datas = sema.code.instructions.items(.data);
- const capture_info = zir_datas[inst].switch_capture;
- const switch_info = zir_datas[capture_info.switch_inst].pl_node;
- const switch_extra = sema.code.extraData(Zir.Inst.SwitchBlock, switch_info.payload_index);
- const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_info.src_node };
- const cond_inst = Zir.refToIndex(switch_extra.data.operand).?;
- const cond_info = zir_datas[cond_inst].un_node;
- const cond_tag = sema.code.instructions.items(.tag)[cond_inst];
- const operand_is_ref = cond_tag == .switch_cond_ref;
- const operand_ptr = try sema.resolveInst(cond_info.operand);
- const operand_ptr_ty = sema.typeOf(operand_ptr);
- const operand_ty = if (operand_is_ref) operand_ptr_ty.childType() else operand_ptr_ty;
-
- if (block.inline_case_capture != .none) {
- const item_val = sema.resolveConstValue(block, .unneeded, block.inline_case_capture, undefined) catch unreachable;
- if (operand_ty.zigTypeTag() == .Union) {
- const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
- const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
- const field_ty = union_obj.fields.values()[field_index].ty;
- if (try sema.resolveDefinedValue(block, sema.src, operand_ptr)) |union_val| {
- if (is_ref) {
- const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
+ const src = inst_data.src();
+ const extra = sema.code.extraData(Zir.Inst.SliceLength, inst_data.payload_index).data;
+ const array_ptr = try sema.resolveInst(extra.lhs);
+ const start = try sema.resolveInst(extra.start);
+ const len = try sema.resolveInst(extra.len);
+ const sentinel = if (extra.sentinel == .none) .none else try sema.resolveInst(extra.sentinel);
+ const ptr_src: LazySrcLoc = .{ .node_offset_slice_ptr = inst_data.src_node };
+ const start_src: LazySrcLoc = .{ .node_offset_slice_start = extra.start_src_node_offset };
+ const end_src: LazySrcLoc = .{ .node_offset_slice_end = inst_data.src_node };
+ const sentinel_src: LazySrcLoc = if (sentinel == .none)
+ .unneeded
+ else
+ .{ .node_offset_slice_sentinel = inst_data.src_node };
+
+ return sema.analyzeSlice(block, src, array_ptr, start, len, sentinel, sentinel_src, ptr_src, start_src, end_src, true);
+}
+
+/// Holds common data used when analyzing or resolving switch prong bodies,
+/// including setting up captures.
+const SwitchProngAnalysis = struct {
+ sema: *Sema,
+ /// The block containing the `switch_block` itself.
+ parent_block: *Block,
+ /// The raw switch operand value (*not* the condition). Always defined.
+ operand: Air.Inst.Ref,
+ /// May be `undefined` if no prong has a by-ref capture.
+ operand_ptr: Air.Inst.Ref,
+ /// The switch condition value. For unions, `operand` is the union and `cond` is its tag.
+ cond: Air.Inst.Ref,
+ /// If this switch is on an error set, this is the type to assign to the
+ /// `else` prong. If `null`, the prong should be unreachable.
+ else_error_ty: ?Type,
+ /// The index of the `switch_block` instruction itself.
+ switch_block_inst: Zir.Inst.Index,
+ /// The dummy index into which inline tag captures should be placed. May be
+ /// undefined if no prong has a tag capture.
+ tag_capture_inst: Zir.Inst.Index,
+
+ /// Resolve a switch prong which is determined at comptime to have no peers.
+ /// Uses `resolveBlockBody`. Sets up captures as needed.
+ fn resolveProngComptime(
+ spa: SwitchProngAnalysis,
+ child_block: *Block,
+ prong_type: enum { normal, special },
+ prong_body: []const Zir.Inst.Index,
+ capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
+ /// Must use the `scalar_capture`, `special_capture`, or `multi_capture` union field.
+ raw_capture_src: Module.SwitchProngSrc,
+ /// The set of all values which can reach this prong. May be undefined
+ /// if the prong is special or contains ranges.
+ case_vals: []const Air.Inst.Ref,
+ /// The inline capture of this prong. If this is not an inline prong,
+ /// this is `.none`.
+ inline_case_capture: Air.Inst.Ref,
+ /// Whether this prong has an inline tag capture. If `true`, then
+ /// `inline_case_capture` cannot be `.none`.
+ has_tag_capture: bool,
+ merges: *Block.Merges,
+ ) CompileError!Air.Inst.Ref {
+ const sema = spa.sema;
+ const src = sema.code.instructions.items(.data)[spa.switch_block_inst].pl_node.src();
+
+ if (has_tag_capture) {
+ const tag_ref = try spa.analyzeTagCapture(child_block, raw_capture_src, inline_case_capture);
+ sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref);
+ }
+ defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst));
+
+ switch (capture) {
+ .none => {
+ return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
+ },
+
+ .by_val, .by_ref => {
+ const capture_ref = try spa.analyzeCapture(
+ child_block,
+ capture == .by_ref,
+ prong_type == .special,
+ raw_capture_src,
+ case_vals,
+ inline_case_capture,
+ );
+
+ if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
+ // This prong should be unreachable!
+ return Air.Inst.Ref.unreachable_value;
+ }
+
+ sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
+ defer assert(sema.inst_map.remove(spa.switch_block_inst));
+
+ return sema.resolveBlockBody(spa.parent_block, src, child_block, prong_body, spa.switch_block_inst, merges);
+ },
+ }
+ }
+
+ /// Analyze a switch prong which may have peers at runtime.
+ /// Uses `analyzeBodyRuntimeBreak`. Sets up captures as needed.
+ fn analyzeProngRuntime(
+ spa: SwitchProngAnalysis,
+ case_block: *Block,
+ prong_type: enum { normal, special },
+ prong_body: []const Zir.Inst.Index,
+ capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
+ /// Must use the `scalar`, `special`, or `multi_capture` union field.
+ raw_capture_src: Module.SwitchProngSrc,
+ /// The set of all values which can reach this prong. May be undefined
+ /// if the prong is special or contains ranges.
+ case_vals: []const Air.Inst.Ref,
+ /// The inline capture of this prong. If this is not an inline prong,
+ /// this is `.none`.
+ inline_case_capture: Air.Inst.Ref,
+ /// Whether this prong has an inline tag capture. If `true`, then
+ /// `inline_case_capture` cannot be `.none`.
+ has_tag_capture: bool,
+ ) CompileError!void {
+ const sema = spa.sema;
+
+ if (has_tag_capture) {
+ const tag_ref = try spa.analyzeTagCapture(case_block, raw_capture_src, inline_case_capture);
+ sema.inst_map.putAssumeCapacity(spa.tag_capture_inst, tag_ref);
+ }
+ defer if (has_tag_capture) assert(sema.inst_map.remove(spa.tag_capture_inst));
+
+ switch (capture) {
+ .none => {
+ return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
+ },
+
+ .by_val, .by_ref => {
+ const capture_ref = try spa.analyzeCapture(
+ case_block,
+ capture == .by_ref,
+ prong_type == .special,
+ raw_capture_src,
+ case_vals,
+ inline_case_capture,
+ );
+
+ if (sema.typeOf(capture_ref).isNoReturn(sema.mod)) {
+ // No need to analyze any further, the prong is unreachable
+ return;
+ }
+
+ sema.inst_map.putAssumeCapacity(spa.switch_block_inst, capture_ref);
+ defer assert(sema.inst_map.remove(spa.switch_block_inst));
+
+ return sema.analyzeBodyRuntimeBreak(case_block, prong_body);
+ },
+ }
+ }
+
+ fn analyzeTagCapture(
+ spa: SwitchProngAnalysis,
+ block: *Block,
+ raw_capture_src: Module.SwitchProngSrc,
+ inline_case_capture: Air.Inst.Ref,
+ ) CompileError!Air.Inst.Ref {
+ const sema = spa.sema;
+ const mod = sema.mod;
+ const operand_ty = sema.typeOf(spa.operand);
+ if (operand_ty.zigTypeTag(mod) != .Union) {
+ const zir_datas = sema.code.instructions.items(.data);
+ const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
+ const raw_tag_capture_src: Module.SwitchProngSrc = switch (raw_capture_src) {
+ .scalar_capture => |i| .{ .scalar_tag_capture = i },
+ .multi_capture => |i| .{ .multi_tag_capture = i },
+ .special_capture => .special_tag_capture,
+ else => unreachable,
+ };
+ const capture_src = raw_tag_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
+ const msg = msg: {
+ const msg = try sema.errMsg(block, capture_src, "cannot capture tag of non-union type '{}'", .{
+ operand_ty.fmt(mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, operand_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ assert(inline_case_capture != .none);
+ return inline_case_capture;
+ }
+
+ fn analyzeCapture(
+ spa: SwitchProngAnalysis,
+ block: *Block,
+ capture_byref: bool,
+ is_special_prong: bool,
+ raw_capture_src: Module.SwitchProngSrc,
+ case_vals: []const Air.Inst.Ref,
+ inline_case_capture: Air.Inst.Ref,
+ ) CompileError!Air.Inst.Ref {
+ const sema = spa.sema;
+ const mod = sema.mod;
+
+ const zir_datas = sema.code.instructions.items(.data);
+ const switch_node_offset = zir_datas[spa.switch_block_inst].pl_node.src_node;
+
+ const operand_ty = sema.typeOf(spa.operand);
+ const operand_ptr_ty = if (capture_byref) sema.typeOf(spa.operand_ptr) else undefined;
+ const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = switch_node_offset };
+
+ if (inline_case_capture != .none) {
+ const item_val = sema.resolveConstValue(block, .unneeded, inline_case_capture, "") catch unreachable;
+ if (operand_ty.zigTypeTag(mod) == .Union) {
+ const field_index = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, mod).?);
+ const union_obj = mod.typeToUnion(operand_ty).?;
+ const field_ty = union_obj.fields.values()[field_index].ty;
+ if (capture_byref) {
+ const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = field_ty,
- .mutable = operand_ptr_ty.ptrIsMutable(),
- .@"volatile" = operand_ptr_ty.isVolatilePtr(),
- .@"addrspace" = operand_ptr_ty.ptrAddressSpace(),
+ .mutable = operand_ptr_ty.ptrIsMutable(mod),
+ .@"volatile" = operand_ptr_ty.isVolatilePtr(mod),
+ .@"addrspace" = operand_ptr_ty.ptrAddressSpace(mod),
});
- return sema.addConstant(
- ptr_field_ty,
- try Value.Tag.field_ptr.create(sema.arena, .{
- .container_ptr = union_val,
- .container_ty = operand_ty,
- .field_index = field_index,
- }),
- );
+ if (try sema.resolveDefinedValue(block, sema.src, spa.operand_ptr)) |union_ptr| {
+ return sema.addConstant(
+ ptr_field_ty,
+ (try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = union_ptr.toIntern(),
+ .index = field_index,
+ } },
+ } })).toValue(),
+ );
+ }
+ return block.addStructFieldPtr(spa.operand_ptr, field_index, ptr_field_ty);
+ } else {
+ if (try sema.resolveDefinedValue(block, sema.src, spa.operand)) |union_val| {
+ const tag_and_val = mod.intern_pool.indexToKey(union_val.toIntern()).un;
+ return sema.addConstant(field_ty, tag_and_val.val.toValue());
+ }
+ return block.addStructFieldVal(spa.operand, field_index, field_ty);
}
- const tag_and_val = union_val.castTag(.@"union").?.data;
- return sema.addConstant(field_ty, tag_and_val.val);
- }
- if (is_ref) {
- const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = field_ty,
- .mutable = operand_ptr_ty.ptrIsMutable(),
- .@"volatile" = operand_ptr_ty.isVolatilePtr(),
- .@"addrspace" = operand_ptr_ty.ptrAddressSpace(),
- });
- return block.addStructFieldPtr(operand_ptr, field_index, ptr_field_ty);
+ } else if (capture_byref) {
+ return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
} else {
- return block.addStructFieldVal(operand_ptr, field_index, field_ty);
+ return inline_case_capture;
}
- } else if (is_ref) {
- return sema.addConstantMaybeRef(block, operand_ty, item_val, true);
- } else {
- return block.inline_case_capture;
}
- }
- const operand = if (operand_is_ref)
- try sema.analyzeLoad(block, operand_src, operand_ptr, operand_src)
- else
- operand_ptr;
+ if (is_special_prong) {
+ if (capture_byref) {
+ return spa.operand_ptr;
+ }
- if (capture_info.prong_index == std.math.maxInt(@TypeOf(capture_info.prong_index))) {
- // It is the else/`_` prong.
- if (is_ref) {
- return operand_ptr;
+ switch (operand_ty.zigTypeTag(mod)) {
+ .ErrorSet => if (spa.else_error_ty) |ty| {
+ return sema.bitCast(block, ty, spa.operand, operand_src, null);
+ } else {
+ try block.addUnreachable(false);
+ return Air.Inst.Ref.unreachable_value;
+ },
+ else => return spa.operand,
+ }
}
- switch (operand_ty.zigTypeTag()) {
- .ErrorSet => if (block.switch_else_err_ty) |some| {
- return sema.bitCast(block, some, operand, operand_src, null);
- } else {
- try block.addUnreachable(false);
- return Air.Inst.Ref.unreachable_value;
- },
- else => return operand,
- }
- }
+ switch (operand_ty.zigTypeTag(mod)) {
+ .Union => {
+ const union_obj = mod.typeToUnion(operand_ty).?;
+ const first_item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
- const items = if (is_multi)
- switch_extra.data.getMultiProng(sema.code, switch_extra.end, capture_info.prong_index).items
- else
- &[_]Zir.Inst.Ref{
- switch_extra.data.getScalarProng(sema.code, switch_extra.end, capture_info.prong_index).item,
- };
+ const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, mod).?);
+ const first_field = union_obj.fields.values()[first_field_index];
- switch (operand_ty.zigTypeTag()) {
- .Union => {
- const union_obj = operand_ty.cast(Type.Payload.Union).?.data;
- const first_item = try sema.resolveInst(items[0]);
- // Previous switch validation ensured this will succeed
- const first_item_val = sema.resolveConstValue(block, .unneeded, first_item, "") catch unreachable;
-
- const first_field_index = @intCast(u32, operand_ty.unionTagFieldIndex(first_item_val, sema.mod).?);
- const first_field = union_obj.fields.values()[first_field_index];
-
- for (items[1..], 0..) |item, i| {
- const item_ref = try sema.resolveInst(item);
- // Previous switch validation ensured this will succeed
- const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
-
- const field_index = operand_ty.unionTagFieldIndex(item_val, sema.mod).?;
- const field = union_obj.fields.values()[field_index];
- if (!field.ty.eql(first_field.ty, sema.mod)) {
- const msg = msg: {
- const raw_capture_src = Module.SwitchProngSrc{ .multi_capture = capture_info.prong_index };
- const capture_src = raw_capture_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
+ const field_tys = try sema.arena.alloc(Type, case_vals.len);
+ for (case_vals, field_tys) |item, *field_ty| {
+ const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
+ const field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(item_val, sema.mod).?);
+ field_ty.* = union_obj.fields.values()[field_idx].ty;
+ }
- const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
- errdefer msg.destroy(sema.gpa);
+ // Fast path: if all the operands are the same type already, we don't need to hit
+ // PTR! This will also allow us to emit simpler code.
+ const same_types = for (field_tys[1..]) |field_ty| {
+ if (!field_ty.eql(field_tys[0], sema.mod)) break false;
+ } else true;
- const raw_first_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 0 } };
- const first_item_src = raw_first_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
- const raw_item_src = Module.SwitchProngSrc{ .multi = .{ .prong = capture_info.prong_index, .item = 1 + @intCast(u32, i) } };
- const item_src = raw_item_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_info.src_node, .first);
- try sema.errNote(block, first_item_src, msg, "type '{}' here", .{first_field.ty.fmt(sema.mod)});
- try sema.errNote(block, item_src, msg, "type '{}' here", .{field.ty.fmt(sema.mod)});
- break :msg msg;
+ const capture_ty = if (same_types) field_tys[0] else capture_ty: {
+ // We need values to run PTR on, so make a bunch of undef constants.
+ const dummy_captures = try sema.arena.alloc(Air.Inst.Ref, case_vals.len);
+ for (dummy_captures, field_tys) |*dummy, field_ty| {
+ dummy.* = try sema.addConstUndef(field_ty);
+ }
+
+ const case_srcs = try sema.arena.alloc(?LazySrcLoc, case_vals.len);
+ @memset(case_srcs, .unneeded);
+
+ break :capture_ty sema.resolvePeerTypes(block, .unneeded, dummy_captures, .{ .override = case_srcs }) catch |err| switch (err) {
+ error.NeededSourceLocation => {
+ // This must be a multi-prong so this must be a `multi_capture` src
+ const multi_idx = raw_capture_src.multi_capture;
+ const src_decl_ptr = sema.mod.declPtr(block.src_decl);
+ for (case_srcs, 0..) |*case_src, i| {
+ const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, i) } };
+ case_src.* = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
+ }
+ const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
+ _ = sema.resolvePeerTypes(block, capture_src, dummy_captures, .{ .override = case_srcs }) catch |err1| switch (err1) {
+ error.AnalysisFail => {
+ const msg = sema.err orelse return error.AnalysisFail;
+ try sema.reparentOwnedErrorMsg(block, capture_src, msg, "capture group with incompatible types", .{});
+ return error.AnalysisFail;
+ },
+ else => |e| return e,
+ };
+ unreachable;
+ },
+ else => |e| return e,
};
- return sema.failWithOwnedErrorMsg(msg);
- }
- }
+ };
- if (is_ref) {
- const field_ty_ptr = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = first_field.ty,
- .@"addrspace" = .generic,
- .mutable = operand_ptr_ty.ptrIsMutable(),
- });
+ // By-reference captures have some further restrictions which make them easier to emit
+ if (capture_byref) {
+ const operand_ptr_info = operand_ptr_ty.ptrInfo(mod);
+ const capture_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ .pointee_type = capture_ty,
+ .@"addrspace" = operand_ptr_info.@"addrspace",
+ .mutable = operand_ptr_info.mutable,
+ .@"volatile" = operand_ptr_info.@"volatile",
+ // TODO: alignment!
+ });
- if (try sema.resolveDefinedValue(block, operand_src, operand_ptr)) |op_ptr_val| {
- return sema.addConstant(
- field_ty_ptr,
- try Value.Tag.field_ptr.create(sema.arena, .{
- .container_ptr = op_ptr_val,
- .container_ty = operand_ty,
- .field_index = first_field_index,
- }),
- );
+ // By-ref captures of hetereogeneous types are only allowed if each field
+ // pointer type is in-memory coercible to the capture pointer type.
+ if (!same_types) {
+ for (field_tys, 0..) |field_ty, i| {
+ const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ .pointee_type = field_ty,
+ .@"addrspace" = operand_ptr_info.@"addrspace",
+ .mutable = operand_ptr_info.mutable,
+ .@"volatile" = operand_ptr_info.@"volatile",
+ // TODO: alignment!
+ });
+ if (.ok != try sema.coerceInMemoryAllowed(block, capture_ptr_ty, field_ptr_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
+ const multi_idx = raw_capture_src.multi_capture;
+ const src_decl_ptr = sema.mod.declPtr(block.src_decl);
+ const capture_src = raw_capture_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
+ const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, i) } };
+ const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
+ const msg = msg: {
+ const msg = try sema.errMsg(block, capture_src, "capture group with incompatible types", .{});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, case_src, msg, "pointer type child '{}' cannot cast into resolved pointer type child '{}'", .{
+ field_ty.fmt(sema.mod),
+ capture_ty.fmt(sema.mod),
+ });
+ try sema.errNote(block, capture_src, msg, "this coercion is only possible when capturing by value", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ }
+ }
+
+ if (try sema.resolveDefinedValue(block, operand_src, spa.operand_ptr)) |op_ptr_val| {
+ if (op_ptr_val.isUndef(mod)) return sema.addConstUndef(capture_ptr_ty);
+ return sema.addConstant(
+ capture_ptr_ty,
+ (try mod.intern(.{ .ptr = .{
+ .ty = capture_ptr_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = op_ptr_val.toIntern(),
+ .index = first_field_index,
+ } },
+ } })).toValue(),
+ );
+ }
+
+ try sema.requireRuntimeBlock(block, operand_src, null);
+ return block.addStructFieldPtr(spa.operand_ptr, first_field_index, capture_ptr_ty);
+ }
+
+ if (try sema.resolveDefinedValue(block, operand_src, spa.operand)) |operand_val| {
+ if (operand_val.isUndef(mod)) return sema.addConstUndef(capture_ty);
+ const union_val = mod.intern_pool.indexToKey(operand_val.toIntern()).un;
+ if (union_val.tag.toValue().isUndef(mod)) return sema.addConstUndef(capture_ty);
+ const active_field_idx = @intCast(u32, operand_ty.unionTagFieldIndex(union_val.tag.toValue(), sema.mod).?);
+ const field_ty = union_obj.fields.values()[active_field_idx].ty;
+ const uncoerced = try sema.addConstant(field_ty, union_val.val.toValue());
+ return sema.coerce(block, capture_ty, uncoerced, operand_src);
}
+
try sema.requireRuntimeBlock(block, operand_src, null);
- return block.addStructFieldPtr(operand_ptr, first_field_index, field_ty_ptr);
- }
- if (try sema.resolveDefinedValue(block, operand_src, operand)) |operand_val| {
- return sema.addConstant(
- first_field.ty,
- operand_val.castTag(.@"union").?.data.val,
- );
- }
- try sema.requireRuntimeBlock(block, operand_src, null);
- return block.addStructFieldVal(operand, first_field_index, first_field.ty);
- },
- .ErrorSet => {
- if (is_multi) {
- var names: Module.ErrorSet.NameMap = .{};
- try names.ensureUnusedCapacity(sema.arena, items.len);
- for (items) |item| {
- const item_ref = try sema.resolveInst(item);
- // Previous switch validation ensured this will succeed
- const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
- names.putAssumeCapacityNoClobber(
- item_val.getError().?,
- {},
- );
+ if (same_types) {
+ return block.addStructFieldVal(spa.operand, first_field_index, capture_ty);
}
- // names must be sorted
- Module.ErrorSet.sortNames(&names);
- const else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
- return sema.bitCast(block, else_error_ty, operand, operand_src, null);
- } else {
- const item_ref = try sema.resolveInst(items[0]);
- // Previous switch validation ensured this will succeed
- const item_val = sema.resolveConstValue(block, .unneeded, item_ref, "") catch unreachable;
+ // We may have to emit a switch block which coerces the operand to the capture type.
+ // If we can, try to avoid that using in-memory coercions.
+ const first_non_imc = in_mem: {
+ for (field_tys, 0..) |field_ty, i| {
+ if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
+ break :in_mem i;
+ }
+ }
+ // All fields are in-memory coercible to the resolved type!
+ // Just take the first field and bitcast the result.
+ const uncoerced = try block.addStructFieldVal(spa.operand, first_field_index, first_field.ty);
+ return block.addBitCast(capture_ty, uncoerced);
+ };
- const item_ty = try Type.Tag.error_set_single.create(sema.arena, item_val.getError().?);
- return sema.bitCast(block, item_ty, operand, operand_src, null);
- }
- },
- else => {
- // In this case the capture value is just the passed-through value of the
- // switch condition.
- if (is_ref) {
- return operand_ptr;
- } else {
- return operand;
- }
- },
- }
-}
+ // By-val capture with heterogeneous types which are not all in-memory coercible to
+ // the resolved capture type. We finally have to fall back to the ugly method.
-fn zirSwitchCaptureTag(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
- const zir_datas = sema.code.instructions.items(.data);
- const inst_data = zir_datas[inst].un_tok;
- const src = inst_data.src();
+ // However, let's first track which operands are in-memory coercible. There may well
+ // be several, and we can squash all of these cases into the same switch prong using
+ // a simple bitcast. We'll make this the 'else' prong.
- const switch_tag = sema.code.instructions.items(.tag)[Zir.refToIndex(inst_data.operand).?];
- const is_ref = switch_tag == .switch_cond_ref;
- const cond_data = zir_datas[Zir.refToIndex(inst_data.operand).?].un_node;
- const operand_ptr = try sema.resolveInst(cond_data.operand);
- const operand_ptr_ty = sema.typeOf(operand_ptr);
- const operand_ty = if (is_ref) operand_ptr_ty.childType() else operand_ptr_ty;
+ var in_mem_coercible = try std.DynamicBitSet.initFull(sema.arena, field_tys.len);
+ in_mem_coercible.unset(first_non_imc);
+ {
+ const next = first_non_imc + 1;
+ for (field_tys[next..], next..) |field_ty, i| {
+ if (.ok != try sema.coerceInMemoryAllowed(block, capture_ty, field_ty, false, sema.mod.getTarget(), .unneeded, .unneeded)) {
+ in_mem_coercible.unset(i);
+ }
+ }
+ }
- if (operand_ty.zigTypeTag() != .Union) {
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "cannot capture tag of non-union type '{}'", .{
- operand_ty.fmt(sema.mod),
- });
- errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, operand_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(msg);
- }
+ const capture_block_inst = try block.addInstAsIndex(.{
+ .tag = .block,
+ .data = .{
+ .ty_pl = .{
+ .ty = try sema.addType(capture_ty),
+ .payload = undefined, // updated below
+ },
+ },
+ });
- return block.inline_case_capture;
-}
+ const prong_count = field_tys.len - in_mem_coercible.count();
+
+ const estimated_extra = prong_count * 6; // 2 for Case, 1 item, probably 3 insts
+ var cases_extra = try std.ArrayList(u32).initCapacity(sema.gpa, estimated_extra);
+ defer cases_extra.deinit();
+
+ {
+ // Non-bitcast cases
+ var it = in_mem_coercible.iterator(.{ .kind = .unset });
+ while (it.next()) |idx| {
+ var coerce_block = block.makeSubBlock();
+ defer coerce_block.instructions.deinit(sema.gpa);
+
+ const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(u32, idx), field_tys[idx]);
+ const coerced = sema.coerce(&coerce_block, capture_ty, uncoerced, .unneeded) catch |err| switch (err) {
+ error.NeededSourceLocation => {
+ const multi_idx = raw_capture_src.multi_capture;
+ const src_decl_ptr = sema.mod.declPtr(block.src_decl);
+ const raw_case_src: Module.SwitchProngSrc = .{ .multi = .{ .prong = multi_idx, .item = @intCast(u32, idx) } };
+ const case_src = raw_case_src.resolve(mod, src_decl_ptr, switch_node_offset, .none);
+ _ = try sema.coerce(&coerce_block, capture_ty, uncoerced, case_src);
+ unreachable;
+ },
+ else => |e| return e,
+ };
+ _ = try coerce_block.addBr(capture_block_inst, coerced);
+
+ try cases_extra.ensureUnusedCapacity(3 + coerce_block.instructions.items.len);
+ cases_extra.appendAssumeCapacity(1); // items_len
+ cases_extra.appendAssumeCapacity(@intCast(u32, coerce_block.instructions.items.len)); // body_len
+ cases_extra.appendAssumeCapacity(@enumToInt(case_vals[idx])); // item
+ cases_extra.appendSliceAssumeCapacity(coerce_block.instructions.items); // body
+ }
+ }
+ const else_body_len = len: {
+ // 'else' prong uses a bitcast
+ var coerce_block = block.makeSubBlock();
+ defer coerce_block.instructions.deinit(sema.gpa);
+
+ const first_imc = in_mem_coercible.findFirstSet().?;
+ const uncoerced = try coerce_block.addStructFieldVal(spa.operand, @intCast(u32, first_imc), field_tys[first_imc]);
+ const coerced = try coerce_block.addBitCast(capture_ty, uncoerced);
+ _ = try coerce_block.addBr(capture_block_inst, coerced);
+
+ try cases_extra.appendSlice(coerce_block.instructions.items);
+ break :len coerce_block.instructions.items.len;
+ };
+
+ try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.SwitchBr).Struct.fields.len +
+ cases_extra.items.len +
+ @typeInfo(Air.Block).Struct.fields.len +
+ 1);
+
+ const switch_br_inst = @intCast(u32, sema.air_instructions.len);
+ try sema.air_instructions.append(sema.gpa, .{
+ .tag = .switch_br,
+ .data = .{ .pl_op = .{
+ .operand = spa.cond,
+ .payload = sema.addExtraAssumeCapacity(Air.SwitchBr{
+ .cases_len = @intCast(u32, prong_count),
+ .else_body_len = @intCast(u32, else_body_len),
+ }),
+ } },
+ });
+ sema.air_extra.appendSliceAssumeCapacity(cases_extra.items);
+
+ // Set up block body
+ sema.air_instructions.items(.data)[capture_block_inst].ty_pl.payload = sema.addExtraAssumeCapacity(Air.Block{
+ .body_len = 1,
+ });
+ sema.air_extra.appendAssumeCapacity(switch_br_inst);
+
+ return Air.indexToRef(capture_block_inst);
+ },
+ .ErrorSet => {
+ if (capture_byref) {
+ const capture_src = raw_capture_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, .none);
+ return sema.fail(
+ block,
+ capture_src,
+ "error set cannot be captured by reference",
+ .{},
+ );
+ }
+
+ if (case_vals.len == 1) {
+ const item_val = sema.resolveConstValue(block, .unneeded, case_vals[0], "") catch unreachable;
+ const item_ty = try mod.singleErrorSetType(item_val.getErrorName(mod).unwrap().?);
+ return sema.bitCast(block, item_ty, spa.operand, operand_src, null);
+ }
+
+ var names: Module.Fn.InferredErrorSet.NameMap = .{};
+ try names.ensureUnusedCapacity(sema.arena, case_vals.len);
+ for (case_vals) |err| {
+ const err_val = sema.resolveConstValue(block, .unneeded, err, "") catch unreachable;
+ names.putAssumeCapacityNoClobber(err_val.getErrorName(mod).unwrap().?, {});
+ }
+ const error_ty = try mod.errorSetFromUnsortedNames(names.keys());
+ return sema.bitCast(block, error_ty, spa.operand, operand_src, null);
+ },
+ else => {
+ // In this case the capture value is just the passed-through value
+ // of the switch condition.
+ if (capture_byref) {
+ return spa.operand_ptr;
+ } else {
+ return spa.operand;
+ }
+ },
+ }
+ }
+};
-fn zirSwitchCond(
+fn switchCond(
sema: *Sema,
block: *Block,
- inst: Zir.Inst.Index,
- is_ref: bool,
+ src: LazySrcLoc,
+ operand: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
- const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const src = inst_data.src();
- const operand_src: LazySrcLoc = .{ .node_offset_switch_operand = inst_data.src_node };
- const operand_ptr = try sema.resolveInst(inst_data.operand);
- const operand = if (is_ref)
- try sema.analyzeLoad(block, src, operand_ptr, operand_src)
- else
- operand_ptr;
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
-
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.Type,
.Void,
.Bool,
@@ -10212,8 +10652,8 @@ fn zirSwitchCond(
.ErrorSet,
.Enum,
=> {
- if (operand_ty.isSlice()) {
- return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)});
+ if (operand_ty.isSlice(mod)) {
+ return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(mod)});
}
if ((try sema.typeHasOnePossibleValue(operand_ty))) |opv| {
return sema.addConstant(operand_ty, opv);
@@ -10223,12 +10663,12 @@ fn zirSwitchCond(
.Union => {
const union_ty = try sema.resolveTypeFields(operand_ty);
- const enum_ty = union_ty.unionTagType() orelse {
+ const enum_ty = union_ty.unionTagType(mod) orelse {
const msg = msg: {
const msg = try sema.errMsg(block, src, "switch on union with no attached enum", .{});
errdefer msg.destroy(sema.gpa);
- if (union_ty.declSrcLocOrNull(sema.mod)) |union_src| {
- try sema.mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{});
+ if (union_ty.declSrcLocOrNull(mod)) |union_src| {
+ try mod.errNoteNonLazy(union_src, msg, "consider 'union(enum)' here", .{});
}
break :msg msg;
};
@@ -10248,17 +10688,19 @@ fn zirSwitchCond(
.Vector,
.Frame,
.AnyFrame,
- => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(sema.mod)}),
+ => return sema.fail(block, src, "switch on type '{}'", .{operand_ty.fmt(mod)}),
}
}
-const SwitchErrorSet = std.StringHashMap(Module.SwitchProngSrc);
+const SwitchErrorSet = std.AutoHashMap(InternPool.NullTerminatedString, Module.SwitchProngSrc);
-fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index, operand_is_ref: bool) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const src_node_offset = inst_data.src_node;
@@ -10266,10 +10708,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const special_prong_src: LazySrcLoc = .{ .node_offset_switch_special_prong = src_node_offset };
const extra = sema.code.extraData(Zir.Inst.SwitchBlock, inst_data.payload_index);
- const operand = try sema.resolveInst(extra.data.operand);
- // AstGen guarantees that the instruction immediately following
- // switch_cond(_ref) is a dbg_stmt
- const cond_dbg_node_index = Zir.refToIndex(extra.data.operand).? + 1;
+ const raw_operand: struct { val: Air.Inst.Ref, ptr: Air.Inst.Ref } = blk: {
+ const maybe_ptr = try sema.resolveInst(extra.data.operand);
+ if (operand_is_ref) {
+ const val = try sema.analyzeLoad(block, src, maybe_ptr, operand_src);
+ break :blk .{ .val = val, .ptr = maybe_ptr };
+ } else {
+ break :blk .{ .val = maybe_ptr, .ptr = undefined };
+ }
+ };
+
+ const operand = try sema.switchCond(block, operand_src, raw_operand.val);
+
+ // AstGen guarantees that the instruction immediately preceding
+ // switch_block(_ref) is a dbg_stmt
+ const cond_dbg_node_index = inst - 1;
var header_extra_index: usize = extra.end;
@@ -10280,34 +10733,56 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
break :blk multi_cases_len;
} else 0;
+ const tag_capture_inst: Zir.Inst.Index = if (extra.data.bits.any_has_tag_capture) blk: {
+ const tag_capture_inst = sema.code.extra[header_extra_index];
+ header_extra_index += 1;
+ // SwitchProngAnalysis wants inst_map to have space for the tag capture.
+ // Note that the normal capture is referred to via the switch block
+ // index, which there is already necessarily space for.
+ try sema.inst_map.ensureSpaceForInstructions(gpa, &.{tag_capture_inst});
+ break :blk tag_capture_inst;
+ } else undefined;
+
+ var case_vals = try std.ArrayListUnmanaged(Air.Inst.Ref).initCapacity(gpa, scalar_cases_len + 2 * multi_cases_len);
+ defer case_vals.deinit(gpa);
+
+ const Special = struct {
+ body: []const Zir.Inst.Index,
+ end: usize,
+ capture: Zir.Inst.SwitchBlock.ProngInfo.Capture,
+ is_inline: bool,
+ has_tag_capture: bool,
+ };
+
const special_prong = extra.data.bits.specialProng();
- const special: struct { body: []const Zir.Inst.Index, end: usize, is_inline: bool } = switch (special_prong) {
- .none => .{ .body = &.{}, .end = header_extra_index, .is_inline = false },
+ const special: Special = switch (special_prong) {
+ .none => .{
+ .body = &.{},
+ .end = header_extra_index,
+ .capture = .none,
+ .is_inline = false,
+ .has_tag_capture = false,
+ },
.under, .@"else" => blk: {
- const body_len = @truncate(u31, sema.code.extra[header_extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[header_extra_index]);
const extra_body_start = header_extra_index + 1;
break :blk .{
- .body = sema.code.extra[extra_body_start..][0..body_len],
- .end = extra_body_start + body_len,
- .is_inline = sema.code.extra[header_extra_index] >> 31 != 0,
+ .body = sema.code.extra[extra_body_start..][0..info.body_len],
+ .end = extra_body_start + info.body_len,
+ .capture = info.capture,
+ .is_inline = info.is_inline,
+ .has_tag_capture = info.has_tag_capture,
};
},
};
- const maybe_union_ty = blk: {
- const zir_tags = sema.code.instructions.items(.tag);
- const zir_data = sema.code.instructions.items(.data);
- const cond_index = Zir.refToIndex(extra.data.operand).?;
- const raw_operand = sema.resolveInst(zir_data[cond_index].un_node.operand) catch unreachable;
- const target_ty = sema.typeOf(raw_operand);
- break :blk if (zir_tags[cond_index] == .switch_cond_ref) target_ty.elemType() else target_ty;
- };
- const union_originally = maybe_union_ty.zigTypeTag() == .Union;
+ const maybe_union_ty = sema.typeOf(raw_operand.val);
+ const union_originally = maybe_union_ty.zigTypeTag(mod) == .Union;
// Duplicate checking variables later also used for `inline else`.
var seen_enum_fields: []?Module.SwitchProngSrc = &.{};
var seen_errors = SwitchErrorSet.init(gpa);
- var range_set = RangeSet.init(gpa, sema.mod);
+ var range_set = RangeSet.init(gpa, mod);
var true_count: u8 = 0;
var false_count: u8 = 0;
@@ -10320,12 +10795,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var empty_enum = false;
const operand_ty = sema.typeOf(operand);
- const err_set = operand_ty.zigTypeTag() == .ErrorSet;
+ const err_set = operand_ty.zigTypeTag(mod) == .ErrorSet;
var else_error_ty: ?Type = null;
// Validate usage of '_' prongs.
- if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum() or union_originally)) {
+ if (special_prong == .under and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally)) {
const msg = msg: {
const msg = try sema.errMsg(
block,
@@ -10346,14 +10821,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return sema.failWithOwnedErrorMsg(msg);
}
- const target = sema.mod.getTarget();
-
// Validate for duplicate items, missing else prong, and invalid range.
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.Union => unreachable, // handled in zirSwitchCond
.Enum => {
- seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount());
- empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum();
+ seen_enum_fields = try gpa.alloc(?Module.SwitchProngSrc, operand_ty.enumFieldCount(mod));
+ empty_enum = seen_enum_fields.len == 0 and !operand_ty.isNonexhaustiveEnum(mod);
@memset(seen_enum_fields, null);
// `range_set` is used for non-exhaustive enum values that do not correspond to any tags.
@@ -10363,18 +10836,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- extra_index += 1;
- extra_index += body_len;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
+ extra_index += 1 + info.body_len;
- try sema.validateSwitchItemEnum(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
block,
seen_enum_fields,
&range_set,
item_ref,
+ operand_ty,
src_node_offset,
.{ .scalar = scalar_i },
- );
+ ));
}
}
{
@@ -10384,20 +10857,22 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
const items = sema.code.refSlice(extra_index, items_len);
- extra_index += items_len + body_len;
+ extra_index += items_len + info.body_len;
+ try case_vals.ensureUnusedCapacity(gpa, items.len);
for (items, 0..) |item_ref, item_i| {
- try sema.validateSwitchItemEnum(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemEnum(
block,
seen_enum_fields,
&range_set,
item_ref,
+ operand_ty,
src_node_offset,
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
- );
+ ));
}
try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
@@ -10408,7 +10883,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
} else true;
if (special_prong == .@"else") {
- if (all_tags_handled and !operand_ty.isNonexhaustiveEnum()) return sema.fail(
+ if (all_tags_handled and !operand_ty.isNonexhaustiveEnum(mod)) return sema.fail(
block,
special_prong_src,
"unreachable else prong; all cases already handled",
@@ -10426,25 +10901,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
for (seen_enum_fields, 0..) |seen_src, i| {
if (seen_src != null) continue;
- const field_name = operand_ty.enumFieldName(i);
+ const field_name = operand_ty.enumFieldName(i, mod);
try sema.addFieldErrNote(
operand_ty,
i,
msg,
- "unhandled enumeration value: '{s}'",
- .{field_name},
+ "unhandled enumeration value: '{}'",
+ .{field_name.fmt(&mod.intern_pool)},
);
}
- try sema.mod.errNoteNonLazy(
- operand_ty.declSrcLoc(sema.mod),
+ try mod.errNoteNonLazy(
+ operand_ty.declSrcLoc(mod),
msg,
"enum '{}' declared here",
- .{operand_ty.fmt(sema.mod)},
+ .{operand_ty.fmt(mod)},
);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum() and !union_originally) {
+ } else if (special_prong == .none and operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
return sema.fail(
block,
src,
@@ -10460,17 +10935,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- extra_index += 1;
- extra_index += body_len;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
+ extra_index += 1 + info.body_len;
- try sema.validateSwitchItemError(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
block,
&seen_errors,
item_ref,
+ operand_ty,
src_node_offset,
.{ .scalar = scalar_i },
- );
+ ));
}
}
{
@@ -10480,19 +10955,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
const items = sema.code.refSlice(extra_index, items_len);
- extra_index += items_len + body_len;
+ extra_index += items_len + info.body_len;
+ try case_vals.ensureUnusedCapacity(gpa, items.len);
for (items, 0..) |item_ref, item_i| {
- try sema.validateSwitchItemError(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemError(
block,
&seen_errors,
item_ref,
+ operand_ty,
src_node_offset,
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
- );
+ ));
}
try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
@@ -10501,7 +10978,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
try sema.resolveInferredErrorSetTy(block, src, operand_ty);
- if (operand_ty.isAnyError()) {
+ if (operand_ty.isAnyError(mod)) {
if (special_prong != .@"else") {
return sema.fail(
block,
@@ -10515,7 +10992,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var maybe_msg: ?*Module.ErrorMsg = null;
errdefer if (maybe_msg) |msg| msg.destroy(sema.gpa);
- for (operand_ty.errorSetNames()) |error_name| {
+ for (operand_ty.errorSetNames(mod)) |error_name| {
if (!seen_errors.contains(error_name) and special_prong != .@"else") {
const msg = maybe_msg orelse blk: {
maybe_msg = try sema.errMsg(
@@ -10531,8 +11008,8 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
block,
src,
msg,
- "unhandled error value: 'error.{s}'",
- .{error_name},
+ "unhandled error value: 'error.{}'",
+ .{error_name.fmt(ip)},
);
}
}
@@ -10543,7 +11020,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
return sema.failWithOwnedErrorMsg(msg);
}
- if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames().len) {
+ if (special_prong == .@"else" and seen_errors.count() == operand_ty.errorSetNames(mod).len) {
// In order to enable common patterns for generic code allow simple else bodies
// else => unreachable,
// else => return,
@@ -10555,7 +11032,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
.dbg_block_end,
.dbg_stmt,
.dbg_var_val,
- .switch_capture,
.ret_type,
.as_node,
.ret_node,
@@ -10580,18 +11056,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
);
}
- const error_names = operand_ty.errorSetNames();
- var names: Module.ErrorSet.NameMap = .{};
+ const error_names = operand_ty.errorSetNames(mod);
+ var names: Module.Fn.InferredErrorSet.NameMap = .{};
try names.ensureUnusedCapacity(sema.arena, error_names.len);
for (error_names) |error_name| {
if (seen_errors.contains(error_name)) continue;
names.putAssumeCapacityNoClobber(error_name, {});
}
-
- // names must be sorted
- Module.ErrorSet.sortNames(&names);
- else_error_ty = try Type.Tag.error_set_merged.create(sema.arena, names);
+ // No need to keep the hash map metadata correct; here we
+ // extract the (sorted) keys only.
+ else_error_ty = try mod.errorSetFromUnsortedNames(names.keys());
}
},
.Int, .ComptimeInt => {
@@ -10601,18 +11076,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- extra_index += 1;
- extra_index += body_len;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
+ extra_index += 1 + info.body_len;
- try sema.validateSwitchItem(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
block,
&range_set,
item_ref,
operand_ty,
src_node_offset,
.{ .scalar = scalar_i },
- );
+ ));
}
}
{
@@ -10622,22 +11096,24 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
const items = sema.code.refSlice(extra_index, items_len);
extra_index += items_len;
+ try case_vals.ensureUnusedCapacity(gpa, items.len);
for (items, 0..) |item_ref, item_i| {
- try sema.validateSwitchItem(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemInt(
block,
&range_set,
item_ref,
operand_ty,
src_node_offset,
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
- );
+ ));
}
+ try case_vals.ensureUnusedCapacity(gpa, 2 * ranges_len);
var range_i: u32 = 0;
while (range_i < ranges_len) : (range_i += 1) {
const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
@@ -10645,7 +11121,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- try sema.validateSwitchRange(
+ const vals = try sema.validateSwitchRange(
block,
&range_set,
item_first,
@@ -10654,20 +11130,19 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
src_node_offset,
.{ .range = .{ .prong = multi_i, .item = range_i } },
);
+ case_vals.appendAssumeCapacity(vals[0]);
+ case_vals.appendAssumeCapacity(vals[1]);
}
- extra_index += body_len;
+ extra_index += info.body_len;
}
}
check_range: {
- if (operand_ty.zigTypeTag() == .Int) {
- var arena = std.heap.ArenaAllocator.init(gpa);
- defer arena.deinit();
-
- const min_int = try operand_ty.minInt(arena.allocator(), target);
- const max_int = try operand_ty.maxInt(arena.allocator(), target);
- if (try range_set.spans(min_int, max_int, operand_ty)) {
+ if (operand_ty.zigTypeTag(mod) == .Int) {
+ const min_int = try operand_ty.minInt(mod, operand_ty);
+ const max_int = try operand_ty.maxInt(mod, operand_ty);
+ if (try range_set.spans(min_int.toIntern(), max_int.toIntern())) {
if (special_prong == .@"else") {
return sema.fail(
block,
@@ -10696,18 +11171,17 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- extra_index += 1;
- extra_index += body_len;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
+ extra_index += 1 + info.body_len;
- try sema.validateSwitchItemBool(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
block,
&true_count,
&false_count,
item_ref,
src_node_offset,
.{ .scalar = scalar_i },
- );
+ ));
}
}
{
@@ -10717,20 +11191,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
const items = sema.code.refSlice(extra_index, items_len);
- extra_index += items_len + body_len;
+ extra_index += items_len + info.body_len;
+ try case_vals.ensureUnusedCapacity(gpa, items.len);
for (items, 0..) |item_ref, item_i| {
- try sema.validateSwitchItemBool(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemBool(
block,
&true_count,
&false_count,
item_ref,
src_node_offset,
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
- );
+ ));
}
try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
@@ -10765,15 +11240,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
block,
src,
"else prong required when switching on type '{}'",
- .{operand_ty.fmt(sema.mod)},
+ .{operand_ty.fmt(mod)},
);
}
- var seen_values = ValueSrcMap.initContext(gpa, .{
- .ty = operand_ty,
- .mod = sema.mod,
- });
- defer seen_values.deinit();
+ var seen_values = ValueSrcMap{};
+ defer seen_values.deinit(gpa);
var extra_index: usize = special.end;
{
@@ -10781,17 +11253,18 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
- extra_index += body_len;
+ extra_index += info.body_len;
- try sema.validateSwitchItemSparse(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
block,
&seen_values,
item_ref,
+ operand_ty,
src_node_offset,
.{ .scalar = scalar_i },
- );
+ ));
}
}
{
@@ -10801,19 +11274,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
const items = sema.code.refSlice(extra_index, items_len);
- extra_index += items_len + body_len;
+ extra_index += items_len + info.body_len;
+ try case_vals.ensureUnusedCapacity(gpa, items.len);
for (items, 0..) |item_ref, item_i| {
- try sema.validateSwitchItemSparse(
+ case_vals.appendAssumeCapacity(try sema.validateSwitchItemSparse(
block,
&seen_values,
item_ref,
+ operand_ty,
src_node_offset,
.{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } },
- );
+ ));
}
try sema.validateSwitchNoRange(block, ranges_len, operand_ty, src_node_offset);
@@ -10835,10 +11310,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
.ComptimeFloat,
.Float,
=> return sema.fail(block, operand_src, "invalid switch operand type '{}'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
}),
}
+ const spa: SwitchProngAnalysis = .{
+ .sema = sema,
+ .parent_block = block,
+ .operand = raw_operand.val,
+ .operand_ptr = raw_operand.ptr,
+ .cond = operand,
+ .else_error_ty = else_error_ty,
+ .switch_block_inst = inst,
+ .tag_capture_inst = tag_capture_inst,
+ };
+
const block_inst = @intCast(Air.Inst.Index, sema.air_instructions.len);
try sema.air_instructions.append(gpa, .{
.tag = .block,
@@ -10866,7 +11352,6 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
.is_comptime = block.is_comptime,
.comptime_reason = block.comptime_reason,
.is_typeof = block.is_typeof,
- .switch_else_err_ty = else_error_ty,
.c_import_buf = block.c_import_buf,
.runtime_cond = block.runtime_cond,
.runtime_loop = block.runtime_loop,
@@ -10878,83 +11363,115 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
defer merges.deinit(gpa);
if (try sema.resolveDefinedValue(&child_block, src, operand)) |operand_val| {
+ const resolved_operand_val = try sema.resolveLazyValue(operand_val);
var extra_index: usize = special.end;
{
var scalar_i: usize = 0;
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
- const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- const is_inline = sema.code.extra[extra_index] >> 31 != 0;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
- const body = sema.code.extra[extra_index..][0..body_len];
- extra_index += body_len;
+ const body = sema.code.extra[extra_index..][0..info.body_len];
+ extra_index += info.body_len;
- const item = try sema.resolveInst(item_ref);
- // Validation above ensured these will succeed.
+ const item = case_vals.items[scalar_i];
const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
if (operand_val.eql(item_val, operand_ty, sema.mod)) {
- if (is_inline) child_block.inline_case_capture = operand;
-
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
- return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
+ return spa.resolveProngComptime(
+ &child_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .scalar_capture = @intCast(u32, scalar_i) },
+ &.{item},
+ if (info.is_inline) operand else .none,
+ info.has_tag_capture,
+ merges,
+ );
}
}
}
{
var multi_i: usize = 0;
+ var case_val_idx: usize = scalar_cases_len;
while (multi_i < multi_cases_len) : (multi_i += 1) {
const items_len = sema.code.extra[extra_index];
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- const is_inline = sema.code.extra[extra_index] >> 31 != 0;
- extra_index += 1;
- const items = sema.code.refSlice(extra_index, items_len);
- extra_index += items_len;
- const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..body_len];
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
+ extra_index += 1 + items_len;
+ const body = sema.code.extra[extra_index + 2 * ranges_len ..][0..info.body_len];
+
+ const items = case_vals.items[case_val_idx..][0..items_len];
+ case_val_idx += items_len;
- for (items) |item_ref| {
- const item = try sema.resolveInst(item_ref);
+ for (items) |item| {
// Validation above ensured these will succeed.
const item_val = sema.resolveConstValue(&child_block, .unneeded, item, "") catch unreachable;
if (operand_val.eql(item_val, operand_ty, sema.mod)) {
- if (is_inline) child_block.inline_case_capture = operand;
-
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
- return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
+ return spa.resolveProngComptime(
+ &child_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .multi_capture = @intCast(u32, multi_i) },
+ items,
+ if (info.is_inline) operand else .none,
+ info.has_tag_capture,
+ merges,
+ );
}
}
var range_i: usize = 0;
while (range_i < ranges_len) : (range_i += 1) {
- const item_first = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
- extra_index += 1;
- const item_last = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
- extra_index += 1;
+ const range_items = case_vals.items[case_val_idx..][0..2];
+ extra_index += 2;
+ case_val_idx += 2;
// Validation above ensured these will succeed.
- const first_tv = sema.resolveInstConst(&child_block, .unneeded, item_first, "") catch unreachable;
- const last_tv = sema.resolveInstConst(&child_block, .unneeded, item_last, "") catch unreachable;
- if ((try sema.compareAll(operand_val, .gte, first_tv.val, operand_ty)) and
- (try sema.compareAll(operand_val, .lte, last_tv.val, operand_ty)))
+ const first_val = sema.resolveConstValue(&child_block, .unneeded, range_items[0], "") catch unreachable;
+ const last_val = sema.resolveConstValue(&child_block, .unneeded, range_items[1], "") catch unreachable;
+ if ((try sema.compareAll(resolved_operand_val, .gte, first_val, operand_ty)) and
+ (try sema.compareAll(resolved_operand_val, .lte, last_val, operand_ty)))
{
- if (is_inline) child_block.inline_case_capture = operand;
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, body, operand);
- return sema.resolveBlockBody(block, src, &child_block, body, inst, merges);
+ return spa.resolveProngComptime(
+ &child_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .multi_capture = @intCast(u32, multi_i) },
+ undefined, // case_vals may be undefined for ranges
+ if (info.is_inline) operand else .none,
+ info.has_tag_capture,
+ merges,
+ );
}
}
- extra_index += body_len;
+ extra_index += info.body_len;
}
}
if (err_set) try sema.maybeErrorUnwrapComptime(&child_block, special.body, operand);
- if (special.is_inline) child_block.inline_case_capture = operand;
if (empty_enum) {
return Air.Inst.Ref.void_value;
}
- return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
+
+ return spa.resolveProngComptime(
+ &child_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ undefined, // case_vals may be undefined for special prongs
+ if (special.is_inline) operand else .none,
+ special.has_tag_capture,
+ merges,
+ );
}
if (scalar_cases_len + multi_cases_len == 0 and !special.is_inline) {
@@ -10967,14 +11484,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (err_set and try sema.maybeErrorUnwrap(block, special.body, operand)) {
return Air.Inst.Ref.unreachable_value;
}
- if (sema.mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag() == .Enum and
- (!operand_ty.isNonexhaustiveEnum() or union_originally))
+ if (mod.backendSupportsFeature(.is_named_enum_value) and block.wantSafety() and operand_ty.zigTypeTag(mod) == .Enum and
+ (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
{
try sema.zirDbgStmt(block, cond_dbg_node_index);
const ok = try block.addUnOp(.is_named_enum_value, operand);
try sema.addSafetyCheck(block, ok, .corrupt_switch);
}
- return sema.resolveBlockBody(block, src, &child_block, special.body, inst, merges);
+
+ return spa.resolveProngComptime(
+ &child_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ undefined, // case_vals may be undefined for special prongs
+ .none,
+ false,
+ merges,
+ );
}
if (child_block.is_comptime) {
@@ -11000,35 +11528,40 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var scalar_i: usize = 0;
while (scalar_i < scalar_cases_len) : (scalar_i += 1) {
- const item_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- const is_inline = sema.code.extra[extra_index] >> 31 != 0;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
extra_index += 1;
- const body = sema.code.extra[extra_index..][0..body_len];
- extra_index += body_len;
+ const body = sema.code.extra[extra_index..][0..info.body_len];
+ extra_index += info.body_len;
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
defer wip_captures.deinit();
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = wip_captures.scope;
- case_block.inline_case_capture = .none;
- const item = try sema.resolveInst(item_ref);
- if (is_inline) case_block.inline_case_capture = item;
+ const item = case_vals.items[scalar_i];
// `item` is already guaranteed to be constant known.
const analyze_body = if (union_originally) blk: {
- const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
- const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
- break :blk field_ty.zigTypeTag() != .NoReturn;
+ const item_val = sema.resolveConstLazyValue(block, .unneeded, item, "") catch unreachable;
+ const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
+ break :blk field_ty.zigTypeTag(mod) != .NoReturn;
} else true;
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
// nothing to do here
} else if (analyze_body) {
- try sema.analyzeBodyRuntimeBreak(&case_block, body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .scalar_capture = @intCast(u32, scalar_i) },
+ &.{item},
+ if (info.is_inline) item else .none,
+ info.has_tag_capture,
+ );
} else {
_ = try case_block.addNoOp(.unreach);
}
@@ -11050,48 +11583,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
defer gpa.free(prev_then_body);
var cases_len = scalar_cases_len;
+ var case_val_idx: usize = scalar_cases_len;
var multi_i: u32 = 0;
while (multi_i < multi_cases_len) : (multi_i += 1) {
const items_len = sema.code.extra[extra_index];
extra_index += 1;
const ranges_len = sema.code.extra[extra_index];
extra_index += 1;
- const body_len = @truncate(u31, sema.code.extra[extra_index]);
- const is_inline = sema.code.extra[extra_index] >> 31 != 0;
- extra_index += 1;
- const items = sema.code.refSlice(extra_index, items_len);
- extra_index += items_len;
+ const info = @bitCast(Zir.Inst.SwitchBlock.ProngInfo, sema.code.extra[extra_index]);
+ extra_index += 1 + items_len;
+
+ const items = case_vals.items[case_val_idx..][0..items_len];
+ case_val_idx += items_len;
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = child_block.wip_capture_scope;
- case_block.inline_case_capture = .none;
// Generate all possible cases as scalar prongs.
- if (is_inline) {
+ if (info.is_inline) {
const body_start = extra_index + 2 * ranges_len;
- const body = sema.code.extra[body_start..][0..body_len];
+ const body = sema.code.extra[body_start..][0..info.body_len];
var emit_bb = false;
var range_i: u32 = 0;
while (range_i < ranges_len) : (range_i += 1) {
- const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
- extra_index += 1;
- const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
- extra_index += 1;
+ const range_items = case_vals.items[case_val_idx..][0..2];
+ extra_index += 2;
+ case_val_idx += 2;
+
+ const item_first_ref = range_items[0];
+ const item_last_ref = range_items[1];
- const item_first_ref = try sema.resolveInst(first_ref);
var item = sema.resolveConstValue(block, .unneeded, item_first_ref, undefined) catch unreachable;
- const item_last_ref = try sema.resolveInst(last_ref);
const item_last = sema.resolveConstValue(block, .unneeded, item_last_ref, undefined) catch unreachable;
- while (item.compareAll(.lte, item_last, operand_ty, sema.mod)) : ({
+ while (item.compareScalar(.lte, item_last, operand_ty, mod)) : ({
// Previous validation has resolved any possible lazy values.
- item = try sema.intAddScalar(item, Value.one);
+ item = sema.intAddScalar(item, try mod.intValue(operand_ty, 1), operand_ty) catch |err| switch (err) {
+ error.Overflow => unreachable,
+ else => |e| return e,
+ };
}) {
cases_len += 1;
const item_ref = try sema.addConstant(operand_ty, item);
- case_block.inline_case_capture = item_ref;
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = child_block.wip_capture_scope;
@@ -11099,44 +11634,50 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
error.NeededSourceLocation => {
const case_src = Module.SwitchProngSrc{ .range = .{ .prong = multi_i, .item = range_i } };
- const decl = sema.mod.declPtr(case_block.src_decl);
- try sema.emitBackwardBranch(block, case_src.resolve(sema.gpa, decl, src_node_offset, .none));
+ const decl = mod.declPtr(case_block.src_decl);
+ try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none));
unreachable;
},
else => return err,
};
emit_bb = true;
- try sema.analyzeBodyRuntimeBreak(&case_block, body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .multi_capture = multi_i },
+ undefined, // case_vals may be undefined for ranges
+ item_ref,
+ info.has_tag_capture,
+ );
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
}
- for (items, 0..) |item_ref, item_i| {
+ for (items, 0..) |item, item_i| {
cases_len += 1;
- const item = try sema.resolveInst(item_ref);
- case_block.inline_case_capture = item;
-
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.resolveConstValue(block, .unneeded, item, undefined) catch unreachable;
- const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
- break :blk field_ty.zigTypeTag() != .NoReturn;
+ const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
+ break :blk field_ty.zigTypeTag(mod) != .NoReturn;
} else true;
if (emit_bb) sema.emitBackwardBranch(block, .unneeded) catch |err| switch (err) {
error.NeededSourceLocation => {
const case_src = Module.SwitchProngSrc{ .multi = .{ .prong = multi_i, .item = @intCast(u32, item_i) } };
- const decl = sema.mod.declPtr(case_block.src_decl);
- try sema.emitBackwardBranch(block, case_src.resolve(sema.gpa, decl, src_node_offset, .none));
+ const decl = mod.declPtr(case_block.src_decl);
+ try sema.emitBackwardBranch(block, case_src.resolve(mod, decl, src_node_offset, .none));
unreachable;
},
else => return err,
@@ -11144,7 +11685,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
emit_bb = true;
if (analyze_body) {
- try sema.analyzeBodyRuntimeBreak(&case_block, body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .multi_capture = multi_i },
+ &.{item},
+ item,
+ info.has_tag_capture,
+ );
} else {
_ = try case_block.addNoOp(.unreach);
}
@@ -11152,11 +11702,11 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(item));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
- extra_index += body_len;
+ extra_index += info.body_len;
continue;
}
@@ -11169,21 +11719,29 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
cases_len += 1;
const analyze_body = if (union_originally)
- for (items) |item_ref| {
- const item = try sema.resolveInst(item_ref);
+ for (items) |item| {
const item_val = sema.resolveConstValue(block, .unneeded, item, "") catch unreachable;
- const field_ty = maybe_union_ty.unionFieldType(item_val, sema.mod);
- if (field_ty.zigTypeTag() != .NoReturn) break true;
+ const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
+ if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
} else false
else
true;
- const body = sema.code.extra[extra_index..][0..body_len];
- extra_index += body_len;
+ const body = sema.code.extra[extra_index..][0..info.body_len];
+ extra_index += info.body_len;
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
// nothing to do here
} else if (analyze_body) {
- try sema.analyzeBodyRuntimeBreak(&case_block, body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .multi_capture = multi_i },
+ items,
+ .none,
+ false,
+ );
} else {
_ = try case_block.addNoOp(.unreach);
}
@@ -11194,15 +11752,13 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
cases_extra.appendAssumeCapacity(@intCast(u32, items.len));
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- for (items) |item_ref| {
- const item = try sema.resolveInst(item_ref);
+ for (items) |item| {
cases_extra.appendAssumeCapacity(@enumToInt(item));
}
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
} else {
- for (items) |item_ref| {
- const item = try sema.resolveInst(item_ref);
+ for (items) |item| {
const cmp_ok = try case_block.addBinOp(if (case_block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, item);
if (any_ok != .none) {
any_ok = try case_block.addBinOp(.bool_or, any_ok, cmp_ok);
@@ -11213,13 +11769,12 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var range_i: usize = 0;
while (range_i < ranges_len) : (range_i += 1) {
- const first_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
- extra_index += 1;
- const last_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
- extra_index += 1;
+ const range_items = case_vals.items[case_val_idx..][0..2];
+ extra_index += 2;
+ case_val_idx += 2;
- const item_first = try sema.resolveInst(first_ref);
- const item_last = try sema.resolveInst(last_ref);
+ const item_first = range_items[0];
+ const item_last = range_items[1];
// operand >= first and operand <= last
const range_first_ok = try case_block.addBinOp(
@@ -11253,18 +11808,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var cond_body = try case_block.instructions.toOwnedSlice(gpa);
defer gpa.free(cond_body);
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
defer wip_captures.deinit();
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = wip_captures.scope;
- const body = sema.code.extra[extra_index..][0..body_len];
- extra_index += body_len;
+ const body = sema.code.extra[extra_index..][0..info.body_len];
+ extra_index += info.body_len;
if (err_set and try sema.maybeErrorUnwrap(&case_block, body, operand)) {
// nothing to do here
} else {
- try sema.analyzeBodyRuntimeBreak(&case_block, body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .normal,
+ body,
+ info.capture,
+ .{ .multi_capture = multi_i },
+ items,
+ .none,
+ false,
+ );
}
try wip_captures.finalize();
@@ -11296,34 +11860,42 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
var final_else_body: []const Air.Inst.Index = &.{};
if (special.body.len != 0 or !is_first or case_block.wantSafety()) {
var emit_bb = false;
- if (special.is_inline) switch (operand_ty.zigTypeTag()) {
+ if (special.is_inline) switch (operand_ty.zigTypeTag(mod)) {
.Enum => {
- if (operand_ty.isNonexhaustiveEnum() and !union_originally) {
+ if (operand_ty.isNonexhaustiveEnum(mod) and !union_originally) {
return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
});
}
for (seen_enum_fields, 0..) |f, i| {
if (f != null) continue;
cases_len += 1;
- const item_val = try Value.Tag.enum_field_index.create(sema.arena, @intCast(u32, i));
+ const item_val = try mod.enumValueFieldIndex(operand_ty, @intCast(u32, i));
const item_ref = try sema.addConstant(operand_ty, item_val);
- case_block.inline_case_capture = item_ref;
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, sema.mod);
- break :blk field_ty.zigTypeTag() != .NoReturn;
+ const field_ty = maybe_union_ty.unionFieldType(item_val, mod);
+ break :blk field_ty.zigTypeTag(mod) != .NoReturn;
} else true;
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
if (analyze_body) {
- try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ &.{item_ref},
+ item_ref,
+ special.has_tag_capture,
+ );
} else {
_ = try case_block.addNoOp(.unreach);
}
@@ -11331,23 +11903,26 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
},
.ErrorSet => {
- if (operand_ty.isAnyError()) {
+ if (operand_ty.isAnyError(mod)) {
return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
});
}
- for (operand_ty.errorSetNames()) |error_name| {
+ for (0..operand_ty.errorSetNames(mod).len) |i| {
+ const error_name = operand_ty.errorSetNames(mod)[i];
if (seen_errors.contains(error_name)) continue;
cases_len += 1;
- const item_val = try Value.Tag.@"error".create(sema.arena, .{ .name = error_name });
- const item_ref = try sema.addConstant(operand_ty, item_val);
- case_block.inline_case_capture = item_ref;
+ const item_val = try mod.intern(.{ .err = .{
+ .ty = operand_ty.toIntern(),
+ .name = error_name,
+ } });
+ const item_ref = try sema.addConstant(operand_ty, item_val.toValue());
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = child_block.wip_capture_scope;
@@ -11355,12 +11930,21 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
- try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ &.{item_ref},
+ item_ref,
+ special.has_tag_capture,
+ );
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
},
@@ -11369,8 +11953,7 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
while (try it.next()) |cur| {
cases_len += 1;
- const item_ref = try sema.addConstant(operand_ty, cur);
- case_block.inline_case_capture = item_ref;
+ const item_ref = try sema.addConstant(operand_ty, cur.toValue());
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = child_block.wip_capture_scope;
@@ -11378,19 +11961,27 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
- try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ &.{item_ref},
+ item_ref,
+ special.has_tag_capture,
+ );
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(item_ref));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
},
.Bool => {
if (true_count == 0) {
cases_len += 1;
- case_block.inline_case_capture = Air.Inst.Ref.bool_true;
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = child_block.wip_capture_scope;
@@ -11398,17 +11989,25 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
- try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ &.{Air.Inst.Ref.bool_true},
+ Air.Inst.Ref.bool_true,
+ special.has_tag_capture,
+ );
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_true));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
if (false_count == 0) {
cases_len += 1;
- case_block.inline_case_capture = Air.Inst.Ref.bool_false;
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = child_block.wip_capture_scope;
@@ -11416,29 +12015,37 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
if (emit_bb) try sema.emitBackwardBranch(block, special_prong_src);
emit_bb = true;
- try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ &.{Air.Inst.Ref.bool_false},
+ Air.Inst.Ref.bool_false,
+ special.has_tag_capture,
+ );
try cases_extra.ensureUnusedCapacity(gpa, 3 + case_block.instructions.items.len);
cases_extra.appendAssumeCapacity(1); // items_len
cases_extra.appendAssumeCapacity(@intCast(u32, case_block.instructions.items.len));
- cases_extra.appendAssumeCapacity(@enumToInt(case_block.inline_case_capture));
+ cases_extra.appendAssumeCapacity(@enumToInt(Air.Inst.Ref.bool_false));
cases_extra.appendSliceAssumeCapacity(case_block.instructions.items);
}
},
else => return sema.fail(block, special_prong_src, "cannot enumerate values of type '{}' for 'inline else'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
}),
};
- var wip_captures = try WipCaptureScope.init(gpa, sema.perm_arena, child_block.wip_capture_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, child_block.wip_capture_scope);
defer wip_captures.deinit();
case_block.instructions.shrinkRetainingCapacity(0);
case_block.wip_capture_scope = wip_captures.scope;
- case_block.inline_case_capture = .none;
- if (sema.mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
- operand_ty.zigTypeTag() == .Enum and (!operand_ty.isNonexhaustiveEnum() or union_originally))
+ if (mod.backendSupportsFeature(.is_named_enum_value) and special.body.len != 0 and block.wantSafety() and
+ operand_ty.zigTypeTag(mod) == .Enum and (!operand_ty.isNonexhaustiveEnum(mod) or union_originally))
{
try sema.zirDbgStmt(&case_block, cond_dbg_node_index);
const ok = try case_block.addUnOp(.is_named_enum_value, operand);
@@ -11448,9 +12055,9 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const analyze_body = if (union_originally and !special.is_inline)
for (seen_enum_fields, 0..) |seen_field, index| {
if (seen_field != null) continue;
- const union_obj = maybe_union_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(maybe_union_ty).?;
const field_ty = union_obj.fields.values()[index].ty;
- if (field_ty.zigTypeTag() != .NoReturn) break true;
+ if (field_ty.zigTypeTag(mod) != .NoReturn) break true;
} else false
else
true;
@@ -11459,7 +12066,16 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
{
// nothing to do here
} else if (special.body.len != 0 and analyze_body and !special.is_inline) {
- try sema.analyzeBodyRuntimeBreak(&case_block, special.body);
+ try spa.analyzeProngRuntime(
+ &case_block,
+ .special,
+ special.body,
+ special.capture,
+ .special_capture,
+ undefined, // case_vals may be undefined for special prongs
+ .none,
+ false,
+ );
} else {
// We still need a terminator in this block, but we have proven
// that it is unreachable.
@@ -11507,74 +12123,118 @@ fn zirSwitchBlock(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
}
const RangeSetUnhandledIterator = struct {
- sema: *Sema,
- ty: Type,
- cur: Value,
- max: Value,
+ mod: *Module,
+ cur: ?InternPool.Index,
+ max: InternPool.Index,
+ range_i: usize,
ranges: []const RangeSet.Range,
- range_i: usize = 0,
- first: bool = true,
+ limbs: []math.big.Limb,
- fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {
- const target = sema.mod.getTarget();
- const min = try ty.minInt(sema.arena, target);
- const max = try ty.maxInt(sema.arena, target);
+ const preallocated_limbs = math.big.int.calcTwosCompLimbCount(128);
- return RangeSetUnhandledIterator{
- .sema = sema,
- .ty = ty,
- .cur = min,
- .max = max,
+ fn init(sema: *Sema, ty: Type, range_set: RangeSet) !RangeSetUnhandledIterator {
+ const mod = sema.mod;
+ const int_type = mod.intern_pool.indexToKey(ty.toIntern()).int_type;
+ const needed_limbs = math.big.int.calcTwosCompLimbCount(int_type.bits);
+ return .{
+ .mod = mod,
+ .cur = (try ty.minInt(mod, ty)).toIntern(),
+ .max = (try ty.maxInt(mod, ty)).toIntern(),
+ .range_i = 0,
.ranges = range_set.ranges.items,
+ .limbs = if (needed_limbs > preallocated_limbs)
+ try sema.arena.alloc(math.big.Limb, needed_limbs)
+ else
+ &.{},
};
}
- fn next(it: *RangeSetUnhandledIterator) !?Value {
- while (it.range_i < it.ranges.len) : (it.range_i += 1) {
- if (!it.first) {
- it.cur = try it.sema.intAdd(it.cur, Value.one, it.ty);
- }
- it.first = false;
- if (it.cur.compareAll(.lt, it.ranges[it.range_i].first, it.ty, it.sema.mod)) {
- return it.cur;
- }
- it.cur = it.ranges[it.range_i].last;
- }
- if (!it.first) {
- it.cur = try it.sema.intAdd(it.cur, Value.one, it.ty);
+ fn addOne(it: *const RangeSetUnhandledIterator, val: InternPool.Index) !?InternPool.Index {
+ if (val == it.max) return null;
+ const int = it.mod.intern_pool.indexToKey(val).int;
+
+ switch (int.storage) {
+ inline .u64, .i64 => |val_int| {
+ const next_int = @addWithOverflow(val_int, 1);
+ if (next_int[1] == 0)
+ return (try it.mod.intValue(int.ty.toType(), next_int[0])).toIntern();
+ },
+ .big_int => {},
+ .lazy_align, .lazy_size => unreachable,
}
- it.first = false;
- if (it.cur.compareAll(.lte, it.max, it.ty, it.sema.mod)) {
- return it.cur;
+
+ var val_space: InternPool.Key.Int.Storage.BigIntSpace = undefined;
+ const val_bigint = int.storage.toBigInt(&val_space);
+
+ var result_limbs: [preallocated_limbs]math.big.Limb = undefined;
+ var result_bigint = math.big.int.Mutable.init(
+ if (it.limbs.len > 0) it.limbs else &result_limbs,
+ 0,
+ );
+
+ result_bigint.addScalar(val_bigint, 1);
+ return (try it.mod.intValue_big(int.ty.toType(), result_bigint.toConst())).toIntern();
+ }
+
+ fn next(it: *RangeSetUnhandledIterator) !?InternPool.Index {
+ var cur = it.cur orelse return null;
+ while (it.range_i < it.ranges.len and cur == it.ranges[it.range_i].first) {
+ defer it.range_i += 1;
+ cur = (try it.addOne(it.ranges[it.range_i].last)) orelse {
+ it.cur = null;
+ return null;
+ };
}
- return null;
+ it.cur = try it.addOne(cur);
+ return cur;
}
};
+const ResolvedSwitchItem = struct {
+ ref: Air.Inst.Ref,
+ val: InternPool.Index,
+};
fn resolveSwitchItemVal(
sema: *Sema,
block: *Block,
item_ref: Zir.Inst.Ref,
+ /// Coerce `item_ref` to this type.
+ coerce_ty: Type,
switch_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
range_expand: Module.SwitchProngSrc.RangeExpand,
-) CompileError!TypedValue {
- const item = try sema.resolveInst(item_ref);
- const item_ty = sema.typeOf(item);
+) CompileError!ResolvedSwitchItem {
+ const mod = sema.mod;
+ const uncoerced_item = try sema.resolveInst(item_ref);
+
// Constructing a LazySrcLoc is costly because we only have the switch AST node.
// Only if we know for sure we need to report a compile error do we resolve the
// full source locations.
- if (sema.resolveConstValue(block, .unneeded, item, "")) |val| {
- try sema.resolveLazyValue(val);
- return TypedValue{ .ty = item_ty, .val = val };
- } else |err| switch (err) {
+
+ const item = sema.coerce(block, coerce_ty, uncoerced_item, .unneeded) catch |err| switch (err) {
+ error.NeededSourceLocation => {
+ const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
+ _ = try sema.coerce(block, coerce_ty, uncoerced_item, src);
+ unreachable;
+ },
+ else => |e| return e,
+ };
+
+ const maybe_lazy = sema.resolveConstValue(block, .unneeded, item, "") catch |err| switch (err) {
error.NeededSourceLocation => {
- const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), switch_node_offset, range_expand);
+ const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), switch_node_offset, range_expand);
_ = try sema.resolveConstValue(block, src, item, "switch prong values must be comptime-known");
unreachable;
},
else => |e| return e,
- }
+ };
+
+ const val = try sema.resolveLazyValue(maybe_lazy);
+ const new_item = if (val.toIntern() != maybe_lazy.toIntern()) blk: {
+ break :blk try sema.addConstant(coerce_ty, val);
+ } else item;
+
+ return .{ .ref = new_item, .val = val.toIntern() };
}
fn validateSwitchRange(
@@ -11586,18 +12246,20 @@ fn validateSwitchRange(
operand_ty: Type,
src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
-) CompileError!void {
- const first_val = (try sema.resolveSwitchItemVal(block, first_ref, src_node_offset, switch_prong_src, .first)).val;
- const last_val = (try sema.resolveSwitchItemVal(block, last_ref, src_node_offset, switch_prong_src, .last)).val;
- if (first_val.compareAll(.gt, last_val, operand_ty, sema.mod)) {
- const src = switch_prong_src.resolve(sema.gpa, sema.mod.declPtr(block.src_decl), src_node_offset, .first);
+) CompileError![2]Air.Inst.Ref {
+ const mod = sema.mod;
+ const first = try sema.resolveSwitchItemVal(block, first_ref, operand_ty, src_node_offset, switch_prong_src, .first);
+ const last = try sema.resolveSwitchItemVal(block, last_ref, operand_ty, src_node_offset, switch_prong_src, .last);
+ if (try first.val.toValue().compareAll(.gt, last.val.toValue(), operand_ty, mod)) {
+ const src = switch_prong_src.resolve(mod, mod.declPtr(block.src_decl), src_node_offset, .first);
return sema.fail(block, src, "range start value is greater than the end value", .{});
}
- const maybe_prev_src = try range_set.add(first_val, last_val, operand_ty, switch_prong_src);
- return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ const maybe_prev_src = try range_set.add(first.val, last.val, switch_prong_src);
+ try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ return .{ first.ref, last.ref };
}
-fn validateSwitchItem(
+fn validateSwitchItemInt(
sema: *Sema,
block: *Block,
range_set: *RangeSet,
@@ -11605,10 +12267,11 @@ fn validateSwitchItem(
operand_ty: Type,
src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
-) CompileError!void {
- const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
- const maybe_prev_src = try range_set.add(item_val, item_val, operand_ty, switch_prong_src);
- return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+) CompileError!Air.Inst.Ref {
+ const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
+ const maybe_prev_src = try range_set.add(item.val, item.val, switch_prong_src);
+ try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ return item.ref;
}
fn validateSwitchItemEnum(
@@ -11617,17 +12280,22 @@ fn validateSwitchItemEnum(
seen_fields: []?Module.SwitchProngSrc,
range_set: *RangeSet,
item_ref: Zir.Inst.Ref,
+ operand_ty: Type,
src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
-) CompileError!void {
- const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
- const field_index = item_tv.ty.enumTagFieldIndex(item_tv.val, sema.mod) orelse {
- const maybe_prev_src = try range_set.add(item_tv.val, item_tv.val, item_tv.ty, switch_prong_src);
- return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+) CompileError!Air.Inst.Ref {
+ 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 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;
};
const maybe_prev_src = seen_fields[field_index];
seen_fields[field_index] = switch_prong_src;
- return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ return item.ref;
}
fn validateSwitchItemError(
@@ -11635,17 +12303,19 @@ fn validateSwitchItemError(
block: *Block,
seen_errors: *SwitchErrorSet,
item_ref: Zir.Inst.Ref,
+ operand_ty: Type,
src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
-) CompileError!void {
- const item_tv = try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none);
- // TODO: Do i need to typecheck here?
- const error_name = item_tv.val.castTag(.@"error").?.data.name;
+) CompileError!Air.Inst.Ref {
+ const ip = &sema.mod.intern_pool;
+ const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
+ const error_name = ip.indexToKey(item.val).err.name;
const maybe_prev_src = if (try seen_errors.fetchPut(error_name, switch_prong_src)) |prev|
prev.value
else
null;
- return sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ try sema.validateSwitchDupe(block, maybe_prev_src, switch_prong_src, src_node_offset);
+ return item.ref;
}
fn validateSwitchDupe(
@@ -11656,10 +12326,10 @@ fn validateSwitchDupe(
src_node_offset: i32,
) CompileError!void {
const prev_prong_src = maybe_prev_src orelse return;
- const gpa = sema.gpa;
- const block_src_decl = sema.mod.declPtr(block.src_decl);
- const src = switch_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none);
- const prev_src = prev_prong_src.resolve(gpa, block_src_decl, src_node_offset, .none);
+ const mod = sema.mod;
+ const block_src_decl = mod.declPtr(block.src_decl);
+ const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
+ const prev_src = prev_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
const msg = msg: {
const msg = try sema.errMsg(
block,
@@ -11688,33 +12358,37 @@ fn validateSwitchItemBool(
item_ref: Zir.Inst.Ref,
src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
-) CompileError!void {
- const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
- if (item_val.toBool()) {
+) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const item = try sema.resolveSwitchItemVal(block, item_ref, Type.bool, src_node_offset, switch_prong_src, .none);
+ if (item.val.toValue().toBool()) {
true_count.* += 1;
} else {
false_count.* += 1;
}
- if (true_count.* + false_count.* > 2) {
+ if (true_count.* > 1 or false_count.* > 1) {
const block_src_decl = sema.mod.declPtr(block.src_decl);
- const src = switch_prong_src.resolve(sema.gpa, block_src_decl, src_node_offset, .none);
+ const src = switch_prong_src.resolve(mod, block_src_decl, src_node_offset, .none);
return sema.fail(block, src, "duplicate switch value", .{});
}
+ return item.ref;
}
-const ValueSrcMap = std.HashMap(Value, Module.SwitchProngSrc, Value.HashContext, std.hash_map.default_max_load_percentage);
+const ValueSrcMap = std.AutoHashMapUnmanaged(InternPool.Index, Module.SwitchProngSrc);
fn validateSwitchItemSparse(
sema: *Sema,
block: *Block,
seen_values: *ValueSrcMap,
item_ref: Zir.Inst.Ref,
+ operand_ty: Type,
src_node_offset: i32,
switch_prong_src: Module.SwitchProngSrc,
-) CompileError!void {
- const item_val = (try sema.resolveSwitchItemVal(block, item_ref, src_node_offset, switch_prong_src, .none)).val;
- const kv = (try seen_values.fetchPut(item_val, switch_prong_src)) orelse return;
- return sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
+) CompileError!Air.Inst.Ref {
+ const item = try sema.resolveSwitchItemVal(block, item_ref, operand_ty, src_node_offset, switch_prong_src, .none);
+ const kv = (try seen_values.fetchPut(sema.gpa, item.val, switch_prong_src)) orelse return item.ref;
+ try sema.validateSwitchDupe(block, kv.value, switch_prong_src, src_node_offset);
+ unreachable;
}
fn validateSwitchNoRange(
@@ -11751,16 +12425,17 @@ fn validateSwitchNoRange(
}
fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, operand: Air.Inst.Ref) !bool {
- if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) return false;
+ const mod = sema.mod;
+ if (!mod.backendSupportsFeature(.panic_unwrap_error)) return false;
const tags = sema.code.instructions.items(.tag);
for (body) |inst| {
switch (tags[inst]) {
+ .@"unreachable" => if (!block.wantSafety()) return false,
.save_err_ret_index,
.dbg_block_begin,
.dbg_block_end,
.dbg_stmt,
- .@"unreachable",
.str,
.as_node,
.panic,
@@ -11787,10 +12462,7 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
.as_node => try sema.zirAsNode(block, inst),
.field_val => try sema.zirFieldVal(block, inst),
.@"unreachable" => {
- const inst_data = sema.code.instructions.items(.data)[inst].@"unreachable";
- const src = inst_data.src();
-
- if (!sema.mod.comp.formatted_panics) {
+ if (!mod.comp.formatted_panics) {
try sema.safetyPanic(block, .unwrap_error);
return true;
}
@@ -11798,23 +12470,22 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
const panic_fn = try sema.getBuiltin("panicUnwrapError");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [2]Air.Inst.Ref = .{ err_return_trace, operand };
- _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
+ try sema.callBuiltin(block, panic_fn, .auto, &args);
return true;
},
.panic => {
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
- const src = inst_data.src();
const msg_inst = try sema.resolveInst(inst_data.operand);
const panic_fn = try sema.getBuiltin("panic");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
- _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
+ try sema.callBuiltin(block, panic_fn, .auto, &args);
return true;
},
else => unreachable,
};
- if (sema.typeOf(air_inst).isNoReturn())
+ if (sema.typeOf(air_inst).isNoReturn(mod))
return true;
sema.inst_map.putAssumeCapacity(inst, air_inst);
}
@@ -11822,19 +12493,20 @@ fn maybeErrorUnwrap(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, op
}
fn maybeErrorUnwrapCondbr(sema: *Sema, block: *Block, body: []const Zir.Inst.Index, cond: Zir.Inst.Ref, cond_src: LazySrcLoc) !void {
+ const mod = sema.mod;
const index = Zir.refToIndex(cond) orelse return;
if (sema.code.instructions.items(.tag)[index] != .is_non_err) return;
const err_inst_data = sema.code.instructions.items(.data)[index].un_node;
const err_operand = try sema.resolveInst(err_inst_data.operand);
const operand_ty = sema.typeOf(err_operand);
- if (operand_ty.zigTypeTag() == .ErrorSet) {
+ if (operand_ty.zigTypeTag(mod) == .ErrorSet) {
try sema.maybeErrorUnwrapComptime(block, body, err_operand);
return;
}
if (try sema.resolveDefinedValue(block, cond_src, err_operand)) |val| {
- if (!operand_ty.isError()) return;
- if (val.getError() == null) return;
+ if (!operand_ty.isError(mod)) return;
+ if (val.getErrorName(mod) == .none) return;
try sema.maybeErrorUnwrapComptime(block, body, err_operand);
}
}
@@ -11856,45 +12528,60 @@ fn maybeErrorUnwrapComptime(sema: *Sema, block: *Block, body: []const Zir.Inst.I
const src = inst_data.src();
if (try sema.resolveDefinedValue(block, src, operand)) |val| {
- if (val.getError()) |name| {
- return sema.fail(block, src, "caught unexpected error '{s}'", .{name});
+ if (val.getErrorName(sema.mod).unwrap()) |name| {
+ return sema.fail(block, src, "caught unexpected error '{}'", .{name.fmt(&sema.mod.intern_pool)});
}
}
}
fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const unresolved_ty = try sema.resolveType(block, ty_src, extra.lhs);
- const field_name = try sema.resolveConstString(block, name_src, extra.rhs, "field name must be comptime-known");
+ const field_name = try sema.resolveConstStringIntern(block, name_src, extra.rhs, "field name must be comptime-known");
const ty = try sema.resolveTypeFields(unresolved_ty);
+ const ip = &mod.intern_pool;
const has_field = hf: {
- if (ty.isSlice()) {
- if (mem.eql(u8, field_name, "ptr")) break :hf true;
- if (mem.eql(u8, field_name, "len")) break :hf true;
- break :hf false;
- }
- if (ty.castTag(.anon_struct)) |pl| {
- break :hf for (pl.data.names) |name| {
- if (mem.eql(u8, name, field_name)) break true;
- } else false;
- }
- if (ty.isTuple()) {
- const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch break :hf false;
- break :hf field_index < ty.structFieldCount();
- }
- break :hf switch (ty.zigTypeTag()) {
- .Struct => ty.structFields().contains(field_name),
- .Union => ty.unionFields().contains(field_name),
- .Enum => ty.enumFields().contains(field_name),
- .Array => mem.eql(u8, field_name, "len"),
- else => return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
- ty.fmt(sema.mod),
- }),
- };
+ switch (ip.indexToKey(ty.toIntern())) {
+ .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
+ .Slice => {
+ if (ip.stringEqlSlice(field_name, "ptr")) break :hf true;
+ if (ip.stringEqlSlice(field_name, "len")) break :hf true;
+ break :hf false;
+ },
+ else => {},
+ },
+ .anon_struct_type => |anon_struct| {
+ if (anon_struct.names.len != 0) {
+ break :hf mem.indexOfScalar(InternPool.NullTerminatedString, anon_struct.names, field_name) != null;
+ } else {
+ const field_index = field_name.toUnsigned(ip) orelse break :hf false;
+ break :hf field_index < ty.structFieldCount(mod);
+ }
+ },
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :hf false;
+ assert(struct_obj.haveFieldTypes());
+ break :hf struct_obj.fields.contains(field_name);
+ },
+ .union_type => |union_type| {
+ const union_obj = mod.unionPtr(union_type.index);
+ assert(union_obj.haveFieldTypes());
+ break :hf union_obj.fields.contains(field_name);
+ },
+ .enum_type => |enum_type| {
+ break :hf enum_type.nameIndex(ip, field_name) != null;
+ },
+ .array_type => break :hf ip.stringEqlSlice(field_name, "len"),
+ else => {},
+ }
+ return sema.fail(block, ty_src, "type '{}' does not support '@hasField'", .{
+ ty.fmt(mod),
+ });
};
if (has_field) {
return Air.Inst.Ref.bool_true;
@@ -11904,20 +12591,22 @@ fn zirHasField(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn zirHasDecl(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const src = inst_data.src();
const lhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const rhs_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const container_type = try sema.resolveType(block, lhs_src, extra.lhs);
- const decl_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "decl name must be comptime-known");
+ const decl_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "decl name must be comptime-known");
try sema.checkNamespaceType(block, lhs_src, container_type);
- const namespace = container_type.getNamespace() orelse return Air.Inst.Ref.bool_false;
+ const namespace = container_type.getNamespaceIndex(mod).unwrap() orelse
+ return Air.Inst.Ref.bool_false;
if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| {
- const decl = sema.mod.declPtr(decl_index);
- if (decl.is_pub or decl.getFileScope() == block.getFileScope()) {
+ const decl = mod.declPtr(decl_index);
+ if (decl.is_pub or decl.getFileScope(mod) == block.getFileScope(mod)) {
return Air.Inst.Ref.bool_true;
}
}
@@ -11933,12 +12622,12 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const operand_src = inst_data.src();
const operand = inst_data.get(sema.code);
- const result = mod.importFile(block.getFileScope(), operand) catch |err| switch (err) {
+ const result = mod.importFile(block.getFileScope(mod), operand) catch |err| switch (err) {
error.ImportOutsidePkgPath => {
return sema.fail(block, operand_src, "import of file outside package path: '{s}'", .{operand});
},
error.PackageNotFound => {
- const name = try block.getFileScope().pkg.getName(sema.gpa, mod.*);
+ const name = try block.getFileScope(mod).pkg.getName(sema.gpa, mod.*);
defer sema.gpa.free(name);
return sema.fail(block, operand_src, "no package named '{s}' available within package '{s}'", .{ operand, name });
},
@@ -11964,7 +12653,7 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const name = try sema.resolveConstString(block, operand_src, inst_data.operand, "file path name must be comptime-known");
- const embed_file = mod.embedFile(block.getFileScope(), name) catch |err| switch (err) {
+ const embed_file = mod.embedFile(block.getFileScope(mod), name) catch |err| switch (err) {
error.ImportOutsidePkgPath => {
return sema.fail(block, operand_src, "embed of file outside package path: '{s}'", .{name});
},
@@ -11978,17 +12667,23 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes_including_null = embed_file.bytes[0 .. embed_file.bytes.len + 1];
-
- // TODO instead of using `Value.Tag.bytes`, create a new value tag for pointing at
+ // TODO instead of using `.bytes`, create a new value tag for pointing at
// a `*Module.EmbedFile`. The purpose of this would be:
// - If only the length is read and the bytes are not inspected by comptime code,
// there can be an optimization where the codegen backend does a copy_file_range
// into the final binary, and never loads the data into memory.
// - When a Decl is destroyed, it can free the `*Module.EmbedFile`.
+ const ty = try mod.arrayType(.{
+ .len = embed_file.bytes.len,
+ .child = .u8_type,
+ .sentinel = .zero_u8,
+ });
embed_file.owner_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), embed_file.bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes_including_null),
+ ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .bytes = embed_file.bytes },
+ } })).toValue(),
0, // default alignment
);
@@ -11996,16 +12691,15 @@ fn zirEmbedFile(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
}
fn zirRetErrValueCode(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
- const err_name = inst_data.get(sema.code);
-
- // Return the error code from the function.
- const kv = try sema.mod.getErrorValue(err_name);
- const result_inst = try sema.addConstant(
- try Type.Tag.error_set_single.create(sema.arena, kv.key),
- try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }),
- );
- return result_inst;
+ const name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ _ = try mod.getErrorValue(name);
+ const error_set_type = try mod.singleErrorSetType(name);
+ return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
+ .ty = error_set_type.toIntern(),
+ .name = name,
+ } })).toValue());
}
fn zirShl(
@@ -12017,6 +12711,7 @@ fn zirShl(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
sema.src = src;
@@ -12027,11 +12722,10 @@ fn zirShl(
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const target = sema.mod.getTarget();
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
- const scalar_ty = lhs_ty.scalarType();
- const scalar_rhs_ty = rhs_ty.scalarType();
+ const scalar_ty = lhs_ty.scalarType(mod);
+ const scalar_rhs_ty = rhs_ty.scalarType(mod);
// TODO coerce rhs if air_tag is not shl_sat
const rhs_is_comptime_int = try sema.checkIntType(block, rhs_src, scalar_rhs_ty);
@@ -12040,62 +12734,56 @@ fn zirShl(
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs);
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(sema.typeOf(lhs));
}
// If rhs is 0, return lhs without doing any calculations.
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
return lhs;
}
- if (scalar_ty.zigTypeTag() != .ComptimeInt and air_tag != .shl_sat) {
- var bits_payload = Value.Payload.U64{
- .base = .{ .tag = .int_u64 },
- .data = scalar_ty.intInfo(target).bits,
- };
- const bit_value = Value.initPayload(&bits_payload.base);
- if (rhs_ty.zigTypeTag() == .Vector) {
+ if (scalar_ty.zigTypeTag(mod) != .ComptimeInt and air_tag != .shl_sat) {
+ const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits);
+ if (rhs_ty.zigTypeTag(mod) == .Vector) {
var i: usize = 0;
- while (i < rhs_ty.vectorLen()) : (i += 1) {
- var elem_value_buf: Value.ElemValueBuffer = undefined;
- const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf);
- if (rhs_elem.compareHetero(.gte, bit_value, target)) {
+ while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
+ const rhs_elem = try rhs_val.elemValue(mod, i);
+ if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
- rhs_elem.fmtValue(scalar_ty, sema.mod),
+ rhs_elem.fmtValue(scalar_ty, mod),
i,
- scalar_ty.fmt(sema.mod),
+ scalar_ty.fmt(mod),
});
}
}
- } else if (rhs_val.compareHetero(.gte, bit_value, target)) {
+ } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
- rhs_val.fmtValue(scalar_ty, sema.mod),
- scalar_ty.fmt(sema.mod),
+ rhs_val.fmtValue(scalar_ty, mod),
+ scalar_ty.fmt(mod),
});
}
}
- if (rhs_ty.zigTypeTag() == .Vector) {
+ if (rhs_ty.zigTypeTag(mod) == .Vector) {
var i: usize = 0;
- while (i < rhs_ty.vectorLen()) : (i += 1) {
- var elem_value_buf: Value.ElemValueBuffer = undefined;
- const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf);
- if (rhs_elem.compareHetero(.lt, Value.zero, target)) {
+ while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
+ const rhs_elem = try rhs_val.elemValue(mod, i);
+ if (rhs_elem.compareHetero(.lt, try mod.intValue(scalar_rhs_ty, 0), mod)) {
return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
- rhs_elem.fmtValue(scalar_ty, sema.mod),
+ rhs_elem.fmtValue(scalar_ty, mod),
i,
});
}
}
- } else if (rhs_val.compareHetero(.lt, Value.zero, target)) {
+ } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
- rhs_val.fmtValue(scalar_ty, sema.mod),
+ rhs_val.fmtValue(scalar_ty, mod),
});
}
}
const runtime_src = if (maybe_lhs_val) |lhs_val| rs: {
- if (lhs_val.isUndef()) return sema.addConstUndef(lhs_ty);
+ if (lhs_val.isUndef(mod)) return sema.addConstUndef(lhs_ty);
const rhs_val = maybe_rhs_val orelse {
- if (scalar_ty.zigTypeTag() == .ComptimeInt) {
+ if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{});
}
break :rs rhs_src;
@@ -12103,25 +12791,25 @@ fn zirShl(
const val = switch (air_tag) {
.shl_exact => val: {
- const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, sema.mod);
- if (scalar_ty.zigTypeTag() == .ComptimeInt) {
+ const shifted = try lhs_val.shlWithOverflow(rhs_val, lhs_ty, sema.arena, mod);
+ if (scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
break :val shifted.wrapped_result;
}
- if (shifted.overflow_bit.compareAllWithZero(.eq, sema.mod)) {
+ if (shifted.overflow_bit.compareAllWithZero(.eq, mod)) {
break :val shifted.wrapped_result;
}
return sema.fail(block, src, "operation caused overflow", .{});
},
- .shl_sat => if (scalar_ty.zigTypeTag() == .ComptimeInt)
- try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod)
+ .shl_sat => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt)
+ try lhs_val.shl(rhs_val, lhs_ty, sema.arena, mod)
else
- try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, sema.mod),
+ try lhs_val.shlSat(rhs_val, lhs_ty, sema.arena, mod),
- .shl => if (scalar_ty.zigTypeTag() == .ComptimeInt)
- try lhs_val.shl(rhs_val, lhs_ty, sema.arena, sema.mod)
+ .shl => if (scalar_ty.zigTypeTag(mod) == .ComptimeInt)
+ try lhs_val.shl(rhs_val, lhs_ty, sema.arena, mod)
else
- try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, sema.mod),
+ try lhs_val.shlTrunc(rhs_val, lhs_ty, sema.arena, mod),
else => unreachable,
};
@@ -12132,13 +12820,13 @@ fn zirShl(
const new_rhs = if (air_tag == .shl_sat) rhs: {
// Limit the RHS type for saturating shl to be an integer as small as the LHS.
if (rhs_is_comptime_int or
- scalar_rhs_ty.intInfo(target).bits > scalar_ty.intInfo(target).bits)
+ scalar_rhs_ty.intInfo(mod).bits > scalar_ty.intInfo(mod).bits)
{
const max_int = try sema.addConstant(
lhs_ty,
- try lhs_ty.maxInt(sema.arena, target),
+ try lhs_ty.maxInt(mod, lhs_ty),
);
- const rhs_limited = try sema.analyzeMinMax(block, rhs_src, rhs, max_int, .min, rhs_src, rhs_src);
+ const rhs_limited = try sema.analyzeMinMax(block, rhs_src, .min, &.{ rhs, max_int }, &.{ rhs_src, rhs_src });
break :rhs try sema.intCast(block, src, lhs_ty, rhs_src, rhs_limited, rhs_src, false);
} else {
break :rhs rhs;
@@ -12147,12 +12835,11 @@ fn zirShl(
try sema.requireRuntimeBlock(block, src, runtime_src);
if (block.wantSafety()) {
- const bit_count = scalar_ty.intInfo(target).bits;
+ const bit_count = scalar_ty.intInfo(mod).bits;
if (!std.math.isPowerOfTwo(bit_count)) {
- const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
-
- const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
- const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
+ const bit_count_val = try mod.intValue(scalar_rhs_ty, bit_count);
+ const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: {
+ const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val));
const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
break :ok try block.addInst(.{
.tag = .reduce,
@@ -12181,7 +12868,7 @@ fn zirShl(
} },
});
const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
- const any_ov_bit = if (lhs_ty.zigTypeTag() == .Vector)
+ const any_ov_bit = if (lhs_ty.zigTypeTag(mod) == .Vector)
try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{
@@ -12191,7 +12878,7 @@ fn zirShl(
})
else
ov_bit;
- const zero_ov = try sema.addConstant(Type.u1, Value.zero);
+ const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
try sema.addSafetyCheck(block, no_ov, .shl_overflow);
@@ -12210,6 +12897,7 @@ fn zirShr(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
sema.src = src;
@@ -12221,94 +12909,87 @@ fn zirShr(
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
- const target = sema.mod.getTarget();
- const scalar_ty = lhs_ty.scalarType();
+ const scalar_ty = lhs_ty.scalarType(mod);
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(rhs);
const runtime_src = if (maybe_rhs_val) |rhs_val| rs: {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(lhs_ty);
}
// If rhs is 0, return lhs without doing any calculations.
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
return lhs;
}
- if (scalar_ty.zigTypeTag() != .ComptimeInt) {
- var bits_payload = Value.Payload.U64{
- .base = .{ .tag = .int_u64 },
- .data = scalar_ty.intInfo(target).bits,
- };
- const bit_value = Value.initPayload(&bits_payload.base);
- if (rhs_ty.zigTypeTag() == .Vector) {
+ if (scalar_ty.zigTypeTag(mod) != .ComptimeInt) {
+ const bit_value = try mod.intValue(Type.comptime_int, scalar_ty.intInfo(mod).bits);
+ if (rhs_ty.zigTypeTag(mod) == .Vector) {
var i: usize = 0;
- while (i < rhs_ty.vectorLen()) : (i += 1) {
- var elem_value_buf: Value.ElemValueBuffer = undefined;
- const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf);
- if (rhs_elem.compareHetero(.gte, bit_value, target)) {
+ while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
+ const rhs_elem = try rhs_val.elemValue(mod, i);
+ if (rhs_elem.compareHetero(.gte, bit_value, mod)) {
return sema.fail(block, rhs_src, "shift amount '{}' at index '{d}' is too large for operand type '{}'", .{
- rhs_elem.fmtValue(scalar_ty, sema.mod),
+ rhs_elem.fmtValue(scalar_ty, mod),
i,
- scalar_ty.fmt(sema.mod),
+ scalar_ty.fmt(mod),
});
}
}
- } else if (rhs_val.compareHetero(.gte, bit_value, target)) {
+ } else if (rhs_val.compareHetero(.gte, bit_value, mod)) {
return sema.fail(block, rhs_src, "shift amount '{}' is too large for operand type '{}'", .{
- rhs_val.fmtValue(scalar_ty, sema.mod),
- scalar_ty.fmt(sema.mod),
+ rhs_val.fmtValue(scalar_ty, mod),
+ scalar_ty.fmt(mod),
});
}
}
- if (rhs_ty.zigTypeTag() == .Vector) {
+ if (rhs_ty.zigTypeTag(mod) == .Vector) {
var i: usize = 0;
- while (i < rhs_ty.vectorLen()) : (i += 1) {
- var elem_value_buf: Value.ElemValueBuffer = undefined;
- const rhs_elem = rhs_val.elemValueBuffer(sema.mod, i, &elem_value_buf);
- if (rhs_elem.compareHetero(.lt, Value.zero, target)) {
+ while (i < rhs_ty.vectorLen(mod)) : (i += 1) {
+ const rhs_elem = try rhs_val.elemValue(mod, i);
+ if (rhs_elem.compareHetero(.lt, try mod.intValue(rhs_ty.childType(mod), 0), mod)) {
return sema.fail(block, rhs_src, "shift by negative amount '{}' at index '{d}'", .{
- rhs_elem.fmtValue(scalar_ty, sema.mod),
+ rhs_elem.fmtValue(scalar_ty, mod),
i,
});
}
}
- } else if (rhs_val.compareHetero(.lt, Value.zero, target)) {
+ } else if (rhs_val.compareHetero(.lt, try mod.intValue(rhs_ty, 0), mod)) {
return sema.fail(block, rhs_src, "shift by negative amount '{}'", .{
- rhs_val.fmtValue(scalar_ty, sema.mod),
+ rhs_val.fmtValue(scalar_ty, mod),
});
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(lhs_ty);
}
if (air_tag == .shr_exact) {
// Detect if any ones would be shifted out.
- const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, sema.mod);
+ const truncated = try lhs_val.intTruncBitsAsValue(lhs_ty, sema.arena, .unsigned, rhs_val, mod);
if (!(try truncated.compareAllWithZeroAdvanced(.eq, sema))) {
return sema.fail(block, src, "exact shift shifted out 1 bits", .{});
}
}
- const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, sema.mod);
+ const val = try lhs_val.shr(rhs_val, lhs_ty, sema.arena, mod);
return sema.addConstant(lhs_ty, val);
} else {
break :rs lhs_src;
}
} else rhs_src;
- if (maybe_rhs_val == null and scalar_ty.zigTypeTag() == .ComptimeInt) {
+ if (maybe_rhs_val == null and scalar_ty.zigTypeTag(mod) == .ComptimeInt) {
return sema.fail(block, src, "LHS of shift must be a fixed-width integer type, or RHS must be comptime-known", .{});
}
try sema.requireRuntimeBlock(block, src, runtime_src);
const result = try block.addBinOp(air_tag, lhs, rhs);
if (block.wantSafety()) {
- const bit_count = scalar_ty.intInfo(target).bits;
+ const bit_count = scalar_ty.intInfo(mod).bits;
if (!std.math.isPowerOfTwo(bit_count)) {
- const bit_count_val = try Value.Tag.int_u64.create(sema.arena, bit_count);
+ const bit_count_val = try mod.intValue(rhs_ty.scalarType(mod), bit_count);
- const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
- const bit_count_inst = try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, bit_count_val));
+ const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: {
+ const bit_count_inst = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, bit_count_val));
const lt = try block.addCmpVector(rhs, bit_count_inst, .lt);
break :ok try block.addInst(.{
.tag = .reduce,
@@ -12327,7 +13008,7 @@ fn zirShr(
if (air_tag == .shr_exact) {
const back = try block.addBinOp(.shl, result, rhs);
- const ok = if (rhs_ty.zigTypeTag() == .Vector) ok: {
+ const ok = if (rhs_ty.zigTypeTag(mod) == .Vector) ok: {
const eql = try block.addCmpVector(lhs, back, .eq);
break :ok try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
@@ -12352,6 +13033,7 @@ fn zirBitwise(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -12366,8 +13048,8 @@ fn zirBitwise(
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
- const scalar_type = resolved_type.scalarType();
- const scalar_tag = scalar_type.zigTypeTag();
+ const scalar_type = resolved_type.scalarType(mod);
+ const scalar_tag = scalar_type.zigTypeTag(mod);
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
@@ -12375,7 +13057,7 @@ fn zirBitwise(
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
if (!is_int) {
- return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag()), @tagName(rhs_ty.zigTypeTag()) });
+ return sema.fail(block, src, "invalid operands to binary bitwise expression: '{s}' and '{s}'", .{ @tagName(lhs_ty.zigTypeTag(mod)), @tagName(rhs_ty.zigTypeTag(mod)) });
}
const runtime_src = runtime: {
@@ -12384,9 +13066,9 @@ fn zirBitwise(
if (try sema.resolveMaybeUndefValIntable(casted_lhs)) |lhs_val| {
if (try sema.resolveMaybeUndefValIntable(casted_rhs)) |rhs_val| {
const result_val = switch (air_tag) {
- .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, sema.mod),
- .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, sema.mod),
- .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, sema.mod),
+ .bit_and => try lhs_val.bitwiseAnd(rhs_val, resolved_type, sema.arena, mod),
+ .bit_or => try lhs_val.bitwiseOr(rhs_val, resolved_type, sema.arena, mod),
+ .xor => try lhs_val.bitwiseXor(rhs_val, resolved_type, sema.arena, mod),
else => unreachable,
};
return sema.addConstant(resolved_type, result_val);
@@ -12406,37 +13088,37 @@ fn zirBitNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
const operand = try sema.resolveInst(inst_data.operand);
const operand_type = sema.typeOf(operand);
- const scalar_type = operand_type.scalarType();
+ const scalar_type = operand_type.scalarType(mod);
- if (scalar_type.zigTypeTag() != .Int) {
+ if (scalar_type.zigTypeTag(mod) != .Int) {
return sema.fail(block, src, "unable to perform binary not operation on type '{}'", .{
- operand_type.fmt(sema.mod),
+ operand_type.fmt(mod),
});
}
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) {
+ if (val.isUndef(mod)) {
return sema.addConstUndef(operand_type);
- } else if (operand_type.zigTypeTag() == .Vector) {
- const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen());
- var elem_val_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, vec_len);
+ } else if (operand_type.zigTypeTag(mod) == .Vector) {
+ const vec_len = try sema.usizeCast(block, operand_src, operand_type.vectorLen(mod));
+ const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
- const elem_val = val.elemValueBuffer(sema.mod, i, &elem_val_buf);
- elem.* = try elem_val.bitwiseNot(scalar_type, sema.arena, sema.mod);
+ const elem_val = try val.elemValue(mod, i);
+ elem.* = try (try elem_val.bitwiseNot(scalar_type, sema.arena, mod)).intern(scalar_type, mod);
}
- return sema.addConstant(
- operand_type,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ return sema.addConstant(operand_type, (try mod.intern(.{ .aggregate = .{
+ .ty = operand_type.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
} else {
- const result_val = try val.bitwiseNot(operand_type, sema.arena, sema.mod);
+ const result_val = try val.bitwiseNot(operand_type, sema.arena, mod);
return sema.addConstant(operand_type, result_val);
}
}
@@ -12452,18 +13134,19 @@ fn analyzeTupleCat(
lhs: Air.Inst.Ref,
rhs: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
const src = LazySrcLoc.nodeOffset(src_node);
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
- const lhs_len = lhs_ty.structFieldCount();
- const rhs_len = rhs_ty.structFieldCount();
+ const lhs_len = lhs_ty.structFieldCount(mod);
+ const rhs_len = rhs_ty.structFieldCount(mod);
const dest_fields = lhs_len + rhs_len;
if (dest_fields == 0) {
- return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));
+ return sema.addConstant(Type.empty_struct_literal, Value.empty_struct);
}
if (lhs_len == 0) {
return rhs;
@@ -12473,42 +13156,48 @@ fn analyzeTupleCat(
}
const final_len = try sema.usizeCast(block, rhs_src, dest_fields);
- const types = try sema.arena.alloc(Type, final_len);
- const values = try sema.arena.alloc(Value, final_len);
+ const types = try sema.arena.alloc(InternPool.Index, final_len);
+ const values = try sema.arena.alloc(InternPool.Index, final_len);
const opt_runtime_src = rs: {
var runtime_src: ?LazySrcLoc = null;
var i: u32 = 0;
while (i < lhs_len) : (i += 1) {
- types[i] = lhs_ty.structFieldType(i);
- const default_val = lhs_ty.structFieldDefaultValue(i);
- values[i] = default_val;
+ types[i] = lhs_ty.structFieldType(i, mod).toIntern();
+ const default_val = lhs_ty.structFieldDefaultValue(i, mod);
+ values[i] = default_val.toIntern();
const operand_src = lhs_src; // TODO better source location
- if (default_val.tag() == .unreachable_value) {
+ if (default_val.toIntern() == .unreachable_value) {
runtime_src = operand_src;
+ values[i] = .none;
}
}
i = 0;
while (i < rhs_len) : (i += 1) {
- types[i + lhs_len] = rhs_ty.structFieldType(i);
- const default_val = rhs_ty.structFieldDefaultValue(i);
- values[i + lhs_len] = default_val;
+ types[i + lhs_len] = rhs_ty.structFieldType(i, mod).toIntern();
+ const default_val = rhs_ty.structFieldDefaultValue(i, mod);
+ values[i + lhs_len] = default_val.toIntern();
const operand_src = rhs_src; // TODO better source location
- if (default_val.tag() == .unreachable_value) {
+ if (default_val.toIntern() == .unreachable_value) {
runtime_src = operand_src;
+ values[i + lhs_len] = .none;
}
}
break :rs runtime_src;
};
- const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
+ const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
.types = types,
.values = values,
- });
+ .names = &.{},
+ } });
const runtime_src = opt_runtime_src orelse {
- const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstant(tuple_ty, tuple_val);
+ const tuple_val = try mod.intern(.{ .aggregate = .{
+ .ty = tuple_ty,
+ .storage = .{ .elems = values },
+ } });
+ return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
};
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -12526,13 +13215,14 @@ fn analyzeTupleCat(
try sema.tupleFieldValByIndex(block, operand_src, rhs, i, rhs_ty);
}
- return block.addAggregateInit(tuple_ty, element_refs);
+ return block.addAggregateInit(tuple_ty.toType(), element_refs);
}
fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const lhs = try sema.resolveInst(extra.lhs);
@@ -12541,8 +13231,8 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const rhs_ty = sema.typeOf(rhs);
const src = inst_data.src();
- const lhs_is_tuple = lhs_ty.isTuple();
- const rhs_is_tuple = rhs_ty.isTuple();
+ const lhs_is_tuple = lhs_ty.isTuple(mod);
+ const rhs_is_tuple = rhs_ty.isTuple(mod);
if (lhs_is_tuple and rhs_is_tuple) {
return sema.analyzeTupleCat(block, inst_data.src_node, lhs, rhs);
}
@@ -12552,11 +13242,11 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, rhs_ty) orelse lhs_info: {
if (lhs_is_tuple) break :lhs_info @as(Type.ArrayInfo, undefined);
- return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)});
+ return sema.fail(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)});
};
const rhs_info = try sema.getArrayCatInfo(block, rhs_src, rhs, lhs_ty) orelse {
assert(!rhs_is_tuple);
- return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(sema.mod)});
+ return sema.fail(block, rhs_src, "expected indexable; found '{}'", .{rhs_ty.fmt(mod)});
};
const resolved_elem_ty = t: {
@@ -12618,73 +13308,71 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
),
};
- const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, sema.mod);
+ const result_ty = try Type.array(sema.arena, result_len, res_sent_val, resolved_elem_ty, mod);
const ptr_addrspace = p: {
- if (lhs_ty.zigTypeTag() == .Pointer) break :p lhs_ty.ptrAddressSpace();
- if (rhs_ty.zigTypeTag() == .Pointer) break :p rhs_ty.ptrAddressSpace();
+ if (lhs_ty.zigTypeTag(mod) == .Pointer) break :p lhs_ty.ptrAddressSpace(mod);
+ if (rhs_ty.zigTypeTag(mod) == .Pointer) break :p rhs_ty.ptrAddressSpace(mod);
break :p null;
};
- const runtime_src = if (switch (lhs_ty.zigTypeTag()) {
+ const runtime_src = if (switch (lhs_ty.zigTypeTag(mod)) {
.Array, .Struct => try sema.resolveMaybeUndefVal(lhs),
.Pointer => try sema.resolveDefinedValue(block, lhs_src, lhs),
else => unreachable,
}) |lhs_val| rs: {
- if (switch (rhs_ty.zigTypeTag()) {
+ if (switch (rhs_ty.zigTypeTag(mod)) {
.Array, .Struct => try sema.resolveMaybeUndefVal(rhs),
.Pointer => try sema.resolveDefinedValue(block, rhs_src, rhs),
else => unreachable,
}) |rhs_val| {
- const lhs_sub_val = if (lhs_ty.isSinglePointer())
+ const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
(try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
else
lhs_val;
- const rhs_sub_val = if (rhs_ty.isSinglePointer())
+ const rhs_sub_val = if (rhs_ty.isSinglePointer(mod))
(try sema.pointerDeref(block, rhs_src, rhs_val, rhs_ty)).?
else
rhs_val;
- const final_len_including_sent = result_len + @boolToInt(res_sent_val != null);
- const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
+ const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
var elem_i: usize = 0;
while (elem_i < lhs_len) : (elem_i += 1) {
const lhs_elem_i = elem_i;
- const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i) else lhs_info.elem_type;
- const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i) else Value.initTag(.unreachable_value);
- const elem_val = if (elem_default_val.tag() == .unreachable_value) try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_elem_i) else elem_default_val;
+ const elem_ty = if (lhs_is_tuple) lhs_ty.structFieldType(lhs_elem_i, mod) else lhs_info.elem_type;
+ const elem_default_val = if (lhs_is_tuple) lhs_ty.structFieldDefaultValue(lhs_elem_i, mod) else Value.@"unreachable";
+ const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try lhs_sub_val.elemValue(mod, lhs_elem_i) else elem_default_val;
const elem_val_inst = try sema.addConstant(elem_ty, elem_val);
const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
- element_vals[elem_i] = coerced_elem_val;
+ element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod);
}
while (elem_i < result_len) : (elem_i += 1) {
const rhs_elem_i = elem_i - lhs_len;
- const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i) else rhs_info.elem_type;
- const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i) else Value.initTag(.unreachable_value);
- const elem_val = if (elem_default_val.tag() == .unreachable_value) try rhs_sub_val.elemValue(sema.mod, sema.arena, rhs_elem_i) else elem_default_val;
+ const elem_ty = if (rhs_is_tuple) rhs_ty.structFieldType(rhs_elem_i, mod) else rhs_info.elem_type;
+ const elem_default_val = if (rhs_is_tuple) rhs_ty.structFieldDefaultValue(rhs_elem_i, mod) else Value.@"unreachable";
+ const elem_val = if (elem_default_val.toIntern() == .unreachable_value) try rhs_sub_val.elemValue(mod, rhs_elem_i) else elem_default_val;
const elem_val_inst = try sema.addConstant(elem_ty, elem_val);
const coerced_elem_val_inst = try sema.coerce(block, resolved_elem_ty, elem_val_inst, .unneeded);
const coerced_elem_val = try sema.resolveConstMaybeUndefVal(block, .unneeded, coerced_elem_val_inst, "");
- element_vals[elem_i] = coerced_elem_val;
- }
- if (res_sent_val) |sent_val| {
- element_vals[result_len] = sent_val;
+ element_vals[elem_i] = try coerced_elem_val.intern(resolved_elem_ty, mod);
}
- const val = try Value.Tag.aggregate.create(sema.arena, element_vals);
- return sema.addConstantMaybeRef(block, result_ty, val, ptr_addrspace != null);
+ return sema.addConstantMaybeRef(block, result_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = result_ty.toIntern(),
+ .storage = .{ .elems = element_vals },
+ } })).toValue(), ptr_addrspace != null);
} else break :rs rhs_src;
} else lhs_src;
try sema.requireRuntimeBlock(block, src, runtime_src);
if (ptr_addrspace) |ptr_as| {
- const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const alloc_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = result_ty,
.@"addrspace" = ptr_as,
});
const alloc = try block.addTy(.alloc, alloc_ty);
- const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = resolved_elem_ty,
.@"addrspace" = ptr_as,
});
@@ -12706,7 +13394,7 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
if (res_sent_val) |sent_val| {
const elem_index = try sema.addIntUnsigned(Type.usize, result_len);
const elem_ptr = try block.addPtrElemPtr(alloc, elem_index, elem_ptr_ty);
- const init = try sema.addConstant(lhs_info.elem_type, sent_val);
+ const init = try sema.addConstant(lhs_info.elem_type, try mod.getCoerced(sent_val, lhs_info.elem_type));
try sema.storePtr2(block, src, elem_ptr, src, init, lhs_src, .store);
}
@@ -12732,11 +13420,12 @@ fn zirArrayCat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Inst.Ref, peer_ty: Type) !?Type.ArrayInfo {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
- switch (operand_ty.zigTypeTag()) {
- .Array => return operand_ty.arrayInfo(),
+ switch (operand_ty.zigTypeTag(mod)) {
+ .Array => return operand_ty.arrayInfo(mod),
.Pointer => {
- const ptr_info = operand_ty.ptrInfo().data;
+ const ptr_info = operand_ty.ptrInfo(mod);
switch (ptr_info.size) {
// TODO: in the Many case here this should only work if the type
// has a sentinel, and this code should compute the length based
@@ -12746,24 +13435,24 @@ fn getArrayCatInfo(sema: *Sema, block: *Block, src: LazySrcLoc, operand: Air.Ins
return Type.ArrayInfo{
.elem_type = ptr_info.pointee_type,
.sentinel = ptr_info.sentinel,
- .len = val.sliceLen(sema.mod),
+ .len = val.sliceLen(mod),
};
},
.One => {
- if (ptr_info.pointee_type.zigTypeTag() == .Array) {
- return ptr_info.pointee_type.arrayInfo();
+ if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) {
+ return ptr_info.pointee_type.arrayInfo(mod);
}
},
.C => {},
}
},
.Struct => {
- if (operand_ty.isTuple() and peer_ty.isIndexable()) {
- assert(!peer_ty.isTuple());
+ if (operand_ty.isTuple(mod) and peer_ty.isIndexable(mod)) {
+ assert(!peer_ty.isTuple(mod));
return .{
- .elem_type = peer_ty.elemType2(),
+ .elem_type = peer_ty.elemType2(mod),
.sentinel = null,
- .len = operand_ty.arrayLen(),
+ .len = operand_ty.arrayLen(mod),
};
}
},
@@ -12777,52 +13466,54 @@ fn analyzeTupleMul(
block: *Block,
src_node: i32,
operand: Air.Inst.Ref,
- factor: u64,
+ factor: usize,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
const src = LazySrcLoc.nodeOffset(src_node);
const lhs_src: LazySrcLoc = .{ .node_offset_bin_lhs = src_node };
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = src_node };
- const tuple_len = operand_ty.structFieldCount();
- const final_len_u64 = std.math.mul(u64, tuple_len, factor) catch
+ const tuple_len = operand_ty.structFieldCount(mod);
+ const final_len = std.math.mul(usize, tuple_len, factor) catch
return sema.fail(block, rhs_src, "operation results in overflow", .{});
- if (final_len_u64 == 0) {
- return sema.addConstant(Type.initTag(.empty_struct_literal), Value.initTag(.empty_struct_value));
+ if (final_len == 0) {
+ return sema.addConstant(Type.empty_struct_literal, Value.empty_struct);
}
- const final_len = try sema.usizeCast(block, rhs_src, final_len_u64);
-
- const types = try sema.arena.alloc(Type, final_len);
- const values = try sema.arena.alloc(Value, final_len);
+ const types = try sema.arena.alloc(InternPool.Index, final_len);
+ const values = try sema.arena.alloc(InternPool.Index, final_len);
const opt_runtime_src = rs: {
var runtime_src: ?LazySrcLoc = null;
- var i: u32 = 0;
- while (i < tuple_len) : (i += 1) {
- types[i] = operand_ty.structFieldType(i);
- values[i] = operand_ty.structFieldDefaultValue(i);
+ for (0..tuple_len) |i| {
+ types[i] = operand_ty.structFieldType(i, mod).toIntern();
+ values[i] = operand_ty.structFieldDefaultValue(i, mod).toIntern();
const operand_src = lhs_src; // TODO better source location
- if (values[i].tag() == .unreachable_value) {
+ if (values[i] == .unreachable_value) {
runtime_src = operand_src;
+ values[i] = .none; // TODO don't treat unreachable_value as special
}
}
- i = 0;
- while (i < factor) : (i += 1) {
- mem.copyForwards(Type, types[tuple_len * i ..], types[0..tuple_len]);
- mem.copyForwards(Value, values[tuple_len * i ..], values[0..tuple_len]);
+ for (0..factor) |i| {
+ mem.copyForwards(InternPool.Index, types[tuple_len * i ..], types[0..tuple_len]);
+ mem.copyForwards(InternPool.Index, values[tuple_len * i ..], values[0..tuple_len]);
}
break :rs runtime_src;
};
- const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
+ const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
.types = types,
.values = values,
- });
+ .names = &.{},
+ } });
const runtime_src = opt_runtime_src orelse {
- const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstant(tuple_ty, tuple_val);
+ const tuple_val = try mod.intern(.{ .aggregate = .{
+ .ty = tuple_ty,
+ .storage = .{ .elems = values },
+ } });
+ return sema.addConstant(tuple_ty.toType(), tuple_val.toValue());
};
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -12838,13 +13529,14 @@ fn analyzeTupleMul(
@memcpy(element_refs[tuple_len * i ..][0..tuple_len], element_refs[0..tuple_len]);
}
- return block.addAggregateInit(tuple_ty, element_refs);
+ return block.addAggregateInit(tuple_ty.toType(), element_refs);
}
fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const lhs = try sema.resolveInst(extra.lhs);
@@ -12854,18 +13546,19 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const operator_src: LazySrcLoc = .{ .node_offset_main_token = inst_data.src_node };
const rhs_src: LazySrcLoc = .{ .node_offset_bin_rhs = inst_data.src_node };
- if (lhs_ty.isTuple()) {
+ if (lhs_ty.isTuple(mod)) {
// In `**` rhs must be comptime-known, but lhs can be runtime-known
const factor = try sema.resolveInt(block, rhs_src, extra.rhs, Type.usize, "array multiplication factor must be comptime-known");
- return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor);
+ const factor_casted = try sema.usizeCast(block, rhs_src, factor);
+ return sema.analyzeTupleMul(block, inst_data.src_node, lhs, factor_casted);
}
// Analyze the lhs first, to catch the case that someone tried to do exponentiation
const lhs_info = try sema.getArrayCatInfo(block, lhs_src, lhs, lhs_ty) orelse {
const msg = msg: {
- const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, lhs_src, "expected indexable; found '{}'", .{lhs_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- switch (lhs_ty.zigTypeTag()) {
+ switch (lhs_ty.zigTypeTag(mod)) {
.Int, .Float, .ComptimeFloat, .ComptimeInt, .Vector => {
try sema.errNote(block, operator_src, msg, "this operator multiplies arrays; use std.math.pow for exponentiation", .{});
},
@@ -12883,15 +13576,13 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
return sema.fail(block, rhs_src, "operation results in overflow", .{});
const result_len = try sema.usizeCast(block, src, result_len_u64);
- const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, sema.mod);
+ const result_ty = try Type.array(sema.arena, result_len, lhs_info.sentinel, lhs_info.elem_type, mod);
- const ptr_addrspace = if (lhs_ty.zigTypeTag() == .Pointer) lhs_ty.ptrAddressSpace() else null;
+ const ptr_addrspace = if (lhs_ty.zigTypeTag(mod) == .Pointer) lhs_ty.ptrAddressSpace(mod) else null;
const lhs_len = try sema.usizeCast(block, lhs_src, lhs_info.len);
if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val| {
- const final_len_including_sent = result_len + @boolToInt(lhs_info.sentinel != null);
-
- const lhs_sub_val = if (lhs_ty.isSinglePointer())
+ const lhs_sub_val = if (lhs_ty.isSinglePointer(mod))
(try sema.pointerDeref(block, lhs_src, lhs_val, lhs_ty)).?
else
lhs_val;
@@ -12899,38 +13590,41 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const val = v: {
// Optimization for the common pattern of a single element repeated N times, such
// as zero-filling a byte array.
- if (lhs_len == 1) {
- const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, 0);
- break :v try Value.Tag.repeated.create(sema.arena, elem_val);
+ if (lhs_len == 1 and lhs_info.sentinel == null) {
+ const elem_val = try lhs_sub_val.elemValue(mod, 0);
+ break :v try mod.intern(.{ .aggregate = .{
+ .ty = result_ty.toIntern(),
+ .storage = .{ .repeated_elem = elem_val.toIntern() },
+ } });
}
- const element_vals = try sema.arena.alloc(Value, final_len_including_sent);
+ const element_vals = try sema.arena.alloc(InternPool.Index, result_len);
var elem_i: usize = 0;
while (elem_i < result_len) {
var lhs_i: usize = 0;
while (lhs_i < lhs_len) : (lhs_i += 1) {
- const elem_val = try lhs_sub_val.elemValue(sema.mod, sema.arena, lhs_i);
- element_vals[elem_i] = elem_val;
+ const elem_val = try lhs_sub_val.elemValue(mod, lhs_i);
+ element_vals[elem_i] = elem_val.toIntern();
elem_i += 1;
}
}
- if (lhs_info.sentinel) |sent_val| {
- element_vals[result_len] = sent_val;
- }
- break :v try Value.Tag.aggregate.create(sema.arena, element_vals);
+ break :v try mod.intern(.{ .aggregate = .{
+ .ty = result_ty.toIntern(),
+ .storage = .{ .elems = element_vals },
+ } });
};
- return sema.addConstantMaybeRef(block, result_ty, val, ptr_addrspace != null);
+ return sema.addConstantMaybeRef(block, result_ty, val.toValue(), ptr_addrspace != null);
}
try sema.requireRuntimeBlock(block, src, lhs_src);
if (ptr_addrspace) |ptr_as| {
- const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const alloc_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = result_ty,
.@"addrspace" = ptr_as,
});
const alloc = try block.addTy(.alloc, alloc_ty);
- const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = lhs_info.elem_type,
.@"addrspace" = ptr_as,
});
@@ -12973,6 +13667,7 @@ fn zirArrayMul(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const lhs_src = src;
@@ -12980,34 +13675,31 @@ fn zirNegate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const rhs = try sema.resolveInst(inst_data.operand);
const rhs_ty = sema.typeOf(rhs);
- const rhs_scalar_ty = rhs_ty.scalarType();
+ const rhs_scalar_ty = rhs_ty.scalarType(mod);
- if (rhs_scalar_ty.isUnsignedInt() or switch (rhs_scalar_ty.zigTypeTag()) {
+ if (rhs_scalar_ty.isUnsignedInt(mod) or switch (rhs_scalar_ty.zigTypeTag(mod)) {
.Int, .ComptimeInt, .Float, .ComptimeFloat => false,
else => true,
}) {
- return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)});
+ return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(mod)});
}
if (rhs_scalar_ty.isAnyFloat()) {
// We handle float negation here to ensure negative zero is represented in the bits.
if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
- if (rhs_val.isUndef()) return sema.addConstUndef(rhs_ty);
- return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, sema.mod));
+ if (rhs_val.isUndef(mod)) return sema.addConstUndef(rhs_ty);
+ return sema.addConstant(rhs_ty, try rhs_val.floatNeg(rhs_ty, sema.arena, mod));
}
try sema.requireRuntimeBlock(block, src, null);
return block.addUnOp(if (block.float_mode == .Optimized) .neg_optimized else .neg, rhs);
}
- const lhs = if (rhs_ty.zigTypeTag() == .Vector)
- try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
- else
- try sema.resolveInst(.zero);
-
+ const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0)));
return sema.analyzeArithmetic(block, .sub, lhs, rhs, src, lhs_src, rhs_src, true);
}
fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const lhs_src = src;
@@ -13015,18 +13707,14 @@ fn zirNegateWrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
const rhs = try sema.resolveInst(inst_data.operand);
const rhs_ty = sema.typeOf(rhs);
- const rhs_scalar_ty = rhs_ty.scalarType();
+ const rhs_scalar_ty = rhs_ty.scalarType(mod);
- switch (rhs_scalar_ty.zigTypeTag()) {
+ switch (rhs_scalar_ty.zigTypeTag(mod)) {
.Int, .ComptimeInt, .Float, .ComptimeFloat => {},
- else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(sema.mod)}),
+ else => return sema.fail(block, src, "negation of type '{}'", .{rhs_ty.fmt(mod)}),
}
- const lhs = if (rhs_ty.zigTypeTag() == .Vector)
- try sema.addConstant(rhs_ty, try Value.Tag.repeated.create(sema.arena, Value.zero))
- else
- try sema.resolveInst(.zero);
-
+ const lhs = try sema.addConstant(rhs_ty, try sema.splat(rhs_ty, try mod.intValue(rhs_scalar_ty, 0)));
return sema.analyzeArithmetic(block, .subwrap, lhs, rhs, src, lhs_src, rhs_src, true);
}
@@ -13052,6 +13740,7 @@ fn zirArithmetic(
}
fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -13062,8 +13751,8 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -13072,25 +13761,22 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
- const is_vector = resolved_type.zigTypeTag() == .Vector;
-
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const lhs_scalar_ty = lhs_ty.scalarType();
- const rhs_scalar_ty = rhs_ty.scalarType();
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const lhs_scalar_ty = lhs_ty.scalarType(mod);
+ const rhs_scalar_ty = rhs_ty.scalarType(mod);
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
- if ((lhs_ty.zigTypeTag() == .ComptimeFloat and rhs_ty.zigTypeTag() == .ComptimeInt) or
- (lhs_ty.zigTypeTag() == .ComptimeInt and rhs_ty.zigTypeTag() == .ComptimeFloat))
+ if ((lhs_ty.zigTypeTag(mod) == .ComptimeFloat and rhs_ty.zigTypeTag(mod) == .ComptimeInt) or
+ (lhs_ty.zigTypeTag(mod) == .ComptimeInt and rhs_ty.zigTypeTag(mod) == .ComptimeFloat))
{
// If it makes a difference whether we coerce to ints or floats before doing the division, error.
// If lhs % rhs is 0, it doesn't matter.
@@ -13098,9 +13784,12 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const rhs_val = maybe_rhs_val orelse unreachable;
const rem = lhs_val.floatRem(rhs_val, resolved_type, sema.arena, mod) catch unreachable;
if (!rem.compareAllWithZero(.eq, mod)) {
- return sema.fail(block, src, "ambiguous coercion of division operands '{s}' and '{s}'; non-zero remainder '{}'", .{
- @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()), rem.fmtValue(resolved_type, sema.mod),
- });
+ return sema.fail(
+ block,
+ src,
+ "ambiguous coercion of division operands '{}' and '{}'; non-zero remainder '{}'",
+ .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod), rem.fmtValue(resolved_type, mod) },
+ );
}
}
@@ -13134,17 +13823,20 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
switch (scalar_tag) {
.Int, .ComptimeInt, .ComptimeFloat => {
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
+ if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
+ .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
+ else => unreachable,
+ };
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13158,10 +13850,10 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const runtime_src = rs: {
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
- if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
+ if (lhs_val.isUndef(mod)) {
+ if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) {
if (maybe_rhs_val) |rhs_val| {
- if (try sema.compareAll(rhs_val, .neq, Value.negative_one, resolved_type)) {
+ if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) {
return sema.addConstUndef(resolved_type);
}
}
@@ -13172,10 +13864,10 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
- const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod);
- var vector_index: usize = undefined;
- if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
+ var overflow_idx: ?usize = null;
+ const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod);
+ if (overflow_idx) |vec_idx| {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx);
}
return sema.addConstant(resolved_type, res);
} else {
@@ -13200,8 +13892,13 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
const air_tag = if (is_int) blk: {
- if (lhs_ty.isSignedInt() or rhs_ty.isSignedInt()) {
- return sema.fail(block, src, "division with '{s}' and '{s}': signed integers must use @divTrunc, @divFloor, or @divExact", .{ @tagName(lhs_ty.tag()), @tagName(rhs_ty.tag()) });
+ if (lhs_ty.isSignedInt(mod) or rhs_ty.isSignedInt(mod)) {
+ return sema.fail(
+ block,
+ src,
+ "division with '{}' and '{}': signed integers must use @divTrunc, @divFloor, or @divExact",
+ .{ lhs_ty.fmt(mod), rhs_ty.fmt(mod) },
+ );
}
break :blk Air.Inst.Tag.div_trunc;
} else switch (block.float_mode) {
@@ -13212,6 +13909,7 @@ fn zirDiv(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -13222,8 +13920,8 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -13232,19 +13930,16 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
- const is_vector = resolved_type.zigTypeTag() == .Vector;
-
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const lhs_scalar_ty = lhs_ty.scalarType();
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const lhs_scalar_ty = lhs_ty.scalarType(mod);
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_exact);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
@@ -13266,19 +13961,22 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// If the lhs is undefined, compile error because there is a possible
// value for which the division would result in a remainder.
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
+ .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
+ else => unreachable,
+ };
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13293,10 +13991,10 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
if (!(modulus_val.compareAllWithZero(.eq, mod))) {
return sema.fail(block, src, "exact division produced remainder", .{});
}
- const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod);
- var vector_index: usize = undefined;
- if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
+ var overflow_idx: ?usize = null;
+ const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod);
+ if (overflow_idx) |vec_idx| {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx);
}
return sema.addConstant(resolved_type, res);
} else {
@@ -13328,7 +14026,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const ok = if (!is_int) ok: {
const floored = try block.addUnOp(.floor, result);
- if (resolved_type.zigTypeTag() == .Vector) {
+ if (resolved_type.zigTypeTag(mod) == .Vector) {
const eql = try block.addCmpVector(result, floored, .eq);
break :ok try block.addInst(.{
.tag = switch (block.float_mode) {
@@ -13350,8 +14048,13 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} else ok: {
const remainder = try block.addBinOp(.rem, casted_lhs, casted_rhs);
- if (resolved_type.zigTypeTag() == .Vector) {
- const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
+ .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
+ else => unreachable,
+ };
+ if (resolved_type.zigTypeTag(mod) == .Vector) {
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
const zero = try sema.addConstant(resolved_type, zero_val);
const eql = try block.addCmpVector(remainder, zero, .eq);
break :ok try block.addInst(.{
@@ -13362,7 +14065,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} },
});
} else {
- const zero = try sema.addConstant(resolved_type, Value.zero);
+ const zero = try sema.addConstant(resolved_type, scalar_zero);
const is_in_range = try block.addBinOp(.cmp_eq, remainder, zero);
break :ok is_in_range;
}
@@ -13375,6 +14078,7 @@ fn zirDivExact(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -13385,8 +14089,8 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -13395,20 +14099,17 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
- const is_vector = resolved_type.zigTypeTag() == .Vector;
-
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const lhs_scalar_ty = lhs_ty.scalarType();
- const rhs_scalar_ty = rhs_ty.scalarType();
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const lhs_scalar_ty = lhs_ty.scalarType(mod);
+ const rhs_scalar_ty = rhs_ty.scalarType(mod);
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_floor);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
@@ -13433,17 +14134,20 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// value (zero) for which the division would be illegal behavior.
// If the lhs is undefined, result is undefined.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
+ if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
+ .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
+ else => unreachable,
+ };
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13452,10 +14156,10 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// TODO: if the RHS is one, return the LHS directly
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
- if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
+ if (lhs_val.isUndef(mod)) {
+ if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) {
if (maybe_rhs_val) |rhs_val| {
- if (try sema.compareAll(rhs_val, .neq, Value.negative_one, resolved_type)) {
+ if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) {
return sema.addConstUndef(resolved_type);
}
}
@@ -13491,6 +14195,7 @@ fn zirDivFloor(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -13501,8 +14206,8 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -13511,20 +14216,17 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
- const is_vector = resolved_type.zigTypeTag() == .Vector;
-
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const lhs_scalar_ty = lhs_ty.scalarType();
- const rhs_scalar_ty = rhs_ty.scalarType();
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const lhs_scalar_ty = lhs_ty.scalarType(mod);
+ const rhs_scalar_ty = rhs_ty.scalarType(mod);
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .div_trunc);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
@@ -13549,17 +14251,20 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// value (zero) for which the division would be illegal behavior.
// If the lhs is undefined, result is undefined.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
+ if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
+ .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
+ else => unreachable,
+ };
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13567,10 +14272,10 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
- if (lhs_scalar_ty.isSignedInt() and rhs_scalar_ty.isSignedInt()) {
+ if (lhs_val.isUndef(mod)) {
+ if (lhs_scalar_ty.isSignedInt(mod) and rhs_scalar_ty.isSignedInt(mod)) {
if (maybe_rhs_val) |rhs_val| {
- if (try sema.compareAll(rhs_val, .neq, Value.negative_one, resolved_type)) {
+ if (try sema.compareAll(rhs_val, .neq, try mod.intValue(resolved_type, -1), resolved_type)) {
return sema.addConstUndef(resolved_type);
}
}
@@ -13581,10 +14286,10 @@ fn zirDivTrunc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
- const res = try lhs_val.intDiv(rhs_val, resolved_type, sema.arena, mod);
- var vector_index: usize = undefined;
- if (!(try sema.intFitsInType(res, resolved_type, &vector_index))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, res, vector_index);
+ var overflow_idx: ?usize = null;
+ const res = try lhs_val.intDiv(rhs_val, resolved_type, &overflow_idx, sema.arena, mod);
+ if (overflow_idx) |vec_idx| {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, res, vec_idx);
}
return sema.addConstant(resolved_type, res);
} else {
@@ -13618,39 +14323,34 @@ fn addDivIntOverflowSafety(
casted_rhs: Air.Inst.Ref,
is_int: bool,
) CompileError!void {
+ const mod = sema.mod;
if (!is_int) return;
// If the LHS is unsigned, it cannot cause overflow.
- if (!lhs_scalar_ty.isSignedInt()) return;
-
- const mod = sema.mod;
- const target = mod.getTarget();
+ if (!lhs_scalar_ty.isSignedInt(mod)) return;
// If the LHS is widened to a larger integer type, no overflow is possible.
- if (lhs_scalar_ty.intInfo(target).bits < resolved_type.intInfo(target).bits) {
+ if (lhs_scalar_ty.intInfo(mod).bits < resolved_type.intInfo(mod).bits) {
return;
}
- const min_int = try resolved_type.minInt(sema.arena, target);
- const neg_one_scalar = try Value.Tag.int_i64.create(sema.arena, -1);
- const neg_one = if (resolved_type.zigTypeTag() == .Vector)
- try Value.Tag.repeated.create(sema.arena, neg_one_scalar)
- else
- neg_one_scalar;
+ const min_int = try resolved_type.minInt(mod, resolved_type);
+ const neg_one_scalar = try mod.intValue(lhs_scalar_ty, -1);
+ const neg_one = try sema.splat(resolved_type, neg_one_scalar);
// If the LHS is comptime-known to be not equal to the min int,
// no overflow is possible.
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return;
+ if (try lhs_val.compareAll(.neq, min_int, resolved_type, mod)) return;
}
// If the RHS is comptime-known to not be equal to -1, no overflow is possible.
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return;
+ if (try rhs_val.compareAll(.neq, neg_one, resolved_type, mod)) return;
}
var ok: Air.Inst.Ref = .none;
- if (resolved_type.zigTypeTag() == .Vector) {
+ if (resolved_type.zigTypeTag(mod) == .Vector) {
if (maybe_lhs_val == null) {
const min_int_ref = try sema.addConstant(resolved_type, min_int);
ok = try block.addCmpVector(casted_lhs, min_int_ref, .neq);
@@ -13706,8 +14406,13 @@ fn addDivByZeroSafety(
// emitted above.
if (maybe_rhs_val != null) return;
- const ok = if (resolved_type.zigTypeTag() == .Vector) ok: {
- const zero_val = try Value.Tag.repeated.create(sema.arena, Value.zero);
+ const mod = sema.mod;
+ const scalar_zero = if (is_int)
+ try mod.intValue(resolved_type.scalarType(mod), 0)
+ else
+ try mod.floatValue(resolved_type.scalarType(mod), 0.0);
+ const ok = if (resolved_type.zigTypeTag(mod) == .Vector) ok: {
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
const zero = try sema.addConstant(resolved_type, zero_val);
const ok = try block.addCmpVector(casted_rhs, zero, .neq);
break :ok try block.addInst(.{
@@ -13718,7 +14423,7 @@ fn addDivByZeroSafety(
} },
});
} else ok: {
- const zero = try sema.addConstant(resolved_type, Value.zero);
+ const zero = try sema.addConstant(resolved_type, scalar_zero);
break :ok try block.addBinOp(if (is_int) .cmp_neq else .cmp_neq_optimized, casted_rhs, zero);
};
try sema.addSafetyCheck(block, ok, .divide_by_zero);
@@ -13733,6 +14438,7 @@ fn airTag(block: *Block, is_int: bool, normal: Air.Inst.Tag, optimized: Air.Inst
}
fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -13743,8 +14449,8 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -13753,20 +14459,19 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
- const is_vector = resolved_type.zigTypeTag() == .Vector;
+ const is_vector = resolved_type.zigTypeTag(mod) == .Vector;
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const lhs_scalar_ty = lhs_ty.scalarType();
- const rhs_scalar_ty = rhs_ty.scalarType();
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const lhs_scalar_ty = lhs_ty.scalarType(mod);
+ const rhs_scalar_ty = rhs_ty.scalarType(mod);
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod_rem);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
@@ -13786,20 +14491,26 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
// then emit a compile error saying you have to pick one.
if (is_int) {
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, lhs_src);
}
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(resolved_type.scalarType(mod), 0.0),
+ .ComptimeInt, .Int => try mod.intValue(resolved_type.scalarType(mod), 0),
+ else => unreachable,
+ };
+ const zero_val = if (is_vector) (try mod.intern(.{ .aggregate = .{
+ .ty = resolved_type.toIntern(),
+ .storage = .{ .repeated_elem = scalar_zero.toIntern() },
+ } })).toValue() else scalar_zero;
return sema.addConstant(resolved_type, zero_val);
}
- } else if (lhs_scalar_ty.isSignedInt()) {
+ } else if (lhs_scalar_ty.isSignedInt(mod)) {
return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13820,7 +14531,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
return sema.addConstant(resolved_type, rem_result);
}
break :rs lhs_src;
- } else if (rhs_scalar_ty.isSignedInt()) {
+ } else if (rhs_scalar_ty.isSignedInt(mod)) {
return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
} else {
break :rs rhs_src;
@@ -13828,7 +14539,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
// float operands
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13838,7 +14549,7 @@ fn zirModRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
return sema.failWithModRemNegative(block, rhs_src, lhs_ty, rhs_ty);
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef() or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
+ if (lhs_val.isUndef(mod) or !(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))) {
return sema.failWithModRemNegative(block, lhs_src, lhs_ty, rhs_ty);
}
return sema.addConstant(
@@ -13869,32 +14580,31 @@ fn intRem(
lhs: Value,
rhs: Value,
) CompileError!Value {
- if (ty.zigTypeTag() == .Vector) {
- const result_data = try sema.arena.alloc(Value, ty.vectorLen());
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Vector) {
+ const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
+ const scalar_ty = ty.scalarType(mod);
for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- scalar.* = try sema.intRemScalar(lhs_elem, rhs_elem);
+ const lhs_elem = try lhs.elemValue(mod, i);
+ const rhs_elem = try rhs.elemValue(mod, i);
+ scalar.* = try (try sema.intRemScalar(lhs_elem, rhs_elem, scalar_ty)).intern(scalar_ty, mod);
}
- return Value.Tag.aggregate.create(sema.arena, result_data);
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue();
}
- return sema.intRemScalar(lhs, rhs);
+ return sema.intRemScalar(lhs, rhs, ty);
}
-fn intRemScalar(
- sema: *Sema,
- lhs: Value,
- rhs: Value,
-) CompileError!Value {
- const target = sema.mod.getTarget();
+fn intRemScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) CompileError!Value {
+ const mod = sema.mod;
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema);
- const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema);
+ const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
+ const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
const limbs_q = try sema.arena.alloc(
math.big.Limb,
lhs_bigint.limbs.len,
@@ -13912,10 +14622,11 @@ fn intRemScalar(
var result_q = math.big.int.Mutable{ .limbs = limbs_q, .positive = undefined, .len = undefined };
var result_r = math.big.int.Mutable{ .limbs = limbs_r, .positive = undefined, .len = undefined };
result_q.divTrunc(&result_r, lhs_bigint, rhs_bigint, limbs_buffer);
- return Value.fromBigInt(sema.arena, result_r.toConst());
+ return mod.intValue_big(scalar_ty, result_r.toConst());
}
fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -13926,8 +14637,8 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -13939,13 +14650,12 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .mod);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
@@ -13963,12 +14673,12 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
// If the lhs is undefined, result is undefined.
if (is_int) {
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, lhs_src);
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13987,7 +14697,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
// float operands
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -13995,7 +14705,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
@@ -14018,6 +14728,7 @@ fn zirMod(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src: LazySrcLoc = .{ .node_offset_bin_op = inst_data.src_node };
sema.src = src;
@@ -14028,8 +14739,8 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const rhs = try sema.resolveInst(extra.rhs);
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
try sema.checkInvalidPtrArithmetic(block, src, lhs_ty);
@@ -14041,13 +14752,12 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const scalar_tag = resolved_type.scalarType(mod).zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, .rem);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
@@ -14065,12 +14775,12 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
// If the lhs is undefined, result is undefined.
if (is_int) {
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, lhs_src);
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -14089,7 +14799,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
// float operands
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, rhs_src);
}
if (!(try rhs_val.compareAllWithZeroAdvanced(.neq, sema))) {
@@ -14097,7 +14807,7 @@ fn zirRem(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Ins
}
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
@@ -14159,7 +14869,7 @@ fn zirOverflowArithmetic(
const lhs = try sema.coerce(block, dest_ty, uncasted_lhs, lhs_src);
const rhs = try sema.coerce(block, rhs_dest_ty, uncasted_rhs, rhs_src);
- if (dest_ty.scalarType().zigTypeTag() != .Int) {
+ if (dest_ty.scalarType(mod).zigTypeTag(mod) != .Int) {
return sema.fail(block, src, "expected vector of integers or integer tag type, found '{}'", .{dest_ty.fmt(mod)});
}
@@ -14167,30 +14877,32 @@ fn zirOverflowArithmetic(
const maybe_rhs_val = try sema.resolveMaybeUndefVal(rhs);
const tuple_ty = try sema.overflowArithmeticTupleType(dest_ty);
+ const overflow_ty = mod.intern_pool.indexToKey(tuple_ty.toIntern()).anon_struct_type.types[1].toType();
var result: struct {
inst: Air.Inst.Ref = .none,
- wrapped: Value = Value.initTag(.unreachable_value),
+ wrapped: Value = Value.@"unreachable",
overflow_bit: Value,
} = result: {
+ const zero_bit = try mod.intValue(Type.u1, 0);
switch (zir_tag) {
.add_with_overflow => {
// If either of the arguments is zero, `false` is returned and the other is stored
// to the result, even if it is undefined..
// Otherwise, if either of the argument is undefined, undefined is returned.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
+ if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
}
}
if (maybe_rhs_val) |rhs_val| {
- if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
+ if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
if (maybe_lhs_val) |lhs_val| {
if (maybe_rhs_val) |rhs_val| {
- if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
}
@@ -14203,12 +14915,12 @@ fn zirOverflowArithmetic(
// If the rhs is zero, then the result is lhs and no overflow occured.
// Otherwise, if either result is undefined, both results are undefined.
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
} else if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
} else if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
}
@@ -14221,29 +14933,30 @@ fn zirOverflowArithmetic(
// If either of the arguments is zero, the result is zero and no overflow occured.
// If either of the arguments is one, the result is the other and no overflow occured.
// Otherwise, if either of the arguments is undefined, both results are undefined.
+ const scalar_one = try mod.intValue(dest_ty.scalarType(mod), 1);
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
+ if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
- } else if (try sema.compareAll(lhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
+ } else if (try sema.compareAll(lhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
}
}
}
if (maybe_rhs_val) |rhs_val| {
- if (!rhs_val.isUndef()) {
+ if (!rhs_val.isUndef(mod)) {
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = rhs };
- } else if (try sema.compareAll(rhs_val, .eq, try maybeRepeated(sema, dest_ty, Value.one), dest_ty)) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = rhs };
+ } else if (try sema.compareAll(rhs_val, .eq, try sema.splat(dest_ty, scalar_one), dest_ty)) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
}
if (maybe_lhs_val) |lhs_val| {
if (maybe_rhs_val) |rhs_val| {
- if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
}
@@ -14257,22 +14970,22 @@ fn zirOverflowArithmetic(
// If rhs is zero, the result is lhs (even if undefined) and no overflow occurred.
// Oterhwise if either of the arguments is undefined, both results are undefined.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
+ if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
if (maybe_rhs_val) |rhs_val| {
- if (!rhs_val.isUndef() and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
- break :result .{ .overflow_bit = try maybeRepeated(sema, dest_ty, Value.zero), .inst = lhs };
+ if (!rhs_val.isUndef(mod) and (try rhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ break :result .{ .overflow_bit = try sema.splat(overflow_ty, zero_bit), .inst = lhs };
}
}
if (maybe_lhs_val) |lhs_val| {
if (maybe_rhs_val) |rhs_val| {
- if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
break :result .{ .overflow_bit = Value.undef, .wrapped = Value.undef };
}
- const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, sema.mod);
+ const result = try lhs_val.shlWithOverflow(rhs_val, dest_ty, sema.arena, mod);
break :result .{ .overflow_bit = result.overflow_bit, .wrapped = result.wrapped_result };
}
}
@@ -14311,40 +15024,46 @@ fn zirOverflowArithmetic(
}
if (result.inst == .none) {
- const values = try sema.arena.alloc(Value, 2);
- values[0] = result.wrapped;
- values[1] = result.overflow_bit;
- const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstant(tuple_ty, tuple_val);
+ return sema.addConstant(tuple_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = tuple_ty.toIntern(),
+ .storage = .{ .elems = &.{
+ result.wrapped.toIntern(),
+ result.overflow_bit.toIntern(),
+ } },
+ } })).toValue());
}
const element_refs = try sema.arena.alloc(Air.Inst.Ref, 2);
element_refs[0] = result.inst;
- element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1), result.overflow_bit);
+ element_refs[1] = try sema.addConstant(tuple_ty.structFieldType(1, mod), result.overflow_bit);
return block.addAggregateInit(tuple_ty, element_refs);
}
-fn maybeRepeated(sema: *Sema, ty: Type, val: Value) !Value {
- if (ty.zigTypeTag() != .Vector) return val;
- return Value.Tag.repeated.create(sema.arena, val);
+fn splat(sema: *Sema, ty: Type, val: Value) !Value {
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) != .Vector) return val;
+ const repeated = try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .repeated_elem = val.toIntern() },
+ } });
+ return repeated.toValue();
}
fn overflowArithmeticTupleType(sema: *Sema, ty: Type) !Type {
- const ov_ty = if (ty.zigTypeTag() == .Vector) try Type.vector(sema.arena, ty.vectorLen(), Type.u1) else Type.u1;
-
- const types = try sema.arena.alloc(Type, 2);
- const values = try sema.arena.alloc(Value, 2);
- const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
- .types = types,
- .values = values,
- });
-
- types[0] = ty;
- types[1] = ov_ty;
- values[0] = Value.initTag(.unreachable_value);
- values[1] = Value.initTag(.unreachable_value);
+ const mod = sema.mod;
+ const ov_ty = if (ty.zigTypeTag(mod) == .Vector) try mod.vectorType(.{
+ .len = ty.vectorLen(mod),
+ .child = .u1_type,
+ }) else Type.u1;
- return tuple_ty;
+ const types = [2]InternPool.Index{ ty.toIntern(), ov_ty.toIntern() };
+ const values = [2]InternPool.Index{ .none, .none };
+ const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
+ .types = &types,
+ .values = &values,
+ .names = &.{},
+ } });
+ return tuple_ty.toType();
}
fn analyzeArithmetic(
@@ -14359,13 +15078,14 @@ fn analyzeArithmetic(
rhs_src: LazySrcLoc,
want_safety: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
- if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize()) {
+ if (lhs_zig_ty_tag == .Pointer) switch (lhs_ty.ptrSize(mod)) {
.One, .Slice => {},
.Many, .C => {
const air_tag: Air.Inst.Tag = switch (zir_tag) {
@@ -14382,18 +15102,16 @@ fn analyzeArithmetic(
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
- const is_vector = resolved_type.zigTypeTag() == .Vector;
-
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, resolved_type, rhs, rhs_src);
- const scalar_tag = resolved_type.scalarType().zigTypeTag();
+ const scalar_type = resolved_type.scalarType(mod);
+ const scalar_tag = scalar_type.zigTypeTag(mod);
const is_int = scalar_tag == .Int or scalar_tag == .ComptimeInt;
try sema.checkArithmeticOp(block, src, scalar_tag, lhs_zig_ty_tag, rhs_zig_ty_tag, zir_tag);
- const mod = sema.mod;
const maybe_lhs_val = try sema.resolveMaybeUndefValIntable(casted_lhs);
const maybe_rhs_val = try sema.resolveMaybeUndefValIntable(casted_rhs);
const rs: struct { src: LazySrcLoc, air_tag: Air.Inst.Tag } = rs: {
@@ -14407,12 +15125,12 @@ fn analyzeArithmetic(
// overflow (max_int), causing illegal behavior.
// For floats: either operand being undef makes the result undef.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
return casted_rhs;
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
if (is_int) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
@@ -14425,7 +15143,7 @@ fn analyzeArithmetic(
}
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .add_optimized else .add;
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
if (is_int) {
return sema.failWithUseOfUndef(block, lhs_src);
} else {
@@ -14434,16 +15152,16 @@ fn analyzeArithmetic(
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
- const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type);
- var vector_index: usize = undefined;
- if (!(try sema.intFitsInType(sum, resolved_type, &vector_index))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vector_index);
+ var overflow_idx: ?usize = null;
+ const sum = try sema.intAdd(lhs_val, rhs_val, resolved_type, &overflow_idx);
+ if (overflow_idx) |vec_idx| {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, sum, vec_idx);
}
return sema.addConstant(resolved_type, sum);
} else {
return sema.addConstant(
resolved_type,
- try sema.floatAdd(lhs_val, rhs_val, resolved_type),
+ try Value.floatAdd(lhs_val, rhs_val, resolved_type, sema.arena, mod),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = air_tag };
@@ -14454,13 +15172,13 @@ fn analyzeArithmetic(
// If either of the operands are zero, the other operand is returned.
// If either of the operands are undefined, the result is undefined.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
return casted_rhs;
}
}
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .addwrap_optimized else .addwrap;
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
@@ -14479,12 +15197,12 @@ fn analyzeArithmetic(
// If either of the operands are zero, then the other operand is returned.
// If either of the operands are undefined, the result is undefined.
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef() and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
+ if (!lhs_val.isUndef(mod) and (try lhs_val.compareAllWithZeroAdvanced(.eq, sema))) {
return casted_rhs;
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
@@ -14492,7 +15210,7 @@ fn analyzeArithmetic(
}
if (maybe_lhs_val) |lhs_val| {
const val = if (scalar_tag == .ComptimeInt)
- try sema.intAdd(lhs_val, rhs_val, resolved_type)
+ try sema.intAdd(lhs_val, rhs_val, resolved_type, undefined)
else
try lhs_val.intAddSat(rhs_val, resolved_type, sema.arena, mod);
@@ -14509,7 +15227,7 @@ fn analyzeArithmetic(
// overflow, causing illegal behavior.
// For floats: either operand being undef makes the result undef.
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
if (is_int) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
@@ -14522,7 +15240,7 @@ fn analyzeArithmetic(
}
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .sub_optimized else .sub;
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
if (is_int) {
return sema.failWithUseOfUndef(block, lhs_src);
} else {
@@ -14531,16 +15249,16 @@ fn analyzeArithmetic(
}
if (maybe_rhs_val) |rhs_val| {
if (is_int) {
- const diff = try sema.intSub(lhs_val, rhs_val, resolved_type);
- var vector_index: usize = undefined;
- if (!(try sema.intFitsInType(diff, resolved_type, &vector_index))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vector_index);
+ var overflow_idx: ?usize = null;
+ const diff = try sema.intSub(lhs_val, rhs_val, resolved_type, &overflow_idx);
+ if (overflow_idx) |vec_idx| {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, diff, vec_idx);
}
return sema.addConstant(resolved_type, diff);
} else {
return sema.addConstant(
resolved_type,
- try sema.floatSub(lhs_val, rhs_val, resolved_type),
+ try Value.floatSub(lhs_val, rhs_val, resolved_type, sema.arena, mod),
);
}
} else break :rs .{ .src = rhs_src, .air_tag = air_tag };
@@ -14551,7 +15269,7 @@ fn analyzeArithmetic(
// If the RHS is zero, then the other operand is returned, even if it is undefined.
// If either of the operands are undefined, the result is undefined.
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
@@ -14560,7 +15278,7 @@ fn analyzeArithmetic(
}
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .subwrap_optimized else .subwrap;
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
@@ -14576,7 +15294,7 @@ fn analyzeArithmetic(
// If the RHS is zero, result is LHS.
// If either of the operands are undefined, result is undefined.
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
@@ -14584,12 +15302,12 @@ fn analyzeArithmetic(
}
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (maybe_rhs_val) |rhs_val| {
const val = if (scalar_tag == .ComptimeInt)
- try sema.intSub(lhs_val, rhs_val, resolved_type)
+ try sema.intSub(lhs_val, rhs_val, resolved_type, undefined)
else
try lhs_val.intSubSat(rhs_val, resolved_type, sema.arena, mod);
@@ -14609,62 +15327,74 @@ fn analyzeArithmetic(
// If either of the operands are inf, and the other operand is zero,
// the result is nan.
// If either of the operands are nan, the result is nan.
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
+ else => unreachable,
+ };
+ const scalar_one = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
+ else => unreachable,
+ };
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
- if (lhs_val.isNan()) {
+ if (!lhs_val.isUndef(mod)) {
+ if (lhs_val.isNan(mod)) {
return sema.addConstant(resolved_type, lhs_val);
}
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) lz: {
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isNan()) {
+ if (rhs_val.isNan(mod)) {
return sema.addConstant(resolved_type, rhs_val);
}
- if (rhs_val.isInf()) {
- return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32));
+ if (rhs_val.isInf(mod)) {
+ return sema.addConstant(
+ resolved_type,
+ try mod.floatValue(resolved_type, std.math.nan_f128),
+ );
}
} else if (resolved_type.isAnyFloat()) {
break :lz;
}
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(lhs_val, .eq, Value.one, resolved_type)) {
+ if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_rhs;
}
}
}
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mul_optimized else .mul;
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
if (is_int) {
return sema.failWithUseOfUndef(block, rhs_src);
} else {
return sema.addConstUndef(resolved_type);
}
}
- if (rhs_val.isNan()) {
+ if (rhs_val.isNan(mod)) {
return sema.addConstant(resolved_type, rhs_val);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) rz: {
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isInf()) {
- return sema.addConstant(resolved_type, try Value.Tag.float_32.create(sema.arena, std.math.nan_f32));
+ if (lhs_val.isInf(mod)) {
+ return sema.addConstant(
+ resolved_type,
+ try mod.floatValue(resolved_type, std.math.nan_f128),
+ );
}
} else if (resolved_type.isAnyFloat()) {
break :rz;
}
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(rhs_val, .eq, Value.one, resolved_type)) {
+ if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
if (is_int) {
return sema.failWithUseOfUndef(block, lhs_src);
} else {
@@ -14672,16 +15402,16 @@ fn analyzeArithmetic(
}
}
if (is_int) {
- const product = try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod);
- var vector_index: usize = undefined;
- if (!(try sema.intFitsInType(product, resolved_type, &vector_index))) {
- return sema.failWithIntegerOverflow(block, src, resolved_type, product, vector_index);
+ var overflow_idx: ?usize = null;
+ const product = try lhs_val.intMul(rhs_val, resolved_type, &overflow_idx, sema.arena, mod);
+ if (overflow_idx) |vec_idx| {
+ return sema.failWithIntegerOverflow(block, src, resolved_type, product, vec_idx);
}
return sema.addConstant(resolved_type, product);
} else {
return sema.addConstant(
resolved_type,
- try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, sema.mod),
+ try lhs_val.floatMul(rhs_val, resolved_type, sema.arena, mod),
);
}
} else break :rs .{ .src = lhs_src, .air_tag = air_tag };
@@ -14692,40 +15422,46 @@ fn analyzeArithmetic(
// If either of the operands are zero, result is zero.
// If either of the operands are one, result is the other operand.
// If either of the operands are undefined, result is undefined.
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
+ else => unreachable,
+ };
+ const scalar_one = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
+ else => unreachable,
+ };
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
+ if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(lhs_val, .eq, Value.one, resolved_type)) {
+ if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_rhs;
}
}
}
const air_tag: Air.Inst.Tag = if (block.float_mode == .Optimized) .mulwrap_optimized else .mulwrap;
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(rhs_val, .eq, Value.one, resolved_type)) {
+ if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
return sema.addConstant(
resolved_type,
- try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, sema.mod),
+ try lhs_val.numberMulWrap(rhs_val, resolved_type, sema.arena, mod),
);
} else break :rs .{ .src = lhs_src, .air_tag = air_tag };
} else break :rs .{ .src = rhs_src, .air_tag = air_tag };
@@ -14735,41 +15471,47 @@ fn analyzeArithmetic(
// If either of the operands are zero, result is zero.
// If either of the operands are one, result is the other operand.
// If either of the operands are undefined, result is undefined.
+ const scalar_zero = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 0.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 0),
+ else => unreachable,
+ };
+ const scalar_one = switch (scalar_tag) {
+ .ComptimeFloat, .Float => try mod.floatValue(scalar_type, 1.0),
+ .ComptimeInt, .Int => try mod.intValue(scalar_type, 1),
+ else => unreachable,
+ };
if (maybe_lhs_val) |lhs_val| {
- if (!lhs_val.isUndef()) {
+ if (!lhs_val.isUndef(mod)) {
if (try lhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(lhs_val, .eq, Value.one, resolved_type)) {
+ if (try sema.compareAll(lhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_rhs;
}
}
}
if (maybe_rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) {
+ if (rhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
if (try rhs_val.compareAllWithZeroAdvanced(.eq, sema)) {
- const zero_val = if (is_vector) b: {
- break :b try Value.Tag.repeated.create(sema.arena, Value.zero);
- } else Value.zero;
+ const zero_val = try sema.splat(resolved_type, scalar_zero);
return sema.addConstant(resolved_type, zero_val);
}
- if (try sema.compareAll(rhs_val, .eq, Value.one, resolved_type)) {
+ if (try sema.compareAll(rhs_val, .eq, try sema.splat(resolved_type, scalar_one), resolved_type)) {
return casted_lhs;
}
if (maybe_lhs_val) |lhs_val| {
- if (lhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod)) {
return sema.addConstUndef(resolved_type);
}
const val = if (scalar_tag == .ComptimeInt)
- try lhs_val.intMul(rhs_val, resolved_type, sema.arena, sema.mod)
+ try lhs_val.intMul(rhs_val, resolved_type, undefined, sema.arena, mod)
else
- try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, sema.mod);
+ try lhs_val.intMulSat(rhs_val, resolved_type, sema.arena, mod);
return sema.addConstant(resolved_type, val);
} else break :rs .{ .src = lhs_src, .air_tag = .mul_sat };
@@ -14801,7 +15543,7 @@ fn analyzeArithmetic(
} },
});
const ov_bit = try sema.tupleFieldValByIndex(block, src, op_ov, 1, op_ov_tuple_ty);
- const any_ov_bit = if (resolved_type.zigTypeTag() == .Vector)
+ const any_ov_bit = if (resolved_type.zigTypeTag(mod) == .Vector)
try block.addInst(.{
.tag = if (block.float_mode == .Optimized) .reduce_optimized else .reduce,
.data = .{ .reduce = .{
@@ -14811,7 +15553,7 @@ fn analyzeArithmetic(
})
else
ov_bit;
- const zero_ov = try sema.addConstant(Type.u1, Value.zero);
+ const zero_ov = try sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
const no_ov = try block.addBinOp(.cmp_eq, any_ov_bit, zero_ov);
try sema.addSafetyCheck(block, no_ov, .integer_overflow);
@@ -14835,15 +15577,12 @@ fn analyzePtrArithmetic(
// TODO if the operand is comptime-known to be negative, or is a negative int,
// coerce to isize instead of usize.
const offset = try sema.coerce(block, Type.usize, uncasted_offset, offset_src);
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
const opt_ptr_val = try sema.resolveMaybeUndefVal(ptr);
const opt_off_val = try sema.resolveDefinedValue(block, offset_src, offset);
const ptr_ty = sema.typeOf(ptr);
- const ptr_info = ptr_ty.ptrInfo().data;
- const elem_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag() == .Array)
- ptr_info.pointee_type.childType()
- else
- ptr_info.pointee_type;
+ const ptr_info = ptr_ty.ptrInfo(mod);
+ assert(ptr_info.size == .Many or ptr_info.size == .C);
const new_ptr_ty = t: {
// Calculate the new pointer alignment.
@@ -14854,9 +15593,9 @@ fn analyzePtrArithmetic(
}
// If the addend is not a comptime-known value we can still count on
// it being a multiple of the type size.
- const elem_size = elem_ty.abiSize(target);
+ const elem_size = ptr_info.pointee_type.abiSize(mod);
const addend = if (opt_off_val) |off_val| a: {
- const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(target));
+ const off_int = try sema.usizeCast(block, offset_src, off_val.toUnsignedInt(mod));
break :a elem_size * off_int;
} else elem_size;
@@ -14865,7 +15604,7 @@ fn analyzePtrArithmetic(
// non zero).
const new_align = @as(u32, 1) << @intCast(u5, @ctz(addend | ptr_info.@"align"));
- break :t try Type.ptr(sema.arena, sema.mod, .{
+ break :t try Type.ptr(sema.arena, mod, .{
.pointee_type = ptr_info.pointee_type,
.sentinel = ptr_info.sentinel,
.@"align" = new_align,
@@ -14880,24 +15619,24 @@ fn analyzePtrArithmetic(
const runtime_src = rs: {
if (opt_ptr_val) |ptr_val| {
if (opt_off_val) |offset_val| {
- if (ptr_val.isUndef()) return sema.addConstUndef(new_ptr_ty);
+ if (ptr_val.isUndef(mod)) return sema.addConstUndef(new_ptr_ty);
- const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(target));
+ const offset_int = try sema.usizeCast(block, offset_src, offset_val.toUnsignedInt(mod));
if (offset_int == 0) return ptr;
- if (try ptr_val.getUnsignedIntAdvanced(target, sema)) |addr| {
- const elem_size = elem_ty.abiSize(target);
+ if (try ptr_val.getUnsignedIntAdvanced(mod, sema)) |addr| {
+ const elem_size = ptr_info.pointee_type.abiSize(mod);
const new_addr = switch (air_tag) {
.ptr_add => addr + elem_size * offset_int,
.ptr_sub => addr - elem_size * offset_int,
else => unreachable,
};
- const new_ptr_val = try Value.Tag.int_u64.create(sema.arena, new_addr);
+ const new_ptr_val = try mod.ptrIntValue(new_ptr_ty, new_addr);
return sema.addConstant(new_ptr_ty, new_ptr_val);
}
if (air_tag == .ptr_sub) {
return sema.fail(block, op_src, "TODO implement Sema comptime pointer subtraction", .{});
}
- const new_ptr_val = try ptr_val.elemPtr(ptr_ty, sema.arena, offset_int, sema.mod);
+ const new_ptr_val = try ptr_val.elemPtr(new_ptr_ty, offset_int, mod);
return sema.addConstant(new_ptr_ty, new_ptr_val);
} else break :rs offset_src;
} else break :rs ptr_src;
@@ -14943,7 +15682,7 @@ fn zirAsm(
const inputs_len = @truncate(u5, extended.small >> 5);
const clobbers_len = @truncate(u5, extended.small >> 10);
const is_volatile = @truncate(u1, extended.small >> 15) != 0;
- const is_global_assembly = sema.func == null;
+ const is_global_assembly = sema.func_index == .none;
const asm_source: []const u8 = if (tmpl_is_expr) blk: {
const tmpl = @intToEnum(Zir.Inst.Ref, extra.data.asm_source);
@@ -15007,6 +15746,7 @@ fn zirAsm(
const args = try sema.arena.alloc(Air.Inst.Ref, inputs_len);
const inputs = try sema.arena.alloc(ConstraintName, inputs_len);
+ const mod = sema.mod;
for (args, 0..) |*arg, arg_i| {
const input = sema.code.extraData(Zir.Inst.Asm.Input, extra_i);
@@ -15014,9 +15754,9 @@ fn zirAsm(
const uncasted_arg = try sema.resolveInst(input.data.operand);
const uncasted_arg_ty = sema.typeOf(uncasted_arg);
- switch (uncasted_arg_ty.zigTypeTag()) {
- .ComptimeInt => arg.* = try sema.coerce(block, Type.initTag(.usize), uncasted_arg, src),
- .ComptimeFloat => arg.* = try sema.coerce(block, Type.initTag(.f64), uncasted_arg, src),
+ switch (uncasted_arg_ty.zigTypeTag(mod)) {
+ .ComptimeInt => arg.* = try sema.coerce(block, Type.usize, uncasted_arg, src),
+ .ComptimeFloat => arg.* = try sema.coerce(block, Type.f64, uncasted_arg, src),
else => {
arg.* = uncasted_arg;
try sema.queueFullTypeResolution(uncasted_arg_ty);
@@ -15096,6 +15836,7 @@ fn zirCmpEq(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const src: LazySrcLoc = inst_data.src();
@@ -15106,8 +15847,8 @@ fn zirCmpEq(
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- const lhs_ty_tag = lhs_ty.zigTypeTag();
- const rhs_ty_tag = rhs_ty.zigTypeTag();
+ const lhs_ty_tag = lhs_ty.zigTypeTag(mod);
+ const rhs_ty_tag = rhs_ty.zigTypeTag(mod);
if (lhs_ty_tag == .Null and rhs_ty_tag == .Null) {
// null == null, null != null
if (op == .eq) {
@@ -15118,16 +15859,16 @@ fn zirCmpEq(
}
// comparing null with optionals
- if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr())) {
+ if (lhs_ty_tag == .Null and (rhs_ty_tag == .Optional or rhs_ty.isCPtr(mod))) {
return sema.analyzeIsNull(block, src, rhs, op == .neq);
}
- if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr())) {
+ if (rhs_ty_tag == .Null and (lhs_ty_tag == .Optional or lhs_ty.isCPtr(mod))) {
return sema.analyzeIsNull(block, src, lhs, op == .neq);
}
if (lhs_ty_tag == .Null or rhs_ty_tag == .Null) {
const non_null_type = if (lhs_ty_tag == .Null) rhs_ty else lhs_ty;
- return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(sema.mod)});
+ return sema.fail(block, src, "comparison of '{}' with null", .{non_null_type.fmt(mod)});
}
if (lhs_ty_tag == .Union and (rhs_ty_tag == .EnumLiteral or rhs_ty_tag == .Enum)) {
@@ -15141,15 +15882,12 @@ fn zirCmpEq(
const runtime_src: LazySrcLoc = src: {
if (try sema.resolveMaybeUndefVal(lhs)) |lval| {
if (try sema.resolveMaybeUndefVal(rhs)) |rval| {
- if (lval.isUndef() or rval.isUndef()) {
+ if (lval.isUndef(mod) or rval.isUndef(mod)) {
return sema.addConstUndef(Type.bool);
}
- // TODO optimisation opportunity: evaluate if mem.eql is faster with the names,
- // or calling to Module.getErrorValue to get the values and then compare them is
- // faster.
- const lhs_name = lval.castTag(.@"error").?.data.name;
- const rhs_name = rval.castTag(.@"error").?.data.name;
- if (mem.eql(u8, lhs_name, rhs_name) == (op == .eq)) {
+ const lkey = mod.intern_pool.indexToKey(lval.toIntern());
+ const rkey = mod.intern_pool.indexToKey(rval.toIntern());
+ if ((lkey.err.name == rkey.err.name) == (op == .eq)) {
return Air.Inst.Ref.bool_true;
} else {
return Air.Inst.Ref.bool_false;
@@ -15167,7 +15905,7 @@ fn zirCmpEq(
if (lhs_ty_tag == .Type and rhs_ty_tag == .Type) {
const lhs_as_type = try sema.analyzeAsType(block, lhs_src, lhs);
const rhs_as_type = try sema.analyzeAsType(block, rhs_src, rhs);
- if (lhs_as_type.eql(rhs_as_type, sema.mod) == (op == .eq)) {
+ if (lhs_as_type.eql(rhs_as_type, mod) == (op == .eq)) {
return Air.Inst.Ref.bool_true;
} else {
return Air.Inst.Ref.bool_false;
@@ -15186,12 +15924,13 @@ fn analyzeCmpUnionTag(
tag_src: LazySrcLoc,
op: std.math.CompareOperator,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const union_ty = try sema.resolveTypeFields(sema.typeOf(un));
- const union_tag_ty = union_ty.unionTagType() orelse {
+ const union_tag_ty = union_ty.unionTagType(mod) orelse {
const msg = msg: {
const msg = try sema.errMsg(block, un_src, "comparison of union and enum literal is only valid for tagged union types", .{});
errdefer msg.destroy(sema.gpa);
- try sema.mod.errNoteNonLazy(union_ty.declSrcLoc(sema.mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(sema.mod)});
+ try mod.errNoteNonLazy(union_ty.declSrcLoc(mod), msg, "union '{}' is not a tagged union", .{union_ty.fmt(mod)});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -15202,9 +15941,9 @@ fn analyzeCmpUnionTag(
const coerced_union = try sema.coerce(block, union_tag_ty, un, un_src);
if (try sema.resolveMaybeUndefVal(coerced_tag)) |enum_val| {
- if (enum_val.isUndef()) return sema.addConstUndef(Type.bool);
- const field_ty = union_ty.unionFieldType(enum_val, sema.mod);
- if (field_ty.zigTypeTag() == .NoReturn) {
+ if (enum_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
+ const field_ty = union_ty.unionFieldType(enum_val, mod);
+ if (field_ty.zigTypeTag(mod) == .NoReturn) {
return Air.Inst.Ref.bool_false;
}
}
@@ -15243,34 +15982,35 @@ fn analyzeCmp(
rhs_src: LazySrcLoc,
is_equality_cmp: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- if (lhs_ty.zigTypeTag() != .Optional and rhs_ty.zigTypeTag() != .Optional) {
+ if (lhs_ty.zigTypeTag(mod) != .Optional and rhs_ty.zigTypeTag(mod) != .Optional) {
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
}
- if (lhs_ty.zigTypeTag() == .Vector and rhs_ty.zigTypeTag() == .Vector) {
+ if (lhs_ty.zigTypeTag(mod) == .Vector and rhs_ty.zigTypeTag(mod) == .Vector) {
return sema.cmpVector(block, src, lhs, rhs, op, lhs_src, rhs_src);
}
- if (lhs_ty.isNumeric() and rhs_ty.isNumeric()) {
+ if (lhs_ty.isNumeric(mod) and rhs_ty.isNumeric(mod)) {
// This operation allows any combination of integer and float types, regardless of the
// signed-ness, comptime-ness, and bit-width. So peer type resolution is incorrect for
// numeric types.
return sema.cmpNumeric(block, src, lhs, rhs, op, lhs_src, rhs_src);
}
- if (is_equality_cmp and lhs_ty.zigTypeTag() == .ErrorUnion and rhs_ty.zigTypeTag() == .ErrorSet) {
+ if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorUnion and rhs_ty.zigTypeTag(mod) == .ErrorSet) {
const casted_lhs = try sema.analyzeErrUnionCode(block, lhs_src, lhs);
return sema.cmpSelf(block, src, casted_lhs, rhs, op, lhs_src, rhs_src);
}
- if (is_equality_cmp and lhs_ty.zigTypeTag() == .ErrorSet and rhs_ty.zigTypeTag() == .ErrorUnion) {
+ if (is_equality_cmp and lhs_ty.zigTypeTag(mod) == .ErrorSet and rhs_ty.zigTypeTag(mod) == .ErrorUnion) {
const casted_rhs = try sema.analyzeErrUnionCode(block, rhs_src, rhs);
return sema.cmpSelf(block, src, lhs, casted_rhs, op, lhs_src, rhs_src);
}
const instructions = &[_]Air.Inst.Ref{ lhs, rhs };
const resolved_type = try sema.resolvePeerTypes(block, src, instructions, .{ .override = &[_]?LazySrcLoc{ lhs_src, rhs_src } });
- if (!resolved_type.isSelfComparable(is_equality_cmp)) {
+ if (!resolved_type.isSelfComparable(mod, is_equality_cmp)) {
return sema.fail(block, src, "operator {s} not allowed for type '{}'", .{
- compareOperatorName(op), resolved_type.fmt(sema.mod),
+ compareOperatorName(op), resolved_type.fmt(mod),
});
}
const casted_lhs = try sema.coerce(block, resolved_type, lhs, lhs_src);
@@ -15299,15 +16039,19 @@ fn cmpSelf(
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const resolved_type = sema.typeOf(casted_lhs);
const runtime_src: LazySrcLoc = src: {
if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| {
- if (lhs_val.isUndef()) return sema.addConstUndef(Type.bool);
+ if (lhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
- if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
+ if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
- if (resolved_type.zigTypeTag() == .Vector) {
- const result_ty = try Type.vector(sema.arena, resolved_type.vectorLen(), Type.bool);
+ if (resolved_type.zigTypeTag(mod) == .Vector) {
+ const result_ty = try mod.vectorType(.{
+ .len = resolved_type.vectorLen(mod),
+ .child = .bool_type,
+ });
const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_type);
return sema.addConstant(result_ty, cmp_val);
}
@@ -15318,7 +16062,7 @@ fn cmpSelf(
return Air.Inst.Ref.bool_false;
}
} else {
- if (resolved_type.zigTypeTag() == .Bool) {
+ if (resolved_type.zigTypeTag(mod) == .Bool) {
// We can lower bool eq/neq more efficiently.
return sema.runtimeBoolCmp(block, src, op, casted_rhs, lhs_val.toBool(), rhs_src);
}
@@ -15327,9 +16071,9 @@ fn cmpSelf(
} else {
// For bools, we still check the other operand, because we can lower
// bool eq/neq more efficiently.
- if (resolved_type.zigTypeTag() == .Bool) {
+ if (resolved_type.zigTypeTag(mod) == .Bool) {
if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
- if (rhs_val.isUndef()) return sema.addConstUndef(Type.bool);
+ if (rhs_val.isUndef(mod)) return sema.addConstUndef(Type.bool);
return sema.runtimeBoolCmp(block, src, op, casted_lhs, rhs_val.toBool(), lhs_src);
}
}
@@ -15337,7 +16081,7 @@ fn cmpSelf(
}
};
try sema.requireRuntimeBlock(block, src, runtime_src);
- if (resolved_type.zigTypeTag() == .Vector) {
+ if (resolved_type.zigTypeTag(mod) == .Vector) {
return block.addCmpVector(casted_lhs, casted_rhs, op);
}
const tag = Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized);
@@ -15366,16 +16110,17 @@ fn runtimeBoolCmp(
}
fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, operand_src, inst_data.operand);
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Fn,
.NoReturn,
.Undefined,
.Null,
.Opaque,
- => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(sema.mod)}),
+ => return sema.fail(block, operand_src, "no size available for type '{}'", .{ty.fmt(mod)}),
.Type,
.EnumLiteral,
@@ -15400,25 +16145,25 @@ fn zirSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
.AnyFrame,
=> {},
}
- const target = sema.mod.getTarget();
- const val = try ty.lazyAbiSize(target, sema.arena);
- if (val.tag() == .lazy_size) {
+ const val = try ty.lazyAbiSize(mod);
+ if (val.isLazySize(mod)) {
try sema.queueFullTypeResolution(ty);
}
return sema.addConstant(Type.comptime_int, val);
}
fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_ty = try sema.resolveType(block, operand_src, inst_data.operand);
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.Fn,
.NoReturn,
.Undefined,
.Null,
.Opaque,
- => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(sema.mod)}),
+ => return sema.fail(block, operand_src, "no size available for type '{}'", .{operand_ty.fmt(mod)}),
.Type,
.EnumLiteral,
@@ -15443,8 +16188,7 @@ fn zirBitSizeOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
.AnyFrame,
=> {},
}
- const target = sema.mod.getTarget();
- const bit_size = try operand_ty.bitSizeAdvanced(target, sema);
+ const bit_size = try operand_ty.bitSizeAdvanced(mod, sema);
return sema.addIntUnsigned(Type.comptime_int, bit_size);
}
@@ -15453,17 +16197,13 @@ fn zirThis(
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
- const this_decl_index = block.namespace.getDeclIndex();
+ const mod = sema.mod;
+ const this_decl_index = mod.namespaceDeclIndex(block.namespace);
const src = LazySrcLoc.nodeOffset(@bitCast(i32, extended.operand));
return sema.analyzeDeclVal(block, src, this_decl_index);
}
-fn zirClosureCapture(
- sema: *Sema,
- block: *Block,
- inst: Zir.Inst.Index,
-) CompileError!void {
- // TODO: Compile error when closed over values are modified
+fn zirClosureCapture(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
// Closures are not necessarily constant values. For example, the
// code might do something like this:
@@ -15471,26 +16211,24 @@ fn zirClosureCapture(
// ...in which case the closure_capture instruction has access to a runtime
// value only. In such case we preserve the type and use a dummy runtime value.
const operand = try sema.resolveInst(inst_data.operand);
- const val = (try sema.resolveMaybeUndefValAllowVariables(operand)) orelse
- Value.initTag(.unreachable_value);
-
- try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, .{
- .ty = try sema.typeOf(operand).copy(sema.perm_arena),
- .val = try val.copy(sema.perm_arena),
- });
+ const ty = sema.typeOf(operand);
+ const capture: CaptureScope.Capture = blk: {
+ if (try sema.resolveMaybeUndefValAllowVariables(operand)) |val| {
+ const ip_index = try val.intern(ty, sema.mod);
+ break :blk .{ .comptime_val = ip_index };
+ }
+ break :blk .{ .runtime_val = ty.toIntern() };
+ };
+ try block.wip_capture_scope.captures.putNoClobber(sema.gpa, inst, capture);
}
-fn zirClosureGet(
- sema: *Sema,
- block: *Block,
- inst: Zir.Inst.Index,
-) CompileError!Air.Inst.Ref {
- // TODO CLOSURE: Test this with inline functions
+fn zirClosureGet(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].inst_node;
- var scope: *CaptureScope = sema.mod.declPtr(block.src_decl).src_scope.?;
+ var scope: *CaptureScope = mod.declPtr(block.src_decl).src_scope.?;
// 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 tv = while (true) {
+ const capture = while (true) {
// Note: We don't need to add a dependency here, because
// decls always depend on their lexical parents.
@@ -15503,17 +16241,17 @@ fn zirClosureGet(
}
return error.AnalysisFail;
}
- if (scope.captures.getPtr(inst_data.inst)) |tv| {
- break tv;
+ if (scope.captures.get(inst_data.inst)) |capture| {
+ break capture;
}
scope = scope.parent.?;
};
- if (tv.val.tag() == .unreachable_value and !block.is_typeof and sema.func == null) {
+ if (capture == .runtime_val and !block.is_typeof and sema.func_index == .none) {
const msg = msg: {
const name = name: {
- const file = sema.owner_decl.getFileScope();
- const tree = file.getTree(sema.mod.gpa) catch |err| {
+ const file = sema.owner_decl.getFileScope(mod);
+ const tree = file.getTree(sema.gpa) catch |err| {
// In this case we emit a warning + a less precise source location.
log.warn("unable to load {s}: {s}", .{
file.sub_file_path, @errorName(err),
@@ -15537,11 +16275,11 @@ fn zirClosureGet(
return sema.failWithOwnedErrorMsg(msg);
}
- if (tv.val.tag() == .unreachable_value and !block.is_typeof and !block.is_comptime and sema.func != null) {
+ if (capture == .runtime_val and !block.is_typeof and !block.is_comptime and sema.func_index != .none) {
const msg = msg: {
const name = name: {
- const file = sema.owner_decl.getFileScope();
- const tree = file.getTree(sema.mod.gpa) catch |err| {
+ const file = sema.owner_decl.getFileScope(mod);
+ const tree = file.getTree(sema.gpa) catch |err| {
// In this case we emit a warning + a less precise source location.
log.warn("unable to load {s}: {s}", .{
file.sub_file_path, @errorName(err),
@@ -15567,13 +16305,17 @@ fn zirClosureGet(
return sema.failWithOwnedErrorMsg(msg);
}
- if (tv.val.tag() == .unreachable_value) {
- assert(block.is_typeof);
- // We need a dummy runtime instruction with the correct type.
- return block.addTy(.alloc, tv.ty);
+ switch (capture) {
+ .runtime_val => |ty_ip_index| {
+ assert(block.is_typeof);
+ // We need a dummy runtime instruction with the correct type.
+ return block.addTy(.alloc, ty_ip_index.toType());
+ },
+ .comptime_val => |val_ip_index| {
+ const ty = mod.intern_pool.typeOf(val_ip_index).toType();
+ return sema.addConstant(ty, val_ip_index.toValue());
+ },
}
-
- return sema.addConstant(tv.ty, tv.val);
}
fn zirRetAddr(
@@ -15608,345 +16350,422 @@ fn zirBuiltinSrc(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.Src, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const func = sema.func orelse return sema.fail(block, src, "@src outside function", .{});
- const fn_owner_decl = sema.mod.declPtr(func.owner_decl);
+ const fn_owner_decl = mod.declPtr(func.owner_decl);
const func_name_val = blk: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const name = std.mem.span(fn_owner_decl.name);
- const bytes = try anon_decl.arena().dupe(u8, name[0 .. name.len + 1]);
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = try sema.arena.dupe(u8, mod.intern_pool.stringToSlice(fn_owner_decl.name));
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ .sentinel = .zero_u8,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len - 1),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl);
+ break :blk try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_sentinel_0_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
const file_name_val = blk: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
// The compiler must not call realpath anywhere.
- const name = try fn_owner_decl.getFileScope().fullPathZ(anon_decl.arena());
+ const name = try fn_owner_decl.getFileScope(mod).fullPathZ(sema.arena);
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ .sentinel = .zero_u8,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), name.len),
- try Value.Tag.bytes.create(anon_decl.arena(), name[0 .. name.len + 1]),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :blk try Value.Tag.decl_ref.create(sema.arena, new_decl);
+ break :blk try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_sentinel_0_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
- const field_values = try sema.arena.alloc(Value, 4);
- // file: [:0]const u8,
- field_values[0] = file_name_val;
- // fn_name: [:0]const u8,
- field_values[1] = func_name_val;
- // line: u32
- field_values[2] = try Value.Tag.runtime_value.create(sema.arena, try Value.Tag.int_u64.create(sema.arena, extra.line + 1));
- // column: u32,
- field_values[3] = try Value.Tag.int_u64.create(sema.arena, extra.column + 1);
-
- return sema.addConstant(
- try sema.getBuiltinType("SourceLocation"),
- try Value.Tag.aggregate.create(sema.arena, field_values),
- );
+ const src_loc_ty = try sema.getBuiltinType("SourceLocation");
+ const fields = .{
+ // file: [:0]const u8,
+ file_name_val,
+ // fn_name: [:0]const u8,
+ func_name_val,
+ // line: u32,
+ try mod.intern(.{ .runtime_value = .{
+ .ty = .u32_type,
+ .val = (try mod.intValue(Type.u32, extra.line + 1)).toIntern(),
+ } }),
+ // column: u32,
+ (try mod.intValue(Type.u32, extra.column + 1)).toIntern(),
+ };
+ return sema.addConstant(src_loc_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = src_loc_ty.toIntern(),
+ .storage = .{ .elems = &fields },
+ } })).toValue());
}
fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ty = try sema.resolveType(block, src, inst_data.operand);
const type_info_ty = try sema.getBuiltinType("Type");
- const target = sema.mod.getTarget();
+ const type_info_tag_ty = type_info_ty.unionTagType(mod).?;
- switch (ty.zigTypeTag()) {
- .Type => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Type)),
- .val = Value.void,
- }),
- ),
- .Void => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Void)),
- .val = Value.void,
- }),
- ),
- .Bool => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Bool)),
- .val = Value.void,
- }),
- ),
- .NoReturn => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.NoReturn)),
- .val = Value.void,
- }),
- ),
- .ComptimeFloat => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeFloat)),
- .val = Value.void,
- }),
- ),
- .ComptimeInt => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ComptimeInt)),
- .val = Value.void,
- }),
- ),
- .Undefined => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Undefined)),
- .val = Value.void,
- }),
- ),
- .Null => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Null)),
- .val = Value.void,
- }),
- ),
- .EnumLiteral => return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.EnumLiteral)),
- .val = Value.void,
- }),
- ),
+ switch (ty.zigTypeTag(mod)) {
+ .Type,
+ .Void,
+ .Bool,
+ .NoReturn,
+ .ComptimeFloat,
+ .ComptimeInt,
+ .Undefined,
+ .Null,
+ .EnumLiteral,
+ => |type_info_tag| return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(type_info_tag))).toIntern(),
+ .val = .void_value,
+ } })).toValue()),
.Fn => {
// TODO: look into memoizing this result.
- const info = ty.fnInfo();
-
var params_anon_decl = try block.startAnonDecl();
defer params_anon_decl.deinit();
- const param_vals = try params_anon_decl.arena().alloc(Value, info.param_types.len);
+ const fn_info_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Fn"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index);
+ try sema.ensureDeclAnalyzed(fn_info_decl_index);
+ const fn_info_decl = mod.declPtr(fn_info_decl_index);
+ const fn_info_ty = fn_info_decl.val.toType();
+
+ const param_info_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ fn_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Param"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index);
+ try sema.ensureDeclAnalyzed(param_info_decl_index);
+ const param_info_decl = mod.declPtr(param_info_decl_index);
+ const param_info_ty = param_info_decl.val.toType();
+
+ const param_vals = try sema.arena.alloc(InternPool.Index, mod.typeToFunc(ty).?.param_types.len);
for (param_vals, 0..) |*param_val, i| {
+ const info = mod.typeToFunc(ty).?;
const param_ty = info.param_types[i];
- const is_generic = param_ty.tag() == .generic_poison;
- const param_ty_val = if (is_generic)
- Value.null
- else
- try Value.Tag.opt_payload.create(
- params_anon_decl.arena(),
- try Value.Tag.ty.create(params_anon_decl.arena(), try param_ty.copy(params_anon_decl.arena())),
- );
+ const is_generic = param_ty == .generic_poison_type;
+ const param_ty_val = try ip.get(gpa, .{ .opt = .{
+ .ty = try ip.get(gpa, .{ .opt_type = .type_type }),
+ .val = if (is_generic) .none else param_ty,
+ } });
const is_noalias = blk: {
const index = std.math.cast(u5, i) orelse break :blk false;
break :blk @truncate(u1, info.noalias_bits >> index) != 0;
};
- const param_fields = try params_anon_decl.arena().create([3]Value);
- param_fields.* = .{
+ const param_fields = .{
// is_generic: bool,
- Value.makeBool(is_generic),
+ Value.makeBool(is_generic).toIntern(),
// is_noalias: bool,
- Value.makeBool(is_noalias),
+ Value.makeBool(is_noalias).toIntern(),
// type: ?type,
param_ty_val,
};
- param_val.* = try Value.Tag.aggregate.create(params_anon_decl.arena(), param_fields);
+ param_val.* = try mod.intern(.{ .aggregate = .{
+ .ty = param_info_ty.toIntern(),
+ .storage = .{ .elems = &param_fields },
+ } });
}
const args_val = v: {
- const fn_info_decl_index = (try sema.namespaceLookup(
- block,
- src,
- type_info_ty.getNamespace().?,
- "Fn",
- )).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, fn_info_decl_index);
- try sema.ensureDeclAnalyzed(fn_info_decl_index);
- const fn_info_decl = sema.mod.declPtr(fn_info_decl_index);
- var fn_ty_buffer: Value.ToTypeBuffer = undefined;
- const fn_ty = fn_info_decl.val.toType(&fn_ty_buffer);
- const param_info_decl_index = (try sema.namespaceLookup(
- block,
- src,
- fn_ty.getNamespace().?,
- "Param",
- )).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, param_info_decl_index);
- try sema.ensureDeclAnalyzed(param_info_decl_index);
- const param_info_decl = sema.mod.declPtr(param_info_decl_index);
- var param_buffer: Value.ToTypeBuffer = undefined;
- const param_ty = param_info_decl.val.toType(&param_buffer);
+ const new_decl_ty = try mod.arrayType(.{
+ .len = param_vals.len,
+ .child = param_info_ty.toIntern(),
+ });
const new_decl = try params_anon_decl.finish(
- try Type.Tag.array.create(params_anon_decl.arena(), .{
- .len = param_vals.len,
- .elem_type = try param_ty.copy(params_anon_decl.arena()),
- }),
- try Value.Tag.aggregate.create(
- params_anon_decl.arena(),
- param_vals,
- ),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .elems = param_vals },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.slice.create(sema.arena, .{
- .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
- .len = try Value.Tag.int_u64.create(sema.arena, param_vals.len),
- });
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = (try mod.ptrType(.{
+ .child = param_info_ty.toIntern(),
+ .flags = .{
+ .size = .Slice,
+ .is_const = true,
+ },
+ })).toIntern(),
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, param_vals.len)).toIntern(),
+ } });
};
- const ret_ty_opt = if (info.return_type.tag() != .generic_poison)
- try Value.Tag.opt_payload.create(
- sema.arena,
- try Value.Tag.ty.create(sema.arena, info.return_type),
- )
- else
- Value.null;
+ const info = mod.typeToFunc(ty).?;
+ const ret_ty_opt = try mod.intern(.{ .opt = .{
+ .ty = try ip.get(gpa, .{ .opt_type = .type_type }),
+ .val = if (info.return_type == .generic_poison_type) .none else info.return_type,
+ } });
+
+ const callconv_ty = try sema.getBuiltinType("CallingConvention");
- const field_values = try sema.arena.create([6]Value);
- field_values.* = .{
+ const field_values = .{
// calling_convention: CallingConvention,
- try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.cc)),
+ (try mod.enumValueFieldIndex(callconv_ty, @enumToInt(info.cc))).toIntern(),
// alignment: comptime_int,
- try Value.Tag.int_u64.create(sema.arena, ty.abiAlignment(target)),
+ (try mod.intValue(Type.comptime_int, ty.abiAlignment(mod))).toIntern(),
// is_generic: bool,
- Value.makeBool(info.is_generic),
+ Value.makeBool(info.is_generic).toIntern(),
// is_var_args: bool,
- Value.makeBool(info.is_var_args),
+ Value.makeBool(info.is_var_args).toIntern(),
// return_type: ?type,
ret_ty_opt,
// args: []const Fn.Param,
args_val,
};
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Fn)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Fn))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = fn_info_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Int => {
- const info = ty.intInfo(target);
- const field_values = try sema.arena.alloc(Value, 2);
- // signedness: Signedness,
- field_values[0] = try Value.Tag.enum_field_index.create(
- sema.arena,
- @enumToInt(info.signedness),
- );
- // bits: comptime_int,
- field_values[1] = try Value.Tag.int_u64.create(sema.arena, info.bits);
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Int)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ const int_info_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Int"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, int_info_decl_index);
+ try sema.ensureDeclAnalyzed(int_info_decl_index);
+ const int_info_decl = mod.declPtr(int_info_decl_index);
+ const int_info_ty = int_info_decl.val.toType();
+
+ const signedness_ty = try sema.getBuiltinType("Signedness");
+ const info = ty.intInfo(mod);
+ const field_values = .{
+ // signedness: Signedness,
+ try (try mod.enumValueFieldIndex(signedness_ty, @enumToInt(info.signedness))).intern(signedness_ty, mod),
+ // bits: u16,
+ (try mod.intValue(Type.u16, info.bits)).toIntern(),
+ };
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Int))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = int_info_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Float => {
- const field_values = try sema.arena.alloc(Value, 1);
- // bits: comptime_int,
- field_values[0] = try Value.Tag.int_u64.create(sema.arena, ty.bitSize(target));
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Float)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ const float_info_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Float"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, float_info_decl_index);
+ try sema.ensureDeclAnalyzed(float_info_decl_index);
+ const float_info_decl = mod.declPtr(float_info_decl_index);
+ const float_info_ty = float_info_decl.val.toType();
+
+ const field_vals = .{
+ // bits: u16,
+ (try mod.intValue(Type.u16, ty.bitSize(mod))).toIntern(),
+ };
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Float))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = float_info_ty.toIntern(),
+ .storage = .{ .elems = &field_vals },
+ } }),
+ } })).toValue());
},
.Pointer => {
- const info = ty.ptrInfo().data;
+ const info = ty.ptrInfo(mod);
const alignment = if (info.@"align" != 0)
- try Value.Tag.int_u64.create(sema.arena, info.@"align")
+ try mod.intValue(Type.comptime_int, info.@"align")
else
- try info.pointee_type.lazyAbiAlignment(target, sema.arena);
+ try info.pointee_type.lazyAbiAlignment(mod);
- const field_values = try sema.arena.create([8]Value);
- field_values.* = .{
+ const addrspace_ty = try sema.getBuiltinType("AddressSpace");
+ const pointer_ty = t: {
+ const decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Pointer"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
+ try sema.ensureDeclAnalyzed(decl_index);
+ const decl = mod.declPtr(decl_index);
+ break :t decl.val.toType();
+ };
+ const ptr_size_ty = t: {
+ const decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ pointer_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Size"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
+ try sema.ensureDeclAnalyzed(decl_index);
+ const decl = mod.declPtr(decl_index);
+ break :t decl.val.toType();
+ };
+
+ const field_values = .{
// size: Size,
- try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.size)),
+ try (try mod.enumValueFieldIndex(ptr_size_ty, @enumToInt(info.size))).intern(ptr_size_ty, mod),
// is_const: bool,
- Value.makeBool(!info.mutable),
+ Value.makeBool(!info.mutable).toIntern(),
// is_volatile: bool,
- Value.makeBool(info.@"volatile"),
+ Value.makeBool(info.@"volatile").toIntern(),
// alignment: comptime_int,
- alignment,
+ alignment.toIntern(),
// address_space: AddressSpace
- try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(info.@"addrspace")),
+ try (try mod.enumValueFieldIndex(addrspace_ty, @enumToInt(info.@"addrspace"))).intern(addrspace_ty, mod),
// child: type,
- try Value.Tag.ty.create(sema.arena, info.pointee_type),
+ info.pointee_type.toIntern(),
// is_allowzero: bool,
- Value.makeBool(info.@"allowzero"),
+ Value.makeBool(info.@"allowzero").toIntern(),
// sentinel: ?*const anyopaque,
- try sema.optRefValue(block, info.pointee_type, info.sentinel),
+ (try sema.optRefValue(block, info.pointee_type, info.sentinel)).toIntern(),
};
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Pointer)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Pointer))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = pointer_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Array => {
- const info = ty.arrayInfo();
- const field_values = try sema.arena.alloc(Value, 3);
- // len: comptime_int,
- field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len);
- // child: type,
- field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type);
- // sentinel: ?*const anyopaque,
- field_values[2] = try sema.optRefValue(block, info.elem_type, info.sentinel);
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Array)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ const array_field_ty = t: {
+ const array_field_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Array"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, array_field_ty_decl_index);
+ try sema.ensureDeclAnalyzed(array_field_ty_decl_index);
+ const array_field_ty_decl = mod.declPtr(array_field_ty_decl_index);
+ break :t array_field_ty_decl.val.toType();
+ };
+
+ const info = ty.arrayInfo(mod);
+ const field_values = .{
+ // len: comptime_int,
+ (try mod.intValue(Type.comptime_int, info.len)).toIntern(),
+ // child: type,
+ info.elem_type.toIntern(),
+ // sentinel: ?*const anyopaque,
+ (try sema.optRefValue(block, info.elem_type, info.sentinel)).toIntern(),
+ };
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Array))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = array_field_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Vector => {
- const info = ty.arrayInfo();
- const field_values = try sema.arena.alloc(Value, 2);
- // len: comptime_int,
- field_values[0] = try Value.Tag.int_u64.create(sema.arena, info.len);
- // child: type,
- field_values[1] = try Value.Tag.ty.create(sema.arena, info.elem_type);
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Vector)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ const vector_field_ty = t: {
+ const vector_field_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Vector"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, vector_field_ty_decl_index);
+ try sema.ensureDeclAnalyzed(vector_field_ty_decl_index);
+ const vector_field_ty_decl = mod.declPtr(vector_field_ty_decl_index);
+ break :t vector_field_ty_decl.val.toType();
+ };
+
+ const info = ty.arrayInfo(mod);
+ const field_values = .{
+ // len: comptime_int,
+ (try mod.intValue(Type.comptime_int, info.len)).toIntern(),
+ // child: type,
+ info.elem_type.toIntern(),
+ };
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Vector))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = vector_field_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Optional => {
- const field_values = try sema.arena.alloc(Value, 1);
- // child: type,
- field_values[0] = try Value.Tag.ty.create(sema.arena, try ty.optionalChildAlloc(sema.arena));
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Optional)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ const optional_field_ty = t: {
+ const optional_field_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Optional"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, optional_field_ty_decl_index);
+ try sema.ensureDeclAnalyzed(optional_field_ty_decl_index);
+ const optional_field_ty_decl = mod.declPtr(optional_field_ty_decl_index);
+ break :t optional_field_ty_decl.val.toType();
+ };
+
+ const field_values = .{
+ // child: type,
+ ty.optionalChild(mod).toIntern(),
+ };
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Optional))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = optional_field_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.ErrorSet => {
var fields_anon_decl = try block.startAnonDecl();
@@ -15957,17 +16776,16 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const set_field_ty_decl_index = (try sema.namespaceLookup(
block,
src,
- type_info_ty.getNamespace().?,
- "Error",
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Error"),
)).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, set_field_ty_decl_index);
try sema.ensureDeclAnalyzed(set_field_ty_decl_index);
- const set_field_ty_decl = sema.mod.declPtr(set_field_ty_decl_index);
- var buffer: Value.ToTypeBuffer = undefined;
- break :t try set_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
+ const set_field_ty_decl = mod.declPtr(set_field_ty_decl_index);
+ break :t set_field_ty_decl.val.toType();
};
- try sema.queueFullTypeResolution(try error_field_ty.copy(sema.arena));
+ try sema.queueFullTypeResolution(error_field_ty);
// If the error set is inferred it must be resolved at this point
try sema.resolveInferredErrorSetTy(block, src, ty);
@@ -15975,90 +16793,119 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// Build our list of Error values
// Optional value is only null if anyerror
// Value can be zero-length slice otherwise
- const error_field_vals: ?[]Value = if (ty.isAnyError()) null else blk: {
- const names = ty.errorSetNames();
- const vals = try fields_anon_decl.arena().alloc(Value, names.len);
+ const error_field_vals = if (ty.isAnyError(mod)) null else blk: {
+ const vals = try sema.arena.alloc(InternPool.Index, ty.errorSetNames(mod).len);
for (vals, 0..) |*field_val, i| {
- const name = names[i];
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = try sema.arena.dupe(u8, ip.stringToSlice(ty.errorSetNames(mod)[i]));
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes = try anon_decl.arena().dupeZ(u8, name);
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
- const error_field_fields = try fields_anon_decl.arena().create([1]Value);
- error_field_fields.* = .{
+ const error_field_fields = .{
// name: []const u8,
name_val,
};
-
- field_val.* = try Value.Tag.aggregate.create(
- fields_anon_decl.arena(),
- error_field_fields,
- );
+ field_val.* = try mod.intern(.{ .aggregate = .{
+ .ty = error_field_ty.toIntern(),
+ .storage = .{ .elems = &error_field_fields },
+ } });
}
break :blk vals;
};
// Build our ?[]const Error value
- const errors_val = if (error_field_vals) |vals| v: {
+ const slice_errors_ty = try mod.ptrType(.{
+ .child = error_field_ty.toIntern(),
+ .flags = .{
+ .size = .Slice,
+ .is_const = true,
+ },
+ });
+ const opt_slice_errors_ty = try mod.optionalType(slice_errors_ty.toIntern());
+ const errors_payload_val: InternPool.Index = if (error_field_vals) |vals| v: {
+ const array_errors_ty = try mod.arrayType(.{
+ .len = vals.len,
+ .child = error_field_ty.toIntern(),
+ .sentinel = .none,
+ });
const new_decl = try fields_anon_decl.finish(
- try Type.Tag.array.create(fields_anon_decl.arena(), .{
- .len = vals.len,
- .elem_type = error_field_ty,
- }),
- try Value.Tag.aggregate.create(
- fields_anon_decl.arena(),
- vals,
- ),
+ array_errors_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = array_errors_ty.toIntern(),
+ .storage = .{ .elems = vals },
+ } })).toValue(),
0, // default alignment
);
-
- const new_decl_val = try Value.Tag.decl_ref.create(sema.arena, new_decl);
- const slice_val = try Value.Tag.slice.create(sema.arena, .{
- .ptr = new_decl_val,
- .len = try Value.Tag.int_u64.create(sema.arena, vals.len),
- });
- break :v try Value.Tag.opt_payload.create(sema.arena, slice_val);
- } else Value.null;
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = slice_errors_ty.toIntern(),
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, vals.len)).toIntern(),
+ } });
+ } else .none;
+ const errors_val = try mod.intern(.{ .opt = .{
+ .ty = opt_slice_errors_ty.toIntern(),
+ .val = errors_payload_val,
+ } });
// Construct Type{ .ErrorSet = errors_val }
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorSet)),
- .val = errors_val,
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorSet))).toIntern(),
+ .val = errors_val,
+ } })).toValue());
},
.ErrorUnion => {
- const field_values = try sema.arena.alloc(Value, 2);
- // error_set: type,
- field_values[0] = try Value.Tag.ty.create(sema.arena, ty.errorUnionSet());
- // payload: type,
- field_values[1] = try Value.Tag.ty.create(sema.arena, ty.errorUnionPayload());
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.ErrorUnion)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ const error_union_field_ty = t: {
+ const error_union_field_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "ErrorUnion"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, error_union_field_ty_decl_index);
+ try sema.ensureDeclAnalyzed(error_union_field_ty_decl_index);
+ const error_union_field_ty_decl = mod.declPtr(error_union_field_ty_decl_index);
+ break :t error_union_field_ty_decl.val.toType();
+ };
+
+ const field_values = .{
+ // error_set: type,
+ ty.errorUnionSet(mod).toIntern(),
+ // payload: type,
+ ty.errorUnionPayload(mod).toIntern(),
+ };
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.ErrorUnion))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = error_union_field_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Enum => {
// TODO: look into memoizing this result.
- var int_tag_type_buffer: Type.Payload.Bits = undefined;
- const int_tag_ty = try ty.intTagType(&int_tag_type_buffer).copy(sema.arena);
-
- const is_exhaustive = Value.makeBool(!ty.isNonexhaustiveEnum());
+ const is_exhaustive = Value.makeBool(ip.indexToKey(ty.toIntern()).enum_type.tag_mode != .nonexhaustive);
var fields_anon_decl = try block.startAnonDecl();
defer fields_anon_decl.deinit();
@@ -16067,88 +16914,121 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const enum_field_ty_decl_index = (try sema.namespaceLookup(
block,
src,
- type_info_ty.getNamespace().?,
- "EnumField",
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "EnumField"),
)).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, enum_field_ty_decl_index);
try sema.ensureDeclAnalyzed(enum_field_ty_decl_index);
- const enum_field_ty_decl = sema.mod.declPtr(enum_field_ty_decl_index);
- var buffer: Value.ToTypeBuffer = undefined;
- break :t try enum_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
+ const enum_field_ty_decl = mod.declPtr(enum_field_ty_decl_index);
+ break :t enum_field_ty_decl.val.toType();
};
- const enum_fields = ty.enumFields();
- const enum_field_vals = try fields_anon_decl.arena().alloc(Value, enum_fields.count());
-
+ const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.indexToKey(ty.toIntern()).enum_type.names.len);
for (enum_field_vals, 0..) |*field_val, i| {
- var tag_val_payload: Value.Payload.U32 = .{
- .base = .{ .tag = .enum_field_index },
- .data = @intCast(u32, i),
- };
- const tag_val = Value.initPayload(&tag_val_payload.base);
-
- var buffer: Value.Payload.U64 = undefined;
- const int_val = try tag_val.enumToInt(ty, &buffer).copy(fields_anon_decl.arena());
-
- const name = enum_fields.keys()[i];
+ const enum_type = ip.indexToKey(ty.toIntern()).enum_type;
+ const value_val = if (enum_type.values.len > 0)
+ try mod.intern_pool.getCoerced(gpa, enum_type.values[i], .comptime_int_type)
+ else
+ try mod.intern(.{ .int = .{
+ .ty = .comptime_int_type,
+ .storage = .{ .u64 = @intCast(u64, i) },
+ } });
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = try sema.arena.dupe(u8, ip.stringToSlice(enum_type.names[i]));
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes = try anon_decl.arena().dupeZ(u8, name);
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
- const enum_field_fields = try fields_anon_decl.arena().create([2]Value);
- enum_field_fields.* = .{
+ const enum_field_fields = .{
// name: []const u8,
name_val,
// value: comptime_int,
- int_val,
+ value_val,
};
- field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), enum_field_fields);
+ field_val.* = try mod.intern(.{ .aggregate = .{
+ .ty = enum_field_ty.toIntern(),
+ .storage = .{ .elems = &enum_field_fields },
+ } });
}
const fields_val = v: {
+ const fields_array_ty = try mod.arrayType(.{
+ .len = enum_field_vals.len,
+ .child = enum_field_ty.toIntern(),
+ .sentinel = .none,
+ });
const new_decl = try fields_anon_decl.finish(
- try Type.Tag.array.create(fields_anon_decl.arena(), .{
- .len = enum_field_vals.len,
- .elem_type = enum_field_ty,
- }),
- try Value.Tag.aggregate.create(
- fields_anon_decl.arena(),
- enum_field_vals,
- ),
+ fields_array_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = fields_array_ty.toIntern(),
+ .storage = .{ .elems = enum_field_vals },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.decl_ref.create(sema.arena, new_decl);
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = (try mod.ptrType(.{
+ .child = enum_field_ty.toIntern(),
+ .flags = .{
+ .size = .Slice,
+ .is_const = true,
+ },
+ })).toIntern(),
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, enum_field_vals.len)).toIntern(),
+ } });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace());
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.indexToKey(ty.toIntern()).enum_type.namespace);
+
+ const type_enum_ty = t: {
+ const type_enum_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Enum"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, type_enum_ty_decl_index);
+ try sema.ensureDeclAnalyzed(type_enum_ty_decl_index);
+ const type_enum_ty_decl = mod.declPtr(type_enum_ty_decl_index);
+ break :t type_enum_ty_decl.val.toType();
+ };
- const field_values = try sema.arena.create([4]Value);
- field_values.* = .{
+ const field_values = .{
// tag_type: type,
- try Value.Tag.ty.create(sema.arena, int_tag_ty),
+ ip.indexToKey(ty.toIntern()).enum_type.tag_ty,
// fields: []const EnumField,
fields_val,
// decls: []const Declaration,
decls_val,
// is_exhaustive: bool,
- is_exhaustive,
+ is_exhaustive.toIntern(),
};
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Enum)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Enum))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = type_enum_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Union => {
// TODO: look into memoizing this result.
@@ -16156,91 +17036,135 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
var fields_anon_decl = try block.startAnonDecl();
defer fields_anon_decl.deinit();
+ const type_union_ty = t: {
+ const type_union_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Union"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, type_union_ty_decl_index);
+ try sema.ensureDeclAnalyzed(type_union_ty_decl_index);
+ const type_union_ty_decl = mod.declPtr(type_union_ty_decl_index);
+ break :t type_union_ty_decl.val.toType();
+ };
+
const union_field_ty = t: {
const union_field_ty_decl_index = (try sema.namespaceLookup(
block,
src,
- type_info_ty.getNamespace().?,
- "UnionField",
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "UnionField"),
)).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, union_field_ty_decl_index);
try sema.ensureDeclAnalyzed(union_field_ty_decl_index);
- const union_field_ty_decl = sema.mod.declPtr(union_field_ty_decl_index);
- var buffer: Value.ToTypeBuffer = undefined;
- break :t try union_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
+ const union_field_ty_decl = mod.declPtr(union_field_ty_decl_index);
+ break :t union_field_ty_decl.val.toType();
};
const union_ty = try sema.resolveTypeFields(ty);
try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
- const layout = union_ty.containerLayout();
+ const layout = union_ty.containerLayout(mod);
- const union_fields = union_ty.unionFields();
- const union_field_vals = try fields_anon_decl.arena().alloc(Value, union_fields.count());
+ const union_fields = union_ty.unionFields(mod);
+ const union_field_vals = try gpa.alloc(InternPool.Index, union_fields.count());
+ defer gpa.free(union_field_vals);
for (union_field_vals, 0..) |*field_val, i| {
const field = union_fields.values()[i];
- const name = union_fields.keys()[i];
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = try sema.arena.dupe(u8, ip.stringToSlice(union_fields.keys()[i]));
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes = try anon_decl.arena().dupeZ(u8, name);
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl);
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
- const union_field_fields = try fields_anon_decl.arena().create([3]Value);
const alignment = switch (layout) {
.Auto, .Extern => try sema.unionFieldAlignment(field),
.Packed => 0,
};
- union_field_fields.* = .{
+ const union_field_fields = .{
// name: []const u8,
name_val,
// type: type,
- try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
+ field.ty.toIntern(),
// alignment: comptime_int,
- try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
+ (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
};
- field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), union_field_fields);
+ field_val.* = try mod.intern(.{ .aggregate = .{
+ .ty = union_field_ty.toIntern(),
+ .storage = .{ .elems = &union_field_fields },
+ } });
}
const fields_val = v: {
+ const array_fields_ty = try mod.arrayType(.{
+ .len = union_field_vals.len,
+ .child = union_field_ty.toIntern(),
+ .sentinel = .none,
+ });
const new_decl = try fields_anon_decl.finish(
- try Type.Tag.array.create(fields_anon_decl.arena(), .{
- .len = union_field_vals.len,
- .elem_type = union_field_ty,
- }),
- try Value.Tag.aggregate.create(
- fields_anon_decl.arena(),
- try fields_anon_decl.arena().dupe(Value, union_field_vals),
- ),
+ array_fields_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = array_fields_ty.toIntern(),
+ .storage = .{ .elems = union_field_vals },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.slice.create(sema.arena, .{
- .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
- .len = try Value.Tag.int_u64.create(sema.arena, union_field_vals.len),
- });
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = (try mod.ptrType(.{
+ .child = union_field_ty.toIntern(),
+ .flags = .{
+ .size = .Slice,
+ .is_const = true,
+ },
+ })).toIntern(),
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, union_field_vals.len)).toIntern(),
+ } });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespace());
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, union_ty.getNamespaceIndex(mod));
- const enum_tag_ty_val = if (union_ty.unionTagType()) |tag_ty| v: {
- const ty_val = try Value.Tag.ty.create(sema.arena, tag_ty);
- break :v try Value.Tag.opt_payload.create(sema.arena, ty_val);
- } else Value.null;
+ const enum_tag_ty_val = try mod.intern(.{ .opt = .{
+ .ty = (try mod.optionalType(.type_type)).toIntern(),
+ .val = if (union_ty.unionTagType(mod)) |tag_ty| tag_ty.toIntern() else .none,
+ } });
+
+ const container_layout_ty = t: {
+ const decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "ContainerLayout"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
+ try sema.ensureDeclAnalyzed(decl_index);
+ const decl = mod.declPtr(decl_index);
+ break :t decl.val.toType();
+ };
- const field_values = try sema.arena.create([4]Value);
- field_values.* = .{
+ const field_values = .{
// layout: ContainerLayout,
- try Value.Tag.enum_field_index.create(
- sema.arena,
- @enumToInt(layout),
- ),
+ (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(),
// tag_type: ?type,
enum_tag_ty_val,
@@ -16249,14 +17173,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// decls: []const Declaration,
decls_val,
};
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Union)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Union))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = type_union_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Struct => {
// TODO: look into memoizing this result.
@@ -16264,154 +17188,212 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
var fields_anon_decl = try block.startAnonDecl();
defer fields_anon_decl.deinit();
+ const type_struct_ty = t: {
+ const type_struct_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Struct"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, type_struct_ty_decl_index);
+ try sema.ensureDeclAnalyzed(type_struct_ty_decl_index);
+ const type_struct_ty_decl = mod.declPtr(type_struct_ty_decl_index);
+ break :t type_struct_ty_decl.val.toType();
+ };
+
const struct_field_ty = t: {
const struct_field_ty_decl_index = (try sema.namespaceLookup(
block,
src,
- type_info_ty.getNamespace().?,
- "StructField",
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "StructField"),
)).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, struct_field_ty_decl_index);
try sema.ensureDeclAnalyzed(struct_field_ty_decl_index);
- const struct_field_ty_decl = sema.mod.declPtr(struct_field_ty_decl_index);
- var buffer: Value.ToTypeBuffer = undefined;
- break :t try struct_field_ty_decl.val.toType(&buffer).copy(fields_anon_decl.arena());
+ const struct_field_ty_decl = mod.declPtr(struct_field_ty_decl_index);
+ break :t struct_field_ty_decl.val.toType();
};
+
const struct_ty = try sema.resolveTypeFields(ty);
try sema.resolveTypeLayout(ty); // Getting alignment requires type layout
- const layout = struct_ty.containerLayout();
-
- const struct_field_vals = fv: {
- if (struct_ty.isSimpleTupleOrAnonStruct()) {
- const tuple = struct_ty.tupleFields();
- const field_types = tuple.types;
- const struct_field_vals = try fields_anon_decl.arena().alloc(Value, field_types.len);
- for (struct_field_vals, 0..) |*struct_field_val, i| {
- const field_ty = field_types[i];
- const name_val = v: {
- var anon_decl = try block.startAnonDecl();
- defer anon_decl.deinit();
- const bytes = if (struct_ty.castTag(.anon_struct)) |payload|
- try anon_decl.arena().dupeZ(u8, payload.data.names[i])
- else
- try std.fmt.allocPrintZ(anon_decl.arena(), "{d}", .{i});
- const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
- 0, // default alignment
- );
- break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{
- .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl),
- .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len),
- });
- };
-
- const struct_field_fields = try fields_anon_decl.arena().create([5]Value);
- const field_val = tuple.values[i];
- const is_comptime = field_val.tag() != .unreachable_value;
- const opt_default_val = if (is_comptime) field_val else null;
- const default_val_ptr = try sema.optRefValue(block, field_ty, opt_default_val);
- struct_field_fields.* = .{
- // name: []const u8,
- name_val,
- // type: type,
- try Value.Tag.ty.create(fields_anon_decl.arena(), field_ty),
- // default_value: ?*const anyopaque,
- try default_val_ptr.copy(fields_anon_decl.arena()),
- // is_comptime: bool,
- Value.makeBool(is_comptime),
- // alignment: comptime_int,
- try field_ty.lazyAbiAlignment(target, fields_anon_decl.arena()),
- };
- struct_field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields);
- }
- break :fv struct_field_vals;
- }
- const struct_fields = struct_ty.structFields();
- const struct_field_vals = try fields_anon_decl.arena().alloc(Value, struct_fields.count());
+ const layout = struct_ty.containerLayout(mod);
+
+ var struct_field_vals: []InternPool.Index = &.{};
+ defer gpa.free(struct_field_vals);
+ fv: {
+ const struct_type = switch (ip.indexToKey(struct_ty.toIntern())) {
+ .anon_struct_type => |tuple| {
+ struct_field_vals = try gpa.alloc(InternPool.Index, tuple.types.len);
+ for (struct_field_vals, 0..) |*struct_field_val, i| {
+ const anon_struct_type = ip.indexToKey(struct_ty.toIntern()).anon_struct_type;
+ const field_ty = anon_struct_type.types[i];
+ const field_val = anon_struct_type.values[i];
+ const name_val = v: {
+ var anon_decl = try block.startAnonDecl();
+ defer anon_decl.deinit();
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const bytes = if (tuple.names.len != 0)
+ // https://github.com/ziglang/zig/issues/15709
+ try sema.arena.dupe(u8, ip.stringToSlice(ip.indexToKey(struct_ty.toIntern()).anon_struct_type.names[i]))
+ else
+ try std.fmt.allocPrint(sema.arena, "{d}", .{i});
+ const new_decl_ty = try mod.arrayType(.{
+ .len = bytes.len,
+ .child = .u8_type,
+ });
+ const new_decl = try anon_decl.finish(
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = bytes },
+ } })).toValue(),
+ 0, // default alignment
+ );
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, bytes.len)).toIntern(),
+ } });
+ };
- for (struct_field_vals, 0..) |*field_val, i| {
- const field = struct_fields.values()[i];
- const name = struct_fields.keys()[i];
+ const is_comptime = field_val != .none;
+ const opt_default_val = if (is_comptime) field_val.toValue() else null;
+ const default_val_ptr = try sema.optRefValue(block, field_ty.toType(), opt_default_val);
+ const struct_field_fields = .{
+ // name: []const u8,
+ name_val,
+ // type: type,
+ field_ty,
+ // default_value: ?*const anyopaque,
+ default_val_ptr.toIntern(),
+ // is_comptime: bool,
+ Value.makeBool(is_comptime).toIntern(),
+ // alignment: comptime_int,
+ (try mod.intValue(Type.comptime_int, field_ty.toType().abiAlignment(mod))).toIntern(),
+ };
+ struct_field_val.* = try mod.intern(.{ .aggregate = .{
+ .ty = struct_field_ty.toIntern(),
+ .storage = .{ .elems = &struct_field_fields },
+ } });
+ }
+ break :fv;
+ },
+ .struct_type => |s| s,
+ else => unreachable,
+ };
+ const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse break :fv;
+ struct_field_vals = try gpa.alloc(InternPool.Index, struct_obj.fields.count());
+
+ for (
+ struct_field_vals,
+ struct_obj.fields.keys(),
+ struct_obj.fields.values(),
+ ) |*field_val, name_nts, field| {
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = try sema.arena.dupe(u8, ip.stringToSlice(name_nts));
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes = try anon_decl.arena().dupeZ(u8, name);
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.slice.create(fields_anon_decl.arena(), .{
- .ptr = try Value.Tag.decl_ref.create(fields_anon_decl.arena(), new_decl),
- .len = try Value.Tag.int_u64.create(fields_anon_decl.arena(), bytes.len),
- });
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
- const struct_field_fields = try fields_anon_decl.arena().create([5]Value);
- const opt_default_val = if (field.default_val.tag() == .unreachable_value)
+ const opt_default_val = if (field.default_val == .none)
null
else
- field.default_val;
+ field.default_val.toValue();
const default_val_ptr = try sema.optRefValue(block, field.ty, opt_default_val);
- const alignment = field.alignment(target, layout);
+ const alignment = field.alignment(mod, layout);
- struct_field_fields.* = .{
+ const struct_field_fields = .{
// name: []const u8,
name_val,
// type: type,
- try Value.Tag.ty.create(fields_anon_decl.arena(), field.ty),
+ field.ty.toIntern(),
// default_value: ?*const anyopaque,
- try default_val_ptr.copy(fields_anon_decl.arena()),
+ default_val_ptr.toIntern(),
// is_comptime: bool,
- Value.makeBool(field.is_comptime),
+ Value.makeBool(field.is_comptime).toIntern(),
// alignment: comptime_int,
- try Value.Tag.int_u64.create(fields_anon_decl.arena(), alignment),
+ (try mod.intValue(Type.comptime_int, alignment)).toIntern(),
};
- field_val.* = try Value.Tag.aggregate.create(fields_anon_decl.arena(), struct_field_fields);
+ field_val.* = try mod.intern(.{ .aggregate = .{
+ .ty = struct_field_ty.toIntern(),
+ .storage = .{ .elems = &struct_field_fields },
+ } });
}
- break :fv struct_field_vals;
- };
+ }
const fields_val = v: {
+ const array_fields_ty = try mod.arrayType(.{
+ .len = struct_field_vals.len,
+ .child = struct_field_ty.toIntern(),
+ .sentinel = .none,
+ });
const new_decl = try fields_anon_decl.finish(
- try Type.Tag.array.create(fields_anon_decl.arena(), .{
- .len = struct_field_vals.len,
- .elem_type = struct_field_ty,
- }),
- try Value.Tag.aggregate.create(
- fields_anon_decl.arena(),
- try fields_anon_decl.arena().dupe(Value, struct_field_vals),
- ),
+ array_fields_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = array_fields_ty.toIntern(),
+ .storage = .{ .elems = struct_field_vals },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.slice.create(sema.arena, .{
- .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
- .len = try Value.Tag.int_u64.create(sema.arena, struct_field_vals.len),
- });
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = (try mod.ptrType(.{
+ .child = struct_field_ty.toIntern(),
+ .flags = .{
+ .size = .Slice,
+ .is_const = true,
+ },
+ })).toIntern(),
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, struct_field_vals.len)).toIntern(),
+ } });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespace());
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, struct_ty.getNamespaceIndex(mod));
- const backing_integer_val = blk: {
- if (layout == .Packed) {
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
+ const backing_integer_val = try mod.intern(.{ .opt = .{
+ .ty = (try mod.optionalType(.type_type)).toIntern(),
+ .val = if (layout == .Packed) val: {
+ const struct_obj = mod.typeToStruct(struct_ty).?;
assert(struct_obj.haveLayout());
- assert(struct_obj.backing_int_ty.isInt());
- const backing_int_ty_val = try Value.Tag.ty.create(sema.arena, struct_obj.backing_int_ty);
- break :blk try Value.Tag.opt_payload.create(sema.arena, backing_int_ty_val);
- } else {
- break :blk Value.initTag(.null_value);
- }
+ assert(struct_obj.backing_int_ty.isInt(mod));
+ break :val struct_obj.backing_int_ty.toIntern();
+ } else .none,
+ } });
+
+ const container_layout_ty = t: {
+ const decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ (try sema.getBuiltinType("Type")).getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "ContainerLayout"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
+ try sema.ensureDeclAnalyzed(decl_index);
+ const decl = mod.declPtr(decl_index);
+ break :t decl.val.toType();
};
- const field_values = try sema.arena.create([5]Value);
- field_values.* = .{
+ const field_values = [_]InternPool.Index{
// layout: ContainerLayout,
- try Value.Tag.enum_field_index.create(
- sema.arena,
- @enumToInt(layout),
- ),
+ (try mod.enumValueFieldIndex(container_layout_ty, @enumToInt(layout))).toIntern(),
// backing_integer: ?type,
backing_integer_val,
// fields: []const StructField,
@@ -16419,36 +17401,48 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
// decls: []const Declaration,
decls_val,
// is_tuple: bool,
- Value.makeBool(struct_ty.isTuple()),
+ Value.makeBool(struct_ty.isTuple(mod)).toIntern(),
};
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Struct)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Struct))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = type_struct_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Opaque => {
// TODO: look into memoizing this result.
+ const type_opaque_ty = t: {
+ const type_opaque_ty_decl_index = (try sema.namespaceLookup(
+ block,
+ src,
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, "Opaque"),
+ )).?;
+ try mod.declareDeclDependency(sema.owner_decl_index, type_opaque_ty_decl_index);
+ try sema.ensureDeclAnalyzed(type_opaque_ty_decl_index);
+ const type_opaque_ty_decl = mod.declPtr(type_opaque_ty_decl_index);
+ break :t type_opaque_ty_decl.val.toType();
+ };
+
const opaque_ty = try sema.resolveTypeFields(ty);
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespace());
+ const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, opaque_ty.getNamespaceIndex(mod));
- const field_values = try sema.arena.create([1]Value);
- field_values.* = .{
+ const field_values = .{
// decls: []const Declaration,
decls_val,
};
-
- return sema.addConstant(
- type_info_ty,
- try Value.Tag.@"union".create(sema.arena, .{
- .tag = try Value.Tag.enum_field_index.create(sema.arena, @enumToInt(std.builtin.TypeId.Opaque)),
- .val = try Value.Tag.aggregate.create(sema.arena, field_values),
- }),
- );
+ return sema.addConstant(type_info_ty, (try mod.intern(.{ .un = .{
+ .ty = type_info_ty.toIntern(),
+ .tag = (try mod.enumValueFieldIndex(type_info_tag_ty, @enumToInt(std.builtin.TypeId.Opaque))).toIntern(),
+ .val = try mod.intern(.{ .aggregate = .{
+ .ty = type_opaque_ty.toIntern(),
+ .storage = .{ .elems = &field_values },
+ } }),
+ } })).toValue());
},
.Frame => return sema.failWithUseOfAsync(block, src),
.AnyFrame => return sema.failWithUseOfAsync(block, src),
@@ -16460,8 +17454,11 @@ fn typeInfoDecls(
block: *Block,
src: LazySrcLoc,
type_info_ty: Type,
- opt_namespace: ?*Module.Namespace,
-) CompileError!Value {
+ opt_namespace: Module.Namespace.OptionalIndex,
+) CompileError!InternPool.Index {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+
var decls_anon_decl = try block.startAnonDecl();
defer decls_anon_decl.deinit();
@@ -16469,89 +17466,110 @@ fn typeInfoDecls(
const declaration_ty_decl_index = (try sema.namespaceLookup(
block,
src,
- type_info_ty.getNamespace().?,
- "Declaration",
+ type_info_ty.getNamespaceIndex(mod).unwrap().?,
+ try mod.intern_pool.getOrPutString(gpa, "Declaration"),
)).?;
- try sema.mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, declaration_ty_decl_index);
try sema.ensureDeclAnalyzed(declaration_ty_decl_index);
- const declaration_ty_decl = sema.mod.declPtr(declaration_ty_decl_index);
- var buffer: Value.ToTypeBuffer = undefined;
- break :t try declaration_ty_decl.val.toType(&buffer).copy(decls_anon_decl.arena());
+ const declaration_ty_decl = mod.declPtr(declaration_ty_decl_index);
+ break :t declaration_ty_decl.val.toType();
};
- try sema.queueFullTypeResolution(try declaration_ty.copy(sema.arena));
+ try sema.queueFullTypeResolution(declaration_ty);
- var decl_vals = std.ArrayList(Value).init(sema.gpa);
+ var decl_vals = std.ArrayList(InternPool.Index).init(gpa);
defer decl_vals.deinit();
- var seen_namespaces = std.AutoHashMap(*Namespace, void).init(sema.gpa);
+ var seen_namespaces = std.AutoHashMap(*Namespace, void).init(gpa);
defer seen_namespaces.deinit();
- if (opt_namespace) |some| {
- try sema.typeInfoNamespaceDecls(block, decls_anon_decl.arena(), some, &decl_vals, &seen_namespaces);
+ if (opt_namespace.unwrap()) |namespace_index| {
+ const namespace = mod.namespacePtr(namespace_index);
+ try sema.typeInfoNamespaceDecls(block, namespace, declaration_ty, &decl_vals, &seen_namespaces);
}
+ const array_decl_ty = try mod.arrayType(.{
+ .len = decl_vals.items.len,
+ .child = declaration_ty.toIntern(),
+ .sentinel = .none,
+ });
const new_decl = try decls_anon_decl.finish(
- try Type.Tag.array.create(decls_anon_decl.arena(), .{
- .len = decl_vals.items.len,
- .elem_type = declaration_ty,
- }),
- try Value.Tag.aggregate.create(
- decls_anon_decl.arena(),
- try decls_anon_decl.arena().dupe(Value, decl_vals.items),
- ),
+ array_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = array_decl_ty.toIntern(),
+ .storage = .{ .elems = decl_vals.items },
+ } })).toValue(),
0, // default alignment
);
- return try Value.Tag.slice.create(sema.arena, .{
- .ptr = try Value.Tag.decl_ref.create(sema.arena, new_decl),
- .len = try Value.Tag.int_u64.create(sema.arena, decl_vals.items.len),
- });
+ return try mod.intern(.{ .ptr = .{
+ .ty = (try mod.ptrType(.{
+ .child = declaration_ty.toIntern(),
+ .flags = .{
+ .size = .Slice,
+ .is_const = true,
+ },
+ })).toIntern(),
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, decl_vals.items.len)).toIntern(),
+ } });
}
fn typeInfoNamespaceDecls(
sema: *Sema,
block: *Block,
- decls_anon_decl: Allocator,
namespace: *Namespace,
- decl_vals: *std.ArrayList(Value),
+ declaration_ty: Type,
+ decl_vals: *std.ArrayList(InternPool.Index),
seen_namespaces: *std.AutoHashMap(*Namespace, void),
) !void {
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const gop = try seen_namespaces.getOrPut(namespace);
if (gop.found_existing) return;
const decls = namespace.decls.keys();
for (decls) |decl_index| {
- const decl = sema.mod.declPtr(decl_index);
+ const decl = mod.declPtr(decl_index);
if (decl.kind == .@"usingnamespace") {
if (decl.analysis == .in_progress) continue;
- try sema.mod.ensureDeclAnalyzed(decl_index);
- var buf: Value.ToTypeBuffer = undefined;
- const new_ns = decl.val.toType(&buf).getNamespace().?;
- try sema.typeInfoNamespaceDecls(block, decls_anon_decl, new_ns, decl_vals, seen_namespaces);
+ try mod.ensureDeclAnalyzed(decl_index);
+ const new_ns = decl.val.toType().getNamespace(mod).?;
+ try sema.typeInfoNamespaceDecls(block, new_ns, declaration_ty, decl_vals, seen_namespaces);
continue;
}
if (decl.kind != .named) continue;
const name_val = v: {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes = try anon_decl.arena().dupeZ(u8, mem.sliceTo(decl.name, 0));
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const name = try sema.arena.dupe(u8, ip.stringToSlice(decl.name));
+ const new_decl_ty = try mod.arrayType(.{
+ .len = name.len,
+ .child = .u8_type,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ new_decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = new_decl_ty.toIntern(),
+ .storage = .{ .bytes = name },
+ } })).toValue(),
0, // default alignment
);
- break :v try Value.Tag.slice.create(decls_anon_decl, .{
- .ptr = try Value.Tag.decl_ref.create(decls_anon_decl, new_decl),
- .len = try Value.Tag.int_u64.create(decls_anon_decl, bytes.len),
- });
+ break :v try mod.intern(.{ .ptr = .{
+ .ty = .slice_const_u8_type,
+ .addr = .{ .decl = new_decl },
+ .len = (try mod.intValue(Type.usize, name.len)).toIntern(),
+ } });
};
- const fields = try decls_anon_decl.create([2]Value);
- fields.* = .{
+ const fields = .{
//name: []const u8,
name_val,
//is_pub: bool,
- Value.makeBool(decl.is_pub),
+ Value.makeBool(decl.is_pub).toIntern(),
};
- try decl_vals.append(try Value.Tag.aggregate.create(decls_anon_decl, fields));
+ try decl_vals.append(try mod.intern(.{ .aggregate = .{
+ .ty = declaration_ty.toIntern(),
+ .storage = .{ .elems = &fields },
+ } }));
}
}
@@ -16586,7 +17604,7 @@ fn zirTypeofBuiltin(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErr
const operand = try sema.resolveBody(&child_block, body, inst);
const operand_ty = sema.typeOf(operand);
- if (operand_ty.tag() == .generic_poison) return error.GenericPoison;
+ if (operand_ty.isGenericPoison()) return error.GenericPoison;
return sema.addType(operand_ty);
}
@@ -16600,10 +17618,11 @@ fn zirTypeofLog2IntType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) Compil
}
fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) CompileError!Type {
- switch (operand.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (operand.zigTypeTag(mod)) {
.ComptimeInt => return Type.comptime_int,
.Int => {
- const bits = operand.bitSize(sema.mod.getTarget());
+ const bits = operand.bitSize(mod);
const count = if (bits == 0)
0
else blk: {
@@ -16614,14 +17633,14 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
}
break :blk count;
};
- return Module.makeIntType(sema.arena, .unsigned, count);
+ return mod.intType(.unsigned, count);
},
.Vector => {
- const elem_ty = operand.elemType2();
+ const elem_ty = operand.elemType2(mod);
const log2_elem_ty = try sema.log2IntType(block, elem_ty, src);
- return Type.Tag.vector.create(sema.arena, .{
- .len = operand.vectorLen(),
- .elem_type = log2_elem_ty,
+ return mod.vectorType(.{
+ .len = operand.vectorLen(mod),
+ .child = log2_elem_ty.toIntern(),
});
},
else => {},
@@ -16630,7 +17649,7 @@ fn log2IntType(sema: *Sema, block: *Block, operand: Type, src: LazySrcLoc) Compi
block,
src,
"bit shifting operation expected integer type, found '{}'",
- .{operand.fmt(sema.mod)},
+ .{operand.fmt(mod)},
);
}
@@ -16681,6 +17700,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_un_op = inst_data.src_node };
@@ -16688,7 +17708,7 @@ fn zirBoolNot(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const operand = try sema.coerce(block, Type.bool, uncasted_operand, operand_src);
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- return if (val.isUndef())
+ return if (val.isUndef(mod))
sema.addConstUndef(Type.bool)
else if (val.toBool())
Air.Inst.Ref.bool_false
@@ -16708,6 +17728,7 @@ fn zirBoolBr(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const datas = sema.code.instructions.items(.data);
const inst_data = datas[inst].bool_br;
const lhs = try sema.resolveInst(inst_data.lhs);
@@ -16756,12 +17777,12 @@ fn zirBoolBr(
_ = try lhs_block.addBr(block_inst, lhs_result);
const rhs_result = try sema.resolveBody(rhs_block, body, inst);
- if (!sema.typeOf(rhs_result).isNoReturn()) {
+ if (!sema.typeOf(rhs_result).isNoReturn(mod)) {
_ = try rhs_block.addBr(block_inst, rhs_result);
}
const result = sema.finishCondBr(parent_block, &child_block, &then_block, &else_block, lhs, block_inst);
- if (!sema.typeOf(rhs_result).isNoReturn()) {
+ if (!sema.typeOf(rhs_result).isNoReturn(mod)) {
if (try sema.resolveDefinedValue(rhs_block, sema.src, rhs_result)) |rhs_val| {
if (is_bool_or and rhs_val.toBool()) {
return Air.Inst.Ref.bool_true;
@@ -16811,9 +17832,10 @@ fn finishCondBr(
}
fn checkNullableType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Optional, .Null, .Undefined => return,
- .Pointer => if (ty.isPtrLikeOptional()) return,
+ .Pointer => if (ty.isPtrLikeOptional(mod)) return,
else => {},
}
return sema.failWithExpectedOptionalType(block, src, ty);
@@ -16842,10 +17864,11 @@ fn zirIsNonNullPtr(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ptr = try sema.resolveInst(inst_data.operand);
- try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2());
+ try sema.checkNullableType(block, src, sema.typeOf(ptr).elemType2(mod));
if ((try sema.resolveMaybeUndefVal(ptr)) == null) {
return block.addUnOp(.is_non_null_ptr, ptr);
}
@@ -16854,10 +17877,11 @@ fn zirIsNonNullPtr(
}
fn checkErrorType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.ErrorSet, .ErrorUnion, .Undefined => return,
else => return sema.fail(block, src, "expected error union type, found '{}'", .{
- ty.fmt(sema.mod),
+ ty.fmt(mod),
}),
}
}
@@ -16877,10 +17901,11 @@ fn zirIsNonErrPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const ptr = try sema.resolveInst(inst_data.operand);
- try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2());
+ try sema.checkErrorType(block, src, sema.typeOf(ptr).elemType2(mod));
const loaded = try sema.analyzeLoad(block, src, ptr, src);
return sema.analyzeIsNonErr(block, src, loaded);
}
@@ -16903,6 +17928,7 @@ fn zirCondbr(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const cond_src: LazySrcLoc = .{ .node_offset_if_cond = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.CondBr, inst_data.payload_index);
@@ -16943,8 +17969,8 @@ fn zirCondbr(
const err_inst_data = sema.code.instructions.items(.data)[index].un_node;
const err_operand = try sema.resolveInst(err_inst_data.operand);
const operand_ty = sema.typeOf(err_operand);
- assert(operand_ty.zigTypeTag() == .ErrorUnion);
- const result_ty = operand_ty.errorUnionSet();
+ assert(operand_ty.zigTypeTag(mod) == .ErrorUnion);
+ const result_ty = operand_ty.errorUnionSet(mod);
break :blk try sub_block.addTyOp(.unwrap_errunion_err, result_ty, err_operand);
};
@@ -16970,7 +17996,7 @@ fn zirCondbr(
return always_noreturn;
}
-fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
+fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
@@ -16978,9 +18004,10 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
const body = sema.code.extra[extra.end..][0..extra.data.body_len];
const err_union = try sema.resolveInst(extra.data.operand);
const err_union_ty = sema.typeOf(err_union);
- if (err_union_ty.zigTypeTag() != .ErrorUnion) {
+ const mod = sema.mod;
+ if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
- err_union_ty.fmt(sema.mod),
+ err_union_ty.fmt(mod),
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
@@ -17015,7 +18042,7 @@ fn zirTry(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!
return try_inst;
}
-fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Zir.Inst.Ref {
+fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
@@ -17024,9 +18051,10 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
const operand = try sema.resolveInst(extra.data.operand);
const err_union = try sema.analyzeLoad(parent_block, src, operand, operand_src);
const err_union_ty = sema.typeOf(err_union);
- if (err_union_ty.zigTypeTag() != .ErrorUnion) {
+ const mod = sema.mod;
+ if (err_union_ty.zigTypeTag(mod) != .ErrorUnion) {
return sema.fail(parent_block, operand_src, "expected error union type, found '{}'", .{
- err_union_ty.fmt(sema.mod),
+ err_union_ty.fmt(mod),
});
}
const is_non_err = try sema.analyzeIsNonErrComptimeOnly(parent_block, operand_src, err_union);
@@ -17047,9 +18075,9 @@ fn zirTryPtr(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileErr
_ = try sema.analyzeBodyInner(&sub_block, body);
const operand_ty = sema.typeOf(operand);
- const ptr_info = operand_ty.ptrInfo().data;
- const res_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = err_union_ty.errorUnionPayload(),
+ const ptr_info = operand_ty.ptrInfo(mod);
+ const res_ty = try Type.ptr(sema.arena, mod, .{
+ .pointee_type = err_union_ty.errorUnionPayload(mod),
.@"addrspace" = ptr_info.@"addrspace",
.mutable = ptr_info.mutable,
.@"allowzero" = ptr_info.@"allowzero",
@@ -17145,16 +18173,17 @@ fn zirRetErrValue(
block: *Block,
inst: Zir.Inst.Index,
) CompileError!Zir.Inst.Index {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].str_tok;
- const err_name = inst_data.get(sema.code);
+ const err_name = try mod.intern_pool.getOrPutString(sema.gpa, inst_data.get(sema.code));
+ _ = try mod.getErrorValue(err_name);
const src = inst_data.src();
-
// Return the error code from the function.
- const kv = try sema.mod.getErrorValue(err_name);
- const result_inst = try sema.addConstant(
- try Type.Tag.error_set_single.create(sema.arena, kv.key),
- try Value.Tag.@"error".create(sema.arena, .{ .name = kv.key }),
- );
+ const error_set_type = try mod.singleErrorSetType(err_name);
+ const result_inst = try sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
+ .ty = error_set_type.toIntern(),
+ .name = err_name,
+ } })).toValue());
return sema.analyzeRet(block, result_inst, src);
}
@@ -17166,16 +18195,17 @@ fn zirRetImplicit(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_tok;
const operand = try sema.resolveInst(inst_data.operand);
const r_brace_src = inst_data.src();
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
- const base_tag = sema.fn_ret_ty.baseZigTypeTag();
+ const base_tag = sema.fn_ret_ty.baseZigTypeTag(mod);
if (base_tag == .NoReturn) {
const msg = msg: {
const msg = try sema.errMsg(block, ret_ty_src, "function declared '{}' implicitly returns", .{
- sema.fn_ret_ty.fmt(sema.mod),
+ sema.fn_ret_ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
@@ -17185,7 +18215,7 @@ fn zirRetImplicit(
} else if (base_tag != .Void) {
const msg = msg: {
const msg = try sema.errMsg(block, ret_ty_src, "function with non-void return type '{}' implicitly returns", .{
- sema.fn_ret_ty.fmt(sema.mod),
+ sema.fn_ret_ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, r_brace_src, msg, "control flow reaches end of body here", .{});
@@ -17223,7 +18253,7 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
if (sema.wantErrorReturnTracing(sema.fn_ret_ty)) {
const is_non_err = try sema.analyzePtrIsNonErr(block, src, ret_ptr);
- return sema.retWithErrTracing(block, src, is_non_err, .ret_load, ret_ptr);
+ return sema.retWithErrTracing(block, is_non_err, .ret_load, ret_ptr);
}
_ = try block.addUnOp(.ret_load, ret_ptr);
@@ -17233,11 +18263,11 @@ fn zirRetLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Zir
fn retWithErrTracing(
sema: *Sema,
block: *Block,
- src: LazySrcLoc,
is_non_err: Air.Inst.Ref,
ret_tag: Air.Inst.Tag,
operand: Air.Inst.Ref,
) CompileError!Zir.Inst.Index {
+ const mod = sema.mod;
const need_check = switch (is_non_err) {
.bool_true => {
_ = try block.addUnOp(ret_tag, operand);
@@ -17249,13 +18279,13 @@ fn retWithErrTracing(
const gpa = sema.gpa;
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
- const ptr_stack_trace_ty = try Type.Tag.single_mut_pointer.create(sema.arena, stack_trace_ty);
+ const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
const return_err_fn = try sema.getBuiltin("returnError");
const args: [1]Air.Inst.Ref = .{err_return_trace};
if (!need_check) {
- _ = try sema.analyzeCall(block, return_err_fn, src, src, .never_inline, false, &args, null);
+ try sema.callBuiltin(block, return_err_fn, .never_inline, &args);
_ = try block.addUnOp(ret_tag, operand);
return always_noreturn;
}
@@ -17266,7 +18296,7 @@ fn retWithErrTracing(
var else_block = block.makeSubBlock();
defer else_block.instructions.deinit(gpa);
- _ = try sema.analyzeCall(&else_block, return_err_fn, src, src, .never_inline, false, &args, null);
+ try sema.callBuiltin(&else_block, return_err_fn, .never_inline, &args);
_ = try else_block.addUnOp(ret_tag, operand);
try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).Struct.fields.len +
@@ -17289,17 +18319,19 @@ fn retWithErrTracing(
}
fn wantErrorReturnTracing(sema: *Sema, fn_ret_ty: Type) bool {
- if (!sema.mod.backendSupportsFeature(.error_return_trace)) return false;
+ const mod = sema.mod;
+ if (!mod.backendSupportsFeature(.error_return_trace)) return false;
- return fn_ret_ty.isError() and
- sema.mod.comp.bin_file.options.error_return_tracing;
+ return fn_ret_ty.isError(mod) and
+ mod.comp.bin_file.options.error_return_tracing;
}
fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].save_err_ret_index;
- if (!sema.mod.backendSupportsFeature(.error_return_trace)) return;
- if (!sema.mod.comp.bin_file.options.error_return_tracing) return;
+ if (!mod.backendSupportsFeature(.error_return_trace)) return;
+ if (!mod.comp.bin_file.options.error_return_tracing) return;
// This is only relevant at runtime.
if (block.is_comptime or block.is_typeof) return;
@@ -17307,7 +18339,7 @@ fn zirSaveErrRetIndex(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const save_index = inst_data.operand == .none or b: {
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
- break :b operand_ty.isError();
+ break :b operand_ty.isError(mod);
};
if (save_index)
@@ -17328,7 +18360,7 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)
const tracy = trace(@src());
defer tracy.end();
- const saved_index = if (Zir.refToIndex(inst_data.block)) |zir_block| b: {
+ const saved_index = if (Zir.refToIndexAllowNone(inst_data.block)) |zir_block| b: {
var block = start_block;
while (true) {
if (block.label) |label| {
@@ -17354,22 +18386,21 @@ fn zirRestoreErrRetIndex(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index)
assert(saved_index != .none); // The .error_return_trace_index field was dropped somewhere
- const operand = try sema.resolveInst(inst_data.operand);
+ const operand = try sema.resolveInstAllowNone(inst_data.operand);
return sema.popErrorReturnTrace(start_block, src, operand, saved_index);
}
fn addToInferredErrorSet(sema: *Sema, uncasted_operand: Air.Inst.Ref) !void {
- assert(sema.fn_ret_ty.zigTypeTag() == .ErrorUnion);
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+ assert(sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion);
- if (sema.fn_ret_ty.errorUnionSet().castTag(.error_set_inferred)) |payload| {
+ if (mod.typeToInferredErrorSet(sema.fn_ret_ty.errorUnionSet(mod))) |ies| {
const op_ty = sema.typeOf(uncasted_operand);
- switch (op_ty.zigTypeTag()) {
- .ErrorSet => {
- try payload.data.addErrorSet(sema.gpa, op_ty);
- },
- .ErrorUnion => {
- try payload.data.addErrorSet(sema.gpa, op_ty.errorUnionSet());
- },
+ switch (op_ty.zigTypeTag(mod)) {
+ .ErrorSet => try ies.addErrorSet(op_ty, ip, gpa),
+ .ErrorUnion => try ies.addErrorSet(op_ty.errorUnionSet(mod), ip, gpa),
else => {},
}
}
@@ -17384,7 +18415,8 @@ fn analyzeRet(
// Special case for returning an error to an inferred error set; we need to
// add the error tag to the inferred error set of the in-scope function, so
// that the coercion below works correctly.
- if (sema.fn_ret_ty.zigTypeTag() == .ErrorUnion) {
+ const mod = sema.mod;
+ if (sema.fn_ret_ty.zigTypeTag(mod) == .ErrorUnion) {
try sema.addToInferredErrorSet(uncasted_operand);
}
const operand = sema.coerceExtra(block, sema.fn_ret_ty, uncasted_operand, src, .{ .is_ret = true }) catch |err| switch (err) {
@@ -17412,7 +18444,7 @@ fn analyzeRet(
// Avoid adding a frame to the error return trace in case the value is comptime-known
// to be not an error.
const is_non_err = try sema.analyzeIsNonErr(block, src, operand);
- return sema.retWithErrTracing(block, src, is_non_err, .ret, operand);
+ return sema.retWithErrTracing(block, is_non_err, .ret, operand);
}
_ = try block.addUnOp(.ret, operand);
@@ -17432,6 +18464,7 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].ptr_type;
const extra = sema.code.extraData(Zir.Inst.PtrType, inst_data.payload_index);
const elem_ty_src: LazySrcLoc = .{ .node_offset_ptr_elem = extra.data.src_node };
@@ -17444,46 +18477,54 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const elem_ty = blk: {
const air_inst = try sema.resolveInst(extra.data.elem_type);
const ty = sema.analyzeAsType(block, elem_ty_src, air_inst) catch |err| {
- if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer()) {
+ if (err == error.AnalysisFail and sema.err != null and sema.typeOf(air_inst).isSinglePointer(mod)) {
try sema.errNote(block, elem_ty_src, sema.err.?, "use '.*' to dereference pointer", .{});
}
return err;
};
- if (ty.tag() == .generic_poison) return error.GenericPoison;
+ if (ty.isGenericPoison()) return error.GenericPoison;
break :blk ty;
};
- const target = sema.mod.getTarget();
+
+ if (elem_ty.zigTypeTag(mod) == .NoReturn)
+ return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
+
+ const target = mod.getTarget();
var extra_i = extra.end;
const sentinel = if (inst_data.flags.has_sentinel) blk: {
const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
extra_i += 1;
- break :blk (try sema.resolveInstConst(block, sentinel_src, ref, "pointer sentinel value must be comptime-known")).val;
- } else null;
+ const coerced = try sema.coerce(block, elem_ty, try sema.resolveInst(ref), sentinel_src);
+ const val = try sema.resolveConstValue(block, sentinel_src, coerced, "pointer sentinel value must be comptime-known");
+ break :blk val.toIntern();
+ } else .none;
- const abi_align: u32 = if (inst_data.flags.has_align) blk: {
+ const abi_align: InternPool.Alignment = if (inst_data.flags.has_align) blk: {
const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
extra_i += 1;
const coerced = try sema.coerce(block, Type.u32, try sema.resolveInst(ref), align_src);
const val = try sema.resolveConstValue(block, align_src, coerced, "pointer alignment must be comptime-known");
// Check if this happens to be the lazy alignment of our element type, in
// which case we can make this 0 without resolving it.
- if (val.castTag(.lazy_align)) |payload| {
- if (payload.data.eql(elem_ty, sema.mod)) {
- break :blk 0;
- }
+ switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .int => |int| switch (int.storage) {
+ .lazy_align => |lazy_ty| if (lazy_ty == elem_ty.toIntern()) break :blk .none,
+ else => {},
+ },
+ else => {},
}
- const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(target, sema)).?);
+ const abi_align = @intCast(u32, (try val.getUnsignedIntAdvanced(mod, sema)).?);
try sema.validateAlign(block, align_src, abi_align);
- break :blk abi_align;
- } else 0;
+ break :blk InternPool.Alignment.fromByteUnits(abi_align);
+ } else .none;
const address_space: std.builtin.AddressSpace = if (inst_data.flags.has_addrspace) blk: {
const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
extra_i += 1;
break :blk try sema.analyzeAddressSpace(block, addrspace_src, ref, .pointer);
- } else if (elem_ty.zigTypeTag() == .Fn and target.cpu.arch == .avr) .flash else .generic;
+ } else if (elem_ty.zigTypeTag(mod) == .Fn and target.cpu.arch == .avr) .flash else .generic;
const bit_offset = if (inst_data.flags.has_bit_range) blk: {
const ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_i]);
@@ -17503,50 +18544,52 @@ fn zirPtrType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return sema.fail(block, bitoffset_src, "bit offset starts after end of host integer", .{});
}
- if (elem_ty.zigTypeTag() == .NoReturn) {
- return sema.fail(block, elem_ty_src, "pointer to noreturn not allowed", .{});
- } else if (elem_ty.zigTypeTag() == .Fn) {
+ if (elem_ty.zigTypeTag(mod) == .Fn) {
if (inst_data.size != .One) {
return sema.fail(block, elem_ty_src, "function pointers must be single pointers", .{});
}
- const fn_align = elem_ty.fnInfo().alignment;
- if (inst_data.flags.has_align and abi_align != 0 and fn_align != 0 and
+ const fn_align = mod.typeToFunc(elem_ty).?.alignment;
+ if (inst_data.flags.has_align and abi_align != .none and fn_align != .none and
abi_align != fn_align)
{
return sema.fail(block, align_src, "function pointer alignment disagrees with function alignment", .{});
}
- } else if (inst_data.size == .Many and elem_ty.zigTypeTag() == .Opaque) {
+ } else if (inst_data.size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, elem_ty_src, "unknown-length pointer to opaque not allowed", .{});
} else if (inst_data.size == .C) {
if (!try sema.validateExternType(elem_ty, .other)) {
const msg = msg: {
- const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, elem_ty_src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl), elem_ty, .other);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, elem_ty_src.toSrcLoc(src_decl, mod), elem_ty, .other);
try sema.addDeclaredHereNote(msg, elem_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (elem_ty.zigTypeTag() == .Opaque) {
+ if (elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, elem_ty_src, "C pointers cannot point to opaque types", .{});
}
}
- const ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = elem_ty,
+ const ty = try mod.ptrType(.{
+ .child = elem_ty.toIntern(),
.sentinel = sentinel,
- .@"align" = abi_align,
- .@"addrspace" = address_space,
- .bit_offset = bit_offset,
- .host_size = host_size,
- .mutable = inst_data.flags.is_mutable,
- .@"allowzero" = inst_data.flags.is_allowzero,
- .@"volatile" = inst_data.flags.is_volatile,
- .size = inst_data.size,
+ .flags = .{
+ .alignment = abi_align,
+ .address_space = address_space,
+ .is_const = !inst_data.flags.is_mutable,
+ .is_allowzero = inst_data.flags.is_allowzero,
+ .is_volatile = inst_data.flags.is_volatile,
+ .size = inst_data.size,
+ },
+ .packed_offset = .{
+ .bit_offset = bit_offset,
+ .host_size = host_size,
+ },
});
return sema.addType(ty);
}
@@ -17558,8 +18601,9 @@ fn zirStructInitEmpty(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileE
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const obj_ty = try sema.resolveType(block, src, inst_data.operand);
+ const mod = sema.mod;
- switch (obj_ty.zigTypeTag()) {
+ switch (obj_ty.zigTypeTag(mod)) {
.Struct => return sema.structInitEmpty(block, obj_ty, src, src),
.Array, .Vector => return sema.arrayInitEmpty(block, src, obj_ty),
.Void => return sema.addConstant(obj_ty, Value.void),
@@ -17575,12 +18619,13 @@ fn structInitEmpty(
dest_src: LazySrcLoc,
init_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const gpa = sema.gpa;
// This logic must be synchronized with that in `zirStructInit`.
const struct_ty = try sema.resolveTypeFields(obj_ty);
// The init values to use for the struct instance.
- const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount());
+ const field_inits = try gpa.alloc(Air.Inst.Ref, struct_ty.structFieldCount(mod));
defer gpa.free(field_inits);
@memset(field_inits, .none);
@@ -17588,20 +18633,19 @@ fn structInitEmpty(
}
fn arrayInitEmpty(sema: *Sema, block: *Block, src: LazySrcLoc, obj_ty: Type) CompileError!Air.Inst.Ref {
- const arr_len = obj_ty.arrayLen();
+ const mod = sema.mod;
+ const arr_len = obj_ty.arrayLen(mod);
if (arr_len != 0) {
- if (obj_ty.zigTypeTag() == .Array) {
+ if (obj_ty.zigTypeTag(mod) == .Array) {
return sema.fail(block, src, "expected {d} array elements; found 0", .{arr_len});
} else {
return sema.fail(block, src, "expected {d} vector elements; found 0", .{arr_len});
}
}
- if (obj_ty.sentinel()) |sentinel| {
- const val = try Value.Tag.empty_array_sentinel.create(sema.arena, sentinel);
- return sema.addConstant(obj_ty, val);
- } else {
- return sema.addConstant(obj_ty, Value.initTag(.empty_array));
- }
+ return sema.addConstant(obj_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = obj_ty.toIntern(),
+ .storage = .{ .elems = &.{} },
+ } })).toValue());
}
fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -17611,7 +18655,7 @@ fn zirUnionInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const init_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
const extra = sema.code.extraData(Zir.Inst.UnionInit, inst_data.payload_index).data;
const union_ty = try sema.resolveType(block, ty_src, extra.union_type);
- const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "name of field being initialized must be comptime-known");
+ const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, "name of field being initialized must be comptime-known");
const init = try sema.resolveInst(extra.init);
return sema.unionInit(block, init, init_src, union_ty, ty_src, field_name, field_src);
}
@@ -17623,21 +18667,23 @@ fn unionInit(
init_src: LazySrcLoc,
union_ty: Type,
union_ty_src: LazySrcLoc,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_src);
- const field = union_ty.unionFields().values()[field_index];
+ const field = union_ty.unionFields(mod).values()[field_index];
const init = try sema.coerce(block, field.ty, uncasted_init, init_src);
if (try sema.resolveMaybeUndefVal(init)) |init_val| {
- const tag_ty = union_ty.unionTagTypeHypothetical();
- const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
- return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
- .tag = tag_val,
- .val = init_val,
- }));
+ const tag_ty = union_ty.unionTagTypeHypothetical(mod);
+ const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
+ const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
+ return sema.addConstant(union_ty, (try mod.intern(.{ .un = .{
+ .ty = union_ty.toIntern(),
+ .tag = try tag_val.intern(tag_ty, mod),
+ .val = try init_val.intern(field.ty, mod),
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, init_src, null);
@@ -17658,29 +18704,30 @@ fn zirStructInit(
const extra = sema.code.extraData(Zir.Inst.StructInit, inst_data.payload_index);
const src = inst_data.src();
+ const mod = sema.mod;
const first_item = sema.code.extraData(Zir.Inst.StructInit.Item, extra.end).data;
const first_field_type_data = zir_datas[first_item.field_type].pl_node;
const first_field_type_extra = sema.code.extraData(Zir.Inst.FieldType, first_field_type_data.payload_index).data;
const resolved_ty = try sema.resolveType(block, src, first_field_type_extra.container_type);
try sema.resolveTypeLayout(resolved_ty);
- if (resolved_ty.zigTypeTag() == .Struct) {
+ if (resolved_ty.zigTypeTag(mod) == .Struct) {
// This logic must be synchronized with that in `zirStructInitEmpty`.
// Maps field index to field_type index of where it was already initialized.
// For making sure all fields are accounted for and no fields are duplicated.
- const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount());
+ const found_fields = try gpa.alloc(Zir.Inst.Index, resolved_ty.structFieldCount(mod));
defer gpa.free(found_fields);
// The init values to use for the struct instance.
- const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount());
+ const field_inits = try gpa.alloc(Air.Inst.Ref, resolved_ty.structFieldCount(mod));
defer gpa.free(field_inits);
@memset(field_inits, .none);
var field_i: u32 = 0;
var extra_index = extra.end;
- const is_packed = resolved_ty.containerLayout() == .Packed;
+ const is_packed = resolved_ty.containerLayout(mod) == .Packed;
while (field_i < extra.data.fields_len) : (field_i += 1) {
const item = sema.code.extraData(Zir.Inst.StructInit.Item, extra_index);
extra_index = item.end;
@@ -17688,8 +18735,8 @@ fn zirStructInit(
const field_type_data = zir_datas[item.data.field_type].pl_node;
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
- const field_index = if (resolved_ty.isTuple())
+ const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));
+ const field_index = if (resolved_ty.isTuple(mod))
try sema.tupleFieldIndex(block, resolved_ty, field_name, field_src)
else
try sema.structFieldIndex(block, resolved_ty, field_name, field_src);
@@ -17707,19 +18754,19 @@ fn zirStructInit(
}
found_fields[field_index] = item.data.field_type;
field_inits[field_index] = try sema.resolveInst(item.data.init);
- if (!is_packed) if (resolved_ty.structFieldValueComptime(field_index)) |default_value| {
+ if (!is_packed) if (try resolved_ty.structFieldValueComptime(mod, field_index)) |default_value| {
const init_val = (try sema.resolveMaybeUndefVal(field_inits[field_index])) orelse {
return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known");
};
- if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index), sema.mod)) {
+ if (!init_val.eql(default_value, resolved_ty.structFieldType(field_index, mod), mod)) {
return sema.failWithInvalidComptimeFieldStore(block, field_src, resolved_ty, field_index);
}
};
}
return sema.finishStructInit(block, src, src, field_inits, resolved_ty, is_ref);
- } else if (resolved_ty.zigTypeTag() == .Union) {
+ } else if (resolved_ty.zigTypeTag(mod) == .Union) {
if (extra.data.fields_len != 1) {
return sema.fail(block, src, "union initialization expects exactly one field", .{});
}
@@ -17729,40 +18776,40 @@ fn zirStructInit(
const field_type_data = zir_datas[item.data.field_type].pl_node;
const field_src: LazySrcLoc = .{ .node_offset_initializer = field_type_data.src_node };
const field_type_extra = sema.code.extraData(Zir.Inst.FieldType, field_type_data.payload_index).data;
- const field_name = sema.code.nullTerminatedString(field_type_extra.name_start);
+ const field_name = try mod.intern_pool.getOrPutString(gpa, sema.code.nullTerminatedString(field_type_extra.name_start));
const field_index = try sema.unionFieldIndex(block, resolved_ty, field_name, field_src);
- const tag_ty = resolved_ty.unionTagTypeHypothetical();
- const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name).?);
- const tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
+ const tag_ty = resolved_ty.unionTagTypeHypothetical(mod);
+ const enum_field_index = @intCast(u32, tag_ty.enumFieldIndex(field_name, mod).?);
+ const tag_val = try mod.enumValueFieldIndex(tag_ty, enum_field_index);
const init_inst = try sema.resolveInst(item.data.init);
if (try sema.resolveMaybeUndefVal(init_inst)) |val| {
- return sema.addConstantMaybeRef(
- block,
- resolved_ty,
- try Value.Tag.@"union".create(sema.arena, .{ .tag = tag_val, .val = val }),
- is_ref,
- );
+ const field = resolved_ty.unionFields(mod).values()[field_index];
+ return sema.addConstantMaybeRef(block, resolved_ty, (try mod.intern(.{ .un = .{
+ .ty = resolved_ty.toIntern(),
+ .tag = try tag_val.intern(tag_ty, mod),
+ .val = try val.intern(field.ty, mod),
+ } })).toValue(), is_ref);
}
if (is_ref) {
- const target = sema.mod.getTarget();
- const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const target = mod.getTarget();
+ const alloc_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = resolved_ty,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
});
const alloc = try block.addTy(.alloc, alloc_ty);
const field_ptr = try sema.unionFieldPtr(block, field_src, alloc, field_name, field_src, resolved_ty, true);
try sema.storePtr(block, src, field_ptr, init_inst);
- const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(), tag_val);
+ const new_tag = try sema.addConstant(resolved_ty.unionTagTypeHypothetical(mod), tag_val);
_ = try block.addBinOp(.set_union_tag, alloc, new_tag);
- return alloc;
+ return sema.makePtrConst(block, alloc);
}
try sema.requireRuntimeBlock(block, src, null);
try sema.queueFullTypeResolution(resolved_ty);
return block.addUnionInit(resolved_ty, field_index, init_inst);
- } else if (resolved_ty.isAnonStruct()) {
+ } else if (resolved_ty.isAnonStruct(mod)) {
return sema.fail(block, src, "TODO anon struct init validation", .{});
}
unreachable;
@@ -17777,101 +18824,100 @@ fn finishStructInit(
struct_ty: Type,
is_ref: bool,
) CompileError!Air.Inst.Ref {
- const gpa = sema.gpa;
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
var root_msg: ?*Module.ErrorMsg = null;
errdefer if (root_msg) |msg| msg.destroy(sema.gpa);
- if (struct_ty.isAnonStruct()) {
- const struct_obj = struct_ty.castTag(.anon_struct).?.data;
- for (struct_obj.values, 0..) |default_val, i| {
- if (field_inits[i] != .none) continue;
-
- if (default_val.tag() == .unreachable_value) {
- const field_name = struct_obj.names[i];
- const template = "missing struct field: {s}";
- const args = .{field_name};
- if (root_msg) |msg| {
- try sema.errNote(block, init_src, msg, template, args);
- } else {
- root_msg = try sema.errMsg(block, init_src, template, args);
- }
- } else {
- field_inits[i] = try sema.addConstant(struct_obj.types[i], default_val);
- }
- }
- } else if (struct_ty.isTuple()) {
- var i: u32 = 0;
- const len = struct_ty.structFieldCount();
- while (i < len) : (i += 1) {
- if (field_inits[i] != .none) continue;
+ switch (ip.indexToKey(struct_ty.toIntern())) {
+ .anon_struct_type => |anon_struct| {
+ for (anon_struct.types, anon_struct.values, 0..) |field_ty, default_val, i| {
+ if (field_inits[i] != .none) continue;
- const default_val = struct_ty.structFieldDefaultValue(i);
- if (default_val.tag() == .unreachable_value) {
- const template = "missing tuple field with index {d}";
- if (root_msg) |msg| {
- try sema.errNote(block, init_src, msg, template, .{i});
+ if (default_val == .none) {
+ if (anon_struct.names.len == 0) {
+ const template = "missing tuple field with index {d}";
+ if (root_msg) |msg| {
+ try sema.errNote(block, init_src, msg, template, .{i});
+ } else {
+ root_msg = try sema.errMsg(block, init_src, template, .{i});
+ }
+ } else {
+ const field_name = anon_struct.names[i];
+ const template = "missing struct field: {}";
+ const args = .{field_name.fmt(ip)};
+ if (root_msg) |msg| {
+ try sema.errNote(block, init_src, msg, template, args);
+ } else {
+ root_msg = try sema.errMsg(block, init_src, template, args);
+ }
+ }
} else {
- root_msg = try sema.errMsg(block, init_src, template, .{i});
+ field_inits[i] = try sema.addConstant(field_ty.toType(), default_val.toValue());
}
- } else {
- field_inits[i] = try sema.addConstant(struct_ty.structFieldType(i), default_val);
}
- }
- } else {
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
- for (struct_obj.fields.values(), 0..) |field, i| {
- if (field_inits[i] != .none) continue;
+ },
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
+ for (struct_obj.fields.values(), 0..) |field, i| {
+ if (field_inits[i] != .none) continue;
- if (field.default_val.tag() == .unreachable_value) {
- const field_name = struct_obj.fields.keys()[i];
- const template = "missing struct field: {s}";
- const args = .{field_name};
- if (root_msg) |msg| {
- try sema.errNote(block, init_src, msg, template, args);
+ if (field.default_val == .none) {
+ const field_name = struct_obj.fields.keys()[i];
+ const template = "missing struct field: {}";
+ const args = .{field_name.fmt(ip)};
+ if (root_msg) |msg| {
+ try sema.errNote(block, init_src, msg, template, args);
+ } else {
+ root_msg = try sema.errMsg(block, init_src, template, args);
+ }
} else {
- root_msg = try sema.errMsg(block, init_src, template, args);
+ field_inits[i] = try sema.addConstant(field.ty, field.default_val.toValue());
}
- } else {
- field_inits[i] = try sema.addConstant(field.ty, field.default_val);
}
- }
+ },
+ else => unreachable,
}
if (root_msg) |msg| {
- if (struct_ty.castTag(.@"struct")) |struct_obj| {
- const fqn = try struct_obj.data.getFullyQualifiedName(sema.mod);
- defer gpa.free(fqn);
- try sema.mod.errNoteNonLazy(
- struct_obj.data.srcLoc(sema.mod),
+ if (mod.typeToStruct(struct_ty)) |struct_obj| {
+ const fqn = try struct_obj.getFullyQualifiedName(mod);
+ try mod.errNoteNonLazy(
+ struct_obj.srcLoc(mod),
msg,
- "struct '{s}' declared here",
- .{fqn},
+ "struct '{}' declared here",
+ .{fqn.fmt(ip)},
);
}
root_msg = null;
return sema.failWithOwnedErrorMsg(msg);
}
- const is_comptime = for (field_inits) |field_init| {
+ // Find which field forces the expression to be runtime, if any.
+ const opt_runtime_index = for (field_inits, 0..) |field_init, i| {
if (!(try sema.isComptimeKnown(field_init))) {
- break false;
+ break i;
}
- } else true;
+ } else null;
- if (is_comptime) {
- const values = try sema.arena.alloc(Value, field_inits.len);
- for (field_inits, 0..) |field_init, i| {
- values[i] = (sema.resolveMaybeUndefVal(field_init) catch unreachable).?;
- }
- const struct_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstantMaybeRef(block, struct_ty, struct_val, is_ref);
- }
+ const runtime_index = opt_runtime_index orelse {
+ const elems = try sema.arena.alloc(InternPool.Index, field_inits.len);
+ for (elems, field_inits, 0..) |*elem, field_init, field_i| {
+ elem.* = try (sema.resolveMaybeUndefVal(field_init) catch unreachable).?
+ .intern(struct_ty.structFieldType(field_i, mod), mod);
+ }
+ const struct_val = try mod.intern(.{ .aggregate = .{
+ .ty = struct_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } });
+ return sema.addConstantMaybeRef(block, struct_ty, struct_val.toValue(), is_ref);
+ };
if (is_ref) {
try sema.resolveStructLayout(struct_ty);
const target = sema.mod.getTarget();
- const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const alloc_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = struct_ty,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
});
@@ -17883,10 +18929,18 @@ fn finishStructInit(
try sema.storePtr(block, dest_src, field_ptr, field_init);
}
- return alloc;
+ return sema.makePtrConst(block, alloc);
}
- try sema.requireRuntimeBlock(block, dest_src, null);
+ sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
+ error.NeededSourceLocation => {
+ const decl = mod.declPtr(block.src_decl);
+ const field_src = mod.initSrc(dest_src.node_offset.x, decl, runtime_index);
+ try sema.requireRuntimeBlock(block, dest_src, field_src);
+ unreachable;
+ },
+ else => |e| return e,
+ };
try sema.queueFullTypeResolution(struct_ty);
return block.addAggregateInit(struct_ty, field_inits);
}
@@ -17897,78 +18951,85 @@ fn zirStructInitAnon(
inst: Zir.Inst.Index,
is_ref: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.StructInitAnon, inst_data.payload_index);
- const types = try sema.arena.alloc(Type, extra.data.fields_len);
- const values = try sema.arena.alloc(Value, types.len);
- var fields = std.StringArrayHashMapUnmanaged(u32){};
- defer fields.deinit(sema.gpa);
- try fields.ensureUnusedCapacity(sema.gpa, types.len);
+ const types = try sema.arena.alloc(InternPool.Index, extra.data.fields_len);
+ const values = try sema.arena.alloc(InternPool.Index, types.len);
+ var fields = std.AutoArrayHashMap(InternPool.NullTerminatedString, u32).init(sema.arena);
+ try fields.ensureUnusedCapacity(types.len);
+ // Find which field forces the expression to be runtime, if any.
const opt_runtime_index = rs: {
var runtime_index: ?usize = null;
var extra_index = extra.end;
- for (types, 0..) |*field_ty, i| {
+ for (types, 0..) |*field_ty, i_usize| {
+ const i = @intCast(u32, i_usize);
const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
extra_index = item.end;
const name = sema.code.nullTerminatedString(item.data.field_name);
- const gop = fields.getOrPutAssumeCapacity(name);
+ const name_ip = try mod.intern_pool.getOrPutString(gpa, name);
+ const gop = fields.getOrPutAssumeCapacity(name_ip);
if (gop.found_existing) {
const msg = msg: {
- const decl = sema.mod.declPtr(block.src_decl);
- const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
+ const decl = mod.declPtr(block.src_decl);
+ const field_src = mod.initSrc(src.node_offset.x, decl, i);
const msg = try sema.errMsg(block, field_src, "duplicate field", .{});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
- const prev_source = Module.initSrc(src.node_offset.x, sema.gpa, decl, gop.value_ptr.*);
+ const prev_source = mod.initSrc(src.node_offset.x, decl, gop.value_ptr.*);
try sema.errNote(block, prev_source, msg, "other field here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- gop.value_ptr.* = @intCast(u32, i);
+ gop.value_ptr.* = i;
const init = try sema.resolveInst(item.data.init);
- field_ty.* = sema.typeOf(init);
- if (types[i].zigTypeTag() == .Opaque) {
+ field_ty.* = sema.typeOf(init).toIntern();
+ if (field_ty.toType().zigTypeTag(mod) == .Opaque) {
const msg = msg: {
- const decl = sema.mod.declPtr(block.src_decl);
- const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
+ const decl = mod.declPtr(block.src_decl);
+ const field_src = mod.initSrc(src.node_offset.x, decl, i);
const msg = try sema.errMsg(block, field_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, types[i]);
+ try sema.addDeclaredHereNote(msg, field_ty.toType());
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
if (try sema.resolveMaybeUndefVal(init)) |init_val| {
- values[i] = init_val;
+ values[i] = try init_val.intern(field_ty.toType(), mod);
} else {
- values[i] = Value.initTag(.unreachable_value);
+ values[i] = .none;
runtime_index = i;
}
}
break :rs runtime_index;
};
- const tuple_ty = try Type.Tag.anon_struct.create(sema.arena, .{
- .names = try sema.arena.dupe([]const u8, fields.keys()),
+ const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
+ .names = fields.keys(),
.types = types,
.values = values,
- });
+ } });
const runtime_index = opt_runtime_index orelse {
- const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref);
+ const tuple_val = try mod.intern(.{ .aggregate = .{
+ .ty = tuple_ty,
+ .storage = .{ .elems = values },
+ } });
+ return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
};
- sema.requireRuntimeBlock(block, src, .unneeded) catch |err| switch (err) {
+ sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
- const field_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index);
+ const decl = mod.declPtr(block.src_decl);
+ const field_src = mod.initSrc(src.node_offset.x, decl, runtime_index);
try sema.requireRuntimeBlock(block, src, field_src);
unreachable;
},
@@ -17976,9 +19037,9 @@ fn zirStructInitAnon(
};
if (is_ref) {
- const target = sema.mod.getTarget();
- const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = tuple_ty,
+ const target = mod.getTarget();
+ const alloc_ty = try Type.ptr(sema.arena, mod, .{
+ .pointee_type = tuple_ty.toType(),
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
});
const alloc = try block.addTy(.alloc, alloc_ty);
@@ -17988,19 +19049,19 @@ fn zirStructInitAnon(
const item = sema.code.extraData(Zir.Inst.StructInitAnon.Item, extra_index);
extra_index = item.end;
- const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const field_ptr_ty = try Type.ptr(sema.arena, mod, .{
.mutable = true,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
- .pointee_type = field_ty,
+ .pointee_type = field_ty.toType(),
});
- if (values[i].tag() == .unreachable_value) {
+ if (values[i] == .none) {
const init = try sema.resolveInst(item.data.init);
const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
_ = try block.addBinOp(.store, field_ptr, init);
}
}
- return alloc;
+ return sema.makePtrConst(block, alloc);
}
const element_refs = try sema.arena.alloc(Air.Inst.Ref, types.len);
@@ -18011,7 +19072,7 @@ fn zirStructInitAnon(
element_refs[i] = try sema.resolveInst(item.data.init);
}
- return block.addAggregateInit(tuple_ty, element_refs);
+ return block.addAggregateInit(tuple_ty.toType(), element_refs);
}
fn zirArrayInit(
@@ -18020,6 +19081,7 @@ fn zirArrayInit(
inst: Zir.Inst.Index,
is_ref: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const gpa = sema.gpa;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
@@ -18029,20 +19091,20 @@ fn zirArrayInit(
assert(args.len >= 2); // array_ty + at least one element
const array_ty = try sema.resolveType(block, src, args[0]);
- const sentinel_val = array_ty.sentinel();
+ const sentinel_val = array_ty.sentinel(mod);
const resolved_args = try gpa.alloc(Air.Inst.Ref, args.len - 1 + @boolToInt(sentinel_val != null));
defer gpa.free(resolved_args);
for (args[1..], 0..) |arg, i| {
const resolved_arg = try sema.resolveInst(arg);
- const elem_ty = if (array_ty.zigTypeTag() == .Struct)
- array_ty.structFieldType(i)
+ const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct)
+ array_ty.structFieldType(i, mod)
else
- array_ty.elemType2();
+ array_ty.elemType2(mod);
resolved_args[i] = sema.coerce(block, elem_ty, resolved_arg, .unneeded) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
- const elem_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, i);
+ const decl = mod.declPtr(block.src_decl);
+ const elem_src = mod.initSrc(src.node_offset.x, decl, i);
_ = try sema.coerce(block, elem_ty, resolved_arg, elem_src);
unreachable;
},
@@ -18051,7 +19113,7 @@ fn zirArrayInit(
}
if (sentinel_val) |some| {
- resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(), some);
+ resolved_args[resolved_args.len - 1] = try sema.addConstant(array_ty.elemType2(mod), some);
}
const opt_runtime_index: ?u32 = for (resolved_args, 0..) |arg, i| {
@@ -18060,21 +19122,25 @@ fn zirArrayInit(
} else null;
const runtime_index = opt_runtime_index orelse {
- const elem_vals = try sema.arena.alloc(Value, resolved_args.len);
-
- for (resolved_args, 0..) |arg, i| {
+ const elem_vals = try sema.arena.alloc(InternPool.Index, resolved_args.len);
+ for (elem_vals, resolved_args, 0..) |*val, arg, i| {
+ const elem_ty = if (array_ty.zigTypeTag(mod) == .Struct)
+ array_ty.structFieldType(i, mod)
+ else
+ array_ty.elemType2(mod);
// We checked that all args are comptime above.
- elem_vals[i] = (sema.resolveMaybeUndefVal(arg) catch unreachable).?;
+ val.* = try ((sema.resolveMaybeUndefVal(arg) catch unreachable).?).intern(elem_ty, mod);
}
-
- const array_val = try Value.Tag.aggregate.create(sema.arena, elem_vals);
- return sema.addConstantMaybeRef(block, array_ty, array_val, is_ref);
+ return sema.addConstantMaybeRef(block, array_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = array_ty.toIntern(),
+ .storage = .{ .elems = elem_vals },
+ } })).toValue(), is_ref);
};
- sema.requireRuntimeBlock(block, src, .unneeded) catch |err| switch (err) {
+ sema.requireRuntimeBlock(block, .unneeded, null) catch |err| switch (err) {
error.NeededSourceLocation => {
- const decl = sema.mod.declPtr(block.src_decl);
- const elem_src = Module.initSrc(src.node_offset.x, sema.gpa, decl, runtime_index);
+ const decl = mod.declPtr(block.src_decl);
+ const elem_src = mod.initSrc(src.node_offset.x, decl, runtime_index);
try sema.requireRuntimeBlock(block, src, elem_src);
unreachable;
},
@@ -18083,19 +19149,19 @@ fn zirArrayInit(
try sema.queueFullTypeResolution(array_ty);
if (is_ref) {
- const target = sema.mod.getTarget();
- const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const target = mod.getTarget();
+ const alloc_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = array_ty,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
});
const alloc = try block.addTy(.alloc, alloc_ty);
- if (array_ty.isTuple()) {
+ if (array_ty.isTuple(mod)) {
for (resolved_args, 0..) |arg, i| {
- const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{
.mutable = true,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
- .pointee_type = array_ty.structFieldType(i),
+ .pointee_type = array_ty.structFieldType(i, mod),
});
const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
@@ -18103,13 +19169,13 @@ fn zirArrayInit(
const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
_ = try block.addBinOp(.store, elem_ptr, arg);
}
- return alloc;
+ return sema.makePtrConst(block, alloc);
}
- const elem_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const elem_ptr_ty = try Type.ptr(sema.arena, mod, .{
.mutable = true,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
- .pointee_type = array_ty.elemType2(),
+ .pointee_type = array_ty.elemType2(mod),
});
const elem_ptr_ty_ref = try sema.addType(elem_ptr_ty);
@@ -18118,7 +19184,7 @@ fn zirArrayInit(
const elem_ptr = try block.addPtrElemPtrTypeRef(alloc, index, elem_ptr_ty_ref);
_ = try block.addBinOp(.store, elem_ptr, arg);
}
- return alloc;
+ return sema.makePtrConst(block, alloc);
}
return block.addAggregateInit(array_ty, resolved_args);
@@ -18134,44 +19200,49 @@ fn zirArrayInitAnon(
const src = inst_data.src();
const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index);
const operands = sema.code.refSlice(extra.end, extra.data.operands_len);
+ const mod = sema.mod;
- const types = try sema.arena.alloc(Type, operands.len);
- const values = try sema.arena.alloc(Value, operands.len);
+ const types = try sema.arena.alloc(InternPool.Index, operands.len);
+ const values = try sema.arena.alloc(InternPool.Index, operands.len);
const opt_runtime_src = rs: {
var runtime_src: ?LazySrcLoc = null;
for (operands, 0..) |operand, i| {
const operand_src = src; // TODO better source location
const elem = try sema.resolveInst(operand);
- types[i] = sema.typeOf(elem);
- if (types[i].zigTypeTag() == .Opaque) {
+ types[i] = sema.typeOf(elem).toIntern();
+ if (types[i].toType().zigTypeTag(mod) == .Opaque) {
const msg = msg: {
const msg = try sema.errMsg(block, operand_src, "opaque types have unknown size and therefore cannot be directly embedded in structs", .{});
errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, types[i]);
+ try sema.addDeclaredHereNote(msg, types[i].toType());
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
if (try sema.resolveMaybeUndefVal(elem)) |val| {
- values[i] = val;
+ values[i] = val.toIntern();
} else {
- values[i] = Value.initTag(.unreachable_value);
+ values[i] = .none;
runtime_src = operand_src;
}
}
break :rs runtime_src;
};
- const tuple_ty = try Type.Tag.tuple.create(sema.arena, .{
+ const tuple_ty = try mod.intern(.{ .anon_struct_type = .{
.types = types,
.values = values,
- });
+ .names = &.{},
+ } });
const runtime_src = opt_runtime_src orelse {
- const tuple_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstantMaybeRef(block, tuple_ty, tuple_val, is_ref);
+ const tuple_val = try mod.intern(.{ .aggregate = .{
+ .ty = tuple_ty,
+ .storage = .{ .elems = values },
+ } });
+ return sema.addConstantMaybeRef(block, tuple_ty.toType(), tuple_val.toValue(), is_ref);
};
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -18179,7 +19250,7 @@ fn zirArrayInitAnon(
if (is_ref) {
const target = sema.mod.getTarget();
const alloc_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = tuple_ty,
+ .pointee_type = tuple_ty.toType(),
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
});
const alloc = try block.addTy(.alloc, alloc_ty);
@@ -18188,15 +19259,15 @@ fn zirArrayInitAnon(
const field_ptr_ty = try Type.ptr(sema.arena, sema.mod, .{
.mutable = true,
.@"addrspace" = target_util.defaultAddressSpace(target, .local),
- .pointee_type = types[i],
+ .pointee_type = types[i].toType(),
});
- if (values[i].tag() == .unreachable_value) {
+ if (values[i] == .none) {
const field_ptr = try block.addStructFieldPtr(alloc, i, field_ptr_ty);
_ = try block.addBinOp(.store, field_ptr, try sema.resolveInst(operand));
}
}
- return alloc;
+ return sema.makePtrConst(block, alloc);
}
const element_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len);
@@ -18204,7 +19275,7 @@ fn zirArrayInitAnon(
element_refs[i] = try sema.resolveInst(operand);
}
- return block.addAggregateInit(tuple_ty, element_refs);
+ return block.addAggregateInit(tuple_ty.toType(), element_refs);
}
fn addConstantMaybeRef(
@@ -18219,8 +19290,8 @@ fn addConstantMaybeRef(
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
const decl = try anon_decl.finish(
- try ty.copy(anon_decl.arena()),
- try val.copy(anon_decl.arena()),
+ ty,
+ val,
0, // default alignment
);
return sema.analyzeDeclRef(decl);
@@ -18232,18 +19303,27 @@ fn zirFieldTypeRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileErro
const ty_src = inst_data.src();
const field_src = inst_data.src();
const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
- const field_name = try sema.resolveConstString(block, field_src, extra.field_name, "field name must be comptime-known");
+ const field_name = try sema.resolveConstStringIntern(block, field_src, extra.field_name, "field name must be comptime-known");
return sema.fieldType(block, aggregate_ty, field_name, field_src, ty_src);
}
fn zirFieldType(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)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.FieldType, inst_data.payload_index).data;
const ty_src = inst_data.src();
const field_name_src: LazySrcLoc = .{ .node_offset_field_name = inst_data.src_node };
- const aggregate_ty = try sema.resolveType(block, ty_src, extra.container_type);
- if (aggregate_ty.tag() == .var_args_param) return sema.addType(aggregate_ty);
- const field_name = sema.code.nullTerminatedString(extra.name_start);
+ const aggregate_ty = sema.resolveType(block, ty_src, extra.container_type) catch |err| switch (err) {
+ // Since this is a ZIR instruction that returns a type, encountering
+ // generic poison should not result in a failed compilation, but the
+ // generic poison type. This prevents unnecessary failures when
+ // constructing types at compile-time.
+ error.GenericPoison => return Air.Inst.Ref.generic_poison_type,
+ else => |e| return e,
+ };
+ const zir_field_name = sema.code.nullTerminatedString(extra.name_start);
+ const field_name = try ip.getOrPutString(sema.gpa, zir_field_name);
return sema.fieldType(block, aggregate_ty, field_name, field_name_src, ty_src);
}
@@ -18251,41 +19331,43 @@ fn fieldType(
sema: *Sema,
block: *Block,
aggregate_ty: Type,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_src: LazySrcLoc,
ty_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
var cur_ty = aggregate_ty;
while (true) {
const resolved_ty = try sema.resolveTypeFields(cur_ty);
cur_ty = resolved_ty;
- switch (cur_ty.zigTypeTag()) {
- .Struct => {
- if (cur_ty.isAnonStruct()) {
+ switch (cur_ty.zigTypeTag(mod)) {
+ .Struct => switch (mod.intern_pool.indexToKey(cur_ty.toIntern())) {
+ .anon_struct_type => |anon_struct| {
const field_index = try sema.anonStructFieldIndex(block, cur_ty, field_name, field_src);
- return sema.addType(cur_ty.tupleFields().types[field_index]);
- }
- const struct_obj = cur_ty.castTag(.@"struct").?.data;
- const field = struct_obj.fields.get(field_name) orelse
- return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
- return sema.addType(field.ty);
+ return sema.addType(anon_struct.types[field_index].toType());
+ },
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
+ const field = struct_obj.fields.get(field_name) orelse
+ return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
+ return sema.addType(field.ty);
+ },
+ else => unreachable,
},
.Union => {
- const union_obj = cur_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(cur_ty).?;
const field = union_obj.fields.get(field_name) orelse
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
return sema.addType(field.ty);
},
.Optional => {
- if (cur_ty.castTag(.optional)) |some| {
- // Struct/array init through optional requires the child type to not be a pointer.
- // If the child of .optional is a pointer it'll error on the next loop.
- cur_ty = some.data;
- continue;
- }
+ // Struct/array init through optional requires the child type to not be a pointer.
+ // If the child of .optional is a pointer it'll error on the next loop.
+ cur_ty = mod.intern_pool.indexToKey(cur_ty.toIntern()).opt_type.toType();
+ continue;
},
.ErrorUnion => {
- cur_ty = cur_ty.errorUnionPayload();
+ cur_ty = cur_ty.errorUnionPayload(mod);
continue;
},
else => {},
@@ -18301,18 +19383,23 @@ fn zirErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
}
fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
- const opt_ptr_stack_trace_ty = try Type.Tag.optional_single_mut_pointer.create(sema.arena, stack_trace_ty);
+ const ptr_stack_trace_ty = try mod.singleMutPtrType(stack_trace_ty);
+ const opt_ptr_stack_trace_ty = try Type.optional(sema.arena, ptr_stack_trace_ty, mod);
if (sema.owner_func != null and
sema.owner_func.?.calls_or_awaits_errorable_fn and
- sema.mod.comp.bin_file.options.error_return_tracing and
- sema.mod.backendSupportsFeature(.error_return_trace))
+ mod.comp.bin_file.options.error_return_tracing and
+ mod.backendSupportsFeature(.error_return_trace))
{
return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
}
- return sema.addConstant(opt_ptr_stack_trace_ty, Value.null);
+ return sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{
+ .ty = opt_ptr_stack_trace_ty.toIntern(),
+ .val = .none,
+ } })).toValue());
}
fn zirFrame(
@@ -18325,27 +19412,28 @@ fn zirFrame(
}
fn zirAlignOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, operand_src, inst_data.operand);
- if (ty.isNoReturn()) {
+ if (ty.isNoReturn(mod)) {
return sema.fail(block, operand_src, "no align available for type '{}'", .{ty.fmt(sema.mod)});
}
- const target = sema.mod.getTarget();
- const val = try ty.lazyAbiAlignment(target, sema.arena);
- if (val.tag() == .lazy_align) {
+ const val = try ty.lazyAbiAlignment(mod);
+ if (val.isLazyAlign(mod)) {
try sema.queueFullTypeResolution(ty);
}
return sema.addConstant(Type.comptime_int, val);
}
fn zirBoolToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand = try sema.resolveInst(inst_data.operand);
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) return sema.addConstUndef(Type.initTag(.u1));
- const bool_ints = [2]Air.Inst.Ref{ .zero, .one };
- return bool_ints[@boolToInt(val.toBool())];
+ if (val.isUndef(mod)) return sema.addConstUndef(Type.u1);
+ if (val.toBool()) return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 1));
+ return sema.addConstant(Type.u1, try mod.intValue(Type.u1, 0));
}
return block.addUnOp(.bool_to_int, operand);
}
@@ -18356,8 +19444,8 @@ fn zirErrorName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
if (try sema.resolveDefinedValue(block, operand_src, operand)) |val| {
- const bytes = val.castTag(.@"error").?.data.name;
- return sema.addStrLit(block, bytes);
+ const err_name = sema.mod.intern_pool.indexToKey(val.toIntern()).err.name;
+ return sema.addStrLit(block, sema.mod.intern_pool.stringToSlice(err_name));
}
// Similar to zirTagName, we have special AIR instruction for the error name in case an optimimzation pass
@@ -18375,16 +19463,17 @@ fn zirUnaryMath(
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const operand = try sema.resolveInst(inst_data.operand);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand_ty = sema.typeOf(operand);
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.ComptimeFloat, .Float => {},
.Vector => {
- const scalar_ty = operand_ty.scalarType();
- switch (scalar_ty.zigTypeTag()) {
+ const scalar_ty = operand_ty.scalarType(mod);
+ switch (scalar_ty.zigTypeTag(mod)) {
.ComptimeFloat, .Float => {},
else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{scalar_ty.fmt(sema.mod)}),
}
@@ -18392,25 +19481,27 @@ fn zirUnaryMath(
else => return sema.fail(block, operand_src, "expected vector of floats or float type, found '{}'", .{operand_ty.fmt(sema.mod)}),
}
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.Vector => {
- const scalar_ty = operand_ty.scalarType();
- const vec_len = operand_ty.vectorLen();
- const result_ty = try Type.vector(sema.arena, vec_len, scalar_ty);
+ const scalar_ty = operand_ty.scalarType(mod);
+ const vec_len = operand_ty.vectorLen(mod);
+ const result_ty = try mod.vectorType(.{
+ .len = vec_len,
+ .child = scalar_ty.toIntern(),
+ });
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef())
+ if (val.isUndef(mod))
return sema.addConstUndef(result_ty);
- var elem_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, vec_len);
+ const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
- const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
- elem.* = try eval(elem_val, scalar_ty, sema.arena, sema.mod);
+ const elem_val = try val.elemValue(sema.mod, i);
+ elem.* = try (try eval(elem_val, scalar_ty, sema.arena, sema.mod)).intern(scalar_ty, mod);
}
- return sema.addConstant(
- result_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = result_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, operand_src, null);
@@ -18418,7 +19509,7 @@ fn zirUnaryMath(
},
.ComptimeFloat, .Float => {
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
- if (operand_val.isUndef())
+ if (operand_val.isUndef(mod))
return sema.addConstUndef(operand_ty);
const result_val = try eval(operand_val, operand_ty, sema.arena, sema.mod);
return sema.addConstant(operand_ty, result_val);
@@ -18438,16 +19529,17 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const mod = sema.mod;
+ const ip = &mod.intern_pool;
try sema.resolveTypeLayout(operand_ty);
- const enum_ty = switch (operand_ty.zigTypeTag()) {
+ const enum_ty = switch (operand_ty.zigTypeTag(mod)) {
.EnumLiteral => {
const val = try sema.resolveConstValue(block, .unneeded, operand, "");
- const bytes = val.castTag(.enum_literal).?.data;
- return sema.addStrLit(block, bytes);
+ const tag_name = ip.indexToKey(val.toIntern()).enum_literal;
+ return sema.addStrLit(block, ip.stringToSlice(tag_name));
},
.Enum => operand_ty,
- .Union => operand_ty.unionTagType() orelse {
+ .Union => operand_ty.unionTagType(mod) orelse {
const msg = msg: {
const msg = try sema.errMsg(block, src, "union '{}' is untagged", .{
operand_ty.fmt(sema.mod),
@@ -18462,30 +19554,31 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
operand_ty.fmt(mod),
}),
};
- if (enum_ty.enumFieldCount() == 0) {
+ if (enum_ty.enumFieldCount(mod) == 0) {
// TODO I don't think this is the correct way to handle this but
// it prevents a crash.
return sema.fail(block, operand_src, "cannot get @tagName of empty enum '{}'", .{
enum_ty.fmt(mod),
});
}
- const enum_decl_index = enum_ty.getOwnerDecl();
+ const enum_decl_index = enum_ty.getOwnerDecl(mod);
const casted_operand = try sema.coerce(block, enum_ty, operand, operand_src);
if (try sema.resolveDefinedValue(block, operand_src, casted_operand)) |val| {
const field_index = enum_ty.enumTagFieldIndex(val, mod) orelse {
const enum_decl = mod.declPtr(enum_decl_index);
const msg = msg: {
- const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{s}'", .{
- val.fmtValue(enum_ty, sema.mod), enum_decl.name,
+ const msg = try sema.errMsg(block, src, "no field with value '{}' in enum '{}'", .{
+ val.fmtValue(enum_ty, sema.mod), enum_decl.name.fmt(ip),
});
errdefer msg.destroy(sema.gpa);
- try mod.errNoteNonLazy(enum_decl.srcLoc(), msg, "declared here", .{});
+ try mod.errNoteNonLazy(enum_decl.srcLoc(mod), msg, "declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
};
- const field_name = enum_ty.enumFieldName(field_index);
- return sema.addStrLit(block, field_name);
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ const field_name = enum_ty.enumFieldName(field_index, mod);
+ return sema.addStrLit(block, ip.stringToSlice(field_name));
}
try sema.requireRuntimeBlock(block, src, operand_src);
if (block.wantSafety() and sema.mod.backendSupportsFeature(.is_named_enum_value)) {
@@ -18498,8 +19591,15 @@ fn zirTagName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return block.addUnOp(.tag_name, casted_operand);
}
-fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+fn zirReify(
+ sema: *Sema,
+ 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 name_strategy = @intToEnum(Zir.Inst.NameStrategy, extended.small);
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
@@ -18508,10 +19608,10 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
const val = try sema.resolveConstValue(block, operand_src, type_info, "operand to @Type must be comptime-known");
- const union_val = val.cast(Value.Payload.Union).?.data;
+ const union_val = ip.indexToKey(val.toIntern()).un;
const target = mod.getTarget();
- const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag, mod).?;
- if (union_val.val.anyUndef(mod)) return sema.failWithUseOfUndef(block, src);
+ if (try union_val.val.toValue().anyUndef(mod)) return sema.failWithUseOfUndef(block, src);
+ const tag_index = type_info_ty.unionTagFieldIndex(union_val.tag.toValue(), mod).?;
switch (@intToEnum(std.builtin.TypeId, tag_index)) {
.Type => return Air.Inst.Ref.type_type,
.Void => return Air.Inst.Ref.void_type,
@@ -18524,41 +19624,48 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
.AnyFrame => return sema.failWithUseOfAsync(block, src),
.EnumLiteral => return Air.Inst.Ref.enum_literal_type,
.Int => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- const signedness_val = struct_val[0];
- const bits_val = struct_val[1];
-
- const signedness = signedness_val.toEnum(std.builtin.Signedness);
- const bits = @intCast(u16, bits_val.toUnsignedInt(target));
- const ty = switch (signedness) {
- .signed => try Type.Tag.int_signed.create(sema.arena, bits),
- .unsigned => try Type.Tag.int_unsigned.create(sema.arena, bits),
- };
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const signedness_val = try union_val.val.toValue().fieldValue(
+ mod,
+ fields.getIndex(try ip.getOrPutString(gpa, "signedness")).?,
+ );
+ const bits_val = try union_val.val.toValue().fieldValue(
+ mod,
+ fields.getIndex(try ip.getOrPutString(gpa, "bits")).?,
+ );
+
+ const signedness = mod.toEnum(std.builtin.Signedness, signedness_val);
+ const bits = @intCast(u16, bits_val.toUnsignedInt(mod));
+ const ty = try mod.intType(signedness, bits);
return sema.addType(ty);
},
.Vector => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- const len_val = struct_val[0];
- const child_val = struct_val[1];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "len"),
+ ).?);
+ const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "child"),
+ ).?);
- const len = len_val.toUnsignedInt(target);
- var buffer: Value.ToTypeBuffer = undefined;
- const child_ty = child_val.toType(&buffer);
+ const len = @intCast(u32, len_val.toUnsignedInt(mod));
+ const child_ty = child_val.toType();
try sema.checkVectorElemType(block, src, child_ty);
- const ty = try Type.vector(sema.arena, len, try child_ty.copy(sema.arena));
+ const ty = try mod.vectorType(.{
+ .len = len,
+ .child = child_ty.toIntern(),
+ });
return sema.addType(ty);
},
.Float => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // bits: comptime_int,
- const bits_val = struct_val[0];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const bits_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "bits"),
+ ).?);
- const bits = @intCast(u16, bits_val.toUnsignedInt(target));
+ const bits = @intCast(u16, bits_val.toUnsignedInt(mod));
const ty = switch (bits) {
16 => Type.f16,
32 => Type.f32,
@@ -18570,25 +19677,42 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
return sema.addType(ty);
},
.Pointer => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- const size_val = struct_val[0];
- const is_const_val = struct_val[1];
- const is_volatile_val = struct_val[2];
- const alignment_val = struct_val[3];
- const address_space_val = struct_val[4];
- const child_val = struct_val[5];
- const is_allowzero_val = struct_val[6];
- const sentinel_val = struct_val[7];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const size_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "size"),
+ ).?);
+ const is_const_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "is_const"),
+ ).?);
+ const is_volatile_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "is_volatile"),
+ ).?);
+ const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "alignment"),
+ ).?);
+ const address_space_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "address_space"),
+ ).?);
+ const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "child"),
+ ).?);
+ const is_allowzero_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "is_allowzero"),
+ ).?);
+ const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "sentinel"),
+ ).?);
if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
return sema.fail(block, src, "alignment must fit in 'u32'", .{});
}
- const abi_align = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?);
- var buffer: Value.ToTypeBuffer = undefined;
- const unresolved_elem_ty = child_val.toType(&buffer);
- const elem_ty = if (abi_align == 0)
+ const abi_align = InternPool.Alignment.fromByteUnits(
+ (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?,
+ );
+
+ const unresolved_elem_ty = child_val.toType();
+ const elem_ty = if (abi_align == .none)
unresolved_elem_ty
else t: {
const elem_ty = try sema.resolveTypeFields(unresolved_elem_ty);
@@ -18596,301 +19720,282 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
break :t elem_ty;
};
- const ptr_size = size_val.toEnum(std.builtin.Type.Pointer.Size);
+ const ptr_size = mod.toEnum(std.builtin.Type.Pointer.Size, size_val);
- var actual_sentinel: ?Value = null;
- if (!sentinel_val.isNull()) {
- if (ptr_size == .One or ptr_size == .C) {
- return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
+ const actual_sentinel: InternPool.Index = s: {
+ if (!sentinel_val.isNull(mod)) {
+ if (ptr_size == .One or ptr_size == .C) {
+ return sema.fail(block, src, "sentinels are only allowed on slices and unknown-length pointers", .{});
+ }
+ const sentinel_ptr_val = sentinel_val.optionalValue(mod).?;
+ const ptr_ty = try Type.ptr(sema.arena, mod, .{
+ .@"addrspace" = .generic,
+ .pointee_type = elem_ty,
+ });
+ const sent_val = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
+ break :s sent_val.toIntern();
}
- const sentinel_ptr_val = sentinel_val.castTag(.opt_payload).?.data;
- const ptr_ty = try Type.ptr(sema.arena, mod, .{
- .@"addrspace" = .generic,
- .pointee_type = try elem_ty.copy(sema.arena),
- });
- actual_sentinel = (try sema.pointerDeref(block, src, sentinel_ptr_val, ptr_ty)).?;
- }
+ break :s .none;
+ };
- if (elem_ty.zigTypeTag() == .NoReturn) {
+ if (elem_ty.zigTypeTag(mod) == .NoReturn) {
return sema.fail(block, src, "pointer to noreturn not allowed", .{});
- } else if (elem_ty.zigTypeTag() == .Fn) {
+ } else if (elem_ty.zigTypeTag(mod) == .Fn) {
if (ptr_size != .One) {
return sema.fail(block, src, "function pointers must be single pointers", .{});
}
- const fn_align = elem_ty.fnInfo().alignment;
- if (abi_align != 0 and fn_align != 0 and
+ const fn_align = mod.typeToFunc(elem_ty).?.alignment;
+ if (abi_align != .none and fn_align != .none and
abi_align != fn_align)
{
return sema.fail(block, src, "function pointer alignment disagrees with function alignment", .{});
}
- } else if (ptr_size == .Many and elem_ty.zigTypeTag() == .Opaque) {
+ } else if (ptr_size == .Many and elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, src, "unknown-length pointer to opaque not allowed", .{});
} else if (ptr_size == .C) {
if (!try sema.validateExternType(elem_ty, .other)) {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(sema.mod)});
- errdefer msg.destroy(sema.gpa);
+ const msg = try sema.errMsg(block, src, "C pointers cannot point to non-C-ABI-compatible type '{}'", .{elem_ty.fmt(mod)});
+ errdefer msg.destroy(gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), elem_ty, .other);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), elem_ty, .other);
try sema.addDeclaredHereNote(msg, elem_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (elem_ty.zigTypeTag() == .Opaque) {
+ if (elem_ty.zigTypeTag(mod) == .Opaque) {
return sema.fail(block, src, "C pointers cannot point to opaque types", .{});
}
}
- const ty = try Type.ptr(sema.arena, mod, .{
- .size = ptr_size,
- .mutable = !is_const_val.toBool(),
- .@"volatile" = is_volatile_val.toBool(),
- .@"align" = abi_align,
- .@"addrspace" = address_space_val.toEnum(std.builtin.AddressSpace),
- .pointee_type = try elem_ty.copy(sema.arena),
- .@"allowzero" = is_allowzero_val.toBool(),
+ const ty = try mod.ptrType(.{
+ .child = elem_ty.toIntern(),
.sentinel = actual_sentinel,
+ .flags = .{
+ .size = ptr_size,
+ .is_const = is_const_val.toBool(),
+ .is_volatile = is_volatile_val.toBool(),
+ .alignment = abi_align,
+ .address_space = mod.toEnum(std.builtin.AddressSpace, address_space_val),
+ .is_allowzero = is_allowzero_val.toBool(),
+ },
});
return sema.addType(ty);
},
.Array => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // len: comptime_int,
- const len_val = struct_val[0];
- // child: type,
- const child_val = struct_val[1];
- // sentinel: ?*const anyopaque,
- const sentinel_val = struct_val[2];
-
- const len = len_val.toUnsignedInt(target);
- var buffer: Value.ToTypeBuffer = undefined;
- const child_ty = try child_val.toType(&buffer).copy(sema.arena);
- const sentinel = if (sentinel_val.castTag(.opt_payload)) |p| blk: {
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const len_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "len"),
+ ).?);
+ const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "child"),
+ ).?);
+ const sentinel_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "sentinel"),
+ ).?);
+
+ const len = len_val.toUnsignedInt(mod);
+ const child_ty = child_val.toType();
+ const sentinel = if (sentinel_val.optionalValue(mod)) |p| blk: {
const ptr_ty = try Type.ptr(sema.arena, mod, .{
.@"addrspace" = .generic,
.pointee_type = child_ty,
});
- break :blk (try sema.pointerDeref(block, src, p.data, ptr_ty)).?;
+ break :blk (try sema.pointerDeref(block, src, p, ptr_ty)).?;
} else null;
- const ty = try Type.array(sema.arena, len, sentinel, child_ty, sema.mod);
+ const ty = try Type.array(sema.arena, len, sentinel, child_ty, mod);
return sema.addType(ty);
},
.Optional => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // child: type,
- const child_val = struct_val[0];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const child_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "child"),
+ ).?);
- var buffer: Value.ToTypeBuffer = undefined;
- const child_ty = try child_val.toType(&buffer).copy(sema.arena);
+ const child_ty = child_val.toType();
- const ty = try Type.optional(sema.arena, child_ty);
+ const ty = try Type.optional(sema.arena, child_ty, mod);
return sema.addType(ty);
},
.ErrorUnion => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // error_set: type,
- const error_set_val = struct_val[0];
- // payload: type,
- const payload_val = struct_val[1];
-
- var buffer: Value.ToTypeBuffer = undefined;
- const error_set_ty = try error_set_val.toType(&buffer).copy(sema.arena);
- const payload_ty = try payload_val.toType(&buffer).copy(sema.arena);
-
- if (error_set_ty.zigTypeTag() != .ErrorSet) {
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const error_set_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "error_set"),
+ ).?);
+ const payload_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "payload"),
+ ).?);
+
+ const error_set_ty = error_set_val.toType();
+ const payload_ty = payload_val.toType();
+
+ if (error_set_ty.zigTypeTag(mod) != .ErrorSet) {
return sema.fail(block, src, "Type.ErrorUnion.error_set must be an error set type", .{});
}
- const ty = try Type.Tag.error_union.create(sema.arena, .{
- .error_set = error_set_ty,
- .payload = payload_ty,
- });
+ const ty = try mod.errorUnionType(error_set_ty, payload_ty);
return sema.addType(ty);
},
.ErrorSet => {
- const payload_val = union_val.val.optionalValue() orelse
- return sema.addType(Type.initTag(.anyerror));
- const slice_val = payload_val.castTag(.slice).?.data;
+ const payload_val = union_val.val.toValue().optionalValue(mod) orelse
+ return sema.addType(Type.anyerror);
- const len = try sema.usizeCast(block, src, slice_val.len.toUnsignedInt(mod.getTarget()));
- var names: Module.ErrorSet.NameMap = .{};
+ const len = try sema.usizeCast(block, src, payload_val.sliceLen(mod));
+ var names: Module.Fn.InferredErrorSet.NameMap = .{};
try names.ensureUnusedCapacity(sema.arena, len);
- var i: usize = 0;
- while (i < len) : (i += 1) {
- var buf: Value.ElemValueBuffer = undefined;
- const elem_val = slice_val.ptr.elemValueBuffer(mod, i, &buf);
- const struct_val = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // error_set: type,
- const name_val = struct_val[0];
- const name_str = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, sema.mod);
-
- const kv = try mod.getErrorValue(name_str);
- const gop = names.getOrPutAssumeCapacity(kv.key);
+ for (0..len) |i| {
+ const elem_val = try payload_val.elemValue(mod, i);
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "name"),
+ ).?);
+
+ const name = try name_val.toIpString(Type.slice_const_u8, mod);
+ _ = try mod.getErrorValue(name);
+ const gop = names.getOrPutAssumeCapacity(name);
if (gop.found_existing) {
- return sema.fail(block, src, "duplicate error '{s}'", .{name_str});
+ return sema.fail(block, src, "duplicate error '{}'", .{
+ name.fmt(ip),
+ });
}
}
- // names must be sorted
- Module.ErrorSet.sortNames(&names);
- const ty = try Type.Tag.error_set_merged.create(sema.arena, names);
+ const ty = try mod.errorSetFromUnsortedNames(names.keys());
return sema.addType(ty);
},
.Struct => {
- // TODO use reflection instead of magic numbers here
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // layout: containerlayout,
- const layout_val = struct_val[0];
- // backing_int: ?type,
- const backing_int_val = struct_val[1];
- // fields: []const enumfield,
- const fields_val = struct_val[2];
- // decls: []const declaration,
- const decls_val = struct_val[3];
- // is_tuple: bool,
- const is_tuple_val = struct_val[4];
- assert(struct_val.len == 5);
-
- const layout = layout_val.toEnum(std.builtin.Type.ContainerLayout);
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "layout"),
+ ).?);
+ const backing_integer_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "backing_integer"),
+ ).?);
+ const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "fields"),
+ ).?);
+ const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "decls"),
+ ).?);
+ const is_tuple_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "is_tuple"),
+ ).?);
+
+ const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
// Decls
if (decls_val.sliceLen(mod) > 0) {
return sema.fail(block, src, "reified structs must have no decls", .{});
}
- if (layout != .Packed and !backing_int_val.isNull()) {
+ if (layout != .Packed and !backing_integer_val.isNull(mod)) {
return sema.fail(block, src, "non-packed struct does not support backing integer type", .{});
}
- return try sema.reifyStruct(block, inst, src, layout, backing_int_val, fields_val, name_strategy, is_tuple_val.toBool());
+ return try sema.reifyStruct(block, inst, src, layout, backing_integer_val, fields_val, name_strategy, is_tuple_val.toBool());
},
.Enum => {
- const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // tag_type: type,
- const tag_type_val = struct_val[0];
- // fields: []const EnumField,
- const fields_val = struct_val[1];
- // decls: []const Declaration,
- const decls_val = struct_val[2];
- // is_exhaustive: bool,
- const is_exhaustive_val = struct_val[3];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "tag_type"),
+ ).?);
+ const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "fields"),
+ ).?);
+ const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "decls"),
+ ).?);
+ const is_exhaustive_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ 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 gpa = sema.gpa;
- var new_decl_arena = std.heap.ArenaAllocator.init(gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ 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.
- // Define our empty enum decl
- const enum_obj = try new_decl_arena_allocator.create(Module.EnumFull);
- const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumFull);
- enum_ty_payload.* = .{
- .base = .{
- .tag = if (!is_exhaustive_val.toBool())
- .enum_nonexhaustive
- else
- .enum_full,
- },
- .data = enum_obj,
- };
- const enum_ty = Type.initPayload(&enum_ty_payload.base);
- const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = enum_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, name_strategy, "enum", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
- errdefer mod.abortAnonDecl(new_decl_index);
-
- enum_obj.* = .{
- .owner_decl = new_decl_index,
- .tag_ty = Type.null,
- .tag_ty_inferred = false,
- .fields = .{},
- .values = .{},
- .namespace = .{
- .parent = block.namespace,
- .ty = enum_ty,
- .file_scope = block.getFileScope(),
- },
- };
-
- // Enum tag type
- var buffer: Value.ToTypeBuffer = undefined;
- const int_tag_ty = try tag_type_val.toType(&buffer).copy(new_decl_arena_allocator);
-
- if (int_tag_ty.zigTypeTag() != .Int) {
- return sema.fail(block, src, "Type.Enum.tag_type must be an integer type", .{});
+ errdefer {
+ new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
+ mod.abortAnonDecl(new_decl_index);
}
- enum_obj.tag_ty = int_tag_ty;
- // Fields
- const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
- try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
- try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
- .ty = enum_obj.tag_ty,
- .mod = mod,
+ // Define our empty enum decl
+ const fields_len = @intCast(u32, 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(),
});
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer ip.remove(incomplete_enum.index);
- var field_i: usize = 0;
- while (field_i < fields_len) : (field_i += 1) {
- const elem_val = try fields_val.elemValue(sema.mod, sema.arena, field_i);
- const field_struct_val: []const Value = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // name: []const u8
- const name_val = field_struct_val[0];
- // value: comptime_int
- const value_val = field_struct_val[1];
-
- const field_name = try name_val.toAllocatedBytes(
- Type.initTag(.const_slice_u8),
- new_decl_arena_allocator,
- sema.mod,
- );
+ new_decl.ty = Type.type;
+ new_decl.val = incomplete_enum.index.toValue();
+
+ for (0..fields_len) |field_i| {
+ const elem_val = try fields_val.elemValue(mod, field_i);
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "name"),
+ ).?);
+ const value_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "value"),
+ ).?);
- if (!try sema.intFitsInType(value_val, enum_obj.tag_ty, null)) {
+ 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 '{s}' with enumeration value '{}' is too large for backing int type '{}'", .{
- field_name,
+ 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),
- enum_obj.tag_ty.fmt(mod),
+ int_tag_ty.fmt(mod),
});
}
- const gop_field = enum_obj.fields.getOrPutAssumeCapacity(field_name);
- if (gop_field.found_existing) {
+ if (try incomplete_enum.addFieldName(ip, gpa, field_name)) |other_index| {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "duplicate enum field '{s}'", .{field_name});
+ 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(msg);
}
- const copied_tag_val = try value_val.copy(new_decl_arena_allocator);
- const gop_val = enum_obj.values.getOrPutAssumeCapacityContext(copied_tag_val, .{
- .ty = enum_obj.tag_ty,
- .mod = mod,
- });
- if (gop_val.found_existing) {
+ if (try incomplete_enum.addFieldValue(ip, gpa, (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;
};
@@ -18898,182 +20003,209 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
}
}
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
},
.Opaque => {
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // decls: []const Declaration,
- const decls_val = struct_val[0];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "decls"),
+ ).?);
// Decls
if (decls_val.sliceLen(mod) > 0) {
return sema.fail(block, src, "reified opaque must have no decls", .{});
}
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ // 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 opaque_obj = try new_decl_arena_allocator.create(Module.Opaque);
- const opaque_ty_payload = try new_decl_arena_allocator.create(Type.Payload.Opaque);
- opaque_ty_payload.* = .{
- .base = .{ .tag = .@"opaque" },
- .data = opaque_obj,
- };
- const opaque_ty = Type.initPayload(&opaque_ty_payload.base);
- const opaque_val = try Value.Tag.ty.create(new_decl_arena_allocator, opaque_ty);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = opaque_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, name_strategy, "opaque", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
- errdefer mod.abortAnonDecl(new_decl_index);
+ errdefer {
+ new_decl.has_tv = false; // namespace and val were destroyed by later errdefers
+ mod.abortAnonDecl(new_decl_index);
+ }
- opaque_obj.* = .{
- .owner_decl = new_decl_index,
- .namespace = .{
- .parent = block.namespace,
- .ty = opaque_ty,
- .file_scope = block.getFileScope(),
- },
- };
+ const new_namespace_index = try mod.createNamespace(.{
+ .parent = block.namespace.toOptional(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
+ });
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer mod.destroyNamespace(new_namespace_index);
+
+ const opaque_ty = try mod.intern(.{ .opaque_type = .{
+ .decl = new_decl_index,
+ .namespace = new_namespace_index,
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer ip.remove(opaque_ty);
+
+ new_decl.ty = Type.type;
+ new_decl.val = opaque_ty.toValue();
+ new_namespace.ty = opaque_ty.toType();
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
},
.Union => {
- // TODO use reflection instead of magic numbers here
- const struct_val = union_val.val.castTag(.aggregate).?.data;
- // layout: containerlayout,
- const layout_val = struct_val[0];
- // tag_type: ?type,
- const tag_type_val = struct_val[1];
- // fields: []const enumfield,
- const fields_val = struct_val[2];
- // decls: []const declaration,
- const decls_val = struct_val[3];
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const layout_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "layout"),
+ ).?);
+ const tag_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "tag_type"),
+ ).?);
+ const fields_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "fields"),
+ ).?);
+ const decls_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ 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 = layout_val.toEnum(std.builtin.Type.ContainerLayout);
+ const layout = mod.toEnum(std.builtin.Type.ContainerLayout, layout_val);
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ // Because these three things each reference each other, `undefined`
+ // placeholders are used before being set after the union type gains an
+ // InternPool index.
- const union_obj = try new_decl_arena_allocator.create(Module.Union);
- const type_tag = if (!tag_type_val.isNull())
- Type.Tag.union_tagged
- else if (layout != .Auto)
- Type.Tag.@"union"
- else switch (block.sema.mod.optimizeMode()) {
- .Debug, .ReleaseSafe => Type.Tag.union_safety_tagged,
- .ReleaseFast, .ReleaseSmall => Type.Tag.@"union",
- };
- const union_payload = try new_decl_arena_allocator.create(Type.Payload.Union);
- union_payload.* = .{
- .base = .{ .tag = type_tag },
- .data = union_obj,
- };
- const union_ty = Type.initPayload(&union_payload.base);
- const new_union_val = try Value.Tag.ty.create(new_decl_arena_allocator, union_ty);
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = new_union_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, name_strategy, "union", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
- errdefer mod.abortAnonDecl(new_decl_index);
- union_obj.* = .{
+ 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(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
+ });
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer mod.destroyNamespace(new_namespace_index);
+
+ const union_index = try mod.createUnion(.{
.owner_decl = new_decl_index,
- .tag_ty = Type.initTag(.null),
+ .tag_ty = Type.null,
.fields = .{},
.zir_index = inst,
.layout = layout,
.status = .have_field_types,
- .namespace = .{
- .parent = block.namespace,
- .ty = union_ty,
- .file_scope = block.getFileScope(),
+ .namespace = new_namespace_index,
+ });
+ const union_obj = mod.unionPtr(union_index);
+ errdefer mod.destroyUnion(union_index);
+
+ const union_ty = try ip.get(gpa, .{ .union_type = .{
+ .index = union_index,
+ .runtime_tag = if (!tag_type_val.isNull(mod))
+ .tagged
+ else if (layout != .Auto)
+ .none
+ else switch (mod.optimizeMode()) {
+ .Debug, .ReleaseSafe => .safety,
+ .ReleaseFast, .ReleaseSmall => .none,
},
- };
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer ip.remove(union_ty);
+
+ new_decl.ty = Type.type;
+ new_decl.val = union_ty.toValue();
+ new_namespace.ty = union_ty.toType();
// Tag type
- var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
- var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
- if (tag_type_val.optionalValue()) |payload_val| {
- var buffer: Value.ToTypeBuffer = undefined;
- union_obj.tag_ty = try payload_val.toType(&buffer).copy(new_decl_arena_allocator);
+ var explicit_tags_seen: []bool = &.{};
+ var enum_field_names: []InternPool.NullTerminatedString = &.{};
+ if (tag_type_val.optionalValue(mod)) |payload_val| {
+ union_obj.tag_ty = payload_val.toType();
+
+ const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) {
+ .enum_type => |x| x,
+ else => return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{}),
+ };
- if (union_obj.tag_ty.zigTypeTag() != .Enum) {
- return sema.fail(block, src, "Type.Union.tag_type must be an enum type", .{});
- }
- tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);
+ explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
+ @memset(explicit_tags_seen, false);
} else {
- union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, fields_len, null);
- enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
+ enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
}
// Fields
- try union_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
-
- var i: usize = 0;
- while (i < fields_len) : (i += 1) {
- const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
- const field_struct_val = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // name: []const u8
- const name_val = field_struct_val[0];
- // type: type,
- const type_val = field_struct_val[1];
- // alignment: comptime_int,
- const alignment_val = field_struct_val[2];
-
- const field_name = try name_val.toAllocatedBytes(
- Type.initTag(.const_slice_u8),
- new_decl_arena_allocator,
- sema.mod,
- );
-
- if (enum_field_names) |set| {
- set.putAssumeCapacity(field_name, {});
- }
-
- if (tag_ty_field_names) |*names| {
- const enum_has_field = names.orderedRemove(field_name);
- if (!enum_has_field) {
+ try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
+
+ for (0..fields_len) |i| {
+ const elem_val = try fields_val.elemValue(mod, i);
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "name"),
+ ).?);
+ const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "type"),
+ ).?);
+ const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ 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 (explicit_tags_seen.len > 0) {
+ const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
+ const enum_index = tag_info.nameIndex(ip, field_name) orelse {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
- errdefer msg.destroy(sema.gpa);
+ const msg = try sema.errMsg(block, src, "no field named '{}' in enum '{}'", .{
+ field_name.fmt(ip),
+ union_obj.tag_ty.fmt(mod),
+ });
+ errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- }
+ };
+ // 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 = union_obj.fields.getOrPutAssumeCapacity(field_name);
if (gop.found_existing) {
// TODO: better source location
- return sema.fail(block, src, "duplicate union field {s}", .{field_name});
+ return sema.fail(block, src, "duplicate union field {}", .{field_name.fmt(ip)});
}
- var buffer: Value.ToTypeBuffer = undefined;
- const field_ty = try type_val.toType(&buffer).copy(new_decl_arena_allocator);
+ const field_ty = type_val.toType();
gop.value_ptr.* = .{
.ty = field_ty,
- .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?),
+ .abi_align = @intCast(u32, (try alignment_val.getUnsignedIntAdvanced(mod, sema)).?),
};
- if (field_ty.zigTypeTag() == .Opaque) {
+ 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(sema.gpa);
+ errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -19082,23 +20214,23 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
}
if (union_obj.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(sema.mod)});
- errdefer msg.destroy(sema.gpa);
+ 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 = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), field_ty, .union_field);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .union_field);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
+ } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
- errdefer msg.destroy(sema.gpa);
+ 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 = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl), field_ty);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -19107,47 +20239,61 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
}
}
- if (tag_ty_field_names) |names| {
- if (names.count() > 0) {
+ if (explicit_tags_seen.len > 0) {
+ const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).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(sema.gpa);
+ errdefer msg.destroy(gpa);
const enum_ty = union_obj.tag_ty;
- for (names.keys()) |field_name| {
- const field_index = enum_ty.enumFieldIndex(field_name).?;
- try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
+ for (tag_info.names, 0..) |field_name, field_index| {
+ if (explicit_tags_seen[field_index]) continue;
+ try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{
+ field_name.fmt(ip),
+ });
}
try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
+ } else {
+ union_obj.tag_ty = try sema.generateUnionTagTypeSimple(block, enum_field_names, null);
}
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
},
.Fn => {
- const struct_val: []const Value = union_val.val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // calling_convention: CallingConvention,
- const cc = struct_val[0].toEnum(std.builtin.CallingConvention);
- // alignment: comptime_int,
- const alignment_val = struct_val[1];
- // is_generic: bool,
- const is_generic = struct_val[2].toBool();
- // is_var_args: bool,
- const is_var_args = struct_val[3].toBool();
- // return_type: ?type,
- const return_type_val = struct_val[4];
- // args: []const Param,
- const args_val = struct_val[5];
-
+ const fields = ip.typeOf(union_val.val).toType().structFields(mod);
+ const calling_convention_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "calling_convention"),
+ ).?);
+ const alignment_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "alignment"),
+ ).?);
+ const is_generic_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "is_generic"),
+ ).?);
+ const is_var_args_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "is_var_args"),
+ ).?);
+ const return_type_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "return_type"),
+ ).?);
+ const params_val = try union_val.val.toValue().fieldValue(mod, fields.getIndex(
+ try ip.getOrPutString(gpa, "params"),
+ ).?);
+
+ const is_generic = is_generic_val.toBool();
if (is_generic) {
return sema.fail(block, src, "Type.Fn.is_generic must be false for @Type", .{});
}
+ const is_var_args = is_var_args_val.toBool();
+ const cc = mod.toEnum(std.builtin.CallingConvention, calling_convention_val);
if (is_var_args and cc != .C) {
return sema.fail(block, src, "varargs functions must have C calling convention", .{});
}
@@ -19156,74 +20302,65 @@ fn zirReify(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData, in
if (!try sema.intFitsInType(alignment_val, Type.u32, null)) {
return sema.fail(block, src, "alignment must fit in 'u32'", .{});
}
- const alignment = @intCast(u29, alignment_val.toUnsignedInt(target));
+ const alignment = @intCast(u29, alignment_val.toUnsignedInt(mod));
if (alignment == target_util.defaultFunctionAlignment(target)) {
- break :alignment 0;
+ break :alignment .none;
} else {
- break :alignment alignment;
+ break :alignment InternPool.Alignment.fromByteUnits(alignment);
}
};
- const return_type = return_type_val.optionalValue() orelse
+ const return_type = return_type_val.optionalValue(mod) orelse
return sema.fail(block, src, "Type.Fn.return_type must be non-null for @Type", .{});
- var buf: Value.ToTypeBuffer = undefined;
-
- const args_slice_val = args_val.castTag(.slice).?.data;
- const args_len = try sema.usizeCast(block, src, args_slice_val.len.toUnsignedInt(mod.getTarget()));
-
- const param_types = try sema.arena.alloc(Type, args_len);
- const comptime_params = try sema.arena.alloc(bool, args_len);
+ const args_len = try sema.usizeCast(block, src, params_val.sliceLen(mod));
+ const param_types = try sema.arena.alloc(InternPool.Index, args_len);
var noalias_bits: u32 = 0;
- var i: usize = 0;
- while (i < args_len) : (i += 1) {
- var arg_buf: Value.ElemValueBuffer = undefined;
- const arg = args_slice_val.ptr.elemValueBuffer(mod, i, &arg_buf);
- const arg_val = arg.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // is_generic: bool,
- const arg_is_generic = arg_val[0].toBool();
- // is_noalias: bool,
- const arg_is_noalias = arg_val[1].toBool();
- // type: ?type,
- const param_type_opt_val = arg_val[2];
-
- if (arg_is_generic) {
+ for (param_types, 0..) |*param_type, i| {
+ const elem_val = try params_val.elemValue(mod, i);
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const param_is_generic_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "is_generic"),
+ ).?);
+ const param_is_noalias_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "is_noalias"),
+ ).?);
+ const opt_param_type_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "type"),
+ ).?);
+
+ if (param_is_generic_val.toBool()) {
return sema.fail(block, src, "Type.Fn.Param.is_generic must be false for @Type", .{});
}
- const param_type_val = param_type_opt_val.optionalValue() orelse
+ const param_type_val = opt_param_type_val.optionalValue(mod) orelse
return sema.fail(block, src, "Type.Fn.Param.arg_type must be non-null for @Type", .{});
- const param_type = try param_type_val.toType(&buf).copy(sema.arena);
+ param_type.* = param_type_val.toIntern();
- if (arg_is_noalias) {
- if (!param_type.isPtrAtRuntime()) {
+ if (param_is_noalias_val.toBool()) {
+ if (!param_type.toType().isPtrAtRuntime(mod)) {
return sema.fail(block, src, "non-pointer parameter declared noalias", .{});
}
noalias_bits |= @as(u32, 1) << (std.math.cast(u5, i) orelse
return sema.fail(block, src, "this compiler implementation only supports 'noalias' on the first 32 parameters", .{}));
}
-
- param_types[i] = param_type;
- comptime_params[i] = false;
}
- var fn_info = Type.Payload.Function.Data{
+ const ty = try mod.funcType(.{
.param_types = param_types,
- .comptime_params = comptime_params.ptr,
+ .comptime_bits = 0,
.noalias_bits = noalias_bits,
- .return_type = try return_type.toType(&buf).copy(sema.arena),
+ .return_type = return_type.toIntern(),
.alignment = alignment,
.cc = cc,
.is_var_args = is_var_args,
.is_generic = false,
+ .is_noinline = false,
.align_is_generic = false,
.cc_is_generic = false,
.section_is_generic = false,
.addrspace_is_generic = false,
- };
-
- const ty = try Type.Tag.function.create(sema.arena, fn_info);
+ });
return sema.addType(ty);
},
.Frame => return sema.failWithUseOfAsync(block, src),
@@ -19241,22 +20378,34 @@ fn reifyStruct(
name_strategy: Zir.Inst.NameStrategy,
is_tuple: bool,
) CompileError!Air.Inst.Ref {
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
-
- const struct_obj = try new_decl_arena_allocator.create(Module.Struct);
- const struct_ty = try Type.Tag.@"struct".create(new_decl_arena_allocator, struct_obj);
- const new_struct_val = try Value.Tag.ty.create(new_decl_arena_allocator, struct_ty);
const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+
+ // Because these three things each reference each other, `undefined`
+ // placeholders are used before being set after the struct type gains an
+ // InternPool index.
+
const new_decl_index = try sema.createAnonymousDeclTypeNamed(block, src, .{
- .ty = Type.type,
- .val = new_struct_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, name_strategy, "struct", inst);
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
- errdefer mod.abortAnonDecl(new_decl_index);
- struct_obj.* = .{
+ 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(),
+ .ty = undefined,
+ .file_scope = block.getFileScope(mod),
+ });
+ const new_namespace = mod.namespacePtr(new_namespace_index);
+ errdefer mod.destroyNamespace(new_namespace_index);
+
+ const struct_index = try mod.createStruct(.{
.owner_decl = new_decl_index,
.fields = .{},
.zir_index = inst,
@@ -19264,38 +20413,49 @@ fn reifyStruct(
.status = .have_field_types,
.known_non_opv = false,
.is_tuple = is_tuple,
- .namespace = .{
- .parent = block.namespace,
- .ty = struct_ty,
- .file_scope = block.getFileScope(),
- },
- };
+ .namespace = new_namespace_index,
+ });
+ const struct_obj = mod.structPtr(struct_index);
+ errdefer mod.destroyStruct(struct_index);
- const target = mod.getTarget();
+ const struct_ty = try ip.get(gpa, .{ .struct_type = .{
+ .index = struct_index.toOptional(),
+ .namespace = new_namespace_index.toOptional(),
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer ip.remove(struct_ty);
+
+ new_decl.ty = Type.type;
+ new_decl.val = struct_ty.toValue();
+ new_namespace.ty = struct_ty.toType();
// Fields
const fields_len = try sema.usizeCast(block, src, fields_val.sliceLen(mod));
- try struct_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
+ try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
var i: usize = 0;
while (i < fields_len) : (i += 1) {
- const elem_val = try fields_val.elemValue(sema.mod, sema.arena, i);
- const field_struct_val = elem_val.castTag(.aggregate).?.data;
- // TODO use reflection instead of magic numbers here
- // name: []const u8
- const name_val = field_struct_val[0];
- // type: type,
- const type_val = field_struct_val[1];
- // default_value: ?*const anyopaque,
- const default_value_val = field_struct_val[2];
- // is_comptime: bool,
- const is_comptime_val = field_struct_val[3];
- // alignment: comptime_int,
- const alignment_val = field_struct_val[4];
+ const elem_val = try fields_val.elemValue(mod, i);
+ const elem_fields = ip.typeOf(elem_val.toIntern()).toType().structFields(mod);
+ const name_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "name"),
+ ).?);
+ const type_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "type"),
+ ).?);
+ const default_value_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "default_value"),
+ ).?);
+ const is_comptime_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ try ip.getOrPutString(gpa, "is_comptime"),
+ ).?);
+ const alignment_val = try elem_val.fieldValue(mod, elem_fields.getIndex(
+ 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 = @intCast(u29, (try alignment_val.getUnsignedIntAdvanced(target, sema)).?);
+ const abi_align = @intCast(u29, (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", .{});
@@ -19305,21 +20465,15 @@ fn reifyStruct(
return sema.fail(block, src, "extern struct fields cannot be marked comptime", .{});
}
- const field_name = try name_val.toAllocatedBytes(
- Type.initTag(.const_slice_u8),
- new_decl_arena_allocator,
- mod,
- );
+ const field_name = try name_val.toIpString(Type.slice_const_u8, mod);
if (is_tuple) {
- const field_index = std.fmt.parseUnsigned(u32, field_name, 10) catch {
- return sema.fail(
- block,
- src,
- "tuple cannot have non-numeric field '{s}'",
- .{field_name},
- );
- };
+ const field_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) {
return sema.fail(
@@ -19333,22 +20487,19 @@ fn reifyStruct(
const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
if (gop.found_existing) {
// TODO: better source location
- return sema.fail(block, src, "duplicate struct field {s}", .{field_name});
+ return sema.fail(block, src, "duplicate struct field {}", .{field_name.fmt(ip)});
}
- const default_val = if (default_value_val.optionalValue()) |opt_val| blk: {
- const payload_val = if (opt_val.pointerDecl()) |opt_decl|
- mod.declPtr(opt_decl).val
- else
- opt_val;
- break :blk try payload_val.copy(new_decl_arena_allocator);
- } else Value.initTag(.unreachable_value);
- if (is_comptime_val.toBool() and default_val.tag() == .unreachable_value) {
+ 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, "struct field default value must be comptime-known")).toIntern()
+ else
+ .none;
+ if (is_comptime_val.toBool() and default_val == .none) {
return sema.fail(block, src, "comptime field without default initialization value", .{});
}
- var buffer: Value.ToTypeBuffer = undefined;
- const field_ty = try type_val.toType(&buffer).copy(new_decl_arena_allocator);
gop.value_ptr.* = .{
.ty = field_ty,
.abi_align = abi_align,
@@ -19357,20 +20508,20 @@ fn reifyStruct(
.offset = undefined,
};
- if (field_ty.zigTypeTag() == .Opaque) {
+ 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 structs", .{});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (field_ty.zigTypeTag() == .NoReturn) {
+ if (field_ty.zigTypeTag(mod) == .NoReturn) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "struct fields cannot be 'noreturn'", .{});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -19380,22 +20531,22 @@ fn reifyStruct(
if (struct_obj.layout == .Extern and !try sema.validateExternType(field_ty, .struct_field)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "extern structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl), field_ty, .struct_field);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), field_ty, .struct_field);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty))) {
+ } else if (struct_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "packed structs cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
- errdefer msg.destroy(sema.gpa);
+ errdefer msg.destroy(gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl), field_ty);
+ try sema.explainWhyTypeIsNotPacked(msg, src.toSrcLoc(src_decl, mod), field_ty);
try sema.addDeclaredHereNote(msg, field_ty);
break :msg msg;
@@ -19411,7 +20562,7 @@ fn reifyStruct(
sema.resolveTypeLayout(field.ty) catch |err| switch (err) {
error.AnalysisFail => {
const msg = sema.err orelse return err;
- try sema.addFieldErrNote(struct_ty, index, msg, "while checking this field", .{});
+ try sema.addFieldErrNote(struct_ty.toType(), index, msg, "while checking this field", .{});
return err;
},
else => return err,
@@ -19420,30 +20571,27 @@ fn reifyStruct(
var fields_bit_sum: u64 = 0;
for (struct_obj.fields.values()) |field| {
- fields_bit_sum += field.ty.bitSize(target);
+ fields_bit_sum += field.ty.bitSize(mod);
}
- if (backing_int_val.optionalValue()) |payload| {
- var buf: Value.ToTypeBuffer = undefined;
- const backing_int_ty = payload.toType(&buf);
+ if (backing_int_val.optionalValue(mod)) |payload| {
+ const backing_int_ty = payload.toType();
try sema.checkBackingIntType(block, src, backing_int_ty, fields_bit_sum);
- struct_obj.backing_int_ty = try backing_int_ty.copy(new_decl_arena_allocator);
+ struct_obj.backing_int_ty = backing_int_ty;
} else {
- var buf: Type.Payload.Bits = .{
- .base = .{ .tag = .int_unsigned },
- .data = @intCast(u16, fields_bit_sum),
- };
- struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(new_decl_arena_allocator);
+ struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum));
}
struct_obj.status = .have_layout;
}
- try new_decl.finalizeNewArena(&new_decl_arena);
- return sema.analyzeDeclVal(block, src, new_decl_index);
+ const decl_val = sema.analyzeDeclVal(block, src, new_decl_index);
+ try mod.finalizeAnonDecl(new_decl_index);
+ return decl_val;
}
fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const addrspace_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
@@ -19455,7 +20603,7 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
try sema.checkPtrOperand(block, ptr_src, ptr_ty);
- var ptr_info = ptr_ty.ptrInfo().data;
+ var ptr_info = ptr_ty.ptrInfo(mod);
const src_addrspace = ptr_info.@"addrspace";
if (!target_util.addrSpaceCastIsValid(sema.mod.getTarget(), src_addrspace, dest_addrspace)) {
const msg = msg: {
@@ -19469,8 +20617,8 @@ fn zirAddrSpaceCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.Inst
ptr_info.@"addrspace" = dest_addrspace;
const dest_ptr_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
- const dest_ty = if (ptr_ty.zigTypeTag() == .Optional)
- try Type.optional(sema.arena, dest_ptr_ty)
+ const dest_ty = if (ptr_ty.zigTypeTag(mod) == .Optional)
+ try Type.optional(sema.arena, dest_ptr_ty, mod)
else
dest_ptr_ty;
@@ -19499,6 +20647,7 @@ fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.In
}
fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const va_list_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
@@ -19513,7 +20662,7 @@ fn zirCVaArg(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl), arg_ty, .param_ty);
+ try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), arg_ty, .param_ty);
try sema.addDeclaredHereNote(msg, arg_ty);
break :msg msg;
@@ -19560,6 +20709,7 @@ fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
}
fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ty = try sema.resolveType(block, ty_src, inst_data.operand);
@@ -19567,11 +20717,19 @@ fn zirTypeName(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
- const bytes = try ty.nameAllocArena(anon_decl.arena(), sema.mod);
+ const bytes = try ty.nameAllocArena(sema.arena, mod);
+ const decl_ty = try mod.arrayType(.{
+ .len = bytes.len,
+ .child = .u8_type,
+ .sentinel = .zero_u8,
+ });
const new_decl = try anon_decl.finish(
- try Type.Tag.array_u8_sentinel_0.create(anon_decl.arena(), bytes.len),
- try Value.Tag.bytes.create(anon_decl.arena(), bytes[0 .. bytes.len + 1]),
+ decl_ty,
+ (try mod.intern(.{ .aggregate = .{
+ .ty = decl_ty.toIntern(),
+ .storage = .{ .bytes = bytes },
+ } })).toValue(),
0, // default alignment
);
@@ -19591,6 +20749,7 @@ fn zirFrameSize(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
}
fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -19605,24 +20764,24 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveMaybeUndefVal(operand)) |val| {
const result_val = try sema.floatToInt(block, operand_src, val, operand_ty, dest_ty);
return sema.addConstant(dest_ty, result_val);
- } else if (dest_ty.zigTypeTag() == .ComptimeInt) {
+ } else if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_int' must be comptime-known");
}
try sema.requireRuntimeBlock(block, inst_data.src(), operand_src);
- if (dest_ty.intInfo(sema.mod.getTarget()).bits == 0) {
+ if (dest_ty.intInfo(mod).bits == 0) {
if (block.wantSafety()) {
- const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, Value.zero));
+ const ok = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_eq_optimized else .cmp_eq, operand, try sema.addConstant(operand_ty, try mod.intValue(operand_ty, 0)));
try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
}
- return sema.addConstant(dest_ty, Value.zero);
+ return sema.addConstant(dest_ty, try mod.intValue(dest_ty, 0));
}
const result = try block.addTyOp(if (block.float_mode == .Optimized) .float_to_int_optimized else .float_to_int, dest_ty, operand);
if (block.wantSafety()) {
const back = try block.addTyOp(.int_to_float, operand_ty, result);
const diff = try block.addBinOp(.sub, operand, back);
- const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, Value.one));
- const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, Value.negative_one));
+ const ok_pos = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_lt_optimized else .cmp_lt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, 1.0)));
+ const ok_neg = try block.addBinOp(if (block.float_mode == .Optimized) .cmp_gt_optimized else .cmp_gt, diff, try sema.addConstant(operand_ty, try mod.floatValue(operand_ty, -1.0)));
const ok = try block.addBinOp(.bool_and, ok_pos, ok_neg);
try sema.addSafetyCheck(block, ok, .integer_part_out_of_bounds);
}
@@ -19630,6 +20789,7 @@ fn zirFloatToInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -19644,7 +20804,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
if (try sema.resolveMaybeUndefVal(operand)) |val| {
const result_val = try val.intToFloatAdvanced(sema.arena, operand_ty, dest_ty, sema.mod, sema);
return sema.addConstant(dest_ty, result_val);
- } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
+ } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
return sema.failWithNeededComptime(block, operand_src, "value being casted to 'comptime_float' must be comptime-known");
}
@@ -19653,6 +20813,7 @@ fn zirIntToFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
@@ -19665,41 +20826,48 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const type_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const ptr_ty = try sema.resolveType(block, src, extra.lhs);
try sema.checkPtrType(block, type_src, ptr_ty);
- const elem_ty = ptr_ty.elemType2();
- const target = sema.mod.getTarget();
- const ptr_align = try ptr_ty.ptrAlignmentAdvanced(target, sema);
+ const elem_ty = ptr_ty.elemType2(mod);
+ const ptr_align = try ptr_ty.ptrAlignmentAdvanced(mod, sema);
+
+ if (ptr_ty.isSlice(mod)) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, type_src, "integer cannot be converted to slice type '{}'", .{ptr_ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, type_src, msg, "slice length cannot be inferred from address", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
if (try sema.resolveDefinedValue(block, operand_src, operand_coerced)) |val| {
- const addr = val.toUnsignedInt(target);
- if (!ptr_ty.isAllowzeroPtr() and addr == 0)
+ const addr = val.toUnsignedInt(mod);
+ if (!ptr_ty.isAllowzeroPtr(mod) and addr == 0)
return sema.fail(block, operand_src, "pointer type '{}' does not allow address zero", .{ptr_ty.fmt(sema.mod)});
if (addr != 0 and ptr_align != 0 and addr % ptr_align != 0)
return sema.fail(block, operand_src, "pointer type '{}' requires aligned address", .{ptr_ty.fmt(sema.mod)});
- const val_payload = try sema.arena.create(Value.Payload.U64);
- val_payload.* = .{
- .base = .{ .tag = .int_u64 },
- .data = addr,
+ const ptr_val = switch (ptr_ty.zigTypeTag(mod)) {
+ .Optional => (try mod.intern(.{ .opt = .{
+ .ty = ptr_ty.toIntern(),
+ .val = if (addr == 0) .none else (try mod.ptrIntValue(ptr_ty.childType(mod), addr)).toIntern(),
+ } })).toValue(),
+ .Pointer => try mod.ptrIntValue(ptr_ty, addr),
+ else => unreachable,
};
- return sema.addConstant(ptr_ty, Value.initPayload(&val_payload.base));
+ return sema.addConstant(ptr_ty, ptr_val);
}
try sema.requireRuntimeBlock(block, src, operand_src);
- if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag() == .Fn)) {
- if (!ptr_ty.isAllowzeroPtr()) {
+ if (block.wantSafety() and (try sema.typeHasRuntimeBits(elem_ty) or elem_ty.zigTypeTag(mod) == .Fn)) {
+ if (!ptr_ty.isAllowzeroPtr(mod)) {
const is_non_zero = try block.addBinOp(.cmp_neq, operand_coerced, .zero_usize);
try sema.addSafetyCheck(block, is_non_zero, .cast_to_null);
}
if (ptr_align > 1) {
- const val_payload = try sema.arena.create(Value.Payload.U64);
- val_payload.* = .{
- .base = .{ .tag = .int_u64 },
- .data = ptr_align - 1,
- };
const align_minus_1 = try sema.addConstant(
Type.usize,
- Value.initPayload(&val_payload.base),
+ try mod.intValue(Type.usize, ptr_align - 1),
);
const remainder = try block.addBinOp(.bit_and, operand_coerced, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
@@ -19710,6 +20878,8 @@ fn zirIntToPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
@@ -19725,22 +20895,27 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
if (disjoint: {
// Try avoiding resolving inferred error sets if we can
- if (!dest_ty.isAnyError() and dest_ty.errorSetNames().len == 0) break :disjoint true;
- if (!operand_ty.isAnyError() and operand_ty.errorSetNames().len == 0) break :disjoint true;
- if (dest_ty.isAnyError()) break :disjoint false;
- if (operand_ty.isAnyError()) break :disjoint false;
- for (dest_ty.errorSetNames()) |dest_err_name|
- if (operand_ty.errorSetHasField(dest_err_name))
+ if (!dest_ty.isAnyError(mod) and dest_ty.errorSetNames(mod).len == 0) break :disjoint true;
+ if (!operand_ty.isAnyError(mod) and operand_ty.errorSetNames(mod).len == 0) break :disjoint true;
+ if (dest_ty.isAnyError(mod)) break :disjoint false;
+ if (operand_ty.isAnyError(mod)) break :disjoint false;
+ for (dest_ty.errorSetNames(mod)) |dest_err_name| {
+ if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
break :disjoint false;
+ }
- if (dest_ty.tag() != .error_set_inferred and operand_ty.tag() != .error_set_inferred)
+ if (!ip.isInferredErrorSetType(dest_ty.toIntern()) and
+ !ip.isInferredErrorSetType(operand_ty.toIntern()))
+ {
break :disjoint true;
+ }
try sema.resolveInferredErrorSetTy(block, dest_ty_src, dest_ty);
try sema.resolveInferredErrorSetTy(block, operand_src, operand_ty);
- for (dest_ty.errorSetNames()) |dest_err_name|
- if (operand_ty.errorSetHasField(dest_err_name))
+ for (dest_ty.errorSetNames(mod)) |dest_err_name| {
+ if (Type.errorSetHasFieldIp(ip, operand_ty.toIntern(), dest_err_name))
break :disjoint false;
+ }
break :disjoint true;
}) {
@@ -19760,15 +20935,15 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
}
if (maybe_operand_val) |val| {
- if (!dest_ty.isAnyError()) {
- const error_name = val.castTag(.@"error").?.data.name;
- if (!dest_ty.errorSetHasField(error_name)) {
+ if (!dest_ty.isAnyError(mod)) {
+ const error_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
+ if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), error_name)) {
const msg = msg: {
const msg = try sema.errMsg(
block,
src,
- "'error.{s}' not a member of error set '{}'",
- .{ error_name, dest_ty.fmt(sema.mod) },
+ "'error.{}' not a member of error set '{}'",
+ .{ error_name.fmt(ip), dest_ty.fmt(sema.mod) },
);
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, dest_ty);
@@ -19778,11 +20953,11 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
}
}
- return sema.addConstant(dest_ty, val);
+ return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
}
try sema.requireRuntimeBlock(block, src, operand_src);
- if (block.wantSafety() and !dest_ty.isAnyError() and sema.mod.backendSupportsFeature(.error_set_has_value)) {
+ if (block.wantSafety() and !dest_ty.isAnyError(mod) and sema.mod.backendSupportsFeature(.error_set_has_value)) {
const err_int_inst = try block.addBitCast(Type.err_int, operand);
const ok = try block.addTyOp(.error_set_has_value, dest_ty, err_int_inst);
try sema.addSafetyCheck(block, ok, .invalid_error_code);
@@ -19791,6 +20966,7 @@ fn zirErrSetCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
}
fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -19799,13 +20975,12 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
const dest_ty = try sema.resolveType(block, dest_ty_src, extra.lhs);
const operand = try sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
- const target = sema.mod.getTarget();
try sema.checkPtrType(block, dest_ty_src, dest_ty);
try sema.checkPtrOperand(block, operand_src, operand_ty);
- const operand_info = operand_ty.ptrInfo().data;
- const dest_info = dest_ty.ptrInfo().data;
+ const operand_info = operand_ty.ptrInfo(mod);
+ const dest_info = dest_ty.ptrInfo(mod);
if (!operand_info.mutable and dest_info.mutable) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "cast discards const qualifier", .{});
@@ -19837,8 +21012,8 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
return sema.failWithOwnedErrorMsg(msg);
}
- const dest_is_slice = dest_ty.isSlice();
- const operand_is_slice = operand_ty.isSlice();
+ const dest_is_slice = dest_ty.isSlice(mod);
+ const operand_is_slice = operand_ty.isSlice(mod);
if (dest_is_slice and !operand_is_slice) {
return sema.fail(block, dest_ty_src, "illegal pointer cast to slice", .{});
}
@@ -19847,32 +21022,31 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
else
operand;
- const dest_elem_ty = dest_ty.elemType2();
+ const dest_elem_ty = dest_ty.elemType2(mod);
try sema.resolveTypeLayout(dest_elem_ty);
- const dest_align = dest_ty.ptrAlignment(target);
+ const dest_align = dest_ty.ptrAlignment(mod);
- const operand_elem_ty = operand_ty.elemType2();
+ const operand_elem_ty = operand_ty.elemType2(mod);
try sema.resolveTypeLayout(operand_elem_ty);
- const operand_align = operand_ty.ptrAlignment(target);
+ const operand_align = operand_ty.ptrAlignment(mod);
// If the destination is less aligned than the source, preserve the source alignment
const aligned_dest_ty = if (operand_align <= dest_align) dest_ty else blk: {
// Unwrap the pointer (or pointer-like optional) type, set alignment, and re-wrap into result
- if (dest_ty.zigTypeTag() == .Optional) {
- var buf: Type.Payload.ElemType = undefined;
- var dest_ptr_info = dest_ty.optionalChild(&buf).ptrInfo().data;
+ if (dest_ty.zigTypeTag(mod) == .Optional) {
+ var dest_ptr_info = dest_ty.optionalChild(mod).ptrInfo(mod);
dest_ptr_info.@"align" = operand_align;
- break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, sema.mod, dest_ptr_info));
+ break :blk try Type.optional(sema.arena, try Type.ptr(sema.arena, mod, dest_ptr_info), mod);
} else {
- var dest_ptr_info = dest_ty.ptrInfo().data;
+ var dest_ptr_info = dest_ty.ptrInfo(mod);
dest_ptr_info.@"align" = operand_align;
- break :blk try Type.ptr(sema.arena, sema.mod, dest_ptr_info);
+ break :blk try Type.ptr(sema.arena, mod, dest_ptr_info);
}
};
if (dest_is_slice) {
- const operand_elem_size = operand_elem_ty.abiSize(target);
- const dest_elem_size = dest_elem_ty.abiSize(target);
+ const operand_elem_size = operand_elem_ty.abiSize(mod);
+ const dest_elem_size = dest_elem_ty.abiSize(mod);
if (operand_elem_size != dest_elem_size) {
return sema.fail(block, dest_ty_src, "TODO: implement @ptrCast between slices changing the length", .{});
}
@@ -19884,10 +21058,10 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, operand_src, msg, "'{}' has alignment '{d}'", .{
- operand_ty.fmt(sema.mod), operand_align,
+ operand_ty.fmt(mod), operand_align,
});
try sema.errNote(block, dest_ty_src, msg, "'{}' has alignment '{d}'", .{
- dest_ty.fmt(sema.mod), dest_align,
+ dest_ty.fmt(mod), dest_align,
});
try sema.errNote(block, src, msg, "consider using '@alignCast'", .{});
@@ -19897,21 +21071,18 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
}
if (try sema.resolveMaybeUndefVal(ptr)) |operand_val| {
- if (!dest_ty.ptrAllowsZero() and operand_val.isUndef()) {
+ if (!dest_ty.ptrAllowsZero(mod) and operand_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, operand_src);
}
- if (!dest_ty.ptrAllowsZero() and operand_val.isNull()) {
- return sema.fail(block, operand_src, "null pointer casted to type {}", .{dest_ty.fmt(sema.mod)});
+ if (!dest_ty.ptrAllowsZero(mod) and operand_val.isNull(mod)) {
+ return sema.fail(block, operand_src, "null pointer casted to type '{}'", .{dest_ty.fmt(mod)});
}
- if (dest_ty.zigTypeTag() == .Optional and sema.typeOf(ptr).zigTypeTag() != .Optional) {
- return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, operand_val));
- }
- return sema.addConstant(aligned_dest_ty, operand_val);
+ return sema.addConstant(aligned_dest_ty, try mod.getCoerced(operand_val, aligned_dest_ty));
}
try sema.requireRuntimeBlock(block, src, null);
- if (block.wantSafety() and operand_ty.ptrAllowsZero() and !dest_ty.ptrAllowsZero() and
- (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn))
+ if (block.wantSafety() and operand_ty.ptrAllowsZero(mod) and !dest_ty.ptrAllowsZero(mod) and
+ (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn))
{
const ptr_int = try block.addUnOp(.ptrtoint, ptr);
const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
@@ -19927,6 +21098,7 @@ fn zirPtrCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
}
fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
@@ -19934,12 +21106,12 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
const operand_ty = sema.typeOf(operand);
try sema.checkPtrOperand(block, operand_src, operand_ty);
- var ptr_info = operand_ty.ptrInfo().data;
+ var ptr_info = operand_ty.ptrInfo(mod);
ptr_info.mutable = true;
- const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
+ const dest_ty = try Type.ptr(sema.arena, mod, ptr_info);
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
- return sema.addConstant(dest_ty, operand_val);
+ return sema.addConstant(dest_ty, try mod.getCoerced(operand_val, dest_ty));
}
try sema.requireRuntimeBlock(block, src, null);
@@ -19947,6 +21119,7 @@ fn zirConstCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData
}
fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
@@ -19954,9 +21127,9 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
const operand_ty = sema.typeOf(operand);
try sema.checkPtrOperand(block, operand_src, operand_ty);
- var ptr_info = operand_ty.ptrInfo().data;
+ var ptr_info = operand_ty.ptrInfo(mod);
ptr_info.@"volatile" = false;
- const dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
+ const dest_ty = try Type.ptr(sema.arena, mod, ptr_info);
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
return sema.addConstant(dest_ty, operand_val);
@@ -19967,6 +21140,7 @@ fn zirVolatileCast(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
}
fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const src = inst_data.src();
const dest_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -19977,9 +21151,12 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const dest_is_comptime_int = try sema.checkIntType(block, dest_ty_src, dest_scalar_ty);
const operand_ty = sema.typeOf(operand);
const operand_scalar_ty = try sema.checkIntOrVectorAllowComptime(block, operand_ty, operand_src);
- const is_vector = operand_ty.zigTypeTag() == .Vector;
+ const is_vector = operand_ty.zigTypeTag(mod) == .Vector;
const dest_ty = if (is_vector)
- try Type.vector(sema.arena, operand_ty.vectorLen(), dest_scalar_ty)
+ try mod.vectorType(.{
+ .len = operand_ty.vectorLen(mod),
+ .child = dest_scalar_ty.toIntern(),
+ })
else
dest_scalar_ty;
@@ -19987,22 +21164,21 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
return sema.coerce(block, dest_ty, operand, operand_src);
}
- const target = sema.mod.getTarget();
- const dest_info = dest_scalar_ty.intInfo(target);
+ const dest_info = dest_scalar_ty.intInfo(mod);
if (try sema.typeHasOnePossibleValue(dest_ty)) |val| {
return sema.addConstant(dest_ty, val);
}
- if (operand_scalar_ty.zigTypeTag() != .ComptimeInt) {
- const operand_info = operand_ty.intInfo(target);
+ if (operand_scalar_ty.zigTypeTag(mod) != .ComptimeInt) {
+ const operand_info = operand_ty.intInfo(mod);
if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
return sema.addConstant(operand_ty, val);
}
if (operand_info.signedness != dest_info.signedness) {
return sema.fail(block, operand_src, "expected {s} integer type, found '{}'", .{
- @tagName(dest_info.signedness), operand_ty.fmt(sema.mod),
+ @tagName(dest_info.signedness), operand_ty.fmt(mod),
});
}
if (operand_info.bits < dest_info.bits) {
@@ -20011,7 +21187,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
block,
src,
"destination type '{}' has more bits than source type '{}'",
- .{ dest_ty.fmt(sema.mod), operand_ty.fmt(sema.mod) },
+ .{ dest_ty.fmt(mod), operand_ty.fmt(mod) },
);
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, dest_ty_src, msg, "destination type has {d} bits", .{
@@ -20027,23 +21203,22 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
if (try sema.resolveMaybeUndefValIntable(operand)) |val| {
- if (val.isUndef()) return sema.addConstUndef(dest_ty);
+ if (val.isUndef(mod)) return sema.addConstUndef(dest_ty);
if (!is_vector) {
- return sema.addConstant(
+ return sema.addConstant(dest_ty, try mod.getCoerced(
+ try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, mod),
dest_ty,
- try val.intTrunc(operand_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod),
- );
+ ));
}
- var elem_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, operand_ty.vectorLen());
+ const elems = try sema.arena.alloc(InternPool.Index, operand_ty.vectorLen(mod));
for (elems, 0..) |*elem, i| {
- const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
- elem.* = try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, sema.mod);
+ const elem_val = try val.elemValue(mod, i);
+ elem.* = try (try elem_val.intTrunc(operand_scalar_ty, sema.arena, dest_info.signedness, dest_info.bits, mod)).intern(dest_scalar_ty, mod);
}
- return sema.addConstant(
- dest_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = dest_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, src, operand_src);
@@ -20051,6 +21226,7 @@ fn zirTruncate(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
}
fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const align_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -20061,43 +21237,38 @@ fn zirAlignCast(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
try sema.checkPtrOperand(block, ptr_src, ptr_ty);
- var ptr_info = ptr_ty.ptrInfo().data;
+ var ptr_info = ptr_ty.ptrInfo(mod);
ptr_info.@"align" = dest_align;
- var dest_ty = try Type.ptr(sema.arena, sema.mod, ptr_info);
- if (ptr_ty.zigTypeTag() == .Optional) {
- dest_ty = try Type.Tag.optional.create(sema.arena, dest_ty);
+ var dest_ty = try Type.ptr(sema.arena, mod, ptr_info);
+ if (ptr_ty.zigTypeTag(mod) == .Optional) {
+ dest_ty = try mod.optionalType(dest_ty.toIntern());
}
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |val| {
- if (try val.getUnsignedIntAdvanced(sema.mod.getTarget(), null)) |addr| {
+ if (try val.getUnsignedIntAdvanced(mod, null)) |addr| {
if (addr % dest_align != 0) {
return sema.fail(block, ptr_src, "pointer address 0x{X} is not aligned to {d} bytes", .{ addr, dest_align });
}
}
- return sema.addConstant(dest_ty, val);
+ return sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
}
try sema.requireRuntimeBlock(block, inst_data.src(), ptr_src);
if (block.wantSafety() and dest_align > 1 and
try sema.typeHasRuntimeBits(ptr_info.pointee_type))
{
- const val_payload = try sema.arena.create(Value.Payload.U64);
- val_payload.* = .{
- .base = .{ .tag = .int_u64 },
- .data = dest_align - 1,
- };
const align_minus_1 = try sema.addConstant(
Type.usize,
- Value.initPayload(&val_payload.base),
+ try mod.intValue(Type.usize, dest_align - 1),
);
- const actual_ptr = if (ptr_ty.isSlice())
+ const actual_ptr = if (ptr_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, ptr_src, ptr, ptr_ty)
else
ptr;
const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
const remainder = try block.addBinOp(.bit_and, ptr_int, align_minus_1);
const is_aligned = try block.addBinOp(.cmp_eq, remainder, .zero_usize);
- const ok = if (ptr_ty.isSlice()) ok: {
+ const ok = if (ptr_ty.isSlice(mod)) ok: {
const len = try sema.analyzeSliceLen(block, ptr_src, ptr);
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_aligned);
@@ -20112,51 +21283,52 @@ fn zirBitCount(
block: *Block,
inst: Zir.Inst.Index,
air_tag: Air.Inst.Tag,
- comptime comptimeOp: fn (val: Value, ty: Type, target: std.Target) u64,
+ comptime comptimeOp: fn (val: Value, ty: Type, mod: *Module) u64,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
_ = try sema.checkIntOrVector(block, operand, operand_src);
- const target = sema.mod.getTarget();
- const bits = operand_ty.intInfo(target).bits;
+ const bits = operand_ty.intInfo(mod).bits;
if (try sema.typeHasOnePossibleValue(operand_ty)) |val| {
return sema.addConstant(operand_ty, val);
}
- const result_scalar_ty = try Type.smallestUnsignedInt(sema.arena, bits);
- switch (operand_ty.zigTypeTag()) {
+ const result_scalar_ty = try mod.smallestUnsignedInt(bits);
+ switch (operand_ty.zigTypeTag(mod)) {
.Vector => {
- const vec_len = operand_ty.vectorLen();
- const result_ty = try Type.vector(sema.arena, vec_len, result_scalar_ty);
+ const vec_len = operand_ty.vectorLen(mod);
+ const result_ty = try mod.vectorType(.{
+ .len = vec_len,
+ .child = result_scalar_ty.toIntern(),
+ });
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) return sema.addConstUndef(result_ty);
+ if (val.isUndef(mod)) return sema.addConstUndef(result_ty);
- var elem_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, vec_len);
- const scalar_ty = operand_ty.scalarType();
+ const elems = try sema.arena.alloc(InternPool.Index, vec_len);
+ const scalar_ty = operand_ty.scalarType(mod);
for (elems, 0..) |*elem, i| {
- const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
- const count = comptimeOp(elem_val, scalar_ty, target);
- elem.* = try Value.Tag.int_u64.create(sema.arena, count);
- }
- return sema.addConstant(
- result_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ const elem_val = try val.elemValue(mod, i);
+ const count = comptimeOp(elem_val, scalar_ty, mod);
+ elem.* = (try mod.intValue(result_scalar_ty, count)).toIntern();
+ }
+ return sema.addConstant(result_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = result_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
} else {
try sema.requireRuntimeBlock(block, src, operand_src);
return block.addTyOp(air_tag, result_ty, operand);
}
},
.Int => {
- if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) return sema.addConstUndef(result_scalar_ty);
- try sema.resolveLazyValue(val);
- return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, target));
+ if (try sema.resolveMaybeUndefLazyVal(operand)) |val| {
+ if (val.isUndef(mod)) return sema.addConstUndef(result_scalar_ty);
+ return sema.addIntUnsigned(result_scalar_ty, comptimeOp(val, operand_ty, mod));
} else {
try sema.requireRuntimeBlock(block, src, operand_src);
return block.addTyOp(air_tag, result_scalar_ty, operand);
@@ -20167,20 +21339,20 @@ fn zirBitCount(
}
fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].un_node;
const src = inst_data.src();
const operand_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const operand = try sema.resolveInst(inst_data.operand);
const operand_ty = sema.typeOf(operand);
const scalar_ty = try sema.checkIntOrVector(block, operand, operand_src);
- const target = sema.mod.getTarget();
- const bits = scalar_ty.intInfo(target).bits;
+ const bits = scalar_ty.intInfo(mod).bits;
if (bits % 8 != 0) {
return sema.fail(
block,
operand_src,
"@byteSwap requires the number of bits to be evenly divisible by 8, but {} has {} bits",
- .{ scalar_ty.fmt(sema.mod), bits },
+ .{ scalar_ty.fmt(mod), bits },
);
}
@@ -20188,11 +21360,11 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
return sema.addConstant(operand_ty, val);
}
- switch (operand_ty.zigTypeTag()) {
+ switch (operand_ty.zigTypeTag(mod)) {
.Int => {
const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) return sema.addConstUndef(operand_ty);
- const result_val = try val.byteSwap(operand_ty, target, sema.arena);
+ if (val.isUndef(mod)) return sema.addConstUndef(operand_ty);
+ const result_val = try val.byteSwap(operand_ty, mod, sema.arena);
return sema.addConstant(operand_ty, result_val);
} else operand_src;
@@ -20201,20 +21373,19 @@ fn zirByteSwap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
},
.Vector => {
const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef())
+ if (val.isUndef(mod))
return sema.addConstUndef(operand_ty);
- const vec_len = operand_ty.vectorLen();
- var elem_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, vec_len);
+ const vec_len = operand_ty.vectorLen(mod);
+ const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
- const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
- elem.* = try elem_val.byteSwap(operand_ty, target, sema.arena);
+ const elem_val = try val.elemValue(mod, i);
+ elem.* = try (try elem_val.byteSwap(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod);
}
- return sema.addConstant(
- operand_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = operand_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
} else operand_src;
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -20236,12 +21407,12 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
return sema.addConstant(operand_ty, val);
}
- const target = sema.mod.getTarget();
- switch (operand_ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (operand_ty.zigTypeTag(mod)) {
.Int => {
const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef()) return sema.addConstUndef(operand_ty);
- const result_val = try val.bitReverse(operand_ty, target, sema.arena);
+ if (val.isUndef(mod)) return sema.addConstUndef(operand_ty);
+ const result_val = try val.bitReverse(operand_ty, mod, sema.arena);
return sema.addConstant(operand_ty, result_val);
} else operand_src;
@@ -20250,20 +21421,19 @@ fn zirBitReverse(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
},
.Vector => {
const runtime_src = if (try sema.resolveMaybeUndefVal(operand)) |val| {
- if (val.isUndef())
+ if (val.isUndef(mod))
return sema.addConstUndef(operand_ty);
- const vec_len = operand_ty.vectorLen();
- var elem_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, vec_len);
+ const vec_len = operand_ty.vectorLen(mod);
+ const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
- const elem_val = val.elemValueBuffer(sema.mod, i, &elem_buf);
- elem.* = try elem_val.bitReverse(scalar_ty, target, sema.arena);
+ const elem_val = try val.elemValue(mod, i);
+ elem.* = try (try elem_val.bitReverse(scalar_ty, mod, sema.arena)).intern(scalar_ty, mod);
}
- return sema.addConstant(
- operand_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ return sema.addConstant(operand_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = operand_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
} else operand_src;
try sema.requireRuntimeBlock(block, src, runtime_src);
@@ -20293,15 +21463,15 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const ty = try sema.resolveType(block, lhs_src, extra.lhs);
- const field_name = try sema.resolveConstString(block, rhs_src, extra.rhs, "name of field must be comptime-known");
- const target = sema.mod.getTarget();
+ const field_name = try sema.resolveConstStringIntern(block, rhs_src, extra.rhs, "name of field must be comptime-known");
+ const mod = sema.mod;
try sema.resolveTypeLayout(ty);
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Struct => {},
else => {
const msg = msg: {
- const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, lhs_src, "expected struct type, found '{}'", .{ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, ty);
break :msg msg;
@@ -20310,45 +21480,47 @@ fn bitOffsetOf(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!u6
},
}
- const field_index = if (ty.isTuple()) blk: {
- if (mem.eql(u8, field_name, "len")) {
+ const field_index = if (ty.isTuple(mod)) blk: {
+ if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
return sema.fail(block, src, "no offset available for 'len' field of tuple", .{});
}
break :blk try sema.tupleFieldIndex(block, ty, field_name, rhs_src);
} else try sema.structFieldIndex(block, ty, field_name, rhs_src);
- if (ty.structFieldIsComptime(field_index)) {
+ if (ty.structFieldIsComptime(field_index, mod)) {
return sema.fail(block, src, "no offset available for comptime field", .{});
}
- switch (ty.containerLayout()) {
+ switch (ty.containerLayout(mod)) {
.Packed => {
var bit_sum: u64 = 0;
- const fields = ty.structFields();
+ const fields = ty.structFields(mod);
for (fields.values(), 0..) |field, i| {
if (i == field_index) {
return bit_sum;
}
- bit_sum += field.ty.bitSize(target);
+ bit_sum += field.ty.bitSize(mod);
} else unreachable;
},
- else => return ty.structFieldOffset(field_index, target) * 8,
+ else => return ty.structFieldOffset(field_index, mod) * 8,
}
}
fn checkNamespaceType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Struct, .Enum, .Union, .Opaque => return,
- else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(sema.mod)}),
+ else => return sema.fail(block, src, "expected struct, enum, union, or opaque; found '{}'", .{ty.fmt(mod)}),
}
}
/// Returns `true` if the type was a comptime_int.
fn checkIntType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!bool {
- switch (try ty.zigTypeTagOrPoison()) {
+ const mod = sema.mod;
+ switch (try ty.zigTypeTagOrPoison(mod)) {
.ComptimeInt => return true,
.Int => return false,
- else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(sema.mod)}),
+ else => return sema.fail(block, src, "expected integer type, found '{}'", .{ty.fmt(mod)}),
}
}
@@ -20358,8 +21530,9 @@ fn checkInvalidPtrArithmetic(
src: LazySrcLoc,
ty: Type,
) CompileError!void {
- switch (try ty.zigTypeTagOrPoison()) {
- .Pointer => switch (ty.ptrSize()) {
+ const mod = sema.mod;
+ switch (try ty.zigTypeTagOrPoison(mod)) {
+ .Pointer => switch (ty.ptrSize(mod)) {
.One, .Slice => return,
.Many, .C => return sema.fail(
block,
@@ -20397,7 +21570,8 @@ fn checkPtrOperand(
ty_src: LazySrcLoc,
ty: Type,
) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Pointer => return,
.Fn => {
const msg = msg: {
@@ -20405,7 +21579,7 @@ fn checkPtrOperand(
block,
ty_src,
"expected pointer, found '{}'",
- .{ty.fmt(sema.mod)},
+ .{ty.fmt(mod)},
);
errdefer msg.destroy(sema.gpa);
@@ -20415,10 +21589,10 @@ fn checkPtrOperand(
};
return sema.failWithOwnedErrorMsg(msg);
},
- .Optional => if (ty.isPtrLikeOptional()) return,
+ .Optional => if (ty.isPtrLikeOptional(mod)) return,
else => {},
}
- return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});
+ return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});
}
fn checkPtrType(
@@ -20427,7 +21601,8 @@ fn checkPtrType(
ty_src: LazySrcLoc,
ty: Type,
) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Pointer => return,
.Fn => {
const msg = msg: {
@@ -20435,7 +21610,7 @@ fn checkPtrType(
block,
ty_src,
"expected pointer type, found '{}'",
- .{ty.fmt(sema.mod)},
+ .{ty.fmt(mod)},
);
errdefer msg.destroy(sema.gpa);
@@ -20445,10 +21620,10 @@ fn checkPtrType(
};
return sema.failWithOwnedErrorMsg(msg);
},
- .Optional => if (ty.isPtrLikeOptional()) return,
+ .Optional => if (ty.isPtrLikeOptional(mod)) return,
else => {},
}
- return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(sema.mod)});
+ return sema.fail(block, ty_src, "expected pointer type, found '{}'", .{ty.fmt(mod)});
}
fn checkVectorElemType(
@@ -20457,11 +21632,12 @@ fn checkVectorElemType(
ty_src: LazySrcLoc,
ty: Type,
) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Int, .Float, .Bool => return,
- else => if (ty.isPtrAtRuntime()) return,
+ else => if (ty.isPtrAtRuntime(mod)) return,
}
- return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(sema.mod)});
+ return sema.fail(block, ty_src, "expected integer, float, bool, or pointer for the vector element type; found '{}'", .{ty.fmt(mod)});
}
fn checkFloatType(
@@ -20470,9 +21646,10 @@ fn checkFloatType(
ty_src: LazySrcLoc,
ty: Type,
) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.ComptimeInt, .ComptimeFloat, .Float => {},
- else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(sema.mod)}),
+ else => return sema.fail(block, ty_src, "expected float type, found '{}'", .{ty.fmt(mod)}),
}
}
@@ -20482,13 +21659,14 @@ fn checkNumericType(
ty_src: LazySrcLoc,
ty: Type,
) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.ComptimeFloat, .Float, .ComptimeInt, .Int => {},
- .Vector => switch (ty.childType().zigTypeTag()) {
+ .Vector => switch (ty.childType(mod).zigTypeTag(mod)) {
.ComptimeFloat, .Float, .ComptimeInt, .Int => {},
else => |t| return sema.fail(block, ty_src, "expected number, found '{}'", .{t}),
},
- else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(sema.mod)}),
+ else => return sema.fail(block, ty_src, "expected number, found '{}'", .{ty.fmt(mod)}),
}
}
@@ -20502,9 +21680,10 @@ fn checkAtomicPtrOperand(
ptr_src: LazySrcLoc,
ptr_const: bool,
) CompileError!Air.Inst.Ref {
- const target = sema.mod.getTarget();
- var diag: target_util.AtomicPtrAlignmentDiagnostics = .{};
- const alignment = target_util.atomicPtrAlignment(target, elem_ty, &diag) catch |err| switch (err) {
+ const mod = sema.mod;
+ var diag: Module.AtomicPtrAlignmentDiagnostics = .{};
+ const alignment = mod.atomicPtrAlignment(elem_ty, &diag) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
error.FloatTooBig => return sema.fail(
block,
elem_ty_src,
@@ -20521,7 +21700,7 @@ fn checkAtomicPtrOperand(
block,
elem_ty_src,
"expected bool, integer, float, enum, or pointer type; found '{}'",
- .{elem_ty.fmt(sema.mod)},
+ .{elem_ty.fmt(mod)},
),
};
@@ -20533,10 +21712,10 @@ fn checkAtomicPtrOperand(
};
const ptr_ty = sema.typeOf(ptr);
- const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison()) {
- .Pointer => ptr_ty.ptrInfo().data,
+ const ptr_data = switch (try ptr_ty.zigTypeTagOrPoison(mod)) {
+ .Pointer => ptr_ty.ptrInfo(mod),
else => {
- const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
+ const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data);
_ = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
unreachable;
},
@@ -20546,7 +21725,7 @@ fn checkAtomicPtrOperand(
wanted_ptr_data.@"allowzero" = ptr_data.@"allowzero";
wanted_ptr_data.@"volatile" = ptr_data.@"volatile";
- const wanted_ptr_ty = try Type.ptr(sema.arena, sema.mod, wanted_ptr_data);
+ const wanted_ptr_ty = try Type.ptr(sema.arena, mod, wanted_ptr_data);
const casted_ptr = try sema.coerce(block, wanted_ptr_ty, ptr, ptr_src);
return casted_ptr;
@@ -20560,7 +21739,7 @@ fn checkPtrIsNotComptimeMutable(
operand_src: LazySrcLoc,
) CompileError!void {
_ = operand_src;
- if (ptr_val.isComptimeMutablePtr()) {
+ if (ptr_val.isComptimeMutablePtr(sema.mod)) {
return sema.fail(block, ptr_src, "cannot store runtime value in compile time variable", .{});
}
}
@@ -20569,7 +21748,7 @@ fn checkComptimeVarStore(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- decl_ref_mut: Value.Payload.DeclRefMut.Data,
+ decl_ref_mut: InternPool.Key.Ptr.Addr.MutDecl,
) CompileError!void {
if (@enumToInt(decl_ref_mut.runtime_index) < @enumToInt(block.runtime_index)) {
if (block.runtime_cond) |cond_src| {
@@ -20600,20 +21779,21 @@ fn checkIntOrVector(
operand: Air.Inst.Ref,
operand_src: LazySrcLoc,
) CompileError!Type {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
- switch (try operand_ty.zigTypeTagOrPoison()) {
+ switch (try operand_ty.zigTypeTagOrPoison(mod)) {
.Int => return operand_ty,
.Vector => {
- const elem_ty = operand_ty.childType();
- switch (try elem_ty.zigTypeTagOrPoison()) {
+ const elem_ty = operand_ty.childType(mod);
+ switch (try elem_ty.zigTypeTagOrPoison(mod)) {
.Int => return elem_ty,
else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
- elem_ty.fmt(sema.mod),
+ elem_ty.fmt(mod),
}),
}
},
else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
}),
}
}
@@ -20624,27 +21804,29 @@ fn checkIntOrVectorAllowComptime(
operand_ty: Type,
operand_src: LazySrcLoc,
) CompileError!Type {
- switch (try operand_ty.zigTypeTagOrPoison()) {
+ const mod = sema.mod;
+ switch (try operand_ty.zigTypeTagOrPoison(mod)) {
.Int, .ComptimeInt => return operand_ty,
.Vector => {
- const elem_ty = operand_ty.childType();
- switch (try elem_ty.zigTypeTagOrPoison()) {
+ const elem_ty = operand_ty.childType(mod);
+ switch (try elem_ty.zigTypeTagOrPoison(mod)) {
.Int, .ComptimeInt => return elem_ty,
else => return sema.fail(block, operand_src, "expected vector of integers; found vector of '{}'", .{
- elem_ty.fmt(sema.mod),
+ elem_ty.fmt(mod),
}),
}
},
else => return sema.fail(block, operand_src, "expected integer or vector, found '{}'", .{
- operand_ty.fmt(sema.mod),
+ operand_ty.fmt(mod),
}),
}
}
fn checkErrorSetType(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.ErrorSet => return,
- else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(sema.mod)}),
+ else => return sema.fail(block, src, "expected error set type, found '{}'", .{ty.fmt(mod)}),
}
}
@@ -20670,11 +21852,12 @@ fn checkSimdBinOp(
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
) CompileError!SimdBinOp {
+ const mod = sema.mod;
const lhs_ty = sema.typeOf(uncasted_lhs);
const rhs_ty = sema.typeOf(uncasted_rhs);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
- var vec_len: ?usize = if (lhs_ty.zigTypeTag() == .Vector) lhs_ty.vectorLen() else null;
+ var vec_len: ?usize = if (lhs_ty.zigTypeTag(mod) == .Vector) lhs_ty.vectorLen(mod) else null;
const result_ty = try sema.resolvePeerTypes(block, src, &.{ uncasted_lhs, uncasted_rhs }, .{
.override = &[_]?LazySrcLoc{ lhs_src, rhs_src },
});
@@ -20688,7 +21871,7 @@ fn checkSimdBinOp(
.lhs_val = try sema.resolveMaybeUndefVal(lhs),
.rhs_val = try sema.resolveMaybeUndefVal(rhs),
.result_ty = result_ty,
- .scalar_ty = result_ty.scalarType(),
+ .scalar_ty = result_ty.scalarType(mod),
};
}
@@ -20701,8 +21884,9 @@ fn checkVectorizableBinaryOperands(
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
) CompileError!void {
- const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison();
- const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison();
+ const mod = sema.mod;
+ const lhs_zig_ty_tag = try lhs_ty.zigTypeTagOrPoison(mod);
+ const rhs_zig_ty_tag = try rhs_ty.zigTypeTagOrPoison(mod);
if (lhs_zig_ty_tag != .Vector and rhs_zig_ty_tag != .Vector) return;
const lhs_is_vector = switch (lhs_zig_ty_tag) {
@@ -20715,8 +21899,8 @@ fn checkVectorizableBinaryOperands(
};
if (lhs_is_vector and rhs_is_vector) {
- const lhs_len = lhs_ty.arrayLen();
- const rhs_len = rhs_ty.arrayLen();
+ const lhs_len = lhs_ty.arrayLen(mod);
+ const rhs_len = rhs_ty.arrayLen(mod);
if (lhs_len != rhs_len) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "vector length mismatch", .{});
@@ -20730,7 +21914,7 @@ fn checkVectorizableBinaryOperands(
} else {
const msg = msg: {
const msg = try sema.errMsg(block, src, "mixed scalar and vector operands: '{}' and '{}'", .{
- lhs_ty.fmt(sema.mod), rhs_ty.fmt(sema.mod),
+ lhs_ty.fmt(mod), rhs_ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
if (lhs_is_vector) {
@@ -20748,7 +21932,8 @@ fn checkVectorizableBinaryOperands(
fn maybeOptionsSrc(sema: *Sema, block: *Block, base_src: LazySrcLoc, wanted: []const u8) LazySrcLoc {
if (base_src == .unneeded) return .unneeded;
- return Module.optionsSrc(sema.gpa, sema.mod.declPtr(block.src_decl), base_src, wanted);
+ const mod = sema.mod;
+ return mod.optionsSrc(mod.declPtr(block.src_decl), base_src, wanted);
}
fn resolveExportOptions(
@@ -20756,7 +21941,10 @@ fn resolveExportOptions(
block: *Block,
src: LazySrcLoc,
zir_ref: Zir.Inst.Ref,
-) CompileError!std.builtin.ExportOptions {
+) CompileError!Module.Export.Options {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const export_options_ty = try sema.getBuiltinType("ExportOptions");
const air_ref = try sema.resolveInst(zir_ref);
const options = try sema.coerce(block, export_options_ty, air_ref, src);
@@ -20766,26 +21954,26 @@ fn resolveExportOptions(
const section_src = sema.maybeOptionsSrc(block, src, "section");
const visibility_src = sema.maybeOptionsSrc(block, src, "visibility");
- const name_operand = try sema.fieldVal(block, src, options, "name", name_src);
+ const name_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);
const name_val = try sema.resolveConstValue(block, name_src, name_operand, "name of exported value must be comptime-known");
- const name_ty = Type.initTag(.const_slice_u8);
- const name = try name_val.toAllocatedBytes(name_ty, sema.arena, sema.mod);
+ const name_ty = Type.slice_const_u8;
+ const name = try name_val.toAllocatedBytes(name_ty, sema.arena, mod);
- const linkage_operand = try sema.fieldVal(block, src, options, "linkage", linkage_src);
+ const linkage_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src);
const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_operand, "linkage of exported value must be comptime-known");
- const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage);
+ const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val);
- const section_operand = try sema.fieldVal(block, src, options, "section", section_src);
+ const section_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "section"), section_src);
const section_opt_val = try sema.resolveConstValue(block, section_src, section_operand, "linksection of exported value must be comptime-known");
- const section_ty = Type.initTag(.const_slice_u8);
- const section = if (section_opt_val.optionalValue()) |section_val|
- try section_val.toAllocatedBytes(section_ty, sema.arena, sema.mod)
+ const section_ty = Type.slice_const_u8;
+ const section = if (section_opt_val.optionalValue(mod)) |section_val|
+ try section_val.toAllocatedBytes(section_ty, sema.arena, mod)
else
null;
- const visibility_operand = try sema.fieldVal(block, src, options, "visibility", visibility_src);
+ const visibility_operand = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "visibility"), visibility_src);
const visibility_val = try sema.resolveConstValue(block, visibility_src, visibility_operand, "visibility of exported value must be comptime-known");
- const visibility = visibility_val.toEnum(std.builtin.SymbolVisibility);
+ const visibility = mod.toEnum(std.builtin.SymbolVisibility, visibility_val);
if (name.len < 1) {
return sema.fail(block, name_src, "exported symbol name cannot be empty", .{});
@@ -20797,10 +21985,10 @@ fn resolveExportOptions(
});
}
- return std.builtin.ExportOptions{
- .name = name,
+ return .{
+ .name = try ip.getOrPutString(gpa, name),
.linkage = linkage,
- .section = section,
+ .section = try ip.getOrPutStringOpt(gpa, section),
.visibility = visibility,
};
}
@@ -20813,11 +22001,12 @@ fn resolveBuiltinEnum(
comptime name: []const u8,
reason: []const u8,
) CompileError!@field(std.builtin, name) {
+ const mod = sema.mod;
const ty = try sema.getBuiltinType(name);
const air_ref = try sema.resolveInst(zir_ref);
const coerced = try sema.coerce(block, ty, air_ref, src);
const val = try sema.resolveConstValue(block, src, coerced, reason);
- return val.toEnum(@field(std.builtin, name));
+ return mod.toEnum(@field(std.builtin, name), val);
}
fn resolveAtomicOrder(
@@ -20844,6 +22033,7 @@ fn zirCmpxchg(
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
const air_tag: Air.Inst.Tag = switch (extended.small) {
0 => .cmpxchg_weak,
@@ -20861,12 +22051,12 @@ fn zirCmpxchg(
// zig fmt: on
const expected_value = try sema.resolveInst(extra.expected_value);
const elem_ty = sema.typeOf(expected_value);
- if (elem_ty.zigTypeTag() == .Float) {
+ if (elem_ty.zigTypeTag(mod) == .Float) {
return sema.fail(
block,
elem_ty_src,
"expected bool, integer, enum, or pointer type; found '{}'",
- .{elem_ty.fmt(sema.mod)},
+ .{elem_ty.fmt(mod)},
);
}
const uncasted_ptr = try sema.resolveInst(extra.ptr);
@@ -20888,29 +22078,34 @@ fn zirCmpxchg(
return sema.fail(block, failure_order_src, "failure atomic ordering must not be Release or AcqRel", .{});
}
- const result_ty = try Type.optional(sema.arena, elem_ty);
+ const result_ty = try Type.optional(sema.arena, elem_ty, mod);
// special case zero bit types
if ((try sema.typeHasOnePossibleValue(elem_ty)) != null) {
- return sema.addConstant(result_ty, Value.null);
+ return sema.addConstant(result_ty, (try mod.intern(.{ .opt = .{
+ .ty = result_ty.toIntern(),
+ .val = .none,
+ } })).toValue());
}
const runtime_src = if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| rs: {
if (try sema.resolveMaybeUndefVal(expected_value)) |expected_val| {
if (try sema.resolveMaybeUndefVal(new_value)) |new_val| {
- if (expected_val.isUndef() or new_val.isUndef()) {
+ if (expected_val.isUndef(mod) or new_val.isUndef(mod)) {
// TODO: this should probably cause the memory stored at the pointer
// to become undef as well
return sema.addConstUndef(result_ty);
}
const ptr_ty = sema.typeOf(ptr);
const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
- const result_val = if (stored_val.eql(expected_val, elem_ty, sema.mod)) blk: {
- try sema.storePtr(block, src, ptr, new_value);
- break :blk Value.null;
- } else try Value.Tag.opt_payload.create(sema.arena, stored_val);
-
- return sema.addConstant(result_ty, result_val);
+ const result_val = try mod.intern(.{ .opt = .{
+ .ty = result_ty.toIntern(),
+ .val = if (stored_val.eql(expected_val, elem_ty, mod)) blk: {
+ try sema.storePtr(block, src, ptr, new_value);
+ break :blk .none;
+ } else stored_val.toIntern(),
+ } });
+ return sema.addConstant(result_ty, result_val.toValue());
} else break :rs new_value_src;
} else break :rs expected_src;
} else ptr_src;
@@ -20934,6 +22129,7 @@ fn zirCmpxchg(
}
fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const len_src: LazySrcLoc = .{ .node_offset_bin_lhs = inst_data.src_node };
@@ -20942,17 +22138,13 @@ fn zirSplat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.I
const scalar = try sema.resolveInst(extra.rhs);
const scalar_ty = sema.typeOf(scalar);
try sema.checkVectorElemType(block, scalar_src, scalar_ty);
- const vector_ty = try Type.Tag.vector.create(sema.arena, .{
+ const vector_ty = try mod.vectorType(.{
.len = len,
- .elem_type = scalar_ty,
+ .child = scalar_ty.toIntern(),
});
if (try sema.resolveMaybeUndefVal(scalar)) |scalar_val| {
- if (scalar_val.isUndef()) return sema.addConstUndef(vector_ty);
-
- return sema.addConstant(
- vector_ty,
- try Value.Tag.repeated.create(sema.arena, scalar_val),
- );
+ if (scalar_val.isUndef(mod)) return sema.addConstUndef(vector_ty);
+ return sema.addConstant(vector_ty, try sema.splat(vector_ty, scalar_val));
}
try sema.requireRuntimeBlock(block, inst_data.src(), scalar_src);
@@ -20967,31 +22159,31 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", "@reduce operation must be comptime-known");
const operand = try sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
- if (operand_ty.zigTypeTag() != .Vector) {
- return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(sema.mod)});
+ if (operand_ty.zigTypeTag(mod) != .Vector) {
+ return sema.fail(block, operand_src, "expected vector, found '{}'", .{operand_ty.fmt(mod)});
}
- const scalar_ty = operand_ty.childType();
+ const scalar_ty = operand_ty.childType(mod);
// Type-check depending on operation.
switch (operation) {
- .And, .Or, .Xor => switch (scalar_ty.zigTypeTag()) {
+ .And, .Or, .Xor => switch (scalar_ty.zigTypeTag(mod)) {
.Int, .Bool => {},
else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or boolean operand; found '{}'", .{
- @tagName(operation), operand_ty.fmt(sema.mod),
+ @tagName(operation), operand_ty.fmt(mod),
}),
},
- .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag()) {
+ .Min, .Max, .Add, .Mul => switch (scalar_ty.zigTypeTag(mod)) {
.Int, .Float => {},
else => return sema.fail(block, operand_src, "@reduce operation '{s}' requires integer or float operand; found '{}'", .{
- @tagName(operation), operand_ty.fmt(sema.mod),
+ @tagName(operation), operand_ty.fmt(mod),
}),
},
}
- const vec_len = operand_ty.vectorLen();
+ const vec_len = operand_ty.vectorLen(mod);
if (vec_len == 0) {
// TODO re-evaluate if we should introduce a "neutral value" for some operations,
// e.g. zero for add and one for mul.
@@ -20999,21 +22191,20 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
if (try sema.resolveMaybeUndefVal(operand)) |operand_val| {
- if (operand_val.isUndef()) return sema.addConstUndef(scalar_ty);
+ if (operand_val.isUndef(mod)) return sema.addConstUndef(scalar_ty);
- var accum: Value = try operand_val.elemValue(sema.mod, sema.arena, 0);
- var elem_buf: Value.ElemValueBuffer = undefined;
+ var accum: Value = try operand_val.elemValue(mod, 0);
var i: u32 = 1;
while (i < vec_len) : (i += 1) {
- const elem_val = operand_val.elemValueBuffer(sema.mod, i, &elem_buf);
+ const elem_val = try operand_val.elemValue(mod, i);
switch (operation) {
- .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, sema.mod),
- .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, sema.mod),
- .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, sema.mod),
- .Min => accum = accum.numberMin(elem_val, target),
- .Max => accum = accum.numberMax(elem_val, target),
+ .And => accum = try accum.bitwiseAnd(elem_val, scalar_ty, sema.arena, mod),
+ .Or => accum = try accum.bitwiseOr(elem_val, scalar_ty, sema.arena, mod),
+ .Xor => accum = try accum.bitwiseXor(elem_val, scalar_ty, sema.arena, mod),
+ .Min => accum = accum.numberMin(elem_val, mod),
+ .Max => accum = accum.numberMax(elem_val, mod),
.Add => accum = try sema.numberAddWrapScalar(accum, elem_val, scalar_ty),
- .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, sema.mod),
+ .Mul => accum = try accum.numberMulWrap(elem_val, scalar_ty, sema.arena, mod),
}
}
return sema.addConstant(scalar_ty, accum);
@@ -21030,6 +22221,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Shuffle, inst_data.payload_index).data;
const elem_ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
@@ -21042,13 +22234,13 @@ fn zirShuffle(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air
var mask = try sema.resolveInst(extra.mask);
var mask_ty = sema.typeOf(mask);
- const mask_len = switch (sema.typeOf(mask).zigTypeTag()) {
- .Array, .Vector => sema.typeOf(mask).arrayLen(),
+ const mask_len = switch (sema.typeOf(mask).zigTypeTag(mod)) {
+ .Array, .Vector => sema.typeOf(mask).arrayLen(mod),
else => return sema.fail(block, mask_src, "expected vector or array, found '{}'", .{sema.typeOf(mask).fmt(sema.mod)}),
};
- mask_ty = try Type.Tag.vector.create(sema.arena, .{
- .len = mask_len,
- .elem_type = Type.i32,
+ mask_ty = try mod.vectorType(.{
+ .len = @intCast(u32, mask_len),
+ .child = .i32_type,
});
mask = try sema.coerce(block, mask_ty, mask, mask_src);
const mask_val = try sema.resolveConstMaybeUndefVal(block, mask_src, mask, "shuffle mask must be comptime-known");
@@ -21065,27 +22257,28 @@ fn analyzeShuffle(
mask: Value,
mask_len: u32,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const a_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = src_node };
const b_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = src_node };
const mask_src: LazySrcLoc = .{ .node_offset_builtin_call_arg3 = src_node };
var a = a_arg;
var b = b_arg;
- const res_ty = try Type.Tag.vector.create(sema.arena, .{
+ const res_ty = try mod.vectorType(.{
.len = mask_len,
- .elem_type = elem_ty,
+ .child = elem_ty.toIntern(),
});
- var maybe_a_len = switch (sema.typeOf(a).zigTypeTag()) {
- .Array, .Vector => sema.typeOf(a).arrayLen(),
+ var maybe_a_len = switch (sema.typeOf(a).zigTypeTag(mod)) {
+ .Array, .Vector => sema.typeOf(a).arrayLen(mod),
.Undefined => null,
else => return sema.fail(block, a_src, "expected vector or array with element type '{}', found '{}'", .{
elem_ty.fmt(sema.mod),
sema.typeOf(a).fmt(sema.mod),
}),
};
- var maybe_b_len = switch (sema.typeOf(b).zigTypeTag()) {
- .Array, .Vector => sema.typeOf(b).arrayLen(),
+ var maybe_b_len = switch (sema.typeOf(b).zigTypeTag(mod)) {
+ .Array, .Vector => sema.typeOf(b).arrayLen(mod),
.Undefined => null,
else => return sema.fail(block, b_src, "expected vector or array with element type '{}', found '{}'", .{
elem_ty.fmt(sema.mod),
@@ -21095,16 +22288,16 @@ fn analyzeShuffle(
if (maybe_a_len == null and maybe_b_len == null) {
return sema.addConstUndef(res_ty);
}
- const a_len = maybe_a_len orelse maybe_b_len.?;
- const b_len = maybe_b_len orelse a_len;
+ const a_len = @intCast(u32, maybe_a_len orelse maybe_b_len.?);
+ const b_len = @intCast(u32, maybe_b_len orelse a_len);
- const a_ty = try Type.Tag.vector.create(sema.arena, .{
+ const a_ty = try mod.vectorType(.{
.len = a_len,
- .elem_type = elem_ty,
+ .child = elem_ty.toIntern(),
});
- const b_ty = try Type.Tag.vector.create(sema.arena, .{
+ const b_ty = try mod.vectorType(.{
.len = b_len,
- .elem_type = elem_ty,
+ .child = elem_ty.toIntern(),
});
if (maybe_a_len == null) a = try sema.addConstUndef(a_ty) else a = try sema.coerce(block, a_ty, a, a_src);
@@ -21115,12 +22308,10 @@ fn analyzeShuffle(
.{ b_len, b_src, b_ty },
};
- var i: usize = 0;
- while (i < mask_len) : (i += 1) {
- var buf: Value.ElemValueBuffer = undefined;
- const elem = mask.elemValueBuffer(sema.mod, i, &buf);
- if (elem.isUndef()) continue;
- const int = elem.toSignedInt(sema.mod.getTarget());
+ for (0..@intCast(usize, mask_len)) |i| {
+ const elem = try mask.elemValue(sema.mod, i);
+ if (elem.isUndef(mod)) continue;
+ const int = elem.toSignedInt(mod);
var unsigned: u32 = undefined;
var chosen: u32 = undefined;
if (int >= 0) {
@@ -21152,26 +22343,21 @@ fn analyzeShuffle(
if (try sema.resolveMaybeUndefVal(a)) |a_val| {
if (try sema.resolveMaybeUndefVal(b)) |b_val| {
- const values = try sema.arena.alloc(Value, mask_len);
-
- i = 0;
- while (i < mask_len) : (i += 1) {
- var buf: Value.ElemValueBuffer = undefined;
- const mask_elem_val = mask.elemValueBuffer(sema.mod, i, &buf);
- if (mask_elem_val.isUndef()) {
- values[i] = Value.undef;
+ const values = try sema.arena.alloc(InternPool.Index, mask_len);
+ for (values, 0..) |*value, i| {
+ const mask_elem_val = try mask.elemValue(sema.mod, i);
+ if (mask_elem_val.isUndef(mod)) {
+ value.* = try mod.intern(.{ .undef = elem_ty.toIntern() });
continue;
}
- const int = mask_elem_val.toSignedInt(sema.mod.getTarget());
+ const int = mask_elem_val.toSignedInt(mod);
const unsigned = if (int >= 0) @intCast(u32, int) else @intCast(u32, ~int);
- if (int >= 0) {
- values[i] = try a_val.elemValue(sema.mod, sema.arena, unsigned);
- } else {
- values[i] = try b_val.elemValue(sema.mod, sema.arena, unsigned);
- }
+ values[i] = try (try (if (int >= 0) a_val else b_val).elemValue(mod, unsigned)).intern(elem_ty, mod);
}
- const res_val = try Value.Tag.aggregate.create(sema.arena, values);
- return sema.addConstant(res_ty, res_val);
+ return sema.addConstant(res_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = res_ty.toIntern(),
+ .storage = .{ .elems = values },
+ } })).toValue());
}
}
@@ -21181,31 +22367,31 @@ fn analyzeShuffle(
// to it up to the length of the longer vector. This recursion terminates
// in 1 call because these calls to analyzeShuffle guarantee a_len == b_len.
if (a_len != b_len) {
- const min_len = std.math.min(a_len, b_len);
+ const min_len = @min(a_len, b_len);
const max_src = if (a_len > b_len) a_src else b_src;
- const max_len = try sema.usizeCast(block, max_src, std.math.max(a_len, b_len));
+ const max_len = try sema.usizeCast(block, max_src, @max(a_len, b_len));
- const expand_mask_values = try sema.arena.alloc(Value, max_len);
- i = 0;
- while (i < min_len) : (i += 1) {
- expand_mask_values[i] = try Value.Tag.int_u64.create(sema.arena, i);
+ const expand_mask_values = try sema.arena.alloc(InternPool.Index, max_len);
+ for (@intCast(usize, 0)..@intCast(usize, min_len)) |i| {
+ expand_mask_values[i] = (try mod.intValue(Type.comptime_int, i)).toIntern();
}
- while (i < max_len) : (i += 1) {
- expand_mask_values[i] = Value.negative_one;
+ for (@intCast(usize, min_len)..@intCast(usize, max_len)) |i| {
+ expand_mask_values[i] = (try mod.intValue(Type.comptime_int, -1)).toIntern();
}
- const expand_mask = try Value.Tag.aggregate.create(sema.arena, expand_mask_values);
+ const expand_mask = try mod.intern(.{ .aggregate = .{
+ .ty = (try mod.vectorType(.{ .len = @intCast(u32, max_len), .child = .comptime_int_type })).toIntern(),
+ .storage = .{ .elems = expand_mask_values },
+ } });
if (a_len < b_len) {
const undef = try sema.addConstUndef(a_ty);
- a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask, @intCast(u32, max_len));
+ a = try sema.analyzeShuffle(block, src_node, elem_ty, a, undef, expand_mask.toValue(), @intCast(u32, max_len));
} else {
const undef = try sema.addConstUndef(b_ty);
- b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask, @intCast(u32, max_len));
+ b = try sema.analyzeShuffle(block, src_node, elem_ty, b, undef, expand_mask.toValue(), @intCast(u32, max_len));
}
}
- const mask_index = @intCast(u32, sema.air_values.items.len);
- try sema.air_values.append(sema.gpa, mask);
return block.addInst(.{
.tag = .shuffle,
.data = .{ .ty_pl = .{
@@ -21213,7 +22399,7 @@ fn analyzeShuffle(
.payload = try block.sema.addExtra(Air.Shuffle{
.a = a,
.b = b,
- .mask = mask_index,
+ .mask = mask.toIntern(),
.mask_len = mask_len,
}),
} },
@@ -21221,6 +22407,7 @@ fn analyzeShuffle(
}
fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.Select, extended.operand).data;
const src = LazySrcLoc.nodeOffset(extra.node);
@@ -21234,16 +22421,22 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
const pred_uncoerced = try sema.resolveInst(extra.pred);
const pred_ty = sema.typeOf(pred_uncoerced);
- const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison()) {
- .Vector, .Array => pred_ty.arrayLen(),
- else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(sema.mod)}),
+ const vec_len_u64 = switch (try pred_ty.zigTypeTagOrPoison(mod)) {
+ .Vector, .Array => pred_ty.arrayLen(mod),
+ else => return sema.fail(block, pred_src, "expected vector or array, found '{}'", .{pred_ty.fmt(mod)}),
};
- const vec_len = try sema.usizeCast(block, pred_src, vec_len_u64);
+ const vec_len = @intCast(u32, try sema.usizeCast(block, pred_src, vec_len_u64));
- const bool_vec_ty = try Type.vector(sema.arena, vec_len, Type.bool);
+ const bool_vec_ty = try mod.vectorType(.{
+ .len = vec_len,
+ .child = .bool_type,
+ });
const pred = try sema.coerce(block, bool_vec_ty, pred_uncoerced, pred_src);
- const vec_ty = try Type.vector(sema.arena, vec_len, elem_ty);
+ const vec_ty = try mod.vectorType(.{
+ .len = vec_len,
+ .child = elem_ty.toIntern(),
+ });
const a = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.a), a_src);
const b = try sema.coerce(block, vec_ty, try sema.resolveInst(extra.b), b_src);
@@ -21252,45 +22445,40 @@ fn zirSelect(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
const maybe_b = try sema.resolveMaybeUndefVal(b);
const runtime_src = if (maybe_pred) |pred_val| rs: {
- if (pred_val.isUndef()) return sema.addConstUndef(vec_ty);
+ if (pred_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
if (maybe_a) |a_val| {
- if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
+ if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
if (maybe_b) |b_val| {
- if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
+ if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
- var buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.gpa.alloc(Value, vec_len);
+ const elems = try sema.gpa.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
- const pred_elem_val = pred_val.elemValueBuffer(sema.mod, i, &buf);
+ const pred_elem_val = try pred_val.elemValue(mod, i);
const should_choose_a = pred_elem_val.toBool();
- if (should_choose_a) {
- elem.* = a_val.elemValueBuffer(sema.mod, i, &buf);
- } else {
- elem.* = b_val.elemValueBuffer(sema.mod, i, &buf);
- }
+ elem.* = try (try (if (should_choose_a) a_val else b_val).elemValue(mod, i)).intern(elem_ty, mod);
}
- return sema.addConstant(
- vec_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
+ return sema.addConstant(vec_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = vec_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
} else {
break :rs b_src;
}
} else {
if (maybe_b) |b_val| {
- if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
+ if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
}
break :rs a_src;
}
} else rs: {
if (maybe_a) |a_val| {
- if (a_val.isUndef()) return sema.addConstUndef(vec_ty);
+ if (a_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
}
if (maybe_b) |b_val| {
- if (b_val.isUndef()) return sema.addConstUndef(vec_ty);
+ if (b_val.isUndef(mod)) return sema.addConstUndef(vec_ty);
}
break :rs pred_src;
};
@@ -21354,6 +22542,7 @@ fn zirAtomicLoad(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!
}
fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.AtomicRmw, inst_data.payload_index).data;
const src = inst_data.src();
@@ -21370,7 +22559,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const ptr = try sema.checkAtomicPtrOperand(block, elem_ty, elem_ty_src, uncasted_ptr, ptr_src, false);
const op = try sema.resolveAtomicRmwOp(block, op_src, extra.operation);
- switch (elem_ty.zigTypeTag()) {
+ switch (elem_ty.zigTypeTag(mod)) {
.Enum => if (op != .Xchg) {
return sema.fail(block, op_src, "@atomicRmw with enum only allowed with .Xchg", .{});
},
@@ -21400,8 +22589,7 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
break :rs operand_src;
};
- if (ptr_val.isComptimeMutablePtr()) {
- const target = sema.mod.getTarget();
+ if (ptr_val.isComptimeMutablePtr(mod)) {
const ptr_ty = sema.typeOf(ptr);
const stored_val = (try sema.pointerDeref(block, ptr_src, ptr_val, ptr_ty)) orelse break :rs ptr_src;
const new_val = switch (op) {
@@ -21409,12 +22597,12 @@ fn zirAtomicRmw(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
.Xchg => operand_val,
.Add => try sema.numberAddWrapScalar(stored_val, operand_val, elem_ty),
.Sub => try sema.numberSubWrapScalar(stored_val, operand_val, elem_ty),
- .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, sema.mod),
- .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, sema.mod),
- .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, sema.mod),
- .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, sema.mod),
- .Max => stored_val.numberMax (operand_val, target),
- .Min => stored_val.numberMin (operand_val, target),
+ .And => try stored_val.bitwiseAnd (operand_val, elem_ty, sema.arena, mod),
+ .Nand => try stored_val.bitwiseNand (operand_val, elem_ty, sema.arena, mod),
+ .Or => try stored_val.bitwiseOr (operand_val, elem_ty, sema.arena, mod),
+ .Xor => try stored_val.bitwiseXor (operand_val, elem_ty, sema.arena, mod),
+ .Max => stored_val.numberMax (operand_val, mod),
+ .Min => stored_val.numberMin (operand_val, mod),
// zig fmt: on
};
try sema.storePtrVal(block, src, ptr_val, new_val, elem_ty);
@@ -21488,18 +22676,19 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const maybe_mulend1 = try sema.resolveMaybeUndefVal(mulend1);
const maybe_mulend2 = try sema.resolveMaybeUndefVal(mulend2);
const maybe_addend = try sema.resolveMaybeUndefVal(addend);
+ const mod = sema.mod;
- switch (ty.zigTypeTag()) {
- .ComptimeFloat, .Float, .Vector => {},
+ switch (ty.scalarType(mod).zigTypeTag(mod)) {
+ .ComptimeFloat, .Float => {},
else => return sema.fail(block, src, "expected vector of floats or float type, found '{}'", .{ty.fmt(sema.mod)}),
}
const runtime_src = if (maybe_mulend1) |mulend1_val| rs: {
if (maybe_mulend2) |mulend2_val| {
- if (mulend2_val.isUndef()) return sema.addConstUndef(ty);
+ if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty);
if (maybe_addend) |addend_val| {
- if (addend_val.isUndef()) return sema.addConstUndef(ty);
+ if (addend_val.isUndef(mod)) return sema.addConstUndef(ty);
const result_val = try Value.mulAdd(ty, mulend1_val, mulend2_val, addend_val, sema.arena, sema.mod);
return sema.addConstant(ty, result_val);
} else {
@@ -21507,16 +22696,16 @@ fn zirMulAdd(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
}
} else {
if (maybe_addend) |addend_val| {
- if (addend_val.isUndef()) return sema.addConstUndef(ty);
+ if (addend_val.isUndef(mod)) return sema.addConstUndef(ty);
}
break :rs mulend2_src;
}
} else rs: {
if (maybe_mulend2) |mulend2_val| {
- if (mulend2_val.isUndef()) return sema.addConstUndef(ty);
+ if (mulend2_val.isUndef(mod)) return sema.addConstUndef(ty);
}
if (maybe_addend) |addend_val| {
- if (addend_val.isUndef()) return sema.addConstUndef(ty);
+ if (addend_val.isUndef(mod)) return sema.addConstUndef(ty);
}
break :rs mulend1_src;
};
@@ -21538,6 +22727,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const modifier_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = inst_data.src_node };
const func_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
@@ -21551,7 +22741,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const air_ref = try sema.resolveInst(extra.modifier);
const modifier_ref = try sema.coerce(block, modifier_ty, air_ref, modifier_src);
const modifier_val = try sema.resolveConstValue(block, modifier_src, modifier_ref, "call modifier must be comptime-known");
- var modifier = modifier_val.toEnum(std.builtin.CallModifier);
+ var modifier = mod.toEnum(std.builtin.CallModifier, modifier_val);
switch (modifier) {
// These can be upgraded to comptime or nosuspend calls.
.auto, .never_tail, .no_async => {
@@ -21597,32 +22787,19 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const args = try sema.resolveInst(extra.args);
const args_ty = sema.typeOf(args);
- if (!args_ty.isTuple() and args_ty.tag() != .empty_struct_literal) {
+ if (!args_ty.isTuple(mod) and args_ty.toIntern() != .empty_struct_type) {
return sema.fail(block, args_src, "expected a tuple, found '{}'", .{args_ty.fmt(sema.mod)});
}
- var resolved_args: []Air.Inst.Ref = undefined;
-
- // Desugar bound functions here
- var bound_arg_src: ?LazySrcLoc = null;
- if (sema.typeOf(func).tag() == .bound_fn) {
- bound_arg_src = func_src;
- const bound_func = try sema.resolveValue(block, .unneeded, func, "");
- const bound_data = &bound_func.cast(Value.Payload.BoundFn).?.data;
- func = bound_data.func_inst;
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount() + 1);
- resolved_args[0] = bound_data.arg0_inst;
- for (resolved_args[1..], 0..) |*resolved, i| {
- resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
- }
- } else {
- resolved_args = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount());
- for (resolved_args, 0..) |*resolved, i| {
- resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
- }
+ var resolved_args: []Air.Inst.Ref = try sema.arena.alloc(Air.Inst.Ref, args_ty.structFieldCount(mod));
+ for (resolved_args, 0..) |*resolved, i| {
+ resolved.* = try sema.tupleFieldValByIndex(block, args_src, args, @intCast(u32, i), args_ty);
}
+
+ const callee_ty = sema.typeOf(func);
+ const func_ty = try sema.checkCallArgumentCount(block, func, func_src, callee_ty, resolved_args.len, false);
const ensure_result_used = extra.flags.ensure_result_used;
- return sema.analyzeCall(block, func, func_src, call_src, modifier, ensure_result_used, resolved_args, bound_arg_src);
+ return sema.analyzeCall(block, func, func_ty, func_src, call_src, modifier, ensure_result_used, resolved_args, null, null);
}
fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
@@ -21634,19 +22811,21 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const ptr_src: LazySrcLoc = .{ .node_offset_builtin_call_arg2 = inst_data.src_node };
const parent_ty = try sema.resolveType(block, ty_src, extra.parent_type);
- const field_name = try sema.resolveConstString(block, name_src, extra.field_name, "field name must be comptime-known");
+ const field_name = try sema.resolveConstStringIntern(block, name_src, extra.field_name, "field name must be comptime-known");
const field_ptr = try sema.resolveInst(extra.field_ptr);
const field_ptr_ty = sema.typeOf(field_ptr);
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
- if (parent_ty.zigTypeTag() != .Struct and parent_ty.zigTypeTag() != .Union) {
+ if (parent_ty.zigTypeTag(mod) != .Struct and parent_ty.zigTypeTag(mod) != .Union) {
return sema.fail(block, ty_src, "expected struct or union type, found '{}'", .{parent_ty.fmt(sema.mod)});
}
try sema.resolveTypeLayout(parent_ty);
- const field_index = switch (parent_ty.zigTypeTag()) {
+ const field_index = switch (parent_ty.zigTypeTag(mod)) {
.Struct => blk: {
- if (parent_ty.isTuple()) {
- if (mem.eql(u8, field_name, "len")) {
+ if (parent_ty.isTuple(mod)) {
+ if (ip.stringEqlSlice(field_name, "len")) {
return sema.fail(block, src, "cannot get @fieldParentPtr of 'len' field of tuple", .{});
}
break :blk try sema.tupleFieldIndex(block, parent_ty, field_name, name_src);
@@ -21658,27 +22837,27 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
else => unreachable,
};
- if (parent_ty.zigTypeTag() == .Struct and parent_ty.structFieldIsComptime(field_index)) {
+ if (parent_ty.zigTypeTag(mod) == .Struct and parent_ty.structFieldIsComptime(field_index, mod)) {
return sema.fail(block, src, "cannot get @fieldParentPtr of a comptime field", .{});
}
try sema.checkPtrOperand(block, ptr_src, field_ptr_ty);
- const field_ptr_ty_info = field_ptr_ty.ptrInfo().data;
+ const field_ptr_ty_info = field_ptr_ty.ptrInfo(mod);
var ptr_ty_data: Type.Payload.Pointer.Data = .{
- .pointee_type = parent_ty.structFieldType(field_index),
+ .pointee_type = parent_ty.structFieldType(field_index, mod),
.mutable = field_ptr_ty_info.mutable,
.@"addrspace" = field_ptr_ty_info.@"addrspace",
};
- if (parent_ty.containerLayout() == .Packed) {
+ if (parent_ty.containerLayout(mod) == .Packed) {
return sema.fail(block, src, "TODO handle packed structs/unions with @fieldParentPtr", .{});
} else {
ptr_ty_data.@"align" = blk: {
- if (parent_ty.castTag(.@"struct")) |struct_obj| {
- break :blk struct_obj.data.fields.values()[field_index].abi_align;
- } else if (parent_ty.cast(Type.Payload.Union)) |union_obj| {
- break :blk union_obj.data.fields.values()[field_index].abi_align;
+ if (mod.typeToStruct(parent_ty)) |struct_obj| {
+ break :blk struct_obj.fields.values()[field_index].abi_align;
+ } else if (mod.typeToUnion(parent_ty)) |union_obj| {
+ break :blk union_obj.fields.values()[field_index].abi_align;
} else {
break :blk 0;
}
@@ -21692,19 +22871,24 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
const result_ptr = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
if (try sema.resolveDefinedValue(block, src, casted_field_ptr)) |field_ptr_val| {
- const payload = field_ptr_val.castTag(.field_ptr) orelse {
- return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
- };
- if (payload.data.field_index != field_index) {
+ const field = switch (ip.indexToKey(field_ptr_val.toIntern())) {
+ .ptr => |ptr| switch (ptr.addr) {
+ .field => |field| field,
+ else => null,
+ },
+ else => null,
+ } orelse return sema.fail(block, ptr_src, "pointer value not based on parent struct", .{});
+
+ if (field.index != field_index) {
const msg = msg: {
const msg = try sema.errMsg(
block,
src,
- "field '{s}' has index '{d}' but pointer value is index '{d}' of struct '{}'",
+ "field '{}' has index '{d}' but pointer value is index '{d}' of struct '{}'",
.{
- field_name,
+ field_name.fmt(ip),
field_index,
- payload.data.field_index,
+ field.index,
parent_ty.fmt(sema.mod),
},
);
@@ -21714,7 +22898,7 @@ fn zirFieldParentPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileEr
};
return sema.failWithOwnedErrorMsg(msg);
}
- return sema.addConstant(result_ptr, payload.data.container_ptr);
+ return sema.addConstant(result_ptr, field.base.toValue());
}
try sema.requireRuntimeBlock(block, src, ptr_src);
@@ -21746,69 +22930,267 @@ fn zirMinMax(
const rhs = try sema.resolveInst(extra.rhs);
try sema.checkNumericType(block, lhs_src, sema.typeOf(lhs));
try sema.checkNumericType(block, rhs_src, sema.typeOf(rhs));
- return sema.analyzeMinMax(block, src, lhs, rhs, air_tag, lhs_src, rhs_src);
+ return sema.analyzeMinMax(block, src, air_tag, &.{ lhs, rhs }, &.{ lhs_src, rhs_src });
+}
+
+fn zirMinMaxMulti(
+ sema: *Sema,
+ block: *Block,
+ extended: Zir.Inst.Extended.InstData,
+ comptime air_tag: Air.Inst.Tag,
+) CompileError!Air.Inst.Ref {
+ const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand);
+ const src_node = extra.data.src_node;
+ const src = LazySrcLoc.nodeOffset(src_node);
+ const operands = sema.code.refSlice(extra.end, extended.small);
+
+ const air_refs = try sema.arena.alloc(Air.Inst.Ref, operands.len);
+ const operand_srcs = try sema.arena.alloc(LazySrcLoc, operands.len);
+
+ for (operands, air_refs, operand_srcs, 0..) |zir_ref, *air_ref, *op_src, i| {
+ op_src.* = switch (i) {
+ 0 => .{ .node_offset_builtin_call_arg0 = src_node },
+ 1 => .{ .node_offset_builtin_call_arg1 = src_node },
+ 2 => .{ .node_offset_builtin_call_arg2 = src_node },
+ 3 => .{ .node_offset_builtin_call_arg3 = src_node },
+ 4 => .{ .node_offset_builtin_call_arg4 = src_node },
+ 5 => .{ .node_offset_builtin_call_arg5 = src_node },
+ else => src, // TODO: better source location
+ };
+ air_ref.* = try sema.resolveInst(zir_ref);
+ try sema.checkNumericType(block, op_src.*, sema.typeOf(air_ref.*));
+ }
+
+ return sema.analyzeMinMax(block, src, air_tag, air_refs, operand_srcs);
}
fn analyzeMinMax(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- lhs: Air.Inst.Ref,
- rhs: Air.Inst.Ref,
comptime air_tag: Air.Inst.Tag,
- lhs_src: LazySrcLoc,
- rhs_src: LazySrcLoc,
+ operands: []const Air.Inst.Ref,
+ operand_srcs: []const LazySrcLoc,
) CompileError!Air.Inst.Ref {
- const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
+ assert(operands.len == operand_srcs.len);
+ assert(operands.len > 0);
+ const mod = sema.mod;
- // TODO @max(max_int, undefined) should return max_int
+ if (operands.len == 1) return operands[0];
- const runtime_src = if (simd_op.lhs_val) |lhs_val| rs: {
- if (lhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
+ const opFunc = switch (air_tag) {
+ .min => Value.numberMin,
+ .max => Value.numberMax,
+ else => @compileError("unreachable"),
+ };
- const rhs_val = simd_op.rhs_val orelse break :rs rhs_src;
+ // The set of runtime-known operands. Set up in the loop below.
+ var runtime_known = try std.DynamicBitSet.initFull(sema.arena, operands.len);
+ // The current minmax value - initially this will always be comptime-known, then we'll add
+ // runtime values into the mix later.
+ var cur_minmax: ?Air.Inst.Ref = null;
+ var cur_minmax_src: LazySrcLoc = undefined; // defined if cur_minmax not null
+ // The current known scalar bounds of the value.
+ var bounds_status: enum {
+ unknown, // We've only seen undef comptime_ints so far, so do not know the bounds.
+ defined, // We've seen only integers, so the bounds are defined.
+ non_integral, // There are floats in the mix, so the bounds aren't defined.
+ } = .unknown;
+ var cur_min_scalar: Value = undefined;
+ var cur_max_scalar: Value = undefined;
+
+ // First, find all comptime-known arguments, and get their min/max
+
+ for (operands, operand_srcs, 0..) |operand, operand_src, operand_idx| {
+ // Resolve the value now to avoid redundant calls to `checkSimdBinOp` - we'll have to call
+ // it in the runtime path anyway since the result type may have been refined
+ const unresolved_uncoerced_val = try sema.resolveMaybeUndefVal(operand) orelse continue;
+ const uncoerced_val = try sema.resolveLazyValue(unresolved_uncoerced_val);
+
+ runtime_known.unset(operand_idx);
+
+ switch (bounds_status) {
+ .unknown, .defined => refine_bounds: {
+ const ty = sema.typeOf(operand);
+ if (!ty.scalarType(mod).isInt(mod) and !ty.scalarType(mod).eql(Type.comptime_int, mod)) {
+ bounds_status = .non_integral;
+ break :refine_bounds;
+ }
+ const scalar_bounds: ?[2]Value = bounds: {
+ if (!ty.isVector(mod)) break :bounds try uncoerced_val.intValueBounds(mod);
+ var cur_bounds: [2]Value = try Value.intValueBounds(try uncoerced_val.elemValue(mod, 0), mod) orelse break :bounds null;
+ const len = try sema.usizeCast(block, src, ty.vectorLen(mod));
+ for (1..len) |i| {
+ const elem = try uncoerced_val.elemValue(mod, i);
+ const elem_bounds = try elem.intValueBounds(mod) orelse break :bounds null;
+ cur_bounds = .{
+ Value.numberMin(elem_bounds[0], cur_bounds[0], mod),
+ Value.numberMax(elem_bounds[1], cur_bounds[1], mod),
+ };
+ }
+ break :bounds cur_bounds;
+ };
+ if (scalar_bounds) |bounds| {
+ if (bounds_status == .unknown) {
+ cur_min_scalar = bounds[0];
+ cur_max_scalar = bounds[1];
+ bounds_status = .defined;
+ } else {
+ cur_min_scalar = opFunc(cur_min_scalar, bounds[0], mod);
+ cur_max_scalar = opFunc(cur_max_scalar, bounds[1], mod);
+ }
+ }
+ },
+ .non_integral => {},
+ }
- if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
+ const cur = cur_minmax orelse {
+ cur_minmax = operand;
+ cur_minmax_src = operand_src;
+ continue;
+ };
- try sema.resolveLazyValue(lhs_val);
- try sema.resolveLazyValue(rhs_val);
+ const simd_op = try sema.checkSimdBinOp(block, src, cur, operand, cur_minmax_src, operand_src);
+ const cur_val = try sema.resolveLazyValue(simd_op.lhs_val.?); // cur_minmax is comptime-known
+ const operand_val = try sema.resolveLazyValue(simd_op.rhs_val.?); // we checked the operand was resolvable above
- const opFunc = switch (air_tag) {
- .min => Value.numberMin,
- .max => Value.numberMax,
- else => unreachable,
- };
- const target = sema.mod.getTarget();
const vec_len = simd_op.len orelse {
- const result_val = opFunc(lhs_val, rhs_val, target);
- return sema.addConstant(simd_op.result_ty, result_val);
+ const result_val = opFunc(cur_val, operand_val, mod);
+ cur_minmax = try sema.addConstant(simd_op.result_ty, result_val);
+ continue;
};
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const elems = try sema.arena.alloc(Value, vec_len);
+ const elems = try sema.arena.alloc(InternPool.Index, vec_len);
for (elems, 0..) |*elem, i| {
- const lhs_elem_val = lhs_val.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem_val = rhs_val.elemValueBuffer(sema.mod, i, &rhs_buf);
- elem.* = opFunc(lhs_elem_val, rhs_elem_val, target);
+ const lhs_elem_val = try cur_val.elemValue(mod, i);
+ const rhs_elem_val = try operand_val.elemValue(mod, i);
+ const uncoerced_elem = opFunc(lhs_elem_val, rhs_elem_val, mod);
+ elem.* = (try mod.getCoerced(uncoerced_elem, simd_op.scalar_ty)).toIntern();
}
- return sema.addConstant(
- simd_op.result_ty,
- try Value.Tag.aggregate.create(sema.arena, elems),
- );
- } else rs: {
- if (simd_op.rhs_val) |rhs_val| {
- if (rhs_val.isUndef()) return sema.addConstUndef(simd_op.result_ty);
+ cur_minmax = try sema.addConstant(simd_op.result_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = simd_op.result_ty.toIntern(),
+ .storage = .{ .elems = elems },
+ } })).toValue());
+ }
+
+ const opt_runtime_idx = runtime_known.findFirstSet();
+
+ if (cur_minmax) |ct_minmax_ref| refine: {
+ // Refine the comptime-known result type based on the bounds. This isn't strictly necessary
+ // in the runtime case, since we'll refine the type again later, but keeping things as small
+ // as possible will allow us to emit more optimal AIR (if all the runtime operands have
+ // smaller types than the non-refined comptime type).
+
+ const val = (try sema.resolveMaybeUndefVal(ct_minmax_ref)).?;
+ const orig_ty = sema.typeOf(ct_minmax_ref);
+
+ if (opt_runtime_idx == null and orig_ty.scalarType(mod).eql(Type.comptime_int, mod)) {
+ // If all arguments were `comptime_int`, and there are no runtime args, we'll preserve that type
+ break :refine;
}
- break :rs lhs_src;
- };
+ // We can't refine float types
+ if (orig_ty.scalarType(mod).isAnyFloat()) break :refine;
+
+ assert(bounds_status == .defined); // there was a non-comptime-int integral comptime-known arg
+
+ const refined_scalar_ty = try mod.intFittingRange(cur_min_scalar, cur_max_scalar);
+ const refined_ty = if (orig_ty.isVector(mod)) try mod.vectorType(.{
+ .len = orig_ty.vectorLen(mod),
+ .child = refined_scalar_ty.toIntern(),
+ }) else refined_scalar_ty;
+
+ // Apply the refined type to the current value
+ if (std.debug.runtime_safety) {
+ assert(try sema.intFitsInType(val, refined_ty, null));
+ }
+ cur_minmax = try sema.coerceInMemory(val, refined_ty);
+ }
+
+ const runtime_idx = opt_runtime_idx orelse return cur_minmax.?;
+ const runtime_src = operand_srcs[runtime_idx];
try sema.requireRuntimeBlock(block, src, runtime_src);
- return block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs);
+
+ // Now, iterate over runtime operands, emitting a min/max instruction for each. We'll refine the
+ // type again at the end, based on the comptime-known bound.
+
+ // If the comptime-known part is undef we can avoid emitting actual instructions later
+ const known_undef = if (cur_minmax) |operand| blk: {
+ const val = (try sema.resolveMaybeUndefVal(operand)).?;
+ break :blk val.isUndef(mod);
+ } else false;
+
+ if (cur_minmax == null) {
+ // No comptime operands - use the first operand as the starting value
+ assert(runtime_idx == 0);
+ cur_minmax = operands[0];
+ cur_minmax_src = runtime_src;
+ runtime_known.unset(0); // don't look at this operand in the loop below
+ const scalar_ty = sema.typeOf(cur_minmax.?).scalarType(mod);
+ if (scalar_ty.isInt(mod)) {
+ cur_min_scalar = try scalar_ty.minInt(mod, scalar_ty);
+ cur_max_scalar = try scalar_ty.maxInt(mod, scalar_ty);
+ }
+ }
+
+ var it = runtime_known.iterator(.{});
+ while (it.next()) |idx| {
+ const lhs = cur_minmax.?;
+ const lhs_src = cur_minmax_src;
+ const rhs = operands[idx];
+ const rhs_src = operand_srcs[idx];
+ const simd_op = try sema.checkSimdBinOp(block, src, lhs, rhs, lhs_src, rhs_src);
+ if (known_undef) {
+ cur_minmax = try sema.addConstUndef(simd_op.result_ty);
+ } else {
+ cur_minmax = try block.addBinOp(air_tag, simd_op.lhs, simd_op.rhs);
+ }
+ // Compute the bounds of this type
+ switch (bounds_status) {
+ .unknown, .defined => refine_bounds: {
+ const scalar_ty = sema.typeOf(rhs).scalarType(mod);
+ if (scalar_ty.isAnyFloat()) {
+ bounds_status = .non_integral;
+ break :refine_bounds;
+ }
+ const scalar_min = try scalar_ty.minInt(mod, scalar_ty);
+ const scalar_max = try scalar_ty.maxInt(mod, scalar_ty);
+ if (bounds_status == .unknown) {
+ cur_min_scalar = scalar_min;
+ cur_max_scalar = scalar_max;
+ bounds_status = .defined;
+ } else {
+ cur_min_scalar = opFunc(cur_min_scalar, scalar_min, mod);
+ cur_max_scalar = opFunc(cur_max_scalar, scalar_max, mod);
+ }
+ },
+ .non_integral => {},
+ }
+ }
+
+ // Finally, refine the type based on the known bounds.
+ const unrefined_ty = sema.typeOf(cur_minmax.?);
+ if (unrefined_ty.scalarType(mod).isAnyFloat()) {
+ // We can't refine floats, so we're done.
+ return cur_minmax.?;
+ }
+ assert(bounds_status == .defined); // there were integral runtime operands
+ const refined_scalar_ty = try mod.intFittingRange(cur_min_scalar, cur_max_scalar);
+ const refined_ty = if (unrefined_ty.isVector(mod)) try mod.vectorType(.{
+ .len = unrefined_ty.vectorLen(mod),
+ .child = refined_scalar_ty.toIntern(),
+ }) else refined_scalar_ty;
+
+ if (!refined_ty.eql(unrefined_ty, mod)) {
+ // We've reduced the type - cast the result down
+ return block.addTyOp(.intcast, refined_ty, cur_minmax.?);
+ }
+
+ return cur_minmax.?;
}
fn upgradeToArrayPtr(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, len: u64) !Air.Inst.Ref {
const mod = sema.mod;
- const info = sema.typeOf(ptr).ptrInfo().data;
+ const info = sema.typeOf(ptr).ptrInfo(mod);
if (info.size == .One) {
// Already an array pointer.
return ptr;
@@ -21837,19 +23219,26 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const src_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = inst_data.src_node };
const dest_ptr = try sema.resolveInst(extra.lhs);
const src_ptr = try sema.resolveInst(extra.rhs);
+ const dest_ty = sema.typeOf(dest_ptr);
+ const src_ty = sema.typeOf(src_ptr);
const dest_len = try indexablePtrLenOrNone(sema, block, dest_src, dest_ptr);
const src_len = try indexablePtrLenOrNone(sema, block, src_src, src_ptr);
const target = sema.mod.getTarget();
+ const mod = sema.mod;
+
+ if (dest_ty.isConstPtr(mod)) {
+ return sema.fail(block, dest_src, "cannot memcpy to constant pointer", .{});
+ }
if (dest_len == .none and src_len == .none) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "unknown @memcpy length", .{});
errdefer msg.destroy(sema.gpa);
- try sema.errNote(block, dest_src, msg, "destination type {} provides no length", .{
- sema.typeOf(dest_ptr).fmt(sema.mod),
+ try sema.errNote(block, dest_src, msg, "destination type '{}' provides no length", .{
+ dest_ty.fmt(sema.mod),
});
- try sema.errNote(block, src_src, msg, "source type {} provides no length", .{
- sema.typeOf(src_ptr).fmt(sema.mod),
+ try sema.errNote(block, src_src, msg, "source type '{}' provides no length", .{
+ src_ty.fmt(sema.mod),
});
break :msg msg;
};
@@ -21887,16 +23276,24 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const ok = try block.addBinOp(.cmp_eq, dest_len, src_len);
try sema.addSafetyCheck(block, ok, .memcpy_len_mismatch);
}
+ } else if (dest_len != .none) {
+ if (try sema.resolveDefinedValue(block, dest_src, dest_len)) |dest_len_val| {
+ len_val = dest_len_val;
+ }
+ } else if (src_len != .none) {
+ if (try sema.resolveDefinedValue(block, src_src, src_len)) |src_len_val| {
+ len_val = src_len_val;
+ }
}
const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |dest_ptr_val| rs: {
- if (!dest_ptr_val.isComptimeMutablePtr()) break :rs dest_src;
+ if (!dest_ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;
if (try sema.resolveDefinedValue(block, src_src, src_ptr)) |_| {
- const len_u64 = (try len_val.?.getUnsignedIntAdvanced(target, sema)).?;
+ const len_u64 = (try len_val.?.getUnsignedIntAdvanced(mod, sema)).?;
const len = try sema.usizeCast(block, dest_src, len_u64);
for (0..len) |i| {
const elem_index = try sema.addIntUnsigned(Type.usize, i);
- const dest_elem_ptr = try sema.elemPtr(
+ const dest_elem_ptr = try sema.elemPtrOneLayerOnly(
block,
src,
dest_ptr,
@@ -21905,7 +23302,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
true, // init
false, // oob_safety
);
- const src_elem_ptr = try sema.elemPtr(
+ const src_elem_ptr = try sema.elemPtrOneLayerOnly(
block,
src,
src_ptr,
@@ -21929,21 +23326,18 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
} else break :rs src_src;
} else dest_src;
- const dest_ty = sema.typeOf(dest_ptr);
- const src_ty = sema.typeOf(src_ptr);
-
// If in-memory coercion is not allowed, explode this memcpy call into a
// for loop that copies element-wise.
// Likewise if this is an iterable rather than a pointer, do the same
// lowering. The AIR instruction requires pointers with element types of
// equal ABI size.
- if (dest_ty.zigTypeTag() != .Pointer or src_ty.zigTypeTag() != .Pointer) {
+ if (dest_ty.zigTypeTag(mod) != .Pointer or src_ty.zigTypeTag(mod) != .Pointer) {
return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the source or destination iterable is a tuple", .{});
}
- const dest_elem_ty = dest_ty.elemType2();
- const src_elem_ty = src_ty.elemType2();
+ const dest_elem_ty = dest_ty.elemType2(mod);
+ const src_elem_ty = src_ty.elemType2(mod);
if (.ok != try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, true, target, dest_src, src_src)) {
return sema.fail(block, src, "TODO: lower @memcpy to a for loop because the element types have different ABI sizes", .{});
}
@@ -21954,7 +23348,7 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
var new_dest_ptr = dest_ptr;
var new_src_ptr = src_ptr;
if (len_val) |val| {
- const len = val.toUnsignedInt(target);
+ const len = val.toUnsignedInt(mod);
if (len == 0) {
// This AIR instruction guarantees length > 0 if it is comptime-known.
return;
@@ -21967,7 +23361,15 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
// Change the src from slice to a many pointer, to avoid multiple ptr
// slice extractions in AIR instructions.
const new_src_ptr_ty = sema.typeOf(new_src_ptr);
- if (new_src_ptr_ty.isSlice()) {
+ if (new_src_ptr_ty.isSlice(mod)) {
+ new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
+ }
+ } else if (dest_len == .none and len_val == null) {
+ // Change the dest to a slice, since its type must have the length.
+ const dest_ptr_ptr = try sema.analyzeRef(block, dest_src, new_dest_ptr);
+ new_dest_ptr = try sema.analyzeSlice(block, dest_src, dest_ptr_ptr, .zero, src_len, .none, .unneeded, dest_src, dest_src, dest_src, false);
+ const new_src_ptr_ty = sema.typeOf(new_src_ptr);
+ if (new_src_ptr_ty.isSlice(mod)) {
new_src_ptr = try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty);
}
}
@@ -21986,14 +23388,30 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
// Extract raw pointer from dest slice. The AIR instructions could support them, but
// it would cause redundant machine code instructions.
const new_dest_ptr_ty = sema.typeOf(new_dest_ptr);
- const raw_dest_ptr = if (new_dest_ptr_ty.isSlice())
+ const raw_dest_ptr = if (new_dest_ptr_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, dest_src, new_dest_ptr, new_dest_ptr_ty)
- else
- new_dest_ptr;
+ else if (new_dest_ptr_ty.ptrSize(mod) == .One) ptr: {
+ var dest_manyptr_ty_key = mod.intern_pool.indexToKey(new_dest_ptr_ty.toIntern()).ptr_type;
+ assert(dest_manyptr_ty_key.flags.size == .One);
+ dest_manyptr_ty_key.child = dest_elem_ty.toIntern();
+ dest_manyptr_ty_key.flags.size = .Many;
+ break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(dest_manyptr_ty_key), new_dest_ptr, dest_src);
+ } else new_dest_ptr;
+
+ const new_src_ptr_ty = sema.typeOf(new_src_ptr);
+ const raw_src_ptr = if (new_src_ptr_ty.isSlice(mod))
+ try sema.analyzeSlicePtr(block, src_src, new_src_ptr, new_src_ptr_ty)
+ else if (new_src_ptr_ty.ptrSize(mod) == .One) ptr: {
+ var src_manyptr_ty_key = mod.intern_pool.indexToKey(new_src_ptr_ty.toIntern()).ptr_type;
+ assert(src_manyptr_ty_key.flags.size == .One);
+ src_manyptr_ty_key.child = src_elem_ty.toIntern();
+ src_manyptr_ty_key.flags.size = .Many;
+ break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(src_manyptr_ty_key), new_src_ptr, src_src);
+ } else new_src_ptr;
// ok1: dest >= src + len
// ok2: src >= dest + len
- const src_plus_len = try sema.analyzePtrArithmetic(block, src, new_src_ptr, len, .ptr_add, src_src, src);
+ const src_plus_len = try sema.analyzePtrArithmetic(block, src, raw_src_ptr, len, .ptr_add, src_src, src);
const dest_plus_len = try sema.analyzePtrArithmetic(block, src, raw_dest_ptr, len, .ptr_add, dest_src, src);
const ok1 = try block.addBinOp(.cmp_gte, raw_dest_ptr, src_plus_len);
const ok2 = try block.addBinOp(.cmp_gte, new_src_ptr, dest_plus_len);
@@ -22011,6 +23429,9 @@ fn zirMemcpy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
}
fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const src = inst_data.src();
@@ -22019,23 +23440,26 @@ fn zirMemset(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void
const dest_ptr = try sema.resolveInst(extra.lhs);
const uncoerced_elem = try sema.resolveInst(extra.rhs);
const dest_ptr_ty = sema.typeOf(dest_ptr);
- try checkIndexable(sema, block, dest_src, dest_ptr_ty);
+ try checkMemOperand(sema, block, dest_src, dest_ptr_ty);
- const dest_elem_ty = dest_ptr_ty.elemType2();
- const target = sema.mod.getTarget();
+ if (dest_ptr_ty.isConstPtr(mod)) {
+ return sema.fail(block, dest_src, "cannot memset constant pointer", .{});
+ }
+
+ const dest_elem_ty = dest_ptr_ty.elemType2(mod);
const runtime_src = if (try sema.resolveDefinedValue(block, dest_src, dest_ptr)) |ptr_val| rs: {
- const len_air_ref = try sema.fieldVal(block, src, dest_ptr, "len", dest_src);
+ const len_air_ref = try sema.fieldVal(block, src, dest_ptr, try ip.getOrPutString(gpa, "len"), dest_src);
const len_val = (try sema.resolveDefinedValue(block, dest_src, len_air_ref)) orelse
break :rs dest_src;
- const len_u64 = (try len_val.getUnsignedIntAdvanced(target, sema)).?;
+ const len_u64 = (try len_val.getUnsignedIntAdvanced(mod, sema)).?;
const len = try sema.usizeCast(block, dest_src, len_u64);
if (len == 0) {
// This AIR instruction guarantees length > 0 if it is comptime-known.
return;
}
- if (!ptr_val.isComptimeMutablePtr()) break :rs dest_src;
+ if (!ptr_val.isComptimeMutablePtr(mod)) break :rs dest_src;
if (try sema.resolveMaybeUndefVal(uncoerced_elem)) |_| {
for (0..len) |i| {
const elem_index = try sema.addIntUnsigned(Type.usize, i);
@@ -22113,6 +23537,7 @@ fn zirVarExtended(
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.ExtendedVar, extended.operand);
const ty_src: LazySrcLoc = .{ .node_offset_var_decl_ty = 0 };
const init_src: LazySrcLoc = .{ .node_offset_var_decl_init = 0 };
@@ -22148,47 +23573,33 @@ fn zirVarExtended(
else
uncasted_init;
- break :blk (try sema.resolveMaybeUndefVal(init)) orelse
- return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known");
- } else Value.initTag(.unreachable_value);
+ break :blk ((try sema.resolveMaybeUndefVal(init)) orelse
+ return sema.failWithNeededComptime(block, init_src, "container level variable initializers must be comptime-known")).toIntern();
+ } else .none;
try sema.validateVarType(block, ty_src, var_ty, small.is_extern);
- const new_var = try sema.gpa.create(Module.Var);
- errdefer sema.gpa.destroy(new_var);
-
- log.debug("created variable {*} owner_decl: {*} ({s})", .{
- new_var, sema.owner_decl, sema.owner_decl.name,
- });
-
- new_var.* = .{
- .owner_decl = sema.owner_decl_index,
+ return sema.addConstant(var_ty, (try mod.intern(.{ .variable = .{
+ .ty = var_ty.toIntern(),
.init = init_val,
+ .decl = sema.owner_decl_index,
+ .lib_name = if (lib_name) |lname| (try mod.intern_pool.getOrPutString(
+ sema.gpa,
+ try sema.handleExternLibName(block, ty_src, lname),
+ )).toOptional() else .none,
.is_extern = small.is_extern,
- .is_mutable = true,
.is_threadlocal = small.is_threadlocal,
- .is_weak_linkage = false,
- .lib_name = null,
- };
-
- if (lib_name) |lname| {
- new_var.lib_name = try sema.handleExternLibName(block, ty_src, lname);
- }
-
- const result = try sema.addConstant(
- var_ty,
- try Value.Tag.variable.create(sema.arena, new_var),
- );
- return result;
+ } })).toValue());
}
fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref {
const tracy = trace(@src());
defer tracy.end();
+ const mod = sema.mod;
const inst_data = sema.code.instructions.items(.data)[inst].pl_node;
const extra = sema.code.extraData(Zir.Inst.FuncFancy, inst_data.payload_index);
- const target = sema.mod.getTarget();
+ const target = mod.getTarget();
const align_src: LazySrcLoc = .{ .node_offset_fn_type_align = inst_data.src_node };
const addrspace_src: LazySrcLoc = .{ .node_offset_fn_type_addrspace = inst_data.src_node };
@@ -22219,10 +23630,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
extra_index += body.len;
const val = try sema.resolveGenericBody(block, align_src, body, inst, Type.u29, "alignment must be comptime-known");
- if (val.tag() == .generic_poison) {
+ if (val.isGenericPoison()) {
break :blk null;
}
- const alignment = @intCast(u32, val.toUnsignedInt(target));
+ const alignment = @intCast(u32, val.toUnsignedInt(mod));
try sema.validateAlign(block, align_src, alignment);
if (alignment == target_util.defaultFunctionAlignment(target)) {
break :blk 0;
@@ -22238,7 +23649,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
},
else => |e| return e,
};
- const alignment = @intCast(u32, align_tv.val.toUnsignedInt(target));
+ const alignment = @intCast(u32, align_tv.val.toUnsignedInt(mod));
try sema.validateAlign(block, align_src, alignment);
if (alignment == target_util.defaultFunctionAlignment(target)) {
break :blk 0;
@@ -22255,10 +23666,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const addrspace_ty = try sema.getBuiltinType("AddressSpace");
const val = try sema.resolveGenericBody(block, addrspace_src, body, inst, addrspace_ty, "addrespace must be comptime-known");
- if (val.tag() == .generic_poison) {
+ if (val.isGenericPoison()) {
break :blk null;
}
- break :blk val.toEnum(std.builtin.AddressSpace);
+ break :blk mod.toEnum(std.builtin.AddressSpace, val);
} else if (extra.data.bits.has_addrspace_ref) blk: {
const addrspace_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
@@ -22268,7 +23679,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
},
else => |e| return e,
};
- break :blk addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+ break :blk mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
} else target_util.defaultAddressSpace(target, .function);
const @"linksection": FuncLinkSection = if (extra.data.bits.has_section_body) blk: {
@@ -22277,16 +23688,16 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const body = sema.code.extra[extra_index..][0..body_len];
extra_index += body.len;
- const ty = Type.initTag(.const_slice_u8);
+ const ty = Type.slice_const_u8;
const val = try sema.resolveGenericBody(block, section_src, body, inst, ty, "linksection must be comptime-known");
- if (val.tag() == .generic_poison) {
+ if (val.isGenericPoison()) {
break :blk FuncLinkSection{ .generic = {} };
}
- break :blk FuncLinkSection{ .explicit = try val.toAllocatedBytes(ty, sema.arena, sema.mod) };
+ break :blk FuncLinkSection{ .explicit = try val.toIpString(ty, mod) };
} else if (extra.data.bits.has_section_ref) blk: {
const section_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
- const section_name = sema.resolveConstString(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) {
+ const section_name = sema.resolveConstStringIntern(block, section_src, section_ref, "linksection must be comptime-known") catch |err| switch (err) {
error.GenericPoison => {
break :blk FuncLinkSection{ .generic = {} };
},
@@ -22303,10 +23714,10 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const cc_ty = try sema.getBuiltinType("CallingConvention");
const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, "calling convention must be comptime-known");
- if (val.tag() == .generic_poison) {
+ if (val.isGenericPoison()) {
break :blk null;
}
- break :blk val.toEnum(std.builtin.CallingConvention);
+ break :blk mod.toEnum(std.builtin.CallingConvention, val);
} else if (extra.data.bits.has_cc_ref) blk: {
const cc_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
@@ -22316,7 +23727,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
},
else => |e| return e,
};
- break :blk cc_tv.val.toEnum(std.builtin.CallingConvention);
+ break :blk mod.toEnum(std.builtin.CallingConvention, cc_tv.val);
} else if (sema.owner_decl.is_exported and has_body)
.C
else
@@ -22329,20 +23740,18 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
extra_index += body.len;
const val = try sema.resolveGenericBody(block, ret_src, body, inst, Type.type, "return type must be comptime-known");
- var buffer: Value.ToTypeBuffer = undefined;
- const ty = try val.toType(&buffer).copy(sema.arena);
+ const ty = val.toType();
break :blk ty;
} else if (extra.data.bits.has_ret_ty_ref) blk: {
const ret_ty_ref = @intToEnum(Zir.Inst.Ref, sema.code.extra[extra_index]);
extra_index += 1;
const ret_ty_tv = sema.resolveInstConst(block, ret_src, ret_ty_ref, "return type must be comptime-known") catch |err| switch (err) {
error.GenericPoison => {
- break :blk Type.initTag(.generic_poison);
+ break :blk Type.generic_poison;
},
else => |e| return e,
};
- var buffer: Value.ToTypeBuffer = undefined;
- const ty = try ret_ty_tv.val.toType(&buffer).copy(sema.arena);
+ const ty = ret_ty_tv.val.toType();
break :blk ty;
} else Type.void;
@@ -22414,13 +23823,14 @@ fn zirCDefine(
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const name_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const val_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
const name = try sema.resolveConstString(block, name_src, extra.lhs, "name of macro being undefined must be comptime-known");
const rhs = try sema.resolveInst(extra.rhs);
- if (sema.typeOf(rhs).zigTypeTag() != .Void) {
+ if (sema.typeOf(rhs).zigTypeTag(mod) != .Void) {
const value = try sema.resolveConstString(block, val_src, extra.rhs, "value of macro being undefined must be comptime-known");
try block.c_import_buf.?.writer().print("#define {s} {s}\n", .{ name, value });
} else {
@@ -22486,27 +23896,29 @@ fn resolvePrefetchOptions(
src: LazySrcLoc,
zir_ref: Zir.Inst.Ref,
) CompileError!std.builtin.PrefetchOptions {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const options_ty = try sema.getBuiltinType("PrefetchOptions");
const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
- const target = sema.mod.getTarget();
const rw_src = sema.maybeOptionsSrc(block, src, "rw");
const locality_src = sema.maybeOptionsSrc(block, src, "locality");
const cache_src = sema.maybeOptionsSrc(block, src, "cache");
- const rw = try sema.fieldVal(block, src, options, "rw", rw_src);
+ const rw = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "rw"), rw_src);
const rw_val = try sema.resolveConstValue(block, rw_src, rw, "prefetch read/write must be comptime-known");
- const locality = try sema.fieldVal(block, src, options, "locality", locality_src);
+ const locality = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "locality"), locality_src);
const locality_val = try sema.resolveConstValue(block, locality_src, locality, "prefetch locality must be comptime-known");
- const cache = try sema.fieldVal(block, src, options, "cache", cache_src);
+ const cache = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "cache"), cache_src);
const cache_val = try sema.resolveConstValue(block, cache_src, cache, "prefetch cache must be comptime-known");
return std.builtin.PrefetchOptions{
- .rw = rw_val.toEnum(std.builtin.PrefetchOptions.Rw),
- .locality = @intCast(u2, locality_val.toUnsignedInt(target)),
- .cache = cache_val.toEnum(std.builtin.PrefetchOptions.Cache),
+ .rw = mod.toEnum(std.builtin.PrefetchOptions.Rw, rw_val),
+ .locality = @intCast(u2, locality_val.toUnsignedInt(mod)),
+ .cache = mod.toEnum(std.builtin.PrefetchOptions.Cache, cache_val),
};
}
@@ -22549,36 +23961,42 @@ fn resolveExternOptions(
block: *Block,
src: LazySrcLoc,
zir_ref: Zir.Inst.Ref,
-) CompileError!std.builtin.ExternOptions {
+) CompileError!struct {
+ name: InternPool.NullTerminatedString,
+ library_name: InternPool.OptionalNullTerminatedString = .none,
+ linkage: std.builtin.GlobalLinkage = .Strong,
+ is_thread_local: bool = false,
+} {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
const options_inst = try sema.resolveInst(zir_ref);
const extern_options_ty = try sema.getBuiltinType("ExternOptions");
const options = try sema.coerce(block, extern_options_ty, options_inst, src);
- const mod = sema.mod;
const name_src = sema.maybeOptionsSrc(block, src, "name");
const library_src = sema.maybeOptionsSrc(block, src, "library");
const linkage_src = sema.maybeOptionsSrc(block, src, "linkage");
const thread_local_src = sema.maybeOptionsSrc(block, src, "thread_local");
- const name_ref = try sema.fieldVal(block, src, options, "name", name_src);
+ const name_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "name"), name_src);
const name_val = try sema.resolveConstValue(block, name_src, name_ref, "name of the extern symbol must be comptime-known");
- const name = try name_val.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod);
+ const name = try name_val.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
- const library_name_inst = try sema.fieldVal(block, src, options, "library_name", library_src);
+ const library_name_inst = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "library_name"), library_src);
const library_name_val = try sema.resolveConstValue(block, library_src, library_name_inst, "library in which extern symbol is must be comptime-known");
- const linkage_ref = try sema.fieldVal(block, src, options, "linkage", linkage_src);
+ const linkage_ref = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "linkage"), linkage_src);
const linkage_val = try sema.resolveConstValue(block, linkage_src, linkage_ref, "linkage of the extern symbol must be comptime-known");
- const linkage = linkage_val.toEnum(std.builtin.GlobalLinkage);
+ const linkage = mod.toEnum(std.builtin.GlobalLinkage, linkage_val);
- const is_thread_local = try sema.fieldVal(block, src, options, "is_thread_local", thread_local_src);
+ const is_thread_local = try sema.fieldVal(block, src, options, try ip.getOrPutString(gpa, "is_thread_local"), thread_local_src);
const is_thread_local_val = try sema.resolveConstValue(block, thread_local_src, is_thread_local, "threadlocality of the extern symbol must be comptime-known");
- const library_name = if (!library_name_val.isNull()) blk: {
- const payload = library_name_val.castTag(.opt_payload).?.data;
- const library_name = try payload.toAllocatedBytes(Type.initTag(.const_slice_u8), sema.arena, mod);
+ const library_name = if (library_name_val.optionalValue(mod)) |payload| blk: {
+ const library_name = try payload.toAllocatedBytes(Type.slice_const_u8, sema.arena, mod);
if (library_name.len == 0) {
- return sema.fail(block, library_src, "library name name cannot be empty", .{});
+ return sema.fail(block, library_src, "library name cannot be empty", .{});
}
break :blk try sema.handleExternLibName(block, library_src, library_name);
} else null;
@@ -22591,9 +24009,9 @@ fn resolveExternOptions(
return sema.fail(block, linkage_src, "extern symbol must use strong or weak linkage", .{});
}
- return std.builtin.ExternOptions{
- .name = name,
- .library_name = library_name,
+ return .{
+ .name = try ip.getOrPutString(gpa, name),
+ .library_name = try ip.getOrPutStringOpt(gpa, library_name),
.linkage = linkage,
.is_thread_local = is_thread_local_val.toBool(),
};
@@ -22604,14 +24022,25 @@ fn zirBuiltinExtern(
block: *Block,
extended: Zir.Inst.Extended.InstData,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const extra = sema.code.extraData(Zir.Inst.BinNode, extended.operand).data;
const ty_src: LazySrcLoc = .{ .node_offset_builtin_call_arg0 = extra.node };
const options_src: LazySrcLoc = .{ .node_offset_builtin_call_arg1 = extra.node };
var ty = try sema.resolveType(block, ty_src, extra.lhs);
- if (!ty.isPtrAtRuntime()) {
+ if (!ty.isPtrAtRuntime(mod)) {
return sema.fail(block, ty_src, "expected (optional) pointer", .{});
}
+ if (!try sema.validateExternType(ty.childType(mod), .other)) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, ty_src, "extern symbol cannot have type '{}'", .{ty.fmt(mod)});
+ errdefer msg.destroy(sema.gpa);
+ const src_decl = sema.mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, ty_src.toSrcLoc(src_decl, mod), ty, .other);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
const options = sema.resolveExternOptions(block, .unneeded, extra.rhs) catch |err| switch (err) {
error.NeededSourceLocation => {
@@ -22621,52 +24050,51 @@ fn zirBuiltinExtern(
else => |e| return e,
};
- if (options.linkage == .Weak and !ty.ptrAllowsZero()) {
- ty = try Type.optional(sema.arena, ty);
+ if (options.linkage == .Weak and !ty.ptrAllowsZero(mod)) {
+ ty = try Type.optional(sema.arena, ty, mod);
}
// TODO check duplicate extern
- const new_decl_index = try sema.mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null);
- errdefer sema.mod.destroyDecl(new_decl_index);
- const new_decl = sema.mod.declPtr(new_decl_index);
- new_decl.name = try sema.gpa.dupeZ(u8, options.name);
+ const new_decl_index = try mod.allocateNewDecl(sema.owner_decl.src_namespace, sema.owner_decl.src_node, null);
+ errdefer mod.destroyDecl(new_decl_index);
+ const new_decl = mod.declPtr(new_decl_index);
+ new_decl.name = options.name;
{
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
-
- const new_var = try new_decl_arena_allocator.create(Module.Var);
- new_var.* = .{
- .owner_decl = sema.owner_decl_index,
- .init = Value.initTag(.unreachable_value),
+ const new_var = try mod.intern(.{ .variable = .{
+ .ty = ty.toIntern(),
+ .init = .none,
+ .decl = sema.owner_decl_index,
.is_extern = true,
- .is_mutable = false,
+ .is_const = true,
.is_threadlocal = options.is_thread_local,
.is_weak_linkage = options.linkage == .Weak,
- .lib_name = null,
- };
+ } });
new_decl.src_line = sema.owner_decl.src_line;
// We only access this decl through the decl_ref with the correct type created
// below, so this type doesn't matter
- new_decl.ty = Type.Tag.init(.anyopaque);
- new_decl.val = try Value.Tag.variable.create(new_decl_arena_allocator, new_var);
+ new_decl.ty = ty;
+ new_decl.val = new_var.toValue();
new_decl.@"align" = 0;
- new_decl.@"linksection" = null;
+ new_decl.@"linksection" = .none;
new_decl.has_tv = true;
new_decl.analysis = .complete;
- new_decl.generation = sema.mod.generation;
-
- try new_decl.finalizeNewArena(&new_decl_arena);
+ new_decl.generation = mod.generation;
}
- try sema.mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
+ try mod.declareDeclDependency(sema.owner_decl_index, new_decl_index);
try sema.ensureDeclAnalyzed(new_decl_index);
- const ref = try Value.Tag.decl_ref.create(sema.arena, new_decl_index);
- return sema.addConstant(ty, ref);
+ return sema.addConstant(ty, try mod.getCoerced((try mod.intern(.{ .ptr = .{
+ .ty = switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .ptr_type => ty.toIntern(),
+ .opt_type => |child_type| child_type,
+ else => unreachable,
+ },
+ .addr = .{ .decl = new_decl_index },
+ } })).toValue(), ty));
}
fn zirWorkItem(
@@ -22743,17 +24171,27 @@ fn validateVarType(
var_ty: Type,
is_extern: bool,
) CompileError!void {
- if (try sema.validateRunTimeType(var_ty, is_extern)) return;
-
const mod = sema.mod;
+ if (is_extern and !try sema.validateExternType(var_ty, .other)) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "extern variable cannot have type '{}'", .{var_ty.fmt(mod)});
+ errdefer msg.destroy(sema.gpa);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsNotExtern(msg, src.toSrcLoc(src_decl, mod), var_ty, .other);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+
+ if (try sema.validateRunTimeType(var_ty, is_extern)) return;
const msg = msg: {
const msg = try sema.errMsg(block, src, "variable of type '{}' must be const or comptime", .{var_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
const src_decl = mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsComptime(block, src, msg, src.toSrcLoc(src_decl), var_ty);
- if (var_ty.zigTypeTag() == .ComptimeInt or var_ty.zigTypeTag() == .ComptimeFloat) {
+ try sema.explainWhyTypeIsComptime(msg, src.toSrcLoc(src_decl, mod), var_ty);
+ if (var_ty.zigTypeTag(mod) == .ComptimeInt or var_ty.zigTypeTag(mod) == .ComptimeFloat) {
try sema.errNote(block, src, msg, "to modify this variable at runtime, it must be given an explicit fixed-size number type", .{});
}
@@ -22767,8 +24205,9 @@ fn validateRunTimeType(
var_ty: Type,
is_extern: bool,
) CompileError!bool {
+ const mod = sema.mod;
var ty = var_ty;
- while (true) switch (ty.zigTypeTag()) {
+ while (true) switch (ty.zigTypeTag(mod)) {
.Bool,
.Int,
.Float,
@@ -22791,23 +24230,22 @@ fn validateRunTimeType(
=> return false,
.Pointer => {
- const elem_ty = ty.childType();
- switch (elem_ty.zigTypeTag()) {
+ const elem_ty = ty.childType(mod);
+ switch (elem_ty.zigTypeTag(mod)) {
.Opaque => return true,
- .Fn => return elem_ty.isFnOrHasRuntimeBits(),
+ .Fn => return elem_ty.isFnOrHasRuntimeBits(mod),
else => ty = elem_ty,
}
},
.Opaque => return is_extern,
.Optional => {
- var buf: Type.Payload.ElemType = undefined;
- const child_ty = ty.optionalChild(&buf);
+ const child_ty = ty.optionalChild(mod);
return sema.validateRunTimeType(child_ty, is_extern);
},
- .Array, .Vector => ty = ty.elemType(),
+ .Array, .Vector => ty = ty.childType(mod),
- .ErrorUnion => ty = ty.errorUnionPayload(),
+ .ErrorUnion => ty = ty.errorUnionPayload(mod),
.Struct, .Union => {
const resolved_ty = try sema.resolveTypeFields(ty);
@@ -22817,12 +24255,10 @@ fn validateRunTimeType(
};
}
-const TypeSet = std.HashMapUnmanaged(Type, void, Type.HashContext64, std.hash_map.default_max_load_percentage);
+const TypeSet = std.AutoHashMapUnmanaged(InternPool.Index, void);
fn explainWhyTypeIsComptime(
sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
msg: *Module.ErrorMsg,
src_loc: Module.SrcLoc,
ty: Type,
@@ -22831,20 +24267,18 @@ fn explainWhyTypeIsComptime(
defer type_set.deinit(sema.gpa);
try sema.resolveTypeFully(ty);
- return sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty, &type_set);
+ return sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty, &type_set);
}
fn explainWhyTypeIsComptimeInner(
sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
msg: *Module.ErrorMsg,
src_loc: Module.SrcLoc,
ty: Type,
type_set: *TypeSet,
) CompileError!void {
const mod = sema.mod;
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Bool,
.Int,
.Float,
@@ -22878,12 +24312,12 @@ fn explainWhyTypeIsComptimeInner(
},
.Array, .Vector => {
- try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
+ try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set);
},
.Pointer => {
- const elem_ty = ty.elemType2();
- if (elem_ty.zigTypeTag() == .Fn) {
- const fn_info = elem_ty.fnInfo();
+ const elem_ty = ty.elemType2(mod);
+ if (elem_ty.zigTypeTag(mod) == .Fn) {
+ const fn_info = mod.typeToFunc(elem_ty).?;
if (fn_info.is_generic) {
try mod.errNoteNonLazy(src_loc, msg, "function is generic", .{});
}
@@ -22891,36 +24325,34 @@ fn explainWhyTypeIsComptimeInner(
.Inline => try mod.errNoteNonLazy(src_loc, msg, "function has inline calling convention", .{}),
else => {},
}
- if (fn_info.return_type.comptimeOnly()) {
+ if (fn_info.return_type.toType().comptimeOnly(mod)) {
try mod.errNoteNonLazy(src_loc, msg, "function has a comptime-only return type", .{});
}
return;
}
- try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.elemType(), type_set);
+ try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.childType(mod), type_set);
},
.Optional => {
- var buf: Type.Payload.ElemType = undefined;
- try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.optionalChild(&buf), type_set);
+ try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.optionalChild(mod), type_set);
},
.ErrorUnion => {
- try sema.explainWhyTypeIsComptimeInner(block, src, msg, src_loc, ty.errorUnionPayload(), type_set);
+ try sema.explainWhyTypeIsComptimeInner(msg, src_loc, ty.errorUnionPayload(mod), type_set);
},
.Struct => {
- if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
+ if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
- if (ty.castTag(.@"struct")) |payload| {
- const struct_obj = payload.data;
+ if (mod.typeToStruct(ty)) |struct_obj| {
for (struct_obj.fields.values(), 0..) |field, i| {
- const field_src_loc = struct_obj.fieldSrcLoc(sema.mod, .{
+ const field_src_loc = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = i,
.range = .type,
});
if (try sema.typeRequiresComptime(field.ty)) {
try mod.errNoteNonLazy(field_src_loc, msg, "struct requires comptime because of this field", .{});
- try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
+ try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set);
}
}
}
@@ -22928,19 +24360,18 @@ fn explainWhyTypeIsComptimeInner(
},
.Union => {
- if ((try type_set.getOrPutContext(sema.gpa, ty, .{ .mod = mod })).found_existing) return;
+ if ((try type_set.getOrPut(sema.gpa, ty.toIntern())).found_existing) return;
- if (ty.cast(Type.Payload.Union)) |payload| {
- const union_obj = payload.data;
+ if (mod.typeToUnion(ty)) |union_obj| {
for (union_obj.fields.values(), 0..) |field, i| {
- const field_src_loc = union_obj.fieldSrcLoc(sema.mod, .{
+ const field_src_loc = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = i,
.range = .type,
});
if (try sema.typeRequiresComptime(field.ty)) {
try mod.errNoteNonLazy(field_src_loc, msg, "union requires comptime because of this field", .{});
- try sema.explainWhyTypeIsComptimeInner(block, src, msg, field_src_loc, field.ty, type_set);
+ try sema.explainWhyTypeIsComptimeInner(msg, field_src_loc, field.ty, type_set);
}
}
}
@@ -22965,7 +24396,8 @@ fn validateExternType(
ty: Type,
position: ExternPosition,
) !bool {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Type,
.ComptimeFloat,
.ComptimeInt,
@@ -22983,8 +24415,8 @@ fn validateExternType(
.Float,
.AnyFrame,
=> return true,
- .Pointer => return !ty.isSlice(),
- .Int => switch (ty.intInfo(sema.mod.getTarget()).bits) {
+ .Pointer => return !(ty.isSlice(mod) or try sema.typeRequiresComptime(ty)),
+ .Int => switch (ty.intInfo(mod).bits) {
8, 16, 32, 64, 128 => return true,
else => return false,
},
@@ -22993,20 +24425,18 @@ fn validateExternType(
const target = sema.mod.getTarget();
// For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI.
// The goal is to experiment with more integrated CPU/GPU code.
- if (ty.fnCallingConvention() == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) {
+ if (ty.fnCallingConvention(mod) == .Kernel and (target.cpu.arch == .nvptx or target.cpu.arch == .nvptx64)) {
return true;
}
- return !Type.fnCallingConventionAllowsZigTypes(target, ty.fnCallingConvention());
+ return !target_util.fnCallConvAllowsZigTypes(target, ty.fnCallingConvention(mod));
},
.Enum => {
- var buf: Type.Payload.Bits = undefined;
- return sema.validateExternType(ty.intTagType(&buf), position);
+ return sema.validateExternType(ty.intTagType(mod), position);
},
- .Struct, .Union => switch (ty.containerLayout()) {
+ .Struct, .Union => switch (ty.containerLayout(mod)) {
.Extern => return true,
.Packed => {
- const target = sema.mod.getTarget();
- const bit_size = try ty.bitSizeAdvanced(target, sema);
+ const bit_size = try ty.bitSizeAdvanced(mod, sema);
switch (bit_size) {
8, 16, 32, 64, 128 => return true,
else => return false,
@@ -23016,10 +24446,10 @@ fn validateExternType(
},
.Array => {
if (position == .ret_ty or position == .param_ty) return false;
- return sema.validateExternType(ty.elemType2(), .element);
+ return sema.validateExternType(ty.elemType2(mod), .element);
},
- .Vector => return sema.validateExternType(ty.elemType2(), .element),
- .Optional => return ty.isPtrLikeOptional(),
+ .Vector => return sema.validateExternType(ty.elemType2(mod), .element),
+ .Optional => return ty.isPtrLikeOptional(mod),
}
}
@@ -23031,7 +24461,7 @@ fn explainWhyTypeIsNotExtern(
position: ExternPosition,
) CompileError!void {
const mod = sema.mod;
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Opaque,
.Bool,
.Float,
@@ -23049,13 +24479,21 @@ fn explainWhyTypeIsNotExtern(
.Frame,
=> return,
- .Pointer => try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{}),
+ .Pointer => {
+ if (ty.isSlice(mod)) {
+ try mod.errNoteNonLazy(src_loc, msg, "slices have no guaranteed in-memory representation", .{});
+ } else {
+ const pointee_ty = ty.childType(mod);
+ try mod.errNoteNonLazy(src_loc, msg, "pointer to comptime-only type '{}'", .{pointee_ty.fmt(sema.mod)});
+ try sema.explainWhyTypeIsComptime(msg, src_loc, pointee_ty);
+ }
+ },
.Void => try mod.errNoteNonLazy(src_loc, msg, "'void' is a zero bit type; for C 'void' use 'anyopaque'", .{}),
.NoReturn => try mod.errNoteNonLazy(src_loc, msg, "'noreturn' is only allowed as a return type", .{}),
- .Int => if (ty.intInfo(sema.mod.getTarget()).bits > 128) {
- try mod.errNoteNonLazy(src_loc, msg, "only integers with less than 128 bits are extern compatible", .{});
- } else {
+ .Int => if (!std.math.isPowerOfTwo(ty.intInfo(mod).bits)) {
try mod.errNoteNonLazy(src_loc, msg, "only integers with power of two bits are extern compatible", .{});
+ } else {
+ try mod.errNoteNonLazy(src_loc, msg, "only integers with 8, 16, 32, 64 and 128 bits are extern compatible", .{});
},
.Fn => {
if (position != .other) {
@@ -23063,7 +24501,7 @@ fn explainWhyTypeIsNotExtern(
try mod.errNoteNonLazy(src_loc, msg, "use '*const ' to make a function pointer type", .{});
return;
}
- switch (ty.fnCallingConvention()) {
+ switch (ty.fnCallingConvention(mod)) {
.Unspecified => try mod.errNoteNonLazy(src_loc, msg, "extern function must specify calling convention", .{}),
.Async => try mod.errNoteNonLazy(src_loc, msg, "async function cannot be extern", .{}),
.Inline => try mod.errNoteNonLazy(src_loc, msg, "inline function cannot be extern", .{}),
@@ -23071,8 +24509,7 @@ fn explainWhyTypeIsNotExtern(
}
},
.Enum => {
- var buf: Type.Payload.Bits = undefined;
- const tag_ty = ty.intTagType(&buf);
+ const tag_ty = ty.intTagType(mod);
try mod.errNoteNonLazy(src_loc, msg, "enum tag type '{}' is not extern compatible", .{tag_ty.fmt(sema.mod)});
try sema.explainWhyTypeIsNotExtern(msg, src_loc, tag_ty, position);
},
@@ -23084,17 +24521,17 @@ fn explainWhyTypeIsNotExtern(
} else if (position == .param_ty) {
return mod.errNoteNonLazy(src_loc, msg, "arrays are not allowed as a parameter type", .{});
}
- try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), .element);
+ try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element);
},
- .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(), .element),
+ .Vector => try sema.explainWhyTypeIsNotExtern(msg, src_loc, ty.elemType2(mod), .element),
.Optional => try mod.errNoteNonLazy(src_loc, msg, "only pointer like optionals are extern compatible", .{}),
}
}
/// Returns true if `ty` is allowed in packed types.
/// Does *NOT* require `ty` to be resolved in any way.
-fn validatePackedType(ty: Type) bool {
- switch (ty.zigTypeTag()) {
+fn validatePackedType(ty: Type, mod: *Module) bool {
+ switch (ty.zigTypeTag(mod)) {
.Type,
.ComptimeFloat,
.ComptimeInt,
@@ -23110,7 +24547,7 @@ fn validatePackedType(ty: Type) bool {
.Fn,
.Array,
=> return false,
- .Optional => return ty.isPtrLikeOptional(),
+ .Optional => return ty.isPtrLikeOptional(mod),
.Void,
.Bool,
.Float,
@@ -23118,8 +24555,8 @@ fn validatePackedType(ty: Type) bool {
.Vector,
.Enum,
=> return true,
- .Pointer => return !ty.isSlice(),
- .Struct, .Union => return ty.containerLayout() == .Packed,
+ .Pointer => return !ty.isSlice(mod),
+ .Struct, .Union => return ty.containerLayout(mod) == .Packed,
}
}
@@ -23130,7 +24567,7 @@ fn explainWhyTypeIsNotPacked(
ty: Type,
) CompileError!void {
const mod = sema.mod;
- switch (ty.zigTypeTag()) {
+ switch (ty.zigTypeTag(mod)) {
.Void,
.Bool,
.Float,
@@ -23188,6 +24625,7 @@ pub const PanicId = enum {
for_len_mismatch,
memcpy_len_mismatch,
memcpy_alias,
+ noreturn_returned,
};
fn addSafetyCheck(
@@ -23274,31 +24712,36 @@ fn addSafetyCheckExtra(
fn panicWithMsg(
sema: *Sema,
block: *Block,
- src: LazySrcLoc,
msg_inst: Air.Inst.Ref,
) !void {
const mod = sema.mod;
- const arena = sema.arena;
if (!mod.backendSupportsFeature(.panic_fn)) {
- _ = try block.addNoOp(.breakpoint);
- _ = try block.addNoOp(.unreach);
+ _ = try block.addNoOp(.trap);
return;
}
const panic_fn = try sema.getBuiltin("panic");
const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
const stack_trace_ty = try sema.resolveTypeFields(unresolved_stack_trace_ty);
const target = mod.getTarget();
- const ptr_stack_trace_ty = try Type.ptr(arena, mod, .{
- .pointee_type = stack_trace_ty,
- .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
+ const ptr_stack_trace_ty = try mod.ptrType(.{
+ .child = stack_trace_ty.toIntern(),
+ .flags = .{
+ .address_space = target_util.defaultAddressSpace(target, .global_constant), // TODO might need a place that is more dynamic
+ },
});
- const null_stack_trace = try sema.addConstant(
- try Type.optional(arena, ptr_stack_trace_ty),
- Value.null,
- );
- const args: [3]Air.Inst.Ref = .{ msg_inst, null_stack_trace, .null_value };
- _ = try sema.analyzeCall(block, panic_fn, src, src, .auto, false, &args, null);
+ const opt_ptr_stack_trace_ty = try mod.optionalType(ptr_stack_trace_ty.toIntern());
+ const null_stack_trace = try sema.addConstant(opt_ptr_stack_trace_ty, (try mod.intern(.{ .opt = .{
+ .ty = opt_ptr_stack_trace_ty.toIntern(),
+ .val = .none,
+ } })).toValue());
+
+ const opt_usize_ty = try mod.optionalType(.usize_type);
+ const null_ret_addr = try sema.addConstant(opt_usize_ty, (try mod.intern(.{ .opt = .{
+ .ty = opt_usize_ty.toIntern(),
+ .val = .none,
+ } })).toValue());
+ try sema.callBuiltin(block, panic_fn, .auto, &.{ msg_inst, null_stack_trace, null_ret_addr });
}
fn panicUnwrapError(
@@ -23330,14 +24773,13 @@ fn panicUnwrapError(
{
if (!sema.mod.backendSupportsFeature(.panic_unwrap_error)) {
- _ = try fail_block.addNoOp(.breakpoint);
- _ = try fail_block.addNoOp(.unreach);
+ _ = try fail_block.addNoOp(.trap);
} else {
const panic_fn = try sema.getBuiltin("panicUnwrapError");
const err = try fail_block.addTyOp(unwrap_err_tag, Type.anyerror, operand);
const err_return_trace = try sema.getErrorReturnTrace(&fail_block);
const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
- _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, &args, null);
+ try sema.callBuiltin(&fail_block, panic_fn, .auto, &args);
}
}
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
@@ -23358,20 +24800,6 @@ fn panicIndexOutOfBounds(
try sema.safetyCheckFormatted(parent_block, ok, "panicOutOfBounds", &.{ index, len });
}
-fn panicStartLargerThanEnd(
- sema: *Sema,
- parent_block: *Block,
- start: Air.Inst.Ref,
- end: Air.Inst.Ref,
-) !void {
- assert(!parent_block.is_comptime);
- const ok = try parent_block.addBinOp(.cmp_lte, start, end);
- if (!sema.mod.comp.formatted_panics) {
- return sema.addSafetyCheck(parent_block, ok, .start_index_greater_than_end);
- }
- try sema.safetyCheckFormatted(parent_block, ok, "panicStartGreaterThanEnd", &.{ start, end });
-}
-
fn panicInactiveUnionField(
sema: *Sema,
parent_block: *Block,
@@ -23395,11 +24823,12 @@ fn panicSentinelMismatch(
sentinel_index: Air.Inst.Ref,
) !void {
assert(!parent_block.is_comptime);
+ const mod = sema.mod;
const expected_sentinel_val = maybe_sentinel orelse return;
const expected_sentinel = try sema.addConstant(sentinel_ty, expected_sentinel_val);
const ptr_ty = sema.typeOf(ptr);
- const actual_sentinel = if (ptr_ty.isSlice())
+ const actual_sentinel = if (ptr_ty.isSlice(mod))
try parent_block.addBinOp(.slice_elem_val, ptr, sentinel_index)
else blk: {
const elem_ptr_ty = try sema.elemPtrType(ptr_ty, null);
@@ -23407,7 +24836,7 @@ fn panicSentinelMismatch(
break :blk try parent_block.addTyOp(.load, sentinel_ty, sentinel_ptr);
};
- const ok = if (sentinel_ty.zigTypeTag() == .Vector) ok: {
+ const ok = if (sentinel_ty.zigTypeTag(mod) == .Vector) ok: {
const eql =
try parent_block.addCmpVector(expected_sentinel, actual_sentinel, .eq);
break :ok try parent_block.addInst(.{
@@ -23417,12 +24846,12 @@ fn panicSentinelMismatch(
.operation = .And,
} },
});
- } else if (sentinel_ty.isSelfComparable(true))
+ } else if (sentinel_ty.isSelfComparable(mod, true))
try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel)
else {
const panic_fn = try sema.getBuiltin("checkNonScalarSentinel");
const args: [2]Air.Inst.Ref = .{ expected_sentinel, actual_sentinel };
- _ = try sema.analyzeCall(parent_block, panic_fn, sema.src, sema.src, .auto, false, &args, null);
+ try sema.callBuiltin(parent_block, panic_fn, .auto, &args);
return;
};
@@ -23456,11 +24885,10 @@ fn safetyCheckFormatted(
defer fail_block.instructions.deinit(gpa);
if (!sema.mod.backendSupportsFeature(.safety_check_formatted)) {
- _ = try fail_block.addNoOp(.breakpoint);
- _ = try fail_block.addNoOp(.unreach);
+ _ = try fail_block.addNoOp(.trap);
} else {
const panic_fn = try sema.getBuiltin(func);
- _ = try sema.analyzeCall(&fail_block, panic_fn, sema.src, sema.src, .auto, false, args, null);
+ try sema.callBuiltin(&fail_block, panic_fn, .auto, args);
}
try sema.addSafetyCheckExtra(parent_block, ok, &fail_block);
}
@@ -23470,16 +24898,18 @@ fn safetyPanic(
block: *Block,
panic_id: PanicId,
) CompileError!void {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const panic_messages_ty = try sema.getBuiltinType("panic_messages");
const msg_decl_index = (try sema.namespaceLookup(
block,
sema.src,
- panic_messages_ty.getNamespace().?,
- @tagName(panic_id),
+ panic_messages_ty.getNamespaceIndex(mod).unwrap().?,
+ try mod.intern_pool.getOrPutString(gpa, @tagName(panic_id)),
)).?;
const msg_inst = try sema.analyzeDeclVal(block, sema.src, msg_decl_index);
- try sema.panicWithMsg(block, sema.src, msg_inst);
+ try sema.panicWithMsg(block, msg_inst);
}
fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
@@ -23507,37 +24937,38 @@ fn fieldVal(
block: *Block,
src: LazySrcLoc,
object: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
// When editing this function, note that there is corresponding logic to be edited
// in `fieldPtr`. This function takes a value and returns a value.
- const arena = sema.arena;
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const object_src = src; // TODO better source location
const object_ty = sema.typeOf(object);
// Zig allows dereferencing a single pointer during field lookup. Note that
// we don't actually need to generate the dereference some field lookups, like the
// length of arrays and other comptime operations.
- const is_pointer_to = object_ty.isSinglePointer();
+ const is_pointer_to = object_ty.isSinglePointer(mod);
const inner_ty = if (is_pointer_to)
- object_ty.childType()
+ object_ty.childType(mod)
else
object_ty;
- switch (inner_ty.zigTypeTag()) {
+ switch (inner_ty.zigTypeTag(mod)) {
.Array => {
- if (mem.eql(u8, field_name, "len")) {
+ if (ip.stringEqlSlice(field_name, "len")) {
return sema.addConstant(
Type.usize,
- try Value.Tag.int_u64.create(arena, inner_ty.arrayLen()),
+ try mod.intValue(Type.usize, inner_ty.arrayLen(mod)),
);
- } else if (mem.eql(u8, field_name, "ptr") and is_pointer_to) {
- const ptr_info = object_ty.ptrInfo().data;
- const result_ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = ptr_info.pointee_type.childType(),
+ } else if (ip.stringEqlSlice(field_name, "ptr") and is_pointer_to) {
+ const ptr_info = object_ty.ptrInfo(mod);
+ const result_ty = try Type.ptr(sema.arena, mod, .{
+ .pointee_type = ptr_info.pointee_type.childType(mod),
.sentinel = ptr_info.sentinel,
.@"align" = ptr_info.@"align",
.@"addrspace" = ptr_info.@"addrspace",
@@ -23554,21 +24985,21 @@ fn fieldVal(
return sema.fail(
block,
field_name_src,
- "no member named '{s}' in '{}'",
- .{ field_name, object_ty.fmt(sema.mod) },
+ "no member named '{}' in '{}'",
+ .{ field_name.fmt(ip), object_ty.fmt(mod) },
);
}
},
.Pointer => {
- const ptr_info = inner_ty.ptrInfo().data;
+ const ptr_info = inner_ty.ptrInfo(mod);
if (ptr_info.size == .Slice) {
- if (mem.eql(u8, field_name, "ptr")) {
+ if (ip.stringEqlSlice(field_name, "ptr")) {
const slice = if (is_pointer_to)
try sema.analyzeLoad(block, src, object, object_src)
else
object;
return sema.analyzeSlicePtr(block, object_src, slice, inner_ty);
- } else if (mem.eql(u8, field_name, "len")) {
+ } else if (ip.stringEqlSlice(field_name, "len")) {
const slice = if (is_pointer_to)
try sema.analyzeLoad(block, src, object, object_src)
else
@@ -23578,8 +25009,8 @@ fn fieldVal(
return sema.fail(
block,
field_name_src,
- "no member named '{s}' in '{}'",
- .{ field_name, object_ty.fmt(sema.mod) },
+ "no member named '{}' in '{}'",
+ .{ field_name.fmt(ip), object_ty.fmt(mod) },
);
}
}
@@ -23591,66 +25022,74 @@ fn fieldVal(
object;
const val = (try sema.resolveDefinedValue(block, object_src, dereffed_type)).?;
- var to_type_buffer: Value.ToTypeBuffer = undefined;
- const child_type = val.toType(&to_type_buffer);
+ const child_type = val.toType();
- switch (try child_type.zigTypeTagOrPoison()) {
+ switch (try child_type.zigTypeTagOrPoison(mod)) {
.ErrorSet => {
- const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
- if (payload.data.names.getEntry(field_name)) |entry| {
- break :blk entry.key_ptr.*;
- }
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "no error named '{s}' in '{}'", .{
- field_name, child_type.fmt(sema.mod),
- });
- errdefer msg.destroy(sema.gpa);
- try sema.addDeclaredHereNote(msg, child_type);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(msg);
- } else (try sema.mod.getErrorValue(field_name)).key;
+ switch (ip.indexToKey(child_type.toIntern())) {
+ .error_set_type => |error_set_type| blk: {
+ if (error_set_type.nameIndex(ip, field_name) != null) break :blk;
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "no error named '{}' in '{}'", .{
+ field_name.fmt(ip), child_type.fmt(mod),
+ });
+ errdefer msg.destroy(sema.gpa);
+ try sema.addDeclaredHereNote(msg, child_type);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ },
+ .inferred_error_set_type => {
+ return sema.fail(block, src, "TODO handle inferred error sets here", .{});
+ },
+ .simple_type => |t| {
+ assert(t == .anyerror);
+ _ = try mod.getErrorValue(field_name);
+ },
+ else => unreachable,
+ }
- return sema.addConstant(
- if (!child_type.isAnyError())
- try child_type.copy(arena)
- else
- try Type.Tag.error_set_single.create(arena, name),
- try Value.Tag.@"error".create(arena, .{ .name = name }),
- );
+ const error_set_type = if (!child_type.isAnyError(mod))
+ child_type
+ else
+ try mod.singleErrorSetType(field_name);
+ return sema.addConstant(error_set_type, (try mod.intern(.{ .err = .{
+ .ty = error_set_type.toIntern(),
+ .name = field_name,
+ } })).toValue());
},
.Union => {
- if (child_type.getNamespace()) |namespace| {
+ if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
return inst;
}
}
const union_ty = try sema.resolveTypeFields(child_type);
- if (union_ty.unionTagType()) |enum_ty| {
- if (enum_ty.enumFieldIndex(field_name)) |field_index_usize| {
+ if (union_ty.unionTagType(mod)) |enum_ty| {
+ if (enum_ty.enumFieldIndex(field_name, mod)) |field_index_usize| {
const field_index = @intCast(u32, field_index_usize);
return sema.addConstant(
enum_ty,
- try Value.Tag.enum_field_index.create(sema.arena, field_index),
+ try mod.enumValueFieldIndex(enum_ty, field_index),
);
}
}
return sema.failWithBadMemberAccess(block, union_ty, field_name_src, field_name);
},
.Enum => {
- if (child_type.getNamespace()) |namespace| {
+ if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
return inst;
}
}
- const field_index_usize = child_type.enumFieldIndex(field_name) orelse
+ const field_index_usize = child_type.enumFieldIndex(field_name, mod) orelse
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
const field_index = @intCast(u32, field_index_usize);
- const enum_val = try Value.Tag.enum_field_index.create(arena, field_index);
- return sema.addConstant(try child_type.copy(arena), enum_val);
+ const enum_val = try mod.enumValueFieldIndex(child_type, field_index);
+ return sema.addConstant(child_type, enum_val);
},
.Struct, .Opaque => {
- if (child_type.getNamespace()) |namespace| {
+ if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookupVal(block, src, namespace, field_name)) |inst| {
return inst;
}
@@ -23659,10 +25098,10 @@ fn fieldVal(
},
else => {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)});
+ const msg = try sema.errMsg(block, src, "type '{}' has no members", .{child_type.fmt(mod)});
errdefer msg.destroy(sema.gpa);
- if (child_type.isSlice()) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
- if (child_type.zigTypeTag() == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
+ if (child_type.isSlice(mod)) try sema.errNote(block, src, msg, "slice values have 'len' and 'ptr' members", .{});
+ if (child_type.zigTypeTag(mod) == .Array) try sema.errNote(block, src, msg, "array values have 'len' member", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -23693,50 +25132,52 @@ fn fieldPtr(
block: *Block,
src: LazySrcLoc,
object_ptr: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
initializing: bool,
) CompileError!Air.Inst.Ref {
// When editing this function, note that there is corresponding logic to be edited
// in `fieldVal`. This function takes a pointer and returns a pointer.
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const object_ptr_src = src; // TODO better source location
const object_ptr_ty = sema.typeOf(object_ptr);
- const object_ty = switch (object_ptr_ty.zigTypeTag()) {
- .Pointer => object_ptr_ty.elemType(),
- else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(sema.mod)}),
+ const object_ty = switch (object_ptr_ty.zigTypeTag(mod)) {
+ .Pointer => object_ptr_ty.childType(mod),
+ else => return sema.fail(block, object_ptr_src, "expected pointer, found '{}'", .{object_ptr_ty.fmt(mod)}),
};
// Zig allows dereferencing a single pointer during field lookup. Note that
// we don't actually need to generate the dereference some field lookups, like the
// length of arrays and other comptime operations.
- const is_pointer_to = object_ty.isSinglePointer();
+ const is_pointer_to = object_ty.isSinglePointer(mod);
const inner_ty = if (is_pointer_to)
- object_ty.childType()
+ object_ty.childType(mod)
else
object_ty;
- switch (inner_ty.zigTypeTag()) {
+ switch (inner_ty.zigTypeTag(mod)) {
.Array => {
- if (mem.eql(u8, field_name, "len")) {
+ if (ip.stringEqlSlice(field_name, "len")) {
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
Type.usize,
- try Value.Tag.int_u64.create(anon_decl.arena(), inner_ty.arrayLen()),
+ try mod.intValue(Type.usize, inner_ty.arrayLen(mod)),
0, // default alignment
));
} else {
return sema.fail(
block,
field_name_src,
- "no member named '{s}' in '{}'",
- .{ field_name, object_ty.fmt(sema.mod) },
+ "no member named '{}' in '{}'",
+ .{ field_name.fmt(ip), object_ty.fmt(mod) },
);
}
},
- .Pointer => if (inner_ty.isSlice()) {
+ .Pointer => if (inner_ty.isSlice(mod)) {
const inner_ptr = if (is_pointer_to)
try sema.analyzeLoad(block, src, object_ptr, object_ptr_src)
else
@@ -23744,47 +25185,44 @@ fn fieldPtr(
const attr_ptr_ty = if (is_pointer_to) object_ty else object_ptr_ty;
- if (mem.eql(u8, field_name, "ptr")) {
- const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
- const slice_ptr_ty = inner_ty.slicePtrFieldType(buf);
+ if (ip.stringEqlSlice(field_name, "ptr")) {
+ const slice_ptr_ty = inner_ty.slicePtrFieldType(mod);
- const result_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const result_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = slice_ptr_ty,
- .mutable = attr_ptr_ty.ptrIsMutable(),
- .@"volatile" = attr_ptr_ty.isVolatilePtr(),
- .@"addrspace" = attr_ptr_ty.ptrAddressSpace(),
+ .mutable = attr_ptr_ty.ptrIsMutable(mod),
+ .@"volatile" = attr_ptr_ty.isVolatilePtr(mod),
+ .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod),
});
if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
- return sema.addConstant(
- result_ty,
- try Value.Tag.field_ptr.create(sema.arena, .{
- .container_ptr = val,
- .container_ty = inner_ty,
- .field_index = Value.Payload.Slice.ptr_index,
- }),
- );
+ return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{
+ .ty = result_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = val.toIntern(),
+ .index = Value.slice_ptr_index,
+ } },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, src, null);
return block.addTyOp(.ptr_slice_ptr_ptr, result_ty, inner_ptr);
- } else if (mem.eql(u8, field_name, "len")) {
- const result_ty = try Type.ptr(sema.arena, sema.mod, .{
+ } else if (ip.stringEqlSlice(field_name, "len")) {
+ const result_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = Type.usize,
- .mutable = attr_ptr_ty.ptrIsMutable(),
- .@"volatile" = attr_ptr_ty.isVolatilePtr(),
- .@"addrspace" = attr_ptr_ty.ptrAddressSpace(),
+ .mutable = attr_ptr_ty.ptrIsMutable(mod),
+ .@"volatile" = attr_ptr_ty.isVolatilePtr(mod),
+ .@"addrspace" = attr_ptr_ty.ptrAddressSpace(mod),
});
if (try sema.resolveDefinedValue(block, object_ptr_src, inner_ptr)) |val| {
- return sema.addConstant(
- result_ty,
- try Value.Tag.field_ptr.create(sema.arena, .{
- .container_ptr = val,
- .container_ty = inner_ty,
- .field_index = Value.Payload.Slice.len_index,
- }),
- );
+ return sema.addConstant(result_ty, (try mod.intern(.{ .ptr = .{
+ .ty = result_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = val.toIntern(),
+ .index = Value.slice_len_index,
+ } },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, src, null);
@@ -23793,8 +25231,8 @@ fn fieldPtr(
return sema.fail(
block,
field_name_src,
- "no member named '{s}' in '{}'",
- .{ field_name, object_ty.fmt(sema.mod) },
+ "no member named '{}' in '{}'",
+ .{ field_name.fmt(ip), object_ty.fmt(mod) },
);
}
},
@@ -23807,47 +25245,59 @@ fn fieldPtr(
result;
const val = (sema.resolveDefinedValue(block, src, inner) catch unreachable).?;
- var to_type_buffer: Value.ToTypeBuffer = undefined;
- const child_type = val.toType(&to_type_buffer);
+ const child_type = val.toType();
- switch (child_type.zigTypeTag()) {
+ switch (child_type.zigTypeTag(mod)) {
.ErrorSet => {
- // TODO resolve inferred error sets
- const name: []const u8 = if (child_type.castTag(.error_set)) |payload| blk: {
- if (payload.data.names.getEntry(field_name)) |entry| {
- break :blk entry.key_ptr.*;
- }
- return sema.fail(block, src, "no error named '{s}' in '{}'", .{
- field_name, child_type.fmt(sema.mod),
- });
- } else (try sema.mod.getErrorValue(field_name)).key;
+ switch (ip.indexToKey(child_type.toIntern())) {
+ .error_set_type => |error_set_type| blk: {
+ if (error_set_type.nameIndex(ip, field_name) != null) {
+ break :blk;
+ }
+ return sema.fail(block, src, "no error named '{}' in '{}'", .{
+ field_name.fmt(ip), child_type.fmt(mod),
+ });
+ },
+ .inferred_error_set_type => {
+ return sema.fail(block, src, "TODO handle inferred error sets here", .{});
+ },
+ .simple_type => |t| {
+ assert(t == .anyerror);
+ _ = try mod.getErrorValue(field_name);
+ },
+ else => unreachable,
+ }
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
+ const error_set_type = if (!child_type.isAnyError(mod))
+ child_type
+ else
+ try mod.singleErrorSetType(field_name);
return sema.analyzeDeclRef(try anon_decl.finish(
- if (!child_type.isAnyError())
- try child_type.copy(anon_decl.arena())
- else
- try Type.Tag.error_set_single.create(anon_decl.arena(), name),
- try Value.Tag.@"error".create(anon_decl.arena(), .{ .name = name }),
+ error_set_type,
+ (try mod.intern(.{ .err = .{
+ .ty = error_set_type.toIntern(),
+ .name = field_name,
+ } })).toValue(),
0, // default alignment
));
},
.Union => {
- if (child_type.getNamespace()) |namespace| {
+ if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
return inst;
}
}
const union_ty = try sema.resolveTypeFields(child_type);
- if (union_ty.unionTagType()) |enum_ty| {
- if (enum_ty.enumFieldIndex(field_name)) |field_index| {
+ if (union_ty.unionTagType(mod)) |enum_ty| {
+ if (enum_ty.enumFieldIndex(field_name, mod)) |field_index| {
const field_index_u32 = @intCast(u32, field_index);
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
- try enum_ty.copy(anon_decl.arena()),
- try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
+ enum_ty,
+ try mod.enumValueFieldIndex(enum_ty, field_index_u32),
0, // default alignment
));
}
@@ -23855,32 +25305,32 @@ fn fieldPtr(
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
},
.Enum => {
- if (child_type.getNamespace()) |namespace| {
+ if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
return inst;
}
}
- const field_index = child_type.enumFieldIndex(field_name) orelse {
+ const field_index = child_type.enumFieldIndex(field_name, mod) orelse {
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
};
const field_index_u32 = @intCast(u32, field_index);
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
- try child_type.copy(anon_decl.arena()),
- try Value.Tag.enum_field_index.create(anon_decl.arena(), field_index_u32),
+ child_type,
+ try mod.enumValueFieldIndex(child_type, field_index_u32),
0, // default alignment
));
},
.Struct, .Opaque => {
- if (child_type.getNamespace()) |namespace| {
+ if (child_type.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookupRef(block, src, namespace, field_name)) |inst| {
return inst;
}
}
return sema.failWithBadMemberAccess(block, child_type, field_name_src, field_name);
},
- else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(sema.mod)}),
+ else => return sema.fail(block, src, "type '{}' has no members", .{child_type.fmt(mod)}),
}
},
.Struct => {
@@ -23902,66 +25352,77 @@ fn fieldPtr(
return sema.failWithInvalidFieldAccess(block, src, object_ty, field_name);
}
+const ResolvedFieldCallee = union(enum) {
+ /// The LHS of the call was an actual field with this value.
+ direct: Air.Inst.Ref,
+ /// This is a method call, with the function and first argument given.
+ method: struct {
+ func_inst: Air.Inst.Ref,
+ arg0_inst: Air.Inst.Ref,
+ },
+};
+
fn fieldCallBind(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
raw_ptr: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
-) CompileError!Air.Inst.Ref {
+) CompileError!ResolvedFieldCallee {
// When editing this function, note that there is corresponding logic to be edited
// in `fieldVal`. This function takes a pointer and returns a pointer.
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const raw_ptr_src = src; // TODO better source location
const raw_ptr_ty = sema.typeOf(raw_ptr);
- const inner_ty = if (raw_ptr_ty.zigTypeTag() == .Pointer and (raw_ptr_ty.ptrSize() == .One or raw_ptr_ty.ptrSize() == .C))
- raw_ptr_ty.childType()
+ const inner_ty = if (raw_ptr_ty.zigTypeTag(mod) == .Pointer and (raw_ptr_ty.ptrSize(mod) == .One or raw_ptr_ty.ptrSize(mod) == .C))
+ raw_ptr_ty.childType(mod)
else
- return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(sema.mod)});
+ return sema.fail(block, raw_ptr_src, "expected single pointer, found '{}'", .{raw_ptr_ty.fmt(mod)});
// Optionally dereference a second pointer to get the concrete type.
- const is_double_ptr = inner_ty.zigTypeTag() == .Pointer and inner_ty.ptrSize() == .One;
- const concrete_ty = if (is_double_ptr) inner_ty.childType() else inner_ty;
+ const is_double_ptr = inner_ty.zigTypeTag(mod) == .Pointer and inner_ty.ptrSize(mod) == .One;
+ const concrete_ty = if (is_double_ptr) inner_ty.childType(mod) else inner_ty;
const ptr_ty = if (is_double_ptr) inner_ty else raw_ptr_ty;
const object_ptr = if (is_double_ptr)
try sema.analyzeLoad(block, src, raw_ptr, src)
else
raw_ptr;
- const arena = sema.arena;
find_field: {
- switch (concrete_ty.zigTypeTag()) {
+ switch (concrete_ty.zigTypeTag(mod)) {
.Struct => {
const struct_ty = try sema.resolveTypeFields(concrete_ty);
- if (struct_ty.castTag(.@"struct")) |struct_obj| {
- const field_index_usize = struct_obj.data.fields.getIndex(field_name) orelse
+ if (mod.typeToStruct(struct_ty)) |struct_obj| {
+ const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
break :find_field;
const field_index = @intCast(u32, field_index_usize);
- const field = struct_obj.data.fields.values()[field_index];
+ const field = struct_obj.fields.values()[field_index];
return sema.finishFieldCallBind(block, src, ptr_ty, field.ty, field_index, object_ptr);
- } else if (struct_ty.isTuple()) {
- if (mem.eql(u8, field_name, "len")) {
- return sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
+ } else if (struct_ty.isTuple(mod)) {
+ if (ip.stringEqlSlice(field_name, "len")) {
+ return .{ .direct = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod)) };
+ }
+ if (field_name.toUnsigned(ip)) |field_index| {
+ if (field_index >= struct_ty.structFieldCount(mod)) break :find_field;
+ return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index, mod), field_index, object_ptr);
}
- if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
- if (field_index >= struct_ty.structFieldCount()) break :find_field;
- return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(field_index), field_index, object_ptr);
- } else |_| {}
} else {
- const max = struct_ty.structFieldCount();
- var i: u32 = 0;
- while (i < max) : (i += 1) {
- if (mem.eql(u8, struct_ty.structFieldName(i), field_name)) {
- return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i), i, object_ptr);
+ const max = struct_ty.structFieldCount(mod);
+ for (0..max) |i_usize| {
+ const i = @intCast(u32, i_usize);
+ if (field_name == struct_ty.structFieldName(i, mod)) {
+ return sema.finishFieldCallBind(block, src, ptr_ty, struct_ty.structFieldType(i, mod), i, object_ptr);
}
}
}
},
.Union => {
const union_ty = try sema.resolveTypeFields(concrete_ty);
- const fields = union_ty.unionFields();
+ const fields = union_ty.unionFields(mod);
const field_index_usize = fields.getIndex(field_name) orelse break :find_field;
const field_index = @intCast(u32, field_index_usize);
const field = fields.values()[field_index];
@@ -23970,84 +25431,72 @@ fn fieldCallBind(
},
.Type => {
const namespace = try sema.analyzeLoad(block, src, object_ptr, src);
- return sema.fieldVal(block, src, namespace, field_name, field_name_src);
+ return .{ .direct = try sema.fieldVal(block, src, namespace, field_name, field_name_src) };
},
else => {},
}
}
// If we get here, we need to look for a decl in the struct type instead.
- const found_decl = switch (concrete_ty.zigTypeTag()) {
+ const found_decl = switch (concrete_ty.zigTypeTag(mod)) {
.Struct, .Opaque, .Union, .Enum => found_decl: {
- if (concrete_ty.getNamespace()) |namespace| {
+ if (concrete_ty.getNamespaceIndex(mod).unwrap()) |namespace| {
if (try sema.namespaceLookup(block, src, namespace, field_name)) |decl_idx| {
try sema.addReferencedBy(block, src, decl_idx);
- const inst = try sema.analyzeDeclRef(decl_idx);
-
- const decl_val = try sema.analyzeLoad(block, src, inst, src);
+ const decl_val = try sema.analyzeDeclVal(block, src, decl_idx);
const decl_type = sema.typeOf(decl_val);
- if (decl_type.zigTypeTag() == .Fn and
- decl_type.fnParamLen() >= 1)
- {
- const first_param_type = decl_type.fnParamType(0);
- const first_param_tag = first_param_type.tag();
+ if (mod.typeToFunc(decl_type)) |func_type| f: {
+ if (func_type.param_types.len == 0) break :f;
+
+ const first_param_type = func_type.param_types[0].toType();
// zig fmt: off
- if (first_param_tag == .var_args_param or
- first_param_tag == .generic_poison or (
- first_param_type.zigTypeTag() == .Pointer and
- (first_param_type.ptrSize() == .One or
- first_param_type.ptrSize() == .C) and
- first_param_type.childType().eql(concrete_ty, sema.mod)))
+ if (first_param_type.isGenericPoison() or (
+ first_param_type.zigTypeTag(mod) == .Pointer and
+ (first_param_type.ptrSize(mod) == .One or
+ first_param_type.ptrSize(mod) == .C) and
+ first_param_type.childType(mod).eql(concrete_ty, mod)))
{
// zig fmt: on
+ // Note that if the param type is generic poison, we know that it must
+ // specifically be `anytype` since it's the first parameter, meaning we
+ // can safely assume it can be a pointer.
// TODO: bound fn calls on rvalues should probably
// generate a by-value argument somehow.
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = object_ptr,
- });
- return sema.addConstant(ty, value);
- } else if (first_param_type.eql(concrete_ty, sema.mod)) {
+ } };
+ } else if (first_param_type.eql(concrete_ty, mod)) {
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
- } else if (first_param_type.zigTypeTag() == .Optional) {
- var opt_buf: Type.Payload.ElemType = undefined;
- const child = first_param_type.optionalChild(&opt_buf);
- if (child.eql(concrete_ty, sema.mod)) {
+ } };
+ } else if (first_param_type.zigTypeTag(mod) == .Optional) {
+ const child = first_param_type.optionalChild(mod);
+ if (child.eql(concrete_ty, mod)) {
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
- } else if (child.zigTypeTag() == .Pointer and
- child.ptrSize() == .One and
- child.childType().eql(concrete_ty, sema.mod))
+ } };
+ } else if (child.zigTypeTag(mod) == .Pointer and
+ child.ptrSize(mod) == .One and
+ child.childType(mod).eql(concrete_ty, mod))
{
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = object_ptr,
- });
- return sema.addConstant(ty, value);
+ } };
}
- } else if (first_param_type.zigTypeTag() == .ErrorUnion and
- first_param_type.errorUnionPayload().eql(concrete_ty, sema.mod))
+ } else if (first_param_type.zigTypeTag(mod) == .ErrorUnion and
+ first_param_type.errorUnionPayload(mod).eql(concrete_ty, mod))
{
const deref = try sema.analyzeLoad(block, src, object_ptr, src);
- const ty = Type.Tag.bound_fn.init();
- const value = try Value.Tag.bound_fn.create(arena, .{
+ return .{ .method = .{
.func_inst = decl_val,
.arg0_inst = deref,
- });
- return sema.addConstant(ty, value);
+ } };
}
}
break :found_decl decl_idx;
@@ -24059,12 +25508,15 @@ fn fieldCallBind(
};
const msg = msg: {
- const msg = try sema.errMsg(block, src, "no field or member function named '{s}' in '{}'", .{ field_name, concrete_ty.fmt(sema.mod) });
+ const msg = try sema.errMsg(block, src, "no field or member function named '{}' in '{}'", .{
+ field_name.fmt(ip),
+ concrete_ty.fmt(mod),
+ });
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, concrete_ty);
if (found_decl) |decl_idx| {
- const decl = sema.mod.declPtr(decl_idx);
- try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "'{s}' is not a member function", .{field_name});
+ const decl = mod.declPtr(decl_idx);
+ try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "'{}' is not a member function", .{field_name.fmt(ip)});
}
break :msg msg;
};
@@ -24079,55 +25531,56 @@ fn finishFieldCallBind(
field_ty: Type,
field_index: u32,
object_ptr: Air.Inst.Ref,
-) CompileError!Air.Inst.Ref {
+) CompileError!ResolvedFieldCallee {
+ const mod = sema.mod;
const arena = sema.arena;
- const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
+ const ptr_field_ty = try Type.ptr(arena, mod, .{
.pointee_type = field_ty,
- .mutable = ptr_ty.ptrIsMutable(),
- .@"addrspace" = ptr_ty.ptrAddressSpace(),
+ .mutable = ptr_ty.ptrIsMutable(mod),
+ .@"addrspace" = ptr_ty.ptrAddressSpace(mod),
});
- const container_ty = ptr_ty.childType();
- if (container_ty.zigTypeTag() == .Struct) {
- if (container_ty.structFieldValueComptime(field_index)) |default_val| {
- return sema.addConstant(field_ty, default_val);
+ const container_ty = ptr_ty.childType(mod);
+ if (container_ty.zigTypeTag(mod) == .Struct) {
+ if (try container_ty.structFieldValueComptime(mod, field_index)) |default_val| {
+ return .{ .direct = try sema.addConstant(field_ty, default_val) };
}
}
if (try sema.resolveDefinedValue(block, src, object_ptr)) |struct_ptr_val| {
- const pointer = try sema.addConstant(
- ptr_field_ty,
- try Value.Tag.field_ptr.create(arena, .{
- .container_ptr = struct_ptr_val,
- .container_ty = container_ty,
- .field_index = field_index,
- }),
- );
- return sema.analyzeLoad(block, src, pointer, src);
+ const pointer = try sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = struct_ptr_val.toIntern(),
+ .index = field_index,
+ } },
+ } })).toValue());
+ return .{ .direct = try sema.analyzeLoad(block, src, pointer, src) };
}
try sema.requireRuntimeBlock(block, src, null);
const ptr_inst = try block.addStructFieldPtr(object_ptr, field_index, ptr_field_ty);
- return sema.analyzeLoad(block, src, ptr_inst, src);
+ return .{ .direct = try sema.analyzeLoad(block, src, ptr_inst, src) };
}
fn namespaceLookup(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- namespace: *Namespace,
- decl_name: []const u8,
+ namespace: Namespace.Index,
+ decl_name: InternPool.NullTerminatedString,
) CompileError!?Decl.Index {
+ const mod = sema.mod;
const gpa = sema.gpa;
if (try sema.lookupInNamespace(block, src, namespace, decl_name, true)) |decl_index| {
- const decl = sema.mod.declPtr(decl_index);
- if (!decl.is_pub and decl.getFileScope() != block.getFileScope()) {
+ const decl = mod.declPtr(decl_index);
+ if (!decl.is_pub and decl.getFileScope(mod) != block.getFileScope(mod)) {
const msg = msg: {
- const msg = try sema.errMsg(block, src, "'{s}' is not marked 'pub'", .{
- decl_name,
+ const msg = try sema.errMsg(block, src, "'{}' is not marked 'pub'", .{
+ decl_name.fmt(&mod.intern_pool),
});
errdefer msg.destroy(gpa);
- try sema.mod.errNoteNonLazy(decl.srcLoc(), msg, "declared here", .{});
+ try mod.errNoteNonLazy(decl.srcLoc(mod), msg, "declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
@@ -24141,8 +25594,8 @@ fn namespaceLookupRef(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- namespace: *Namespace,
- decl_name: []const u8,
+ namespace: Namespace.Index,
+ decl_name: InternPool.NullTerminatedString,
) CompileError!?Air.Inst.Ref {
const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
try sema.addReferencedBy(block, src, decl);
@@ -24153,8 +25606,8 @@ fn namespaceLookupVal(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- namespace: *Namespace,
- decl_name: []const u8,
+ namespace: Namespace.Index,
+ decl_name: InternPool.NullTerminatedString,
) CompileError!?Air.Inst.Ref {
const decl = (try sema.namespaceLookup(block, src, namespace, decl_name)) orelse return null;
return try sema.analyzeDeclVal(block, src, decl);
@@ -24165,29 +25618,30 @@ fn structFieldPtr(
block: *Block,
src: LazySrcLoc,
struct_ptr: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
unresolved_struct_ty: Type,
initializing: bool,
) CompileError!Air.Inst.Ref {
- assert(unresolved_struct_ty.zigTypeTag() == .Struct);
+ const mod = sema.mod;
+ assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct);
const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty);
try sema.resolveStructLayout(struct_ty);
- if (struct_ty.isTuple()) {
- if (mem.eql(u8, field_name, "len")) {
- const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount());
+ if (struct_ty.isTuple(mod)) {
+ if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
+ const len_inst = try sema.addIntUnsigned(Type.usize, struct_ty.structFieldCount(mod));
return sema.analyzeRef(block, src, len_inst);
}
const field_index = try sema.tupleFieldIndex(block, struct_ty, field_name, field_name_src);
return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
- } else if (struct_ty.isAnonStruct()) {
+ } else if (struct_ty.isAnonStruct(mod)) {
const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
return sema.tupleFieldPtr(block, src, struct_ptr, field_name_src, field_index, initializing);
}
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
+ const struct_obj = mod.typeToStruct(struct_ty).?;
const field_index_big = struct_obj.fields.getIndex(field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_obj, field_name_src, field_name);
@@ -24206,14 +25660,15 @@ fn structFieldPtrByIndex(
struct_ty: Type,
initializing: bool,
) CompileError!Air.Inst.Ref {
- if (struct_ty.isAnonStruct()) {
+ const mod = sema.mod;
+ if (struct_ty.isAnonStruct(mod)) {
return sema.tupleFieldPtr(block, src, struct_ptr, field_src, field_index, initializing);
}
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
+ const struct_obj = mod.typeToStruct(struct_ty).?;
const field = struct_obj.fields.values()[field_index];
const struct_ptr_ty = sema.typeOf(struct_ptr);
- const struct_ptr_ty_info = struct_ptr_ty.ptrInfo().data;
+ const struct_ptr_ty_info = struct_ptr_ty.ptrInfo(mod);
var ptr_ty_data: Type.Payload.Pointer.Data = .{
.pointee_type = field.ty,
@@ -24222,7 +25677,7 @@ fn structFieldPtrByIndex(
.@"addrspace" = struct_ptr_ty_info.@"addrspace",
};
- const target = sema.mod.getTarget();
+ const target = mod.getTarget();
if (struct_obj.layout == .Packed) {
comptime assert(Type.packed_struct_layout_version == 2);
@@ -24234,7 +25689,7 @@ fn structFieldPtrByIndex(
if (i == field_index) {
ptr_ty_data.bit_offset = running_bits;
}
- running_bits += @intCast(u16, f.ty.bitSize(target));
+ running_bits += @intCast(u16, f.ty.bitSize(mod));
}
ptr_ty_data.host_size = (running_bits + 7) / 8;
@@ -24248,7 +25703,7 @@ fn structFieldPtrByIndex(
const parent_align = if (struct_ptr_ty_info.@"align" != 0)
struct_ptr_ty_info.@"align"
else
- struct_ptr_ty_info.pointee_type.abiAlignment(target);
+ struct_ptr_ty_info.pointee_type.abiAlignment(mod);
ptr_ty_data.@"align" = parent_align;
// If the field happens to be byte-aligned, simplify the pointer type.
@@ -24262,8 +25717,8 @@ fn structFieldPtrByIndex(
if (parent_align != 0 and ptr_ty_data.bit_offset % 8 == 0 and
target.cpu.arch.endian() == .Little)
{
- const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(target);
- const elem_size_bits = ptr_ty_data.pointee_type.bitSize(target);
+ const elem_size_bytes = ptr_ty_data.pointee_type.abiSize(mod);
+ const elem_size_bits = ptr_ty_data.pointee_type.bitSize(mod);
if (elem_size_bytes * 8 == elem_size_bits) {
const byte_offset = ptr_ty_data.bit_offset / 8;
const new_align = @as(u32, 1) << @intCast(u5, @ctz(byte_offset | parent_align));
@@ -24276,25 +25731,25 @@ fn structFieldPtrByIndex(
ptr_ty_data.@"align" = field.abi_align;
}
- const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, ptr_ty_data);
+ const ptr_field_ty = try Type.ptr(sema.arena, mod, ptr_ty_data);
if (field.is_comptime) {
- const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{
- .field_ty = try field.ty.copy(sema.arena),
- .field_val = try field.default_val.copy(sema.arena),
- });
- return sema.addConstant(ptr_field_ty, val);
+ const val = try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .comptime_field = field.default_val },
+ } });
+ return sema.addConstant(ptr_field_ty, val.toValue());
}
if (try sema.resolveDefinedValue(block, src, struct_ptr)) |struct_ptr_val| {
- return sema.addConstant(
- ptr_field_ty,
- try Value.Tag.field_ptr.create(sema.arena, .{
- .container_ptr = struct_ptr_val,
- .container_ty = struct_ptr_ty.childType(),
- .field_index = field_index,
- }),
- );
+ const val = try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = try struct_ptr_val.intern(struct_ptr_ty, mod),
+ .index = field_index,
+ } },
+ } });
+ return sema.addConstant(ptr_field_ty, val.toValue());
}
try sema.requireRuntimeBlock(block, src, null);
@@ -24306,21 +25761,17 @@ fn structFieldVal(
block: *Block,
src: LazySrcLoc,
struct_byval: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
unresolved_struct_ty: Type,
) CompileError!Air.Inst.Ref {
- assert(unresolved_struct_ty.zigTypeTag() == .Struct);
+ const mod = sema.mod;
+ assert(unresolved_struct_ty.zigTypeTag(mod) == .Struct);
const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty);
- switch (struct_ty.tag()) {
- .tuple, .empty_struct_literal => return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty),
- .anon_struct => {
- const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
- return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty);
- },
- .@"struct" => {
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
+ switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index).?;
if (struct_obj.is_tuple) return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
@@ -24329,22 +25780,28 @@ fn structFieldVal(
const field = struct_obj.fields.values()[field_index];
if (field.is_comptime) {
- return sema.addConstant(field.ty, field.default_val);
+ return sema.addConstant(field.ty, field.default_val.toValue());
}
if (try sema.resolveMaybeUndefVal(struct_byval)) |struct_val| {
- if (struct_val.isUndef()) return sema.addConstUndef(field.ty);
+ if (struct_val.isUndef(mod)) return sema.addConstUndef(field.ty);
if ((try sema.typeHasOnePossibleValue(field.ty))) |opv| {
return sema.addConstant(field.ty, opv);
}
-
- const field_values = struct_val.castTag(.aggregate).?.data;
- return sema.addConstant(field.ty, field_values[field_index]);
+ return sema.addConstant(field.ty, try struct_val.fieldValue(mod, field_index));
}
try sema.requireRuntimeBlock(block, src, null);
return block.addStructFieldVal(struct_byval, field_index, field.ty);
},
+ .anon_struct_type => |anon_struct| {
+ if (anon_struct.names.len == 0) {
+ return sema.tupleFieldVal(block, src, struct_byval, field_name, field_name_src, struct_ty);
+ } else {
+ const field_index = try sema.anonStructFieldIndex(block, struct_ty, field_name, field_name_src);
+ return sema.tupleFieldValByIndex(block, src, struct_byval, field_index, struct_ty);
+ }
+ },
else => unreachable,
}
}
@@ -24354,12 +25811,13 @@ fn tupleFieldVal(
block: *Block,
src: LazySrcLoc,
tuple_byval: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
tuple_ty: Type,
) CompileError!Air.Inst.Ref {
- if (mem.eql(u8, field_name, "len")) {
- return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount());
+ const mod = sema.mod;
+ if (mod.intern_pool.stringEqlSlice(field_name, "len")) {
+ return sema.addIntUnsigned(Type.usize, tuple_ty.structFieldCount(mod));
}
const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_name_src);
return sema.tupleFieldValByIndex(block, src, tuple_byval, field_index, tuple_ty);
@@ -24370,19 +25828,20 @@ fn tupleFieldIndex(
sema: *Sema,
block: *Block,
tuple_ty: Type,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
) CompileError!u32 {
- assert(!std.mem.eql(u8, field_name, "len"));
- if (std.fmt.parseUnsigned(u32, field_name, 10)) |field_index| {
- if (field_index < tuple_ty.structFieldCount()) return field_index;
- return sema.fail(block, field_name_src, "index '{s}' out of bounds of tuple '{}'", .{
- field_name, tuple_ty.fmt(sema.mod),
+ const mod = sema.mod;
+ assert(!mod.intern_pool.stringEqlSlice(field_name, "len"));
+ if (field_name.toUnsigned(&mod.intern_pool)) |field_index| {
+ if (field_index < tuple_ty.structFieldCount(mod)) return field_index;
+ return sema.fail(block, field_name_src, "index '{}' out of bounds of tuple '{}'", .{
+ field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod),
});
- } else |_| {}
+ }
- return sema.fail(block, field_name_src, "no field named '{s}' in tuple '{}'", .{
- field_name, tuple_ty.fmt(sema.mod),
+ return sema.fail(block, field_name_src, "no field named '{}' in tuple '{}'", .{
+ field_name.fmt(&mod.intern_pool), tuple_ty.fmt(mod),
});
}
@@ -24394,22 +25853,29 @@ fn tupleFieldValByIndex(
field_index: u32,
tuple_ty: Type,
) CompileError!Air.Inst.Ref {
- const field_ty = tuple_ty.structFieldType(field_index);
+ const mod = sema.mod;
+ const field_ty = tuple_ty.structFieldType(field_index, mod);
- if (tuple_ty.structFieldValueComptime(field_index)) |default_value| {
+ if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| {
return sema.addConstant(field_ty, default_value);
}
if (try sema.resolveMaybeUndefVal(tuple_byval)) |tuple_val| {
- if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
if ((try sema.typeHasOnePossibleValue(field_ty))) |opv| {
return sema.addConstant(field_ty, opv);
}
- const field_values = tuple_val.castTag(.aggregate).?.data;
- return sema.addConstant(field_ty, field_values[field_index]);
+ return switch (mod.intern_pool.indexToKey(tuple_val.toIntern())) {
+ .undef => sema.addConstUndef(field_ty),
+ .aggregate => |aggregate| sema.addConstant(field_ty, switch (aggregate.storage) {
+ .bytes => |bytes| try mod.intValue(Type.u8, bytes[0]),
+ .elems => |elems| elems[field_index].toValue(),
+ .repeated_elem => |elem| elem.toValue(),
+ }),
+ else => unreachable,
+ };
}
- if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
+ if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
return sema.addConstant(field_ty, default_val);
}
@@ -24422,33 +25888,38 @@ fn unionFieldPtr(
block: *Block,
src: LazySrcLoc,
union_ptr: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
unresolved_union_ty: Type,
initializing: bool,
) CompileError!Air.Inst.Ref {
const arena = sema.arena;
- assert(unresolved_union_ty.zigTypeTag() == .Union);
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
+
+ assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
const union_ptr_ty = sema.typeOf(union_ptr);
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(union_ty).?;
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
const field = union_obj.fields.values()[field_index];
- const ptr_field_ty = try Type.ptr(arena, sema.mod, .{
+ const ptr_field_ty = try Type.ptr(arena, mod, .{
.pointee_type = field.ty,
- .mutable = union_ptr_ty.ptrIsMutable(),
- .@"volatile" = union_ptr_ty.isVolatilePtr(),
- .@"addrspace" = union_ptr_ty.ptrAddressSpace(),
+ .mutable = union_ptr_ty.ptrIsMutable(mod),
+ .@"volatile" = union_ptr_ty.isVolatilePtr(mod),
+ .@"addrspace" = union_ptr_ty.ptrAddressSpace(mod),
});
- const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
+ const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?);
- if (initializing and field.ty.zigTypeTag() == .NoReturn) {
+ if (initializing and field.ty.zigTypeTag(mod) == .NoReturn) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "cannot initialize 'noreturn' field of union", .{});
errdefer msg.destroy(sema.gpa);
- try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
+ try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
+ field_name.fmt(ip),
+ });
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
};
@@ -24460,21 +25931,20 @@ fn unionFieldPtr(
.Auto => if (!initializing) {
const union_val = (try sema.pointerDeref(block, src, union_ptr_val, union_ptr_ty)) orelse
break :ct;
- if (union_val.isUndef()) {
+ if (union_val.isUndef(mod)) {
return sema.failWithUseOfUndef(block, src);
}
- const tag_and_val = union_val.castTag(.@"union").?.data;
- var field_tag_buf: Value.Payload.U32 = .{
- .base = .{ .tag = .enum_field_index },
- .data = enum_field_index,
- };
- const field_tag = Value.initPayload(&field_tag_buf.base);
- const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
+ const un = ip.indexToKey(union_val.toIntern()).un;
+ const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
+ const tag_matches = un.tag == field_tag.toIntern();
if (!tag_matches) {
const msg = msg: {
- const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
- const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
- const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
+ const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?;
+ const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);
+ const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{
+ field_name.fmt(ip),
+ active_field_name.fmt(ip),
+ });
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
@@ -24484,28 +25954,27 @@ fn unionFieldPtr(
},
.Packed, .Extern => {},
}
- return sema.addConstant(
- ptr_field_ty,
- try Value.Tag.field_ptr.create(arena, .{
- .container_ptr = union_ptr_val,
- .container_ty = union_ty,
- .field_index = field_index,
- }),
- );
+ return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = union_ptr_val.toIntern(),
+ .index = field_index,
+ } },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, src, null);
if (!initializing and union_obj.layout == .Auto and block.wantSafety() and
- union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
+ union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
{
- const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
+ const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
// TODO would it be better if get_union_tag supported pointers to unions?
const union_val = try block.addTyOp(.load, union_ty, union_ptr);
const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_val);
try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
}
- if (field.ty.zigTypeTag() == .NoReturn) {
+ if (field.ty.zigTypeTag(mod) == .NoReturn) {
_ = try block.addNoOp(.unreach);
return Air.Inst.Ref.unreachable_value;
}
@@ -24517,37 +25986,37 @@ fn unionFieldVal(
block: *Block,
src: LazySrcLoc,
union_byval: Air.Inst.Ref,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_name_src: LazySrcLoc,
unresolved_union_ty: Type,
) CompileError!Air.Inst.Ref {
- assert(unresolved_union_ty.zigTypeTag() == .Union);
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
+ assert(unresolved_union_ty.zigTypeTag(mod) == .Union);
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(union_ty).?;
const field_index = try sema.unionFieldIndex(block, union_ty, field_name, field_name_src);
const field = union_obj.fields.values()[field_index];
- const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name).?);
+ const enum_field_index = @intCast(u32, union_obj.tag_ty.enumFieldIndex(field_name, mod).?);
if (try sema.resolveMaybeUndefVal(union_byval)) |union_val| {
- if (union_val.isUndef()) return sema.addConstUndef(field.ty);
+ if (union_val.isUndef(mod)) return sema.addConstUndef(field.ty);
- const tag_and_val = union_val.castTag(.@"union").?.data;
- var field_tag_buf: Value.Payload.U32 = .{
- .base = .{ .tag = .enum_field_index },
- .data = enum_field_index,
- };
- const field_tag = Value.initPayload(&field_tag_buf.base);
- const tag_matches = tag_and_val.tag.eql(field_tag, union_obj.tag_ty, sema.mod);
+ const un = ip.indexToKey(union_val.toIntern()).un;
+ const field_tag = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
+ const tag_matches = un.tag == field_tag.toIntern();
switch (union_obj.layout) {
.Auto => {
if (tag_matches) {
- return sema.addConstant(field.ty, tag_and_val.val);
+ return sema.addConstant(field.ty, un.val.toValue());
} else {
const msg = msg: {
- const active_index = tag_and_val.tag.castTag(.enum_field_index).?.data;
- const active_field_name = union_obj.tag_ty.enumFieldName(active_index);
- const msg = try sema.errMsg(block, src, "access of union field '{s}' while field '{s}' is active", .{ field_name, active_field_name });
+ const active_index = union_obj.tag_ty.enumTagFieldIndex(un.tag.toValue(), mod).?;
+ const active_field_name = union_obj.tag_ty.enumFieldName(active_index, mod);
+ const msg = try sema.errMsg(block, src, "access of union field '{}' while field '{}' is active", .{
+ field_name.fmt(ip), active_field_name.fmt(ip),
+ });
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
@@ -24557,10 +26026,10 @@ fn unionFieldVal(
},
.Packed, .Extern => {
if (tag_matches) {
- return sema.addConstant(field.ty, tag_and_val.val);
+ return sema.addConstant(field.ty, un.val.toValue());
} else {
- const old_ty = union_ty.unionFieldType(tag_and_val.tag, sema.mod);
- if (try sema.bitCastVal(block, src, tag_and_val.val, old_ty, field.ty, 0)) |new_val| {
+ const old_ty = union_ty.unionFieldType(un.tag.toValue(), mod);
+ if (try sema.bitCastVal(block, src, un.val.toValue(), old_ty, field.ty, 0)) |new_val| {
return sema.addConstant(field.ty, new_val);
}
}
@@ -24570,14 +26039,14 @@ fn unionFieldVal(
try sema.requireRuntimeBlock(block, src, null);
if (union_obj.layout == .Auto and block.wantSafety() and
- union_ty.unionTagTypeSafety() != null and union_obj.fields.count() > 1)
+ union_ty.unionTagTypeSafety(mod) != null and union_obj.fields.count() > 1)
{
- const wanted_tag_val = try Value.Tag.enum_field_index.create(sema.arena, enum_field_index);
+ const wanted_tag_val = try mod.enumValueFieldIndex(union_obj.tag_ty, enum_field_index);
const wanted_tag = try sema.addConstant(union_obj.tag_ty, wanted_tag_val);
const active_tag = try block.addTyOp(.get_union_tag, union_obj.tag_ty, union_byval);
try sema.panicInactiveUnionField(block, active_tag, wanted_tag);
}
- if (field.ty.zigTypeTag() == .NoReturn) {
+ if (field.ty.zigTypeTag(mod) == .NoReturn) {
_ = try block.addNoOp(.unreach);
return Air.Inst.Ref.unreachable_value;
}
@@ -24594,24 +26063,22 @@ fn elemPtr(
init: bool,
oob_safety: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const indexable_ptr_src = src; // TODO better source location
const indexable_ptr_ty = sema.typeOf(indexable_ptr);
- const target = sema.mod.getTarget();
- const indexable_ty = switch (indexable_ptr_ty.zigTypeTag()) {
- .Pointer => indexable_ptr_ty.elemType(),
- else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(sema.mod)}),
+ const indexable_ty = switch (indexable_ptr_ty.zigTypeTag(mod)) {
+ .Pointer => indexable_ptr_ty.childType(mod),
+ else => return sema.fail(block, indexable_ptr_src, "expected pointer, found '{}'", .{indexable_ptr_ty.fmt(mod)}),
};
- if (!indexable_ty.isIndexable()) {
- return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)});
- }
+ try checkIndexable(sema, block, src, indexable_ty);
- switch (indexable_ty.zigTypeTag()) {
+ switch (indexable_ty.zigTypeTag(mod)) {
.Array, .Vector => return sema.elemPtrArray(block, src, indexable_ptr_src, indexable_ptr, elem_index_src, elem_index, init, oob_safety),
.Struct => {
// Tuple field access.
const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
- const index = @intCast(u32, index_val.toUnsignedInt(target));
+ const index = @intCast(u32, index_val.toUnsignedInt(mod));
return sema.tupleFieldPtr(block, src, indexable_ptr, elem_index_src, index, init);
},
else => {
@@ -24634,13 +26101,11 @@ fn elemPtrOneLayerOnly(
) CompileError!Air.Inst.Ref {
const indexable_src = src; // TODO better source location
const indexable_ty = sema.typeOf(indexable);
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
- if (!indexable_ty.isIndexable()) {
- return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)});
- }
+ try checkIndexable(sema, block, src, indexable_ty);
- switch (indexable_ty.ptrSize()) {
+ switch (indexable_ty.ptrSize(mod)) {
.Slice => return sema.elemPtrSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
.Many, .C => {
const maybe_ptr_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
@@ -24648,9 +26113,9 @@ fn elemPtrOneLayerOnly(
const runtime_src = rs: {
const ptr_val = maybe_ptr_val orelse break :rs indexable_src;
const index_val = maybe_index_val orelse break :rs elem_index_src;
- const index = @intCast(usize, index_val.toUnsignedInt(target));
- const elem_ptr = try ptr_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);
+ const index = @intCast(usize, index_val.toUnsignedInt(mod));
const result_ty = try sema.elemPtrType(indexable_ty, index);
+ const elem_ptr = try ptr_val.elemPtr(result_ty, index, mod);
return sema.addConstant(result_ty, elem_ptr);
};
const result_ty = try sema.elemPtrType(indexable_ty, null);
@@ -24659,8 +26124,19 @@ fn elemPtrOneLayerOnly(
return block.addPtrElemPtr(indexable, elem_index, result_ty);
},
.One => {
- assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
- return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety);
+ const child_ty = indexable_ty.childType(mod);
+ switch (child_ty.zigTypeTag(mod)) {
+ .Array, .Vector => {
+ return sema.elemPtrArray(block, src, indexable_src, indexable, elem_index_src, elem_index, init, oob_safety);
+ },
+ .Struct => {
+ assert(child_ty.isTuple(mod));
+ const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
+ const index = @intCast(u32, index_val.toUnsignedInt(mod));
+ return sema.tupleFieldPtr(block, indexable_src, indexable, elem_index_src, index, false);
+ },
+ else => unreachable, // Guaranteed by checkIndexable
+ }
},
}
}
@@ -24676,18 +26152,16 @@ fn elemVal(
) CompileError!Air.Inst.Ref {
const indexable_src = src; // TODO better source location
const indexable_ty = sema.typeOf(indexable);
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
- if (!indexable_ty.isIndexable()) {
- return sema.fail(block, src, "element access of non-indexable type '{}'", .{indexable_ty.fmt(sema.mod)});
- }
+ try checkIndexable(sema, block, src, indexable_ty);
// TODO in case of a vector of pointers, we need to detect whether the element
// index is a scalar or vector instead of unconditionally casting to usize.
const elem_index = try sema.coerce(block, Type.usize, elem_index_uncasted, elem_index_src);
- switch (indexable_ty.zigTypeTag()) {
- .Pointer => switch (indexable_ty.ptrSize()) {
+ switch (indexable_ty.zigTypeTag(mod)) {
+ .Pointer => switch (indexable_ty.ptrSize(mod)) {
.Slice => return sema.elemValSlice(block, src, indexable_src, indexable, elem_index_src, elem_index, oob_safety),
.Many, .C => {
const maybe_indexable_val = try sema.resolveDefinedValue(block, indexable_src, indexable);
@@ -24696,10 +26170,14 @@ fn elemVal(
const runtime_src = rs: {
const indexable_val = maybe_indexable_val orelse break :rs indexable_src;
const index_val = maybe_index_val orelse break :rs elem_index_src;
- const index = @intCast(usize, index_val.toUnsignedInt(target));
- const elem_ptr_val = try indexable_val.elemPtr(indexable_ty, sema.arena, index, sema.mod);
- if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, indexable_ty)) |elem_val| {
- return sema.addConstant(indexable_ty.elemType2(), elem_val);
+ const index = @intCast(usize, index_val.toUnsignedInt(mod));
+ const elem_ty = indexable_ty.elemType2(mod);
+ const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
+ const many_ptr_val = try mod.getCoerced(indexable_val, many_ptr_ty);
+ const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
+ const elem_ptr_val = try many_ptr_val.elemPtr(elem_ptr_ty, index, mod);
+ if (try sema.pointerDeref(block, indexable_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
+ return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty));
}
break :rs indexable_src;
};
@@ -24708,7 +26186,15 @@ fn elemVal(
return block.addBinOp(.ptr_elem_val, indexable, elem_index);
},
.One => {
- assert(indexable_ty.childType().zigTypeTag() == .Array); // Guaranteed by isIndexable
+ arr_sent: {
+ const inner_ty = indexable_ty.childType(mod);
+ if (inner_ty.zigTypeTag(mod) != .Array) break :arr_sent;
+ const sentinel = inner_ty.sentinel(mod) orelse break :arr_sent;
+ const index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index) orelse break :arr_sent;
+ const index = try sema.usizeCast(block, src, index_val.toUnsignedInt(mod));
+ if (index != inner_ty.arrayLen(mod)) break :arr_sent;
+ return sema.addConstant(inner_ty.childType(mod), sentinel);
+ }
const elem_ptr = try sema.elemPtr(block, indexable_src, indexable, elem_index, elem_index_src, false, oob_safety);
return sema.analyzeLoad(block, indexable_src, elem_ptr, elem_index_src);
},
@@ -24721,7 +26207,7 @@ fn elemVal(
.Struct => {
// Tuple field access.
const index_val = try sema.resolveConstValue(block, elem_index_src, elem_index, "tuple field access index must be comptime-known");
- const index = @intCast(u32, index_val.toUnsignedInt(target));
+ const index = @intCast(u32, index_val.toUnsignedInt(mod));
return sema.tupleField(block, indexable_src, indexable, elem_index_src, index);
},
else => unreachable,
@@ -24736,6 +26222,7 @@ fn validateRuntimeElemAccess(
parent_ty: Type,
parent_src: LazySrcLoc,
) CompileError!void {
+ const mod = sema.mod;
const valid_rt = try sema.validateRunTimeType(elem_ty, false);
if (!valid_rt) {
const msg = msg: {
@@ -24743,12 +26230,12 @@ fn validateRuntimeElemAccess(
block,
elem_index_src,
"values of type '{}' must be comptime-known, but index value is runtime-known",
- .{parent_ty.fmt(sema.mod)},
+ .{parent_ty.fmt(mod)},
);
errdefer msg.destroy(sema.gpa);
- const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsComptime(block, elem_index_src, msg, parent_src.toSrcLoc(src_decl), parent_ty);
+ const src_decl = mod.declPtr(block.src_decl);
+ try sema.explainWhyTypeIsComptime(msg, parent_src.toSrcLoc(src_decl, mod), parent_ty);
break :msg msg;
};
@@ -24765,10 +26252,11 @@ fn tupleFieldPtr(
field_index: u32,
init: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const tuple_ptr_ty = sema.typeOf(tuple_ptr);
- const tuple_ty = tuple_ptr_ty.childType();
+ const tuple_ty = tuple_ptr_ty.childType(mod);
_ = try sema.resolveTypeFields(tuple_ty);
- const field_count = tuple_ty.structFieldCount();
+ const field_count = tuple_ty.structFieldCount(mod);
if (field_count == 0) {
return sema.fail(block, tuple_ptr_src, "indexing into empty tuple is not allowed", .{});
@@ -24780,31 +26268,29 @@ fn tupleFieldPtr(
});
}
- const field_ty = tuple_ty.structFieldType(field_index);
- const ptr_field_ty = try Type.ptr(sema.arena, sema.mod, .{
+ const field_ty = tuple_ty.structFieldType(field_index, mod);
+ const ptr_field_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = field_ty,
- .mutable = tuple_ptr_ty.ptrIsMutable(),
- .@"volatile" = tuple_ptr_ty.isVolatilePtr(),
- .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(),
+ .mutable = tuple_ptr_ty.ptrIsMutable(mod),
+ .@"volatile" = tuple_ptr_ty.isVolatilePtr(mod),
+ .@"addrspace" = tuple_ptr_ty.ptrAddressSpace(mod),
});
- if (tuple_ty.structFieldValueComptime(field_index)) |default_val| {
- const val = try Value.Tag.comptime_field_ptr.create(sema.arena, .{
- .field_ty = field_ty,
- .field_val = default_val,
- });
- return sema.addConstant(ptr_field_ty, val);
+ if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_val| {
+ return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .comptime_field = default_val.toIntern() },
+ } })).toValue());
}
if (try sema.resolveMaybeUndefVal(tuple_ptr)) |tuple_ptr_val| {
- return sema.addConstant(
- ptr_field_ty,
- try Value.Tag.field_ptr.create(sema.arena, .{
- .container_ptr = tuple_ptr_val,
- .container_ty = tuple_ty,
- .field_index = field_index,
- }),
- );
+ return sema.addConstant(ptr_field_ty, (try mod.intern(.{ .ptr = .{
+ .ty = ptr_field_ty.toIntern(),
+ .addr = .{ .field = .{
+ .base = tuple_ptr_val.toIntern(),
+ .index = field_index,
+ } },
+ } })).toValue());
}
if (!init) {
@@ -24823,8 +26309,9 @@ fn tupleField(
field_index_src: LazySrcLoc,
field_index: u32,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const tuple_ty = try sema.resolveTypeFields(sema.typeOf(tuple));
- const field_count = tuple_ty.structFieldCount();
+ const field_count = tuple_ty.structFieldCount(mod);
if (field_count == 0) {
return sema.fail(block, tuple_src, "indexing into empty tuple is not allowed", .{});
@@ -24836,15 +26323,15 @@ fn tupleField(
});
}
- const field_ty = tuple_ty.structFieldType(field_index);
+ const field_ty = tuple_ty.structFieldType(field_index, mod);
- if (tuple_ty.structFieldValueComptime(field_index)) |default_value| {
+ if (try tuple_ty.structFieldValueComptime(mod, field_index)) |default_value| {
return sema.addConstant(field_ty, default_value); // comptime field
}
if (try sema.resolveMaybeUndefVal(tuple)) |tuple_val| {
- if (tuple_val.isUndef()) return sema.addConstUndef(field_ty);
- return sema.addConstant(field_ty, tuple_val.fieldValue(tuple_ty, field_index));
+ if (tuple_val.isUndef(mod)) return sema.addConstUndef(field_ty);
+ return sema.addConstant(field_ty, try tuple_val.fieldValue(mod, field_index));
}
try sema.validateRuntimeElemAccess(block, field_index_src, field_ty, tuple_ty, tuple_src);
@@ -24863,11 +26350,12 @@ fn elemValArray(
elem_index: Air.Inst.Ref,
oob_safety: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const array_ty = sema.typeOf(array);
- const array_sent = array_ty.sentinel();
- const array_len = array_ty.arrayLen();
+ const array_sent = array_ty.sentinel(mod);
+ const array_len = array_ty.arrayLen(mod);
const array_len_s = array_len + @boolToInt(array_sent != null);
- const elem_ty = array_ty.childType();
+ const elem_ty = array_ty.childType(mod);
if (array_len_s == 0) {
return sema.fail(block, array_src, "indexing into empty array is not allowed", .{});
@@ -24876,10 +26364,9 @@ fn elemValArray(
const maybe_undef_array_val = try sema.resolveMaybeUndefVal(array);
// index must be defined since it can access out of bounds
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
- const target = sema.mod.getTarget();
if (maybe_index_val) |index_val| {
- const index = @intCast(usize, index_val.toUnsignedInt(target));
+ const index = @intCast(usize, index_val.toUnsignedInt(mod));
if (array_sent) |s| {
if (index == array_len) {
return sema.addConstant(elem_ty, s);
@@ -24891,12 +26378,12 @@ fn elemValArray(
}
}
if (maybe_undef_array_val) |array_val| {
- if (array_val.isUndef()) {
+ if (array_val.isUndef(mod)) {
return sema.addConstUndef(elem_ty);
}
if (maybe_index_val) |index_val| {
- const index = @intCast(usize, index_val.toUnsignedInt(target));
- const elem_val = try array_val.elemValue(sema.mod, sema.arena, index);
+ const index = @intCast(usize, index_val.toUnsignedInt(mod));
+ const elem_val = try array_val.elemValue(mod, index);
return sema.addConstant(elem_ty, elem_val);
}
}
@@ -24927,11 +26414,11 @@ fn elemPtrArray(
init: bool,
oob_safety: bool,
) CompileError!Air.Inst.Ref {
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
const array_ptr_ty = sema.typeOf(array_ptr);
- const array_ty = array_ptr_ty.childType();
- const array_sent = array_ty.sentinel() != null;
- const array_len = array_ty.arrayLen();
+ const array_ty = array_ptr_ty.childType(mod);
+ const array_sent = array_ty.sentinel(mod) != null;
+ const array_len = array_ty.arrayLen(mod);
const array_len_s = array_len + @boolToInt(array_sent);
if (array_len_s == 0) {
@@ -24941,7 +26428,7 @@ fn elemPtrArray(
const maybe_undef_array_ptr_val = try sema.resolveMaybeUndefVal(array_ptr);
// The index must not be undefined since it can be out of bounds.
const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
- const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target));
+ const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod));
if (index >= array_len_s) {
const sentinel_label: []const u8 = if (array_sent) " +1 (sentinel)" else "";
return sema.fail(block, elem_index_src, "index {d} outside array of length {d}{s}", .{ index, array_len, sentinel_label });
@@ -24952,17 +26439,17 @@ fn elemPtrArray(
const elem_ptr_ty = try sema.elemPtrType(array_ptr_ty, offset);
if (maybe_undef_array_ptr_val) |array_ptr_val| {
- if (array_ptr_val.isUndef()) {
+ if (array_ptr_val.isUndef(mod)) {
return sema.addConstUndef(elem_ptr_ty);
}
if (offset) |index| {
- const elem_ptr = try array_ptr_val.elemPtr(array_ptr_ty, sema.arena, index, sema.mod);
+ const elem_ptr = try array_ptr_val.elemPtr(elem_ptr_ty, index, mod);
return sema.addConstant(elem_ptr_ty, elem_ptr);
}
}
if (!init) {
- try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(), array_ty, array_ptr_src);
+ try sema.validateRuntimeElemAccess(block, elem_index_src, array_ty.elemType2(mod), array_ty, array_ptr_src);
}
const runtime_src = if (maybe_undef_array_ptr_val != null) elem_index_src else array_ptr_src;
@@ -24988,32 +26475,33 @@ fn elemValSlice(
elem_index: Air.Inst.Ref,
oob_safety: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const slice_ty = sema.typeOf(slice);
- const slice_sent = slice_ty.sentinel() != null;
- const elem_ty = slice_ty.elemType2();
+ const slice_sent = slice_ty.sentinel(mod) != null;
+ const elem_ty = slice_ty.elemType2(mod);
var runtime_src = slice_src;
// slice must be defined since it can dereferenced as null
const maybe_slice_val = try sema.resolveDefinedValue(block, slice_src, slice);
// index must be defined since it can index out of bounds
const maybe_index_val = try sema.resolveDefinedValue(block, elem_index_src, elem_index);
- const target = sema.mod.getTarget();
if (maybe_slice_val) |slice_val| {
runtime_src = elem_index_src;
- const slice_len = slice_val.sliceLen(sema.mod);
+ const slice_len = slice_val.sliceLen(mod);
const slice_len_s = slice_len + @boolToInt(slice_sent);
if (slice_len_s == 0) {
return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
}
if (maybe_index_val) |index_val| {
- const index = @intCast(usize, index_val.toUnsignedInt(target));
+ const index = @intCast(usize, index_val.toUnsignedInt(mod));
if (index >= slice_len_s) {
const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
}
- const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod);
- if (try sema.pointerDeref(block, slice_src, elem_ptr_val, slice_ty)) |elem_val| {
+ const elem_ptr_ty = try sema.elemPtrType(slice_ty, index);
+ const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
+ if (try sema.pointerDeref(block, slice_src, elem_ptr_val, elem_ptr_ty)) |elem_val| {
return sema.addConstant(elem_ty, elem_val);
}
runtime_src = slice_src;
@@ -25025,7 +26513,7 @@ fn elemValSlice(
try sema.requireRuntimeBlock(block, src, runtime_src);
if (oob_safety and block.wantSafety()) {
const len_inst = if (maybe_slice_val) |slice_val|
- try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod))
+ try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod))
else
try block.addTyOp(.slice_len, Type.usize, slice);
const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
@@ -25045,24 +26533,24 @@ fn elemPtrSlice(
elem_index: Air.Inst.Ref,
oob_safety: bool,
) CompileError!Air.Inst.Ref {
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
const slice_ty = sema.typeOf(slice);
- const slice_sent = slice_ty.sentinel() != null;
+ const slice_sent = slice_ty.sentinel(mod) != null;
const maybe_undef_slice_val = try sema.resolveMaybeUndefVal(slice);
// The index must not be undefined since it can be out of bounds.
const offset: ?usize = if (try sema.resolveDefinedValue(block, elem_index_src, elem_index)) |index_val| o: {
- const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(target));
+ const index = try sema.usizeCast(block, elem_index_src, index_val.toUnsignedInt(mod));
break :o index;
} else null;
const elem_ptr_ty = try sema.elemPtrType(slice_ty, offset);
if (maybe_undef_slice_val) |slice_val| {
- if (slice_val.isUndef()) {
+ if (slice_val.isUndef(mod)) {
return sema.addConstUndef(elem_ptr_ty);
}
- const slice_len = slice_val.sliceLen(sema.mod);
+ const slice_len = slice_val.sliceLen(mod);
const slice_len_s = slice_len + @boolToInt(slice_sent);
if (slice_len_s == 0) {
return sema.fail(block, slice_src, "indexing into empty slice is not allowed", .{});
@@ -25072,7 +26560,7 @@ fn elemPtrSlice(
const sentinel_label: []const u8 = if (slice_sent) " +1 (sentinel)" else "";
return sema.fail(block, elem_index_src, "index {d} outside slice of length {d}{s}", .{ index, slice_len, sentinel_label });
}
- const elem_ptr_val = try slice_val.elemPtr(slice_ty, sema.arena, index, sema.mod);
+ const elem_ptr_val = try slice_val.elemPtr(elem_ptr_ty, index, mod);
return sema.addConstant(elem_ptr_ty, elem_ptr_val);
}
}
@@ -25084,8 +26572,8 @@ fn elemPtrSlice(
if (oob_safety and block.wantSafety()) {
const len_inst = len: {
if (maybe_undef_slice_val) |slice_val|
- if (!slice_val.isUndef())
- break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod));
+ if (!slice_val.isUndef(mod))
+ break :len try sema.addIntUnsigned(Type.usize, slice_val.sliceLen(mod));
break :len try block.addTyOp(.slice_len, Type.usize, slice);
};
const cmp_op: Air.Inst.Tag = if (slice_sent) .cmp_lte else .cmp_lt;
@@ -25127,16 +26615,17 @@ const CoerceOpts = struct {
fn get(info: @This(), sema: *Sema) !?Module.SrcLoc {
if (info.func_inst == .none) return null;
+ const mod = sema.mod;
const fn_decl = (try sema.funcDeclSrc(info.func_inst)) orelse return null;
- const param_src = Module.paramSrc(0, sema.gpa, fn_decl, info.param_i);
+ const param_src = Module.paramSrc(0, mod, fn_decl, info.param_i);
if (param_src == .node_offset_param) {
return Module.SrcLoc{
- .file_scope = fn_decl.getFileScope(),
+ .file_scope = fn_decl.getFileScope(mod),
.parent_decl_node = fn_decl.src_node,
.lazy = LazySrcLoc.nodeOffset(param_src.node_offset_param),
};
}
- return param_src.toSrcLoc(fn_decl);
+ return param_src.toSrcLoc(fn_decl, mod);
}
} = .{},
};
@@ -25149,35 +26638,30 @@ fn coerceExtra(
inst_src: LazySrcLoc,
opts: CoerceOpts,
) CoersionError!Air.Inst.Ref {
- switch (dest_ty_unresolved.tag()) {
- .var_args_param => return sema.coerceVarArgParam(block, inst, inst_src),
- .generic_poison => return inst,
- else => {},
- }
+ if (dest_ty_unresolved.isGenericPoison()) return inst;
+ const mod = sema.mod;
const dest_ty_src = inst_src; // TODO better source location
const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);
const inst_ty = try sema.resolveTypeFields(sema.typeOf(inst));
- const target = sema.mod.getTarget();
+ const target = mod.getTarget();
// If the types are the same, we can return the operand.
- if (dest_ty.eql(inst_ty, sema.mod))
+ if (dest_ty.eql(inst_ty, mod))
return inst;
- const arena = sema.arena;
const maybe_inst_val = try sema.resolveMaybeUndefVal(inst);
var in_memory_result = try sema.coerceInMemoryAllowed(block, dest_ty, inst_ty, false, target, dest_ty_src, inst_src);
if (in_memory_result == .ok) {
if (maybe_inst_val) |val| {
- // Keep the comptime Value representation; take the new type.
- return sema.addConstant(dest_ty, val);
+ return sema.coerceInMemory(val, dest_ty);
}
try sema.requireRuntimeBlock(block, inst_src, null);
return block.addBitCast(dest_ty, inst);
}
- const is_undef = inst_ty.zigTypeTag() == .Undefined;
+ const is_undef = inst_ty.zigTypeTag(mod) == .Undefined;
- switch (dest_ty.zigTypeTag()) {
+ switch (dest_ty.zigTypeTag(mod)) {
.Optional => optional: {
// undefined sets the optional bit also to undefined.
if (is_undef) {
@@ -25185,18 +26669,22 @@ fn coerceExtra(
}
// null to ?T
- if (inst_ty.zigTypeTag() == .Null) {
- return sema.addConstant(dest_ty, Value.null);
+ if (inst_ty.zigTypeTag(mod) == .Null) {
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .opt = .{
+ .ty = dest_ty.toIntern(),
+ .val = .none,
+ } })).toValue());
}
// cast from ?*T and ?[*]T to ?*anyopaque
// but don't do it if the source type is a double pointer
- if (dest_ty.isPtrLikeOptional() and dest_ty.elemType2().tag() == .anyopaque and
- inst_ty.isPtrAtRuntime())
+ if (dest_ty.isPtrLikeOptional(mod) and
+ dest_ty.elemType2(mod).toIntern() == .anyopaque_type and
+ inst_ty.isPtrAtRuntime(mod))
anyopaque_check: {
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :optional;
- const elem_ty = inst_ty.elemType2();
- if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) {
+ const elem_ty = inst_ty.elemType2(mod);
+ if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {
in_memory_result = .{ .double_ptr_to_anyopaque = .{
.actual = inst_ty,
.wanted = dest_ty,
@@ -25205,12 +26693,12 @@ fn coerceExtra(
}
// Let the logic below handle wrapping the optional now that
// it has been checked to correctly coerce.
- if (!inst_ty.isPtrLikeOptional()) break :anyopaque_check;
+ if (!inst_ty.isPtrLikeOptional(mod)) break :anyopaque_check;
return sema.coerceCompatiblePtrs(block, dest_ty, inst, inst_src);
}
// T to ?T
- const child_type = try dest_ty.optionalChildAlloc(sema.arena);
+ const child_type = dest_ty.optionalChild(mod);
const intermediate = sema.coerceExtra(block, child_type, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
error.NotCoercible => {
if (in_memory_result == .no_match) {
@@ -25224,12 +26712,12 @@ fn coerceExtra(
return try sema.wrapOptional(block, dest_ty, intermediate, inst_src);
},
.Pointer => pointer: {
- const dest_info = dest_ty.ptrInfo().data;
+ const dest_info = dest_ty.ptrInfo(mod);
// Function body to function pointer.
- if (inst_ty.zigTypeTag() == .Fn) {
+ if (inst_ty.zigTypeTag(mod) == .Fn) {
const fn_val = try sema.resolveConstValue(block, .unneeded, inst, "");
- const fn_decl = fn_val.pointerDecl().?;
+ const fn_decl = fn_val.pointerDecl(mod).?;
const inst_as_ptr = try sema.analyzeDeclRef(fn_decl);
return sema.coerce(block, dest_ty, inst_as_ptr, inst_src);
}
@@ -25237,13 +26725,13 @@ fn coerceExtra(
// *T to *[1]T
single_item: {
if (dest_info.size != .One) break :single_item;
- if (!inst_ty.isSinglePointer()) break :single_item;
+ if (!inst_ty.isSinglePointer(mod)) break :single_item;
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
- const ptr_elem_ty = inst_ty.childType();
+ const ptr_elem_ty = inst_ty.childType(mod);
const array_ty = dest_info.pointee_type;
- if (array_ty.zigTypeTag() != .Array) break :single_item;
- const array_elem_ty = array_ty.childType();
- if (array_ty.arrayLen() != 1) break :single_item;
+ if (array_ty.zigTypeTag(mod) != .Array) break :single_item;
+ const array_elem_ty = array_ty.childType(mod);
+ if (array_ty.arrayLen(mod) != 1) break :single_item;
const dest_is_mut = dest_info.mutable;
switch (try sema.coerceInMemoryAllowed(block, array_elem_ty, ptr_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
.ok => {},
@@ -25254,11 +26742,11 @@ fn coerceExtra(
// Coercions where the source is a single pointer to an array.
src_array_ptr: {
- if (!inst_ty.isSinglePointer()) break :src_array_ptr;
+ if (!inst_ty.isSinglePointer(mod)) break :src_array_ptr;
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
- const array_ty = inst_ty.childType();
- if (array_ty.zigTypeTag() != .Array) break :src_array_ptr;
- const array_elem_type = array_ty.childType();
+ const array_ty = inst_ty.childType(mod);
+ if (array_ty.zigTypeTag(mod) != .Array) break :src_array_ptr;
+ const array_elem_type = array_ty.childType(mod);
const dest_is_mut = dest_info.mutable;
const dst_elem_type = dest_info.pointee_type;
@@ -25276,8 +26764,8 @@ fn coerceExtra(
}
if (dest_info.sentinel) |dest_sent| {
- if (array_ty.sentinel()) |inst_sent| {
- if (!dest_sent.eql(inst_sent, dst_elem_type, sema.mod)) {
+ if (array_ty.sentinel(mod)) |inst_sent| {
+ if (!dest_sent.eql(inst_sent, dst_elem_type, mod)) {
in_memory_result = .{ .ptr_sentinel = .{
.actual = inst_sent,
.wanted = dest_sent,
@@ -25287,7 +26775,7 @@ fn coerceExtra(
}
} else {
in_memory_result = .{ .ptr_sentinel = .{
- .actual = Value.initTag(.unreachable_value),
+ .actual = Value.@"unreachable",
.wanted = dest_sent,
.ty = dst_elem_type,
} };
@@ -25313,11 +26801,11 @@ fn coerceExtra(
}
// coercion from C pointer
- if (inst_ty.isCPtr()) src_c_ptr: {
+ if (inst_ty.isCPtr(mod)) src_c_ptr: {
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :src_c_ptr;
// In this case we must add a safety check because the C pointer
// could be null.
- const src_elem_ty = inst_ty.childType();
+ const src_elem_ty = inst_ty.childType(mod);
const dest_is_mut = dest_info.mutable;
const dst_elem_type = dest_info.pointee_type;
switch (try sema.coerceInMemoryAllowed(block, dst_elem_type, src_elem_ty, dest_is_mut, target, dest_ty_src, inst_src)) {
@@ -25329,17 +26817,18 @@ fn coerceExtra(
// cast from *T and [*]T to *anyopaque
// but don't do it if the source type is a double pointer
- if (dest_info.pointee_type.tag() == .anyopaque and inst_ty.zigTypeTag() == .Pointer) {
+ if (dest_info.pointee_type.toIntern() == .anyopaque_type and inst_ty.zigTypeTag(mod) == .Pointer) to_anyopaque: {
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :pointer;
- const elem_ty = inst_ty.elemType2();
- if (elem_ty.zigTypeTag() == .Pointer or elem_ty.isPtrLikeOptional()) {
+ const elem_ty = inst_ty.elemType2(mod);
+ if (elem_ty.zigTypeTag(mod) == .Pointer or elem_ty.isPtrLikeOptional(mod)) {
in_memory_result = .{ .double_ptr_to_anyopaque = .{
.actual = inst_ty,
.wanted = dest_ty,
} };
break :pointer;
}
- if (inst_ty.isSlice()) {
+ if (dest_ty.isSlice(mod)) break :to_anyopaque;
+ if (inst_ty.isSlice(mod)) {
in_memory_result = .{ .slice_to_anyopaque = .{
.actual = inst_ty,
.wanted = dest_ty,
@@ -25351,9 +26840,9 @@ fn coerceExtra(
switch (dest_info.size) {
// coercion to C pointer
- .C => switch (inst_ty.zigTypeTag()) {
+ .C => switch (inst_ty.zigTypeTag(mod)) {
.Null => {
- return sema.addConstant(dest_ty, Value.null);
+ return sema.addConstant(dest_ty, try mod.getCoerced(Value.null, dest_ty));
},
.ComptimeInt => {
const addr = sema.coerceExtra(block, Type.usize, inst, inst_src, .{ .report_err = false }) catch |err| switch (err) {
@@ -25363,7 +26852,7 @@ fn coerceExtra(
return try sema.coerceCompatiblePtrs(block, dest_ty, addr, inst_src);
},
.Int => {
- const ptr_size_ty = switch (inst_ty.intInfo(target).signedness) {
+ const ptr_size_ty = switch (inst_ty.intInfo(mod).signedness) {
.signed => Type.isize,
.unsigned => Type.usize,
};
@@ -25379,7 +26868,7 @@ fn coerceExtra(
},
.Pointer => p: {
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
- const inst_info = inst_ty.ptrInfo().data;
+ const inst_info = inst_ty.ptrInfo(mod);
switch (try sema.coerceInMemoryAllowed(
block,
dest_info.pointee_type,
@@ -25395,7 +26884,7 @@ fn coerceExtra(
if (inst_info.size == .Slice) {
assert(dest_info.sentinel == null);
if (inst_info.sentinel == null or
- !inst_info.sentinel.?.eql(Value.zero, dest_info.pointee_type, sema.mod))
+ !inst_info.sentinel.?.eql(try mod.intValue(dest_info.pointee_type, 0), dest_info.pointee_type, mod))
break :p;
const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
@@ -25405,11 +26894,11 @@ fn coerceExtra(
},
else => {},
},
- .One => switch (dest_info.pointee_type.zigTypeTag()) {
+ .One => switch (dest_info.pointee_type.zigTypeTag(mod)) {
.Union => {
// pointer to anonymous struct to pointer to union
- if (inst_ty.isSinglePointer() and
- inst_ty.childType().isAnonStruct() and
+ if (inst_ty.isSinglePointer(mod) and
+ inst_ty.childType(mod).isAnonStruct(mod) and
sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
{
return sema.coerceAnonStructToUnionPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
@@ -25417,8 +26906,8 @@ fn coerceExtra(
},
.Struct => {
// pointer to anonymous struct to pointer to struct
- if (inst_ty.isSinglePointer() and
- inst_ty.childType().isAnonStruct() and
+ if (inst_ty.isSinglePointer(mod) and
+ inst_ty.childType(mod).isAnonStruct(mod) and
sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
{
return sema.coerceAnonStructToStructPtrs(block, dest_ty, dest_ty_src, inst, inst_src) catch |err| switch (err) {
@@ -25429,8 +26918,8 @@ fn coerceExtra(
},
.Array => {
// pointer to tuple to pointer to array
- if (inst_ty.isSinglePointer() and
- inst_ty.childType().isTuple() and
+ if (inst_ty.isSinglePointer(mod) and
+ inst_ty.childType(mod).isTuple(mod) and
sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result))
{
return sema.coerceTupleToArrayPtrs(block, dest_ty, dest_ty_src, inst, inst_src);
@@ -25439,38 +26928,38 @@ fn coerceExtra(
else => {},
},
.Slice => to_slice: {
- if (inst_ty.zigTypeTag() == .Array) {
+ if (inst_ty.zigTypeTag(mod) == .Array) {
return sema.fail(
block,
inst_src,
"array literal requires address-of operator (&) to coerce to slice type '{}'",
- .{dest_ty.fmt(sema.mod)},
+ .{dest_ty.fmt(mod)},
);
}
- if (!inst_ty.isSinglePointer()) break :to_slice;
- const inst_child_ty = inst_ty.childType();
- if (!inst_child_ty.isTuple()) break :to_slice;
+ if (!inst_ty.isSinglePointer(mod)) break :to_slice;
+ const inst_child_ty = inst_ty.childType(mod);
+ if (!inst_child_ty.isTuple(mod)) break :to_slice;
// empty tuple to zero-length slice
// note that this allows coercing to a mutable slice.
- if (inst_child_ty.structFieldCount() == 0) {
+ if (inst_child_ty.structFieldCount(mod) == 0) {
// Optional slice is represented with a null pointer so
// we use a dummy pointer value with the required alignment.
- const slice_val = try Value.Tag.slice.create(sema.arena, .{
- .ptr = if (dest_info.@"align" != 0)
- try Value.Tag.int_u64.create(sema.arena, dest_info.@"align")
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .ptr = .{
+ .ty = dest_ty.toIntern(),
+ .addr = .{ .int = (if (dest_info.@"align" != 0)
+ try mod.intValue(Type.usize, dest_info.@"align")
else
- try dest_info.pointee_type.lazyAbiAlignment(target, sema.arena),
- .len = Value.zero,
- });
- return sema.addConstant(dest_ty, slice_val);
+ try mod.getCoerced(try dest_info.pointee_type.lazyAbiAlignment(mod), Type.usize)).toIntern() },
+ .len = (try mod.intValue(Type.usize, 0)).toIntern(),
+ } })).toValue());
}
// pointer to tuple to slice
if (dest_info.mutable) {
const err_msg = err_msg: {
- const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(sema.mod)});
+ const err_msg = try sema.errMsg(block, inst_src, "cannot cast pointer to tuple to '{}'", .{dest_ty.fmt(mod)});
errdefer err_msg.deinit(sema.gpa);
try sema.errNote(block, dest_ty_src, err_msg, "pointers to tuples can only coerce to constant pointers", .{});
break :err_msg err_msg;
@@ -25480,9 +26969,9 @@ fn coerceExtra(
return sema.coerceTupleToSlicePtrs(block, dest_ty, dest_ty_src, inst, inst_src);
},
.Many => p: {
- if (!inst_ty.isSlice()) break :p;
+ if (!inst_ty.isSlice(mod)) break :p;
if (!sema.checkPtrAttributes(dest_ty, inst_ty, &in_memory_result)) break :p;
- const inst_info = inst_ty.ptrInfo().data;
+ const inst_info = inst_ty.ptrInfo(mod);
switch (try sema.coerceInMemoryAllowed(
block,
@@ -25498,7 +26987,11 @@ fn coerceExtra(
}
if (dest_info.sentinel == null or inst_info.sentinel == null or
- !dest_info.sentinel.?.eql(inst_info.sentinel.?, dest_info.pointee_type, sema.mod))
+ !dest_info.sentinel.?.eql(
+ try mod.getCoerced(inst_info.sentinel.?, dest_info.pointee_type),
+ dest_info.pointee_type,
+ mod,
+ ))
break :p;
const slice_ptr = try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty);
@@ -25506,25 +26999,25 @@ fn coerceExtra(
},
}
},
- .Int, .ComptimeInt => switch (inst_ty.zigTypeTag()) {
+ .Int, .ComptimeInt => switch (inst_ty.zigTypeTag(mod)) {
.Float, .ComptimeFloat => float: {
if (is_undef) {
return sema.addConstUndef(dest_ty);
}
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
- if (dest_ty.zigTypeTag() == .ComptimeInt) {
+ if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
if (!opts.report_err) return error.NotCoercible;
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known");
}
break :float;
};
- if (val.floatHasFraction()) {
+ if (val.floatHasFraction(mod)) {
return sema.fail(
block,
inst_src,
"fractional component prevents float value '{}' from coercion to type '{}'",
- .{ val.fmtValue(inst_ty, sema.mod), dest_ty.fmt(sema.mod) },
+ .{ val.fmtValue(inst_ty, mod), dest_ty.fmt(mod) },
);
}
const result_val = try sema.floatToInt(block, inst_src, val, inst_ty, dest_ty);
@@ -25538,19 +27031,19 @@ fn coerceExtra(
// comptime-known integer to other number
if (!(try sema.intFitsInType(val, dest_ty, null))) {
if (!opts.report_err) return error.NotCoercible;
- return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) });
+ return sema.fail(block, inst_src, "type '{}' cannot represent integer value '{}'", .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) });
}
- return try sema.addConstant(dest_ty, val);
+ return try sema.addConstant(dest_ty, try mod.getCoerced(val, dest_ty));
}
- if (dest_ty.zigTypeTag() == .ComptimeInt) {
+ if (dest_ty.zigTypeTag(mod) == .ComptimeInt) {
if (!opts.report_err) return error.NotCoercible;
if (opts.no_cast_to_comptime_int) return inst;
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_int' must be comptime-known");
}
// integer widening
- const dst_info = dest_ty.intInfo(target);
- const src_info = inst_ty.intInfo(target);
+ const dst_info = dest_ty.intInfo(mod);
+ const src_info = inst_ty.intInfo(mod);
if ((src_info.signedness == dst_info.signedness and dst_info.bits >= src_info.bits) or
// small enough unsigned ints can get casted to large enough signed ints
(dst_info.signedness == .signed and dst_info.bits > src_info.bits))
@@ -25564,10 +27057,10 @@ fn coerceExtra(
},
else => {},
},
- .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag()) {
+ .Float, .ComptimeFloat => switch (inst_ty.zigTypeTag(mod)) {
.ComptimeFloat => {
const val = try sema.resolveConstValue(block, .unneeded, inst, "");
- const result_val = try val.floatCast(sema.arena, dest_ty, target);
+ const result_val = try val.floatCast(dest_ty, mod);
return try sema.addConstant(dest_ty, result_val);
},
.Float => {
@@ -25575,17 +27068,17 @@ fn coerceExtra(
return sema.addConstUndef(dest_ty);
}
if (try sema.resolveMaybeUndefVal(inst)) |val| {
- const result_val = try val.floatCast(sema.arena, dest_ty, target);
- if (!val.eql(result_val, inst_ty, sema.mod)) {
+ const result_val = try val.floatCast(dest_ty, mod);
+ if (!val.eql(try result_val.floatCast(inst_ty, mod), inst_ty, mod)) {
return sema.fail(
block,
inst_src,
"type '{}' cannot represent float value '{}'",
- .{ dest_ty.fmt(sema.mod), val.fmtValue(inst_ty, sema.mod) },
+ .{ dest_ty.fmt(mod), val.fmtValue(inst_ty, mod) },
);
}
return try sema.addConstant(dest_ty, result_val);
- } else if (dest_ty.zigTypeTag() == .ComptimeFloat) {
+ } else if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
if (!opts.report_err) return error.NotCoercible;
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known");
}
@@ -25603,13 +27096,13 @@ fn coerceExtra(
return sema.addConstUndef(dest_ty);
}
const val = (try sema.resolveMaybeUndefVal(inst)) orelse {
- if (dest_ty.zigTypeTag() == .ComptimeFloat) {
+ if (dest_ty.zigTypeTag(mod) == .ComptimeFloat) {
if (!opts.report_err) return error.NotCoercible;
return sema.failWithNeededComptime(block, inst_src, "value being casted to 'comptime_float' must be comptime-known");
}
break :int;
};
- const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, sema.mod, sema);
+ const result_val = try val.intToFloatAdvanced(sema.arena, inst_ty, dest_ty, mod, sema);
// TODO implement this compile error
//const int_again_val = try result_val.floatToInt(sema.arena, inst_ty);
//if (!int_again_val.eql(val, inst_ty, mod)) {
@@ -25617,7 +27110,7 @@ fn coerceExtra(
// block,
// inst_src,
// "type '{}' cannot represent integer value '{}'",
- // .{ dest_ty.fmt(sema.mod), val },
+ // .{ dest_ty.fmt(mod), val },
// );
//}
return try sema.addConstant(dest_ty, result_val);
@@ -25627,18 +27120,18 @@ fn coerceExtra(
},
else => {},
},
- .Enum => switch (inst_ty.zigTypeTag()) {
+ .Enum => switch (inst_ty.zigTypeTag(mod)) {
.EnumLiteral => {
// enum literal to enum
const val = try sema.resolveConstValue(block, .unneeded, inst, "");
- const bytes = val.castTag(.enum_literal).?.data;
- const field_index = dest_ty.enumFieldIndex(bytes) orelse {
+ const string = mod.intern_pool.indexToKey(val.toIntern()).enum_literal;
+ const field_index = dest_ty.enumFieldIndex(string, mod) orelse {
const msg = msg: {
const msg = try sema.errMsg(
block,
inst_src,
- "no field named '{s}' in enum '{}'",
- .{ bytes, dest_ty.fmt(sema.mod) },
+ "no field named '{}' in enum '{}'",
+ .{ string.fmt(&mod.intern_pool), dest_ty.fmt(mod) },
);
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, dest_ty);
@@ -25648,13 +27141,13 @@ fn coerceExtra(
};
return sema.addConstant(
dest_ty,
- try Value.Tag.enum_field_index.create(arena, @intCast(u32, field_index)),
+ try mod.enumValueFieldIndex(dest_ty, @intCast(u32, field_index)),
);
},
.Union => blk: {
// union to its own tag type
- const union_tag_ty = inst_ty.unionTagType() orelse break :blk;
- if (union_tag_ty.eql(dest_ty, sema.mod)) {
+ const union_tag_ty = inst_ty.unionTagType(mod) orelse break :blk;
+ if (union_tag_ty.eql(dest_ty, mod)) {
return sema.unionToTag(block, dest_ty, inst, inst_src);
}
},
@@ -25663,27 +27156,33 @@ fn coerceExtra(
},
else => {},
},
- .ErrorUnion => switch (inst_ty.zigTypeTag()) {
+ .ErrorUnion => switch (inst_ty.zigTypeTag(mod)) {
.ErrorUnion => eu: {
if (maybe_inst_val) |inst_val| {
- switch (inst_val.tag()) {
+ switch (inst_val.toIntern()) {
.undef => return sema.addConstUndef(dest_ty),
- .eu_payload => {
- const payload = try sema.addConstant(
- inst_ty.errorUnionPayload(),
- inst_val.castTag(.eu_payload).?.data,
- );
- return sema.wrapErrorUnionPayload(block, dest_ty, payload, inst_src) catch |err| switch (err) {
- error.NotCoercible => break :eu,
- else => |e| return e,
- };
- },
- else => {
- const error_set = try sema.addConstant(
- inst_ty.errorUnionSet(),
- inst_val,
- );
- return sema.wrapErrorUnionSet(block, dest_ty, error_set, inst_src);
+ else => switch (mod.intern_pool.indexToKey(inst_val.toIntern())) {
+ .error_union => |error_union| switch (error_union.val) {
+ .err_name => |err_name| {
+ const error_set_ty = inst_ty.errorUnionSet(mod);
+ const error_set_val = try sema.addConstant(error_set_ty, (try mod.intern(.{ .err = .{
+ .ty = error_set_ty.toIntern(),
+ .name = err_name,
+ } })).toValue());
+ return sema.wrapErrorUnionSet(block, dest_ty, error_set_val, inst_src);
+ },
+ .payload => |payload| {
+ const payload_val = try sema.addConstant(
+ inst_ty.errorUnionPayload(mod),
+ payload.toValue(),
+ );
+ return sema.wrapErrorUnionPayload(block, dest_ty, payload_val, inst_src) catch |err| switch (err) {
+ error.NotCoercible => break :eu,
+ else => |e| return e,
+ };
+ },
+ },
+ else => unreachable,
},
}
}
@@ -25703,10 +27202,10 @@ fn coerceExtra(
};
},
},
- .Union => switch (inst_ty.zigTypeTag()) {
+ .Union => switch (inst_ty.zigTypeTag(mod)) {
.Enum, .EnumLiteral => return sema.coerceEnumToUnion(block, dest_ty, dest_ty_src, inst, inst_src),
.Struct => {
- if (inst_ty.isAnonStruct()) {
+ if (inst_ty.isAnonStruct(mod)) {
return sema.coerceAnonStructToUnion(block, dest_ty, dest_ty_src, inst, inst_src);
}
},
@@ -25715,13 +27214,13 @@ fn coerceExtra(
},
else => {},
},
- .Array => switch (inst_ty.zigTypeTag()) {
+ .Array => switch (inst_ty.zigTypeTag(mod)) {
.Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
.Struct => {
if (inst == .empty_struct) {
return sema.arrayInitEmpty(block, inst_src, dest_ty);
}
- if (inst_ty.isTuple()) {
+ if (inst_ty.isTuple(mod)) {
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
}
},
@@ -25730,10 +27229,10 @@ fn coerceExtra(
},
else => {},
},
- .Vector => switch (inst_ty.zigTypeTag()) {
+ .Vector => switch (inst_ty.zigTypeTag(mod)) {
.Array, .Vector => return sema.coerceArrayLike(block, dest_ty, dest_ty_src, inst, inst_src),
.Struct => {
- if (inst_ty.isTuple()) {
+ if (inst_ty.isTuple(mod)) {
return sema.coerceTupleToArray(block, dest_ty, dest_ty_src, inst, inst_src);
}
},
@@ -25746,7 +27245,7 @@ fn coerceExtra(
if (inst == .empty_struct) {
return sema.structInitEmpty(block, dest_ty, dest_ty_src, inst_src);
}
- if (inst_ty.isTupleOrAnonStruct()) {
+ if (inst_ty.isTupleOrAnonStruct(mod)) {
return sema.coerceTupleToStruct(block, dest_ty, inst, inst_src) catch |err| switch (err) {
error.NotCoercible => break :blk,
else => |e| return e,
@@ -25765,35 +27264,34 @@ fn coerceExtra(
if (!opts.report_err) return error.NotCoercible;
- if (opts.is_ret and dest_ty.zigTypeTag() == .NoReturn) {
+ if (opts.is_ret and dest_ty.zigTypeTag(mod) == .NoReturn) {
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "function declared 'noreturn' returns", .{});
errdefer msg.destroy(sema.gpa);
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
- const src_decl = sema.mod.declPtr(sema.func.?.owner_decl);
- try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "'noreturn' declared here", .{});
+ const src_decl = mod.declPtr(sema.func.?.owner_decl);
+ try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "'noreturn' declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
const msg = msg: {
- const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod) });
+ const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{ dest_ty.fmt(mod), inst_ty.fmt(mod) });
errdefer msg.destroy(sema.gpa);
// E!T to T
- if (inst_ty.zigTypeTag() == .ErrorUnion and
- (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
+ if (inst_ty.zigTypeTag(mod) == .ErrorUnion and
+ (try sema.coerceInMemoryAllowed(block, inst_ty.errorUnionPayload(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
{
try sema.errNote(block, inst_src, msg, "cannot convert error union to payload type", .{});
try sema.errNote(block, inst_src, msg, "consider using 'try', 'catch', or 'if'", .{});
}
// ?T to T
- var buf: Type.Payload.ElemType = undefined;
- if (inst_ty.zigTypeTag() == .Optional and
- (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(&buf), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
+ if (inst_ty.zigTypeTag(mod) == .Optional and
+ (try sema.coerceInMemoryAllowed(block, inst_ty.optionalChild(mod), dest_ty, false, target, dest_ty_src, inst_src)) == .ok)
{
try sema.errNote(block, inst_src, msg, "cannot convert optional to payload type", .{});
try sema.errNote(block, inst_src, msg, "consider using '.?', 'orelse', or 'if'", .{});
@@ -25802,18 +27300,18 @@ fn coerceExtra(
try in_memory_result.report(sema, block, inst_src, msg);
// Add notes about function return type
- if (opts.is_ret and sema.mod.test_functions.get(sema.func.?.owner_decl) == null) {
+ if (opts.is_ret and mod.test_functions.get(sema.func.?.owner_decl) == null) {
const ret_ty_src: LazySrcLoc = .{ .node_offset_fn_type_ret_ty = 0 };
- const src_decl = sema.mod.declPtr(sema.func.?.owner_decl);
- if (inst_ty.isError() and !dest_ty.isError()) {
- try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function cannot return an error", .{});
+ const src_decl = mod.declPtr(sema.func.?.owner_decl);
+ if (inst_ty.isError(mod) and !dest_ty.isError(mod)) {
+ try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function cannot return an error", .{});
} else {
- try sema.mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl), msg, "function return type declared here", .{});
+ try mod.errNoteNonLazy(ret_ty_src.toSrcLoc(src_decl, mod), msg, "function return type declared here", .{});
}
}
if (try opts.param_src.get(sema)) |param_src| {
- try sema.mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{});
+ try mod.errNoteNonLazy(param_src, msg, "parameter type declared here", .{});
}
// TODO maybe add "cannot store an error in type '{}'" note
@@ -25823,6 +27321,14 @@ fn coerceExtra(
return sema.failWithOwnedErrorMsg(msg);
}
+fn coerceInMemory(
+ sema: *Sema,
+ val: Value,
+ dst_ty: Type,
+) CompileError!Air.Inst.Ref {
+ return sema.addConstant(dst_ty, try sema.mod.getCoerced(val, dst_ty));
+}
+
const InMemoryCoercionResult = union(enum) {
ok,
no_match: Pair,
@@ -25836,7 +27342,7 @@ const InMemoryCoercionResult = union(enum) {
optional_shape: Pair,
optional_child: PairAndChild,
from_anyerror,
- missing_error: []const []const u8,
+ missing_error: []const InternPool.NullTerminatedString,
/// true if wanted is var args
fn_var_args: bool,
/// true if wanted is generic
@@ -25936,6 +27442,7 @@ const InMemoryCoercionResult = union(enum) {
}
fn report(res: *const InMemoryCoercionResult, sema: *Sema, block: *Block, src: LazySrcLoc, msg: *Module.ErrorMsg) !void {
+ const mod = sema.mod;
var cur = res;
while (true) switch (cur.*) {
.ok => unreachable,
@@ -25952,7 +27459,7 @@ const InMemoryCoercionResult = union(enum) {
},
.error_union_payload => |pair| {
try sema.errNote(block, src, msg, "error union payload '{}' cannot cast into error union payload '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
cur = pair.child;
},
@@ -25963,20 +27470,20 @@ const InMemoryCoercionResult = union(enum) {
break;
},
.array_sentinel => |sentinel| {
- if (sentinel.actual.tag() != .unreachable_value) {
+ if (sentinel.actual.toIntern() != .unreachable_value) {
try sema.errNote(block, src, msg, "array sentinel '{}' cannot cast into array sentinel '{}'", .{
- sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
+ sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod),
});
} else {
try sema.errNote(block, src, msg, "destination array requires '{}' sentinel", .{
- sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
+ sentinel.wanted.fmtValue(sentinel.ty, mod),
});
}
break;
},
.array_elem => |pair| {
try sema.errNote(block, src, msg, "array element type '{}' cannot cast into array element type '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
cur = pair.child;
},
@@ -25988,21 +27495,19 @@ const InMemoryCoercionResult = union(enum) {
},
.vector_elem => |pair| {
try sema.errNote(block, src, msg, "vector element type '{}' cannot cast into vector element type '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
cur = pair.child;
},
.optional_shape => |pair| {
- var buf_actual: Type.Payload.ElemType = undefined;
- var buf_wanted: Type.Payload.ElemType = undefined;
try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
- pair.actual.optionalChild(&buf_actual).fmt(sema.mod), pair.wanted.optionalChild(&buf_wanted).fmt(sema.mod),
+ pair.actual.optionalChild(mod).fmt(mod), pair.wanted.optionalChild(mod).fmt(mod),
});
break;
},
.optional_child => |pair| {
try sema.errNote(block, src, msg, "optional type child '{}' cannot cast into optional type child '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
cur = pair.child;
},
@@ -26012,7 +27517,7 @@ const InMemoryCoercionResult = union(enum) {
},
.missing_error => |missing_errors| {
for (missing_errors) |err| {
- try sema.errNote(block, src, msg, "'error.{s}' not a member of destination error set", .{err});
+ try sema.errNote(block, src, msg, "'error.{}' not a member of destination error set", .{err.fmt(&mod.intern_pool)});
}
break;
},
@@ -26066,7 +27571,7 @@ const InMemoryCoercionResult = union(enum) {
},
.fn_param => |param| {
try sema.errNote(block, src, msg, "parameter {d} '{}' cannot cast into '{}'", .{
- param.index, param.actual.fmt(sema.mod), param.wanted.fmt(sema.mod),
+ param.index, param.actual.fmt(mod), param.wanted.fmt(mod),
});
cur = param.child;
},
@@ -26076,13 +27581,13 @@ const InMemoryCoercionResult = union(enum) {
},
.fn_return_type => |pair| {
try sema.errNote(block, src, msg, "return type '{}' cannot cast into return type '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
cur = pair.child;
},
.ptr_child => |pair| {
try sema.errNote(block, src, msg, "pointer type child '{}' cannot cast into pointer type child '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
cur = pair.child;
},
@@ -26091,13 +27596,13 @@ const InMemoryCoercionResult = union(enum) {
break;
},
.ptr_sentinel => |sentinel| {
- if (sentinel.actual.tag() != .unreachable_value) {
+ if (sentinel.actual.toIntern() != .unreachable_value) {
try sema.errNote(block, src, msg, "pointer sentinel '{}' cannot cast into pointer sentinel '{}'", .{
- sentinel.actual.fmtValue(sentinel.ty, sema.mod), sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
+ sentinel.actual.fmtValue(sentinel.ty, mod), sentinel.wanted.fmtValue(sentinel.ty, mod),
});
} else {
try sema.errNote(block, src, msg, "destination pointer requires '{}' sentinel", .{
- sentinel.wanted.fmtValue(sentinel.ty, sema.mod),
+ sentinel.wanted.fmtValue(sentinel.ty, mod),
});
}
break;
@@ -26117,15 +27622,15 @@ const InMemoryCoercionResult = union(enum) {
break;
},
.ptr_allowzero => |pair| {
- const wanted_allow_zero = pair.wanted.ptrAllowsZero();
- const actual_allow_zero = pair.actual.ptrAllowsZero();
+ const wanted_allow_zero = pair.wanted.ptrAllowsZero(mod);
+ const actual_allow_zero = pair.actual.ptrAllowsZero(mod);
if (actual_allow_zero and !wanted_allow_zero) {
try sema.errNote(block, src, msg, "'{}' could have null values which are illegal in type '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
} else {
try sema.errNote(block, src, msg, "mutable '{}' allows illegal null values stored to type '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
}
break;
@@ -26151,13 +27656,13 @@ const InMemoryCoercionResult = union(enum) {
},
.double_ptr_to_anyopaque => |pair| {
try sema.errNote(block, src, msg, "cannot implicitly cast double pointer '{}' to anyopaque pointer '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
break;
},
.slice_to_anyopaque => |pair| {
try sema.errNote(block, src, msg, "cannot implicitly cast slice '{}' to anyopaque pointer '{}'", .{
- pair.actual.fmt(sema.mod), pair.wanted.fmt(sema.mod),
+ pair.actual.fmt(mod), pair.wanted.fmt(mod),
});
try sema.errNote(block, src, msg, "consider using '.ptr'", .{});
break;
@@ -26194,13 +27699,18 @@ fn coerceInMemoryAllowed(
dest_src: LazySrcLoc,
src_src: LazySrcLoc,
) CompileError!InMemoryCoercionResult {
- if (dest_ty.eql(src_ty, sema.mod))
+ const mod = sema.mod;
+
+ if (dest_ty.eql(src_ty, mod))
return .ok;
+ const dest_tag = dest_ty.zigTypeTag(mod);
+ const src_tag = src_ty.zigTypeTag(mod);
+
// Differently-named integers with the same number of bits.
- if (dest_ty.zigTypeTag() == .Int and src_ty.zigTypeTag() == .Int) {
- const dest_info = dest_ty.intInfo(target);
- const src_info = src_ty.intInfo(target);
+ if (dest_tag == .Int and src_tag == .Int) {
+ const dest_info = dest_ty.intInfo(mod);
+ const src_info = src_ty.intInfo(mod);
if (dest_info.signedness == src_info.signedness and
dest_info.bits == src_info.bits)
@@ -26223,7 +27733,7 @@ fn coerceInMemoryAllowed(
}
// Differently-named floats with the same number of bits.
- if (dest_ty.zigTypeTag() == .Float and src_ty.zigTypeTag() == .Float) {
+ if (dest_tag == .Float and src_tag == .Float) {
const dest_bits = dest_ty.floatBits(target);
const src_bits = src_ty.floatBits(target);
if (dest_bits == src_bits) {
@@ -26232,10 +27742,8 @@ fn coerceInMemoryAllowed(
}
// Pointers / Pointer-like Optionals
- var dest_buf: Type.Payload.ElemType = undefined;
- var src_buf: Type.Payload.ElemType = undefined;
- const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty, &dest_buf);
- const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty, &src_buf);
+ const maybe_dest_ptr_ty = try sema.typePtrOrOptionalPtrTy(dest_ty);
+ const maybe_src_ptr_ty = try sema.typePtrOrOptionalPtrTy(src_ty);
if (maybe_dest_ptr_ty) |dest_ptr_ty| {
if (maybe_src_ptr_ty) |src_ptr_ty| {
return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ptr_ty, src_ptr_ty, dest_is_mut, target, dest_src, src_src);
@@ -26243,13 +27751,10 @@ fn coerceInMemoryAllowed(
}
// Slices
- if (dest_ty.isSlice() and src_ty.isSlice()) {
+ if (dest_ty.isSlice(mod) and src_ty.isSlice(mod)) {
return try sema.coerceInMemoryAllowedPtrs(block, dest_ty, src_ty, dest_ty, src_ty, dest_is_mut, target, dest_src, src_src);
}
- const dest_tag = dest_ty.zigTypeTag();
- const src_tag = src_ty.zigTypeTag();
-
// Functions
if (dest_tag == .Fn and src_tag == .Fn) {
return try sema.coerceInMemoryAllowedFns(block, dest_ty, src_ty, target, dest_src, src_src);
@@ -26257,8 +27762,8 @@ fn coerceInMemoryAllowed(
// Error Unions
if (dest_tag == .ErrorUnion and src_tag == .ErrorUnion) {
- const dest_payload = dest_ty.errorUnionPayload();
- const src_payload = src_ty.errorUnionPayload();
+ const dest_payload = dest_ty.errorUnionPayload(mod);
+ const src_payload = src_ty.errorUnionPayload(mod);
const child = try sema.coerceInMemoryAllowed(block, dest_payload, src_payload, dest_is_mut, target, dest_src, src_src);
if (child != .ok) {
return InMemoryCoercionResult{ .error_union_payload = .{
@@ -26267,7 +27772,7 @@ fn coerceInMemoryAllowed(
.wanted = dest_payload,
} };
}
- return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(), src_ty.errorUnionSet(), dest_is_mut, target, dest_src, src_src);
+ return try sema.coerceInMemoryAllowed(block, dest_ty.errorUnionSet(mod), src_ty.errorUnionSet(mod), dest_is_mut, target, dest_src, src_src);
}
// Error Sets
@@ -26277,8 +27782,8 @@ fn coerceInMemoryAllowed(
// Arrays
if (dest_tag == .Array and src_tag == .Array) {
- const dest_info = dest_ty.arrayInfo();
- const src_info = src_ty.arrayInfo();
+ const dest_info = dest_ty.arrayInfo(mod);
+ const src_info = src_ty.arrayInfo(mod);
if (dest_info.len != src_info.len) {
return InMemoryCoercionResult{ .array_len = .{
.actual = src_info.len,
@@ -26296,11 +27801,15 @@ fn coerceInMemoryAllowed(
}
const ok_sent = dest_info.sentinel == null or
(src_info.sentinel != null and
- dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.elem_type, sema.mod));
+ dest_info.sentinel.?.eql(
+ try mod.getCoerced(src_info.sentinel.?, dest_info.elem_type),
+ dest_info.elem_type,
+ mod,
+ ));
if (!ok_sent) {
return InMemoryCoercionResult{ .array_sentinel = .{
- .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
- .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
+ .actual = src_info.sentinel orelse Value.@"unreachable",
+ .wanted = dest_info.sentinel orelse Value.@"unreachable",
.ty = dest_info.elem_type,
} };
}
@@ -26309,8 +27818,8 @@ fn coerceInMemoryAllowed(
// Vectors
if (dest_tag == .Vector and src_tag == .Vector) {
- const dest_len = dest_ty.vectorLen();
- const src_len = src_ty.vectorLen();
+ const dest_len = dest_ty.vectorLen(mod);
+ const src_len = src_ty.vectorLen(mod);
if (dest_len != src_len) {
return InMemoryCoercionResult{ .vector_len = .{
.actual = src_len,
@@ -26318,8 +27827,8 @@ fn coerceInMemoryAllowed(
} };
}
- const dest_elem_ty = dest_ty.scalarType();
- const src_elem_ty = src_ty.scalarType();
+ const dest_elem_ty = dest_ty.scalarType(mod);
+ const src_elem_ty = src_ty.scalarType(mod);
const child = try sema.coerceInMemoryAllowed(block, dest_elem_ty, src_elem_ty, dest_is_mut, target, dest_src, src_src);
if (child != .ok) {
return InMemoryCoercionResult{ .vector_elem = .{
@@ -26340,21 +27849,37 @@ fn coerceInMemoryAllowed(
.wanted = dest_ty,
} };
}
- const dest_child_type = dest_ty.optionalChild(&dest_buf);
- const src_child_type = src_ty.optionalChild(&src_buf);
+ const dest_child_type = dest_ty.optionalChild(mod);
+ const src_child_type = src_ty.optionalChild(mod);
const child = try sema.coerceInMemoryAllowed(block, dest_child_type, src_child_type, dest_is_mut, target, dest_src, src_src);
if (child != .ok) {
return InMemoryCoercionResult{ .optional_child = .{
.child = try child.dupe(sema.arena),
- .actual = try src_child_type.copy(sema.arena),
- .wanted = try dest_child_type.copy(sema.arena),
+ .actual = src_child_type,
+ .wanted = dest_child_type,
} };
}
return .ok;
}
+ // Tuples (with in-memory-coercible fields)
+ if (dest_ty.isTuple(mod) and src_ty.isTuple(mod)) tuple: {
+ if (dest_ty.containerLayout(mod) != src_ty.containerLayout(mod)) break :tuple;
+ if (dest_ty.structFieldCount(mod) != src_ty.structFieldCount(mod)) break :tuple;
+ const field_count = dest_ty.structFieldCount(mod);
+ for (0..field_count) |field_idx| {
+ if (dest_ty.structFieldIsComptime(field_idx, mod) != src_ty.structFieldIsComptime(field_idx, mod)) break :tuple;
+ if (dest_ty.structFieldAlign(field_idx, mod) != src_ty.structFieldAlign(field_idx, mod)) break :tuple;
+ const dest_field_ty = dest_ty.structFieldType(field_idx, mod);
+ const src_field_ty = src_ty.structFieldType(field_idx, mod);
+ const field = try sema.coerceInMemoryAllowed(block, dest_field_ty, src_field_ty, dest_is_mut, target, dest_src, src_src);
+ if (field != .ok) break :tuple;
+ }
+ return .ok;
+ }
+
return InMemoryCoercionResult{ .no_match = .{
.actual = dest_ty,
.wanted = src_ty,
@@ -26369,141 +27894,108 @@ fn coerceInMemoryAllowedErrorSets(
dest_src: LazySrcLoc,
src_src: LazySrcLoc,
) !InMemoryCoercionResult {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
+ const ip = &mod.intern_pool;
+
// Coercion to `anyerror`. Note that this check can return false negatives
// in case the error sets did not get resolved.
- if (dest_ty.isAnyError()) {
+ if (dest_ty.isAnyError(mod)) {
return .ok;
}
- if (dest_ty.castTag(.error_set_inferred)) |dst_payload| {
- const dst_ies = dst_payload.data;
+ if (mod.typeToInferredErrorSetIndex(dest_ty).unwrap()) |dst_ies_index| {
+ const dst_ies = mod.inferredErrorSetPtr(dst_ies_index);
// We will make an effort to return `ok` without resolving either error set, to
// avoid unnecessary "unable to resolve error set" dependency loop errors.
- switch (src_ty.tag()) {
- .error_set_inferred => {
- // If both are inferred error sets of functions, and
- // the dest includes the source function, the coercion is OK.
- // This check is important because it works without forcing a full resolution
- // of inferred error sets.
- const src_ies = src_ty.castTag(.error_set_inferred).?.data;
-
- if (dst_ies.inferred_error_sets.contains(src_ies)) {
- return .ok;
- }
- },
- .error_set_single => {
- const name = src_ty.castTag(.error_set_single).?.data;
- if (dst_ies.errors.contains(name)) return .ok;
- },
- .error_set_merged => {
- const names = src_ty.castTag(.error_set_merged).?.data.keys();
- for (names) |name| {
- if (!dst_ies.errors.contains(name)) break;
- } else return .ok;
- },
- .error_set => {
- const names = src_ty.castTag(.error_set).?.data.names.keys();
- for (names) |name| {
- if (!dst_ies.errors.contains(name)) break;
- } else return .ok;
- },
- .anyerror => {},
- else => unreachable,
+ switch (src_ty.toIntern()) {
+ .anyerror_type => {},
+ else => switch (ip.indexToKey(src_ty.toIntern())) {
+ .inferred_error_set_type => |src_index| {
+ // If both are inferred error sets of functions, and
+ // the dest includes the source function, the coercion is OK.
+ // This check is important because it works without forcing a full resolution
+ // of inferred error sets.
+ if (dst_ies.inferred_error_sets.contains(src_index)) {
+ return .ok;
+ }
+ },
+ .error_set_type => |error_set_type| {
+ for (error_set_type.names) |name| {
+ if (!dst_ies.errors.contains(name)) break;
+ } else return .ok;
+ },
+ else => unreachable,
+ },
}
- if (dst_ies.func == sema.owner_func) {
+ if (dst_ies.func == sema.owner_func_index.unwrap()) {
// We are trying to coerce an error set to the current function's
// inferred error set.
- try dst_ies.addErrorSet(sema.gpa, src_ty);
+ try dst_ies.addErrorSet(src_ty, ip, gpa);
return .ok;
}
- try sema.resolveInferredErrorSet(block, dest_src, dst_payload.data);
+ try sema.resolveInferredErrorSet(block, dest_src, dst_ies_index);
// isAnyError might have changed from a false negative to a true positive after resolution.
- if (dest_ty.isAnyError()) {
+ if (dest_ty.isAnyError(mod)) {
return .ok;
}
}
- var missing_error_buf = std.ArrayList([]const u8).init(sema.gpa);
+ var missing_error_buf = std.ArrayList(InternPool.NullTerminatedString).init(gpa);
defer missing_error_buf.deinit();
- switch (src_ty.tag()) {
- .error_set_inferred => {
- const src_data = src_ty.castTag(.error_set_inferred).?.data;
+ switch (src_ty.toIntern()) {
+ .anyerror_type => switch (ip.indexToKey(dest_ty.toIntern())) {
+ .simple_type => unreachable, // filtered out above
+ .error_set_type, .inferred_error_set_type => return .from_anyerror,
+ else => unreachable,
+ },
- try sema.resolveInferredErrorSet(block, src_src, src_data);
- // src anyerror status might have changed after the resolution.
- if (src_ty.isAnyError()) {
- // dest_ty.isAnyError() == true is already checked for at this point.
- return .from_anyerror;
- }
+ else => switch (ip.indexToKey(src_ty.toIntern())) {
+ .inferred_error_set_type => |src_index| {
+ const src_data = mod.inferredErrorSetPtr(src_index);
- for (src_data.errors.keys()) |key| {
- if (!dest_ty.errorSetHasField(key)) {
- try missing_error_buf.append(key);
+ try sema.resolveInferredErrorSet(block, src_src, src_index);
+ // src anyerror status might have changed after the resolution.
+ if (src_ty.isAnyError(mod)) {
+ // dest_ty.isAnyError(mod) == true is already checked for at this point.
+ return .from_anyerror;
}
- }
- if (missing_error_buf.items.len != 0) {
- return InMemoryCoercionResult{
- .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
- };
- }
-
- return .ok;
- },
- .error_set_single => {
- const name = src_ty.castTag(.error_set_single).?.data;
- if (dest_ty.errorSetHasField(name)) {
- return .ok;
- }
- const list = try sema.arena.alloc([]const u8, 1);
- list[0] = name;
- return InMemoryCoercionResult{ .missing_error = list };
- },
- .error_set_merged => {
- const names = src_ty.castTag(.error_set_merged).?.data.keys();
- for (names) |name| {
- if (!dest_ty.errorSetHasField(name)) {
- try missing_error_buf.append(name);
+ for (src_data.errors.keys()) |key| {
+ if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), key)) {
+ try missing_error_buf.append(key);
+ }
}
- }
- if (missing_error_buf.items.len != 0) {
- return InMemoryCoercionResult{
- .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
- };
- }
+ if (missing_error_buf.items.len != 0) {
+ return InMemoryCoercionResult{
+ .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
+ };
+ }
- return .ok;
- },
- .error_set => {
- const names = src_ty.castTag(.error_set).?.data.names.keys();
- for (names) |name| {
- if (!dest_ty.errorSetHasField(name)) {
- try missing_error_buf.append(name);
+ return .ok;
+ },
+ .error_set_type => |error_set_type| {
+ for (error_set_type.names) |name| {
+ if (!Type.errorSetHasFieldIp(ip, dest_ty.toIntern(), name)) {
+ try missing_error_buf.append(name);
+ }
}
- }
- if (missing_error_buf.items.len != 0) {
- return InMemoryCoercionResult{
- .missing_error = try sema.arena.dupe([]const u8, missing_error_buf.items),
- };
- }
+ if (missing_error_buf.items.len != 0) {
+ return InMemoryCoercionResult{
+ .missing_error = try sema.arena.dupe(InternPool.NullTerminatedString, missing_error_buf.items),
+ };
+ }
- return .ok;
- },
- .anyerror => switch (dest_ty.tag()) {
- .error_set_inferred => unreachable, // Caught by dest_ty.isAnyError() above.
- .error_set_single, .error_set_merged, .error_set => return .from_anyerror,
- .anyerror => unreachable, // Filtered out above.
+ return .ok;
+ },
else => unreachable,
},
- else => unreachable,
}
-
- unreachable;
}
fn coerceInMemoryAllowedFns(
@@ -26515,69 +28007,95 @@ fn coerceInMemoryAllowedFns(
dest_src: LazySrcLoc,
src_src: LazySrcLoc,
) !InMemoryCoercionResult {
- const dest_info = dest_ty.fnInfo();
- const src_info = src_ty.fnInfo();
+ const mod = sema.mod;
- if (dest_info.is_var_args != src_info.is_var_args) {
- return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
- }
+ {
+ const dest_info = mod.typeToFunc(dest_ty).?;
+ const src_info = mod.typeToFunc(src_ty).?;
- if (dest_info.is_generic != src_info.is_generic) {
- return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
- }
+ if (dest_info.is_var_args != src_info.is_var_args) {
+ return InMemoryCoercionResult{ .fn_var_args = dest_info.is_var_args };
+ }
- if (dest_info.cc != src_info.cc) {
- return InMemoryCoercionResult{ .fn_cc = .{
- .actual = src_info.cc,
- .wanted = dest_info.cc,
- } };
- }
+ if (dest_info.is_generic != src_info.is_generic) {
+ return InMemoryCoercionResult{ .fn_generic = dest_info.is_generic };
+ }
- if (!src_info.return_type.isNoReturn()) {
- const rt = try sema.coerceInMemoryAllowed(block, dest_info.return_type, src_info.return_type, false, target, dest_src, src_src);
- if (rt != .ok) {
- return InMemoryCoercionResult{ .fn_return_type = .{
- .child = try rt.dupe(sema.arena),
- .actual = src_info.return_type,
- .wanted = dest_info.return_type,
+ if (dest_info.cc != src_info.cc) {
+ return InMemoryCoercionResult{ .fn_cc = .{
+ .actual = src_info.cc,
+ .wanted = dest_info.cc,
} };
}
- }
- if (dest_info.param_types.len != src_info.param_types.len) {
- return InMemoryCoercionResult{ .fn_param_count = .{
- .actual = src_info.param_types.len,
- .wanted = dest_info.param_types.len,
- } };
+ switch (src_info.return_type) {
+ .noreturn_type, .generic_poison_type => {},
+ else => {
+ const dest_return_type = dest_info.return_type.toType();
+ const src_return_type = src_info.return_type.toType();
+ const rt = try sema.coerceInMemoryAllowed(block, dest_return_type, src_return_type, false, target, dest_src, src_src);
+ if (rt != .ok) {
+ return InMemoryCoercionResult{ .fn_return_type = .{
+ .child = try rt.dupe(sema.arena),
+ .actual = src_return_type,
+ .wanted = dest_return_type,
+ } };
+ }
+ },
+ }
}
- if (dest_info.noalias_bits != src_info.noalias_bits) {
- return InMemoryCoercionResult{ .fn_param_noalias = .{
- .actual = src_info.noalias_bits,
- .wanted = dest_info.noalias_bits,
- } };
- }
+ const params_len = params_len: {
+ const dest_info = mod.typeToFunc(dest_ty).?;
+ const src_info = mod.typeToFunc(src_ty).?;
- for (dest_info.param_types, 0..) |dest_param_ty, i| {
- const src_param_ty = src_info.param_types[i];
+ if (dest_info.param_types.len != src_info.param_types.len) {
+ return InMemoryCoercionResult{ .fn_param_count = .{
+ .actual = src_info.param_types.len,
+ .wanted = dest_info.param_types.len,
+ } };
+ }
- if (dest_info.comptime_params[i] != src_info.comptime_params[i]) {
- return InMemoryCoercionResult{ .fn_param_comptime = .{
- .index = i,
- .wanted = dest_info.comptime_params[i],
+ if (dest_info.noalias_bits != src_info.noalias_bits) {
+ return InMemoryCoercionResult{ .fn_param_noalias = .{
+ .actual = src_info.noalias_bits,
+ .wanted = dest_info.noalias_bits,
} };
}
- // Note: Cast direction is reversed here.
- const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
- if (param != .ok) {
- return InMemoryCoercionResult{ .fn_param = .{
- .child = try param.dupe(sema.arena),
- .actual = src_param_ty,
- .wanted = dest_param_ty,
- .index = i,
+ break :params_len dest_info.param_types.len;
+ };
+
+ for (0..params_len) |param_i| {
+ const dest_info = mod.typeToFunc(dest_ty).?;
+ const src_info = mod.typeToFunc(src_ty).?;
+
+ const dest_param_ty = dest_info.param_types[param_i].toType();
+ const src_param_ty = src_info.param_types[param_i].toType();
+
+ const param_i_small = @intCast(u5, param_i);
+ if (dest_info.paramIsComptime(param_i_small) != src_info.paramIsComptime(param_i_small)) {
+ return InMemoryCoercionResult{ .fn_param_comptime = .{
+ .index = param_i,
+ .wanted = dest_info.paramIsComptime(param_i_small),
} };
}
+
+ switch (src_param_ty.toIntern()) {
+ .generic_poison_type => {},
+ else => {
+ // Note: Cast direction is reversed here.
+ const param = try sema.coerceInMemoryAllowed(block, src_param_ty, dest_param_ty, false, target, dest_src, src_src);
+ if (param != .ok) {
+ return InMemoryCoercionResult{ .fn_param = .{
+ .child = try param.dupe(sema.arena),
+ .actual = src_param_ty,
+ .wanted = dest_param_ty,
+ .index = param_i,
+ } };
+ }
+ },
+ }
}
return .ok;
@@ -26595,8 +28113,9 @@ fn coerceInMemoryAllowedPtrs(
dest_src: LazySrcLoc,
src_src: LazySrcLoc,
) !InMemoryCoercionResult {
- const dest_info = dest_ptr_ty.ptrInfo().data;
- const src_info = src_ptr_ty.ptrInfo().data;
+ const mod = sema.mod;
+ const dest_info = dest_ptr_ty.ptrInfo(mod);
+ const src_info = src_ptr_ty.ptrInfo(mod);
const ok_ptr_size = src_info.size == dest_info.size or
src_info.size == .C or dest_info.size == .C;
@@ -26636,8 +28155,8 @@ fn coerceInMemoryAllowedPtrs(
} };
}
- const dest_allow_zero = dest_ty.ptrAllowsZero();
- const src_allow_zero = src_ty.ptrAllowsZero();
+ const dest_allow_zero = dest_ty.ptrAllowsZero(mod);
+ const src_allow_zero = src_ty.ptrAllowsZero(mod);
const ok_allows_zero = (dest_allow_zero and
(src_allow_zero or !dest_is_mut)) or
@@ -26661,12 +28180,15 @@ fn coerceInMemoryAllowedPtrs(
}
const ok_sent = dest_info.sentinel == null or src_info.size == .C or
- (src_info.sentinel != null and
- dest_info.sentinel.?.eql(src_info.sentinel.?, dest_info.pointee_type, sema.mod));
+ (src_info.sentinel != null and dest_info.sentinel.?.eql(
+ try mod.getCoerced(src_info.sentinel.?, dest_info.pointee_type),
+ dest_info.pointee_type,
+ sema.mod,
+ ));
if (!ok_sent) {
return InMemoryCoercionResult{ .ptr_sentinel = .{
- .actual = src_info.sentinel orelse Value.initTag(.unreachable_value),
- .wanted = dest_info.sentinel orelse Value.initTag(.unreachable_value),
+ .actual = src_info.sentinel orelse Value.@"unreachable",
+ .wanted = dest_info.sentinel orelse Value.@"unreachable",
.ty = dest_info.pointee_type,
} };
}
@@ -26685,12 +28207,12 @@ fn coerceInMemoryAllowedPtrs(
const src_align = if (src_info.@"align" != 0)
src_info.@"align"
else
- src_info.pointee_type.abiAlignment(target);
+ src_info.pointee_type.abiAlignment(mod);
const dest_align = if (dest_info.@"align" != 0)
dest_info.@"align"
else
- dest_info.pointee_type.abiAlignment(target);
+ dest_info.pointee_type.abiAlignment(mod);
if (dest_align > src_align) {
return InMemoryCoercionResult{ .ptr_alignment = .{
@@ -26713,8 +28235,9 @@ fn coerceVarArgParam(
) !Air.Inst.Ref {
if (block.is_typeof) return inst;
+ const mod = sema.mod;
const uncasted_ty = sema.typeOf(inst);
- const coerced = switch (uncasted_ty.zigTypeTag()) {
+ const coerced = switch (uncasted_ty.zigTypeTag(mod)) {
// TODO consider casting to c_int/f64 if they fit
.ComptimeInt, .ComptimeFloat => return sema.fail(
block,
@@ -26724,7 +28247,7 @@ fn coerceVarArgParam(
),
.Fn => blk: {
const fn_val = try sema.resolveConstValue(block, .unneeded, inst, "");
- const fn_decl = fn_val.pointerDecl().?;
+ const fn_decl = fn_val.pointerDecl(mod).?;
break :blk try sema.analyzeDeclRef(fn_decl);
},
.Array => return sema.fail(block, inst_src, "arrays must be passed by reference to variadic function", .{}),
@@ -26749,7 +28272,7 @@ fn coerceVarArgParam(
errdefer msg.destroy(sema.gpa);
const src_decl = sema.mod.declPtr(block.src_decl);
- try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl), coerced_ty, .param_ty);
+ try sema.explainWhyTypeIsNotExtern(msg, inst_src.toSrcLoc(src_decl, mod), coerced_ty, .param_ty);
try sema.addDeclaredHereNote(msg, coerced_ty);
break :msg msg;
@@ -26781,11 +28304,12 @@ fn storePtr2(
operand_src: LazySrcLoc,
air_tag: Air.Inst.Tag,
) CompileError!void {
+ const mod = sema.mod;
const ptr_ty = sema.typeOf(ptr);
- if (ptr_ty.isConstPtr())
+ if (ptr_ty.isConstPtr(mod))
return sema.fail(block, ptr_src, "cannot assign to constant", .{});
- const elem_ty = ptr_ty.childType();
+ const elem_ty = ptr_ty.childType(mod);
// To generate better code for tuples, we detect a tuple operand here, and
// analyze field loads and stores directly. This avoids an extra allocation + memcpy
@@ -26796,8 +28320,8 @@ fn storePtr2(
// this code does not handle tuple-to-struct coercion which requires dealing with missing
// fields.
const operand_ty = sema.typeOf(uncasted_operand);
- if (operand_ty.isTuple() and elem_ty.zigTypeTag() == .Array) {
- const field_count = operand_ty.structFieldCount();
+ if (operand_ty.isTuple(mod) and elem_ty.zigTypeTag(mod) == .Array) {
+ const field_count = operand_ty.structFieldCount(mod);
var i: u32 = 0;
while (i < field_count) : (i += 1) {
const elem_src = operand_src; // TODO better source location
@@ -26821,7 +28345,7 @@ fn storePtr2(
// as well as working around an LLVM bug:
// https://github.com/ziglang/zig/issues/11154
if (sema.obtainBitCastedVectorPtr(ptr)) |vector_ptr| {
- const vector_ty = sema.typeOf(vector_ptr).childType();
+ const vector_ty = sema.typeOf(vector_ptr).childType(mod);
const vector = sema.coerceExtra(block, vector_ty, uncasted_operand, operand_src, .{ .is_ret = is_ret }) catch |err| switch (err) {
error.NotCoercible => unreachable,
else => |e| return e,
@@ -26841,7 +28365,7 @@ fn storePtr2(
try sema.checkPtrIsNotComptimeMutable(block, ptr_val, ptr_src, operand_src);
break :rs operand_src;
};
- if (ptr_val.isComptimeMutablePtr()) {
+ if (ptr_val.isComptimeMutablePtr(mod)) {
try sema.storePtrVal(block, src, ptr_val, operand_val, elem_ty);
return;
} else break :rs ptr_src;
@@ -26862,7 +28386,7 @@ fn storePtr2(
try sema.requireRuntimeBlock(block, src, runtime_src);
try sema.queueFullTypeResolution(elem_ty);
- if (ptr_ty.ptrInfo().data.vector_index == .runtime) {
+ if (ptr_ty.ptrInfo(mod).vector_index == .runtime) {
const ptr_inst = Air.refToIndex(ptr).?;
const air_tags = sema.air_instructions.items(.tag);
if (air_tags[ptr_inst] == .ptr_elem_ptr) {
@@ -26896,30 +28420,27 @@ fn storePtr2(
/// pointer. Only if the final element type matches the vector element type, and the
/// lengths match.
fn obtainBitCastedVectorPtr(sema: *Sema, ptr: Air.Inst.Ref) ?Air.Inst.Ref {
- const array_ty = sema.typeOf(ptr).childType();
- if (array_ty.zigTypeTag() != .Array) return null;
- var ptr_inst = Air.refToIndex(ptr) orelse return null;
+ const mod = sema.mod;
+ const array_ty = sema.typeOf(ptr).childType(mod);
+ if (array_ty.zigTypeTag(mod) != .Array) return null;
+ var ptr_ref = ptr;
+ var ptr_inst = Air.refToIndex(ptr_ref) orelse return null;
const air_datas = sema.air_instructions.items(.data);
const air_tags = sema.air_instructions.items(.tag);
- const prev_ptr = while (air_tags[ptr_inst] == .bitcast) {
- const prev_ptr = air_datas[ptr_inst].ty_op.operand;
- const prev_ptr_ty = sema.typeOf(prev_ptr);
- const prev_ptr_child_ty = switch (prev_ptr_ty.tag()) {
- .single_mut_pointer => prev_ptr_ty.castTag(.single_mut_pointer).?.data,
- .pointer => prev_ptr_ty.castTag(.pointer).?.data.pointee_type,
- else => return null,
- };
- if (prev_ptr_child_ty.zigTypeTag() == .Vector) break prev_ptr;
- ptr_inst = Air.refToIndex(prev_ptr) orelse return null;
+ const vector_ty = while (air_tags[ptr_inst] == .bitcast) {
+ ptr_ref = air_datas[ptr_inst].ty_op.operand;
+ if (!sema.isKnownZigType(ptr_ref, .Pointer)) return null;
+ const child_ty = sema.typeOf(ptr_ref).childType(mod);
+ if (child_ty.zigTypeTag(mod) == .Vector) break child_ty;
+ ptr_inst = Air.refToIndex(ptr_ref) orelse return null;
} else return null;
// We have a pointer-to-array and a pointer-to-vector. If the elements and
// lengths match, return the result.
- const vector_ty = sema.typeOf(prev_ptr).childType();
- if (array_ty.childType().eql(vector_ty.childType(), sema.mod) and
- array_ty.arrayLen() == vector_ty.vectorLen())
+ if (array_ty.childType(mod).eql(vector_ty.childType(mod), sema.mod) and
+ array_ty.arrayLen(mod) == vector_ty.vectorLen(mod))
{
- return prev_ptr;
+ return ptr_ref;
} else {
return null;
}
@@ -26935,54 +28456,55 @@ fn storePtrVal(
operand_val: Value,
operand_ty: Type,
) !void {
+ const mod = sema.mod;
var mut_kit = try sema.beginComptimePtrMutation(block, src, ptr_val, operand_ty);
- try sema.checkComptimeVarStore(block, src, mut_kit.decl_ref_mut);
+ try sema.checkComptimeVarStore(block, src, mut_kit.mut_decl);
switch (mut_kit.pointee) {
.direct => |val_ptr| {
- if (mut_kit.decl_ref_mut.runtime_index == .comptime_field_ptr) {
- if (!operand_val.eql(val_ptr.*, operand_ty, sema.mod)) {
+ if (mut_kit.mut_decl.runtime_index == .comptime_field_ptr) {
+ if (!operand_val.eql(val_ptr.*, operand_ty, mod)) {
// TODO use failWithInvalidComptimeFieldStore
return sema.fail(block, src, "value stored in comptime field does not match the default value of the field", .{});
}
return;
}
- const arena = mut_kit.beginArena(sema.mod);
- defer mut_kit.finishArena(sema.mod);
-
- val_ptr.* = try operand_val.copy(arena);
+ val_ptr.* = (try operand_val.intern(operand_ty, mod)).toValue();
},
.reinterpret => |reinterpret| {
- const target = sema.mod.getTarget();
- const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(target));
+ const abi_size = try sema.usizeCast(block, src, mut_kit.ty.abiSize(mod));
const buffer = try sema.gpa.alloc(u8, abi_size);
defer sema.gpa.free(buffer);
- reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, sema.mod, buffer) catch |err| switch (err) {
+ reinterpret.val_ptr.*.writeToMemory(mut_kit.ty, mod, buffer) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
error.ReinterpretDeclRef => unreachable,
error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
- error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}),
+ error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
};
- operand_val.writeToMemory(operand_ty, sema.mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
+ operand_val.writeToMemory(operand_ty, mod, buffer[reinterpret.byte_offset..]) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
error.ReinterpretDeclRef => unreachable,
error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
- error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(sema.mod)}),
+ error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{mut_kit.ty.fmt(mod)}),
};
- const arena = mut_kit.beginArena(sema.mod);
- defer mut_kit.finishArena(sema.mod);
-
- reinterpret.val_ptr.* = try Value.readFromMemory(mut_kit.ty, sema.mod, buffer, arena);
+ reinterpret.val_ptr.* = (try (try Value.readFromMemory(mut_kit.ty, mod, buffer, sema.arena)).intern(mut_kit.ty, mod)).toValue();
},
.bad_decl_ty, .bad_ptr_ty => {
// TODO show the decl declaration site in a note and explain whether the decl
// or the pointer is the problematic type
- return sema.fail(block, src, "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout", .{mut_kit.ty.fmt(sema.mod)});
+ return sema.fail(
+ block,
+ src,
+ "comptime mutation of a reinterpreted pointer requires type '{}' to have a well-defined memory layout",
+ .{mut_kit.ty.fmt(mod)},
+ );
},
}
}
const ComptimePtrMutationKit = struct {
- decl_ref_mut: Value.Payload.DeclRefMut.Data,
+ mut_decl: InternPool.Key.Ptr.Addr.MutDecl,
pointee: union(enum) {
/// The pointer type matches the actual comptime Value so a direct
/// modification is possible.
@@ -27005,18 +28527,6 @@ const ComptimePtrMutationKit = struct {
bad_ptr_ty,
},
ty: Type,
- decl_arena: std.heap.ArenaAllocator = undefined,
-
- fn beginArena(self: *ComptimePtrMutationKit, mod: *Module) Allocator {
- const decl = mod.declPtr(self.decl_ref_mut.decl_index);
- return decl.value_arena.?.acquire(mod.gpa, &self.decl_arena);
- }
-
- fn finishArena(self: *ComptimePtrMutationKit, mod: *Module) void {
- const decl = mod.declPtr(self.decl_ref_mut.decl_index);
- decl.value_arena.?.release(&self.decl_arena);
- self.decl_arena = undefined;
- }
};
fn beginComptimePtrMutation(
@@ -27026,201 +28536,251 @@ fn beginComptimePtrMutation(
ptr_val: Value,
ptr_elem_ty: Type,
) CompileError!ComptimePtrMutationKit {
- const target = sema.mod.getTarget();
- switch (ptr_val.tag()) {
- .decl_ref_mut => {
- const decl_ref_mut = ptr_val.castTag(.decl_ref_mut).?.data;
- const decl = sema.mod.declPtr(decl_ref_mut.decl_index);
- return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, decl_ref_mut);
- },
- .comptime_field_ptr => {
- const payload = ptr_val.castTag(.comptime_field_ptr).?.data;
+ const mod = sema.mod;
+ const ptr = mod.intern_pool.indexToKey(ptr_val.toIntern()).ptr;
+ switch (ptr.addr) {
+ .decl, .int => unreachable, // isComptimeMutablePtr has been checked already
+ .mut_decl => |mut_decl| {
+ const decl = mod.declPtr(mut_decl.decl);
+ return sema.beginComptimePtrMutationInner(block, src, decl.ty, &decl.val, ptr_elem_ty, mut_decl);
+ },
+ .comptime_field => |comptime_field| {
const duped = try sema.arena.create(Value);
- duped.* = payload.field_val;
- return sema.beginComptimePtrMutationInner(block, src, payload.field_ty, duped, ptr_elem_ty, .{
- .decl_index = @intToEnum(Module.Decl.Index, 0),
+ duped.* = comptime_field.toValue();
+ return sema.beginComptimePtrMutationInner(block, src, mod.intern_pool.typeOf(comptime_field).toType(), duped, ptr_elem_ty, .{
+ .decl = undefined,
.runtime_index = .comptime_field_ptr,
});
},
- .elem_ptr => {
- const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
- var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.array_ptr, elem_ptr.elem_ty);
+ .eu_payload => |eu_ptr| {
+ const eu_ty = mod.intern_pool.typeOf(eu_ptr).toType().childType(mod);
+ var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.toValue(), eu_ty);
+ switch (parent.pointee) {
+ .direct => |val_ptr| {
+ const payload_ty = parent.ty.errorUnionPayload(mod);
+ if (val_ptr.ip_index == .none and val_ptr.tag() == .eu_payload) {
+ return ComptimePtrMutationKit{
+ .mut_decl = parent.mut_decl,
+ .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
+ .ty = payload_ty,
+ };
+ } else {
+ // An error union has been initialized to undefined at comptime and now we
+ // are for the first time setting the payload. We must change the
+ // representation of the error union from `undef` to `opt_payload`.
+
+ const payload = try sema.arena.create(Value.Payload.SubValue);
+ payload.* = .{
+ .base = .{ .tag = .eu_payload },
+ .data = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
+ };
+
+ val_ptr.* = Value.initPayload(&payload.base);
+
+ return ComptimePtrMutationKit{
+ .mut_decl = parent.mut_decl,
+ .pointee = .{ .direct = &payload.data },
+ .ty = payload_ty,
+ };
+ }
+ },
+ .bad_decl_ty, .bad_ptr_ty => return parent,
+ // Even though the parent value type has well-defined memory layout, our
+ // pointer type does not.
+ .reinterpret => return ComptimePtrMutationKit{
+ .mut_decl = parent.mut_decl,
+ .pointee = .bad_ptr_ty,
+ .ty = eu_ty,
+ },
+ }
+ },
+ .opt_payload => |opt_ptr| {
+ const opt_ty = mod.intern_pool.typeOf(opt_ptr).toType().childType(mod);
+ var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.toValue(), opt_ty);
+ switch (parent.pointee) {
+ .direct => |val_ptr| {
+ const payload_ty = parent.ty.optionalChild(mod);
+ switch (val_ptr.ip_index) {
+ .none => return ComptimePtrMutationKit{
+ .mut_decl = parent.mut_decl,
+ .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
+ .ty = payload_ty,
+ },
+ else => {
+ const payload_val = switch (mod.intern_pool.indexToKey(val_ptr.ip_index)) {
+ .undef => try mod.intern(.{ .undef = payload_ty.toIntern() }),
+ .opt => |opt| switch (opt.val) {
+ .none => try mod.intern(.{ .undef = payload_ty.toIntern() }),
+ else => |payload| payload,
+ },
+ else => unreachable,
+ };
+
+ // An optional has been initialized to undefined at comptime and now we
+ // are for the first time setting the payload. We must change the
+ // representation of the optional from `undef` to `opt_payload`.
+
+ const payload = try sema.arena.create(Value.Payload.SubValue);
+ payload.* = .{
+ .base = .{ .tag = .opt_payload },
+ .data = payload_val.toValue(),
+ };
+
+ val_ptr.* = Value.initPayload(&payload.base);
+
+ return ComptimePtrMutationKit{
+ .mut_decl = parent.mut_decl,
+ .pointee = .{ .direct = &payload.data },
+ .ty = payload_ty,
+ };
+ },
+ }
+ },
+ .bad_decl_ty, .bad_ptr_ty => return parent,
+ // Even though the parent value type has well-defined memory layout, our
+ // pointer type does not.
+ .reinterpret => return ComptimePtrMutationKit{
+ .mut_decl = parent.mut_decl,
+ .pointee = .bad_ptr_ty,
+ .ty = opt_ty,
+ },
+ }
+ },
+ .elem => |elem_ptr| {
+ const base_elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
+ var parent = try sema.beginComptimePtrMutation(block, src, elem_ptr.base.toValue(), base_elem_ty);
switch (parent.pointee) {
- .direct => |val_ptr| switch (parent.ty.zigTypeTag()) {
+ .direct => |val_ptr| switch (parent.ty.zigTypeTag(mod)) {
.Array, .Vector => {
- const check_len = parent.ty.arrayLenIncludingSentinel();
+ const check_len = parent.ty.arrayLenIncludingSentinel(mod);
if (elem_ptr.index >= check_len) {
// TODO have the parent include the decl so we can say "declared here"
return sema.fail(block, src, "comptime store of index {d} out of bounds of array length {d}", .{
elem_ptr.index, check_len,
});
}
- const elem_ty = parent.ty.childType();
+ const elem_ty = parent.ty.childType(mod);
// We might have a pointer to multiple elements of the array (e.g. a pointer
// to a sub-array). In this case, we just have to reinterpret the relevant
// bytes of the whole array rather than any single element.
- const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty);
+ const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
if (elem_abi_size_u64 < try sema.typeAbiSize(ptr_elem_ty)) {
const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
+ const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
return .{
- .decl_ref_mut = parent.decl_ref_mut,
+ .mut_decl = parent.mut_decl,
.pointee = .{ .reinterpret = .{
.val_ptr = val_ptr,
- .byte_offset = elem_abi_size * elem_ptr.index,
+ .byte_offset = elem_abi_size * elem_idx,
} },
.ty = parent.ty,
};
}
- switch (val_ptr.tag()) {
- .undef => {
- // An array has been initialized to undefined at comptime and now we
- // are for the first time setting an element. We must change the representation
- // of the array from `undef` to `array`.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
+ switch (val_ptr.ip_index) {
+ .none => switch (val_ptr.tag()) {
+ .bytes => {
+ // An array is memory-optimized to store a slice of bytes, but we are about
+ // to modify an individual field and the representation has to change.
+ // If we wanted to avoid this, there would need to be special detection
+ // elsewhere to identify when writing a value to an array element that is stored
+ // using the `bytes` tag, and handle it without making a call to this function.
+ const arena = sema.arena;
+
+ const bytes = val_ptr.castTag(.bytes).?.data;
+ const dest_len = parent.ty.arrayLenIncludingSentinel(mod);
+ // bytes.len may be one greater than dest_len because of the case when
+ // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
+ assert(bytes.len >= dest_len);
+ const elems = try arena.alloc(Value, @intCast(usize, dest_len));
+ for (elems, 0..) |*elem, i| {
+ elem.* = try mod.intValue(elem_ty, bytes[i]);
+ }
- const array_len_including_sentinel =
- try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
- const elems = try arena.alloc(Value, array_len_including_sentinel);
- @memset(elems, Value.undef);
+ val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
- val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ elem_ty,
+ &elems[@intCast(usize, elem_ptr.index)],
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
+ .repeated => {
+ // An array is memory-optimized to store only a single element value, and
+ // that value is understood to be the same for the entire length of the array.
+ // However, now we want to modify an individual field and so the
+ // representation has to change. If we wanted to avoid this, there would
+ // need to be special detection elsewhere to identify when writing a value to an
+ // array element that is stored using the `repeated` tag, and handle it
+ // without making a call to this function.
+ const arena = sema.arena;
+
+ const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena);
+ const array_len_including_sentinel =
+ try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
+ const elems = try arena.alloc(Value, array_len_including_sentinel);
+ if (elems.len > 0) elems[0] = repeated_val;
+ for (elems[1..]) |*elem| {
+ elem.* = try repeated_val.copy(arena);
+ }
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- elem_ty,
- &elems[elem_ptr.index],
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
- },
- .bytes => {
- // An array is memory-optimized to store a slice of bytes, but we are about
- // to modify an individual field and the representation has to change.
- // If we wanted to avoid this, there would need to be special detection
- // elsewhere to identify when writing a value to an array element that is stored
- // using the `bytes` tag, and handle it without making a call to this function.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- const bytes = val_ptr.castTag(.bytes).?.data;
- const dest_len = parent.ty.arrayLenIncludingSentinel();
- // bytes.len may be one greater than dest_len because of the case when
- // assigning `[N:S]T` to `[N]T`. This is allowed; the sentinel is omitted.
- assert(bytes.len >= dest_len);
- const elems = try arena.alloc(Value, @intCast(usize, dest_len));
- for (elems, 0..) |*elem, i| {
- elem.* = try Value.Tag.int_u64.create(arena, bytes[i]);
- }
+ val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
- val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ elem_ty,
+ &elems[@intCast(usize, elem_ptr.index)],
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
- return beginComptimePtrMutationInner(
+ .aggregate => return beginComptimePtrMutationInner(
sema,
block,
src,
elem_ty,
- &elems[elem_ptr.index],
+ &val_ptr.castTag(.aggregate).?.data[@intCast(usize, elem_ptr.index)],
ptr_elem_ty,
- parent.decl_ref_mut,
- );
- },
- .str_lit => {
- // An array is memory-optimized to store a slice of bytes, but we are about
- // to modify an individual field and the representation has to change.
- // If we wanted to avoid this, there would need to be special detection
- // elsewhere to identify when writing a value to an array element that is stored
- // using the `str_lit` tag, and handle it without making a call to this function.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- const str_lit = val_ptr.castTag(.str_lit).?.data;
- const dest_len = parent.ty.arrayLenIncludingSentinel();
- const bytes = sema.mod.string_literal_bytes.items[str_lit.index..][0..str_lit.len];
- const elems = try arena.alloc(Value, @intCast(usize, dest_len));
- for (bytes, 0..) |byte, i| {
- elems[i] = try Value.Tag.int_u64.create(arena, byte);
- }
- if (parent.ty.sentinel()) |sent_val| {
- assert(elems.len == bytes.len + 1);
- elems[bytes.len] = sent_val;
- }
-
- val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
+ parent.mut_decl,
+ ),
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- elem_ty,
- &elems[elem_ptr.index],
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
+ else => unreachable,
},
- .repeated => {
- // An array is memory-optimized to store only a single element value, and
- // that value is understood to be the same for the entire length of the array.
- // However, now we want to modify an individual field and so the
- // representation has to change. If we wanted to avoid this, there would
- // need to be special detection elsewhere to identify when writing a value to an
- // array element that is stored using the `repeated` tag, and handle it
- // without making a call to this function.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- const repeated_val = try val_ptr.castTag(.repeated).?.data.copy(arena);
- const array_len_including_sentinel =
- try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel());
- const elems = try arena.alloc(Value, array_len_including_sentinel);
- if (elems.len > 0) elems[0] = repeated_val;
- for (elems[1..]) |*elem| {
- elem.* = try repeated_val.copy(arena);
- }
-
- val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
+ else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) {
+ .undef => {
+ // An array has been initialized to undefined at comptime and now we
+ // are for the first time setting an element. We must change the representation
+ // of the array from `undef` to `array`.
+ const arena = sema.arena;
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- elem_ty,
- &elems[elem_ptr.index],
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
- },
+ const array_len_including_sentinel =
+ try sema.usizeCast(block, src, parent.ty.arrayLenIncludingSentinel(mod));
+ const elems = try arena.alloc(Value, array_len_including_sentinel);
+ @memset(elems, (try mod.intern(.{ .undef = elem_ty.toIntern() })).toValue());
- .aggregate => return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- elem_ty,
- &val_ptr.castTag(.aggregate).?.data[elem_ptr.index],
- ptr_elem_ty,
- parent.decl_ref_mut,
- ),
+ val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
- .the_only_possible_value => {
- const duped = try sema.arena.create(Value);
- duped.* = Value.initTag(.the_only_possible_value);
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- elem_ty,
- duped,
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ elem_ty,
+ &elems[@intCast(usize, elem_ptr.index)],
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
+ else => unreachable,
},
-
- else => unreachable,
}
},
else => {
@@ -27237,28 +28797,29 @@ fn beginComptimePtrMutation(
parent.ty,
val_ptr,
ptr_elem_ty,
- parent.decl_ref_mut,
+ parent.mut_decl,
);
},
},
.reinterpret => |reinterpret| {
- if (!elem_ptr.elem_ty.hasWellDefinedLayout()) {
+ if (!base_elem_ty.hasWellDefinedLayout(mod)) {
// Even though the parent value type has well-defined memory layout, our
// pointer type does not.
return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
+ .mut_decl = parent.mut_decl,
.pointee = .bad_ptr_ty,
- .ty = elem_ptr.elem_ty,
+ .ty = base_elem_ty,
};
}
- const elem_abi_size_u64 = try sema.typeAbiSize(elem_ptr.elem_ty);
+ const elem_abi_size_u64 = try sema.typeAbiSize(base_elem_ty);
const elem_abi_size = try sema.usizeCast(block, src, elem_abi_size_u64);
+ const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
+ .mut_decl = parent.mut_decl,
.pointee = .{ .reinterpret = .{
.val_ptr = reinterpret.val_ptr,
- .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_ptr.index,
+ .byte_offset = reinterpret.byte_offset + elem_abi_size * elem_idx,
} },
.ty = parent.ty,
};
@@ -27266,162 +28827,184 @@ fn beginComptimePtrMutation(
.bad_decl_ty, .bad_ptr_ty => return parent,
}
},
- .field_ptr => {
- const field_ptr = ptr_val.castTag(.field_ptr).?.data;
- const field_index = @intCast(u32, field_ptr.field_index);
+ .field => |field_ptr| {
+ const base_child_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
+ const field_index = @intCast(u32, field_ptr.index);
- var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.container_ptr, field_ptr.container_ty);
+ var parent = try sema.beginComptimePtrMutation(block, src, field_ptr.base.toValue(), base_child_ty);
switch (parent.pointee) {
- .direct => |val_ptr| switch (val_ptr.tag()) {
- .undef => {
- // A struct or union has been initialized to undefined at comptime and now we
- // are for the first time setting a field. We must change the representation
- // of the struct/union from `undef` to `struct`/`union`.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- switch (parent.ty.zigTypeTag()) {
- .Struct => {
- const fields = try arena.alloc(Value, parent.ty.structFieldCount());
- @memset(fields, Value.undef);
-
- val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
-
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- parent.ty.structFieldType(field_index),
- &fields[field_index],
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
- },
- .Union => {
- const payload = try arena.create(Value.Payload.Union);
- payload.* = .{ .data = .{
- .tag = try Value.Tag.enum_field_index.create(arena, field_index),
- .val = Value.undef,
- } };
-
- val_ptr.* = Value.initPayload(&payload.base);
-
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- parent.ty.structFieldType(field_index),
- &payload.data.val,
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
- },
- .Pointer => {
- assert(parent.ty.isSlice());
- val_ptr.* = try Value.Tag.slice.create(arena, .{
- .ptr = Value.undef,
- .len = Value.undef,
- });
-
- switch (field_index) {
- Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
- &val_ptr.castTag(.slice).?.data.ptr,
- ptr_elem_ty,
- parent.decl_ref_mut,
- ),
- Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- Type.usize,
- &val_ptr.castTag(.slice).?.data.len,
- ptr_elem_ty,
- parent.decl_ref_mut,
- ),
-
- else => unreachable,
- }
- },
- else => unreachable,
- }
- },
- .aggregate => return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- parent.ty.structFieldType(field_index),
- &val_ptr.castTag(.aggregate).?.data[field_index],
- ptr_elem_ty,
- parent.decl_ref_mut,
- ),
-
- .@"union" => {
- // We need to set the active field of the union.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- const payload = &val_ptr.castTag(.@"union").?.data;
- payload.tag = try Value.Tag.enum_field_index.create(arena, field_index);
-
+ .direct => |val_ptr| switch (val_ptr.ip_index) {
+ .empty_struct => {
+ const duped = try sema.arena.create(Value);
+ duped.* = val_ptr.*;
return beginComptimePtrMutationInner(
sema,
block,
src,
- parent.ty.structFieldType(field_index),
- &payload.val,
+ parent.ty.structFieldType(field_index, mod),
+ duped,
ptr_elem_ty,
- parent.decl_ref_mut,
+ parent.mut_decl,
);
},
- .slice => switch (field_index) {
- Value.Payload.Slice.ptr_index => return beginComptimePtrMutationInner(
+ .none => switch (val_ptr.tag()) {
+ .aggregate => return beginComptimePtrMutationInner(
sema,
block,
src,
- parent.ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
- &val_ptr.castTag(.slice).?.data.ptr,
+ parent.ty.structFieldType(field_index, mod),
+ &val_ptr.castTag(.aggregate).?.data[field_index],
ptr_elem_ty,
- parent.decl_ref_mut,
+ parent.mut_decl,
),
+ .repeated => {
+ const arena = sema.arena;
- Value.Payload.Slice.len_index => return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- Type.usize,
- &val_ptr.castTag(.slice).?.data.len,
- ptr_elem_ty,
- parent.decl_ref_mut,
- ),
+ const elems = try arena.alloc(Value, parent.ty.structFieldCount(mod));
+ @memset(elems, val_ptr.castTag(.repeated).?.data);
+ val_ptr.* = try Value.Tag.aggregate.create(arena, elems);
+
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ parent.ty.structFieldType(field_index, mod),
+ &elems[field_index],
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
+ .@"union" => {
+ // We need to set the active field of the union.
+ const union_tag_ty = base_child_ty.unionTagTypeHypothetical(mod);
+
+ const payload = &val_ptr.castTag(.@"union").?.data;
+ payload.tag = try mod.enumValueFieldIndex(union_tag_ty, field_index);
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ parent.ty.structFieldType(field_index, mod),
+ &payload.val,
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
+ .slice => switch (field_index) {
+ Value.slice_ptr_index => return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ parent.ty.slicePtrFieldType(mod),
+ &val_ptr.castTag(.slice).?.data.ptr,
+ ptr_elem_ty,
+ parent.mut_decl,
+ ),
+
+ Value.slice_len_index => return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ Type.usize,
+ &val_ptr.castTag(.slice).?.data.len,
+ ptr_elem_ty,
+ parent.mut_decl,
+ ),
+
+ else => unreachable,
+ },
else => unreachable,
},
-
- .empty_struct_value => {
- const duped = try sema.arena.create(Value);
- duped.* = Value.initTag(.the_only_possible_value);
- return beginComptimePtrMutationInner(
- sema,
- block,
- src,
- parent.ty.structFieldType(field_index),
- duped,
- ptr_elem_ty,
- parent.decl_ref_mut,
- );
+ else => switch (mod.intern_pool.indexToKey(val_ptr.toIntern())) {
+ .undef => {
+ // A struct or union has been initialized to undefined at comptime and now we
+ // are for the first time setting a field. We must change the representation
+ // of the struct/union from `undef` to `struct`/`union`.
+ const arena = sema.arena;
+
+ switch (parent.ty.zigTypeTag(mod)) {
+ .Struct => {
+ const fields = try arena.alloc(Value, parent.ty.structFieldCount(mod));
+ for (fields, 0..) |*field, i| field.* = (try mod.intern(.{
+ .undef = parent.ty.structFieldType(i, mod).toIntern(),
+ })).toValue();
+
+ val_ptr.* = try Value.Tag.aggregate.create(arena, fields);
+
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ parent.ty.structFieldType(field_index, mod),
+ &fields[field_index],
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
+ .Union => {
+ const payload = try arena.create(Value.Payload.Union);
+ const tag_ty = parent.ty.unionTagTypeHypothetical(mod);
+ const payload_ty = parent.ty.structFieldType(field_index, mod);
+ payload.* = .{ .data = .{
+ .tag = try mod.enumValueFieldIndex(tag_ty, field_index),
+ .val = (try mod.intern(.{ .undef = payload_ty.toIntern() })).toValue(),
+ } };
+
+ val_ptr.* = Value.initPayload(&payload.base);
+
+ return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ payload_ty,
+ &payload.data.val,
+ ptr_elem_ty,
+ parent.mut_decl,
+ );
+ },
+ .Pointer => {
+ assert(parent.ty.isSlice(mod));
+ const ptr_ty = parent.ty.slicePtrFieldType(mod);
+ val_ptr.* = try Value.Tag.slice.create(arena, .{
+ .ptr = (try mod.intern(.{ .undef = ptr_ty.toIntern() })).toValue(),
+ .len = (try mod.intern(.{ .undef = .usize_type })).toValue(),
+ });
+
+ switch (field_index) {
+ Value.slice_ptr_index => return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ ptr_ty,
+ &val_ptr.castTag(.slice).?.data.ptr,
+ ptr_elem_ty,
+ parent.mut_decl,
+ ),
+ Value.slice_len_index => return beginComptimePtrMutationInner(
+ sema,
+ block,
+ src,
+ Type.usize,
+ &val_ptr.castTag(.slice).?.data.len,
+ ptr_elem_ty,
+ parent.mut_decl,
+ ),
+
+ else => unreachable,
+ }
+ },
+ else => unreachable,
+ }
+ },
+ else => unreachable,
},
-
- else => unreachable,
},
.reinterpret => |reinterpret| {
- const field_offset_u64 = field_ptr.container_ty.structFieldOffset(field_index, target);
+ const field_offset_u64 = base_child_ty.structFieldOffset(field_index, mod);
const field_offset = try sema.usizeCast(block, src, field_offset_u64);
return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
+ .mut_decl = parent.mut_decl,
.pointee = .{ .reinterpret = .{
.val_ptr = reinterpret.val_ptr,
.byte_offset = reinterpret.byte_offset + field_offset,
@@ -27432,106 +29015,6 @@ fn beginComptimePtrMutation(
.bad_decl_ty, .bad_ptr_ty => return parent,
}
},
- .eu_payload_ptr => {
- const eu_ptr = ptr_val.castTag(.eu_payload_ptr).?.data;
- var parent = try sema.beginComptimePtrMutation(block, src, eu_ptr.container_ptr, eu_ptr.container_ty);
- switch (parent.pointee) {
- .direct => |val_ptr| {
- const payload_ty = parent.ty.errorUnionPayload();
- switch (val_ptr.tag()) {
- else => {
- // An error union has been initialized to undefined at comptime and now we
- // are for the first time setting the payload. We must change the
- // representation of the error union from `undef` to `opt_payload`.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- const payload = try arena.create(Value.Payload.SubValue);
- payload.* = .{
- .base = .{ .tag = .eu_payload },
- .data = Value.undef,
- };
-
- val_ptr.* = Value.initPayload(&payload.base);
-
- return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .{ .direct = &payload.data },
- .ty = payload_ty,
- };
- },
- .eu_payload => return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .{ .direct = &val_ptr.castTag(.eu_payload).?.data },
- .ty = payload_ty,
- },
- }
- },
- .bad_decl_ty, .bad_ptr_ty => return parent,
- // Even though the parent value type has well-defined memory layout, our
- // pointer type does not.
- .reinterpret => return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .bad_ptr_ty,
- .ty = eu_ptr.container_ty,
- },
- }
- },
- .opt_payload_ptr => {
- const opt_ptr = if (ptr_val.castTag(.opt_payload_ptr)) |some| some.data else {
- return sema.beginComptimePtrMutation(block, src, ptr_val, try ptr_elem_ty.optionalChildAlloc(sema.arena));
- };
- var parent = try sema.beginComptimePtrMutation(block, src, opt_ptr.container_ptr, opt_ptr.container_ty);
- switch (parent.pointee) {
- .direct => |val_ptr| {
- const payload_ty = try parent.ty.optionalChildAlloc(sema.arena);
- switch (val_ptr.tag()) {
- .undef, .null_value => {
- // An optional has been initialized to undefined at comptime and now we
- // are for the first time setting the payload. We must change the
- // representation of the optional from `undef` to `opt_payload`.
- const arena = parent.beginArena(sema.mod);
- defer parent.finishArena(sema.mod);
-
- const payload = try arena.create(Value.Payload.SubValue);
- payload.* = .{
- .base = .{ .tag = .opt_payload },
- .data = Value.undef,
- };
-
- val_ptr.* = Value.initPayload(&payload.base);
-
- return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .{ .direct = &payload.data },
- .ty = payload_ty,
- };
- },
- .opt_payload => return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .{ .direct = &val_ptr.castTag(.opt_payload).?.data },
- .ty = payload_ty,
- },
-
- else => return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .{ .direct = val_ptr },
- .ty = payload_ty,
- },
- }
- },
- .bad_decl_ty, .bad_ptr_ty => return parent,
- // Even though the parent value type has well-defined memory layout, our
- // pointer type does not.
- .reinterpret => return ComptimePtrMutationKit{
- .decl_ref_mut = parent.decl_ref_mut,
- .pointee = .bad_ptr_ty,
- .ty = opt_ptr.container_ty,
- },
- }
- },
- .decl_ref => unreachable, // isComptimeMutablePtr() has been checked already
- else => unreachable,
}
}
@@ -27542,46 +29025,50 @@ fn beginComptimePtrMutationInner(
decl_ty: Type,
decl_val: *Value,
ptr_elem_ty: Type,
- decl_ref_mut: Value.Payload.DeclRefMut.Data,
+ mut_decl: InternPool.Key.Ptr.Addr.MutDecl,
) CompileError!ComptimePtrMutationKit {
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
+ const target = mod.getTarget();
const coerce_ok = (try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_ty, true, target, src, src)) == .ok;
+
+ decl_val.* = try decl_val.unintern(sema.arena, mod);
+
if (coerce_ok) {
return ComptimePtrMutationKit{
- .decl_ref_mut = decl_ref_mut,
+ .mut_decl = mut_decl,
.pointee = .{ .direct = decl_val },
.ty = decl_ty,
};
}
// Handle the case that the decl is an array and we're actually trying to point to an element.
- if (decl_ty.isArrayOrVector()) {
- const decl_elem_ty = decl_ty.childType();
+ if (decl_ty.isArrayOrVector(mod)) {
+ const decl_elem_ty = decl_ty.childType(mod);
if ((try sema.coerceInMemoryAllowed(block, ptr_elem_ty, decl_elem_ty, true, target, src, src)) == .ok) {
return ComptimePtrMutationKit{
- .decl_ref_mut = decl_ref_mut,
+ .mut_decl = mut_decl,
.pointee = .{ .direct = decl_val },
.ty = decl_ty,
};
}
}
- if (!decl_ty.hasWellDefinedLayout()) {
+ if (!decl_ty.hasWellDefinedLayout(mod)) {
return ComptimePtrMutationKit{
- .decl_ref_mut = decl_ref_mut,
- .pointee = .{ .bad_decl_ty = {} },
+ .mut_decl = mut_decl,
+ .pointee = .bad_decl_ty,
.ty = decl_ty,
};
}
- if (!ptr_elem_ty.hasWellDefinedLayout()) {
+ if (!ptr_elem_ty.hasWellDefinedLayout(mod)) {
return ComptimePtrMutationKit{
- .decl_ref_mut = decl_ref_mut,
- .pointee = .{ .bad_ptr_ty = {} },
+ .mut_decl = mut_decl,
+ .pointee = .bad_ptr_ty,
.ty = ptr_elem_ty,
};
}
return ComptimePtrMutationKit{
- .decl_ref_mut = decl_ref_mut,
+ .mut_decl = mut_decl,
.pointee = .{ .reinterpret = .{
.val_ptr = decl_val,
.byte_offset = 0,
@@ -27623,237 +29110,227 @@ fn beginComptimePtrLoad(
ptr_val: Value,
maybe_array_ty: ?Type,
) ComptimePtrLoadError!ComptimePtrLoadKit {
- const target = sema.mod.getTarget();
- var deref: ComptimePtrLoadKit = switch (ptr_val.tag()) {
- .decl_ref,
- .decl_ref_mut,
- => blk: {
- const decl_index = switch (ptr_val.tag()) {
- .decl_ref => ptr_val.castTag(.decl_ref).?.data,
- .decl_ref_mut => ptr_val.castTag(.decl_ref_mut).?.data.decl_index,
- else => unreachable,
- };
- const is_mutable = ptr_val.tag() == .decl_ref_mut;
- const decl = sema.mod.declPtr(decl_index);
- const decl_tv = try decl.typedValue();
- if (decl_tv.val.tag() == .variable) return error.RuntimeLoad;
-
- const layout_defined = decl.ty.hasWellDefinedLayout();
- break :blk ComptimePtrLoadKit{
- .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
- .pointee = decl_tv,
- .is_mutable = is_mutable,
- .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
- };
- },
-
- .elem_ptr => blk: {
- const elem_ptr = ptr_val.castTag(.elem_ptr).?.data;
- const elem_ty = elem_ptr.elem_ty;
- var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.array_ptr, null);
+ const mod = sema.mod;
+ const target = mod.getTarget();
- // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
- // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
- // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
- if (elem_ptr.array_ptr.castTag(.elem_ptr)) |parent_elem_ptr| {
- assert(!(parent_elem_ptr.data.elem_ty.eql(elem_ty, sema.mod)));
- }
+ var deref: ComptimePtrLoadKit = switch (mod.intern_pool.indexToKey(ptr_val.toIntern())) {
+ .ptr => |ptr| switch (ptr.addr) {
+ .decl, .mut_decl => blk: {
+ const decl_index = switch (ptr.addr) {
+ .decl => |decl| decl,
+ .mut_decl => |mut_decl| mut_decl.decl,
+ else => unreachable,
+ };
+ const is_mutable = ptr.addr == .mut_decl;
+ const decl = mod.declPtr(decl_index);
+ const decl_tv = try decl.typedValue();
+ if (decl.val.getVariable(mod) != null) return error.RuntimeLoad;
+
+ const layout_defined = decl.ty.hasWellDefinedLayout(mod);
+ break :blk ComptimePtrLoadKit{
+ .parent = if (layout_defined) .{ .tv = decl_tv, .byte_offset = 0 } else null,
+ .pointee = decl_tv,
+ .is_mutable = is_mutable,
+ .ty_without_well_defined_layout = if (!layout_defined) decl.ty else null,
+ };
+ },
+ .int => return error.RuntimeLoad,
+ .eu_payload, .opt_payload => |container_ptr| blk: {
+ const container_ty = mod.intern_pool.typeOf(container_ptr).toType().childType(mod);
+ const payload_ty = switch (ptr.addr) {
+ .eu_payload => container_ty.errorUnionPayload(mod),
+ .opt_payload => container_ty.optionalChild(mod),
+ else => unreachable,
+ };
+ var deref = try sema.beginComptimePtrLoad(block, src, container_ptr.toValue(), container_ty);
- if (elem_ptr.index != 0) {
- if (elem_ty.hasWellDefinedLayout()) {
- if (deref.parent) |*parent| {
- // Update the byte offset (in-place)
- const elem_size = try sema.typeAbiSize(elem_ty);
- const offset = parent.byte_offset + elem_size * elem_ptr.index;
- parent.byte_offset = try sema.usizeCast(block, src, offset);
- }
- } else {
+ // eu_payload and opt_payload never have a well-defined layout
+ if (deref.parent != null) {
deref.parent = null;
- deref.ty_without_well_defined_layout = elem_ty;
+ deref.ty_without_well_defined_layout = container_ty;
+ }
+
+ if (deref.pointee) |*tv| {
+ const coerce_in_mem_ok =
+ (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or
+ (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok;
+ if (coerce_in_mem_ok) {
+ const payload_val = switch (tv.val.ip_index) {
+ .none => tv.val.cast(Value.Payload.SubValue).?.data,
+ .null_value => return sema.fail(block, src, "attempt to use null value", .{}),
+ else => switch (mod.intern_pool.indexToKey(tv.val.toIntern())) {
+ .error_union => |error_union| switch (error_union.val) {
+ .err_name => |err_name| return sema.fail(
+ block,
+ src,
+ "attempt to unwrap error: {}",
+ .{err_name.fmt(&mod.intern_pool)},
+ ),
+ .payload => |payload| payload,
+ },
+ .opt => |opt| switch (opt.val) {
+ .none => return sema.fail(block, src, "attempt to use null value", .{}),
+ else => |payload| payload,
+ },
+ else => unreachable,
+ }.toValue(),
+ };
+ tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
+ break :blk deref;
+ }
}
- }
-
- // If we're loading an elem_ptr that was derived from a different type
- // than the true type of the underlying decl, we cannot deref directly
- const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector()) x: {
- const deref_elem_ty = deref.pointee.?.ty.childType();
- break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
- (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
- } else false;
- if (!ty_matches) {
deref.pointee = null;
break :blk deref;
- }
+ },
+ .comptime_field => |comptime_field| blk: {
+ const field_ty = mod.intern_pool.typeOf(comptime_field).toType();
+ break :blk ComptimePtrLoadKit{
+ .parent = null,
+ .pointee = .{ .ty = field_ty, .val = comptime_field.toValue() },
+ .is_mutable = false,
+ .ty_without_well_defined_layout = field_ty,
+ };
+ },
+ .elem => |elem_ptr| blk: {
+ const elem_ty = mod.intern_pool.typeOf(elem_ptr.base).toType().elemType2(mod);
+ var deref = try sema.beginComptimePtrLoad(block, src, elem_ptr.base.toValue(), null);
+
+ // This code assumes that elem_ptrs have been "flattened" in order for direct dereference
+ // to succeed, meaning that elem ptrs of the same elem_ty are coalesced. Here we check that
+ // our parent is not an elem_ptr with the same elem_ty, since that would be "unflattened"
+ switch (mod.intern_pool.indexToKey(elem_ptr.base)) {
+ .ptr => |base_ptr| switch (base_ptr.addr) {
+ .elem => |base_elem| assert(!mod.intern_pool.typeOf(base_elem.base).toType().elemType2(mod).eql(elem_ty, mod)),
+ else => {},
+ },
+ else => {},
+ }
- var array_tv = deref.pointee.?;
- const check_len = array_tv.ty.arrayLenIncludingSentinel();
- if (maybe_array_ty) |load_ty| {
- // It's possible that we're loading a [N]T, in which case we'd like to slice
- // the pointee array directly from our parent array.
- if (load_ty.isArrayOrVector() and load_ty.childType().eql(elem_ty, sema.mod)) {
- const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel());
- deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
- .ty = try Type.array(sema.arena, N, null, elem_ty, sema.mod),
- .val = try array_tv.val.sliceArray(sema.mod, sema.arena, elem_ptr.index, elem_ptr.index + N),
- } else null;
- break :blk deref;
+ if (elem_ptr.index != 0) {
+ if (elem_ty.hasWellDefinedLayout(mod)) {
+ if (deref.parent) |*parent| {
+ // Update the byte offset (in-place)
+ const elem_size = try sema.typeAbiSize(elem_ty);
+ const offset = parent.byte_offset + elem_size * elem_ptr.index;
+ parent.byte_offset = try sema.usizeCast(block, src, offset);
+ }
+ } else {
+ deref.parent = null;
+ deref.ty_without_well_defined_layout = elem_ty;
+ }
}
- }
- if (elem_ptr.index >= check_len) {
- deref.pointee = null;
- break :blk deref;
- }
- if (elem_ptr.index == check_len - 1) {
- if (array_tv.ty.sentinel()) |sent| {
- deref.pointee = TypedValue{
- .ty = elem_ty,
- .val = sent,
- };
+ // If we're loading an elem that was derived from a different type
+ // than the true type of the underlying decl, we cannot deref directly
+ const ty_matches = if (deref.pointee != null and deref.pointee.?.ty.isArrayOrVector(mod)) x: {
+ const deref_elem_ty = deref.pointee.?.ty.childType(mod);
+ break :x (try sema.coerceInMemoryAllowed(block, deref_elem_ty, elem_ty, false, target, src, src)) == .ok or
+ (try sema.coerceInMemoryAllowed(block, elem_ty, deref_elem_ty, false, target, src, src)) == .ok;
+ } else false;
+ if (!ty_matches) {
+ deref.pointee = null;
break :blk deref;
}
- }
- deref.pointee = TypedValue{
- .ty = elem_ty,
- .val = try array_tv.val.elemValue(sema.mod, sema.arena, elem_ptr.index),
- };
- break :blk deref;
- },
-
- .slice => blk: {
- const slice = ptr_val.castTag(.slice).?.data;
- break :blk try sema.beginComptimePtrLoad(block, src, slice.ptr, null);
- },
- .field_ptr => blk: {
- const field_ptr = ptr_val.castTag(.field_ptr).?.data;
- const field_index = @intCast(u32, field_ptr.field_index);
- var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.container_ptr, field_ptr.container_ty);
-
- if (field_ptr.container_ty.hasWellDefinedLayout()) {
- const struct_ty = field_ptr.container_ty.castTag(.@"struct");
- if (struct_ty != null and struct_ty.?.data.layout == .Packed) {
- // packed structs are not byte addressable
- deref.parent = null;
- } else if (deref.parent) |*parent| {
- // Update the byte offset (in-place)
- try sema.resolveTypeLayout(field_ptr.container_ty);
- const field_offset = field_ptr.container_ty.structFieldOffset(field_index, target);
- parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset);
+ var array_tv = deref.pointee.?;
+ const check_len = array_tv.ty.arrayLenIncludingSentinel(mod);
+ if (maybe_array_ty) |load_ty| {
+ // It's possible that we're loading a [N]T, in which case we'd like to slice
+ // the pointee array directly from our parent array.
+ if (load_ty.isArrayOrVector(mod) and load_ty.childType(mod).eql(elem_ty, mod)) {
+ const N = try sema.usizeCast(block, src, load_ty.arrayLenIncludingSentinel(mod));
+ const elem_idx = try sema.usizeCast(block, src, elem_ptr.index);
+ deref.pointee = if (elem_ptr.index + N <= check_len) TypedValue{
+ .ty = try Type.array(sema.arena, N, null, elem_ty, mod),
+ .val = try array_tv.val.sliceArray(mod, sema.arena, elem_idx, elem_idx + N),
+ } else null;
+ break :blk deref;
+ }
}
- } else {
- deref.parent = null;
- deref.ty_without_well_defined_layout = field_ptr.container_ty;
- }
-
- const tv = deref.pointee orelse {
- deref.pointee = null;
- break :blk deref;
- };
- const coerce_in_mem_ok =
- (try sema.coerceInMemoryAllowed(block, field_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
- (try sema.coerceInMemoryAllowed(block, tv.ty, field_ptr.container_ty, false, target, src, src)) == .ok;
- if (!coerce_in_mem_ok) {
- deref.pointee = null;
- break :blk deref;
- }
- if (field_ptr.container_ty.isSlice()) {
- const slice_val = tv.val.castTag(.slice).?.data;
- deref.pointee = switch (field_index) {
- Value.Payload.Slice.ptr_index => TypedValue{
- .ty = field_ptr.container_ty.slicePtrFieldType(try sema.arena.create(Type.SlicePtrFieldTypeBuffer)),
- .val = slice_val.ptr,
- },
- Value.Payload.Slice.len_index => TypedValue{
- .ty = Type.usize,
- .val = slice_val.len,
- },
- else => unreachable,
- };
- } else {
- const field_ty = field_ptr.container_ty.structFieldType(field_index);
+ if (elem_ptr.index >= check_len) {
+ deref.pointee = null;
+ break :blk deref;
+ }
+ if (elem_ptr.index == check_len - 1) {
+ if (array_tv.ty.sentinel(mod)) |sent| {
+ deref.pointee = TypedValue{
+ .ty = elem_ty,
+ .val = sent,
+ };
+ break :blk deref;
+ }
+ }
deref.pointee = TypedValue{
- .ty = field_ty,
- .val = tv.val.fieldValue(tv.ty, field_index),
+ .ty = elem_ty,
+ .val = try array_tv.val.elemValue(mod, @intCast(usize, elem_ptr.index)),
};
- }
- break :blk deref;
- },
-
- .comptime_field_ptr => blk: {
- const comptime_field_ptr = ptr_val.castTag(.comptime_field_ptr).?.data;
- break :blk ComptimePtrLoadKit{
- .parent = null,
- .pointee = .{ .ty = comptime_field_ptr.field_ty, .val = comptime_field_ptr.field_val },
- .is_mutable = false,
- .ty_without_well_defined_layout = comptime_field_ptr.field_ty,
- };
- },
-
- .opt_payload_ptr,
- .eu_payload_ptr,
- => blk: {
- const payload_ptr = ptr_val.cast(Value.Payload.PayloadPtr).?.data;
- const payload_ty = switch (ptr_val.tag()) {
- .eu_payload_ptr => payload_ptr.container_ty.errorUnionPayload(),
- .opt_payload_ptr => try payload_ptr.container_ty.optionalChildAlloc(sema.arena),
- else => unreachable,
- };
- var deref = try sema.beginComptimePtrLoad(block, src, payload_ptr.container_ptr, payload_ptr.container_ty);
-
- // eu_payload_ptr and opt_payload_ptr never have a well-defined layout
- if (deref.parent != null) {
- deref.parent = null;
- deref.ty_without_well_defined_layout = payload_ptr.container_ty;
- }
+ break :blk deref;
+ },
+ .field => |field_ptr| blk: {
+ const field_index = @intCast(u32, field_ptr.index);
+ const container_ty = mod.intern_pool.typeOf(field_ptr.base).toType().childType(mod);
+ var deref = try sema.beginComptimePtrLoad(block, src, field_ptr.base.toValue(), container_ty);
+
+ if (container_ty.hasWellDefinedLayout(mod)) {
+ const struct_obj = mod.typeToStruct(container_ty);
+ if (struct_obj != null and struct_obj.?.layout == .Packed) {
+ // packed structs are not byte addressable
+ deref.parent = null;
+ } else if (deref.parent) |*parent| {
+ // Update the byte offset (in-place)
+ try sema.resolveTypeLayout(container_ty);
+ const field_offset = container_ty.structFieldOffset(field_index, mod);
+ parent.byte_offset = try sema.usizeCast(block, src, parent.byte_offset + field_offset);
+ }
+ } else {
+ deref.parent = null;
+ deref.ty_without_well_defined_layout = container_ty;
+ }
- if (deref.pointee) |*tv| {
+ const tv = deref.pointee orelse {
+ deref.pointee = null;
+ break :blk deref;
+ };
const coerce_in_mem_ok =
- (try sema.coerceInMemoryAllowed(block, payload_ptr.container_ty, tv.ty, false, target, src, src)) == .ok or
- (try sema.coerceInMemoryAllowed(block, tv.ty, payload_ptr.container_ty, false, target, src, src)) == .ok;
- if (coerce_in_mem_ok) {
- const payload_val = switch (ptr_val.tag()) {
- .eu_payload_ptr => if (tv.val.castTag(.eu_payload)) |some| some.data else {
- return sema.fail(block, src, "attempt to unwrap error: {s}", .{tv.val.castTag(.@"error").?.data.name});
+ (try sema.coerceInMemoryAllowed(block, container_ty, tv.ty, false, target, src, src)) == .ok or
+ (try sema.coerceInMemoryAllowed(block, tv.ty, container_ty, false, target, src, src)) == .ok;
+ if (!coerce_in_mem_ok) {
+ deref.pointee = null;
+ break :blk deref;
+ }
+
+ if (container_ty.isSlice(mod)) {
+ deref.pointee = switch (field_index) {
+ Value.slice_ptr_index => TypedValue{
+ .ty = container_ty.slicePtrFieldType(mod),
+ .val = tv.val.slicePtr(mod),
},
- .opt_payload_ptr => if (tv.val.castTag(.opt_payload)) |some| some.data else opt: {
- if (tv.val.isNull()) return sema.fail(block, src, "attempt to use null value", .{});
- break :opt tv.val;
+ Value.slice_len_index => TypedValue{
+ .ty = Type.usize,
+ .val = mod.intern_pool.indexToKey(try tv.val.intern(tv.ty, mod)).ptr.len.toValue(),
},
else => unreachable,
};
- tv.* = TypedValue{ .ty = payload_ty, .val = payload_val };
- break :blk deref;
+ } else {
+ const field_ty = container_ty.structFieldType(field_index, mod);
+ deref.pointee = TypedValue{
+ .ty = field_ty,
+ .val = try tv.val.fieldValue(mod, field_index),
+ };
}
- }
- deref.pointee = null;
- break :blk deref;
- },
- .null_value => {
- return sema.fail(block, src, "attempt to use null value", .{});
+ break :blk deref;
+ },
},
- .opt_payload => blk: {
- const opt_payload = ptr_val.castTag(.opt_payload).?.data;
- break :blk try sema.beginComptimePtrLoad(block, src, opt_payload, null);
+ .opt => |opt| switch (opt.val) {
+ .none => return sema.fail(block, src, "attempt to use null value", .{}),
+ else => |payload| try sema.beginComptimePtrLoad(block, src, payload.toValue(), null),
},
-
- .zero,
- .one,
- .int_u64,
- .int_i64,
- .int_big_positive,
- .int_big_negative,
- .variable,
- .extern_fn,
- .function,
- => return error.RuntimeLoad,
-
else => unreachable,
};
if (deref.pointee) |tv| {
- if (deref.parent == null and tv.ty.hasWellDefinedLayout()) {
+ if (deref.parent == null and tv.ty.hasWellDefinedLayout(mod)) {
deref.parent = .{ .tv = tv, .byte_offset = 0 };
}
}
@@ -27868,21 +29345,21 @@ fn bitCast(
inst_src: LazySrcLoc,
operand_src: ?LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const dest_ty = try sema.resolveTypeFields(dest_ty_unresolved);
try sema.resolveTypeLayout(dest_ty);
const old_ty = try sema.resolveTypeFields(sema.typeOf(inst));
try sema.resolveTypeLayout(old_ty);
- const target = sema.mod.getTarget();
- const dest_bits = dest_ty.bitSize(target);
- const old_bits = old_ty.bitSize(target);
+ const dest_bits = dest_ty.bitSize(mod);
+ const old_bits = old_ty.bitSize(mod);
if (old_bits != dest_bits) {
return sema.fail(block, inst_src, "@bitCast size mismatch: destination type '{}' has {d} bits but source type '{}' has {d} bits", .{
- dest_ty.fmt(sema.mod),
+ dest_ty.fmt(mod),
dest_bits,
- old_ty.fmt(sema.mod),
+ old_ty.fmt(mod),
old_bits,
});
}
@@ -27905,20 +29382,21 @@ fn bitCastVal(
new_ty: Type,
buffer_offset: usize,
) !?Value {
- const target = sema.mod.getTarget();
- if (old_ty.eql(new_ty, sema.mod)) return val;
+ const mod = sema.mod;
+ if (old_ty.eql(new_ty, mod)) return val;
// For types with well-defined memory layouts, we serialize them a byte buffer,
// then deserialize to the new type.
- const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(target));
+ const abi_size = try sema.usizeCast(block, src, old_ty.abiSize(mod));
const buffer = try sema.gpa.alloc(u8, abi_size);
defer sema.gpa.free(buffer);
- val.writeToMemory(old_ty, sema.mod, buffer) catch |err| switch (err) {
+ val.writeToMemory(old_ty, mod, buffer) catch |err| switch (err) {
+ error.OutOfMemory => return error.OutOfMemory,
error.ReinterpretDeclRef => return null,
error.IllDefinedMemoryLayout => unreachable, // Sema was supposed to emit a compile error already
- error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(sema.mod)}),
+ error.Unimplemented => return sema.fail(block, src, "TODO: implement writeToMemory for type '{}'", .{old_ty.fmt(mod)}),
};
- return try Value.readFromMemory(new_ty, sema.mod, buffer[buffer_offset..], sema.arena);
+ return try Value.readFromMemory(new_ty, mod, buffer[buffer_offset..], sema.arena);
}
fn coerceArrayPtrToSlice(
@@ -27928,25 +29406,32 @@ fn coerceArrayPtrToSlice(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
if (try sema.resolveMaybeUndefVal(inst)) |val| {
const ptr_array_ty = sema.typeOf(inst);
- const array_ty = ptr_array_ty.childType();
- const slice_val = try Value.Tag.slice.create(sema.arena, .{
- .ptr = val,
- .len = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen()),
- });
- return sema.addConstant(dest_ty, slice_val);
+ const array_ty = ptr_array_ty.childType(mod);
+ const slice_val = try mod.intern(.{ .ptr = .{
+ .ty = dest_ty.toIntern(),
+ .addr = switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .undef => .{ .int = try mod.intern(.{ .undef = .usize_type }) },
+ .ptr => |ptr| ptr.addr,
+ else => unreachable,
+ },
+ .len = (try mod.intValue(Type.usize, array_ty.arrayLen(mod))).toIntern(),
+ } });
+ return sema.addConstant(dest_ty, slice_val.toValue());
}
try sema.requireRuntimeBlock(block, inst_src, null);
return block.addTyOp(.array_to_slice, dest_ty, inst);
}
fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_result: *InMemoryCoercionResult) bool {
- const dest_info = dest_ty.ptrInfo().data;
- const inst_info = inst_ty.ptrInfo().data;
- const len0 = (inst_info.pointee_type.zigTypeTag() == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel() == 0 or
- (inst_info.pointee_type.arrayLen() == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or
- (inst_info.pointee_type.isTuple() and inst_info.pointee_type.structFieldCount() == 0);
+ const mod = sema.mod;
+ const dest_info = dest_ty.ptrInfo(mod);
+ const inst_info = inst_ty.ptrInfo(mod);
+ const len0 = (inst_info.pointee_type.zigTypeTag(mod) == .Array and (inst_info.pointee_type.arrayLenIncludingSentinel(mod) == 0 or
+ (inst_info.pointee_type.arrayLen(mod) == 0 and dest_info.sentinel == null and dest_info.size != .C and dest_info.size != .Many))) or
+ (inst_info.pointee_type.isTuple(mod) and inst_info.pointee_type.structFieldCount(mod) == 0);
const ok_cv_qualifiers =
((inst_info.mutable or !dest_info.mutable) or len0) and
@@ -27970,17 +29455,16 @@ fn checkPtrAttributes(sema: *Sema, dest_ty: Type, inst_ty: Type, in_memory_resul
}
if (inst_info.@"align" == 0 and dest_info.@"align" == 0) return true;
if (len0) return true;
- const target = sema.mod.getTarget();
const inst_align = if (inst_info.@"align" != 0)
inst_info.@"align"
else
- inst_info.pointee_type.abiAlignment(target);
+ inst_info.pointee_type.abiAlignment(mod);
const dest_align = if (dest_info.@"align" != 0)
dest_info.@"align"
else
- dest_info.pointee_type.abiAlignment(target);
+ dest_info.pointee_type.abiAlignment(mod);
if (dest_align > inst_align) {
in_memory_result.* = .{ .ptr_alignment = .{
@@ -27999,26 +29483,30 @@ fn coerceCompatiblePtrs(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
const inst_ty = sema.typeOf(inst);
if (try sema.resolveMaybeUndefVal(inst)) |val| {
- if (!val.isUndef() and val.isNull() and !dest_ty.isAllowzeroPtr()) {
+ if (!val.isUndef(mod) and val.isNull(mod) and !dest_ty.isAllowzeroPtr(mod)) {
return sema.fail(block, inst_src, "null pointer casted to type '{}'", .{dest_ty.fmt(sema.mod)});
}
// The comptime Value representation is compatible with both types.
- return sema.addConstant(dest_ty, val);
+ return sema.addConstant(
+ dest_ty,
+ try mod.getCoerced((try val.intern(inst_ty, mod)).toValue(), dest_ty),
+ );
}
try sema.requireRuntimeBlock(block, inst_src, null);
- const inst_allows_zero = inst_ty.zigTypeTag() != .Pointer or inst_ty.ptrAllowsZero();
- if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero() and
- (try sema.typeHasRuntimeBits(dest_ty.elemType2()) or dest_ty.elemType2().zigTypeTag() == .Fn))
+ const inst_allows_zero = inst_ty.zigTypeTag(mod) != .Pointer or inst_ty.ptrAllowsZero(mod);
+ if (block.wantSafety() and inst_allows_zero and !dest_ty.ptrAllowsZero(mod) and
+ (try sema.typeHasRuntimeBits(dest_ty.elemType2(mod)) or dest_ty.elemType2(mod).zigTypeTag(mod) == .Fn))
{
- const actual_ptr = if (inst_ty.isSlice())
+ const actual_ptr = if (inst_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, inst_src, inst, inst_ty)
else
inst;
const ptr_int = try block.addUnOp(.ptrtoint, actual_ptr);
const is_non_zero = try block.addBinOp(.cmp_neq, ptr_int, .zero_usize);
- const ok = if (inst_ty.isSlice()) ok: {
+ const ok = if (inst_ty.isSlice(mod)) ok: {
const len = try sema.analyzeSliceLen(block, inst_src, inst);
const len_zero = try block.addBinOp(.cmp_eq, len, .zero_usize);
break :ok try block.addBinOp(.bit_or, len_zero, is_non_zero);
@@ -28036,9 +29524,11 @@ fn coerceEnumToUnion(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const inst_ty = sema.typeOf(inst);
- const tag_ty = union_ty.unionTagType() orelse {
+ const tag_ty = union_ty.unionTagType(mod) orelse {
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
union_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
@@ -28065,16 +29555,18 @@ fn coerceEnumToUnion(
return sema.failWithOwnedErrorMsg(msg);
};
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(union_ty).?;
const field = union_obj.fields.values()[field_index];
const field_ty = try sema.resolveTypeFields(field.ty);
- if (field_ty.zigTypeTag() == .NoReturn) {
+ if (field_ty.zigTypeTag(mod) == .NoReturn) {
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "cannot initialize 'noreturn' field of union", .{});
errdefer msg.destroy(sema.gpa);
const field_name = union_obj.fields.keys()[field_index];
- try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
+ try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
+ field_name.fmt(ip),
+ });
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
};
@@ -28083,27 +29575,27 @@ fn coerceEnumToUnion(
const opv = (try sema.typeHasOnePossibleValue(field_ty)) orelse {
const msg = msg: {
const field_name = union_obj.fields.keys()[field_index];
- const msg = try sema.errMsg(block, inst_src, "coercion from enum '{}' to union '{}' must initialize '{}' field '{s}'", .{
- inst_ty.fmt(sema.mod), union_ty.fmt(sema.mod), field_ty.fmt(sema.mod), field_name,
+ 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),
});
errdefer msg.destroy(sema.gpa);
- try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' declared here", .{field_name});
+ try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' declared here", .{
+ field_name.fmt(ip),
+ });
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
};
- return sema.addConstant(union_ty, try Value.Tag.@"union".create(sema.arena, .{
- .tag = val,
- .val = opv,
- }));
+ return sema.addConstant(union_ty, try mod.unionValue(union_ty, val, opv));
}
try sema.requireRuntimeBlock(block, inst_src, null);
- if (tag_ty.isNonexhaustiveEnum()) {
+ if (tag_ty.isNonexhaustiveEnum(mod)) {
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "runtime coercion to union '{}' from non-exhaustive enum", .{
union_ty.fmt(sema.mod),
@@ -28115,13 +29607,13 @@ fn coerceEnumToUnion(
return sema.failWithOwnedErrorMsg(msg);
}
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(union_ty).?;
{
var msg: ?*Module.ErrorMsg = null;
errdefer if (msg) |some| some.destroy(sema.gpa);
for (union_obj.fields.values(), 0..) |field, i| {
- if (field.ty.zigTypeTag() == .NoReturn) {
+ if (field.ty.zigTypeTag(mod) == .NoReturn) {
const err_msg = msg orelse try sema.errMsg(
block,
inst_src,
@@ -28141,7 +29633,7 @@ fn coerceEnumToUnion(
}
// If the union has all fields 0 bits, the union value is just the enum value.
- if (union_ty.unionHasAllZeroBitFieldTypes()) {
+ if (union_ty.unionHasAllZeroBitFieldTypes(mod)) {
return block.addBitCast(union_ty, enum_tag);
}
@@ -28159,8 +29651,11 @@ fn coerceEnumToUnion(
while (it.next()) |field| : (field_index += 1) {
const field_name = field.key_ptr.*;
const field_ty = field.value_ptr.ty;
- if (!field_ty.hasRuntimeBits()) continue;
- try sema.addFieldErrNote(union_ty, field_index, msg, "field '{s}' has type '{}'", .{ field_name, field_ty.fmt(sema.mod) });
+ if (!(try sema.typeHasRuntimeBits(field_ty))) continue;
+ try sema.addFieldErrNote(union_ty, field_index, msg, "field '{}' has type '{}'", .{
+ field_name.fmt(ip),
+ field_ty.fmt(sema.mod),
+ });
}
try sema.addDeclaredHereNote(msg, union_ty);
break :msg msg;
@@ -28176,36 +29671,55 @@ fn coerceAnonStructToUnion(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
const inst_ty = sema.typeOf(inst);
- const field_count = inst_ty.structFieldCount();
- if (field_count != 1) {
- const msg = msg: {
- const msg = if (field_count > 1) try sema.errMsg(
- block,
- inst_src,
- "cannot initialize multiple union fields at once; unions can only have one active field",
- .{},
- ) else try sema.errMsg(
- block,
- inst_src,
- "union initializer must initialize one field",
- .{},
- );
- errdefer msg.destroy(sema.gpa);
+ const field_info: union(enum) {
+ name: InternPool.NullTerminatedString,
+ count: usize,
+ } = switch (mod.intern_pool.indexToKey(inst_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len == 1)
+ .{ .name = anon_struct_type.names[0] }
+ else
+ .{ .count = anon_struct_type.names.len },
+ .struct_type => |struct_type| name: {
+ const field_names = mod.structPtrUnwrap(struct_type.index).?.fields.keys();
+ break :name if (field_names.len == 1)
+ .{ .name = field_names[0] }
+ else
+ .{ .count = field_names.len };
+ },
+ else => unreachable,
+ };
+ switch (field_info) {
+ .name => |field_name| {
+ const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
+ return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
+ },
+ .count => |field_count| {
+ assert(field_count != 1);
+ const msg = msg: {
+ const msg = if (field_count > 1) try sema.errMsg(
+ block,
+ inst_src,
+ "cannot initialize multiple union fields at once; unions can only have one active field",
+ .{},
+ ) else try sema.errMsg(
+ block,
+ inst_src,
+ "union initializer must initialize one field",
+ .{},
+ );
+ errdefer msg.destroy(sema.gpa);
- // TODO add notes for where the anon struct was created to point out
- // the extra fields.
+ // TODO add notes for where the anon struct was created to point out
+ // the extra fields.
- try sema.addDeclaredHereNote(msg, union_ty);
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(msg);
+ try sema.addDeclaredHereNote(msg, union_ty);
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ },
}
-
- const anon_struct = inst_ty.castTag(.anon_struct).?.data;
- const field_name = anon_struct.names[0];
- const init = try sema.structFieldVal(block, inst_src, inst, field_name, inst_src, inst_ty);
- return sema.unionInit(block, init, inst_src, union_ty, union_ty_src, field_name, inst_src);
}
fn coerceAnonStructToUnionPtrs(
@@ -28216,7 +29730,8 @@ fn coerceAnonStructToUnionPtrs(
ptr_anon_struct: Air.Inst.Ref,
anon_struct_src: LazySrcLoc,
) !Air.Inst.Ref {
- const union_ty = ptr_union_ty.childType();
+ const mod = sema.mod;
+ const union_ty = ptr_union_ty.childType(mod);
const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
const union_inst = try sema.coerceAnonStructToUnion(block, union_ty, union_ty_src, anon_struct, anon_struct_src);
return sema.analyzeRef(block, union_ty_src, union_inst);
@@ -28230,7 +29745,8 @@ fn coerceAnonStructToStructPtrs(
ptr_anon_struct: Air.Inst.Ref,
anon_struct_src: LazySrcLoc,
) !Air.Inst.Ref {
- const struct_ty = ptr_struct_ty.childType();
+ const mod = sema.mod;
+ const struct_ty = ptr_struct_ty.childType(mod);
const anon_struct = try sema.analyzeLoad(block, anon_struct_src, ptr_anon_struct, anon_struct_src);
const struct_inst = try sema.coerceTupleToStruct(block, struct_ty, anon_struct, anon_struct_src);
return sema.analyzeRef(block, struct_ty_src, struct_inst);
@@ -28245,15 +29761,16 @@ fn coerceArrayLike(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
const inst_ty = sema.typeOf(inst);
- const inst_len = inst_ty.arrayLen();
- const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen());
- const target = sema.mod.getTarget();
+ const inst_len = inst_ty.arrayLen(mod);
+ const dest_len = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLen(mod));
+ const target = mod.getTarget();
if (dest_len != inst_len) {
const msg = msg: {
const msg = try sema.errMsg(block, inst_src, "expected type '{}', found '{}'", .{
- dest_ty.fmt(sema.mod), inst_ty.fmt(sema.mod),
+ dest_ty.fmt(mod), inst_ty.fmt(mod),
});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, dest_ty_src, msg, "destination has length {d}", .{dest_len});
@@ -28263,35 +29780,32 @@ fn coerceArrayLike(
return sema.failWithOwnedErrorMsg(msg);
}
- const dest_elem_ty = dest_ty.childType();
- const inst_elem_ty = inst_ty.childType();
+ const dest_elem_ty = dest_ty.childType(mod);
+ const inst_elem_ty = inst_ty.childType(mod);
const in_memory_result = try sema.coerceInMemoryAllowed(block, dest_elem_ty, inst_elem_ty, false, target, dest_ty_src, inst_src);
if (in_memory_result == .ok) {
if (try sema.resolveMaybeUndefVal(inst)) |inst_val| {
// These types share the same comptime value representation.
- return sema.addConstant(dest_ty, inst_val);
+ return sema.coerceInMemory(inst_val, dest_ty);
}
try sema.requireRuntimeBlock(block, inst_src, null);
return block.addBitCast(dest_ty, inst);
}
- const element_vals = try sema.arena.alloc(Value, dest_len);
+ const element_vals = try sema.arena.alloc(InternPool.Index, dest_len);
const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_len);
var runtime_src: ?LazySrcLoc = null;
- for (element_vals, 0..) |*elem, i| {
- const index_ref = try sema.addConstant(
- Type.usize,
- try Value.Tag.int_u64.create(sema.arena, i),
- );
+ for (element_vals, element_refs, 0..) |*val, *ref, i| {
+ const index_ref = try sema.addConstant(Type.usize, try mod.intValue(Type.usize, i));
const src = inst_src; // TODO better source location
const elem_src = inst_src; // TODO better source location
const elem_ref = try sema.elemValArray(block, src, inst_src, inst, elem_src, index_ref, true);
const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
- element_refs[i] = coerced;
+ ref.* = coerced;
if (runtime_src == null) {
if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| {
- elem.* = elem_val;
+ val.* = try elem_val.intern(dest_elem_ty, mod);
} else {
runtime_src = elem_src;
}
@@ -28303,10 +29817,10 @@ fn coerceArrayLike(
return block.addAggregateInit(dest_ty, element_refs);
}
- return sema.addConstant(
- dest_ty,
- try Value.Tag.aggregate.create(sema.arena, element_vals),
- );
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = dest_ty.toIntern(),
+ .storage = .{ .elems = element_vals },
+ } })).toValue());
}
/// If the lengths match, coerces element-wise.
@@ -28318,9 +29832,10 @@ fn coerceTupleToArray(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
const inst_ty = sema.typeOf(inst);
- const inst_len = inst_ty.arrayLen();
- const dest_len = dest_ty.arrayLen();
+ const inst_len = inst_ty.arrayLen(mod);
+ const dest_len = dest_ty.arrayLen(mod);
if (dest_len != inst_len) {
const msg = msg: {
@@ -28335,26 +29850,27 @@ fn coerceTupleToArray(
return sema.failWithOwnedErrorMsg(msg);
}
- const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_ty.arrayLenIncludingSentinel());
- const element_vals = try sema.arena.alloc(Value, dest_elems);
+ const dest_elems = try sema.usizeCast(block, dest_ty_src, dest_len);
+ const element_vals = try sema.arena.alloc(InternPool.Index, dest_elems);
const element_refs = try sema.arena.alloc(Air.Inst.Ref, dest_elems);
- const dest_elem_ty = dest_ty.childType();
+ const dest_elem_ty = dest_ty.childType(mod);
var runtime_src: ?LazySrcLoc = null;
- for (element_vals, 0..) |*elem, i_usize| {
+ for (element_vals, element_refs, 0..) |*val, *ref, i_usize| {
const i = @intCast(u32, i_usize);
if (i_usize == inst_len) {
- elem.* = dest_ty.sentinel().?;
- element_refs[i] = try sema.addConstant(dest_elem_ty, elem.*);
+ const sentinel_val = dest_ty.sentinel(mod).?;
+ val.* = sentinel_val.toIntern();
+ ref.* = try sema.addConstant(dest_elem_ty, sentinel_val);
break;
}
const elem_src = inst_src; // TODO better source location
const elem_ref = try sema.tupleField(block, inst_src, inst, elem_src, i);
const coerced = try sema.coerce(block, dest_elem_ty, elem_ref, elem_src);
- element_refs[i] = coerced;
+ ref.* = coerced;
if (runtime_src == null) {
if (try sema.resolveMaybeUndefVal(coerced)) |elem_val| {
- elem.* = elem_val;
+ val.* = try elem_val.intern(dest_elem_ty, mod);
} else {
runtime_src = elem_src;
}
@@ -28366,10 +29882,10 @@ fn coerceTupleToArray(
return block.addAggregateInit(dest_ty, element_refs);
}
- return sema.addConstant(
- dest_ty,
- try Value.Tag.aggregate.create(sema.arena, element_vals),
- );
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .aggregate = .{
+ .ty = dest_ty.toIntern(),
+ .storage = .{ .elems = element_vals },
+ } })).toValue());
}
/// If the lengths match, coerces element-wise.
@@ -28381,10 +29897,11 @@ fn coerceTupleToSlicePtrs(
ptr_tuple: Air.Inst.Ref,
tuple_src: LazySrcLoc,
) !Air.Inst.Ref {
- const tuple_ty = sema.typeOf(ptr_tuple).childType();
+ const mod = sema.mod;
+ const tuple_ty = sema.typeOf(ptr_tuple).childType(mod);
const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
- const slice_info = slice_ty.ptrInfo().data;
- const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(), slice_info.sentinel, slice_info.pointee_type, sema.mod);
+ const slice_info = slice_ty.ptrInfo(mod);
+ const array_ty = try Type.array(sema.arena, tuple_ty.structFieldCount(mod), slice_info.sentinel, slice_info.pointee_type, sema.mod);
const array_inst = try sema.coerceTupleToArray(block, array_ty, slice_ty_src, tuple, tuple_src);
if (slice_info.@"align" != 0) {
return sema.fail(block, slice_ty_src, "TODO: override the alignment of the array decl we create here", .{});
@@ -28402,8 +29919,9 @@ fn coerceTupleToArrayPtrs(
ptr_tuple: Air.Inst.Ref,
tuple_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
const tuple = try sema.analyzeLoad(block, tuple_src, ptr_tuple, tuple_src);
- const ptr_info = ptr_array_ty.ptrInfo().data;
+ const ptr_info = ptr_array_ty.ptrInfo(mod);
const array_ty = ptr_info.pointee_type;
const array_inst = try sema.coerceTupleToArray(block, array_ty, array_ty_src, tuple, tuple_src);
if (ptr_info.@"align" != 0) {
@@ -28422,27 +29940,41 @@ fn coerceTupleToStruct(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const struct_ty = try sema.resolveTypeFields(dest_ty);
- if (struct_ty.isTupleOrAnonStruct()) {
+ if (struct_ty.isTupleOrAnonStruct(mod)) {
return sema.coerceTupleToTuple(block, struct_ty, inst, inst_src);
}
- const fields = struct_ty.structFields();
- const field_vals = try sema.arena.alloc(Value, fields.count());
+ const fields = struct_ty.structFields(mod);
+ const field_vals = try sema.arena.alloc(InternPool.Index, fields.count());
const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
@memset(field_refs, .none);
const inst_ty = sema.typeOf(inst);
var runtime_src: ?LazySrcLoc = null;
- const field_count = inst_ty.structFieldCount();
- var field_i: u32 = 0;
- while (field_i < field_count) : (field_i += 1) {
- const field_src = inst_src; // TODO better source location
- const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
- payload.data.names[field_i]
+ const field_count = switch (ip.indexToKey(inst_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| anon_struct_type.types.len,
+ .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
+ struct_obj.fields.count()
else
- try std.fmt.allocPrint(sema.arena, "{d}", .{field_i});
+ 0,
+ else => unreachable,
+ };
+ for (0..field_count) |field_index_usize| {
+ const field_i = @intCast(u32, field_index_usize);
+ const field_src = inst_src; // TODO better source location
+ // https://github.com/ziglang/zig/issues/15709
+ const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0)
+ anon_struct_type.names[field_i]
+ else
+ try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i],
+ else => unreachable,
+ };
const field_index = try sema.structFieldIndex(block, struct_ty, field_name, field_src);
const field = fields.values()[field_index];
const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
@@ -28453,13 +29985,13 @@ fn coerceTupleToStruct(
return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known");
};
- if (!init_val.eql(field.default_val, field.ty, sema.mod)) {
+ if (!init_val.eql(field.default_val.toValue(), field.ty, sema.mod)) {
return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
}
}
if (runtime_src == null) {
if (try sema.resolveMaybeUndefVal(coerced)) |field_val| {
- field_vals[field_index] = field_val;
+ field_vals[field_index] = field_val.toIntern();
} else {
runtime_src = field_src;
}
@@ -28476,9 +30008,9 @@ fn coerceTupleToStruct(
const field_name = fields.keys()[i];
const field = fields.values()[i];
const field_src = inst_src; // TODO better source location
- if (field.default_val.tag() == .unreachable_value) {
- const template = "missing struct field: {s}";
- const args = .{field_name};
+ if (field.default_val == .none) {
+ const template = "missing struct field: {}";
+ const args = .{field_name.fmt(ip)};
if (root_msg) |msg| {
try sema.errNote(block, field_src, msg, template, args);
} else {
@@ -28489,7 +30021,7 @@ fn coerceTupleToStruct(
if (runtime_src == null) {
field_vals[i] = field.default_val;
} else {
- field_ref.* = try sema.addConstant(field.ty, field.default_val);
+ field_ref.* = try sema.addConstant(field.ty, field.default_val.toValue());
}
}
@@ -28504,10 +30036,14 @@ fn coerceTupleToStruct(
return block.addAggregateInit(struct_ty, field_refs);
}
- return sema.addConstant(
- struct_ty,
- try Value.Tag.aggregate.create(sema.arena, field_vals),
- );
+ const struct_val = try mod.intern(.{ .aggregate = .{
+ .ty = struct_ty.toIntern(),
+ .storage = .{ .elems = field_vals },
+ } });
+ // TODO: figure out InternPool removals for incremental compilation
+ //errdefer ip.remove(struct_val);
+
+ return sema.addConstant(struct_ty, struct_val.toValue());
}
fn coerceTupleToTuple(
@@ -28517,47 +30053,76 @@ fn coerceTupleToTuple(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
- const dest_field_count = tuple_ty.structFieldCount();
- const field_vals = try sema.arena.alloc(Value, dest_field_count);
+ const mod = sema.mod;
+ 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| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
+ struct_obj.fields.count()
+ else
+ 0,
+ else => unreachable,
+ };
+ const field_vals = try sema.arena.alloc(InternPool.Index, dest_field_count);
const field_refs = try sema.arena.alloc(Air.Inst.Ref, field_vals.len);
@memset(field_refs, .none);
const inst_ty = sema.typeOf(inst);
- const inst_field_count = inst_ty.structFieldCount();
- if (inst_field_count > dest_field_count) return error.NotCoercible;
+ 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| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj|
+ struct_obj.fields.count()
+ else
+ 0,
+ else => unreachable,
+ };
+ if (src_field_count > dest_field_count) return error.NotCoercible;
var runtime_src: ?LazySrcLoc = null;
- var field_i: u32 = 0;
- while (field_i < inst_field_count) : (field_i += 1) {
+ for (0..dest_field_count) |field_index_usize| {
+ const field_i = @intCast(u32, field_index_usize);
const field_src = inst_src; // TODO better source location
- const field_name = if (inst_ty.castTag(.anon_struct)) |payload|
- payload.data.names[field_i]
- else
- try std.fmt.allocPrint(sema.arena, "{d}", .{field_i});
+ // https://github.com/ziglang/zig/issues/15709
+ const field_name: InternPool.NullTerminatedString = switch (ip.indexToKey(inst_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| if (anon_struct_type.names.len > 0)
+ anon_struct_type.names[field_i]
+ else
+ try ip.getOrPutStringFmt(sema.gpa, "{d}", .{field_i}),
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.keys()[field_i],
+ else => unreachable,
+ };
- if (mem.eql(u8, field_name, "len")) {
+ if (ip.stringEqlSlice(field_name, "len"))
return sema.fail(block, field_src, "cannot assign to 'len' field of tuple", .{});
- }
+
+ const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| anon_struct_type.types[field_index_usize].toType(),
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].ty,
+ else => unreachable,
+ };
+ const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| anon_struct_type.values[field_index_usize],
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[field_index_usize].default_val,
+ else => unreachable,
+ };
const field_index = try sema.tupleFieldIndex(block, tuple_ty, field_name, field_src);
- const field_ty = tuple_ty.structFieldType(field_i);
- const default_val = tuple_ty.structFieldDefaultValue(field_i);
const elem_ref = try sema.tupleField(block, inst_src, inst, field_src, field_i);
const coerced = try sema.coerce(block, field_ty, elem_ref, field_src);
field_refs[field_index] = coerced;
- if (default_val.tag() != .unreachable_value) {
+ if (default_val != .none) {
const init_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
return sema.failWithNeededComptime(block, field_src, "value stored in comptime field must be comptime-known");
};
- if (!init_val.eql(default_val, field_ty, sema.mod)) {
+ if (!init_val.eql(default_val.toValue(), field_ty, sema.mod)) {
return sema.failWithInvalidComptimeFieldStore(block, field_src, inst_ty, field_i);
}
}
if (runtime_src == null) {
if (try sema.resolveMaybeUndefVal(coerced)) |field_val| {
- field_vals[field_index] = field_val;
+ field_vals[field_index] = field_val.toIntern();
} else {
runtime_src = field_src;
}
@@ -28571,12 +30136,15 @@ fn coerceTupleToTuple(
for (field_refs, 0..) |*field_ref, i| {
if (field_ref.* != .none) continue;
- const default_val = tuple_ty.structFieldDefaultValue(i);
- const field_ty = tuple_ty.structFieldType(i);
+ const default_val = switch (ip.indexToKey(tuple_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| anon_struct_type.values[i],
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].default_val,
+ else => unreachable,
+ };
const field_src = inst_src; // TODO better source location
- if (default_val.tag() == .unreachable_value) {
- if (tuple_ty.isTuple()) {
+ if (default_val == .none) {
+ if (tuple_ty.isTuple(mod)) {
const template = "missing tuple field: {d}";
if (root_msg) |msg| {
try sema.errNote(block, field_src, msg, template, .{i});
@@ -28585,8 +30153,8 @@ fn coerceTupleToTuple(
}
continue;
}
- const template = "missing struct field: {s}";
- const args = .{tuple_ty.structFieldName(i)};
+ const template = "missing struct field: {}";
+ const args = .{tuple_ty.structFieldName(i, mod).fmt(ip)};
if (root_msg) |msg| {
try sema.errNote(block, field_src, msg, template, args);
} else {
@@ -28597,7 +30165,12 @@ fn coerceTupleToTuple(
if (runtime_src == null) {
field_vals[i] = default_val;
} else {
- field_ref.* = try sema.addConstant(field_ty, default_val);
+ const field_ty = switch (ip.indexToKey(tuple_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| anon_struct_type.types[i].toType(),
+ .struct_type => |struct_type| mod.structPtrUnwrap(struct_type.index).?.fields.values()[i].ty,
+ else => unreachable,
+ };
+ field_ref.* = try sema.addConstant(field_ty, default_val.toValue());
}
}
@@ -28614,7 +30187,10 @@ fn coerceTupleToTuple(
return sema.addConstant(
tuple_ty,
- try Value.Tag.aggregate.create(sema.arena, field_vals),
+ (try mod.intern(.{ .aggregate = .{
+ .ty = tuple_ty.toIntern(),
+ .storage = .{ .elems = field_vals },
+ } })).toValue(),
);
}
@@ -28628,10 +30204,10 @@ fn analyzeDeclVal(
if (sema.decl_val_table.get(decl_index)) |result| {
return result;
}
- const decl_ref = try sema.analyzeDeclRef(decl_index);
+ const decl_ref = try sema.analyzeDeclRefInner(decl_index, false);
const result = try sema.analyzeLoad(block, src, decl_ref, src);
if (Air.refToIndex(result)) |index| {
- if (sema.air_instructions.items(.tag)[index] == .constant and !block.is_typeof) {
+ if (sema.air_instructions.items(.tag)[index] == .interned and !block.is_typeof) {
try sema.decl_val_table.put(sema.gpa, decl_index, result);
}
}
@@ -28652,13 +30228,14 @@ fn addReferencedBy(
}
fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void {
- const decl = sema.mod.declPtr(decl_index);
+ const mod = sema.mod;
+ const decl = mod.declPtr(decl_index);
if (decl.analysis == .in_progress) {
- const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(), "dependency loop detected", .{});
+ const msg = try Module.ErrorMsg.create(sema.gpa, decl.srcLoc(mod), "dependency loop detected", .{});
return sema.failWithOwnedErrorMsg(msg);
}
- sema.mod.ensureDeclAnalyzed(decl_index) catch |err| {
+ mod.ensureDeclAnalyzed(decl_index) catch |err| {
if (sema.owner_func) |owner_func| {
owner_func.state = .dependency_failure;
} else {
@@ -28668,7 +30245,7 @@ fn ensureDeclAnalyzed(sema: *Sema, decl_index: Decl.Index) CompileError!void {
};
}
-fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void {
+fn ensureFuncBodyAnalyzed(sema: *Sema, func: Module.Fn.Index) CompileError!void {
sema.mod.ensureFuncBodyAnalyzed(func) catch |err| {
if (sema.owner_func) |owner_func| {
owner_func.state = .dependency_failure;
@@ -28680,49 +30257,75 @@ fn ensureFuncBodyAnalyzed(sema: *Sema, func: *Module.Fn) CompileError!void {
}
fn refValue(sema: *Sema, block: *Block, ty: Type, val: Value) !Value {
+ const mod = sema.mod;
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
const decl = try anon_decl.finish(
- try ty.copy(anon_decl.arena()),
- try val.copy(anon_decl.arena()),
+ ty,
+ val,
0, // default alignment
);
- try sema.mod.declareDeclDependency(sema.owner_decl_index, decl);
- return try Value.Tag.decl_ref.create(sema.arena, decl);
+ try sema.maybeQueueFuncBodyAnalysis(decl);
+ try mod.declareDeclDependency(sema.owner_decl_index, decl);
+ const result = try mod.intern(.{ .ptr = .{
+ .ty = (try mod.singleConstPtrType(ty)).toIntern(),
+ .addr = .{ .decl = decl },
+ } });
+ return result.toValue();
}
fn optRefValue(sema: *Sema, block: *Block, ty: Type, opt_val: ?Value) !Value {
- const val = opt_val orelse return Value.null;
- const ptr_val = try sema.refValue(block, ty, val);
- const result = try Value.Tag.opt_payload.create(sema.arena, ptr_val);
- return result;
+ const mod = sema.mod;
+ const ptr_anyopaque_ty = try mod.singleConstPtrType(Type.anyopaque);
+ return (try mod.intern(.{ .opt = .{
+ .ty = (try mod.optionalType(ptr_anyopaque_ty.toIntern())).toIntern(),
+ .val = if (opt_val) |val| (try mod.getCoerced(
+ try sema.refValue(block, ty, val),
+ ptr_anyopaque_ty,
+ )).toIntern() else .none,
+ } })).toValue();
}
fn analyzeDeclRef(sema: *Sema, decl_index: Decl.Index) CompileError!Air.Inst.Ref {
- try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
+ return sema.analyzeDeclRefInner(decl_index, true);
+}
+
+/// Analyze a reference to the decl at the given index. Ensures the underlying decl is analyzed, but
+/// only triggers analysis for function bodies if `analyze_fn_body` is true. If it's possible for a
+/// decl_ref to end up in runtime code, the function body must be analyzed: `analyzeDeclRef` wraps
+/// this function with `analyze_fn_body` set to true.
+fn analyzeDeclRefInner(sema: *Sema, decl_index: Decl.Index, analyze_fn_body: bool) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
+ try mod.declareDeclDependency(sema.owner_decl_index, decl_index);
try sema.ensureDeclAnalyzed(decl_index);
- const decl = sema.mod.declPtr(decl_index);
+ const decl = mod.declPtr(decl_index);
const decl_tv = try decl.typedValue();
- if (decl_tv.val.castTag(.variable)) |payload| {
- const variable = payload.data;
- const ty = try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = decl_tv.ty,
- .mutable = variable.is_mutable,
- .@"addrspace" = decl.@"addrspace",
- .@"align" = decl.@"align",
- });
- return sema.addConstant(ty, try Value.Tag.decl_ref.create(sema.arena, decl_index));
+ const ptr_ty = try mod.ptrType(.{
+ .child = decl_tv.ty.toIntern(),
+ .flags = .{
+ .alignment = InternPool.Alignment.fromByteUnits(decl.@"align"),
+ .is_const = if (decl.val.getVariable(mod)) |variable| variable.is_const else true,
+ .address_space = decl.@"addrspace",
+ },
+ });
+ if (analyze_fn_body) {
+ try sema.maybeQueueFuncBodyAnalysis(decl_index);
}
- return sema.addConstant(
- try Type.ptr(sema.arena, sema.mod, .{
- .pointee_type = decl_tv.ty,
- .mutable = false,
- .@"addrspace" = decl.@"addrspace",
- .@"align" = decl.@"align",
- }),
- try Value.Tag.decl_ref.create(sema.arena, decl_index),
- );
+ return sema.addConstant(ptr_ty, (try mod.intern(.{ .ptr = .{
+ .ty = ptr_ty.toIntern(),
+ .addr = .{ .decl = decl_index },
+ } })).toValue());
+}
+
+fn maybeQueueFuncBodyAnalysis(sema: *Sema, decl_index: Decl.Index) !void {
+ const mod = sema.mod;
+ const decl = mod.declPtr(decl_index);
+ const tv = try decl.typedValue();
+ if (tv.ty.zigTypeTag(mod) != .Fn) return;
+ if (!try sema.fnHasRuntimeBits(tv.ty)) return;
+ const func_index = mod.intern_pool.indexToFunc(tv.val.toIntern()).unwrap() orelse return; // undef or extern_fn
+ try mod.ensureFuncBodyAnalysisQueued(func_index);
}
fn analyzeRef(
@@ -28734,18 +30337,16 @@ fn analyzeRef(
const operand_ty = sema.typeOf(operand);
if (try sema.resolveMaybeUndefVal(operand)) |val| {
- switch (val.tag()) {
- .extern_fn, .function => {
- const decl_index = val.pointerDecl().?;
- return sema.analyzeDeclRef(decl_index);
- },
+ switch (sema.mod.intern_pool.indexToKey(val.toIntern())) {
+ .extern_func => |extern_func| return sema.analyzeDeclRef(extern_func.decl),
+ .func => |func| return sema.analyzeDeclRef(sema.mod.funcPtr(func.index).owner_decl),
else => {},
}
var anon_decl = try block.startAnonDecl();
defer anon_decl.deinit();
return sema.analyzeDeclRef(try anon_decl.finish(
- try operand_ty.copy(anon_decl.arena()),
- try val.copy(anon_decl.arena()),
+ operand_ty,
+ val,
0, // default alignment
));
}
@@ -28775,9 +30376,10 @@ fn analyzeLoad(
ptr: Air.Inst.Ref,
ptr_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const ptr_ty = sema.typeOf(ptr);
- const elem_ty = switch (ptr_ty.zigTypeTag()) {
- .Pointer => ptr_ty.childType(),
+ const elem_ty = switch (ptr_ty.zigTypeTag(mod)) {
+ .Pointer => ptr_ty.childType(mod),
else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ty.fmt(sema.mod)}),
};
@@ -28787,11 +30389,11 @@ fn analyzeLoad(
if (try sema.resolveDefinedValue(block, ptr_src, ptr)) |ptr_val| {
if (try sema.pointerDeref(block, src, ptr_val, ptr_ty)) |elem_val| {
- return sema.addConstant(elem_ty, elem_val);
+ return sema.addConstant(elem_ty, try mod.getCoerced(elem_val, elem_ty));
}
}
- if (ptr_ty.ptrInfo().data.vector_index == .runtime) {
+ if (ptr_ty.ptrInfo(mod).vector_index == .runtime) {
const ptr_inst = Air.refToIndex(ptr).?;
const air_tags = sema.air_instructions.items(.tag);
if (air_tags[ptr_inst] == .ptr_elem_ptr) {
@@ -28814,11 +30416,11 @@ fn analyzeSlicePtr(
slice: Air.Inst.Ref,
slice_ty: Type,
) CompileError!Air.Inst.Ref {
- const buf = try sema.arena.create(Type.SlicePtrFieldTypeBuffer);
- const result_ty = slice_ty.slicePtrFieldType(buf);
+ const mod = sema.mod;
+ const result_ty = slice_ty.slicePtrFieldType(mod);
if (try sema.resolveMaybeUndefVal(slice)) |val| {
- if (val.isUndef()) return sema.addConstUndef(result_ty);
- return sema.addConstant(result_ty, val.slicePtr());
+ if (val.isUndef(mod)) return sema.addConstUndef(result_ty);
+ return sema.addConstant(result_ty, val.slicePtr(mod));
}
try sema.requireRuntimeBlock(block, slice_src, null);
return block.addTyOp(.slice_ptr, result_ty, slice);
@@ -28830,8 +30432,9 @@ fn analyzeSliceLen(
src: LazySrcLoc,
slice_inst: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
if (try sema.resolveMaybeUndefVal(slice_inst)) |slice_val| {
- if (slice_val.isUndef()) {
+ if (slice_val.isUndef(mod)) {
return sema.addConstUndef(Type.usize);
}
return sema.addIntUnsigned(Type.usize, slice_val.sliceLen(sema.mod));
@@ -28847,12 +30450,13 @@ fn analyzeIsNull(
operand: Air.Inst.Ref,
invert_logic: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const result_ty = Type.bool;
if (try sema.resolveMaybeUndefVal(operand)) |opt_val| {
- if (opt_val.isUndef()) {
+ if (opt_val.isUndef(mod)) {
return sema.addConstUndef(result_ty);
}
- const is_null = opt_val.isNull();
+ const is_null = opt_val.isNull(mod);
const bool_value = if (invert_logic) !is_null else is_null;
if (bool_value) {
return Air.Inst.Ref.bool_true;
@@ -28863,11 +30467,10 @@ fn analyzeIsNull(
const inverted_non_null_res = if (invert_logic) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
const operand_ty = sema.typeOf(operand);
- var buf: Type.Payload.ElemType = undefined;
- if (operand_ty.zigTypeTag() == .Optional and operand_ty.optionalChild(&buf).zigTypeTag() == .NoReturn) {
+ if (operand_ty.zigTypeTag(mod) == .Optional and operand_ty.optionalChild(mod).zigTypeTag(mod) == .NoReturn) {
return inverted_non_null_res;
}
- if (operand_ty.zigTypeTag() != .Optional and !operand_ty.isPtrLikeOptional()) {
+ if (operand_ty.zigTypeTag(mod) != .Optional and !operand_ty.isPtrLikeOptional(mod)) {
return inverted_non_null_res;
}
try sema.requireRuntimeBlock(block, src, null);
@@ -28881,11 +30484,12 @@ fn analyzePtrIsNonErrComptimeOnly(
src: LazySrcLoc,
operand: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const ptr_ty = sema.typeOf(operand);
- assert(ptr_ty.zigTypeTag() == .Pointer);
- const child_ty = ptr_ty.childType();
+ assert(ptr_ty.zigTypeTag(mod) == .Pointer);
+ const child_ty = ptr_ty.childType(mod);
- const child_tag = child_ty.zigTypeTag();
+ const child_tag = child_ty.zigTypeTag(mod);
if (child_tag != .ErrorSet and child_tag != .ErrorUnion) return Air.Inst.Ref.bool_true;
if (child_tag == .ErrorSet) return Air.Inst.Ref.bool_false;
assert(child_tag == .ErrorUnion);
@@ -28902,14 +30506,15 @@ fn analyzeIsNonErrComptimeOnly(
src: LazySrcLoc,
operand: Air.Inst.Ref,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const operand_ty = sema.typeOf(operand);
- const ot = operand_ty.zigTypeTag();
+ const ot = operand_ty.zigTypeTag(mod);
if (ot != .ErrorSet and ot != .ErrorUnion) return Air.Inst.Ref.bool_true;
if (ot == .ErrorSet) return Air.Inst.Ref.bool_false;
assert(ot == .ErrorUnion);
- const payload_ty = operand_ty.errorUnionPayload();
- if (payload_ty.zigTypeTag() == .NoReturn) {
+ const payload_ty = operand_ty.errorUnionPayload(mod);
+ if (payload_ty.zigTypeTag(mod) == .NoReturn) {
return Air.Inst.Ref.bool_false;
}
@@ -28930,50 +30535,56 @@ fn analyzeIsNonErrComptimeOnly(
// exception if the error union error set is known to be empty,
// we allow the comparison but always make it comptime-known.
- const set_ty = operand_ty.errorUnionSet();
- switch (set_ty.tag()) {
- .anyerror => {},
- .error_set_inferred => blk: {
- // If the error set is empty, we must return a comptime true or false.
- // However we want to avoid unnecessarily resolving an inferred error set
- // in case it is already non-empty.
- const ies = set_ty.castTag(.error_set_inferred).?.data;
- if (ies.is_anyerror) break :blk;
- if (ies.errors.count() != 0) break :blk;
- if (maybe_operand_val == null) {
- // Try to avoid resolving inferred error set if possible.
- if (ies.errors.count() != 0) break :blk;
+ const set_ty = operand_ty.errorUnionSet(mod);
+ switch (set_ty.toIntern()) {
+ .anyerror_type => {},
+ else => switch (mod.intern_pool.indexToKey(set_ty.toIntern())) {
+ .error_set_type => |error_set_type| {
+ if (error_set_type.names.len == 0) return Air.Inst.Ref.bool_true;
+ },
+ .inferred_error_set_type => |ies_index| blk: {
+ // If the error set is empty, we must return a comptime true or false.
+ // However we want to avoid unnecessarily resolving an inferred error set
+ // in case it is already non-empty.
+ const ies = mod.inferredErrorSetPtr(ies_index);
if (ies.is_anyerror) break :blk;
- for (ies.inferred_error_sets.keys()) |other_ies| {
- if (ies == other_ies) continue;
- try sema.resolveInferredErrorSet(block, src, other_ies);
- if (other_ies.is_anyerror) {
- ies.is_anyerror = true;
- ies.is_resolved = true;
- break :blk;
- }
+ if (ies.errors.count() != 0) break :blk;
+ if (maybe_operand_val == null) {
+ // Try to avoid resolving inferred error set if possible.
+ if (ies.errors.count() != 0) break :blk;
+ if (ies.is_anyerror) break :blk;
+ for (ies.inferred_error_sets.keys()) |other_ies_index| {
+ if (ies_index == other_ies_index) continue;
+ try sema.resolveInferredErrorSet(block, src, other_ies_index);
+ const other_ies = mod.inferredErrorSetPtr(other_ies_index);
+ if (other_ies.is_anyerror) {
+ ies.is_anyerror = true;
+ ies.is_resolved = true;
+ break :blk;
+ }
- if (other_ies.errors.count() != 0) break :blk;
- }
- if (ies.func == sema.owner_func) {
- // We're checking the inferred errorset of the current function and none of
- // its child inferred error sets contained any errors meaning that any value
- // so far with this type can't contain errors either.
- return Air.Inst.Ref.bool_true;
+ if (other_ies.errors.count() != 0) break :blk;
+ }
+ if (ies.func == sema.owner_func_index.unwrap()) {
+ // We're checking the inferred errorset of the current function and none of
+ // its child inferred error sets contained any errors meaning that any value
+ // so far with this type can't contain errors either.
+ return Air.Inst.Ref.bool_true;
+ }
+ try sema.resolveInferredErrorSet(block, src, ies_index);
+ if (ies.is_anyerror) break :blk;
+ if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true;
}
- try sema.resolveInferredErrorSet(block, src, ies);
- if (ies.is_anyerror) break :blk;
- if (ies.errors.count() == 0) return Air.Inst.Ref.bool_true;
- }
+ },
+ else => unreachable,
},
- else => if (set_ty.errorSetNames().len == 0) return Air.Inst.Ref.bool_true,
}
if (maybe_operand_val) |err_union| {
- if (err_union.isUndef()) {
+ if (err_union.isUndef(mod)) {
return sema.addConstUndef(Type.bool);
}
- if (err_union.getError() == null) {
+ if (err_union.getErrorName(mod) == .none) {
return Air.Inst.Ref.bool_true;
} else {
return Air.Inst.Ref.bool_false;
@@ -29024,73 +30635,80 @@ fn analyzeSlice(
ptr_src: LazySrcLoc,
start_src: LazySrcLoc,
end_src: LazySrcLoc,
+ by_length: bool,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
// Slice expressions can operate on a variable whose type is an array. This requires
// the slice operand to be a pointer. In the case of a non-array, it will be a double pointer.
const ptr_ptr_ty = sema.typeOf(ptr_ptr);
- const target = sema.mod.getTarget();
- const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag()) {
- .Pointer => ptr_ptr_ty.elemType(),
- else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(sema.mod)}),
+ const ptr_ptr_child_ty = switch (ptr_ptr_ty.zigTypeTag(mod)) {
+ .Pointer => ptr_ptr_ty.childType(mod),
+ else => return sema.fail(block, ptr_src, "expected pointer, found '{}'", .{ptr_ptr_ty.fmt(mod)}),
};
- const mod = sema.mod;
var array_ty = ptr_ptr_child_ty;
var slice_ty = ptr_ptr_ty;
var ptr_or_slice = ptr_ptr;
var elem_ty: Type = undefined;
var ptr_sentinel: ?Value = null;
- switch (ptr_ptr_child_ty.zigTypeTag()) {
+ switch (ptr_ptr_child_ty.zigTypeTag(mod)) {
.Array => {
- ptr_sentinel = ptr_ptr_child_ty.sentinel();
- elem_ty = ptr_ptr_child_ty.childType();
+ ptr_sentinel = ptr_ptr_child_ty.sentinel(mod);
+ elem_ty = ptr_ptr_child_ty.childType(mod);
},
- .Pointer => switch (ptr_ptr_child_ty.ptrSize()) {
+ .Pointer => switch (ptr_ptr_child_ty.ptrSize(mod)) {
.One => {
- const double_child_ty = ptr_ptr_child_ty.childType();
- if (double_child_ty.zigTypeTag() == .Array) {
- ptr_sentinel = double_child_ty.sentinel();
+ const double_child_ty = ptr_ptr_child_ty.childType(mod);
+ if (double_child_ty.zigTypeTag(mod) == .Array) {
+ ptr_sentinel = double_child_ty.sentinel(mod);
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
slice_ty = ptr_ptr_child_ty;
array_ty = double_child_ty;
- elem_ty = double_child_ty.childType();
+ elem_ty = double_child_ty.childType(mod);
} else {
return sema.fail(block, src, "slice of single-item pointer", .{});
}
},
.Many, .C => {
- ptr_sentinel = ptr_ptr_child_ty.sentinel();
+ ptr_sentinel = ptr_ptr_child_ty.sentinel(mod);
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
slice_ty = ptr_ptr_child_ty;
array_ty = ptr_ptr_child_ty;
- elem_ty = ptr_ptr_child_ty.childType();
+ elem_ty = ptr_ptr_child_ty.childType(mod);
- if (ptr_ptr_child_ty.ptrSize() == .C) {
+ if (ptr_ptr_child_ty.ptrSize(mod) == .C) {
if (try sema.resolveDefinedValue(block, ptr_src, ptr_or_slice)) |ptr_val| {
- if (ptr_val.isNull()) {
+ if (ptr_val.isNull(mod)) {
return sema.fail(block, src, "slice of null pointer", .{});
}
}
}
},
.Slice => {
- ptr_sentinel = ptr_ptr_child_ty.sentinel();
+ ptr_sentinel = ptr_ptr_child_ty.sentinel(mod);
ptr_or_slice = try sema.analyzeLoad(block, src, ptr_ptr, ptr_src);
slice_ty = ptr_ptr_child_ty;
array_ty = ptr_ptr_child_ty;
- elem_ty = ptr_ptr_child_ty.childType();
+ elem_ty = ptr_ptr_child_ty.childType(mod);
},
},
else => return sema.fail(block, src, "slice of non-array type '{}'", .{ptr_ptr_child_ty.fmt(mod)}),
}
- const ptr = if (slice_ty.isSlice())
+ const ptr = if (slice_ty.isSlice(mod))
try sema.analyzeSlicePtr(block, ptr_src, ptr_or_slice, slice_ty)
- else
- ptr_or_slice;
+ else if (array_ty.zigTypeTag(mod) == .Array) ptr: {
+ var manyptr_ty_key = mod.intern_pool.indexToKey(slice_ty.toIntern()).ptr_type;
+ assert(manyptr_ty_key.child == array_ty.toIntern());
+ assert(manyptr_ty_key.flags.size == .One);
+ manyptr_ty_key.child = elem_ty.toIntern();
+ manyptr_ty_key.flags.size = .Many;
+ break :ptr try sema.coerceCompatiblePtrs(block, try mod.ptrType(manyptr_ty_key), ptr_or_slice, ptr_src);
+ } else ptr_or_slice;
const start = try sema.coerce(block, Type.usize, uncasted_start, start_src);
const new_ptr = try sema.analyzePtrArithmetic(block, src, ptr, start, .ptr_add, ptr_src, start_src);
+ const new_ptr_ty = sema.typeOf(new_ptr);
// true if and only if the end index of the slice, implicitly or explicitly, equals
// the length of the underlying object being sliced. we might learn the length of the
@@ -29098,18 +30716,22 @@ fn analyzeSlice(
// we might learn of the length because it is a comptime-known slice value.
var end_is_len = uncasted_end_opt == .none;
const end = e: {
- if (array_ty.zigTypeTag() == .Array) {
- const len_val = try Value.Tag.int_u64.create(sema.arena, array_ty.arrayLen());
+ if (array_ty.zigTypeTag(mod) == .Array) {
+ const len_val = try mod.intValue(Type.usize, array_ty.arrayLen(mod));
if (!end_is_len) {
- const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ const end = if (by_length) end: {
+ const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
+ break :end try sema.coerce(block, Type.usize, uncasted_end, end_src);
+ } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
if (try sema.resolveMaybeUndefVal(end)) |end_val| {
- const len_s_val = try Value.Tag.int_u64.create(
- sema.arena,
- array_ty.arrayLenIncludingSentinel(),
+ const len_s_val = try mod.intValue(
+ Type.usize,
+ array_ty.arrayLenIncludingSentinel(mod),
);
if (!(try sema.compareAll(end_val, .lte, len_s_val, Type.usize))) {
- const sentinel_label: []const u8 = if (array_ty.sentinel() != null)
+ const sentinel_label: []const u8 = if (array_ty.sentinel(mod) != null)
" +1 (sentinel)"
else
"";
@@ -29137,21 +30759,23 @@ fn analyzeSlice(
}
break :e try sema.addConstant(Type.usize, len_val);
- } else if (slice_ty.isSlice()) {
+ } else if (slice_ty.isSlice(mod)) {
if (!end_is_len) {
- const end = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ const end = if (by_length) end: {
+ const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
+ break :end try sema.coerce(block, Type.usize, uncasted_end, end_src);
+ } else try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
if (try sema.resolveMaybeUndefVal(ptr_or_slice)) |slice_val| {
- if (slice_val.isUndef()) {
+ if (slice_val.isUndef(mod)) {
return sema.fail(block, src, "slice of undefined", .{});
}
- const has_sentinel = slice_ty.sentinel() != null;
- var int_payload: Value.Payload.U64 = .{
- .base = .{ .tag = .int_u64 },
- .data = slice_val.sliceLen(mod) + @boolToInt(has_sentinel),
- };
- const slice_len_val = Value.initPayload(&int_payload.base);
- if (!(try sema.compareAll(end_val, .lte, slice_len_val, Type.usize))) {
+ const has_sentinel = slice_ty.sentinel(mod) != null;
+ const slice_len = slice_val.sliceLen(mod);
+ const len_plus_sent = slice_len + @boolToInt(has_sentinel);
+ const slice_len_val_with_sentinel = try mod.intValue(Type.usize, len_plus_sent);
+ if (!(try sema.compareAll(end_val, .lte, slice_len_val_with_sentinel, Type.usize))) {
const sentinel_label: []const u8 = if (has_sentinel)
" +1 (sentinel)"
else
@@ -29169,13 +30793,10 @@ fn analyzeSlice(
);
}
- // If the slice has a sentinel, we subtract one so that
- // end_is_len is only true if it equals the length WITHOUT
- // the sentinel, so we don't add a sentinel type.
- if (has_sentinel) {
- int_payload.data -= 1;
- }
-
+ // If the slice has a sentinel, we consider end_is_len
+ // is only true if it equals the length WITHOUT the
+ // sentinel, so we don't add a sentinel type.
+ const slice_len_val = try mod.intValue(Type.usize, slice_len);
if (end_val.eql(slice_len_val, Type.usize, mod)) {
end_is_len = true;
}
@@ -29186,7 +30807,11 @@ fn analyzeSlice(
break :e try sema.analyzeSliceLen(block, src, ptr_or_slice);
}
if (!end_is_len) {
- break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ if (by_length) {
+ const len = try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
+ const uncasted_end = try sema.analyzeArithmetic(block, .add, start, len, src, start_src, end_src, false);
+ break :e try sema.coerce(block, Type.usize, uncasted_end, end_src);
+ } else break :e try sema.coerce(block, Type.usize, uncasted_end_opt, end_src);
}
return sema.fail(block, src, "slice of pointer must include end value", .{});
};
@@ -29207,10 +30832,13 @@ fn analyzeSlice(
};
const slice_sentinel = if (sentinel_opt != .none) sentinel else null;
+ var checked_start_lte_end = by_length;
+ var runtime_src: ?LazySrcLoc = null;
+
// requirement: start <= end
if (try sema.resolveDefinedValue(block, end_src, end)) |end_val| {
if (try sema.resolveDefinedValue(block, start_src, start)) |start_val| {
- if (!(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
+ if (!by_length and !(try sema.compareAll(start_val, .lte, end_val, Type.usize))) {
return sema.fail(
block,
start_src,
@@ -29221,14 +30849,18 @@ fn analyzeSlice(
},
);
}
+ checked_start_lte_end = true;
if (try sema.resolveMaybeUndefVal(new_ptr)) |ptr_val| sentinel_check: {
const expected_sentinel = sentinel orelse break :sentinel_check;
- const start_int = start_val.getUnsignedInt(sema.mod.getTarget()).?;
- const end_int = end_val.getUnsignedInt(sema.mod.getTarget()).?;
+ const start_int = start_val.getUnsignedInt(mod).?;
+ const end_int = end_val.getUnsignedInt(mod).?;
const sentinel_index = try sema.usizeCast(block, end_src, end_int - start_int);
- const elem_ptr = try ptr_val.elemPtr(sema.typeOf(new_ptr), sema.arena, sentinel_index, sema.mod);
- const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty, false);
+ const many_ptr_ty = try mod.manyConstPtrType(elem_ty);
+ const many_ptr_val = try mod.getCoerced(ptr_val, many_ptr_ty);
+ const elem_ptr_ty = try mod.singleConstPtrType(elem_ty);
+ const elem_ptr = try many_ptr_val.elemPtr(elem_ptr_ty, sentinel_index, mod);
+ const res = try sema.pointerDerefExtra(block, src, elem_ptr, elem_ty);
const actual_sentinel = switch (res) {
.runtime_load => break :sentinel_check,
.val => |v| v,
@@ -29236,45 +30868,61 @@ fn analyzeSlice(
block,
src,
"comptime dereference requires '{}' to have a well-defined layout, but it does not.",
- .{ty.fmt(sema.mod)},
+ .{ty.fmt(mod)},
),
.out_of_bounds => |ty| return sema.fail(
block,
end_src,
"slice end index {d} exceeds bounds of containing decl of type '{}'",
- .{ end_int, ty.fmt(sema.mod) },
+ .{ end_int, ty.fmt(mod) },
),
};
- if (!actual_sentinel.eql(expected_sentinel, elem_ty, sema.mod)) {
+ if (!actual_sentinel.eql(expected_sentinel, elem_ty, mod)) {
const msg = msg: {
const msg = try sema.errMsg(block, src, "value in memory does not match slice sentinel", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(block, src, msg, "expected '{}', found '{}'", .{
- expected_sentinel.fmtValue(elem_ty, sema.mod),
- actual_sentinel.fmtValue(elem_ty, sema.mod),
+ expected_sentinel.fmtValue(elem_ty, mod),
+ actual_sentinel.fmtValue(elem_ty, mod),
});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
+ } else {
+ runtime_src = ptr_src;
}
+ } else {
+ runtime_src = start_src;
}
+ } else {
+ runtime_src = end_src;
}
- if (block.wantSafety() and !block.is_comptime) {
+ if (!checked_start_lte_end and block.wantSafety() and !block.is_comptime) {
// requirement: start <= end
- try sema.panicStartLargerThanEnd(block, start, end);
+ assert(!block.is_comptime);
+ try sema.requireRuntimeBlock(block, src, runtime_src.?);
+ const ok = try block.addBinOp(.cmp_lte, start, end);
+ if (!sema.mod.comp.formatted_panics) {
+ try sema.addSafetyCheck(block, ok, .start_index_greater_than_end);
+ } else {
+ try sema.safetyCheckFormatted(block, ok, "panicStartGreaterThanEnd", &.{ start, end });
+ }
}
- const new_len = try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
+ const new_len = if (by_length)
+ try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
+ else
+ try sema.analyzeArithmetic(block, .sub, end, start, src, end_src, start_src, false);
const opt_new_len_val = try sema.resolveDefinedValue(block, src, new_len);
- const new_ptr_ty_info = sema.typeOf(new_ptr).ptrInfo().data;
- const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize() != .C;
+ const new_ptr_ty_info = new_ptr_ty.ptrInfo(mod);
+ const new_allowzero = new_ptr_ty_info.@"allowzero" and sema.typeOf(ptr).ptrSize(mod) != .C;
if (opt_new_len_val) |new_len_val| {
- const new_len_int = new_len_val.toUnsignedInt(target);
+ const new_len_int = new_len_val.toUnsignedInt(mod);
const return_ty = try Type.ptr(sema.arena, mod, .{
.pointee_type = try Type.array(sema.arena, new_len_int, sentinel, elem_ty, mod),
@@ -29292,14 +30940,14 @@ fn analyzeSlice(
const result = try block.addBitCast(return_ty, new_ptr);
if (block.wantSafety()) {
// requirement: slicing C ptr is non-null
- if (ptr_ptr_child_ty.isCPtr()) {
+ if (ptr_ptr_child_ty.isCPtr(mod)) {
const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
}
- if (slice_ty.isSlice()) {
+ if (slice_ty.isSlice(mod)) {
const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
- const actual_len = if (slice_ty.sentinel() == null)
+ const actual_len = if (slice_ty.sentinel(mod) == null)
slice_len_inst
else
try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
@@ -29318,8 +30966,11 @@ fn analyzeSlice(
return result;
};
- if (!new_ptr_val.isUndef()) {
- return sema.addConstant(return_ty, new_ptr_val);
+ if (!new_ptr_val.isUndef(mod)) {
+ return sema.addConstant(return_ty, try mod.getCoerced(
+ (try new_ptr_val.intern(new_ptr_ty, mod)).toValue(),
+ return_ty,
+ ));
}
// Special case: @as([]i32, undefined)[x..x]
@@ -29341,25 +30992,18 @@ fn analyzeSlice(
.size = .Slice,
});
- const runtime_src = if ((try sema.resolveMaybeUndefVal(ptr_or_slice)) == null)
- ptr_src
- else if ((try sema.resolveMaybeUndefVal(start)) == null)
- start_src
- else
- end_src;
-
- try sema.requireRuntimeBlock(block, src, runtime_src);
+ try sema.requireRuntimeBlock(block, src, runtime_src.?);
if (block.wantSafety()) {
// requirement: slicing C ptr is non-null
- if (ptr_ptr_child_ty.isCPtr()) {
+ if (ptr_ptr_child_ty.isCPtr(mod)) {
const is_non_null = try sema.analyzeIsNull(block, ptr_src, ptr, true);
try sema.addSafetyCheck(block, is_non_null, .unwrap_null);
}
// requirement: end <= len
- const opt_len_inst = if (array_ty.zigTypeTag() == .Array)
- try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel())
- else if (slice_ty.isSlice()) blk: {
+ const opt_len_inst = if (array_ty.zigTypeTag(mod) == .Array)
+ try sema.addIntUnsigned(Type.usize, array_ty.arrayLenIncludingSentinel(mod))
+ else if (slice_ty.isSlice(mod)) blk: {
if (try sema.resolveDefinedValue(block, src, ptr_or_slice)) |slice_val| {
// we don't need to add one for sentinels because the
// underlying value data includes the sentinel
@@ -29367,7 +31011,7 @@ fn analyzeSlice(
}
const slice_len_inst = try block.addTyOp(.slice_len, Type.usize, ptr_or_slice);
- if (slice_ty.sentinel() == null) break :blk slice_len_inst;
+ if (slice_ty.sentinel(mod) == null) break :blk slice_len_inst;
// we have to add one because slice lengths don't include the sentinel
break :blk try sema.analyzeArithmetic(block, .add, slice_len_inst, .one, src, end_src, end_src, true);
@@ -29411,15 +31055,16 @@ fn cmpNumeric(
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const lhs_ty = sema.typeOf(uncasted_lhs);
const rhs_ty = sema.typeOf(uncasted_rhs);
- assert(lhs_ty.isNumeric());
- assert(rhs_ty.isNumeric());
+ assert(lhs_ty.isNumeric(mod));
+ assert(rhs_ty.isNumeric(mod));
- const lhs_ty_tag = lhs_ty.zigTypeTag();
- const rhs_ty_tag = rhs_ty.zigTypeTag();
- const target = sema.mod.getTarget();
+ const lhs_ty_tag = lhs_ty.zigTypeTag(mod);
+ const rhs_ty_tag = rhs_ty.zigTypeTag(mod);
+ const target = mod.getTarget();
// One exception to heterogeneous comparison: comptime_float needs to
// coerce to fixed-width float.
@@ -29438,49 +31083,45 @@ fn cmpNumeric(
if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
// Compare ints: const vs. undefined (or vice versa)
- if (!lhs_val.isUndef() and (lhs_ty.isInt() or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt() and rhs_val.isUndef()) {
- try sema.resolveLazyValue(lhs_val);
- if (sema.compareIntsOnlyPossibleResult(target, lhs_val, op, rhs_ty)) |res| {
+ if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod) and rhs_val.isUndef(mod)) {
+ if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| {
return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
}
- } else if (!rhs_val.isUndef() and (rhs_ty.isInt() or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt() and lhs_val.isUndef()) {
- try sema.resolveLazyValue(rhs_val);
- if (sema.compareIntsOnlyPossibleResult(target, rhs_val, op.reverse(), lhs_ty)) |res| {
+ } else if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod) and lhs_val.isUndef(mod)) {
+ if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| {
return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
}
}
- if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
return sema.addConstUndef(Type.bool);
}
- if (lhs_val.isNan() or rhs_val.isNan()) {
+ if (lhs_val.isNan(mod) or rhs_val.isNan(mod)) {
if (op == std.math.CompareOperator.neq) {
return Air.Inst.Ref.bool_true;
} else {
return Air.Inst.Ref.bool_false;
}
}
- if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, target, sema)) {
+ if (try Value.compareHeteroAdvanced(lhs_val, op, rhs_val, mod, sema)) {
return Air.Inst.Ref.bool_true;
} else {
return Air.Inst.Ref.bool_false;
}
} else {
- if (!lhs_val.isUndef() and (lhs_ty.isInt() or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt()) {
+ if (!lhs_val.isUndef(mod) and (lhs_ty.isInt(mod) or lhs_ty_tag == .ComptimeInt) and rhs_ty.isInt(mod)) {
// Compare ints: const vs. var
- try sema.resolveLazyValue(lhs_val);
- if (sema.compareIntsOnlyPossibleResult(target, lhs_val, op, rhs_ty)) |res| {
+ if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(lhs_val), op, rhs_ty)) |res| {
return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
}
}
break :src rhs_src;
}
} else {
- if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
- if (!rhs_val.isUndef() and (rhs_ty.isInt() or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt()) {
+ if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| {
+ if (!rhs_val.isUndef(mod) and (rhs_ty.isInt(mod) or rhs_ty_tag == .ComptimeInt) and lhs_ty.isInt(mod)) {
// Compare ints: var vs. const
- try sema.resolveLazyValue(rhs_val);
- if (sema.compareIntsOnlyPossibleResult(target, rhs_val, op.reverse(), lhs_ty)) |res| {
+ if (try sema.compareIntsOnlyPossibleResult(try sema.resolveLazyValue(rhs_val), op.reverse(), lhs_ty)) |res| {
return if (res) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false;
}
}
@@ -29534,32 +31175,31 @@ fn cmpNumeric(
const lhs_is_signed = if (try sema.resolveDefinedValue(block, lhs_src, lhs)) |lhs_val|
!(try lhs_val.compareAllWithZeroAdvanced(.gte, sema))
else
- (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt());
+ (lhs_ty.isRuntimeFloat() or lhs_ty.isSignedInt(mod));
const rhs_is_signed = if (try sema.resolveDefinedValue(block, rhs_src, rhs)) |rhs_val|
!(try rhs_val.compareAllWithZeroAdvanced(.gte, sema))
else
- (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt());
+ (rhs_ty.isRuntimeFloat() or rhs_ty.isSignedInt(mod));
const dest_int_is_signed = lhs_is_signed or rhs_is_signed;
var dest_float_type: ?Type = null;
var lhs_bits: usize = undefined;
- if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
- try sema.resolveLazyValue(lhs_val);
- if (lhs_val.isUndef())
+ if (try sema.resolveMaybeUndefLazyVal(lhs)) |lhs_val| {
+ if (lhs_val.isUndef(mod))
return sema.addConstUndef(Type.bool);
- if (lhs_val.isNan()) switch (op) {
+ if (lhs_val.isNan(mod)) switch (op) {
.neq => return Air.Inst.Ref.bool_true,
else => return Air.Inst.Ref.bool_false,
};
- if (lhs_val.isInf()) switch (op) {
+ if (lhs_val.isInf(mod)) switch (op) {
.neq => return Air.Inst.Ref.bool_true,
.eq => return Air.Inst.Ref.bool_false,
- .gt, .gte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true,
- .lt, .lte => return if (lhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false,
+ .gt, .gte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true,
+ .lt, .lte => return if (lhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false,
};
if (!rhs_is_signed) {
- switch (lhs_val.orderAgainstZero()) {
+ switch (lhs_val.orderAgainstZero(mod)) {
.gt => {},
.eq => switch (op) { // LHS = 0, RHS is unsigned
.lte => return Air.Inst.Ref.bool_true,
@@ -29573,7 +31213,7 @@ fn cmpNumeric(
}
}
if (lhs_is_float) {
- if (lhs_val.floatHasFraction()) {
+ if (lhs_val.floatHasFraction(mod)) {
switch (op) {
.eq => return Air.Inst.Ref.bool_false,
.neq => return Air.Inst.Ref.bool_true,
@@ -29581,9 +31221,9 @@ fn cmpNumeric(
}
}
- var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128));
+ var bigint = try float128IntPartToBigInt(sema.gpa, lhs_val.toFloat(f128, mod));
defer bigint.deinit();
- if (lhs_val.floatHasFraction()) {
+ if (lhs_val.floatHasFraction(mod)) {
if (lhs_is_signed) {
try bigint.addScalar(&bigint, -1);
} else {
@@ -29592,33 +31232,32 @@ fn cmpNumeric(
}
lhs_bits = bigint.toConst().bitCountTwosComp();
} else {
- lhs_bits = lhs_val.intBitCountTwosComp(target);
+ lhs_bits = lhs_val.intBitCountTwosComp(mod);
}
lhs_bits += @boolToInt(!lhs_is_signed and dest_int_is_signed);
} else if (lhs_is_float) {
dest_float_type = lhs_ty;
} else {
- const int_info = lhs_ty.intInfo(target);
+ const int_info = lhs_ty.intInfo(mod);
lhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
}
var rhs_bits: usize = undefined;
- if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
- try sema.resolveLazyValue(rhs_val);
- if (rhs_val.isUndef())
+ if (try sema.resolveMaybeUndefLazyVal(rhs)) |rhs_val| {
+ if (rhs_val.isUndef(mod))
return sema.addConstUndef(Type.bool);
- if (rhs_val.isNan()) switch (op) {
+ if (rhs_val.isNan(mod)) switch (op) {
.neq => return Air.Inst.Ref.bool_true,
else => return Air.Inst.Ref.bool_false,
};
- if (rhs_val.isInf()) switch (op) {
+ if (rhs_val.isInf(mod)) switch (op) {
.neq => return Air.Inst.Ref.bool_true,
.eq => return Air.Inst.Ref.bool_false,
- .gt, .gte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false,
- .lt, .lte => return if (rhs_val.isNegativeInf()) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true,
+ .gt, .gte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_true else Air.Inst.Ref.bool_false,
+ .lt, .lte => return if (rhs_val.isNegativeInf(mod)) Air.Inst.Ref.bool_false else Air.Inst.Ref.bool_true,
};
if (!lhs_is_signed) {
- switch (rhs_val.orderAgainstZero()) {
+ switch (rhs_val.orderAgainstZero(mod)) {
.gt => {},
.eq => switch (op) { // RHS = 0, LHS is unsigned
.gte => return Air.Inst.Ref.bool_true,
@@ -29632,7 +31271,7 @@ fn cmpNumeric(
}
}
if (rhs_is_float) {
- if (rhs_val.floatHasFraction()) {
+ if (rhs_val.floatHasFraction(mod)) {
switch (op) {
.eq => return Air.Inst.Ref.bool_false,
.neq => return Air.Inst.Ref.bool_true,
@@ -29640,9 +31279,9 @@ fn cmpNumeric(
}
}
- var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128));
+ var bigint = try float128IntPartToBigInt(sema.gpa, rhs_val.toFloat(f128, mod));
defer bigint.deinit();
- if (rhs_val.floatHasFraction()) {
+ if (rhs_val.floatHasFraction(mod)) {
if (rhs_is_signed) {
try bigint.addScalar(&bigint, -1);
} else {
@@ -29651,21 +31290,21 @@ fn cmpNumeric(
}
rhs_bits = bigint.toConst().bitCountTwosComp();
} else {
- rhs_bits = rhs_val.intBitCountTwosComp(target);
+ rhs_bits = rhs_val.intBitCountTwosComp(mod);
}
rhs_bits += @boolToInt(!rhs_is_signed and dest_int_is_signed);
} else if (rhs_is_float) {
dest_float_type = rhs_ty;
} else {
- const int_info = rhs_ty.intInfo(target);
+ const int_info = rhs_ty.intInfo(mod);
rhs_bits = int_info.bits + @boolToInt(int_info.signedness == .unsigned and dest_int_is_signed);
}
const dest_ty = if (dest_float_type) |ft| ft else blk: {
- const max_bits = std.math.max(lhs_bits, rhs_bits);
+ const max_bits = @max(lhs_bits, rhs_bits);
const casted_bits = std.math.cast(u16, max_bits) orelse return sema.fail(block, src, "{d} exceeds maximum integer bit count", .{max_bits});
const signedness: std.builtin.Signedness = if (dest_int_is_signed) .signed else .unsigned;
- break :blk try Module.makeIntType(sema.arena, signedness, casted_bits);
+ break :blk try mod.intType(signedness, casted_bits);
};
const casted_lhs = try sema.coerce(block, dest_ty, lhs, lhs_src);
const casted_rhs = try sema.coerce(block, dest_ty, rhs, rhs_src);
@@ -29673,13 +31312,20 @@ fn cmpNumeric(
return block.addBinOp(Air.Inst.Tag.fromCmpOp(op, block.float_mode == .Optimized), casted_lhs, casted_rhs);
}
-/// Asserts that LHS value is an int or comptime int and not undefined, and that RHS type is an int.
-/// Given a const LHS and an unknown RHS, attempt to determine whether `op` has a guaranteed result.
+/// Asserts that LHS value is an int or comptime int and not undefined, and
+/// that RHS type is an int. Given a const LHS and an unknown RHS, attempt to
+/// determine whether `op` has a guaranteed result.
/// If it cannot be determined, returns null.
/// Otherwise returns a bool for the guaranteed comparison operation.
-fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value, op: std.math.CompareOperator, rhs_ty: Type) ?bool {
- const rhs_info = rhs_ty.intInfo(target);
- const vs_zero = lhs_val.orderAgainstZeroAdvanced(sema) catch unreachable;
+fn compareIntsOnlyPossibleResult(
+ sema: *Sema,
+ lhs_val: Value,
+ op: std.math.CompareOperator,
+ rhs_ty: Type,
+) Allocator.Error!?bool {
+ const mod = sema.mod;
+ const rhs_info = rhs_ty.intInfo(mod);
+ const vs_zero = lhs_val.orderAgainstZeroAdvanced(mod, sema) catch unreachable;
const is_zero = vs_zero == .eq;
const is_negative = vs_zero == .lt;
const is_positive = vs_zero == .gt;
@@ -29711,7 +31357,7 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value
};
const sign_adj = @boolToInt(!is_negative and rhs_info.signedness == .signed);
- const req_bits = lhs_val.intBitCountTwosComp(target) + sign_adj;
+ const req_bits = lhs_val.intBitCountTwosComp(mod) + sign_adj;
// No sized type can have more than 65535 bits.
// The RHS type operand is either a runtime value or sized (but undefined) constant.
@@ -29744,12 +31390,11 @@ fn compareIntsOnlyPossibleResult(sema: *Sema, target: std.Target, lhs_val: Value
.max = false,
};
- var ty_buffer: Type.Payload.Bits = .{
- .base = .{ .tag = if (is_negative) .int_signed else .int_unsigned },
- .data = @intCast(u16, req_bits),
- };
- const ty = Type.initPayload(&ty_buffer.base);
- const pop_count = lhs_val.popCount(ty, target);
+ const ty = try mod.intType(
+ if (is_negative) .signed else .unsigned,
+ @intCast(u16, req_bits),
+ );
+ const pop_count = lhs_val.popCount(ty, mod);
if (is_negative) {
break :edge .{
@@ -29785,21 +31430,29 @@ fn cmpVector(
lhs_src: LazySrcLoc,
rhs_src: LazySrcLoc,
) CompileError!Air.Inst.Ref {
+ const mod = sema.mod;
const lhs_ty = sema.typeOf(lhs);
const rhs_ty = sema.typeOf(rhs);
- assert(lhs_ty.zigTypeTag() == .Vector);
- assert(rhs_ty.zigTypeTag() == .Vector);
+ assert(lhs_ty.zigTypeTag(mod) == .Vector);
+ assert(rhs_ty.zigTypeTag(mod) == .Vector);
try sema.checkVectorizableBinaryOperands(block, src, lhs_ty, rhs_ty, lhs_src, rhs_src);
- const result_ty = try Type.vector(sema.arena, lhs_ty.vectorLen(), Type.bool);
+ const resolved_ty = try sema.resolvePeerTypes(block, src, &.{ lhs, rhs }, .{ .override = &.{ lhs_src, rhs_src } });
+ const casted_lhs = try sema.coerce(block, resolved_ty, lhs, lhs_src);
+ const casted_rhs = try sema.coerce(block, resolved_ty, rhs, rhs_src);
+
+ const result_ty = try mod.vectorType(.{
+ .len = lhs_ty.vectorLen(mod),
+ .child = .bool_type,
+ });
const runtime_src: LazySrcLoc = src: {
- if (try sema.resolveMaybeUndefVal(lhs)) |lhs_val| {
- if (try sema.resolveMaybeUndefVal(rhs)) |rhs_val| {
- if (lhs_val.isUndef() or rhs_val.isUndef()) {
+ if (try sema.resolveMaybeUndefVal(casted_lhs)) |lhs_val| {
+ if (try sema.resolveMaybeUndefVal(casted_rhs)) |rhs_val| {
+ if (lhs_val.isUndef(mod) or rhs_val.isUndef(mod)) {
return sema.addConstUndef(result_ty);
}
- const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, lhs_ty);
+ const cmp_val = try sema.compareVector(lhs_val, op, rhs_val, resolved_ty);
return sema.addConstant(result_ty, cmp_val);
} else {
break :src rhs_src;
@@ -29810,7 +31463,7 @@ fn cmpVector(
};
try sema.requireRuntimeBlock(block, src, runtime_src);
- return block.addCmpVector(lhs, rhs, op);
+ return block.addCmpVector(casted_lhs, casted_rhs, op);
}
fn wrapOptional(
@@ -29821,7 +31474,10 @@ fn wrapOptional(
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
if (try sema.resolveMaybeUndefVal(inst)) |val| {
- return sema.addConstant(dest_ty, try Value.Tag.opt_payload.create(sema.arena, val));
+ return sema.addConstant(dest_ty, (try sema.mod.intern(.{ .opt = .{
+ .ty = dest_ty.toIntern(),
+ .val = val.toIntern(),
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, inst_src, null);
@@ -29835,10 +31491,14 @@ fn wrapErrorUnionPayload(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
- const dest_payload_ty = dest_ty.errorUnionPayload();
+ const mod = sema.mod;
+ const dest_payload_ty = dest_ty.errorUnionPayload(mod);
const coerced = try sema.coerceExtra(block, dest_payload_ty, inst, inst_src, .{ .report_err = false });
if (try sema.resolveMaybeUndefVal(coerced)) |val| {
- return sema.addConstant(dest_ty, try Value.Tag.eu_payload.create(sema.arena, val));
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
+ .ty = dest_ty.toIntern(),
+ .val = .{ .payload = try val.intern(dest_payload_ty, mod) },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, inst_src, null);
try sema.queueFullTypeResolution(dest_payload_ty);
@@ -29852,48 +31512,41 @@ fn wrapErrorUnionSet(
inst: Air.Inst.Ref,
inst_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
+ const ip = &mod.intern_pool;
const inst_ty = sema.typeOf(inst);
- const dest_err_set_ty = dest_ty.errorUnionSet();
+ const dest_err_set_ty = dest_ty.errorUnionSet(mod);
if (try sema.resolveMaybeUndefVal(inst)) |val| {
- switch (dest_err_set_ty.tag()) {
- .anyerror => {},
- .error_set_single => ok: {
- const expected_name = val.castTag(.@"error").?.data.name;
- const n = dest_err_set_ty.castTag(.error_set_single).?.data;
- if (mem.eql(u8, expected_name, n)) break :ok;
- return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
- },
- .error_set => {
- const expected_name = val.castTag(.@"error").?.data.name;
- const error_set = dest_err_set_ty.castTag(.error_set).?.data;
- if (!error_set.names.contains(expected_name)) {
+ switch (dest_err_set_ty.toIntern()) {
+ .anyerror_type => {},
+ else => switch (ip.indexToKey(dest_err_set_ty.toIntern())) {
+ .error_set_type => |error_set_type| ok: {
+ const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
+ if (error_set_type.nameIndex(ip, expected_name) != null) break :ok;
return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
- }
- },
- .error_set_inferred => ok: {
- const expected_name = val.castTag(.@"error").?.data.name;
- const ies = dest_err_set_ty.castTag(.error_set_inferred).?.data;
+ },
+ .inferred_error_set_type => |ies_index| ok: {
+ const ies = mod.inferredErrorSetPtr(ies_index);
+ const expected_name = mod.intern_pool.indexToKey(val.toIntern()).err.name;
- // We carefully do this in an order that avoids unnecessarily
- // resolving the destination error set type.
- if (ies.is_anyerror) break :ok;
- if (ies.errors.contains(expected_name)) break :ok;
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) {
- break :ok;
- }
+ // We carefully do this in an order that avoids unnecessarily
+ // resolving the destination error set type.
+ if (ies.is_anyerror) break :ok;
+
+ if (ies.errors.contains(expected_name)) break :ok;
+ if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, dest_err_set_ty, inst_ty, inst_src, inst_src)) break :ok;
- return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
- },
- .error_set_merged => {
- const expected_name = val.castTag(.@"error").?.data.name;
- const error_set = dest_err_set_ty.castTag(.error_set_merged).?.data;
- if (!error_set.contains(expected_name)) {
return sema.failWithErrorSetCodeMissing(block, inst_src, dest_err_set_ty, inst_ty);
- }
+ },
+ else => unreachable,
},
- else => unreachable,
}
- return sema.addConstant(dest_ty, val);
+ return sema.addConstant(dest_ty, (try mod.intern(.{ .error_union = .{
+ .ty = dest_ty.toIntern(),
+ .val = .{
+ .err_name = mod.intern_pool.indexToKey(try val.intern(dest_err_set_ty, mod)).err.name,
+ },
+ } })).toValue());
}
try sema.requireRuntimeBlock(block, inst_src, null);
@@ -29908,16 +31561,301 @@ fn unionToTag(
un: Air.Inst.Ref,
un_src: LazySrcLoc,
) !Air.Inst.Ref {
+ const mod = sema.mod;
if ((try sema.typeHasOnePossibleValue(enum_ty))) |opv| {
return sema.addConstant(enum_ty, opv);
}
if (try sema.resolveMaybeUndefVal(un)) |un_val| {
- return sema.addConstant(enum_ty, un_val.unionTag());
+ return sema.addConstant(enum_ty, un_val.unionTag(mod));
}
try sema.requireRuntimeBlock(block, un_src, null);
return block.addTyOp(.get_union_tag, enum_ty, un);
}
+const PeerResolveStrategy = enum {
+ /// The type is not known.
+ /// If refined no further, this is equivalent to `exact`.
+ unknown,
+ /// The type may be an error set or error union.
+ /// If refined no further, it is an error set.
+ error_set,
+ /// The type must be some error union.
+ error_union,
+ /// The type may be @TypeOf(null), an optional or a C pointer.
+ /// If refined no further, it is @TypeOf(null).
+ nullable,
+ /// The type must be some optional or a C pointer.
+ /// If refined no further, it is an optional.
+ optional,
+ /// The type must be either an array or a vector.
+ /// If refined no further, it is an array.
+ array,
+ /// The type must be a vector.
+ vector,
+ /// The type must be a C pointer.
+ c_ptr,
+ /// The type must be a pointer (C or not).
+ /// If refined no further, it is a non-C pointer.
+ ptr,
+ /// The type must be a function or a pointer to a function.
+ /// If refined no further, it is a function.
+ func,
+ /// The type must be an enum literal, or some specific enum or union. Which one is decided
+ /// afterwards based on the types in question.
+ enum_or_union,
+ /// The type must be some integer or float type.
+ /// If refined no further, it is `comptime_int`.
+ comptime_int,
+ /// The type must be some float type.
+ /// If refined no further, it is `comptime_float`.
+ comptime_float,
+ /// The type must be some float or fixed-width integer type.
+ /// If refined no further, it is some fixed-width integer type.
+ fixed_int,
+ /// The type must be some fixed-width float type.
+ fixed_float,
+ /// The type must be a struct literal or tuple type.
+ coercible_struct,
+ /// The peers must all be of the same type.
+ exact,
+
+ /// Given two strategies, find a strategy that satisfies both, if one exists. If no such
+ /// strategy exists, any strategy may be returned; an error will be emitted when the caller
+ /// attempts to use the strategy to resolve the type.
+ /// Strategy `a` comes from the peer in `reason_peer`, while strategy `b` comes from the peer at
+ /// index `b_peer_idx`. `reason_peer` is updated to reflect the reason for the new strategy.
+ fn merge(a: PeerResolveStrategy, b: PeerResolveStrategy, reason_peer: *usize, b_peer_idx: usize) PeerResolveStrategy {
+ // Our merging should be order-independent. Thus, even though the union order is arbitrary,
+ // by sorting the tags and switching first on the smaller, we have half as many cases to
+ // worry about (since we avoid the duplicates).
+ const s0_is_a = @enumToInt(a) <= @enumToInt(b);
+ const s0 = if (s0_is_a) a else b;
+ const s1 = if (s0_is_a) b else a;
+
+ const ReasonMethod = enum {
+ all_s0,
+ all_s1,
+ either,
+ };
+
+ const res: struct { ReasonMethod, PeerResolveStrategy } = switch (s0) {
+ .unknown => .{ .all_s1, s1 },
+ .error_set => switch (s1) {
+ .error_set => .{ .either, .error_set },
+ else => .{ .all_s0, .error_union },
+ },
+ .error_union => switch (s1) {
+ .error_union => .{ .either, .error_union },
+ else => .{ .all_s0, .error_union },
+ },
+ .nullable => switch (s1) {
+ .nullable => .{ .either, .nullable },
+ .c_ptr => .{ .all_s1, .c_ptr },
+ else => .{ .all_s0, .optional },
+ },
+ .optional => switch (s1) {
+ .optional => .{ .either, .optional },
+ .c_ptr => .{ .all_s1, .c_ptr },
+ else => .{ .all_s0, .optional },
+ },
+ .array => switch (s1) {
+ .array => .{ .either, .array },
+ .vector => .{ .all_s1, .vector },
+ else => .{ .all_s0, .array },
+ },
+ .vector => switch (s1) {
+ .vector => .{ .either, .vector },
+ else => .{ .all_s0, .vector },
+ },
+ .c_ptr => switch (s1) {
+ .c_ptr => .{ .either, .c_ptr },
+ else => .{ .all_s0, .c_ptr },
+ },
+ .ptr => switch (s1) {
+ .ptr => .{ .either, .ptr },
+ else => .{ .all_s0, .ptr },
+ },
+ .func => switch (s1) {
+ .func => .{ .either, .func },
+ else => .{ .all_s1, s1 }, // doesn't override anything later
+ },
+ .enum_or_union => switch (s1) {
+ .enum_or_union => .{ .either, .enum_or_union },
+ else => .{ .all_s0, .enum_or_union },
+ },
+ .comptime_int => switch (s1) {
+ .comptime_int => .{ .either, .comptime_int },
+ else => .{ .all_s1, s1 }, // doesn't override anything later
+ },
+ .comptime_float => switch (s1) {
+ .comptime_float => .{ .either, .comptime_float },
+ else => .{ .all_s1, s1 }, // doesn't override anything later
+ },
+ .fixed_int => switch (s1) {
+ .fixed_int => .{ .either, .fixed_int },
+ else => .{ .all_s1, s1 }, // doesn't override anything later
+ },
+ .fixed_float => switch (s1) {
+ .fixed_float => .{ .either, .fixed_float },
+ else => .{ .all_s1, s1 }, // doesn't override anything later
+ },
+ .coercible_struct => switch (s1) {
+ .exact => .{ .all_s1, .exact },
+ else => .{ .all_s0, .coercible_struct },
+ },
+ .exact => .{ .all_s0, .exact },
+ };
+
+ switch (res[0]) {
+ .all_s0 => {
+ if (!s0_is_a) {
+ reason_peer.* = b_peer_idx;
+ }
+ },
+ .all_s1 => {
+ if (s0_is_a) {
+ reason_peer.* = b_peer_idx;
+ }
+ },
+ .either => {
+ // Prefer the earliest peer
+ reason_peer.* = @min(reason_peer.*, b_peer_idx);
+ },
+ }
+
+ return res[1];
+ }
+
+ fn select(ty: Type, mod: *Module) PeerResolveStrategy {
+ return switch (ty.zigTypeTag(mod)) {
+ .Type, .Void, .Bool, .Opaque, .Frame, .AnyFrame => .exact,
+ .NoReturn, .Undefined => .unknown,
+ .Null => .nullable,
+ .ComptimeInt => .comptime_int,
+ .Int => .fixed_int,
+ .ComptimeFloat => .comptime_float,
+ .Float => .fixed_float,
+ .Pointer => if (ty.ptrInfo(mod).size == .C) .c_ptr else .ptr,
+ .Array => .array,
+ .Vector => .vector,
+ .Optional => .optional,
+ .ErrorSet => .error_set,
+ .ErrorUnion => .error_union,
+ .EnumLiteral, .Enum, .Union => .enum_or_union,
+ .Struct => if (ty.isTupleOrAnonStruct(mod)) .coercible_struct else .exact,
+ .Fn => .func,
+ };
+ }
+};
+
+const PeerResolveResult = union(enum) {
+ /// The peer type resolution was successful, and resulted in the given type.
+ success: Type,
+ /// There was some generic conflict between two peers.
+ conflict: struct {
+ peer_idx_a: usize,
+ peer_idx_b: usize,
+ },
+ /// There was an error when resolving the type of a struct or tuple field.
+ field_error: struct {
+ /// The name of the field which caused the failure.
+ field_name: []const u8,
+ /// The type of this field in each peer.
+ field_types: []Type,
+ /// The error from resolving the field type. Guaranteed not to be `success`.
+ sub_result: *PeerResolveResult,
+ },
+
+ fn report(
+ result: PeerResolveResult,
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ instructions: []const Air.Inst.Ref,
+ candidate_srcs: Module.PeerTypeCandidateSrc,
+ ) !*Module.ErrorMsg {
+ const mod = sema.mod;
+ const decl_ptr = mod.declPtr(block.src_decl);
+
+ var opt_msg: ?*Module.ErrorMsg = null;
+ errdefer if (opt_msg) |msg| msg.destroy(sema.gpa);
+
+ // If we mention fields we'll want to include field types, so put peer types in a buffer
+ var peer_tys = try sema.arena.alloc(Type, instructions.len);
+ for (peer_tys, instructions) |*ty, inst| {
+ ty.* = sema.typeOf(inst);
+ }
+
+ var cur = result;
+ while (true) {
+ var conflict_idx: [2]usize = undefined;
+
+ switch (cur) {
+ .success => unreachable,
+ .conflict => |conflict| {
+ // Fall through to two-peer conflict handling below
+ conflict_idx = .{
+ conflict.peer_idx_a,
+ conflict.peer_idx_b,
+ };
+ },
+ .field_error => |field_error| {
+ const fmt = "struct field '{s}' has conflicting types";
+ const args = .{field_error.field_name};
+ if (opt_msg) |msg| {
+ try sema.errNote(block, src, msg, fmt, args);
+ } else {
+ opt_msg = try sema.errMsg(block, src, fmt, args);
+ }
+
+ // Continue on to child error
+ cur = field_error.sub_result.*;
+ peer_tys = field_error.field_types;
+ continue;
+ },
+ }
+
+ // This is the path for reporting a generic conflict between two peers.
+
+ if (conflict_idx[1] < conflict_idx[0]) {
+ // b comes first in source, so it's better if it comes first in the error
+ std.mem.swap(usize, &conflict_idx[0], &conflict_idx[1]);
+ }
+
+ const conflict_tys: [2]Type = .{
+ peer_tys[conflict_idx[0]],
+ peer_tys[conflict_idx[1]],
+ };
+ const conflict_srcs: [2]?LazySrcLoc = .{
+ candidate_srcs.resolve(mod, decl_ptr, conflict_idx[0]),
+ candidate_srcs.resolve(mod, decl_ptr, conflict_idx[1]),
+ };
+
+ const fmt = "incompatible types: '{}' and '{}'";
+ const args = .{
+ conflict_tys[0].fmt(mod),
+ conflict_tys[1].fmt(mod),
+ };
+ const msg = if (opt_msg) |msg| msg: {
+ try sema.errNote(block, src, msg, fmt, args);
+ break :msg msg;
+ } else msg: {
+ const msg = try sema.errMsg(block, src, fmt, args);
+ opt_msg = msg;
+ break :msg msg;
+ };
+
+ if (conflict_srcs[0]) |src_loc| try sema.errNote(block, src_loc, msg, "type '{}' here", .{conflict_tys[0].fmt(mod)});
+ if (conflict_srcs[1]) |src_loc| try sema.errNote(block, src_loc, msg, "type '{}' here", .{conflict_tys[1].fmt(mod)});
+
+ // No child error
+ break;
+ }
+
+ return opt_msg.?;
+ }
+};
+
fn resolvePeerTypes(
sema: *Sema,
block: *Block,
@@ -29926,663 +31864,1303 @@ fn resolvePeerTypes(
candidate_srcs: Module.PeerTypeCandidateSrc,
) !Type {
switch (instructions.len) {
- 0 => return Type.initTag(.noreturn),
+ 0 => return Type.noreturn,
1 => return sema.typeOf(instructions[0]),
else => {},
}
- const target = sema.mod.getTarget();
+ var peer_tys = try sema.arena.alloc(?Type, instructions.len);
+ var peer_vals = try sema.arena.alloc(?Value, instructions.len);
- var chosen = instructions[0];
- // If this is non-null then it does the following thing, depending on the chosen zigTypeTag().
- // * ErrorSet: this is an override
- // * ErrorUnion: this is an override of the error set only
- // * other: at the end we make an ErrorUnion with the other thing and this
- var err_set_ty: ?Type = null;
- var any_are_null = false;
- var seen_const = false;
- var convert_to_slice = false;
- var chosen_i: usize = 0;
- for (instructions[1..], 0..) |candidate, candidate_i| {
- const candidate_ty = sema.typeOf(candidate);
- const chosen_ty = sema.typeOf(chosen);
-
- const candidate_ty_tag = try candidate_ty.zigTypeTagOrPoison();
- const chosen_ty_tag = try chosen_ty.zigTypeTagOrPoison();
-
- // If the candidate can coerce into our chosen type, we're done.
- // If the chosen type can coerce into the candidate, use that.
- if ((try sema.coerceInMemoryAllowed(block, chosen_ty, candidate_ty, false, target, src, src)) == .ok) {
- continue;
- }
- if ((try sema.coerceInMemoryAllowed(block, candidate_ty, chosen_ty, false, target, src, src)) == .ok) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- }
+ for (instructions, peer_tys, peer_vals) |inst, *ty, *val| {
+ ty.* = sema.typeOf(inst);
+ val.* = try sema.resolveMaybeUndefVal(inst);
+ }
- switch (candidate_ty_tag) {
- .NoReturn, .Undefined => continue,
+ switch (try sema.resolvePeerTypesInner(block, src, peer_tys, peer_vals)) {
+ .success => |ty| return ty,
+ else => |result| {
+ const msg = try result.report(sema, block, src, instructions, candidate_srcs);
+ return sema.failWithOwnedErrorMsg(msg);
+ },
+ }
+}
- .Null => {
- any_are_null = true;
- continue;
- },
+fn resolvePeerTypesInner(
+ sema: *Sema,
+ block: *Block,
+ src: LazySrcLoc,
+ peer_tys: []?Type,
+ peer_vals: []?Value,
+) !PeerResolveResult {
+ const mod = sema.mod;
- .Int => switch (chosen_ty_tag) {
- .ComptimeInt => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- .Int => {
- const chosen_info = chosen_ty.intInfo(target);
- const candidate_info = candidate_ty.intInfo(target);
+ var strat_reason: usize = 0;
+ var s: PeerResolveStrategy = .unknown;
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ s = s.merge(PeerResolveStrategy.select(ty, mod), &strat_reason, i);
+ }
- if (chosen_info.bits < candidate_info.bits) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- }
- continue;
- },
- .Pointer => if (chosen_ty.ptrSize() == .C) continue,
- else => {},
- },
- .ComptimeInt => switch (chosen_ty_tag) {
- .Int, .Float, .ComptimeFloat => continue,
- .Pointer => if (chosen_ty.ptrSize() == .C) continue,
- else => {},
- },
- .Float => switch (chosen_ty_tag) {
- .Float => {
- if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- }
- continue;
- },
- .ComptimeFloat, .ComptimeInt => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- else => {},
- },
- .ComptimeFloat => switch (chosen_ty_tag) {
- .Float => continue,
- .ComptimeInt => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- else => {},
- },
- .Enum => switch (chosen_ty_tag) {
- .EnumLiteral => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- .Union => continue,
- else => {},
- },
- .EnumLiteral => switch (chosen_ty_tag) {
- .Enum, .Union => continue,
- else => {},
- },
- .Union => switch (chosen_ty_tag) {
- .Enum, .EnumLiteral => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
+ if (s == .unknown) {
+ // The whole thing was noreturn or undefined - try to do an exact match
+ s = .exact;
+ } else {
+ // There was something other than noreturn and undefined, so we can ignore those peers
+ for (peer_tys) |*ty_ptr| {
+ const ty = ty_ptr.* orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .NoReturn, .Undefined => ty_ptr.* = null,
else => {},
- },
- .ErrorSet => switch (chosen_ty_tag) {
- .ErrorSet => {
- // If chosen is superset of candidate, keep it.
- // If candidate is superset of chosen, switch it.
- // If neither is a superset, merge errors.
- const chosen_set_ty = err_set_ty orelse chosen_ty;
+ }
+ }
+ }
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
- continue;
- }
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
- err_set_ty = null;
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
+ const target = mod.getTarget();
+
+ switch (s) {
+ .unknown => unreachable,
+
+ .error_set => {
+ var final_set: ?Type = null;
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ if (ty.zigTypeTag(mod) != .ErrorSet) return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+ if (final_set) |cur_set| {
+ final_set = try sema.maybeMergeErrorSets(block, src, cur_set, ty);
+ } else {
+ final_set = ty;
+ }
+ }
+ return .{ .success = final_set.? };
+ },
+
+ .error_union => {
+ var final_set: ?Type = null;
+ for (peer_tys, peer_vals) |*ty_ptr, *val_ptr| {
+ const ty = ty_ptr.* orelse continue;
+ const set_ty = switch (ty.zigTypeTag(mod)) {
+ .ErrorSet => blk: {
+ ty_ptr.* = null; // no payload to decide on
+ val_ptr.* = null;
+ break :blk ty;
+ },
+ .ErrorUnion => blk: {
+ const set_ty = ty.errorUnionSet(mod);
+ ty_ptr.* = ty.errorUnionPayload(mod);
+ if (val_ptr.*) |eu_val| switch (mod.intern_pool.indexToKey(eu_val.toIntern())) {
+ .error_union => |eu| switch (eu.val) {
+ .payload => |payload_ip| val_ptr.* = payload_ip.toValue(),
+ .err_name => val_ptr.* = null,
+ },
+ .undef => val_ptr.* = (try sema.mod.intern(.{ .undef = ty_ptr.*.?.toIntern() })).toValue(),
+ else => unreachable,
+ };
+ break :blk set_ty;
+ },
+ else => continue, // whole type is the payload
+ };
+ if (final_set) |cur_set| {
+ final_set = try sema.maybeMergeErrorSets(block, src, cur_set, set_ty);
+ } else {
+ final_set = set_ty;
+ }
+ }
+ assert(final_set != null);
+ const final_payload = switch (try sema.resolvePeerTypesInner(
+ block,
+ src,
+ peer_tys,
+ peer_vals,
+ )) {
+ .success => |ty| ty,
+ else => |result| return result,
+ };
+ return .{ .success = try mod.errorUnionType(final_set.?, final_payload) };
+ },
+
+ .nullable => {
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ if (!ty.eql(Type.null, mod)) return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+ }
+ return .{ .success = Type.null };
+ },
+
+ .optional => {
+ for (peer_tys, peer_vals) |*ty_ptr, *val_ptr| {
+ const ty = ty_ptr.* orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .Null => {
+ ty_ptr.* = null;
+ val_ptr.* = null;
+ },
+ .Optional => {
+ ty_ptr.* = ty.optionalChild(mod);
+ if (val_ptr.*) |opt_val| val_ptr.* = if (!opt_val.isUndef(mod)) opt_val.optionalValue(mod) else null;
+ },
+ else => {},
+ }
+ }
+ const child_ty = switch (try sema.resolvePeerTypesInner(
+ block,
+ src,
+ peer_tys,
+ peer_vals,
+ )) {
+ .success => |ty| ty,
+ else => |result| return result,
+ };
+ return .{ .success = try mod.optionalType(child_ty.toIntern()) };
+ },
+
+ .array => {
+ // Index of the first non-null peer
+ var opt_first_idx: ?usize = null;
+ // Index of the first array or vector peer (i.e. not a tuple)
+ var opt_first_arr_idx: ?usize = null;
+ // Set to non-null once we see any peer, even a tuple
+ var len: u64 = undefined;
+ var sentinel: ?Value = undefined;
+ // Only set once we see a non-tuple peer
+ var elem_ty: Type = undefined;
+
+ for (peer_tys, 0..) |*ty_ptr, i| {
+ const ty = ty_ptr.* orelse continue;
+
+ if (!ty.isArrayOrVector(mod)) {
+ // We allow tuples of the correct length. We won't validate their elem type, since the elements can be coerced.
+ const arr_like = sema.typeIsArrayLike(ty) orelse return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+
+ if (opt_first_idx) |first_idx| {
+ if (arr_like.len != len) return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ } else {
+ opt_first_idx = i;
+ len = arr_like.len;
}
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
+ sentinel = null;
+
continue;
- },
- .ErrorUnion => {
- const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
+ }
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
- continue;
+ const first_arr_idx = opt_first_arr_idx orelse {
+ if (opt_first_idx == null) {
+ opt_first_idx = i;
+ len = ty.arrayLen(mod);
+ sentinel = ty.sentinel(mod);
}
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
- err_set_ty = candidate_ty;
- continue;
- }
-
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
+ opt_first_arr_idx = i;
+ elem_ty = ty.childType(mod);
continue;
- },
- else => {
- if (err_set_ty) |chosen_set_ty| {
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_ty, src, src)) {
- continue;
- }
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_ty, chosen_set_ty, src, src)) {
- err_set_ty = candidate_ty;
- continue;
- }
+ };
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_ty);
- continue;
+ if (ty.arrayLen(mod) != len) return .{ .conflict = .{
+ .peer_idx_a = first_arr_idx,
+ .peer_idx_b = i,
+ } };
+
+ if (!ty.childType(mod).eql(elem_ty, mod)) {
+ return .{ .conflict = .{
+ .peer_idx_a = first_arr_idx,
+ .peer_idx_b = i,
+ } };
+ }
+
+ if (sentinel) |cur_sent| {
+ if (ty.sentinel(mod)) |peer_sent| {
+ if (!peer_sent.eql(cur_sent, elem_ty, mod)) sentinel = null;
} else {
- err_set_ty = candidate_ty;
- continue;
+ sentinel = null;
}
- },
- },
- .ErrorUnion => switch (chosen_ty_tag) {
- .ErrorSet => {
- const chosen_set_ty = err_set_ty orelse chosen_ty;
- const candidate_set_ty = candidate_ty.errorUnionSet();
+ }
+ }
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
- err_set_ty = chosen_set_ty;
- } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
- err_set_ty = null;
+ // There should always be at least one array or vector peer
+ assert(opt_first_arr_idx != null);
+
+ return .{ .success = try mod.arrayType(.{
+ .len = len,
+ .child = elem_ty.toIntern(),
+ .sentinel = if (sentinel) |sent_val| sent_val.toIntern() else .none,
+ }) };
+ },
+
+ .vector => {
+ var len: ?u64 = null;
+ var first_idx: usize = undefined;
+ for (peer_tys, peer_vals, 0..) |*ty_ptr, *val_ptr, i| {
+ const ty = ty_ptr.* orelse continue;
+
+ if (!ty.isArrayOrVector(mod)) {
+ // Allow tuples of the correct length
+ const arr_like = sema.typeIsArrayLike(ty) orelse return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+
+ if (len) |expect_len| {
+ if (arr_like.len != expect_len) return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
} else {
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
+ len = arr_like.len;
+ first_idx = i;
}
- chosen = candidate;
- chosen_i = candidate_i + 1;
+
+ // Tuples won't participate in the child type resolution. We'll resolve without
+ // them, and if the tuples have a bad type, we'll get a coercion error later.
+ ty_ptr.* = null;
+ val_ptr.* = null;
+
continue;
- },
+ }
- .ErrorUnion => {
- const chosen_payload_ty = chosen_ty.errorUnionPayload();
- const candidate_payload_ty = candidate_ty.errorUnionPayload();
+ if (len) |expect_len| {
+ if (ty.arrayLen(mod) != expect_len) return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ } else {
+ len = ty.arrayLen(mod);
+ first_idx = i;
+ }
- const coerce_chosen = (try sema.coerceInMemoryAllowed(block, chosen_payload_ty, candidate_payload_ty, false, target, src, src)) == .ok;
- const coerce_candidate = (try sema.coerceInMemoryAllowed(block, candidate_payload_ty, chosen_payload_ty, false, target, src, src)) == .ok;
+ ty_ptr.* = ty.childType(mod);
+ val_ptr.* = null; // multiple child vals, so we can't easily use them in PTR
+ }
- if (coerce_chosen or coerce_candidate) {
- // If we can coerce to the candidate, we switch to that
- // type. This is the same logic as the bare (non-union)
- // coercion check we do at the top of this func.
- if (coerce_candidate) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- }
+ const child_ty = switch (try sema.resolvePeerTypesInner(
+ block,
+ src,
+ peer_tys,
+ peer_vals,
+ )) {
+ .success => |ty| ty,
+ else => |result| return result,
+ };
- const chosen_set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
- const candidate_set_ty = candidate_ty.errorUnionSet();
+ return .{ .success = try mod.vectorType(.{
+ .len = @intCast(u32, len.?),
+ .child = child_ty.toIntern(),
+ }) };
+ },
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
- err_set_ty = chosen_set_ty;
- } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
- err_set_ty = candidate_set_ty;
+ .c_ptr => {
+ var opt_ptr_info: ?Type.Payload.Pointer.Data = null;
+ var first_idx: usize = undefined;
+ for (peer_tys, peer_vals, 0..) |opt_ty, opt_val, i| {
+ const ty = opt_ty orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .ComptimeInt => continue, // comptime-known integers can always coerce to C pointers
+ .Int => {
+ if (opt_val != null) {
+ // Always allow the coercion for comptime-known ints
+ continue;
} else {
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
+ // Runtime-known, so check if the type is no bigger than a usize
+ const ptr_bits = target.ptrBitWidth();
+ const bits = ty.intInfo(mod).bits;
+ if (bits <= ptr_bits) continue;
}
- continue;
- }
- },
+ },
+ .Null => continue,
+ else => {},
+ }
- else => {
- if (err_set_ty) |chosen_set_ty| {
- const candidate_set_ty = candidate_ty.errorUnionSet();
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, candidate_set_ty, src, src)) {
- err_set_ty = chosen_set_ty;
- } else if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, candidate_set_ty, chosen_set_ty, src, src)) {
- err_set_ty = null;
- } else {
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, candidate_set_ty);
- }
+ if (!ty.isPtrAtRuntime(mod)) return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+
+ // Goes through optionals
+ const peer_info = ty.ptrInfo(mod);
+
+ var ptr_info = opt_ptr_info orelse {
+ opt_ptr_info = peer_info;
+ opt_ptr_info.?.size = .C;
+ first_idx = i;
+ continue;
+ };
+
+ // Try peer -> cur, then cur -> peer
+ ptr_info.pointee_type = (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) orelse {
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ };
+
+ if (ptr_info.sentinel != null and peer_info.sentinel != null) {
+ const peer_sent = try mod.getCoerced(ptr_info.sentinel.?, ptr_info.pointee_type);
+ const ptr_sent = try mod.getCoerced(peer_info.sentinel.?, ptr_info.pointee_type);
+ if (ptr_sent.eql(peer_sent, ptr_info.pointee_type, mod)) {
+ ptr_info.sentinel = ptr_sent;
+ } else {
+ ptr_info.sentinel = null;
}
- seen_const = seen_const or chosen_ty.isConstPtr();
- chosen = candidate;
- chosen_i = candidate_i + 1;
+ } else {
+ ptr_info.sentinel = null;
+ }
+
+ // Note that the align can be always non-zero; Type.ptr will canonicalize it
+ ptr_info.@"align" = @min(ptr_info.alignment(mod), peer_info.alignment(mod));
+ if (ptr_info.@"addrspace" != peer_info.@"addrspace") {
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ }
+
+ if (ptr_info.bit_offset != peer_info.bit_offset or
+ ptr_info.host_size != peer_info.host_size)
+ {
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ }
+
+ ptr_info.mutable = ptr_info.mutable and peer_info.mutable;
+ ptr_info.@"volatile" = ptr_info.@"volatile" or peer_info.@"volatile";
+
+ opt_ptr_info = ptr_info;
+ }
+ return .{ .success = try Type.ptr(sema.arena, mod, opt_ptr_info.?) };
+ },
+
+ .ptr => {
+ // If we've resolved to a `[]T` but then see a `[*]T`, we can resolve to a `[*]T` only
+ // if there were no actual slices. Else, we want the slice index to report a conflict.
+ var opt_slice_idx: ?usize = null;
+
+ var opt_ptr_info: ?Type.Payload.Pointer.Data = null;
+ var first_idx: usize = undefined;
+ var other_idx: usize = undefined; // We sometimes need a second peer index to report a generic error
+
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ const peer_info: Type.Payload.Pointer.Data = switch (ty.zigTypeTag(mod)) {
+ .Pointer => ty.ptrInfo(mod),
+ .Fn => .{
+ .pointee_type = ty,
+ .@"addrspace" = target_util.defaultAddressSpace(target, .global_constant),
+ },
+ else => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
+ };
+
+ switch (peer_info.size) {
+ .One, .Many => {},
+ .Slice => opt_slice_idx = i,
+ .C => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
+ }
+
+ var ptr_info = opt_ptr_info orelse {
+ opt_ptr_info = peer_info;
+ first_idx = i;
continue;
- },
- },
- .Pointer => {
- const cand_info = candidate_ty.ptrInfo().data;
- switch (chosen_ty_tag) {
- .Pointer => {
- const chosen_info = chosen_ty.ptrInfo().data;
+ };
- seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
+ other_idx = i;
- // *[N]T to [*]T
- // *[N]T to []T
- if ((cand_info.size == .Many or cand_info.size == .Slice) and
- chosen_info.size == .One and
- chosen_info.pointee_type.zigTypeTag() == .Array)
- {
- // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
- convert_to_slice = false;
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- }
- if (cand_info.size == .One and
- cand_info.pointee_type.zigTypeTag() == .Array and
- (chosen_info.size == .Many or chosen_info.size == .Slice))
- {
- // In case we see i.e.: `*[1]T`, `*[2]T`, `[*]T`
- convert_to_slice = false;
- continue;
- }
+ // We want to return this in a lot of cases, so alias it here for convenience
+ const generic_err: PeerResolveResult = .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
- // *[N]T and *[M]T
- // Verify both are single-pointers to arrays.
- // Keep the one whose element type can be coerced into.
- if (chosen_info.size == .One and
- cand_info.size == .One and
- chosen_info.pointee_type.zigTypeTag() == .Array and
- cand_info.pointee_type.zigTypeTag() == .Array)
- {
- const chosen_elem_ty = chosen_info.pointee_type.childType();
- const cand_elem_ty = cand_info.pointee_type.childType();
+ // Note that the align can be always non-zero; Type.ptr will canonicalize it
+ ptr_info.@"align" = @min(ptr_info.alignment(mod), peer_info.alignment(mod));
- const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_elem_ty, cand_elem_ty, chosen_info.mutable, target, src, src);
- if (chosen_ok) {
- convert_to_slice = true;
- continue;
- }
+ if (ptr_info.@"addrspace" != peer_info.@"addrspace") {
+ return generic_err;
+ }
- const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_elem_ty, chosen_elem_ty, cand_info.mutable, target, src, src);
- if (cand_ok) {
- convert_to_slice = true;
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- }
+ if (ptr_info.bit_offset != peer_info.bit_offset or
+ ptr_info.host_size != peer_info.host_size)
+ {
+ return generic_err;
+ }
- // They're both bad. Report error.
- // In the future we probably want to use the
- // coerceInMemoryAllowed error reporting mechanism,
- // however, for now we just fall through for the
- // "incompatible types" error below.
- }
+ ptr_info.mutable = ptr_info.mutable and peer_info.mutable;
+ ptr_info.@"volatile" = ptr_info.@"volatile" or peer_info.@"volatile";
+
+ const peer_sentinel: ?Value = switch (peer_info.size) {
+ .One => switch (peer_info.pointee_type.zigTypeTag(mod)) {
+ .Array => peer_info.pointee_type.sentinel(mod),
+ else => null,
+ },
+ .Many, .Slice => peer_info.sentinel,
+ .C => unreachable,
+ };
+
+ const cur_sentinel: ?Value = switch (ptr_info.size) {
+ .One => switch (ptr_info.pointee_type.zigTypeTag(mod)) {
+ .Array => ptr_info.pointee_type.sentinel(mod),
+ else => null,
+ },
+ .Many, .Slice => ptr_info.sentinel,
+ .C => unreachable,
+ };
- // [*c]T and any other pointer size
- // Whichever element type can coerce to the other one, is
- // the one we will keep. If they're both OK then we keep the
- // C pointer since it matches both single and many pointers.
- if (cand_info.size == .C or chosen_info.size == .C) {
- const cand_ok = .ok == try sema.coerceInMemoryAllowed(block, cand_info.pointee_type, chosen_info.pointee_type, cand_info.mutable, target, src, src);
- const chosen_ok = .ok == try sema.coerceInMemoryAllowed(block, chosen_info.pointee_type, cand_info.pointee_type, chosen_info.mutable, target, src, src);
-
- if (cand_ok) {
- if (chosen_ok) {
- if (chosen_info.size == .C) {
- continue;
- } else {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
+ // We abstract array handling slightly so that tuple pointers can work like array pointers
+ const peer_pointee_array = sema.typeIsArrayLike(peer_info.pointee_type);
+ const cur_pointee_array = sema.typeIsArrayLike(ptr_info.pointee_type);
+
+ // This switch is just responsible for deciding the size and pointee (not including
+ // single-pointer array sentinel).
+ good: {
+ switch (peer_info.size) {
+ .One => switch (ptr_info.size) {
+ .One => {
+ if (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) |pointee| {
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+
+ const cur_arr = cur_pointee_array orelse return generic_err;
+ const peer_arr = peer_pointee_array orelse return generic_err;
+
+ if (try sema.resolvePairInMemoryCoercible(block, src, cur_arr.elem_ty, peer_arr.elem_ty)) |elem_ty| {
+ // *[n:x]T + *[n:y]T = *[n]T
+ if (cur_arr.len == peer_arr.len) {
+ ptr_info.pointee_type = try mod.arrayType(.{
+ .len = cur_arr.len,
+ .child = elem_ty.toIntern(),
+ });
+ break :good;
}
- } else {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
+ // *[a]T + *[b]T = []T
+ ptr_info.size = .Slice;
+ ptr_info.pointee_type = elem_ty;
+ break :good;
}
- } else {
- if (chosen_ok) {
- continue;
- } else {
- // They're both bad. Report error.
- // In the future we probably want to use the
- // coerceInMemoryAllowed error reporting mechanism,
- // however, for now we just fall through for the
- // "incompatible types" error below.
+
+ if (peer_arr.elem_ty.toIntern() == .noreturn_type) {
+ // *struct{} + *[a]T = []T
+ ptr_info.size = .Slice;
+ ptr_info.pointee_type = cur_arr.elem_ty;
+ break :good;
}
- }
- }
- },
- .Int, .ComptimeInt => {
- if (cand_info.size == .C) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
+
+ if (cur_arr.elem_ty.toIntern() == .noreturn_type) {
+ // *[a]T + *struct{} = []T
+ ptr_info.size = .Slice;
+ ptr_info.pointee_type = peer_arr.elem_ty;
+ break :good;
+ }
+
+ return generic_err;
+ },
+ .Many => {
+ // Only works for *[n]T + [*]T -> [*]T
+ const arr = peer_pointee_array orelse return generic_err;
+ if (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, arr.elem_ty)) |pointee| {
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ if (arr.elem_ty.toIntern() == .noreturn_type) {
+ // *struct{} + [*]T -> [*]T
+ break :good;
+ }
+ return generic_err;
+ },
+ .Slice => {
+ // Only works for *[n]T + []T -> []T
+ const arr = peer_pointee_array orelse return generic_err;
+ if (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, arr.elem_ty)) |pointee| {
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ if (arr.elem_ty.toIntern() == .noreturn_type) {
+ // *struct{} + []T -> []T
+ break :good;
+ }
+ return generic_err;
+ },
+ .C => unreachable,
+ },
+ .Many => switch (ptr_info.size) {
+ .One => {
+ // Only works for [*]T + *[n]T -> [*]T
+ const arr = cur_pointee_array orelse return generic_err;
+ if (try sema.resolvePairInMemoryCoercible(block, src, arr.elem_ty, peer_info.pointee_type)) |pointee| {
+ ptr_info.size = .Many;
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ if (arr.elem_ty.toIntern() == .noreturn_type) {
+ // [*]T + *struct{} -> [*]T
+ ptr_info.size = .Many;
+ ptr_info.pointee_type = peer_info.pointee_type;
+ break :good;
+ }
+ return generic_err;
+ },
+ .Many => {
+ if (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) |pointee| {
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ return generic_err;
+ },
+ .Slice => {
+ // Only works if no peers are actually slices
+ if (opt_slice_idx) |slice_idx| {
+ return .{ .conflict = .{
+ .peer_idx_a = slice_idx,
+ .peer_idx_b = i,
+ } };
+ }
+ // Okay, then works for [*]T + "[]T" -> [*]T
+ if (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) |pointee| {
+ ptr_info.size = .Many;
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ return generic_err;
+ },
+ .C => unreachable,
+ },
+ .Slice => switch (ptr_info.size) {
+ .One => {
+ // Only works for []T + *[n]T -> []T
+ const arr = cur_pointee_array orelse return generic_err;
+ if (try sema.resolvePairInMemoryCoercible(block, src, arr.elem_ty, peer_info.pointee_type)) |pointee| {
+ ptr_info.size = .Slice;
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ if (arr.elem_ty.toIntern() == .noreturn_type) {
+ // []T + *struct{} -> []T
+ ptr_info.size = .Slice;
+ ptr_info.pointee_type = peer_info.pointee_type;
+ break :good;
+ }
+ return generic_err;
+ },
+ .Many => {
+ // Impossible! (current peer is an actual slice)
+ return generic_err;
+ },
+ .Slice => {
+ if (try sema.resolvePairInMemoryCoercible(block, src, ptr_info.pointee_type, peer_info.pointee_type)) |pointee| {
+ ptr_info.pointee_type = pointee;
+ break :good;
+ }
+ return generic_err;
+ },
+ .C => unreachable,
+ },
+ .C => unreachable,
+ }
+ }
+
+ const sentinel_ty = if (ptr_info.size == .One and ptr_info.pointee_type.zigTypeTag(mod) == .Array) blk: {
+ break :blk ptr_info.pointee_type.childType(mod);
+ } else ptr_info.pointee_type;
+
+ // TODO: once InternPool is in, we need to cast the sentinels to sentinel_ty
+
+ sentinel: {
+ no_sentinel: {
+ if (peer_sentinel == null) break :no_sentinel;
+ if (cur_sentinel == null) break :no_sentinel;
+ const peer_sent_coerced = try mod.getCoerced(peer_sentinel.?, sentinel_ty);
+ const cur_sent_coerced = try mod.getCoerced(cur_sentinel.?, sentinel_ty);
+ if (!peer_sent_coerced.eql(cur_sent_coerced, sentinel_ty, mod)) break :no_sentinel;
+ // Sentinels match
+ if (ptr_info.size == .One) {
+ assert(ptr_info.pointee_type.zigTypeTag(mod) == .Array);
+ ptr_info.pointee_type = try mod.arrayType(.{
+ .len = ptr_info.pointee_type.arrayLen(mod),
+ .child = ptr_info.pointee_type.childType(mod).toIntern(),
+ .sentinel = cur_sent_coerced.toIntern(),
+ });
+ } else {
+ ptr_info.sentinel = cur_sent_coerced;
}
+ break :sentinel;
+ }
+ // Clear existing sentinel
+ ptr_info.sentinel = null;
+ if (ptr_info.pointee_type.zigTypeTag(mod) == .Array) {
+ ptr_info.pointee_type = try mod.arrayType(.{
+ .len = ptr_info.pointee_type.arrayLen(mod),
+ .child = ptr_info.pointee_type.childType(mod).toIntern(),
+ .sentinel = .none,
+ });
+ }
+ }
+
+ opt_ptr_info = ptr_info;
+ }
+
+ // Before we succeed, check the pointee type. If we tried to apply PTR to (for instance)
+ // &.{} and &.{}, we'll currently have a pointer type of `*[0]noreturn` - we wanted to
+ // coerce the empty struct to a specific type, but no peer provided one. We need to
+ // detect this case and emit an error.
+ const pointee = opt_ptr_info.?.pointee_type;
+ if (pointee.toIntern() == .noreturn_type or
+ (pointee.zigTypeTag(mod) == .Array and pointee.childType(mod).toIntern() == .noreturn_type))
+ {
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = other_idx,
+ } };
+ }
+
+ return .{ .success = try Type.ptr(sema.arena, mod, opt_ptr_info.?) };
+ },
+
+ .func => {
+ var opt_cur_ty: ?Type = null;
+ var first_idx: usize = undefined;
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ const cur_ty = opt_cur_ty orelse {
+ opt_cur_ty = ty;
+ first_idx = i;
+ continue;
+ };
+ if (ty.zigTypeTag(mod) != .Fn) return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+ // ty -> cur_ty
+ if (.ok == try sema.coerceInMemoryAllowedFns(block, cur_ty, ty, target, src, src)) {
+ continue;
+ }
+ // cur_ty -> ty
+ if (.ok == try sema.coerceInMemoryAllowedFns(block, ty, cur_ty, target, src, src)) {
+ opt_cur_ty = ty;
+ continue;
+ }
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ }
+ return .{ .success = opt_cur_ty.? };
+ },
+
+ .enum_or_union => {
+ var opt_cur_ty: ?Type = null;
+ // The peer index which gave the current type
+ var cur_ty_idx: usize = undefined;
+
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .EnumLiteral, .Enum, .Union => {},
+ else => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
+ }
+ const cur_ty = opt_cur_ty orelse {
+ opt_cur_ty = ty;
+ cur_ty_idx = i;
+ continue;
+ };
+
+ // We want to return this in a lot of cases, so alias it here for convenience
+ const generic_err: PeerResolveResult = .{ .conflict = .{
+ .peer_idx_a = cur_ty_idx,
+ .peer_idx_b = i,
+ } };
+
+ switch (cur_ty.zigTypeTag(mod)) {
+ .EnumLiteral => {
+ opt_cur_ty = ty;
+ cur_ty_idx = i;
},
- .Optional => {
- var opt_child_buf: Type.Payload.ElemType = undefined;
- const chosen_ptr_ty = chosen_ty.optionalChild(&opt_child_buf);
- if (chosen_ptr_ty.zigTypeTag() == .Pointer) {
- const chosen_info = chosen_ptr_ty.ptrInfo().data;
-
- seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
-
- // *[N]T to ?![*]T
- // *[N]T to ?![]T
- if (cand_info.size == .One and
- cand_info.pointee_type.zigTypeTag() == .Array and
- (chosen_info.size == .Many or chosen_info.size == .Slice))
- {
- continue;
- }
- }
+ .Enum => switch (ty.zigTypeTag(mod)) {
+ .EnumLiteral => {},
+ .Enum => {
+ if (!ty.eql(cur_ty, mod)) return generic_err;
+ },
+ .Union => {
+ const tag_ty = ty.unionTagTypeHypothetical(mod);
+ if (!tag_ty.eql(cur_ty, mod)) return generic_err;
+ opt_cur_ty = ty;
+ cur_ty_idx = i;
+ },
+ else => unreachable,
},
- .ErrorUnion => {
- const chosen_ptr_ty = chosen_ty.errorUnionPayload();
- if (chosen_ptr_ty.zigTypeTag() == .Pointer) {
- const chosen_info = chosen_ptr_ty.ptrInfo().data;
-
- seen_const = seen_const or !chosen_info.mutable or !cand_info.mutable;
-
- // *[N]T to E![*]T
- // *[N]T to E![]T
- if (cand_info.size == .One and
- cand_info.pointee_type.zigTypeTag() == .Array and
- (chosen_info.size == .Many or chosen_info.size == .Slice))
- {
- continue;
- }
- }
+ .Union => switch (ty.zigTypeTag(mod)) {
+ .EnumLiteral => {},
+ .Enum => {
+ const cur_tag_ty = cur_ty.unionTagTypeHypothetical(mod);
+ if (!ty.eql(cur_tag_ty, mod)) return generic_err;
+ },
+ .Union => {
+ if (!ty.eql(cur_ty, mod)) return generic_err;
+ },
+ else => unreachable,
},
- .Fn => {
- if (!cand_info.mutable and cand_info.pointee_type.zigTypeTag() == .Fn and .ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty, cand_info.pointee_type, target, src, src)) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- }
+ else => unreachable,
+ }
+ }
+ return .{ .success = opt_cur_ty.? };
+ },
+
+ .comptime_int => {
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .ComptimeInt => {},
+ else => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
+ }
+ }
+ return .{ .success = Type.comptime_int };
+ },
+
+ .comptime_float => {
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .ComptimeInt, .ComptimeFloat => {},
+ else => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
+ }
+ }
+ return .{ .success = Type.comptime_float };
+ },
+
+ .fixed_int => {
+ var idx_unsigned: ?usize = null;
+ var idx_signed: ?usize = null;
+
+ // TODO: this is for compatibility with legacy behavior. See beneath the loop.
+ var any_comptime_known = false;
+
+ for (peer_tys, peer_vals, 0..) |opt_ty, *ptr_opt_val, i| {
+ const ty = opt_ty orelse continue;
+ const opt_val = ptr_opt_val.*;
+
+ const peer_tag = ty.zigTypeTag(mod);
+ switch (peer_tag) {
+ .ComptimeInt => {
+ // If the value is undefined, we can't refine to a fixed-width int
+ if (opt_val == null or opt_val.?.isUndef(mod)) return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+ any_comptime_known = true;
+ ptr_opt_val.* = try sema.resolveLazyValue(opt_val.?);
+ continue;
},
- else => {},
+ .Int => {},
+ else => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
}
- },
- .Optional => {
- var opt_child_buf: Type.Payload.ElemType = undefined;
- const opt_child_ty = candidate_ty.optionalChild(&opt_child_buf);
- if ((try sema.coerceInMemoryAllowed(block, chosen_ty, opt_child_ty, false, target, src, src)) == .ok) {
- seen_const = seen_const or opt_child_ty.isConstPtr();
- any_are_null = true;
+
+ if (opt_val != null) any_comptime_known = true;
+
+ const info = ty.intInfo(mod);
+
+ const idx_ptr = switch (info.signedness) {
+ .unsigned => &idx_unsigned,
+ .signed => &idx_signed,
+ };
+
+ const largest_idx = idx_ptr.* orelse {
+ idx_ptr.* = i;
continue;
+ };
+
+ const cur_info = peer_tys[largest_idx].?.intInfo(mod);
+ if (info.bits > cur_info.bits) {
+ idx_ptr.* = i;
}
+ }
- seen_const = seen_const or chosen_ty.isConstPtr();
- any_are_null = false;
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- .Vector => switch (chosen_ty_tag) {
- .Vector => {
- const chosen_len = chosen_ty.vectorLen();
- const candidate_len = candidate_ty.vectorLen();
- if (chosen_len != candidate_len)
- continue;
+ if (idx_signed == null) {
+ return .{ .success = peer_tys[idx_unsigned.?].? };
+ }
- const chosen_child_ty = chosen_ty.childType();
- const candidate_child_ty = candidate_ty.childType();
- if (chosen_child_ty.zigTypeTag() == .Int and candidate_child_ty.zigTypeTag() == .Int) {
- const chosen_info = chosen_child_ty.intInfo(target);
- const candidate_info = candidate_child_ty.intInfo(target);
- if (chosen_info.bits < candidate_info.bits) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- }
- continue;
- }
- if (chosen_child_ty.zigTypeTag() == .Float and candidate_child_ty.zigTypeTag() == .Float) {
- if (chosen_ty.floatBits(target) < candidate_ty.floatBits(target)) {
- chosen = candidate;
- chosen_i = candidate_i + 1;
+ if (idx_unsigned == null) {
+ return .{ .success = peer_tys[idx_signed.?].? };
+ }
+
+ const unsigned_info = peer_tys[idx_unsigned.?].?.intInfo(mod);
+ const signed_info = peer_tys[idx_signed.?].?.intInfo(mod);
+ if (signed_info.bits > unsigned_info.bits) {
+ return .{ .success = peer_tys[idx_signed.?].? };
+ }
+
+ // TODO: this is for compatibility with legacy behavior. Before this version of PTR was
+ // implemented, the algorithm very often returned false positives, with the expectation
+ // that you'd just hit a coercion error later. One of these was that for integers, the
+ // largest type would always be returned, even if it couldn't fit everything. This had
+ // an unintentional consequence to semantics, which is that if values were known at
+ // comptime, they would be coerced down to the smallest type where possible. This
+ // behavior is unintuitive and order-dependent, so in my opinion should be eliminated,
+ // but for now we'll retain compatibility.
+ if (any_comptime_known) {
+ if (unsigned_info.bits > signed_info.bits) {
+ return .{ .success = peer_tys[idx_unsigned.?].? };
+ }
+ const idx = @min(idx_unsigned.?, idx_signed.?);
+ return .{ .success = peer_tys[idx].? };
+ }
+
+ return .{ .conflict = .{
+ .peer_idx_a = idx_unsigned.?,
+ .peer_idx_b = idx_signed.?,
+ } };
+ },
+
+ .fixed_float => {
+ var opt_cur_ty: ?Type = null;
+
+ for (peer_tys, peer_vals, 0..) |opt_ty, opt_val, i| {
+ const ty = opt_ty orelse continue;
+ switch (ty.zigTypeTag(mod)) {
+ .ComptimeFloat, .ComptimeInt => {},
+ .Int => {
+ if (opt_val == null) return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
+ },
+ .Float => {
+ if (opt_cur_ty) |cur_ty| {
+ if (cur_ty.eql(ty, mod)) continue;
+ // Recreate the type so we eliminate any c_longdouble
+ const bits = @max(cur_ty.floatBits(target), ty.floatBits(target));
+ opt_cur_ty = switch (bits) {
+ 16 => Type.f16,
+ 32 => Type.f32,
+ 64 => Type.f64,
+ 80 => Type.f80,
+ 128 => Type.f128,
+ else => unreachable,
+ };
+ } else {
+ opt_cur_ty = ty;
}
- continue;
- }
- },
- .Array => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- else => {},
- },
- .Array => switch (chosen_ty_tag) {
- .Vector => continue,
- else => {},
- },
- .Fn => if (chosen_ty.isSinglePointer() and chosen_ty.isConstPtr() and chosen_ty.childType().zigTypeTag() == .Fn) {
- if (.ok == try sema.coerceInMemoryAllowedFns(block, chosen_ty.childType(), candidate_ty, target, src, src)) {
- continue;
+ },
+ else => return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } },
}
- },
- else => {},
- }
+ }
- switch (chosen_ty_tag) {
- .NoReturn, .Undefined => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- .Null => {
- any_are_null = true;
- chosen = candidate;
- chosen_i = candidate_i + 1;
- continue;
- },
- .Optional => {
- var opt_child_buf: Type.Payload.ElemType = undefined;
- const opt_child_ty = chosen_ty.optionalChild(&opt_child_buf);
- if ((try sema.coerceInMemoryAllowed(block, opt_child_ty, candidate_ty, false, target, src, src)) == .ok) {
- continue;
+ // Note that fixed_float is only chosen if there is at least one fixed-width float peer,
+ // so opt_cur_ty must be non-null.
+ return .{ .success = opt_cur_ty.? };
+ },
+
+ .coercible_struct => {
+ // First, check that every peer has the same approximate structure (field count and names)
+
+ var opt_first_idx: ?usize = null;
+ var is_tuple: bool = undefined;
+ var field_count: usize = undefined;
+ // Only defined for non-tuples.
+ var field_names: []InternPool.NullTerminatedString = undefined;
+
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+
+ if (!ty.isTupleOrAnonStruct(mod)) {
+ return .{ .conflict = .{
+ .peer_idx_a = strat_reason,
+ .peer_idx_b = i,
+ } };
}
- if ((try sema.coerceInMemoryAllowed(block, candidate_ty, opt_child_ty, false, target, src, src)) == .ok) {
- any_are_null = true;
- chosen = candidate;
- chosen_i = candidate_i + 1;
+
+ const first_idx = opt_first_idx orelse {
+ opt_first_idx = i;
+ is_tuple = ty.isTuple(mod);
+ field_count = ty.structFieldCount(mod);
+ if (!is_tuple) {
+ const names = mod.intern_pool.indexToKey(ty.toIntern()).anon_struct_type.names;
+ field_names = try sema.arena.dupe(InternPool.NullTerminatedString, names);
+ }
continue;
+ };
+
+ if (ty.isTuple(mod) != is_tuple or ty.structFieldCount(mod) != field_count) {
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
}
- },
- .ErrorUnion => {
- const payload_ty = chosen_ty.errorUnionPayload();
- if ((try sema.coerceInMemoryAllowed(block, payload_ty, candidate_ty, false, target, src, src)) == .ok) {
- continue;
+
+ if (!is_tuple) {
+ for (field_names, 0..) |expected, field_idx| {
+ const actual = ty.structFieldName(field_idx, mod);
+ if (actual == expected) continue;
+ return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ }
}
- },
- .ErrorSet => {
- chosen = candidate;
- chosen_i = candidate_i + 1;
- if (err_set_ty) |chosen_set_ty| {
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_set_ty, chosen_ty, src, src)) {
+ }
+
+ assert(opt_first_idx != null);
+
+ // Now, we'll recursively resolve the field types
+ const field_types = try sema.arena.alloc(InternPool.Index, field_count);
+ // Values for `comptime` fields - `.none` used for non-comptime fields
+ const field_vals = try sema.arena.alloc(InternPool.Index, field_count);
+ const sub_peer_tys = try sema.arena.alloc(?Type, peer_tys.len);
+ const sub_peer_vals = try sema.arena.alloc(?Value, peer_vals.len);
+
+ for (field_types, field_vals, 0..) |*field_ty, *field_val, field_idx| {
+ // Fill buffers with types and values of the field
+ for (peer_tys, peer_vals, sub_peer_tys, sub_peer_vals) |opt_ty, opt_val, *peer_field_ty, *peer_field_val| {
+ const ty = opt_ty orelse {
+ peer_field_ty.* = null;
+ peer_field_val.* = null;
continue;
- }
- if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, chosen_ty, chosen_set_ty, src, src)) {
- err_set_ty = chosen_ty;
+ };
+ peer_field_ty.* = ty.structFieldType(field_idx, mod);
+ peer_field_val.* = if (opt_val) |val| try val.fieldValue(mod, field_idx) else null;
+ }
+
+ // Resolve field type recursively
+ field_ty.* = switch (try sema.resolvePeerTypesInner(block, src, sub_peer_tys, sub_peer_vals)) {
+ .success => |ty| ty.toIntern(),
+ else => |result| {
+ const result_buf = try sema.arena.create(PeerResolveResult);
+ result_buf.* = result;
+ const field_name = if (is_tuple) name: {
+ break :name try std.fmt.allocPrint(sema.arena, "{d}", .{field_idx});
+ } else try sema.arena.dupe(u8, mod.intern_pool.stringToSlice(field_names[field_idx]));
+
+ // The error info needs the field types, but we can't reuse sub_peer_tys
+ // since the recursive call may have clobbered it.
+ const peer_field_tys = try sema.arena.alloc(Type, peer_tys.len);
+ for (peer_tys, peer_field_tys) |opt_ty, *peer_field_ty| {
+ // Already-resolved types won't be referenced by the error so it's fine
+ // to leave them undefined.
+ const ty = opt_ty orelse continue;
+ peer_field_ty.* = ty.structFieldType(field_idx, mod);
+ }
+
+ return .{ .field_error = .{
+ .field_name = field_name,
+ .field_types = peer_field_tys,
+ .sub_result = result_buf,
+ } };
+ },
+ };
+
+ // Decide if this is a comptime field. If it is comptime in all peers, and the
+ // coerced comptime values are all the same, we say it is comptime, else not.
+
+ var comptime_val: ?Value = null;
+ for (peer_tys) |opt_ty| {
+ const struct_ty = opt_ty orelse continue;
+ const uncoerced_field_val = try struct_ty.structFieldValueComptime(mod, field_idx) orelse {
+ comptime_val = null;
+ break;
+ };
+ const uncoerced_field_ty = struct_ty.structFieldType(field_idx, mod);
+ const uncoerced_field = try sema.addConstant(uncoerced_field_ty, uncoerced_field_val);
+ const coerced_inst = sema.coerceExtra(block, field_ty.toType(), uncoerced_field, src, .{ .report_err = false }) catch |err| switch (err) {
+ // It's possible for PTR to give false positives. Just give up on making this a comptime field, we'll get an error later anyway
+ error.NotCoercible => {
+ comptime_val = null;
+ break;
+ },
+ else => |e| return e,
+ };
+ const coerced_val = (try sema.resolveMaybeUndefVal(coerced_inst)) orelse continue;
+ const existing = comptime_val orelse {
+ comptime_val = coerced_val;
continue;
+ };
+ if (!coerced_val.eql(existing, field_ty.toType(), mod)) {
+ comptime_val = null;
+ break;
}
-
- err_set_ty = try chosen_set_ty.errorSetMerge(sema.arena, chosen_ty);
- continue;
- } else {
- err_set_ty = chosen_ty;
- continue;
}
- },
- else => {},
- }
- // At this point, we hit a compile error. We need to recover
- // the source locations.
- const chosen_src = candidate_srcs.resolve(
- sema.gpa,
- sema.mod.declPtr(block.src_decl),
- chosen_i,
- );
- const candidate_src = candidate_srcs.resolve(
- sema.gpa,
- sema.mod.declPtr(block.src_decl),
- candidate_i + 1,
- );
+ field_val.* = if (comptime_val) |v| v.toIntern() else .none;
+ }
- const msg = msg: {
- const msg = try sema.errMsg(block, src, "incompatible types: '{}' and '{}'", .{
- chosen_ty.fmt(sema.mod),
- candidate_ty.fmt(sema.mod),
- });
- errdefer msg.destroy(sema.gpa);
+ const final_ty = try mod.intern(.{ .anon_struct_type = .{
+ .types = field_types,
+ .names = if (is_tuple) &.{} else field_names,
+ .values = field_vals,
+ } });
- if (chosen_src) |src_loc|
- try sema.errNote(block, src_loc, msg, "type '{}' here", .{chosen_ty.fmt(sema.mod)});
+ return .{ .success = final_ty.toType() };
+ },
- if (candidate_src) |src_loc|
- try sema.errNote(block, src_loc, msg, "type '{}' here", .{candidate_ty.fmt(sema.mod)});
+ .exact => {
+ var expect_ty: ?Type = null;
+ var first_idx: usize = undefined;
+ for (peer_tys, 0..) |opt_ty, i| {
+ const ty = opt_ty orelse continue;
+ if (expect_ty) |expect| {
+ if (!ty.eql(expect, mod)) return .{ .conflict = .{
+ .peer_idx_a = first_idx,
+ .peer_idx_b = i,
+ } };
+ } else {
+ expect_ty = ty;
+ first_idx = i;
+ }
+ }
+ return .{ .success = expect_ty.? };
+ },
+ }
+}
- break :msg msg;
- };
- return sema.failWithOwnedErrorMsg(msg);
+fn maybeMergeErrorSets(sema: *Sema, block: *Block, src: LazySrcLoc, e0: Type, e1: Type) !Type {
+ // e0 -> e1
+ if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, e1, e0, src, src)) {
+ return e1;
}
- const chosen_ty = sema.typeOf(chosen);
+ // e1 -> e0
+ if (.ok == try sema.coerceInMemoryAllowedErrorSets(block, e0, e1, src, src)) {
+ return e0;
+ }
- if (convert_to_slice) {
- // turn *[N]T => []T
- const chosen_child_ty = chosen_ty.childType();
- var info = chosen_ty.ptrInfo();
- info.data.sentinel = chosen_child_ty.sentinel();
- info.data.size = .Slice;
- info.data.mutable = !(seen_const or chosen_child_ty.isConstPtr());
- info.data.pointee_type = chosen_child_ty.elemType2();
+ return sema.errorSetMerge(e0, e1);
+}
- const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
- const opt_ptr_ty = if (any_are_null)
- try Type.optional(sema.arena, new_ptr_ty)
- else
- new_ptr_ty;
- const set_ty = err_set_ty orelse return opt_ptr_ty;
- return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod);
+fn resolvePairInMemoryCoercible(sema: *Sema, block: *Block, src: LazySrcLoc, ty_a: Type, ty_b: Type) !?Type {
+ // ty_b -> ty_a
+ if (.ok == try sema.coerceInMemoryAllowed(block, ty_a, ty_b, true, sema.mod.getTarget(), src, src)) {
+ return ty_a;
}
- if (seen_const) {
- // turn []T => []const T
- switch (chosen_ty.zigTypeTag()) {
- .ErrorUnion => {
- const ptr_ty = chosen_ty.errorUnionPayload();
- var info = ptr_ty.ptrInfo();
- info.data.mutable = false;
- const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
- const opt_ptr_ty = if (any_are_null)
- try Type.optional(sema.arena, new_ptr_ty)
- else
- new_ptr_ty;
- const set_ty = err_set_ty orelse chosen_ty.errorUnionSet();
- return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod);
- },
- .Pointer => {
- var info = chosen_ty.ptrInfo();
- info.data.mutable = false;
- const new_ptr_ty = try Type.ptr(sema.arena, sema.mod, info.data);
- const opt_ptr_ty = if (any_are_null)
- try Type.optional(sema.arena, new_ptr_ty)
- else
- new_ptr_ty;
- const set_ty = err_set_ty orelse return opt_ptr_ty;
- return try Type.errorUnion(sema.arena, set_ty, opt_ptr_ty, sema.mod);
- },
- else => return chosen_ty,
- }
+ // ty_a -> ty_b
+ if (.ok == try sema.coerceInMemoryAllowed(block, ty_b, ty_a, true, sema.mod.getTarget(), src, src)) {
+ return ty_b;
}
- if (any_are_null) {
- const opt_ty = switch (chosen_ty.zigTypeTag()) {
- .Null, .Optional => chosen_ty,
- else => try Type.optional(sema.arena, chosen_ty),
- };
- const set_ty = err_set_ty orelse return opt_ty;
- return try Type.errorUnion(sema.arena, set_ty, opt_ty, sema.mod);
- }
+ return null;
+}
- if (err_set_ty) |ty| switch (chosen_ty.zigTypeTag()) {
- .ErrorSet => return ty,
- .ErrorUnion => {
- const payload_ty = chosen_ty.errorUnionPayload();
- return try Type.errorUnion(sema.arena, ty, payload_ty, sema.mod);
+const ArrayLike = struct {
+ len: u64,
+ /// `noreturn` indicates that this type is `struct{}` so can coerce to anything
+ elem_ty: Type,
+};
+fn typeIsArrayLike(sema: *Sema, ty: Type) ?ArrayLike {
+ const mod = sema.mod;
+ return switch (ty.zigTypeTag(mod)) {
+ .Array => .{
+ .len = ty.arrayLen(mod),
+ .elem_ty = ty.childType(mod),
},
- else => return try Type.errorUnion(sema.arena, ty, chosen_ty, sema.mod),
+ .Struct => {
+ const field_count = ty.structFieldCount(mod);
+ if (field_count == 0) return .{
+ .len = 0,
+ .elem_ty = Type.noreturn,
+ };
+ if (!ty.isTuple(mod)) return null;
+ const elem_ty = ty.structFieldType(0, mod);
+ for (1..field_count) |i| {
+ if (!ty.structFieldType(i, mod).eql(elem_ty, mod)) {
+ return null;
+ }
+ }
+ return .{
+ .len = field_count,
+ .elem_ty = elem_ty,
+ };
+ },
+ else => null,
};
-
- return chosen_ty;
}
-pub fn resolveFnTypes(sema: *Sema, fn_info: Type.Payload.Function.Data) CompileError!void {
- try sema.resolveTypeFully(fn_info.return_type);
+pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void {
+ const mod = sema.mod;
+ try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.return_type.toType());
- if (sema.mod.comp.bin_file.options.error_return_tracing and fn_info.return_type.isError()) {
+ if (mod.comp.bin_file.options.error_return_tracing and mod.typeToFunc(fn_ty).?.return_type.toType().isError(mod)) {
// Ensure the type exists so that backends can assume that.
_ = try sema.getBuiltinType("StackTrace");
}
- for (fn_info.param_types) |param_ty| {
- try sema.resolveTypeFully(param_ty);
+ for (0..mod.typeToFunc(fn_ty).?.param_types.len) |i| {
+ try sema.resolveTypeFully(mod.typeToFunc(fn_ty).?.param_types[i].toType());
}
}
/// Make it so that calling hash() and eql() on `val` will not assert due
/// to a type not having its layout resolved.
-fn resolveLazyValue(sema: *Sema, val: Value) CompileError!void {
- switch (val.tag()) {
- .lazy_align => {
- const ty = val.castTag(.lazy_align).?.data;
- return sema.resolveTypeLayout(ty);
- },
- .lazy_size => {
- const ty = val.castTag(.lazy_size).?.data;
- return sema.resolveTypeLayout(ty);
- },
- .comptime_field_ptr => {
- const field_ptr = val.castTag(.comptime_field_ptr).?.data;
- return sema.resolveLazyValue(field_ptr.field_val);
- },
- .eu_payload,
- .opt_payload,
- => {
- const sub_val = val.cast(Value.Payload.SubValue).?.data;
- return sema.resolveLazyValue(sub_val);
- },
- .@"union" => {
- const union_val = val.castTag(.@"union").?.data;
- return sema.resolveLazyValue(union_val.val);
- },
- .aggregate => {
- const aggregate = val.castTag(.aggregate).?.data;
- for (aggregate) |elem_val| {
- try sema.resolveLazyValue(elem_val);
+fn resolveLazyValue(sema: *Sema, val: Value) CompileError!Value {
+ const mod = sema.mod;
+ switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .int => |int| switch (int.storage) {
+ .u64, .i64, .big_int => return val,
+ .lazy_align, .lazy_size => return (try mod.intern(.{ .int = .{
+ .ty = int.ty,
+ .storage = .{ .u64 = (try val.getUnsignedIntAdvanced(mod, sema)).? },
+ } })).toValue(),
+ },
+ .ptr => |ptr| {
+ const resolved_len = switch (ptr.len) {
+ .none => .none,
+ else => (try sema.resolveLazyValue(ptr.len.toValue())).toIntern(),
+ };
+ switch (ptr.addr) {
+ .decl, .mut_decl => return if (resolved_len == ptr.len)
+ val
+ else
+ (try mod.intern(.{ .ptr = .{
+ .ty = ptr.ty,
+ .addr = switch (ptr.addr) {
+ .decl => |decl| .{ .decl = decl },
+ .mut_decl => |mut_decl| .{ .mut_decl = mut_decl },
+ else => unreachable,
+ },
+ .len = resolved_len,
+ } })).toValue(),
+ .comptime_field => |field_val| {
+ const resolved_field_val =
+ (try sema.resolveLazyValue(field_val.toValue())).toIntern();
+ return if (resolved_field_val == field_val and resolved_len == ptr.len)
+ val
+ else
+ (try mod.intern(.{ .ptr = .{
+ .ty = ptr.ty,
+ .addr = .{ .comptime_field = resolved_field_val },
+ .len = resolved_len,
+ } })).toValue();
+ },
+ .int => |int| {
+ const resolved_int = (try sema.resolveLazyValue(int.toValue())).toIntern();
+ return if (resolved_int == int and resolved_len == ptr.len)
+ val
+ else
+ (try mod.intern(.{ .ptr = .{
+ .ty = ptr.ty,
+ .addr = .{ .int = resolved_int },
+ .len = resolved_len,
+ } })).toValue();
+ },
+ .eu_payload, .opt_payload => |base| {
+ const resolved_base = (try sema.resolveLazyValue(base.toValue())).toIntern();
+ return if (resolved_base == base and resolved_len == ptr.len)
+ val
+ else
+ (try mod.intern(.{ .ptr = .{
+ .ty = ptr.ty,
+ .addr = switch (ptr.addr) {
+ .eu_payload => .{ .eu_payload = resolved_base },
+ .opt_payload => .{ .opt_payload = resolved_base },
+ else => unreachable,
+ },
+ .len = ptr.len,
+ } })).toValue();
+ },
+ .elem, .field => |base_index| {
+ const resolved_base = (try sema.resolveLazyValue(base_index.base.toValue())).toIntern();
+ return if (resolved_base == base_index.base and resolved_len == ptr.len)
+ val
+ else
+ (try mod.intern(.{ .ptr = .{
+ .ty = ptr.ty,
+ .addr = switch (ptr.addr) {
+ .elem => .{ .elem = .{
+ .base = resolved_base,
+ .index = base_index.index,
+ } },
+ .field => .{ .field = .{
+ .base = resolved_base,
+ .index = base_index.index,
+ } },
+ else => unreachable,
+ },
+ .len = ptr.len,
+ } })).toValue();
+ },
}
},
- .slice => {
- const slice = val.castTag(.slice).?.data;
- try sema.resolveLazyValue(slice.ptr);
- return sema.resolveLazyValue(slice.len);
+ .aggregate => |aggregate| switch (aggregate.storage) {
+ .bytes => return val,
+ .elems => |elems| {
+ var resolved_elems: []InternPool.Index = &.{};
+ for (elems, 0..) |elem, i| {
+ const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern();
+ if (resolved_elems.len == 0 and resolved_elem != elem) {
+ resolved_elems = try sema.arena.alloc(InternPool.Index, elems.len);
+ @memcpy(resolved_elems[0..i], elems[0..i]);
+ }
+ if (resolved_elems.len > 0) resolved_elems[i] = resolved_elem;
+ }
+ return if (resolved_elems.len == 0) val else (try mod.intern(.{ .aggregate = .{
+ .ty = aggregate.ty,
+ .storage = .{ .elems = resolved_elems },
+ } })).toValue();
+ },
+ .repeated_elem => |elem| {
+ const resolved_elem = (try sema.resolveLazyValue(elem.toValue())).toIntern();
+ return if (resolved_elem == elem) val else (try mod.intern(.{ .aggregate = .{
+ .ty = aggregate.ty,
+ .storage = .{ .repeated_elem = resolved_elem },
+ } })).toValue();
+ },
+ },
+ .un => |un| {
+ const resolved_tag = (try sema.resolveLazyValue(un.tag.toValue())).toIntern();
+ const resolved_val = (try sema.resolveLazyValue(un.val.toValue())).toIntern();
+ return if (resolved_tag == un.tag and resolved_val == un.val)
+ val
+ else
+ (try mod.intern(.{ .un = .{
+ .ty = un.ty,
+ .tag = resolved_tag,
+ .val = resolved_val,
+ } })).toValue();
},
- else => return,
+ else => return val,
}
}
pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Struct => return sema.resolveStructLayout(ty),
.Union => return sema.resolveUnionLayout(ty),
.Array => {
- if (ty.arrayLenIncludingSentinel() == 0) return;
- const elem_ty = ty.childType();
+ if (ty.arrayLenIncludingSentinel(mod) == 0) return;
+ const elem_ty = ty.childType(mod);
return sema.resolveTypeLayout(elem_ty);
},
.Optional => {
- var buf: Type.Payload.ElemType = undefined;
- const payload_ty = ty.optionalChild(&buf);
+ const payload_ty = ty.optionalChild(mod);
// In case of querying the ABI alignment of this optional, we will ask
// for hasRuntimeBits() of the payload type, so we need "requires comptime"
// to be known already before this function returns.
@@ -30590,37 +33168,37 @@ pub fn resolveTypeLayout(sema: *Sema, ty: Type) CompileError!void {
return sema.resolveTypeLayout(payload_ty);
},
.ErrorUnion => {
- const payload_ty = ty.errorUnionPayload();
+ const payload_ty = ty.errorUnionPayload(mod);
return sema.resolveTypeLayout(payload_ty);
},
.Fn => {
- const info = ty.fnInfo();
+ const info = mod.typeToFunc(ty).?;
if (info.is_generic) {
// Resolving of generic function types is deferred to when
// the function is instantiated.
return;
}
for (info.param_types) |param_ty| {
- try sema.resolveTypeLayout(param_ty);
+ try sema.resolveTypeLayout(param_ty.toType());
}
- try sema.resolveTypeLayout(info.return_type);
+ try sema.resolveTypeLayout(info.return_type.toType());
},
else => {},
}
}
fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
+ const mod = sema.mod;
const resolved_ty = try sema.resolveTypeFields(ty);
- if (resolved_ty.castTag(.@"struct")) |payload| {
- const struct_obj = payload.data;
+ if (mod.typeToStruct(resolved_ty)) |struct_obj| {
switch (struct_obj.status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
const msg = try Module.ErrorMsg.create(
sema.gpa,
- struct_obj.srcLoc(sema.mod),
+ struct_obj.srcLoc(mod),
"struct '{}' depends on itself",
- .{ty.fmt(sema.mod)},
+ .{ty.fmt(mod)},
);
return sema.failWithOwnedErrorMsg(msg);
},
@@ -30644,35 +33222,27 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
}
if (struct_obj.layout == .Packed) {
- try semaBackingIntType(sema.mod, struct_obj);
+ try semaBackingIntType(mod, struct_obj);
}
struct_obj.status = .have_layout;
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
- if (struct_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
+ if (struct_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) {
const msg = try Module.ErrorMsg.create(
sema.gpa,
- struct_obj.srcLoc(sema.mod),
+ struct_obj.srcLoc(mod),
"struct layout depends on it having runtime bits",
.{},
);
return sema.failWithOwnedErrorMsg(msg);
}
- if (struct_obj.layout == .Auto and sema.mod.backendSupportsFeature(.field_reordering)) {
- const optimized_order = if (struct_obj.owner_decl == sema.owner_decl_index)
- try sema.perm_arena.alloc(u32, struct_obj.fields.count())
- else blk: {
- const decl = sema.mod.declPtr(struct_obj.owner_decl);
- var decl_arena: std.heap.ArenaAllocator = undefined;
- const decl_arena_allocator = decl.value_arena.?.acquire(sema.mod.gpa, &decl_arena);
- defer decl.value_arena.?.release(&decl_arena);
- break :blk try decl_arena_allocator.alloc(u32, struct_obj.fields.count());
- };
+ if (struct_obj.layout == .Auto and mod.backendSupportsFeature(.field_reordering)) {
+ const optimized_order = try mod.tmp_hack_arena.allocator().alloc(u32, struct_obj.fields.count());
for (struct_obj.fields.values(), 0..) |field, i| {
- optimized_order[i] = if (field.ty.hasRuntimeBits())
+ optimized_order[i] = if (try sema.typeHasRuntimeBits(field.ty))
@intCast(u32, i)
else
Module.Struct.omitted_field;
@@ -30683,14 +33253,14 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
sema: *Sema,
fn lessThan(ctx: @This(), a: u32, b: u32) bool {
+ const m = ctx.sema.mod;
if (a == Module.Struct.omitted_field) return false;
if (b == Module.Struct.omitted_field) return true;
- const target = ctx.sema.mod.getTarget();
- return ctx.struct_obj.fields.values()[a].ty.abiAlignment(target) >
- ctx.struct_obj.fields.values()[b].ty.abiAlignment(target);
+ return ctx.struct_obj.fields.values()[a].ty.abiAlignment(m) >
+ ctx.struct_obj.fields.values()[b].ty.abiAlignment(m);
}
};
- std.sort.sort(u32, optimized_order, AlignSortContext{
+ mem.sort(u32, optimized_order, AlignSortContext{
.struct_obj = struct_obj,
.sema = sema,
}, AlignSortContext.lessThan);
@@ -30702,20 +33272,16 @@ fn resolveStructLayout(sema: *Sema, ty: Type) CompileError!void {
fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
const gpa = mod.gpa;
- const target = mod.getTarget();
var fields_bit_sum: u64 = 0;
for (struct_obj.fields.values()) |field| {
- fields_bit_sum += field.ty.bitSize(target);
+ fields_bit_sum += field.ty.bitSize(mod);
}
const decl_index = struct_obj.owner_decl;
const decl = mod.declPtr(decl_index);
- var decl_arena: std.heap.ArenaAllocator = undefined;
- const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
- defer decl.value_arena.?.release(&decl_arena);
- const zir = struct_obj.namespace.file_scope.zir;
+ const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
assert(extended.opcode == .struct_decl);
const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
@@ -30732,28 +33298,33 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
+ var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
+ defer comptime_mutable_decls.deinit();
+
var sema: Sema = .{
.mod = mod,
.gpa = gpa,
.arena = analysis_arena.allocator(),
- .perm_arena = decl_arena_allocator,
.code = zir,
.owner_decl = decl,
.owner_decl_index = decl_index,
.func = null,
+ .func_index = .none,
.fn_ret_ty = Type.void,
.owner_func = null,
+ .owner_func_index = .none,
+ .comptime_mutable_decls = &comptime_mutable_decls,
};
defer sema.deinit();
- var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
defer wip_captures.deinit();
var block: Block = .{
.parent = null,
.sema = &sema,
.src_decl = decl_index,
- .namespace = &struct_obj.namespace,
+ .namespace = struct_obj.namespace,
.wip_capture_scope = wip_captures.scope,
.instructions = .{},
.inlining = null,
@@ -30777,21 +33348,27 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
};
try sema.checkBackingIntType(&block, backing_int_src, backing_int_ty, fields_bit_sum);
- struct_obj.backing_int_ty = try backing_int_ty.copy(decl_arena_allocator);
+ struct_obj.backing_int_ty = backing_int_ty;
try wip_captures.finalize();
+ for (comptime_mutable_decls.items) |ct_decl_index| {
+ const ct_decl = mod.declPtr(ct_decl_index);
+ try ct_decl.intern(mod);
+ }
} else {
if (fields_bit_sum > std.math.maxInt(u16)) {
var sema: Sema = .{
.mod = mod,
.gpa = gpa,
.arena = undefined,
- .perm_arena = decl_arena_allocator,
.code = zir,
.owner_decl = decl,
.owner_decl_index = decl_index,
.func = null,
+ .func_index = .none,
.fn_ret_ty = Type.void,
.owner_func = null,
+ .owner_func_index = .none,
+ .comptime_mutable_decls = undefined,
};
defer sema.deinit();
@@ -30799,7 +33376,7 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
.parent = null,
.sema = &sema,
.src_decl = decl_index,
- .namespace = &struct_obj.namespace,
+ .namespace = struct_obj.namespace,
.wip_capture_scope = undefined,
.instructions = .{},
.inlining = null,
@@ -30807,56 +33384,65 @@ fn semaBackingIntType(mod: *Module, struct_obj: *Module.Struct) CompileError!voi
};
return sema.fail(&block, LazySrcLoc.nodeOffset(0), "size of packed struct '{d}' exceeds maximum bit width of 65535", .{fields_bit_sum});
}
- var buf: Type.Payload.Bits = .{
- .base = .{ .tag = .int_unsigned },
- .data = @intCast(u16, fields_bit_sum),
- };
- struct_obj.backing_int_ty = try Type.initPayload(&buf.base).copy(decl_arena_allocator);
+ struct_obj.backing_int_ty = try mod.intType(.unsigned, @intCast(u16, fields_bit_sum));
}
}
fn checkBackingIntType(sema: *Sema, block: *Block, src: LazySrcLoc, backing_int_ty: Type, fields_bit_sum: u64) CompileError!void {
- const target = sema.mod.getTarget();
+ const mod = sema.mod;
- if (!backing_int_ty.isInt()) {
+ if (!backing_int_ty.isInt(mod)) {
return sema.fail(block, src, "expected backing integer type, found '{}'", .{backing_int_ty.fmt(sema.mod)});
}
- if (backing_int_ty.bitSize(target) != fields_bit_sum) {
+ if (backing_int_ty.bitSize(mod) != fields_bit_sum) {
return sema.fail(
block,
src,
"backing integer type '{}' has bit size {} but the struct fields have a total bit size of {}",
- .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(target), fields_bit_sum },
+ .{ backing_int_ty.fmt(sema.mod), backing_int_ty.bitSize(mod), fields_bit_sum },
);
}
}
-fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, array_ty: Type) !void {
- if (!array_ty.isIndexable()) {
+fn checkIndexable(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+ const mod = sema.mod;
+ if (!ty.isIndexable(mod)) {
const msg = msg: {
- const msg = try sema.errMsg(
- block,
- src,
- "type '{}' does not support indexing",
- .{array_ty.fmt(sema.mod)},
- );
+ const msg = try sema.errMsg(block, src, "type '{}' does not support indexing", .{ty.fmt(sema.mod)});
errdefer msg.destroy(sema.gpa);
- try sema.errNote(
- block,
- src,
- msg,
- "for loop operand must be an array, slice, tuple, or vector",
- .{},
- );
+ try sema.errNote(block, src, msg, "operand must be an array, slice, tuple, or vector", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
}
+fn checkMemOperand(sema: *Sema, block: *Block, src: LazySrcLoc, ty: Type) !void {
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Pointer) {
+ switch (ty.ptrSize(mod)) {
+ .Slice, .Many, .C => return,
+ .One => {
+ const elem_ty = ty.childType(mod);
+ if (elem_ty.zigTypeTag(mod) == .Array) return;
+ // TODO https://github.com/ziglang/zig/issues/15479
+ // if (elem_ty.isTuple()) return;
+ },
+ }
+ }
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "type '{}' is not an indexable pointer", .{ty.fmt(sema.mod)});
+ errdefer msg.destroy(sema.gpa);
+ try sema.errNote(block, src, msg, "operand must be a slice, a many pointer or a pointer to an array", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+}
+
fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
+ const mod = sema.mod;
const resolved_ty = try sema.resolveTypeFields(ty);
- const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(resolved_ty).?;
switch (union_obj.status) {
.none, .have_field_types => {},
.field_types_wip, .layout_wip => {
@@ -30889,7 +33475,7 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
union_obj.status = .have_layout;
_ = try sema.resolveTypeRequiresComptime(resolved_ty);
- if (union_obj.assumed_runtime_bits and !resolved_ty.hasRuntimeBits()) {
+ if (union_obj.assumed_runtime_bits and !(try sema.typeHasRuntimeBits(resolved_ty))) {
const msg = try Module.ErrorMsg.create(
sema.gpa,
union_obj.srcLoc(sema.mod),
@@ -30904,190 +33490,154 @@ fn resolveUnionLayout(sema: *Sema, ty: Type) CompileError!void {
// for hasRuntimeBits() of each field, so we need "requires comptime"
// to be known already before this function returns.
pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
- return switch (ty.tag()) {
- .u1,
- .u8,
- .i8,
- .u16,
- .i16,
- .u29,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .anyopaque,
- .bool,
- .void,
- .anyerror,
- .noreturn,
- .@"anyframe",
- .null,
- .undefined,
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .modifier,
- .prefetch_options,
- .export_options,
- .extern_options,
- .manyptr_u8,
- .manyptr_const_u8,
- .manyptr_const_u8_sentinel_0,
- .const_slice_u8,
- .const_slice_u8_sentinel_0,
- .anyerror_void_error_union,
- .empty_struct_literal,
- .empty_struct,
- .error_set,
- .error_set_single,
- .error_set_inferred,
- .error_set_merged,
- .@"opaque",
- .generic_poison,
- .array_u8,
- .array_u8_sentinel_0,
- .int_signed,
- .int_unsigned,
- .enum_simple,
- => false,
-
- .single_const_pointer_to_comptime_int,
- .type,
- .comptime_int,
- .comptime_float,
- .enum_literal,
- .type_info,
- // These are function bodies, not function pointers.
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- => true,
-
- .var_args_param => unreachable,
- .inferred_alloc_mut => unreachable,
- .inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
-
- .array,
- .array_sentinel,
- .vector,
- => return sema.resolveTypeRequiresComptime(ty.childType()),
-
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- => {
- const child_ty = ty.childType();
- if (child_ty.zigTypeTag() == .Fn) {
- return child_ty.fnInfo().is_generic;
- } else {
- return sema.resolveTypeRequiresComptime(child_ty);
- }
- },
-
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- => {
- var buf: Type.Payload.ElemType = undefined;
- return sema.resolveTypeRequiresComptime(ty.optionalChild(&buf));
- },
+ const mod = sema.mod;
- .tuple, .anon_struct => {
- const tuple = ty.tupleFields();
- for (tuple.types, 0..) |field_ty, i| {
- const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
- if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty)) {
- return true;
+ return switch (ty.toIntern()) {
+ .empty_struct_type => false,
+ else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .int_type => false,
+ .ptr_type => |ptr_type| {
+ const child_ty = ptr_type.child.toType();
+ if (child_ty.zigTypeTag(mod) == .Fn) {
+ return mod.typeToFunc(child_ty).?.is_generic;
+ } else {
+ return sema.resolveTypeRequiresComptime(child_ty);
}
- }
- return false;
- },
+ },
+ .anyframe_type => |child| {
+ if (child == .none) return false;
+ return sema.resolveTypeRequiresComptime(child.toType());
+ },
+ .array_type => |array_type| return sema.resolveTypeRequiresComptime(array_type.child.toType()),
+ .vector_type => |vector_type| return sema.resolveTypeRequiresComptime(vector_type.child.toType()),
+ .opt_type => |child| return sema.resolveTypeRequiresComptime(child.toType()),
+ .error_union_type => |error_union_type| return sema.resolveTypeRequiresComptime(error_union_type.payload_type.toType()),
+ .error_set_type, .inferred_error_set_type => false,
+
+ .func_type => true,
+
+ .simple_type => |t| switch (t) {
+ .f16,
+ .f32,
+ .f64,
+ .f80,
+ .f128,
+ .usize,
+ .isize,
+ .c_char,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .anyopaque,
+ .bool,
+ .void,
+ .anyerror,
+ .noreturn,
+ .generic_poison,
+ .atomic_order,
+ .atomic_rmw_op,
+ .calling_convention,
+ .address_space,
+ .float_mode,
+ .reduce_op,
+ .call_modifier,
+ .prefetch_options,
+ .export_options,
+ .extern_options,
+ => false,
+
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .null,
+ .undefined,
+ .enum_literal,
+ .type_info,
+ => true,
+ },
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
+ switch (struct_obj.requires_comptime) {
+ .no, .wip => return false,
+ .yes => return true,
+ .unknown => {
+ var requires_comptime = false;
+ struct_obj.requires_comptime = .wip;
+ for (struct_obj.fields.values()) |field| {
+ if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
+ }
+ if (requires_comptime) {
+ struct_obj.requires_comptime = .yes;
+ } else {
+ struct_obj.requires_comptime = .no;
+ }
+ return requires_comptime;
+ },
+ }
+ },
- .@"struct" => {
- const struct_obj = ty.castTag(.@"struct").?.data;
- switch (struct_obj.requires_comptime) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- var requires_comptime = false;
- struct_obj.requires_comptime = .wip;
- for (struct_obj.fields.values()) |field| {
- if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
- }
- if (requires_comptime) {
- struct_obj.requires_comptime = .yes;
- } else {
- struct_obj.requires_comptime = .no;
+ .anon_struct_type => |tuple| {
+ for (tuple.types, tuple.values) |field_ty, field_val| {
+ const have_comptime_val = field_val != .none;
+ if (!have_comptime_val and try sema.resolveTypeRequiresComptime(field_ty.toType())) {
+ return true;
}
- return requires_comptime;
- },
- }
- },
+ }
+ return false;
+ },
- .@"union", .union_safety_tagged, .union_tagged => {
- const union_obj = ty.cast(Type.Payload.Union).?.data;
- switch (union_obj.requires_comptime) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- var requires_comptime = false;
- union_obj.requires_comptime = .wip;
- for (union_obj.fields.values()) |field| {
- if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
- }
- if (requires_comptime) {
- union_obj.requires_comptime = .yes;
- } else {
- union_obj.requires_comptime = .no;
- }
- return requires_comptime;
- },
- }
- },
+ .union_type => |union_type| {
+ const union_obj = mod.unionPtr(union_type.index);
+ switch (union_obj.requires_comptime) {
+ .no, .wip => return false,
+ .yes => return true,
+ .unknown => {
+ var requires_comptime = false;
+ union_obj.requires_comptime = .wip;
+ for (union_obj.fields.values()) |field| {
+ if (try sema.resolveTypeRequiresComptime(field.ty)) requires_comptime = true;
+ }
+ if (requires_comptime) {
+ union_obj.requires_comptime = .yes;
+ } else {
+ union_obj.requires_comptime = .no;
+ }
+ return requires_comptime;
+ },
+ }
+ },
- .error_union => return sema.resolveTypeRequiresComptime(ty.errorUnionPayload()),
- .anyframe_T => {
- const child_ty = ty.castTag(.anyframe_T).?.data;
- return sema.resolveTypeRequiresComptime(child_ty);
- },
- .enum_numbered => {
- const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
- return sema.resolveTypeRequiresComptime(tag_ty);
- },
- .enum_full, .enum_nonexhaustive => {
- const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
- return sema.resolveTypeRequiresComptime(tag_ty);
+ .opaque_type => false,
+
+ .enum_type => |enum_type| try sema.resolveTypeRequiresComptime(enum_type.tag_ty.toType()),
+
+ // values, not types
+ .undef,
+ .runtime_value,
+ .simple_value,
+ .variable,
+ .extern_func,
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .empty_enum_value,
+ .float,
+ .ptr,
+ .opt,
+ .aggregate,
+ .un,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
},
};
}
@@ -31095,40 +33645,38 @@ pub fn resolveTypeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
/// Returns `error.AnalysisFail` if any of the types (recursively) failed to
/// be resolved.
pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void {
- switch (ty.zigTypeTag()) {
+ const mod = sema.mod;
+ switch (ty.zigTypeTag(mod)) {
.Pointer => {
- const child_ty = try sema.resolveTypeFields(ty.childType());
+ const child_ty = try sema.resolveTypeFields(ty.childType(mod));
return sema.resolveTypeFully(child_ty);
},
- .Struct => switch (ty.tag()) {
- .@"struct" => return sema.resolveStructFully(ty),
- .tuple, .anon_struct => {
- const tuple = ty.tupleFields();
-
+ .Struct => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .struct_type => return sema.resolveStructFully(ty),
+ .anon_struct_type => |tuple| {
for (tuple.types) |field_ty| {
- try sema.resolveTypeFully(field_ty);
+ try sema.resolveTypeFully(field_ty.toType());
}
},
else => {},
},
.Union => return sema.resolveUnionFully(ty),
- .Array => return sema.resolveTypeFully(ty.childType()),
+ .Array => return sema.resolveTypeFully(ty.childType(mod)),
.Optional => {
- var buf: Type.Payload.ElemType = undefined;
- return sema.resolveTypeFully(ty.optionalChild(&buf));
+ return sema.resolveTypeFully(ty.optionalChild(mod));
},
- .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload()),
+ .ErrorUnion => return sema.resolveTypeFully(ty.errorUnionPayload(mod)),
.Fn => {
- const info = ty.fnInfo();
+ const info = mod.typeToFunc(ty).?;
if (info.is_generic) {
// Resolving of generic function types is deferred to when
// the function is instantiated.
return;
}
for (info.param_types) |param_ty| {
- try sema.resolveTypeFully(param_ty);
+ try sema.resolveTypeFully(param_ty.toType());
}
- try sema.resolveTypeFully(info.return_type);
+ try sema.resolveTypeFully(info.return_type.toType());
},
else => {},
}
@@ -31137,9 +33685,9 @@ pub fn resolveTypeFully(sema: *Sema, ty: Type) CompileError!void {
fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
try sema.resolveStructLayout(ty);
+ const mod = sema.mod;
const resolved_ty = try sema.resolveTypeFields(ty);
- const payload = resolved_ty.castTag(.@"struct").?;
- const struct_obj = payload.data;
+ const struct_obj = mod.typeToStruct(resolved_ty).?;
switch (struct_obj.status) {
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
@@ -31167,8 +33715,9 @@ fn resolveStructFully(sema: *Sema, ty: Type) CompileError!void {
fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
try sema.resolveUnionLayout(ty);
+ const mod = sema.mod;
const resolved_ty = try sema.resolveTypeFields(ty);
- const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(resolved_ty).?;
switch (union_obj.status) {
.none, .have_field_types, .field_types_wip, .layout_wip, .have_layout => {},
.fully_resolved_wip, .fully_resolved => return,
@@ -31193,30 +33742,111 @@ fn resolveUnionFully(sema: *Sema, ty: Type) CompileError!void {
}
pub fn resolveTypeFields(sema: *Sema, ty: Type) CompileError!Type {
- switch (ty.tag()) {
- .@"struct" => {
- const struct_obj = ty.castTag(.@"struct").?.data;
- try sema.resolveTypeFieldsStruct(ty, struct_obj);
- return ty;
- },
- .@"union", .union_safety_tagged, .union_tagged => {
- const union_obj = ty.cast(Type.Payload.Union).?.data;
- try sema.resolveTypeFieldsUnion(ty, union_obj);
- return ty;
- },
- .type_info => return sema.getBuiltinType("Type"),
- .extern_options => return sema.getBuiltinType("ExternOptions"),
- .export_options => return sema.getBuiltinType("ExportOptions"),
- .atomic_order => return sema.getBuiltinType("AtomicOrder"),
- .atomic_rmw_op => return sema.getBuiltinType("AtomicRmwOp"),
- .calling_convention => return sema.getBuiltinType("CallingConvention"),
- .address_space => return sema.getBuiltinType("AddressSpace"),
- .float_mode => return sema.getBuiltinType("FloatMode"),
- .reduce_op => return sema.getBuiltinType("ReduceOp"),
- .modifier => return sema.getBuiltinType("CallModifier"),
- .prefetch_options => return sema.getBuiltinType("PrefetchOptions"),
+ const mod = sema.mod;
+
+ switch (ty.toIntern()) {
+ .var_args_param_type => unreachable,
+
+ .none => unreachable,
+
+ .u1_type,
+ .u8_type,
+ .i8_type,
+ .u16_type,
+ .i16_type,
+ .u29_type,
+ .u32_type,
+ .i32_type,
+ .u64_type,
+ .i64_type,
+ .u80_type,
+ .u128_type,
+ .i128_type,
+ .usize_type,
+ .isize_type,
+ .c_char_type,
+ .c_short_type,
+ .c_ushort_type,
+ .c_int_type,
+ .c_uint_type,
+ .c_long_type,
+ .c_ulong_type,
+ .c_longlong_type,
+ .c_ulonglong_type,
+ .c_longdouble_type,
+ .f16_type,
+ .f32_type,
+ .f64_type,
+ .f80_type,
+ .f128_type,
+ .anyopaque_type,
+ .bool_type,
+ .void_type,
+ .type_type,
+ .anyerror_type,
+ .comptime_int_type,
+ .comptime_float_type,
+ .noreturn_type,
+ .anyframe_type,
+ .null_type,
+ .undefined_type,
+ .enum_literal_type,
+ .manyptr_u8_type,
+ .manyptr_const_u8_type,
+ .manyptr_const_u8_sentinel_0_type,
+ .single_const_pointer_to_comptime_int_type,
+ .slice_const_u8_type,
+ .slice_const_u8_sentinel_0_type,
+ .anyerror_void_error_union_type,
+ .generic_poison_type,
+ .empty_struct_type,
+ => return ty,
+
+ .undef => unreachable,
+ .zero => unreachable,
+ .zero_usize => unreachable,
+ .zero_u8 => unreachable,
+ .one => unreachable,
+ .one_usize => unreachable,
+ .one_u8 => unreachable,
+ .four_u8 => unreachable,
+ .negative_one => unreachable,
+ .calling_convention_c => unreachable,
+ .calling_convention_inline => unreachable,
+ .void_value => unreachable,
+ .unreachable_value => unreachable,
+ .null_value => unreachable,
+ .bool_true => unreachable,
+ .bool_false => unreachable,
+ .empty_struct => unreachable,
+ .generic_poison => unreachable,
+
+ .type_info_type => return sema.getBuiltinType("Type"),
+ .extern_options_type => return sema.getBuiltinType("ExternOptions"),
+ .export_options_type => return sema.getBuiltinType("ExportOptions"),
+ .atomic_order_type => return sema.getBuiltinType("AtomicOrder"),
+ .atomic_rmw_op_type => return sema.getBuiltinType("AtomicRmwOp"),
+ .calling_convention_type => return sema.getBuiltinType("CallingConvention"),
+ .address_space_type => return sema.getBuiltinType("AddressSpace"),
+ .float_mode_type => return sema.getBuiltinType("FloatMode"),
+ .reduce_op_type => return sema.getBuiltinType("ReduceOp"),
+ .call_modifier_type => return sema.getBuiltinType("CallModifier"),
+ .prefetch_options_type => return sema.getBuiltinType("PrefetchOptions"),
+
+ _ => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return ty;
+ try sema.resolveTypeFieldsStruct(ty, struct_obj);
+ return ty;
+ },
+ .union_type => |union_type| {
+ const union_obj = mod.unionPtr(union_type.index);
+ try sema.resolveTypeFieldsUnion(ty, union_obj);
+ return ty;
+ },
- else => return ty,
+ else => return ty,
+ },
}
}
@@ -31303,29 +33933,43 @@ fn resolveInferredErrorSet(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- ies: *Module.Fn.InferredErrorSet,
+ ies_index: Module.Fn.InferredErrorSet.Index,
) CompileError!void {
+ const mod = sema.mod;
+ const ies = mod.inferredErrorSetPtr(ies_index);
+
if (ies.is_resolved) return;
- if (ies.func.state == .in_progress) {
+ const func = mod.funcPtr(ies.func);
+ if (func.state == .in_progress) {
return sema.fail(block, src, "unable to resolve inferred error set", .{});
}
// In order to ensure that all dependencies are properly added to the set, we
// need to ensure the function body is analyzed of the inferred error set.
// However, in the case of comptime/inline function calls with inferred error sets,
- // each call gets a new InferredErrorSet object, which points to the same
- // `*Module.Fn`. Not only is the function not relevant to the inferred error set
+ // each call gets a new InferredErrorSet object, which contains the same
+ // `Module.Fn.Index`. Not only is the function not relevant to the inferred error set
// in this case, it may be a generic function which would cause an assertion failure
// if we called `ensureFuncBodyAnalyzed` on it here.
- const ies_func_owner_decl = sema.mod.declPtr(ies.func.owner_decl);
- const ies_func_info = ies_func_owner_decl.ty.fnInfo();
+ const ies_func_owner_decl = mod.declPtr(func.owner_decl);
+ const ies_func_info = mod.typeToFunc(ies_func_owner_decl.ty).?;
// if ies declared by a inline function with generic return type, the return_type should be generic_poison,
// because inline function does not create a new declaration, and the ies has been filled with analyzeCall,
// so here we can simply skip this case.
- if (ies_func_info.return_type.tag() == .generic_poison) {
+ if (ies_func_info.return_type == .generic_poison_type) {
assert(ies_func_info.cc == .Inline);
- } else if (ies_func_info.return_type.errorUnionSet().castTag(.error_set_inferred).?.data == ies) {
+ } else if (mod.typeToInferredErrorSet(ies_func_info.return_type.toType().errorUnionSet(mod)).? == ies) {
+ if (ies_func_info.is_generic) {
+ const msg = msg: {
+ const msg = try sema.errMsg(block, src, "unable to resolve inferred error set of generic function", .{});
+ errdefer msg.destroy(sema.gpa);
+
+ try sema.mod.errNoteNonLazy(ies_func_owner_decl.srcLoc(mod), msg, "generic function declared here", .{});
+ break :msg msg;
+ };
+ return sema.failWithOwnedErrorMsg(msg);
+ }
// In this case we are dealing with the actual InferredErrorSet object that
// corresponds to the function, not one created to track an inline/comptime call.
try sema.ensureFuncBodyAnalyzed(ies.func);
@@ -31333,10 +33977,11 @@ fn resolveInferredErrorSet(
ies.is_resolved = true;
- for (ies.inferred_error_sets.keys()) |other_ies| {
- if (ies == other_ies) continue;
- try sema.resolveInferredErrorSet(block, src, other_ies);
+ for (ies.inferred_error_sets.keys()) |other_ies_index| {
+ if (ies_index == other_ies_index) continue;
+ try sema.resolveInferredErrorSet(block, src, other_ies_index);
+ const other_ies = mod.inferredErrorSetPtr(other_ies_index);
for (other_ies.errors.keys()) |key| {
try ies.errors.put(sema.gpa, key, {});
}
@@ -31351,15 +33996,17 @@ fn resolveInferredErrorSetTy(
src: LazySrcLoc,
ty: Type,
) CompileError!void {
- if (ty.castTag(.error_set_inferred)) |inferred| {
- try sema.resolveInferredErrorSet(block, src, inferred.data);
+ const mod = sema.mod;
+ if (mod.typeToInferredErrorSetIndex(ty).unwrap()) |ies_index| {
+ try sema.resolveInferredErrorSet(block, src, ies_index);
}
}
fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void {
const gpa = mod.gpa;
+ const ip = &mod.intern_pool;
const decl_index = struct_obj.owner_decl;
- const zir = struct_obj.namespace.file_scope.zir;
+ const zir = mod.namespacePtr(struct_obj.namespace).file_scope.zir;
const extended = zir.instructions.items(.data)[struct_obj.zir_index].extended;
assert(extended.opcode == .struct_decl);
const small = @bitCast(Zir.Inst.StructDecl.Small, extended.small);
@@ -31405,35 +34052,37 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
}
const decl = mod.declPtr(decl_index);
- var decl_arena: std.heap.ArenaAllocator = undefined;
- const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
- defer decl.value_arena.?.release(&decl_arena);
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
+ var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
+ defer comptime_mutable_decls.deinit();
+
var sema: Sema = .{
.mod = mod,
.gpa = gpa,
.arena = analysis_arena.allocator(),
- .perm_arena = decl_arena_allocator,
.code = zir,
.owner_decl = decl,
.owner_decl_index = decl_index,
.func = null,
+ .func_index = .none,
.fn_ret_ty = Type.void,
.owner_func = null,
+ .owner_func_index = .none,
+ .comptime_mutable_decls = &comptime_mutable_decls,
};
defer sema.deinit();
- var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
defer wip_captures.deinit();
var block_scope: Block = .{
.parent = null,
.sema = &sema,
.src_decl = decl_index,
- .namespace = &struct_obj.namespace,
+ .namespace = struct_obj.namespace,
.wip_capture_scope = wip_captures.scope,
.instructions = .{},
.inlining = null,
@@ -31445,13 +34094,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
}
struct_obj.fields = .{};
- try struct_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
+ try struct_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
const Field = struct {
type_body_len: u32 = 0,
align_body_len: u32 = 0,
init_body_len: u32 = 0,
- type_ref: Air.Inst.Ref = .none,
+ type_ref: Zir.Inst.Ref = .none,
};
const fields = try sema.arena.alloc(Field, fields_len);
var any_inits = false;
@@ -31496,30 +34145,30 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
extra_index += 1;
// This string needs to outlive the ZIR code.
- const field_name = if (field_name_zir) |some|
- try decl_arena_allocator.dupe(u8, some)
+ const field_name = try ip.getOrPutString(gpa, if (field_name_zir) |s|
+ s
else
- try std.fmt.allocPrint(decl_arena_allocator, "{d}", .{field_i});
+ try std.fmt.allocPrint(sema.arena, "{d}", .{field_i}));
const gop = struct_obj.fields.getOrPutAssumeCapacity(field_name);
if (gop.found_existing) {
const msg = msg: {
- const field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
- const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{s}'", .{field_name});
+ const field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = field_i }).lazy;
+ const msg = try sema.errMsg(&block_scope, field_src, "duplicate struct field: '{}'", .{field_name.fmt(ip)});
errdefer msg.destroy(gpa);
const prev_field_index = struct_obj.fields.getIndex(field_name).?;
- const prev_field_src = struct_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index });
- try sema.mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
+ const prev_field_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{ .index = prev_field_index });
+ try mod.errNoteNonLazy(prev_field_src, msg, "other field here", .{});
try sema.errNote(&block_scope, src, msg, "struct declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
gop.value_ptr.* = .{
- .ty = Type.initTag(.noreturn),
+ .ty = Type.noreturn,
.abi_align = 0,
- .default_val = Value.initTag(.unreachable_value),
+ .default_val = .none,
.is_comptime = is_comptime,
.offset = undefined,
};
@@ -31545,7 +34194,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
if (zir_field.type_ref != .none) {
break :ty sema.resolveType(&block_scope, .unneeded, zir_field.type_ref) catch |err| switch (err) {
error.NeededSourceLocation => {
- const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
@@ -31561,7 +34210,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
const ty_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
break :ty sema.analyzeAsType(&block_scope, .unneeded, ty_ref) catch |err| switch (err) {
error.NeededSourceLocation => {
- const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
@@ -31571,16 +34220,16 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
else => |e| return e,
};
};
- if (field_ty.tag() == .generic_poison) {
+ if (field_ty.isGenericPoison()) {
return error.GenericPoison;
}
const field = &struct_obj.fields.values()[field_i];
- field.ty = try field_ty.copy(decl_arena_allocator);
+ field.ty = field_ty;
- if (field_ty.zigTypeTag() == .Opaque) {
+ if (field_ty.zigTypeTag(mod) == .Opaque) {
const msg = msg: {
- const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
@@ -31592,9 +34241,9 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (field_ty.zigTypeTag() == .NoReturn) {
+ if (field_ty.zigTypeTag(mod) == .NoReturn) {
const msg = msg: {
- const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
@@ -31608,11 +34257,11 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
}
if (struct_obj.layout == .Extern and !try sema.validateExternType(field.ty, .struct_field)) {
const msg = msg: {
- const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .type,
});
- const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
try sema.explainWhyTypeIsNotExtern(msg, ty_src, field.ty, .struct_field);
@@ -31621,13 +34270,13 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty))) {
+ } else if (struct_obj.layout == .Packed and !(validatePackedType(field.ty, mod))) {
const msg = msg: {
- const ty_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .type,
});
- const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed structs cannot contain fields of type '{}'", .{field.ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
try sema.explainWhyTypeIsNotPacked(msg, ty_src, field.ty);
@@ -31644,7 +34293,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
const align_ref = try sema.resolveBody(&block_scope, body, struct_obj.zir_index);
field.abi_align = sema.analyzeAsAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
error.NeededSourceLocation => {
- const align_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const align_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .alignment,
}).lazy;
@@ -31672,7 +34321,7 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
const field = &struct_obj.fields.values()[field_i];
const coerced = sema.coerce(&block_scope, field.ty, init, .unneeded) catch |err| switch (err) {
error.NeededSourceLocation => {
- const init_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .value,
}).lazy;
@@ -31682,17 +34331,21 @@ fn semaStructFields(mod: *Module, struct_obj: *Module.Struct) CompileError!void
else => |e| return e,
};
const default_val = (try sema.resolveMaybeUndefVal(coerced)) orelse {
- const init_src = struct_obj.fieldSrcLoc(sema.mod, .{
+ const init_src = mod.fieldSrcLoc(struct_obj.owner_decl, .{
.index = field_i,
.range = .value,
}).lazy;
return sema.failWithNeededComptime(&block_scope, init_src, "struct field default value must be comptime-known");
};
- field.default_val = try default_val.copy(decl_arena_allocator);
+ field.default_val = try default_val.intern(field.ty, mod);
}
}
}
try wip_captures.finalize();
+ for (comptime_mutable_decls.items) |ct_decl_index| {
+ const ct_decl = mod.declPtr(ct_decl_index);
+ try ct_decl.intern(mod);
+ }
struct_obj.have_field_inits = true;
}
@@ -31702,8 +34355,9 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
defer tracy.end();
const gpa = mod.gpa;
+ const ip = &mod.intern_pool;
const decl_index = union_obj.owner_decl;
- const zir = union_obj.namespace.file_scope.zir;
+ const zir = mod.namespacePtr(union_obj.namespace).file_scope.zir;
const extended = zir.instructions.items(.data)[union_obj.zir_index].extended;
assert(extended.opcode == .union_decl);
const small = @bitCast(Zir.Inst.UnionDecl.Small, extended.small);
@@ -31745,35 +34399,37 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
extra_index += body.len;
const decl = mod.declPtr(decl_index);
- var decl_arena: std.heap.ArenaAllocator = undefined;
- const decl_arena_allocator = decl.value_arena.?.acquire(gpa, &decl_arena);
- defer decl.value_arena.?.release(&decl_arena);
var analysis_arena = std.heap.ArenaAllocator.init(gpa);
defer analysis_arena.deinit();
+ var comptime_mutable_decls = std.ArrayList(Decl.Index).init(gpa);
+ defer comptime_mutable_decls.deinit();
+
var sema: Sema = .{
.mod = mod,
.gpa = gpa,
.arena = analysis_arena.allocator(),
- .perm_arena = decl_arena_allocator,
.code = zir,
.owner_decl = decl,
.owner_decl_index = decl_index,
.func = null,
+ .func_index = .none,
.fn_ret_ty = Type.void,
.owner_func = null,
+ .owner_func_index = .none,
+ .comptime_mutable_decls = &comptime_mutable_decls,
};
defer sema.deinit();
- var wip_captures = try WipCaptureScope.init(gpa, decl_arena_allocator, decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(gpa, decl.src_scope);
defer wip_captures.deinit();
var block_scope: Block = .{
.parent = null,
.sema = &sema,
.src_decl = decl_index,
- .namespace = &union_obj.namespace,
+ .namespace = union_obj.namespace,
.wip_capture_scope = wip_captures.scope,
.instructions = .{},
.inlining = null,
@@ -31789,66 +34445,61 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
}
try wip_captures.finalize();
+ for (comptime_mutable_decls.items) |ct_decl_index| {
+ const ct_decl = mod.declPtr(ct_decl_index);
+ try ct_decl.intern(mod);
+ }
- try union_obj.fields.ensureTotalCapacity(decl_arena_allocator, fields_len);
+ try union_obj.fields.ensureTotalCapacity(mod.tmp_hack_arena.allocator(), fields_len);
var int_tag_ty: Type = undefined;
- var enum_field_names: ?*Module.EnumNumbered.NameMap = null;
- var enum_value_map: ?*Module.EnumNumbered.ValueMap = null;
- var tag_ty_field_names: ?Module.EnumFull.NameMap = null;
+ var enum_field_names: []InternPool.NullTerminatedString = &.{};
+ var enum_field_vals: std.AutoArrayHashMapUnmanaged(InternPool.Index, void) = .{};
+ var explicit_tags_seen: []bool = &.{};
if (tag_type_ref != .none) {
const tag_ty_src: LazySrcLoc = .{ .node_offset_container_tag = src.node_offset.x };
const provided_ty = try sema.resolveType(&block_scope, tag_ty_src, tag_type_ref);
if (small.auto_enum_tag) {
// The provided type is an integer type and we must construct the enum tag type here.
int_tag_ty = provided_ty;
- if (int_tag_ty.zigTypeTag() != .Int and int_tag_ty.zigTypeTag() != .ComptimeInt) {
- return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(sema.mod)});
+ if (int_tag_ty.zigTypeTag(mod) != .Int and int_tag_ty.zigTypeTag(mod) != .ComptimeInt) {
+ return sema.fail(&block_scope, tag_ty_src, "expected integer tag type, found '{}'", .{int_tag_ty.fmt(mod)});
}
if (fields_len > 0) {
- var field_count_val: Value.Payload.U64 = .{
- .base = .{ .tag = .int_u64 },
- .data = fields_len - 1,
- };
- if (!(try sema.intFitsInType(Value.initPayload(&field_count_val.base), int_tag_ty, null))) {
+ const field_count_val = try mod.intValue(Type.comptime_int, fields_len - 1);
+ if (!(try sema.intFitsInType(field_count_val, int_tag_ty, null))) {
const msg = msg: {
const msg = try sema.errMsg(&block_scope, tag_ty_src, "specified integer tag type cannot represent every field", .{});
errdefer msg.destroy(sema.gpa);
try sema.errNote(&block_scope, tag_ty_src, msg, "type '{}' cannot fit values in range 0...{d}", .{
- int_tag_ty.fmt(sema.mod),
+ int_tag_ty.fmt(mod),
fields_len - 1,
});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
+ enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
+ try enum_field_vals.ensureTotalCapacity(sema.arena, fields_len);
}
- union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, fields_len, provided_ty, union_obj);
- const enum_obj = union_obj.tag_ty.castTag(.enum_numbered).?.data;
- enum_field_names = &enum_obj.fields;
- enum_value_map = &enum_obj.values;
} else {
// The provided type is the enum tag type.
- union_obj.tag_ty = try provided_ty.copy(decl_arena_allocator);
- if (union_obj.tag_ty.zigTypeTag() != .Enum) {
- return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(sema.mod)});
- }
+ union_obj.tag_ty = provided_ty;
+ const enum_type = switch (ip.indexToKey(union_obj.tag_ty.toIntern())) {
+ .enum_type => |x| x,
+ else => return sema.fail(&block_scope, tag_ty_src, "expected enum tag type, found '{}'", .{union_obj.tag_ty.fmt(mod)}),
+ };
// The fields of the union must match the enum exactly.
- // Store a copy of the enum field names so we can check for
- // missing or extraneous fields later.
- tag_ty_field_names = try union_obj.tag_ty.enumFields().clone(sema.arena);
+ // A flag per field is used to check for missing and extraneous fields.
+ explicit_tags_seen = try sema.arena.alloc(bool, enum_type.names.len);
+ @memset(explicit_tags_seen, false);
}
} else {
// If auto_enum_tag is false, this is an untagged union. However, for semantic analysis
// purposes, we still auto-generate an enum tag type the same way. That the union is
// untagged is represented by the Type tag (union vs union_tagged).
- union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, fields_len, union_obj);
- enum_field_names = &union_obj.tag_ty.castTag(.enum_simple).?.data.fields;
- }
-
- if (fields_len == 0) {
- return;
+ enum_field_names = try sema.arena.alloc(InternPool.NullTerminatedString, fields_len);
}
const bits_per_field = 4;
@@ -31892,17 +34543,17 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
break :blk align_ref;
} else .none;
- const tag_ref: Zir.Inst.Ref = if (has_tag) blk: {
+ const tag_ref: Air.Inst.Ref = if (has_tag) blk: {
const tag_ref = @intToEnum(Zir.Inst.Ref, zir.extra[extra_index]);
extra_index += 1;
break :blk try sema.resolveInst(tag_ref);
} else .none;
- if (enum_value_map) |map| {
- const copied_val = if (tag_ref != .none) blk: {
+ if (enum_field_vals.capacity() > 0) {
+ const enum_tag_val = if (tag_ref != .none) blk: {
const val = sema.semaUnionFieldVal(&block_scope, .unneeded, int_tag_ty, tag_ref) catch |err| switch (err) {
error.NeededSourceLocation => {
- const val_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const val_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .value,
}).lazy;
@@ -31913,27 +34564,22 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
};
last_tag_val = val;
- // This puts the memory into the union arena, not the enum arena, but
- // it is OK since they share the same lifetime.
- break :blk try val.copy(decl_arena_allocator);
+ break :blk val;
} else blk: {
const val = if (last_tag_val) |val|
- try sema.intAdd(val, Value.one, int_tag_ty)
+ try sema.intAdd(val, Value.one_comptime_int, int_tag_ty, undefined)
else
- Value.zero;
+ try mod.intValue(int_tag_ty, 0);
last_tag_val = val;
- break :blk try val.copy(decl_arena_allocator);
+ break :blk val;
};
- const gop = map.getOrPutAssumeCapacityContext(copied_val, .{
- .ty = int_tag_ty,
- .mod = mod,
- });
+ const gop = enum_field_vals.getOrPutAssumeCapacity(enum_tag_val.toIntern());
if (gop.found_existing) {
- const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
- const other_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = gop.index }).lazy;
+ const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
+ const other_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = gop.index }).lazy;
const msg = msg: {
- const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{copied_val.fmtValue(int_tag_ty, sema.mod)});
+ const msg = try sema.errMsg(&block_scope, field_src, "enum tag value {} already taken", .{enum_tag_val.fmtValue(int_tag_ty, mod)});
errdefer msg.destroy(gpa);
try sema.errNote(&block_scope, other_field_src, msg, "other occurrence here", .{});
break :msg msg;
@@ -31943,19 +34589,19 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
}
// This string needs to outlive the ZIR code.
- const field_name = try decl_arena_allocator.dupe(u8, field_name_zir);
- if (enum_field_names) |set| {
- set.putAssumeCapacity(field_name, {});
+ const field_name = try ip.getOrPutString(gpa, field_name_zir);
+ if (enum_field_names.len != 0) {
+ enum_field_names[field_i] = field_name;
}
const field_ty: Type = if (!has_type)
Type.void
else if (field_type_ref == .none)
- Type.initTag(.noreturn)
+ Type.noreturn
else
sema.resolveType(&block_scope, .unneeded, field_type_ref) catch |err| switch (err) {
error.NeededSourceLocation => {
- const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
@@ -31965,46 +34611,54 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
else => |e| return e,
};
- if (field_ty.tag() == .generic_poison) {
+ if (field_ty.isGenericPoison()) {
return error.GenericPoison;
}
const gop = union_obj.fields.getOrPutAssumeCapacity(field_name);
if (gop.found_existing) {
const msg = msg: {
- const field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = field_i }).lazy;
- const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{s}'", .{field_name});
+ const field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = field_i }).lazy;
+ const msg = try sema.errMsg(&block_scope, field_src, "duplicate union field: '{}'", .{
+ field_name.fmt(ip),
+ });
errdefer msg.destroy(gpa);
const prev_field_index = union_obj.fields.getIndex(field_name).?;
- const prev_field_src = union_obj.fieldSrcLoc(sema.mod, .{ .index = prev_field_index }).lazy;
- try sema.mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl), msg, "other field here", .{});
+ const prev_field_src = mod.fieldSrcLoc(union_obj.owner_decl, .{ .index = prev_field_index }).lazy;
+ try mod.errNoteNonLazy(prev_field_src.toSrcLoc(decl, mod), msg, "other field here", .{});
try sema.errNote(&block_scope, src, msg, "union declared here", .{});
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
- if (tag_ty_field_names) |*names| {
- const enum_has_field = names.orderedRemove(field_name);
- if (!enum_has_field) {
+ if (explicit_tags_seen.len > 0) {
+ const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
+ const enum_index = tag_info.nameIndex(ip, field_name) orelse {
const msg = msg: {
- const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
- const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{s}' in enum '{}'", .{ field_name, union_obj.tag_ty.fmt(sema.mod) });
+ const msg = try sema.errMsg(&block_scope, ty_src, "no field named '{}' in enum '{}'", .{
+ field_name.fmt(ip), union_obj.tag_ty.fmt(mod),
+ });
errdefer msg.destroy(sema.gpa);
try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- }
+ };
+ // 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;
}
- if (field_ty.zigTypeTag() == .Opaque) {
+ if (field_ty.zigTypeTag(mod) == .Opaque) {
const msg = msg: {
- const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .type,
}).lazy;
@@ -32018,11 +34672,11 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
}
if (union_obj.layout == .Extern and !try sema.validateExternType(field_ty, .union_field)) {
const msg = msg: {
- const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .type,
});
- const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(&block_scope, ty_src.lazy, "extern unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
try sema.explainWhyTypeIsNotExtern(msg, ty_src, field_ty, .union_field);
@@ -32031,13 +34685,13 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
- } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty))) {
+ } else if (union_obj.layout == .Packed and !(validatePackedType(field_ty, mod))) {
const msg = msg: {
- const ty_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const ty_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .type,
});
- const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(sema.mod)});
+ const msg = try sema.errMsg(&block_scope, ty_src.lazy, "packed unions cannot contain fields of type '{}'", .{field_ty.fmt(mod)});
errdefer msg.destroy(sema.gpa);
try sema.explainWhyTypeIsNotPacked(msg, ty_src, field_ty);
@@ -32049,14 +34703,14 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
}
gop.value_ptr.* = .{
- .ty = try field_ty.copy(decl_arena_allocator),
+ .ty = field_ty,
.abi_align = 0,
};
if (align_ref != .none) {
gop.value_ptr.abi_align = sema.resolveAlign(&block_scope, .unneeded, align_ref) catch |err| switch (err) {
error.NeededSourceLocation => {
- const align_src = union_obj.fieldSrcLoc(sema.mod, .{
+ const align_src = mod.fieldSrcLoc(union_obj.owner_decl, .{
.index = field_i,
.range = .alignment,
}).lazy;
@@ -32070,22 +34724,29 @@ fn semaUnionFields(mod: *Module, union_obj: *Module.Union) CompileError!void {
}
}
- if (tag_ty_field_names) |names| {
- if (names.count() > 0) {
+ if (explicit_tags_seen.len > 0) {
+ const tag_info = ip.indexToKey(union_obj.tag_ty.toIntern()).enum_type;
+ if (tag_info.names.len > fields_len) {
const msg = msg: {
const msg = try sema.errMsg(&block_scope, src, "enum field(s) missing in union", .{});
errdefer msg.destroy(sema.gpa);
const enum_ty = union_obj.tag_ty;
- for (names.keys()) |field_name| {
- const field_index = enum_ty.enumFieldIndex(field_name).?;
- try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{s}' missing, declared here", .{field_name});
+ for (tag_info.names, 0..) |field_name, field_index| {
+ if (explicit_tags_seen[field_index]) continue;
+ try sema.addFieldErrNote(enum_ty, field_index, msg, "field '{}' missing, declared here", .{
+ field_name.fmt(ip),
+ });
}
try sema.addDeclaredHereNote(msg, union_obj.tag_ty);
break :msg msg;
};
return sema.failWithOwnedErrorMsg(msg);
}
+ } else if (enum_field_vals.count() > 0) {
+ union_obj.tag_ty = try sema.generateUnionTagTypeNumbered(&block_scope, enum_field_names, enum_field_vals.keys(), union_obj);
+ } else {
+ union_obj.tag_ty = try sema.generateUnionTagTypeSimple(&block_scope, enum_field_names, union_obj);
}
}
@@ -32097,116 +34758,103 @@ fn semaUnionFieldVal(sema: *Sema, block: *Block, src: LazySrcLoc, int_tag_ty: Ty
fn generateUnionTagTypeNumbered(
sema: *Sema,
block: *Block,
- fields_len: u32,
- int_ty: Type,
+ enum_field_names: []const InternPool.NullTerminatedString,
+ enum_field_vals: []const InternPool.Index,
union_obj: *Module.Union,
) !Type {
const mod = sema.mod;
-
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
-
- const enum_obj = try new_decl_arena_allocator.create(Module.EnumNumbered);
- const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumNumbered);
- enum_ty_payload.* = .{
- .base = .{ .tag = .enum_numbered },
- .data = enum_obj,
- };
- const enum_ty = Type.initPayload(&enum_ty_payload.base);
- const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
+ const gpa = sema.gpa;
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);
errdefer mod.destroyDecl(new_decl_index);
- const name = name: {
- const fqn = try union_obj.getFullyQualifiedName(mod);
- defer sema.gpa.free(fqn);
- break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
- };
+ const fqn = try union_obj.getFullyQualifiedName(mod);
+ const name = try mod.intern_pool.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(&mod.intern_pool)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
- .ty = Type.type,
- .val = enum_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, name);
- sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
+ errdefer mod.abortAnonDecl(new_decl_index);
const new_decl = mod.declPtr(new_decl_index);
+ new_decl.name_fully_qualified = true;
new_decl.owns_tv = true;
new_decl.name_fully_qualified = true;
- errdefer mod.abortAnonDecl(new_decl_index);
- const copied_int_ty = try int_ty.copy(new_decl_arena_allocator);
- enum_obj.* = .{
- .owner_decl = new_decl_index,
- .tag_ty = copied_int_ty,
- .fields = .{},
- .values = .{},
- };
- // Here we pre-allocate the maps using the decl arena.
- try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
- try enum_obj.values.ensureTotalCapacityContext(new_decl_arena_allocator, fields_len, .{
- .ty = copied_int_ty,
- .mod = mod,
- });
- try new_decl.finalizeNewArena(&new_decl_arena);
- return enum_ty;
-}
+ const enum_ty = try mod.intern(.{ .enum_type = .{
+ .decl = new_decl_index,
+ .namespace = .none,
+ .tag_ty = if (enum_field_vals.len == 0)
+ (try mod.intType(.unsigned, 0)).toIntern()
+ else
+ mod.intern_pool.typeOf(enum_field_vals[0]),
+ .names = enum_field_names,
+ .values = enum_field_vals,
+ .tag_mode = .explicit,
+ } });
-fn generateUnionTagTypeSimple(sema: *Sema, block: *Block, fields_len: usize, maybe_union_obj: ?*Module.Union) !Type {
- const mod = sema.mod;
+ new_decl.ty = Type.type;
+ new_decl.val = enum_ty.toValue();
- var new_decl_arena = std.heap.ArenaAllocator.init(sema.gpa);
- errdefer new_decl_arena.deinit();
- const new_decl_arena_allocator = new_decl_arena.allocator();
+ try mod.finalizeAnonDecl(new_decl_index);
+ return enum_ty.toType();
+}
- const enum_obj = try new_decl_arena_allocator.create(Module.EnumSimple);
- const enum_ty_payload = try new_decl_arena_allocator.create(Type.Payload.EnumSimple);
- enum_ty_payload.* = .{
- .base = .{ .tag = .enum_simple },
- .data = enum_obj,
- };
- const enum_ty = Type.initPayload(&enum_ty_payload.base);
- const enum_val = try Value.Tag.ty.create(new_decl_arena_allocator, enum_ty);
+fn generateUnionTagTypeSimple(
+ sema: *Sema,
+ block: *Block,
+ enum_field_names: []const InternPool.NullTerminatedString,
+ maybe_union_obj: ?*Module.Union,
+) !Type {
+ const mod = sema.mod;
+ const gpa = sema.gpa;
const new_decl_index = new_decl_index: {
const union_obj = maybe_union_obj orelse {
break :new_decl_index try mod.createAnonymousDecl(block, .{
- .ty = Type.type,
- .val = enum_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
});
};
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);
errdefer mod.destroyDecl(new_decl_index);
- const name = name: {
- const fqn = try union_obj.getFullyQualifiedName(mod);
- defer sema.gpa.free(fqn);
- break :name try std.fmt.allocPrintZ(mod.gpa, "@typeInfo({s}).Union.tag_type.?", .{fqn});
- };
+ const fqn = try union_obj.getFullyQualifiedName(mod);
+ const name = try mod.intern_pool.getOrPutStringFmt(gpa, "@typeInfo({}).Union.tag_type.?", .{fqn.fmt(&mod.intern_pool)});
try mod.initNewAnonDecl(new_decl_index, src_decl.src_line, block.namespace, .{
- .ty = Type.type,
- .val = enum_val,
+ .ty = Type.noreturn,
+ .val = Value.@"unreachable",
}, name);
- sema.mod.declPtr(new_decl_index).name_fully_qualified = true;
+ mod.declPtr(new_decl_index).name_fully_qualified = true;
break :new_decl_index new_decl_index;
};
+ errdefer mod.abortAnonDecl(new_decl_index);
+
+ const enum_ty = try mod.intern(.{ .enum_type = .{
+ .decl = new_decl_index,
+ .namespace = .none,
+ .tag_ty = if (enum_field_names.len == 0)
+ (try mod.intType(.unsigned, 0)).toIntern()
+ else
+ (try mod.smallestUnsignedInt(enum_field_names.len - 1)).toIntern(),
+ .names = enum_field_names,
+ .values = &.{},
+ .tag_mode = .auto,
+ } });
const new_decl = mod.declPtr(new_decl_index);
new_decl.owns_tv = true;
- errdefer mod.abortAnonDecl(new_decl_index);
+ new_decl.ty = Type.type;
+ new_decl.val = enum_ty.toValue();
- enum_obj.* = .{
- .owner_decl = new_decl_index,
- .fields = .{},
- };
- // Here we pre-allocate the maps using the decl arena.
- try enum_obj.fields.ensureTotalCapacity(new_decl_arena_allocator, fields_len);
- try new_decl.finalizeNewArena(&new_decl_arena);
- return enum_ty;
+ try mod.finalizeAnonDecl(new_decl_index);
+ return enum_ty.toType();
}
fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
- var wip_captures = try WipCaptureScope.init(sema.gpa, sema.perm_arena, sema.owner_decl.src_scope);
+ const gpa = sema.gpa;
+
+ var wip_captures = try WipCaptureScope.init(gpa, sema.owner_decl.src_scope);
defer wip_captures.deinit();
var block: Block = .{
@@ -32220,19 +34868,20 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
.is_comptime = true,
};
defer {
- block.instructions.deinit(sema.gpa);
- block.params.deinit(sema.gpa);
+ block.instructions.deinit(gpa);
+ block.params.deinit(gpa);
}
const src = LazySrcLoc.nodeOffset(0);
const mod = sema.mod;
+ const ip = &mod.intern_pool;
const std_pkg = mod.main_pkg.table.get("std").?;
const std_file = (mod.importPkg(std_pkg) catch unreachable).file;
const opt_builtin_inst = (try sema.namespaceLookupRef(
&block,
src,
mod.declPtr(std_file.root_decl.unwrap().?).src_namespace,
- "builtin",
+ try ip.getOrPutString(gpa, "builtin"),
)) orelse @panic("lib/std.zig is corrupt and missing 'builtin'");
const builtin_inst = try sema.analyzeLoad(&block, src, opt_builtin_inst, src);
const builtin_ty = sema.analyzeAsType(&block, src, builtin_inst) catch |err| switch (err) {
@@ -32242,8 +34891,8 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
const opt_ty_decl = (try sema.namespaceLookup(
&block,
src,
- builtin_ty.getNamespace().?,
- name,
+ builtin_ty.getNamespaceIndex(mod).unwrap().?,
+ try ip.getOrPutString(gpa, name),
)) orelse std.debug.panic("lib/std/builtin.zig is corrupt and missing '{s}'", .{name});
return sema.analyzeDeclVal(&block, src, opt_ty_decl);
}
@@ -32251,7 +34900,7 @@ fn getBuiltin(sema: *Sema, name: []const u8) CompileError!Air.Inst.Ref {
fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
const ty_inst = try sema.getBuiltin(name);
- var wip_captures = try WipCaptureScope.init(sema.gpa, sema.perm_arena, sema.owner_decl.src_scope);
+ var wip_captures = try WipCaptureScope.init(sema.gpa, sema.owner_decl.src_scope);
defer wip_captures.deinit();
var block: Block = .{
@@ -32284,343 +34933,287 @@ fn getBuiltinType(sema: *Sema, name: []const u8) CompileError!Type {
/// that the types are already resolved.
/// TODO assert the return value matches `ty.onePossibleValue`
pub fn typeHasOnePossibleValue(sema: *Sema, ty: Type) CompileError!?Value {
- switch (ty.tag()) {
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .c_longdouble,
- .comptime_int,
- .comptime_float,
- .u1,
- .u8,
- .i8,
- .u16,
- .i16,
- .u29,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .bool,
- .type,
- .anyerror,
- .error_set_single,
- .error_set,
- .error_set_merged,
- .error_union,
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- .single_const_pointer_to_comptime_int,
- .array_sentinel,
- .array_u8_sentinel_0,
- .const_slice_u8,
- .const_slice_u8_sentinel_0,
- .const_slice,
- .mut_slice,
- .anyopaque,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- .enum_literal,
- .anyerror_void_error_union,
- .error_set_inferred,
- .@"opaque",
- .var_args_param,
- .manyptr_u8,
- .manyptr_const_u8,
- .manyptr_const_u8_sentinel_0,
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .modifier,
- .prefetch_options,
- .export_options,
- .extern_options,
- .type_info,
- .@"anyframe",
- .anyframe_T,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .pointer,
- .bound_fn,
- => return null,
+ const mod = sema.mod;
+ return switch (ty.toIntern()) {
+ .empty_struct_type => Value.empty_struct,
+ else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .int_type => |int_type| {
+ if (int_type.bits == 0) {
+ return try mod.intValue(ty, 0);
+ } else {
+ return null;
+ }
+ },
- .optional => {
- var buf: Type.Payload.ElemType = undefined;
- const child_ty = ty.optionalChild(&buf);
- if (child_ty.isNoReturn()) {
- return Value.null;
- } else {
+ .ptr_type,
+ .error_union_type,
+ .func_type,
+ .anyframe_type,
+ .error_set_type,
+ .inferred_error_set_type,
+ => null,
+
+ inline .array_type, .vector_type => |seq_type, seq_tag| {
+ const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none;
+ if (seq_type.len + @boolToInt(has_sentinel) == 0) return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = &.{} },
+ } })).toValue();
+
+ if (try sema.typeHasOnePossibleValue(seq_type.child.toType())) |opv| {
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .repeated_elem = opv.toIntern() },
+ } })).toValue();
+ }
return null;
- }
- },
+ },
+ .opt_type => |child| {
+ if (child == .noreturn_type) {
+ return try mod.nullValue(ty);
+ } else {
+ return null;
+ }
+ },
- .@"struct" => {
- const resolved_ty = try sema.resolveTypeFields(ty);
- const s = resolved_ty.castTag(.@"struct").?.data;
- for (s.fields.values(), 0..) |field, i| {
- if (field.is_comptime) continue;
- if (field.ty.eql(resolved_ty, sema.mod)) {
+ .simple_type => |t| switch (t) {
+ .f16,
+ .f32,
+ .f64,
+ .f80,
+ .f128,
+ .usize,
+ .isize,
+ .c_char,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .anyopaque,
+ .bool,
+ .type,
+ .anyerror,
+ .comptime_int,
+ .comptime_float,
+ .enum_literal,
+ .atomic_order,
+ .atomic_rmw_op,
+ .calling_convention,
+ .address_space,
+ .float_mode,
+ .reduce_op,
+ .call_modifier,
+ .prefetch_options,
+ .export_options,
+ .extern_options,
+ .type_info,
+ => null,
+
+ .void => Value.void,
+ .noreturn => Value.@"unreachable",
+ .null => Value.null,
+ .undefined => Value.undef,
+
+ .generic_poison => return error.GenericPoison,
+ },
+ .struct_type => |struct_type| {
+ const resolved_ty = try sema.resolveTypeFields(ty);
+ if (mod.structPtrUnwrap(struct_type.index)) |s| {
+ const field_vals = try sema.arena.alloc(InternPool.Index, s.fields.count());
+ for (field_vals, s.fields.values(), 0..) |*field_val, field, i| {
+ if (field.is_comptime) {
+ field_val.* = field.default_val;
+ continue;
+ }
+ if (field.ty.eql(resolved_ty, sema.mod)) {
+ const msg = try Module.ErrorMsg.create(
+ sema.gpa,
+ s.srcLoc(sema.mod),
+ "struct '{}' depends on itself",
+ .{ty.fmt(sema.mod)},
+ );
+ try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{});
+ return sema.failWithOwnedErrorMsg(msg);
+ }
+ if (try sema.typeHasOnePossibleValue(field.ty)) |field_opv| {
+ field_val.* = try field_opv.intern(field.ty, mod);
+ } else return null;
+ }
+
+ // In this case the struct has no runtime-known fields and
+ // therefore has one possible value.
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = field_vals },
+ } })).toValue();
+ }
+
+ // In this case the struct has no fields at all and
+ // therefore has one possible value.
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = &.{} },
+ } })).toValue();
+ },
+
+ .anon_struct_type => |tuple| {
+ for (tuple.values) |val| {
+ if (val == .none) return null;
+ }
+ // In this case the struct has all comptime-known fields and
+ // therefore has one possible value.
+ // TODO: write something like getCoercedInts to avoid needing to dupe
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = try sema.arena.dupe(InternPool.Index, tuple.values) },
+ } })).toValue();
+ },
+
+ .union_type => |union_type| {
+ const resolved_ty = try sema.resolveTypeFields(ty);
+ const union_obj = mod.unionPtr(union_type.index);
+ const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
+ return null;
+ const fields = union_obj.fields.values();
+ if (fields.len == 0) {
+ const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
+ return only.toValue();
+ }
+ const only_field = fields[0];
+ if (only_field.ty.eql(resolved_ty, sema.mod)) {
const msg = try Module.ErrorMsg.create(
sema.gpa,
- s.srcLoc(sema.mod),
- "struct '{}' depends on itself",
+ union_obj.srcLoc(sema.mod),
+ "union '{}' depends on itself",
.{ty.fmt(sema.mod)},
);
- try sema.addFieldErrNote(resolved_ty, i, msg, "while checking this field", .{});
+ try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
return sema.failWithOwnedErrorMsg(msg);
}
- if ((try sema.typeHasOnePossibleValue(field.ty)) == null) {
+ const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
return null;
- }
- }
- return Value.initTag(.empty_struct_value);
- },
-
- .tuple, .anon_struct => {
- const tuple = ty.tupleFields();
- for (tuple.values, 0..) |val, i| {
- const is_comptime = val.tag() != .unreachable_value;
- if (is_comptime) continue;
- if ((try sema.typeHasOnePossibleValue(tuple.types[i])) != null) continue;
- return null;
- }
- return Value.initTag(.empty_struct_value);
- },
+ const only = try mod.intern(.{ .un = .{
+ .ty = resolved_ty.toIntern(),
+ .tag = tag_val.toIntern(),
+ .val = val_val.toIntern(),
+ } });
+ return only.toValue();
+ },
+ .opaque_type => null,
+ .enum_type => |enum_type| switch (enum_type.tag_mode) {
+ .nonexhaustive => {
+ if (enum_type.tag_ty == .comptime_int_type) return null;
+
+ if (try sema.typeHasOnePossibleValue(enum_type.tag_ty.toType())) |int_opv| {
+ const only = try mod.intern(.{ .enum_tag = .{
+ .ty = ty.toIntern(),
+ .int = int_opv.toIntern(),
+ } });
+ return only.toValue();
+ }
- .enum_numbered => {
- const resolved_ty = try sema.resolveTypeFields(ty);
- const enum_obj = resolved_ty.castTag(.enum_numbered).?.data;
- // An explicit tag type is always provided for enum_numbered.
- if (enum_obj.tag_ty.hasRuntimeBits()) {
- return null;
- }
- if (enum_obj.fields.count() == 1) {
- if (enum_obj.values.count() == 0) {
- return Value.zero; // auto-numbered
- } else {
- return enum_obj.values.keys()[0];
- }
- } else {
- return null;
- }
- },
- .enum_full => {
- const resolved_ty = try sema.resolveTypeFields(ty);
- const enum_obj = resolved_ty.castTag(.enum_full).?.data;
- if (enum_obj.tag_ty.hasRuntimeBits()) {
- return null;
- }
- switch (enum_obj.fields.count()) {
- 0 => return Value.initTag(.unreachable_value),
- 1 => if (enum_obj.values.count() == 0) {
- return Value.zero; // auto-numbered
- } else {
- return enum_obj.values.keys()[0];
+ return null;
},
- else => return null,
- }
- },
- .enum_simple => {
- const resolved_ty = try sema.resolveTypeFields(ty);
- const enum_simple = resolved_ty.castTag(.enum_simple).?.data;
- switch (enum_simple.fields.count()) {
- 0 => return Value.initTag(.unreachable_value),
- 1 => return Value.zero,
- else => return null,
- }
- },
- .enum_nonexhaustive => {
- const tag_ty = ty.castTag(.enum_nonexhaustive).?.data.tag_ty;
- if (tag_ty.zigTypeTag() != .ComptimeInt and !(try sema.typeHasRuntimeBits(tag_ty))) {
- return Value.zero;
- } else {
- return null;
- }
- },
- .@"union", .union_safety_tagged, .union_tagged => {
- const resolved_ty = try sema.resolveTypeFields(ty);
- const union_obj = resolved_ty.cast(Type.Payload.Union).?.data;
- const tag_val = (try sema.typeHasOnePossibleValue(union_obj.tag_ty)) orelse
- return null;
- const fields = union_obj.fields.values();
- if (fields.len == 0) return Value.initTag(.unreachable_value);
- const only_field = fields[0];
- if (only_field.ty.eql(resolved_ty, sema.mod)) {
- const msg = try Module.ErrorMsg.create(
- sema.gpa,
- union_obj.srcLoc(sema.mod),
- "union '{}' depends on itself",
- .{ty.fmt(sema.mod)},
- );
- try sema.addFieldErrNote(resolved_ty, 0, msg, "while checking this field", .{});
- return sema.failWithOwnedErrorMsg(msg);
- }
- const val_val = (try sema.typeHasOnePossibleValue(only_field.ty)) orelse
- return null;
- // TODO make this not allocate. The function in `Type.onePossibleValue`
- // currently returns `empty_struct_value` and we should do that here too.
- return try Value.Tag.@"union".create(sema.arena, .{
- .tag = tag_val,
- .val = val_val,
- });
- },
+ .auto, .explicit => {
+ if (enum_type.tag_ty.toType().hasRuntimeBits(mod)) return null;
- .empty_struct, .empty_struct_literal => return Value.initTag(.empty_struct_value),
- .void => return Value.void,
- .noreturn => return Value.initTag(.unreachable_value),
- .null => return Value.null,
- .undefined => return Value.initTag(.undef),
+ switch (enum_type.names.len) {
+ 0 => {
+ const only = try mod.intern(.{ .empty_enum_value = ty.toIntern() });
+ return only.toValue();
+ },
+ 1 => return try mod.getCoerced((if (enum_type.values.len == 0)
+ try mod.intern(.{ .int = .{
+ .ty = enum_type.tag_ty,
+ .storage = .{ .u64 = 0 },
+ } })
+ else
+ enum_type.values[0]).toValue(), ty),
+ else => return null,
+ }
+ },
+ },
- .int_unsigned, .int_signed => {
- if (ty.cast(Type.Payload.Bits).?.data == 0) {
- return Value.zero;
- } else {
- return null;
- }
+ // values, not types
+ .undef,
+ .runtime_value,
+ .simple_value,
+ .variable,
+ .extern_func,
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .empty_enum_value,
+ .float,
+ .ptr,
+ .opt,
+ .aggregate,
+ .un,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
},
- .vector, .array, .array_u8 => {
- if (ty.arrayLen() == 0)
- return Value.initTag(.empty_array);
- if ((try sema.typeHasOnePossibleValue(ty.elemType())) != null) {
- return Value.initTag(.the_only_possible_value);
- }
- return null;
- },
-
- .inferred_alloc_const => unreachable,
- .inferred_alloc_mut => unreachable,
- .generic_poison => return error.GenericPoison,
- }
+ };
}
/// Returns the type of the AIR instruction.
fn typeOf(sema: *Sema, inst: Air.Inst.Ref) Type {
- return sema.getTmpAir().typeOf(inst);
+ return sema.getTmpAir().typeOf(inst, &sema.mod.intern_pool);
}
pub fn getTmpAir(sema: Sema) Air {
return .{
.instructions = sema.air_instructions.slice(),
.extra = sema.air_extra.items,
- .values = sema.air_values.items,
};
}
pub fn addType(sema: *Sema, ty: Type) !Air.Inst.Ref {
- switch (ty.tag()) {
- .u1 => return .u1_type,
- .u8 => return .u8_type,
- .i8 => return .i8_type,
- .u16 => return .u16_type,
- .u29 => return .u29_type,
- .i16 => return .i16_type,
- .u32 => return .u32_type,
- .i32 => return .i32_type,
- .u64 => return .u64_type,
- .i64 => return .i64_type,
- .u128 => return .u128_type,
- .i128 => return .i128_type,
- .usize => return .usize_type,
- .isize => return .isize_type,
- .c_short => return .c_short_type,
- .c_ushort => return .c_ushort_type,
- .c_int => return .c_int_type,
- .c_uint => return .c_uint_type,
- .c_long => return .c_long_type,
- .c_ulong => return .c_ulong_type,
- .c_longlong => return .c_longlong_type,
- .c_ulonglong => return .c_ulonglong_type,
- .c_longdouble => return .c_longdouble_type,
- .f16 => return .f16_type,
- .f32 => return .f32_type,
- .f64 => return .f64_type,
- .f80 => return .f80_type,
- .f128 => return .f128_type,
- .anyopaque => return .anyopaque_type,
- .bool => return .bool_type,
- .void => return .void_type,
- .type => return .type_type,
- .anyerror => return .anyerror_type,
- .comptime_int => return .comptime_int_type,
- .comptime_float => return .comptime_float_type,
- .noreturn => return .noreturn_type,
- .@"anyframe" => return .anyframe_type,
- .null => return .null_type,
- .undefined => return .undefined_type,
- .enum_literal => return .enum_literal_type,
- .atomic_order => return .atomic_order_type,
- .atomic_rmw_op => return .atomic_rmw_op_type,
- .calling_convention => return .calling_convention_type,
- .address_space => return .address_space_type,
- .float_mode => return .float_mode_type,
- .reduce_op => return .reduce_op_type,
- .modifier => return .modifier_type,
- .prefetch_options => return .prefetch_options_type,
- .export_options => return .export_options_type,
- .extern_options => return .extern_options_type,
- .type_info => return .type_info_type,
- .manyptr_u8 => return .manyptr_u8_type,
- .manyptr_const_u8 => return .manyptr_const_u8_type,
- .fn_noreturn_no_args => return .fn_noreturn_no_args_type,
- .fn_void_no_args => return .fn_void_no_args_type,
- .fn_naked_noreturn_no_args => return .fn_naked_noreturn_no_args_type,
- .fn_ccc_void_no_args => return .fn_ccc_void_no_args_type,
- .single_const_pointer_to_comptime_int => return .single_const_pointer_to_comptime_int_type,
- .const_slice_u8 => return .const_slice_u8_type,
- .anyerror_void_error_union => return .anyerror_void_error_union_type,
- .generic_poison => return .generic_poison_type,
- else => {},
- }
+ if (@enumToInt(ty.toIntern()) < Air.ref_start_index)
+ return @intToEnum(Air.Inst.Ref, @enumToInt(ty.toIntern()));
try sema.air_instructions.append(sema.gpa, .{
- .tag = .const_ty,
- .data = .{ .ty = ty },
+ .tag = .interned,
+ .data = .{ .interned = ty.toIntern() },
});
return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
}
fn addIntUnsigned(sema: *Sema, ty: Type, int: u64) CompileError!Air.Inst.Ref {
- return sema.addConstant(ty, try Value.Tag.int_u64.create(sema.arena, int));
+ const mod = sema.mod;
+ return sema.addConstant(ty, try mod.intValue(ty, int));
}
fn addConstUndef(sema: *Sema, ty: Type) CompileError!Air.Inst.Ref {
- return sema.addConstant(ty, Value.undef);
+ return sema.addConstant(ty, (try sema.mod.intern(.{ .undef = ty.toIntern() })).toValue());
}
pub fn addConstant(sema: *Sema, ty: Type, val: Value) SemaError!Air.Inst.Ref {
+ const mod = sema.mod;
const gpa = sema.gpa;
- const ty_inst = try sema.addType(ty);
- try sema.air_values.append(gpa, val);
+
+ // This assertion can be removed when the `ty` parameter is removed from
+ // this function thanks to the InternPool transition being complete.
+ if (std.debug.runtime_safety) {
+ const val_ty = mod.intern_pool.typeOf(val.toIntern());
+ if (ty.toIntern() != val_ty) {
+ std.debug.panic("addConstant type mismatch: '{}' vs '{}'\n", .{
+ ty.fmt(mod), val_ty.toType().fmt(mod),
+ });
+ }
+ }
+ if (@enumToInt(val.toIntern()) < Air.ref_start_index)
+ return @intToEnum(Air.Inst.Ref, @enumToInt(val.toIntern()));
try sema.air_instructions.append(gpa, .{
- .tag = .constant,
- .data = .{ .ty_pl = .{
- .ty = ty_inst,
- .payload = @intCast(u32, sema.air_values.items.len - 1),
- } },
+ .tag = .interned,
+ .data = .{ .interned = val.toIntern() },
});
return Air.indexToRef(@intCast(u32, sema.air_instructions.len - 1));
}
@@ -32639,7 +35232,8 @@ pub fn addExtraAssumeCapacity(sema: *Sema, extra: anytype) u32 {
u32 => @field(extra, field.name),
Air.Inst.Ref => @enumToInt(@field(extra, field.name)),
i32 => @bitCast(u32, @field(extra, field.name)),
- else => @compileError("bad field type"),
+ InternPool.Index => @enumToInt(@field(extra, field.name)),
+ else => @compileError("bad field type: " ++ @typeName(field.type)),
});
}
return result;
@@ -32685,21 +35279,25 @@ fn analyzeComptimeAlloc(
defer anon_decl.deinit();
const decl_index = try anon_decl.finish(
- try var_type.copy(anon_decl.arena()),
+ var_type,
// There will be stores before the first load, but they may be to sub-elements or
// sub-fields. So we need to initialize with undef to allow the mechanism to expand
// into fields/elements and have those overridden with stored values.
- Value.undef,
+ (try sema.mod.intern(.{ .undef = var_type.toIntern() })).toValue(),
alignment,
);
const decl = sema.mod.declPtr(decl_index);
decl.@"align" = alignment;
+ try sema.comptime_mutable_decls.append(decl_index);
try sema.mod.declareDeclDependency(sema.owner_decl_index, decl_index);
- return sema.addConstant(ptr_type, try Value.Tag.decl_ref_mut.create(sema.arena, .{
- .runtime_index = block.runtime_index,
- .decl_index = decl_index,
- }));
+ return sema.addConstant(ptr_type, (try sema.mod.intern(.{ .ptr = .{
+ .ty = ptr_type.toIntern(),
+ .addr = .{ .mut_decl = .{
+ .decl = decl_index,
+ .runtime_index = block.runtime_index,
+ } },
+ } })).toValue());
}
/// The places where a user can specify an address space attribute
@@ -32727,8 +35325,9 @@ pub fn analyzeAddressSpace(
zir_ref: Zir.Inst.Ref,
ctx: AddressSpaceContext,
) !std.builtin.AddressSpace {
+ const mod = sema.mod;
const addrspace_tv = try sema.resolveInstConst(block, src, zir_ref, "addresspace must be comptime-known");
- const address_space = addrspace_tv.val.toEnum(std.builtin.AddressSpace);
+ const address_space = mod.toEnum(std.builtin.AddressSpace, addrspace_tv.val);
const target = sema.mod.getTarget();
const arch = target.cpu.arch;
@@ -32771,8 +35370,9 @@ pub fn analyzeAddressSpace(
/// Asserts the value is a pointer and dereferences it.
/// Returns `null` if the pointer contents cannot be loaded at comptime.
fn pointerDeref(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, ptr_ty: Type) CompileError!?Value {
- const load_ty = ptr_ty.childType();
- const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty, true);
+ const mod = sema.mod;
+ const load_ty = ptr_ty.childType(mod);
+ const res = try sema.pointerDerefExtra(block, src, ptr_val, load_ty);
switch (res) {
.runtime_load => return null,
.val => |v| return v,
@@ -32798,8 +35398,9 @@ const DerefResult = union(enum) {
out_of_bounds: Type,
};
-fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type, want_mutable: bool) CompileError!DerefResult {
- const target = sema.mod.getTarget();
+fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value, load_ty: Type) CompileError!DerefResult {
+ const mod = sema.mod;
+ const target = mod.getTarget();
const deref = sema.beginComptimePtrLoad(block, src, ptr_val, load_ty) catch |err| switch (err) {
error.RuntimeLoad => return DerefResult{ .runtime_load = {} },
else => |e| return e,
@@ -32812,19 +35413,17 @@ fn pointerDerefExtra(sema: *Sema, block: *Block, src: LazySrcLoc, ptr_val: Value
if (coerce_in_mem_ok) {
// We have a Value that lines up in virtual memory exactly with what we want to load,
// and it is in-memory coercible to load_ty. It may be returned without modifications.
- if (deref.is_mutable and want_mutable) {
- // The decl whose value we are obtaining here may be overwritten with
- // a different value upon further semantic analysis, which would
- // invalidate this memory. So we must copy here.
- return DerefResult{ .val = try tv.val.copy(sema.arena) };
- }
- return DerefResult{ .val = tv.val };
+ // Move mutable decl values to the InternPool and assert other decls are already in
+ // the InternPool.
+ const uncoerced_val = if (deref.is_mutable) try tv.val.intern(tv.ty, mod) else tv.val.toIntern();
+ const coerced_val = try mod.getCoerced(uncoerced_val.toValue(), load_ty);
+ return .{ .val = coerced_val };
}
}
// The type is not in-memory coercible or the direct dereference failed, so it must
// be bitcast according to the pointer type we are performing the load through.
- if (!load_ty.hasWellDefinedLayout()) {
+ if (!load_ty.hasWellDefinedLayout(mod)) {
return DerefResult{ .needed_well_defined = load_ty };
}
@@ -32861,59 +35460,32 @@ fn usizeCast(sema: *Sema, block: *Block, src: LazySrcLoc, int: u64) CompileError
/// This can return `error.AnalysisFail` because it sometimes requires resolving whether
/// a type has zero bits, which can cause a "foo depends on itself" compile error.
/// This logic must be kept in sync with `Type.isPtrLikeOptional`.
-fn typePtrOrOptionalPtrTy(
- sema: *Sema,
- ty: Type,
- buf: *Type.Payload.ElemType,
-) !?Type {
- switch (ty.tag()) {
- .optional_single_const_pointer,
- .optional_single_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- => return ty.optionalChild(buf),
-
- .single_const_pointer_to_comptime_int,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .manyptr_u8,
- .manyptr_const_u8,
- .manyptr_const_u8_sentinel_0,
- => return ty,
-
- .pointer => switch (ty.ptrSize()) {
- .Slice => return null,
- .C => return ty.optionalChild(buf),
- else => return ty,
- },
-
- .inferred_alloc_const => unreachable,
- .inferred_alloc_mut => unreachable,
-
- .optional => {
- const child_type = ty.optionalChild(buf);
- if (child_type.zigTypeTag() != .Pointer) return null;
-
- const info = child_type.ptrInfo().data;
- switch (info.size) {
- .Slice, .C => return null,
+fn typePtrOrOptionalPtrTy(sema: *Sema, ty: Type) !?Type {
+ const mod = sema.mod;
+ return switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
+ .One, .Many, .C => ty,
+ .Slice => null,
+ },
+ .opt_type => |opt_child| switch (mod.intern_pool.indexToKey(opt_child)) {
+ .ptr_type => |ptr_type| switch (ptr_type.flags.size) {
+ .Slice, .C => null,
.Many, .One => {
- if (info.@"allowzero") return null;
+ if (ptr_type.flags.is_allowzero) return null;
// optionals of zero sized types behave like bools, not pointers
- if ((try sema.typeHasOnePossibleValue(child_type)) != null) {
+ const payload_ty = opt_child.toType();
+ if ((try sema.typeHasOnePossibleValue(payload_ty)) != null) {
return null;
}
- return child_type;
+ return payload_ty;
},
- }
+ },
+ else => null,
},
-
- else => return null,
- }
+ else => null,
+ };
}
/// `generic_poison` will return false.
@@ -32923,203 +35495,170 @@ fn typePtrOrOptionalPtrTy(
/// TODO merge these implementations together with the "advanced"/opt_sema pattern seen
/// elsewhere in value.zig
pub fn typeRequiresComptime(sema: *Sema, ty: Type) CompileError!bool {
- return switch (ty.tag()) {
- .u1,
- .u8,
- .i8,
- .u16,
- .i16,
- .u29,
- .u32,
- .i32,
- .u64,
- .i64,
- .u128,
- .i128,
- .usize,
- .isize,
- .c_char,
- .c_short,
- .c_ushort,
- .c_int,
- .c_uint,
- .c_long,
- .c_ulong,
- .c_longlong,
- .c_ulonglong,
- .c_longdouble,
- .f16,
- .f32,
- .f64,
- .f80,
- .f128,
- .anyopaque,
- .bool,
- .void,
- .anyerror,
- .noreturn,
- .@"anyframe",
- .null,
- .undefined,
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .modifier,
- .prefetch_options,
- .export_options,
- .extern_options,
- .manyptr_u8,
- .manyptr_const_u8,
- .manyptr_const_u8_sentinel_0,
- .const_slice_u8,
- .const_slice_u8_sentinel_0,
- .anyerror_void_error_union,
- .empty_struct_literal,
- .empty_struct,
- .error_set,
- .error_set_single,
- .error_set_inferred,
- .error_set_merged,
- .@"opaque",
- .generic_poison,
- .array_u8,
- .array_u8_sentinel_0,
- .int_signed,
- .int_unsigned,
- .enum_simple,
- => false,
-
- .single_const_pointer_to_comptime_int,
- .type,
- .comptime_int,
- .comptime_float,
- .enum_literal,
- .type_info,
- // These are function bodies, not function pointers.
- .fn_noreturn_no_args,
- .fn_void_no_args,
- .fn_naked_noreturn_no_args,
- .fn_ccc_void_no_args,
- .function,
- => true,
-
- .var_args_param => unreachable,
- .inferred_alloc_mut => unreachable,
- .inferred_alloc_const => unreachable,
- .bound_fn => unreachable,
-
- .array,
- .array_sentinel,
- .vector,
- => return sema.typeRequiresComptime(ty.childType()),
-
- .pointer,
- .single_const_pointer,
- .single_mut_pointer,
- .many_const_pointer,
- .many_mut_pointer,
- .c_const_pointer,
- .c_mut_pointer,
- .const_slice,
- .mut_slice,
- => {
- const child_ty = ty.childType();
- if (child_ty.zigTypeTag() == .Fn) {
- return child_ty.fnInfo().is_generic;
- } else {
- return sema.typeRequiresComptime(child_ty);
- }
- },
-
- .optional,
- .optional_single_mut_pointer,
- .optional_single_const_pointer,
- => {
- var buf: Type.Payload.ElemType = undefined;
- return sema.typeRequiresComptime(ty.optionalChild(&buf));
- },
-
- .tuple, .anon_struct => {
- const tuple = ty.tupleFields();
- for (tuple.types, 0..) |field_ty, i| {
- const have_comptime_val = tuple.values[i].tag() != .unreachable_value;
- if (!have_comptime_val and try sema.typeRequiresComptime(field_ty)) {
- return true;
+ const mod = sema.mod;
+ return switch (ty.toIntern()) {
+ .empty_struct_type => false,
+
+ else => switch (mod.intern_pool.indexToKey(ty.toIntern())) {
+ .int_type => return false,
+ .ptr_type => |ptr_type| {
+ const child_ty = ptr_type.child.toType();
+ if (child_ty.zigTypeTag(mod) == .Fn) {
+ return mod.typeToFunc(child_ty).?.is_generic;
+ } else {
+ return sema.typeRequiresComptime(child_ty);
}
- }
- return false;
- },
-
- .@"struct" => {
- const struct_obj = ty.castTag(.@"struct").?.data;
- switch (struct_obj.requires_comptime) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- if (struct_obj.status == .field_types_wip)
- return false;
+ },
+ .anyframe_type => |child| {
+ if (child == .none) return false;
+ return sema.typeRequiresComptime(child.toType());
+ },
+ .array_type => |array_type| return sema.typeRequiresComptime(array_type.child.toType()),
+ .vector_type => |vector_type| return sema.typeRequiresComptime(vector_type.child.toType()),
+ .opt_type => |child| return sema.typeRequiresComptime(child.toType()),
- try sema.resolveTypeFieldsStruct(ty, struct_obj);
+ .error_union_type => |error_union_type| {
+ return sema.typeRequiresComptime(error_union_type.payload_type.toType());
+ },
- struct_obj.requires_comptime = .wip;
- for (struct_obj.fields.values()) |field| {
- if (field.is_comptime) continue;
- if (try sema.typeRequiresComptime(field.ty)) {
- struct_obj.requires_comptime = .yes;
- return true;
+ .error_set_type, .inferred_error_set_type => false,
+
+ .func_type => true,
+
+ .simple_type => |t| return switch (t) {
+ .f16,
+ .f32,
+ .f64,
+ .f80,
+ .f128,
+ .usize,
+ .isize,
+ .c_char,
+ .c_short,
+ .c_ushort,
+ .c_int,
+ .c_uint,
+ .c_long,
+ .c_ulong,
+ .c_longlong,
+ .c_ulonglong,
+ .c_longdouble,
+ .anyopaque,
+ .bool,
+ .void,
+ .anyerror,
+ .noreturn,
+ .generic_poison,
+ .atomic_order,
+ .atomic_rmw_op,
+ .calling_convention,
+ .address_space,
+ .float_mode,
+ .reduce_op,
+ .call_modifier,
+ .prefetch_options,
+ .export_options,
+ .extern_options,
+ => false,
+
+ .type,
+ .comptime_int,
+ .comptime_float,
+ .null,
+ .undefined,
+ .enum_literal,
+ .type_info,
+ => true,
+ },
+ .struct_type => |struct_type| {
+ const struct_obj = mod.structPtrUnwrap(struct_type.index) orelse return false;
+ switch (struct_obj.requires_comptime) {
+ .no, .wip => return false,
+ .yes => return true,
+ .unknown => {
+ if (struct_obj.status == .field_types_wip)
+ return false;
+
+ try sema.resolveTypeFieldsStruct(ty, struct_obj);
+
+ struct_obj.requires_comptime = .wip;
+ for (struct_obj.fields.values()) |field| {
+ if (field.is_comptime) continue;
+ if (try sema.typeRequiresComptime(field.ty)) {
+ struct_obj.requires_comptime = .yes;
+ return true;
+ }
}
- }
- struct_obj.requires_comptime = .no;
- return false;
- },
- }
- },
-
- .@"union", .union_safety_tagged, .union_tagged => {
- const union_obj = ty.cast(Type.Payload.Union).?.data;
- switch (union_obj.requires_comptime) {
- .no, .wip => return false,
- .yes => return true,
- .unknown => {
- if (union_obj.status == .field_types_wip)
+ struct_obj.requires_comptime = .no;
return false;
+ },
+ }
+ },
+ .anon_struct_type => |tuple| {
+ for (tuple.types, tuple.values) |field_ty, val| {
+ const have_comptime_val = val != .none;
+ if (!have_comptime_val and try sema.typeRequiresComptime(field_ty.toType())) {
+ return true;
+ }
+ }
+ return false;
+ },
- try sema.resolveTypeFieldsUnion(ty, union_obj);
-
- union_obj.requires_comptime = .wip;
- for (union_obj.fields.values()) |field| {
- if (try sema.typeRequiresComptime(field.ty)) {
- union_obj.requires_comptime = .yes;
- return true;
+ .union_type => |union_type| {
+ const union_obj = mod.unionPtr(union_type.index);
+ switch (union_obj.requires_comptime) {
+ .no, .wip => return false,
+ .yes => return true,
+ .unknown => {
+ if (union_obj.status == .field_types_wip)
+ return false;
+
+ try sema.resolveTypeFieldsUnion(ty, union_obj);
+
+ union_obj.requires_comptime = .wip;
+ for (union_obj.fields.values()) |field| {
+ if (try sema.typeRequiresComptime(field.ty)) {
+ union_obj.requires_comptime = .yes;
+ return true;
+ }
}
- }
- union_obj.requires_comptime = .no;
- return false;
- },
- }
- },
+ union_obj.requires_comptime = .no;
+ return false;
+ },
+ }
+ },
- .error_union => return sema.typeRequiresComptime(ty.errorUnionPayload()),
- .anyframe_T => {
- const child_ty = ty.castTag(.anyframe_T).?.data;
- return sema.typeRequiresComptime(child_ty);
- },
- .enum_numbered => {
- const tag_ty = ty.castTag(.enum_numbered).?.data.tag_ty;
- return sema.typeRequiresComptime(tag_ty);
- },
- .enum_full, .enum_nonexhaustive => {
- const tag_ty = ty.cast(Type.Payload.EnumFull).?.data.tag_ty;
- return sema.typeRequiresComptime(tag_ty);
+ .opaque_type => false,
+ .enum_type => |enum_type| try sema.typeRequiresComptime(enum_type.tag_ty.toType()),
+
+ // values, not types
+ .undef,
+ .runtime_value,
+ .simple_value,
+ .variable,
+ .extern_func,
+ .func,
+ .int,
+ .err,
+ .error_union,
+ .enum_literal,
+ .enum_tag,
+ .empty_enum_value,
+ .float,
+ .ptr,
+ .opt,
+ .aggregate,
+ .un,
+ // memoization, not types
+ .memoized_call,
+ => unreachable,
},
};
}
pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
- return ty.hasRuntimeBitsAdvanced(false, .{ .sema = sema }) catch |err| switch (err) {
+ const mod = sema.mod;
+ return ty.hasRuntimeBitsAdvanced(mod, false, .{ .sema = sema }) catch |err| switch (err) {
error.NeedLazy => unreachable,
else => |e| return e,
};
@@ -33127,19 +35666,18 @@ pub fn typeHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
fn typeAbiSize(sema: *Sema, ty: Type) !u64 {
try sema.resolveTypeLayout(ty);
- const target = sema.mod.getTarget();
- return ty.abiSize(target);
+ return ty.abiSize(sema.mod);
}
fn typeAbiAlignment(sema: *Sema, ty: Type) CompileError!u32 {
- const target = sema.mod.getTarget();
- return (try ty.abiAlignmentAdvanced(target, .{ .sema = sema })).scalar;
+ return (try ty.abiAlignmentAdvanced(sema.mod, .{ .sema = sema })).scalar;
}
/// Not valid to call for packed unions.
/// Keep implementation in sync with `Module.Union.Field.normalAlignment`.
fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 {
- if (field.ty.zigTypeTag() == .NoReturn) {
+ const mod = sema.mod;
+ if (field.ty.zigTypeTag(mod) == .NoReturn) {
return @as(u32, 0);
} else if (field.abi_align == 0) {
return sema.typeAbiAlignment(field.ty);
@@ -33150,7 +35688,8 @@ fn unionFieldAlignment(sema: *Sema, field: Module.Union.Field) !u32 {
/// Synchronize logic with `Type.isFnOrHasRuntimeBits`.
pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
- const fn_info = ty.fnInfo();
+ const mod = sema.mod;
+ const fn_info = mod.typeToFunc(ty).?;
if (fn_info.is_generic) return false;
if (fn_info.is_var_args) return true;
switch (fn_info.cc) {
@@ -33158,7 +35697,7 @@ pub fn fnHasRuntimeBits(sema: *Sema, ty: Type) CompileError!bool {
.Inline => return false,
else => {},
}
- if (try sema.typeRequiresComptime(fn_info.return_type)) {
+ if (try sema.typeRequiresComptime(fn_info.return_type.toType())) {
return false;
}
return true;
@@ -33168,11 +35707,12 @@ fn unionFieldIndex(
sema: *Sema,
block: *Block,
unresolved_union_ty: Type,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_src: LazySrcLoc,
) !u32 {
+ const mod = sema.mod;
const union_ty = try sema.resolveTypeFields(unresolved_union_ty);
- const union_obj = union_ty.cast(Type.Payload.Union).?.data;
+ const union_obj = mod.typeToUnion(union_ty).?;
const field_index_usize = union_obj.fields.getIndex(field_name) orelse
return sema.failWithBadUnionFieldAccess(block, union_obj, field_src, field_name);
return @intCast(u32, field_index_usize);
@@ -33182,14 +35722,15 @@ fn structFieldIndex(
sema: *Sema,
block: *Block,
unresolved_struct_ty: Type,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_src: LazySrcLoc,
) !u32 {
+ const mod = sema.mod;
const struct_ty = try sema.resolveTypeFields(unresolved_struct_ty);
- if (struct_ty.isAnonStruct()) {
+ if (struct_ty.isAnonStruct(mod)) {
return sema.anonStructFieldIndex(block, struct_ty, field_name, field_src);
} else {
- const struct_obj = struct_ty.castTag(.@"struct").?.data;
+ const struct_obj = mod.typeToStruct(struct_ty).?;
const field_index_usize = struct_obj.fields.getIndex(field_name) orelse
return sema.failWithBadStructFieldAccess(block, struct_obj, field_src, field_name);
return @intCast(u32, field_index_usize);
@@ -33200,55 +35741,98 @@ fn anonStructFieldIndex(
sema: *Sema,
block: *Block,
struct_ty: Type,
- field_name: []const u8,
+ field_name: InternPool.NullTerminatedString,
field_src: LazySrcLoc,
) !u32 {
- const anon_struct = struct_ty.castTag(.anon_struct).?.data;
- for (anon_struct.names, 0..) |name, i| {
- if (mem.eql(u8, name, field_name)) {
- return @intCast(u32, i);
- }
+ const mod = sema.mod;
+ switch (mod.intern_pool.indexToKey(struct_ty.toIntern())) {
+ .anon_struct_type => |anon_struct_type| for (anon_struct_type.names, 0..) |name, i| {
+ if (name == field_name) return @intCast(u32, i);
+ },
+ .struct_type => |struct_type| if (mod.structPtrUnwrap(struct_type.index)) |struct_obj| {
+ for (struct_obj.fields.keys(), 0..) |name, i| {
+ if (name == field_name) {
+ return @intCast(u32, i);
+ }
+ }
+ },
+ else => unreachable,
}
- return sema.fail(block, field_src, "no field named '{s}' in anonymous struct '{}'", .{
- field_name, struct_ty.fmt(sema.mod),
+ return sema.fail(block, field_src, "no field named '{}' in anonymous struct '{}'", .{
+ field_name.fmt(&mod.intern_pool), struct_ty.fmt(sema.mod),
});
}
fn queueFullTypeResolution(sema: *Sema, ty: Type) !void {
- const inst_ref = try sema.addType(ty);
- try sema.types_to_resolve.append(sema.gpa, inst_ref);
+ try sema.types_to_resolve.put(sema.gpa, ty.toIntern(), {});
+}
+
+/// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting
+/// overflow_idx to the vector index the overflow was at (or 0 for a scalar).
+fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value {
+ var overflow: usize = undefined;
+ return sema.intAddInner(lhs, rhs, ty, &overflow) catch |err| switch (err) {
+ error.Overflow => {
+ const is_vec = ty.isVector(sema.mod);
+ overflow_idx.* = if (is_vec) overflow else 0;
+ const safe_ty = if (is_vec) try sema.mod.vectorType(.{
+ .len = ty.vectorLen(sema.mod),
+ .child = .comptime_int_type,
+ }) else Type.comptime_int;
+ return sema.intAddInner(lhs, rhs, safe_ty, undefined) catch |err1| switch (err1) {
+ error.Overflow => unreachable,
+ else => |e| return e,
+ };
+ },
+ else => |e| return e,
+ };
}
-fn intAdd(sema: *Sema, lhs: Value, rhs: Value, ty: Type) !Value {
- if (ty.zigTypeTag() == .Vector) {
- const result_data = try sema.arena.alloc(Value, ty.vectorLen());
+fn intAddInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize) !Value {
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Vector) {
+ const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
+ const scalar_ty = ty.scalarType(mod);
for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- scalar.* = try sema.intAddScalar(lhs_elem, rhs_elem);
+ const lhs_elem = try lhs.elemValue(mod, i);
+ const rhs_elem = try rhs.elemValue(mod, i);
+ const val = sema.intAddScalar(lhs_elem, rhs_elem, scalar_ty) catch |err| switch (err) {
+ error.Overflow => {
+ overflow_idx.* = i;
+ return error.Overflow;
+ },
+ else => |e| return e,
+ };
+ scalar.* = try val.intern(scalar_ty, mod);
}
- return Value.Tag.aggregate.create(sema.arena, result_data);
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue();
}
- return sema.intAddScalar(lhs, rhs);
+ return sema.intAddScalar(lhs, rhs, ty);
}
-fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value) !Value {
+fn intAddScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value {
+ const mod = sema.mod;
+ if (scalar_ty.toIntern() != .comptime_int_type) {
+ const res = try sema.intAddWithOverflowScalar(lhs, rhs, scalar_ty);
+ if (res.overflow_bit.compareAllWithZero(.neq, mod)) return error.Overflow;
+ return res.wrapped_result;
+ }
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const target = sema.mod.getTarget();
- const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema);
- const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema);
+ const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
+ const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
- std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
+ @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.add(lhs_bigint, rhs_bigint);
- return Value.fromBigInt(sema.arena, result_bigint.toConst());
+ return mod.intValue_big(scalar_ty, result_bigint.toConst());
}
/// Supports both floats and ints; handles undefined.
@@ -33258,55 +35842,87 @@ fn numberAddWrapScalar(
rhs: Value,
ty: Type,
) !Value {
- if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
+ const mod = sema.mod;
+ if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
- if (ty.zigTypeTag() == .ComptimeInt) {
- return sema.intAdd(lhs, rhs, ty);
+ if (ty.zigTypeTag(mod) == .ComptimeInt) {
+ return sema.intAdd(lhs, rhs, ty, undefined);
}
if (ty.isAnyFloat()) {
- return sema.floatAdd(lhs, rhs, ty);
+ return Value.floatAdd(lhs, rhs, ty, sema.arena, mod);
}
const overflow_result = try sema.intAddWithOverflow(lhs, rhs, ty);
return overflow_result.wrapped_result;
}
-fn intSub(
- sema: *Sema,
- lhs: Value,
- rhs: Value,
- ty: Type,
-) !Value {
- if (ty.zigTypeTag() == .Vector) {
- const result_data = try sema.arena.alloc(Value, ty.vectorLen());
+/// If the value overflowed the type, returns a comptime_int (or vector thereof) instead, setting
+/// overflow_idx to the vector index the overflow was at (or 0 for a scalar).
+fn intSub(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *?usize) !Value {
+ var overflow: usize = undefined;
+ return sema.intSubInner(lhs, rhs, ty, &overflow) catch |err| switch (err) {
+ error.Overflow => {
+ const is_vec = ty.isVector(sema.mod);
+ overflow_idx.* = if (is_vec) overflow else 0;
+ const safe_ty = if (is_vec) try sema.mod.vectorType(.{
+ .len = ty.vectorLen(sema.mod),
+ .child = .comptime_int_type,
+ }) else Type.comptime_int;
+ return sema.intSubInner(lhs, rhs, safe_ty, undefined) catch |err1| switch (err1) {
+ error.Overflow => unreachable,
+ else => |e| return e,
+ };
+ },
+ else => |e| return e,
+ };
+}
+
+fn intSubInner(sema: *Sema, lhs: Value, rhs: Value, ty: Type, overflow_idx: *usize) !Value {
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Vector) {
+ const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
+ const scalar_ty = ty.scalarType(mod);
for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- scalar.* = try sema.intSubScalar(lhs_elem, rhs_elem);
+ const lhs_elem = try lhs.elemValue(sema.mod, i);
+ const rhs_elem = try rhs.elemValue(sema.mod, i);
+ const val = sema.intSubScalar(lhs_elem, rhs_elem, scalar_ty) catch |err| switch (err) {
+ error.Overflow => {
+ overflow_idx.* = i;
+ return error.Overflow;
+ },
+ else => |e| return e,
+ };
+ scalar.* = try val.intern(scalar_ty, mod);
}
- return Value.Tag.aggregate.create(sema.arena, result_data);
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue();
}
- return sema.intSubScalar(lhs, rhs);
+ return sema.intSubScalar(lhs, rhs, ty);
}
-fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value) !Value {
+fn intSubScalar(sema: *Sema, lhs: Value, rhs: Value, scalar_ty: Type) !Value {
+ const mod = sema.mod;
+ if (scalar_ty.toIntern() != .comptime_int_type) {
+ const res = try sema.intSubWithOverflowScalar(lhs, rhs, scalar_ty);
+ if (res.overflow_bit.compareAllWithZero(.neq, mod)) return error.Overflow;
+ return res.wrapped_result;
+ }
// TODO is this a performance issue? maybe we should try the operation without
// resorting to BigInt first.
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const target = sema.mod.getTarget();
- const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema);
- const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema);
+ const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
+ const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
- std.math.max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
+ @max(lhs_bigint.limbs.len, rhs_bigint.limbs.len) + 1,
);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
result_bigint.sub(lhs_bigint, rhs_bigint);
- return Value.fromBigInt(sema.arena, result_bigint.toConst());
+ return mod.intValue_big(scalar_ty, result_bigint.toConst());
}
/// Supports both floats and ints; handles undefined.
@@ -33316,155 +35932,49 @@ fn numberSubWrapScalar(
rhs: Value,
ty: Type,
) !Value {
- if (lhs.isUndef() or rhs.isUndef()) return Value.initTag(.undef);
+ const mod = sema.mod;
+ if (lhs.isUndef(mod) or rhs.isUndef(mod)) return Value.undef;
- if (ty.zigTypeTag() == .ComptimeInt) {
- return sema.intSub(lhs, rhs, ty);
+ if (ty.zigTypeTag(mod) == .ComptimeInt) {
+ return sema.intSub(lhs, rhs, ty, undefined);
}
if (ty.isAnyFloat()) {
- return sema.floatSub(lhs, rhs, ty);
+ return Value.floatSub(lhs, rhs, ty, sema.arena, mod);
}
const overflow_result = try sema.intSubWithOverflow(lhs, rhs, ty);
return overflow_result.wrapped_result;
}
-fn floatAdd(
- sema: *Sema,
- lhs: Value,
- rhs: Value,
- float_type: Type,
-) !Value {
- if (float_type.zigTypeTag() == .Vector) {
- const result_data = try sema.arena.alloc(Value, float_type.vectorLen());
- for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- scalar.* = try sema.floatAddScalar(lhs_elem, rhs_elem, float_type.scalarType());
- }
- return Value.Tag.aggregate.create(sema.arena, result_data);
- }
- return sema.floatAddScalar(lhs, rhs, float_type);
-}
-
-fn floatAddScalar(
- sema: *Sema,
- lhs: Value,
- rhs: Value,
- float_type: Type,
-) !Value {
- const target = sema.mod.getTarget();
- switch (float_type.floatBits(target)) {
- 16 => {
- const lhs_val = lhs.toFloat(f16);
- const rhs_val = rhs.toFloat(f16);
- return Value.Tag.float_16.create(sema.arena, lhs_val + rhs_val);
- },
- 32 => {
- const lhs_val = lhs.toFloat(f32);
- const rhs_val = rhs.toFloat(f32);
- return Value.Tag.float_32.create(sema.arena, lhs_val + rhs_val);
- },
- 64 => {
- const lhs_val = lhs.toFloat(f64);
- const rhs_val = rhs.toFloat(f64);
- return Value.Tag.float_64.create(sema.arena, lhs_val + rhs_val);
- },
- 80 => {
- const lhs_val = lhs.toFloat(f80);
- const rhs_val = rhs.toFloat(f80);
- return Value.Tag.float_80.create(sema.arena, lhs_val + rhs_val);
- },
- 128 => {
- const lhs_val = lhs.toFloat(f128);
- const rhs_val = rhs.toFloat(f128);
- return Value.Tag.float_128.create(sema.arena, lhs_val + rhs_val);
- },
- else => unreachable,
- }
-}
-
-fn floatSub(
- sema: *Sema,
- lhs: Value,
- rhs: Value,
- float_type: Type,
-) !Value {
- if (float_type.zigTypeTag() == .Vector) {
- const result_data = try sema.arena.alloc(Value, float_type.vectorLen());
- for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- scalar.* = try sema.floatSubScalar(lhs_elem, rhs_elem, float_type.scalarType());
- }
- return Value.Tag.aggregate.create(sema.arena, result_data);
- }
- return sema.floatSubScalar(lhs, rhs, float_type);
-}
-
-fn floatSubScalar(
- sema: *Sema,
- lhs: Value,
- rhs: Value,
- float_type: Type,
-) !Value {
- const target = sema.mod.getTarget();
- switch (float_type.floatBits(target)) {
- 16 => {
- const lhs_val = lhs.toFloat(f16);
- const rhs_val = rhs.toFloat(f16);
- return Value.Tag.float_16.create(sema.arena, lhs_val - rhs_val);
- },
- 32 => {
- const lhs_val = lhs.toFloat(f32);
- const rhs_val = rhs.toFloat(f32);
- return Value.Tag.float_32.create(sema.arena, lhs_val - rhs_val);
- },
- 64 => {
- const lhs_val = lhs.toFloat(f64);
- const rhs_val = rhs.toFloat(f64);
- return Value.Tag.float_64.create(sema.arena, lhs_val - rhs_val);
- },
- 80 => {
- const lhs_val = lhs.toFloat(f80);
- const rhs_val = rhs.toFloat(f80);
- return Value.Tag.float_80.create(sema.arena, lhs_val - rhs_val);
- },
- 128 => {
- const lhs_val = lhs.toFloat(f128);
- const rhs_val = rhs.toFloat(f128);
- return Value.Tag.float_128.create(sema.arena, lhs_val - rhs_val);
- },
- else => unreachable,
- }
-}
-
fn intSubWithOverflow(
sema: *Sema,
lhs: Value,
rhs: Value,
ty: Type,
) !Value.OverflowArithmeticResult {
- if (ty.zigTypeTag() == .Vector) {
- const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen());
- const result_data = try sema.arena.alloc(Value, ty.vectorLen());
- for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());
- overflowed_data[i] = of_math_result.overflow_bit;
- scalar.* = of_math_result.wrapped_result;
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Vector) {
+ const vec_len = ty.vectorLen(mod);
+ const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len);
+ const result_data = try sema.arena.alloc(InternPool.Index, vec_len);
+ const scalar_ty = ty.scalarType(mod);
+ for (overflowed_data, result_data, 0..) |*of, *scalar, i| {
+ const lhs_elem = try lhs.elemValue(sema.mod, i);
+ const rhs_elem = try rhs.elemValue(sema.mod, i);
+ const of_math_result = try sema.intSubWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty);
+ of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
+ scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
}
return Value.OverflowArithmeticResult{
- .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
- .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
+ .overflow_bit = (try mod.intern(.{ .aggregate = .{
+ .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
+ .storage = .{ .elems = overflowed_data },
+ } })).toValue(),
+ .wrapped_result = (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue(),
};
}
return sema.intSubWithOverflowScalar(lhs, rhs, ty);
@@ -33476,22 +35986,22 @@ fn intSubWithOverflowScalar(
rhs: Value,
ty: Type,
) !Value.OverflowArithmeticResult {
- const target = sema.mod.getTarget();
- const info = ty.intInfo(target);
+ const mod = sema.mod;
+ const info = ty.intInfo(mod);
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema);
- const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema);
+ const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
+ const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(info.bits),
);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
const overflowed = result_bigint.subWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
- const wrapped_result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
+ const wrapped_result = try mod.intValue_big(ty, result_bigint.toConst());
return Value.OverflowArithmeticResult{
- .overflow_bit = Value.boolToInt(overflowed),
+ .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
.wrapped_result = wrapped_result,
};
}
@@ -33504,15 +36014,19 @@ fn floatToInt(
float_ty: Type,
int_ty: Type,
) CompileError!Value {
- if (float_ty.zigTypeTag() == .Vector) {
- const elem_ty = float_ty.childType();
- const result_data = try sema.arena.alloc(Value, float_ty.vectorLen());
+ const mod = sema.mod;
+ if (float_ty.zigTypeTag(mod) == .Vector) {
+ const elem_ty = float_ty.scalarType(mod);
+ const result_data = try sema.arena.alloc(InternPool.Index, float_ty.vectorLen(mod));
+ const scalar_ty = int_ty.scalarType(mod);
for (result_data, 0..) |*scalar, i| {
- var buf: Value.ElemValueBuffer = undefined;
- const elem_val = val.elemValueBuffer(sema.mod, i, &buf);
- scalar.* = try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType());
+ const elem_val = try val.elemValue(sema.mod, i);
+ scalar.* = try (try sema.floatToIntScalar(block, src, elem_val, elem_ty, int_ty.scalarType(mod))).intern(scalar_ty, mod);
}
- return Value.Tag.aggregate.create(sema.arena, result_data);
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = int_ty.toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue();
}
return sema.floatToIntScalar(block, src, val, float_ty, int_ty);
}
@@ -33550,9 +36064,9 @@ fn floatToIntScalar(
float_ty: Type,
int_ty: Type,
) CompileError!Value {
- const Limb = std.math.big.Limb;
+ const mod = sema.mod;
- const float = val.toFloat(f128);
+ const float = val.toFloat(f128, mod);
if (std.math.isNan(float)) {
return sema.fail(block, src, "float value NaN cannot be stored in integer type '{}'", .{
int_ty.fmt(sema.mod),
@@ -33567,18 +36081,14 @@ fn floatToIntScalar(
var big_int = try float128IntPartToBigInt(sema.arena, float);
defer big_int.deinit();
- const result_limbs = try sema.arena.dupe(Limb, big_int.toConst().limbs);
- const result = if (!big_int.isPositive())
- try Value.Tag.int_big_negative.create(sema.arena, result_limbs)
- else
- try Value.Tag.int_big_positive.create(sema.arena, result_limbs);
+ const cti_result = try mod.intValue_big(Type.comptime_int, big_int.toConst());
- if (!(try sema.intFitsInType(result, int_ty, null))) {
+ if (!(try sema.intFitsInType(cti_result, int_ty, null))) {
return sema.fail(block, src, "float value '{}' cannot be stored in integer type '{}'", .{
val.fmtValue(float_ty, sema.mod), int_ty.fmt(sema.mod),
});
}
- return result;
+ return mod.getCoerced(cti_result, int_ty);
}
/// Asserts the value is an integer, and the destination type is ComptimeInt or Int.
@@ -33591,208 +36101,91 @@ fn intFitsInType(
ty: Type,
vector_index: ?*usize,
) CompileError!bool {
- const target = sema.mod.getTarget();
- switch (val.tag()) {
- .zero,
- .undef,
- .bool_false,
- => return true,
-
- .one,
- .bool_true,
- => switch (ty.zigTypeTag()) {
- .Int => {
- const info = ty.intInfo(target);
+ const mod = sema.mod;
+ if (ty.toIntern() == .comptime_int_type) return true;
+ const info = ty.intInfo(mod);
+ switch (val.toIntern()) {
+ .zero_usize, .zero_u8 => return true,
+ else => switch (mod.intern_pool.indexToKey(val.toIntern())) {
+ .undef => return true,
+ .variable, .extern_func, .func, .ptr => {
+ const target = mod.getTarget();
+ const ptr_bits = target.ptrBitWidth();
return switch (info.signedness) {
- .signed => info.bits >= 2,
- .unsigned => info.bits >= 1,
+ .signed => info.bits > ptr_bits,
+ .unsigned => info.bits >= ptr_bits,
};
},
- .ComptimeInt => return true,
- else => unreachable,
- },
-
- .lazy_align => switch (ty.zigTypeTag()) {
- .Int => {
- const info = ty.intInfo(target);
- const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed);
- // If it is u16 or bigger we know the alignment fits without resolving it.
- if (info.bits >= max_needed_bits) return true;
- const x = try sema.typeAbiAlignment(val.castTag(.lazy_align).?.data);
- if (x == 0) return true;
- const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
- return info.bits >= actual_needed_bits;
- },
- .ComptimeInt => return true,
- else => unreachable,
- },
- .lazy_size => switch (ty.zigTypeTag()) {
- .Int => {
- const info = ty.intInfo(target);
- const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed);
- // If it is u64 or bigger we know the size fits without resolving it.
- if (info.bits >= max_needed_bits) return true;
- const x = try sema.typeAbiSize(val.castTag(.lazy_size).?.data);
- if (x == 0) return true;
- const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
- return info.bits >= actual_needed_bits;
- },
- .ComptimeInt => return true,
- else => unreachable,
- },
-
- .int_u64 => switch (ty.zigTypeTag()) {
- .Int => {
- const x = val.castTag(.int_u64).?.data;
- if (x == 0) return true;
- const info = ty.intInfo(target);
- const needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
- return info.bits >= needed_bits;
- },
- .ComptimeInt => return true,
- else => unreachable,
- },
- .int_i64 => switch (ty.zigTypeTag()) {
- .Int => {
- const x = val.castTag(.int_i64).?.data;
- if (x == 0) return true;
- const info = ty.intInfo(target);
- if (info.signedness == .unsigned and x < 0)
- return false;
- var buffer: Value.BigIntSpace = undefined;
- return (try val.toBigIntAdvanced(&buffer, target, sema)).fitsInTwosComp(info.signedness, info.bits);
- },
- .ComptimeInt => return true,
- else => unreachable,
- },
- .int_big_positive => switch (ty.zigTypeTag()) {
- .Int => {
- const info = ty.intInfo(target);
- return val.castTag(.int_big_positive).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
- },
- .ComptimeInt => return true,
- else => unreachable,
- },
- .int_big_negative => switch (ty.zigTypeTag()) {
- .Int => {
- const info = ty.intInfo(target);
- return val.castTag(.int_big_negative).?.asBigInt().fitsInTwosComp(info.signedness, info.bits);
+ .int => |int| switch (int.storage) {
+ .u64, .i64, .big_int => {
+ var buffer: InternPool.Key.Int.Storage.BigIntSpace = undefined;
+ const big_int = int.storage.toBigInt(&buffer);
+ return big_int.fitsInTwosComp(info.signedness, info.bits);
+ },
+ .lazy_align => |lazy_ty| {
+ const max_needed_bits = @as(u16, 16) + @boolToInt(info.signedness == .signed);
+ // If it is u16 or bigger we know the alignment fits without resolving it.
+ if (info.bits >= max_needed_bits) return true;
+ const x = try sema.typeAbiAlignment(lazy_ty.toType());
+ if (x == 0) return true;
+ const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
+ return info.bits >= actual_needed_bits;
+ },
+ .lazy_size => |lazy_ty| {
+ const max_needed_bits = @as(u16, 64) + @boolToInt(info.signedness == .signed);
+ // If it is u64 or bigger we know the size fits without resolving it.
+ if (info.bits >= max_needed_bits) return true;
+ const x = try sema.typeAbiSize(lazy_ty.toType());
+ if (x == 0) return true;
+ const actual_needed_bits = std.math.log2(x) + 1 + @boolToInt(info.signedness == .signed);
+ return info.bits >= actual_needed_bits;
+ },
},
- .ComptimeInt => return true,
- else => unreachable,
- },
-
- .the_only_possible_value => {
- assert(ty.intInfo(target).bits == 0);
- return true;
- },
-
- .decl_ref_mut,
- .extern_fn,
- .decl_ref,
- .function,
- .variable,
- => switch (ty.zigTypeTag()) {
- .Int => {
- const info = ty.intInfo(target);
- const ptr_bits = target.cpu.arch.ptrBitWidth();
- return switch (info.signedness) {
- .signed => info.bits > ptr_bits,
- .unsigned => info.bits >= ptr_bits,
+ .aggregate => |aggregate| {
+ assert(ty.zigTypeTag(mod) == .Vector);
+ return switch (aggregate.storage) {
+ .bytes => |bytes| for (bytes, 0..) |byte, i| {
+ if (byte == 0) continue;
+ const actual_needed_bits = std.math.log2(byte) + 1 + @boolToInt(info.signedness == .signed);
+ if (info.bits >= actual_needed_bits) continue;
+ if (vector_index) |vi| vi.* = i;
+ break false;
+ } else true,
+ .elems, .repeated_elem => for (switch (aggregate.storage) {
+ .bytes => unreachable,
+ .elems => |elems| elems,
+ .repeated_elem => |elem| @as(*const [1]InternPool.Index, &elem),
+ }, 0..) |elem, i| {
+ if (try sema.intFitsInType(elem.toValue(), ty.scalarType(mod), null)) continue;
+ if (vector_index) |vi| vi.* = i;
+ break false;
+ } else true,
};
},
- .ComptimeInt => return true,
else => unreachable,
},
-
- .aggregate => {
- assert(ty.zigTypeTag() == .Vector);
- for (val.castTag(.aggregate).?.data, 0..) |elem, i| {
- if (!(try sema.intFitsInType(elem, ty.scalarType(), null))) {
- if (vector_index) |some| some.* = i;
- return false;
- }
- }
- return true;
- },
-
- else => unreachable,
}
}
-fn intInRange(
- sema: *Sema,
- tag_ty: Type,
- int_val: Value,
- end: usize,
-) !bool {
+fn intInRange(sema: *Sema, tag_ty: Type, int_val: Value, end: usize) !bool {
+ const mod = sema.mod;
if (!(try int_val.compareAllWithZeroAdvanced(.gte, sema))) return false;
- var end_payload: Value.Payload.U64 = .{
- .base = .{ .tag = .int_u64 },
- .data = end,
- };
- const end_val = Value.initPayload(&end_payload.base);
+ const end_val = try mod.intValue(tag_ty, end);
if (!(try sema.compareAll(int_val, .lt, end_val, tag_ty))) return false;
return true;
}
/// Asserts the type is an enum.
-fn enumHasInt(
- sema: *Sema,
- ty: Type,
- int: Value,
-) CompileError!bool {
- switch (ty.tag()) {
- .enum_nonexhaustive => unreachable,
- .enum_full => {
- const enum_full = ty.castTag(.enum_full).?.data;
- const tag_ty = enum_full.tag_ty;
- if (enum_full.values.count() == 0) {
- return sema.intInRange(tag_ty, int, enum_full.fields.count());
- } else {
- return enum_full.values.containsContext(int, .{
- .ty = tag_ty,
- .mod = sema.mod,
- });
- }
- },
- .enum_numbered => {
- const enum_obj = ty.castTag(.enum_numbered).?.data;
- const tag_ty = enum_obj.tag_ty;
- if (enum_obj.values.count() == 0) {
- return sema.intInRange(tag_ty, int, enum_obj.fields.count());
- } else {
- return enum_obj.values.containsContext(int, .{
- .ty = tag_ty,
- .mod = sema.mod,
- });
- }
- },
- .enum_simple => {
- const enum_simple = ty.castTag(.enum_simple).?.data;
- const fields_len = enum_simple.fields.count();
- const bits = std.math.log2_int_ceil(usize, fields_len);
- var buffer: Type.Payload.Bits = .{
- .base = .{ .tag = .int_unsigned },
- .data = bits,
- };
- const tag_ty = Type.initPayload(&buffer.base);
- return sema.intInRange(tag_ty, int, fields_len);
- },
- .atomic_order,
- .atomic_rmw_op,
- .calling_convention,
- .address_space,
- .float_mode,
- .reduce_op,
- .modifier,
- .prefetch_options,
- .export_options,
- .extern_options,
- => unreachable,
+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;
+ 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.
+ if (!(try sema.intFitsInType(int, enum_type.tag_ty.toType(), null))) return false;
+ const int_coerced = try mod.getCoerced(int, enum_type.tag_ty.toType());
- else => unreachable,
- }
+ return enum_type.tagValueIndex(&mod.intern_pool, int_coerced.toIntern()) != null;
}
fn intAddWithOverflow(
@@ -33801,21 +36194,28 @@ fn intAddWithOverflow(
rhs: Value,
ty: Type,
) !Value.OverflowArithmeticResult {
- if (ty.zigTypeTag() == .Vector) {
- const overflowed_data = try sema.arena.alloc(Value, ty.vectorLen());
- const result_data = try sema.arena.alloc(Value, ty.vectorLen());
- for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, ty.scalarType());
- overflowed_data[i] = of_math_result.overflow_bit;
- scalar.* = of_math_result.wrapped_result;
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Vector) {
+ const vec_len = ty.vectorLen(mod);
+ const overflowed_data = try sema.arena.alloc(InternPool.Index, vec_len);
+ const result_data = try sema.arena.alloc(InternPool.Index, vec_len);
+ const scalar_ty = ty.scalarType(mod);
+ for (overflowed_data, result_data, 0..) |*of, *scalar, i| {
+ const lhs_elem = try lhs.elemValue(sema.mod, i);
+ const rhs_elem = try rhs.elemValue(sema.mod, i);
+ const of_math_result = try sema.intAddWithOverflowScalar(lhs_elem, rhs_elem, scalar_ty);
+ of.* = try of_math_result.overflow_bit.intern(Type.u1, mod);
+ scalar.* = try of_math_result.wrapped_result.intern(scalar_ty, mod);
}
return Value.OverflowArithmeticResult{
- .overflow_bit = try Value.Tag.aggregate.create(sema.arena, overflowed_data),
- .wrapped_result = try Value.Tag.aggregate.create(sema.arena, result_data),
+ .overflow_bit = (try mod.intern(.{ .aggregate = .{
+ .ty = (try mod.vectorType(.{ .len = vec_len, .child = .u1_type })).toIntern(),
+ .storage = .{ .elems = overflowed_data },
+ } })).toValue(),
+ .wrapped_result = (try mod.intern(.{ .aggregate = .{
+ .ty = ty.toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue(),
};
}
return sema.intAddWithOverflowScalar(lhs, rhs, ty);
@@ -33827,22 +36227,22 @@ fn intAddWithOverflowScalar(
rhs: Value,
ty: Type,
) !Value.OverflowArithmeticResult {
- const target = sema.mod.getTarget();
- const info = ty.intInfo(target);
+ const mod = sema.mod;
+ const info = ty.intInfo(mod);
var lhs_space: Value.BigIntSpace = undefined;
var rhs_space: Value.BigIntSpace = undefined;
- const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, target, sema);
- const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, target, sema);
+ const lhs_bigint = try lhs.toBigIntAdvanced(&lhs_space, mod, sema);
+ const rhs_bigint = try rhs.toBigIntAdvanced(&rhs_space, mod, sema);
const limbs = try sema.arena.alloc(
std.math.big.Limb,
std.math.big.int.calcTwosCompLimbCount(info.bits),
);
var result_bigint = std.math.big.int.Mutable{ .limbs = limbs, .positive = undefined, .len = undefined };
const overflowed = result_bigint.addWrap(lhs_bigint, rhs_bigint, info.signedness, info.bits);
- const result = try Value.fromBigInt(sema.arena, result_bigint.toConst());
+ const result = try mod.intValue_big(ty, result_bigint.toConst());
return Value.OverflowArithmeticResult{
- .overflow_bit = Value.boolToInt(overflowed),
+ .overflow_bit = try mod.intValue(Type.u1, @boolToInt(overflowed)),
.wrapped_result = result,
};
}
@@ -33858,14 +36258,13 @@ fn compareAll(
rhs: Value,
ty: Type,
) CompileError!bool {
- if (ty.zigTypeTag() == .Vector) {
+ const mod = sema.mod;
+ if (ty.zigTypeTag(mod) == .Vector) {
var i: usize = 0;
- while (i < ty.vectorLen()) : (i += 1) {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType()))) {
+ while (i < ty.vectorLen(mod)) : (i += 1) {
+ const lhs_elem = try lhs.elemValue(sema.mod, i);
+ const rhs_elem = try rhs.elemValue(sema.mod, i);
+ if (!(try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod)))) {
return false;
}
}
@@ -33882,10 +36281,13 @@ fn compareScalar(
rhs: Value,
ty: Type,
) CompileError!bool {
+ const mod = sema.mod;
+ const coerced_lhs = try mod.getCoerced(lhs, ty);
+ const coerced_rhs = try mod.getCoerced(rhs, ty);
switch (op) {
- .eq => return sema.valuesEqual(lhs, rhs, ty),
- .neq => return !(try sema.valuesEqual(lhs, rhs, ty)),
- else => return Value.compareHeteroAdvanced(lhs, op, rhs, sema.mod.getTarget(), sema),
+ .eq => return sema.valuesEqual(coerced_lhs, coerced_rhs, ty),
+ .neq => return !(try sema.valuesEqual(coerced_lhs, coerced_rhs, ty)),
+ else => return Value.compareHeteroAdvanced(coerced_lhs, op, coerced_rhs, mod, sema),
}
}
@@ -33906,17 +36308,19 @@ fn compareVector(
rhs: Value,
ty: Type,
) !Value {
- assert(ty.zigTypeTag() == .Vector);
- const result_data = try sema.arena.alloc(Value, ty.vectorLen());
+ const mod = sema.mod;
+ assert(ty.zigTypeTag(mod) == .Vector);
+ const result_data = try sema.arena.alloc(InternPool.Index, ty.vectorLen(mod));
for (result_data, 0..) |*scalar, i| {
- var lhs_buf: Value.ElemValueBuffer = undefined;
- var rhs_buf: Value.ElemValueBuffer = undefined;
- const lhs_elem = lhs.elemValueBuffer(sema.mod, i, &lhs_buf);
- const rhs_elem = rhs.elemValueBuffer(sema.mod, i, &rhs_buf);
- const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType());
- scalar.* = Value.makeBool(res_bool);
+ const lhs_elem = try lhs.elemValue(sema.mod, i);
+ const rhs_elem = try rhs.elemValue(sema.mod, i);
+ const res_bool = try sema.compareScalar(lhs_elem, op, rhs_elem, ty.scalarType(mod));
+ scalar.* = try Value.makeBool(res_bool).intern(Type.bool, mod);
}
- return Value.Tag.aggregate.create(sema.arena, result_data);
+ return (try mod.intern(.{ .aggregate = .{
+ .ty = (try mod.vectorType(.{ .len = ty.vectorLen(mod), .child = .bool_type })).toIntern(),
+ .storage = .{ .elems = result_data },
+ } })).toValue();
}
/// Returns the type of a pointer to an element.
@@ -33927,11 +36331,11 @@ fn compareVector(
/// Handles const-ness and address spaces in particular.
/// This code is duplicated in `analyzePtrArithmetic`.
fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
- const ptr_info = ptr_ty.ptrInfo().data;
- const elem_ty = ptr_ty.elemType2();
+ const mod = sema.mod;
+ const ptr_info = ptr_ty.ptrInfo(mod);
+ const elem_ty = ptr_ty.elemType2(mod);
const allow_zero = ptr_info.@"allowzero" and (offset orelse 0) == 0;
- const target = sema.mod.getTarget();
- const parent_ty = ptr_ty.childType();
+ const parent_ty = ptr_ty.childType(mod);
const VI = Type.Payload.Pointer.Data.VectorIndex;
@@ -33939,15 +36343,15 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
host_size: u16 = 0,
alignment: u32 = 0,
vector_index: VI = .none,
- } = if (parent_ty.tag() == .vector and ptr_info.size == .One) blk: {
- const elem_bits = elem_ty.bitSize(target);
+ } = if (parent_ty.isVector(mod) and ptr_info.size == .One) blk: {
+ const elem_bits = elem_ty.bitSize(mod);
if (elem_bits == 0) break :blk .{};
const is_packed = elem_bits < 8 or !std.math.isPowerOfTwo(elem_bits);
if (!is_packed) break :blk .{};
break :blk .{
- .host_size = @intCast(u16, parent_ty.arrayLen()),
- .alignment = @intCast(u16, parent_ty.abiAlignment(target)),
+ .host_size = @intCast(u16, parent_ty.arrayLen(mod)),
+ .alignment = @intCast(u16, parent_ty.abiAlignment(mod)),
.vector_index = if (offset) |some| @intToEnum(VI, some) else .runtime,
};
} else .{};
@@ -33981,3 +36385,42 @@ fn elemPtrType(sema: *Sema, ptr_ty: Type, offset: ?usize) !Type {
.vector_index = vector_info.vector_index,
});
}
+
+/// Merge lhs with rhs.
+/// Asserts that lhs and rhs are both error sets and are resolved.
+fn errorSetMerge(sema: *Sema, lhs: Type, rhs: Type) !Type {
+ const mod = sema.mod;
+ const arena = sema.arena;
+ const lhs_names = lhs.errorSetNames(mod);
+ const rhs_names = rhs.errorSetNames(mod);
+ var names: Module.Fn.InferredErrorSet.NameMap = .{};
+ try names.ensureUnusedCapacity(arena, lhs_names.len);
+
+ for (lhs_names) |name| {
+ names.putAssumeCapacityNoClobber(name, {});
+ }
+ for (rhs_names) |name| {
+ try names.put(arena, name, {});
+ }
+
+ return mod.errorSetFromUnsortedNames(names.keys());
+}
+
+/// Avoids crashing the compiler when asking if inferred allocations are noreturn.
+fn isNoReturn(sema: *Sema, ref: Air.Inst.Ref) bool {
+ if (ref == .unreachable_value) return true;
+ if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) {
+ .inferred_alloc, .inferred_alloc_comptime => return false,
+ else => {},
+ };
+ return sema.typeOf(ref).isNoReturn(sema.mod);
+}
+
+/// Avoids crashing the compiler when asking if inferred allocations are known to be a certain zig type.
+fn isKnownZigType(sema: *Sema, ref: Air.Inst.Ref, tag: std.builtin.TypeId) bool {
+ if (Air.refToIndex(ref)) |inst| switch (sema.air_instructions.items(.tag)[inst]) {
+ .inferred_alloc, .inferred_alloc_comptime => return false,
+ else => {},
+ };
+ return sema.typeOf(ref).zigTypeTag(sema.mod) == tag;
+}