play around with benchmarking and Rc in types vs. Box.

The results are... not worth it, to say the least.  Rc'ing
vs Box'ing in types does indeed save a bit of time, about 10%,
in various passes since we probably avoid a lot of copying of types.
However, what takes the most time apart from executing rustc of course
is actually the parser!

Given my propensity for saying "parsing isn't slow, don't worry about
it" to new PL devs, all I can say is... lol.  lmao.

But it's still 60k lines a second or whatever, so it's fine even if
I expected it to be like 3x that.  But attempting to profile garnetfmt
(while commenting out anything it does besides parsing) results in
`perf` saying that 93% of the time is spent in
`__memmove_avx_unaligned_erms`.  And if that isn't a sign from on high
to shrug and get on with life then idk what is.  XD

If we wanna optimize types then really they should be interned and/or
flattened into a vec instead of a tree, I suspect.  Then the AST and
HIR should be flattened into a vec as well, though honestly they tend
to be allocated all together so I bet data locality is pretty
ok anyway.  But none of that matters compared to the parser!

Well this was a weird Learning Experience, I guess.
M benches/basic.rs +83 -19
@@ 5,7 5,7 @@ 
 
 use criterion::{black_box, criterion_group, criterion_main, Criterion};
 
-
+use garnet::*;
 
 /// Each iteration creates about 32 sLOC
 fn gen_dumb_test_code(count: usize) -> String {

          
@@ 66,33 66,22 @@ end
     buf
 }
 
-fn criterion_benchmark(c: &mut Criterion) {
+fn bench_with_rust_backend(c: &mut Criterion) {
     let code = gen_dumb_test_code(103);
     let lines = code.lines().count();
-    let name = format!("compile {}ish lines", lines);
+    let name = format!("compile {}ish lines to Rust", lines);
     c.bench_function(&name, |b| {
-        b.iter(|| {
-            garnet::compile(
-                "criterion.gt",
-                black_box(&code),
-                garnet::backend::Backend::Rust,
-            )
-        })
+        b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Rust))
     });
 
     let code = gen_dumb_test_code(103 * 8);
     let lines = code.lines().count();
-    let name = format!("compile {}ish lines", lines);
+    let name = format!("compile {}ish lines to Rust", lines);
     c.bench_function(&name, |b| {
-        b.iter(|| {
-            garnet::compile(
-                "criterion.gt",
-                black_box(&code),
-                garnet::backend::Backend::Rust,
-            )
-        })
+        b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Rust))
     });
 
+    /*
     let code = gen_dumb_test_code(103 * 16);
     let lines = code.lines().count();
     let name = format!("compile {}ish lines", lines);

          
@@ 105,7 94,82 @@ fn criterion_benchmark(c: &mut Criterion
             )
         })
     });
+    */
+}
+
+fn bench_with_null_backend(c: &mut Criterion) {
+    let code = gen_dumb_test_code(103);
+    let lines = code.lines().count();
+    let name = format!("compile {}ish lines to nothing", lines);
+    c.bench_function(&name, |b| {
+        b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Null))
+    });
+
+    let code = gen_dumb_test_code(103 * 8);
+    let lines = code.lines().count();
+    let name = format!("compile {}ish lines to nothing", lines);
+    c.bench_function(&name, |b| {
+        b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Null))
+    });
+
+    let code = gen_dumb_test_code(103 * 16);
+    let lines = code.lines().count();
+    let name = format!("compile {}ish lines to nothing", lines);
+    c.bench_function(&name, |b| {
+        b.iter(|| compile("criterion.gt", black_box(&code), backend::Backend::Rust))
+    });
 }
 
-criterion_group!(benches, criterion_benchmark);
+fn bench_stages(c: &mut Criterion) {
+    let code = gen_dumb_test_code(103 * 8);
+    let lines = code.lines().count();
+    let name = format!("Parse {} lines", lines);
+    c.bench_function(&name, |b| {
+        b.iter(|| {
+            let mut parser = parser::Parser::new("criterion.gt", black_box(&code));
+            parser.parse()
+        })
+    });
+
+    let mut parser = parser::Parser::new("criterion.gt", black_box(&code));
+    let ast = parser.parse();
+
+    c.bench_function("lower and run passes", |b| {
+        b.iter(|| {
+            let hir = hir::lower(black_box(&ast));
+            passes::run_passes(hir)
+        })
+    });
+
+    let hir = hir::lower(black_box(&ast));
+    let hir = passes::run_passes(hir);
+
+    c.bench_function("typecheck and borrowcheck", |b| {
+        b.iter(|| {
+            let tck = &mut typeck::typecheck(black_box(&hir)).unwrap();
+            borrowck::borrowck(&hir, tck).unwrap();
+        })
+    });
+
+    let tck = &mut typeck::typecheck(black_box(&hir)).unwrap();
+    borrowck::borrowck(&hir, tck).unwrap();
+
+    c.bench_function("typechecked passes", |b| {
+        b.iter(|| {
+            passes::run_typechecked_passes(black_box(hir.clone()), black_box(tck));
+        })
+    });
+
+    let hir = passes::run_typechecked_passes(hir, tck);
+    c.bench_function("codegen", |b| {
+        b.iter(|| backend::output(backend::Backend::Rust, black_box(&hir), black_box(tck)))
+    });
+}
+
+criterion_group!(
+    benches,
+    //bench_with_rust_backend,
+    //bench_with_null_backend,
+    bench_stages
+);
 criterion_main!(benches);

          
