jfc I forgot to commit this apparently
6 files changed, 174 insertions(+), 13 deletions(-)

M src/backend/rust2.rs
M src/builtins.rs
M src/hir2.rs
M src/nbe.rs
M src/simptbl.rs
M tests/programs/hello1.gt => tests/programs/test_hello2.gt
M src/backend/rust2.rs +5 -7
@@ 12,8 12,6 @@ use std::io::{self, Write};
 
 use log::*;
 
-use crate::typeck::Tck;
-use crate::types::*;
 use crate::*;
 
 /// Compiles a `Type` into a a valid Rust type.

          
@@ 161,7 159,7 @@ pub(super) fn output(ir: &hir2::Ir) -> V
     output
 }
 
-fn compile_import(w: &mut impl Write, ir: &hir2::Import) -> io::Result<()> {
+fn compile_import(_w: &mut impl Write, _ir: &hir2::Import) -> io::Result<()> {
     todo!()
 }
 

          
@@ 421,10 419,10 @@ fn compile_expr(expr: &hir2::ENode) -> S
         }
         E::Block { body } => format!("{{\n{}\n}}", compile_exprs(body, ";\n")),
         E::Let {
-            varname,
+            varname: _,
             typename: _,
-            init,
-            mutable,
+            init: _,
+            mutable: _,
         } => {
             todo!("tck")
             /*

          
@@ 524,7 522,7 @@ fn compile_expr(expr: &hir2::ENode) -> S
             // panic!("Should never happen, structs should always be tuples by now!");
             format!("{}.{}", compile_expr(expr), elt)
         }
-        E::TupleRef { expr, elt } => {
+        E::TupleRef { expr: _, elt: _ } => {
             todo!("tck")
             /*
             // We turn our structs into Rust tuples, so we need to

          
M src/builtins.rs +3 -0
@@ 2,6 2,7 @@ 
 //! instead of having them scattered all over.
 
 use crate::backend::Backend;
+use crate::hir2::{Type as Type2, TypeNode as TN};
 use crate::types::*;
 use crate::*;
 

          
@@ 11,6 12,7 @@ pub struct Builtin {
     pub name: Sym,
     /// The value's type, used for typechecking
     pub sig: Type,
+    pub sig2: hir2::TypeNode,
     /// The implmentation of the builtin as raw code for each particular
     /// backend.
     pub code: BTreeMap<Backend, String>,

          
@@ 103,6 105,7 @@ fn __{name}_to_u32(x: {name}) -> u32 {{
             Builtin {
                 name: Sym::new(format!("__println_{name}")),
                 sig: Type::Func(vec![ty.clone()], Box::new(Type::unit()), vec![]),
+                sig2: TN::function(vec![ty.clone()], TN::unit()),
                 code: BTreeMap::from([(Backend::Null, "".into()), (Backend::Rust, println)]),
             },
             Builtin {

          
M src/hir2.rs +139 -0
@@ 62,6 62,145 @@ impl TypeNode {
     pub fn get_mangled_name(&self) -> String {
         self.t.get_mangled_name()
     }
+
+    pub fn struct_(body: BTreeMap<Sym, Self>) -> Self {
+        Self::new(Type::Struct(body))
+    }
+
+    /// Shortcut for getting the type for an unknown int
+    pub fn iunknown() -> Self {
+        Self::new(Type::Prim(PrimType::UnknownInt))
+    }
+
+    /// Shortcut for getting the Type for a signed int of a particular size
+    pub fn isize(size: u8) -> Self {
+        Self::new(Type::Prim(PrimType::Int(size, true)))
+    }
+
+    /// Shortcut for getting the Type for an unsigned signed int of a particular size
+    pub fn usize(size: u8) -> Self {
+        Self::new(Type::Prim(PrimType::Int(size, false)))
+    }
+
+    /// Shortcut for getting the Type for I128
+    pub fn i128() -> Self {
+        Self::isize(16)
+    }
+
+    /// Shortcut for getting the Type for I64
+    pub fn i64() -> Self {
+        Self::isize(8)
+    }
+
+    /// Shortcut for getting the Type for I32
+    pub fn i32() -> Self {
+        Self::isize(4)
+    }
+
+    /// Shortcut for getting the type for I16
+    pub fn i16() -> Self {
+        Self::isize(2)
+    }
+
+    /// Shortcut for getting the type for I8
+    pub fn i8() -> Self {
+        Self::isize(1)
+    }
+
+    /// Shortcut for getting the Type for U128
+    pub fn u128() -> Self {
+        Self::usize(16)
+    }
+
+    /// Shortcut for getting the Type for U64
+    pub fn u64() -> Self {
+        Self::usize(8)
+    }
+
+    /// Shortcut for getting the Type for U32
+    pub fn u32() -> Self {
+        Self::usize(4)
+    }
+
+    /// Shortcut for getting the type for U16
+    pub fn u16() -> Self {
+        Self::usize(2)
+    }
+
+    /// Shortcut for getting the type for U8
+    pub fn u8() -> Self {
+        Self::usize(1)
+    }
+
+    /// Shortcut for getting the type for Bool
+    pub fn bool() -> Self {
+        Self::new(Type::Prim(PrimType::Bool))
+    }
+
+    /// Shortcut for getting the type for Unit
+    pub fn unit() -> Self {
+        Self::new(Type::Tuple(vec![]))
+    }
+
+    /// Shortcut for getting the type for Never
+    pub fn never() -> Self {
+        // Self::new(Named(Sym::new("Never"), vec![])
+        todo!()
+    }
+
+    /// Create a Tuple with the given values
+    pub fn tuple(args: &[Self]) -> Self {
+        Self::new(Type::Tuple(args.to_vec()))
+    }
+
+    /// Used in some tests
+    pub fn array(t: &TypeNode, len: usize) -> Self {
+        Self::new(Type::Array(t.clone(), len))
+    }
+
+    /// Shortcut for a named type with no type params
+    // pub fn named0(s: impl AsRef<str>) -> Self {
+    pub fn named0(_s: Sym) -> Self {
+        // Type::Var(s, vec![])
+        todo!()
+    }
+    pub fn function(params: &[TypeNode], rettype: &Type) -> Self {
+        TypeNode::new(Type::Func(
+            Vec::from(params),
+            TypeNode::new(rettype.clone()),
+        ))
+    }
+
+    pub fn is_func(&self) -> bool {
+        matches!(&*self.t, &Type::Func(_, _))
+    }
+
+    /// Takes a string and matches it against the builtin/
+    /// primitive types, returning the appropriate `TypeDef`
+    ///
+    /// If it is not a built-in type, or is a compound such
+    /// as a tuple or struct, returns None.
+    ///
+    /// The effective inverse of `TypeDef::get_name()`.  Compound
+    /// types take more parsing to turn from strings to `TypeDef`'s
+    /// and are handled in `parser::parse_type()`.
+    pub fn get_primitive_type(s: &str) -> Option<Type> {
+        match s {
+            "I8" => Some(Type::i8()),
+            "I16" => Some(Type::i16()),
+            "I32" => Some(Type::i32()),
+            "I64" => Some(Type::i64()),
+            "I128" => Some(Type::i128()),
+            "U8" => Some(Type::u8()),
+            "U16" => Some(Type::u16()),
+            "U32" => Some(Type::u32()),
+            "U64" => Some(Type::u64()),
+            "U128" => Some(Type::u128()),
+            "Bool" => Some(Type::bool()),
+            "Never" => Some(Type::never()),
+            _ => None,
+        }
+    }
 }
 
 impl From<&Type> for TypeNode {

          
M src/nbe.rs +26 -5
@@ 45,7 45,7 @@ pub struct Env {
     // figure out around vars and indices before I actually
     // switch everything over.  This is basically a placeholder
     // to make the transition simpler later.
-    _vals: Vector<ValBinding>,
+    vals: Vector<ValBinding>,
 
     /// Where we record our association of expressions to their types
     /// for type inference/unification. Maybe should be its own type passed

          
@@ 156,10 156,16 @@ impl Env {
         self.types.len()
     }
 
-    /// Binds a variable to a name.
+    fn add_binding(&self, vl: ValBinding) -> Self {
+        let mut s = self.clone();
+        s.vals.push_back(vl.clone());
+        s
+    }
+
+    /// Binds a type variable to a name.
     /// Not suuuuure yet whether we need to juggle bindings separately
     /// from values?  Yeah we do.
-    fn add_binding(&self, vl: TypeBinding) -> Self {
+    fn add_type_binding(&self, vl: TypeBinding) -> Self {
         let mut s = self.clone();
         s.types.push_back(vl.clone());
         s

          
@@ 171,7 177,7 @@ impl Env {
     fn add_neu_binding(&self, name: Sym, kind: Kind) -> Self {
         let varlvl = Lvl(self.size() + 1); // new var is at the top of our bindings env, plus one
         let vartype = NType::Neu(Neutral::Var(varlvl, name));
-        self.add_binding(TypeBinding::TypeVar(vartype, kind, name))
+        self.add_type_binding(TypeBinding::TypeVar(vartype, kind, name))
     }
 
     /// Look up a bound value by de Bruijn index.

          
@@ 867,6 873,20 @@ impl Env {
         self.set_expr_type(e, &res);
         Ok(res)
     }
+
+    fn add_builtins(&self) -> Self {
+        let mut res = self.clone();
+        for builtin in &*builtins::BUILTINS {
+            let ty = self
+                .eval_type(builtin.sig2.clone())
+                .expect("Builtin has invalid type, shouldn't happen");
+            // let binding = ValBinding::Var(NType::, )
+            // *res = self.add_binding(builtin.)
+            // let ty = tck.insert_known(&builtin.sig);
+            // self.add_var(builtin.name, ty, false);
+        }
+        res
+    }
 }
 
 /// Our quote operation that just translates our NbE world back into

          
@@ 962,7 982,7 @@ pub fn inst(c: Closure, args: &[NType]) 
     // bind the closure's args to the given type variable names, and eval it.
     let mut new_env = env;
     for ((nm, declared_kind), arg) in nms.into_iter().zip(args) {
-        new_env = new_env.add_binding(TypeBinding::TypeVar(
+        new_env = new_env.add_type_binding(TypeBinding::TypeVar(
             arg.clone(),
             declared_kind.clone(),
             nm.clone(),

          
@@ 1091,6 1111,7 @@ fn predeclare_decls(_env: &mut Env, ir: 
 /// Or just the part of the Env that
 pub fn typecheck(ir: &hir2::Ir) -> Result<(), String> {
     let env = &mut Env::default();
+    *env = env.add_builtins();
     predeclare_decls(env, &ir)?;
     typecheck_typedefs(env, &ir.typedefs)?;
     typecheck_consts(env, &ir.consts)?;

          
M src/simptbl.rs +1 -1
@@ 8,7 8,7 @@ 
 //!
 //! Just use this as a piece to build other more complicated operations atop.
 
-use std::cell::RefCell;
+// use std::cell::RefCell;
 
 use crate::*;
 

          
M tests/programs/hello1.gt => tests/programs/test_hello2.gt +0 -0