fn infer_up(&mut self, env: &mut TypeMap) -> WeldResult<bool> {
        // Remember whether we inferred any new type.
        let mut changed = false;
        // Remember the old bindings so they can be restored.
        let mut old_bindings: Vec<Binding> = Vec::new();
        // Let and Lambda are the only expressions that change bindings.
        match self.kind {
            Let {
                ref mut name,
                ref mut value,
                ref mut body,
            } => {
                // First perform type inference on the value. Then, take the old binding to `name`
                // and perform type inference on the body. Finally, restore the original
                // environment.
                changed |= value.infer_up(env)?;
                let previous = env.insert(name.clone(), value.ty.clone());
                old_bindings.push((name.clone(), previous));
                changed |= body.infer_up(env)?;
            }
            Lambda {
                ref mut params,
                ref mut body,
            } => {
                for p in params {
                    let previous = env.insert(p.name.clone(), p.ty.clone());
                    old_bindings.push((p.name.clone(), previous));
                }
                changed |= body.infer_up(env)?;
            }
            _ => (),
        };

        // For Let and Lambda, we already inferred the types of each child. For all other
        // expressions, we still need to do it after undoing the binding..
        match self.kind {
            Let { .. } | Lambda { .. } => (),
            _ => {
                // Infer/check the type of the subexpressions.
                for child in self.children_mut() {
                    changed |= child.infer_up(env)?;
                }
            }
        };

        // Undo symbol bindings.
        for (symbol, opt) in old_bindings {
            match opt {
                Some(old) => env.insert(symbol, old),
                None => env.remove(&symbol),
            };
        }

        // Infer local type.
        changed |= self.infer_locally(env)?;
        Ok(changed)
    }
Infer types for an expression upward.

This method iterates over each expression in the AST in post-order, operating on the trees
leaves and propogating types up. The method returns whether the type of this expression or
any subexpressions changed, or an error if one occurred.
weld/src/ast/type_inference.rs