incremental: new AnalUnit to group dependencies on std.builtin decls

This commit reworks how values like the panic handler function are
memoized during a compiler invocation. Previously, the value was
resolved by whichever analysis requested it first, and cached on `Zcu`.
This is problematic for incremental compilation, as after the initial
resolution, no dependencies are marked by users of this memoized state.
This is arguably acceptable for `std.builtin`, but it's definitely not
acceptable for the panic handler/messages, because those can be set by
the user (`std.builtin.Panic` checks `@import("root").Panic`).

So, here we introduce a new kind of `AnalUnit`, called `memoized_state`.
There are 3 such units:
* `.{ .memoized_state = .va_list }` resolves the type `std.builtin.VaList`
* `.{ .memoized_state = .panic }` resolves `std.Panic`
* `.{ .memoized_state = .main }` resolves everything else we want

These units essentially "bundle" the resolution of their corresponding
declarations, storing the results into fields on `Zcu`. This way, when,
for instance, a function wants to call the panic handler, it simply runs
`ensureMemoizedStateResolved`, registering one dependency, and pulls the
values from the `Zcu`. This "bundling" minimizes dependency edges. The 3
units are separated to allow them to act independently: for instance,
the panic handler can use `std.builtin.Type` without triggering a
dependency loop.
This commit is contained in:
mlugg 2025-01-04 05:09:02 +00:00
parent fd62912787
commit f01029c4af
No known key found for this signature in database
GPG Key ID: 3F5B7DCCBF4AF02E
6 changed files with 639 additions and 254 deletions

View File

@ -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) {

View File

@ -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) {

View File

@ -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();
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 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;
}
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;
}

View File

@ -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"),
}
}

View File

@ -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;

View File

@ -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);