Commit f01029c4af
Changed files (6)
src/codegen/llvm.zig
@@ -5754,10 +5754,12 @@ pub const FuncGen = struct {
const o = fg.ng.object;
const zcu = o.pt.zcu;
const ip = &zcu.intern_pool;
- const msg_nav_index = zcu.panic_messages[@intFromEnum(panic_id)].unwrap().?;
- const msg_nav = ip.getNav(msg_nav_index);
- const msg_len = Type.fromInterned(msg_nav.typeOf(ip)).childType(zcu).arrayLen(zcu);
- const msg_ptr = try o.lowerValue(msg_nav.status.fully_resolved.val);
+ const panic_msg_val: InternPool.Index = switch (panic_id) {
+ inline else => |ct_panic_id| @field(zcu.builtin_decl_values, "Panic.messages." ++ @tagName(ct_panic_id)),
+ };
+ assert(panic_msg_val != .none);
+ const msg_len = Value.fromInterned(panic_msg_val).typeOf(zcu).childType(zcu).arrayLen(zcu);
+ const msg_ptr = try o.lowerValue(panic_msg_val);
const null_opt_addr_global = try fg.resolveNullOptUsize();
const target = zcu.getTarget();
const llvm_usize = try o.lowerType(Type.usize);
@@ -5768,7 +5770,7 @@ pub const FuncGen = struct {
// ptr null, ; stack trace
// ptr @2, ; addr (null ?usize)
// )
- const panic_func = zcu.funcInfo(zcu.panic_func_index);
+ const panic_func = zcu.funcInfo(zcu.builtin_decl_values.@"Panic.call");
const panic_nav = ip.getNav(panic_func.owner_nav);
const fn_info = zcu.typeToFunc(Type.fromInterned(panic_nav.typeOf(ip))).?;
const panic_global = try o.resolveLlvmFunction(panic_func.owner_nav);
src/Zcu/PerThread.zig
@@ -560,6 +560,147 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) Zcu.Sem
return pt.semaFile(file_index);
}
+/// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary.
+/// Returns `error.AnalysisFail` if an analysis error is encountered; the caller is free to ignore
+/// this, since the error is already registered, but it must not use the value of memoized fields.
+pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.SemaError!void {
+ const tracy = trace(@src());
+ defer tracy.end();
+
+ const zcu = pt.zcu;
+ const gpa = zcu.gpa;
+
+ const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
+
+ log.debug("ensureMemoizedStateUpToDate", .{});
+
+ assert(!zcu.analysis_in_progress.contains(unit));
+
+ const was_outdated = zcu.outdated.swapRemove(unit) or zcu.potentially_outdated.swapRemove(unit);
+ const prev_failed = zcu.failed_analysis.contains(unit) or zcu.transitive_failed_analysis.contains(unit);
+
+ if (was_outdated) {
+ dev.check(.incremental);
+ _ = zcu.outdated_ready.swapRemove(unit);
+ // No need for `deleteUnitExports` because we never export anything.
+ zcu.deleteUnitReferences(unit);
+ if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| {
+ kv.value.destroy(gpa);
+ }
+ _ = zcu.transitive_failed_analysis.swapRemove(unit);
+ } else {
+ if (prev_failed) return error.AnalysisFail;
+ // We use an arbitrary field to check if the state has been resolved yet.
+ const val = switch (stage) {
+ .main => zcu.builtin_decl_values.Type,
+ .panic => zcu.builtin_decl_values.Panic,
+ .va_list => zcu.builtin_decl_values.VaList,
+ };
+ if (val != .none) return;
+ }
+
+ const any_changed: bool, const new_failed: bool = if (pt.analyzeMemoizedState(stage)) |any_changed|
+ .{ any_changed or prev_failed, false }
+ else |err| switch (err) {
+ error.AnalysisFail => res: {
+ if (!zcu.failed_analysis.contains(unit)) {
+ // If this unit caused the error, it would have an entry in `failed_analysis`.
+ // Since it does not, this must be a transitive failure.
+ try zcu.transitive_failed_analysis.put(gpa, unit, {});
+ log.debug("mark transitive analysis failure for {}", .{zcu.fmtAnalUnit(unit)});
+ }
+ break :res .{ !prev_failed, true };
+ },
+ error.OutOfMemory => {
+ // TODO: same as for `ensureComptimeUnitUpToDate` etc
+ return error.OutOfMemory;
+ },
+ error.GenericPoison => unreachable,
+ error.ComptimeReturn => unreachable,
+ error.ComptimeBreak => unreachable,
+ };
+
+ if (was_outdated) {
+ const dependee: InternPool.Dependee = .{ .memoized_state = stage };
+ if (any_changed) {
+ try zcu.markDependeeOutdated(.marked_po, dependee);
+ } else {
+ try zcu.markPoDependeeUpToDate(dependee);
+ }
+ }
+
+ if (new_failed) return error.AnalysisFail;
+}
+
+fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.CompileError!bool {
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.gpa;
+
+ const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
+
+ try zcu.analysis_in_progress.put(gpa, unit, {});
+ defer assert(zcu.analysis_in_progress.swapRemove(unit));
+
+ // Before we begin, collect:
+ // * The type `std`, and its namespace
+ // * The type `std.builtin`, and its namespace
+ // * A semi-reasonable source location
+ const std_file_imported = pt.importPkg(zcu.std_mod) catch return error.AnalysisFail;
+ try pt.ensureFileAnalyzed(std_file_imported.file_index);
+ const std_type: Type = .fromInterned(zcu.fileRootType(std_file_imported.file_index));
+ const std_namespace = std_type.getNamespaceIndex(zcu);
+ try pt.ensureNamespaceUpToDate(std_namespace);
+ const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
+ const builtin_nav = zcu.namespacePtr(std_namespace).pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
+ @panic("lib/std.zig is corrupt and missing 'builtin'");
+ try pt.ensureNavValUpToDate(builtin_nav);
+ const builtin_type: Type = .fromInterned(ip.getNav(builtin_nav).status.fully_resolved.val);
+ const builtin_namespace = builtin_type.getNamespaceIndex(zcu);
+ try pt.ensureNamespaceUpToDate(builtin_namespace);
+ const src: Zcu.LazySrcLoc = .{
+ .base_node_inst = builtin_type.typeDeclInst(zcu).?,
+ .offset = .entire_file,
+ };
+
+ var analysis_arena: std.heap.ArenaAllocator = .init(gpa);
+ defer analysis_arena.deinit();
+
+ var comptime_err_ret_trace: std.ArrayList(Zcu.LazySrcLoc) = .init(gpa);
+ defer comptime_err_ret_trace.deinit();
+
+ var sema: Sema = .{
+ .pt = pt,
+ .gpa = gpa,
+ .arena = analysis_arena.allocator(),
+ .code = .{ .instructions = .empty, .string_bytes = &.{}, .extra = &.{} },
+ .owner = unit,
+ .func_index = .none,
+ .func_is_naked = false,
+ .fn_ret_ty = .void,
+ .fn_ret_ty_ies = null,
+ .comptime_err_ret_trace = &comptime_err_ret_trace,
+ };
+ defer sema.deinit();
+
+ var block: Sema.Block = .{
+ .parent = null,
+ .sema = &sema,
+ .namespace = std_namespace,
+ .instructions = .{},
+ .inlining = null,
+ .comptime_reason = .{ .reason = .{
+ .src = src,
+ .r = .{ .simple = .type },
+ } },
+ .src_base_inst = src.base_node_inst,
+ .type_name_ctx = .empty,
+ };
+ defer block.instructions.deinit(gpa);
+
+ return sema.analyzeMemoizedState(&block, src, builtin_namespace, stage);
+}
+
/// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis
/// if necessary. Returns `error.AnalysisFail` if an analysis error is encountered; the caller is
/// free to ignore this, since the error is already registered.
@@ -2615,7 +2756,7 @@ fn analyzeFnBodyInner(pt: Zcu.PerThread, func_index: InternPool.Index) Zcu.SemaE
// result in circular dependency errors.
// TODO: this can go away once we fix backends having to resolve `StackTrace`.
// The codegen timing guarantees that the parameter types will be populated.
- sema.resolveFnTypes(fn_ty) catch |err| switch (err) {
+ sema.resolveFnTypes(fn_ty, inner_block.nodeOffset(0)) catch |err| switch (err) {
error.GenericPoison => unreachable,
error.ComptimeReturn => unreachable,
error.ComptimeBreak => unreachable,
@@ -3471,23 +3612,6 @@ pub fn structPackedFieldBitOffset(
unreachable; // index out of bounds
}
-pub fn getBuiltinNav(pt: Zcu.PerThread, name: []const u8) Allocator.Error!InternPool.Nav.Index {
- const zcu = pt.zcu;
- const gpa = zcu.gpa;
- const ip = &zcu.intern_pool;
- const std_file_imported = pt.importPkg(zcu.std_mod) catch @panic("failed to import lib/std.zig");
- const std_type = Type.fromInterned(zcu.fileRootType(std_file_imported.file_index));
- const std_namespace = zcu.namespacePtr(std_type.getNamespace(zcu).unwrap().?);
- const builtin_str = try ip.getOrPutString(gpa, pt.tid, "builtin", .no_embedded_nulls);
- const builtin_nav = std_namespace.pub_decls.getKeyAdapted(builtin_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse
- @panic("lib/std.zig is corrupt and missing 'builtin'");
- pt.ensureNavValUpToDate(builtin_nav) catch @panic("std.builtin is corrupt");
- const builtin_type = Type.fromInterned(ip.getNav(builtin_nav).status.fully_resolved.val);
- const builtin_namespace = zcu.namespacePtr(builtin_type.getNamespace(zcu).unwrap() orelse @panic("std.builtin is corrupt"));
- const name_str = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
- return builtin_namespace.pub_decls.getKeyAdapted(name_str, Zcu.Namespace.NameAdapter{ .zcu = zcu }) orelse @panic("lib/std/builtin.zig is corrupt");
-}
-
pub fn navPtrType(pt: Zcu.PerThread, nav_id: InternPool.Nav.Index) Allocator.Error!Type {
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
src/Compilation.zig
@@ -3158,16 +3158,19 @@ pub fn getAllErrorsAlloc(comp: *Compilation) !ErrorBundle {
if (!refs.contains(anal_unit)) continue;
}
- const file_index = switch (anal_unit.unwrap()) {
- .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
- .nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
- .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
- .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
- };
+ report_ok: {
+ const file_index = switch (anal_unit.unwrap()) {
+ .@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index.resolveFile(ip),
+ .nav_val, .nav_ty => |nav| ip.getNav(nav).analysis.?.zir_index.resolveFile(ip),
+ .type => |ty| Type.fromInterned(ty).typeDeclInst(zcu).?.resolveFile(ip),
+ .func => |ip_index| zcu.funcInfo(ip_index).zir_body_inst.resolveFile(ip),
+ .memoized_state => break :report_ok, // always report std.builtin errors
+ };
- // Skip errors for AnalUnits within files that had a parse failure.
- // We'll try again once parsing succeeds.
- if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
+ // Skip errors for AnalUnits within files that had a parse failure.
+ // We'll try again once parsing succeeds.
+ if (!zcu.fileByIndex(file_index).okToReportErrors()) continue;
+ }
std.log.scoped(.zcu).debug("analysis error '{s}' reported from unit '{}'", .{
error_msg.msg,
@@ -3391,7 +3394,7 @@ pub fn addModuleErrorMsg(
const ref = maybe_ref orelse break;
const gop = try seen.getOrPut(gpa, ref.referencer);
if (gop.found_existing) break;
- if (ref_traces.items.len < max_references) {
+ if (ref_traces.items.len < max_references) skip: {
const src = ref.src.upgrade(zcu);
const source = try src.file_scope.getSource(gpa);
const span = try src.span(gpa);
@@ -3403,6 +3406,7 @@ pub fn addModuleErrorMsg(
.nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip),
.type => |ty| Type.fromInterned(ty).containerTypeName(ip).toSlice(ip),
.func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip),
+ .memoized_state => break :skip,
};
try ref_traces.append(gpa, .{
.decl_name = try eb.addString(name),
@@ -3670,6 +3674,7 @@ fn performAllTheWorkInner(
if (try zcu.findOutdatedToAnalyze()) |outdated| {
try comp.queueJob(switch (outdated.unwrap()) {
.func => |f| .{ .analyze_func = f },
+ .memoized_state,
.@"comptime",
.nav_ty,
.nav_val,
@@ -3737,6 +3742,7 @@ fn processOneJob(tid: usize, comp: *Compilation, job: Job, prog_node: std.Progre
.nav_ty => |nav| pt.ensureNavTypeUpToDate(nav),
.nav_val => |nav| pt.ensureNavValUpToDate(nav),
.type => |ty| if (pt.ensureTypeUpToDate(ty)) |_| {} else |err| err,
+ .memoized_state => |stage| pt.ensureMemoizedStateUpToDate(stage),
.func => unreachable,
};
maybe_err catch |err| switch (err) {
src/InternPool.zig
@@ -49,6 +49,11 @@ namespace_deps: std.AutoArrayHashMapUnmanaged(TrackedInst.Index, DepEntry.Index)
/// Dependencies on the (non-)existence of some name in a namespace.
/// Value is index into `dep_entries` of the first dependency on this name.
namespace_name_deps: std.AutoArrayHashMapUnmanaged(NamespaceNameKey, DepEntry.Index),
+// Dependencies on the value of fields memoized on `Zcu` (`panic_messages` etc).
+// If set, these are indices into `dep_entries` of the first dependency on this state.
+memoized_state_main_deps: DepEntry.Index.Optional,
+memoized_state_panic_deps: DepEntry.Index.Optional,
+memoized_state_va_list_deps: DepEntry.Index.Optional,
/// Given a `Depender`, points to an entry in `dep_entries` whose `depender`
/// matches. The `next_dependee` field can be used to iterate all such entries
@@ -87,6 +92,9 @@ pub const empty: InternPool = .{
.interned_deps = .empty,
.namespace_deps = .empty,
.namespace_name_deps = .empty,
+ .memoized_state_main_deps = .none,
+ .memoized_state_panic_deps = .none,
+ .memoized_state_va_list_deps = .none,
.first_dependency = .empty,
.dep_entries = .empty,
.free_dep_entries = .empty,
@@ -385,6 +393,7 @@ pub const AnalUnit = packed struct(u64) {
nav_ty,
type,
func,
+ memoized_state,
};
pub const Unwrapped = union(Kind) {
@@ -399,6 +408,8 @@ pub const AnalUnit = packed struct(u64) {
type: InternPool.Index,
/// This `AnalUnit` analyzes the body of the given runtime function.
func: InternPool.Index,
+ /// This `AnalUnit` resolves all state which is memoized in fields on `Zcu`.
+ memoized_state: MemoizedStateStage,
};
pub fn unwrap(au: AnalUnit) Unwrapped {
@@ -434,6 +445,16 @@ pub const AnalUnit = packed struct(u64) {
};
};
+pub const MemoizedStateStage = enum(u32) {
+ /// Everything other than panics and `VaList`.
+ main,
+ /// Everything within `std.builtin.Panic`.
+ /// Since the panic handler is user-provided, this must be able to reference the other memoized state.
+ panic,
+ /// Specifically `std.builtin.VaList`. See `Zcu.BuiltinDecl.stage`.
+ va_list,
+};
+
pub const ComptimeUnit = extern struct {
zir_index: TrackedInst.Index,
namespace: NamespaceIndex,
@@ -769,6 +790,7 @@ pub const Dependee = union(enum) {
interned: Index,
namespace: TrackedInst.Index,
namespace_name: NamespaceNameKey,
+ memoized_state: MemoizedStateStage,
};
pub fn removeDependenciesForDepender(ip: *InternPool, gpa: Allocator, depender: AnalUnit) void {
@@ -819,6 +841,11 @@ pub fn dependencyIterator(ip: *const InternPool, dependee: Dependee) DependencyI
.interned => |x| ip.interned_deps.get(x),
.namespace => |x| ip.namespace_deps.get(x),
.namespace_name => |x| ip.namespace_name_deps.get(x),
+ .memoized_state => |stage| switch (stage) {
+ .main => ip.memoized_state_main_deps.unwrap(),
+ .panic => ip.memoized_state_panic_deps.unwrap(),
+ .va_list => ip.memoized_state_va_list_deps.unwrap(),
+ },
} orelse return .{
.ip = ip,
.next_entry = .none,
@@ -848,6 +875,33 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
// This block should allocate an entry and prepend it to the relevant `*_deps` list.
// The `next` field should be correctly initialized; all other fields may be undefined.
const new_index: DepEntry.Index = switch (dependee) {
+ .memoized_state => |stage| new_index: {
+ const deps = switch (stage) {
+ .main => &ip.memoized_state_main_deps,
+ .panic => &ip.memoized_state_panic_deps,
+ .va_list => &ip.memoized_state_va_list_deps,
+ };
+
+ if (deps.unwrap()) |first| {
+ if (ip.dep_entries.items[@intFromEnum(first)].depender == .none) {
+ // Dummy entry, so we can reuse it rather than allocating a new one!
+ break :new_index first;
+ }
+ }
+
+ // Prepend a new dependency.
+ const new_index: DepEntry.Index, const ptr = if (ip.free_dep_entries.popOrNull()) |new_index| new: {
+ break :new .{ new_index, &ip.dep_entries.items[@intFromEnum(new_index)] };
+ } else .{ @enumFromInt(ip.dep_entries.items.len), ip.dep_entries.addOneAssumeCapacity() };
+ if (deps.unwrap()) |old_first| {
+ ptr.next = old_first.toOptional();
+ ip.dep_entries.items[@intFromEnum(old_first)].prev = new_index.toOptional();
+ } else {
+ ptr.next = .none;
+ }
+ deps.* = new_index.toOptional();
+ break :new_index new_index;
+ },
inline else => |dependee_payload, tag| new_index: {
const gop = try switch (tag) {
.file => ip.file_deps,
@@ -857,6 +911,7 @@ pub fn addDependency(ip: *InternPool, gpa: Allocator, depender: AnalUnit, depend
.interned => ip.interned_deps,
.namespace => ip.namespace_deps,
.namespace_name => ip.namespace_name_deps,
+ .memoized_state => comptime unreachable,
}.getOrPut(gpa, dependee_payload);
if (gop.found_existing and ip.dep_entries.items[@intFromEnum(gop.value_ptr.*)].depender == .none) {
src/Sema.zig
@@ -428,7 +428,7 @@ pub const Block = struct {
} });
}
- fn nodeOffset(block: Block, node_offset: i32) LazySrcLoc {
+ pub fn nodeOffset(block: Block, node_offset: i32) LazySrcLoc {
return block.src(LazySrcLoc.Offset.nodeOffset(node_offset));
}
@@ -2149,7 +2149,7 @@ pub fn setupErrorReturnTrace(sema: *Sema, block: *Block, last_arg_index: usize)
const addrs_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(addr_arr_ty));
// var st: StackTrace = undefined;
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(0), .StackTrace);
try stack_trace_ty.resolveFields(pt);
const st_ptr = try err_trace_block.addTy(.alloc, try pt.singleMutPtrType(stack_trace_ty));
@@ -6600,6 +6600,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
.nav_val,
.nav_ty,
.type,
+ .memoized_state,
=> return, // does nothing outside a function
};
ip.funcSetDisableInstrumentation(func);
@@ -6609,7 +6610,7 @@ fn zirDisableInstrumentation(sema: *Sema) CompileError!void {
fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void {
const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data;
const src = block.builtinCallArgSrc(extra.node, 0);
- block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, "FloatMode", .{ .simple = .operand_setFloatMode });
+ block.float_mode = try sema.resolveBuiltinEnum(block, src, extra.operand, .FloatMode, .{ .simple = .operand_setFloatMode });
}
fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void {
@@ -6917,7 +6918,7 @@ fn lookupInNamespace(
ignore_self: {
const skip_nav = switch (sema.owner.unwrap()) {
- .@"comptime", .type, .func => break :ignore_self,
+ .@"comptime", .type, .func, .memoized_state => break :ignore_self,
.nav_ty, .nav_val => |nav| nav,
};
var i: usize = 0;
@@ -6990,7 +6991,7 @@ pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref
if (!block.ownerModule().error_tracing) return .none;
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(0), .StackTrace);
try stack_trace_ty.resolveFields(pt);
const field_name = try zcu.intern_pool.getOrPutString(gpa, pt.tid, "index", .no_embedded_nulls);
const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) {
@@ -7032,7 +7033,7 @@ fn popErrorReturnTrace(
// AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or
// the result is comptime-known to be a non-error. Either way, pop unconditionally.
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty);
@@ -7058,7 +7059,7 @@ fn popErrorReturnTrace(
defer then_block.instructions.deinit(gpa);
// If non-error, then pop the error return trace by restoring the index.
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty);
@@ -7178,7 +7179,7 @@ fn zirCall(
const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call);
switch (sema.owner.unwrap()) {
- .@"comptime", .type, .nav_ty, .nav_val => input_is_error = false,
+ .@"comptime", .type, .memoized_state, .nav_ty, .nav_val => input_is_error = false,
.func => |owner_func| if (!zcu.intern_pool.funcAnalysisUnordered(owner_func).calls_or_awaits_errorable_fn) {
// No errorable fn actually called; we have no error return trace
input_is_error = false;
@@ -7201,7 +7202,7 @@ fn zirCall(
// 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 return_ty.isError(zcu))) {
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(call_src, .StackTrace);
try stack_trace_ty.resolveFields(pt);
const field_name = try zcu.intern_pool.getOrPutString(sema.gpa, pt.tid, "index", .no_embedded_nulls);
const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src);
@@ -8091,7 +8092,7 @@ fn analyzeCall(
if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
switch (sema.owner.unwrap()) {
- .@"comptime", .nav_ty, .nav_val, .type => {},
+ .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
.func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
},
@@ -8557,7 +8558,7 @@ fn instantiateGenericCall(
if (call_dbg_node) |some| try sema.zirDbgStmt(block, some);
switch (sema.owner.unwrap()) {
- .@"comptime", .nav_ty, .nav_val, .type => {},
+ .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
.func => |owner_func| if (Type.fromInterned(func_ty_info.return_type).isError(zcu)) {
ip.funcSetCallsOrAwaitsErrorableFn(owner_func);
},
@@ -9537,6 +9538,7 @@ fn zirFunc(
const extra = sema.code.extraData(Zir.Inst.Func, inst_data.payload_index);
const target = zcu.getTarget();
const ret_ty_src = block.src(.{ .node_offset_fn_type_ret_ty = inst_data.src_node });
+ const src = block.nodeOffset(inst_data.src_node);
var extra_index = extra.end;
@@ -9588,7 +9590,7 @@ fn zirFunc(
// error by trying to evaluate `std.builtin.CallingConvention.c`, so for consistency,
// let's eval that now and just get the transitive error. (It's guaranteed to error
// because it does the exact `cCallingConvention` call we just did.)
- const cc_type = try sema.getBuiltinType("CallingConvention");
+ const cc_type = try sema.getBuiltinType(src, .CallingConvention);
_ = try sema.namespaceLookupVal(
block,
LazySrcLoc.unneeded,
@@ -10302,7 +10304,7 @@ fn finishFunc(
if (!final_is_generic and sema.wantErrorReturnTracing(return_type)) {
// Make sure that StackTrace's fields are resolved so that the backend can
// lower this fn type.
- const unresolved_stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const unresolved_stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(0), .StackTrace);
try unresolved_stack_trace_ty.resolveFields(pt);
}
@@ -14283,7 +14285,7 @@ fn maybeErrorUnwrap(
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const msg_inst = try sema.resolveInst(inst_data.operand);
- const panic_fn = try getPanicInnerFn(sema, block, operand_src, "call");
+ const panic_fn = try getBuiltin(sema, operand_src, .@"Panic.call");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [3]Air.Inst.Ref = .{ msg_inst, err_return_trace, .null_value };
try sema.callBuiltin(block, operand_src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
@@ -17477,7 +17479,7 @@ fn analyzeArithmetic(
if (block.wantSafety() and want_safety and scalar_tag == .int) {
if (zcu.backendSupportsFeature(.safety_checked_instructions)) {
if (air_tag != air_tag_safe) {
- _ = try sema.preparePanicId(block, src, .integer_overflow);
+ _ = try sema.preparePanicId(src, .integer_overflow);
}
return block.addBinOp(air_tag_safe, casted_lhs, casted_rhs);
} else {
@@ -18381,7 +18383,7 @@ fn zirBuiltinSrc(
} });
};
- const src_loc_ty = try sema.getBuiltinType("SourceLocation");
+ const src_loc_ty = try sema.getBuiltinType(block.nodeOffset(0), .SourceLocation);
const fields = .{
// module: [:0]const u8,
module_name_val,
@@ -18408,7 +18410,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
const inst_data = sema.code.instructions.items(.data)[@intFromEnum(inst)].un_node;
const src = block.nodeOffset(inst_data.src_node);
const ty = try sema.resolveType(block, src, inst_data.operand);
- const type_info_ty = try sema.getBuiltinType("Type");
+ const type_info_ty = try sema.getBuiltinType(src, .Type);
const type_info_tag_ty = type_info_ty.unionTagType(zcu).?;
if (ty.typeDeclInst(zcu)) |type_decl_inst| {
@@ -18428,8 +18430,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
=> |type_info_tag| return unionInitFromEnumTag(sema, block, src, type_info_ty, @intFromEnum(type_info_tag), .void_value),
.@"fn" => {
- const fn_info_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Fn");
- const param_info_ty = try getBuiltinInnerType(sema, block, src, fn_info_ty, "Type.Fn", "Param");
+ const fn_info_ty = try sema.getBuiltinType(src, .@"Type.Fn");
+ const param_info_ty = try sema.getBuiltinType(src, .@"Type.Fn.Param");
const func_ty_info = zcu.typeToFunc(ty).?;
const param_vals = try sema.arena.alloc(InternPool.Index, func_ty_info.param_types.len);
@@ -18499,7 +18501,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
func_ty_info.return_type,
} });
- const callconv_ty = try sema.getBuiltinType("CallingConvention");
+ const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
const callconv_val = Value.uninterpret(func_ty_info.cc, callconv_ty, pt) catch |err| switch (err) {
error.TypeMismatch => @panic("std.builtin is corrupt"),
error.OutOfMemory => |e| return e,
@@ -18527,8 +18529,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.int => {
- const int_info_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Int");
- const signedness_ty = try sema.getBuiltinType("Signedness");
+ const int_info_ty = try sema.getBuiltinType(src, .@"Type.Int");
+ const signedness_ty = try sema.getBuiltinType(src, .Signedness);
const info = ty.intInfo(zcu);
const field_values = .{
// signedness: Signedness,
@@ -18546,7 +18548,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.float => {
- const float_info_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Float");
+ const float_info_ty = try sema.getBuiltinType(src, .@"Type.Float");
const field_vals = .{
// bits: u16,
@@ -18568,9 +18570,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
else
try Type.fromInterned(info.child).lazyAbiAlignment(pt);
- const addrspace_ty = try sema.getBuiltinType("AddressSpace");
- const pointer_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Pointer");
- const ptr_size_ty = try getBuiltinInnerType(sema, block, src, pointer_ty, "Type.Pointer", "Size");
+ const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);
+ const pointer_ty = try sema.getBuiltinType(src, .@"Type.Pointer");
+ const ptr_size_ty = try sema.getBuiltinType(src, .@"Type.Pointer.Size");
const field_values = .{
// size: Size,
@@ -18603,7 +18605,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.array => {
- const array_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Array");
+ const array_field_ty = try sema.getBuiltinType(src, .@"Type.Array");
const info = ty.arrayInfo(zcu);
const field_values = .{
@@ -18624,7 +18626,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.vector => {
- const vector_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Vector");
+ const vector_field_ty = try sema.getBuiltinType(src, .@"Type.Vector");
const info = ty.arrayInfo(zcu);
const field_values = .{
@@ -18643,7 +18645,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.optional => {
- const optional_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Optional");
+ const optional_field_ty = try sema.getBuiltinType(src, .@"Type.Optional");
const field_values = .{
// child: type,
@@ -18660,7 +18662,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
},
.error_set => {
// Get the Error type
- const error_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Error");
+ const error_field_ty = try sema.getBuiltinType(src, .@"Type.Error");
// Build our list of Error values
// Optional value is only null if anyerror
@@ -18756,7 +18758,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.error_union => {
- const error_union_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "ErrorUnion");
+ const error_union_field_ty = try sema.getBuiltinType(src, .@"Type.ErrorUnion");
const field_values = .{
// error_set: type,
@@ -18776,7 +18778,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
.@"enum" => {
const is_exhaustive = Value.makeBool(ip.loadEnumType(ty.toIntern()).tag_mode != .nonexhaustive);
- const enum_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "EnumField");
+ const enum_field_ty = try sema.getBuiltinType(src, .@"Type.EnumField");
const enum_field_vals = try sema.arena.alloc(InternPool.Index, ip.loadEnumType(ty.toIntern()).names.len);
for (enum_field_vals, 0..) |*field_val, tag_index| {
@@ -18861,9 +18863,9 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ip.loadEnumType(ty.toIntern()).namespace.toOptional());
+ const decls_val = try sema.typeInfoDecls(block, src, ip.loadEnumType(ty.toIntern()).namespace.toOptional());
- const type_enum_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Enum");
+ const type_enum_ty = try sema.getBuiltinType(src, .@"Type.Enum");
const field_values = .{
// tag_type: type,
@@ -18885,8 +18887,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.@"union" => {
- const type_union_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Union");
- const union_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "UnionField");
+ const type_union_ty = try sema.getBuiltinType(src, .@"Type.Union");
+ const union_field_ty = try sema.getBuiltinType(src, .@"Type.UnionField");
try ty.resolveLayout(pt); // Getting alignment requires type layout
const union_obj = zcu.typeToUnion(ty).?;
@@ -18974,14 +18976,14 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespaceIndex(zcu).toOptional());
+ const decls_val = try sema.typeInfoDecls(block, src, ty.getNamespaceIndex(zcu).toOptional());
const enum_tag_ty_val = try pt.intern(.{ .opt = .{
.ty = (try pt.optionalType(.type_type)).toIntern(),
.val = if (ty.unionTagType(zcu)) |tag_ty| tag_ty.toIntern() else .none,
} });
- const container_layout_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "ContainerLayout");
+ const container_layout_ty = try sema.getBuiltinType(src, .@"Type.ContainerLayout");
const field_values = .{
// layout: ContainerLayout,
@@ -19004,8 +19006,8 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.@"struct" => {
- const type_struct_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Struct");
- const struct_field_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "StructField");
+ const type_struct_ty = try sema.getBuiltinType(src, .@"Type.Struct");
+ const struct_field_ty = try sema.getBuiltinType(src, .@"Type.StructField");
try ty.resolveLayout(pt); // Getting alignment requires type layout
@@ -19169,7 +19171,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} });
};
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace(zcu));
+ const decls_val = try sema.typeInfoDecls(block, src, ty.getNamespace(zcu));
const backing_integer_val = try pt.intern(.{ .opt = .{
.ty = (try pt.optionalType(.type_type)).toIntern(),
@@ -19179,7 +19181,7 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
} else .none,
} });
- const container_layout_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "ContainerLayout");
+ const container_layout_ty = try sema.getBuiltinType(src, .@"Type.ContainerLayout");
const layout = ty.containerLayout(zcu);
@@ -19205,10 +19207,10 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai
})));
},
.@"opaque" => {
- const type_opaque_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Opaque");
+ const type_opaque_ty = try sema.getBuiltinType(src, .@"Type.Opaque");
try ty.resolveFields(pt);
- const decls_val = try sema.typeInfoDecls(block, src, type_info_ty, ty.getNamespace(zcu));
+ const decls_val = try sema.typeInfoDecls(block, src, ty.getNamespace(zcu));
const field_values = .{
// decls: []const Declaration,
@@ -19232,14 +19234,13 @@ fn typeInfoDecls(
sema: *Sema,
block: *Block,
src: LazySrcLoc,
- type_info_ty: Type,
opt_namespace: InternPool.OptionalNamespaceIndex,
) CompileError!InternPool.Index {
const pt = sema.pt;
const zcu = pt.zcu;
const gpa = sema.gpa;
- const declaration_ty = try getBuiltinInnerType(sema, block, src, type_info_ty, "Type", "Declaration");
+ const declaration_ty = try sema.getBuiltinType(src, .@"Type.Declaration");
var decl_vals = std.ArrayList(InternPool.Index).init(gpa);
defer decl_vals.deinit();
@@ -20181,11 +20182,11 @@ fn retWithErrTracing(
else => true,
};
const gpa = sema.gpa;
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.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 return_err_fn = Air.internedToRef(try sema.getBuiltin(src, .returnError));
const args: [1]Air.Inst.Ref = .{err_return_trace};
if (!need_check) {
@@ -21607,7 +21608,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
+ const stack_trace_ty = try sema.getBuiltinType(block.nodeOffset(0), .StackTrace);
try stack_trace_ty.resolveFields(pt);
const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
@@ -21616,7 +21617,7 @@ fn getErrorReturnTrace(sema: *Sema, block: *Block) CompileError!Air.Inst.Ref {
.func => |func| if (ip.funcAnalysisUnordered(func).calls_or_awaits_errorable_fn and block.ownerModule().error_tracing) {
return block.addTy(.err_return_trace, opt_ptr_stack_trace_ty);
},
- .@"comptime", .nav_ty, .nav_val, .type => {},
+ .@"comptime", .nav_ty, .nav_val, .type, .memoized_state => {},
}
return Air.internedToRef(try pt.intern(.{ .opt = .{
.ty = opt_ptr_stack_trace_ty.toIntern(),
@@ -21896,7 +21897,7 @@ fn zirReify(
},
},
};
- const type_info_ty = try sema.getBuiltinType("Type");
+ const type_info_ty = try sema.getBuiltinType(src, .Type);
const uncasted_operand = try sema.resolveInst(extra.operand);
const type_info = try sema.coerce(block, type_info_ty, uncasted_operand, operand_src);
const val = try sema.resolveConstDefinedValue(block, operand_src, type_info, .{ .simple = .operand_Type });
@@ -23156,7 +23157,7 @@ fn reifyStruct(
fn resolveVaListRef(sema: *Sema, block: *Block, src: LazySrcLoc, zir_ref: Zir.Inst.Ref) CompileError!Air.Inst.Ref {
const pt = sema.pt;
- const va_list_ty = try sema.getBuiltinType("VaList");
+ const va_list_ty = try sema.getBuiltinType(src, .VaList);
const va_list_ptr = try pt.singleMutPtrType(va_list_ty);
const inst = try sema.resolveInst(zir_ref);
@@ -23195,7 +23196,7 @@ fn zirCVaCopy(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData)
const va_list_src = block.builtinCallArgSrc(extra.node, 0);
const va_list_ref = try sema.resolveVaListRef(block, va_list_src, extra.operand);
- const va_list_ty = try sema.getBuiltinType("VaList");
+ const va_list_ty = try sema.getBuiltinType(src, .VaList);
try sema.requireRuntimeBlock(block, src, null);
return block.addTyOp(.c_va_copy, va_list_ty, va_list_ref);
@@ -23215,7 +23216,7 @@ fn zirCVaEnd(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) C
fn zirCVaStart(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref {
const src = block.nodeOffset(@bitCast(extended.operand));
- const va_list_ty = try sema.getBuiltinType("VaList");
+ const va_list_ty = try sema.getBuiltinType(src, .VaList);
try sema.requireRuntimeBlock(block, src, null);
return block.addInst(.{
.tag = .c_va_start,
@@ -24821,7 +24822,7 @@ fn resolveExportOptions(
const zcu = pt.zcu;
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- const export_options_ty = try sema.getBuiltinType("ExportOptions");
+ const export_options_ty = try sema.getBuiltinType(src, .ExportOptions);
const air_ref = try sema.resolveInst(zir_ref);
const options = try sema.coerce(block, export_options_ty, air_ref, src);
@@ -24871,15 +24872,15 @@ fn resolveBuiltinEnum(
block: *Block,
src: LazySrcLoc,
zir_ref: Zir.Inst.Ref,
- comptime name: []const u8,
+ comptime name: Zcu.BuiltinDecl,
reason: ComptimeReason,
-) CompileError!@field(std.builtin, name) {
+) CompileError!@field(std.builtin, @tagName(name)) {
const pt = sema.pt;
- const ty = try sema.getBuiltinType(name);
+ const ty = try sema.getBuiltinType(src, name);
const air_ref = try sema.resolveInst(zir_ref);
const coerced = try sema.coerce(block, ty, air_ref, src);
const val = try sema.resolveConstDefinedValue(block, src, coerced, reason);
- return pt.zcu.toEnum(@field(std.builtin, name), val);
+ return pt.zcu.toEnum(@field(std.builtin, @tagName(name)), val);
}
fn resolveAtomicOrder(
@@ -24889,7 +24890,7 @@ fn resolveAtomicOrder(
zir_ref: Zir.Inst.Ref,
reason: ComptimeReason,
) CompileError!std.builtin.AtomicOrder {
- return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicOrder", reason);
+ return sema.resolveBuiltinEnum(block, src, zir_ref, .AtomicOrder, reason);
}
fn resolveAtomicRmwOp(
@@ -24898,7 +24899,7 @@ fn resolveAtomicRmwOp(
src: LazySrcLoc,
zir_ref: Zir.Inst.Ref,
) CompileError!std.builtin.AtomicRmwOp {
- return sema.resolveBuiltinEnum(block, src, zir_ref, "AtomicRmwOp", .{ .simple = .operand_atomicRmw_operation });
+ return sema.resolveBuiltinEnum(block, src, zir_ref, .AtomicRmwOp, .{ .simple = .operand_atomicRmw_operation });
}
fn zirCmpxchg(
@@ -25078,7 +25079,7 @@ fn zirReduce(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.
const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data;
const op_src = block.builtinCallArgSrc(inst_data.src_node, 0);
const operand_src = block.builtinCallArgSrc(inst_data.src_node, 1);
- const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, "ReduceOp", .{ .simple = .operand_reduce_operation });
+ const operation = try sema.resolveBuiltinEnum(block, op_src, extra.lhs, .ReduceOp, .{ .simple = .operand_reduce_operation });
const operand = try sema.resolveInst(extra.rhs);
const operand_ty = sema.typeOf(operand);
const pt = sema.pt;
@@ -25668,7 +25669,7 @@ fn zirBuiltinCall(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError
const extra = sema.code.extraData(Zir.Inst.BuiltinCall, inst_data.payload_index).data;
const func = try sema.resolveInst(extra.callee);
- const modifier_ty = try sema.getBuiltinType("CallModifier");
+ const modifier_ty = try sema.getBuiltinType(call_src, .CallModifier);
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.resolveConstDefinedValue(block, modifier_src, modifier_ref, .{ .simple = .call_modifier });
@@ -26630,13 +26631,13 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
const body = sema.code.bodySlice(extra_index, body_len);
extra_index += body.len;
- const cc_ty = try sema.getBuiltinType("CallingConvention");
+ const cc_ty = try sema.getBuiltinType(cc_src, .CallingConvention);
const val = try sema.resolveGenericBody(block, cc_src, body, inst, cc_ty, .{ .simple = .@"callconv" });
break :blk try sema.analyzeValueAsCallconv(block, cc_src, val);
} else if (extra.data.bits.has_cc_ref) blk: {
const cc_ref: Zir.Inst.Ref = @enumFromInt(sema.code.extra[extra_index]);
extra_index += 1;
- const cc_ty = try sema.getBuiltinType("CallingConvention");
+ const cc_ty = try sema.getBuiltinType(cc_src, .CallingConvention);
const uncoerced_cc = try sema.resolveInst(cc_ref);
const coerced_cc = try sema.coerce(block, cc_ty, uncoerced_cc, cc_src);
const cc_val = try sema.resolveConstDefinedValue(block, cc_src, coerced_cc, .{ .simple = .@"callconv" });
@@ -26656,7 +26657,7 @@ fn zirFuncFancy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!A
// error by trying to evaluate `std.builtin.CallingConvention.c`, so for consistency,
// let's eval that now and just get the transitive error. (It's guaranteed to error
// because it does the exact `cCallingConvention` call we just did.)
- const cc_type = try sema.getBuiltinType("CallingConvention");
+ const cc_type = try sema.getBuiltinType(cc_src, .CallingConvention);
_ = try sema.namespaceLookupVal(
block,
LazySrcLoc.unneeded,
@@ -26834,7 +26835,7 @@ fn resolvePrefetchOptions(
const zcu = pt.zcu;
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
- const options_ty = try sema.getBuiltinType("PrefetchOptions");
+ const options_ty = try sema.getBuiltinType(src, .PrefetchOptions);
const options = try sema.coerce(block, options_ty, try sema.resolveInst(zir_ref), src);
const rw_src = block.src(.{ .init_field_rw = src.offset.node_offset_builtin_call_arg.builtin_call_node });
@@ -26902,7 +26903,7 @@ fn resolveExternOptions(
const gpa = sema.gpa;
const ip = &zcu.intern_pool;
const options_inst = try sema.resolveInst(zir_ref);
- const extern_options_ty = try sema.getBuiltinType("ExternOptions");
+ const extern_options_ty = try sema.getBuiltinType(src, .ExternOptions);
const options = try sema.coerce(block, extern_options_ty, options_inst, src);
const name_src = block.src(.{ .init_field_name = src.offset.node_offset_builtin_call_arg.builtin_call_node });
@@ -27004,6 +27005,7 @@ fn zirBuiltinExtern(
.zir_index = switch (sema.owner.unwrap()) {
.@"comptime" => |cu| ip.getComptimeUnit(cu).zir_index,
.type => |owner_ty| Type.fromInterned(owner_ty).typeDeclInst(zcu).?,
+ .memoized_state => unreachable,
.nav_ty, .nav_val => |nav| ip.getNav(nav).analysis.?.zir_index,
.func => |func| zir_index: {
const func_info = zcu.funcInfo(func);
@@ -27081,23 +27083,25 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
const src = block.nodeOffset(@bitCast(extended.operand));
const value: Zir.Inst.BuiltinValue = @enumFromInt(extended.small);
- const type_name = switch (value) {
- .atomic_order => "AtomicOrder",
- .atomic_rmw_op => "AtomicRmwOp",
- .calling_convention => "CallingConvention",
- .address_space => "AddressSpace",
- .float_mode => "FloatMode",
- .reduce_op => "ReduceOp",
- .call_modifier => "CallModifier",
- .prefetch_options => "PrefetchOptions",
- .export_options => "ExportOptions",
- .extern_options => "ExternOptions",
- .type_info => "Type",
- .branch_hint => "BranchHint",
+ const ty = switch (value) {
+ // zig fmt: off
+ .atomic_order => try sema.getBuiltinType(src, .AtomicOrder),
+ .atomic_rmw_op => try sema.getBuiltinType(src, .AtomicRmwOp),
+ .calling_convention => try sema.getBuiltinType(src, .CallingConvention),
+ .address_space => try sema.getBuiltinType(src, .AddressSpace),
+ .float_mode => try sema.getBuiltinType(src, .FloatMode),
+ .reduce_op => try sema.getBuiltinType(src, .ReduceOp),
+ .call_modifier => try sema.getBuiltinType(src, .CallModifier),
+ .prefetch_options => try sema.getBuiltinType(src, .PrefetchOptions),
+ .export_options => try sema.getBuiltinType(src, .ExportOptions),
+ .extern_options => try sema.getBuiltinType(src, .ExternOptions),
+ .type_info => try sema.getBuiltinType(src, .Type),
+ .branch_hint => try sema.getBuiltinType(src, .BranchHint),
+ // zig fmt: on
// Values are handled here.
.calling_convention_c => {
- const callconv_ty = try sema.getBuiltinType("CallingConvention");
+ const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
return try sema.namespaceLookupVal(
block,
src,
@@ -27107,7 +27111,7 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
},
.calling_convention_inline => {
comptime assert(@typeInfo(std.builtin.CallingConvention.Tag).@"enum".tag_type == u8);
- const callconv_ty = try sema.getBuiltinType("CallingConvention");
+ const callconv_ty = try sema.getBuiltinType(src, .CallingConvention);
const callconv_tag_ty = callconv_ty.unionTagType(zcu) orelse @panic("std.builtin is corrupt");
const inline_tag_val = try pt.enumValue(
callconv_tag_ty,
@@ -27119,7 +27123,6 @@ fn zirBuiltinValue(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstD
return sema.coerce(block, callconv_ty, Air.internedToRef(inline_tag_val.toIntern()), src);
},
};
- const ty = try sema.getBuiltinType(type_name);
return Air.internedToRef(ty.toIntern());
}
@@ -27158,7 +27161,7 @@ fn zirBranchHint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstDat
const uncoerced_hint = try sema.resolveInst(extra.operand);
const operand_src = block.builtinCallArgSrc(extra.node, 0);
- const hint_ty = try sema.getBuiltinType("BranchHint");
+ const hint_ty = try sema.getBuiltinType(operand_src, .BranchHint);
const coerced_hint = try sema.coerce(block, hint_ty, uncoerced_hint, operand_src);
const hint_val = try sema.resolveConstDefinedValue(block, operand_src, coerced_hint, .{ .simple = .operand_branchHint });
@@ -27603,61 +27606,19 @@ fn explainWhyTypeIsNotPacked(
}
}
-fn prepareSimplePanic(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
- const pt = sema.pt;
- const zcu = pt.zcu;
-
- if (zcu.panic_func_index == .none) {
- zcu.panic_func_index = try sema.getPanicInnerFn(block, src, "call");
- // Here, function body analysis must be queued up so that backends can
- // make calls to this function.
- try zcu.ensureFuncBodyAnalysisQueued(zcu.panic_func_index);
- }
-
- if (zcu.null_stack_trace == .none) {
- const stack_trace_ty = try sema.getBuiltinType("StackTrace");
- try stack_trace_ty.resolveFields(pt);
- const target = zcu.getTarget();
- const ptr_stack_trace_ty = try pt.ptrTypeSema(.{
- .child = stack_trace_ty.toIntern(),
- .flags = .{
- .address_space = target_util.defaultAddressSpace(target, .global_constant),
- },
- });
- const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
- zcu.null_stack_trace = try pt.intern(.{ .opt = .{
- .ty = opt_ptr_stack_trace_ty.toIntern(),
- .val = .none,
- } });
- }
-}
-
/// Backends depend on panic decls being available when lowering safety-checked
/// instructions. This function ensures the panic function will be available to
/// be called during that time.
-fn preparePanicId(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Nav.Index {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const gpa = sema.gpa;
- if (zcu.panic_messages[@intFromEnum(panic_id)].unwrap()) |x| return x;
-
- try sema.prepareSimplePanic(block, src);
-
- const panic_ty = try sema.getBuiltinType("Panic");
- const panic_messages_ty = try sema.getBuiltinInnerType(block, src, panic_ty, "Panic", "messages");
- const msg_nav_index = (sema.namespaceLookup(
- block,
- LazySrcLoc.unneeded,
- panic_messages_ty.getNamespaceIndex(zcu),
- try zcu.intern_pool.getOrPutString(gpa, pt.tid, @tagName(panic_id), .no_embedded_nulls),
- ) catch |err| switch (err) {
- error.AnalysisFail => return error.AnalysisFail,
- error.GenericPoison, error.ComptimeReturn, error.ComptimeBreak => unreachable,
- error.OutOfMemory => |e| return e,
- }).?;
- try sema.ensureNavResolved(src, msg_nav_index, .fully);
- zcu.panic_messages[@intFromEnum(panic_id)] = msg_nav_index.toOptional();
- return msg_nav_index;
+fn preparePanicId(sema: *Sema, src: LazySrcLoc, panic_id: Zcu.PanicId) !InternPool.Index {
+ const zcu = sema.pt.zcu;
+ try sema.ensureMemoizedStateResolved(src, .panic);
+ try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.@"Panic.call");
+ switch (panic_id) {
+ inline else => |ct_panic_id| {
+ const name = "Panic.messages." ++ @tagName(ct_panic_id);
+ return @field(zcu.builtin_decl_values, name);
+ },
+ }
}
fn addSafetyCheck(
@@ -27761,10 +27722,10 @@ fn panicWithMsg(sema: *Sema, block: *Block, src: LazySrcLoc, msg_inst: Air.Inst.
return;
}
- try sema.prepareSimplePanic(block, src);
+ try sema.ensureMemoizedStateResolved(src, .panic);
+ try zcu.ensureFuncBodyAnalysisQueued(zcu.builtin_decl_values.@"Panic.call");
- const panic_func = zcu.funcInfo(zcu.panic_func_index);
- const panic_fn = try sema.analyzeNavVal(block, src, panic_func.owner_nav);
+ const panic_fn = Air.internedToRef(zcu.builtin_decl_values.@"Panic.call");
const null_stack_trace = Air.internedToRef(zcu.null_stack_trace);
const opt_usize_ty = try pt.optionalType(.usize_type);
@@ -27812,7 +27773,7 @@ fn safetyPanicUnwrapError(sema: *Sema, block: *Block, src: LazySrcLoc, err: Air.
if (!zcu.backendSupportsFeature(.panic_fn)) {
_ = try block.addNoOp(.trap);
} else {
- const panic_fn = try getPanicInnerFn(sema, block, src, "unwrapError");
+ const panic_fn = try getBuiltin(sema, src, .@"Panic.unwrapError");
const err_return_trace = try sema.getErrorReturnTrace(block);
const args: [2]Air.Inst.Ref = .{ err_return_trace, err };
try sema.callBuiltin(block, src, Air.internedToRef(panic_fn), .auto, &args, .@"safety check");
@@ -27829,7 +27790,7 @@ fn addSafetyCheckIndexOob(
) !void {
assert(!parent_block.isComptime());
const ok = try parent_block.addBinOp(cmp_op, index, len);
- return addSafetyCheckCall(sema, parent_block, src, ok, "outOfBounds", &.{ index, len });
+ return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.outOfBounds", &.{ index, len });
}
fn addSafetyCheckInactiveUnionField(
@@ -27841,7 +27802,7 @@ fn addSafetyCheckInactiveUnionField(
) !void {
assert(!parent_block.isComptime());
const ok = try parent_block.addBinOp(.cmp_eq, active_tag, wanted_tag);
- return addSafetyCheckCall(sema, parent_block, src, ok, "inactiveUnionField", &.{ active_tag, wanted_tag });
+ return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.inactiveUnionField", &.{ active_tag, wanted_tag });
}
fn addSafetyCheckSentinelMismatch(
@@ -27882,7 +27843,7 @@ fn addSafetyCheckSentinelMismatch(
break :ok try parent_block.addBinOp(.cmp_eq, expected_sentinel, actual_sentinel);
};
- return addSafetyCheckCall(sema, parent_block, src, ok, "sentinelMismatch", &.{
+ return addSafetyCheckCall(sema, parent_block, src, ok, .@"Panic.sentinelMismatch", &.{
expected_sentinel, actual_sentinel,
});
}
@@ -27892,7 +27853,7 @@ fn addSafetyCheckCall(
parent_block: *Block,
src: LazySrcLoc,
ok: Air.Inst.Ref,
- func_name: []const u8,
+ comptime func_decl: Zcu.BuiltinDecl,
args: []const Air.Inst.Ref,
) !void {
assert(!parent_block.isComptime());
@@ -27916,7 +27877,7 @@ fn addSafetyCheckCall(
if (!zcu.backendSupportsFeature(.panic_fn)) {
_ = try fail_block.addNoOp(.trap);
} else {
- const panic_fn = try getPanicInnerFn(sema, &fail_block, src, func_name);
+ const panic_fn = try getBuiltin(sema, src, func_decl);
try sema.callBuiltin(&fail_block, src, Air.internedToRef(panic_fn), .auto, args, .@"safety check");
}
@@ -27925,9 +27886,8 @@ fn addSafetyCheckCall(
/// This does not set `sema.branch_hint`.
fn safetyPanic(sema: *Sema, block: *Block, src: LazySrcLoc, panic_id: Zcu.PanicId) CompileError!void {
- const msg_nav_index = try sema.preparePanicId(block, src, panic_id);
- const msg_inst = try sema.analyzeNavVal(block, src, msg_nav_index);
- try sema.panicWithMsg(block, src, msg_inst, .@"safety check");
+ const msg_val = try sema.preparePanicId(src, panic_id);
+ try sema.panicWithMsg(block, src, Air.internedToRef(msg_val), .@"safety check");
}
fn emitBackwardBranch(sema: *Sema, block: *Block, src: LazySrcLoc) !void {
@@ -32524,6 +32484,19 @@ fn addTypeReferenceEntry(
try zcu.addTypeReference(sema.owner, referenced_type, src);
}
+fn ensureMemoizedStateResolved(sema: *Sema, src: LazySrcLoc, stage: InternPool.MemoizedStateStage) SemaError!void {
+ const pt = sema.pt;
+
+ const unit: AnalUnit = .wrap(.{ .memoized_state = stage });
+ try sema.addReferenceEntry(src, unit);
+ try sema.declareDependency(.{ .memoized_state = stage });
+
+ if (pt.zcu.analysis_in_progress.contains(unit)) {
+ return sema.failWithOwnedErrorMsg(null, try sema.errMsg(src, "dependency loop detected", .{}));
+ }
+ try pt.ensureMemoizedStateUpToDate(stage);
+}
+
pub fn ensureNavResolved(sema: *Sema, src: LazySrcLoc, nav_index: InternPool.Nav.Index, kind: enum { type, fully }) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
@@ -33373,7 +33346,7 @@ fn analyzeSlice(
assert(!block.isComptime());
try sema.requireRuntimeBlock(block, src, runtime_src.?);
const ok = try block.addBinOp(.cmp_lte, start, end);
- try sema.addSafetyCheckCall(block, src, ok, "startGreaterThanEnd", &.{ start, end });
+ try sema.addSafetyCheckCall(block, src, ok, .@"Panic.startGreaterThanEnd", &.{ start, end });
}
const new_len = if (by_length)
try sema.coerce(block, Type.usize, uncasted_end_opt, end_src)
@@ -35493,7 +35466,7 @@ pub fn resolveIes(sema: *Sema, block: *Block, src: LazySrcLoc) CompileError!void
}
}
-pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void {
+pub fn resolveFnTypes(sema: *Sema, fn_ty: Type, src: LazySrcLoc) CompileError!void {
const pt = sema.pt;
const zcu = pt.zcu;
const ip = &zcu.intern_pool;
@@ -35505,7 +35478,7 @@ pub fn resolveFnTypes(sema: *Sema, fn_ty: Type) CompileError!void {
Type.fromInterned(fn_ty_info.return_type).isError(zcu))
{
// Ensure the type exists so that backends can assume that.
- _ = try sema.getBuiltinType("StackTrace");
+ _ = try sema.getBuiltinType(src, .StackTrace);
}
for (0..fn_ty_info.param_types.len) |i| {
@@ -37550,7 +37523,7 @@ pub fn analyzeAsAddressSpace(
) !std.builtin.AddressSpace {
const pt = sema.pt;
const zcu = pt.zcu;
- const addrspace_ty = try sema.getBuiltinType("AddressSpace");
+ const addrspace_ty = try sema.getBuiltinType(src, .AddressSpace);
const coerced = try sema.coerce(block, addrspace_ty, air_ref, src);
const addrspace_val = try sema.resolveConstDefinedValue(block, src, coerced, .{ .simple = .@"addrspace" });
const address_space = zcu.toEnum(std.builtin.AddressSpace, addrspace_val);
@@ -38747,69 +38720,15 @@ const ComptimeLoadResult = @import("Sema/comptime_ptr_access.zig").ComptimeLoadR
const storeComptimePtr = @import("Sema/comptime_ptr_access.zig").storeComptimePtr;
const ComptimeStoreResult = @import("Sema/comptime_ptr_access.zig").ComptimeStoreResult;
-fn getPanicInnerFn(
- sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
- inner_name: []const u8,
-) !InternPool.Index {
- const gpa = sema.gpa;
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const outer_ty = try sema.getBuiltinType("Panic");
- const inner_name_ip = try ip.getOrPutString(gpa, pt.tid, inner_name, .no_embedded_nulls);
- const opt_fn_ref = try namespaceLookupVal(sema, block, src, outer_ty.getNamespaceIndex(zcu), inner_name_ip);
- const fn_ref = opt_fn_ref orelse return sema.fail(block, src, "std.builtin.Panic missing {s}", .{inner_name});
- const fn_val = try sema.resolveConstValue(block, src, fn_ref, .{ .simple = .panic_handler });
- if (fn_val.typeOf(zcu).zigTypeTag(zcu) != .@"fn") {
- return sema.fail(block, src, "std.builtin.Panic.{s} is not a function", .{inner_name});
- }
- // Better not to queue up function body analysis because the function might be generic, and
- // the semantic analysis for the call will already queue if necessary.
- return fn_val.toIntern();
-}
-
-fn getBuiltinType(sema: *Sema, name: []const u8) SemaError!Type {
- const pt = sema.pt;
- const ty_inst = try sema.getBuiltin(name);
- const ty = Type.fromInterned(ty_inst.toInterned() orelse @panic("std.builtin is corrupt"));
- try ty.resolveFully(pt);
- return ty;
-}
-
-fn getBuiltinInnerType(
- sema: *Sema,
- block: *Block,
- src: LazySrcLoc,
- outer_ty: Type,
- /// Relative to "std.builtin".
- compile_error_parent_name: []const u8,
- inner_name: []const u8,
-) !Type {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const gpa = sema.gpa;
- const inner_name_ip = try ip.getOrPutString(gpa, pt.tid, inner_name, .no_embedded_nulls);
- const opt_nav = try sema.namespaceLookup(block, src, outer_ty.getNamespaceIndex(zcu), inner_name_ip);
- const nav = opt_nav orelse return sema.fail(block, src, "std.builtin.{s} missing {s}", .{
- compile_error_parent_name, inner_name,
- });
- try sema.ensureNavResolved(src, nav, .fully);
- const val = Value.fromInterned(ip.getNav(nav).status.fully_resolved.val);
- const ty = val.toType();
- try ty.resolveFully(pt);
- return ty;
+pub fn getBuiltinType(sema: *Sema, src: LazySrcLoc, comptime decl: Zcu.BuiltinDecl) SemaError!Type {
+ comptime assert(decl.kind() == .type);
+ try sema.ensureMemoizedStateResolved(src, decl.stage());
+ return .fromInterned(@field(sema.pt.zcu.builtin_decl_values, @tagName(decl)));
}
-
-fn getBuiltin(sema: *Sema, name: []const u8) SemaError!Air.Inst.Ref {
- const pt = sema.pt;
- const zcu = pt.zcu;
- const ip = &zcu.intern_pool;
- const nav = try pt.getBuiltinNav(name);
- try pt.ensureNavValUpToDate(nav);
- return Air.internedToRef(ip.getNav(nav).status.fully_resolved.val);
+pub fn getBuiltin(sema: *Sema, src: LazySrcLoc, comptime decl: Zcu.BuiltinDecl) SemaError!InternPool.Index {
+ comptime assert(decl.kind() != .type);
+ try sema.ensureMemoizedStateResolved(src, decl.stage());
+ return @field(sema.pt.zcu.builtin_decl_values, @tagName(decl));
}
pub const NavPtrModifiers = struct {
@@ -38877,3 +38796,77 @@ pub fn resolveNavPtrModifiers(
.@"addrspace" = @"addrspace",
};
}
+
+pub fn analyzeMemoizedState(sema: *Sema, block: *Block, src: LazySrcLoc, builtin_namespace: InternPool.NamespaceIndex, stage: InternPool.MemoizedStateStage) CompileError!bool {
+ const pt = sema.pt;
+ const zcu = pt.zcu;
+ const ip = &zcu.intern_pool;
+ const gpa = zcu.gpa;
+
+ var any_changed = false;
+
+ inline for (comptime std.enums.values(Zcu.BuiltinDecl)) |builtin_decl| {
+ if (stage == comptime builtin_decl.stage()) {
+ const parent_ns: Zcu.Namespace.Index, const parent_name: []const u8, const name: []const u8 = switch (comptime builtin_decl.access()) {
+ .direct => |name| .{ builtin_namespace, "std.builtin", name },
+ .nested => |nested| access: {
+ const parent_ty: Type = .fromInterned(@field(zcu.builtin_decl_values, @tagName(nested[0])));
+ const parent_ns = parent_ty.getNamespace(zcu).unwrap() orelse {
+ return sema.fail(block, src, "std.builtin.{s} is not a container type", .{@tagName(nested[0])});
+ };
+ break :access .{ parent_ns, "std.builtin." ++ @tagName(nested[0]), nested[1] };
+ },
+ };
+
+ const name_nts = try ip.getOrPutString(gpa, pt.tid, name, .no_embedded_nulls);
+ const result = try sema.namespaceLookupVal(block, src, parent_ns, name_nts) orelse
+ return sema.fail(block, src, "{s} missing {s}", .{ parent_name, name });
+
+ const val = try sema.resolveConstDefinedValue(block, src, result, null);
+
+ switch (builtin_decl.kind()) {
+ .type => if (val.typeOf(zcu).zigTypeTag(zcu) != .type) {
+ return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name });
+ } else {
+ try val.toType().resolveFully(pt);
+ },
+ .func => if (val.typeOf(zcu).zigTypeTag(zcu) != .@"fn") {
+ return sema.fail(block, src, "{s}.{s} is not a function", .{ parent_name, name });
+ },
+ .string => {
+ const ty = val.typeOf(zcu);
+ if (!ty.isSinglePointer(zcu) or
+ !ty.isConstPtr(zcu) or
+ ty.childType(zcu).zigTypeTag(zcu) != .array or
+ ty.childType(zcu).childType(zcu).toIntern() != .u8_type)
+ {
+ return sema.fail(block, src, "{s}.{s} is not a valid string", .{ parent_name, name });
+ }
+ },
+ }
+
+ const prev = @field(zcu.builtin_decl_values, @tagName(builtin_decl));
+ if (val.toIntern() != prev) {
+ @field(zcu.builtin_decl_values, @tagName(builtin_decl)) = val.toIntern();
+ any_changed = true;
+ }
+ }
+ }
+
+ if (stage == .panic) {
+ // We use `getBuiltinType` because this is from an earlier stage.
+ const stack_trace_ty = try sema.getBuiltinType(src, .StackTrace);
+ const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty);
+ const opt_ptr_stack_trace_ty = try pt.optionalType(ptr_stack_trace_ty.toIntern());
+ const null_stack_trace = try pt.intern(.{ .opt = .{
+ .ty = opt_ptr_stack_trace_ty.toIntern(),
+ .val = .none,
+ } });
+ if (null_stack_trace != zcu.null_stack_trace) {
+ zcu.null_stack_trace = null_stack_trace;
+ any_changed = true;
+ }
+ }
+
+ return any_changed;
+}
src/Zcu.zig
@@ -217,15 +217,212 @@ all_type_references: std.ArrayListUnmanaged(TypeReference) = .empty,
/// Freelist of indices in `all_type_references`.
free_type_references: std.ArrayListUnmanaged(u32) = .empty,
-panic_messages: [PanicId.len]InternPool.Nav.Index.Optional = .{.none} ** PanicId.len,
-/// The panic function body.
-panic_func_index: InternPool.Index = .none,
+/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the field.
+builtin_decl_values: BuiltinDecl.Memoized = .{},
+/// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = .panic })`.
null_stack_trace: InternPool.Index = .none,
generation: u32 = 0,
pub const PerThread = @import("Zcu/PerThread.zig");
+/// Names of declarations in `std.builtin` whose values are memoized in a `BuiltinDecl.Memoized`.
+/// The name must exactly match the declaration name, as comptime logic is used to compute the namespace accesses.
+/// Parent namespaces must be before their children in this enum. For instance, `.Type` must be before `.@"Type.Fn"`.
+/// Additionally, parent namespaces must be resolved in the same stage as their children; see `BuiltinDecl.stage`.
+pub const BuiltinDecl = enum {
+ Signedness,
+ AddressSpace,
+ CallingConvention,
+ returnError,
+ StackTrace,
+ SourceLocation,
+ CallModifier,
+ AtomicOrder,
+ AtomicRmwOp,
+ ReduceOp,
+ FloatMode,
+ PrefetchOptions,
+ ExportOptions,
+ ExternOptions,
+ BranchHint,
+
+ Type,
+ @"Type.Fn",
+ @"Type.Fn.Param",
+ @"Type.Int",
+ @"Type.Float",
+ @"Type.Pointer",
+ @"Type.Pointer.Size",
+ @"Type.Array",
+ @"Type.Vector",
+ @"Type.Optional",
+ @"Type.Error",
+ @"Type.ErrorUnion",
+ @"Type.EnumField",
+ @"Type.Enum",
+ @"Type.Union",
+ @"Type.UnionField",
+ @"Type.Struct",
+ @"Type.StructField",
+ @"Type.ContainerLayout",
+ @"Type.Opaque",
+ @"Type.Declaration",
+
+ Panic,
+ @"Panic.call",
+ @"Panic.sentinelMismatch",
+ @"Panic.unwrapError",
+ @"Panic.outOfBounds",
+ @"Panic.startGreaterThanEnd",
+ @"Panic.inactiveUnionField",
+ @"Panic.messages",
+ @"Panic.messages.reached_unreachable",
+ @"Panic.messages.unwrap_null",
+ @"Panic.messages.cast_to_null",
+ @"Panic.messages.incorrect_alignment",
+ @"Panic.messages.invalid_error_code",
+ @"Panic.messages.cast_truncated_data",
+ @"Panic.messages.negative_to_unsigned",
+ @"Panic.messages.integer_overflow",
+ @"Panic.messages.shl_overflow",
+ @"Panic.messages.shr_overflow",
+ @"Panic.messages.divide_by_zero",
+ @"Panic.messages.exact_division_remainder",
+ @"Panic.messages.integer_part_out_of_bounds",
+ @"Panic.messages.corrupt_switch",
+ @"Panic.messages.shift_rhs_too_big",
+ @"Panic.messages.invalid_enum_value",
+ @"Panic.messages.for_len_mismatch",
+ @"Panic.messages.memcpy_len_mismatch",
+ @"Panic.messages.memcpy_alias",
+ @"Panic.messages.noreturn_returned",
+
+ VaList,
+
+ /// Determines what kind of validation will be done to the decl's value.
+ pub fn kind(decl: BuiltinDecl) enum { type, func, string } {
+ return switch (decl) {
+ .returnError => .func,
+
+ .StackTrace,
+ .CallingConvention,
+ .SourceLocation,
+ .Signedness,
+ .AddressSpace,
+ .VaList,
+ .CallModifier,
+ .AtomicOrder,
+ .AtomicRmwOp,
+ .ReduceOp,
+ .FloatMode,
+ .PrefetchOptions,
+ .ExportOptions,
+ .ExternOptions,
+ .BranchHint,
+ => .type,
+
+ .Type,
+ .@"Type.Fn",
+ .@"Type.Fn.Param",
+ .@"Type.Int",
+ .@"Type.Float",
+ .@"Type.Pointer",
+ .@"Type.Pointer.Size",
+ .@"Type.Array",
+ .@"Type.Vector",
+ .@"Type.Optional",
+ .@"Type.Error",
+ .@"Type.ErrorUnion",
+ .@"Type.EnumField",
+ .@"Type.Enum",
+ .@"Type.Union",
+ .@"Type.UnionField",
+ .@"Type.Struct",
+ .@"Type.StructField",
+ .@"Type.ContainerLayout",
+ .@"Type.Opaque",
+ .@"Type.Declaration",
+ => .type,
+
+ .Panic => .type,
+
+ .@"Panic.call",
+ .@"Panic.sentinelMismatch",
+ .@"Panic.unwrapError",
+ .@"Panic.outOfBounds",
+ .@"Panic.startGreaterThanEnd",
+ .@"Panic.inactiveUnionField",
+ => .func,
+
+ .@"Panic.messages" => .type,
+
+ .@"Panic.messages.reached_unreachable",
+ .@"Panic.messages.unwrap_null",
+ .@"Panic.messages.cast_to_null",
+ .@"Panic.messages.incorrect_alignment",
+ .@"Panic.messages.invalid_error_code",
+ .@"Panic.messages.cast_truncated_data",
+ .@"Panic.messages.negative_to_unsigned",
+ .@"Panic.messages.integer_overflow",
+ .@"Panic.messages.shl_overflow",
+ .@"Panic.messages.shr_overflow",
+ .@"Panic.messages.divide_by_zero",
+ .@"Panic.messages.exact_division_remainder",
+ .@"Panic.messages.integer_part_out_of_bounds",
+ .@"Panic.messages.corrupt_switch",
+ .@"Panic.messages.shift_rhs_too_big",
+ .@"Panic.messages.invalid_enum_value",
+ .@"Panic.messages.for_len_mismatch",
+ .@"Panic.messages.memcpy_len_mismatch",
+ .@"Panic.messages.memcpy_alias",
+ .@"Panic.messages.noreturn_returned",
+ => .string,
+ };
+ }
+
+ /// Resolution of these values is done in three distinct stages:
+ /// * Resolution of `std.builtin.Panic` and everything under it
+ /// * Resolution of `VaList`
+ /// * Everything else
+ ///
+ /// Panics are separated because they are provided by the user, so must be able to use
+ /// things like reification.
+ ///
+ /// `VaList` is separate because its value depends on the target, so it needs some reflection
+ /// machinery to work; additionally, it is `@compileError` on some targets, so must be referenced
+ /// by itself.
+ pub fn stage(decl: BuiltinDecl) InternPool.MemoizedStateStage {
+ if (decl == .VaList) return .va_list;
+
+ if (@intFromEnum(decl) <= @intFromEnum(BuiltinDecl.@"Type.Declaration")) {
+ return .main;
+ } else {
+ return .panic;
+ }
+ }
+
+ /// Based on the tag name, determines how to access this decl; either as a direct child of the
+ /// `std.builtin` namespace, or as a child of some preceding `BuiltinDecl` value.
+ pub fn access(decl: BuiltinDecl) union(enum) {
+ direct: []const u8,
+ nested: struct { BuiltinDecl, []const u8 },
+ } {
+ @setEvalBranchQuota(2000);
+ return switch (decl) {
+ inline else => |tag| {
+ const name = @tagName(tag);
+ const split = (comptime std.mem.lastIndexOfScalar(u8, name, '.')) orelse return .{ .direct = name };
+ const parent = @field(BuiltinDecl, name[0..split]);
+ comptime assert(@intFromEnum(parent) < @intFromEnum(tag)); // dependencies ordered correctly
+ return .{ .nested = .{ parent, name[split + 1 ..] } };
+ },
+ };
+ }
+
+ const Memoized = std.enums.EnumFieldStruct(BuiltinDecl, InternPool.Index, .none);
+};
+
pub const PanicId = enum {
reached_unreachable,
unwrap_null,
@@ -247,8 +444,6 @@ pub const PanicId = enum {
memcpy_len_mismatch,
memcpy_alias,
noreturn_returned,
-
- pub const len = @typeInfo(PanicId).@"enum".fields.len;
};
pub const GlobalErrorSet = std.AutoArrayHashMapUnmanaged(InternPool.NullTerminatedString, void);
@@ -2454,6 +2649,7 @@ pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void {
.nav_ty => |nav| try zcu.markPoDependeeUpToDate(.{ .nav_ty = nav }),
.type => |ty| try zcu.markPoDependeeUpToDate(.{ .interned = ty }),
.func => |func| try zcu.markPoDependeeUpToDate(.{ .interned = func }),
+ .memoized_state => |stage| try zcu.markPoDependeeUpToDate(.{ .memoized_state = stage }),
}
}
}
@@ -2468,6 +2664,7 @@ fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUni
.nav_ty => |nav| .{ .nav_ty = nav },
.type => |ty| .{ .interned = ty },
.func => |func_index| .{ .interned = func_index }, // IES
+ .memoized_state => |stage| .{ .memoized_state = stage },
};
log.debug("potentially outdated dependee: {}", .{zcu.fmtDependee(dependee)});
var it = ip.dependencyIterator(dependee);
@@ -2553,6 +2750,12 @@ pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit {
.type => |ty| .{ .interned = ty },
.nav_val => |nav| .{ .nav_val = nav },
.nav_ty => |nav| .{ .nav_ty = nav },
+ .memoized_state => {
+ // If we've hit a loop and some `.memoized_state` is outdated, we should make that choice eagerly.
+ // In general, it's good to resolve this early on, since -- for instance -- almost every function
+ // references the panic handler.
+ return unit;
+ },
});
while (it.next()) |_| n += 1;
@@ -3462,7 +3665,7 @@ fn resolveReferencesInner(zcu: *Zcu) !std.AutoHashMapUnmanaged(AnalUnit, ?Resolv
const other: AnalUnit = .wrap(switch (unit.unwrap()) {
.nav_val => |n| .{ .nav_ty = n },
.nav_ty => |n| .{ .nav_val = n },
- .@"comptime", .type, .func => break :queue_paired,
+ .@"comptime", .type, .func, .memoized_state => break :queue_paired,
});
if (result.contains(other)) break :queue_paired;
try unit_queue.put(gpa, other, kv.value); // same reference location
@@ -3597,6 +3800,7 @@ fn formatAnalUnit(data: struct { unit: AnalUnit, zcu: *Zcu }, comptime fmt: []co
const nav = zcu.funcInfo(func).owner_nav;
return writer.print("func('{}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @intFromEnum(func) });
},
+ .memoized_state => return writer.writeAll("memoized_state"),
}
}
fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, comptime fmt: []const u8, options: std.fmt.FormatOptions, writer: anytype) !void {
@@ -3642,6 +3846,7 @@ fn formatDependee(data: struct { dependee: InternPool.Dependee, zcu: *Zcu }, com
const file_path = zcu.fileByIndex(info.file).sub_file_path;
return writer.print("namespace('{s}', %{d}, '{}')", .{ file_path, @intFromEnum(info.inst), k.name.fmt(ip) });
},
+ .memoized_state => return writer.writeAll("memoized_state"),
}
}