Lines
100 %
Functions
Branches
use crate::ast::{Expr, PairElement, WasmType};
use super::infer::infer_pair_element;
/// `infer_pair_element` decides the static PairElement from a
/// `(cons car cdr)` form, balancing the car's compile-time type
/// against the cdr's. The legacy integration test reached this
/// via `Symbol::new("BAL").with_value(Expr::WasmRuntime(Commodity))`
/// in the symbol table; the unit form exercises the function
/// directly so the contract is locked in without needing a
/// script-mode Commodity producer.
#[test]
fn commodity_car_with_nil_cdr_is_commodity_pair() {
let car = Expr::WasmRuntime(WasmType::Commodity);
let elem = infer_pair_element(&car, &Expr::Nil).unwrap();
assert_eq!(elem, PairElement::Commodity);
}
fn commodity_car_with_pair_of_i32_cdr_widens_to_anyref() {
// ADR-0025 escape hatch: when the car and cdr disagree on element
// type, CONS widens to `PairElement::AnyRef` (canonical Common Lisp
// heterogeneous `cons`) rather than rejecting. The strict typed path
// still applies when both arms agree.
let cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::I32));
let elem = infer_pair_element(&car, &cdr).expect("heterogeneous CONS widens to AnyRef");
assert_eq!(elem, PairElement::AnyRef);
fn ratio_car_with_pair_of_ratio_cdr_resolves_to_ratio_pair() {
let car = Expr::WasmRuntime(WasmType::Ratio);
let cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::Ratio));
let elem = infer_pair_element(&car, &cdr).unwrap();
assert_eq!(elem, PairElement::Ratio);
fn integer_number_car_with_nil_cdr_uses_ratio() {
// A numeric literal is a dimensionless Ratio in EVERY context, including a
// pair cell — never an I32 count. Reclassifying an integer literal as I32
// here would be an illegal implicit Ratio→count conversion: the `1` would
// come back from the list as a count and arithmetic would refuse it.
let car = Expr::Number(crate::ast::Fraction::from_integer(1));
fn fractional_number_car_with_nil_cdr_uses_ratio_default() {
let car = Expr::Number(crate::ast::Fraction::new(1, 2));
fn bool_car_with_nil_cdr_uses_bool_slot() {
// A bool literal car rides PairElement::Bool (not I32), so CAR recovers a
// truth value that serializes as Nil/Bool rather than Number.
let car = Expr::Bool(true);
assert_eq!(elem, PairElement::Bool);
fn string_car_with_nil_cdr_uses_stringref() {
let car = Expr::String("hi".to_string());
assert_eq!(elem, PairElement::StringRef);
fn anyref_cdr_propagates_anyref_pair_element() {
let cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::AnyRef));
let elem = infer_pair_element(&car, &cdr).expect("AnyRef cdr accepts any car");
fn ratio_car_with_pair_of_string_cdr_widens_to_anyref() {
let cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::StringRef));
fn anyref_widen_is_symmetric_and_idempotent() {
assert_eq!(
PairElement::I32.widen(PairElement::Ratio),
PairElement::AnyRef
);
PairElement::Ratio.widen(PairElement::I32),
PairElement::AnyRef.widen(PairElement::I32),
assert_eq!(PairElement::I32.widen(PairElement::I32), PairElement::I32);
fn literal_string_car_with_pair_of_ratio_cdr_widens_to_anyref() {
// Regression: before the literal-shape branch ran ahead of the
// cdr-element fallback, a literal String car with a typed Ratio
// cdr was silently classified as Ratio and erroried at codegen
// ("expected ratio, got string"). The widening contract says a
// disagreeing arm widens to AnyRef instead.
let car = Expr::String("label".to_string());
let elem = infer_pair_element(&car, &cdr).expect("literal car widens against typed cdr");
fn pair_element_anyref_round_trips_through_wasm_type() {
assert_eq!(PairElement::AnyRef.as_wasm_type(), WasmType::AnyRef);
PairElement::from_wasm_type(WasmType::AnyRef),
Some(PairElement::AnyRef)