Repository: HigherOrderCO/Bend
File: src/term/transform/flatten.rs (Rust)

Code before:
  //   (Foo.0 a     x P y0 y1) = F
  //   (Foo.0 (A k) x Q f0 f1) = G [y <- (C f0 f1)] // f0 and f1 are fresh
  let mut new_pats = Vec::new();
  let mut new_body = other_rule.body.clone();
  let mut var_count = 0;
  for (rule_arg, other_arg) in old_rule.pats.iter().zip(&other_rule.pats) {
    match (rule_arg, other_arg) {
      // We checked before that these two have the same constructor and match together
      (Pattern::Ctr(_, _), Pattern::Ctr(_, other_arg_args)) => {
        for other_field in other_arg_args {
          new_pats.push(other_field.clone());
        }
      }
      (Pattern::Ctr(rule_arg_name, rule_arg_args), Pattern::Var(Some(other_arg))) => {
        let mut new_ctr_args = vec![];
        for _ in 0 .. rule_arg_args.len() {
          let new_nam = make_var_name(&mut var_count);
          new_ctr_args.push(Term::Var { nam: new_nam.clone() });
          new_pats.push(Pattern::Var(Some(new_nam)));
        }
        let rule_arg_def_id = def_names.def_id(rule_arg_name).unwrap();
        let new_ctr = Term::call(Term::Ref { def_id: rule_arg_def_id }, new_ctr_args);
        new_body.subst(other_arg, &new_ctr);
      }
      (Pattern::Num(..), Pattern::Num(..)) => new_pats.push(other_arg.clone()),
      (Pattern::Num(..), _) => unreachable!(),
      (Pattern::Tup(_, _), Pattern::Tup(fst, snd)) => {
        new_pats.push(*fst.clone());
        new_pats.push(*snd.clone());
      }
      (Pattern::Tup(..), Pattern::Var(Some(other_arg))) => {
        let fst_nam = make_var_name(&mut var_count);
        let snd_nam = make_var_name(&mut var_count);
        let fst_arg = Term::Var { nam: fst_nam.clone() };
        let snd_arg = Term::Var { nam: snd_nam.clone() };
        new_pats.push(Pattern::Var(Some(fst_nam)));
        new_pats.push(Pattern::Var(Some(snd_nam)));
        let new_ctr = Term::Tup { fst: Box::new(fst_arg), snd: Box::new(snd_arg) };
        new_body.subst(other_arg, &new_ctr);
      }
      (Pattern::Var(..), _) => new_pats.push(other_arg.clone()),
      // Unreachable cases, we only call this function if we know the two patterns match together
      (
        Pattern::Ctr(..) | Pattern::Tup(..),
        Pattern::Ctr(..) | Pattern::Num(..) | Pattern::Tup(..),
      ) => {
        unreachable!()
      }
      (Pattern::Ctr(..), Pattern::Var(None)) => new_pats.push(Pattern::Var(None)),
      (Pattern::Tup(..), Pattern::Var(None)) => {
        new_pats.push(Pattern::Var(None));

Review comment (suggestion):
All `(Pattern::Num(..), _) => unreachable!(),` should be unreachable I think, because there can't be patterns nested in num (it's always final, a number). You can remove the line above.

Code after:
  //   (Foo.0 a     x P y0 y1) = F
  //   (Foo.0 (A k) x Q f0 f1) = G [y <- (C f0 f1)] // f0 and f1 are fresh
  let mut new_pats = Vec::new();
  let mut new_body = other_rule.body.clone();
  let mut var_count = 0;
  for (rule_arg, other_arg) in old_rule.pats.iter().zip(&other_rule.pats) {
    match (rule_arg, other_arg) {
      // We checked before that these two have the same constructor and match together
      (Pattern::Ctr(_, _), Pattern::Ctr(_, other_arg_args)) => {
        for other_field in other_arg_args {
          new_pats.push(other_field.clone());
        }
      }
      (Pattern::Ctr(rule_arg_name, rule_arg_args), Pattern::Var(Some(other_arg))) => {
        let mut new_ctr_args = vec![];
        for _ in 0 .. rule_arg_args.len() {
          let new_nam = make_var_name(&mut var_count);
          new_ctr_args.push(Term::Var { nam: new_nam.clone() });
          new_pats.push(Pattern::Var(Some(new_nam)));
        }
        let rule_arg_def_id = def_names.def_id(rule_arg_name).unwrap();
        let new_ctr = Term::call(Term::Ref { def_id: rule_arg_def_id }, new_ctr_args);
        new_body.subst(other_arg, &new_ctr);
      }
      // Since numbers don't have subpatterns this should be unreachable.
      (Pattern::Num(..), _) => unreachable!(),
      (Pattern::Tup(_, _), Pattern::Tup(fst, snd)) => {
        new_pats.push(*fst.clone());
        new_pats.push(*snd.clone());
      }
      (Pattern::Tup(..), Pattern::Var(Some(other_arg))) => {
        let fst_nam = make_var_name(&mut var_count);
        let snd_nam = make_var_name(&mut var_count);
        let fst_arg = Term::Var { nam: fst_nam.clone() };
        let snd_arg = Term::Var { nam: snd_nam.clone() };
        new_pats.push(Pattern::Var(Some(fst_nam)));
        new_pats.push(Pattern::Var(Some(snd_nam)));
        let new_ctr = Term::Tup { fst: Box::new(fst_arg), snd: Box::new(snd_arg) };
        new_body.subst(other_arg, &new_ctr);
      }
      (Pattern::Var(..), _) => new_pats.push(other_arg.clone()),
      // Unreachable cases, we only call this function if we know the two patterns match together
      (
        Pattern::Ctr(..) | Pattern::Tup(..),
        Pattern::Ctr(..) | Pattern::Num(..) | Pattern::Tup(..),
      ) => {
        unreachable!()
      }
      (Pattern::Ctr(_, ctr_fields), Pattern::Var(None)) => {
        for _ in ctr_fields {
          new_pats.push(Pattern::Var(None));