lsts 0.6.34

Large Scale Type Systems
Documentation
use lsts::typ::*;
use lsts::constant::Constant;

#[test]
fn check_structural_equality() {
   let tany = Type::Any;
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tn3  = Type::Named("Cc".to_string(),vec![tn1.clone(),tn2.clone()]);
   let td1  = Type::And(vec![]);
   let td2  = Type::And(vec![tn1.clone()]);
   let td3  = Type::And(vec![tn1.clone(),tn2.clone(),tn3.clone()]);
   let ta1  = Type::Arrow(Box::new(tn1.clone()), Box::new(tn2.clone()));
   let tt1  = Type::Tuple(vec![tn1.clone(),ta1.clone()]);
   let tp1  = Type::Product(vec![tn1.clone(),ta1.clone()]);
   let tr1  = Type::Ratio(Box::new(tt1.clone()),Box::new(tp1.clone()));
   let tc1  = Type::Constant(Constant::Literal("1".to_string()));
   let tc2  = Type::Constant(Constant::Literal("2".to_string()));
   assert_eq!(tany, tany);
   assert_eq!(tn1, tn1);
   assert_eq!(tn2, tn2);
   assert_eq!(tn3, tn3);
   assert_eq!(td1, td1);
   assert_eq!(td2, td2);
   assert_eq!(td3, td3);
   assert_eq!(ta1, ta1);
   assert_eq!(tt1, tt1);
   assert_eq!(tp1, tp1);
   assert_eq!(tr1, tr1);
   assert_eq!(tc1, tc1);
   assert_eq!(tc2, tc2);

   assert_ne!(tany, tn1);
   assert_ne!(tn1, tn2);
   assert_ne!(tn2, tn3);
   assert_ne!(tn3, td1);
   assert_ne!(td1, td2);
   assert_ne!(td2, td3);
   assert_ne!(td3, ta1);
   assert_ne!(ta1, tt1);
   assert_ne!(tt1, tp1);
   assert_ne!(tp1, tr1);
   assert_ne!(tr1, tc1);
   assert_ne!(tc1, tc2);
   assert_ne!(tc2, tany);
}

#[test]
fn check_self_unifies() {
   let tany = Type::Any;
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tn3  = Type::Named("Cc".to_string(),vec![tn1.clone(),tn2.clone()]);
   let td1  = Type::And(vec![]);
   let td2  = Type::And(vec![tn1.clone()]);
   let td3  = Type::And(vec![tn1.clone(),tn2.clone(),tn3.clone()]);
   let ta1  = Type::Arrow(Box::new(tn1.clone()), Box::new(tn2.clone()));
   let tt1  = Type::Tuple(vec![tn1.clone(),ta1.clone()]);
   let tp1  = Type::Product(vec![tn1.clone(),ta1.clone()]);
   let tr1  = Type::Ratio(Box::new(tt1.clone()),Box::new(tp1.clone()));
   let tc1  = Type::Constant(Constant::Literal("1".to_string()));
   let tc2  = Type::Constant(Constant::Literal("2".to_string()));
   assert_eq!(tany, tany.implication_unifier(&tany));
   assert_eq!(tn1, tn1.implication_unifier(&tn1));
   assert_eq!(tn2, tn2.implication_unifier(&tn2));
   assert_eq!(tn3, tn3.implication_unifier(&tn3));
   assert_eq!(td1, td1.implication_unifier(&td1));
   assert_eq!(tn1, td2.implication_unifier(&td2));
   assert_eq!(td3, td3.implication_unifier(&td3));
   assert_eq!(ta1, ta1.implication_unifier(&ta1));
   assert_eq!(tt1, tt1.implication_unifier(&tt1));
   assert_eq!(tp1, tp1.implication_unifier(&tp1));
   assert_eq!(tr1, tr1.implication_unifier(&tr1));
   assert_eq!(tc1, tc1.implication_unifier(&tc1));
   assert_eq!(tc2, tc2.implication_unifier(&tc2));
}

