use std::{
    fs,
    path::PathBuf,
    process::{Command, Output},
    sync::atomic::{AtomicUsize, Ordering},
};

static NEXT_FIXTURE_ID: AtomicUsize = AtomicUsize::new(0);

macro_rules! unsafe_required_source {
    ($head:literal) => {
        concat!(
            "\n(module main)\n\n(fn main () -> i32\n  (",
            $head,
            " i32))\n"
        )
    };
}

macro_rules! unsupported_unsafe_source {
    ($head:literal) => {
        concat!(
            "\n(module main)\n\n(fn main () -> i32\n  (unsafe\n    (",
            $head,
            " i32)))\n"
        )
    };
}

const CASES: &[DiagnosticCase] = &[
    DiagnosticCase {
        name: "unknown-function",
        source: r#"
(module main)

(fn main () -> i32
  (missing 1))
"#,
        snapshot: "../tests/unknown-function.diag",
    },
    DiagnosticCase {
        name: "arity-mismatch",
        source: r#"
(module main)

(fn add ((a i32) (b i32)) -> i32
  (+ a b))

(fn main () -> i32
  (add 1))
"#,
        snapshot: "../tests/arity-mismatch.diag",
    },
    DiagnosticCase {
        name: "type-mismatch",
        source: r#"
(module main)

(fn id ((value i32)) -> i32
  value)

(fn main () -> i32
  (id true))
"#,
        snapshot: "../tests/type-mismatch.diag",
    },
    DiagnosticCase {
        name: "unclosed-list",
        source: r#"
(module main)

(fn main () -> i32
  (+ 1 2)
"#,
        snapshot: "../tests/unclosed-list.diag",
    },
    DiagnosticCase {
        name: "unknown-top-level-form",
        source: r#"
(module main)

(bogus top level)
"#,
        snapshot: "../tests/unknown-top-level-form.diag",
    },
    DiagnosticCase {
        name: "malformed-type-alias",
        source: r#"
(module main)

(type Count)
"#,
        snapshot: "../tests/malformed-type-alias.diag",
    },
    DiagnosticCase {
        name: "duplicate-type-alias",
        source: r#"
(module main)

(type Count i32)
(type Count i64)
"#,
        snapshot: "../tests/duplicate-type-alias.diag",
    },
    DiagnosticCase {
        name: "type-alias-name-conflict",
        source: r#"
(module main)

(struct Count
  (value i32))

(type Count i32)
"#,
        snapshot: "../tests/type-alias-name-conflict.diag",
    },
    DiagnosticCase {
        name: "type-alias-value-name-conflict",
        source: r#"
(module main)

(import_c c_add ((value i32)) -> i32)

(type main i32)

(type c_add i32)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/type-alias-value-name-conflict.diag",
    },
    DiagnosticCase {
        name: "unknown-type-alias-target",
        source: r#"
(module main)

(type Count Missing)
"#,
        snapshot: "../tests/unknown-type-alias-target.diag",
    },
    DiagnosticCase {
        name: "unsupported-type-alias-target",
        source: r#"
(module main)

(type BadUnit unit)

(type BadPtr (ptr i32))

(type BadSlice (slice i32))

(type BadVec (vec u32))

(type BadResult (result i32 string))
"#,
        snapshot: "../tests/unsupported-type-alias-target.diag",
    },
    DiagnosticCase {
        name: "self-type-alias",
        source: r#"
(module main)

(type Count Count)
"#,
        snapshot: "../tests/self-type-alias.diag",
    },
    DiagnosticCase {
        name: "cyclic-type-alias",
        source: r#"
(module main)

(type A B)
(type B A)
"#,
        snapshot: "../tests/cyclic-type-alias.diag",
    },
    DiagnosticCase {
        name: "unsupported-generic-function",
        source: r#"
(module main)

(fn id (type_params T) ((value T)) -> T
  value)
"#,
        snapshot: "../tests/unsupported-generic-function.diag",
    },
    DiagnosticCase {
        name: "unsupported-generic-type-alias",
        source: r#"
(module main)

(type VecOf (type_params T) (vec T))
"#,
        snapshot: "../tests/unsupported-generic-type-alias.diag",
    },
    DiagnosticCase {
        name: "unsupported-generic-type-parameter",
        source: r#"
(module main)

(fn main () -> i32
  (let xs (vec T) (std.vec.i32.empty))
  0)
"#,
        snapshot: "../tests/unsupported-generic-type-parameter.diag",
    },
    DiagnosticCase {
        name: "unsupported-map-type",
        source: r#"
(module main)

(fn main () -> (map string i32)
  0)
"#,
        snapshot: "../tests/unsupported-map-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-set-type",
        source: r#"
(module main)

(fn main () -> (set string)
  0)
"#,
        snapshot: "../tests/unsupported-set-type.diag",
    },
    DiagnosticCase {
        name: "enum-empty",
        source: r#"
(module main)

(enum Empty)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-empty.diag",
    },
    DiagnosticCase {
        name: "enum-duplicate",
        source: r#"
(module main)

(enum Color Red)
(enum Color Blue)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-duplicate.diag",
    },
    DiagnosticCase {
        name: "enum-duplicate-variant",
        source: r#"
(module main)

(enum Color Red Red)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-duplicate-variant.diag",
    },
    DiagnosticCase {
        name: "enum-unknown-constructor",
        source: r#"
(module main)

(fn main () -> i32
  (Missing.Red))
"#,
        snapshot: "../tests/enum-unknown-constructor.diag",
    },
    DiagnosticCase {
        name: "enum-unknown-variant",
        source: r#"
(module main)

(enum Color Red)

(fn main () -> Color
  (Color.Blue))
"#,
        snapshot: "../tests/enum-unknown-variant.diag",
    },
    DiagnosticCase {
        name: "enum-constructor-arity",
        source: r#"
(module main)

(enum Color Red)

(fn main () -> Color
  (Color.Red 1))
"#,
        snapshot: "../tests/enum-constructor-arity.diag",
    },
    DiagnosticCase {
        name: "enum-match-non-exhaustive",
        source: r#"
(module main)

(enum Color Red Blue)

(fn main () -> i32
  (match (Color.Red)
    ((Color.Red) 1)))
"#,
        snapshot: "../tests/enum-match-non-exhaustive.diag",
    },
    DiagnosticCase {
        name: "enum-match-duplicate-arm",
        source: r#"
(module main)

(enum Color Red Blue)

(fn main () -> i32
  (match (Color.Red)
    ((Color.Red) 1)
    ((Color.Red) 2)
    ((Color.Blue) 3)))
"#,
        snapshot: "../tests/enum-match-duplicate-arm.diag",
    },
    DiagnosticCase {
        name: "enum-match-invalid-arm",
        source: r#"
(module main)

(enum Color Red)
(enum Shape Circle)

(fn main () -> i32
  (match (Color.Red)
    ((Shape.Circle) 1)))
"#,
        snapshot: "../tests/enum-match-invalid-arm.diag",
    },
    DiagnosticCase {
        name: "enum-container-values",
        source: r#"
(module main)

(enum Color Red)

(fn main () -> i32
  (let colors (array Color 1) (array Color (Color.Red)))
  (let maybe (option Color) (some Color (Color.Red)))
  0)
"#,
        snapshot: "../tests/enum-container-values.diag",
    },
    DiagnosticCase {
        name: "enum-struct-fields-container",
        source: r#"
(module main)

(enum Color Red)

(struct Bag
  (colors (array Color 1))
  (maybe (option Color)))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-struct-fields-container.diag",
    },
    DiagnosticCase {
        name: "enum-printing",
        source: r#"
(module main)

(enum Color Red)

(fn main () -> i32
  (print_i32 (Color.Red))
  0)
"#,
        snapshot: "../tests/enum-printing.diag",
    },
    DiagnosticCase {
        name: "enum-subject-mismatch",
        source: r#"
(module main)

(enum Color Red)
(enum Shape Circle)

(fn main () -> bool
  (= (Color.Red) (Shape.Circle)))
"#,
        snapshot: "../tests/enum-subject-mismatch.diag",
    },
    DiagnosticCase {
        name: "enum-ordering",
        source: r#"
(module main)

(enum Color Red Blue)

(fn main () -> bool
  (< (Color.Red) (Color.Blue)))
"#,
        snapshot: "../tests/enum-ordering.diag",
    },
    DiagnosticCase {
        name: "enum-match-payload-binding",
        source: r#"
(module main)

(enum Color Red Blue)

(fn main () -> i32
  (match (Color.Red)
    ((Color.Red payload) 1)
    ((Color.Blue) 2)))
"#,
        snapshot: "../tests/enum-match-payload-binding.diag",
    },
    DiagnosticCase {
        name: "enum-payload-unsupported-type",
        source: r#"
(module main)

(enum Reading
  (Value (vec i32)))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-payload-unsupported-type.diag",
    },
    DiagnosticCase {
        name: "enum-payload-mixed-types",
        source: r#"
(module main)

(enum Reading
  (Value i32)
  (Message string))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-payload-mixed-types.diag",
    },
    DiagnosticCase {
        name: "enum-payload-struct-equality",
        source: r#"
(module main)

(struct Pair
  (left i32)
  (right i32))

(enum Reading
  Missing
  (Value Pair))

(fn main () -> bool
  (= (Reading.Value (Pair (left 1) (right 2)))
     (Reading.Value (Pair (left 1) (right 2)))))
"#,
        snapshot: "../tests/enum-payload-struct-equality.diag",
    },
    DiagnosticCase {
        name: "enum-payload-recursive-struct",
        source: r#"
(module main)

(struct Node
  (next Wrapper))

(enum Wrapper
  Missing
  (Value Node))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/enum-payload-recursive-struct.diag",
    },
    DiagnosticCase {
        name: "enum-payload-constructor-arity",
        source: r#"
(module main)

(enum Reading
  (Value string))

(fn main () -> Reading
  (Reading.Value))
"#,
        snapshot: "../tests/enum-payload-constructor-arity.diag",
    },
    DiagnosticCase {
        name: "enum-payload-constructor-type",
        source: r#"
(module main)

(enum Reading
  (Value string))

(fn main () -> Reading
  (Reading.Value 1))
"#,
        snapshot: "../tests/enum-payload-constructor-type.diag",
    },
    DiagnosticCase {
        name: "enum-payload-match-missing-binding",
        source: r#"
(module main)

(enum Reading
  Missing
  (Value i32))

(fn main () -> i32
  (match (Reading.Value 1)
    ((Reading.Missing) 0)
    ((Reading.Value) 1)))
"#,
        snapshot: "../tests/enum-payload-match-missing-binding.diag",
    },
    DiagnosticCase {
        name: "enum-unqualified-variant-constructor",
        source: r#"
(module main)

(enum Color Red)

(fn main () -> Color
  (Red))
"#,
        snapshot: "../tests/enum-unqualified-variant-constructor.diag",
    },
    DiagnosticCase {
        name: "unsupported-string-escape",
        source: r#"
(module main)

(fn main () -> i32
  (print_string "\0")
  0)
"#,
        snapshot: "../tests/unsupported-string-escape.diag",
    },
    DiagnosticCase {
        name: "unsupported-string-literal",
        source: concat!(
            "\n(module main)\n\n(fn main () -> i32\n  (print_string \"zdravo ",
            "\u{017E}",
            "\")\n  0)\n"
        ),
        snapshot: "../tests/unsupported-string-literal.diag",
    },
    DiagnosticCase {
        name: "unsupported-string-concatenation",
        source: r#"
(module main)

(fn main () -> string
  (+ "a" "b"))
"#,
        snapshot: "../tests/unsupported-string-concatenation.diag",
    },
    DiagnosticCase {
        name: "unsupported-string-array",
        source: r#"
(module main)

(fn main () -> i32
  (index (array (array string 1) (array string "a")) 0))
"#,
        snapshot: "../tests/unsupported-string-array.diag",
    },
    DiagnosticCase {
        name: "unsupported-print-unit",
        source: r#"
(module main)

(fn main () -> i32
  (print_unit 0)
  0)
"#,
        snapshot: "../tests/unsupported-print-unit.diag",
    },
    DiagnosticCase {
        name: "unsupported-standard-library-call",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.print_unit 0)
  0)
"#,
        snapshot: "../tests/unsupported-standard-library-call.diag",
    },
    DiagnosticCase {
        name: "std-num-i32-to-i64-arity",
        source: r#"
(module main)

(fn main () -> i64
  (std.num.i32_to_i64))
"#,
        snapshot: "../tests/std-num-i32-to-i64-arity.diag",
    },
    DiagnosticCase {
        name: "std-num-i32-to-f64-type",
        source: r#"
(module main)

(fn main () -> f64
  (std.num.i32_to_f64 1i64))
"#,
        snapshot: "../tests/std-num-i32-to-f64-type.diag",
    },
    DiagnosticCase {
        name: "std-num-i64-to-i32-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.i64_to_i32 1i64)
  0)
