pub fn unroll_structs(expr: &mut Expr) {
    use crate::util::SymbolGenerator;

    expr.uniquify().unwrap();
    let mut sym_gen = SymbolGenerator::from_expression(expr);
    expr.transform_up(&mut |ref mut expr| {
        if let Let {
            ref name,
            ref value,
            ref body,
        } = expr.kind
        {
            if let MakeStruct { ref elems } = value.kind {
                // First, ensure that the name is not used anywhere but a `GetField`.
                let mut total_count: i32 = 0;
                let mut getstruct_count: i32 = 0;
                body.traverse(&mut |ref e| {
                    if getfield_on_symbol(e, name).is_some() {
                        getstruct_count += 1;
                    }
                    if let Ident(ref ident_name) = e.kind {
                        if ident_name == name {
                            total_count += 1;
                        }
                    }
                });

                // We used the struct somewhere else, so we can't safely get rid of it.
                if total_count != getstruct_count {
                    return None;
                }

                let mut new_body = body.as_ref().clone();
                let symbols: Vec<_> = elems.iter().map(|_| sym_gen.new_symbol("us")).collect();
                // Replace the new_body with the symbol we assigned the struct element to.
                new_body.transform(&mut |ref mut expr2| {
                    if let Some(index) = getfield_on_symbol(expr2, name) {
                        let sym = symbols[index as usize].clone();
                        return Some(Expr::new_ident(sym, expr2.ty.clone()).unwrap());
                    }
                    None
                });

                // Unroll the struct elements by assigning each one to a name.
                let mut prev = new_body;
                for (i, sym) in symbols.into_iter().enumerate().rev() {
                    prev = Expr::new_let(sym, elems[i].clone(), prev).unwrap();
                }
                return Some(prev);
            }
        }
        None
    });
}
Changes struct definitions assigned to a name and only used in `GetField` operations
to `Let` definitions over the struct elements themselves.

This transformation is similar to a simple SROA (scalar replacement of aggregates) transform in
other compilers.

## Example

let a = {1, 2, 3, 4};
a.$0 + a.$1 + a.$2

Becomes

let us = 1;
let us#1 = 2;
let us#1 = 3;
let us#1 = 4;
us + us#1 + us#2
weld/src/optimizer/transforms/inliner.rs