parent
							
								
									9f69cfd65b
								
							
						
					
					
						commit
						3fc99af58b
					
				| @ -0,0 +1,138 @@ | ||||
| use std::{collections::HashSet, fmt::Display}; | ||||
| 
 | ||||
| use crate::parse::Ident; | ||||
| 
 | ||||
| use super::tagged::TypeTag; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum PrimitiveType { | ||||
|     Nat, | ||||
|     Bool, | ||||
|     Float, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum Type { | ||||
|     Variable(Ident),             // a
 | ||||
|     Primitive(PrimitiveType),    // Bool | Nat
 | ||||
|     Arrow(Box<Type>, Box<Type>), // 0 -> 1
 | ||||
| } | ||||
| 
 | ||||
| impl From<PrimitiveType> for Type { | ||||
|     fn from(value: PrimitiveType) -> Self { | ||||
|         Self::Primitive(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&str> for Type { | ||||
|     fn from(value: &str) -> Self { | ||||
|         Self::Variable(value.to_string()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Type { | ||||
|     pub fn arrow<T1: Into<Type>, T2: Into<Type>>(t1: T1, t2: T2) -> Self { | ||||
|         Self::Arrow(Box::new(t1.into()), Box::new(t2.into())) | ||||
|     } | ||||
| 
 | ||||
|     pub fn split_arrow(self) -> Option<(Type, Type)> { | ||||
|         match self { | ||||
|             Type::Arrow(lhs, rhs) => Some((*lhs, *rhs)), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_concrete(&self) -> bool { | ||||
|         match self { | ||||
|             Type::Variable(_) => false, | ||||
|             Type::Primitive(_) => true, | ||||
|             Type::Arrow(t1, t2) => t1.is_concrete() && t2.is_concrete(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn has_tag(&self, tag: &TypeTag) -> bool { | ||||
|         match self { | ||||
|             Type::Variable(_) => true, | ||||
|             Type::Primitive(primitive_type) => matches!( | ||||
|                 (primitive_type, tag), | ||||
|                 (_, TypeTag::Any) | (PrimitiveType::Nat | PrimitiveType::Float, TypeTag::Num) | ||||
|             ), | ||||
|             Type::Arrow(_, _) => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_name<F: Fn(&mut String)>(&mut self, f: &F) { | ||||
|         match self { | ||||
|             Type::Variable(v) => f(v), | ||||
|             Type::Arrow(lhs, rhs) => { | ||||
|                 lhs.map_name(f); | ||||
|                 rhs.map_name(f); | ||||
|             } | ||||
|             Type::Primitive(_) => {} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn name_used(&self, ident: &str) -> bool { | ||||
|         match self { | ||||
|             Type::Variable(i) if *i == ident => true, | ||||
|             Type::Arrow(lhs, rhs) => lhs.name_used(ident) || rhs.name_used(ident), | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_var(&self) -> Option<String> { | ||||
|         match self { | ||||
|             Type::Variable(v) => Some(v.clone()), | ||||
|             Type::Primitive(_) | Type::Arrow(_, _) => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_vars(&self) -> HashSet<String> { | ||||
|         match self { | ||||
|             Type::Variable(v) => { | ||||
|                 let mut set = HashSet::new(); | ||||
|                 set.insert(v.to_string()); | ||||
|                 set | ||||
|             } | ||||
|             Type::Primitive(_) => HashSet::new(), | ||||
|             Type::Arrow(lhs, rhs) => { | ||||
|                 let mut vars = lhs.type_vars(); | ||||
|                 for var in rhs.type_vars() { | ||||
|                     vars.insert(var); | ||||
|                 } | ||||
|                 vars | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn specialize(self, ident: &str, typ: &Type) -> Type { | ||||
|         match self { | ||||
|             Type::Variable(i) if i == ident => typ.clone(), | ||||
|             Type::Arrow(lhs, rhs) => Type::Arrow( | ||||
|                 Box::new(lhs.specialize(ident, typ)), | ||||
|                 Box::new(rhs.specialize(ident, typ)), | ||||
|             ), | ||||
|             t => t, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for Type { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             Type::Variable(i) => write!(f, "{i}"), | ||||
|             Type::Primitive(primitive_type) => write!(f, "{primitive_type}"), | ||||
|             Type::Arrow(t1, t2) => write!(f, "({t1} -> {t2})"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for PrimitiveType { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             PrimitiveType::Nat => write!(f, "Nat"), | ||||
|             PrimitiveType::Bool => write!(f, "Bool"), | ||||
|             PrimitiveType::Float => write!(f, "Float"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| @ -1,363 +1,5 @@ | ||||
| use std::{ | ||||
|     collections::{HashMap, HashSet}, | ||||
|     fmt::Display, | ||||
|     mem, | ||||
|     rc::Rc, | ||||
|     str, | ||||
| }; | ||||
| mod concrete; | ||||
| mod tagged; | ||||
| 
 | ||||
| pub type Ident = String; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum PrimitiveType { | ||||
|     Nat, | ||||
|     Bool, | ||||
|     Float, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum TypeTag { | ||||
|     Num, | ||||
|     Any, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum TaggedType { | ||||
|     Tagged(TypeTag, Ident, Box<TaggedType>), | ||||
|     Concrete(Type), | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum Type { | ||||
|     Variable(Ident),             // a
 | ||||
|     Primitive(PrimitiveType),    // Bool | Nat
 | ||||
|     Arrow(Box<Type>, Box<Type>), // 0 -> 1
 | ||||
| } | ||||
| 
 | ||||
| impl From<Type> for TaggedType { | ||||
|     fn from(value: Type) -> Self { | ||||
|         Self::Concrete(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeTag { | ||||
|     // If one tag tightens the other return that tag, otherwise none,
 | ||||
|     pub fn tightens(self, other: Self) -> Option<Self> { | ||||
|         match (self, other) { | ||||
|             (TypeTag::Num, TypeTag::Num) => Some(Self::Num), | ||||
|             (TypeTag::Num, TypeTag::Any) => Some(Self::Num), | ||||
|             (TypeTag::Any, TypeTag::Num) => Some(Self::Num), | ||||
|             (TypeTag::Any, TypeTag::Any) => Some(Self::Any), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TaggedType { | ||||
|     pub fn r#type(&self) -> &Type { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, tagged_type) => tagged_type.r#type(), | ||||
|             TaggedType::Concrete(t) => t, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_mut(&mut self) -> &mut Type { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, tagged_type) => tagged_type.type_mut(), | ||||
|             TaggedType::Concrete(t) => t, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn into_concrete(self) -> Option<Type> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, _, tagged_type) => None, | ||||
|             TaggedType::Concrete(t) => Some(t), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn matches(&self, typ: &Type) -> (bool, Option<Ident>) { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 if typ.has_tag(type_tag) { | ||||
|                     (true, Some(ident.clone())) | ||||
|                 } else { | ||||
|                     tagged_type.matches(typ) | ||||
|                 } | ||||
|             } | ||||
|             TaggedType::Concrete(c) => (c == typ, None), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn split_arrow(self) -> Option<(TaggedType, TaggedType)> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 let (lhs, rhs) = tagged_type.split_arrow()?; | ||||
|                 Some(( | ||||
|                     TaggedType::Tagged(type_tag.clone(), ident.clone(), Box::new(lhs)) | ||||
|                         .clear_unused_names(), | ||||
|                     TaggedType::Tagged(type_tag, ident, Box::new(rhs)).clear_unused_names(), | ||||
|                 )) | ||||
|             } | ||||
|             TaggedType::Concrete(Type::Arrow(lhs, rhs)) => { | ||||
|                 Some((TaggedType::Concrete(*lhs), TaggedType::Concrete(*rhs))) | ||||
|             } | ||||
|             TaggedType::Concrete(_) => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn make_arrow(self, rhs: TaggedType) -> Self { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 TaggedType::Tagged(type_tag, ident, Box::new(tagged_type.make_arrow(rhs))) | ||||
|             } | ||||
|             TaggedType::Concrete(t) => rhs.make_arrow_lhs(t), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn make_arrow_lhs(self, lhs: Type) -> Self { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 TaggedType::Tagged(type_tag, ident, Box::new(tagged_type.make_arrow_lhs(lhs))) | ||||
|             } | ||||
|             TaggedType::Concrete(t) => Type::arrow(lhs, t).into(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn specialize(self, ident: &str, typ: &Type) -> TaggedType { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, i, tagged_type) if i == ident => { | ||||
|                 tagged_type.specialize(ident, typ) | ||||
|             } | ||||
|             TaggedType::Tagged(t, i, tagged_type) => { | ||||
|                 TaggedType::Tagged(t, i, Box::new(tagged_type.specialize(ident, typ))) | ||||
|             } | ||||
|             TaggedType::Concrete(c) => TaggedType::Concrete(c.specialize(ident, typ)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_name<F: Fn(&mut String)>(&mut self, f: F) { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 f(ident); | ||||
|                 tagged_type.map_name(f); | ||||
|             } | ||||
|             TaggedType::Concrete(t) => t.map_name(&f), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_var(&self) -> Option<String> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, _, tagged_type) => tagged_type.type_var(), | ||||
|             TaggedType::Concrete(c) => c.type_var(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn free_vars(&self) -> HashSet<String> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 let mut vars = tagged_type.free_vars(); | ||||
|                 vars.retain(|v| v != ident); | ||||
|                 vars | ||||
|             } | ||||
|             TaggedType::Concrete(c) => c.type_vars(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn name_used(&self, ident: &str) -> bool { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, tagged_type) => tagged_type.name_used(ident), | ||||
|             TaggedType::Concrete(c) => c.name_used(ident), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_concrete(&self) -> bool { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, _, tagged_type) => tagged_type.is_concrete(), | ||||
|             TaggedType::Concrete(c) => c.is_concrete(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn normalise(self) -> TaggedType { | ||||
|         let only_used = self.clear_unused_names(); | ||||
|         fn dedup(this: TaggedType, mut used: Rc<HashMap<String, TypeTag>>) -> TaggedType { | ||||
|             match this { | ||||
|                 TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                     if !used.contains_key(&ident) { | ||||
|                         Rc::make_mut(&mut used).insert(ident, type_tag); | ||||
|                         dedup(*tagged_type, used) | ||||
|                     } else { | ||||
|                         let Some(tag) = TypeTag::tightens( | ||||
|                             Rc::make_mut(&mut used).remove(&ident).unwrap(), | ||||
|                             type_tag, | ||||
|                         ) else { | ||||
|                             todo!() | ||||
|                         }; | ||||
|                         Rc::make_mut(&mut used).insert(ident.clone(), tag.clone()); | ||||
|                         dedup(*tagged_type, used) | ||||
|                     } | ||||
|                 } | ||||
|                 TaggedType::Concrete(c) => mem::take(Rc::make_mut(&mut used)) | ||||
|                     .into_iter() | ||||
|                     .fold(TaggedType::Concrete(c), |acc, (i, t)| { | ||||
|                         TaggedType::Tagged(t, i, Box::new(acc)) | ||||
|                     }), | ||||
|             } | ||||
|         } | ||||
| 
 | ||||
|         dedup(only_used, Rc::new(HashMap::new())) | ||||
|     } | ||||
| 
 | ||||
|     fn clear_unused_names(self) -> TaggedType { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 if tagged_type.name_used(&ident) { | ||||
|                     TaggedType::Tagged(type_tag, ident, Box::new(tagged_type.clear_unused_names())) | ||||
|                 } else { | ||||
|                     tagged_type.clear_unused_names() | ||||
|                 } | ||||
|             } | ||||
|             t => t, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<PrimitiveType> for Type { | ||||
|     fn from(value: PrimitiveType) -> Self { | ||||
|         Self::Primitive(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<&str> for Type { | ||||
|     fn from(value: &str) -> Self { | ||||
|         Self::Variable(value.to_string()) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Type { | ||||
|     pub fn arrow<T1: Into<Type>, T2: Into<Type>>(t1: T1, t2: T2) -> Self { | ||||
|         Self::Arrow(Box::new(t1.into()), Box::new(t2.into())) | ||||
|     } | ||||
| 
 | ||||
|     pub fn split_arrow(self) -> Option<(Type, Type)> { | ||||
|         match self { | ||||
|             Type::Arrow(lhs, rhs) => Some((*lhs, *rhs)), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_concrete(&self) -> bool { | ||||
|         match self { | ||||
|             Type::Variable(_) => false, | ||||
|             Type::Primitive(primitive_type) => true, | ||||
|             Type::Arrow(t1, t2) => t1.is_concrete() && t2.is_concrete(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn has_tag(&self, tag: &TypeTag) -> bool { | ||||
|         match self { | ||||
|             Type::Variable(_) => true, | ||||
|             Type::Primitive(primitive_type) => matches!( | ||||
|                 (primitive_type, tag), | ||||
|                 (_, TypeTag::Any) | ||||
|                     | (PrimitiveType::Nat, TypeTag::Num) | ||||
|                     | (PrimitiveType::Float, TypeTag::Num) | ||||
|             ), | ||||
|             Type::Arrow(_, _) => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_name<F: Fn(&mut String)>(&mut self, f: &F) { | ||||
|         match self { | ||||
|             Type::Variable(v) => f(v), | ||||
|             Type::Arrow(lhs, rhs) => { | ||||
|                 lhs.map_name(f); | ||||
|                 rhs.map_name(f); | ||||
|             } | ||||
|             _ => {} | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn name_used(&self, ident: &str) -> bool { | ||||
|         match self { | ||||
|             Type::Variable(i) if *i == ident => true, | ||||
|             Type::Arrow(lhs, rhs) => lhs.name_used(ident) || rhs.name_used(ident), | ||||
|             _ => false, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_var(&self) -> Option<String> { | ||||
|         match self { | ||||
|             Type::Variable(v) => Some(v.clone()), | ||||
|             Type::Primitive(primitive_type) => None, | ||||
|             Type::Arrow(_, _) => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_vars(&self) -> HashSet<String> { | ||||
|         match self { | ||||
|             Type::Variable(v) => { | ||||
|                 let mut set = HashSet::new(); | ||||
|                 set.insert(v.to_string()); | ||||
|                 set | ||||
|             } | ||||
|             Type::Primitive(primitive_type) => HashSet::new(), | ||||
|             Type::Arrow(lhs, rhs) => { | ||||
|                 let mut vars = lhs.type_vars(); | ||||
|                 for var in rhs.type_vars().into_iter() { | ||||
|                     vars.insert(var); | ||||
|                 } | ||||
|                 vars | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn specialize(self, ident: &str, typ: &Type) -> Type { | ||||
|         match self { | ||||
|             Type::Variable(i) if i == ident => typ.clone(), | ||||
|             Type::Arrow(lhs, rhs) => Type::Arrow( | ||||
|                 Box::new(lhs.specialize(ident, typ)), | ||||
|                 Box::new(rhs.specialize(ident, typ)), | ||||
|             ), | ||||
|             t => t, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for TypeTag { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             TypeTag::Num => write!(f, "Num"), | ||||
|             TypeTag::Any => write!(f, "Any"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for TaggedType { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 write!(f, "{type_tag} {ident} => {tagged_type}") | ||||
|             } | ||||
|             TaggedType::Concrete(t) => write!(f, "{t}"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for Type { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             Type::Variable(i) => write!(f, "{i}"), | ||||
|             Type::Primitive(primitive_type) => write!(f, "{primitive_type}"), | ||||
|             Type::Arrow(t1, t2) => write!(f, "({t1} -> {t2})"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for PrimitiveType { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             PrimitiveType::Nat => write!(f, "Nat"), | ||||
|             PrimitiveType::Bool => write!(f, "Bool"), | ||||
|             PrimitiveType::Float => write!(f, "Float"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| pub use concrete::{PrimitiveType, Type}; | ||||
| pub use tagged::{TaggedType, TypeTag}; | ||||
|  | ||||
| @ -0,0 +1,180 @@ | ||||
| use std::{collections::HashSet, fmt::Display}; | ||||
| 
 | ||||
| use crate::parse::Ident; | ||||
| 
 | ||||
| use super::concrete::Type; | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| #[non_exhaustive] | ||||
| pub enum TypeTag { | ||||
|     Num, | ||||
|     Any, | ||||
| } | ||||
| 
 | ||||
| #[derive(Debug, Clone, PartialEq, Eq, Hash)] | ||||
| pub enum TaggedType { | ||||
|     Tagged(TypeTag, Ident, Box<TaggedType>), | ||||
|     Concrete(Type), | ||||
| } | ||||
| 
 | ||||
| impl From<Type> for TaggedType { | ||||
|     fn from(value: Type) -> Self { | ||||
|         Self::Concrete(value) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TypeTag { | ||||
|     // If one tag tightens the other return that tag, otherwise none,
 | ||||
|     pub fn tightens(self, other: Self) -> Option<Self> { | ||||
|         #[allow(unreachable_patterns)] // #[non_exhaustive] doesn't apply with tuples
 | ||||
|         match (self, other) { | ||||
|             (TypeTag::Any, t) | (t, TypeTag::Any) => Some(t), | ||||
|             (TypeTag::Num, TypeTag::Num) => Some(Self::Num), | ||||
|             _ => None, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl TaggedType { | ||||
|     pub fn into_concrete(self) -> Option<Type> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, _) => None, | ||||
|             TaggedType::Concrete(t) => Some(t), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn matches(&self, typ: &Type) -> (bool, Option<Ident>) { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 if typ.has_tag(type_tag) { | ||||
|                     (true, Some(ident.clone())) | ||||
|                 } else { | ||||
|                     tagged_type.matches(typ) | ||||
|                 } | ||||
|             } | ||||
|             TaggedType::Concrete(c) => (c == typ, None), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn split_arrow(self) -> Option<(TaggedType, TaggedType)> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 let (lhs, rhs) = tagged_type.split_arrow()?; | ||||
|                 Some(( | ||||
|                     TaggedType::Tagged(type_tag.clone(), ident.clone(), Box::new(lhs)) | ||||
|                         .clear_unused_names(), | ||||
|                     TaggedType::Tagged(type_tag, ident, Box::new(rhs)).clear_unused_names(), | ||||
|                 )) | ||||
|             } | ||||
|             TaggedType::Concrete(Type::Arrow(lhs, rhs)) => { | ||||
|                 Some((TaggedType::Concrete(*lhs), TaggedType::Concrete(*rhs))) | ||||
|             } | ||||
|             TaggedType::Concrete(_) => None, | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn make_arrow(self, rhs: TaggedType) -> Self { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 TaggedType::Tagged(type_tag, ident, Box::new(tagged_type.make_arrow(rhs))) | ||||
|             } | ||||
|             TaggedType::Concrete(t) => rhs.make_arrow_lhs(t), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn make_arrow_lhs(self, lhs: Type) -> Self { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 TaggedType::Tagged(type_tag, ident, Box::new(tagged_type.make_arrow_lhs(lhs))) | ||||
|             } | ||||
|             TaggedType::Concrete(t) => Type::arrow(lhs, t).into(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn specialize(self, ident: &str, typ: &Type) -> TaggedType { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, i, tagged_type) if i == ident => { | ||||
|                 tagged_type.specialize(ident, typ) | ||||
|             } | ||||
|             TaggedType::Tagged(t, i, tagged_type) => { | ||||
|                 TaggedType::Tagged(t, i, Box::new(tagged_type.specialize(ident, typ))) | ||||
|             } | ||||
|             TaggedType::Concrete(c) => TaggedType::Concrete(c.specialize(ident, typ)), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn map_name<F: Fn(&mut String)>(&mut self, f: F) { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, ident, tagged_type) => { | ||||
|                 f(ident); | ||||
|                 tagged_type.map_name(f); | ||||
|             } | ||||
|             TaggedType::Concrete(t) => t.map_name(&f), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn type_var(&self) -> Option<String> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, tagged_type) => tagged_type.type_var(), | ||||
|             TaggedType::Concrete(c) => c.type_var(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn free_vars(&self) -> HashSet<String> { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, ident, tagged_type) => { | ||||
|                 let mut vars = tagged_type.free_vars(); | ||||
|                 vars.retain(|v| v != ident); | ||||
|                 vars | ||||
|             } | ||||
|             TaggedType::Concrete(c) => c.type_vars(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn name_used(&self, ident: &str) -> bool { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, tagged_type) => tagged_type.name_used(ident), | ||||
|             TaggedType::Concrete(c) => c.name_used(ident), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     pub fn is_concrete(&self) -> bool { | ||||
|         match self { | ||||
|             TaggedType::Tagged(_, _, tagged_type) => tagged_type.is_concrete(), | ||||
|             TaggedType::Concrete(c) => c.is_concrete(), | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
|     fn clear_unused_names(self) -> TaggedType { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 if tagged_type.name_used(&ident) { | ||||
|                     TaggedType::Tagged(type_tag, ident, Box::new(tagged_type.clear_unused_names())) | ||||
|                 } else { | ||||
|                     tagged_type.clear_unused_names() | ||||
|                 } | ||||
|             } | ||||
|             t @ TaggedType::Concrete(_) => t, | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for TypeTag { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             TypeTag::Num => write!(f, "Num"), | ||||
|             TypeTag::Any => write!(f, "Any"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl Display for TaggedType { | ||||
|     fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result { | ||||
|         match self { | ||||
|             TaggedType::Tagged(type_tag, ident, tagged_type) => { | ||||
|                 write!(f, "{type_tag} {ident} => {tagged_type}") | ||||
|             } | ||||
|             TaggedType::Concrete(t) => write!(f, "{t}"), | ||||
|         } | ||||
|     } | ||||
| } | ||||
					Loading…
					
					
				
		Reference in new issue