"#,
        snapshot: "../tests/std-num-i64-to-i32-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-num-i64-to-i32-result-arity",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.num.i64_to_i32_result))
"#,
        snapshot: "../tests/std-num-i64-to-i32-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-num-i64-to-i32-result-type",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.num.i64_to_i32_result 1))
"#,
        snapshot: "../tests/std-num-i64-to-i32-result-type.diag",
    },
    DiagnosticCase {
        name: "std-num-i32-to-string-arity",
        source: r#"
(module main)

(fn main () -> string
  (std.num.i32_to_string))
"#,
        snapshot: "../tests/std-num-i32-to-string-arity.diag",
    },
    DiagnosticCase {
        name: "std-num-i64-to-string-type",
        source: r#"
(module main)

(fn main () -> string
  (std.num.i64_to_string 1))
"#,
        snapshot: "../tests/std-num-i64-to-string-type.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-string-arity",
        source: r#"
(module main)

(fn main () -> string
  (std.num.f64_to_string))
"#,
        snapshot: "../tests/std-num-f64-to-string-arity.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-string-type",
        source: r#"
(module main)

(fn main () -> string
  (std.num.f64_to_string 1))
"#,
        snapshot: "../tests/std-num-f64-to-string-type.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-string-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.f64_to_string 1.0)
)
"#,
        snapshot: "../tests/std-num-f64-to-string-context.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-string-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.num.f64_to_string 1.0) 1 0))
"#,
        snapshot: "../tests/std-num-f64-to-string-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-string-name-shadow",
        source: r#"
(module main)

(fn std.num.f64_to_string ((value f64)) -> string
  "0.0")

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-num-f64-to-string-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-string-helper-shadow",
        source: r#"
(module main)

(fn __glagol_num_f64_to_string ((value f64)) -> string
  "0.0")

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-num-f64-to-string-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-num-to-string-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.to_string 1)
  0)
"#,
        snapshot: "../tests/std-num-to-string-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-from-i64-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.from_i64 1i64)
  0)
"#,
        snapshot: "../tests/std-string-from-i64-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-num-i32-to-i64-result-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.i32_to_i64_result 1)
  0)
"#,
        snapshot: "../tests/std-num-i32-to-i64-result-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i32-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.f64_to_i32 1.0)
  0)
"#,
        snapshot: "../tests/std-num-f64-to-i32-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i64-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.f64_to_i64 1.0)
  0)
"#,
        snapshot: "../tests/std-num-f64-to-i64-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i32-result-arity",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.num.f64_to_i32_result))
"#,
        snapshot: "../tests/std-num-f64-to-i32-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i32-result-type",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.num.f64_to_i32_result 1))
"#,
        snapshot: "../tests/std-num-f64-to-i32-result-type.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i32-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.f64_to_i32_result 1.0))
"#,
        snapshot: "../tests/std-num-f64-to-i32-result-context.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i32-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.num.f64_to_i32_result 1.0) 1 0))
"#,
        snapshot: "../tests/std-num-f64-to-i32-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i32-result-name-shadow",
        source: r#"
(module main)

(fn std.num.f64_to_i32_result ((value f64)) -> (result i32 i32)
  (ok 0))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-num-f64-to-i32-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i64-result-arity",
        source: r#"
(module main)

(fn main () -> (result i64 i32)
  (std.num.f64_to_i64_result))
"#,
        snapshot: "../tests/std-num-f64-to-i64-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i64-result-type",
        source: r#"
(module main)

(fn main () -> (result i64 i32)
  (std.num.f64_to_i64_result 1))
"#,
        snapshot: "../tests/std-num-f64-to-i64-result-type.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i64-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.f64_to_i64_result 1.0))
"#,
        snapshot: "../tests/std-num-f64-to-i64-result-context.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i64-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.num.f64_to_i64_result 1.0) 1 0))
"#,
        snapshot: "../tests/std-num-f64-to-i64-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-num-f64-to-i64-result-name-shadow",
        source: r#"
(module main)

(fn std.num.f64_to_i64_result ((value f64)) -> (result i64 i32)
  (ok 0i64))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-num-f64-to-i64-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-num-cast-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.cast 1)
  0)
"#,
        snapshot: "../tests/std-num-cast-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-num-cast-checked-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.num.cast_checked 1)
  0)
"#,
        snapshot: "../tests/std-num-cast-checked-unsupported.diag",
    },
    DiagnosticCase {
        name: "print-bool-arity",
        source: r#"
(module main)

(fn main () -> i32
  (print_bool true false)
  0)
"#,
        snapshot: "../tests/print-bool-arity.diag",
    },
    DiagnosticCase {
        name: "std-print-bool-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.print_bool true false)
  0)
"#,
        snapshot: "../tests/std-print-bool-arity.diag",
    },
    DiagnosticCase {
        name: "print-bool-type",
        source: r#"
(module main)

(fn main () -> i32
  (print_bool 1)
  0)
"#,
        snapshot: "../tests/print-bool-type.diag",
    },
    DiagnosticCase {
        name: "string-len-arity",
        source: r#"
(module main)

(fn main () -> i32
  (string_len "a" "b"))
"#,
        snapshot: "../tests/string-len-arity.diag",
    },
    DiagnosticCase {
        name: "string-len-type",
        source: r#"
(module main)

(fn main () -> i32
  (string_len 1))
"#,
        snapshot: "../tests/string-len-type.diag",
    },
    DiagnosticCase {
        name: "std-string-len-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.len 1))
"#,
        snapshot: "../tests/std-string-len-type.diag",
    },
    DiagnosticCase {
        name: "std-string-concat-arity",
        source: r#"
(module main)

(fn main () -> string
  (std.string.concat "a"))
"#,
        snapshot: "../tests/std-string-concat-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-concat-type",
        source: r#"
(module main)

(fn main () -> string
  (std.string.concat 1 "a"))
"#,
        snapshot: "../tests/std-string-concat-type.diag",
    },
    DiagnosticCase {
        name: "std-string-concat-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.concat "a" "b"))
"#,
        snapshot: "../tests/std-string-concat-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-concat-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_concat ((left string) (right string)) -> string
  "intercepted")