#[test]
fn check_compound_failures() {
   let tb   = Type::And(vec![]);
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let ta1  = Type::Arrow(Box::new(tn1.clone()), Box::new(tn1.clone()));
   let ta2  = Type::Arrow(Box::new(tn1.clone()), Box::new(tn2.clone()));
   let ta3  = Type::Arrow(Box::new(tn2.clone()), Box::new(tn1.clone()));
   let tt1  = Type::Tuple(vec![]);
   let tt2  = Type::Tuple(vec![tn1.clone()]);
   let tt3  = Type::Tuple(vec![tn2.clone()]);
   let tt4  = Type::Tuple(vec![tn1.clone(),tn2.clone()]);
   let tp1  = Type::Product(vec![]);
   let tp2  = Type::Product(vec![tn1.clone()]);
   let tp3  = Type::Product(vec![tn2.clone()]);
   let tp4  = Type::Product(vec![tn1.clone(),tn2.clone()]);
   let tr1  = Type::Ratio(Box::new(tn1.clone()), Box::new(tn1.clone()));
   let tr2  = Type::Ratio(Box::new(tn1.clone()), Box::new(tn2.clone()));
   let tr3  = Type::Ratio(Box::new(tn2.clone()), Box::new(tn1.clone()));
   assert_eq!(ta1.implication_unifier(&ta2), tb.clone());
   assert_eq!(ta1.implication_unifier(&ta3), tb.clone());

   assert_eq!(tt1.implication_unifier(&tt2), tb.clone());
   assert_eq!(tt2.implication_unifier(&tt3), tb.clone());
   assert_eq!(tt2.implication_unifier(&tt4), tb.clone());

   assert_eq!(tp1.implication_unifier(&tp2), tb.clone());
   assert_eq!(tp2.implication_unifier(&tp3), tb.clone());
   assert_eq!(tp2.implication_unifier(&tp4), tb.clone());

   assert_eq!(tr1.implication_unifier(&tr2), tb.clone());
   assert_eq!(tr1.implication_unifier(&tr3), tb.clone());
}

#[test]
fn check_simplytyped() {
   let tb   = Type::And(vec![]);
   let tany = Type::Any;
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let ta1  = Type::Arrow(Box::new(tn1.clone()), Box::new(tn2.clone()));
   let ta2  = Type::Arrow(Box::new(tn1.clone()), Box::new(tany.clone()));
   let ta3  = Type::Arrow(Box::new(tn2.clone()), Box::new(tany.clone()));
   assert_eq!(ta1, ta1.implication_unifier(&ta2));
   assert_eq!(tb, ta1.implication_unifier(&ta3));
}

#[test]
fn check_normalization() {
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tn3  = Type::Named("Cc".to_string(),vec![]);
   let tp1  = Type::Product(vec![tn1.clone(),tn2.clone()]);
   let tp2  = Type::Product(vec![tn2.clone(),tn1.clone()]);
   let ts1  = Type::And(vec![tn3.clone(),tp1.clone()]);
   let ts2  = Type::And(vec![tp2.clone(),tn3.clone()]);
   assert_eq!(ts1.normalize(), ts1.normalize().implication_unifier(&ts2.normalize()));

   //{(Cd*Bc)+Ab} = {Ab+(Bc*Cd)}
   let tp3  = Type::Product(vec![tn3.clone(),tn2.clone()]);
   let tp4  = Type::Product(vec![tn2.clone(),tn3.clone()]);
   let ts3  = Type::And(vec![tp3.clone(),tn1.clone()]);
   let ts4  = Type::And(vec![tn1.clone(),tp4.clone()]);
   assert_eq!(ts3.normalize(), ts4.normalize());
}

#[test]
fn check_subtyping() {
   let td   = Type::And(vec![]);
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tn3  = Type::Named("Cc".to_string(),vec![]);
   let ts1  = Type::And(vec![tn1.clone(),tn2.clone()]);
   let ts2  = Type::And(vec![tn1.clone(),tn2.clone(),tn3.clone()]);
   assert_eq!(tn1, ts1.implication_unifier(&tn1));
   assert_eq!(tn2, ts1.implication_unifier(&tn2));
   assert_eq!(td, ts1.implication_unifier(&tn3));
   assert_eq!(td, tn1.implication_unifier(&ts1));
   assert_eq!(td, tn2.implication_unifier(&ts1));
   assert_eq!(td, tn3.implication_unifier(&ts1));
   assert_eq!(ts1, ts2.implication_unifier(&ts1));
   assert_eq!(td, ts1.implication_unifier(&ts2));
}

