diff --git a/analysis/src/class.rs b/analysis/src/class.rs index e94d115..f1e7e52 100644 --- a/analysis/src/class.rs +++ b/analysis/src/class.rs @@ -23,11 +23,7 @@ impl Class { .as_ref() .expect("Class associated types must be known here") .iter() - .find_map(|a| if *a.name == assoc { - Some(()) - } else { - None - }) + .find_map(|a| if *a.name == assoc { Some(()) } else { None }) } pub fn field(&self, field: Ident) -> Option<&SrcNode> { @@ -35,11 +31,7 @@ impl Class { .as_ref() .expect("Class fields must be known here") .iter() - .find_map(|f| if *f.name == field { - Some(&f.ty) - } else { - None - }) + .find_map(|f| if *f.name == field { Some(&f.ty) } else { None }) } } @@ -79,11 +71,17 @@ impl Classes { } pub fn iter(&self) -> impl Iterator { - self.classes.iter().enumerate().map(|(i, class)| (ClassId(i), class)) + self.classes + .iter() + .enumerate() + .map(|(i, class)| (ClassId(i), class)) } pub fn iter_members(&self) -> impl Iterator { - self.members.iter().enumerate().map(|(i, member)| (MemberId(i), member)) + self.members + .iter() + .enumerate() + .map(|(i, member)| (MemberId(i), member)) } pub fn class_gen_scope(&self, class: ClassId) -> GenScopeId { @@ -100,22 +98,45 @@ impl Classes { if let Err(old) = self.lut.try_insert(*name, (span, id)) { Err(Error::DuplicateClassName(*name, old.entry.get().0, span)) } else { - if let Some(lang) = class.attr + if let Some(lang) = class + .attr .iter() .find(|a| &**a.name == "lang") .and_then(|a| a.args.as_ref()) { - if lang.iter().find(|a| &**a.name == "not").is_some() { self.lang.not = Some(id); } - if lang.iter().find(|a| &**a.name == "neg").is_some() { self.lang.neg = Some(id); } - if lang.iter().find(|a| &**a.name == "add").is_some() { self.lang.add = Some(id); } - if lang.iter().find(|a| &**a.name == "sub").is_some() { self.lang.sub = Some(id); } - if lang.iter().find(|a| &**a.name == "mul").is_some() { self.lang.mul = Some(id); } - if lang.iter().find(|a| &**a.name == "div").is_some() { self.lang.div = Some(id); } - if lang.iter().find(|a| &**a.name == "eq").is_some() { self.lang.eq = Some(id); } - if lang.iter().find(|a| &**a.name == "ord_ext").is_some() { self.lang.ord_ext = Some(id); } - if lang.iter().find(|a| &**a.name == "and_").is_some() { self.lang.and = Some(id); } - if lang.iter().find(|a| &**a.name == "or_").is_some() { self.lang.or = Some(id); } - if lang.iter().find(|a| &**a.name == "join").is_some() { self.lang.join = Some(id); } + if lang.iter().any(|a| &**a.name == "not") { + self.lang.not = Some(id); + } + if lang.iter().any(|a| &**a.name == "neg") { + self.lang.neg = Some(id); + } + if lang.iter().any(|a| &**a.name == "add") { + self.lang.add = Some(id); + } + if lang.iter().any(|a| &**a.name == "sub") { + self.lang.sub = Some(id); + } + if lang.iter().any(|a| &**a.name == "mul") { + self.lang.mul = Some(id); + } + if lang.iter().any(|a| &**a.name == "div") { + self.lang.div = Some(id); + } + if lang.iter().any(|a| &**a.name == "eq") { + self.lang.eq = Some(id); + } + if lang.iter().any(|a| &**a.name == "ord_ext") { + self.lang.ord_ext = Some(id); + } + if lang.iter().any(|a| &**a.name == "and_") { + self.lang.and = Some(id); + } + if lang.iter().any(|a| &**a.name == "or_") { + self.lang.or = Some(id); + } + if lang.iter().any(|a| &**a.name == "join") { + self.lang.join = Some(id); + } } self.classes.push(class); @@ -126,17 +147,39 @@ impl Classes { pub fn check_lang_items(&self) -> Vec { let mut errors = Vec::new(); - if self.lang.not.is_none() { errors.push(Error::MissingLangItem("not")); } - if self.lang.neg.is_none() { errors.push(Error::MissingLangItem("neg")); } - if self.lang.add.is_none() { errors.push(Error::MissingLangItem("add")); } - if self.lang.sub.is_none() { errors.push(Error::MissingLangItem("sub")); } - if self.lang.mul.is_none() { errors.push(Error::MissingLangItem("mul")); } - if self.lang.div.is_none() { errors.push(Error::MissingLangItem("div")); } - if self.lang.eq.is_none() { errors.push(Error::MissingLangItem("eq")); } - if self.lang.ord_ext.is_none() { errors.push(Error::MissingLangItem("ord_ext")); } - if self.lang.and.is_none() { errors.push(Error::MissingLangItem("and_")); } - if self.lang.or.is_none() { errors.push(Error::MissingLangItem("or_")); } - if self.lang.join.is_none() { errors.push(Error::MissingLangItem("join")); } + if self.lang.not.is_none() { + errors.push(Error::MissingLangItem("not")); + } + if self.lang.neg.is_none() { + errors.push(Error::MissingLangItem("neg")); + } + if self.lang.add.is_none() { + errors.push(Error::MissingLangItem("add")); + } + if self.lang.sub.is_none() { + errors.push(Error::MissingLangItem("sub")); + } + if self.lang.mul.is_none() { + errors.push(Error::MissingLangItem("mul")); + } + if self.lang.div.is_none() { + errors.push(Error::MissingLangItem("div")); + } + if self.lang.eq.is_none() { + errors.push(Error::MissingLangItem("eq")); + } + if self.lang.ord_ext.is_none() { + errors.push(Error::MissingLangItem("ord_ext")); + } + if self.lang.and.is_none() { + errors.push(Error::MissingLangItem("and_")); + } + if self.lang.or.is_none() { + errors.push(Error::MissingLangItem("or_")); + } + if self.lang.join.is_none() { + errors.push(Error::MissingLangItem("join")); + } errors } @@ -162,11 +205,21 @@ impl Classes { id } - pub fn define_member_assoc(&mut self, id: MemberId, class: ClassId, assoc: HashMap) { + pub fn define_member_assoc( + &mut self, + id: MemberId, + _class: ClassId, + assoc: HashMap, + ) { self.members[id.0].assoc = Some(assoc); } - pub fn define_member_fields(&mut self, id: MemberId, class: ClassId, fields: HashMap) { + pub fn define_member_fields( + &mut self, + id: MemberId, + _class: ClassId, + fields: HashMap, + ) { self.members[id.0].fields = Some(fields); } @@ -184,26 +237,30 @@ impl Classes { member: TyId, ty: ConTyId, gen_ty_links: &mut HashMap, - gen_eff_links: &mut HashMap, ) -> bool { match (hir.tys.get(member), ctx.get_ty(ty)) { (Ty::Gen(idx, _), _) => *gen_ty_links.entry(idx).or_insert(ty) == ty, (Ty::Prim(a), ConTy::Prim(b)) if a == *b => true, - (Ty::List(x), ConTy::List(y)) => covers(hir, ctx, x, *y, gen_ty_links, gen_eff_links), + (Ty::List(x), ConTy::List(y)) => { + covers(hir, ctx, x, *y, gen_ty_links) + } // TODO: Care about field names! (Ty::Record(xs, _), ConTy::Record(ys)) if xs.len() == ys.len() => xs .into_iter() - .zip(ys.into_iter()) - .all(|((_, x), (_, y))| covers(hir, ctx, x, *y, gen_ty_links, gen_eff_links)), + .zip(ys.iter()) + .all(|((_, x), (_, y))| covers(hir, ctx, x, *y, gen_ty_links)), (Ty::Func(x_i, x_o), ConTy::Func(y_i, y_o)) => { - covers(hir, ctx, x_i, *y_i, gen_ty_links, gen_eff_links) && covers(hir, ctx, x_o, *y_o, gen_ty_links, gen_eff_links) - }, - (Ty::Data(x, xs), ConTy::Data(y)) if x == y.0.0 && xs.len() == y.0.1.len() => xs + covers(hir, ctx, x_i, *y_i, gen_ty_links) + && covers(hir, ctx, x_o, *y_o, gen_ty_links) + } + (Ty::Data(x, xs), ConTy::Data(y)) if x == y.0 .0 && xs.len() == y.0 .1.len() => xs .into_iter() - .zip(y.0.1.iter()) - .all(|(x, y)| covers(hir, ctx, x, *y, gen_ty_links, gen_eff_links)), + .zip(y.0 .1.iter()) + .all(|(x, y)| covers(hir, ctx, x, *y, gen_ty_links)), // Flatten empty effects - (_, ConTy::Effect(eff, ty)) if eff.is_empty() => covers(hir, ctx, member, *ty, gen_ty_links, gen_eff_links), + (_, ConTy::Effect(eff, ty)) if eff.is_empty() => { + covers(hir, ctx, member, *ty, gen_ty_links) + } (Ty::Effect(_, _), ConTy::Effect(_, _)) => todo!(), (Ty::Error(_), _) => panic!("Error ty during monomorphisation"), _ => false, @@ -212,11 +269,11 @@ impl Classes { fn covers_eff( hir: &Context, - ctx: &ConContext, + _ctx: &ConContext, member: EffectId, effs: &[ConEffectId], - gen_ty_links: &mut HashMap, - gen_eff_links: &mut HashMap, + _gen_ty_links: &mut HashMap, + _gen_eff_links: &mut HashMap, ) -> bool { match (hir.tys.get_effect(member), effs) { (Effect::Known(member_effs), effs) if member_effs.len() <= 1 || effs.len() <= 1 => effs @@ -224,7 +281,7 @@ impl Classes { .all(|eff| member_effs .iter() .any(|member_eff| match (member_eff, eff) { - (Ok(EffectInst::Gen(idx, _)), eff) => { + (Ok(EffectInst::Gen(_idx, _)), _eff) => { // println!("Compare {:?} with {:?}", gen_eff_links.get(idx), eff); // gen_eff_links.entry(*idx).or_insert(*eff) == eff // TODO: Is this correct? Can all generics be assumed to match?! @@ -237,62 +294,84 @@ impl Classes { } } - self.member_lut - .get(&class) - .and_then(|xs| { - let candidates = xs - .iter() + self.member_lut.get(&class).and_then(|xs| { + let candidates = + xs.iter() .filter(|m| { let member = self.get_member(**m); let mut gen_ty_links = HashMap::new(); let mut gen_eff_links = HashMap::new(); - covers(hir, ctx, member.member, ty, &mut gen_ty_links, &mut gen_eff_links) - && member.gen_tys.iter() - .zip(gen_tys.iter()) - .all(|(member_gen_ty, gen_ty)| covers(hir, ctx, *member_gen_ty, *gen_ty, &mut gen_ty_links, &mut gen_eff_links)) - && member.gen_effs.iter() - .zip(gen_effs.iter()) - .all(|(member_gen_eff, gen_eff)| covers_eff(hir, ctx, member_gen_eff.expect("Error eff during monomorphisation"), gen_eff, &mut gen_ty_links, &mut gen_eff_links)) + covers( + hir, + ctx, + member.member, + ty, + &mut gen_ty_links, + ) && member.gen_tys.iter().zip(gen_tys.iter()).all( + |(member_gen_ty, gen_ty)| { + covers( + hir, + ctx, + *member_gen_ty, + *gen_ty, + &mut gen_ty_links, + ) + }, + ) && member.gen_effs.iter().zip(gen_effs.iter()).all( + |(member_gen_eff, gen_eff)| { + covers_eff( + hir, + ctx, + member_gen_eff.expect("Error eff during monomorphisation"), + gen_eff, + &mut gen_ty_links, + &mut gen_eff_links, + ) + }, + ) }) .collect::>(); - assert!( - candidates.len() <= 1, - "Multiple member candidates detected during lowering <{:?} as {:?}>.\n\ + assert!( + candidates.len() <= 1, + "Multiple member candidates detected during lowering <{:?} as {:?}>.\n\ This means that incoherence has occurred!\n\ Candidate members:\n{}", - ctx.get_ty(ty), - **self.get(class).name, - candidates - .iter() - .map(|c| { - let c = self.get_member(**c); - let gen_scope = hir.tys.get_gen_scope(c.gen_scope); - format!( - "- {}member {} of {}{} (in {})\n", - if gen_scope.len() == 0 { - String::new() - } else { - format!("for {} ", (0..gen_scope.len()) + ctx.get_ty(ty), + **self.get(class).name, + candidates + .iter() + .map(|c| { + let c = self.get_member(**c); + let gen_scope = hir.tys.get_gen_scope(c.gen_scope); + format!( + "- {}member {} of {}{} (in {})\n", + if gen_scope.is_empty() { + String::new() + } else { + format!( + "for {} ", + (0..gen_scope.len()) .map(|idx| format!("{}", *gen_scope.get(idx).name)) .collect::>() - .join(", ")) - }, - hir.tys.display(hir, c.member), - **self.get(class).name, - c.gen_tys - .iter() - .map(|ty| format!(" {}", hir.tys.display(hir, *ty))) - .collect::(), - hir.tys.get_span(c.member).src(), - ) - }) - .collect::>() - .join("") - ); - - candidates.first().copied().copied() - }) + .join(", ") + ) + }, + hir.tys.display(hir, c.member), + **self.get(class).name, + c.gen_tys + .iter() + .map(|ty| format!(" {}", hir.tys.display(hir, *ty))) + .collect::(), + hir.tys.get_span(c.member).src(), + ) + }) + .collect::>() + .join("") + ); + + candidates.first().copied().copied() + }) } pub fn members_of(&self, class: ClassId) -> impl Iterator { @@ -306,14 +385,8 @@ impl Classes { } pub enum MemberItem { - Value { - name: SrcNode, - val: TyExpr, - }, - Type { - name: SrcNode, - ty: TyId, - }, + Value { name: SrcNode, val: TyExpr }, + Type { name: SrcNode, ty: TyId }, } pub struct Member { diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index 7b12674..4b92d4d 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -17,10 +17,13 @@ pub enum ConTy { pub struct ConTyId(usize); impl ConTyId { - pub fn id(&self) -> u64 { self.0 as u64 } + pub fn id(&self) -> u64 { + self.0 as u64 + } } #[derive(Debug)] +#[allow(dead_code)] pub struct ConEffect { send: ConTyId, recv: ConTyId, @@ -29,7 +32,13 @@ pub struct ConEffect { #[derive(Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] pub enum ConProc { Def(DefId, Vec, Vec>), - Field(ConTyId, MemberId, Vec, Vec>, Ident), + Field( + ConTyId, + MemberId, + Vec, + Vec>, + Ident, + ), } #[derive(Copy, Clone, PartialEq, Eq, Hash, PartialOrd, Ord)] @@ -38,23 +47,33 @@ pub struct ConProcId(Intern); impl fmt::Debug for ConProcId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { match &*self.0 { - ConProc::Def(def, gen_tys, gen_effs) if gen_tys.is_empty() && gen_effs.is_empty() => write!(f, "{:?}", def), - ConProc::Def(def, gen_tys, gen_effs) => write!(f, "{:?}::<{}>", def, gen_tys - .iter() - .map(|a| format!("{:?}", a)) - .chain(gen_effs + ConProc::Def(def, gen_tys, gen_effs) if gen_tys.is_empty() && gen_effs.is_empty() => { + write!(f, "{:?}", def) + } + ConProc::Def(def, gen_tys, gen_effs) => write!( + f, + "{:?}::<{}>", + def, + gen_tys .iter() - .map(|e| format!("{:?}", e))) - .collect::>() - .join(", ")), - ConProc::Field(ty, member, gen_tys, gen_effs, field) => write!(f, "<{:?} as {:?} {}>.{}", ty, member, gen_tys - .iter() - .map(|ty| format!("{:?}", ty)) - .chain(gen_effs + .map(|a| format!("{:?}", a)) + .chain(gen_effs.iter().map(|e| format!("{:?}", e))) + .collect::>() + .join(", ") + ), + ConProc::Field(ty, member, gen_tys, gen_effs, field) => write!( + f, + "<{:?} as {:?} {}>.{}", + ty, + member, + gen_tys .iter() - .map(|eff| format!("{:?}", eff))) - .collect::>() - .join(", "), field), + .map(|ty| format!("{:?}", ty)) + .chain(gen_effs.iter().map(|eff| format!("{:?}", eff))) + .collect::>() + .join(", "), + field + ), } } } @@ -63,19 +82,27 @@ impl fmt::Debug for ConProcId { pub struct ConDataId(pub(crate) Intern<(DataId, Vec, Vec>)>); impl ConDataId { - pub fn data_id(&self) -> DataId { self.0.0 } + pub fn data_id(&self) -> DataId { + self.0 .0 + } } impl fmt::Debug for ConDataId { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if self.0.1.is_empty() { - write!(f, "{:?}", self.0.0) + if self.0 .1.is_empty() { + write!(f, "{:?}", self.0 .0) } else { - write!(f, "{:?}::<{}>", self.0.0, self.0.1 - .iter() - .map(|a| format!("{:?}", a)) - .collect::>() - .join(", ")) + write!( + f, + "{:?}::<{}>", + self.0 .0, + self.0 + .1 + .iter() + .map(|a| format!("{:?}", a)) + .collect::>() + .join(", ") + ) } } } @@ -122,38 +149,49 @@ impl ConContext { let mut errors = Vec::new(); - let mut entries = hir.defs + let mut entries = hir + .defs .iter() - .filter_map(|(id, def)| if def.attr - .iter() - .find(|attr| attr.name.as_str() == "entry") - .is_some() - { - Some((id, def)) - } else { - None + .filter_map(|(id, def)| { + if def + .attr + .iter() + .any(|attr| attr.name.as_str() == "entry") + { + Some((id, def)) + } else { + None + } }) .collect::>(); // If no entry point attribute exists, use 'main' if entries.is_empty() { - entries.extend(hir.defs - .lookup(Ident::new("main")) - .map(|id| (id, hir.defs.get(id)))); + entries.extend( + hir.defs + .lookup(Ident::new("main")) + .map(|id| (id, hir.defs.get(id))), + ); } let mut entries = entries.into_iter(); if let Some((id, main)) = entries.next() { if let Some((_, second)) = entries.next() { - errors.push(Error::MultipleEntryPoints(main.name.span(), second.name.span())); + errors.push(Error::MultipleEntryPoints( + main.name.span(), + second.name.span(), + )); } let gen_scope = hir.tys.get_gen_scope(main.gen_scope); - if gen_scope.len() == 0 && gen_scope.len_eff() == 0 { + if gen_scope.is_empty() && gen_scope.len_eff() == 0 { let main_def = ConProcId(Intern::new(ConProc::Def(id, Vec::new(), Vec::new()))); this.lower_proc(hir, main_def); this.entry = Some(main_def); } else { - errors.push(Error::GenericEntryPoint(main.name.clone(), gen_scope.get(0).name.span())); + errors.push(Error::GenericEntryPoint( + main.name.clone(), + gen_scope.get(0).name.span(), + )); } } else { errors.push(Error::NoEntryPoint(hir.root_span)); @@ -163,7 +201,7 @@ impl ConContext { } pub fn entry_proc(&self) -> ConProcId { - self.entry.clone().unwrap() + self.entry.unwrap() } pub fn get_proc(&self, proc: ConProcId) -> &ConExpr { @@ -176,7 +214,9 @@ impl ConContext { } pub fn get_data(&self, data: ConDataId) -> &ConData { - self.datas[&data].as_ref().expect("Data should be fully defined") + self.datas[&data] + .as_ref() + .expect("Data should be fully defined") } pub fn get_effect(&self, eff: ConEffectId) -> &ConEffect { @@ -184,13 +224,11 @@ impl ConContext { } pub fn insert_ty(&mut self, ty: ConTy) -> ConTyId { - *self.ty_lookup - .entry(ty.clone()) - .or_insert_with(|| { - let id = ConTyId(self.tys.len()); - self.tys.push(ty); - id - }) + *self.ty_lookup.entry(ty.clone()).or_insert_with(|| { + let id = ConTyId(self.tys.len()); + self.tys.push(ty); + id + }) } fn derive_links( @@ -204,25 +242,32 @@ impl ConContext { match (hir.tys.get(member), self.get_ty(ty)) { (Ty::Prim(x), ConTy::Prim(y)) => assert_eq!(x, *y), (Ty::Gen(gen_idx, _), _) => ty_link_gen(gen_idx, ty), - (Ty::List(x), ConTy::List(y)) => self.derive_links(hir, x, *y, ty_link_gen, eff_link_gen), - (Ty::Record(xs, _), ConTy::Record(ys)) => xs - .into_iter() - .zip(ys.into_iter()) - .for_each(|((_, x), (_, y))| self.derive_links(hir, x, *y, ty_link_gen, eff_link_gen)), + (Ty::List(x), ConTy::List(y)) => { + self.derive_links(hir, x, *y, ty_link_gen, eff_link_gen) + } + (Ty::Record(xs, _), ConTy::Record(ys)) => { + xs.into_iter() + .zip(ys.iter()) + .for_each(|((_, x), (_, y))| { + self.derive_links(hir, x, *y, ty_link_gen, eff_link_gen) + }) + } (Ty::Func(x_i, x_o), ConTy::Func(y_i, y_o)) => { self.derive_links(hir, x_i, *y_i, ty_link_gen, eff_link_gen); self.derive_links(hir, x_o, *y_o, ty_link_gen, eff_link_gen); - }, + } (Ty::Data(_, xs), ConTy::Data(y)) => xs .into_iter() - .zip(y.0.1.iter()) + .zip(y.0 .1.iter()) .for_each(|(x, y)| self.derive_links(hir, x, *y, ty_link_gen, eff_link_gen)), (Ty::Effect(xs, x_out), ConTy::Effect(ys, y_out)) => { self.derive_links_effect(hir, xs, ys, ty_link_gen, eff_link_gen); self.derive_links(hir, x_out, *y_out, ty_link_gen, eff_link_gen); - }, + } // Flatten empty effects - (_, ConTy::Effect(effs, ty)) if effs.is_empty() => self.derive_links(hir, member, *ty, ty_link_gen, eff_link_gen), + (_, ConTy::Effect(effs, ty)) if effs.is_empty() => { + self.derive_links(hir, member, *ty, ty_link_gen, eff_link_gen) + } (x, y) => todo!("{:?}", (x, y)), } } @@ -238,20 +283,29 @@ impl ConContext { // TODO: link gen for effects when polymorphic effects are added match (hir.tys.get_effect(member), effs) { // Assumption here is that canonical ordering has been generated! - (Effect::Known(member_effs), _) if member_effs.len() <= 1 => member_effs - .iter() - .for_each(|effect| match effect.as_ref().expect("effect instance cannot be an error") { - EffectInst::Concrete(_, args) => args - .iter() - .zip(&effs[0].1) - .for_each(|(x, y)| self.derive_links(hir, *x, *y, ty_link_gen, eff_link_gen)), - EffectInst::Gen(idx, _) => eff_link_gen(*idx, effs.to_vec()), - }), + (Effect::Known(member_effs), _) if member_effs.len() <= 1 => { + member_effs.iter().for_each(|effect| { + match effect.as_ref().expect("effect instance cannot be an error") { + EffectInst::Concrete(_, args) => { + args.iter().zip(&effs[0].1).for_each(|(x, y)| { + self.derive_links(hir, *x, *y, ty_link_gen, eff_link_gen) + }) + } + EffectInst::Gen(idx, _) => eff_link_gen(*idx, effs.to_vec()), + } + }) + } x => todo!("{:?}", x), } } - pub fn lower_data(&mut self, hir: &Context, data: DataId, gen_tys: &[ConTyId], gen_effs: &[Vec]) -> ConDataId { + pub fn lower_data( + &mut self, + hir: &Context, + data: DataId, + gen_tys: &[ConTyId], + gen_effs: &[Vec], + ) -> ConDataId { let id = ConDataId(Intern::new((data, gen_tys.to_vec(), gen_effs.to_vec()))); if let Some(data) = self.datas.get_mut(&id) { if let Err(is_recursive) = data { @@ -262,19 +316,36 @@ impl ConContext { self.datas.insert(id, Err(false)); // Prevent overflow with phoney value let mut data = ConData { is_recursive: false, - cons: hir.datas + cons: hir + .datas .get_data(data) .cons .iter() - .map(|(name, ty)| (**name, self.lower_ty(hir, *ty, &TyInsts { - self_ty: None, - gen_tys, - gen_effs, - }))) + .map(|(name, ty)| { + ( + **name, + self.lower_ty( + hir, + *ty, + &TyInsts { + self_ty: None, + gen_tys, + gen_effs, + }, + ), + ) + }) .collect(), }; // Mark the data type as recursive if the recursive flag got set during lowering - if *self.datas.get(&id).unwrap().as_ref().map(|_| ()).unwrap_err() { + if *self + .datas + .get(&id) + .unwrap() + .as_ref() + .map(|_| ()) + .unwrap_err() + { data.is_recursive = true; } self.datas.insert(id, Ok(data)); @@ -288,10 +359,12 @@ impl ConContext { Ty::Error(_) => panic!("Concretizable type cannot be an error"), Ty::Prim(prim) => ConTy::Prim(prim), Ty::List(item) => ConTy::List(self.lower_ty(hir, item, ty_insts)), - Ty::Record(fields, _) => ConTy::Record(fields - .into_iter() - .map(|(name, field)| (name, self.lower_ty(hir, field, ty_insts))) - .collect()), + Ty::Record(fields, _) => ConTy::Record( + fields + .into_iter() + .map(|(name, field)| (name, self.lower_ty(hir, field, ty_insts))) + .collect(), + ), Ty::Func(i, o) => ConTy::Func( self.lower_ty(hir, i, ty_insts), self.lower_ty(hir, o, ty_insts), @@ -302,9 +375,13 @@ impl ConContext { .map(|arg| self.lower_ty(hir, arg, ty_insts)) .collect::>(); ConTy::Data(self.lower_data(hir, data, &gen_tys, &[])) - }, + } Ty::Gen(idx, _) => return ty_insts.gen_tys[idx], - Ty::SelfType => return ty_insts.self_ty.expect("Self type required during concretization but none was provided"), + Ty::SelfType => { + return ty_insts + .self_ty + .expect("Self type required during concretization but none was provided") + } Ty::Assoc(ty, (class_id, gen_tys, gen_effs), assoc) => { let self_ty = self.lower_ty(hir, ty, ty_insts); let gen_tys = gen_tys @@ -313,17 +390,36 @@ impl ConContext { .collect::>(); let gen_effs = gen_effs .into_iter() - .map(|eff| self.lower_effect(hir, eff.expect("Error effect instance should not exist during concretization"), ty_insts)) + .map(|eff| { + self.lower_effect( + hir, + eff.expect( + "Error effect instance should not exist during concretization", + ), + ty_insts, + ) + }) .collect::>(); - let member = hir.classes - .lookup_member(hir, self, self_ty, (class_id, gen_tys.clone(), gen_effs.clone())) + let member = hir + .classes + .lookup_member( + hir, + self, + self_ty, + (class_id, gen_tys.clone(), gen_effs.clone()), + ) .map(|m| hir.classes.get_member(m)) - .unwrap_or_else(|| panic!( - "Could not select member candidate for {} as {}{}", - self.display(hir, self_ty), - *hir.classes.get(class_id).name, - gen_tys.iter().map(|ty| format!(" {}", self.display(hir, *ty))).collect::(), - )); + .unwrap_or_else(|| { + panic!( + "Could not select member candidate for {} as {}{}", + self.display(hir, self_ty), + *hir.classes.get(class_id).name, + gen_tys + .iter() + .map(|ty| format!(" {}", self.display(hir, *ty))) + .collect::(), + ) + }); let member_gen_scope = hir.tys.get_gen_scope(member.gen_scope); let mut ty_links = HashMap::new(); @@ -332,8 +428,12 @@ impl ConContext { hir, member.member, self_ty, - &mut |gen_idx, ty| { ty_links.insert(gen_idx, ty); }, - &mut |gen_idx, eff| { eff_links.insert(gen_idx, eff); }, + &mut |gen_idx, ty| { + ty_links.insert(gen_idx, ty); + }, + &mut |gen_idx, eff| { + eff_links.insert(gen_idx, eff); + }, ); assert_eq!( (gen_tys.len(), gen_effs.len()), @@ -347,27 +447,37 @@ impl ConContext { hir, *member_arg, *arg, - &mut |gen_idx, ty| { ty_links.insert(gen_idx, ty); }, - &mut |gen_idx, eff| { eff_links.insert(gen_idx, eff); }, + &mut |gen_idx, ty| { + ty_links.insert(gen_idx, ty); + }, + &mut |gen_idx, eff| { + eff_links.insert(gen_idx, eff); + }, ); } let gen_tys = (0..member_gen_scope.len()) - .map(|idx| *ty_links.get(&idx).expect("Generic type not mentioned in member")) + .map(|idx| { + *ty_links + .get(&idx) + .expect("Generic type not mentioned in member") + }) .collect::>(); let gen_effs = (0..member_gen_scope.len_eff()) // TODO: Is reverting to an empty effect set valid here? .map(|idx| eff_links.get(&idx).cloned().unwrap_or_default()) .collect::>(); - let assoc = member - .assoc_ty(*assoc) - .unwrap(); - return self.lower_ty(hir, assoc, &TyInsts { - self_ty: Some(self_ty), - gen_tys: &gen_tys, - gen_effs: &gen_effs, - }); - }, + let assoc = member.assoc_ty(*assoc).unwrap(); + return self.lower_ty( + hir, + assoc, + &TyInsts { + self_ty: Some(self_ty), + gen_tys: &gen_tys, + gen_effs: &gen_effs, + }, + ); + } Ty::Effect(eff, out) => { let effs = match hir.tys.get_effect(eff) { Effect::Error => panic!("Concretizable effect cannot be an error"), @@ -381,7 +491,7 @@ impl ConContext { .map(|arg| self.lower_ty(hir, arg, ty_insts)) .collect::>(); vec![Intern::new((decl, args.to_vec()))] - }, + } Err(()) => panic!("Concretizable effect instance cannot be an error"), }) .collect::>(), @@ -393,37 +503,46 @@ impl ConContext { } else { ConTy::Effect(effs, out) } - }, + } }; self.insert_ty(cty) } // Returns (record_ty, field_ty, number_of_indirections) - pub fn follow_field_access(&self, hir: &Context, mut ty: ConTyId, field: Ident) -> Option<(ConTyId, ConTyId, usize)> { + pub fn follow_field_access( + &self, + _hir: &Context, + mut ty: ConTyId, + field: Ident, + ) -> Option<(ConTyId, ConTyId, usize)> { let mut already_seen = Vec::new(); loop { match self.get_ty(ty).clone() { - ConTy::Data(data_id) => if already_seen.contains(&data_id.0) { - // We've already seen this data type, it must be recursive. Give up, it has no fields. - break None - } else { - already_seen.push(data_id.0); - let data = self.get_data(data_id); - if data.cons.len() == 1 { - ty = data.cons[0].1; + ConTy::Data(data_id) => { + if already_seen.contains(&data_id.0) { + // We've already seen this data type, it must be recursive. Give up, it has no fields. + break None; + } else { + already_seen.push(data_id.0); + let data = self.get_data(data_id); + if data.cons.len() == 1 { + ty = data.cons[0].1; + } else { + // Sum types have no fields + break None; + } + } + } + ConTy::Record(fields) => { + if let Some((_, field_ty)) = fields.iter().find(|(name, _)| **name == field) { + break Some((ty, *field_ty, already_seen.len())); } else { - // Sum types have no fields + // Record has no such field break None; } - }, - ConTy::Record(fields) => if let Some((_, field_ty)) = fields.iter().find(|(name, _)| **name == field) { - break Some((ty, *field_ty, already_seen.len())); - } else { - // Record has no such field - break None; - }, + } _ => break None, // Only `Data` or `Record` can have fields } } @@ -436,12 +555,12 @@ impl ConContext { let body = match &*proc.0 { ConProc::Def(def, gen_tys, gen_effs) => self.lower_expr( hir, - hir.defs - .get(*def) - .body - .as_ref() - .unwrap(), - &TyInsts { self_ty: None, gen_tys, gen_effs }, + hir.defs.get(*def).body.as_ref().unwrap(), + &TyInsts { + self_ty: None, + gen_tys, + gen_effs, + }, ), ConProc::Field(self_ty, member_id, gen_tys, gen_effs, field) => { let member = hir.classes.get_member(*member_id); @@ -453,23 +572,33 @@ impl ConContext { hir, member.member, *self_ty, - &mut |gen_idx, ty| { ty_links.insert(gen_idx, ty); }, - &mut |gen_idx, eff| { eff_links.insert(gen_idx, eff); }, + &mut |gen_idx, ty| { + ty_links.insert(gen_idx, ty); + }, + &mut |gen_idx, eff| { + eff_links.insert(gen_idx, eff); + }, ); assert_eq!( (gen_tys.len(), gen_effs.len()), (member.gen_tys.len(), member.gen_effs.len()), "Member and instance args must be the same length in member {} of {}", hir.tys.display(hir, member.member), - *hir.classes.get(hir.classes.get_member(*member_id).class).name, + *hir.classes + .get(hir.classes.get_member(*member_id).class) + .name, ); for (member_ty, ty) in member.gen_tys.iter().zip(gen_tys.iter()) { self.derive_links( hir, *member_ty, *ty, - &mut |gen_idx, ty| { ty_links.insert(gen_idx, ty); }, - &mut |gen_idx, eff| { eff_links.insert(gen_idx, eff); }, + &mut |gen_idx, ty| { + ty_links.insert(gen_idx, ty); + }, + &mut |gen_idx, eff| { + eff_links.insert(gen_idx, eff); + }, ); } for (member_eff, eff) in member.gen_effs.iter().zip(gen_effs.iter()) { @@ -477,54 +606,85 @@ impl ConContext { hir, member_eff.expect("Error effect found during concretization"), eff, - &mut |gen_idx, ty| { ty_links.insert(gen_idx, ty); }, - &mut |gen_idx, eff| { eff_links.insert(gen_idx, eff); }, + &mut |gen_idx, ty| { + ty_links.insert(gen_idx, ty); + }, + &mut |gen_idx, eff| { + eff_links.insert(gen_idx, eff); + }, ); } let gen_tys = (0..member_gen_scope.len()) - .map(|idx| *ty_links.get(&idx).expect("Generic type not mentioned in member")) + .map(|idx| { + *ty_links + .get(&idx) + .expect("Generic type not mentioned in member") + }) .collect::>(); let gen_effs = (0..member_gen_scope.len_eff()) // TODO: Is reverting to an empty effect set valid here? - .map(|idx| eff_links.get(&idx).cloned().expect("Effect not found in generic scope")) + .map(|idx| { + eff_links + .get(&idx) + .cloned() + .expect("Effect not found in generic scope") + }) .collect::>(); self.lower_expr( hir, - member - .field(*field) - .unwrap(), - &TyInsts { self_ty: Some(*self_ty), gen_tys: &gen_tys, gen_effs: &gen_effs }, + member.field(*field).unwrap(), + &TyInsts { + self_ty: Some(*self_ty), + gen_tys: &gen_tys, + gen_effs: &gen_effs, + }, ) - }, + } }; self.procs.insert(proc, Some(body)); } } - pub fn lower_binding(&mut self, hir: &Context, binding: &TyBinding, ty_insts: &TyInsts) -> ConBinding { + pub fn lower_binding( + &mut self, + hir: &Context, + binding: &TyBinding, + ty_insts: &TyInsts, + ) -> ConBinding { let pat = match &*binding.pat { hir::Pat::Error => panic!("Error pattern should not exist during concretization"), hir::Pat::Wildcard => hir::Pat::Wildcard, hir::Pat::Literal(litr) => hir::Pat::Literal(*litr), hir::Pat::Single(inner) => hir::Pat::Single(self.lower_binding(hir, inner, ty_insts)), - hir::Pat::Add(lhs, rhs) => hir::Pat::Add(self.lower_binding(hir, lhs, ty_insts), rhs.clone()), - hir::Pat::Record(fields, is_tuple) => hir::Pat::Record(fields - .iter() - .map(|(name, field)| (*name, self.lower_binding(hir, field, ty_insts))) - .collect(), *is_tuple), - hir::Pat::ListExact(items) => hir::Pat::ListExact(items - .iter() - .map(|item| self.lower_binding(hir, item, ty_insts)) - .collect()), - hir::Pat::ListFront(items, tail) => hir::Pat::ListFront(items - .iter() - .map(|item| self.lower_binding(hir, item, ty_insts)) - .collect(), tail.as_ref().map(|tail| self.lower_binding(hir, tail, ty_insts))), - hir::Pat::Decons(data, variant, inner) => { + hir::Pat::Add(lhs, rhs) => { + hir::Pat::Add(self.lower_binding(hir, lhs, ty_insts), rhs.clone()) + } + hir::Pat::Record(fields, is_tuple) => hir::Pat::Record( + fields + .iter() + .map(|(name, field)| (*name, self.lower_binding(hir, field, ty_insts))) + .collect(), + *is_tuple, + ), + hir::Pat::ListExact(items) => hir::Pat::ListExact( + items + .iter() + .map(|item| self.lower_binding(hir, item, ty_insts)) + .collect(), + ), + hir::Pat::ListFront(items, tail) => hir::Pat::ListFront( + items + .iter() + .map(|item| self.lower_binding(hir, item, ty_insts)) + .collect(), + tail.as_ref() + .map(|tail| self.lower_binding(hir, tail, ty_insts)), + ), + hir::Pat::Decons(_data, variant, inner) => { let ty = self.lower_ty(hir, binding.meta().1, ty_insts); let ConTy::Data(data) = self.get_ty(ty) else { unreachable!() }; hir::Pat::Decons(*data, *variant, self.lower_binding(hir, inner, ty_insts)) - }, + } }; ConNode::new( @@ -548,14 +708,15 @@ impl ConContext { .collect::>(); let gen_effs = gen_effs .iter() - .map(|eff| eff - .map(|eff| self.lower_effect(hir, eff, ty_insts)) - .unwrap_or_default()) + .map(|eff| { + eff.map(|eff| self.lower_effect(hir, eff, ty_insts)) + .unwrap_or_default() + }) .collect(); - let id = ConProcId(Intern::new(ConProc::Def(*x, gen_tys.clone(), gen_effs))); + let id = ConProcId(Intern::new(ConProc::Def(*x, gen_tys, gen_effs))); self.lower_proc(hir, id); hir::Expr::Global(id) - }, + } hir::Expr::List(items, tails) => hir::Expr::List( items .iter() @@ -566,20 +727,26 @@ impl ConContext { .map(|tail| self.lower_expr(hir, tail, ty_insts)) .collect(), ), - hir::Expr::Record(fields, is_tuple) => hir::Expr::Record(fields - .iter() - .map(|(name, field)| (name.clone(), self.lower_expr(hir, field, ty_insts))) - .collect(), *is_tuple), - hir::Expr::Access(record, field) => hir::Expr::Access(self.lower_expr(hir, record, ty_insts), field.clone()), + hir::Expr::Record(fields, is_tuple) => hir::Expr::Record( + fields + .iter() + .map(|(name, field)| (name.clone(), self.lower_expr(hir, field, ty_insts))) + .collect(), + *is_tuple, + ), + hir::Expr::Access(record, field) => { + hir::Expr::Access(self.lower_expr(hir, record, ty_insts), field.clone()) + } hir::Expr::Match(hidden_outer, pred, arms) => hir::Expr::Match( *hidden_outer, self.lower_expr(hir, pred, ty_insts), - arms - .iter() - .map(|(binding, arm)| ( - self.lower_binding(hir, binding, ty_insts), - self.lower_expr(hir, arm, ty_insts), - )) + arms.iter() + .map(|(binding, arm)| { + ( + self.lower_binding(hir, binding, ty_insts), + self.lower_expr(hir, arm, ty_insts), + ) + }) .collect(), ), hir::Expr::Func(arg, body) => hir::Expr::Func( @@ -590,86 +757,121 @@ impl ConContext { self.lower_expr(hir, f, ty_insts), self.lower_expr(hir, arg, ty_insts), ), - hir::Expr::Cons(data, variant, inner) => { + hir::Expr::Cons(_data, variant, inner) => { let ty = self.lower_ty(hir, ty_expr.meta().1, ty_insts); let ConTy::Data(data) = self.get_ty(ty) else { unreachable!() }; hir::Expr::Cons(*data, *variant, self.lower_expr(hir, inner, ty_insts)) - }, + } hir::Expr::ClassAccess(ty, class, field) => { let self_ty = self.lower_ty(hir, ty.1, ty_insts); - let (class_id, gen_tys, gen_effs) = class.as_ref().expect("Uninferred class during concretization"); + let (class_id, gen_tys, gen_effs) = class + .as_ref() + .expect("Uninferred class during concretization"); let gen_tys = gen_tys .iter() .map(|ty| self.lower_ty(hir, *ty, ty_insts)) .collect::>(); let gen_effs = gen_effs .iter() - .map(|eff| eff - .map(|eff| self.lower_effect(hir, eff, ty_insts)) - .expect("Error effect during concretization")) + .map(|eff| { + eff.map(|eff| self.lower_effect(hir, eff, ty_insts)) + .expect("Error effect during concretization") + }) .collect::>(); - let member_id = hir.classes - .lookup_member(hir, self, self_ty, (*class_id, gen_tys.clone(), gen_effs.clone())) - .unwrap_or_else(|| panic!( - "Could not select member candidate for {} as {}{}{}", - self.display(hir, self_ty), - *hir.classes.get(*class_id).name, - gen_tys.iter().map(|ty| format!(" {}", self.display(hir, *ty))).collect::(), - gen_effs.iter().map(|eff| format!(" {:?}", eff)).collect::(), - )); - - let id = ConProcId(Intern::new(ConProc::Field(self_ty, member_id, gen_tys, gen_effs, **field))); + let member_id = hir + .classes + .lookup_member( + hir, + self, + self_ty, + (*class_id, gen_tys.clone(), gen_effs.clone()), + ) + .unwrap_or_else(|| { + panic!( + "Could not select member candidate for {} as {}{}{}", + self.display(hir, self_ty), + *hir.classes.get(*class_id).name, + gen_tys + .iter() + .map(|ty| format!(" {}", self.display(hir, *ty))) + .collect::(), + gen_effs + .iter() + .map(|eff| format!(" {:?}", eff)) + .collect::(), + ) + }); + + let id = ConProcId(Intern::new(ConProc::Field( + self_ty, member_id, gen_tys, gen_effs, **field, + ))); self.lower_proc(hir, id); hir::Expr::Global(id) - }, - hir::Expr::Intrinsic(name, args) => if matches!(&**name, Intrinsic::Propagate) { - let inner = self.lower_expr(hir, &args[0], ty_insts); - // Flatten empty effects - if matches!(self.get_ty(*inner.meta()), ConTy::Effect(effs, _) if !effs.is_empty()) { - hir::Expr::Intrinsic(name.clone(), vec![inner]) - } else { - inner.into_inner() - } - } else if let Intrinsic::Dispatch = &**name { - let specialised_fn = self.lower_ty(hir, args[1].meta().1, ty_insts); - let i = match self.get_ty(specialised_fn) { - ConTy::Func(i, _) => *i, - ty => unreachable!("Specialised function was of type {:?}", ty), - }; - let input = self.lower_expr(hir, &args[0], ty_insts); - if *input.meta() == i { - // Types match, time to specialise! - let specialised_fn = self.lower_expr(hir, &args[1], ty_insts); - hir::Expr::Apply(specialised_fn, input) + } + hir::Expr::Intrinsic(name, args) => { + if matches!(&**name, Intrinsic::Propagate) { + let inner = self.lower_expr(hir, &args[0], ty_insts); + // Flatten empty effects + if matches!(self.get_ty(*inner.meta()), ConTy::Effect(effs, _) if !effs.is_empty()) + { + hir::Expr::Intrinsic(name.clone(), vec![inner]) + } else { + inner.into_inner() + } + } else if let Intrinsic::Dispatch = &**name { + let specialised_fn = self.lower_ty(hir, args[1].meta().1, ty_insts); + let i = match self.get_ty(specialised_fn) { + ConTy::Func(i, _) => *i, + ty => unreachable!("Specialised function was of type {:?}", ty), + }; + let input = self.lower_expr(hir, &args[0], ty_insts); + if *input.meta() == i { + // Types match, time to specialise! + let specialised_fn = self.lower_expr(hir, &args[1], ty_insts); + hir::Expr::Apply(specialised_fn, input) + } else { + //println!("Unmatched: {} with {}", self.display(hir, *input.meta()), self.display(hir, i)); + // No match, use the fallback implementation + let fallback_fn = self.lower_expr(hir, &args[2], ty_insts); + hir::Expr::Apply(fallback_fn, input) + } } else { - //println!("Unmatched: {} with {}", self.display(hir, *input.meta()), self.display(hir, i)); - // No match, use the fallback implementation - let fallback_fn = self.lower_expr(hir, &args[2], ty_insts); - hir::Expr::Apply(fallback_fn, input) + hir::Expr::Intrinsic( + name.clone(), + args.iter() + .map(|arg| self.lower_expr(hir, arg, ty_insts)) + .collect(), + ) } - } else { - hir::Expr::Intrinsic(name.clone(), args - .into_iter() - .map(|arg| self.lower_expr(hir, arg, ty_insts)) - .collect()) - }, - hir::Expr::Update(record, fields) => hir::Expr::Update(self.lower_expr(hir, record, ty_insts), fields - .iter() - .map(|(name, field)| (name.clone(), self.lower_expr(hir, field, ty_insts))) - .collect()), + } + hir::Expr::Update(record, fields) => hir::Expr::Update( + self.lower_expr(hir, record, ty_insts), + fields + .iter() + .map(|(name, field)| (name.clone(), self.lower_expr(hir, field, ty_insts))) + .collect(), + ), hir::Expr::Basin(eff, inner) => { - let effs = self.lower_effect(hir, eff.expect("Error effect instance should not exist during concretization"), ty_insts); + let effs = self.lower_effect( + hir, + eff.expect("Error effect instance should not exist during concretization"), + ty_insts, + ); // Flatten empty effect if effs.is_empty() { self.lower_expr(hir, inner, ty_insts).into_inner() } else { hir::Expr::Basin(effs, self.lower_expr(hir, inner, ty_insts)) } - }, + } hir::Expr::Suspend(eff, inner) => hir::Expr::Suspend( - self.lower_effect_inst(hir, eff.clone().expect("Error effect instance should not exist during concretization"), ty_insts) - .ok() - .expect("Generic effect used in suspend?!"), + self.lower_effect_inst( + hir, + eff.clone() + .expect("Error effect instance should not exist during concretization"), + ty_insts, + ) + .expect("Generic effect used in suspend?!"), self.lower_expr(hir, inner, ty_insts), ), hir::Expr::Handle { expr, handlers } => { @@ -684,7 +886,6 @@ impl ConContext { .iter() .map(|hir::Handler { eff, send, state, recv }| hir::Handler { eff: self.lower_effect_inst(hir, eff.clone().expect("Error effect instance should not exist during concretization"), ty_insts) - .ok() .expect("Generic effect used in handler?!"), send: ConNode::new(**send, self.lower_ty(hir, send.meta().1, ty_insts)), state: state.as_ref().map(|state| ConNode::new(**state, self.lower_ty(hir, state.meta().1, ty_insts))), @@ -695,22 +896,30 @@ impl ConContext { } else { expr.into_inner() } - }, + } }; ConNode::new(expr, self.lower_ty(hir, ty_expr.meta().1, ty_insts)) } - pub fn lower_effect(&mut self, hir: &Context, eff: EffectId, ty_insts: &TyInsts) -> Vec { + pub fn lower_effect( + &mut self, + hir: &Context, + eff: EffectId, + ty_insts: &TyInsts, + ) -> Vec { match hir.tys.get_effect(eff) { Effect::Error => panic!("Error effect should not exist during concretization"), Effect::Known(effs) => effs .into_iter() .flat_map(|eff| match eff { - Ok(eff) => self.lower_effect_inst(hir, eff, ty_insts) + Ok(eff) => self + .lower_effect_inst(hir, eff, ty_insts) .map(|eff| vec![eff]) .unwrap_or_else(|effs| effs), - Err(()) => panic!("Error effect instance should not exist during concretization"), + Err(()) => { + panic!("Error effect instance should not exist during concretization") + } }) .collect::>(), } @@ -718,7 +927,12 @@ impl ConContext { // Ok(single effect instance) // Err(many effect instances) - pub fn lower_effect_inst(&mut self, hir: &Context, eff: EffectInst, ty_insts: &TyInsts) -> Result> { + pub fn lower_effect_inst( + &mut self, + hir: &Context, + eff: EffectInst, + ty_insts: &TyInsts, + ) -> Result> { match eff { EffectInst::Gen(idx, _) => Err(ty_insts.gen_effs[idx].clone()), EffectInst::Concrete(decl, gen_tys) => { @@ -729,7 +943,11 @@ impl ConContext { let id = Intern::new((decl, gen_tys.clone())); if !self.effects.contains_key(&id) { let decl = hir.effects.get_decl(decl); - let ty_insts = TyInsts { self_ty: None, gen_tys: &gen_tys, gen_effs: &[] }; + let ty_insts = TyInsts { + self_ty: None, + gen_tys: &gen_tys, + gen_effs: &[], + }; let eff = ConEffect { send: self.lower_ty(hir, decl.send.unwrap(), &ty_insts), recv: self.lower_ty(hir, decl.recv.unwrap(), &ty_insts), @@ -737,7 +955,7 @@ impl ConContext { self.effects.insert(id, eff); } Ok(id) - }, + } } } @@ -763,7 +981,11 @@ pub struct ConTyDisplay<'a> { impl<'a> ConTyDisplay<'a> { fn with_ty(&self, ty: ConTyId, lhs_exposed: bool) -> Self { - Self { ty, lhs_exposed, ..self.clone() } + Self { + ty, + lhs_exposed, + ..self.clone() + } } } @@ -772,30 +994,64 @@ impl<'a> fmt::Display for ConTyDisplay<'a> { match self.con_ctx.get_ty(self.ty).clone() { ConTy::Prim(prim) => write!(f, "{}", prim), ConTy::List(item) => write!(f, "[{}]", self.with_ty(item, false)), - ConTy::Record(fields) => write!(f, "{{ {} }}", fields - .into_iter() - .map(|(name, field)| format!("{}: {}", name, self.with_ty(field, false))) - .collect::>() - .join(", ")), - ConTy::Func(i, o) if self.lhs_exposed => write!(f, "({} -> {})", self.with_ty(i, true), self.with_ty(o, self.lhs_exposed)), - ConTy::Func(i, o) => write!(f, "{} -> {}", self.with_ty(i, true), self.with_ty(o, self.lhs_exposed)), - ConTy::Data(data_id) if self.lhs_exposed && data_id.0.1.len() > 0 => write!(f, "({}{})", *self.datas.get_data(data_id.0.0).name, data_id.0.1 - .iter() - .map(|param| format!(" {}", self.with_ty(*param, true))) - .collect::()), - ConTy::Data(data_id) => write!(f, "{}{}", *self.datas.get_data(data_id.0.0).name, data_id.0.1 - .iter() - .map(|param| format!(" {}", self.with_ty(*param, true))) - .collect::()), + ConTy::Record(fields) => write!( + f, + "{{ {} }}", + fields + .into_iter() + .map(|(name, field)| format!("{}: {}", name, self.with_ty(field, false))) + .collect::>() + .join(", ") + ), + ConTy::Func(i, o) if self.lhs_exposed => write!( + f, + "({} -> {})", + self.with_ty(i, true), + self.with_ty(o, self.lhs_exposed) + ), + ConTy::Func(i, o) => write!( + f, + "{} -> {}", + self.with_ty(i, true), + self.with_ty(o, self.lhs_exposed) + ), + ConTy::Data(data_id) if self.lhs_exposed && !data_id.0.1.is_empty() => write!( + f, + "({}{})", + *self.datas.get_data(data_id.0 .0).name, + data_id + .0 + .1 + .iter() + .map(|param| format!(" {}", self.with_ty(*param, true))) + .collect::() + ), + ConTy::Data(data_id) => write!( + f, + "{}{}", + *self.datas.get_data(data_id.0 .0).name, + data_id + .0 + .1 + .iter() + .map(|param| format!(" {}", self.with_ty(*param, true))) + .collect::() + ), ConTy::Effect(effs, out) => { for eff_id in effs { - write!(f, "{}{}", *self.effects.get_decl(eff_id.0).name, eff_id.1 - .iter() - .map(|param| format!(" {}", self.with_ty(*param, true))) - .collect::())?; + write!( + f, + "{}{}", + *self.effects.get_decl(eff_id.0).name, + eff_id + .1 + .iter() + .map(|param| format!(" {}", self.with_ty(*param, true))) + .collect::() + )?; } write!(f, " ~ {}", self.with_ty(out, true)) - }, + } } } } diff --git a/analysis/src/context.rs b/analysis/src/context.rs index 9d25c82..f795dd1 100644 --- a/analysis/src/context.rs +++ b/analysis/src/context.rs @@ -42,36 +42,48 @@ impl Context { ); errors.append(&mut errs); let gen_scope = this.tys.insert_gen_scope(gen_scope); - match this.classes.declare(class.name.clone(), Class { - name: class.name.clone(), - attr: attr.to_vec(), - gen_scope, - fields: None, - assoc: Some(class.items - .iter() - .filter_map(|item| match item { - ast::ClassItem::Type { name, obligations } => Some(ClassAssoc { name: name.clone() }), - _ => None, - }) - .collect::>()), - }) { + match this.classes.declare( + class.name.clone(), + Class { + name: class.name.clone(), + attr: attr.to_vec(), + gen_scope, + fields: None, + assoc: Some( + class + .items + .iter() + .filter_map(|item| match item { + ast::ClassItem::Type { name, obligations: _ } => { + Some(ClassAssoc { name: name.clone() }) + } + _ => None, + }) + .collect::>(), + ), + }, + ) { Err(err) => { errors.push(err); continue; - }, + } // Only mark for further processing if no errors occurred during declaration Ok(class_id) => classes.push((attr, class, class_id, gen_scope)), } } // Class associated types - for (attr, class, class_id, gen_scope) in &classes { + for (_attr, class, class_id, _gen_scope) in &classes { let mut existing_tys = HashMap::new(); - let assoc = class.items + let assoc = class + .items .iter() .filter_map(|item| match item { ast::ClassItem::Type { name, obligations } => { if !obligations.is_empty() { - errors.push(Error::Unsupported(obligations.span(), "obligations on associated types")); + errors.push(Error::Unsupported( + obligations.span(), + "obligations on associated types", + )); } if let Some(old) = existing_tys.get(&**name) { @@ -81,19 +93,15 @@ impl Context { existing_tys.insert(**name, name.span()); Some(ClassAssoc { name: name.clone() }) } - }, + } _ => None, }) .collect::>(); this.classes.define_assoc(*class_id, assoc); } for (attr, eff) in module.effects() { - let (gen_scope, mut errs) = GenScope::from_ast( - &eff.generics, - eff.name.span(), - |_| true, - |_| true, - ); + let (gen_scope, mut errs) = + GenScope::from_ast(&eff.generics, eff.name.span(), |_| true, |_| true); errors.append(&mut errs); let gen_scope = this.tys.insert_gen_scope(gen_scope); match this.effects.declare(EffectDecl { @@ -106,7 +114,7 @@ impl Context { Err(err) => { errors.push(err); continue; - }, + } // Only mark for further processing if no errors occurred during declaration Ok(eff_id) => effects.push((attr, eff, eff_id, gen_scope)), } @@ -130,7 +138,7 @@ impl Context { Err(err) => { errors.push(err); continue; - }, + } // Only mark for further processing if no errors occurred during declaration Ok(eff_id) => effect_aliases.push((attr, alias, eff_id, gen_scope)), } @@ -144,12 +152,15 @@ impl Context { ); errors.append(&mut errs); let gen_scope = this.tys.insert_gen_scope(gen_scope); - match this.datas.declare_alias(*alias.name, alias.name.span(), gen_scope) { + match this + .datas + .declare_alias(*alias.name, alias.name.span(), gen_scope) + { Ok(alias_id) => aliases.push((attr, alias, alias_id)), Err(err) => { errors.push(err); continue; - }, + } } } for (attr, data) in module.datas() { @@ -164,12 +175,12 @@ impl Context { ); errors.append(&mut errs); let gen_scope = this.tys.insert_gen_scope(gen_scope); - match this.datas.declare_data(data.name.clone(), gen_scope, &attr) { + match this.datas.declare_data(data.name.clone(), gen_scope, attr) { Ok(data_id) => datas.push((attr, data, data_id)), Err(err) => { errors.push(err); continue; - }, + } } } for (attr, member) in module.members() { @@ -183,24 +194,24 @@ impl Context { let (gen_scope, mut errs) = GenScope::from_ast( &member.generics, member.member.span(), - |name| member.member.mentions_ty(name) - || member.class.gen_tys.iter().any(|ty| ty.mentions_ty(name)) - || member.class.gen_effs.iter().any(|ty| ty.mentions_ty(name)), - |name| member.member.mentions_eff(name) - || member.class.gen_tys.iter().any(|ty| ty.mentions_eff(name)) - || member.class.gen_effs.iter().any(|ty| ty.mentions_eff(name)), + |name| { + member.member.mentions_ty(name) + || member.class.gen_tys.iter().any(|ty| ty.mentions_ty(name)) + || member.class.gen_effs.iter().any(|ty| ty.mentions_ty(name)) + }, + |name| { + member.member.mentions_eff(name) + || member.class.gen_tys.iter().any(|ty| ty.mentions_eff(name)) + || member.class.gen_effs.iter().any(|ty| ty.mentions_eff(name)) + }, ); errors.append(&mut errs); let gen_scope = this.tys.insert_gen_scope(gen_scope); members_init.push((attr, member, class_id, gen_scope)); } for (attr, def) in module.defs() { - let (gen_scope, mut errs) = GenScope::from_ast( - &def.generics, - def.name.span(), - |_| true, - |_| true, - ); + let (gen_scope, mut errs) = + GenScope::from_ast(&def.generics, def.name.span(), |_| true, |_| true); errors.append(&mut errs); let gen_scope = this.tys.insert_gen_scope(gen_scope); defs_init.push((attr, def, gen_scope)); @@ -210,95 +221,98 @@ impl Context { for (_, class, class_id, _) in &classes { let gen_scope = this.classes.get(*class_id).gen_scope; - this.reify_gen_scope( - gen_scope, - |infer| { - let self_ty = infer.set_self_unknown(class.name.span()); - let gen_tys = (0..infer.ctx().tys.get_gen_scope(gen_scope).len()) - .map(|idx| { - let span = infer.ctx().tys.get_gen_scope(gen_scope).get(idx).name.span(); - infer.insert(span, TyInfo::Gen(idx, gen_scope, span)) - }) - .collect::>(); - let gen_effs = (0..infer.ctx().tys.get_gen_scope(gen_scope).len_eff()) - .map(|idx| { - let span = infer.ctx().tys.get_gen_scope(gen_scope).get_eff(idx).name.span(); - infer.insert_gen_eff(span, idx, gen_scope) - }) - .collect::>(); - infer.add_implied_member_single(ImpliedMember { - member: SrcNode::new(self_ty, class.name.span()), - class: SrcNode::new(*class_id, class.name.span()), - gen_tys, - gen_effs, - items: ImpliedItems::Eq(Vec::new()), - }); - }, - ); + this.reify_gen_scope(gen_scope, |infer| { + let self_ty = infer.set_self_unknown(class.name.span()); + let gen_tys = (0..infer.ctx().tys.get_gen_scope(gen_scope).len()) + .map(|idx| { + let span = infer + .ctx() + .tys + .get_gen_scope(gen_scope) + .get(idx) + .name + .span(); + infer.insert(span, TyInfo::Gen(idx, gen_scope, span)) + }) + .collect::>(); + let gen_effs = (0..infer.ctx().tys.get_gen_scope(gen_scope).len_eff()) + .map(|idx| { + let span = infer + .ctx() + .tys + .get_gen_scope(gen_scope) + .get_eff(idx) + .name + .span(); + infer.insert_gen_eff(span, idx, gen_scope) + }) + .collect::>(); + infer.add_implied_member_single(ImpliedMember { + member: SrcNode::new(self_ty, class.name.span()), + class: SrcNode::new(*class_id, class.name.span()), + gen_tys, + gen_effs, + items: ImpliedItems::Eq(Vec::new()), + }); + }); } for (_, _, effect_id, _) in &effects { - this.reify_gen_scope( - this.effects.get_decl(*effect_id).gen_scope, - |_infer| {}, - ); + this.reify_gen_scope(this.effects.get_decl(*effect_id).gen_scope, |_infer| {}); } for (_, _, alias_id, _) in &effect_aliases { - this.reify_gen_scope( - this.effects.get_alias(*alias_id).gen_scope, - |_infer| {}, - ); + this.reify_gen_scope(this.effects.get_alias(*alias_id).gen_scope, |_infer| {}); } for (_, _, alias_id) in &aliases { - this.reify_gen_scope( - this.datas.alias_gen_scope(*alias_id), - |_infer| {}, - ); + this.reify_gen_scope(this.datas.alias_gen_scope(*alias_id), |_infer| {}); } for (_, _, data_id) in &datas { - this.reify_gen_scope( - this.datas.data_gen_scope(*data_id), - |_infer| {}, - ); + this.reify_gen_scope(this.datas.data_gen_scope(*data_id), |_infer| {}); } for (_, _, _, gen_scope_id) in &members_init { - this.reify_gen_scope( - *gen_scope_id, - |infer| {}, - ); + this.reify_gen_scope(*gen_scope_id, |_infer| {}); } - for (_, def, gen_scope_id) in &defs_init { - this.reify_gen_scope( - *gen_scope_id, - |infer| {}, - ); + for (_, _def, gen_scope_id) in &defs_init { + this.reify_gen_scope(*gen_scope_id, |_infer| {}); } let mut members = Vec::new(); for (attr, member, class_id, gen_scope) in &members_init { - let mut infer = Infer::new(&mut this, Some(*gen_scope)) - .with_gen_scope_implied(); + let mut infer = Infer::new(&mut this, Some(*gen_scope)).with_gen_scope_implied(); - let member_ty = member.member.to_hir(&TypeLowerCfg::member(), &mut infer, &Scope::Empty); + let member_ty = + member + .member + .to_hir(&TypeLowerCfg::member(), &mut infer, &Scope::Empty); let mut infer = infer.with_self_var(member_ty.meta().1); - let gen_tys = member.class.gen_tys + let gen_tys = member + .class + .gen_tys .iter() .map(|ty| ty.to_hir(&TypeLowerCfg::member(), &mut infer, &Scope::Empty)) .collect::>(); - let gen_effs = member.class.gen_effs + let gen_effs = member + .class + .gen_effs .iter() - .map(|eff| lower::lower_effect_set(eff, &TypeLowerCfg::member(), &mut infer, &Scope::Empty)) + .map(|eff| { + lower::lower_effect_set(eff, &TypeLowerCfg::member(), &mut infer, &Scope::Empty) + }) .collect::>(); - let class_gen_scope = infer.ctx().tys.get_gen_scope(infer.ctx().classes.get(*class_id).gen_scope); - if class_gen_scope.len() != gen_tys.len() || class_gen_scope.len_eff() != gen_effs.len() { + let class_gen_scope = infer + .ctx() + .tys + .get_gen_scope(infer.ctx().classes.get(*class_id).gen_scope); + if class_gen_scope.len() != gen_tys.len() || class_gen_scope.len_eff() != gen_effs.len() + { let item_span = class_gen_scope.item_span; let class_gen_scope_len = class_gen_scope.len(); // TODO: Proper error for effects @@ -323,16 +337,19 @@ impl Context { .map(|eff| checked.reify_effect(*eff)) .collect::>(); - let member_id = this.classes.declare_member(*class_id, Member { - gen_scope: *gen_scope, - attr: attr.to_vec(), - member: member_ty, - class: *class_id, - gen_tys, - gen_effs, - fields: None, - assoc: None, - }); + let member_id = this.classes.declare_member( + *class_id, + Member { + gen_scope: *gen_scope, + attr: attr.to_vec(), + member: member_ty, + class: *class_id, + gen_tys, + gen_effs, + fields: None, + assoc: None, + }, + ); members.push((*member, *class_id, member_id, member_ty, *gen_scope)); } @@ -342,10 +359,12 @@ impl Context { let gen_scope = this.datas.name_gen_scope(*alias.name); let mut infer = Infer::new(&mut this, Some(gen_scope)); - // TODO: Enforce these? - //.with_gen_scope_implied(); + // TODO: Enforce these? + //.with_gen_scope_implied(); - let ty = alias.ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + let ty = alias + .ty + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); let (mut checked, mut errs) = infer.into_checked(); errors.append(&mut errs); @@ -367,12 +386,13 @@ impl Context { // Effect alias definition must go before members and defs because they might have type hints that make use of type // aliases - for (attr, alias, alias_id, gen_scope) in effect_aliases { + for (_attr, alias, alias_id, gen_scope) in effect_aliases { let mut infer = Infer::new(&mut this, Some(gen_scope)); - // TODO: Enforce these? - //.with_gen_scope_implied(); + // TODO: Enforce these? + //.with_gen_scope_implied(); - let effs = alias.effects + let effs = alias + .effects .iter() .filter_map(|(name, params)| match infer.ctx().effects.lookup(**name) { None => todo!("No such effect!"), @@ -380,7 +400,12 @@ impl Context { SrcNode::new(eff, name.span()), params .iter() - .map(|param| param.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1) + .map(|param| { + param + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1 + }) .collect::>(), )), Some(Err(_)) => todo!("Nested effect aliases"), @@ -392,10 +417,15 @@ impl Context { let effs = effs .into_iter() - .map(|(eff, params)| (eff, params - .into_iter() - .map(|param| checked.reify(param)) - .collect())) + .map(|(eff, params)| { + ( + eff, + params + .into_iter() + .map(|param| checked.reify(param)) + .collect(), + ) + }) .collect(); this.effects.define_alias_effects(alias_id, effs); @@ -405,12 +435,15 @@ impl Context { this.errors.append(&mut this.classes.check_lang_items()); this.errors.append(&mut this.datas.check_lang_items()); - for (attr, eff, eff_id, gen_scope) in effects { - let mut infer = Infer::new(&mut this, Some(gen_scope)) - .with_gen_scope_implied(); + for (_attr, eff, eff_id, gen_scope) in effects { + let mut infer = Infer::new(&mut this, Some(gen_scope)).with_gen_scope_implied(); - let send = eff.send.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); - let recv = eff.recv.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + let send = eff + .send + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + let recv = eff + .recv + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); let (mut checked, mut errs) = infer.into_checked(); errors.append(&mut errs); @@ -422,9 +455,10 @@ impl Context { } // Class fields - for (attr, class, class_id, gen_scope) in &classes { + for (_attr, class, class_id, gen_scope) in &classes { let mut existing_fields = HashMap::new(); - let fields = class.items + let fields = class + .items .iter() .filter_map(|item| match item { ast::ClassItem::Value { name, ty } => { @@ -432,13 +466,25 @@ impl Context { let self_ty = infer.set_self_unknown(class.name.span()); let gen_tys = (0..infer.ctx().tys.get_gen_scope(*gen_scope).len()) .map(|idx| { - let span = infer.ctx().tys.get_gen_scope(*gen_scope).get(idx).name.span(); + let span = infer + .ctx() + .tys + .get_gen_scope(*gen_scope) + .get(idx) + .name + .span(); infer.insert(span, TyInfo::Gen(idx, *gen_scope, span)) }) .collect::>(); let gen_effs = (0..infer.ctx().tys.get_gen_scope(*gen_scope).len_eff()) .map(|idx| { - let span = infer.ctx().tys.get_gen_scope(*gen_scope).get(idx).name.span(); + let span = infer + .ctx() + .tys + .get_gen_scope(*gen_scope) + .get(idx) + .name + .span(); infer.insert_gen_eff(span, idx, *gen_scope) }) .collect::>(); @@ -467,41 +513,63 @@ impl Context { ty: SrcNode::new(checked.reify(ty.meta().1), ty.meta().0), }) } - }, + } _ => None, }) .collect::>(); this.classes.define_fields(*class_id, fields); } // Member associated types - for (member, class_id, member_id, member_ty, gen_scope) in &members { - let assoc = member.items + for (member, class_id, member_id, _member_ty, gen_scope) in &members { + let assoc = member + .items .iter() .filter_map(|item| { let member_ty = this.classes.get_member(*member_id).member; let mut infer = Infer::new(&mut this, Some(*gen_scope)) .with_self_type(member_ty, member.member.span()); - let gen_tys = member.class.gen_tys + let gen_tys = member + .class + .gen_tys .iter() - .map(|ty| ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1) + .map(|ty| { + ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1 + }) .collect(); - let gen_effs = member.class.gen_effs + let gen_effs = member + .class + .gen_effs .iter() - .map(|eff| lower::lower_effect_set(eff, &TypeLowerCfg::other(), &mut infer, &Scope::Empty)) + .map(|eff| { + lower::lower_effect_set( + eff, + &TypeLowerCfg::other(), + &mut infer, + &Scope::Empty, + ) + }) .collect(); - let assoc_tys = member.items + let assoc_tys = member + .items .iter() .filter_map(|item| match item { - ast::MemberItem::Type { name, ty } => Some(( - name.clone(), - ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1, - )), - _ => None, + ast::MemberItem::Type { name, ty } => Some(( + name.clone(), + ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1, + )), + _ => None, }) .collect(); infer.add_implied_member(ImpliedMember { member: SrcNode::new(infer.self_type().unwrap(), member.member.span()), - class: SrcNode::new(*class_id, infer.ctx().classes.get(*class_id).name.span()), + class: SrcNode::new( + *class_id, + infer.ctx().classes.get(*class_id).name.span(), + ), gen_tys, gen_effs, items: ImpliedItems::Eq(assoc_tys), @@ -511,19 +579,23 @@ impl Context { let class = infer.ctx().classes.get(*class_id); match item { - ast::MemberItem::Type { name, ty } => if class.assoc_ty(**name).is_none() { - errors.push(Error::NoSuchClassItem(name.clone(), class.name.clone())); - None - } else { - let ty = ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + ast::MemberItem::Type { name, ty } => { + if class.assoc_ty(**name).is_none() { + errors + .push(Error::NoSuchClassItem(name.clone(), class.name.clone())); + None + } else { + let ty = + ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); - let (mut checked, mut errs) = infer.into_checked(); - errors.append(&mut errs); + let (mut checked, mut errs) = infer.into_checked(); + errors.append(&mut errs); - let ty = checked.reify(ty.meta().1); + let ty = checked.reify(ty.meta().1); - Some((name.clone(), ty)) - }, + Some((name.clone(), ty)) + } + } _ => None, } }) @@ -544,21 +616,29 @@ impl Context { let class = this.classes.get(*class_id); - for class_assoc in class.assoc.as_ref().expect("Class associated types must be known here") { + for class_assoc in class + .assoc + .as_ref() + .expect("Class associated types must be known here") + { if !assoc.contains_key(&*class_assoc.name) { - errors.push(Error::MissingClassItem(member.member.span(), class.name.clone(), class_assoc.name.clone())); + errors.push(Error::MissingClassItem( + member.member.span(), + class.name.clone(), + class_assoc.name.clone(), + )); } } - this.classes.define_member_assoc(*member_id, *class_id, assoc); + this.classes + .define_member_assoc(*member_id, *class_id, assoc); } // Define datas for (attr, data, data_id) in datas { let gen_scope_id = this.datas.name_gen_scope(*data.name); - let mut infer = Infer::new(&mut this, Some(gen_scope_id)) - .with_gen_scope_implied(); + let mut infer = Infer::new(&mut this, Some(gen_scope_id)).with_gen_scope_implied(); // Generate `Self` type let gen_scope = infer.ctx().tys.get_gen_scope(gen_scope_id); @@ -572,7 +652,8 @@ impl Context { let self_ty = infer.insert(data.name.span(), TyInfo::Data(data_id, gen_tys)); let mut infer = infer.with_self_var(self_ty); - let variants = data.variants + let variants = data + .variants .iter() .map(|(name, ty)| { let ty = ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); @@ -603,19 +684,28 @@ impl Context { } // Enforce member obligations - for (member, class_id, member_id, member_ty, gen_scope) in &members { - let mut infer = Infer::new(&mut this, Some(*gen_scope)) - .with_gen_scope_implied(); + for (member, class_id, _member_id, member_ty, gen_scope) in &members { + let mut infer = Infer::new(&mut this, Some(*gen_scope)).with_gen_scope_implied(); let member_ty = infer.instantiate_local(*member_ty, member.member.span()); - let member_gen_tys = member.class.gen_tys + let member_gen_tys = member + .class + .gen_tys .iter() - .map(|arg| arg.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1) + .map(|arg| { + arg.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1 + }) .collect::>(); - let member_gen_effs = member.class.gen_effs + let member_gen_effs = member + .class + .gen_effs .iter() - .map(|eff| lower::lower_effect_set(eff, &TypeLowerCfg::other(), &mut infer, &Scope::Empty)) + .map(|eff| { + lower::lower_effect_set(eff, &TypeLowerCfg::other(), &mut infer, &Scope::Empty) + }) .collect::>(); // infer.add_implied_member(ImpliedMember { @@ -650,20 +740,23 @@ impl Context { *member_obl.member, member_obl.member.span(), &mut |idx, _, _| member_gen_tys.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), Some(member_ty), invariant(), ); - let obl_member_gen_tys = member_obl.gen_tys + let obl_member_gen_tys = member_obl + .gen_tys .iter() - .map(|ty| infer.instantiate( - *ty, - member_obl.member.span(), - &mut |idx, _, _| member_gen_tys.get(idx).copied(), - &mut |idx, _| member_gen_effs.get(idx).copied(), - Some(member_ty), - invariant(), - )) + .map(|ty| { + infer.instantiate( + *ty, + member_obl.member.span(), + &mut |idx, _, _| member_gen_tys.get(idx).copied(), + &mut |idx, _| member_gen_effs.get(idx).copied(), + Some(member_ty), + invariant(), + ) + }) .collect(); // TODO let obl_member_gen_effs = Vec::new()/*member_obl.gen_effs @@ -681,14 +774,19 @@ impl Context { ImpliedItems::Real(_) => Vec::new(), ImpliedItems::Eq(assoc) => assoc .iter() - .map(|(name, assoc)| (name.clone(), infer.instantiate( - *assoc, - name.span(), - &mut |idx, _, _| member_gen_tys.get(idx).copied(), - &mut |idx, _| member_gen_effs.get(idx).copied(), - Some(member_ty), - invariant(), - ))) + .map(|(name, assoc)| { + ( + name.clone(), + infer.instantiate( + *assoc, + name.span(), + &mut |idx, _, _| member_gen_tys.get(idx).copied(), + &mut |idx, _| member_gen_effs.get(idx).copied(), + Some(member_ty), + invariant(), + ), + ) + }) .collect(), }; infer.make_impl( @@ -700,7 +798,7 @@ impl Context { ); } - let (mut checked, mut errs) = infer.into_checked(); + let (_checked, mut errs) = infer.into_checked(); errors.append(&mut errs); } @@ -709,9 +807,11 @@ impl Context { // If the type hint is fully specified, check it let ty_hint = if def.ty_hint.is_fully_specified() { let mut infer = Infer::new(&mut this, Some(gen_scope)) - .with_debug(attr.iter().find(|a| **a.name == "ty_debug").is_some()) + .with_debug(attr.iter().any(|a| **a.name == "ty_debug")) .with_gen_scope_implied(); - let ty_hint = def.ty_hint.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + let ty_hint = def + .ty_hint + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); let (mut checked, mut errs) = infer.into_checked(); errors.append(&mut errs); @@ -741,18 +841,27 @@ impl Context { // Member fields for (member, class_id, member_id, member_ty, gen_scope) in &members { - let fields = member.items + let fields = member + .items .iter() .filter_map(|item| { let mut infer = Infer::new(&mut this, Some(*gen_scope)) .with_self_type(*member_ty, member.member.span()) .with_gen_scope_implied(); let self_ty = infer.self_type().unwrap(); - let gen_tys = member.class.gen_tys + let gen_tys = member + .class + .gen_tys .iter() - .map(|ty| ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1) + .map(|ty| { + ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1 + }) .collect::>(); - let gen_effs = member.class.gen_effs + let gen_effs = member + .class + .gen_effs .iter() .enumerate() .map(|(i, eff)| infer.insert_gen_eff(eff.span(), i, *gen_scope)) @@ -772,31 +881,41 @@ impl Context { let class = infer.ctx().classes.get(*class_id); match item { - ast::MemberItem::Value { name, val } => if class.field(**name).is_none() { - errors.push(Error::NoSuchClassItem(name.clone(), class.name.clone())); - None - } else { - let val = val.to_hir(&(), &mut infer, &Scope::Empty); - let class = infer.ctx().classes.get(*class_id); - if let Some(field_ty) = class.field(**name).cloned() { - let val_ty = infer.instantiate( - *field_ty, - None, - &mut |idx, _, _| gen_tys.get(idx).copied(), - &mut |idx, _| gen_effs.get(idx).copied(), - Some(self_ty), - contravariant(), - ); - infer.make_flow(val.meta().1, val_ty, EqInfo::new(name.span(), format!("Type of member item must match class"))); + ast::MemberItem::Value { name, val } => { + if class.field(**name).is_none() { + errors + .push(Error::NoSuchClassItem(name.clone(), class.name.clone())); + None + } else { + let val = val.to_hir(&(), &mut infer, &Scope::Empty); + let class = infer.ctx().classes.get(*class_id); + if let Some(field_ty) = class.field(**name).cloned() { + let val_ty = infer.instantiate( + *field_ty, + None, + &mut |idx, _, _| gen_tys.get(idx).copied(), + &mut |idx, _| gen_effs.get(idx).copied(), + Some(self_ty), + contravariant(), + ); + infer.make_flow( + val.meta().1, + val_ty, + EqInfo::new( + name.span(), + "Type of member item must match class".to_string(), + ), + ); + } + + let (mut checked, mut errs) = infer.into_checked(); + errors.append(&mut errs); + + let val = val.reify(&mut checked); + + Some((name.clone(), val)) } - - let (mut checked, mut errs) = infer.into_checked(); - errors.append(&mut errs); - - let val = val.reify(&mut checked); - - Some((name.clone(), val)) - }, + } _ => None, } }) @@ -817,26 +936,38 @@ impl Context { let class = this.classes.get(*class_id); - for field in class.fields.as_ref().expect("Class fields must be known here") { + for field in class + .fields + .as_ref() + .expect("Class fields must be known here") + { if !fields.contains_key(&*field.name) { - errors.push(Error::MissingClassItem(member.member.span(), class.name.clone(), field.name.clone())); + errors.push(Error::MissingClassItem( + member.member.span(), + class.name.clone(), + field.name.clone(), + )); } } - this.classes.define_member_fields(*member_id, *class_id, fields); + this.classes + .define_member_fields(*member_id, *class_id, fields); } // Def impls for (attr, def) in defs { - let id = this.defs + let id = this + .defs .lookup(*def.name) .expect("Def must be pre-declared before definition"); let gen_scope = this.defs.get(id).gen_scope; let mut infer = Infer::new(&mut this, Some(gen_scope)) - .with_debug(attr.iter().find(|a| **a.name == "ty_debug").is_some()) + .with_debug(attr.iter().any(|a| **a.name == "ty_debug")) .with_gen_scope_implied(); - let ty_hint = def.ty_hint.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + let ty_hint = def + .ty_hint + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); let gen_tys = (0..infer.ctx().tys.get_gen_scope(gen_scope).len()) .map(|i| { @@ -846,12 +977,22 @@ impl Context { .collect(); let gen_effs = (0..infer.ctx().tys.get_gen_scope(gen_scope).len_eff()) .map(|i| { - let span = infer.ctx().tys.get_gen_scope(gen_scope).get_eff(i).name.span(); + let span = infer + .ctx() + .tys + .get_gen_scope(gen_scope) + .get_eff(i) + .name + .span(); infer.insert_gen_eff(span, i, gen_scope) }) .collect(); - let body = def.body.to_hir(&(), &mut infer, &Scope::Recursive(def.name.clone(), ty_hint.meta().1, id, gen_tys, gen_effs)); + let body = def.body.to_hir( + &(), + &mut infer, + &Scope::Recursive(def.name.clone(), ty_hint.meta().1, id, gen_tys, gen_effs), + ); infer.make_flow(body.meta().1, ty_hint.meta().1, body.meta().0); let (mut checked, mut errs) = infer.into_checked(); @@ -883,7 +1024,9 @@ impl Context { ConContext::from_ctx(self) } - pub fn emit(&mut self, error: Error) { self.errors.push(error) } + pub fn emit(&mut self, error: Error) { + self.errors.push(error) + } // Returns (record_ty, field_ty, number_of_indirections) pub fn follow_field_access(&self, mut ty: TyId, field: Ident) -> Option<(TyId, TyId, usize)> { @@ -891,25 +1034,29 @@ impl Context { loop { match self.tys.get(ty) { - Ty::Data(data, _gen_tys) => if already_seen.contains(&data) { - // We've already seen this data type, it must be recursive. Give up, it has no fields. - break None - } else { - already_seen.push(data); - let data = self.datas.get_data(data); - if data.cons.len() == 1 { - ty = data.cons[0].1; + Ty::Data(data, _gen_tys) => { + if already_seen.contains(&data) { + // We've already seen this data type, it must be recursive. Give up, it has no fields. + break None; } else { - // Sum types have no fields + already_seen.push(data); + let data = self.datas.get_data(data); + if data.cons.len() == 1 { + ty = data.cons[0].1; + } else { + // Sum types have no fields + break None; + } + } + } + Ty::Record(fields, _) => { + if let Some((_, field_ty)) = fields.iter().find(|(name, _)| **name == field) { + break Some((ty, *field_ty, already_seen.len())); + } else { + // Record has no such field break None; } - }, - Ty::Record(fields, _) => if let Some((_, field_ty)) = fields.iter().find(|(name, _)| **name == field) { - break Some((ty, *field_ty, already_seen.len())); - } else { - // Record has no such field - break None; - }, + } _ => break None, // Only `Data` or `Record` can have fields } } @@ -920,39 +1067,67 @@ impl Context { f(&mut infer); - let gen_scope = infer - .ctx() - .tys - .get_gen_scope(gen_scope_id); - let ast_implied_members = gen_scope - .ast_implied_members - .clone(); + let gen_scope = infer.ctx().tys.get_gen_scope(gen_scope_id); + let ast_implied_members = gen_scope.ast_implied_members.clone(); let infer_members = ast_implied_members .into_iter() .filter_map(|member| { - let class = if let Some(class_id) = infer.ctx_mut().classes.lookup(*member.class.name) { - SrcNode::new(class_id, member.class.span()) - } else { - infer.ctx_mut().errors.push(Error::NoSuchClass(member.class.name.clone())); - return None; - }; - - let ty = member.member.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); - let gen_tys = member.class.gen_tys + let class = + if let Some(class_id) = infer.ctx_mut().classes.lookup(*member.class.name) { + SrcNode::new(class_id, member.class.span()) + } else { + infer + .ctx_mut() + .errors + .push(Error::NoSuchClass(member.class.name.clone())); + return None; + }; + + let ty = member + .member + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty); + let gen_tys = member + .class + .gen_tys .iter() - .map(|ty| ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1) + .map(|ty| { + ty.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1 + }) .collect::>(); - let gen_effs = member.class.gen_effs + let gen_effs = member + .class + .gen_effs .iter() - .map(|eff| lower::lower_effect_set(eff, &TypeLowerCfg::other(), &mut infer, &Scope::Empty)) + .map(|eff| { + lower::lower_effect_set( + eff, + &TypeLowerCfg::other(), + &mut infer, + &Scope::Empty, + ) + }) .collect::>(); - let items = member.assoc + let items = member + .assoc .iter() - .map(|(name, assoc)| (name.clone(), assoc.to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty).meta().1)) + .map(|(name, assoc)| { + ( + name.clone(), + assoc + .to_hir(&TypeLowerCfg::other(), &mut infer, &Scope::Empty) + .meta() + .1, + ) + }) .collect::>(); - let gen_scope = infer.ctx().tys.get_gen_scope(infer.ctx().classes.get(*class).gen_scope); + let gen_scope = infer + .ctx() + .tys + .get_gen_scope(infer.ctx().classes.get(*class).gen_scope); if gen_scope.len() != gen_tys.len() || gen_scope.len_eff() != gen_effs.len() { // TODO: Proper error for effect length mismatch let item_span = gen_scope.item_span; @@ -983,28 +1158,27 @@ impl Context { let implied_members = infer_members .into_iter() .map(|(ty, class, gen_tys, gen_effs, items, span)| { - SrcNode::new(TyImpliedMember { - member: SrcNode::new(checked.reify(ty.meta().1), ty.meta().0), - gen_tys: gen_tys - .iter() - .map(|ty| checked.reify(*ty)) - .collect(), - gen_effs: gen_effs - .iter() - .map(|eff| checked.reify_effect(*eff)) - .collect(), - class, - items: ImpliedItems::Eq(items - .iter() - .map(|(name, assoc)| (name.clone(), checked.reify(*assoc))) - .collect()), - }, span) + SrcNode::new( + TyImpliedMember { + member: SrcNode::new(checked.reify(ty.meta().1), ty.meta().0), + gen_tys: gen_tys.iter().map(|ty| checked.reify(*ty)).collect(), + gen_effs: gen_effs + .iter() + .map(|eff| checked.reify_effect(*eff)) + .collect(), + class, + items: ImpliedItems::Eq( + items + .iter() + .map(|(name, assoc)| (name.clone(), checked.reify(*assoc))) + .collect(), + ), + }, + span, + ) }) .collect(); - self - .tys - .get_gen_scope_mut(gen_scope_id) - .implied_members = Some(implied_members); + self.tys.get_gen_scope_mut(gen_scope_id).implied_members = Some(implied_members); } } diff --git a/analysis/src/data.rs b/analysis/src/data.rs index f41b17a..52dc227 100644 --- a/analysis/src/data.rs +++ b/analysis/src/data.rs @@ -37,7 +37,6 @@ pub struct Datas { // TODO: Don't use `Result` name_lut: HashMap, GenScopeId)>, cons_lut: HashMap, - alias_lut: HashMap, datas: Vec<(Span, Option, GenScopeId, Ident)>, aliases: Vec<(Span, Option, GenScopeId)>, pub lang: Lang, @@ -49,7 +48,7 @@ impl Datas { } pub fn iter_aliases(&self) -> impl Iterator { - (0..self.aliases.len()).map(|i| AliasId(i)) + (0..self.aliases.len()).map(AliasId) } pub fn data_gen_scope(&self, data: DataId) -> GenScopeId { @@ -94,27 +93,41 @@ impl Datas { } pub fn get_alias(&self, alias: AliasId) -> Option<&Alias> { - self.aliases[alias.0] - .1 - .as_ref() + self.aliases[alias.0].1.as_ref() } pub fn get_alias_span(&self, alias: AliasId) -> Span { self.aliases[alias.0].0 } - pub fn declare_data(&mut self, name: SrcNode, gen_scope: GenScopeId, attr: &[SrcNode]) -> Result { + pub fn declare_data( + &mut self, + name: SrcNode, + gen_scope: GenScopeId, + attr: &[SrcNode], + ) -> Result { let id = DataId(self.datas.len(), *name); - if let Err(old) = self.name_lut.try_insert(*name, (name.span(), Ok(id), gen_scope)) { - Err(Error::DuplicateTypeName(*name, old.entry.get().0, name.span())) + if let Err(old) = self + .name_lut + .try_insert(*name, (name.span(), Ok(id), gen_scope)) + { + Err(Error::DuplicateTypeName( + *name, + old.entry.get().0, + name.span(), + )) } else { if let Some(lang) = attr .iter() .find(|a| &**a.name == "lang") .and_then(|a| a.args.as_ref()) { - if lang.iter().find(|a| &**a.name == "go").is_some() { self.lang.go = Some(id); } - if lang.iter().find(|a| &**a.name == "bool").is_some() { self.lang.r#bool = Some(id); } + if lang.iter().any(|a| &**a.name == "go") { + self.lang.go = Some(id); + } + if lang.iter().any(|a| &**a.name == "bool") { + self.lang.r#bool = Some(id); + } } self.datas.push((name.span(), None, gen_scope, *name)); @@ -125,13 +138,22 @@ impl Datas { pub fn check_lang_items(&self) -> Vec { let mut errors = Vec::new(); - if self.lang.go.is_none() { errors.push(Error::MissingLangItem("go")); } - if self.lang.r#bool.is_none() { errors.push(Error::MissingLangItem("bool")); } + if self.lang.go.is_none() { + errors.push(Error::MissingLangItem("go")); + } + if self.lang.r#bool.is_none() { + errors.push(Error::MissingLangItem("bool")); + } errors } - pub fn declare_alias(&mut self, name: Ident, span: Span, gen_scope: GenScopeId) -> Result { + pub fn declare_alias( + &mut self, + name: Ident, + span: Span, + gen_scope: GenScopeId, + ) -> Result { let id = AliasId(self.aliases.len()); if let Err(old) = self.name_lut.try_insert(name, (span, Err(id), gen_scope)) { Err(Error::DuplicateTypeName(name, old.entry.get().0, span)) @@ -141,15 +163,19 @@ impl Datas { } } - pub fn define_data(&mut self, id: DataId, span: Span, data: Data) -> Result<(), Vec> { + pub fn define_data(&mut self, id: DataId, _span: Span, data: Data) -> Result<(), Vec> { let mut errors = Vec::new(); for (cons, _) in &data.cons { if let Err(old) = self.cons_lut.try_insert(**cons, (cons.span(), id)) { - errors.push(Error::DuplicateConsName(**cons, old.entry.get().0, cons.span())); + errors.push(Error::DuplicateConsName( + **cons, + old.entry.get().0, + cons.span(), + )); } } self.datas[id.0].1 = Some(data); - if errors.len() == 0 { + if errors.is_empty() { Ok(()) } else { Err(errors) diff --git a/analysis/src/debug.rs b/analysis/src/debug.rs index 2d5a128..224e18a 100644 --- a/analysis/src/debug.rs +++ b/analysis/src/debug.rs @@ -37,12 +37,15 @@ impl<'hir, 'a> dot::Labeller<'a, Node, Edge> for CallGraph<'hir> { impl<'hir, 'a> dot::GraphWalk<'a, Node, Edge> for CallGraph<'hir> { fn nodes(&'a self) -> dot::Nodes<'a, Node> { - self.ctx.defs + self.ctx + .defs .iter() - .filter_map(|(id, def)| if def.attr.iter().find(|a| &**a.name == "util").is_none() { - Some((id, *def.name)) - } else { - None + .filter_map(|(id, def)| { + if !def.attr.iter().any(|a| &**a.name == "util") { + Some((id, *def.name)) + } else { + None + } }) .collect() } @@ -50,11 +53,8 @@ impl<'hir, 'a> dot::GraphWalk<'a, Node, Edge> for CallGraph<'hir> { fn fetch_edge(ctx: &Context, parent: Node, expr: &TyExpr, edges: &mut HashSet) { if let hir::Expr::Global(global) = &**expr { let def = ctx.defs.get(global.0); - if def.attr.iter().find(|a| &**a.name == "util").is_none() { - edges.insert(( - parent, - (global.0, *def.name), - )); + if !def.attr.iter().any(|a| &**a.name == "util") { + edges.insert((parent, (global.0, *def.name))); } } @@ -63,13 +63,17 @@ impl<'hir, 'a> dot::GraphWalk<'a, Node, Edge> for CallGraph<'hir> { let mut edges = HashSet::new(); for (id, def) in self.ctx.defs.iter() { - if def.attr.iter().find(|a| &**a.name == "util").is_none() { + if !def.attr.iter().any(|a| &**a.name == "util") { let parent = (id, *def.name); fetch_edge(self.ctx, parent, def.body.as_ref().unwrap(), &mut edges); } } edges.into_iter().collect() } - fn source(&self, e: &Edge) -> Node { e.0 } - fn target(&self, e: &Edge) -> Node { e.1 } + fn source(&self, e: &Edge) -> Node { + e.0 + } + fn target(&self, e: &Edge) -> Node { + e.1 + } } diff --git a/analysis/src/def.rs b/analysis/src/def.rs index 453eb5d..7399463 100644 --- a/analysis/src/def.rs +++ b/analysis/src/def.rs @@ -52,7 +52,8 @@ impl Defs { if let Err(old) = self.lut.try_insert(name, (span, id)) { Err(Error::DuplicateDefName(name, old.entry.get().0, span)) } else { - if let Some(lang) = def.attr + if let Some(_lang) = def + .attr .iter() .find(|a| &**a.name == "lang") .and_then(|a| a.args.as_ref()) @@ -68,11 +69,7 @@ impl Defs { } pub fn check_lang_items(&self) -> Vec { - let mut errors = Vec::new(); - - // if self.lang.io_unit.is_none() { errors.push(Error::MissingLangItem("io_unit")); } - - errors + Vec::new() } pub fn define_body(&mut self, id: DefId, expr: TyExpr) { diff --git a/analysis/src/effect.rs b/analysis/src/effect.rs index 5baff38..2927e13 100644 --- a/analysis/src/effect.rs +++ b/analysis/src/effect.rs @@ -50,7 +50,10 @@ impl Effects { } pub fn iter(&self) -> impl Iterator { - self.effect_decls.iter().enumerate().map(|(i, eff)| (EffectDeclId(i, *eff.name), eff)) + self.effect_decls + .iter() + .enumerate() + .map(|(i, eff)| (EffectDeclId(i, *eff.name), eff)) } // pub fn iter(&self) -> impl Iterator { @@ -65,9 +68,14 @@ impl Effects { let id = EffectDeclId(self.effect_decls.len(), *eff.name); let span = eff.name.span(); if let Err(old) = self.lut.try_insert(*eff.name, (span, Ok(id))) { - Err(Error::DuplicateEffectDecl(*eff.name, old.entry.get().0, span)) + Err(Error::DuplicateEffectDecl( + *eff.name, + old.entry.get().0, + span, + )) } else { - if let Some(lang) = eff.attr + if let Some(_lang) = eff + .attr .iter() .find(|a| &**a.name == "lang") .and_then(|a| a.args.as_ref()) @@ -86,7 +94,11 @@ impl Effects { let id = EffectAliasId(self.effect_aliases.len()); let span = alias.name.span(); if let Err(old) = self.lut.try_insert(*alias.name, (span, Err(id))) { - Err(Error::DuplicateEffectDecl(*alias.name, old.entry.get().0, span)) + Err(Error::DuplicateEffectDecl( + *alias.name, + old.entry.get().0, + span, + )) } else { self.effect_aliases.push(alias); Ok(id) @@ -94,11 +106,7 @@ impl Effects { } pub fn check_lang_items(&self) -> Vec { - let mut errors = Vec::new(); - - // if self.lang.not.is_none() { errors.push(Error::MissingLangItem("not")); } - - errors + Vec::new() } pub fn define_send_recv(&mut self, id: EffectDeclId, send: TyId, recv: TyId) { @@ -106,7 +114,11 @@ impl Effects { self.effect_decls[id.0].recv = Some(recv); } - pub fn define_alias_effects(&mut self, id: EffectAliasId, effs: Vec<(SrcNode, Vec)>) { + pub fn define_alias_effects( + &mut self, + id: EffectAliasId, + effs: Vec<(SrcNode, Vec)>, + ) { self.effect_aliases[id.0].effects = Some(effs); } } diff --git a/analysis/src/error.rs b/analysis/src/error.rs index 03b3f20..adb7948 100644 --- a/analysis/src/error.rs +++ b/analysis/src/error.rs @@ -16,7 +16,13 @@ pub enum Error { WrongNumberOfParams(Span, usize, Span, usize), NoBranches(Span), // (obligation, type, obligation_origin, generic_definition - TypeDoesNotFulfil(Option<(ClassId, Vec, Vec>)>, TyId, Span, Option, Span), + TypeDoesNotFulfil( + Option<(ClassId, Vec, Vec>)>, + TyId, + Span, + Option, + Span, + ), CycleWhenResolving(TyId, (ClassId, Vec, Vec>), Span), NoSuchData(SrcNode), NoSuchCons(SrcNode), @@ -52,28 +58,36 @@ pub enum Error { } impl Error { - pub fn write>(self, ctx: &Context, cache: C, main_src: SrcId, writer: impl Write) { - use ariadne::{Report, ReportKind, Label, Color, Fmt, Span, Config}; + pub fn write>( + self, + ctx: &Context, + cache: C, + main_src: SrcId, + writer: impl Write, + ) { + use ariadne::{Color, Config, Fmt, Label, Report, ReportKind, Span}; let display = |id| ctx.tys.display(ctx, id); - let display_eff = |id| if let Some(eff) = id { - ctx.tys.display_eff(ctx, eff).to_string() - } else { - format!("!") + let display_eff = |id| { + if let Some(eff) = id { + ctx.tys.display_eff(ctx, eff).to_string() + } else { + "!".to_string() + } }; - let display_class = |class_id, gen_tys: &[_], gen_effs: &[_]| format!( - "{}{}", - *ctx.classes.get(class_id).name, - gen_tys - .iter() - .map(|ty| format!(" {}", display(*ty))) - .chain(gen_effs + let display_class = |class_id, gen_tys: &[_], gen_effs: &[_]| { + format!( + "{}{}", + *ctx.classes.get(class_id).name, + gen_tys .iter() - .map(|eff| format!(" {}", display_eff(*eff)))) - .collect::(), - ); + .map(|ty| format!(" {}", display(*ty))) + .chain(gen_effs.iter().map(|eff| format!(" {}", display_eff(*eff)))) + .collect::(), + ) + }; let (msg, spans, notes) = match self { Error::CannotCoerce(x, y, inner, info) => { @@ -91,7 +105,7 @@ impl Error { (ctx.tys.get_span(dst), format!("Type {} is required here", display(dst).fg(Color::Yellow)), Color::Yellow), ]; if let Some(at) = info.at { - labels.push((at, format!("Coercion is required here"), Color::Cyan)); + labels.push((at, "Coercion is required here".to_string(), Color::Cyan)); } labels }, @@ -106,22 +120,22 @@ impl Error { format!("Cannot infer type {}", display(a).fg(Color::Red)), match origin { Some(origin) => vec![ - (ctx.tys.get_span(a), format!("Use of generic item"), Color::Red), - (origin, format!("Instantiation of this generic type"), Color::Yellow) + (ctx.tys.get_span(a), "Use of generic item".to_string(), Color::Red), + (origin, "Instantiation of this generic type".to_string(), Color::Yellow) ], None => vec![(ctx.tys.get_span(a), format!("{}", display(a)), Color::Red)], }, vec![], ), Error::CannotInferEffect(span, _a) => ( - format!("Cannot infer effect"), - vec![(span, format!("Cannot be inferred"), Color::Red)], + "Cannot infer effect".to_string(), + vec![(span, "Cannot be inferred".to_string(), Color::Red)], vec![], ), Error::NotEffectful(ty, obj_span, span) => ( format!("Type {} has no effects to be propagated", display(ty).fg(Color::Yellow)), vec![ - (span, format!("Propagation is attempted here"), Color::Red), + (span, "Propagation is attempted here".to_string(), Color::Red), (obj_span, format!("This is of type {} and so has no effects to propagate", display(ty).fg(Color::Yellow)), Color::Yellow), ], vec![format!("Only values with types like {} can have their effects propagated to the enclosing scope", "e ~ T".fg(Color::Cyan))], @@ -129,11 +143,11 @@ impl Error { Error::Recursive(a, span, part) => ( format!("Self-referencing type {} expands to have infinite size", display(a).fg(Color::Red)), vec![ - (span, format!("Mentions itself"), Color::Red), - (part, format!("Self-reference occurs here"), Color::Yellow), + (span, "Mentions itself".to_string(), Color::Red), + (part, "Self-reference occurs here".to_string(), Color::Yellow), ], vec![ - format!("Types expand eagerly and so self-reference results in infinite size"), + "Types expand eagerly and so self-reference results in infinite size".to_string(), format!("If this was intentional, consider using {} instead", "data".fg(Color::Cyan)), ], ), @@ -142,10 +156,10 @@ impl Error { ( format!("Type alias {} not valid here", alias.name.fg(Color::Red)), vec![ - (span, format!("Not valid here"), Color::Red), + (span, "Not valid here".to_string(), Color::Red), ], vec![ - format!("Types aliases are not valid as class members"), + "Types aliases are not valid as class members".to_string(), format!("Consider using the full type, {}, instead", display(alias.ty).fg(Color::Blue)), ], ) @@ -154,7 +168,7 @@ impl Error { format!("Type {} has no item named {}", display(a).fg(Color::Red), (*field).fg(Color::Red)), vec![ (record_span, format!("Has type {}", display(a).fg(Color::Yellow)), Color::Yellow), - (field.span(), format!("Item does not exist"), Color::Red), + (field.span(), "Item does not exist".to_string(), Color::Red), ], vec![], ), @@ -162,17 +176,17 @@ impl Error { format!("Type {} has no field named {}", display(a).fg(Color::Red), (*field).fg(Color::Red)), vec![ (record_span, format!("Has type {}", display(a).fg(Color::Yellow)), Color::Yellow), - (field.span(), format!("Field does not exist"), Color::Red), + (field.span(), "Field does not exist".to_string(), Color::Red), ], vec![], ), Error::NoSuchLocal(local) => ( format!("No such local {}", (*local).fg(Color::Red)), - vec![(local.span(), format!("Scope does not contain this"), Color::Red)], + vec![(local.span(), "Scope does not contain this".to_string(), Color::Red)], vec![], ), Error::WrongNumberOfParams(a, a_count, b, b_count) => ( - format!("Pattern arms must all have the same number of parameters"), + "Pattern arms must all have the same number of parameters".to_string(), vec![ (a, format!("Has {} parameter(s)", a_count), Color::Red), (b, format!("Has {} parameter(s)", b_count), Color::Red), @@ -180,21 +194,21 @@ impl Error { vec![], ), Error::NoBranches(span) => ( - format!("Pattern match must have at least one branch"), - vec![(span, format!("Must have a branch"), Color::Red)], + "Pattern match must have at least one branch".to_string(), + vec![(span, "Must have a branch".to_string(), Color::Red)], vec![], ), Error::TypeDoesNotFulfil(class, ty, obl_span, gen_span, use_span) => { let class = if let Some((class_id, gen_tys, gen_effs)) = class { display_class(class_id, &gen_tys, &gen_effs) } else { - format!("?") + "?".to_string() }; ( format!("Type {} is not a member of {}", display(ty).fg(Color::Red), (&class).fg(Color::Cyan)), { let mut labels = vec![ - (use_span, format!("Because it is used here"), Color::Yellow), + (use_span, "Because it is used here".to_string(), Color::Yellow), (ctx.tys.get_span(ty), format!( "This is of type {}", display(ty).fg(Color::Red), @@ -209,7 +223,7 @@ impl Error { } labels }, - vec![format!("Types must fulfil their class obligations")], + vec!["Types must fulfil their class obligations".to_string()], ) }, Error::CycleWhenResolving(ty, (class_id, gen_tys, gen_effs), cycle_span) => ( @@ -219,36 +233,36 @@ impl Error { display_class(class_id, &gen_tys, &gen_effs).fg(Color::Cyan), ), vec![ - (cycle_span, format!("This bound causes cyclical reasoning"), Color::Red), + (cycle_span, "This bound causes cyclical reasoning".to_string(), Color::Red), (ctx.tys.get_span(ty), format!( "This is of type {}", display(ty).fg(Color::Red), ), Color::Red), ], - vec![format!("Types must fulfil their class obligations")], + vec!["Types must fulfil their class obligations".to_string()], ), Error::NoSuchData(a) => ( format!("No such type {}", (*a).fg(Color::Red)), - vec![(a.span(), format!("Does not exist"), Color::Red)], + vec![(a.span(), "Does not exist".to_string(), Color::Red)], vec![], ), Error::NoSuchCons(a) => ( format!("No such constructor {}", (*a).fg(Color::Red)), - vec![(a.span(), format!("Does not exist"), Color::Red)], + vec![(a.span(), "Does not exist".to_string(), Color::Red)], vec![], ), Error::NoSuchClass(a) => ( format!("No such class {}", (*a).fg(Color::Red)), - vec![(a.span(), format!("Does not exist"), Color::Red)], + vec![(a.span(), "Does not exist".to_string(), Color::Red)], vec![], ), Error::NoSuchClassItem(item, class) => ( format!("No such item {} on class {}", (*item).fg(Color::Red), (*class).fg(Color::Red)), vec![ - (item.span(), format!("This item is not required in the class contract"), Color::Red), + (item.span(), "This item is not required in the class contract".to_string(), Color::Red), (class.span(), format!("Does not have an item named {}", (*item).fg(Color::Red)), Color::Yellow), ], - vec![format!("Class members must provide only the items required by their class")], + vec!["Class members must provide only the items required by their class".to_string()], ), Error::MissingClassItem(member, class, item) => ( format!("Member of class {} is missing class item {}", (*class).fg(Color::Red), (*item).fg(Color::Red)), @@ -260,14 +274,14 @@ impl Error { ), Error::NoSuchEffect(a) => ( format!("No such effect {}", (*a).fg(Color::Red)), - vec![(a.span(), format!("Does not exist"), Color::Red)], + vec![(a.span(), "Does not exist".to_string(), Color::Red)], vec![], ), Error::RecursiveAlias(alias, ty, span) => ( - format!("Recursive type alias"), + "Recursive type alias".to_string(), vec![ - (ctx.datas.get_alias_span(alias), format!("Alias mentions itself, leading to an infinite expansion"), Color::Red), - (span, format!("Recursion occurs here"), Color::Yellow), + (ctx.datas.get_alias_span(alias), "Alias mentions itself, leading to an infinite expansion".to_string(), Color::Red), + (span, "Recursion occurs here".to_string(), Color::Yellow), ], { let alias = ctx.datas.get_alias(alias).unwrap(); @@ -280,16 +294,16 @@ impl Error { Error::DuplicateTypeName(name, old, new) => ( format!("Type {} cannot be declared multiple times", name.fg(Color::Red)), vec![ - (old, format!("Previous declaration"), Color::Yellow), - (new, format!("Conflicting declaration"), Color::Red), + (old, "Previous declaration".to_string(), Color::Yellow), + (new, "Conflicting declaration".to_string(), Color::Red), ], vec![], ), Error::DuplicateDefName(name, old, new) => ( format!("Definition {} cannot be declared multiple times", name.fg(Color::Red)), vec![ - (old, format!("Previous declaration"), Color::Yellow), - (new, format!("Conflicting declaration"), Color::Red), + (old, "Previous declaration".to_string(), Color::Yellow), + (new, "Conflicting declaration".to_string(), Color::Red), (new, format!("Consider renaming this, perhaps to {}?", format!("{}2", name).fg(Color::Cyan)), Color::Cyan), ], vec![], @@ -297,8 +311,8 @@ impl Error { Error::DuplicateConsName(name, old, new) => ( format!("Constructor {} cannot be declared multiple times", name.fg(Color::Red)), vec![ - (old, format!("Previous declaration"), Color::Yellow), - (new, format!("Conflicting declaration"), Color::Red), + (old, "Previous declaration".to_string(), Color::Yellow), + (new, "Conflicting declaration".to_string(), Color::Red), (new, format!("Consider renaming this, perhaps to {}?", format!("{}2", name).fg(Color::Cyan)), Color::Cyan), ], vec![], @@ -306,8 +320,8 @@ impl Error { Error::DuplicateGenName(name, old, new) => ( format!("Type parameter {} declared multiple times", name.fg(Color::Red)), vec![ - (old, format!("Previous type parameter"), Color::Yellow), - (new, format!("Conflicting type parameter"), Color::Red), + (old, "Previous type parameter".to_string(), Color::Yellow), + (new, "Conflicting type parameter".to_string(), Color::Red), (new, format!("Consider renaming this, perhaps to {}?", format!("{}2", name).fg(Color::Cyan)), Color::Cyan), ], vec![], @@ -315,32 +329,32 @@ impl Error { Error::DuplicateClassName(name, old, new) => ( format!("Type class {} declared multiple times", name.fg(Color::Red)), vec![ - (old, format!("Previous type class"), Color::Yellow), - (new, format!("Conflicting type class"), Color::Red), + (old, "Previous type class".to_string(), Color::Yellow), + (new, "Conflicting type class".to_string(), Color::Red), ], vec![], ), Error::DuplicateEffectDecl(name, old, new) => ( format!("Effect {} declared multiple times", name.fg(Color::Red)), vec![ - (old, format!("Previous effect"), Color::Yellow), - (new, format!("Conflicting effect"), Color::Red), + (old, "Previous effect".to_string(), Color::Yellow), + (new, "Conflicting effect".to_string(), Color::Red), ], vec![], ), Error::DuplicateClassItem(name, old, new) => ( format!("Item {} declared multiple times in class", name.fg(Color::Red)), vec![ - (old, format!("Previous item"), Color::Yellow), - (new, format!("Conflicting item"), Color::Red), + (old, "Previous item".to_string(), Color::Yellow), + (new, "Conflicting item".to_string(), Color::Red), ], vec![], ), Error::DuplicateMemberItem(name, old, new) => ( format!("Item {} declared multiple times in class member", name.fg(Color::Red)), vec![ - (old, format!("Previous item"), Color::Yellow), - (new, format!("Conflicting item"), Color::Red), + (old, "Previous item".to_string(), Color::Yellow), + (new, "Conflicting item".to_string(), Color::Red), ], vec![], ), @@ -349,7 +363,7 @@ impl Error { vec![(span, format!("Pattern {} used here", (*op).fg(Color::Red)), Color::Red)], vec![format!( "Only specific arithmetic patterns, such as {}, are supported", - format!("Nat + Nat").fg(Color::Blue), + "Nat + Nat".to_string().fg(Color::Blue), )], ), Error::NotExhaustive(span, example, hidden_outer) => ( @@ -361,11 +375,11 @@ impl Error { format!("| {} => ...", example.display(ctx, hidden_outer)).fg(Color::Blue), )] } else { - vec![format!("Let patterns must be exhaustive")] + vec!["Let patterns must be exhaustive".to_string()] }, ), Error::WrongNumberOfGenerics(a, a_count, b, b_count) => ( - format!("Wrong number of type parameters"), + "Wrong number of type parameters".to_string(), vec![ (a, format!("Provided with {} parameters", a_count), Color::Red), (b, format!("Has {} parameter(s)", b_count), Color::Yellow), @@ -382,8 +396,8 @@ impl Error { ( format!("Type of {} must be fully specified", name.fg(Color::Red)), vec![ - (def.span(), format!("Definition does not have a fully specified type hint"), Color::Red), - (usage, format!("Type must be fully known here"), Color::Yellow), + (def.span(), "Definition does not have a fully specified type hint".to_string(), Color::Red), + (usage, "Type must be fully known here".to_string(), Color::Yellow), ], vec![format!( "Add a type hint to the def like {}", @@ -394,41 +408,41 @@ impl Error { Error::SelfNotValidHere(span) => ( format!("Special type {} cannot be used here", "Self".fg(Color::Red)), vec![ - (span, format!("Not valid in this context"), Color::Red), + (span, "Not valid in this context".to_string(), Color::Red), ], vec![format!("The {} type can only be used in type classes", "Self".fg(Color::Blue))], ), Error::AssocNotValidHere(span) => ( - format!("Associated types cannot be used here"), + "Associated types cannot be used here".to_string(), vec![ - (span, format!("Not valid in this context"), Color::Red), + (span, "Not valid in this context".to_string(), Color::Red), ], - vec![format!("Associated types may not be used as class members directly")], + vec!["Associated types may not be used as class members directly".to_string()], ), Error::NoEntryPoint(root_span) => ( - format!("No main definition"), - vec![(root_span, format!("Does not contain a definition marked as the main entry point"), Color::Red)], + "No main definition".to_string(), + vec![(root_span, "Does not contain a definition marked as the main entry point".to_string(), Color::Red)], vec![format!("Mark a definition as the main entry point with {}", "$[main]".fg(Color::Blue))], ), Error::MultipleEntryPoints(a, b) => ( - format!("Multiple entry points"), + "Multiple entry points".to_string(), vec![ - (a, format!("First entry point is here"), Color::Red), - (b, format!("Second entry point is here"), Color::Red), + (a, "First entry point is here".to_string(), Color::Red), + (b, "Second entry point is here".to_string(), Color::Red), ], - vec![format!("A program may only have a single entry point")], + vec!["A program may only have a single entry point".to_string()], ), Error::GenericEntryPoint(name, gen) => ( format!("Entry point {} cannot be generic", (*name).fg(Color::Red)), vec![ - (gen, format!("Generics are not allowed here"), Color::Red), + (gen, "Generics are not allowed here".to_string(), Color::Red), ], - vec![format!("A program cannot be generic over types")], + vec!["A program cannot be generic over types".to_string()], ), Error::AmbiguousClassItem(item, candidate_classes) => ( format!("Class item {} is ambiguous", (*item).fg(Color::Red)), vec![ - (item.span(), format!("Item could be from multiple classes"), Color::Red), + (item.span(), "Item could be from multiple classes".to_string(), Color::Red), ], vec![format!("Possible candidates are members of {}", candidate_classes .into_iter() @@ -439,35 +453,35 @@ impl Error { Error::InvalidIntrinsic(intrinsic) => ( format!("Intrinsic {} is not valid", (*intrinsic).fg(Color::Red)), vec![ - (intrinsic.span(), format!("No such intrinsic"), Color::Red), + (intrinsic.span(), "No such intrinsic".to_string(), Color::Red), ], - vec![format!("Maybe the wrong number of arguments were used?")], + vec!["Maybe the wrong number of arguments were used?".to_string()], ), Error::Unsupported(span, feature) => ( format!("Feature {} is not yet supported", feature.fg(Color::Yellow)), vec![ - (span, format!("This is unsupported"), Color::Red), + (span, "This is unsupported".to_string(), Color::Red), ], vec![], ), Error::MissingLangItem(name) => ( format!("Lang item {} is missing", name.fg(Color::Yellow)), Vec::new(), - vec![format!("All lang items must be defined")], + vec!["All lang items must be defined".to_string()], ), Error::NoBasin(span) => ( - format!("Effect propagated, but nothing catches it"/*, display(eff_ty).fg(Color::Yellow)*/), + "Effect propagated, but nothing catches it".to_string(), vec![ - (span, format!("Nothing catches this propagation"), Color::Red), + (span, "Nothing catches this propagation".to_string(), Color::Red), ], vec![format!("Place this expression within a {} block", "effect { ... }".fg(Color::Blue))], ), Error::NotMentioned(param) => ( format!("Generic parameter {} not mentioned in item", (*param).fg(Color::Red)), vec![ - (param.span(), format!("The item this generic parameterises does not mention it"), Color::Red), + (param.span(), "The item this generic parameterises does not mention it".to_string(), Color::Red), ], - vec![format!("Generic parameters must always be mentioned by the thing they parameterise")], + vec!["Generic parameters must always be mentioned by the thing they parameterise".to_string()], ), }; @@ -476,14 +490,16 @@ impl Error { spans.first().map(|s| s.0.src()).unwrap_or(main_src), spans.first().map(|s| s.0.start()).unwrap_or(0), ) - .with_code(3) - .with_message(msg); + .with_code(3) + .with_message(msg); for (i, (span, msg, col)) in spans.into_iter().enumerate() { - report = report.with_label(Label::new(span) - .with_message(msg) - .with_order(i as i32) - .with_color(col)); + report = report.with_label( + Label::new(span) + .with_message(msg) + .with_order(i as i32) + .with_color(col), + ); } for note in notes { @@ -491,8 +507,7 @@ impl Error { } report - .with_config(Config::default() - .with_compact(false)) + .with_config(Config::default().with_compact(false)) .finish() .write(cache, writer) .unwrap(); diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 49e0f02..c80aec1 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -1,10 +1,6 @@ use super::*; -use std::{ - ops::Range, - cmp::Ord, - fmt, -}; use ranges::Ranges; +use std::{fmt}; #[derive(Debug)] pub enum AbstractPat { @@ -16,13 +12,13 @@ pub enum AbstractPat { // (_, is_tuple) Record(Vec<(Ident, Self)>, bool), Variant(DataId, Ident, Box), - ListExact(Vec), // Exactly N in size + ListExact(Vec), // Exactly N in size ListFront(Vec, Box), // At least N in size Gen(Ident), } impl AbstractPat { - fn from_binding(ctx: &Context, binding: &TyBinding) -> Self { + fn from_binding(binding: &TyBinding) -> Self { match &*binding.pat { hir::Pat::Error => Self::Wildcard, hir::Pat::Wildcard => Self::Wildcard, @@ -37,26 +33,44 @@ impl AbstractPat { range }), hir::Pat::Literal(hir::Literal::Char(c)) => Self::Char(*c), - hir::Pat::Literal(hir::Literal::Str(x)) => Self::ListExact(x.chars().map(Self::Char).collect()), - hir::Pat::Single(inner) => Self::from_binding(ctx, inner), + hir::Pat::Literal(hir::Literal::Str(x)) => { + Self::ListExact(x.chars().map(Self::Char).collect()) + } + hir::Pat::Single(inner) => Self::from_binding(inner), hir::Pat::Add(lhs, rhs) if matches!(&*lhs.pat, hir::Pat::Wildcard) => Self::Nat({ let mut range = Ranges::new(); range.insert(**rhs..); range }), - hir::Pat::Decons(data, cons, inner) => AbstractPat::Variant(**data, *cons, Box::new(AbstractPat::from_binding(ctx, inner))), - hir::Pat::ListExact(items) => AbstractPat::ListExact(items - .iter() - .map(|item| AbstractPat::from_binding(ctx, item)) - .collect()), - hir::Pat::ListFront(items, tail) => AbstractPat::ListFront(items - .iter() - .map(|item| AbstractPat::from_binding(ctx, item)) - .collect(), Box::new(tail.as_ref().map(|tail| AbstractPat::from_binding(ctx, tail)).unwrap_or(AbstractPat::Wildcard))), - hir::Pat::Record(fields, is_tuple) => AbstractPat::Record(fields - .iter() - .map(|(name, field)| (*name, AbstractPat::from_binding(ctx, field))) - .collect(), *is_tuple), + hir::Pat::Decons(data, cons, inner) => AbstractPat::Variant( + **data, + *cons, + Box::new(AbstractPat::from_binding(inner)), + ), + hir::Pat::ListExact(items) => AbstractPat::ListExact( + items + .iter() + .map(AbstractPat::from_binding) + .collect(), + ), + hir::Pat::ListFront(items, tail) => AbstractPat::ListFront( + items + .iter() + .map(AbstractPat::from_binding) + .collect(), + Box::new( + tail.as_ref() + .map(AbstractPat::from_binding) + .unwrap_or(AbstractPat::Wildcard), + ), + ), + hir::Pat::Record(fields, is_tuple) => AbstractPat::Record( + fields + .iter() + .map(|(name, field)| (*name, AbstractPat::from_binding(field))) + .collect(), + *is_tuple, + ), pat => todo!("{:?}", pat), } } @@ -68,7 +82,9 @@ impl AbstractPat { AbstractPat::Int(set) => !set.clone().invert().is_empty(), AbstractPat::Char(_) => true, AbstractPat::ListExact(_) => true, - AbstractPat::ListFront(items, tail) => !items.is_empty() || tail.is_refutable_basic(ctx), + AbstractPat::ListFront(items, tail) => { + !items.is_empty() || tail.is_refutable_basic(ctx) + } AbstractPat::Variant(data, _, _) => ctx.datas.get_data(*data).cons.len() > 1, AbstractPat::Record(fields, _) => !fields .iter() @@ -77,20 +93,25 @@ impl AbstractPat { } } - fn is_refutable(&self, ctx: &Context, ty: TyId, get_gen_ty: Option<&dyn Fn(usize) -> Option>) -> bool { + fn is_refutable( + &self, + ctx: &Context, + ty: TyId, + get_gen_ty: Option<&dyn Fn(usize) -> Option>, + ) -> bool { Self::inexhaustive_pat(ctx, ty, &mut std::iter::once(self), get_gen_ty).is_some() } - fn inexhaustive_pat<'a>( + fn inexhaustive_pat( ctx: &Context, ty: TyId, - mut filter: &mut dyn Iterator, + mut filter: &mut dyn Iterator, get_gen_ty: Option<&dyn Fn(usize) -> Option>, ) -> Option { let ty = match ctx.tys.get(ty) { - Ty::Gen(idx, _) => { - get_gen_ty.and_then(|get_gen_ty| get_gen_ty(idx)).unwrap_or(ty) - }, + Ty::Gen(idx, _) => get_gen_ty + .and_then(|get_gen_ty| get_gen_ty(idx)) + .unwrap_or(ty), _ => ty, }; @@ -105,8 +126,13 @@ impl AbstractPat { _ => return None, // Type mismatch, don't yield an error because one was already generated } } - covered.clone().invert().into_iter().next().map(ExamplePrim::Nat).map(ExamplePat::Prim) - }, + covered + .invert() + .into_iter() + .next() + .map(ExamplePrim::Nat) + .map(ExamplePat::Prim) + } Ty::Prim(Prim::Int) => { let mut covered = Ranges::new(); for pat in filter { @@ -116,29 +142,35 @@ impl AbstractPat { _ => return None, // Type mismatch, don't yield an error because one was already generated } } - covered.clone().invert().into_iter().next().map(ExamplePrim::Int).map(ExamplePat::Prim) - }, + covered + .invert() + .into_iter() + .next() + .map(ExamplePrim::Int) + .map(ExamplePat::Prim) + } Ty::Prim(Prim::Char) => { for pat in filter { match pat { AbstractPat::Wildcard => return None, - AbstractPat::Char(_) => {}, + AbstractPat::Char(_) => {} _ => return None, // Type mismatch, don't yield an error because one was already generated } } Some(ExamplePat::Wildcard) - }, + } Ty::Prim(Prim::Real) => { for pat in filter { match pat { AbstractPat::Wildcard => return None, - AbstractPat::Real(_) => {}, + AbstractPat::Real(_) => {} _ => return None, // Type mismatch, don't yield an error because one was already generated } } Some(ExamplePat::Wildcard) - }, + } Ty::Prim(Prim::Universe) => { + #[allow(clippy::never_loop)] for pat in filter { match pat { AbstractPat::Wildcard => return None, @@ -146,8 +178,7 @@ impl AbstractPat { } } Some(ExamplePat::Wildcard) - }, - Ty::Prim(prim) => todo!("{:?}", prim), + } Ty::Record(fields, is_tuple) if fields.len() == 1 => { let mut inners = Vec::new(); for pat in filter { @@ -157,26 +188,41 @@ impl AbstractPat { _ => return None, // Type mismatch, don't yield an error because one was already generated } } - Self::inexhaustive_pat(ctx, *fields.values().next().unwrap(), &mut inners.into_iter(), get_gen_ty) - .map(|inner| ExamplePat::Record(vec![(*fields.keys().next().unwrap(), inner)], is_tuple)) - }, + Self::inexhaustive_pat( + ctx, + *fields.values().next().unwrap(), + &mut inners.into_iter(), + get_gen_ty, + ) + .map(|inner| { + ExamplePat::Record(vec![(*fields.keys().next().unwrap(), inner)], is_tuple) + }) + } Ty::Record(fields, is_tuple) => { let filter = (&mut filter).collect::>(); - if filter.iter().copied().any(|pat| !pat.is_refutable_basic(ctx)) { + if filter + .iter() + .copied() + .any(|pat| !pat.is_refutable_basic(ctx)) + { None } else { let wildcard = AbstractPat::Wildcard; let mut cols = vec![Vec::new(); fields.len()]; for pat in filter.iter().copied() { match pat { - AbstractPat::Wildcard => (0..fields.len()).for_each(|i| cols[i].push((&wildcard, ty))), + AbstractPat::Wildcard => { + (0..fields.len()).for_each(|i| cols[i].push((&wildcard, ty))) + } AbstractPat::Record(pat_fields, _) => { debug_assert_eq!(fields.len(), cols.len()); - for ((i, (_, pat)), (_, ty)) in pat_fields.iter().enumerate().zip(fields.iter()) { + for ((i, (_, pat)), (_, ty)) in + pat_fields.iter().enumerate().zip(fields.iter()) + { cols[i].push((pat, *ty)); } - }, + } _ => return None, // Type mismatch, don't yield an error because one was already generated } } @@ -184,52 +230,77 @@ impl AbstractPat { let mut refutable = cols .into_iter() .enumerate() - .filter(|(_, col)| col.iter().any(|(pat, ty)| pat.is_refutable(ctx, *ty, get_gen_ty))) + .filter(|(_, col)| { + col.iter() + .any(|(pat, ty)| pat.is_refutable(ctx, *ty, get_gen_ty)) + }) .collect::>(); match refutable.len() { 0 => None, 1 => { let (idx, col) = refutable.remove(0); - Self::inexhaustive_pat(ctx, *fields.values().nth(idx).unwrap(), &mut col.into_iter().map(|(pat, _)| pat), get_gen_ty) - .map(|pat| ExamplePat::Record( - (0..idx).map(|idx| (*fields.keys().nth(idx).unwrap(), ExamplePat::Wildcard)) - .chain(std::iter::once((*fields.keys().nth(idx).unwrap(), pat))) - .chain((idx + 1..fields.len()).map(|idx| (*fields.keys().nth(idx).unwrap(), ExamplePat::Wildcard))) - .collect(), is_tuple)) - }, + Self::inexhaustive_pat( + ctx, + *fields.values().nth(idx).unwrap(), + &mut col.into_iter().map(|(pat, _)| pat), + get_gen_ty, + ) + .map(|pat| { + ExamplePat::Record( + (0..idx) + .map(|idx| { + (*fields.keys().nth(idx).unwrap(), ExamplePat::Wildcard) + }) + .chain(std::iter::once(( + *fields.keys().nth(idx).unwrap(), + pat, + ))) + .chain((idx + 1..fields.len()).map(|idx| { + (*fields.keys().nth(idx).unwrap(), ExamplePat::Wildcard) + })) + .collect(), + is_tuple, + ) + }) + } _ => Some(ExamplePat::Wildcard), } } - }, + } Ty::Data(data, gen_tys) => { let mut variants = HashMap::<_, Vec<_>>::default(); for pat in filter { match pat { AbstractPat::Wildcard => return None, - AbstractPat::Variant(_, x, inner) => variants - .entry(*x) - .or_default() - .push(&**inner), + AbstractPat::Variant(_, x, inner) => { + variants.entry(*x).or_default().push(&**inner) + } _ => return None, // Type mismatch, don't yield an error because one was already generated } } for (cons, cons_ty) in &ctx.datas.get_data(data).cons { - let variant_is_empty = || matches!(ctx.tys.get(ctx + let variant_is_empty = || { + matches!(ctx.tys.get(ctx .datas .get_data(data) .cons .iter() .find(|(name, _)| **name == **cons) - .unwrap().1), Ty::Record(fields, _) if fields.is_empty()); + .unwrap().1), Ty::Record(fields, _) if fields.is_empty()) + }; if let Some(variants) = variants.remove(&**cons) { let get_gen_ty = |idx| match ctx.tys.get(gen_tys[idx]) { - Ty::Gen(idx, _) => get_gen_ty - .and_then(|get_gen_ty| get_gen_ty(idx)), + Ty::Gen(idx, _) => get_gen_ty.and_then(|get_gen_ty| get_gen_ty(idx)), _ => Some(gen_tys[idx]), }; - if let Some(pat) = Self::inexhaustive_pat(ctx, *cons_ty, &mut variants.into_iter(), Some(&get_gen_ty)) { + if let Some(pat) = Self::inexhaustive_pat( + ctx, + *cons_ty, + &mut variants.into_iter(), + Some(&get_gen_ty), + ) { return Some(ExamplePat::Variant( **cons, Box::new(pat), @@ -238,7 +309,8 @@ impl AbstractPat { } // TODO: This is ugly, but checks for inhabitants of sub-patterns, allowing things like `let Just x = Just 5` } else if ctx.tys.has_inhabitants(&ctx.datas, *cons_ty, &mut |id| { - ctx.tys.has_inhabitants(&ctx.datas, gen_tys[id], &mut |_| true) + ctx.tys + .has_inhabitants(&ctx.datas, gen_tys[id], &mut |_| true) }) { return Some(ExamplePat::Variant( **cons, @@ -248,40 +320,51 @@ impl AbstractPat { } } None - }, + } Ty::Gen(_, _) | Ty::Assoc(_, _, _) => { for pat in filter { match pat { AbstractPat::Wildcard => return None, - pat => {}, + _pat => {} } } Some(ExamplePat::Wildcard) - }, + } Ty::List(item_ty) => { let mut covered_lens = Ranges::new(); for pat in filter { match pat { AbstractPat::Wildcard => return None, AbstractPat::ListExact(items) => { - if items.iter().all(|item| !item.is_refutable(ctx, item_ty, get_gen_ty)) { + if items + .iter() + .all(|item| !item.is_refutable(ctx, item_ty, get_gen_ty)) + { covered_lens.insert(items.len() as u64..items.len() as u64 + 1); } - }, + } AbstractPat::ListFront(items, tail) => { - if items.iter().all(|item| !item.is_refutable(ctx, item_ty, get_gen_ty)) && !tail.is_refutable(ctx, ty, get_gen_ty) { + if items + .iter() + .all(|item| !item.is_refutable(ctx, item_ty, get_gen_ty)) + && !tail.is_refutable(ctx, ty, get_gen_ty) + { covered_lens.insert(items.len() as u64..); } - }, + } _ => return None, // Type mismatch, don't yield an error because one was already generated } } - covered_lens.clone().invert().into_iter().next().map(|n| { - ExamplePat::List((0..n).map(|_| ExamplePat::Wildcard).collect()) - }) - }, + covered_lens + .clone() + .invert() + .into_iter() + .next() + .map(|n| ExamplePat::List((0..n).map(|_| ExamplePat::Wildcard).collect())) + } Ty::Func(_, _) | Ty::Effect(_, _) => { + #[allow(clippy::never_loop)] for pat in filter { match pat { AbstractPat::Wildcard => return None, @@ -289,7 +372,7 @@ impl AbstractPat { } } Some(ExamplePat::Wildcard) - }, + } ty => todo!("{:?}", ty), } } @@ -330,12 +413,50 @@ impl ExamplePat { match &self.0 { ExamplePat::Wildcard => write!(f, "_"), ExamplePat::Prim(prim) => write!(f, "{}", prim), - ExamplePat::Record(fields, true) if self.1 => write!(f, "{}", fields.iter().map(|(name, f)| format!("{}", DisplayExamplePat(f, false, ctx))).collect::>().join(", ")), - ExamplePat::Record(fields, true) => write!(f, "({})", fields.iter().map(|(name, f)| format!("{},", DisplayExamplePat(f, false, ctx))).collect::>().join(" ")), - ExamplePat::Record(fields, false) => write!(f, "{{ {} }}", fields.iter().map(|(name, f)| format!("{}: {},", name, DisplayExamplePat(f, false, ctx))).collect::>().join(" ")), - ExamplePat::List(items) => write!(f, "[{}]", items.iter().map(|i| format!("{}", DisplayExamplePat(i, false, ctx))).collect::>().join(", ")), - ExamplePat::Variant(name, inner, false) => write!(f, "{} {}", name, DisplayExamplePat(inner, false, ctx)), - ExamplePat::Variant(name, inner, true) => write!(f, "{}", name), + ExamplePat::Record(fields, true) if self.1 => write!( + f, + "{}", + fields + .iter() + .map(|(_name, f)| format!("{}", DisplayExamplePat(f, false, ctx))) + .collect::>() + .join(", ") + ), + ExamplePat::Record(fields, true) => write!( + f, + "({})", + fields + .iter() + .map(|(_name, f)| format!("{},", DisplayExamplePat(f, false, ctx))) + .collect::>() + .join(" ") + ), + ExamplePat::Record(fields, false) => write!( + f, + "{{ {} }}", + fields + .iter() + .map(|(name, f)| format!( + "{}: {},", + name, + DisplayExamplePat(f, false, ctx) + )) + .collect::>() + .join(" ") + ), + ExamplePat::List(items) => write!( + f, + "[{}]", + items + .iter() + .map(|i| format!("{}", DisplayExamplePat(i, false, ctx))) + .collect::>() + .join(", ") + ), + ExamplePat::Variant(name, inner, false) => { + write!(f, "{} {}", name, DisplayExamplePat(inner, false, ctx)) + } + ExamplePat::Variant(name, _inner, true) => write!(f, "{}", name), } } } @@ -344,10 +465,14 @@ impl ExamplePat { } } -pub fn exhaustivity<'a>(ctx: &Context, ty: TyId, arms: impl IntoIterator) -> Result<(), ExamplePat> { +pub fn exhaustivity<'a>( + ctx: &Context, + ty: TyId, + arms: impl IntoIterator, +) -> Result<(), ExamplePat> { let arms = arms .into_iter() - .map(|b| AbstractPat::from_binding(ctx, b)) + .map(AbstractPat::from_binding) .collect::>(); if let Some(pat) = AbstractPat::inexhaustive_pat(ctx, ty, &mut arms.iter(), None) { diff --git a/analysis/src/hir.rs b/analysis/src/hir.rs index 71c56e9..ee3a13c 100644 --- a/analysis/src/hir.rs +++ b/analysis/src/hir.rs @@ -1,6 +1,6 @@ use super::*; -pub use ast::Literal as Literal; +pub use ast::Literal; pub trait Meta { type Ty; @@ -54,11 +54,13 @@ pub enum Pat { impl Pat { pub fn tuple(i: impl IntoIterator, M>>) -> Self { - Self::Record(i - .into_iter() - .enumerate() - .map(|(i, field)| (Ident::new(format!("{}", i)), field)) - .collect(), true) + Self::Record( + i.into_iter() + .enumerate() + .map(|(i, field)| (Ident::new(format!("{}", i)), field)) + .collect(), + true, + ) } } @@ -78,11 +80,17 @@ impl Binding { } pub fn wildcard(name: SrcNode) -> Self { - Self { pat: SrcNode::new(hir::Pat::Wildcard, name.span()), name: Some(name) } + Self { + pat: SrcNode::new(hir::Pat::Wildcard, name.span()), + name: Some(name), + } } pub fn unit(span: Span) -> Self { - Self { pat: SrcNode::new(hir::Pat::tuple([]), span), name: None } + Self { + pat: SrcNode::new(hir::Pat::tuple([]), span), + name: None, + } } } @@ -97,11 +105,13 @@ impl Binding { impl Binding { fn visit_bindings_inner(self: &Node, visit: &mut impl FnMut(&SrcNode, &M)) { // TODO: Check for duplicates! - if let Some(name) = &self.name { visit(name, self.meta()); }; + if let Some(name) = &self.name { + visit(name, self.meta()); + }; match &*self.pat { - Pat::Error => {}, - Pat::Wildcard => {}, - Pat::Literal(_) => {}, + Pat::Error => {} + Pat::Wildcard => {} + Pat::Literal(_) => {} Pat::Single(inner) => inner.visit_bindings_inner(visit), Pat::Add(lhs, _) => lhs.visit_bindings_inner(visit), Pat::Record(fields, _) => fields @@ -114,8 +124,10 @@ impl Binding { items .iter() .for_each(|item| item.visit_bindings_inner(visit)); - if let Some(tail) = tail { tail.visit_bindings_inner(visit); } - }, + if let Some(tail) = tail { + tail.visit_bindings_inner(visit); + } + } Pat::Decons(_, _, inner) => inner.visit_bindings_inner(visit), } } @@ -160,7 +172,11 @@ pub enum Expr { Record(BTreeMap, Node>, bool), Access(Node, SrcNode), // hidden_outer - Match(bool, Node, Vec<(Node, M>, Node)>), + Match( + bool, + Node, + Vec<(Node, M>, Node)>, + ), Func(Node, Node), Apply(Node, Node), Cons(M::Data, Ident, Node), @@ -195,11 +211,18 @@ pub type ConExpr = ConNode>; impl Expr { pub fn tuple(i: impl IntoIterator) -> Self { - Self::Record(i - .into_iter() - .enumerate() - .map(|(i, field)| (SrcNode::new(Ident::new(format!("{}", i)), field.meta().0), field)) - .collect(), true) + Self::Record( + i.into_iter() + .enumerate() + .map(|(i, field)| { + ( + SrcNode::new(Ident::new(format!("{}", i)), field.meta().0), + field, + ) + }) + .collect(), + true, + ) } } @@ -210,48 +233,34 @@ impl Expr { | Expr::Error | Expr::Local(_) | Expr::ClassAccess(_, _, _) - | Expr::Global(_) => {}, + | Expr::Global(_) => {} Expr::List(items, tails) => { - items - .iter() - .for_each(|item| f(item)); - tails - .iter() - .for_each(|tail| f(tail)); - }, - Expr::Record(fields, _) => fields - .iter() - .for_each(|(_, field)| f(field)), - Expr::Access(record, _) => f(&record), + items.iter().for_each(&mut f); + tails.iter().for_each(f); + } + Expr::Record(fields, _) => fields.iter().for_each(|(_, field)| f(field)), + Expr::Access(record, _) => f(record), Expr::Match(_, pred, arms) => { - f(&pred); - arms - .iter() - .for_each(|(_, arm)| f(arm)); - }, - Expr::Func(_, body) => f(&body), + f(pred); + arms.iter().for_each(|(_, arm)| f(arm)); + } + Expr::Func(_, body) => f(body), Expr::Apply(func, arg) => { - f(&func); - f(&arg); - }, - Expr::Cons(_, _, inner) => f(&inner), - Expr::Intrinsic(_, args) => args - .iter() - .for_each(|arg| f(arg)), + f(func); + f(arg); + } + Expr::Cons(_, _, inner) => f(inner), + Expr::Intrinsic(_, args) => args.iter().for_each(f), Expr::Update(record, fields) => { - f(&record); - fields - .iter() - .for_each(|(_, field)| f(field)); - }, - Expr::Basin(_, inner) => f(&inner), - Expr::Suspend(_, inner) => f(&inner), + f(record); + fields.iter().for_each(|(_, field)| f(field)); + } + Expr::Basin(_, inner) => f(inner), + Expr::Suspend(_, inner) => f(inner), Expr::Handle { expr, handlers } => { - f(&expr); - handlers - .iter() - .for_each(|handler| f(&handler.recv)); - }, + f(expr); + handlers.iter().for_each(|handler| f(&handler.recv)); + } } } } @@ -259,13 +268,13 @@ impl Expr { impl Expr { fn required_locals_inner(&self, stack: &mut Vec, required: &mut Vec) { match self { - Expr::Literal(_) | Expr::Error => {}, + Expr::Literal(_) | Expr::Error => {} Expr::Local(local) => { if !stack.contains(local) { required.push(*local); } - }, - Expr::Global(_) => {}, + } + Expr::Global(_) => {} Expr::Intrinsic(_, args) => args .iter() .for_each(|arg| arg.required_locals_inner(stack, required)), @@ -277,16 +286,16 @@ impl Expr { body.required_locals_inner(stack, required); stack.truncate(old_stack); } - }, + } Expr::Func(arg, body) => { stack.push(**arg); body.required_locals_inner(stack, required); stack.pop(); - }, + } Expr::Apply(f, arg) => { f.required_locals_inner(stack, required); arg.required_locals_inner(stack, required); - }, + } Expr::Record(fields, _) => fields .iter() .for_each(|(_, field)| field.required_locals_inner(stack, required)), @@ -297,29 +306,33 @@ impl Expr { tails .iter() .for_each(|tail| tail.required_locals_inner(stack, required)); - }, + } Expr::Access(tuple, _) => tuple.required_locals_inner(stack, required), Expr::Cons(_, _, inner) => inner.required_locals_inner(stack, required), - Expr::Access(inner, _) => inner.required_locals_inner(stack, required), - Expr::ClassAccess(_, _, _) => {}, + Expr::ClassAccess(_, _, _) => {} Expr::Update(record, fields) => { record.required_locals_inner(stack, required); fields .iter() .for_each(|(_, field)| field.required_locals_inner(stack, required)); - }, + } Expr::Basin(_, inner) => inner.required_locals_inner(stack, required), Expr::Suspend(_, inner) => inner.required_locals_inner(stack, required), Expr::Handle { expr, handlers } => { expr.required_locals_inner(stack, required); - for Handler { send, recv, state, .. } in handlers { + for Handler { + send, recv, state, .. + } in handlers + { let old_len = stack.len(); stack.push(**send); - if let Some(state) = state { stack.push(**state); } + if let Some(state) = state { + stack.push(**state); + } recv.required_locals_inner(stack, required); stack.truncate(old_len); } - }, + } } } diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index f2ca03f..89adc04 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1,8 +1,5 @@ use super::*; -use std::{ - cmp::Ordering, - collections::VecDeque, -}; +use std::{cmp::Ordering, collections::VecDeque}; pub type InferMeta = (Span, TyVar); pub type InferNode = Node; @@ -23,12 +20,20 @@ impl Variance { } } - fn is_out(&self) -> bool { matches!(self, Self::Out | Self::InOut) } + fn is_out(&self) -> bool { + matches!(self, Self::Out | Self::InOut) + } } -pub fn covariant() -> Variance { Variance::Out } -pub fn contravariant() -> Variance { Variance::In } -pub fn invariant() -> Variance { Variance::InOut } +pub fn covariant() -> Variance { + Variance::Out +} +pub fn contravariant() -> Variance { + Variance::In +} +pub fn invariant() -> Variance { + Variance::InOut +} #[derive(Clone, Debug, PartialEq)] pub enum TyInfo { @@ -52,11 +57,13 @@ pub enum TyInfo { impl TyInfo { pub fn tuple(i: impl IntoIterator) -> Self { - Self::Record(i - .into_iter() - .enumerate() - .map(|(i, ty)| (Ident::new(format!("{}", i)), ty)) - .collect(), true) + Self::Record( + i.into_iter() + .enumerate() + .map(|(i, ty)| (Ident::new(format!("{}", i)), ty)) + .collect(), + true, + ) } } @@ -68,7 +75,9 @@ pub enum EffectInfo { } impl EffectInfo { - pub fn free() -> Self { Self::Open(Vec::new()) } + pub fn free() -> Self { + Self::Open(Vec::new()) + } } #[derive(Clone, Debug, PartialEq)] @@ -95,13 +104,19 @@ pub struct EqInfo { impl From for EqInfo { fn from(span: Span) -> Self { - Self { at: Some(span), reason: None } + Self { + at: Some(span), + reason: None, + } } } impl EqInfo { pub fn new(at: Span, reason: String) -> Self { - Self { at: Some(at), reason: Some(reason) } + Self { + at: Some(at), + reason: Some(reason), + } } } @@ -120,43 +135,87 @@ trait FlowInfer<'a>: AsRef> { } struct CheckFlow<'a, 'b>(&'b Infer<'a>, Option); -impl<'a, 'b> AsRef> for CheckFlow<'a, 'b> { fn as_ref(&self) -> &Infer<'a> { self.0 } } +impl<'a, 'b> AsRef> for CheckFlow<'a, 'b> { + fn as_ref(&self) -> &Infer<'a> { + self.0 + } +} impl<'a, 'b> FlowInfer<'a> for CheckFlow<'a, 'b> { - fn infer(&self) -> &Infer<'_> { self.0 } - fn is_check(&self) -> bool { true } - fn set_info(&mut self, x: TyVar, info: TyInfo) {} - fn set_effect_info(&mut self, x: EffectVar, info: EffectInfo) { self.1 = Some(false); } - fn set_effect_inst_info(&mut self, x: EffectInstVar, info: EffectInstInfo) { self.1 = Some(false); } - fn set_class_info(&mut self, x: ClassVar, info: ClassInfo) {} - fn set_error(&mut self, x: TyVar) { self.1 = Some(false); } - fn set_unknown_flow(&mut self, x: TyVar, y: TyVar) { if self.1 == Some(true) { self.1 = None; } } - fn emit_error(&mut self, err: InferError) { self.1 = Some(false); } - fn make_check_eff(&mut self, x: (EffectVar, TyVar), y: (EffectVar, TyVar)) -> bool { false } - fn make_check_eff_empty(&mut self, x: (EffectVar, TyVar), other: TyVar) -> bool { false } + fn infer(&self) -> &Infer<'_> { + self.0 + } + fn is_check(&self) -> bool { + true + } + fn set_info(&mut self, _x: TyVar, _info: TyInfo) {} + fn set_effect_info(&mut self, _x: EffectVar, _info: EffectInfo) { + self.1 = Some(false); + } + fn set_effect_inst_info(&mut self, _x: EffectInstVar, _info: EffectInstInfo) { + self.1 = Some(false); + } + fn set_class_info(&mut self, _x: ClassVar, _info: ClassInfo) {} + fn set_error(&mut self, _x: TyVar) { + self.1 = Some(false); + } + fn set_unknown_flow(&mut self, _x: TyVar, _y: TyVar) { + if self.1 == Some(true) { + self.1 = None; + } + } + fn emit_error(&mut self, _err: InferError) { + self.1 = Some(false); + } + fn make_check_eff(&mut self, _x: (EffectVar, TyVar), _y: (EffectVar, TyVar)) -> bool { + false + } + fn make_check_eff_empty(&mut self, _x: (EffectVar, TyVar), _other: TyVar) -> bool { + false + } } struct MakeFlow<'a, 'b>(&'b mut Infer<'a>, &'b EqInfo); -impl<'a, 'b> AsRef> for MakeFlow<'a, 'b> { fn as_ref(&self) -> &Infer<'a> { self.0 } } +impl<'a, 'b> AsRef> for MakeFlow<'a, 'b> { + fn as_ref(&self) -> &Infer<'a> { + self.0 + } +} impl<'a, 'b> FlowInfer<'a> for MakeFlow<'a, 'b> { - fn infer(&self) -> &Infer<'_> { self.0 } - fn is_check(&self) -> bool { false } - fn set_info(&mut self, x: TyVar, info: TyInfo) { self.0.set_info(x, info) } - fn set_effect_info(&mut self, x: EffectVar, info: EffectInfo) { self.0.effect_vars[x.0].1 = info; } - fn set_effect_inst_info(&mut self, x: EffectInstVar, info: EffectInstInfo) { self.0.effect_inst_vars[x.0].1 = info; } - fn set_class_info(&mut self, x: ClassVar, info: ClassInfo) { self.0.class_vars[x.0].1 = info; } + fn infer(&self) -> &Infer<'_> { + self.0 + } + fn is_check(&self) -> bool { + false + } + fn set_info(&mut self, x: TyVar, info: TyInfo) { + self.0.set_info(x, info) + } + fn set_effect_info(&mut self, x: EffectVar, info: EffectInfo) { + self.0.effect_vars[x.0].1 = info; + } + fn set_effect_inst_info(&mut self, x: EffectInstVar, info: EffectInstInfo) { + self.0.effect_inst_vars[x.0].1 = info; + } + fn set_class_info(&mut self, x: ClassVar, info: ClassInfo) { + self.0.class_vars[x.0].1 = info; + } fn set_error(&mut self, x: TyVar) { self.0.set_error(x); } - fn set_unknown_flow(&mut self, x: TyVar, y: TyVar) {} + fn set_unknown_flow(&mut self, _x: TyVar, _y: TyVar) {} fn emit_error(&mut self, err: InferError) { self.0.errors.push(err); } fn make_check_eff(&mut self, x: (EffectVar, TyVar), y: (EffectVar, TyVar)) -> bool { - self.0.checks.push_back(Check::FlowEffect(x, y, self.1.clone())); + self.0 + .checks + .push_back(Check::FlowEffect(x, y, self.1.clone())); true } fn make_check_eff_empty(&mut self, x: (EffectVar, TyVar), other: TyVar) -> bool { - self.0.checks.push_back(Check::EffectEmpty(x, other, self.1.clone())); + self.0 + .checks + .push_back(Check::EffectEmpty(x, other, self.1.clone())); true } } @@ -231,9 +290,9 @@ impl<'a> Infer<'a> { // gen_scope: Some((_, true)) means that generic bounds are implied (almost always what you want) // gen_scope: Some((_, false)) means that generic bounds are not implied (used when inferring the bounds themselves) pub fn new(ctx: &'a mut Context, gen_scope: Option) -> Self { - let mut this = Self { + Self { ctx, - gen_scope: gen_scope, + gen_scope, vars: Vec::new(), class_vars: Vec::new(), effect_vars: Vec::new(), @@ -246,9 +305,7 @@ impl<'a> Infer<'a> { // self_obligations: Vec::new(), implied_members: Vec::new(), debug: false, - }; - - this + } } pub fn with_debug(mut self, debug: bool) -> Self { @@ -266,23 +323,34 @@ impl<'a> Infer<'a> { .clone() { let member_ty = self.instantiate_local(*member.member, member.member.span()); - let gen_tys = member.gen_tys + let gen_tys = member + .gen_tys .iter() .map(|ty| self.instantiate_local(*ty, member.member.span())) .collect(); - let gen_effs = member.gen_effs + let gen_effs = member + .gen_effs .iter() - .map(|eff| match eff.map(|eff| self.instantiate_local_eff(eff, member.member.span())) { - Some(Ok(Some(eff))) => eff, - _ => self.insert_effect(member.member.span(), EffectInfo::free()), + .map(|eff| { + match eff.map(|eff| self.instantiate_local_eff(eff, member.member.span())) { + Some(Ok(Some(eff))) => eff, + _ => self.insert_effect(member.member.span(), EffectInfo::free()), + } }) .collect(); let items = match &member.items { ImpliedItems::Real(member) => ImpliedItems::Real(*member), - ImpliedItems::Eq(assoc) => ImpliedItems::Eq(assoc - .iter() - .map(|(name, assoc)| (name.clone(), self.instantiate_local(*assoc, member.member.span()))) - .collect()), + ImpliedItems::Eq(assoc) => ImpliedItems::Eq( + assoc + .iter() + .map(|(name, assoc)| { + ( + name.clone(), + self.instantiate_local(*assoc, member.member.span()), + ) + }) + .collect(), + ), }; self.add_implied_member(InferImpliedMember { member: SrcNode::new(member_ty, member.member.span()), @@ -312,13 +380,21 @@ impl<'a> Infer<'a> { ty } - pub fn self_type(&self) -> Option { self.self_type } + pub fn self_type(&self) -> Option { + self.self_type + } - fn add_implied_member_inner(&mut self, searched: &mut HashSet, member: InferImpliedMember) { + fn add_implied_member_inner( + &mut self, + searched: &mut HashSet, + member: InferImpliedMember, + ) { searched.insert(*member.class); // Recursively search for member implied by the class let gen_scope_id = self.ctx.classes.get(*member.class).gen_scope; - for new_member in self.ctx.tys + for new_member in self + .ctx + .tys .get_gen_scope(gen_scope_id) .implied_members .as_ref() @@ -329,58 +405,75 @@ impl<'a> Infer<'a> { *new_member.member, new_member.member.span(), &mut |idx, _, _| member.gen_tys.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), Some(*member.member), invariant(), ); - let member_gen_tys = new_member.gen_tys - .iter() - .map(|ty| self.instantiate( - *ty, - new_member.member.span(), - &mut |idx, _, _| member.gen_tys.get(idx).copied(), - &mut |idx, _| todo!(), - Some(*member.member), - invariant(), - )) - .collect(); - let member_gen_effs = new_member.gen_effs + let member_gen_tys = new_member + .gen_tys .iter() - .map(|eff| match eff.map(|eff| self.instantiate_eff( - eff, + .map(|ty| { + self.instantiate( + *ty, new_member.member.span(), &mut |idx, _, _| member.gen_tys.get(idx).copied(), - &mut |idx, _| member.gen_effs.get(idx).copied(), + &mut |_idx, _| todo!(), Some(*member.member), invariant(), - )) - { - Some(Ok(Some(eff))) => eff, - _ => self.insert_effect(new_member.member.span(), EffectInfo::free()), + ) + }) + .collect(); + let member_gen_effs = new_member + .gen_effs + .iter() + .map(|eff| { + match eff.map(|eff| { + self.instantiate_eff( + eff, + new_member.member.span(), + &mut |idx, _, _| member.gen_tys.get(idx).copied(), + &mut |idx, _| member.gen_effs.get(idx).copied(), + Some(*member.member), + invariant(), + ) + }) { + Some(Ok(Some(eff))) => eff, + _ => self.insert_effect(new_member.member.span(), EffectInfo::free()), + } }) .collect(); let items = match &new_member.items { ImpliedItems::Real(member) => ImpliedItems::Real(*member), - ImpliedItems::Eq(assoc) => ImpliedItems::Eq(assoc - .iter() - .map(|(name, assoc)| (name.clone(), self.instantiate( - *assoc, - name.span(), - &mut |idx, _, _| member.gen_tys.get(idx).copied(), - &mut |idx, _| member.gen_effs.get(idx).copied(), - Some(*member.member), - invariant(), - ))) - .collect()), + ImpliedItems::Eq(assoc) => ImpliedItems::Eq( + assoc + .iter() + .map(|(name, assoc)| { + ( + name.clone(), + self.instantiate( + *assoc, + name.span(), + &mut |idx, _, _| member.gen_tys.get(idx).copied(), + &mut |idx, _| member.gen_effs.get(idx).copied(), + Some(*member.member), + invariant(), + ), + ) + }) + .collect(), + ), }; - self.add_implied_member_inner(searched, InferImpliedMember { - member: SrcNode::new(member_ty, member.member.span()), - class: new_member.class.clone(), - gen_tys: member_gen_tys, - gen_effs: member_gen_effs, - items, - }); + self.add_implied_member_inner( + searched, + InferImpliedMember { + member: SrcNode::new(member_ty, member.member.span()), + class: new_member.class.clone(), + gen_tys: member_gen_tys, + gen_effs: member_gen_effs, + items, + }, + ); } self.implied_members.push(member); @@ -395,16 +488,19 @@ impl<'a> Infer<'a> { self.implied_members.push(member); } - pub fn ctx(&self) -> &Context { self.ctx } - pub fn ctx_mut(&mut self) -> &mut Context { self.ctx } + pub fn ctx(&self) -> &Context { + self.ctx + } + pub fn ctx_mut(&mut self) -> &mut Context { + self.ctx + } pub fn gen_scope(&self) -> Option { self.gen_scope } fn iter(&self) -> impl Iterator + '_ { - (0..self.vars.len()) - .map(|i| (TyVar(i), self.vars[i].1.clone())) + (0..self.vars.len()).map(|i| (TyVar(i), self.vars[i].1.clone())) } fn follow(&self, ty: TyVar) -> TyVar { @@ -420,7 +516,7 @@ impl<'a> Infer<'a> { _ => { self.vars[ty.0].1 = info; ty - }, + } } } @@ -436,13 +532,13 @@ impl<'a> Infer<'a> { if self.vars[ty.0].2.is_ok() { self.vars[ty.0].2 = Err(()); match self.vars[ty.0].1.clone() { - TyInfo::Ref(x) => return self.set_error(x), + TyInfo::Ref(x) => self.set_error(x), TyInfo::Error(_) | TyInfo::Unknown(_) | TyInfo::Prim(_) | TyInfo::Gen(..) | TyInfo::Opaque(_, _) - | TyInfo::SelfType => {}, + | TyInfo::SelfType => {} TyInfo::List(item) => self.set_error(item), TyInfo::Record(fields, _) => fields .into_iter() @@ -450,16 +546,14 @@ impl<'a> Infer<'a> { TyInfo::Func(i, o) => { self.set_error(i); self.set_error(o); - }, - TyInfo::Data(_, args) => args - .into_iter() - .for_each(|arg| self.set_error(arg)), - TyInfo::Assoc(_, _, assoc) => {}, // Type is projected, so error does not propagate backwards + } + TyInfo::Data(_, args) => args.into_iter().for_each(|arg| self.set_error(arg)), + TyInfo::Assoc(_, _, _assoc) => {} // Type is projected, so error does not propagate backwards TyInfo::Effect(_eff, out, opaque) => { // TODO: Set error for eff self.set_error(out); self.set_error(opaque); - }, + } } } } @@ -467,21 +561,22 @@ impl<'a> Infer<'a> { fn set_error_class(&mut self, class: ClassVar) { match self.follow_class(class) { ClassInfo::Ref(_) => unreachable!(), - ClassInfo::Unknown => {}, - ClassInfo::Known(_, gen_tys, gen_effs) => { + ClassInfo::Unknown => {} + ClassInfo::Known(_, gen_tys, _gen_effs) => { for ty in gen_tys { self.set_error(ty); } - }, + } } } fn is_error(&self, ty: TyVar) -> bool { - self.vars[ty.0].2.is_err() || match self.vars[ty.0].1.clone() { - TyInfo::Ref(x) => self.is_error(x), - TyInfo::Effect(_, out, _) => self.is_error(out), - _ => false, - } + self.vars[ty.0].2.is_err() + || match self.vars[ty.0].1.clone() { + TyInfo::Ref(x) => self.is_error(x), + TyInfo::Effect(_, out, _) => self.is_error(out), + _ => false, + } } fn is_unknown(&self, ty: TyVar) -> bool { @@ -497,9 +592,9 @@ impl<'a> Infer<'a> { match self.follow_class(class) { ClassInfo::Ref(_) => unreachable!(), ClassInfo::Unknown => false, - ClassInfo::Known(_, gen_tys, gen_effs) => gen_tys - .into_iter() - .any(|ty| self.is_error(ty)), + ClassInfo::Known(_, gen_tys, _gen_effs) => { + gen_tys.into_iter().any(|ty| self.is_error(ty)) + } } } @@ -521,17 +616,24 @@ impl<'a> Infer<'a> { #[track_caller] pub fn insert(&mut self, span: Span, info: TyInfo) -> TyVar { let id = TyVar(self.vars.len()); - let err = if matches!(&info, TyInfo::Error(_)) { Err(()) } else { Ok(()) }; - self.vars.push((span, info, err, *std::panic::Location::caller())); + let err = if matches!(&info, TyInfo::Error(_)) { + Err(()) + } else { + Ok(()) + }; + self.vars + .push((span, info, err, *std::panic::Location::caller())); id } - fn instantiate_local_helpers(&mut self) -> ( + fn instantiate_local_helpers( + &mut self, + ) -> ( impl Fn(usize, GenScopeId, &mut Infer<'a>) -> Option, impl Fn(usize, &mut Infer<'a>) -> Option, ) { - let gens = self.gen_scope - .map(|gen_scope| ( + let gens = self.gen_scope.map(|gen_scope| { + ( (0..self.ctx.tys.get_gen_scope(gen_scope).len()) .map(|idx| { let span = self.ctx.tys.get_gen_scope(gen_scope).get(idx).name.span(); @@ -540,26 +642,57 @@ impl<'a> Infer<'a> { .collect::>(), (0..self.ctx.tys.get_gen_scope(gen_scope).len_eff()) .map(|idx| { - let span = self.ctx.tys.get_gen_scope(gen_scope).get_eff(idx).name.span(); - let eff_inst = self.insert_effect_inst(span, EffectInstInfo::Gen(idx, gen_scope)); + let span = self + .ctx + .tys + .get_gen_scope(gen_scope) + .get_eff(idx) + .name + .span(); + let eff_inst = + self.insert_effect_inst(span, EffectInstInfo::Gen(idx, gen_scope)); self.insert_effect(span, EffectInfo::Closed(vec![eff_inst], None)) }) .collect::>(), - )); + ) + }); ( - { let gens = gens.clone(); move |idx, gen_scope, ctx| gens.as_ref().expect("No gen scope").0.get(idx).copied() }, - move |idx, ctx| gens.as_ref().expect("No gen scope").1.get(idx).copied(), + { + let gens = gens.clone(); + move |idx, _gen_scope, _ctx| { + gens.as_ref().expect("No gen scope").0.get(idx).copied() + } + }, + move |idx, _ctx| gens.as_ref().expect("No gen scope").1.get(idx).copied(), ) } pub fn instantiate_local(&mut self, ty: TyId, span: Span) -> TyVar { let (mut gen_ty, mut gen_eff) = self.instantiate_local_helpers(); - self.instantiate(ty, span, &mut gen_ty, &mut gen_eff, self.self_type, invariant()) + self.instantiate( + ty, + span, + &mut gen_ty, + &mut gen_eff, + self.self_type, + invariant(), + ) } - pub fn instantiate_local_eff(&mut self, eff: EffectId, span: Span) -> Result, ()> { + pub fn instantiate_local_eff( + &mut self, + eff: EffectId, + span: Span, + ) -> Result, ()> { let (mut gen_ty, mut gen_eff) = self.instantiate_local_helpers(); - self.instantiate_eff(eff, span, &mut gen_ty, &mut gen_eff, self.self_type, invariant()) + self.instantiate_eff( + eff, + span, + &mut gen_ty, + &mut gen_eff, + self.self_type, + invariant(), + ) } // Ok(Some(eff)) => lowered effect @@ -605,8 +738,10 @@ impl<'a> Infer<'a> { Some(self.insert_effect_inst(span, inst)) }) .collect(); - Ok(Some(self.insert_effect(span, EffectInfo::Closed(effs, opener)))) - }, + Ok(Some( + self.insert_effect(span, EffectInfo::Closed(effs, opener)), + )) + } } } @@ -623,36 +758,53 @@ impl<'a> Infer<'a> { let info = match self.ctx.tys.get(ty) { Ty::Error(reason) => TyInfo::Error(reason), Ty::Prim(prim) => TyInfo::Prim(prim), - Ty::List(item) => TyInfo::List(self.instantiate(item, span, gen_ty, gen_eff, self_ty, vari)), - Ty::Record(fields, is_tuple) => TyInfo::Record(fields - .into_iter() - .map(|(name, field)| (name, self.instantiate(field, span, gen_ty, gen_eff, self_ty, vari))) - .collect(), is_tuple), + Ty::List(item) => { + TyInfo::List(self.instantiate(item, span, gen_ty, gen_eff, self_ty, vari)) + } + Ty::Record(fields, is_tuple) => TyInfo::Record( + fields + .into_iter() + .map(|(name, field)| { + ( + name, + self.instantiate(field, span, gen_ty, gen_eff, self_ty, vari), + ) + }) + .collect(), + is_tuple, + ), Ty::Func(i, o) => TyInfo::Func( self.instantiate(i, span, gen_ty, gen_eff, self_ty, vari.flip()), self.instantiate(o, span, gen_ty, gen_eff, self_ty, vari), ), - Ty::Data(data, params) => TyInfo::Data(data, params - .into_iter() - // TODO: Derive variance from definition instead of assuming invariance - .map(|param| self.instantiate(param, span, gen_ty, gen_eff, self_ty, invariant())) - .collect()), - // TODO: Check scope is valid for nested scopes + Ty::Data(data, params) => TyInfo::Data( + data, + params + .into_iter() + // TODO: Derive variance from definition instead of assuming invariance + .map(|param| { + self.instantiate(param, span, gen_ty, gen_eff, self_ty, invariant()) + }) + .collect(), + ), + // TODO: Check scope is valid for nested scopes Ty::Gen(index, scope) => match gen_ty(index, scope, self) { Some(ty) => TyInfo::Ref(ty), None => { println!("Generic type length mismatch! Tried to get idx = {}. Implies that the caller isn't checking that all generics are present.", index); - let span = span.unwrap_or_else(|| self.ctx.tys.get_span(ty)); + let _span = span.unwrap_or_else(|| self.ctx.tys.get_span(ty)); TyInfo::Error(ErrorReason::Invalid) - }, - }, - Ty::SelfType => if let Some(self_ty) = self_ty { - TyInfo::Ref(self_ty) - } else { - let span = span.unwrap_or_else(|| self.ctx.tys.get_span(ty)); - self.ctx.emit(Error::SelfNotValidHere(span)); - TyInfo::Error(ErrorReason::Invalid) + } }, + Ty::SelfType => { + if let Some(self_ty) = self_ty { + TyInfo::Ref(self_ty) + } else { + let span = span.unwrap_or_else(|| self.ctx.tys.get_span(ty)); + self.ctx.emit(Error::SelfNotValidHere(span)); + TyInfo::Error(ErrorReason::Invalid) + } + } Ty::Assoc(inner, (class_id, gen_tys, gen_effs), assoc) => { let span = span.unwrap_or_else(|| self.ctx.tys.get_span(ty)); let inner = self.instantiate(inner, span, gen_ty, gen_eff, self_ty, vari); @@ -662,21 +814,41 @@ impl<'a> Infer<'a> { .collect(); let gen_effs = gen_effs .iter() - .map(|eff| match eff.map(|eff| self.instantiate_eff(eff, span, gen_ty, gen_eff, self_ty, invariant())) { - Some(Ok(Some(eff))) => eff, - _ => self.insert_effect(span, EffectInfo::free()), + .map(|eff| { + match eff.map(|eff| { + self.instantiate_eff(eff, span, gen_ty, gen_eff, self_ty, invariant()) + }) { + Some(Ok(Some(eff))) => eff, + _ => self.insert_effect(span, EffectInfo::free()), + } }) .collect(); let assoc_ty = self.unknown(span); - self.make_impl(inner, (class_id, gen_tys, gen_effs), span, vec![(assoc, assoc_ty)], span); + self.make_impl( + inner, + (class_id, gen_tys, gen_effs), + span, + vec![(assoc, assoc_ty)], + span, + ); TyInfo::Ref(assoc_ty) - }, - Ty::Effect(eff, out) => match self.instantiate_eff(eff, span.unwrap_or_else(|| self.ctx.tys.get_span(ty)), gen_ty, gen_eff, self_ty, vari) { + } + Ty::Effect(eff, out) => match self.instantiate_eff( + eff, + span.unwrap_or_else(|| self.ctx.tys.get_span(ty)), + gen_ty, + gen_eff, + self_ty, + vari, + ) { Ok(Some(eff)) => { let out = self.instantiate(out, span, gen_ty, gen_eff, self_ty, vari); - let opaque = self.opaque(span.unwrap_or_else(|| self.ctx.tys.get_span(ty)), !vari.is_out()); + let opaque = self.opaque( + span.unwrap_or_else(|| self.ctx.tys.get_span(ty)), + !vari.is_out(), + ); TyInfo::Effect(eff, out, opaque) - }, + } Ok(None) => return self.instantiate(out, span, gen_ty, gen_eff, self_ty, vari), Err(()) => TyInfo::Error(ErrorReason::Invalid), }, @@ -696,11 +868,13 @@ impl<'a> Infer<'a> { } pub fn make_access(&mut self, record: TyVar, field_name: SrcNode, field: TyVar) { - self.constraints.push_back(Constraint::Access(record, field_name, field)); + self.constraints + .push_back(Constraint::Access(record, field_name, field)); } pub fn make_update(&mut self, record: TyVar, field_name: SrcNode, field: TyVar) { - self.constraints.push_back(Constraint::Update(record, field_name, field)); + self.constraints + .push_back(Constraint::Update(record, field_name, field)); } // `unchecked_assoc` allows unification of type variables with an instance's associated type @@ -714,11 +888,23 @@ impl<'a> Infer<'a> { use_span: Span, ) { let class = ClassVar(self.class_vars.len()); - self.class_vars.push((use_span, ClassInfo::Known(class_id, gen_tys, gen_effs))); - self.constraints.push_back(Constraint::Impl(ty, class, obl_span, unchecked_assoc, use_span)); - } - - fn instantiate_class(&mut self, class_id: ClassId, inst_span: Span, self_ty: Option) -> (Vec, Vec) { + self.class_vars + .push((use_span, ClassInfo::Known(class_id, gen_tys, gen_effs))); + self.constraints.push_back(Constraint::Impl( + ty, + class, + obl_span, + unchecked_assoc, + use_span, + )); + } + + fn instantiate_class( + &mut self, + class_id: ClassId, + inst_span: Span, + self_ty: Option, + ) -> (Vec, Vec) { let gen_scope_id = self.ctx.classes.class_gen_scope(class_id); let gen_scope = self.ctx.tys.get_gen_scope(gen_scope_id); let gen_tys = (0..gen_scope.len()) @@ -733,7 +919,7 @@ impl<'a> Infer<'a> { .collect::>(); let gen_effs = gen_effs .into_iter() - .map(|origin| self.insert_effect(inst_span, EffectInfo::free())) + .map(|_origin| self.insert_effect(inst_span, EffectInfo::free())) .collect::>(); // TODO: Move this function? @@ -745,7 +931,8 @@ impl<'a> Infer<'a> { inst_span, self.ctx.classes.get(class_id).name.span(), self_ty, - ).expect("Wrong number of generic params"); + ) + .expect("Wrong number of generic params"); (gen_tys, gen_effs) } @@ -765,13 +952,23 @@ impl<'a> Infer<'a> { span: Span, ) -> ClassVar { let class = self.insert_class(span, ClassInfo::Known(class_id, gen_tys, gen_effs)); - self.constraints.push_back(Constraint::ClassField(ty, class, field_name, field_ty, span)); + self.constraints.push_back(Constraint::ClassField( + ty, class, field_name, field_ty, span, + )); class } - pub fn make_class_field(&mut self, ty: TyVar, field_name: SrcNode, field_ty: TyVar, span: Span) -> ClassVar { + pub fn make_class_field( + &mut self, + ty: TyVar, + field_name: SrcNode, + field_ty: TyVar, + span: Span, + ) -> ClassVar { let class = self.class_var_unknown(span); - self.constraints.push_back(Constraint::ClassField(ty, class, field_name, field_ty, span)); + self.constraints.push_back(Constraint::ClassField( + ty, class, field_name, field_ty, span, + )); class } @@ -779,8 +976,17 @@ impl<'a> Infer<'a> { self.insert_class(span, ClassInfo::Unknown) } - pub fn make_class_assoc(&mut self, ty: TyVar, assoc_name: SrcNode, class: ClassVar, assoc_ty: TyVar, span: Span) { - self.constraints.push_back(Constraint::ClassAssoc(ty, class, assoc_name, assoc_ty, span)); + pub fn make_class_assoc( + &mut self, + ty: TyVar, + assoc_name: SrcNode, + class: ClassVar, + assoc_ty: TyVar, + span: Span, + ) { + self.constraints.push_back(Constraint::ClassAssoc( + ty, class, assoc_name, assoc_ty, span, + )); } fn follow_class(&self, class: ClassVar) -> ClassInfo { @@ -794,11 +1000,6 @@ impl<'a> Infer<'a> { self.effect_vars[eff.0].0 } - fn iter_effects(&self) -> impl Iterator + '_ { - (0..self.effect_vars.len()) - .map(|i| (EffectVar(i), self.effect_vars[i].1.clone())) - } - fn info_effect(&self, eff: EffectVar) -> EffectInfo { self.effect_vars[eff.0].1.clone() } @@ -838,12 +1039,29 @@ impl<'a> Infer<'a> { id } - pub fn make_effect_send_recv(&mut self, eff: EffectInstVar, send: TyVar, recv: TyVar, span: Span) { - self.constraints.push_back(Constraint::EffectSendRecv(eff, send, recv, span)); + pub fn make_effect_send_recv( + &mut self, + eff: EffectInstVar, + send: TyVar, + recv: TyVar, + span: Span, + ) { + self.constraints + .push_back(Constraint::EffectSendRecv(eff, send, recv, span)); } - pub fn make_effect_propagate(&mut self, obj: TyVar, basin_eff: EffectVar, out: TyVar, obj_span: Span, op_span: Span, out_span: Span) { - self.constraints.push_back(Constraint::EffectPropagate(obj, basin_eff, out, obj_span, op_span, out_span)); + pub fn make_effect_propagate( + &mut self, + obj: TyVar, + basin_eff: EffectVar, + out: TyVar, + obj_span: Span, + op_span: Span, + out_span: Span, + ) { + self.constraints.push_back(Constraint::EffectPropagate( + obj, basin_eff, out, obj_span, op_span, out_span, + )); } pub fn emit(&mut self, err: InferError) { @@ -853,20 +1071,8 @@ impl<'a> Infer<'a> { fn occurs_in_eff_inner(&self, x: TyVar, y: EffectVar, seen: &mut Vec) -> bool { match self.follow_effect(y) { EffectInfo::Ref(_) => unreachable!(), - EffectInfo::Closed(effs, opener) => effs - .iter() - .any(|eff| match self.follow_effect_inst(*eff) { - EffectInstInfo::Unknown => false, - EffectInstInfo::Error => false, - EffectInstInfo::Ref(_) => unreachable!(), - EffectInstInfo::Gen(_, _) => false, - EffectInstInfo::Known(_, params) => params - .into_iter() - .any(|y| x == y || self.occurs_in_inner(x, y, seen)), - }) || opener.map_or(false, |opener| self.occurs_in_eff_inner(x, opener, seen)), - EffectInfo::Open(effs) => effs - .iter() - .any(|eff| match self.follow_effect_inst(*eff) { + EffectInfo::Closed(effs, opener) => { + effs.iter().any(|eff| match self.follow_effect_inst(*eff) { EffectInstInfo::Unknown => false, EffectInstInfo::Error => false, EffectInstInfo::Ref(_) => unreachable!(), @@ -874,7 +1080,17 @@ impl<'a> Infer<'a> { EffectInstInfo::Known(_, params) => params .into_iter() .any(|y| x == y || self.occurs_in_inner(x, y, seen)), - }), + }) || opener.map_or(false, |opener| self.occurs_in_eff_inner(x, opener, seen)) + } + EffectInfo::Open(effs) => effs.iter().any(|eff| match self.follow_effect_inst(*eff) { + EffectInstInfo::Unknown => false, + EffectInstInfo::Error => false, + EffectInstInfo::Ref(_) => unreachable!(), + EffectInstInfo::Gen(_, _) => false, + EffectInstInfo::Known(_, params) => params + .into_iter() + .any(|y| x == y || self.occurs_in_inner(x, y, seen)), + }), } } @@ -893,26 +1109,38 @@ impl<'a> Infer<'a> { | TyInfo::Gen(_, _, _) => false, TyInfo::Ref(y) => x == y || self.occurs_in_inner(x, y, seen), TyInfo::List(item) => x == item || self.occurs_in_inner(x, item, seen), - TyInfo::Func(i, o) => x == i || x == o || self.occurs_in_inner(x, i, seen) || self.occurs_in_inner(x, o, seen), + TyInfo::Func(i, o) => { + x == i + || x == o + || self.occurs_in_inner(x, i, seen) + || self.occurs_in_inner(x, o, seen) + } TyInfo::Record(ys, _) => ys .into_iter() .any(|(_, y)| x == y || self.occurs_in_inner(x, y, seen)), TyInfo::Data(_, ys) => ys .into_iter() .any(|y| x == y || self.occurs_in_inner(x, y, seen)), - TyInfo::Assoc(inner, class, _) => x == inner - || self.occurs_in_inner(x, inner, seen) - || match self.follow_class(class) { - ClassInfo::Ref(_) => unreachable!(), - ClassInfo::Unknown => false, - ClassInfo::Known(_, gen_tys, gen_effs) => gen_tys - .into_iter() - .any(|y| x == y || self.occurs_in_inner(x, y, seen)) || gen_effs - .into_iter() - .any(|y| self.occurs_in_eff_inner(x, y, seen)), - }, + TyInfo::Assoc(inner, class, _) => { + x == inner + || self.occurs_in_inner(x, inner, seen) + || match self.follow_class(class) { + ClassInfo::Ref(_) => unreachable!(), + ClassInfo::Unknown => false, + ClassInfo::Known(_, gen_tys, gen_effs) => { + gen_tys + .into_iter() + .any(|y| x == y || self.occurs_in_inner(x, y, seen)) + || gen_effs + .into_iter() + .any(|y| self.occurs_in_eff_inner(x, y, seen)) + } + } + } // Opaque type is not checked, it's always opaque... hopefully - TyInfo::Effect(eff, out, _opaque) => self.occurs_in_inner(x, out, seen) || self.occurs_in_eff_inner(x, eff, seen), + TyInfo::Effect(eff, out, _opaque) => { + self.occurs_in_inner(x, out, seen) || self.occurs_in_eff_inner(x, eff, seen) + } }; seen.pop(); @@ -929,14 +1157,14 @@ impl<'a> Infer<'a> { fn collect_eff_insts(&self, var: EffectVar) -> Vec { match self.follow_effect(var) { EffectInfo::Ref(_) => unreachable!(), - EffectInfo::Open(effs) => effs.clone(), + EffectInfo::Open(effs) => effs, EffectInfo::Closed(effs, opener) => { - let mut effs = effs.clone(); + let mut effs = effs; if let Some(opener) = opener { effs.append(&mut self.collect_eff_insts(opener)) } effs - }, + } } } @@ -948,22 +1176,31 @@ impl<'a> Infer<'a> { self.set_error(a); self.set_error(b); // TODO: Don't put this here, it's a bit silly - if let (TyInfo::Effect(_, _, _), TyInfo::Effect(_, _, _)) = (self.info(a), self.info(b)) { + if let (TyInfo::Effect(_, _, _), TyInfo::Effect(_, _, _)) = + (self.info(a), self.info(b)) + { eq_info.reason = Some("Effect objects have unique types and cannot be substituted for one-another".to_string()); } - self.errors.push(InferError::CannotCoerce(x, y, Some((a, b)), eq_info)); + self.errors + .push(InferError::CannotCoerce(x, y, Some((a, b)), eq_info)); } } } // Flow the effect `x` into the effect `y` - pub fn make_flow_effect(&mut self, x: (EffectVar, TyVar), y: (EffectVar, TyVar), info: impl Into) { - let mut eq_info = info.into(); + pub fn make_flow_effect( + &mut self, + x: (EffectVar, TyVar), + y: (EffectVar, TyVar), + info: impl Into, + ) { + let eq_info = info.into(); if let Err((a, b)) = Self::flow_effect(&mut MakeFlow(self, &eq_info), x, y) { if !self.is_error(a) && !self.is_error(b) { self.set_error(a); self.set_error(b); - self.errors.push(InferError::CannotCoerce(x.1, y.1, Some((a, b)), eq_info)); + self.errors + .push(InferError::CannotCoerce(x.1, y.1, Some((a, b)), eq_info)); } } } @@ -975,19 +1212,35 @@ impl<'a> Infer<'a> { let res = Self::flow_inner(&mut check, x, y); match check.1 { Some(true) => Some(res.is_ok()), - None => if !res.is_ok() { Some(false) } else { None }, - Some(false) => Some(false) + None => { + if res.is_err() { + Some(false) + } else { + None + } + } + Some(false) => Some(false), } } // Check to see whether the effect `x` may flow into the effect `y`. Returns Some(true) for correct flow, Some(false) // for an error, and None for a flow that may or may not be permitted - pub fn check_flow_eff(&self, (x, x_ty): (EffectVar, TyVar), (y, y_ty): (EffectVar, TyVar)) -> Option { + pub fn check_flow_eff( + &self, + (x, x_ty): (EffectVar, TyVar), + (y, y_ty): (EffectVar, TyVar), + ) -> Option { let mut check = CheckFlow(self, Some(true)); let res = Self::flow_effect(&mut check, (x, x_ty), (y, y_ty)); match check.1 { Some(true) => Some(res.is_ok()), - None => if !res.is_ok() { Some(false) } else { None }, + None => { + if res.is_err() { + Some(false) + } else { + None + } + } Some(false) => Some(false), } } @@ -997,11 +1250,13 @@ impl<'a> Infer<'a> { xs: impl IntoIterator, ys: impl IntoIterator, ) -> Result<(), (TyVar, TyVar)> { - xs - .into_iter() + xs.into_iter() .zip(ys.into_iter()) - .fold(None, |err, (x, y)| err.or(Infer::flow_inner(infer, x, y).err())) - .map(Err).unwrap_or(Ok(())) + .fold(None, |err, (x, y)| { + err.or(Infer::flow_inner(infer, x, y).err()) + }) + .map(Err) + .unwrap_or(Ok(())) } fn flow_many_effect<'b, I: FlowInfer<'b>>( @@ -1009,11 +1264,13 @@ impl<'a> Infer<'a> { (xs, x_ty): (impl IntoIterator, TyVar), (ys, y_ty): (impl IntoIterator, TyVar), ) -> Result<(), (TyVar, TyVar)> { - xs - .into_iter() + xs.into_iter() .zip(ys.into_iter()) - .fold(None, |err, (x, y)| err.or(Infer::flow_effect(infer, (x, x_ty), (y, y_ty)).err())) - .map(Err).unwrap_or(Ok(())) + .fold(None, |err, (x, y)| { + err.or(Infer::flow_effect(infer, (x, x_ty), (y, y_ty)).err()) + }) + .map(Err) + .unwrap_or(Ok(())) } fn flow_effect_inst<'b, I: FlowInfer<'b>>( @@ -1021,34 +1278,45 @@ impl<'a> Infer<'a> { (x, x_ty): (EffectInstVar, TyVar), (y, y_ty): (EffectInstVar, TyVar), ) -> Result<(), (TyVar, TyVar)> { - match (infer.as_ref().info_effect_inst(x), infer.as_ref().info_effect_inst(y)) { + match ( + infer.as_ref().info_effect_inst(x), + infer.as_ref().info_effect_inst(y), + ) { (EffectInstInfo::Ref(x), _) => Self::flow_effect_inst(infer, (x, x_ty), (y, y_ty)), (_, EffectInstInfo::Ref(y)) => Self::flow_effect_inst(infer, (x, x_ty), (y, y_ty)), (EffectInstInfo::Error, _) => Ok(()), (_, EffectInstInfo::Error) => Ok(()), - (EffectInstInfo::Unknown, _) => Ok(infer.set_effect_inst_info(x, EffectInstInfo::Ref(y))), - (_, EffectInstInfo::Unknown) => Ok(infer.set_effect_inst_info(y, EffectInstInfo::Ref(x))), - (EffectInstInfo::Known(x, x_args), EffectInstInfo::Known(y, y_args)) if x == y => x_args - .into_iter() - .zip(y_args) - .fold(None, |err, (x, y)| err.or(Infer::flow_inner(infer, x, y).err())) - .map(Err).unwrap_or(Ok(())), + (EffectInstInfo::Unknown, _) => { + infer.set_effect_inst_info(x, EffectInstInfo::Ref(y)); + Ok(()) + } + (_, EffectInstInfo::Unknown) => { + infer.set_effect_inst_info(y, EffectInstInfo::Ref(x)); + Ok(()) + } + (EffectInstInfo::Known(x, x_args), EffectInstInfo::Known(y, y_args)) if x == y => { + x_args + .into_iter() + .zip(y_args) + .fold(None, |err, (x, y)| { + err.or(Infer::flow_inner(infer, x, y).err()) + }) + .map(Err) + .unwrap_or(Ok(())) + } (EffectInstInfo::Gen(x, _), EffectInstInfo::Gen(y, _)) if x == y => Ok(()), - (x, y) => { - Err((x_ty, y_ty)) - }, + (_x, _y) => Err((x_ty, y_ty)), } } // TODO: Allow errors that mention effects instead of types - fn check_eff_empty( - &self, - (x, x_ty): (EffectVar, TyVar), - ) -> Option { + fn check_eff_empty(&self, (x, x_ty): (EffectVar, TyVar)) -> Option { match self.follow_effect(x) { - EffectInfo::Ref(x) => unreachable!(), + EffectInfo::Ref(_x) => unreachable!(), EffectInfo::Open(x_effs) | EffectInfo::Closed(x_effs, None) => Some(x_effs.is_empty()), - EffectInfo::Closed(x_effs, Some(opener)) => Some(x_effs.is_empty() && self.check_eff_empty((opener, x_ty))?), + EffectInfo::Closed(x_effs, Some(opener)) => { + Some(x_effs.is_empty() && self.check_eff_empty((opener, x_ty))?) + } } } @@ -1058,38 +1326,43 @@ impl<'a> Infer<'a> { (x, x_ty): (EffectVar, TyVar), (y, y_ty): (EffectVar, TyVar), ) -> Result<(), (TyVar, TyVar)> { - if x == y { return Ok(()) } + if x == y { + return Ok(()); + } match (infer.as_ref().info_effect(x), infer.as_ref().info_effect(y)) { (EffectInfo::Ref(x), _) => Self::flow_effect(infer, (x, x_ty), (y, y_ty)), (_, EffectInfo::Ref(y)) => Self::flow_effect(infer, (x, x_ty), (y, y_ty)), // Closed with opener into closed - (EffectInfo::Closed(x_effs, Some(x_opener)), EffectInfo::Closed(y_effs, None) | EffectInfo::Open(y_effs)) if x_effs.is_empty() => { - Self::flow_effect(infer, (x_opener, x_ty), (y, y_ty)) - }, + ( + EffectInfo::Closed(x_effs, Some(x_opener)), + EffectInfo::Closed(_y_effs, None) | EffectInfo::Open(_y_effs), + ) if x_effs.is_empty() => Self::flow_effect(infer, (x_opener, x_ty), (y, y_ty)), // Closed into closed with opener - (EffectInfo::Closed(x_effs, None) | EffectInfo::Open(x_effs), EffectInfo::Closed(y_effs, Some(y_opener))) if y_effs.is_empty() => { - Self::flow_effect(infer, (x, x_ty), (y_opener, y_ty)) - }, + ( + EffectInfo::Closed(_x_effs, None) | EffectInfo::Open(_x_effs), + EffectInfo::Closed(y_effs, Some(y_opener)), + ) if y_effs.is_empty() => Self::flow_effect(infer, (x, x_ty), (y_opener, y_ty)), // Closed with opener into closed with opener - (EffectInfo::Closed(x_effs, Some(x_opener)), EffectInfo::Closed(y_effs, Some(y_opener))) if x_effs.is_empty() && y_effs.is_empty() => { + ( + EffectInfo::Closed(x_effs, Some(x_opener)), + EffectInfo::Closed(y_effs, Some(y_opener)), + ) if x_effs.is_empty() && y_effs.is_empty() => { Self::flow_effect(infer, (x_opener, x_ty), (y_opener, y_ty)) - }, + } // Ensure closed into closed (EffectInfo::Closed(x_effs, None), EffectInfo::Closed(y_effs, None)) => { - if x_effs - .iter() - .all(|x| y_effs + if x_effs.iter().all(|x| { + y_effs .iter() - .any(|y| Self::flow_effect_inst(infer, (*x, x_ty), (*y, y_ty)) == Ok(()))) + .any(|y| Self::flow_effect_inst(infer, (*x, x_ty), (*y, y_ty)).is_ok()) + }) || infer.make_check_eff((x, x_ty), (y, y_ty)) { Ok(()) - } else if infer.make_check_eff((x, x_ty), (y, y_ty)) { - Ok(()) } else { Err((x_ty, y_ty)) } - }, + } // Grow open into one-another (EffectInfo::Open(mut x_effs), EffectInfo::Open(mut y_effs)) => { if infer.is_check() { @@ -1101,7 +1374,7 @@ impl<'a> Infer<'a> { infer.set_effect_info(x, EffectInfo::Ref(y)); Ok(()) } - }, + } // Grow closed into open (EffectInfo::Closed(mut x_effs, opener), EffectInfo::Open(mut y_effs)) => { y_effs.append(&mut x_effs); @@ -1110,25 +1383,23 @@ impl<'a> Infer<'a> { Self::flow_effect(infer, (opener, x_ty), (y, y_ty))?; } Ok(()) - }, + } // Defer check open into closed (EffectInfo::Open(mut x_effs), EffectInfo::Closed(mut y_effs, None)) => { if infer.is_check() { - if x_effs - .iter() - .all(|x| y_effs - .iter() - .any(|y| Self::flow_effect_inst(infer, (*x, x_ty), (*y, y_ty)) == Ok(()))) - { + if x_effs.iter().all(|x| { + y_effs.iter().any(|y| { + Self::flow_effect_inst(infer, (*x, x_ty), (*y, y_ty)) == Ok(()) + }) + }) { Ok(()) } else { Err((x_ty, y_ty)) } } else if y_effs.len() == 1 { - x_effs - .iter() - .map(|x| Self::flow_effect_inst(infer, (*x, x_ty), (y_effs[0], y_ty))) - .collect::>()?; + x_effs.iter().try_for_each(|x| { + Self::flow_effect_inst(infer, (*x, x_ty), (y_effs[0], y_ty)) + })?; infer.set_effect_info(x, EffectInfo::Ref(y)); Ok(()) } else if infer.make_check_eff((x, x_ty), (y, y_ty)) { @@ -1141,7 +1412,7 @@ impl<'a> Infer<'a> { } else { Err((x_ty, y_ty)) } - }, + } (x_info, y_info) => todo!("{:?} into {:?}", x_info, y_info), } } @@ -1152,61 +1423,90 @@ impl<'a> Infer<'a> { (x, x_ty): (ClassVar, TyVar), (y, y_ty): (ClassVar, TyVar), ) -> Result<(), (TyVar, TyVar)> { - match (infer.as_ref().follow_class(x), infer.as_ref().follow_class(y)) { - (ClassInfo::Unknown, _) => Ok(infer.set_class_info(x, ClassInfo::Ref(y))), - (_, ClassInfo::Unknown) => Ok(infer.set_class_info(y, ClassInfo::Ref(x))), - (ClassInfo::Known(class_id_x, xs, e_xs), ClassInfo::Known(class_id_y, ys, e_ys)) if class_id_x == class_id_y => { + match ( + infer.as_ref().follow_class(x), + infer.as_ref().follow_class(y), + ) { + (ClassInfo::Unknown, _) => { + infer.set_class_info(x, ClassInfo::Ref(y)); + Ok(()) + } + (_, ClassInfo::Unknown) => { + infer.set_class_info(y, ClassInfo::Ref(x)); + Ok(()) + } + (ClassInfo::Known(class_id_x, xs, e_xs), ClassInfo::Known(class_id_y, ys, e_ys)) + if class_id_x == class_id_y => + { // Class generics are always invariant let co_error = Self::flow_many(infer, xs.iter().copied(), ys.iter().copied()).err(); let contra_error = Self::flow_many(infer, ys, xs).err().map(|(a, b)| (b, a)); // Effects are also invariant - let e_co_error = Self::flow_many_effect(infer, (e_xs.iter().copied(), x_ty), (e_ys.iter().copied(), y_ty)).err(); - let e_contra_error = Self::flow_many_effect(infer, (e_ys, y_ty), (e_xs, x_ty)).err(); + let e_co_error = Self::flow_many_effect( + infer, + (e_xs.iter().copied(), x_ty), + (e_ys.iter().copied(), y_ty), + ) + .err(); + let e_contra_error = + Self::flow_many_effect(infer, (e_ys, y_ty), (e_xs, x_ty)).err(); co_error .or(contra_error) .or(e_co_error) .or(e_contra_error) .map(Err) .unwrap_or(Ok(())) - }, + } (_, _) => Err((x_ty, y_ty)), } } - fn flow_inner>(infer: &mut I, x: TyVar, y: TyVar) -> Result<(), (TyVar, TyVar)> { - if x == y { return Ok(()) } // If the vars are equal, we have no need to check flow + fn flow_inner>( + infer: &mut I, + x: TyVar, + y: TyVar, + ) -> Result<(), (TyVar, TyVar)> { + if x == y { + return Ok(()); + } // If the vars are equal, we have no need to check flow match (infer.as_ref().info(x), infer.as_ref().info(y)) { // Follow references (TyInfo::Ref(x), _) => Self::flow_inner(infer, x, y), (_, TyInfo::Ref(y)) => Self::flow_inner(infer, x, y), // Unify unknown or erronoeus types - (TyInfo::Unknown(_), y_info) => if infer.as_ref().occurs_in(x, y) { + (TyInfo::Unknown(_), _y_info) => if infer.as_ref().occurs_in(x, y) { infer.emit_error(InferError::Recursive(y, infer.as_ref().follow(x))); infer.set_info(x, TyInfo::Error(ErrorReason::Recursive)); - Ok(infer.set_error(x)) + infer.set_error(x); + Ok(()) } else { infer.set_unknown_flow(x, y); - Ok(infer.set_info(x, TyInfo::Ref(y))) + infer.set_info(x, TyInfo::Ref(y)); + Ok(()) }, - (x_info, TyInfo::Unknown(_)) => if infer.as_ref().occurs_in(y, x) { + (_x_info, TyInfo::Unknown(_)) => if infer.as_ref().occurs_in(y, x) { infer.emit_error(InferError::Recursive(x, infer.as_ref().follow(y))); infer.set_info(y, TyInfo::Error(ErrorReason::Recursive)); - Ok(infer.set_error(y)) + infer.set_error(y); + Ok(()) } else { infer.set_unknown_flow(x, y); - Ok(infer.set_info(y, TyInfo::Ref(x))) + infer.set_info(y, TyInfo::Ref(x)); + Ok(()) }, // Unify errors (_, TyInfo::Error(_)) => { infer.set_error(x); - Ok(infer.set_info(x, TyInfo::Ref(y))) + infer.set_info(x, TyInfo::Ref(y)); + Ok(()) }, (TyInfo::Error(_), _) => { infer.set_error(y); - Ok(infer.set_info(y, TyInfo::Ref(x))) + infer.set_info(y, TyInfo::Ref(x)); + Ok(()) }, (TyInfo::Prim(x), TyInfo::Prim(y)) if x == y => Ok(()), @@ -1262,15 +1562,7 @@ impl<'a> Infer<'a> { o_err.map(Err).unwrap_or(Ok(())) }, // TODO: Don't ignore!!! But make `fix` work, somehow - (TyInfo::Opaque(x_id, _), TyInfo::Opaque(y_id, _)) /*if x_id == y_id*/ => Ok(()), - (TyInfo::Opaque(x_id, relaxed_x), TyInfo::Opaque(y_id, relaxed_y)) if relaxed_x || relaxed_y => { - if relaxed_y { - infer.set_info(y, TyInfo::Ref(x)); - } else { - infer.set_info(x, TyInfo::Ref(y)); - } - Ok(()) - }, + (TyInfo::Opaque(_x_id, _), TyInfo::Opaque(_y_id, _)) /*if x_id == y_id*/ => Ok(()), (_, _) => Err((x, y)), } } @@ -1284,40 +1576,48 @@ impl<'a> Infer<'a> { .iter() .map(|eff| match self.follow_effect_inst(*eff) { EffectInstInfo::Unknown => *eff, - EffectInstInfo::Error => self.insert_effect_inst(span, EffectInstInfo::Error), + EffectInstInfo::Error => { + self.insert_effect_inst(span, EffectInstInfo::Error) + } EffectInstInfo::Ref(_) => unreachable!(), EffectInstInfo::Gen(_, _) => *eff, EffectInstInfo::Known(eff, args) => { - let inst_info = EffectInstInfo::Known(eff, args - .iter() - .map(|arg| self.reinstantiate(span, *arg)) - .collect()); + let inst_info = EffectInstInfo::Known( + eff, + args.iter() + .map(|arg| self.reinstantiate(span, *arg)) + .collect(), + ); self.insert_effect_inst(span, inst_info) - }, + } }) .collect(); self.insert_effect(span, EffectInfo::Open(effs)) - }, + } EffectInfo::Closed(effs, opener) => { let effs = effs .iter() .map(|eff| match self.follow_effect_inst(*eff) { EffectInstInfo::Unknown => *eff, - EffectInstInfo::Error => self.insert_effect_inst(span, EffectInstInfo::Error), + EffectInstInfo::Error => { + self.insert_effect_inst(span, EffectInstInfo::Error) + } EffectInstInfo::Ref(_) => unreachable!(), EffectInstInfo::Gen(_, _) => *eff, EffectInstInfo::Known(eff, args) => { - let inst_info = EffectInstInfo::Known(eff, args - .iter() - .map(|arg| self.reinstantiate(span, *arg)) - .collect()); + let inst_info = EffectInstInfo::Known( + eff, + args.iter() + .map(|arg| self.reinstantiate(span, *arg)) + .collect(), + ); self.insert_effect_inst(span, inst_info) - }, + } }) .collect(); // let opener = opener.map(|opener| self.reinstantiate_eff(span, opener)); self.insert_effect(span, EffectInfo::Closed(effs, opener)) - }, + } } } @@ -1333,29 +1633,29 @@ impl<'a> Infer<'a> { TyInfo::List(item) => { let item = self.reinstantiate(span, item); self.insert(self.span(ty), TyInfo::List(item)) - }, + } TyInfo::Func(i, o) => { let i = self.reinstantiate(span, i); let o = self.reinstantiate(span, o); self.insert(self.span(ty), TyInfo::Func(i, o)) - }, + } // TODO: Reinstantiate type parameters with fresh type variables, but without creating inference problems // TODO: Is this even correct? - TyInfo::Gen(x, _, origin) => ty,//self.insert(span, TyInfo::Unknown(Some(origin))), + TyInfo::Gen(_x, _, _origin) => ty, //self.insert(span, TyInfo::Unknown(Some(origin))), TyInfo::Record(fields, is_tuple) => { let fields = fields .into_iter() .map(|(name, field)| (name, self.reinstantiate(span, field))) .collect(); self.insert(self.span(ty), TyInfo::Record(fields, is_tuple)) - }, + } TyInfo::Data(data, args) => { let args = args .into_iter() .map(|arg| self.reinstantiate(span, arg)) .collect(); self.insert(self.span(ty), TyInfo::Data(data, args)) - }, + } TyInfo::SelfType => todo!(), // ??? TyInfo::Assoc(inner, class, assoc) => { let class = match self.follow_class(class) { @@ -1370,22 +1670,31 @@ impl<'a> Infer<'a> { .into_iter() .map(|eff| self.reinstantiate_eff(span, eff)) .collect(); - self.insert_class(self.span(ty), ClassInfo::Known(class_id, gen_tys, gen_effs)) - }, + self.insert_class( + self.span(ty), + ClassInfo::Known(class_id, gen_tys, gen_effs), + ) + } }; let inner = self.reinstantiate(span, inner); self.insert(self.span(ty), TyInfo::Assoc(inner, class, assoc)) - }, + } TyInfo::Effect(eff, out, opaque) => { let eff = self.reinstantiate_eff(self.span(ty), eff); let out = self.reinstantiate(span, out); let opaque = self.reinstantiate(span, opaque); self.insert(self.span(ty), TyInfo::Effect(eff, out, opaque)) - }, + } } } - fn resolve_access(&mut self, record: TyVar, field_name: &SrcNode, field: TyVar, flow_out: bool) -> Option { + fn resolve_access( + &mut self, + record: TyVar, + field_name: &SrcNode, + field: TyVar, + flow_out: bool, + ) -> Option { // TODO: Allow chaining accesses match self.follow_info(record) { _ if self.is_error(record) => { @@ -1393,38 +1702,44 @@ impl<'a> Infer<'a> { // Trying to access a field on an error type counts as success because we don't want to emit more // errors than necessary. Some(true) - }, + } TyInfo::Unknown(_) => None, - TyInfo::Record(fields, _) => if let Some(field_ty) = fields.get(&field_name) { - self.make_flow(*field_ty, field, field_name.span()); - Some(true) - } else { - Some(false) - }, + TyInfo::Record(fields, _) => { + if let Some(field_ty) = fields.get(field_name) { + self.make_flow(*field_ty, field, field_name.span()); + Some(true) + } else { + Some(false) + } + } TyInfo::Effect(eff, out, _) => { let res = self.resolve_access(out, field_name, field, flow_out); // If projecting through the effect worked, make sure that the effect ends up being empty eventually if res == Some(true) { - self.checks.push_back(Check::EffectEmpty((eff, record), out, EqInfo::from(field_name.span()))); + self.checks.push_back(Check::EffectEmpty( + (eff, record), + out, + EqInfo::from(field_name.span()), + )); } res - }, + } // Field access through a data type TyInfo::Data(data, params) => { // TODO: Use `self.ctx.follow_field_access(...)` but work out how to instantiate type parameters // throughout the chain. let data = self.ctx.datas.get_data(data); // Field access on data only works for single-variant, record datatypes - if let (Some((_, ty)), true) = (data.cons.iter().next(), data.cons.len() == 1) { + if let (Some((_, ty)), true) = (data.cons.first(), data.cons.len() == 1) { if let Ty::Record(fields, _) = self.ctx.tys.get(*ty) { - if let Some(field_ty) = fields.get(&field_name) { + if let Some(field_ty) = fields.get(field_name) { let field_ty = self.instantiate( *field_ty, self.span(record), &mut |index, _, _| params.get(index).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), Some(record), invariant(), ); @@ -1443,117 +1758,183 @@ impl<'a> Infer<'a> { } else { Some(false) } - }, + } _ => Some(false), } } fn resolve(&mut self, c: Constraint) -> Option> { match c { - Constraint::Access(record, field_name, field) => self.resolve_access(record, &field_name, field, true) - .map(|success| if success { - Ok(()) - } else { - self.set_error(field); - Err(InferError::NoSuchField(record, self.span(record), field_name.clone())) + Constraint::Access(record, field_name, field) => self + .resolve_access(record, &field_name, field, true) + .map(|success| { + if success { + Ok(()) + } else { + self.set_error(field); + Err(InferError::NoSuchField( + record, + self.span(record), + field_name.clone(), + )) + } }), - Constraint::Update(record, field_name, field) => self.resolve_access(record, &field_name, field, false) - .map(|success| if success { - Ok(()) - } else { - self.set_error(field); - Err(InferError::NoSuchField(record, self.span(record), field_name.clone())) + Constraint::Update(record, field_name, field) => self + .resolve_access(record, &field_name, field, false) + .map(|success| { + if success { + Ok(()) + } else { + self.set_error(field); + Err(InferError::NoSuchField( + record, + self.span(record), + field_name.clone(), + )) + } }), Constraint::Impl(ty, class, obl_span, unchecked_assoc, use_span) => { if let ClassInfo::Known(class_id, gen_tys, gen_effs) = self.follow_class(class) { - self.resolve_obligation(&mut Vec::new(), ty, (class_id, gen_tys.clone(), gen_effs.clone()), unchecked_assoc.clone(), obl_span, use_span) - .map(|res| match res { - Ok(member) => { - for (assoc, assoc_ty) in unchecked_assoc { - match member { - Ok(ImpliedItems::Real(member_id)) => { - let member = self.ctx.classes.get_member(member_id); - let member_member = member.member; - let member_gen_tys = member.gen_tys.clone(); - let member_gen_effs = member.gen_effs.clone(); - - let mut ty_links = HashMap::new(); - let mut eff_links = HashMap::new(); - self.derive_links(member_member, ty, Some(ty), use_span, &mut ty_links, &mut eff_links); - for (member_gen_ty, gen_ty) in member_gen_tys.iter().zip(gen_tys.iter()) { - self.derive_links(*member_gen_ty, *gen_ty, Some(ty), use_span, &mut ty_links, &mut eff_links); - } - for (member_gen_eff, gen_eff) in member_gen_effs.iter().zip(gen_effs.iter()) { - if let Some(member_gen_eff) = *member_gen_eff { - self.derive_links_eff(member_gen_eff, *gen_eff, Some(ty), use_span, &mut ty_links, &mut eff_links); - } - } - - let member = self.ctx.classes.get_member(member_id); - if let Some(member_assoc_ty) = member.assoc_ty(*assoc) { - let assoc_ty_inst = self.instantiate( - member_assoc_ty, - obl_span, - &mut |idx, gen_scope, ctx| ty_links.get(&idx).copied(), - &mut |idx, ctx| eff_links.get(&idx).copied(), + self.resolve_obligation( + &mut Vec::new(), + ty, + (class_id, gen_tys.clone(), gen_effs.clone()), + unchecked_assoc.clone(), + obl_span, + use_span, + ) + .map(|res| match res { + Ok(member) => { + for (assoc, assoc_ty) in unchecked_assoc { + match member { + Ok(ImpliedItems::Real(member_id)) => { + let member = self.ctx.classes.get_member(member_id); + let member_member = member.member; + let member_gen_tys = member.gen_tys.clone(); + let member_gen_effs = member.gen_effs.clone(); + + let mut ty_links = HashMap::new(); + let mut eff_links = HashMap::new(); + self.derive_links( + member_member, + ty, + Some(ty), + use_span, + &mut ty_links, + &mut eff_links, + ); + for (member_gen_ty, gen_ty) in + member_gen_tys.iter().zip(gen_tys.iter()) + { + self.derive_links( + *member_gen_ty, + *gen_ty, + Some(ty), + use_span, + &mut ty_links, + &mut eff_links, + ); + } + for (member_gen_eff, gen_eff) in + member_gen_effs.iter().zip(gen_effs.iter()) + { + if let Some(member_gen_eff) = *member_gen_eff { + self.derive_links_eff( + member_gen_eff, + *gen_eff, Some(ty), - invariant(), + use_span, + &mut ty_links, + &mut eff_links, ); - // TODO: Check ordering for soundness - self.make_flow(assoc_ty_inst, assoc_ty, obl_span); - } - }, - Ok(ImpliedItems::Eq(ref assoc_set)) => { - if let Some((name, ty)) = assoc_set.iter().find(|(name, _)| **name == *assoc) { - self.make_flow(*ty, assoc_ty, name.span()); - } else { - let assoc_info = self.insert(obl_span, TyInfo::Assoc(ty, class, assoc.clone())); - // TODO: Check ordering for soundness - self.make_flow(assoc_info, assoc_ty, obl_span); } - }, - Err(()) => { - // Errors propagate through projected associated types - self.set_error(assoc_ty); - }, + } + + let member = self.ctx.classes.get_member(member_id); + if let Some(member_assoc_ty) = member.assoc_ty(*assoc) { + let assoc_ty_inst = self.instantiate( + member_assoc_ty, + obl_span, + &mut |idx, _gen_scope, _ctx| { + ty_links.get(&idx).copied() + }, + &mut |idx, _ctx| eff_links.get(&idx).copied(), + Some(ty), + invariant(), + ); + // TODO: Check ordering for soundness + self.make_flow(assoc_ty_inst, assoc_ty, obl_span); + } + } + Ok(ImpliedItems::Eq(ref assoc_set)) => { + if let Some((name, ty)) = + assoc_set.iter().find(|(name, _)| **name == *assoc) + { + self.make_flow(*ty, assoc_ty, name.span()); + } else { + let assoc_info = self.insert( + obl_span, + TyInfo::Assoc(ty, class, assoc.clone()), + ); + // TODO: Check ordering for soundness + self.make_flow(assoc_info, assoc_ty, obl_span); + } + } + Err(()) => { + // Errors propagate through projected associated types + self.set_error(assoc_ty); } } - Ok(()) - }, - Err(err) => { - // The obligation produced an error, so propagate the error to associated type variables - for (_, assoc_ty) in unchecked_assoc { - self.set_error(assoc_ty); - } - Err(err) - }, - }) + } + Ok(()) + } + Err(err) => { + // The obligation produced an error, so propagate the error to associated type variables + for (_, assoc_ty) in unchecked_assoc { + self.set_error(assoc_ty); + } + Err(err) + } + }) } else { None } - }, - Constraint::ClassField(ty, class, field, field_ty, span) => self.try_resolve_class_from_field(ty, class, field.clone(), field_ty, span), - Constraint::ClassAssoc(ty, class, assoc, assoc_ty, span) => self.try_resolve_class_from_assoc(ty, class, assoc.clone(), assoc_ty, span), - Constraint::EffectSendRecv(eff, send, recv, span) => match self.follow_effect_inst(eff) { + } + Constraint::ClassField(ty, class, field, field_ty, span) => { + self.try_resolve_class_from_field(ty, class, field, field_ty, span) + } + Constraint::ClassAssoc(ty, class, assoc, assoc_ty, span) => { + self.try_resolve_class_from_assoc(ty, class, assoc, assoc_ty, span) + } + Constraint::EffectSendRecv(eff, send, recv, span) => match self.follow_effect_inst(eff) + { EffectInstInfo::Unknown => None, EffectInstInfo::Error => Some(Ok(())), // Error, assume valid EffectInstInfo::Ref(_) => unreachable!(), - EffectInstInfo::Gen(_, _) => todo!("Cannot handle or suspend generic effect"),//TODO: Some(Err(InferError::CannotHandleSuspendGenericEffect(*eff, span))), + EffectInstInfo::Gen(_, _) => todo!("Cannot handle or suspend generic effect"), //TODO: Some(Err(InferError::CannotHandleSuspendGenericEffect(*eff, span))), EffectInstInfo::Known(decl, args) => { let send_ty = self.instantiate( - self.ctx.effects.get_decl(decl).send.expect("Send must be init"), + self.ctx + .effects + .get_decl(decl) + .send + .expect("Send must be init"), span, &mut |idx, _gen_scope, _ctx| args.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), None, invariant(), ); self.make_flow(send, send_ty, span); let recv_ty = self.instantiate( - self.ctx.effects.get_decl(decl).recv.expect("Recv must be init"), + self.ctx + .effects + .get_decl(decl) + .recv + .expect("Recv must be init"), span, &mut |idx, _gen_scope, _ctx| args.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), None, invariant(), ); @@ -1563,89 +1944,126 @@ impl<'a> Infer<'a> { self.make_flow(recv, recv_ty, self.span(recv)); self.make_flow(recv_ty, recv, self.span(recv)); Some(Ok(())) - }, + } }, - Constraint::EffectPropagate(obj, basin_eff, out_ty, obj_span, op_span, out_span) => match self.follow_info(obj) { - TyInfo::Effect(eff, out, _) => { - self.make_flow(out, out_ty, EqInfo::from(out_span)); - - // If we're propagating the effect, it can't be empty - // TODO: Make this actually work (right now, the effect grows backwards as well as forwards) - // One solution might be to replace `EffectInfo::Open/Closed` with something that allows specifying - // whether the effect can grow or shrink in input or output position, like - // `EffectInfo::Set(grow: bool, grow_rev: bool, Vec)`. `Open` then becomes - // `Set(true, true, ...)` and `Closed` becomes `Set(false, false, ...)`. - // self.checks.push_back(Check::EffectNonEmpty(obj, eff, span)); - - // Generating a whole new type variable for this is stupid, it should be possible to flow effects without tying them to a ty - let fake_opaque = self.opaque(op_span, true); - let fake_basin_ty = self.insert(self.effect_span(basin_eff), TyInfo::Effect(basin_eff, out_ty, fake_opaque)); - - self.make_flow_effect((eff, obj), (basin_eff, fake_basin_ty), EqInfo::from(op_span)); - Some(Ok(())) - }, - _ => None, + Constraint::EffectPropagate(obj, basin_eff, out_ty, _obj_span, op_span, out_span) => { + match self.follow_info(obj) { + TyInfo::Effect(eff, out, _) => { + self.make_flow(out, out_ty, EqInfo::from(out_span)); + + // If we're propagating the effect, it can't be empty + // TODO: Make this actually work (right now, the effect grows backwards as well as forwards) + // One solution might be to replace `EffectInfo::Open/Closed` with something that allows specifying + // whether the effect can grow or shrink in input or output position, like + // `EffectInfo::Set(grow: bool, grow_rev: bool, Vec)`. `Open` then becomes + // `Set(true, true, ...)` and `Closed` becomes `Set(false, false, ...)`. + // self.checks.push_back(Check::EffectNonEmpty(obj, eff, span)); + + // Generating a whole new type variable for this is stupid, it should be possible to flow effects without tying them to a ty + let fake_opaque = self.opaque(op_span, true); + let fake_basin_ty = self.insert( + self.effect_span(basin_eff), + TyInfo::Effect(basin_eff, out_ty, fake_opaque), + ); + + self.make_flow_effect( + (eff, obj), + (basin_eff, fake_basin_ty), + EqInfo::from(op_span), + ); + Some(Ok(())) + } + _ => None, + } } } } fn check(&mut self, c: Check) -> Result<(), InferError> { match c { - Check::FlowEffect((x, x_ty), (y, y_ty), eq_info) => self.check_flow_eff((x, x_ty), (y, y_ty)) - .and_then(|ok| if ok { - Some(()) - } else { - None - }) + Check::FlowEffect((x, x_ty), (y, y_ty), eq_info) => self + .check_flow_eff((x, x_ty), (y, y_ty)) + .and_then(|ok| if ok { Some(()) } else { None }) .ok_or_else(|| InferError::CannotCoerce(x_ty, y_ty, None, eq_info)), - Check::EffectEmpty((x, x_ty), other, eq_info) => self.check_eff_empty((x, x_ty)) - .and_then(|ok| if ok { - Some(()) - } else { - None - }) + Check::EffectEmpty((x, x_ty), other, eq_info) => self + .check_eff_empty((x, x_ty)) + .and_then(|ok| if ok { Some(()) } else { None }) .ok_or_else(|| InferError::CannotCoerce(x_ty, other, None, eq_info)), - Check::EffectNonEmpty(ty, eff, span) => if self.collect_eff_insts(eff).is_empty() { - Err(InferError::NotEffectful(ty, self.span(ty), span)) - } else { - Ok(()) - }, + Check::EffectNonEmpty(ty, eff, span) => { + if self.collect_eff_insts(eff).is_empty() { + Err(InferError::NotEffectful(ty, self.span(ty), span)) + } else { + Ok(()) + } + } } } - fn try_resolve_class_from_assoc(&mut self, ty: TyVar, class_var: ClassVar, assoc: SrcNode, assoc_ty: TyVar, span: Span) -> Option> { - let (class_id, gen_tys, gen_effs) = match self.select_member_from_item(ty, class_var, assoc.clone(), assoc_ty, span, true) { + fn try_resolve_class_from_assoc( + &mut self, + ty: TyVar, + class_var: ClassVar, + assoc: SrcNode, + assoc_ty: TyVar, + span: Span, + ) -> Option> { + let (class_id, gen_tys, gen_effs) = match self.select_member_from_item( + ty, + class_var, + assoc.clone(), + assoc_ty, + span, + true, + ) { Some(Ok(Some((class_id, gen_tys, gen_effs)))) => (class_id, gen_tys, gen_effs), Some(Ok(None)) => return None, Some(Err(err)) => return Some(Err(err)), None => return None, }; - self.class_vars[class_var.0].1 = ClassInfo::Known(class_id, gen_tys.clone(), gen_effs.clone()); + self.class_vars[class_var.0].1 = + ClassInfo::Known(class_id, gen_tys.clone(), gen_effs.clone()); // Require an implementation to exist - self.make_impl(ty, (class_id, gen_tys, gen_effs), span, vec![ - (assoc, assoc_ty), - ], span); + self.make_impl( + ty, + (class_id, gen_tys, gen_effs), + span, + vec![(assoc, assoc_ty)], + span, + ); Some(Ok(())) } - fn try_resolve_class_from_field(&mut self, ty: TyVar, class_var: ClassVar, field: SrcNode, field_ty: TyVar, span: Span) -> Option> { - let (class_id, gen_tys, gen_effs) = match self.select_member_from_item(ty, class_var, field.clone(), field_ty, span, false) { - Some(Ok(Some((class_id, gen_tys, gen_effs)))) => (class_id, gen_tys, gen_effs), - Some(Ok(None)) => return Some(Ok(())), - Some(Err(err)) => return Some(Err(err)), - None => return None, - }; + fn try_resolve_class_from_field( + &mut self, + ty: TyVar, + class_var: ClassVar, + field: SrcNode, + field_ty: TyVar, + span: Span, + ) -> Option> { + let (class_id, gen_tys, gen_effs) = + match self.select_member_from_item(ty, class_var, field.clone(), field_ty, span, false) + { + Some(Ok(Some((class_id, gen_tys, gen_effs)))) => (class_id, gen_tys, gen_effs), + Some(Ok(None)) => return Some(Ok(())), + Some(Err(err)) => return Some(Err(err)), + None => return None, + }; - self.class_vars[class_var.0].1 = ClassInfo::Known(class_id, gen_tys.clone(), gen_effs.clone()); + self.class_vars[class_var.0].1 = + ClassInfo::Known(class_id, gen_tys.clone(), gen_effs.clone()); - self.make_impl(ty, (class_id, gen_tys.clone(), gen_effs.clone()), span, Vec::new(), span); - let field_ty_id = **self.ctx.classes - .get(class_id) - .field(*field) - .unwrap(); + self.make_impl( + ty, + (class_id, gen_tys.clone(), gen_effs.clone()), + span, + Vec::new(), + span, + ); + let field_ty_id = **self.ctx.classes.get(class_id).field(*field).unwrap(); let inst_field_ty = self.instantiate( field_ty_id, span, @@ -1666,7 +2084,7 @@ impl<'a> Infer<'a> { class_var: ClassVar, item: SrcNode, item_ty: TyVar, - span: Span, + _span: Span, is_assoc: bool, ) -> Option, Vec)>, InferError>> { if let ClassInfo::Known(class_id, gen_tys, gen_effs) = self.follow_class(class_var) { @@ -1681,7 +2099,7 @@ impl<'a> Infer<'a> { // Can't fail let member = implied_candidates.into_iter().next().unwrap(); Some(Ok(Some((*member.class, member.gen_tys, member.gen_effs)))) - }, + } // Exactly one external candidate was found, so instantiate it // TODO: Should we even make use of external member information? It implies that adding new members is // a breaking change... Alternatively, we could have a DAG-based member 'visibility' system for @@ -1689,59 +2107,68 @@ impl<'a> Infer<'a> { (0, 1) => { // Can't fail let class_id = external_candidates.into_iter().next().unwrap(); - let (gen_tys, gen_effs) = self.instantiate_class(class_id, item.span(), Some(ty)); + let (gen_tys, gen_effs) = + self.instantiate_class(class_id, item.span(), Some(ty)); Some(Ok(Some((class_id, gen_tys, gen_effs)))) - }, + } // No implied or external candidates were found, so we can't resolve the member (0, 0) => { // No external candidates match either, so bail self.set_error(item_ty); Some(Err(InferError::NoSuchItem(ty, self.span(ty), item))) - }, + } (_, _) => { self.set_error(item_ty); let possible_classes = implied_candidates .into_iter() .map(|member| *member.class) - .chain(external_candidates - .into_iter()) + .chain(external_candidates.into_iter()) .collect(); Some(Err(InferError::AmbiguousClassItem(item, possible_classes))) - }, + } } } } - fn find_class_candidates_from_item(&mut self, ty: TyVar, item: SrcNode, item_ty: TyVar, is_assoc: bool) -> Option<(Vec, HashSet)> { + fn find_class_candidates_from_item( + &mut self, + ty: TyVar, + item: SrcNode, + _item_ty: TyVar, + is_assoc: bool, + ) -> Option<(Vec, HashSet)> { let mut implied_candidates = HashMap::new(); - for member in self.implied_members - .iter() - .filter(|member| if is_assoc { - self.ctx.classes.get(*member.class).assoc_ty(*item).is_some() + for member in self.implied_members.iter().filter(|member| { + if is_assoc { + self.ctx + .classes + .get(*member.class) + .assoc_ty(*item) + .is_some() } else { self.ctx.classes.get(*member.class).field(*item).is_some() - }) - { + } + }) { if self.var_covers_var(ty, *member.member)? { // TODO: Only replace if the new member has 'better' information than the previous one // TODO: Figure out what 'better' means. Heck, we could even try to combine them together! implied_candidates.insert(*member.class, member); } } - let implied_candidates = implied_candidates - .values() - .cloned() - .cloned() - .collect(); + let implied_candidates = implied_candidates.values().cloned().cloned().collect(); let mut external_candidates = HashSet::new(); - for (class_id, class) in self.ctx.classes + for (class_id, _class) in self + .ctx + .classes .iter() // Filter by classes that contain the given field - .filter(|(_, class)| if is_assoc { - class.assoc_ty(*item).is_some() - } else { - class.field(*item).is_some() + .filter(|(_, class)| { + if is_assoc { + class.assoc_ty(*item).is_some() + } else { + class.field(*item).is_some() + } }) { let mut covers = false; @@ -1754,7 +2181,11 @@ impl<'a> Infer<'a> { // Checking these cases isn't essential for now, we can be as coarse as we like. We're only generating // a candidate list: checking of the finally selected member will occur later. let mut todo = Vec::new(); - if matches!(self.covers_var(ty, member.member, &mut ty_gens, &mut eff_gens, &mut todo), Ok(_)) && todo.is_empty() { + if matches!( + self.covers_var(ty, member.member, &mut ty_gens, &mut eff_gens, &mut todo), + Ok(_) + ) && todo.is_empty() + { covers = true; } } @@ -1780,27 +2211,35 @@ impl<'a> Infer<'a> { (TyInfo::Record(xs, _), TyInfo::Record(ys, _)) if xs.len() == ys.len() => xs .into_iter() .zip(ys.into_iter()) - .fold(Some(true), |a, (x, y)| Some(a? && x.0 == y.0 && self.var_covers_var(x.1, y.1)?)), + .fold(Some(true), |a, (x, y)| { + Some(a? && x.0 == y.0 && self.var_covers_var(x.1, y.1)?) + }), (TyInfo::Func(x_i, x_o), TyInfo::Func(y_i, y_o)) => { Some(self.var_covers_var(x_i, y_i)? && self.var_covers_var(x_o, y_o)?) - }, + } (TyInfo::Data(x, xs), TyInfo::Data(y, ys)) if x == y && xs.len() == ys.len() => xs .into_iter() .zip(ys.into_iter()) - .fold(Some(true), |a, (x, y)| Some(a? && self.var_covers_var(x, y)?)), + .fold(Some(true), |a, (x, y)| { + Some(a? && self.var_covers_var(x, y)?) + }), (TyInfo::Assoc(x, class_x, assoc_x), TyInfo::Assoc(y, class_y, assoc_y)) - if assoc_x == assoc_y => Some(self.var_covers_var(x, y)? && self.class_covers_class(class_x, class_y)?), + if assoc_x == assoc_y => + { + Some(self.var_covers_var(x, y)? && self.class_covers_class(class_x, class_y)?) + } (TyInfo::SelfType, TyInfo::SelfType) => Some(true), - (TyInfo::Effect(x_eff, x_out, _), TyInfo::Effect(y_eff, y_out, _)) => - Some(self.var_covers_var(x_out, y_out)? && self.eff_covers_eff(x_eff, y_eff)?), + (TyInfo::Effect(x_eff, x_out, _), TyInfo::Effect(y_eff, y_out, _)) => { + Some(self.var_covers_var(x_out, y_out)? && self.eff_covers_eff(x_eff, y_eff)?) + } // TODO: This probably isn't correct by itself, we need to enforce that `eff` is indeed empty for this to // be valid (TyInfo::Effect(_eff, out, _), _) => self.var_covers_var(out, ty), (_, TyInfo::Effect(_eff, out, _)) => self.var_covers_var(var, out), - (x, y) => { + (_x, _y) => { // dbg!("{:?} covers {:?}", x, y); Some(false) - }, + } } } @@ -1812,45 +2251,56 @@ impl<'a> Infer<'a> { EffectInfo::Closed(mut effs, Some(opener)) => { effs.append(&mut self.collect_eff_insts(opener)); effs - }, + } } } fn eff_covers_eff(&self, var: EffectVar, eff: EffectVar) -> Option { - let effs_cover_effs = |effs: Vec, effs_of: Vec| if effs - .into_iter() - .all(|eff| effs_of - .iter() - .any(|var| match (self.follow_effect_inst(*var), self.follow_effect_inst(eff)) { - (EffectInstInfo::Error, _) | (_, EffectInstInfo::Error) => true, // Errors always cover - (EffectInstInfo::Unknown, _) | (_, EffectInstInfo::Unknown) => false, - (EffectInstInfo::Gen(x, _), EffectInstInfo::Gen(y, _)) if x == y => true, - (EffectInstInfo::Known(x, x_gen_tys), EffectInstInfo::Known(y, y_gen_tys)) if x == y => x_gen_tys - .into_iter() - .zip(y_gen_tys.into_iter()) - .fold(Some(true), |a, (x, y)| Some(a? && self.var_covers_var(x, y)?)) - .unwrap_or(false), - (_, _) => false, - })) - { - Some(true) - } else { - dbg!("{:?} covers {:?}", self.follow_effect(var), self.follow_effect(eff)); - None + let effs_cover_effs = |effs: Vec, effs_of: Vec| { + if effs.into_iter().all(|eff| { + effs_of.iter().any(|var| { + match (self.follow_effect_inst(*var), self.follow_effect_inst(eff)) { + (EffectInstInfo::Error, _) | (_, EffectInstInfo::Error) => true, // Errors always cover + (EffectInstInfo::Unknown, _) | (_, EffectInstInfo::Unknown) => false, + (EffectInstInfo::Gen(x, _), EffectInstInfo::Gen(y, _)) if x == y => true, + ( + EffectInstInfo::Known(x, x_gen_tys), + EffectInstInfo::Known(y, y_gen_tys), + ) if x == y => x_gen_tys + .into_iter() + .zip(y_gen_tys.into_iter()) + .fold(Some(true), |a, (x, y)| { + Some(a? && self.var_covers_var(x, y)?) + }) + .unwrap_or(false), + (_, _) => false, + } + }) + }) { + Some(true) + } else { + dbg!( + "{:?} covers {:?}", + self.follow_effect(var), + self.follow_effect(eff) + ); + None + } }; // TODO: These cases generate an obligation that lhs covers rhs. A check probably needs to be generated for this! match (self.follow_effect(var), self.follow_effect(eff)) { - (var, EffectInfo::Open(effs)| EffectInfo::Closed(effs, None)) => { + (var, EffectInfo::Open(effs) | EffectInfo::Closed(effs, None)) => { effs_cover_effs(effs, self.effs_of(var)) - }, - (EffectInfo::Closed(x_effs, Some(x_opener)), EffectInfo::Closed(y_effs, Some(y_opener))) if x_effs.is_empty() && y_effs.is_empty() => { - self.eff_covers_eff(x_opener, y_opener) - }, + } + ( + EffectInfo::Closed(x_effs, Some(x_opener)), + EffectInfo::Closed(y_effs, Some(y_opener)), + ) if x_effs.is_empty() && y_effs.is_empty() => self.eff_covers_eff(x_opener, y_opener), (x, y) => { dbg!("{:?} covers {:?}", x, y); None - }, + } } } @@ -1859,17 +2309,27 @@ impl<'a> Infer<'a> { (ClassInfo::Unknown, _) => Some(false), (_, ClassInfo::Unknown) => None, (ClassInfo::Ref(_), _) | (_, ClassInfo::Ref(_)) => unreachable!(), - (ClassInfo::Known(class_id_x, x_gen_tys, x_gen_effs), ClassInfo::Known(class_id_y, y_gen_tys, y_gen_effs)) if class_id_x == class_id_y => Some(x_gen_tys - .into_iter() - .zip(y_gen_tys.into_iter()) - .fold(Some(true), |a, (x, y)| Some(a? && self.var_covers_var(x, y)?))? && x_gen_effs + ( + ClassInfo::Known(class_id_x, x_gen_tys, x_gen_effs), + ClassInfo::Known(class_id_y, y_gen_tys, y_gen_effs), + ) if class_id_x == class_id_y => Some( + x_gen_tys .into_iter() - .zip(y_gen_effs.into_iter()) - .fold(Some(true), |a, (x, y)| Some(a? && self.eff_covers_eff(x, y)?))?), + .zip(y_gen_tys.into_iter()) + .fold(Some(true), |a, (x, y)| { + Some(a? && self.var_covers_var(x, y)?) + })? + && x_gen_effs + .into_iter() + .zip(y_gen_effs.into_iter()) + .fold(Some(true), |a, (x, y)| { + Some(a? && self.eff_covers_eff(x, y)?) + })?, + ), (x, y) => { dbg!("{:?} covers {:?}", x, y); Some(false) - }, + } } } @@ -1896,42 +2356,58 @@ impl<'a> Infer<'a> { (_, Ty::Gen(idx, _)) => { let other_gen_var = *ty_gens.entry(idx).or_insert(var); // Invariance check of generic types with one-another - match (self.check_flow(var, other_gen_var), self.check_flow(other_gen_var, var)) { + match ( + self.check_flow(var, other_gen_var), + self.check_flow(other_gen_var, var), + ) { (Some(true), Some(true)) => Ok(true), (Some(false), _) | (_, Some(false)) => Err(()), (_, _) => Ok(false), } - }, + } (TyInfo::Prim(x), Ty::Prim(y)) if x == y => Ok(true), (TyInfo::List(x), Ty::List(y)) => self.covers_var(x, y, ty_gens, eff_gens, todo), // TODO: Care about field names! (TyInfo::Record(xs, _), Ty::Record(ys, _)) if xs.len() == ys.len() => xs .into_iter() .zip(ys.into_iter()) - .try_fold(true, |a, ((_, x), (_, y))| Ok(a && self.covers_var(x, y, ty_gens, eff_gens, todo)?)), - (TyInfo::Func(x_i, x_o), Ty::Func(y_i, y_o)) => { - Ok(self.covers_var(x_i, y_i, ty_gens, eff_gens, todo)? && self.covers_var(x_o, y_o, ty_gens, eff_gens, todo)?) - }, + .try_fold(true, |a, ((_, x), (_, y))| { + Ok(a && self.covers_var(x, y, ty_gens, eff_gens, todo)?) + }), + (TyInfo::Func(x_i, x_o), Ty::Func(y_i, y_o)) => Ok(self + .covers_var(x_i, y_i, ty_gens, eff_gens, todo)? + && self.covers_var(x_o, y_o, ty_gens, eff_gens, todo)?), (TyInfo::Data(x, xs), Ty::Data(y, ys)) if x == y && xs.len() == ys.len() => xs .into_iter() .zip(ys.into_iter()) - .try_fold(true, |a, (x, y)| Ok(a && self.covers_var(x, y, ty_gens, eff_gens, todo)?)), - (TyInfo::Assoc(x, class_x, assoc_x), Ty::Assoc(y, (class_id_y, y_gen_tys, y_gen_effs), assoc_y)) - if assoc_x == assoc_y => Ok(self.covers_var(x, y, ty_gens, eff_gens, todo)? && match self.follow_class(class_x) { + .try_fold(true, |a, (x, y)| { + Ok(a && self.covers_var(x, y, ty_gens, eff_gens, todo)?) + }), + ( + TyInfo::Assoc(x, class_x, assoc_x), + Ty::Assoc(y, (class_id_y, y_gen_tys, _y_gen_effs), assoc_y), + ) if assoc_x == assoc_y => Ok(self.covers_var(x, y, ty_gens, eff_gens, todo)? + && match self.follow_class(class_x) { ClassInfo::Ref(_) => unreachable!(), ClassInfo::Unknown => false, // TODO: correct? - ClassInfo::Known(class_id_x, x_gen_tys, x_gen_effs) => class_id_x == class_id_y && x_gen_tys - .into_iter() - .zip(y_gen_tys.into_iter()) - .try_fold(true, |a, (x, y)| Ok(a && self.covers_var(x, y, ty_gens, eff_gens, todo)?))?, + ClassInfo::Known(class_id_x, x_gen_tys, _x_gen_effs) => { + class_id_x == class_id_y + && x_gen_tys + .into_iter() + .zip(y_gen_tys.into_iter()) + .try_fold(true, |a, (x, y)| { + Ok(a && self.covers_var(x, y, ty_gens, eff_gens, todo)?) + })? + } }), - (TyInfo::Effect(x_eff, x_out, _), Ty::Effect(y_eff, y_out)) => - Ok(self.covers_var(x_out, y_out, ty_gens, eff_gens, todo)? && self.covers_var_eff((x_eff, var), y_eff, ty_gens, eff_gens, todo)?), + (TyInfo::Effect(x_eff, x_out, _), Ty::Effect(y_eff, y_out)) => Ok(self + .covers_var(x_out, y_out, ty_gens, eff_gens, todo)? + && self.covers_var_eff((x_eff, var), y_eff, ty_gens, eff_gens, todo)?), (TyInfo::Effect(eff, out, _), _) => { // This only covers if the effect is empty! todo.push(Check::EffectEmpty((eff, var), var, EqInfo::default())); self.covers_var(out, ty, ty_gens, eff_gens, todo) - }, + } // Unknown types *could* match, maybe (TyInfo::Unknown(_), _) => Ok(false), @@ -1948,13 +2424,14 @@ impl<'a> Infer<'a> { todo: &mut Vec, ) -> Result { match (self.follow_effect(var), self.ctx.tys.get_effect(eff)) { - (EffectInfo::Open(var_effs) | EffectInfo::Closed(var_effs, None), Effect::Known(effs)) => { - if var_effs - .into_iter() - .all(|x| effs - .iter() - .any(|y| match (self.follow_effect_inst(x), y) { - (_, Ok(EffectInst::Gen(idx, _))) => if let Some((other_gen_var, other_ty)) = eff_gens.get(&idx) { + ( + EffectInfo::Open(var_effs) | EffectInfo::Closed(var_effs, None), + Effect::Known(effs), + ) => { + if var_effs.into_iter().all(|x| { + effs.iter().any(|y| match (self.follow_effect_inst(x), y) { + (_, Ok(EffectInst::Gen(idx, _))) => { + if let Some((other_gen_var, other_ty)) = eff_gens.get(idx) { // Invariance check of generic types with one-another match ( self.check_flow_eff((var, var_ty), (*other_gen_var, *other_ty)), @@ -1967,31 +2444,42 @@ impl<'a> Infer<'a> { } else { eff_gens.insert(*idx, (var, var_ty)); true - }, - (EffectInstInfo::Known(x, x_gen_tys), Ok(EffectInst::Concrete(y, y_gen_tys))) if x == *y => x_gen_tys - .into_iter() - .zip(y_gen_tys.into_iter()) - .try_fold(true, |a, (x, y)| Ok(a && self.covers_var(x, *y, ty_gens, eff_gens, todo)?)) - .unwrap_or_else(|()| false), - (x, y) => { - dbg!("{:?} covers {:?}", x, y); - false - }, - })) - { + } + } + ( + EffectInstInfo::Known(x, x_gen_tys), + Ok(EffectInst::Concrete(y, y_gen_tys)), + ) if x == *y => x_gen_tys + .into_iter() + .zip(y_gen_tys.iter()) + .try_fold(true, |a, (x, y)| { + self.covers_var(x, *y, ty_gens, eff_gens, todo) + .map(|b| a && b) + }) + .unwrap_or(false), + (x, y) => { + dbg!("{:?} covers {:?}", x, y); + false + } + }) + }) { Ok(true) } else { - dbg!("{:?} covers {:?}", self.follow_effect(var), self.ctx.tys.get_effect(eff)); + dbg!( + "{:?} covers {:?}", + self.follow_effect(var), + self.ctx.tys.get_effect(eff) + ); Err(()) } - }, + } (EffectInfo::Closed(var_effs, Some(opener)), _) if var_effs.is_empty() => { self.covers_var_eff((opener, var_ty), eff, ty_gens, eff_gens, todo) - }, + } (x, y) => { dbg!("{:?} covers {:?}", x, y); Err(()) - }, // TODO: Other cases + } // TODO: Other cases } } @@ -2008,60 +2496,81 @@ impl<'a> Infer<'a> { eff_links: &mut HashMap, ) { match (self.ctx.tys.get(member), self.follow_info(ty)) { - (Ty::Gen(gen_idx, _), _) => { ty_links.insert(gen_idx, ty); }, + (Ty::Gen(gen_idx, _), _) => { + ty_links.insert(gen_idx, ty); + } // If we try to derive links through an unknown type variable, we instantiate the reified type into the // current context, generating free type variables for any as-yet unseen generics. This allows // maybe-covering impls to work. // TODO: This can potentially result in orphaned free type variables that never get inferred, despite the // program being well-typed, which could cause phantom errors, or maybe this is fine? - (_, TyInfo::Unknown(inst_span)) => { + (_, TyInfo::Unknown(_inst_span)) => { let span = self.ctx().tys.get_span(member); - let inst_ty = self.instantiate( - member, - span, - &mut |idx, _, this: &mut Self| Some(*ty_links.entry(idx).or_insert_with(|| this.insert(use_span, TyInfo::Unknown(Some(this.span(ty)))))), - &mut |idx, this: &mut Self| Some(*eff_links.entry(idx).or_insert_with(|| this.insert_effect(use_span, EffectInfo::free()))), - self_ty, - invariant(), - ); + let inst_ty = + self.instantiate( + member, + span, + &mut |idx, _, this: &mut Self| { + Some(*ty_links.entry(idx).or_insert_with(|| { + this.insert(use_span, TyInfo::Unknown(Some(this.span(ty)))) + })) + }, + &mut |idx, this: &mut Self| { + Some(*eff_links.entry(idx).or_insert_with(|| { + this.insert_effect(use_span, EffectInfo::free()) + })) + }, + self_ty, + invariant(), + ); self.make_flow(ty, inst_ty, use_span); - }, - (Ty::List(x), TyInfo::List(y)) => self.derive_links(x, y, self_ty, use_span, ty_links, eff_links), + } + (Ty::List(x), TyInfo::List(y)) => { + self.derive_links(x, y, self_ty, use_span, ty_links, eff_links) + } (Ty::Record(xs, _), TyInfo::Record(ys, _)) => xs .into_iter() .zip(ys.into_iter()) - .for_each(|((_, x), (_, y))| self.derive_links(x, y, self_ty, use_span, ty_links, eff_links)), + .for_each(|((_, x), (_, y))| { + self.derive_links(x, y, self_ty, use_span, ty_links, eff_links) + }), (Ty::Func(x_i, x_o), TyInfo::Func(y_i, y_o)) => { self.derive_links(x_i, y_i, self_ty, use_span, ty_links, eff_links); self.derive_links(x_o, y_o, self_ty, use_span, ty_links, eff_links); - }, + } (Ty::Data(_, xs), TyInfo::Data(_, ys)) => xs .into_iter() .zip(ys.into_iter()) .for_each(|(x, y)| self.derive_links(x, y, self_ty, use_span, ty_links, eff_links)), - (Ty::Assoc(x, (class_id_x, x_gen_tys, x_gen_effs), assoc_x), TyInfo::Assoc(y, class_y, assoc_y)) - if assoc_x == assoc_y => { - self.derive_links(x, y, self_ty, use_span, ty_links, eff_links); - match self.follow_class(class_y) { - ClassInfo::Unknown => panic!("Deriving links for unknown class!"), - ClassInfo::Ref(_) => unreachable!(), - ClassInfo::Known(class_id_y, y_gen_tys, y_gen_effs) => { - assert!(class_id_x == class_id_y); - x_gen_tys - .into_iter() - .zip(y_gen_tys.into_iter()) - .for_each(|(x, y)| self.derive_links(x, y, self_ty, use_span, ty_links, eff_links)); - x_gen_effs - .into_iter() - .zip(y_gen_effs.into_iter()) - .for_each(|(x, y)| { - if let Some(x) = x { - self.derive_links_eff(x, y, self_ty, use_span, ty_links, eff_links) - } - }); - }, + ( + Ty::Assoc(x, (class_id_x, x_gen_tys, x_gen_effs), assoc_x), + TyInfo::Assoc(y, class_y, assoc_y), + ) if assoc_x == assoc_y => { + self.derive_links(x, y, self_ty, use_span, ty_links, eff_links); + match self.follow_class(class_y) { + ClassInfo::Unknown => panic!("Deriving links for unknown class!"), + ClassInfo::Ref(_) => unreachable!(), + ClassInfo::Known(class_id_y, y_gen_tys, y_gen_effs) => { + assert!(class_id_x == class_id_y); + x_gen_tys + .into_iter() + .zip(y_gen_tys.into_iter()) + .for_each(|(x, y)| { + self.derive_links(x, y, self_ty, use_span, ty_links, eff_links) + }); + x_gen_effs + .into_iter() + .zip(y_gen_effs.into_iter()) + .for_each(|(x, y)| { + if let Some(x) = x { + self.derive_links_eff( + x, y, self_ty, use_span, ty_links, eff_links, + ) + } + }); } - }, + } + } (Ty::Effect(_, _), TyInfo::Effect(_, _, _)) => todo!(), /* (Ty::Effect(eff, out), _) => { @@ -2073,12 +2582,13 @@ impl<'a> Infer<'a> { (_, TyInfo::Effect(eff, out, _)) => { // Make sure we actually can see through this effect! // TODO: Make this generate better errors - self.checks.push_back(Check::EffectEmpty((eff, ty), ty, EqInfo::default())); + self.checks + .push_back(Check::EffectEmpty((eff, ty), ty, EqInfo::default())); self.derive_links(member, out, self_ty, use_span, ty_links, eff_links) - }, + } (_, TyInfo::SelfType) => panic!("Self type not permitted here"), - _ => {}, // Only type constructors and generic types generate obligations + _ => {} // Only type constructors and generic types generate obligations } } @@ -2092,24 +2602,41 @@ impl<'a> Infer<'a> { eff_links: &mut HashMap, ) { match (self.ctx.tys.get_effect(member), self.follow_effect(eff)) { - (Effect::Known(effs), EffectInfo::Open(member_effs)| EffectInfo::Closed(member_effs, None)) if effs.is_empty() && member_effs.is_empty() => {} + ( + Effect::Known(effs), + EffectInfo::Open(member_effs) | EffectInfo::Closed(member_effs, None), + ) if effs.is_empty() && member_effs.is_empty() => {} (Effect::Known(mut effs), info) if effs.len() == 1 => { let eff_id = effs.remove(0); for eff_var in self.effs_of(info) { match (&eff_id, self.follow_effect_inst(eff_var)) { - (Ok(EffectInst::Gen(idx, _)), _) => { eff_links.insert(*idx, eff); }, - (Ok(EffectInst::Concrete(x, x_gen_tys)), EffectInstInfo::Known(y, y_gen_tys)) if *x == y => x_gen_tys - .into_iter() - .zip(y_gen_tys.into_iter()) - .for_each(|(x, y)| self.derive_links(*x, y, self_ty, use_span, ty_links, eff_links)), + (Ok(EffectInst::Gen(idx, _)), _) => { + eff_links.insert(*idx, eff); + } + ( + Ok(EffectInst::Concrete(x, x_gen_tys)), + EffectInstInfo::Known(y, y_gen_tys), + ) if *x == y => { + x_gen_tys + .iter() + .zip(y_gen_tys.into_iter()) + .for_each(|(x, y)| { + self.derive_links(*x, y, self_ty, use_span, ty_links, eff_links) + }) + } (x, y) => todo!("Derive links between {:?} and {:?}", x, y), } } } (_, EffectInfo::Closed(member_effs, Some(opener))) if member_effs.is_empty() => { self.derive_links_eff(member, opener, self_ty, use_span, ty_links, eff_links) - }, - (x, y) => todo!("Derive links between {:?} and {:?} (effs_of(y) = {:?})", x, y, self.effs_of(y.clone())), + } + (x, y) => todo!( + "Derive links between {:?} and {:?} (effs_of(y) = {:?})", + x, + y, + self.effs_of(y.clone()) + ), } } @@ -2121,7 +2648,7 @@ impl<'a> Infer<'a> { proof_stack: &mut Vec<(TyVar, ClassId, Vec)>, ty: TyVar, (class_id, class_gen_tys, class_gen_effs): (ClassId, Vec, Vec), - assoc: Vec<(SrcNode, TyVar)>, + _assoc: Vec<(SrcNode, TyVar)>, obl_span: Span, use_span: Span, ) -> Option, InferError>> { @@ -2130,31 +2657,41 @@ impl<'a> Infer<'a> { TyInfo::Error(_) => { self.set_error(ty); Some(Ok(Err(()))) // Resolving an error type always succeeds - }, + } // First, search through real members to resolve the obligation - info => { + _info => { // If searching through real obligations failed, search through implied obligations if let Some(member) = { let mut selected = None; for member in self.implied_members.iter() { if class_id == *member.class && self.var_covers_var(ty, *member.member)? - && class_gen_tys.iter() + && class_gen_tys + .iter() .zip(member.gen_tys.iter()) - .fold(Some(true), |a, (ty, arg)| Some(a? && Self::var_covers_var(self, *ty, *arg)?))? - && class_gen_effs.iter() + .fold(Some(true), |a, (ty, arg)| { + Some(a? && Self::var_covers_var(self, *ty, *arg)?) + })? + && class_gen_effs + .iter() .zip(member.gen_effs.iter()) - .fold(Some(true), |a, (eff, arg)| Some(a? && Self::eff_covers_eff(self, *eff, *arg)?))? + .fold(Some(true), |a, (eff, arg)| { + Some(a? && Self::eff_covers_eff(self, *eff, *arg)?) + })? { // Try to select an implied member where the real member is known // TODO: Is multiple covering impls an error? Should coherence prevent this case? - selected = Some(selected - .zip_with(Some(member), |s: &InferImpliedMember, m| if matches!(&s.items, ImpliedItems::Eq(_)) { - s - } else { - m - }) - .unwrap_or(member)); + selected = Some( + selected + .zip_with(Some(member), |s: &InferImpliedMember, m| { + if matches!(&s.items, ImpliedItems::Eq(_)) { + s + } else { + m + } + }) + .unwrap_or(member), + ); } } selected @@ -2167,12 +2704,21 @@ impl<'a> Infer<'a> { for (member_gen_ty, gen_ty) in member.gen_tys.iter().zip(class_gen_tys.iter()) { self.make_flow(*gen_ty, *member_gen_ty, EqInfo::from(obl_span)); } - for (member_gen_eff, gen_eff) in member.gen_effs.iter().zip(class_gen_effs.iter()) { - self.make_flow_effect((*gen_eff, ty), (*member_gen_eff, *member.member), EqInfo::from(obl_span)); + for (member_gen_eff, gen_eff) in + member.gen_effs.iter().zip(class_gen_effs.iter()) + { + self.make_flow_effect( + (*gen_eff, ty), + (*member_gen_eff, *member.member), + EqInfo::from(obl_span), + ); } // Check constrained associated types - let class = self.insert_class(obl_span, ClassInfo::Known(class_id, class_gen_tys.clone(), class_gen_effs.clone())); + let _class = self.insert_class( + obl_span, + ClassInfo::Known(class_id, class_gen_tys, class_gen_effs), + ); // if let ImpliedItems::Eq(assoc_set) = &items { // for (assoc, assoc_ty) in assoc { // if let Some((name, ty)) = assoc_set.iter().find(|(name, _)| **name == *assoc) { @@ -2192,26 +2738,62 @@ impl<'a> Infer<'a> { let mut eff_gens = HashMap::new(); let mut todo = Vec::new(); // TODO: Instantiation should occur here, in a temporary inference context, to allow type projections to occur - let (covers, maybe_covers) = match Self::covers_var(self, ty, member.member, &mut ty_gens, &mut eff_gens, &mut todo) - .and_then(|covers| Ok(covers && class_gen_tys.iter() - .zip(member.gen_tys.iter()) - .try_fold(true, |a, (ty, arg)| Ok(a && Self::covers_var(self, *ty, *arg, &mut ty_gens, &mut eff_gens, &mut todo)?))?)) - .and_then(|covers| Ok(covers && class_gen_effs.iter() - .zip(member.gen_effs.iter()) - .try_fold(true, |a, (eff, arg)| if let Some(arg) = *arg { - Ok(a && Self::covers_var_eff(self, (*eff, ty), arg, &mut ty_gens, &mut eff_gens, &mut todo)?) - } else { - // Errors always fail - Err(()) - })?)) - { + let (covers, maybe_covers) = match Self::covers_var( + self, + ty, + member.member, + &mut ty_gens, + &mut eff_gens, + &mut todo, + ) + .and_then(|covers| { + Ok(covers + && class_gen_tys.iter().zip(member.gen_tys.iter()).try_fold( + true, + |a, (ty, arg)| { + Ok(a && Self::covers_var( + self, + *ty, + *arg, + &mut ty_gens, + &mut eff_gens, + &mut todo, + )?) + }, + )?) + }) + .and_then(|covers| { + Ok(covers + && class_gen_effs.iter().zip(member.gen_effs.iter()).try_fold( + true, + |a, (eff, arg)| { + if let Some(arg) = *arg { + Ok(a && Self::covers_var_eff( + self, + (*eff, ty), + arg, + &mut ty_gens, + &mut eff_gens, + &mut todo, + )?) + } else { + // Errors always fail + Err(()) + } + }, + )?) + }) { Ok(true) => (true, false), Ok(false) => (false, true), Err(()) => (false, false), }; - if covers { covering_members.push((member_id, member, todo.clone())); } - if maybe_covers { maybe_covering_members.push((member_id, member, todo)); } + if covers { + covering_members.push((member_id, member, todo.clone())); + } + if maybe_covers { + maybe_covering_members.push((member_id, member, todo)); + } } match (covering_members.len(), maybe_covering_members.len()) { @@ -2223,11 +2805,19 @@ impl<'a> Infer<'a> { // *self.ctx.classes.get(class_id).name, // gen_tys.iter().map(|ty| format!(" {:?}", self.follow_info(*ty))).collect::(), // ); - let gen_span = if let TyInfo::Gen(gen_idx, gen_scope, _) = self.follow_info(ty) { - Some(self.ctx.tys.get_gen_scope(gen_scope).get(gen_idx).name.span()) - } else { - None - }; + let _gen_span = + if let TyInfo::Gen(gen_idx, gen_scope, _) = self.follow_info(ty) { + Some( + self.ctx + .tys + .get_gen_scope(gen_scope) + .get(gen_idx) + .name + .span(), + ) + } else { + None + }; // panic!( // "Failed to prove that {:?} is a member of {}{}{}!", // self.follow_info(ty), @@ -2237,13 +2827,14 @@ impl<'a> Infer<'a> { // ); //Some(Err(InferError::TypeDoesNotFulfil(self.insert_class(obl_span, ClassInfo::Known(class_id, class_gen_tys, class_gen_effs)), ty, obl_span, gen_span, use_span))) None - }, + } // Exactly one definitely covering member, one one possible-covering member: great, we know // what to substitute! (1, _) | (0, 1) => { // Can't fail let (covering_member_id, covering_member, todo) = covering_members - .into_iter().next() + .into_iter() + .next() .or(maybe_covering_members.into_iter().next()) .unwrap(); @@ -2253,23 +2844,54 @@ impl<'a> Infer<'a> { let covering_member_gen_tys = covering_member.gen_tys.clone(); let covering_member_gen_effs = covering_member.gen_effs.clone(); let covering_member_gen_scope = covering_member.gen_scope; - let covering_member_assoc = covering_member.assoc.clone(); + let _covering_member_assoc = covering_member.assoc.clone(); // Derive generic types that need substituting from the member let mut ty_links = HashMap::new(); let mut eff_links = HashMap::new(); - self.derive_links(covering_member_member, ty, Some(ty), use_span, &mut ty_links, &mut eff_links); - for (member_gen_ty, gen_ty) in covering_member_gen_tys.iter().zip(class_gen_tys.iter()) { - self.derive_links(*member_gen_ty, *gen_ty, Some(ty), use_span, &mut ty_links, &mut eff_links); + self.derive_links( + covering_member_member, + ty, + Some(ty), + use_span, + &mut ty_links, + &mut eff_links, + ); + for (member_gen_ty, gen_ty) in + covering_member_gen_tys.iter().zip(class_gen_tys.iter()) + { + self.derive_links( + *member_gen_ty, + *gen_ty, + Some(ty), + use_span, + &mut ty_links, + &mut eff_links, + ); } - for (member_gen_eff, gen_eff) in covering_member_gen_effs.iter().zip(class_gen_effs.iter()) { + for (member_gen_eff, gen_eff) in + covering_member_gen_effs.iter().zip(class_gen_effs.iter()) + { if let Some(member_gen_eff) = member_gen_eff { - self.derive_links_eff(*member_gen_eff, *gen_eff, Some(ty), use_span, &mut ty_links, &mut eff_links); + self.derive_links_eff( + *member_gen_eff, + *gen_eff, + Some(ty), + use_span, + &mut ty_links, + &mut eff_links, + ); } } - let covering_gen_scope = self.ctx.tys.get_gen_scope(covering_member_gen_scope); - for member in covering_gen_scope.implied_members.as_ref().expect("Implied members must be known here").clone() { + let covering_gen_scope = + self.ctx.tys.get_gen_scope(covering_member_gen_scope); + for member in covering_gen_scope + .implied_members + .as_ref() + .expect("Implied members must be known here") + .clone() + { // println!("Deriving links from {}, {:?} in {}", self.ctx().tys.display(self.ctx(), covering_member_member), self.follow_info(ty), self.ctx().tys.get_span(*member.member).src()); let member_ty = self.instantiate( *member.member, @@ -2279,52 +2901,71 @@ impl<'a> Infer<'a> { Some(ty), invariant(), ); - let member_gen_tys = member.gen_tys - .iter() - .map(|gen_ty| self.instantiate( - *gen_ty, - member.member.span(), - &mut |idx, _, _| ty_links.get(&idx).copied(), - &mut |idx, _| eff_links.get(&idx).copied(), - Some(ty), - invariant(), - )) - .collect::>(); - let member_gen_effs = member.gen_effs + let member_gen_tys = member + .gen_tys .iter() - .map(|gen_eff| match gen_eff.map(|gen_eff| self.instantiate_eff( - gen_eff, + .map(|gen_ty| { + self.instantiate( + *gen_ty, member.member.span(), &mut |idx, _, _| ty_links.get(&idx).copied(), &mut |idx, _| eff_links.get(&idx).copied(), Some(ty), invariant(), - )) - { - Some(Ok(Some(eff))) => eff, - // TODO: Make sure this is fine in all other cases. It should be? - _ => self.insert_effect(member.member.span(), EffectInfo::free()), + ) + }) + .collect::>(); + let member_gen_effs = member + .gen_effs + .iter() + .map(|gen_eff| { + match gen_eff.map(|gen_eff| { + self.instantiate_eff( + gen_eff, + member.member.span(), + &mut |idx, _, _| ty_links.get(&idx).copied(), + &mut |idx, _| eff_links.get(&idx).copied(), + Some(ty), + invariant(), + ) + }) { + Some(Ok(Some(eff))) => eff, + // TODO: Make sure this is fine in all other cases. It should be? + _ => self.insert_effect( + member.member.span(), + EffectInfo::free(), + ), + } }) .collect::>(); let member_assoc = match &member.items { ImpliedItems::Eq(assoc) => assoc .iter() - .map(|(name, assoc)| (name.clone(), self.instantiate( - *assoc, - member.member.span(), - &mut |idx, _, _| ty_links.get(&idx).copied(), - &mut |idx, _| eff_links.get(&idx).copied(), - Some(ty), - invariant(), - ))) + .map(|(name, assoc)| { + ( + name.clone(), + self.instantiate( + *assoc, + member.member.span(), + &mut |idx, _, _| ty_links.get(&idx).copied(), + &mut |idx, _| eff_links.get(&idx).copied(), + Some(ty), + invariant(), + ), + ) + }) .collect::>(), ImpliedItems::Real(_) => Vec::new(), }; let proof_key = (member_ty, *member.class, member_gen_tys.clone()); if proof_stack.contains(&proof_key) { - return Some(Err(InferError::CycleWhenResolving(ty, (class_id, class_gen_tys.clone(), class_gen_effs.clone()), member.span()))); + return Some(Err(InferError::CycleWhenResolving( + ty, + (class_id, class_gen_tys, class_gen_effs), + member.span(), + ))); } else { // println!( // "Trying to prove that {:?} is a member of {}{}{}!", @@ -2337,7 +2978,11 @@ impl<'a> Infer<'a> { let res = self.resolve_obligation( proof_stack, member_ty, - (*member.class, member_gen_tys.clone(), member_gen_effs.clone()), + ( + *member.class, + member_gen_tys.clone(), + member_gen_effs.clone(), + ), member_assoc, member.class.span(), use_span, @@ -2351,10 +2996,10 @@ impl<'a> Infer<'a> { // } proof_stack.pop(); match res { - Some(Ok(Ok(_))) => {}, + Some(Ok(Ok(_))) => {} // Successful, but only because an existing error occurred // TODO: Return immediately, or continue to generate errors? - Some(Ok(Err(()))) => {},//return Some(Ok(Err(()))), + Some(Ok(Err(()))) => {} //return Some(Ok(Err(()))), Some(Err(err)) => return Some(Err(err)), None => { // Not enough information to resolve it yet? That's okay! Take it as a win @@ -2366,7 +3011,7 @@ impl<'a> Infer<'a> { vec![], use_span, ); - }, + } } } } @@ -2383,7 +3028,9 @@ impl<'a> Infer<'a> { invariant(), ); self.make_flow(ty, member_ty, EqInfo::from(use_span)); - for (gen_ty, covering_gen_ty) in class_gen_tys.iter().zip(covering_member_gen_tys.iter()) { + for (gen_ty, covering_gen_ty) in + class_gen_tys.iter().zip(covering_member_gen_tys.iter()) + { let covering_gen_ty = self.instantiate( *covering_gen_ty, use_span, @@ -2396,15 +3043,19 @@ impl<'a> Infer<'a> { self.make_flow(*gen_ty, covering_gen_ty, EqInfo::from(use_span)); } - for (gen_eff, covering_gen_eff) in class_gen_effs.iter().zip(covering_member_gen_effs.iter()) { + for (gen_eff, covering_gen_eff) in + class_gen_effs.iter().zip(covering_member_gen_effs.iter()) + { if let Some(covering_gen_eff) = *covering_gen_eff { let covering_gen_eff = match self.instantiate_eff( covering_gen_eff, use_span, &mut |idx, _, _| ty_links.get(&idx).copied(), - &mut |idx, infer| Some(*eff_links - .entry(idx) - .or_insert_with(|| infer.insert_effect(use_span, EffectInfo::free()))), + &mut |idx, infer| { + Some(*eff_links.entry(idx).or_insert_with(|| { + infer.insert_effect(use_span, EffectInfo::free()) + })) + }, Some(ty), invariant(), ) { @@ -2413,7 +3064,11 @@ impl<'a> Infer<'a> { _ => self.insert_effect(use_span, EffectInfo::free()), }; // TODO: Invariance - self.make_flow_effect((*gen_eff, member_ty), (covering_gen_eff, member_ty), EqInfo::from(use_span)); + self.make_flow_effect( + (*gen_eff, member_ty), + (covering_gen_eff, member_ty), + EqInfo::from(use_span), + ); } } @@ -2437,7 +3092,7 @@ impl<'a> Infer<'a> { // } Some(Ok(Ok(ImpliedItems::Real(covering_member_id)))) - }, + } // Multiple covering members: we don't know which one to pick! // This *probably* happened because we don't have have enough information about the member or // about available members, so bail for now and resolve this later. @@ -2447,26 +3102,36 @@ impl<'a> Infer<'a> { "Incoherence when solving {:?} as member of {}{}!", self.follow_info(ty), *self.ctx.classes.get(class_id).name, - class_gen_tys.iter().map(|arg| format!(" {:?}", self.follow_info(*arg))).collect::(), + class_gen_tys + .iter() + .map(|arg| format!(" {:?}", self.follow_info(*arg))) + .collect::(), ); println!("Members are:"); - for (member_id, member, _) in covering_members { + for (_member_id, member, _) in covering_members { println!( "{} < {}{} (in {})", self.ctx().tys.display(self.ctx(), member.member), *self.ctx.classes.get(class_id).name, - member.gen_tys.iter().map(|ty| format!(" {}", self.ctx().tys.display(self.ctx(), *ty))).collect::(), + member + .gen_tys + .iter() + .map(|ty| format!( + " {}", + self.ctx().tys.display(self.ctx(), *ty) + )) + .collect::(), self.ctx().tys.get_span(member.member).src(), ); } println!("This probably should be caught by a member overlap/coherence checker"); println!("Note that Tao's understanding of a member overlap is current unnecessarily conservative and does not consider type obligations"); None - }, + } (_, _) => None, } } - }, + } } } @@ -2484,17 +3149,17 @@ impl<'a> Infer<'a> { } // A constraint being resolved resets the counter tries = self.constraints.len(); - }, + } None => self.constraints.push_back(c), // Still unresolved... } } else { - break + break; } } for check in std::mem::take(&mut self.checks) { match self.check(check) { - Ok(()) => {}, + Ok(()) => {} Err(e) => self.errors.push(e), } } @@ -2510,17 +3175,33 @@ impl<'a> Infer<'a> { match c { Constraint::Access(record, field_name, _field) => { if !self.is_error(record) { - errors.push(InferError::NoSuchItem(record, self.span(record), field_name.clone())); + errors.push(InferError::NoSuchItem( + record, + self.span(record), + field_name.clone(), + )); } - }, + } Constraint::Update(record, field_name, _field) => { if !self.is_error(record) { - errors.push(InferError::NoSuchItem(record, self.span(record), field_name.clone())); + errors.push(InferError::NoSuchItem( + record, + self.span(record), + field_name.clone(), + )); } - }, + } Constraint::Impl(ty, class, obl_span, assoc, use_span) => { - let gen_span = if let TyInfo::Gen(gen_idx, gen_scope, _) = self.follow_info(ty) { - Some(self.ctx.tys.get_gen_scope(gen_scope).get(gen_idx).name.span()) + let gen_span = if let TyInfo::Gen(gen_idx, gen_scope, _) = self.follow_info(ty) + { + Some( + self.ctx + .tys + .get_gen_scope(gen_scope) + .get(gen_idx) + .name + .span(), + ) } else { None }; @@ -2531,24 +3212,28 @@ impl<'a> Infer<'a> { for (_, assoc_ty) in assoc { self.set_error(assoc_ty); } - errors.push(InferError::TypeDoesNotFulfil(class, ty, obl_span, gen_span, use_span)); + errors.push(InferError::TypeDoesNotFulfil( + class, ty, obl_span, gen_span, use_span, + )); } - }, + } Constraint::ClassField(_ty, _class, field, _field_ty, _span) => { errors.push(InferError::AmbiguousClassItem(field, Vec::new())) - }, + } Constraint::ClassAssoc(ty, _class, assoc, assoc_ty, _span) => { if !self.is_error(ty) && !self.is_error(assoc_ty) { errors.push(InferError::AmbiguousClassItem(assoc, Vec::new())) } - }, - Constraint::EffectSendRecv(eff, send, recv, span) => errors.push(InferError::CannotInferEffect(eff)), + } + Constraint::EffectSendRecv(eff, _send, _recv, _span) => { + errors.push(InferError::CannotInferEffect(eff)) + } Constraint::EffectPropagate(obj, _, out_ty, obj_span, op_span, _) => { if !self.is_error(obj) && !self.is_unknown(obj) { self.set_error(out_ty); errors.push(InferError::NotEffectful(obj, obj_span, op_span)) } - }, + } } } @@ -2556,7 +3241,7 @@ impl<'a> Infer<'a> { if errors.is_empty() { // Report errors for types that cannot be inferred let tys = self.iter().collect::>(); - for (ty, info) in tys { + for (ty, _info) in tys { let ty = self.follow(ty); if let TyInfo::Unknown(origin) = self.follow_info(ty) { if !self.is_error(ty) { @@ -2585,22 +3270,30 @@ impl<'a> Infer<'a> { InferError::CannotCoerce(x, y, inner, info) => { let inner = inner.map(|(a, b)| (checked.reify(a), checked.reify(b))); Error::CannotCoerce(checked.reify(x), checked.reify(y), inner, info) - }, + } InferError::CannotInfer(a, origin) => Error::CannotInfer(checked.reify(a), origin), - InferError::CannotInferEffect(eff) => Error::CannotInferEffect(checked.infer.effect_inst_vars[eff.0].0, checked.reify_effect_inst(eff)), - InferError::Recursive(a, part) => Error::Recursive(checked.reify(a), checked.infer.span(a), checked.infer.span(part)), - InferError::NoSuchItem(a, record_span, field) => Error::NoSuchItem(checked.reify(a), record_span, field), - InferError::NoSuchField(a, record_span, field) => Error::NoSuchField(checked.reify(a), record_span, field), + InferError::CannotInferEffect(eff) => Error::CannotInferEffect( + checked.infer.effect_inst_vars[eff.0].0, + checked.reify_effect_inst(eff), + ), + InferError::Recursive(a, part) => Error::Recursive( + checked.reify(a), + checked.infer.span(a), + checked.infer.span(part), + ), + InferError::NoSuchItem(a, record_span, field) => { + Error::NoSuchItem(checked.reify(a), record_span, field) + } + InferError::NoSuchField(a, record_span, field) => { + Error::NoSuchField(checked.reify(a), record_span, field) + } InferError::TypeDoesNotFulfil(class, ty, obl_span, gen_span, use_span) => { let class = match checked.infer.follow_class(class) { ClassInfo::Unknown => None, ClassInfo::Ref(_) => unreachable!(), ClassInfo::Known(class_id, gen_tys, gen_effs) => Some(( class_id, - gen_tys - .iter() - .map(|ty| checked.reify(*ty)) - .collect(), + gen_tys.iter().map(|ty| checked.reify(*ty)).collect(), gen_effs .iter() .map(|eff| checked.reify_effect(*eff)) @@ -2608,26 +3301,33 @@ impl<'a> Infer<'a> { )), }; Error::TypeDoesNotFulfil(class, checked.reify(ty), obl_span, gen_span, use_span) - }, - InferError::RecursiveAlias(alias, a, span) => Error::RecursiveAlias(alias, checked.reify(a), span), - InferError::PatternNotSupported(lhs, op, rhs, span) => Error::PatternNotSupported(checked.reify(lhs), op, checked.reify(rhs), span), - InferError::AmbiguousClassItem(field, candidate_classes) => Error::AmbiguousClassItem(field, candidate_classes), - InferError::CycleWhenResolving(ty, (class_id, gen_tys, gen_effs), cycle_span) => Error::CycleWhenResolving( - checked.reify(ty), - ( - class_id, - gen_tys - .iter() - .map(|ty| checked.reify(*ty)) - .collect(), - gen_effs - .iter() - .map(|eff| checked.reify_effect(*eff)) - .collect(), - ), - cycle_span, - ), - InferError::NotEffectful(ty, obj_span, span) => Error::NotEffectful(checked.reify(ty), obj_span, span), + } + InferError::RecursiveAlias(alias, a, span) => { + Error::RecursiveAlias(alias, checked.reify(a), span) + } + InferError::PatternNotSupported(lhs, op, rhs, span) => { + Error::PatternNotSupported(checked.reify(lhs), op, checked.reify(rhs), span) + } + InferError::AmbiguousClassItem(field, candidate_classes) => { + Error::AmbiguousClassItem(field, candidate_classes) + } + InferError::CycleWhenResolving(ty, (class_id, gen_tys, gen_effs), cycle_span) => { + Error::CycleWhenResolving( + checked.reify(ty), + ( + class_id, + gen_tys.iter().map(|ty| checked.reify(*ty)).collect(), + gen_effs + .iter() + .map(|eff| checked.reify_effect(*eff)) + .collect(), + ), + cycle_span, + ) + } + InferError::NotEffectful(ty, obj_span, span) => { + Error::NotEffectful(checked.reify(ty), obj_span, span) + } }) .collect(); @@ -2642,8 +3342,12 @@ pub struct Checked<'a> { } impl<'a> Checked<'a> { - pub fn ctx(&self) -> &Context { &self.infer.ctx } - pub fn ctx_mut(&mut self) -> &mut Context { &mut self.infer.ctx } + pub fn ctx(&self) -> &Context { + self.infer.ctx + } + pub fn ctx_mut(&mut self) -> &mut Context { + self.infer.ctx + } fn reify_inner(&mut self, var: TyVar) -> TyId { if let Some(ty) = self.ty_cache.get(&var) { @@ -2659,15 +3363,18 @@ impl<'a> Checked<'a> { TyInfo::Error(reason) => Ty::Error(reason), TyInfo::Prim(prim) => Ty::Prim(prim), TyInfo::List(item) => Ty::List(self.reify_inner(item)), - TyInfo::Record(fields, is_tuple) => Ty::Record(fields - .into_iter() - .map(|(name, field)| (name, self.reify_inner(field))) - .collect(), is_tuple), + TyInfo::Record(fields, is_tuple) => Ty::Record( + fields + .into_iter() + .map(|(name, field)| (name, self.reify_inner(field))) + .collect(), + is_tuple, + ), TyInfo::Func(i, o) => Ty::Func(self.reify_inner(i), self.reify_inner(o)), - TyInfo::Data(data, args) => Ty::Data(data, args - .into_iter() - .map(|arg| self.reify_inner(arg)) - .collect()), + TyInfo::Data(data, args) => Ty::Data( + data, + args.into_iter().map(|arg| self.reify_inner(arg)).collect(), + ), TyInfo::Gen(name, scope, _) => Ty::Gen(name, scope), TyInfo::SelfType => Ty::SelfType, TyInfo::Assoc(inner, class, assoc) => match self.infer.follow_class(class) { @@ -2677,10 +3384,7 @@ impl<'a> Checked<'a> { self.reify_inner(inner), ( class_id, - gen_tys - .into_iter() - .map(|ty| self.reify_inner(ty)) - .collect(), + gen_tys.into_iter().map(|ty| self.reify_inner(ty)).collect(), gen_effs .into_iter() .map(|eff| self.reify_effect(eff)) @@ -2708,12 +3412,12 @@ impl<'a> Checked<'a> { match self.infer.follow_effect_inst(var) { EffectInstInfo::Unknown => Err(()), EffectInstInfo::Error => Err(()), - EffectInstInfo::Ref(x) => return self.reify_effect_inst(x), + EffectInstInfo::Ref(x) => self.reify_effect_inst(x), EffectInstInfo::Gen(idx, gen_scope) => Ok(EffectInst::Gen(idx, gen_scope)), - EffectInstInfo::Known(eff, args) => Ok(EffectInst::Concrete(eff, args - .into_iter() - .map(|arg| self.reify_inner(arg)) - .collect())), + EffectInstInfo::Known(eff, args) => Ok(EffectInst::Concrete( + eff, + args.into_iter().map(|arg| self.reify_inner(arg)).collect(), + )), } } @@ -2725,18 +3429,31 @@ impl<'a> Checked<'a> { let sort_and_order = |this: &mut Self, effs: &mut Vec<_>| { // Sort effects into a canonical order so we can compare them easily later effs.sort_by(|x, y| match (x, y) { - (Ok(EffectInst::Concrete(x, x_params)), Ok(EffectInst::Concrete(y, y_params))) => x.cmp(y).then_with(|| x_params - .iter() - .zip(y_params) - .fold(Ordering::Equal, |a, (x, y)| a.then_with(|| this.infer.ctx().tys.cmp_ty(*x, *y)))), + ( + Ok(EffectInst::Concrete(x, x_params)), + Ok(EffectInst::Concrete(y, y_params)), + ) => x.cmp(y).then_with(|| { + x_params + .iter() + .zip(y_params) + .fold(Ordering::Equal, |a, (x, y)| { + a.then_with(|| this.infer.ctx().tys.cmp_ty(*x, *y)) + }) + }), (Ok(EffectInst::Gen(x, _)), Ok(EffectInst::Gen(y, _))) => x.cmp(y), (_, _) => Ordering::Equal, }); effs.dedup_by(|x, y| match (x, y) { - (Ok(EffectInst::Concrete(x, x_params)), Ok(EffectInst::Concrete(y, y_params))) => x == y && x_params - .iter() - .zip(y_params) - .all(|(x, y)| this.infer.ctx().tys.cmp_ty(*x, *y).is_eq()), + ( + Ok(EffectInst::Concrete(x, x_params)), + Ok(EffectInst::Concrete(y, y_params)), + ) => { + x == y + && x_params + .iter() + .zip(y_params) + .all(|(x, y)| this.infer.ctx().tys.cmp_ty(*x, *y).is_eq()) + } (Ok(EffectInst::Gen(x, _)), Ok(EffectInst::Gen(y, _))) => x == y, _ => false, }); @@ -2744,7 +3461,9 @@ impl<'a> Checked<'a> { let eff = match self.infer.follow_effect(var) { EffectInfo::Ref(_) => unreachable!(), - EffectInfo::Open(effs) | EffectInfo::Closed(effs, None) if effs.is_empty() => return None, + EffectInfo::Open(effs) | EffectInfo::Closed(effs, None) if effs.is_empty() => { + return None + } EffectInfo::Open(effs) | EffectInfo::Closed(effs, None) => { let mut effs = effs .into_iter() @@ -2752,7 +3471,7 @@ impl<'a> Checked<'a> { .collect::>(); sort_and_order(self, &mut effs); Effect::Known(effs) - }, + } EffectInfo::Closed(effs, Some(opener)) => { let opener = self.infer.collect_eff_insts(opener); let mut effs = effs @@ -2761,29 +3480,32 @@ impl<'a> Checked<'a> { .map(|eff| self.reify_effect_inst(eff)) .collect::>(); if effs.is_empty() { - return None + return None; } else { sort_and_order(self, &mut effs); Effect::Known(effs) } - }, + } }; - self.infer.ctx.tys.insert_effect(self.infer.effect_span(var), eff) + self.infer + .ctx + .tys + .insert_effect(self.infer.effect_span(var), eff) }; self.eff_cache.insert(var, eff); Some(eff) } - pub fn reify_class(&mut self, class: ClassVar) -> Option<(ClassId, Vec, Vec>)> { + pub fn reify_class( + &mut self, + class: ClassVar, + ) -> Option<(ClassId, Vec, Vec>)> { match self.infer.follow_class(class) { ClassInfo::Unknown => None, ClassInfo::Ref(_) => unreachable!(), ClassInfo::Known(class_id, gen_tys, gen_effs) => Some(( class_id, - gen_tys - .into_iter() - .map(|ty| self.reify_inner(ty)) - .collect(), + gen_tys.into_iter().map(|ty| self.reify_inner(ty)).collect(), gen_effs .into_iter() .map(|eff| self.reify_effect(eff)) diff --git a/analysis/src/lib.rs b/analysis/src/lib.rs index d744314..626f021 100644 --- a/analysis/src/lib.rs +++ b/analysis/src/lib.rs @@ -1,4 +1,7 @@ -#![feature(arbitrary_self_types, option_zip, never_type, let_else, let_chains)] +#![feature(arbitrary_self_types, option_zip, never_type, let_chains)] + +#![allow(clippy::result_unit_err)] +#![allow(clippy::type_complexity)] pub mod class; pub mod concrete; @@ -10,41 +13,41 @@ pub mod def; pub mod effect; pub mod error; pub mod exhaustivity; -pub mod infer; pub mod hir; +pub mod infer; pub mod lower; pub mod reify; pub mod ty; pub use crate::{ - class::{ClassId, Class, Classes, ClassAssoc, ClassField, Member, MemberId, MemberItem}, - concrete::{ConContext, ConTyId, ConTy, ConNode, ConMeta, ConProc, ConProcId, ConDataId, ConEffectId}, + class::{Class, ClassAssoc, ClassField, ClassId, Classes, Member, MemberId, MemberItem}, + concrete::{ + ConContext, ConDataId, ConEffectId, ConMeta, ConNode, ConProc, ConProcId, ConTy, ConTyId, + }, context::Context, - data::{Datas, Data, DataId, Alias, AliasId}, - def::{Defs, Def, DefId}, - effect::{Effects, EffectDecl, EffectDeclId, EffectAlias, EffectAliasId}, + data::{Alias, AliasId, Data, DataId, Datas}, + def::{Def, DefId, Defs}, + effect::{EffectAlias, EffectAliasId, EffectDecl, EffectDeclId, Effects}, error::Error, exhaustivity::{exhaustivity, ExamplePat}, - hir::{InferExpr, InferBinding, TyExpr, TyBinding, ConBinding, ConExpr, Intrinsic, Meta}, - infer::{Infer, Checked, TyVar, TyInfo, InferNode, InferMeta, InferError, EqInfo, ClassVar, ClassInfo, EffectVar, EffectInfo, EffectInstInfo, EffectInstVar, covariant, contravariant, invariant}, + hir::{ConBinding, ConExpr, InferBinding, InferExpr, Intrinsic, Meta, TyBinding, TyExpr}, + infer::{ + contravariant, covariant, invariant, Checked, ClassInfo, ClassVar, EffectInfo, + EffectInstInfo, EffectInstVar, EffectVar, EqInfo, Infer, InferError, InferMeta, InferNode, + TyInfo, TyVar, + }, lower::{Scope, ToHir, TypeLowerCfg}, reify::Reify, - ty::{Types, TyId, GenScope, GenScopeId, Prim, Ty, TyNode, TyMeta, ErrorReason, ImpliedMember, TyImpliedMember, InferImpliedMember, ImpliedItems, InferImpliedItems, Effect, EffectId, EffectInst}, + ty::{ + Effect, EffectId, EffectInst, ErrorReason, GenScope, GenScopeId, ImpliedItems, + ImpliedMember, InferImpliedItems, InferImpliedMember, Prim, Ty, TyId, TyImpliedMember, + TyMeta, TyNode, Types, + }, }; pub use tao_syntax::ast::Ident; pub use tao_util::index::{Id, Index}; -use tao_syntax::{ - Node, - Span, - SrcNode, - SrcId, - ast, -}; use hashbrown::{HashMap, HashSet}; use internment::Intern; -use std::{ - fmt, - marker::PhantomData, - collections::BTreeMap, -}; +use std::{collections::BTreeMap, fmt}; +use tao_syntax::{ast, Node, Span, SrcId, SrcNode}; diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index a962c44..009f258 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -5,7 +5,7 @@ fn litr_ty_info(litr: &ast::Literal, infer: &mut Infer, span: Span) -> TyInfo { match litr { ast::Literal::Nat(_) => TyInfo::Prim(Prim::Nat), ast::Literal::Int(_) => TyInfo::Prim(Prim::Int), - ast::Literal::Real(x) => TyInfo::Prim(Prim::Real), + ast::Literal::Real(_x) => TyInfo::Prim(Prim::Real), ast::Literal::Char(_) => TyInfo::Prim(Prim::Char), ast::Literal::Str(_) => TyInfo::List(infer.insert(span, TyInfo::Prim(Prim::Char))), } @@ -13,7 +13,13 @@ fn litr_ty_info(litr: &ast::Literal, infer: &mut Infer, span: Span) -> TyInfo { pub enum Scope<'a> { Empty, - Recursive(SrcNode, TyVar, DefId, Vec<(Span, TyVar)>, Vec), + Recursive( + SrcNode, + TyVar, + DefId, + Vec<(Span, TyVar)>, + Vec, + ), Binding(&'a Scope<'a>, SrcNode, TyVar), Many(&'a Scope<'a>, &'a [(SrcNode, TyVar)]), // `None` is no basin, i.e: in a function @@ -21,40 +27,47 @@ pub enum Scope<'a> { } impl<'a> Scope<'a> { - pub fn empty() -> Self { Self::Empty } - - fn with(&self, name: SrcNode, ty: TyVar) -> Scope<'_> { - Scope::Binding(self, name, ty) + pub fn empty() -> Self { + Self::Empty } fn with_many<'b>(&'b self, many: &'b [(SrcNode, TyVar)]) -> Scope<'b> { Scope::Many(self, many) } - fn with_basin<'b>(&'b self, eff: EffectVar) -> Scope<'b> { + fn with_basin(&self, eff: EffectVar) -> Scope { Scope::Basin(self, Some(eff)) } - fn without_basin<'b>(&'b self) -> Scope<'b> { - Scope::Basin(self, None) - } // bool = is_local - fn find(&self, infer: &mut Infer, span: Span, name: &Ident) -> Option<(TyVar, Option<(DefId, Vec<(Span, TyVar)>, Vec)>)> { + fn find( + &self, + infer: &mut Infer, + span: Span, + name: &Ident, + ) -> Option<(TyVar, Option<(DefId, Vec<(Span, TyVar)>, Vec)>)> { match self { Self::Empty => None, - Self::Recursive(def, ty, def_id, tys, effs) => if &**def == name { - Some((infer.reinstantiate(span, *ty), Some((*def_id, tys.clone(), effs.clone())))) - } else { - None - }, + Self::Recursive(def, ty, def_id, tys, effs) => { + if &**def == name { + Some(( + infer.reinstantiate(span, *ty), + Some((*def_id, tys.clone(), effs.clone())), + )) + } else { + None + } + } Self::Binding(_, local, ty) if &**local == name => Some((*ty, None)), Self::Binding(parent, _, _) => parent.find(infer, span, name), - Self::Many(parent, locals) => if let Some((_, ty)) = locals.iter().find(|(local, _)| &**local == name) { - Some((*ty, None)) - } else { - parent.find(infer, span, name) - }, + Self::Many(parent, locals) => { + if let Some((_, ty)) = locals.iter().find(|(local, _)| &**local == name) { + Some((*ty, None)) + } else { + parent.find(infer, span, name) + } + } Self::Basin(parent, _) => parent.find(infer, span, name), } } @@ -74,7 +87,12 @@ pub trait ToHir: Sized { type Cfg; type Output; - fn to_hir(self: &SrcNode, cfg: &Self::Cfg, infer: &mut Infer, scope: &Scope) -> InferNode; + fn to_hir( + self: &SrcNode, + cfg: &Self::Cfg, + infer: &mut Infer, + scope: &Scope, + ) -> InferNode; } // Enforce the obligations of a kind's generics @@ -95,7 +113,7 @@ pub fn enforce_generic_obligations( let err = Error::WrongNumberOfGenerics( use_span, gen_tys.len(), - if gen_scope.len() == 0 { + if gen_scope.is_empty() { item_span } else { gen_scope.get(0).name.span() @@ -105,7 +123,12 @@ pub fn enforce_generic_obligations( infer.ctx_mut().emit(err); Err(()) } else { - for member in gen_scope.implied_members.as_ref().expect("Implied members must be available").clone() { + for member in gen_scope + .implied_members + .as_ref() + .expect("Implied members must be available") + .clone() + { let member_ty = infer.instantiate( *member.member, member.member.span(), @@ -114,47 +137,70 @@ pub fn enforce_generic_obligations( self_ty, invariant(), ); - let member_gen_tys = member.gen_tys - .iter() - .map(|ty| infer.instantiate( - *ty, - member.member.span(), - &mut |idx, _, _| gen_tys.get(idx).copied(), - &mut |idx, _| gen_effs.get(idx).copied(), - self_ty, - invariant(), - )) - .collect::>(); - let member_gen_effs = member.gen_effs + let member_gen_tys = member + .gen_tys .iter() - .map(|eff| eff - .and_then(|eff| infer.instantiate_eff( - eff, + .map(|ty| { + infer.instantiate( + *ty, member.member.span(), &mut |idx, _, _| gen_tys.get(idx).copied(), &mut |idx, _| gen_effs.get(idx).copied(), self_ty, invariant(), - ).ok()) + ) + }) + .collect::>(); + let member_gen_effs = member + .gen_effs + .iter() + .map(|eff| { + eff.and_then(|eff| { + infer + .instantiate_eff( + eff, + member.member.span(), + &mut |idx, _, _| gen_tys.get(idx).copied(), + &mut |idx, _| gen_effs.get(idx).copied(), + self_ty, + invariant(), + ) + .ok() + }) .flatten() // Is it correct to use a free effect variable on error? Probably... // TODO: This might need to be a closed set, not all other cases are actually errors! - .unwrap_or_else(|| infer.insert_effect(member.member.span(), EffectInfo::free()))) + .unwrap_or_else(|| { + infer.insert_effect(member.member.span(), EffectInfo::free()) + }) + }) .collect::>(); let assoc = match &member.items { - ImpliedItems::Eq(assoc) => assoc.iter() - .map(|(name, assoc)| (name.clone(), infer.instantiate( - *assoc, - member.member.span(), - &mut |idx, _, _| gen_tys.get(idx).copied(), - &mut |idx, _| gen_effs.get(idx).copied(), - self_ty, - invariant(), - ))) + ImpliedItems::Eq(assoc) => assoc + .iter() + .map(|(name, assoc)| { + ( + name.clone(), + infer.instantiate( + *assoc, + member.member.span(), + &mut |idx, _, _| gen_tys.get(idx).copied(), + &mut |idx, _| gen_effs.get(idx).copied(), + self_ty, + invariant(), + ), + ) + }) .collect(), ImpliedItems::Real(_) => Vec::new(), }; - infer.make_impl(member_ty, (*member.class, member_gen_tys, member_gen_effs), member.class.span(), assoc, use_span); + infer.make_impl( + member_ty, + (*member.class, member_gen_tys, member_gen_effs), + member.class.span(), + assoc, + use_span, + ); } Ok(()) } @@ -181,7 +227,12 @@ impl TypeLowerCfg { } } -pub fn lower_effect_set(set: &SrcNode, cfg: &TypeLowerCfg, infer: &mut Infer, scope: &Scope) -> EffectVar { +pub fn lower_effect_set( + set: &SrcNode, + cfg: &TypeLowerCfg, + infer: &mut Infer, + scope: &Scope, +) -> EffectVar { let mut eff_insts = Vec::new(); for (name, gen_tys) in &set.effs { let gen_tys = gen_tys @@ -189,48 +240,68 @@ pub fn lower_effect_set(set: &SrcNode, cfg: &TypeLowerCfg, infer .map(|ty| ty.to_hir(cfg, infer, scope).meta().1) .collect::>(); - if let Some((gen_scope_id, (idx, _))) = infer - .gen_scope() - .and_then(|gen_scope_id| Some((gen_scope_id, infer.ctx().tys.get_gen_scope(gen_scope_id).find_eff(**name)?))) - { - eff_insts.push(infer.insert_effect_inst(name.span(), EffectInstInfo::Gen(idx, gen_scope_id))); + if let Some((gen_scope_id, (idx, _))) = infer.gen_scope().and_then(|gen_scope_id| { + Some(( + gen_scope_id, + infer + .ctx() + .tys + .get_gen_scope(gen_scope_id) + .find_eff(**name)?, + )) + }) { + eff_insts.push( + infer.insert_effect_inst(name.span(), EffectInstInfo::Gen(idx, gen_scope_id)), + ); } else { match infer.ctx().effects.lookup(**name) { Some(Ok(eff_id)) => { let eff = infer.ctx().effects.get_decl(eff_id); let eff_gen_scope = eff.gen_scope; let eff_span = eff.name.span(); - eff_insts.push(match enforce_generic_obligations( - infer, - eff_gen_scope, - &gen_tys, - &[], - set.span(), - eff_span, - None, - ) { - Ok(()) => infer.insert_effect_inst(name.span(), EffectInstInfo::Known(eff_id, gen_tys)), - Err(()) => infer.insert_effect_inst(name.span(), EffectInstInfo::Error), - }); - }, + eff_insts.push( + match enforce_generic_obligations( + infer, + eff_gen_scope, + &gen_tys, + &[], + set.span(), + eff_span, + None, + ) { + Ok(()) => infer.insert_effect_inst( + name.span(), + EffectInstInfo::Known(eff_id, gen_tys), + ), + Err(()) => infer.insert_effect_inst(name.span(), EffectInstInfo::Error), + }, + ); + } Some(Err(eff)) => { - fn build_effect_set(infer: &mut Infer, eff_insts: &mut Vec, eff: EffectAliasId) { + fn build_effect_set( + infer: &mut Infer, + eff_insts: &mut Vec, + eff: EffectAliasId, + ) { match &infer.ctx().effects.get_alias(eff).effects { Some(effs) => { for (name, gen_tys) in effs.clone() { - eff_insts.push(infer.insert_effect_inst(name.span(), EffectInstInfo::Known(*name, Vec::new()))); + eff_insts.push(infer.insert_effect_inst( + name.span(), + EffectInstInfo::Known(*name, Vec::new()), + )); assert_eq!(gen_tys.len(), 0); } - }, + } None => todo!("Effect alias cycle, should generate an error"), } } build_effect_set(infer, &mut eff_insts, eff); - }, + } None => { infer.ctx_mut().emit(Error::NoSuchEffect(name.clone())); eff_insts.push(infer.insert_effect_inst(name.span(), EffectInstInfo::Error)); - }, + } } } } @@ -241,27 +312,42 @@ impl ToHir for ast::Type { type Cfg = TypeLowerCfg; type Output = (); - fn to_hir(self: &SrcNode, cfg: &Self::Cfg, infer: &mut Infer, scope: &Scope) -> InferNode<()> { + fn to_hir( + self: &SrcNode, + cfg: &Self::Cfg, + infer: &mut Infer, + scope: &Scope, + ) -> InferNode<()> { let info = match &**self { ast::Type::Error => TyInfo::Error(ErrorReason::Unknown), ast::Type::Unknown => TyInfo::Unknown(None), ast::Type::Universe => TyInfo::Prim(Prim::Universe), ast::Type::List(item) => TyInfo::List(item.to_hir(cfg, infer, scope).meta().1), - ast::Type::Tuple(items) => TyInfo::tuple(items - .iter() - .map(|item| item.to_hir(cfg, infer, scope).meta().1)), - ast::Type::Record(fields) => TyInfo::Record(fields - .iter() - .map(|(name, field)| (**name, field.to_hir(cfg, infer, scope).meta().1)) - .collect(), false), - ast::Type::Func(i, o) => TyInfo::Func(i.to_hir(cfg, infer, scope).meta().1, o.to_hir(cfg, infer, scope).meta().1), + ast::Type::Tuple(items) => TyInfo::tuple( + items + .iter() + .map(|item| item.to_hir(cfg, infer, scope).meta().1), + ), + ast::Type::Record(fields) => TyInfo::Record( + fields + .iter() + .map(|(name, field)| (**name, field.to_hir(cfg, infer, scope).meta().1)) + .collect(), + false, + ), + ast::Type::Func(i, o) => TyInfo::Func( + i.to_hir(cfg, infer, scope).meta().1, + o.to_hir(cfg, infer, scope).meta().1, + ), ast::Type::Data(name, gen_tys) => match (name.as_str(), gen_tys.len()) { - ("Self", 0) => if let Some(var) = infer.self_type() { - TyInfo::Ref(var) - } else { - infer.ctx_mut().emit(Error::SelfNotValidHere(name.span())); - TyInfo::Error(ErrorReason::Invalid) - }, + ("Self", 0) => { + if let Some(var) = infer.self_type() { + TyInfo::Ref(var) + } else { + infer.ctx_mut().emit(Error::SelfNotValidHere(name.span())); + TyInfo::Error(ErrorReason::Invalid) + } + } ("Nat", 0) => TyInfo::Prim(Prim::Nat), ("Int", 0) => TyInfo::Prim(Prim::Int), ("Real", 0) => TyInfo::Prim(Prim::Real), @@ -272,22 +358,23 @@ impl ToHir for ast::Type { .map(|ty| ty.to_hir(cfg, infer, scope).meta().1) .collect::>(); - if let Some((scope, (gen_idx, gen_ty))) = infer - .gen_scope() - .and_then(|scope| Some((scope, infer.ctx().tys.get_gen_scope(scope).find(**name)?))) - { + if let Some((scope, (gen_idx, gen_ty))) = infer.gen_scope().and_then(|scope| { + Some((scope, infer.ctx().tys.get_gen_scope(scope).find(**name)?)) + }) { if gen_tys.is_empty() { TyInfo::Gen(gen_idx, scope, gen_ty.name.span()) } else { - infer.ctx_mut().emit(Error::Unsupported(self.span(), "higher kinded types")); + infer + .ctx_mut() + .emit(Error::Unsupported(self.span(), "higher kinded types")); TyInfo::Error(ErrorReason::Invalid) } } else if let Some(alias_id) = infer.ctx().datas.lookup_alias(**name) { if let Some(alias) = infer.ctx().datas.get_alias(alias_id) { - let alias_ty = alias.ty; let alias_gen_scope = alias.gen_scope; - let mut get_gen = |index, scope, infer: &mut Infer| gen_tys.get(index).copied(); + let mut get_gen = + |index, _scope, _infer: &mut Infer| gen_tys.get(index).copied(); let res = enforce_generic_obligations( infer, @@ -300,11 +387,12 @@ impl ToHir for ast::Type { ); match res { Err(()) => { - let alias_gen_scope = infer.ctx().tys.get_gen_scope(alias_gen_scope); + let alias_gen_scope = + infer.ctx().tys.get_gen_scope(alias_gen_scope); let err = Error::WrongNumberOfGenerics( self.span(), gen_tys.len(), - if alias_gen_scope.len() == 0 { + if alias_gen_scope.is_empty() { infer.ctx().datas.get_alias_span(alias_id) } else { alias_gen_scope.get(0).name.span() @@ -313,22 +401,29 @@ impl ToHir for ast::Type { ); infer.ctx_mut().emit(err); TyInfo::Error(ErrorReason::Unknown) - }, + } Ok(()) => TyInfo::Ref(infer.instantiate( alias_ty, self.span(), &mut get_gen, - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), None, invariant(), )), } } else { - let err_ty = infer.insert(self.span(), TyInfo::Error(ErrorReason::Unknown)); + let err_ty = + infer.insert(self.span(), TyInfo::Error(ErrorReason::Unknown)); if cfg.alias_permitted { - infer.emit(InferError::RecursiveAlias(alias_id, err_ty, name.span())); + infer.emit(InferError::RecursiveAlias( + alias_id, + err_ty, + name.span(), + )); } else { - infer.ctx_mut().emit(Error::AliasNotPermitted(alias_id, name.span())); + infer + .ctx_mut() + .emit(Error::AliasNotPermitted(alias_id, name.span())); }; TyInfo::Ref(err_ty) } @@ -345,12 +440,11 @@ impl ToHir for ast::Type { ) { Ok(()) => TyInfo::Data(data_id, gen_tys), Err(()) => { - let data_gen_scope = infer.ctx().tys.get_gen_scope(data_gen_scope); let err = Error::WrongNumberOfGenerics( self.span(), gen_tys.len(), - if data_gen_scope.len() == 0 { + if data_gen_scope.is_empty() { infer.ctx().datas.get_data_span(data_id) } else { data_gen_scope.get(0).name.span() @@ -359,46 +453,65 @@ impl ToHir for ast::Type { ); infer.ctx_mut().emit(err); TyInfo::Error(ErrorReason::Unknown) - }, + } } } else { infer.ctx_mut().emit(Error::NoSuchData(name.clone())); TyInfo::Error(ErrorReason::Invalid) } - }, + } }, - ast::Type::Assoc(inner, class, assoc) => if !cfg.projection_permitted { - infer.ctx_mut().errors.push(Error::AssocNotValidHere(self.span())); - TyInfo::Error(ErrorReason::Invalid) - } else { - let inner = inner.to_hir(cfg, infer, scope); - let assoc_ty = infer.unknown(self.span()); - let class = if let Some(class) = class { - let gen_tys = class.gen_tys - .iter() - .map(|ty| ty.to_hir(cfg, infer, scope).meta().1) - .collect::>(); - let gen_effs = class.gen_effs - .iter() - .map(|ty| todo!("to_hir for effect")) - .collect::>(); - if let Some(class_id) = infer.ctx_mut().classes.lookup(*class.name) { - infer.insert_class(class.span(), ClassInfo::Known(class_id, gen_tys, gen_effs)) + ast::Type::Assoc(inner, class, assoc) => { + if !cfg.projection_permitted { + infer + .ctx_mut() + .errors + .push(Error::AssocNotValidHere(self.span())); + TyInfo::Error(ErrorReason::Invalid) + } else { + let inner = inner.to_hir(cfg, infer, scope); + let assoc_ty = infer.unknown(self.span()); + let class = if let Some(class) = class { + let gen_tys = class + .gen_tys + .iter() + .map(|ty| ty.to_hir(cfg, infer, scope).meta().1) + .collect::>(); + let gen_effs = class + .gen_effs + .iter() + .map(|_ty| todo!("to_hir for effect")) + .collect::>(); + if let Some(class_id) = infer.ctx_mut().classes.lookup(*class.name) { + infer.insert_class( + class.span(), + ClassInfo::Known(class_id, gen_tys, gen_effs), + ) + } else { + infer + .ctx_mut() + .errors + .push(Error::NoSuchClass(class.name.clone())); + infer.class_var_unknown(self.span()) + } } else { - infer.ctx_mut().errors.push(Error::NoSuchClass(class.name.clone())); infer.class_var_unknown(self.span()) - } - } else { - infer.class_var_unknown(self.span()) - }; - infer.make_class_assoc(inner.meta().1, assoc.clone(), class, assoc_ty, self.span()); - TyInfo::Ref(assoc_ty) - }, + }; + infer.make_class_assoc( + inner.meta().1, + assoc.clone(), + class, + assoc_ty, + self.span(), + ); + TyInfo::Ref(assoc_ty) + } + } ast::Type::Effect(set, out) => { let out = out.to_hir(cfg, infer, scope).meta().1; let opaque = infer.opaque(self.span(), true); TyInfo::Effect(lower_effect_set(set, cfg, infer, scope), out, opaque) - }, + } }; InferNode::new((), (self.span(), infer.insert(self.span(), info))) @@ -409,163 +522,207 @@ impl ToHir for ast::Binding { type Cfg = (); type Output = hir::Binding; - fn to_hir(self: &SrcNode, cfg: &Self::Cfg, infer: &mut Infer, scope: &Scope) -> InferNode { + fn to_hir( + self: &SrcNode, + _cfg: &Self::Cfg, + infer: &mut Infer, + scope: &Scope, + ) -> InferNode { let (info, pat) = match &*self.pat { ast::Pat::Error => (TyInfo::Error(ErrorReason::Unknown), hir::Pat::Error), ast::Pat::Wildcard => (TyInfo::Unknown(None), hir::Pat::Wildcard), ast::Pat::Literal(litr) => { let ty_info = litr_ty_info(litr, infer, self.pat.span()); - (TyInfo::Ref(infer.insert(self.span(), ty_info)), match litr { - ast::Literal::Nat(x) => hir::Pat::Literal(ast::Literal::Nat(*x)), - ast::Literal::Int(x) => hir::Pat::Literal(ast::Literal::Int(*x)), - ast::Literal::Real(x) => hir::Pat::Literal(ast::Literal::Real(*x)), - ast::Literal::Char(c) => hir::Pat::Literal(ast::Literal::Char(*c)), - ast::Literal::Str(s) => { - // Bit of a hack, we do this because equality of literals is not supported in the MIR, so a - // string pattern desugars to a list pattern. - let c_ty = infer.insert(self.span(), TyInfo::Prim(Prim::Char)); - hir::Pat::ListExact(s - .chars() - .map(|c| InferNode::new(hir::Binding::from_pat(SrcNode::new(hir::Pat::Literal(ast::Literal::Char(c)), self.span())), (self.span(), c_ty))) - .collect()) + ( + TyInfo::Ref(infer.insert(self.span(), ty_info)), + match litr { + ast::Literal::Nat(x) => hir::Pat::Literal(ast::Literal::Nat(*x)), + ast::Literal::Int(x) => hir::Pat::Literal(ast::Literal::Int(*x)), + ast::Literal::Real(x) => hir::Pat::Literal(ast::Literal::Real(*x)), + ast::Literal::Char(c) => hir::Pat::Literal(ast::Literal::Char(*c)), + ast::Literal::Str(s) => { + // Bit of a hack, we do this because equality of literals is not supported in the MIR, so a + // string pattern desugars to a list pattern. + let c_ty = infer.insert(self.span(), TyInfo::Prim(Prim::Char)); + hir::Pat::ListExact( + s.chars() + .map(|c| { + InferNode::new( + hir::Binding::from_pat(SrcNode::new( + hir::Pat::Literal(ast::Literal::Char(c)), + self.span(), + )), + (self.span(), c_ty), + ) + }) + .collect(), + ) + } }, - }) - }, + ) + } ast::Pat::Single(inner) => { - let binding = inner.to_hir(cfg, infer, scope); + let binding = inner.to_hir(_cfg, infer, scope); // TODO: don't use `Ref` to link types (TyInfo::Ref(binding.meta().1), hir::Pat::Single(binding)) - }, + } ast::Pat::Binary(op, lhs, rhs) => { - let lhs = lhs.to_hir(cfg, infer, scope); + let lhs = lhs.to_hir(_cfg, infer, scope); match (&**rhs, &**op) { (ast::Literal::Nat(rhs_nat), ast::BinaryOp::Add) => { let nat = infer.insert(rhs.span(), TyInfo::Prim(Prim::Nat)); - infer.make_flow(lhs.meta().1, nat, EqInfo::new(self.span(), format!("Only natural numbers support arithmetic patterns"))); - (TyInfo::Ref(nat), hir::Pat::Add(lhs, SrcNode::new(*rhs_nat, rhs.span()))) - }, + infer.make_flow( + lhs.meta().1, + nat, + EqInfo::new( + self.span(), + "Only natural numbers support arithmetic patterns".to_string(), + ), + ); + ( + TyInfo::Ref(nat), + hir::Pat::Add(lhs, SrcNode::new(*rhs_nat, rhs.span())), + ) + } (_, _) => { let ty_info = litr_ty_info(rhs, infer, self.pat.span()); let rhs_ty = infer.insert(rhs.span(), ty_info); - infer.emit(InferError::PatternNotSupported(lhs.meta().1, op.clone(), rhs_ty, self.span())); + infer.emit(InferError::PatternNotSupported( + lhs.meta().1, + op.clone(), + rhs_ty, + self.span(), + )); (TyInfo::Error(ErrorReason::Unknown), hir::Pat::Error) - }, + } } - }, + } ast::Pat::Tuple(items) => { let items = items .iter() - .map(|item| item.to_hir(cfg, infer, scope)) + .map(|item| item.to_hir(_cfg, infer, scope)) .collect::>(); - (TyInfo::tuple(items - .iter() - .map(|item| item.meta().1)), hir::Pat::tuple(items)) - }, + ( + TyInfo::tuple(items.iter().map(|item| item.meta().1)), + hir::Pat::tuple(items), + ) + } ast::Pat::Record(fields) => { let fields = fields .iter() - .map(|(name, field)| (**name, field.to_hir(cfg, infer, scope))) + .map(|(name, field)| (**name, field.to_hir(_cfg, infer, scope))) .collect::>(); - (TyInfo::Record(fields - .iter() - .map(|(name, field)| (*name, field.meta().1)) - .collect(), false), hir::Pat::Record(fields, false)) - }, + ( + TyInfo::Record( + fields + .iter() + .map(|(name, field)| (*name, field.meta().1)) + .collect(), + false, + ), + hir::Pat::Record(fields, false), + ) + } ast::Pat::ListExact(items) => { let item_ty = infer.unknown(self.pat.span()); let items = items .iter() .map(|item| { - let item = item.to_hir(cfg, infer, scope); + let item = item.to_hir(_cfg, infer, scope); infer.make_flow(item.meta().1, item_ty, item.meta().0); item }) .collect::>(); (TyInfo::List(item_ty), hir::Pat::ListExact(items)) - }, + } ast::Pat::ListFront(items, tail) => { let item_ty = infer.unknown(self.pat.span()); let items = items .iter() .map(|item| { - let item = item.to_hir(cfg, infer, scope); + let item = item.to_hir(_cfg, infer, scope); infer.make_flow(item.meta().1, item_ty, item.meta().0); item }) .collect::>(); let tail = tail.as_ref().map(|tail| { - let tail = tail.to_hir(cfg, infer, scope); + let tail = tail.to_hir(_cfg, infer, scope); let ty = infer.insert(tail.meta().0, TyInfo::List(item_ty)); infer.make_flow(tail.meta().1, ty, tail.meta().0); tail }); (TyInfo::List(item_ty), hir::Pat::ListFront(items, tail)) - }, - ast::Pat::Deconstruct(name, inner) => if let Some(data) = infer.ctx().datas.lookup_cons(**name) { - let gen_scope_id = infer.ctx().datas.get_data(data).gen_scope; - let gen_scope = infer.ctx().tys.get_gen_scope(gen_scope_id); - let gen_tys = (0..gen_scope.len()) - .map(|i| gen_scope.get(i).name.span()) - .collect::>(); - let gen_effs = (0..gen_scope.len_eff()) - .map(|i| gen_scope.get_eff(i).name.span()) - .collect::>(); - let gen_tys = gen_tys - .into_iter() - .map(|origin| infer.insert(self.span(), TyInfo::Unknown(Some(origin)))) - .collect::>(); - let gen_effs = gen_effs - .into_iter() - .map(|origin| infer.insert_effect(self.span(), EffectInfo::free())) - .collect::>(); + } + ast::Pat::Deconstruct(name, inner) => { + if let Some(data) = infer.ctx().datas.lookup_cons(**name) { + let gen_scope_id = infer.ctx().datas.get_data(data).gen_scope; + let gen_scope = infer.ctx().tys.get_gen_scope(gen_scope_id); + let gen_tys = (0..gen_scope.len()) + .map(|i| gen_scope.get(i).name.span()) + .collect::>(); + let gen_effs = (0..gen_scope.len_eff()) + .map(|i| gen_scope.get_eff(i).name.span()) + .collect::>(); + let gen_tys = gen_tys + .into_iter() + .map(|origin| infer.insert(self.span(), TyInfo::Unknown(Some(origin)))) + .collect::>(); + let gen_effs = gen_effs + .into_iter() + .map(|_origin| infer.insert_effect(self.span(), EffectInfo::free())) + .collect::>(); - if let Err(()) = enforce_generic_obligations( - infer, - gen_scope_id, - &gen_tys, - &gen_effs, - self.span(), - infer.ctx().datas.get_data_span(data), - None, - ) { - // Only fails if generic count doesn't match, but they're from the same source of truth! - unreachable!(); - } + if let Err(()) = enforce_generic_obligations( + infer, + gen_scope_id, + &gen_tys, + &gen_effs, + self.span(), + infer.ctx().datas.get_data_span(data), + None, + ) { + // Only fails if generic count doesn't match, but they're from the same source of truth! + unreachable!(); + } - let inner_ty = infer - .ctx() - .datas - .get_data(data) - .cons - .iter() - .find(|(cons, _)| **cons == **name) - .unwrap() - .1; + let inner_ty = infer + .ctx() + .datas + .get_data(data) + .cons + .iter() + .find(|(cons, _)| **cons == **name) + .unwrap() + .1; + + // Recreate type in context + let inner_ty = { + let data = infer.ctx().datas.get_data(data); + let _data_gen_scope = data.gen_scope; + + infer.instantiate( + inner_ty, + inner.span(), + &mut |index, _, _infer: &mut Infer| gen_tys.get(index).copied(), + &mut |index, _infer: &mut Infer| gen_effs.get(index).copied(), + None, + invariant(), + ) + }; - // Recreate type in context - let inner_ty = { - let data = infer.ctx().datas.get_data(data); - let data_gen_scope = data.gen_scope; + let inner = inner.to_hir(_cfg, infer, scope); + infer.make_flow(inner_ty, inner.meta().1, self.span()); - infer.instantiate( - inner_ty, - inner.span(), - &mut |index, _, infer: &mut Infer| gen_tys.get(index).copied(), - &mut |index, infer: &mut Infer| gen_effs.get(index).copied(), - None, - invariant(), + ( + TyInfo::Data(data, gen_tys), + hir::Pat::Decons(SrcNode::new(data, self.span()), **name, inner), ) - }; - - let inner = inner.to_hir(cfg, infer, scope); - infer.make_flow(inner_ty, inner.meta().1, self.span()); - - (TyInfo::Data(data, gen_tys), hir::Pat::Decons(SrcNode::new(data, self.span()), **name, inner)) - } else { - infer.ctx_mut().emit(Error::NoSuchCons(name.clone())); - // TODO: Don't use a hard, preserve inner expression - (TyInfo::Error(ErrorReason::Unknown), hir::Pat::Error) - }, + } else { + infer.ctx_mut().emit(Error::NoSuchCons(name.clone())); + // TODO: Don't use a hard, preserve inner expression + (TyInfo::Error(ErrorReason::Unknown), hir::Pat::Error) + } + } }; let ty = infer.insert(self.span(), info); @@ -575,20 +732,32 @@ impl ToHir for ast::Binding { infer.make_flow(ty, hint.meta().1, self.span()); } - InferNode::new(hir::Binding { - pat: SrcNode::new(pat, self.pat.span()), - name: self.name.clone(), - }, (self.span(), ty)) + InferNode::new( + hir::Binding { + pat: SrcNode::new(pat, self.pat.span()), + name: self.name.clone(), + }, + (self.span(), ty), + ) } } -fn instantiate_def(def_id: DefId, span: Span, infer: &mut Infer, span_override: Option, inst_span: Span) -> (TyInfo, hir::Expr) { - let scope = infer.ctx().tys.get_gen_scope(infer.ctx().defs.get(def_id).gen_scope); +fn instantiate_def( + def_id: DefId, + span: Span, + infer: &mut Infer, + span_override: Option, + inst_span: Span, +) -> (TyInfo, hir::Expr) { + let scope = infer + .ctx() + .tys + .get_gen_scope(infer.ctx().defs.get(def_id).gen_scope); let gen_tys = (0..scope.len()) .map(|i| TyInfo::Unknown(Some(scope.get(i).name.span()))) .collect::>(); let gen_effs = (0..scope.len_eff()) - .map(|i| EffectInfo::free()) + .map(|_i| EffectInfo::free()) .collect::>(); let gen_tys = gen_tys .into_iter() @@ -608,18 +777,18 @@ fn instantiate_def(def_id: DefId, span: Span, infer: &mut Infer, span_override: span, infer.ctx().defs.get(def_id).name.span(), None, - ).expect("not possible"); + ) + .expect("not possible"); // Recreate type in context let def = infer.ctx().defs.get(def_id); - let def_gen_scope = def.gen_scope; + let _def_gen_scope = def.gen_scope; let def_name = def.name.clone(); - let mut gen_ty = |index: usize, _, infer: &mut Infer| gen_tys.get(index).map(|(_, ty)| *ty); - let mut gen_eff = |index: usize, infer: &mut Infer| gen_effs.get(index).copied(); - let ty = if let Some(body_ty) = def.ty_hint - .or_else(|| def.body - .as_ref() - .map(|body| body.meta().1)) + let mut gen_ty = |index: usize, _, _infer: &mut Infer| gen_tys.get(index).map(|(_, ty)| *ty); + let mut gen_eff = |index: usize, _infer: &mut Infer| gen_effs.get(index).copied(); + let ty = if let Some(body_ty) = def + .ty_hint + .or_else(|| def.body.as_ref().map(|body| body.meta().1)) { // Bit messy, makes sure that we don't accidentally infer a bad type backwards let def_ty_actual = infer.instantiate( @@ -638,9 +807,16 @@ fn instantiate_def(def_id: DefId, span: Span, infer: &mut Infer, span_override: }; if let Some(ty) = ty { - (TyInfo::Ref(ty), hir::Expr::Global((def_id, gen_tys, gen_effs))) + ( + TyInfo::Ref(ty), + hir::Expr::Global((def_id, gen_tys, gen_effs)), + ) } else { - infer.ctx_mut().emit(Error::DefTypeNotSpecified(SrcNode::new(def_id, def_name.span()), span, *def_name)); + infer.ctx_mut().emit(Error::DefTypeNotSpecified( + SrcNode::new(def_id, def_name.span()), + span, + *def_name, + )); (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) } } @@ -649,37 +825,51 @@ impl ToHir for ast::Expr { type Cfg = (); type Output = hir::Expr; - fn to_hir(self: &SrcNode, cfg: &Self::Cfg, infer: &mut Infer, scope: &Scope) -> InferNode { + fn to_hir( + self: &SrcNode, + _cfg: &Self::Cfg, + infer: &mut Infer, + scope: &Scope, + ) -> InferNode { let mut span = self.span(); let (info, expr) = match &**self { ast::Expr::Error => (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error), ast::Expr::Literal(litr) => { let ty_info = litr_ty_info(litr, infer, span); - (TyInfo::Ref(infer.insert(span, ty_info)), hir::Expr::Literal(*litr)) - }, + ( + TyInfo::Ref(infer.insert(span, ty_info)), + hir::Expr::Literal(*litr), + ) + } ast::Expr::Local(local) => { - if let Some((ty, rec)) = scope.find(infer, self.span(), &local) { + if let Some((ty, rec)) = scope.find(infer, self.span(), local) { if let Some((def_id, gen_tys, gen_effs)) = rec { - (TyInfo::Ref(ty), hir::Expr::Global((def_id, gen_tys, gen_effs))) + ( + TyInfo::Ref(ty), + hir::Expr::Global((def_id, gen_tys, gen_effs)), + ) } else { (TyInfo::Ref(ty), hir::Expr::Local(*local)) } } else if let Some(def_id) = infer.ctx().defs.lookup(*local) { instantiate_def(def_id, self.span(), infer, None, self.span()) } else { - infer.ctx_mut().emit(Error::NoSuchLocal(SrcNode::new(*local, self.span()))); + infer + .ctx_mut() + .emit(Error::NoSuchLocal(SrcNode::new(*local, self.span()))); (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) } - }, + } ast::Expr::Tuple(items) => { let items = items .iter() - .map(|item| item.to_hir(cfg, infer, scope)) + .map(|item| item.to_hir(_cfg, infer, scope)) .collect::>(); - (TyInfo::tuple(items - .iter() - .map(|item| item.meta().1)), hir::Expr::tuple(items)) - }, + ( + TyInfo::tuple(items.iter().map(|item| item.meta().1)), + hir::Expr::tuple(items), + ) + } ast::Expr::List(items, tails) => { let item_ty = infer.unknown(self.span()); let list_ty = infer.insert(self.span(), TyInfo::List(item_ty)); @@ -687,7 +877,7 @@ impl ToHir for ast::Expr { let items = items .iter() .map(|item| { - let item = item.to_hir(cfg, infer, scope); + let item = item.to_hir(_cfg, infer, scope); infer.make_flow(item.meta().1, item_ty, item.meta().0); item }) @@ -696,85 +886,176 @@ impl ToHir for ast::Expr { let tails = tails .iter() .map(|tail| { - let tail = tail.to_hir(cfg, infer, scope); + let tail = tail.to_hir(_cfg, infer, scope); infer.make_flow(tail.meta().1, list_ty, tail.meta().0); tail }) .collect(); (TyInfo::Ref(list_ty), hir::Expr::List(items, tails)) - }, + } ast::Expr::Record(fields) => { let fields = fields .iter() - .map(|(name, field)| (name.clone(), field.to_hir(cfg, infer, scope))) + .map(|(name, field)| (name.clone(), field.to_hir(_cfg, infer, scope))) .collect::>(); let tys = fields .iter() .map(|(name, field)| (**name, field.meta().1)) .collect(); (TyInfo::Record(tys, false), hir::Expr::Record(fields, false)) - }, + } ast::Expr::Access(record, field) => { - let record = record.to_hir(cfg, infer, scope); + let record = record.to_hir(_cfg, infer, scope); let field_ty = infer.unknown(self.span()); infer.make_access(record.meta().1, field.clone(), field_ty); // TODO: don't use `Ref` to link types - (TyInfo::Ref(field_ty), hir::Expr::Access(record, field.clone())) - }, - ast::Expr::Unary(op, a) => if let ast::UnaryOp::Propagate = &**op { - let a = a.to_hir(cfg, infer, scope); - let out_ty = infer.unknown(self.span()); - - let basin_eff = if let Some(basin_eff) = scope.last_basin() { - basin_eff - } else { - infer.ctx_mut().errors.push(Error::NoBasin(op.span())); - infer.insert_effect(a.meta().0, EffectInfo::free()) // TODO: EffectInfo::Error instead - }; - - infer.make_effect_propagate(a.meta().1, basin_eff, out_ty, a.meta().0, op.span(), self.span()); - - (TyInfo::Ref(out_ty), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::Propagate, op.span()), vec![a])) - } else { - let a = a.to_hir(cfg, infer, scope); - let output_ty = infer.unknown(self.span()); - - let func = infer.insert(op.span(), TyInfo::Func(a.meta().1, output_ty)); - - let (class_id, field) = match &**op { - ast::UnaryOp::Not => (infer.ctx().classes.lang.not, SrcNode::new(Ident::new("not"), self.span())), - ast::UnaryOp::Neg => (infer.ctx().classes.lang.neg, SrcNode::new(Ident::new("neg"), self.span())), - ast::UnaryOp::Propagate => unreachable!(), // handled above - }; + ( + TyInfo::Ref(field_ty), + hir::Expr::Access(record, field.clone()), + ) + } + ast::Expr::Unary(op, a) => { + if let ast::UnaryOp::Propagate = &**op { + let a = a.to_hir(_cfg, infer, scope); + let out_ty = infer.unknown(self.span()); - if let Some(class_id) = class_id { - let class = infer.make_class_field_known(a.meta().1, field.clone(), (class_id, Vec::new(), Vec::new()), func, self.span()); + let basin_eff = if let Some(basin_eff) = scope.last_basin() { + basin_eff + } else { + infer.ctx_mut().errors.push(Error::NoBasin(op.span())); + infer.insert_effect(a.meta().0, EffectInfo::free()) // TODO: EffectInfo::Error instead + }; + + infer.make_effect_propagate( + a.meta().1, + basin_eff, + out_ty, + a.meta().0, + op.span(), + self.span(), + ); - (TyInfo::Ref(output_ty), hir::Expr::Apply(InferNode::new(hir::Expr::ClassAccess(*a.meta(), class, field), (op.span(), func)), a)) + ( + TyInfo::Ref(out_ty), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::Propagate, op.span()), + vec![a], + ), + ) } else { - (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) + let a = a.to_hir(_cfg, infer, scope); + let output_ty = infer.unknown(self.span()); + + let func = infer.insert(op.span(), TyInfo::Func(a.meta().1, output_ty)); + + let (class_id, field) = match &**op { + ast::UnaryOp::Not => ( + infer.ctx().classes.lang.not, + SrcNode::new(Ident::new("not"), self.span()), + ), + ast::UnaryOp::Neg => ( + infer.ctx().classes.lang.neg, + SrcNode::new(Ident::new("neg"), self.span()), + ), + ast::UnaryOp::Propagate => unreachable!(), // handled above + }; + + if let Some(class_id) = class_id { + let class = infer.make_class_field_known( + a.meta().1, + field.clone(), + (class_id, Vec::new(), Vec::new()), + func, + self.span(), + ); + + ( + TyInfo::Ref(output_ty), + hir::Expr::Apply( + InferNode::new( + hir::Expr::ClassAccess(*a.meta(), class, field), + (op.span(), func), + ), + a, + ), + ) + } else { + (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) + } } - }, + } ast::Expr::Binary(op, a, b) => { - let a = a.to_hir(cfg, infer, scope); - let b = b.to_hir(cfg, infer, scope); + let a = a.to_hir(_cfg, infer, scope); + let b = b.to_hir(_cfg, infer, scope); let output_ty = infer.unknown(self.span()); let (class_id, field, class_gen_tys) = match &**op { - ast::BinaryOp::Eq => (infer.ctx().classes.lang.eq, SrcNode::new(Ident::new("eq"), self.span()), vec![]), - ast::BinaryOp::NotEq => (infer.ctx().classes.lang.eq, SrcNode::new(Ident::new("ne"), self.span()), vec![]), - ast::BinaryOp::Add => (infer.ctx().classes.lang.add, SrcNode::new(Ident::new("add"), self.span()), vec![b.meta().1]), - ast::BinaryOp::Sub => (infer.ctx().classes.lang.sub, SrcNode::new(Ident::new("sub"), self.span()), vec![b.meta().1]), - ast::BinaryOp::Mul => (infer.ctx().classes.lang.mul, SrcNode::new(Ident::new("mul"), self.span()), vec![b.meta().1]), - ast::BinaryOp::Div => (infer.ctx().classes.lang.div, SrcNode::new(Ident::new("div"), self.span()), vec![b.meta().1]), - ast::BinaryOp::Less => (infer.ctx().classes.lang.ord_ext, SrcNode::new(Ident::new("less"), self.span()), vec![]), - ast::BinaryOp::LessEq => (infer.ctx().classes.lang.ord_ext, SrcNode::new(Ident::new("less_eq"), self.span()), vec![]), - ast::BinaryOp::More => (infer.ctx().classes.lang.ord_ext, SrcNode::new(Ident::new("more"), self.span()), vec![]), - ast::BinaryOp::MoreEq => (infer.ctx().classes.lang.ord_ext, SrcNode::new(Ident::new("more_eq"), self.span()), vec![]), - ast::BinaryOp::And => (infer.ctx().classes.lang.and, SrcNode::new(Ident::new("and_"), self.span()), vec![b.meta().1]), - ast::BinaryOp::Or => (infer.ctx().classes.lang.or, SrcNode::new(Ident::new("or_"), self.span()), vec![b.meta().1]), - ast::BinaryOp::Join => (infer.ctx().classes.lang.join, SrcNode::new(Ident::new("join"), self.span()), vec![b.meta().1]), + ast::BinaryOp::Eq => ( + infer.ctx().classes.lang.eq, + SrcNode::new(Ident::new("eq"), self.span()), + vec![], + ), + ast::BinaryOp::NotEq => ( + infer.ctx().classes.lang.eq, + SrcNode::new(Ident::new("ne"), self.span()), + vec![], + ), + ast::BinaryOp::Add => ( + infer.ctx().classes.lang.add, + SrcNode::new(Ident::new("add"), self.span()), + vec![b.meta().1], + ), + ast::BinaryOp::Sub => ( + infer.ctx().classes.lang.sub, + SrcNode::new(Ident::new("sub"), self.span()), + vec![b.meta().1], + ), + ast::BinaryOp::Mul => ( + infer.ctx().classes.lang.mul, + SrcNode::new(Ident::new("mul"), self.span()), + vec![b.meta().1], + ), + ast::BinaryOp::Div => ( + infer.ctx().classes.lang.div, + SrcNode::new(Ident::new("div"), self.span()), + vec![b.meta().1], + ), + ast::BinaryOp::Less => ( + infer.ctx().classes.lang.ord_ext, + SrcNode::new(Ident::new("less"), self.span()), + vec![], + ), + ast::BinaryOp::LessEq => ( + infer.ctx().classes.lang.ord_ext, + SrcNode::new(Ident::new("less_eq"), self.span()), + vec![], + ), + ast::BinaryOp::More => ( + infer.ctx().classes.lang.ord_ext, + SrcNode::new(Ident::new("more"), self.span()), + vec![], + ), + ast::BinaryOp::MoreEq => ( + infer.ctx().classes.lang.ord_ext, + SrcNode::new(Ident::new("more_eq"), self.span()), + vec![], + ), + ast::BinaryOp::And => ( + infer.ctx().classes.lang.and, + SrcNode::new(Ident::new("and_"), self.span()), + vec![b.meta().1], + ), + ast::BinaryOp::Or => ( + infer.ctx().classes.lang.or, + SrcNode::new(Ident::new("or_"), self.span()), + vec![b.meta().1], + ), + ast::BinaryOp::Join => ( + infer.ctx().classes.lang.join, + SrcNode::new(Ident::new("join"), self.span()), + vec![b.meta().1], + ), op => todo!("Implement binary op {:?}", op), }; @@ -785,13 +1066,25 @@ impl ToHir for ast::Expr { //infer.make_flow(b.meta().1, a.meta().1, EqInfo::from(self.span())); // TODO: Pass second arg to class - let class = infer.make_class_field_known(a.meta().1, field.clone(), (class_id, class_gen_tys, Vec::new()), func, self.span()); + let class = infer.make_class_field_known( + a.meta().1, + field.clone(), + (class_id, class_gen_tys, Vec::new()), + func, + self.span(), + ); let expr = hir::Expr::Apply( - InferNode::new(hir::Expr::Apply( - InferNode::new(hir::Expr::ClassAccess(*a.meta(), class, field), (op.span(), func)), - a, - ), (self.span(), func)), + InferNode::new( + hir::Expr::Apply( + InferNode::new( + hir::Expr::ClassAccess(*a.meta(), class, field), + (op.span(), func), + ), + a, + ), + (self.span(), func), + ), b, ); @@ -799,11 +1092,13 @@ impl ToHir for ast::Expr { } else { (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) } - }, + } ast::Expr::Let(bindings, then) => { fn fold<'a>( then: &SrcNode, - bindings: &'a mut impl Iterator, SrcNode)>, + bindings: &'a mut impl Iterator< + Item = &'a (SrcNode, SrcNode), + >, cfg: &::Cfg, infer: &mut Infer, scope: &Scope, @@ -813,28 +1108,38 @@ impl ToHir for ast::Expr { let binding = binding.to_hir(cfg, infer, scope); let val = val.to_hir(cfg, infer, scope); infer.make_flow(val.meta().1, binding.meta().1, val.meta().0); - let then = fold(then, bindings, cfg, infer, &scope.with_many(&binding.get_binding_tys())); + let then = fold( + then, + bindings, + cfg, + infer, + &scope.with_many(&binding.get_binding_tys()), + ); let span = binding.meta().0; let ty = then.meta().1; // TODO: Make a TyInfo::Ref? - InferNode::new(hir::Expr::Match( - false, - val, - vec![(binding, then)], - ), (span, ty)) - }, + InferNode::new( + hir::Expr::Match(false, val, vec![(binding, then)]), + (span, ty), + ) + } None => then.to_hir(cfg, infer, scope), } } - let expr = fold(then, &mut bindings.iter(), cfg, infer, scope); + let expr = fold(then, &mut bindings.iter(), _cfg, infer, scope); span = expr.meta().0; (TyInfo::Ref(expr.meta().1), expr.into_inner()) - }, + } ast::Expr::Match(preds, arms) => { let mut is_err = false; for arm in arms { if arm.0.len() != preds.len() { - infer.ctx_mut().emit(Error::WrongNumberOfParams(arm.0.span(), arm.0.len(), preds.span(), preds.len())); + infer.ctx_mut().emit(Error::WrongNumberOfParams( + arm.0.span(), + arm.0.len(), + preds.span(), + preds.len(), + )); is_err = true; } } @@ -842,42 +1147,105 @@ impl ToHir for ast::Expr { if is_err { (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) } else { - let pred = tupleify_expr(preds, cfg, infer, scope); + let pred = tupleify_expr(preds, _cfg, infer, scope); let output_ty = infer.unknown(self.span()); let arms = arms .iter() .map(|(bindings, body)| { - let binding = tupleify_binding(bindings, cfg, infer, scope); + let binding = tupleify_binding(bindings, _cfg, infer, scope); infer.make_flow(pred.meta().1, binding.meta().1, binding.meta().0); - let body = body.to_hir(cfg, infer, &scope.with_many(&binding.get_binding_tys())); - infer.make_flow(body.meta().1, output_ty, EqInfo::new(self.span(), format!("Branches must produce compatible values"))); + let body = body.to_hir( + _cfg, + infer, + &scope.with_many(&binding.get_binding_tys()), + ); + infer.make_flow( + body.meta().1, + output_ty, + EqInfo::new( + self.span(), + "Branches must produce compatible values".to_string(), + ), + ); (binding, body) }) .collect(); (TyInfo::Ref(output_ty), hir::Expr::Match(true, pred, arms)) } - }, - ast::Expr::If(pred, a, b) => if let Some(bool_data) = infer.ctx().datas.lang.r#bool { - let pred_ty = infer.insert(pred.span(), TyInfo::Data(bool_data, Vec::new())); - let output_ty = infer.unknown(self.span()); - let pred = pred.to_hir(cfg, infer, scope); - infer.make_flow(pred.meta().1, pred_ty, EqInfo::new(self.span(), format!("Conditions must be booleans"))); - let a = a.to_hir(cfg, infer, scope); - let b = b.to_hir(cfg, infer, scope); - infer.make_flow(a.meta().1, output_ty, EqInfo::new(self.span(), format!("Branches must produce compatible values"))); - infer.make_flow(b.meta().1, output_ty, EqInfo::new(self.span(), format!("Branches must produce compatible values"))); - let unit = InferNode::new(hir::Binding::unit(pred.meta().0), (pred.meta().0, infer.insert(pred.meta().0, TyInfo::tuple(Vec::new())))); - let arms = vec![ - (InferNode::new(hir::Binding::from_pat(SrcNode::new(hir::Pat::Decons(SrcNode::new(bool_data, pred.meta().0), Ident::new("True"), unit.clone()), pred.meta().0)), *pred.meta()), a), - (InferNode::new(hir::Binding::from_pat(SrcNode::new(hir::Pat::Decons(SrcNode::new(bool_data, pred.meta().0), Ident::new("False"), unit), pred.meta().0)), *pred.meta()), b), - ]; - (TyInfo::Ref(output_ty), hir::Expr::Match(false, pred, arms)) - } else { - (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) - }, + } + ast::Expr::If(pred, a, b) => { + if let Some(bool_data) = infer.ctx().datas.lang.r#bool { + let pred_ty = infer.insert(pred.span(), TyInfo::Data(bool_data, Vec::new())); + let output_ty = infer.unknown(self.span()); + let pred = pred.to_hir(_cfg, infer, scope); + infer.make_flow( + pred.meta().1, + pred_ty, + EqInfo::new(self.span(), "Conditions must be booleans".to_string()), + ); + let a = a.to_hir(_cfg, infer, scope); + let b = b.to_hir(_cfg, infer, scope); + infer.make_flow( + a.meta().1, + output_ty, + EqInfo::new( + self.span(), + "Branches must produce compatible values".to_string(), + ), + ); + infer.make_flow( + b.meta().1, + output_ty, + EqInfo::new( + self.span(), + "Branches must produce compatible values".to_string(), + ), + ); + let unit = InferNode::new( + hir::Binding::unit(pred.meta().0), + ( + pred.meta().0, + infer.insert(pred.meta().0, TyInfo::tuple(Vec::new())), + ), + ); + let arms = vec![ + ( + InferNode::new( + hir::Binding::from_pat(SrcNode::new( + hir::Pat::Decons( + SrcNode::new(bool_data, pred.meta().0), + Ident::new("True"), + unit.clone(), + ), + pred.meta().0, + )), + *pred.meta(), + ), + a, + ), + ( + InferNode::new( + hir::Binding::from_pat(SrcNode::new( + hir::Pat::Decons( + SrcNode::new(bool_data, pred.meta().0), + Ident::new("False"), + unit, + ), + pred.meta().0, + )), + *pred.meta(), + ), + b, + ), + ]; + (TyInfo::Ref(output_ty), hir::Expr::Match(false, pred, arms)) + } else { + (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) + } + } ast::Expr::Func(arms) => { // Effects cannot be propagated from function bodies to their environment // let scope = &scope.without_basin(); @@ -891,7 +1259,12 @@ impl ToHir for ast::Expr { let mut is_err = false; for arm in arms.iter() { if arm.0.len() != first_arm.0.len() { - infer.ctx_mut().emit(Error::WrongNumberOfParams(arm.0.span(), arm.0.len(), first_arm.0.span(), first_arm.0.len())); + infer.ctx_mut().emit(Error::WrongNumberOfParams( + arm.0.span(), + arm.0.len(), + first_arm.0.span(), + first_arm.0.len(), + )); is_err = true; } } @@ -913,39 +1286,65 @@ impl ToHir for ast::Expr { }) .collect::>(); - let pred = tupleify_expr(&SrcNode::new(pseudos - .iter() - .map(|(pseudo, _)| SrcNode::new(ast::Expr::Local(**pseudo), pseudo.span())) - .collect(), self.span()), cfg, infer, &scope.with_many(&pseudos.clone())); + let pred = tupleify_expr( + &SrcNode::new( + pseudos + .iter() + .map(|(pseudo, _)| { + SrcNode::new(ast::Expr::Local(**pseudo), pseudo.span()) + }) + .collect(), + self.span(), + ), + _cfg, + infer, + &scope.with_many(&pseudos.clone()), + ); let arms = arms .iter() .map(|(bindings, body)| { - let binding = tupleify_binding(bindings, cfg, infer, &scope); + let binding = tupleify_binding(bindings, _cfg, infer, &scope); infer.make_flow(pred.meta().1, binding.meta().1, binding.meta().0); - let body = body.to_hir(cfg, infer, &scope.with_many(&binding.get_binding_tys())); - infer.make_flow(body.meta().1, output_ty, EqInfo::new(self.span(), format!("Branches must produce compatible values"))); + let body = body.to_hir( + _cfg, + infer, + &scope.with_many(&binding.get_binding_tys()), + ); + infer.make_flow( + body.meta().1, + output_ty, + EqInfo::new( + self.span(), + "Branches must produce compatible values".to_string(), + ), + ); (binding, body) }) .collect(); let pred_meta = *pred.meta(); - let branches = InferNode::new(hir::Expr::Match(true, pred, arms), (self.span(), output_ty)); + let branches = InferNode::new( + hir::Expr::Match(true, pred, arms), + (self.span(), output_ty), + ); let opaque = infer.opaque(self.span(), true /* false */); // TODO: `false` instead? - let output = infer.insert(self.span(), TyInfo::Effect(eff, branches.meta().1, opaque)); - - let f = pseudos - .into_iter() - .rev() - .fold( - InferNode::new(hir::Expr::Basin(eff, branches), (self.span(), output)), - |body, (pseudo, pseudo_ty)| { - let f = infer.insert(self.span(), TyInfo::Func(pseudo_ty, body.meta().1)); - InferNode::new(hir::Expr::Func(InferNode::new(*pseudo, pred_meta), body), (self.span(), f)) - }, - ); + let output = infer + .insert(self.span(), TyInfo::Effect(eff, branches.meta().1, opaque)); + + let f = pseudos.into_iter().rev().fold( + InferNode::new(hir::Expr::Basin(eff, branches), (self.span(), output)), + |body, (pseudo, pseudo_ty)| { + let f = infer + .insert(self.span(), TyInfo::Func(pseudo_ty, body.meta().1)); + InferNode::new( + hir::Expr::Func(InferNode::new(*pseudo, pred_meta), body), + (self.span(), f), + ) + }, + ); (TyInfo::Ref(f.meta().1), f.into_inner()) } @@ -953,405 +1352,668 @@ impl ToHir for ast::Expr { infer.ctx_mut().emit(Error::NoBranches(self.span())); (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) } - }, + } ast::Expr::Apply(f, param) => { - let f = f.to_hir(cfg, infer, scope); - let param = param.to_hir(cfg, infer, scope); + let f = f.to_hir(_cfg, infer, scope); + let param = param.to_hir(_cfg, infer, scope); let input_ty = infer.unknown(param.meta().0); let output_ty = infer.unknown(self.span()); let func = infer.insert(f.meta().0, TyInfo::Func(input_ty, output_ty)); - infer.make_flow(f.meta().1, func, EqInfo::new(self.span(), format!("Only functions are callable"))); - infer.make_flow(param.meta().1, input_ty, EqInfo::new(param.meta().0, format!("Functions may only be called with compatible arguments"))); + infer.make_flow( + f.meta().1, + func, + EqInfo::new(self.span(), "Only functions are callable".to_string()), + ); + infer.make_flow( + param.meta().1, + input_ty, + EqInfo::new( + param.meta().0, + "Functions may only be called with compatible arguments".to_string(), + ), + ); (TyInfo::Ref(output_ty), hir::Expr::Apply(f, param)) - }, - ast::Expr::Cons(name, inner) => if let Some(data) = infer.ctx().datas.lookup_cons(**name) { - let gen_scope = infer.ctx().tys.get_gen_scope(infer.ctx().datas.get_data(data).gen_scope); - let gen_tys = (0..gen_scope.len()) - .map(|i| gen_scope.get(i).name.span()) - .collect::>(); - let gen_effs = (0..gen_scope.len_eff()) - .map(|i| gen_scope.get_eff(i).name.span()) - .collect::>(); - let gen_tys = gen_tys - .into_iter() - .map(|origin| infer.insert(self.span(), TyInfo::Unknown(Some(origin)))) - .collect::>(); - let gen_effs = gen_effs - .into_iter() - .map(|_origin| infer.insert_effect(self.span(), EffectInfo::free())) - .collect::>(); + } + ast::Expr::Cons(name, inner) => { + if let Some(data) = infer.ctx().datas.lookup_cons(**name) { + let gen_scope = infer + .ctx() + .tys + .get_gen_scope(infer.ctx().datas.get_data(data).gen_scope); + let gen_tys = (0..gen_scope.len()) + .map(|i| gen_scope.get(i).name.span()) + .collect::>(); + let gen_effs = (0..gen_scope.len_eff()) + .map(|i| gen_scope.get_eff(i).name.span()) + .collect::>(); + let gen_tys = gen_tys + .into_iter() + .map(|origin| infer.insert(self.span(), TyInfo::Unknown(Some(origin)))) + .collect::>(); + let gen_effs = gen_effs + .into_iter() + .map(|_origin| infer.insert_effect(self.span(), EffectInfo::free())) + .collect::>(); - if let Err(()) = enforce_generic_obligations( - infer, - infer.ctx().datas.get_data(data).gen_scope, - &gen_tys, - &gen_effs, - self.span(), - infer.ctx().datas.get_data_span(data), - None, - ) { - // Only fails if generic count doesn't match, but they're from the same source of truth! - unreachable!(); - } + if let Err(()) = enforce_generic_obligations( + infer, + infer.ctx().datas.get_data(data).gen_scope, + &gen_tys, + &gen_effs, + self.span(), + infer.ctx().datas.get_data_span(data), + None, + ) { + // Only fails if generic count doesn't match, but they're from the same source of truth! + unreachable!(); + } - let inner_ty = infer - .ctx() - .datas - .get_data(data) - .cons - .iter() - .find(|(cons, _)| **cons == **name) - .unwrap() - .1; + let inner_ty = infer + .ctx() + .datas + .get_data(data) + .cons + .iter() + .find(|(cons, _)| **cons == **name) + .unwrap() + .1; + + // Recreate type in context + let inner_ty = { + let data = infer.ctx().datas.get_data(data); + let _data_gen_scope = data.gen_scope; + + infer.instantiate( + inner_ty, + name.span(), + &mut |index, _, _infer: &mut Infer| gen_tys.get(index).copied(), + &mut |_idx, _| todo!(), + None, + invariant(), + ) + }; - // Recreate type in context - let inner_ty = { - let data = infer.ctx().datas.get_data(data); - let data_gen_scope = data.gen_scope; + let inner = inner.to_hir(_cfg, infer, scope); + infer.make_flow(inner.meta().1, inner_ty, self.span()); - infer.instantiate( - inner_ty, - name.span(), - &mut |index, _, infer: &mut Infer| gen_tys.get(index).copied(), - &mut |idx, _| todo!(), - None, - invariant(), + ( + TyInfo::Data(data, gen_tys), + hir::Expr::Cons(SrcNode::new(data, name.span()), **name, inner), ) - }; - - let inner = inner.to_hir(cfg, infer, scope); - infer.make_flow(inner.meta().1, inner_ty, self.span()); - - (TyInfo::Data(data, gen_tys), hir::Expr::Cons(SrcNode::new(data, name.span()), **name, inner)) - } else { - infer.ctx_mut().emit(Error::NoSuchCons(name.clone())); - // TODO: Don't use a hard, preserve inner expression - (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) - }, + } else { + infer.ctx_mut().emit(Error::NoSuchCons(name.clone())); + // TODO: Don't use a hard, preserve inner expression + (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) + } + } ast::Expr::ClassAccess(ty, field) => { let ty = ty.to_hir(&TypeLowerCfg::other(), infer, scope); let field_ty = infer.unknown(self.span()); - let class = infer.make_class_field(ty.meta().1, field.clone(), field_ty, self.span()); - (TyInfo::Ref(field_ty), hir::Expr::ClassAccess(*ty.meta(), class, field.clone())) - }, - ast::Expr::Intrinsic(name, args) => if let Some(bool_data) = infer.ctx().datas.lang.r#bool { - fn make_str(infer: &mut Infer, span: Span) -> TyVar { - let c = infer.insert(span, TyInfo::Prim(Prim::Char)); - infer.insert(span, TyInfo::List(c)) - } - - let mut args = args - .iter() - .map(|arg| arg.to_hir(cfg, infer, scope)) - .collect::>(); - - let unary_ops = [ - ("neg_nat", Intrinsic::NegNat, Prim::Nat, TyInfo::Prim(Prim::Int)), - ("neg_int", Intrinsic::NegInt, Prim::Int, TyInfo::Prim(Prim::Int)), - ("neg_real", Intrinsic::NegReal, Prim::Real, TyInfo::Prim(Prim::Real)), - ("display_int", Intrinsic::DisplayInt, Prim::Int, TyInfo::Ref(make_str(infer, self.span()))), - ("codepoint_char", Intrinsic::CodepointChar, Prim::Char, TyInfo::Prim(Prim::Nat)), - ]; - - let binary_ops = [ - ("add_nat", Intrinsic::AddNat, Prim::Nat, Prim::Nat, TyInfo::Prim(Prim::Nat)), - ("add_int", Intrinsic::AddInt, Prim::Int, Prim::Int, TyInfo::Prim(Prim::Int)), - ("mul_nat", Intrinsic::MulNat, Prim::Nat, Prim::Nat, TyInfo::Prim(Prim::Nat)), - ("mul_int", Intrinsic::MulInt, Prim::Int, Prim::Int, TyInfo::Prim(Prim::Int)), - ("eq_char", Intrinsic::EqChar, Prim::Char, Prim::Char, TyInfo::Data(bool_data, Vec::new())), - ("eq_nat", Intrinsic::EqNat, Prim::Nat, Prim::Nat, TyInfo::Data(bool_data, Vec::new())), - ("less_nat", Intrinsic::LessNat, Prim::Nat, Prim::Nat, TyInfo::Data(bool_data, Vec::new())), - ]; - - if let Some((_, intrinsic, a_prim, out_ty)) = unary_ops - .iter() - .find(|(op, _, _, _)| op == &***name) - .filter(|_| args.len() == 1) - .cloned() - { - let a = &args[0]; - let a_ty = infer.insert(a.meta().0, TyInfo::Prim(a_prim)); - infer.make_flow(args[0].meta().1, a_ty, EqInfo::from(name.span())); - (out_ty, hir::Expr::Intrinsic(SrcNode::new(intrinsic, name.span()), args)) - } else if let Some((_, intrinsic, a_prim, b_prim, out_ty)) = binary_ops - .iter() - .find(|(op, _, _, _, _)| op == &***name) - .filter(|_| args.len() == 2) - .cloned() - { - let a = &args[0]; - let b = &args[1]; - let a_ty = infer.insert(a.meta().0, TyInfo::Prim(a_prim)); - let b_ty = infer.insert(b.meta().0, TyInfo::Prim(b_prim)); - infer.make_flow(args[0].meta().1, a_ty, EqInfo::from(name.span())); - infer.make_flow(args[1].meta().1, b_ty, EqInfo::from(name.span())); - (out_ty, hir::Expr::Intrinsic(SrcNode::new(intrinsic, name.span()), args)) - } else { - match name.as_str() { - "type_name" if args.len() == 1 => { - // Takes an empty list - let item = infer.unknown(args[0].meta().0); - let list = infer.insert(args[0].meta().0, TyInfo::List(item)); - infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); - // Produces a string - let c = infer.insert(name.span(), TyInfo::Prim(Prim::Char)); - (TyInfo::List(c), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::TypeName, name.span()), args)) - }, - "go" if args.len() == 2 => if let Some(go_data) = infer.ctx().datas.lang.go { - let c = args[1].meta().1; - let r = infer.unknown(self.span()); - let ret = infer.insert(args[0].meta().0, TyInfo::Data(go_data, vec![c, r])); - let f = infer.insert(args[0].meta().0, TyInfo::Func(c, ret)); - infer.make_flow(args[0].meta().1, f, EqInfo::from(name.span())); - (TyInfo::Ref(r), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::Go, name.span()), args)) - } else { - (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) - }, - "print" if args.len() == 2 => { - let a = &args[0]; - let b = &args[1]; - - let universe = infer.insert(a.meta().0, TyInfo::Prim(Prim::Universe)); - infer.make_flow(a.meta().1, universe, EqInfo::from(name.span())); - - let c = infer.insert(b.meta().0, TyInfo::Prim(Prim::Char)); - let s = infer.insert(b.meta().0, TyInfo::List(c)); - infer.make_flow(b.meta().1, s, EqInfo::from(name.span())); - - (TyInfo::Prim(Prim::Universe), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::Print, name.span()), args)) - }, - "input" if args.len() == 1 => { - let a = &args[0]; - - let universe = infer.insert(a.meta().0, TyInfo::Prim(Prim::Universe)); - infer.make_flow(a.meta().1, universe, EqInfo::from(name.span())); - - let s = make_str(infer, self.span()); - - (TyInfo::tuple(vec![universe, s]), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::Input, name.span()), args)) - }, - "rand" if args.len() == 2 => { - let a = &args[0]; - let b = &args[1]; - - let universe = infer.insert(a.meta().0, TyInfo::Prim(Prim::Universe)); - infer.make_flow(a.meta().1, universe, EqInfo::from(name.span())); - let nat = infer.insert(a.meta().0, TyInfo::Prim(Prim::Nat)); - infer.make_flow(b.meta().1, nat, EqInfo::from(name.span())); - - let nat = infer.insert(a.meta().0, TyInfo::Prim(Prim::Nat)); - - (TyInfo::tuple(vec![universe, nat]), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::Rand, name.span()), args)) - }, - "len_list" if args.len() == 1 => { - let item = infer.unknown(args[0].meta().0); - let list = infer.insert(args[0].meta().0, TyInfo::List(item)); - infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); - (TyInfo::Prim(Prim::Nat), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::LenList, name.span()), args)) - }, - "skip_list" if args.len() == 2 => { - let item = infer.unknown(args[0].meta().0); - let list = infer.insert(args[0].meta().0, TyInfo::List(item)); - infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); - let nat = infer.insert(args[1].meta().0, TyInfo::Prim(Prim::Nat)); - infer.make_flow(args[1].meta().1, nat, EqInfo::from(name.span())); - (TyInfo::Ref(list), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::SkipList, name.span()), args)) - }, - "trim_list" if args.len() == 2 => { - let item = infer.unknown(args[0].meta().0); - let list = infer.insert(args[0].meta().0, TyInfo::List(item)); - infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); - let nat = infer.insert(args[1].meta().0, TyInfo::Prim(Prim::Nat)); - infer.make_flow(args[1].meta().1, nat, EqInfo::from(name.span())); - (TyInfo::Ref(list), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::TrimList, name.span()), args)) - }, - "join_list" if args.len() == 2 => { - let item = infer.unknown(args[0].meta().0); - let list = infer.insert(args[0].meta().0, TyInfo::List(item)); - infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); - infer.make_flow(args[1].meta().1, list, EqInfo::from(name.span())); - (TyInfo::Ref(list), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::JoinList, name.span()), args)) - }, - "suspend" if args.len() == 1 => { - let a = &args[0]; - let out = infer.unknown(self.span()); - - let eff_inst = if let Some(basin_eff) = scope.last_basin() { - // TODO: Probably bad! - // eff - let eff_inst = infer.insert_effect_inst(self.span(), EffectInstInfo::Unknown); - let eff = infer.insert_effect(self.span(), EffectInfo::Open(vec![eff_inst])); - let phoney_ty = infer.insert(self.span(), TyInfo::tuple([])); - infer.make_flow_effect((eff, phoney_ty), (basin_eff, phoney_ty), EqInfo::default()); - eff_inst - } else { - infer.ctx_mut().errors.push(Error::NoBasin(name.span())); - infer.insert_effect_inst(self.span(), EffectInstInfo::Unknown) - }; - - infer.make_effect_send_recv(eff_inst, a.meta().1, out, self.span()); - (TyInfo::Ref(out), hir::Expr::Suspend(eff_inst, args.remove(0))) - }, - "dispatch" if args.len() == 3 => { - let general = infer.unknown(args[0].meta().0); - let special = infer.unknown(args[1].meta().0); - let byproduct = infer.unknown(self.span()); - - let specialised_out = infer.insert(args[1].meta().0, TyInfo::tuple([special, byproduct])); - let specialised_fn = infer.insert(args[1].meta().0, TyInfo::Func(special, specialised_out)); + let class = + infer.make_class_field(ty.meta().1, field.clone(), field_ty, self.span()); + ( + TyInfo::Ref(field_ty), + hir::Expr::ClassAccess(*ty.meta(), class, field.clone()), + ) + } + ast::Expr::Intrinsic(name, args) => { + if let Some(bool_data) = infer.ctx().datas.lang.r#bool { + fn make_str(infer: &mut Infer, span: Span) -> TyVar { + let c = infer.insert(span, TyInfo::Prim(Prim::Char)); + infer.insert(span, TyInfo::List(c)) + } - let fallback_out = infer.insert(args[2].meta().0, TyInfo::tuple([general, byproduct])); - let fallback_fn = infer.insert(args[2].meta().0, TyInfo::Func(general, fallback_out)); + let mut args = args + .iter() + .map(|arg| arg.to_hir(_cfg, infer, scope)) + .collect::>(); - infer.make_flow(args[0].meta().1, general, self.span()); - infer.make_flow(args[1].meta().1, specialised_fn, self.span()); - infer.make_flow(args[2].meta().1, fallback_fn, self.span()); + let unary_ops = [ + ( + "neg_nat", + Intrinsic::NegNat, + Prim::Nat, + TyInfo::Prim(Prim::Int), + ), + ( + "neg_int", + Intrinsic::NegInt, + Prim::Int, + TyInfo::Prim(Prim::Int), + ), + ( + "neg_real", + Intrinsic::NegReal, + Prim::Real, + TyInfo::Prim(Prim::Real), + ), + ( + "display_int", + Intrinsic::DisplayInt, + Prim::Int, + TyInfo::Ref(make_str(infer, self.span())), + ), + ( + "codepoint_char", + Intrinsic::CodepointChar, + Prim::Char, + TyInfo::Prim(Prim::Nat), + ), + ]; + + let binary_ops = [ + ( + "add_nat", + Intrinsic::AddNat, + Prim::Nat, + Prim::Nat, + TyInfo::Prim(Prim::Nat), + ), + ( + "add_int", + Intrinsic::AddInt, + Prim::Int, + Prim::Int, + TyInfo::Prim(Prim::Int), + ), + ( + "mul_nat", + Intrinsic::MulNat, + Prim::Nat, + Prim::Nat, + TyInfo::Prim(Prim::Nat), + ), + ( + "mul_int", + Intrinsic::MulInt, + Prim::Int, + Prim::Int, + TyInfo::Prim(Prim::Int), + ), + ( + "eq_char", + Intrinsic::EqChar, + Prim::Char, + Prim::Char, + TyInfo::Data(bool_data, Vec::new()), + ), + ( + "eq_nat", + Intrinsic::EqNat, + Prim::Nat, + Prim::Nat, + TyInfo::Data(bool_data, Vec::new()), + ), + ( + "less_nat", + Intrinsic::LessNat, + Prim::Nat, + Prim::Nat, + TyInfo::Data(bool_data, Vec::new()), + ), + ]; + + if let Some((_, intrinsic, a_prim, out_ty)) = unary_ops + .iter() + .find(|(op, _, _, _)| op == &***name) + .filter(|_| args.len() == 1) + .cloned() + { + let a = &args[0]; + let a_ty = infer.insert(a.meta().0, TyInfo::Prim(a_prim)); + infer.make_flow(args[0].meta().1, a_ty, EqInfo::from(name.span())); + ( + out_ty, + hir::Expr::Intrinsic(SrcNode::new(intrinsic, name.span()), args), + ) + } else if let Some((_, intrinsic, a_prim, b_prim, out_ty)) = binary_ops + .iter() + .find(|(op, _, _, _, _)| op == &***name) + .filter(|_| args.len() == 2) + .cloned() + { + let a = &args[0]; + let b = &args[1]; + let a_ty = infer.insert(a.meta().0, TyInfo::Prim(a_prim)); + let b_ty = infer.insert(b.meta().0, TyInfo::Prim(b_prim)); + infer.make_flow(args[0].meta().1, a_ty, EqInfo::from(name.span())); + infer.make_flow(args[1].meta().1, b_ty, EqInfo::from(name.span())); + ( + out_ty, + hir::Expr::Intrinsic(SrcNode::new(intrinsic, name.span()), args), + ) + } else { + match name.as_str() { + "type_name" if args.len() == 1 => { + // Takes an empty list + let item = infer.unknown(args[0].meta().0); + let list = infer.insert(args[0].meta().0, TyInfo::List(item)); + infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); + // Produces a string + let c = infer.insert(name.span(), TyInfo::Prim(Prim::Char)); + ( + TyInfo::List(c), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::TypeName, name.span()), + args, + ), + ) + } + "go" if args.len() == 2 => { + if let Some(go_data) = infer.ctx().datas.lang.go { + let c = args[1].meta().1; + let r = infer.unknown(self.span()); + let ret = infer.insert( + args[0].meta().0, + TyInfo::Data(go_data, vec![c, r]), + ); + let f = infer.insert(args[0].meta().0, TyInfo::Func(c, ret)); + infer.make_flow(args[0].meta().1, f, EqInfo::from(name.span())); + ( + TyInfo::Ref(r), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::Go, name.span()), + args, + ), + ) + } else { + (TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error) + } + } + "print" if args.len() == 2 => { + let a = &args[0]; + let b = &args[1]; + + let universe = + infer.insert(a.meta().0, TyInfo::Prim(Prim::Universe)); + infer.make_flow(a.meta().1, universe, EqInfo::from(name.span())); + + let c = infer.insert(b.meta().0, TyInfo::Prim(Prim::Char)); + let s = infer.insert(b.meta().0, TyInfo::List(c)); + infer.make_flow(b.meta().1, s, EqInfo::from(name.span())); + + ( + TyInfo::Prim(Prim::Universe), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::Print, name.span()), + args, + ), + ) + } + "input" if args.len() == 1 => { + let a = &args[0]; + + let universe = + infer.insert(a.meta().0, TyInfo::Prim(Prim::Universe)); + infer.make_flow(a.meta().1, universe, EqInfo::from(name.span())); + + let s = make_str(infer, self.span()); + + ( + TyInfo::tuple(vec![universe, s]), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::Input, name.span()), + args, + ), + ) + } + "rand" if args.len() == 2 => { + let a = &args[0]; + let b = &args[1]; + + let universe = + infer.insert(a.meta().0, TyInfo::Prim(Prim::Universe)); + infer.make_flow(a.meta().1, universe, EqInfo::from(name.span())); + let nat = infer.insert(a.meta().0, TyInfo::Prim(Prim::Nat)); + infer.make_flow(b.meta().1, nat, EqInfo::from(name.span())); + + let nat = infer.insert(a.meta().0, TyInfo::Prim(Prim::Nat)); + + ( + TyInfo::tuple(vec![universe, nat]), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::Rand, name.span()), + args, + ), + ) + } + "len_list" if args.len() == 1 => { + let item = infer.unknown(args[0].meta().0); + let list = infer.insert(args[0].meta().0, TyInfo::List(item)); + infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); + ( + TyInfo::Prim(Prim::Nat), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::LenList, name.span()), + args, + ), + ) + } + "skip_list" if args.len() == 2 => { + let item = infer.unknown(args[0].meta().0); + let list = infer.insert(args[0].meta().0, TyInfo::List(item)); + infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); + let nat = infer.insert(args[1].meta().0, TyInfo::Prim(Prim::Nat)); + infer.make_flow(args[1].meta().1, nat, EqInfo::from(name.span())); + ( + TyInfo::Ref(list), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::SkipList, name.span()), + args, + ), + ) + } + "trim_list" if args.len() == 2 => { + let item = infer.unknown(args[0].meta().0); + let list = infer.insert(args[0].meta().0, TyInfo::List(item)); + infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); + let nat = infer.insert(args[1].meta().0, TyInfo::Prim(Prim::Nat)); + infer.make_flow(args[1].meta().1, nat, EqInfo::from(name.span())); + ( + TyInfo::Ref(list), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::TrimList, name.span()), + args, + ), + ) + } + "join_list" if args.len() == 2 => { + let item = infer.unknown(args[0].meta().0); + let list = infer.insert(args[0].meta().0, TyInfo::List(item)); + infer.make_flow(args[0].meta().1, list, EqInfo::from(name.span())); + infer.make_flow(args[1].meta().1, list, EqInfo::from(name.span())); + ( + TyInfo::Ref(list), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::JoinList, name.span()), + args, + ), + ) + } + "suspend" if args.len() == 1 => { + let a = &args[0]; + let out = infer.unknown(self.span()); + + let eff_inst = if let Some(basin_eff) = scope.last_basin() { + // TODO: Probably bad! + // eff + let eff_inst = infer + .insert_effect_inst(self.span(), EffectInstInfo::Unknown); + let eff = infer.insert_effect( + self.span(), + EffectInfo::Open(vec![eff_inst]), + ); + let phoney_ty = infer.insert(self.span(), TyInfo::tuple([])); + infer.make_flow_effect( + (eff, phoney_ty), + (basin_eff, phoney_ty), + EqInfo::default(), + ); + eff_inst + } else { + infer.ctx_mut().errors.push(Error::NoBasin(name.span())); + infer.insert_effect_inst(self.span(), EffectInstInfo::Unknown) + }; + + infer.make_effect_send_recv(eff_inst, a.meta().1, out, self.span()); + ( + TyInfo::Ref(out), + hir::Expr::Suspend(eff_inst, args.remove(0)), + ) + } + "dispatch" if args.len() == 3 => { + let general = infer.unknown(args[0].meta().0); + let special = infer.unknown(args[1].meta().0); + let byproduct = infer.unknown(self.span()); + + let specialised_out = infer + .insert(args[1].meta().0, TyInfo::tuple([special, byproduct])); + let specialised_fn = infer.insert( + args[1].meta().0, + TyInfo::Func(special, specialised_out), + ); - (TyInfo::Ref(fallback_out), hir::Expr::Intrinsic(SrcNode::new(Intrinsic::Dispatch, name.span()), args)) - }, - _ => { - infer.ctx_mut().emit(Error::InvalidIntrinsic(name.clone())); - (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) - }, + let fallback_out = infer + .insert(args[2].meta().0, TyInfo::tuple([general, byproduct])); + let fallback_fn = infer + .insert(args[2].meta().0, TyInfo::Func(general, fallback_out)); + + infer.make_flow(args[0].meta().1, general, self.span()); + infer.make_flow(args[1].meta().1, specialised_fn, self.span()); + infer.make_flow(args[2].meta().1, fallback_fn, self.span()); + + ( + TyInfo::Ref(fallback_out), + hir::Expr::Intrinsic( + SrcNode::new(Intrinsic::Dispatch, name.span()), + args, + ), + ) + } + _ => { + infer.ctx_mut().emit(Error::InvalidIntrinsic(name.clone())); + (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) + } + } } + } else { + (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) } - } else { - (TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error) - }, + } ast::Expr::Update(record, fields) => { - let record = record.to_hir(cfg, infer, scope); + let record = record.to_hir(_cfg, infer, scope); let fields = fields .iter() .map(|(name, field)| { - let field = field.to_hir(cfg, infer, scope); + let field = field.to_hir(_cfg, infer, scope); infer.make_update(record.meta().1, name.clone(), field.meta().1); (name.clone(), field) }) .collect(); - (TyInfo::Ref(record.meta().1), hir::Expr::Update(record, fields)) - }, + ( + TyInfo::Ref(record.meta().1), + hir::Expr::Update(record, fields), + ) + } ast::Expr::Basin(init, last) => { let eff = infer.insert_effect(self.span(), EffectInfo::free()); // Collect effects into this basin let scope = scope.with_basin(eff); - let expr = gen_block(infer, cfg, &init, last, &scope); + let expr = gen_block(infer, _cfg, init, last, &scope); let opaque = infer.opaque(self.span(), false); - (TyInfo::Effect(eff, expr.meta().1, opaque), hir::Expr::Basin(eff, expr)) - }, + ( + TyInfo::Effect(eff, expr.meta().1, opaque), + hir::Expr::Basin(eff, expr), + ) + } ast::Expr::Block(init, last) => { - let expr = gen_block(infer, cfg, &init, last, &scope); + let expr = gen_block(infer, _cfg, init, last, scope); (TyInfo::Ref(expr.meta().1), expr.into_inner()) - }, + } ast::Expr::Handle { expr, handlers } => { - let expr = expr.to_hir(cfg, infer, &scope); + let expr = expr.to_hir(_cfg, infer, scope); let out_ty = infer.unknown(self.span()); let mut state_ty = None; handlers .iter() - .map(|ast::Handler { eff_name, eff_gen_tys, send, state, recv }| { - let send = send.to_hir(cfg, infer, &scope); - let state = state.as_ref().map(|state| state.to_hir(cfg, infer, &scope)); - let recv = recv.to_hir(cfg, infer, &scope - .with_many(&send.get_binding_tys()) - .with_many(&state.as_ref().map(|state| state.get_binding_tys()).unwrap_or_default())); - - let eff_gen_tys = eff_gen_tys - .iter() - .map(|ty| ty.to_hir(&TypeLowerCfg::other(), infer, scope).meta().1) - .collect::>(); - - if let Some(Ok(eff_id)) = infer.ctx().effects.lookup(**eff_name) { - let eff = infer.ctx().effects.get_decl(eff_id); - let eff_gen_scope = eff.gen_scope; - let eff_span = eff.name.span(); - match enforce_generic_obligations( + .map( + |ast::Handler { + eff_name, + eff_gen_tys, + send, + state, + recv, + }| { + let send = send.to_hir(_cfg, infer, scope); + let state = + state.as_ref().map(|state| state.to_hir(_cfg, infer, scope)); + let recv = recv.to_hir( + _cfg, infer, - eff_gen_scope, - &eff_gen_tys, - &[], - self.span(), - eff_span, - None, - ) { - Ok(()) => { - let eff = infer.insert_effect_inst(self.span(), EffectInstInfo::Known(eff_id, eff_gen_tys)); - - if let Some(state) = &state { - let recv_ty = infer.unknown(recv.meta().0); - let recv_and_state = infer.insert(expr.meta().0, TyInfo::tuple([recv_ty, state.meta().1])); - infer.make_flow(recv.meta().1, recv_and_state, EqInfo::from(self.span())); - - infer.make_effect_send_recv(eff, send.meta().1, recv_ty, eff_name.span()); - - match &mut state_ty { - Some(state_ty) => { - infer.make_flow(*state_ty, state.meta().1, EqInfo::from(state.meta().0)); - }, - None => state_ty = Some(state.meta().1), - } - } else { - infer.make_effect_send_recv(eff, send.meta().1, recv.meta().1, eff_name.span()); - }; - - let recv_meta = *recv.meta(); - let handler = hir::Handler { - eff, - send: InferNode::new(Ident::new("0"), *send.meta()), - state: state.as_ref().map(|state| InferNode::new(Ident::new("1"), *state.meta())), - recv: InferNode::new(hir::Expr::Match( - false, - InferNode::new(hir::Expr::Local(Ident::new("0")), *send.meta()), - if let Some(state) = state { - vec![(send, InferNode::new(hir::Expr::Match( + &scope.with_many(&send.get_binding_tys()).with_many( + &state + .as_ref() + .map(|state| state.get_binding_tys()) + .unwrap_or_default(), + ), + ); + + let eff_gen_tys = eff_gen_tys + .iter() + .map(|ty| ty.to_hir(&TypeLowerCfg::other(), infer, scope).meta().1) + .collect::>(); + + if let Some(Ok(eff_id)) = infer.ctx().effects.lookup(**eff_name) { + let eff = infer.ctx().effects.get_decl(eff_id); + let eff_gen_scope = eff.gen_scope; + let eff_span = eff.name.span(); + match enforce_generic_obligations( + infer, + eff_gen_scope, + &eff_gen_tys, + &[], + self.span(), + eff_span, + None, + ) { + Ok(()) => { + let eff = infer.insert_effect_inst( + self.span(), + EffectInstInfo::Known(eff_id, eff_gen_tys), + ); + + if let Some(state) = &state { + let recv_ty = infer.unknown(recv.meta().0); + let recv_and_state = infer.insert( + expr.meta().0, + TyInfo::tuple([recv_ty, state.meta().1]), + ); + infer.make_flow( + recv.meta().1, + recv_and_state, + EqInfo::from(self.span()), + ); + + infer.make_effect_send_recv( + eff, + send.meta().1, + recv_ty, + eff_name.span(), + ); + + match &mut state_ty { + Some(state_ty) => { + infer.make_flow( + *state_ty, + state.meta().1, + EqInfo::from(state.meta().0), + ); + } + None => state_ty = Some(state.meta().1), + } + } else { + infer.make_effect_send_recv( + eff, + send.meta().1, + recv.meta().1, + eff_name.span(), + ); + }; + + let recv_meta = *recv.meta(); + let handler = hir::Handler { + eff, + send: InferNode::new(Ident::new("0"), *send.meta()), + state: state.as_ref().map(|state| { + InferNode::new(Ident::new("1"), *state.meta()) + }), + recv: InferNode::new( + hir::Expr::Match( false, - InferNode::new(hir::Expr::Local(Ident::new("1")), *state.meta()), - vec![(state, recv)], - ), recv_meta))] - } else { - vec![(send, recv)] - }, - ), recv_meta), - }; - - Ok((eff, handler)) - }, - Err(()) => Err((TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error)), + InferNode::new( + hir::Expr::Local(Ident::new("0")), + *send.meta(), + ), + if let Some(state) = state { + vec![( + send, + InferNode::new( + hir::Expr::Match( + false, + InferNode::new( + hir::Expr::Local( + Ident::new("1"), + ), + *state.meta(), + ), + vec![(state, recv)], + ), + recv_meta, + ), + )] + } else { + vec![(send, recv)] + }, + ), + recv_meta, + ), + }; + + Ok((eff, handler)) + } + Err(()) => { + Err((TyInfo::Error(ErrorReason::Unknown), hir::Expr::Error)) + } + } + } else { + infer.ctx_mut().emit(Error::NoSuchEffect(eff_name.clone())); + Err((TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error)) + // TODO: Can we avoid making this entire node an error? } - } else { - infer.ctx_mut().emit(Error::NoSuchEffect(eff_name.clone())); - Err((TyInfo::Error(ErrorReason::Invalid), hir::Expr::Error)) // TODO: Can we avoid making this entire node an error? - } - }) + }, + ) .collect::, _>>() .map(|handlers| { let opaque = infer.unknown(expr.meta().0); - let eff_set = infer.insert_effect(self.span(), EffectInfo::Closed(handlers.iter().map(|(ty, _)| *ty).collect(), None)); - let eff_obj_ty = infer.insert(self.span(), TyInfo::Effect(eff_set, out_ty, opaque)); + let eff_set = infer.insert_effect( + self.span(), + EffectInfo::Closed(handlers.iter().map(|(ty, _)| *ty).collect(), None), + ); + let eff_obj_ty = + infer.insert(self.span(), TyInfo::Effect(eff_set, out_ty, opaque)); let overall_ty = if let Some(state_ty) = state_ty { - let eff_and_state = infer.insert(expr.meta().0, TyInfo::tuple([eff_obj_ty, state_ty])); - infer.make_flow(expr.meta().1, eff_and_state, EqInfo::from(self.span())); + let eff_and_state = + infer.insert(expr.meta().0, TyInfo::tuple([eff_obj_ty, state_ty])); + infer.make_flow( + expr.meta().1, + eff_and_state, + EqInfo::from(self.span()), + ); TyInfo::tuple([out_ty, state_ty]) } else { infer.make_flow(expr.meta().1, eff_obj_ty, EqInfo::from(self.span())); TyInfo::Ref(out_ty) }; - (overall_ty, hir::Expr::Handle { - expr, - handlers: handlers - .into_iter() - .map(|(_, handler)| handler) - .collect(), - }) + ( + overall_ty, + hir::Expr::Handle { + expr, + handlers: handlers + .into_iter() + .map(|(_, handler)| handler) + .collect(), + }, + ) }) .unwrap_or_else(|e| e) - }, + } }; InferNode::new(expr, (span, infer.insert(span, info))) @@ -1370,10 +2032,13 @@ fn gen_block( let rhs = rhs.to_hir(cfg, infer, scope); let lhs = match lhs { - None => InferNode::new(hir::Binding { + None => InferNode::new( + hir::Binding { pat: SrcNode::new(hir::Pat::Wildcard, rhs.meta().0), name: None, - }, *rhs.meta()), + }, + *rhs.meta(), + ), Some(lhs) => lhs.to_hir(cfg, infer, scope), }; @@ -1385,36 +2050,45 @@ fn gen_block( let then = gen_block(infer, cfg, init, last, &scope); let then_meta = *then.meta(); - InferNode::new(hir::Expr::Match(false, rhs, vec![( - lhs, - then, - )]), then_meta) - }, + InferNode::new(hir::Expr::Match(false, rhs, vec![(lhs, then)]), then_meta) + } [] => last.to_hir(cfg, infer, scope), } } // Desugar a list of expressions into a tuple -fn tupleify_expr(items: &SrcNode>>, cfg: &::Cfg, infer: &mut Infer, scope: &Scope) -> InferExpr { +fn tupleify_expr( + items: &SrcNode>>, + cfg: &::Cfg, + infer: &mut Infer, + scope: &Scope, +) -> InferExpr { let hir_items = items .iter() .map(|item| item.to_hir(cfg, infer, scope)) .collect::>(); - let tuple_ty = infer.insert(items.span(), TyInfo::tuple(hir_items - .iter() - .map(|item| item.meta().1))); + let tuple_ty = infer.insert( + items.span(), + TyInfo::tuple(hir_items.iter().map(|item| item.meta().1)), + ); InferNode::new(hir::Expr::tuple(hir_items), (items.span(), tuple_ty)) } // Desugar a list of bindings into a tuple -fn tupleify_binding(items: &SrcNode>>, cfg: &::Cfg, infer: &mut Infer, scope: &Scope) -> InferBinding { +fn tupleify_binding( + items: &SrcNode>>, + cfg: &::Cfg, + infer: &mut Infer, + scope: &Scope, +) -> InferBinding { let hir_items = items .iter() .map(|item| item.to_hir(cfg, infer, scope)) .collect::>(); - let tuple_ty = infer.insert(items.span(), TyInfo::tuple(hir_items - .iter() - .map(|item| item.meta().1))); + let tuple_ty = infer.insert( + items.span(), + TyInfo::tuple(hir_items.iter().map(|item| item.meta().1)), + ); let binding = hir::Binding { pat: SrcNode::new(hir::Pat::tuple(hir_items), items.span()), name: None, diff --git a/analysis/src/reify.rs b/analysis/src/reify.rs index efadcf6..68b46fb 100644 --- a/analysis/src/reify.rs +++ b/analysis/src/reify.rs @@ -13,29 +13,36 @@ impl Reify for hir::Binding { let (span, ty) = *self.meta(); let this = self.into_inner(); - TyNode::new(hir::Binding { - pat: this.pat.map(|pat| match pat { - hir::Pat::Error => hir::Pat::Error, - hir::Pat::Wildcard => hir::Pat::Wildcard, - hir::Pat::Literal(litr) => hir::Pat::Literal(litr), - hir::Pat::Single(inner) => hir::Pat::Single(inner.reify(infer)), - hir::Pat::Add(lhs, rhs) => hir::Pat::Add(lhs.reify(infer), rhs), - hir::Pat::Record(fields, is_tuple) => hir::Pat::Record(fields - .into_iter() - .map(|(name, field)| (name, field.reify(infer))) - .collect(), is_tuple), - hir::Pat::ListExact(items) => hir::Pat::ListExact(items - .into_iter() - .map(|item| item.reify(infer)) - .collect()), - hir::Pat::ListFront(items, tail) => hir::Pat::ListFront(items - .into_iter() - .map(|item| item.reify(infer)) - .collect(), tail.map(|tail| tail.reify(infer))), - hir::Pat::Decons(data, variant, inner) => hir::Pat::Decons(data, variant, inner.reify(infer)), - }), - name: this.name, - }, (span, infer.reify(ty))) + TyNode::new( + hir::Binding { + pat: this.pat.map(|pat| match pat { + hir::Pat::Error => hir::Pat::Error, + hir::Pat::Wildcard => hir::Pat::Wildcard, + hir::Pat::Literal(litr) => hir::Pat::Literal(litr), + hir::Pat::Single(inner) => hir::Pat::Single(inner.reify(infer)), + hir::Pat::Add(lhs, rhs) => hir::Pat::Add(lhs.reify(infer), rhs), + hir::Pat::Record(fields, is_tuple) => hir::Pat::Record( + fields + .into_iter() + .map(|(name, field)| (name, field.reify(infer))) + .collect(), + is_tuple, + ), + hir::Pat::ListExact(items) => hir::Pat::ListExact( + items.into_iter().map(|item| item.reify(infer)).collect(), + ), + hir::Pat::ListFront(items, tail) => hir::Pat::ListFront( + items.into_iter().map(|item| item.reify(infer)).collect(), + tail.map(|tail| tail.reify(infer)), + ), + hir::Pat::Decons(data, variant, inner) => { + hir::Pat::Decons(data, variant, inner.reify(infer)) + } + }), + name: this.name, + }, + (span, infer.reify(ty)), + ) } } @@ -61,20 +68,19 @@ impl Reify for hir::Expr { .collect(), )), hir::Expr::List(items, tails) => hir::Expr::List( - items - .into_iter() - .map(|item| item.reify(infer)) - .collect(), - tails + items.into_iter().map(|item| item.reify(infer)).collect(), + tails.into_iter().map(|tail| tail.reify(infer)).collect(), + ), + hir::Expr::Record(fields, is_tuple) => hir::Expr::Record( + fields .into_iter() - .map(|tail| tail.reify(infer)) + .map(|(name, field)| (name, field.reify(infer))) .collect(), + is_tuple, ), - hir::Expr::Record(fields, is_tuple) => hir::Expr::Record(fields - .into_iter() - .map(|(name, field)| (name, field.reify(infer))) - .collect(), is_tuple), - hir::Expr::Access(record, field_name) => hir::Expr::Access(record.reify(infer), field_name), + hir::Expr::Access(record, field_name) => { + hir::Expr::Access(record.reify(infer), field_name) + } hir::Expr::Match(hidden_outer, pred, arms) => { let pred = pred.reify(infer); let arms = arms @@ -82,12 +88,16 @@ impl Reify for hir::Expr { .map(|(binding, arm)| (binding.reify(infer), arm.reify(infer))) .collect::>(); - if let Err(example) = exhaustivity(infer.ctx(), pred.meta().1, arms.iter().map(|(b, _)| b)) { - infer.ctx_mut().emit(Error::NotExhaustive(span, example, hidden_outer)); + if let Err(example) = + exhaustivity(infer.ctx(), pred.meta().1, arms.iter().map(|(b, _)| b)) + { + infer + .ctx_mut() + .emit(Error::NotExhaustive(span, example, hidden_outer)); } hir::Expr::Match(hidden_outer, pred, arms) - }, + } hir::Expr::Func(param, body) => hir::Expr::Func( TyNode::new(*param, (param.meta().0, infer.reify(param.meta().1))), body.reify(infer), @@ -96,30 +106,43 @@ impl Reify for hir::Expr { hir::Expr::Cons(name, variant, a) => hir::Expr::Cons(name, variant, a.reify(infer)), hir::Expr::ClassAccess((ty_span, ty), class, field) => { hir::Expr::ClassAccess((ty_span, infer.reify(ty)), infer.reify_class(class), field) - }, - hir::Expr::Intrinsic(name, args) => hir::Expr::Intrinsic(name, args - .into_iter() - .map(|arg| arg.reify(infer)) - .collect()), - hir::Expr::Update(record, fields) => hir::Expr::Update(record.reify(infer), fields - .into_iter() - .map(|(name, field)| (name, field.reify(infer))) - .collect()), + } + hir::Expr::Intrinsic(name, args) => { + hir::Expr::Intrinsic(name, args.into_iter().map(|arg| arg.reify(infer)).collect()) + } + hir::Expr::Update(record, fields) => hir::Expr::Update( + record.reify(infer), + fields + .into_iter() + .map(|(name, field)| (name, field.reify(infer))) + .collect(), + ), hir::Expr::Basin(eff, inner) => match infer.reify_effect(eff) { Some(eff) => hir::Expr::Basin(Some(eff), inner.reify(infer)), None => inner.reify(infer).into_inner(), }, - hir::Expr::Suspend(eff, inner) => hir::Expr::Suspend(infer.reify_effect_inst(eff), inner.reify(infer)), + hir::Expr::Suspend(eff, inner) => { + hir::Expr::Suspend(infer.reify_effect_inst(eff), inner.reify(infer)) + } hir::Expr::Handle { expr, handlers } => hir::Expr::Handle { expr: expr.reify(infer), handlers: handlers .into_iter() - .map(|hir::Handler { eff, send, state, recv }| hir::Handler { - eff: infer.reify_effect_inst(eff), - send: TyNode::new(*send, (send.meta().0, infer.reify(send.meta().1))), - state: state.map(|state| TyNode::new(*state, (state.meta().0, infer.reify(state.meta().1)))), - recv: recv.reify(infer), - }) + .map( + |hir::Handler { + eff, + send, + state, + recv, + }| hir::Handler { + eff: infer.reify_effect_inst(eff), + send: TyNode::new(*send, (send.meta().0, infer.reify(send.meta().1))), + state: state.map(|state| { + TyNode::new(*state, (state.meta().0, infer.reify(state.meta().1))) + }), + recv: recv.reify(infer), + }, + ) .collect(), }, }; diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 884638a..2355f44 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -1,8 +1,5 @@ use super::*; -use std::{ - cmp::Ordering, - rc::Rc, -}; +use std::{cmp::Ordering, rc::Rc}; pub type TyMeta = (Span, TyId); pub type TyNode = Node; @@ -46,7 +43,11 @@ pub enum Ty { Data(DataId, Vec), Gen(usize, GenScopeId), SelfType, - Assoc(TyId, (ClassId, Vec, Vec>), SrcNode), + Assoc( + TyId, + (ClassId, Vec, Vec>), + SrcNode, + ), Effect(EffectId, TyId), } @@ -109,19 +110,25 @@ impl Types { (Effect::Error, _) => Ordering::Equal, (_, Effect::Error) => Ordering::Equal, // Assumes canonical order - (Effect::Known(xs), Effect::Known(ys)) => xs.len().cmp(&ys.len()).then_with(|| xs - .into_iter() - .zip(ys) - .fold(Ordering::Equal, |a, (x, y)| a.then_with(|| match (x, y) { - (Ok(EffectInst::Concrete(x_decl, x_args)), Ok(EffectInst::Concrete(y_decl, y_args))) => x_decl - .cmp(&y_decl) - .then_with(|| x_args - .into_iter() - .zip(y_args) - .fold(Ordering::Equal, |a, (x, y)| a.then_with(|| self.cmp_ty(x, y)))), - (Ok(EffectInst::Gen(x, _)), Ok(EffectInst::Gen(y, _))) => x.cmp(&y), - _ => Ordering::Equal, // Errors always equal (bad?) - }))), + (Effect::Known(xs), Effect::Known(ys)) => xs.len().cmp(&ys.len()).then_with(|| { + xs.into_iter().zip(ys).fold(Ordering::Equal, |a, (x, y)| { + a.then_with(|| match (x, y) { + ( + Ok(EffectInst::Concrete(x_decl, x_args)), + Ok(EffectInst::Concrete(y_decl, y_args)), + ) => x_decl.cmp(&y_decl).then_with(|| { + x_args + .into_iter() + .zip(y_args) + .fold(Ordering::Equal, |a, (x, y)| { + a.then_with(|| self.cmp_ty(x, y)) + }) + }), + (Ok(EffectInst::Gen(x, _)), Ok(EffectInst::Gen(y, _))) => x.cmp(&y), + _ => Ordering::Equal, // Errors always equal (bad?) + }) + }) + }), } } @@ -138,28 +145,43 @@ impl Types { (Ty::Prim(x), Ty::Prim(y)) => x.cmp(&y), (Ty::List(x), Ty::List(y)) => self.cmp_ty(x, y), (Ty::Record(_, _), Ty::Record(_, _)) => todo!("Record equality"), - (Ty::Func(x_i, x_o), Ty::Func(y_i, y_o)) => self.cmp_ty(x_i, y_i).then_with(|| self.cmp_ty(x_o, y_o)), - (Ty::Data(x, xs), Ty::Data(y, ys)) => x.cmp(&y).then_with(|| xs - .into_iter() - .zip(ys) - .fold(Ordering::Equal, |a, (x, y)| a.then_with(|| self.cmp_ty(x, y)))), - (Ty::Gen(x, x_scope), Ty::Gen(y, y_scope)) => if x_scope == y_scope { - x.cmp(&y) - } else { - todo!("ordering of generic types in different scopes... does reordering need to occur with every reinstantiation?!") - }, + (Ty::Func(x_i, x_o), Ty::Func(y_i, y_o)) => { + self.cmp_ty(x_i, y_i).then_with(|| self.cmp_ty(x_o, y_o)) + } + (Ty::Data(x, xs), Ty::Data(y, ys)) => x.cmp(&y).then_with(|| { + xs.into_iter().zip(ys).fold(Ordering::Equal, |a, (x, y)| { + a.then_with(|| self.cmp_ty(x, y)) + }) + }), + (Ty::Gen(x, x_scope), Ty::Gen(y, y_scope)) => { + if x_scope == y_scope { + x.cmp(&y) + } else { + todo!("ordering of generic types in different scopes... does reordering need to occur with every reinstantiation?!") + } + } (Ty::SelfType, Ty::SelfType) => Ordering::Equal, // TODO: Check equality of effect parameters? - (Ty::Assoc(x_ty, (x_class_id, x_gen_tys, x_gen_effs), x_name), Ty::Assoc(y_ty, (y_class_id, y_gen_tys, y_gen_effs), y_name)) => self.cmp_ty(x_ty, y_ty) + ( + Ty::Assoc(x_ty, (x_class_id, x_gen_tys, _x_gen_effs), x_name), + Ty::Assoc(y_ty, (y_class_id, y_gen_tys, _y_gen_effs), y_name), + ) => self + .cmp_ty(x_ty, y_ty) .then_with(|| x_class_id.cmp(&y_class_id)) .then_with(|| x_name.cmp(&y_name)) - .then_with(|| x_gen_tys - .into_iter() - .zip(y_gen_tys) - .fold(Ordering::Equal, |a, (x, y)| a.then_with(|| self.cmp_ty(x, y)))), + .then_with(|| { + x_gen_tys + .into_iter() + .zip(y_gen_tys) + .fold(Ordering::Equal, |a, (x, y)| { + a.then_with(|| self.cmp_ty(x, y)) + }) + }), (Ty::Effect(x, x_out), Ty::Effect(y, y_out)) => - // TODO: Actually compare effects - x.cmp(&y).then_with(|| self.cmp_ty(x_out, y_out)), + // TODO: Actually compare effects + { + x.cmp(&y).then_with(|| self.cmp_ty(x_out, y_out)) + } (x, y) => { // Generate an ordering for all other types, fairly arbitrary // Would be nice to use std::mem::Discriminant for this, but it's not ordered @@ -177,11 +199,16 @@ impl Types { }; rank_of(&x).cmp(&rank_of(&y)) - }, + } } } - pub fn has_inhabitants(&self, datas: &Datas, ty: TyId, gen: &mut dyn FnMut(usize) -> bool) -> bool { + pub fn has_inhabitants( + &self, + datas: &Datas, + ty: TyId, + gen: &mut dyn FnMut(usize) -> bool, + ) -> bool { match self.get(ty) { Ty::Error(_) => false, Ty::Prim(_) => true, @@ -190,13 +217,11 @@ impl Types { .into_iter() .all(|(_, field)| self.has_inhabitants(datas, field, gen)), Ty::Func(_, _) => true, - Ty::Data(data, args) => datas - .get_data(data) - .cons - .iter() - .any(|(_, ty)| { - self.has_inhabitants(datas, *ty, &mut |id| self.has_inhabitants(datas, args[id], gen)) - }), + Ty::Data(data, args) => datas.get_data(data).cons.iter().any(|(_, ty)| { + self.has_inhabitants(datas, *ty, &mut |id| { + self.has_inhabitants(datas, args[id], gen) + }) + }), Ty::Gen(id, _) => gen(id), Ty::SelfType => true, Ty::Assoc(_, _, _) => true, @@ -246,14 +271,26 @@ pub struct TyDisplay<'a> { impl<'a> TyDisplay<'a> { fn with_ty(&self, ty: TyId, lhs_exposed: bool) -> Self { - Self { ty: Ok(ty), lhs_exposed, ..self.clone() } + Self { + ty: Ok(ty), + lhs_exposed, + ..self.clone() + } } fn with_eff(&self, eff: EffectId, lhs_exposed: bool) -> Self { - Self { ty: Err(eff), lhs_exposed, ..self.clone() } + Self { + ty: Err(eff), + lhs_exposed, + ..self.clone() + } } - pub fn substitute(mut self, ty: TyId, sub: impl Fn(&mut fmt::Formatter) -> fmt::Result + 'a) -> Self { + pub fn substitute( + mut self, + ty: TyId, + sub: impl Fn(&mut fmt::Formatter) -> fmt::Result + 'a, + ) -> Self { self.substitutes.push((ty, Rc::new(sub))); self } @@ -261,10 +298,7 @@ impl<'a> TyDisplay<'a> { impl<'a> fmt::Display for TyDisplay<'a> { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { - if let Some((_, sub)) = self.substitutes - .iter() - .find(|(ty, _)| Ok(*ty) == self.ty) - { + if let Some((_, sub)) = self.substitutes.iter().find(|(ty, _)| Ok(*ty) == self.ty) { return sub(f); } @@ -275,44 +309,82 @@ impl<'a> fmt::Display for TyDisplay<'a> { Ty::Error(ErrorReason::Invalid) => write!(f, "!"), Ty::Prim(prim) => write!(f, "{}", prim), Ty::List(item) => write!(f, "[{}]", self.with_ty(item, false)), - Ty::Record(fields, is_tuple) => if is_tuple { - write!(f, "({})", fields - .values() - .map(|field| format!("{}", self.with_ty(*field, false))) - .collect::>() - .join(", ")) - } else { - write!(f, "{{ {} }}", fields - .into_iter() - .map(|(name, field)| format!("{}: {}", name, self.with_ty(field, false))) - .collect::>() - .join(", ")) - }, - Ty::Func(i, o) if self.lhs_exposed => write!(f, "({} -> {})", self.with_ty(i, true), self.with_ty(o, self.lhs_exposed)), - Ty::Func(i, o) => write!(f, "{} -> {}", self.with_ty(i, true), self.with_ty(o, self.lhs_exposed)), - Ty::Data(name, params) if self.lhs_exposed && params.len() > 0 => write!(f, "({}{})", *self.ctx.datas.get_data(name).name, params - .iter() - .map(|param| format!(" {}", self.with_ty(*param, true))) - .collect::()), - Ty::Data(name, params) => write!(f, "{}{}", *self.ctx.datas.get_data(name).name, params - .iter() - .map(|param| format!(" {}", self.with_ty(*param, true))) - .collect::()), - Ty::Gen(index, scope) => write!(f, "{}", **self.ctx.tys.get_gen_scope(scope).get(index).name), + Ty::Record(fields, is_tuple) => { + if is_tuple { + write!( + f, + "({})", + fields + .values() + .map(|field| format!("{}", self.with_ty(*field, false))) + .collect::>() + .join(", ") + ) + } else { + write!( + f, + "{{ {} }}", + fields + .into_iter() + .map(|(name, field)| format!( + "{}: {}", + name, + self.with_ty(field, false) + )) + .collect::>() + .join(", ") + ) + } + } + Ty::Func(i, o) if self.lhs_exposed => write!( + f, + "({} -> {})", + self.with_ty(i, true), + self.with_ty(o, self.lhs_exposed) + ), + Ty::Func(i, o) => write!( + f, + "{} -> {}", + self.with_ty(i, true), + self.with_ty(o, self.lhs_exposed) + ), + Ty::Data(name, params) if self.lhs_exposed && !params.is_empty() => write!( + f, + "({}{})", + *self.ctx.datas.get_data(name).name, + params + .iter() + .map(|param| format!(" {}", self.with_ty(*param, true))) + .collect::() + ), + Ty::Data(name, params) => write!( + f, + "{}{}", + *self.ctx.datas.get_data(name).name, + params + .iter() + .map(|param| format!(" {}", self.with_ty(*param, true))) + .collect::() + ), + Ty::Gen(index, scope) => { + write!(f, "{}", **self.ctx.tys.get_gen_scope(scope).get(index).name) + } // TODO: Include class_id? Ty::Assoc(inner, (class_id, gen_tys, gen_effs), assoc) => { - let class = format!("{}{}", *self.ctx.classes.get(class_id).name, gen_tys - .iter() - .map(|ty| format!(" {}", self.with_ty(*ty, true))) - .chain(gen_effs + let class = format!( + "{}{}", + *self.ctx.classes.get(class_id).name, + gen_tys .iter() - .map(|eff| match *eff { + .map(|ty| format!(" {}", self.with_ty(*ty, true))) + .chain(gen_effs.iter().map(|eff| match *eff { Some(eff) => format!(" {}", self.with_eff(eff, true)), - None => format!(" !"), + None => " !".to_string(), })) - .collect::()); + .collect::() + ); write!(f, "<{} as {}>.{}", self.with_ty(inner, true), class, *assoc) - }, + } Ty::SelfType => write!(f, "Self"), Ty::Effect(eff, out) => { if self.lhs_exposed { @@ -324,7 +396,7 @@ impl<'a> fmt::Display for TyDisplay<'a> { write!(f, ")")?; } Ok(()) - }, + } }, Err(eff) => match self.ctx.tys.get_effect(eff) { Effect::Error => write!(f, "!"), @@ -332,12 +404,21 @@ impl<'a> fmt::Display for TyDisplay<'a> { let effs = effs .iter() .map(|eff| match eff { - Ok(EffectInst::Gen(idx, scope)) => format!("{}", **self.ctx.tys.get_gen_scope(*scope).get_eff(*idx).name), - Ok(EffectInst::Concrete(decl, args)) => format!("{}{}", *self.ctx.effects.get_decl(*decl).name, args - .iter() - .map(|arg| format!(" {}", self.with_ty(*arg, true))) - .collect::()), - Err(()) => format!("!"), + Ok(EffectInst::Gen(idx, scope)) => self + .ctx + .tys + .get_gen_scope(*scope) + .get_eff(*idx) + .name + .to_string(), + Ok(EffectInst::Concrete(decl, args)) => format!( + "{}{}", + *self.ctx.effects.get_decl(*decl).name, + args.iter() + .map(|arg| format!(" {}", self.with_ty(*arg, true))) + .collect::() + ), + Err(()) => "!".to_string(), }) .collect::>(); if effs.is_empty() { @@ -345,7 +426,7 @@ impl<'a> fmt::Display for TyDisplay<'a> { } else { write!(f, "{}", effs.join(" + ")) } - }, + } }, } } @@ -405,37 +486,59 @@ impl GenScope { let mut errors = Vec::new(); for gen in &generics.tys { if let Some(old_span) = existing.insert(*gen.name, gen.name.span()) { - errors.push(Error::DuplicateGenName(*gen.name, old_span, gen.name.span())); + errors.push(Error::DuplicateGenName( + *gen.name, + old_span, + gen.name.span(), + )); } } - (Self { - item_span, - types: generics.tys - .iter() - .map(|gen_ty| { - if !mentions_ty(*gen_ty.name) { - errors.push(Error::NotMentioned(gen_ty.name.clone())); - } - GenTy { name: gen_ty.name.clone() } - }) - .collect(), - effects: generics.effs - .iter() - .map(|gen_eff| { - if !mentions_eff(*gen_eff.name) { - errors.push(Error::NotMentioned(gen_eff.name.clone())); - } - GenEff { name: gen_eff.name.clone() } - }) - .collect(), - ast_implied_members: generics.implied_members.clone(), - implied_members: None, - }, errors) + ( + Self { + item_span, + types: generics + .tys + .iter() + .map(|gen_ty| { + if !mentions_ty(*gen_ty.name) { + errors.push(Error::NotMentioned(gen_ty.name.clone())); + } + GenTy { + name: gen_ty.name.clone(), + } + }) + .collect(), + effects: generics + .effs + .iter() + .map(|gen_eff| { + if !mentions_eff(*gen_eff.name) { + errors.push(Error::NotMentioned(gen_eff.name.clone())); + } + GenEff { + name: gen_eff.name.clone(), + } + }) + .collect(), + ast_implied_members: generics.implied_members.clone(), + implied_members: None, + }, + errors, + ) } - pub fn len(&self) -> usize { self.types.len() } - pub fn len_eff(&self) -> usize { self.effects.len() } + pub fn len(&self) -> usize { + self.types.len() + } + + pub fn is_empty(&self) -> bool { + self.len() == 0 + } + + pub fn len_eff(&self) -> usize { + self.effects.len() + } pub fn get(&self, index: usize) -> &GenTy { &self.types[index] @@ -446,10 +549,16 @@ impl GenScope { } pub fn find(&self, name: Ident) -> Option<(usize, &GenTy)> { - self.types.iter().enumerate().find(|(_, ty)| &*ty.name == &name) + self.types + .iter() + .enumerate() + .find(|(_, ty)| *ty.name == name) } pub fn find_eff(&self, name: Ident) -> Option<(usize, &GenEff)> { - self.effects.iter().enumerate().find(|(_, eff)| &*eff.name == &name) + self.effects + .iter() + .enumerate() + .find(|(_, eff)| *eff.name == name) } } diff --git a/cir/src/lib.rs b/cir/src/lib.rs index 80f478c..b94f252 100644 --- a/cir/src/lib.rs +++ b/cir/src/lib.rs @@ -1,4 +1,4 @@ -use tao_util::index::{Index, Id}; +use tao_util::index::{Id, Index}; #[derive(Copy, Clone)] pub struct Reg(usize); @@ -75,6 +75,7 @@ pub struct Func { } #[derive(Clone)] +#[allow(dead_code)] pub struct Program { datas: Index, funcs: Index, diff --git a/compiler/src/error.rs b/compiler/src/error.rs index f832449..576c25f 100644 --- a/compiler/src/error.rs +++ b/compiler/src/error.rs @@ -8,35 +8,32 @@ pub enum Error { impl Error { pub fn write>(self, cache: C, writer: impl Write) { - use ariadne::{Report, ReportKind, Label, Color, Fmt, Span}; + use ariadne::{Color, Fmt, Label, Report, ReportKind, Span}; let (msg, spans, notes) = match self { Error::CannotImport(path) => ( format!("Cannot import {}, no such file", (*path).fg(Color::Red)), - vec![ - (path.span(), format!("Does not exist"), Color::Red), - ], + vec![(path.span(), "Does not exist".to_string(), Color::Red)], vec![format!("The file {} must exist", (*path).fg(Color::Yellow))], ), }; - let mut report = Report::build(ReportKind::Error, spans.first().unwrap().0.src(), spans.first().unwrap().0.start()) - .with_code(3) - .with_message(msg); + let mut report = Report::build( + ReportKind::Error, + spans.first().unwrap().0.src(), + spans.first().unwrap().0.start(), + ) + .with_code(3) + .with_message(msg); for (span, msg, col) in spans { - report = report.with_label(Label::new(span) - .with_message(msg) - .with_color(col)); + report = report.with_label(Label::new(span).with_message(msg).with_color(col)); } for note in notes { report = report.with_note(note); } - report - .finish() - .write(cache, writer) - .unwrap(); + report.finish().write(cache, writer).unwrap(); } } diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index 13b2eba..9852a63 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -1,22 +1,17 @@ mod error; -pub use tao_syntax::SrcId; pub use tao_middle::OptMode; +pub use tao_syntax::SrcId; -use tao_syntax::{parse_module, ast, SrcNode, Error as SyntaxError}; +use ariadne::sources; +use error::Error; +use internment::Intern; +use std::{collections::HashMap, io::Write}; +use structopt::StructOpt; use tao_analysis::Context as HirContext; use tao_middle::Context; +use tao_syntax::{ast, parse_module, Error as SyntaxError, SrcNode}; use tao_vm::Program; -use ariadne::sources; -use structopt::StructOpt; -use internment::Intern; -use std::{ - str::FromStr, - io::Write, - collections::HashMap, - fmt, -}; -use error::Error; #[derive(Clone, Debug, Default, StructOpt)] pub struct Options { @@ -39,7 +34,10 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio let (mut ast, mut syntax_errors) = parse_module(&src, src_id); // TODO: Write a proper module system you lazy git - fn resolve_imports Option, G: FnMut(SrcId, &str) -> Option>( + fn resolve_imports< + F: FnMut(SrcId) -> Option, + G: FnMut(SrcId, &str) -> Option, + >( parent_src: SrcId, module: Option<&mut ast::Module>, imported: &mut HashMap, @@ -52,14 +50,24 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio let imports = std::mem::take(&mut module.imports); for import in imports { - match make_src(parent_src, import.as_str()).and_then(|src_id| Some((src_id, get_file(src_id)?))) { + match make_src(parent_src, import.as_str()) + .and_then(|src_id| Some((src_id, get_file(src_id)?))) + { Some((src_id, src)) => { // Check for cycles if imported.insert(src_id, src.clone()).is_none() { let (mut ast, mut new_syntax_errors) = parse_module(&src, src_id); syntax_errors.append(&mut new_syntax_errors); - resolve_imports(src_id, ast.as_deref_mut(), imported, import_errors, syntax_errors, get_file, make_src); + resolve_imports( + src_id, + ast.as_deref_mut(), + imported, + import_errors, + syntax_errors, + get_file, + make_src, + ); if let Some(mut ast) = ast { let mut old_items = std::mem::take(&mut module.items); @@ -67,7 +75,7 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio module.items.append(&mut old_items); } } - }, + } None => import_errors.push(Error::CannotImport(import.clone())), } } @@ -77,7 +85,15 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio // Resolve imports let mut imported = HashMap::new(); let mut import_errors = Vec::new(); - resolve_imports(src_id, ast.as_deref_mut(), &mut imported, &mut import_errors, &mut syntax_errors, &mut get_file, &mut make_src); + resolve_imports( + src_id, + ast.as_deref_mut(), + &mut imported, + &mut import_errors, + &mut syntax_errors, + &mut get_file, + &mut make_src, + ); let mut srcs = sources(imported.into_iter().chain(std::iter::once((src_id, src)))); if !import_errors.is_empty() { for e in import_errors { @@ -97,7 +113,7 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio } if let Some(ast) = ast { - let (ctx, mut analysis_errors) = HirContext::from_module(&ast); + let (ctx, analysis_errors) = HirContext::from_module(&ast); if options.debug.contains(&"hir".to_string()) { for (_, def) in ctx.defs.iter() { @@ -107,10 +123,7 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio #[cfg(feature = "debug")] if options.debug.contains(&"call_graph".to_string()) { - ctx - .generate_call_graph() - .render_to(&mut writer) - .unwrap(); + ctx.generate_call_graph().render_to(&mut writer).unwrap(); } if !analysis_errors.is_empty() || syntax_error { @@ -119,7 +132,7 @@ pub fn compile Option, G: FnMut(SrcId, &str) -> Optio } None } else { - let (concrete, mut con_errors) = ctx.concretize(); + let (concrete, con_errors) = ctx.concretize(); if !con_errors.is_empty() { for e in con_errors { diff --git a/compiler/src/main.rs b/compiler/src/main.rs index 23e9ed3..315a379 100644 --- a/compiler/src/main.rs +++ b/compiler/src/main.rs @@ -1,8 +1,8 @@ -use tao::{Options, SrcId, compile}; -use tao_vm::{exec, Env}; -use structopt::StructOpt; -use std::{fs, path::PathBuf}; use rand::prelude::*; +use std::{fs, path::PathBuf}; +use structopt::StructOpt; +use tao::{compile, Options, SrcId}; +use tao_vm::{exec, Env}; #[derive(Clone, Debug, StructOpt)] pub struct Args { @@ -38,8 +38,7 @@ impl Env for Stdio { fn main() { let args = Args::from_args(); - let src = fs::read_to_string(&args.file) - .expect("Failed to read file"); + let src = fs::read_to_string(&args.file).expect("Failed to read file"); let src_id = SrcId::from_path(args.file); let prog = compile( src, diff --git a/compiler/tests/tester.rs b/compiler/tests/tester.rs index 9ba1a0a..3380c70 100644 --- a/compiler/tests/tester.rs +++ b/compiler/tests/tester.rs @@ -11,8 +11,8 @@ test!(math); test!(lists); test!(records); -use tao::{Options, OptMode, SrcId, run}; use std::fs; +use tao::{run, OptMode, Options, SrcId}; fn test_configs(name: &str) { fn test_config(name: &str, options: Options) { @@ -33,46 +33,53 @@ fn test_configs(name: &str) { let mut state = State::Start; for line in src.lines().chain(std::iter::once("# >>>> END")) { match &state { - State::Start | State::Output => if line.trim() == "# >>>> INPUT" || line.trim() == "# >>>> END" { - if let State::Output = &state { - let mut output = Vec::new(); - run( - input.clone(), - src_id, - options.clone(), - &mut output, - |src| fs::read_to_string(src.to_path()).ok(), - |parent, rel| { - let mut path = parent.to_path(); - path.pop(); - path.push(rel); - let path = path.canonicalize().ok()?; - Some(SrcId::from_path(path)) - }, - ); - let output = String::from_utf8(output).unwrap(); - if output.trim() != expected.trim() { - panic!("\n\n \ + State::Start | State::Output => { + if line.trim() == "# >>>> INPUT" || line.trim() == "# >>>> END" { + if let State::Output = &state { + let mut output = Vec::new(); + run( + input.clone(), + src_id, + options.clone(), + &mut output, + |src| fs::read_to_string(src.to_path()).ok(), + |parent, rel| { + let mut path = parent.to_path(); + path.pop(); + path.push(rel); + let path = path.canonicalize().ok()?; + Some(SrcId::from_path(path)) + }, + ); + let output = String::from_utf8(output).unwrap(); + if output.trim() != expected.trim() { + panic!( + "\n\n \ ========[ EXPECTED OUTPUT ]========\n\n\ {}\n \ ========[ FOUND OUTPUT ]========\n\n\ - {}\n", expected, output); - } + {}\n", + expected, output + ); + } - input.clear(); - expected.clear(); + input.clear(); + expected.clear(); + } + state = State::Input; + } else { + expected += line; + expected += "\n"; + } + } + State::Input => { + if line.trim() == "# >>>> OUTPUT" { + state = State::Output; + } else { + input += line; + input += "\n"; } - state = State::Input; - } else { - expected += line; - expected += "\n"; - }, - State::Input => if line.trim() == "# >>>> OUTPUT" { - state = State::Output; - } else { - input += line; - input += "\n"; - }, + } } } } diff --git a/middle/src/context.rs b/middle/src/context.rs index c6fcb2e..12cf4f1 100644 --- a/middle/src/context.rs +++ b/middle/src/context.rs @@ -48,7 +48,7 @@ impl Context { opt::ConstFold { inline: !matches!(opt_mode, OptMode::Size), } - .run(self, debug); + .run(self, debug); opt::RemoveUnusedBindings::default().run(self, debug); opt::RemoveDeadProc::default().run(self, debug); } diff --git a/middle/src/error.rs b/middle/src/error.rs index 98e7595..2561654 100644 --- a/middle/src/error.rs +++ b/middle/src/error.rs @@ -9,50 +9,60 @@ pub enum Error { } impl Error { - pub fn write>(self, ctx: &Context, cache: C, writer: impl Write) { - use ariadne::{Report, ReportKind, Label, Color, Fmt, Span}; + pub fn write>(self, _ctx: &Context, cache: C, writer: impl Write) { + use ariadne::{Color, Fmt, Label, Report, ReportKind, Span}; let (msg, spans, notes) = match self { Error::NoEntryPoint(root_span) => ( - format!("No main definition"), - vec![(root_span, format!("Does not contain a definition marked as the main entry point"), Color::Red)], - vec![format!("Mark a definition as the main entry point with {}", "$[main]".fg(Color::Blue))], + "No main definition".to_string(), + vec![( + root_span, + "Does not contain a definition marked as the main entry point".to_string(), + Color::Red, + )], + vec![format!( + "Mark a definition as the main entry point with {}", + "$[main]".fg(Color::Blue) + )], ), Error::MultipleEntryPoints(a, b) => ( - format!("Multiple entry points"), + "Multiple entry points".to_string(), vec![ - (a, format!("First entry point is here"), Color::Red), - (b, format!("Second entry point is here"), Color::Red), + (a, "First entry point is here".to_string(), Color::Red), + (b, "Second entry point is here".to_string(), Color::Red), ], - vec![format!("A program may only have a single entry point")], + vec!["A program may only have a single entry point".to_string()], ), Error::GenericEntryPoint(name, gen, entry) => ( format!("Entry point {} cannot be generic", (*name).fg(Color::Red)), vec![ - (gen, format!("Generics are not allowed here"), Color::Red), - (entry, format!("Declared as an entry point because of this attribute"), Color::Yellow), + (gen, "Generics are not allowed here".to_string(), Color::Red), + ( + entry, + "Declared as an entry point because of this attribute".to_string(), + Color::Yellow, + ), ], - vec![format!("A program cannot be generic over types")], + vec!["A program cannot be generic over types".to_string()], ), }; - let mut report = Report::build(ReportKind::Error, spans.first().unwrap().0.src(), spans.first().unwrap().0.start()) - .with_code(3) - .with_message(msg); + let mut report = Report::build( + ReportKind::Error, + spans.first().unwrap().0.src(), + spans.first().unwrap().0.start(), + ) + .with_code(3) + .with_message(msg); for (span, msg, col) in spans { - report = report.with_label(Label::new(span) - .with_message(msg) - .with_color(col)); + report = report.with_label(Label::new(span).with_message(msg).with_color(col)); } for note in notes { report = report.with_note(note); } - report - .finish() - .write(cache, writer) - .unwrap(); + report.finish().write(cache, writer).unwrap(); } } diff --git a/middle/src/lib.rs b/middle/src/lib.rs index c337c8d..774c4ff 100644 --- a/middle/src/lib.rs +++ b/middle/src/lib.rs @@ -1,49 +1,30 @@ -#![feature(arbitrary_self_types, cell_update, never_type, drain_filter, let_else)] +#![feature(arbitrary_self_types, cell_update, never_type, drain_filter)] +pub mod context; pub mod error; -pub mod proc; +pub mod lower; pub mod mir; pub mod opt; +pub mod proc; pub mod repr; -pub mod lower; -pub mod context; pub use crate::{ + context::{Context, OptMode}, error::Error, + mir::{Binding, Expr, Handler, Intrinsic, Literal, Local, MirNode, Partial, Pat}, opt::Pass, - proc::{ProcId, Proc, Procs}, - mir::{MirNode, Pat, Binding, Expr, Handler, Literal, Partial, Intrinsic, Local}, - repr::{Repr, Reprs, Prim, Data}, - context::{Context, OptMode}, + proc::{Proc, ProcId, Procs}, + repr::{Data, Prim, Repr, Reprs}, }; pub use tao_analysis::Ident; -use tao_syntax::{ - Node, - Span, - SrcId, - SrcNode, - ast, -}; +use hashbrown::{HashSet}; + +use std::collections::{BTreeMap, BTreeSet}; use tao_analysis::{ - hir, - TyNode, - ty, - DefId, - Context as HirContext, - data::DataId, - ConProc, - ConProcId, - ConContext, - ConExpr, - ConBinding, - ConTy, - ConTyId, - ConDataId, - ConEffectId, + hir, ty, ConBinding, ConContext, ConDataId, ConEffectId, ConExpr, + ConProcId, ConTy, ConTyId, Context as HirContext, }; -use hashbrown::{HashMap, HashSet}; -use internment::Intern; -use std::collections::{BTreeMap, BTreeSet}; +use tao_syntax::{Node, Span, SrcId, SrcNode}; pub type EffectId = ConEffectId; diff --git a/middle/src/lower.rs b/middle/src/lower.rs index c51190f..32faa00 100644 --- a/middle/src/lower.rs +++ b/middle/src/lower.rs @@ -8,7 +8,7 @@ pub struct TyInsts<'a> { impl Context { pub fn lower_proc(&mut self, hir: &HirContext, con: &ConContext, proc: ConProcId) -> ProcId { - let id = self.procs.id_of_con(proc.clone()); + let id = self.procs.id_of_con(proc); // Instantiate proc if not already done if !self.procs.is_declared(id) { @@ -22,7 +22,12 @@ impl Context { id } - pub fn lower_litr(&mut self, hir: &HirContext, con: &ConContext, litr: &hir::Literal) -> mir::Literal { + pub fn lower_litr( + &mut self, + _hir: &HirContext, + _con: &ConContext, + litr: &hir::Literal, + ) -> mir::Literal { match litr { hir::Literal::Nat(x) => mir::Literal::Nat(*x), hir::Literal::Int(x) => mir::Literal::Int(*x), @@ -40,10 +45,13 @@ impl Context { .iter() .map(|(_, ty)| self.lower_ty(hir, con, *ty)) .collect(); - self.reprs.define(data, Data { - is_recursive: con_data.is_recursive, - repr: Repr::Sum(variants), - }); + self.reprs.define( + data, + Data { + is_recursive: con_data.is_recursive, + repr: Repr::Sum(variants), + }, + ); } data } @@ -67,31 +75,52 @@ impl Context { Box::new(self.lower_ty(hir, con, *o)), ), ConTy::Data(data_id) => Repr::Data(self.lower_data(hir, con, *data_id)), - ConTy::Record(fields) => Repr::Tuple(fields.iter().map(|(_, field)| self.lower_ty(hir, con, *field)).collect()), - ConTy::Effect(effs, out) => Repr::Effect(effs.clone(), Box::new(self.lower_ty(hir, con, *out))), + ConTy::Record(fields) => Repr::Tuple( + fields + .iter() + .map(|(_, field)| self.lower_ty(hir, con, *field)) + .collect(), + ), + ConTy::Effect(effs, out) => { + Repr::Effect(effs.clone(), Box::new(self.lower_ty(hir, con, *out))) + } } } - pub fn lower_binding(&mut self, hir: &HirContext, con: &ConContext, con_binding: &ConBinding, bindings: &mut Vec<(Ident, Local)>) -> mir::MirNode { + pub fn lower_binding( + &mut self, + hir: &HirContext, + con: &ConContext, + con_binding: &ConBinding, + bindings: &mut Vec<(Ident, Local)>, + ) -> mir::MirNode { let pat = match &*con_binding.pat { hir::Pat::Error => unreachable!(), hir::Pat::Wildcard => mir::Pat::Wildcard, hir::Pat::Literal(litr) => mir::Pat::Literal(self.lower_litr(hir, con, litr)), - hir::Pat::Single(inner) => mir::Pat::Single(self.lower_binding(hir, con, inner, bindings)), - hir::Pat::Add(lhs, rhs) => mir::Pat::Add(self.lower_binding(hir, con, lhs, bindings), **rhs), - hir::Pat::ListExact(items) => mir::Pat::ListExact(items - .iter() - .map(|item| self.lower_binding(hir, con, item, bindings)) - .collect()), + hir::Pat::Single(inner) => { + mir::Pat::Single(self.lower_binding(hir, con, inner, bindings)) + } + hir::Pat::Add(lhs, rhs) => { + mir::Pat::Add(self.lower_binding(hir, con, lhs, bindings), **rhs) + } + hir::Pat::ListExact(items) => mir::Pat::ListExact( + items + .iter() + .map(|item| self.lower_binding(hir, con, item, bindings)) + .collect(), + ), hir::Pat::ListFront(items, tail) => mir::Pat::ListFront( items .iter() .map(|item| self.lower_binding(hir, con, item, bindings)) .collect(), - tail.as_ref().map(|tail| self.lower_binding(hir, con, tail, bindings)), + tail.as_ref() + .map(|tail| self.lower_binding(hir, con, tail, bindings)), ), hir::Pat::Decons(data, variant, inner) => { - let variant = hir.datas + let variant = hir + .datas .get_data(data.data_id()) .cons .iter() @@ -101,23 +130,28 @@ impl Context { .0; self.lower_data(hir, con, *data); let pat = mir::Pat::Variant(variant, self.lower_binding(hir, con, inner, bindings)); - mir::Pat::Data(*data, MirNode::new(mir::Binding { pat, name: None }, self.reprs.get(*data).repr.clone())) - }, + mir::Pat::Data( + *data, + MirNode::new( + mir::Binding { pat, name: None }, + self.reprs.get(*data).repr.clone(), + ), + ) + } hir::Pat::Record(fields, _) => { let mut fields = fields .iter() .map(|(name, field)| (*name, self.lower_binding(hir, con, field, bindings))) .collect::>(); - fields.sort_by_key(|(name, _)| name.as_ref()); + fields.sort_by_key(|(name, _)| name.as_string()); mir::Pat::Tuple(fields.into_iter().map(|(_, field)| field).collect()) - }, - pat => todo!("{:?}", pat), + } }; let binding = mir::Binding { pat, name: if let Some(name) = &con_binding.name { - let local = Local::new(); + let local = Local::default(); bindings.push((**name, local)); Some(local) } else { @@ -128,17 +162,27 @@ impl Context { MirNode::new(binding, self.lower_ty(hir, con, *con_binding.meta())) } - pub fn lower_expr(&mut self, hir: &HirContext, con: &ConContext, con_expr: &ConExpr, stack: &mut Vec<(Ident, Local)>) -> mir::MirNode { + pub fn lower_expr( + &mut self, + hir: &HirContext, + con: &ConContext, + con_expr: &ConExpr, + stack: &mut Vec<(Ident, Local)>, + ) -> mir::MirNode { let expr = match &**con_expr { hir::Expr::Error => unreachable!(), hir::Expr::Literal(litr) => mir::Expr::Literal(self.lower_litr(hir, con, litr)), - hir::Expr::Local(local) => mir::Expr::Local(stack - .iter() - .rev() - .find(|(name, _)| name == local) - .expect("No such local") - .1), - hir::Expr::Global(proc) => mir::Expr::Global(self.lower_proc(hir, con, *proc), Default::default()), + hir::Expr::Local(local) => mir::Expr::Local( + stack + .iter() + .rev() + .find(|(name, _)| name == local) + .expect("No such local") + .1, + ), + hir::Expr::Global(proc) => { + mir::Expr::Global(self.lower_proc(hir, con, *proc), Default::default()) + } hir::Expr::Match(_, pred, arms) => { let arms = arms .iter() @@ -151,12 +195,14 @@ impl Context { }) .collect(); mir::Expr::Match(self.lower_expr(hir, con, pred, stack), arms) - }, + } hir::Expr::List(items, tails) => { - let mut list = mir::Expr::List(items - .iter() - .map(|item| self.lower_expr(hir, con, item, stack)) - .collect()); + let mut list = mir::Expr::List( + items + .iter() + .map(|item| self.lower_expr(hir, con, item, stack)) + .collect(), + ); for tail in tails { let tail = self.lower_expr(hir, con, tail, stack); @@ -165,26 +211,30 @@ impl Context { Repr::List(item) => (**item).clone(), _ => unreachable!(), }), - vec![ - MirNode::new(list, tail.meta().clone()), - tail, - ], + vec![MirNode::new(list, tail.meta().clone()), tail], ); } list - }, + } hir::Expr::Func(arg, body) => { - let arg_local = Local::new(); + let arg_local = Local::default(); stack.push((**arg, arg_local)); let body = self.lower_expr(hir, con, body, stack); stack.pop(); - mir::Expr::Func(MirNode::new(arg_local, self.lower_ty(hir, con, *arg.meta())), body) - }, - hir::Expr::Apply(f, arg) => mir::Expr::Apply(self.lower_expr(hir, con, f, stack), self.lower_expr(hir, con, arg, stack)), + mir::Expr::Func( + MirNode::new(arg_local, self.lower_ty(hir, con, *arg.meta())), + body, + ) + } + hir::Expr::Apply(f, arg) => mir::Expr::Apply( + self.lower_expr(hir, con, f, stack), + self.lower_expr(hir, con, arg, stack), + ), hir::Expr::Cons(data, variant, inner) => { - let variant = hir.datas + let variant = hir + .datas .get_data(data.data_id()) .cons .iter() @@ -194,14 +244,24 @@ impl Context { .0; self.lower_data(hir, con, *data); let expr = mir::Expr::Variant(variant, self.lower_expr(hir, con, inner, stack)); - mir::Expr::Data(*data, MirNode::new(expr, self.reprs.get(*data).repr.clone())) - }, + mir::Expr::Data( + *data, + MirNode::new(expr, self.reprs.get(*data).repr.clone()), + ) + } hir::Expr::Access(record, field) => { - let (record_ty, _, indirections) = con.follow_field_access(hir, *record.meta(), **field).unwrap(); + let (record_ty, _, indirections) = con + .follow_field_access(hir, *record.meta(), **field) + .unwrap(); let field_idx = if let ConTy::Record(fields) = con.get_ty(record_ty) { let mut fields = fields.iter().map(|(name, _)| *name).collect::>(); - fields.sort_by_key(|name| name.as_ref()); - fields.iter().enumerate().find(|(_, name)| **name == **field).unwrap().0 + fields.sort_by_key(|name| name.as_string()); + fields + .iter() + .enumerate() + .find(|(_, name)| **name == **field) + .unwrap() + .0 } else { unreachable!(); }; @@ -222,118 +282,200 @@ impl Context { } mir::Expr::Access(record, field_idx) - }, + } hir::Expr::Record(fields, _) => { let mut fields = fields .iter() .map(|(name, field)| (**name, self.lower_expr(hir, con, field, stack))) .collect::>(); - fields.sort_by_key(|(name, _)| name.as_ref()); + fields.sort_by_key(|(name, _)| name.as_string()); mir::Expr::Tuple(fields.into_iter().map(|(_, field)| field).collect()) - }, - hir::Expr::ClassAccess(ty, class, field) => panic!("Class access should not still exist during MIR lowering"), + } + hir::Expr::ClassAccess(_ty, _class, _field) => { + panic!("Class access should not still exist during MIR lowering") + } hir::Expr::Intrinsic(name, args) => { match name.inner() { hir::Intrinsic::TypeName => { - let name = match con.get_ty(*args.first().expect("type_name intrinsic must have an argument").meta()) { + let name = match con.get_ty( + *args + .first() + .expect("type_name intrinsic must have an argument") + .meta(), + ) { ConTy::List(inner) => con.display(hir, *inner).to_string(), _ => panic!("type_name argument must be list of type"), }; - mir::Expr::Literal(mir::Literal::List(name.chars().map(mir::Literal::Char).collect())) - }, - hir::Intrinsic::NegNat => mir::Expr::Intrinsic(mir::Intrinsic::NegNat, vec![self.lower_expr(hir, con, &args[0], stack)]), - hir::Intrinsic::NegInt => mir::Expr::Intrinsic(mir::Intrinsic::NegInt, vec![self.lower_expr(hir, con, &args[0], stack)]), - hir::Intrinsic::NegReal => mir::Expr::Intrinsic(mir::Intrinsic::NegReal, vec![self.lower_expr(hir, con, &args[0], stack)]), - hir::Intrinsic::DisplayInt => mir::Expr::Intrinsic(mir::Intrinsic::DisplayInt, vec![self.lower_expr(hir, con, &args[0], stack)]), - hir::Intrinsic::CodepointChar => mir::Expr::Intrinsic(mir::Intrinsic::CodepointChar, vec![self.lower_expr(hir, con, &args[0], stack)]), - hir::Intrinsic::EqChar => mir::Expr::Intrinsic(mir::Intrinsic::EqChar, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::EqNat => mir::Expr::Intrinsic(mir::Intrinsic::EqNat, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::LessNat => mir::Expr::Intrinsic(mir::Intrinsic::LessNat, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::AddNat => mir::Expr::Intrinsic(mir::Intrinsic::AddNat, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::AddInt => mir::Expr::Intrinsic(mir::Intrinsic::AddInt, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::MulNat => mir::Expr::Intrinsic(mir::Intrinsic::MulNat, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::MulInt => mir::Expr::Intrinsic(mir::Intrinsic::MulInt, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), + mir::Expr::Literal(mir::Literal::List( + name.chars().map(mir::Literal::Char).collect(), + )) + } + hir::Intrinsic::NegNat => mir::Expr::Intrinsic( + mir::Intrinsic::NegNat, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::NegInt => mir::Expr::Intrinsic( + mir::Intrinsic::NegInt, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::NegReal => mir::Expr::Intrinsic( + mir::Intrinsic::NegReal, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::DisplayInt => mir::Expr::Intrinsic( + mir::Intrinsic::DisplayInt, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::CodepointChar => mir::Expr::Intrinsic( + mir::Intrinsic::CodepointChar, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::EqChar => mir::Expr::Intrinsic( + mir::Intrinsic::EqChar, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::EqNat => mir::Expr::Intrinsic( + mir::Intrinsic::EqNat, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::LessNat => mir::Expr::Intrinsic( + mir::Intrinsic::LessNat, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::AddNat => mir::Expr::Intrinsic( + mir::Intrinsic::AddNat, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::AddInt => mir::Expr::Intrinsic( + mir::Intrinsic::AddInt, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::MulNat => mir::Expr::Intrinsic( + mir::Intrinsic::MulNat, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::MulInt => mir::Expr::Intrinsic( + mir::Intrinsic::MulInt, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), hir::Intrinsic::Go => { - let next_local = Local::new(); + let next_local = Local::default(); let func = self.lower_expr(hir, con, &args[0], stack); let next = self.lower_expr(hir, con, &args[1], stack); - let output_repr = if let Repr::Func(_, o) = func.meta() { (**o).clone() } else { unreachable!() }; + let output_repr = if let Repr::Func(_, o) = func.meta() { + (**o).clone() + } else { + unreachable!() + }; mir::Expr::Go( MirNode::new(next_local, next.meta().clone()), - MirNode::new(mir::Expr::Apply(func, MirNode::new(mir::Expr::Local(next_local), next.meta().clone())), output_repr), + MirNode::new( + mir::Expr::Apply( + func, + MirNode::new(mir::Expr::Local(next_local), next.meta().clone()), + ), + output_repr, + ), next, ) - }, - hir::Intrinsic::Print => mir::Expr::Intrinsic(mir::Intrinsic::Print, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::Input => mir::Expr::Intrinsic(mir::Intrinsic::Input, vec![ - self.lower_expr(hir, con, &args[0], stack), - ]), - hir::Intrinsic::Rand => mir::Expr::Intrinsic(mir::Intrinsic::Rand, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::LenList => mir::Expr::Intrinsic(mir::Intrinsic::LenList, vec![ - self.lower_expr(hir, con, &args[0], stack), - ]), - hir::Intrinsic::SkipList => mir::Expr::Intrinsic(mir::Intrinsic::SkipList, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), - hir::Intrinsic::TrimList => mir::Expr::Intrinsic(mir::Intrinsic::TrimList, vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]), + } + hir::Intrinsic::Print => mir::Expr::Intrinsic( + mir::Intrinsic::Print, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::Input => mir::Expr::Intrinsic( + mir::Intrinsic::Input, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::Rand => mir::Expr::Intrinsic( + mir::Intrinsic::Rand, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::LenList => mir::Expr::Intrinsic( + mir::Intrinsic::LenList, + vec![self.lower_expr(hir, con, &args[0], stack)], + ), + hir::Intrinsic::SkipList => mir::Expr::Intrinsic( + mir::Intrinsic::SkipList, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), + hir::Intrinsic::TrimList => mir::Expr::Intrinsic( + mir::Intrinsic::TrimList, + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ), hir::Intrinsic::JoinList => { let Repr::List(item_repr) = self.lower_ty(hir, con, *args[0].meta()) else { panic!("Joining non-lists!") }; - mir::Expr::Intrinsic(mir::Intrinsic::Join(*item_repr), vec![ - self.lower_expr(hir, con, &args[0], stack), - self.lower_expr(hir, con, &args[1], stack), - ]) - }, + mir::Expr::Intrinsic( + mir::Intrinsic::Join(*item_repr), + vec![ + self.lower_expr(hir, con, &args[0], stack), + self.lower_expr(hir, con, &args[1], stack), + ], + ) + } hir::Intrinsic::Propagate => match con.get_ty(*args[0].meta()) { - ConTy::Effect(effs, _) => mir::Expr::Intrinsic(mir::Intrinsic::Propagate(effs.clone()), vec![ - self.lower_expr(hir, con, &args[0], stack), - ]), + ConTy::Effect(effs, _) => mir::Expr::Intrinsic( + mir::Intrinsic::Propagate(effs.clone()), + vec![self.lower_expr(hir, con, &args[0], stack)], + ), _ => unreachable!(), // _ => self.lower_expr(hir, con, &args[0], stack).into_inner(), }, - hir::Intrinsic::Dispatch => panic!("Type dispatching should have occurred during concretisation!"), + hir::Intrinsic::Dispatch => { + panic!("Type dispatching should have occurred during concretisation!") + } } - }, + } hir::Expr::Update(record, fields) => { let mut mir_record = self.lower_expr(hir, con, record, stack); for (field_name, field) in fields { - let (record_ty, _, indirections) = con.follow_field_access(hir, *record.meta(), **field_name).unwrap(); + let (record_ty, _, indirections) = con + .follow_field_access(hir, *record.meta(), **field_name) + .unwrap(); let field_idx = if let ConTy::Record(fields) = con.get_ty(record_ty) { let mut fields = fields.iter().map(|(name, _)| *name).collect::>(); - fields.sort_by_key(|name| name.as_ref()); - fields.iter().enumerate().find(|(_, name)| **name == **field_name).unwrap().0 + fields.sort_by_key(|name| name.as_string()); + fields + .iter() + .enumerate() + .find(|(_, name)| **name == **field_name) + .unwrap() + .0 } else { unreachable!(); }; @@ -351,14 +493,22 @@ impl Context { } else { unreachable!() }; - mir_record = MirNode::new(mir::Expr::AccessData(mir_record, data), Repr::Data(data)); - mir_record = MirNode::new(mir::Expr::AccessVariant(mir_record, 0), variant_repr); + mir_record = + MirNode::new(mir::Expr::AccessData(mir_record, data), Repr::Data(data)); + mir_record = + MirNode::new(mir::Expr::AccessVariant(mir_record, 0), variant_repr); } // Update field let record_repr = mir_record.meta().clone(); let field = self.lower_expr(hir, con, field, stack); - mir_record = MirNode::new(mir::Expr::Intrinsic(Intrinsic::UpdateField(field_idx), vec![mir_record, field]), record_repr); + mir_record = MirNode::new( + mir::Expr::Intrinsic( + Intrinsic::UpdateField(field_idx), + vec![mir_record, field], + ), + record_repr, + ); // Re-wrap the record for (data, sum_repr) in datas.into_iter().rev() { @@ -368,8 +518,10 @@ impl Context { } mir_record.into_inner() - }, - hir::Expr::Basin(effs, inner) => mir::Expr::Basin(effs.clone(), self.lower_expr(hir, con, inner, stack)), + } + hir::Expr::Basin(effs, inner) => { + mir::Expr::Basin(effs.clone(), self.lower_expr(hir, con, inner, stack)) + } hir::Expr::Handle { expr, handlers } => { let expr = self.lower_expr(hir, con, expr, stack); let expr_repr = expr.meta().clone(); @@ -379,45 +531,76 @@ impl Context { let handlers = handlers .iter() - .map(|hir::Handler { eff, send, state, recv }| { - let send_local = Local::new(); - let state_local = Local::new(); - is_state = state.is_some(); - mir::Handler { - eff: *eff, - send: MirNode::new(send_local, self.lower_ty(hir, con, *send.meta())), - state: state.as_ref() - .map(|state| MirNode::new(state_local, self.lower_ty(hir, con, *state.meta()))) - .unwrap_or(MirNode::new(state_local, default_state_repr.clone())), - recv: { - let old_len = stack.len(); - stack.push((**send, send_local)); - if let Some(state) = state { - stack.push((**state, state_local)); - } - let recv = if state.is_none() { - let out = self.lower_expr(hir, con, recv, stack); - let out_repr = out.meta().clone(); - MirNode::new(mir::Expr::Tuple(vec![ - out, - MirNode::new(mir::Expr::Tuple(Vec::new()), default_state_repr.clone()) - ]), Repr::Tuple(vec![out_repr, default_state_repr.clone()])) - } else { - self.lower_expr(hir, con, recv, stack) - }; - stack.truncate(old_len); - recv - }, - } - }) + .map( + |hir::Handler { + eff, + send, + state, + recv, + }| { + let send_local = Local::default(); + let state_local = Local::default(); + is_state = state.is_some(); + mir::Handler { + eff: *eff, + send: MirNode::new( + send_local, + self.lower_ty(hir, con, *send.meta()), + ), + state: state + .as_ref() + .map(|state| { + MirNode::new( + state_local, + self.lower_ty(hir, con, *state.meta()), + ) + }) + .unwrap_or(MirNode::new( + state_local, + default_state_repr.clone(), + )), + recv: { + let old_len = stack.len(); + stack.push((**send, send_local)); + if let Some(state) = state { + stack.push((**state, state_local)); + } + let recv = if state.is_none() { + let out = self.lower_expr(hir, con, recv, stack); + let out_repr = out.meta().clone(); + MirNode::new( + mir::Expr::Tuple(vec![ + out, + MirNode::new( + mir::Expr::Tuple(Vec::new()), + default_state_repr.clone(), + ), + ]), + Repr::Tuple(vec![out_repr, default_state_repr.clone()]), + ) + } else { + self.lower_expr(hir, con, recv, stack) + }; + stack.truncate(old_len); + recv + }, + } + }, + ) .collect(); let handler = mir::Expr::Handle { expr: if !is_state { - MirNode::new(mir::Expr::Tuple(vec![ - expr, - MirNode::new(mir::Expr::Tuple(Vec::new()), default_state_repr.clone()) - ]), Repr::Tuple(vec![expr_repr.clone(), default_state_repr.clone()])) + MirNode::new( + mir::Expr::Tuple(vec![ + expr, + MirNode::new( + mir::Expr::Tuple(Vec::new()), + default_state_repr.clone(), + ), + ]), + Repr::Tuple(vec![expr_repr.clone(), default_state_repr.clone()]), + ) } else { expr }, @@ -427,19 +610,26 @@ impl Context { if is_state { handler } else { - mir::Expr::Access(MirNode::new(handler, Repr::Tuple(vec![ - if let Repr::Effect(_, out) = expr_repr { - (*out).clone() - } else { - unreachable!() - }, - default_state_repr.clone(), - ])), 1) + mir::Expr::Access( + MirNode::new( + handler, + Repr::Tuple(vec![ + if let Repr::Effect(_, out) = expr_repr { + (*out).clone() + } else { + unreachable!() + }, + default_state_repr, + ]), + ), + 1, + ) } - }, - hir::Expr::Suspend(eff, inner) => mir::Expr::Intrinsic(mir::Intrinsic::Suspend(*eff), vec![ - self.lower_expr(hir, con, inner, stack), - ]), + } + hir::Expr::Suspend(eff, inner) => mir::Expr::Intrinsic( + mir::Intrinsic::Suspend(*eff), + vec![self.lower_expr(hir, con, inner, stack)], + ), }; MirNode::new(expr, self.lower_ty(hir, con, *con_expr.meta())) diff --git a/middle/src/mir.rs b/middle/src/mir.rs index ca19e1d..46d0f91 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -1,10 +1,7 @@ //! The MIR is *not* correct (in the context of Tao's abstract machine) by construction. See the 'SAFETY' notes. use super::*; -use std::{ - cell::Cell, - fmt, -}; +use std::{cell::Cell, fmt}; pub type EffectId = ConEffectId; @@ -36,9 +33,27 @@ pub type Literal = Const; pub type Partial = Const>; impl Const { - pub fn nat(&self) -> u64 { if let Const::Nat(x) = self { *x } else { panic!("{:?}", self) } } - pub fn int(&self) -> i64 { if let Const::Int(x) = self { *x } else { panic!("{:?}", self) } } - pub fn list(&self) -> Vec { if let Const::List(x) = self { x.clone() } else { panic!("{:?}", self) } } + pub fn nat(&self) -> u64 { + if let Const::Nat(x) = self { + *x + } else { + panic!("{:?}", self) + } + } + pub fn int(&self) -> i64 { + if let Const::Int(x) = self { + *x + } else { + panic!("{:?}", self) + } + } + pub fn list(&self) -> Vec { + if let Const::List(x) = self { + x.clone() + } else { + panic!("{:?}", self) + } + } } impl Partial { @@ -50,14 +65,18 @@ impl Partial { Self::Int(x) => Some(Literal::Int(*x)), Self::Real(x) => Some(Literal::Real(*x)), Self::Char(c) => Some(Literal::Char(*c)), - Self::Tuple(fields) => Some(Literal::Tuple(fields - .iter() - .map(|field| field.to_literal()) - .collect::>()?)), - Self::List(items) => Some(Literal::List(items - .iter() - .map(|item| item.to_literal()) - .collect::>()?)), + Self::Tuple(fields) => Some(Literal::Tuple( + fields + .iter() + .map(|field| field.to_literal()) + .collect::>()?, + )), + Self::List(items) => Some(Literal::List( + items + .iter() + .map(|item| item.to_literal()) + .collect::>()?, + )), Self::Sum(v, inner) => Some(Literal::Sum(*v, Box::new(inner.to_literal()?))), Self::Data(data, inner) => Some(Literal::Data(*data, Box::new(inner.to_literal()?))), } @@ -75,16 +94,12 @@ impl Partial { (Self::Int(x), Self::Int(y)) if x == y => Self::Int(x), (Self::Real(x), Self::Real(y)) if x == y => Self::Real(x), (Self::Char(x), Self::Char(y)) if x == y => Self::Char(x), - (Self::Tuple(xs), Self::Tuple(ys)) => Self::Tuple(xs - .into_iter() - .zip(ys) - .map(|(x, y)| x.or(y)) - .collect()), - (Self::List(xs), Self::List(ys)) if xs.len() == ys.len() => Self::List(xs - .into_iter() - .zip(ys) - .map(|(x, y)| x.or(y)) - .collect()), + (Self::Tuple(xs), Self::Tuple(ys)) => { + Self::Tuple(xs.into_iter().zip(ys).map(|(x, y)| x.or(y)).collect()) + } + (Self::List(xs), Self::List(ys)) if xs.len() == ys.len() => { + Self::List(xs.into_iter().zip(ys).map(|(x, y)| x.or(y)).collect()) + } (Self::Sum(a, x), Self::Sum(b, y)) if a == b => Self::Sum(a, Box::new(x.or(*y))), (Self::Data(a, x), Self::Data(b, y)) if a == b => Self::Data(a, Box::new(x.or(*y))), _ => Self::Unknown(None), @@ -101,14 +116,12 @@ impl Literal { Self::Int(x) => Partial::Int(*x), Self::Real(x) => Partial::Real(*x), Self::Char(c) => Partial::Char(*c), - Self::Tuple(fields) => Partial::Tuple(fields - .iter() - .map(|field| field.to_partial()) - .collect()), - Self::List(items) => Partial::List(items - .iter() - .map(|item| item.to_partial()) - .collect()), + Self::Tuple(fields) => { + Partial::Tuple(fields.iter().map(|field| field.to_partial()).collect()) + } + Self::List(items) => { + Partial::List(items.iter().map(|item| item.to_partial()).collect()) + } Self::Sum(v, inner) => Partial::Sum(*v, Box::new(inner.to_partial())), Self::Data(data, inner) => Partial::Data(*data, Box::new(inner.to_partial())), } @@ -126,8 +139,22 @@ impl fmt::Display for Literal { Self::Char('\t') => write!(f, "'\\t'"), Self::Char('\n') => write!(f, "'\\n'"), Self::Char(c) => write!(f, "'{}'", c), - Self::Tuple(xs) => write!(f, "({})", xs.iter().map(|x| format!("{},", x)).collect::>().join(" ")), - Self::List(xs) => write!(f, "[{}]", xs.iter().map(|x| format!("{}", x)).collect::>().join(", ")), + Self::Tuple(xs) => write!( + f, + "({})", + xs.iter() + .map(|x| format!("{},", x)) + .collect::>() + .join(" ") + ), + Self::List(xs) => write!( + f, + "[{}]", + xs.iter() + .map(|x| format!("{}", x)) + .collect::>() + .join(", ") + ), Self::Sum(v, x) => write!(f, "#{} {}", v, x), Self::Data(data, x) => write!(f, "{:?} {}", data, x), } @@ -192,8 +219,8 @@ pub enum Pat { #[derive(Copy, Clone, Debug, PartialEq, Eq)] pub struct Local(pub usize); -impl Local { - pub fn new() -> Self { +impl Default for Local { + fn default() -> Self { use core::sync::atomic::{AtomicUsize, Ordering}; static ID: AtomicUsize = AtomicUsize::new(0); Self(ID.fetch_add(1, Ordering::Relaxed)) @@ -217,41 +244,36 @@ impl Binding { pub fn is_refutable(&self) -> bool { match &self.pat { Pat::Wildcard => false, - Pat::Literal(c) => match c { - Const::Tuple(fields) if fields.is_empty() => false, - _ => true, - }, + Pat::Literal(c) => !matches!(c, Const::Tuple(fields) if fields.is_empty()), Pat::Single(inner) => inner.is_refutable(), Pat::Add(lhs, rhs) => *rhs > 0 || lhs.is_refutable(), - Pat::Tuple(fields) => fields - .iter() - .any(|field| field.is_refutable()), + Pat::Tuple(fields) => fields.iter().any(|field| field.is_refutable()), Pat::ListExact(_) => true, - Pat::ListFront(items, tail) => items.len() > 0 || tail.as_ref().map_or(false, |tail| tail.is_refutable()), + Pat::ListFront(items, tail) => { + !items.is_empty() || tail.as_ref().map_or(false, |tail| tail.is_refutable()) + } Pat::Variant(_, _) => true, // TODO: Check number of variants Pat::Data(_, inner) => inner.is_refutable(), } } - fn visit_bindings(self: &MirNode, mut bind: &mut impl FnMut(Local, &Repr)) { - self.name.map(|name| bind(name, self.meta())); + fn visit_bindings(self: &MirNode, bind: &mut impl FnMut(Local, &Repr)) { + if let Some(name) = self.name { + bind(name, self.meta()); + } match &self.pat { - Pat::Wildcard => {}, - Pat::Literal(_) => {}, + Pat::Wildcard => {} + Pat::Literal(_) => {} Pat::Single(inner) => inner.visit_bindings(bind), Pat::Add(lhs, _) => lhs.visit_bindings(bind), - Pat::Tuple(fields) => fields - .iter() - .for_each(|field| field.visit_bindings(bind)), - Pat::ListExact(items) => items - .iter() - .for_each(|item| item.visit_bindings(bind)), + Pat::Tuple(fields) => fields.iter().for_each(|field| field.visit_bindings(bind)), + Pat::ListExact(items) => items.iter().for_each(|item| item.visit_bindings(bind)), Pat::ListFront(items, tail) => { - items - .iter() - .for_each(|item| item.visit_bindings(bind)); - tail.as_ref().map(|tail| tail.visit_bindings(bind)); - }, + items.iter().for_each(|item| item.visit_bindings(bind)); + if let Some(tail) = tail.as_ref() { + tail.visit_bindings(bind); + } + } Pat::Variant(_, inner) => inner.visit_bindings(bind), Pat::Data(_, inner) => inner.visit_bindings(bind), } @@ -277,7 +299,12 @@ impl Binding { fn refresh_locals_inner(&mut self, stack: &mut Vec<(Local, Local)>) { if let Some(name) = self.name { - let new_name = stack.iter().rev().find(|(old, _)| *old == name).expect("No such local").1; + let new_name = stack + .iter() + .rev() + .find(|(old, _)| *old == name) + .expect("No such local") + .1; self.name = Some(new_name); } self.for_children_mut(|expr| expr.refresh_locals_inner(stack)); @@ -293,17 +320,12 @@ impl Binding { Pat::Literal(_) => true, Pat::Single(inner) => inner.has_matches(ctx), Pat::Add(inner, _) => inner.has_matches(ctx), - Pat::Tuple(xs) => xs - .iter() - .all(|x| x.has_matches(ctx)), - Pat::ListExact(xs) => xs - .iter() - .all(|x| x.has_matches(ctx)), - Pat::ListFront(xs, tail) => xs - .iter() - .all(|x| x.has_matches(ctx)) && tail - .as_ref() - .map_or(true, |tail| tail.has_matches(ctx)), + Pat::Tuple(xs) => xs.iter().all(|x| x.has_matches(ctx)), + Pat::ListExact(xs) => xs.iter().all(|x| x.has_matches(ctx)), + Pat::ListFront(xs, tail) => { + xs.iter().all(|x| x.has_matches(ctx)) + && tail.as_ref().map_or(true, |tail| tail.has_matches(ctx)) + } Pat::Variant(_, inner) => inner.has_matches(ctx), Pat::Data(_, inner) => inner.has_matches(ctx), } @@ -320,9 +342,7 @@ pub struct GlobalFlags { impl Default for GlobalFlags { fn default() -> Self { - Self { - can_inline: true, - } + Self { can_inline: true } } } @@ -386,7 +406,7 @@ impl Expr { } pub fn refresh_locals(&mut self) { - let required = self.required_locals(None); + let _required = self.required_locals(None); // debug_assert_eq!(required.len(), 0, "Cannot refresh locals for an expression\n\n{}\n\nthat captures (required = {:?})", self.print(), required); self.refresh_locals_inner(&mut Vec::new()); } @@ -394,43 +414,53 @@ impl Expr { fn refresh_locals_inner(&mut self, stack: &mut Vec<(Local, Local)>) { match self { Expr::Local(local) => { - let new_local = stack.iter().rev().find(|(old, _)| old == local) - .unwrap_or_else(|| panic!("No such local ${} in {:?}", local.0, stack)).1; + let new_local = stack + .iter() + .rev() + .find(|(old, _)| old == local) + .unwrap_or_else(|| panic!("No such local ${} in {:?}", local.0, stack)) + .1; *local = new_local; - }, + } Expr::Match(pred, arms) => { pred.refresh_locals_inner(stack); for (binding, arm) in arms { let old_stack = stack.len(); - binding.visit_bindings(&mut |name, _| stack.push((name, Local::new()))); + binding.visit_bindings(&mut |name, _| stack.push((name, Local::default()))); binding.refresh_locals_inner(stack); arm.refresh_locals_inner(stack); stack.truncate(old_stack); } - }, + } Expr::Func(arg, body) => { - let new_arg = Local::new(); + let new_arg = Local::default(); stack.push((**arg, new_arg)); body.refresh_locals_inner(stack); stack.pop(); **arg = new_arg; - }, + } Expr::Go(next, body, init) => { init.refresh_locals_inner(stack); - let new_init = Local::new(); + let new_init = Local::default(); stack.push((**next, new_init)); body.refresh_locals_inner(stack); stack.pop(); **next = new_init; - }, + } Expr::Handle { expr, handlers } => { expr.refresh_locals_inner(stack); - for Handler { eff, send, state, recv } in handlers { - let new_send = Local::new(); - let new_state = Local::new(); + for Handler { + eff: _, + send, + state, + recv, + } in handlers + { + let new_send = Local::default(); + let new_state = Local::default(); let old_len = stack.len(); stack.push((**send, new_send)); stack.push((**state, new_state)); @@ -439,21 +469,21 @@ impl Expr { **send = new_send; **state = new_state; } - }, + } _ => self.for_children_mut(|expr| expr.refresh_locals_inner(stack)), } } fn required_locals_inner(&self, stack: &mut Vec, required: &mut Vec) { match self { - Expr::Undefined => {}, - Expr::Literal(_) => {}, + Expr::Undefined => {} + Expr::Literal(_) => {} Expr::Local(local) => { if !stack.contains(local) { required.push(*local); } - }, - Expr::Global(_, _) => {}, + } + Expr::Global(_, _) => {} Expr::Intrinsic(_, args) => args .iter() .for_each(|arg| arg.required_locals_inner(stack, required)), @@ -467,22 +497,22 @@ impl Expr { stack.truncate(old_stack); } - }, + } Expr::Func(arg, body) => { stack.push(**arg); body.required_locals_inner(stack, required); stack.pop(); - }, + } Expr::Go(next, body, init) => { init.required_locals_inner(stack, required); stack.push(**next); body.required_locals_inner(stack, required); stack.pop(); - }, + } Expr::Apply(f, arg) => { f.required_locals_inner(stack, required); arg.required_locals_inner(stack, required); - }, + } Expr::Tuple(fields) => fields .iter() .for_each(|field| field.required_locals_inner(stack, required)), @@ -497,14 +527,20 @@ impl Expr { Expr::Basin(_, inner) => inner.required_locals_inner(stack, required), Expr::Handle { expr, handlers } => { expr.required_locals_inner(stack, required); - for Handler { eff, send, state, recv } in handlers { + for Handler { + eff: _, + send, + state, + recv, + } in handlers + { let old_len = stack.len(); stack.push(**send); stack.push(**state); recv.required_locals_inner(stack, required); stack.truncate(old_len); } - }, + } } } @@ -519,33 +555,30 @@ impl Expr { match self { Expr::Undefined => false, Expr::Literal(_) => false, - Expr::Local(local) => false, + Expr::Local(_local) => false, Expr::Global(_, _) => false, Expr::Intrinsic(Intrinsic::Propagate(_), _) => true, - Expr::Intrinsic(_, args) => args - .iter() - .any(|arg| arg.may_have_effect()), - Expr::Match(pred, arms) => pred.may_have_effect() || arms - .iter() - .any(|(_, body)| body.may_have_effect()), + Expr::Intrinsic(_, args) => args.iter().any(|arg| arg.may_have_effect()), + Expr::Match(pred, arms) => { + pred.may_have_effect() || arms.iter().any(|(_, body)| body.may_have_effect()) + } Expr::Func(_, _) => false, - Expr::Go(next, body, init) => init.may_have_effect() || body.may_have_effect(), + Expr::Go(_next, body, init) => init.may_have_effect() || body.may_have_effect(), Expr::Apply(f, arg) => f.may_have_effect() || arg.may_have_effect(), - Expr::Tuple(fields) => fields - .iter() - .any(|field| field.may_have_effect()), - Expr::List(items) => items - .iter() - .any(|item| item.may_have_effect()), + Expr::Tuple(fields) => fields.iter().any(|field| field.may_have_effect()), + Expr::List(items) => items.iter().any(|item| item.may_have_effect()), Expr::Access(tuple, _) => tuple.may_have_effect(), Expr::Variant(_, inner) => inner.may_have_effect(), Expr::AccessVariant(inner, _) => inner.may_have_effect(), Expr::Data(_, inner) => inner.may_have_effect(), Expr::AccessData(inner, _) => inner.may_have_effect(), - Expr::Basin(_, inner) => false, - Expr::Handle { expr, handlers } => expr.may_have_effect() || handlers - .iter() - .any(|Handler { recv, .. }| recv.may_have_effect()), + Expr::Basin(_, _inner) => false, + Expr::Handle { expr, handlers } => { + expr.may_have_effect() + || handlers + .iter() + .any(|Handler { recv, .. }| recv.may_have_effect()) + } } } @@ -566,18 +599,43 @@ impl Expr { Pat::Wildcard => write!(f, "_"), Pat::Literal(c) => write!(f, "{}", c), Pat::Single(inner) => write!(f, "{}", DisplayBinding(inner, self.1)), - Pat::Variant(variant, inner) => write!(f, "#{} {}", variant, DisplayBinding(inner, self.1)), - Pat::ListExact(items) => write!(f, "[{}]", items.iter().map(|i| format!("{},", DisplayBinding(i, self.1 + 1))).collect::>().join(" ")), + Pat::Variant(variant, inner) => { + write!(f, "#{} {}", variant, DisplayBinding(inner, self.1)) + } + Pat::ListExact(items) => write!( + f, + "[{}]", + items + .iter() + .map(|i| format!("{},", DisplayBinding(i, self.1 + 1))) + .collect::>() + .join(" ") + ), Pat::ListFront(items, tail) => write!( f, "[{} .. {}]", - items.iter().map(|i| format!("{},", DisplayBinding(i, self.1))).collect::>().join(" "), - tail.as_ref().map(|tail| format!("{}", DisplayBinding(tail, self.1))).unwrap_or_default(), + items + .iter() + .map(|i| format!("{},", DisplayBinding(i, self.1))) + .collect::>() + .join(" "), + tail.as_ref() + .map(|tail| format!("{}", DisplayBinding(tail, self.1))) + .unwrap_or_default(), + ), + Pat::Tuple(fields) => write!( + f, + "({})", + fields + .iter() + .map(|f| format!("{},", DisplayBinding(f, self.1))) + .collect::>() + .join(" ") ), - Pat::Tuple(fields) => write!(f, "({})", fields.iter().map(|f| format!("{},", DisplayBinding(f, self.1))).collect::>().join(" ")), Pat::Add(inner, n) => write!(f, "{} + {}", DisplayBinding(inner, self.1), n), - Pat::Data(data, inner) => write!(f, "{:?} {}", data, DisplayBinding(inner, self.1)), - pat => todo!("{:?}", pat), + Pat::Data(data, inner) => { + write!(f, "{:?} {}", data, DisplayBinding(inner, self.1)) + } } } } @@ -594,70 +652,227 @@ impl Expr { Expr::Local(local) => write!(f, "${}", local.0), Expr::Global(global, _) => write!(f, "{:?}", global), Expr::Literal(c) => write!(f, "{}", c), - Expr::Func(arg, body) => write!(f, "fn ${} =>\n{}", arg.0, DisplayExpr(body, self.1 + 1, true)), - Expr::Go(next, body, init) => write!(f, "go(${} => {}, {})", next.0, DisplayExpr(body, self.1, false), DisplayExpr(init, self.1, false)), - Expr::Apply(func, arg) => write!(f, "({})({})", DisplayExpr(func, self.1, false), DisplayExpr(arg, self.1, false)), - Expr::Variant(variant, inner) => write!(f, "#{} {}", variant, DisplayExpr(inner, self.1, false)), - Expr::Tuple(fields) => write!(f, "({})", fields.iter().map(|f| format!("{},", DisplayExpr(f, self.1, false))).collect::>().join(" ")), - Expr::List(items) => write!(f, "[{}]", items.iter().map(|i| format!("{}", DisplayExpr(i, self.1 + 1, false))).collect::>().join(", ")), - Expr::Intrinsic(NegNat | NegInt | NegReal, args) => write!(f, "- {}", DisplayExpr(&args[0], self.1, false)), - Expr::Intrinsic(DisplayInt, args) => write!(f, "@display_int({})", DisplayExpr(&args[0], self.1, false)), - Expr::Intrinsic(CodepointChar, args) => write!(f, "@codepoint_char({})", DisplayExpr(&args[0], self.1, false)), - Expr::Intrinsic(EqChar | EqNat | EqInt, args) => write!(f, "{} = {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(AddNat | AddInt, args) => write!(f, "{} + {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(SubNat | SubInt, args) => write!(f, "{} - {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(MulNat | MulInt, args) => write!(f, "{} * {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(LessNat, args) => write!(f, "{} < {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(MoreNat, args) => write!(f, "{} > {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(MoreEqNat, args) => write!(f, "{} >= {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(LessEqNat, args) => write!(f, "{} <= {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(Join(_), args) => write!(f, "{} ++ {}", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(Print, args) => write!(f, "@print({}, {})", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(Input, args) => write!(f, "@input({})", DisplayExpr(&args[0], self.1, false)), - Expr::Intrinsic(Rand, args) => write!(f, "@rand({}, {})", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(UpdateField(idx), args) => write!(f, "@update_field<{}>({}, {})", idx, DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(LenList, args) => write!(f, "@len_list({})", DisplayExpr(&args[0], self.1, false)), - Expr::Intrinsic(SkipList, args) => write!(f, "@skip_list({}, {})", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(TrimList, args) => write!(f, "@trim_list({}, {})", DisplayExpr(&args[0], self.1, false), DisplayExpr(&args[1], self.1, false)), - Expr::Intrinsic(Suspend(eff), args) => write!(f, "@suspend::<{:?}>({})", eff.0, DisplayExpr(&args[0], self.1, false)), - Expr::Intrinsic(Propagate(_), args) => write!(f, "{}!", DisplayExpr(&args[0], self.1, false)), + Expr::Func(arg, body) => write!( + f, + "fn ${} =>\n{}", + arg.0, + DisplayExpr(body, self.1 + 1, true) + ), + Expr::Go(next, body, init) => write!( + f, + "go(${} => {}, {})", + next.0, + DisplayExpr(body, self.1, false), + DisplayExpr(init, self.1, false) + ), + Expr::Apply(func, arg) => write!( + f, + "({})({})", + DisplayExpr(func, self.1, false), + DisplayExpr(arg, self.1, false) + ), + Expr::Variant(variant, inner) => { + write!(f, "#{} {}", variant, DisplayExpr(inner, self.1, false)) + } + Expr::Tuple(fields) => write!( + f, + "({})", + fields + .iter() + .map(|f| format!("{},", DisplayExpr(f, self.1, false))) + .collect::>() + .join(" ") + ), + Expr::List(items) => write!( + f, + "[{}]", + items + .iter() + .map(|i| format!("{}", DisplayExpr(i, self.1 + 1, false))) + .collect::>() + .join(", ") + ), + Expr::Intrinsic(NegNat | NegInt | NegReal, args) => { + write!(f, "- {}", DisplayExpr(&args[0], self.1, false)) + } + Expr::Intrinsic(DisplayInt, args) => { + write!(f, "@display_int({})", DisplayExpr(&args[0], self.1, false)) + } + Expr::Intrinsic(CodepointChar, args) => write!( + f, + "@codepoint_char({})", + DisplayExpr(&args[0], self.1, false) + ), + Expr::Intrinsic(EqChar | EqNat | EqInt, args) => write!( + f, + "{} = {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(AddNat | AddInt, args) => write!( + f, + "{} + {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(SubNat | SubInt, args) => write!( + f, + "{} - {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(MulNat | MulInt, args) => write!( + f, + "{} * {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(LessNat, args) => write!( + f, + "{} < {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(MoreNat, args) => write!( + f, + "{} > {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(MoreEqNat, args) => write!( + f, + "{} >= {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(LessEqNat, args) => write!( + f, + "{} <= {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(Join(_), args) => write!( + f, + "{} ++ {}", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(Print, args) => write!( + f, + "@print({}, {})", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(Input, args) => { + write!(f, "@input({})", DisplayExpr(&args[0], self.1, false)) + } + Expr::Intrinsic(Rand, args) => write!( + f, + "@rand({}, {})", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(UpdateField(idx), args) => write!( + f, + "@update_field<{}>({}, {})", + idx, + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(LenList, args) => { + write!(f, "@len_list({})", DisplayExpr(&args[0], self.1, false)) + } + Expr::Intrinsic(SkipList, args) => write!( + f, + "@skip_list({}, {})", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(TrimList, args) => write!( + f, + "@trim_list({}, {})", + DisplayExpr(&args[0], self.1, false), + DisplayExpr(&args[1], self.1, false) + ), + Expr::Intrinsic(Suspend(eff), args) => write!( + f, + "@suspend::<{:?}>({})", + eff.0, + DisplayExpr(&args[0], self.1, false) + ), + Expr::Intrinsic(Propagate(_), args) => { + write!(f, "{}!", DisplayExpr(&args[0], self.1, false)) + } Expr::Match(pred, arms) if arms.len() == 1 => { let (arm, body) = &arms[0]; - write!(f, "let {} = {} in\n{}", DisplayBinding(arm, self.1 + 1), DisplayExpr(pred, self.1, false), DisplayExpr(body, self.1, true)) - }, + write!( + f, + "let {} = {} in\n{}", + DisplayBinding(arm, self.1 + 1), + DisplayExpr(pred, self.1, false), + DisplayExpr(body, self.1, true) + ) + } Expr::Match(pred, arms) => { write!(f, "match {} in", DisplayExpr(pred, self.1 + 1, false))?; for (i, (arm, body)) in arms.iter().enumerate() { let start = if i + 1 == arms.len() { '\\' } else { '|' }; - write!(f, "\n{}{} {} => {}", " ".repeat(self.1 + 1), start, DisplayBinding(arm, self.1 + 1), DisplayExpr(body, self.1 + 1, false))?; + write!( + f, + "\n{}{} {} => {}", + " ".repeat(self.1 + 1), + start, + DisplayBinding(arm, self.1 + 1), + DisplayExpr(body, self.1 + 1, false) + )?; } - if arms.len() == 0 { + if arms.is_empty() { write!(f, " (no arms)")?; } Ok(()) - }, - Expr::Basin(eff, inner) => write!(f, "effect {{\n{}\n{}}}", DisplayExpr(inner, self.1 + 1, true), " ".repeat(self.1)), + } + Expr::Basin(_eff, inner) => write!( + f, + "effect {{\n{}\n{}}}", + DisplayExpr(inner, self.1 + 1, true), + " ".repeat(self.1) + ), Expr::Handle { expr, handlers } => write!( f, "{}\n{}", DisplayExpr(expr, self.1, false), handlers .iter() - .map(|Handler { eff, send, state, recv }| format!( - "{}handle {:?} with ${}, ${} =>\n{}", - " ".repeat(self.1 + 1), - eff, - send.0, - state.0, - DisplayExpr(recv, self.1 + 1, true), - )) + .map( + |Handler { + eff, + send, + state, + recv, + }| format!( + "{}handle {:?} with ${}, ${} =>\n{}", + " ".repeat(self.1 + 1), + eff, + send.0, + state.0, + DisplayExpr(recv, self.1 + 1, true), + ) + ) .collect::>() .join("\n"), ), - Expr::Access(inner, field) => write!(f, "({}).{}", DisplayExpr(inner, self.1, false), field), - Expr::AccessVariant(inner, variant) => write!(f, "({}).#{}", DisplayExpr(inner, self.1, false), variant), - Expr::Data(data, inner) => write!(f, "{:?} {}", data, DisplayExpr(inner, self.1, false)), - Expr::AccessData(inner, data) => write!(f, "{}.#{:?}", DisplayExpr(inner, self.1, false), data), + Expr::Access(inner, field) => { + write!(f, "({}).{}", DisplayExpr(inner, self.1, false), field) + } + Expr::AccessVariant(inner, variant) => { + write!(f, "({}).#{}", DisplayExpr(inner, self.1, false), variant) + } + Expr::Data(data, inner) => { + write!(f, "{:?} {}", data, DisplayExpr(inner, self.1, false)) + } + Expr::AccessData(inner, data) => { + write!(f, "{}.#{:?}", DisplayExpr(inner, self.1, false), data) + } // _ => write!(f, ""), expr => todo!("{:?}", expr), } diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index dc11bc8..ab39a94 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -11,7 +11,12 @@ pub struct ConstFold { impl ConstFold { // Returns `true` if the branch *could* still match the partial value and the partial value has inhabitants. If // `false` is returned, there's no saying what was or wasn't added to the locals. - fn extract(&self, ctx: &Context, binding: &mut MirNode, partial: &Partial, locals: &mut Vec<(Local, Partial)>) -> bool { + fn extract( + ctx: &Context, + binding: &mut MirNode, + partial: &Partial, + locals: &mut Vec<(Local, Partial)>, + ) -> bool { if let Some(name) = binding.name { locals.push((name, partial.clone())); } @@ -24,65 +29,74 @@ impl ConstFold { binding.for_children_mut(|binding| { // TODO: This will become unsound if or patterns are ever added because it assumes that all child // patterns are and patterns. - matches &= self.extract(ctx, binding, &Partial::Unknown(None), locals); + matches &= ConstFold::extract(ctx, binding, &Partial::Unknown(None), locals); }); matches } else { match (&mut binding.pat, partial) { (Pat::Wildcard, _) => true, - (Pat::Literal(litr), partial) => if let Some(rhs) = partial.to_literal() { - litr == &rhs - } else { - true - }, - (Pat::Single(inner), partial) => self.extract(ctx, inner, partial, locals), - (Pat::Variant(variant, x), Partial::Sum(tag, y)) => if variant == tag { - self.extract(ctx, x, y, locals) - } else { - false - }, - (Pat::Tuple(xs), Partial::Tuple(ys)) => { - debug_assert_eq!(xs.len(), ys.len()); - xs - .iter_mut() - .zip(ys.iter()) - .all(|(x, y)| self.extract(ctx, x, y, locals)) - }, - (Pat::ListExact(xs), Partial::List(ys)) => if xs.len() != ys.len() { - false - } else { - xs - .iter_mut() - .zip(ys.iter()) - .all(|(x, y)| self.extract(ctx, x, y, locals)) - }, - (Pat::ListFront(xs, tail), Partial::List(ys)) => if ys.len() < xs.len() { - false - } else { - let could_match_tail = if let Some(tail) = tail { - self.extract(ctx, tail, &Partial::List(ys[xs.len()..].to_vec()), locals) + (Pat::Literal(litr), partial) => { + if let Some(rhs) = partial.to_literal() { + litr == &rhs } else { true - }; - could_match_tail && xs - .iter_mut() + } + } + (Pat::Single(inner), partial) => ConstFold::extract(ctx, inner, partial, locals), + (Pat::Variant(variant, x), Partial::Sum(tag, y)) => { + if variant == tag { + ConstFold::extract(ctx, x, y, locals) + } else { + false + } + } + (Pat::Tuple(xs), Partial::Tuple(ys)) => { + debug_assert_eq!(xs.len(), ys.len()); + xs.iter_mut() .zip(ys.iter()) - .all(|(x, y)| self.extract(ctx, x, y, locals)) - }, - (Pat::Add(inner, n), partial) => if let Some(rhs) = partial.to_literal() { - let rhs = rhs.nat(); - if rhs >= *n { - self.extract(ctx, inner, &Partial::Nat(rhs - *n), locals) + .all(|(x, y)| ConstFold::extract(ctx, x, y, locals)) + } + (Pat::ListExact(xs), Partial::List(ys)) => { + if xs.len() != ys.len() { + false } else { + xs.iter_mut() + .zip(ys.iter()) + .all(|(x, y)| ConstFold::extract(ctx, x, y, locals)) + } + } + (Pat::ListFront(xs, tail), Partial::List(ys)) => { + if ys.len() < xs.len() { false + } else { + let could_match_tail = if let Some(tail) = tail { + ConstFold::extract(ctx, tail, &Partial::List(ys[xs.len()..].to_vec()), locals) + } else { + true + }; + could_match_tail + && xs + .iter_mut() + .zip(ys.iter()) + .all(|(x, y)| ConstFold::extract(ctx, x, y, locals)) } - } else { - true - }, + } + (Pat::Add(inner, n), partial) => { + if let Some(rhs) = partial.to_literal() { + let rhs = rhs.nat(); + if rhs >= *n { + ConstFold::extract(ctx, inner, &Partial::Nat(rhs - *n), locals) + } else { + false + } + } else { + true + } + } (Pat::Data(a, inner), Partial::Data(b, partial)) => { debug_assert_eq!(a, b); - self.extract(ctx, inner, partial, locals) - }, + ConstFold::extract(ctx, inner, partial, locals) + } (p, v) => todo!("Pattern:\n\n{:?}\n\nPartial:\n\n{:?}\n\n", p, v), } } @@ -101,20 +115,24 @@ impl ConstFold { .clone() { // If the local is still accessible, we can just inline it directly - Partial::Unknown(Some(local)) if locals.iter().find(|(name, _)| *name == local).is_some() => { + Partial::Unknown(Some(local)) + if locals.iter().any(|(name, _)| *name == local) => + { *expr = Expr::Local(local); - return Partial::Unknown(Some(local)) - }, + return Partial::Unknown(Some(local)); + } partial => partial, }, - Expr::Global(proc_id, flags) => if flags.get().can_inline && self.inline { - *expr = ctx.procs.get(*proc_id).unwrap().body.inner().clone(); - expr.refresh_locals(); - // Return directly, since we apply to itself - return self.eval(ctx, expr, &mut Vec::new()) - } else { - Partial::Unknown(None) - }, + Expr::Global(proc_id, flags) => { + if flags.get().can_inline && self.inline { + *expr = ctx.procs.get(*proc_id).unwrap().body.inner().clone(); + expr.refresh_locals(); + // Return directly, since we apply to itself + return self.eval(ctx, expr, &mut Vec::new()); + } else { + Partial::Unknown(None) + } + } Expr::Match(pred, arms) => { let pred = self.eval(ctx, pred, locals); let mut output = Partial::Never; @@ -122,11 +140,12 @@ impl ConstFold { // Remove arms that cannot possibly match .drain_filter(|(binding, arm)| { let old_locals = locals.len(); - let cull = if self.extract(ctx, binding, &pred, locals) { + let cull = if ConstFold::extract(ctx, binding, &pred, locals) { let arm_output = self.eval(ctx, arm, locals); // Combine outputs together in an attempt to unify their values - output = std::mem::replace(&mut output, Partial::Unknown(None)).or(arm_output); + output = std::mem::replace(&mut output, Partial::Unknown(None)) + .or(arm_output); false } else { @@ -139,7 +158,7 @@ impl ConstFold { }) .for_each(|_| {}); output - }, + } Expr::Func(arg, body) => { if ctx.reprs.has_inhabitants(arg.meta()) { locals.push((**arg, Partial::Unknown(Some(**arg)))); @@ -149,7 +168,7 @@ impl ConstFold { **body = Expr::Undefined; } Partial::Unknown(None) // TODO: Turn into a `Partial::Func` if no captures - }, + } Expr::Go(next, body, init) => { self.eval(ctx, init, locals); @@ -158,16 +177,22 @@ impl ConstFold { locals.pop(); Partial::Unknown(None) - }, - Expr::Variant(variant, inner) => Partial::Sum(*variant, Box::new(self.eval(ctx, inner, locals))), - Expr::Tuple(fields) => Partial::Tuple(fields - .iter_mut() - .map(|field| self.eval(ctx, field, locals)) - .collect()), - Expr::List(items) => Partial::List(items - .iter_mut() - .map(|item| self.eval(ctx, item, locals)) - .collect()), + } + Expr::Variant(variant, inner) => { + Partial::Sum(*variant, Box::new(self.eval(ctx, inner, locals))) + } + Expr::Tuple(fields) => Partial::Tuple( + fields + .iter_mut() + .map(|field| self.eval(ctx, field, locals)) + .collect(), + ), + Expr::List(items) => Partial::List( + items + .iter_mut() + .map(|item| self.eval(ctx, item, locals)) + .collect(), + ), Expr::Apply(f, arg) => { self.eval(ctx, f, locals); self.eval(ctx, arg, locals); @@ -176,20 +201,23 @@ impl ConstFold { if let Expr::Func(param, body) = &mut **f { *expr = Expr::Match( arg.clone(), - vec![(MirNode::new(Binding::wildcard(**param), arg.meta().clone()), body.clone())], + vec![( + MirNode::new(Binding::wildcard(**param), arg.meta().clone()), + body.clone(), + )], ); - return self.eval(ctx, expr, locals) + return self.eval(ctx, expr, locals); } else { Partial::Unknown(None) } - }, + } Expr::Intrinsic(intrinsic, args) => { let args = args .iter_mut() .map(|arg| self.eval(ctx, arg, locals)) .collect::>(); intrinsic.eval(ctx, &args) - }, + } Expr::Access(tuple, field) => { let tuple = self.eval(ctx, tuple, locals); if let Partial::Tuple(mut fields) = tuple { @@ -197,7 +225,7 @@ impl ConstFold { } else { Partial::Unknown(None) } - }, + } Expr::AccessVariant(inner, variant) => { let inner = self.eval(ctx, inner, locals); if let Partial::Sum(tag, inner) = inner { @@ -206,11 +234,11 @@ impl ConstFold { } else { Partial::Unknown(None) } - }, + } Expr::Data(data, inner) => { let inner = self.eval(ctx, inner, locals); Partial::Data(*data, Box::new(inner)) - }, + } Expr::AccessData(inner, data) => { let inner = self.eval(ctx, inner, locals); if let Partial::Data(id, inner) = inner { @@ -219,15 +247,18 @@ impl ConstFold { } else { Partial::Unknown(None) } - }, + } Expr::Basin(_, inner) => { self.eval(ctx, inner, locals); Partial::Unknown(None) - }, + } Expr::Handle { expr, handlers } => { self.eval(ctx, expr, locals); - for Handler { send, state, recv, .. } in handlers { + for Handler { + send, state, recv, .. + } in handlers + { let old_len = locals.len(); locals.push((**send, Partial::Unknown(Some(**send)))); locals.push((**state, Partial::Unknown(Some(**state)))); @@ -236,23 +267,22 @@ impl ConstFold { } Partial::Unknown(None) - }, - e => todo!("{:?}", e), + } }; - let partial = match partial { + match partial { // If the partial output of this expression is a local found in the enclosing expression, just refer to it // directly. - Partial::Unknown(local) if local - .map_or(false, |local| locals - .iter() - .find(|(l, _)| *l == local) - .is_some()) => { + Partial::Unknown(local) + if local.map_or(false, |local| { + locals.iter().any(|(l, _)| *l == local) + }) => + { if !expr.may_have_effect() { *expr = Expr::Local(local.unwrap()); } partial - }, + } partial => { // Otherwise, if the partial is just a literal, use the literal directly. if let Some(literal) = partial.to_literal() { @@ -261,10 +291,8 @@ impl ConstFold { } } partial - }, - }; - - partial + } + } } } @@ -285,15 +313,19 @@ impl Intrinsic { }; } - let r#bool = |x| Data( - ctx.reprs.r#bool.expect("bool type must be known here"), - Box::new(Sum(x as usize, Box::new(Tuple(Vec::new())))), - ); + let r#bool = |x| { + Data( + ctx.reprs.r#bool.expect("bool type must be known here"), + Box::new(Sum(x as usize, Box::new(Tuple(Vec::new())))), + ) + }; match self { Intrinsic::NegNat => op!(Nat(x) => Int(-(*x as i64))), Intrinsic::NegInt => op!(Int(x) => Int(-*x)), - Intrinsic::DisplayInt => op!(Int(x) => List(x.to_string().chars().map(Const::Char).collect())), + Intrinsic::DisplayInt => { + op!(Int(x) => List(x.to_string().chars().map(Const::Char).collect())) + } Intrinsic::CodepointChar => op!(Char(c) => Nat(*c as u64)), Intrinsic::AddNat => op!(Nat(x), Nat(y) => Nat(x + y)), Intrinsic::SubNat => op!(Nat(x), Nat(y) => Int(*x as i64 - *y as i64)), @@ -306,14 +338,17 @@ impl Intrinsic { Intrinsic::MulInt => op!(Int(x), Int(y) => Int(x * y)), Intrinsic::EqNat => op!(Nat(x), Nat(y) => r#bool(x == y)), Intrinsic::EqChar => op!(Char(x), Char(y) => r#bool(x == y)), - Intrinsic::EqNat => op!(Nat(x), Nat(y) => r#bool(x == y)), - Intrinsic::Join(_) => op!(List(xs), List(ys) => List(xs.iter().chain(ys).cloned().collect())), + Intrinsic::Join(_) => { + op!(List(xs), List(ys) => List(xs.iter().chain(ys).cloned().collect())) + } Intrinsic::Print => Partial::Unknown(None), Intrinsic::Input => Partial::Unknown(None), Intrinsic::Rand => Partial::Unknown(None), - Intrinsic::UpdateField(idx) => Partial::Unknown(None), // TODO + Intrinsic::UpdateField(_idx) => Partial::Unknown(None), // TODO Intrinsic::LenList => op!(List(xs) => Nat(xs.len() as u64)), - Intrinsic::SkipList => op!(List(xs), Nat(i) => List(xs.clone().split_off((*i as usize).min(xs.len())))), + Intrinsic::SkipList => { + op!(List(xs), Nat(i) => List(xs.clone().split_off((*i as usize).min(xs.len())))) + } Intrinsic::TrimList => op!(List(xs), Nat(i) => List({ let mut xs = xs.clone(); xs.truncate(*i as usize); @@ -328,16 +363,24 @@ impl Intrinsic { impl Pass for ConstFold { fn apply(&mut self, ctx: &mut Context) { - let proc_bodies = ctx.procs + let proc_bodies = ctx + .procs .iter() .map(|(id, proc)| (id, proc.body.clone())) .collect::>(); for (id, mut body) in proc_bodies { // visit(&ctx, &mut body, &mut Vec::new()); - self.eval(&ctx, &mut body, &mut Vec::new()); + self.eval(ctx, &mut body, &mut Vec::new()); let requires = body.required_locals(None); - debug_assert_eq!(requires.len(), 0, "Procedure requires locals {:?}\n\nOld = {}\n\n\nNew = {}\n", requires, ctx.procs.get_mut(id).unwrap().body.print(), body.print()); + debug_assert_eq!( + requires.len(), + 0, + "Procedure requires locals {:?}\n\nOld = {}\n\n\nNew = {}\n", + requires, + ctx.procs.get_mut(id).unwrap().body.print(), + body.print() + ); ctx.procs.get_mut(id).unwrap().body = body; } } diff --git a/middle/src/opt/flatten_single_field.rs b/middle/src/opt/flatten_single_field.rs index 0da6ebb..da84c5f 100644 --- a/middle/src/opt/flatten_single_field.rs +++ b/middle/src/opt/flatten_single_field.rs @@ -5,7 +5,7 @@ use super::*; pub struct FlattenSingleField; impl Pass for FlattenSingleField { - fn apply(&mut self, ctx: &mut Context) { + fn apply(&mut self, _ctx: &mut Context) { // TODO: Implement /* ctx.visit( diff --git a/middle/src/opt/mod.rs b/middle/src/opt/mod.rs index 9bad8df..2f64b68 100644 --- a/middle/src/opt/mod.rs +++ b/middle/src/opt/mod.rs @@ -1,5 +1,5 @@ use super::*; -use std::any::{Any, type_name}; +use std::any::{type_name, Any}; mod const_fold; mod flatten_single_field; @@ -7,10 +7,8 @@ mod remove_dead_proc; mod remove_unused_bindings; pub use { - const_fold::ConstFold, - flatten_single_field::FlattenSingleField, - remove_dead_proc::RemoveDeadProc, - remove_unused_bindings::RemoveUnusedBindings, + const_fold::ConstFold, flatten_single_field::FlattenSingleField, + remove_dead_proc::RemoveDeadProc, remove_unused_bindings::RemoveUnusedBindings, }; pub trait Pass: Any { @@ -114,21 +112,15 @@ impl Repr { impl Binding { pub fn for_children(&self, mut f: impl FnMut(&MirNode)) { match &self.pat { - mir::Pat::Wildcard | mir::Pat::Literal(_) => {}, + mir::Pat::Wildcard | mir::Pat::Literal(_) => {} mir::Pat::Single(inner) => f(inner), mir::Pat::Add(lhs, _) => f(lhs), - mir::Pat::Tuple(fields) => fields - .iter() - .for_each(|field| f(field)), - mir::Pat::ListExact(items) => items - .iter() - .for_each(|item| f(item)), + mir::Pat::Tuple(fields) => fields.iter().for_each(f), + mir::Pat::ListExact(items) => items.iter().for_each(f), mir::Pat::ListFront(items, tail) => { - items - .iter() - .for_each(|item| f(item)); - tail.as_ref().map(|tail| f(tail)); - }, + items.iter().for_each(&mut f); + tail.as_ref().map(f); + } mir::Pat::Variant(_, inner) => f(inner), mir::Pat::Data(_, inner) => f(inner), } @@ -136,21 +128,15 @@ impl Binding { pub fn for_children_mut(&mut self, mut f: impl FnMut(&mut MirNode)) { match &mut self.pat { - mir::Pat::Wildcard | mir::Pat::Literal(_) => {}, + mir::Pat::Wildcard | mir::Pat::Literal(_) => {} mir::Pat::Single(inner) => f(inner), mir::Pat::Add(lhs, _) => f(lhs), - mir::Pat::Tuple(fields) => fields - .iter_mut() - .for_each(|field| f(field)), - mir::Pat::ListExact(items) => items - .iter_mut() - .for_each(|item| f(item)), + mir::Pat::Tuple(fields) => fields.iter_mut().for_each(f), + mir::Pat::ListExact(items) => items.iter_mut().for_each(f), mir::Pat::ListFront(items, tail) => { - items - .iter_mut() - .for_each(|item| f(item)); - tail.as_mut().map(|tail| f(tail)); - }, + items.iter_mut().for_each(&mut f); + tail.as_mut().map(f); + } mir::Pat::Variant(_, inner) => f(inner), mir::Pat::Data(_, inner) => f(inner), } @@ -200,31 +186,25 @@ impl Binding { impl Expr { pub fn for_children(&self, mut f: impl FnMut(&MirNode)) { match self { - Expr::Undefined | Expr::Literal(_) | Expr::Local(_) | Expr::Global(_, _) => {}, - Expr::Intrinsic(_, args) => args - .iter() - .for_each(|arg| f(arg)), - Expr::Tuple(fields) => fields - .iter() - .for_each(|field| f(field)), - Expr::List(items) => items - .iter() - .for_each(|item| f(item)), + Expr::Undefined | Expr::Literal(_) | Expr::Local(_) | Expr::Global(_, _) => {} + Expr::Intrinsic(_, args) => args.iter().for_each(f), + Expr::Tuple(fields) => fields.iter().for_each(f), + Expr::List(items) => items.iter().for_each(f), Expr::Match(pred, arms) => { f(pred); for (_, body) in arms { f(body); } - }, + } Expr::Func(_, body) => f(body), Expr::Go(_, body, init) => { f(body); f(init); - }, + } Expr::Apply(func, arg) => { f(func); f(arg); - }, + } Expr::Access(record, _) => f(record), Expr::Variant(_, inner) => f(inner), Expr::AccessVariant(inner, _) => f(inner), @@ -233,40 +213,40 @@ impl Expr { Expr::Basin(_, inner) => f(inner), Expr::Handle { expr, handlers } => { f(expr); - for Handler { eff, send, state, recv } in handlers { + for Handler { + eff: _, + send: _, + state: _, + recv, + } in handlers + { f(recv); } - }, + } } } pub fn for_children_mut(&mut self, mut f: impl FnMut(&mut MirNode)) { match self { - Expr::Undefined | Expr::Literal(_) | Expr::Local(_) | Expr::Global(_, _) => {}, - Expr::Intrinsic(_, args) => args - .iter_mut() - .for_each(|arg| f(arg)), - Expr::Tuple(fields) => fields - .iter_mut() - .for_each(|field| f(field)), - Expr::List(items) => items - .iter_mut() - .for_each(|item| f(item)), + Expr::Undefined | Expr::Literal(_) | Expr::Local(_) | Expr::Global(_, _) => {} + Expr::Intrinsic(_, args) => args.iter_mut().for_each(f), + Expr::Tuple(fields) => fields.iter_mut().for_each(f), + Expr::List(items) => items.iter_mut().for_each(f), Expr::Match(pred, arms) => { f(pred); for (_, body) in arms { f(body); } - }, + } Expr::Func(_, body) => f(body), Expr::Go(_, body, init) => { f(body); f(init); - }, + } Expr::Apply(func, arg) => { f(func); f(arg); - }, + } Expr::Access(record, _) => f(record), Expr::Variant(_, inner) => f(inner), Expr::AccessVariant(inner, _) => f(inner), @@ -275,10 +255,16 @@ impl Expr { Expr::Basin(_, inner) => f(inner), Expr::Handle { expr, handlers } => { f(expr); - for Handler { eff, send, state, recv } in handlers { + for Handler { + eff: _, + send: _, + state: _, + recv, + } in handlers + { f(recv); } - }, + } } } @@ -292,20 +278,26 @@ impl Expr { body.inline_local(name, local_expr); } } - }, + } Expr::Func(arg, body) => { if **arg != name { body.inline_local(name, local_expr); } - }, + } Expr::Handle { expr, handlers } => { expr.inline_local(name, local_expr); - for Handler { eff, send, state, recv } in handlers { + for Handler { + eff: _, + send, + state, + recv, + } in handlers + { if **send != name && **state != name { recv.inline_local(name, local_expr); } } - }, + } _ => self.for_children_mut(|expr| expr.inline_local(name, local_expr)), } } @@ -393,84 +385,97 @@ pub fn prepare(ctx: &mut Context) { /// Check the self-consistency of the MIR pub fn check(ctx: &Context) { - fn check_binding(ctx: &Context, binding: &Binding, repr: &Repr, stack: &mut Vec<(Local, Repr)>) { + fn check_binding( + binding: &Binding, + repr: &Repr, + ) { match (&binding.pat, repr) { - (Pat::Data(a, inner), Repr::Data(b)) if a == b => {}, // TODO: Check inner - (Pat::Wildcard, _) => {}, - (Pat::Tuple(a), Repr::Tuple(b)) if a.len() == b.len() => {}, - (Pat::Variant(idx, inner), Repr::Sum(variants)) if *idx < variants.len() => check_binding(ctx, inner, &variants[*idx], stack), - (Pat::Single(inner), _) => check_binding(ctx, inner, repr, stack), - (Pat::ListExact(_), Repr::List(_)) => {}, - (Pat::ListFront(_, _), Repr::List(_)) => {}, - (_, repr) => panic!("Inconsistency between binding\n\n {:?}\n\nand repr {:?}", binding, repr), + (Pat::Data(a, _inner), Repr::Data(b)) if a == b => {} // TODO: Check inner + (Pat::Wildcard, _) => {} + (Pat::Tuple(a), Repr::Tuple(b)) if a.len() == b.len() => {} + (Pat::Variant(idx, inner), Repr::Sum(variants)) if *idx < variants.len() => { + check_binding(inner, &variants[*idx]) + } + (Pat::Single(inner), _) => check_binding(inner, repr), + (Pat::ListExact(_), Repr::List(_)) => {} + (Pat::ListFront(_, _), Repr::List(_)) => {} + (_, repr) => panic!( + "Inconsistency between binding\n\n {:?}\n\nand repr {:?}", + binding, repr + ), } - binding.for_children(|binding| check_binding(ctx, binding, binding.meta(), stack)); + binding.for_children(|binding| check_binding(binding, binding.meta())); } fn check_expr(ctx: &Context, expr: &Expr, repr: &Repr, stack: &mut Vec<(Local, Repr)>) { match (expr, repr) { - (Expr::Data(a, inner), Repr::Data(b)) if a == b => {}, // TODO: Check inner + (Expr::Data(a, _inner), Repr::Data(b)) if a == b => {} // TODO: Check inner // TODO: Check literals elsewhere - (Expr::Literal(Literal::Nat(_)), Repr::Prim(Prim::Nat)) => {}, - (Expr::Literal(Literal::List(_)), Repr::List(_)) => {}, - (Expr::Literal(Literal::Tuple(_)), Repr::Tuple(_)) => {}, - (Expr::Literal(Literal::Sum(_, _)), _) => {}, - (Expr::Literal(Literal::Data(a, _)), Repr::Data(b)) if a == b => {}, - (Expr::Global(_, _), _) => {}, // TODO - (Expr::Local(local), repr) if &stack - .iter() - .rev() - .find(|(name, _)| name == local) - .unwrap_or_else(|| panic!("Failed to find local ${} in scope", local.0)).1 == repr => {}, + (Expr::Literal(Literal::Nat(_)), Repr::Prim(Prim::Nat)) => {} + (Expr::Literal(Literal::List(_)), Repr::List(_)) => {} + (Expr::Literal(Literal::Tuple(_)), Repr::Tuple(_)) => {} + (Expr::Literal(Literal::Sum(_, _)), _) => {} + (Expr::Literal(Literal::Data(a, _)), Repr::Data(b)) if a == b => {} + (Expr::Global(_, _), _) => {} // TODO + (Expr::Local(local), repr) + if &stack + .iter() + .rev() + .find(|(name, _)| name == local) + .unwrap_or_else(|| panic!("Failed to find local ${} in scope", local.0)) + .1 + == repr => {} (Expr::Func(i, body), Repr::Func(i_repr, _)) => { stack.push((**i, (**i_repr).clone())); visit_expr(ctx, body, stack); stack.pop(); - }, - (Expr::Go(_, body, init), _) => { + } + (Expr::Go(_, _body, _init), _) => { // TODO: Validate return body and return type - }, - (Expr::Apply(f, arg), _) => { + } + (Expr::Apply(f, _arg), _) => { assert!(matches!(f.meta(), Repr::Func(_, _))); - }, + } (Expr::Tuple(a), Repr::Tuple(b)) if a.len() == b.len() => { expr.for_children(|expr| visit_expr(ctx, expr, stack)); - }, + } (Expr::List(items), Repr::List(b)) => { for item in items { check_expr(ctx, item, b, stack); } - }, - (Expr::Match(pred, arms), repr) => { + } + (Expr::Match(pred, arms), _repr) => { for (arm, body) in arms { // TODO: visit binding - check_binding(ctx, arm.inner(), pred.meta(), stack); + check_binding(arm.inner(), pred.meta()); let old_stack = stack.len(); stack.append(&mut arm.bindings()); check_expr(ctx, body, body.meta(), stack); stack.truncate(old_stack); } - }, + } (Expr::Variant(idx, inner), Repr::Sum(variants)) if *idx < variants.len() => { check_expr(ctx, inner, &variants[*idx], stack); expr.for_children(|expr| visit_expr(ctx, expr, stack)); - }, + } (expr, Repr::Data(data)) => { check_expr(ctx, expr, &ctx.reprs.get(*data).repr, stack); - }, - (Expr::Variant(idx, inner), Repr::Data(_)) => {}, // TODO - (Expr::Intrinsic(_, _), _) => {}, // TODO - (Expr::Access(_, _), _) => {}, // TODO + } + (Expr::Intrinsic(_, _), _) => {} // TODO + (Expr::Access(_, _), _) => {} // TODO (Expr::Basin(_, inner), Repr::Effect(_, o)) => { check_expr(ctx, inner, o, stack); - }, // TODO - (Expr::Handle { expr, handlers }, r) if matches!(expr.meta(), Repr::Effect(_, _)) => { + } // TODO + (Expr::Handle { expr, handlers: _ }, _r) if matches!(expr.meta(), Repr::Effect(_, _)) => { // TODO: Revisit this, might not be correct with subtyping // check_expr(ctx, expr, &Repr::Effect(vec![*eff], Box::new(r.clone())), stack); - }, + } // (Expr::Data(_, _, _), Repr::Func(_, _)) => {}, - (expr, repr) => panic!("Inconsistency between expression\n\n {:?}\n\nand repr {:?}", expr, repr), + (expr, repr) => panic!( + "Inconsistency between expression\n\n {:?}\n\nand repr {:?}", + expr, repr + ), } } @@ -481,7 +486,11 @@ pub fn check(ctx: &Context) { for (id, proc) in ctx.procs.iter() { println!("Checking {:?}", id); println!("{}", proc.body.print()); - assert_eq!(proc.body.required_locals(None).len(), 0, "Procedure requires locals"); + assert_eq!( + proc.body.required_locals(None).len(), + 0, + "Procedure requires locals" + ); visit_expr(ctx, &proc.body, &mut Vec::new()); } } diff --git a/middle/src/opt/remove_unused_bindings.rs b/middle/src/opt/remove_unused_bindings.rs index 70ee3a4..cc373e3 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -8,20 +8,22 @@ pub struct RemoveUnusedBindings; impl Pass for RemoveUnusedBindings { fn apply(&mut self, ctx: &mut Context) { fn visit( - mir: &Context, + _mir: &Context, expr: &mut Expr, stack: &mut Vec<(Local, u64)>, - proc_stack: &mut Vec, + _proc_stack: &mut Vec, ) { match expr { - Expr::Local(local) => if let Some((_, n)) = stack.iter_mut().rev().find(|(name, _)| *name == *local) { - // Increment uses - *n += 1; - } else { - panic!("Could not find local ${} in {:?}", local.0, stack); - }, + Expr::Local(local) => { + if let Some((_, n)) = stack.iter_mut().rev().find(|(name, _)| *name == *local) { + // Increment uses + *n += 1; + } else { + panic!("Could not find local ${} in {:?}", local.0, stack); + } + } Expr::Match(pred, arms) => { - visit(mir, pred, stack, proc_stack); + visit(_mir, pred, stack, _proc_stack); // Remove any arms that follow an irrefutable arm for i in 0..arms.len() { @@ -31,103 +33,116 @@ impl Pass for RemoveUnusedBindings { } } - arms - .iter_mut() - .for_each(|(arm, body)| { - let old_stack = stack.len(); + arms.iter_mut().for_each(|(arm, body)| { + let old_stack = stack.len(); - stack.extend(arm.binding_names().into_iter().map(|name| (name, 0))); - visit(mir, body, stack, proc_stack); + stack.extend(arm.binding_names().into_iter().map(|name| (name, 0))); + visit(_mir, body, stack, _proc_stack); - fn remove_unused(binding: &mut Binding, stack: &mut Vec<(Local, u64)>) { - if let Some(name) = binding.name { - if stack.iter_mut().rev().find(|(n, _)| *n == name).unwrap().1 == 0 { - binding.name = None; - } + fn remove_unused(binding: &mut Binding, stack: &mut Vec<(Local, u64)>) { + if let Some(name) = binding.name { + if stack.iter_mut().rev().find(|(n, _)| *n == name).unwrap().1 == 0 + { + binding.name = None; } + } - match &mut binding.pat { - Pat::Wildcard => {}, - Pat::Literal(_) => {}, - Pat::Single(inner) => remove_unused(inner, stack), - Pat::Add(lhs, _) => remove_unused(lhs, stack), - Pat::Tuple(fields) => fields - .iter_mut() - .for_each(|field| remove_unused(field, stack)), - Pat::ListExact(items) => items - .iter_mut() - .for_each(|item| remove_unused(item, stack)), - Pat::ListFront(items, tail) => { - items - .iter_mut() - .for_each(|item| remove_unused(item, stack)); - tail - .as_mut() - .map(|tail| remove_unused(tail, stack)); - }, - Pat::Variant(_, inner) => remove_unused(inner, stack), - Pat::Data(_, inner) => remove_unused(inner, stack), + match &mut binding.pat { + Pat::Wildcard => {} + Pat::Literal(_) => {} + Pat::Single(inner) => remove_unused(inner, stack), + Pat::Add(lhs, _) => remove_unused(lhs, stack), + Pat::Tuple(fields) => fields + .iter_mut() + .for_each(|field| remove_unused(field, stack)), + Pat::ListExact(items) => { + items.iter_mut().for_each(|item| remove_unused(item, stack)) + } + Pat::ListFront(items, tail) => { + items.iter_mut().for_each(|item| remove_unused(item, stack)); + if let Some(tail) = tail.as_mut() { + remove_unused(tail, stack); + } } + Pat::Variant(_, inner) => remove_unused(inner, stack), + Pat::Data(_, inner) => remove_unused(inner, stack), } + } - remove_unused(arm, stack); + remove_unused(arm, stack); - stack.truncate(old_stack); - }); + stack.truncate(old_stack); + }); // Visit predicate last to avoid visiting it again if the match was removed - visit(mir, pred, stack, proc_stack); + visit(_mir, pred, stack, _proc_stack); // Flatten matches with a single arm where the arm does not bind if arms.len() == 1 && !arms.first().unwrap().0.binds() { if !pred.may_have_effect() { *expr = arms.remove(0).1.into_inner(); } - } else if arms.get(0).map_or(false, |(b, _)| matches!(&b.pat, Pat::Wildcard)) { - if !pred.may_have_effect() { - let (arm, mut body) = arms.remove(0); - if let Some(name) = arm.name { - body.inline_local(name, pred); - } - *expr = body.into_inner(); + } else if arms + .get(0) + .map_or(false, |(b, _)| matches!(&b.pat, Pat::Wildcard)) + && !pred.may_have_effect() + { + let (arm, mut body) = arms.remove(0); + if let Some(name) = arm.name { + body.inline_local(name, pred); } + *expr = body.into_inner(); } - }, + } Expr::Func(arg, body) => { stack.push((**arg, 0)); - visit(mir, body, stack, proc_stack); + visit(_mir, body, stack, _proc_stack); stack.pop(); - }, + } Expr::Go(next, body, init) => { - visit(mir, init, stack, proc_stack); + visit(_mir, init, stack, _proc_stack); stack.push((**next, 0)); - visit(mir, body, stack, proc_stack); + visit(_mir, body, stack, _proc_stack); stack.pop(); - }, + } Expr::Handle { expr, handlers } => { - visit(mir, expr, stack, proc_stack); - for Handler { eff: _, send, state, recv } in handlers { + visit(_mir, expr, stack, _proc_stack); + for Handler { + eff: _, + send, + state, + recv, + } in handlers + { let old_len = stack.len(); stack.push((**send, 0)); stack.push((**state, 0)); - visit(mir, recv, stack, proc_stack); + visit(_mir, recv, stack, _proc_stack); stack.truncate(old_len); } - }, - _ => expr.for_children_mut(|expr| visit(mir, expr, stack, proc_stack)), + } + _ => expr.for_children_mut(|expr| visit(_mir, expr, stack, _proc_stack)), } } - let proc_bodies = ctx.procs + let proc_bodies = ctx + .procs .iter() .map(|(id, proc)| (id, proc.body.clone())) .collect::>(); for (id, mut body) in proc_bodies { let mut proc_stack = vec![id]; - visit(&ctx, &mut body, &mut Vec::new(), &mut proc_stack); + visit(ctx, &mut body, &mut Vec::new(), &mut proc_stack); let requires = body.required_locals(None); - debug_assert_eq!(requires.len(), 0, "Procedure requires locals {:?}\n\nOld = {}\n\n\nNew = {}\n", requires, ctx.procs.get_mut(id).unwrap().body.print(), body.print()); + debug_assert_eq!( + requires.len(), + 0, + "Procedure requires locals {:?}\n\nOld = {}\n\n\nNew = {}\n", + requires, + ctx.procs.get_mut(id).unwrap().body.print(), + body.print() + ); ctx.procs.get_mut(id).unwrap().body = body; } } diff --git a/middle/src/proc.rs b/middle/src/proc.rs index 816894e..c0b547f 100644 --- a/middle/src/proc.rs +++ b/middle/src/proc.rs @@ -29,11 +29,15 @@ impl Procs { } pub fn iter_mut(&mut self) -> impl Iterator { - self.procs.iter_mut().filter_map(|(id, proc)| Some((*id, proc.as_mut()?))) + self.procs + .iter_mut() + .filter_map(|(id, proc)| Some((*id, proc.as_mut()?))) } pub fn iter(&self) -> impl Iterator { - self.procs.iter().filter_map(|(id, proc)| Some((*id, proc.as_ref()?))) + self.procs + .iter() + .filter_map(|(id, proc)| Some((*id, proc.as_ref()?))) } pub fn declare(&mut self, id: ProcId) { @@ -41,6 +45,9 @@ impl Procs { } pub fn define(&mut self, id: ProcId, proc: Proc) { - assert!(self.procs.insert(id, Some(proc)).unwrap().is_none(), "Proc defined without declaration"); + assert!( + self.procs.insert(id, Some(proc)).unwrap().is_none(), + "Proc defined without declaration" + ); } } diff --git a/middle/src/repr.rs b/middle/src/repr.rs index 08bdce5..52dd12e 100644 --- a/middle/src/repr.rs +++ b/middle/src/repr.rs @@ -1,6 +1,6 @@ use super::*; // use hashbrown::hash_map::Entry; -use std::collections::{BTreeMap, btree_map::Entry}; +use std::collections::{btree_map::Entry, BTreeMap}; #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Prim { @@ -44,14 +44,12 @@ impl Reprs { } pub fn iter_mut(&mut self) -> impl Iterator { - self.datas - .values_mut() - .filter_map(|r| r.as_mut()) + self.datas.values_mut().filter_map(|r| r.as_mut()) } pub fn declare(&mut self, data: ConDataId) -> bool { match self.datas.entry(data) { - Entry::Occupied(data) => false, + Entry::Occupied(_data) => false, Entry::Vacant(data) => { data.insert(None); true @@ -67,12 +65,8 @@ impl Reprs { match repr { Repr::Prim(_) => true, Repr::List(_) => true, // Empty list - Repr::Tuple(xs) => xs - .iter() - .all(|x| self.has_inhabitants(x)), - Repr::Sum(variants) => variants - .iter() - .any(|v| self.has_inhabitants(v)), + Repr::Tuple(xs) => xs.iter().all(|x| self.has_inhabitants(x)), + Repr::Sum(variants) => variants.iter().any(|v| self.has_inhabitants(v)), Repr::Data(data) => self.has_inhabitants(&self.get(*data).repr), Repr::Func(_, _) => true, Repr::Effect(_, _) => true, // Effect objects always have inhabitants diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..36755d2 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +# default diff --git a/syntax/src/ast.rs b/syntax/src/ast.rs index cf5f250..af2b4be 100644 --- a/syntax/src/ast.rs +++ b/syntax/src/ast.rs @@ -6,22 +6,33 @@ use std::ops::Deref; pub struct Ident(Intern); impl fmt::Display for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self.0) } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self.0) + } } impl fmt::Debug for Ident { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "`{}`", self.0) } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "`{}`", self.0) + } } impl Ident { - pub fn new(s: S) -> Self { Self(Intern::new(s.to_string())) } - pub fn as_ref(self) -> &'static String { self.0.as_ref() } + pub fn new(s: S) -> Self { + Self(Intern::new(s.to_string())) + } + + pub fn as_string(self) -> &'static String { + self.0.as_ref() + } } impl Deref for Ident { type Target = String; - fn deref(&self) -> &Self::Target { &self.0 } + fn deref(&self) -> &Self::Target { + &self.0 + } } // #[derive(Copy, Clone, Debug, PartialEq, Eq)] @@ -57,16 +68,24 @@ impl fmt::Display for UnaryOp { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum BinaryOp { // Sum - Add, Sub, + Add, + Sub, // Product - Mul, Div, Rem, + Mul, + Div, + Rem, // Equality - Eq, NotEq, + Eq, + NotEq, // Comparison - Less, LessEq, - More, MoreEq, + Less, + LessEq, + More, + MoreEq, // Logical - And, Or, Xor, + And, + Or, + Xor, // Lists Join, } @@ -123,17 +142,13 @@ impl EffectSet { pub fn mentions_ty(&self, name: Ident) -> bool { self.effs .iter() - .any(|(_, params)| params - .iter() - .any(|p| p.mentions_ty(name))) + .any(|(_, params)| params.iter().any(|p| p.mentions_ty(name))) } pub fn mentions_eff(&self, name: Ident) -> bool { self.effs .iter() - .any(|(eff, params)| **eff == name || params - .iter() - .any(|p| p.mentions_eff(name))) + .any(|(eff, params)| **eff == name || params.iter().any(|p| p.mentions_eff(name))) } } @@ -156,39 +171,28 @@ pub enum Type { impl Type { pub fn for_children(&self, mut f: impl FnMut(&Self)) { match self { - Self::Error | Self::Universe | Self::Unknown => {}, + Self::Error | Self::Universe | Self::Unknown => {} Self::List(x) => f(x), - Self::Tuple(fields) => fields - .iter() - .for_each(|field| f(field)), - Self::Record(fields) => fields - .iter() - .for_each(|(_, field)| f(field)), + Self::Tuple(fields) => fields.iter().for_each(|field| f(field)), + Self::Record(fields) => fields.iter().for_each(|(_, field)| f(field)), Self::Func(i, o) => { f(i); f(o); - }, - Self::Data(data, args) => args - .iter() - .for_each(|arg| f(arg)), + } + Self::Data(_data, args) => args.iter().for_each(|arg| f(arg)), // TODO: Recurse into class inst? Self::Assoc(inner, _, _) => f(inner), Self::Effect(set, out) => { f(out); set.effs .iter() - .for_each(|(_, args)| args - .iter() - .for_each(|arg| f(arg))); - }, + .for_each(|(_, args)| args.iter().for_each(|arg| f(arg))); + } } } pub fn is_fully_specified(&self) -> bool { - let mut specified = match self { - Self::Unknown => false, - _ => true, - }; + let mut specified = !matches!(self, Self::Unknown); self.for_children(|ty| specified &= ty.is_fully_specified()); specified } @@ -204,9 +208,7 @@ impl Type { pub fn mentions_eff(&self, name: Ident) -> bool { let mut mentions = match self { - Self::Effect(set, _) => set.effs - .iter() - .any(|(eff, _)| **eff == name), + Self::Effect(set, _) => set.effs.iter().any(|(eff, _)| **eff == name), _ => false, }; self.for_children(|ty| mentions |= ty.mentions_eff(name)); @@ -258,7 +260,10 @@ pub enum Expr { Unary(SrcNode, SrcNode), Binary(SrcNode, SrcNode, SrcNode), Let(Vec<(SrcNode, SrcNode)>, SrcNode), - Match(SrcNode>>, Vec<(SrcNode>>, SrcNode)>), + Match( + SrcNode>>, + Vec<(SrcNode>>, SrcNode)>, + ), If(SrcNode, SrcNode, SrcNode), Func(SrcNode>>, SrcNode)>>), Apply(SrcNode, SrcNode), @@ -266,8 +271,14 @@ pub enum Expr { ClassAccess(SrcNode, SrcNode), Intrinsic(SrcNode, Vec>), Update(SrcNode, Vec<(SrcNode, SrcNode)>), - Basin(Vec<(Option>, SrcNode)>, SrcNode), - Block(Vec<(Option>, SrcNode)>, SrcNode), + Basin( + Vec<(Option>, SrcNode)>, + SrcNode, + ), + Block( + Vec<(Option>, SrcNode)>, + SrcNode, + ), Handle { expr: SrcNode, handlers: Vec, @@ -434,65 +445,51 @@ pub struct Module { impl Module { pub fn classes(&self) -> impl Iterator], &Class)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::Class(class) => Some((item.attrs.as_slice(), class)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::Class(class) => Some((item.attrs.as_slice(), class)), + _ => None, + }) } pub fn datas(&self) -> impl Iterator], &Data)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::Data(data) => Some((item.attrs.as_slice(), data)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::Data(data) => Some((item.attrs.as_slice(), data)), + _ => None, + }) } pub fn aliases(&self) -> impl Iterator], &Alias)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::Alias(alias) => Some((item.attrs.as_slice(), alias)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::Alias(alias) => Some((item.attrs.as_slice(), alias)), + _ => None, + }) } pub fn members(&self) -> impl Iterator], &Member)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::Member(member) => Some((item.attrs.as_slice(), member)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::Member(member) => Some((item.attrs.as_slice(), member)), + _ => None, + }) } pub fn defs(&self) -> impl Iterator], &Def)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::Def(def) => Some((item.attrs.as_slice(), def)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::Def(def) => Some((item.attrs.as_slice(), def)), + _ => None, + }) } pub fn effects(&self) -> impl Iterator], &Effect)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::Effect(eff) => Some((item.attrs.as_slice(), eff)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::Effect(eff) => Some((item.attrs.as_slice(), eff)), + _ => None, + }) } pub fn effect_aliases(&self) -> impl Iterator], &EffectAlias)> + '_ { - self.items - .iter() - .filter_map(|item| match &item.kind { - ItemKind::EffectAlias(eff) => Some((item.attrs.as_slice(), eff)), - _ => None, - }) + self.items.iter().filter_map(|item| match &item.kind { + ItemKind::EffectAlias(eff) => Some((item.attrs.as_slice(), eff)), + _ => None, + }) } } diff --git a/syntax/src/error.rs b/syntax/src/error.rs index 2a58e36..47b79db 100644 --- a/syntax/src/error.rs +++ b/syntax/src/error.rs @@ -1,14 +1,15 @@ use super::*; -use std::{ - collections::HashSet, - io::Write, -}; +use std::{collections::HashSet, io::Write}; #[derive(Debug, PartialEq)] pub enum ErrorKind { UnexpectedEnd, Unexpected(Pattern), - Unclosed { start: Pattern, before_span: Span, before: Option }, + Unclosed { + start: Pattern, + before_span: Span, + before: Option, + }, NoEndBranch, } @@ -28,7 +29,7 @@ impl Error { } pub fn while_parsing(mut self, span: Span, structure: &'static str) -> Self { - self.while_parsing = self.while_parsing.or_else(|| Some((span, structure))); + self.while_parsing = self.while_parsing.or(Some((span, structure))); self } } @@ -53,15 +54,16 @@ impl Error { } pub fn write>(self, cache: C, writer: impl Write) { - use ariadne::{Report, ReportKind, Label, Color, Fmt}; + use ariadne::{Color, Fmt, Label, Report, ReportKind}; let msg = format!( "{}{}, expected {}", match &self.kind { ErrorKind::UnexpectedEnd => "Unexpected end of input".to_string(), ErrorKind::Unexpected(pat) => format!("Unexpected {}", pat.fg(Color::Red)), - ErrorKind::Unclosed { start, .. } => format!("Unclosed delimiter {}", start.fg(Color::Red)), - ErrorKind::NoEndBranch => format!("No end branch"), + ErrorKind::Unclosed { start, .. } => + format!("Unclosed delimiter {}", start.fg(Color::Red)), + ErrorKind::NoEndBranch => "No end branch".to_string(), }, if let Some(label) = self.label { format!(" while parsing {}", label.fg(Color::Cyan)) @@ -70,55 +72,77 @@ impl Error { }, match self.expected.len() { 0 => "something else".to_string(), - 1 => format!("{}", self.expected.into_iter().next().unwrap().fg(Color::Yellow)), - _ => format!("one of {}", self.expected.into_iter().map(|x| x.fg(Color::Yellow).to_string()).collect::>().join(", ")), + 1 => format!( + "{}", + self.expected.into_iter().next().unwrap().fg(Color::Yellow) + ), + _ => format!( + "one of {}", + self.expected + .into_iter() + .map(|x| x.fg(Color::Yellow).to_string()) + .collect::>() + .join(", ") + ), }, ); let report = Report::build(ReportKind::Error, self.span.src(), self.span.start()) .with_code(3) .with_message(msg) - .with_label(Label::new(self.span) - .with_message(match &self.kind { - ErrorKind::UnexpectedEnd => "End of input".to_string(), - ErrorKind::Unexpected(pat) => format!("Unexpected {}", pat.fg(Color::Red)), - ErrorKind::Unclosed { start, .. } => format!("Delimiter {} is never closed", start.fg(Color::Red)), - ErrorKind::NoEndBranch => format!("Requires a {} branch", "\\ ... => ...".fg(Color::Blue)), - }) - .with_color(Color::Red)); - - let report = if let ErrorKind::Unclosed { before, before_span, .. } = self.kind { - report - .with_label(Label::new(before_span) - .with_message(format!("Must be closed before {}", match before { - Some(before) => format!("this {}", before.fg(Color::Yellow)), - None => "end of input".to_string(), - })) - .with_color(Color::Yellow)) + .with_label( + Label::new(self.span) + .with_message(match &self.kind { + ErrorKind::UnexpectedEnd => "End of input".to_string(), + ErrorKind::Unexpected(pat) => format!("Unexpected {}", pat.fg(Color::Red)), + ErrorKind::Unclosed { start, .. } => { + format!("Delimiter {} is never closed", start.fg(Color::Red)) + } + ErrorKind::NoEndBranch => { + format!("Requires a {} branch", "\\ ... => ...".fg(Color::Blue)) + } + }) + .with_color(Color::Red), + ); + + let report = if let ErrorKind::Unclosed { + before, + before_span, + .. + } = self.kind + { + report.with_label( + Label::new(before_span) + .with_message(format!( + "Must be closed before {}", + match before { + Some(before) => format!("this {}", before.fg(Color::Yellow)), + None => "end of input".to_string(), + } + )) + .with_color(Color::Yellow), + ) } else { report }; let report = if let Some((while_parsing, s)) = self.while_parsing { - report.with_label(Label::new(while_parsing) - .with_message(format!("encountered while parsing this {}", s)) - .with_color(Color::Blue)) + report.with_label( + Label::new(while_parsing) + .with_message(format!("encountered while parsing this {}", s)) + .with_color(Color::Blue), + ) } else { report }; - report - .finish() - .write(cache, writer) - .unwrap(); + report.finish().write(cache, writer).unwrap(); } } impl PartialEq for Error { fn eq(&self, other: &Self) -> bool { - self.kind == other.kind - && self.span == other.span - && self.label == other.label + self.kind == other.kind && self.span == other.span && self.label == other.label } } @@ -186,8 +210,16 @@ pub enum Pattern { End, } -impl From for Pattern { fn from(c: char) -> Self { Self::Char(c) } } -impl From for Pattern { fn from(tok: Token) -> Self { Self::Token(tok) } } +impl From for Pattern { + fn from(c: char) -> Self { + Self::Char(c) + } +} +impl From for Pattern { + fn from(tok: Token) -> Self { + Self::Token(tok) + } +} impl fmt::Display for Pattern { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { diff --git a/syntax/src/lib.rs b/syntax/src/lib.rs index 25d6111..54a1b3c 100644 --- a/syntax/src/lib.rs +++ b/syntax/src/lib.rs @@ -1,23 +1,25 @@ #![feature(option_zip, trait_alias)] -pub mod error; -pub mod token; -pub mod span; -pub mod src; +#![allow(clippy::type_complexity)] + pub mod ast; +pub mod error; pub mod node; pub mod parse; +pub mod span; +pub mod src; +pub mod token; pub use crate::{ error::{Error, ErrorKind, Pattern}, - span::Span, node::{Node, SrcNode}, + span::Span, src::SrcId, - token::{Token, Op, Delimiter}, + token::{Delimiter, Op, Token}, }; -use std::fmt; use chumsky::prelude::*; +use std::fmt; fn parse(parser: impl parse::Parser, code: &str, src: SrcId) -> (Option, Vec) { let mut errors = Vec::new(); @@ -25,14 +27,12 @@ fn parse(parser: impl parse::Parser, code: &str, src: SrcId) -> (Option let len = code.chars().count(); let eoi = Span::new(src, len..len); - let (tokens, mut lex_errors) = token::lexer() - .parse_recovery(chumsky::Stream::from_iter( - eoi, - code - .chars() - .enumerate() - .map(|(i, c)| (c, Span::new(src, i..i + 1))), - )); + let (tokens, mut lex_errors) = token::lexer().parse_recovery(chumsky::Stream::from_iter( + eoi, + code.chars() + .enumerate() + .map(|(i, c)| (c, Span::new(src, i..i + 1))), + )); errors.append(&mut lex_errors); let tokens = if let Some(tokens) = tokens { @@ -41,7 +41,8 @@ fn parse(parser: impl parse::Parser, code: &str, src: SrcId) -> (Option return (None, errors); }; - let (output, mut parse_errors) = parser.parse_recovery(chumsky::Stream::from_iter(eoi, tokens.into_iter())); + let (output, mut parse_errors) = + parser.parse_recovery(chumsky::Stream::from_iter(eoi, tokens.into_iter())); errors.append(&mut parse_errors); (output, errors) @@ -59,8 +60,7 @@ pub fn parse_expr(code: &str, src: SrcId) -> (Option>, Vec (Option>, Vec) { parse( - parse::module_parser() - .map_with_span(SrcNode::new), + parse::module_parser().map_with_span(SrcNode::new), code, src, ) diff --git a/syntax/src/node.rs b/syntax/src/node.rs index 56a5cbe..7daa252 100644 --- a/syntax/src/node.rs +++ b/syntax/src/node.rs @@ -1,8 +1,8 @@ use super::*; use std::{ - ops::{Deref, DerefMut}, - cmp::{PartialEq, Eq, PartialOrd, Ord, Ordering}, + cmp::{Eq, Ord, Ordering, PartialEq, PartialOrd}, fmt, + ops::{Deref, DerefMut}, }; #[derive(Clone)] @@ -14,7 +14,10 @@ pub struct Node { impl Node { /// Create a new node with the given inner value and metadata. pub fn new(inner: T, meta: M) -> Self { - Node { inner: Box::new(inner), meta } + Node { + inner: Box::new(inner), + meta, + } } /// Get a reference to the inner value. @@ -28,7 +31,9 @@ impl Node { } // Take the node's inner value. - pub fn into_inner(self) -> T { *self.inner } + pub fn into_inner(self) -> T { + *self.inner + } /// Map the node's inner value. pub fn map U>(self, f: F) -> Node { @@ -39,19 +44,27 @@ impl Node { } /// Get a reference to the metadata. - pub fn meta(&self) -> &M { &self.meta } + pub fn meta(&self) -> &M { + &self.meta + } /// Get a mutable reference to the metadata. - pub fn meta_mut(&mut self) -> &mut M { &mut self.meta } + pub fn meta_mut(&mut self) -> &mut M { + &mut self.meta + } } impl Deref for Node { type Target = T; - fn deref(&self) -> &Self::Target { self.inner() } + fn deref(&self) -> &Self::Target { + self.inner() + } } impl DerefMut for Node { - fn deref_mut(&mut self) -> &mut Self::Target { self.inner_mut() } + fn deref_mut(&mut self) -> &mut Self::Target { + self.inner_mut() + } } impl PartialEq for Node { @@ -84,5 +97,7 @@ impl fmt::Debug for Node { pub type SrcNode = Node; impl SrcNode { - pub fn span(&self) -> Span { self.meta } + pub fn span(&self) -> Span { + self.meta + } } diff --git a/syntax/src/parse.rs b/syntax/src/parse.rs index daad329..24e269d 100644 --- a/syntax/src/parse.rs +++ b/syntax/src/parse.rs @@ -10,35 +10,49 @@ pub fn literal_parser() -> impl Parser { Token::Char(x) => ast::Literal::Char(x), Token::Str(x) => ast::Literal::Str(x), } - .map_err(|e: Error| e.expected(Pattern::Literal)) + .map_err(|e: Error| e.expected(Pattern::Literal)) } pub fn term_ident_parser() -> impl Parser { - select! { Token::TermIdent(x) => x } - .map_err(|e: Error| e.expected(Pattern::TermIdent)) + select! { Token::TermIdent(x) => x }.map_err(|e: Error| e.expected(Pattern::TermIdent)) } pub fn type_ident_parser() -> impl Parser { - select! { Token::TypeIdent(x) => x } - .map_err(|e: Error| e.expected(Pattern::TypeIdent)) + select! { Token::TypeIdent(x) => x }.map_err(|e: Error| e.expected(Pattern::TypeIdent)) } -pub fn nested_parser<'a, T: 'a>(parser: impl Parser + 'a, delimiter: Delimiter, f: impl Fn(Span) -> T + Clone + 'a) -> impl Parser + 'a { +pub fn nested_parser<'a, T: 'a>( + parser: impl Parser + 'a, + delimiter: Delimiter, + f: impl Fn(Span) -> T + Clone + 'a, +) -> impl Parser + 'a { parser .delimited_by(just(Token::Open(delimiter)), just(Token::Close(delimiter))) .recover_with(nested_delimiters( - Token::Open(delimiter), Token::Close(delimiter), + Token::Open(delimiter), + Token::Close(delimiter), [ - (Token::Open(Delimiter::Paren), Token::Close(Delimiter::Paren)), - (Token::Open(Delimiter::Brack), Token::Close(Delimiter::Brack)), - (Token::Open(Delimiter::Brace), Token::Close(Delimiter::Brace)), + ( + Token::Open(Delimiter::Paren), + Token::Close(Delimiter::Paren), + ), + ( + Token::Open(Delimiter::Brack), + Token::Close(Delimiter::Brack), + ), + ( + Token::Open(Delimiter::Brace), + Token::Close(Delimiter::Brace), + ), ], f, )) .boxed() } -pub fn effect_set_parser(ty: impl Parser> + 'static) -> impl Parser { +pub fn effect_set_parser( + ty: impl Parser> + 'static, +) -> impl Parser { let effect_insts = term_ident_parser() // TODO: Replace with `term_item_parser` when ready .map_with_span(SrcNode::new) .then(ty.repeated()) @@ -46,11 +60,7 @@ pub fn effect_set_parser(ty: impl Parser> + 'static) -> impl .at_least(1) .allow_leading(); - nested_parser( - effect_insts.clone(), - Delimiter::Paren, - |_| Vec::new() - ) + nested_parser(effect_insts.clone(), Delimiter::Paren, |_| Vec::new()) .or(effect_insts) .map(|effs| ast::EffectSet { effs }) } @@ -62,13 +72,11 @@ pub fn type_parser() -> impl Parser { .map(|data_name| ast::Type::Data(data_name, Vec::new())); let list = nested_parser( - ty.clone() - .map_with_span(SrcNode::new) - .map(Some), + ty.clone().map_with_span(SrcNode::new).map(Some), Delimiter::Brack, |_| None, ) - .map(|ty| ty.map(ast::Type::List).unwrap_or(ast::Type::Error)); + .map(|ty| ty.map(ast::Type::List).unwrap_or(ast::Type::Error)); let tuple = nested_parser( ty.clone() @@ -80,7 +88,7 @@ pub fn type_parser() -> impl Parser { Delimiter::Paren, |_| None, ) - .map(|tys| tys.map(ast::Type::Tuple).unwrap_or(ast::Type::Error)); + .map(|tys| tys.map(ast::Type::Tuple).unwrap_or(ast::Type::Error)); let record = nested_parser( term_ident_parser() @@ -95,19 +103,13 @@ pub fn type_parser() -> impl Parser { Delimiter::Brace, |_| None, ) - .map(|tys| tys.map(ast::Type::Record).unwrap_or(ast::Type::Error)); + .map(|tys| tys.map(ast::Type::Record).unwrap_or(ast::Type::Error)); - let unknown = just(Token::Question) - .map(|_| ast::Type::Unknown); + let unknown = just(Token::Question).map(|_| ast::Type::Unknown); - let universe = just(Token::At) - .map(|_| ast::Type::Universe); + let universe = just(Token::At).map(|_| ast::Type::Universe); - let paren_ty = nested_parser( - ty.clone().map(Some), - Delimiter::Paren, - |_| None, - ) + let paren_ty = nested_parser(ty.clone().map(Some), Delimiter::Paren, |_| None) .map(|ty| ty.unwrap_or(ast::Type::Error)); let atom = paren_ty @@ -122,20 +124,30 @@ pub fn type_parser() -> impl Parser { .boxed(); let assoc = atom - .then(just(Token::Op(Op::Dot)) - .ignore_then(type_ident_parser().map_with_span(SrcNode::new) - .then(ty.clone().map_with_span(SrcNode::new).repeated()) - .delimited_by(just(Token::Op(Op::Less)), just(Token::Op(Op::More)))) - .map_with_span(SrcNode::new) - .or_not() - .then(just(Token::Op(Op::Dot)).ignore_then(type_ident_parser().map_with_span(SrcNode::new))) - .repeated()) + .then( + just(Token::Op(Op::Dot)) + .ignore_then( + type_ident_parser() + .map_with_span(SrcNode::new) + .then(ty.clone().map_with_span(SrcNode::new).repeated()) + .delimited_by(just(Token::Op(Op::Less)), just(Token::Op(Op::More))), + ) + .map_with_span(SrcNode::new) + .or_not() + .then( + just(Token::Op(Op::Dot)) + .ignore_then(type_ident_parser().map_with_span(SrcNode::new)), + ) + .repeated(), + ) .foldl(|inner, (class, assoc)| { - let class = class.map(|class| class.map(|(name, gen_tys)| ast::ClassInst { - name, - gen_tys, - gen_effs: Vec::new(), // TODO: Allow specifying effects in explicit form - })); + let class = class.map(|class| { + class.map(|(name, gen_tys)| ast::ClassInst { + name, + gen_tys, + gen_effs: Vec::new(), // TODO: Allow specifying effects in explicit form + }) + }); let span = inner.span().union(assoc.span()); SrcNode::new(ast::Type::Assoc(inner, class, assoc), span) }); @@ -157,10 +169,13 @@ pub fn type_parser() -> impl Parser { .or(data) .boxed(); - effect.clone() - .then(just(Token::Op(Op::RArrow)) - .ignore_then(ty.clone().map_with_span(SrcNode::new)) - .repeated()) + effect + .clone() + .then( + just(Token::Op(Op::RArrow)) + .ignore_then(ty.clone().map_with_span(SrcNode::new)) + .repeated(), + ) .foldl(|i, o| { let span = i.span().union(o.span()); SrcNode::new(ast::Type::Func(i, o), span) @@ -168,19 +183,21 @@ pub fn type_parser() -> impl Parser { .or(effect) .map(|ty| ty.into_inner()) }) - .labelled("type") + .labelled("type") } pub fn class_inst_parser() -> impl Parser { type_ident_parser() .map_with_span(SrcNode::new) - .then(type_parser() - .map_with_span(SrcNode::new) - .map(Ok) - .or(effect_set_parser(type_parser().map_with_span(SrcNode::new)) + .then( + type_parser() .map_with_span(SrcNode::new) - .map(Err)) - .repeated()) + .map(Ok) + .or(effect_set_parser(type_parser().map_with_span(SrcNode::new)) + .map_with_span(SrcNode::new) + .map(Err)) + .repeated(), + ) .map(|(name, gens)| { let mut gen_tys = Vec::new(); let mut gen_effs = Vec::new(); @@ -200,8 +217,7 @@ pub fn class_inst_parser() -> impl Parser { pub fn ty_hint_parser() -> impl Parser>> { just(Token::Colon) - .ignore_then(type_parser() - .map_with_span(SrcNode::new)) + .ignore_then(type_parser().map_with_span(SrcNode::new)) .or_not() } @@ -209,32 +225,32 @@ pub fn always_branches(branch: impl Parser + Clone) -> impl Parser> just(Token::Pipe) .ignore_then(branch.clone()) .repeated() - .then(just(Token::EndPipe) - .ignore_then(branch.clone()) - .or_not()) - .try_map(|(mut init, end), span| if let Some(end) = end { - init.push(end); - Ok(init) - } else { - Err(Error::new(ErrorKind::NoEndBranch, span)) + .then(just(Token::EndPipe).ignore_then(branch).or_not()) + .try_map(|(mut init, end), span| { + if let Some(end) = end { + init.push(end); + Ok(init) + } else { + Err(Error::new(ErrorKind::NoEndBranch, span)) + } }) } pub fn branches(branch: impl Parser + Clone) -> impl Parser> { - branch.clone().map(|x| vec![x]) - .or(always_branches(branch)) + branch.clone().map(|x| vec![x]).or(always_branches(branch)) } pub fn binding_parser() -> impl Parser { let binding = recursive(move |binding| { - let wildcard = just(Token::Wildcard) - .map_with_span(|_, span| SrcNode::new(ast::Pat::Wildcard, span)); + let wildcard = + just(Token::Wildcard).map_with_span(|_, span| SrcNode::new(ast::Pat::Wildcard, span)); let litr = literal_parser() .map_with_span(|litr, span| SrcNode::new(ast::Pat::Literal(litr), span)); let paren_binding = nested_parser( - binding.clone() + binding + .clone() .then(ty_hint_parser()) .map(|(binding, ty): (SrcNode, _)| ast::Binding { ty, @@ -245,33 +261,37 @@ pub fn binding_parser() -> impl Parser { Delimiter::Paren, |_| None, ) - .map(|x| x.map(ast::Pat::Single).unwrap_or(ast::Pat::Error)) - .map_with_span(SrcNode::new); + .map(|x| x.map(ast::Pat::Single).unwrap_or(ast::Pat::Error)) + .map_with_span(SrcNode::new); let tuple = nested_parser( - binding.clone() + binding + .clone() .separated_by(just(Token::Comma)) .allow_trailing() .map(Some), Delimiter::Paren, |_| None, ) - .map(|x| x.map(ast::Pat::Tuple).unwrap_or(ast::Pat::Error)) - .map_with_span(SrcNode::new); + .map(|x| x.map(ast::Pat::Tuple).unwrap_or(ast::Pat::Error)) + .map_with_span(SrcNode::new); let record = nested_parser( term_ident_parser() .map_with_span(SrcNode::new) .then(ty_hint_parser()) - .then(just(Token::Tilde) - .ignore_then(binding.clone()) - .or_not()) + .then(just(Token::Tilde).ignore_then(binding.clone()).or_not()) .map_with_span(|((field, ty), binding), span| { - let binding = binding.unwrap_or_else(|| SrcNode::new(ast::Binding { - pat: SrcNode::new(ast::Pat::Wildcard, field.span()), - name: Some(field.clone()), - ty, - }, span)); + let binding = binding.unwrap_or_else(|| { + SrcNode::new( + ast::Binding { + pat: SrcNode::new(ast::Pat::Wildcard, field.span()), + name: Some(field.clone()), + ty, + }, + span, + ) + }); (field, binding) }) @@ -283,38 +303,47 @@ pub fn binding_parser() -> impl Parser { Delimiter::Brace, |_| None, ) - .map(|x| x.map(ast::Pat::Record).unwrap_or(ast::Pat::Error)) - .map_with_span(SrcNode::new); + .map(|x| x.map(ast::Pat::Record).unwrap_or(ast::Pat::Error)) + .map_with_span(SrcNode::new); let list = nested_parser( - binding.clone() + binding + .clone() .separated_by(just(Token::Comma)) .allow_trailing() - .then(just(Token::Op(Op::Ellipsis)) - .ignore_then(binding.clone().or_not()) - .or_not()) + .then( + just(Token::Op(Op::Ellipsis)) + .ignore_then(binding.clone().or_not()) + .or_not(), + ) .map(Some) .boxed(), Delimiter::Brack, |_| None, ) - .map(|x| x - .map(|(items, tail)| match tail { - Some(tail) => ast::Pat::ListFront(items, tail), - None => ast::Pat::ListExact(items), - }) - .unwrap_or(ast::Pat::Error)) - .map_with_span(SrcNode::new); + .map(|x| { + x.map(|(items, tail)| match tail { + Some(tail) => ast::Pat::ListFront(items, tail), + None => ast::Pat::ListExact(items), + }) + .unwrap_or(ast::Pat::Error) + }) + .map_with_span(SrcNode::new); let deconstruct = type_ident_parser() // TODO: Replace with `data_item_parser` when ready .map_with_span(SrcNode::new) .then(binding.or_not()) .map_with_span(|(data, inner), span| { - let inner = inner.unwrap_or_else(|| SrcNode::new(ast::Binding { - pat: SrcNode::new(ast::Pat::Tuple(Vec::new()), data.span()), - name: None, - ty: None, - }, data.span())); + let inner = inner.unwrap_or_else(|| { + SrcNode::new( + ast::Binding { + pat: SrcNode::new(ast::Pat::Tuple(Vec::new()), data.span()), + name: None, + ty: None, + }, + data.span(), + ) + }); SrcNode::new(ast::Pat::Deconstruct(data, inner), span) }); @@ -326,31 +355,46 @@ pub fn binding_parser() -> impl Parser { .or(record) .or(list) .or(deconstruct) - .or(select! { Token::Error(_) => () }.map_with_span(|_, span| SrcNode::new(ast::Pat::Error, span))) + .or(select! { Token::Error(_) => () } + .map_with_span(|_, span| SrcNode::new(ast::Pat::Error, span))) .map(|atom| (atom, None)) .or(term_ident_parser().map_with_span(|ident, span| { - (SrcNode::new(ast::Pat::Wildcard, span), Some(SrcNode::new(ident, span))) + ( + SrcNode::new(ast::Pat::Wildcard, span), + Some(SrcNode::new(ident, span)), + ) })) .boxed(); let sum = atom - .then(just(Token::Op(Op::Add)) - .to(ast::BinaryOp::Add) - .map_with_span(SrcNode::new) - .then(literal_parser().map_with_span(SrcNode::new)) - .repeated()) + .then( + just(Token::Op(Op::Add)) + .to(ast::BinaryOp::Add) + .map_with_span(SrcNode::new) + .then(literal_parser().map_with_span(SrcNode::new)) + .repeated(), + ) .foldl(|(lhs_pat, lhs_name), (op, rhs)| { let span = lhs_pat.span().union(op.span()).union(rhs.span()); let lhs_span = lhs_pat.span(); - (SrcNode::new(ast::Pat::Binary( - op, - SrcNode::new(ast::Binding { - pat: lhs_pat, - name: lhs_name, - ty: None, - }, lhs_span), - rhs, - ), span), None) + ( + SrcNode::new( + ast::Pat::Binary( + op, + SrcNode::new( + ast::Binding { + pat: lhs_pat, + name: lhs_name, + ty: None, + }, + lhs_span, + ), + rhs, + ), + span, + ), + None, + ) }); let pat = sum; @@ -362,31 +406,44 @@ pub fn binding_parser() -> impl Parser { .then(pat.clone()) .map(|(binding, (pat, name))| { let pat_span = pat.span(); - let inner_binding = SrcNode::new(ast::Binding { - pat, - name, - ty: None, - }, pat_span); - (SrcNode::new(ast::Pat::Single(inner_binding), pat_span), Some(binding)) + let inner_binding = SrcNode::new( + ast::Binding { + pat, + name, + ty: None, + }, + pat_span, + ); + ( + SrcNode::new(ast::Pat::Single(inner_binding), pat_span), + Some(binding), + ) }) // Unbound pattern .or(pat) // Ident - .or(term_ident_parser().map_with_span(|name, span| ( - SrcNode::new(ast::Pat::Wildcard, span), - if *name == "_" { - None - } else { - Some(SrcNode::new(name, span)) - }, - ))) + .or(term_ident_parser().map_with_span(|name, span| { + ( + SrcNode::new(ast::Pat::Wildcard, span), + if *name == "_" { + None + } else { + Some(SrcNode::new(name, span)) + }, + ) + })) // TODO: Resolve ambiguity // .then(ty_hint_parser()) - .map_with_span(|/*(*/(pat, name)/*, ty)*/, span| SrcNode::new(ast::Binding { - pat, - name, - ty: None, - }, span)) + .map_with_span(|/*(*/ (pat, name) /*, ty)*/, span| { + SrcNode::new( + ast::Binding { + pat, + name, + ty: None, + }, + span, + ) + }) .boxed(); binding @@ -396,14 +453,10 @@ pub fn binding_parser() -> impl Parser { let binding = binding .map(|expr| expr.into_inner()) .then(ty_hint_parser()) - .map(|(binding, ty)| ast::Binding { - ty, - ..binding - }); + .map(|(binding, ty)| ast::Binding { ty, ..binding }); // Union pattern - binding - .labelled("pattern") + binding.labelled("pattern") } pub fn expr_parser() -> impl Parser { @@ -412,8 +465,7 @@ pub fn expr_parser() -> impl Parser { let ident = term_ident_parser().map(ast::Expr::Local); let paren_exp_list = nested_parser( - expr - .clone() + expr.clone() .map_with_span(SrcNode::new) .separated_by(just(Token::Comma)) .allow_trailing() @@ -430,15 +482,17 @@ pub fn expr_parser() -> impl Parser { let fields = nested_parser( term_ident_parser() .map_with_span(SrcNode::new) - .then(just(Token::Colon) - .ignore_then(expr.clone().map_with_span(SrcNode::new)) - .or_not()) + .then( + just(Token::Colon) + .ignore_then(expr.clone().map_with_span(SrcNode::new)) + .or_not(), + ) .map(|(field, val)| match val { Some(val) => (field, val), None => { let val = SrcNode::new(ast::Expr::Local(*field), field.span()); (field, val) - }, + } }) .separated_by(just(Token::Comma)) .allow_trailing() @@ -454,26 +508,29 @@ pub fn expr_parser() -> impl Parser { .labelled("record"); let list = nested_parser( - expr - .clone() + expr.clone() .map_with_span(SrcNode::new) .separated_by(just(Token::Comma)) .allow_trailing() - .then(just(Token::Op(Op::Ellipsis)) - .ignore_then(expr.clone() - .map_with_span(SrcNode::new) - .separated_by(just(Token::Comma)) - .allow_trailing()) - .or_not()) + .then( + just(Token::Op(Op::Ellipsis)) + .ignore_then( + expr.clone() + .map_with_span(SrcNode::new) + .separated_by(just(Token::Comma)) + .allow_trailing(), + ) + .or_not(), + ) .map(Some), Delimiter::Brack, |_| None, ) - .map(|x| match x { - Some((items, tails)) => ast::Expr::List(items, tails.unwrap_or_else(Vec::new)), - None => ast::Expr::Error, - }) - .labelled("list"); + .map(|x| match x { + Some((items, tails)) => ast::Expr::List(items, tails.unwrap_or_default()), + None => ast::Expr::Error, + }) + .labelled("list"); let branch = binding_parser() .map_with_span(SrcNode::new) @@ -481,13 +538,10 @@ pub fn expr_parser() -> impl Parser { .allow_trailing() .map_with_span(SrcNode::new) .then_ignore(just(Token::Op(Op::RFlow))) - .then(expr - .clone() - .map_with_span(SrcNode::new)) + .then(expr.clone().map_with_span(SrcNode::new)) .boxed(); - let pattern_branches = branches(branch) - .or(just(Token::Pipe).map(|_| Vec::new())); + let pattern_branches = branches(branch).or(just(Token::Pipe).map(|_| Vec::new())); let func = just(Token::Fn) .ignore_then(pattern_branches.clone().map_with_span(SrcNode::new)) @@ -496,22 +550,25 @@ pub fn expr_parser() -> impl Parser { let class_access = type_parser() .map_with_span(SrcNode::new) .delimited_by(just(Token::Op(Op::Less)), just(Token::Op(Op::More))) - .or(type_ident_parser() - .map_with_span(SrcNode::new) - .map(|ty| { - let ty_span = ty.span(); - SrcNode::new(ast::Type::Data(ty, Vec::new()), ty_span) - })) - .then(just(Token::Op(Op::Dot)) - .ignore_then(term_ident_parser().map_with_span(SrcNode::new))) + .or(type_ident_parser().map_with_span(SrcNode::new).map(|ty| { + let ty_span = ty.span(); + SrcNode::new(ast::Type::Data(ty, Vec::new()), ty_span) + })) + .then( + just(Token::Op(Op::Dot)) + .ignore_then(term_ident_parser().map_with_span(SrcNode::new)), + ) .map(|(ty, field)| ast::Expr::ClassAccess(ty, field)); let let_ = just(Token::Let) - .ignore_then(binding_parser().map_with_span(SrcNode::new) - .then_ignore(just(Token::Op(Op::Eq))) - .then(expr.clone().map_with_span(SrcNode::new)) - .separated_by(just(Token::Comma)) - .allow_trailing()) + .ignore_then( + binding_parser() + .map_with_span(SrcNode::new) + .then_ignore(just(Token::Op(Op::Eq))) + .then(expr.clone().map_with_span(SrcNode::new)) + .separated_by(just(Token::Comma)) + .allow_trailing(), + ) .then_ignore(just(Token::In)) .then(expr.clone().map_with_span(SrcNode::new)) .map(|(bindings, then)| ast::Expr::Let(bindings, then)) @@ -527,10 +584,13 @@ pub fn expr_parser() -> impl Parser { .boxed(); let match_ = just(Token::When) - .ignore_then(expr.clone().map_with_span(SrcNode::new) - .separated_by(just(Token::Comma)) - .allow_trailing() - .map_with_span(SrcNode::new)) + .ignore_then( + expr.clone() + .map_with_span(SrcNode::new) + .separated_by(just(Token::Comma)) + .allow_trailing() + .map_with_span(SrcNode::new), + ) .then_ignore(just(Token::Is)) .then(pattern_branches) .map(|(inputs, branches)| ast::Expr::Match(inputs, branches)) @@ -541,63 +601,59 @@ pub fn expr_parser() -> impl Parser { .then(paren_exp_list.clone().or_not()) .map(|(name, args)| ast::Expr::Intrinsic(name, args.flatten().unwrap_or_default())); - let cons_unit = type_ident_parser() - .map_with_span(SrcNode::new) - .map(|cons| { - let span = cons.span(); - ast::Expr::Cons(cons, SrcNode::new(ast::Expr::Tuple(Vec::new()), span)) - }); + let cons_unit = type_ident_parser().map_with_span(SrcNode::new).map(|cons| { + let span = cons.span(); + ast::Expr::Cons(cons, SrcNode::new(ast::Expr::Tuple(Vec::new()), span)) + }); let stmt = just(Token::Let) .ignore_then(binding_parser().map_with_span(SrcNode::new)) .then_ignore(just(Token::Op(Op::Eq))) .then(expr.clone().map_with_span(SrcNode::new)) .map(|(lhs, rhs)| (Some(lhs), rhs)) - .or(expr.clone().map_with_span(SrcNode::new).map(|rhs| (None, rhs))); - - let basin = just(Token::Effect) - .ignore_then(nested_parser( - stmt.clone() - .then_ignore(just(Token::Semicolon)) - .repeated() - .then(expr.clone() - .map_with_span(SrcNode::new) - .or_not()) - .map_with_span(|(init, end), span| { - let last = if let Some(end) = end { - end - } else { - SrcNode::new(ast::Expr::Tuple(Vec::new()), span) - }; - ast::Expr::Basin(init, last) - }), - Delimiter::Brace, - |_| ast::Expr::Error, - )); - - let block = just(Token::Do) - .ignore_then(nested_parser( - stmt - .then_ignore(just(Token::Semicolon)) - .repeated() - .then(expr.clone() - .map_with_span(SrcNode::new) - .or_not()) - .map_with_span(|(init, end), span| { - let last = if let Some(end) = end { - end - } else { - SrcNode::new(ast::Expr::Tuple(Vec::new()), span) - }; - ast::Expr::Block(init, last) - }), - Delimiter::Brace, - |_| ast::Expr::Error, - )); + .or(expr + .clone() + .map_with_span(SrcNode::new) + .map(|rhs| (None, rhs))); + + let basin = just(Token::Effect).ignore_then(nested_parser( + stmt.clone() + .then_ignore(just(Token::Semicolon)) + .repeated() + .then(expr.clone().map_with_span(SrcNode::new).or_not()) + .map_with_span(|(init, end), span| { + let last = if let Some(end) = end { + end + } else { + SrcNode::new(ast::Expr::Tuple(Vec::new()), span) + }; + ast::Expr::Basin(init, last) + }), + Delimiter::Brace, + |_| ast::Expr::Error, + )); + + let block = just(Token::Do).ignore_then(nested_parser( + stmt.then_ignore(just(Token::Semicolon)) + .repeated() + .then(expr.clone().map_with_span(SrcNode::new).or_not()) + .map_with_span(|(init, end), span| { + let last = if let Some(end) = end { + end + } else { + SrcNode::new(ast::Expr::Tuple(Vec::new()), span) + }; + ast::Expr::Block(init, last) + }), + Delimiter::Brace, + |_| ast::Expr::Error, + )); let atom = litr .or(ident) - .or(nested_parser(expr.clone(), Delimiter::Paren, |_| ast::Expr::Error)) + .or(nested_parser(expr.clone(), Delimiter::Paren, |_| { + ast::Expr::Error + })) .or(tuple) .or(record) .or(list) @@ -617,26 +673,23 @@ pub fn expr_parser() -> impl Parser { .boxed(); // Apply direct (a pattern like `f(arg)` more eagerly binds than a simple application chain - let direct = atom - .then(paren_exp_list.clone().or_not()) - .map_with_span(|(expr, args), span| match args { + let direct = atom.then(paren_exp_list.clone().or_not()).map_with_span( + |(expr, args), span| match args { Some(Some(args)) => { let arg_count = args.len(); - args - .into_iter() - .enumerate() - .fold(expr, |f, (i, arg)| { - let span = if i == arg_count - 1 { - span - } else { - f.span().union(arg.span()) - }; - SrcNode::new(ast::Expr::Apply(f, arg), span) - }) - }, + args.into_iter().enumerate().fold(expr, |f, (i, arg)| { + let span = if i == arg_count - 1 { + span + } else { + f.span().union(arg.span()) + }; + SrcNode::new(ast::Expr::Apply(f, arg), span) + }) + } Some(None) => SrcNode::new(ast::Expr::Error, span), None => expr, - }); + }, + ); enum Chain { Field(SrcNode), @@ -645,7 +698,8 @@ pub fn expr_parser() -> impl Parser { Propagate(SrcNode), } - let field = term_ident_parser().or(select! { Token::Nat(x) => ast::Ident::new(format!("{}", x)) }); + let field = + term_ident_parser().or(select! { Token::Nat(x) => ast::Ident::new(format!("{}", x)) }); let chain = just(Token::Op(Op::Dot)) .ignore_then(field.map_with_span(SrcNode::new)) .map(Chain::Field) @@ -653,10 +707,10 @@ pub fn expr_parser() -> impl Parser { .to(ast::UnaryOp::Propagate) .map_with_span(SrcNode::new) .map(Chain::Propagate)) - .or(just(Token::Op(Op::RArrow)).ignore_then(direct.clone()) + .or(just(Token::Op(Op::RArrow)) + .ignore_then(direct.clone()) .map(Chain::Infix)) - .or(paren_exp_list - .map_with_span(|args, span| Chain::Apply(args, span))) + .or(paren_exp_list.map_with_span(Chain::Apply)) .boxed(); let chained = direct @@ -665,38 +719,37 @@ pub fn expr_parser() -> impl Parser { Chain::Field(field) => { let span = expr.span().union(field.span()); SrcNode::new(ast::Expr::Access(expr, field), span) - }, + } Chain::Infix(f) => { let span = expr.span().union(f.span()); SrcNode::new(ast::Expr::Apply(f, expr), span) - }, + } Chain::Apply(None, _span) => SrcNode::new(ast::Expr::Error, expr.span()), Chain::Apply(Some(args), outer_span) => { let arg_count = args.len(); - args - .into_iter() - .enumerate() - .fold(expr, |f, (i, arg)| { - let span = if i == arg_count - 1 { - outer_span - } else { - f.span().union(arg.span()) - }; - SrcNode::new(ast::Expr::Apply(f, arg), span) - }) - }, + args.into_iter().enumerate().fold(expr, |f, (i, arg)| { + let span = if i == arg_count - 1 { + outer_span + } else { + f.span().union(arg.span()) + }; + SrcNode::new(ast::Expr::Apply(f, arg), span) + }) + } Chain::Propagate(op) => { let span = expr.span().union(op.span()); SrcNode::new(ast::Expr::Unary(op, expr), span) - }, + } }) .boxed(); // Unary - let op = just(Token::Op(Op::Sub)).to(ast::UnaryOp::Neg) + let op = just(Token::Op(Op::Sub)) + .to(ast::UnaryOp::Neg) .or(just(Token::Op(Op::Not)).to(ast::UnaryOp::Not)) .map_with_span(SrcNode::new); - let unary = op.repeated() + let unary = op + .repeated() .then(chained.labelled("unary operand")) .foldr(|op, expr| { let span = op.span().union(expr.span()); @@ -705,11 +758,13 @@ pub fn expr_parser() -> impl Parser { .boxed(); // Product - let op = just(Token::Op(Op::Mul)).to(ast::BinaryOp::Mul) + let op = just(Token::Op(Op::Mul)) + .to(ast::BinaryOp::Mul) .or(just(Token::Op(Op::Div)).to(ast::BinaryOp::Div)) .or(just(Token::Op(Op::Rem)).to(ast::BinaryOp::Rem)) .map_with_span(SrcNode::new); - let product = unary.clone() + let product = unary + .clone() .then(op.then(unary.labelled("binary operand")).repeated()) .foldl(|a, (op, b)| { let span = a.span().union(b.span()); @@ -718,10 +773,12 @@ pub fn expr_parser() -> impl Parser { .boxed(); // Sum - let op = just(Token::Op(Op::Add)).to(ast::BinaryOp::Add) + let op = just(Token::Op(Op::Add)) + .to(ast::BinaryOp::Add) .or(just(Token::Op(Op::Sub)).to(ast::BinaryOp::Sub)) .map_with_span(SrcNode::new); - let sum = product.clone() + let sum = product + .clone() .then(op.then(product.labelled("binary operand")).repeated()) .foldl(|a, (op, b)| { let span = a.span().union(b.span()); @@ -730,9 +787,11 @@ pub fn expr_parser() -> impl Parser { .boxed(); // List joining - let op = just(Token::Op(Op::Join)).to(ast::BinaryOp::Join) + let op = just(Token::Op(Op::Join)) + .to(ast::BinaryOp::Join) .map_with_span(SrcNode::new); - let join = sum.clone() + let join = sum + .clone() .then(op.then(sum.labelled("binary operand")).repeated()) .foldl(|a, (op, b)| { let span = a.span().union(b.span()); @@ -741,14 +800,16 @@ pub fn expr_parser() -> impl Parser { .boxed(); // Comparison - let op = just(Token::Op(Op::Less)).to(ast::BinaryOp::Less) + let op = just(Token::Op(Op::Less)) + .to(ast::BinaryOp::Less) .or(just(Token::Op(Op::LessEq)).to(ast::BinaryOp::LessEq)) .or(just(Token::Op(Op::More)).to(ast::BinaryOp::More)) .or(just(Token::Op(Op::MoreEq)).to(ast::BinaryOp::MoreEq)) .or(just(Token::Op(Op::Eq)).to(ast::BinaryOp::Eq)) .or(just(Token::Op(Op::NotEq)).to(ast::BinaryOp::NotEq)) .map_with_span(SrcNode::new); - let comparison = join.clone() + let comparison = join + .clone() .then(op.then(join.labelled("binary operand")).repeated()) .foldl(|a, (op, b)| { let span = a.span().union(b.span()); @@ -757,11 +818,13 @@ pub fn expr_parser() -> impl Parser { .boxed(); // Logical - let op = just(Token::Op(Op::And)).to(ast::BinaryOp::And) + let op = just(Token::Op(Op::And)) + .to(ast::BinaryOp::And) .or(just(Token::Op(Op::Or)).to(ast::BinaryOp::Or)) .or(just(Token::Op(Op::Xor)).to(ast::BinaryOp::Xor)) .map_with_span(SrcNode::new); - let logical = comparison.clone() + let logical = comparison + .clone() .then(op.then(comparison.labelled("binary operand")).repeated()) .foldl(|a, (op, b)| { let span = a.span().union(b.span()); @@ -771,14 +834,19 @@ pub fn expr_parser() -> impl Parser { let with = logical .then(just(Token::With).ignore_then(fields).or_not()) - .map_with_span(|(expr, fields), span| if let Some(fields) = fields { - SrcNode::new(if let Some(fields) = fields { - ast::Expr::Update(expr, fields) + .map_with_span(|(expr, fields), span| { + if let Some(fields) = fields { + SrcNode::new( + if let Some(fields) = fields { + ast::Expr::Update(expr, fields) + } else { + ast::Expr::Error + }, + span, + ) } else { - ast::Expr::Error - }, span) - } else { - expr + expr + } }) .boxed(); @@ -791,51 +859,64 @@ pub fn expr_parser() -> impl Parser { .boxed(); let binding = binding_parser().map_with_span(SrcNode::new); - let handle = cons.then(just(Token::Handle).ignore_then(branches( - term_ident_parser().map_with_span(SrcNode::new) - .then(type_parser() - .map_with_span(SrcNode::new) - .repeated()) - .then_ignore(just(Token::With)) - .then(binding.clone()) - .then(just(Token::Comma).ignore_then(binding).or_not()) - .then_ignore(just(Token::Op(Op::RFlow))) - .then(expr.clone().map_with_span(SrcNode::new)) - )) - .or_not()) - .map_with_span(|(expr, handlers), span| if let Some(handlers) = handlers { - SrcNode::new(ast::Expr::Handle { - expr, - handlers: handlers - .into_iter() - .map(|((((eff_name, eff_gen_tys), send), state), recv)| ast::Handler { - eff_name, - eff_gen_tys, - send, - state, - recv, - }) - .collect(), - }, span) - } else { - expr + let handle = cons + .then( + just(Token::Handle) + .ignore_then(branches( + term_ident_parser() + .map_with_span(SrcNode::new) + .then(type_parser().map_with_span(SrcNode::new).repeated()) + .then_ignore(just(Token::With)) + .then(binding.clone()) + .then(just(Token::Comma).ignore_then(binding).or_not()) + .then_ignore(just(Token::Op(Op::RFlow))) + .then(expr.clone().map_with_span(SrcNode::new)), + )) + .or_not(), + ) + .map_with_span(|(expr, handlers), span| { + if let Some(handlers) = handlers { + SrcNode::new( + ast::Expr::Handle { + expr, + handlers: handlers + .into_iter() + .map(|((((eff_name, eff_gen_tys), send), state), recv)| { + ast::Handler { + eff_name, + eff_gen_tys, + send, + state, + recv, + } + }) + .collect(), + }, + span, + ) + } else { + expr + } }); - handle - .map(|b| b.into_inner()) + handle.map(|b| b.into_inner()) }) - .labelled("expression") + .labelled("expression") } pub fn obligation_parser() -> impl Parser>> { - just(Token::Op(Op::Less)) - .ignore_then(class_inst_parser() + just(Token::Op(Op::Less)).ignore_then( + class_inst_parser() .map_with_span(SrcNode::new) .separated_by(just(Token::Op(Op::Add))) - .allow_leading()) + .allow_leading(), + ) } -pub fn implied_member_parser() -> impl Parser<(SrcNode, Vec<(SrcNode, SrcNode)>)> { +pub fn implied_member_parser() -> impl Parser<( + SrcNode, + Vec<(SrcNode, SrcNode)>, +)> { let assoc = nested_parser( type_ident_parser() .map_with_span(SrcNode::new) @@ -847,32 +928,51 @@ pub fn implied_member_parser() -> impl Parser<(SrcNode, Vec<(Src |_| Vec::new(), ); - class_inst_parser() - .map_with_span(SrcNode::new) - .then(just(Token::With).ignore_then(assoc) + class_inst_parser().map_with_span(SrcNode::new).then( + just(Token::With) + .ignore_then(assoc) .or_not() - .map(|xs| xs.unwrap_or_default())) + .map(|xs| xs.unwrap_or_default()), + ) } -pub fn generics_parser() -> impl Parser<(Vec<(ast::GenericTy, Vec>)>, Vec)> { +pub fn generics_parser() -> impl Parser<( + Vec<(ast::GenericTy, Vec>)>, + Vec, +)> { type_ident_parser() .map_with_span(SrcNode::new) - .then(just(Token::Op(Op::Less)).ignore_then(implied_member_parser() - .separated_by(just(Token::Op(Op::Add))) - .allow_leading()) - .or_not()) - .map_with_span(|(name, implied_members), span| ( - ast::GenericTy { name: name.clone() }, - implied_members - .unwrap_or_default() - .into_iter() - .map(move |(class, assoc)| SrcNode::new(ast::ImpliedMember { - member: SrcNode::new(ast::Type::Data(name.clone(), Vec::new()), name.span()), - class, - assoc, - }, span)) - .collect(), - )) + .then( + just(Token::Op(Op::Less)) + .ignore_then( + implied_member_parser() + .separated_by(just(Token::Op(Op::Add))) + .allow_leading(), + ) + .or_not(), + ) + .map_with_span(|(name, implied_members), span| { + ( + ast::GenericTy { name: name.clone() }, + implied_members + .unwrap_or_default() + .into_iter() + .map(move |(class, assoc)| { + SrcNode::new( + ast::ImpliedMember { + member: SrcNode::new( + ast::Type::Data(name.clone(), Vec::new()), + name.span(), + ), + class, + assoc, + }, + span, + ) + }) + .collect(), + ) + }) .map(Ok) .or(term_ident_parser() .map_with_span(SrcNode::new) @@ -897,31 +997,36 @@ pub fn where_parser() -> impl Parser>> { let clause = type_parser() .map_with_span(SrcNode::new) .then_ignore(just(Token::Op(Op::Less))) - .then(implied_member_parser() - .separated_by(just(Token::Op(Op::Add))) - .allow_leading()) + .then( + implied_member_parser() + .separated_by(just(Token::Op(Op::Add))) + .allow_leading(), + ) .map_with_span(SrcNode::new); just(Token::Where) - .ignore_then(clause - .separated_by(just(Token::Comma)) - .allow_trailing()) + .ignore_then(clause.separated_by(just(Token::Comma)).allow_trailing()) .or_not() - .map(|clauses| clauses - .into_iter() - .flat_map(|clauses| clauses.into_iter()) - .flat_map(|clause| { - let span = clause.span(); - let (ty, classes) = clause.into_inner(); - classes - .into_iter() - .map(move |(class, assoc)| SrcNode::new(ast::ImpliedMember { - member: ty.clone(), - class, - assoc, - }, span)) - }) - .collect()) + .map(|clauses| { + clauses + .into_iter() + .flat_map(|clauses| clauses.into_iter()) + .flat_map(|clause| { + let span = clause.span(); + let (ty, classes) = clause.into_inner(); + classes.into_iter().map(move |(class, assoc)| { + SrcNode::new( + ast::ImpliedMember { + member: ty.clone(), + class, + assoc, + }, + span, + ) + }) + }) + .collect() + }) } const ITEM_STARTS: [Token; 8] = [ @@ -938,32 +1043,50 @@ const ITEM_STARTS: [Token; 8] = [ pub fn data_parser() -> impl Parser { let variant = type_ident_parser() .map_with_span(SrcNode::new) - .then(type_parser() - .map_with_span(SrcNode::new) - .or_not()) + .then(type_parser().map_with_span(SrcNode::new).or_not()) .map(|(name, ty)| { let name_span = name.span(); - (name, ty.unwrap_or_else(|| SrcNode::new(ast::Type::Tuple(Vec::new()), name_span))) + ( + name, + ty.unwrap_or_else(|| SrcNode::new(ast::Type::Tuple(Vec::new()), name_span)), + ) }) .boxed(); just(Token::Data) - .ignore_then(type_ident_parser() - .map_with_span(SrcNode::new)) - .then(generics_parser() - .then(where_parser()) - .map(|((tys, effs), implied)| ast::Generics::from_tys_and_implied(tys, effs, implied))) - .then(just(Token::Op(Op::Eq)) - // TODO: Don't use `Result` - .ignore_then(type_parser().map_with_span(SrcNode::new).map(Err) - .or(branches(variant).map(Some).or(just(Token::Pipe).to(None)).map(Ok))) - .or_not()) + .ignore_then(type_ident_parser().map_with_span(SrcNode::new)) + .then( + generics_parser() + .then(where_parser()) + .map(|((tys, effs), implied)| { + ast::Generics::from_tys_and_implied(tys, effs, implied) + }), + ) + .then( + just(Token::Op(Op::Eq)) + // TODO: Don't use `Result` + .ignore_then( + type_parser() + .map_with_span(SrcNode::new) + .map(Err) + .or(branches(variant) + .map(Some) + .or(just(Token::Pipe).to(None)) + .map(Ok)), + ) + .or_not(), + ) .map(|((name, generics), variants)| ast::Data { generics, variants: variants - .unwrap_or_else(|| Ok(Some(vec![(name.clone(), SrcNode::new(ast::Type::Tuple(Vec::new()), name.span()))]))) + .unwrap_or_else(|| { + Ok(Some(vec![( + name.clone(), + SrcNode::new(ast::Type::Tuple(Vec::new()), name.span()), + )])) + }) .unwrap_or_else(|ty| Some(vec![(name.clone(), ty)])) - .unwrap_or_else(|| Vec::new()), + .unwrap_or_default(), name, }) .boxed() @@ -971,18 +1094,17 @@ pub fn data_parser() -> impl Parser { pub fn alias_parser() -> impl Parser { just(Token::Type) - .ignore_then(type_ident_parser() - .map_with_span(SrcNode::new)) - .then(generics_parser() - .then(where_parser()) - .map(|((tys, effs), implied)| ast::Generics::from_tys_and_implied(tys, effs, implied))) + .ignore_then(type_ident_parser().map_with_span(SrcNode::new)) + .then( + generics_parser() + .then(where_parser()) + .map(|((tys, effs), implied)| { + ast::Generics::from_tys_and_implied(tys, effs, implied) + }), + ) .then_ignore(just(Token::Op(Op::Eq))) .then(type_parser().map_with_span(SrcNode::new)) - .map(|((name, generics), ty)| ast::Alias { - name, - generics, - ty, - }) + .map(|((name, generics), ty)| ast::Alias { name, generics, ty }) .boxed() } @@ -993,45 +1115,55 @@ pub fn fn_parser() -> impl Parser { .allow_trailing() .map_with_span(SrcNode::new) .then_ignore(just(Token::Op(Op::RFlow))) - .then(expr_parser() - .map_with_span(SrcNode::new)) + .then(expr_parser().map_with_span(SrcNode::new)) .boxed(); just(Token::Fn) - .ignore_then(term_ident_parser() - .map_with_span(SrcNode::new)) + .ignore_then(term_ident_parser().map_with_span(SrcNode::new)) .then(generics_parser()) .then(ty_hint_parser()) .then(where_parser()) .then_ignore(just(Token::Op(Op::Eq))) - .then(branches(branch) - .map_with_span(|branches, span| SrcNode::new(ast::Expr::Func(SrcNode::new(branches, span)), span))) - .map(|((((name, (generic_tys, generic_effs)), ty_hint), where_clauses), body)| ast::Def { - generics: ast::Generics::from_tys_and_implied(generic_tys, generic_effs, where_clauses), - ty_hint: ty_hint.unwrap_or_else(|| SrcNode::new(ast::Type::Unknown, name.span())), - name, - body, - }) + .then(branches(branch).map_with_span(|branches, span| { + SrcNode::new(ast::Expr::Func(SrcNode::new(branches, span)), span) + })) + .map( + |((((name, (generic_tys, generic_effs)), ty_hint), where_clauses), body)| ast::Def { + generics: ast::Generics::from_tys_and_implied( + generic_tys, + generic_effs, + where_clauses, + ), + ty_hint: ty_hint.unwrap_or_else(|| SrcNode::new(ast::Type::Unknown, name.span())), + name, + body, + }, + ) } pub fn def_parser() -> impl Parser { just(Token::Def) - .ignore_then(term_ident_parser() - .map_with_span(SrcNode::new)) + .ignore_then(term_ident_parser().map_with_span(SrcNode::new)) .then(generics_parser()) .then(ty_hint_parser()) .then(where_parser()) .then_ignore(just(Token::Op(Op::Eq))) .then(expr_parser().map_with_span(SrcNode::new)) - .map(|((((name, (generic_tys, generic_effs)), ty_hint), where_clauses), body)| ast::Def { - generics: ast::Generics::from_tys_and_implied(generic_tys, generic_effs, where_clauses), - ty_hint: ty_hint.unwrap_or_else(|| SrcNode::new(ast::Type::Unknown, name.span())), - name, - body: { - let body_span = body.span(); - SrcNode::new(ast::Expr::Basin(Vec::new(), body), body_span) + .map( + |((((name, (generic_tys, generic_effs)), ty_hint), where_clauses), body)| ast::Def { + generics: ast::Generics::from_tys_and_implied( + generic_tys, + generic_effs, + where_clauses, + ), + ty_hint: ty_hint.unwrap_or_else(|| SrcNode::new(ast::Type::Unknown, name.span())), + name, + body: { + let body_span = body.span(); + SrcNode::new(ast::Expr::Basin(Vec::new(), body), body_span) + }, }, - }) + ) .boxed() } @@ -1046,40 +1178,51 @@ pub fn class_parser() -> impl Parser { let assoc_type = type_ident_parser() .map_with_span(SrcNode::new) - .then(obligation_parser() - .or_not() - .map_with_span(|o, span| SrcNode::new(o.unwrap_or_default(), span))) - .map(|(name, obligations)| ast::ClassItem::Type { - obligations, - name, - }); + .then( + obligation_parser() + .or_not() + .map_with_span(|o, span| SrcNode::new(o.unwrap_or_default(), span)), + ) + .map(|(name, obligations)| ast::ClassItem::Type { obligations, name }); - let item = just(Token::Op(Op::RFlow)) - .ignore_then(value.or(assoc_type)); + let item = just(Token::Op(Op::RFlow)).ignore_then(value.or(assoc_type)); just(Token::Class) - .ignore_then(type_ident_parser() - .map_with_span(SrcNode::new)) + .ignore_then(type_ident_parser().map_with_span(SrcNode::new)) .then(obligation_parser().or_not()) - .then(generics_parser() - .then(where_parser()) - .map(|((tys, effs), implied)| ast::Generics::from_tys_and_implied(tys, effs, implied))) - .then(just(Token::Op(Op::Eq)) - .ignore_then(item.repeated()) - .or_not()) + .then( + generics_parser() + .then(where_parser()) + .map(|((tys, effs), implied)| { + ast::Generics::from_tys_and_implied(tys, effs, implied) + }), + ) + .then( + just(Token::Op(Op::Eq)) + .ignore_then(item.repeated()) + .or_not(), + ) .map(|(((name, obligation), mut generics), items)| ast::Class { generics: { - generics.implied_members.extend(obligation - .into_iter() - .flatten() - .map(|class| { + generics + .implied_members + .extend(obligation.into_iter().flatten().map(|class| { let class_span = class.name.span(); // TODO: Horrible - SrcNode::new(ast::ImpliedMember { - member: SrcNode::new(ast::Type::Data(SrcNode::new(ast::Ident::new("Self"), class_span), Vec::new()), name.span()), - class, - assoc: Vec::new(), - }, class_span) + SrcNode::new( + ast::ImpliedMember { + member: SrcNode::new( + ast::Type::Data( + SrcNode::new(ast::Ident::new("Self"), class_span), + Vec::new(), + ), + name.span(), + ), + class, + assoc: Vec::new(), + }, + class_span, + ) })); generics }, @@ -1093,8 +1236,7 @@ pub fn member_parser() -> impl Parser { let value = term_ident_parser() .map_with_span(SrcNode::new) .then_ignore(just(Token::Op(Op::Eq))) - .then(expr_parser() - .map_with_span(SrcNode::new)) + .then(expr_parser().map_with_span(SrcNode::new)) .map(|(name, val)| { let val_span = val.span(); ast::MemberItem::Value { @@ -1109,30 +1251,27 @@ pub fn member_parser() -> impl Parser { .then(type_parser().map_with_span(SrcNode::new)) .map(|(name, ty)| ast::MemberItem::Type { name, ty }); - let item = just(Token::Op(Op::RFlow)) - .ignore_then(value.or(assoc_type)); + let item = just(Token::Op(Op::RFlow)).ignore_then(value.or(assoc_type)); just(Token::For) .ignore_then(generics_parser()) .or_not() - .then(just(Token::Member) - .ignore_then(type_parser() - .map_with_span(SrcNode::new)) - .then_ignore(just(Token::Of)) - .then(class_inst_parser() - .map_with_span(SrcNode::new)) - .then(where_parser()) - .then(just(Token::Op(Op::Eq)) - .ignore_then(item.repeated()) - .or_not())) + .then( + just(Token::Member) + .ignore_then(type_parser().map_with_span(SrcNode::new)) + .then_ignore(just(Token::Of)) + .then(class_inst_parser().map_with_span(SrcNode::new)) + .then(where_parser()) + .then( + just(Token::Op(Op::Eq)) + .ignore_then(item.repeated()) + .or_not(), + ), + ) .map(|(generics, (((member, class), implied), items))| { let (generic_tys, generic_effs) = generics.unwrap_or_default(); ast::Member { - generics: ast::Generics::from_tys_and_implied( - generic_tys, - generic_effs, - implied, - ), + generics: ast::Generics::from_tys_and_implied(generic_tys, generic_effs, implied), member, class, items: items.unwrap_or_default(), @@ -1142,14 +1281,17 @@ pub fn member_parser() -> impl Parser { } pub fn effect_parser() -> impl Parser { - let ty = type_parser() - .map_with_span(SrcNode::new); + let ty = type_parser().map_with_span(SrcNode::new); just(Token::Effect) .ignore_then(term_ident_parser().map_with_span(SrcNode::new)) - .then(generics_parser() - .then(where_parser()) - .map(|((tys, effs), implied)| ast::Generics::from_tys_and_implied(tys, effs, implied))) + .then( + generics_parser() + .then(where_parser()) + .map(|((tys, effs), implied)| { + ast::Generics::from_tys_and_implied(tys, effs, implied) + }), + ) .then_ignore(just(Token::Op(Op::Eq))) .then(ty.clone()) .then_ignore(just(Token::Op(Op::RFlow))) @@ -1164,17 +1306,21 @@ pub fn effect_parser() -> impl Parser { } pub fn effect_alias_parser() -> impl Parser { - let ty = type_parser() - .map_with_span(SrcNode::new); + let ty = type_parser().map_with_span(SrcNode::new); - let effect = term_ident_parser().map_with_span(SrcNode::new) + let effect = term_ident_parser() + .map_with_span(SrcNode::new) .then(ty.repeated()); just(Token::Effect) .ignore_then(term_ident_parser().map_with_span(SrcNode::new)) - .then(generics_parser() - .then(where_parser()) - .map(|((tys, effs), implied)| ast::Generics::from_tys_and_implied(tys, effs, implied))) + .then( + generics_parser() + .then(where_parser()) + .map(|((tys, effs), implied)| { + ast::Generics::from_tys_and_implied(tys, effs, implied) + }), + ) .then_ignore(just(Token::Op(Op::Eq))) .then(effect.separated_by(just(Token::Op(Op::Add)))) .map(|((name, generics), effects)| ast::EffectAlias { @@ -1186,45 +1332,55 @@ pub fn effect_alias_parser() -> impl Parser { } pub fn item_parser() -> impl Parser { - let attr = recursive(|attr| term_ident_parser() - .map_with_span(SrcNode::new) - .then(nested_parser( - attr - .separated_by(just(Token::Comma)) - .allow_trailing(), - Delimiter::Paren, - |_| Vec::new(), + let attr = recursive(|attr| { + term_ident_parser() + .map_with_span(SrcNode::new) + .then( + nested_parser( + attr.separated_by(just(Token::Comma)).allow_trailing(), + Delimiter::Paren, + |_| Vec::new(), + ) + .or_not(), ) - .or_not()) - .map(|(name, args)| ast::Attr { name, args }) - .map_with_span(SrcNode::new)); + .map(|(name, args)| ast::Attr { name, args }) + .map_with_span(SrcNode::new) + }); let attrs = just(Token::Dollar) .ignore_then(nested_parser( - attr - .separated_by(just(Token::Comma)) - .allow_trailing(), + attr.separated_by(just(Token::Comma)).allow_trailing(), Delimiter::Brack, |_| Vec::new(), )) .repeated() .flatten(); - let item = def_parser().map(ast::ItemKind::Def).labelled("definition") + let item = def_parser() + .map(ast::ItemKind::Def) + .labelled("definition") .boxed() .or(fn_parser().map(ast::ItemKind::Def).labelled("function")) .boxed() .or(data_parser().map(ast::ItemKind::Data).labelled("data type")) .boxed() - .or(alias_parser().map(ast::ItemKind::Alias).labelled("type alias")) + .or(alias_parser() + .map(ast::ItemKind::Alias) + .labelled("type alias")) .boxed() .or(class_parser().map(ast::ItemKind::Class).labelled("class")) .boxed() - .or(member_parser().map(ast::ItemKind::Member).labelled("class member")) + .or(member_parser() + .map(ast::ItemKind::Member) + .labelled("class member")) .boxed() - .or(effect_parser().map(ast::ItemKind::Effect).labelled("effect")) + .or(effect_parser() + .map(ast::ItemKind::Effect) + .labelled("effect")) .boxed() - .or(effect_alias_parser().map(ast::ItemKind::EffectAlias).labelled("effect alias")) + .or(effect_alias_parser() + .map(ast::ItemKind::EffectAlias) + .labelled("effect alias")) .boxed(); let tail = one_of::<_, _, Error>(ITEM_STARTS) @@ -1236,7 +1392,12 @@ pub fn item_parser() -> impl Parser { .then(item) .map(|(attrs, kind)| ast::Item { attrs, kind }) .map_with_span(|item, span| (item, span)) - .then(tail.rewind().map(Ok).map(Some).or_else(|e| Ok(Some(Err(e))))) + .then( + tail.rewind() + .map(Ok) + .map(Some) + .or_else(|e| Ok(Some(Err(e)))), + ) .validate(|((item, span), mut r), _, emit| { if let Some(Err(e)) = r.take() { emit(e.while_parsing(span, "item")); @@ -1251,10 +1412,12 @@ pub fn module_parser() -> impl Parser { .repeated(); imports - .then(item_parser() - .map(Some) - .recover_with(skip_until(ITEM_STARTS, |_| None).skip_start()) - .repeated()) + .then( + item_parser() + .map(Some) + .recover_with(skip_until(ITEM_STARTS, |_| None).skip_start()) + .repeated(), + ) .then_ignore(end()) .map(|(imports, items)| ast::Module { imports, @@ -1285,38 +1448,66 @@ mod tests { let res = expr_parser() .then_ignore(end()) - .parse(chumsky::Stream::from_iter( - span(len), - tokens.into_iter(), - )) + .parse(chumsky::Stream::from_iter(span(len), tokens.into_iter())) .unwrap(); assert_eq!( res, ast::Expr::Binary( SrcNode::new(ast::BinaryOp::Add, Span::empty()), - SrcNode::new(ast::Expr::Binary( - SrcNode::new(ast::BinaryOp::Mul, Span::empty()), - SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(4)), Span::empty()), - SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(5)), Span::empty()), - ), Span::empty()), - SrcNode::new(ast::Expr::Binary( - SrcNode::new(ast::BinaryOp::Div, Span::empty()), - SrcNode::new(ast::Expr::Binary( - SrcNode::new(ast::BinaryOp::Sub, Span::empty()), - SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(3)), Span::empty()), - SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(2)), Span::empty()), - ), Span::empty()), - SrcNode::new(ast::Expr::Apply( - SrcNode::new(ast::Expr::Apply( - SrcNode::new(ast::Expr::Local(ast::Ident::new("foo")), Span::empty()), - SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(3)), Span::empty()), - ), Span::empty()), + SrcNode::new( + ast::Expr::Binary( + SrcNode::new(ast::BinaryOp::Mul, Span::empty()), SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(4)), Span::empty()), - ), Span::empty()), - ), Span::empty()), + SrcNode::new(ast::Expr::Literal(ast::Literal::Nat(5)), Span::empty()), + ), + Span::empty() + ), + SrcNode::new( + ast::Expr::Binary( + SrcNode::new(ast::BinaryOp::Div, Span::empty()), + SrcNode::new( + ast::Expr::Binary( + SrcNode::new(ast::BinaryOp::Sub, Span::empty()), + SrcNode::new( + ast::Expr::Literal(ast::Literal::Nat(3)), + Span::empty() + ), + SrcNode::new( + ast::Expr::Literal(ast::Literal::Nat(2)), + Span::empty() + ), + ), + Span::empty() + ), + SrcNode::new( + ast::Expr::Apply( + SrcNode::new( + ast::Expr::Apply( + SrcNode::new( + ast::Expr::Local(ast::Ident::new("foo")), + Span::empty() + ), + SrcNode::new( + ast::Expr::Literal(ast::Literal::Nat(3)), + Span::empty() + ), + ), + Span::empty() + ), + SrcNode::new( + ast::Expr::Literal(ast::Literal::Nat(4)), + Span::empty() + ), + ), + Span::empty() + ), + ), + Span::empty() + ), ), - "{:#?}", res, + "{:#?}", + res, ); } } diff --git a/syntax/src/span.rs b/syntax/src/span.rs index 5932d93..428a83f 100644 --- a/syntax/src/span.rs +++ b/syntax/src/span.rs @@ -1,8 +1,5 @@ use super::*; -use std::{ - ops::Range, - fmt, -}; +use std::{fmt, ops::Range}; #[derive(Copy, Clone, PartialEq, Eq)] pub struct Span { @@ -16,12 +13,19 @@ impl Span { Self::new(SrcId::empty(), 0..0) } - pub fn src(&self) -> SrcId { self.src } + pub fn src(&self) -> SrcId { + self.src + } - pub fn range(&self) -> Range { self.start()..self.end() } + pub fn range(&self) -> Range { + self.start()..self.end() + } pub fn union(self, other: Self) -> Self { - assert_eq!(self.src, other.src, "attempted to union spans with different sources"); + assert_eq!( + self.src, other.src, + "attempted to union spans with different sources" + ); Self { range: (self.start().min(other.start()), self.end().max(other.end())), ..self @@ -41,19 +45,34 @@ impl chumsky::Span for Span { fn new(src: SrcId, range: Range) -> Self { assert!(range.start <= range.end); - Self { src, range: (range.start, range.end) } + Self { + src, + range: (range.start, range.end), + } } - fn context(&self) -> SrcId { self.src } - fn start(&self) -> Self::Offset { self.range.0 } - fn end(&self) -> Self::Offset { self.range.1 } + fn context(&self) -> SrcId { + self.src + } + fn start(&self) -> Self::Offset { + self.range.0 + } + fn end(&self) -> Self::Offset { + self.range.1 + } } impl ariadne::Span for Span { type SourceId = SrcId; - fn source(&self) -> &SrcId { &self.src } + fn source(&self) -> &SrcId { + &self.src + } - fn start(&self) -> usize { self.range.0 } - fn end(&self) -> usize { self.range.1 } + fn start(&self) -> usize { + self.range.0 + } + fn end(&self) -> usize { + self.range.1 + } } diff --git a/syntax/src/src.rs b/syntax/src/src.rs index 15f1709..db16104 100644 --- a/syntax/src/src.rs +++ b/syntax/src/src.rs @@ -1,7 +1,7 @@ use internment::Intern; use std::{ - path::{Path, PathBuf}, fmt, + path::{Path, PathBuf}, }; #[derive(Copy, Clone, PartialEq, Eq, Hash)] @@ -18,7 +18,9 @@ impl fmt::Display for SrcId { } impl fmt::Debug for SrcId { - fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { write!(f, "{}", self) } + fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { + write!(f, "{}", self) + } } impl SrcId { @@ -32,11 +34,12 @@ impl SrcId { } pub fn from_path>(path: P) -> Self { - SrcId(Intern::new(path - .as_ref() - .iter() - .map(|c| c.to_string_lossy().into_owned()) - .collect())) + SrcId(Intern::new( + path.as_ref() + .iter() + .map(|c| c.to_string_lossy().into_owned()) + .collect(), + )) } pub fn to_path(&self) -> PathBuf { diff --git a/syntax/src/token.rs b/syntax/src/token.rs index 9df5254..678c529 100644 --- a/syntax/src/token.rs +++ b/syntax/src/token.rs @@ -12,16 +12,25 @@ pub enum Delimiter { #[derive(Copy, Clone, Debug, PartialEq, Eq, Hash)] pub enum Op { // Sum - Add, Sub, + Add, + Sub, // Product - Mul, Div, Rem, + Mul, + Div, + Rem, // Equality - Eq, NotEq, + Eq, + NotEq, // Comparison - Less, LessEq, - More, MoreEq, + Less, + LessEq, + More, + MoreEq, // Logical - Not, And, Or, Xor, + Not, + And, + Or, + Xor, // Lists Join, Ellipsis, @@ -216,7 +225,7 @@ pub fn lexer() -> impl Parser, Error = Error> { just('/').to(Op::Div), just('%').to(Op::Rem), )) - .map(Token::Op); + .map(Token::Op); let delim = choice(( just('(').to(Token::Open(Delimiter::Paren)), @@ -227,15 +236,16 @@ pub fn lexer() -> impl Parser, Error = Error> { just('}').to(Token::Close(Delimiter::Brace)), )); - let escape = just('\\') - .ignore_then(just('\\') - .or(just('/')) - .or(just('"')) - .or(just('b').to('\x08')) - .or(just('f').to('\x0C')) - .or(just('n').to('\n')) - .or(just('r').to('\r')) - .or(just('t').to('\t'))); + let escape = just('\\').ignore_then( + just('\\') + .or(just('/')) + .or(just('"')) + .or(just('b').to('\x08')) + .or(just('f').to('\x0C')) + .or(just('n').to('\n')) + .or(just('r').to('\r')) + .or(just('t').to('\t')), + ); let r#char = just('\'') .ignore_then(filter(|c| *c != '\\' && *c != '\'').or(escape)) @@ -288,43 +298,35 @@ pub fn lexer() -> impl Parser, Error = Error> { "when" => Token::When, "is" => Token::Is, "_" => Token::Wildcard, - _ => if s.chars().next().map_or(false, |c| c.is_uppercase()) { - Token::TypeIdent(ast::Ident::new(s)) - } else { - Token::TermIdent(ast::Ident::new(s)) - }, + _ => { + if s.chars().next().map_or(false, |c| c.is_uppercase()) { + Token::TypeIdent(ast::Ident::new(s)) + } else { + Token::TermIdent(ast::Ident::new(s)) + } + } }); let comments = just('#') - .then_ignore(just('(') - .ignore_then(take_until(just(")#")).ignored()) - .or(none_of('\n').ignored().repeated().ignored())) + .then_ignore( + just('(') + .ignore_then(take_until(just(")#")).ignored()) + .or(none_of('\n').ignored().repeated().ignored()), + ) .padded() .ignored() .repeated(); let token = choice(( - ctrl, - word, - real, - int, - nat, - op, - delim, - string, - r#char, - intrinsic, - at, + ctrl, word, real, int, nat, op, delim, string, r#char, intrinsic, at, )) - .or(any() - .map(Token::Error) - .validate(|t, span, emit| { - emit(Error::expected_input_found(span, None, Some(t))); - t - })) - .map_with_span(move |token, span| (token, span)) - .padded() - .recover_with(skip_then_retry_until([])); + .or(any().map(Token::Error).validate(|t, span, emit| { + emit(Error::expected_input_found(span, None, Some(t))); + t + })) + .map_with_span(move |token, span| (token, span)) + .padded() + .recover_with(skip_then_retry_until([])); token .padded_by(comments) diff --git a/util/src/index.rs b/util/src/index.rs index cdc21ea..25fa96b 100644 --- a/util/src/index.rs +++ b/util/src/index.rs @@ -7,16 +7,26 @@ use std::{ pub struct Id(usize, PhantomData); impl Copy for Id {} -impl Clone for Id { fn clone(&self) -> Self { *self } } +impl Clone for Id { + fn clone(&self) -> Self { + *self + } +} impl Eq for Id {} impl PartialEq for Id { - fn eq(&self, other: &Self) -> bool { self.0 == other.0 } + fn eq(&self, other: &Self) -> bool { + self.0 == other.0 + } } impl Ord for Id { - fn cmp(&self, other: &Self) -> Ordering { self.0.cmp(&(other.0)) } + fn cmp(&self, other: &Self) -> Ordering { + self.0.cmp(&(other.0)) + } } impl PartialOrd for Id { - fn partial_cmp(&self, other: &Self) -> Option { Some(self.cmp(other)) } + fn partial_cmp(&self, other: &Self) -> Option { + Some(self.cmp(other)) + } } impl fmt::Debug for Id { fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result { @@ -24,7 +34,9 @@ impl fmt::Debug for Id { } } impl hash::Hash for Id { - fn hash(&self, h: &mut H) { self.0.hash(h); } + fn hash(&self, h: &mut H) { + self.0.hash(h); + } } #[derive(Clone)] @@ -63,9 +75,13 @@ impl Index { impl std::ops::Index> for Index { type Output = T; - fn index(&self, id: Id) -> &Self::Output { &self.items[id.0] } + fn index(&self, id: Id) -> &Self::Output { + &self.items[id.0] + } } impl std::ops::IndexMut> for Index { - fn index_mut(&mut self, id: Id) -> &mut Self::Output { &mut self.items[id.0] } + fn index_mut(&mut self, id: Id) -> &mut Self::Output { + &mut self.items[id.0] + } } diff --git a/vm/src/code.rs b/vm/src/code.rs index 12c5317..44fee0f 100644 --- a/vm/src/code.rs +++ b/vm/src/code.rs @@ -1,9 +1,6 @@ use super::*; -use std::{ - io::Write, - rc::Rc, -}; use im::Vector; +use std::{io::Write, rc::Rc}; #[derive(Clone, Debug)] pub enum Instr { @@ -17,10 +14,10 @@ pub enum Instr { MakeFunc(isize, usize), ApplyFunc, - MakeList(usize), // T * N => [T] - IndexList(usize), // Nth field of list/tuple + MakeList(usize), // T * N => [T] + IndexList(usize), // Nth field of list/tuple SkipListImm(usize), // (N..) fields of list/tuple - SetList(usize), // Set Nth field of list + SetList(usize), // Set Nth field of list LenList, JoinList, SkipList, @@ -43,17 +40,17 @@ pub enum Instr { GetLocal(usize), // Duplicate value in locals position (len - 1 - N) and put on stack NotBool, // Bool -> Bool - NegInt, // Int -> Int + NegInt, // Int -> Int NegReal, // Real -> Real - Display, // ? -> Str + Display, // ? -> Str Codepoint, // Char -> Int AddInt, // Int -> Int -> Int SubInt, // Int -> Int -> Int MulInt, - EqInt, // Int -> Int -> Bool + EqInt, // Int -> Int -> Bool EqBool, // Bool -> Bool -> Bool EqChar, // Char -> Char -> Bool LessInt, @@ -86,9 +83,15 @@ impl Instr { pub struct Addr(pub usize); impl Addr { - pub fn incr(self) -> Self { Self(self.0 + 1) } - pub fn jump(self, rel: isize) -> Self { Self((self.0 as isize + rel) as usize) } - pub fn jump_to(self, other: Self) -> isize { other.0 as isize - self.0 as isize } + pub fn incr(self) -> Self { + Self(self.0 + 1) + } + pub fn jump(self, rel: isize) -> Self { + Self((self.0 as isize + rel) as usize) + } + pub fn jump_to(self, other: Self) -> isize { + other.0 as isize - self.0 as isize + } } #[derive(Default, Debug)] @@ -104,7 +107,9 @@ impl Program { self.debug.push((self.next_addr(), msg.to_string())); } - pub fn next_addr(&self) -> Addr { Addr(self.instrs.len()) } + pub fn next_addr(&self) -> Addr { + Addr(self.instrs.len()) + } pub fn instr(&self, ip: Addr) -> Instr { self.instrs @@ -188,61 +193,70 @@ impl Program { let instr_display = match instr { Instr::Error(msg) => format!("error \"{}\"", msg), - Instr::Nop => format!("nop"), - Instr::Break => format!("break"), + Instr::Nop => "nop".to_string(), + Instr::Break => "break".to_string(), Instr::Imm(x) => format!("imm `{}`", x), Instr::Pop(n) => format!("pop {}", n), - Instr::Replace => format!("replace"), - Instr::Swap => format!("swap"), + Instr::Replace => "replace".to_string(), + Instr::Swap => "swap".to_string(), Instr::Call(x) => format!("call {:+} (0x{:03X})", x, addr.jump(x).0), - Instr::Ret => format!("ret"), - Instr::MakeFunc(i, n) => format!("func.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n), - Instr::ApplyFunc => format!("func.apply"), + Instr::Ret => "ret".to_string(), + Instr::MakeFunc(i, n) => { + format!("func.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n) + } + Instr::ApplyFunc => "func.apply".to_string(), Instr::MakeList(n) => format!("list.make {}", n), Instr::IndexList(i) => format!("list.index #{}", i), Instr::SkipListImm(i) => format!("list.skip_imm #{}", i), Instr::SetList(idx) => format!("list.set #{}", idx), - Instr::LenList => format!("list.len"), - Instr::JoinList => format!("list.join"), - Instr::SkipList => format!("list.skip"), - Instr::TrimList => format!("list.trim"), + Instr::LenList => "list.len".to_string(), + Instr::JoinList => "list.join".to_string(), + Instr::SkipList => "list.skip".to_string(), + Instr::TrimList => "list.trim".to_string(), Instr::MakeSum(i) => format!("sum.make #{}", i), Instr::IndexSum(i) => format!("sum.index #{}", i), - Instr::VariantSum => format!("sum.variant"), - Instr::Dup => format!("dup"), + Instr::VariantSum => "sum.variant".to_string(), + Instr::Dup => "dup".to_string(), Instr::Jump(x) => format!("jump {:+} (0x{:03X})", x, addr.jump(x).0), - Instr::IfNot => format!("if_not"), - Instr::PushLocal => format!("local.push"), + Instr::IfNot => "if_not".to_string(), + Instr::PushLocal => "local.push".to_string(), Instr::PopLocal(n) => format!("local.pop {}", n), Instr::GetLocal(x) => format!("local.get +{}", x), - Instr::NotBool => format!("bool.not"), - Instr::NegInt => format!("int.neg"), - Instr::NegReal => format!("real.neg"), - Instr::Display => format!("any.display"), - Instr::Codepoint => format!("char.codepoint"), - Instr::AddInt => format!("int.add"), - Instr::SubInt => format!("int.sub"), - Instr::MulInt => format!("int.mul"), - Instr::EqInt => format!("int.eq"), - Instr::EqBool => format!("bool.eq"), - Instr::EqChar => format!("char.eq"), - Instr::LessInt => format!("int.less"), - Instr::MoreInt => format!("int.more"), - Instr::LessEqInt => format!("int.less_eq"), - Instr::MoreEqInt => format!("int.more_eq"), - Instr::AndBool => format!("bool.and"), - Instr::Print => format!("io.print"), - Instr::Input => format!("io.input"), - Instr::Rand => format!("io.rand"), - Instr::MakeEffect(i, n) => format!("eff.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n), - Instr::Propagate => format!("eff.propagate"), + Instr::NotBool => "bool.not".to_string(), + Instr::NegInt => "int.neg".to_string(), + Instr::NegReal => "real.neg".to_string(), + Instr::Display => "any.display".to_string(), + Instr::Codepoint => "char.codepoint".to_string(), + Instr::AddInt => "int.add".to_string(), + Instr::SubInt => "int.sub".to_string(), + Instr::MulInt => "int.mul".to_string(), + Instr::EqInt => "int.eq".to_string(), + Instr::EqBool => "bool.eq".to_string(), + Instr::EqChar => "char.eq".to_string(), + Instr::LessInt => "int.less".to_string(), + Instr::MoreInt => "int.more".to_string(), + Instr::LessEqInt => "int.less_eq".to_string(), + Instr::MoreEqInt => "int.more_eq".to_string(), + Instr::AndBool => "bool.and".to_string(), + Instr::Print => "io.print".to_string(), + Instr::Input => "io.input".to_string(), + Instr::Rand => "io.rand".to_string(), + Instr::MakeEffect(i, n) => { + format!("eff.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n) + } + Instr::Propagate => "eff.propagate".to_string(), Instr::Suspend(eff) => format!("eff.suspend {:?}", eff), Instr::Register(eff) => format!("eff.register {:?}", eff), Instr::Resume(eff) => format!("eff.resume {:?}", eff), Instr::EndHandlers(n) => format!("eff.end_handlers {}", n), }; - writeln!(writer, "0x{:03X} | {:>+3} | {}", addr.0, stack_diff, instr_display).unwrap(); + writeln!( + writer, + "0x{:03X} | {:>+3} | {}", + addr.0, stack_diff, instr_display + ) + .unwrap(); } writeln!(writer, "{} instructions in total.", self.instrs.len()).unwrap(); diff --git a/vm/src/exec.rs b/vm/src/exec.rs index 38251fd..0a40588 100644 --- a/vm/src/exec.rs +++ b/vm/src/exec.rs @@ -1,9 +1,6 @@ use super::*; -use std::{ - fmt, - rc::Rc, -}; -use im::{Vector, vector}; +use im::{vector, Vector}; +use std::{fmt, rc::Rc}; #[derive(Clone, Debug)] pub struct Effect { @@ -28,15 +25,69 @@ impl Value { Value::Sum(x as usize, Rc::new(Value::List(Vector::new()))) } - pub fn int(self) -> i64 { if let Value::Int(x) = self { x } else { panic!("{}", self) } } - pub fn real(self) -> f64 { if let Value::Real(x) = self { x } else { panic!("{}", self) } } - pub fn char(self) -> char { if let Value::Char(c) = self { c } else { panic!("{}", self) } } - pub fn bool(self) -> bool { if let Value::Sum(x, _) = self { x > 0 } else { panic!("{}", self) } } - pub fn list(self) -> Vector { if let Value::List(xs) = self { xs } else { panic!("{}", self) } } - pub fn func(self) -> (Addr, Vector) { if let Value::Func(f_addr, captures) = self { (f_addr, captures) } else { panic!("{}", self) } } - pub fn sum(self) -> (usize, Rc) { if let Value::Sum(variant, inner) = self { (variant, inner) } else { panic!("{}", self) } } - pub fn universe(self) -> u64 { if let Value::Universe(x) = self { x } else { panic!("{}", self) } } - pub fn eff(self) -> Rc { if let Value::Effect(eff) = self { eff } else { panic!("{}", self) } } + pub fn int(self) -> i64 { + if let Value::Int(x) = self { + x + } else { + panic!("{}", self) + } + } + pub fn real(self) -> f64 { + if let Value::Real(x) = self { + x + } else { + panic!("{}", self) + } + } + pub fn char(self) -> char { + if let Value::Char(c) = self { + c + } else { + panic!("{}", self) + } + } + pub fn bool(self) -> bool { + if let Value::Sum(x, _) = self { + x > 0 + } else { + panic!("{}", self) + } + } + pub fn list(self) -> Vector { + if let Value::List(xs) = self { + xs + } else { + panic!("{}", self) + } + } + pub fn func(self) -> (Addr, Vector) { + if let Value::Func(f_addr, captures) = self { + (f_addr, captures) + } else { + panic!("{}", self) + } + } + pub fn sum(self) -> (usize, Rc) { + if let Value::Sum(variant, inner) = self { + (variant, inner) + } else { + panic!("{}", self) + } + } + pub fn universe(self) -> u64 { + if let Value::Universe(x) = self { + x + } else { + panic!("{}", self) + } + } + pub fn eff(self) -> Rc { + if let Value::Effect(eff) = self { + eff + } else { + panic!("{}", self) + } + } pub fn display(self) -> String { match self { @@ -55,14 +106,16 @@ impl fmt::Display for Value { Value::Real(x) => write!(f, "{}f", x), Value::Char(c) => write!(f, "{}", c), Value::List(items) => match items.iter().next() { - Some(Value::Char(_)) => items - .iter() - .try_for_each(|c| write!(f, "{}", c)), - _ => write!(f, "[{}]", items - .iter() - .map(|x| format!("{}", x)) - .collect::>() - .join(", ")), + Some(Value::Char(_)) => items.iter().try_for_each(|c| write!(f, "{}", c)), + _ => write!( + f, + "[{}]", + items + .iter() + .map(|x| format!("{}", x)) + .collect::>() + .join(", ") + ), }, Value::Func(addr, captures) => write!( f, @@ -95,7 +148,6 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { }; let mut handlers: Vector<(_, Value, usize)> = Vector::new(); - let mut tick = 0u64; loop { let mut next_addr = addr.incr(); @@ -103,213 +155,228 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { match prog.instr(addr) { Instr::Error(err) => panic!("Error: {}", err), - Instr::Nop => {}, + Instr::Nop => {} Instr::Break => { println!("Breakpoint at 0x{:03X?}", addr.0); for (i, x) in stack.iter().rev().enumerate() { println!("{:02} | {:?}", i, x); } - }, + } Instr::Imm(x) => stack.push(x.clone()), Instr::Pop(n) => { assert!(n > 0, "Popped zero items, this is probably a bug"); stack.truncate(stack.len().saturating_sub(n)); - }, + } Instr::Replace => { let x = stack.pop().unwrap(); stack.pop(); stack.push(x); - }, + } Instr::Swap => { let x = stack.pop().unwrap(); let y = stack.pop().unwrap(); stack.push(x); stack.push(y); - }, + } Instr::Call(n) => { funcs.push(next_addr); next_addr = addr.jump(n); - }, - Instr::Ret => if let Some(addr) = funcs.pop() { - next_addr = addr; - } else { - assert_eq!(locals.len(), 0, "Local stack still has values, this is probably a bug"); - assert_eq!(stack.len(), 1, "Stack size must be 1 on program exit"); - // println!("Executed {} instructions.", tick); - break if prog.does_io { - let mut r = stack.pop().unwrap().list(); - assert_eq!(r.remove(0).universe(), universe_counter); - None + } + Instr::Ret => { + if let Some(addr) = funcs.pop() { + next_addr = addr; } else { - stack.pop() - }; - }, + assert_eq!( + locals.len(), + 0, + "Local stack still has values, this is probably a bug" + ); + assert_eq!(stack.len(), 1, "Stack size must be 1 on program exit"); + // println!("Executed {} instructions.", tick); + break if prog.does_io { + let mut r = stack.pop().unwrap().list(); + assert_eq!(r.remove(0).universe(), universe_counter); + None + } else { + stack.pop() + }; + } + } Instr::MakeFunc(i, n) => { let f_addr = addr.jump(i); - let func = Value::Func(f_addr, stack.split_off(stack.len().saturating_sub(n)).into()); + let func = Value::Func( + f_addr, + stack.split_off(stack.len().saturating_sub(n)).into(), + ); stack.push(func); - }, + } Instr::ApplyFunc => { - let (f_addr, mut captures) = stack.pop().unwrap().func(); + let (f_addr, captures) = stack.pop().unwrap().func(); funcs.push(next_addr); next_addr = f_addr; locals.extend(captures.into_iter()); - }, + } Instr::MakeList(n) => { let val = Value::List(stack.split_off(stack.len().saturating_sub(n)).into()); stack.push(val); - }, + } Instr::IndexList(i) => { let mut x = stack.pop().unwrap().list(); if x.len() < i + 1 { panic!("Removing item {} from list {:?} at 0x{:X}", i, x, addr.0); } stack.push(x.remove(i)); - }, + } Instr::SkipListImm(i) => { let x = stack.pop().unwrap().list(); stack.push(Value::List(x.skip(i))); - }, + } Instr::SetList(idx) => { let item = stack.pop().unwrap(); let mut xs = stack.pop().unwrap().list(); xs[idx] = item; stack.push(Value::List(xs)); - }, + } Instr::LenList => { let len = stack.pop().unwrap().list().len(); stack.push(Value::Int(len as i64)); - }, + } Instr::JoinList => { - let mut y = stack.pop().unwrap().list(); + let y = stack.pop().unwrap().list(); let mut x = stack.pop().unwrap().list(); x.append(y); stack.push(Value::List(x)); - }, + } Instr::SkipList => { let i = stack.pop().unwrap().int(); let xs = stack.pop().unwrap().list(); stack.push(Value::List(xs.skip((i as usize).min(xs.len())))); - }, + } Instr::TrimList => { let i = stack.pop().unwrap().int(); let mut xs = stack.pop().unwrap().list(); xs.truncate((i as usize).min(xs.len())); stack.push(Value::List(xs)); - }, + } Instr::MakeSum(variant) => { let x = stack.pop().unwrap(); stack.push(Value::Sum(variant, Rc::new(x))); - }, + } Instr::IndexSum(variant) => { let (v, inner) = stack.pop().unwrap().sum(); debug_assert_eq!(variant, v); stack.push((*inner).clone()); - }, + } Instr::VariantSum => { let (variant, _) = stack.pop().unwrap().sum(); stack.push(Value::Int(variant as i64)); - }, + } Instr::Dup => stack.push(stack.last().unwrap().clone()), Instr::Jump(n) => { next_addr = addr.jump(n); - }, + } Instr::IfNot => { if stack.pop().unwrap().bool() { next_addr = next_addr.jump(1); } - }, + } Instr::PushLocal => locals.push(stack.pop().unwrap()), Instr::PopLocal(n) => locals.truncate(locals.len() - n), Instr::GetLocal(x) => stack.push(locals[locals.len() - 1 - x].clone()), Instr::NotBool => { let x = stack.pop().unwrap().bool(); stack.push(Value::new_bool(!x)) - }, + } Instr::NegInt => { let x = stack.pop().unwrap().int(); stack.push(Value::Int(-x)) - }, + } Instr::NegReal => { let x = stack.pop().unwrap().real(); stack.push(Value::Real(-x)) - }, + } Instr::Display => { let s = stack.pop().unwrap().display(); stack.push(Value::List(s.chars().map(Value::Char).collect())) - }, + } Instr::Codepoint => { let c = stack.pop().unwrap().char(); stack.push(Value::Int(c as u64 as i64)) - }, + } Instr::AddInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::Int(x + y)) - }, + } Instr::SubInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::Int(x - y)) - }, + } Instr::MulInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::Int(x * y)) - }, + } Instr::EqInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::new_bool(x == y)) - }, + } Instr::EqBool => { let y = stack.pop().unwrap().bool(); let x = stack.pop().unwrap().bool(); stack.push(Value::new_bool(x == y)) - }, + } Instr::EqChar => { let y = stack.pop().unwrap().char(); let x = stack.pop().unwrap().char(); stack.push(Value::new_bool(x == y)) - }, + } Instr::LessInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::new_bool(x < y)) - }, + } Instr::MoreInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::new_bool(x > y)) - }, + } Instr::LessEqInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::new_bool(x <= y)) - }, + } Instr::MoreEqInt => { let y = stack.pop().unwrap().int(); let x = stack.pop().unwrap().int(); stack.push(Value::new_bool(x >= y)) - }, + } Instr::AndBool => { let y = stack.pop().unwrap().bool(); let x = stack.pop().unwrap().bool(); stack.push(Value::new_bool(x && y)) - }, + } Instr::Print => { let s = stack.pop().unwrap().list(); let universe = stack.pop().unwrap().universe(); - assert!(universe == universe_counter, "Universe forked, the thread of prophecy has been broken"); + assert!( + universe == universe_counter, + "Universe forked, the thread of prophecy has been broken" + ); universe_counter += 1; env.print(s.into_iter().map(|c| c.char()).collect::()); stack.push(Value::Universe(universe_counter)) - }, + } Instr::Input => { let universe = stack.pop().unwrap().universe(); - assert!(universe == universe_counter, "Universe forked, the thread of prophecy has been broken"); + assert!( + universe == universe_counter, + "Universe forked, the thread of prophecy has been broken" + ); universe_counter += 1; let s = env.input(); @@ -318,11 +385,14 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { Value::Universe(universe_counter), Value::List(s.trim_end().chars().map(Value::Char).collect()), ])); - }, + } Instr::Rand => { let max = stack.pop().unwrap().int(); let universe = stack.pop().unwrap().universe(); - assert!(universe == universe_counter, "Universe forked, the thread of prophecy has been broken"); + assert!( + universe == universe_counter, + "Universe forked, the thread of prophecy has been broken" + ); universe_counter += 1; let n = env.rand(max); @@ -331,7 +401,7 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { Value::Universe(universe_counter), Value::Int(n), ])); - }, + } Instr::MakeEffect(i, n) => { let addr = addr.jump(i); let func = Value::Effect(Rc::new(Effect { @@ -339,7 +409,7 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { captures: stack.split_off(stack.len().saturating_sub(n)).into(), })); stack.push(func); - }, + } Instr::Propagate => { let eff = stack.pop().unwrap().eff(); @@ -347,36 +417,37 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { next_addr = eff.addr; locals.extend(eff.captures.iter().cloned()); - }, + } Instr::Suspend(eff_id) => { let handler = handlers .iter() .rev() .find(|(e, _, _)| *e == eff_id) - .unwrap_or_else(|| panic!( - "No such effect handler for {:?} on effect stack. Effect stack:\n{:#?}", - eff_id, - handlers, - )); - let (f_addr, mut captures) = handler.1.clone().func(); + .unwrap_or_else(|| { + panic!( + "No such effect handler for {:?} on effect stack. Effect stack:\n{:#?}", + eff_id, handlers, + ) + }); + let (f_addr, captures) = handler.1.clone().func(); funcs.push(next_addr); next_addr = f_addr; locals.push(stack[handler.2].clone()); // Push effect locals.extend(captures.into_iter()); - }, + } Instr::Register(eff_id) => { let handler = stack.pop().unwrap(); // let state = stack.pop().unwrap(); handlers.push_back((eff_id, handler, stack.len() - 1)); - }, + } Instr::EndHandlers(n) => { let out = stack.pop().unwrap(); let state = stack.pop().unwrap(); handlers.truncate(handlers.len() - n); stack.push(Value::List([out, state].into_iter().collect())); - }, + } Instr::Resume(eff_id) => { let out_and_state = stack.pop().unwrap().list(); let out = out_and_state[0].clone(); @@ -387,15 +458,14 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { .iter_mut() .rev() .find(|(e, _, _)| *e == eff_id) - .unwrap().2; + .unwrap() + .2; stack[stack_idx] = state; stack.push(out); - }, + } } - tick += 1; - addr = next_addr; } } diff --git a/vm/src/lib.rs b/vm/src/lib.rs index fb30374..8582644 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -3,16 +3,8 @@ pub mod exec; pub mod lower; pub use crate::{ - code::{Instr, Program, Addr}, - exec::{exec, Value, Env}, + code::{Addr, Instr, Program}, + exec::{exec, Env, Value}, }; -use tao_middle::{ - mir, - Context as MirContext, - MirNode, - ProcId, - repr, - Ident, - EffectId, -}; -use hashbrown::HashMap; + +use tao_middle::{mir, repr, Context as MirContext, EffectId, MirNode, ProcId}; diff --git a/vm/src/lower.rs b/vm/src/lower.rs index c809b79..5d32316 100644 --- a/vm/src/lower.rs +++ b/vm/src/lower.rs @@ -1,8 +1,5 @@ use super::*; -use std::{ - collections::BTreeMap, - rc::Rc, -}; +use std::{collections::BTreeMap, rc::Rc}; fn litr_to_value(literal: &mir::Literal) -> Option { Some(match literal { @@ -12,14 +9,12 @@ fn litr_to_value(literal: &mir::Literal) -> Option { mir::Literal::Int(x) => Value::Int(*x), mir::Literal::Real(x) => Value::Real(*x), mir::Literal::Char(c) => Value::Char(*c), - mir::Literal::Tuple(fields) => Value::List(fields - .iter() - .map(litr_to_value) - .collect::>()?), - mir::Literal::List(items) => Value::List(items - .iter() - .map(litr_to_value) - .collect::>()?), + mir::Literal::Tuple(fields) => { + Value::List(fields.iter().map(litr_to_value).collect::>()?) + } + mir::Literal::List(items) => { + Value::List(items.iter().map(litr_to_value).collect::>()?) + } mir::Literal::Sum(variant, inner) => Value::Sum(*variant, Rc::new(litr_to_value(inner)?)), mir::Literal::Data(_, inner) => litr_to_value(inner)?, }) @@ -27,11 +22,11 @@ fn litr_to_value(literal: &mir::Literal) -> Option { impl Program { // [.., T] => [..] - pub fn compile_extractor(&mut self, mir: &MirContext, binding: &MirNode) { + pub fn compile_extractor(&mut self, binding: &MirNode) { // The total number of locals this pattern produces let mut binds = binding.bindings().len(); - if let Some(_) = binding.name { + if binding.name.is_some() { if binds == 1 { self.push(Instr::PushLocal); return; @@ -49,30 +44,30 @@ impl Program { } match &binding.pat { - mir::Pat::Wildcard => {}, - mir::Pat::Literal(_) => {}, + mir::Pat::Wildcard => {} + mir::Pat::Literal(_) => {} mir::Pat::Single(inner) => { self.push(Instr::Dup); - self.compile_extractor(mir, inner); - }, + self.compile_extractor(inner); + } mir::Pat::Add(lhs, rhs) => { self.push(Instr::Dup); self.push(Instr::Imm(Value::Int(*rhs as i64))); self.push(Instr::SubInt); - self.compile_extractor(mir, lhs); - }, + self.compile_extractor(lhs); + } mir::Pat::Tuple(items) | mir::Pat::ListExact(items) => { for (i, item) in items.iter().enumerate() { if item.binds() { self.push(Instr::Dup); self.push(Instr::IndexList(i)); - self.compile_extractor(mir, item); + self.compile_extractor(item); } } - }, + } mir::Pat::ListFront(items, tail) => { - if let Some(tail) = tail.as_ref() { + if let Some(_tail) = tail.as_ref() { self.push(Instr::Dup); // Used for tail later } @@ -81,31 +76,36 @@ impl Program { self.push(Instr::Dup); self.push(Instr::IndexList(i)); - self.compile_extractor(mir, item); + self.compile_extractor(item); } } if let Some(tail) = tail.as_ref() { self.push(Instr::SkipListImm(items.len())); - self.compile_extractor(mir, tail); + self.compile_extractor(tail); } - }, + } mir::Pat::Variant(variant, inner) => { self.push(Instr::Dup); self.push(Instr::IndexSum(*variant)); - self.compile_extractor(mir, inner); - }, + self.compile_extractor(inner); + } mir::Pat::Data(_, inner) => { self.push(Instr::Dup); - self.compile_extractor(mir, inner); - }, + self.compile_extractor(inner); + } } self.push(Instr::Pop(1)); } // [.., [T]] -> [.., Bool] - pub fn compile_item_matcher<'a>(&mut self, items: impl IntoIterator>, is_list: bool, fail_fixup: impl IntoIterator) { + pub fn compile_item_matcher<'a>( + &mut self, + items: impl IntoIterator>, + is_list: bool, + fail_fixup: impl IntoIterator, + ) { let mut fixups = fail_fixup.into_iter().collect::>(); for (i, item) in items.into_iter().enumerate() { @@ -152,7 +152,7 @@ impl Program { repr::Repr::Prim(repr::Prim::Char) => self.push(Instr::EqChar), r => todo!("repr = {:?}, litr = {:?}", r, litr), }; - }, + } mir::Pat::Single(inner) => self.compile_matcher(inner), mir::Pat::Add(lhs, rhs) => { self.push(Instr::Dup); @@ -161,24 +161,26 @@ impl Program { self.push(Instr::IfNot); let fail_fixup = self.push(Instr::Jump(0)); // Fixed by #2 self.compile_item_matcher(Some(lhs), false, Some(fail_fixup)); - }, + } mir::Pat::Tuple(items) => { self.compile_item_matcher(items, true, None); - }, - mir::Pat::ListExact(items) => if items.len() == 0 { - self.push(Instr::LenList); - self.push(Instr::Imm(Value::Int(items.len() as i64))); - self.push(Instr::EqInt); - } else { - self.push(Instr::Dup); - self.push(Instr::LenList); - self.push(Instr::Imm(Value::Int(items.len() as i64))); - self.push(Instr::EqInt); - self.push(Instr::IfNot); - let fail_fixup = Some(self.push(Instr::Jump(0))); // Fixed by #2 + } + mir::Pat::ListExact(items) => { + if items.is_empty() { + self.push(Instr::LenList); + self.push(Instr::Imm(Value::Int(items.len() as i64))); + self.push(Instr::EqInt); + } else { + self.push(Instr::Dup); + self.push(Instr::LenList); + self.push(Instr::Imm(Value::Int(items.len() as i64))); + self.push(Instr::EqInt); + self.push(Instr::IfNot); + let fail_fixup = Some(self.push(Instr::Jump(0))); // Fixed by #2 - self.compile_item_matcher(items, true, fail_fixup); - }, + self.compile_item_matcher(items, true, fail_fixup); + } + } mir::Pat::ListFront(items, tail) => { self.push(Instr::Dup); self.push(Instr::LenList); @@ -196,7 +198,7 @@ impl Program { } self.compile_item_matcher(items, true, fail_fixup); - }, + } mir::Pat::Variant(variant, inner) => { self.push(Instr::Dup); self.push(Instr::VariantSum); @@ -206,7 +208,7 @@ impl Program { let fail_fixup = self.push(Instr::Jump(0)); // Fixed by #2 self.push(Instr::IndexSum(*variant)); self.compile_item_matcher(Some(inner), false, Some(fail_fixup)); - }, + } mir::Pat::Data(_, inner) => self.compile_matcher(inner), } } @@ -236,7 +238,7 @@ impl Program { f_stack.append(&mut captures.clone()); // A function with an undefined body doesn't need to be compiled! - if !matches!(&*body, mir::Expr::Undefined) { + if !matches!(body, mir::Expr::Undefined) { self.compile_expr(mir, body, &mut f_stack, proc_fixups); self.push(Instr::PopLocal(args.len() + captures.len())); // +1 is for the argument self.push(Instr::Ret); @@ -268,83 +270,136 @@ impl Program { stack: &mut Vec, proc_fixups: &mut Vec<(ProcId, Addr)>, ) { - match &*expr { - mir::Expr::Undefined => {}, // Do the minimum possible work, execution is undefined anyway + match expr { + mir::Expr::Undefined => {} // Do the minimum possible work, execution is undefined anyway mir::Expr::Literal(literal) => { if let Some(val) = litr_to_value(literal) { self.push(Instr::Imm(val)); } - }, + } mir::Expr::Local(local) => { let idx = stack .iter() .rev() .enumerate() .find(|(_, name)| *name == local) - .unwrap_or_else(|| panic!("Tried to find local ${}, but it was not found. Stack: {:?}", local.0, stack)) + .unwrap_or_else(|| { + panic!( + "Tried to find local ${}, but it was not found. Stack: {:?}", + local.0, stack + ) + }) .0; self.push(Instr::GetLocal(idx)); - }, - mir::Expr::Global(global, _) => { proc_fixups.push((*global, self.push(Instr::Call(0)))); }, // Fixed by #4 + } + mir::Expr::Global(global, _) => { + proc_fixups.push((*global, self.push(Instr::Call(0)))); + } // Fixed by #4 mir::Expr::Intrinsic(intrinsic, args) => { for arg in args { self.compile_expr(mir, arg, stack, proc_fixups); } use mir::Intrinsic; match intrinsic { - Intrinsic::Debug => { self.push(Instr::Break); }, - Intrinsic::MakeList(_) => { self.push(Instr::MakeList(args.len())); }, - Intrinsic::NegNat | Intrinsic::NegInt => { self.push(Instr::NegInt); }, - Intrinsic::NegReal => { self.push(Instr::NegReal); }, - Intrinsic::DisplayInt => { self.push(Instr::Display); }, - Intrinsic::CodepointChar => { self.push(Instr::Codepoint); }, - Intrinsic::AddNat | Intrinsic::AddInt => { self.push(Instr::AddInt); }, - Intrinsic::SubNat | Intrinsic::SubInt => { self.push(Instr::SubInt); }, - Intrinsic::MulNat | Intrinsic::MulInt => { self.push(Instr::MulInt); }, - Intrinsic::EqNat | Intrinsic::EqInt => { self.push(Instr::EqInt); }, - Intrinsic::EqChar => { self.push(Instr::EqChar); }, + Intrinsic::Debug => { + self.push(Instr::Break); + } + Intrinsic::MakeList(_) => { + self.push(Instr::MakeList(args.len())); + } + Intrinsic::NegNat | Intrinsic::NegInt => { + self.push(Instr::NegInt); + } + Intrinsic::NegReal => { + self.push(Instr::NegReal); + } + Intrinsic::DisplayInt => { + self.push(Instr::Display); + } + Intrinsic::CodepointChar => { + self.push(Instr::Codepoint); + } + Intrinsic::AddNat | Intrinsic::AddInt => { + self.push(Instr::AddInt); + } + Intrinsic::SubNat | Intrinsic::SubInt => { + self.push(Instr::SubInt); + } + Intrinsic::MulNat | Intrinsic::MulInt => { + self.push(Instr::MulInt); + } + Intrinsic::EqNat | Intrinsic::EqInt => { + self.push(Instr::EqInt); + } + Intrinsic::EqChar => { + self.push(Instr::EqChar); + } Intrinsic::NotEqNat | Intrinsic::NotEqInt => { self.push(Instr::EqInt); self.push(Instr::NotBool); - }, + } Intrinsic::NotEqChar => { self.push(Instr::EqChar); self.push(Instr::NotBool); - }, - Intrinsic::LessNat | Intrinsic::LessInt => { self.push(Instr::LessInt); }, - Intrinsic::MoreNat | Intrinsic::MoreInt => { self.push(Instr::MoreInt); }, - Intrinsic::LessEqNat | Intrinsic::LessEqInt => { self.push(Instr::LessEqInt); }, - Intrinsic::MoreEqNat | Intrinsic::MoreEqInt => { self.push(Instr::MoreEqInt); }, - Intrinsic::Join(_) => { self.push(Instr::JoinList); }, - Intrinsic::Print => { self.push(Instr::Print); }, - Intrinsic::Input => { self.push(Instr::Input); }, - Intrinsic::Rand => { self.push(Instr::Rand); }, - Intrinsic::UpdateField(idx) => { self.push(Instr::SetList(*idx)); }, - Intrinsic::LenList => { self.push(Instr::LenList); }, - Intrinsic::SkipList => { self.push(Instr::SkipList); }, - Intrinsic::TrimList => { self.push(Instr::TrimList); }, + } + Intrinsic::LessNat | Intrinsic::LessInt => { + self.push(Instr::LessInt); + } + Intrinsic::MoreNat | Intrinsic::MoreInt => { + self.push(Instr::MoreInt); + } + Intrinsic::LessEqNat | Intrinsic::LessEqInt => { + self.push(Instr::LessEqInt); + } + Intrinsic::MoreEqNat | Intrinsic::MoreEqInt => { + self.push(Instr::MoreEqInt); + } + Intrinsic::Join(_) => { + self.push(Instr::JoinList); + } + Intrinsic::Print => { + self.push(Instr::Print); + } + Intrinsic::Input => { + self.push(Instr::Input); + } + Intrinsic::Rand => { + self.push(Instr::Rand); + } + Intrinsic::UpdateField(idx) => { + self.push(Instr::SetList(*idx)); + } + Intrinsic::LenList => { + self.push(Instr::LenList); + } + Intrinsic::SkipList => { + self.push(Instr::SkipList); + } + Intrinsic::TrimList => { + self.push(Instr::TrimList); + } Intrinsic::Suspend(eff) => { self.push(Instr::PushLocal); self.push(Instr::Suspend(*eff)); self.push(Instr::Resume(*eff)); - }, - Intrinsic::Propagate(effs) => { + } + Intrinsic::Propagate(_effs) => { self.push(Instr::Propagate); - }, + } }; - }, + } mir::Expr::Tuple(fields) => { for field in fields { self.compile_expr(mir, field, stack, proc_fixups); } self.push(Instr::MakeList(fields.len())); - }, + } mir::Expr::List(items) => { for item in items { self.compile_expr(mir, item, stack, proc_fixups); } self.push(Instr::MakeList(items.len())); - }, + } mir::Expr::Match(pred, arms) => { self.compile_expr(mir, pred, stack, proc_fixups); @@ -364,7 +419,7 @@ impl Program { fail_jumps.push(self.push(Instr::Jump(0))); } - self.compile_extractor(mir, binding); + self.compile_extractor(binding); let old_stack = stack.len(); let names = binding.binding_names(); @@ -372,7 +427,7 @@ impl Program { self.compile_expr(mir, body, stack, proc_fixups); - if names.len() > 0 { + if !names.is_empty() { self.push(Instr::PopLocal(names.len())); } stack.truncate(old_stack); // End scope @@ -391,12 +446,16 @@ impl Program { for end_arm in end_matches { self.fixup(end_arm, end_match, Instr::Jump); // Fixes #1 } - }, + } mir::Expr::Func(arg, body) => { - let (f_addr, captures_len) = self.compile_body(mir, vec![**arg], body, stack, proc_fixups); + let (f_addr, captures_len) = + self.compile_body(mir, vec![**arg], body, stack, proc_fixups); - self.push(Instr::MakeFunc(self.next_addr().jump_to(f_addr), captures_len)); - }, + self.push(Instr::MakeFunc( + self.next_addr().jump_to(f_addr), + captures_len, + )); + } mir::Expr::Go(arg, body, init) => { self.compile_expr(mir, init, stack, proc_fixups); @@ -425,45 +484,58 @@ impl Program { self.fixup(done, self.next_addr(), Instr::Jump); // Fixes #6 self.push(Instr::IndexSum(DONE_VARIANT)); self.push(Instr::Replace); - }, + } mir::Expr::Apply(f, arg) => { self.compile_expr(mir, f, stack, proc_fixups); self.compile_expr(mir, arg, stack, proc_fixups); self.push(Instr::PushLocal); self.push(Instr::ApplyFunc); - }, + } mir::Expr::Variant(variant, inner) => { self.compile_expr(mir, inner, stack, proc_fixups); self.push(Instr::MakeSum(*variant)); - }, + } mir::Expr::Access(record, field) => { self.compile_expr(mir, record, stack, proc_fixups); self.push(Instr::IndexList(*field)); - }, + } mir::Expr::AccessVariant(inner, variant) => { self.compile_expr(mir, inner, stack, proc_fixups); self.push(Instr::IndexSum(*variant)); - }, + } mir::Expr::Data(_, inner) => { self.compile_expr(mir, inner, stack, proc_fixups); - }, + } mir::Expr::AccessData(inner, _) => { self.compile_expr(mir, inner, stack, proc_fixups); - }, - mir::Expr::Basin(eff, inner) => { - let (f_addr, captures_len) = self.compile_body(mir, Vec::new(), inner, stack, proc_fixups); - self.push(Instr::MakeEffect(self.next_addr().jump_to(f_addr), captures_len)); - }, + } + mir::Expr::Basin(_eff, inner) => { + let (f_addr, captures_len) = + self.compile_body(mir, Vec::new(), inner, stack, proc_fixups); + self.push(Instr::MakeEffect( + self.next_addr().jump_to(f_addr), + captures_len, + )); + } mir::Expr::Handle { expr, handlers } => { // self.debug("Starting handler..."); // self.debug("Compiling expr..."); self.compile_expr(mir, expr, stack, proc_fixups); - for mir::Handler { eff, send, state, recv } in handlers { - + for mir::Handler { + eff, + send, + state, + recv, + } in handlers + { // self.debug("Compiling body..."); - let (h_addr, captures_len) = self.compile_body(mir, vec![**send, **state], recv, stack, proc_fixups); - self.push(Instr::MakeFunc(self.next_addr().jump_to(h_addr), captures_len)); + let (h_addr, captures_len) = + self.compile_body(mir, vec![**send, **state], recv, stack, proc_fixups); + self.push(Instr::MakeFunc( + self.next_addr().jump_to(h_addr), + captures_len, + )); self.push(Instr::Register(*eff)); } @@ -475,14 +547,25 @@ impl Program { self.push(Instr::Propagate); self.push(Instr::EndHandlers(handlers.len())); - }, + } } } - pub fn compile_proc(&mut self, mir: &MirContext, proc: ProcId, entry_io: bool, proc_fixups: &mut Vec<(ProcId, Addr)>) -> Addr { + pub fn compile_proc( + &mut self, + mir: &MirContext, + proc: ProcId, + entry_io: bool, + proc_fixups: &mut Vec<(ProcId, Addr)>, + ) -> Addr { self.debug(format!("Proc {:?}", proc)); let addr = self.next_addr(); - self.compile_expr(mir, &mir.procs.get(proc).unwrap().body, &mut Vec::new(), proc_fixups); + self.compile_expr( + mir, + &mir.procs.get(proc).unwrap().body, + &mut Vec::new(), + proc_fixups, + ); if entry_io { self.push(Instr::ApplyFunc); } @@ -497,7 +580,7 @@ impl Program { this.does_io = if let repr::Repr::Func(i, o) = mir.procs.get(entry).unwrap().body.meta() { if let (repr::Repr::Prim(repr::Prim::Universe), repr::Repr::Tuple(xs)) = (&**i, &**o) { if let [repr::Repr::Prim(repr::Prim::Universe), repr::Repr::Tuple(xs)] = &xs[..] { - xs.len() == 0 + xs.is_empty() } else { false } @@ -512,7 +595,15 @@ impl Program { let mut proc_fixups = Vec::new(); for proc_id in mir.reachable_procs() { - procs.insert(proc_id, this.compile_proc(mir, proc_id, this.does_io && proc_id == entry, &mut proc_fixups)); + procs.insert( + proc_id, + this.compile_proc( + mir, + proc_id, + this.does_io && proc_id == entry, + &mut proc_fixups, + ), + ); } for (proc_id, addr) in proc_fixups { diff --git a/web_demo/src/lib.rs b/web_demo/src/lib.rs index 8fb24dc..ee3953f 100644 --- a/web_demo/src/lib.rs +++ b/web_demo/src/lib.rs @@ -1,9 +1,9 @@ -use wasm_bindgen::prelude::*; use include_dir::{include_dir, Dir}; use rand::prelude::*; -use tao::{compile, SrcId, Options, OptMode}; -use tao_vm::{Program, Env, exec}; -use std::path::{PathBuf, Component}; +use std::path::{Component, PathBuf}; +use tao::{compile, OptMode, Options, SrcId}; +use tao_vm::{exec, Env}; +use wasm_bindgen::prelude::*; static LIB_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../lib"); @@ -13,7 +13,7 @@ static LIB_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../lib"); static ALLOC: wee_alloc::WeeAlloc = wee_alloc::WeeAlloc::INIT; #[wasm_bindgen] -extern { +extern "C" { fn prompt(s: String) -> String; fn alert(s: String); } @@ -21,19 +21,21 @@ extern { struct WebEnv(rand::rngs::SmallRng); impl Env for WebEnv { - fn input(&mut self) -> String { prompt("Provide input to program".to_string()) } + fn input(&mut self) -> String { + prompt("Provide input to program".to_string()) + } fn print(&mut self, s: String) { let win = web_sys::window().unwrap(); let doc = win.document().unwrap(); let output = doc.get_element_by_id("output").unwrap(); - let mut output_buf = output - .text_content() - .unwrap(); + let mut output_buf = output.text_content().unwrap(); output_buf += &s; output_buf += "\n"; output.set_text_content(Some(&output_buf)); } - fn rand(&mut self, max: i64) -> i64 { self.0.gen_range(0..max) } + fn rand(&mut self, max: i64) -> i64 { + self.0.gen_range(0..max) + } } #[wasm_bindgen] @@ -61,11 +63,11 @@ pub fn run(src: &str, mode: &str, optimisation: &str) { }, }, &mut stderr, - |src_id| std::str::from_utf8(LIB_DIR - .get_file(src_id.to_path())? - .contents()) - .map(|s| s.to_string()) - .ok(), + |src_id| { + std::str::from_utf8(LIB_DIR.get_file(src_id.to_path())?.contents()) + .map(|s| s.to_string()) + .ok() + }, |parent, rel| { let mut path = parent.to_path(); path.pop(); @@ -73,8 +75,10 @@ pub fn run(src: &str, mode: &str, optimisation: &str) { let mut new_path = PathBuf::new(); for c in path.components() { match c { - Component::Prefix(_) | Component::RootDir | Component::CurDir => {}, - Component::ParentDir => { new_path.pop(); }, + Component::Prefix(_) | Component::RootDir | Component::CurDir => {} + Component::ParentDir => { + new_path.pop(); + } Component::Normal(p) => new_path.push(p), } } @@ -92,7 +96,7 @@ pub fn run(src: &str, mode: &str, optimisation: &str) { if debug.is_empty() { if let Some(prog) = prog { - env.print(format!("Compilation succeeded.")); + env.print("Compilation succeeded.".to_string()); exec(&prog, &mut env); } }