zig

fork of https://codeberg.org/ziglang/zig
Log | Files | Refs | README | LICENSE

commit a9bfc94ee65f1dafe5c67bb8fbd58cd2372cfd28 (tree)
parent b8997f871fc63cee28d94168330d84f177543f2c
Author: Matthew Lugg <mlugg@mlugg.co.uk>
Date:   Mon,  2 Feb 2026 13:32:06 +0000

compiler: small misc cleanups

Diffstat:
Mlib/std/zig.zig | 4++--
Msrc/Compilation.zig | 23++++++++++++-----------
Msrc/Sema.zig | 140+++++++++++++++++++++++++++++++++++++++++++------------------------------------
Msrc/Zcu/PerThread.zig | 50++++----------------------------------------------
4 files changed, 94 insertions(+), 123 deletions(-)

diff --git a/lib/std/zig.zig b/lib/std/zig.zig @@ -868,7 +868,7 @@ pub const SimpleComptimeReason = enum(u32) { casted_to_comptime_enum, casted_to_comptime_int, casted_to_comptime_float, - panic_handler, + std_builtin_decl, pub fn message(r: SimpleComptimeReason) []const u8 { return switch (r) { @@ -957,7 +957,7 @@ pub const SimpleComptimeReason = enum(u32) { .casted_to_comptime_enum => "value casted to enum with 'comptime_int' tag type must be comptime-known", .casted_to_comptime_int => "value casted to 'comptime_int' must be comptime-known", .casted_to_comptime_float => "value casted to 'comptime_float' must be comptime-known", - .panic_handler => "panic handler must be comptime-known", + .std_builtin_decl => "'std.builtin' declaration values must be comptime-known", // zig fmt: on }; } diff --git a/src/Compilation.zig b/src/Compilation.zig @@ -986,7 +986,9 @@ const Job = union(enum) { /// If the unit is a *test* function, an `analyze_func` job will also be queued. analyze_unit: InternPool.AnalUnit, /// The main source file for the module needs to be analyzed. - analyze_mod: *Package.Module, + /// For every module which is an analysis root, analyze the main struct type of the module's + /// root source file. This is how semantic analysis begins. + analyze_roots, /// The value is the index into `windows_libs`. windows_import_lib: usize, @@ -1396,7 +1398,6 @@ pub const MiscTask = enum { wasi_libc_crt_file, compiler_rt, libzigc, - analyze_mod, link_depfile, docs_copy, docs_wasm, @@ -4840,9 +4841,7 @@ fn performAllTheWork( try zcu.flushRetryableFailures(); // It's analysis time! Queue up our initial analysis. - for (zcu.analysisRoots()) |mod| { - try comp.queueJob(.{ .analyze_mod = mod }); - } + try comp.queueJob(.analyze_roots); zcu.sema_prog_node = main_progress_node.start("Semantic Analysis", 0); if (comp.bin_file != null) { @@ -5275,15 +5274,17 @@ fn processOneJob(tid: Zcu.PerThread.Id, comp: *Compilation, job: Job) JobError!v try pt.zcu.ensureFuncBodyAnalysisQueued(ip.getNav(nav).status.fully_resolved.val); } }, - .analyze_mod => |mod| { - const tracy_trace = traceNamed(@src(), "analyze_mod"); + .analyze_roots => { + const tracy_trace = traceNamed(@src(), "analyze_roots"); defer tracy_trace.end(); - const pt: Zcu.PerThread = .activate(comp.zcu.?, tid); + const zcu = comp.zcu.?; + const pt: Zcu.PerThread = .activate(zcu, tid); defer pt.deactivate(); - - const mod_root_file = pt.zcu.module_roots.get(mod).?.unwrap().?; - try pt.ensureFileAnalyzed(mod_root_file); + for (zcu.analysisRoots()) |analysis_root_mod| { + const analysis_root_file = zcu.module_roots.get(analysis_root_mod).?.unwrap().?; + try pt.ensureFileAnalyzed(analysis_root_file); + } }, .windows_import_lib => |index| { const tracy_trace = traceNamed(@src(), "windows_import_lib"); diff --git a/src/Sema.zig b/src/Sema.zig @@ -2308,6 +2308,7 @@ pub fn resolveConstValue( /// being comptime-resolved is that the block is being comptime-evaluated. reason: ?ComptimeReason, ) CompileError!Value { + assert(reason != null or block.isComptime()); return sema.resolveValue(inst) orelse { return sema.failWithNeededComptime(block, src, reason); }; @@ -12927,6 +12928,8 @@ fn zirImport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air. try pt.ensureFileAnalyzed(file_index); const ty: Type = .fromInterned(zcu.fileRootType(file_index)); try sema.addTypeReferenceEntry(operand_src, ty); + // No need for `ensureNamespaceUpToDate`, because `Zcu.PerThread.updateFileNamespace` + // already made sure that all root file structs have up-to-date namespaces. return .fromType(ty); }, .zon => { @@ -16342,7 +16345,6 @@ fn zirTypeInfo(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Ai const alignment_val = try pt.intValue(.comptime_int, bytes: { if (info.flags.alignment.toByteUnits()) |b| break :bytes b; const elem_ty: Type = .fromInterned(info.child); - // MLUGG TODO: this resolution is sus, but i doubt i'll solve it in this branch try sema.ensureLayoutResolved(elem_ty, src); break :bytes elem_ty.abiAlignment(zcu).toByteUnits().?; }); @@ -18942,12 +18944,13 @@ fn structInitAnon( .file_scope = block.getFileScopeIndex(zcu), .generation = zcu.generation, }); + errdefer pt.destroyNamespace(new_namespace_index); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; try sema.addTypeReferenceEntry(src, struct_ty); + // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty. try sema.ensureLayoutResolved(struct_ty, src); _ = opt_runtime_index orelse { @@ -20150,6 +20153,7 @@ fn zirReifyStruct( })) { .existing => |ty| { try sema.addTypeReferenceEntry(src, .fromInterned(ty)); + // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty. return .fromIntern(ty); }, .wip => |wip| { @@ -20210,9 +20214,9 @@ fn zirReifyStruct( .file_scope = block.getFileScopeIndex(zcu), .generation = zcu.generation, }); - try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); + errdefer pt.destroyNamespace(new_namespace_index); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - + try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); return .fromIntern(wip.finish(ip, new_namespace_index)); }, } @@ -20393,6 +20397,7 @@ fn zirReifyUnion( })) { .existing => |ty| { try sema.addTypeReferenceEntry(src, .fromInterned(ty)); + // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty. return .fromIntern(ty); }, .wip => |wip| { @@ -20430,9 +20435,9 @@ fn zirReifyUnion( .file_scope = block.getFileScopeIndex(zcu), .generation = zcu.generation, }); + errdefer pt.destroyNamespace(new_namespace_index); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); - return .fromIntern(wip.finish(ip, new_namespace_index)); }, } @@ -20557,6 +20562,7 @@ fn zirReifyEnum( })) { .existing => |ty| { try sema.addTypeReferenceEntry(src, .fromInterned(ty)); + // No need for `ensureNamespaceUpToDate` because this type's namespace is always empty. return .fromIntern(ty); }, .wip => |wip| { @@ -20581,10 +20587,9 @@ fn zirReifyEnum( .file_scope = block.getFileScopeIndex(zcu), .generation = zcu.generation, }); - - try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); + errdefer pt.destroyNamespace(new_namespace_index); if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - + try sema.addTypeReferenceEntry(src, .fromInterned(wip.index)); return .fromIntern(wip.finish(ip, new_namespace_index)); }, } @@ -33861,7 +33866,7 @@ pub fn resolveNavPtrModifiers( }; } -pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, builtin_namespace: InternPool.NamespaceIndex, stage: InternPool.MemoizedStateStage) CompileError!bool { +pub fn analyzeMemoizedState(sema: *Sema, stage: InternPool.MemoizedStateStage) CompileError!bool { const pt = sema.pt; const zcu = pt.zcu; const comp = zcu.comp; @@ -33869,53 +33874,87 @@ pub fn analyzeMemoizedState(sema: *Sema, block: *Block, simple_src: LazySrcLoc, const io = comp.io; const ip = &zcu.intern_pool; + // This `Block` acts kind of like it's evaluating a `comptime` declaration in the root source + // file of the standard library. In particular, its namespace is the root std namespace. + var block: Block = block: { + // Get the main struct type of the root source file of `std`. No need for a reference entry + // because `std` is always an analysis root. + const std_file_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?; + try pt.ensureFileAnalyzed(std_file_index); + const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index)); + break :block .{ + .parent = null, + .sema = sema, + .namespace = std_type.getNamespaceIndex(zcu), + .instructions = .empty, + .inlining = null, + .comptime_reason = null, + .src_base_inst = std_type.typeDeclInst(zcu).?, + .type_name_ctx = .empty, + }; + }; + defer block.instructions.deinit(gpa); + + const std_builtin_ty: Type = ty: { + const std_src = block.nodeOffset(.zero); + const decl_name = try ip.getOrPutString(gpa, io, pt.tid, "builtin", .no_embedded_nulls); + const nav = try sema.namespaceLookup(&block, std_src, block.namespace, decl_name) orelse { + return sema.fail(&block, std_src, "'std' missing 'builtin'", .{}); + }; + const uncoerced_val = try sema.analyzeNavVal(&block, std_src, nav); + const decl_src: LazySrcLoc = .{ + .base_node_inst = ip.getNav(nav).srcInst(ip), + .offset = .nodeOffset(.zero), + }; + break :ty try sema.analyzeAsType(&block, decl_src, .std_builtin_decl, uncoerced_val); + }; + 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 }, + const parent_ns_ty: Type, const parent_name: []const u8, const name: []const u8 = switch (comptime builtin_decl.access()) { + .direct => |name| .{ std_builtin_ty, "std.builtin", name }, .nested => |nested| access: { - const parent_ty: Type = .fromInterned(zcu.builtin_decl_values.get(nested[0])); - const parent_ns = parent_ty.getNamespace(zcu).unwrap() orelse { - return sema.fail(block, simple_src, "std.builtin.{s} is not a container type", .{@tagName(nested[0])}); - }; - break :access .{ parent_ns, "std.builtin." ++ @tagName(nested[0]), nested[1] }; + const parent_decl, const name = nested; + const parent_ty: Type = .fromInterned(zcu.builtin_decl_values.get(parent_decl)); + break :access .{ parent_ty, "std.builtin." ++ @tagName(parent_decl), name }; }, }; + const parent_ns = parent_ns_ty.getNamespace(zcu).unwrap() orelse { + return sema.fail(&block, block.nodeOffset(.zero), "'{s}' is not a container type", .{parent_name}); + }; + const parent_ty_src = parent_ns_ty.srcLoc(zcu); const name_nts = try ip.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls); - const nav = try sema.namespaceLookup(block, simple_src, parent_ns, name_nts) orelse - return sema.fail(block, simple_src, "{s} missing {s}", .{ parent_name, name }); + const nav = try sema.namespaceLookup(&block, parent_ty_src, parent_ns, name_nts) orelse { + return sema.fail(&block, parent_ty_src, "'{s}' missing '{s}'", .{ parent_name, name }); + }; + const uncoerced_val = try sema.analyzeNavVal(&block, parent_ty_src, nav); - const src: LazySrcLoc = .{ + const decl_src: LazySrcLoc = .{ .base_node_inst = ip.getNav(nav).srcInst(ip), .offset = .nodeOffset(.zero), }; - const result = try sema.analyzeNavVal(block, src, nav); - - const uncoerced_val = try sema.resolveConstDefinedValue(block, src, result, null); const val: Value = switch (builtin_decl.kind()) { - .type => if (uncoerced_val.typeOf(zcu).zigTypeTag(zcu) != .type) { - return sema.fail(block, src, "{s}.{s} is not a type", .{ parent_name, name }); - } else val: { - try sema.ensureLayoutResolved(uncoerced_val.toType(), src); - break :val uncoerced_val; + .type => val: { + const ty = try sema.analyzeAsType(&block, decl_src, .std_builtin_decl, uncoerced_val); + try sema.ensureLayoutResolved(ty, decl_src); + break :val ty.toValue(); }, .func => val: { const func_ty = try sema.getExpectedBuiltinFnType(builtin_decl); - const coerced = try sema.coerce(block, func_ty, Air.internedToRef(uncoerced_val.toIntern()), src); - break :val .fromInterned(coerced.toInterned().?); + const coerced = try sema.coerce(&block, func_ty, uncoerced_val, decl_src); + break :val try sema.resolveConstDefinedValue(&block, decl_src, coerced, .{ .simple = .std_builtin_decl }); }, .string => val: { - const coerced = try sema.coerce(block, .slice_const_u8, Air.internedToRef(uncoerced_val.toIntern()), src); - break :val .fromInterned(coerced.toInterned().?); + const coerced = try sema.coerce(&block, .slice_const_u8, uncoerced_val, decl_src); + break :val try sema.resolveConstDefinedValue(&block, decl_src, coerced, .{ .simple = .std_builtin_decl }); }, }; - const prev = zcu.builtin_decl_values.get(builtin_decl); - if (val.toIntern() != prev) { + if (zcu.builtin_decl_values.get(builtin_decl) != val.toIntern()) { zcu.builtin_decl_values.set(builtin_decl, val.toIntern()); any_changed = true; } @@ -34147,21 +34186,15 @@ fn zirStructDecl( }); errdefer pt.destroyNamespace(new_namespace_index); try pt.scanNamespace(new_namespace_index, struct_decl.decls); - if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; try sema.addTypeReferenceEntry(src, ty); - - // Make sure we update the namespace if the declaration is re-analyzed, to pick - // up on e.g. changed comptime decls. - // TODO MLUGG: me no likey, maybe model namespaces less badly idk try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); - return .fromIntern(ty.toIntern()); + return .fromType(ty); } fn zirUnionDecl( sema: *Sema, @@ -34218,7 +34251,6 @@ fn zirUnionDecl( .wip => |wip| ty: { errdefer wip.cancel(ip, pt.tid); try sema.setTypeName(block, &wip, union_decl.name_strategy, "union", inst); - const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), .owner_type = wip.index, @@ -34226,23 +34258,16 @@ fn zirUnionDecl( .generation = zcu.generation, }); errdefer pt.destroyNamespace(new_namespace_index); - try pt.scanNamespace(new_namespace_index, union_decl.decls); - if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; try sema.addTypeReferenceEntry(src, ty); - - // Make sure we update the namespace if the declaration is re-analyzed, to pick - // up on e.g. changed comptime decls. - // TODO MLUGG: me no likey, maybe model namespaces less badly idk try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); - return .fromIntern(ty.toIntern()); + return .fromType(ty); } fn zirEnumDecl( sema: *Sema, @@ -34277,9 +34302,7 @@ fn zirEnumDecl( .existing => |ty| .fromInterned(ty), .wip => |wip| ty: { errdefer wip.cancel(ip, pt.tid); - try sema.setTypeName(block, &wip, enum_decl.name_strategy, "enum", inst); - const new_namespace_index: InternPool.NamespaceIndex = try pt.createNamespace(.{ .parent = block.namespace.toOptional(), .owner_type = wip.index, @@ -34287,23 +34310,16 @@ fn zirEnumDecl( .generation = zcu.generation, }); errdefer pt.destroyNamespace(new_namespace_index); - try pt.scanNamespace(new_namespace_index, enum_decl.decls); - if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - break :ty .fromInterned(wip.finish(ip, new_namespace_index)); }, }; try sema.addTypeReferenceEntry(src, ty); - - // Make sure we update the namespace if the declaration is re-analyzed, to pick - // up on e.g. changed comptime decls. - // TODO MLUGG: me no likey, maybe model namespaces less badly idk try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); - return .fromIntern(ty.toIntern()); + return .fromType(ty); } fn zirOpaqueDecl( sema: *Sema, @@ -34350,11 +34366,7 @@ fn zirOpaqueDecl( }; try sema.addTypeReferenceEntry(src, ty); - - // Make sure we update the namespace if the declaration is re-analyzed, to pick - // up on e.g. changed comptime decls. - // TODO MLUGG: me no likey, maybe model namespaces less badly idk try pt.ensureNamespaceUpToDate(ty.getNamespaceIndex(zcu)); - return .fromIntern(ty.toIntern()); + return .fromType(ty); } diff --git a/src/Zcu/PerThread.zig b/src/Zcu/PerThread.zig @@ -688,6 +688,8 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca if (zcu.fileRootType(file_index) != .none) return; // already good + if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1; + const file = zcu.fileByIndex(file_index); assert(file.getMode() == .zig); const struct_decl = file.zir.?.getStructDecl(.main_struct_inst); @@ -719,13 +721,8 @@ pub fn ensureFileAnalyzed(pt: Zcu.PerThread, file_index: Zcu.File.Index) (Alloca }); errdefer pt.destroyNamespace(new_namespace_index); try pt.scanNamespace(new_namespace_index, struct_decl.decls); - if (zcu.comp.debugIncremental()) try zcu.incremental_debug_state.newType(zcu, wip.index); - - const file_root_type: Type = .fromInterned(wip.finish(ip, new_namespace_index)); - - zcu.setFileRootType(file_index, file_root_type.toIntern()); - if (zcu.comp.time_report) |*tr| tr.stats.n_imported_files += 1; + zcu.setFileRootType(file_index, wip.finish(ip, new_namespace_index)); } /// Ensures that all memoized state on `Zcu` is up-to-date, performing re-analysis if necessary. @@ -810,37 +807,14 @@ pub fn ensureMemoizedStateUpToDate(pt: Zcu.PerThread, stage: InternPool.Memoized fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) Zcu.CompileError!bool { const zcu = pt.zcu; - const ip = &zcu.intern_pool; const comp = zcu.comp; const gpa = comp.gpa; - const io = comp.io; const unit: AnalUnit = .wrap(.{ .memoized_state = stage }); try zcu.analysis_in_progress.putNoClobber(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_index = zcu.module_roots.get(zcu.std_mod).?.unwrap().?; - try pt.ensureFileAnalyzed(std_file_index); - const std_type: Type = .fromInterned(zcu.fileRootType(std_file_index)); - const std_namespace = std_type.getNamespaceIndex(zcu); - try pt.ensureNamespaceUpToDate(std_namespace); - const builtin_str = try ip.getOrPutString(gpa, io, 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 = .{ .byte_abs = 0 }, - }; - var analysis_arena: std.heap.ArenaAllocator = .init(gpa); defer analysis_arena.deinit(); @@ -861,22 +835,7 @@ fn analyzeMemoizedState(pt: Zcu.PerThread, stage: InternPool.MemoizedStateStage) }; defer sema.deinit(); - var block: Sema.Block = .{ - .parent = null, - .sema = &sema, - .namespace = std_namespace, - .instructions = .empty, - .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); + return sema.analyzeMemoizedState(stage); } /// Ensures that the state of the given `ComptimeUnit` is fully up-to-date, performing re-analysis @@ -1966,7 +1925,6 @@ fn analyzeFuncBody( /// If the file's root struct type is not populated (the file is unreferenced), nothing is done. /// This is called by `updateZirRefs` for all updated files before the main work loop. /// This function does not perform any semantic analysis. -/// MLUGG TODO: mmmmm i have no idea if this makes sense... tbhwy i just want to update all *changed* namespaces at the start of an update or something lol fn updateFileNamespace(pt: Zcu.PerThread, file_index: Zcu.File.Index) Allocator.Error!void { const zcu = pt.zcu;