#[test]
fn check_parameters_subtyping() {
   let td   = Type::And(vec![]);
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tn3  = Type::Named("Cc".to_string(),vec![ tn1.clone() ]);
   let tn4  = Type::Named("Cc".to_string(),vec![ Type::And(vec![tn1.clone(),tn2.clone()]) ]);
   assert_eq!(tn3, tn3.implication_unifier(&tn3));
   assert_eq!(tn3, tn4.implication_unifier(&tn3));
   assert_eq!(td, tn3.implication_unifier(&tn4));
}

#[test]
fn check_compound_subtyping() {
   let td   = Type::And(vec![]);
   let tnil = Type::Tuple(vec![]);
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let ts1  = Type::And(vec![tn1.clone(),tn2.clone()]);

   let ta1  = Type::Arrow(Box::new(tn1.clone()), Box::new(tn1.clone()));
   let ta2  = Type::Arrow(Box::new(ts1.clone()), Box::new(tn1.clone()));
   let ta3  = Type::Arrow(Box::new(tn1.clone()), Box::new(ts1.clone()));
   assert_eq!(ta1, ta1.implication_unifier(&ta1));
   assert_eq!(td, ta2.implication_unifier(&ta1));  //contravariance
   assert_eq!(ta1, ta3.implication_unifier(&ta1));
   assert_eq!(ta1, ta1.implication_unifier(&ta2)); //contravariance
   assert_eq!(td, ta1.implication_unifier(&ta3));

   let tt1  = Type::Tuple(vec![tn1.clone(), tn1.clone()]);
   let tt2  = Type::Tuple(vec![ts1.clone(), tn1.clone()]);
   let tt3  = Type::Tuple(vec![tn1.clone(), ts1.clone()]);
   assert_eq!(tt1, tt1.implication_unifier(&tt1));
   assert_eq!(tt1, tt2.implication_unifier(&tt1));
   assert_eq!(tt1, tt3.implication_unifier(&tt1));
   assert_eq!(td, tt1.implication_unifier(&tt2));
   assert_eq!(td, tt1.implication_unifier(&tt3));

   let tp1  = Type::Product(vec![tn1.clone(), tn1.clone()]);
   let tp2  = Type::Product(vec![ts1.clone(), tn1.clone()]);
   let tp3  = Type::Product(vec![tn1.clone(), ts1.clone()]);
   assert_eq!(tp1, tp1.implication_unifier(&tp1));
   assert_eq!(tp1, tp2.implication_unifier(&tp1));
   assert_eq!(tp1, tp3.implication_unifier(&tp1));
   assert_eq!(td, tp1.implication_unifier(&tp2));
   assert_eq!(td, tp1.implication_unifier(&tp3));

   let tr1  = Type::Ratio(Box::new(tn1.clone()), Box::new(tn1.clone()));
   let tr2  = Type::Ratio(Box::new(ts1.clone()), Box::new(tn1.clone()));
   let tr3  = Type::Ratio(Box::new(tn1.clone()), Box::new(ts1.clone()));
   assert_eq!(tnil, tr1.implication_unifier(&tr1));
   assert_eq!(tnil, tr2.implication_unifier(&tr1));
   assert_eq!(tnil, tr3.implication_unifier(&tr1));
   assert_eq!(td, tr1.implication_unifier(&tr2));
   assert_eq!(td, tr1.implication_unifier(&tr3));
}