(fn main () -> string
  (std.string.concat "a" "b"))
"#,
        snapshot: "../tests/std-string-concat-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-concat-unsupported-string-container",
        source: r#"
(module main)

(fn main () -> string
  (std.string.concat (array string "a") "b"))
"#,
        snapshot: "../tests/std-string-concat-unsupported-string-container.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-result-arity",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.string.byte_at_result "abc"))
"#,
        snapshot: "../tests/std-string-byte-at-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-result-type",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.string.byte_at_result "abc" "0"))
"#,
        snapshot: "../tests/std-string-byte-at-result-type.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.byte_at_result "abc" 0))
"#,
        snapshot: "../tests/std-string-byte-at-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.string.byte_at_result "abc" 0) 1 0))
"#,
        snapshot: "../tests/std-string-byte-at-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-result-name-shadow",
        source: r#"
(module main)

(fn std.string.byte_at_result ((text string) (index i32)) -> (result i32 i32)
  (err i32 i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-byte-at-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_byte_at_result ((text string) (index i32)) -> (result i32 i32)
  (err i32 i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-byte-at-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-result-arity",
        source: r#"
(module main)

(fn main () -> (result string i32)
  (std.string.slice_result "abc" 0))
"#,
        snapshot: "../tests/std-string-slice-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-result-type",
        source: r#"
(module main)

(fn main () -> (result string i32)
  (std.string.slice_result "abc" 0 "1"))
"#,
        snapshot: "../tests/std-string-slice-result-type.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-result-context",
        source: r#"
(module main)

(fn main () -> string
  (std.string.slice_result "abc" 0 1))
"#,
        snapshot: "../tests/std-string-slice-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.string.slice_result "abc" 0 1) 1 0))
"#,
        snapshot: "../tests/std-string-slice-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-result-name-shadow",
        source: r#"
(module main)

(fn std.string.slice_result ((text string) (start i32) (count i32)) -> (result string i32)
  (err string i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-slice-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_slice_result ((text string) (start i32) (count i32)) -> (result string i32)
  (err string i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-slice-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-starts-with-arity",
        source: r#"
(module main)

(fn main () -> bool
  (std.string.starts_with "abc"))
"#,
        snapshot: "../tests/std-string-starts-with-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-starts-with-type",
        source: r#"
(module main)

(fn main () -> bool
  (std.string.starts_with "abc" 1))
"#,
        snapshot: "../tests/std-string-starts-with-type.diag",
    },
    DiagnosticCase {
        name: "std-string-starts-with-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.starts_with "abc" "a"))
"#,
        snapshot: "../tests/std-string-starts-with-context.diag",
    },
    DiagnosticCase {
        name: "std-string-starts-with-name-shadow",
        source: r#"
(module main)

(fn std.string.starts_with ((text string) (prefix string)) -> bool
  false)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-starts-with-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-starts-with-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_starts_with ((text string) (prefix string)) -> bool
  false)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-starts-with-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-ends-with-arity",
        source: r#"
(module main)

(fn main () -> bool
  (std.string.ends_with "abc"))
"#,
        snapshot: "../tests/std-string-ends-with-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-ends-with-type",
        source: r#"
(module main)

(fn main () -> bool
  (std.string.ends_with "abc" 1))
"#,
        snapshot: "../tests/std-string-ends-with-type.diag",
    },
    DiagnosticCase {
        name: "std-string-ends-with-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.ends_with "abc" "c"))
"#,
        snapshot: "../tests/std-string-ends-with-context.diag",
    },
    DiagnosticCase {
        name: "std-string-ends-with-name-shadow",
        source: r#"
(module main)

(fn std.string.ends_with ((text string) (suffix string)) -> bool
  false)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-ends-with-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-ends-with-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_ends_with ((text string) (suffix string)) -> bool
  false)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-ends-with-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-result-arity",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.string.parse_i32_result))
"#,
        snapshot: "../tests/std-string-parse-i32-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-result-type",
        source: r#"
(module main)

(fn main () -> (result i32 i32)
  (std.string.parse_i32_result 1))
"#,
        snapshot: "../tests/std-string-parse-i32-result-type.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_result "42"))
"#,
        snapshot: "../tests/std-string-parse-i32-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.string.parse_i32_result "42") 1 0))
"#,
        snapshot: "../tests/std-string-parse-i32-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-result-name-shadow",
        source: r#"
(module main)

(fn std.string.parse_i32_result ((text string)) -> (result i32 i32)
  (err i32 i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_parse_i32_result ((text string)) -> (result i32 i32)
  (err i32 i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i64-result-arity",
        source: r#"
(module main)

(fn main () -> (result i64 i32)
  (std.string.parse_i64_result))
"#,
        snapshot: "../tests/std-string-parse-i64-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i64-result-type",
        source: r#"
(module main)

(fn main () -> (result i64 i32)
  (std.string.parse_i64_result 1))
"#,
        snapshot: "../tests/std-string-parse-i64-result-type.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i64-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i64_result "42"))
"#,
        snapshot: "../tests/std-string-parse-i64-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i64-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.string.parse_i64_result "42") 1 0))
"#,
        snapshot: "../tests/std-string-parse-i64-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i64-result-name-shadow",
        source: r#"
(module main)

(fn std.string.parse_i64_result ((text string)) -> (result i64 i32)
  (err i64 i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-i64-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i64-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_parse_i64_result ((text string)) -> (result i64 i32)
  (err i64 i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-i64-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-result-arity",
        source: r#"
(module main)

(fn main () -> (result f64 i32)
  (std.string.parse_f64_result))
"#,
        snapshot: "../tests/std-string-parse-f64-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-result-type",
        source: r#"
(module main)

(fn main () -> (result f64 i32)
  (std.string.parse_f64_result 1))
"#,
        snapshot: "../tests/std-string-parse-f64-result-type.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_f64_result "1.0"))
"#,
        snapshot: "../tests/std-string-parse-f64-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.string.parse_f64_result "1.0") 1 0))
"#,
        snapshot: "../tests/std-string-parse-f64-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-result-name-shadow",
        source: r#"
(module main)

(fn std.string.parse_f64_result ((text string)) -> (result f64 i32)
  (std.string.parse_f64_result text))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-f64-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_parse_f64_result ((text string)) -> (result f64 i32)
  (std.string.parse_f64_result text))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-f64-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-result-arity",
        source: r#"
(module main)

(fn main () -> (result bool i32)
  (std.string.parse_bool_result))
"#,
        snapshot: "../tests/std-string-parse-bool-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-result-type",
        source: r#"
(module main)

(fn main () -> (result bool i32)
  (std.string.parse_bool_result 1))
"#,
        snapshot: "../tests/std-string-parse-bool-result-type.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_bool_result "true"))
"#,
        snapshot: "../tests/std-string-parse-bool-result-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.string.parse_bool_result "true") 1 0))
"#,
        snapshot: "../tests/std-string-parse-bool-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-result-name-shadow",
        source: r#"
(module main)

(fn std.string.parse_bool_result ((text string)) -> (result bool i32)
  (std.string.parse_bool_result text))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-bool-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_string_parse_bool_result ((text string)) -> (result bool i32)
  (std.string.parse_bool_result text))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-string-parse-bool-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32 "42")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-f64-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_f64 "1.0")
  0)
"#,
        snapshot: "../tests/std-string-parse-f64-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bool-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_bool "true")
  0)
"#,
        snapshot: "../tests/std-string-parse-bool-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-string-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_string_result "text")
  0)
"#,
        snapshot: "../tests/std-string-parse-string-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-bytes-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_bytes_result "42")
  0)
"#,
        snapshot: "../tests/std-string-parse-bytes-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-trim-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_trim_result " 42 ")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-trim-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-whitespace-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_whitespace_result " 42 ")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-whitespace-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-locale-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_locale_result "42" "hr-HR")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-locale-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-base-prefix-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_base_prefix_result "0x2a")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-base-prefix-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-binary-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_binary_result "101010")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-binary-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-octal-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_octal_result "52")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-octal-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-hex-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_hex_result "2a")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-hex-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-radix-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_radix_result "2a" 16)
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-radix-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-underscore-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_underscore_result "1_000")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-underscore-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-plus-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_plus_result "+42")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-plus-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-generic-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_result "42")
  0)
"#,
        snapshot: "../tests/std-string-parse-generic-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-message-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_message_result "nope")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-message-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-code-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_code_result "nope")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-code-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-error-adt-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_error_result "nope")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-error-adt-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-parse-i32-unicode-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.parse_i32_unicode_result "42")
  0)
"#,
        snapshot: "../tests/std-string-parse-i32-unicode-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-index-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.index "42" 0))
"#,
        snapshot: "../tests/std-string-index-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-byte-at-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.byte_at "42" 0))
"#,
        snapshot: "../tests/std-string-byte-at-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-slice-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.slice "42" 0 1)
  0)
"#,
        snapshot: "../tests/std-string-slice-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-contains-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.contains "slovo" "lo")
  0)
"#,
        snapshot: "../tests/std-string-contains-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-find-result-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.find_result "slovo" "lo")
  0)
"#,
        snapshot: "../tests/std-string-find-result-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-split-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.split "a,b" ",")
  0)
"#,
        snapshot: "../tests/std-string-split-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-tokenize-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.tokenize "1 2")
  0)
