//! mir.1b producer pin: `Subst::apply` must preserve fn-type modes.
//!
//! The typed-MIR boundary carries the modes `check` proved. The
//! codegen drop path reads `ret_mode == Own` off a call's callee node
//! to decide RC trackability — an Own-returning call hands a fresh heap
//! allocation to the caller's frame, so the binder needs an
//! `ailang_rc_dec` at scope close. `Subst::apply` is the last transform
//! `lower_to_mir::synth_pure` runs on every node type, so an `apply`
//! that rebuilds `Type::Fn` with empty `param_modes` / `Implicit`
//! `ret_mode` silently erases the Own signal: the callee node reads
//! back `Implicit`, nothing is trackable, and a heap-`Str` binder leaks
//! (`frees=0`). This pins that `apply` is mode-preserving — a
//! type-preserving substitution must not drop the modes that are part
//! of a fn type's identity.

use ailang_core::ast::ParamMode;
use ailang_core::Type;
use ailang_check::Subst;

#[test]
fn subst_apply_preserves_fn_ret_and_param_modes() {
    // `(borrow Int) -> (own Str)` — an identity substitution must
    // round-trip both the borrow param-mode and the Own ret-mode
    // unchanged. (`Own` is the mode the drop path actually reads;
    // `Borrow` is the one the custom `Type` equality keeps distinct,
    // so it doubles as a witness that a stripped result is observable.)
    let fn_ty = Type::Fn {
        params: vec![Type::int()],
        param_modes: vec![ParamMode::Borrow],
        ret: Box::new(Type::str_()),
        ret_mode: ParamMode::Own,
        effects: vec![],
    };

    let applied = Subst::default().apply(&fn_ty);

    let Type::Fn {
        param_modes,
        ret_mode,
        ..
    } = applied
    else {
        panic!("apply of a Fn type is a Fn type");
    };

    assert!(
        matches!(ret_mode, ParamMode::Own),
        "ret_mode Own must survive Subst::apply (the drop path reads it \
         for RC trackability), got {ret_mode:?}"
    );
    assert_eq!(
        param_modes.first(),
        Some(&ParamMode::Borrow),
        "param_modes must survive Subst::apply, got {param_modes:?}"
    );
}
