Now that I've done this flattened-HIR thing I don't need to worry about it.
3 files changed, 0 insertions(+), 1686 deletions(-)

R src/hir2.rs => 
R src/passes2.rs => 
R src/passes2/lambda_lift.rs => 
R src/hir2.rs =>  +0 -1049
@@ 1,1049 0,0 @@ 
-//! High-level intermediate representation, basically what you get after immediate parsing and
-//! where all the typechecking and other kinds of checking happen.  Slightly simplified over the
-//! AST -- basically the result of a lowering/desugaring pass.  This might give us a nice place to
-//! do other simple optimization-like things like constant folding, dead code detection, etc.
-//!
-//! Currently it's not really lowered by much!  If's and maybe loops or something.
-//! It's mostly a layer of indirection for further stuff to happen to, so we can change
-//! the parser without changing the typechecking and codegen.
-//!
-//! This is an EXPERIMENT for having our IR all shoved down into a single vec
-//! with everything in it just arrays.
-
-use std::fmt;
-use std::sync::atomic::{AtomicUsize, Ordering};
-
-use crate::ast;
-pub use crate::ast::{BOp, IfCase, Literal, Signature, UOp};
-use crate::*;
-
-/// Expression ID.  Used for associating individual expressions to types, and whatever
-/// other metadata we feel like.  That way we can keep that data in tables instead of
-/// having to mutate the HIR tree.
-/// The only guarantees the number offers is it will be unique.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct Eid(usize);
-
-/// Slightly less ugly horrible atomic global for storing index values for
-/// expression ID's, so each expression gets a unique ID.
-static NEXT_EID: AtomicUsize = AtomicUsize::new(0);
-
-impl Eid {
-    fn new() -> Self {
-        // We may be able to use Ordering::Relaxed here since we don't
-        // care what the value actually is, just that it increments
-        // atomically.  Eh, it's fine.
-        let current = NEXT_EID.fetch_add(1, Ordering::AcqRel);
-        // Check for overflow, since fetch_add can't do it.
-        // It returns the previous value, so if the next value
-        // is < than it, we've overflowed.
-        if (current.wrapping_add(1)) < current {
-            panic!("Integer overflow incrementing Eid; is your program absolutely enormous?");
-        }
-        Eid(current)
-    }
-}
-
-/// Expression index to an expr node in our flat list thing.
-#[derive(Debug, Copy, Clone, PartialEq, Eq, PartialOrd, Ord, Hash)]
-pub struct EIdx(usize);
-
-/// An expression node with a unique ID attached.
-/// Expressions are assigned types by the typechecker
-/// via an `Eid`->type map.
-#[derive(Debug, Clone)]
-pub struct ExprNode {
-    /// expression
-    pub e: Expr,
-    /// Expression ID
-    pub id: Eid,
-    /// Whether or not the expression is constant,
-    /// ie can be entirely evaluated at compile time.
-    pub is_const: bool,
-}
-
-impl PartialEq for ExprNode {
-    /// ExprNode's must ignore the Eid for equality purposes,
-    /// otherwise they will just *never* be equal.
-    ///
-    /// If you need to compare ExprNode including Eid's, then
-    /// write a new function.  (And then you might as well *only*
-    /// compare the Eid's unless you are purposefully testing for
-    /// ill-constructed nodes.)
-    fn eq(&self, other: &Self) -> bool {
-        self.e == other.e
-    }
-}
-
-impl ExprNode {
-    pub fn write(&self, indent: usize, f: &mut dyn fmt::Write) -> fmt::Result {
-        // TODO: We can make this take a callback that gets called for each
-        // expr node, which prints out types for each node.  Will make the
-        // formatting even more horrible though.
-        self.e.write(indent, f)?;
-        Ok(())
-    }
-}
-
-/*
-impl fmt::Display for Decl {
-    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
-        use crate::hir2::Decl as D;
-        match self {
-            D::Function {
-                name,
-                signature,
-                body,
-            } => {
-                writeln!(f, "fn {}{} =", name, signature.to_name())?;
-                for e in body {
-                    e.write(1, f)?;
-                }
-                writeln!(f, "\nend")?;
-            }
-
-            D::Const {
-                name,
-                typ: typename,
-                init,
-            } => {
-                write!(f, "const {}: {} = ", name, typename.get_name())?;
-                init.write(1, f)?;
-                writeln!(f)?;
-            }
-            D::TypeDef {
-                name,
-                typedecl,
-                params,
-            } => {
-                writeln!(f, "type {}({:?}) = {}", name, params, typedecl.get_name())?;
-            }
-            D::Import { name, localname } => {
-                writeln!(f, "import {} as {}", name, localname)?;
-            }
-        }
-        Ok(())
-    }
-}
-    */
-
-impl ExprNode {
-    pub fn new(e: Expr) -> Self {
-        ExprNode {
-            e: e,
-            id: Eid::new(),
-            is_const: false,
-        }
-    }
-
-    /// Call the function on the contents
-    /// and turn the result into a new ExprNode *without*
-    /// changing our Eid.
-    ///
-    /// Consumes self to preserve the invariant that no
-    /// Eid's are ever duplicated.
-    pub fn map(self, f: &mut dyn FnMut(Expr) -> Expr) -> Self {
-        ExprNode {
-            e: f(self.e),
-            ..self
-        }
-    }
-
-    /*
-    /// Apply a function with extra state to the given node.
-    /// Unneeded so far, see passes::expr_fold()
-    pub fn fold<S>(self, state: S, f: &dyn Fn(Expr, S) -> (Expr, S)) -> (Self, S) {
-        let (new_e, new_s) = f(*self.e, state);
-        (
-            ExprNode {
-                e: Box::new(new_e),
-                id: self.id,
-            },
-            new_s,
-        )
-    }
-    */
-}
-
-/// An expression.
-#[derive(Debug, Clone, PartialEq)]
-pub enum Expr {
-    Lit {
-        val: Literal,
-    },
-    Var {
-        name: Sym,
-    },
-    BinOp {
-        op: BOp,
-        lhs: EIdx,
-        rhs: EIdx,
-    },
-    UniOp {
-        op: UOp,
-        rhs: EIdx,
-    },
-    Block {
-        body: Vec<EIdx>,
-    },
-    Let {
-        varname: Sym,
-        typename: Option<Type>,
-        init: EIdx,
-        mutable: bool,
-    },
-    If {
-        cases: Vec<(EIdx, Vec<EIdx>)>,
-    },
-    Loop {
-        body: Vec<EIdx>,
-    },
-    Lambda {
-        signature: Signature,
-        body: Vec<EIdx>,
-    },
-    Funcall {
-        func: EIdx,
-        params: Vec<EIdx>,
-        type_params: Vec<Type>,
-    },
-    Break,
-    Return {
-        retval: EIdx,
-    },
-    TupleCtor {
-        body: Vec<EIdx>,
-    },
-    StructCtor {
-        body: Vec<(Sym, EIdx)>,
-    },
-    ArrayCtor {
-        body: Vec<EIdx>,
-    },
-    EnumCtor {
-        name: Sym,
-        variant: Sym,
-        value: i32,
-    },
-    // Create a new sum type.
-    // Like EnumCtor, this is generated for you by the
-    // compiler.
-    SumCtor {
-        name: Sym,
-        variant: Sym,
-        body: EIdx,
-    },
-    // Wrap a new type.
-    // Like EnumCtor, this is generated by the compiler.
-    TypeCtor {
-        name: Sym,
-        type_params: Vec<Type>,
-        body: EIdx,
-    },
-    // Opposite of TypeCtor
-    TypeUnwrap {
-        expr: EIdx,
-    },
-    TupleRef {
-        expr: EIdx,
-        elt: usize,
-    },
-    StructRef {
-        expr: EIdx,
-        elt: Sym,
-    },
-    ArrayRef {
-        expr: EIdx,
-        idx: EIdx,
-    },
-    Assign {
-        lhs: EIdx,
-        rhs: EIdx,
-    },
-    Typecast {
-        e: EIdx,
-        to: Type,
-    },
-    Deref {
-        expr: EIdx,
-    },
-    Ref {
-        expr: EIdx,
-    },
-}
-
-impl Expr {
-    /// Shortcut function for making literal bools
-    pub fn bool(ir: &mut Ir, b: bool) -> EIdx {
-        ir.insert(Self::Lit {
-            val: Literal::Bool(b),
-        })
-    }
-
-    /// Shortcut function for making literal integers
-    pub fn int(ir: &mut Ir, i: i128) -> EIdx {
-        ir.insert(Self::Lit {
-            val: Literal::Integer(i),
-        })
-    }
-
-    /// Shortcut function for making literal unit
-    pub fn unit(ir: &mut Ir) -> EIdx {
-        ir.insert(Self::TupleCtor { body: vec![] })
-    }
-
-    pub fn write(&self, indent: usize, f: &mut dyn fmt::Write) -> fmt::Result {
-        todo!()
-        /*
-        use Expr::*;
-        for _ in 0..(indent * 2) {
-            write!(f, " ")?;
-        }
-        match self {
-            Lit { val } => {
-                write!(f, "{}", val)?;
-            }
-            Var { name } => write!(f, "{}", name)?,
-            BinOp { op, lhs, rhs } => {
-                write!(f, "({:?} ", op)?;
-                lhs.write(indent, f)?;
-                rhs.write(indent, f)?;
-                writeln!(f, ")")?;
-            }
-            UniOp { op, rhs } => {
-                write!(f, "({:?} ", op)?;
-                rhs.write(indent, f)?;
-                writeln!(f, ")")?;
-            }
-            Block { body } => {
-                writeln!(f, "(block")?;
-                for b in body {
-                    b.write(indent + 1, f)?;
-                }
-                writeln!(f, ")")?;
-            }
-            Let {
-                varname,
-                typename,
-                init,
-                mutable,
-            } => {
-                let m = if *mutable { " mut" } else { "" };
-                let type_str = typename
-                    .as_ref()
-                    .map(|inner| inner.get_name())
-                    .unwrap_or(Cow::from(""));
-                write!(f, "(let {}{} {} = ", &*varname.val(), m, type_str)?;
-                init.write(0, f)?;
-                writeln!(f, ")")?;
-            }
-            If { cases } => {
-                writeln!(f, "(if")?;
-                for (case, arm) in cases {
-                    case.write(indent + 1, f)?;
-                    for expr in arm {
-                        expr.write(indent + 2, f)?;
-                    }
-                }
-                writeln!(f, ")")?;
-            }
-            Loop { body } => {
-                writeln!(f, "(loop")?;
-                for b in body {
-                    b.write(indent + 1, f)?;
-                }
-                writeln!(f, ")")?;
-            }
-            Lambda { signature, body } => {
-                writeln!(f, "(lambda {}", signature.to_name())?;
-                for b in body {
-                    b.write(indent + 1, f)?;
-                }
-                writeln!(f, ")")?;
-            }
-            Funcall {
-                func,
-                params,
-                type_params,
-            } => {
-                write!(f, "(funcall ")?;
-                func.write(0, f)?;
-                for b in params {
-                    b.write(indent + 1, f)?;
-                    write!(f, " ")?;
-                }
-                write!(f, "|")?;
-                for ty in type_params {
-                    write!(f, "{},", ty.get_name())?;
-                }
-                write!(f, ")")?;
-            }
-            Break => {
-                writeln!(f, "(break)")?;
-            }
-            Return { retval } => {
-                write!(f, "(return ")?;
-                retval.write(0, f)?;
-                writeln!(f)?;
-            }
-            EnumCtor {
-                name,
-                variant,
-                value,
-            } => {
-                write!(f, "(enumval {} {} {})", name, &*variant.val(), value)?;
-            }
-            TupleCtor { body } => {
-                write!(f, "(tuple ")?;
-                for b in body {
-                    b.write(0, f)?;
-                    write!(f, " ")?;
-                }
-                write!(f, ")")?;
-            }
-            StructCtor { body } => {
-                writeln!(f, "(struct")?;
-                for (nm, expr) in body {
-                    write!(f, "{} = ", &*nm.val())?;
-                    expr.write(0, f)?;
-                    writeln!(f)?;
-                }
-                writeln!(f, ")")?;
-            }
-            ArrayCtor { body } => {
-                writeln!(f, "(array")?;
-                for b in body {
-                    b.write(indent + 1, f)?;
-                }
-                write!(f, ")")?;
-            }
-            SumCtor {
-                name,
-                variant,
-                body,
-            } => {
-                write!(f, "(sum {} {} ", name, &*variant.val())?;
-                body.write(0, f)?;
-                write!(f, ")")?;
-            }
-            TypeCtor {
-                name,
-                type_params: _,
-                body,
-            } => {
-                // TODO: type_params
-                write!(f, "(typector {} ", name)?;
-                body.write(0, f)?;
-                write!(f, ")")?;
-            }
-            TypeUnwrap { expr } => {
-                write!(f, "(typeunwrap ")?;
-                expr.write(0, f)?;
-                write!(f, ")")?;
-            }
-            TupleRef { expr, elt } => {
-                write!(f, "(tupleref ")?;
-                expr.write(0, f)?;
-                write!(f, " {})", elt)?;
-            }
-            StructRef { expr, elt } => {
-                write!(f, "(structref ")?;
-                expr.write(0, f)?;
-                write!(f, " {})", elt)?;
-            }
-            ArrayRef { expr: e, idx } => {
-                write!(f, "(arrayref ")?;
-                e.write(0, f)?;
-                write!(f, " ")?;
-                idx.write(0, f)?;
-                write!(f, ")")?;
-            }
-            Assign { lhs, rhs } => {
-                write!(f, "(assign ")?;
-                lhs.write(0, f)?;
-                write!(f, " ")?;
-                rhs.write(0, f)?;
-                write!(f, ")")?;
-            }
-            Typecast { e, to } => {
-                write!(f, "(cast {} ", to.get_name())?;
-                e.write(0, f)?;
-                write!(f, ")")?;
-            }
-            Deref { expr } => {
-                write!(f, "(ref ")?;
-                expr.write(0, f)?;
-                write!(f, ")")?;
-            }
-            Ref { expr } => {
-                write!(f, "(ref ")?;
-                expr.write(0, f)?;
-                write!(f, ")")?;
-            }
-        }
-        Ok(())
-        */
-    }
-}
-
-impl ExprNode {
-    /// Shortcut function for making literal bools
-    pub fn bool(b: bool) -> Self {
-        Self::new(Expr::Lit {
-            val: Literal::Bool(b),
-        })
-    }
-
-    /// Shortcut function for making literal integers
-    pub fn int(i: i128) -> Self {
-        Self::new(Expr::Lit {
-            val: Literal::Integer(i),
-        })
-    }
-
-    /// Shortcut function for making literal unit
-    pub fn unit() -> Self {
-        Self::new(Expr::TupleCtor { body: vec![] })
-    }
-}
-/// A top-level declaration in the source file.
-/// Like ExprNode, contains a type annotation.
-#[derive(Debug, Clone, PartialEq)]
-pub enum Decl {
-    Function {
-        name: Sym,
-        signature: Signature,
-        body: Vec<EIdx>,
-    },
-    Const {
-        name: Sym,
-        typ: Type,
-        init: EIdx,
-    },
-    TypeDef {
-        name: Sym,
-        params: Vec<Sym>,
-        typedecl: Type,
-    },
-    Import {
-        name: Sym,
-        localname: Sym,
-    },
-}
-
-/// A compilable chunk of IR.
-///
-/// Currently, basically a compilation unit.
-#[derive(Debug, Clone, Default)]
-pub struct Ir {
-    pub decls: Vec<Decl>,
-    pub exprs: Vec<ExprNode>,
-    pub filename: String,
-    pub modulename: String,
-}
-
-impl Ir {
-    fn new(filename: &str, modulename: &str) -> Self {
-        Ir {
-            decls: vec![],
-            exprs: vec![],
-            filename: filename.to_owned(),
-            modulename: modulename.to_owned(),
-        }
-    }
-    fn insert(&mut self, expr: Expr) -> EIdx {
-        let en = ExprNode::new(expr);
-        self.exprs.push(en);
-        EIdx(self.exprs.len() - 1)
-    }
-
-    fn get(&self, eidx: EIdx) -> &ExprNode {
-        self.exprs
-            .get(eidx.0)
-            .expect("Invalid expr idx, should never happen!")
-    }
-}
-
-impl fmt::Display for Ir {
-    fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
-        todo!()
-        /*
-        for decl in &self.decls {
-            write!(f, "{}", decl)?;
-        }
-        Ok(())
-        */
-    }
-}
-
-/// Transforms AST into HIR
-pub fn lower(ast: &ast::Ast) -> Ir {
-    let mut ir = Ir {
-        decls: vec![],
-        exprs: vec![],
-        filename: ast.filename.clone(),
-        modulename: ast.modulename.clone(),
-    };
-    for d in ast.decls.iter() {
-        lower_decl(&mut ir, d)
-    }
-
-    ir
-}
-
-fn lower_lit(lit: &ast::Literal) -> Literal {
-    lit.clone()
-}
-
-fn lower_bop(bop: &ast::BOp) -> BOp {
-    *bop
-}
-
-fn lower_uop(uop: &ast::UOp) -> UOp {
-    *uop
-}
-
-fn lower_signature(sig: &ast::Signature) -> Signature {
-    sig.clone()
-}
-
-/// This is the biggie currently
-fn lower_expr(ir: &mut Ir, expr: &ast::Expr) -> EIdx {
-    use ast::Expr as E;
-    use Expr::*;
-    let new_exp = match expr {
-        E::Lit { val } => Lit {
-            val: lower_lit(val),
-        },
-        E::Var { name } => Var { name: *name },
-        E::BinOp { op, lhs, rhs } => {
-            let nop = lower_bop(op);
-            let nlhs = lower_expr(ir, lhs);
-            let nrhs = lower_expr(ir, rhs);
-            BinOp {
-                op: nop,
-                lhs: nlhs,
-                rhs: nrhs,
-            }
-        }
-        E::UniOp { op, rhs } => {
-            let nop = lower_uop(op);
-            let nrhs = lower_expr(ir, rhs);
-            UniOp { op: nop, rhs: nrhs }
-        }
-        E::Block { body } => {
-            let nbody = lower_exprs(ir, body);
-            Block { body: nbody }
-        }
-        E::Let {
-            varname,
-            typename,
-            init,
-            mutable,
-        } => {
-            let ninit = lower_expr(ir, init);
-            Let {
-                varname: *varname,
-                typename: typename.clone(),
-                init: ninit,
-                mutable: *mutable,
-            }
-        }
-        E::If { cases, falseblock } => {
-            // One of the actual transformations, this makes all if/else statements
-            // into essentially a switch: `if ... else if ... else if ... else if true ... end`
-            // This is more consistent and easier to handle for typechecking.
-            assert!(!cases.is_empty(), "Should never happen");
-            let mut cases: Vec<_> = cases
-                .iter()
-                .map(|case| (lower_expr(ir, &case.condition), lower_exprs(ir, &case.body)))
-                .collect();
-            // Add the "else" case, which we can just make `else if true then...`
-            // No idea if this is a good idea, but it makes life easier right
-            // this instant, so.  Hasn't bit me yet, so it's not a *bad* idea.
-            let nelse_case = Expr::bool(ir, true);
-            // Empty false block becomes a false block that returns unit
-            let false_exprs = if falseblock.is_empty() {
-                lower_exprs(ir, &[ast::Expr::TupleCtor { body: vec![] }])
-            } else {
-                lower_exprs(ir, falseblock)
-            };
-            cases.push((nelse_case, false_exprs));
-            If { cases }
-        }
-        E::Loop { body } => {
-            let nbody = lower_exprs(ir, body);
-            Loop { body: nbody }
-        }
-        E::While { cond, body } => {
-            // While loops just get turned into a Loop containing
-            // if not cond then break end
-            let inverted_cond = E::UniOp {
-                op: UOp::Not,
-                rhs: cond.clone(),
-            };
-            let test = lower_expr(ir, &inverted_cond);
-            let brk = vec![ir.insert(Break)];
-            // As per above, we need to always have an "else" end case
-            let else_case = Expr::bool(ir, true);
-            let else_exprs = lower_exprs(ir, &[ast::Expr::TupleCtor { body: vec![] }]);
-            let if_expr = ir.insert(If {
-                cases: vec![(test, brk), (else_case, else_exprs)],
-            });
-            let mut nbody = lower_exprs(ir, body);
-            nbody.insert(0, if_expr);
-            Loop { body: nbody }
-        }
-        E::Lambda { signature, body } => {
-            let nsig = lower_signature(signature);
-            let nbody = lower_exprs(ir, body);
-            Lambda {
-                signature: nsig,
-                body: nbody,
-            }
-        }
-        E::Funcall {
-            func,
-            params,
-            typeparams,
-        } => {
-            let nfunc = lower_expr(ir, func);
-            let nparams = lower_exprs(ir, params);
-            Funcall {
-                func: nfunc,
-                params: nparams,
-                type_params: typeparams.clone(),
-            }
-        }
-        E::Break => Break,
-        E::Return { retval: e } => Return {
-            retval: lower_expr(ir, e),
-        },
-        E::TupleCtor { body } => {
-            /*
-            // Turn {foo, bar} into {_0: foo, _1: bar}
-                let body_pairs = body
-                    .into_iter()
-                    .enumerate()
-                    .map(|(i, vl)| (Sym::new(format!("_{}", i)), lower_expr(ir, vl)))
-                    .collect();
-                Expr::StructCtor { body: body_pairs }
-                */
-            let body = lower_exprs(ir, body);
-            Expr::TupleCtor { body }
-        }
-        E::StructCtor { body } => {
-            let lowered_body = body
-                .iter()
-                .map(|(nm, expr)| (*nm, lower_expr(ir, expr)))
-                .collect();
-            Expr::StructCtor { body: lowered_body }
-        }
-        E::ArrayRef { expr, idx } => Expr::ArrayRef {
-            expr: lower_expr(ir, expr),
-            idx: lower_expr(ir, idx),
-        },
-        E::TupleRef { expr, elt } => Expr::TupleRef {
-            expr: lower_expr(ir, expr),
-            elt: *elt,
-        },
-        E::StructRef { expr, elt } => Expr::StructRef {
-            expr: lower_expr(ir, expr),
-            elt: *elt,
-        },
-        E::TypeUnwrap { expr } => Expr::TypeUnwrap {
-            expr: lower_expr(ir, expr),
-        },
-        E::Deref { expr } => Expr::Deref {
-            expr: lower_expr(ir, expr),
-        },
-        E::Ref { expr } => Expr::Ref {
-            expr: lower_expr(ir, expr),
-        },
-        E::Assign { lhs, rhs } => Expr::Assign {
-            lhs: lower_expr(ir, lhs),
-            rhs: lower_expr(ir, rhs),
-        },
-        E::ArrayCtor { body } => Expr::ArrayCtor {
-            body: lower_exprs(ir, body.as_slice()),
-        },
-    };
-    ir.insert(new_exp)
-}
-
-/// handy shortcut to lower Vec<ast::Expr>
-fn lower_exprs(ir: &mut Ir, exprs: &[ast::Expr]) -> Vec<EIdx> {
-    exprs.iter().map(|e| lower_expr(ir, e)).collect()
-}
-fn lower_typedef(ir: &mut Ir, name: Sym, ty: &Type, params: &[Sym]) {
-    use Decl::*;
-    match ty {
-        // For `type Foo = enum Foo, Bar, Baz end`
-        // synthesize
-        // const Foo = {
-        //     .Foo = <magic unprintable thing>
-        //     .Bar = <magic unprintable thing>
-        //     .Baz = <magic unprintable thing>
-        // }
-        Type::Enum(ts) => {
-            let struct_body: Vec<_> = ts
-                .iter()
-                .map(|(enumname, enumval)| {
-                    // TODO: Enum vals?
-                    let e = ir.insert(Expr::EnumCtor {
-                        name,
-                        variant: *enumname,
-                        value: *enumval,
-                    });
-                    let e2 = ir.insert(Expr::TypeCtor {
-                        name,
-                        type_params: vec![],
-                        body: e,
-                    });
-                    (*enumname, e2)
-                })
-                .collect();
-            let init_val = ir.insert(Expr::StructCtor { body: struct_body });
-            let struct_signature = ts
-                .iter()
-                //.map(|(enumname, _enumval)| (*enumname, ty.clone()))
-                .map(|(enumname, _enumval)| (*enumname, Type::Named(name, vec![])))
-                .collect();
-            // Enums cannot have type parameters, so this works.
-            let init_type = Type::Struct(struct_signature, vec![]);
-            let new_constdef = Const {
-                name,
-                typ: init_type,
-                init: init_val,
-            };
-            ir.decls.push(new_constdef);
-        }
-        // For `type Foo = sum X {}, Y Thing end`
-        // synthesize
-        // const Foo = {
-        //     .X = fn({}) Foo = <magic unprintable thing> end
-        //     .Y = fn(Thing) Foo = <magic unprintable thing> end
-        // }
-        //
-        // Maybe also something like this???
-        // type X = {}
-        // type Y = Thing
-        // TODO: What do we do with the generics...  Right now they just
-        // get stuffed into the constructor functions verbatim.
-        Type::Sum(body, generics) => {
-            trace!("Lowering sum type {}", name);
-            let struct_body: Vec<_> = body
-                .iter()
-                .map(|(variant_name, variant_type)| {
-                    let paramname = Sym::new("x");
-                    let signature = ast::Signature {
-                        params: vec![(paramname, variant_type.clone())],
-                        rettype: Type::Named(name, generics.clone()),
-                        typeparams: generics.clone(),
-                    };
-                    // Just return the value passed to it wrapped
-                    // in a constructor of some kind...?
-                    let contents = ir.insert(Expr::Var { name: paramname });
-                    let body = vec![ir.insert(Expr::SumCtor {
-                        name,
-                        variant: *variant_name,
-                        body: contents,
-                    })];
-                    let e = ir.insert(Expr::Lambda { signature, body });
-                    //println!("{} is {:#?}", variant_name, e);
-                    (*variant_name, e)
-                })
-                .collect();
-            let init_val = ir.insert(Expr::StructCtor { body: struct_body });
-            let struct_typebody = body
-                .iter()
-                .map(|(variant_name, variant_type)| {
-                    // The function inside the struct has the signature
-                    // `fn(variant_type) name`
-                    (
-                        *variant_name,
-                        Type::Func(
-                            vec![variant_type.clone()],
-                            Box::new(Type::Named(name, generics.clone())),
-                            generics.clone(),
-                        ),
-                    )
-                })
-                .collect();
-            let struct_type = Type::Struct(struct_typebody, generics.clone());
-            let new_constdef = Const {
-                name: name.to_owned(),
-                typ: struct_type,
-                init: init_val,
-            };
-            //println!("Lowered to {:#?}", &new_constdef);
-            ir.decls.push(new_constdef);
-        }
-        // For other types, we create a constructor function to build them.
-        other => {
-            let s = Sym::new("x");
-            trace!("Lowering params {:?}", params);
-            let type_params: Vec<_> = params.iter().map(|s| Type::Generic(*s)).collect();
-            let signature = ast::Signature {
-                params: vec![(s, other.clone())],
-                rettype: Type::Named(name.to_owned(), type_params.clone()),
-                typeparams: type_params.clone(),
-            };
-            // The generated function just returns the value passed to it wrapped
-            // in a type constructor
-            let contents = ir.insert(Expr::Var { name: s });
-            let body = vec![ir.insert(Expr::TypeCtor {
-                name,
-                type_params,
-                body: contents,
-            })];
-            //println!("{} is {:#?}", variant_name, e);
-            let new_fundecl = Function {
-                name: name.to_owned(),
-                signature,
-                body,
-            };
-            ir.decls.push(new_fundecl);
-        }
-    }
-}
-
-/// Lower an AST decl to IR.
-///
-/// Is there a more elegant way of doing this than passing an accumulator?
-/// Returning a vec is lame.  Return an iterator?  Sounds like work.
-fn lower_decl(ir: &mut Ir, decl: &ast::Decl) {
-    use ast::Decl as D;
-    match decl {
-        D::Function {
-            name,
-            signature,
-            body,
-            ..
-        } => {
-            let body = lower_exprs(ir, body);
-            ir.decls.push(Decl::Function {
-                name: *name,
-                signature: lower_signature(signature),
-                body,
-            })
-        }
-        D::Const {
-            name,
-            typename,
-            init,
-            ..
-        } => {
-            let init = lower_expr(ir, init);
-            ir.decls.push(Decl::Const {
-                name: *name,
-                typ: typename.clone(),
-                init,
-            })
-        }
-        // this needs to generate the typedef AND the type constructor
-        // declaration.  Plus the type deconstructor.
-        D::TypeDef {
-            name,
-            typedecl,
-            doc_comment: _,
-            params,
-        } => {
-            lower_typedef(ir, *name, typedecl, params);
-            ir.decls.push(Decl::TypeDef {
-                name: *name,
-                params: params.clone(),
-                typedecl: typedecl.clone(),
-            });
-        }
-        D::Import { name, rename } => ir.decls.push(Decl::Import {
-            name: *name,
-            localname: rename.unwrap_or(*name),
-        }),
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    use crate::ast::Expr as A;
-    use crate::hir2::Expr as I;
-    use crate::hir2::ExprNode as EN;
-
-    /// Does `return;` turn into `return ();`?
-    /// Not doing that to make parsing simpler, since we don't
-    /// actually have semicolons.
-    #[test]
-    fn test_return_none() {
-        let ir = &mut Ir::new("", "");
-        let input = A::Return {
-            retval: Box::new(A::unit()),
-        };
-        let retval = Expr::unit(ir);
-        let output = ir.insert(I::Return { retval });
-        let res = lower_expr(ir, &input);
-        assert_eq!(&res, &output);
-    }
-
-    /*
-    /// Do we turn chained if's properly into nested ones?
-    /// Single if.
-    #[test]
-    fn test_if_lowering_single() {
-        let input = A::If {
-            cases: vec![ast::IfCase {
-                condition: Box::new(A::bool(false)),
-                body: vec![A::int(1)],
-            }],
-            falseblock: vec![A::int(2)],
-        };
-        let output = EN::new(I::If {
-            cases: vec![
-                (EN::bool(false), vec![EN::int(1)]),
-                (EN::bool(true), vec![EN::int(2)]),
-            ],
-        });
-        let res = lower_expr(ir, &input);
-        assert_eq!(&res, &output);
-    }
-
-    /// Do we turn chained if's properly into nested ones?
-    /// Chained if/else's
-    #[test]
-    fn test_if_lowering_chained() {
-        let input = A::If {
-            cases: vec![
-                ast::IfCase {
-                    condition: Box::new(A::bool(false)),
-                    body: vec![A::int(1)],
-                },
-                ast::IfCase {
-                    condition: Box::new(A::bool(true)),
-                    body: vec![A::int(2)],
-                },
-            ],
-            falseblock: vec![A::int(3)],
-        };
-        let output = EN::new(I::If {
-            cases: vec![
-                (EN::bool(false), vec![EN::int(1)]),
-                (EN::bool(true), vec![EN::int(2)]),
-                (EN::bool(true), vec![EN::int(3)]),
-            ],
-        });
-        let res = lower_expr(ir, &input);
-        assert_eq!(&res, &output);
-    }
-
-    /// Do we panic if we get an impossible if with no cases?
-    #[test]
-    #[should_panic]
-    fn test_if_nothing() {
-        let input = A::If {
-            cases: vec![],
-            falseblock: vec![],
-        };
-        let _ = lower_expr(ir, &input);
-    }
-    */
-}

          
R src/passes2.rs =>  +0 -574
@@ 1,574 0,0 @@ 
-//! Transformation/optimization passes that function on the IR.
-//! May happen before or after typechecking, either way.
-//! For now each is a function from `IR -> IR`, with some recursion
-//! scheme helper functions.  There's two types of passes, one that
-//! happens before type checking and one that happens after.
-//!
-//! It could probably be more efficient, especially with
-//! IR nodes flattened into a vec, but that doesn't matter for now.
-//! We just allocate our way to happiness.
-//!
-//! TODO: A pass that might be useful would be "alpha renaming".
-//! Essentially you walk through your entire compilation unit and
-//! rename everything to a globally unique name.  This means that
-//! scope vanishes, for example, and anything potentially
-//! ambiguous becomes unambiguous.  It can come after typechecking tho.
-//!
-//!
-//! TODO: Passes that need to be done still:
-//!  * Closure conversion
-//!  * Monomorphization
-//!  * Pointerification, turning large struct values into pointers?  Maybe.
-//!  * Turning all enums into ints?  Maybe.
-
-// Not 100% convinced that having a submodule for each pass is
-// necessary, since many of the passes are pretty small, but
-// oh well.
-
-mod lambda_lift;
-use crate::hir2::{Decl as D, EIdx, Expr as E, ExprNode, Ir};
-use crate::*;
-
-type Pass = fn(Ir) -> Ir;
-
-/// Tck has to be mutable because we may change the return type
-/// of expr nodes.
-type TckPass = fn(Ir, &mut typeck::Tck) -> Ir;
-
-pub fn run_passes(ir: Ir) -> Ir {
-    // TODO: It may be more efficient to compose passes rather than fold them?
-    // That way they don't need to build the full intermediate IR each time.
-    // You can use the recursion scheme pattern for this.
-    // That will take some nontrivial restructuring of expr_map though, will also need
-    // a decl_map or something that can compose multiple passes together.
-    // Probably not *difficult*, but tricksy.
-    let passes: &[Pass] = &[lambda_lift::lambda_lift];
-    passes.iter().fold(ir, |prev_ir, f| f(prev_ir))
-}
-
-pub fn run_typechecked_passes(ir: Ir, tck: &mut typeck::Tck) -> Ir {
-    // let passes: &[TckPass] = &[nameify, enum_to_int];
-    //let passes: &[TckPass] = &[nameify, struct_to_tuple];
-    let passes: &[TckPass] = &[];
-    let res = passes.iter().fold(ir, |prev_ir, f| f(prev_ir, tck));
-    res
-}
-
-/// Handy do-nothing combinator
-fn id<T>(thing: T) -> T {
-    thing
-}
-
-/// This is the core recusion scheme that takes a function and applies
-/// it to an expression, and all its subexpressions.
-/// The function is `&mut FnMut` so if it needs to have access to more
-/// data between calls besides the expression itself, just smuggle it
-/// into the closure.  Trying to make this generic over different funcs
-/// signatures is probably not worth the effort
-///
-/// To handle multiple expressions this will turn more into a fold()
-/// than a map(), it will take an accumulator that gets threaded through
-/// everything...  That gets *very weird* though and I manage to pour
-/// my coffee on my cat this morning so let's give that a miss for now.
-/// As it is, this can only transform subtrees into other subtrees.
-///
-/// We don't really need a version of this for decls, 'cause decls
-/// can't be nested.
-///
-/// The function has to take and return an ExprNode, not an expr,
-/// because they may have to look up the type of the expression.
-///
-/// This can take a function to call to transform the current node
-/// before descending into sub-expressions
-/// sub-nodes, and one to call after.  Use expr_map_pre()
-/// and expr_map_post() to just do a pre-traversal or a post-traversal
-/// specifically.
-fn expr_map(
-    ir: &Ir,
-    out: &mut Ir,
-    expr: ExprNode,
-    f_pre: &mut dyn FnMut(ExprNode) -> EIdx,
-    f_post: &mut dyn FnMut(ExprNode) -> EIdx,
-) -> hir2::EIdx {
-    let thing = f_pre(expr);
-    let exprfn = &mut |e| match e {
-        // Nodes with no recursive expressions.
-        // I list all these out explicitly instead of
-        // using a catchall so it doesn't fuck up if we change
-        // the type of Expr.
-        E::Lit { .. } => e,
-        E::Var { .. } => e,
-        E::Break => e,
-        E::EnumCtor { .. } => e,
-        E::TupleCtor { body } => E::TupleCtor {
-            body: exprs_map(out, body, f_pre, f_post),
-        },
-        E::StructCtor { body } => {
-            let new_body = body
-                .into_iter()
-                .map(|(sym, vl)| (sym, expr_map(ir, out, vl, f_pre, f_post)))
-                .collect();
-            E::StructCtor { body: new_body }
-        }
-        E::TypeCtor {
-            name,
-            type_params,
-            body,
-        } => E::TypeCtor {
-            name,
-            type_params,
-            body: expr_map(ir, out, body, f_pre, f_post),
-        },
-        E::SumCtor {
-            name,
-            variant,
-            body,
-        } => E::SumCtor {
-            name,
-            variant,
-            body: expr_map(ir, out, body, f_pre, f_post),
-        },
-        E::ArrayCtor { body } => E::ArrayCtor {
-            body: exprs_map(out, body, f_pre, f_post),
-        },
-        E::TypeUnwrap { expr } => E::TypeUnwrap {
-            expr: expr_map(ir, out, expr, f_pre, f_post),
-        },
-        E::TupleRef { expr, elt } => E::TupleRef {
-            expr: expr_map(ir, out, expr, f_pre, f_post),
-            elt,
-        },
-        E::StructRef { expr, elt } => E::StructRef {
-            expr: expr_map(ir, out, expr, f_pre, f_post),
-            elt,
-        },
-        E::ArrayRef { expr, idx } => E::ArrayRef {
-            expr: expr_map(ir, out, expr, f_pre, f_post),
-            idx,
-        },
-        E::Assign { lhs, rhs } => E::Assign {
-            lhs: expr_map(ir, out, lhs, f_pre, f_post), // TODO: Think real hard about lvalues
-            rhs: expr_map(ir, out, rhs, f_pre, f_post),
-        },
-        E::BinOp { op, lhs, rhs } => E::BinOp {
-            op,
-            lhs: expr_map(ir, out, lhs, f_pre, f_post),
-            rhs: expr_map(ir, out, rhs, f_pre, f_post),
-        },
-        E::UniOp { op, rhs } => E::UniOp {
-            op,
-            rhs: expr_map(ir, out, rhs, f_pre, f_post),
-        },
-        E::Block { body } => E::Block {
-            body: exprs_map(out, body, f_pre, f_post),
-        },
-        E::Let {
-            varname,
-            typename,
-            init,
-            mutable,
-        } => E::Let {
-            varname,
-            typename,
-            init: expr_map(ir, out, init, f_pre, f_post),
-            mutable,
-        },
-        E::If { cases } => {
-            let new_cases = cases
-                .into_iter()
-                .map(|(test, case)| {
-                    let new_test = expr_map(ir, out, test, f_pre, f_post);
-                    let new_cases = exprs_map(out, case, f_pre, f_post);
-                    (new_test, new_cases)
-                })
-                .collect();
-            E::If { cases: new_cases }
-        }
-        E::Loop { body } => E::Loop {
-            body: exprs_map(out, body, f_pre, f_post),
-        },
-        E::Return { retval } => E::Return {
-            retval: expr_map(ir, out, retval, f_pre, f_post),
-        },
-        E::Funcall {
-            func,
-            params,
-            type_params,
-        } => {
-            let new_func = expr_map(ir, out, func, f_pre, f_post);
-            let new_params = exprs_map(out, params, f_pre, f_post);
-            E::Funcall {
-                func: new_func,
-                params: new_params,
-                type_params,
-            }
-        }
-        E::Lambda { signature, body } => E::Lambda {
-            signature,
-            body: exprs_map(out, body, f_pre, f_post),
-        },
-        E::Typecast { e, to } => E::Typecast {
-            e: expr_map(ir, out, e, f_pre, f_post),
-            to,
-        },
-        E::Ref { expr } => E::Ref {
-            expr: expr_map(ir, out, expr, f_pre, f_post),
-        },
-        E::Deref { expr } => E::Deref {
-            expr: expr_map(ir, out, expr, f_pre, f_post),
-        },
-    };
-    let post_thing = thing.map(exprfn);
-    f_post(post_thing)
-}
-
-pub fn expr_map_pre(expr: ExprNode, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> ExprNode {
-    expr_map(ir, out, expr, f, &mut id)
-}
-
-pub fn expr_map_post(expr: ExprNode, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> ExprNode {
-    expr_map(ir, out, expr, &mut id, f)
-}
-
-/// Map functions over a list of exprs.
-fn exprs_map(
-    in: &Ir,
-    out: &mut Ir,
-    exprs: Vec<ExprNode>,
-    f_pre: &mut dyn FnMut(ExprNode) -> EIdx,
-    f_post: &mut dyn FnMut(ExprNode) -> EIdx,
-) -> Vec<EIdx> {
-    exprs
-        .into_iter()
-        .map(|e| expr_map(ir, out, e, f_pre, f_post))
-        .collect()
-}
-
-fn exprs_map_pre(
-    out: &mut Ir,
-    exprs: Vec<ExprNode>,
-    f: &mut dyn FnMut(ExprNode) -> ExprNode,
-) -> Vec<EIdx> {
-    exprs_map(out, exprs, f, &mut id)
-}
-
-fn _exprs_map_post(
-    out: &mut Ir,
-    exprs: Vec<ExprNode>,
-    f: &mut dyn FnMut(ExprNode) -> ExprNode,
-) -> Vec<EIdx> {
-    exprs_map(out, exprs, &mut id, f)
-}
-
-fn decl_map_pre(
-    out: &mut Ir,
-    decl: D,
-    fe: &mut dyn FnMut(ExprNode) -> ExprNode,
-    ft: &mut dyn FnMut(Type) -> Type,
-) {
-    decl_map(out, decl, fe, &mut id, ft)
-}
-
-fn decl_map_post(
-    out: &mut Ir,
-    decl: D,
-    fe: &mut dyn FnMut(ExprNode) -> ExprNode,
-    ft: &mut dyn FnMut(Type) -> Type,
-) {
-    decl_map(out, decl, &mut id, fe, ft)
-}
-
-/// Takes a decl and applies the given expr and type transformers to any
-/// expression in it.
-///
-/// Technically not very necessary, since decls can't contain other decls,
-/// but happens often enough that it's worth having.
-fn decl_map(
-    out: &mut Ir,
-    decl: D,
-    fe_pre: &mut dyn FnMut(ExprNode) -> ExprNode,
-    fe_post: &mut dyn FnMut(ExprNode) -> ExprNode,
-    ft: &mut dyn FnMut(Type) -> Type,
-) {
-    let d = match decl {
-        D::Function {
-            name,
-            signature,
-            body,
-        } => D::Function {
-            name,
-            signature: signature_map(signature, ft),
-            body: exprs_map(out, body, fe_pre, fe_post),
-        },
-        D::Const { name, typ, init } => D::Const {
-            name,
-            typ: type_map(typ, ft),
-            init: expr_map(ir, out, init, fe_pre, fe_post),
-        },
-        D::TypeDef {
-            name,
-            params,
-            typedecl,
-        } => D::TypeDef {
-            name,
-            params,
-            typedecl: type_map(typedecl, ft),
-        },
-        D::Import { .. } => decl,
-    };
-    out.decls.push(d)
-}
-
-fn types_map(typs: Vec<Type>, f: &mut dyn FnMut(Type) -> Type) -> Vec<Type> {
-    typs.into_iter().map(|t| type_map(t, f)).collect()
-}
-
-/// Recursion scheme to turn one type into another.
-fn type_map(typ: Type, f: &mut dyn FnMut(Type) -> Type) -> Type {
-    /// Really this is only here to be cute, it's used a grand total of twice.
-    /// There's probably some horrible combinator chain we could use to make
-    /// it generic over any iterator, if we want to make life even harder for
-    /// ourself.
-    fn types_map_btree<K>(
-        typs: BTreeMap<K, Type>,
-        f: &mut dyn FnMut(Type) -> Type,
-    ) -> BTreeMap<K, Type>
-    where
-        K: Ord,
-    {
-        typs.into_iter()
-            .map(|(key, ty)| (key, type_map(ty, f)))
-            .collect()
-    }
-    let res = match typ {
-        Type::Struct(fields, generics) => {
-            let fields = types_map_btree(fields, f);
-            Type::Struct(fields, generics)
-        }
-        Type::Sum(fields, generics) => {
-            let new_fields = types_map_btree(fields, f);
-            Type::Sum(new_fields, generics)
-        }
-        Type::Array(ty, len) => Type::Array(Box::new(type_map(*ty, f)), len),
-        Type::Func(args, rettype, typeparams) => {
-            let new_args = types_map(args, f);
-            let new_rettype = type_map(*rettype, f);
-            let new_typeparams = types_map(typeparams, f);
-            Type::Func(new_args, Box::new(new_rettype), new_typeparams)
-        }
-        // Not super sure whether this is necessary, but can't hurt.
-        Type::Named(nm, tys) => Type::Named(nm, types_map(tys, f)),
-        Type::Prim(_) => typ,
-        Type::Never => typ,
-        Type::Enum(_) => typ,
-        Type::Generic(_) => typ,
-        Type::Uniq(t) => {
-            let new_t = type_map(*t, f);
-            Type::Uniq(Box::new(new_t))
-        }
-    };
-    f(res)
-}
-
-/// Produce a new signature by transforming the types
-fn signature_map(sig: hir::Signature, f: &mut dyn FnMut(Type) -> Type) -> hir::Signature {
-    let new_params = sig
-        .params
-        .into_iter()
-        .map(|(sym, ty)| (sym, type_map(ty, f)))
-        .collect();
-    hir::Signature {
-        params: new_params,
-        rettype: type_map(sig.rettype, f),
-        typeparams: types_map(sig.typeparams, f),
-    }
-}
-
-pub fn generate_type_name(typ: &Type) -> String {
-    match typ {
-        Type::Enum(fields) => {
-            let fieldnames: Vec<_> = fields
-                .iter()
-                .map(|(nm, vl)| format!("F{}_{}", nm, vl))
-                .collect();
-            let fieldstr = fieldnames.join("_");
-            format!("__Enum{}", fieldstr)
-        }
-        Type::Func(params, rettype, typeparams) => {
-            let paramnames: Vec<String> = params.iter().map(generate_type_name).collect();
-            let paramstr = paramnames.join("_");
-            let retname = generate_type_name(rettype);
-            let tparamnames: Vec<String> = typeparams.iter().map(generate_type_name).collect();
-            let tparamstr = tparamnames.join("_");
-            format!("__Func__{}__{}_{}", paramstr, retname, tparamstr)
-        }
-        Type::Struct(body, _) => {
-            let fieldnames: Vec<_> = body
-                .iter()
-                .map(|(nm, ty)| format!("{}_{}", nm, generate_type_name(ty)))
-                .collect();
-            let fieldstr = fieldnames.join("_");
-            format!("__Struct__{}", fieldstr)
-        }
-        Type::Sum(body, _) => {
-            let fieldnames: Vec<_> = body
-                .iter()
-                .map(|(nm, ty)| format!("{}_{}", nm, generate_type_name(ty)))
-                .collect();
-            let fieldstr = fieldnames.join("_");
-            format!("__Sum__{}", fieldstr)
-        }
-        Type::Generic(name) => {
-            format!("__G{}", name)
-        }
-        Type::Named(name, fields) => {
-            let field_names: Vec<_> = fields.iter().map(generate_type_name).collect();
-            let field_str = field_names.join("_");
-            format!("__Named{}__{}", name, field_str)
-        }
-        Type::Prim(p) => p.get_name().into_owned(),
-        Type::Never => format!("!"),
-        Type::Array(t, len) => {
-            format!("__Arr{}__{}", generate_type_name(t), len)
-        }
-        Type::Uniq(t) => {
-            format!("__Uniq__{}", generate_type_name(t))
-        }
-    }
-}
-
-#[cfg(test)]
-mod tests {
-    use super::*;
-    #[test]
-    fn test_expr_map(ir, )) {
-        fn swap_binop_args(expr: ExprNode) -> ExprNode {
-            trace!("Swapping {:?}", expr);
-            expr.map(&mut |e| match e {
-                E::BinOp { op, lhs, rhs } => E::BinOp {
-                    op,
-                    lhs: rhs,
-                    rhs: lhs,
-                },
-                other => other,
-            })
-        }
-        // Make sure this works for trivial exppressions
-        let inp = ExprNode::new(E::BinOp {
-            op: hir::BOp::Add,
-            lhs: ExprNode::int(3),
-            rhs: ExprNode::int(4),
-        });
-        let desired = ExprNode::new(E::BinOp {
-            op: hir::BOp::Add,
-            lhs: ExprNode::int(4),
-            rhs: ExprNode::int(3),
-        });
-        let out = expr_map_pre(inp, &mut swap_binop_args);
-        assert_eq!(out, desired);
-
-        // Make sure it recurses properly for deeper trees.
-        let inp2 = ExprNode::new(E::BinOp {
-            op: hir::BOp::Add,
-            lhs: ExprNode::new(E::BinOp {
-                op: hir::BOp::Sub,
-                lhs: ExprNode::int(100),
-                rhs: ExprNode::int(200),
-            }),
-            rhs: ExprNode::int(4),
-        });
-        let desired2 = ExprNode::new(E::BinOp {
-            op: hir::BOp::Add,
-            lhs: ExprNode::int(4),
-            rhs: ExprNode::new(E::BinOp {
-                op: hir::BOp::Sub,
-                lhs: ExprNode::int(200),
-                rhs: ExprNode::int(100),
-            }),
-        });
-        let out2 = expr_map_pre(inp2, &mut swap_binop_args);
-        assert_eq!(out2, desired2);
-    }
-
-    /// Test whether our pre-traversal expr map works properly.
-    #[test]
-    fn test_expr_pretraverse() {
-        let inp = ExprNode::new(E::Block {
-            body: vec![ExprNode::new(E::Var {
-                name: Sym::new("foo"),
-            })],
-        });
-        // Make a transformer that renames vars, and check in the Block
-        // body whether the inner var has been transformed.
-        let f = &mut |e: ExprNode| {
-            let helper = &mut |e| match e {
-                E::Var { .. } => E::Var {
-                    name: Sym::new("bar!"),
-                },
-                E::Block { body } => {
-                    // Has the name within the body been transformed yet?
-                    {
-                        let inner = &*body[0].e;
-                        assert_eq!(
-                            inner,
-                            &E::Var {
-                                name: Sym::new("foo")
-                            }
-                        );
-                    }
-                    E::Block { body }
-                }
-                _other => _other,
-            };
-            e.map(helper)
-        };
-        let outp = expr_map_pre(inp, f);
-        // Make sure that the actual transformation has done what we expected.
-        let expected = ExprNode::new(E::Block {
-            body: vec![ExprNode::new(E::Var {
-                name: Sym::new("bar!"),
-            })],
-        });
-        assert_eq!(outp, expected);
-    }
-
-    /// Similar to above with the case in helper() reversed
-    #[test]
-    fn test_expr_posttraverse() {
-        let inp = ExprNode::new(E::Block {
-            body: vec![ExprNode::new(E::Var {
-                name: Sym::new("foo"),
-            })],
-        });
-        let f = &mut |e: ExprNode| {
-            let helper = &mut |e| match e {
-                E::Var { .. } => E::Var {
-                    name: Sym::new("bar!"),
-                },
-                E::Block { body } => {
-                    // Has the name within the body been transformed yet?
-                    {
-                        let inner = &*body[0].e;
-                        assert_eq!(
-                            inner,
-                            &E::Var {
-                                name: Sym::new("bar!")
-                            }
-                        );
-                    }
-                    E::Block { body }
-                }
-                _other => _other,
-            };
-            e.map(helper)
-        };
-        let outp = expr_map_post(inp, f);
-        // Make sure that the actual transformation has done what we expected.
-        let expected = ExprNode::new(E::Block {
-            body: vec![ExprNode::new(E::Var {
-                name: Sym::new("bar!"),
-            })],
-        });
-        assert_eq!(outp, expected);
-    }
-}

          
R src/passes2/lambda_lift.rs =>  +0 -63
@@ 1,63 0,0 @@ 
-//! Lambda lifting.
-//!
-//! Basically take any function expression and turn it into
-//! a standalone function.
-//!
-//! Note this does NOT do closure conversion yet; this will break
-//! closures. We will need a spearate pass operating before this to take a
-//! closure, define an environment type for it, and turn it into
-//! a function taking an arg of that environment type.
-
-use crate::passes2::*;
-use crate::*;
-
-/// Lambda lift a single expr, creating a new toplevel function if necessary.
-fn lambda_lift_expr(out: &mut Ir, expr: ExprNode, output_funcs: &mut Vec<D>) -> EIdx {
-    let result = &mut |e| match e {
-        E::Lambda { signature, body } => {
-            // This is actually the only important bit.
-            // TODO: Make a more informative name, maybe including the file and line number or
-            // such.
-            let lambda_name = INT.gensym("lambda");
-            let function_decl = D::Function {
-                name: lambda_name,
-                signature,
-                body: exprs_map_pre(out, body, &mut |e| lambda_lift_expr(e, output_funcs)),
-            };
-            output_funcs.push(function_decl);
-            E::Var { name: lambda_name }
-        }
-        x => x,
-    };
-    expr.map(result)
-}
-
-/// A transformation pass that removes lambda expressions and turns
-/// them into function decl's.
-/// TODO: Doesn't handle actual closures yet though.  That should be a
-/// separate pass that happens first?
-///
-/// TODO: Output is a HIR tree that does not have any lambda expr's in it, which
-/// I would like to make un-representable, but don't see a good way
-/// to do yet.  Add a tag type of some kind to the Ir?
-/// Eeeeeeeeh we might just have to check on it later one way or another,
-/// either when doing codegen or when transforming our HIR to a lower-level IR.
-pub(super) fn lambda_lift(ir: Ir) -> Ir {
-    let mut new_functions = vec![];
-    let new_decls: Vec<D> = ir
-        .decls
-        .into_iter()
-        .map(|decl| {
-            decl_map_pre(
-                decl,
-                &mut |e| lambda_lift_expr(e, &mut new_functions),
-                &mut |t| t,
-            )
-        })
-        .collect();
-    new_functions.extend(new_decls.into_iter());
-    Ir {
-        decls: new_functions,
-        ..ir
-    }
-}