"#,
        snapshot: "../tests/std-string-tokenize-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-string-scan-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.string.scan "42")
  0)
"#,
        snapshot: "../tests/std-string-scan-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-eprint-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.eprint "a" "b")
  0)
"#,
        snapshot: "../tests/std-io-eprint-arity.diag",
    },
    DiagnosticCase {
        name: "std-process-arg-type",
        source: r#"
(module main)

(fn main () -> string
  (std.process.arg true))
"#,
        snapshot: "../tests/std-process-arg-type.diag",
    },
    DiagnosticCase {
        name: "std-env-get-type",
        source: r#"
(module main)

(fn main () -> string
  (std.env.get 1))
"#,
        snapshot: "../tests/std-env-get-type.diag",
    },
    DiagnosticCase {
        name: "std-fs-write-text-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.fs.write_text "path"))
"#,
        snapshot: "../tests/std-fs-write-text-arity.diag",
    },
    DiagnosticCase {
        name: "std-io-eprint-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.eprint "not an i32"))
"#,
        snapshot: "../tests/std-io-eprint-result-context.diag",
    },
    DiagnosticCase {
        name: "std-fs-read-text-helper-shadow",
        source: r#"
(module main)

(fn __glagol_fs_read_text ((path string)) -> string
  "intercepted")

(fn main () -> string
  (std.fs.read_text "path"))
"#,
        snapshot: "../tests/std-fs-read-text-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-fs-read-binary-unsupported-alias",
        source: r#"
(module main)

(fn main () -> string
  (std.fs.read_binary "path"))
"#,
        snapshot: "../tests/std-fs-read-binary-unsupported-alias.diag",
    },
    DiagnosticCase {
        name: "std-net-connect-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.net.connect "host")
  0)
"#,
        snapshot: "../tests/std-net-connect-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-async-spawn-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.async.spawn 0)
  0)
"#,
        snapshot: "../tests/std-async-spawn-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-fs-list-dir-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.fs.list_dir ".")
  0)
"#,
        snapshot: "../tests/std-fs-list-dir-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-terminal-clear-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.terminal.clear)
  0)
"#,
        snapshot: "../tests/std-terminal-clear-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-platform-os-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.platform.os)
  0)
"#,
        snapshot: "../tests/std-platform-os-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.read_stdin)
  0)
"#,
        snapshot: "../tests/std-io-read-stdin-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-read-line-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.read_line)
  0)
"#,
        snapshot: "../tests/std-io-read-line-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-stdin-lines-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.stdin_lines)
  0)
"#,
        snapshot: "../tests/std-io-stdin-lines-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-prompt-unsupported",
        source: r#"
(module main)

(fn main () -> string
  (std.io.prompt "name"))
"#,
        snapshot: "../tests/std-io-prompt-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-terminal-raw-mode-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.terminal.raw_mode true)
  0)
"#,
        snapshot: "../tests/std-terminal-raw-mode-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-terminal-echo-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.terminal.echo false)
  0)
"#,
        snapshot: "../tests/std-terminal-echo-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-terminal-is-tty-unsupported",
        source: r#"
(module main)

(fn main () -> bool
  (std.terminal.is_tty))
"#,
        snapshot: "../tests/std-terminal-is-tty-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-binary-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.read_stdin_binary)
  0)
"#,
        snapshot: "../tests/std-io-read-stdin-binary-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-bytes-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.read_stdin_bytes)
  0)
"#,
        snapshot: "../tests/std-io-read-stdin-bytes-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-stdin-stream-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.stdin_stream)
  0)
"#,
        snapshot: "../tests/std-io-stdin-stream-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-async-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.read_stdin_async)
  0)
"#,
        snapshot: "../tests/std-io-read-stdin-async-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-io-stdin-encoding-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.stdin_encoding)
  0)
"#,
        snapshot: "../tests/std-io-stdin-encoding-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-i32-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.i32 1))
"#,
        snapshot: "../tests/std-random-i32-arity.diag",
    },
    DiagnosticCase {
        name: "std-random-i32-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.random.i32) 1 0))
"#,
        snapshot: "../tests/std-random-i32-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-random-i32-name-shadow",
        source: r#"
(module main)

(fn std.random.i32 () -> i32
  0)

(fn main () -> i32
  (std.random.i32))
"#,
        snapshot: "../tests/std-random-i32-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-random-i32-helper-shadow",
        source: r#"
(module main)

(fn __glagol_random_i32 () -> i32
  0)

(fn main () -> i32
  (std.random.i32))
"#,
        snapshot: "../tests/std-random-i32-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-random-seed-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.seed 1)
  0)
"#,
        snapshot: "../tests/std-random-seed-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-range-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.range 0 10))
"#,
        snapshot: "../tests/std-random-range-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-bytes-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.bytes 16)
  0)
"#,
        snapshot: "../tests/std-random-bytes-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-float-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.float)
  0)
"#,
        snapshot: "../tests/std-random-float-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-shuffle-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.shuffle (std.vec.i32.empty))
  0)
"#,
        snapshot: "../tests/std-random-shuffle-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-string-unsupported",
        source: r#"
(module main)

(fn main () -> string
  (std.random.string 8))
"#,
        snapshot: "../tests/std-random-string-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-uuid-unsupported",
        source: r#"
(module main)

(fn main () -> string
  (std.random.uuid))
"#,
        snapshot: "../tests/std-random-uuid-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-random-crypto-i32-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.random.crypto_i32))
"#,
        snapshot: "../tests/std-random-crypto-i32-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-time-now-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.time.now)
  0)
"#,
        snapshot: "../tests/std-time-now-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-time-monotonic-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.time.monotonic_ms 1))
"#,
        snapshot: "../tests/std-time-monotonic-arity.diag",
    },
    DiagnosticCase {
        name: "std-time-monotonic-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (let elapsed string (std.time.monotonic_ms))
  0)
"#,
        snapshot: "../tests/std-time-monotonic-result-context.diag",
    },
    DiagnosticCase {
        name: "std-time-sleep-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.time.sleep_ms)
  0)
"#,
        snapshot: "../tests/std-time-sleep-arity.diag",
    },
    DiagnosticCase {
        name: "std-time-sleep-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.time.sleep_ms true)
  0)
"#,
        snapshot: "../tests/std-time-sleep-type.diag",
    },
    DiagnosticCase {
        name: "std-time-monotonic-helper-shadow",
        source: r#"
(module main)

(fn __glagol_time_monotonic_ms () -> i32
  0)

(fn main () -> i32
  (std.time.monotonic_ms))
"#,
        snapshot: "../tests/std-time-monotonic-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-time-monotonic-name-shadow",
        source: r#"
(module main)

(fn std.time.monotonic_ms () -> i32
  0)

(fn main () -> i32
  (std.time.monotonic_ms))
"#,
        snapshot: "../tests/std-time-monotonic-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-time-sleep-helper-shadow",
        source: r#"
(module main)

(fn __glagol_time_sleep_ms ((ms i32)) -> i32
  ms)

(fn main () -> i32
  (std.time.sleep_ms 0)
  0)
"#,
        snapshot: "../tests/std-time-sleep-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-time-sleep-name-shadow",
        source: r#"
(module main)

(fn std.time.sleep_ms ((ms i32)) -> i32
  ms)

(fn main () -> i32
  (std.time.sleep_ms 0)
  0)
"#,
        snapshot: "../tests/std-time-sleep-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-process-arg-result-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.process.arg_result)
  0)
"#,
        snapshot: "../tests/std-process-arg-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-env-get-result-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.env.get_result 1)
  0)
"#,
        snapshot: "../tests/std-env-get-result-type.diag",
    },
    DiagnosticCase {
        name: "std-fs-write-text-result-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.fs.write_text_result "path")
  0)
"#,
        snapshot: "../tests/std-fs-write-text-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-fs-write-text-result-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.fs.write_text_result "path" 1)
  0)
"#,
        snapshot: "../tests/std-fs-write-text-result-type.diag",
    },
    DiagnosticCase {
        name: "std-process-arg-result-name-shadow",
        source: r#"
(module main)

(fn std.process.arg_result ((index i32)) -> (result string i32)
  (err string i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-process-arg-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-process-arg-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_process_arg_result ((index i32)) -> (result string i32)
  (err string i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-process-arg-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-result-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.read_stdin_result 1))
"#,
        snapshot: "../tests/std-io-read-stdin-result-arity.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-result-bool-context",
        source: r#"
(module main)

(fn main () -> i32
  (if (std.io.read_stdin_result) 1 0))
"#,
        snapshot: "../tests/std-io-read-stdin-result-bool-context.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-result-type",
        source: r#"
(module main)

(fn main () -> i32
  (let value i32 (std.io.read_stdin_result))
  value)
"#,
        snapshot: "../tests/std-io-read-stdin-result-type.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-result-name-shadow",
        source: r#"
(module main)

(fn std.io.read_stdin_result () -> (result string i32)
  (err string i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-io-read-stdin-result-name-shadow.diag",
    },
    DiagnosticCase {
        name: "std-io-read-stdin-result-helper-shadow",
        source: r#"
(module main)

(fn __glagol_io_read_stdin_result () -> (result string i32)
  (err string i32 1))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/std-io-read-stdin-result-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-result-map-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.result.map (ok string i32 "a") mapper)
  0)
"#,
        snapshot: "../tests/std-result-map-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-vec-empty-generic-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.empty i32)
  0)
"#,
        snapshot: "../tests/std-vec-empty-generic-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-package-load-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.package.load "dep")
  0)