#[test]
fn check_products_and_ratios() {
   let td   = Type::And(vec![]);
   let tany = Type::Any;
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tp1  = Type::Product(vec![ tn1.clone(), tn1.clone() ]);
   let tp2  = Type::Product(vec![ tn1.clone(), tn2.clone() ]);
   let tt1  = Type::Tuple(vec![]);
   let tr1  = Type::Ratio( Box::new(tp1.clone()), Box::new(tt1.clone()) );
   let tr2  = Type::Ratio( Box::new(tp1.clone()), Box::new(tn1.clone()) );
   let tr3  = Type::Ratio( Box::new(tn1.clone()), Box::new(tn1.clone()) );
   let tr4  = Type::Ratio( Box::new(tt1.clone()), Box::new(tn1.clone()) );
   let tr5  = Type::Ratio( Box::new(tany.clone()), Box::new(tn1.clone()) );

   assert_eq!(tp1.normalize(), tp1.normalize().implication_unifier(&tp1));
   assert_eq!(tp1.normalize(), tp1.normalize().implication_unifier(&tany));
   assert_eq!(tp2.normalize(), tp2.normalize().implication_unifier(&tp2));
   assert_eq!(tp2.normalize(), tp2.normalize().implication_unifier(&tany));

   assert_eq!(tp1.normalize(), tp1.normalize().implication_unifier(&tr1));

   assert_eq!(td, tp1.normalize().implication_unifier(&tn1));
   assert_eq!(td, tp2.normalize().implication_unifier(&tn1));

   assert_eq!(tn1, tr2.normalize());
   assert_eq!(tn1, tr2.normalize().implication_unifier(&tn1));

   assert_eq!(tt1, tr3.normalize());
   assert_eq!(tt1, tr3.normalize().implication_unifier(&tt1));

   assert_eq!(tr4, tr4.normalize());
   assert_eq!(tr4, tr4.normalize().implication_unifier(&tr4));

   assert_eq!(td, tr3.normalize().implication_unifier(&tr5));
}

#[test]
fn check_parameter_unification() {
   let td   = Type::And(vec![]);
   let tn1  = Type::Named("Aa".to_string(),vec![]);
   let tn2  = Type::Named("Bb".to_string(),vec![]);
   let tn3  = Type::Named("Cc".to_string(),vec![]);
   let tn4  = Type::Named("X".to_string(),vec![]);

   let tt1  = Type::Tuple(vec![tn1.clone(), tn1.clone()]);
   let tt2  = Type::Tuple(vec![tn1.clone(), tn2.clone()]);
   let tt3  = Type::Tuple(vec![tn4.clone(), tn4.clone()]);

   let ts1  = Type::And(vec![tn1.clone(), tn2.clone()]);
   let ts2  = Type::And(vec![tn1.clone(), tn2.clone(), tn3.clone()]);
   let ts3  = Type::And(vec![tn1.clone(), tn3.clone()]);
   let ts4  = Type::And(vec![tn2.clone(), tn3.clone()]);

   let tt4  = Type::Tuple(vec![ts1.clone(), ts1.clone()]);
   let tt5  = Type::Tuple(vec![ts1.clone(), ts3.clone()]);

   let ta1  = Type::Arrow( Box::new(tt1.clone()), Box::new(tn1.clone()) );
   let ta2  = Type::Arrow( Box::new(tt1.clone()), Box::new(tn3.clone()) );
   let ta3  = Type::Arrow( Box::new(tt2.clone()), Box::new(tn3.clone()) );
   let ta4  = Type::Arrow( Box::new(tt3.clone()), Box::new(tn4.clone()) );
   assert_eq!(ta1, ta1.implication_unifier(&ta4));
   assert_eq!(td,  ta2.implication_unifier(&ta4));
   assert_eq!(td,  ta3.implication_unifier(&ta4));

   let ta5  = Type::Arrow( Box::new(tt4.clone()), Box::new(ts2.clone()) );
   let ta6  = Type::Arrow( Box::new(tt5.clone()), Box::new(ts2.clone()) );
   let ta7  = Type::Arrow( Box::new(tt5.clone()), Box::new(ts4.clone()) );
   let ta8  = Type::Arrow( Box::new(tt4.clone()), Box::new(ts1.clone()) );
   assert_eq!(ta8, ta5.implication_unifier(&ta4));
   assert_eq!(ta1, ta6.implication_unifier(&ta4));
   assert_eq!(td,  ta7.implication_unifier(&ta4));
}

