//! Pin: the codegen mechanism that emits primitive Eq/Ord
//! instance bodies (try_emit_primitive_instance_body) MUST
//! attach an `alwaysinline` attribute to the generated LLVM
//! function definition so the `-O0` build path inlines the
//! single-instruction body at every use site, matching the IR
//! shape the deleted `lower_eq` direct-emit produced. Without
//! `alwaysinline`, `ail run` (which defaults to -O0) pays a
//! function-call overhead per comparison.

use std::path::PathBuf;
use std::process::Command;

#[test]
fn prelude_eq_int_carries_alwaysinline_attribute_in_emitted_ir() {
    let manifest_dir = env!("CARGO_MANIFEST_DIR");
    let repo_root = PathBuf::from(manifest_dir).join("../..");
    // Use a fixture that invokes the class-method `eq` path so
    // `prelude.eq__Int` gets monomorphised into the emitted IR.
    // `eq_ord_user_adt.ail` calls `(app eq …)` on an IntBox whose
    // user instance body internally calls `(app eq ai bi)` on Int —
    // class-dispatch resolves both the outer (Eq IntBox) and inner
    // (Eq Int) calls. The inner Eq Int path is the one we pin here:
    // its `define i1 @ail_prelude_eq__Int(...) alwaysinline { ... }`
    // must carry `alwaysinline` so the call folds to a single
    // `icmp eq i64` at every use site under -O0.
    let fixture = repo_root.join("examples/eq_ord_user_adt.ail");

    let out = Command::new(env!("CARGO_BIN_EXE_ail"))
        .arg("emit-ir")
        .arg(&fixture)
        .output()
        .expect("ail emit-ir failed to spawn");
    assert!(
        out.status.success(),
        "ail emit-ir failed: stderr={}",
        String::from_utf8_lossy(&out.stderr)
    );

    let ir = String::from_utf8_lossy(&out.stdout);
    // Either form is acceptable:
    //   define i1 @ail_prelude_eq__Int(i64, i64) alwaysinline { ... }
    // (attribute appended to the define line). The grep checks for
    // both the symbol presence and the alwaysinline annotation in
    // the same line as the define.
    let saw_define_with_alwaysinline = ir
        .lines()
        .any(|line| line.contains("define") && line.contains("eq__Int") && line.contains("alwaysinline"));
    assert!(
        saw_define_with_alwaysinline,
        "expected `define … eq__Int … alwaysinline` in emitted IR; full IR follows:\n{ir}"
    );
}
