diff --git a/src/dict.rs b/src/dict.rs index e5cb464..d6636c4 100644 --- a/src/dict.rs +++ b/src/dict.rs @@ -25,11 +25,11 @@ pub trait TypeDict : Send + Sync { } } - fn get_typeid_creat(&mut self, tn: &String) -> TypeID { - if let Some(id) = self.get_typeid(tn) { + fn get_typeid_creat(&mut self, tn: &str) -> TypeID { + if let Some(id) = self.get_typeid(&tn.to_string()) { id } else { - self.add_typename(tn.clone()) + self.add_typename(tn.to_string()) } } } diff --git a/src/lib.rs b/src/lib.rs index 6c844a6..882082c 100644 --- a/src/lib.rs +++ b/src/lib.rs @@ -1,21 +1,37 @@ +#![allow(mixed_script_confusables)] pub mod bimap; pub mod dict; -pub mod term; -pub mod substitution; pub mod lexer; pub mod parser; pub mod unparser; -pub mod sugar; pub mod curry; -pub mod lnf; + +pub mod lnf; // deprecated +pub mod subtype; // deprecated + pub mod pnf; -pub mod subtype; +pub mod pnf_sugared; + +pub mod term; +pub mod sugar; + +pub mod substitution; +pub mod substitution_sugared; + pub mod unification; +pub mod unification_sugared; + pub mod morphism; +pub mod morphism_sugared; + pub mod morphism_base; +pub mod morphism_base_sugared; + pub mod morphism_path; +pub mod morphism_path_sugared; + pub mod steiner_tree; #[cfg(test)] diff --git a/src/morphism.rs b/src/morphism.rs index 69853f3..dc99b38 100644 --- a/src/morphism.rs +++ b/src/morphism.rs @@ -1,6 +1,13 @@ use { crate::{ - subtype_unify, sugar::SugaredTypeTerm, unification::UnificationProblem, unparser::*, TypeDict, TypeID, TypeTerm + pnf::splice_ladders, + substitution_sugared::SugaredSubstitution, + subtype_unify, + sugar::{SugaredStructMember, SugaredTypeTerm}, + unification::UnificationProblem, + unification_sugared::SugaredUnificationProblem, + unparser::*, + TypeDict, TypeID, TypeTerm }, std::{collections::HashMap, u64} }; @@ -11,11 +18,6 @@ use { pub struct MorphismType { pub src_type: TypeTerm, pub dst_type: TypeTerm, -/* - pub subtype_bounds: Vec< (TypeTerm, TypeTerm) >, - pub trait_bounds: Vec< (TypeTerm, TypeTerm) >, - pub equal_bounds: Vec< (TypeTerm, TypeTerm) >, -*/ } impl MorphismType { @@ -23,10 +25,6 @@ impl MorphismType { MorphismType { src_type: self.src_type.strip().param_normalize(), dst_type: self.dst_type.strip().param_normalize(), -/* - subtype_bounds: Vec::new(), - trait_bounds: Vec::new() - */ } } } @@ -65,12 +63,6 @@ impl<M: Morphism + Clone> MorphismInstance<M> { self.m.get_type().dst_type.clone() ]).apply_subst(&self.σ) .clone(), -/* - trait_bounds: Vec::new(), - subtype_bounds: Vec::new() - */ }.normalize() } } - -//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/morphism_base.rs b/src/morphism_base.rs index 91dcba0..f922046 100644 --- a/src/morphism_base.rs +++ b/src/morphism_base.rs @@ -1,9 +1,7 @@ use { crate::{ - subtype_unify, sugar::SugaredTypeTerm, unification::UnificationProblem, unparser::*, TypeDict, TypeID, TypeTerm, - morphism::{MorphismType, Morphism, MorphismInstance} - }, - std::{collections::HashMap, u64} + morphism::{Morphism, MorphismInstance, MorphismType}, morphism_path_sugared::SugaredShortestPathProblem, morphism_sugared::{MorphismInstance2, SugaredMorphismType}, subtype_unify, sugar::SugaredTypeTerm, unification::UnificationProblem, TypeDict, TypeID, TypeTerm + } }; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ @@ -101,29 +99,29 @@ impl<M: Morphism + Clone> MorphismBase<M> { ty: &MorphismType, dict: &mut impl TypeDict ) -> Option< MorphismInstance<M> > { - eprintln!("find direct morph"); + //eprintln!("find direct morph"); for m in self.morphisms.iter() { let ty = ty.clone().normalize(); let morph_type = m.get_type().normalize(); - + /* eprintln!("find direct morph:\n {} <= {}", dict.unparse(&ty.src_type), dict.unparse(&morph_type.src_type), ); - +*/ if let Ok((halo, σ)) = subtype_unify(&ty.src_type, &morph_type.src_type) { - eprintln!("halo: {}", dict.unparse(&halo)); + //eprintln!("halo: {}", dict.unparse(&halo)); let dst_type = TypeTerm::Ladder(vec![ halo.clone(), morph_type.dst_type.clone() ]).normalize().param_normalize(); - +/* eprintln!("-----------> {} <= {}", dict.unparse(&dst_type), dict.unparse(&ty.dst_type) ); - +*/ if let Ok((halo2, σ2)) = subtype_unify(&dst_type, &ty.dst_type) { - eprintln!("match. halo2 = {}", dict.unparse(&halo2)); + //eprintln!("match. halo2 = {}", dict.unparse(&halo2)); return Some(MorphismInstance { m: m.clone(), halo, diff --git a/src/morphism_base_sugared.rs b/src/morphism_base_sugared.rs new file mode 100644 index 0000000..1fb1dcf --- /dev/null +++ b/src/morphism_base_sugared.rs @@ -0,0 +1,143 @@ +use { + crate::{ + morphism_path_sugared::{SugaredMorphismPath, SugaredShortestPathProblem}, morphism_sugared::{MorphismInstance2, SugaredMorphism, SugaredMorphismType}, sugar::SugaredTypeTerm, SugaredStructMember, TypeDict, TypeID, TypeTerm + } +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +#[derive(Clone)] +pub struct SugaredMorphismBase<M: SugaredMorphism + Clone> { + morphisms: Vec< M > +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +impl<M: SugaredMorphism + Clone> SugaredMorphismBase<M> { + pub fn new() -> Self { + SugaredMorphismBase { + morphisms: Vec::new() + } + } + + pub fn add_morphism(&mut self, m: M) { + self.morphisms.push( m ); + } + + pub fn get_morphism_instance(&self, ty: &SugaredMorphismType) -> Option<MorphismInstance2<M>> { + if let Some(path) = SugaredShortestPathProblem::new(self, ty.clone()).solve() { + if path.len() == 1 { + Some(path[0].clone()) + } else { + Some(MorphismInstance2::Chain { path }) + } + } else { + None + } + } + + pub fn complex_morphism_decomposition(&self, src_type: &SugaredTypeTerm, dst_type: &SugaredTypeTerm) -> Option< MorphismInstance2<M> > { + let (src_ψ, src_floor) = src_type.get_floor_type(); + let (dst_ψ, dst_floor) = dst_type.get_floor_type(); + + if !dst_ψ.is_empty() { + if !crate::unification_sugared::subtype_unify(&src_ψ, &dst_ψ).is_ok() { + return None; + } + } + + match (src_floor, dst_floor) { + (SugaredTypeTerm::Struct{ struct_repr: struct_repr_lhs, members: members_lhs}, + SugaredTypeTerm::Struct { struct_repr: _struct_repr_rhs, members: members_rhs }) + => { + // todo: optimization: check if struct repr match + + let mut member_morph = Vec::new(); + let mut failed = false; + let mut necessary = false; + + for SugaredStructMember{ symbol: symbol_rhs, ty: ty_rhs } in members_rhs.iter() { + let mut found_src_member = false; + for SugaredStructMember{ symbol: symbol_lhs, ty: ty_lhs } in members_lhs.iter() { + if symbol_rhs == symbol_lhs { + found_src_member = true; + + if let Some(mm) = self.get_morphism_instance(&SugaredMorphismType { src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }) { + if ty_lhs != ty_rhs { + necessary = true; + } + member_morph.push((symbol_lhs.clone(), mm)) + } else { + failed = true; + } + break; + } + } + + // member of rhs not found in lhs + if ! found_src_member { + failed = true; + break; + } + } + + if ! failed && necessary { + Some(MorphismInstance2::MapStruct { + ψ: src_ψ, + struct_repr: struct_repr_lhs.clone(), + member_morph + }) + } else { + None + } + } + + + (SugaredTypeTerm::Seq{ seq_repr: seq_repr_lhs, items: items_lhs }, + SugaredTypeTerm::Seq{ seq_repr: _seq_rerpr_rhs, items: items_rhs }) + => { + //let mut item_morphs = Vec::new(); + + for (ty_lhs, ty_rhs) in items_lhs.iter().zip(items_rhs.iter()) { + if let Some(item_morph) = self.get_morphism_instance(&SugaredMorphismType{ src_type: ty_lhs.clone(), dst_type: ty_rhs.clone() }) { + return Some(MorphismInstance2::MapSeq { ψ: src_ψ, seq_repr: seq_repr_lhs.clone(), item_morph: Box::new(item_morph) }); + } + break; + } + None + } + + _ => { + None + } + } + } + + pub fn enum_morphisms_from(&self, src_type: &SugaredTypeTerm) -> Vec< MorphismInstance2<M> > { + let mut morphs = Vec::new(); + + for m in self.morphisms.iter() { + let m_src_type = m.get_type().src_type; + let m_dst_type = m.get_type().dst_type; + + /* 1. primitive morphisms */ + + // check if the given start type is compatible with the + // morphisms source type, + // i.e. check if `src_type` is a subtype of `m_src_type` + if let Ok((ψ, σ)) = crate::unification_sugared::subtype_unify(src_type, &m_src_type) { + morphs.push(MorphismInstance2::Primitive { ψ, σ, morph: m.clone() }); + } + + /* 2. check complex types */ + if let Some(complex_morph) = self.complex_morphism_decomposition(src_type, &m_src_type) { + morphs.push(complex_morph); + } + } + + morphs + } + +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/morphism_path.rs b/src/morphism_path.rs index 849603d..c67e0cc 100644 --- a/src/morphism_path.rs +++ b/src/morphism_path.rs @@ -39,10 +39,14 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> { pub fn solve(&mut self) -> Option< Vec<MorphismInstance<M>> > { while ! self.queue.is_empty() { + /* take the shortest partial path and try to advance it by one step */ self.queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight)); if let Some(mut cur_path) = self.queue.pop() { - if let Ok((halo, σ)) = crate::unification::subtype_unify( &cur_path.cur_type, &self.goal ) { + + /* 1. Check if goal is already reached by the current path */ + + if let Ok((ψ, σ)) = crate::unification::subtype_unify( &cur_path.cur_type, &self.goal ) { /* found path, * now apply substitution and trim to variables in terms of each step */ @@ -78,6 +82,9 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> { return Some(cur_path.morphisms); } + /* 2. Try to advance the path */ + /* 2.1. Direct Morphisms */ + //eprintln!("cur path (w ={}) : @ {:?}", cur_path.weight, cur_path.cur_type);//.clone().sugar(type_dict).pretty(type_dict, 0) ); for mut next_morph_inst in self.morphism_base.enum_morphisms(&cur_path.cur_type) { let dst_type = next_morph_inst.get_type().dst_type; @@ -125,6 +132,12 @@ impl<'a, M:Morphism+Clone> ShortestPathProblem<'a, M> { self.queue.push(new_path); } } + + /* 2.2. Try to decompose */ + /* 2.2.1. Seq - Map */ + /* 2.2.2. Struct - Map */ + /* 2.2.3. Enum - Map */ + } } None diff --git a/src/morphism_path_sugared.rs b/src/morphism_path_sugared.rs new file mode 100644 index 0000000..c2b6cf7 --- /dev/null +++ b/src/morphism_path_sugared.rs @@ -0,0 +1,108 @@ +use { + crate::{ + dict::*, + morphism_sugared::{SugaredMorphism, SugaredMorphismType, MorphismInstance2}, + morphism_base_sugared::SugaredMorphismBase, + substitution_sugared::SugaredSubstitution, + sugar::*, term::*, + } +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +#[derive(Clone)] +pub struct SugaredMorphismPath<M: SugaredMorphism + Clone> { + pub weight: u64, + pub cur_type: SugaredTypeTerm, + pub morphisms: Vec< MorphismInstance2<M> > +} + + +impl<M: SugaredMorphism+Clone> SugaredMorphismPath<M> { + fn apply_subst(&mut self, σ: &std::collections::HashMap<TypeID, SugaredTypeTerm>) { + for m in self.morphisms.iter_mut() { + m.apply_subst(σ); + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +pub struct SugaredShortestPathProblem<'a, M: SugaredMorphism + Clone> { + pub morphism_base: &'a SugaredMorphismBase<M>, + pub goal: SugaredTypeTerm, + queue: Vec< SugaredMorphismPath<M> > +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +impl<'a, M:SugaredMorphism+Clone> SugaredShortestPathProblem<'a, M> { + pub fn new(morphism_base: &'a SugaredMorphismBase<M>, ty: SugaredMorphismType) -> Self { + SugaredShortestPathProblem { + morphism_base, + queue: vec![ + SugaredMorphismPath::<M> { weight: 0, cur_type: ty.src_type, morphisms: vec![] } + ], + goal: ty.dst_type + } + } + + pub fn advance(&mut self, prev_path: &SugaredMorphismPath<M>, morph_inst: MorphismInstance2<M>) { + let dst_type = morph_inst.get_type().dst_type; + //eprintln!("try morph to {:?}", dst_type.clone());//.sugar(type_dict).pretty(type_dict, 0)); + + let mut creates_loop = false; + + let mut new_path = prev_path.clone(); + for n in new_path.morphisms.iter_mut() { + n.apply_subst(&morph_inst.get_subst()); + } + + for m in new_path.morphisms.iter() { + if m.get_type().src_type == dst_type { + creates_loop = true; + break; + } + } + + if ! creates_loop { + new_path.weight += 1;//next_morph_inst.get_weight(); + new_path.cur_type = dst_type; + + new_path.morphisms.push(morph_inst); + self.queue.push(new_path); + } + } + + pub fn solve(&mut self) -> Option< Vec<MorphismInstance2<M>> > { + while ! self.queue.is_empty() { + /* take the shortest partial path and try to advance it by one step */ + self.queue.sort_by( |p1,p2| p2.weight.cmp(&p1.weight)); + if let Some(mut cur_path) = self.queue.pop() { + + /* 1. Check if goal is already reached by the current path */ + if let Ok((_ψ, σ)) = crate::unification_sugared::subtype_unify( &cur_path.cur_type, &self.goal ) { + /* found path, + * now apply substitution and trim to variables in terms of each step + */ + cur_path.apply_subst(&σ); + return Some(cur_path.morphisms); + } + + /* 2. Try to advance current path */ + else if let Some(complex_morph) = + self.morphism_base.complex_morphism_decomposition( &cur_path.cur_type, &self.goal ) + { + self.advance(&cur_path, complex_morph); + } else { + for next_morph_inst in self.morphism_base.enum_morphisms_from(&cur_path.cur_type) { + self.advance(&cur_path, next_morph_inst); + } + } + } + } + None + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/morphism_sugared.rs b/src/morphism_sugared.rs new file mode 100644 index 0000000..cd41216 --- /dev/null +++ b/src/morphism_sugared.rs @@ -0,0 +1,205 @@ +use { + crate::{ + substitution_sugared::SugaredSubstitution, + sugar::{SugaredStructMember, SugaredTypeTerm}, + unification::UnificationProblem, + unification_sugared::SugaredUnificationProblem, + unparser::*, TypeDict, + TypeID, TypeTerm + }, + std::{collections::HashMap, u64} +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +#[derive(Clone, Debug, PartialEq, Eq)] +pub struct SugaredMorphismType { + pub src_type: SugaredTypeTerm, + pub dst_type: SugaredTypeTerm +} + +pub trait SugaredMorphism : Sized { + fn get_type(&self) -> SugaredMorphismType; + fn weight(&self) -> u64 { + 1 + } +} + +#[derive(Clone)] +pub enum MorphismInstance2<M: SugaredMorphism + Clone> { + Primitive{ + ψ: SugaredTypeTerm, + σ: HashMap<TypeID, SugaredTypeTerm>, + morph: M, + }, + Chain{ + path: Vec<MorphismInstance2<M>> + }, + MapSeq{ + ψ: SugaredTypeTerm, + seq_repr: Option<Box<SugaredTypeTerm>>, + item_morph: Box<MorphismInstance2<M>>, + }, + MapStruct{ + ψ: SugaredTypeTerm, + struct_repr: Option<Box<SugaredTypeTerm>>, + member_morph: Vec< (String, MorphismInstance2<M>) > + }, + MapEnum{ + ψ: SugaredTypeTerm, + enum_repr: Option<Box<SugaredTypeTerm>>, + variant_morph: Vec< (String, MorphismInstance2<M>) > + } +} + + +impl<M: SugaredMorphism + Clone> MorphismInstance2<M> { + pub fn get_type(&self) -> SugaredMorphismType { + match self { + MorphismInstance2::Primitive { ψ, σ, morph } => { + SugaredMorphismType { + src_type: + SugaredTypeTerm::Ladder(vec![ + ψ.clone(), + morph.get_type().src_type + .apply_subst(σ).clone() + ]).strip(), + + dst_type: SugaredTypeTerm::Ladder(vec![ + ψ.clone(), + morph.get_type().dst_type + .apply_subst(σ).clone() + ]).strip(), + } + } + MorphismInstance2::Chain { path } => { + if path.len() > 0 { + SugaredMorphismType { + src_type: path.first().unwrap().get_type().src_type, + dst_type: path.last().unwrap().get_type().dst_type + } + } else { + SugaredMorphismType { + src_type: SugaredTypeTerm::TypeID(TypeID::Var(45454)), + dst_type: SugaredTypeTerm::TypeID(TypeID::Var(45454)) + } + } + } + MorphismInstance2::MapSeq { ψ, seq_repr, item_morph } => { + SugaredMorphismType { + src_type: SugaredTypeTerm::Ladder(vec![ + ψ.clone(), + SugaredTypeTerm::Seq{ seq_repr: seq_repr.clone(), + items: vec![ item_morph.get_type().src_type ]} + ]).strip(), + dst_type: SugaredTypeTerm::Ladder(vec![ + ψ.clone(), + SugaredTypeTerm::Seq{ seq_repr: seq_repr.clone(), + items: vec![ item_morph.get_type().dst_type ]} + ]).strip() + } + } + MorphismInstance2::MapStruct { ψ, struct_repr, member_morph } => { + SugaredMorphismType { + src_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(), + SugaredTypeTerm::Struct{ + struct_repr: struct_repr.clone(), + members: + member_morph.iter().map(|(symbol, morph)| { + SugaredStructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type } + }).collect() + } + ]).strip(), + dst_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(), + SugaredTypeTerm::Struct{ + struct_repr: struct_repr.clone(), + members: member_morph.iter().map(|(symbol, morph)| { + SugaredStructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type} + }).collect() + } + ]).strip() + } + } + MorphismInstance2::MapEnum { ψ, enum_repr, variant_morph } => { + SugaredMorphismType { + src_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(), + SugaredTypeTerm::Struct{ + struct_repr: enum_repr.clone(), + members: + variant_morph.iter().map(|(symbol, morph)| { + SugaredStructMember{ symbol:symbol.clone(), ty: morph.get_type().src_type } + }).collect() + } + ]).strip(), + dst_type: SugaredTypeTerm::Ladder(vec![ ψ.clone(), + SugaredTypeTerm::Struct{ + struct_repr: enum_repr.clone(), + members: variant_morph.iter().map(|(symbol, morph)| { + SugaredStructMember { symbol: symbol.clone(), ty: morph.get_type().dst_type} + }).collect() + } + ]).strip() + } + } + } + } + + pub fn get_subst(&self) -> std::collections::HashMap< TypeID, SugaredTypeTerm > { + match self { + MorphismInstance2::Primitive { ψ, σ, morph } => σ.clone(), + MorphismInstance2::Chain { path } => { + path.iter().fold( + std::collections::HashMap::new(), + |mut σ, m| { + σ = σ.append(&m.get_subst()); + σ + } + ) + }, + MorphismInstance2::MapSeq { ψ, seq_repr, item_morph } => { + item_morph.get_subst() + }, + MorphismInstance2::MapStruct { ψ, struct_repr, member_morph } => { + let mut σ = HashMap::new(); + for (symbol, m) in member_morph.iter() { + σ = σ.append(&mut m.get_subst()); + } + σ + }, + MorphismInstance2::MapEnum { ψ, enum_repr, variant_morph } => { + todo!(); + HashMap::new() + }, + } + } + + pub fn apply_subst(&mut self, γ: &std::collections::HashMap< TypeID, SugaredTypeTerm >) { + match self { + MorphismInstance2::Primitive { ψ, σ, morph } => { + ψ.apply_subst(σ); + *σ = σ.clone().append(γ); + }, + MorphismInstance2::Chain { path } => { + for n in path.iter_mut() { + n.apply_subst(γ); + } + } + MorphismInstance2::MapSeq { ψ, seq_repr, item_morph } => { + ψ.apply_subst(γ); + item_morph.apply_subst(γ); + } + MorphismInstance2::MapStruct { ψ, struct_repr, member_morph } => { + for (_,ty) in member_morph { + ty.apply_subst(γ); + } + }, + MorphismInstance2::MapEnum { ψ, enum_repr, variant_morph } => { + for (_,ty) in variant_morph { + ty.apply_subst(γ); + } + } + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/pnf_sugared.rs b/src/pnf_sugared.rs new file mode 100644 index 0000000..f5a72d7 --- /dev/null +++ b/src/pnf_sugared.rs @@ -0,0 +1,161 @@ +use crate::{sugar::SugaredTypeTerm, SugaredEnumVariant, SugaredStructMember}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +pub fn splice_ladders( mut upper: Vec< SugaredTypeTerm >, mut lower: Vec< SugaredTypeTerm > ) -> Vec< SugaredTypeTerm > { + for i in 0 .. upper.len() { + if upper[i] == lower[0] { + let mut result_ladder = Vec::<SugaredTypeTerm>::new(); + result_ladder.append(&mut upper[0..i].iter().cloned().collect()); + result_ladder.append(&mut lower); + return result_ladder; + } + } + + upper.append(&mut lower); + upper +} + +impl SugaredTypeTerm { + /// transmute type into Parameter-Normal-Form (PNF) + /// + /// Example: + /// ```ignore + /// <Seq <Digit 10>>~<Seq Char> + /// ⇒ <Seq <Digit 10>~Char> + /// ``` + pub fn param_normalize(mut self) -> Self { + + match self { + SugaredTypeTerm::Ladder(mut rungs) => { + if rungs.len() > 0 { + let mut new_rungs = Vec::new(); + while let Some(bottom) = rungs.pop() { + if let Some(last_but) = rungs.last_mut() { + match (bottom, last_but) { + (SugaredTypeTerm::Spec(bot_args), SugaredTypeTerm::Spec(last_args)) => { + if bot_args.len() == last_args.len() { + let mut new_rung_params = Vec::new(); + let mut require_break = false; + + if bot_args.len() > 0 { + todo!(); + /* + if let Ok(_idx) = last_args[0].is_syntactic_subtype_of(&bot_args[0]) { + for i in 0 .. bot_args.len() { + + let spliced_type_ladder = splice_ladders( + last_args[i].clone().get_lnf_vec(), + bot_args[i].clone().get_lnf_vec() + ); + let spliced_type = + if spliced_type_ladder.len() == 1 { + spliced_type_ladder[0].clone() + } else if spliced_type_ladder.len() > 1 { + SugaredTypeTerm::Ladder(spliced_type_ladder) + } else { + SugaredTypeTerm::unit() + }; + + new_rung_params.push( spliced_type.param_normalize() ); + } + + } else { + new_rung_params.push( + SugaredTypeTerm::Ladder(vec![ + last_args[0].clone(), + bot_args[0].clone() + ])//.normalize() + ); + + for i in 1 .. bot_args.len() { + if let Ok(_idx) = last_args[i].is_syntactic_subtype_of(&bot_args[i]) { + let spliced_type_ladder = splice_ladders( + last_args[i].clone().get_lnf_vec(), + bot_args[i].clone().get_lnf_vec() + ); + let spliced_type = + if spliced_type_ladder.len() == 1 { + spliced_type_ladder[0].clone() + } else if spliced_type_ladder.len() > 1 { + SugaredTypeTerm::Ladder(spliced_type_ladder) + } else { + SugaredTypeTerm::unit() + }; + + new_rung_params.push( spliced_type.param_normalize() ); + } else { + new_rung_params.push( bot_args[i].clone() ); + require_break = true; + } + } + } + */ + } + + if require_break { + new_rungs.push( SugaredTypeTerm::Spec(new_rung_params) ); + } else { + rungs.pop(); + rungs.push(SugaredTypeTerm::Spec(new_rung_params)); + } + + } else { + new_rungs.push( SugaredTypeTerm::Spec(bot_args) ); + } + } + (bottom, last_buf) => { + new_rungs.push( bottom ); + } + } + } else { + new_rungs.push( bottom ); + } + } + + new_rungs.reverse(); + + if new_rungs.len() > 1 { + SugaredTypeTerm::Ladder(new_rungs) + } else if new_rungs.len() == 1 { + new_rungs[0].clone() + } else { + SugaredTypeTerm::unit() + } + } else { + SugaredTypeTerm::unit() + } + } + + SugaredTypeTerm::Spec(params) => { + SugaredTypeTerm::Spec( + params.into_iter() + .map(|p| p.param_normalize()) + .collect()) + } + + SugaredTypeTerm::Seq { seq_repr, items } => SugaredTypeTerm::Seq { + seq_repr: if let Some(seq_repr) = seq_repr { Some(Box::new(seq_repr.param_normalize())) } else { None }, + items: items.into_iter().map(|p| p.param_normalize()).collect() + }, + SugaredTypeTerm::Struct { struct_repr, members } =>SugaredTypeTerm::Struct { + struct_repr: if let Some(struct_repr) = struct_repr { Some(Box::new(struct_repr.param_normalize())) } else { None }, + members: members.into_iter() + .map(|SugaredStructMember{symbol, ty}| + SugaredStructMember{ symbol, ty: ty.param_normalize() }) + .collect() + }, + SugaredTypeTerm::Enum{ enum_repr, variants } => SugaredTypeTerm::Enum{ + enum_repr: if let Some(enum_repr) = enum_repr { Some(Box::new(enum_repr.param_normalize())) } else { None }, + variants: variants.into_iter() + .map(|SugaredEnumVariant{symbol, ty}| + SugaredEnumVariant{ symbol, ty: ty.param_normalize() }) + .collect() + }, + + atomic => atomic + } + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/pretty.rs b/src/pretty.rs index 47f85f7..c3cc103 100644 --- a/src/pretty.rs +++ b/src/pretty.rs @@ -5,18 +5,18 @@ use { impl SugaredStructMember { - pub fn pretty(&self, dict: &TypeDict, indent: u64) -> String { + pub fn pretty(&self, dict: &impl TypeDict, indent: u64) -> String { format!("{}: {}", self.symbol, self.ty.pretty(dict, indent+1)) } } impl SugaredEnumVariant { - pub fn pretty(&self, dict: &TypeDict, indent: u64) -> String { + pub fn pretty(&self, dict: &impl TypeDict, indent: u64) -> String { format!("{}: {}", self.symbol, self.ty.pretty(dict, indent+1)) } } impl SugaredTypeTerm { - pub fn pretty(&self, dict: &TypeDict, indent: u64) -> String { + pub fn pretty(&self, dict: &impl TypeDict, indent: u64) -> String { let indent_width = 4; match self { SugaredTypeTerm::TypeID(id) => { @@ -64,15 +64,20 @@ impl SugaredTypeTerm { s } - SugaredTypeTerm::Struct(args) => { + SugaredTypeTerm::Struct{ struct_repr, members } => { let mut s = String::new(); s.push_str(&"{".yellow().bold()); - for arg in args { + + if let Some(struct_repr) = struct_repr { + s.push_str(&format!("{}{} ", "~".yellow(), struct_repr.pretty(dict, indent+1))); + } + + for member in members { s.push('\n'); for x in 0..(indent+1)*indent_width { s.push(' '); } - s.push_str(&arg.pretty(dict, indent + 1)); + s.push_str(&member.pretty(dict, indent + 1)); s.push_str(&";\n".bright_yellow()); } @@ -84,11 +89,16 @@ impl SugaredTypeTerm { s } - SugaredTypeTerm::Enum(args) => { + SugaredTypeTerm::Enum{ enum_repr, variants } => { let mut s = String::new(); s.push_str(&"(".yellow().bold()); - for i in 0..args.len() { - let arg = &args[i]; + + if let Some(enum_repr) = enum_repr { + s.push_str(&format!("{}{} ", "~".yellow(), enum_repr.pretty(dict, indent+1))); + } + + + for (i,variant) in variants.iter().enumerate() { s.push('\n'); for x in 0..(indent+1)*indent_width { s.push(' '); @@ -96,7 +106,7 @@ impl SugaredTypeTerm { if i > 0 { s.push_str(&"| ".yellow().bold()); } - s.push_str(&arg.pretty(dict, indent + 1)); + s.push_str(&variant.pretty(dict, indent + 1)); } s.push('\n'); @@ -107,15 +117,20 @@ impl SugaredTypeTerm { s } - SugaredTypeTerm::Seq(args) => { + SugaredTypeTerm::Seq{ seq_repr, items } => { let mut s = String::new(); - s.push_str(&"[ ".yellow().bold()); - for i in 0..args.len() { - let arg = &args[i]; + s.push_str(&"[".yellow().bold()); + + if let Some(seq_repr) = seq_repr { + s.push_str(&format!("{}{}", "~".yellow(), seq_repr.pretty(dict, indent+1))); + } + s.push(' '); + + for (i, item) in items.iter().enumerate() { if i > 0 { s.push(' '); } - s.push_str(&arg.pretty(dict, indent+1)); + s.push_str(&item.pretty(dict, indent+1)); } s.push_str(&" ]".yellow().bold()); s diff --git a/src/substitution.rs b/src/substitution.rs index b0f70ff..09935d0 100644 --- a/src/substitution.rs +++ b/src/substitution.rs @@ -60,3 +60,5 @@ impl TypeTerm { self } } + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/substitution_sugared.rs b/src/substitution_sugared.rs new file mode 100644 index 0000000..1386e35 --- /dev/null +++ b/src/substitution_sugared.rs @@ -0,0 +1,114 @@ + +use std::ops::DerefMut; +use crate::{ + TypeID, + TypeTerm +}; +use crate::sugar::*; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +pub trait SugaredSubstitution { + fn get(&self, t: &TypeID) -> Option< SugaredTypeTerm >; + fn add(&mut self, tyid: TypeID, val: SugaredTypeTerm); + fn append(self, rhs: &Self) -> Self; +} + +impl SugaredSubstitution for std::collections::HashMap< TypeID, SugaredTypeTerm > { + fn get(&self, t: &TypeID) -> Option< SugaredTypeTerm > { + (self as &std::collections::HashMap< TypeID, SugaredTypeTerm >).get(t).cloned() + } + + fn add(&mut self, tyid: TypeID, val: SugaredTypeTerm) { + if let TypeID::Var(id) = tyid { + if !val.contains_var(id) { + self.insert(tyid, val); + } else { + eprintln!("substitution cannot contain loop"); + } + } + } + + fn append(self, rhs: &Self) -> Self { + let mut new_σ = std::collections::HashMap::new(); + for (v, tt) in self.iter() { + let mut tt = tt.clone(); + tt.apply_subst(rhs); + tt.apply_subst(&self); + new_σ.add(v.clone(), tt); + } + for (v, tt) in rhs.iter() { + new_σ.add(v.clone(), tt.clone()); + } + + new_σ + } +} + +impl SugaredTypeTerm { + /// recursively apply substitution to all subterms, + /// which will replace all occurences of variables which map + /// some type-term in `subst` + pub fn apply_substitution( + &mut self, + σ: &impl SugaredSubstitution + ) -> &mut Self { + self.apply_subst(σ) + } + + pub fn apply_subst( + &mut self, + σ: &impl SugaredSubstitution + ) -> &mut Self { + match self { + SugaredTypeTerm::Num(_) => {}, + SugaredTypeTerm::Char(_) => {}, + + SugaredTypeTerm::TypeID(typid) => { + if let Some(t) = σ.get(typid) { + *self = t; + } + } + SugaredTypeTerm::Ladder(args) | + SugaredTypeTerm::Spec(args) | + SugaredTypeTerm::Func(args) | + SugaredTypeTerm::Morph(args) + => { + for r in args.iter_mut() { + r.apply_subst(σ); + } + } + + SugaredTypeTerm::Univ(t) => { t.apply_subst(σ); } + + SugaredTypeTerm::Struct { struct_repr, members } => { + if let Some(struct_repr) = struct_repr.as_mut() { + struct_repr.apply_subst(σ); + } + for SugaredStructMember{ symbol:_, ty } in members.iter_mut() { + ty.apply_subst(σ); + } + }, + SugaredTypeTerm::Enum { enum_repr, variants } => { + if let Some(enum_repr) = enum_repr.as_mut() { + enum_repr.apply_subst(σ); + } + for SugaredEnumVariant{ symbol:_, ty } in variants.iter_mut() { + ty.apply_subst(σ); + } + } + SugaredTypeTerm::Seq { seq_repr, items } => { + if let Some(seq_repr) = seq_repr { + seq_repr.apply_subst(σ); + } + for ty in items.iter_mut() { + ty.apply_subst(σ); + } + }, + } + + self + } +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/subtype.rs b/src/subtype.rs index 8c46752..6843160 100644 --- a/src/subtype.rs +++ b/src/subtype.rs @@ -2,7 +2,7 @@ use crate::term::TypeTerm; //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ -impl TypeTerm { +impl TypeTerm { // returns ladder-step of first match and provided representation-type pub fn is_semantic_subtype_of(&self, expected_type: &TypeTerm) -> Option<(usize, TypeTerm)> { let provided_lnf = self.clone().get_lnf_vec(); @@ -49,3 +49,28 @@ impl TypeTerm { } //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +use crate::sugar::*; + +impl SugaredTypeTerm { + pub fn is_compatible(&self, supertype: SugaredTypeTerm) -> bool { + match (self, supertype) { + (SugaredTypeTerm::TypeID(idl), SugaredTypeTerm::TypeID(idr)) => { + if *idl == idr { + true + } else { + false + } + } + + + (SugaredTypeTerm::Ladder(l_rungs), SugaredTypeTerm::Ladder(r_rungs)) => { + false + } + + _ => { + false + } + } + } +} diff --git a/src/sugar.rs b/src/sugar.rs index aa1ff4e..eef8dee 100644 --- a/src/sugar.rs +++ b/src/sugar.rs @@ -1,20 +1,20 @@ use { - crate::{parser::ParseLadderType, TypeDict, TypeID, TypeTerm} + crate::{parser::ParseLadderType, subtype_unify, TypeDict, TypeID, TypeTerm} }; -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct SugaredStructMember { pub symbol: String, pub ty: SugaredTypeTerm } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub struct SugaredEnumVariant { pub symbol: String, pub ty: SugaredTypeTerm } -#[derive(Clone, PartialEq)] +#[derive(Clone, PartialEq, Eq, Debug)] pub enum SugaredTypeTerm { TypeID(TypeID), Num(i64), @@ -24,24 +24,37 @@ pub enum SugaredTypeTerm { Func(Vec< SugaredTypeTerm >), Morph(Vec< SugaredTypeTerm >), Ladder(Vec< SugaredTypeTerm >), - Struct(Vec< SugaredStructMember >), - Enum(Vec< SugaredEnumVariant >), - Seq(Vec< SugaredTypeTerm >) + Struct{ + struct_repr: Option< Box<SugaredTypeTerm> >, + members: Vec< SugaredStructMember > + }, + Enum{ + enum_repr: Option<Box< SugaredTypeTerm >>, + variants: Vec< SugaredEnumVariant > + }, + Seq{ + seq_repr: Option<Box< SugaredTypeTerm >>, + items: Vec< SugaredTypeTerm > + }, + + /* + Todo: Ref, RefMut + */ } impl SugaredStructMember { pub fn parse( dict: &mut impl TypeDict, ty: &TypeTerm ) -> Option<Self> { match ty { TypeTerm::App(args) => { - if args.len() != 3 { + if args.len() != 2 { return None; } - +/* if args[0] != dict.parse("Struct.Field").expect("parse") { return None; } - - let symbol = match args[1] { +*/ + let symbol = match args[0] { TypeTerm::Char(c) => c.to_string(), TypeTerm::TypeID(id) => dict.get_typename(&id).expect("cant get member name"), _ => { @@ -49,7 +62,7 @@ impl SugaredStructMember { } }; - let ty = args[2].clone().sugar(dict); + let ty = args[1].clone().sugar(dict); Some(SugaredStructMember { symbol, ty }) } @@ -64,15 +77,15 @@ impl SugaredEnumVariant { pub fn parse( dict: &mut impl TypeDict, ty: &TypeTerm ) -> Option<Self> { match ty { TypeTerm::App(args) => { - if args.len() != 3 { + if args.len() != 2 { return None; } - +/* if args[0] != dict.parse("Enum.Variant").expect("parse") { return None; } - - let symbol = match args[1] { +*/ + let symbol = match args[0] { TypeTerm::Char(c) => c.to_string(), TypeTerm::TypeID(id) => dict.get_typename(&id).expect("cant get member name"), _ => { @@ -80,7 +93,7 @@ impl SugaredEnumVariant { } }; - let ty = args[2].clone().sugar(dict); + let ty = args[1].clone().sugar(dict); Some(SugaredEnumVariant { symbol, ty }) } @@ -93,6 +106,10 @@ impl SugaredEnumVariant { impl TypeTerm { pub fn sugar(self: TypeTerm, dict: &mut impl crate::TypeDict) -> SugaredTypeTerm { + dict.add_varname("StructRepr".into()); + dict.add_varname("EnumRepr".into()); + dict.add_varname("SeqRepr".into()); + match self { TypeTerm::TypeID(id) => SugaredTypeTerm::TypeID(id), TypeTerm::Num(n) => SugaredTypeTerm::Num(n), @@ -105,13 +122,52 @@ impl TypeTerm { SugaredTypeTerm::Morph( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() ) } else if first == &dict.parse("Struct").unwrap() { - SugaredTypeTerm::Struct( args[1..].into_iter().map(|t| SugaredStructMember::parse(dict, t).expect("cant parse field")).collect() ) + SugaredTypeTerm::Struct{ + struct_repr: None, + members: args[1..].into_iter() + .map(|t| SugaredStructMember::parse(dict, t).expect("cant parse field")) + .collect() + } + } + else if let Ok(σ) = crate::unify( first, &dict.parse("Struct ~ StructRepr").expect("") ) { + SugaredTypeTerm::Struct{ + struct_repr: Some(Box::new(σ.get(&dict.get_typeid(&"StructRepr".into()).expect("")).unwrap().clone().sugar(dict))), + members: args[1..].into_iter() + .map(|t| SugaredStructMember::parse(dict, t).expect("cant parse field")) + .collect() + } } else if first == &dict.parse("Enum").unwrap() { - SugaredTypeTerm::Enum( args[1..].into_iter().map(|t| SugaredEnumVariant::parse(dict, t).expect("cant parse variant")).collect() ) + SugaredTypeTerm::Enum{ + enum_repr: None, + variants: args[1..].into_iter() + .map(|t| SugaredEnumVariant::parse(dict, t).expect("cant parse variant")) + .collect() + } + } + else if let Ok(σ) = crate::unify( first, &dict.parse("Enum ~ EnumRepr").expect("") ) { + SugaredTypeTerm::Enum{ + enum_repr: Some(Box::new(σ.get(&dict.get_typeid(&"EnumRepr".into()).expect("")).unwrap().clone().sugar(dict))), + variants: args[1..].into_iter() + .map(|t| SugaredEnumVariant::parse(dict, t).expect("cant parse variant")) + .collect() + } } else if first == &dict.parse("Seq").unwrap() { - SugaredTypeTerm::Seq( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() ) + SugaredTypeTerm::Seq { + seq_repr: None, + items: args[1..].into_iter() + .map(|t| t.clone().sugar(dict)) + .collect() + } + } + else if let Ok(σ) = crate::unify( first, &dict.parse("Seq ~ SeqRepr").expect("") ) { + SugaredTypeTerm::Seq { + seq_repr: Some(Box::new(σ.get(&dict.get_typeid(&"SeqRepr".into()).expect("")).unwrap().clone().sugar(dict))), + items: args[1..].into_iter() + .map(|t| t.clone().sugar(dict)) + .collect() + } } else if first == &dict.parse("Spec").unwrap() { SugaredTypeTerm::Spec( args[1..].into_iter().map(|t| t.clone().sugar(dict)).collect() ) @@ -139,7 +195,7 @@ impl TypeTerm { impl SugaredStructMember { pub fn desugar(self, dict: &mut impl crate::TypeDict) -> TypeTerm { TypeTerm::App(vec![ - dict.parse("Struct.Field").expect("parse"), + //dict.parse("Struct.Field").expect("parse"), dict.parse(&self.symbol).expect("parse"), self.ty.desugar(dict) ]) @@ -149,7 +205,7 @@ impl SugaredStructMember { impl SugaredEnumVariant { pub fn desugar(self, dict: &mut impl crate::TypeDict) -> TypeTerm { TypeTerm::App(vec![ - dict.parse("Enum.Variant").expect("parse"), + //dict.parse("Enum.Variant").expect("parse"), dict.parse(&self.symbol).expect("parse"), self.ty.desugar(dict) ]) @@ -157,6 +213,10 @@ impl SugaredEnumVariant { } impl SugaredTypeTerm { + pub fn unit() -> Self { + SugaredTypeTerm::Ladder(vec![]) + } + pub fn desugar(self, dict: &mut impl crate::TypeDict) -> TypeTerm { match self { SugaredTypeTerm::TypeID(id) => TypeTerm::TypeID(id), @@ -173,21 +233,270 @@ impl SugaredTypeTerm { std::iter::once( dict.parse("Morph").unwrap() ).chain( ts.into_iter().map(|t| t.desugar(dict)) ).collect()), - SugaredTypeTerm::Struct(ts) => TypeTerm::App( - std::iter::once( dict.parse("Struct").unwrap() ).chain( - ts.into_iter().map(|t| t.desugar(dict)) + SugaredTypeTerm::Struct{ struct_repr, members } => TypeTerm::App( + std::iter::once( + if let Some(sr) = struct_repr { + TypeTerm::Ladder(vec![ + dict.parse("Struct").unwrap(), + sr.desugar(dict) + ]) + } else { + dict.parse("Struct").unwrap() + } + ).chain( + members.into_iter().map(|t| t.desugar(dict)) ).collect()), - SugaredTypeTerm::Enum(ts) => TypeTerm::App( + SugaredTypeTerm::Enum{ enum_repr, variants } => TypeTerm::App( std::iter::once( dict.parse("Enum").unwrap() ).chain( - ts.into_iter().map(|t| t.desugar(dict)) + variants.into_iter().map(|t| t.desugar(dict)) ).collect()), - SugaredTypeTerm::Seq(ts) => TypeTerm::App( + SugaredTypeTerm::Seq{ seq_repr, items } => TypeTerm::App( std::iter::once( dict.parse("Seq").unwrap() ).chain( - ts.into_iter().map(|t| t.desugar(dict)) + items.into_iter().map(|t| t.desugar(dict)) ).collect()), } } + pub fn contains_var(&self, var_id: u64) -> bool { + match self { + SugaredTypeTerm::TypeID(TypeID::Var(v)) => (&var_id == v), + SugaredTypeTerm::Spec(args) | + SugaredTypeTerm::Func(args) | + SugaredTypeTerm::Morph(args) | + SugaredTypeTerm::Ladder(args) => { + for a in args.iter() { + if a.contains_var(var_id) { + return true; + } + } + false + } + SugaredTypeTerm::Univ(t) => { + t.contains_var(var_id) + } + SugaredTypeTerm::Struct { struct_repr, members } => { + if let Some(struct_repr) = struct_repr { + if struct_repr.contains_var(var_id) { + return true; + } + } + + for SugaredStructMember{ symbol, ty } in members { + if ty.contains_var(var_id) { + return true; + } + } + false + } + SugaredTypeTerm::Enum { enum_repr, variants } => { + if let Some(enum_repr) = enum_repr { + if enum_repr.contains_var(var_id) { + return true; + } + } + + for SugaredEnumVariant{ symbol, ty } in variants { + if ty.contains_var(var_id) { + return true; + } + } + false + } + SugaredTypeTerm::Seq { seq_repr, items } => { + if let Some(seq_repr) = seq_repr { + if seq_repr.contains_var(var_id) { + return true; + } + } + + for ty in items { + if ty.contains_var(var_id) { + return true; + } + } + false + } + + SugaredTypeTerm::Num(_) | + SugaredTypeTerm::Char(_) | + SugaredTypeTerm::TypeID(TypeID::Fun(_)) => false + } + } + + pub fn strip(self) -> SugaredTypeTerm { + if self.is_empty() { + return SugaredTypeTerm::unit(); + } + + match self { + SugaredTypeTerm::Ladder(rungs) => { + let mut rungs :Vec<_> = rungs.into_iter() + .filter_map(|mut r| { + r = r.strip(); + if r != SugaredTypeTerm::unit() { + Some(match r { + SugaredTypeTerm::Ladder(r) => r, + a => vec![ a ] + }) + } + else { None } + }) + .flatten() + .collect(); + + if rungs.len() == 1 { + rungs.pop().unwrap() + } else { + SugaredTypeTerm::Ladder(rungs) + } + }, + SugaredTypeTerm::Spec(args) => { + let mut args :Vec<_> = args.into_iter().map(|arg| arg.strip()).collect(); + if args.len() == 0 { + SugaredTypeTerm::unit() + } else if args.len() == 1 { + args.pop().unwrap() + } else { + SugaredTypeTerm::Spec(args) + } + } + SugaredTypeTerm::Seq{ mut seq_repr, mut items } => { + if let Some(seq_repr) = seq_repr.as_mut() { + *seq_repr = Box::new(seq_repr.clone().strip()); + } + for i in items.iter_mut() { + *i = i.clone().strip(); + } + + SugaredTypeTerm::Seq { seq_repr, items } + } + atom => atom + } + } + + + pub fn get_interface_type(&self) -> SugaredTypeTerm { + match self { + SugaredTypeTerm::Ladder(rungs) => { + if let Some(top) = rungs.first() { + top.get_interface_type() + } else { + SugaredTypeTerm::unit() + } + } + SugaredTypeTerm::Spec(args) + => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_interface_type()).collect()), + + SugaredTypeTerm::Func(args) + => SugaredTypeTerm::Func(args.iter().map(|a| a.get_interface_type()).collect()), + + SugaredTypeTerm::Morph(args) + => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_interface_type()).collect()), + + SugaredTypeTerm::Univ(t) + => SugaredTypeTerm::Univ(Box::new(t.get_interface_type())), + + SugaredTypeTerm::Seq { seq_repr, items } => { + SugaredTypeTerm::Seq { + seq_repr: if let Some(sr) = seq_repr { + Some(Box::new(sr.clone().get_interface_type())) + } else { None }, + items: items.iter().map(|t| t.get_interface_type()).collect() + } + } + SugaredTypeTerm::Struct { struct_repr, members } => { + SugaredTypeTerm::Struct { + struct_repr: if let Some(sr) = struct_repr { + Some(Box::new(sr.clone().get_interface_type())) + } else { None }, + members: members.iter() + .map(|SugaredStructMember{symbol,ty}| + SugaredStructMember {symbol:symbol.clone(), ty:ty.get_interface_type() }) + .collect() + } + } + SugaredTypeTerm::Enum { enum_repr, variants } => { + SugaredTypeTerm::Enum { + enum_repr: if let Some(sr) = enum_repr { + Some(Box::new(sr.clone().get_interface_type())) + } else { None }, + variants: variants.iter() + .map(|SugaredEnumVariant{symbol,ty}| + SugaredEnumVariant{ symbol:symbol.clone(), ty:ty.get_interface_type() }) + .collect() + } + } + + SugaredTypeTerm::TypeID(tyid) => SugaredTypeTerm::TypeID(tyid.clone()), + SugaredTypeTerm::Num(n) => SugaredTypeTerm::Num(*n), + SugaredTypeTerm::Char(c) => SugaredTypeTerm::Char(*c) + } + } + + pub fn get_floor_type(&self) -> (SugaredTypeTerm, SugaredTypeTerm) { + match self.clone() { + SugaredTypeTerm::Ladder(mut rungs) => { + if let Some(bot) = rungs.pop() { + let (bot_ψ, bot_floor) = bot.get_floor_type(); + rungs.push(bot_ψ); + (SugaredTypeTerm::Ladder(rungs).strip(), bot_floor.strip()) + } else { + (SugaredTypeTerm::unit(), SugaredTypeTerm::unit()) + } + } + /* + SugaredTypeTerm::Spec(args) + => (SugaredTypeTerm::SugaredTypeTerm::Spec(args.iter().map(|a| a.get_floor_type()).collect()), + + SugaredTypeTerm::Func(args) + => SugaredTypeTerm::Func(args.iter().map(|a| a.get_floor_type()).collect()), + + SugaredTypeTerm::Morph(args) + => SugaredTypeTerm::Spec(args.iter().map(|a| a.get_floor_type()).collect()), + + SugaredTypeTerm::Univ(t) + => SugaredTypeTerm::Univ(Box::new(t.get_floor_type())), + + SugaredTypeTerm::Seq { seq_repr, items } => { + SugaredTypeTerm::Seq { + seq_repr: if let Some(sr) = seq_repr { + Some(Box::new(sr.clone().get_floor_type())) + } else { None }, + items: items.iter().map(|t| t.get_floor_type()).collect() + } + } + SugaredTypeTerm::Struct { struct_repr, members } => { + SugaredTypeTerm::Struct { + struct_repr: if let Some(sr) = struct_repr { + Some(Box::new(sr.clone().get_floor_type())) + } else { None }, + members: members.iter() + .map(|SugaredStructMember{symbol,ty}| + SugaredStructMember {symbol:symbol.clone(), ty:ty.get_floor_type() }) + .collect() + } + } + SugaredTypeTerm::Enum { enum_repr, variants } => { + SugaredTypeTerm::Enum { + enum_repr: if let Some(sr) = enum_repr { + Some(Box::new(sr.clone().get_floor_type())) + } else { None }, + variants: variants.iter() + .map(|SugaredEnumVariant{symbol,ty}| + SugaredEnumVariant{ symbol:symbol.clone(), ty:ty.get_floor_type() }) + .collect() + } + } + + SugaredTypeTerm::TypeID(tyid) => SugaredTypeTerm::TypeID(tyid.clone()), + SugaredTypeTerm::Num(n) => SugaredTypeTerm::Num(*n), + SugaredTypeTerm::Char(c) => SugaredTypeTerm::Char(*c) + */ + + other => (SugaredTypeTerm::unit(), other.clone().strip()) + } + } + pub fn is_empty(&self) -> bool { match self { SugaredTypeTerm::TypeID(_) => false, @@ -197,16 +506,18 @@ impl SugaredTypeTerm { SugaredTypeTerm::Spec(ts) | SugaredTypeTerm::Ladder(ts) | SugaredTypeTerm::Func(ts) | - SugaredTypeTerm::Morph(ts) | - SugaredTypeTerm::Seq(ts) => { + SugaredTypeTerm::Morph(ts) => { ts.iter().fold(true, |s,t| s && t.is_empty() ) } - SugaredTypeTerm::Struct(ts) => { - ts.iter() + SugaredTypeTerm::Seq{ seq_repr, items } => { + items.iter().fold(true, |s,t| s && t.is_empty() ) + } + SugaredTypeTerm::Struct{ struct_repr, members } => { + members.iter() .fold(true, |s,member_decl| s && member_decl.ty.is_empty() ) } - SugaredTypeTerm::Enum(ts) => { - ts.iter() + SugaredTypeTerm::Enum{ enum_repr, variants } => { + variants.iter() .fold(true, |s,variant_decl| s && variant_decl.ty.is_empty() ) } } diff --git a/src/test/unification.rs b/src/test/unification.rs index 99ea7ed..ae99a18 100644 --- a/src/test/unification.rs +++ b/src/test/unification.rs @@ -336,14 +336,14 @@ pub fn test_subtype_delim() { UnificationProblem::new_sub(vec![ ( - //given type + // given type dict.parse(" < Seq <Seq <Digit 10>~Char~Ascii~UInt8> > ~ < ValueSep ':' Char~Ascii~UInt8 > ~ < Seq~<LengthPrefix UInt64> Char~Ascii~UInt8 > ").expect(""), - //expected type + // expected type dict.parse(" < Seq <Seq T> > ~ < ValueSep Delim T > @@ -378,3 +378,78 @@ pub fn test_subtype_delim() { )) ); } + + + +use crate::{sugar::*, unification_sugared::{SugaredUnificationPair, SugaredUnificationProblem}}; + +#[test] +fn test_list_subtype_sugared() { + let mut dict = BimapTypeDict::new(); + + dict.add_varname("Item".into()); + + let subtype_constraints = vec![ + SugaredUnificationPair::new( + dict.parse("<List~Vec <Digit 10>~Char~ReprTree>").expect("").sugar(&mut dict), + dict.parse("<List~Vec Item~ReprTree>").expect("").sugar(&mut dict) + ) + ]; + + assert_eq!( + SugaredUnificationProblem::new_sub(&mut dict, subtype_constraints).solve(), + Ok(( + vec![ SugaredTypeTerm::Ladder(vec![]) ], + vec![ + (dict.get_typeid(&"Item".into()).unwrap(), + dict.parse("<Digit 10>~Char").unwrap().sugar(&mut dict)) + ].into_iter().collect() + )) + ); +} + + +#[test] +pub fn test_subtype_delim_sugared() { + let mut dict = BimapTypeDict::new(); + + dict.add_varname(String::from("T")); + dict.add_varname(String::from("Delim")); + + let subtype_constraints = vec![ + SugaredUnificationPair::new( + dict.parse(" + < Seq <Seq <Digit 10>~Char~Ascii~UInt8> > + ~ < ValueSep ':' Char~Ascii~UInt8 > + ~ < Seq~<LengthPrefix UInt64> Char~Ascii~UInt8 > + ").expect("").sugar(&mut dict), + + dict.parse(" + < Seq <Seq T> > + ~ < ValueSep Delim T > + ~ < Seq~<LengthPrefix UInt64> T > + ").expect("").sugar(&mut dict), + ), + SugaredUnificationPair::new( + dict.parse("T").expect("").sugar(&mut dict), + dict.parse("UInt8").expect("").sugar(&mut dict), + ), + ]; + + assert_eq!( + SugaredUnificationProblem::new_sub(&mut dict, subtype_constraints).solve(), + Ok(( + // halo types for each rhs in the sub-equations + vec![ + dict.parse("<Seq <Seq <Digit 10>>>").expect("").sugar(&mut dict), + dict.parse("Char~Ascii").expect("").sugar(&mut dict), + ], + + // variable substitution + vec![ + (dict.get_typeid(&"T".into()).unwrap(), dict.parse("Char~Ascii~UInt8").expect("").sugar(&mut dict)), + (dict.get_typeid(&"Delim".into()).unwrap(), SugaredTypeTerm::Char(':')), + ].into_iter().collect() + )) + ); +} diff --git a/src/unification.rs b/src/unification.rs index 32d45df..6cbe842 100644 --- a/src/unification.rs +++ b/src/unification.rs @@ -25,16 +25,19 @@ pub struct UnificationProblem { σ: HashMap<TypeID, TypeTerm>, upper_bounds: HashMap< u64, TypeTerm >, lower_bounds: HashMap< u64, TypeTerm >, + equal_pairs: Vec<UnificationPair>, subtype_pairs: Vec<UnificationPair>, - trait_pairs: Vec<UnificationPair> + trait_pairs: Vec<UnificationPair>, + parallel_pairs: Vec<UnificationPair> } impl UnificationProblem { pub fn new( equal_pairs: Vec<(TypeTerm, TypeTerm)>, subtype_pairs: Vec<(TypeTerm, TypeTerm)>, - trait_pairs: Vec<(TypeTerm, TypeTerm)> + trait_pairs: Vec<(TypeTerm, TypeTerm)>, + parallel_pairs: Vec<(TypeTerm, TypeTerm)> ) -> Self { UnificationProblem { σ: HashMap::new(), @@ -60,17 +63,24 @@ impl UnificationProblem { addr: Vec::new() }).collect(), + parallel_pairs: parallel_pairs.into_iter().map(|(lhs,rhs)| + UnificationPair{ + lhs,rhs, + halo: TypeTerm::unit(), + addr: Vec::new() + }).collect(), + upper_bounds: HashMap::new(), lower_bounds: HashMap::new(), } } pub fn new_eq(eqs: Vec<(TypeTerm, TypeTerm)>) -> Self { - UnificationProblem::new( eqs, Vec::new(), Vec::new() ) + UnificationProblem::new( eqs, Vec::new(), Vec::new(), Vec::new() ) } pub fn new_sub(subs: Vec<(TypeTerm, TypeTerm)>) -> Self { - UnificationProblem::new( Vec::new(), subs, Vec::new() ) + UnificationProblem::new( Vec::new(), subs, Vec::new(), Vec::new() ) } @@ -527,4 +537,12 @@ pub fn subtype_unify( unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(TypeTerm::unit()), σ) ) } +pub fn parallel_unify( + t1: &TypeTerm, + t2: &TypeTerm +) -> Result<(TypeTerm, HashMap<TypeID, TypeTerm>), UnificationError> { + let unification = UnificationProblem::new(vec![], vec![], vec![], vec![ (t1.clone(), t2.clone()) ]); + unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(TypeTerm::unit()), σ) ) +} + //<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ diff --git a/src/unification_sugared.rs b/src/unification_sugared.rs new file mode 100644 index 0000000..2e61e80 --- /dev/null +++ b/src/unification_sugared.rs @@ -0,0 +1,686 @@ +use { + crate::{dict::*, sugar::SugaredTypeTerm, term::*, SugaredEnumVariant, SugaredStructMember}, std::collections::HashMap +}; + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\ + +#[derive(Clone, Eq, PartialEq, Debug)] +pub struct SugaredUnificationError { + pub addr: Vec<usize>, + pub t1: SugaredTypeTerm, + pub t2: SugaredTypeTerm +} + +#[derive(Clone)] +pub struct SugaredUnificationPair { + addr: Vec<usize>, + lhs: SugaredTypeTerm, + rhs: SugaredTypeTerm, +} + +impl SugaredUnificationPair { + pub fn new(lhs: SugaredTypeTerm, rhs: SugaredTypeTerm) -> Self { + SugaredUnificationPair { + lhs,rhs, addr:vec![] + } + } +} + +pub struct SugaredUnificationProblem { + // dict: &'a Dict, + + σ: HashMap<TypeID, SugaredTypeTerm>, + upper_bounds: HashMap< u64, SugaredTypeTerm >, + lower_bounds: HashMap< u64, SugaredTypeTerm >, + + equal_pairs: Vec<SugaredUnificationPair>, + subtype_pairs: Vec<SugaredUnificationPair>, + trait_pairs: Vec<SugaredUnificationPair>, + parallel_pairs: Vec<SugaredUnificationPair> +} + +impl SugaredUnificationProblem { + pub fn new( + // dict: &'a mut Dict, + equal_pairs: Vec<SugaredUnificationPair>, + subtype_pairs: Vec<SugaredUnificationPair>, + trait_pairs: Vec<SugaredUnificationPair>, + parallel_pairs: Vec<SugaredUnificationPair> + ) -> Self { + SugaredUnificationProblem { + // dict, + σ: HashMap::new(), + + equal_pairs, + subtype_pairs, + trait_pairs, + parallel_pairs, + + upper_bounds: HashMap::new(), + lower_bounds: HashMap::new(), + } + } + + pub fn new_eq(eqs: Vec<SugaredUnificationPair>) -> Self { + SugaredUnificationProblem::new( eqs, Vec::new(), Vec::new(), Vec::new() ) + } + + pub fn new_sub( subs: Vec<SugaredUnificationPair>) -> Self { + SugaredUnificationProblem::new( Vec::new(), subs, Vec::new(), Vec::new() ) + } + + pub fn new_trait(traits: Vec<SugaredUnificationPair>) -> Self { + SugaredUnificationProblem::new( Vec::new(), Vec::new(), traits, Vec::new() ) + } + + pub fn new_parallel( parallels: Vec<SugaredUnificationPair>) -> Self { + SugaredUnificationProblem::new(Vec::new(), Vec::new(), Vec::new(), parallels ) + } + + + /// update all values in substitution + pub fn reapply_subst(&mut self) { + let mut new_σ = HashMap::new(); + for (v, tt) in self.σ.iter() { + let mut tt = tt.clone(); + tt.apply_subst(&self.σ); + //eprintln!("update σ : {:?} --> {:?}", v, tt); + new_σ.insert(v.clone(), tt); + } + self.σ = new_σ; + } + + + pub fn eval_equation(&mut self, unification_pair: SugaredUnificationPair) -> Result<(), SugaredUnificationError> { + match (&unification_pair.lhs, &unification_pair.rhs) { + (SugaredTypeTerm::TypeID(TypeID::Var(varid)), t) | + (t, SugaredTypeTerm::TypeID(TypeID::Var(varid))) => { + if ! t.contains_var( *varid ) { + self.σ.insert(TypeID::Var(*varid), t.clone()); + self.reapply_subst(); + Ok(()) + } else if t == &SugaredTypeTerm::TypeID(TypeID::Var(*varid)) { + Ok(()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::TypeID(TypeID::Var(*varid)), t2: t.clone() }) + } + } + + (SugaredTypeTerm::TypeID(a1), SugaredTypeTerm::TypeID(a2)) => { + if a1 == a2 { Ok(()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) } + } + (SugaredTypeTerm::Num(n1), SugaredTypeTerm::Num(n2)) => { + if n1 == n2 { Ok(()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) } + } + (SugaredTypeTerm::Char(c1), SugaredTypeTerm::Char(c2)) => { + if c1 == c2 { Ok(()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) } + } + + (SugaredTypeTerm::Ladder(a1), SugaredTypeTerm::Ladder(a2)) | + (SugaredTypeTerm::Spec(a1), SugaredTypeTerm::Spec(a2)) => { + if a1.len() == a2.len() { + for (i, (x, y)) in a1.iter().cloned().zip(a2.iter().cloned()).enumerate().rev() { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + self.equal_pairs.push( + SugaredUnificationPair { + lhs: x, + rhs: y, + addr: new_addr + }); + } + Ok(()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + + (SugaredTypeTerm::Seq{ seq_repr: lhs_seq_repr, items: lhs_items }, + SugaredTypeTerm::Seq { seq_repr: rhs_seq_repr, items: rhs_items }) + => { + // todo: unify seq reprü + + if lhs_items.len() == rhs_items.len() { + for (i, (lhs_ty, rhs_ty)) in lhs_items.into_iter().zip(rhs_items.into_iter()).enumerate() + { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + self.equal_pairs.push( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } ); + } + Ok(()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + (SugaredTypeTerm::Struct{ struct_repr: lhs_struct_repr, members: lhs_members }, + SugaredTypeTerm::Struct{ struct_repr: rhs_struct_repr, members: rhs_members }) + => { + // todo: unify struct repr + + if lhs_members.len() == rhs_members.len() { + for (i, + (SugaredStructMember{ symbol: lhs_symbol, ty: lhs_ty}, + SugaredStructMember{ symbol: rhs_symbol, ty: rhs_ty }) + ) in + lhs_members.into_iter().zip(rhs_members.into_iter()).enumerate() + { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + self.equal_pairs.push( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } ); + } + Ok(()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + (SugaredTypeTerm::Enum{ enum_repr: lhs_enum_repr, variants: lhs_variants }, + SugaredTypeTerm::Enum{ enum_repr: rhs_enum_repr, variants: rhs_variants }) + => { + // todo: unify enum repr + + if lhs_variants.len() == rhs_variants.len() { + for (i, + (SugaredEnumVariant{ symbol: lhs_symbol, ty: lhs_ty }, + SugaredEnumVariant{ symbol: rhs_symbol, ty: rhs_ty }) + ) in + lhs_variants.into_iter().zip(rhs_variants.into_iter()).enumerate() + { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + self.equal_pairs.push( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } ); + } + Ok(()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + + _ => Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + + + + pub fn add_lower_subtype_bound(&mut self, v: u64, new_lower_bound: SugaredTypeTerm) -> Result<(),()> { + + if new_lower_bound == SugaredTypeTerm::TypeID(TypeID::Var(v)) { + return Ok(()); + } + + if new_lower_bound.contains_var(v) { + // loop + return Err(()); + } + + if let Some(lower_bound) = self.lower_bounds.get(&v).cloned() { +// eprintln!("var already exists. check max. type"); + if let Ok(halo) = self.eval_subtype( + SugaredUnificationPair { + lhs: lower_bound.clone(), + rhs: new_lower_bound.clone(), + addr: vec![] + } + ) { +// eprintln!("found more general lower bound"); +// eprintln!("set var {}'s lowerbound to {:?}", varid, t.clone()); + // generalize variable type to supertype + self.lower_bounds.insert(v, new_lower_bound); + Ok(()) + } else if let Ok(halo) = self.eval_subtype( + SugaredUnificationPair{ + lhs: new_lower_bound, + rhs: lower_bound, + addr: vec![] + } + ) { +// eprintln!("OK, is already larger type"); + Ok(()) + } else { +// eprintln!("violated subtype restriction"); + Err(()) + } + } else { +// eprintln!("set var {}'s lowerbound to {:?}", varid, t.clone()); + self.lower_bounds.insert(v, new_lower_bound); + Ok(()) + } + } + + + pub fn add_upper_subtype_bound(&mut self, v: u64, new_upper_bound: SugaredTypeTerm) -> Result<(),()> { + if new_upper_bound == SugaredTypeTerm::TypeID(TypeID::Var(v)) { + return Ok(()); + } + + if new_upper_bound.contains_var(v) { + // loop + return Err(()); + } + + if let Some(upper_bound) = self.upper_bounds.get(&v).cloned() { + if let Ok(_halo) = self.eval_subtype( + SugaredUnificationPair { + lhs: new_upper_bound.clone(), + rhs: upper_bound, + addr: vec![] + } + ) { + // found a lower upper bound + self.upper_bounds.insert(v, new_upper_bound); + Ok(()) + } else { + Err(()) + } + } else { + self.upper_bounds.insert(v, new_upper_bound); + Ok(()) + } + } + + pub fn eval_subtype(&mut self, unification_pair: SugaredUnificationPair) -> Result< + // ok: halo type + SugaredTypeTerm, + // error + SugaredUnificationError + > { + // eprintln!("eval_subtype {:?} <=? {:?}", unification_pair.lhs, unification_pair.rhs); + match (unification_pair.lhs.clone().strip(), unification_pair.rhs.clone().strip()) { + + /* + Variables + */ + + (t, SugaredTypeTerm::TypeID(TypeID::Var(v))) => { + //eprintln!("t <= variable"); + if self.add_lower_subtype_bound(v, t.clone()).is_ok() { + Ok(SugaredTypeTerm::unit()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::TypeID(TypeID::Var(v)), t2: t }) + } + } + + (SugaredTypeTerm::TypeID(TypeID::Var(v)), t) => { + //eprintln!("variable <= t"); + if self.add_upper_subtype_bound(v, t.clone()).is_ok() { + Ok(SugaredTypeTerm::unit()) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::TypeID(TypeID::Var(v)), t2: t }) + } + } + + + /* + Atoms + */ + (SugaredTypeTerm::TypeID(a1), SugaredTypeTerm::TypeID(a2)) => { + if a1 == a2 { Ok(SugaredTypeTerm::unit()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs}) } + } + (SugaredTypeTerm::Num(n1), SugaredTypeTerm::Num(n2)) => { + if n1 == n2 { Ok(SugaredTypeTerm::unit()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) } + } + (SugaredTypeTerm::Char(c1), SugaredTypeTerm::Char(c2)) => { + if c1 == c2 { Ok(SugaredTypeTerm::unit()) } else { Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) } + } + + /* + Complex Types + */ + + (SugaredTypeTerm::Seq{ seq_repr: lhs_seq_repr, items: lhs_items }, + SugaredTypeTerm::Seq { seq_repr: rhs_seq_repr, items: rhs_items }) + => { + if lhs_items.len() == rhs_items.len() && lhs_items.len() > 0 { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(0); + match self.eval_subtype( SugaredUnificationPair { addr: new_addr.clone(), lhs: lhs_items[0].clone(), rhs: rhs_items[0].clone() } ) { + Ok(ψ) => Ok(SugaredTypeTerm::Seq { + seq_repr: None, // <<- todo + items: vec![ψ] + }.strip()), + Err(e) => Err(SugaredUnificationError{ + addr: new_addr, + t1: e.t1, + t2: e.t2, + }) + } + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + (SugaredTypeTerm::Struct{ struct_repr: lhs_struct_repr, members: lhs_members }, + SugaredTypeTerm::Struct{ struct_repr: rhs_struct_repr, members: rhs_members }) + => { + if lhs_members.len() == rhs_members.len() { + let mut halo_members = Vec::new(); + for (i, + (SugaredStructMember{ symbol: lhs_symbol, ty: lhs_ty}, + SugaredStructMember{ symbol: rhs_symbol, ty: rhs_ty }) + ) in + lhs_members.into_iter().zip(rhs_members.into_iter()).enumerate() + { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + + let ψ = self.eval_subtype( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } )?; + halo_members.push(SugaredStructMember { symbol: lhs_symbol, ty: ψ }); + } + Ok(SugaredTypeTerm::Struct { + struct_repr: None, + members: halo_members + }) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + (SugaredTypeTerm::Enum{ enum_repr: lhs_enum_repr, variants: lhs_variants }, + SugaredTypeTerm::Enum{ enum_repr: rhs_enum_repr, variants: rhs_variants }) + => { + if lhs_variants.len() == rhs_variants.len() { + let mut halo_variants = Vec::new(); + for (i, + (SugaredEnumVariant{ symbol: lhs_symbol, ty: lhs_ty }, + SugaredEnumVariant{ symbol: rhs_symbol, ty: rhs_ty }) + ) in + lhs_variants.into_iter().zip(rhs_variants.into_iter()).enumerate() + { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + let ψ = self.eval_subtype( SugaredUnificationPair { addr: new_addr, lhs: lhs_ty.clone(), rhs: rhs_ty.clone() } )?; + halo_variants.push(SugaredEnumVariant { symbol: lhs_symbol, ty: ψ }); + } + Ok(SugaredTypeTerm::Enum { + enum_repr: None, + variants: halo_variants + }) + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + + + + /* + Ladders + */ + + (SugaredTypeTerm::Ladder(a1), SugaredTypeTerm::Ladder(a2)) => { + + let mut l1_iter = a1.into_iter().enumerate().rev(); + let mut l2_iter = a2.into_iter().rev(); + + let mut halo_ladder = Vec::new(); + + while let Some(rhs) = l2_iter.next() { + //eprintln!("take rhs = {:?}", rhs); + if let Some((i, lhs)) = l1_iter.next() { + //eprintln!("take lhs ({}) = {:?}", i, lhs); + let mut addr = unification_pair.addr.clone(); + addr.push(i); + //eprintln!("addr = {:?}", addr); + + match (lhs.clone(), rhs.clone()) { + (t, SugaredTypeTerm::TypeID(TypeID::Var(v))) => { + + if self.add_upper_subtype_bound(v,t.clone()).is_ok() { + let mut new_upper_bound_ladder = vec![ t ]; + + if let Some(next_rhs) = l2_iter.next() { + + // TODO + todo!(); + + } else { + // ladder of rhs is empty + // take everything + + while let Some((i,t)) = l1_iter.next() { + new_upper_bound_ladder.push(t); + } + } + + new_upper_bound_ladder.reverse(); + if self.add_upper_subtype_bound(v, SugaredTypeTerm::Ladder(new_upper_bound_ladder)).is_ok() { + // ok + } else { + return Err(SugaredUnificationError { + addr, + t1: lhs, + t2: rhs + }); + } + } else { + return Err(SugaredUnificationError { + addr, + t1: lhs, + t2: rhs + }); + } + } + (lhs, rhs) => { + if let Ok(ψ) = self.eval_subtype( + SugaredUnificationPair { + lhs: lhs.clone(), + rhs: rhs.clone(), + addr:addr.clone(), + } + ) { + // ok. + //eprintln!("rungs are subtypes. continue"); + halo_ladder.push(ψ); + } else { + return Err(SugaredUnificationError { + addr, + t1: lhs, + t2: rhs + }); + } + } + } + } else { + // not a subtype, + return Err(SugaredUnificationError { + addr: vec![], + t1: unification_pair.lhs, + t2: unification_pair.rhs + }); + } + } + //eprintln!("left ladder fully consumed"); + + for (i,t) in l1_iter { + //!("push {} to halo ladder", t.pretty(self.dict,0)); + halo_ladder.push(t); + } + halo_ladder.reverse(); + Ok(SugaredTypeTerm::Ladder(halo_ladder).strip())//.param_normalize()) + }, + + (t, SugaredTypeTerm::Ladder(a1)) => { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: t, t2: SugaredTypeTerm::Ladder(a1) }) + } + + (SugaredTypeTerm::Ladder(mut a1), t) => { + if a1.len() > 0 { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push( a1.len() -1 ); + if let Ok(halo) = self.eval_subtype( + SugaredUnificationPair { + lhs: a1.pop().unwrap(), + rhs: t.clone(), + addr: new_addr + } + ) { + a1.push(halo); + if a1.len() == 1 { + Ok(a1.pop().unwrap()) + } else { + Ok(SugaredTypeTerm::Ladder(a1)) + } + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: SugaredTypeTerm::Ladder(a1), t2: t }) + } + } else if t == SugaredTypeTerm::unit() { + Ok(SugaredTypeTerm::unit()) + } else { + Err(SugaredUnificationError { addr: unification_pair.addr, t1: SugaredTypeTerm::unit(), t2: t }) + } + } + + + /* + Application + */ + + (SugaredTypeTerm::Spec(a1), SugaredTypeTerm::Spec(a2)) => { + if a1.len() == a2.len() { + let mut halo_args = Vec::new(); + let mut n_halos_required = 0; + + for (i, (mut x, mut y)) in a1.iter().cloned().zip(a2.iter().cloned()).enumerate() { + let mut new_addr = unification_pair.addr.clone(); + new_addr.push(i); + + x = x.strip(); + +// eprintln!("before strip: {:?}", y); + y = y.strip(); +// eprintln!("after strip: {:?}", y); +// eprintln!("APP<> eval {:?} \n ?<=? {:?} ", x, y); + + match self.eval_subtype( + SugaredUnificationPair { + lhs: x.clone(), + rhs: y.clone(), + addr: new_addr, + } + ) { + Ok(halo) => { + if halo == SugaredTypeTerm::unit() { + let mut y = y.clone(); + y.apply_subst(&self.σ); + y = y.strip(); + + let top = y.get_interface_type(); + // eprintln!("add top {}", top.pretty(self.dict, 0)); + halo_args.push(top); + } else { + //println!("add halo {}", halo.pretty(self.dict, 0)); + if n_halos_required > 0 { + let x = &mut halo_args[n_halos_required-1]; + if let SugaredTypeTerm::Ladder(arg_rungs) = x { + let mut a = a2[n_halos_required-1].clone(); + a.apply_subst(&self.σ); + arg_rungs.push(a.get_interface_type()); + } else { + *x = SugaredTypeTerm::Ladder(vec![ + x.clone(), + a2[n_halos_required-1].get_interface_type() + ]); + + x.apply_subst(&self.σ); + } + } + + halo_args.push(halo); + n_halos_required += 1; + } + }, + Err(err) => { return Err(err); } + } + } + + if n_halos_required > 0 { + //eprintln!("halo args : {:?}", halo_args); + Ok(SugaredTypeTerm::Spec(halo_args)) + } else { + Ok(SugaredTypeTerm::unit()) + } + } else { + Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + + _ => Err(SugaredUnificationError{ addr: unification_pair.addr, t1: unification_pair.lhs, t2: unification_pair.rhs }) + } + } + + pub fn solve(mut self) -> Result<(Vec<SugaredTypeTerm>, HashMap<TypeID, SugaredTypeTerm>), SugaredUnificationError> { + // solve equations + while let Some( mut equal_pair ) = self.equal_pairs.pop() { + equal_pair.lhs.apply_subst(&self.σ); + equal_pair.rhs.apply_subst(&self.σ); + + self.eval_equation(equal_pair)?; + } + + // solve subtypes +// eprintln!("------ SOLVE SUBTYPES ---- "); + for mut subtype_pair in self.subtype_pairs.clone().into_iter() { + subtype_pair.lhs.apply_subst(&self.σ); + subtype_pair.rhs.apply_subst(&self.σ); + let _halo = self.eval_subtype( subtype_pair.clone() )?.strip(); + } + + // add variables from subtype bounds + for (var_id, t) in self.upper_bounds.iter() { +// eprintln!("VAR {} upper bound {:?}", var_id, t); + self.σ.insert(TypeID::Var(*var_id), t.clone().strip()); + } + + for (var_id, t) in self.lower_bounds.iter() { +// eprintln!("VAR {} lower bound {:?}", var_id, t); + self.σ.insert(TypeID::Var(*var_id), t.clone().strip()); + } + + self.reapply_subst(); + +// eprintln!("------ MAKE HALOS -----"); + let mut halo_types = Vec::new(); + for mut subtype_pair in self.subtype_pairs.clone().into_iter() { + subtype_pair.lhs = subtype_pair.lhs.apply_subst(&self.σ).clone().strip(); + subtype_pair.rhs = subtype_pair.rhs.apply_subst(&self.σ).clone().strip(); + + subtype_pair.lhs.apply_subst(&self.σ); + subtype_pair.rhs.apply_subst(&self.σ); + + // eprintln!("find halo.\n lhs={}", subtype_pair.lhs.pretty(self.dict,0)); + // eprintln!("rhs={}", subtype_pair.rhs.pretty(self.dict,0)); + + let halo = self.eval_subtype( subtype_pair.clone() )?.strip(); + halo_types.push(halo); + } + + // solve traits + while let Some( trait_pair ) = self.trait_pairs.pop() { + unimplemented!(); + } + + Ok((halo_types, self.σ)) + } +} + +pub fn unify( + t1: &SugaredTypeTerm, + t2: &SugaredTypeTerm +) -> Result<HashMap<TypeID, SugaredTypeTerm>, SugaredUnificationError> { + let unification = SugaredUnificationProblem::new_eq(vec![ SugaredUnificationPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]); + Ok(unification.solve()?.1) +} + +pub fn subtype_unify( + t1: &SugaredTypeTerm, + t2: &SugaredTypeTerm +) -> Result<(SugaredTypeTerm, HashMap<TypeID, SugaredTypeTerm>), SugaredUnificationError> { + let unification = SugaredUnificationProblem::new_sub(vec![ SugaredUnificationPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]); + unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(SugaredTypeTerm::unit()), σ) ) +} + +pub fn parallel_unify( + t1: &SugaredTypeTerm, + t2: &SugaredTypeTerm +) -> Result<(SugaredTypeTerm, HashMap<TypeID, SugaredTypeTerm>), SugaredUnificationError> { + let unification = SugaredUnificationProblem::new_parallel(vec![ SugaredUnificationPair{ lhs: t1.clone(), rhs: t2.clone(), addr:vec![] } ]); + unification.solve().map( |(halos,σ)| ( halos.first().cloned().unwrap_or(SugaredTypeTerm::unit()), σ) ) +} + +//<<<<>>>><<>><><<>><<<*>>><<>><><<>><<<<>>>>\\