#[test]
fn check_function_unification() {
   let tany = Type::Any;
   let tn1  = Type::Named("Integer".to_string(),vec![]);
   let tn2  = Type::Named("Number".to_string(),vec![]);
   let tn3  = Type::Named("Point2D".to_string(),vec![]);
   let tn4  = Type::Named("N".to_string(),vec![]);
   let tn5  = Type::Named("Point2D".to_string(),vec![ Type::And(vec![tn1.clone(), tn2.clone()]) ]);
   let tn6  = Type::Named("Point2D".to_string(),vec![ tn4.clone() ]);
   let ts1  = Type::And(vec![tn1.clone(), tn2.clone()]);
   let ts2  = Type::And(vec![tn3.clone(), tn5.clone()]);

   //Integer -> ? => N -> N = Integer -> Integer
   let ta1  = Type::Arrow( Box::new(tn1.clone()), Box::new(tany.clone()) );
   let ta2  = Type::Arrow( Box::new(tn4.clone()), Box::new(tn4.clone()) );
   let ta3  = Type::Arrow( Box::new(tn1.clone()), Box::new(tn1.clone()) );
   assert_eq!(ta3, ta1.implication_unifier(&ta2));

   //Point2D<{Integer+Number}> -> ? => Point2D<N> -> N = Point2D<{Integer+Number}> -> {Integer+Number}
   let ta4  = Type::Arrow( Box::new(tn5.clone()), Box::new(tany.clone()) );
   let ta5  = Type::Arrow( Box::new(tn6.clone()), Box::new(tn4.clone()) );
   let ta6  = Type::Arrow( Box::new(tn5.clone()), Box::new(ts1.clone()) );
   assert_eq!(ta6, ta4.implication_unifier(&ta5));

   //{Point2D+Point2D<{Integer+Number}>} -> ? => Point2D<N> -> N = Point2D<{Integer+Number}> -> {Integer+Number}
   let ta7  = Type::Arrow( Box::new(ts2.clone()), Box::new(tany.clone()) );
   let ta8  = Type::Arrow( Box::new(tn6.clone()), Box::new(tn4.clone()) );
   let ta9  = Type::Arrow( Box::new(tn5.clone()), Box::new(ts1.clone()) );
   assert_eq!(ta9, ta7.implication_unifier(&ta8));

}

#[test]
fn check_arrow_ratio() {
   let tany = Type::Any;
   let tn1  = Type::Named("Pt".to_string(),vec![]);
   let tn2  = Type::Named("Qt".to_string(),vec![]);
   let tn3  = Type::Named("X".to_string(),vec![]);
   let tr1  = Type::Ratio( Box::new(tn1.clone()), Box::new(tn2.clone()) );
   let tp1  = Type::Product(vec![ tn1.clone(), tn1.clone() ]); 
   let tp2  = Type::Product(vec![ tn2.clone(), tn2.clone() ]); 
   let tp3  = Type::Product(vec![ tn3.clone(), tn3.clone() ]); 
   let tr2  = Type::Ratio( Box::new(tp1.clone()), Box::new(tp2.clone()) );
   let ta1  = Type::Arrow( Box::new(tr1.clone()), Box::new(tany.clone()) );
   let ta2  = Type::Arrow( Box::new(tn3.clone()), Box::new(tp3.clone()) );
   let ta3  = Type::Arrow( Box::new(tr1.clone()), Box::new(tr2.clone()) );
   //Pt/Qt -> ? => X -> X*X = Pt/Qt -> Pt*Pt/Qt*Qt
   assert_eq!( ta3, ta1.implication_unifier(&ta2) );
}

#[test]
fn check_constant_arrows() {
   let tany = Type::Any;
   let tc1  = Type::Constant(Constant::Literal("1".to_string()));
   let tc2  = Type::Constant(Constant::Literal("2".to_string()));
   let tc3  = Type::Constant(Constant::Literal("3".to_string()));
   let tc4  = Type::Constant(Constant::Literal("4".to_string()));
   let ta1  = Type::Arrow( Box::new(tc1.clone()), Box::new(tany.clone()) );
   let ta2  = Type::Arrow( Box::new(tc1.clone()), Box::new(tc3.clone()) );
   assert_eq!( ta2, ta1.implication_unifier(&ta2) );

   let ts1  = Type::And(vec![ tc1.clone(), tc4.clone() ]);
   let ta3  = Type::Arrow( Box::new(ts1.clone()), Box::new(tany.clone()) );
   assert_eq!( ta2, ta3.implication_unifier(&ta2) );

   let tt1  = Type::Tuple(vec![ tc1.clone(), tc2.clone() ]);
   let tt2  = Type::Tuple(vec![ tc3.clone(), tc4.clone() ]);
   let ta4  = Type::Arrow( Box::new(tt1.clone()), Box::new(tt2.clone()) );
   assert_eq!( ta4, ta4.implication_unifier(&ta4) );
}