Commit 356e653f9b

Andrew Kelley <andrew@ziglang.org>
2024-02-28 21:32:39
better to use AST than ZIR for doc generation
1 parent 94daf87
Changed files (3)
src/autodoc/render_source.zig
@@ -1,435 +0,0 @@
-const std = @import("std");
-const builtin = @import("builtin");
-const io = std.io;
-const fs = std.fs;
-const process = std.process;
-const ChildProcess = std.ChildProcess;
-const Progress = std.Progress;
-const print = std.debug.print;
-const mem = std.mem;
-const testing = std.testing;
-const Allocator = std.mem.Allocator;
-const Module = @import("../Module.zig");
-
-pub fn genHtml(
-    allocator: Allocator,
-    src: *Module.File,
-    out: anytype,
-) !void {
-    try out.writeAll(
-        \\<!doctype html>
-        \\<html lang="en">
-        \\<head>
-        \\    <meta charset="utf-8">
-        \\    <meta name="viewport" content="width=device-width, initial-scale=1.0">
-    );
-    try out.print("    <title>{s} - source view</title>\n", .{src.sub_file_path});
-    try out.writeAll(
-        \\    <link rel="icon" href="data:image/png;base64,iVBORw0KGgoAAAANSUhEUgAAABAAAAAQCAYAAAAf8/9hAAAAgklEQVR4AWMYWuD7EllJIM4G4g4g5oIJ/odhOJ8wToOxSTXgNxDHoeiBMfA4+wGShjyYOCkG/IGqWQziEzYAoUAeiF9D5U+DxEg14DRU7jWIT5IBIOdCxf+A+CQZAAoopEB7QJwBCBwHiip8UYmRdrAlDpIMgApwQZNnNii5Dq0MBgCxxycBnwEd+wAAAABJRU5ErkJggg==">
-        \\    <link rel="icon" href="data:image/svg+xml;base64,PHN2ZyB4bWxucz0iaHR0cDovL3d3dy53My5vcmcvMjAwMC9zdmciIHZpZXdCb3g9IjAgMCAxNTMgMTQwIj48ZyBmaWxsPSIjRjdBNDFEIj48Zz48cG9seWdvbiBwb2ludHM9IjQ2LDIyIDI4LDQ0IDE5LDMwIi8+PHBvbHlnb24gcG9pbnRzPSI0NiwyMiAzMywzMyAyOCw0NCAyMiw0NCAyMiw5NSAzMSw5NSAyMCwxMDAgMTIsMTE3IDAsMTE3IDAsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMzEsOTUgMTIsMTE3IDQsMTA2Ii8+PC9nPjxnPjxwb2x5Z29uIHBvaW50cz0iNTYsMjIgNjIsMzYgMzcsNDQiLz48cG9seWdvbiBwb2ludHM9IjU2LDIyIDExMSwyMiAxMTEsNDQgMzcsNDQgNTYsMzIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTE2LDk1IDk3LDExNyA5MCwxMDQiLz48cG9seWdvbiBwb2ludHM9IjExNiw5NSAxMDAsMTA0IDk3LDExNyA0MiwxMTcgNDIsOTUiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTUwLDAgNTIsMTE3IDMsMTQwIDEwMSwyMiIvPjwvZz48Zz48cG9seWdvbiBwb2ludHM9IjE0MSwyMiAxNDAsNDAgMTIyLDQ1Ii8+PHBvbHlnb24gcG9pbnRzPSIxNTMsMjIgMTUzLDExNyAxMDYsMTE3IDEyMCwxMDUgMTI1LDk1IDEzMSw5NSAxMzEsNDUgMTIyLDQ1IDEzMiwzNiAxNDEsMjIiIHNoYXBlLXJlbmRlcmluZz0iY3Jpc3BFZGdlcyIvPjxwb2x5Z29uIHBvaW50cz0iMTI1LDk1IDEzMCwxMTAgMTA2LDExNyIvPjwvZz48L2c+PC9zdmc+">
-        \\    <style>
-        \\      body{
-        \\        font-family: system-ui, -apple-system, Roboto, "Segoe UI", sans-serif;
-        \\        margin: 0;
-        \\        line-height: 1.5;
-        \\      }
-        \\
-        \\      pre > code {
-        \\        display: block;
-        \\        overflow: auto;
-        \\        line-height: normal;
-        \\        margin: 0em;
-        \\      }
-        \\      .tok-kw {
-        \\          color: #333;
-        \\          font-weight: bold;
-        \\      }
-        \\      .tok-str {
-        \\          color: #d14;
-        \\      }
-        \\      .tok-builtin {
-        \\          color: #005C7A;
-        \\      }
-        \\      .tok-comment {
-        \\          color: #545454;
-        \\          font-style: italic;
-        \\      }
-        \\      .tok-fn {
-        \\          color: #900;
-        \\          font-weight: bold;
-        \\      }
-        \\      .tok-null {
-        \\          color: #005C5C;
-        \\      }
-        \\      .tok-number {
-        \\          color: #005C5C;
-        \\      }
-        \\      .tok-type {
-        \\          color: #458;
-        \\          font-weight: bold;
-        \\      }
-        \\      pre {
-        \\        counter-reset: line;
-        \\      }
-        \\      pre .line:before {
-        \\        counter-increment: line;
-        \\        content: counter(line);
-        \\        display: inline-block;
-        \\        padding-right: 1em;
-        \\        width: 2em;
-        \\        text-align: right;
-        \\        color: #999;
-        \\      }
-        \\      
-        \\      .line {
-        \\        width: 100%;
-        \\        display: inline-block;
-        \\      }
-        \\      .line:target {
-        \\        border-top: 1px solid #ccc;
-        \\        border-bottom: 1px solid #ccc;
-        \\        background: #fafafa;
-        \\      }
-        \\
-        \\      @media (prefers-color-scheme: dark) {
-        \\        body{
-        \\            background:#222;
-        \\            color: #ccc;
-        \\        }
-        \\        pre > code {
-        \\            color: #ccc;
-        \\            background: #222;
-        \\            border: unset;
-        \\        }
-        \\        .line:target {
-        \\            border-top: 1px solid #444;
-        \\            border-bottom: 1px solid #444;
-        \\            background: #333;
-        \\        }
-        \\        .tok-kw {
-        \\            color: #eee;
-        \\        }
-        \\        .tok-str {
-        \\            color: #2e5;
-        \\        }
-        \\        .tok-builtin {
-        \\            color: #ff894c;
-        \\        }
-        \\        .tok-comment {
-        \\            color: #aa7;
-        \\        }
-        \\        .tok-fn {
-        \\            color: #B1A0F8;
-        \\        }
-        \\        .tok-null {
-        \\            color: #ff8080;
-        \\        }
-        \\        .tok-number {
-        \\            color: #ff8080;
-        \\        }
-        \\        .tok-type {
-        \\            color: #68f;
-        \\        }
-        \\      }
-        \\    </style>
-        \\</head>
-        \\<body>
-        \\
-    );
-
-    const source = try src.getSource(allocator);
-    try tokenizeAndPrintRaw(out, source.bytes);
-    try out.writeAll(
-        \\</body>
-        \\</html>
-    );
-}
-
-const start_line = "<span class=\"line\" id=\"L{d}\">";
-const end_line = "</span>\n";
-
-var line_counter: usize = 1;
-
-pub fn tokenizeAndPrintRaw(
-    out: anytype,
-    src: [:0]const u8,
-) !void {
-    line_counter = 1;
-
-    try out.print("<pre><code>" ++ start_line, .{line_counter});
-    var tokenizer = std.zig.Tokenizer.init(src);
-    var index: usize = 0;
-    var next_tok_is_fn = false;
-    while (true) {
-        const prev_tok_was_fn = next_tok_is_fn;
-        next_tok_is_fn = false;
-
-        const token = tokenizer.next();
-        if (mem.indexOf(u8, src[index..token.loc.start], "//")) |comment_start_off| {
-            // render one comment
-            const comment_start = index + comment_start_off;
-            const comment_end_off = mem.indexOf(u8, src[comment_start..token.loc.start], "\n");
-            const comment_end = if (comment_end_off) |o| comment_start + o else token.loc.start;
-
-            try writeEscapedLines(out, src[index..comment_start]);
-            try out.writeAll("<span class=\"tok-comment\">");
-            try writeEscaped(out, src[comment_start..comment_end]);
-            try out.writeAll("</span>\n");
-            index = comment_end;
-            tokenizer.index = index;
-            continue;
-        }
-
-        try writeEscapedLines(out, src[index..token.loc.start]);
-        switch (token.tag) {
-            .eof => break,
-
-            .keyword_addrspace,
-            .keyword_align,
-            .keyword_and,
-            .keyword_asm,
-            .keyword_async,
-            .keyword_await,
-            .keyword_break,
-            .keyword_catch,
-            .keyword_comptime,
-            .keyword_const,
-            .keyword_continue,
-            .keyword_defer,
-            .keyword_else,
-            .keyword_enum,
-            .keyword_errdefer,
-            .keyword_error,
-            .keyword_export,
-            .keyword_extern,
-            .keyword_for,
-            .keyword_if,
-            .keyword_inline,
-            .keyword_noalias,
-            .keyword_noinline,
-            .keyword_nosuspend,
-            .keyword_opaque,
-            .keyword_or,
-            .keyword_orelse,
-            .keyword_packed,
-            .keyword_anyframe,
-            .keyword_pub,
-            .keyword_resume,
-            .keyword_return,
-            .keyword_linksection,
-            .keyword_callconv,
-            .keyword_struct,
-            .keyword_suspend,
-            .keyword_switch,
-            .keyword_test,
-            .keyword_threadlocal,
-            .keyword_try,
-            .keyword_union,
-            .keyword_unreachable,
-            .keyword_usingnamespace,
-            .keyword_var,
-            .keyword_volatile,
-            .keyword_allowzero,
-            .keyword_while,
-            .keyword_anytype,
-            => {
-                try out.writeAll("<span class=\"tok-kw\">");
-                try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                try out.writeAll("</span>");
-            },
-
-            .keyword_fn => {
-                try out.writeAll("<span class=\"tok-kw\">");
-                try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                try out.writeAll("</span>");
-                next_tok_is_fn = true;
-            },
-
-            .string_literal,
-            .char_literal,
-            => {
-                try out.writeAll("<span class=\"tok-str\">");
-                try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                try out.writeAll("</span>");
-            },
-
-            .multiline_string_literal_line => {
-                if (src[token.loc.end - 1] == '\n') {
-                    try out.writeAll("<span class=\"tok-str\">");
-                    try writeEscaped(out, src[token.loc.start .. token.loc.end - 1]);
-                    line_counter += 1;
-                    try out.print("</span>" ++ end_line ++ "\n" ++ start_line, .{line_counter});
-                } else {
-                    try out.writeAll("<span class=\"tok-str\">");
-                    try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                    try out.writeAll("</span>");
-                }
-            },
-
-            .builtin => {
-                try out.writeAll("<span class=\"tok-builtin\">");
-                try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                try out.writeAll("</span>");
-            },
-
-            .doc_comment,
-            .container_doc_comment,
-            => {
-                try out.writeAll("<span class=\"tok-comment\">");
-                try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                try out.writeAll("</span>");
-            },
-
-            .identifier => {
-                const tok_bytes = src[token.loc.start..token.loc.end];
-                if (mem.eql(u8, tok_bytes, "undefined") or
-                    mem.eql(u8, tok_bytes, "null") or
-                    mem.eql(u8, tok_bytes, "true") or
-                    mem.eql(u8, tok_bytes, "false"))
-                {
-                    try out.writeAll("<span class=\"tok-null\">");
-                    try writeEscaped(out, tok_bytes);
-                    try out.writeAll("</span>");
-                } else if (prev_tok_was_fn) {
-                    try out.writeAll("<span class=\"tok-fn\">");
-                    try writeEscaped(out, tok_bytes);
-                    try out.writeAll("</span>");
-                } else {
-                    const is_int = blk: {
-                        if (src[token.loc.start] != 'i' and src[token.loc.start] != 'u')
-                            break :blk false;
-                        var i = token.loc.start + 1;
-                        if (i == token.loc.end)
-                            break :blk false;
-                        while (i != token.loc.end) : (i += 1) {
-                            if (src[i] < '0' or src[i] > '9')
-                                break :blk false;
-                        }
-                        break :blk true;
-                    };
-                    if (is_int or isType(tok_bytes)) {
-                        try out.writeAll("<span class=\"tok-type\">");
-                        try writeEscaped(out, tok_bytes);
-                        try out.writeAll("</span>");
-                    } else {
-                        try writeEscaped(out, tok_bytes);
-                    }
-                }
-            },
-
-            .number_literal => {
-                try out.writeAll("<span class=\"tok-number\">");
-                try writeEscaped(out, src[token.loc.start..token.loc.end]);
-                try out.writeAll("</span>");
-            },
-
-            .bang,
-            .pipe,
-            .pipe_pipe,
-            .pipe_equal,
-            .equal,
-            .equal_equal,
-            .equal_angle_bracket_right,
-            .bang_equal,
-            .l_paren,
-            .r_paren,
-            .semicolon,
-            .percent,
-            .percent_equal,
-            .l_brace,
-            .r_brace,
-            .l_bracket,
-            .r_bracket,
-            .period,
-            .period_asterisk,
-            .ellipsis2,
-            .ellipsis3,
-            .caret,
-            .caret_equal,
-            .plus,
-            .plus_plus,
-            .plus_equal,
-            .plus_percent,
-            .plus_percent_equal,
-            .plus_pipe,
-            .plus_pipe_equal,
-            .minus,
-            .minus_equal,
-            .minus_percent,
-            .minus_percent_equal,
-            .minus_pipe,
-            .minus_pipe_equal,
-            .asterisk,
-            .asterisk_equal,
-            .asterisk_asterisk,
-            .asterisk_percent,
-            .asterisk_percent_equal,
-            .asterisk_pipe,
-            .asterisk_pipe_equal,
-            .arrow,
-            .colon,
-            .slash,
-            .slash_equal,
-            .comma,
-            .ampersand,
-            .ampersand_equal,
-            .question_mark,
-            .angle_bracket_left,
-            .angle_bracket_left_equal,
-            .angle_bracket_angle_bracket_left,
-            .angle_bracket_angle_bracket_left_equal,
-            .angle_bracket_angle_bracket_left_pipe,
-            .angle_bracket_angle_bracket_left_pipe_equal,
-            .angle_bracket_right,
-            .angle_bracket_right_equal,
-            .angle_bracket_angle_bracket_right,
-            .angle_bracket_angle_bracket_right_equal,
-            .tilde,
-            => try writeEscaped(out, src[token.loc.start..token.loc.end]),
-
-            .invalid, .invalid_periodasterisks => return error.ParseError,
-        }
-        index = token.loc.end;
-    }
-    try out.writeAll(end_line ++ "</code></pre>");
-}
-
-fn writeEscapedLines(out: anytype, text: []const u8) !void {
-    for (text) |char| {
-        if (char == '\n') {
-            try out.writeAll(end_line);
-            line_counter += 1;
-            try out.print(start_line, .{line_counter});
-        } else {
-            try writeEscaped(out, &[_]u8{char});
-        }
-    }
-}
-
-fn writeEscaped(out: anytype, input: []const u8) !void {
-    for (input) |c| {
-        try switch (c) {
-            '&' => out.writeAll("&amp;"),
-            '<' => out.writeAll("&lt;"),
-            '>' => out.writeAll("&gt;"),
-            '"' => out.writeAll("&quot;"),
-            else => out.writeByte(c),
-        };
-    }
-}
-
-const builtin_types = [_][]const u8{
-    "f16",          "f32",     "f64",        "f80",          "f128",
-    "c_longdouble", "c_short", "c_ushort",   "c_int",        "c_uint",
-    "c_long",       "c_ulong", "c_longlong", "c_ulonglong",  "c_char",
-    "anyopaque",    "void",    "bool",       "isize",        "usize",
-    "noreturn",     "type",    "anyerror",   "comptime_int", "comptime_float",
-};
-
-fn isType(name: []const u8) bool {
-    for (builtin_types) |t| {
-        if (mem.eql(u8, t, name))
-            return true;
-    }
-    return false;
-}
src/Autodoc.zig
@@ -1,6035 +0,0 @@
-const builtin = @import("builtin");
-const std = @import("std");
-const build_options = @import("build_options");
-const Ast = std.zig.Ast;
-const Autodoc = @This();
-const Compilation = @import("Compilation.zig");
-const Zcu = @import("Module.zig");
-const File = Zcu.File;
-const Module = @import("Package.zig").Module;
-const Tokenizer = std.zig.Tokenizer;
-const InternPool = @import("InternPool.zig");
-const Zir = std.zig.Zir;
-const Ref = Zir.Inst.Ref;
-const log = std.log.scoped(.autodoc);
-const renderer = @import("autodoc/render_source.zig");
-
-zcu: *Zcu,
-arena: std.mem.Allocator,
-
-// The goal of autodoc is to fill up these arrays
-// that will then be serialized as JSON and consumed
-// by the JS frontend.
-modules: std.AutoArrayHashMapUnmanaged(*Module, DocData.DocModule) = .{},
-files: std.AutoArrayHashMapUnmanaged(*File, usize) = .{},
-calls: std.ArrayListUnmanaged(DocData.Call) = .{},
-types: std.ArrayListUnmanaged(DocData.Type) = .{},
-decls: std.ArrayListUnmanaged(DocData.Decl) = .{},
-exprs: std.ArrayListUnmanaged(DocData.Expr) = .{},
-ast_nodes: std.ArrayListUnmanaged(DocData.AstNode) = .{},
-comptime_exprs: std.ArrayListUnmanaged(DocData.ComptimeExpr) = .{},
-guide_sections: std.ArrayListUnmanaged(Section) = .{},
-
-// These fields hold temporary state of the analysis process
-// and are mainly used by the decl path resolving algorithm.
-pending_ref_paths: std.AutoHashMapUnmanaged(
-    *DocData.Expr, // pointer to declpath tail end (ie `&decl_path[decl_path.len - 1]`)
-    std.ArrayListUnmanaged(RefPathResumeInfo),
-) = .{},
-ref_paths_pending_on_decls: std.AutoHashMapUnmanaged(
-    *Scope.DeclStatus,
-    std.ArrayListUnmanaged(RefPathResumeInfo),
-) = .{},
-ref_paths_pending_on_types: std.AutoHashMapUnmanaged(
-    usize,
-    std.ArrayListUnmanaged(RefPathResumeInfo),
-) = .{},
-
-/// A set of ZIR instruction refs which have a meaning other than the
-/// instruction they refer to. For instance, during analysis of the arguments to
-/// a `call`, the index of the `call` itself is repurposed to refer to the
-/// parameter type.
-/// TODO: there should be some kind of proper handling for these instructions;
-/// currently we just ignore them!
-repurposed_insts: std.AutoHashMapUnmanaged(Zir.Inst.Index, void) = .{},
-
-const RefPathResumeInfo = struct {
-    file: *File,
-    ref_path: []DocData.Expr,
-};
-
-/// Used to accumulate src_node offsets.
-/// In ZIR, all ast node indices are relative to the parent decl.
-/// More concretely, `union_decl`, `struct_decl`, `enum_decl` and `opaque_decl`
-/// and the value of each of their decls participate in the relative offset
-/// counting, and nothing else.
-/// We keep track of the line and byte values for these instructions in order
-/// to avoid tokenizing every file (on new lines) from the start every time.
-const SrcLocInfo = struct {
-    bytes: u32 = 0,
-    line: usize = 0,
-    src_node: u32 = 0,
-};
-
-const Section = struct {
-    name: []const u8 = "", // empty string is the default section
-    guides: std.ArrayListUnmanaged(Guide) = .{},
-
-    const Guide = struct {
-        name: []const u8,
-        body: []const u8,
-    };
-};
-
-pub fn generate(zcu: *Zcu, output_dir: std.fs.Dir) !void {
-    var arena_allocator = std.heap.ArenaAllocator.init(zcu.gpa);
-    defer arena_allocator.deinit();
-    var autodoc: Autodoc = .{
-        .zcu = zcu,
-        .arena = arena_allocator.allocator(),
-    };
-    try autodoc.generateZirData(output_dir);
-
-    const lib_dir = zcu.comp.zig_lib_directory.handle;
-    try lib_dir.copyFile("docs/main.js", output_dir, "main.js", .{});
-    try lib_dir.copyFile("docs/ziglexer.js", output_dir, "ziglexer.js", .{});
-    try lib_dir.copyFile("docs/commonmark.js", output_dir, "commonmark.js", .{});
-    try lib_dir.copyFile("docs/index.html", output_dir, "index.html", .{});
-}
-
-fn generateZirData(self: *Autodoc, output_dir: std.fs.Dir) !void {
-    const root_src_path = self.zcu.main_mod.root_src_path;
-    const joined_src_path = try self.zcu.main_mod.root.joinString(self.arena, root_src_path);
-    defer self.arena.free(joined_src_path);
-
-    const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{ ".", joined_src_path });
-    defer self.arena.free(abs_root_src_path);
-
-    const file = self.zcu.import_table.get(abs_root_src_path).?; // file is expected to be present in the import table
-    // Append all the types in Zir.Inst.Ref.
-    {
-        comptime std.debug.assert(@intFromEnum(InternPool.Index.first_type) == 0);
-        var i: u32 = 0;
-        while (i <= @intFromEnum(InternPool.Index.last_type)) : (i += 1) {
-            const ip_index = @as(InternPool.Index, @enumFromInt(i));
-            var tmpbuf = std.ArrayList(u8).init(self.arena);
-            if (ip_index == .generic_poison_type) {
-                // Not a real type, doesn't have a normal name
-                try tmpbuf.writer().writeAll("(generic poison)");
-            } else {
-                try @import("type.zig").Type.fromInterned(ip_index).fmt(self.zcu).format("", .{}, tmpbuf.writer());
-            }
-            try self.types.append(
-                self.arena,
-                switch (ip_index) {
-                    .u0_type,
-                    .i0_type,
-                    .u1_type,
-                    .u8_type,
-                    .i8_type,
-                    .u16_type,
-                    .i16_type,
-                    .u29_type,
-                    .u32_type,
-                    .i32_type,
-                    .u64_type,
-                    .i64_type,
-                    .u80_type,
-                    .u128_type,
-                    .i128_type,
-                    .usize_type,
-                    .isize_type,
-                    .c_char_type,
-                    .c_short_type,
-                    .c_ushort_type,
-                    .c_int_type,
-                    .c_uint_type,
-                    .c_long_type,
-                    .c_ulong_type,
-                    .c_longlong_type,
-                    .c_ulonglong_type,
-                    => .{
-                        .Int = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .f16_type,
-                    .f32_type,
-                    .f64_type,
-                    .f80_type,
-                    .f128_type,
-                    .c_longdouble_type,
-                    => .{
-                        .Float = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .comptime_int_type => .{
-                        .ComptimeInt = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .comptime_float_type => .{
-                        .ComptimeFloat = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-
-                    .anyopaque_type => .{
-                        .ComptimeExpr = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-
-                    .bool_type => .{
-                        .Bool = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .noreturn_type => .{
-                        .NoReturn = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .void_type => .{
-                        .Void = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .type_info_type => .{
-                        .ComptimeExpr = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .type_type => .{
-                        .Type = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .anyerror_type => .{
-                        .ErrorSet = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    // should be different types but if we don't analyze std we don't get the ast nodes etc.
-                    // since they're defined in std.builtin
-                    .calling_convention_type,
-                    .atomic_order_type,
-                    .atomic_rmw_op_type,
-                    .address_space_type,
-                    .float_mode_type,
-                    .reduce_op_type,
-                    .call_modifier_type,
-                    .prefetch_options_type,
-                    .export_options_type,
-                    .extern_options_type,
-                    => .{
-                        .Type = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .manyptr_u8_type => .{
-                        .Pointer = .{
-                            .size = .Many,
-                            .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
-                            .is_mutable = true,
-                        },
-                    },
-                    .manyptr_const_u8_type => .{
-                        .Pointer = .{
-                            .size = .Many,
-                            .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
-                        },
-                    },
-                    .manyptr_const_u8_sentinel_0_type => .{
-                        .Pointer = .{
-                            .size = .Many,
-                            .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
-                            .sentinel = .{ .int = .{ .value = 0 } },
-                        },
-                    },
-                    .single_const_pointer_to_comptime_int_type => .{
-                        .Pointer = .{
-                            .size = .One,
-                            .child = .{ .type = @intFromEnum(InternPool.Index.comptime_int_type) },
-                        },
-                    },
-                    .slice_const_u8_type => .{
-                        .Pointer = .{
-                            .size = .Slice,
-                            .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
-                        },
-                    },
-                    .slice_const_u8_sentinel_0_type => .{
-                        .Pointer = .{
-                            .size = .Slice,
-                            .child = .{ .type = @intFromEnum(InternPool.Index.u8_type) },
-                            .sentinel = .{ .int = .{ .value = 0 } },
-                        },
-                    },
-                    // Not fully correct
-                    // since it actually has no src or line_number
-                    .empty_struct_type => .{
-                        .Struct = .{
-                            .name = "",
-                            .src = 0,
-                            .is_tuple = false,
-                            .line_number = 0,
-                            .parent_container = null,
-                            .layout = null,
-                        },
-                    },
-                    .anyerror_void_error_union_type => .{
-                        .ErrorUnion = .{
-                            .lhs = .{ .type = @intFromEnum(InternPool.Index.anyerror_type) },
-                            .rhs = .{ .type = @intFromEnum(InternPool.Index.void_type) },
-                        },
-                    },
-                    .anyframe_type => .{
-                        .AnyFrame = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .enum_literal_type => .{
-                        .EnumLiteral = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .undefined_type => .{
-                        .Undefined = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .null_type => .{
-                        .Null = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    .optional_noreturn_type => .{
-                        .Optional = .{
-                            .name = try tmpbuf.toOwnedSlice(),
-                            .child = .{ .type = @intFromEnum(InternPool.Index.noreturn_type) },
-                        },
-                    },
-                    // Poison and special tag
-                    .generic_poison_type,
-                    .var_args_param_type,
-                    .adhoc_inferred_error_set_type,
-                    => .{
-                        .Type = .{ .name = try tmpbuf.toOwnedSlice() },
-                    },
-                    // We want to catch new types added to InternPool.Index
-                    else => unreachable,
-                },
-            );
-        }
-    }
-
-    const rootName = blk: {
-        const rootName = std.fs.path.basename(self.zcu.main_mod.root_src_path);
-        break :blk rootName[0 .. rootName.len - 4];
-    };
-
-    const main_type_index = self.types.items.len;
-    {
-        try self.modules.put(self.arena, self.zcu.main_mod, .{
-            .name = rootName,
-            .main = main_type_index,
-            .table = .{},
-        });
-        try self.modules.entries.items(.value)[0].table.put(
-            self.arena,
-            self.zcu.main_mod,
-            .{
-                .name = rootName,
-                .value = 0,
-            },
-        );
-    }
-
-    var root_scope = Scope{
-        .parent = null,
-        .enclosing_type = null,
-    };
-
-    const tldoc_comment = try self.getTLDocComment(file);
-    const cleaned_tldoc_comment = try self.findGuidePaths(file, tldoc_comment);
-    defer self.arena.free(cleaned_tldoc_comment);
-    try self.ast_nodes.append(self.arena, .{
-        .name = "(root)",
-        .docs = cleaned_tldoc_comment,
-    });
-    try self.files.put(self.arena, file, main_type_index);
-
-    _ = try self.walkInstruction(
-        file,
-        &root_scope,
-        .{},
-        .main_struct_inst,
-        false,
-        null,
-    );
-
-    if (self.ref_paths_pending_on_decls.count() > 0) {
-        @panic("some decl paths were never fully analyzed (pending on decls)");
-    }
-
-    if (self.ref_paths_pending_on_types.count() > 0) {
-        @panic("some decl paths were never fully analyzed (pending on types)");
-    }
-
-    if (self.pending_ref_paths.count() > 0) {
-        @panic("some decl paths were never fully analyzed");
-    }
-
-    var data = DocData{
-        .modules = self.modules,
-        .files = self.files,
-        .calls = self.calls.items,
-        .types = self.types.items,
-        .decls = self.decls.items,
-        .exprs = self.exprs.items,
-        .astNodes = self.ast_nodes.items,
-        .comptimeExprs = self.comptime_exprs.items,
-        .guideSections = self.guide_sections,
-    };
-
-    inline for (comptime std.meta.tags(std.meta.FieldEnum(DocData))) |f| {
-        const field_name = @tagName(f);
-        const file_name = "data-" ++ field_name ++ ".js";
-        const data_js_f = try output_dir.createFile(file_name, .{});
-        defer data_js_f.close();
-
-        var buffer = std.io.bufferedWriter(data_js_f.writer());
-        const out = buffer.writer();
-
-        try out.print("var {s} =", .{field_name});
-
-        var jsw = std.json.writeStream(out, .{
-            .whitespace = .minified,
-            .emit_null_optional_fields = true,
-        });
-
-        switch (f) {
-            .files => try writeFileTableToJson(data.files, data.modules, &jsw),
-            .guideSections => try writeGuidesToJson(data.guideSections, &jsw),
-            .modules => try jsw.write(data.modules.values()),
-            else => try jsw.write(@field(data, field_name)),
-        }
-
-        // try std.json.stringifyArbitraryDepth(
-        //     self.arena,
-        //     @field(data, field.name),
-        //     .{
-        //         .whitespace = .minified,
-        //         .emit_null_optional_fields = true,
-        //     },
-        //     out,
-        // );
-        try out.print(";", .{});
-
-        // last thing (that can fail) that we do is flush
-        try buffer.flush();
-    }
-
-    {
-        output_dir.makeDir("src") catch |e| switch (e) {
-            error.PathAlreadyExists => {},
-            else => |err| return err,
-        };
-        const html_dir = try output_dir.openDir("src", .{});
-
-        var files_iterator = self.files.iterator();
-
-        while (files_iterator.next()) |entry| {
-            const sub_file_path = entry.key_ptr.*.sub_file_path;
-            const file_module = entry.key_ptr.*.mod;
-            const module_name = (self.modules.get(file_module) orelse continue).name;
-
-            const file_path = std.fs.path.dirname(sub_file_path) orelse "";
-            const file_name = if (file_path.len > 0) sub_file_path[file_path.len + 1 ..] else sub_file_path;
-
-            const html_file_name = try std.mem.concat(self.arena, u8, &.{ file_name, ".html" });
-            defer self.arena.free(html_file_name);
-
-            const dir_name = try std.fs.path.join(self.arena, &.{ module_name, file_path });
-            defer self.arena.free(dir_name);
-
-            var dir = try html_dir.makeOpenPath(dir_name, .{});
-            defer dir.close();
-
-            const html_file = dir.createFile(html_file_name, .{}) catch |err| switch (err) {
-                error.PathAlreadyExists => try dir.openFile(html_file_name, .{}),
-                else => return err,
-            };
-            defer html_file.close();
-            var buffer = std.io.bufferedWriter(html_file.writer());
-
-            const out = buffer.writer();
-
-            try renderer.genHtml(self.zcu.gpa, entry.key_ptr.*, out);
-            try buffer.flush();
-        }
-    }
-}
-
-/// Represents a chain of scopes, used to resolve decl references to the
-/// corresponding entry in `self.decls`. It also keeps track of whether
-/// a given decl has been analyzed or not.
-const Scope = struct {
-    parent: ?*Scope,
-    map: std.AutoHashMapUnmanaged(
-        Zir.NullTerminatedString, // index into the current file's string table (decl name)
-        *DeclStatus,
-    ) = .{},
-    captures: []const Zir.Inst.Capture = &.{},
-    enclosing_type: ?usize, // index into `types`, null = file top-level struct
-
-    pub const DeclStatus = union(enum) {
-        Analyzed: usize, // index into `decls`
-        Pending,
-        NotRequested: u32, // instr_index
-    };
-
-    fn getCapture(scope: Scope, idx: u16) struct {
-        union(enum) { inst: Zir.Inst.Index, decl: Zir.NullTerminatedString },
-        *Scope,
-    } {
-        const parent = scope.parent.?;
-        return switch (scope.captures[idx].unwrap()) {
-            .nested => |parent_idx| parent.getCapture(parent_idx),
-            .instruction => |inst| .{
-                .{ .inst = inst },
-                parent,
-            },
-            .decl_val, .decl_ref => |str| .{
-                .{ .decl = str },
-                parent,
-            },
-        };
-    }
-
-    /// Returns a pointer so that the caller has a chance to modify the value
-    /// in case they decide to start analyzing a previously not requested decl.
-    /// Another reason is that in some places we use the pointer to uniquely
-    /// refer to a decl, as we wait for it to be analyzed. This means that
-    /// those pointers must stay stable.
-    pub fn resolveDeclName(self: Scope, string_table_idx: Zir.NullTerminatedString, file: *File, inst: Zir.Inst.OptionalIndex) *DeclStatus {
-        var cur: ?*const Scope = &self;
-        return while (cur) |s| : (cur = s.parent) {
-            break s.map.get(string_table_idx) orelse continue;
-        } else {
-            printWithOptionalContext(
-                file,
-                inst,
-                "Could not find `{s}`\n\n",
-                .{file.zir.nullTerminatedString(string_table_idx)},
-            );
-            unreachable;
-        };
-    }
-
-    pub fn insertDeclRef(
-        self: *Scope,
-        arena: std.mem.Allocator,
-        decl_name_index: Zir.NullTerminatedString, // index into the current file's string table
-        decl_status: DeclStatus,
-    ) !void {
-        const decl_status_ptr = try arena.create(DeclStatus);
-        errdefer arena.destroy(decl_status_ptr);
-
-        decl_status_ptr.* = decl_status;
-        try self.map.put(arena, decl_name_index, decl_status_ptr);
-    }
-};
-
-/// The output of our analysis process.
-const DocData = struct {
-    // NOTE: editing fields of DocData requires also updating:
-    //       - the deployment script for ziglang.org
-    //       - imports in index.html
-    typeKinds: []const []const u8 = std.meta.fieldNames(DocTypeKinds),
-    rootMod: u32 = 0,
-    modules: std.AutoArrayHashMapUnmanaged(*Module, DocModule),
-
-    // non-hardcoded stuff
-    astNodes: []AstNode,
-    calls: []Call,
-    files: std.AutoArrayHashMapUnmanaged(*File, usize),
-    types: []Type,
-    decls: []Decl,
-    exprs: []Expr,
-    comptimeExprs: []ComptimeExpr,
-
-    guideSections: std.ArrayListUnmanaged(Section),
-
-    const Call = struct {
-        func: Expr,
-        args: []Expr,
-        ret: Expr,
-    };
-
-    /// All the type "families" as described by `std.builtin.TypeId`
-    /// plus a couple extra that are unique to our use case.
-    ///
-    /// `Unanalyzed` is used so that we can refer to types that have started
-    /// analysis but that haven't been fully analyzed yet (in case we find
-    /// self-referential stuff, like `@This()`).
-    ///
-    /// `ComptimeExpr` represents the result of a piece of comptime logic
-    /// that we weren't able to analyze fully. Examples of that are comptime
-    /// function calls and comptime if / switch / ... expressions.
-    const DocTypeKinds = @typeInfo(Type).Union.tag_type.?;
-
-    const ComptimeExpr = struct {
-        code: []const u8,
-    };
-    const DocModule = struct {
-        name: []const u8 = "(root)",
-        file: usize = 0, // index into `files`
-        main: usize = 0, // index into `types`
-        table: std.AutoHashMapUnmanaged(*Module, TableEntry),
-        pub const TableEntry = struct {
-            name: []const u8,
-            value: usize,
-        };
-
-        pub fn jsonStringify(self: DocModule, jsw: anytype) !void {
-            try jsw.beginObject();
-            inline for (comptime std.meta.tags(std.meta.FieldEnum(DocModule))) |f| {
-                const f_name = @tagName(f);
-                try jsw.objectField(f_name);
-                switch (f) {
-                    .table => try writeModuleTableToJson(self.table, jsw),
-                    else => try jsw.write(@field(self, f_name)),
-                }
-            }
-            try jsw.endObject();
-        }
-    };
-
-    const Decl = struct {
-        name: []const u8,
-        kind: []const u8,
-        src: usize, // index into astNodes
-        value: WalkResult,
-        // The index in astNodes of the `test declname { }` node
-        decltest: ?usize = null,
-        is_uns: bool = false, // usingnamespace
-        parent_container: ?usize, // index into `types`
-
-        pub fn jsonStringify(self: Decl, jsw: anytype) !void {
-            try jsw.beginArray();
-            inline for (comptime std.meta.fields(Decl)) |f| {
-                try jsw.write(@field(self, f.name));
-            }
-            try jsw.endArray();
-        }
-    };
-
-    const AstNode = struct {
-        file: usize = 0, // index into files
-        line: usize = 0,
-        col: usize = 0,
-        name: ?[]const u8 = null,
-        code: ?[]const u8 = null,
-        docs: ?[]const u8 = null,
-        fields: ?[]usize = null, // index into astNodes
-        @"comptime": bool = false,
-
-        pub fn jsonStringify(self: AstNode, jsw: anytype) !void {
-            try jsw.beginArray();
-            inline for (comptime std.meta.fields(AstNode)) |f| {
-                try jsw.write(@field(self, f.name));
-            }
-            try jsw.endArray();
-        }
-    };
-
-    const Type = union(enum) {
-        Unanalyzed: struct {},
-        Type: struct { name: []const u8 },
-        Void: struct { name: []const u8 },
-        Bool: struct { name: []const u8 },
-        NoReturn: struct { name: []const u8 },
-        Int: struct { name: []const u8 },
-        Float: struct { name: []const u8 },
-        Pointer: struct {
-            size: std.builtin.Type.Pointer.Size,
-            child: Expr,
-            sentinel: ?Expr = null,
-            @"align": ?Expr = null,
-            address_space: ?Expr = null,
-            bit_start: ?Expr = null,
-            host_size: ?Expr = null,
-            is_ref: bool = false,
-            is_allowzero: bool = false,
-            is_mutable: bool = false,
-            is_volatile: bool = false,
-            has_sentinel: bool = false,
-            has_align: bool = false,
-            has_addrspace: bool = false,
-            has_bit_range: bool = false,
-        },
-        Array: struct {
-            len: Expr,
-            child: Expr,
-            sentinel: ?Expr = null,
-        },
-        Struct: struct {
-            name: []const u8,
-            src: usize, // index into astNodes
-            privDecls: []usize = &.{}, // index into decls
-            pubDecls: []usize = &.{}, // index into decls
-            field_types: []Expr = &.{}, // (use src->fields to find names)
-            field_defaults: []?Expr = &.{}, // default values is specified
-            backing_int: ?Expr = null, // backing integer if specified
-            is_tuple: bool,
-            line_number: usize,
-            parent_container: ?usize, // index into `types`
-            layout: ?Expr, // if different than Auto
-        },
-        ComptimeExpr: struct { name: []const u8 },
-        ComptimeFloat: struct { name: []const u8 },
-        ComptimeInt: struct { name: []const u8 },
-        Undefined: struct { name: []const u8 },
-        Null: struct { name: []const u8 },
-        Optional: struct {
-            name: []const u8,
-            child: Expr,
-        },
-        ErrorUnion: struct { lhs: Expr, rhs: Expr },
-        InferredErrorUnion: struct { payload: Expr },
-        ErrorSet: struct {
-            name: []const u8,
-            fields: ?[]const Field = null,
-            // TODO: fn field for inferred error sets?
-        },
-        Enum: struct {
-            name: []const u8,
-            src: usize, // index into astNodes
-            privDecls: []usize = &.{}, // index into decls
-            pubDecls: []usize = &.{}, // index into decls
-            // (use src->fields to find field names)
-            tag: ?Expr = null, // tag type if specified
-            values: []?Expr = &.{}, // tag values if specified
-            nonexhaustive: bool,
-            parent_container: ?usize, // index into `types`
-        },
-        Union: struct {
-            name: []const u8,
-            src: usize, // index into astNodes
-            privDecls: []usize = &.{}, // index into decls
-            pubDecls: []usize = &.{}, // index into decls
-            fields: []Expr = &.{}, // (use src->fields to find names)
-            tag: ?Expr, // tag type if specified
-            auto_enum: bool, // tag is an auto enum
-            parent_container: ?usize, // index into `types`
-            layout: ?Expr, // if different than Auto
-        },
-        Fn: struct {
-            name: []const u8,
-            src: ?usize = null, // index into `astNodes`
-            ret: Expr,
-            generic_ret: ?Expr = null,
-            params: ?[]Expr = null, // (use src->fields to find names)
-            lib_name: []const u8 = "",
-            is_var_args: bool = false,
-            is_inferred_error: bool = false,
-            has_lib_name: bool = false,
-            has_cc: bool = false,
-            cc: ?usize = null,
-            @"align": ?usize = null,
-            has_align: bool = false,
-            is_test: bool = false,
-            is_extern: bool = false,
-        },
-        Opaque: struct {
-            name: []const u8,
-            src: usize, // index into astNodes
-            privDecls: []usize = &.{}, // index into decls
-            pubDecls: []usize = &.{}, // index into decls
-            parent_container: ?usize, // index into `types`
-        },
-        Frame: struct { name: []const u8 },
-        AnyFrame: struct { name: []const u8 },
-        Vector: struct { name: []const u8 },
-        EnumLiteral: struct { name: []const u8 },
-
-        const Field = struct {
-            name: []const u8,
-            docs: []const u8,
-        };
-
-        pub fn jsonStringify(self: Type, jsw: anytype) !void {
-            const active_tag = std.meta.activeTag(self);
-            try jsw.beginArray();
-            try jsw.write(@intFromEnum(active_tag));
-            inline for (comptime std.meta.fields(Type)) |case| {
-                if (@field(Type, case.name) == active_tag) {
-                    const current_value = @field(self, case.name);
-                    inline for (comptime std.meta.fields(case.type)) |f| {
-                        if (f.type == std.builtin.Type.Pointer.Size) {
-                            try jsw.write(@intFromEnum(@field(current_value, f.name)));
-                        } else {
-                            try jsw.write(@field(current_value, f.name));
-                        }
-                    }
-                }
-            }
-            try jsw.endArray();
-        }
-    };
-
-    /// An Expr represents the (untyped) result of analyzing instructions.
-    /// The data is normalized, which means that an Expr that results in a
-    /// type definition will hold an index into `self.types`.
-    pub const Expr = union(enum) {
-        comptimeExpr: usize, // index in `comptimeExprs`
-        void: struct {},
-        @"unreachable": struct {},
-        null: struct {},
-        undefined: struct {},
-        @"struct": []FieldVal,
-        fieldVal: FieldVal,
-        bool: bool,
-        @"anytype": struct {},
-        @"&": usize, // index in `exprs`
-        type: usize, // index in `types`
-        this: usize, // index in `types`
-        declRef: *Scope.DeclStatus,
-        declIndex: usize, // index into `decls`, alternative repr for `declRef`
-        declName: []const u8, // unresolved decl name
-        builtinField: enum { len, ptr },
-        fieldRef: FieldRef,
-        refPath: []Expr,
-        int: struct {
-            value: u64, // direct value
-            negated: bool = false,
-        },
-        int_big: struct {
-            value: []const u8, // string representation
-            negated: bool = false,
-        },
-        float: f64, // direct value
-        float128: f128, // direct value
-        array: []usize, // index in `exprs`
-        call: usize, // index in `calls`
-        enumLiteral: []const u8, // direct value
-        typeOf: usize, // index in `exprs`
-        typeOf_peer: []usize,
-        errorUnion: usize, // index in `types`
-        as: As,
-        sizeOf: usize, // index in `exprs`
-        bitSizeOf: usize, // index in `exprs`
-        compileError: usize, // index in `exprs`
-        optionalPayload: usize, // index in `exprs`
-        elemVal: ElemVal,
-        errorSets: usize,
-        string: []const u8, // direct value
-        sliceIndex: usize,
-        slice: Slice,
-        sliceLength: SliceLength,
-        cmpxchgIndex: usize,
-        cmpxchg: Cmpxchg,
-        builtin: Builtin,
-        builtinIndex: usize,
-        builtinBin: BuiltinBin,
-        builtinBinIndex: usize,
-        unionInit: UnionInit,
-        builtinCall: BuiltinCall,
-        mulAdd: MulAdd,
-        switchIndex: usize, // index in `exprs`
-        switchOp: SwitchOp,
-        unOp: UnOp,
-        unOpIndex: usize,
-        binOp: BinOp,
-        binOpIndex: usize,
-        load: usize, // index in `exprs`
-        const UnOp = struct {
-            param: usize, // index in `exprs`
-            name: []const u8 = "", // tag name
-        };
-        const BinOp = struct {
-            lhs: usize, // index in `exprs`
-            rhs: usize, // index in `exprs`
-            name: []const u8 = "", // tag name
-        };
-        const SwitchOp = struct {
-            cond_index: usize,
-            file_name: []const u8,
-            src: usize,
-            outer_decl: usize, // index in `types`
-        };
-        const BuiltinBin = struct {
-            name: []const u8 = "", // fn name
-            lhs: usize, // index in `exprs`
-            rhs: usize, // index in `exprs`
-        };
-        const UnionInit = struct {
-            type: usize, // index in `exprs`
-            field: usize, // index in `exprs`
-            init: usize, // index in `exprs`
-        };
-        const Builtin = struct {
-            name: []const u8 = "", // fn name
-            param: usize, // index in `exprs`
-        };
-        const BuiltinCall = struct {
-            modifier: usize, // index in `exprs`
-            function: usize, // index in `exprs`
-            args: usize, // index in `exprs`
-        };
-        const MulAdd = struct {
-            mulend1: usize, // index in `exprs`
-            mulend2: usize, // index in `exprs`
-            addend: usize, // index in `exprs`
-            type: usize, // index in `exprs`
-        };
-        const Slice = struct {
-            lhs: usize, // index in `exprs`
-            start: usize,
-            end: ?usize = null,
-            sentinel: ?usize = null, // index in `exprs`
-        };
-        const SliceLength = struct {
-            lhs: usize,
-            start: usize,
-            len: usize,
-            sentinel: ?usize = null,
-        };
-        const Cmpxchg = struct {
-            name: []const u8,
-            type: usize,
-            ptr: usize,
-            expected_value: usize,
-            new_value: usize,
-            success_order: usize,
-            failure_order: usize,
-        };
-        const As = struct {
-            typeRefArg: ?usize, // index in `exprs`
-            exprArg: usize, // index in `exprs`
-        };
-        const FieldRef = struct {
-            type: usize, // index in `types`
-            index: usize, // index in type.fields
-        };
-
-        const FieldVal = struct {
-            name: []const u8,
-            val: struct {
-                typeRef: ?usize, // index in `exprs`
-                expr: usize, // index in `exprs`
-            },
-        };
-
-        const ElemVal = struct {
-            lhs: usize, // index in `exprs`
-            rhs: usize, // index in `exprs`
-        };
-
-        pub fn jsonStringify(self: Expr, jsw: anytype) !void {
-            const active_tag = std.meta.activeTag(self);
-            try jsw.beginObject();
-            if (active_tag == .declIndex) {
-                try jsw.objectField("declRef");
-            } else {
-                try jsw.objectField(@tagName(active_tag));
-            }
-            switch (self) {
-                .int => {
-                    if (self.int.negated) {
-                        try jsw.write(-@as(i65, self.int.value));
-                    } else {
-                        try jsw.write(self.int.value);
-                    }
-                },
-                .builtinField => {
-                    try jsw.write(@tagName(self.builtinField));
-                },
-                .declRef => {
-                    try jsw.write(self.declRef.Analyzed);
-                },
-                else => {
-                    inline for (comptime std.meta.fields(Expr)) |case| {
-                        // TODO: this is super ugly, fix once `inline else` is a thing
-                        if (comptime std.mem.eql(u8, case.name, "builtinField"))
-                            continue;
-                        if (comptime std.mem.eql(u8, case.name, "declRef"))
-                            continue;
-                        if (@field(Expr, case.name) == active_tag) {
-                            try jsw.write(@field(self, case.name));
-                        }
-                    }
-                },
-            }
-            try jsw.endObject();
-        }
-    };
-
-    /// A WalkResult represents the result of the analysis process done to a
-    /// a Zir instruction. Walk results carry type information either inferred
-    /// from the context (eg string literals are pointers to null-terminated
-    /// arrays), or because of @as() instructions.
-    /// Since the type information is only needed in certain contexts, the
-    /// underlying normalized data (Expr) is untyped.
-    const WalkResult = struct {
-        typeRef: ?Expr = null,
-        expr: Expr,
-    };
-};
-
-const AutodocErrors = error{
-    OutOfMemory,
-    CurrentWorkingDirectoryUnlinked,
-    UnexpectedEndOfFile,
-    ModuleNotFound,
-    ImportOutsideModulePath,
-} || std.fs.File.OpenError || std.fs.File.ReadError;
-
-/// `call` instructions will have loopy references to themselves
-///  whenever an as_node is required for a complex expression.
-///  This type is used to keep track of dangerous instruction
-///  numbers that we definitely don't want to recurse into.
-const CallContext = struct {
-    inst: Zir.Inst.Index,
-    prev: ?*const CallContext,
-};
-
-/// Called when we need to analyze a Zir instruction.
-/// For example it gets called by `generateZirData` on instruction 0,
-/// which represents the top-level struct corresponding to the root file.
-/// Note that in some situations where we're analyzing code that only allows
-/// for a limited subset of Zig syntax, we don't always resort to calling
-/// `walkInstruction` and instead sometimes we handle Zir directly.
-/// The best example of that are instructions corresponding to function
-/// params, as those can only occur while analyzing a function definition.
-fn walkInstruction(
-    self: *Autodoc,
-    file: *File,
-    parent_scope: *Scope,
-    parent_src: SrcLocInfo,
-    inst: Zir.Inst.Index,
-    need_type: bool, // true if the caller needs us to provide also a typeRef
-    call_ctx: ?*const CallContext,
-) AutodocErrors!DocData.WalkResult {
-    const tags = file.zir.instructions.items(.tag);
-    const data = file.zir.instructions.items(.data);
-
-    if (self.repurposed_insts.contains(inst)) {
-        // TODO: better handling here
-        return .{ .expr = .{ .comptimeExpr = 0 } };
-    }
-
-    // We assume that the topmost ast_node entry corresponds to our decl
-    const self_ast_node_index = self.ast_nodes.items.len - 1;
-
-    switch (tags[@intFromEnum(inst)]) {
-        else => {
-            printWithContext(
-                file,
-                inst,
-                "TODO: implement `{s}` for walkInstruction\n\n",
-                .{@tagName(tags[@intFromEnum(inst)])},
-            );
-            return self.cteTodo(@tagName(tags[@intFromEnum(inst)]));
-        },
-        .import => {
-            const str_tok = data[@intFromEnum(inst)].str_tok;
-            const path = str_tok.get(file.zir);
-
-            // importFile cannot error out since all files
-            // are already loaded at this point
-            if (file.mod.deps.get(path)) |other_module| {
-                const result = try self.modules.getOrPut(self.arena, other_module);
-
-                // Immediately add this module to the import table of our
-                // current module, regardless of wether it's new or not.
-                if (self.modules.getPtr(file.mod)) |current_module| {
-                    // TODO: apparently, in the stdlib a file gets analyzed before
-                    //       its module gets added. I guess we're importing a file
-                    //       that belongs to another module through its file path?
-                    //       (ie not through its module name).
-                    //       We're bailing for now, but maybe we shouldn't?
-                    _ = try current_module.table.getOrPutValue(
-                        self.arena,
-                        other_module,
-                        .{
-                            .name = path,
-                            .value = self.modules.getIndex(other_module).?,
-                        },
-                    );
-                }
-
-                if (result.found_existing) {
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .type = result.value_ptr.main },
-                    };
-                }
-
-                // create a new module entry
-                const main_type_index = self.types.items.len;
-                result.value_ptr.* = .{
-                    .name = path,
-                    .main = main_type_index,
-                    .table = .{},
-                };
-
-                // TODO: Add this module as a dependency to the current module
-                // TODO: this seems something that could be done in bulk
-                //       at the beginning or the end, or something.
-                const abs_root_src_path = try std.fs.path.resolve(self.arena, &.{
-                    ".",
-                    other_module.root.root_dir.path orelse ".",
-                    other_module.root.sub_path,
-                    other_module.root_src_path,
-                });
-                defer self.arena.free(abs_root_src_path);
-
-                const new_file = self.zcu.import_table.get(abs_root_src_path).?;
-
-                var root_scope = Scope{
-                    .parent = null,
-                    .enclosing_type = null,
-                };
-                const maybe_tldoc_comment = try self.getTLDocComment(file);
-                try self.ast_nodes.append(self.arena, .{
-                    .name = "(root)",
-                    .docs = maybe_tldoc_comment,
-                });
-                try self.files.put(self.arena, new_file, main_type_index);
-                return self.walkInstruction(
-                    new_file,
-                    &root_scope,
-                    .{},
-                    .main_struct_inst,
-                    false,
-                    call_ctx,
-                );
-            }
-
-            const new_file = try self.zcu.importFile(file, path);
-            const result = try self.files.getOrPut(self.arena, new_file.file);
-            if (result.found_existing) {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                    .expr = .{ .type = result.value_ptr.* },
-                };
-            }
-
-            const maybe_tldoc_comment = try self.getTLDocComment(new_file.file);
-            try self.ast_nodes.append(self.arena, .{
-                .name = path,
-                .docs = maybe_tldoc_comment,
-            });
-
-            result.value_ptr.* = self.types.items.len;
-
-            var new_scope = Scope{
-                .parent = null,
-                .enclosing_type = null,
-            };
-
-            return self.walkInstruction(
-                new_file.file,
-                &new_scope,
-                .{},
-                .main_struct_inst,
-                need_type,
-                call_ctx,
-            );
-        },
-        .ret_type => {
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = @intFromEnum(Ref.type_type) },
-            };
-        },
-        .ret_node => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-            return self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-        },
-        .ret_load => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-            const res_ptr_ref = un_node.operand;
-            const res_ptr_inst = @intFromEnum(res_ptr_ref.toIndex().?);
-            // TODO: this instruction doesn't let us know trivially if there's
-            //       branching involved or not. For now here's the strat:
-            //       We search backwarts until `ret_ptr` for `store_node`,
-            //       if we find only one, then that's our value, if we find more
-            //       than one, then it means that there's branching involved.
-            //       Maybe.
-
-            var i = @intFromEnum(inst) - 1;
-            var result_ref: ?Ref = null;
-            while (i > res_ptr_inst) : (i -= 1) {
-                if (tags[i] == .store_node) {
-                    const pl_node = data[i].pl_node;
-                    const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-                    if (extra.data.lhs == res_ptr_ref) {
-                        // this store_load instruction is indeed pointing at
-                        // the result location that we care about!
-                        if (result_ref != null) return DocData.WalkResult{
-                            .expr = .{ .comptimeExpr = 0 },
-                        };
-                        result_ref = extra.data.rhs;
-                    }
-                }
-            }
-
-            if (result_ref) |rr| {
-                return self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    rr,
-                    need_type,
-                    call_ctx,
-                );
-            }
-
-            return DocData.WalkResult{
-                .expr = .{ .comptimeExpr = 0 },
-            };
-        },
-        .str => {
-            const str = data[@intFromEnum(inst)].str.get(file.zir);
-
-            const tRef: ?DocData.Expr = if (!need_type) null else blk: {
-                const arrTypeId = self.types.items.len;
-                try self.types.append(self.arena, .{
-                    .Array = .{
-                        .len = .{ .int = .{ .value = str.len } },
-                        .child = .{ .type = @intFromEnum(Ref.u8_type) },
-                        .sentinel = .{ .int = .{
-                            .value = 0,
-                            .negated = false,
-                        } },
-                    },
-                });
-                // const sentinel: ?usize = if (ptr.flags.has_sentinel) 0 else null;
-                const ptrTypeId = self.types.items.len;
-                try self.types.append(self.arena, .{
-                    .Pointer = .{
-                        .size = .One,
-                        .child = .{ .type = arrTypeId },
-                        .sentinel = .{ .int = .{
-                            .value = 0,
-                            .negated = false,
-                        } },
-                        .is_mutable = false,
-                    },
-                });
-                break :blk .{ .type = ptrTypeId };
-            };
-
-            return DocData.WalkResult{
-                .typeRef = tRef,
-                .expr = .{ .string = str },
-            };
-        },
-        .compile_error => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-
-            const operand_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            return DocData.WalkResult{
-                .expr = .{ .compileError = operand_index },
-            };
-        },
-        .enum_literal => {
-            const str_tok = data[@intFromEnum(inst)].str_tok;
-            const literal = file.zir.nullTerminatedString(str_tok.start);
-            const type_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .EnumLiteral = .{ .name = "todo enum literal" },
-            });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = type_index },
-                .expr = .{ .enumLiteral = literal },
-            };
-        },
-        .int => {
-            const int = data[@intFromEnum(inst)].int;
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                .expr = .{ .int = .{ .value = int } },
-            };
-        },
-        .int_big => {
-            // @check
-            const str = data[@intFromEnum(inst)].str; //.get(file.zir);
-            const byte_count = str.len * @sizeOf(std.math.big.Limb);
-            const limb_bytes = file.zir.string_bytes[@intFromEnum(str.start)..][0..byte_count];
-
-            const limbs = try self.arena.alloc(std.math.big.Limb, str.len);
-            @memcpy(std.mem.sliceAsBytes(limbs)[0..limb_bytes.len], limb_bytes);
-
-            const big_int = std.math.big.int.Const{
-                .limbs = limbs,
-                .positive = true,
-            };
-
-            const as_string = try big_int.toStringAlloc(self.arena, 10, .lower);
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                .expr = .{ .int_big = .{ .value = as_string } },
-            };
-        },
-        .@"unreachable" => {
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.noreturn_type) },
-                .expr = .{ .@"unreachable" = .{} },
-            };
-        },
-
-        .slice_start => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.SliceStart, pl_node.payload_index);
-
-            const slice_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const start: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.start,
-                false,
-                call_ctx,
-            );
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const start_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, start.expr);
-            self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index } };
-
-            const typeRef = switch (lhs.expr) {
-                .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
-                else => null,
-            };
-
-            return DocData.WalkResult{
-                .typeRef = typeRef,
-                .expr = .{ .sliceIndex = slice_index },
-            };
-        },
-        .slice_end => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.SliceEnd, pl_node.payload_index);
-
-            const slice_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const start: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.start,
-                false,
-                call_ctx,
-            );
-            const end: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.end,
-                false,
-                call_ctx,
-            );
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const start_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, start.expr);
-            const end_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, end.expr);
-            self.exprs.items[slice_index] = .{ .slice = .{ .lhs = lhs_index, .start = start_index, .end = end_index } };
-
-            const typeRef = switch (lhs.expr) {
-                .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
-                else => null,
-            };
-
-            return DocData.WalkResult{
-                .typeRef = typeRef,
-                .expr = .{ .sliceIndex = slice_index },
-            };
-        },
-        .slice_sentinel => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.SliceSentinel, pl_node.payload_index);
-
-            const slice_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const start: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.start,
-                false,
-                call_ctx,
-            );
-            const end: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.end,
-                false,
-                call_ctx,
-            );
-            const sentinel: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.sentinel,
-                false,
-                call_ctx,
-            );
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const start_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, start.expr);
-            const end_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, end.expr);
-            const sentinel_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, sentinel.expr);
-            self.exprs.items[slice_index] = .{ .slice = .{
-                .lhs = lhs_index,
-                .start = start_index,
-                .end = end_index,
-                .sentinel = sentinel_index,
-            } };
-
-            const typeRef = switch (lhs.expr) {
-                .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
-                else => null,
-            };
-
-            return DocData.WalkResult{
-                .typeRef = typeRef,
-                .expr = .{ .sliceIndex = slice_index },
-            };
-        },
-        .slice_length => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.SliceLength, pl_node.payload_index);
-
-            const slice_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .slice = .{ .lhs = 0, .start = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const start: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.start,
-                false,
-                call_ctx,
-            );
-            const len: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.len,
-                false,
-                call_ctx,
-            );
-            const sentinel_opt: ?DocData.WalkResult = if (extra.data.sentinel != .none)
-                try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    extra.data.sentinel,
-                    false,
-                    call_ctx,
-                )
-            else
-                null;
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const start_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, start.expr);
-            const len_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, len.expr);
-            const sentinel_index = if (sentinel_opt) |sentinel| sentinel_index: {
-                const index = self.exprs.items.len;
-                try self.exprs.append(self.arena, sentinel.expr);
-                break :sentinel_index index;
-            } else null;
-            self.exprs.items[slice_index] = .{ .sliceLength = .{
-                .lhs = lhs_index,
-                .start = start_index,
-                .len = len_index,
-                .sentinel = sentinel_index,
-            } };
-
-            const typeRef = switch (lhs.expr) {
-                .declRef => |ref| self.decls.items[ref.Analyzed].value.typeRef,
-                else => null,
-            };
-
-            return DocData.WalkResult{
-                .typeRef = typeRef,
-                .expr = .{ .sliceIndex = slice_index },
-            };
-        },
-
-        .load => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                need_type,
-                call_ctx,
-            );
-            const load_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            var typeRef: ?DocData.Expr = null;
-            if (operand.typeRef) |ref| {
-                switch (ref) {
-                    .type => |t_index| {
-                        switch (self.types.items[t_index]) {
-                            .Pointer => |p| typeRef = p.child,
-                            else => {},
-                        }
-                    },
-                    else => {},
-                }
-            }
-
-            return DocData.WalkResult{
-                .typeRef = typeRef,
-                .expr = .{ .load = load_idx },
-            };
-        },
-        .ref => {
-            const un_tok = data[@intFromEnum(inst)].un_tok;
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_tok.operand,
-                need_type,
-                call_ctx,
-            );
-            const ref_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            return DocData.WalkResult{
-                .expr = .{ .@"&" = ref_idx },
-            };
-        },
-
-        .add,
-        .addwrap,
-        .add_sat,
-        .sub,
-        .subwrap,
-        .sub_sat,
-        .mul,
-        .mulwrap,
-        .mul_sat,
-        .div,
-        .shl,
-        .shl_sat,
-        .shr,
-        .bit_or,
-        .bit_and,
-        .xor,
-        .array_cat,
-        => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-
-            const binop_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const rhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-            self.exprs.items[binop_index] = .{ .binOp = .{
-                .name = @tagName(tags[@intFromEnum(inst)]),
-                .lhs = lhs_index,
-                .rhs = rhs_index,
-            } };
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .binOpIndex = binop_index },
-            };
-        },
-        .array_mul => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.ArrayMul, pl_node.payload_index);
-
-            const binop_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-            const res_ty: ?DocData.WalkResult = if (extra.data.res_ty != .none)
-                try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    extra.data.res_ty,
-                    false,
-                    call_ctx,
-                )
-            else
-                null;
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const rhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-            self.exprs.items[binop_index] = .{ .binOp = .{
-                .name = @tagName(tags[@intFromEnum(inst)]),
-                .lhs = lhs_index,
-                .rhs = rhs_index,
-            } };
-
-            return DocData.WalkResult{
-                .typeRef = if (res_ty) |rt| rt.expr else null,
-                .expr = .{ .binOpIndex = binop_index },
-            };
-        },
-        // compare operators
-        .cmp_eq,
-        .cmp_neq,
-        .cmp_gt,
-        .cmp_gte,
-        .cmp_lt,
-        .cmp_lte,
-        => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-
-            const binop_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const rhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-            self.exprs.items[binop_index] = .{ .binOp = .{
-                .name = @tagName(tags[@intFromEnum(inst)]),
-                .lhs = lhs_index,
-                .rhs = rhs_index,
-            } };
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
-                .expr = .{ .binOpIndex = binop_index },
-            };
-        },
-
-        // builtin functions
-        .align_of,
-        .int_from_bool,
-        .embed_file,
-        .error_name,
-        .panic,
-        .set_runtime_safety, // @check
-        .sqrt,
-        .sin,
-        .cos,
-        .tan,
-        .exp,
-        .exp2,
-        .log,
-        .log2,
-        .log10,
-        .abs,
-        .floor,
-        .ceil,
-        .trunc,
-        .round,
-        .tag_name,
-        .type_name,
-        .frame_type,
-        .frame_size,
-        .int_from_ptr,
-        .type_info,
-        // @check
-        .clz,
-        .ctz,
-        .pop_count,
-        .byte_swap,
-        .bit_reverse,
-        => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-            const bin_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
-            const param = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-
-            const param_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, param.expr);
-
-            self.exprs.items[bin_index] = .{
-                .builtin = .{
-                    .name = @tagName(tags[@intFromEnum(inst)]),
-                    .param = param_index,
-                },
-            };
-
-            return DocData.WalkResult{
-                .typeRef = param.typeRef orelse .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .builtinIndex = bin_index },
-            };
-        },
-        .bit_not,
-        .bool_not,
-        .negate_wrap,
-        => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-            const un_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .unOp = .{ .param = 0 } });
-            const param = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-
-            const param_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, param.expr);
-
-            self.exprs.items[un_index] = .{
-                .unOp = .{
-                    .name = @tagName(tags[@intFromEnum(inst)]),
-                    .param = param_index,
-                },
-            };
-
-            return DocData.WalkResult{
-                .typeRef = param.typeRef,
-                .expr = .{ .unOpIndex = un_index },
-            };
-        },
-        .bool_br_and, .bool_br_or => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.BoolBr, pl_node.payload_index);
-
-            const bin_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .binOp = .{ .lhs = 0, .rhs = 0 } });
-
-            const lhs = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-
-            const rhs = try self.walkInstruction(
-                file,
-                parent_scope,
-                parent_src,
-                @enumFromInt(file.zir.extra[extra.end..][extra.data.body_len - 1]),
-                false,
-                call_ctx,
-            );
-            const rhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-
-            self.exprs.items[bin_index] = .{ .binOp = .{ .name = @tagName(tags[@intFromEnum(inst)]), .lhs = lhs_index, .rhs = rhs_index } };
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
-                .expr = .{ .binOpIndex = bin_index },
-            };
-        },
-        .truncate => {
-            // in the ZIR this node is a builtin `bin` but we want send it as a `un` builtin
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-
-            const bin_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
-
-            const rhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-
-            self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(tags[@intFromEnum(inst)]), .param = rhs_index } };
-
-            return DocData.WalkResult{
-                .typeRef = lhs.expr,
-                .expr = .{ .builtinIndex = bin_index },
-            };
-        },
-        .int_from_float,
-        .float_from_int,
-        .ptr_from_int,
-        .enum_from_int,
-        .float_cast,
-        .int_cast,
-        .ptr_cast,
-        .has_decl,
-        .has_field,
-        .div_exact,
-        .div_floor,
-        .div_trunc,
-        .mod,
-        .rem,
-        .mod_rem,
-        .shl_exact,
-        .shr_exact,
-        .bitcast,
-        .vector_type,
-        // @check
-        .bit_offset_of,
-        .offset_of,
-        .splat,
-        .reduce,
-        .min,
-        .max,
-        => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-
-            const binop_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .builtinBin = .{ .lhs = 0, .rhs = 0 } });
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-
-            const lhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const rhs_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-            self.exprs.items[binop_index] = .{ .builtinBin = .{ .name = @tagName(tags[@intFromEnum(inst)]), .lhs = lhs_index, .rhs = rhs_index } };
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .builtinBinIndex = binop_index },
-            };
-        },
-        .mul_add => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.MulAdd, pl_node.payload_index);
-
-            const mul1: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.mulend1,
-                false,
-                call_ctx,
-            );
-            const mul2: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.mulend2,
-                false,
-                call_ctx,
-            );
-            const add: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.addend,
-                false,
-                call_ctx,
-            );
-
-            const mul1_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, mul1.expr);
-            const mul2_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, mul2.expr);
-            const add_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, add.expr);
-
-            const type_index: usize = self.exprs.items.len;
-            try self.exprs.append(self.arena, add.typeRef orelse .{ .type = @intFromEnum(Ref.type_type) });
-
-            return DocData.WalkResult{
-                .typeRef = add.typeRef,
-                .expr = .{
-                    .mulAdd = .{
-                        .mulend1 = mul1_index,
-                        .mulend2 = mul2_index,
-                        .addend = add_index,
-                        .type = type_index,
-                    },
-                },
-            };
-        },
-        .union_init => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.UnionInit, pl_node.payload_index);
-
-            const union_type: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.union_type,
-                false,
-                call_ctx,
-            );
-            const field_name: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.field_name,
-                false,
-                call_ctx,
-            );
-            const init: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.init,
-                false,
-                call_ctx,
-            );
-
-            const union_type_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, union_type.expr);
-            const field_name_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, field_name.expr);
-            const init_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, init.expr);
-
-            return DocData.WalkResult{
-                .typeRef = union_type.expr,
-                .expr = .{
-                    .unionInit = .{
-                        .type = union_type_index,
-                        .field = field_name_index,
-                        .init = init_index,
-                    },
-                },
-            };
-        },
-        .builtin_call => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.BuiltinCall, pl_node.payload_index);
-
-            const modifier: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.modifier,
-                false,
-                call_ctx,
-            );
-
-            const callee: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.callee,
-                false,
-                call_ctx,
-            );
-
-            const args: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.args,
-                false,
-                call_ctx,
-            );
-
-            const modifier_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, modifier.expr);
-            const function_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, callee.expr);
-            const args_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, args.expr);
-
-            return DocData.WalkResult{
-                .expr = .{
-                    .builtinCall = .{
-                        .modifier = modifier_index,
-                        .function = function_index,
-                        .args = args_index,
-                    },
-                },
-            };
-        },
-        .error_union_type => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{ .ErrorUnion = .{
-                .lhs = lhs.expr,
-                .rhs = rhs.expr,
-            } });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .errorUnion = type_slot_index },
-            };
-        },
-        .merge_error_sets => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-
-            const lhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                false,
-                call_ctx,
-            );
-            const rhs: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                false,
-                call_ctx,
-            );
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{ .ErrorUnion = .{
-                .lhs = lhs.expr,
-                .rhs = rhs.expr,
-            } });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .errorSets = type_slot_index },
-            };
-        },
-        // .elem_type => {
-        //     const un_node = data[@intFromEnum(inst)].un_node;
-
-        //     const operand: DocData.WalkResult = try self.walkRef(
-        //         file,
-        //         parent_scope, parent_src,
-        //         un_node.operand,
-        //         false,
-        //     );
-
-        //     return operand;
-        // },
-        .ptr_type => {
-            const ptr = data[@intFromEnum(inst)].ptr_type;
-            const extra = file.zir.extraData(Zir.Inst.PtrType, ptr.payload_index);
-            var extra_index = extra.end;
-
-            const elem_type_ref = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.elem_type,
-                false,
-                call_ctx,
-            );
-
-            // @check if `addrspace`, `bit_start` and `host_size` really need to be
-            // present in json
-            var sentinel: ?DocData.Expr = null;
-            if (ptr.flags.has_sentinel) {
-                const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-                const ref_result = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                sentinel = ref_result.expr;
-                extra_index += 1;
-            }
-
-            var @"align": ?DocData.Expr = null;
-            if (ptr.flags.has_align) {
-                const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-                const ref_result = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                @"align" = ref_result.expr;
-                extra_index += 1;
-            }
-            var address_space: ?DocData.Expr = null;
-            if (ptr.flags.has_addrspace) {
-                const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-                const ref_result = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                address_space = ref_result.expr;
-                extra_index += 1;
-            }
-            const bit_start: ?DocData.Expr = null;
-            if (ptr.flags.has_bit_range) {
-                const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-                const ref_result = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                address_space = ref_result.expr;
-                extra_index += 1;
-            }
-
-            var host_size: ?DocData.Expr = null;
-            if (ptr.flags.has_bit_range) {
-                const ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-                const ref_result = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                host_size = ref_result.expr;
-            }
-
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .Pointer = .{
-                    .size = ptr.size,
-                    .child = elem_type_ref.expr,
-                    .has_align = ptr.flags.has_align,
-                    .@"align" = @"align",
-                    .has_addrspace = ptr.flags.has_addrspace,
-                    .address_space = address_space,
-                    .has_sentinel = ptr.flags.has_sentinel,
-                    .sentinel = sentinel,
-                    .is_mutable = ptr.flags.is_mutable,
-                    .is_volatile = ptr.flags.is_volatile,
-                    .has_bit_range = ptr.flags.has_bit_range,
-                    .bit_start = bit_start,
-                    .host_size = host_size,
-                },
-            });
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = type_slot_index },
-            };
-        },
-        .array_type => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-
-            const bin = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index).data;
-            const len = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                bin.lhs,
-                false,
-                call_ctx,
-            );
-            const child = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                bin.rhs,
-                false,
-                call_ctx,
-            );
-
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .Array = .{
-                    .len = len.expr,
-                    .child = child.expr,
-                },
-            });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = type_slot_index },
-            };
-        },
-        .array_type_sentinel => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.ArrayTypeSentinel, pl_node.payload_index);
-            const len = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.len,
-                false,
-                call_ctx,
-            );
-            const sentinel = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.sentinel,
-                false,
-                call_ctx,
-            );
-            const elem_type = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.elem_type,
-                false,
-                call_ctx,
-            );
-
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .Array = .{
-                    .len = len.expr,
-                    .child = elem_type.expr,
-                    .sentinel = sentinel.expr,
-                },
-            });
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = type_slot_index },
-            };
-        },
-        .array_init => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
-            const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
-            const array_data = try self.arena.alloc(usize, operands.len - 1);
-
-            std.debug.assert(operands.len > 0);
-            const array_type = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                operands[0],
-                false,
-                call_ctx,
-            );
-
-            for (operands[1..], 0..) |op, idx| {
-                const wr = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    op,
-                    false,
-                    call_ctx,
-                );
-                const expr_index = self.exprs.items.len;
-                try self.exprs.append(self.arena, wr.expr);
-                array_data[idx] = expr_index;
-            }
-
-            return DocData.WalkResult{
-                .typeRef = array_type.expr,
-                .expr = .{ .array = array_data },
-            };
-        },
-        .array_init_anon => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
-            const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
-            const array_data = try self.arena.alloc(usize, operands.len);
-
-            for (operands, 0..) |op, idx| {
-                const wr = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    op,
-                    false,
-                    call_ctx,
-                );
-                const expr_index = self.exprs.items.len;
-                try self.exprs.append(self.arena, wr.expr);
-                array_data[idx] = expr_index;
-            }
-
-            return DocData.WalkResult{
-                .typeRef = null,
-                .expr = .{ .array = array_data },
-            };
-        },
-        .array_init_ref => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.MultiOp, pl_node.payload_index);
-            const operands = file.zir.refSlice(extra.end, extra.data.operands_len);
-            const array_data = try self.arena.alloc(usize, operands.len - 1);
-
-            std.debug.assert(operands.len > 0);
-            const array_type = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                operands[0],
-                false,
-                call_ctx,
-            );
-
-            for (operands[1..], 0..) |op, idx| {
-                const wr = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    op,
-                    false,
-                    call_ctx,
-                );
-                const expr_index = self.exprs.items.len;
-                try self.exprs.append(self.arena, wr.expr);
-                array_data[idx] = expr_index;
-            }
-
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .Pointer = .{
-                    .size = .One,
-                    .child = array_type.expr,
-                },
-            });
-
-            const expr_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .array = array_data });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = type_slot_index },
-                .expr = .{ .@"&" = expr_index },
-            };
-        },
-        .float => {
-            const float = data[@intFromEnum(inst)].float;
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.comptime_float_type) },
-                .expr = .{ .float = float },
-            };
-        },
-        // @check: In frontend I'm handling float128 with `.toFixed(2)`
-        .float128 => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Float128, pl_node.payload_index);
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.comptime_float_type) },
-                .expr = .{ .float128 = extra.data.get() },
-            };
-        },
-        .negate => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            var operand: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                need_type,
-                call_ctx,
-            );
-            switch (operand.expr) {
-                .int => |*int| int.negated = true,
-                .int_big => |*int_big| int_big.negated = true,
-                else => {
-                    const un_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, .{ .unOp = .{ .param = 0 } });
-                    const param_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, operand.expr);
-                    self.exprs.items[un_index] = .{
-                        .unOp = .{
-                            .name = @tagName(tags[@intFromEnum(inst)]),
-                            .param = param_index,
-                        },
-                    };
-                    return DocData.WalkResult{
-                        .typeRef = operand.typeRef,
-                        .expr = .{ .unOpIndex = un_index },
-                    };
-                },
-            }
-            return operand;
-        },
-        .size_of => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-            const operand_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                .expr = .{ .sizeOf = operand_index },
-            };
-        },
-        .bit_size_of => {
-            // not working correctly with `align()`
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                need_type,
-                call_ctx,
-            );
-            const operand_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            return DocData.WalkResult{
-                .typeRef = operand.typeRef,
-                .expr = .{ .bitSizeOf = operand_index },
-            };
-        },
-        .int_from_enum => {
-            // not working correctly with `align()`
-            const un_node = data[@intFromEnum(inst)].un_node;
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-            const builtin_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
-            const operand_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-            self.exprs.items[builtin_index] = .{
-                .builtin = .{
-                    .name = @tagName(tags[@intFromEnum(inst)]),
-                    .param = operand_index,
-                },
-            };
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                .expr = .{ .builtinIndex = builtin_index },
-            };
-        },
-        .switch_block => {
-            // WIP
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.SwitchBlock, pl_node.payload_index);
-
-            const switch_cond = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.operand,
-                false,
-                call_ctx,
-            );
-            const cond_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, switch_cond.expr);
-            _ = cond_index;
-
-            // const ast_index = self.ast_nodes.items.len;
-            // const type_index = self.types.items.len - 1;
-
-            // const ast_line = self.ast_nodes.items[ast_index - 1];
-
-            // const sep = "=" ** 200;
-            // log.debug("{s}", .{sep});
-            // log.debug("SWITCH BLOCK", .{});
-            // log.debug("extra = {any}", .{extra});
-            // log.debug("outer_decl = {any}", .{self.types.items[type_index]});
-            // log.debug("ast_lines = {}", .{ast_line});
-            // log.debug("{s}", .{sep});
-
-            const switch_index = self.exprs.items.len;
-
-            // const src_loc = try self.srcLocInfo(file, pl_node.src_node, parent_src);
-
-            const switch_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
-            try self.exprs.append(self.arena, .{ .comptimeExpr = self.comptime_exprs.items.len });
-            try self.comptime_exprs.append(self.arena, .{ .code = switch_expr });
-            // try self.exprs.append(self.arena, .{ .switchOp = .{
-            //     .cond_index = cond_index,
-            //     .file_name = file.sub_file_path,
-            //     .src = ast_index,
-            //     .outer_decl = type_index,
-            // } });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .switchIndex = switch_index },
-            };
-        },
-
-        .typeof => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                need_type,
-                call_ctx,
-            );
-            const operand_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            return DocData.WalkResult{
-                .typeRef = operand.typeRef,
-                .expr = .{ .typeOf = operand_index },
-            };
-        },
-        .typeof_builtin => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
-            const body = file.zir.extra[extra.end..][extra.data.body_len - 1];
-            const operand: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                data[body].@"break".operand,
-                false,
-                call_ctx,
-            );
-
-            const operand_index = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            return DocData.WalkResult{
-                .typeRef = operand.typeRef,
-                .expr = .{ .typeOf = operand_index },
-            };
-        },
-        .as_node, .as_shift_operand => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.As, pl_node.payload_index);
-
-            // Skip the as_node if the destination type is a call instruction
-            if (extra.data.dest_type.toIndex()) |dti| {
-                var maybe_cc = call_ctx;
-                while (maybe_cc) |cc| : (maybe_cc = cc.prev) {
-                    if (cc.inst == dti) {
-                        return try self.walkRef(
-                            file,
-                            parent_scope,
-                            parent_src,
-                            extra.data.operand,
-                            false,
-                            call_ctx,
-                        );
-                    }
-                }
-            }
-
-            const dest_type_walk = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.dest_type,
-                false,
-                call_ctx,
-            );
-
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.operand,
-                false,
-                call_ctx,
-            );
-
-            const operand_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            const dest_type_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, dest_type_walk.expr);
-
-            // TODO: there's something wrong with how both `as` and `WalkrResult`
-            //       try to store type information.
-            return DocData.WalkResult{
-                .typeRef = dest_type_walk.expr,
-                .expr = .{
-                    .as = .{
-                        .typeRefArg = dest_type_idx,
-                        .exprArg = operand_idx,
-                    },
-                },
-            };
-        },
-        .optional_type => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-
-            const operand_idx = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .Optional = .{ .name = "?TODO", .child = operand.expr },
-            });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = operand_idx },
-            };
-        },
-        .decl_val, .decl_ref => {
-            const str_tok = data[@intFromEnum(inst)].str_tok;
-            const decl_status = parent_scope.resolveDeclName(str_tok.start, file, inst.toOptional());
-            return DocData.WalkResult{
-                .expr = .{ .declRef = decl_status },
-            };
-        },
-        .field_val, .field_ptr => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Field, pl_node.payload_index);
-
-            var path: std.ArrayListUnmanaged(DocData.Expr) = .{};
-            try path.append(self.arena, .{
-                .declName = file.zir.nullTerminatedString(extra.data.field_name_start),
-            });
-
-            // Put inside path the starting index of each decl name that
-            // we encounter as we navigate through all the field_*s
-            const lhs_ref = blk: {
-                var lhs_extra = extra;
-                while (true) {
-                    const lhs = @intFromEnum(lhs_extra.data.lhs.toIndex() orelse {
-                        break :blk lhs_extra.data.lhs;
-                    });
-
-                    if (tags[lhs] != .field_val and
-                        tags[lhs] != .field_ptr)
-                    {
-                        break :blk lhs_extra.data.lhs;
-                    }
-
-                    lhs_extra = file.zir.extraData(
-                        Zir.Inst.Field,
-                        data[lhs].pl_node.payload_index,
-                    );
-
-                    try path.append(self.arena, .{
-                        .declName = file.zir.nullTerminatedString(lhs_extra.data.field_name_start),
-                    });
-                }
-            };
-
-            // If the lhs is a `call` instruction, it means that we're inside
-            // a function call and we're referring to one of its arguments.
-            // We can't just blindly analyze the instruction or we will
-            // start recursing forever.
-            // TODO: add proper resolution of the container type for `calls`
-            // TODO: we're like testing lhs as an instruction twice
-            //       (above and below) this todo, maybe a cleaer solution woul
-            //       avoid that.
-            // TODO: double check that we really don't need type info here
-
-            const wr = blk: {
-                if (lhs_ref.toIndex()) |lhs_inst| switch (tags[@intFromEnum(lhs_inst)]) {
-                    .call, .field_call => {
-                        break :blk DocData.WalkResult{
-                            .expr = .{
-                                .comptimeExpr = 0,
-                            },
-                        };
-                    },
-                    else => {},
-                };
-
-                break :blk try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    lhs_ref,
-                    false,
-                    call_ctx,
-                );
-            };
-            try path.append(self.arena, wr.expr);
-
-            // This way the data in `path` has the same ordering that the ref
-            // path has in the text: most general component first.
-            std.mem.reverse(DocData.Expr, path.items);
-
-            // Righ now, every element of `path` is a string except its first
-            // element (at index 0). We're now going to attempt to resolve each
-            // string. If one or more components in this path are not yet fully
-            // analyzed, the path will only be solved partially, but we expect
-            // to eventually solve it fully(or give up in case of a
-            // comptimeExpr). This means that:
-            // - (1) Paths can be not fully analyzed temporarily, so any code
-            //       that requires to know where a ref path leads to, neeeds to
-            //       implement support for lazyness (see self.pending_ref_paths)
-            // - (2) Paths can sometimes never resolve fully. This means that
-            //       any value that depends on that will have to become a
-            //       comptimeExpr.
-            try self.tryResolveRefPath(file, inst, path.items);
-            return DocData.WalkResult{ .expr = .{ .refPath = path.items } };
-        },
-        .int_type => {
-            const int_type = data[@intFromEnum(inst)].int_type;
-            const sign = if (int_type.signedness == .unsigned) "u" else "i";
-            const bits = int_type.bit_count;
-            const name = try std.fmt.allocPrint(self.arena, "{s}{}", .{ sign, bits });
-
-            try self.types.append(self.arena, .{
-                .Int = .{ .name = name },
-            });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = self.types.items.len - 1 },
-            };
-        },
-        .block => {
-            const res = DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .comptimeExpr = self.comptime_exprs.items.len },
-            };
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const block_expr = try self.getBlockSource(file, parent_src, pl_node.src_node);
-            try self.comptime_exprs.append(self.arena, .{
-                .code = block_expr,
-            });
-            return res;
-        },
-        .block_inline => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Block, pl_node.payload_index);
-            return self.walkInlineBody(
-                file,
-                parent_scope,
-                try self.srcLocInfo(file, pl_node.src_node, parent_src),
-                parent_src,
-                file.zir.bodySlice(extra.end, extra.data.body_len),
-                need_type,
-                call_ctx,
-            );
-        },
-        .break_inline => {
-            const @"break" = data[@intFromEnum(inst)].@"break";
-            return try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                @"break".operand,
-                need_type,
-                call_ctx,
-            );
-        },
-        .struct_init => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.StructInit, pl_node.payload_index);
-            const field_vals = try self.arena.alloc(
-                DocData.Expr.FieldVal,
-                extra.data.fields_len,
-            );
-
-            var type_ref: DocData.Expr = undefined;
-            var idx = extra.end;
-            for (field_vals) |*fv| {
-                const init_extra = file.zir.extraData(Zir.Inst.StructInit.Item, idx);
-                defer idx = init_extra.end;
-
-                const field_name = blk: {
-                    const field_inst_index = @intFromEnum(init_extra.data.field_type);
-                    if (tags[field_inst_index] != .struct_init_field_type) unreachable;
-                    const field_pl_node = data[field_inst_index].pl_node;
-                    const field_extra = file.zir.extraData(
-                        Zir.Inst.FieldType,
-                        field_pl_node.payload_index,
-                    );
-                    const field_src = try self.srcLocInfo(
-                        file,
-                        field_pl_node.src_node,
-                        parent_src,
-                    );
-
-                    // On first iteration use field info to find out the struct type
-                    if (idx == extra.end) {
-                        const wr = try self.walkRef(
-                            file,
-                            parent_scope,
-                            field_src,
-                            field_extra.data.container_type,
-                            false,
-                            call_ctx,
-                        );
-                        type_ref = wr.expr;
-                    }
-                    break :blk file.zir.nullTerminatedString(field_extra.data.name_start);
-                };
-                const value = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    init_extra.data.init,
-                    need_type,
-                    call_ctx,
-                );
-                const exprIdx = self.exprs.items.len;
-                try self.exprs.append(self.arena, value.expr);
-                var typeRefIdx: ?usize = null;
-                if (value.typeRef) |ref| {
-                    typeRefIdx = self.exprs.items.len;
-                    try self.exprs.append(self.arena, ref);
-                }
-                fv.* = .{
-                    .name = field_name,
-                    .val = .{
-                        .typeRef = typeRefIdx,
-                        .expr = exprIdx,
-                    },
-                };
-            }
-
-            return DocData.WalkResult{
-                .typeRef = type_ref,
-                .expr = .{ .@"struct" = field_vals },
-            };
-        },
-        .struct_init_empty,
-        .struct_init_empty_result,
-        => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-
-            return DocData.WalkResult{
-                .typeRef = operand.expr,
-                .expr = .{ .@"struct" = &.{} },
-            };
-        },
-        .struct_init_empty_ref_result => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-
-            const operand: DocData.WalkResult = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                false,
-                call_ctx,
-            );
-
-            const struct_init_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, .{ .@"struct" = &.{} });
-
-            return DocData.WalkResult{
-                .typeRef = operand.expr,
-                .expr = .{ .@"&" = struct_init_idx },
-            };
-        },
-        .struct_init_anon => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.StructInitAnon, pl_node.payload_index);
-
-            const field_vals = try self.arena.alloc(
-                DocData.Expr.FieldVal,
-                extra.data.fields_len,
-            );
-
-            var idx = extra.end;
-            for (field_vals) |*fv| {
-                const init_extra = file.zir.extraData(Zir.Inst.StructInitAnon.Item, idx);
-                const field_name = file.zir.nullTerminatedString(init_extra.data.field_name);
-                const value = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    init_extra.data.init,
-                    need_type,
-                    call_ctx,
-                );
-
-                const exprIdx = self.exprs.items.len;
-                try self.exprs.append(self.arena, value.expr);
-                var typeRefIdx: ?usize = null;
-                if (value.typeRef) |ref| {
-                    typeRefIdx = self.exprs.items.len;
-                    try self.exprs.append(self.arena, ref);
-                }
-
-                fv.* = .{
-                    .name = field_name,
-                    .val = .{
-                        .typeRef = typeRefIdx,
-                        .expr = exprIdx,
-                    },
-                };
-
-                idx = init_extra.end;
-            }
-
-            return DocData.WalkResult{
-                .expr = .{ .@"struct" = field_vals },
-            };
-        },
-        .error_set_decl => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.ErrorSetDecl, pl_node.payload_index);
-            const fields = try self.arena.alloc(
-                DocData.Type.Field,
-                extra.data.fields_len,
-            );
-            var idx = extra.end;
-            for (fields) |*f| {
-                const name = file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[idx]));
-                idx += 1;
-
-                const docs = file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[idx]));
-                idx += 1;
-
-                f.* = .{
-                    .name = name,
-                    .docs = docs,
-                };
-            }
-
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .ErrorSet = .{
-                    .name = "todo errset",
-                    .fields = fields,
-                },
-            });
-
-            return DocData.WalkResult{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .type = type_slot_index },
-            };
-        },
-        .param_anytype, .param_anytype_comptime => {
-            // @check if .param_anytype_comptime can be here
-            // Analysis of anytype function params happens in `.func`.
-            // This switch case handles the case where an expression depends
-            // on an anytype field. E.g.: `fn foo(bar: anytype) @TypeOf(bar)`.
-            // This means that we're looking at a generic expression.
-            const str_tok = data[@intFromEnum(inst)].str_tok;
-            const name = str_tok.get(file.zir);
-            const cte_slot_index = self.comptime_exprs.items.len;
-            try self.comptime_exprs.append(self.arena, .{
-                .code = name,
-            });
-            return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
-        },
-        .param, .param_comptime => {
-            // See .param_anytype for more information.
-            const pl_tok = data[@intFromEnum(inst)].pl_tok;
-            const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
-            const name = file.zir.nullTerminatedString(extra.data.name);
-
-            const cte_slot_index = self.comptime_exprs.items.len;
-            try self.comptime_exprs.append(self.arena, .{
-                .code = name,
-            });
-            return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
-        },
-        .call => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Call, pl_node.payload_index);
-
-            const callee = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.callee,
-                need_type,
-                call_ctx,
-            );
-
-            const args_len = extra.data.flags.args_len;
-            var args = try self.arena.alloc(DocData.Expr, args_len);
-            const body = file.zir.extra[extra.end..];
-
-            try self.repurposed_insts.put(self.arena, inst, {});
-            defer _ = self.repurposed_insts.remove(inst);
-
-            var i: usize = 0;
-            while (i < args_len) : (i += 1) {
-                const arg_end = file.zir.extra[extra.end + i];
-                const break_index = body[arg_end - 1];
-                const ref = data[break_index].@"break".operand;
-                // TODO: consider toggling need_type to true if we ever want
-                //       to show discrepancies between the types of provided
-                //       arguments and the types declared in the function
-                //       signature for its parameters.
-                const wr = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    &.{
-                        .inst = inst,
-                        .prev = call_ctx,
-                    },
-                );
-                args[i] = wr.expr;
-            }
-
-            const cte_slot_index = self.comptime_exprs.items.len;
-            try self.comptime_exprs.append(self.arena, .{
-                .code = "func call",
-            });
-
-            const call_slot_index = self.calls.items.len;
-            try self.calls.append(self.arena, .{
-                .func = callee.expr,
-                .args = args,
-                .ret = .{ .comptimeExpr = cte_slot_index },
-            });
-
-            return DocData.WalkResult{
-                .typeRef = if (callee.typeRef) |tr| switch (tr) {
-                    .type => |func_type_idx| switch (self.types.items[func_type_idx]) {
-                        .Fn => |func| func.ret,
-                        else => blk: {
-                            printWithContext(
-                                file,
-                                inst,
-                                "unexpected callee type in walkInstruction.call: `{s}`\n",
-                                .{@tagName(self.types.items[func_type_idx])},
-                            );
-
-                            break :blk null;
-                        },
-                    },
-                    else => null,
-                } else null,
-                .expr = .{ .call = call_slot_index },
-            };
-        },
-        .field_call => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.FieldCall, pl_node.payload_index);
-
-            const obj_ptr = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.obj_ptr,
-                need_type,
-                call_ctx,
-            );
-
-            var field_call = try self.arena.alloc(DocData.Expr, 2);
-
-            if (obj_ptr.typeRef) |ref| {
-                field_call[0] = ref;
-            } else {
-                field_call[0] = obj_ptr.expr;
-            }
-            field_call[1] = .{ .declName = file.zir.nullTerminatedString(extra.data.field_name_start) };
-            try self.tryResolveRefPath(file, inst, field_call);
-
-            const args_len = extra.data.flags.args_len;
-            var args = try self.arena.alloc(DocData.Expr, args_len);
-            const body = file.zir.extra[extra.end..];
-
-            try self.repurposed_insts.put(self.arena, inst, {});
-            defer _ = self.repurposed_insts.remove(inst);
-
-            var i: usize = 0;
-            while (i < args_len) : (i += 1) {
-                const arg_end = file.zir.extra[extra.end + i];
-                const break_index = body[arg_end - 1];
-                const ref = data[break_index].@"break".operand;
-                // TODO: consider toggling need_type to true if we ever want
-                //       to show discrepancies between the types of provided
-                //       arguments and the types declared in the function
-                //       signature for its parameters.
-                const wr = try self.walkRef(
-                    file,
-                    parent_scope,
-                    parent_src,
-                    ref,
-                    false,
-                    &.{
-                        .inst = inst,
-                        .prev = call_ctx,
-                    },
-                );
-                args[i] = wr.expr;
-            }
-
-            const cte_slot_index = self.comptime_exprs.items.len;
-            try self.comptime_exprs.append(self.arena, .{
-                .code = "field call",
-            });
-
-            const call_slot_index = self.calls.items.len;
-            try self.calls.append(self.arena, .{
-                .func = .{ .refPath = field_call },
-                .args = args,
-                .ret = .{ .comptimeExpr = cte_slot_index },
-            });
-
-            return DocData.WalkResult{
-                .expr = .{ .call = call_slot_index },
-            };
-        },
-        .func, .func_inferred => {
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{ .Unanalyzed = .{} });
-
-            const result = self.analyzeFunction(
-                file,
-                parent_scope,
-                parent_src,
-                inst,
-                self_ast_node_index,
-                type_slot_index,
-                tags[@intFromEnum(inst)] == .func_inferred,
-                call_ctx,
-            );
-
-            return result;
-        },
-        .func_fancy => {
-            const type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{ .Unanalyzed = .{} });
-
-            const result = self.analyzeFancyFunction(
-                file,
-                parent_scope,
-                parent_src,
-                inst,
-                self_ast_node_index,
-                type_slot_index,
-                call_ctx,
-            );
-
-            return result;
-        },
-        .optional_payload_safe, .optional_payload_unsafe => {
-            const un_node = data[@intFromEnum(inst)].un_node;
-            const operand = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                un_node.operand,
-                need_type,
-                call_ctx,
-            );
-            const optional_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, operand.expr);
-
-            var typeRef: ?DocData.Expr = null;
-            if (operand.typeRef) |ref| {
-                switch (ref) {
-                    .type => |t_index| {
-                        const t = self.types.items[t_index];
-                        switch (t) {
-                            .Optional => |opt| typeRef = opt.child,
-                            else => {
-                                printWithContext(file, inst, "Invalid type for optional_payload_*: {}\n", .{t});
-                            },
-                        }
-                    },
-                    else => {},
-                }
-            }
-
-            return DocData.WalkResult{
-                .typeRef = typeRef,
-                .expr = .{ .optionalPayload = optional_idx },
-            };
-        },
-        .elem_val_node => {
-            const pl_node = data[@intFromEnum(inst)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Bin, pl_node.payload_index);
-            const lhs = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.lhs,
-                need_type,
-                call_ctx,
-            );
-            const rhs = try self.walkRef(
-                file,
-                parent_scope,
-                parent_src,
-                extra.data.rhs,
-                need_type,
-                call_ctx,
-            );
-            const lhs_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, lhs.expr);
-            const rhs_idx = self.exprs.items.len;
-            try self.exprs.append(self.arena, rhs.expr);
-            return DocData.WalkResult{
-                .expr = .{
-                    .elemVal = .{
-                        .lhs = lhs_idx,
-                        .rhs = rhs_idx,
-                    },
-                },
-            };
-        },
-        .extended => {
-            const extended = data[@intFromEnum(inst)].extended;
-            switch (extended.opcode) {
-                else => {
-                    printWithContext(
-                        file,
-                        inst,
-                        "TODO: implement `walkInstruction.extended` for {s}",
-                        .{@tagName(extended.opcode)},
-                    );
-                    return self.cteTodo(@tagName(extended.opcode));
-                },
-                .typeof_peer => {
-                    // Zir says it's a NodeMultiOp but in this case it's TypeOfPeer
-                    const extra = file.zir.extraData(Zir.Inst.TypeOfPeer, extended.operand);
-                    const args = file.zir.refSlice(extra.end, extended.small);
-                    const array_data = try self.arena.alloc(usize, args.len);
-
-                    var array_type: ?DocData.Expr = null;
-                    for (args, 0..) |arg, idx| {
-                        const wr = try self.walkRef(
-                            file,
-                            parent_scope,
-                            parent_src,
-                            arg,
-                            idx == 0,
-                            call_ctx,
-                        );
-                        if (idx == 0) {
-                            array_type = wr.typeRef;
-                        }
-
-                        const expr_index = self.exprs.items.len;
-                        try self.exprs.append(self.arena, wr.expr);
-                        array_data[idx] = expr_index;
-                    }
-
-                    const type_slot_index = self.types.items.len;
-                    try self.types.append(self.arena, .{
-                        .Array = .{
-                            .len = .{
-                                .int = .{
-                                    .value = args.len,
-                                    .negated = false,
-                                },
-                            },
-                            .child = .{ .type = 0 },
-                        },
-                    });
-                    const result = DocData.WalkResult{
-                        .typeRef = .{ .type = type_slot_index },
-                        .expr = .{ .typeOf_peer = array_data },
-                    };
-
-                    return result;
-                },
-                .opaque_decl => {
-                    const type_slot_index = self.types.items.len;
-                    try self.types.append(self.arena, .{ .Unanalyzed = .{} });
-
-                    var scope: Scope = .{
-                        .parent = parent_scope,
-                        .enclosing_type = type_slot_index,
-                    };
-
-                    const small: Zir.Inst.OpaqueDecl.Small = @bitCast(extended.small);
-                    const extra = file.zir.extraData(Zir.Inst.OpaqueDecl, extended.operand);
-                    var extra_index: usize = extra.end;
-
-                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
-
-                    const captures_len = if (small.has_captures_len) blk: {
-                        const captures_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk captures_len;
-                    } else 0;
-
-                    if (small.has_decls_len) extra_index += 1;
-
-                    scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
-                    extra_index += captures_len;
-
-                    var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-                    var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-
-                    extra_index = try self.analyzeAllDecls(
-                        file,
-                        &scope,
-                        inst,
-                        src_info,
-                        &decl_indexes,
-                        &priv_decl_indexes,
-                        call_ctx,
-                    );
-
-                    self.types.items[type_slot_index] = .{
-                        .Opaque = .{
-                            .name = "todo_name",
-                            .src = self_ast_node_index,
-                            .privDecls = priv_decl_indexes.items,
-                            .pubDecls = decl_indexes.items,
-                            .parent_container = parent_scope.enclosing_type,
-                        },
-                    };
-                    if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
-                        for (paths.items) |resume_info| {
-                            try self.tryResolveRefPath(
-                                resume_info.file,
-                                inst,
-                                resume_info.ref_path,
-                            );
-                        }
-
-                        _ = self.ref_paths_pending_on_types.remove(type_slot_index);
-                        // TODO: we should deallocate the arraylist that holds all the
-                        //       decl paths. not doing it now since it's arena-allocated
-                        //       anyway, but maybe we should put it elsewhere.
-                    }
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .type = type_slot_index },
-                    };
-                },
-                .variable => {
-                    const extra = file.zir.extraData(Zir.Inst.ExtendedVar, extended.operand);
-
-                    const small = @as(Zir.Inst.ExtendedVar.Small, @bitCast(extended.small));
-                    var extra_index: usize = extra.end;
-                    if (small.has_lib_name) extra_index += 1;
-                    if (small.has_align) extra_index += 1;
-
-                    const var_type = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.data.var_type,
-                        need_type,
-                        call_ctx,
-                    );
-
-                    var value: DocData.WalkResult = .{
-                        .typeRef = var_type.expr,
-                        .expr = .{ .undefined = .{} },
-                    };
-
-                    if (small.has_init) {
-                        const var_init_ref = @as(Ref, @enumFromInt(file.zir.extra[extra_index]));
-                        const var_init = try self.walkRef(
-                            file,
-                            parent_scope,
-                            parent_src,
-                            var_init_ref,
-                            need_type,
-                            call_ctx,
-                        );
-                        value.expr = var_init.expr;
-                        value.typeRef = var_init.typeRef;
-                    }
-
-                    return value;
-                },
-                .union_decl => {
-                    const type_slot_index = self.types.items.len;
-                    try self.types.append(self.arena, .{ .Unanalyzed = .{} });
-
-                    var scope: Scope = .{
-                        .parent = parent_scope,
-                        .enclosing_type = type_slot_index,
-                    };
-
-                    const small = @as(Zir.Inst.UnionDecl.Small, @bitCast(extended.small));
-                    const extra = file.zir.extraData(Zir.Inst.UnionDecl, extended.operand);
-                    var extra_index: usize = extra.end;
-
-                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
-
-                    // We delay analysis because union tags can refer to
-                    // decls defined inside the union itself.
-                    const tag_type_ref: ?Ref = if (small.has_tag_type) blk: {
-                        const tag_type = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        const tag_ref = @as(Ref, @enumFromInt(tag_type));
-                        break :blk tag_ref;
-                    } else null;
-
-                    const captures_len = if (small.has_captures_len) blk: {
-                        const captures_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk captures_len;
-                    } else 0;
-
-                    const body_len = if (small.has_body_len) blk: {
-                        const body_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk body_len;
-                    } else 0;
-
-                    const fields_len = if (small.has_fields_len) blk: {
-                        const fields_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk fields_len;
-                    } else 0;
-
-                    const layout_expr: ?DocData.Expr = switch (small.layout) {
-                        .Auto => null,
-                        else => .{ .enumLiteral = @tagName(small.layout) },
-                    };
-
-                    if (small.has_decls_len) extra_index += 1;
-
-                    scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
-                    extra_index += captures_len;
-
-                    var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-                    var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-
-                    extra_index = try self.analyzeAllDecls(
-                        file,
-                        &scope,
-                        inst,
-                        src_info,
-                        &decl_indexes,
-                        &priv_decl_indexes,
-                        call_ctx,
-                    );
-
-                    // Analyze the tag once all decls have been analyzed
-                    const tag_type = if (tag_type_ref) |tt_ref| (try self.walkRef(
-                        file,
-                        &scope,
-                        parent_src,
-                        tt_ref,
-                        false,
-                        call_ctx,
-                    )).expr else null;
-
-                    // Fields
-                    extra_index += body_len;
-
-                    var field_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
-                        self.arena,
-                        fields_len,
-                    );
-                    var field_name_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
-                        self.arena,
-                        fields_len,
-                    );
-                    try self.collectUnionFieldInfo(
-                        file,
-                        &scope,
-                        src_info,
-                        fields_len,
-                        &field_type_refs,
-                        &field_name_indexes,
-                        extra_index,
-                        call_ctx,
-                    );
-
-                    self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
-
-                    self.types.items[type_slot_index] = .{
-                        .Union = .{
-                            .name = "todo_name",
-                            .src = self_ast_node_index,
-                            .privDecls = priv_decl_indexes.items,
-                            .pubDecls = decl_indexes.items,
-                            .fields = field_type_refs.items,
-                            .tag = tag_type,
-                            .auto_enum = small.auto_enum_tag,
-                            .parent_container = parent_scope.enclosing_type,
-                            .layout = layout_expr,
-                        },
-                    };
-
-                    if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
-                        for (paths.items) |resume_info| {
-                            try self.tryResolveRefPath(
-                                resume_info.file,
-                                inst,
-                                resume_info.ref_path,
-                            );
-                        }
-
-                        _ = self.ref_paths_pending_on_types.remove(type_slot_index);
-                        // TODO: we should deallocate the arraylist that holds all the
-                        //       decl paths. not doing it now since it's arena-allocated
-                        //       anyway, but maybe we should put it elsewhere.
-                    }
-
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .type = type_slot_index },
-                    };
-                },
-                .enum_decl => {
-                    const type_slot_index = self.types.items.len;
-                    try self.types.append(self.arena, .{ .Unanalyzed = .{} });
-
-                    var scope: Scope = .{
-                        .parent = parent_scope,
-                        .enclosing_type = type_slot_index,
-                    };
-
-                    const small = @as(Zir.Inst.EnumDecl.Small, @bitCast(extended.small));
-                    const extra = file.zir.extraData(Zir.Inst.EnumDecl, extended.operand);
-                    var extra_index: usize = extra.end;
-
-                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
-
-                    const tag_type: ?DocData.Expr = if (small.has_tag_type) blk: {
-                        const tag_type = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        const tag_ref = @as(Ref, @enumFromInt(tag_type));
-                        const wr = try self.walkRef(
-                            file,
-                            parent_scope,
-                            parent_src,
-                            tag_ref,
-                            false,
-                            call_ctx,
-                        );
-                        break :blk wr.expr;
-                    } else null;
-
-                    const captures_len = if (small.has_captures_len) blk: {
-                        const captures_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk captures_len;
-                    } else 0;
-
-                    const body_len = if (small.has_body_len) blk: {
-                        const body_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk body_len;
-                    } else 0;
-
-                    const fields_len = if (small.has_fields_len) blk: {
-                        const fields_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk fields_len;
-                    } else 0;
-
-                    if (small.has_decls_len) extra_index += 1;
-
-                    scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
-                    extra_index += captures_len;
-
-                    var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-                    var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-
-                    extra_index = try self.analyzeAllDecls(
-                        file,
-                        &scope,
-                        inst,
-                        src_info,
-                        &decl_indexes,
-                        &priv_decl_indexes,
-                        call_ctx,
-                    );
-
-                    // const body = file.zir.extra[extra_index..][0..body_len];
-                    extra_index += body_len;
-
-                    var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
-                    var field_values: std.ArrayListUnmanaged(?DocData.Expr) = .{};
-                    {
-                        var bit_bag_idx = extra_index;
-                        var cur_bit_bag: u32 = undefined;
-                        extra_index += std.math.divCeil(usize, fields_len, 32) catch unreachable;
-
-                        var idx: usize = 0;
-                        while (idx < fields_len) : (idx += 1) {
-                            if (idx % 32 == 0) {
-                                cur_bit_bag = file.zir.extra[bit_bag_idx];
-                                bit_bag_idx += 1;
-                            }
-
-                            const has_value = @as(u1, @truncate(cur_bit_bag)) != 0;
-                            cur_bit_bag >>= 1;
-
-                            const field_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
-                            extra_index += 1;
-
-                            const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
-                            extra_index += 1;
-
-                            const value_expr: ?DocData.Expr = if (has_value) blk: {
-                                const value_ref = file.zir.extra[extra_index];
-                                extra_index += 1;
-                                const value = try self.walkRef(
-                                    file,
-                                    &scope,
-                                    src_info,
-                                    @as(Ref, @enumFromInt(value_ref)),
-                                    false,
-                                    call_ctx,
-                                );
-                                break :blk value.expr;
-                            } else null;
-                            try field_values.append(self.arena, value_expr);
-
-                            const field_name = file.zir.nullTerminatedString(field_name_index);
-
-                            try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
-                            const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
-                                file.zir.nullTerminatedString(doc_comment_index)
-                            else
-                                null;
-                            try self.ast_nodes.append(self.arena, .{
-                                .name = field_name,
-                                .docs = doc_comment,
-                            });
-                        }
-                    }
-
-                    self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
-
-                    self.types.items[type_slot_index] = .{
-                        .Enum = .{
-                            .name = "todo_name",
-                            .src = self_ast_node_index,
-                            .privDecls = priv_decl_indexes.items,
-                            .pubDecls = decl_indexes.items,
-                            .tag = tag_type,
-                            .values = field_values.items,
-                            .nonexhaustive = small.nonexhaustive,
-                            .parent_container = parent_scope.enclosing_type,
-                        },
-                    };
-                    if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
-                        for (paths.items) |resume_info| {
-                            try self.tryResolveRefPath(
-                                resume_info.file,
-                                inst,
-                                resume_info.ref_path,
-                            );
-                        }
-
-                        _ = self.ref_paths_pending_on_types.remove(type_slot_index);
-                        // TODO: we should deallocate the arraylist that holds all the
-                        //       decl paths. not doing it now since it's arena-allocated
-                        //       anyway, but maybe we should put it elsewhere.
-                    }
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .type = type_slot_index },
-                    };
-                },
-                .struct_decl => {
-                    const type_slot_index = self.types.items.len;
-                    try self.types.append(self.arena, .{ .Unanalyzed = .{} });
-
-                    var scope: Scope = .{
-                        .parent = parent_scope,
-                        .enclosing_type = type_slot_index,
-                    };
-
-                    const small = @as(Zir.Inst.StructDecl.Small, @bitCast(extended.small));
-                    const extra = file.zir.extraData(Zir.Inst.StructDecl, extended.operand);
-                    var extra_index: usize = extra.end;
-
-                    const src_info = try self.srcLocInfo(file, extra.data.src_node, parent_src);
-
-                    const captures_len = if (small.has_captures_len) blk: {
-                        const captures_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk captures_len;
-                    } else 0;
-
-                    const fields_len = if (small.has_fields_len) blk: {
-                        const fields_len = file.zir.extra[extra_index];
-                        extra_index += 1;
-                        break :blk fields_len;
-                    } else 0;
-
-                    // We don't care about decls yet
-                    if (small.has_decls_len) extra_index += 1;
-
-                    scope.captures = @ptrCast(file.zir.extra[extra_index..][0..captures_len]);
-                    extra_index += captures_len;
-
-                    var backing_int: ?DocData.Expr = null;
-                    if (small.has_backing_int) {
-                        const backing_int_body_len = file.zir.extra[extra_index];
-                        extra_index += 1; // backing_int_body_len
-                        if (backing_int_body_len == 0) {
-                            const backing_int_ref = @as(Ref, @enumFromInt(file.zir.extra[extra_index]));
-                            const backing_int_res = try self.walkRef(
-                                file,
-                                &scope,
-                                src_info,
-                                backing_int_ref,
-                                true,
-                                call_ctx,
-                            );
-                            backing_int = backing_int_res.expr;
-                            extra_index += 1; // backing_int_ref
-                        } else {
-                            const backing_int_body = file.zir.bodySlice(extra_index, backing_int_body_len);
-                            const break_inst = backing_int_body[backing_int_body.len - 1];
-                            const operand = data[@intFromEnum(break_inst)].@"break".operand;
-                            const backing_int_res = try self.walkRef(
-                                file,
-                                &scope,
-                                src_info,
-                                operand,
-                                true,
-                                call_ctx,
-                            );
-                            backing_int = backing_int_res.expr;
-                            extra_index += backing_int_body_len; // backing_int_body_inst
-                        }
-                    }
-
-                    const layout_expr: ?DocData.Expr = switch (small.layout) {
-                        .Auto => null,
-                        else => .{ .enumLiteral = @tagName(small.layout) },
-                    };
-
-                    var decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-                    var priv_decl_indexes: std.ArrayListUnmanaged(usize) = .{};
-
-                    extra_index = try self.analyzeAllDecls(
-                        file,
-                        &scope,
-                        inst,
-                        src_info,
-                        &decl_indexes,
-                        &priv_decl_indexes,
-                        call_ctx,
-                    );
-
-                    // Inside field init bodies, the struct decl instruction is used to refer to the
-                    // field type during the second pass of analysis.
-                    try self.repurposed_insts.put(self.arena, inst, {});
-                    defer _ = self.repurposed_insts.remove(inst);
-
-                    var field_type_refs: std.ArrayListUnmanaged(DocData.Expr) = .{};
-                    var field_default_refs: std.ArrayListUnmanaged(?DocData.Expr) = .{};
-                    var field_name_indexes: std.ArrayListUnmanaged(usize) = .{};
-                    try self.collectStructFieldInfo(
-                        file,
-                        &scope,
-                        src_info,
-                        fields_len,
-                        &field_type_refs,
-                        &field_default_refs,
-                        &field_name_indexes,
-                        extra_index,
-                        small.is_tuple,
-                        call_ctx,
-                    );
-
-                    self.ast_nodes.items[self_ast_node_index].fields = field_name_indexes.items;
-
-                    self.types.items[type_slot_index] = .{
-                        .Struct = .{
-                            .name = "todo_name",
-                            .src = self_ast_node_index,
-                            .privDecls = priv_decl_indexes.items,
-                            .pubDecls = decl_indexes.items,
-                            .field_types = field_type_refs.items,
-                            .field_defaults = field_default_refs.items,
-                            .is_tuple = small.is_tuple,
-                            .backing_int = backing_int,
-                            .line_number = self.ast_nodes.items[self_ast_node_index].line,
-                            .parent_container = parent_scope.enclosing_type,
-                            .layout = layout_expr,
-                        },
-                    };
-                    if (self.ref_paths_pending_on_types.get(type_slot_index)) |paths| {
-                        for (paths.items) |resume_info| {
-                            try self.tryResolveRefPath(
-                                resume_info.file,
-                                inst,
-                                resume_info.ref_path,
-                            );
-                        }
-
-                        _ = self.ref_paths_pending_on_types.remove(type_slot_index);
-                        // TODO: we should deallocate the arraylist that holds all the
-                        //       decl paths. not doing it now since it's arena-allocated
-                        //       anyway, but maybe we should put it elsewhere.
-                    }
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .type = type_slot_index },
-                    };
-                },
-                .this => {
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{
-                            .this = parent_scope.enclosing_type.?,
-                            // We know enclosing_type is always present
-                            // because it's only null for the top-level
-                            // struct instruction of a file.
-                        },
-                    };
-                },
-                .int_from_error,
-                .error_from_int,
-                .reify,
-                => {
-                    const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
-                    const bin_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
-                    const param = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.operand,
-                        false,
-                        call_ctx,
-                    );
-
-                    const param_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, param.expr);
-
-                    self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(extended.opcode), .param = param_index } };
-
-                    return DocData.WalkResult{
-                        .typeRef = param.typeRef orelse .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .builtinIndex = bin_index },
-                    };
-                },
-                .work_item_id,
-                .work_group_size,
-                .work_group_id,
-                => {
-                    const extra = file.zir.extraData(Zir.Inst.UnNode, extended.operand).data;
-                    const bin_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, .{ .builtin = .{ .param = 0 } });
-                    const param = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.operand,
-                        false,
-                        call_ctx,
-                    );
-
-                    const param_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, param.expr);
-
-                    self.exprs.items[bin_index] = .{ .builtin = .{ .name = @tagName(extended.opcode), .param = param_index } };
-
-                    return DocData.WalkResult{
-                        // from docs we know they return u32
-                        .typeRef = .{ .type = @intFromEnum(Ref.u32_type) },
-                        .expr = .{ .builtinIndex = bin_index },
-                    };
-                },
-                .cmpxchg => {
-                    const extra = file.zir.extraData(Zir.Inst.Cmpxchg, extended.operand).data;
-
-                    const last_type_index = self.exprs.items.len;
-                    const last_type = self.exprs.items[last_type_index - 1];
-                    const type_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, last_type);
-
-                    const ptr_index = self.exprs.items.len;
-                    const ptr: DocData.WalkResult = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.ptr,
-                        false,
-                        call_ctx,
-                    );
-                    try self.exprs.append(self.arena, ptr.expr);
-
-                    const expected_value_index = self.exprs.items.len;
-                    const expected_value: DocData.WalkResult = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.expected_value,
-                        false,
-                        call_ctx,
-                    );
-                    try self.exprs.append(self.arena, expected_value.expr);
-
-                    const new_value_index = self.exprs.items.len;
-                    const new_value: DocData.WalkResult = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.new_value,
-                        false,
-                        call_ctx,
-                    );
-                    try self.exprs.append(self.arena, new_value.expr);
-
-                    const success_order_index = self.exprs.items.len;
-                    const success_order: DocData.WalkResult = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.success_order,
-                        false,
-                        call_ctx,
-                    );
-                    try self.exprs.append(self.arena, success_order.expr);
-
-                    const failure_order_index = self.exprs.items.len;
-                    const failure_order: DocData.WalkResult = try self.walkRef(
-                        file,
-                        parent_scope,
-                        parent_src,
-                        extra.failure_order,
-                        false,
-                        call_ctx,
-                    );
-                    try self.exprs.append(self.arena, failure_order.expr);
-
-                    const cmpxchg_index = self.exprs.items.len;
-                    try self.exprs.append(self.arena, .{ .cmpxchg = .{
-                        .name = @tagName(tags[@intFromEnum(inst)]),
-                        .type = type_index,
-                        .ptr = ptr_index,
-                        .expected_value = expected_value_index,
-                        .new_value = new_value_index,
-                        .success_order = success_order_index,
-                        .failure_order = failure_order_index,
-                    } });
-                    return DocData.WalkResult{
-                        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                        .expr = .{ .cmpxchgIndex = cmpxchg_index },
-                    };
-                },
-                .closure_get => {
-                    const captured, const scope = parent_scope.getCapture(extended.small);
-                    switch (captured) {
-                        .inst => |cap_inst| return self.walkInstruction(file, scope, parent_src, cap_inst, need_type, call_ctx),
-                        .decl => |str| {
-                            const decl_status = parent_scope.resolveDeclName(str, file, inst.toOptional());
-                            return .{ .expr = .{ .declRef = decl_status } };
-                        },
-                    }
-                },
-            }
-        },
-    }
-}
-
-/// Called by `walkInstruction` when encountering a container type.
-/// Iterates over all decl definitions in its body and it also analyzes each
-/// decl's body recursively by calling into `walkInstruction`.
-///
-/// Does not append to `self.decls` directly because `walkInstruction`
-/// is expected to look-ahead scan all decls and reserve `body_len`
-/// slots in `self.decls`, which are then filled out by this function.
-fn analyzeAllDecls(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    parent_inst: Zir.Inst.Index,
-    parent_src: SrcLocInfo,
-    decl_indexes: *std.ArrayListUnmanaged(usize),
-    priv_decl_indexes: *std.ArrayListUnmanaged(usize),
-    call_ctx: ?*const CallContext,
-) AutodocErrors!usize {
-    const first_decl_indexes_slot = decl_indexes.items.len;
-    const original_it = file.zir.declIterator(parent_inst);
-
-    // First loop to discover decl names
-    {
-        var it = original_it;
-        while (it.next()) |zir_index| {
-            const declaration, _ = file.zir.getDeclaration(zir_index);
-            if (declaration.name.isNamedTest(file.zir)) continue;
-            const decl_name = declaration.name.toString(file.zir) orelse continue;
-            try scope.insertDeclRef(self.arena, decl_name, .Pending);
-        }
-    }
-
-    // Second loop to analyze `usingnamespace` decls
-    {
-        var it = original_it;
-        var decl_indexes_slot = first_decl_indexes_slot;
-        while (it.next()) |zir_index| : (decl_indexes_slot += 1) {
-            const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
-            if (extra.data.name != .@"usingnamespace") continue;
-            try self.analyzeUsingnamespaceDecl(
-                file,
-                scope,
-                try self.srcLocInfo(file, pl_node.src_node, parent_src),
-                decl_indexes,
-                priv_decl_indexes,
-                extra.data,
-                @intCast(extra.end),
-                call_ctx,
-            );
-        }
-    }
-
-    // Third loop to analyze all remaining decls
-    {
-        var it = original_it;
-        while (it.next()) |zir_index| {
-            const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
-            const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
-            switch (extra.data.name) {
-                .@"comptime", .@"usingnamespace", .unnamed_test, .decltest => continue,
-                _ => if (extra.data.name.isNamedTest(file.zir)) continue,
-            }
-            try self.analyzeDecl(
-                file,
-                scope,
-                try self.srcLocInfo(file, pl_node.src_node, parent_src),
-                decl_indexes,
-                priv_decl_indexes,
-                zir_index,
-                extra.data,
-                @intCast(extra.end),
-                call_ctx,
-            );
-        }
-    }
-
-    // Fourth loop to analyze decltests
-    var it = original_it;
-    while (it.next()) |zir_index| {
-        const pl_node = file.zir.instructions.items(.data)[@intFromEnum(zir_index)].pl_node;
-        const extra = file.zir.extraData(Zir.Inst.Declaration, pl_node.payload_index);
-        if (extra.data.name != .decltest) continue;
-        try self.analyzeDecltest(
-            file,
-            scope,
-            try self.srcLocInfo(file, pl_node.src_node, parent_src),
-            extra.data,
-            @intCast(extra.end),
-        );
-    }
-
-    return it.extra_index;
-}
-
-fn walkInlineBody(
-    autodoc: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    block_src: SrcLocInfo,
-    parent_src: SrcLocInfo,
-    body: []const Zir.Inst.Index,
-    need_type: bool,
-    call_ctx: ?*const CallContext,
-) AutodocErrors!DocData.WalkResult {
-    const tags = file.zir.instructions.items(.tag);
-    const break_inst = switch (tags[@intFromEnum(body[body.len - 1])]) {
-        .condbr_inline => {
-            // Unresolvable.
-            const res: DocData.WalkResult = .{
-                .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                .expr = .{ .comptimeExpr = autodoc.comptime_exprs.items.len },
-            };
-            const source = (try file.getTree(autodoc.zcu.gpa)).getNodeSource(block_src.src_node);
-            try autodoc.comptime_exprs.append(autodoc.arena, .{
-                .code = source,
-            });
-            return res;
-        },
-        .break_inline => body[body.len - 1],
-        else => unreachable,
-    };
-    const break_data = file.zir.instructions.items(.data)[@intFromEnum(break_inst)].@"break";
-    return autodoc.walkRef(file, scope, parent_src, break_data.operand, need_type, call_ctx);
-}
-
-// Asserts the given decl is public
-fn analyzeDecl(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    decl_src: SrcLocInfo,
-    decl_indexes: *std.ArrayListUnmanaged(usize),
-    priv_decl_indexes: *std.ArrayListUnmanaged(usize),
-    decl_inst: Zir.Inst.Index,
-    declaration: Zir.Inst.Declaration,
-    extra_index: u32,
-    call_ctx: ?*const CallContext,
-) AutodocErrors!void {
-    const bodies = declaration.getBodies(extra_index, file.zir);
-    const name = file.zir.nullTerminatedString(declaration.name.toString(file.zir).?);
-
-    const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
-        file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
-    else
-        null;
-
-    // astnode
-    const ast_node_index = idx: {
-        const idx = self.ast_nodes.items.len;
-        try self.ast_nodes.append(self.arena, .{
-            .file = self.files.getIndex(file).?,
-            .line = decl_src.line,
-            .col = 0,
-            .docs = doc_comment,
-            .fields = null, // walkInstruction will fill `fields` if necessary
-        });
-        break :idx idx;
-    };
-
-    const walk_result = try self.walkInlineBody(
-        file,
-        scope,
-        decl_src,
-        decl_src,
-        bodies.value_body,
-        true,
-        call_ctx,
-    );
-
-    const tree = try file.getTree(self.zcu.gpa);
-    const kind_token = tree.nodes.items(.main_token)[decl_src.src_node];
-    const kind: []const u8 = switch (tree.tokens.items(.tag)[kind_token]) {
-        .keyword_var => "var",
-        else => "const",
-    };
-
-    const decls_slot_index = self.decls.items.len;
-    try self.decls.append(self.arena, .{
-        .name = name,
-        .src = ast_node_index,
-        .value = walk_result,
-        .kind = kind,
-        .parent_container = scope.enclosing_type,
-    });
-
-    if (declaration.flags.is_pub) {
-        try decl_indexes.append(self.arena, decls_slot_index);
-    } else {
-        try priv_decl_indexes.append(self.arena, decls_slot_index);
-    }
-
-    const decl_status_ptr = scope.resolveDeclName(declaration.name.toString(file.zir).?, file, .none);
-    std.debug.assert(decl_status_ptr.* == .Pending);
-    decl_status_ptr.* = .{ .Analyzed = decls_slot_index };
-
-    // Unblock any pending decl path that was waiting for this decl.
-    if (self.ref_paths_pending_on_decls.get(decl_status_ptr)) |paths| {
-        for (paths.items) |resume_info| {
-            try self.tryResolveRefPath(
-                resume_info.file,
-                decl_inst,
-                resume_info.ref_path,
-            );
-        }
-
-        _ = self.ref_paths_pending_on_decls.remove(decl_status_ptr);
-        // TODO: we should deallocate the arraylist that holds all the
-        //       ref paths. not doing it now since it's arena-allocated
-        //       anyway, but maybe we should put it elsewhere.
-    }
-}
-
-fn analyzeUsingnamespaceDecl(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    decl_src: SrcLocInfo,
-    decl_indexes: *std.ArrayListUnmanaged(usize),
-    priv_decl_indexes: *std.ArrayListUnmanaged(usize),
-    declaration: Zir.Inst.Declaration,
-    extra_index: u32,
-    call_ctx: ?*const CallContext,
-) AutodocErrors!void {
-    const bodies = declaration.getBodies(extra_index, file.zir);
-
-    const doc_comment: ?[]const u8 = if (declaration.flags.has_doc_comment)
-        file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]))
-    else
-        null;
-
-    // astnode
-    const ast_node_index = idx: {
-        const idx = self.ast_nodes.items.len;
-        try self.ast_nodes.append(self.arena, .{
-            .file = self.files.getIndex(file).?,
-            .line = decl_src.line,
-            .col = 0,
-            .docs = doc_comment,
-            .fields = null, // walkInstruction will fill `fields` if necessary
-        });
-        break :idx idx;
-    };
-
-    const walk_result = try self.walkInlineBody(
-        file,
-        scope,
-        decl_src,
-        decl_src,
-        bodies.value_body,
-        true,
-        call_ctx,
-    );
-
-    const decl_slot_index = self.decls.items.len;
-    try self.decls.append(self.arena, .{
-        .name = "",
-        .kind = "",
-        .src = ast_node_index,
-        .value = walk_result,
-        .is_uns = true,
-        .parent_container = scope.enclosing_type,
-    });
-
-    if (declaration.flags.is_pub) {
-        try decl_indexes.append(self.arena, decl_slot_index);
-    } else {
-        try priv_decl_indexes.append(self.arena, decl_slot_index);
-    }
-}
-
-fn analyzeDecltest(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    decl_src: SrcLocInfo,
-    declaration: Zir.Inst.Declaration,
-    extra_index: u32,
-) AutodocErrors!void {
-    std.debug.assert(declaration.flags.has_doc_comment);
-    const decl_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
-
-    const test_source_code = (try file.getTree(self.zcu.gpa)).getNodeSource(decl_src.src_node);
-
-    const decl_name: ?[]const u8 = if (decl_name_index != .empty)
-        file.zir.nullTerminatedString(decl_name_index)
-    else
-        null;
-
-    // astnode
-    const ast_node_index = idx: {
-        const idx = self.ast_nodes.items.len;
-        try self.ast_nodes.append(self.arena, .{
-            .file = self.files.getIndex(file).?,
-            .line = decl_src.line,
-            .col = 0,
-            .name = decl_name,
-            .code = test_source_code,
-        });
-        break :idx idx;
-    };
-
-    const decl_status = scope.resolveDeclName(decl_name_index, file, .none);
-
-    switch (decl_status.*) {
-        .Analyzed => |idx| {
-            self.decls.items[idx].decltest = ast_node_index;
-        },
-        else => unreachable, // we assume analyzeAllDecls analyzed other decls by this point
-    }
-}
-
-/// An unresolved path has a non-string WalkResult at its beginnig, while every
-/// other element is a string WalkResult. Resolving means iteratively map each
-/// string to a Decl / Type / Call / etc.
-///
-/// If we encounter an unanalyzed decl during the process, we append the
-/// unsolved sub-path to `self.ref_paths_pending_on_decls` and bail out.
-/// Same happens when a decl holds a type definition that hasn't been fully
-/// analyzed yet (except that we append to `self.ref_paths_pending_on_types`.
-///
-/// When analyzeAllDecls / walkInstruction finishes analyzing a decl / type, it will
-/// then check if there's any pending ref path blocked on it and, if any, it
-/// will progress their resolution by calling tryResolveRefPath again.
-///
-/// Ref paths can also depend on other ref paths. See
-/// `self.pending_ref_paths` for more info.
-///
-/// A ref path that has a component that resolves into a comptimeExpr will
-/// give up its resolution process entirely, leaving the remaining components
-/// as strings.
-fn tryResolveRefPath(
-    self: *Autodoc,
-    /// File from which the decl path originates.
-    file: *File,
-    inst: Zir.Inst.Index, // used only for panicWithContext
-    path: []DocData.Expr,
-) AutodocErrors!void {
-    var i: usize = 0;
-    outer: while (i < path.len - 1) : (i += 1) {
-        const parent = path[i];
-        const child_string = path[i + 1].declName; // we expect to find an unsolved decl
-
-        var resolved_parent = parent;
-        var j: usize = 0;
-        while (j < 10_000) : (j += 1) {
-            switch (resolved_parent) {
-                else => break,
-                .this => |t| resolved_parent = .{ .type = t },
-                .declIndex => |decl_index| {
-                    const decl = self.decls.items[decl_index];
-                    resolved_parent = decl.value.expr;
-                    continue;
-                },
-                .declRef => |decl_status_ptr| {
-                    // NOTE: must be kep in sync with `findNameInUnsDecls`
-                    switch (decl_status_ptr.*) {
-                        // The use of unreachable here is conservative.
-                        // It might be that it truly should be up to us to
-                        // request the analys of this decl, but it's not clear
-                        // at the moment of writing.
-                        .NotRequested => unreachable,
-                        .Analyzed => |decl_index| {
-                            const decl = self.decls.items[decl_index];
-                            resolved_parent = decl.value.expr;
-                            continue;
-                        },
-                        .Pending => {
-                            // This decl path is pending completion
-                            {
-                                const res = try self.pending_ref_paths.getOrPut(
-                                    self.arena,
-                                    &path[path.len - 1],
-                                );
-                                if (!res.found_existing) res.value_ptr.* = .{};
-                            }
-
-                            const res = try self.ref_paths_pending_on_decls.getOrPut(
-                                self.arena,
-                                decl_status_ptr,
-                            );
-                            if (!res.found_existing) res.value_ptr.* = .{};
-                            try res.value_ptr.*.append(self.arena, .{
-                                .file = file,
-                                .ref_path = path[i..path.len],
-                            });
-
-                            // We return instead doing `break :outer` to prevent the
-                            // code after the :outer while loop to run, as it assumes
-                            // that the path will have been fully analyzed (or we
-                            // have given up because of a comptimeExpr).
-                            return;
-                        },
-                    }
-                },
-                .refPath => |rp| {
-                    if (self.pending_ref_paths.getPtr(&rp[rp.len - 1])) |waiter_list| {
-                        try waiter_list.append(self.arena, .{
-                            .file = file,
-                            .ref_path = path[i..path.len],
-                        });
-
-                        // This decl path is pending completion
-                        {
-                            const res = try self.pending_ref_paths.getOrPut(
-                                self.arena,
-                                &path[path.len - 1],
-                            );
-                            if (!res.found_existing) res.value_ptr.* = .{};
-                        }
-
-                        return;
-                    }
-
-                    // If the last element is a declName or a CTE, then we give up,
-                    // otherwise we resovle the parent to it and loop again.
-                    // NOTE: we assume that if we find a string, it's because of
-                    // a CTE component somewhere in the path. We know that the path
-                    // is not pending futher evaluation because we just checked!
-                    const last = rp[rp.len - 1];
-                    switch (last) {
-                        .comptimeExpr, .declName => break :outer,
-                        else => {
-                            resolved_parent = last;
-                            continue;
-                        },
-                    }
-                },
-                .fieldVal => |fv| {
-                    resolved_parent = self.exprs.items[fv.val.expr];
-                },
-            }
-        } else {
-            panicWithContext(
-                file,
-                inst,
-                "exhausted eval quota for `{}`in tryResolveRefPath\n",
-                .{resolved_parent},
-            );
-        }
-
-        switch (resolved_parent) {
-            else => {
-                // NOTE: indirect references to types / decls should be handled
-                //       in the switch above this one!
-                printWithContext(
-                    file,
-                    inst,
-                    "TODO: handle `{s}`in tryResolveRefPath\nInfo: {}",
-                    .{ @tagName(resolved_parent), resolved_parent },
-                );
-                // path[i + 1] = (try self.cteTodo("<match failure>")).expr;
-                continue :outer;
-            },
-            .comptimeExpr, .call, .typeOf => {
-                // Since we hit a cte, we leave the remaining strings unresolved
-                // and completely give up on resolving this decl path.
-                //decl_path.hasCte = true;
-                break :outer;
-            },
-            .type => |t_index| switch (self.types.items[t_index]) {
-                else => {
-                    panicWithContext(
-                        file,
-                        inst,
-                        "TODO: handle `{s}` in tryResolveDeclPath.type\nInfo: {}",
-                        .{ @tagName(self.types.items[t_index]), resolved_parent },
-                    );
-                },
-                .ComptimeExpr => {
-                    // Same as the comptimeExpr branch above
-                    break :outer;
-                },
-                .Unanalyzed => {
-                    // This decl path is pending completion
-                    {
-                        const res = try self.pending_ref_paths.getOrPut(
-                            self.arena,
-                            &path[path.len - 1],
-                        );
-                        if (!res.found_existing) res.value_ptr.* = .{};
-                    }
-
-                    const res = try self.ref_paths_pending_on_types.getOrPut(
-                        self.arena,
-                        t_index,
-                    );
-                    if (!res.found_existing) res.value_ptr.* = .{};
-                    try res.value_ptr.*.append(self.arena, .{
-                        .file = file,
-                        .ref_path = path[i..path.len],
-                    });
-
-                    return;
-                },
-                .Array => {
-                    if (std.mem.eql(u8, child_string, "len")) {
-                        path[i + 1] = .{
-                            .builtinField = .len,
-                        };
-                    } else {
-                        panicWithContext(
-                            file,
-                            inst,
-                            "TODO: handle `{s}` in tryResolveDeclPath.type.Array\nInfo: {}",
-                            .{ child_string, resolved_parent },
-                        );
-                    }
-                },
-                // TODO: the following searches could probably
-                //       be performed more efficiently on the corresponding
-                //       scope
-                .Enum => |t_enum| { // foo.bar.baz
-                    // Look into locally-defined pub decls
-                    for (t_enum.pubDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    // Look into locally-defined priv decls
-                    for (t_enum.privDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
-                        .Pending => return,
-                        .NotFound => {},
-                        .Found => |match| {
-                            path[i + 1] = match;
-                            continue :outer;
-                        },
-                    }
-
-                    for (self.ast_nodes.items[t_enum.src].fields.?, 0..) |ast_node, idx| {
-                        const name = self.ast_nodes.items[ast_node].name.?;
-                        if (std.mem.eql(u8, name, child_string)) {
-                            // TODO: should we really create an artificial
-                            //       decl for this type? Probably not.
-
-                            path[i + 1] = .{
-                                .fieldRef = .{
-                                    .type = t_index,
-                                    .index = idx,
-                                },
-                            };
-                            continue :outer;
-                        }
-                    }
-
-                    // if we got here, our search failed
-                    printWithContext(
-                        file,
-                        inst,
-                        "failed to match `{s}` in enum",
-                        .{child_string},
-                    );
-
-                    path[i + 1] = (try self.cteTodo("match failure")).expr;
-                    continue :outer;
-                },
-                .Union => |t_union| {
-                    // Look into locally-defined pub decls
-                    for (t_union.pubDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    // Look into locally-defined priv decls
-                    for (t_union.privDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
-                        .Pending => return,
-                        .NotFound => {},
-                        .Found => |match| {
-                            path[i + 1] = match;
-                            continue :outer;
-                        },
-                    }
-
-                    for (self.ast_nodes.items[t_union.src].fields.?, 0..) |ast_node, idx| {
-                        const name = self.ast_nodes.items[ast_node].name.?;
-                        if (std.mem.eql(u8, name, child_string)) {
-                            // TODO: should we really create an artificial
-                            //       decl for this type? Probably not.
-
-                            path[i + 1] = .{
-                                .fieldRef = .{
-                                    .type = t_index,
-                                    .index = idx,
-                                },
-                            };
-                            continue :outer;
-                        }
-                    }
-
-                    // if we got here, our search failed
-                    printWithContext(
-                        file,
-                        inst,
-                        "failed to match `{s}` in union",
-                        .{child_string},
-                    );
-                    path[i + 1] = (try self.cteTodo("match failure")).expr;
-                    continue :outer;
-                },
-
-                .Struct => |t_struct| {
-                    // Look into locally-defined pub decls
-                    for (t_struct.pubDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    // Look into locally-defined priv decls
-                    for (t_struct.privDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
-                        .Pending => return,
-                        .NotFound => {},
-                        .Found => |match| {
-                            path[i + 1] = match;
-                            continue :outer;
-                        },
-                    }
-
-                    for (self.ast_nodes.items[t_struct.src].fields.?, 0..) |ast_node, idx| {
-                        const name = self.ast_nodes.items[ast_node].name.?;
-                        if (std.mem.eql(u8, name, child_string)) {
-                            // TODO: should we really create an artificial
-                            //       decl for this type? Probably not.
-
-                            path[i + 1] = .{
-                                .fieldRef = .{
-                                    .type = t_index,
-                                    .index = idx,
-                                },
-                            };
-                            continue :outer;
-                        }
-                    }
-
-                    // if we got here, our search failed
-                    // printWithContext(
-                    //     file,
-                    //     inst,
-                    //     "failed to match `{s}` in struct",
-                    //     .{child_string},
-                    // );
-                    // path[i + 1] = (try self.cteTodo("match failure")).expr;
-                    //
-                    // that's working
-                    path[i + 1] = (try self.cteTodo(child_string)).expr;
-                    continue :outer;
-                },
-                .Opaque => |t_opaque| {
-                    // Look into locally-defined pub decls
-                    for (t_opaque.pubDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    // Look into locally-defined priv decls
-                    for (t_opaque.privDecls) |idx| {
-                        const d = self.decls.items[idx];
-                        if (d.is_uns) continue;
-                        if (std.mem.eql(u8, d.name, child_string)) {
-                            path[i + 1] = .{ .declIndex = idx };
-                            continue :outer;
-                        }
-                    }
-
-                    // We delay looking into Uns decls since they could be
-                    // not fully analyzed yet.
-                    switch (try self.findNameInUnsDecls(file, path[i..path.len], resolved_parent, child_string)) {
-                        .Pending => return,
-                        .NotFound => {},
-                        .Found => |match| {
-                            path[i + 1] = match;
-                            continue :outer;
-                        },
-                    }
-
-                    // if we got here, our search failed
-                    printWithContext(
-                        file,
-                        inst,
-                        "failed to match `{s}` in opaque",
-                        .{child_string},
-                    );
-
-                    path[i + 1] = (try self.cteTodo("match failure")).expr;
-                    continue :outer;
-                },
-            },
-            .@"struct" => |st| {
-                for (st) |field| {
-                    if (std.mem.eql(u8, field.name, child_string)) {
-                        path[i + 1] = .{ .fieldVal = field };
-                        continue :outer;
-                    }
-                }
-
-                // if we got here, our search failed
-                printWithContext(
-                    file,
-                    inst,
-                    "failed to match `{s}` in struct",
-                    .{child_string},
-                );
-
-                path[i + 1] = (try self.cteTodo("match failure")).expr;
-                continue :outer;
-            },
-        }
-    }
-
-    if (self.pending_ref_paths.get(&path[path.len - 1])) |waiter_list| {
-        // It's important to de-register ourselves as pending before
-        // attempting to resolve any other decl.
-        _ = self.pending_ref_paths.remove(&path[path.len - 1]);
-
-        for (waiter_list.items) |resume_info| {
-            try self.tryResolveRefPath(resume_info.file, inst, resume_info.ref_path);
-        }
-        // TODO: this is where we should free waiter_list, but its in the arena
-        //       that said, we might want to store it elsewhere and reclaim memory asap
-    }
-}
-
-const UnsSearchResult = union(enum) {
-    Found: DocData.Expr,
-    Pending,
-    NotFound,
-};
-
-fn findNameInUnsDecls(
-    self: *Autodoc,
-    file: *File,
-    tail: []DocData.Expr,
-    uns_expr: DocData.Expr,
-    name: []const u8,
-) !UnsSearchResult {
-    var to_analyze = std.SegmentedList(DocData.Expr, 1){};
-    // TODO: make this an appendAssumeCapacity
-    try to_analyze.append(self.arena, uns_expr);
-
-    while (to_analyze.pop()) |cte| {
-        var container_expression = cte;
-        for (0..10_000) |_| {
-            // TODO: handle other types of indirection, like @import
-            const type_index = switch (container_expression) {
-                .type => |t| t,
-                .declRef => |decl_status_ptr| {
-                    switch (decl_status_ptr.*) {
-                        // The use of unreachable here is conservative.
-                        // It might be that it truly should be up to us to
-                        // request the analys of this decl, but it's not clear
-                        // at the moment of writing.
-                        .NotRequested => unreachable,
-                        .Analyzed => |decl_index| {
-                            const decl = self.decls.items[decl_index];
-                            container_expression = decl.value.expr;
-                            continue;
-                        },
-                        .Pending => {
-                            // This decl path is pending completion
-                            {
-                                const res = try self.pending_ref_paths.getOrPut(
-                                    self.arena,
-                                    &tail[tail.len - 1],
-                                );
-                                if (!res.found_existing) res.value_ptr.* = .{};
-                            }
-
-                            const res = try self.ref_paths_pending_on_decls.getOrPut(
-                                self.arena,
-                                decl_status_ptr,
-                            );
-                            if (!res.found_existing) res.value_ptr.* = .{};
-                            try res.value_ptr.*.append(self.arena, .{
-                                .file = file,
-                                .ref_path = tail,
-                            });
-
-                            // TODO: save some state that keeps track of our
-                            //       progress because, as things stand, we
-                            //       always re-start the search from scratch
-                            return .Pending;
-                        },
-                    }
-                },
-                else => {
-                    log.debug(
-                        "Handle `{s}` in findNameInUnsDecls (first switch)",
-                        .{@tagName(cte)},
-                    );
-                    return .{ .Found = .{ .comptimeExpr = 0 } };
-                },
-            };
-
-            const t = self.types.items[type_index];
-            const decls = switch (t) {
-                else => {
-                    log.debug(
-                        "Handle `{s}` in findNameInUnsDecls (second switch)",
-                        .{@tagName(cte)},
-                    );
-                    return .{ .Found = .{ .comptimeExpr = 0 } };
-                },
-                inline .Struct, .Union, .Opaque, .Enum => |c| c.pubDecls,
-            };
-
-            for (decls) |idx| {
-                const d = self.decls.items[idx];
-                if (d.is_uns) {
-                    try to_analyze.append(self.arena, d.value.expr);
-                } else if (std.mem.eql(u8, d.name, name)) {
-                    return .{ .Found = .{ .declIndex = idx } };
-                }
-            }
-        }
-    }
-
-    return .NotFound;
-}
-
-fn analyzeFancyFunction(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    parent_src: SrcLocInfo,
-    inst: Zir.Inst.Index,
-    self_ast_node_index: usize,
-    type_slot_index: usize,
-    call_ctx: ?*const CallContext,
-) AutodocErrors!DocData.WalkResult {
-    const tags = file.zir.instructions.items(.tag);
-    const data = file.zir.instructions.items(.data);
-    const fn_info = file.zir.getFnInfo(inst);
-
-    try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
-    var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
-        self.arena,
-        fn_info.total_params_len,
-    );
-    var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
-        self.arena,
-        fn_info.total_params_len,
-    );
-
-    // TODO: handle scope rules for fn parameters
-    for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
-        switch (tags[@intFromEnum(param_index)]) {
-            else => {
-                panicWithContext(
-                    file,
-                    param_index,
-                    "TODO: handle `{s}` in walkInstruction.func\n",
-                    .{@tagName(tags[@intFromEnum(param_index)])},
-                );
-            },
-            .param_anytype, .param_anytype_comptime => {
-                // TODO: where are the doc comments?
-                const str_tok = data[@intFromEnum(param_index)].str_tok;
-
-                const name = str_tok.get(file.zir);
-
-                param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
-                self.ast_nodes.appendAssumeCapacity(.{
-                    .name = name,
-                    .docs = "",
-                    .@"comptime" = tags[@intFromEnum(param_index)] == .param_anytype_comptime,
-                });
-
-                param_type_refs.appendAssumeCapacity(
-                    DocData.Expr{ .@"anytype" = .{} },
-                );
-            },
-            .param, .param_comptime => {
-                const pl_tok = data[@intFromEnum(param_index)].pl_tok;
-                const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
-                const doc_comment = if (extra.data.doc_comment != .empty)
-                    file.zir.nullTerminatedString(extra.data.doc_comment)
-                else
-                    "";
-                const name = file.zir.nullTerminatedString(extra.data.name);
-
-                param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
-                try self.ast_nodes.append(self.arena, .{
-                    .name = name,
-                    .docs = doc_comment,
-                    .@"comptime" = tags[@intFromEnum(param_index)] == .param_comptime,
-                });
-
-                const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
-                const break_operand = data[break_index].@"break".operand;
-                const param_type_ref = try self.walkRef(
-                    file,
-                    scope,
-                    parent_src,
-                    break_operand,
-                    false,
-                    call_ctx,
-                );
-
-                param_type_refs.appendAssumeCapacity(param_type_ref.expr);
-            },
-        }
-    }
-
-    self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
-
-    const pl_node = data[@intFromEnum(inst)].pl_node;
-    const extra = file.zir.extraData(Zir.Inst.FuncFancy, pl_node.payload_index);
-
-    var extra_index: usize = extra.end;
-
-    var lib_name: []const u8 = "";
-    if (extra.data.bits.has_lib_name) {
-        const lib_name_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
-        lib_name = file.zir.nullTerminatedString(lib_name_index);
-        extra_index += 1;
-    }
-
-    var align_index: ?usize = null;
-    if (extra.data.bits.has_align_ref) {
-        const align_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-        align_index = self.exprs.items.len;
-        _ = try self.walkRef(
-            file,
-            scope,
-            parent_src,
-            align_ref,
-            false,
-            call_ctx,
-        );
-        extra_index += 1;
-    } else if (extra.data.bits.has_align_body) {
-        const align_body_len = file.zir.extra[extra_index];
-        extra_index += 1;
-        const align_body = file.zir.extra[extra_index .. extra_index + align_body_len];
-        _ = align_body;
-        // TODO: analyze the block (or bail with a comptimeExpr)
-        extra_index += align_body_len;
-    } else {
-        // default alignment
-    }
-
-    var addrspace_index: ?usize = null;
-    if (extra.data.bits.has_addrspace_ref) {
-        const addrspace_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-        addrspace_index = self.exprs.items.len;
-        _ = try self.walkRef(
-            file,
-            scope,
-            parent_src,
-            addrspace_ref,
-            false,
-            call_ctx,
-        );
-        extra_index += 1;
-    } else if (extra.data.bits.has_addrspace_body) {
-        const addrspace_body_len = file.zir.extra[extra_index];
-        extra_index += 1;
-        const addrspace_body = file.zir.extra[extra_index .. extra_index + addrspace_body_len];
-        _ = addrspace_body;
-        // TODO: analyze the block (or bail with a comptimeExpr)
-        extra_index += addrspace_body_len;
-    } else {
-        // default alignment
-    }
-
-    var section_index: ?usize = null;
-    if (extra.data.bits.has_section_ref) {
-        const section_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-        section_index = self.exprs.items.len;
-        _ = try self.walkRef(
-            file,
-            scope,
-            parent_src,
-            section_ref,
-            false,
-            call_ctx,
-        );
-        extra_index += 1;
-    } else if (extra.data.bits.has_section_body) {
-        const section_body_len = file.zir.extra[extra_index];
-        extra_index += 1;
-        const section_body = file.zir.extra[extra_index .. extra_index + section_body_len];
-        _ = section_body;
-        // TODO: analyze the block (or bail with a comptimeExpr)
-        extra_index += section_body_len;
-    } else {
-        // default alignment
-    }
-
-    var cc_index: ?usize = null;
-    if (extra.data.bits.has_cc_ref and !extra.data.bits.has_cc_body) {
-        const cc_ref: Zir.Inst.Ref = @enumFromInt(file.zir.extra[extra_index]);
-        const cc_expr = try self.walkRef(
-            file,
-            scope,
-            parent_src,
-            cc_ref,
-            false,
-            call_ctx,
-        );
-
-        cc_index = self.exprs.items.len;
-        try self.exprs.append(self.arena, cc_expr.expr);
-
-        extra_index += 1;
-    } else if (extra.data.bits.has_cc_body) {
-        const cc_body_len = file.zir.extra[extra_index];
-        extra_index += 1;
-        const cc_body = file.zir.bodySlice(extra_index, cc_body_len);
-
-        // We assume the body ends with a break_inline
-        const break_index = cc_body[cc_body.len - 1];
-        const break_operand = data[@intFromEnum(break_index)].@"break".operand;
-        const cc_expr = try self.walkRef(
-            file,
-            scope,
-            parent_src,
-            break_operand,
-            false,
-            call_ctx,
-        );
-
-        cc_index = self.exprs.items.len;
-        try self.exprs.append(self.arena, cc_expr.expr);
-
-        extra_index += cc_body_len;
-    } else {
-        // auto calling convention
-    }
-
-    // ret
-    const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
-        0 => switch (fn_info.ret_ty_ref) {
-            .none => DocData.Expr{ .void = .{} },
-            else => blk: {
-                const ref = fn_info.ret_ty_ref;
-                const wr = try self.walkRef(
-                    file,
-                    scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                break :blk wr.expr;
-            },
-        },
-        else => blk: {
-            const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
-            const break_operand = data[@intFromEnum(last_instr_index)].@"break".operand;
-            const wr = try self.walkRef(
-                file,
-                scope,
-                parent_src,
-                break_operand,
-                false,
-                call_ctx,
-            );
-            break :blk wr.expr;
-        },
-    };
-
-    // TODO: a complete version of this will probably need a scope
-    //       in order to evaluate correctly closures around funcion
-    //       parameters etc.
-    const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
-        .type => |t| blk: {
-            if (fn_info.body.len == 0) break :blk null;
-            if (t == @intFromEnum(Ref.type_type)) {
-                break :blk try self.getGenericReturnType(
-                    file,
-                    scope,
-                    parent_src,
-                    fn_info.body,
-                    call_ctx,
-                );
-            } else {
-                break :blk null;
-            }
-        },
-        else => null,
-    };
-
-    // if we're analyzing a function signature (ie without body), we
-    // actually don't have an ast_node reserved for us, but since
-    // we don't have a name, we don't need it.
-    const src = if (fn_info.body.len == 0) 0 else self_ast_node_index;
-
-    self.types.items[type_slot_index] = .{
-        .Fn = .{
-            .name = "todo_name func",
-            .src = src,
-            .params = param_type_refs.items,
-            .ret = ret_type_ref,
-            .generic_ret = generic_ret,
-            .is_extern = extra.data.bits.is_extern,
-            .has_cc = cc_index != null,
-            .has_align = align_index != null,
-            .has_lib_name = extra.data.bits.has_lib_name,
-            .lib_name = lib_name,
-            .is_inferred_error = extra.data.bits.is_inferred_error,
-            .cc = cc_index,
-            .@"align" = align_index,
-        },
-    };
-
-    return DocData.WalkResult{
-        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-        .expr = .{ .type = type_slot_index },
-    };
-}
-fn analyzeFunction(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    parent_src: SrcLocInfo,
-    inst: Zir.Inst.Index,
-    self_ast_node_index: usize,
-    type_slot_index: usize,
-    ret_is_inferred_error_set: bool,
-    call_ctx: ?*const CallContext,
-) AutodocErrors!DocData.WalkResult {
-    const tags = file.zir.instructions.items(.tag);
-    const data = file.zir.instructions.items(.data);
-    const fn_info = file.zir.getFnInfo(inst);
-
-    try self.ast_nodes.ensureUnusedCapacity(self.arena, fn_info.total_params_len);
-    var param_type_refs = try std.ArrayListUnmanaged(DocData.Expr).initCapacity(
-        self.arena,
-        fn_info.total_params_len,
-    );
-    var param_ast_indexes = try std.ArrayListUnmanaged(usize).initCapacity(
-        self.arena,
-        fn_info.total_params_len,
-    );
-
-    // TODO: handle scope rules for fn parameters
-    for (fn_info.param_body[0..fn_info.total_params_len]) |param_index| {
-        switch (tags[@intFromEnum(param_index)]) {
-            else => {
-                panicWithContext(
-                    file,
-                    param_index,
-                    "TODO: handle `{s}` in walkInstruction.func\n",
-                    .{@tagName(tags[@intFromEnum(param_index)])},
-                );
-            },
-            .param_anytype, .param_anytype_comptime => {
-                // TODO: where are the doc comments?
-                const str_tok = data[@intFromEnum(param_index)].str_tok;
-
-                const name = str_tok.get(file.zir);
-
-                param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
-                self.ast_nodes.appendAssumeCapacity(.{
-                    .name = name,
-                    .docs = "",
-                    .@"comptime" = tags[@intFromEnum(param_index)] == .param_anytype_comptime,
-                });
-
-                param_type_refs.appendAssumeCapacity(
-                    DocData.Expr{ .@"anytype" = .{} },
-                );
-            },
-            .param, .param_comptime => {
-                const pl_tok = data[@intFromEnum(param_index)].pl_tok;
-                const extra = file.zir.extraData(Zir.Inst.Param, pl_tok.payload_index);
-                const doc_comment = if (extra.data.doc_comment != .empty)
-                    file.zir.nullTerminatedString(extra.data.doc_comment)
-                else
-                    "";
-                const name = file.zir.nullTerminatedString(extra.data.name);
-
-                param_ast_indexes.appendAssumeCapacity(self.ast_nodes.items.len);
-                try self.ast_nodes.append(self.arena, .{
-                    .name = name,
-                    .docs = doc_comment,
-                    .@"comptime" = tags[@intFromEnum(param_index)] == .param_comptime,
-                });
-
-                const break_index = file.zir.extra[extra.end..][extra.data.body_len - 1];
-                const break_operand = data[break_index].@"break".operand;
-                const param_type_ref = try self.walkRef(
-                    file,
-                    scope,
-                    parent_src,
-                    break_operand,
-                    false,
-                    call_ctx,
-                );
-
-                param_type_refs.appendAssumeCapacity(param_type_ref.expr);
-            },
-        }
-    }
-
-    // ret
-    const ret_type_ref: DocData.Expr = switch (fn_info.ret_ty_body.len) {
-        0 => switch (fn_info.ret_ty_ref) {
-            .none => DocData.Expr{ .void = .{} },
-            else => blk: {
-                const ref = fn_info.ret_ty_ref;
-                const wr = try self.walkRef(
-                    file,
-                    scope,
-                    parent_src,
-                    ref,
-                    false,
-                    call_ctx,
-                );
-                break :blk wr.expr;
-            },
-        },
-        else => blk: {
-            const last_instr_index = fn_info.ret_ty_body[fn_info.ret_ty_body.len - 1];
-            const break_operand = data[@intFromEnum(last_instr_index)].@"break".operand;
-            const wr = try self.walkRef(
-                file,
-                scope,
-                parent_src,
-                break_operand,
-                false,
-                call_ctx,
-            );
-            break :blk wr.expr;
-        },
-    };
-
-    // TODO: a complete version of this will probably need a scope
-    //       in order to evaluate correctly closures around funcion
-    //       parameters etc.
-    const generic_ret: ?DocData.Expr = switch (ret_type_ref) {
-        .type => |t| blk: {
-            if (fn_info.body.len == 0) break :blk null;
-            if (t == @intFromEnum(Ref.type_type)) {
-                break :blk try self.getGenericReturnType(
-                    file,
-                    scope,
-                    parent_src,
-                    fn_info.body,
-                    call_ctx,
-                );
-            } else {
-                break :blk null;
-            }
-        },
-        else => null,
-    };
-
-    const ret_type: DocData.Expr = blk: {
-        if (ret_is_inferred_error_set) {
-            const ret_type_slot_index = self.types.items.len;
-            try self.types.append(self.arena, .{
-                .InferredErrorUnion = .{ .payload = ret_type_ref },
-            });
-            break :blk .{ .type = ret_type_slot_index };
-        } else break :blk ret_type_ref;
-    };
-
-    // if we're analyzing a function signature (ie without body), we
-    // actually don't have an ast_node reserved for us, but since
-    // we don't have a name, we don't need it.
-    const src = if (fn_info.body.len == 0) 0 else self_ast_node_index;
-
-    self.ast_nodes.items[self_ast_node_index].fields = param_ast_indexes.items;
-    self.types.items[type_slot_index] = .{
-        .Fn = .{
-            .name = "todo_name func",
-            .src = src,
-            .params = param_type_refs.items,
-            .ret = ret_type,
-            .generic_ret = generic_ret,
-        },
-    };
-
-    return DocData.WalkResult{
-        .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-        .expr = .{ .type = type_slot_index },
-    };
-}
-
-fn getGenericReturnType(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    parent_src: SrcLocInfo, // function decl line
-    body: []const Zir.Inst.Index,
-    call_ctx: ?*const CallContext,
-) !DocData.Expr {
-    const tags = file.zir.instructions.items(.tag);
-    if (body.len >= 4) {
-        const maybe_ret_inst = body[body.len - 4];
-        switch (tags[@intFromEnum(maybe_ret_inst)]) {
-            .ret_node, .ret_load => {
-                const wr = try self.walkInstruction(
-                    file,
-                    scope,
-                    parent_src,
-                    maybe_ret_inst,
-                    false,
-                    call_ctx,
-                );
-                return wr.expr;
-            },
-            else => {},
-        }
-    }
-    return DocData.Expr{ .comptimeExpr = 0 };
-}
-
-fn collectUnionFieldInfo(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    parent_src: SrcLocInfo,
-    fields_len: usize,
-    field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
-    field_name_indexes: *std.ArrayListUnmanaged(usize),
-    ei: usize,
-    call_ctx: ?*const CallContext,
-) !void {
-    if (fields_len == 0) return;
-    var extra_index = ei;
-
-    const bits_per_field = 4;
-    const fields_per_u32 = 32 / bits_per_field;
-    const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
-    var bit_bag_index: usize = extra_index;
-    extra_index += bit_bags_count;
-
-    var cur_bit_bag: u32 = undefined;
-    var field_i: u32 = 0;
-    while (field_i < fields_len) : (field_i += 1) {
-        if (field_i % fields_per_u32 == 0) {
-            cur_bit_bag = file.zir.extra[bit_bag_index];
-            bit_bag_index += 1;
-        }
-        const has_type = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-        const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-        const has_tag = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-        const unused = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-        _ = unused;
-
-        const field_name = file.zir.nullTerminatedString(@enumFromInt(file.zir.extra[extra_index]));
-        extra_index += 1;
-        const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
-        extra_index += 1;
-        const field_type: Zir.Inst.Ref = if (has_type) @enumFromInt(file.zir.extra[extra_index]) else .void_type;
-        if (has_type) extra_index += 1;
-
-        if (has_align) extra_index += 1;
-        if (has_tag) extra_index += 1;
-
-        // type
-        {
-            const walk_result = try self.walkRef(
-                file,
-                scope,
-                parent_src,
-                field_type,
-                false,
-                call_ctx,
-            );
-            try field_type_refs.append(self.arena, walk_result.expr);
-        }
-
-        // ast node
-        {
-            try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
-            const doc_comment: ?[]const u8 = if (doc_comment_index != .empty)
-                file.zir.nullTerminatedString(doc_comment_index)
-            else
-                null;
-            try self.ast_nodes.append(self.arena, .{
-                .name = field_name,
-                .docs = doc_comment,
-            });
-        }
-    }
-}
-
-fn collectStructFieldInfo(
-    self: *Autodoc,
-    file: *File,
-    scope: *Scope,
-    parent_src: SrcLocInfo,
-    fields_len: usize,
-    field_type_refs: *std.ArrayListUnmanaged(DocData.Expr),
-    field_default_refs: *std.ArrayListUnmanaged(?DocData.Expr),
-    field_name_indexes: *std.ArrayListUnmanaged(usize),
-    ei: usize,
-    is_tuple: bool,
-    call_ctx: ?*const CallContext,
-) !void {
-    if (fields_len == 0) return;
-    var extra_index = ei;
-
-    const bits_per_field = 4;
-    const fields_per_u32 = 32 / bits_per_field;
-    const bit_bags_count = std.math.divCeil(usize, fields_len, fields_per_u32) catch unreachable;
-
-    const Field = struct {
-        field_name: Zir.NullTerminatedString,
-        doc_comment_index: Zir.NullTerminatedString,
-        type_body_len: u32 = 0,
-        align_body_len: u32 = 0,
-        init_body_len: u32 = 0,
-        type_ref: Zir.Inst.Ref = .none,
-    };
-    const fields = try self.arena.alloc(Field, fields_len);
-
-    var bit_bag_index: usize = extra_index;
-    extra_index += bit_bags_count;
-
-    var cur_bit_bag: u32 = undefined;
-    var field_i: u32 = 0;
-    while (field_i < fields_len) : (field_i += 1) {
-        if (field_i % fields_per_u32 == 0) {
-            cur_bit_bag = file.zir.extra[bit_bag_index];
-            bit_bag_index += 1;
-        }
-        const has_align = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-        const has_default = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-        // const is_comptime = @truncate(u1, cur_bit_bag) != 0;
-        cur_bit_bag >>= 1;
-        const has_type_body = @as(u1, @truncate(cur_bit_bag)) != 0;
-        cur_bit_bag >>= 1;
-
-        const field_name: Zir.NullTerminatedString = if (!is_tuple) blk: {
-            const fname = file.zir.extra[extra_index];
-            extra_index += 1;
-            break :blk @enumFromInt(fname);
-        } else .empty;
-
-        const doc_comment_index: Zir.NullTerminatedString = @enumFromInt(file.zir.extra[extra_index]);
-        extra_index += 1;
-
-        fields[field_i] = .{
-            .field_name = field_name,
-            .doc_comment_index = doc_comment_index,
-        };
-
-        if (has_type_body) {
-            fields[field_i].type_body_len = file.zir.extra[extra_index];
-        } else {
-            fields[field_i].type_ref = @enumFromInt(file.zir.extra[extra_index]);
-        }
-        extra_index += 1;
-
-        if (has_align) {
-            fields[field_i].align_body_len = file.zir.extra[extra_index];
-            extra_index += 1;
-        }
-        if (has_default) {
-            fields[field_i].init_body_len = file.zir.extra[extra_index];
-            extra_index += 1;
-        }
-    }
-
-    const data = file.zir.instructions.items(.data);
-
-    for (fields) |field| {
-        const type_expr = expr: {
-            if (field.type_ref != .none) {
-                const walk_result = try self.walkRef(
-                    file,
-                    scope,
-                    parent_src,
-                    field.type_ref,
-                    false,
-                    call_ctx,
-                );
-                break :expr walk_result.expr;
-            }
-
-            std.debug.assert(field.type_body_len != 0);
-            const body = file.zir.bodySlice(extra_index, field.type_body_len);
-            extra_index += body.len;
-
-            const break_inst = body[body.len - 1];
-            const operand = data[@intFromEnum(break_inst)].@"break".operand;
-            try self.ast_nodes.append(self.arena, .{
-                .file = self.files.getIndex(file).?,
-                .line = parent_src.line,
-                .col = 0,
-                .fields = null, // walkInstruction will fill `fields` if necessary
-            });
-            const walk_result = try self.walkRef(
-                file,
-                scope,
-                parent_src,
-                operand,
-                false,
-                call_ctx,
-            );
-            break :expr walk_result.expr;
-        };
-
-        extra_index += field.align_body_len;
-
-        const default_expr: ?DocData.Expr = def: {
-            if (field.init_body_len == 0) {
-                break :def null;
-            }
-
-            const body = file.zir.bodySlice(extra_index, field.init_body_len);
-            extra_index += body.len;
-
-            const break_inst = body[body.len - 1];
-            const operand = data[@intFromEnum(break_inst)].@"break".operand;
-            const walk_result = try self.walkRef(
-                file,
-                scope,
-                parent_src,
-                operand,
-                false,
-                call_ctx,
-            );
-            break :def walk_result.expr;
-        };
-
-        try field_type_refs.append(self.arena, type_expr);
-        try field_default_refs.append(self.arena, default_expr);
-
-        // ast node
-        {
-            try field_name_indexes.append(self.arena, self.ast_nodes.items.len);
-            const doc_comment: ?[]const u8 = if (field.doc_comment_index != .empty)
-                file.zir.nullTerminatedString(field.doc_comment_index)
-            else
-                null;
-            const field_name: []const u8 = if (field.field_name != .empty)
-                file.zir.nullTerminatedString(field.field_name)
-            else
-                "";
-
-            try self.ast_nodes.append(self.arena, .{
-                .name = field_name,
-                .docs = doc_comment,
-            });
-        }
-    }
-}
-
-/// A Zir Ref can either refer to common types and values, or to a Zir index.
-/// WalkRef resolves common cases and delegates to `walkInstruction` otherwise.
-fn walkRef(
-    self: *Autodoc,
-    file: *File,
-    parent_scope: *Scope,
-    parent_src: SrcLocInfo,
-    ref: Ref,
-    need_type: bool, // true when the caller needs also a typeRef for the return value
-    call_ctx: ?*const CallContext,
-) AutodocErrors!DocData.WalkResult {
-    if (ref == .none) {
-        return .{ .expr = .{ .comptimeExpr = 0 } };
-    } else if (@intFromEnum(ref) <= @intFromEnum(InternPool.Index.last_type)) {
-        // We can just return a type that indexes into `types` with the
-        // enum value because in the beginning we pre-filled `types` with
-        // the types that are listed in `Ref`.
-        return DocData.WalkResult{
-            .typeRef = .{ .type = @intFromEnum(std.builtin.TypeId.Type) },
-            .expr = .{ .type = @intFromEnum(ref) },
-        };
-    } else if (ref.toIndex()) |zir_index| {
-        return self.walkInstruction(
-            file,
-            parent_scope,
-            parent_src,
-            zir_index,
-            need_type,
-            call_ctx,
-        );
-    } else {
-        switch (ref) {
-            else => {
-                panicWithOptionalContext(
-                    file,
-                    .none,
-                    "TODO: handle {s} in walkRef",
-                    .{@tagName(ref)},
-                );
-            },
-            .undef => {
-                return DocData.WalkResult{ .expr = .undefined };
-            },
-            .zero => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                    .expr = .{ .int = .{ .value = 0 } },
-                };
-            },
-            .one => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                    .expr = .{ .int = .{ .value = 1 } },
-                };
-            },
-            .negative_one => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.comptime_int_type) },
-                    .expr = .{ .int = .{ .value = 1, .negated = true } },
-                };
-            },
-            .zero_usize => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.usize_type) },
-                    .expr = .{ .int = .{ .value = 0 } },
-                };
-            },
-            .one_usize => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.usize_type) },
-                    .expr = .{ .int = .{ .value = 1 } },
-                };
-            },
-            .zero_u8 => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.u8_type) },
-                    .expr = .{ .int = .{ .value = 0 } },
-                };
-            },
-            .one_u8 => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.u8_type) },
-                    .expr = .{ .int = .{ .value = 1 } },
-                };
-            },
-            .four_u8 => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.u8_type) },
-                    .expr = .{ .int = .{ .value = 4 } },
-                };
-            },
-
-            .void_value => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.void_type) },
-                    .expr = .{ .void = .{} },
-                };
-            },
-            .unreachable_value => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.noreturn_type) },
-                    .expr = .{ .@"unreachable" = .{} },
-                };
-            },
-            .null_value => {
-                return DocData.WalkResult{ .expr = .null };
-            },
-            .bool_true => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
-                    .expr = .{ .bool = true },
-                };
-            },
-            .bool_false => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.bool_type) },
-                    .expr = .{ .bool = false },
-                };
-            },
-            .empty_struct => {
-                return DocData.WalkResult{ .expr = .{ .@"struct" = &.{} } };
-            },
-            .calling_convention_type => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.type_type) },
-                    .expr = .{ .type = @intFromEnum(Ref.calling_convention_type) },
-                };
-            },
-            .calling_convention_c => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.calling_convention_type) },
-                    .expr = .{ .enumLiteral = "C" },
-                };
-            },
-            .calling_convention_inline => {
-                return DocData.WalkResult{
-                    .typeRef = .{ .type = @intFromEnum(Ref.calling_convention_type) },
-                    .expr = .{ .enumLiteral = "Inline" },
-                };
-            },
-            // .generic_poison => {
-            //     return DocData.WalkResult{ .int = .{
-            //         .type = @intFromEnum(Ref.comptime_int_type),
-            //         .value = 1,
-            //     } };
-            // },
-        }
-    }
-}
-
-fn printWithContext(
-    file: *File,
-    inst: Zir.Inst.Index,
-    comptime fmt: []const u8,
-    args: anytype,
-) void {
-    return printWithOptionalContext(file, inst.toOptional(), fmt, args);
-}
-
-fn printWithOptionalContext(file: *File, inst: Zir.Inst.OptionalIndex, comptime fmt: []const u8, args: anytype) void {
-    log.debug("Context [{s}] % {} \n " ++ fmt, .{ file.sub_file_path, inst } ++ args);
-}
-
-fn panicWithContext(
-    file: *File,
-    inst: Zir.Inst.Index,
-    comptime fmt: []const u8,
-    args: anytype,
-) noreturn {
-    printWithOptionalContext(file, inst.toOptional(), fmt, args);
-    unreachable;
-}
-
-fn panicWithOptionalContext(
-    file: *File,
-    inst: Zir.Inst.OptionalIndex,
-    comptime fmt: []const u8,
-    args: anytype,
-) noreturn {
-    printWithOptionalContext(file, inst, fmt, args);
-    unreachable;
-}
-
-fn cteTodo(self: *Autodoc, msg: []const u8) error{OutOfMemory}!DocData.WalkResult {
-    const cte_slot_index = self.comptime_exprs.items.len;
-    try self.comptime_exprs.append(self.arena, .{
-        .code = msg,
-    });
-    return DocData.WalkResult{ .expr = .{ .comptimeExpr = cte_slot_index } };
-}
-
-fn writeFileTableToJson(
-    map: std.AutoArrayHashMapUnmanaged(*File, usize),
-    mods: std.AutoArrayHashMapUnmanaged(*Module, DocData.DocModule),
-    jsw: anytype,
-) !void {
-    try jsw.beginArray();
-    var it = map.iterator();
-    while (it.next()) |entry| {
-        try jsw.beginArray();
-        try jsw.write(entry.key_ptr.*.sub_file_path);
-        try jsw.write(mods.getIndex(entry.key_ptr.*.mod) orelse 0);
-        try jsw.endArray();
-    }
-    try jsw.endArray();
-}
-
-/// Writes the data like so:
-/// ```
-/// {
-///    "<section name>": [{name: "<guide name>", text: "<guide contents>"},],
-/// }
-/// ```
-fn writeGuidesToJson(sections: std.ArrayListUnmanaged(Section), jsw: anytype) !void {
-    try jsw.beginArray();
-
-    for (sections.items) |s| {
-        // section name
-        try jsw.beginObject();
-        try jsw.objectField("name");
-        try jsw.write(s.name);
-        try jsw.objectField("guides");
-
-        // section value
-        try jsw.beginArray();
-        for (s.guides.items) |g| {
-            try jsw.beginObject();
-            try jsw.objectField("name");
-            try jsw.write(g.name);
-            try jsw.objectField("body");
-            try jsw.write(g.body);
-            try jsw.endObject();
-        }
-        try jsw.endArray();
-        try jsw.endObject();
-    }
-
-    try jsw.endArray();
-}
-
-fn writeModuleTableToJson(
-    map: std.AutoHashMapUnmanaged(*Module, DocData.DocModule.TableEntry),
-    jsw: anytype,
-) !void {
-    try jsw.beginObject();
-    var it = map.valueIterator();
-    while (it.next()) |entry| {
-        try jsw.objectField(entry.name);
-        try jsw.write(entry.value);
-    }
-    try jsw.endObject();
-}
-
-fn srcLocInfo(
-    self: Autodoc,
-    file: *File,
-    src_node: i32,
-    parent_src: SrcLocInfo,
-) !SrcLocInfo {
-    const sn = @as(u32, @intCast(@as(i32, @intCast(parent_src.src_node)) + src_node));
-    const tree = try file.getTree(self.zcu.gpa);
-    const node_idx = @as(Ast.Node.Index, @bitCast(sn));
-    const tokens = tree.nodes.items(.main_token);
-
-    const tok_idx = tokens[node_idx];
-    const start = tree.tokens.items(.start)[tok_idx];
-    const loc = tree.tokenLocation(parent_src.bytes, tok_idx);
-    return SrcLocInfo{
-        .line = parent_src.line + loc.line,
-        .bytes = start,
-        .src_node = sn,
-    };
-}
-
-fn declIsVar(
-    self: Autodoc,
-    file: *File,
-    src_node: i32,
-    parent_src: SrcLocInfo,
-) !bool {
-    const sn = @as(u32, @intCast(@as(i32, @intCast(parent_src.src_node)) + src_node));
-    const tree = try file.getTree(self.zcu.gpa);
-    const node_idx = @as(Ast.Node.Index, @bitCast(sn));
-    const tokens = tree.nodes.items(.main_token);
-    const tags = tree.tokens.items(.tag);
-
-    const tok_idx = tokens[node_idx];
-
-    // tags[tok_idx] is the token called 'mut token' in AstGen
-    return (tags[tok_idx] == .keyword_var);
-}
-
-fn getBlockSource(
-    self: Autodoc,
-    file: *File,
-    parent_src: SrcLocInfo,
-    block_src_node: i32,
-) AutodocErrors![]const u8 {
-    const tree = try file.getTree(self.zcu.gpa);
-    const block_src = try self.srcLocInfo(file, block_src_node, parent_src);
-    return tree.getNodeSource(block_src.src_node);
-}
-
-fn getTLDocComment(self: *Autodoc, file: *File) ![]const u8 {
-    const source = (try file.getSource(self.zcu.gpa)).bytes;
-    var tokenizer = Tokenizer.init(source);
-    var tok = tokenizer.next();
-    var comment = std.ArrayList(u8).init(self.arena);
-    while (tok.tag == .container_doc_comment) : (tok = tokenizer.next()) {
-        try comment.appendSlice(source[tok.loc.start + "//!".len .. tok.loc.end + 1]);
-    }
-
-    return comment.items;
-}
-
-/// Returns the doc comment cleared of autodoc directives.
-fn findGuidePaths(self: *Autodoc, file: *File, str: []const u8) ![]const u8 {
-    const guide_prefix = "zig-autodoc-guide:";
-    const section_prefix = "zig-autodoc-section:";
-
-    try self.guide_sections.append(self.arena, .{}); // add a default section
-    var current_section = &self.guide_sections.items[self.guide_sections.items.len - 1];
-
-    var clean_docs: std.ArrayListUnmanaged(u8) = .{};
-    errdefer clean_docs.deinit(self.arena);
-
-    // TODO: this algo is kinda inefficient
-
-    var it = std.mem.splitScalar(u8, str, '\n');
-    while (it.next()) |line| {
-        const trimmed_line = std.mem.trim(u8, line, " ");
-        if (std.mem.startsWith(u8, trimmed_line, guide_prefix)) {
-            const path = trimmed_line[guide_prefix.len..];
-            const trimmed_path = std.mem.trim(u8, path, " ");
-            try self.addGuide(file, trimmed_path, current_section);
-        } else if (std.mem.startsWith(u8, trimmed_line, section_prefix)) {
-            const section_name = trimmed_line[section_prefix.len..];
-            const trimmed_section_name = std.mem.trim(u8, section_name, " ");
-            try self.guide_sections.append(self.arena, .{
-                .name = trimmed_section_name,
-            });
-            current_section = &self.guide_sections.items[self.guide_sections.items.len - 1];
-        } else {
-            try clean_docs.appendSlice(self.arena, line);
-            try clean_docs.append(self.arena, '\n');
-        }
-    }
-
-    return clean_docs.toOwnedSlice(self.arena);
-}
-
-fn addGuide(self: *Autodoc, file: *File, guide_path: []const u8, section: *Section) !void {
-    if (guide_path.len == 0) return error.MissingAutodocGuideName;
-
-    const resolved_path = try std.fs.path.resolve(self.arena, &[_][]const u8{
-        file.sub_file_path, "..", guide_path,
-    });
-
-    var guide_file = try file.mod.root.openFile(resolved_path, .{});
-    defer guide_file.close();
-
-    const guide = guide_file.reader().readAllAlloc(self.arena, 1 * 1024 * 1024) catch |err| switch (err) {
-        error.StreamTooLong => @panic("stream too long"),
-        else => |e| return e,
-    };
-
-    try section.guides.append(self.arena, .{
-        .name = resolved_path,
-        .body = guide,
-    });
-}
src/Compilation.zig
@@ -36,7 +36,6 @@ const Cache = std.Build.Cache;
 const c_codegen = @import("codegen/c.zig");
 const libtsan = @import("libtsan.zig");
 const Zir = std.zig.Zir;
