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

Code before:
      | Term::Tup { fst, snd }
      | Term::Sup { fst, snd, .. }
      | Term::Opx { fst, snd, .. }
      | Term::Dup { val: fst, nxt: snd, .. } => {
        let fst_uses = fst.encode_lists();
        let snd_uses = snd.encode_lists();
        fst_uses || snd_uses
      }
      Term::Match { scrutinee, arms } => {
        let mut used = scrutinee.encode_lists();
        for (pat, arm) in arms {
          used |= pat.names().chain(pat.ctrs()).any(|Name(n)| matches!(n.as_str(), LCONS | LNIL));
          used |= arm.encode_lists();
        }
        used
      }
      Term::Var { nam: Name(nam) } => nam == LCONS || nam == LNIL,
      Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => false,
    }
  }
}

impl Pattern {
  pub fn encode_lists(&mut self) -> bool {
    match self {
      Pattern::Var(Some(Name(nam))) => nam == LNIL,
      Pattern::List(pats) => {
        let lnil = Pattern::Var(Some(Name::new(LNIL)));

        *self = pats.iter_mut().rfold(lnil, |acc, nxt| {
          nxt.encode_lists();
          Pattern::Ctr(Name::new(LCONS), vec![nxt.clone(), acc])
        });

        true
      }
      Pattern::Ctr(Name(nam), pats) => {
        let mut uses = nam == LCONS;
        for pat in pats {
          uses |= pat.encode_lists();
        }
        uses
      }
      Pattern::Tup(fst, snd) => {
        let fst_uses = fst.encode_lists();
        let snd_uses = snd.encode_lists();
        fst_uses || snd_uses
      }
      Pattern::Var(..) | Pattern::Num(..) => false,
    }
  }

Review comment (suggestion):
Can you add a TODO here that this should be removed once we separate adding the constructors to the book from desugaring list terms?
This is necessary to work right now, but it's not the right way we should be doing it.

Code after:
        let fst_uses = fst.encode_lists();
        let snd_uses = snd.encode_lists();
        fst_uses || snd_uses
      }
      Term::Match { scrutinee, arms } => {
        let mut used = scrutinee.encode_lists();
        for (pat, arm) in arms {
          used |= pat.encode_lists();
          used |= arm.encode_lists();
        }
        used
      }
      Term::Var { nam: Name(nam) } => nam == LCONS || nam == LNIL,
      Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } | Term::Era => false,
    }
  }
}

impl Pattern {
  pub fn encode_lists(&mut self) -> bool {
    match self {
      // TODO: This should be removed once when we separate adding
      // constructors to desugaring list terms.
      Pattern::Var(Some(Name(nam))) => nam == LCONS || nam == LNIL,
      Pattern::List(pats) => {
        let lnil = Pattern::Var(Some(Name::new(LNIL)));

        *self = pats.iter_mut().rfold(lnil, |acc, nxt| {
          nxt.encode_lists();
          Pattern::Ctr(Name::new(LCONS), vec![nxt.clone(), acc])
        });

        true
      }
      Pattern::Ctr(Name(nam), pats) => {
        let mut uses = nam == LCONS || nam == LNIL;
        for pat in pats {
          uses |= pat.encode_lists();
        }
        uses
      }
      Pattern::Tup(fst, snd) => {
        let fst_uses = fst.encode_lists();
        let snd_uses = snd.encode_lists();
        fst_uses || snd_uses
      }
      Pattern::Var(..) | Pattern::Num(..) => false,
    }
  }
}