"#,
        snapshot: "../tests/std-package-load-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-abi-layout-unsupported",
        source: r#"
(module main)

(fn main () -> i32
  (std.abi.layout)
  0)
"#,
        snapshot: "../tests/std-abi-layout-unsupported.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-arity",
        source: r#"
(module main)

(fn main () -> (vec i32)
  (std.vec.i32.append (std.vec.i32.empty)))
"#,
        snapshot: "../tests/std-vec-i32-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-empty-arity",
        source: r#"
(module main)

(fn main () -> (vec i32)
  (std.vec.i32.empty 1))
"#,
        snapshot: "../tests/std-vec-i32-empty-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-len-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i32.len))
"#,
        snapshot: "../tests/std-vec-i32-len-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-index-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i32.index (std.vec.i32.empty)))
"#,
        snapshot: "../tests/std-vec-i32-index-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-type",
        source: r#"
(module main)

(fn main () -> (vec i32)
  (std.vec.i32.append (std.vec.i32.empty) true))
"#,
        snapshot: "../tests/std-vec-i32-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-append-vector-type",
        source: r#"
(module main)

(fn main () -> (vec i32)
  (std.vec.i32.append 1 2))
"#,
        snapshot: "../tests/std-vec-i32-append-vector-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-len-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i32.len 1))
"#,
        snapshot: "../tests/std-vec-i32-len-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-index-vector-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i32.index 1 0))
"#,
        snapshot: "../tests/std-vec-i32-index-vector-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-index-index-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i32.index (std.vec.i32.empty) true))
"#,
        snapshot: "../tests/std-vec-i32-index-index-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i32.empty))
"#,
        snapshot: "../tests/std-vec-i32-result-context.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-one-sided-equality",
        source: r#"
(module main)

(fn main () -> bool
  (= (std.vec.i32.empty) 1))
"#,
        snapshot: "../tests/std-vec-i32-one-sided-equality.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-helper-shadow",
        source: r#"
(module main)

(fn __glagol_vec_i32_eq ((left (vec i32)) (right (vec i32))) -> bool
  (= left right))

(fn main () -> (vec i32)
  (std.vec.i32.empty))
"#,
        snapshot: "../tests/std-vec-i32-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-vec-i32-push-alias",
        source: r#"
(module main)

(fn main () -> (vec i32)
  (std.vec.i32.push (std.vec.i32.empty) 1))
"#,
        snapshot: "../tests/std-vec-i32-push-alias.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-arity",
        source: r#"
(module main)

(fn main () -> (vec i64)
  (std.vec.i64.append (std.vec.i64.empty)))
"#,
        snapshot: "../tests/std-vec-i64-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-empty-arity",
        source: r#"
(module main)

(fn main () -> (vec i64)
  (std.vec.i64.empty 1))
"#,
        snapshot: "../tests/std-vec-i64-empty-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-len-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i64.len))
"#,
        snapshot: "../tests/std-vec-i64-len-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-index-arity",
        source: r#"
(module main)

(fn main () -> i64
  (std.vec.i64.index (std.vec.i64.empty)))
"#,
        snapshot: "../tests/std-vec-i64-index-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-type",
        source: r#"
(module main)

(fn main () -> (vec i64)
  (std.vec.i64.append (std.vec.i64.empty) true))
"#,
        snapshot: "../tests/std-vec-i64-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-append-vector-type",
        source: r#"
(module main)

(fn main () -> (vec i64)
  (std.vec.i64.append 1 2i64))
"#,
        snapshot: "../tests/std-vec-i64-append-vector-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-len-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i64.len 1))
"#,
        snapshot: "../tests/std-vec-i64-len-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-index-vector-type",
        source: r#"
(module main)

(fn main () -> i64
  (std.vec.i64.index 1 0))
"#,
        snapshot: "../tests/std-vec-i64-index-vector-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-index-index-type",
        source: r#"
(module main)

(fn main () -> i64
  (std.vec.i64.index (std.vec.i64.empty) true))
"#,
        snapshot: "../tests/std-vec-i64-index-index-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.i64.empty))
"#,
        snapshot: "../tests/std-vec-i64-result-context.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-one-sided-equality",
        source: r#"
(module main)

(fn main () -> bool
  (= (std.vec.i64.empty) 1))
"#,
        snapshot: "../tests/std-vec-i64-one-sided-equality.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-helper-shadow",
        source: r#"
(module main)

(fn __glagol_vec_i64_eq ((left (vec i64)) (right (vec i64))) -> bool
  (= left right))

(fn main () -> (vec i64)
  (std.vec.i64.empty))
"#,
        snapshot: "../tests/std-vec-i64-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-vec-i64-push-alias",
        source: r#"
(module main)

(fn main () -> (vec i64)
  (std.vec.i64.push (std.vec.i64.empty) 1i64))
"#,
        snapshot: "../tests/std-vec-i64-push-alias.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-arity",
        source: r#"
(module main)

(fn main () -> (vec string)
  (std.vec.string.append (std.vec.string.empty)))
"#,
        snapshot: "../tests/std-vec-string-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-empty-arity",
        source: r#"
(module main)

(fn main () -> (vec string)
  (std.vec.string.empty "extra"))
"#,
        snapshot: "../tests/std-vec-string-empty-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-len-arity",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.string.len))
"#,
        snapshot: "../tests/std-vec-string-len-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-index-arity",
        source: r#"
(module main)

(fn main () -> string
  (std.vec.string.index (std.vec.string.empty)))
"#,
        snapshot: "../tests/std-vec-string-index-arity.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-type",
        source: r#"
(module main)

(fn main () -> (vec string)
  (std.vec.string.append (std.vec.string.empty) 1))
"#,
        snapshot: "../tests/std-vec-string-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-append-vector-type",
        source: r#"
(module main)

(fn main () -> (vec string)
  (std.vec.string.append 1 "x"))
"#,
        snapshot: "../tests/std-vec-string-append-vector-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-len-type",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.string.len 1))
"#,
        snapshot: "../tests/std-vec-string-len-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-index-vector-type",
        source: r#"
(module main)

(fn main () -> string
  (std.vec.string.index 1 0))
"#,
        snapshot: "../tests/std-vec-string-index-vector-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-index-index-type",
        source: r#"
(module main)

(fn main () -> string
  (std.vec.string.index (std.vec.string.empty) true))
"#,
        snapshot: "../tests/std-vec-string-index-index-type.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-result-context",
        source: r#"
(module main)

(fn main () -> i32
  (std.vec.string.empty))
"#,
        snapshot: "../tests/std-vec-string-result-context.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-one-sided-equality",
        source: r#"
(module main)

(fn main () -> bool
  (= (std.vec.string.empty) 1))
"#,
        snapshot: "../tests/std-vec-string-one-sided-equality.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-helper-shadow",
        source: r#"
(module main)

(fn __glagol_vec_string_eq ((left (vec string)) (right (vec string))) -> bool
  (= left right))

(fn main () -> (vec string)
  (std.vec.string.empty))
"#,
        snapshot: "../tests/std-vec-string-helper-shadow.diag",
    },
    DiagnosticCase {
        name: "std-vec-string-push-alias",
        source: r#"
(module main)

(fn main () -> (vec string)
  (std.vec.string.push (std.vec.string.empty) "x"))
"#,
        snapshot: "../tests/std-vec-string-push-alias.diag",
    },
    DiagnosticCase {
        name: "std-print-bool-result",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.print_bool true))
