fn generate_bindings_scoped(
        &mut self,
        expr: &mut Expr,
        bindings: &mut HashMap<Symbol, Expr>,
        generated: &mut HashSet<Symbol>,
        current_site: &mut Site,
        stack: &mut Vec<Vec<(Symbol, Expr)>>,
        sites: &mut SiteMap,
    ) {
        current_site.push(self.counter);
        self.counter += 1;

        stack.push(vec![]);

        self.generate_bindings(expr, bindings, generated, current_site, stack, sites);

        // Generate the Let expressions for the bindings in this site.
        let binding_list = stack.pop().unwrap();
        let mut prev = expr.take();
        // Reverse list since the tree of let statements is built bottom-up, but evaluated
        // top-down.
        for (sym, expr) in binding_list.into_iter().rev() {
            generated.remove(&sym);
            prev = Expr::new_let(sym, expr, prev).unwrap();
        }

        current_site.pop();

        // Update the expression to contain the Lets.
        *expr = prev;
    }
Creates a new site (e.g., for a function or if statement) and generates bindings.

The new site represents a new site in the expression tree to insert let statements.

The created bindings may not necessarily be in the newest site -- bindings for a symbol
`sym` are generated in the site defined by `sites` (i.e., in the site
`stack[sites.get(sym)]`).
weld/src/optimizer/transforms/cse.rs