1
//! Unit tests for the runtime-type inference used to promote the
2
//! body's tail value when a binding form has side effects. Each
3
//! variant must map to the wasm type the codegen path emits;
4
//! otherwise upstream consumers downcast to the wrong shape and the
5
//! wasm becomes invalid.
6

            
7
use crate::ast::{Expr, Fraction, WasmType};
8

            
9
use super::infer::infer_runtime_type;
10

            
11
/// `infer_runtime_type` is the fallback for promoting a let body's
12
/// tail value to a runtime type when the body has side-effects.
13
#[test]
14
1
fn infer_runtime_type_integer_is_index_fraction_is_scalar() {
15
    // ADR-0028: an integer literal defaults to Index (I32); a fractional
16
    // literal is a dimensionless Scalar (Ratio). Mirrors `classify_stack_type`.
17
1
    assert_eq!(
18
1
        infer_runtime_type(&Expr::Number(Fraction::from_integer(0))),
19
        WasmType::I32
20
    );
21
1
    assert_eq!(
22
1
        infer_runtime_type(&Expr::Number(Fraction::new(1, 2))),
23
        WasmType::Ratio
24
    );
25
1
}
26

            
27
#[test]
28
1
fn infer_runtime_type_bool_is_bool() {
29
    // Bool/nil literals lower to `WasmType::Bool` on the stack, so the let-body
30
    // tail inference must mirror that (sizing the binding local to match the
31
    // value codegen pushes — see the WasmType::Bool serialization split).
32
1
    assert_eq!(infer_runtime_type(&Expr::Bool(true)), WasmType::Bool);
33
1
    assert_eq!(infer_runtime_type(&Expr::Nil), WasmType::Bool);
34
1
}
35

            
36
/// A let body whose tail is a String literal must report
37
/// `StringRef`. The previous hardcoded `PairRef(I32)` fallback
38
/// made `(cons (let ...) nil)` see a pair-of-pair and refuse
39
/// at compile time.
40
#[test]
41
1
fn infer_runtime_type_string_is_stringref() {
42
1
    assert_eq!(
43
1
        infer_runtime_type(&Expr::String("hi".into())),
44
        WasmType::StringRef,
45
    );
46
1
}
47

            
48
/// `WasmLocal(idx, ty)` carries its wasm type directly. Promoting
49
/// must surface that type unchanged.
50
#[test]
51
1
fn infer_runtime_type_wasm_local_passes_type_through() {
52
1
    assert_eq!(
53
1
        infer_runtime_type(&Expr::WasmLocal(5, WasmType::Ratio)),
54
        WasmType::Ratio,
55
    );
56
1
    assert_eq!(
57
1
        infer_runtime_type(&Expr::WasmLocal(7, WasmType::StringRef)),
58
        WasmType::StringRef,
59
    );
60
1
}
61

            
62
/// `WasmRuntime(ty)` carries its wasm type directly. Same path
63
/// as `WasmLocal` from the inference perspective.
64
#[test]
65
1
fn infer_runtime_type_wasm_runtime_passes_type_through() {
66
1
    assert_eq!(
67
1
        infer_runtime_type(&Expr::WasmRuntime(WasmType::Commodity)),
68
        WasmType::Commodity,
69
    );
70
1
}