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

Code before:
      let node = inet.new_node(Num { val: *val });
      // This representation only has nodes of arity 2, so we connect the two aux ports that are not used.
      inet.link(Port(node, 1), Port(node, 2));
      Ok(Some(Port(node, 0)))
    }
    // core: & #op ~ <fst <snd ret>>
    Term::Opx { op, fst, snd } => {
      let op_node = inet.new_node(Num { val: op.to_hvmc_label() });
      inet.link(Port(op_node, 1), Port(op_node, 2));

      let fst_node = inet.new_node(Op2);
      inet.link(Port(op_node, 0), Port(fst_node, 0));

      let fst = encode_term(inet, fst, Port(fst_node, 1), scope, vars, global_vars, dups)?;
      link_local(inet, Port(fst_node, 1), fst);

      let snd_node = inet.new_node(Op2);
      inet.link(Port(fst_node, 2), Port(snd_node, 0));

      let snd = encode_term(inet, snd, Port(snd_node, 1), scope, vars, global_vars, dups)?;
      link_local(inet, Port(snd_node, 1), snd);

      Ok(Some(Port(snd_node, 2)))
    }
    Term::Tup { fst, snd } => {
      let tup = inet.new_node(Con { lab: 1 });

      let fst = encode_term(inet, fst, Port(tup, 1), scope, vars, global_vars, dups)?;
      link_local(inet, Port(tup, 1), fst);

      let snd = encode_term(inet, snd, Port(tup, 2), scope, vars, global_vars, dups)?;
      link_local(inet, Port(tup, 2), snd);

      Ok(Some(Port(tup, 0)))
    }
  }
}

fn push_scope(
  name: &Option<Name>,
  decl_port: Port,
  scope: &mut HashMap<Name, Vec<usize>>,
  vars: &mut Vec<(Port, Option<Port>)>,
) {
  if let Some(name) = name {
    scope.entry(name.clone()).or_default().push(vars.len());
    vars.push((decl_port, None));
  }
}

fn pop_scope(name: &Option<Name>, decl_port: Port, inet: &mut INet, scope: &mut HashMap<Name, Vec<usize>>) {

Review comment (suggestion):
Is there som specific reason why you added labels to Con nodes? It seems that it only used here and the only used values are either 0 or 1.

I think you should remove the `lab` field and either compile to a Dup node like you did for Tup destructuring in the let case above (or use a Tup node type as I suggested).

Code after:
      // We assume this variable to be valid, bound and correctly scoped.
      // This pass must be done before.
      debug_assert!(
        scope.contains_key(nam),
        "Unbound variable {nam}. Expected this check to be already done"
      );
      let var_stack = scope.get(nam).unwrap();
      let crnt_var = *var_stack.last().unwrap();
      let (declare_port, use_port) = vars.get_mut(crnt_var).unwrap();
      debug_assert!(use_port.is_none(), "Variable {nam} used more than once");
      inet.link(up, *declare_port);
      *use_port = Some(up);
      Ok(Some(*declare_port))
    }
    Term::Lnk { nam } => {
      global_vars.entry(nam.clone()).or_default().1 = up;
      Ok(None)
    }
    // core: @def_id
    Term::Ref { def_id } => {
      let node = inet.new_node(Ref { def_id: *def_id });
      inet.link(Port(node, 1), Port(node, 2));
      inet.link(up, Port(node, 0));
      Ok(Some(Port(node, 0)))
    }
    Term::Let { pat: LetPat::Tup(l_nam, r_nam), val, nxt } => {
      let dup = inet.new_node(Tup);

      let val = encode_term(inet, val, Port(dup, 0), scope, vars, global_vars, dups)?;
      link_local(inet, Port(dup, 0), val);

      push_scope(l_nam, Port(dup, 1), scope, vars);
      push_scope(r_nam, Port(dup, 2), scope, vars);
      let nxt = encode_term(inet, nxt, up, scope, vars, global_vars, dups)?;
      pop_scope(r_nam, Port(dup, 2), inet, scope);
      pop_scope(l_nam, Port(dup, 1), inet, scope);

      Ok(nxt)
    }
    Term::Let { .. } => unreachable!(), // Removed in earlier poss
    Term::Sup { .. } => unreachable!(), // Not supported in syntax
    Term::Era => unreachable!(),        // Not supported in syntax
    // core: #val
    Term::Num { val } => {
      debug_assert!(*val <= LABEL_MASK);
      let node = inet.new_node(Num { val: *val });
      // This representation only has nodes of arity 2, so we connect the two aux ports that are not used.
      inet.link(Port(node, 1), Port(node, 2));
      Ok(Some(Port(node, 0)))
    }
    // core: & #op ~ <fst <snd ret>>