"#,
        snapshot: "../tests/std-print-bool-result.diag",
    },
    DiagnosticCase {
        name: "std-parameter-shadows-runtime",
        source: r#"
(module main)

(fn leak ((std.io.print_i32 i32)) -> i32
  std.io.print_i32)
"#,
        snapshot: "../tests/std-parameter-shadows-runtime.diag",
    },
    DiagnosticCase {
        name: "unsafe-parameter-shadows-callable",
        source: r#"
(module main)

(fn leak ((alloc i32)) -> i32
  alloc)
"#,
        snapshot: "../tests/unsafe-parameter-shadows-callable.diag",
    },
    DiagnosticCase {
        name: "integer-out-of-range",
        source: r#"
(module main)

(fn main () -> i32
  2147483648)
"#,
        snapshot: "../tests/integer-out-of-range.diag",
    },
    DiagnosticCase {
        name: "i64-literal-out-of-range",
        source: r#"
(module main)

(fn main () -> i32
  9223372036854775808i64)
"#,
        snapshot: "../tests/i64-literal-out-of-range.diag",
    },
    DiagnosticCase {
        name: "invalid-i64-literal",
        source: r#"
(module main)

(fn main () -> i32
  1.0i64)
"#,
        snapshot: "../tests/invalid-i64-literal.diag",
    },
    DiagnosticCase {
        name: "invalid-leading-plus-i64-literal",
        source: r#"
(module main)

(fn main () -> i32
  +1i64)
"#,
        snapshot: "../tests/invalid-leading-plus-i64-literal.diag",
    },
    DiagnosticCase {
        name: "invalid-sign-only-i64-literal",
        source: r#"
(module main)

(fn main () -> i32
  -i64)
"#,
        snapshot: "../tests/invalid-sign-only-i64-literal.diag",
    },
    DiagnosticCase {
        name: "unsupported-float-literal",
        source: r#"
(module main)

(fn main () -> i32
  (let value f64 NaN)
  0)
"#,
        snapshot: "../tests/unsupported-float-literal.diag",
    },
    DiagnosticCase {
        name: "test-invalid-name",
        source: r#"
(module main)

(test not-a-string true)
"#,
        snapshot: "../tests/test-invalid-name.diag",
    },
    DiagnosticCase {
        name: "test-invalid-escaped-name",
        source: r#"
(module main)

(test "bad\nname" true)
"#,
        snapshot: "../tests/test-invalid-escaped-name.diag",
    },
    DiagnosticCase {
        name: "test-duplicate-name",
        source: r#"
(module main)

(test "same" true)
(test "same" true)
"#,
        snapshot: "../tests/test-duplicate-name.diag",
    },
    DiagnosticCase {
        name: "test-non-bool",
        source: r#"
(module main)

(test "not bool"
  1)
"#,
        snapshot: "../tests/test-non-bool.diag",
    },
    DiagnosticCase {
        name: "test-invalid-form",
        source: r#"
(module main)

(test "too many" true false)
"#,
        snapshot: "../tests/test-invalid-form.diag",
    },
    DiagnosticCase {
        name: "unsupported-signature-type",
        source: r#"
(module main)

(fn id ((value (ptr i32))) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-signature-type.diag",
    },
    DiagnosticCase {
        name: "unknown-struct-parameter",
        source: r#"
(module main)

(fn take ((value Missing)) -> i32
  0)
"#,
        snapshot: "../tests/unknown-struct-parameter.diag",
    },
    DiagnosticCase {
        name: "unknown-struct-return",
        source: r#"
(module main)

(fn make () -> Missing
  0)
"#,
        snapshot: "../tests/unknown-struct-return.diag",
    },
    DiagnosticCase {
        name: "unsupported-unit-return-signature",
        source: r#"
(module main)

(fn main () -> unit
  (print_i32 1))
"#,
        snapshot: "../tests/unsupported-unit-return-signature.diag",
    },
    DiagnosticCase {
        name: "unsupported-unit-parameter-signature",
        source: r#"
(module main)

(fn ignore ((value unit)) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-unit-parameter-signature.diag",
    },
    DiagnosticCase {
        name: "empty-array",
        source: r#"
(module main)

(fn main () -> i32
  (index (array i32) 0))
"#,
        snapshot: "../tests/empty-array.diag",
    },
    DiagnosticCase {
        name: "zero-length-array-type",
        source: r#"
(module main)

(fn main () -> i32
  (let values (array i32 0) (array i32 1))
  0)
"#,
        snapshot: "../tests/zero-length-array-type.diag",
    },
    DiagnosticCase {
        name: "array-index-out-of-bounds",
        source: r#"
(module main)

(fn main () -> i32
  (index (array i32 1 2) 2))
"#,
        snapshot: "../tests/array-index-out-of-bounds.diag",
    },
    DiagnosticCase {
        name: "index-on-non-array",
        source: r#"
(module main)

(fn main () -> i32
  (index 1 0))
"#,
        snapshot: "../tests/index-on-non-array.diag",
    },
    DiagnosticCase {
        name: "array-index-not-i32",
        source: r#"
(module main)

(fn main () -> i32
  (index (array i32 1) true))
"#,
        snapshot: "../tests/array-index-not-i32.diag",
    },
    DiagnosticCase {
        name: "unsupported-array-element-type",
        source: r#"
(module main)

(fn main () -> i32
  (index (array (array i32 1) (array i32 1)) 0))
"#,
        snapshot: "../tests/unsupported-array-element-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-array-signature-element-type",
        source: r#"
(module main)

(fn first ((values (array (array string 1) 1))) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-array-signature-element-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-array-equality",
        source: r#"
(module main)

(fn main () -> i32
  (if (= (array i32 1) (array i32 1)) 1 0))
"#,
        snapshot: "../tests/unsupported-array-equality.diag",
    },
    DiagnosticCase {
        name: "unsupported-array-local-mutation",
        source: r#"
(module main)

(fn main () -> i32
  (var values (array i32 1) (array i32 1))
  0)
"#,
        snapshot: "../tests/unsupported-array-local-mutation.diag",
    },
    DiagnosticCase {
        name: "unsupported-array-print",
        source: r#"
(module main)

(fn main () -> i32
  (print_i32 (array i32 1))
  0)
"#,
        snapshot: "../tests/unsupported-array-print.diag",
    },
    DiagnosticCase {
        name: "unsupported-vec-element-type",
        source: r#"
(module main)

(fn main ((values (vec f32))) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-vec-element-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-generic-vec-type",
        source: r#"
(module main)

(fn main () -> (vec)
  (std.vec.i32.empty))
"#,
        snapshot: "../tests/unsupported-generic-vec-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-vec-nesting",
        source: r#"
(module main)

(fn main ((values (array (vec i32) 1))) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-vec-nesting.diag",
    },
    DiagnosticCase {
        name: "unsupported-vec-option",
        source: r#"
(module main)

(fn main () -> i32
  (is_some (some (vec i32) (std.vec.i32.empty))))
"#,
        snapshot: "../tests/unsupported-vec-option.diag",
    },
    DiagnosticCase {
        name: "unsupported-vec-result",
        source: r#"
(module main)

(fn main () -> i32
  (is_ok (ok (vec i32) i32 (std.vec.i32.empty))))
"#,
        snapshot: "../tests/unsupported-vec-result.diag",
    },
    DiagnosticCase {
        name: "unsupported-vec-literal",
        source: r#"
(module main)

(fn main () -> (vec i32)
  (vec i32 1))
"#,
        snapshot: "../tests/unsupported-vec-literal.diag",
    },
    DiagnosticCase {
        name: "array-return-type-mismatch",
        source: r#"
(module main)

(fn bad () -> (array i32 2)
  (array i32 1))
"#,
        snapshot: "../tests/array-return-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "array-argument-type-mismatch",
        source: r#"
(module main)

(fn first ((values (array i32 2))) -> i32
  (index values 0))

(fn main () -> i32
  (first (array i32 1)))
"#,
        snapshot: "../tests/array-argument-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "array-local-initializer-type-mismatch",
        source: r#"
(module main)

(fn main () -> i32
  (let values (array i32 2) (array i32 1))
  0)
"#,
        snapshot: "../tests/array-local-initializer-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "malformed-option-constructor",
        source: r#"
(module main)

(fn bad () -> (option i32)
  (some i32))
"#,
        snapshot: "../tests/malformed-option-constructor.diag",
    },
    DiagnosticCase {
        name: "option-constructor-type-mismatch",
        source: r#"
(module main)

(fn bad () -> (option i32)
  (some i32 true))
"#,
        snapshot: "../tests/option-constructor-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "unsupported-option-payload-type",
        source: r#"
(module main)

(fn main () -> i32
  (some (vec i32) (std.vec.i32.empty)))
"#,
        snapshot: "../tests/unsupported-option-payload-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-option-parameter-payload-type",
        source: r#"
(module main)

(fn take ((value (option (vec i32)))) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-option-parameter-payload-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-option-return-payload-type",
        source: r#"
(module main)

(fn bad () -> (option (vec i32))
  0)
"#,
        snapshot: "../tests/unsupported-option-return-payload-type.diag",
    },
    DiagnosticCase {
        name: "malformed-result-constructor",
        source: r#"
(module main)

(fn bad () -> (result i32 i32)
  (ok i32 i32))
"#,
        snapshot: "../tests/malformed-result-constructor.diag",
    },
    DiagnosticCase {
        name: "result-constructor-type-mismatch",
        source: r#"
(module main)

(fn bad () -> (result i32 i32)
  (err i32 i32 true))
"#,
        snapshot: "../tests/result-constructor-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "unsupported-result-payload-type",
        source: r#"
(module main)

(fn main () -> i32
  (ok i32 bool true))
"#,
        snapshot: "../tests/unsupported-result-payload-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-result-string-bool",
        source: r#"
(module main)

(fn main () -> i32
  (ok string bool "value"))
"#,
        snapshot: "../tests/unsupported-result-string-bool.diag",
    },
    DiagnosticCase {
        name: "unsupported-result-parameter-payload-type",
        source: r#"
(module main)

(fn take ((value (result i32 bool))) -> i32
  0)
"#,
        snapshot: "../tests/unsupported-result-parameter-payload-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-result-return-payload-type",
        source: r#"
(module main)

(fn bad () -> (result i32 bool)
  0)
"#,
        snapshot: "../tests/unsupported-result-return-payload-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-option-result-equality",
        source: r#"
(module main)

(fn main () -> i32
  (if (= (some i32 1) (none i32)) 1 0))
"#,
        snapshot: "../tests/unsupported-option-result-equality.diag",
    },
    DiagnosticCase {
        name: "unsupported-result-string-equality",
        source: r#"
(module main)

(fn main () -> i32
  (if (= (ok string i32 "a") (err string i32 1)) 1 0))
"#,
        snapshot: "../tests/unsupported-result-string-equality.diag",
    },
    DiagnosticCase {
        name: "unsupported-option-result-print",
        source: r#"
(module main)

(fn main () -> i32
  (print_i32 (none i32))
  0)
"#,
        snapshot: "../tests/unsupported-option-result-print.diag",
    },
    DiagnosticCase {
        name: "unsupported-result-string-print",
        source: r#"
(module main)

(fn main () -> i32
  (std.io.print_i32 (ok string i32 "a"))
  0)
"#,
        snapshot: "../tests/unsupported-result-string-print.diag",
    },
    DiagnosticCase {
        name: "match-subject-type-mismatch",
        source: r#"
(module main)

(fn main () -> i32
  (match 1
    ((some payload)
      payload)
    ((none)
      0)))
"#,
        snapshot: "../tests/match-subject-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "unsupported-match-payload-type",
        source: r#"
(module main)

(fn main () -> i32
  (match (some (vec i32) (std.vec.i32.empty))
    ((some payload)
      payload)
    ((none)
      0)))
"#,
        snapshot: "../tests/unsupported-match-payload-type.diag",
    },
    DiagnosticCase {
        name: "non-exhaustive-match",
        source: r#"
(module main)

(fn main ((value (option i32))) -> i32
  (match value
    ((some payload)
      payload)))
"#,
        snapshot: "../tests/non-exhaustive-match.diag",
    },
    DiagnosticCase {
        name: "duplicate-match-arm",
        source: r#"
(module main)

(fn main ((value (option i32))) -> i32
  (match value
    ((some payload)
      payload)
    ((some other)
      other)
    ((none)
      0)))
"#,
        snapshot: "../tests/duplicate-match-arm.diag",
    },
    DiagnosticCase {
        name: "malformed-match-pattern",
        source: r#"
(module main)

(fn main ((value (option i32))) -> i32
  (match value
    ((some)
      1)
    ((none)
      0)))
"#,
        snapshot: "../tests/malformed-match-pattern.diag",
    },
    DiagnosticCase {
        name: "match-arm-type-mismatch",
        source: r#"
(module main)

(fn main ((value (option i32))) -> i32
  (match value
    ((some payload)
      payload)
    ((none)
      false)))
"#,
        snapshot: "../tests/match-arm-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "match-binding-collision",
        source: r#"
(module main)

(fn main ((value (option i32)) (payload i32)) -> i32
  (match value
    ((some payload)
      payload)
    ((none)
      0)))
"#,
        snapshot: "../tests/match-binding-collision.diag",
    },
    DiagnosticCase {
        name: "unsupported-match-mutation",
        source: r#"
(module main)

(fn main ((value (option i32))) -> i32
  (match (set value (none i32))
    ((some payload)
      payload)
    ((none)
      0)))
"#,
        snapshot: "../tests/unsupported-match-mutation.diag",
    },
    DiagnosticCase {
        name: "unsupported-match-container",
        source: r#"
(module main)

(fn main () -> i32
  (match (array (option i32) (none i32))
    ((some payload)
      payload)
    ((none)
      0)))
"#,
        snapshot: "../tests/unsupported-match-container.diag",
    },
    DiagnosticCase {
        name: "option-observation-non-option",
        source: r#"
(module main)

(fn main () -> bool
  (is_some 1))
"#,
        snapshot: "../tests/option-observation-non-option.diag",
    },
    DiagnosticCase {
        name: "result-observation-non-result",
        source: r#"
(module main)

(fn main () -> bool
  (is_ok 1))
"#,
        snapshot: "../tests/result-observation-non-result.diag",
    },
    DiagnosticCase {
        name: "malformed-option-unwrap",
        source: r#"
(module main)

(fn main () -> i32
  (unwrap_some))
"#,
        snapshot: "../tests/malformed-option-unwrap.diag",
    },
    DiagnosticCase {
        name: "malformed-result-ok-unwrap",
        source: r#"
(module main)

(fn main () -> i32
  (unwrap_ok))
"#,
        snapshot: "../tests/malformed-result-ok-unwrap.diag",
    },
    DiagnosticCase {
        name: "malformed-result-err-unwrap",
        source: r#"
(module main)

(fn main () -> i32
  (unwrap_err))
"#,
        snapshot: "../tests/malformed-result-err-unwrap.diag",
    },
    DiagnosticCase {
        name: "option-unwrap-non-option",
        source: r#"
(module main)

(fn main () -> i32
  (unwrap_some 1))
"#,
        snapshot: "../tests/option-unwrap-non-option.diag",
    },
    DiagnosticCase {
        name: "result-ok-unwrap-non-result",
        source: r#"
(module main)

(fn main () -> i32
  (unwrap_ok 1))
"#,
        snapshot: "../tests/result-ok-unwrap-non-result.diag",
    },
    DiagnosticCase {
        name: "result-err-unwrap-non-result",
        source: r#"
(module main)

(fn main () -> i32
  (unwrap_err 1))
"#,
        snapshot: "../tests/result-err-unwrap-non-result.diag",
    },
    DiagnosticCase {
        name: "malformed-unsafe-form",
        source: r#"
(module main)

(fn main () -> i32
  (unsafe))
"#,
        snapshot: "../tests/malformed-unsafe-form.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-operation",
        source: r#"
(module main)

(fn main () -> i32
  (alloc i32))
"#,
        snapshot: "../tests/unsafe-required-operation.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-operation",
        source: r#"
(module main)

(fn main () -> i32
  (unsafe
    (alloc i32)))
"#,
        snapshot: "../tests/unsupported-unsafe-operation.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-dealloc",
        source: unsafe_required_source!("dealloc"),
        snapshot: "../tests/unsafe-required-dealloc.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-load",
        source: unsafe_required_source!("load"),
        snapshot: "../tests/unsafe-required-load.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-store",
        source: unsafe_required_source!("store"),
        snapshot: "../tests/unsafe-required-store.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-ptr-add",
        source: unsafe_required_source!("ptr_add"),
        snapshot: "../tests/unsafe-required-ptr-add.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-unchecked-index",
        source: unsafe_required_source!("unchecked_index"),
        snapshot: "../tests/unsafe-required-unchecked-index.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-reinterpret",
        source: unsafe_required_source!("reinterpret"),
        snapshot: "../tests/unsafe-required-reinterpret.diag",
    },
    DiagnosticCase {
        name: "unsafe-required-ffi-call",
        source: unsafe_required_source!("ffi_call"),
        snapshot: "../tests/unsafe-required-ffi-call.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-dealloc",
        source: unsupported_unsafe_source!("dealloc"),
        snapshot: "../tests/unsupported-unsafe-dealloc.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-load",
        source: unsupported_unsafe_source!("load"),
        snapshot: "../tests/unsupported-unsafe-load.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-store",
        source: unsupported_unsafe_source!("store"),
        snapshot: "../tests/unsupported-unsafe-store.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-ptr-add",
        source: unsupported_unsafe_source!("ptr_add"),
        snapshot: "../tests/unsupported-unsafe-ptr-add.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-unchecked-index",
        source: unsupported_unsafe_source!("unchecked_index"),
        snapshot: "../tests/unsupported-unsafe-unchecked-index.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-reinterpret",
        source: unsupported_unsafe_source!("reinterpret"),
        snapshot: "../tests/unsupported-unsafe-reinterpret.diag",
    },
    DiagnosticCase {
        name: "unsupported-unsafe-ffi-call",
        source: unsupported_unsafe_source!("ffi_call"),
        snapshot: "../tests/unsupported-unsafe-ffi-call.diag",
    },
    DiagnosticCase {
        name: "unsupported-struct-field-type",
        source: r#"
(module main)

(struct Point
  (x unit))
"#,
        snapshot: "../tests/unsupported-struct-field-type.diag",
    },
    DiagnosticCase {
        name: "unsupported-primitive-struct-field-container",
        source: r#"
(module main)

(struct Matrix
  (rows (array (array i32 2) 2)))
"#,
        snapshot: "../tests/unsupported-primitive-struct-field-container.diag",
    },
    DiagnosticCase {
        name: "empty-struct",
        source: r#"
(module main)

(struct Empty)

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/empty-struct.diag",
    },
    DiagnosticCase {
        name: "duplicate-struct",
        source: r#"
(module main)

(struct Point
  (x i32))

(struct Point
  (x i32))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/duplicate-struct.diag",
    },
    DiagnosticCase {
        name: "duplicate-struct-field",
        source: r#"
(module main)

(struct Point
  (x i32)
  (x i32))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/duplicate-struct-field.diag",
    },
    DiagnosticCase {
        name: "recursive-struct-field",
        source: r#"
(module main)

(struct Node
  (next Node))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/recursive-struct-field.diag",
    },
    DiagnosticCase {
        name: "cyclic-struct-fields",
        source: r#"
(module main)

(struct Left
  (right Right))

(struct Right
  (left Left))

(fn main () -> i32
  0)
"#,
        snapshot: "../tests/cyclic-struct-fields.diag",
    },
    DiagnosticCase {
        name: "struct-missing-field",
        source: r#"
(module main)

(struct Point
  (x i32)
  (y i32))

(fn main () -> i32
  (. (Point (x 1)) x))
"#,
        snapshot: "../tests/struct-missing-field.diag",
    },
    DiagnosticCase {
        name: "struct-unknown-field",
        source: r#"
(module main)

(struct Point
  (x i32)
  (y i32))

(fn main () -> i32
  (. (Point (x 1) (z 2)) x))
"#,
        snapshot: "../tests/struct-unknown-field.diag",
    },
    DiagnosticCase {
        name: "struct-field-order-mismatch",
        source: r#"
(module main)

(struct Point
  (x i32)
  (y i32))

(fn main () -> i32
  (. (Point (y 2) (x 1)) x))
"#,
        snapshot: "../tests/struct-field-order-mismatch.diag",
    },
    DiagnosticCase {
        name: "duplicate-struct-constructor-field",
        source: r#"
(module main)

(struct Point
  (x i32))

(fn main () -> i32
  (. (Point (x 1) (x 2)) x))
"#,
        snapshot: "../tests/duplicate-struct-constructor-field.diag",
    },
    DiagnosticCase {
        name: "field-access-on-non-struct",
        source: r#"
(module main)

(fn main () -> i32
  (. 1 x))
"#,
        snapshot: "../tests/field-access-on-non-struct.diag",
    },
    DiagnosticCase {
        name: "unknown-struct-local",
        source: r#"
(module main)

(fn main () -> i32
  (let value Missing 0)
  0)
"#,
        snapshot: "../tests/unknown-struct-local.diag",
    },
    DiagnosticCase {
        name: "unsupported-struct-field-mutation",
        source: r#"
(module main)

(struct Point
  (x i32))

(fn main () -> i32
  (let p Point (Point (x 1)))
  (set (. p x) 2)
  (. p x))
"#,
        snapshot: "../tests/unsupported-struct-field-mutation.diag",
    },
    DiagnosticCase {
        name: "duplicate-local",
        source: r#"
(module main)

(fn main () -> i32
  (let x i32 1)
  (var x i32 2)
  x)
"#,
        snapshot: "../tests/duplicate-local.diag",
    },
    DiagnosticCase {
        name: "local-redeclares-parameter",
        source: r#"
(module main)

(fn id ((value i32)) -> i32
  (let value i32 1)
  value)
"#,
        snapshot: "../tests/local-redeclares-parameter.diag",
    },
    DiagnosticCase {
        name: "local-shadows-function",
        source: r#"
(module main)

(fn helper () -> i32
  1)

(fn main () -> i32
  (let helper i32 2)
  helper)
"#,
        snapshot: "../tests/local-shadows-function.diag",
    },
    DiagnosticCase {
        name: "local-shadows-intrinsic",
        source: r#"
(module main)

(fn main () -> i32
  (let print_i32 i32 1)
  print_i32)
"#,
        snapshot: "../tests/local-shadows-intrinsic.diag",
    },
    DiagnosticCase {
        name: "unsupported-local-type",
        source: r#"
(module main)

(fn main () -> i32
  (let ignored unit (print_i32 1))
  0)
"#,
        snapshot: "../tests/unsupported-local-type.diag",
    },
    DiagnosticCase {
        name: "single-file-main-i64-return",
        source: r#"
(module main)

(fn main () -> i64
  1i64)
"#,
        snapshot: "../tests/single-file-main-i64-return.diag",
    },
    DiagnosticCase {
        name: "set-unknown-local",
        source: r#"
(module main)

(fn main () -> i32
  (set missing 1)
  0)
"#,
        snapshot: "../tests/set-unknown-local.diag",
    },
    DiagnosticCase {
        name: "set-parameter",
        source: r#"
(module main)

(fn id ((value i32)) -> i32
  (set value 1)
  value)
"#,
        snapshot: "../tests/set-parameter.diag",
    },
    DiagnosticCase {
        name: "set-immutable-local",
        source: r#"
(module main)

(fn main () -> i32
  (let x i32 1)
  (set x 2)
  x)
"#,
        snapshot: "../tests/set-immutable-local.diag",
    },
    DiagnosticCase {
        name: "set-type-mismatch",
        source: r#"
(module main)

(fn main () -> i32
  (var x i32 1)
  (set x true)
  x)
"#,
        snapshot: "../tests/set-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "nested-local-declaration",
        source: r#"
(module main)

(fn main () -> i32
  (+ (let x i32 1) 2))
"#,
        snapshot: "../tests/nested-local-declaration.diag",
    },
    DiagnosticCase {
        name: "malformed-if",
        source: r#"
(module main)

(fn main () -> i32
  (if true 1)
)
"#,
        snapshot: "../tests/malformed-if.diag",
    },
    DiagnosticCase {
        name: "if-condition-not-bool",
        source: r#"
(module main)

(fn main () -> i32
  (if 1 2 3))
"#,
        snapshot: "../tests/if-condition-not-bool.diag",
    },
    DiagnosticCase {
        name: "if-branch-type-mismatch",
        source: r#"
(module main)

(fn main () -> i32
  (if true 1 false))
"#,
        snapshot: "../tests/if-branch-type-mismatch.diag",
    },
    DiagnosticCase {
        name: "malformed-while",
        source: r#"
(module main)

(fn main () -> i32
  (while)
  0)
"#,
        snapshot: "../tests/malformed-while.diag",
    },
    DiagnosticCase {
        name: "empty-while-body",
        source: r#"
(module main)

(fn main () -> i32
  (while true)
  0)
"#,
        snapshot: "../tests/empty-while-body.diag",
    },
    DiagnosticCase {
        name: "while-condition-not-bool",
        source: r#"
(module main)

(fn main () -> i32
  (while 1
    (print_i32 1))
  0)
"#,
        snapshot: "../tests/while-condition-not-bool.diag",
    },
    DiagnosticCase {
        name: "while-body-local",
        source: r#"
(module main)

(fn main () -> i32
  (while true
    (let x i32 1))
  0)
"#,
        snapshot: "../tests/while-body-local.diag",
    },
    DiagnosticCase {
        name: "while-body-non-unit",
        source: r#"
(module main)

(fn main () -> i32
  (while true
    1)
  0)
"#,
        snapshot: "../tests/while-body-non-unit.diag",
    },
    DiagnosticCase {
        name: "nested-while",
        source: r#"
(module main)

(fn main () -> i32
  (while true
    (while false
      (print_i32 1)))
  0)
"#,
        snapshot: "../tests/nested-while.diag",
    },
    DiagnosticCase {
        name: "while-final-function",
        source: r#"
(module main)

(fn main () -> i32
  (while false
    (print_i32 1))
)
"#,
        snapshot: "../tests/while-final-function.diag",
    },
    DiagnosticCase {
        name: "while-final-test",
        source: r#"
(module main)

(test "loop final"
  (var i i32 0)
  (while false
    (set i 1)))
"#,
        snapshot: "../tests/while-final-test.diag",
    },
];

#[test]
fn current_negative_cases_match_machine_diagnostic_snapshots() {
    for case in CASES {
        let output = run_compiler(case.name, case.source);
        let stdout = String::from_utf8_lossy(&output.stdout);
        let stderr = String::from_utf8_lossy(&output.stderr);

        assert!(
            !output.status.success(),
            "compiler unexpectedly accepted fixture `{}`\nstdout:\n{}\nstderr:\n{}",
            case.name,
            stdout,
            stderr,
        );
        assert!(
            stdout.is_empty(),
            "compiler emitted stdout for rejected fixture `{}`\nstdout:\n{}\nstderr:\n{}",
            case.name,
            stdout,
            stderr,
        );

        let actual = normalize_fixture_path(&machine_diagnostic(&stderr));
        let expected = fs::read_to_string(case.snapshot)
            .unwrap_or_else(|err| panic!("read `{}`: {}", case.snapshot, err));

        assert_eq!(
            expected, actual,
            "machine diagnostic snapshot mismatch for `{}`",
            case.name
        );
    }
}

struct DiagnosticCase {
    name: &'static str,
    source: &'static str,
    snapshot: &'static str,
}

fn run_compiler(name: &str, source: &str) -> Output {
    let compiler = env!("CARGO_BIN_EXE_glagol");
    let fixture = write_fixture(name, source);

    Command::new(compiler)
        .arg(&fixture)
        .output()
        .unwrap_or_else(|err| panic!("run glagol on `{}`: {}", fixture.display(), err))
}

fn write_fixture(name: &str, source: &str) -> PathBuf {
    let mut path = std::env::temp_dir();
    let id = NEXT_FIXTURE_ID.fetch_add(1, Ordering::Relaxed);
    path.push(format!(
        "glagol-diagnostics-contract-{}-{}-{}.slo",
        std::process::id(),
        id,
        name
    ));
    fs::write(&path, source).unwrap_or_else(|err| panic!("write `{}`: {}", path.display(), err));
    path
}

fn machine_diagnostic(stderr: &str) -> String {
    let mut diagnostics = Vec::new();
    let mut current = Vec::new();
    let mut in_machine_diagnostic = false;
    let mut depth = 0;

    for line in stderr.lines() {
        if line == "(diagnostic" {
            in_machine_diagnostic = true;
            current.clear();
            depth = 0;
        }

        if in_machine_diagnostic {
            current.push(line);
            depth += paren_delta(line);
        }

        if in_machine_diagnostic && depth == 0 {
            diagnostics.push(current.join("\n"));
            current.clear();
            in_machine_diagnostic = false;
        }
    }

    assert!(
        !diagnostics.is_empty(),
        "stderr did not contain a machine diagnostic:\n{}",
        stderr
    );

    diagnostics.join("\n\n") + "\n"
}

fn paren_delta(line: &str) -> isize {
    let mut delta = 0;
    let mut in_string = false;
    let mut escaped = false;

    for ch in line.chars() {
        if in_string {
            if escaped {
                escaped = false;
            } else if ch == '\\' {
                escaped = true;
            } else if ch == '"' {
                in_string = false;
            }
        } else if ch == '"' {
            in_string = true;
        } else if ch == '(' {
            delta += 1;
        } else if ch == ')' {
            delta -= 1;
        }
    }

    delta
}

fn normalize_fixture_path(diagnostic: &str) -> String {
    diagnostic
        .lines()
        .map(|line| {
            let trimmed = line.trim_start();
            if trimmed.starts_with("(file ") {
                format!(
                    "{}(file \"<fixture>\")",
                    " ".repeat(line.len() - trimmed.len())
                )
            } else {
                line.to_string()
            }
        })
        .collect::<Vec<_>>()
        .join("\n")
        + "\n"
}
