Lines
100 %
Functions
Branches
use crate::ast::{Expr, PairElement, WasmType};
use super::infer::{chain_pair_element, infer_pair_element};
fn int(n: i64) -> Expr {
Expr::Number(crate::ast::Fraction::from_integer(n))
}
#[test]
fn chain_of_integer_literals_is_an_index_chain() {
assert_eq!(
chain_pair_element(&[int(1), int(2)]).unwrap(),
PairElement::I32
);
fn chain_integer_literals_cross_to_a_ratio_neighbor() {
let half = Expr::Number(crate::ast::Fraction::new(1, 2));
chain_pair_element(&[half, int(3)]).unwrap(),
PairElement::Ratio
chain_pair_element(&[Expr::WasmRuntime(WasmType::Ratio), int(3)]).unwrap(),
fn chain_integer_literal_beyond_i31_takes_a_ratio_cell() {
for big in [1 << 30, i64::from(i32::MAX), -(1 << 30) - 1] {
chain_pair_element(&[int(big), int(2)]).unwrap(),
PairElement::Ratio,
"literal {big}"
chain_pair_element(&[int(big), Expr::WasmRuntime(WasmType::I32)]).unwrap(),
PairElement::AnyRef,
"literal {big} beside a runtime index"
chain_pair_element(&[int((1 << 30) - 1), int(-(1 << 30))]).unwrap(),
fn chain_of_bool_and_nil_uses_bool() {
chain_pair_element(&[Expr::T, Expr::Nil]).unwrap(),
PairElement::Bool
fn chain_integer_literal_adopts_runtime_index_on_either_side() {
let index = Expr::WasmRuntime(WasmType::I32);
chain_pair_element(&[index.clone(), int(2)]).unwrap(),
chain_pair_element(&[int(2), index]).unwrap(),
fn chain_literal_tail_disagreeing_with_runtime_head_widens_to_anyref() {
let scalar = Expr::WasmRuntime(WasmType::Ratio);
chain_pair_element(&[scalar, Expr::String("a".to_string())]).unwrap(),
PairElement::AnyRef
fn chain_integer_literal_against_non_numeric_slot_widens_to_anyref() {
chain_pair_element(&[int(1), Expr::Nil]).unwrap(),
chain_pair_element(&[Expr::String("a".to_string()), int(1)]).unwrap(),
fn chain_fractional_literal_against_runtime_index_widens_to_anyref() {
chain_pair_element(&[Expr::WasmRuntime(WasmType::I32), half]).unwrap(),
fn chain_of_unrepresentable_datum_or_nothing_uses_anyref() {
assert_eq!(chain_pair_element(&[]).unwrap(), PairElement::AnyRef);
chain_pair_element(&[Expr::Symbol("A".to_string())]).unwrap(),
fn chain_rejects_runtime_element_that_cannot_ride_a_pair_cell() {
let nested = Expr::WasmRuntime(WasmType::PairRef(PairElement::I32));
assert!(chain_pair_element(&[nested]).is_err());
/// `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.
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_is_an_index_cell() {
let elem = infer_pair_element(&int(1), &Expr::Nil).unwrap();
assert_eq!(elem, PairElement::I32);
fn integer_number_car_adopts_a_ratio_cdr() {
infer_pair_element(&int(1), &cdr).unwrap(),
fn nil_car_takes_the_bool_slot_and_widens() {
let index_cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::I32));
infer_pair_element(&Expr::Nil, &index_cdr).unwrap(),
let bool_cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::Bool));
infer_pair_element(&Expr::Nil, &bool_cdr).unwrap(),
fn runtime_car_unifies_with_quoted_list_cdr_members() {
let quoted = |members: Vec<Expr>| Expr::Quote(Box::new(Expr::List(members)));
infer_pair_element(&index, "ed(vec![int(1), int(2)])).unwrap(),
infer_pair_element(&index, "ed(vec![Expr::Nil])).unwrap(),
fn constant_car_without_slot_adopts_typed_cdr_or_is_rejected() {
let symbol = Expr::Quote(Box::new(Expr::Symbol("A".to_string())));
let cdr = Expr::WasmRuntime(WasmType::PairRef(PairElement::StringRef));
infer_pair_element(&symbol, &cdr).unwrap(),
PairElement::StringRef
assert!(infer_pair_element(&symbol, &Expr::Nil).is_err());
fn runtime_car_that_cannot_ride_a_cell_is_rejected() {
assert!(infer_pair_element(&nested, &Expr::Nil).is_err());
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::T;
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() {
fn anyref_widen_is_symmetric_and_idempotent() {
PairElement::I32.widen(PairElement::Ratio),
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)