-const Autodoc = @import("Autodoc.zig");
 const resinator = @import("resinator.zig");
 const Builtin = @import("Builtin.zig");
 const LlvmObject = @import("codegen/llvm.zig").Object;
@@ -2347,10 +2346,6 @@ fn flush(comp: *Compilation, arena: Allocator, prog_node: *std.Progress.Node) !v
             try emitLlvmObject(comp, arena, default_emit, null, llvm_object, prog_node);
         }
     }
-
-    if (comp.totalErrorCount() == 0) {
-        try maybeGenerateAutodocs(comp, prog_node);
-    }
 }
 
 /// This function is called by the frontend before flush(). It communicates that
@@ -2401,26 +2396,6 @@ fn renameTmpIntoCache(
     }
 }
 
-fn maybeGenerateAutodocs(comp: *Compilation, prog_node: *std.Progress.Node) !void {
-    const mod = comp.module orelse return;
-    // TODO: do this in a separate job during performAllTheWork(). The
-    // file copies at the end of generate() can also be extracted to
-    // separate jobs
-    if (!build_options.only_c and !build_options.only_core_functionality) {
-        if (comp.docs_emit) |emit| {
-            var dir = try emit.directory.handle.makeOpenPath(emit.sub_path, .{});
-            defer dir.close();
-
-            var sub_prog_node = prog_node.start("Generating documentation", 0);
-            sub_prog_node.activate();
-            sub_prog_node.context.refresh();
-            defer sub_prog_node.end();
-
-            try Autodoc.generate(mod, dir);
-        }
-    }
-}
-
 /// Communicate the output binary location to parent Compilations.
 fn wholeCacheModeSetBinFilePath(
     comp: *Compilation,