From dc578d170b1251ac1f0074c64ab9b0afcddae6d7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:48:03 +0100 Subject: [PATCH 001/106] Add default rustfmt config Signed-off-by: Matthias Beyer --- rustfmt.toml | 1 + 1 file changed, 1 insertion(+) create mode 100644 rustfmt.toml diff --git a/rustfmt.toml b/rustfmt.toml new file mode 100644 index 0000000..36755d2 --- /dev/null +++ b/rustfmt.toml @@ -0,0 +1 @@ +# default From 77d74f6432690c3a0cbc640bece41bfa7ec6aa32 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:47:33 +0100 Subject: [PATCH 002/106] Run cargo-fmt Signed-off-by: Matthias Beyer --- analysis/src/class.rs | 268 ++- analysis/src/concrete.rs | 766 +++++--- analysis/src/context.rs | 718 ++++--- analysis/src/data.rs | 51 +- analysis/src/debug.rs | 26 +- analysis/src/def.rs | 3 +- analysis/src/effect.rs | 26 +- analysis/src/error.rs | 65 +- analysis/src/exhaustivity.rs | 282 ++- analysis/src/hir.rs | 132 +- analysis/src/infer.rs | 2209 ++++++++++++++-------- analysis/src/lib.rs | 42 +- analysis/src/lower.rs | 2063 +++++++++++++------- analysis/src/reify.rs | 129 +- analysis/src/ty.rs | 335 ++-- cir/src/lib.rs | 2 +- compiler/src/error.rs | 25 +- compiler/src/lib.rs | 55 +- compiler/src/main.rs | 11 +- compiler/tests/tester.rs | 79 +- middle/src/context.rs | 2 +- middle/src/error.rs | 38 +- middle/src/lib.rs | 43 +- middle/src/lower.rs | 537 ++++-- middle/src/mir.rs | 513 +++-- middle/src/opt/const_fold.rs | 236 ++- middle/src/opt/mod.rs | 204 +- middle/src/opt/remove_unused_bindings.rs | 112 +- middle/src/proc.rs | 13 +- middle/src/repr.rs | 14 +- syntax/src/ast.rs | 159 +- syntax/src/error.rs | 108 +- syntax/src/lib.rs | 34 +- syntax/src/node.rs | 33 +- syntax/src/parse.rs | 1217 +++++++----- syntax/src/span.rs | 47 +- syntax/src/src.rs | 17 +- syntax/src/token.rs | 90 +- util/src/index.rs | 30 +- vm/src/code.rs | 48 +- vm/src/exec.rs | 255 ++- vm/src/lib.rs | 14 +- vm/src/lower.rs | 283 ++- web_demo/src/lib.rs | 38 +- 44 files changed, 7273 insertions(+), 4099 deletions(-) diff --git a/analysis/src/class.rs b/analysis/src/class.rs index e94d115..7c336ce 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().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); + } } 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); } @@ -189,21 +242,26 @@ impl Classes { 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, gen_eff_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)), (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, 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 .into_iter() - .zip(y.0.1.iter()) + .zip(y.0 .1.iter()) .all(|(x, y)| covers(hir, ctx, x, *y, gen_ty_links, gen_eff_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, gen_eff_links) + } (Ty::Effect(_, _), ConTy::Effect(_, _)) => todo!(), (Ty::Error(_), _) => panic!("Error ty during monomorphisation"), _ => false, @@ -237,62 +295,86 @@ 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, + &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, + ) + }, + ) }) .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.len() == 0 { + 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 +388,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..2a9c114 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -17,7 +17,9 @@ 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)] @@ -29,7 +31,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 +46,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 +81,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,29 +148,38 @@ 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() + .find(|attr| attr.name.as_str() == "entry") + .is_some() + { + 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); @@ -153,7 +188,10 @@ impl ConContext { 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)); @@ -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.into_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 { - // Sum types have no fields + 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 { + // 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::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))); 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( @@ -594,82 +761,118 @@ impl ConContext { 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.into_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, + ) + .ok() + .expect("Generic effect used in suspend?!"), self.lower_expr(hir, inner, ty_insts), ), hir::Expr::Handle { expr, handlers } => { @@ -695,22 +898,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 +929,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 +945,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 +957,7 @@ impl ConContext { self.effects.insert(id, eff); } Ok(id) - }, + } } } @@ -763,7 +983,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 +996,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.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::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..ced74ec 100644 --- a/analysis/src/context.rs +++ b/analysis/src/context.rs @@ -42,23 +42,31 @@ 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)), } @@ -66,12 +74,16 @@ impl Context { // Class associated types 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() { @@ -169,7 +180,7 @@ impl Context { 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| {}, - ); + 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); @@ -369,10 +388,11 @@ impl Context { // 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); @@ -406,11 +436,14 @@ impl Context { 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(); + 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); @@ -424,7 +457,8 @@ impl Context { // Class fields 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,7 +513,7 @@ impl Context { ty: SrcNode::new(checked.reify(ty.meta().1), ty.meta().0), }) } - }, + } _ => None, }) .collect::>(); @@ -475,33 +521,55 @@ impl Context { } // Member associated types for (member, class_id, member_id, member_ty, gen_scope) in &members { - let assoc = member.items + 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); @@ -604,18 +685,27 @@ 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(); + 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 { @@ -654,16 +744,19 @@ impl Context { 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( @@ -711,7 +809,9 @@ impl Context { let mut infer = Infer::new(&mut this, Some(gen_scope)) .with_debug(attr.iter().find(|a| **a.name == "ty_debug").is_some()) .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(), + format!("Type of member item must match class"), + ), + ); + } + + 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,17 +936,27 @@ 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; @@ -836,7 +965,9 @@ impl Context { .with_debug(attr.iter().find(|a| **a.name == "ty_debug").is_some()) .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 { + 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 { - // Sum types have no fields + // 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..a8753f3 100644 --- a/analysis/src/data.rs +++ b/analysis/src/data.rs @@ -94,27 +94,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().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); + } } self.datas.push((name.span(), None, gen_scope, *name)); @@ -125,13 +139,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)) @@ -145,7 +168,11 @@ impl Datas { 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); diff --git a/analysis/src/debug.rs b/analysis/src/debug.rs index 2d5a128..fefdf3e 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().find(|a| &**a.name == "util").is_none() { + Some((id, *def.name)) + } else { + None + } }) .collect() } @@ -51,10 +54,7 @@ impl<'hir, 'a> dot::GraphWalk<'a, Node, Edge> for CallGraph<'hir> { 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), - )); + edges.insert((parent, (global.0, *def.name))); } } @@ -70,6 +70,10 @@ impl<'hir, 'a> dot::GraphWalk<'a, Node, Edge> for CallGraph<'hir> { } 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..11c24f7 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()) diff --git a/analysis/src/effect.rs b/analysis/src/effect.rs index 5baff38..9ff8981 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) @@ -106,7 +118,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..456f873 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 { + format!("!") + } }; - 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) => { @@ -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..48973d4 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::{cmp::Ord, fmt, ops::Range}; #[derive(Debug)] pub enum AbstractPat { @@ -16,7 +12,7 @@ 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), } @@ -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::Literal(hir::Literal::Str(x)) => { + Self::ListExact(x.chars().map(Self::Char).collect()) + } hir::Pat::Single(inner) => Self::from_binding(ctx, 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(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, + ), 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,7 +93,12 @@ 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() } @@ -88,9 +109,9 @@ impl AbstractPat { 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,14 @@ 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 + .clone() + .invert() + .into_iter() + .next() + .map(ExamplePrim::Nat) + .map(ExamplePat::Prim) + } Ty::Prim(Prim::Int) => { let mut covered = Ranges::new(); for pat in filter { @@ -116,28 +143,34 @@ 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 + .clone() + .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) => { for pat in filter { match pat { @@ -146,7 +179,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(); @@ -157,26 +190,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 +232,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 +311,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,39 +322,49 @@ 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(_, _) => { for pat in filter { match pat { @@ -289,7 +373,7 @@ impl AbstractPat { } } Some(ExamplePat::Wildcard) - }, + } ty => todo!("{:?}", ty), } } @@ -330,11 +414,49 @@ 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::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,7 +466,11 @@ 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)) diff --git a/analysis/src/hir.rs b/analysis/src/hir.rs index 71c56e9..7c5c62d 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)), + 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), Expr::Match(_, pred, arms) => { f(&pred); - arms - .iter() - .for_each(|(_, arm)| f(arm)); - }, + 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)), + Expr::Intrinsic(_, args) => args.iter().for_each(|arg| f(arg)), Expr::Update(record, fields) => { f(&record); - fields - .iter() - .for_each(|(_, field)| f(field)); - }, + 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)); - }, + 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,34 @@ 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..958be38 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,30 +135,70 @@ 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 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_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 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); } @@ -152,11 +207,15 @@ impl<'a, 'b> FlowInfer<'a> for MakeFlow<'a, 'b> { 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 } } @@ -266,23 +325,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 +382,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() @@ -333,54 +411,71 @@ impl<'a> Infer<'a> { 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 +490,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 +518,7 @@ impl<'a> Infer<'a> { _ => { self.vars[ty.0].1 = info; ty - }, + } } } @@ -442,7 +540,7 @@ impl<'a> Infer<'a> { | 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 +548,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 +563,22 @@ impl<'a> Infer<'a> { fn set_error_class(&mut self, class: ClassVar) { match self.follow_class(class) { ClassInfo::Ref(_) => unreachable!(), - ClassInfo::Unknown => {}, + 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 +594,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 +618,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 +644,55 @@ 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() }, + { + 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)); 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()) @@ -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 { @@ -795,8 +1001,7 @@ impl<'a> Infer<'a> { } fn iter_effects(&self) -> impl Iterator + '_ { - (0..self.effect_vars.len()) - .map(|i| (EffectVar(i), self.effect_vars[i].1.clone())) + (0..self.effect_vars.len()).map(|i| (EffectVar(i), self.effect_vars[i].1.clone())) } fn info_effect(&self, eff: EffectVar) -> EffectInfo { @@ -838,12 +1043,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 +1075,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 +1084,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 +1113,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(); @@ -936,7 +1168,7 @@ impl<'a> Infer<'a> { effs.append(&mut self.collect_eff_insts(opener)) } effs - }, + } } } @@ -948,22 +1180,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) { + pub fn make_flow_effect( + &mut self, + x: (EffectVar, TyVar), + y: (EffectVar, TyVar), + info: impl Into, + ) { let mut 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 +1216,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_ok() { + 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_ok() { + Some(false) + } else { + None + } + } Some(false) => Some(false), } } @@ -997,11 +1254,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 +1268,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 +1282,43 @@ 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, _) => { + 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::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::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 +1328,44 @@ 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)) == Ok(())) + }) { 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 +1377,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,22 +1386,21 @@ 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 + x_effs .iter() .map(|x| Self::flow_effect_inst(infer, (*x, x_ty), (y_effs[0], y_ty))) .collect::>()?; @@ -1141,7 +1416,7 @@ impl<'a> Infer<'a> { } else { Err((x_ty, y_ty)) } - }, + } (x_info, y_info) => todo!("{:?} into {:?}", x_info, y_info), } } @@ -1152,30 +1427,47 @@ 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)) { + 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 => { + (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), @@ -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,24 +1702,30 @@ 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 @@ -1443,105 +1758,167 @@ 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.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) + { 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!(), @@ -1550,7 +1927,11 @@ impl<'a> Infer<'a> { ); 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!(), @@ -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, @@ -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,19 +2211,27 @@ 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), @@ -1800,7 +2239,7 @@ impl<'a> Infer<'a> { (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,41 @@ 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.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 + } + }) + }) { 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,7 +2495,9 @@ 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. @@ -2016,52 +2505,71 @@ impl<'a> Infer<'a> { // program being well-typed, which could cause phantom errors, or maybe this is fine? (_, 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 +2581,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 +2601,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 + .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, 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()) + ), } } @@ -2130,7 +2656,7 @@ 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 => { // If searching through real obligations failed, search through implied obligations @@ -2139,22 +2665,32 @@ impl<'a> Infer<'a> { 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 +2703,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.clone(), class_gen_effs.clone()), + ); // 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 +2737,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 +2804,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 +2826,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(); @@ -2258,18 +2848,49 @@ impl<'a> Infer<'a> { // 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 +2900,71 @@ impl<'a> Infer<'a> { Some(ty), invariant(), ); - let member_gen_tys = member.gen_tys + 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 - .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.clone(), class_gen_effs.clone()), + member.span(), + ))); } else { // println!( // "Trying to prove that {:?} is a member of {}{}{}!", @@ -2337,7 +2977,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 +2995,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 +3010,7 @@ impl<'a> Infer<'a> { vec![], use_span, ); - }, + } } } } @@ -2383,7 +3027,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 +3042,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 +3063,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 +3091,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,7 +3101,10 @@ 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 { @@ -2455,18 +3112,25 @@ impl<'a> Infer<'a> { "{} < {}{} (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 +3148,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 +3174,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 +3211,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)) } - }, + } } } @@ -2585,22 +3269,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 +3300,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 +3341,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 { + &mut self.infer.ctx + } fn reify_inner(&mut self, var: TyVar) -> TyId { if let Some(ty) = self.ty_cache.get(&var) { @@ -2659,15 +3362,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 +3383,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)) @@ -2710,10 +3413,10 @@ impl<'a> Checked<'a> { EffectInstInfo::Error => Err(()), EffectInstInfo::Ref(x) => return 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 +3428,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 +3460,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 +3470,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 +3479,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..38d496b 100644 --- a/analysis/src/lib.rs +++ b/analysis/src/lib.rs @@ -10,41 +10,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, marker::PhantomData}; +use tao_syntax::{ast, Node, Span, SrcId, SrcNode}; diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index a962c44..6f69553 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -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,7 +27,9 @@ pub enum Scope<'a> { } impl<'a> Scope<'a> { - pub fn empty() -> Self { Self::Empty } + pub fn empty() -> Self { + Self::Empty + } fn with(&self, name: SrcNode, ty: TyVar) -> Scope<'_> { Scope::Binding(self, name, ty) @@ -40,21 +48,33 @@ impl<'a> Scope<'a> { } // 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 +94,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 @@ -105,7 +130,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 +144,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 +234,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 +247,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 +319,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 +365,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,7 +394,8 @@ 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(), @@ -313,7 +408,7 @@ impl ToHir for ast::Type { ); infer.ctx_mut().emit(err); TyInfo::Error(ErrorReason::Unknown) - }, + } Ok(()) => TyInfo::Ref(infer.instantiate( alias_ty, self.span(), @@ -324,11 +419,18 @@ impl ToHir for ast::Type { )), } } 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,7 +447,6 @@ 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(), @@ -359,46 +460,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,68 +529,107 @@ 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); // 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); 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(), + format!("Only natural numbers support arithmetic patterns"), + ), + ); + ( + 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)) .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))) .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 @@ -482,7 +641,7 @@ impl ToHir for ast::Binding { }) .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 @@ -500,72 +659,77 @@ impl ToHir for ast::Binding { 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,15 +739,27 @@ 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::>(); @@ -608,7 +784,8 @@ 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); @@ -616,10 +793,9 @@ fn instantiate_def(def_id: DefId, span: Span, infer: &mut Infer, span_override: 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 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 +814,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 +832,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((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)) .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)); @@ -703,7 +900,7 @@ impl ToHir for ast::Expr { .collect(); (TyInfo::Ref(list_ty), hir::Expr::List(items, tails)) - }, + } ast::Expr::Record(fields) => { let fields = fields .iter() @@ -714,67 +911,158 @@ impl ToHir for ast::Expr { .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 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 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 +1073,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 +1099,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,15 +1115,20 @@ 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), } } @@ -829,12 +1136,17 @@ impl ToHir for ast::Expr { 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; } } @@ -851,33 +1163,96 @@ impl ToHir for ast::Expr { .map(|(bindings, body)| { 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(), + format!("Branches must produce compatible values"), + ), + ); (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(), 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::Func(arms) => { // Effects cannot be propagated from function bodies to their environment // let scope = &scope.without_basin(); @@ -891,7 +1266,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 +1293,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); 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(), + format!("Branches must produce compatible values"), + ), + ); (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,272 +1359,455 @@ 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 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(), 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"), + ), + ); (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 fields = fields @@ -1230,8 +1819,11 @@ impl ToHir for ast::Expr { }) .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()); @@ -1241,117 +1833,194 @@ impl ToHir for ast::Expr { 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); (TyInfo::Ref(expr.meta().1), expr.into_inner()) - }, + } ast::Expr::Handle { expr, handlers } => { 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 +2039,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 +2057,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..6289999 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.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) + } // 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!(" !"), })) - .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,11 +404,17 @@ 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::()), + 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!("!"), }) .collect::>(); @@ -345,7 +423,7 @@ impl<'a> fmt::Display for TyDisplay<'a> { } else { write!(f, "{}", effs.join(" + ")) } - }, + } }, } } @@ -405,37 +483,54 @@ 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 len_eff(&self) -> usize { + self.effects.len() + } pub fn get(&self, index: usize) -> &GenTy { &self.types[index] @@ -446,10 +541,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..3dab3a0 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); diff --git a/compiler/src/error.rs b/compiler/src/error.rs index f832449..c89f247 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(), format!("Does not exist"), 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..3764f1b 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, fmt, io::Write, str::FromStr}; +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 { @@ -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 { 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..ff878ae 100644 --- a/middle/src/error.rs +++ b/middle/src/error.rs @@ -10,13 +10,20 @@ pub enum Error { impl Error { pub fn write>(self, ctx: &Context, 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::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))], + 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) + )], ), Error::MultipleEntryPoints(a, b) => ( format!("Multiple entry points"), @@ -30,29 +37,32 @@ impl Error { 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), + ( + entry, + format!("Declared as an entry point because of this attribute"), + Color::Yellow, + ), ], vec![format!("A program cannot be generic over types")], ), }; - 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..8141d3d 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)] +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 tao_analysis::{ - hir, - TyNode, - ty, - DefId, - Context as HirContext, - data::DataId, - ConProc, - ConProcId, - ConContext, - ConExpr, - ConBinding, - ConTy, - ConTyId, - ConDataId, - ConEffectId, -}; use hashbrown::{HashMap, HashSet}; use internment::Intern; use std::collections::{BTreeMap, BTreeSet}; +use tao_analysis::{ + data::DataId, hir, ty, ConBinding, ConContext, ConDataId, ConEffectId, ConExpr, ConProc, + ConProcId, ConTy, ConTyId, Context as HirContext, DefId, TyNode, +}; +use tao_syntax::{ast, Node, Span, SrcId, SrcNode}; pub type EffectId = ConEffectId; diff --git a/middle/src/lower.rs b/middle/src/lower.rs index c51190f..7e98afc 100644 --- a/middle/src/lower.rs +++ b/middle/src/lower.rs @@ -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,8 +130,14 @@ 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() @@ -110,7 +145,7 @@ impl Context { .collect::>(); fields.sort_by_key(|(name, _)| name.as_ref()); mir::Pat::Tuple(fields.into_iter().map(|(_, field)| field).collect()) - }, + } pat => todo!("{:?}", pat), }; @@ -128,17 +163,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 +196,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 +212,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(); 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 +245,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 + .iter() + .enumerate() + .find(|(_, name)| **name == **field) + .unwrap() + .0 } else { unreachable!(); }; @@ -222,7 +283,7 @@ impl Context { } mir::Expr::Access(record, field_idx) - }, + } hir::Expr::Record(fields, _) => { let mut fields = fields .iter() @@ -230,110 +291,192 @@ impl Context { .collect::>(); fields.sort_by_key(|(name, _)| name.as_ref()); 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 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 + .iter() + .enumerate() + .find(|(_, name)| **name == **field_name) + .unwrap() + .0 } else { unreachable!(); }; @@ -351,14 +494,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 +519,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 +532,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::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 + }, + } + }, + ) .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 +611,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.clone(), + ]), + ), + 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..fc6bf70 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), } @@ -223,11 +250,11 @@ impl Binding { }, 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.len() > 0 || tail.as_ref().map_or(false, |tail| tail.is_refutable()) + } Pat::Variant(_, _) => true, // TODO: Check number of variants Pat::Data(_, inner) => inner.is_refutable(), } @@ -236,22 +263,16 @@ impl Binding { fn visit_bindings(self: &MirNode, mut bind: &mut impl FnMut(Local, &Repr)) { self.name.map(|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)); + items.iter().for_each(|item| item.visit_bindings(bind)); tail.as_ref().map(|tail| tail.visit_bindings(bind)); - }, + } Pat::Variant(_, inner) => inner.visit_bindings(bind), Pat::Data(_, inner) => inner.visit_bindings(bind), } @@ -277,7 +298,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 +319,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 +341,7 @@ pub struct GlobalFlags { impl Default for GlobalFlags { fn default() -> Self { - Self { - can_inline: true, - } + Self { can_inline: true } } } @@ -394,10 +413,14 @@ 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 { @@ -408,14 +431,14 @@ impl Expr { arm.refresh_locals_inner(stack); stack.truncate(old_stack); } - }, + } Expr::Func(arg, body) => { let new_arg = Local::new(); 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); @@ -424,11 +447,17 @@ impl Expr { 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 { + for Handler { + eff, + send, + state, + recv, + } in handlers + { let new_send = Local::new(); let new_state = Local::new(); let old_len = stack.len(); @@ -439,21 +468,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 +496,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 +526,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); } - }, + } } } @@ -522,30 +557,27 @@ impl Expr { 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::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::Handle { expr, handlers } => { + expr.may_have_effect() + || handlers + .iter() + .any(|Handler { recv, .. }| recv.may_have_effect()) + } } } @@ -566,17 +598,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::Data(data, inner) => { + write!(f, "{:?} {}", data, DisplayBinding(inner, self.1)) + } pat => todo!("{:?}", pat), } } @@ -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 { 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..b93373d 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -11,7 +11,13 @@ 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( + &self, + ctx: &Context, + binding: &mut MirNode, + partial: &Partial, + locals: &mut Vec<(Local, Partial)>, + ) -> bool { if let Some(name) = binding.name { locals.push((name, partial.clone())); } @@ -30,59 +36,68 @@ impl ConstFold { } 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::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::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() + 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) - } else { - true - }; - could_match_tail && 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) + } + (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) + } else { + true + }; + could_match_tail + && xs + .iter_mut() + .zip(ys.iter()) + .all(|(x, y)| self.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 { + self.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) - }, + } (p, v) => todo!("Pattern:\n\n{:?}\n\nPartial:\n\n{:?}\n\n", p, v), } } @@ -101,20 +116,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().find(|(name, _)| *name == local).is_some() => + { *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; @@ -126,7 +145,8 @@ impl ConstFold { 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 +159,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 +169,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 +178,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 +202,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 +226,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 +235,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 +248,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 +268,23 @@ impl ConstFold { } Partial::Unknown(None) - }, + } e => todo!("{:?}", e), }; let 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().find(|(l, _)| *l == local).is_some() + }) => + { 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,7 +293,7 @@ impl ConstFold { } } partial - }, + } }; partial @@ -285,15 +317,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)), @@ -307,13 +343,17 @@ impl Intrinsic { 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::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,7 +368,8 @@ 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::>(); @@ -337,7 +378,14 @@ impl Pass for ConstFold { // visit(&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/mod.rs b/middle/src/opt/mod.rs index 9bad8df..0961d39 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(|field| f(field)), + mir::Pat::ListExact(items) => items.iter().for_each(|item| f(item)), mir::Pat::ListFront(items, tail) => { - items - .iter() - .for_each(|item| f(item)); + items.iter().for_each(|item| f(item)); tail.as_ref().map(|tail| f(tail)); - }, + } 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(|field| f(field)), + mir::Pat::ListExact(items) => items.iter_mut().for_each(|item| f(item)), mir::Pat::ListFront(items, tail) => { - items - .iter_mut() - .for_each(|item| f(item)); + items.iter_mut().for_each(|item| f(item)); tail.as_mut().map(|tail| f(tail)); - }, + } 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(|arg| f(arg)), + Expr::Tuple(fields) => fields.iter().for_each(|field| f(field)), + Expr::List(items) => items.iter().for_each(|item| f(item)), 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(|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::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,16 +385,26 @@ 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( + ctx: &Context, + binding: &Binding, + repr: &Repr, + stack: &mut Vec<(Local, 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::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::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)); @@ -410,38 +412,41 @@ pub fn check(ctx: &Context) { 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), _) => { // TODO: Validate return body and return type - }, + } (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) => { for (arm, body) in arms { // TODO: visit binding @@ -451,26 +456,29 @@ pub fn check(ctx: &Context) { 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::Variant(idx, inner), Repr::Data(_)) => {} // TODO + (Expr::Intrinsic(_, _), _) => {} // TODO + (Expr::Access(_, _), _) => {} // TODO (Expr::Basin(_, inner), Repr::Effect(_, o)) => { check_expr(ctx, inner, o, stack); - }, // TODO + } // 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 +489,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..4bcb106 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -14,12 +14,14 @@ impl Pass for RemoveUnusedBindings { 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); @@ -31,49 +33,44 @@ 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)); + tail.as_mut().map(|tail| 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); @@ -83,7 +80,10 @@ impl Pass for RemoveUnusedBindings { 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)) { + } 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 { @@ -92,33 +92,40 @@ impl Pass for RemoveUnusedBindings { *expr = body.into_inner(); } } - }, + } Expr::Func(arg, body) => { stack.push((**arg, 0)); visit(mir, body, stack, proc_stack); stack.pop(); - }, + } Expr::Go(next, body, init) => { visit(mir, init, stack, proc_stack); stack.push((**next, 0)); 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 { + 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); stack.truncate(old_len); } - }, + } _ => 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::>(); @@ -127,7 +134,14 @@ impl Pass for RemoveUnusedBindings { let mut proc_stack = vec![id]; 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..e897c8f 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,9 +44,7 @@ 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 { @@ -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/syntax/src/ast.rs b/syntax/src/ast.rs index cf5f250..b6ae7a3 100644 --- a/syntax/src/ast.rs +++ b/syntax/src/ast.rs @@ -6,22 +6,32 @@ 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_ref(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 +67,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 +141,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,31 +170,23 @@ 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))); + } } } @@ -204,9 +210,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 +262,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 +273,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 +447,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..79e77a9 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, } @@ -53,14 +54,15 @@ 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::Unclosed { start, .. } => + format!("Unclosed delimiter {}", start.fg(Color::Red)), ErrorKind::NoEndBranch => format!("No end branch"), }, if let Some(label) = self.label { @@ -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..7e0191b 100644 --- a/syntax/src/lib.rs +++ b/syntax/src/lib.rs @@ -1,23 +1,23 @@ #![feature(option_zip, trait_alias)] -pub mod error; -pub mod token; -pub mod span; -pub mod src; 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 +25,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 +39,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 +58,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..9df29c9 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.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)) + } }) } 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_else(Vec::new)), + 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(|args, span| Chain::Apply(args, span))) .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,30 +1043,48 @@ 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()), name, @@ -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..bbfa066 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 @@ -196,7 +201,9 @@ impl Program { Instr::Swap => format!("swap"), 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::MakeFunc(i, n) => { + format!("func.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n) + } Instr::ApplyFunc => format!("func.apply"), Instr::MakeList(n) => format!("list.make {}", n), Instr::IndexList(i) => format!("list.index #{}", i), @@ -234,7 +241,9 @@ impl Program { 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::MakeEffect(i, n) => { + format!("eff.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n) + } Instr::Propagate => format!("eff.propagate"), Instr::Suspend(eff) => format!("eff.suspend {:?}", eff), Instr::Register(eff) => format!("eff.register {:?}", eff), @@ -242,7 +251,12 @@ impl Program { 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..73903d0 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, @@ -103,52 +156,61 @@ 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(); @@ -156,160 +218,166 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { 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 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 +386,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 +402,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 +410,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,17 +418,18 @@ 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, - )); + .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(); funcs.push(next_addr); @@ -365,18 +437,18 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { 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,11 +459,12 @@ 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; diff --git a/vm/src/lib.rs b/vm/src/lib.rs index fb30374..7471dbb 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}, -}; -use tao_middle::{ - mir, - Context as MirContext, - MirNode, - ProcId, - repr, - Ident, - EffectId, + code::{Addr, Instr, Program}, + exec::{exec, Env, Value}, }; use hashbrown::HashMap; +use tao_middle::{mir, repr, Context as MirContext, EffectId, Ident, MirNode, ProcId}; diff --git a/vm/src/lower.rs b/vm/src/lower.rs index c809b79..966d16b 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)?, }) @@ -49,18 +44,18 @@ 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); - }, + } 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); - }, + } mir::Pat::Tuple(items) | mir::Pat::ListExact(items) => { for (i, item) in items.iter().enumerate() { if item.binds() { @@ -70,7 +65,7 @@ impl Program { self.compile_extractor(mir, item); } } - }, + } mir::Pat::ListFront(items, tail) => { if let Some(tail) = tail.as_ref() { self.push(Instr::Dup); // Used for tail later @@ -89,23 +84,28 @@ impl Program { self.push(Instr::SkipListImm(items.len())); self.compile_extractor(mir, tail); } - }, + } mir::Pat::Variant(variant, inner) => { self.push(Instr::Dup); self.push(Instr::IndexSum(*variant)); self.compile_extractor(mir, inner); - }, + } mir::Pat::Data(_, inner) => { self.push(Instr::Dup); self.compile_extractor(mir, 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.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 - 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), } } @@ -269,82 +271,135 @@ impl Program { proc_fixups: &mut Vec<(ProcId, Addr)>, ) { match &*expr { - mir::Expr::Undefined => {}, // Do the minimum possible work, execution is undefined anyway + 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) => { 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); @@ -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)); - }, + 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); } @@ -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..6eb00c9 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, Program}; +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), } } From c97f55814d7a8958d42fb279b9b08dedc49c525f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:53:37 +0100 Subject: [PATCH 003/106] Run clippy-fix: Mark variables as unused Signed-off-by: Matthias Beyer --- analysis/src/class.rs | 12 +-- analysis/src/concrete.rs | 6 +- analysis/src/context.rs | 24 +++--- analysis/src/data.rs | 2 +- analysis/src/def.rs | 2 +- analysis/src/effect.rs | 2 +- analysis/src/exhaustivity.rs | 8 +- analysis/src/infer.rs | 100 +++++++++++++------------ analysis/src/lower.rs | 30 ++++---- analysis/src/ty.rs | 4 +- middle/src/error.rs | 2 +- middle/src/lower.rs | 6 +- middle/src/mir.rs | 14 ++-- middle/src/opt/const_fold.rs | 2 +- middle/src/opt/flatten_single_field.rs | 2 +- middle/src/opt/mod.rs | 28 +++---- middle/src/repr.rs | 2 +- syntax/src/ast.rs | 2 +- vm/src/exec.rs | 2 +- vm/src/lower.rs | 6 +- 20 files changed, 129 insertions(+), 127 deletions(-) diff --git a/analysis/src/class.rs b/analysis/src/class.rs index 7c336ce..8021475 100644 --- a/analysis/src/class.rs +++ b/analysis/src/class.rs @@ -208,7 +208,7 @@ impl Classes { pub fn define_member_assoc( &mut self, id: MemberId, - class: ClassId, + _class: ClassId, assoc: HashMap, ) { self.members[id.0].assoc = Some(assoc); @@ -217,7 +217,7 @@ impl Classes { pub fn define_member_fields( &mut self, id: MemberId, - class: ClassId, + _class: ClassId, fields: HashMap, ) { self.members[id.0].fields = Some(fields); @@ -270,11 +270,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 @@ -282,7 +282,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?! diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index 2a9c114..a247b07 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -512,7 +512,7 @@ impl ConContext { // Returns (record_ty, field_ty, number_of_indirections) pub fn follow_field_access( &self, - hir: &Context, + _hir: &Context, mut ty: ConTyId, field: Ident, ) -> Option<(ConTyId, ConTyId, usize)> { @@ -680,7 +680,7 @@ impl ConContext { tail.as_ref() .map(|tail| self.lower_binding(hir, tail, ty_insts)), ), - hir::Pat::Decons(data, variant, inner) => { + 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)) @@ -757,7 +757,7 @@ 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)) diff --git a/analysis/src/context.rs b/analysis/src/context.rs index ced74ec..56383ed 100644 --- a/analysis/src/context.rs +++ b/analysis/src/context.rs @@ -54,7 +54,7 @@ impl Context { .items .iter() .filter_map(|item| match item { - ast::ClassItem::Type { name, obligations } => { + ast::ClassItem::Type { name, obligations: _ } => { Some(ClassAssoc { name: name.clone() }) } _ => None, @@ -72,7 +72,7 @@ impl Context { } } // 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 @@ -274,11 +274,11 @@ impl Context { } 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(); @@ -386,7 +386,7 @@ 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(); @@ -435,7 +435,7 @@ 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 { + 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 @@ -455,7 +455,7 @@ 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 @@ -520,7 +520,7 @@ impl Context { this.classes.define_fields(*class_id, fields); } // Member associated types - for (member, class_id, member_id, member_ty, gen_scope) in &members { + for (member, class_id, member_id, _member_ty, gen_scope) in &members { let assoc = member .items .iter() @@ -684,7 +684,7 @@ impl Context { } // Enforce member obligations - for (member, class_id, member_id, member_ty, gen_scope) in &members { + 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()); @@ -740,7 +740,7 @@ 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(), ); @@ -798,7 +798,7 @@ impl Context { ); } - let (mut checked, mut errs) = infer.into_checked(); + let (_checked, mut errs) = infer.into_checked(); errors.append(&mut errs); } diff --git a/analysis/src/data.rs b/analysis/src/data.rs index a8753f3..0898691 100644 --- a/analysis/src/data.rs +++ b/analysis/src/data.rs @@ -164,7 +164,7 @@ 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)) { diff --git a/analysis/src/def.rs b/analysis/src/def.rs index 11c24f7..91e5411 100644 --- a/analysis/src/def.rs +++ b/analysis/src/def.rs @@ -52,7 +52,7 @@ 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 + if let Some(_lang) = def .attr .iter() .find(|a| &**a.name == "lang") diff --git a/analysis/src/effect.rs b/analysis/src/effect.rs index 9ff8981..ac9b837 100644 --- a/analysis/src/effect.rs +++ b/analysis/src/effect.rs @@ -74,7 +74,7 @@ impl Effects { span, )) } else { - if let Some(lang) = eff + if let Some(_lang) = eff .attr .iter() .find(|a| &**a.name == "lang") diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 48973d4..f99a07e 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -327,7 +327,7 @@ impl AbstractPat { for pat in filter { match pat { AbstractPat::Wildcard => return None, - pat => {} + _pat => {} } } Some(ExamplePat::Wildcard) @@ -419,7 +419,7 @@ impl ExamplePat { "{}", fields .iter() - .map(|(name, f)| format!("{}", DisplayExamplePat(f, false, ctx))) + .map(|(_name, f)| format!("{}", DisplayExamplePat(f, false, ctx))) .collect::>() .join(", ") ), @@ -428,7 +428,7 @@ impl ExamplePat { "({})", fields .iter() - .map(|(name, f)| format!("{},", DisplayExamplePat(f, false, ctx))) + .map(|(_name, f)| format!("{},", DisplayExamplePat(f, false, ctx))) .collect::>() .join(" ") ), @@ -457,7 +457,7 @@ impl ExamplePat { ExamplePat::Variant(name, inner, false) => { write!(f, "{} {}", name, DisplayExamplePat(inner, false, ctx)) } - ExamplePat::Variant(name, inner, true) => write!(f, "{}", name), + ExamplePat::Variant(name, _inner, true) => write!(f, "{}", name), } } } diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 958be38..9b65c79 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -147,29 +147,29 @@ impl<'a, 'b> FlowInfer<'a> for CheckFlow<'a, 'b> { 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) { + 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) { + 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) { + 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) { + 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) { + fn emit_error(&mut self, _err: InferError) { self.1 = Some(false); } - fn make_check_eff(&mut self, x: (EffectVar, TyVar), y: (EffectVar, TyVar)) -> bool { + 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 { + fn make_check_eff_empty(&mut self, _x: (EffectVar, TyVar), _other: TyVar) -> bool { false } } @@ -202,7 +202,7 @@ impl<'a, 'b> FlowInfer<'a> for MakeFlow<'a, 'b> { 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); } @@ -407,7 +407,7 @@ 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(), ); @@ -419,7 +419,7 @@ impl<'a> Infer<'a> { *ty, new_member.member.span(), &mut |idx, _, _| member.gen_tys.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), Some(*member.member), invariant(), ) @@ -550,7 +550,7 @@ impl<'a> Infer<'a> { 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::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); @@ -564,7 +564,7 @@ impl<'a> Infer<'a> { match self.follow_class(class) { ClassInfo::Ref(_) => unreachable!(), ClassInfo::Unknown => {} - ClassInfo::Known(_, gen_tys, gen_effs) => { + ClassInfo::Known(_, gen_tys, _gen_effs) => { for ty in gen_tys { self.set_error(ty); } @@ -594,7 +594,7 @@ impl<'a> Infer<'a> { match self.follow_class(class) { ClassInfo::Ref(_) => unreachable!(), ClassInfo::Unknown => false, - ClassInfo::Known(_, gen_tys, gen_effs) => { + ClassInfo::Known(_, gen_tys, _gen_effs) => { gen_tys.into_iter().any(|ty| self.is_error(ty)) } } @@ -661,9 +661,11 @@ impl<'a> Infer<'a> { ( { let gens = gens.clone(); - move |idx, gen_scope, ctx| gens.as_ref().expect("No gen scope").0.get(idx).copied() + 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(), + move |idx, _ctx| gens.as_ref().expect("No gen scope").1.get(idx).copied(), ) } @@ -792,7 +794,7 @@ impl<'a> Infer<'a> { 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) } }, @@ -919,7 +921,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? @@ -1307,14 +1309,14 @@ impl<'a> Infer<'a> { .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 { 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))?) @@ -1338,11 +1340,11 @@ impl<'a> Infer<'a> { // Closed with opener into closed ( EffectInfo::Closed(x_effs, Some(x_opener)), - EffectInfo::Closed(y_effs, None) | EffectInfo::Open(y_effs), + 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(_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 @@ -1474,7 +1476,7 @@ impl<'a> Infer<'a> { (_, 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)) @@ -1482,7 +1484,7 @@ impl<'a> Infer<'a> { infer.set_unknown_flow(x, y); Ok(infer.set_info(x, TyInfo::Ref(y))) }, - (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)) @@ -1554,8 +1556,8 @@ 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 => { + (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 { @@ -1641,7 +1643,7 @@ impl<'a> Infer<'a> { } // 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() @@ -1739,7 +1741,7 @@ impl<'a> Infer<'a> { *field_ty, self.span(record), &mut |index, _, _| params.get(index).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), Some(record), invariant(), ); @@ -1855,10 +1857,10 @@ impl<'a> Infer<'a> { let assoc_ty_inst = self.instantiate( member_assoc_ty, obl_span, - &mut |idx, gen_scope, ctx| { + &mut |idx, _gen_scope, _ctx| { ty_links.get(&idx).copied() }, - &mut |idx, ctx| eff_links.get(&idx).copied(), + &mut |idx, _ctx| eff_links.get(&idx).copied(), Some(ty), invariant(), ); @@ -1921,7 +1923,7 @@ impl<'a> Infer<'a> { .expect("Send must be init"), span, &mut |idx, _gen_scope, _ctx| args.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), None, invariant(), ); @@ -1934,7 +1936,7 @@ impl<'a> Infer<'a> { .expect("Recv must be init"), span, &mut |idx, _gen_scope, _ctx| args.get(idx).copied(), - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), None, invariant(), ); @@ -1946,7 +1948,7 @@ impl<'a> Infer<'a> { Some(Ok(())) } }, - Constraint::EffectPropagate(obj, basin_eff, out_ty, obj_span, op_span, out_span) => { + 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)); @@ -2084,7 +2086,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) { @@ -2134,7 +2136,7 @@ impl<'a> Infer<'a> { &mut self, ty: TyVar, item: SrcNode, - item_ty: TyVar, + _item_ty: TyVar, is_assoc: bool, ) -> Option<(Vec, HashSet)> { let mut implied_candidates = HashMap::new(); @@ -2158,7 +2160,7 @@ impl<'a> Infer<'a> { let implied_candidates = implied_candidates.values().cloned().cloned().collect(); let mut external_candidates = HashSet::new(); - for (class_id, class) in self + for (class_id, _class) in self .ctx .classes .iter() @@ -2236,7 +2238,7 @@ impl<'a> Infer<'a> { // 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) } @@ -2385,12 +2387,12 @@ impl<'a> Infer<'a> { }), ( TyInfo::Assoc(x, class_x, assoc_x), - Ty::Assoc(y, (class_id_y, y_gen_tys, y_gen_effs), assoc_y), + 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) => { + ClassInfo::Known(class_id_x, x_gen_tys, _x_gen_effs) => { class_id_x == class_id_y && x_gen_tys .into_iter() @@ -2503,7 +2505,7 @@ impl<'a> Infer<'a> { // 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( @@ -2647,7 +2649,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>> { @@ -2658,7 +2660,7 @@ impl<'a> Infer<'a> { 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; @@ -2714,7 +2716,7 @@ impl<'a> Infer<'a> { } // Check constrained associated types - let class = self.insert_class( + let _class = self.insert_class( obl_span, ClassInfo::Known(class_id, class_gen_tys.clone(), class_gen_effs.clone()), ); @@ -2804,7 +2806,7 @@ 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 = + let _gen_span = if let TyInfo::Gen(gen_idx, gen_scope, _) = self.follow_info(ty) { Some( self.ctx @@ -2843,7 +2845,7 @@ 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(); @@ -3107,7 +3109,7 @@ impl<'a> Infer<'a> { .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), @@ -3224,7 +3226,7 @@ impl<'a> Infer<'a> { errors.push(InferError::AmbiguousClassItem(assoc, Vec::new())) } } - Constraint::EffectSendRecv(eff, send, recv, span) => { + Constraint::EffectSendRecv(eff, _send, _recv, _span) => { errors.push(InferError::CannotInferEffect(eff)) } Constraint::EffectPropagate(obj, _, out_ty, obj_span, op_span, _) => { @@ -3240,7 +3242,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) { diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index 6f69553..5c057d7 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))), } @@ -381,7 +381,7 @@ impl ToHir for ast::Type { 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(); + |index, _scope, _infer: &mut Infer| gen_tys.get(index).copied(); let res = enforce_generic_obligations( infer, @@ -413,7 +413,7 @@ impl ToHir for ast::Type { alias_ty, self.span(), &mut get_gen, - &mut |idx, _| todo!(), + &mut |_idx, _| todo!(), None, invariant(), )), @@ -487,7 +487,7 @@ impl ToHir for ast::Type { let gen_effs = class .gen_effs .iter() - .map(|ty| todo!("to_hir for effect")) + .map(|_ty| todo!("to_hir for effect")) .collect::>(); if let Some(class_id) = infer.ctx_mut().classes.lookup(*class.name) { infer.insert_class( @@ -676,7 +676,7 @@ impl ToHir for ast::Binding { .collect::>(); let gen_effs = gen_effs .into_iter() - .map(|origin| infer.insert_effect(self.span(), EffectInfo::free())) + .map(|_origin| infer.insert_effect(self.span(), EffectInfo::free())) .collect::>(); if let Err(()) = enforce_generic_obligations( @@ -705,13 +705,13 @@ impl ToHir for ast::Binding { // Recreate type in context let inner_ty = { let data = infer.ctx().datas.get_data(data); - let data_gen_scope = data.gen_scope; + 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(), + &mut |index, _, _infer: &mut Infer| gen_tys.get(index).copied(), + &mut |index, _infer: &mut Infer| gen_effs.get(index).copied(), None, invariant(), ) @@ -764,7 +764,7 @@ fn instantiate_def( .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() @@ -789,10 +789,10 @@ fn instantiate_def( // 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 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)) @@ -1429,13 +1429,13 @@ impl ToHir for ast::Expr { // Recreate type in context let inner_ty = { let data = infer.ctx().datas.get_data(data); - let data_gen_scope = data.gen_scope; + 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!(), + &mut |index, _, _infer: &mut Infer| gen_tys.get(index).copied(), + &mut |_idx, _| todo!(), None, invariant(), ) diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 6289999..026ab7b 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -163,8 +163,8 @@ impl Types { (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), + 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)) diff --git a/middle/src/error.rs b/middle/src/error.rs index ff878ae..4eebcb6 100644 --- a/middle/src/error.rs +++ b/middle/src/error.rs @@ -9,7 +9,7 @@ pub enum Error { } impl Error { - pub fn write>(self, ctx: &Context, cache: C, writer: impl Write) { + 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 { diff --git a/middle/src/lower.rs b/middle/src/lower.rs index 7e98afc..cdb0444 100644 --- a/middle/src/lower.rs +++ b/middle/src/lower.rs @@ -24,8 +24,8 @@ impl Context { pub fn lower_litr( &mut self, - hir: &HirContext, - con: &ConContext, + _hir: &HirContext, + _con: &ConContext, litr: &hir::Literal, ) -> mir::Literal { match litr { @@ -292,7 +292,7 @@ impl Context { fields.sort_by_key(|(name, _)| name.as_ref()); mir::Expr::Tuple(fields.into_iter().map(|(_, field)| field).collect()) } - hir::Expr::ClassAccess(ty, class, field) => { + hir::Expr::ClassAccess(_ty, _class, _field) => { panic!("Class access should not still exist during MIR lowering") } hir::Expr::Intrinsic(name, args) => { diff --git a/middle/src/mir.rs b/middle/src/mir.rs index fc6bf70..d883330 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -405,7 +405,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()); } @@ -452,7 +452,7 @@ impl Expr { expr.refresh_locals_inner(stack); for Handler { - eff, + eff: _, send, state, recv, @@ -527,7 +527,7 @@ impl Expr { Expr::Handle { expr, handlers } => { expr.required_locals_inner(stack, required); for Handler { - eff, + eff: _, send, state, recv, @@ -554,7 +554,7 @@ 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()), @@ -562,7 +562,7 @@ impl Expr { 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()), @@ -571,7 +571,7 @@ impl Expr { 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::Basin(_, _inner) => false, Expr::Handle { expr, handlers } => { expr.may_have_effect() || handlers @@ -831,7 +831,7 @@ impl Expr { } Ok(()) } - Expr::Basin(eff, inner) => write!( + Expr::Basin(_eff, inner) => write!( f, "effect {{\n{}\n{}}}", DisplayExpr(inner, self.1 + 1, true), diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index b93373d..2c8ffa9 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -349,7 +349,7 @@ impl Intrinsic { 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())))) 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 0961d39..22dce4f 100644 --- a/middle/src/opt/mod.rs +++ b/middle/src/opt/mod.rs @@ -214,9 +214,9 @@ impl Expr { Expr::Handle { expr, handlers } => { f(expr); for Handler { - eff, - send, - state, + eff: _, + send: _, + state: _, recv, } in handlers { @@ -256,9 +256,9 @@ impl Expr { Expr::Handle { expr, handlers } => { f(expr); for Handler { - eff, - send, - state, + eff: _, + send: _, + state: _, recv, } in handlers { @@ -287,7 +287,7 @@ impl Expr { Expr::Handle { expr, handlers } => { expr.inline_local(name, local_expr); for Handler { - eff, + eff: _, send, state, recv, @@ -392,7 +392,7 @@ pub fn check(ctx: &Context) { stack: &mut Vec<(Local, Repr)>, ) { match (&binding.pat, repr) { - (Pat::Data(a, inner), Repr::Data(b)) if a == b => {} // TODO: Check inner + (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() => { @@ -412,7 +412,7 @@ pub fn check(ctx: &Context) { 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(_)) => {} @@ -433,10 +433,10 @@ pub fn check(ctx: &Context) { 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() => { @@ -447,7 +447,7 @@ pub fn check(ctx: &Context) { 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); @@ -464,13 +464,13 @@ pub fn check(ctx: &Context) { (expr, Repr::Data(data)) => { check_expr(ctx, expr, &ctx.reprs.get(*data).repr, stack); } - (Expr::Variant(idx, inner), Repr::Data(_)) => {} // TODO + (Expr::Variant(_idx, _inner), Repr::Data(_)) => {} // 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(_, _)) => { + (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); } diff --git a/middle/src/repr.rs b/middle/src/repr.rs index e897c8f..52dd12e 100644 --- a/middle/src/repr.rs +++ b/middle/src/repr.rs @@ -49,7 +49,7 @@ impl Reprs { 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 diff --git a/syntax/src/ast.rs b/syntax/src/ast.rs index b6ae7a3..b43643c 100644 --- a/syntax/src/ast.rs +++ b/syntax/src/ast.rs @@ -178,7 +178,7 @@ impl Type { 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) => { diff --git a/vm/src/exec.rs b/vm/src/exec.rs index 73903d0..f6cbcd7 100644 --- a/vm/src/exec.rs +++ b/vm/src/exec.rs @@ -430,7 +430,7 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { eff_id, handlers, ) }); - let (f_addr, mut captures) = handler.1.clone().func(); + let (f_addr, captures) = handler.1.clone().func(); funcs.push(next_addr); next_addr = f_addr; diff --git a/vm/src/lower.rs b/vm/src/lower.rs index 966d16b..cc8b71f 100644 --- a/vm/src/lower.rs +++ b/vm/src/lower.rs @@ -67,7 +67,7 @@ impl Program { } } 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 } @@ -383,7 +383,7 @@ impl Program { self.push(Instr::Suspend(*eff)); self.push(Instr::Resume(*eff)); } - Intrinsic::Propagate(effs) => { + Intrinsic::Propagate(_effs) => { self.push(Instr::Propagate); } }; @@ -509,7 +509,7 @@ impl Program { mir::Expr::AccessData(inner, _) => { self.compile_expr(mir, inner, stack, proc_fixups); } - mir::Expr::Basin(eff, inner) => { + mir::Expr::Basin(_eff, inner) => { let (f_addr, captures_len) = self.compile_body(mir, Vec::new(), inner, stack, proc_fixups); self.push(Instr::MakeEffect( From d80876d145dcf87ab738d2011818e97ce8a3b709 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:53:37 +0100 Subject: [PATCH 004/106] Run clippy-fix: Remove "mut" keyword where unnecessary Signed-off-by: Matthias Beyer --- analysis/src/def.rs | 2 +- analysis/src/effect.rs | 2 +- analysis/src/infer.rs | 4 ++-- compiler/src/lib.rs | 4 ++-- middle/src/mir.rs | 2 +- vm/src/exec.rs | 4 ++-- 6 files changed, 9 insertions(+), 9 deletions(-) diff --git a/analysis/src/def.rs b/analysis/src/def.rs index 91e5411..87beb28 100644 --- a/analysis/src/def.rs +++ b/analysis/src/def.rs @@ -69,7 +69,7 @@ impl Defs { } pub fn check_lang_items(&self) -> Vec { - let mut errors = Vec::new(); + let errors = Vec::new(); // if self.lang.io_unit.is_none() { errors.push(Error::MissingLangItem("io_unit")); } diff --git a/analysis/src/effect.rs b/analysis/src/effect.rs index ac9b837..4eb413a 100644 --- a/analysis/src/effect.rs +++ b/analysis/src/effect.rs @@ -106,7 +106,7 @@ impl Effects { } pub fn check_lang_items(&self) -> Vec { - let mut errors = Vec::new(); + let errors = Vec::new(); // if self.lang.not.is_none() { errors.push(Error::MissingLangItem("not")); } diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 9b65c79..8655f13 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -290,7 +290,7 @@ 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 { + let this = Self { ctx, gen_scope: gen_scope, vars: Vec::new(), @@ -1200,7 +1200,7 @@ impl<'a> Infer<'a> { y: (EffectVar, TyVar), info: impl Into, ) { - let mut eq_info = info.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); diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index 3764f1b..d323bbb 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -113,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() { @@ -132,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/middle/src/mir.rs b/middle/src/mir.rs index d883330..3a9069c 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -260,7 +260,7 @@ impl Binding { } } - fn visit_bindings(self: &MirNode, mut bind: &mut impl FnMut(Local, &Repr)) { + fn visit_bindings(self: &MirNode, bind: &mut impl FnMut(Local, &Repr)) { self.name.map(|name| bind(name, self.meta())); match &self.pat { Pat::Wildcard => {} diff --git a/vm/src/exec.rs b/vm/src/exec.rs index f6cbcd7..71b4a0d 100644 --- a/vm/src/exec.rs +++ b/vm/src/exec.rs @@ -212,7 +212,7 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { 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; @@ -245,7 +245,7 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { 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)); From 37a989e461c842965aac11267e90abcf25cae063 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:53:37 +0100 Subject: [PATCH 005/106] Run clippy-fix: Remove unused imports Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 2 +- analysis/src/lib.rs | 2 +- compiler/src/lib.rs | 2 +- middle/src/lib.rs | 10 +++++----- vm/src/lib.rs | 4 ++-- web_demo/src/lib.rs | 2 +- 6 files changed, 11 insertions(+), 11 deletions(-) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index f99a07e..2f08161 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -1,6 +1,6 @@ use super::*; use ranges::Ranges; -use std::{cmp::Ord, fmt, ops::Range}; +use std::{fmt}; #[derive(Debug)] pub enum AbstractPat { diff --git a/analysis/src/lib.rs b/analysis/src/lib.rs index 38d496b..57a35fe 100644 --- a/analysis/src/lib.rs +++ b/analysis/src/lib.rs @@ -46,5 +46,5 @@ pub use tao_util::index::{Id, Index}; use hashbrown::{HashMap, HashSet}; use internment::Intern; -use std::{collections::BTreeMap, fmt, marker::PhantomData}; +use std::{collections::BTreeMap, fmt}; use tao_syntax::{ast, Node, Span, SrcId, SrcNode}; diff --git a/compiler/src/lib.rs b/compiler/src/lib.rs index d323bbb..9852a63 100644 --- a/compiler/src/lib.rs +++ b/compiler/src/lib.rs @@ -6,7 +6,7 @@ pub use tao_syntax::SrcId; use ariadne::sources; use error::Error; use internment::Intern; -use std::{collections::HashMap, fmt, io::Write, str::FromStr}; +use std::{collections::HashMap, io::Write}; use structopt::StructOpt; use tao_analysis::Context as HirContext; use tao_middle::Context; diff --git a/middle/src/lib.rs b/middle/src/lib.rs index 8141d3d..8788c4a 100644 --- a/middle/src/lib.rs +++ b/middle/src/lib.rs @@ -18,13 +18,13 @@ pub use crate::{ }; pub use tao_analysis::Ident; -use hashbrown::{HashMap, HashSet}; -use internment::Intern; +use hashbrown::{HashSet}; + use std::collections::{BTreeMap, BTreeSet}; use tao_analysis::{ - data::DataId, hir, ty, ConBinding, ConContext, ConDataId, ConEffectId, ConExpr, ConProc, - ConProcId, ConTy, ConTyId, Context as HirContext, DefId, TyNode, + hir, ty, ConBinding, ConContext, ConDataId, ConEffectId, ConExpr, + ConProcId, ConTy, ConTyId, Context as HirContext, }; -use tao_syntax::{ast, Node, Span, SrcId, SrcNode}; +use tao_syntax::{Node, Span, SrcId, SrcNode}; pub type EffectId = ConEffectId; diff --git a/vm/src/lib.rs b/vm/src/lib.rs index 7471dbb..8582644 100644 --- a/vm/src/lib.rs +++ b/vm/src/lib.rs @@ -6,5 +6,5 @@ pub use crate::{ code::{Addr, Instr, Program}, exec::{exec, Env, Value}, }; -use hashbrown::HashMap; -use tao_middle::{mir, repr, Context as MirContext, EffectId, Ident, MirNode, ProcId}; + +use tao_middle::{mir, repr, Context as MirContext, EffectId, MirNode, ProcId}; diff --git a/web_demo/src/lib.rs b/web_demo/src/lib.rs index 6eb00c9..b6a3531 100644 --- a/web_demo/src/lib.rs +++ b/web_demo/src/lib.rs @@ -2,7 +2,7 @@ use include_dir::{include_dir, Dir}; use rand::prelude::*; use std::path::{Component, PathBuf}; use tao::{compile, OptMode, Options, SrcId}; -use tao_vm::{exec, Env, Program}; +use tao_vm::{exec, Env}; use wasm_bindgen::prelude::*; static LIB_DIR: Dir<'_> = include_dir!("$CARGO_MANIFEST_DIR/../lib"); From 98cab60e6f9bccd38f16bab3fddbf8ca717098bd Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:56:32 +0100 Subject: [PATCH 006/106] Fix clippy: Remove needless borrow Signed-off-by: Matthias Beyer --- analysis/src/ty.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 026ab7b..7373e9d 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -544,13 +544,13 @@ impl GenScope { self.types .iter() .enumerate() - .find(|(_, ty)| &*ty.name == &name) + .find(|(_, ty)| *ty.name == name) } pub fn find_eff(&self, name: Ident) -> Option<(usize, &GenEff)> { self.effects .iter() .enumerate() - .find(|(_, eff)| &*eff.name == &name) + .find(|(_, eff)| *eff.name == name) } } From 28a837ffdf325d48d02a300293faf9496e96182d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:57:37 +0100 Subject: [PATCH 007/106] Fix clippy: Type with len() fn should also have is_empty() Signed-off-by: Matthias Beyer --- analysis/src/ty.rs | 5 +++++ 1 file changed, 5 insertions(+) diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 7373e9d..445d92e 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -528,6 +528,11 @@ impl GenScope { 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() } From 415ddc4581a47077ef6e23e72ad53689ee0e15bb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:59:06 +0100 Subject: [PATCH 008/106] Fix clippy: use to_string() instead of format!() macro Signed-off-by: Matthias Beyer --- analysis/src/ty.rs | 15 +++++++++------ 1 file changed, 9 insertions(+), 6 deletions(-) diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 445d92e..6eacf5b 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -379,7 +379,7 @@ impl<'a> fmt::Display for TyDisplay<'a> { .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::() ); @@ -404,10 +404,13 @@ 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::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, @@ -415,7 +418,7 @@ impl<'a> fmt::Display for TyDisplay<'a> { .map(|arg| format!(" {}", self.with_ty(*arg, true))) .collect::() ), - Err(()) => format!("!"), + Err(()) => "!".to_string(), }) .collect::>(); if effs.is_empty() { From c00f062c587aac4cff72e393ab199eb38c08056c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 08:59:41 +0100 Subject: [PATCH 009/106] Fix clippy: Use is_empty() instead of len() == 0 Signed-off-by: Matthias Beyer --- analysis/src/ty.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/ty.rs b/analysis/src/ty.rs index 6eacf5b..2355f44 100644 --- a/analysis/src/ty.rs +++ b/analysis/src/ty.rs @@ -348,7 +348,7 @@ impl<'a> fmt::Display for TyDisplay<'a> { self.with_ty(i, true), self.with_ty(o, self.lhs_exposed) ), - Ty::Data(name, params) if self.lhs_exposed && params.len() > 0 => write!( + Ty::Data(name, params) if self.lhs_exposed && !params.is_empty() => write!( f, "({}{})", *self.ctx.datas.get_data(name).name, From c43085f83239a7c845ba4a6af555040d00b2644f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:01:06 +0100 Subject: [PATCH 010/106] Fix clippy: Remove needless borrow Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index 5c057d7..1be7519 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -1830,7 +1830,7 @@ impl ToHir for ast::Expr { // 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); ( @@ -1839,11 +1839,11 @@ impl ToHir for ast::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 @@ -1856,9 +1856,9 @@ impl ToHir for ast::Expr { state, recv, }| { - let send = send.to_hir(cfg, infer, &scope); + let send = send.to_hir(cfg, infer, scope); let state = - state.as_ref().map(|state| state.to_hir(cfg, infer, &scope)); + state.as_ref().map(|state| state.to_hir(cfg, infer, scope)); let recv = recv.to_hir( cfg, infer, From 180e7db06dfbfce915d1e8f08442fcd0559423dd Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:02:40 +0100 Subject: [PATCH 011/106] Fix clippy: Replace format!() with to_string() call Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index 1be7519..49bfedf 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -583,7 +583,7 @@ impl ToHir for ast::Binding { nat, EqInfo::new( self.span(), - format!("Only natural numbers support arithmetic patterns"), + "Only natural numbers support arithmetic patterns".to_string(), ), ); ( @@ -1173,7 +1173,7 @@ impl ToHir for ast::Expr { output_ty, EqInfo::new( self.span(), - format!("Branches must produce compatible values"), + "Branches must produce compatible values".to_string(), ), ); (binding, body) @@ -1191,7 +1191,7 @@ impl ToHir for ast::Expr { infer.make_flow( pred.meta().1, pred_ty, - EqInfo::new(self.span(), format!("Conditions must be booleans")), + 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); @@ -1200,7 +1200,7 @@ impl ToHir for ast::Expr { output_ty, EqInfo::new( self.span(), - format!("Branches must produce compatible values"), + "Branches must produce compatible values".to_string(), ), ); infer.make_flow( @@ -1208,7 +1208,7 @@ impl ToHir for ast::Expr { output_ty, EqInfo::new( self.span(), - format!("Branches must produce compatible values"), + "Branches must produce compatible values".to_string(), ), ); let unit = InferNode::new( @@ -1323,7 +1323,7 @@ impl ToHir for ast::Expr { output_ty, EqInfo::new( self.span(), - format!("Branches must produce compatible values"), + "Branches must produce compatible values".to_string(), ), ); (binding, body) @@ -1369,14 +1369,14 @@ impl ToHir for ast::Expr { infer.make_flow( f.meta().1, func, - EqInfo::new(self.span(), format!("Only functions are callable")), + EqInfo::new(self.span(), "Only functions are callable".to_string()), ); infer.make_flow( param.meta().1, input_ty, EqInfo::new( param.meta().0, - format!("Functions may only be called with compatible arguments"), + "Functions may only be called with compatible arguments".to_string(), ), ); From 8de1deb9e079beccc7acd9b61e6a50c6259354ad Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:10:37 +0100 Subject: [PATCH 012/106] Fix clippy: Mask unused variable This variable is only used in the recursion. We cannot easily remove it, because other trait implementations might need it (any this isnt supposed to be a refactoring, but only a clippy cleanup). Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 66 +++++++++++++++++++++---------------------- 1 file changed, 33 insertions(+), 33 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index 49bfedf..cc0da50 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -834,7 +834,7 @@ impl ToHir for ast::Expr { fn to_hir( self: &SrcNode, - cfg: &Self::Cfg, + _cfg: &Self::Cfg, infer: &mut Infer, scope: &Scope, ) -> InferNode { @@ -849,7 +849,7 @@ impl ToHir for ast::Expr { ) } 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), @@ -870,7 +870,7 @@ impl ToHir for ast::Expr { 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)), @@ -884,7 +884,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 }) @@ -893,7 +893,7 @@ 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 }) @@ -904,7 +904,7 @@ impl ToHir for ast::Expr { 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() @@ -913,7 +913,7 @@ impl ToHir for ast::Expr { (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 @@ -924,7 +924,7 @@ impl ToHir for ast::Expr { } ast::Expr::Unary(op, a) => { if let ast::UnaryOp::Propagate = &**op { - let a = a.to_hir(cfg, infer, scope); + 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() { @@ -951,7 +951,7 @@ impl ToHir for ast::Expr { ), ) } else { - let a = a.to_hir(cfg, infer, scope); + 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)); @@ -993,8 +993,8 @@ impl ToHir for ast::Expr { } } 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 { @@ -1133,7 +1133,7 @@ impl ToHir for ast::Expr { } } - 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()) } @@ -1154,17 +1154,17 @@ 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, + _cfg, infer, &scope.with_many(&binding.get_binding_tys()), ); @@ -1187,14 +1187,14 @@ impl ToHir for ast::Expr { 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); + 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); + let a = a.to_hir(_cfg, infer, scope); + let b = b.to_hir(_cfg, infer, scope); infer.make_flow( a.meta().1, output_ty, @@ -1303,7 +1303,7 @@ impl ToHir for ast::Expr { .collect(), self.span(), ), - cfg, + _cfg, infer, &scope.with_many(&pseudos.clone()), ); @@ -1311,10 +1311,10 @@ impl ToHir for ast::Expr { 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, + _cfg, infer, &scope.with_many(&binding.get_binding_tys()), ); @@ -1361,8 +1361,8 @@ impl ToHir for ast::Expr { } } 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)); @@ -1441,7 +1441,7 @@ impl ToHir for ast::Expr { ) }; - let inner = inner.to_hir(cfg, infer, scope); + let inner = inner.to_hir(_cfg, infer, scope); infer.make_flow(inner.meta().1, inner_ty, self.span()); ( @@ -1473,7 +1473,7 @@ impl ToHir for ast::Expr { let mut args = args .iter() - .map(|arg| arg.to_hir(cfg, infer, scope)) + .map(|arg| arg.to_hir(_cfg, infer, scope)) .collect::>(); let unary_ops = [ @@ -1809,11 +1809,11 @@ impl ToHir for ast::Expr { } } 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) }) @@ -1830,7 +1830,7 @@ impl ToHir for ast::Expr { // 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); ( @@ -1839,11 +1839,11 @@ impl ToHir for ast::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 @@ -1856,11 +1856,11 @@ impl ToHir for ast::Expr { state, recv, }| { - let send = send.to_hir(cfg, infer, scope); + let send = send.to_hir(_cfg, infer, scope); let state = - state.as_ref().map(|state| state.to_hir(cfg, infer, scope)); + state.as_ref().map(|state| state.to_hir(_cfg, infer, scope)); let recv = recv.to_hir( - cfg, + _cfg, infer, &scope.with_many(&send.get_binding_tys()).with_many( &state From 1bb82f0aed2ddf5ce8b3b110563fb84626c5d5e1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:10:37 +0100 Subject: [PATCH 013/106] Fix clippy: Mask unused variable This variable is only used in the recursion. We cannot easily remove it, because other trait implementations might need it (any this isnt supposed to be a refactoring, but only a clippy cleanup). Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index cc0da50..ed11226 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -531,7 +531,7 @@ impl ToHir for ast::Binding { fn to_hir( self: &SrcNode, - cfg: &Self::Cfg, + _cfg: &Self::Cfg, infer: &mut Infer, scope: &Scope, ) -> InferNode { @@ -569,12 +569,12 @@ impl ToHir for ast::Binding { ) } 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)); @@ -607,7 +607,7 @@ impl ToHir for ast::Binding { 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)), @@ -617,7 +617,7 @@ impl ToHir for ast::Binding { 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( @@ -635,7 +635,7 @@ impl ToHir for ast::Binding { 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 }) @@ -647,13 +647,13 @@ impl ToHir for ast::Binding { 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 @@ -717,7 +717,7 @@ impl ToHir for ast::Binding { ) }; - let inner = inner.to_hir(cfg, infer, scope); + let inner = inner.to_hir(_cfg, infer, scope); infer.make_flow(inner_ty, inner.meta().1, self.span()); ( From 5acbdbcd857843b65bfbaa148efa4657128d0faa Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:12:46 +0100 Subject: [PATCH 014/106] Fix clippy: Use is_empty() instead of len() > 0 Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index ed11226..5ce65d2 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -120,7 +120,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() @@ -399,7 +399,7 @@ impl ToHir for ast::Type { 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() @@ -451,7 +451,7 @@ impl ToHir for ast::Type { 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() From 775e02505b14a18df8f565f151e4638b4d292d9e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:13:44 +0100 Subject: [PATCH 015/106] Fix clippy: Remove unnecessary keyword "return" Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 8655f13..ad31ecd 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -3413,7 +3413,7 @@ 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, From ac8960fade756a8a2135425d7661592fe82288e7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:14:38 +0100 Subject: [PATCH 016/106] Fix clippy: Remove unnecessary borrow Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index ad31ecd..935066f 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -3344,10 +3344,10 @@ pub struct Checked<'a> { impl<'a> Checked<'a> { pub fn ctx(&self) -> &Context { - &self.infer.ctx + self.infer.ctx } pub fn ctx_mut(&mut self) -> &mut Context { - &mut self.infer.ctx + self.infer.ctx } fn reify_inner(&mut self, var: TyVar) -> TyId { From 8ff143bbaf993eb1e68086606a9b7b5a7e6f1b16 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:15:34 +0100 Subject: [PATCH 017/106] Fix clippy: Remove unnecessary clone() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 935066f..b9d8655 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -2718,7 +2718,7 @@ impl<'a> Infer<'a> { // Check constrained associated types let _class = self.insert_class( obl_span, - ClassInfo::Known(class_id, class_gen_tys.clone(), class_gen_effs.clone()), + ClassInfo::Known(class_id, class_gen_tys, class_gen_effs), ); // if let ImpliedItems::Eq(assoc_set) = &items { // for (assoc, assoc_ty) in assoc { @@ -2964,7 +2964,7 @@ impl<'a> Infer<'a> { if proof_stack.contains(&proof_key) { return Some(Err(InferError::CycleWhenResolving( ty, - (class_id, class_gen_tys.clone(), class_gen_effs.clone()), + (class_id, class_gen_tys, class_gen_effs), member.span(), ))); } else { From d2998e074db92d2592a31adb6982d778ce0d76b1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:17:04 +0100 Subject: [PATCH 018/106] Fix clippy: Elide lifetimes Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index 5ce65d2..d716df9 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -39,11 +39,11 @@ impl<'a> Scope<'a> { 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> { + fn without_basin(&self) -> Scope { Scope::Basin(self, None) } From 1e1d359908902034c7583ec69176031fa2d07d92 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:17:51 +0100 Subject: [PATCH 019/106] Fix clippy: Replace into_iter() with iter() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index b9d8655..ef48dad 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -2453,7 +2453,7 @@ impl<'a> Infer<'a> { Ok(EffectInst::Concrete(y, y_gen_tys)), ) if x == *y => x_gen_tys .into_iter() - .zip(y_gen_tys.into_iter()) + .zip(y_gen_tys.iter()) .try_fold(true, |a, (x, y)| { Ok(a && self.covers_var(x, *y, ty_gens, eff_gens, todo)?) }) @@ -2619,7 +2619,7 @@ impl<'a> Infer<'a> { EffectInstInfo::Known(y, y_gen_tys), ) if *x == y => { x_gen_tys - .into_iter() + .iter() .zip(y_gen_tys.into_iter()) .for_each(|(x, y)| { self.derive_links(*x, y, self_ty, use_span, ty_links, eff_links) From 9630ce3fb86bd8cdeb844d296898b1cdc59588e2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:18:22 +0100 Subject: [PATCH 020/106] Fix clippy: Remove unnecessary clone() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index ef48dad..fe7298d 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1903,10 +1903,10 @@ impl<'a> Infer<'a> { } } Constraint::ClassField(ty, class, field, field_ty, span) => { - self.try_resolve_class_from_field(ty, class, field.clone(), 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.clone(), 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) { From 3ff7f425b19a376b693abd4fad43c2e1abc08101 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:19:15 +0100 Subject: [PATCH 021/106] Fix clippy: Remove unnecessary closure Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index fe7298d..0545466 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -2457,7 +2457,7 @@ impl<'a> Infer<'a> { .try_fold(true, |a, (x, y)| { Ok(a && self.covers_var(x, *y, ty_gens, eff_gens, todo)?) }) - .unwrap_or_else(|()| false), + .unwrap_or(false), (x, y) => { dbg!("{:?} covers {:?}", x, y); false From 21472c9bfd33f09d97a30d28438e8b1f4f021e64 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:21:02 +0100 Subject: [PATCH 022/106] Fix: Do not use ? operator when we can easily map() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 3 ++- 1 file changed, 2 insertions(+), 1 deletion(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 0545466..3831b3c 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -2455,7 +2455,8 @@ impl<'a> Infer<'a> { .into_iter() .zip(y_gen_tys.iter()) .try_fold(true, |a, (x, y)| { - Ok(a && self.covers_var(x, *y, ty_gens, eff_gens, todo)?) + self.covers_var(x, *y, ty_gens, eff_gens, todo) + .map(|b| a && b) }) .unwrap_or(false), (x, y) => { From 0fb0f523679f3507cb6f29b6ffd513810c6abe1d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:39:24 +0100 Subject: [PATCH 023/106] Clippy: Allow result_unit_err lint for now Allow this lint for now, so we can fix the simpler ones first and don't have to scroll in the clippy output all the time. This patch will be reverted as soon as possible. Signed-off-by: Matthias Beyer --- analysis/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/analysis/src/lib.rs b/analysis/src/lib.rs index 57a35fe..37198c7 100644 --- a/analysis/src/lib.rs +++ b/analysis/src/lib.rs @@ -1,5 +1,7 @@ #![feature(arbitrary_self_types, option_zip, never_type, let_else, let_chains)] +#![allow(clippy::result_unit_err)] + pub mod class; pub mod concrete; pub mod context; From 5706371ea314a7e7ecb2cdac0a4a5ef9d80e9ab1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:39:24 +0100 Subject: [PATCH 024/106] Clippy: Allow type_complexity lint for now Allow this lint for now, so we can fix the simpler ones first and don't have to scroll in the clippy output all the time. This patch will be reverted as soon as possible. Signed-off-by: Matthias Beyer --- analysis/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/analysis/src/lib.rs b/analysis/src/lib.rs index 37198c7..fecaf34 100644 --- a/analysis/src/lib.rs +++ b/analysis/src/lib.rs @@ -1,6 +1,7 @@ #![feature(arbitrary_self_types, option_zip, never_type, let_else, let_chains)] #![allow(clippy::result_unit_err)] +#![allow(clippy::type_complexity)] pub mod class; pub mod concrete; From 9398920bc4c9b7e842be97a759f324d50c9b0520 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:40:35 +0100 Subject: [PATCH 025/106] Fix clippy: Remove unnecessary borrow Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 3831b3c..9a72489 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1707,7 +1707,7 @@ impl<'a> Infer<'a> { } TyInfo::Unknown(_) => None, TyInfo::Record(fields, _) => { - if let Some(field_ty) = fields.get(&field_name) { + if let Some(field_ty) = fields.get(field_name) { self.make_flow(*field_ty, field, field_name.span()); Some(true) } else { @@ -1736,7 +1736,7 @@ impl<'a> Infer<'a> { // 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 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), @@ -2433,7 +2433,7 @@ impl<'a> Infer<'a> { 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) { + 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)), From 830f22d7e29ddf1a21dc981f3e46092b60a7bcd2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:41:41 +0100 Subject: [PATCH 026/106] Fix clippy: Don't pass unit to function Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 34 ++++++++++++++++++++++++---------- 1 file changed, 24 insertions(+), 10 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 9a72489..15758b3 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1293,10 +1293,12 @@ impl<'a> Infer<'a> { (EffectInstInfo::Error, _) => Ok(()), (_, EffectInstInfo::Error) => Ok(()), (EffectInstInfo::Unknown, _) => { - Ok(infer.set_effect_inst_info(x, EffectInstInfo::Ref(y))) + infer.set_effect_inst_info(x, EffectInstInfo::Ref(y)); + Ok(()) } (_, EffectInstInfo::Unknown) => { - Ok(infer.set_effect_inst_info(y, EffectInstInfo::Ref(x))) + 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 @@ -1433,8 +1435,14 @@ impl<'a> Infer<'a> { 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::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 => { @@ -1479,28 +1487,34 @@ impl<'a> Infer<'a> { (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) { 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(()), From efdd42c60b48039a39ed9960409313a9949cabb4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:43:13 +0100 Subject: [PATCH 027/106] Fix clippy: Use try_for_each instead of collecting to Result Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 15758b3..5b8d6d4 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1406,8 +1406,7 @@ impl<'a> Infer<'a> { } 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::>()?; + .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)) { From 0553ddba0434f38d85196a11aef77ebc2cecdb59 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:45:10 +0100 Subject: [PATCH 028/106] Fix clippy: Don't compare to Ok(()), is is_ok() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 12 ++++++------ 1 file changed, 6 insertions(+), 6 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 5b8d6d4..b72c6a2 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1361,7 +1361,7 @@ impl<'a> Infer<'a> { 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()) }) { Ok(()) } else if infer.make_check_eff((x, x_ty), (y, y_ty)) { @@ -1404,9 +1404,9 @@ impl<'a> Infer<'a> { Err((x_ty, y_ty)) } } else if y_effs.len() == 1 { - x_effs - .iter() - .try_for_each(|x| Self::flow_effect_inst(infer, (*x, x_ty), (y_effs[0], y_ty)))?; + 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)) { @@ -1437,11 +1437,11 @@ impl<'a> Infer<'a> { (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 => { From 99609ae6ea8f7a659d73151dac65a9f1f122e265 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:46:24 +0100 Subject: [PATCH 029/106] Fix clippy: Don't use else-if when logical OR is possible Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 5 ++--- 1 file changed, 2 insertions(+), 3 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index b72c6a2..36d1528 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1362,9 +1362,8 @@ impl<'a> Infer<'a> { y_effs .iter() .any(|y| Self::flow_effect_inst(infer, (*x, x_ty), (*y, y_ty)).is_ok()) - }) { - Ok(()) - } else if infer.make_check_eff((x, x_ty), (y, y_ty)) { + }) || infer.make_check_eff((x, x_ty), (y, y_ty)) + { Ok(()) } else { Err((x_ty, y_ty)) From 05fa58dc1c1916347cb20a5c535a57b86473abec Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:47:02 +0100 Subject: [PATCH 030/106] Fix clippy: don't negate is_ok() result, use is_err() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 36d1528..b9e39cf 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1219,7 +1219,7 @@ impl<'a> Infer<'a> { match check.1 { Some(true) => Some(res.is_ok()), None => { - if !res.is_ok() { + if res.is_err() { Some(false) } else { None @@ -1241,7 +1241,7 @@ impl<'a> Infer<'a> { match check.1 { Some(true) => Some(res.is_ok()), None => { - if !res.is_ok() { + if res.is_err() { Some(false) } else { None From 2c47232b4b0a8875ad33f2da12638a37a1be33e5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:47:34 +0100 Subject: [PATCH 031/106] Fix clippy: Remove unnecessary clone() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index b9e39cf..7bfa3c3 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1163,9 +1163,9 @@ 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)) } From b4158535619251c3a23fca700c276657c1ed9ef0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:48:03 +0100 Subject: [PATCH 032/106] Fix clippy: Remove unnecessary keyword "return" Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 7bfa3c3..dd1366f 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -534,7 +534,7 @@ 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(_) From fddc74f57dfcc04920151799ff96926e6d807329 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:48:27 +0100 Subject: [PATCH 033/106] Fix clippy: Replace .iter().next() with .first() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index dd1366f..a83d2e8 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1746,7 +1746,7 @@ impl<'a> Infer<'a> { // 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) { let field_ty = self.instantiate( From 3e1ce9c279f8eb10b96c965f8ec3f5c2cc0f34a3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:48:53 +0100 Subject: [PATCH 034/106] Fix clippy: Simplify constructor Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index a83d2e8..952a9d0 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -290,7 +290,7 @@ 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 this = Self { + Self { ctx, gen_scope: gen_scope, vars: Vec::new(), @@ -305,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 { From 4c02daf7ef2b602e42ed532e4efbcc30b1e6449a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:49:05 +0100 Subject: [PATCH 035/106] Fix clippy: Use field initialization from variable directly Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 952a9d0..428c117 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -292,7 +292,7 @@ impl<'a> Infer<'a> { pub fn new(ctx: &'a mut Context, gen_scope: Option) -> Self { Self { ctx, - gen_scope: gen_scope, + gen_scope, vars: Vec::new(), class_vars: Vec::new(), effect_vars: Vec::new(), From 50f63570c75aaf2de922ca3c9fb308666b8c3b6a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:50:45 +0100 Subject: [PATCH 036/106] Fix clippy: Remove unnecessary dereference Signed-off-by: Matthias Beyer --- analysis/src/hir.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/analysis/src/hir.rs b/analysis/src/hir.rs index 7c5c62d..6426ee8 100644 --- a/analysis/src/hir.rs +++ b/analysis/src/hir.rs @@ -239,26 +239,26 @@ impl Expr { tails.iter().for_each(|tail| f(tail)); } Expr::Record(fields, _) => fields.iter().for_each(|(_, field)| f(field)), - Expr::Access(record, _) => f(&record), + Expr::Access(record, _) => f(record), Expr::Match(_, pred, arms) => { - f(&pred); + f(pred); arms.iter().for_each(|(_, arm)| f(arm)); } - Expr::Func(_, body) => f(&body), + Expr::Func(_, body) => f(body), Expr::Apply(func, arg) => { - f(&func); - f(&arg); + f(func); + f(arg); } - Expr::Cons(_, _, inner) => f(&inner), + Expr::Cons(_, _, inner) => f(inner), Expr::Intrinsic(_, args) => args.iter().for_each(|arg| f(arg)), Expr::Update(record, fields) => { - f(&record); + f(record); fields.iter().for_each(|(_, field)| f(field)); } - Expr::Basin(_, inner) => f(&inner), - Expr::Suspend(_, inner) => f(&inner), + Expr::Basin(_, inner) => f(inner), + Expr::Suspend(_, inner) => f(inner), Expr::Handle { expr, handlers } => { - f(&expr); + f(expr); handlers.iter().for_each(|handler| f(&handler.recv)); } } From 92bba893a8f916db5a1b443fc3be612d6aa814be Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:51:54 +0100 Subject: [PATCH 037/106] Fix clippy: Remove unnecessary closures Signed-off-by: Matthias Beyer --- analysis/src/hir.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/analysis/src/hir.rs b/analysis/src/hir.rs index 6426ee8..0288d81 100644 --- a/analysis/src/hir.rs +++ b/analysis/src/hir.rs @@ -235,8 +235,8 @@ impl Expr { | Expr::ClassAccess(_, _, _) | Expr::Global(_) => {} Expr::List(items, tails) => { - items.iter().for_each(|item| f(item)); - tails.iter().for_each(|tail| f(tail)); + 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), @@ -250,7 +250,7 @@ impl Expr { f(arg); } Expr::Cons(_, _, inner) => f(inner), - Expr::Intrinsic(_, args) => args.iter().for_each(|arg| f(arg)), + Expr::Intrinsic(_, args) => args.iter().for_each(f), Expr::Update(record, fields) => { f(record); fields.iter().for_each(|(_, field)| f(field)); From eb6473c5ddc219ce76d53ca9f88ce9a132e5fd9f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:54:06 +0100 Subject: [PATCH 038/106] Clippy: Allow never_loop in two instances This looks like a bug to me. Allow the lint for now, so we can continue working on clippy warnings without them getting in the way. This patch should be reverted as soon as possible. Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 2f08161..908845a 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -172,6 +172,7 @@ impl AbstractPat { Some(ExamplePat::Wildcard) } Ty::Prim(Prim::Universe) => { + #[allow(clippy::never_loop)] for pat in filter { match pat { AbstractPat::Wildcard => return None, @@ -366,6 +367,7 @@ impl AbstractPat { .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, From 962d110abce628a3dc52b9faf7d51e96db1a9c4e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:56:02 +0100 Subject: [PATCH 039/106] Fix clippy: Replace format!() with .to_string() Signed-off-by: Matthias Beyer --- compiler/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/compiler/src/error.rs b/compiler/src/error.rs index c89f247..576c25f 100644 --- a/compiler/src/error.rs +++ b/compiler/src/error.rs @@ -13,7 +13,7 @@ impl Error { 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))], ), }; From 8739f44b06a04c624a751e653bee6b45734d6897 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:56:34 +0100 Subject: [PATCH 040/106] Fix clippy: Replace format!() with .to_string() Signed-off-by: Matthias Beyer --- web_demo/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/web_demo/src/lib.rs b/web_demo/src/lib.rs index b6a3531..ee3953f 100644 --- a/web_demo/src/lib.rs +++ b/web_demo/src/lib.rs @@ -96,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); } } From 055dbe3c3d6883a802f2d6001af1a57a0f789a71 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:57:08 +0100 Subject: [PATCH 041/106] Fix clippy: Replace len() > 0 with is_empty() Signed-off-by: Matthias Beyer --- vm/src/lower.rs | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/vm/src/lower.rs b/vm/src/lower.rs index cc8b71f..be7f5be 100644 --- a/vm/src/lower.rs +++ b/vm/src/lower.rs @@ -166,7 +166,7 @@ impl Program { self.compile_item_matcher(items, true, None); } mir::Pat::ListExact(items) => { - if items.len() == 0 { + if items.is_empty() { self.push(Instr::LenList); self.push(Instr::Imm(Value::Int(items.len() as i64))); self.push(Instr::EqInt); @@ -427,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 @@ -580,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 } From 7677153c2a129256787067e0c628c52f9fc3b41f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:57:35 +0100 Subject: [PATCH 042/106] Fix clippy: Remove unnecessary borrow Signed-off-by: Matthias Beyer --- vm/src/lower.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/vm/src/lower.rs b/vm/src/lower.rs index be7f5be..94edcdb 100644 --- a/vm/src/lower.rs +++ b/vm/src/lower.rs @@ -238,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); @@ -270,7 +270,7 @@ impl Program { stack: &mut Vec, proc_fixups: &mut Vec<(ProcId, Addr)>, ) { - match &*expr { + 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) { From 1afb7f366595f982b0701c06baa363766ded0ae8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:58:42 +0100 Subject: [PATCH 043/106] Fix clippy: Remove unused variable Signed-off-by: Matthias Beyer --- vm/src/exec.rs | 2 -- vm/src/lower.rs | 18 +++++++++--------- 2 files changed, 9 insertions(+), 11 deletions(-) diff --git a/vm/src/exec.rs b/vm/src/exec.rs index 71b4a0d..e13c6be 100644 --- a/vm/src/exec.rs +++ b/vm/src/exec.rs @@ -467,8 +467,6 @@ pub fn exec(prog: &Program, env: &mut E) -> Option { } } - tick += 1; - addr = next_addr; } } diff --git a/vm/src/lower.rs b/vm/src/lower.rs index 94edcdb..6e3aa4a 100644 --- a/vm/src/lower.rs +++ b/vm/src/lower.rs @@ -22,7 +22,7 @@ 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(); @@ -48,13 +48,13 @@ impl Program { 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() { @@ -62,7 +62,7 @@ impl Program { self.push(Instr::Dup); self.push(Instr::IndexList(i)); - self.compile_extractor(mir, item); + self.compile_extractor(item); } } } @@ -76,23 +76,23 @@ 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); } } @@ -419,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(); From 9e447ba080995d61c687906d5dc7cec981964c09 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:59:55 +0100 Subject: [PATCH 044/106] Fix clippy: Replace format!() with .to_string() Signed-off-by: Matthias Beyer --- vm/src/code.rs | 68 +++++++++++++++++++++++++------------------------- 1 file changed, 34 insertions(+), 34 deletions(-) diff --git a/vm/src/code.rs b/vm/src/code.rs index bbfa066..44fee0f 100644 --- a/vm/src/code.rs +++ b/vm/src/code.rs @@ -193,58 +193,58 @@ 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::Ret => "ret".to_string(), Instr::MakeFunc(i, n) => { format!("func.make {:+} (0x{:03X}) {}", i, addr.jump(i).0, n) } - Instr::ApplyFunc => format!("func.apply"), + 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::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 => format!("eff.propagate"), + 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), From 77e339d5a23c751e0c4c26fd3b7e434976fac82b Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:00:28 +0100 Subject: [PATCH 045/106] Fix clippy: Replace matching with .is_some() Signed-off-by: Matthias Beyer --- vm/src/lower.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/vm/src/lower.rs b/vm/src/lower.rs index 6e3aa4a..5d32316 100644 --- a/vm/src/lower.rs +++ b/vm/src/lower.rs @@ -26,7 +26,7 @@ impl Program { // 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; From 3d68fdda9bdcb25ee3efc54e6085d28877bc42c9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:00:46 +0100 Subject: [PATCH 046/106] Fix clippy: Remove unused variable Signed-off-by: Matthias Beyer --- vm/src/exec.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/vm/src/exec.rs b/vm/src/exec.rs index e13c6be..0a40588 100644 --- a/vm/src/exec.rs +++ b/vm/src/exec.rs @@ -148,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(); From f09b7f1d8701da064b4541026a315de81e9d7ba1 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:02:00 +0100 Subject: [PATCH 047/106] Fix clippy: Remove unused function param Signed-off-by: Matthias Beyer --- middle/src/opt/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/middle/src/opt/mod.rs b/middle/src/opt/mod.rs index 22dce4f..a5f9f53 100644 --- a/middle/src/opt/mod.rs +++ b/middle/src/opt/mod.rs @@ -389,16 +389,15 @@ pub fn check(ctx: &Context) { ctx: &Context, binding: &Binding, repr: &Repr, - stack: &mut Vec<(Local, 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) + check_binding(ctx, inner, &variants[*idx]) } - (Pat::Single(inner), _) => check_binding(ctx, inner, repr, stack), + (Pat::Single(inner), _) => check_binding(ctx, inner, repr), (Pat::ListExact(_), Repr::List(_)) => {} (Pat::ListFront(_, _), Repr::List(_)) => {} (_, repr) => panic!( @@ -407,7 +406,7 @@ pub fn check(ctx: &Context) { ), } - binding.for_children(|binding| check_binding(ctx, binding, binding.meta(), stack)); + binding.for_children(|binding| check_binding(ctx, binding, binding.meta())); } fn check_expr(ctx: &Context, expr: &Expr, repr: &Repr, stack: &mut Vec<(Local, Repr)>) { @@ -450,7 +449,7 @@ pub fn check(ctx: &Context) { (Expr::Match(pred, arms), _repr) => { for (arm, body) in arms { // TODO: visit binding - check_binding(ctx, arm.inner(), pred.meta(), stack); + check_binding(ctx, arm.inner(), pred.meta()); let old_stack = stack.len(); stack.append(&mut arm.bindings()); check_expr(ctx, body, body.meta(), stack); From ff2f40864634d07f4a343f9898cad1efc82d0cd5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:02:43 +0100 Subject: [PATCH 048/106] Fix clippy: Remove unused function param Signed-off-by: Matthias Beyer --- middle/src/opt/mod.rs | 9 ++++----- 1 file changed, 4 insertions(+), 5 deletions(-) diff --git a/middle/src/opt/mod.rs b/middle/src/opt/mod.rs index a5f9f53..32f8326 100644 --- a/middle/src/opt/mod.rs +++ b/middle/src/opt/mod.rs @@ -386,7 +386,6 @@ 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, ) { @@ -395,9 +394,9 @@ pub fn check(ctx: &Context) { (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]) + check_binding(inner, &variants[*idx]) } - (Pat::Single(inner), _) => check_binding(ctx, inner, repr), + (Pat::Single(inner), _) => check_binding(inner, repr), (Pat::ListExact(_), Repr::List(_)) => {} (Pat::ListFront(_, _), Repr::List(_)) => {} (_, repr) => panic!( @@ -406,7 +405,7 @@ pub fn check(ctx: &Context) { ), } - binding.for_children(|binding| check_binding(ctx, binding, binding.meta())); + binding.for_children(|binding| check_binding(binding, binding.meta())); } fn check_expr(ctx: &Context, expr: &Expr, repr: &Repr, stack: &mut Vec<(Local, Repr)>) { @@ -449,7 +448,7 @@ pub fn check(ctx: &Context) { (Expr::Match(pred, arms), _repr) => { for (arm, body) in arms { // TODO: visit binding - check_binding(ctx, arm.inner(), pred.meta()); + check_binding(arm.inner(), pred.meta()); let old_stack = stack.len(); stack.append(&mut arm.bindings()); check_expr(ctx, body, body.meta(), stack); From 62029da33deeb0f2c9334c56210e98b12dfd51bf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:04:01 +0100 Subject: [PATCH 049/106] Fix clippy: Remove unnecessary closure Signed-off-by: Matthias Beyer --- middle/src/opt/mod.rs | 28 ++++++++++++++-------------- 1 file changed, 14 insertions(+), 14 deletions(-) diff --git a/middle/src/opt/mod.rs b/middle/src/opt/mod.rs index 32f8326..c6338f1 100644 --- a/middle/src/opt/mod.rs +++ b/middle/src/opt/mod.rs @@ -115,11 +115,11 @@ impl Binding { 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), @@ -131,11 +131,11 @@ impl Binding { 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), @@ -187,9 +187,9 @@ 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::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 { @@ -229,9 +229,9 @@ impl Expr { 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::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 { From efeec63d6d9a1def67d32eff9b19befd3677750c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:04:45 +0100 Subject: [PATCH 050/106] Fix clippy: mask unused function parameter We cannot remove it because the trait requires it and we don't want to do refactoring here, so we just mask it for now. Signed-off-by: Matthias Beyer --- middle/src/opt/remove_unused_bindings.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/middle/src/opt/remove_unused_bindings.rs b/middle/src/opt/remove_unused_bindings.rs index 4bcb106..4e40433 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -11,7 +11,7 @@ impl Pass for RemoveUnusedBindings { mir: &Context, expr: &mut Expr, stack: &mut Vec<(Local, u64)>, - proc_stack: &mut Vec, + _proc_stack: &mut Vec, ) { match expr { Expr::Local(local) => { @@ -23,7 +23,7 @@ impl Pass for RemoveUnusedBindings { } } 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() { @@ -37,7 +37,7 @@ impl Pass for RemoveUnusedBindings { let old_stack = stack.len(); stack.extend(arm.binding_names().into_iter().map(|name| (name, 0))); - visit(mir, body, stack, proc_stack); + visit(mir, body, stack, _proc_stack); fn remove_unused(binding: &mut Binding, stack: &mut Vec<(Local, u64)>) { if let Some(name) = binding.name { @@ -73,7 +73,7 @@ impl Pass for RemoveUnusedBindings { }); // 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() { @@ -95,17 +95,17 @@ impl Pass for RemoveUnusedBindings { } 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); + visit(mir, expr, stack, _proc_stack); for Handler { eff: _, send, @@ -116,11 +116,11 @@ impl Pass for RemoveUnusedBindings { 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)), } } From 273f0fcfd9bc97878e23838704361e19685ae699 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:04:45 +0100 Subject: [PATCH 051/106] Fix clippy: mask unused function parameter We cannot remove it because the trait requires it and we don't want to do refactoring here, so we just mask it for now. Signed-off-by: Matthias Beyer --- middle/src/opt/remove_unused_bindings.rs | 20 ++++++++++---------- 1 file changed, 10 insertions(+), 10 deletions(-) diff --git a/middle/src/opt/remove_unused_bindings.rs b/middle/src/opt/remove_unused_bindings.rs index 4e40433..bf5a57b 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -8,7 +8,7 @@ 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, @@ -23,7 +23,7 @@ impl Pass for RemoveUnusedBindings { } } 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() { @@ -37,7 +37,7 @@ impl Pass for RemoveUnusedBindings { let old_stack = stack.len(); stack.extend(arm.binding_names().into_iter().map(|name| (name, 0))); - visit(mir, body, stack, _proc_stack); + visit(_mir, body, stack, _proc_stack); fn remove_unused(binding: &mut Binding, stack: &mut Vec<(Local, u64)>) { if let Some(name) = binding.name { @@ -73,7 +73,7 @@ impl Pass for RemoveUnusedBindings { }); // 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() { @@ -95,17 +95,17 @@ impl Pass for RemoveUnusedBindings { } 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); + visit(_mir, expr, stack, _proc_stack); for Handler { eff: _, send, @@ -116,11 +116,11 @@ impl Pass for RemoveUnusedBindings { 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)), } } From d64fc63315ee1dc6a4ea18b023a2eba08e8caf66 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:06:13 +0100 Subject: [PATCH 052/106] Fix clippy: Remove unnecessary reference Signed-off-by: Matthias Beyer --- middle/src/opt/const_fold.rs | 2 +- middle/src/opt/remove_unused_bindings.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index 2c8ffa9..f265bb7 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -376,7 +376,7 @@ impl Pass for ConstFold { 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(), diff --git a/middle/src/opt/remove_unused_bindings.rs b/middle/src/opt/remove_unused_bindings.rs index bf5a57b..759d1c0 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -132,7 +132,7 @@ impl Pass for RemoveUnusedBindings { 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(), From 4ff0fd782f907269fad05d001fa3a5a081903cc4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:07:12 +0100 Subject: [PATCH 053/106] Fix clippy: Replace map with if-let Strange that clippy suggests this, but it looks nicer and is easier to understand. Signed-off-by: Matthias Beyer --- middle/src/opt/remove_unused_bindings.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/middle/src/opt/remove_unused_bindings.rs b/middle/src/opt/remove_unused_bindings.rs index 759d1c0..4960fc2 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -60,7 +60,9 @@ impl Pass for RemoveUnusedBindings { } Pat::ListFront(items, tail) => { items.iter_mut().for_each(|item| remove_unused(item, stack)); - tail.as_mut().map(|tail| remove_unused(tail, 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), From e5e1bb866eb83e25d549a510d94732ce680a766d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:08:00 +0100 Subject: [PATCH 054/106] Fix clippy: Use any() instead of iter()...is_some() Signed-off-by: Matthias Beyer --- middle/src/opt/const_fold.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index f265bb7..9c48260 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -117,7 +117,7 @@ impl ConstFold { { // 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() => + if locals.iter().any(|(name, _)| *name == local) => { *expr = Expr::Local(local); return Partial::Unknown(Some(local)); @@ -277,7 +277,7 @@ impl ConstFold { // directly. Partial::Unknown(local) if local.map_or(false, |local| { - locals.iter().find(|(l, _)| *l == local).is_some() + locals.iter().any(|(l, _)| *l == local) }) => { if !expr.may_have_effect() { From 54a5c3eb21bb2d6daa4b65a304aa1da07a13c30c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:11:53 +0100 Subject: [PATCH 055/106] Fix clippy: Collapse if Signed-off-by: Matthias Beyer --- middle/src/opt/remove_unused_bindings.rs | 11 +++++------ 1 file changed, 5 insertions(+), 6 deletions(-) diff --git a/middle/src/opt/remove_unused_bindings.rs b/middle/src/opt/remove_unused_bindings.rs index 4960fc2..cc373e3 100644 --- a/middle/src/opt/remove_unused_bindings.rs +++ b/middle/src/opt/remove_unused_bindings.rs @@ -85,14 +85,13 @@ impl Pass for RemoveUnusedBindings { } else if arms .get(0) .map_or(false, |(b, _)| matches!(&b.pat, Pat::Wildcard)) + && !pred.may_have_effect() { - 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(); + 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) => { From 20e4db1d7ea41c0522af0829384cbbbb8cc13242 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:12:18 +0100 Subject: [PATCH 056/106] Fix clippy: Remove unnecessary binding Signed-off-by: Matthias Beyer --- middle/src/opt/const_fold.rs | 6 ++---- 1 file changed, 2 insertions(+), 4 deletions(-) diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index 9c48260..aafc24e 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -272,7 +272,7 @@ impl ConstFold { 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) @@ -294,9 +294,7 @@ impl ConstFold { } partial } - }; - - partial + } } } From c81a5f599b8af7defdf0938d31809a6ffad074e0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:14:23 +0100 Subject: [PATCH 057/106] Fix clippy: Remove param that's only used in recursion Signed-off-by: Matthias Beyer --- middle/src/opt/const_fold.rs | 21 ++++++++++----------- 1 file changed, 10 insertions(+), 11 deletions(-) diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index aafc24e..90c5bb2 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -12,7 +12,6 @@ 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, @@ -30,7 +29,7 @@ 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 { @@ -43,10 +42,10 @@ impl ConstFold { true } } - (Pat::Single(inner), partial) => self.extract(ctx, inner, partial, locals), + (Pat::Single(inner), partial) => ConstFold::extract(ctx, inner, partial, locals), (Pat::Variant(variant, x), Partial::Sum(tag, y)) => { if variant == tag { - self.extract(ctx, x, y, locals) + ConstFold::extract(ctx, x, y, locals) } else { false } @@ -55,7 +54,7 @@ impl ConstFold { debug_assert_eq!(xs.len(), ys.len()); xs.iter_mut() .zip(ys.iter()) - .all(|(x, y)| self.extract(ctx, x, y, locals)) + .all(|(x, y)| ConstFold::extract(ctx, x, y, locals)) } (Pat::ListExact(xs), Partial::List(ys)) => { if xs.len() != ys.len() { @@ -63,7 +62,7 @@ impl ConstFold { } else { xs.iter_mut() .zip(ys.iter()) - .all(|(x, y)| self.extract(ctx, x, y, locals)) + .all(|(x, y)| ConstFold::extract(ctx, x, y, locals)) } } (Pat::ListFront(xs, tail), Partial::List(ys)) => { @@ -71,7 +70,7 @@ impl ConstFold { false } else { let could_match_tail = if let Some(tail) = tail { - self.extract(ctx, tail, &Partial::List(ys[xs.len()..].to_vec()), locals) + ConstFold::extract(ctx, tail, &Partial::List(ys[xs.len()..].to_vec()), locals) } else { true }; @@ -79,14 +78,14 @@ impl ConstFold { && xs .iter_mut() .zip(ys.iter()) - .all(|(x, y)| self.extract(ctx, x, y, locals)) + .all(|(x, y)| ConstFold::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) + ConstFold::extract(ctx, inner, &Partial::Nat(rhs - *n), locals) } else { false } @@ -96,7 +95,7 @@ impl ConstFold { } (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), } @@ -141,7 +140,7 @@ 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 From c58e0e5ec97b598d53f99ce2c932f9bfe88ebdc3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:15:22 +0100 Subject: [PATCH 058/106] Fix clippy: Replace map with if-let Signed-off-by: Matthias Beyer --- middle/src/mir.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/middle/src/mir.rs b/middle/src/mir.rs index 3a9069c..74a9585 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -271,7 +271,9 @@ impl Binding { 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)); + 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), From c304a2e98ec435f9e81add3e8278782624874c1e Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:16:45 +0100 Subject: [PATCH 059/106] Fix clippy: Replace len() == 0 with is_empty() Signed-off-by: Matthias Beyer --- middle/src/mir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middle/src/mir.rs b/middle/src/mir.rs index 74a9585..f67543e 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -828,7 +828,7 @@ impl Expr { DisplayExpr(body, self.1 + 1, false) )?; } - if arms.len() == 0 { + if arms.is_empty() { write!(f, " (no arms)")?; } Ok(()) From 69b2e5442720d881bfdf528122378d72070cc05f Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:17:35 +0100 Subject: [PATCH 060/106] Fix clippy: Replace map with if-let Signed-off-by: Matthias Beyer --- middle/src/mir.rs | 4 +++- 1 file changed, 3 insertions(+), 1 deletion(-) diff --git a/middle/src/mir.rs b/middle/src/mir.rs index f67543e..1beffaa 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -261,7 +261,9 @@ impl Binding { } fn visit_bindings(self: &MirNode, bind: &mut impl FnMut(Local, &Repr)) { - self.name.map(|name| bind(name, self.meta())); + if let Some(name) = self.name { + bind(name, self.meta()); + } match &self.pat { Pat::Wildcard => {} Pat::Literal(_) => {} From e2346915ea19854fcdde24aa698935e034f7ef27 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:18:00 +0100 Subject: [PATCH 061/106] Fix clippy: Replace len() > 0 with ! is_empty() Signed-off-by: Matthias Beyer --- middle/src/mir.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middle/src/mir.rs b/middle/src/mir.rs index 1beffaa..c1b2d84 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -253,7 +253,7 @@ impl Binding { 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()) + !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(), From 564742e66bffab280b7be3c67336730151981ec9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:21:42 +0100 Subject: [PATCH 062/106] Fix clippy: Replace manual matches!() with macro Signed-off-by: Matthias Beyer --- middle/src/mir.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/middle/src/mir.rs b/middle/src/mir.rs index c1b2d84..894a549 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -244,10 +244,7 @@ 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()), From 79fcbad06617f3723e77e551fa61b0c663d60c80 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:23:32 +0100 Subject: [PATCH 063/106] Fix clippy: Replace constructor without params with Default impl Signed-off-by: Matthias Beyer --- middle/src/lower.rs | 10 +++++----- middle/src/mir.rs | 14 +++++++------- 2 files changed, 12 insertions(+), 12 deletions(-) diff --git a/middle/src/lower.rs b/middle/src/lower.rs index cdb0444..f868405 100644 --- a/middle/src/lower.rs +++ b/middle/src/lower.rs @@ -152,7 +152,7 @@ impl Context { 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 { @@ -219,7 +219,7 @@ impl Context { 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(); @@ -381,7 +381,7 @@ impl Context { ], ), 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() { @@ -539,8 +539,8 @@ impl Context { state, recv, }| { - let send_local = Local::new(); - let state_local = Local::new(); + let send_local = Local::default(); + let state_local = Local::default(); is_state = state.is_some(); mir::Handler { eff: *eff, diff --git a/middle/src/mir.rs b/middle/src/mir.rs index 894a549..0e0194a 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -219,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)) @@ -426,7 +426,7 @@ impl Expr { 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); @@ -434,7 +434,7 @@ impl Expr { } } 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(); @@ -443,7 +443,7 @@ impl Expr { 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(); @@ -459,8 +459,8 @@ impl Expr { recv, } in handlers { - let new_send = Local::new(); - let new_state = Local::new(); + 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)); From 68bb4d1201176e3d18ec593900c1c275bdb2efb7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:23:54 +0100 Subject: [PATCH 064/106] Fix clippy: Remove unnecessary clone() Signed-off-by: Matthias Beyer --- middle/src/lower.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/middle/src/lower.rs b/middle/src/lower.rs index f868405..b9e1184 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) { @@ -620,7 +620,7 @@ impl Context { } else { unreachable!() }, - default_state_repr.clone(), + default_state_repr, ]), ), 1, From 32b86537f0e2813f882c556b39e3bc9a4644fb21 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:26:39 +0100 Subject: [PATCH 065/106] Fix clippy: Replace format!() with to_string() Signed-off-by: Matthias Beyer --- middle/src/error.rs | 18 +++++++++--------- 1 file changed, 9 insertions(+), 9 deletions(-) diff --git a/middle/src/error.rs b/middle/src/error.rs index 4eebcb6..2561654 100644 --- a/middle/src/error.rs +++ b/middle/src/error.rs @@ -14,10 +14,10 @@ impl Error { let (msg, spans, notes) = match self { Error::NoEntryPoint(root_span) => ( - format!("No main definition"), + "No main definition".to_string(), vec![( root_span, - format!("Does not contain a definition marked as the main entry point"), + "Does not contain a definition marked as the main entry point".to_string(), Color::Red, )], vec![format!( @@ -26,24 +26,24 @@ impl Error { )], ), 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), + (gen, "Generics are not allowed here".to_string(), Color::Red), ( entry, - format!("Declared as an entry point because of this attribute"), + "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()], ), }; From 36cab3599f7d9fc8f7e281bc5bf0f975dbb572e9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:28:46 +0100 Subject: [PATCH 066/106] Fix clippy: Remove unreachable patterns Signed-off-by: Matthias Beyer --- middle/src/lower.rs | 1 - middle/src/mir.rs | 1 - middle/src/opt/const_fold.rs | 2 -- middle/src/opt/mod.rs | 1 - 4 files changed, 5 deletions(-) diff --git a/middle/src/lower.rs b/middle/src/lower.rs index b9e1184..1200a71 100644 --- a/middle/src/lower.rs +++ b/middle/src/lower.rs @@ -146,7 +146,6 @@ impl Context { fields.sort_by_key(|(name, _)| name.as_ref()); mir::Pat::Tuple(fields.into_iter().map(|(_, field)| field).collect()) } - pat => todo!("{:?}", pat), }; let binding = mir::Binding { diff --git a/middle/src/mir.rs b/middle/src/mir.rs index 0e0194a..46d0f91 100644 --- a/middle/src/mir.rs +++ b/middle/src/mir.rs @@ -636,7 +636,6 @@ impl Expr { Pat::Data(data, inner) => { write!(f, "{:?} {}", data, DisplayBinding(inner, self.1)) } - pat => todo!("{:?}", pat), } } } diff --git a/middle/src/opt/const_fold.rs b/middle/src/opt/const_fold.rs index 90c5bb2..ab39a94 100644 --- a/middle/src/opt/const_fold.rs +++ b/middle/src/opt/const_fold.rs @@ -268,7 +268,6 @@ impl ConstFold { Partial::Unknown(None) } - e => todo!("{:?}", e), }; match partial { @@ -339,7 +338,6 @@ 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())) } diff --git a/middle/src/opt/mod.rs b/middle/src/opt/mod.rs index c6338f1..2f64b68 100644 --- a/middle/src/opt/mod.rs +++ b/middle/src/opt/mod.rs @@ -462,7 +462,6 @@ pub fn check(ctx: &Context) { (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::Basin(_, inner), Repr::Effect(_, o)) => { From d1272d6994614ebf1c9d4b337c4f0e4f3e7ac3a4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:29:15 +0100 Subject: [PATCH 067/106] Fix clippy: Remove feature gate that has been stabelized Signed-off-by: Matthias Beyer --- middle/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/middle/src/lib.rs b/middle/src/lib.rs index 8788c4a..774c4ff 100644 --- a/middle/src/lib.rs +++ b/middle/src/lib.rs @@ -1,4 +1,4 @@ -#![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; From 2e2ec7c7e1f17bd291197a687dfb41e4c48843a3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:29:34 +0100 Subject: [PATCH 068/106] Fix clippy: Remove unnecessary clone() calls Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 908845a..a64e8e2 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -127,7 +127,6 @@ impl AbstractPat { } } covered - .clone() .invert() .into_iter() .next() @@ -144,7 +143,6 @@ impl AbstractPat { } } covered - .clone() .invert() .into_iter() .next() From 1026b30f6a52768280247c3dee5a985d241418cf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:29:58 +0100 Subject: [PATCH 069/106] Fix clippy: Remove lifetimes taht are infered Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index a64e8e2..7cc5710 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -102,10 +102,10 @@ impl AbstractPat { 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) { From f9426613db0c49d9d7ecb623a547298aa5304e7c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:30:43 +0100 Subject: [PATCH 070/106] Fix clippy: Remove fn param that is only used in recursion Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 16 ++++++++-------- 1 file changed, 8 insertions(+), 8 deletions(-) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 7cc5710..18512c4 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -18,7 +18,7 @@ pub enum AbstractPat { } 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, @@ -36,7 +36,7 @@ impl AbstractPat { 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::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..); @@ -45,29 +45,29 @@ impl AbstractPat { hir::Pat::Decons(data, cons, inner) => AbstractPat::Variant( **data, *cons, - Box::new(AbstractPat::from_binding(ctx, inner)), + Box::new(AbstractPat::from_binding(inner)), ), hir::Pat::ListExact(items) => AbstractPat::ListExact( items .iter() - .map(|item| AbstractPat::from_binding(ctx, item)) + .map(|item| AbstractPat::from_binding(item)) .collect(), ), hir::Pat::ListFront(items, tail) => AbstractPat::ListFront( items .iter() - .map(|item| AbstractPat::from_binding(ctx, item)) + .map(|item| AbstractPat::from_binding(item)) .collect(), Box::new( tail.as_ref() - .map(|tail| AbstractPat::from_binding(ctx, tail)) + .map(|tail| AbstractPat::from_binding(tail)) .unwrap_or(AbstractPat::Wildcard), ), ), hir::Pat::Record(fields, is_tuple) => AbstractPat::Record( fields .iter() - .map(|(name, field)| (*name, AbstractPat::from_binding(ctx, field))) + .map(|(name, field)| (*name, AbstractPat::from_binding(field))) .collect(), *is_tuple, ), @@ -473,7 +473,7 @@ pub fn exhaustivity<'a>( ) -> Result<(), ExamplePat> { let arms = arms .into_iter() - .map(|b| AbstractPat::from_binding(ctx, b)) + .map(|b| AbstractPat::from_binding(b)) .collect::>(); if let Some(pat) = AbstractPat::inexhaustive_pat(ctx, ty, &mut arms.iter(), None) { From 4b64825873c55a7ece92b91f3dca789d4890ee65 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:31:43 +0100 Subject: [PATCH 071/106] Fix clippy: Remove unnecessary closure Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 8 ++++---- 1 file changed, 4 insertions(+), 4 deletions(-) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 18512c4..340fb61 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -50,17 +50,17 @@ impl AbstractPat { hir::Pat::ListExact(items) => AbstractPat::ListExact( items .iter() - .map(|item| AbstractPat::from_binding(item)) + .map(AbstractPat::from_binding) .collect(), ), hir::Pat::ListFront(items, tail) => AbstractPat::ListFront( items .iter() - .map(|item| AbstractPat::from_binding(item)) + .map(AbstractPat::from_binding) .collect(), Box::new( tail.as_ref() - .map(|tail| AbstractPat::from_binding(tail)) + .map(AbstractPat::from_binding) .unwrap_or(AbstractPat::Wildcard), ), ), @@ -473,7 +473,7 @@ pub fn exhaustivity<'a>( ) -> Result<(), ExamplePat> { let arms = arms .into_iter() - .map(|b| AbstractPat::from_binding(b)) + .map(AbstractPat::from_binding) .collect::>(); if let Some(pat) = AbstractPat::inexhaustive_pat(ctx, ty, &mut arms.iter(), None) { From ebe3a844d8ce2e415d61620442a7ace42985c864 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:38:36 +0100 Subject: [PATCH 072/106] Fix clippy: Replace format!() with to_string() Signed-off-by: Matthias Beyer --- analysis/src/error.rs | 148 +++++++++++++++++++++--------------------- 1 file changed, 74 insertions(+), 74 deletions(-) diff --git a/analysis/src/error.rs b/analysis/src/error.rs index 456f873..adb7948 100644 --- a/analysis/src/error.rs +++ b/analysis/src/error.rs @@ -73,7 +73,7 @@ impl Error { if let Some(eff) = id { ctx.tys.display_eff(ctx, eff).to_string() } else { - format!("!") + "!".to_string() } }; @@ -105,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 }, @@ -120,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))], @@ -143,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)), ], ), @@ -156,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)), ], ) @@ -168,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![], ), @@ -176,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), @@ -194,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), @@ -223,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) => ( @@ -233,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)), @@ -274,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(); @@ -294,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![], @@ -311,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![], @@ -320,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![], @@ -329,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![], ), @@ -363,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) => ( @@ -375,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), @@ -396,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 {}", @@ -408,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() @@ -453,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()], ), }; From 37ff79d7721eb88bd27e723729b889db30c51afe Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:39:13 +0100 Subject: [PATCH 073/106] Fix clippy: Remove unnecesary binding Signed-off-by: Matthias Beyer --- analysis/src/effect.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/analysis/src/effect.rs b/analysis/src/effect.rs index 4eb413a..2927e13 100644 --- a/analysis/src/effect.rs +++ b/analysis/src/effect.rs @@ -106,11 +106,7 @@ impl Effects { } pub fn check_lang_items(&self) -> Vec { - let 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) { From 11e4626344394fd968a92e38e6e0e2602fd156e8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:39:13 +0100 Subject: [PATCH 074/106] Fix clippy: Remove unnecesary binding Signed-off-by: Matthias Beyer --- analysis/src/def.rs | 6 +----- 1 file changed, 1 insertion(+), 5 deletions(-) diff --git a/analysis/src/def.rs b/analysis/src/def.rs index 87beb28..7399463 100644 --- a/analysis/src/def.rs +++ b/analysis/src/def.rs @@ -69,11 +69,7 @@ impl Defs { } pub fn check_lang_items(&self) -> Vec { - let 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) { From 7586ddf6b580df73c62db50766a82b297508a212 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:40:28 +0100 Subject: [PATCH 075/106] Fix clippy: Replace find().is_{some,none}() with any() Signed-off-by: Matthias Beyer --- analysis/src/context.rs | 4 ++-- analysis/src/data.rs | 4 ++-- analysis/src/debug.rs | 6 +++--- 3 files changed, 7 insertions(+), 7 deletions(-) diff --git a/analysis/src/context.rs b/analysis/src/context.rs index 56383ed..2a41dc3 100644 --- a/analysis/src/context.rs +++ b/analysis/src/context.rs @@ -807,7 +807,7 @@ 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 @@ -962,7 +962,7 @@ impl Context { 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 diff --git a/analysis/src/data.rs b/analysis/src/data.rs index 0898691..725d150 100644 --- a/analysis/src/data.rs +++ b/analysis/src/data.rs @@ -123,10 +123,10 @@ impl Datas { .find(|a| &**a.name == "lang") .and_then(|a| a.args.as_ref()) { - if lang.iter().find(|a| &**a.name == "go").is_some() { + if lang.iter().any(|a| &**a.name == "go") { self.lang.go = Some(id); } - if lang.iter().find(|a| &**a.name == "bool").is_some() { + if lang.iter().any(|a| &**a.name == "bool") { self.lang.r#bool = Some(id); } } diff --git a/analysis/src/debug.rs b/analysis/src/debug.rs index fefdf3e..224e18a 100644 --- a/analysis/src/debug.rs +++ b/analysis/src/debug.rs @@ -41,7 +41,7 @@ impl<'hir, 'a> dot::GraphWalk<'a, Node, Edge> for CallGraph<'hir> { .defs .iter() .filter_map(|(id, def)| { - if def.attr.iter().find(|a| &**a.name == "util").is_none() { + if !def.attr.iter().any(|a| &**a.name == "util") { Some((id, *def.name)) } else { None @@ -53,7 +53,7 @@ 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() { + if !def.attr.iter().any(|a| &**a.name == "util") { edges.insert((parent, (global.0, *def.name))); } } @@ -63,7 +63,7 @@ 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); } From c5e11928d5ca6dbc57536fe34e45da687820d4b2 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:42:18 +0100 Subject: [PATCH 076/106] Fix clippy: Replace len() == 0 with is_empty() Signed-off-by: Matthias Beyer --- analysis/src/data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/data.rs b/analysis/src/data.rs index 725d150..aec8893 100644 --- a/analysis/src/data.rs +++ b/analysis/src/data.rs @@ -176,7 +176,7 @@ impl Datas { } } self.datas[id.0].1 = Some(data); - if errors.len() == 0 { + if errors.is_empty() { Ok(()) } else { Err(errors) From fdb78a5fccd4c1e80c921a9fb2dc5beaabe9d90d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:42:39 +0100 Subject: [PATCH 077/106] Fix clippy: Remove unnecessary closure Signed-off-by: Matthias Beyer --- analysis/src/data.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/data.rs b/analysis/src/data.rs index aec8893..c1206ad 100644 --- a/analysis/src/data.rs +++ b/analysis/src/data.rs @@ -49,7 +49,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 { From c4f710c440f278ed304382fef9507939f0e877e9 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:42:58 +0100 Subject: [PATCH 078/106] Fix clippy: Remove unnecessary reference Signed-off-by: Matthias Beyer --- analysis/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/context.rs b/analysis/src/context.rs index 2a41dc3..21f9c71 100644 --- a/analysis/src/context.rs +++ b/analysis/src/context.rs @@ -175,7 +175,7 @@ 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); From a7b64440bc2d2b13d9d3b71b8b569d1153cc8493 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:43:15 +0100 Subject: [PATCH 079/106] Fix clippy: Replace format!() with to_string() Signed-off-by: Matthias Beyer --- analysis/src/context.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/context.rs b/analysis/src/context.rs index 21f9c71..f795dd1 100644 --- a/analysis/src/context.rs +++ b/analysis/src/context.rs @@ -903,7 +903,7 @@ impl Context { val_ty, EqInfo::new( name.span(), - format!("Type of member item must match class"), + "Type of member item must match class".to_string(), ), ); } From 374b239a95e3f0f4624ba520b62f8a37f762ac0a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:44:28 +0100 Subject: [PATCH 080/106] Fix clippy: Remove unnecessary call to Result::ok() Signed-off-by: Matthias Beyer --- analysis/src/concrete.rs | 2 -- 1 file changed, 2 deletions(-) diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index a247b07..3f3a348 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -871,7 +871,6 @@ impl ConContext { .expect("Error effect instance should not exist during concretization"), ty_insts, ) - .ok() .expect("Generic effect used in suspend?!"), self.lower_expr(hir, inner, ty_insts), ), @@ -887,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))), From 57dd433ff57356aab99ed8f476b76af08aef87ab Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:44:52 +0100 Subject: [PATCH 081/106] Fix clippy: Replace into_iter() with iter() Signed-off-by: Matthias Beyer --- analysis/src/concrete.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index 3f3a348..7b829e7 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -247,7 +247,7 @@ impl ConContext { } (Ty::Record(xs, _), ConTy::Record(ys)) => { xs.into_iter() - .zip(ys.into_iter()) + .zip(ys.iter()) .for_each(|((_, x), (_, y))| { self.derive_links(hir, x, *y, ty_link_gen, eff_link_gen) }) @@ -838,7 +838,7 @@ impl ConContext { } else { hir::Expr::Intrinsic( name.clone(), - args.into_iter() + args.iter() .map(|arg| self.lower_expr(hir, arg, ty_insts)) .collect(), ) From 539ab5697d069468491d8a46fd68513fda536bdf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:45:23 +0100 Subject: [PATCH 082/106] Fix clippy: Replace len() > 0 with ! is_empty() Signed-off-by: Matthias Beyer --- analysis/src/concrete.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index 7b829e7..e5bab68 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -1015,7 +1015,7 @@ impl<'a> fmt::Display for ConTyDisplay<'a> { 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!( + 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, From f2f82069ec655c3d3f2ac2ab7834a55c6c0e9ddb Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:47:10 +0100 Subject: [PATCH 083/106] Fix clippy: Remove unnecessary clone() Signed-off-by: Matthias Beyer --- analysis/src/concrete.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index e5bab68..2c510cb 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -201,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 { @@ -713,7 +713,7 @@ impl ConContext { .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) } From 430e975905802bcb168088a41f729d3a100dd62c Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:47:47 +0100 Subject: [PATCH 084/106] Fix clippy: Replace len() == 0 with is_empty() Signed-off-by: Matthias Beyer --- analysis/src/class.rs | 2 +- analysis/src/concrete.rs | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) diff --git a/analysis/src/class.rs b/analysis/src/class.rs index 8021475..5f18dde 100644 --- a/analysis/src/class.rs +++ b/analysis/src/class.rs @@ -349,7 +349,7 @@ impl Classes { let gen_scope = hir.tys.get_gen_scope(c.gen_scope); format!( "- {}member {} of {}{} (in {})\n", - if gen_scope.len() == 0 { + if gen_scope.is_empty() { String::new() } else { format!( diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index 2c510cb..e6acd03 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -183,7 +183,7 @@ impl ConContext { } 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); From 682f1e27e73b2925e3f7eb9ce02d1be1be0d2edc Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:49:13 +0100 Subject: [PATCH 085/106] Fix clippy: Replace into_iter() with iter() Signed-off-by: Matthias Beyer --- analysis/src/class.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/class.rs b/analysis/src/class.rs index 5f18dde..2dd6050 100644 --- a/analysis/src/class.rs +++ b/analysis/src/class.rs @@ -248,7 +248,7 @@ impl Classes { // TODO: Care about field names! (Ty::Record(xs, _), ConTy::Record(ys)) if xs.len() == ys.len() => xs .into_iter() - .zip(ys.into_iter()) + .zip(ys.iter()) .all(|((_, x), (_, y))| covers(hir, ctx, x, *y, gen_ty_links, gen_eff_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) From 722649c179d26d0e37accd0295af20d2e4c6518d Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:50:12 +0100 Subject: [PATCH 086/106] Fix clippy: Remove unused function param Signed-off-by: Matthias Beyer --- analysis/src/class.rs | 15 ++++++--------- 1 file changed, 6 insertions(+), 9 deletions(-) diff --git a/analysis/src/class.rs b/analysis/src/class.rs index 2dd6050..623564b 100644 --- a/analysis/src/class.rs +++ b/analysis/src/class.rs @@ -237,30 +237,29 @@ 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) + 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.iter()) - .all(|((_, x), (_, y))| covers(hir, ctx, x, *y, gen_ty_links, gen_eff_links)), + .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) + 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)), + .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) + covers(hir, ctx, member, *ty, gen_ty_links) } (Ty::Effect(_, _), ConTy::Effect(_, _)) => todo!(), (Ty::Error(_), _) => panic!("Error ty during monomorphisation"), @@ -308,7 +307,6 @@ impl Classes { 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( @@ -317,7 +315,6 @@ impl Classes { *member_gen_ty, *gen_ty, &mut gen_ty_links, - &mut gen_eff_links, ) }, ) && member.gen_effs.iter().zip(gen_effs.iter()).all( From 2084bcb4ae3883342030eac001c028ff2a16c3ce Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:51:17 +0100 Subject: [PATCH 087/106] Fix clippy: Replace find().is_some() with .any() Signed-off-by: Matthias Beyer --- analysis/src/class.rs | 22 +++++++++++----------- analysis/src/concrete.rs | 3 +-- 2 files changed, 12 insertions(+), 13 deletions(-) diff --git a/analysis/src/class.rs b/analysis/src/class.rs index 623564b..f1e7e52 100644 --- a/analysis/src/class.rs +++ b/analysis/src/class.rs @@ -104,37 +104,37 @@ impl Classes { .find(|a| &**a.name == "lang") .and_then(|a| a.args.as_ref()) { - if lang.iter().find(|a| &**a.name == "not").is_some() { + if lang.iter().any(|a| &**a.name == "not") { self.lang.not = Some(id); } - if lang.iter().find(|a| &**a.name == "neg").is_some() { + if lang.iter().any(|a| &**a.name == "neg") { self.lang.neg = Some(id); } - if lang.iter().find(|a| &**a.name == "add").is_some() { + if lang.iter().any(|a| &**a.name == "add") { self.lang.add = Some(id); } - if lang.iter().find(|a| &**a.name == "sub").is_some() { + if lang.iter().any(|a| &**a.name == "sub") { self.lang.sub = Some(id); } - if lang.iter().find(|a| &**a.name == "mul").is_some() { + if lang.iter().any(|a| &**a.name == "mul") { self.lang.mul = Some(id); } - if lang.iter().find(|a| &**a.name == "div").is_some() { + if lang.iter().any(|a| &**a.name == "div") { self.lang.div = Some(id); } - if lang.iter().find(|a| &**a.name == "eq").is_some() { + if lang.iter().any(|a| &**a.name == "eq") { self.lang.eq = Some(id); } - if lang.iter().find(|a| &**a.name == "ord_ext").is_some() { + if lang.iter().any(|a| &**a.name == "ord_ext") { self.lang.ord_ext = Some(id); } - if lang.iter().find(|a| &**a.name == "and_").is_some() { + if lang.iter().any(|a| &**a.name == "and_") { self.lang.and = Some(id); } - if lang.iter().find(|a| &**a.name == "or_").is_some() { + if lang.iter().any(|a| &**a.name == "or_") { self.lang.or = Some(id); } - if lang.iter().find(|a| &**a.name == "join").is_some() { + if lang.iter().any(|a| &**a.name == "join") { self.lang.join = Some(id); } } diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index e6acd03..42074b2 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -155,8 +155,7 @@ impl ConContext { if def .attr .iter() - .find(|attr| attr.name.as_str() == "entry") - .is_some() + .any(|attr| attr.name.as_str() == "entry") { Some((id, def)) } else { From 84c1774dc248e920367301432d943b2726ce93f7 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:52:07 +0100 Subject: [PATCH 088/106] Fix clippy: Remove unused fn Scope::with() Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index d716df9..53ff528 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -31,10 +31,6 @@ impl<'a> Scope<'a> { Self::Empty } - fn with(&self, name: SrcNode, ty: TyVar) -> Scope<'_> { - Scope::Binding(self, name, ty) - } - fn with_many<'b>(&'b self, many: &'b [(SrcNode, TyVar)]) -> Scope<'b> { Scope::Many(self, many) } From ed5d48fb38948ac4a0e41c141330a7158e196cd8 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:52:21 +0100 Subject: [PATCH 089/106] Fix clippy: Remove unused fn Scope::without_basin() Signed-off-by: Matthias Beyer --- analysis/src/lower.rs | 3 --- 1 file changed, 3 deletions(-) diff --git a/analysis/src/lower.rs b/analysis/src/lower.rs index 53ff528..009f258 100644 --- a/analysis/src/lower.rs +++ b/analysis/src/lower.rs @@ -39,9 +39,6 @@ impl<'a> Scope<'a> { Scope::Basin(self, Some(eff)) } - fn without_basin(&self) -> Scope { - Scope::Basin(self, None) - } // bool = is_local fn find( From 60ef0e98f0c1a5da65be393870727ef83f728cb5 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:52:49 +0100 Subject: [PATCH 090/106] Fix clippy: Remove unused fn Infer::iter_effects() Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 4 ---- 1 file changed, 4 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index 428c117..a48529d 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1000,10 +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() } From 05ca3795df09bd85356370ae7495e5f86a0c0d20 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:53:17 +0100 Subject: [PATCH 091/106] Fix clippy: Remove unused member Datas::alias_lut Signed-off-by: Matthias Beyer --- analysis/src/data.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/analysis/src/data.rs b/analysis/src/data.rs index c1206ad..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, From b1c0fea819bb59e51c02f215385525e5cb280d47 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:54:13 +0100 Subject: [PATCH 092/106] Fix: Allow dead code here Not sure whether this is a bug, as all members of this type are unused. Signed-off-by: Matthias Beyer --- analysis/src/concrete.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/analysis/src/concrete.rs b/analysis/src/concrete.rs index 42074b2..4b92d4d 100644 --- a/analysis/src/concrete.rs +++ b/analysis/src/concrete.rs @@ -23,6 +23,7 @@ impl ConTyId { } #[derive(Debug)] +#[allow(dead_code)] pub struct ConEffect { send: ConTyId, recv: ConTyId, From 626281d2ef80e2b5352808c8862485a9d71b22dc Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:55:12 +0100 Subject: [PATCH 093/106] Fix clippy: Remove unreachable pattern Signed-off-by: Matthias Beyer --- analysis/src/infer.rs | 8 -------- 1 file changed, 8 deletions(-) diff --git a/analysis/src/infer.rs b/analysis/src/infer.rs index a48529d..89adc04 100644 --- a/analysis/src/infer.rs +++ b/analysis/src/infer.rs @@ -1563,14 +1563,6 @@ impl<'a> Infer<'a> { }, // 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(()) - }, (_, _) => Err((x, y)), } } From 47d248df703cb9b0e30c0f2da50079a2266489ce Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:55:12 +0100 Subject: [PATCH 094/106] Fix clippy: Remove unreachable pattern Signed-off-by: Matthias Beyer --- analysis/src/hir.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/analysis/src/hir.rs b/analysis/src/hir.rs index 0288d81..ee3a13c 100644 --- a/analysis/src/hir.rs +++ b/analysis/src/hir.rs @@ -309,7 +309,6 @@ impl Expr { } 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::Update(record, fields) => { record.required_locals_inner(stack, required); From 8a0fd25569d4609854d34bc7fb529f5e1bad1ccf Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:55:12 +0100 Subject: [PATCH 095/106] Fix clippy: Remove unreachable pattern Signed-off-by: Matthias Beyer --- analysis/src/exhaustivity.rs | 1 - 1 file changed, 1 deletion(-) diff --git a/analysis/src/exhaustivity.rs b/analysis/src/exhaustivity.rs index 340fb61..c80aec1 100644 --- a/analysis/src/exhaustivity.rs +++ b/analysis/src/exhaustivity.rs @@ -179,7 +179,6 @@ 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 { From 92f6e2f67cad68ce4bbd460ec2bedffbbe0c9744 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 10:29:15 +0100 Subject: [PATCH 096/106] Fix clippy: Remove feature gate that has been stabelized Signed-off-by: Matthias Beyer --- analysis/src/lib.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/analysis/src/lib.rs b/analysis/src/lib.rs index fecaf34..626f021 100644 --- a/analysis/src/lib.rs +++ b/analysis/src/lib.rs @@ -1,4 +1,4 @@ -#![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)] From 91bf3efb43879740fd3f41358de9fa8e84866458 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:09:10 +0100 Subject: [PATCH 097/106] Fix clippy: Remove unnecessary closure Signed-off-by: Matthias Beyer --- syntax/src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syntax/src/parse.rs b/syntax/src/parse.rs index 9df29c9..004879f 100644 --- a/syntax/src/parse.rs +++ b/syntax/src/parse.rs @@ -1086,7 +1086,7 @@ pub fn data_parser() -> impl Parser { )])) }) .unwrap_or_else(|ty| Some(vec![(name.clone(), ty)])) - .unwrap_or_else(|| Vec::new()), + .unwrap_or_else(Vec::new), name, }) .boxed() From 770a1f42cc85980588d573f56f1867a9d20f5c66 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:11:23 +0100 Subject: [PATCH 098/106] Fix clippy: Use unwrap_or_default() Signed-off-by: Matthias Beyer --- syntax/src/parse.rs | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/syntax/src/parse.rs b/syntax/src/parse.rs index 004879f..b34a243 100644 --- a/syntax/src/parse.rs +++ b/syntax/src/parse.rs @@ -527,7 +527,7 @@ pub fn expr_parser() -> impl Parser { |_| None, ) .map(|x| match x { - Some((items, tails)) => ast::Expr::List(items, tails.unwrap_or_else(Vec::new)), + Some((items, tails)) => ast::Expr::List(items, tails.unwrap_or_default()), None => ast::Expr::Error, }) .labelled("list"); @@ -1086,7 +1086,7 @@ pub fn data_parser() -> impl Parser { )])) }) .unwrap_or_else(|ty| Some(vec![(name.clone(), ty)])) - .unwrap_or_else(Vec::new), + .unwrap_or_default(), name, }) .boxed() From 7bad21b890bdb842cd5f42baeb371e356cd7bec0 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:12:37 +0100 Subject: [PATCH 099/106] Fix Clippy: Remove unnecessary closure Signed-off-by: Matthias Beyer --- syntax/src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syntax/src/parse.rs b/syntax/src/parse.rs index b34a243..4bc3935 100644 --- a/syntax/src/parse.rs +++ b/syntax/src/parse.rs @@ -710,7 +710,7 @@ pub fn expr_parser() -> impl Parser { .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 From 4014c39733867ad0c47c08cca8af9336a1bf1c29 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:13:38 +0100 Subject: [PATCH 100/106] Fix clippy: Remove unnecessary clone Signed-off-by: Matthias Beyer --- syntax/src/parse.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syntax/src/parse.rs b/syntax/src/parse.rs index 4bc3935..24e269d 100644 --- a/syntax/src/parse.rs +++ b/syntax/src/parse.rs @@ -225,7 +225,7 @@ 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()) + .then(just(Token::EndPipe).ignore_then(branch).or_not()) .try_map(|(mut init, end), span| { if let Some(end) = end { init.push(end); From 2ca961828afefa3b159ca95e2085db66a728de7a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:13:57 +0100 Subject: [PATCH 101/106] Fix clippy: Replace or_else() with or() Signed-off-by: Matthias Beyer --- syntax/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syntax/src/error.rs b/syntax/src/error.rs index 79e77a9..751dccb 100644 --- a/syntax/src/error.rs +++ b/syntax/src/error.rs @@ -29,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 } } From 6e28f6f2659def6158a28a09dfcb5b31346b660a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:14:22 +0100 Subject: [PATCH 102/106] Fix clippy: Replace format!() with to_string() Signed-off-by: Matthias Beyer --- syntax/src/error.rs | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/syntax/src/error.rs b/syntax/src/error.rs index 751dccb..47b79db 100644 --- a/syntax/src/error.rs +++ b/syntax/src/error.rs @@ -63,7 +63,7 @@ impl Error { 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::NoEndBranch => "No end branch".to_string(), }, if let Some(label) = self.label { format!(" while parsing {}", label.fg(Color::Cyan)) From 85317eec76307ad7abf9db1d1ef9af766bea50c4 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:15:01 +0100 Subject: [PATCH 103/106] Fix clippy: Replace manual matches!() with macro Signed-off-by: Matthias Beyer --- syntax/src/ast.rs | 5 +---- 1 file changed, 1 insertion(+), 4 deletions(-) diff --git a/syntax/src/ast.rs b/syntax/src/ast.rs index b43643c..143a07b 100644 --- a/syntax/src/ast.rs +++ b/syntax/src/ast.rs @@ -191,10 +191,7 @@ impl Type { } 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 } From 03514dfa49bad9e303a7f495bb91eb74f823c2c3 Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:17:34 +0100 Subject: [PATCH 104/106] Fix clippy: Rename Ident::as_ref() This function name could be confused because it is named like AsRef::as_ref(). Rename this function to Ident::as_string() because it actually does this. Signed-off-by: Matthias Beyer --- middle/src/lower.rs | 8 ++++---- syntax/src/ast.rs | 3 ++- 2 files changed, 6 insertions(+), 5 deletions(-) diff --git a/middle/src/lower.rs b/middle/src/lower.rs index 1200a71..32faa00 100644 --- a/middle/src/lower.rs +++ b/middle/src/lower.rs @@ -143,7 +143,7 @@ impl Context { .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()) } }; @@ -255,7 +255,7 @@ impl Context { .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.sort_by_key(|name| name.as_string()); fields .iter() .enumerate() @@ -288,7 +288,7 @@ impl Context { .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) => { @@ -469,7 +469,7 @@ impl Context { .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.sort_by_key(|name| name.as_string()); fields .iter() .enumerate() diff --git a/syntax/src/ast.rs b/syntax/src/ast.rs index 143a07b..af2b4be 100644 --- a/syntax/src/ast.rs +++ b/syntax/src/ast.rs @@ -21,7 +21,8 @@ impl Ident { pub fn new(s: S) -> Self { Self(Intern::new(s.to_string())) } - pub fn as_ref(self) -> &'static String { + + pub fn as_string(self) -> &'static String { self.0.as_ref() } } From b89ca84568d36c5d74904ff90a88c2e8dd283aee Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 09:39:24 +0100 Subject: [PATCH 105/106] Clippy: Allow type_complexity lint for now Allow this lint for now, so we can fix the simpler ones first and don't have to scroll in the clippy output all the time. This patch will be reverted as soon as possible. Signed-off-by: Matthias Beyer --- syntax/src/lib.rs | 2 ++ 1 file changed, 2 insertions(+) diff --git a/syntax/src/lib.rs b/syntax/src/lib.rs index 7e0191b..54a1b3c 100644 --- a/syntax/src/lib.rs +++ b/syntax/src/lib.rs @@ -1,5 +1,7 @@ #![feature(option_zip, trait_alias)] +#![allow(clippy::type_complexity)] + pub mod ast; pub mod error; pub mod node; From 09daafbdc09122bcbe64e9f3ec152bb46e90794a Mon Sep 17 00:00:00 2001 From: Matthias Beyer Date: Fri, 10 Mar 2023 11:19:44 +0100 Subject: [PATCH 106/106] Allow dead code for now This might be a bug, not sure what to do about it. Signed-off-by: Matthias Beyer --- cir/src/lib.rs | 1 + 1 file changed, 1 insertion(+) diff --git a/cir/src/lib.rs b/cir/src/lib.rs index 3dab3a0..b94f252 100644 --- a/cir/src/lib.rs +++ b/cir/src/lib.rs @@ -75,6 +75,7 @@ pub struct Func { } #[derive(Clone)] +#[allow(dead_code)] pub struct Program { datas: Index, funcs: Index,