M src/ast.rs +7 -7
@@ 96,11 96,11 @@ pub struct IfCase {
 #[derive(Debug, Clone, PartialEq)]
 pub struct Signature {
     /// Parameters
-    pub params: Vec<(Sym, Type)>,
+    pub params: Arc<Vec<(Sym, Type)>>,
     /// Return type
     pub rettype: Type,
     /// Type parameters
-    pub typeparams: Vec<Type>,
+    pub typeparams: Arc<Vec<Type>>,
 }
 
 impl Signature {

          
@@ 108,8 108,8 @@ impl Signature {
     pub fn to_type(&self) -> Type {
         let paramtypes = self.params.iter().map(|(_nm, ty)| ty.clone()).collect();
         Type::Func(
-            paramtypes,
-            Box::new(self.rettype.clone()),
+            Arc::new(paramtypes),
+            Arc::new(self.rettype.clone()),
             self.typeparams.clone(),
         )
     }

          
@@ 150,14 150,14 @@ impl Signature {
                 let new_params = self
                     .params
                     .iter()
-                    .zip(params)
+                    .zip(params.as_ref())
                     .map(|((nm, _t1), t2)| (*nm, t2.clone()))
                     .collect();
                 let new_rettype = rettype.clone();
                 let new_type_params = typeparams.clone();
                 Self {
-                    params: new_params,
-                    rettype: *new_rettype,
+                    params: Arc::new(new_params),
+                    rettype: new_rettype.as_ref().clone(),
                     typeparams: new_type_params,
                 }
             }

          
M src/backend/rust.rs +4 -4
@@ 44,7 44,7 @@ fn compile_typename(t: &Type) -> Cow<'st
         Named(s, types) if s == &Sym::new("Tuple") => {
             trace!("Compiling tuple {:?}...", t);
             let mut accm = String::from("(");
-            for typ in types {
+            for typ in &**types {
                 accm += &compile_typename(typ);
                 accm += ", ";
             }

          
@@ 68,7 68,7 @@ fn compile_typename(t: &Type) -> Cow<'st
             }
             */
             accm += "(";
-            for p in params {
+            for p in &**params {
                 accm += &compile_typename(p);
                 accm += ", ";
             }

          
@@ 149,7 149,7 @@ fn compile_typename(t: &Type) -> Cow<'st
 /// Driver that turns a pile of Ir into Rust code.
 pub(super) fn output(lir: &hir::Ir, tck: &Tck) -> Vec<u8> {
     let mut output = Vec::new();
-    for builtin in &*builtins::BUILTINS {
+    for builtin in &*builtins::all() {
         output.extend(builtin.code[&backend::Backend::Rust].as_bytes());
     }
     for decl in lir.decls.iter() {

          
@@ 223,7 223,7 @@ fn compile_decl(w: &mut impl Write, decl
                         params.iter().map(|sym| (*sym.val()).clone()).collect();
                     let args = param_strings.join(", ");
                     writeln!(w, "pub enum {}<{}> {{ ", nstr, args)?;
-                    for (nm, ty) in body {
+                    for (nm, ty) in &**body {
                         writeln!(w, "    {} ({}),", nm, compile_typename(ty))?;
                     }
                     writeln!(w, "}}")?;

          
M src/bin/garnetfmt.rs +0 -1
@@ 39,7 39,6 @@ fn main() -> io::Result<()> {
     // anything
     let formatted_data = &formatted_src.into_inner();
     let formatted_str = String::from_utf8_lossy(formatted_data);
-    println!("{}", formatted_str);
     let formatted_ast = {
         let mut parser = parser::Parser::new(filename, &formatted_str);
         parser.parse()

          
M src/builtins.rs +45 -49
@@ 6,8 6,6 @@ 
 
 use std::collections::BTreeMap;
 
-use once_cell::sync::Lazy;
-
 use crate::backend::Backend;
 use crate::*;
 

          
@@ 22,8 20,6 @@ pub struct Builtin {
     pub code: BTreeMap<Backend, String>,
 }
 
-pub static BUILTINS: Lazy<Vec<Builtin>> = Lazy::new(Builtin::all);
-
 impl Builtin {
     /// Generate all appropriate methods for the given numeric type.
     /// Right now we just stick em in the toplevel with constructed names,

          
@@ 108,99 104,99 @@ fn __{name}_to_u32(x: {name}) -> u32 {{
         vec![
             Builtin {
                 name: Sym::new(format!("__println_{name}")),
-                sig: Type::Func(vec![ty.clone()], Box::new(Type::unit()), vec![]),
+                sig: Type::function(&vec![ty.clone()], &Type::unit(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, println)]),
             },
             Builtin {
                 name: Sym::new(format!("__band_{name}")),
-                sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, band)]),
             },
             Builtin {
                 name: Sym::new(format!("__bor_{name}")),
-                sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, bor)]),
             },
             Builtin {
                 name: Sym::new(format!("__bxor_{name}")),
-                sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, bxor)]),
             },
             Builtin {
                 name: Sym::new(format!("__bnot_{name}")),
-                sig: Type::Func(vec![ty.clone()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, bnot)]),
             },
             Builtin {
                 name: Sym::new(format!("__rshift_{name}")),
-                sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, rshift)]),
             },
             Builtin {
                 name: Sym::new(format!("__lshift_{name}")),
-                sig: Type::Func(vec![ty.clone(), ty.clone()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), ty.clone()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, lshift)]),
             },
             Builtin {
                 name: Sym::new(format!("__rol_{name}")),
-                sig: Type::Func(vec![ty.clone(), Type::i32()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), Type::i32()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, rol)]),
             },
             Builtin {
                 name: Sym::new(format!("__ror_{name}")),
-                sig: Type::Func(vec![ty.clone(), Type::i32()], Box::new(ty.clone()), vec![]),
+                sig: Type::function(&vec![ty.clone(), Type::i32()], &ty.clone(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, ror)]),
             },
             Builtin {
                 name: Sym::new(format!("__{name}_to_i32")),
-                sig: Type::Func(vec![ty.clone()], Box::new(Type::i32()), vec![]),
+                sig: Type::function(&vec![ty.clone()], &Type::i32(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, cast_i32)]),
             },
             Builtin {
                 name: Sym::new(format!("__{name}_to_u32")),
-                sig: Type::Func(vec![ty.clone()], Box::new(Type::u32()), vec![]),
+                sig: Type::function(&vec![ty.clone()], &Type::u32(), &vec![]),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, cast_u32)]),
             },
         ]
     }
