╭─────────────╮╭────────────╮ │scroll to top││next lines →│ ╰─────────────╯╰────────────╯ ╭ Sema.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
3019 .no_embedded_nulls, 3020 ); 3021 const nav = try sema.lookupIdentifier(block, decl_name); 3022 break :capture InternPool.CaptureValue.wrap(.{ .nav_ref = nav }); 3023 }, 3024 }; 3025 } 3026 3027 return captures; 3028 } 3029 3030 fn zirErrorSetDecl( 3031 sema: *Sema, 3032 inst: Zir.Inst.Index, 3033 ) CompileError!Air.Inst.Ref { 3034 const pt = sema.pt; 3035 const zcu = pt.zcu; 3036 const comp = zcu.comp; 3037 const gpa = comp.gpa; 3038 const io = comp.io; 3039 3040 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 3041 const extra = sema.code.extraData(Zir.Inst.ErrorSetDecl, inst_data.payload_index); 3042 3043 var names: InferredErrorSet.NameMap = .{}; 3044 try names.ensureUnusedCapacity(sema.arena, extra.data.fields_len); 3045 3046 var extra_index: u32 = @intCast(extra.end); 3047 const extra_index_end = extra_index + extra.data.fields_len; 3048 while (extra_index < extra_index_end) : (extra_index += 1) { 3049 const name_index: Zir.NullTerminatedString = @fromBackingInt(@intCast(sema.code.extra[extra_index])); 3050 const name = sema.code.nullTerminatedString(name_index); 3051 const name_ip = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls); 3052 _ = try pt.getErrorValue(name_ip); 3053 const result = names.getOrPutAssumeCapacity(name_ip); 3054 assert(!result.found_existing); // verified in AstGen 3055 } 3056 3057 return Air.internedToRef((try pt.errorSetFromUnsortedNames(names.keys())).toIntern()); 3058 } 3059 3060 fn zirRetPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3061 const pt = sema.pt; 3062 const zcu = pt.zcu; 3063 3064 const src = block.nodeOffset(sema.code.instructions.items(.data)[@backingInt(inst)].node); 3065 3066 if (block.isComptime() or sema.fn_ret_ty.comptimeOnly(zcu)) { 3067 return sema.analyzeComptimeAlloc(block, src, sema.fn_ret_ty, .none); 3068 } 3069 3070 const target = zcu.getTarget(); 3071 const ptr_type = try pt.ptrType(.{ 3072 .child = sema.fn_ret_ty.toIntern(), 3073 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, 3074 }); 3075 3076 if (block.inlining != null) { 3077 // We are inlining a function call; this should be emitted as an alloc, not a ret_ptr. 3078 // TODO when functions gain result location support, the inlining struct in 3079 // Block should contain the return pointer, and we would pass that through here. 3080 return block.addTy(.alloc, ptr_type); 3081 } 3082 3083 return block.addTy(.ret_ptr, ptr_type); 3084 } 3085 3086 fn zirRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3087 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_tok; 3088 const operand = sema.resolveInst(inst_data.operand); 3089 return sema.analyzeRef(block, block.tokenOffset(inst_data.src_tok), operand, .none); 3090 } 3091 3092 fn zirDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3093 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3094 const src = block.nodeOffset(inst_data.src_node); 3095 const ptr_src = block.src(.{ .node_offset_deref_ptr = inst_data.src_node }); 3096 const operand = sema.resolveInst(inst_data.operand); 3097 3098 try sema.validateDeref(block, src, operand, sema.typeOf(operand)); 3099 3100 return sema.analyzeLoad(block, src, operand, ptr_src); 3101 } 3102 3103 fn zirRefDeref(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3104 const pt = sema.pt; 3105 const zcu = pt.zcu; 3106 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3107 const src = block.nodeOffset(inst_data.src_node); 3108 const operand = sema.resolveInst(inst_data.operand); 3109 const operand_ty = sema.typeOf(operand); 3110 3111 try sema.validateDeref(block, src, operand, operand_ty); 3112 3113 const ptr_info = operand_ty.ptrInfo(zcu); 3114 return single_ptr: switch (ptr_info.flags.size) { 3115 .many => unreachable, // cannot be dereferenced directly 3116 .slice => { 3117 const slice_val = sema.resolveValue(operand).?; 3118 const slice = zcu.intern_pool.indexToKey(slice_val.toIntern()).slice; 3119 break :single_ptr .fromValue(try pt.sliceToArrayPtr(slice)); 3120 }, 3121 .c => { 3122 const single_ptr_ty = try pt.ptrType(p: { 3123 var p = ptr_info; 3124 p.flags.size = .one; 3125 p.flags.is_allowzero = false; 3126 break :p p; 3127 }); 3128 // https://github.com/ziglang/zig/issues/6597 3129 if (sema.resolveValue(operand)) |operand_val| { 3130 if (!operand_val.isNull(zcu)) { 3131 break :single_ptr .fromValue(try pt.getCoerced(operand_val, single_ptr_ty)); 3132 } 3133 } 3134 if (block.wantSafety()) { 3135 const is_non_null = try block.addUnOp(.is_non_null, operand); 3136 try sema.addSafetyCheck(block, src, is_non_null, .unwrap_null); 3137 } 3138 const single_ptr = try block.addTyOp(.ptr_cast, single_ptr_ty, operand); 3139 try sema.checkKnownAllocPtr(block, operand, single_ptr); 3140 break :single_ptr single_ptr; 3141 }, 3142 .one => operand, 3143 }; 3144 } 3145 3146 fn validateDeref( 3147 sema: *Sema, 3148 block: *Block, 3149 src: LazySrcLoc, 3150 ref: Air.Inst.Ref, 3151 ty: Type, 3152 ) CompileError!void { 3153 const pt = sema.pt; 3154 const zcu = pt.zcu; 3155 const ip = &zcu.intern_pool; 3156 if (ty.zigTypeTag(zcu) != .pointer) { 3157 return sema.fail(block, src, "cannot dereference non-pointer type '{f}'", .{ty.fmt(pt)}); 3158 } 3159 const size = ty.ptrSize(zcu); 3160 switch (size) { 3161 .many => return sema.fail(block, src, "index syntax required for unknown-length pointer type '{f}'", .{ty.fmt(pt)}), 3162 .one, .c, .slice => {}, 3163 } 3164 if (sema.resolveValue(ref)) |val| { 3165 // Error for deref of undef pointer, unless the pointee is OPV in which case it's legal. 3166 if (val.isUndef(zcu) and ty.childType(zcu).classify(zcu) != .one_possible_value) { 3167 return sema.fail(block, src, "cannot dereference undefined value", .{}); 3168 } 3169 // We need a defined slice length for the array type the slice should be dereferenced to. 3170 if (size == .slice and ip.indexToKey(val.toIntern()).slice.len == .undef_usize) { 3171 return sema.fail(block, src, "cannot dereference slice with undefined length", .{}); 3172 } 3173 } else if (size == .slice) { 3174 return sema.fail(block, src, "index syntax required to access runtime-known slice", .{}); 3175 } 3176 } 3177 3178 fn zirEnsureResultUsed(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3179 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3180 const operand = sema.resolveInst(inst_data.operand); 3181 const src = block.nodeOffset(inst_data.src_node); 3182 3183 return sema.ensureResultUsed(block, sema.typeOf(operand), src); 3184 } 3185 3186 fn ensureResultUsed( 3187 sema: *Sema, 3188 block: *Block, 3189 ty: Type, 3190 src: LazySrcLoc, 3191 ) CompileError!void { 3192 const pt = sema.pt; 3193 const zcu = pt.zcu; 3194 switch (ty.zigTypeTag(zcu)) { 3195 .void, .noreturn => return, 3196 .error_set => { 3197 return sema.fail(block, src, "error set of type '{f}' is ignored", .{ty.fmt(pt)}); 3198 }, 3199 .error_union => { 3200 const msg = msg: { 3201 const msg = try sema.errMsg(src, "error union of type '{f}' is ignored", .{ty.fmt(pt)}); 3202 errdefer msg.destroy(sema.gpa); 3203 try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); 3204 break :msg msg; 3205 }; 3206 return sema.failWithOwnedErrorMsg(block, msg); 3207 }, 3208 else => { 3209 const msg = msg: { 3210 const msg = try sema.errMsg(src, "value of type '{f}' ignored", .{ty.fmt(pt)}); 3211 errdefer msg.destroy(sema.gpa); 3212 try sema.errNote(src, msg, "all non-void values must be used", .{}); 3213 try sema.errNote(src, msg, "to discard the value, assign it to '_'", .{}); 3214 break :msg msg; 3215 }; 3216 return sema.failWithOwnedErrorMsg(block, msg); 3217 }, 3218 } 3219 } 3220 3221 fn zirEnsureResultNonError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3222 const pt = sema.pt; 3223 const zcu = pt.zcu; 3224 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3225 const operand = sema.resolveInst(inst_data.operand); 3226 const src = block.nodeOffset(inst_data.src_node); 3227 const operand_ty = sema.typeOf(operand); 3228 switch (operand_ty.zigTypeTag(zcu)) { 3229 .error_set => return sema.fail(block, src, "error set is discarded", .{}), 3230 .error_union => { 3231 const msg = msg: { 3232 const msg = try sema.errMsg(src, "error union is discarded", .{}); 3233 errdefer msg.destroy(sema.gpa); 3234 try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); 3235 break :msg msg; 3236 }; 3237 return sema.failWithOwnedErrorMsg(block, msg); 3238 }, 3239 else => return, 3240 } 3241 } 3242 3243 fn zirEnsureErrUnionPayloadVoid(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 3244 const pt = sema.pt; 3245 const zcu = pt.zcu; 3246 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3247 const src = block.nodeOffset(inst_data.src_node); 3248 const operand = sema.resolveInst(inst_data.operand); 3249 const operand_ty = sema.typeOf(operand); 3250 const err_union_ty = if (operand_ty.zigTypeTag(zcu) == .pointer) 3251 operand_ty.childType(zcu) 3252 else 3253 operand_ty; 3254 if (err_union_ty.zigTypeTag(zcu) != .error_union) return; 3255 const payload_ty = err_union_ty.errorUnionPayload(zcu).zigTypeTag(zcu); 3256 if (payload_ty != .void and payload_ty != .noreturn) { 3257 const msg = msg: { 3258 const msg = try sema.errMsg(src, "error union payload is ignored", .{}); 3259 errdefer msg.destroy(sema.gpa); 3260 try sema.errNote(src, msg, "payload value can be explicitly ignored with '|_|'", .{}); 3261 break :msg msg; 3262 }; 3263 return sema.failWithOwnedErrorMsg(block, msg); 3264 } 3265 } 3266 3267 fn zirIndexablePtrLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3268 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3269 const src = block.nodeOffset(inst_data.src_node); 3270 const object = sema.resolveInst(inst_data.operand); 3271 3272 return indexablePtrLen(sema, block, src, object); 3273 } 3274 3275 fn indexablePtrLen( 3276 sema: *Sema, 3277 block: *Block, 3278 src: LazySrcLoc, 3279 object: Air.Inst.Ref, 3280 ) CompileError!Air.Inst.Ref { 3281 const pt = sema.pt; 3282 const zcu = pt.zcu; 3283 const comp = zcu.comp; 3284 const gpa = comp.gpa; 3285 const io = comp.io; 3286 const object_ty = sema.typeOf(object); 3287 const is_pointer_to = object_ty.isSinglePointer(zcu); 3288 const indexable_ty = if (is_pointer_to) object_ty.childType(zcu) else object_ty; 3289 try sema.checkIndexable(block, src, indexable_ty); 3290 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls); 3291 return sema.fieldVal(block, src, object, field_name, src); 3292 } 3293 3294 fn indexablePtrLenOrNone( 3295 sema: *Sema, 3296 block: *Block, 3297 src: LazySrcLoc, 3298 operand: Air.Inst.Ref, 3299 ) CompileError!Air.Inst.Ref { 3300 const pt = sema.pt; 3301 const zcu = pt.zcu; 3302 const comp = zcu.comp; 3303 const gpa = comp.gpa; 3304 const io = comp.io; 3305 const operand_ty = sema.typeOf(operand); 3306 try checkMemOperand(sema, block, src, operand_ty); 3307 switch (operand_ty.ptrSize(zcu)) { 3308 .many, .c => return .none, 3309 .one, .slice => {}, 3310 } 3311 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls); 3312 return sema.fieldVal(block, src, operand, field_name, src); 3313 } 3314 3315 fn zirAllocExtended( 3316 sema: *Sema, 3317 block: *Block, 3318 extended: Zir.Inst.Extended.InstData, 3319 ) CompileError!Air.Inst.Ref { 3320 const pt = sema.pt; 3321 const zcu = pt.zcu; 3322 const gpa = sema.gpa; 3323 const extra = sema.code.extraData(Zir.Inst.AllocExtended, extended.operand); 3324 const var_src = block.nodeOffset(extra.data.src_node); 3325 const ty_src = block.src(.{ .node_offset_var_decl_ty = extra.data.src_node }); 3326 const align_src = block.src(.{ .node_offset_var_decl_align = extra.data.src_node }); 3327 const small: Zir.Inst.AllocExtended.Small = @bitCast(extended.small); 3328 3329 var extra_index: usize = extra.end; 3330 3331 const var_ty: Type = if (small.has_type) blk: { 3332 const type_ref: Zir.Inst.Ref = @fromBackingInt(@intCast(sema.code.extra[extra_index])); 3333 extra_index += 1; 3334 break :blk try sema.resolveType(block, ty_src, type_ref); 3335 } else undefined; 3336 3337 const alignment = if (small.has_align) blk: { 3338 const align_ref: Zir.Inst.Ref = @fromBackingInt(@intCast(sema.code.extra[extra_index])); 3339 extra_index += 1; 3340 break :blk try sema.resolveAlign(block, align_src, align_ref); 3341 } else .none; 3342 3343 if (small.has_type) { 3344 try sema.ensureLayoutResolved(var_ty, var_src, if (small.is_const) .constant else .variable); 3345 if (block.isComptime() or small.is_comptime or var_ty.comptimeOnly(zcu)) { 3346 return sema.analyzeComptimeAlloc(block, var_src, var_ty, alignment); 3347 } 3348 if (!small.is_const) { 3349 try sema.validateVarType(block, ty_src, var_ty, false); 3350 } 3351 const target = pt.zcu.getTarget(); 3352 if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) { 3353 const store_src = block.src(.{ .node_offset_store_ptr = extra.data.src_node }); 3354 return sema.fail(block, store_src, "local variable in naked function", .{}); 3355 } 3356 const ptr_type = try pt.ptrType(.{ 3357 .child = var_ty.toIntern(), 3358 .flags = .{ 3359 .alignment = alignment, 3360 .address_space = target_util.defaultAddressSpace(target, .local), 3361 }, 3362 }); 3363 const ptr = try block.addTy(.alloc, ptr_type); 3364 if (small.is_const) { 3365 const ptr_inst = ptr.toIndex().?; 3366 try sema.maybe_comptime_allocs.put(gpa, ptr_inst, .{ .runtime_index = block.runtime_index }); 3367 try sema.base_allocs.put(gpa, ptr_inst, ptr_inst); 3368 } 3369 return ptr; 3370 } 3371 3372 if (block.isComptime() or small.is_comptime) { 3373 const iac_index: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 3374 try sema.air_instructions.append(gpa, .{ 3375 .tag = .inferred_alloc_comptime, 3376 .data = .{ .inferred_alloc_comptime = .{ 3377 .alignment = alignment, 3378 .is_const = small.is_const, 3379 .ptr = undefined, 3380 } }, 3381 }); 3382 return iac_index.toRef(); 3383 } 3384 3385 const result_index = try block.addInstAsIndex(.{ 3386 .tag = .inferred_alloc, 3387 .data = .{ .inferred_alloc = .{ 3388 .alignment = alignment, 3389 .is_const = small.is_const, 3390 } }, 3391 }); 3392 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); 3393 if (small.is_const) { 3394 try sema.maybe_comptime_allocs.put(gpa, result_index, .{ .runtime_index = block.runtime_index }); 3395 try sema.base_allocs.put(gpa, result_index, result_index); 3396 } 3397 return result_index.toRef(); 3398 } 3399 3400 fn zirAllocComptime(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3401 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3402 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); 3403 const var_src = block.nodeOffset(inst_data.src_node); 3404 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3405 try sema.ensureLayoutResolved(var_ty, var_src, .variable); 3406 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); 3407 } 3408 3409 fn zirMakePtrConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3410 const pt = sema.pt; 3411 const zcu = pt.zcu; 3412 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3413 const alloc = sema.resolveInst(inst_data.operand); 3414 const alloc_ty = sema.typeOf(alloc); 3415 const ptr_info = alloc_ty.ptrInfo(zcu); 3416 const elem_ty: Type = .fromInterned(ptr_info.child); 3417 3418 // If the alloc was created in a comptime scope, we already created a comptime alloc for it. 3419 // However, if the final constructed value does not reference comptime-mutable memory, we wish 3420 // to promote it to an anon decl. 3421 already_ct: { 3422 const ptr_val = sema.resolveValue(alloc) orelse break :already_ct; 3423 3424 // If this was a comptime inferred alloc, then `storeToInferredAllocComptime` 3425 // might have already done our job and created an anon decl ref. 3426 switch (zcu.intern_pool.indexToKey(ptr_val.toIntern())) { 3427 .ptr => |ptr| switch (ptr.base_addr) { 3428 .uav => { 3429 // The comptime-ification was already done for us. 3430 // Just make sure the pointer is const. 3431 return sema.makePtrConst(block, alloc); 3432 }, 3433 else => {}, 3434 }, 3435 else => {}, 3436 } 3437 3438 if (!sema.isComptimeMutablePtr(ptr_val)) break :already_ct; 3439 const ptr = zcu.intern_pool.indexToKey(ptr_val.toIntern()).ptr; 3440 assert(ptr.byte_offset == 0); 3441 const alloc_index = ptr.base_addr.comptime_alloc; 3442 const ct_alloc = sema.getComptimeAlloc(alloc_index); 3443 const interned = try ct_alloc.val.intern(pt, sema.arena); 3444 if (interned.canMutateComptimeVarState(zcu)) { 3445 // Preserve the comptime alloc, just make the pointer const. 3446 ct_alloc.val = .{ .interned = interned.toIntern() }; 3447 ct_alloc.is_const = true; 3448 return sema.makePtrConst(block, alloc); 3449 } else { 3450 // Promote the constant to an anon decl. 3451 const new_mut_ptr = Air.internedToRef(try pt.intern(.{ .ptr = .{ 3452 .ty = alloc_ty.toIntern(), 3453 .base_addr = .{ .uav = .{ 3454 .val = interned.toIntern(), 3455 .orig_ty = alloc_ty.toIntern(), 3456 } }, 3457 .byte_offset = 0, 3458 } })); 3459 return sema.makePtrConst(block, new_mut_ptr); 3460 } 3461 } 3462 3463 // Otherwise, check if the alloc is comptime-known despite being in a runtime scope. 3464 if (try sema.resolveComptimeKnownAllocPtr(block, alloc, null)) |ptr_val| { 3465 return sema.makePtrConst(block, Air.internedToRef(ptr_val)); 3466 } 3467 3468 if (elem_ty.comptimeOnly(zcu)) { 3469 // The value was initialized through RLS, so we didn't detect the runtime condition earlier. 3470 // TODO: source location of runtime control flow 3471 const init_src = block.src(.{ .node_offset_var_decl_init = inst_data.src_node }); 3472 return sema.fail(block, init_src, "value with comptime-only type '{f}' depends on runtime control flow", .{elem_ty.fmt(pt)}); 3473 } 3474 3475 // This is a runtime value. 3476 return sema.makePtrConst(block, alloc); 3477 } 3478 3479 /// If `alloc` is an inferred allocation, `resolved_inferred_ty` is taken to be its resolved 3480 /// type. Otherwise, it may be `null`, and the type will be inferred from `alloc`. 3481 fn resolveComptimeKnownAllocPtr(sema: *Sema, block: *Block, alloc: Air.Inst.Ref, resolved_alloc_ty: ?Type) CompileError!?InternPool.Index { 3482 const pt = sema.pt; 3483 const zcu = pt.zcu; 3484 const comp = zcu.comp; 3485 const gpa = comp.gpa; 3486 const io = comp.io; 3487 3488 const alloc_ty = resolved_alloc_ty orelse sema.typeOf(alloc); 3489 const ptr_info = alloc_ty.ptrInfo(zcu); 3490 const elem_ty: Type = .fromInterned(ptr_info.child); 3491 elem_ty.assertHasLayout(zcu); 3492 3493 const alloc_inst = alloc.toIndex() orelse return null; 3494 const comptime_info = sema.maybe_comptime_allocs.fetchRemove(alloc_inst) orelse return null; 3495 const stores = comptime_info.value.stores.items(.inst); 3496 3497 // If the elem type is OPV, no need to faff about with `stores`; just use the OPV. 3498 if (try elem_ty.onePossibleValue(pt)) |opv| { 3499 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, opv.toIntern(), null, alloc_inst, comptime_info.value); 3500 } 3501 3502 // Since the elem type isn't OPV, there should have been at least one store. 3503 assert(stores.len > 0); 3504 3505 // Since the entry existed in `maybe_comptime_allocs`, the allocation is comptime-known. 3506 // We will resolve and return its value. 3507 3508 // In general, we want to create a comptime alloc of the correct type and 3509 // apply the stores to that alloc in order. However, before going to all 3510 // that effort, let's optimize for the common case of a single store. 3511 3512 simple: { 3513 if (stores.len != 1) break :simple; 3514 const store_inst = sema.air_instructions.get(@backingInt(stores[0])); 3515 switch (store_inst.tag) { 3516 .store, .store_safe => {}, 3517 .set_union_tag, .optional_payload_ptr_set, .errunion_payload_ptr_set => break :simple, // there's OPV stuff going on! 3518 else => unreachable, 3519 } 3520 if (store_inst.data.bin_op.lhs != alloc) break :simple; 3521 3522 const val = store_inst.data.bin_op.rhs.toInterned().?; 3523 assert(zcu.intern_pool.typeOf(val) == elem_ty.toIntern()); 3524 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, null, alloc_inst, comptime_info.value); 3525 } 3526 3527 // The simple strategy failed: we must create a mutable comptime alloc and 3528 // perform all of the runtime store operations at comptime. 3529 3530 const ct_alloc = try sema.newComptimeAlloc(block, .unneeded, elem_ty, ptr_info.flags.alignment); 3531 3532 const alloc_ptr = try pt.intern(.{ .ptr = .{ 3533 .ty = alloc_ty.toIntern(), 3534 .base_addr = .{ .comptime_alloc = ct_alloc }, 3535 .byte_offset = 0, 3536 } }); 3537 3538 // Maps from pointers into the runtime allocs, to comptime-mutable pointers into the comptime alloc 3539 var ptr_mapping = std.AutoHashMap(Air.Inst.Index, InternPool.Index).init(sema.arena); 3540 try ptr_mapping.ensureTotalCapacity(@intCast(stores.len)); 3541 ptr_mapping.putAssumeCapacity(alloc_inst, alloc_ptr); 3542 3543 // Whilst constructing our mapping, we will also initialize optional and error union payloads when 3544 // we encounter the corresponding pointers. For this reason, the ordering of `to_map` matters. 3545 var to_map = try std.array_list.Managed(Air.Inst.Index).initCapacity(sema.arena, stores.len); 3546 3547 for (stores) |store_inst_idx| { 3548 const store_inst = sema.air_instructions.get(@backingInt(store_inst_idx)); 3549 const ptr_to_map = switch (store_inst.tag) { 3550 .store, .store_safe => store_inst.data.bin_op.lhs.toIndex().?, // Map the pointer being stored to. 3551 .set_union_tag => store_inst.data.bin_op.lhs.toIndex().?, // Map the union pointer. 3552 .optional_payload_ptr_set, .errunion_payload_ptr_set => store_inst_idx, // Map the generated pointer itself. 3553 else => unreachable, 3554 }; 3555 to_map.appendAssumeCapacity(ptr_to_map); 3556 } 3557 3558 const tmp_air = sema.getTmpAir(); 3559 3560 while (to_map.pop()) |air_ptr| { 3561 if (ptr_mapping.contains(air_ptr)) continue; 3562 const PointerMethod = union(enum) { 3563 same_addr, 3564 opt_payload, 3565 eu_payload, 3566 field: u32, 3567 elem: u64, 3568 }; 3569 const inst_tag = tmp_air.instructions.items(.tag)[@backingInt(air_ptr)]; 3570 const air_parent_ptr: Air.Inst.Ref, const method: PointerMethod = switch (inst_tag) { 3571 .struct_field_ptr => blk: { 3572 const data = tmp_air.extraData( 3573 Air.StructField, 3574 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_pl.payload, 3575 ).data; 3576 break :blk .{ 3577 data.struct_operand, 3578 .{ .field = data.field_index }, 3579 }; 3580 }, 3581 .struct_field_ptr_index_0, 3582 .struct_field_ptr_index_1, 3583 .struct_field_ptr_index_2, 3584 .struct_field_ptr_index_3, 3585 => .{ 3586 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_op.operand, 3587 .{ .field = switch (inst_tag) { 3588 .struct_field_ptr_index_0 => 0, 3589 .struct_field_ptr_index_1 => 1, 3590 .struct_field_ptr_index_2 => 2, 3591 .struct_field_ptr_index_3 => 3, 3592 else => unreachable, 3593 } }, 3594 }, 3595 .ptr_slice_ptr_ptr => .{ 3596 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_op.operand, 3597 .{ .field = Value.slice_ptr_index }, 3598 }, 3599 .ptr_slice_len_ptr => .{ 3600 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_op.operand, 3601 .{ .field = Value.slice_len_index }, 3602 }, 3603 .ptr_elem_ptr => blk: { 3604 const data = tmp_air.extraData( 3605 Air.Bin, 3606 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_pl.payload, 3607 ).data; 3608 const idx_val = sema.resolveValue(data.rhs).?; 3609 break :blk .{ 3610 data.lhs, 3611 .{ .elem = idx_val.toUnsignedInt(zcu) }, 3612 }; 3613 }, 3614 .ptr_cast => .{ 3615 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_op.operand, 3616 .same_addr, 3617 }, 3618 .optional_payload_ptr_set => .{ 3619 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_op.operand, 3620 .opt_payload, 3621 }, 3622 .errunion_payload_ptr_set => .{ 3623 tmp_air.instructions.items(.data)[@backingInt(air_ptr)].ty_op.operand, 3624 .eu_payload, 3625 }, 3626 else => unreachable, 3627 }; 3628 3629 const decl_parent_ptr = ptr_mapping.get(air_parent_ptr.toIndex().?) orelse { 3630 // Resolve the parent pointer first. 3631 // Note that we add in what seems like the wrong order, because we're popping from the end of this array. 3632 try to_map.appendSlice(&.{ air_ptr, air_parent_ptr.toIndex().? }); 3633 continue; 3634 }; 3635 const new_ptr_ty = tmp_air.typeOfIndex(air_ptr, &zcu.intern_pool).toIntern(); 3636 const new_ptr = switch (method) { 3637 .same_addr => try zcu.intern_pool.getCoerced(gpa, io, pt.tid, decl_parent_ptr, new_ptr_ty), 3638 .opt_payload => ptr: { 3639 // Set the optional to non-null at comptime. 3640 // If the payload is OPV, we must use that value instead of undef. 3641 const opt_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); 3642 const payload_ty = opt_ty.optionalChild(zcu); 3643 const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty); 3644 const opt_val = try pt.intern(.{ .opt = .{ 3645 .ty = opt_ty.toIntern(), 3646 .val = payload_val.toIntern(), 3647 } }); 3648 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(opt_val), opt_ty); 3649 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrOptPayload(pt)).toIntern(); 3650 }, 3651 .eu_payload => ptr: { 3652 // Set the error union to non-error at comptime. 3653 // If the payload is OPV, we must use that value instead of undef. 3654 const eu_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); 3655 const payload_ty = eu_ty.errorUnionPayload(zcu); 3656 const payload_val = try payload_ty.onePossibleValue(pt) orelse try pt.undefValue(payload_ty); 3657 const eu_val = try pt.intern(.{ .error_union = .{ 3658 .ty = eu_ty.toIntern(), 3659 .val = .{ .payload = payload_val.toIntern() }, 3660 } }); 3661 try sema.storePtrVal(block, LazySrcLoc.unneeded, Value.fromInterned(decl_parent_ptr), Value.fromInterned(eu_val), eu_ty); 3662 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrEuPayload(pt)).toIntern(); 3663 }, 3664 .field => |idx| ptr: { 3665 const maybe_union_ty = Value.fromInterned(decl_parent_ptr).typeOf(zcu).childType(zcu); 3666 if (zcu.typeToUnion(maybe_union_ty)) |union_obj| if (union_obj.layout == .auto) { 3667 // As this is a union field, we must store to the pointer now to set the tag. 3668 // The payload value will be stored later, so undef is a sufficent payload for now. 3669 const payload_ty: Type = .fromInterned(union_obj.field_types.get(&zcu.intern_pool)[idx]); 3670 const payload_val = try pt.undefValue(payload_ty); 3671 const tag_val = try pt.enumValueFieldIndex(.fromInterned(union_obj.enum_tag_type), idx); 3672 const store_val = try pt.unionValue(maybe_union_ty, tag_val, payload_val); 3673 try sema.storePtrVal(block, .unneeded, .fromInterned(decl_parent_ptr), store_val, maybe_union_ty); 3674 }; 3675 break :ptr (try Value.fromInterned(decl_parent_ptr).ptrField(idx, pt)).toIntern(); 3676 }, 3677 .elem => |idx| ptr: { 3678 const parent_ptr_val: Value = .fromInterned(decl_parent_ptr); 3679 if (parent_ptr_val.typeOf(zcu).childType(zcu).zigTypeTag(zcu) == .vector) { 3680 const elem_ptr_ty: Type = .fromInterned(new_ptr_ty); 3681 // Vectors are a bit weird; see logic in `elemPtrVector`. 3682 if (elem_ptr_ty.ptrInfo(zcu).flags.vector_index != .none) { 3683 break :ptr (try pt.getCoerced(parent_ptr_val, elem_ptr_ty)).toIntern(); 3684 } else { 3685 const bit_offset = idx * @divExact(elem_ptr_ty.childType(zcu).bitSize(zcu), 8); 3686 break :ptr (try parent_ptr_val.getOffsetPtr(bit_offset, elem_ptr_ty, pt)).toIntern(); 3687 } 3688 } 3689 break :ptr (try parent_ptr_val.ptrElem(idx, pt)).toIntern(); 3690 }, 3691 }; 3692 try ptr_mapping.put(air_ptr, new_ptr); 3693 } 3694 3695 // We have a correlation between AIR pointers and decl pointers. Perform all stores at comptime. 3696 // Any implicit stores performed by `optional_payload_ptr_set` or `errunion_payload_ptr_set` 3697 // instructions were already done above. 3698 3699 for (stores) |store_inst_idx| { 3700 const store_inst = sema.air_instructions.get(@backingInt(store_inst_idx)); 3701 switch (store_inst.tag) { 3702 .optional_payload_ptr_set, .errunion_payload_ptr_set => {}, // Handled explicitly above 3703 .set_union_tag => { 3704 // Usually, we can ignore these, because the creation of the field pointer above 3705 // already did it for us. However, if the field is OPV, this is relevant, because 3706 // there is not going to be a store to the field. So we must initialize the union 3707 // tag if the field is OPV. 3708 const union_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?; 3709 const union_ptr_val: Value = .fromInterned(ptr_mapping.get(union_ptr_inst).?); 3710 const tag_val: Value = .fromInterned(store_inst.data.bin_op.rhs.toInterned().?); 3711 const union_ty = union_ptr_val.typeOf(zcu).childType(zcu); 3712 const field_ty = union_ty.unionFieldType(tag_val, zcu).?; 3713 if (try field_ty.onePossibleValue(pt)) |payload_val| { 3714 const new_union_val = try pt.unionValue(union_ty, tag_val, payload_val); 3715 try sema.storePtrVal(block, .unneeded, union_ptr_val, new_union_val, union_ty); 3716 } 3717 }, 3718 .store, .store_safe => { 3719 const air_ptr_inst = store_inst.data.bin_op.lhs.toIndex().?; 3720 const store_val = sema.resolveValue(store_inst.data.bin_op.rhs).?; 3721 const new_ptr = ptr_mapping.get(air_ptr_inst).?; 3722 try sema.storePtrVal(block, .unneeded, .fromInterned(new_ptr), store_val, store_val.typeOf(zcu)); 3723 }, 3724 else => unreachable, 3725 } 3726 } 3727 3728 // The value is finalized - load it! 3729 const val = (try sema.pointerDeref(block, LazySrcLoc.unneeded, Value.fromInterned(alloc_ptr), alloc_ty)).?.toIntern(); 3730 return sema.finishResolveComptimeKnownAllocPtr(block, alloc_ty, val, ct_alloc, alloc_inst, comptime_info.value); 3731 } 3732 3733 /// Given the resolved comptime-known value, rewrites the dead AIR to not 3734 /// create a runtime stack allocation. Also places the resulting value into 3735 /// either an anon decl ref or a comptime alloc depending on whether it 3736 /// references comptime-mutable memory. If `existing_comptime_alloc` is 3737 /// passed, it is a scratch allocation which already contains `result_val`. 3738 /// Same return type as `resolveComptimeKnownAllocPtr` so we can tail call. 3739 fn finishResolveComptimeKnownAllocPtr( 3740 sema: *Sema, 3741 block: *Block, 3742 alloc_ty: Type, 3743 result_val: InternPool.Index, 3744 existing_comptime_alloc: ?ComptimeAllocIndex, 3745 alloc_inst: Air.Inst.Index, 3746 comptime_info: MaybeComptimeAlloc, 3747 ) CompileError!?InternPool.Index { 3748 const pt = sema.pt; 3749 const zcu = pt.zcu; 3750 3751 // We're almost done - we have the resolved comptime value. We just need to 3752 // eliminate the now-dead runtime instructions. 3753 3754 // This instruction has type `alloc_ty`, meaning we can rewrite the `alloc` AIR instruction to 3755 // this one to drop the side effect. We also need to rewrite the stores; we'll turn them to this 3756 // too because it doesn't really matter what they become. 3757 const nop_inst: Air.Inst = .{ .tag = .ptr_from_int, .data = .{ .ty_op = .{ 3758 .ty = alloc_ty, 3759 .operand = .zero_usize, 3760 } } }; 3761 3762 sema.air_instructions.set(@backingInt(alloc_inst), nop_inst); 3763 for (comptime_info.stores.items(.inst)) |store_inst| { 3764 sema.air_instructions.set(@backingInt(store_inst), nop_inst); 3765 } 3766 3767 if (Value.fromInterned(result_val).canMutateComptimeVarState(zcu)) { 3768 const alloc_index = existing_comptime_alloc orelse a: { 3769 const idx = try sema.newComptimeAlloc(block, .unneeded, alloc_ty.childType(zcu), alloc_ty.ptrAlignment(zcu)); 3770 const alloc = sema.getComptimeAlloc(idx); 3771 alloc.val = .{ .interned = result_val }; 3772 break :a idx; 3773 }; 3774 sema.getComptimeAlloc(alloc_index).is_const = true; 3775 return try pt.intern(.{ .ptr = .{ 3776 .ty = alloc_ty.toIntern(), 3777 .base_addr = .{ .comptime_alloc = alloc_index }, 3778 .byte_offset = 0, 3779 } }); 3780 } else { 3781 return try pt.intern(.{ .ptr = .{ 3782 .ty = alloc_ty.toIntern(), 3783 .base_addr = .{ .uav = .{ 3784 .orig_ty = alloc_ty.toIntern(), 3785 .val = result_val, 3786 } }, 3787 .byte_offset = 0, 3788 } }); 3789 } 3790 } 3791 3792 fn makePtrTyConst(sema: *Sema, ptr_ty: Type) CompileError!Type { 3793 var ptr_info = ptr_ty.ptrInfo(sema.pt.zcu); 3794 ptr_info.flags.is_const = true; 3795 return sema.pt.ptrType(ptr_info); 3796 } 3797 3798 fn makePtrConst(sema: *Sema, block: *Block, alloc: Air.Inst.Ref) CompileError!Air.Inst.Ref { 3799 const alloc_ty = sema.typeOf(alloc); 3800 const const_ptr_ty = try sema.makePtrTyConst(alloc_ty); 3801 3802 // Detect if a comptime value simply needs to have its type changed. 3803 if (sema.resolveValue(alloc)) |val| { 3804 return Air.internedToRef((try sema.pt.getCoerced(val, const_ptr_ty)).toIntern()); 3805 } 3806 3807 return block.addTyOp(.ptr_cast, const_ptr_ty, alloc); 3808 } 3809 3810 fn zirAllocInferredComptime( 3811 sema: *Sema, 3812 is_const: bool, 3813 ) CompileError!Air.Inst.Ref { 3814 const gpa = sema.gpa; 3815 3816 try sema.air_instructions.append(gpa, .{ 3817 .tag = .inferred_alloc_comptime, 3818 .data = .{ .inferred_alloc_comptime = .{ 3819 .alignment = .none, 3820 .is_const = is_const, 3821 .ptr = undefined, 3822 } }, 3823 }); 3824 return @as(Air.Inst.Index, @fromBackingInt(@intCast(sema.air_instructions.len - 1))).toRef(); 3825 } 3826 3827 fn zirAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3828 const pt = sema.pt; 3829 const zcu = pt.zcu; 3830 3831 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3832 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); 3833 const var_src = block.nodeOffset(inst_data.src_node); 3834 3835 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3836 try sema.ensureLayoutResolved(var_ty, var_src, .constant); 3837 if (block.isComptime() or var_ty.comptimeOnly(zcu)) { 3838 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); 3839 } 3840 if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) { 3841 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); 3842 return sema.fail(block, mut_src, "local variable in naked function", .{}); 3843 } 3844 const target = zcu.getTarget(); 3845 const ptr_type = try pt.ptrType(.{ 3846 .child = var_ty.toIntern(), 3847 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, 3848 }); 3849 const ptr = try block.addTy(.alloc, ptr_type); 3850 const ptr_inst = ptr.toIndex().?; 3851 try sema.maybe_comptime_allocs.put(sema.gpa, ptr_inst, .{ .runtime_index = block.runtime_index }); 3852 try sema.base_allocs.put(sema.gpa, ptr_inst, ptr_inst); 3853 return ptr; 3854 } 3855 3856 fn zirAllocMut(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3857 const pt = sema.pt; 3858 const zcu = pt.zcu; 3859 3860 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3861 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); 3862 const var_src = block.nodeOffset(inst_data.src_node); 3863 3864 const var_ty = try sema.resolveType(block, ty_src, inst_data.operand); 3865 try sema.ensureLayoutResolved(var_ty, var_src, .variable); 3866 if (block.isComptime()) { 3867 return sema.analyzeComptimeAlloc(block, var_src, var_ty, .none); 3868 } 3869 if (sema.func_is_naked and var_ty.hasRuntimeBits(zcu)) { 3870 const store_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); 3871 return sema.fail(block, store_src, "local variable in naked function", .{}); 3872 } 3873 try sema.validateVarType(block, ty_src, var_ty, false); 3874 const target = zcu.getTarget(); 3875 const ptr_type = try pt.ptrType(.{ 3876 .child = var_ty.toIntern(), 3877 .flags = .{ .address_space = target_util.defaultAddressSpace(target, .local) }, 3878 }); 3879 return block.addTy(.alloc, ptr_type); 3880 } 3881 3882 fn zirAllocInferred( 3883 sema: *Sema, 3884 block: *Block, 3885 is_const: bool, 3886 ) CompileError!Air.Inst.Ref { 3887 const gpa = sema.gpa; 3888 3889 if (block.isComptime()) { 3890 try sema.air_instructions.append(gpa, .{ 3891 .tag = .inferred_alloc_comptime, 3892 .data = .{ .inferred_alloc_comptime = .{ 3893 .alignment = .none, 3894 .is_const = is_const, 3895 .ptr = undefined, 3896 } }, 3897 }); 3898 return @as(Air.Inst.Index, @fromBackingInt(@intCast(sema.air_instructions.len - 1))).toRef(); 3899 } 3900 3901 const result_index = try block.addInstAsIndex(.{ 3902 .tag = .inferred_alloc, 3903 .data = .{ .inferred_alloc = .{ 3904 .alignment = .none, 3905 .is_const = is_const, 3906 } }, 3907 }); 3908 try sema.unresolved_inferred_allocs.putNoClobber(gpa, result_index, .{}); 3909 if (is_const) { 3910 try sema.maybe_comptime_allocs.put(gpa, result_index, .{ .runtime_index = block.runtime_index }); 3911 try sema.base_allocs.put(sema.gpa, result_index, result_index); 3912 } 3913 return result_index.toRef(); 3914 } 3915 3916 fn zirResolveInferredAlloc(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 3917 const pt = sema.pt; 3918 const zcu = pt.zcu; 3919 const gpa = sema.gpa; 3920 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 3921 const src = block.nodeOffset(inst_data.src_node); 3922 const ty_src = block.src(.{ .node_offset_var_decl_ty = inst_data.src_node }); 3923 const ptr = sema.resolveInst(inst_data.operand); 3924 const ptr_inst = ptr.toIndex().?; 3925 const target = zcu.getTarget(); 3926 3927 switch (sema.air_instructions.items(.tag)[@backingInt(ptr_inst)]) { 3928 .inferred_alloc_comptime => { 3929 // The work was already done for us by `Sema.storeToInferredAllocComptime`. Also, since 3930 // we had a value of the exact correct type to store, the result type's layout must be 3931 // already resolved. So all we need to do here is return the pointer. 3932 const iac = sema.air_instructions.items(.data)[@backingInt(ptr_inst)].inferred_alloc_comptime; 3933 const resolved_ptr = iac.ptr; 3934 3935 if (std.debug.runtime_safety) { 3936 // The inferred_alloc_comptime should never be referenced again 3937 sema.air_instructions.set(@backingInt(ptr_inst), .{ .tag = undefined, .data = undefined }); 3938 } 3939 3940 const val = switch (zcu.intern_pool.indexToKey(resolved_ptr).ptr.base_addr) { 3941 .uav => |a| a.val, 3942 .comptime_alloc => |i| val: { 3943 const alloc = sema.getComptimeAlloc(i); 3944 break :val (try alloc.val.intern(pt, sema.arena)).toIntern(); 3945 }, 3946 else => unreachable, 3947 }; 3948 if (zcu.intern_pool.isFuncBody(val)) { 3949 const ty: Type = .fromInterned(zcu.intern_pool.typeOf(val)); 3950 if (ty.fnHasRuntimeBits(zcu)) { 3951 const orig_fn_index = zcu.intern_pool.unwrapCoercedFunc(val); 3952 try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index })); 3953 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index); 3954 } 3955 } 3956 3957 return Air.internedToRef(resolved_ptr); 3958 }, 3959 .inferred_alloc => { 3960 const ia1 = sema.air_instructions.items(.data)[@backingInt(ptr_inst)].inferred_alloc; 3961 const ia2 = sema.unresolved_inferred_allocs.fetchSwapRemove(ptr_inst).?.value; 3962 const peer_vals = try sema.arena.alloc(Air.Inst.Ref, ia2.prongs.items.len); 3963 for (peer_vals, ia2.prongs.items) |*peer_val, store_inst| { 3964 assert(sema.air_instructions.items(.tag)[@backingInt(store_inst)] == .store); 3965 const bin_op = sema.air_instructions.items(.data)[@backingInt(store_inst)].bin_op; 3966 peer_val.* = bin_op.rhs; 3967 } 3968 const final_elem_ty = try sema.resolvePeerTypes(block, ty_src, peer_vals, .none); 3969 // The layout of the peers is already resolved, so the layout of `final_elem_ty` is too. 3970 final_elem_ty.assertHasLayout(zcu); 3971 3972 const final_ptr_ty = try pt.ptrType(.{ 3973 .child = final_elem_ty.toIntern(), 3974 .flags = .{ 3975 .alignment = ia1.alignment, 3976 .address_space = target_util.defaultAddressSpace(target, .local), 3977 }, 3978 }); 3979 3980 if (!ia1.is_const) { 3981 try sema.validateVarType(block, ty_src, final_elem_ty, false); 3982 } else if (try sema.resolveComptimeKnownAllocPtr(block, ptr, final_ptr_ty)) |ptr_val| { 3983 const const_ptr_ty = try sema.makePtrTyConst(final_ptr_ty); 3984 const new_const_ptr = try pt.getCoerced(Value.fromInterned(ptr_val), const_ptr_ty); 3985 3986 return Air.internedToRef(new_const_ptr.toIntern()); 3987 } 3988 3989 if (final_elem_ty.comptimeOnly(zcu)) { 3990 // The alloc wasn't comptime-known per the above logic, so the 3991 // type cannot be comptime-only. 3992 // TODO: source location of runtime control flow 3993 return sema.fail(block, src, "value with comptime-only type '{f}' depends on runtime control flow", .{final_elem_ty.fmt(pt)}); 3994 } 3995 if (sema.func_is_naked and final_elem_ty.hasRuntimeBits(zcu)) { 3996 const mut_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); 3997 return sema.fail(block, mut_src, "local variable in naked function", .{}); 3998 } 3999 // Change it to a normal alloc. 4000 sema.air_instructions.set(@backingInt(ptr_inst), .{ 4001 .tag = .alloc, 4002 .data = .{ .ty = final_ptr_ty }, 4003 }); 4004 4005 // Now we need to go back over all the store instructions, and do the logic as if 4006 // the new result ptr type was available. 4007 4008 for (ia2.prongs.items) |placeholder_inst| { 4009 var replacement_block = block.makeSubBlock(); 4010 defer replacement_block.instructions.deinit(gpa); 4011 4012 assert(sema.air_instructions.items(.tag)[@backingInt(placeholder_inst)] == .store); 4013 const bin_op = sema.air_instructions.items(.data)[@backingInt(placeholder_inst)].bin_op; 4014 try sema.storePtr2(&replacement_block, src, bin_op.lhs, src, bin_op.rhs, src, .store); 4015 4016 // If only one instruction is produced then we can replace the store 4017 // placeholder instruction with this instruction; no need for an entire block. 4018 if (replacement_block.instructions.items.len == 1) { 4019 const only_inst = replacement_block.instructions.items[0]; 4020 sema.air_instructions.set(@backingInt(placeholder_inst), sema.air_instructions.get(@backingInt(only_inst))); 4021 continue; 4022 } 4023 4024 // Here we replace the placeholder store instruction with a block 4025 // that does the actual store logic. 4026 _ = try replacement_block.addBr(placeholder_inst, .void_value); 4027 try sema.air_extra.ensureUnusedCapacity( 4028 gpa, 4029 @typeInfo(Air.Block).@"struct".field_names.len + replacement_block.instructions.items.len, 4030 ); 4031 sema.air_instructions.set(@backingInt(placeholder_inst), .{ 4032 .tag = .block, 4033 .data = .{ .ty_pl = .{ 4034 .ty = .void, 4035 .payload = sema.addExtraAssumeCapacity(Air.Block{ 4036 .body_len = @intCast(replacement_block.instructions.items.len), 4037 }), 4038 } }, 4039 }); 4040 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(replacement_block.instructions.items)); 4041 } 4042 4043 if (ia1.is_const) { 4044 return sema.makePtrConst(block, ptr); 4045 } else { 4046 return ptr; 4047 } 4048 }, 4049 else => unreachable, 4050 } 4051 } 4052 4053 fn zirForLen(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4054 const pt = sema.pt; 4055 const zcu = pt.zcu; 4056 const comp = zcu.comp; 4057 const gpa = comp.gpa; 4058 const io = comp.io; 4059 const ip = &zcu.intern_pool; 4060 4061 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4062 const extra = sema.code.extraData(Zir.Inst.MultiOp, inst_data.payload_index); 4063 const all_args = sema.code.refSlice(extra.end, extra.data.operands_len); 4064 const arg_pairs: []const [2]Zir.Inst.Ref = @as([*]const [2]Zir.Inst.Ref, @ptrCast(all_args))[0..@divExact(all_args.len, 2)]; 4065 const src = block.nodeOffset(inst_data.src_node); 4066 4067 var len: Air.Inst.Ref = .none; 4068 var len_val: ?Value = null; 4069 var len_idx: u32 = undefined; 4070 var any_runtime = false; 4071 4072 const runtime_arg_lens = try gpa.alloc(Air.Inst.Ref, arg_pairs.len); 4073 defer gpa.free(runtime_arg_lens); 4074 4075 // First pass to look for comptime values. 4076 for (arg_pairs, 0..) |zir_arg_pair, i_usize| { 4077 const i: u32 = @intCast(i_usize); 4078 runtime_arg_lens[i] = .none; 4079 if (zir_arg_pair[0] == .none) continue; 4080 4081 const arg_src = block.src(.{ .for_input = .{ 4082 .for_node_offset = inst_data.src_node, 4083 .input_index = i, 4084 } }); 4085 4086 const arg_len_uncoerced = if (zir_arg_pair[1] == .none) l: { 4087 // This argument is an indexable. 4088 const object = sema.resolveInst(zir_arg_pair[0]); 4089 const object_ty = sema.typeOf(object); 4090 if (!object_ty.isIndexable(zcu)) { 4091 // Instead of using checkIndexable we customize this error. 4092 const msg = msg: { 4093 const msg = try sema.errMsg(arg_src, "type '{f}' is not indexable and not a range", .{object_ty.fmt(pt)}); 4094 errdefer msg.destroy(sema.gpa); 4095 try sema.errNote(arg_src, msg, "for loop operand must be a range, array, slice, tuple, or vector", .{}); 4096 4097 if (object_ty.zigTypeTag(zcu) == .error_union) { 4098 try sema.errNote(arg_src, msg, "consider using 'try', 'catch', or 'if'", .{}); 4099 } 4100 4101 break :msg msg; 4102 }; 4103 return sema.failWithOwnedErrorMsg(block, msg); 4104 } 4105 if (!object_ty.indexableHasLen(zcu)) continue; 4106 break :l try sema.fieldVal(block, arg_src, object, try ip.getOrPutString(gpa, io, pt.tid, "len", .no_embedded_nulls), arg_src); 4107 } else l: { 4108 // This argument is a range. 4109 const range_start = sema.resolveInst(zir_arg_pair[0]); 4110 const range_end = sema.resolveInst(zir_arg_pair[1]); 4111 if (try sema.resolveDefinedValue(block, arg_src, range_start)) |start| { 4112 if (try sema.valuesEqual(start, .zero_usize, .usize)) break :l range_end; 4113 } 4114 break :l try sema.analyzeArithmetic(block, .sub, range_end, range_start, arg_src, arg_src, arg_src, true); 4115 }; 4116 const arg_len = try sema.coerce(block, .usize, arg_len_uncoerced, arg_src); 4117 if (len == .none) { 4118 len = arg_len; 4119 len_idx = i; 4120 } 4121 if (try sema.resolveDefinedValue(block, src, arg_len)) |arg_val| { 4122 if (len_val) |v| { 4123 if (!(try sema.valuesEqual(arg_val, v, .usize))) { 4124 const msg = msg: { 4125 const msg = try sema.errMsg(src, "non-matching for loop lengths", .{}); 4126 errdefer msg.destroy(gpa); 4127 const a_src = block.src(.{ .for_input = .{ 4128 .for_node_offset = inst_data.src_node, 4129 .input_index = len_idx, 4130 } }); 4131 try sema.errNote(a_src, msg, "length {f} here", .{ 4132 v.fmtValueSema(pt, sema), 4133 }); 4134 try sema.errNote(arg_src, msg, "length {f} here", .{ 4135 arg_val.fmtValueSema(pt, sema), 4136 }); 4137 break :msg msg; 4138 }; 4139 return sema.failWithOwnedErrorMsg(block, msg); 4140 } 4141 } else { 4142 len = arg_len; 4143 len_val = arg_val; 4144 len_idx = i; 4145 } 4146 continue; 4147 } 4148 runtime_arg_lens[i] = arg_len; 4149 any_runtime = true; 4150 } 4151 4152 if (len == .none) { 4153 const msg = msg: { 4154 const msg = try sema.errMsg(src, "unbounded for loop", .{}); 4155 errdefer msg.destroy(gpa); 4156 for (arg_pairs, 0..) |zir_arg_pair, i_usize| { 4157 const i: u32 = @intCast(i_usize); 4158 if (zir_arg_pair[0] == .none) continue; 4159 if (zir_arg_pair[1] != .none) continue; 4160 const object = sema.resolveInst(zir_arg_pair[0]); 4161 const object_ty = sema.typeOf(object); 4162 const arg_src = block.src(.{ .for_input = .{ 4163 .for_node_offset = inst_data.src_node, 4164 .input_index = i, 4165 } }); 4166 try sema.errNote(arg_src, msg, "type '{f}' has no upper bound", .{ 4167 object_ty.fmt(pt), 4168 }); 4169 } 4170 break :msg msg; 4171 }; 4172 return sema.failWithOwnedErrorMsg(block, msg); 4173 } 4174 4175 // Now for the runtime checks. 4176 if (any_runtime and block.wantSafety()) { 4177 var ok: Air.Inst.Ref = .none; 4178 for (runtime_arg_lens, 0..) |arg_len, i| { 4179 if (arg_len == .none) continue; 4180 if (i == len_idx) continue; 4181 const eq = try block.addBinOp(.cmp_eq, len, arg_len); 4182 ok = if (ok != .none) 4183 try block.addBinOp(.bit_and, ok, eq) 4184 else 4185 eq; 4186 } 4187 if (ok != .none) 4188 try sema.addSafetyCheck(block, src, ok, .for_len_mismatch); 4189 } 4190 4191 return len; 4192 } 4193 4194 /// Given any single pointer, retrieve a pointer to the payload of any optional 4195 /// or error union pointed to, initializing these pointers along the way. 4196 /// Given a `*E!?T`, returns a (valid) `*T`. 4197 /// May invalidate already-stored payload data. 4198 /// Asserts that the layout of the pointer child type is already resolved. 4199 fn optEuBasePtrInit(sema: *Sema, block: *Block, ptr: Air.Inst.Ref, src: LazySrcLoc) CompileError!Air.Inst.Ref { 4200 const pt = sema.pt; 4201 const zcu = pt.zcu; 4202 sema.typeOf(ptr).childType(zcu).assertHasLayout(zcu); 4203 var base_ptr = ptr; 4204 while (true) switch (sema.typeOf(base_ptr).childType(zcu).zigTypeTag(zcu)) { 4205 .error_union => base_ptr = try sema.analyzeErrUnionPayloadPtr(block, src, base_ptr, false, true), 4206 .optional => base_ptr = try sema.analyzeOptionalPayloadPtr(block, src, base_ptr, false, true), 4207 else => break, 4208 }; 4209 try sema.checkKnownAllocPtr(block, ptr, base_ptr); 4210 return base_ptr; 4211 } 4212 4213 fn zirOptEuBasePtrInit(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4214 const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 4215 const ptr = sema.resolveInst(un_node.operand); 4216 const src = block.nodeOffset(un_node.src_node); 4217 try sema.ensureLayoutResolved(sema.typeOf(ptr).childType(sema.pt.zcu), src, .init); 4218 return sema.optEuBasePtrInit(block, ptr, src); 4219 } 4220 4221 fn zirCoercePtrElemTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4222 const pt = sema.pt; 4223 const zcu = pt.zcu; 4224 const pl_node = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4225 const src = block.nodeOffset(pl_node.src_node); 4226 const extra = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data; 4227 const uncoerced_val = sema.resolveInst(extra.rhs); 4228 const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, extra.lhs) orelse return uncoerced_val; 4229 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu); 4230 assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction 4231 const elem_ty = ptr_ty.childType(zcu); 4232 switch (ptr_ty.ptrSize(zcu)) { 4233 .one => { 4234 const uncoerced_ty = sema.typeOf(uncoerced_val); 4235 if (elem_ty.zigTypeTag(zcu) == .array and elem_ty.childType(zcu).toIntern() == uncoerced_ty.toIntern()) { 4236 // We're trying to initialize a *[1]T with a reference to a T - don't perform any coercion. 4237 return uncoerced_val; 4238 } 4239 // If the destination type is anyopaque, don't coerce - the pointer will coerce instead. 4240 if (elem_ty.toIntern() == .anyopaque_type) { 4241 return uncoerced_val; 4242 } else { 4243 return sema.coerce(block, elem_ty, uncoerced_val, src); 4244 } 4245 }, 4246 .slice, .many => { 4247 // Our goal is to coerce `uncoerced_val` to an array of `elem_ty`. 4248 const val_ty = sema.typeOf(uncoerced_val); 4249 switch (val_ty.zigTypeTag(zcu)) { 4250 .array, .vector => {}, 4251 else => if (!val_ty.isTuple(zcu)) { 4252 return sema.fail(block, src, "expected array of '{f}', found '{f}'", .{ elem_ty.fmt(pt), val_ty.fmt(pt) }); 4253 }, 4254 } 4255 const want_ty = try pt.arrayType(.{ 4256 .len = val_ty.arrayLen(zcu), 4257 .child = elem_ty.toIntern(), 4258 .sentinel = if (ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, 4259 }); 4260 return sema.coerce(block, want_ty, uncoerced_val, src); 4261 }, 4262 .c => { 4263 // There's nothing meaningful to do here, because we don't know if this is meant to be a 4264 // single-pointer or a many-pointer. 4265 return uncoerced_val; 4266 }, 4267 } 4268 } 4269 4270 fn zirTryOperandTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index, is_ref: bool) CompileError!Air.Inst.Ref { 4271 const pt = sema.pt; 4272 const zcu = pt.zcu; 4273 const comp = zcu.comp; 4274 const gpa = comp.gpa; 4275 const io = comp.io; 4276 4277 const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 4278 const src = block.nodeOffset(un_node.src_node); 4279 4280 const operand_ty = try sema.resolveTypeOrPoison(block, src, un_node.operand) orelse return .generic_poison_type; 4281 4282 const payload_ty = if (is_ref) ty: { 4283 if (!operand_ty.isSinglePointer(zcu)) { 4284 return .generic_poison_type; // we can't get a meaningful result type here, since it will be `*E![n]T`, and we don't know `n`. 4285 } 4286 break :ty operand_ty.childType(zcu); 4287 } else operand_ty; 4288 4289 const err_set_ty: Type = err_set: { 4290 // There are awkward cases, like `?E`. Our strategy is to repeatedly unwrap optionals 4291 // until we hit an error union or set. 4292 var cur_ty = sema.fn_ret_ty; 4293 while (true) { 4294 switch (cur_ty.zigTypeTag(zcu)) { 4295 .error_set => break :err_set cur_ty, 4296 .error_union => break :err_set cur_ty.errorUnionSet(zcu), 4297 .optional => cur_ty = cur_ty.optionalChild(zcu), 4298 else => { 4299 // This function cannot return an error. 4300 // `try` is still valid if the error case is impossible, i.e. no error is returned. 4301 // So, the result type has an error set of `error{}`. 4302 break :err_set .fromInterned(try zcu.intern_pool.getErrorSetType(gpa, io, pt.tid, &.{})); 4303 }, 4304 } 4305 } 4306 }; 4307 4308 const eu_ty = try pt.errorUnionType(err_set_ty, payload_ty); 4309 4310 if (is_ref) { 4311 var ptr_info = operand_ty.ptrInfo(zcu); 4312 ptr_info.child = eu_ty.toIntern(); 4313 const eu_ptr_ty = try pt.ptrType(ptr_info); 4314 return Air.internedToRef(eu_ptr_ty.toIntern()); 4315 } else { 4316 return Air.internedToRef(eu_ty.toIntern()); 4317 } 4318 } 4319 4320 fn zirValidateRefTy(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4321 const pt = sema.pt; 4322 const zcu = pt.zcu; 4323 const un_tok = sema.code.instructions.items(.data)[@backingInt(inst)].un_tok; 4324 const src = block.tokenOffset(un_tok.src_tok); 4325 // In case of GenericPoison, we don't actually have a type, so this will be 4326 // treated as an untyped address-of operator. 4327 const ty_operand = try sema.resolveTypeOrPoison(block, src, un_tok.operand) orelse return; 4328 if (ty_operand.optEuBaseType(zcu).zigTypeTag(zcu) != .pointer) { 4329 return sema.failWithOwnedErrorMsg(block, msg: { 4330 const msg = try sema.errMsg(src, "expected type '{f}', found pointer", .{ty_operand.fmt(pt)}); 4331 errdefer msg.destroy(sema.gpa); 4332 try sema.errNote(src, msg, "address-of operator always returns a pointer", .{}); 4333 break :msg msg; 4334 }); 4335 } 4336 } 4337 4338 fn zirValidateConst(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4339 if (!block.isComptime()) return; 4340 4341 const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 4342 const src = block.nodeOffset(un_node.src_node); 4343 const init_ref = sema.resolveInst(un_node.operand); 4344 if (!try sema.isComptimeKnown(init_ref)) { 4345 return sema.failWithNeededComptime(block, src, null); 4346 } 4347 } 4348 4349 fn zirValidateArrayInitRefTy( 4350 sema: *Sema, 4351 block: *Block, 4352 inst: Zir.Inst.Index, 4353 ) CompileError!Air.Inst.Ref { 4354 const pt = sema.pt; 4355 const zcu = pt.zcu; 4356 const pl_node = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4357 const src = block.nodeOffset(pl_node.src_node); 4358 const extra = sema.code.extraData(Zir.Inst.ArrayInitRefTy, pl_node.payload_index).data; 4359 const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, extra.ptr_ty) orelse return .generic_poison_type; 4360 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu); 4361 assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction 4362 switch (zcu.intern_pool.indexToKey(ptr_ty.toIntern())) { 4363 .ptr_type => |ptr_type| switch (ptr_type.flags.size) { 4364 .slice, .many => { 4365 // Use array of correct length 4366 const arr_ty = try pt.arrayType(.{ 4367 .len = extra.elem_count, 4368 .child = ptr_ty.childType(zcu).toIntern(), 4369 .sentinel = if (ptr_ty.sentinel(zcu)) |s| s.toIntern() else .none, 4370 }); 4371 return Air.internedToRef(arr_ty.toIntern()); 4372 }, 4373 else => {}, 4374 }, 4375 else => {}, 4376 } 4377 // Otherwise, we just want the pointer child type 4378 const ret_ty = ptr_ty.childType(zcu); 4379 if (ret_ty.toIntern() == .anyopaque_type) { 4380 // The actual array type is unknown, which we represent with a generic poison. 4381 return .generic_poison_type; 4382 } 4383 const arr_ty = ret_ty.optEuBaseType(zcu); 4384 try sema.validateArrayInitTy(block, src, src, extra.elem_count, arr_ty); 4385 return Air.internedToRef(ret_ty.toIntern()); 4386 } 4387 4388 fn zirValidateArrayInitTy( 4389 sema: *Sema, 4390 block: *Block, 4391 inst: Zir.Inst.Index, 4392 is_result_ty: bool, 4393 ) CompileError!void { 4394 const pt = sema.pt; 4395 const zcu = pt.zcu; 4396 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4397 const src = block.nodeOffset(inst_data.src_node); 4398 const ty_src: LazySrcLoc = if (is_result_ty) src else block.src(.{ .node_offset_init_ty = inst_data.src_node }); 4399 const extra = sema.code.extraData(Zir.Inst.ArrayInit, inst_data.payload_index).data; 4400 // It's okay for the type to be poison: this will result in an anonymous array init. 4401 const ty = try sema.resolveTypeOrPoison(block, ty_src, extra.ty) orelse return; 4402 const arr_ty = if (is_result_ty) ty.optEuBaseType(zcu) else ty; 4403 return sema.validateArrayInitTy(block, src, ty_src, extra.init_count, arr_ty); 4404 } 4405 4406 fn validateArrayInitTy( 4407 sema: *Sema, 4408 block: *Block, 4409 src: LazySrcLoc, 4410 ty_src: LazySrcLoc, 4411 init_count: u32, 4412 ty: Type, 4413 ) CompileError!void { 4414 const pt = sema.pt; 4415 const zcu = pt.zcu; 4416 switch (ty.zigTypeTag(zcu)) { 4417 .array => { 4418 const array_len = ty.arrayLen(zcu); 4419 if (init_count != array_len) { 4420 return sema.fail(block, src, "expected {d} array elements; found {d}", .{ 4421 array_len, init_count, 4422 }); 4423 } 4424 return; 4425 }, 4426 .vector => { 4427 const array_len = ty.arrayLen(zcu); 4428 if (init_count != array_len) { 4429 return sema.fail(block, src, "expected {d} vector elements; found {d}", .{ 4430 array_len, init_count, 4431 }); 4432 } 4433 return; 4434 }, 4435 .@"struct" => if (ty.isTuple(zcu)) { 4436 const array_len = ty.arrayLen(zcu); 4437 if (init_count > array_len) { 4438 return sema.fail(block, src, "expected at most {d} tuple fields; found {d}", .{ 4439 array_len, init_count, 4440 }); 4441 } 4442 return; 4443 }, 4444 else => {}, 4445 } 4446 return sema.failWithArrayInitNotSupported(block, ty_src, ty); 4447 } 4448 4449 fn zirValidateStructInitTy( 4450 sema: *Sema, 4451 block: *Block, 4452 inst: Zir.Inst.Index, 4453 is_result_ty: bool, 4454 ) CompileError!void { 4455 const pt = sema.pt; 4456 const zcu = pt.zcu; 4457 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 4458 const src = block.nodeOffset(inst_data.src_node); 4459 // It's okay for the type to be poison: this will result in an anonymous struct init. 4460 const ty = try sema.resolveTypeOrPoison(block, src, inst_data.operand) orelse return; 4461 const struct_ty = if (is_result_ty) ty.optEuBaseType(zcu) else ty; 4462 4463 switch (struct_ty.zigTypeTag(zcu)) { 4464 .@"struct", .@"union" => return, 4465 else => {}, 4466 } 4467 return sema.failWithStructInitNotSupported(block, src, struct_ty); 4468 } 4469 4470 fn zirValidatePtrStructInit( 4471 sema: *Sema, 4472 block: *Block, 4473 inst: Zir.Inst.Index, 4474 ) CompileError!void { 4475 const pt = sema.pt; 4476 const zcu = pt.zcu; 4477 const validate_inst = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4478 const init_src = block.nodeOffset(validate_inst.src_node); 4479 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); 4480 const instrs = sema.code.bodySlice(validate_extra.end, validate_extra.data.body_len); 4481 const field_ptr_data = sema.code.instructions.items(.data)[@backingInt(instrs[0])].pl_node; 4482 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 4483 const object_ptr = sema.resolveInst(field_ptr_extra.lhs); 4484 const agg_ty = sema.typeOf(object_ptr).childType(zcu).optEuBaseType(zcu); 4485 switch (agg_ty.zigTypeTag(zcu)) { 4486 .@"struct" => return sema.validateStructInit( 4487 block, 4488 agg_ty, 4489 init_src, 4490 instrs, 4491 object_ptr, 4492 ), 4493 .@"union" => return sema.validateUnionInit( 4494 block, 4495 agg_ty, 4496 init_src, 4497 instrs, 4498 ), 4499 else => unreachable, 4500 } 4501 } 4502 4503 fn validateUnionInit( 4504 sema: *Sema, 4505 block: *Block, 4506 union_ty: Type, 4507 init_src: LazySrcLoc, 4508 instrs: []const Zir.Inst.Index, 4509 ) CompileError!void { 4510 if (instrs.len == 1) { 4511 // Trvial validation done, and the union tag was already set by machinery in `unionFieldPtr`. 4512 return; 4513 } 4514 const msg = msg: { 4515 const msg = try sema.errMsg( 4516 init_src, 4517 "cannot initialize multiple union fields at once; unions can only have one active field", 4518 .{}, 4519 ); 4520 errdefer msg.destroy(sema.gpa); 4521 4522 for (instrs[1..]) |inst| { 4523 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4524 const inst_src = block.src(.{ .node_offset_initializer = inst_data.src_node }); 4525 try sema.errNote(inst_src, msg, "additional initializer here", .{}); 4526 } 4527 try sema.addDeclaredHereNote(msg, union_ty); 4528 break :msg msg; 4529 }; 4530 return sema.failWithOwnedErrorMsg(block, msg); 4531 } 4532 4533 fn validateStructInit( 4534 sema: *Sema, 4535 block: *Block, 4536 struct_ty: Type, 4537 init_src: LazySrcLoc, 4538 instrs: []const Zir.Inst.Index, 4539 struct_ptr: Air.Inst.Ref, 4540 ) CompileError!void { 4541 const pt = sema.pt; 4542 const zcu = pt.zcu; 4543 const comp = zcu.comp; 4544 const gpa = comp.gpa; 4545 const io = comp.io; 4546 const ip = &zcu.intern_pool; 4547 4548 // Tracks whether each field was explicitly initialized. 4549 const found_fields = try gpa.alloc(bool, struct_ty.structFieldCount(zcu)); 4550 defer gpa.free(found_fields); 4551 @memset(found_fields, false); 4552 4553 for (instrs) |field_ptr| { 4554 const field_ptr_data = sema.code.instructions.items(.data)[@backingInt(field_ptr)].pl_node; 4555 const field_src = block.src(.{ .node_offset_initializer = field_ptr_data.src_node }); 4556 const field_ptr_extra = sema.code.extraData(Zir.Inst.Field, field_ptr_data.payload_index).data; 4557 const field_name = try ip.getOrPutString( 4558 gpa, 4559 io, 4560 pt.tid, 4561 sema.code.nullTerminatedString(field_ptr_extra.field_name_start), 4562 .no_embedded_nulls, 4563 ); 4564 const field_index = if (struct_ty.isTuple(zcu)) 4565 try sema.tupleFieldIndex(block, struct_ty, field_name, field_src) 4566 else 4567 try sema.structFieldIndex(block, struct_ty, field_name, field_src); 4568 assert(found_fields[field_index] == false); 4569 found_fields[field_index] = true; 4570 } 4571 4572 // Our job is simply to deal with default field values. Specifically, any field which was not 4573 // explicitly initialized must have its default value stored to the field pointer, or, if the 4574 // field has no default value, a compile error must be emitted instead. 4575 4576 // In the past, this code had other responsibilities, which involved some nasty AIR rewrites. However, 4577 // that work was actually all redundant: 4578 // 4579 // * If the struct value is comptime-known, field stores remain a perfectly valid way of initializing 4580 // the struct through RLS; there is no need to turn the field stores into one store. Comptime-known 4581 // consts are handled correctly either way thanks to `maybe_comptime_allocs` and friends. 4582 // 4583 // * If the struct type is comptime-only, we need to make sure all of the fields were comptime-known. 4584 // But the comptime-only type means that `struct_ptr` must be a comptime-mutable pointer, so the 4585 // field stores were to comptime-mutable pointers, so have already errored if not comptime-known. 4586 // 4587 // * If the value is runtime-known, then comptime-known fields must be validated as runtime values. 4588 // But this was already handled for every field store by the machinery in `checkComptimeKnownStore`. 4589 4590 var root_msg: ?*Zcu.ErrorMsg = null; 4591 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 4592 4593 for (found_fields, 0..) |explicit, i_usize| { 4594 const i: u32 = @intCast(i_usize); 4595 4596 if (explicit) continue; 4597 if (struct_ty.structFieldIsComptime(i, zcu)) continue; 4598 4599 if (!struct_ty.isTuple(zcu)) { 4600 try sema.ensureStructDefaultsResolved(struct_ty, init_src); 4601 } 4602 4603 const default_val = struct_ty.structFieldDefaultValue(i, zcu) orelse { 4604 const field_name = struct_ty.structFieldName(i, zcu).unwrap() orelse { 4605 const template = "missing tuple field with index {d}"; 4606 if (root_msg) |msg| { 4607 try sema.errNote(init_src, msg, template, .{i}); 4608 } else { 4609 root_msg = try sema.errMsg(init_src, template, .{i}); 4610 } 4611 continue; 4612 }; 4613 const template = "missing struct field: {f}"; 4614 const args = .{field_name.fmt(ip)}; 4615 if (root_msg) |msg| { 4616 try sema.errNote(init_src, msg, template, args); 4617 } else { 4618 root_msg = try sema.errMsg(init_src, template, args); 4619 } 4620 continue; 4621 }; 4622 4623 const field_src = init_src; // TODO better source location 4624 const default_field_ptr = try sema.structFieldPtrByIndex(block, init_src, struct_ptr, @intCast(i), struct_ty); 4625 try sema.checkKnownAllocPtr(block, struct_ptr, default_field_ptr); 4626 try sema.storePtr2(block, init_src, default_field_ptr, init_src, .fromValue(default_val), field_src, .store); 4627 } 4628 4629 if (root_msg) |msg| { 4630 try sema.addDeclaredHereNote(msg, struct_ty); 4631 root_msg = null; 4632 return sema.failWithOwnedErrorMsg(block, msg); 4633 } 4634 } 4635 4636 fn zirValidatePtrArrayInit( 4637 sema: *Sema, 4638 block: *Block, 4639 inst: Zir.Inst.Index, 4640 ) CompileError!void { 4641 const pt = sema.pt; 4642 const zcu = pt.zcu; 4643 const validate_inst = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4644 const init_src = block.nodeOffset(validate_inst.src_node); 4645 const validate_extra = sema.code.extraData(Zir.Inst.Block, validate_inst.payload_index); 4646 const instrs = sema.code.bodySlice(validate_extra.end, validate_extra.data.body_len); 4647 const first_elem_ptr_data = sema.code.instructions.items(.data)[@backingInt(instrs[0])].pl_node; 4648 const elem_ptr_extra = sema.code.extraData(Zir.Inst.ElemPtrImm, first_elem_ptr_data.payload_index).data; 4649 const array_ptr = sema.resolveInst(elem_ptr_extra.ptr); 4650 const array_ty = sema.typeOf(array_ptr).childType(zcu).optEuBaseType(zcu); 4651 const array_len = array_ty.arrayLen(zcu); 4652 4653 // Analagously to `validateStructInit`, our job is to handle default fields; either emitting AIR 4654 // to initialize them, or emitting a compile error if an unspecified field has no default. For 4655 // tuples, there are literally default field values, although they're guaranteed to be comptime 4656 // fields so we don't need to initialize them. For arrays, we may have a sentinel, which is never 4657 // specified so we always need to initialize here. For vectors, there's no such thing. 4658 4659 switch (array_ty.zigTypeTag(zcu)) { 4660 .@"struct" => if (instrs.len != array_len) { 4661 var root_msg: ?*Zcu.ErrorMsg = null; 4662 errdefer if (root_msg) |msg| msg.destroy(sema.gpa); 4663 4664 var i = instrs.len; 4665 while (i < array_len) : (i += 1) { 4666 if (array_ty.structFieldDefaultValue(i, zcu) == null) { 4667 const template = "missing tuple field with index {d}"; 4668 if (root_msg) |msg| { 4669 try sema.errNote(init_src, msg, template, .{i}); 4670 } else { 4671 root_msg = try sema.errMsg(init_src, template, .{i}); 4672 } 4673 continue; 4674 } 4675 } 4676 4677 if (root_msg) |msg| { 4678 root_msg = null; 4679 return sema.failWithOwnedErrorMsg(block, msg); 4680 } 4681 }, 4682 4683 .array => if (instrs.len != array_len) { 4684 return sema.fail(block, init_src, "expected {d} array elements; found {d}", .{ 4685 array_len, instrs.len, 4686 }); 4687 } else if (array_ty.sentinel(zcu)) |sentinel| { 4688 const array_len_ref = try pt.intRef(.usize, array_len); 4689 const sentinel_ptr = try sema.elemPtrArray(block, init_src, init_src, array_ptr, init_src, array_len_ref, true, true); 4690 try sema.checkKnownAllocPtr(block, array_ptr, sentinel_ptr); 4691 try sema.storePtr2(block, init_src, sentinel_ptr, init_src, .fromValue(sentinel), init_src, .store); 4692 }, 4693 4694 .vector => if (instrs.len != array_len) { 4695 return sema.fail(block, init_src, "expected {d} vector elements; found {d}", .{ 4696 array_len, instrs.len, 4697 }); 4698 }, 4699 4700 else => unreachable, 4701 } 4702 } 4703 4704 fn zirValidateDestructure(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4705 const pt = sema.pt; 4706 const zcu = pt.zcu; 4707 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4708 const extra = sema.code.extraData(Zir.Inst.ValidateDestructure, inst_data.payload_index).data; 4709 const src = block.nodeOffset(inst_data.src_node); 4710 const destructure_src = block.nodeOffset(extra.destructure_node); 4711 const operand = sema.resolveInst(extra.operand); 4712 const operand_ty = sema.typeOf(operand); 4713 4714 if (!operand_ty.destructurable(zcu)) { 4715 return sema.failWithOwnedErrorMsg(block, msg: { 4716 const msg = try sema.errMsg(src, "type '{f}' cannot be destructured", .{operand_ty.fmt(pt)}); 4717 errdefer msg.destroy(sema.gpa); 4718 try sema.errNote(destructure_src, msg, "result destructured here", .{}); 4719 if (operand_ty.zigTypeTag(pt.zcu) == .error_union) { 4720 const base_op_ty = operand_ty.errorUnionPayload(zcu); 4721 if (base_op_ty.destructurable(zcu)) 4722 try sema.errNote(src, msg, "consider using 'try', 'catch', or 'if'", .{}); 4723 } 4724 break :msg msg; 4725 }); 4726 } 4727 4728 if (operand_ty.arrayLen(zcu) != extra.expect_len) { 4729 return sema.failWithOwnedErrorMsg(block, msg: { 4730 const msg = try sema.errMsg(src, "expected {d} elements for destructure, found {d}", .{ 4731 extra.expect_len, operand_ty.arrayLen(zcu), 4732 }); 4733 errdefer msg.destroy(sema.gpa); 4734 try sema.errNote(destructure_src, msg, "result destructured here", .{}); 4735 break :msg msg; 4736 }); 4737 } 4738 } 4739 4740 fn failWithBadMemberAccess( 4741 sema: *Sema, 4742 block: *Block, 4743 agg_ty: Type, 4744 field_src: LazySrcLoc, 4745 field_name: InternPool.NullTerminatedString, 4746 ) CompileError { 4747 const pt = sema.pt; 4748 const zcu = pt.zcu; 4749 const ip = &zcu.intern_pool; 4750 const kw_name = switch (agg_ty.zigTypeTag(zcu)) { 4751 .@"union" => "union", 4752 .@"struct" => "struct", 4753 .@"opaque" => "opaque", 4754 .@"enum" => "enum", 4755 else => unreachable, 4756 }; 4757 if (agg_ty.typeDeclInst(zcu)) |inst| { 4758 const inst_index = inst.resolve(ip) orelse return sema.failTransitive(.{ .lost_tracking = inst }); 4759 if (inst_index == .main_struct_inst) { 4760 return sema.fail(block, field_src, "root source file struct '{f}' has no member named '{f}'", .{ 4761 agg_ty.fmt(pt), field_name.fmt(ip), 4762 }); 4763 } 4764 } 4765 4766 return sema.fail(block, field_src, "{s} '{f}' has no member named '{f}'", .{ 4767 kw_name, agg_ty.fmt(pt), field_name.fmt(ip), 4768 }); 4769 } 4770 4771 fn failWithBadStructFieldAccess( 4772 sema: *Sema, 4773 block: *Block, 4774 struct_ty: Type, 4775 struct_type: InternPool.LoadedStructType, 4776 field_src: LazySrcLoc, 4777 field_name: InternPool.NullTerminatedString, 4778 ) CompileError { 4779 const pt = sema.pt; 4780 const zcu = pt.zcu; 4781 const ip = &zcu.intern_pool; 4782 4783 const msg = msg: { 4784 const msg = try sema.errMsg( 4785 field_src, 4786 "no field named '{f}' in struct '{f}'", 4787 .{ field_name.fmt(ip), struct_type.fqn.fmt(ip) }, 4788 ); 4789 errdefer msg.destroy(sema.gpa); 4790 try sema.errNote(struct_ty.srcLoc(zcu), msg, "struct declared here", .{}); 4791 break :msg msg; 4792 }; 4793 return sema.failWithOwnedErrorMsg(block, msg); 4794 } 4795 4796 fn failWithBadUnionFieldAccess( 4797 sema: *Sema, 4798 block: *Block, 4799 union_ty: Type, 4800 union_obj: InternPool.LoadedUnionType, 4801 field_src: LazySrcLoc, 4802 field_name: InternPool.NullTerminatedString, 4803 ) CompileError { 4804 const pt = sema.pt; 4805 const zcu = pt.zcu; 4806 const ip = &zcu.intern_pool; 4807 const gpa = sema.gpa; 4808 4809 const msg = msg: { 4810 const msg = try sema.errMsg( 4811 field_src, 4812 "no field named '{f}' in union '{f}'", 4813 .{ field_name.fmt(ip), union_obj.fqn.fmt(ip) }, 4814 ); 4815 errdefer msg.destroy(gpa); 4816 try sema.errNote(union_ty.srcLoc(zcu), msg, "union declared here", .{}); 4817 break :msg msg; 4818 }; 4819 return sema.failWithOwnedErrorMsg(block, msg); 4820 } 4821 4822 pub fn addDeclaredHereNote(sema: *Sema, parent: *Zcu.ErrorMsg, decl_ty: Type) Allocator.Error!void { 4823 const zcu = sema.pt.zcu; 4824 const src_loc = decl_ty.srcLocOrNull(zcu) orelse return; 4825 const category = switch (decl_ty.zigTypeTag(zcu)) { 4826 .@"union" => "union", 4827 .@"struct" => "struct", 4828 .@"enum" => "enum", 4829 .@"opaque" => "opaque", 4830 else => unreachable, 4831 }; 4832 try sema.errNote(src_loc, parent, "{s} declared here", .{category}); 4833 } 4834 4835 fn zirStoreToInferredPtr(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4836 const pl_node = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 4837 const src = block.nodeOffset(pl_node.src_node); 4838 const bin = sema.code.extraData(Zir.Inst.Bin, pl_node.payload_index).data; 4839 const ptr = sema.resolveInst(bin.lhs); 4840 const operand = sema.resolveInst(bin.rhs); 4841 const ptr_inst = ptr.toIndex().?; 4842 const air_datas = sema.air_instructions.items(.data); 4843 4844 switch (sema.air_instructions.items(.tag)[@backingInt(ptr_inst)]) { 4845 .inferred_alloc_comptime => { 4846 const iac = &air_datas[@backingInt(ptr_inst)].inferred_alloc_comptime; 4847 return sema.storeToInferredAllocComptime(block, src, operand, iac); 4848 }, 4849 .inferred_alloc => { 4850 const ia = sema.unresolved_inferred_allocs.getPtr(ptr_inst).?; 4851 return sema.storeToInferredAlloc(block, src, ptr, operand, ia); 4852 }, 4853 else => unreachable, 4854 } 4855 } 4856 4857 fn storeToInferredAlloc( 4858 sema: *Sema, 4859 block: *Block, 4860 src: LazySrcLoc, 4861 ptr: Air.Inst.Ref, 4862 operand: Air.Inst.Ref, 4863 inferred_alloc: *InferredAlloc, 4864 ) CompileError!void { 4865 // Create a store instruction as a placeholder. This will be replaced by a 4866 // proper store sequence once we know the stored type. 4867 const dummy_store = try block.addBinOp(.store, ptr, operand); 4868 try sema.checkComptimeKnownStore(block, dummy_store, src); 4869 // Add the stored instruction to the set we will use to resolve peer types 4870 // for the inferred allocation. 4871 try inferred_alloc.prongs.append(sema.arena, dummy_store.toIndex().?); 4872 } 4873 4874 fn storeToInferredAllocComptime( 4875 sema: *Sema, 4876 block: *Block, 4877 src: LazySrcLoc, 4878 operand: Air.Inst.Ref, 4879 iac: *Air.Inst.Data.InferredAllocComptime, 4880 ) CompileError!void { 4881 const pt = sema.pt; 4882 const zcu = pt.zcu; 4883 const operand_ty = sema.typeOf(operand); 4884 // There will be only one store_to_inferred_ptr because we are running at comptime. 4885 // The alloc will turn into a Decl or a ComptimeAlloc. 4886 const operand_val = sema.resolveValue(operand) orelse { 4887 return sema.failWithNeededComptime(block, src, .{ .simple = .stored_to_comptime_var }); 4888 }; 4889 const alloc_ty = try pt.ptrType(.{ 4890 .child = operand_ty.toIntern(), 4891 .flags = .{ 4892 .alignment = iac.alignment, 4893 .is_const = iac.is_const, 4894 }, 4895 }); 4896 if (operand_ty.classify(zcu) == .one_possible_value or 4897 (iac.is_const and !operand_val.canMutateComptimeVarState(zcu))) 4898 { 4899 iac.ptr = try pt.intern(.{ .ptr = .{ 4900 .ty = alloc_ty.toIntern(), 4901 .base_addr = .{ .uav = .{ 4902 .val = operand_val.toIntern(), 4903 .orig_ty = alloc_ty.toIntern(), 4904 } }, 4905 .byte_offset = 0, 4906 } }); 4907 } else { 4908 const alloc_index = try sema.newComptimeAlloc(block, src, operand_ty, iac.alignment); 4909 sema.getComptimeAlloc(alloc_index).val = .{ .interned = operand_val.toIntern() }; 4910 iac.ptr = try pt.intern(.{ .ptr = .{ 4911 .ty = alloc_ty.toIntern(), 4912 .base_addr = .{ .comptime_alloc = alloc_index }, 4913 .byte_offset = 0, 4914 } }); 4915 } 4916 } 4917 4918 fn zirSetEvalBranchQuota(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4919 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 4920 const src = block.nodeOffset(inst_data.src_node); 4921 const quota: u32 = @intCast(try sema.resolveInt(block, src, inst_data.operand, .u32, .{ .simple = .operand_setEvalBranchQuota })); 4922 sema.branch_quota = @max(sema.branch_quota, quota); 4923 sema.quota_request = @max(sema.quota_request, quota); 4924 } 4925 4926 fn zirStoreNode(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 4927 const zir_tags = sema.code.instructions.items(.tag); 4928 const zir_datas = sema.code.instructions.items(.data); 4929 const inst_data = zir_datas[@backingInt(inst)].pl_node; 4930 const src = block.nodeOffset(inst_data.src_node); 4931 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 4932 const ptr = sema.resolveInst(extra.lhs); 4933 const operand = sema.resolveInst(extra.rhs); 4934 4935 const is_ret = if (extra.lhs.toIndex()) |ptr_index| 4936 zir_tags[@backingInt(ptr_index)] == .ret_ptr 4937 else 4938 false; 4939 4940 const ptr_src = block.src(.{ .node_offset_store_ptr = inst_data.src_node }); 4941 const operand_src = block.src(.{ .node_offset_store_operand = inst_data.src_node }); 4942 const air_tag: Air.Inst.Tag = if (is_ret) 4943 .ret_ptr 4944 else if (block.wantSafety()) 4945 .store_safe 4946 else 4947 .store; 4948 return sema.storePtr2(block, src, ptr, ptr_src, operand, operand_src, air_tag); 4949 } 4950 4951 fn zirStr(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4952 const pt = sema.pt; 4953 const zcu = pt.zcu; 4954 const comp = zcu.comp; 4955 const gpa = comp.gpa; 4956 const io = comp.io; 4957 const ip = &zcu.intern_pool; 4958 const bytes = sema.code.instructions.items(.data)[@backingInt(inst)].str.get(sema.code); 4959 return sema.addStrLit( 4960 try ip.getOrPutString(gpa, io, pt.tid, bytes, .maybe_embedded_nulls), 4961 bytes.len, 4962 ); 4963 } 4964 4965 fn addNullTerminatedStrLit(sema: *Sema, string: InternPool.NullTerminatedString) CompileError!Air.Inst.Ref { 4966 return sema.addStrLit(string.toString(), string.length(&sema.pt.zcu.intern_pool)); 4967 } 4968 4969 pub fn addStrLit(sema: *Sema, string: InternPool.String, len: u64) CompileError!Air.Inst.Ref { 4970 const pt = sema.pt; 4971 const array_ty = try pt.arrayType(.{ 4972 .len = len, 4973 .sentinel = .zero_u8, 4974 .child = .u8_type, 4975 }); 4976 const val = try pt.intern(.{ .aggregate = .{ 4977 .ty = array_ty.toIntern(), 4978 .storage = .{ .bytes = string }, 4979 } }); 4980 return sema.uavRef(.fromInterned(val)); 4981 } 4982 4983 fn uavRef(sema: *Sema, val: Value) CompileError!Air.Inst.Ref { 4984 return .fromValue(try sema.pt.uavValue(val)); 4985 } 4986 4987 fn zirInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4988 _ = block; 4989 4990 const int = sema.code.instructions.items(.data)[@backingInt(inst)].int; 4991 return sema.pt.intRef(.comptime_int, int); 4992 } 4993 4994 fn zirIntBig(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 4995 _ = block; 4996 4997 const int = sema.code.instructions.items(.data)[@backingInt(inst)].str; 4998 const byte_count = int.len * @sizeOf(std.math.big.Limb); 4999 const limb_bytes = sema.code.string_bytes[@backingInt(int.start)..][0..byte_count]; 5000 5001 // TODO: this allocation and copy is only needed because the limbs may be unaligned. 5002 // If ZIR is adjusted so that big int limbs are guaranteed to be aligned, these 5003 // two lines can be removed. 5004 const limbs = try sema.arena.alloc(std.math.big.Limb, int.len); 5005 @memcpy(mem.sliceAsBytes(limbs), limb_bytes); 5006 5007 return Air.internedToRef((try sema.pt.intValue_big(.comptime_int, .{ 5008 .limbs = limbs, 5009 .positive = true, 5010 })).toIntern()); 5011 } 5012 5013 fn zirFloat(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5014 _ = block; 5015 const number = sema.code.instructions.items(.data)[@backingInt(inst)].float; 5016 return Air.internedToRef((try sema.pt.floatValue( 5017 .comptime_float, 5018 number, 5019 )).toIntern()); 5020 } 5021 5022 fn zirFloat128(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5023 _ = block; 5024 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 5025 const extra = sema.code.extraData(Zir.Inst.Float128, inst_data.payload_index).data; 5026 const number = extra.get(); 5027 return Air.internedToRef((try sema.pt.floatValue(.comptime_float, number)).toIntern()); 5028 } 5029 5030 fn zirCompileError(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5031 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 5032 const src = block.nodeOffset(inst_data.src_node); 5033 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); 5034 const msg = try sema.resolveConstString(block, operand_src, inst_data.operand, .{ .simple = .compile_error_string }); 5035 return sema.fail(block, src, "{s}", .{msg}); 5036 } 5037 5038 fn zirCompileLog( 5039 sema: *Sema, 5040 block: *Block, 5041 extended: Zir.Inst.Extended.InstData, 5042 ) CompileError!Air.Inst.Ref { 5043 const pt = sema.pt; 5044 const zcu = pt.zcu; 5045 const comp = zcu.comp; 5046 const gpa = comp.gpa; 5047 const io = comp.io; 5048 5049 var aw: std.Io.Writer.Allocating = .init(gpa); 5050 defer aw.deinit(); 5051 const writer = &aw.writer; 5052 5053 const extra = sema.code.extraData(Zir.Inst.NodeMultiOp, extended.operand); 5054 const src_node = extra.data.src_node; 5055 const args = sema.code.refSlice(extra.end, extended.small); 5056 5057 for (args, 0..) |arg_ref, i| { 5058 if (i != 0) writer.writeAll(", ") catch return error.OutOfMemory; 5059 5060 const arg = sema.resolveInst(arg_ref); 5061 const arg_ty = sema.typeOf(arg); 5062 if (sema.resolveValue(arg)) |val| { 5063 writer.print("@as({f}, {f})", .{ 5064 arg_ty.fmt(pt), val.fmtValueSema(pt, sema), 5065 }) catch return error.OutOfMemory; 5066 } else { 5067 writer.print("@as({f}, [runtime value])", .{arg_ty.fmt(pt)}) catch return error.OutOfMemory; 5068 } 5069 } 5070 5071 const line_data = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, aw.written(), .no_embedded_nulls); 5072 5073 const line_idx: Zcu.CompileLogLine.Index = if (zcu.free_compile_log_lines.pop()) |idx| idx: { 5074 zcu.compile_log_lines.items[@backingInt(idx)] = .{ 5075 .next = .none, 5076 .data = line_data, 5077 }; 5078 break :idx idx; 5079 } else idx: { 5080 try zcu.compile_log_lines.append(gpa, .{ 5081 .next = .none, 5082 .data = line_data, 5083 }); 5084 break :idx @fromBackingInt(@intCast(zcu.compile_log_lines.items.len - 1)); 5085 }; 5086 5087 const gop = try zcu.compile_logs.getOrPut(gpa, sema.owner); 5088 if (gop.found_existing) { 5089 const prev_line = gop.value_ptr.last_line.get(zcu); 5090 assert(prev_line.next == .none); 5091 prev_line.next = line_idx.toOptional(); 5092 gop.value_ptr.last_line = line_idx; 5093 } else { 5094 gop.value_ptr.* = .{ 5095 .base_node_inst = block.src_base_inst, 5096 .node_offset = src_node, 5097 .first_line = line_idx, 5098 .last_line = line_idx, 5099 }; 5100 } 5101 return .void_value; 5102 } 5103 5104 fn zirPanic(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5105 const pt = sema.pt; 5106 const zcu = pt.zcu; 5107 5108 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 5109 const src = block.nodeOffset(inst_data.src_node); 5110 const msg_inst = sema.resolveInst(inst_data.operand); 5111 5112 const arg_src = block.builtinCallArgSrc(inst_data.src_node, 0); 5113 const coerced_msg = try sema.coerce(block, .slice_const_u8, msg_inst, arg_src); 5114 5115 if (block.isComptime()) { 5116 const string = try sema.resolveConstString(block, arg_src, inst_data.operand, null); 5117 return sema.fail(block, src, "encountered @panic at comptime: {s}", .{string}); 5118 } 5119 5120 // We only apply the first hint in a branch. 5121 // This allows user-provided hints to override implicit cold hints. 5122 if (sema.branch_hint == null) { 5123 sema.branch_hint = .cold; 5124 } 5125 5126 if (!zcu.backendSupportsFeature(.panic_fn)) { 5127 _ = try block.addNoOp(.trap); 5128 return; 5129 } 5130 5131 try sema.ensureMemoizedStateResolved(src, .panic); 5132 const panic_fn_index = zcu.std_lang_decl_values.get(.@"panic.call"); 5133 const opt_usize_ty = try pt.optionalType(.usize_type); 5134 const null_ret_addr = Air.internedToRef((try pt.intern(.{ .opt = .{ 5135 .ty = opt_usize_ty.toIntern(), 5136 .val = .none, 5137 } }))); 5138 // `callBuiltin` also calls `addReferenceEntry` to the function body for us. 5139 try sema.callBuiltin( 5140 block, 5141 src, 5142 .fromIntern(panic_fn_index), 5143 .auto, 5144 &.{ coerced_msg, null_ret_addr }, 5145 .@"@panic", 5146 ); 5147 } 5148 5149 fn zirTrap(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5150 const src_node = sema.code.instructions.items(.data)[@backingInt(inst)].node; 5151 const src = block.nodeOffset(src_node); 5152 if (block.isComptime()) 5153 return sema.fail(block, src, "encountered @trap at comptime", .{}); 5154 _ = try block.addNoOp(.trap); 5155 } 5156 5157 fn zirBreakpoint(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5158 const src_node: std.zig.Ast.Node.Offset = @fromBackingInt(@intCast(@as(i32, @bitCast(extended.operand)))); 5159 const src = block.nodeOffset(src_node); 5160 if (block.isComptime()) 5161 return sema.fail(block, src, "encountered @breakpoint at comptime", .{}); 5162 _ = try block.addNoOp(.breakpoint); 5163 } 5164 5165 fn zirLoop(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5166 const pt = sema.pt; 5167 const zcu = pt.zcu; 5168 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 5169 const src = parent_block.nodeOffset(inst_data.src_node); 5170 const extra = sema.code.extraData(Zir.Inst.Block, inst_data.payload_index); 5171 const body = sema.code.bodySlice(extra.end, extra.data.body_len); 5172 const gpa = sema.gpa; 5173 5174 // AIR expects a block outside the loop block too. 5175 // Reserve space for a Loop instruction so that generated Break instructions can 5176 // point to it, even if it doesn't end up getting used because the code ends up being 5177 // comptime evaluated. 5178 const block_inst: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 5179 const loop_inst: Air.Inst.Index = @fromBackingInt(@intCast(@backingInt(block_inst) + 1)); 5180 try sema.air_instructions.ensureUnusedCapacity(gpa, 2); 5181 sema.air_instructions.appendAssumeCapacity(.{ 5182 .tag = .block, 5183 .data = undefined, 5184 }); 5185 sema.air_instructions.appendAssumeCapacity(.{ 5186 .tag = .loop, 5187 .data = .{ .ty_pl = .{ 5188 .ty = .noreturn, 5189 .payload = undefined, 5190 } }, 5191 }); 5192 var label: Block.Label = .{ 5193 .zir_block = inst, 5194 .merges = .{ 5195 .src_locs = .empty, 5196 .results = .empty, 5197 .br_list = .empty, 5198 .block_inst = block_inst, 5199 }, 5200 }; 5201 var child_block = parent_block.makeSubBlock(); 5202 child_block.label = &label; 5203 child_block.runtime_cond = null; 5204 child_block.runtime_loop = src; 5205 child_block.runtime_index.increment(); 5206 const merges = &child_block.label.?.merges; 5207 5208 defer child_block.instructions.deinit(gpa); 5209 defer merges.deinit(gpa); 5210 5211 var loop_block = child_block.makeSubBlock(); 5212 defer loop_block.instructions.deinit(gpa); 5213 5214 // Use `analyzeBodyInner` directly to push any comptime control flow up the stack. 5215 try sema.analyzeBodyInner(&loop_block, body); 5216 5217 // TODO: since AIR has `repeat` now, we could change ZIR to generate 5218 // more optimal code utilizing `repeat` instructions across blocks! 5219 // For now, if the generated loop body does not terminate `noreturn`, 5220 // then `analyzeBodyInner` is signalling that it ended with `repeat`. 5221 5222 const loop_block_len = loop_block.instructions.items.len; 5223 if (loop_block_len > 0 and sema.typeOf(loop_block.instructions.items[loop_block_len - 1].toRef()).isNoReturn(zcu)) { 5224 // If the loop ended with a noreturn terminator, then there is no way for it to loop, 5225 // so we can just use the block instead. 5226 try child_block.instructions.appendSlice(gpa, loop_block.instructions.items); 5227 } else { 5228 _ = try loop_block.addInst(.{ 5229 .tag = .repeat, 5230 .data = .{ .repeat = .{ 5231 .loop_inst = loop_inst, 5232 } }, 5233 }); 5234 // Note that `loop_block_len` is now off by one. 5235 5236 try child_block.instructions.append(gpa, loop_inst); 5237 5238 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).@"struct".field_names.len + loop_block_len + 1); 5239 sema.air_instructions.items(.data)[@backingInt(loop_inst)].ty_pl.payload = sema.addExtraAssumeCapacity( 5240 Air.Block{ .body_len = @intCast(loop_block_len + 1) }, 5241 ); 5242 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(loop_block.instructions.items)); 5243 } 5244 return sema.resolveAnalyzedBlock(parent_block, src, &child_block, merges, false); 5245 } 5246 5247 fn zirSuspendBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5248 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 5249 const src = parent_block.nodeOffset(inst_data.src_node); 5250 return sema.failWithUseOfAsync(parent_block, src); 5251 } 5252 5253 fn zirBlock(sema: *Sema, parent_block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5254 const pl_node = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 5255 const src = parent_block.nodeOffset(pl_node.src_node); 5256 const extra = sema.code.extraData(Zir.Inst.Block, pl_node.payload_index); 5257 const body = sema.code.bodySlice(extra.end, extra.data.body_len); 5258 const gpa = sema.gpa; 5259 5260 // Reserve space for a Block instruction so that generated Break instructions can 5261 // point to it, even if it doesn't end up getting used because the code ends up being 5262 // comptime evaluated or is an unlabeled block. 5263 const block_inst: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 5264 try sema.air_instructions.append(gpa, .{ 5265 .tag = .block, 5266 .data = undefined, 5267 }); 5268 5269 var label: Block.Label = .{ 5270 .zir_block = inst, 5271 .merges = .{ 5272 .src_locs = .empty, 5273 .results = .empty, 5274 .br_list = .empty, 5275 .block_inst = block_inst, 5276 }, 5277 }; 5278 5279 var child_block: Block = .{ 5280 .parent = parent_block, 5281 .sema = sema, 5282 .namespace = parent_block.namespace, 5283 .instructions = .empty, 5284 .label = &label, 5285 .inlining = parent_block.inlining, 5286 .comptime_reason = parent_block.comptime_reason, 5287 .is_typeof = parent_block.is_typeof, 5288 .want_safety = parent_block.want_safety, 5289 .float_mode = parent_block.float_mode, 5290 .runtime_cond = parent_block.runtime_cond, 5291 .runtime_loop = parent_block.runtime_loop, 5292 .runtime_index = parent_block.runtime_index, 5293 .error_return_trace_index = parent_block.error_return_trace_index, 5294 .src_base_inst = parent_block.src_base_inst, 5295 .type_name_ctx = parent_block.type_name_ctx, 5296 .type_fqn_ctx = parent_block.type_fqn_ctx, 5297 }; 5298 5299 defer child_block.instructions.deinit(gpa); 5300 defer label.merges.deinit(gpa); 5301 5302 return sema.resolveBlockBody(parent_block, src, &child_block, body, inst, &label.merges); 5303 } 5304 5305 /// Semantically analyze the given ZIR body, emitting any resulting runtime code into the AIR block 5306 /// specified by `child_block` if necessary (and emitting this block into `parent_block`). 5307 /// TODO: `merges` is known from `child_block`, remove this parameter. 5308 fn resolveBlockBody( 5309 sema: *Sema, 5310 parent_block: *Block, 5311 src: LazySrcLoc, 5312 child_block: *Block, 5313 body: []const Zir.Inst.Index, 5314 /// This is the instruction that a break instruction within `body` can 5315 /// use to return from the body. 5316 body_inst: Zir.Inst.Index, 5317 merges: *Block.Merges, 5318 ) CompileError!Air.Inst.Ref { 5319 if (child_block.isComptime()) { 5320 return sema.resolveInlineBody(child_block, body, body_inst); 5321 } else { 5322 assert(sema.air_instructions.items(.tag)[@backingInt(merges.block_inst)] == .block); 5323 var need_debug_scope = false; 5324 child_block.need_debug_scope = &need_debug_scope; 5325 if (sema.analyzeBodyInner(child_block, body)) { 5326 return sema.resolveAnalyzedBlock(parent_block, src, child_block, merges, need_debug_scope); 5327 } else |err| switch (err) { 5328 error.ComptimeBreak => { 5329 const break_inst = sema.comptime_break_inst; 5330 const break_data = sema.code.instructions.items(.data)[@backingInt(break_inst)].@"break"; 5331 const extra = sema.code.extraData(Zir.Inst.Break, break_data.payload_index).data; 5332 const breaks_to_body = extra.block_inst == body_inst; 5333 5334 // Comptime control flow is happening, however child_block may still contain 5335 // runtime instructions which need to be copied to the parent block. 5336 if (need_debug_scope and child_block.instructions.items.len > 0) { 5337 // We need a runtime block for scoping reasons. The break 5338 // operand may have been produced by a runtime instruction 5339 // inside `child_blocks`. 5340 const operand = sema.resolveInst(break_data.operand); 5341 const operand_ty = sema.typeOf(operand); 5342 _ = try child_block.addBr(merges.block_inst, operand); 5343 try parent_block.instructions.append(sema.gpa, merges.block_inst); 5344 try sema.air_extra.ensureUnusedCapacity(sema.gpa, @typeInfo(Air.Block).@"struct".field_names.len + 5345 child_block.instructions.items.len); 5346 sema.air_instructions.items(.data)[@backingInt(merges.block_inst)] = .{ .ty_pl = .{ 5347 .ty = operand_ty, 5348 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5349 .body_len = @intCast(child_block.instructions.items.len), 5350 }), 5351 } }; 5352 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); 5353 5354 // The block result now holds the operand value, so we remap 5355 // the operand such that an enclosing scope which resolves 5356 // it picks up the block result rather than the internal 5357 // block instruction. 5358 if (break_data.operand.toIndex()) |operand_zir| { 5359 sema.inst_map.putAssumeCapacity(operand_zir, merges.block_inst.toRef()); 5360 } 5361 if (breaks_to_body) { 5362 return merges.block_inst.toRef(); 5363 } else { 5364 return error.ComptimeBreak; 5365 } 5366 } else { 5367 // We can copy instructions directly to the parent block. 5368 try parent_block.instructions.appendSlice(sema.gpa, child_block.instructions.items); 5369 if (breaks_to_body) { 5370 return sema.resolveInst(break_data.operand); 5371 } else { 5372 return error.ComptimeBreak; 5373 } 5374 } 5375 }, 5376 else => |e| return e, 5377 } 5378 } 5379 } 5380 5381 /// After a body corresponding to an AIR `block` has been analyzed, this function places them into 5382 /// the block pointed at by `merges.block_inst` if necessary, or the block may be elided in favor of 5383 /// inlining the instructions directly into the parent block. Either way, it considers all merges of 5384 /// this block, and combines them appropriately using peer type resolution, returning the final 5385 /// value of the block. 5386 fn resolveAnalyzedBlock( 5387 sema: *Sema, 5388 parent_block: *Block, 5389 src: LazySrcLoc, 5390 child_block: *Block, 5391 merges: *Block.Merges, 5392 need_debug_scope: bool, 5393 ) CompileError!Air.Inst.Ref { 5394 const gpa = sema.gpa; 5395 const pt = sema.pt; 5396 const zcu = pt.zcu; 5397 5398 // Blocks must terminate with noreturn instruction. 5399 assert(child_block.instructions.items.len != 0); 5400 assert(sema.typeOf(child_block.instructions.items[child_block.instructions.items.len - 1].toRef()).isNoReturn(zcu)); 5401 5402 const block_tag = sema.air_instructions.items(.tag)[@backingInt(merges.block_inst)]; 5403 switch (block_tag) { 5404 .block => {}, 5405 .dbg_inline_block => assert(need_debug_scope), 5406 else => unreachable, 5407 } 5408 if (merges.results.items.len == 0) { 5409 switch (block_tag) { 5410 .block => { 5411 // No need for a block instruction. We can put the new instructions 5412 // directly into the parent block. 5413 if (need_debug_scope) { 5414 // The code following this block is unreachable, as the block has no 5415 // merges, so we don't necessarily need to emit this as an AIR block. 5416 // However, we need a block *somewhere* to make the scoping correct, 5417 // so forward this request to the parent block. 5418 if (parent_block.need_debug_scope) |ptr| ptr.* = true; 5419 } 5420 try parent_block.instructions.appendSlice(gpa, child_block.instructions.items); 5421 return child_block.instructions.items[child_block.instructions.items.len - 1].toRef(); 5422 }, 5423 .dbg_inline_block => { 5424 // Create a block containing all instruction from the body. 5425 try parent_block.instructions.append(gpa, merges.block_inst); 5426 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.DbgInlineBlock).@"struct".field_names.len + 5427 child_block.instructions.items.len); 5428 sema.air_instructions.items(.data)[@backingInt(merges.block_inst)] = .{ .ty_pl = .{ 5429 .ty = .noreturn, 5430 .payload = sema.addExtraAssumeCapacity(Air.DbgInlineBlock{ 5431 .func = child_block.inlining.?.func, 5432 .body_len = @intCast(child_block.instructions.items.len), 5433 }), 5434 } }; 5435 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); 5436 return merges.block_inst.toRef(); 5437 }, 5438 else => unreachable, 5439 } 5440 } 5441 if (merges.results.items.len == 1) { 5442 // If the `break` is trailing, we may be able to elide the AIR block here 5443 // by appending the new instructions directly to the parent block. 5444 if (!need_debug_scope) { 5445 const last_inst_index = child_block.instructions.items.len - 1; 5446 const last_inst = child_block.instructions.items[last_inst_index]; 5447 if (sema.getBreakBlock(last_inst)) |br_block| { 5448 if (br_block == merges.block_inst) { 5449 // Great, the last instruction is the break! Put the instructions 5450 // directly into the parent block. 5451 try parent_block.instructions.appendSlice(gpa, child_block.instructions.items[0..last_inst_index]); 5452 return merges.results.items[0]; 5453 } 5454 } 5455 } 5456 // Okay, we need a runtime block. If the value is comptime-known, the 5457 // block should just return void, and we return the merge result 5458 // directly. Otherwise, we can defer to the logic below. 5459 if (sema.resolveValue(merges.results.items[0])) |result_val| { 5460 // Create a block containing all instruction from the body. 5461 try parent_block.instructions.append(gpa, merges.block_inst); 5462 switch (block_tag) { 5463 .block => { 5464 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).@"struct".field_names.len + 5465 child_block.instructions.items.len); 5466 sema.air_instructions.items(.data)[@backingInt(merges.block_inst)] = .{ .ty_pl = .{ 5467 .ty = .void, 5468 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5469 .body_len = @intCast(child_block.instructions.items.len), 5470 }), 5471 } }; 5472 }, 5473 .dbg_inline_block => { 5474 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.DbgInlineBlock).@"struct".field_names.len + 5475 child_block.instructions.items.len); 5476 sema.air_instructions.items(.data)[@backingInt(merges.block_inst)] = .{ .ty_pl = .{ 5477 .ty = .void, 5478 .payload = sema.addExtraAssumeCapacity(Air.DbgInlineBlock{ 5479 .func = child_block.inlining.?.func, 5480 .body_len = @intCast(child_block.instructions.items.len), 5481 }), 5482 } }; 5483 }, 5484 else => unreachable, 5485 } 5486 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); 5487 // Rewrite the break to just give value {}; the value is 5488 // comptime-known and will be returned directly. 5489 sema.air_instructions.items(.data)[@backingInt(merges.br_list.items[0])].br.operand = .void_value; 5490 return Air.internedToRef(result_val.toIntern()); 5491 } 5492 } 5493 // It is impossible to have the number of results be > 1 in a comptime scope. 5494 assert(!child_block.isComptime()); // Should already got a compile error in the condbr condition. 5495 5496 // Note that we'll always create an AIR block here, so `need_debug_scope` is irrelevant. 5497 5498 // Need to set the type and emit the Block instruction. This allows machine code generation 5499 // to emit a jump instruction to after the block when it encounters the break. 5500 try parent_block.instructions.append(gpa, merges.block_inst); 5501 const resolved_ty = try sema.resolvePeerTypes(parent_block, src, merges.results.items, .{ .override = merges.src_locs.items }); 5502 resolved_ty.assertHasLayout(zcu); 5503 // TODO add note "missing else causes void value" 5504 5505 const type_src = src; // TODO: better source location 5506 if (resolved_ty.comptimeOnly(zcu)) { 5507 const msg = msg: { 5508 const msg = try sema.errMsg(type_src, "value with comptime-only type '{f}' depends on runtime control flow", .{resolved_ty.fmt(pt)}); 5509 errdefer msg.destroy(sema.gpa); 5510 5511 const runtime_src = child_block.runtime_cond orelse child_block.runtime_loop.?; 5512 try sema.errNote(runtime_src, msg, "runtime control flow here", .{}); 5513 5514 try sema.explainWhyTypeIsComptime(msg, type_src, resolved_ty); 5515 5516 break :msg msg; 5517 }; 5518 return sema.failWithOwnedErrorMsg(child_block, msg); 5519 } 5520 for (merges.results.items, merges.src_locs.items) |merge_inst, merge_src| { 5521 try sema.validateRuntimeValue(child_block, merge_src orelse src, merge_inst); 5522 } 5523 5524 try sema.checkMergeAllowed(child_block, type_src, resolved_ty); 5525 5526 switch (block_tag) { 5527 .block => { 5528 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).@"struct".field_names.len + 5529 child_block.instructions.items.len); 5530 sema.air_instructions.items(.data)[@backingInt(merges.block_inst)] = .{ .ty_pl = .{ 5531 .ty = resolved_ty, 5532 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5533 .body_len = @intCast(child_block.instructions.items.len), 5534 }), 5535 } }; 5536 }, 5537 .dbg_inline_block => { 5538 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.DbgInlineBlock).@"struct".field_names.len + 5539 child_block.instructions.items.len); 5540 sema.air_instructions.items(.data)[@backingInt(merges.block_inst)] = .{ .ty_pl = .{ 5541 .ty = resolved_ty, 5542 .payload = sema.addExtraAssumeCapacity(Air.DbgInlineBlock{ 5543 .func = child_block.inlining.?.func, 5544 .body_len = @intCast(child_block.instructions.items.len), 5545 }), 5546 } }; 5547 }, 5548 else => unreachable, 5549 } 5550 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(child_block.instructions.items)); 5551 // Now that the block has its type resolved, we need to go back into all the break 5552 // instructions, and insert type coercion on the operands. 5553 for (merges.br_list.items) |br| { 5554 const br_operand = sema.air_instructions.items(.data)[@backingInt(br)].br.operand; 5555 const br_operand_src = src; 5556 const br_operand_ty = sema.typeOf(br_operand); 5557 if (br_operand_ty.eql(resolved_ty)) { 5558 // No type coercion needed. 5559 continue; 5560 } 5561 var coerce_block = parent_block.makeSubBlock(); 5562 defer coerce_block.instructions.deinit(gpa); 5563 const coerced_operand = try sema.coerce(&coerce_block, resolved_ty, br_operand, br_operand_src); 5564 // If no instructions were produced, such as in the case of a coercion of a 5565 // constant value to a new type, we can simply point the br operand to it. 5566 if (coerce_block.instructions.items.len == 0) { 5567 sema.air_instructions.items(.data)[@backingInt(br)].br.operand = coerced_operand; 5568 continue; 5569 } 5570 assert(coerce_block.instructions.items[coerce_block.instructions.items.len - 1].toRef() == coerced_operand); 5571 5572 // Convert the br instruction to a block instruction that has the coercion 5573 // and then a new br inside that returns the coerced instruction. 5574 const sub_block_len: u32 = @intCast(coerce_block.instructions.items.len + 1); 5575 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).@"struct".field_names.len + 5576 sub_block_len); 5577 try sema.air_instructions.ensureUnusedCapacity(gpa, 1); 5578 const sub_br_inst: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 5579 5580 sema.air_instructions.items(.tag)[@backingInt(br)] = .block; 5581 sema.air_instructions.items(.data)[@backingInt(br)] = .{ .ty_pl = .{ 5582 .ty = .noreturn, 5583 .payload = sema.addExtraAssumeCapacity(Air.Block{ 5584 .body_len = sub_block_len, 5585 }), 5586 } }; 5587 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(coerce_block.instructions.items)); 5588 sema.air_extra.appendAssumeCapacity(@backingInt(sub_br_inst)); 5589 5590 sema.air_instructions.appendAssumeCapacity(.{ 5591 .tag = .br, 5592 .data = .{ .br = .{ 5593 .block_inst = merges.block_inst, 5594 .operand = coerced_operand, 5595 } }, 5596 }); 5597 } 5598 5599 if (try resolved_ty.onePossibleValue(pt)) |opv| return .fromValue(opv); 5600 return merges.block_inst.toRef(); 5601 } 5602 5603 fn zirExport(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5604 const pt = sema.pt; 5605 const zcu = pt.zcu; 5606 const ip = &zcu.intern_pool; 5607 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 5608 const extra = sema.code.extraData(Zir.Inst.Export, inst_data.payload_index).data; 5609 5610 const src = block.nodeOffset(inst_data.src_node); 5611 const ptr_src = block.builtinCallArgSrc(inst_data.src_node, 0); 5612 const options_src = block.builtinCallArgSrc(inst_data.src_node, 1); 5613 5614 const ptr = sema.resolveInst(extra.exported); 5615 const ptr_val = try sema.resolveConstDefinedValue(block, ptr_src, ptr, .{ .simple = .export_target }); 5616 const ptr_ty = ptr_val.typeOf(zcu); 5617 5618 const options = try sema.resolveExportOptions(block, options_src, extra.options); 5619 5620 { 5621 if (ptr_ty.zigTypeTag(zcu) != .pointer) { 5622 return sema.fail(block, ptr_src, "expected pointer type, found '{f}'", .{ptr_ty.fmt(pt)}); 5623 } 5624 const ptr_ty_info = ptr_ty.ptrInfo(zcu); 5625 if (ptr_ty_info.flags.size == .slice) { 5626 return sema.fail(block, ptr_src, "export target cannot be slice", .{}); 5627 } 5628 if (ptr_ty_info.packed_offset.host_size != 0) { 5629 return sema.fail(block, ptr_src, "export target cannot be bit-pointer", .{}); 5630 } 5631 } 5632 5633 const export_ty = ptr_ty.childType(zcu); 5634 try sema.ensureLayoutResolved(export_ty, src, .@"export"); 5635 if (!export_ty.validateExtern(.other, zcu)) { 5636 return sema.failWithOwnedErrorMsg(block, msg: { 5637 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); 5638 errdefer msg.destroy(sema.gpa); 5639 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); 5640 try sema.addDeclaredHereNote(msg, export_ty); 5641 break :msg msg; 5642 }); 5643 } 5644 5645 const ptr_info = ip.indexToKey(ptr_val.toIntern()).ptr; 5646 const target: Zcu.Exported = switch (ptr_info.base_addr) { 5647 .comptime_alloc, .int, .comptime_field => return sema.fail(block, ptr_src, "export target must be a global variable or a comptime-known constant", .{}), 5648 .eu_payload, .opt_payload, .field, .arr_elem => return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}), 5649 .uav => |uav| .{ .uav = uav.val }, 5650 .nav => |orig_nav| target: { 5651 try sema.ensureNavResolved(block, src, orig_nav, .fully); 5652 const export_nav = switch (ip.indexToKey(ip.getNav(orig_nav).resolved.?.value)) { 5653 .@"extern" => |e| e.owner_nav, 5654 .func => |f| f.owner_nav, 5655 else => orig_nav, 5656 }; 5657 if (ip.getNav(export_nav).getExtern(ip) != null) { 5658 return sema.fail(block, src, "export target cannot be extern", .{}); 5659 } 5660 try sema.maybeQueueFuncBodyAnalysis(block, src, export_nav); 5661 break :target .{ .nav = export_nav }; 5662 }, 5663 }; 5664 if (ptr_info.byte_offset != 0) { 5665 return sema.fail(block, ptr_src, "TODO: export pointer in middle of value", .{}); 5666 } 5667 try sema.exports.append(zcu.gpa, .{ 5668 .opts = options, 5669 .src = src, 5670 .exported = target, 5671 }); 5672 } 5673 5674 /// Asserts that `sema.owner` is a `.nav_val` whose value is resolved. 5675 /// 5676 /// Exports that `Nav` by the given name with all other options set to default. 5677 pub fn analyzeExportSelfNav( 5678 sema: *Sema, 5679 block: *Block, 5680 src: LazySrcLoc, 5681 name: InternPool.NullTerminatedString, 5682 ) !void { 5683 const gpa = sema.gpa; 5684 const pt = sema.pt; 5685 const zcu = pt.zcu; 5686 const ip = &zcu.intern_pool; 5687 5688 const orig_nav = sema.owner.unwrap().nav_val; 5689 const export_val: Value = .fromInterned(ip.getNav(orig_nav).resolved.?.value); 5690 const export_ty = export_val.typeOf(zcu); 5691 5692 if (!export_ty.validateExtern(.other, zcu)) { 5693 return sema.failWithOwnedErrorMsg(block, msg: { 5694 const msg = try sema.errMsg(src, "unable to export type '{f}'", .{export_ty.fmt(pt)}); 5695 errdefer msg.destroy(gpa); 5696 try sema.explainWhyTypeIsNotExtern(msg, src, export_ty, .other); 5697 try sema.addDeclaredHereNote(msg, export_ty); 5698 break :msg msg; 5699 }); 5700 } 5701 5702 const export_nav = switch (ip.indexToKey(export_val.toIntern())) { 5703 .@"extern" => |e| e.owner_nav, 5704 .func => |f| export_nav: { 5705 assert(export_ty.fnHasRuntimeBits(zcu)); // otherwise `validateExtern` failed above 5706 const orig_fn_index = ip.unwrapCoercedFunc(export_val.toIntern()); 5707 try sema.addReferenceEntry(block, src, .wrap(.{ .func = orig_fn_index })); 5708 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index); 5709 break :export_nav f.owner_nav; 5710 }, 5711 else => orig_nav, 5712 }; 5713 5714 try sema.exports.append(gpa, .{ 5715 .opts = .{ .name = name }, 5716 .src = src, 5717 .exported = .{ .nav = export_nav }, 5718 }); 5719 } 5720 5721 fn zirDisableInstrumentation(sema: *Sema) CompileError!void { 5722 const pt = sema.pt; 5723 const zcu = pt.zcu; 5724 const io = zcu.comp.io; 5725 const ip = &zcu.intern_pool; 5726 const func = switch (sema.owner.unwrap()) { 5727 .func => |func| func, 5728 .@"comptime", 5729 .nav_val, 5730 .nav_ty, 5731 .type_layout, 5732 .struct_defaults, 5733 .memoized_state, 5734 => return, // does nothing outside a function 5735 }; 5736 ip.funcSetDisableInstrumentation(io, func); 5737 sema.allow_memoize = false; 5738 } 5739 5740 fn zirDisableIntrinsics(sema: *Sema) CompileError!void { 5741 const pt = sema.pt; 5742 const zcu = pt.zcu; 5743 const io = zcu.comp.io; 5744 const ip = &zcu.intern_pool; 5745 const func = switch (sema.owner.unwrap()) { 5746 .func => |func| func, 5747 .@"comptime", 5748 .nav_val, 5749 .nav_ty, 5750 .type_layout, 5751 .struct_defaults, 5752 .memoized_state, 5753 => return, // does nothing outside a function 5754 }; 5755 ip.funcSetDisableIntrinsics(io, func); 5756 sema.allow_memoize = false; 5757 } 5758 5759 fn zirSetFloatMode(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!void { 5760 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 5761 const src = block.builtinCallArgSrc(extra.node, 0); 5762 block.float_mode = try sema.resolveStdLangEnum(block, src, extra.operand, .FloatMode, .{ .simple = .operand_setFloatMode }); 5763 } 5764 5765 fn zirSetRuntimeSafety(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5766 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 5767 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); 5768 block.want_safety = try sema.resolveConstBool(block, operand_src, inst_data.operand, .{ .simple = .operand_setRuntimeSafety }); 5769 } 5770 5771 fn zirBreak(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void { 5772 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].@"break"; 5773 const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data; 5774 const operand = sema.resolveInst(inst_data.operand); 5775 const zir_block = extra.block_inst; 5776 5777 var block = start_block; 5778 while (true) { 5779 if (block.label) |label| { 5780 if (label.zir_block == zir_block) { 5781 const br_ref = try start_block.addBr(label.merges.block_inst, operand); 5782 const src_loc = if (extra.operand_src_node.unwrap()) |operand_src_node| 5783 start_block.nodeOffset(operand_src_node) 5784 else 5785 null; 5786 try label.merges.src_locs.append(sema.gpa, src_loc); 5787 try label.merges.results.append(sema.gpa, operand); 5788 try label.merges.br_list.append(sema.gpa, br_ref.toIndex().?); 5789 block.runtime_index.increment(); 5790 if (block.runtime_cond == null and block.runtime_loop == null) { 5791 block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop; 5792 block.runtime_loop = start_block.runtime_loop; 5793 } 5794 return; 5795 } 5796 } 5797 block = block.parent.?; 5798 } 5799 } 5800 5801 fn zirSwitchContinue(sema: *Sema, start_block: *Block, inst: Zir.Inst.Index) CompileError!void { 5802 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].@"break"; 5803 const extra = sema.code.extraData(Zir.Inst.Break, inst_data.payload_index).data; 5804 const operand_src = start_block.nodeOffset(extra.operand_src_node.unwrap().?); 5805 const uncoerced_operand = sema.resolveInst(inst_data.operand); 5806 const switch_inst = extra.block_inst; 5807 5808 switch (sema.code.instructions.items(.tag)[@backingInt(switch_inst)]) { 5809 .switch_block, .switch_block_ref => {}, 5810 .switch_block_err_union => unreachable, // wrong code path! 5811 else => unreachable, // assertion failure 5812 } 5813 5814 const operand_ty = (sema.resolveInst(switch_inst.toRef())).toType(); 5815 const operand = try sema.coerce(start_block, operand_ty, uncoerced_operand, operand_src); 5816 try sema.validateRuntimeValue(start_block, operand_src, operand); 5817 5818 // We want to generate a `switch_dispatch` instruction with the switch condition, 5819 // possibly preceded by a store to the stack alloc containing the raw operand. 5820 // However, to avoid too much special-case state in Sema, this is handled by the 5821 // `switch` lowering logic. As such, we will find the `Block` corresponding to 5822 // the parent `switch_block[_ref]` instruction, create a dummy `br`, and add a 5823 // merge to signal to the switch logic to rewrite this into an appropriate dispatch. 5824 5825 var block = start_block; 5826 while (true) : (block = block.parent.?) { 5827 if (block.label) |label| { 5828 if (label.zir_block == switch_inst) { 5829 const br_ref = try start_block.addBr(label.merges.block_inst, operand); 5830 try label.merges.extra_insts.append(sema.gpa, br_ref.toIndex().?); 5831 try label.merges.extra_src_locs.append(sema.gpa, operand_src); 5832 block.runtime_index.increment(); 5833 if (block.runtime_cond == null and block.runtime_loop == null) { 5834 block.runtime_cond = start_block.runtime_cond orelse start_block.runtime_loop; 5835 block.runtime_loop = start_block.runtime_loop; 5836 } 5837 return; 5838 } 5839 } 5840 } 5841 } 5842 5843 fn zirDbgStmt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!void { 5844 if (block.isComptime() or block.ownerModule().strip) return; 5845 5846 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].dbg_stmt; 5847 5848 if (block.instructions.items.len != 0) { 5849 const idx = block.instructions.items[block.instructions.items.len - 1]; 5850 if (sema.air_instructions.items(.tag)[@backingInt(idx)] == .dbg_stmt) { 5851 // The previous dbg_stmt didn't correspond to any actual code, so replace it. 5852 sema.air_instructions.items(.data)[@backingInt(idx)].dbg_stmt = .{ 5853 .line = inst_data.line, 5854 .column = inst_data.column, 5855 }; 5856 return; 5857 } 5858 } 5859 5860 _ = try block.addInst(.{ 5861 .tag = .dbg_stmt, 5862 .data = .{ .dbg_stmt = .{ 5863 .line = inst_data.line, 5864 .column = inst_data.column, 5865 } }, 5866 }); 5867 } 5868 5869 fn zirDbgEmptyStmt(_: *Sema, block: *Block, _: Zir.Inst.Index) CompileError!void { 5870 if (block.isComptime() or block.ownerModule().strip) return; 5871 _ = try block.addNoOp(.dbg_empty_stmt); 5872 } 5873 5874 fn zirDbgVar( 5875 sema: *Sema, 5876 block: *Block, 5877 inst: Zir.Inst.Index, 5878 air_tag: Air.Inst.Tag, 5879 ) CompileError!void { 5880 const str_op = sema.code.instructions.items(.data)[@backingInt(inst)].str_op; 5881 const operand = sema.resolveInst(str_op.operand); 5882 const name = str_op.getStr(sema.code); 5883 try sema.addDbgVar(block, operand, air_tag, name); 5884 } 5885 5886 fn addDbgVar( 5887 sema: *Sema, 5888 block: *Block, 5889 operand: Air.Inst.Ref, 5890 air_tag: Air.Inst.Tag, 5891 name: []const u8, 5892 ) CompileError!void { 5893 if (block.isComptime() or block.ownerModule().strip) return; 5894 5895 const pt = sema.pt; 5896 const zcu = pt.zcu; 5897 const operand_ty = sema.typeOf(operand); 5898 const val_ty = switch (air_tag) { 5899 .dbg_var_ptr => operand_ty.childType(zcu), 5900 .dbg_var_val, .dbg_arg_inline => operand_ty, 5901 else => unreachable, 5902 }; 5903 if (val_ty.comptimeOnly(zcu)) return; 5904 if (!val_ty.hasRuntimeBits(zcu)) return; 5905 if (sema.resolveValue(operand)) |operand_val| { 5906 if (operand_val.canMutateComptimeVarState(zcu)) return; 5907 } 5908 5909 // To ensure the lexical scoping is known to backends, this alloc must be 5910 // within a real runtime block. We set a flag which communicates information 5911 // to the closest lexically enclosing block: 5912 // * If it is a `block_inline`, communicates to logic in `analyzeBodyInner` 5913 // to create a post-hoc block. 5914 // * Otherwise, communicates to logic in `resolveBlockBody` to create a 5915 // real `block` instruction. 5916 if (block.need_debug_scope) |ptr| ptr.* = true; 5917 5918 // Add the name to the AIR. 5919 const name_nts = try sema.appendAirString(name); 5920 5921 _ = try block.addInst(.{ 5922 .tag = air_tag, 5923 .data = .{ .pl_op = .{ 5924 .payload = @backingInt(name_nts), 5925 .operand = operand, 5926 } }, 5927 }); 5928 } 5929 5930 pub fn appendAirString(sema: *Sema, str: []const u8) Allocator.Error!Air.NullTerminatedString { 5931 if (str.len == 0) return .none; 5932 const nts: Air.NullTerminatedString = @fromBackingInt(@intCast(sema.air_extra.items.len)); 5933 const elements_used = str.len / 4 + 1; 5934 const elements = try sema.air_extra.addManyAsSlice(sema.gpa, elements_used); 5935 const buffer = mem.sliceAsBytes(elements); 5936 @memcpy(buffer[0..str.len], str); 5937 buffer[str.len] = 0; 5938 return nts; 5939 } 5940 5941 fn zirDeclRef(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5942 const pt = sema.pt; 5943 const zcu = pt.zcu; 5944 const comp = zcu.comp; 5945 const gpa = comp.gpa; 5946 const io = comp.io; 5947 5948 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].str_tok; 5949 const src = block.tokenOffset(inst_data.src_tok); 5950 const decl_name = try zcu.intern_pool.getOrPutString( 5951 gpa, 5952 io, 5953 pt.tid, 5954 inst_data.get(sema.code), 5955 .no_embedded_nulls, 5956 ); 5957 const nav_index = try sema.lookupIdentifier(block, decl_name); 5958 return sema.analyzeNavRef(block, src, nav_index); 5959 } 5960 5961 fn zirDeclVal(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 5962 const pt = sema.pt; 5963 const zcu = pt.zcu; 5964 const comp = zcu.comp; 5965 const gpa = comp.gpa; 5966 const io = comp.io; 5967 5968 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].str_tok; 5969 const src = block.tokenOffset(inst_data.src_tok); 5970 const decl_name = try zcu.intern_pool.getOrPutString( 5971 gpa, 5972 io, 5973 pt.tid, 5974 inst_data.get(sema.code), 5975 .no_embedded_nulls, 5976 ); 5977 const nav = try sema.lookupIdentifier(block, decl_name); 5978 return sema.analyzeNavVal(block, src, nav); 5979 } 5980 5981 fn lookupIdentifier(sema: *Sema, block: *Block, name: InternPool.NullTerminatedString) !InternPool.Nav.Index { 5982 const pt = sema.pt; 5983 const zcu = pt.zcu; 5984 var namespace = block.namespace; 5985 while (true) { 5986 if (try sema.lookupInNamespace(block, namespace, name)) |lookup| { 5987 assert(lookup.accessible == .public or lookup.accessible == .private_same_file); 5988 return lookup.nav; 5989 } 5990 namespace = zcu.namespacePtr(namespace).parent.unwrap() orelse break; 5991 } 5992 unreachable; // AstGen detects use of undeclared identifiers. 5993 } 5994 5995 /// This looks up a member of a specific namespace. 5996 fn lookupInNamespace( 5997 sema: *Sema, 5998 block: *Block, 5999 namespace_index: InternPool.NamespaceIndex, 6000 ident_name: InternPool.NullTerminatedString, 6001 ) CompileError!?struct { 6002 nav: InternPool.Nav.Index, 6003 accessible: enum { public, private_same_file, private }, 6004 } { 6005 const pt = sema.pt; 6006 const zcu = pt.zcu; 6007 6008 pt.ensureNamespaceUpToDate(namespace_index) catch |err| switch (err) { 6009 error.LostZirContainerDecl => { 6010 const namespace = zcu.namespacePtr(namespace_index); 6011 const ns_ty: Type = .fromInterned(namespace.owner_type); 6012 return sema.failTransitive(.{ .lost_tracking = ns_ty.typeDeclInstAllowGeneratedTag(zcu).? }); 6013 }, 6014 else => |e| return e, 6015 }; 6016 6017 const namespace = zcu.namespacePtr(namespace_index); 6018 6019 const adapter: Zcu.Namespace.NameAdapter = .{ .zcu = zcu }; 6020 6021 const src_file = zcu.namespacePtr(block.namespace).file_scope; 6022 6023 if (Type.fromInterned(namespace.owner_type).typeDeclInst(zcu)) |type_decl_inst| { 6024 try sema.declareDependency(.{ .namespace_name = .{ 6025 .namespace = type_decl_inst, 6026 .name = ident_name, 6027 } }); 6028 } 6029 6030 if (namespace.pub_decls.getKeyAdapted(ident_name, adapter)) |nav_index| { 6031 return .{ 6032 .nav = nav_index, 6033 .accessible = .public, 6034 }; 6035 } else if (namespace.priv_decls.getKeyAdapted(ident_name, adapter)) |nav_index| { 6036 return .{ 6037 .nav = nav_index, 6038 .accessible = if (src_file == namespace.file_scope) .private_same_file else .private, 6039 }; 6040 } 6041 6042 return null; 6043 } 6044 6045 fn funcDeclSrcInst(sema: *Sema, func_inst: Air.Inst.Ref) !?InternPool.TrackedInst.Index { 6046 const pt = sema.pt; 6047 const zcu = pt.zcu; 6048 const ip = &zcu.intern_pool; 6049 const func_val = sema.resolveValue(func_inst) orelse return null; 6050 if (func_val.isUndef(zcu)) return null; 6051 const nav = switch (ip.indexToKey(func_val.toIntern())) { 6052 .@"extern" => |e| e.owner_nav, 6053 .func => |f| f.owner_nav, 6054 .ptr => |ptr| switch (ptr.base_addr) { 6055 .nav => |nav| if (ptr.byte_offset == 0) nav else return null, 6056 else => return null, 6057 }, 6058 else => return null, 6059 }; 6060 return ip.getNav(nav).srcInst(ip); 6061 } 6062 6063 pub fn analyzeSaveErrRetIndex(sema: *Sema, block: *Block) SemaError!Air.Inst.Ref { 6064 const pt = sema.pt; 6065 const zcu = pt.zcu; 6066 const comp = zcu.comp; 6067 const gpa = comp.gpa; 6068 const io = comp.io; 6069 6070 if (block.isComptime() or block.is_typeof) { 6071 const index_val = try pt.intValue_u64(.usize, sema.comptime_err_ret_trace.items.len); 6072 return Air.internedToRef(index_val.toIntern()); 6073 } 6074 6075 if (!block.ownerModule().error_tracing) return .none; 6076 6077 const stack_trace_ty = try sema.getStdLangType(block.nodeOffset(.zero), .StackTrace); 6078 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); 6079 const field_index = sema.structFieldIndex(block, stack_trace_ty, field_name, LazySrcLoc.unneeded) catch |err| switch (err) { 6080 error.AlreadyReported => @panic("std.lang.StackTrace is corrupt"), 6081 error.ComptimeReturn, error.ComptimeBreak => unreachable, 6082 error.OutOfMemory, error.Canceled => |e| return e, 6083 }; 6084 6085 return try block.addInst(.{ 6086 .tag = .save_err_return_trace_index, 6087 .data = .{ .ty_pl = .{ 6088 .ty = stack_trace_ty, 6089 .payload = @intCast(field_index), 6090 } }, 6091 }); 6092 } 6093 6094 /// Add instructions to block to "pop" the error return trace. 6095 /// If `operand` is provided, only pops if operand is non-error. 6096 fn popErrorReturnTrace( 6097 sema: *Sema, 6098 block: *Block, 6099 src: LazySrcLoc, 6100 operand: Air.Inst.Ref, 6101 saved_error_trace_index: Air.Inst.Ref, 6102 ) CompileError!void { 6103 const pt = sema.pt; 6104 const zcu = pt.zcu; 6105 const comp = zcu.comp; 6106 const gpa = comp.gpa; 6107 const io = comp.io; 6108 var is_non_error: ?bool = null; 6109 var is_non_error_inst: Air.Inst.Ref = undefined; 6110 if (operand != .none) { 6111 is_non_error_inst = try sema.analyzeIsNonErr(block, src, operand); 6112 if (try sema.resolveDefinedValue(block, src, is_non_error_inst)) |cond_val| 6113 is_non_error = cond_val.toBool(); 6114 } else is_non_error = true; // no operand means pop unconditionally 6115 6116 if (is_non_error == true) { 6117 // AstGen determined this result does not go to an error-handling expr (try/catch/return etc.), or 6118 // the result is comptime-known to be a non-error. Either way, pop unconditionally. 6119 6120 const stack_trace_ty = try sema.getStdLangType(src, .StackTrace); 6121 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); 6122 const err_return_trace = try block.addTy(.err_return_trace, ptr_stack_trace_ty); 6123 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); 6124 const field_ptr = try sema.structFieldPtr(block, src, err_return_trace, field_name, src, stack_trace_ty); 6125 try sema.storePtr2(block, src, field_ptr, src, saved_error_trace_index, src, .store); 6126 } else if (is_non_error == null) { 6127 // The result might be an error. If it is, we leave the error trace alone. If it isn't, we need 6128 // to pop any error trace that may have been propagated from our arguments. 6129 6130 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Block).@"struct".field_names.len); 6131 const cond_block_inst = try block.addInstAsIndex(.{ 6132 .tag = .block, 6133 .data = .{ 6134 .ty_pl = .{ 6135 .ty = .void, 6136 .payload = undefined, // updated below 6137 }, 6138 }, 6139 }); 6140 6141 var then_block = block.makeSubBlock(); 6142 defer then_block.instructions.deinit(gpa); 6143 6144 // If non-error, then pop the error return trace by restoring the index. 6145 const stack_trace_ty = try sema.getStdLangType(src, .StackTrace); 6146 const ptr_stack_trace_ty = try pt.singleMutPtrType(stack_trace_ty); 6147 const err_return_trace = try then_block.addTy(.err_return_trace, ptr_stack_trace_ty); 6148 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); 6149 const field_ptr = try sema.structFieldPtr(&then_block, src, err_return_trace, field_name, src, stack_trace_ty); 6150 try sema.storePtr2(&then_block, src, field_ptr, src, saved_error_trace_index, src, .store); 6151 _ = try then_block.addBr(cond_block_inst, .void_value); 6152 6153 // Otherwise, do nothing 6154 var else_block = block.makeSubBlock(); 6155 defer else_block.instructions.deinit(gpa); 6156 _ = try else_block.addBr(cond_block_inst, .void_value); 6157 6158 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.CondBr).@"struct".field_names.len + 6159 then_block.instructions.items.len + else_block.instructions.items.len + 6160 @typeInfo(Air.Block).@"struct".field_names.len + 1); // +1 for the sole .cond_br instruction in the .block 6161 6162 const cond_br_inst: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 6163 try sema.air_instructions.append(gpa, .{ 6164 .tag = .cond_br, 6165 .data = .{ 6166 .pl_op = .{ 6167 .operand = is_non_error_inst, 6168 .payload = sema.addExtraAssumeCapacity(Air.CondBr{ 6169 .then_body_len = @intCast(then_block.instructions.items.len), 6170 .else_body_len = @intCast(else_block.instructions.items.len), 6171 .branch_hints = .{ 6172 // Weight against error branch. 6173 .true = .likely, 6174 .false = .unlikely, 6175 // Code coverage is not valuable on either branch. 6176 .then_cov = .none, 6177 .else_cov = .none, 6178 }, 6179 }), 6180 }, 6181 }, 6182 }); 6183 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(then_block.instructions.items)); 6184 sema.air_extra.appendSliceAssumeCapacity(@ptrCast(else_block.instructions.items)); 6185 6186 sema.air_instructions.items(.data)[@backingInt(cond_block_inst)].ty_pl.payload = sema.addExtraAssumeCapacity(Air.Block{ .body_len = 1 }); 6187 sema.air_extra.appendAssumeCapacity(@backingInt(cond_br_inst)); 6188 } 6189 } 6190 6191 fn zirCall( 6192 sema: *Sema, 6193 block: *Block, 6194 inst: Zir.Inst.Index, 6195 comptime kind: enum { direct, field }, 6196 ) CompileError!Air.Inst.Ref { 6197 const pt = sema.pt; 6198 const zcu = pt.zcu; 6199 const comp = zcu.comp; 6200 const gpa = comp.gpa; 6201 const io = comp.io; 6202 6203 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 6204 const callee_src = block.src(.{ .node_offset_call_func = inst_data.src_node }); 6205 const call_src = block.nodeOffset(inst_data.src_node); 6206 const ExtraType = switch (kind) { 6207 .direct => Zir.Inst.Call, 6208 .field => Zir.Inst.FieldCall, 6209 }; 6210 const extra = sema.code.extraData(ExtraType, inst_data.payload_index); 6211 const args_len = extra.data.flags.args_len; 6212 6213 const modifier: std.lang.CallModifier = @fromBackingInt(@intCast(extra.data.flags.packed_modifier)); 6214 const ensure_result_used = extra.data.flags.ensure_result_used; 6215 const pop_error_return_trace = extra.data.flags.pop_error_return_trace; 6216 6217 const callee: ResolvedFieldCallee = switch (kind) { 6218 .direct => .{ .direct = sema.resolveInst(extra.data.callee) }, 6219 .field => blk: { 6220 const object_ptr = sema.resolveInst(extra.data.obj_ptr); 6221 const field_name = try zcu.intern_pool.getOrPutString( 6222 gpa, 6223 io, 6224 pt.tid, 6225 sema.code.nullTerminatedString(extra.data.field_name_start), 6226 .no_embedded_nulls, 6227 ); 6228 const field_name_src = block.src(.{ .node_offset_field_name = inst_data.src_node }); 6229 break :blk try sema.fieldCallBind(block, callee_src, object_ptr, field_name, field_name_src); 6230 }, 6231 }; 6232 const func: Air.Inst.Ref = switch (callee) { 6233 .direct => |func_inst| func_inst, 6234 .method => |method| method.func_inst, 6235 }; 6236 6237 const callee_ty = sema.typeOf(func); 6238 const total_args = args_len + @intFromBool(callee == .method); 6239 const func_ty = try sema.checkCallArgumentCount(block, func, callee_src, callee_ty, total_args, callee == .method); 6240 6241 // The block index before the call, so we can potentially insert an error trace save here later. 6242 const block_index: Air.Inst.Index = @fromBackingInt(@intCast(block.instructions.items.len)); 6243 6244 // This will be set by `analyzeCall` to indicate whether any parameter was an error (making the 6245 // error trace potentially dirty). 6246 var input_is_error = false; 6247 6248 const args_info: CallArgsInfo = .{ .zir_call = .{ 6249 .bound_arg = switch (callee) { 6250 .direct => .none, 6251 .method => |method| method.arg0_inst, 6252 }, 6253 .bound_arg_src = callee_src, 6254 .call_inst = inst, 6255 .call_node_offset = inst_data.src_node, 6256 .num_args = args_len, 6257 .args_body = @ptrCast(sema.code.extra[extra.end..]), 6258 .any_arg_is_error = &input_is_error, 6259 } }; 6260 6261 // AstGen ensures that a call instruction is always preceded by a dbg_stmt instruction. 6262 const call_dbg_node: Zir.Inst.Index = @fromBackingInt(@intCast(@backingInt(inst) - 1)); 6263 const call_inst = try sema.analyzeCall(block, func, func_ty, callee_src, call_src, modifier, ensure_result_used, args_info, call_dbg_node, .call); 6264 6265 if (block.ownerModule().error_tracing and 6266 !block.isComptime() and !block.is_typeof and (input_is_error or pop_error_return_trace)) 6267 { 6268 const return_ty = sema.typeOf(call_inst); 6269 if (modifier != .always_tail and return_ty.isNoReturn(zcu)) 6270 return call_inst; // call to "fn (...) noreturn", don't pop 6271 6272 // TODO: we don't fix up the error trace for always_tail correctly, we should be doing it 6273 // *before* the recursive call. This will be a bit tricky to do and probably requires 6274 // moving this logic into analyzeCall. But that's probably a good idea anyway. 6275 if (modifier == .always_tail) 6276 return call_inst; 6277 6278 // If any input is an error-type, we might need to pop any trace it generated. Otherwise, we only 6279 // need to clean-up our own trace if we were passed to a non-error-handling expression. 6280 if (input_is_error or (pop_error_return_trace and return_ty.isError(zcu))) { 6281 const stack_trace_ty = try sema.getStdLangType(call_src, .StackTrace); 6282 const field_name = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, "index", .no_embedded_nulls); 6283 const field_index = try sema.structFieldIndex(block, stack_trace_ty, field_name, call_src); 6284 6285 // Insert a save instruction before the arg resolution + call instructions we just generated 6286 const save_inst = try block.insertInst(block_index, .{ 6287 .tag = .save_err_return_trace_index, 6288 .data = .{ .ty_pl = .{ 6289 .ty = stack_trace_ty, 6290 .payload = @intCast(field_index), 6291 } }, 6292 }); 6293 6294 // Pop the error return trace, testing the result for non-error if necessary 6295 const operand = if (pop_error_return_trace or modifier == .always_tail) .none else call_inst; 6296 try sema.popErrorReturnTrace(block, call_src, operand, save_inst); 6297 } 6298 6299 return call_inst; 6300 } else { 6301 return call_inst; 6302 } 6303 } 6304 6305 fn checkCallArgumentCount( 6306 sema: *Sema, 6307 block: *Block, 6308 func: Air.Inst.Ref, 6309 func_src: LazySrcLoc, 6310 callee_ty: Type, 6311 total_args: usize, 6312 member_fn: bool, 6313 ) !Type { 6314 const pt = sema.pt; 6315 const zcu = pt.zcu; 6316 const func_ty: Type = func_ty: { 6317 switch (callee_ty.zigTypeTag(zcu)) { 6318 .@"fn" => break :func_ty callee_ty, 6319 .pointer => { 6320 const ptr_info = callee_ty.ptrInfo(zcu); 6321 if (ptr_info.flags.size == .one and Type.fromInterned(ptr_info.child).zigTypeTag(zcu) == .@"fn") { 6322 break :func_ty .fromInterned(ptr_info.child); 6323 } 6324 }, 6325 .optional => { 6326 const opt_child = callee_ty.optionalChild(zcu); 6327 if (opt_child.zigTypeTag(zcu) == .@"fn" or (opt_child.isSinglePointer(zcu) and 6328 opt_child.childType(zcu).zigTypeTag(zcu) == .@"fn")) 6329 { 6330 const msg = msg: { 6331 const msg = try sema.errMsg(func_src, "cannot call optional type '{f}'", .{ 6332 callee_ty.fmt(pt), 6333 }); 6334 errdefer msg.destroy(sema.gpa); 6335 try sema.errNote(func_src, msg, "consider using '.?', 'orelse' or 'if'", .{}); 6336 break :msg msg; 6337 }; 6338 return sema.failWithOwnedErrorMsg(block, msg); 6339 } 6340 }, 6341 else => {}, 6342 } 6343 return sema.fail(block, func_src, "type '{f}' not a function", .{callee_ty.fmt(pt)}); 6344 }; 6345 6346 const func_ty_info = zcu.typeToFunc(func_ty).?; 6347 const fn_params_len = func_ty_info.param_types.len; 6348 const args_len = total_args - @intFromBool(member_fn); 6349 if (func_ty_info.is_var_args) { 6350 assert(callConvSupportsVarArgs(func_ty_info.cc)); 6351 if (total_args >= fn_params_len) return func_ty; 6352 } else if (fn_params_len == total_args) { 6353 return func_ty; 6354 } 6355 6356 const maybe_func_inst = try sema.funcDeclSrcInst(func); 6357 const member_str = if (member_fn) "member function " else ""; 6358 const variadic_str = if (func_ty_info.is_var_args) "at least " else ""; 6359 const msg = msg: { 6360 const msg = try sema.errMsg( 6361 func_src, 6362 "{s}expected {s}{d} argument(s), found {d}", 6363 .{ 6364 member_str, 6365 variadic_str, 6366 fn_params_len - @intFromBool(member_fn), 6367 args_len, 6368 }, 6369 ); 6370 errdefer msg.destroy(sema.gpa); 6371 6372 if (maybe_func_inst) |func_inst| { 6373 try sema.errNote(.{ 6374 .base_node_inst = func_inst, 6375 .offset = LazySrcLoc.Offset.nodeOffset(.zero), 6376 }, msg, "function declared here", .{}); 6377 } 6378 break :msg msg; 6379 }; 6380 return sema.failWithOwnedErrorMsg(block, msg); 6381 } 6382 6383 fn callBuiltin( 6384 sema: *Sema, 6385 block: *Block, 6386 call_src: LazySrcLoc, 6387 builtin_fn: Air.Inst.Ref, 6388 modifier: std.lang.CallModifier, 6389 args: []const Air.Inst.Ref, 6390 operation: CallOperation, 6391 ) !void { 6392 const pt = sema.pt; 6393 const zcu = pt.zcu; 6394 const callee_ty = sema.typeOf(builtin_fn); 6395 const func_ty: Type = func_ty: { 6396 switch (callee_ty.zigTypeTag(zcu)) { 6397 .@"fn" => break :func_ty callee_ty, 6398 .pointer => { 6399 const ptr_info = callee_ty.ptrInfo(zcu); 6400 if (ptr_info.flags.size == .one and Type.fromInterned(ptr_info.child).zigTypeTag(zcu) == .@"fn") { 6401 break :func_ty .fromInterned(ptr_info.child); 6402 } 6403 }, 6404 else => {}, 6405 } 6406 std.debug.panic("type '{f}' is not a function calling builtin fn", .{callee_ty.fmt(pt)}); 6407 }; 6408 6409 const func_ty_info = zcu.typeToFunc(func_ty).?; 6410 const fn_params_len = func_ty_info.param_types.len; 6411 if (args.len != fn_params_len or (func_ty_info.is_var_args and args.len < fn_params_len)) { 6412 std.debug.panic("parameter count mismatch calling builtin fn, expected {d}, found {d}", .{ fn_params_len, args.len }); 6413 } 6414 6415 _ = try sema.analyzeCall( 6416 block, 6417 builtin_fn, 6418 func_ty, 6419 call_src, 6420 call_src, 6421 modifier, 6422 false, 6423 .{ .resolved = .{ .src = call_src, .args = args } }, 6424 null, 6425 operation, 6426 ); 6427 } 6428 6429 const CallOperation = enum { 6430 call, 6431 @"@call", 6432 @"@panic", 6433 @"safety check", 6434 @"error return", 6435 }; 6436 6437 const CallArgsInfo = union(enum) { 6438 /// The full list of resolved (but uncoerced) arguments is known ahead of time. 6439 resolved: struct { 6440 src: LazySrcLoc, 6441 args: []const Air.Inst.Ref, 6442 }, 6443 6444 /// The list of resolved (but uncoerced) arguments is known ahead of time, but 6445 /// originated from a usage of the @call builtin at the given node offset. 6446 call_builtin: struct { 6447 call_node_offset: std.zig.Ast.Node.Offset, 6448 args: []const Air.Inst.Ref, 6449 }, 6450 6451 /// This call corresponds to a ZIR call instruction. The arguments have not yet been 6452 /// resolved. They must be resolved by `analyzeCall` so that argument resolution and 6453 /// generic instantiation may be interleaved. This is required for RLS to work on 6454 /// generic parameters. 6455 zir_call: struct { 6456 /// This may be `none`, in which case it is ignored. Otherwise, it is the 6457 /// already-resolved value of the first argument, from method call syntax. 6458 bound_arg: Air.Inst.Ref, 6459 /// The source location of `bound_arg` if it is not `null`. Otherwise `undefined`. 6460 bound_arg_src: LazySrcLoc, 6461 /// The ZIR call instruction. The parameter type is placed at this index while 6462 /// analyzing arguments. 6463 call_inst: Zir.Inst.Index, 6464 /// The node offset of `call_inst`. 6465 call_node_offset: std.zig.Ast.Node.Offset, 6466 /// The number of arguments to this call, not including `bound_arg`. 6467 num_args: u32, 6468 /// The ZIR corresponding to all function arguments (other than `bound_arg`, if it 6469 /// is not `none`). Format is precisely the same as trailing data of ZIR `call`. 6470 args_body: []const Zir.Inst.Index, 6471 /// This bool will be set to true if any argument evaluated turns out to have an error set or error union type. 6472 /// This is used by the caller to restore the error return trace when necessary. 6473 any_arg_is_error: *bool, 6474 }, 6475 6476 fn count(cai: CallArgsInfo) usize { 6477 return switch (cai) { 6478 inline .resolved, .call_builtin => |resolved| resolved.args.len, 6479 .zir_call => |zir_call| zir_call.num_args + @intFromBool(zir_call.bound_arg != .none), 6480 }; 6481 } 6482 6483 fn argSrc(cai: CallArgsInfo, block: *Block, arg_index: usize) LazySrcLoc { 6484 return switch (cai) { 6485 .resolved => |resolved| resolved.src, 6486 .call_builtin => |call_builtin| block.src(.{ .call_arg = .{ 6487 .call_node_offset = call_builtin.call_node_offset, 6488 .arg_index = @intCast(arg_index), 6489 } }), 6490 .zir_call => |zir_call| if (arg_index == 0 and zir_call.bound_arg != .none) { 6491 return zir_call.bound_arg_src; 6492 } else block.src(.{ .call_arg = .{ 6493 .call_node_offset = zir_call.call_node_offset, 6494 .arg_index = @intCast(arg_index - @intFromBool(zir_call.bound_arg != .none)), 6495 } }), 6496 }; 6497 } 6498 6499 /// Analyzes the arg at `arg_index` and coerces it to `param_ty`. 6500 /// `param_ty` may be `generic_poison`. A value of `null` indicates a varargs parameter. 6501 /// `func_ty_info` may be the type before instantiation, even if a generic instantiation is in progress. 6502 /// Emits a compile error if the argument is not comptime-known despite either `block.isComptime()` or 6503 /// the parameter being marked `comptime`. 6504 fn analyzeArg( 6505 cai: CallArgsInfo, 6506 sema: *Sema, 6507 block: *Block, 6508 arg_index: usize, 6509 maybe_param_ty: ?Type, 6510 func_ty_info: InternPool.Key.FuncType, 6511 func_inst: Air.Inst.Ref, 6512 maybe_func_src_inst: ?InternPool.TrackedInst.Index, 6513 ) CompileError!Air.Inst.Ref { 6514 const pt = sema.pt; 6515 const zcu = pt.zcu; 6516 const param_count = func_ty_info.param_types.len; 6517 const uncoerced_arg: Air.Inst.Ref = switch (cai) { 6518 inline .resolved, .call_builtin => |resolved| resolved.args[arg_index], 6519 .zir_call => |zir_call| arg_val: { 6520 // Generate args to comptime params in comptime block 6521 const parent_comptime = block.comptime_reason; 6522 defer block.comptime_reason = parent_comptime; 6523 // Note that we are indexing into parameters, not arguments, so use `arg_index` instead of `real_arg_idx` 6524 if (std.math.cast(u5, arg_index)) |i| { 6525 if (i < param_count and func_ty_info.paramIsComptime(i)) { 6526 block.comptime_reason = .{ 6527 .reason = .{ 6528 .src = cai.argSrc(block, arg_index), 6529 .r = .{ 6530 .comptime_param = .{ 6531 .comptime_src = if (maybe_func_src_inst) |src_inst| .{ 6532 .base_node_inst = src_inst, 6533 .offset = .{ .func_decl_param_comptime = @intCast(arg_index) }, 6534 } else unreachable, // should be non-null because the function is generic 6535 }, 6536 }, 6537 }, 6538 }; 6539 } 6540 } 6541 6542 const has_bound_arg = zir_call.bound_arg != .none; 6543 const uncoerced_arg = if (arg_index == 0 and has_bound_arg) zir_call.bound_arg else arg: { 6544 const real_arg_idx = arg_index - @intFromBool(has_bound_arg); 6545 6546 const arg_body = if (real_arg_idx == 0) blk: { 6547 const start = zir_call.num_args; 6548 const end = @backingInt(zir_call.args_body[0]); 6549 break :blk zir_call.args_body[start..end]; 6550 } else blk: { 6551 const start = @backingInt(zir_call.args_body[real_arg_idx - 1]); 6552 const end = @backingInt(zir_call.args_body[real_arg_idx]); 6553 break :blk zir_call.args_body[start..end]; 6554 }; 6555 6556 // Give the arg its result type 6557 const provide_param_ty: Type = maybe_param_ty orelse .generic_poison; 6558 sema.inst_map.putAssumeCapacity(zir_call.call_inst, Air.internedToRef(provide_param_ty.toIntern())); 6559 // Resolve the arg! 6560 break :arg try sema.resolveInlineBody(block, arg_body, zir_call.call_inst); 6561 }; 6562 6563 if (block.isComptime() and !try sema.isComptimeKnown(uncoerced_arg)) { 6564 return sema.failWithNeededComptime(block, cai.argSrc(block, arg_index), null); 6565 } 6566 6567 if (sema.typeOf(uncoerced_arg).classify(zcu) == .no_possible_value) { 6568 // This terminates resolution of arguments. The caller should 6569 // propagate this. 6570 return uncoerced_arg; 6571 } 6572 6573 if (sema.typeOf(uncoerced_arg).isError(zcu)) { 6574 zir_call.any_arg_is_error.* = true; 6575 } 6576 6577 break :arg_val uncoerced_arg; 6578 }, 6579 }; 6580 const param_ty = maybe_param_ty orelse { 6581 return sema.coerceVarArgParam(block, uncoerced_arg, cai.argSrc(block, arg_index)); 6582 }; 6583 switch (param_ty.toIntern()) { 6584 .generic_poison_type => return uncoerced_arg, 6585 else => return sema.coerceExtra( 6586 block, 6587 param_ty, 6588 uncoerced_arg, 6589 cai.argSrc(block, arg_index), 6590 .{ .param_src = .{ 6591 .func_inst = func_inst, 6592 .param_i = @intCast(arg_index), 6593 } }, 6594 ) catch |err| switch (err) { 6595 error.NotCoercible => unreachable, 6596 else => |e| return e, 6597 }, 6598 } 6599 } 6600 }; 6601 6602 fn analyzeCall( 6603 sema: *Sema, 6604 block: *Block, 6605 callee: Air.Inst.Ref, 6606 func_ty: Type, 6607 func_src: LazySrcLoc, 6608 call_src: LazySrcLoc, 6609 modifier: std.lang.CallModifier, 6610 ensure_result_used: bool, 6611 args_info: CallArgsInfo, 6612 call_dbg_node: ?Zir.Inst.Index, 6613 operation: CallOperation, 6614 ) CompileError!Air.Inst.Ref { 6615 const pt = sema.pt; 6616 const zcu = pt.zcu; 6617 const comp = zcu.comp; 6618 const gpa = comp.gpa; 6619 const io = comp.io; 6620 const ip = &zcu.intern_pool; 6621 const arena = sema.arena; 6622 6623 const maybe_func_inst = try sema.funcDeclSrcInst(callee); 6624 const func_ret_ty_src: LazySrcLoc = if (maybe_func_inst) |fn_decl_inst| .{ 6625 .base_node_inst = fn_decl_inst, 6626 .offset = .{ .node_offset_fn_type_ret_ty = .zero }, 6627 } else func_src; 6628 6629 const func_ty_info = zcu.typeToFunc(func_ty).?; 6630 6631 for (func_ty_info.param_types.get(ip), 0..) |param_ty_ip, param_index| { 6632 const arg_src = args_info.argSrc(block, param_index); 6633 try sema.ensureLayoutResolved(.fromInterned(param_ty_ip), arg_src, .init); 6634 } 6635 try sema.ensureLayoutResolved(.fromInterned(func_ty_info.return_type), func_ret_ty_src, .return_type); 6636 try sema.validateResolvedFuncType( 6637 block, 6638 func_ty_info.cc, 6639 func_ty_info.param_types.get(ip), 6640 .fromInterned(func_ty_info.return_type), 6641 func_src, 6642 maybe_func_inst, 6643 ); 6644 6645 if (!callConvIsCallable(func_ty_info.cc)) { 6646 return sema.failWithOwnedErrorMsg(block, msg: { 6647 const msg = try sema.errMsg( 6648 func_src, 6649 "unable to call function with calling convention '{s}'", 6650 .{@tagName(func_ty_info.cc)}, 6651 ); 6652 errdefer msg.destroy(gpa); 6653 if (maybe_func_inst) |func_inst| try sema.errNote(.{ 6654 .base_node_inst = func_inst, 6655 .offset = .nodeOffset(.zero), 6656 }, msg, "function declared here", .{}); 6657 break :msg msg; 6658 }); 6659 } 6660 6661 const any_comptime_params = func_ty_info.comptime_bits != 0 or ct: { 6662 for (func_ty_info.param_types.get(ip)) |param_ty| { 6663 if (Type.fromInterned(param_ty).comptimeOnly(zcu)) break :ct true; 6664 } 6665 break :ct Type.fromInterned(func_ty_info.return_type).comptimeOnly(zcu); 6666 }; 6667 const any_generic_types = generic: { 6668 for (func_ty_info.param_types.get(ip)) |param_ty| { 6669 if (param_ty == .generic_poison_type) break :generic true; 6670 } 6671 const ret_ty: Type = .fromInterned(func_ty_info.return_type); 6672 if (ret_ty.toIntern() == .generic_poison_type) { 6673 break :generic true; 6674 } 6675 if (ret_ty.zigTypeTag(zcu) == .error_union and 6676 ret_ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) 6677 { 6678 break :generic true; 6679 } 6680 break :generic false; 6681 }; 6682 6683 // We need this value in a few code paths. 6684 const callee_val = try sema.resolveDefinedValue(block, call_src, callee); 6685 // If the callee is a comptime-known *non-extern* function, `func_val` is populated. 6686 // If it is a comptime-known extern function, `func_is_extern` is set instead. 6687 // If it is not comptime-known, neither is set. 6688 const func_val: ?Value, const func_is_extern: bool = if (callee_val) |c| switch (ip.indexToKey(c.toIntern())) { 6689 .func => .{ c, false }, 6690 .ptr => switch (try sema.pointerDerefExtra(block, func_src, c)) { 6691 .runtime_load, .needed_well_defined, .out_of_bounds => .{ null, false }, 6692 .val => |pointee| switch (ip.indexToKey(pointee.toIntern())) { 6693 .func => .{ pointee, false }, 6694 .@"extern" => .{ null, true }, 6695 else => unreachable, 6696 }, 6697 }, 6698 .@"extern" => .{ null, true }, 6699 else => unreachable, 6700 } else .{ null, false }; 6701 6702 if ((any_generic_types or any_comptime_params) and func_val == null) { 6703 return sema.failWithNeededComptime(block, func_src, .{ .simple = .generic_call_target }); 6704 } 6705 6706 const inline_requested = func_ty_info.cc == .@"inline" or modifier == .always_inline; 6707 6708 // If the modifier is `.compile_time`, or if the return type is non-generic and comptime-only, 6709 // then we need to enter a comptime scope *now* to make sure the args are comptime-eval'd. 6710 const old_block_comptime_reason = block.comptime_reason; 6711 defer block.comptime_reason = old_block_comptime_reason; 6712 if (!block.isComptime()) { 6713 if (modifier == .compile_time) { 6714 block.comptime_reason = .{ .reason = .{ 6715 .src = call_src, 6716 .r = .{ .simple = .comptime_call_modifier }, 6717 } }; 6718 } else if (!inline_requested) { 6719 const ret_ty: Type = .fromInterned(func_ty_info.return_type); 6720 if (ret_ty.comptimeOnly(zcu)) { 6721 block.comptime_reason = .{ .reason = .{ 6722 .src = call_src, 6723 .r = .{ .comptime_only_ret_ty = .{ 6724 .ty = .fromInterned(func_ty_info.return_type), 6725 .is_generic_inst = false, 6726 .ret_ty_src = func_ret_ty_src, 6727 } }, 6728 } }; 6729 } 6730 } 6731 } 6732 6733 // This is whether we already know this to be an inline call. 6734 // If so, then comptime-known arguments are propagated when evaluating generic parameter/return types. 6735 // We might still learn that this call is inline *after* evaluating the generic return type. 6736 const early_known_inline = inline_requested or block.isComptime(); 6737 6738 // These values are undefined if `func_val == null`. 6739 const fn_nav: InternPool.Nav, const fn_zir: Zir, const fn_tracked_inst: InternPool.TrackedInst.Index, const fn_zir_inst: Zir.Inst.Index, const fn_zir_info: Zir.FnInfo = if (func_val) |f| b: { 6740 const info = ip.indexToKey(f.toIntern()).func; 6741 const nav = ip.getNav(info.owner_nav); 6742 const resolved_func_inst = info.zir_body_inst.resolveFull(ip) orelse { 6743 return sema.failTransitive(.{ .lost_tracking = info.zir_body_inst }); 6744 }; 6745 const file = zcu.fileByIndex(resolved_func_inst.file); 6746 const zir_info = file.zir.?.getFnInfo(resolved_func_inst.inst); 6747 break :b .{ nav, file.zir.?, info.zir_body_inst, resolved_func_inst.inst, zir_info }; 6748 } else .{ undefined, undefined, undefined, undefined, undefined }; 6749 6750 // This is the `inst_map` used when evaluating generic parameters and return types. 6751 var generic_inst_map: InstMap = .{}; 6752 defer generic_inst_map.deinit(gpa); 6753 if (any_generic_types) { 6754 try generic_inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body); 6755 } 6756 6757 // This exists so that `generic_block` below can include a "called from here" note back to this 6758 // call site when analyzing generic parameter/return types. 6759 var generic_inlining: Block.Inlining = if (any_generic_types) .{ 6760 .call_block = block, 6761 .call_src = call_src, 6762 .func = func_val.?.toIntern(), 6763 .is_generic_instantiation = true, // this allows the following fields to be `undefined` 6764 .has_comptime_args = undefined, 6765 .comptime_result = undefined, 6766 .merges = undefined, 6767 } else undefined; 6768 6769 // This is the block in which we evaluate generic function components: that is, generic parameter 6770 // types and the generic return type. This must not be used if the function is not generic. 6771 // `comptime_reason` is set as needed. 6772 var generic_block: Block = if (any_generic_types) .{ 6773 .parent = null, 6774 .sema = sema, 6775 .namespace = fn_nav.analysis.?.namespace, 6776 .instructions = .empty, 6777 .inlining = &generic_inlining, 6778 .src_base_inst = fn_nav.analysis.?.zir_index, 6779 .type_name_ctx = fn_nav.name, 6780 .type_fqn_ctx = fn_nav.fqn, 6781 } else undefined; 6782 defer if (any_generic_types) generic_block.instructions.deinit(gpa); 6783 6784 if (any_generic_types) { 6785 // We certainly depend on the generic owner's signature! 6786 try sema.declareDependency(.{ .src_hash = fn_tracked_inst }); 6787 } 6788 6789 const args = try arena.alloc(Air.Inst.Ref, args_info.count()); 6790 for (args, 0..) |*arg, arg_idx| { 6791 const param_ty: ?Type = if (arg_idx < func_ty_info.param_types.len) ty: { 6792 const raw = func_ty_info.param_types.get(ip)[arg_idx]; 6793 if (raw != .generic_poison_type) break :ty .fromInterned(raw); 6794 6795 // We must discover the generic parameter type. 6796 assert(any_generic_types); 6797 const param_inst_idx = fn_zir_info.param_body[arg_idx]; 6798 const param_inst = fn_zir.instructions.get(@backingInt(param_inst_idx)); 6799 switch (param_inst.tag) { 6800 .param_anytype, .param_anytype_comptime => break :ty .generic_poison, 6801 .param, .param_comptime => {}, 6802 else => unreachable, 6803 } 6804 6805 // Evaluate the generic parameter type. We need to switch out `sema.code` and `sema.inst_map`, because 6806 // the function definition may be in a different file to the call site. 6807 const old_code = sema.code; 6808 const old_inst_map = sema.inst_map; 6809 defer { 6810 generic_inst_map = sema.inst_map; 6811 sema.code = old_code; 6812 sema.inst_map = old_inst_map; 6813 } 6814 sema.code = fn_zir; 6815 sema.inst_map = generic_inst_map; 6816 6817 const extra = sema.code.extraData(Zir.Inst.Param, param_inst.data.pl_tok.payload_index); 6818 const param_src = generic_block.tokenOffset(param_inst.data.pl_tok.src_tok); 6819 const body = sema.code.bodySlice(extra.end, extra.data.type.body_len); 6820 6821 generic_block.comptime_reason = .{ .reason = .{ 6822 .r = .{ .simple = .fn_param_types }, 6823 .src = param_src, 6824 } }; 6825 6826 const ty_ref = try sema.resolveInlineBody(&generic_block, body, param_inst_idx); 6827 const param_ty = try sema.analyzeAsType(&generic_block, param_src, .fn_param_types, ty_ref); 6828 6829 if (!param_ty.isValidParamType(zcu)) { 6830 const opaque_str = if (param_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; 6831 return sema.fail(block, param_src, "parameter of {s}type '{f}' not allowed", .{ 6832 opaque_str, param_ty.fmt(pt), 6833 }); 6834 } 6835 6836 break :ty param_ty; 6837 } else null; // vararg 6838 6839 arg.* = try args_info.analyzeArg(sema, block, arg_idx, param_ty, func_ty_info, callee, maybe_func_inst); 6840 const arg_ty = sema.typeOf(arg.*); 6841 if (arg_ty.classify(zcu) == .no_possible_value) { 6842 return arg.*; // terminate analysis here 6843 } 6844 6845 if (any_generic_types) { 6846 // We need to put the argument into `generic_inst_map` so that other parameters can refer to it. 6847 const param_inst_idx = fn_zir_info.param_body[arg_idx]; 6848 const declared_comptime = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsComptime(i) else false; 6849 const param_is_comptime = declared_comptime or arg_ty.comptimeOnly(zcu); 6850 // We allow comptime-known arguments to propagate to generic types not only for comptime 6851 // parameters, but if the call is known to be inline. 6852 if (param_is_comptime or early_known_inline) { 6853 if (param_is_comptime and !try sema.isComptimeKnown(arg.*)) { 6854 assert(!declared_comptime); // `analyzeArg` handles this 6855 const arg_src = args_info.argSrc(block, arg_idx); 6856 const param_ty_src: LazySrcLoc = .{ 6857 .base_node_inst = maybe_func_inst.?, // the function is generic 6858 .offset = .{ .func_decl_param_ty = @intCast(arg_idx) }, 6859 }; 6860 return sema.failWithNeededComptime( 6861 block, 6862 arg_src, 6863 .{ .comptime_only_param_ty = .{ .ty = arg_ty, .param_ty_src = param_ty_src } }, 6864 ); 6865 } 6866 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, arg.*); 6867 } else if (try arg_ty.onePossibleValue(pt)) |opv| { 6868 // The argument is comptime-known, even though this is a generic instantiation (as 6869 // opposed to an inline call), because the parameter type is OPV. 6870 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, .fromValue(opv)); 6871 } else { 6872 // We need a dummy instruction with this type. It doesn't actually need to be in any block, 6873 // since it will never be referenced at runtime! 6874 const dummy: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 6875 try sema.air_instructions.append(gpa, .{ .tag = .alloc, .data = .{ .ty = arg_ty } }); 6876 generic_inst_map.putAssumeCapacityNoClobber(param_inst_idx, dummy.toRef()); 6877 } 6878 } 6879 } 6880 6881 // This return type is never generic poison. 6882 // However, if it has an IES, it is always associated with the callee value. 6883 // This is not correct for inline calls (where it should be an ad-hoc IES), nor for generic 6884 // calls (where it should be the IES of the instantiation). However, it's how we print this 6885 // in error messages. 6886 const resolved_ret_ty: Type = ret_ty: { 6887 if (!any_generic_types) break :ret_ty .fromInterned(func_ty_info.return_type); 6888 6889 const maybe_poison_bare = if (fn_zir_info.inferred_error_set) maybe_poison: { 6890 break :maybe_poison ip.errorUnionPayload(func_ty_info.return_type); 6891 } else func_ty_info.return_type; 6892 6893 if (maybe_poison_bare != .generic_poison_type) break :ret_ty .fromInterned(func_ty_info.return_type); 6894 6895 // Evaluate the generic return type. As with generic parameters, we switch out `sema.code` and `sema.inst_map`. 6896 6897 assert(any_generic_types); 6898 6899 const old_code = sema.code; 6900 const old_inst_map = sema.inst_map; 6901 defer { 6902 generic_inst_map = sema.inst_map; 6903 sema.code = old_code; 6904 sema.inst_map = old_inst_map; 6905 } 6906 sema.code = fn_zir; 6907 sema.inst_map = generic_inst_map; 6908 6909 generic_block.comptime_reason = .{ .reason = .{ 6910 .r = .{ .simple = .fn_ret_ty }, 6911 .src = func_ret_ty_src, 6912 } }; 6913 6914 const bare_ty = if (fn_zir_info.ret_ty_ref != .none) bare: { 6915 assert(fn_zir_info.ret_ty_body.len == 0); 6916 break :bare try sema.resolveType(&generic_block, func_ret_ty_src, fn_zir_info.ret_ty_ref); 6917 } else bare: { 6918 assert(fn_zir_info.ret_ty_body.len != 0); 6919 const ty_ref = try sema.resolveInlineBody(&generic_block, fn_zir_info.ret_ty_body, fn_zir_inst); 6920 break :bare try sema.analyzeAsType(&generic_block, func_ret_ty_src, .fn_ret_ty, ty_ref); 6921 }; 6922 assert(bare_ty.toIntern() != .generic_poison_type); 6923 6924 const full_ty = if (fn_zir_info.inferred_error_set) full: { 6925 try sema.validateErrorUnionPayloadType(block, bare_ty, func_ret_ty_src); 6926 const set = ip.errorUnionSet(func_ty_info.return_type); 6927 break :full try pt.errorUnionType(.fromInterned(set), bare_ty); 6928 } else bare_ty; 6929 6930 if (!full_ty.isValidReturnType(zcu)) { 6931 const opaque_str = if (full_ty.zigTypeTag(zcu) == .@"opaque") "opaque " else ""; 6932 return sema.fail(block, func_ret_ty_src, "{s}return type '{f}' not allowed", .{ 6933 opaque_str, full_ty.fmt(pt), 6934 }); 6935 } 6936 6937 break :ret_ty full_ty; 6938 }; 6939 try sema.ensureLayoutResolved(resolved_ret_ty, func_ret_ty_src, .return_type); 6940 6941 // If we've discovered after evaluating arguments that a generic function instantiation is 6942 // comptime-only, then we can mark the block as comptime *now*. 6943 if (!inline_requested and !block.isComptime() and resolved_ret_ty.comptimeOnly(zcu)) { 6944 block.comptime_reason = .{ 6945 .reason = .{ 6946 .src = call_src, 6947 .r = .{ 6948 .comptime_only_ret_ty = .{ 6949 .ty = resolved_ret_ty, 6950 .is_generic_inst = true, 6951 .ret_ty_src = func_ret_ty_src, 6952 }, 6953 }, 6954 }, 6955 }; 6956 } 6957 6958 if (call_dbg_node) |some| try sema.zirDbgStmt(block, some); 6959 6960 const is_inline_call = block.isComptime() or inline_requested; 6961 6962 if (!is_inline_call) { 6963 if (func_val == null and !func_is_extern and !block.is_typeof and zcu.getTarget().cpu.arch.isSpirV()) { 6964 return sema.fail(block, func_src, "SPIR-V does not support calling function pointers", .{}); 6965 } 6966 if (sema.func_is_naked) return sema.failWithOwnedErrorMsg(block, msg: { 6967 const msg = try sema.errMsg(call_src, "runtime {s} not allowed in naked function", .{@tagName(operation)}); 6968 errdefer msg.destroy(gpa); 6969 switch (operation) { 6970 .call, .@"@call", .@"@panic", .@"error return" => {}, 6971 .@"safety check" => try sema.errNote(call_src, msg, "use @setRuntimeSafety to disable runtime safety", .{}), 6972 } 6973 break :msg msg; 6974 }); 6975 if (func_ty_info.cc == .auto) { 6976 switch (sema.owner.unwrap()) { 6977 .@"comptime", 6978 .nav_ty, 6979 .nav_val, 6980 .type_layout, 6981 .struct_defaults, 6982 .memoized_state, 6983 => {}, 6984 6985 .func => |owner_func| ip.funcSetHasErrorTrace(io, owner_func, true), 6986 } 6987 } 6988 for (args, 0..) |arg, arg_idx| { 6989 const arg_src = args_info.argSrc(block, arg_idx); 6990 try sema.validateRuntimeValue(block, arg_src, arg); 6991 } 6992 const runtime_func: Air.Inst.Ref, const runtime_args: []const Air.Inst.Ref = func: { 6993 if (!any_generic_types and !any_comptime_params) break :func .{ callee, args }; 6994 6995 // Instantiate the generic function! 6996 6997 // This may be an overestimate, but it's definitely sufficient. 6998 const max_runtime_args = args_info.count() - @popCount(func_ty_info.comptime_bits); 6999 var runtime_args: std.ArrayList(Air.Inst.Ref) = try .initCapacity(arena, max_runtime_args); 7000 var runtime_param_tys: std.ArrayList(InternPool.Index) = try .initCapacity(arena, max_runtime_args); 7001 7002 const comptime_args = try arena.alloc(InternPool.Index, args_info.count()); 7003 7004 var noalias_bits: u32 = 0; 7005 7006 for (args, comptime_args, 0..) |arg, *comptime_arg, arg_idx| { 7007 const arg_ty = sema.typeOf(arg); 7008 7009 const is_comptime = c: { 7010 if (std.math.cast(u5, arg_idx)) |i| { 7011 if (func_ty_info.paramIsComptime(i)) { 7012 break :c true; 7013 } 7014 } 7015 break :c arg_ty.comptimeOnly(zcu); 7016 }; 7017 const is_noalias = if (std.math.cast(u5, arg_idx)) |i| func_ty_info.paramIsNoalias(i) else false; 7018 7019 if (is_comptime) { 7020 // We already emitted an error if the argument isn't comptime-known. 7021 comptime_arg.* = sema.resolveValue(arg).?.toIntern(); 7022 } else { 7023 comptime_arg.* = .none; 7024 if (is_noalias) { 7025 const runtime_idx = runtime_args.items.len; 7026 noalias_bits |= @as(u32, 1) << @intCast(runtime_idx); 7027 } 7028 runtime_args.appendAssumeCapacity(arg); 7029 runtime_param_tys.appendAssumeCapacity(arg_ty.toIntern()); 7030 } 7031 } 7032 7033 const bare_ret_ty = if (fn_zir_info.inferred_error_set) t: { 7034 break :t resolved_ret_ty.errorUnionPayload(zcu); 7035 } else resolved_ret_ty; 7036 7037 // We now need to actually create the function instance. 7038 const func_instance = try ip.getFuncInstance(gpa, io, pt.tid, .{ 7039 .param_types = runtime_param_tys.items, 7040 .noalias_bits = noalias_bits, 7041 .bare_return_type = bare_ret_ty.toIntern(), 7042 .is_noinline = func_ty_info.is_noinline, 7043 .inferred_error_set = fn_zir_info.inferred_error_set, 7044 .generic_owner = func_val.?.toIntern(), 7045 .comptime_args = comptime_args, 7046 .anon_name_counter = &zcu.anon_name_counter, 7047 }); 7048 if (zcu.comp.debugIncremental()) { 7049 const nav = ip.indexToKey(func_instance).func.owner_nav; 7050 const gop = try zcu.incremental_debug_state.navs.getOrPut(gpa, nav); 7051 if (!gop.found_existing) gop.value_ptr.* = zcu.generation; 7052 } 7053 7054 // This call is problematic as it breaks guarantees about order-independency of semantic analysis. 7055 // These guarantees are necessary for incremental compilation and parallel semantic analysis. 7056 // See: #22410 7057 zcu.funcInfo(func_instance).maxBranchQuota(ip, io, sema.branch_quota); 7058 7059 break :func .{ Air.internedToRef(func_instance), runtime_args.items }; 7060 }; 7061 7062 ref_func: { 7063 const runtime_func_val = sema.resolveValue(runtime_func) orelse break :ref_func; 7064 if (!ip.isFuncBody(runtime_func_val.toIntern())) break :ref_func; 7065 const orig_fn_index = ip.unwrapCoercedFunc(runtime_func_val.toIntern()); 7066 try sema.addReferenceEntry(block, call_src, .wrap(.{ .func = orig_fn_index })); 7067 try zcu.ensureFuncBodyAnalysisQueued(orig_fn_index); 7068 } 7069 7070 const call_tag: Air.Inst.Tag = switch (modifier) { 7071 .auto, .no_suspend => .call, 7072 .never_tail => .call_never_tail, 7073 .never_inline => .call_never_inline, 7074 .always_tail => .call_always_tail, 7075 7076 .always_inline, 7077 .compile_time, 7078 => unreachable, 7079 }; 7080 7081 try sema.air_extra.ensureUnusedCapacity(gpa, @typeInfo(Air.Call).@"struct".field_names.len + runtime_args.len); 7082 const call_ref = try block.addInst(.{ 7083 .tag = call_tag, 7084 .data = .{ .pl_op = .{ 7085 .operand = runtime_func, 7086 .payload = sema.addExtraAssumeCapacity(Air.Call{ 7087 .args_len = @intCast(runtime_args.len), 7088 }), 7089 } }, 7090 }); 7091 sema.appendRefsAssumeCapacity(runtime_args); 7092 7093 const actual_ret_ty = sema.typeOf(call_ref); 7094 7095 if (ensure_result_used) { 7096 try sema.ensureResultUsed(block, actual_ret_ty, call_src); 7097 } 7098 7099 if (call_tag == .call_always_tail) { 7100 const func_or_ptr_ty = sema.typeOf(runtime_func); 7101 const runtime_func_ty = switch (func_or_ptr_ty.zigTypeTag(zcu)) { 7102 .@"fn" => func_or_ptr_ty, 7103 .pointer => func_or_ptr_ty.childType(zcu), 7104 else => unreachable, 7105 }; 7106 const result = sema.coerceExtra(block, sema.fn_ret_ty, call_ref, call_src, .{ .is_ret = true }) catch |err| switch (err) { 7107 error.NotCoercible => unreachable, 7108 else => |e| return e, 7109 }; 7110 return sema.handleTailCall(block, call_src, runtime_func_ty, result); 7111 } 7112 7113 switch (actual_ret_ty.classify(zcu)) { 7114 .no_possible_value => { 7115 const want_check = c: { 7116 if (!block.wantSafety()) break :c false; 7117 if (func_val != null) break :c false; 7118 break :c true; 7119 }; 7120 if (want_check) { 7121 try sema.safetyPanic(block, call_src, .noreturn_returned); 7122 } else { 7123 _ = try block.addNoOp(.unreach); 7124 } 7125 return .unreachable_value; 7126 }, 7127 .one_possible_value => { 7128 return .fromValue((try actual_ret_ty.onePossibleValue(pt)).?); 7129 }, 7130 .runtime => { 7131 return call_ref; 7132 }, 7133 .partially_comptime => unreachable, 7134 .fully_comptime => unreachable, 7135 } 7136 } 7137 7138 // This is an inline call. The function must be comptime-known. We will analyze its body directly using this `Sema`. 7139 7140 if (zcu.comp.time_report) |*tr| { 7141 if (!block.isComptime()) { 7142 tr.stats.n_inline_calls += 1; 7143 } 7144 } 7145 7146 if (func_ty_info.is_noinline and !block.isComptime()) { 7147 return sema.fail(block, call_src, "inline call of noinline function", .{}); 7148 } 7149 7150 const call_type: []const u8 = if (block.isComptime()) "comptime" else "inline"; 7151 if (modifier == .never_inline) { 7152 const msg, const fail_block = msg: { 7153 const msg = try sema.errMsg(call_src, "cannot perform {s} call with 'never_inline' modifier", .{call_type}); 7154 errdefer msg.destroy(gpa); 7155 const fail_block = if (block.isComptime()) b: { 7156 break :b try block.explainWhyBlockIsComptime(msg); 7157 } else block; 7158 break :msg .{ msg, fail_block }; 7159 }; 7160 return sema.failWithOwnedErrorMsg(fail_block, msg); 7161 } 7162 if (func_ty_info.is_var_args) { 7163 const msg, const fail_block = msg: { 7164 const msg = try sema.errMsg(call_src, "{s} call of variadic function", .{call_type}); 7165 errdefer msg.destroy(gpa); 7166 const fail_block = if (block.isComptime()) b: { 7167 break :b try block.explainWhyBlockIsComptime(msg); 7168 } else block; 7169 break :msg .{ msg, fail_block }; 7170 }; 7171 return sema.failWithOwnedErrorMsg(fail_block, msg); 7172 } 7173 if (func_val == null) { 7174 if (func_is_extern) { 7175 const msg, const fail_block = msg: { 7176 const msg = try sema.errMsg(call_src, "{s} call of extern function", .{call_type}); 7177 errdefer msg.destroy(gpa); 7178 const fail_block = if (block.isComptime()) b: { 7179 break :b try block.explainWhyBlockIsComptime(msg); 7180 } else block; 7181 break :msg .{ msg, fail_block }; 7182 }; 7183 return sema.failWithOwnedErrorMsg(fail_block, msg); 7184 } 7185 return sema.failWithNeededComptime( 7186 block, 7187 func_src, 7188 if (block.isComptime()) null else .{ .simple = .inline_call_target }, 7189 ); 7190 } 7191 7192 if (block.isComptime()) { 7193 for (args, 0..) |arg, arg_idx| { 7194 if (!try sema.isComptimeKnown(arg)) { 7195 const arg_src = args_info.argSrc(block, arg_idx); 7196 return sema.failWithNeededComptime(block, arg_src, null); 7197 } 7198 } 7199 } 7200 7201 // For an inline call, we depend on the source code of the whole function definition. 7202 try sema.declareDependency(.{ .src_hash = fn_nav.analysis.?.zir_index }); 7203 7204 try sema.emitBackwardBranch(block, call_src); 7205 7206 const want_memoize = m: { 7207 // TODO: comptime call memoization is currently not supported under incremental compilation 7208 // since dependencies are not marked on callers. If we want to keep this around (we should 7209 // check that it's worthwhile first!), each memoized call needs an `AnalUnit`. 7210 if (zcu.comp.config.incremental) break :m false; 7211 if (!block.isComptime()) break :m false; 7212 for (args) |a| { 7213 const val = sema.resolveValue(a).?; 7214 if (val.canMutateComptimeVarState(zcu)) break :m false; 7215 } 7216 break :m true; 7217 }; 7218 const memoized_arg_values: []const InternPool.Index = if (want_memoize) arg_vals: { 7219 const vals = try sema.arena.alloc(InternPool.Index, args.len); 7220 for (vals, args) |*v, a| v.* = sema.resolveValue(a).?.toIntern(); 7221 break :arg_vals vals; 7222 } else undefined; 7223 if (want_memoize) memoize: { 7224 const memoized_call_index = ip.getIfExists(.{ 7225 .memoized_call = .{ 7226 .func = func_val.?.toIntern(), 7227 .arg_values = memoized_arg_values, 7228 .result = undefined, // ignored by hash+eql 7229 .branch_count = undefined, // ignored by hash+eql 7230 .branch_quota = undefined, // ignored by hash+eql 7231 }, 7232 }) orelse break :memoize; 7233 const memoized_call = ip.indexToKey(memoized_call_index).memoized_call; 7234 if (sema.branch_count + memoized_call.branch_count > sema.branch_quota) { 7235 // Let the call play out se we get the correct source location for the 7236 // "evaluation exceeded X backwards branches" error. 7237 break :memoize; 7238 } 7239 sema.branch_count += memoized_call.branch_count; 7240 sema.branch_quota = @max(sema.branch_quota, memoized_call.branch_quota); 7241 sema.quota_request = @max(sema.quota_request, memoized_call.branch_quota); 7242 const result = Air.internedToRef(memoized_call.result); 7243 if (ensure_result_used) { 7244 try sema.ensureResultUsed(block, sema.typeOf(result), call_src); 7245 } 7246 return result; 7247 } 7248 7249 var new_ies: InferredErrorSet = .{ .func = .none }; 7250 7251 const old_inst_map = sema.inst_map; 7252 const old_code = sema.code; 7253 const old_func_index = sema.func_index; 7254 const old_fn_ret_ty = sema.fn_ret_ty; 7255 const old_fn_ret_ty_ies = sema.fn_ret_ty_ies; 7256 const old_error_return_trace_index_on_fn_entry = sema.error_return_trace_index_on_fn_entry; 7257 defer { 7258 sema.inst_map.deinit(gpa); 7259 sema.inst_map = old_inst_map; 7260 sema.code = old_code; 7261 sema.func_index = old_func_index; 7262 sema.fn_ret_ty = old_fn_ret_ty; 7263 sema.fn_ret_ty_ies = old_fn_ret_ty_ies; 7264 sema.error_return_trace_index_on_fn_entry = old_error_return_trace_index_on_fn_entry; 7265 } 7266 sema.inst_map = .{}; 7267 sema.code = fn_zir; 7268 sema.func_index = func_val.?.toIntern(); 7269 sema.fn_ret_ty = if (fn_zir_info.inferred_error_set) try pt.errorUnionType( 7270 .fromInterned(.adhoc_inferred_error_set_type), 7271 resolved_ret_ty.errorUnionPayload(zcu), 7272 ) else resolved_ret_ty; 7273 sema.fn_ret_ty_ies = if (fn_zir_info.inferred_error_set) &new_ies else null; 7274 7275 try sema.inst_map.ensureSpaceForInstructions(gpa, fn_zir_info.param_body); 7276 for (args, 0..) |arg, arg_idx| { 7277 sema.inst_map.putAssumeCapacityNoClobber(fn_zir_info.param_body[arg_idx], arg); 7278 } 7279 7280 const need_debug_scope = !block.isComptime() and !block.is_typeof and !block.ownerModule().strip; 7281 const block_inst: Air.Inst.Index = @fromBackingInt(@intCast(sema.air_instructions.len)); 7282 try sema.air_instructions.append(gpa, .{ 7283 .tag = if (need_debug_scope) .dbg_inline_block else .block, 7284 .data = undefined, 7285 }); 7286 7287 var inlining: Block.Inlining = .{ 7288 .call_block = block, 7289 .call_src = call_src, 7290 .func = func_val.?.toIntern(), 7291 .is_generic_instantiation = false, 7292 .has_comptime_args = for (args) |a| { 7293 if (try sema.isComptimeKnown(a)) break true; 7294 } else false, 7295 .comptime_result = undefined, 7296 .merges = .{ 7297 .block_inst = block_inst, 7298 .results = .empty, 7299 .br_list = .empty, 7300 .src_locs = .empty, 7301 }, 7302 }; 7303 var child_block: Block = .{ 7304 .parent = null, 7305 .sema = sema, 7306 .namespace = fn_nav.analysis.?.namespace, 7307 .instructions = .empty, 7308 .inlining = &inlining, 7309 .is_typeof = block.is_typeof, 7310 .comptime_reason = if (block.isComptime()) .inlining_parent else null, 7311 .error_return_trace_index = block.error_return_trace_index, 7312 .runtime_cond = block.runtime_cond, 7313 .runtime_loop = block.runtime_loop, 7314 .runtime_index = block.runtime_index, 7315 .src_base_inst = fn_nav.analysis.?.zir_index, 7316 .type_name_ctx = fn_nav.name, 7317 .type_fqn_ctx = fn_nav.fqn, 7318 }; 7319 7320 defer child_block.instructions.deinit(gpa); 7321 defer inlining.merges.deinit(gpa); 7322 7323 if (!inlining.has_comptime_args) { 7324 var block_it = block; 7325 while (block_it.inlining) |parent_inlining| { 7326 if (!parent_inlining.is_generic_instantiation and 7327 !parent_inlining.has_comptime_args and 7328 parent_inlining.func == func_val.?.toIntern()) 7329 { 7330 return sema.fail(block, call_src, "inline call is recursive", .{}); 7331 } 7332 block_it = parent_inlining.call_block; 7333 } 7334 } 7335 7336 if (!block.isComptime() and !block.is_typeof) { 7337 const zir_tags = sema.code.instructions.items(.tag); 7338 const zir_datas = sema.code.instructions.items(.data); 7339 for (fn_zir_info.param_body) |inst| switch (zir_tags[@backingInt(inst)]) { 7340 .param, .param_comptime => { 7341 const extra = sema.code.extraData(Zir.Inst.Param, zir_datas[@backingInt(inst)].pl_tok.payload_index); 7342 const param_name = sema.code.nullTerminatedString(extra.data.name); 7343 const air_inst = sema.inst_map.get(inst).?; 7344 try sema.addDbgVar(&child_block, air_inst, .dbg_arg_inline, param_name); 7345 }, 7346 .param_anytype, .param_anytype_comptime => { 7347 const param_name = zir_datas[@backingInt(inst)].str_tok.get(sema.code); 7348 const air_inst = sema.inst_map.get(inst).?; 7349 try sema.addDbgVar(&child_block, air_inst, .dbg_arg_inline, param_name); 7350 }, 7351 else => {}, 7352 }; 7353 } 7354 7355 child_block.error_return_trace_index = try sema.analyzeSaveErrRetIndex(&child_block); 7356 // Save the error trace as our first action in the function 7357 // to match the behavior of runtime function calls. 7358 const error_return_trace_index_on_parent_fn_entry = sema.error_return_trace_index_on_fn_entry; 7359 sema.error_return_trace_index_on_fn_entry = child_block.error_return_trace_index; 7360 defer sema.error_return_trace_index_on_fn_entry = error_return_trace_index_on_parent_fn_entry; 7361 7362 // We temporarily set `allow_memoize` to `true` to track this comptime call. 7363 // It is restored after the call finishes analysis, so that a caller may 7364 // know whether an in-progress call (containing this call) may be memoized. 7365 const old_allow_memoize = sema.allow_memoize; 7366 defer sema.allow_memoize = old_allow_memoize and sema.allow_memoize; 7367 sema.allow_memoize = true; 7368 7369 const old_quota_request = sema.quota_request; 7370 defer sema.quota_request = @max(old_quota_request, sema.quota_request); 7371 sema.quota_request = 0; 7372 7373 // Store the current eval branch count so we can find out how many eval branches 7374 // the comptime call caused. 7375 const old_branch_count = sema.branch_count; 7376 7377 const result_raw: Air.Inst.Ref = result: { 7378 sema.analyzeFnBody(&child_block, fn_zir_info.body) catch |err| switch (err) { 7379 error.ComptimeReturn => break :result inlining.comptime_result, 7380 else => |e| return e, 7381 }; 7382 break :result try sema.resolveAnalyzedBlock(block, call_src, &child_block, &inlining.merges, need_debug_scope); 7383 }; 7384 7385 if (sema.typeOf(result_raw).isNoReturn(zcu)) { 7386 return .unreachable_value; 7387 } 7388 7389 const maybe_opv: Air.Inst.Ref = if (sema.resolveValue(result_raw)) |result_val| r: { 7390 const val_resolved = try sema.resolveAdHocInferredErrorSet(block, call_src, result_val.toIntern()); 7391 break :r Air.internedToRef(val_resolved); 7392 } else r: { 7393 const resolved_ty = try sema.resolveAdHocInferredErrorSetTy(block, call_src, sema.typeOf(result_raw).toIntern()); 7394 if (resolved_ty == .none) break :r result_raw; 7395 // TODO: mutate in place the previous instruction if possible 7396 // rather than adding a bitcast instruction. 7397 break :r try block.addTyOp(.error_cast, .fromInterned(resolved_ty), result_raw); 7398 }; 7399 7400 if (block.isComptime()) { 7401 const result_val = sema.resolveValue(maybe_opv).?; 7402 if (want_memoize and sema.allow_memoize and !result_val.canMutateComptimeVarState(zcu)) { 7403 _ = try pt.intern(.{ .memoized_call = .{ 7404 .func = func_val.?.toIntern(), 7405 .arg_values = memoized_arg_values, 7406 .result = result_val.toIntern(), 7407 .branch_count = sema.branch_count - old_branch_count, 7408 .branch_quota = sema.quota_request, 7409 } }); 7410 } 7411 } 7412 7413 if (ensure_result_used) { 7414 try sema.ensureResultUsed(block, sema.typeOf(maybe_opv), call_src); 7415 } 7416 7417 return maybe_opv; 7418 } 7419 7420 fn handleTailCall(sema: *Sema, block: *Block, call_src: LazySrcLoc, func_ty: Type, result: Air.Inst.Ref) !Air.Inst.Ref { 7421 const pt = sema.pt; 7422 const zcu = pt.zcu; 7423 const target = zcu.getTarget(); 7424 const backend = zcu.comp.getZigBackend(); 7425 if (!target_util.supportsTailCall(target, backend)) { 7426 return sema.fail(block, call_src, "unable to perform tail call: compiler backend '{s}' does not support tail calls on target architecture '{s}' with the selected CPU feature flags", .{ 7427 @tagName(backend), @tagName(target.cpu.arch), 7428 }); 7429 } 7430 const owner_func_ty: Type = .fromInterned(zcu.funcInfo(sema.owner.unwrap().func).ty); 7431 if (owner_func_ty.toIntern() != func_ty.toIntern()) { 7432 return sema.fail(block, call_src, "unable to perform tail call: type of function being called '{f}' does not match type of calling function '{f}'", .{ 7433 func_ty.fmt(pt), owner_func_ty.fmt(pt), 7434 }); 7435 } 7436 _ = try block.addUnOp(.ret, result); 7437 return .unreachable_value; 7438 } 7439 7440 fn zirIntType(sema: *Sema, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7441 const int_type = sema.code.instructions.items(.data)[@backingInt(inst)].int_type; 7442 const ty = try sema.pt.intType(int_type.signedness, int_type.bit_count); 7443 return Air.internedToRef(ty.toIntern()); 7444 } 7445 7446 fn zirOptionalType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7447 const pt = sema.pt; 7448 const zcu = pt.zcu; 7449 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7450 const operand_src = block.src(.{ .node_offset_un_op = inst_data.src_node }); 7451 const child_type = try sema.resolveType(block, operand_src, inst_data.operand); 7452 if (child_type.zigTypeTag(zcu) == .@"opaque") { 7453 return sema.fail(block, operand_src, "opaque type '{f}' cannot be optional", .{child_type.fmt(pt)}); 7454 } else if (child_type.zigTypeTag(zcu) == .null) { 7455 return sema.fail(block, operand_src, "type '{f}' cannot be optional", .{child_type.fmt(pt)}); 7456 } 7457 const opt_type = try pt.optionalType(child_type.toIntern()); 7458 7459 return Air.internedToRef(opt_type.toIntern()); 7460 } 7461 7462 fn zirArrayInitElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7463 const pt = sema.pt; 7464 const zcu = pt.zcu; 7465 const bin = sema.code.instructions.items(.data)[@backingInt(inst)].bin; 7466 const maybe_wrapped_indexable_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, bin.lhs) orelse return .generic_poison_type; 7467 const indexable_ty = maybe_wrapped_indexable_ty.optEuBaseType(zcu); 7468 assert(indexable_ty.isIndexable(zcu)); // validated by a previous instruction 7469 const elem_ty = switch (indexable_ty.zigTypeTag(zcu)) { 7470 .@"struct" => indexable_ty.fieldType(@backingInt(bin.rhs), zcu), 7471 else => indexable_ty.indexableElem(zcu), 7472 }; 7473 return .fromType(elem_ty); 7474 } 7475 7476 fn zirElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7477 const pt = sema.pt; 7478 const zcu = pt.zcu; 7479 const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7480 const maybe_wrapped_ptr_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; 7481 const ptr_ty = maybe_wrapped_ptr_ty.optEuBaseType(zcu); 7482 assert(ptr_ty.zigTypeTag(zcu) == .pointer); // validated by a previous instruction 7483 const elem_ty = ptr_ty.childType(zcu); 7484 if (elem_ty.toIntern() == .anyopaque_type) { 7485 // The pointer's actual child type is effectively unknown, so it makes 7486 // sense to represent it with a generic poison. 7487 return .generic_poison_type; 7488 } 7489 return Air.internedToRef(ptr_ty.childType(zcu).toIntern()); 7490 } 7491 7492 fn zirIndexablePtrElemType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7493 const pt = sema.pt; 7494 const zcu = pt.zcu; 7495 const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7496 const src = block.nodeOffset(un_node.src_node); 7497 const ptr_ty = try sema.resolveTypeOrPoison(block, src, un_node.operand) orelse return .generic_poison_type; 7498 try sema.checkMemOperand(block, src, ptr_ty); 7499 const elem_ty = switch (ptr_ty.ptrSize(zcu)) { 7500 .slice, .many, .c => ptr_ty.childType(zcu), 7501 .one => ptr_ty.childType(zcu).childType(zcu), 7502 }; 7503 return Air.internedToRef(elem_ty.toIntern()); 7504 } 7505 7506 fn zirSplatOpResultType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7507 const pt = sema.pt; 7508 const zcu = pt.zcu; 7509 const un_node = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7510 7511 const raw_ty = try sema.resolveTypeOrPoison(block, LazySrcLoc.unneeded, un_node.operand) orelse return .generic_poison_type; 7512 const vec_ty = raw_ty.optEuBaseType(zcu); 7513 7514 switch (vec_ty.zigTypeTag(zcu)) { 7515 .array, .vector => {}, 7516 else => return sema.fail(block, block.nodeOffset(un_node.src_node), "expected array or vector type, found '{f}'", .{vec_ty.fmt(pt)}), 7517 } 7518 return Air.internedToRef(vec_ty.childType(zcu).toIntern()); 7519 } 7520 7521 fn zirVectorType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7522 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7523 const len_src = block.builtinCallArgSrc(inst_data.src_node, 0); 7524 const elem_type_src = block.builtinCallArgSrc(inst_data.src_node, 1); 7525 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7526 const len: u32 = @intCast(try sema.resolveInt(block, len_src, extra.lhs, .u32, .{ .simple = .vector_length })); 7527 const elem_type = try sema.resolveType(block, elem_type_src, extra.rhs); 7528 try sema.checkVectorElemType(block, elem_type_src, elem_type); 7529 const vector_type = try sema.pt.vectorType(.{ 7530 .len = len, 7531 .child = elem_type.toIntern(), 7532 }); 7533 return Air.internedToRef(vector_type.toIntern()); 7534 } 7535 7536 fn zirArrayType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7537 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7538 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7539 const len_src = block.src(.{ .node_offset_array_type_len = inst_data.src_node }); 7540 const elem_src = block.src(.{ .node_offset_array_type_elem = inst_data.src_node }); 7541 const len = try sema.resolveInt(block, len_src, extra.lhs, .usize, .{ .simple = .array_length }); 7542 const elem_type = try sema.resolveType(block, elem_src, extra.rhs); 7543 try sema.validateArrayElemType(block, elem_type, elem_src); 7544 const array_ty = try sema.pt.arrayType(.{ 7545 .len = len, 7546 .child = elem_type.toIntern(), 7547 }); 7548 7549 return Air.internedToRef(array_ty.toIntern()); 7550 } 7551 7552 fn zirArrayTypeSentinel(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7553 const pt = sema.pt; 7554 const zcu = pt.zcu; 7555 const comp = zcu.comp; 7556 const gpa = comp.gpa; 7557 const io = comp.io; 7558 const ip = &zcu.intern_pool; 7559 7560 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7561 const extra = sema.code.extraData(Zir.Inst.ArrayTypeSentinel, inst_data.payload_index).data; 7562 const len_src = block.src(.{ .node_offset_array_type_len = inst_data.src_node }); 7563 const sentinel_src = block.src(.{ .node_offset_array_type_sentinel = inst_data.src_node }); 7564 const elem_src = block.src(.{ .node_offset_array_type_elem = inst_data.src_node }); 7565 const len = try sema.resolveInt(block, len_src, extra.len, .usize, .{ .simple = .array_length }); 7566 const elem_type = try sema.resolveType(block, elem_src, extra.elem_type); 7567 try sema.validateArrayElemType(block, elem_type, elem_src); 7568 const uncasted_sentinel = sema.resolveInst(extra.sentinel); 7569 const sentinel = try sema.coerce(block, elem_type, uncasted_sentinel, sentinel_src); 7570 const sentinel_val = try sema.resolveConstDefinedValue(block, sentinel_src, sentinel, .{ .simple = .array_sentinel }); 7571 if (sentinel_val.canMutateComptimeVarState(zcu)) { 7572 const sentinel_name = try ip.getOrPutString(gpa, io, pt.tid, "sentinel", .no_embedded_nulls); 7573 return sema.failWithContainsReferenceToComptimeVar(block, sentinel_src, sentinel_name, "sentinel", sentinel_val); 7574 } 7575 const array_ty = try pt.arrayType(.{ 7576 .len = len, 7577 .sentinel = sentinel_val.toIntern(), 7578 .child = elem_type.toIntern(), 7579 }); 7580 try sema.checkSentinelType(block, sentinel_src, elem_type); 7581 7582 return Air.internedToRef(array_ty.toIntern()); 7583 } 7584 7585 fn validateArrayElemType(sema: *Sema, block: *Block, elem_type: Type, elem_src: LazySrcLoc) !void { 7586 const pt = sema.pt; 7587 const zcu = pt.zcu; 7588 if (elem_type.zigTypeTag(zcu) == .@"opaque") { 7589 return sema.fail(block, elem_src, "array of opaque type '{f}' not allowed", .{elem_type.fmt(pt)}); 7590 } else if (elem_type.zigTypeTag(zcu) == .noreturn) { 7591 return sema.fail(block, elem_src, "array of 'noreturn' not allowed", .{}); 7592 } 7593 } 7594 7595 fn zirAnyframeType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7596 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7597 if (true) { 7598 return sema.failWithUseOfAsync(block, block.nodeOffset(inst_data.src_node)); 7599 } 7600 const zcu = sema.zcu; 7601 const operand_src = block.src(.{ .node_offset_anyframe_type = inst_data.src_node }); 7602 const return_type = try sema.resolveType(block, operand_src, inst_data.operand); 7603 const anyframe_type = try zcu.anyframeType(return_type); 7604 7605 return Air.internedToRef(anyframe_type.toIntern()); 7606 } 7607 7608 fn zirErrorUnionType(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7609 const pt = sema.pt; 7610 const zcu = pt.zcu; 7611 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7612 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7613 const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node }); 7614 const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node }); 7615 const error_set = try sema.resolveType(block, lhs_src, extra.lhs); 7616 const payload = try sema.resolveType(block, rhs_src, extra.rhs); 7617 7618 if (error_set.zigTypeTag(zcu) != .error_set) { 7619 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{ 7620 error_set.fmt(pt), 7621 }); 7622 } 7623 try sema.validateErrorUnionPayloadType(block, payload, rhs_src); 7624 const err_union_ty = try pt.errorUnionType(error_set, payload); 7625 return Air.internedToRef(err_union_ty.toIntern()); 7626 } 7627 7628 fn validateErrorUnionPayloadType(sema: *Sema, block: *Block, payload_ty: Type, payload_src: LazySrcLoc) !void { 7629 const pt = sema.pt; 7630 const zcu = pt.zcu; 7631 if (payload_ty.zigTypeTag(zcu) == .@"opaque") { 7632 return sema.fail(block, payload_src, "error union with payload of opaque type '{f}' not allowed", .{ 7633 payload_ty.fmt(pt), 7634 }); 7635 } else if (payload_ty.zigTypeTag(zcu) == .error_set) { 7636 return sema.fail(block, payload_src, "error union with payload of error set type '{f}' not allowed", .{ 7637 payload_ty.fmt(pt), 7638 }); 7639 } 7640 } 7641 7642 fn zirErrorValue(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7643 _ = block; 7644 7645 const pt = sema.pt; 7646 const zcu = pt.zcu; 7647 const comp = zcu.comp; 7648 const gpa = comp.gpa; 7649 const io = comp.io; 7650 7651 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].str_tok; 7652 const name = try pt.zcu.intern_pool.getOrPutString( 7653 gpa, 7654 io, 7655 pt.tid, 7656 inst_data.get(sema.code), 7657 .no_embedded_nulls, 7658 ); 7659 _ = try pt.getErrorValue(name); 7660 // Create an error set type with only this error value, and return the value. 7661 const error_set_type = try pt.singleErrorSetType(name); 7662 return Air.internedToRef((try pt.intern(.{ .err = .{ 7663 .ty = error_set_type.toIntern(), 7664 .name = name, 7665 } }))); 7666 } 7667 7668 fn zirIntFromError(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 7669 const pt = sema.pt; 7670 const zcu = pt.zcu; 7671 const ip = &zcu.intern_pool; 7672 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 7673 const src = block.nodeOffset(extra.node); 7674 const operand_src = block.builtinCallArgSrc(extra.node, 0); 7675 const uncasted_operand = sema.resolveInst(extra.operand); 7676 const operand = try sema.coerce(block, .anyerror, uncasted_operand, operand_src); 7677 const err_int_ty = try pt.errorIntType(); 7678 7679 if (sema.resolveValue(operand)) |val| { 7680 if (val.isUndef(zcu)) { 7681 return pt.undefRef(err_int_ty); 7682 } 7683 const err_name = ip.indexToKey(val.toIntern()).err.name; 7684 return Air.internedToRef((try pt.intValue( 7685 err_int_ty, 7686 try pt.getErrorValue(err_name), 7687 )).toIntern()); 7688 } 7689 7690 const op_ty = sema.typeOf(uncasted_operand); 7691 switch (try sema.resolveInferredErrorSetTy(block, src, op_ty.toIntern())) { 7692 .anyerror_type => {}, 7693 else => |err_set_ty_index| { 7694 const names = ip.indexToKey(err_set_ty_index).error_set_type.names; 7695 switch (names.len) { 7696 0 => return Air.internedToRef((try pt.intValue(err_int_ty, 0)).toIntern()), 7697 1 => return pt.intRef(err_int_ty, ip.getErrorValueIfExists(names.get(ip)[0]).?), 7698 else => {}, 7699 } 7700 }, 7701 } 7702 7703 try sema.requireRuntimeBlock(block, src, operand_src); 7704 return block.addTyOp(.int_from_error, err_int_ty, operand); 7705 } 7706 7707 fn zirErrorFromInt(sema: *Sema, block: *Block, extended: Zir.Inst.Extended.InstData) CompileError!Air.Inst.Ref { 7708 const pt = sema.pt; 7709 const zcu = pt.zcu; 7710 const io = zcu.comp.io; 7711 const ip = &zcu.intern_pool; 7712 7713 const extra = sema.code.extraData(Zir.Inst.UnNode, extended.operand).data; 7714 const src = block.nodeOffset(extra.node); 7715 const operand_src = block.builtinCallArgSrc(extra.node, 0); 7716 const uncasted_operand = sema.resolveInst(extra.operand); 7717 const err_int_ty = try pt.errorIntType(); 7718 const operand = try sema.coerce(block, err_int_ty, uncasted_operand, operand_src); 7719 7720 if (try sema.resolveDefinedValue(block, operand_src, operand)) |value| { 7721 const int = try sema.usizeCast(block, operand_src, value.toUnsignedInt(zcu)); 7722 if (int > len: { 7723 const mutate = &ip.global_error_set.mutate; 7724 mutate.map.mutex.lockUncancelable(io); 7725 defer mutate.map.mutex.unlock(io); 7726 break :len mutate.names.len; 7727 } or int == 0) 7728 return sema.fail(block, operand_src, "integer value '{d}' represents no error", .{int}); 7729 return Air.internedToRef((try pt.intern(.{ .err = .{ 7730 .ty = .anyerror_type, 7731 .name = ip.global_error_set.shared.names.acquire().view().items(.@"0")[int - 1], 7732 } }))); 7733 } 7734 try sema.requireRuntimeBlock(block, src, operand_src); 7735 if (block.wantSafety()) { 7736 const is_lte_len = try block.addUnOp(.cmp_lte_errors_len, operand); 7737 const zero_val = Air.internedToRef((try pt.intValue(err_int_ty, 0)).toIntern()); 7738 const is_non_zero = try block.addBinOp(.cmp_neq, operand, zero_val); 7739 const ok = try block.addBinOp(.bit_and, is_lte_len, is_non_zero); 7740 try sema.addSafetyCheck(block, src, ok, .invalid_error_code); 7741 } 7742 return block.addTyOp(.error_from_int, .anyerror, operand); 7743 } 7744 7745 fn zirMergeErrorSets(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7746 const pt = sema.pt; 7747 const zcu = pt.zcu; 7748 const ip = &zcu.intern_pool; 7749 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7750 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7751 const src = block.src(.{ .node_offset_bin_op = inst_data.src_node }); 7752 const lhs_src = block.src(.{ .node_offset_bin_lhs = inst_data.src_node }); 7753 const rhs_src = block.src(.{ .node_offset_bin_rhs = inst_data.src_node }); 7754 const lhs = sema.resolveInst(extra.lhs); 7755 const rhs = sema.resolveInst(extra.rhs); 7756 if (sema.typeOf(lhs).zigTypeTag(zcu) == .bool and sema.typeOf(rhs).zigTypeTag(zcu) == .bool) { 7757 const msg = msg: { 7758 const msg = try sema.errMsg(lhs_src, "expected error set type, found 'bool'", .{}); 7759 errdefer msg.destroy(sema.gpa); 7760 try sema.errNote(src, msg, "'||' merges error sets; 'or' performs boolean OR", .{}); 7761 break :msg msg; 7762 }; 7763 return sema.failWithOwnedErrorMsg(block, msg); 7764 } 7765 const lhs_ty = try sema.analyzeAsType(block, lhs_src, .type, lhs); 7766 const rhs_ty = try sema.analyzeAsType(block, rhs_src, .type, rhs); 7767 if (lhs_ty.zigTypeTag(zcu) != .error_set) 7768 return sema.fail(block, lhs_src, "expected error set type, found '{f}'", .{lhs_ty.fmt(pt)}); 7769 if (rhs_ty.zigTypeTag(zcu) != .error_set) 7770 return sema.fail(block, rhs_src, "expected error set type, found '{f}'", .{rhs_ty.fmt(pt)}); 7771 7772 // Anything merged with anyerror is anyerror. 7773 if (lhs_ty.toIntern() == .anyerror_type or rhs_ty.toIntern() == .anyerror_type) { 7774 return .anyerror_type; 7775 } 7776 7777 switch (ip.indexToKey(lhs_ty.toIntern())) { 7778 .inferred_error_set_type => |func_index| { 7779 try sema.ensureFuncIesResolved(block, src, func_index); 7780 if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type; 7781 }, 7782 .error_set_type => {}, 7783 else => unreachable, 7784 } 7785 switch (ip.indexToKey(rhs_ty.toIntern())) { 7786 .inferred_error_set_type => |func_index| { 7787 try sema.ensureFuncIesResolved(block, src, func_index); 7788 if (ip.funcIesResolvedUnordered(func_index) == .anyerror_type) return .anyerror_type; 7789 }, 7790 .error_set_type => {}, 7791 else => unreachable, 7792 } 7793 7794 const err_set_ty = try sema.errorSetMerge(lhs_ty, rhs_ty); 7795 return Air.internedToRef(err_set_ty.toIntern()); 7796 } 7797 7798 fn zirEnumLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7799 _ = block; 7800 7801 const pt = sema.pt; 7802 const zcu = pt.zcu; 7803 const comp = zcu.comp; 7804 const gpa = comp.gpa; 7805 const io = comp.io; 7806 7807 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].str_tok; 7808 const name = inst_data.get(sema.code); 7809 return Air.internedToRef((try pt.intern(.{ 7810 .enum_literal = try zcu.intern_pool.getOrPutString(gpa, io, pt.tid, name, .no_embedded_nulls), 7811 }))); 7812 } 7813 7814 fn zirDeclLiteral(sema: *Sema, block: *Block, inst: Zir.Inst.Index, do_coerce: bool) CompileError!Air.Inst.Ref { 7815 const pt = sema.pt; 7816 const zcu = pt.zcu; 7817 const comp = zcu.comp; 7818 const gpa = comp.gpa; 7819 const io = comp.io; 7820 7821 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7822 const src = block.nodeOffset(inst_data.src_node); 7823 const extra = sema.code.extraData(Zir.Inst.Field, inst_data.payload_index).data; 7824 const name = try zcu.intern_pool.getOrPutString( 7825 gpa, 7826 io, 7827 pt.tid, 7828 sema.code.nullTerminatedString(extra.field_name_start), 7829 .no_embedded_nulls, 7830 ); 7831 const orig_ty: Type = try sema.resolveTypeOrPoison(block, src, extra.lhs) orelse .generic_poison; 7832 return sema.analyzeDeclLiteral(block, src, name, orig_ty, do_coerce); 7833 } 7834 7835 fn analyzeDeclLiteral( 7836 sema: *Sema, 7837 block: *Block, 7838 src: LazySrcLoc, 7839 name: InternPool.NullTerminatedString, 7840 orig_ty: Type, 7841 do_coerce: bool, 7842 ) CompileError!Air.Inst.Ref { 7843 const pt = sema.pt; 7844 const zcu = pt.zcu; 7845 7846 const uncoerced_result = res: { 7847 if (orig_ty.toIntern() == .generic_poison_type) { 7848 // Treat this as a normal enum literal. 7849 break :res Air.internedToRef(try pt.intern(.{ .enum_literal = name })); 7850 } 7851 7852 var ty = orig_ty; 7853 while (true) switch (ty.zigTypeTag(zcu)) { 7854 .error_union => ty = ty.errorUnionPayload(zcu), 7855 .optional => ty = ty.optionalChild(zcu), 7856 .pointer => ty = if (ty.isSinglePointer(zcu)) ty.childType(zcu) else break, 7857 .enum_literal, .error_set => { 7858 // Treat this as a normal enum literal. 7859 break :res Air.internedToRef(try pt.intern(.{ .enum_literal = name })); 7860 }, 7861 else => break, 7862 }; 7863 7864 break :res try sema.fieldVal(block, src, Air.internedToRef(ty.toIntern()), name, src); 7865 }; 7866 7867 // Decl literals cannot lookup runtime `var`s. 7868 if (!try sema.isComptimeKnown(uncoerced_result)) { 7869 return sema.fail(block, src, "decl literal must be comptime-known", .{}); 7870 } 7871 7872 if (do_coerce) { 7873 return sema.coerce(block, orig_ty, uncoerced_result, src); 7874 } else { 7875 return uncoerced_result; 7876 } 7877 } 7878 7879 fn zirIntFromEnum(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7880 const pt = sema.pt; 7881 const zcu = pt.zcu; 7882 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7883 const src = block.nodeOffset(inst_data.src_node); 7884 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); 7885 const operand = sema.resolveInst(inst_data.operand); 7886 const operand_ty = sema.typeOf(operand); 7887 7888 const enum_tag: Air.Inst.Ref = switch (operand_ty.zigTypeTag(zcu)) { 7889 .@"enum" => operand, 7890 .@"union" => blk: { 7891 if (operand_ty.unionTagType(zcu) == null) { 7892 return sema.fail( 7893 block, 7894 operand_src, 7895 "untagged union '{f}' cannot be converted to integer", 7896 .{operand_ty.fmt(pt)}, 7897 ); 7898 } 7899 7900 break :blk try sema.unionToTag(block, operand); 7901 }, 7902 else => { 7903 return sema.fail(block, operand_src, "expected enum or tagged union, found '{f}'", .{ 7904 operand_ty.fmt(pt), 7905 }); 7906 }, 7907 }; 7908 const enum_tag_ty = sema.typeOf(enum_tag); 7909 const int_tag_ty = enum_tag_ty.backingIntType(zcu); 7910 assert(int_tag_ty.classify(zcu) != .no_possible_value); 7911 7912 if (sema.resolveValue(enum_tag)) |enum_tag_val| { 7913 if (enum_tag_val.isUndef(zcu)) return pt.undefRef(int_tag_ty); 7914 return .fromValue(enum_tag_val.backingInt(zcu)); 7915 } 7916 7917 try sema.requireRuntimeBlock(block, src, operand_src); 7918 return block.addTyOp(.bit_cast, int_tag_ty, enum_tag); 7919 } 7920 7921 fn zirEnumFromInt(sema: *Sema, block: *Block, inst: Zir.Inst.Index) CompileError!Air.Inst.Ref { 7922 const pt = sema.pt; 7923 const zcu = pt.zcu; 7924 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].pl_node; 7925 const extra = sema.code.extraData(Zir.Inst.Bin, inst_data.payload_index).data; 7926 const src = block.nodeOffset(inst_data.src_node); 7927 const operand_src = block.builtinCallArgSrc(inst_data.src_node, 0); 7928 const dest_ty = try sema.resolveDestType(block, src, extra.lhs, .remove_eu_opt, "@enumFromInt"); 7929 const operand = sema.resolveInst(extra.rhs); 7930 const operand_ty = sema.typeOf(operand); 7931 7932 if (dest_ty.zigTypeTag(zcu) != .@"enum") { 7933 return sema.fail(block, src, "expected enum, found '{f}'", .{dest_ty.fmt(pt)}); 7934 } 7935 try sema.ensureLayoutResolved(dest_ty, src, .init); 7936 _ = try sema.checkIntType(block, operand_src, operand_ty); 7937 7938 if (sema.resolveValue(operand)) |int_val| { 7939 if (dest_ty.isNonexhaustiveEnum(zcu)) { 7940 const int_tag_ty = dest_ty.backingIntType(zcu); 7941 if (int_val.intFitsInType(int_tag_ty, null, zcu)) { 7942 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); 7943 } 7944 return sema.fail(block, src, "int value '{f}' out of range of non-exhaustive enum '{f}'", .{ 7945 int_val.fmtValueSema(pt, sema), dest_ty.fmt(pt), 7946 }); 7947 } 7948 if (int_val.isUndef(zcu)) { 7949 return sema.failWithUseOfUndef(block, operand_src, null); 7950 } 7951 if (!(try sema.enumHasInt(dest_ty, int_val))) { 7952 return sema.fail(block, src, "enum '{f}' has no tag with value '{f}'", .{ 7953 dest_ty.fmt(pt), int_val.fmtValueSema(pt, sema), 7954 }); 7955 } 7956 return Air.internedToRef((try pt.getCoerced(int_val, dest_ty)).toIntern()); 7957 } 7958 7959 if (try dest_ty.onePossibleValue(pt)) |opv| { 7960 if (block.wantSafety()) { 7961 // The operand is runtime-known but the result is comptime-known. In 7962 // this case we still need a safety check. 7963 const expect_int = try pt.getCoerced(opv.backingInt(zcu), operand_ty); 7964 const ok = try block.addBinOp(.cmp_eq, operand, .fromValue(expect_int)); 7965 try sema.addSafetyCheck(block, src, ok, .invalid_enum_value); 7966 } 7967 return .fromValue(opv); 7968 } 7969 7970 try sema.requireRuntimeBlock(block, src, operand_src); 7971 if (block.wantSafety()) { 7972 try sema.preparePanicId(src, .invalid_enum_value); 7973 return block.addTyOp(.int_cast_safe, dest_ty, operand); 7974 } 7975 return block.addTyOp(.int_cast, dest_ty, operand); 7976 } 7977 7978 /// Pointer in, pointer out. 7979 fn zirOptionalPayloadPtr( 7980 sema: *Sema, 7981 block: *Block, 7982 inst: Zir.Inst.Index, 7983 safety_check: bool, 7984 ) CompileError!Air.Inst.Ref { 7985 const inst_data = sema.code.instructions.items(.data)[@backingInt(inst)].un_node; 7986 const optional_ptr = sema.resolveInst(inst_data.operand); 7987 const src = block.nodeOffset(inst_data.src_node); 7988 7989 const ptr_ty = sema.typeOf(optional_ptr); 7990 assert(ptr_ty.zigTypeTag(sema.pt.zcu) == .pointer); 7991 try sema.ensureLayoutResolved(ptr_ty.childType(sema.pt.zcu), src, .ptr_access); 7992 7993 return sema.analyzeOptionalPayloadPtr(block, src, optional_ptr, safety_check, false); 7994 } 7995 7996 /// Asserts that the layout of the pointer child type is already resolved. 7997 fn analyzeOptionalPayloadPtr( 7998 sema: *Sema, 7999 block: *Block, 8000 src: LazySrcLoc, 8001 optional_ptr: Air.Inst.Ref, 8002 safety_check: bool, 8003 initializing: bool, 8004 ) CompileError!Air.Inst.Ref { 8005 const pt = sema.pt; 8006 const zcu = pt.zcu; 8007 const optional_ptr_ty = sema.typeOf(optional_ptr); 8008 assert(optional_ptr_ty.zigTypeTag(zcu) == .pointer); 8009 8010 const opt_type = optional_ptr_ty.childType(zcu); 8011 opt_type.assertHasLayout(zcu); 8012 if (opt_type.zigTypeTag(zcu) != .optional) { 8013 return sema.failWithExpectedOptionalType(block, src, opt_type); 8014 } 8015 8016 const child_type = opt_type.optionalChild(zcu); 8017 const child_pointer = try pt.ptrType(info: { 8018 var new = optional_ptr_ty.ptrInfo(zcu);