╭─────────────╮ │scroll to top│ ╰─────────────╯ ╭ Type.zig ─────────────────────────────────────────────────────╮ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ │ ╰───────────────────────────────────────────────────────────────╯
╭ find file ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╮ ╭────╮ ╭ clone ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╮ │ │ │http│ ssh │ │ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─╯ ╰────╯ ╰ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ─ ╯
1639 return Type.getUnionLayout(union_obj, zcu); 1640 } 1641 1642 pub fn containerLayout(ty: Type, zcu: *const Zcu) std.lang.Type.ContainerLayout { 1643 const ip = &zcu.intern_pool; 1644 return switch (ip.indexToKey(ty.toIntern())) { 1645 .tuple_type => .auto, 1646 .struct_type => ip.loadStructType(ty.toIntern()).layout, 1647 .union_type => ip.loadUnionType(ty.toIntern()).layout, 1648 else => unreachable, 1649 }; 1650 } 1651 1652 /// Asserts that the type is either an enum or a bitpack. 1653 pub fn backingIntType(ty: Type, zcu: *const Zcu) Type { 1654 const ip = &zcu.intern_pool; 1655 return switch (ip.indexToKey(ty.toIntern())) { 1656 .enum_type => .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type), 1657 .struct_type => .fromInterned(ip.loadStructType(ty.toIntern()).packed_backing_int_type), 1658 .union_type => .fromInterned(ip.loadUnionType(ty.toIntern()).packed_backing_int_type), 1659 else => unreachable, 1660 }; 1661 } 1662 1663 /// For unions, returns the *backing int* mode, not the *enum tag* mode. 1664 pub fn backingIntMode(ty: Type, zcu: *const Zcu) InternPool.BackingTypeMode { 1665 const ip = &zcu.intern_pool; 1666 return switch (ip.indexToKey(ty.toIntern())) { 1667 .enum_type => ip.loadEnumType(ty.toIntern()).int_tag_mode, 1668 .struct_type => ip.loadStructType(ty.toIntern()).packed_backing_mode, 1669 .union_type => ip.loadUnionType(ty.toIntern()).packed_backing_mode, 1670 else => unreachable, 1671 }; 1672 } 1673 1674 /// Asserts that the type is an error union. 1675 pub fn errorUnionPayload(ty: Type, zcu: *const Zcu) Type { 1676 return Type.fromInterned(zcu.intern_pool.indexToKey(ty.toIntern()).error_union_type.payload_type); 1677 } 1678 1679 /// Asserts that the type is an error union. 1680 pub fn errorUnionSet(ty: Type, zcu: *const Zcu) Type { 1681 return Type.fromInterned(zcu.intern_pool.errorUnionSet(ty.toIntern())); 1682 } 1683 1684 /// Returns false for unresolved inferred error sets. 1685 /// 1686 /// TODO: this function will behave incorrectly under incremental compilation, because in that case 1687 /// it may see an outdated resolved error set. This function must be either deleted, or its contract 1688 /// changed to require the caller to resolve the error set beforehand. If you must introduce new 1689 /// call sites, please make sure the error set in question is definitely resolved first! 1690 pub fn errorSetIsEmpty(ty: Type, zcu: *const Zcu) bool { 1691 const ip = &zcu.intern_pool; 1692 return switch (ty.toIntern()) { 1693 .anyerror_type, .adhoc_inferred_error_set_type => false, 1694 else => switch (ip.indexToKey(ty.toIntern())) { 1695 .error_set_type => |error_set_type| error_set_type.names.len == 0, 1696 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) { 1697 .none, .anyerror_type => false, 1698 else => |t| ip.indexToKey(t).error_set_type.names.len == 0, 1699 }, 1700 else => unreachable, 1701 }, 1702 }; 1703 } 1704 1705 /// Returns true if it is an error set that includes anyerror, false otherwise. 1706 /// Note that the result may be a false negative if the type did not get error set 1707 /// resolution prior to this call. 1708 /// 1709 /// TODO: this function will behave incorrectly under incremental compilation, because in that case 1710 /// it may see an outdated resolved error set. This function must be either deleted, or its contract 1711 /// changed to require the caller to resolve the error set beforehand. If you must introduce new 1712 /// call sites, please make sure the error set in question is definitely resolved first! 1713 pub fn isAnyError(ty: Type, zcu: *const Zcu) bool { 1714 const ip = &zcu.intern_pool; 1715 return switch (ty.toIntern()) { 1716 .anyerror_type => true, 1717 .adhoc_inferred_error_set_type => false, 1718 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 1719 .inferred_error_set_type => |i| ip.funcIesResolvedUnordered(i) == .anyerror_type, 1720 else => false, 1721 }, 1722 }; 1723 } 1724 1725 pub fn isError(ty: Type, zcu: *const Zcu) bool { 1726 return switch (ty.zigTypeTag(zcu)) { 1727 .error_union, .error_set => true, 1728 else => false, 1729 }; 1730 } 1731 1732 /// Returns whether ty, which must be an error set, includes an error `name`. 1733 /// Might return a false negative if `ty` is an inferred error set and not fully 1734 /// resolved yet. 1735 /// 1736 /// TODO: this function will behave incorrectly under incremental compilation, because in that case 1737 /// it may see an outdated resolved error set. This function must be either deleted, or its contract 1738 /// changed to require the caller to resolve the error set beforehand. If you must introduce new 1739 /// call sites, please make sure the error set in question is definitely resolved first! 1740 pub fn errorSetHasField( 1741 ty: Type, 1742 name: InternPool.NullTerminatedString, 1743 zcu: *const Zcu, 1744 ) bool { 1745 const ip = &zcu.intern_pool; 1746 return switch (ty.toIntern()) { 1747 .anyerror_type => true, 1748 else => switch (ip.indexToKey(ty.toIntern())) { 1749 .error_set_type => |error_set_type| error_set_type.nameIndex(ip, name) != null, 1750 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) { 1751 .anyerror_type => true, 1752 .none => false, 1753 else => |t| ip.indexToKey(t).error_set_type.nameIndex(ip, name) != null, 1754 }, 1755 else => unreachable, 1756 }, 1757 }; 1758 } 1759 1760 /// Asserts the type is an array or vector or struct. 1761 pub fn arrayLen(ty: Type, zcu: *const Zcu) u64 { 1762 return ty.arrayLenIp(&zcu.intern_pool); 1763 } 1764 1765 pub fn arrayLenIp(ty: Type, ip: *const InternPool) u64 { 1766 return ip.aggregateTypeLen(ty.toIntern()); 1767 } 1768 1769 pub fn arrayLenIncludingSentinel(ty: Type, zcu: *const Zcu) u64 { 1770 return zcu.intern_pool.aggregateTypeLenIncludingSentinel(ty.toIntern()); 1771 } 1772 1773 pub fn vectorLen(ty: Type, zcu: *const Zcu) u32 { 1774 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 1775 .vector_type => |vector_type| vector_type.len, 1776 .tuple_type => |tuple| @intCast(tuple.types.len), 1777 else => unreachable, 1778 }; 1779 } 1780 1781 /// Asserts the type is an array, pointer or vector. 1782 pub fn sentinel(ty: Type, zcu: *const Zcu) ?Value { 1783 return switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 1784 .vector_type, 1785 .struct_type, 1786 .tuple_type, 1787 => null, 1788 1789 .array_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null, 1790 .ptr_type => |t| if (t.sentinel != .none) Value.fromInterned(t.sentinel) else null, 1791 1792 else => unreachable, 1793 }; 1794 } 1795 1796 /// Returns true if and only if the type is a fixed-width integer. 1797 pub fn isInt(self: Type, zcu: *const Zcu) bool { 1798 return self.toIntern() != .comptime_int_type and 1799 zcu.intern_pool.isIntegerType(self.toIntern()); 1800 } 1801 1802 /// Returns true if and only if the type is a fixed-width, signed integer. 1803 pub fn isSignedInt(ty: Type, zcu: *const Zcu) bool { 1804 return switch (ty.toIntern()) { 1805 .c_char_type => zcu.getTarget().cCharSignedness().? == .signed, 1806 .isize_type, .c_short_type, .c_int_type, .c_long_type, .c_longlong_type => true, 1807 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 1808 .int_type => |int_type| int_type.signedness == .signed, 1809 else => false, 1810 }, 1811 }; 1812 } 1813 1814 /// Returns true if and only if the type is a fixed-width, unsigned integer. 1815 pub fn isUnsignedInt(ty: Type, zcu: *const Zcu) bool { 1816 return switch (ty.toIntern()) { 1817 .c_char_type => zcu.getTarget().cCharSignedness().? == .unsigned, 1818 .usize_type, .c_ushort_type, .c_uint_type, .c_ulong_type, .c_ulonglong_type => true, 1819 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 1820 .int_type => |int_type| int_type.signedness == .unsigned, 1821 else => false, 1822 }, 1823 }; 1824 } 1825 1826 /// Returns true for integers, enums, error sets, and packed structs/unions. 1827 /// If this function returns true, then intInfo() can be called on the type. 1828 pub fn isAbiInt(ty: Type, zcu: *const Zcu) bool { 1829 return switch (ty.zigTypeTag(zcu)) { 1830 .int, .@"enum", .error_set => true, 1831 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", 1832 else => false, 1833 }; 1834 } 1835 1836 /// Asserts the type is an integer, enum, error set, or vector of one of them. 1837 pub fn intInfo(starting_ty: Type, zcu: *const Zcu) InternPool.Key.IntType { 1838 const ip = &zcu.intern_pool; 1839 const target = zcu.getTarget(); 1840 var ty = starting_ty; 1841 1842 while (true) switch (ty.toIntern()) { 1843 .anyerror_type, .adhoc_inferred_error_set_type => { 1844 return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }; 1845 }, 1846 .usize_type => return .{ .signedness = .unsigned, .bits = target.ptrBitWidth() }, 1847 .isize_type => return .{ .signedness = .signed, .bits = target.ptrBitWidth() }, 1848 .c_char_type => return .{ .signedness = target.cCharSignedness().?, .bits = target.cTypeBitSize(.char).? }, 1849 .c_short_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.short).? }, 1850 .c_ushort_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ushort).? }, 1851 .c_int_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.int).? }, 1852 .c_uint_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.uint).? }, 1853 .c_long_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.long).? }, 1854 .c_ulong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulong).? }, 1855 .c_longlong_type => return .{ .signedness = .signed, .bits = target.cTypeBitSize(.longlong).? }, 1856 .c_ulonglong_type => return .{ .signedness = .unsigned, .bits = target.cTypeBitSize(.ulonglong).? }, 1857 else => switch (ip.indexToKey(ty.toIntern())) { 1858 .int_type => |int_type| return int_type, 1859 .struct_type => { 1860 const struct_obj = ip.loadStructType(ty.toIntern()); 1861 assert(struct_obj.layout == .@"packed"); 1862 ty = .fromInterned(struct_obj.packed_backing_int_type); 1863 }, 1864 .union_type => { 1865 const union_obj = ip.loadUnionType(ty.toIntern()); 1866 assert(union_obj.layout == .@"packed"); 1867 ty = .fromInterned(union_obj.packed_backing_int_type); 1868 }, 1869 .enum_type => ty = .fromInterned(ip.loadEnumType(ty.toIntern()).int_tag_type), 1870 .vector_type => |vector_type| ty = Type.fromInterned(vector_type.child), 1871 1872 .error_set_type, .inferred_error_set_type => { 1873 return .{ .signedness = .unsigned, .bits = zcu.errorSetBits() }; 1874 }, 1875 1876 .tuple_type => unreachable, 1877 1878 .ptr_type => unreachable, 1879 .anyframe_type => unreachable, 1880 .array_type => unreachable, 1881 1882 .opt_type => unreachable, 1883 .error_union_type => unreachable, 1884 .func_type => unreachable, 1885 .simple_type => unreachable, // handled via Index enum tag above 1886 1887 .spirv_type => unreachable, 1888 .opaque_type => unreachable, 1889 1890 // values, not types 1891 .undef, 1892 .simple_value, 1893 .@"extern", 1894 .func, 1895 .int, 1896 .err, 1897 .error_union, 1898 .enum_literal, 1899 .enum_tag, 1900 .float, 1901 .ptr, 1902 .slice, 1903 .opt, 1904 .aggregate, 1905 .un, 1906 .bitpack, 1907 // memoization, not types 1908 .memoized_call, 1909 => unreachable, 1910 }, 1911 }; 1912 } 1913 1914 /// Returns `false` for `comptime_float`. 1915 pub fn isRuntimeFloat(ty: Type) bool { 1916 return switch (ty.toIntern()) { 1917 .f16_type, 1918 .f32_type, 1919 .f64_type, 1920 .f80_type, 1921 .f128_type, 1922 .c_longdouble_type, 1923 => true, 1924 1925 else => false, 1926 }; 1927 } 1928 1929 /// Returns `true` for `comptime_float`. 1930 pub fn isAnyFloat(ty: Type) bool { 1931 return switch (ty.toIntern()) { 1932 .f16_type, 1933 .f32_type, 1934 .f64_type, 1935 .f80_type, 1936 .f128_type, 1937 .c_longdouble_type, 1938 .comptime_float_type, 1939 => true, 1940 1941 else => false, 1942 }; 1943 } 1944 1945 /// Asserts the type is a fixed-size float or comptime_float. 1946 /// Returns 128 for comptime_float types. 1947 pub fn floatBits(ty: Type, target: *const Target) u16 { 1948 return switch (ty.toIntern()) { 1949 .f16_type => 16, 1950 .f32_type => 32, 1951 .f64_type => 64, 1952 .f80_type => 80, 1953 .f128_type, .comptime_float_type => 128, 1954 .c_longdouble_type => target.cTypeBitSize(.longdouble).?, 1955 1956 else => unreachable, 1957 }; 1958 } 1959 1960 /// Asserts the type is a fixed-size float or comptime_float. 1961 pub fn floatSignificandBits(ty: Type, target: *const Target) u16 { 1962 return switch (ty.floatBits(target)) { 1963 16 => 11, 1964 32 => 24, 1965 64 => 53, 1966 80 => 64, 1967 128 => 113, 1968 else => unreachable, 1969 }; 1970 } 1971 1972 /// Asserts the type is a function or a function pointer. 1973 pub fn fnReturnType(ty: Type, zcu: *const Zcu) Type { 1974 return Type.fromInterned(zcu.intern_pool.funcTypeReturnType(ty.toIntern())); 1975 } 1976 1977 /// Asserts the type is a function. 1978 pub fn fnCallingConvention(ty: Type, zcu: *const Zcu) std.lang.CallingConvention { 1979 return zcu.intern_pool.indexToKey(ty.toIntern()).func_type.cc; 1980 } 1981 1982 pub fn isValidParamType(self: Type, zcu: *const Zcu) bool { 1983 if (self.toIntern() == .generic_poison_type) return true; 1984 return switch (self.zigTypeTag(zcu)) { 1985 .@"opaque", .noreturn => false, 1986 else => true, 1987 }; 1988 } 1989 1990 pub fn isValidReturnType(self: Type, zcu: *const Zcu) bool { 1991 if (self.toIntern() == .generic_poison_type) return true; 1992 return switch (self.zigTypeTag(zcu)) { 1993 .@"opaque" => false, 1994 else => true, 1995 }; 1996 } 1997 1998 /// Asserts the type is a function. 1999 pub fn fnIsVarArgs(ty: Type, zcu: *const Zcu) bool { 2000 return zcu.intern_pool.indexToKey(ty.toIntern()).func_type.is_var_args; 2001 } 2002 2003 pub fn fnPtrMaskOrNull(ty: Type, zcu: *const Zcu) ?u64 { 2004 return switch (ty.zigTypeTag(zcu)) { 2005 .@"fn" => target_util.functionPointerMask(zcu.getTarget()), 2006 else => null, 2007 }; 2008 } 2009 2010 pub fn isNumeric(ty: Type, zcu: *const Zcu) bool { 2011 return switch (ty.toIntern()) { 2012 .f16_type, 2013 .f32_type, 2014 .f64_type, 2015 .f80_type, 2016 .f128_type, 2017 .c_longdouble_type, 2018 .comptime_int_type, 2019 .comptime_float_type, 2020 .usize_type, 2021 .isize_type, 2022 .c_char_type, 2023 .c_short_type, 2024 .c_ushort_type, 2025 .c_int_type, 2026 .c_uint_type, 2027 .c_long_type, 2028 .c_ulong_type, 2029 .c_longlong_type, 2030 .c_ulonglong_type, 2031 => true, 2032 2033 else => switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 2034 .int_type => true, 2035 else => false, 2036 }, 2037 }; 2038 } 2039 2040 /// If the type's classification is `Class.one_possible_value` (see `classify`), returns the only 2041 /// possible value for the type. Otherwise, returns `null`. 2042 pub fn onePossibleValue(ty: Type, pt: Zcu.PerThread) !?Value { 2043 const zcu = pt.zcu; 2044 const comp = zcu.comp; 2045 const gpa = comp.gpa; 2046 const ip = &zcu.intern_pool; 2047 assertHasLayout(ty, zcu); 2048 return switch (ip.indexToKey(ty.toIntern())) { 2049 .ptr_type, 2050 .error_union_type, 2051 .func_type, 2052 .anyframe_type, 2053 .error_set_type, 2054 .inferred_error_set_type, 2055 .opaque_type, 2056 .spirv_type, 2057 => null, 2058 2059 .simple_type => |t| switch (t) { 2060 .f16, 2061 .f32, 2062 .f64, 2063 .f80, 2064 .f128, 2065 .usize, 2066 .isize, 2067 .c_char, 2068 .c_short, 2069 .c_ushort, 2070 .c_int, 2071 .c_uint, 2072 .c_long, 2073 .c_ulong, 2074 .c_longlong, 2075 .c_ulonglong, 2076 .c_longdouble, 2077 .anyopaque, 2078 .bool, 2079 .type, 2080 .anyerror, 2081 .comptime_int, 2082 .comptime_float, 2083 .enum_literal, 2084 .adhoc_inferred_error_set, 2085 .null, 2086 .undefined, 2087 .noreturn, 2088 => null, 2089 2090 .void => .void, 2091 2092 .generic_poison => unreachable, 2093 }, 2094 2095 .int_type => |int_type| switch (int_type.bits) { 2096 0 => try pt.intValue(ty, 0), 2097 else => null, 2098 }, 2099 2100 inline .array_type, .vector_type => |seq_type, seq_tag| { 2101 const has_sentinel = seq_tag == .array_type and seq_type.sentinel != .none; 2102 if (seq_type.len + @intFromBool(has_sentinel) == 0) { 2103 return try pt.aggregateValue(ty, &.{}); 2104 } 2105 if (try Type.fromInterned(seq_type.child).onePossibleValue(pt)) |opv| { 2106 return try pt.aggregateSplatValue(ty, opv); 2107 } 2108 return null; 2109 }, 2110 .opt_type => |child| switch (Type.fromInterned(child).classify(zcu)) { 2111 .no_possible_value => try pt.nullValue(ty), 2112 else => null, 2113 }, 2114 .tuple_type => |tuple| { 2115 // Check *whether* the OPV exists first, because constructing it is a little more expensive. 2116 if (ty.classify(zcu) != .one_possible_value) return null; 2117 const field_vals = try zcu.gpa.dupe(InternPool.Index, tuple.values.get(ip)); 2118 defer zcu.gpa.free(field_vals); 2119 for (field_vals, tuple.types.get(ip)) |*field_val, field_ty_ip| { 2120 if (field_val.* != .none) continue; // comptime field value 2121 const field_ty: Type = .fromInterned(field_ty_ip); 2122 field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern(); 2123 } 2124 return try pt.aggregateValue(ty, field_vals); 2125 }, 2126 .struct_type => { 2127 const struct_obj = ip.loadStructType(ty.toIntern()); 2128 switch (struct_obj.layout) { 2129 .auto, .@"extern" => {}, 2130 .@"packed" => { 2131 const backing_ty: Type = .fromInterned(struct_obj.packed_backing_int_type); 2132 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null; 2133 return try pt.bitpackValue(ty, backing_val); 2134 }, 2135 } 2136 // Type resolution already figured out whether there is an OPV, but if there is, it's 2137 // our job to compute it. 2138 if (struct_obj.class != .one_possible_value) return null; 2139 const field_vals = try gpa.alloc(InternPool.Index, struct_obj.field_types.len); 2140 defer gpa.free(field_vals); 2141 for (field_vals, 0..) |*field_val, i_usize| { 2142 const i: u32 = @intCast(i_usize); 2143 if (struct_obj.field_is_comptime_bits.get(ip, i)) { 2144 field_val.* = struct_obj.field_defaults.get(ip)[i]; 2145 assert(field_val.* != .none); 2146 continue; 2147 } 2148 const field_ty: Type = .fromInterned(struct_obj.field_types.get(ip)[i]); 2149 field_val.* = (try field_ty.onePossibleValue(pt)).?.toIntern(); 2150 } 2151 return try pt.aggregateValue(ty, field_vals); 2152 }, 2153 .union_type => { 2154 const union_obj = ip.loadUnionType(ty.toIntern()); 2155 if (union_obj.layout == .@"packed") { 2156 const backing_ty: Type = .fromInterned(union_obj.packed_backing_int_type); 2157 const backing_val = try backing_ty.onePossibleValue(pt) orelse return null; 2158 return try pt.bitpackValue(ty, backing_val); 2159 } 2160 // Type resolution already figured out whether there is an OPV, but if there is, it's 2161 // our job to compute it. 2162 if (union_obj.class != .one_possible_value) return null; 2163 // The OPV comes from exactly one field whose type is OPV, while all others are NPV. 2164 for (union_obj.field_types.get(ip), 0..) |field_ty_ip, field_index| { 2165 const field_ty: Type = .fromInterned(field_ty_ip); 2166 switch (field_ty.classify(zcu)) { 2167 .no_possible_value => continue, 2168 .one_possible_value => {}, 2169 else => unreachable, 2170 } 2171 // This field is the one! 2172 const enum_tag_ty: Type = .fromInterned(union_obj.enum_tag_type); 2173 const tag_val = try pt.enumValueFieldIndex(enum_tag_ty, @intCast(field_index)); 2174 const payload_val = (try field_ty.onePossibleValue(pt)).?; 2175 return try pt.unionValue(ty, tag_val, payload_val); 2176 } else unreachable; 2177 }, 2178 .enum_type => if (try ty.backingIntType(zcu).onePossibleValue(pt)) |int_tag_opv| { 2179 return try pt.enumValue(ty, int_tag_opv); 2180 } else null, 2181 2182 // values, not types 2183 .undef, 2184 .simple_value, 2185 .@"extern", 2186 .func, 2187 .int, 2188 .err, 2189 .error_union, 2190 .enum_literal, 2191 .enum_tag, 2192 .float, 2193 .ptr, 2194 .slice, 2195 .opt, 2196 .aggregate, 2197 .un, 2198 .bitpack, 2199 // memoization, not types 2200 .memoized_call, 2201 => unreachable, 2202 }; 2203 } 2204 2205 /// Asserts that `ty` has its layout resolved. `generic_poison` will return `false`. 2206 pub fn comptimeOnly(ty: Type, zcu: *const Zcu) bool { 2207 if (ty.toIntern() == .generic_poison_type) return false; 2208 if (ty.zigTypeTag(zcu) == .error_union and ty.errorUnionPayload(zcu).toIntern() == .generic_poison_type) return false; 2209 return ty.classify(zcu).comptimeOnly(); 2210 } 2211 2212 pub fn isVector(ty: Type, zcu: *const Zcu) bool { 2213 return ty.zigTypeTag(zcu) == .vector; 2214 } 2215 2216 pub fn isArrayOrVector(ty: Type, zcu: *const Zcu) bool { 2217 return switch (ty.zigTypeTag(zcu)) { 2218 .array, .vector => true, 2219 else => false, 2220 }; 2221 } 2222 2223 pub fn isIndexable(ty: Type, zcu: *const Zcu) bool { 2224 return switch (ty.zigTypeTag(zcu)) { 2225 .array, .vector => true, 2226 .pointer => switch (ty.ptrSize(zcu)) { 2227 .slice, .many, .c => true, 2228 .one => switch (ty.childType(zcu).zigTypeTag(zcu)) { 2229 .array, .vector => true, 2230 .@"struct" => ty.childType(zcu).isTuple(zcu), 2231 .spirv => ty.childType(zcu).isSpirvRuntimeArray(zcu), 2232 else => false, 2233 }, 2234 }, 2235 .@"struct" => ty.isTuple(zcu), 2236 .spirv => ty.isSpirvRuntimeArray(zcu), 2237 else => false, 2238 }; 2239 } 2240 2241 pub fn indexableHasLen(ty: Type, zcu: *const Zcu) bool { 2242 return switch (ty.zigTypeTag(zcu)) { 2243 .array, .vector => true, 2244 .pointer => switch (ty.ptrSize(zcu)) { 2245 .many, .c => false, 2246 .slice => true, 2247 .one => switch (ty.childType(zcu).zigTypeTag(zcu)) { 2248 .array, .vector => true, 2249 .@"struct" => ty.childType(zcu).isTuple(zcu), 2250 else => false, 2251 }, 2252 }, 2253 .@"struct" => ty.isTuple(zcu), 2254 else => false, 2255 }; 2256 } 2257 2258 /// Asserts that the type can have a namespace. 2259 pub fn getNamespaceIndex(ty: Type, zcu: *Zcu) InternPool.NamespaceIndex { 2260 return ty.getNamespace(zcu).unwrap().?; 2261 } 2262 2263 /// Returns null if the type has no namespace. 2264 pub fn getNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex { 2265 const ip = &zcu.intern_pool; 2266 return switch (ip.indexToKey(ty.toIntern())) { 2267 .opaque_type => ip.loadOpaqueType(ty.toIntern()).namespace.toOptional(), 2268 .struct_type => ip.loadStructType(ty.toIntern()).namespace.toOptional(), 2269 .union_type => ip.loadUnionType(ty.toIntern()).namespace.toOptional(), 2270 .enum_type => ip.loadEnumType(ty.toIntern()).namespace.toOptional(), 2271 else => .none, 2272 }; 2273 } 2274 2275 // TODO: new dwarf structure will also need the enclosing code block for types created in imperative scopes 2276 pub fn getParentNamespace(ty: Type, zcu: *Zcu) InternPool.OptionalNamespaceIndex { 2277 return zcu.namespacePtr(ty.getNamespace(zcu).unwrap() orelse return .none).parent; 2278 } 2279 2280 // Works for vectors and vectors of integers. 2281 pub fn minInt(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value { 2282 const zcu = pt.zcu; 2283 const scalar = try minIntScalar(ty.scalarType(zcu), pt, dest_ty.scalarType(zcu)); 2284 return if (ty.zigTypeTag(zcu) == .vector) pt.aggregateSplatValue(dest_ty, scalar) else scalar; 2285 } 2286 2287 /// Asserts that the type is an integer. 2288 pub fn minIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value { 2289 const zcu = pt.zcu; 2290 const info = ty.intInfo(zcu); 2291 if (info.signedness == .unsigned) return pt.intValue(dest_ty, 0); 2292 2293 if (std.math.cast(u6, info.bits - 1)) |shift| { 2294 const n = @as(i64, std.math.minInt(i64)) >> (63 - shift); 2295 return pt.intValue(dest_ty, n); 2296 } 2297 2298 var res = try std.math.big.int.Managed.init(zcu.gpa); 2299 defer res.deinit(); 2300 2301 try res.setTwosCompIntLimit(.min, info.signedness, info.bits); 2302 2303 return pt.intValue_big(dest_ty, res.toConst()); 2304 } 2305 2306 // Works for vectors and vectors of integers. 2307 /// The returned Value will have type dest_ty. 2308 pub fn maxInt(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value { 2309 const zcu = pt.zcu; 2310 const scalar = try maxIntScalar(ty.scalarType(zcu), pt, dest_ty.scalarType(zcu)); 2311 return if (ty.zigTypeTag(zcu) == .vector) pt.aggregateSplatValue(dest_ty, scalar) else scalar; 2312 } 2313 2314 /// The returned Value will have type dest_ty. 2315 pub fn maxIntScalar(ty: Type, pt: Zcu.PerThread, dest_ty: Type) !Value { 2316 const info = ty.intInfo(pt.zcu); 2317 2318 switch (info.bits) { 2319 0 => return pt.intValue(dest_ty, 0), 2320 1 => return switch (info.signedness) { 2321 .signed => try pt.intValue(dest_ty, 0), 2322 .unsigned => try pt.intValue(dest_ty, 1), 2323 }, 2324 else => {}, 2325 } 2326 2327 if (std.math.cast(u6, info.bits - 1)) |shift| switch (info.signedness) { 2328 .signed => { 2329 const n = @as(i64, std.math.maxInt(i64)) >> (63 - shift); 2330 return pt.intValue(dest_ty, n); 2331 }, 2332 .unsigned => { 2333 const n = @as(u64, std.math.maxInt(u64)) >> (63 - shift); 2334 return pt.intValue(dest_ty, n); 2335 }, 2336 }; 2337 2338 var res = try std.math.big.int.Managed.init(pt.zcu.gpa); 2339 defer res.deinit(); 2340 2341 try res.setTwosCompIntLimit(.max, info.signedness, info.bits); 2342 2343 return pt.intValue_big(dest_ty, res.toConst()); 2344 } 2345 2346 pub fn isNonexhaustiveEnum(ty: Type, zcu: *const Zcu) bool { 2347 const ip = &zcu.intern_pool; 2348 return switch (ip.indexToKey(ty.toIntern())) { 2349 .enum_type => ip.loadEnumType(ty.toIntern()).nonexhaustive, 2350 else => false, 2351 }; 2352 } 2353 2354 // Asserts that `ty` is an error set and not `anyerror`. 2355 // Asserts that `ty` is resolved if it is an inferred error set. 2356 pub fn errorSetNames(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice { 2357 const ip = &zcu.intern_pool; 2358 return switch (ip.indexToKey(ty.toIntern())) { 2359 .error_set_type => |x| x.names, 2360 .inferred_error_set_type => |i| switch (ip.funcIesResolvedUnordered(i)) { 2361 .none => unreachable, // unresolved inferred error set 2362 .anyerror_type => unreachable, 2363 else => |t| ip.indexToKey(t).error_set_type.names, 2364 }, 2365 else => unreachable, 2366 }; 2367 } 2368 2369 pub fn enumFields(ty: Type, zcu: *const Zcu) InternPool.NullTerminatedString.Slice { 2370 assertHasLayout(ty, zcu); 2371 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names; 2372 } 2373 2374 pub fn enumFieldCount(ty: Type, zcu: *const Zcu) usize { 2375 assertHasLayout(ty, zcu); 2376 return zcu.intern_pool.loadEnumType(ty.toIntern()).field_names.len; 2377 } 2378 2379 pub fn enumFieldName(ty: Type, field_index: usize, zcu: *const Zcu) InternPool.NullTerminatedString { 2380 assertHasLayout(ty, zcu); 2381 const ip = &zcu.intern_pool; 2382 return ip.loadEnumType(ty.toIntern()).field_names.get(ip)[field_index]; 2383 } 2384 2385 pub fn enumFieldIndex(ty: Type, field_name: InternPool.NullTerminatedString, zcu: *const Zcu) ?u32 { 2386 assertHasLayout(ty, zcu); 2387 const ip = &zcu.intern_pool; 2388 const enum_type = ip.loadEnumType(ty.toIntern()); 2389 return enum_type.nameIndex(ip, field_name); 2390 } 2391 2392 /// Asserts `ty` is an enum. `enum_tag` can either be the actual enum tag value 2393 /// or an integer which represents the enum value. Returns the field index in 2394 /// declaration order, or `null` if `enum_tag` does not match any field. 2395 pub fn enumTagFieldIndex(ty: Type, enum_tag: Value, zcu: *const Zcu) ?u32 { 2396 assertHasLayout(ty, zcu); 2397 const ip = &zcu.intern_pool; 2398 const enum_type = ip.loadEnumType(ty.toIntern()); 2399 const int_tag = switch (ip.indexToKey(enum_tag.toIntern())) { 2400 .int => enum_tag.toIntern(), 2401 .enum_tag => |info| info.int, 2402 else => unreachable, 2403 }; 2404 assert(ip.typeOf(int_tag) == enum_type.int_tag_type); 2405 return enum_type.tagValueIndex(ip, int_tag); 2406 } 2407 2408 /// Returns none in the case of a tuple which uses the integer index as the field name. 2409 pub fn structFieldName(ty: Type, index: usize, zcu: *const Zcu) InternPool.OptionalNullTerminatedString { 2410 const ip = &zcu.intern_pool; 2411 switch (ip.indexToKey(ty.toIntern())) { 2412 .struct_type => { 2413 assertHasLayout(ty, zcu); 2414 return ip.loadStructType(ty.toIntern()).field_names.get(ip)[index].toOptional(); 2415 }, 2416 .tuple_type => return .none, 2417 else => unreachable, 2418 } 2419 } 2420 2421 pub fn structFieldCount(ty: Type, zcu: *const Zcu) u32 { 2422 const ip = &zcu.intern_pool; 2423 switch (ip.indexToKey(ty.toIntern())) { 2424 .struct_type => { 2425 assertHasLayout(ty, zcu); 2426 return ip.loadStructType(ty.toIntern()).field_types.len; 2427 }, 2428 .tuple_type => |tuple| return tuple.types.len, 2429 else => unreachable, 2430 } 2431 } 2432 2433 /// Returns the field type. Supports tuples, structs, and unions. 2434 pub fn fieldType(ty: Type, index: usize, zcu: *const Zcu) Type { 2435 const ip = &zcu.intern_pool; 2436 const types = switch (ip.indexToKey(ty.toIntern())) { 2437 .struct_type => types: { 2438 assertHasLayout(ty, zcu); 2439 break :types ip.loadStructType(ty.toIntern()).field_types; 2440 }, 2441 .union_type => types: { 2442 assertHasLayout(ty, zcu); 2443 break :types ip.loadUnionType(ty.toIntern()).field_types; 2444 }, 2445 .tuple_type => |tuple| tuple.types, 2446 else => unreachable, 2447 }; 2448 return .fromInterned(types.get(ip)[index]); 2449 } 2450 2451 /// If an alignment was explicitly specified for the given field of the struct or union type `ty`, 2452 /// returns that. Otherwise, returns `.none`. This function also supports tuples, for which it 2453 /// always returns `.none`. 2454 /// 2455 /// Asserts that the layout of `ty` is resolved, unless `ty` is a tuple. 2456 pub fn explicitFieldAlignment(ty: Type, index: usize, zcu: *const Zcu) Alignment { 2457 const ip = &zcu.intern_pool; 2458 return switch (ip.indexToKey(ty.toIntern())) { 2459 .tuple_type => .none, 2460 .struct_type => { 2461 assertHasLayout(ty, zcu); 2462 const struct_obj = ip.loadStructType(ty.toIntern()); 2463 assert(struct_obj.layout != .@"packed"); 2464 if (struct_obj.field_aligns.len == 0) return .none; 2465 return struct_obj.field_aligns.get(ip)[index]; 2466 }, 2467 .union_type => { 2468 assertHasLayout(ty, zcu); 2469 const union_obj = ip.loadUnionType(ty.toIntern()); 2470 assert(union_obj.layout != .@"packed"); 2471 if (union_obj.field_aligns.len == 0) return .none; 2472 return union_obj.field_aligns.get(ip)[index]; 2473 }, 2474 else => unreachable, 2475 }; 2476 } 2477 2478 pub fn structFieldDefaultValue(ty: Type, index: usize, zcu: *const Zcu) ?Value { 2479 const ip = &zcu.intern_pool; 2480 switch (ip.indexToKey(ty.toIntern())) { 2481 .struct_type => { 2482 const field_defaults = ip.loadStructType(ty.toIntern()).field_defaults.get(ip); 2483 if (field_defaults.len == 0) return null; 2484 if (field_defaults[index] == .none) return null; 2485 return .fromInterned(field_defaults[index]); 2486 }, 2487 .tuple_type => |tuple| { 2488 const val = tuple.values.get(ip)[index]; 2489 if (val == .none) return null; 2490 return .fromInterned(val); 2491 }, 2492 else => unreachable, 2493 } 2494 } 2495 2496 pub fn structFieldValueComptime(ty: Type, pt: Zcu.PerThread, index: usize) !?Value { 2497 const zcu = pt.zcu; 2498 const ip = &zcu.intern_pool; 2499 switch (ip.indexToKey(ty.toIntern())) { 2500 .struct_type => { 2501 const struct_type = ip.loadStructType(ty.toIntern()); 2502 if (struct_type.field_is_comptime_bits.get(ip, index)) { 2503 return .fromInterned(struct_type.field_defaults.get(ip)[index]); 2504 } else { 2505 return Type.fromInterned(struct_type.field_types.get(ip)[index]).onePossibleValue(pt); 2506 } 2507 }, 2508 .tuple_type => |tuple| { 2509 const val = tuple.values.get(ip)[index]; 2510 if (val == .none) { 2511 return Type.fromInterned(tuple.types.get(ip)[index]).onePossibleValue(pt); 2512 } else { 2513 return .fromInterned(val); 2514 } 2515 }, 2516 else => unreachable, 2517 } 2518 } 2519 2520 pub fn structFieldIsComptime(ty: Type, index: usize, zcu: *const Zcu) bool { 2521 const ip = &zcu.intern_pool; 2522 switch (ip.indexToKey(ty.toIntern())) { 2523 .struct_type => { 2524 assertHasLayout(ty, zcu); 2525 return ip.loadStructType(ty.toIntern()).field_is_comptime_bits.get(ip, index); 2526 }, 2527 .tuple_type => |tuple| return tuple.values.get(ip)[index] != .none, 2528 else => unreachable, 2529 } 2530 } 2531 2532 pub const FieldOffset = struct { 2533 field: usize, 2534 offset: u64, 2535 }; 2536 2537 /// Supports structs, tuples, and unions. 2538 pub fn structFieldOffset(ty: Type, index: usize, zcu: *const Zcu) u64 { 2539 assertHasLayout(ty, zcu); 2540 const ip = &zcu.intern_pool; 2541 switch (ip.indexToKey(ty.toIntern())) { 2542 .struct_type => { 2543 const struct_type = ip.loadStructType(ty.toIntern()); 2544 assert(struct_type.layout != .@"packed"); 2545 return struct_type.field_offsets.get(ip)[index]; 2546 }, 2547 2548 .tuple_type => |tuple| { 2549 var offset: u64 = 0; 2550 var big_align: Alignment = .none; 2551 2552 for (tuple.types.get(ip), tuple.values.get(ip), 0..) |field_ty, field_val, i| { 2553 if (field_val != .none or !Type.fromInterned(field_ty).hasRuntimeBits(zcu)) { 2554 // comptime field 2555 if (i == index) return 0; 2556 continue; 2557 } 2558 2559 const field_align = Type.fromInterned(field_ty).abiAlignment(zcu); 2560 big_align = big_align.max(field_align); 2561 offset = field_align.forward(offset); 2562 if (i == index) return offset; 2563 offset += Type.fromInterned(field_ty).abiSize(zcu); 2564 } 2565 offset = big_align.max(.@"1").forward(offset); 2566 return offset; 2567 }, 2568 2569 .union_type => { 2570 const union_type = ip.loadUnionType(ty.toIntern()); 2571 if (!union_type.has_runtime_tag) return 0; 2572 const layout = Type.getUnionLayout(union_type, zcu); 2573 if (layout.tag_align.compare(.gte, layout.payload_align)) { 2574 // {Tag, Payload} 2575 return layout.payload_align.forward(layout.tag_size); 2576 } else { 2577 // {Payload, Tag} 2578 return 0; 2579 } 2580 }, 2581 2582 else => unreachable, 2583 } 2584 } 2585 2586 pub fn srcLocOrNull(ty: Type, zcu: *Zcu) ?Zcu.LazySrcLoc { 2587 const ip = &zcu.intern_pool; 2588 return .{ 2589 .base_node_inst = switch (ip.indexToKey(ty.toIntern())) { 2590 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) { 2591 .declared => |d| d.zir_index, 2592 .reified => |r| r.zir_index, 2593 .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index, 2594 }, 2595 else => return null, 2596 }, 2597 .offset = Zcu.LazySrcLoc.Offset.nodeOffset(.zero), 2598 }; 2599 } 2600 2601 pub fn srcLoc(ty: Type, zcu: *Zcu) Zcu.LazySrcLoc { 2602 return ty.srcLocOrNull(zcu).?; 2603 } 2604 2605 pub fn isGenericPoison(ty: Type) bool { 2606 return ty.toIntern() == .generic_poison_type; 2607 } 2608 2609 pub fn isTuple(ty: Type, zcu: *const Zcu) bool { 2610 const ip = &zcu.intern_pool; 2611 return switch (ip.indexToKey(ty.toIntern())) { 2612 .tuple_type => true, 2613 else => false, 2614 }; 2615 } 2616 2617 /// Traverses optional child types and error union payloads until the type is neither of those. 2618 /// For `E!?u32`, returns `u32`; for `*u8`, returns `*u8`. 2619 pub fn optEuBaseType(ty: Type, zcu: *const Zcu) Type { 2620 var cur = ty; 2621 while (true) switch (cur.zigTypeTag(zcu)) { 2622 .optional => cur = cur.optionalChild(zcu), 2623 .error_union => cur = cur.errorUnionPayload(zcu), 2624 else => return cur, 2625 }; 2626 } 2627 2628 pub fn toUnsigned(ty: Type, pt: Zcu.PerThread) !Type { 2629 const zcu = pt.zcu; 2630 return switch (ty.toIntern()) { 2631 // zig fmt: off 2632 .usize_type, .isize_type => .usize, 2633 .c_ushort_type, .c_short_type => .c_ushort, 2634 .c_uint_type, .c_int_type => .c_uint, 2635 .c_ulong_type, .c_long_type => .c_ulong, 2636 .c_ulonglong_type, .c_longlong_type => .c_ulonglong, 2637 // zig fmt: on 2638 else => switch (ty.zigTypeTag(zcu)) { 2639 .int => pt.intType(.unsigned, ty.intInfo(zcu).bits), 2640 .vector => try pt.vectorType(.{ 2641 .len = ty.vectorLen(zcu), 2642 .child = (try ty.childType(zcu).toUnsigned(pt)).toIntern(), 2643 }), 2644 else => unreachable, 2645 }, 2646 }; 2647 } 2648 2649 pub fn typeDeclInst(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index { 2650 const ip = &zcu.intern_pool; 2651 return switch (ip.indexToKey(ty.toIntern())) { 2652 .struct_type => ip.loadStructType(ty.toIntern()).zir_index, 2653 .union_type => ip.loadUnionType(ty.toIntern()).zir_index, 2654 .enum_type => ip.loadEnumType(ty.toIntern()).zir_index.unwrap(), 2655 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index, 2656 else => null, 2657 }; 2658 } 2659 2660 pub fn typeDeclInstAllowGeneratedTag(ty: Type, zcu: *const Zcu) ?InternPool.TrackedInst.Index { 2661 const ip = &zcu.intern_pool; 2662 return switch (ip.indexToKey(ty.toIntern())) { 2663 .struct_type => ip.loadStructType(ty.toIntern()).zir_index, 2664 .union_type => ip.loadUnionType(ty.toIntern()).zir_index, 2665 .enum_type => |e| switch (e) { 2666 .declared, .reified => ip.loadEnumType(ty.toIntern()).zir_index.unwrap().?, 2667 .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index, 2668 }, 2669 .opaque_type => ip.loadOpaqueType(ty.toIntern()).zir_index, 2670 else => null, 2671 }; 2672 } 2673 2674 pub fn typeDeclSrcLine(ty: Type, zcu: *Zcu) ?u32 { 2675 // Note that changes to ZIR instruction tracking only need to update this code 2676 // if a newly-tracked instruction can be a type's owner `zir_index`. 2677 comptime assert(Zir.inst_tracking_version == 0); 2678 2679 const ip = &zcu.intern_pool; 2680 const tracked = switch (ip.indexToKey(ty.toIntern())) { 2681 .struct_type, .union_type, .opaque_type, .enum_type => |info| switch (info) { 2682 .declared => |d| d.zir_index, 2683 .reified => |r| r.zir_index, 2684 .generated_union_tag => |union_ty| ip.loadUnionType(union_ty).zir_index, 2685 }, 2686 else => return null, 2687 }; 2688 const info = tracked.resolveFull(&zcu.intern_pool) orelse return null; 2689 const file = zcu.fileByIndex(info.file); 2690 const zir = switch (file.getMode()) { 2691 .zig => file.zir.?, 2692 .zon => return 0, 2693 }; 2694 const inst = zir.instructions.get(@backingInt(info.inst)); 2695 return switch (inst.tag) { 2696 .struct_init, .struct_init_ref => zir.extraData(Zir.Inst.StructInit, inst.data.pl_node.payload_index).data.src_line, 2697 .struct_init_anon => zir.extraData(Zir.Inst.StructInitAnon, inst.data.pl_node.payload_index).data.src_line, 2698 .extended => switch (inst.data.extended.opcode) { 2699 .struct_decl => zir.getStructDecl(info.inst).src_line, 2700 .union_decl => zir.getUnionDecl(info.inst).src_line, 2701 .enum_decl => zir.getEnumDecl(info.inst).src_line, 2702 .opaque_decl => zir.getOpaqueDecl(info.inst).src_line, 2703 .reify_enum => zir.extraData(Zir.Inst.ReifyEnum, inst.data.extended.operand).data.src_line, 2704 .reify_struct => zir.extraData(Zir.Inst.ReifyStruct, inst.data.extended.operand).data.src_line, 2705 .reify_union => zir.extraData(Zir.Inst.ReifyUnion, inst.data.extended.operand).data.src_line, 2706 else => unreachable, 2707 }, 2708 else => unreachable, 2709 }; 2710 } 2711 2712 /// Given a namespace type, returns its list of captured values. 2713 pub fn getCaptures(ty: Type, zcu: *const Zcu) InternPool.CaptureValue.Slice { 2714 const ip = &zcu.intern_pool; 2715 return switch (ip.indexToKey(ty.toIntern())) { 2716 .struct_type => ip.loadStructType(ty.toIntern()).captures, 2717 .union_type => ip.loadUnionType(ty.toIntern()).captures, 2718 .enum_type => ip.loadEnumType(ty.toIntern()).captures, 2719 .opaque_type => ip.loadOpaqueType(ty.toIntern()).captures, 2720 else => unreachable, 2721 }; 2722 } 2723 2724 pub fn arrayBase(ty: Type, zcu: *const Zcu) struct { Type, u64 } { 2725 var cur_ty: Type = ty; 2726 var cur_len: u64 = 1; 2727 while (cur_ty.zigTypeTag(zcu) == .array) { 2728 cur_len *= cur_ty.arrayLenIncludingSentinel(zcu); 2729 cur_ty = cur_ty.childType(zcu); 2730 } 2731 return .{ cur_ty, cur_len }; 2732 } 2733 2734 /// Asserts that `loaded_union.layout` is not `.@"packed"`. 2735 pub fn getUnionLayout(loaded_union: InternPool.LoadedUnionType, zcu: *const Zcu) Zcu.UnionLayout { 2736 assert(loaded_union.layout != .@"packed"); 2737 2738 const ip = &zcu.intern_pool; 2739 var most_aligned_field: u32 = 0; 2740 var most_aligned_field_align: InternPool.Alignment = .@"1"; 2741 var most_aligned_field_size: u64 = 0; 2742 var biggest_field: u32 = 0; 2743 var payload_size: u64 = 0; 2744 var payload_align: InternPool.Alignment = .@"1"; 2745 for (loaded_union.field_types.get(ip), 0..) |field_ty_ip_index, field_index| { 2746 const field_ty: Type = .fromInterned(field_ty_ip_index); 2747 if (field_ty.isNoReturn(zcu)) continue; 2748 2749 const field_align: InternPool.Alignment = a: { 2750 const explicit_aligns = loaded_union.field_aligns.get(ip); 2751 if (explicit_aligns.len > 0) { 2752 const a = explicit_aligns[field_index]; 2753 if (a != .none) break :a a; 2754 } 2755 break :a field_ty.abiAlignment(zcu); 2756 }; 2757 if (field_ty.hasRuntimeBits(zcu)) { 2758 const field_size = field_ty.abiSize(zcu); 2759 if (field_size > payload_size) { 2760 payload_size = field_size; 2761 biggest_field = @intCast(field_index); 2762 } 2763 if (field_size > 0 and field_align.compare(.gte, most_aligned_field_align)) { 2764 most_aligned_field = @intCast(field_index); 2765 most_aligned_field_align = field_align; 2766 most_aligned_field_size = field_size; 2767 } 2768 } 2769 payload_align = payload_align.max(field_align); 2770 } 2771 if (!loaded_union.has_runtime_tag or 2772 !Type.fromInterned(loaded_union.enum_tag_type).hasRuntimeBits(zcu)) 2773 { 2774 return .{ 2775 .abi_size = payload_align.forward(payload_size), 2776 .abi_align = payload_align, 2777 .most_aligned_field = most_aligned_field, 2778 .most_aligned_field_size = most_aligned_field_size, 2779 .biggest_field = biggest_field, 2780 .payload_size = payload_size, 2781 .payload_align = payload_align, 2782 .tag_align = .none, 2783 .tag_size = 0, 2784 .padding = 0, 2785 }; 2786 } 2787 2788 const tag_size = Type.fromInterned(loaded_union.enum_tag_type).abiSize(zcu); 2789 const tag_align = Type.fromInterned(loaded_union.enum_tag_type).abiAlignment(zcu).max(.@"1"); 2790 return .{ 2791 .abi_size = loaded_union.size, 2792 .abi_align = tag_align.max(payload_align), 2793 .most_aligned_field = most_aligned_field, 2794 .most_aligned_field_size = most_aligned_field_size, 2795 .biggest_field = biggest_field, 2796 .payload_size = payload_size, 2797 .payload_align = payload_align, 2798 .tag_align = tag_align, 2799 .tag_size = tag_size, 2800 .padding = loaded_union.padding, 2801 }; 2802 } 2803 2804 /// Asserts that `ptr_ty` is either a many-item pointer, a slice, a C pointer, or a single pointer 2805 /// to array (in other words, a pointer which is indexed by pointer arithmetic), and returns the 2806 /// type of the element pointer at the given index. 2807 /// 2808 /// Asserts that the layout of the pointer element type is resolved. 2809 /// 2810 /// If `index` is `null`, the index is an arbitrary runtime-known value. 2811 pub fn elemPtrType(ptr_ty: Type, index: ?u64, pt: Zcu.PerThread) Allocator.Error!Type { 2812 const zcu = pt.zcu; 2813 const ip = &zcu.intern_pool; 2814 const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type; 2815 const elem_ty: Type = switch (ptr_info.flags.size) { 2816 .slice, .many, .c => .fromInterned(ptr_info.child), 2817 .one => switch (ip.indexToKey(ptr_info.child)) { 2818 .array_type => |array_type| .fromInterned(array_type.child), 2819 .spirv_type => Type.fromInterned(ptr_info.child).childType(zcu), 2820 else => unreachable, 2821 }, 2822 }; 2823 elem_ty.assertHasLayout(zcu); 2824 const elem_align: Alignment = switch (elem_ty.classify(zcu)) { 2825 .no_possible_value, 2826 .one_possible_value, 2827 => ptr_info.flags.alignment, 2828 2829 .partially_comptime, 2830 .fully_comptime, 2831 => switch (ptr_info.flags.alignment) { 2832 .none => .none, 2833 else => |array_align| .minStrict(array_align, elem_ty.abiAlignment(zcu)), 2834 }, 2835 2836 .runtime => switch (ptr_info.flags.alignment) { 2837 .none => .none, 2838 else => |array_align| elem_align: { 2839 // If the index is runtime-known, use 1 as it gives the minimum possible alignment. 2840 const effective_index = index orelse 1; 2841 if (effective_index == 0) break :elem_align array_align; 2842 const byte_offset = effective_index * elem_ty.abiSize(zcu); 2843 break :elem_align .minStrict(array_align, .fromLog2Units(@ctz(byte_offset))); 2844 }, 2845 }, 2846 }; 2847 return pt.ptrType(.{ 2848 .child = elem_ty.toIntern(), 2849 .flags = .{ 2850 .size = .one, 2851 .is_const = ptr_info.flags.is_const, 2852 .is_volatile = ptr_info.flags.is_volatile, 2853 .is_allowzero = ptr_info.flags.is_allowzero and (index == null or index == 0), 2854 .address_space = ptr_info.flags.address_space, 2855 .alignment = elem_align, 2856 }, 2857 }); 2858 } 2859 2860 /// Asserts that `ptr_ty` is a pointer (single-item or C) to a struct, union, tuple, or slice, and 2861 /// returns the type of a pointer to the field at `field_index`. 2862 /// 2863 /// Asserts that the layout of the pointer child type is resolved. 2864 /// 2865 /// For slices, `Value.slice_ptr_index` and `Value.slice_len_index` are used for the field index. 2866 pub fn fieldPtrType(ptr_ty: Type, field_index: u32, pt: Zcu.PerThread) Allocator.Error!Type { 2867 const zcu = pt.zcu; 2868 const ip = &zcu.intern_pool; 2869 const ptr_info = ip.indexToKey(ptr_ty.toIntern()).ptr_type; 2870 assert(ptr_info.flags.size == .one or ptr_info.flags.size == .c); 2871 const aggregate_ty: Type = .fromInterned(ptr_info.child); 2872 aggregate_ty.assertHasLayout(zcu); 2873 // We only exit this `switch` for default-layout aggregates, where the field pointer alignment 2874 // is a simple minimum of the aggregate pointer alignment and the field alignment. 2875 // `field_align` is `.none` if there is no explicit alignment annotation. 2876 const field_ty: Type, const field_align: Alignment = switch (aggregate_ty.zigTypeTag(zcu)) { 2877 .@"struct" => switch (aggregate_ty.containerLayout(zcu)) { 2878 .auto => field: { 2879 if (aggregate_ty.isTuple(zcu)) { 2880 break :field .{ aggregate_ty.fieldType(field_index, zcu), .none }; 2881 } 2882 const struct_obj = ip.loadStructType(aggregate_ty.toIntern()); 2883 break :field .{ 2884 .fromInterned(struct_obj.field_types.get(ip)[field_index]), 2885 struct_obj.field_aligns.getOrNone(ip, field_index), 2886 }; 2887 }, 2888 .@"extern" => { 2889 // Field alignment is determined based on the actual field offset. For instance, in 2890 // `extern struct { x: u32, y: u16 }`, the `y` field is 4-byte aligned. 2891 const field_ty = aggregate_ty.fieldType(field_index, zcu); 2892 const field_offset = aggregate_ty.structFieldOffset(field_index, zcu); 2893 const parent_align = switch (ptr_info.flags.alignment) { 2894 .none => aggregate_ty.abiAlignment(zcu), 2895 else => |a| a, 2896 }; 2897 const actual_field_align = switch (field_offset) { 2898 0 => parent_align, 2899 else => parent_align.minStrict(.fromLog2Units(@ctz(field_offset))), 2900 }; 2901 const field_ptr_align: Alignment = a: { 2902 if (ptr_info.flags.alignment == .none and 2903 aggregate_ty.explicitFieldAlignment(field_index, zcu) == .none and 2904 actual_field_align == field_ty.abiAlignment(zcu)) 2905 { 2906 // There's no user-specified 'align' in sight, and the alignment from the 2907 // field offset matches the field type's natural alignment, so just use a 2908 // default-aligned pointer. 2909 break :a .none; 2910 } 2911 break :a actual_field_align; 2912 }; 2913 var field_ptr_info = ptr_info; 2914 field_ptr_info.child = field_ty.toIntern(); 2915 field_ptr_info.flags.alignment = field_ptr_align; 2916 return pt.ptrType(field_ptr_info); 2917 }, 2918 .@"packed" => { 2919 var field_ptr_info = ptr_info; 2920 if (field_ptr_info.flags.alignment == .none) { 2921 field_ptr_info.flags.alignment = aggregate_ty.abiAlignment(zcu); 2922 } 2923 field_ptr_info.packed_offset = packed_offset: { 2924 comptime assert(Type.packed_struct_layout_version == 2); 2925 const bit_offset = zcu.structPackedFieldBitOffset( 2926 ip.loadStructType(aggregate_ty.toIntern()), 2927 field_index, 2928 ); 2929 break :packed_offset if (ptr_info.packed_offset.host_size != 0) .{ 2930 .host_size = ptr_info.packed_offset.host_size, 2931 .bit_offset = ptr_info.packed_offset.bit_offset + bit_offset, 2932 } else .{ 2933 .host_size = switch (zcu.comp.getZigBackend()) { 2934 else => @intCast((aggregate_ty.bitSize(zcu) + 7) / 8), 2935 .stage2_x86_64, .stage2_c => @intCast(aggregate_ty.abiSize(zcu)), 2936 }, 2937 .bit_offset = ptr_info.packed_offset.bit_offset + bit_offset, 2938 }; 2939 }; 2940 field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern(); 2941 return pt.ptrType(field_ptr_info); 2942 }, 2943 }, 2944 .@"union" => switch (aggregate_ty.containerLayout(zcu)) { 2945 .auto => field: { 2946 const union_obj = ip.loadUnionType(aggregate_ty.toIntern()); 2947 break :field .{ 2948 .fromInterned(union_obj.field_types.get(ip)[field_index]), 2949 union_obj.field_aligns.getOrNone(ip, field_index), 2950 }; 2951 }, 2952 .@"extern" => { 2953 // The alignment always matches that of the union pointer. If the union pointer is 2954 // default aligned (`.none`), we may need to explicitly align the result pointer. 2955 const field_ty = aggregate_ty.fieldType(field_index, zcu); 2956 var field_ptr_info = ptr_info; 2957 field_ptr_info.child = field_ty.toIntern(); 2958 if (field_ptr_info.flags.alignment == .none and 2959 Alignment.compareStrict(field_ty.abiAlignment(zcu), .neq, aggregate_ty.abiAlignment(zcu))) 2960 { 2961 field_ptr_info.flags.alignment = aggregate_ty.abiAlignment(zcu); 2962 } 2963 return pt.ptrType(field_ptr_info); 2964 }, 2965 .@"packed" => { 2966 const field_ty = aggregate_ty.fieldType(field_index, zcu); 2967 var field_ptr_info = ptr_info; 2968 if (field_ptr_info.flags.alignment == .none) { 2969 const resolved_align = aggregate_ty.abiAlignment(zcu); 2970 if (field_ty.abiAlignment(zcu) != resolved_align) { 2971 field_ptr_info.flags.alignment = resolved_align; 2972 } 2973 } 2974 field_ptr_info.child = aggregate_ty.fieldType(field_index, zcu).toIntern(); 2975 return pt.ptrType(field_ptr_info); 2976 }, 2977 }, 2978 .pointer => field: { 2979 assert(aggregate_ty.isSlice(zcu)); 2980 break :field switch (field_index) { 2981 Value.slice_ptr_index => .{ aggregate_ty.slicePtrFieldType(zcu), .none }, 2982 Value.slice_len_index => .{ .usize, .none }, 2983 else => unreachable, 2984 }; 2985 }, 2986 else => unreachable, 2987 }; 2988 const field_ptr_align: Alignment = a: { 2989 if (aggregate_ty.zigTypeTag(zcu) == .@"struct" and aggregate_ty.structFieldIsComptime(field_index, zcu)) { 2990 // For `comptime` fields, just use exactly what was specified, or ABI alignment if nothing was specified. 2991 break :a field_align; 2992 } 2993 const actual_field_align = switch (field_align) { 2994 .none => switch (ip.indexToKey(aggregate_ty.toIntern())) { 2995 .struct_type, .tuple_type, .union_type => field_ty.abiAlignment(zcu), 2996 .ptr_type => Type.usize.abiAlignment(zcu), 2997 else => unreachable, 2998 }, 2999 else => |a| a, 3000 }; 3001 const actual_aggregate_align = switch (ptr_info.flags.alignment) { 3002 .none => aggregate_ty.abiAlignment(zcu), 3003 else => |a| a, 3004 }; 3005 if (actual_aggregate_align.compareStrict(.lt, actual_field_align)) { 3006 // Underaligned aggregate; use that alignment. 3007 assert(ptr_info.flags.alignment != .none); 3008 break :a actual_aggregate_align; 3009 } 3010 if (field_align == .none and actual_field_align == field_ty.abiAlignment(zcu)) { 3011 // No explicit annotation on the field (nor an unusual default), and the aggregate 3012 // alignment is irrelevant to us, so return an un-annotated pointer. 3013 break :a .none; 3014 } 3015 break :a actual_field_align; 3016 }; 3017 var field_ptr_info = ptr_info; 3018 field_ptr_info.flags.alignment = field_ptr_align; 3019 field_ptr_info.child = field_ty.toIntern(); 3020 return pt.ptrType(field_ptr_info); 3021 } 3022 3023 pub fn containerTypeName(ty: Type, ip: *const InternPool) struct { 3024 name: InternPool.NullTerminatedString, 3025 fqn: InternPool.NullTerminatedString, 3026 } { 3027 switch (ip.indexToKey(ty.toIntern())) { 3028 .struct_type => { 3029 const loaded_struct = ip.loadStructType(ty.toIntern()); 3030 return .{ .name = loaded_struct.name, .fqn = loaded_struct.fqn }; 3031 }, 3032 .union_type => { 3033 const loaded_union = ip.loadUnionType(ty.toIntern()); 3034 return .{ .name = loaded_union.name, .fqn = loaded_union.fqn }; 3035 }, 3036 .enum_type => { 3037 const loaded_enum = ip.loadEnumType(ty.toIntern()); 3038 return .{ .name = loaded_enum.name, .fqn = loaded_enum.fqn }; 3039 }, 3040 .opaque_type => { 3041 const loaded_opaque = ip.loadOpaqueType(ty.toIntern()); 3042 return .{ .name = loaded_opaque.name, .fqn = loaded_opaque.fqn }; 3043 }, 3044 else => unreachable, 3045 } 3046 } 3047 3048 pub fn destructurable(ty: Type, zcu: *const Zcu) bool { 3049 return switch (ty.zigTypeTag(zcu)) { 3050 .array, .vector => true, 3051 .@"struct" => ty.isTuple(zcu), 3052 else => false, 3053 }; 3054 } 3055 3056 pub const UnpackableReason = union(enum) { 3057 comptime_only, 3058 pointer, 3059 enum_inferred_int_tag: Type, 3060 non_packed_struct: Type, 3061 non_packed_union: Type, 3062 slice, 3063 other, 3064 }; 3065 3066 /// Returns `null` iff `ty` is allowed in packed types. 3067 pub fn unpackable(ty: Type, zcu: *const Zcu) ?UnpackableReason { 3068 return switch (ty.zigTypeTag(zcu)) { 3069 .void, 3070 .bool, 3071 .float, 3072 .int, 3073 => null, 3074 3075 .type, 3076 .comptime_float, 3077 .comptime_int, 3078 .enum_literal, 3079 .undefined, 3080 .null, 3081 => .comptime_only, 3082 3083 .noreturn, 3084 .@"opaque", 3085 .spirv, 3086 .error_union, 3087 .error_set, 3088 .frame, 3089 .@"anyframe", 3090 .@"fn", 3091 .array, 3092 .vector, 3093 => .other, 3094 3095 .optional => if (ty.isPtrLikeOptional(zcu)) 3096 .pointer 3097 else 3098 .other, 3099 3100 .pointer => switch (ty.ptrSize(zcu)) { 3101 .slice => .slice, 3102 .one, .many, .c => .pointer, 3103 }, 3104 3105 .@"enum" => switch (ty.backingIntMode(zcu)) { 3106 .explicit => switch (ty.backingIntType(zcu).toIntern()) { 3107 else => null, 3108 .noreturn_type => .other, 3109 }, 3110 .auto => .{ .enum_inferred_int_tag = ty }, 3111 }, 3112 3113 .@"struct" => switch (ty.containerLayout(zcu)) { 3114 .@"packed" => null, 3115 .auto, .@"extern" => .{ .non_packed_struct = ty }, 3116 }, 3117 .@"union" => switch (ty.containerLayout(zcu)) { 3118 .@"packed" => null, 3119 .auto, .@"extern" => .{ .non_packed_union = ty }, 3120 }, 3121 }; 3122 } 3123 3124 pub const ExternPosition = enum { 3125 ret_ty, 3126 param_ty, 3127 union_field, 3128 struct_field, 3129 element, 3130 other, 3131 }; 3132 3133 /// Returns true if `ty` is allowed in extern types. 3134 /// Asserts that `ty` is fully resolved. 3135 /// Keep in sync with `Sema.explainWhyTypeIsNotExtern`. 3136 pub fn validateExtern(ty: Type, position: ExternPosition, zcu: *const Zcu) bool { 3137 ty.assertHasLayout(zcu); 3138 return switch (ty.zigTypeTag(zcu)) { 3139 .type, 3140 .comptime_float, 3141 .comptime_int, 3142 .enum_literal, 3143 .undefined, 3144 .null, 3145 .error_union, 3146 .error_set, 3147 .frame, 3148 => false, 3149 3150 .vector => { 3151 if (zcu.getTarget().cpu.arch.isSpirV()) return true; 3152 return position == .param_ty or position == .ret_ty; 3153 }, 3154 3155 .void => switch (position) { 3156 .ret_ty, 3157 .union_field, 3158 .struct_field, 3159 .element, 3160 => true, 3161 .param_ty, 3162 .other, 3163 => false, 3164 }, 3165 3166 .noreturn => position == .ret_ty, 3167 3168 .@"opaque", 3169 .bool, 3170 .@"anyframe", 3171 => true, 3172 3173 .spirv => switch (position) { 3174 .struct_field, .union_field => true, 3175 .ret_ty, .param_ty, .element => !ty.isSpirvRuntimeArray(zcu), 3176 .other => !ty.isSpirvRuntimeArray(zcu) or zcu.getTarget().cpu.has(.spirv, .runtime_descriptor_array), 3177 }, 3178 3179 .pointer => { 3180 if (ty.isSlice(zcu)) return false; 3181 const child_ty = ty.childType(zcu); 3182 if (child_ty.zigTypeTag(zcu) == .@"fn") { 3183 return ty.isConstPtr(zcu) and validateExternCallconv(child_ty.fnCallingConvention(zcu)); 3184 } 3185 return true; 3186 }, 3187 .int => switch (ty.intInfo(zcu).bits) { 3188 0, 8, 16, 32, 64, 128 => true, 3189 24, 48 => zcu.getTarget().cpu.arch == .ez80, 3190 else => false, 3191 }, 3192 .float => switch (ty.floatBits(zcu.getTarget())) { 3193 else => true, 3194 80 => |bits| std.zig.target.compilerRtFloatAbi(zcu.getTarget(), bits) == .hard, 3195 }, 3196 .@"fn" => { 3197 if (position != .other) return false; 3198 return validateExternCallconv(ty.fnCallingConvention(zcu)); 3199 }, 3200 .@"enum" => { 3201 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); 3202 return switch (enum_obj.int_tag_mode) { 3203 .auto => false, 3204 .explicit => Type.fromInterned(enum_obj.int_tag_type).validateExtern(position, zcu), 3205 }; 3206 }, 3207 .@"struct" => { 3208 if (ty.isTuple(zcu)) return false; 3209 const struct_obj = zcu.intern_pool.loadStructType(ty.toIntern()); 3210 return switch (struct_obj.layout) { 3211 .auto => false, 3212 .@"extern" => true, 3213 .@"packed" => switch (struct_obj.packed_backing_mode) { 3214 .auto => false, 3215 .explicit => Type.fromInterned(struct_obj.packed_backing_int_type).validateExtern(position, zcu), 3216 }, 3217 }; 3218 }, 3219 .@"union" => { 3220 const union_obj = zcu.intern_pool.loadUnionType(ty.toIntern()); 3221 return switch (union_obj.layout) { 3222 .auto => false, 3223 .@"extern" => true, 3224 .@"packed" => switch (union_obj.packed_backing_mode) { 3225 .auto => false, 3226 .explicit => Type.fromInterned(union_obj.packed_backing_int_type).validateExtern(position, zcu), 3227 }, 3228 }; 3229 }, 3230 .array => switch (position) { 3231 .ret_ty, 3232 .param_ty, 3233 => false, 3234 3235 .union_field, 3236 .struct_field, 3237 .element, 3238 .other, 3239 => ty.childType(zcu).validateExtern(.element, zcu), 3240 }, 3241 .optional => ty.isPtrLikeOptional(zcu), 3242 }; 3243 } 3244 fn validateExternCallconv(cc: std.lang.CallingConvention) bool { 3245 return switch (cc) { 3246 // For now we want to authorize PTX kernel to use zig objects, even if we end up exposing the ABI. 3247 // The goal is to experiment with more integrated CPU/GPU code. 3248 .nvptx_kernel => true, 3249 else => !target_util.fnCallConvAllowsZigTypes(cc), 3250 }; 3251 } 3252 3253 /// Returns whether `ty` is considered by Zig to have a bit-level representation, meaning it is 3254 /// allowed as the operand to `@bitSizeOf`. This is a superset of packable types. 3255 pub fn hasBitRepresentation(ty: Type, zcu: *const Zcu) bool { 3256 return switch (ty.zigTypeTag(zcu)) { 3257 .@"fn", 3258 .noreturn, 3259 .undefined, 3260 .null, 3261 .@"opaque", 3262 .spirv, 3263 .type, 3264 .enum_literal, 3265 .comptime_float, 3266 .comptime_int, 3267 .error_set, 3268 .error_union, 3269 .frame, 3270 .@"anyframe", 3271 => false, 3272 3273 .void, 3274 .bool, 3275 .int, 3276 .float, 3277 => true, 3278 3279 .@"enum" => { 3280 const enum_obj = zcu.intern_pool.loadEnumType(ty.toIntern()); 3281 return enum_obj.int_tag_mode == .explicit and 3282 enum_obj.int_tag_type != .noreturn_type; 3283 }, 3284 .pointer, .optional => ty.isPtrAtRuntime(zcu), 3285 .@"struct", .@"union" => ty.containerLayout(zcu) == .@"packed", 3286 3287 .array, .vector => ty.childType(zcu).hasBitRepresentation(zcu), 3288 }; 3289 } 3290 3291 /// Asserts that `ty` has resolved layout. 3292 pub fn assertHasLayout(ty: Type, zcu: *const Zcu) void { 3293 if (!std.debug.runtime_safety) { 3294 // This early exit isn't necessary (`Zcu.assertUpToDate` checks `std.debug.runtime_safety` 3295 // itself), but LLVM has been observed to fail at optimizing away this safety check, which 3296 // has a major performance impact on ReleaseFast compiler builds. 3297 return; 3298 } 3299 switch (zcu.intern_pool.indexToKey(ty.toIntern())) { 3300 .int_type, 3301 .ptr_type, 3302 .anyframe_type, 3303 .simple_type, 3304 .opaque_type, 3305 .error_set_type, 3306 .spirv_type, 3307 .inferred_error_set_type, 3308 => {}, 3309 .func_type => |func_type| { 3310 for (func_type.param_types.get(&zcu.intern_pool)) |param_ty| { 3311 assertHasLayout(.fromInterned(param_ty), zcu); 3312 } 3313 assertHasLayout(.fromInterned(func_type.return_type), zcu); 3314 }, 3315 .array_type => |arr| assertHasLayout(.fromInterned(arr.child), zcu), 3316 .vector_type => |vec| assertHasLayout(.fromInterned(vec.child), zcu), 3317 .opt_type => |child| assertHasLayout(.fromInterned(child), zcu), 3318 .error_union_type => |eu| assertHasLayout(.fromInterned(eu.payload_type), zcu), 3319 .tuple_type => |tuple| for (tuple.types.get(&zcu.intern_pool)) |field_ty| { 3320 assertHasLayout(.fromInterned(field_ty), zcu); 3321 }, 3322 .struct_type => { 3323 assert(zcu.intern_pool.loadStructType(ty.toIntern()).want_layout); 3324 zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() })); 3325 }, 3326 .union_type => { 3327 assert(zcu.intern_pool.loadUnionType(ty.toIntern()).want_layout); 3328 zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() })); 3329 }, 3330 .enum_type => { 3331 assert(zcu.intern_pool.loadEnumType(ty.toIntern()).want_layout); 3332 zcu.assertUpToDate(.wrap(.{ .type_layout = ty.toIntern() })); 3333 }, 3334 3335 // values, not types 3336 .simple_value, 3337 .@"extern", 3338 .func, 3339 .int, 3340 .err, 3341 .error_union, 3342 .enum_literal, 3343 .enum_tag, 3344 .float, 3345 .ptr, 3346 .slice, 3347 .opt, 3348 .aggregate, 3349 .un, 3350 .bitpack, 3351 .undef, 3352 // memoization, not types 3353 .memoized_call, 3354 => unreachable, 3355 } 3356 } 3357 3358 /// Recursively walks the type and marks for each subtype how many times it has been seen 3359 fn collectSubtypes(ty: Type, pt: Zcu.PerThread, visited: *std.array_hash_map.Auto(Type, u16)) error{OutOfMemory}!void { 3360 const zcu = pt.zcu; 3361 const ip = &zcu.intern_pool; 3362 3363 const gop = try visited.getOrPut(zcu.gpa, ty); 3364 if (gop.found_existing) { 3365 gop.value_ptr.* += 1; 3366 } else { 3367 gop.value_ptr.* = 1; 3368 } 3369 3370 switch (ip.indexToKey(ty.toIntern())) { 3371 .ptr_type => try collectSubtypes(Type.fromInterned(ty.ptrInfo(zcu).child), pt, visited), 3372 .array_type => |array_type| try collectSubtypes(Type.fromInterned(array_type.child), pt, visited), 3373 .vector_type => |vector_type| try collectSubtypes(Type.fromInterned(vector_type.child), pt, visited), 3374 .opt_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited), 3375 .error_union_type => |error_union_type| { 3376 try collectSubtypes(Type.fromInterned(error_union_type.error_set_type), pt, visited); 3377 if (error_union_type.payload_type != .generic_poison_type) { 3378 try collectSubtypes(Type.fromInterned(error_union_type.payload_type), pt, visited); 3379 } 3380 }, 3381 .tuple_type => |tuple| { 3382 for (tuple.types.get(ip)) |field_ty| { 3383 try collectSubtypes(Type.fromInterned(field_ty), pt, visited); 3384 } 3385 }, 3386 .func_type => |fn_info| { 3387 const param_types = fn_info.param_types.get(&zcu.intern_pool); 3388 for (param_types) |param_ty| { 3389 if (param_ty != .generic_poison_type) { 3390 try collectSubtypes(Type.fromInterned(param_ty), pt, visited); 3391 } 3392 } 3393 3394 if (fn_info.return_type != .generic_poison_type) { 3395 try collectSubtypes(Type.fromInterned(fn_info.return_type), pt, visited); 3396 } 3397 }, 3398 .anyframe_type => |child| try collectSubtypes(Type.fromInterned(child), pt, visited), 3399 3400 // leaf types 3401 .undef, 3402 .inferred_error_set_type, 3403 .error_set_type, 3404 .struct_type, 3405 .union_type, 3406 .opaque_type, 3407 .enum_type, 3408 .spirv_type, 3409 .simple_type, 3410 .int_type, 3411 => {}, 3412 3413 // values, not types 3414 .simple_value, 3415 .@"extern", 3416 .func, 3417 .int, 3418 .err, 3419 .error_union, 3420 .enum_literal, 3421 .enum_tag, 3422 .float, 3423 .ptr, 3424 .slice, 3425 .opt, 3426 .aggregate, 3427 .un, 3428 .bitpack, 3429 // memoization, not types 3430 .memoized_call, 3431 => unreachable, 3432 } 3433 } 3434 3435 fn shouldDedupeType(ty: Type, ctx: *Comparison, pt: Zcu.PerThread) error{OutOfMemory}!Comparison.DedupeEntry { 3436 if (ctx.type_occurrences.get(ty)) |occ| { 3437 if (ctx.type_dedupe_cache.get(ty)) |cached| { 3438 return cached; 3439 } 3440 3441 var discarding: std.Io.Writer.Discarding = .init(&.{}); 3442 3443 print(ty, &discarding.writer, pt, null) catch 3444 unreachable; // we are writing into a discarding writer, it should never fail 3445 3446 const type_len: i32 = @intCast(discarding.count); 3447 3448 const placeholder_len: i32 = 1; 3449 const min_saved_bytes: i32 = 20; 3450 3451 const saved_bytes = (type_len - placeholder_len) * (occ - 1); 3452 const max_placeholders = 7; // T to Z 3453 const should_dedupe = saved_bytes >= min_saved_bytes and ctx.placeholder_index < max_placeholders; 3454 3455 const entry: Comparison.DedupeEntry = if (should_dedupe) b: { 3456 ctx.placeholder_index += 1; 3457 break :b .{ .dedupe = .{ .index = ctx.placeholder_index - 1 } }; 3458 } else .dont_dedupe; 3459 3460 try ctx.type_dedupe_cache.put(pt.zcu.gpa, ty, entry); 3461 3462 return entry; 3463 } else { 3464 return .{ .dont_dedupe = {} }; 3465 } 3466 } 3467 3468 /// The comparison recursively walks all types given and notes how many times 3469 /// each subtype occurs. It then while recursively printing decides for each 3470 /// subtype whether to print the type inline or create a placeholder based on 3471 /// the subtype length and number of occurences. Placeholders are then found by 3472 /// iterating `type_dedupe_cache` which caches the inline/placeholder decisions. 3473 pub const Comparison = struct { 3474 type_occurrences: std.array_hash_map.Auto(Type, u16), 3475 type_dedupe_cache: std.array_hash_map.Auto(Type, DedupeEntry), 3476 placeholder_index: u8, 3477 3478 pub const Placeholder = struct { 3479 index: u8, 3480 3481 pub fn format(p: Placeholder, writer: *std.Io.Writer) error{WriteFailed}!void { 3482 return writer.print("{c}", .{p.index + 'T'}); 3483 } 3484 }; 3485 3486 pub const DedupeEntry = union(enum) { 3487 dont_dedupe: void, 3488 dedupe: Placeholder, 3489 }; 3490 3491 pub fn init(types: []const Type, pt: Zcu.PerThread) error{OutOfMemory}!Comparison { 3492 var cmp: Comparison = .{ 3493 .type_occurrences = .empty, 3494 .type_dedupe_cache = .empty, 3495 .placeholder_index = 0, 3496 }; 3497 3498 errdefer cmp.deinit(pt); 3499 3500 for (types) |ty| { 3501 try collectSubtypes(ty, pt, &cmp.type_occurrences); 3502 } 3503 3504 return cmp; 3505 } 3506 3507 pub fn deinit(cmp: *Comparison, pt: Zcu.PerThread) void { 3508 const gpa = pt.zcu.gpa; 3509 cmp.type_occurrences.deinit(gpa); 3510 cmp.type_dedupe_cache.deinit(gpa); 3511 } 3512 3513 pub fn fmtType(ctx: *Comparison, ty: Type, pt: Zcu.PerThread) Comparison.Formatter { 3514 return .{ .ty = ty, .ctx = ctx, .pt = pt }; 3515 } 3516 pub const Formatter = struct { 3517 ty: Type, 3518 ctx: *Comparison, 3519 pt: Zcu.PerThread, 3520 3521 pub fn format(self: Comparison.Formatter, writer: anytype) error{WriteFailed}!void { 3522 print(self.ty, writer, self.pt, self.ctx) catch return error.WriteFailed; 3523 } 3524 }; 3525 }; 3526 3527 pub const @"u0": Type = .{ .ip_index = .u0_type }; 3528 pub const @"u1": Type = .{ .ip_index = .u1_type }; 3529 pub const @"u8": Type = .{ .ip_index = .u8_type }; 3530 pub const @"u16": Type = .{ .ip_index = .u16_type }; 3531 pub const @"u29": Type = .{ .ip_index = .u29_type }; 3532 pub const @"u32": Type = .{ .ip_index = .u32_type }; 3533 pub const @"u64": Type = .{ .ip_index = .u64_type }; 3534 pub const @"u80": Type = .{ .ip_index = .u80_type }; 3535 pub const @"u128": Type = .{ .ip_index = .u128_type }; 3536 pub const @"u256": Type = .{ .ip_index = .u256_type }; 3537 3538 pub const @"i8": Type = .{ .ip_index = .i8_type }; 3539 pub const @"i16": Type = .{ .ip_index = .i16_type }; 3540 pub const @"i32": Type = .{ .ip_index = .i32_type }; 3541 pub const @"i64": Type = .{ .ip_index = .i64_type }; 3542 pub const @"i128": Type = .{ .ip_index = .i128_type }; 3543 3544 pub const @"f16": Type = .{ .ip_index = .f16_type }; 3545 pub const @"f32": Type = .{ .ip_index = .f32_type }; 3546 pub const @"f64": Type = .{ .ip_index = .f64_type }; 3547 pub const @"f80": Type = .{ .ip_index = .f80_type }; 3548 pub const @"f128": Type = .{ .ip_index = .f128_type }; 3549 3550 pub const @"bool": Type = .{ .ip_index = .bool_type }; 3551 pub const @"usize": Type = .{ .ip_index = .usize_type }; 3552 pub const @"isize": Type = .{ .ip_index = .isize_type }; 3553 pub const @"comptime_int": Type = .{ .ip_index = .comptime_int_type }; 3554 pub const @"comptime_float": Type = .{ .ip_index = .comptime_float_type }; 3555 pub const @"void": Type = .{ .ip_index = .void_type }; 3556 pub const @"type": Type = .{ .ip_index = .type_type }; 3557 pub const @"anyerror": Type = .{ .ip_index = .anyerror_type }; 3558 pub const @"anyopaque": Type = .{ .ip_index = .anyopaque_type }; 3559 pub const @"anyframe": Type = .{ .ip_index = .anyframe_type }; 3560 pub const @"null": Type = .{ .ip_index = .null_type }; 3561 pub const @"undefined": Type = .{ .ip_index = .undefined_type }; 3562 pub const @"noreturn": Type = .{ .ip_index = .noreturn_type }; 3563 pub const enum_literal: Type = .{ .ip_index = .enum_literal_type }; 3564 3565 pub const @"c_char": Type = .{ .ip_index = .c_char_type }; 3566 pub const @"c_short": Type = .{ .ip_index = .c_short_type }; 3567 pub const @"c_ushort": Type = .{ .ip_index = .c_ushort_type }; 3568 pub const @"c_int": Type = .{ .ip_index = .c_int_type }; 3569 pub const @"c_uint": Type = .{ .ip_index = .c_uint_type }; 3570 pub const @"c_long": Type = .{ .ip_index = .c_long_type }; 3571 pub const @"c_ulong": Type = .{ .ip_index = .c_ulong_type }; 3572 pub const @"c_longlong": Type = .{ .ip_index = .c_longlong_type }; 3573 pub const @"c_ulonglong": Type = .{ .ip_index = .c_ulonglong_type }; 3574 pub const @"c_longdouble": Type = .{ .ip_index = .c_longdouble_type }; 3575 3576 pub const ptr_usize: Type = .{ .ip_index = .ptr_usize_type }; 3577 pub const ptr_const_comptime_int: Type = .{ .ip_index = .ptr_const_comptime_int_type }; 3578 pub const manyptr_u8: Type = .{ .ip_index = .manyptr_u8_type }; 3579 pub const manyptr_const_u8: Type = .{ .ip_index = .manyptr_const_u8_type }; 3580 pub const manyptr_const_u8_sentinel_0: Type = .{ .ip_index = .manyptr_const_u8_sentinel_0_type }; 3581 pub const slice_const_u8: Type = .{ .ip_index = .slice_const_u8_type }; 3582 pub const slice_const_u8_sentinel_0: Type = .{ .ip_index = .slice_const_u8_sentinel_0_type }; 3583 pub const slice_const_slice_const_u8: Type = .{ .ip_index = .slice_const_slice_const_u8_type }; 3584 pub const slice_const_type: Type = .{ .ip_index = .slice_const_type_type }; 3585 pub const optional_type: Type = .{ .ip_index = .optional_type_type }; 3586 pub const optional_noreturn: Type = .{ .ip_index = .optional_noreturn_type }; 3587 3588 pub const vector_8_i8: Type = .{ .ip_index = .vector_8_i8_type }; 3589 pub const vector_16_i8: Type = .{ .ip_index = .vector_16_i8_type }; 3590 pub const vector_32_i8: Type = .{ .ip_index = .vector_32_i8_type }; 3591 pub const vector_64_i8: Type = .{ .ip_index = .vector_64_i8_type }; 3592 pub const vector_1_u8: Type = .{ .ip_index = .vector_1_u8_type }; 3593 pub const vector_2_u8: Type = .{ .ip_index = .vector_2_u8_type }; 3594 pub const vector_4_u8: Type = .{ .ip_index = .vector_4_u8_type }; 3595 pub const vector_8_u8: Type = .{ .ip_index = .vector_8_u8_type }; 3596 pub const vector_16_u8: Type = .{ .ip_index = .vector_16_u8_type }; 3597 pub const vector_32_u8: Type = .{ .ip_index = .vector_32_u8_type }; 3598 pub const vector_64_u8: Type = .{ .ip_index = .vector_64_u8_type }; 3599 pub const vector_2_i16: Type = .{ .ip_index = .vector_2_i16_type }; 3600 pub const vector_4_i16: Type = .{ .ip_index = .vector_4_i16_type }; 3601 pub const vector_8_i16: Type = .{ .ip_index = .vector_8_i16_type }; 3602 pub const vector_16_i16: Type = .{ .ip_index = .vector_16_i16_type }; 3603 pub const vector_32_i16: Type = .{ .ip_index = .vector_32_i16_type }; 3604 pub const vector_4_u16: Type = .{ .ip_index = .vector_4_u16_type }; 3605 pub const vector_8_u16: Type = .{ .ip_index = .vector_8_u16_type }; 3606 pub const vector_16_u16: Type = .{ .ip_index = .vector_16_u16_type }; 3607 pub const vector_32_u16: Type = .{ .ip_index = .vector_32_u16_type }; 3608 pub const vector_2_i32: Type = .{ .ip_index = .vector_2_i32_type }; 3609 pub const vector_4_i32: Type = .{ .ip_index = .vector_4_i32_type }; 3610 pub const vector_8_i32: Type = .{ .ip_index = .vector_8_i32_type }; 3611 pub const vector_16_i32: Type = .{ .ip_index = .vector_16_i32_type }; 3612 pub const vector_4_u32: Type = .{ .ip_index = .vector_4_u32_type }; 3613 pub const vector_8_u32: Type = .{ .ip_index = .vector_8_u32_type }; 3614 pub const vector_16_u32: Type = .{ .ip_index = .vector_16_u32_type }; 3615 pub const vector_2_i64: Type = .{ .ip_index = .vector_2_i64_type }; 3616 pub const vector_4_i64: Type = .{ .ip_index = .vector_4_i64_type }; 3617 pub const vector_8_i64: Type = .{ .ip_index = .vector_8_i64_type }; 3618 pub const vector_2_u64: Type = .{ .ip_index = .vector_2_u64_type }; 3619 pub const vector_4_u64: Type = .{ .ip_index = .vector_4_u64_type }; 3620 pub const vector_8_u64: Type = .{ .ip_index = .vector_8_u64_type }; 3621 pub const vector_1_u128: Type = .{ .ip_index = .vector_1_u128_type }; 3622 pub const vector_2_u128: Type = .{ .ip_index = .vector_2_u128_type }; 3623 pub const vector_1_u256: Type = .{ .ip_index = .vector_1_u256_type }; 3624 pub const vector_4_f16: Type = .{ .ip_index = .vector_4_f16_type }; 3625 pub const vector_8_f16: Type = .{ .ip_index = .vector_8_f16_type }; 3626 pub const vector_16_f16: Type = .{ .ip_index = .vector_16_f16_type }; 3627 pub const vector_32_f16: Type = .{ .ip_index = .vector_32_f16_type }; 3628 pub const vector_2_f32: Type = .{ .ip_index = .vector_2_f32_type }; 3629 pub const vector_4_f32: Type = .{ .ip_index = .vector_4_f32_type }; 3630 pub const vector_8_f32: Type = .{ .ip_index = .vector_8_f32_type }; 3631 pub const vector_16_f32: Type = .{ .ip_index = .vector_16_f32_type }; 3632 pub const vector_2_f64: Type = .{ .ip_index = .vector_2_f64_type }; 3633 pub const vector_4_f64: Type = .{ .ip_index = .vector_4_f64_type }; 3634 pub const vector_8_f64: Type = .{ .ip_index = .vector_8_f64_type }; 3635 3636 pub const empty_tuple: Type = .{ .ip_index = .empty_tuple_type }; 3637 3638 pub const generic_poison: Type = .{ .ip_index = .generic_poison_type }; 3639 3640 pub fn smallestUnsignedBits(max: u64) u16 { 3641 return switch (max) { 3642 0 => 0, 3643 else => @as(u16, 1) + std.math.log2_int(u64, max), 3644 }; 3645 } 3646 3647 /// This is only used for comptime asserts. Bump this number when you make a change 3648 /// to packed struct layout to find out all the places in the codebase you need to edit! 3649 pub const packed_struct_layout_version = 2; 3650 3651 fn cTypeAlign(target: *const Target, c_type: Target.CType) Alignment { 3652 return .fromByteUnits(target.cTypeAlignment(c_type).?); 3653 } 3654