-    /// A function that returns all the compiler builtin info.  Just
-    /// use the `BUILTINS` global instead, this is basically here
-    /// to initialize it.
-    fn all() -> Vec<Builtin> {
-        let rust_println = r#"fn __println(x: i32) {
+}
+/// A function that returns all the compiler builtin info.  Just
+/// use the `BUILTINS` global instead, this is basically here
+/// to initialize it.
+pub fn all() -> Vec<Builtin> {
+    let rust_println = r#"fn __println(x: i32) {
     println!("{}", x);
 }"#;
-        let rust_println_bool = r#"
+    let rust_println_bool = r#"
 fn __println_bool(x: bool) {
     println!("{}", x);
 }"#;
 
-        let mut funcs = vec![
-            Builtin {
-                name: Sym::new("__println"),
-                sig: Type::Func(vec![Type::i32()], Box::new(Type::unit()), vec![]),
-                code: BTreeMap::from([
-                    (Backend::Null, "".into()),
-                    (Backend::Rust, rust_println.into()),
-                ]),
-            },
-            Builtin {
-                name: Sym::new("__println_bool"),
-                sig: Type::Func(vec![Type::bool()], Box::new(Type::unit()), vec![]),
-                code: BTreeMap::from([
-                    (Backend::Null, "".into()),
-                    (Backend::Rust, rust_println_bool.into()),
-                ]),
-            },
-        ];
-        funcs.extend(Self::generate_numerics_for("i8", Type::i8()));
-        funcs.extend(Self::generate_numerics_for("i16", Type::i16()));
-        funcs.extend(Self::generate_numerics_for("i32", Type::i32()));
-        funcs.extend(Self::generate_numerics_for("i64", Type::i64()));
-        funcs.extend(Self::generate_numerics_for("u8", Type::u8()));
-        funcs.extend(Self::generate_numerics_for("u16", Type::u16()));
-        funcs.extend(Self::generate_numerics_for("u32", Type::u32()));
-        funcs.extend(Self::generate_numerics_for("u64", Type::u64()));
-        funcs
-    }
+    let mut funcs = vec![
+        Builtin {
+            name: Sym::new("__println"),
+            sig: Type::function(&vec![Type::i32()], &Type::unit(), &vec![]),
+            code: BTreeMap::from([
+                (Backend::Null, "".into()),
+                (Backend::Rust, rust_println.into()),
+            ]),
+        },
+        Builtin {
+            name: Sym::new("__println_bool"),
+            sig: Type::function(&vec![Type::bool()], &Type::unit(), &vec![]),
+            code: BTreeMap::from([
+                (Backend::Null, "".into()),
+                (Backend::Rust, rust_println_bool.into()),
+            ]),
+        },
+    ];
+    funcs.extend(Builtin::generate_numerics_for("i8", Type::i8()));
+    funcs.extend(Builtin::generate_numerics_for("i16", Type::i16()));
+    funcs.extend(Builtin::generate_numerics_for("i32", Type::i32()));
+    funcs.extend(Builtin::generate_numerics_for("i64", Type::i64()));
+    funcs.extend(Builtin::generate_numerics_for("u8", Type::u8()));
+    funcs.extend(Builtin::generate_numerics_for("u16", Type::u16()));
+    funcs.extend(Builtin::generate_numerics_for("u32", Type::u32()));
+    funcs.extend(Builtin::generate_numerics_for("u64", Type::u64()));
+    funcs
 }

          
