╭─────────────╮╭────────────╮ │scroll to top││next lines →│ ╰─────────────╯╰────────────╯ ╭ Zcu.zig ──────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
333 all_type_references: std.ArrayList(TypeReference) = .empty, 334 /// Freelist of indices in `all_type_references`. 335 free_type_references: std.ArrayList(u32) = .empty, 336 337 /// Populated by analysis of `AnalUnit.wrap(.{ .memoized_state = s })`, where `s` depends on the element. 338 std_lang_decl_values: StdLangDecl.Memoized = .initFill(.none), 339 340 incremental_debug_state: if (build_options.enable_debug_extensions) IncrementalDebugState else void = 341 if (build_options.enable_debug_extensions) .init else {}, 342 343 /// Times semantic analysis of the current `AnalUnit`. When we pause to analyze a different unit, 344 /// this timer must be temporarily paused and resumed later. 345 cur_analysis_timer: ?Compilation.Timer = null, 346 347 codegen_task_pool: CodegenTaskPool, 348 349 generation: u32 = 0, 350 351 /// Only access from the Sema thread. 352 anon_name_counter: u32, 353 354 pub const DependencyReason = struct { 355 src: LazySrcLoc, 356 /// Only populated if this is for a `.type_layout` unit. 357 type_layout_reason: Sema.type_resolution.LayoutResolveReason, 358 }; 359 360 /// These are not required for anything, but when the compiler is built with debug extensions, we 361 /// store these in `Zcu.transitive_failed_analysis` and surface them in the incremental debug server 362 /// (see `src/IncrementalDebugServer.zig`) because they are a useful debugging aid for bugs in 363 /// incremental compilation. 364 pub const TransitiveFailureReason = union(enum) { 365 astgen_error, 366 dependency_loop, 367 lost_tracking: InternPool.TrackedInst.Index, 368 failed_unit: AnalUnit, 369 func_nav_val_changed: InternPool.Index, 370 }; 371 372 pub const IncrementalDebugState = struct { 373 /// All container types in the ZCU, even dead ones. 374 /// Value is the generation the type was created on. 375 types: std.array_hash_map.Auto(InternPool.Index, u32), 376 /// All `Nav`s in the ZCU, even dead ones. 377 /// Value is the generation the `Nav` was created on. 378 navs: std.array_hash_map.Auto(InternPool.Nav.Index, u32), 379 /// All `AnalUnit`s in the ZCU, even dead ones. 380 units: std.array_hash_map.Auto(AnalUnit, UnitInfo), 381 382 pub const init: IncrementalDebugState = .{ 383 .types = .empty, 384 .navs = .empty, 385 .units = .empty, 386 }; 387 pub fn deinit(ids: *IncrementalDebugState, gpa: Allocator) void { 388 for (ids.units.values()) |*unit_info| { 389 unit_info.deps.deinit(gpa); 390 } 391 ids.types.deinit(gpa); 392 ids.navs.deinit(gpa); 393 ids.units.deinit(gpa); 394 } 395 396 pub const UnitInfo = struct { 397 last_update_gen: u32, 398 /// This information isn't easily recoverable from `InternPool`'s dependency storage format. 399 deps: std.ArrayList(InternPool.Dependee), 400 }; 401 pub fn getUnitInfo(ids: *IncrementalDebugState, gpa: Allocator, unit: AnalUnit) Allocator.Error!*UnitInfo { 402 const gop = try ids.units.getOrPut(gpa, unit); 403 if (!gop.found_existing) gop.value_ptr.* = .{ 404 .last_update_gen = std.math.maxInt(u32), 405 .deps = .empty, 406 }; 407 return gop.value_ptr; 408 } 409 pub fn newType(ids: *IncrementalDebugState, zcu: *Zcu, ty: InternPool.Index) Allocator.Error!void { 410 try ids.types.putNoClobber(zcu.gpa, ty, zcu.generation); 411 } 412 pub fn newNav(ids: *IncrementalDebugState, zcu: *Zcu, nav: InternPool.Nav.Index) Allocator.Error!void { 413 try ids.navs.putNoClobber(zcu.gpa, nav, zcu.generation); 414 } 415 }; 416 417 pub const PerThread = @import("Zcu/PerThread.zig"); 418 419 pub const ImportTableAdapter = struct { 420 zcu: *const Zcu, 421 pub fn hash(ctx: ImportTableAdapter, path: Compilation.Path) u32 { 422 _ = ctx; 423 return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path)); 424 } 425 pub fn eql(ctx: ImportTableAdapter, a_path: Compilation.Path, b_file: File.Index, b_index: usize) bool { 426 _ = b_index; 427 const b_path = ctx.zcu.fileByIndex(b_file).path; 428 return a_path.root == b_path.root and mem.eql(u8, a_path.sub_path, b_path.sub_path); 429 } 430 }; 431 432 pub const EmbedTableAdapter = struct { 433 pub fn hash(ctx: EmbedTableAdapter, path: Compilation.Path) u32 { 434 _ = ctx; 435 return @truncate(std.hash.Wyhash.hash(@backingInt(path.root), path.sub_path)); 436 } 437 pub fn eql(ctx: EmbedTableAdapter, a_path: Compilation.Path, b_file: *EmbedFile, b_index: usize) bool { 438 _ = ctx; 439 _ = b_index; 440 const b_path = b_file.path; 441 return a_path.root == b_path.root and mem.eql(u8, a_path.sub_path, b_path.sub_path); 442 } 443 }; 444 445 /// Names of declarations in `std.lang` whose values are memoized in a `StdLangDecl.Memoized`. 446 /// The name must exactly match the declaration name, as comptime logic is used to compute the namespace accesses. 447 /// Parent namespaces must be before their children in this enum. For instance, `.Type` must be before `.@"Type.Fn"`. 448 /// Additionally, parent namespaces must be resolved in the same stage as their children; see `StdLangDecl.stage`. 449 pub const StdLangDecl = enum { 450 Signedness, 451 AddressSpace, 452 CallingConvention, 453 returnError, 454 StackTrace, 455 SourceLocation, 456 CallModifier, 457 AtomicOrder, 458 AtomicRmwOp, 459 ReduceOp, 460 FloatMode, 461 PrefetchOptions, 462 ExportOptions, 463 ExternOptions, 464 BranchHint, 465 466 Type, 467 @"Type.Fn", 468 @"Type.Fn.ParamAttributes", 469 @"Type.Fn.Attributes", 470 @"Type.Int", 471 @"Type.Float", 472 @"Type.Pointer", 473 @"Type.Pointer.Size", 474 @"Type.Pointer.Attributes", 475 @"Type.Array", 476 @"Type.Vector", 477 @"Type.Optional", 478 @"Type.ErrorUnion", 479 @"Type.ErrorSet", 480 @"Type.Enum", 481 @"Type.Enum.Mode", 482 @"Type.Union", 483 @"Type.Union.FieldAttributes", 484 @"Type.Struct", 485 @"Type.Struct.FieldAttributes", 486 @"Type.ContainerLayout", 487 @"Type.Opaque", 488 @"Type.Spirv", 489 @"Type.Spirv.Image", 490 @"Type.Spirv.Image.Usage", 491 @"Type.Spirv.Image.Format", 492 @"Type.Spirv.Image.Dimensionality", 493 @"Type.Spirv.Image.Depth", 494 @"Type.Spirv.Image.Access", 495 496 panic, 497 @"panic.call", 498 @"panic.sentinelMismatch", 499 @"panic.unwrapError", 500 @"panic.outOfBounds", 501 @"panic.startGreaterThanEnd", 502 @"panic.inactiveUnionField", 503 @"panic.sliceCastLenRemainder", 504 @"panic.reachedUnreachable", 505 @"panic.unwrapNull", 506 @"panic.castToNull", 507 @"panic.incorrectAlignment", 508 @"panic.invalidErrorCode", 509 @"panic.unexpectedErrorCode", 510 @"panic.integerOutOfBounds", 511 @"panic.integerOverflow", 512 @"panic.shlOverflow", 513 @"panic.shrOverflow", 514 @"panic.divideByZero", 515 @"panic.exactDivisionRemainder", 516 @"panic.integerPartOutOfBounds", 517 @"panic.corruptSwitch", 518 @"panic.shiftRhsTooBig", 519 @"panic.invalidEnumValue", 520 @"panic.forLenMismatch", 521 @"panic.copyLenMismatch", 522 @"panic.memcpyAlias", 523 @"panic.noreturnReturned", 524 @"panic.loadUninstantiableType", 525 526 VaList, 527 528 assembly, 529 @"assembly.Clobbers", 530 531 /// Determines what kind of validation will be done to the decl's value. 532 pub fn kind(decl: StdLangDecl) enum { type, func, string } { 533 return switch (decl) { 534 .returnError => .func, 535 536 .StackTrace, 537 .CallingConvention, 538 .SourceLocation, 539 .Signedness, 540 .AddressSpace, 541 .VaList, 542 .CallModifier, 543 .AtomicOrder, 544 .AtomicRmwOp, 545 .ReduceOp, 546 .FloatMode, 547 .PrefetchOptions, 548 .ExportOptions, 549 .ExternOptions, 550 .BranchHint, 551 .assembly, 552 .@"assembly.Clobbers", 553 => .type, 554 555 .Type, 556 .@"Type.Fn", 557 .@"Type.Fn.ParamAttributes", 558 .@"Type.Fn.Attributes", 559 .@"Type.Int", 560 .@"Type.Float", 561 .@"Type.Pointer", 562 .@"Type.Pointer.Size", 563 .@"Type.Pointer.Attributes", 564 .@"Type.Array", 565 .@"Type.Vector", 566 .@"Type.Optional", 567 .@"Type.ErrorUnion", 568 .@"Type.ErrorSet", 569 .@"Type.Enum", 570 .@"Type.Enum.Mode", 571 .@"Type.Union", 572 .@"Type.Union.FieldAttributes", 573 .@"Type.Struct", 574 .@"Type.Struct.FieldAttributes", 575 .@"Type.ContainerLayout", 576 .@"Type.Opaque", 577 .@"Type.Spirv", 578 .@"Type.Spirv.Image", 579 .@"Type.Spirv.Image.Usage", 580 .@"Type.Spirv.Image.Format", 581 .@"Type.Spirv.Image.Dimensionality", 582 .@"Type.Spirv.Image.Depth", 583 .@"Type.Spirv.Image.Access", 584 => .type, 585 586 .panic => .type, 587 588 .@"panic.call", 589 .@"panic.sentinelMismatch", 590 .@"panic.unwrapError", 591 .@"panic.outOfBounds", 592 .@"panic.startGreaterThanEnd", 593 .@"panic.inactiveUnionField", 594 .@"panic.sliceCastLenRemainder", 595 .@"panic.reachedUnreachable", 596 .@"panic.unwrapNull", 597 .@"panic.castToNull", 598 .@"panic.incorrectAlignment", 599 .@"panic.invalidErrorCode", 600 .@"panic.unexpectedErrorCode", 601 .@"panic.integerOutOfBounds", 602 .@"panic.integerOverflow", 603 .@"panic.shlOverflow", 604 .@"panic.shrOverflow", 605 .@"panic.divideByZero", 606 .@"panic.exactDivisionRemainder", 607 .@"panic.integerPartOutOfBounds", 608 .@"panic.corruptSwitch", 609 .@"panic.shiftRhsTooBig", 610 .@"panic.invalidEnumValue", 611 .@"panic.forLenMismatch", 612 .@"panic.copyLenMismatch", 613 .@"panic.memcpyAlias", 614 .@"panic.noreturnReturned", 615 .@"panic.loadUninstantiableType", 616 => .func, 617 }; 618 } 619 620 /// Resolution of these values is done in three distinct stages: 621 /// * Resolution of `std.lang.Panic` and everything under it 622 /// * Resolution of `VaList` 623 /// * Resolution of `assembly` 624 /// * Everything else 625 /// 626 /// Panics are separated because they are provided by the user, so must be able to use 627 /// things like reification. 628 /// 629 /// `VaList` is separate because its value depends on the target, so it needs some reflection 630 /// machinery to work; additionally, it is `@compileError` on some targets, so must be referenced 631 /// by itself. 632 /// 633 /// `assembly` is separate because its value depends on the target. 634 pub fn stage(decl: StdLangDecl) InternPool.MemoizedStateStage { 635 return switch (decl) { 636 .VaList => .va_list, 637 .assembly, .@"assembly.Clobbers" => .assembly, 638 else => { 639 if (@backingInt(decl) <= @backingInt(StdLangDecl.@"Type.Spirv.Image.Access")) { 640 return .main; 641 } else { 642 return .panic; 643 } 644 }, 645 }; 646 } 647 648 /// Based on the tag name, determines how to access this decl; either as a direct child of the 649 /// `std.lang` namespace, or as a child of some preceding `StdLangDecl` value. 650 pub fn access(decl: StdLangDecl) union(enum) { 651 direct: []const u8, 652 nested: struct { StdLangDecl, []const u8 }, 653 } { 654 @setEvalBranchQuota(2000); 655 return switch (decl) { 656 inline else => |tag| { 657 const name = @tagName(tag); 658 const split = (comptime std.mem.findScalarLast(u8, name, '.')) orelse return .{ .direct = name }; 659 const parent = @field(StdLangDecl, name[0..split]); 660 comptime assert(@backingInt(parent) < @backingInt(tag)); // dependencies ordered correctly 661 return .{ .nested = .{ parent, name[split + 1 ..] } }; 662 }, 663 }; 664 } 665 666 const Memoized = std.enums.EnumArray(StdLangDecl, InternPool.Index); 667 }; 668 669 pub const SimplePanicId = enum { 670 reached_unreachable, 671 unwrap_null, 672 cast_to_null, 673 incorrect_alignment, 674 invalid_error_code, 675 integer_out_of_bounds, 676 integer_overflow, 677 shl_overflow, 678 shr_overflow, 679 divide_by_zero, 680 exact_division_remainder, 681 integer_part_out_of_bounds, 682 corrupt_switch, 683 shift_rhs_too_big, 684 invalid_enum_value, 685 for_len_mismatch, 686 copy_len_mismatch, 687 memcpy_alias, 688 noreturn_returned, 689 load_uninstantiable_type, 690 691 pub fn toStdLangDecl(id: SimplePanicId) StdLangDecl { 692 return switch (id) { 693 // zig fmt: off 694 .reached_unreachable => .@"panic.reachedUnreachable", 695 .unwrap_null => .@"panic.unwrapNull", 696 .cast_to_null => .@"panic.castToNull", 697 .incorrect_alignment => .@"panic.incorrectAlignment", 698 .invalid_error_code => .@"panic.invalidErrorCode", 699 .integer_out_of_bounds => .@"panic.integerOutOfBounds", 700 .integer_overflow => .@"panic.integerOverflow", 701 .shl_overflow => .@"panic.shlOverflow", 702 .shr_overflow => .@"panic.shrOverflow", 703 .divide_by_zero => .@"panic.divideByZero", 704 .exact_division_remainder => .@"panic.exactDivisionRemainder", 705 .integer_part_out_of_bounds => .@"panic.integerPartOutOfBounds", 706 .corrupt_switch => .@"panic.corruptSwitch", 707 .shift_rhs_too_big => .@"panic.shiftRhsTooBig", 708 .invalid_enum_value => .@"panic.invalidEnumValue", 709 .for_len_mismatch => .@"panic.forLenMismatch", 710 .copy_len_mismatch => .@"panic.copyLenMismatch", 711 .memcpy_alias => .@"panic.memcpyAlias", 712 .noreturn_returned => .@"panic.noreturnReturned", 713 .load_uninstantiable_type => .@"panic.loadUninstantiableType", 714 // zig fmt: on 715 }; 716 } 717 }; 718 719 pub const GlobalErrorSet = std.array_hash_map.Auto(InternPool.NullTerminatedString, void); 720 721 pub const CImportError = struct { 722 offset: u32, 723 line: u32, 724 column: u32, 725 path: ?[*:0]u8, 726 source_line: ?[*:0]u8, 727 msg: [*:0]u8, 728 729 pub fn deinit(err: CImportError, gpa: Allocator) void { 730 if (err.path) |some| gpa.free(std.mem.span(some)); 731 if (err.source_line) |some| gpa.free(std.mem.span(some)); 732 gpa.free(std.mem.span(err.msg)); 733 } 734 }; 735 736 pub const ErrorInt = u32; 737 738 pub const Exported = union(enum) { 739 /// The Nav being exported. Note this is *not* the Nav corresponding to the AnalUnit performing the export. 740 nav: InternPool.Nav.Index, 741 /// Constant value being exported. 742 uav: InternPool.Index, 743 744 pub fn getValue(exported: Exported, zcu: *Zcu) Value { 745 return switch (exported) { 746 .nav => |nav| zcu.navValue(nav), 747 .uav => |uav| Value.fromInterned(uav), 748 }; 749 } 750 751 pub fn getAlign(exported: Exported, zcu: *Zcu) Alignment { 752 return switch (exported) { 753 .nav => |nav| zcu.intern_pool.getNav(nav).resolved.?.@"align", 754 .uav => .none, 755 }; 756 } 757 }; 758 759 pub const Export = struct { 760 opts: Options, 761 src: LazySrcLoc, 762 exported: Exported, 763 764 pub const Options = struct { 765 name: InternPool.NullTerminatedString, 766 linkage: std.lang.GlobalLinkage = .strong, 767 section: InternPool.OptionalNullTerminatedString = .none, 768 visibility: std.lang.SymbolVisibility = .default, 769 }; 770 771 /// Index into `all_exports`. 772 pub const Index = enum(u32) { 773 _, 774 775 pub fn ptr(i: Index, zcu: *const Zcu) *Export { 776 return &zcu.all_exports.items[@backingInt(i)]; 777 } 778 }; 779 }; 780 781 pub const CompileLogLine = struct { 782 next: Index.Optional, 783 /// Does *not* include the trailing newline. 784 data: InternPool.NullTerminatedString, 785 pub const Index = enum(u32) { 786 _, 787 pub fn get(idx: Index, zcu: *Zcu) *CompileLogLine { 788 return &zcu.compile_log_lines.items[@backingInt(idx)]; 789 } 790 pub fn toOptional(idx: Index) Optional { 791 return @fromBackingInt(@intCast(@backingInt(idx))); 792 } 793 pub const Optional = enum(u32) { 794 none = std.math.maxInt(u32), 795 _, 796 pub fn unwrap(opt: Optional) ?Index { 797 return switch (opt) { 798 .none => null, 799 _ => @fromBackingInt(@intCast(@backingInt(opt))), 800 }; 801 } 802 }; 803 }; 804 }; 805 806 pub const Reference = struct { 807 /// The `AnalUnit` whose semantic analysis was triggered by this reference. 808 referenced: AnalUnit, 809 /// Index into `all_references` of the next `Reference` triggered by the same `AnalUnit`. 810 /// `std.math.maxInt(u32)` is the sentinel. 811 next: u32, 812 /// The source location of the reference. 813 src: LazySrcLoc, 814 /// If not `.none`, this is the index of the `InlineReferenceFrame` which should appear 815 /// between the referencer and `referenced` in the reference trace. These frames represent 816 /// inline calls, which do not create actual references (since they happen in the caller's 817 /// `AnalUnit`), but do show in the reference trace. 818 inline_frame: InlineReferenceFrame.Index.Optional, 819 }; 820 821 pub const InlineReferenceFrame = struct { 822 /// The inline *callee*; that is, the function which was called inline. 823 /// The *caller* is either `parent`, or else the unit causing the original `Reference`. 824 callee: InternPool.Index, 825 /// The source location of the inline call, in the *caller*. 826 call_src: LazySrcLoc, 827 /// If not `.none`, a frame which should appear directly below this one. 828 /// This will be the "parent" inline call; this frame's `callee` is our caller. 829 parent: InlineReferenceFrame.Index.Optional, 830 831 pub const Index = enum(u32) { 832 _, 833 pub fn ptr(idx: Index, zcu: *Zcu) *InlineReferenceFrame { 834 return &zcu.inline_reference_frames.items[@backingInt(idx)]; 835 } 836 pub fn toOptional(idx: Index) Optional { 837 return @fromBackingInt(@intCast(@backingInt(idx))); 838 } 839 pub const Optional = enum(u32) { 840 none = std.math.maxInt(u32), 841 _, 842 pub fn unwrap(opt: Optional) ?Index { 843 return switch (opt) { 844 .none => null, 845 _ => @fromBackingInt(@intCast(@backingInt(opt))), 846 }; 847 } 848 }; 849 }; 850 }; 851 852 pub const TypeReference = struct { 853 /// The container type which was referenced. 854 referenced: InternPool.Index, 855 /// Index into `all_type_references` of the next `TypeReference` triggered by the same `AnalUnit`. 856 /// `std.math.maxInt(u32)` is the sentinel. 857 next: u32, 858 /// The source location of the reference. 859 src: LazySrcLoc, 860 }; 861 862 /// The container that structs, enums, unions, and opaques have. 863 pub const Namespace = struct { 864 parent: OptionalIndex, 865 file_scope: File.Index, 866 generation: u32, 867 /// Will be a struct, enum, union, or opaque. 868 owner_type: InternPool.Index, 869 /// Members of the namespace which are marked `pub`. 870 pub_decls: std.array_hash_map.Custom(InternPool.Nav.Index, void, NavNameContext, true) = .empty, 871 /// Members of the namespace which are *not* marked `pub`. 872 priv_decls: std.array_hash_map.Custom(InternPool.Nav.Index, void, NavNameContext, true) = .empty, 873 /// All `comptime` declarations in this namespace. We store these purely so that incremental 874 /// compilation can re-use the existing `ComptimeUnit`s when a namespace changes. 875 comptime_decls: std.ArrayList(InternPool.ComptimeUnit.Id) = .empty, 876 /// All `test` declarations in this namespace. We store these purely so that incremental 877 /// compilation can re-use the existing `Nav`s when a namespace changes. 878 test_decls: std.ArrayList(InternPool.Nav.Index) = .empty, 879 880 pub const Index = InternPool.NamespaceIndex; 881 pub const OptionalIndex = InternPool.OptionalNamespaceIndex; 882 883 const NavNameContext = struct { 884 zcu: *Zcu, 885 886 pub fn hash(ctx: NavNameContext, nav: InternPool.Nav.Index) u32 { 887 const name = ctx.zcu.intern_pool.getNav(nav).name; 888 return std.hash.int(@backingInt(name)); 889 } 890 891 pub fn eql(ctx: NavNameContext, a_nav: InternPool.Nav.Index, b_nav: InternPool.Nav.Index, b_index: usize) bool { 892 _ = b_index; 893 const a_name = ctx.zcu.intern_pool.getNav(a_nav).name; 894 const b_name = ctx.zcu.intern_pool.getNav(b_nav).name; 895 return a_name == b_name; 896 } 897 }; 898 899 pub const NameAdapter = struct { 900 zcu: *Zcu, 901 902 pub fn hash(ctx: NameAdapter, s: InternPool.NullTerminatedString) u32 { 903 _ = ctx; 904 return std.hash.int(@backingInt(s)); 905 } 906 907 pub fn eql(ctx: NameAdapter, a: InternPool.NullTerminatedString, b_nav: InternPool.Nav.Index, b_index: usize) bool { 908 _ = b_index; 909 return a == ctx.zcu.intern_pool.getNav(b_nav).name; 910 } 911 }; 912 913 pub fn fileScope(ns: Namespace, zcu: *Zcu) *File { 914 return zcu.fileByIndex(ns.file_scope); 915 } 916 917 pub fn fileScopeIp(ns: Namespace, ip: *InternPool) *File { 918 return ip.filePtr(ns.file_scope); 919 } 920 921 /// This renders e.g. "std/fs.zig:Dir.OpenOptions" 922 pub fn renderFullyQualifiedDebugName( 923 ns: Namespace, 924 zcu: *Zcu, 925 name: InternPool.NullTerminatedString, 926 writer: *Writer, 927 ) @TypeOf(writer).Error!void { 928 const sep: u8 = if (ns.parent.unwrap()) |parent| sep: { 929 try zcu.namespacePtr(parent).renderFullyQualifiedDebugName( 930 zcu, 931 zcu.declPtr(ns.decl_index).name, 932 writer, 933 ); 934 break :sep '.'; 935 } else sep: { 936 try ns.fileScope(zcu).renderFullyQualifiedDebugName(writer); 937 break :sep ':'; 938 }; 939 if (name != .empty) try writer.print("{c}{f}", .{ sep, name.fmt(&zcu.intern_pool) }); 940 } 941 942 pub fn internFullyQualifiedName( 943 ns: Namespace, 944 ip: *InternPool, 945 gpa: Allocator, 946 io: Io, 947 tid: Zcu.PerThread.Id, 948 name: InternPool.NullTerminatedString, 949 ) !InternPool.NullTerminatedString { 950 const ns_fqn = Type.fromInterned(ns.owner_type).containerTypeName(ip).fqn; 951 if (name == .empty) return ns_fqn; 952 return ip.getOrPutStringFmt(gpa, io, tid, "{f}.{f}", .{ ns_fqn.fmt(ip), name.fmt(ip) }, .no_embedded_nulls); 953 } 954 }; 955 956 pub const File = struct { 957 status: enum { 958 /// We have not yet attempted to load this file. 959 /// `stat` is not populated and may be `undefined`. 960 never_loaded, 961 /// A filesystem access failed. It should be retried on the next update. 962 /// There is guaranteed to be a `failed_files` entry with at least one message. 963 /// ZIR/ZOIR errors should not be emitted as `zir`/`zoir` is not up-to-date. 964 /// `stat` is not populated and may be `undefined`. 965 retryable_failure, 966 /// This file has failed parsing, AstGen, or ZonGen. 967 /// There is guaranteed to be a `failed_files` entry, which may or may not have messages. 968 /// ZIR/ZOIR errors *should* be emitted as `zir`/`zoir` is up-to-date. 969 /// `stat` is populated. 970 astgen_failure, 971 /// Parsing and AstGen/ZonGen of this file has succeeded. 972 /// There may still be a `failed_files` entry, e.g. for non-fatal AstGen errors. 973 /// `stat` is populated. 974 success, 975 }, 976 /// Whether this is populated depends on `status`. 977 stat: Cache.Manifest.Stat, 978 979 /// Whether this file is the generated file of a "builtin" module. This matters because those 980 /// files are generated and stored in-nemory rather than being read off-disk. The rest of the 981 /// pipeline generally shouldn't care about this. 982 is_builtin: bool, 983 984 /// The path of this file. It is important that this path has a "canonical form" because files 985 /// are deduplicated based on path; `Compilation.Path` guarantees this. Owned by this `File`, 986 /// allocated into `gpa`. 987 path: Compilation.Path, 988 989 /// Populated only when emitting error messages; see `getSource`. 990 source: ?[:0]const u8, 991 /// Populated only when emitting error messages; see `getTree`. 992 tree: ?Ast, 993 994 zir: ?Zir, 995 zoir: ?Zoir, 996 997 /// Module that this file is a part of, managed externally. 998 /// This is initially `null`. After AstGen, a pass is run to determine which module each 999 /// file belongs to, at which point this field is set. It is never set to `null` again; 1000 /// this is so that if the file starts belonging to a different module instead, we can 1001 /// tell, and invalidate dependencies as needed (see `module_changed`). 1002 /// During semantic analysis, this is always non-`null` for alive files (i.e. those which 1003 /// have imports targeting them). 1004 mod: ?*Module, 1005 /// Relative to the root directory of `mod`. If `mod == null`, this field is `undefined`. 1006 /// This memory is managed externally and must not be directly freed. 1007 /// Its lifetime is at least equal to that of this `File`. 1008 sub_file_path: []const u8, 1009 1010 /// If this file's module identity changes on an incremental update, this flag is set to signal 1011 /// to `Zcu.updateZirRefs` that all references to this file must be invalidated. This matters 1012 /// because changing your module changes things like your optimization mode and codegen flags, 1013 /// so everything needs to be re-done. `updateZirRefs` is responsible for resetting this flag. 1014 module_changed: bool, 1015 1016 /// The ZIR for this file from the last update with no file failures. As such, this ZIR is never 1017 /// failed (although it may have compile errors). 1018 /// 1019 /// Because updates with file failures do not perform ZIR mapping or semantic analysis, we keep 1020 /// this around so we have the "old" ZIR to map when an update is ready to do so. Once such an 1021 /// update occurs, this field is unloaded, since it is no longer necessary. 1022 /// 1023 /// In other words, if `TrackedInst`s are tied to ZIR other than what's in the `zir` field, this 1024 /// field is populated with that old ZIR. 1025 prev_zir: ?*Zir, 1026 1027 /// This field serves a similar purpose to `prev_zir`, but for ZOIR. However, since we do not 1028 /// need to map old ZOIR to new ZOIR -- instead only invalidating dependencies if the ZOIR 1029 /// changed -- this field is just a simple boolean. 1030 /// 1031 /// When `zoir` is updated, this field is set to `true`. In `updateZirRefs`, if this is `true`, 1032 /// we invalidate the corresponding `source_file` dependency, and reset it to `false`. 1033 zoir_invalidated: bool, 1034 1035 pub const Path = struct { 1036 root: enum { 1037 cwd, 1038 fs_root, 1039 local_cache, 1040 global_cache, 1041 lib_dir, 1042 }, 1043 }; 1044 1045 /// A single reference to a file. 1046 pub const Reference = union(enum) { 1047 analysis_root: *Module, 1048 import: struct { 1049 importer: Zcu.File.Index, 1050 tok: Ast.TokenIndex, 1051 /// If the file is imported as the root of a module, this is that module. 1052 /// `null` means the file was imported directly by path. 1053 module: ?*Module, 1054 }, 1055 }; 1056 1057 pub fn getMode(self: File) Ast.Mode { 1058 // We never create a `File` whose path doesn't give a mode. 1059 return modeFromPath(self.path.sub_path).?; 1060 } 1061 1062 pub fn modeFromPath(path: []const u8) ?Ast.Mode { 1063 if (std.mem.endsWith(u8, path, ".zon")) { 1064 return .zon; 1065 } else if (std.mem.endsWith(u8, path, ".zig")) { 1066 return .zig; 1067 } else { 1068 return null; 1069 } 1070 } 1071 1072 pub fn unload(file: *File, gpa: Allocator) void { 1073 if (file.zoir) |zoir| zoir.deinit(gpa); 1074 file.unloadTree(gpa); 1075 file.unloadSource(gpa); 1076 file.unloadZir(gpa); 1077 } 1078 1079 pub fn unloadTree(file: *File, gpa: Allocator) void { 1080 if (file.tree) |*tree| { 1081 tree.deinit(gpa); 1082 file.tree = null; 1083 } 1084 } 1085 1086 pub fn unloadSource(file: *File, gpa: Allocator) void { 1087 if (file.source) |source| { 1088 gpa.free(source); 1089 file.source = null; 1090 } 1091 } 1092 1093 pub fn unloadZir(file: *File, gpa: Allocator) void { 1094 if (file.zir) |*zir| { 1095 zir.deinit(gpa); 1096 file.zir = null; 1097 } 1098 } 1099 1100 pub const GetSourceError = error{ 1101 OutOfMemory, 1102 FileChanged, 1103 } || std.Io.File.OpenError || std.Io.File.Reader.Error; 1104 1105 /// This must only be called in error conditions where `stat` *is* populated. It returns the 1106 /// contents of the source file, assuming the stat has not changed since it was originally 1107 /// loaded. 1108 pub fn getSource(file: *File, zcu: *const Zcu) GetSourceError![:0]const u8 { 1109 const gpa = zcu.gpa; 1110 const io = zcu.comp.io; 1111 1112 if (file.source) |source| return source; 1113 1114 switch (file.status) { 1115 .never_loaded => unreachable, // stat must be populated 1116 .retryable_failure => unreachable, // stat must be populated 1117 .astgen_failure, .success => {}, 1118 } 1119 1120 assert(file.stat.size <= std.math.maxInt(u32)); // `PerThread.updateFile` checks this 1121 1122 var f = f: { 1123 const dir, const sub_path = file.path.openInfo(zcu.comp.dirs); 1124 break :f try dir.openFile(io, sub_path, .{}); 1125 }; 1126 defer f.close(io); 1127 1128 const stat = f.stat(io) catch |err| switch (err) { 1129 error.Streaming => { 1130 // Since `file.stat` is populated, this was previously a file stream; since it is 1131 // now not a file stream, it must have changed. 1132 return error.FileChanged; 1133 }, 1134 else => |e| return e, 1135 }; 1136 1137 if (stat.inode != file.stat.inode or 1138 stat.size != file.stat.size or 1139 stat.mtime.nanoseconds != file.stat.mtime.nanoseconds) 1140 { 1141 return error.FileChanged; 1142 } 1143 1144 const source = try gpa.allocSentinel(u8, @intCast(file.stat.size), 0); 1145 errdefer gpa.free(source); 1146 1147 var file_reader = f.reader(io, &.{}); 1148 file_reader.size = stat.size; 1149 file_reader.interface.readSliceAll(source) catch return file_reader.err.?; 1150 1151 file.source = source; 1152 errdefer comptime unreachable; // don't error after populating `source` 1153 1154 return source; 1155 } 1156 1157 /// This must only be called in error conditions where `stat` *is* populated. It returns the 1158 /// parsed AST of the source file, assuming the stat has not changed since it was originally 1159 /// loaded. 1160 pub fn getTree(file: *File, zcu: *const Zcu) GetSourceError!*const Ast { 1161 if (file.tree) |*tree| return tree; 1162 1163 const source = try file.getSource(zcu); 1164 file.tree = try .parse(zcu.gpa, source, .{ .mode = file.getMode() }); 1165 return &file.tree.?; 1166 } 1167 1168 pub fn fullyQualifiedNameLen(file: File) usize { 1169 const ext = std.fs.path.extension(file.sub_file_path); 1170 return file.sub_file_path.len - ext.len; 1171 } 1172 1173 pub fn renderFullyQualifiedName(file: File, writer: *Writer) !void { 1174 // Convert all the slashes into dots and truncate the extension. 1175 const ext = std.fs.path.extension(file.sub_file_path); 1176 const noext = file.sub_file_path[0 .. file.sub_file_path.len - ext.len]; 1177 for (noext) |byte| switch (byte) { 1178 '/', '\\' => try writer.writeByte('.'), 1179 else => try writer.writeByte(byte), 1180 }; 1181 } 1182 1183 pub fn renderFullyQualifiedDebugName(file: File, writer: *Writer) !void { 1184 for (file.sub_file_path) |byte| switch (byte) { 1185 '/', '\\' => try writer.writeByte('/'), 1186 else => try writer.writeByte(byte), 1187 }; 1188 } 1189 1190 pub fn internFullyQualifiedName(file: File, pt: Zcu.PerThread) !InternPool.NullTerminatedString { 1191 const ip = &pt.zcu.intern_pool; 1192 const comp = pt.zcu.comp; 1193 const gpa = comp.gpa; 1194 const io = comp.io; 1195 const string_bytes = ip.getLocal(pt.tid).getMutableStringBytes(gpa, io); 1196 var w: Writer = .fixed((try string_bytes.addManyAsSlice(file.fullyQualifiedNameLen()))[0]); 1197 file.renderFullyQualifiedName(&w) catch unreachable; 1198 assert(w.end == w.buffer.len); 1199 return ip.getOrPutTrailingString(gpa, io, pt.tid, @intCast(w.end), .no_embedded_nulls); 1200 } 1201 1202 pub const Index = InternPool.FileIndex; 1203 1204 pub fn errorBundleWholeFileSrc( 1205 file: *File, 1206 zcu: *const Zcu, 1207 eb: *std.zig.ErrorBundle.Wip, 1208 ) Allocator.Error!std.zig.ErrorBundle.SourceLocationIndex { 1209 return eb.addSourceLocation(.{ 1210 .src_path = try eb.printString("{f}", .{file.path.fmt(zcu.comp)}), 1211 .span_start = 0, 1212 .span_main = 0, 1213 .span_end = 0, 1214 .line = 0, 1215 .column = 0, 1216 .source_line = 0, 1217 }); 1218 } 1219 /// Asserts that the tree has already been loaded with `getTree`. 1220 pub fn errorBundleTokenSrc( 1221 file: *File, 1222 tok: Ast.TokenIndex, 1223 zcu: *const Zcu, 1224 eb: *std.zig.ErrorBundle.Wip, 1225 ) Allocator.Error!std.zig.ErrorBundle.SourceLocationIndex { 1226 const tree = &file.tree.?; 1227 const start = tree.tokenStart(tok); 1228 const end = start + tree.tokenSlice(tok).len; 1229 const loc = std.zig.findLineColumn(file.source.?, start); 1230 return eb.addSourceLocation(.{ 1231 .src_path = try eb.printString("{f}", .{file.path.fmt(zcu.comp)}), 1232 .span_start = start, 1233 .span_main = start, 1234 .span_end = @intCast(end), 1235 .line = @intCast(loc.line), 1236 .column = @intCast(loc.column), 1237 .source_line = try eb.addString(loc.source_line), 1238 }); 1239 } 1240 }; 1241 1242 /// Represents the contents of a file loaded with `@embedFile`. 1243 pub const EmbedFile = struct { 1244 path: Compilation.Path, 1245 /// `.none` means the file was not loaded, so `stat` is undefined. 1246 val: InternPool.Index, 1247 /// If this is `null` and `val` is `.none`, the file has never been loaded. 1248 err: ?(Io.File.OpenError || Io.File.StatError || Io.File.Reader.Error || error{UnexpectedEof}), 1249 stat: Cache.Manifest.Stat, 1250 1251 pub const Index = enum(u32) { 1252 _, 1253 pub fn get(idx: Index, zcu: *const Zcu) *EmbedFile { 1254 return zcu.embed_table.keys()[@backingInt(idx)]; 1255 } 1256 }; 1257 }; 1258 1259 /// This struct holds data necessary to construct API-facing `AllErrors.Message`. 1260 /// Its memory is managed with the general purpose allocator so that they 1261 /// can be created and destroyed in response to incremental updates. 1262 pub const ErrorMsg = struct { 1263 src_loc: LazySrcLoc, 1264 msg: []const u8, 1265 notes: []ErrorMsg = &.{}, 1266 reference_trace_root: AnalUnit.Optional = .none, 1267 1268 pub fn order(lhs: *const ErrorMsg, rhs: *const ErrorMsg, zcu: *Zcu) std.math.Order { 1269 return lhs.src_loc.order(rhs.src_loc, zcu).differ() orelse 1270 std.mem.order(u8, lhs.msg, rhs.msg).differ() orelse 1271 std.math.order(lhs.notes.len, rhs.notes.len).differ() orelse 1272 for (lhs.notes, rhs.notes) |*lhs_note, *rhs_note| { 1273 if (order(lhs_note, rhs_note, zcu).differ()) |o| break o; 1274 } else .eq; 1275 } 1276 1277 pub fn create( 1278 gpa: Allocator, 1279 src_loc: LazySrcLoc, 1280 comptime format: []const u8, 1281 args: anytype, 1282 ) !*ErrorMsg { 1283 assert(src_loc.offset != .unneeded); 1284 const err_msg = try gpa.create(ErrorMsg); 1285 errdefer gpa.destroy(err_msg); 1286 err_msg.* = try ErrorMsg.init(gpa, src_loc, format, args); 1287 return err_msg; 1288 } 1289 1290 /// Assumes the ErrorMsg struct and msg were both allocated with `gpa`, 1291 /// as well as all notes. 1292 pub fn destroy(err_msg: *ErrorMsg, gpa: Allocator) void { 1293 err_msg.deinit(gpa); 1294 gpa.destroy(err_msg); 1295 } 1296 1297 pub fn init(gpa: Allocator, src_loc: LazySrcLoc, comptime format: []const u8, args: anytype) !ErrorMsg { 1298 return .{ 1299 .src_loc = src_loc, 1300 .msg = try std.fmt.allocPrint(gpa, format, args), 1301 }; 1302 } 1303 1304 pub fn deinit(err_msg: *ErrorMsg, gpa: Allocator) void { 1305 for (err_msg.notes) |*note| { 1306 note.deinit(gpa); 1307 } 1308 gpa.free(err_msg.notes); 1309 gpa.free(err_msg.msg); 1310 err_msg.* = undefined; 1311 } 1312 }; 1313 1314 pub const AstGenSrc = union(enum) { 1315 root, 1316 import: struct { 1317 importing_file: Zcu.File.Index, 1318 import_tok: std.zig.Ast.TokenIndex, 1319 }, 1320 }; 1321 1322 /// Canonical reference to a position within a source file. 1323 pub const SrcLoc = struct { 1324 file_scope: *File, 1325 base_node: Ast.Node.Index, 1326 /// Relative to `base_node`. 1327 lazy: LazySrcLoc.Offset, 1328 1329 pub fn baseSrcToken(src_loc: SrcLoc) Ast.TokenIndex { 1330 const tree = src_loc.file_scope.tree.?; 1331 return tree.firstToken(src_loc.base_node); 1332 } 1333 1334 pub const Span = Ast.Span; 1335 1336 pub fn span(src_loc: SrcLoc, zcu: *const Zcu) !Span { 1337 switch (src_loc.lazy) { 1338 .unneeded => unreachable, 1339 1340 .byte_abs => |byte_index| return Span{ .start = byte_index, .end = byte_index + 1, .main = byte_index }, 1341 1342 .token_abs => |tok_index| { 1343 const tree = try src_loc.file_scope.getTree(zcu); 1344 const start = tree.tokenStart(tok_index); 1345 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1346 return Span{ .start = start, .end = end, .main = start }; 1347 }, 1348 .node_abs => |node| { 1349 const tree = try src_loc.file_scope.getTree(zcu); 1350 return tree.nodeToSpan(node); 1351 }, 1352 .byte_offset => |byte_off| { 1353 const tree = try src_loc.file_scope.getTree(zcu); 1354 const tok_index = src_loc.baseSrcToken(); 1355 const start = tree.tokenStart(tok_index) + byte_off; 1356 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1357 return Span{ .start = start, .end = end, .main = start }; 1358 }, 1359 .token_offset => |tok_off| { 1360 const tree = try src_loc.file_scope.getTree(zcu); 1361 const tok_index = tok_off.toAbsolute(src_loc.baseSrcToken()); 1362 const start = tree.tokenStart(tok_index); 1363 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1364 return Span{ .start = start, .end = end, .main = start }; 1365 }, 1366 .node_offset => |traced_off| { 1367 const node_off = traced_off.x; 1368 const tree = try src_loc.file_scope.getTree(zcu); 1369 const node = node_off.toAbsolute(src_loc.base_node); 1370 return tree.nodeToSpan(node); 1371 }, 1372 .node_offset_main_token => |node_off| { 1373 const tree = try src_loc.file_scope.getTree(zcu); 1374 const node = node_off.toAbsolute(src_loc.base_node); 1375 const main_token = tree.nodeMainToken(node); 1376 return tree.tokensToSpan(main_token, main_token, main_token); 1377 }, 1378 .node_offset_bin_op => |node_off| { 1379 const tree = try src_loc.file_scope.getTree(zcu); 1380 const node = node_off.toAbsolute(src_loc.base_node); 1381 return tree.nodeToSpan(node); 1382 }, 1383 .node_offset_initializer => |node_off| { 1384 const tree = try src_loc.file_scope.getTree(zcu); 1385 const node = node_off.toAbsolute(src_loc.base_node); 1386 return tree.tokensToSpan( 1387 tree.firstToken(node) - 3, 1388 tree.lastToken(node), 1389 tree.nodeMainToken(node) - 2, 1390 ); 1391 }, 1392 .node_offset_var_decl_ty => |node_off| { 1393 const tree = try src_loc.file_scope.getTree(zcu); 1394 const node = node_off.toAbsolute(src_loc.base_node); 1395 const full = switch (tree.nodeTag(node)) { 1396 .global_var_decl, 1397 .local_var_decl, 1398 .simple_var_decl, 1399 .aligned_var_decl, 1400 => tree.fullVarDecl(node).?, 1401 else => unreachable, 1402 }; 1403 if (full.ast.type_node.unwrap()) |type_node| { 1404 return tree.nodeToSpan(type_node); 1405 } 1406 const tok_index = full.ast.mut_token + 1; // the name token 1407 const start = tree.tokenStart(tok_index); 1408 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1409 return Span{ .start = start, .end = end, .main = start }; 1410 }, 1411 .node_offset_var_decl_align => |node_off| { 1412 const tree = try src_loc.file_scope.getTree(zcu); 1413 const node = node_off.toAbsolute(src_loc.base_node); 1414 var buf: [1]Ast.Node.Index = undefined; 1415 const align_node = if (tree.fullVarDecl(node)) |v| 1416 v.ast.align_node.unwrap().? 1417 else if (tree.fullFnProto(&buf, node)) |f| 1418 f.ast.align_expr.unwrap().? 1419 else 1420 unreachable; 1421 return tree.nodeToSpan(align_node); 1422 }, 1423 .node_offset_var_decl_section => |node_off| { 1424 const tree = try src_loc.file_scope.getTree(zcu); 1425 const node = node_off.toAbsolute(src_loc.base_node); 1426 var buf: [1]Ast.Node.Index = undefined; 1427 const section_node = if (tree.fullVarDecl(node)) |v| 1428 v.ast.section_node.unwrap().? 1429 else if (tree.fullFnProto(&buf, node)) |f| 1430 f.ast.section_expr.unwrap().? 1431 else 1432 unreachable; 1433 return tree.nodeToSpan(section_node); 1434 }, 1435 .node_offset_var_decl_addrspace => |node_off| { 1436 const tree = try src_loc.file_scope.getTree(zcu); 1437 const node = node_off.toAbsolute(src_loc.base_node); 1438 var buf: [1]Ast.Node.Index = undefined; 1439 const addrspace_node = if (tree.fullVarDecl(node)) |v| 1440 v.ast.addrspace_node.unwrap().? 1441 else if (tree.fullFnProto(&buf, node)) |f| 1442 f.ast.addrspace_expr.unwrap().? 1443 else 1444 unreachable; 1445 return tree.nodeToSpan(addrspace_node); 1446 }, 1447 .node_offset_var_decl_init => |node_off| { 1448 const tree = try src_loc.file_scope.getTree(zcu); 1449 const node = node_off.toAbsolute(src_loc.base_node); 1450 const init_node = switch (tree.nodeTag(node)) { 1451 .global_var_decl, 1452 .local_var_decl, 1453 .aligned_var_decl, 1454 .simple_var_decl, 1455 => tree.fullVarDecl(node).?.ast.init_node.unwrap().?, 1456 .assign_destructure => tree.assignDestructure(node).ast.value_expr, 1457 else => unreachable, 1458 }; 1459 return tree.nodeToSpan(init_node); 1460 }, 1461 .node_offset_builtin_call_arg => |builtin_arg| { 1462 const tree = try src_loc.file_scope.getTree(zcu); 1463 const node = builtin_arg.builtin_call_node.toAbsolute(src_loc.base_node); 1464 var buf: [2]Ast.Node.Index = undefined; 1465 const params = tree.builtinCallParams(&buf, node).?; 1466 return tree.nodeToSpan(params[builtin_arg.arg_index]); 1467 }, 1468 .node_offset_ptrcast_operand => |node_off| { 1469 const tree = try src_loc.file_scope.getTree(zcu); 1470 1471 var node = node_off.toAbsolute(src_loc.base_node); 1472 while (true) { 1473 switch (tree.nodeTag(node)) { 1474 .builtin_call_two, .builtin_call_two_comma => {}, 1475 else => break, 1476 } 1477 1478 const first_arg, const second_arg = tree.nodeData(node).opt_node_and_opt_node; 1479 if (first_arg == .none) break; // 0 args 1480 if (second_arg != .none) break; // 2 args 1481 1482 const builtin_token = tree.nodeMainToken(node); 1483 const builtin_name = tree.tokenSlice(builtin_token); 1484 const info = BuiltinFn.list.get(builtin_name) orelse break; 1485 1486 switch (info.tag) { 1487 else => break, 1488 .ptr_cast, 1489 .align_cast, 1490 .addrspace_cast, 1491 .const_cast, 1492 .volatile_cast, 1493 => {}, 1494 } 1495 1496 node = first_arg.unwrap().?; 1497 } 1498 1499 return tree.nodeToSpan(node); 1500 }, 1501 .node_offset_array_access_index => |node_off| { 1502 const tree = try src_loc.file_scope.getTree(zcu); 1503 const node = node_off.toAbsolute(src_loc.base_node); 1504 return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]); 1505 }, 1506 .node_offset_slice_ptr, 1507 .node_offset_slice_start, 1508 .node_offset_slice_end, 1509 .node_offset_slice_sentinel, 1510 => |node_off| { 1511 const tree = try src_loc.file_scope.getTree(zcu); 1512 const node = node_off.toAbsolute(src_loc.base_node); 1513 const full = tree.fullSlice(node).?; 1514 const part_node = switch (src_loc.lazy) { 1515 .node_offset_slice_ptr => full.ast.sliced, 1516 .node_offset_slice_start => full.ast.start, 1517 .node_offset_slice_end => full.ast.end.unwrap().?, 1518 .node_offset_slice_sentinel => full.ast.sentinel.unwrap().?, 1519 else => unreachable, 1520 }; 1521 return tree.nodeToSpan(part_node); 1522 }, 1523 .node_offset_call_func => |node_off| { 1524 const tree = try src_loc.file_scope.getTree(zcu); 1525 const node = node_off.toAbsolute(src_loc.base_node); 1526 var buf: [1]Ast.Node.Index = undefined; 1527 const full = tree.fullCall(&buf, node).?; 1528 return tree.nodeToSpan(full.ast.fn_expr); 1529 }, 1530 .node_offset_field_name => |node_off| { 1531 const tree = try src_loc.file_scope.getTree(zcu); 1532 const node = node_off.toAbsolute(src_loc.base_node); 1533 var buf: [1]Ast.Node.Index = undefined; 1534 const tok_index = switch (tree.nodeTag(node)) { 1535 .field_access => tree.nodeData(node).node_and_token[1], 1536 .call_one, 1537 .call_one_comma, 1538 .call, 1539 .call_comma, 1540 => blk: { 1541 const full = tree.fullCall(&buf, node).?; 1542 break :blk tree.lastToken(full.ast.fn_expr); 1543 }, 1544 else => tree.firstToken(node) - 2, 1545 }; 1546 const start = tree.tokenStart(tok_index); 1547 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1548 return Span{ .start = start, .end = end, .main = start }; 1549 }, 1550 .node_offset_field_name_init => |node_off| { 1551 const tree = try src_loc.file_scope.getTree(zcu); 1552 const node = node_off.toAbsolute(src_loc.base_node); 1553 const tok_index = tree.firstToken(node) - 2; 1554 const start = tree.tokenStart(tok_index); 1555 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1556 return Span{ .start = start, .end = end, .main = start }; 1557 }, 1558 .node_offset_deref_ptr => |node_off| { 1559 const tree = try src_loc.file_scope.getTree(zcu); 1560 const node = node_off.toAbsolute(src_loc.base_node); 1561 return tree.nodeToSpan(tree.nodeData(node).node); 1562 }, 1563 .node_offset_asm_source => |node_off| { 1564 const tree = try src_loc.file_scope.getTree(zcu); 1565 const node = node_off.toAbsolute(src_loc.base_node); 1566 const full = tree.fullAsm(node).?; 1567 return tree.nodeToSpan(full.ast.template); 1568 }, 1569 .node_offset_asm_ret_ty => |node_off| { 1570 const tree = try src_loc.file_scope.getTree(zcu); 1571 const node = node_off.toAbsolute(src_loc.base_node); 1572 const full = tree.fullAsm(node).?; 1573 const asm_output = full.outputs[0]; 1574 return tree.nodeToSpan(tree.nodeData(asm_output).opt_node_and_token[0].unwrap().?); 1575 }, 1576 1577 .node_offset_if_cond => |node_off| { 1578 const tree = try src_loc.file_scope.getTree(zcu); 1579 const node = node_off.toAbsolute(src_loc.base_node); 1580 const src_node = switch (tree.nodeTag(node)) { 1581 .if_simple, 1582 .@"if", 1583 => tree.fullIf(node).?.ast.cond_expr, 1584 1585 .while_simple, 1586 .while_cont, 1587 .@"while", 1588 => tree.fullWhile(node).?.ast.cond_expr, 1589 1590 .for_simple, 1591 .@"for", 1592 => { 1593 const inputs = tree.fullFor(node).?.ast.inputs; 1594 const start = tree.firstToken(inputs[0]); 1595 const end = tree.lastToken(inputs[inputs.len - 1]); 1596 return tree.tokensToSpan(start, end, start); 1597 }, 1598 1599 .@"orelse" => node, 1600 .@"catch" => node, 1601 else => unreachable, 1602 }; 1603 return tree.nodeToSpan(src_node); 1604 }, 1605 .asm_input => |input| { 1606 const tree = try src_loc.file_scope.getTree(zcu); 1607 const node = input.offset.toAbsolute(src_loc.base_node); 1608 const full = tree.fullAsm(node).?; 1609 const asm_input = full.inputs[input.input_index]; 1610 return tree.nodeToSpan(tree.nodeData(asm_input).node_and_token[0]); 1611 }, 1612 .asm_output => |output| { 1613 const tree = try src_loc.file_scope.getTree(zcu); 1614 const node = output.offset.toAbsolute(src_loc.base_node); 1615 const full = tree.fullAsm(node).?; 1616 const asm_output = full.outputs[output.output_index]; 1617 const data = tree.nodeData(asm_output).opt_node_and_token; 1618 return if (data[0].unwrap()) |output_node| 1619 tree.nodeToSpan(output_node) 1620 else 1621 // token points to the ')' 1622 tree.tokenToSpan(data[1] - 1); 1623 }, 1624 .asm_clobbers => |offset| { 1625 const tree = try src_loc.file_scope.getTree(zcu); 1626 const node = offset.toAbsolute(src_loc.base_node); 1627 const full = tree.fullAsm(node).?; 1628 return tree.nodeToSpan(full.ast.clobbers.unwrap().?); // this should only be reachable if the clobbers are written in the source 1629 }, 1630 .for_input => |for_input| { 1631 const tree = try src_loc.file_scope.getTree(zcu); 1632 const node = for_input.for_node_offset.toAbsolute(src_loc.base_node); 1633 const for_full = tree.fullFor(node).?; 1634 const src_node = for_full.ast.inputs[for_input.input_index]; 1635 return tree.nodeToSpan(src_node); 1636 }, 1637 .for_capture_from_input => |node_off| { 1638 const tree = try src_loc.file_scope.getTree(zcu); 1639 const input_node = node_off.toAbsolute(src_loc.base_node); 1640 // We have to actually linear scan the whole AST to find the for loop 1641 // that contains this input. 1642 const node_tags = tree.nodes.items(.tag); 1643 for (node_tags, 0..) |node_tag, node_usize| { 1644 const node: Ast.Node.Index = @fromBackingInt(@intCast(node_usize)); 1645 switch (node_tag) { 1646 .for_simple, .@"for" => { 1647 const for_full = tree.fullFor(node).?; 1648 for (for_full.ast.inputs, 0..) |input, input_index| { 1649 if (input_node == input) { 1650 var count = input_index; 1651 var tok = for_full.payload_token; 1652 while (true) { 1653 switch (tree.tokenTag(tok)) { 1654 .comma => { 1655 count -= 1; 1656 tok += 1; 1657 }, 1658 .identifier => { 1659 if (count == 0) 1660 return tree.tokensToSpan(tok, tok + 1, tok); 1661 tok += 1; 1662 }, 1663 .asterisk => { 1664 if (count == 0) 1665 return tree.tokensToSpan(tok, tok + 2, tok); 1666 tok += 1; 1667 }, 1668 else => unreachable, 1669 } 1670 } 1671 } 1672 } 1673 }, 1674 else => continue, 1675 } 1676 } else unreachable; 1677 }, 1678 .call_arg => |call_arg| { 1679 const tree = try src_loc.file_scope.getTree(zcu); 1680 const node = call_arg.call_node_offset.toAbsolute(src_loc.base_node); 1681 var buf: [2]Ast.Node.Index = undefined; 1682 const call_full = tree.fullCall(buf[0..1], node) orelse { 1683 assert(tree.nodeTag(node) == .builtin_call); 1684 const call_args_node: Ast.Node.Index = @fromBackingInt(@intCast(tree.extra_data[@backingInt(tree.nodeData(node).extra_range.end) - 1])); 1685 switch (tree.nodeTag(call_args_node)) { 1686 .array_init_one, 1687 .array_init_one_comma, 1688 .array_init_dot_two, 1689 .array_init_dot_two_comma, 1690 .array_init_dot, 1691 .array_init_dot_comma, 1692 .array_init, 1693 .array_init_comma, 1694 => { 1695 const full = tree.fullArrayInit(&buf, call_args_node).?.ast.elements; 1696 return tree.nodeToSpan(full[call_arg.arg_index]); 1697 }, 1698 .struct_init_one, 1699 .struct_init_one_comma, 1700 .struct_init_dot_two, 1701 .struct_init_dot_two_comma, 1702 .struct_init_dot, 1703 .struct_init_dot_comma, 1704 .struct_init, 1705 .struct_init_comma, 1706 => { 1707 const full = tree.fullStructInit(&buf, call_args_node).?.ast.fields; 1708 return tree.nodeToSpan(full[call_arg.arg_index]); 1709 }, 1710 else => return tree.nodeToSpan(call_args_node), 1711 } 1712 }; 1713 return tree.nodeToSpan(call_full.ast.params[call_arg.arg_index]); 1714 }, 1715 .fn_proto_param, .fn_proto_param_type => |fn_proto_param| { 1716 const tree = try src_loc.file_scope.getTree(zcu); 1717 const node = fn_proto_param.fn_proto_node_offset.toAbsolute(src_loc.base_node); 1718 var buf: [1]Ast.Node.Index = undefined; 1719 const full = tree.fullFnProto(&buf, node).?; 1720 var it = full.iterate(tree); 1721 var i: usize = 0; 1722 while (it.next()) |param| : (i += 1) { 1723 if (i != fn_proto_param.param_index) continue; 1724 1725 switch (src_loc.lazy) { 1726 .fn_proto_param_type => if (param.anytype_ellipsis3) |tok| { 1727 return tree.tokenToSpan(tok); 1728 } else { 1729 return tree.nodeToSpan(param.type_expr.?); 1730 }, 1731 .fn_proto_param => if (param.anytype_ellipsis3) |tok| { 1732 const first = param.comptime_noalias orelse param.name_token orelse tok; 1733 return tree.tokensToSpan(first, tok, first); 1734 } else { 1735 const first = param.comptime_noalias orelse param.name_token orelse tree.firstToken(param.type_expr.?); 1736 return tree.tokensToSpan(first, tree.lastToken(param.type_expr.?), first); 1737 }, 1738 else => unreachable, 1739 } 1740 } 1741 unreachable; 1742 }, 1743 .node_offset_bin_lhs => |node_off| { 1744 const tree = try src_loc.file_scope.getTree(zcu); 1745 const node = node_off.toAbsolute(src_loc.base_node); 1746 return tree.nodeToSpan(tree.nodeData(node).node_and_node[0]); 1747 }, 1748 .node_offset_bin_rhs => |node_off| { 1749 const tree = try src_loc.file_scope.getTree(zcu); 1750 const node = node_off.toAbsolute(src_loc.base_node); 1751 return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]); 1752 }, 1753 .array_cat_lhs, .array_cat_rhs => |cat| { 1754 const tree = try src_loc.file_scope.getTree(zcu); 1755 const node = cat.array_cat_offset.toAbsolute(src_loc.base_node); 1756 const arr_node = if (src_loc.lazy == .array_cat_lhs) 1757 tree.nodeData(node).node_and_node[0] 1758 else 1759 tree.nodeData(node).node_and_node[1]; 1760 1761 var buf: [2]Ast.Node.Index = undefined; 1762 switch (tree.nodeTag(arr_node)) { 1763 .array_init_one, 1764 .array_init_one_comma, 1765 .array_init_dot_two, 1766 .array_init_dot_two_comma, 1767 .array_init_dot, 1768 .array_init_dot_comma, 1769 .array_init, 1770 .array_init_comma, 1771 => { 1772 const full = tree.fullArrayInit(&buf, arr_node).?.ast.elements; 1773 return tree.nodeToSpan(full[cat.elem_index]); 1774 }, 1775 else => return tree.nodeToSpan(arr_node), 1776 } 1777 }, 1778 1779 .node_offset_try_operand => |node_off| { 1780 const tree = try src_loc.file_scope.getTree(zcu); 1781 const node = node_off.toAbsolute(src_loc.base_node); 1782 return tree.nodeToSpan(tree.nodeData(node).node); 1783 }, 1784 1785 .node_offset_switch_operand => |node_off| { 1786 const tree = try src_loc.file_scope.getTree(zcu); 1787 const node = node_off.toAbsolute(src_loc.base_node); 1788 const condition, _ = tree.nodeData(node).node_and_extra; 1789 return tree.nodeToSpan(condition); 1790 }, 1791 1792 .node_offset_switch_else_prong => |node_off| { 1793 const tree = try src_loc.file_scope.getTree(zcu); 1794 const switch_node = node_off.toAbsolute(src_loc.base_node); 1795 _, const extra_index = tree.nodeData(switch_node).node_and_extra; 1796 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index); 1797 for (case_nodes) |case_node| { 1798 const case = tree.fullSwitchCase(case_node).?; 1799 if (case.ast.values.len == 0) { 1800 return tree.nodeToSpan(case_node); 1801 } 1802 } else unreachable; 1803 }, 1804 1805 .node_offset_switch_range => |node_off| { 1806 const tree = try src_loc.file_scope.getTree(zcu); 1807 const switch_node = node_off.toAbsolute(src_loc.base_node); 1808 _, const extra_index = tree.nodeData(switch_node).node_and_extra; 1809 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index); 1810 for (case_nodes) |case_node| { 1811 const case = tree.fullSwitchCase(case_node).?; 1812 for (case.ast.values) |item_node| { 1813 if (tree.nodeTag(item_node) == .switch_range) { 1814 return tree.nodeToSpan(item_node); 1815 } 1816 } 1817 } else unreachable; 1818 }, 1819 .node_offset_fn_type_align => |node_off| { 1820 const tree = try src_loc.file_scope.getTree(zcu); 1821 const node = node_off.toAbsolute(src_loc.base_node); 1822 var buf: [1]Ast.Node.Index = undefined; 1823 const full = tree.fullFnProto(&buf, node).?; 1824 return tree.nodeToSpan(full.ast.align_expr.unwrap() orelse node); 1825 }, 1826 .node_offset_fn_type_addrspace => |node_off| { 1827 const tree = try src_loc.file_scope.getTree(zcu); 1828 const node = node_off.toAbsolute(src_loc.base_node); 1829 var buf: [1]Ast.Node.Index = undefined; 1830 const full = tree.fullFnProto(&buf, node).?; 1831 return tree.nodeToSpan(full.ast.addrspace_expr.unwrap() orelse node); 1832 }, 1833 .node_offset_fn_type_section => |node_off| { 1834 const tree = try src_loc.file_scope.getTree(zcu); 1835 const node = node_off.toAbsolute(src_loc.base_node); 1836 var buf: [1]Ast.Node.Index = undefined; 1837 const full = tree.fullFnProto(&buf, node).?; 1838 return tree.nodeToSpan(full.ast.section_expr.unwrap() orelse node); 1839 }, 1840 .node_offset_fn_type_cc => |node_off| { 1841 const tree = try src_loc.file_scope.getTree(zcu); 1842 const node = node_off.toAbsolute(src_loc.base_node); 1843 var buf: [1]Ast.Node.Index = undefined; 1844 const full = tree.fullFnProto(&buf, node).?; 1845 return tree.nodeToSpan(full.ast.callconv_expr.unwrap() orelse node); 1846 }, 1847 1848 .node_offset_fn_type_ret_ty => |node_off| { 1849 const tree = try src_loc.file_scope.getTree(zcu); 1850 const node = node_off.toAbsolute(src_loc.base_node); 1851 var buf: [1]Ast.Node.Index = undefined; 1852 const full = tree.fullFnProto(&buf, node).?; 1853 return tree.nodeToSpan(full.ast.return_type.unwrap().?); 1854 }, 1855 .node_offset_param => |node_off| { 1856 const tree = try src_loc.file_scope.getTree(zcu); 1857 const node = node_off.toAbsolute(src_loc.base_node); 1858 1859 var first_tok = tree.firstToken(node); 1860 while (true) switch (tree.tokenTag(first_tok - 1)) { 1861 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1, 1862 else => break, 1863 }; 1864 return tree.tokensToSpan( 1865 first_tok, 1866 tree.lastToken(node), 1867 first_tok, 1868 ); 1869 }, 1870 .token_offset_param => |token_off| { 1871 const tree = try src_loc.file_scope.getTree(zcu); 1872 const main_token = tree.nodeMainToken(src_loc.base_node); 1873 const tok_index = token_off.toAbsolute(main_token); 1874 1875 var first_tok = tok_index; 1876 while (true) switch (tree.tokenTag(first_tok - 1)) { 1877 .colon, .identifier, .keyword_comptime, .keyword_noalias => first_tok -= 1, 1878 else => break, 1879 }; 1880 return tree.tokensToSpan( 1881 first_tok, 1882 tok_index, 1883 first_tok, 1884 ); 1885 }, 1886 1887 .node_offset_anyframe_type => |node_off| { 1888 const tree = try src_loc.file_scope.getTree(zcu); 1889 const parent_node = node_off.toAbsolute(src_loc.base_node); 1890 _, const child_type = tree.nodeData(parent_node).token_and_node; 1891 return tree.nodeToSpan(child_type); 1892 }, 1893 1894 .node_offset_lib_name => |node_off| { 1895 const tree = try src_loc.file_scope.getTree(zcu); 1896 const parent_node = node_off.toAbsolute(src_loc.base_node); 1897 var buf: [1]Ast.Node.Index = undefined; 1898 const full = tree.fullFnProto(&buf, parent_node).?; 1899 const tok_index = full.lib_name.?; 1900 const start = tree.tokenStart(tok_index); 1901 const end = start + @as(u32, @intCast(tree.tokenSlice(tok_index).len)); 1902 return Span{ .start = start, .end = end, .main = start }; 1903 }, 1904 1905 .node_offset_array_type_len => |node_off| { 1906 const tree = try src_loc.file_scope.getTree(zcu); 1907 const parent_node = node_off.toAbsolute(src_loc.base_node); 1908 1909 const full = tree.fullArrayType(parent_node).?; 1910 return tree.nodeToSpan(full.ast.elem_count); 1911 }, 1912 .node_offset_array_type_sentinel => |node_off| { 1913 const tree = try src_loc.file_scope.getTree(zcu); 1914 const parent_node = node_off.toAbsolute(src_loc.base_node); 1915 1916 const full = tree.fullArrayType(parent_node).?; 1917 return tree.nodeToSpan(full.ast.sentinel.unwrap().?); 1918 }, 1919 .node_offset_array_type_elem => |node_off| { 1920 const tree = try src_loc.file_scope.getTree(zcu); 1921 const parent_node = node_off.toAbsolute(src_loc.base_node); 1922 1923 const full = tree.fullArrayType(parent_node).?; 1924 return tree.nodeToSpan(full.ast.elem_type); 1925 }, 1926 .node_offset_un_op => |node_off| { 1927 const tree = try src_loc.file_scope.getTree(zcu); 1928 const node = node_off.toAbsolute(src_loc.base_node); 1929 return tree.nodeToSpan(tree.nodeData(node).node); 1930 }, 1931 .node_offset_ptr_elem => |node_off| { 1932 const tree = try src_loc.file_scope.getTree(zcu); 1933 const parent_node = node_off.toAbsolute(src_loc.base_node); 1934 1935 const full = tree.fullPtrType(parent_node).?; 1936 return tree.nodeToSpan(full.ast.child_type); 1937 }, 1938 .node_offset_ptr_sentinel => |node_off| { 1939 const tree = try src_loc.file_scope.getTree(zcu); 1940 const parent_node = node_off.toAbsolute(src_loc.base_node); 1941 1942 const full = tree.fullPtrType(parent_node).?; 1943 return tree.nodeToSpan(full.ast.sentinel.unwrap().?); 1944 }, 1945 .node_offset_ptr_align => |node_off| { 1946 const tree = try src_loc.file_scope.getTree(zcu); 1947 const parent_node = node_off.toAbsolute(src_loc.base_node); 1948 1949 const full = tree.fullPtrType(parent_node).?; 1950 return tree.nodeToSpan(full.ast.align_node.unwrap().?); 1951 }, 1952 .node_offset_ptr_addrspace => |node_off| { 1953 const tree = try src_loc.file_scope.getTree(zcu); 1954 const parent_node = node_off.toAbsolute(src_loc.base_node); 1955 1956 const full = tree.fullPtrType(parent_node).?; 1957 return tree.nodeToSpan(full.ast.addrspace_node.unwrap().?); 1958 }, 1959 .node_offset_ptr_bitoffset => |node_off| { 1960 const tree = try src_loc.file_scope.getTree(zcu); 1961 const parent_node = node_off.toAbsolute(src_loc.base_node); 1962 1963 const full = tree.fullPtrType(parent_node).?; 1964 return tree.nodeToSpan(full.ast.bit_range_start.unwrap().?); 1965 }, 1966 .node_offset_ptr_hostsize => |node_off| { 1967 const tree = try src_loc.file_scope.getTree(zcu); 1968 const parent_node = node_off.toAbsolute(src_loc.base_node); 1969 1970 const full = tree.fullPtrType(parent_node).?; 1971 return tree.nodeToSpan(full.ast.bit_range_end.unwrap().?); 1972 }, 1973 .node_offset_init_ty => |node_off| { 1974 const tree = try src_loc.file_scope.getTree(zcu); 1975 const parent_node = node_off.toAbsolute(src_loc.base_node); 1976 1977 var buf: [2]Ast.Node.Index = undefined; 1978 const type_expr = if (tree.fullArrayInit(&buf, parent_node)) |array_init| 1979 array_init.ast.type_expr.unwrap().? 1980 else 1981 tree.fullStructInit(&buf, parent_node).?.ast.type_expr.unwrap().?; 1982 return tree.nodeToSpan(type_expr); 1983 }, 1984 .node_offset_store_ptr => |node_off| { 1985 const tree = try src_loc.file_scope.getTree(zcu); 1986 const node = node_off.toAbsolute(src_loc.base_node); 1987 1988 switch (tree.nodeTag(node)) { 1989 .assign, 1990 .assign_mul, 1991 .assign_div, 1992 .assign_mod, 1993 .assign_add, 1994 .assign_sub, 1995 .assign_shl, 1996 .assign_shl_sat, 1997 .assign_shr, 1998 .assign_bit_and, 1999 .assign_bit_xor, 2000 .assign_bit_or, 2001 .assign_mul_wrap, 2002 .assign_add_wrap, 2003 .assign_sub_wrap, 2004 .assign_mul_sat, 2005 .assign_add_sat, 2006 .assign_sub_sat, 2007 => return tree.nodeToSpan(tree.nodeData(node).node_and_node[0]), 2008 else => return tree.nodeToSpan(node), 2009 } 2010 }, 2011 .node_offset_store_operand => |node_off| { 2012 const tree = try src_loc.file_scope.getTree(zcu); 2013 const node = node_off.toAbsolute(src_loc.base_node); 2014 2015 switch (tree.nodeTag(node)) { 2016 .assign, 2017 .assign_mul, 2018 .assign_div, 2019 .assign_mod, 2020 .assign_add, 2021 .assign_sub, 2022 .assign_shl, 2023 .assign_shl_sat, 2024 .assign_shr, 2025 .assign_bit_and, 2026 .assign_bit_xor, 2027 .assign_bit_or, 2028 .assign_mul_wrap, 2029 .assign_add_wrap, 2030 .assign_sub_wrap, 2031 .assign_mul_sat, 2032 .assign_add_sat, 2033 .assign_sub_sat, 2034 => return tree.nodeToSpan(tree.nodeData(node).node_and_node[1]), 2035 else => return tree.nodeToSpan(node), 2036 } 2037 }, 2038 .node_offset_return_operand => |node_off| { 2039 const tree = try src_loc.file_scope.getTree(zcu); 2040 const node = node_off.toAbsolute(src_loc.base_node); 2041 if (tree.nodeTag(node) == .@"return") { 2042 if (tree.nodeData(node).opt_node.unwrap()) |lhs| { 2043 return tree.nodeToSpan(lhs); 2044 } 2045 } 2046 return tree.nodeToSpan(node); 2047 }, 2048 .container_arg => { 2049 const tree = try src_loc.file_scope.getTree(zcu); 2050 const node = src_loc.base_node; 2051 var buf: [2]Ast.Node.Index = undefined; 2052 if (tree.fullContainerDecl(&buf, node)) |container_decl| { 2053 const arg_node = container_decl.ast.arg.unwrap() orelse return tree.nodeToSpan(node); 2054 return tree.nodeToSpan(arg_node); 2055 } else if (tree.builtinCallParams(&buf, node)) |args| { 2056 // Builtin calls (`@Enum` etc) should use the first argument. 2057 return tree.nodeToSpan(if (args.len > 0) args[0] else node); 2058 } else { 2059 return tree.nodeToSpan(node); 2060 } 2061 }, 2062 .container_field_name, 2063 .container_field_value, 2064 .container_field_type, 2065 .container_field_align, 2066 => |field_idx| { 2067 const tree = try src_loc.file_scope.getTree(zcu); 2068 const node = src_loc.base_node; 2069 var buf: [2]Ast.Node.Index = undefined; 2070 const container_decl = tree.fullContainerDecl(&buf, node) orelse { 2071 // This could be a reification builtin. These are the args we care about: 2072 // * `@Enum(_, _, names, values)` 2073 // * `@Struct(_, _, names, types, values_and_aligns)` 2074 // * `@Union(_, _, names, types, aligns)` 2075 if (tree.builtinCallParams(&buf, node)) |args| { 2076 const builtin_name = tree.tokenSlice(tree.firstToken(node)); 2077 const arg_index: ?u3 = if (std.mem.eql(u8, builtin_name, "@Enum")) switch (src_loc.lazy) { 2078 .container_field_name => 2, 2079 .container_field_value => 3, 2080 .container_field_type => null, 2081 .container_field_align => null, 2082 else => unreachable, 2083 } else if (std.mem.eql(u8, builtin_name, "@Struct")) switch (src_loc.lazy) { 2084 .container_field_name => 2, 2085 .container_field_value => 4, 2086 .container_field_type => 3, 2087 .container_field_align => 4, 2088 else => unreachable, 2089 } else if (std.mem.eql(u8, builtin_name, "@Union")) switch (src_loc.lazy) { 2090 .container_field_name => 2, 2091 .container_field_value => 4, 2092 .container_field_type => 3, 2093 .container_field_align => null, 2094 else => unreachable, 2095 } else null; 2096 if (arg_index) |i| { 2097 if (args.len >= i) return tree.nodeToSpan(args[i]); 2098 } 2099 } 2100 return tree.nodeToSpan(node); 2101 }; 2102 2103 var cur_field_idx: usize = 0; 2104 for (container_decl.ast.members) |member_node| { 2105 const field = tree.fullContainerField(member_node) orelse continue; 2106 if (cur_field_idx < field_idx) { 2107 cur_field_idx += 1; 2108 continue; 2109 } 2110 const field_component_node = switch (src_loc.lazy) { 2111 .container_field_name => .none, 2112 .container_field_value => field.ast.value_expr, 2113 .container_field_type => field.ast.type_expr, 2114 .container_field_align => field.ast.align_expr, 2115 else => unreachable, 2116 }; 2117 if (field_component_node.unwrap()) |component_node| { 2118 return tree.nodeToSpan(component_node); 2119 } else { 2120 return tree.tokenToSpan(field.ast.main_token); 2121 } 2122 } else unreachable; 2123 }, 2124 .tuple_field_type, .tuple_field_init => |field_info| { 2125 const tree = try src_loc.file_scope.getTree(zcu); 2126 const node = field_info.tuple_decl_node_offset.toAbsolute(src_loc.base_node); 2127 var buf: [2]Ast.Node.Index = undefined; 2128 const container_decl = tree.fullContainerDecl(&buf, node) orelse 2129 return tree.nodeToSpan(node); 2130 2131 const field = tree.fullContainerField(container_decl.ast.members[field_info.elem_index]).?; 2132 return tree.nodeToSpan(switch (src_loc.lazy) { 2133 .tuple_field_type => field.ast.type_expr.unwrap().?, 2134 .tuple_field_init => field.ast.value_expr.unwrap().?, 2135 else => unreachable, 2136 }); 2137 }, 2138 .init_elem => |init_elem| { 2139 const tree = try src_loc.file_scope.getTree(zcu); 2140 const init_node = init_elem.init_node_offset.toAbsolute(src_loc.base_node); 2141 var buf: [2]Ast.Node.Index = undefined; 2142 if (tree.fullArrayInit(&buf, init_node)) |full| { 2143 const elem_node = full.ast.elements[init_elem.elem_index]; 2144 return tree.nodeToSpan(elem_node); 2145 } else if (tree.fullStructInit(&buf, init_node)) |full| { 2146 const field_node = full.ast.fields[init_elem.elem_index]; 2147 return tree.tokensToSpan( 2148 tree.firstToken(field_node) - 3, 2149 tree.lastToken(field_node), 2150 tree.nodeMainToken(field_node) - 2, 2151 ); 2152 } else unreachable; 2153 }, 2154 .init_field_name, 2155 .init_field_linkage, 2156 .init_field_section, 2157 .init_field_visibility, 2158 .init_field_rw, 2159 .init_field_locality, 2160 .init_field_cache, 2161 .init_field_library, 2162 .init_field_thread_local, 2163 .init_field_dll_import, 2164 .init_field_relocation, 2165 .init_field_decoration, 2166 => |builtin_call_node| { 2167 const wanted = switch (src_loc.lazy) { 2168 .init_field_name => "name", 2169 .init_field_linkage => "linkage", 2170 .init_field_section => "section", 2171 .init_field_visibility => "visibility", 2172 .init_field_rw => "rw", 2173 .init_field_locality => "locality", 2174 .init_field_cache => "cache", 2175 .init_field_library => "library", 2176 .init_field_thread_local => "thread_local", 2177 .init_field_dll_import => "dll_import", 2178 .init_field_relocation => "relocation", 2179 .init_field_decoration => "decoration", 2180 else => unreachable, 2181 }; 2182 const tree = try src_loc.file_scope.getTree(zcu); 2183 const node = builtin_call_node.toAbsolute(src_loc.base_node); 2184 var builtin_buf: [2]Ast.Node.Index = undefined; 2185 const args = tree.builtinCallParams(&builtin_buf, node).?; 2186 const arg_node = args[1]; 2187 var buf: [2]Ast.Node.Index = undefined; 2188 const full = tree.fullStructInit(&buf, arg_node) orelse 2189 return tree.nodeToSpan(arg_node); 2190 for (full.ast.fields) |field_node| { 2191 // . IDENTIFIER = field_node 2192 const name_token = tree.firstToken(field_node) - 2; 2193 const name = tree.tokenSlice(name_token); 2194 if (std.mem.eql(u8, name, wanted)) { 2195 return tree.tokensToSpan( 2196 name_token - 1, 2197 tree.lastToken(field_node), 2198 tree.nodeMainToken(field_node) - 2, 2199 ); 2200 } 2201 } 2202 return tree.nodeToSpan(arg_node); 2203 }, 2204 .switch_case_item, 2205 .switch_case_item_range_first, 2206 .switch_case_item_range_last, 2207 .switch_capture, 2208 .switch_tag_capture, 2209 => { 2210 const switch_node_offset, const want_case_idx = switch (src_loc.lazy) { 2211 .switch_case_item, 2212 .switch_case_item_range_first, 2213 .switch_case_item_range_last, 2214 => |x| .{ x.switch_node_offset, x.case_idx }, 2215 .switch_capture, 2216 .switch_tag_capture, 2217 => |x| .{ x.switch_node_offset, x.case_idx }, 2218 else => unreachable, 2219 }; 2220 2221 const tree = try src_loc.file_scope.getTree(zcu); 2222 const switch_node = switch_node_offset.toAbsolute(src_loc.base_node); 2223 _, const extra_index = tree.nodeData(switch_node).node_and_extra; 2224 const case_nodes = tree.extraDataSlice(tree.extraData(extra_index, Ast.Node.SubRange), Ast.Node.Index); 2225 2226 var multi_i: u32 = 0; 2227 var scalar_i: u32 = 0; 2228 const case: Ast.full.SwitchCase = case: for (case_nodes) |case_node| { 2229 const case = tree.fullSwitchCase(case_node).?; 2230 if (case.ast.values.len == 0) { 2231 if (want_case_idx == Zir.UnwrappedSwitchBlock.Case.Index.@"else") { 2232 break :case case; 2233 } 2234 continue :case; 2235 } 2236 2237 const is_multi = case.ast.values.len != 1 or 2238 tree.nodeTag(case.ast.values[0]) == .switch_range; 2239 2240 switch (want_case_idx.kind) { 2241 .scalar => if (!is_multi and want_case_idx.value == scalar_i) 2242 break :case case, 2243 .multi => if (is_multi and want_case_idx.value == multi_i) 2244 break :case case, 2245 } 2246 2247 if (is_multi) { 2248 multi_i += 1; 2249 } else { 2250 scalar_i += 1; 2251 } 2252 } else unreachable; 2253 2254 const want_item_idx = switch (src_loc.lazy) { 2255 .switch_case_item, 2256 .switch_case_item_range_first, 2257 .switch_case_item_range_last, 2258 => |x| item_idx: { 2259 assert(want_case_idx != Zir.UnwrappedSwitchBlock.Case.Index.@"else"); 2260 break :item_idx x.item_idx; 2261 }, 2262 .switch_capture, .switch_tag_capture => { 2263 const start = switch (src_loc.lazy) { 2264 .switch_capture => case.payload_token.?, 2265 .switch_tag_capture => tok: { 2266 var tok = case.payload_token.?; 2267 if (tree.tokenTag(tok) == .asterisk) tok += 1; 2268 tok = tok + 2; // skip over comma 2269 break :tok tok; 2270 }, 2271 else => unreachable, 2272 }; 2273 const end = switch (tree.tokenTag(start)) { 2274 .asterisk => start + 1, 2275 else => start, 2276 }; 2277 return tree.tokensToSpan(start, end, start); 2278 }, 2279 else => unreachable, 2280 }; 2281 2282 switch (want_item_idx.kind) { 2283 .single => { 2284 var item_i: u32 = 0; 2285 for (case.ast.values) |item_node| { 2286 if (tree.nodeTag(item_node) == .switch_range) { 2287 continue; 2288 } 2289 if (item_i != want_item_idx.value) { 2290 item_i += 1; 2291 continue; 2292 } 2293 return tree.nodeToSpan(item_node); 2294 } else unreachable; 2295 }, 2296 .range => { 2297 var range_i: u32 = 0; 2298 for (case.ast.values) |item_node| { 2299 if (tree.nodeTag(item_node) != .switch_range) { 2300 continue; 2301 } 2302 if (range_i != want_item_idx.value) { 2303 range_i += 1; 2304 continue; 2305 } 2306 const first, const last = tree.nodeData(item_node).node_and_node; 2307 return switch (src_loc.lazy) { 2308 .switch_case_item => tree.nodeToSpan(item_node), 2309 .switch_case_item_range_first => tree.nodeToSpan(first), 2310 .switch_case_item_range_last => tree.nodeToSpan(last), 2311 else => unreachable, 2312 }; 2313 } else unreachable; 2314 }, 2315 } 2316 }, 2317 .func_decl_param_comptime => |param_idx| { 2318 const tree = try src_loc.file_scope.getTree(zcu); 2319 var buf: [1]Ast.Node.Index = undefined; 2320 const full = tree.fullFnProto(&buf, src_loc.base_node).?; 2321 var param_it = full.iterate(tree); 2322 for (0..param_idx) |_| assert(param_it.next() != null); 2323 const param = param_it.next().?; 2324 return tree.tokenToSpan(param.comptime_noalias.?); 2325 }, 2326 .func_decl_param_ty => |param_idx| { 2327 const tree = try src_loc.file_scope.getTree(zcu); 2328 var buf: [1]Ast.Node.Index = undefined; 2329 const full = tree.fullFnProto(&buf, src_loc.base_node).?; 2330 var param_it = full.iterate(tree); 2331 for (0..param_idx) |_| assert(param_it.next() != null); 2332 const param = param_it.next().?; 2333 if (param.anytype_ellipsis3) |tok| { 2334 return tree.tokenToSpan(tok); 2335 } else { 2336 return tree.nodeToSpan(param.type_expr.?); 2337 } 2338 }, 2339 } 2340 } 2341 }; 2342 2343 pub const LazySrcLoc = struct { 2344 /// This instruction provides the source node locations are resolved relative to. 2345 /// It is a `declaration`, `struct_decl`, `union_decl`, `enum_decl`, or `opaque_decl`. 2346 /// This must be valid even if `relative` is an absolute value, since it is required to 2347 /// determine the file which the `LazySrcLoc` refers to. 2348 base_node_inst: InternPool.TrackedInst.Index, 2349 /// This field determines the source location relative to `base_node_inst`. 2350 offset: Offset, 2351 2352 pub const Offset = union(enum) { 2353 /// When this tag is set, the code that constructed this `LazySrcLoc` is asserting 2354 /// that all code paths which would need to resolve the source location are 2355 /// unreachable. If you are debugging this tag incorrectly being this value, 2356 /// look into using reverse-continue with a memory watchpoint to see where the 2357 /// value is being set to this tag. 2358 /// `base_node_inst` is unused. 2359 unneeded, 2360 /// The source location points to a byte offset within a source file, 2361 /// offset from 0. The source file is determined contextually. 2362 byte_abs: u32, 2363 /// The source location points to a token within a source file, 2364 /// offset from 0. The source file is determined contextually. 2365 token_abs: Ast.TokenIndex, 2366 /// The source location points to an AST node within a source file, 2367 /// offset from 0. The source file is determined contextually. 2368 node_abs: Ast.Node.Index, 2369 /// The source location points to a byte offset within a source file, 2370 /// offset from the byte offset of the base node within the file. 2371 byte_offset: u32, 2372 /// This data is the offset into the token list from the base node's first token. 2373 token_offset: Ast.TokenOffset, 2374 /// The source location points to an AST node, which is this value offset 2375 /// from its containing base node AST index. 2376 node_offset: TracedOffset, 2377 /// The source location points to the main token of an AST node, found 2378 /// by taking this AST node index offset from the containing base node. 2379 node_offset_main_token: Ast.Node.Offset, 2380 /// The source location points to the beginning of a struct initializer. 2381 node_offset_initializer: Ast.Node.Offset, 2382 /// The source location points to a variable declaration type expression, 2383 /// found by taking this AST node index offset from the containing 2384 /// base node, which points to a variable declaration AST node. Next, navigate 2385 /// to the type expression. 2386 node_offset_var_decl_ty: Ast.Node.Offset, 2387 /// The source location points to the alignment expression of a var decl. 2388 node_offset_var_decl_align: Ast.Node.Offset, 2389 /// The source location points to the linksection expression of a var decl. 2390 node_offset_var_decl_section: Ast.Node.Offset, 2391 /// The source location points to the addrspace expression of a var decl. 2392 node_offset_var_decl_addrspace: Ast.Node.Offset, 2393 /// The source location points to the initializer of a var decl. 2394 node_offset_var_decl_init: Ast.Node.Offset, 2395 /// The source location points to the given argument of a builtin function call. 2396 /// `builtin_call_node` points to the builtin call. 2397 /// `arg_index` is the index of the argument which hte source location refers to. 2398 node_offset_builtin_call_arg: struct { 2399 builtin_call_node: Ast.Node.Offset, 2400 arg_index: u32, 2401 }, 2402 /// Like `node_offset_builtin_call_arg` but recurses through arbitrarily many calls 2403 /// to pointer cast builtins (taking the first argument of the most nested). 2404 node_offset_ptrcast_operand: Ast.Node.Offset, 2405 /// The source location points to the index expression of an array access 2406 /// expression, found by taking this AST node index offset from the containing 2407 /// base node, which points to an array access AST node. Next, navigate 2408 /// to the index expression. 2409 node_offset_array_access_index: Ast.Node.Offset, 2410 /// The source location points to the LHS of a slice expression 2411 /// expression, found by taking this AST node index offset from the containing 2412 /// base node, which points to a slice AST node. Next, navigate 2413 /// to the sentinel expression. 2414 node_offset_slice_ptr: Ast.Node.Offset, 2415 /// The source location points to start expression of a slice expression 2416 /// expression, found by taking this AST node index offset from the containing 2417 /// base node, which points to a slice AST node. Next, navigate 2418 /// to the sentinel expression. 2419 node_offset_slice_start: Ast.Node.Offset, 2420 /// The source location points to the end expression of a slice 2421 /// expression, found by taking this AST node index offset from the containing 2422 /// base node, which points to a slice AST node. Next, navigate 2423 /// to the sentinel expression. 2424 node_offset_slice_end: Ast.Node.Offset, 2425 /// The source location points to the sentinel expression of a slice 2426 /// expression, found by taking this AST node index offset from the containing 2427 /// base node, which points to a slice AST node. Next, navigate 2428 /// to the sentinel expression. 2429 node_offset_slice_sentinel: Ast.Node.Offset, 2430 /// The source location points to the callee expression of a function 2431 /// call expression, found by taking this AST node index offset from the containing 2432 /// base node, which points to a function call AST node. Next, navigate 2433 /// to the callee expression. 2434 node_offset_call_func: Ast.Node.Offset, 2435 /// The payload is offset from the containing base node. 2436 /// The source location points to the field name of: 2437 /// * a field access expression (`a.b`), or 2438 /// * the callee of a method call (`a.b()`) 2439 node_offset_field_name: Ast.Node.Offset, 2440 /// The payload is offset from the containing base node. 2441 /// The source location points to the field name of the operand ("b" node) 2442 /// of a field initialization expression (`.a = b`) 2443 node_offset_field_name_init: Ast.Node.Offset, 2444 /// The source location points to the pointer of a pointer deref expression, 2445 /// found by taking this AST node index offset from the containing 2446 /// base node, which points to a pointer deref AST node. Next, navigate 2447 /// to the pointer expression. 2448 node_offset_deref_ptr: Ast.Node.Offset, 2449 /// The source location points to the assembly source code of an inline assembly 2450 /// expression, found by taking this AST node index offset from the containing 2451 /// base node, which points to inline assembly AST node. Next, navigate 2452 /// to the asm template source code. 2453 node_offset_asm_source: Ast.Node.Offset, 2454 /// The source location points to the return type of an inline assembly 2455 /// expression, found by taking this AST node index offset from the containing 2456 /// base node, which points to inline assembly AST node. Next, navigate 2457 /// to the return type expression. 2458 node_offset_asm_ret_ty: Ast.Node.Offset, 2459 /// The source location points to the condition expression of an if 2460 /// expression, found by taking this AST node index offset from the containing 2461 /// base node, which points to an if expression AST node. Next, navigate 2462 /// to the condition expression. 2463 node_offset_if_cond: Ast.Node.Offset, 2464 /// The source location points to a binary expression, such as `a + b`, found 2465 /// by taking this AST node index offset from the containing base node. 2466 node_offset_bin_op: Ast.Node.Offset, 2467 /// The source location points to the LHS of a binary expression, found 2468 /// by taking this AST node index offset from the containing base node, 2469 /// which points to a binary expression AST node. Next, navigate to the LHS. 2470 node_offset_bin_lhs: Ast.Node.Offset, 2471 /// The source location points to the RHS of a binary expression, found 2472 /// by taking this AST node index offset from the containing base node, 2473 /// which points to a binary expression AST node. Next, navigate to the RHS. 2474 node_offset_bin_rhs: Ast.Node.Offset, 2475 /// The source location points to the operand of a try expression, found 2476 /// by taking this AST node index offset from the containing base node, 2477 /// which points to a try expression AST node. Next, navigate to the 2478 /// operand expression. 2479 node_offset_try_operand: Ast.Node.Offset, 2480 /// The source location points to the operand of a switch expression, found 2481 /// by taking this AST node index offset from the containing base node, 2482 /// which points to a switch expression AST node. Next, navigate to the operand. 2483 node_offset_switch_operand: Ast.Node.Offset, 2484 /// The source location points to the else prong of a switch expression, found 2485 /// by taking this AST node index offset from the containing base node, 2486 /// which points to a switch expression AST node. Next, navigate to the else prong. 2487 node_offset_switch_else_prong: Ast.Node.Offset, 2488 /// The source location points to all the ranges of a switch expression, found 2489 /// by taking this AST node index offset from the containing base node, 2490 /// which points to a switch expression AST node. Next, navigate to any of the 2491 /// range nodes. The error applies to all of them. 2492 node_offset_switch_range: Ast.Node.Offset, 2493 /// The source location points to the align expr of a function type 2494 /// expression, found by taking this AST node index offset from the containing 2495 /// base node, which points to a function type AST node. Next, navigate to 2496 /// the calling convention node. 2497 node_offset_fn_type_align: Ast.Node.Offset, 2498 /// The source location points to the addrspace expr of a function type 2499 /// expression, found by taking this AST node index offset from the containing 2500 /// base node, which points to a function type AST node. Next, navigate to 2501 /// the calling convention node. 2502 node_offset_fn_type_addrspace: Ast.Node.Offset, 2503 /// The source location points to the linksection expr of a function type 2504 /// expression, found by taking this AST node index offset from the containing 2505 /// base node, which points to a function type AST node. Next, navigate to 2506 /// the calling convention node. 2507 node_offset_fn_type_section: Ast.Node.Offset, 2508 /// The source location points to the calling convention of a function type 2509 /// expression, found by taking this AST node index offset from the containing 2510 /// base node, which points to a function type AST node. Next, navigate to 2511 /// the calling convention node. 2512 node_offset_fn_type_cc: Ast.Node.Offset, 2513 /// The source location points to the return type of a function type 2514 /// expression, found by taking this AST node index offset from the containing 2515 /// base node, which points to a function type AST node. Next, navigate to 2516 /// the return type node. 2517 node_offset_fn_type_ret_ty: Ast.Node.Offset, 2518 node_offset_param: Ast.Node.Offset, 2519 token_offset_param: Ast.TokenOffset, 2520 /// The source location points to the type expression of an `anyframe->T` 2521 /// expression, found by taking this AST node index offset from the containing 2522 /// base node, which points to a `anyframe->T` expression AST node. Next, navigate 2523 /// to the type expression. 2524 node_offset_anyframe_type: Ast.Node.Offset, 2525 /// The source location points to the string literal of `extern "foo"`, found 2526 /// by taking this AST node index offset from the containing 2527 /// base node, which points to a function prototype or variable declaration 2528 /// expression AST node. Next, navigate to the string literal of the `extern "foo"`. 2529 node_offset_lib_name: Ast.Node.Offset, 2530 /// The source location points to the len expression of an `[N:S]T` 2531 /// expression, found by taking this AST node index offset from the containing 2532 /// base node, which points to an `[N:S]T` expression AST node. Next, navigate 2533 /// to the len expression. 2534 node_offset_array_type_len: Ast.Node.Offset, 2535 /// The source location points to the sentinel expression of an `[N:S]T` 2536 /// expression, found by taking this AST node index offset from the containing 2537 /// base node, which points to an `[N:S]T` expression AST node. Next, navigate 2538 /// to the sentinel expression. 2539 node_offset_array_type_sentinel: Ast.Node.Offset, 2540 /// The source location points to the elem expression of an `[N:S]T` 2541 /// expression, found by taking this AST node index offset from the containing 2542 /// base node, which points to an `[N:S]T` expression AST node. Next, navigate 2543 /// to the elem expression. 2544 node_offset_array_type_elem: Ast.Node.Offset, 2545 /// The source location points to the operand of an unary expression. 2546 node_offset_un_op: Ast.Node.Offset, 2547 /// The source location points to the elem type of a pointer. 2548 node_offset_ptr_elem: Ast.Node.Offset, 2549 /// The source location points to the sentinel of a pointer. 2550 node_offset_ptr_sentinel: Ast.Node.Offset, 2551 /// The source location points to the align expr of a pointer. 2552 node_offset_ptr_align: Ast.Node.Offset, 2553 /// The source location points to the addrspace expr of a pointer. 2554 node_offset_ptr_addrspace: Ast.Node.Offset, 2555 /// The source location points to the bit-offset of a pointer. 2556 node_offset_ptr_bitoffset: Ast.Node.Offset, 2557 /// The source location points to the host size of a pointer. 2558 node_offset_ptr_hostsize: Ast.Node.Offset, 2559 /// The source location points to the type of an array or struct initializer. 2560 node_offset_init_ty: Ast.Node.Offset, 2561 /// The source location points to the LHS of an assignment (or assign-op, e.g. `+=`). 2562 node_offset_store_ptr: Ast.Node.Offset, 2563 /// The source location points to the RHS of an assignment (or assign-op, e.g. `+=`). 2564 node_offset_store_operand: Ast.Node.Offset, 2565 /// The source location points to the operand of a `return` statement, or 2566 /// the `return` itself if there is no explicit operand. 2567 node_offset_return_operand: Ast.Node.Offset, 2568 /// The source location points to an assembly input 2569 asm_input: struct { 2570 /// Points to the assembly node 2571 offset: Ast.Node.Offset, 2572 input_index: u32, 2573 }, 2574 /// The source location points to an assembly output 2575 asm_output: struct { 2576 /// Points to the assembly node 2577 offset: Ast.Node.Offset, 2578 output_index: u32, 2579 }, 2580 /// Points to the assembly node 2581 asm_clobbers: Ast.Node.Offset, 2582 /// The source location points to a for loop input. 2583 for_input: struct { 2584 /// Points to the for loop AST node. 2585 for_node_offset: Ast.Node.Offset, 2586 /// Picks one of the inputs from the condition. 2587 input_index: u32, 2588 }, 2589 /// The source location points to one of the captures of a for loop, found 2590 /// by taking this AST node index offset from the containing 2591 /// base node, which points to one of the input nodes of a for loop. 2592 /// Next, navigate to the corresponding capture. 2593 for_capture_from_input: Ast.Node.Offset, 2594 /// The source location points to the argument node of a function call. 2595 call_arg: struct { 2596 /// Points to the function call AST node. 2597 call_node_offset: Ast.Node.Offset, 2598 /// The index of the argument the source location points to. 2599 arg_index: u32, 2600 }, 2601 fn_proto_param: FnProtoParam, 2602 fn_proto_param_type: FnProtoParam, 2603 array_cat_lhs: ArrayCat, 2604 array_cat_rhs: ArrayCat, 2605 /// The source location points to the backing or tag type expression of 2606 /// the container type declaration at the base node. 2607 /// 2608 /// For 'union(enum(T))', this points to 'T', not 'enum(T)'. 2609 container_arg, 2610 /// The source location points to the name of the field at the given index 2611 /// of the container type declaration at the base node. 2612 container_field_name: u32, 2613 /// Like `continer_field_name`, but points at the field's default value. 2614 container_field_value: u32, 2615 /// Like `continer_field_name`, but points at the field's type. 2616 container_field_type: u32, 2617 /// Like `continer_field_name`, but points at the field's alignment. 2618 container_field_align: u32, 2619 /// The source location points to the type of the field at the given index 2620 /// of the tuple type declaration at `tuple_decl_node_offset`. 2621 tuple_field_type: TupleField, 2622 /// The source location points to the default init of the field at the given index 2623 /// of the tuple type declaration at `tuple_decl_node_offset`. 2624 tuple_field_init: TupleField, 2625 /// The source location points to the given element/field of a struct or 2626 /// array initialization expression. 2627 init_elem: struct { 2628 /// Points to the AST node of the initialization expression. 2629 init_node_offset: Ast.Node.Offset, 2630 /// The index of the field/element the source location points to. 2631 elem_index: u32, 2632 }, 2633 // The following source locations are like `init_elem`, but refer to a 2634 // field with a specific name. If such a field is not given, the entire 2635 // initialization expression is used instead. 2636 // The `Ast.Node.Offset` points to the AST node of a builtin call, whose *second* 2637 // argument is the init expression. 2638 init_field_name: Ast.Node.Offset, 2639 init_field_linkage: Ast.Node.Offset, 2640 init_field_section: Ast.Node.Offset, 2641 init_field_visibility: Ast.Node.Offset, 2642 init_field_rw: Ast.Node.Offset, 2643 init_field_locality: Ast.Node.Offset, 2644 init_field_cache: Ast.Node.Offset, 2645 init_field_library: Ast.Node.Offset, 2646 init_field_thread_local: Ast.Node.Offset, 2647 init_field_dll_import: Ast.Node.Offset, 2648 init_field_relocation: Ast.Node.Offset, 2649 init_field_decoration: Ast.Node.Offset, 2650 /// The source location points to the value of an item in a specific 2651 /// case of a `switch`. 2652 switch_case_item: SwitchItem, 2653 /// The source location points to the "first" value of a range item in 2654 /// a specific case of a `switch`. 2655 switch_case_item_range_first: SwitchItem, 2656 /// The source location points to the "last" value of a range item in 2657 /// a specific case of a `switch`. 2658 switch_case_item_range_last: SwitchItem, 2659 /// The source location points to the main capture of a specific case of 2660 /// a `switch`. 2661 switch_capture: SwitchCapture, 2662 /// The source location points to the "tag" capture (second capture) of 2663 /// a specific case of a `switch`. 2664 switch_tag_capture: SwitchCapture, 2665 /// The source location points to the `comptime` token on the given comptime parameter, 2666 /// where the base node is a function declaration. The value is the parameter index. 2667 func_decl_param_comptime: u32, 2668 /// The source location points to the type annotation on the given function parameter, 2669 /// where the base node is a function declaration. The value is the parameter index. 2670 func_decl_param_ty: u32, 2671 2672 pub const FnProtoParam = struct { 2673 /// The offset of the function prototype AST node. 2674 fn_proto_node_offset: Ast.Node.Offset, 2675 /// The index of the parameter the source location points to. 2676 param_index: u32, 2677 }; 2678 2679 pub const SwitchItem = struct { 2680 /// The offset of the switch AST node. 2681 switch_node_offset: Ast.Node.Offset, 2682 /// The index of the case to point to within this switch. 2683 case_idx: Zir.UnwrappedSwitchBlock.Case.Index, 2684 /// The index of the item to point to within this case. 2685 item_idx: SwitchItem.Index, 2686 2687 pub const Index = packed struct(u32) { 2688 kind: enum(u1) { single, range }, 2689 value: u31, 2690 }; 2691 }; 2692 2693 pub const SwitchCapture = struct { 2694 /// The offset of the switch AST node. 2695 switch_node_offset: Ast.Node.Offset, 2696 /// The index of the case whose capture to point to. 2697 case_idx: Zir.UnwrappedSwitchBlock.Case.Index, 2698 }; 2699 2700 pub const ArrayCat = struct { 2701 /// Points to the array concat AST node. 2702 array_cat_offset: Ast.Node.Offset, 2703 /// The index of the element the source location points to. 2704 elem_index: u32, 2705 }; 2706 2707 pub const TupleField = struct { 2708 /// Points to the AST node of the tuple type decaration. 2709 tuple_decl_node_offset: Ast.Node.Offset, 2710 /// The index of the tuple field the source location points to. 2711 elem_index: u32, 2712 }; 2713 2714 pub const nodeOffset = if (TracedOffset.want_tracing) nodeOffsetDebug else nodeOffsetRelease; 2715 2716 noinline fn nodeOffsetDebug(node_offset: Ast.Node.Offset) Offset { 2717 var result: LazySrcLoc = .{ .node_offset = .{ .x = node_offset } }; 2718 result.node_offset.trace.addAddr(@returnAddress(), "init"); 2719 return result; 2720 } 2721 2722 fn nodeOffsetRelease(node_offset: Ast.Node.Offset) Offset { 2723 return .{ .node_offset = .{ .x = node_offset } }; 2724 } 2725 2726 /// This wraps a simple integer in debug builds so that later on we can find out 2727 /// where in semantic analysis the value got set. 2728 pub const TracedOffset = struct { 2729 x: Ast.Node.Offset, 2730 trace: std.debug.Trace = std.debug.Trace.init, 2731 2732 const want_tracing = false; 2733 }; 2734 }; 2735 2736 pub const unneeded: LazySrcLoc = .{ 2737 .base_node_inst = undefined, 2738 .offset = .unneeded, 2739 }; 2740 2741 /// Returns `null` if the ZIR instruction has been lost across incremental updates. 2742 pub fn resolveBaseNode(base_node_inst: InternPool.TrackedInst.Index, zcu: *Zcu) ?struct { *File, Ast.Node.Index } { 2743 comptime assert(Zir.inst_tracking_version == 0); 2744 2745 const ip = &zcu.intern_pool; 2746 const file_index, const zir_inst = inst: { 2747 const info = base_node_inst.resolveFull(ip) orelse return null; 2748 break :inst .{ info.file, info.inst }; 2749 }; 2750 const file = zcu.fileByIndex(file_index); 2751 2752 // If we're relative to .main_struct_inst, we know the ast node is the root and don't need to resolve the ZIR, 2753 // which may not exist e.g. in the case of errors in ZON files. 2754 if (zir_inst == .main_struct_inst) return .{ file, .root }; 2755 2756 // Otherwise, make sure ZIR is loaded. 2757 const zir = &file.zir.?; 2758 2759 const inst = zir.instructions.get(@backingInt(zir_inst)); 2760 const base_node: Ast.Node.Index = switch (inst.tag) { 2761 .declaration => inst.data.declaration.src_node, 2762 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.abs_node, 2763 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.abs_node, 2764 .extended => switch (inst.data.extended.opcode) { 2765 .struct_decl => zir.getStructDecl(zir_inst).src_node, 2766 .union_decl => zir.getUnionDecl(zir_inst).src_node, 2767 .enum_decl => zir.getEnumDecl(zir_inst).src_node, 2768 .opaque_decl => zir.getOpaqueDecl(zir_inst).src_node, 2769 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.node, 2770 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.node, 2771 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.node, 2772 .reify_spirv_type => zir.extraData(Zir.Inst.ReifySpirvType, inst.data.extended.operand).data.node, 2773 else => unreachable, 2774 }, 2775 else => unreachable, 2776 }; 2777 return .{ file, base_node }; 2778 } 2779 2780 /// Resolve the file and AST node of `base_node_inst` to get a resolved `SrcLoc`. 2781 /// The resulting `SrcLoc` should only be used ephemerally, as it is not correct across incremental updates. 2782 pub fn upgrade(lazy: LazySrcLoc, zcu: *Zcu) SrcLoc { 2783 return lazy.upgradeOrLost(zcu).?; 2784 } 2785 2786 /// Like `upgrade`, but returns `null` if the source location has been lost across incremental updates. 2787 pub fn upgradeOrLost(lazy: LazySrcLoc, zcu: *Zcu) ?SrcLoc { 2788 const file, const base_node: Ast.Node.Index = resolveBaseNode(lazy.base_node_inst, zcu) orelse return null; 2789 return .{ 2790 .file_scope = file, 2791 .base_node = base_node, 2792 .lazy = lazy.offset, 2793 }; 2794 } 2795 2796 pub fn order(lhs: LazySrcLoc, rhs: LazySrcLoc, zcu: *Zcu) std.math.Order { 2797 const lhs_resolved = lhs.upgradeOrLost(zcu) orelse { 2798 // LHS source location lost, so should never be referenced. Just sort it to the end. 2799 return .gt; 2800 }; 2801 const rhs_resolved = rhs.upgradeOrLost(zcu) orelse { 2802 // RHS source location lost, so should never be referenced. Just sort it to the end. 2803 return .lt; 2804 }; 2805 if (lhs_resolved.file_scope != rhs_resolved.file_scope) { 2806 const lhs_path = lhs_resolved.file_scope.path; 2807 const rhs_path = rhs_resolved.file_scope.path; 2808 return std.math.order(@backingInt(lhs_path.root), @backingInt(rhs_path.root)).differ() orelse 2809 std.mem.order(u8, lhs_path.sub_path, rhs_path.sub_path).differ().?; 2810 } 2811 const prev_prot = zcu.comp.io.swapCancelProtection(.blocked); 2812 defer _ = zcu.comp.io.swapCancelProtection(prev_prot); 2813 const lhs_span = lhs_resolved.span(zcu) catch |err| { 2814 assert(err != error.Canceled); // we're protected 2815 // Failed to read LHS, so we'll get a transient error. Just sort it to the end. 2816 return .gt; 2817 }; 2818 const rhs_span = rhs_resolved.span(zcu) catch |err| { 2819 assert(err != error.Canceled); // we're protected 2820 // Failed to read RHS, so we'll get a transient error. Just sort it to the end. 2821 return .lt; 2822 }; 2823 return std.math.order(lhs_span.main, rhs_span.main); 2824 } 2825 }; 2826 2827 pub const SemaError = error{ OutOfMemory, Canceled, AlreadyReported }; 2828 pub const CompileError = error{ 2829 OutOfMemory, 2830 /// The compilation update is no longer desired. 2831 Canceled, 2832 /// When this is returned, the compile error for the failure has already been recorded. 2833 AlreadyReported, 2834 /// In a comptime scope, a return instruction was encountered. This error is only seen when 2835 /// doing a comptime function call. 2836 ComptimeReturn, 2837 /// In a comptime scope, a break instruction was encountered. This error is only seen when 2838 /// evaluating a comptime block. 2839 ComptimeBreak, 2840 }; 2841 2842 pub fn init(zcu: *Zcu, gpa: Allocator, io: Io, thread_count: usize) !void { 2843 try zcu.intern_pool.init(gpa, io, thread_count); 2844 } 2845 2846 /// It is valid to not call this function before `deinit` in error paths. 2847 /// Requires the fields on `zcu.comp` to already be initialized. 2848 pub fn initAfterCompilation(zcu: *Zcu) void { 2849 zcu.initTracyPlots(); 2850 } 2851 2852 pub fn deinit(zcu: *Zcu) void { 2853 const comp = zcu.comp; 2854 const io = comp.io; 2855 const gpa = zcu.gpa; 2856 { 2857 if (zcu.llvm_object) |llvm_object| llvm_object.deinit(); 2858 2859 zcu.builtin_modules.deinit(gpa); 2860 zcu.module_roots.deinit(gpa); 2861 for (zcu.import_table.keys()) |file_index| { 2862 zcu.destroyFile(file_index); 2863 } 2864 zcu.import_table.deinit(gpa); 2865 zcu.alive_files.deinit(gpa); 2866 2867 for (zcu.embed_table.keys()) |embed_file| { 2868 embed_file.path.deinit(gpa); 2869 gpa.destroy(embed_file); 2870 } 2871 zcu.embed_table.deinit(gpa); 2872 2873 zcu.local_zir_cache.handle.close(io); 2874 zcu.global_zir_cache.handle.close(io); 2875 2876 for (zcu.failed_analysis.values()) |value| value.destroy(gpa); 2877 for (zcu.failed_codegen.values()) |value| value.destroy(gpa); 2878 for (zcu.failed_types.values()) |value| value.destroy(gpa); 2879 zcu.analysis_in_progress.deinit(gpa); 2880 zcu.failed_analysis.deinit(gpa); 2881 zcu.transitive_failed_analysis.deinit(gpa); 2882 zcu.dependency_loops.deinit(gpa); 2883 zcu.dependency_loop_nodes.deinit(gpa); 2884 zcu.failed_codegen.deinit(gpa); 2885 zcu.failed_types.deinit(gpa); 2886 2887 for (zcu.failed_files.values()) |value| { 2888 if (value) |msg| gpa.free(msg); 2889 } 2890 zcu.failed_files.deinit(gpa); 2891 zcu.failed_imports.deinit(gpa); 2892 2893 for (zcu.failed_exports.values()) |value| { 2894 value.destroy(gpa); 2895 } 2896 zcu.failed_exports.deinit(gpa); 2897 2898 for (zcu.cimport_errors.values()) |*errs| { 2899 errs.deinit(gpa); 2900 } 2901 zcu.cimport_errors.deinit(gpa); 2902 2903 zcu.compile_logs.deinit(gpa); 2904 zcu.compile_log_lines.deinit(gpa); 2905 zcu.free_compile_log_lines.deinit(gpa); 2906 2907 zcu.all_exports.deinit(gpa); 2908 zcu.free_exports.deinit(gpa); 2909 zcu.single_exports.deinit(gpa); 2910 zcu.multi_exports.deinit(gpa); 2911 2912 zcu.potentially_outdated.deinit(gpa); 2913 zcu.outdated.deinit(gpa); 2914 zcu.outdated_ready.funcs.deinit(gpa); 2915 zcu.outdated_ready.other.deinit(gpa); 2916 zcu.retryable_failures.deinit(gpa); 2917 2918 zcu.test_functions.deinit(gpa); 2919 2920 for (zcu.global_assembly.values()) |s| { 2921 gpa.free(s); 2922 } 2923 zcu.global_assembly.deinit(gpa); 2924 2925 zcu.reference_table.deinit(gpa); 2926 zcu.all_references.deinit(gpa); 2927 zcu.free_references.deinit(gpa); 2928 2929 zcu.inline_reference_frames.deinit(gpa); 2930 zcu.free_inline_reference_frames.deinit(gpa); 2931 2932 zcu.type_reference_table.deinit(gpa); 2933 zcu.all_type_references.deinit(gpa); 2934 zcu.free_type_references.deinit(gpa); 2935 2936 if (zcu.resolved_references) |*r| r.deinit(gpa); 2937 2938 if (comp.debugIncremental()) { 2939 zcu.incremental_debug_state.deinit(gpa); 2940 } 2941 } 2942 zcu.intern_pool.deinit(gpa, io); 2943 } 2944 2945 fn deinitFile(zcu: *Zcu, file_index: Zcu.File.Index) void { 2946 const gpa = zcu.gpa; 2947 const file = zcu.fileByIndex(file_index); 2948 log.debug("deinit File {f}", .{file.path.fmt(zcu.comp)}); 2949 file.path.deinit(gpa); 2950 file.unload(gpa); 2951 if (file.prev_zir) |prev_zir| { 2952 prev_zir.deinit(gpa); 2953 gpa.destroy(prev_zir); 2954 } 2955 file.* = undefined; 2956 } 2957 2958 fn destroyFile(zcu: *Zcu, file_index: Zcu.File.Index) void { 2959 const gpa = zcu.gpa; 2960 const file = zcu.fileByIndex(file_index); 2961 deinitFile(zcu, file_index); 2962 gpa.destroy(file); 2963 } 2964 2965 pub fn namespacePtr(zcu: *Zcu, index: Namespace.Index) *Namespace { 2966 return zcu.intern_pool.namespacePtr(index); 2967 } 2968 2969 pub fn namespacePtrUnwrap(zcu: *Zcu, index: Namespace.OptionalIndex) ?*Namespace { 2970 return zcu.namespacePtr(index.unwrap() orelse return null); 2971 } 2972 2973 // TODO https://github.com/ziglang/zig/issues/8643 2974 pub const data_has_safety_tag = @sizeOf(Zir.Inst.Data) != 8; 2975 pub const HackDataLayout = extern struct { 2976 data: [8]u8 align(@alignOf(Zir.Inst.Data)), 2977 safety_tag: u8, 2978 }; 2979 comptime { 2980 if (data_has_safety_tag) { 2981 assert(@sizeOf(HackDataLayout) == @sizeOf(Zir.Inst.Data)); 2982 } 2983 } 2984 2985 pub fn loadZirCache(gpa: Allocator, io: Io, cache_file: Io.File) !Zir { 2986 var buffer: [2000]u8 = undefined; 2987 var file_reader = cache_file.reader(io, &buffer); 2988 return result: { 2989 const header = file_reader.interface.takeStructPointer(Zir.Header) catch |err| break :result err; 2990 break :result loadZirCacheBody(gpa, header.*, &file_reader.interface); 2991 } catch |err| switch (err) { 2992 error.ReadFailed => return file_reader.err.?, 2993 else => |e| return e, 2994 }; 2995 } 2996 2997 pub fn loadZirCacheBody(gpa: Allocator, header: Zir.Header, cache_br: *Io.Reader) !Zir { 2998 var instructions: std.MultiArrayList(Zir.Inst) = .{}; 2999 errdefer instructions.deinit(gpa); 3000 3001 try instructions.setCapacity(gpa, header.instructions_len); 3002 instructions.len = header.instructions_len; 3003 3004 var zir: Zir = .{ 3005 .instructions = instructions.toOwnedSlice(), 3006 .string_bytes = &.{}, 3007 .extra = &.{}, 3008 }; 3009 errdefer zir.deinit(gpa); 3010 3011 zir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); 3012 zir.extra = try gpa.alloc(u32, header.extra_len); 3013 3014 const safety_buffer = if (data_has_safety_tag) 3015 try gpa.alloc([8]u8, header.instructions_len) 3016 else 3017 undefined; 3018 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3019 3020 var vecs = [_][]u8{ 3021 @ptrCast(zir.instructions.items(.tag)), 3022 if (data_has_safety_tag) 3023 @ptrCast(safety_buffer) 3024 else 3025 @ptrCast(zir.instructions.items(.data)), 3026 zir.string_bytes, 3027 @ptrCast(zir.extra), 3028 }; 3029 try cache_br.readVecAll(&vecs); 3030 if (data_has_safety_tag) { 3031 const tags = zir.instructions.items(.tag); 3032 for (zir.instructions.items(.data), 0..) |*data, i| { 3033 const union_tag = Zir.Inst.Tag.data_tags[@backingInt(tags[i])]; 3034 const as_struct = @as(*HackDataLayout, @ptrCast(data)); 3035 as_struct.* = .{ 3036 .safety_tag = @backingInt(union_tag), 3037 .data = safety_buffer[i], 3038 }; 3039 } 3040 } 3041 return zir; 3042 } 3043 3044 pub fn saveZirCache( 3045 gpa: Allocator, 3046 cache_file_writer: *Io.File.Writer, 3047 stat: Io.File.Stat, 3048 zir: *const Zir, 3049 ) (Io.File.Writer.Error || Allocator.Error)!void { 3050 const safety_buffer = if (data_has_safety_tag) 3051 try gpa.alloc([8]u8, zir.instructions.len) 3052 else 3053 undefined; 3054 defer if (data_has_safety_tag) gpa.free(safety_buffer); 3055 3056 if (data_has_safety_tag) { 3057 // The `Data` union has a safety tag but in the file format we store it without. 3058 for (zir.instructions.items(.data), 0..) |*data, i| { 3059 const as_struct: *const HackDataLayout = @ptrCast(data); 3060 safety_buffer[i] = as_struct.data; 3061 } 3062 } 3063 3064 const header: Zir.Header = .{ 3065 .instructions_len = @intCast(zir.instructions.len), 3066 .string_bytes_len = @intCast(zir.string_bytes.len), 3067 .extra_len = @intCast(zir.extra.len), 3068 3069 .stat_size = stat.size, 3070 .stat_inode = stat.inode, 3071 .stat_mtime = stat.mtime.toNanoseconds(), 3072 }; 3073 var vecs = [_][]const u8{ 3074 @ptrCast((&header)[0..1]), 3075 @ptrCast(zir.instructions.items(.tag)), 3076 if (data_has_safety_tag) 3077 @ptrCast(safety_buffer) 3078 else 3079 @ptrCast(zir.instructions.items(.data)), 3080 zir.string_bytes, 3081 @ptrCast(zir.extra), 3082 }; 3083 cache_file_writer.interface.writeVecAll(&vecs) catch |err| switch (err) { 3084 error.WriteFailed => return cache_file_writer.err.?, 3085 }; 3086 } 3087 3088 pub fn saveZoirCache(cache_file_writer: *Io.File.Writer, stat: Io.File.Stat, zoir: *const Zoir) Io.File.Writer.Error!void { 3089 const header: Zoir.Header = .{ 3090 .nodes_len = @intCast(zoir.nodes.len), 3091 .extra_len = @intCast(zoir.extra.len), 3092 .limbs_len = @intCast(zoir.limbs.len), 3093 .string_bytes_len = @intCast(zoir.string_bytes.len), 3094 .compile_errors_len = @intCast(zoir.compile_errors.len), 3095 .error_notes_len = @intCast(zoir.error_notes.len), 3096 3097 .stat_size = stat.size, 3098 .stat_inode = stat.inode, 3099 .stat_mtime = stat.mtime.toNanoseconds(), 3100 }; 3101 var vecs = [_][]const u8{ 3102 @ptrCast((&header)[0..1]), 3103 @ptrCast(zoir.nodes.items(.tag)), 3104 @ptrCast(zoir.nodes.items(.data)), 3105 @ptrCast(zoir.nodes.items(.ast_node)), 3106 @ptrCast(zoir.extra), 3107 @ptrCast(zoir.limbs), 3108 zoir.string_bytes, 3109 @ptrCast(zoir.compile_errors), 3110 @ptrCast(zoir.error_notes), 3111 }; 3112 cache_file_writer.interface.writeVecAll(&vecs) catch |err| switch (err) { 3113 error.WriteFailed => return cache_file_writer.err.?, 3114 }; 3115 } 3116 3117 pub fn loadZoirCacheBody(gpa: Allocator, header: Zoir.Header, cache_br: *Io.Reader) !Zoir { 3118 var zoir: Zoir = .{ 3119 .nodes = .empty, 3120 .extra = &.{}, 3121 .limbs = &.{}, 3122 .string_bytes = &.{}, 3123 .compile_errors = &.{}, 3124 .error_notes = &.{}, 3125 }; 3126 errdefer zoir.deinit(gpa); 3127 3128 zoir.nodes = nodes: { 3129 var nodes: std.MultiArrayList(Zoir.Node.Repr) = .empty; 3130 defer nodes.deinit(gpa); 3131 try nodes.setCapacity(gpa, header.nodes_len); 3132 nodes.len = header.nodes_len; 3133 break :nodes nodes.toOwnedSlice(); 3134 }; 3135 3136 zoir.extra = try gpa.alloc(u32, header.extra_len); 3137 zoir.limbs = try gpa.alloc(std.math.big.Limb, header.limbs_len); 3138 zoir.string_bytes = try gpa.alloc(u8, header.string_bytes_len); 3139 3140 zoir.compile_errors = try gpa.alloc(Zoir.CompileError, header.compile_errors_len); 3141 zoir.error_notes = try gpa.alloc(Zoir.CompileError.Note, header.error_notes_len); 3142 3143 var vecs = [_][]u8{ 3144 @ptrCast(zoir.nodes.items(.tag)), 3145 @ptrCast(zoir.nodes.items(.data)), 3146 @ptrCast(zoir.nodes.items(.ast_node)), 3147 @ptrCast(zoir.extra), 3148 @ptrCast(zoir.limbs), 3149 zoir.string_bytes, 3150 @ptrCast(zoir.compile_errors), 3151 @ptrCast(zoir.error_notes), 3152 }; 3153 try cache_br.readVecAll(&vecs); 3154 return zoir; 3155 } 3156 3157 pub fn markDependeeOutdated( 3158 zcu: *Zcu, 3159 /// When we are diffing ZIR and marking things as outdated, we won't yet have marked the dependencies as PO. 3160 /// However, when we discover during analysis that something was outdated, the `Dependee` was already 3161 /// marked as PO, so we need to decrement the PO dep count for each depender. 3162 marked_po: enum { not_marked_po, marked_po }, 3163 dependee: InternPool.Dependee, 3164 ) !void { 3165 const gpa = zcu.comp.gpa; 3166 deps_log.debug("outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); 3167 var it = zcu.intern_pool.dependencyIterator(dependee); 3168 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3169 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3170 while (it.next()) |depender| { 3171 if (zcu.outdated.getPtr(depender)) |po_dep_count| { 3172 switch (marked_po) { 3173 .not_marked_po => {}, 3174 .marked_po => { 3175 po_dep_count.* -= 1; 3176 deps_log.debug("outdated {f} => already outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); 3177 if (po_dep_count.* == 0) { 3178 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); 3179 switch (depender.unwrap()) { 3180 .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}), 3181 else => try zcu.outdated_ready.other.put(gpa, depender, {}), 3182 } 3183 } 3184 }, 3185 } 3186 continue; 3187 } 3188 const opt_po_entry = zcu.potentially_outdated.fetchSwapRemove(depender); 3189 const new_po_dep_count = switch (marked_po) { 3190 .not_marked_po => if (opt_po_entry) |e| e.value else 0, 3191 .marked_po => if (opt_po_entry) |e| e.value - 1 else { 3192 // This `AnalUnit` has already been re-analyzed this update, and registered a dependency 3193 // on this thing, but already has sufficiently up-to-date information. Nothing to do. 3194 continue; 3195 }, 3196 }; 3197 try zcu.outdated.putNoClobber( 3198 gpa, 3199 depender, 3200 new_po_dep_count, 3201 ); 3202 deps_log.debug("outdated {f} => new outdated {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), new_po_dep_count }); 3203 if (new_po_dep_count == 0) { 3204 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); 3205 switch (depender.unwrap()) { 3206 .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}), 3207 else => try zcu.outdated_ready.other.put(gpa, depender, {}), 3208 } 3209 } 3210 // If this is a Decl and was not previously PO, we must recursively 3211 // mark dependencies on its tyval as PO. 3212 if (opt_po_entry == null) { 3213 assert(marked_po == .not_marked_po); 3214 try zcu.markTransitiveDependersPotentiallyOutdated(depender); 3215 } 3216 } 3217 3218 zcu.updateTracyOutdatedPlots(); 3219 } 3220 3221 pub fn markPoDependeeUpToDate(zcu: *Zcu, dependee: InternPool.Dependee) !void { 3222 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3223 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3224 try markPoDependeeUpToDateInner(zcu, dependee); 3225 zcu.updateTracyOutdatedPlots(); 3226 } 3227 /// Assumes that `zcu.outdated_lock` is already held exclusively. 3228 fn markPoDependeeUpToDateInner(zcu: *Zcu, dependee: InternPool.Dependee) !void { 3229 const gpa = zcu.comp.gpa; 3230 deps_log.debug("up-to-date dependee: {f}", .{zcu.fmtDependee(dependee)}); 3231 var it = zcu.intern_pool.dependencyIterator(dependee); 3232 while (it.next()) |depender| { 3233 if (zcu.outdated.getPtr(depender)) |po_dep_count| { 3234 // This depender is already outdated, but it now has one 3235 // less PO dependency! 3236 po_dep_count.* -= 1; 3237 deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), po_dep_count.* }); 3238 if (po_dep_count.* == 0) { 3239 deps_log.debug("outdated ready: {f}", .{zcu.fmtAnalUnit(depender)}); 3240 switch (depender.unwrap()) { 3241 .func => |func| try zcu.outdated_ready.funcs.put(gpa, func, {}), 3242 else => try zcu.outdated_ready.other.put(gpa, depender, {}), 3243 } 3244 } 3245 continue; 3246 } 3247 // This depender is definitely at least PO, because this Decl was just analyzed 3248 // due to being outdated. 3249 const ptr = zcu.potentially_outdated.getPtr(depender) orelse { 3250 // This dependency has been registered during in-progress analysis, but the unit is 3251 // not in `potentially_outdated` because analysis is in-progress. Nothing to do. 3252 continue; 3253 }; 3254 if (ptr.* > 1) { 3255 ptr.* -= 1; 3256 deps_log.debug("up-to-date {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender), ptr.* }); 3257 continue; 3258 } 3259 3260 deps_log.debug("up-to-date {f} => {f} po_deps=0 (up-to-date)", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(depender) }); 3261 3262 // This dependency is no longer PO, i.e. is known to be up-to-date. 3263 assert(zcu.potentially_outdated.swapRemove(depender)); 3264 // If this is a Decl, we must recursively mark dependencies on its tyval 3265 // as no longer PO. 3266 switch (depender.unwrap()) { 3267 .@"comptime" => {}, 3268 .nav_val => |nav| try zcu.markPoDependeeUpToDateInner(.{ .nav_val = nav }), 3269 .nav_ty => |nav| try zcu.markPoDependeeUpToDateInner(.{ .nav_ty = nav }), 3270 .type_layout => |ty| try zcu.markPoDependeeUpToDateInner(.{ .type_layout = ty }), 3271 .struct_defaults => |ty| try zcu.markPoDependeeUpToDateInner(.{ .struct_defaults = ty }), 3272 .func => |func| try zcu.markPoDependeeUpToDateInner(.{ .func_ies = func }), 3273 .memoized_state => |stage| try zcu.markPoDependeeUpToDateInner(.{ .memoized_state = stage }), 3274 } 3275 } 3276 } 3277 3278 /// Given a AnalUnit which is newly outdated or PO, mark all AnalUnits which may 3279 /// in turn be PO, due to a dependency on the original AnalUnit's tyval or IES. 3280 /// 3281 /// Assumes that `zcu.outdated_lock` is already held exclusively. 3282 fn markTransitiveDependersPotentiallyOutdated(zcu: *Zcu, maybe_outdated: AnalUnit) Allocator.Error!void { 3283 const gpa = zcu.comp.gpa; 3284 const ip = &zcu.intern_pool; 3285 const dependee: InternPool.Dependee = switch (maybe_outdated.unwrap()) { 3286 .@"comptime" => return, // analysis of a comptime decl can't outdate any dependencies 3287 .nav_val => |nav| .{ .nav_val = nav }, 3288 .nav_ty => |nav| .{ .nav_ty = nav }, 3289 .type_layout => |ty| .{ .type_layout = ty }, 3290 .struct_defaults => |ty| .{ .struct_defaults = ty }, 3291 .func => |func_index| .{ .func_ies = func_index }, 3292 .memoized_state => |stage| .{ .memoized_state = stage }, 3293 }; 3294 deps_log.debug("potentially outdated dependee: {f}", .{zcu.fmtDependee(dependee)}); 3295 var it = ip.dependencyIterator(dependee); 3296 while (it.next()) |po| { 3297 if (zcu.outdated.getPtr(po)) |po_dep_count| { 3298 // This dependency is already outdated, but it now has one more PO dependency. 3299 if (po_dep_count.* == 0) { 3300 switch (po.unwrap()) { 3301 .func => |func| _ = zcu.outdated_ready.funcs.swapRemove(func), 3302 else => _ = zcu.outdated_ready.other.swapRemove(po), 3303 } 3304 } 3305 po_dep_count.* += 1; 3306 deps_log.debug("po {f} => {f} [outdated] po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), po_dep_count.* }); 3307 continue; 3308 } 3309 if (zcu.potentially_outdated.getPtr(po)) |n| { 3310 // There is now one more PO dependency. 3311 n.* += 1; 3312 deps_log.debug("po {f} => {f} po_deps={}", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po), n.* }); 3313 continue; 3314 } 3315 try zcu.potentially_outdated.putNoClobber(gpa, po, 1); 3316 deps_log.debug("po {f} => {f} po_deps=1", .{ zcu.fmtDependee(dependee), zcu.fmtAnalUnit(po) }); 3317 // This AnalUnit was not already PO, so we must recursively mark its dependers as also PO. 3318 try zcu.markTransitiveDependersPotentiallyOutdated(po); 3319 } 3320 } 3321 3322 /// Selects an outdated `AnalUnit` to analyze next. Called from the main semantic analysis loop when 3323 /// there is no work immediately queued. The unit is chosen such that it is unlikely to require any 3324 /// recursive analysis (all of its previously-marked dependencies are already up-to-date), because 3325 /// recursive analysis can cause over-analysis on incremental updates. 3326 pub fn findOutdatedToAnalyze(zcu: *Zcu) Allocator.Error!?AnalUnit { 3327 // We prioritize functions, because the sooner they get analyzed, the sooner they can be send to 3328 // the codegen backend and linker, which are usually running in parallel (so this can increase 3329 // parallelism). 3330 // TODO: perhaps we should also experiment with *avoiding* functions if the codegen/link queue 3331 // is backed up (for instance due to a very large function). That could help minimize blocking 3332 // on the main thread in `CodegenTaskPool.start` waiting for the linker to catch up. 3333 if (zcu.outdated_ready.funcs.count() > 0) { 3334 const unit: AnalUnit = .wrap(.{ .func = zcu.outdated_ready.funcs.keys()[0] }); 3335 log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)}); 3336 return unit; 3337 } 3338 3339 if (zcu.outdated_ready.other.count() > 0) { 3340 const unit = zcu.outdated_ready.other.keys()[0]; 3341 log.debug("findOutdatedToAnalyze: {f}", .{zcu.fmtAnalUnit(unit)}); 3342 return unit; 3343 } 3344 3345 // Usually, getting here means that everything is up-to-date, so there is no more work to do. We 3346 // will see that `zcu.outdated` and `zcu.potentially_outdated` are both empty. 3347 // 3348 // However, if a previous update had a dependency loop compile error, there is a cycle in the 3349 // dependency graph (which is usually acyclic), which can cause a scenario where no unit appears 3350 // to be ready, because they're all waiting for the next in the loop to be up-to-date. In that 3351 // case, we usually have to just bite the bullet and analyze one of them. An exception is if 3352 // `zcu.outdated` is empty but `zcu.potentially_outdated` is non-empty: in that case, the only 3353 // possible situation is a cycle where everything is actually up-to-date, so we can clear out 3354 // `zcu.potentially_outdated` and we are done. 3355 3356 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3357 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3358 3359 if (zcu.outdated.count() == 0) { 3360 // Everything is up-to-date. There could be lingering entries in `zcu.potentially_outdated` 3361 // from a dependency loop on a previous update. 3362 zcu.potentially_outdated.clearRetainingCapacity(); 3363 zcu.updateTracyOutdatedPlots(); 3364 log.debug("findOutdatedToAnalyze: all up-to-date", .{}); 3365 return null; 3366 } 3367 3368 const unit = zcu.outdated.keys()[0]; 3369 log.debug("findOutdatedToAnalyze: dependency loop affecting {d} units, selected {f}", .{ 3370 zcu.outdated.count(), 3371 zcu.fmtAnalUnit(unit), 3372 }); 3373 return unit; 3374 } 3375 3376 /// During an incremental update, before semantic analysis, call this to flush all values from 3377 /// `retryable_failures` and mark them as outdated so they get re-analyzed. 3378 pub fn flushRetryableFailures(zcu: *Zcu) !void { 3379 const comp = zcu.comp; 3380 const gpa = comp.gpa; 3381 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(comp.io); 3382 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(comp.io); 3383 for (zcu.retryable_failures.items) |depender| { 3384 if (zcu.outdated.contains(depender)) continue; 3385 if (zcu.potentially_outdated.fetchSwapRemove(depender)) |kv| { 3386 // This AnalUnit was already PO, but we now consider it outdated. 3387 // Any transitive dependencies are already marked PO. 3388 try zcu.outdated.put(gpa, depender, kv.value); 3389 continue; 3390 } 3391 // This AnalUnit was not marked PO, but is now outdated. Mark it as 3392 // such, then recursively mark transitive dependencies as PO. 3393 try zcu.outdated.put(gpa, depender, 0); 3394 try zcu.markTransitiveDependersPotentiallyOutdated(depender); 3395 } 3396 zcu.retryable_failures.clearRetainingCapacity(); 3397 zcu.updateTracyOutdatedPlots(); 3398 } 3399 3400 pub fn mapOldZirToNew( 3401 gpa: Allocator, 3402 old_zir: *const Zir, 3403 new_zir: *const Zir, 3404 inst_map: *std.AutoHashMapUnmanaged(Zir.Inst.Index, Zir.Inst.Index), 3405 ) Allocator.Error!void { 3406 // Contain ZIR indexes of namespace declaration instructions, e.g. struct_decl, union_decl, etc. 3407 // Not `declaration`, as this does not create a namespace. 3408 const MatchedZirDecl = struct { 3409 old_inst: Zir.Inst.Index, 3410 new_inst: Zir.Inst.Index, 3411 }; 3412 var pending_matched_type_decls: std.ArrayList(MatchedZirDecl) = .empty; 3413 defer pending_matched_type_decls.deinit(gpa); 3414 3415 // Used as temporary buffers for namespace declaration instructions 3416 var old_contents: Zir.DeclContents = .init; 3417 defer old_contents.deinit(gpa); 3418 var new_contents: Zir.DeclContents = .init; 3419 defer new_contents.deinit(gpa); 3420 3421 // Map the main struct inst to start off with. 3422 try pending_matched_type_decls.append(gpa, .{ 3423 .old_inst = .main_struct_inst, 3424 .new_inst = .main_struct_inst, 3425 }); 3426 3427 while (pending_matched_type_decls.pop()) |match_item| { 3428 // There are some properties of type declarations which cannot change across incremental 3429 // updates. If they have, we need to ignore this mapping. These properties are essentially 3430 // everything passed into `InternPool.getDeclaredStructType` (likewise for unions, enums, 3431 // and opaques). 3432 const old_tag = old_zir.instructions.items(.data)[@backingInt(match_item.old_inst)].extended.opcode; 3433 const new_tag = new_zir.instructions.items(.data)[@backingInt(match_item.new_inst)].extended.opcode; 3434 if (old_tag != new_tag) continue; 3435 switch (old_tag) { 3436 .struct_decl => { 3437 const old = old_zir.getStructDecl(match_item.old_inst); 3438 const new = new_zir.getStructDecl(match_item.new_inst); 3439 if (old.captures.len != new.captures.len) continue; 3440 if (old.field_names.len != new.field_names.len) continue; 3441 if (old.layout != new.layout) continue; 3442 const old_any_field_aligns = old.field_align_body_lens != null; 3443 const old_any_field_defaults = old.field_default_body_lens != null; 3444 const old_any_comptime_fields = old.field_comptime_bits != null; 3445 const old_explicit_backing_int = old.backing_int_type_body != null; 3446 const new_any_field_aligns = new.field_align_body_lens != null; 3447 const new_any_field_defaults = new.field_default_body_lens != null; 3448 const new_any_comptime_fields = new.field_comptime_bits != null; 3449 const new_explicit_backing_int = new.backing_int_type_body != null; 3450 if (old_any_field_aligns != new_any_field_aligns) continue; 3451 if (old_any_field_defaults != new_any_field_defaults) continue; 3452 if (old_any_comptime_fields != new_any_comptime_fields) continue; 3453 if (old_explicit_backing_int != new_explicit_backing_int) continue; 3454 }, 3455 .union_decl => { 3456 const old = old_zir.getUnionDecl(match_item.old_inst); 3457 const new = new_zir.getUnionDecl(match_item.new_inst); 3458 if (old.captures.len != new.captures.len) continue; 3459 if (old.field_names.len != new.field_names.len) continue; 3460 if (old.kind != new.kind) continue; 3461 const old_any_field_aligns = old.field_align_body_lens != null; 3462 const new_any_field_aligns = new.field_align_body_lens != null; 3463 if (old_any_field_aligns != new_any_field_aligns) continue; 3464 }, 3465 .enum_decl => { 3466 const old = old_zir.getEnumDecl(match_item.old_inst); 3467 const new = new_zir.getEnumDecl(match_item.new_inst); 3468 if (old.captures.len != new.captures.len) continue; 3469 if (old.field_names.len != new.field_names.len) continue; 3470 if (old.nonexhaustive != new.nonexhaustive) continue; 3471 const old_explicit_tag_type = old.tag_type_body != null; 3472 const new_explicit_tag_type = new.tag_type_body != null; 3473 if (old_explicit_tag_type != new_explicit_tag_type) continue; 3474 }, 3475 .opaque_decl => { 3476 const old = old_zir.getOpaqueDecl(match_item.old_inst); 3477 const new = new_zir.getOpaqueDecl(match_item.new_inst); 3478 if (old.captures.len != new.captures.len) continue; 3479 }, 3480 else => unreachable, 3481 } 3482 3483 // Match the container declaration itself 3484 try inst_map.put(gpa, match_item.old_inst, match_item.new_inst); 3485 3486 { 3487 // First, map the fields... 3488 try old_zir.findTrackableFields(gpa, &old_contents, match_item.old_inst); 3489 try new_zir.findTrackableFields(gpa, &new_contents, match_item.new_inst); 3490 3491 // This isn't a `.declaration`, so we shouldn't see a function declaration. 3492 assert(old_contents.func_decl == null); 3493 assert(new_contents.func_decl == null); 3494 3495 // We don't have any smart way of matching up these instructions, so we correlate them based on source order 3496 // in their respective arrays. 3497 3498 const num_type_decls = @min(old_contents.type_decls.items.len, new_contents.type_decls.items.len); 3499 try pending_matched_type_decls.ensureUnusedCapacity(gpa, @intCast(num_type_decls)); 3500 for ( 3501 old_contents.type_decls.items[0..num_type_decls], 3502 new_contents.type_decls.items[0..num_type_decls], 3503 ) |old_inst, new_inst| { 3504 pending_matched_type_decls.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); 3505 } 3506 3507 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); 3508 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other)); 3509 for ( 3510 old_contents.other.items[0..num_other], 3511 new_contents.other.items[0..num_other], 3512 ) |old_inst, new_inst| { 3513 // These instructions don't have declarations, so we just modify `inst_map` directly. 3514 inst_map.putAssumeCapacity(old_inst, new_inst); 3515 } 3516 } 3517 3518 // Maps decl name to `declaration` instruction. 3519 var named_decls: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; 3520 defer named_decls.deinit(gpa); 3521 // Maps test name to `declaration` instruction. 3522 var named_tests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; 3523 defer named_tests.deinit(gpa); 3524 // Maps test name to `declaration` instruction. 3525 var named_decltests: std.StringHashMapUnmanaged(Zir.Inst.Index) = .empty; 3526 defer named_decltests.deinit(gpa); 3527 // All unnamed tests, in order, for a best-effort match. 3528 var unnamed_tests: std.ArrayList(Zir.Inst.Index) = .empty; 3529 defer unnamed_tests.deinit(gpa); 3530 // All comptime declarations, in order, for a best-effort match. 3531 var comptime_decls: std.ArrayList(Zir.Inst.Index) = .empty; 3532 defer comptime_decls.deinit(gpa); 3533 3534 for (old_zir.typeDecls(match_item.old_inst)) |old_decl_inst| { 3535 const old_decl = old_zir.getDeclaration(old_decl_inst); 3536 switch (old_decl.kind) { 3537 .@"comptime" => try comptime_decls.append(gpa, old_decl_inst), 3538 .unnamed_test => try unnamed_tests.append(gpa, old_decl_inst), 3539 .@"test" => try named_tests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), 3540 .decltest => try named_decltests.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), 3541 .@"const", .@"var" => try named_decls.put(gpa, old_zir.nullTerminatedString(old_decl.name), old_decl_inst), 3542 } 3543 } 3544 3545 var unnamed_test_idx: u32 = 0; 3546 var comptime_decl_idx: u32 = 0; 3547 3548 for (new_zir.typeDecls(match_item.new_inst)) |new_decl_inst| { 3549 const new_decl = new_zir.getDeclaration(new_decl_inst); 3550 // Attempt to match this to a declaration in the old ZIR: 3551 // * For named declarations (`const`/`var`/`fn`), we match based on name. 3552 // * For named tests (`test "foo"`) and decltests (`test foo`), we also match based on name. 3553 // * For unnamed tests, we match based on order. 3554 // * For comptime blocks, we match based on order. 3555 // If we cannot match this declaration, we can't match anything nested inside of it either, so we just `continue`. 3556 const old_decl_inst = switch (new_decl.kind) { 3557 .@"comptime" => inst: { 3558 if (comptime_decl_idx == comptime_decls.items.len) continue; 3559 defer comptime_decl_idx += 1; 3560 break :inst comptime_decls.items[comptime_decl_idx]; 3561 }, 3562 .unnamed_test => inst: { 3563 if (unnamed_test_idx == unnamed_tests.items.len) continue; 3564 defer unnamed_test_idx += 1; 3565 break :inst unnamed_tests.items[unnamed_test_idx]; 3566 }, 3567 .@"test" => inst: { 3568 const name = new_zir.nullTerminatedString(new_decl.name); 3569 break :inst named_tests.get(name) orelse continue; 3570 }, 3571 .decltest => inst: { 3572 const name = new_zir.nullTerminatedString(new_decl.name); 3573 break :inst named_decltests.get(name) orelse continue; 3574 }, 3575 .@"const", .@"var" => inst: { 3576 const name = new_zir.nullTerminatedString(new_decl.name); 3577 break :inst named_decls.get(name) orelse continue; 3578 }, 3579 }; 3580 3581 // Match the `declaration` instruction 3582 try inst_map.put(gpa, old_decl_inst, new_decl_inst); 3583 3584 // Find trackable instructions within this declaration 3585 try old_zir.findTrackable(gpa, &old_contents, old_decl_inst); 3586 try new_zir.findTrackable(gpa, &new_contents, new_decl_inst); 3587 3588 // We don't have any smart way of matching up these instructions, so we correlate them based on source order 3589 // in their respective arrays. 3590 3591 const num_type_decls = @min(old_contents.type_decls.items.len, new_contents.type_decls.items.len); 3592 try pending_matched_type_decls.ensureUnusedCapacity(gpa, @intCast(num_type_decls)); 3593 for ( 3594 old_contents.type_decls.items[0..num_type_decls], 3595 new_contents.type_decls.items[0..num_type_decls], 3596 ) |old_inst, new_inst| { 3597 pending_matched_type_decls.appendAssumeCapacity(.{ .old_inst = old_inst, .new_inst = new_inst }); 3598 } 3599 3600 const num_other = @min(old_contents.other.items.len, new_contents.other.items.len); 3601 try inst_map.ensureUnusedCapacity(gpa, @intCast(num_other)); 3602 for ( 3603 old_contents.other.items[0..num_other], 3604 new_contents.other.items[0..num_other], 3605 ) |old_inst, new_inst| { 3606 // These instructions don't have declarations, so we just modify `inst_map` directly. 3607 inst_map.putAssumeCapacity(old_inst, new_inst); 3608 } 3609 3610 if (old_contents.func_decl) |old_func_inst| { 3611 if (new_contents.func_decl) |new_func_inst| { 3612 // There are no declarations on a function either, so again, we just directly add it to `inst_map`. 3613 try inst_map.put(gpa, old_func_inst, new_func_inst); 3614 } 3615 } 3616 } 3617 } 3618 } 3619 3620 /// Ensure this function's body is or will be analyzed and emitted. This should 3621 /// be called whenever a potential runtime call of a function is seen. 3622 /// 3623 /// The caller is responsible for ensuring the function decl itself is already 3624 /// analyzed, and for ensuring it can exist at runtime (see 3625 /// `Type.fnHasRuntimeBitsSema`). This function does *not* guarantee that the body 3626 /// will be analyzed when it returns: for that, see `PerThread.ensureFuncBodyUpToDate`. 3627 pub fn ensureFuncBodyAnalysisQueued(zcu: *Zcu, func: InternPool.Index) !void { 3628 const comp = zcu.comp; 3629 const gpa = comp.gpa; 3630 const io = comp.io; 3631 const ip = &zcu.intern_pool; 3632 assert(func == ip.unwrapCoercedFunc(func)); // analyze the body of the original function, not a coerced one 3633 if (ip.setWantRuntimeFnAnalysis(io, func)) { 3634 // This is the first reference to this function, so we must ensure it will be analyzed. 3635 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3636 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3637 try zcu.outdated.ensureUnusedCapacity(gpa, 1); 3638 try zcu.outdated_ready.funcs.ensureUnusedCapacity(gpa, 1); 3639 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .func = func }), 0); 3640 zcu.outdated_ready.funcs.putAssumeCapacityNoClobber(func, {}); 3641 zcu.updateTracyOutdatedPlots(); 3642 } 3643 } 3644 3645 pub fn ensureNavValAnalysisQueued(zcu: *Zcu, nav: InternPool.Nav.Index) !void { 3646 const comp = zcu.comp; 3647 const gpa = comp.gpa; 3648 const io = comp.io; 3649 const ip = &zcu.intern_pool; 3650 if (ip.setWantNavAnalysis(io, nav)) { 3651 // This is the first reference to this function, so we must ensure it will be analyzed. 3652 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(zcu.comp.io); 3653 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(zcu.comp.io); 3654 try zcu.outdated.ensureUnusedCapacity(gpa, 2); 3655 try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 2); 3656 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), 0); 3657 zcu.outdated.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), 0); 3658 zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_val = nav }), {}); 3659 zcu.outdated_ready.other.putAssumeCapacityNoClobber(.wrap(.{ .nav_ty = nav }), {}); 3660 zcu.updateTracyOutdatedPlots(); 3661 } 3662 } 3663 3664 /// Called when an `InternPool.ComptimeUnit` is first created to mark it as outdated so that it will 3665 /// be semantically analyzed. 3666 pub fn queueComptimeUnitAnalysis(zcu: *Zcu, cu: InternPool.ComptimeUnit.Id) Allocator.Error!void { 3667 const comp = zcu.comp; 3668 const gpa = comp.gpa; 3669 const io = comp.io; 3670 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); 3671 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(io); 3672 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(io); 3673 try zcu.outdated.ensureUnusedCapacity(gpa, 1); 3674 try zcu.outdated_ready.other.ensureUnusedCapacity(gpa, 1); 3675 zcu.outdated.putAssumeCapacityNoClobber(unit, 0); 3676 zcu.outdated_ready.other.putAssumeCapacityNoClobber(unit, {}); 3677 zcu.updateTracyOutdatedPlots(); 3678 } 3679 3680 /// If `unit` was marked as outdated or porentially outdated, clears that status and returns `true`. 3681 /// Otherwise, returns `false`. 3682 pub fn clearOutdatedState(zcu: *Zcu, unit: AnalUnit) bool { 3683 const io = zcu.comp.io; 3684 if (std.debug.runtime_safety) zcu.outdated_lock.lockUncancelable(io); 3685 defer if (std.debug.runtime_safety) zcu.outdated_lock.unlock(io); 3686 if (zcu.outdated.fetchSwapRemove(unit)) |kv| { 3687 const was_ready = switch (unit.unwrap()) { 3688 .func => |func| zcu.outdated_ready.funcs.swapRemove(func), 3689 else => zcu.outdated_ready.other.swapRemove(unit), 3690 }; 3691 if (kv.value == 0) { 3692 assert(was_ready); 3693 } else { 3694 assert(!was_ready); 3695 } 3696 zcu.updateTracyOutdatedPlots(); 3697 return true; 3698 } else if (zcu.potentially_outdated.swapRemove(unit)) { 3699 zcu.updateTracyOutdatedPlots(); 3700 return true; 3701 } else { 3702 return false; 3703 } 3704 } 3705 3706 /// This function takes a `*const Zcu` and `@constCast`s it so that it can be called from functions 3707 /// in `Type` which otherwise do not modify the `Zcu`. 3708 pub fn assertUpToDate(zcu: *const Zcu, unit: AnalUnit) void { 3709 if (!std.debug.runtime_safety) return; 3710 3711 const io = zcu.comp.io; 3712 3713 @constCast(zcu).outdated_lock.lockSharedUncancelable(io); 3714 defer @constCast(zcu).outdated_lock.unlockShared(io); 3715 3716 assert(!zcu.outdated.contains(unit)); 3717 assert(!zcu.potentially_outdated.contains(unit)); 3718 } 3719 3720 pub const ImportResult = struct { 3721 /// Whether `file` has been newly created; in other words, whether this is the first import of 3722 /// this file. This should only be `true` when importing files during AstGen. After that, all 3723 /// files should have already been discovered. 3724 is_new: bool, 3725 3726 /// `file.mod` is not populated by this function, so if `is_new`, then it is `undefined`. 3727 file: *Zcu.File, 3728 file_index: File.Index, 3729 3730 /// If this import was a simple file path, this is `null`; the imported file should exist within 3731 /// the importer's module. Otherwise, it's the module which the import resolved to. This module 3732 /// could match the module of `cur_file`, since a module can depend on itself. 3733 module: ?*Module, 3734 }; 3735 3736 /// Prepares `unit` for re-analysis by clearing all of the following state: 3737 /// * Compile errors associated with `unit` 3738 /// * Compile logs associated with `unit` 3739 /// * Exports performed by `unit` 3740 /// * Dependencies from `unit` on other things 3741 /// * References from `unit` to other units 3742 /// Delete all references in `reference_table` which are caused by `unit`, and all dependencies it 3743 /// has. Called in preparation for re-analysis, which will recreate references and dependencies. 3744 /// Re-analysis of the `AnalUnit` will cause appropriate references to be recreated. 3745 pub fn resetUnit(zcu: *Zcu, unit: AnalUnit) void { 3746 const gpa = zcu.comp.gpa; 3747 3748 if (!dev.env.supports(.incremental)) { 3749 // This is the first time `unit` is being analyzed, so there is no stale data to clear. 3750 return; 3751 } 3752 3753 // Compile errors 3754 if (zcu.failed_analysis.fetchSwapRemove(unit)) |kv| { 3755 kv.value.destroy(gpa); 3756 } else if (zcu.dependency_loop_nodes.swapRemove(unit)) { 3757 _ = zcu.dependency_loops.swapRemove(unit); 3758 _ = zcu.transitive_failed_analysis.swapRemove(unit); 3759 } else { 3760 _ = zcu.transitive_failed_analysis.swapRemove(unit); 3761 } 3762 3763 // Compile logs 3764 if (zcu.compile_logs.fetchSwapRemove(unit)) |kv| { 3765 var opt_line_idx = kv.value.first_line.toOptional(); 3766 while (opt_line_idx.unwrap()) |line_idx| { 3767 zcu.free_compile_log_lines.append(gpa, line_idx) catch { 3768 // This space will be reused eventually, so we need not propagate this error. 3769 // Just leak it for now, and let GC reclaim it later on. 3770 break; 3771 }; 3772 opt_line_idx = line_idx.get(zcu).next; 3773 } 3774 } 3775 3776 // Exports 3777 exports: { 3778 const base: u32, const len: u32 = index: { 3779 if (zcu.single_exports.fetchSwapRemove(unit)) |kv| { 3780 break :index .{ @backingInt(kv.value), 1 }; 3781 } 3782 if (zcu.multi_exports.fetchSwapRemove(unit)) |kv| { 3783 break :index .{ kv.value.index, kv.value.len }; 3784 } 3785 break :exports; 3786 }; 3787 for (base..base + len) |exp_index_usize| { 3788 const exp_index: Export.Index = @fromBackingInt(@intCast(exp_index_usize)); 3789 if (zcu.failed_exports.fetchSwapRemove(exp_index)) |failed_kv| { 3790 failed_kv.value.destroy(gpa); 3791 } 3792 } 3793 zcu.free_exports.ensureUnusedCapacity(gpa, len) catch { 3794 // This space will be reused eventually, so we need not propagate this error. 3795 // Just leak it for now, and let GC reclaim it later on. 3796 break :exports; 3797 }; 3798 for (base..base + len) |exp_index| { 3799 zcu.free_exports.appendAssumeCapacity(@fromBackingInt(@intCast(exp_index))); 3800 } 3801 } 3802 3803 // Dependencies 3804 zcu.intern_pool.removeDependenciesForDepender(gpa, unit); 3805 3806 // References 3807 zcu.clearCachedResolvedReferences(); 3808 unit_refs: { 3809 const kv = zcu.reference_table.fetchSwapRemove(unit) orelse break :unit_refs; 3810 var idx = kv.value; 3811 3812 while (idx != std.math.maxInt(u32)) { 3813 const ref = zcu.all_references.items[idx]; 3814 zcu.free_references.append(gpa, idx) catch { 3815 // This space will be reused eventually, so we need not propagate this error. 3816 // Just leak it for now, and let GC reclaim it later on. 3817 break :unit_refs; 3818 }; 3819 idx = ref.next; 3820 3821 var opt_inline_frame = ref.inline_frame; 3822 while (opt_inline_frame.unwrap()) |inline_frame| { 3823 // The same inline frame could be used multiple times by one unit. We need to 3824 // detect this case to avoid adding it to `free_inline_reference_frames` more 3825 // than once. We do that by setting `parent` to itself as a marker. 3826 if (inline_frame.ptr(zcu).parent == inline_frame.toOptional()) break; 3827 zcu.free_inline_reference_frames.append(gpa, inline_frame) catch { 3828 // This space will be reused eventually, so we need not propagate this error. 3829 // Just leak it for now, and let GC reclaim it later on. 3830 break :unit_refs; 3831 }; 3832 opt_inline_frame = inline_frame.ptr(zcu).parent; 3833 inline_frame.ptr(zcu).parent = inline_frame.toOptional(); // signal to code above 3834 } 3835 } 3836 } 3837 type_refs: { 3838 const kv = zcu.type_reference_table.fetchSwapRemove(unit) orelse break :type_refs; 3839 var idx = kv.value; 3840 3841 while (idx != std.math.maxInt(u32)) { 3842 zcu.free_type_references.append(gpa, idx) catch { 3843 // This space will be reused eventually, so we need not propagate this error. 3844 // Just leak it for now, and let GC reclaim it later on. 3845 break :type_refs; 3846 }; 3847 idx = zcu.all_type_references.items[idx].next; 3848 } 3849 } 3850 } 3851 3852 pub fn addInlineReferenceFrame(zcu: *Zcu, frame: InlineReferenceFrame) Allocator.Error!Zcu.InlineReferenceFrame.Index { 3853 const frame_idx: InlineReferenceFrame.Index = zcu.free_inline_reference_frames.pop() orelse idx: { 3854 _ = try zcu.inline_reference_frames.addOne(zcu.gpa); 3855 break :idx @fromBackingInt(@intCast(zcu.inline_reference_frames.items.len - 1)); 3856 }; 3857 frame_idx.ptr(zcu).* = frame; 3858 return frame_idx; 3859 } 3860 3861 pub fn addUnitReference( 3862 zcu: *Zcu, 3863 src_unit: AnalUnit, 3864 referenced_unit: AnalUnit, 3865 ref_src: LazySrcLoc, 3866 inline_frame: InlineReferenceFrame.Index.Optional, 3867 ) Allocator.Error!void { 3868 const gpa = zcu.gpa; 3869 3870 zcu.clearCachedResolvedReferences(); 3871 3872 try zcu.reference_table.ensureUnusedCapacity(gpa, 1); 3873 3874 const ref_idx = zcu.free_references.pop() orelse idx: { 3875 _ = try zcu.all_references.addOne(gpa); 3876 break :idx zcu.all_references.items.len - 1; 3877 }; 3878 3879 errdefer comptime unreachable; 3880 3881 const gop = zcu.reference_table.getOrPutAssumeCapacity(src_unit); 3882 3883 zcu.all_references.items[ref_idx] = .{ 3884 .referenced = referenced_unit, 3885 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), 3886 .src = ref_src, 3887 .inline_frame = inline_frame, 3888 }; 3889 3890 gop.value_ptr.* = @intCast(ref_idx); 3891 } 3892 3893 pub fn addTypeReference(zcu: *Zcu, src_unit: AnalUnit, referenced_type: InternPool.Index, ref_src: LazySrcLoc) Allocator.Error!void { 3894 const gpa = zcu.gpa; 3895 3896 zcu.clearCachedResolvedReferences(); 3897 3898 try zcu.type_reference_table.ensureUnusedCapacity(gpa, 1); 3899 3900 const ref_idx = zcu.free_type_references.pop() orelse idx: { 3901 _ = try zcu.all_type_references.addOne(gpa); 3902 break :idx zcu.all_type_references.items.len - 1; 3903 }; 3904 3905 errdefer comptime unreachable; 3906 3907 const gop = zcu.type_reference_table.getOrPutAssumeCapacity(src_unit); 3908 3909 zcu.all_type_references.items[ref_idx] = .{ 3910 .referenced = referenced_type, 3911 .next = if (gop.found_existing) gop.value_ptr.* else std.math.maxInt(u32), 3912 .src = ref_src, 3913 }; 3914 3915 gop.value_ptr.* = @intCast(ref_idx); 3916 } 3917 3918 fn clearCachedResolvedReferences(zcu: *Zcu) void { 3919 if (zcu.resolved_references) |*r| r.deinit(zcu.gpa); 3920 zcu.resolved_references = null; 3921 } 3922 3923 pub fn errorSetBits(zcu: *const Zcu) u16 { 3924 const target = zcu.getTarget(); 3925 3926 if (zcu.error_limit == 0) return 0; 3927 if (target.cpu.arch.isSpirV()) { 3928 // As expected by https://github.com/Snektron/zig-spirv-test-executor 3929 if (zcu.comp.config.is_test) return 32; 3930 } 3931 3932 return @as(u16, std.math.log2_int(ErrorInt, zcu.error_limit)) + 1; 3933 } 3934 3935 pub fn errNote( 3936 zcu: *Zcu, 3937 src_loc: LazySrcLoc, 3938 parent: *ErrorMsg, 3939 comptime format: []const u8, 3940 args: anytype, 3941 ) error{OutOfMemory}!void { 3942 const msg = try std.fmt.allocPrint(zcu.gpa, format, args); 3943 errdefer zcu.gpa.free(msg); 3944 3945 parent.notes = try zcu.gpa.realloc(parent.notes, parent.notes.len + 1); 3946 parent.notes[parent.notes.len - 1] = .{ 3947 .src_loc = src_loc, 3948 .msg = msg, 3949 }; 3950 } 3951 3952 /// Deprecated. There is no global target for a Zig Compilation Unit. Instead, 3953 /// look up the target based on the Module that contains the source code being 3954 /// analyzed. 3955 pub fn getTarget(zcu: *const Zcu) *const Target { 3956 return &zcu.root_mod.resolved_target.result; 3957 } 3958 3959 pub fn addGlobalAssembly(zcu: *Zcu, unit: AnalUnit, source: []const u8) !void { 3960 const gpa = zcu.gpa; 3961 const gop = try zcu.global_assembly.getOrPut(gpa, unit); 3962 if (gop.found_existing) { 3963 const new_value = try std.fmt.allocPrint(gpa, "{s}\n{s}", .{ gop.value_ptr.*, source }); 3964 gpa.free(gop.value_ptr.*); 3965 gop.value_ptr.* = new_value; 3966 } else { 3967 gop.value_ptr.* = try gpa.dupe(u8, source); 3968 } 3969 } 3970 3971 pub const Feature = enum { 3972 /// When this feature is enabled, Sema will emit calls to 3973 /// `std.lang.panic` functions for things like safety checks and 3974 /// unreachables. Otherwise traps will be emitted. 3975 panic_fn, 3976 /// When this feature is enabled, Sema will insert tracer functions for gathering a stack 3977 /// trace for error returns. 3978 error_return_trace, 3979 /// When this feature is enabled, Sema will emit the `is_named_enum_value` AIR instructions 3980 /// and use it to check for corrupt switches. Backends currently need to implement their own 3981 /// logic to determine whether an enum value is in the set of named values. 3982 is_named_enum_value, 3983 error_set_has_value, 3984 field_reordering, 3985 /// In theory, backends are supposed to work like this: 3986 /// 3987 /// * The AIR emitted by `Sema` is converted into MIR by `codegen.generateFunction`. This pass 3988 /// is "pure", in that it does not depend on or modify any external mutable state. 3989 /// 3990 /// * That MIR is sent to the linker, which calls `codegen.emitFunction` to convert the MIR to 3991 /// finalized machine code. This process is permitted to query and modify linker state. 3992 /// 3993 /// * The linker stores the resulting machine code in the binary as needed. 3994 /// 3995 /// The first stage described above can run in parallel to the rest of the compiler, and even to 3996 /// other code generation work; we can run as many codegen threads as we want in parallel because 3997 /// of the fact that this pass is pure. Emit and link must be single-threaded, but are generally 3998 /// very fast, so that isn't a problem. 3999 /// 4000 /// Unfortunately, some code generation implementations currently query and/or mutate linker state 4001 /// or even (in the case of the LLVM backend) semantic analysis state. Such backends cannot be run 4002 /// in parallel with each other, with linking, or (potentially) with semantic analysis. 4003 /// 4004 /// Additionally, some backends continue to need the AIR in the "emit" stage, despite this pass 4005 /// operating on MIR. This complicates memory management under the threading model above. 4006 /// 4007 /// These are both **bugs** in backend implementations, left over from legacy code. However, they 4008 /// are difficult to fix. So, this `Feature` currently guards correct threading of code generation: 4009 /// 4010 /// * With this feature enabled, the backend is threaded as described above. The "emit" stage does 4011 /// not have access to AIR (it will be `undefined`; see `codegen.emitFunction`). 4012 /// 4013 /// * With this feature disabled, semantic analysis, code generation, and linking all occur on the 4014 /// same thread, and the "emit" stage has access to AIR. 4015 separate_thread, 4016 }; 4017 4018 pub fn backendSupportsFeature(zcu: *const Zcu, comptime feature: Feature) bool { 4019 const backend = target_util.zigBackend(&zcu.root_mod.resolved_target.result, zcu.comp.config.use_llvm); 4020 return target_util.backendSupportsFeature(backend, feature); 4021 } 4022 4023 pub const AtomicPtrAlignmentError = error{ 4024 FloatTooBig, 4025 IntTooBig, 4026 BadType, 4027 OutOfMemory, 4028 }; 4029 4030 pub const AtomicPtrAlignmentDiagnostics = struct { 4031 bits: u16 = undefined, 4032 max_bits: u16 = undefined, 4033 }; 4034 4035 /// Returns the alignment required for the target to perform atomic operations on type `ty` (that 4036 /// is, the required align attribute on the pointer). If the ABI alignment of `ty` is sufficient, 4037 /// returns `.none`. 4038 // TODO this function does not take into account CPU features, which can affect 4039 // this value. Audit this! 4040 pub fn atomicPtrAlignment( 4041 zcu: *Zcu, 4042 ty: Type, 4043 diags: *AtomicPtrAlignmentDiagnostics, 4044 ) AtomicPtrAlignmentError!Alignment { 4045 const target = zcu.getTarget(); 4046 const max_atomic_bits: u16 = switch (target.cpu.arch) { 4047 .ez80, 4048 .spork8, 4049 => 8, 4050 4051 .aarch64, 4052 .aarch64_be, 4053 => 128, 4054 4055 .mips64, 4056 .mips64el, 4057 => 64, // N32 should be 64, not 32. 4058 4059 .x86_64 => if (target.cpu.has(.x86, .cx16)) 128 else 64, // x32 should be 64 or 128, not 32. 4060 4061 else => target.ptrBitWidth(), 4062 }; 4063 4064 if (ty.toIntern() == .bool_type) return .none; 4065 if (ty.isRuntimeFloat()) { 4066 const bit_count = ty.floatBits(target); 4067 if (bit_count > max_atomic_bits) { 4068 diags.* = .{ 4069 .bits = bit_count, 4070 .max_bits = max_atomic_bits, 4071 }; 4072 return error.FloatTooBig; 4073 } 4074 return .none; 4075 } 4076 if (switch (ty.zigTypeTag(zcu)) { 4077 .int, .@"enum" => true, 4078 .@"struct" => ty.containerLayout(zcu) == .@"packed", 4079 else => false, 4080 }) { 4081 assert(ty.isAbiInt(zcu)); 4082 const bit_count = ty.intInfo(zcu).bits; 4083 if (bit_count > max_atomic_bits) { 4084 diags.* = .{ 4085 .bits = bit_count, 4086 .max_bits = max_atomic_bits, 4087 }; 4088 return error.IntTooBig; 4089 } 4090 return .none; 4091 } 4092 if (ty.isPtrAtRuntime(zcu)) return .none; 4093 return error.BadType; 4094 } 4095 4096 /// Returns null if `ty` is not a struct. 4097 pub fn typeToStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType { 4098 if (ty.ip_index == .none) return null; 4099 const ip = &zcu.intern_pool; 4100 return switch (ip.indexToKey(ty.ip_index)) { 4101 .struct_type => ip.loadStructType(ty.ip_index), 4102 else => null, 4103 }; 4104 } 4105 4106 pub fn typeToPackedStruct(zcu: *const Zcu, ty: Type) ?InternPool.LoadedStructType { 4107 const s = zcu.typeToStruct(ty) orelse return null; 4108 if (s.layout != .@"packed") return null; 4109 return s; 4110 } 4111 4112 /// https://github.com/ziglang/zig/issues/17178 explored storing these bit offsets 4113 /// into the packed struct InternPool data rather than computing this on the 4114 /// fly, however it was found to perform worse when measured on real world 4115 /// projects. 4116 pub fn structPackedFieldBitOffset( 4117 zcu: *Zcu, 4118 struct_type: InternPool.LoadedStructType, 4119 field_index: u32, 4120 ) u16 { 4121 const ip = &zcu.intern_pool; 4122 assert(struct_type.layout == .@"packed"); 4123 var bit_sum: u64 = 0; 4124 for (0..struct_type.field_types.len) |i| { 4125 if (i == field_index) { 4126 return @intCast(bit_sum); 4127 } 4128 const field_ty = Type.fromInterned(struct_type.field_types.get(ip)[i]); 4129 bit_sum += field_ty.bitSize(zcu); 4130 } 4131 unreachable; // index out of bounds 4132 } 4133 4134 pub fn typeToUnion(zcu: *const Zcu, ty: Type) ?InternPool.LoadedUnionType { 4135 if (ty.ip_index == .none) return null; 4136 const ip = &zcu.intern_pool; 4137 return switch (ip.indexToKey(ty.ip_index)) { 4138 .union_type => ip.loadUnionType(ty.ip_index), 4139 else => null, 4140 }; 4141 } 4142 4143 pub fn typeToFunc(zcu: *const Zcu, ty: Type) ?InternPool.Key.FuncType { 4144 if (ty.ip_index == .none) return null; 4145 return zcu.intern_pool.indexToFuncType(ty.toIntern()); 4146 } 4147 4148 pub fn iesFuncIndex(zcu: *const Zcu, ies_index: InternPool.Index) InternPool.Index { 4149 return zcu.intern_pool.iesFuncIndex(ies_index); 4150 } 4151 4152 pub fn funcInfo(zcu: *const Zcu, func_index: InternPool.Index) InternPool.Key.Func { 4153 return zcu.intern_pool.toFunc(func_index); 4154 } 4155 4156 pub const UnionLayout = struct { 4157 abi_size: u64, 4158 abi_align: Alignment, 4159 most_aligned_field: u32, 4160 most_aligned_field_size: u64, 4161 biggest_field: u32, 4162 payload_size: u64, 4163 payload_align: Alignment, 4164 tag_align: Alignment, 4165 tag_size: u64, 4166 padding: u32, 4167 4168 pub fn tagOffset(layout: UnionLayout) u64 { 4169 return if (layout.tag_align.compare(.lt, layout.payload_align)) layout.payload_size else 0; 4170 } 4171 4172 pub fn payloadOffset(layout: UnionLayout) u64 { 4173 return if (layout.tag_align.compare(.lt, layout.payload_align)) 0 else layout.tag_size; 4174 } 4175 }; 4176 4177 /// Returns the index of the active field, given the current tag value 4178 pub fn unionTagFieldIndex(zcu: *const Zcu, loaded_union: InternPool.LoadedUnionType, enum_tag: Value) ?u32 { 4179 const ip = &zcu.intern_pool; 4180 if (enum_tag.toIntern() == .none) return null; 4181 const enum_tag_key = ip.indexToKey(enum_tag.toIntern()).enum_tag; 4182 assert(enum_tag_key.ty == loaded_union.enum_tag_type); 4183 const loaded_enum = ip.loadEnumType(loaded_union.enum_tag_type); 4184 return loaded_enum.tagValueIndex(ip, enum_tag_key.int); 4185 } 4186 4187 pub const ResolvedReference = struct { 4188 referencer: AnalUnit, 4189 /// If `inline_frame` is not `.none`, this is the *deepest* source location in the chain of 4190 /// inline calls. For source locations further up the inline call stack, consult `inline_frame`. 4191 src: LazySrcLoc, 4192 inline_frame: InlineReferenceFrame.Index.Optional, 4193 }; 4194 4195 /// Returns a mapping from an `AnalUnit` to where it is referenced. 4196 /// If the value is `null`, the `AnalUnit` is a root of analysis. 4197 /// If an `AnalUnit` is not in the returned map, it is unreferenced. 4198 /// The returned hashmap is owned by the `Zcu`, so should not be freed by the caller. 4199 /// This hashmap is cached, so repeated calls to this function are cheap. 4200 pub fn resolveReferences(zcu: *Zcu) Allocator.Error!*const std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) { 4201 if (zcu.resolved_references == null) { 4202 zcu.resolved_references = try zcu.resolveReferencesInner(); 4203 } 4204 return &zcu.resolved_references.?; 4205 } 4206 fn resolveReferencesInner(zcu: *Zcu) Allocator.Error!std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) { 4207 const trace = tracy.trace(@src()); 4208 defer trace.end(); 4209 4210 const gpa = zcu.gpa; 4211 const comp = zcu.comp; 4212 const ip = &zcu.intern_pool; 4213 4214 var units: std.array_hash_map.Auto(AnalUnit, ?ResolvedReference) = .empty; 4215 var types: std.array_hash_map.Auto(InternPool.Index, ?ResolvedReference) = .empty; 4216 defer { 4217 units.deinit(gpa); 4218 types.deinit(gpa); 4219 } 4220 4221 // This is not a sufficient size, but an approximate lower bound. 4222 try units.ensureTotalCapacity(gpa, @intCast(zcu.reference_table.count())); 4223 4224 try types.ensureTotalCapacity(gpa, zcu.analysis_roots_len); 4225 for (zcu.analysisRoots()) |mod| { 4226 const file = zcu.module_roots.get(mod).?.unwrap() orelse continue; 4227 const root_ty = zcu.fileRootType(file); 4228 if (root_ty == .none) continue; 4229 types.putAssumeCapacityNoClobber(root_ty, null); 4230 } 4231 4232 var unit_idx: usize = 0; 4233 var type_idx: usize = 0; 4234 while (true) { 4235 if (type_idx < types.count()) { 4236 const ty = types.keys()[type_idx]; 4237 const referencer = types.values()[type_idx]; 4238 type_idx += 1; 4239 4240 refs_log.debug("handle type '{f}'", .{Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip)}); 4241 4242 // Queue any decls within this type which would be automatically analyzed. 4243 // Keep in sync with analysis queueing logic in `Zcu.PerThread.ScanDeclIter.scanDecl`. 4244 const ns = Type.fromInterned(ty).getNamespace(zcu).unwrap().?; 4245 for (zcu.namespacePtr(ns).comptime_decls.items) |cu| { 4246 // `comptime` decls are always analyzed. 4247 const unit: AnalUnit = .wrap(.{ .@"comptime" = cu }); 4248 const gop = try units.getOrPut(gpa, unit); 4249 if (!gop.found_existing) { 4250 refs_log.debug("type '{f}': ref comptime %{}", .{ 4251 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4252 @backingInt(ip.getComptimeUnit(cu).zir_index.resolve(ip) orelse continue), 4253 }); 4254 gop.value_ptr.* = referencer; 4255 } 4256 } 4257 for (zcu.namespacePtr(ns).test_decls.items) |nav_id| { 4258 const nav = ip.getNav(nav_id); 4259 // `test` declarations are analyzed depending on the test filter. 4260 const inst_info = nav.analysis.?.zir_index.resolveFull(ip) orelse continue; 4261 const file = zcu.fileByIndex(inst_info.file); 4262 const decl = file.zir.?.getDeclaration(inst_info.inst); 4263 4264 if (!comp.config.is_test or file.mod != zcu.main_mod) continue; 4265 4266 const want_analysis = switch (decl.kind) { 4267 .@"const", .@"var" => unreachable, 4268 .@"comptime" => unreachable, 4269 .unnamed_test => true, 4270 .@"test", .decltest => a: { 4271 const fqn_slice = nav.fqn.toSlice(ip); 4272 if (comp.test_filters.len > 0) { 4273 for (comp.test_filters) |test_filter| { 4274 if (std.mem.find(u8, fqn_slice, test_filter) != null) break; 4275 } else break :a false; 4276 } 4277 break :a true; 4278 }, 4279 }; 4280 if (want_analysis) { 4281 { 4282 const gop = try units.getOrPut(gpa, .wrap(.{ .nav_val = nav_id })); 4283 if (!gop.found_existing) { 4284 refs_log.debug("type '{f}': ref test %{}", .{ 4285 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4286 @backingInt(inst_info.inst), 4287 }); 4288 gop.value_ptr.* = referencer; 4289 } 4290 } 4291 // Non-fatal AstGen errors could mean this test decl failed 4292 if (nav.resolved != null and nav.resolved.?.value != .none) { 4293 const gop = try units.getOrPut(gpa, .wrap(.{ .func = nav.resolved.?.value })); 4294 if (!gop.found_existing) gop.value_ptr.* = referencer; 4295 } 4296 } 4297 } 4298 for (zcu.namespacePtr(ns).pub_decls.keys()) |nav| { 4299 // These are named declarations. They are analyzed only if marked `export`. 4300 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue; 4301 const file = zcu.fileByIndex(inst_info.file); 4302 const decl = file.zir.?.getDeclaration(inst_info.inst); 4303 if (decl.linkage == .@"export") { 4304 const unit: AnalUnit = .wrap(.{ .nav_val = nav }); 4305 const gop = try units.getOrPut(gpa, unit); 4306 if (!gop.found_existing) { 4307 refs_log.debug("type '{f}': ref named %{}", .{ 4308 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4309 @backingInt(inst_info.inst), 4310 }); 4311 gop.value_ptr.* = referencer; 4312 } 4313 } 4314 } 4315 for (zcu.namespacePtr(ns).priv_decls.keys()) |nav| { 4316 // These are named declarations. They are analyzed only if marked `export`. 4317 const inst_info = ip.getNav(nav).analysis.?.zir_index.resolveFull(ip) orelse continue; 4318 const file = zcu.fileByIndex(inst_info.file); 4319 const decl = file.zir.?.getDeclaration(inst_info.inst); 4320 if (decl.linkage == .@"export") { 4321 const unit: AnalUnit = .wrap(.{ .nav_val = nav }); 4322 const gop = try units.getOrPut(gpa, unit); 4323 if (!gop.found_existing) { 4324 refs_log.debug("type '{f}': ref named %{}", .{ 4325 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 4326 @backingInt(inst_info.inst), 4327 }); 4328 gop.value_ptr.* = referencer; 4329 } 4330 } 4331 } 4332 continue; 4333 } 4334 if (unit_idx < units.count()) { 4335 const unit = units.keys()[unit_idx]; 4336 unit_idx += 1; 4337 4338 // `nav_val` and `nav_ty` reference each other *implicitly* to save memory. 4339 // Likewise for `type_layout` and `struct_defaults` of a struct type. 4340 queue_paired: { 4341 const other: AnalUnit = .wrap(switch (unit.unwrap()) { 4342 .nav_val => |n| .{ .nav_ty = n }, 4343 .nav_ty => |n| .{ .nav_val = n }, 4344 .struct_defaults => |ty| .{ .type_layout = ty }, 4345 .type_layout => |ty| switch (ip.indexToKey(ty)) { 4346 .struct_type => .{ .struct_defaults = ty }, 4347 .union_type, .enum_type, .opaque_type => break :queue_paired, 4348 else => unreachable, 4349 }, 4350 .@"comptime", .func, .memoized_state => break :queue_paired, 4351 }); 4352 const gop = try units.getOrPut(gpa, other); 4353 if (gop.found_existing) break :queue_paired; 4354 gop.value_ptr.* = units.values()[unit_idx - 1]; // same reference location 4355 } 4356 4357 refs_log.debug("handle unit '{f}'", .{zcu.fmtAnalUnit(unit)}); 4358 4359 if (zcu.reference_table.get(unit)) |first_ref_idx| { 4360 assert(first_ref_idx != std.math.maxInt(u32)); 4361 var ref_idx = first_ref_idx; 4362 while (ref_idx != std.math.maxInt(u32)) { 4363 const ref = zcu.all_references.items[ref_idx]; 4364 const gop = try units.getOrPut(gpa, ref.referenced); 4365 if (!gop.found_existing) { 4366 refs_log.debug("unit '{f}': ref unit '{f}'", .{ 4367 zcu.fmtAnalUnit(unit), 4368 zcu.fmtAnalUnit(ref.referenced), 4369 }); 4370 gop.value_ptr.* = .{ 4371 .referencer = unit, 4372 .src = ref.src, 4373 .inline_frame = ref.inline_frame, 4374 }; 4375 } 4376 ref_idx = ref.next; 4377 } 4378 } 4379 if (zcu.type_reference_table.get(unit)) |first_ref_idx| { 4380 assert(first_ref_idx != std.math.maxInt(u32)); 4381 var ref_idx = first_ref_idx; 4382 while (ref_idx != std.math.maxInt(u32)) { 4383 const ref = zcu.all_type_references.items[ref_idx]; 4384 const gop = try types.getOrPut(gpa, ref.referenced); 4385 if (!gop.found_existing) { 4386 refs_log.debug("unit '{f}': ref type '{f}'", .{ 4387 zcu.fmtAnalUnit(unit), 4388 Type.fromInterned(ref.referenced).containerTypeName(ip).fqn.fmt(ip), 4389 }); 4390 gop.value_ptr.* = .{ 4391 .referencer = unit, 4392 .src = ref.src, 4393 .inline_frame = .none, 4394 }; 4395 } 4396 ref_idx = ref.next; 4397 } 4398 } 4399 continue; 4400 } 4401 break; 4402 } 4403 4404 return units.move(); 4405 } 4406 4407 pub fn analysisRoots(zcu: *Zcu) []*Module { 4408 return zcu.analysis_roots_buffer[0..zcu.analysis_roots_len]; 4409 } 4410 4411 pub fn fileByIndex(zcu: *const Zcu, file_index: File.Index) *File { 4412 return zcu.intern_pool.filePtr(file_index); 4413 } 4414 4415 /// Returns the struct that represents this `File`. 4416 /// If the struct has not been created, returns `.none`. 4417 pub fn fileRootType(zcu: *const Zcu, file_index: File.Index) InternPool.Index { 4418 const ip = &zcu.intern_pool; 4419 const file_index_unwrapped = file_index.unwrap(ip); 4420 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire(); 4421 return files.view().items(.root_type)[file_index_unwrapped.index]; 4422 } 4423 4424 pub fn setFileRootType(zcu: *Zcu, file_index: File.Index, root_type: InternPool.Index) void { 4425 const ip = &zcu.intern_pool; 4426 const file_index_unwrapped = file_index.unwrap(ip); 4427 const files = ip.getLocalShared(file_index_unwrapped.tid).files.acquire(); 4428 files.view().items(.root_type)[file_index_unwrapped.index] = root_type; 4429 } 4430 4431 pub fn navSrcLoc(zcu: *const Zcu, nav_index: InternPool.Nav.Index) LazySrcLoc { 4432 const ip = &zcu.intern_pool; 4433 return .{ 4434 .base_node_inst = ip.getNav(nav_index).srcInst(ip), 4435 .offset = LazySrcLoc.Offset.nodeOffset(.zero), 4436 }; 4437 } 4438 4439 pub fn typeSrcLoc(zcu: *const Zcu, ty_index: InternPool.Index) LazySrcLoc { 4440 _ = zcu; 4441 _ = ty_index; 4442 @panic("TODO"); 4443 } 4444 4445 pub fn typeFileScope(zcu: *Zcu, ty_index: InternPool.Index) *File { 4446 _ = zcu; 4447 _ = ty_index; 4448 @panic("TODO"); 4449 } 4450 4451 pub fn navSrcLine(zcu: *Zcu, nav_index: InternPool.Nav.Index) u32 { 4452 const ip = &zcu.intern_pool; 4453 const inst_info = ip.getNav(nav_index).srcInst(ip).resolveFull(ip).?; 4454 const zir = zcu.fileByIndex(inst_info.file).zir; 4455 return zir.?.getDeclaration(inst_info.inst).src_line; 4456 } 4457 4458 pub fn navValue(zcu: *const Zcu, nav_index: InternPool.Nav.Index) Value { 4459 return .fromInterned(zcu.intern_pool.getNav(nav_index).resolved.?.value); 4460 } 4461 4462 pub fn navFileScopeIndex(zcu: *Zcu, nav: InternPool.Nav.Index) File.Index { 4463 const ip = &zcu.intern_pool; 4464 return ip.getNav(nav).srcInst(ip).resolveFile(ip); 4465 } 4466 4467 pub fn navFileScope(zcu: *Zcu, nav: InternPool.Nav.Index) *File { 4468 return zcu.fileByIndex(zcu.navFileScopeIndex(nav)); 4469 } 4470 4471 pub fn navAlignment(zcu: *Zcu, nav_id: InternPool.Nav.Index) InternPool.Alignment { 4472 const resolved = zcu.intern_pool.getNav(nav_id).resolved.?; 4473 return switch (resolved.@"align") { 4474 else => |a| a, 4475 .none => Type.fromInterned(resolved.type).abiAlignment(zcu), 4476 }; 4477 } 4478 4479 pub fn fmtAnalUnit(zcu: *Zcu, unit: AnalUnit) std.fmt.Alt(FormatAnalUnit, formatAnalUnit) { 4480 return .{ .data = .{ .unit = unit, .zcu = zcu } }; 4481 } 4482 pub fn fmtDependee(zcu: *Zcu, d: InternPool.Dependee) std.fmt.Alt(FormatDependee, formatDependee) { 4483 return .{ .data = .{ .dependee = d, .zcu = zcu } }; 4484 } 4485 4486 const FormatAnalUnit = struct { unit: AnalUnit, zcu: *const Zcu }; 4487 fn formatAnalUnit(data: FormatAnalUnit, writer: *Io.Writer) Io.Writer.Error!void { 4488 const zcu = data.zcu; 4489 const ip = &zcu.intern_pool; 4490 switch (data.unit.unwrap()) { 4491 .@"comptime" => |cu_id| { 4492 const cu = ip.getComptimeUnit(cu_id); 4493 if (cu.zir_index.resolveFull(ip)) |resolved| { 4494 const file_path = zcu.fileByIndex(resolved.file).path; 4495 return writer.print("comptime(inst=('{f}', %{}) [{}])", .{ file_path.fmt(zcu.comp), @backingInt(resolved.inst), @backingInt(cu_id) }); 4496 } else { 4497 return writer.print("comptime(inst=<lost> [{}])", .{@backingInt(cu_id)}); 4498 } 4499 }, 4500 .nav_val, .nav_ty => |nav, tag| return writer.print("{t}('{f}' [{}])", .{ tag, ip.getNav(nav).fqn.fmt(ip), @backingInt(nav) }), 4501 .type_layout, .struct_defaults => |ty, tag| return writer.print("{t}('{f}' [{}])", .{ tag, Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), @backingInt(ty) }), 4502 .func => |func| { 4503 const nav = zcu.funcInfo(func).owner_nav; 4504 return writer.print("func('{f}' [{}])", .{ ip.getNav(nav).fqn.fmt(ip), @backingInt(func) }); 4505 }, 4506 .memoized_state => return writer.writeAll("memoized_state"), 4507 } 4508 } 4509 4510 const FormatDependee = struct { dependee: InternPool.Dependee, zcu: *const Zcu }; 4511 fn formatDependee(data: FormatDependee, writer: *Io.Writer) Io.Writer.Error!void { 4512 const zcu = data.zcu; 4513 const ip = &zcu.intern_pool; 4514 switch (data.dependee) { 4515 .src_hash => |ti| { 4516 const info = ti.resolveFull(ip) orelse { 4517 return writer.writeAll("inst(<lost>)"); 4518 }; 4519 const file_path = zcu.fileByIndex(info.file).path; 4520 return writer.print("inst('{f}', %{d})", .{ file_path.fmt(zcu.comp), @backingInt(info.inst) }); 4521 }, 4522 .nav_val, .nav_ty => |nav, tag| { 4523 const fqn = ip.getNav(nav).fqn; 4524 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); 4525 }, 4526 .type_layout, .struct_defaults => |ip_index, tag| { 4527 const fqn = Type.fromInterned(ip_index).containerTypeName(ip).fqn; 4528 return writer.print("{t}('{f}')", .{ tag, fqn.fmt(ip) }); 4529 }, 4530 .func_ies => |ip_index| { 4531 const fqn = ip.getNav(ip.indexToKey(ip_index).func.owner_nav).fqn; 4532 return writer.print("func_ies('{f}')", .{fqn.fmt(ip)}); 4533 }, 4534 .source_file => |file| { 4535 const file_path = zcu.fileByIndex(file).path; 4536 return writer.print("source_file('{f}')", .{file_path.fmt(zcu.comp)}); 4537 }, 4538 .embed_file => |ef_idx| { 4539 const ef = ef_idx.get(zcu); 4540 return writer.print("embed_file('{f}')", .{ef.path.fmt(zcu.comp)}); 4541 }, 4542 .namespace => |ti| { 4543 const info = ti.resolveFull(ip) orelse { 4544 return writer.writeAll("namespace(<lost>)"); 4545 }; 4546 const file_path = zcu.fileByIndex(info.file).path; 4547 return writer.print("namespace('{f}', %{d})", .{ file_path.fmt(zcu.comp), @backingInt(info.inst) }); 4548 }, 4549 .namespace_name => |k| { 4550 const info = k.namespace.resolveFull(ip) orelse { 4551 return writer.print("namespace(<lost>, '{f}')", .{k.name.fmt(ip)}); 4552 }; 4553 const file_path = zcu.fileByIndex(info.file).path; 4554 return writer.print("namespace('{f}', %{d}, '{f}')", .{ file_path.fmt(zcu.comp), @backingInt(info.inst), k.name.fmt(ip) }); 4555 }, 4556 .memoized_state => return writer.writeAll("memoized_state"), 4557 } 4558 } 4559 4560 pub fn callconvSupported(zcu: *Zcu, cc: std.lang.CallingConvention) union(enum) { 4561 ok, 4562 bad_arch: []const std.Target.Cpu.Arch, // value is allowed archs for cc 4563 bad_backend: std.lang.CompilerBackend, // value is current backend 4564 } { 4565 const target = zcu.getTarget(); 4566 const backend = target_util.zigBackend(target, zcu.comp.config.use_llvm); 4567 switch (cc) { 4568 .auto, .@"inline" => return .ok, 4569 .async => return .{ .bad_backend = backend }, // nothing supports async currently 4570 .naked => {}, // depends only on backend 4571 else => for (cc.archs()) |allowed_arch| { 4572 if (allowed_arch == target.cpu.arch) break; 4573 } else return .{ .bad_arch = cc.archs() }, 4574 } 4575 const backend_ok = ok: switch (backend) { 4576 .stage1 => unreachable, 4577 .other => unreachable, 4578 _ => unreachable, 4579 4580 .stage2_llvm => { 4581 dev.check(.llvm_backend); 4582 break :ok @import("codegen/llvm.zig").toLlvmCallConv(cc, target) != null; 4583 }, 4584 .stage2_c => { 4585 dev.check(.c_backend); 4586 if (target.cCallingConvention()) |default_c| { 4587 if (cc.eql(default_c)) { 4588 break :ok true; 4589 } 4590 } 4591 break :ok switch (cc) { 4592 .x86_16_cdecl, 4593 .x86_16_stdcall, 4594 .x86_16_regparmcall, 4595 .x86_16_interrupt, 4596 .x86_64_sysv, 4597 .x86_64_win, 4598 .x86_64_vectorcall, 4599 .x86_64_regcall_v3_sysv, 4600 .x86_64_regcall_v4_win, 4601 .x86_64_interrupt, 4602 .x86_64_preserve_none, 4603 .x86_fastcall, 4604 .x86_thiscall, 4605 .x86_vectorcall, 4606 .x86_regcall_v3, 4607 .x86_regcall_v4_win, 4608 .x86_interrupt, 4609 .aarch64_vfabi, 4610 .aarch64_vfabi_sve, 4611 .aarch64_preserve_none, 4612 .arm_aapcs, 4613 .csky_interrupt, 4614 .riscv64_lp64_v, 4615 .riscv32_ilp32_v, 4616 .m68k_rtd, 4617 .m68k_interrupt, 4618 .msp430_interrupt, 4619 .arm_aapcs_vfp, 4620 .arc_interrupt, 4621 .arm_interrupt, 4622 .microblaze_interrupt, 4623 .mips_interrupt, 4624 .mips64_interrupt, 4625 .riscv32_interrupt, 4626 .riscv64_interrupt, 4627 .sh_interrupt, 4628 .avr_interrupt, 4629 .avr_signal, 4630 .ez80_tiflags, 4631 .naked, 4632 => true, // incoming stack alignment supported 4633 4634 .x86_sysv, 4635 .x86_win, 4636 .x86_mingw, 4637 .x86_stdcall, 4638 => |opts| opts.register_params == 0, // incoming stack alignment supported 4639 4640 else => false, 4641 }; 4642 }, 4643 .stage2_wasm => { 4644 dev.check(.wasm_backend); 4645 break :ok switch (cc) { 4646 .wasm_mvp => |opts| opts.incoming_stack_alignment == null, 4647 else => false, 4648 }; 4649 }, 4650 .stage2_arm => { 4651 dev.check(.arm_backend); 4652 break :ok switch (cc) { 4653 .arm_aapcs => |opts| opts.incoming_stack_alignment == null, 4654 .naked => true, 4655 else => false, 4656 }; 4657 }, 4658 .stage2_x86_64 => { 4659 dev.check(.x86_64_backend); 4660 break :ok switch (cc) { 4661 .x86_64_sysv, .x86_64_win, .naked => true, // incoming stack alignment supported 4662 else => false, 4663 }; 4664 }, 4665 .stage2_aarch64 => { 4666 dev.check(.aarch64_backend); 4667 break :ok switch (cc) { 4668 .aarch64_aapcs, .aarch64_aapcs_darwin, .naked => true, 4669 else => false, 4670 }; 4671 }, 4672 .stage2_x86 => { 4673 dev.check(.x86_backend); 4674 break :ok switch (cc) { 4675 .x86_sysv, 4676 .x86_win, 4677 .x86_mingw, 4678 => |opts| opts.incoming_stack_alignment == null and opts.register_params == 0, 4679 .naked => true, 4680 else => false, 4681 }; 4682 }, 4683 .stage2_powerpc => { 4684 dev.check(.powerpc_backend); 4685 break :ok switch (target.cpu.arch) { 4686 .powerpc, .powerpcle => switch (cc) { 4687 .powerpc_sysv, 4688 .powerpc_sysv_altivec, 4689 .powerpc_aix, 4690 .powerpc_aix_altivec, 4691 .naked, 4692 => true, 4693 else => false, 4694 }, 4695 .powerpc64, .powerpc64le => switch (cc) { 4696 .powerpc64_elf, 4697 .powerpc64_elf_altivec, 4698 .powerpc64_elf_v2, 4699 .naked, 4700 => true, 4701 else => false, 4702 }, 4703 else => unreachable, 4704 }; 4705 }, 4706 .stage2_riscv64 => { 4707 dev.check(.riscv64_backend); 4708 break :ok switch (cc) { 4709 .riscv64_lp64 => |opts| opts.incoming_stack_alignment == null, 4710 .naked => true, 4711 else => false, 4712 }; 4713 }, 4714 .stage2_sparc64 => { 4715 dev.check(.sparc64_backend); 4716 break :ok switch (cc) { 4717 .sparc64_sysv => |opts| opts.incoming_stack_alignment == null, 4718 .naked => true, 4719 else => false, 4720 }; 4721 }, 4722 .stage2_spirv => { 4723 dev.check(.spirv_backend); 4724 break :ok switch (cc) { 4725 .spirv_device, .spirv_kernel => true, 4726 .spirv_fragment, .spirv_vertex => target.os.tag == .vulkan or target.os.tag == .opengl, 4727 .spirv_task, .spirv_mesh => target.os.tag == .vulkan, 4728 else => false, 4729 }; 4730 }, 4731 .stage2_loongarch => { 4732 dev.check(.loongarch_backend); 4733 break :ok switch (cc) { 4734 .loongarch64_lp64, .loongarch32_ilp32, .naked => true, 4735 else => false, 4736 }; 4737 }, 4738 .zsf_spork8 => { 4739 dev.check(.spork8_backend); 4740 break :ok switch (cc) { 4741 .spork8, .naked => true, 4742 else => false, 4743 }; 4744 }, 4745 }; 4746 if (!backend_ok) return .{ .bad_backend = backend }; 4747 return .ok; 4748 } 4749 4750 pub const CodegenFailError = Io.Cancelable || error{ 4751 /// Indicates the error message has been already stored at `Zcu.failed_codegen`. 4752 AlreadyReported, 4753 OutOfMemory, 4754 }; 4755 4756 pub fn codegenFail( 4757 zcu: *Zcu, 4758 nav_index: InternPool.Nav.Index, 4759 comptime format: []const u8, 4760 args: anytype, 4761 ) CodegenFailError { 4762 const msg = try Zcu.ErrorMsg.create(zcu.gpa, zcu.navSrcLoc(nav_index), format, args); 4763 return zcu.codegenFailMsg(nav_index, msg); 4764 } 4765 4766 /// Takes ownership of `msg`, even on OOM. 4767 pub fn codegenFailMsg(zcu: *Zcu, nav_index: InternPool.Nav.Index, msg: *ErrorMsg) CodegenFailError { 4768 const comp = zcu.comp; 4769 const gpa = comp.gpa; 4770 const io = comp.io; 4771 { 4772 comp.mutex.lockUncancelable(io); 4773 defer comp.mutex.unlock(io); 4774 errdefer msg.deinit(gpa); 4775 try zcu.failed_codegen.putNoClobber(gpa, nav_index, msg); 4776 } 4777 return error.AlreadyReported; 4778 } 4779 4780 pub fn codegenFailType( 4781 zcu: *Zcu, 4782 ty_index: InternPool.Index, 4783 comptime format: []const u8, 4784 args: anytype, 4785 ) CodegenFailError { 4786 const gpa = zcu.gpa; 4787 try zcu.failed_types.ensureUnusedCapacity(gpa, 1); 4788 const msg = try Zcu.ErrorMsg.create(gpa, zcu.typeSrcLoc(ty_index), format, args); 4789 zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg); 4790 return error.AlreadyReported; 4791 } 4792 4793 pub fn codegenFailTypeMsg(zcu: *Zcu, ty_index: InternPool.Index, msg: *ErrorMsg) CodegenFailError { 4794 const gpa = zcu.gpa; 4795 { 4796 errdefer msg.deinit(gpa); 4797 try zcu.failed_types.ensureUnusedCapacity(gpa, 1); 4798 } 4799 zcu.failed_types.putAssumeCapacityNoClobber(ty_index, msg); 4800 return error.AlreadyReported; 4801 } 4802 4803 /// Asserts that `zcu.multi_module_err != null`. 4804 pub fn addFileInMultipleModulesError( 4805 zcu: *Zcu, 4806 eb: *std.zig.ErrorBundle.Wip, 4807 ) Allocator.Error!void { 4808 const gpa = zcu.gpa; 4809 4810 const info = zcu.multi_module_err.?; 4811 const file = info.file; 4812 4813 // error: file exists in modules 'root.foo' and 'root.bar' 4814 // note: files must belong to only one module 4815 // note: file is imported here 4816 // note: which is imported here 4817 // note: which is the root of module 'root.foo' imported here 4818 // note: file is the root of module 'root.bar' imported here 4819 4820 const file_src = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb); 4821 const root_msg = try eb.printString("file exists in modules '{s}' and '{s}'", .{ 4822 info.modules[0].fully_qualified_name, 4823 info.modules[1].fully_qualified_name, 4824 }); 4825 4826 var notes: std.ArrayList(std.zig.ErrorBundle.MessageIndex) = .empty; 4827 defer notes.deinit(gpa); 4828 4829 try notes.append(gpa, try eb.addErrorMessage(.{ 4830 .msg = try eb.addString("files must belong to only one module"), 4831 .src_loc = file_src, 4832 })); 4833 4834 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[0], info.refs[0]); 4835 try zcu.explainWhyFileIsInModule(eb, &notes, file, info.modules[1], info.refs[1]); 4836 4837 try eb.addRootErrorMessage(.{ 4838 .msg = root_msg, 4839 .src_loc = file_src, 4840 .notes_len = @intCast(notes.items.len), 4841 }); 4842 const notes_start = try eb.reserveNotes(@intCast(notes.items.len)); 4843 const notes_slice: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]); 4844 @memcpy(notes_slice, notes.items); 4845 } 4846 4847 fn explainWhyFileIsInModule( 4848 zcu: *Zcu, 4849 eb: *std.zig.ErrorBundle.Wip, 4850 notes_out: *std.ArrayList(std.zig.ErrorBundle.MessageIndex), 4851 file: File.Index, 4852 in_module: *Module, 4853 ref: File.Reference, 4854 ) Allocator.Error!void { 4855 const gpa = zcu.gpa; 4856 4857 // error: file is the root of module 'foo' 4858 // 4859 // error: file is imported here by the root of module 'foo' 4860 // 4861 // error: file is imported here 4862 // note: which is imported here 4863 // note: which is imported here by the root of module 'foo' 4864 4865 var import = switch (ref) { 4866 .analysis_root => |mod| { 4867 assert(mod == in_module); 4868 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4869 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}), 4870 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb), 4871 })); 4872 return; 4873 }, 4874 .import => |import| if (import.module) |mod| { 4875 assert(mod == in_module); 4876 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4877 .msg = try eb.printString("file is the root of module '{s}'", .{mod.fully_qualified_name}), 4878 .src_loc = try zcu.fileByIndex(file).errorBundleWholeFileSrc(zcu, eb), 4879 })); 4880 return; 4881 } else import, 4882 }; 4883 4884 var is_first = true; 4885 while (true) { 4886 const thing: []const u8 = if (is_first) "file" else "which"; 4887 is_first = false; 4888 4889 const importer_file = zcu.fileByIndex(import.importer); 4890 // `errorBundleTokenSrc` expects the tree to be loaded 4891 _ = importer_file.getTree(zcu) catch |err| { 4892 try Compilation.unableToLoadZcuFile(zcu, eb, importer_file, err); 4893 return; // stop the explanation early 4894 }; 4895 const import_src = try importer_file.errorBundleTokenSrc(import.tok, zcu, eb); 4896 4897 const importer_ref = zcu.alive_files.get(import.importer).?; 4898 const importer_root: ?*Module = switch (importer_ref) { 4899 .analysis_root => |mod| mod, 4900 .import => |i| i.module, 4901 }; 4902 4903 if (importer_root) |m| { 4904 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4905 .msg = try eb.printString("{s} is imported here by the root of module '{s}'", .{ thing, m.fully_qualified_name }), 4906 .src_loc = import_src, 4907 })); 4908 return; 4909 } 4910 4911 try notes_out.append(gpa, try eb.addErrorMessage(.{ 4912 .msg = try eb.printString("{s} is imported here", .{thing}), 4913 .src_loc = import_src, 4914 })); 4915 4916 import = importer_ref.import; 4917 } 4918 } 4919 4920 pub fn addDependencyLoopErrors(zcu: *Zcu, eb: *std.zig.ErrorBundle.Wip) Allocator.Error!void { 4921 const gpa = zcu.comp.gpa; 4922 4923 const all_references = try zcu.resolveReferences(); 4924 4925 var units: std.ArrayList(AnalUnit) = .empty; 4926 defer units.deinit(gpa); 4927 4928 // TODO: sort the dependency loops somehow to make the error bundle reproducible 4929 for (zcu.dependency_loops.keys()) |arbitrary_unit| { 4930 units.clearRetainingCapacity(); 4931 4932 var cur = arbitrary_unit; 4933 while (true) { 4934 try units.append(gpa, cur); 4935 cur = zcu.dependency_loop_nodes.get(cur).?.unit; 4936 if (cur == arbitrary_unit) break; 4937 } 4938 4939 // `units` now contains all units in the loop. We need to pick a starting point somewhere 4940 // along that loop to begin. We will pick whichever node has the shortest reference trace, 4941 // because the other units may well just be referenced *by* that one! This is also likely 4942 // to match the user's intuition for where the loop "starts". 4943 var start_index: usize = 0; 4944 var start_depth: u32 = depth: { 4945 var depth: u32 = 0; 4946 var opt_ref = all_references.get(units.items[0]) orelse { 4947 // This dependency loop is actually unreferenced, so we don't need to emit a compile 4948 // error at all! Move onto the next dependency loop. 4949 continue; 4950 }; 4951 while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1; 4952 break :depth depth; 4953 }; 4954 for (units.items[1..], 1..) |unit, index| { 4955 var depth: u32 = 0; 4956 var opt_ref = all_references.get(unit).?; 4957 while (opt_ref) |ref| : (opt_ref = all_references.get(ref.referencer).?) depth += 1; 4958 if (depth < start_depth) { 4959 start_index = index; 4960 start_depth = depth; 4961 } 4962 } 4963 4964 // Collect a reference trace for the start of the loop. 4965 var ref_trace: std.ArrayList(std.zig.ErrorBundle.ReferenceTrace) = .empty; 4966 defer ref_trace.deinit(gpa); 4967 const frame_limit = zcu.comp.reference_trace orelse 0; 4968 try zcu.populateReferenceTrace(units.items[start_index], frame_limit, eb, &ref_trace); 4969 4970 if (units.items.len == 1) { 4971 // Don't do a complicated message with multiple notes, just do a single error message. 4972 assert(start_index == 0); 4973 const root_msg = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) { 4974 error.AlreadyReported => return, // give up on the dep loop error 4975 error.OutOfMemory => |e| return e, 4976 }; 4977 try eb.root_list.append(eb.gpa, root_msg); 4978 continue; 4979 } 4980 4981 // Collect all notes first so we don't leave an incomplete root error message on `error.AlreadyReported`. 4982 const note_buf = try gpa.alloc(std.zig.ErrorBundle.MessageIndex, units.items.len + 1); 4983 defer gpa.free(note_buf); 4984 note_buf[0] = addDependencyLoopErrorLine(zcu, eb, units.items[start_index], ref_trace.items) catch |err| switch (err) { 4985 error.AlreadyReported => return, // give up on the dep loop error 4986 error.OutOfMemory => |e| return e, 4987 }; 4988 for (units.items[start_index + 1 ..], note_buf[1 .. units.items.len - start_index]) |unit, *note| { 4989 note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) { 4990 error.AlreadyReported => return, // give up on the dep loop error 4991 error.OutOfMemory => |e| return e, 4992 }; 4993 } 4994 for (units.items[0..start_index], note_buf[units.items.len - start_index .. units.items.len]) |unit, *note| { 4995 note.* = addDependencyLoopErrorLine(zcu, eb, unit, &.{}) catch |err| switch (err) { 4996 error.AlreadyReported => return, // give up on the dep loop error 4997 error.OutOfMemory => |e| return e, 4998 }; 4999 } 5000 note_buf[units.items.len] = try eb.addErrorMessage(.{ 5001 .msg = try eb.addString("eliminate any one of these dependencies to break the loop"), 5002 .src_loc = .none, 5003 }); 5004 5005 try eb.addRootErrorMessage(.{ 5006 .msg = try eb.printString("dependency loop with length {d}", .{units.items.len}), 5007 .src_loc = .none, 5008 .notes_len = @intCast(units.items.len + 1), 5009 }); 5010 const notes_start = try eb.reserveNotes(@intCast(units.items.len + 1)); 5011 const notes: []std.zig.ErrorBundle.MessageIndex = @ptrCast(eb.extra.items[notes_start..]); 5012 @memcpy(notes, note_buf); 5013 } 5014 } 5015 fn addDependencyLoopErrorLine( 5016 zcu: *Zcu, 5017 eb: *std.zig.ErrorBundle.Wip, 5018 source_unit: AnalUnit, 5019 ref_trace: []const std.zig.ErrorBundle.ReferenceTrace, 5020 ) (Allocator.Error || error{AlreadyReported})!std.zig.ErrorBundle.MessageIndex { 5021 const ip = &zcu.intern_pool; 5022 const comp = zcu.comp; 5023 5024 const fmt_source: std.fmt.Alt(FormatAnalUnit, formatDependencyLoopSourceUnit) = .{ .data = .{ 5025 .unit = source_unit, 5026 .zcu = zcu, 5027 } }; 5028 5029 const dep_node = zcu.dependency_loop_nodes.get(source_unit).?; 5030 5031 const msg: std.zig.ErrorBundle.String = if (dep_node.unit == source_unit) switch (source_unit.unwrap()) { 5032 .@"comptime" => unreachable, // cannot be involved in a dependency loop 5033 .nav_ty, .nav_val => try eb.printString("{f} depends on itself here", .{fmt_source}), 5034 .memoized_state => unreachable, // memoized_state definitely does not *directly* depend on itself 5035 .func => try eb.printString("{f} uses its own inferred error set here", .{fmt_source}), 5036 .type_layout => try eb.printString("{f} depends on itself {s}", .{ 5037 fmt_source, 5038 dep_node.reason.type_layout_reason.msg(), 5039 }), 5040 .struct_defaults => |ty| try eb.printString( 5041 "default field values of '{f}' depend on themselves for initialization here", 5042 .{Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip)}, 5043 ), 5044 } else switch (dep_node.unit.unwrap()) { 5045 .@"comptime" => unreachable, // cannot be involved in a dependency loop 5046 .nav_val => |nav| try eb.printString("{f} uses value of declaration '{f}' here", .{ 5047 fmt_source, ip.getNav(nav).fqn.fmt(ip), 5048 }), 5049 .nav_ty => |nav| try eb.printString("{f} uses type of declaration '{f}' here", .{ 5050 fmt_source, ip.getNav(nav).fqn.fmt(ip), 5051 }), 5052 .memoized_state => |stage| switch (stage) { 5053 .panic => try eb.printString("{f} requires panic handler for call here", .{fmt_source}), 5054 else => try eb.printString("{f} requires 'std.lang' declarations here", .{fmt_source}), 5055 }, 5056 .func => |func| try eb.printString("{f} uses inferred error set of function '{f}' here", .{ 5057 fmt_source, ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip), 5058 }), 5059 .type_layout => |ty| try eb.printString("{f} depends on type '{f}' {s}", .{ 5060 fmt_source, 5061 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 5062 dep_node.reason.type_layout_reason.msg(), 5063 }), 5064 .struct_defaults => |ty| try eb.printString( 5065 "{f} uses default field values of '{f}' here", 5066 .{ fmt_source, Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip) }, 5067 ), 5068 }; 5069 5070 const src_loc = dep_node.reason.src.upgrade(zcu); 5071 const source = src_loc.file_scope.getSource(zcu) catch |err| { 5072 try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err); 5073 return error.AlreadyReported; 5074 }; 5075 const span = src_loc.span(zcu) catch |err| { 5076 try Compilation.unableToLoadZcuFile(zcu, eb, src_loc.file_scope, err); 5077 return error.AlreadyReported; 5078 }; 5079 const loc = std.zig.findLineColumn(source, span.main); 5080 const eb_src = try eb.addSourceLocation(.{ 5081 .src_path = try eb.printString("{f}", .{src_loc.file_scope.path.fmt(comp)}), 5082 .span_start = span.start, 5083 .span_main = span.main, 5084 .span_end = span.end, 5085 .line = @intCast(loc.line), 5086 .column = @intCast(loc.column), 5087 .source_line = try eb.addString(loc.source_line), 5088 .reference_trace_len = @intCast(ref_trace.len), 5089 }); 5090 for (ref_trace) |rt| try eb.addReferenceTrace(rt); 5091 return eb.addErrorMessage(.{ 5092 .msg = msg, 5093 .src_loc = eb_src, 5094 }); 5095 } 5096 fn formatDependencyLoopSourceUnit(data: FormatAnalUnit, w: *Io.Writer) Io.Writer.Error!void { 5097 const zcu = data.zcu; 5098 const ip = &zcu.intern_pool; 5099 switch (data.unit.unwrap()) { 5100 .@"comptime" => unreachable, // cannot be involved in a dependency loop 5101 .nav_val => |nav| try w.print("value of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}), 5102 .nav_ty => |nav| try w.print("type of declaration '{f}'", .{ip.getNav(nav).fqn.fmt(ip)}), 5103 .memoized_state => |stage| switch (stage) { 5104 .panic => try w.writeAll("panic handler"), 5105 else => try w.writeAll("'std.lang' declarations"), 5106 }, 5107 .type_layout => |ty| try w.print("type '{f}'", .{ 5108 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 5109 }), 5110 .struct_defaults => |ty| try w.print("default field value of '{f}'", .{ 5111 Type.fromInterned(ty).containerTypeName(ip).fqn.fmt(ip), 5112 }), 5113 .func => |func| try w.print("function '{f}'", .{ 5114 ip.getNav(zcu.funcInfo(func).owner_nav).fqn.fmt(ip), 5115 }), 5116 } 5117 } 5118 5119 pub fn populateReferenceTrace( 5120 zcu: *Zcu, 5121 root: AnalUnit, 5122 frame_limit: u32, 5123 eb: *std.zig.ErrorBundle.Wip, 5124 ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace), 5125 ) Allocator.Error!void { 5126 const ip = &zcu.intern_pool; 5127 const gpa = zcu.comp.gpa; 5128 5129 if (frame_limit == 0) return; 5130 5131 const all_references = try zcu.resolveReferences(); 5132 5133 var seen: std.AutoHashMapUnmanaged(InternPool.AnalUnit, void) = .empty; 5134 defer seen.deinit(gpa); 5135 5136 var referenced_by = root; 5137 while (all_references.get(referenced_by)) |maybe_ref| { 5138 const ref = maybe_ref orelse break; 5139 const gop = try seen.getOrPut(gpa, ref.referencer); 5140 if (gop.found_existing) break; 5141 if (ref_trace.items.len < frame_limit) { 5142 var last_call_src = ref.src; 5143 var opt_inline_frame = ref.inline_frame; 5144 while (opt_inline_frame.unwrap()) |inline_frame| { 5145 const f = inline_frame.ptr(zcu).*; 5146 const func_nav = ip.indexToKey(f.callee).func.owner_nav; 5147 const func_name = ip.getNav(func_nav).name.toSlice(ip); 5148 addReferenceTraceFrame(zcu, eb, ref_trace, func_name, last_call_src, true) catch |err| switch (err) { 5149 error.OutOfMemory => |e| return e, 5150 error.AlreadyReported => { 5151 // An incomplete reference trace isn't the end of the world; just cut it off. 5152 return; 5153 }, 5154 }; 5155 last_call_src = f.call_src; 5156 opt_inline_frame = f.parent; 5157 } 5158 const root_name: ?[]const u8 = switch (ref.referencer.unwrap()) { 5159 .@"comptime" => "comptime", 5160 .nav_val, .nav_ty => |nav| ip.getNav(nav).name.toSlice(ip), 5161 .type_layout, .struct_defaults => |ty| Type.fromInterned(ty).containerTypeName(ip).fqn.toSlice(ip), 5162 .func => |f| ip.getNav(zcu.funcInfo(f).owner_nav).name.toSlice(ip), 5163 .memoized_state => null, 5164 }; 5165 if (root_name) |n| { 5166 addReferenceTraceFrame(zcu, eb, ref_trace, n, last_call_src, false) catch |err| switch (err) { 5167 error.OutOfMemory => |e| return e, 5168 error.AlreadyReported => { 5169 // An incomplete reference trace isn't the end of the world; just cut it off. 5170 return; 5171 }, 5172 }; 5173 } 5174 } 5175 referenced_by = ref.referencer; 5176 } 5177 5178 if (seen.count() > ref_trace.items.len) { 5179 try ref_trace.append(gpa, .{ 5180 .decl_name = @intCast(seen.count() - ref_trace.items.len), 5181 .src_loc = .none, 5182 }); 5183 } 5184 } 5185 fn addReferenceTraceFrame( 5186 zcu: *Zcu, 5187 eb: *std.zig.ErrorBundle.Wip, 5188 ref_trace: *std.ArrayList(std.zig.ErrorBundle.ReferenceTrace), 5189 name: []const u8, 5190 lazy_src: Zcu.LazySrcLoc, 5191 inlined: bool, 5192 ) error{ OutOfMemory, AlreadyReported }!void { 5193 const gpa = zcu.gpa; 5194 const src = lazy_src.upgrade(zcu); 5195 const source = src.file_scope.getSource(zcu) catch |err| { 5196 try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err); 5197 return error.AlreadyReported; 5198 }; 5199 const span = src.span(zcu) catch |err| { 5200 try Compilation.unableToLoadZcuFile(zcu, eb, src.file_scope, err); 5201 return error.AlreadyReported; 5202 }; 5203 const loc = std.zig.findLineColumn(source, span.main); 5204 try ref_trace.append(gpa, .{ 5205 .decl_name = try eb.printString("{s}{s}", .{ name, if (inlined) " [inlined]" else "" }), 5206 .src_loc = try eb.addSourceLocation(.{ 5207 .src_path = try eb.printString("{f}", .{src.file_scope.path.fmt(zcu.comp)}), 5208 .span_start = span.start, 5209 .span_main = span.main, 5210 .span_end = span.end, 5211 .line = @intCast(loc.line), 5212 .column = @intCast(loc.column), 5213 .source_line = 0, 5214 }), 5215 }); 5216 } 5217 5218 const TrackedUnitSema = struct { 5219 /// `null` means we created the node, so should end it. 5220 old_name: ?[std.Progress.Node.max_name_len]u8, 5221 old_analysis_timer: ?Compilation.Timer, 5222 analysis_timer_decl: ?InternPool.TrackedInst.Index, 5223 pub fn end(tus: TrackedUnitSema, zcu: *Zcu) void { 5224 const comp = zcu.comp; 5225 const io = comp.io; 5226 if (tus.old_name) |old_name| { 5227 zcu.sema_prog_node.completeOne(); // we're just renaming, but it's effectively completion 5228 zcu.cur_sema_prog_node.setName(&old_name); 5229 } else { 5230 zcu.cur_sema_prog_node.end(); 5231 zcu.cur_sema_prog_node = .none; 5232 } 5233 report_time: { 5234 const sema_ns = zcu.cur_analysis_timer.?.finish(io) orelse break :report_time; 5235 const zir_decl = tus.analysis_timer_decl orelse break :report_time; 5236 comp.mutex.lockUncancelable(io); 5237 defer comp.mutex.unlock(io); 5238 comp.time_report.?.stats.cpu_ns_sema += sema_ns; 5239 const gop = comp.time_report.?.decl_sema_info.getOrPut(comp.gpa, zir_decl) catch |err| switch (err) { 5240 error.OutOfMemory => { 5241 comp.setAllocFailure(); 5242 break :report_time; 5243 }, 5244 }; 5245 if (!gop.found_existing) gop.value_ptr.* = .{ .ns = 0, .count = 0 }; 5246 gop.value_ptr.ns += sema_ns; 5247 gop.value_ptr.count += 1; 5248 } 5249 zcu.cur_analysis_timer = tus.old_analysis_timer; 5250 if (zcu.cur_analysis_timer) |*t| t.@"resume"(io); 5251 } 5252 }; 5253 pub fn trackUnitSema(zcu: *Zcu, name: []const u8, zir_inst: ?InternPool.TrackedInst.Index) TrackedUnitSema { 5254 const comp = zcu.comp; 5255 const io = comp.io; 5256 if (zcu.cur_analysis_timer) |*t| t.pause(io); 5257 const old_analysis_timer = zcu.cur_analysis_timer; 5258 zcu.cur_analysis_timer = zcu.comp.startTimer(); 5259 const old_name: ?[std.Progress.Node.max_name_len]u8 = old_name: { 5260 if (zcu.cur_sema_prog_node.index == .none) { 5261 zcu.cur_sema_prog_node = zcu.sema_prog_node.start(name, 0); 5262 break :old_name null; 5263 } 5264 const old_name = zcu.cur_sema_prog_node.getName(); 5265 zcu.cur_sema_prog_node.setName(name); 5266 break :old_name old_name; 5267 }; 5268 return .{ 5269 .old_name = old_name, 5270 .old_analysis_timer = old_analysis_timer, 5271 .analysis_timer_decl = zir_inst, 5272 }; 5273 } 5274 5275 pub const CodegenTaskPool = struct { 5276 const CodegenResult = PerThread.RunCodegenError!codegen.AnyMir; 5277 5278 /// In the worst observed case, MIR is around 50 times as large as AIR. More typically, the ratio is 5279 /// around 20. Going by that 50x multiplier, and assuming we want to consume no more than 500 MiB of 5280 /// memory on AIR/MIR, we see a limit of around 10 MiB of AIR in-flight. 5281 const max_air_bytes_in_flight = 10 * 1024 * 1024; 5282 5283 const max_funcs_in_flight = link.Queue.buffer_size; 5284 5285 available_air_bytes: u32, 5286 5287 /// Locks the freelist and `available_air_bytes`. 5288 mutex: Io.Mutex, 5289 5290 /// Signaled when an item is added to the freelist. 5291 free_cond: Io.Condition, 5292 /// Pre-allocated with enough capacity for all indices. 5293 free: std.ArrayList(Index), 5294 5295 /// `.none` means this task is in the freelist. The `task_air_bytes` and 5296 /// `task_futures` entries are `undefined`. 5297 task_funcs: []InternPool.Index, 5298 task_air_bytes: []u32, 5299 task_futures: []Io.Future(CodegenResult), 5300 5301 pub fn init(arena: Allocator) Allocator.Error!CodegenTaskPool { 5302 const task_funcs = try arena.alloc(InternPool.Index, max_funcs_in_flight); 5303 const task_air_bytes = try arena.alloc(u32, max_funcs_in_flight); 5304 const task_futures = try arena.alloc(Io.Future(CodegenResult), max_funcs_in_flight); 5305 @memset(task_funcs, .none); 5306 5307 var free: std.ArrayList(Index) = try .initCapacity(arena, max_funcs_in_flight); 5308 for (0..max_funcs_in_flight) |index| free.appendAssumeCapacity(@fromBackingInt(@intCast(index))); 5309 5310 return .{ 5311 .available_air_bytes = max_air_bytes_in_flight, 5312 .mutex = .init, 5313 .free_cond = .init, 5314 .free = free, 5315 .task_funcs = task_funcs, 5316 .task_air_bytes = task_air_bytes, 5317 .task_futures = task_futures, 5318 }; 5319 } 5320 5321 pub fn cancel(pool: *CodegenTaskPool, zcu: *const Zcu) void { 5322 const io = zcu.comp.io; 5323 for ( 5324 pool.task_funcs, 5325 pool.task_air_bytes, 5326 pool.task_futures, 5327 ) |func, effective_air_bytes, *future| { 5328 if (func == .none) continue; 5329 pool.available_air_bytes += effective_air_bytes; 5330 var mir = future.cancel(io) catch continue; 5331 mir.deinit(zcu); 5332 }