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

Code before:
          }
          Pattern::Num(_) => term_to_affine(term, var_uses, let_bodies),
          _ => unreachable!(),
        }
      }
    }
    Term::List { .. } => unreachable!("Should have been desugared already"),
    Term::Era | Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } => (),
  };
}

fn get_var_uses(nam: Option<&Name>, var_uses: &HashMap<Name, Val>) -> Val {
  if let Some(nam) = nam { *var_uses.get(nam).unwrap() } else { 0 }
}

// TODO: Is it really necessary to `count_var_uses_in_term` before `term_to_affine`?
// Can't it be unified in the same function? (given that the actual var uses in a term is already dynamic)
//
/// When a term is removed, the number of uses of a variable can change inside the term_to_affine call.
/// This returns the updated count instead of using the one we calculated initially
fn actual_var_use<'a>(var_uses: &'a mut HashMap<Name, Val>, name: &Name) -> &'a mut u64 {
  var_uses.entry(actual_var_use_counter(name)).or_default()
}

/// We use a special named variable to only count the number of actual var uses on the resulting term
fn actual_var_use_counter(var_name: &Name) -> Name {
  Name(format!("${var_name}$used"))
}

// TODO: Is there a difference between a list of dups and a complete binary tree of dups?
//
/// # Example
///
/// ```txt
/// let {x1 x1_dup} = body;
/// let {x2 x2_dup} = x1_dup;
/// let {x3 x4}     = x2_dup;
/// nxt
/// ```
fn make_dup_tree(nam: &Name, nxt: &mut Term, uses: Val, mut dup_body: Option<&mut Term>) {
  let free_vars = &mut nxt.free_vars();

  if let Some(ref body) = dup_body {
    free_vars.extend(body.free_vars())
  };

  let make_name = |uses| {
    let dup_name = dup_name(nam, uses);
    free_vars.contains_key(&dup_name).then(|| dup_name)
  };


Review comment (suggestion):
This is still not good function name. We are creating a `Name` that is derived from an existing `var_name`, so this is not a counter.

Also, the doc comment is not clear on how this new name is used (we count all non-single use let variables twice basically).

Code after:
    }
    Term::Match { scrutinee, arms } => {
      term_to_affine(scrutinee, var_uses, inst_count, let_bodies);
      for (rule, term) in arms {
        match rule {
          Pattern::Num(MatchNum::Succ(Some(nam))) => {
            term_with_bind_to_affine(term, nam, var_uses, inst_count, let_bodies)
          }
          Pattern::Num(_) => term_to_affine(term, var_uses, inst_count, let_bodies),
          _ => unreachable!(),
        }
      }
    }
    Term::List { .. } => unreachable!("Should have been desugared already"),
    Term::Era | Term::Lnk { .. } | Term::Ref { .. } | Term::Num { .. } | Term::Str { .. } => (),
  };
}

fn get_var_uses(nam: Option<&Name>, var_uses: &HashMap<Name, Val>) -> Val {
  nam.and_then(|nam| var_uses.get(nam).copied()).unwrap_or_default()
}

// TODO: Is there a difference between a list of dups and a complete binary tree of dups?
//
/// # Example
///
/// ```txt
/// let {x1 x1_dup} = body;
/// let {x2 x2_dup} = x1_dup;
/// let {x3 x4}     = x2_dup;
/// nxt
/// ```
fn make_dup_tree(nam: &Name, nxt: &mut Term, uses: Val, mut dup_body: Option<&mut Term>) {
  let free_vars = &mut nxt.free_vars();

  if let Some(ref body) = dup_body {
    free_vars.extend(body.free_vars())
  };

  let make_name = |uses| {
    let dup_name = dup_name(nam, uses);
    free_vars.contains_key(&dup_name).then(|| dup_name)
  };

  for i in (1 .. uses).rev() {
    *nxt = Term::Dup {
      tag: Tag::Auto,
      fst: make_name(i),
      snd: if i == uses - 1 { make_name(uses) } else { Some(internal_dup_name(nam, uses)) },
      val: if i == 1 {
        match dup_body.as_deref_mut() {