M src/hir.rs +12 -11
@@ 768,10 768,10 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
             let struct_signature = ts
                 .iter()
                 //.map(|(enumname, _enumval)| (*enumname, ty.clone()))
-                .map(|(enumname, _enumval)| (*enumname, Type::Named(name, vec![])))
+                .map(|(enumname, _enumval)| (*enumname, Type::Named(name, Arc::new(vec![]))))
                 .collect();
             // Enums cannot have type parameters, so this works.
-            let init_type = Type::Struct(struct_signature, vec![]);
+            let init_type = Type::Struct(Arc::new(struct_signature), Arc::new(vec![]));
             let new_constdef = Const {
                 name,
                 typ: init_type,

          
@@ 798,7 798,7 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
                 .map(|(variant_name, variant_type)| {
                     let paramname = Sym::new("x");
                     let signature = ast::Signature {
-                        params: vec![(paramname, variant_type.clone())],
+                        params: Arc::new(vec![(paramname, variant_type.clone())]),
                         rettype: Type::Named(name, generics.clone()),
                         typeparams: generics.clone(),
                     };

          
@@ 822,15 822,15 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
                     // `fn(variant_type) name`
                     (
                         *variant_name,
-                        Type::Func(
-                            vec![variant_type.clone()],
-                            Box::new(Type::Named(name, generics.clone())),
-                            generics.clone(),
+                        Type::function(
+                            &[variant_type.clone()],
+                            &Type::Named(name, generics.clone()),
+                            &generics,
                         ),
                     )
                 })
                 .collect();
-            let struct_type = Type::Struct(struct_typebody, generics.clone());
+            let struct_type = Type::Struct(Arc::new(struct_typebody), generics.clone());
             let new_constdef = Const {
                 name: name.to_owned(),
                 typ: struct_type,

          
@@ 843,9 843,10 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
         other => {
             let s = Sym::new("x");
             trace!("Lowering params {:?}", params);
-            let type_params: Vec<_> = params.iter().map(|s| Type::Generic(*s)).collect();
+            let type_params: Arc<Vec<_>> =
+                Arc::new(params.iter().map(|s| Type::Generic(*s)).collect());
             let signature = ast::Signature {
-                params: vec![(s, other.clone())],
+                params: Arc::new(vec![(s, other.clone())]),
                 rettype: Type::Named(name.to_owned(), type_params.clone()),
                 typeparams: type_params.clone(),
             };

          
@@ 853,7 854,7 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
             // in a type constructor
             let body = vec![ExprNode::new(Expr::TypeCtor {
                 name,
-                type_params,
+                type_params: type_params.to_vec(),
                 body: ExprNode::new(Expr::Var { name: s }),
             })];
             //println!("{} is {:#?}", variant_name, e);

          
M src/lib.rs +40 -28
@@ 12,7 12,7 @@ use once_cell::sync::Lazy;
 
 mod ast;
 pub mod backend;
-mod borrowck;
+pub mod borrowck;
 mod builtins;
 pub mod format;
 pub mod hir;

          
@@ 74,26 74,26 @@ pub enum Type {
     /// Never type, the type of an infinite loop
     Never,
     /// A C-like enum, and the integer values it corresponds to
-    Enum(Vec<(Sym, i32)>),
+    Enum(Arc<Vec<(Sym, i32)>>),
     /// A nominal type of some kind; may be built-in (like Tuple)
     /// or user-defined.
-    Named(Sym, Vec<Type>),
+    Named(Sym, Arc<Vec<Type>>),
     /// A function pointer.
     ///
     /// The contents are arg types, return types, type parameters
-    Func(Vec<Type>, Box<Type>, Vec<Type>),
+    Func(Arc<Vec<Type>>, Arc<Type>, Arc<Vec<Type>>),
     /// An anonymous struct.  The vec is type parameters.
-    Struct(BTreeMap<Sym, Type>, Vec<Type>),
+    Struct(Arc<BTreeMap<Sym, Type>>, Arc<Vec<Type>>),
     /// Sum type.
     ///
     /// Like structs, contains a list of type parameters.
-    Sum(BTreeMap<Sym, Type>, Vec<Type>),
+    Sum(Arc<BTreeMap<Sym, Type>>, Arc<Vec<Type>>),
     /// Arrays are just a type and a number.
-    Array(Box<Type>, usize),
+    Array(Arc<Type>, usize),
     /// A generic type parameter that has been given an explicit name.
     Generic(Sym),
     /// Unique borrow
-    Uniq(Box<Type>),
+    Uniq(Arc<Type>),
 }
 
 impl Type {

          
@@ 112,32 112,32 @@ impl Type {
                 Type::Never => (),
                 Type::Enum(_ts) => (),
                 Type::Named(_, generics) => {
-                    for g in generics {
+                    for g in &**generics {
                         helper(g, accm);
                     }
                 }
                 Type::Func(args, rettype, typeparams) => {
-                    for t in args {
+                    for t in &**args {
                         helper(t, accm);
                     }
-                    for t in typeparams {
+                    for t in &**typeparams {
                         helper(t, accm);
                     }
                     helper(rettype, accm)
                 }
                 Type::Struct(body, generics) => {
-                    for (_, ty) in body {
+                    for (_, ty) in &**body {
                         helper(ty, accm);
                     }
-                    for g in generics {
+                    for g in &**generics {
                         helper(g, accm);
                     }
                 }
                 Type::Sum(body, generics) => {
-                    for (_, ty) in body {
+                    for (_, ty) in &**body {
                         helper(ty, accm);
                     }
-                    for g in generics {
+                    for g in &**generics {
                         helper(g, accm);
                     }
                 }

          
@@ 238,22 238,30 @@ impl Type {
 
     /// Shortcut for getting the type for Unit
     pub fn unit() -> Self {
-        Self::Named(Sym::new("Tuple"), vec![])
+        Self::Named(Sym::new("Tuple"), Arc::new(vec![]))
     }
 
     /// Shortcut for getting the type for Never
     pub fn never() -> Self {
-        Self::Named(Sym::new("Never"), vec![])
+        Self::Named(Sym::new("Never"), Arc::new(vec![]))
     }
 
     /// Create a Tuple with the given values
-    pub fn tuple(args: Vec<Self>) -> Self {
+    pub fn tuple(args: Arc<Vec<Self>>) -> Self {
         Self::Named(Sym::new("Tuple"), args)
     }
 
     /// Used in some tests
     pub fn array(t: &Type, len: usize) -> Self {
-        Self::Array(Box::new(t.clone()), len)
+        Self::Array(Arc::new(t.clone()), len)
+    }
+
+    fn function(params: &[Type], rettype: &Type, generics: &[Type]) -> Self {
+        Type::Func(
+            Arc::new(Vec::from(params)),
+            Arc::new(rettype.clone()),
+            Arc::new(Vec::from(generics)),
+        )
     }
 
     fn _is_integer(&self) -> bool {

          
@@ 399,7 407,7 @@ impl Type {
             // Types are identical, noop.
             (s, o) if s == o => (),
             (Type::Named(n1, args1), Type::Named(n2, args2)) if n1 == n2 => {
-                for (p1, p2) in args1.iter().zip(args2) {
+                for (p1, p2) in (&**args1).iter().zip(&**args2) {
                     p1._find_substs(p2, substitutions);
                 }
             }

          
@@ 416,7 424,7 @@ impl Type {
                 if typeparams1.len() > 0 {
                     todo!()
                 }
-                for (p1, p2) in params1.iter().zip(params2) {
+                for (p1, p2) in (&**params1).iter().zip(&**params2) {
                     p1._find_substs(p2, substitutions);
                 }
                 rettype1._find_substs(rettype2, substitutions);

          
@@ 438,11 446,11 @@ impl Type {
                 if !body1.keys().eq(body2.keys()) {
                     panic!("subst for sum type had non-matching keys")
                 }
-                for ((_nm1, t1), (_nm2, t2)) in body1.iter().zip(body2) {
+                for ((_nm1, t1), (_nm2, t2)) in (&**body1).iter().zip(&**body2) {
                     t1._find_substs(t2, substitutions);
                 }
 
-                for (p1, p2) in generics1.iter().zip(generics2) {
+                for (p1, p2) in (&**generics1).iter().zip(&**generics2) {
                     p1._find_substs(p2, substitutions);
                 }
             }

          
@@ 480,11 488,15 @@ impl Type {
                 if typeparams1.len() > 0 {
                     todo!("Hsfjkdslfjs");
                 }
-                Type::Func(new_params, Box::new(new_rettype), vec![])
+                Type::Func(
+                    Arc::new(new_params),
+                    Arc::new(new_rettype),
+                    Arc::new(vec![]),
+                )
             }
             Type::Named(n1, args1) => {
                 let new_args = args1.iter().map(|p1| p1._apply_substs(substs)).collect();
-                Type::Named(*n1, new_args)
+                Type::Named(*n1, Arc::new(new_args))
             }
             Type::Struct(_, _) => unreachable!("see other unreachable in substitute()"),
             Type::Sum(body, generics) => {

          
@@ 493,9 505,9 @@ impl Type {
                     .map(|(nm, ty)| (*nm, ty._apply_substs(substs)))
                     .collect();
                 let new_generics = generics.iter().map(|p1| p1._apply_substs(substs)).collect();
-                Type::Sum(new_body, new_generics)
+                Type::Sum(Arc::new(new_body), Arc::new(new_generics))
             }
-            Type::Array(body, len) => Type::Array(Box::new(body._apply_substs(substs)), *len),
+            Type::Array(body, len) => Type::Array(Arc::new(body._apply_substs(substs)), *len),
             Type::Generic(nm) => substs
                 .get(&nm)
                 .unwrap_or_else(|| panic!("No substitution found for generic named {}!", nm))

          
@@ 625,7 637,7 @@ mod tests {
     #[test]
     fn check_name_format() {
         let args = vec![Type::i32(), Type::bool()];
-        let def = Type::Func(args, Box::new(Type::i32()), vec![]);
+        let def = Type::function(&args, &Type::i32(), &vec![]);
         let gotten_name = def.get_name();
         let desired_name = "fn(I32, Bool) I32";
         assert_eq!(&gotten_name, desired_name);

          
M src/parser.rs +12 -12
@@ 706,9 706,9 @@ impl<'input> Parser<'input> {
         let (params, typeparams) = self.parse_fn_args();
         let rettype = self.try_parse_type().unwrap_or(Type::unit());
         ast::Signature {
-            params,
+            params: Arc::new(params),
             rettype,
-            typeparams,
+            typeparams: Arc::new(typeparams),
         }
     }
 

          
@@ 795,7 795,7 @@ impl<'input> Parser<'input> {
     fn parse_fn_type(&mut self) -> Type {
         let (params, typeparams) = self.parse_type_list_with_typeparams();
         let rettype = self.try_parse_type().unwrap_or(Type::unit());
-        Type::Func(params, Box::new(rettype), typeparams)
+        Type::function(&params, &rettype, &typeparams)
     }
 
     /// Parse the fields for a struct *type decl*

          
@@ 890,19 890,19 @@ impl<'input> Parser<'input> {
             }
         });
         self.expect(T::RBrace);
-        Some(Type::tuple(body))
+        Some(Type::tuple(Arc::new(body)))
     }
 
     fn try_parse_struct_type(&mut self) -> Option<Type> {
         let (fields, type_params) = self.parse_struct_fields();
         self.expect(T::End);
-        Some(Type::Struct(fields, type_params))
+        Some(Type::Struct(Arc::new(fields), Arc::new(type_params)))
     }
 
     fn parse_enum_type(&mut self) -> Type {
         let variants = self.parse_enum_fields();
         self.expect(T::End);
-        Type::Enum(variants)
+        Type::Enum(Arc::new(variants))
     }
 
     /// isomorphic-ish with parse_type_list()

          
@@ 941,7 941,7 @@ impl<'input> Parser<'input> {
             .map(|ty| Type::Generic(ty))
             .collect();
         */
-        Type::Sum(fields, generics)
+        Type::Sum(Arc::new(fields), Arc::new(generics))
     }
 
     fn parse_exprs(&mut self) -> Vec<ast::Expr> {

          
@@ 1384,7 1384,7 @@ impl<'input> Parser<'input> {
                     } else {
                         vec![]
                     };
-                    Type::Named(Sym::new(s), type_params)
+                    Type::Named(Sym::new(s), Arc::new(type_params))
                 }
             }
             T::At => {

          
@@ 1401,11 1401,11 @@ impl<'input> Parser<'input> {
                 assert!(len >= 0);
                 self.expect(T::RBracket);
                 let inner = self.parse_type();
-                Type::Array(Box::new(inner), len as usize)
+                Type::Array(Arc::new(inner), len as usize)
             }
             T::Ampersand => {
                 let next = self.try_parse_type()?;
-                Type::Uniq(Box::new(next))
+                Type::Uniq(Arc::new(next))
             }
             _ => {
                 // Wind the parse stream back to wherever we started

          
@@ 1552,9 1552,9 @@ mod tests {
             ast::Decl::Function {
                 name: Sym::new("foo"),
                 signature: ast::Signature {
-                    params: vec![(Sym::new("x"), i32_t.clone())],
+                    params: Arc::new(vec![(Sym::new("x"), i32_t.clone())]),
                     rettype: i32_t,
-                    typeparams: vec![],
+                    typeparams: Arc::new(vec![]),
                 },
                 body: vec![Expr::int(9)],
                 doc_comment: vec![],

          
M src/passes.rs +18 -15
@@ 319,8 319,8 @@ fn decl_map(
     }
 }
 
-fn types_map(typs: Vec<Type>, f: &mut dyn FnMut(Type) -> Type) -> Vec<Type> {
-    typs.into_iter().map(|t| type_map(t, f)).collect()
+fn types_map(typs: Arc<Vec<Type>>, f: &mut dyn FnMut(Type) -> Type) -> Arc<Vec<Type>> {
+    Arc::new(typs.iter().cloned().map(|t| type_map(t, f)).collect())
 }
 
 /// Recursion scheme to turn one type into another.

          
@@ 330,15 330,17 @@ fn type_map(typ: Type, f: &mut dyn FnMut
     /// it generic over any iterator, if we want to make life even harder for
     /// ourself.
     fn types_map_btree<K>(
-        typs: BTreeMap<K, Type>,
+        typs: Arc<BTreeMap<K, Type>>,
         f: &mut dyn FnMut(Type) -> Type,
-    ) -> BTreeMap<K, Type>
+    ) -> Arc<BTreeMap<K, Type>>
     where
-        K: Ord,
+        K: Ord + Clone,
     {
-        typs.into_iter()
-            .map(|(key, ty)| (key, type_map(ty, f)))
-            .collect()
+        Arc::new(
+            typs.iter()
+                .map(|(key, ty)| (key.clone(), type_map(ty.clone(), f)))
+                .collect(),
+        )
     }
     let res = match typ {
         Type::Struct(fields, generics) => {

          
@@ 349,12 351,12 @@ fn type_map(typ: Type, f: &mut dyn FnMut
             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::Array(ty, len) => Type::array(&type_map(ty.as_ref().clone(), f), len),
         Type::Func(args, rettype, typeparams) => {
             let new_args = types_map(args, f);
-            let new_rettype = type_map(*rettype, f);
+            let new_rettype = type_map(rettype.as_ref().clone(), f);
             let new_typeparams = types_map(typeparams, f);
-            Type::Func(new_args, Box::new(new_rettype), new_typeparams)
+            Type::function(&new_args, &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)),

          
@@ 363,8 365,8 @@ fn type_map(typ: Type, f: &mut dyn FnMut
         Type::Enum(_) => typ,
         Type::Generic(_) => typ,
         Type::Uniq(t) => {
-            let new_t = type_map(*t, f);
-            Type::Uniq(Box::new(new_t))
+            let new_t = type_map(t.as_ref().clone(), f);
+            Type::Uniq(Arc::new(new_t))
         }
     };
     f(res)

          
@@ 374,11 376,12 @@ fn type_map(typ: Type, f: &mut dyn FnMut
 fn signature_map(sig: hir::Signature, f: &mut dyn FnMut(Type) -> Type) -> hir::Signature {
     let new_params = sig
         .params
-        .into_iter()
+        .iter()
+        .cloned()
         .map(|(sym, ty)| (sym, type_map(ty, f)))
         .collect();
     hir::Signature {
-        params: new_params,
+        params: Arc::new(new_params),
         rettype: type_map(sig.rettype, f),
         typeparams: types_map(sig.typeparams, f),
     }

          
M src/passes/struct_to_tuple.rs +10 -10
@@ 38,9 38,11 @@ fn tuplize_type(typ: Type) -> Type {
             // on the field names.
 
             // TODO: What do we do with generics?  Anything?
-            let tuple_fields = fields.values().map(|ty| type_map(ty.clone(), &mut tuplize_type))
+            let tuple_fields = fields
+                .values()
+                .map(|ty| type_map(ty.clone(), &mut tuplize_type))
                 .collect();
-            Type::tuple(tuple_fields)
+            Type::tuple(Arc::new(tuple_fields))
         }
         other => other,
     }

          
@@ 77,10 79,7 @@ fn tuplize_expr(expr: ExprNode, tck: &mu
                     .map(|(ky, vl)| (offset_of_field(type_body, ky), vl))
                     .collect();
                 ordered_body.sort_by(|a, b| a.0.cmp(&b.0));
-                let new_body = ordered_body
-                    .into_iter()
-                    .map(|(_i, expr)| expr)
-                    .collect();
+                let new_body = ordered_body.into_iter().map(|(_i, expr)| expr).collect();
 
                 E::TupleCtor { body: new_body }
             }

          
@@ 271,14 270,15 @@ mod tests {
         let mut body = BTreeMap::new();
         body.insert(Sym::new("foo"), Type::i32());
         body.insert(Sym::new("bar"), Type::i64());
+        let body = Arc::new(body);
 
-        let desired = tuplize_type(Type::Struct(body.clone(), vec![]));
-        let inp = Type::Struct(body, vec![]);
+        let desired = tuplize_type(Type::Struct(body.clone(), Arc::new(vec![])));
+        let inp = Type::Struct(body, Arc::new(vec![]));
         let out = type_map(inp.clone(), &mut tuplize_type);
         assert_eq!(out, desired);
 
-        let desired2 = Type::Array(Box::new(out), 3);
-        let inp2 = Type::Array(Box::new(inp), 3);
+        let desired2 = Type::array(&out, 3);
+        let inp2 = Type::array(&inp, 3);
         let out2 = type_map(inp2, &mut tuplize_type);
         assert_eq!(out2, desired2);
     }

          
M src/typeck.rs +20 -17
@@ 409,7 409,7 @@ impl Tck {
         let tinfo = match t {
             Type::Prim(ty) => TypeInfo::Prim(*ty),
             Type::Never => TypeInfo::Never,
-            Type::Enum(vals) => TypeInfo::Enum(vals.clone()),
+            Type::Enum(vals) => TypeInfo::Enum((&**vals).clone()),
             Type::Named(s, args) => {
                 let new_args = args.iter().map(|t| self.insert_known(t)).collect();
                 TypeInfo::Named(*s, new_args)

          
@@ 726,11 726,11 @@ impl Tck {
             Never => Ok(Type::Never),
             Prim(ty) => Ok(Type::Prim(*ty)),
             Ref(id) => self.reconstruct(*id),
-            Enum(ts) => Ok(Type::Enum(ts.clone())),
+            Enum(ts) => Ok(Type::Enum(Arc::new(ts.clone()))),
             Named(s, args) => {
                 let arg_types: Result<Vec<_>, _> =
                     args.iter().map(|x| self.reconstruct(*x)).collect();
-                Ok(Type::Named(*s, arg_types?))
+                Ok(Type::Named(*s, Arc::new(arg_types?)))
             }
             Func(args, rettype, typeparams) => {
                 let real_args: Result<Vec<Type>, TypeError> =

          
@@ 738,10 738,12 @@ impl Tck {
                 let type_param_types: Result<Vec<Type>, _> =
                     typeparams.iter().map(|x| self.reconstruct(*x)).collect();
 
-                Ok(Type::Func(
-                    real_args?,
-                    Box::new(self.reconstruct(*rettype)?),
-                    type_param_types?,
+                let real_args = real_args?;
+                let type_param_types = type_param_types?;
+                Ok(Type::function(
+                    &real_args,
+                    &self.reconstruct(*rettype)?,
+                    &type_param_types,
                 ))
             }
             TypeParam(name) => Ok(Type::Generic(*name)),

          
@@ 755,11 757,11 @@ impl Tck {
                     .collect();
                 // TODO: The empty params here feels suspicious, verify.
                 let params = vec![];
-                Ok(Type::Struct(real_body?, params))
+                Ok(Type::Struct(Arc::new(real_body?), Arc::new(params)))
             }
             Array(ty, len) => {
                 let real_body = self.reconstruct(*ty)?;
-                Ok(Type::Array(Box::new(real_body), len.unwrap()))
+                Ok(Type::array(&real_body, len.unwrap()))
             }
             Sum(body) => {
                 let real_body: Result<BTreeMap<_, _>, TypeError> = body

          
@@ 770,11 772,11 @@ impl Tck {
                     })
                     .collect();
                 let params = vec![];
-                Ok(Type::Sum(real_body?, params))
+                Ok(Type::Sum(Arc::new(real_body?), Arc::new(params)))
             }
             Uniq(ty) => {
                 let inner_type = self.reconstruct(*ty)?;
-                Ok(Type::Uniq(Box::new(inner_type)))
+                Ok(Type::Uniq(Arc::new(inner_type)))
             }
         }
     }

          
@@ 804,7 806,7 @@ impl Tck {
             let typeinfo = match t {
                 Type::Prim(val) => TypeInfo::Prim(*val),
                 Type::Never => TypeInfo::Never,
-                Type::Enum(vals) => TypeInfo::Enum(vals.clone()),
+                Type::Enum(vals) => TypeInfo::Enum((**vals).clone()),
                 Type::Named(s, args) => {
                     let inst_args: Vec<_> =
                         args.iter().map(|t| helper(tck, named_types, t)).collect();

          
@@ 914,7 916,7 @@ impl Drop for ScopeGuard {
 
 impl Symtbl {
     fn add_builtins(&self, tck: &mut Tck) {
-        for builtin in &*builtins::BUILTINS {
+        for builtin in &*builtins::all() {
             let ty = tck.insert_known(&builtin.sig);
             self.add_var(builtin.name, ty, false);
         }

          
@@ 1008,7 1010,7 @@ fn typecheck_func_body(
     */
     // Insert info about the function signature
     let mut params = vec![];
-    for (_paramname, paramtype) in &signature.params {
+    for (_paramname, paramtype) in &*signature.params {
         let p = tck.insert_known(paramtype);
         params.push(p);
     }

          
@@ 1031,7 1033,7 @@ fn typecheck_func_body(
 
     // Add params to function's scope
     let _guard = symtbl.push_scope();
-    for (paramname, paramtype) in &signature.params {
+    for (paramname, paramtype) in &*signature.params {
         let p = tck.insert_known(paramtype);
         symtbl.add_var(*paramname, p, false);
     }

          
@@ 1472,7 1474,8 @@ fn typecheck_expr(
             tck.unify(symtbl, tid, body_type)?;
             trace!("Done unifying type ctor");
             // The type the expression returns
-            let constructed_type = tck.insert_known(&Type::Named(*name, type_params.clone()));
+            let constructed_type =
+                tck.insert_known(&Type::Named(*name, Arc::new(type_params.clone())));
             tck.set_expr_type(expr, constructed_type);
             Ok(constructed_type)
         }

          
@@ 1623,7 1626,7 @@ fn predeclare_decls(tck: &mut Tck, symtb
             } => {
                 // TODO: Kinda duplicated, not a huge fan.
                 let mut params = vec![];
-                for (_paramname, paramtype) in &signature.params {
+                for (_paramname, paramtype) in &*signature.params {
                     let p = tck.insert_known(paramtype);
                     params.push(p);
                 }