Workin' on generic sum types.
5 files changed, 43 insertions(+), 18 deletions(-)

M src/hir.rs
M src/lib.rs
M src/passes.rs
M src/typeck.rs
M tests/programs/test_sum2.gt
M src/hir.rs +1 -1
@@ 721,7 721,7 @@ fn lower_typedef(accm: &mut Vec<Decl>, n
                     let paramname = Sym::new("x");
                     let signature = ast::Signature {
                         params: vec![(paramname, variant_type.clone())],
-                        rettype: Type::Named(name, vec![]),
+                        rettype: Type::Named(name, generics.clone()),
                     };
                     // Just return the value passed to it wrapped
                     // in a constructor of some kind...?

          
M src/lib.rs +2 -2
@@ 345,9 345,9 @@ impl Type {
                 Cow::Owned(res)
             }
             Type::Sum(body, _generics) => {
-                let mut res = String::from("sum");
+                let mut res = String::from("sum ");
                 res += &join_vars_with_commas(body);
-                res += "end";
+                res += " end";
                 Cow::Owned(res)
             }
             Type::Array(body, len) => {

          
M src/passes.rs +10 -8
@@ 356,10 356,10 @@ fn types_map(typs: Vec<Type>, f: &mut dy
 
 /// 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.
+    /// 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,

          
@@ 372,13 372,13 @@ fn type_map(typ: Type, f: &mut dyn FnMut
             .collect()
     }
     let res = match typ {
-        Type::Struct(fields, _generics) => {
+        Type::Struct(fields, generics) => {
             let fields = types_map_btree(fields, f);
-            Type::Struct(fields, _generics)
+            Type::Struct(fields, generics)
         }
-        Type::Sum(fields, _generics) => {
+        Type::Sum(fields, generics) => {
             let new_fields = types_map_btree(fields, f);
-            Type::Sum(new_fields, _generics)
+            Type::Sum(new_fields, generics)
         }
         Type::Array(ty, len) => Type::Array(Box::new(type_map(*ty, f)), len),
         Type::Func(args, rettype) => {

          
@@ 671,10 671,12 @@ fn tuplize_type(typ: Type) -> Type {
 ///
 /// TODO: Do something with the expr types?
 fn tuplize_expr(expr: ExprNode, tck: &mut typeck::Tck) -> ExprNode {
+    println!("Tuplizing expr {:?}", expr);
     let expr_typeid = tck.get_expr_type(&expr);
     let struct_type = tck.reconstruct(expr_typeid).expect("Should never happen?");
     let new_contents = match &*expr.e {
         E::StructCtor { body } => match &struct_type {
+            // TODO: Generics?
             Type::Struct(type_body, _generics) => {
                 let mut ordered_body: Vec<_> = body
                     .into_iter()

          
M src/typeck.rs +11 -7
@@ 1363,10 1363,8 @@ fn typecheck_expr(
             // This might be wrong, we can probably do it the other way around
             // like we do with TypeUnwrap: start by checking the inner expr type and make
             // sure it matches what we expect.  Generics might require that.
-            //
-            // TODO: Generics
             match named_type.clone() {
-                Type::Sum(sum_body, _generics) => {
+                Type::Sum(sum_body, generics) => {
                     let variant_type = &sum_body[variant];
                     let variant_typeid = tck.insert_known(variant_type);
                     let body_type = typecheck_expr(tck, symtbl, func_rettype, body)?;

          
@@ 1376,7 1374,7 @@ fn typecheck_expr(
                     // sum type we conjure up
                     // TODO: Might be easier to have our compiler generate
                     // the TypeCtor for it?
-                    let rettype = tck.insert_known(&Type::Named(name.clone(), vec![]));
+                    let rettype = tck.insert_known(&Type::Named(name.clone(), generics));
                     tck.set_expr_type(expr, rettype);
                     Ok(rettype)
                 }

          
@@ 1532,10 1530,16 @@ pub fn typecheck(ast: &hir::Ir) -> Resul
         }
     }
     // Print out toplevel symbols
-    /*
     for (name, id) in &symtbl.frames.borrow().last().unwrap().symbols {
-        println!("value {} type is {:?}", name, tck.reconstruct(*id));
+        println!(
+            "value {} type is {:?}",
+            name,
+            tck.reconstruct(id.0).map(|t| t.get_name())
+        );
     }
-    */
+    println!("Type variables:");
+    for (id, info) in &tck.vars {
+        println!("  ${} = {info:?}", id.0);
+    }
     Ok(t)
 }

          
M tests/programs/test_sum2.gt +19 -0
@@ 1,6 1,25 @@ 
 -- Compile:
 --   status: success
 
+/- BUGGO
+TFW your typechecker catches a real bug.
+Especially one you don't know how to fix.
+We lower the constructors for this type into functions,
+and then it complains that the function Option.None()
+returns Option(@T) and it has no way of knowing what
+the @T is for that function.
+
+This should technically be fine because @T is
+instantiated and figured out wherever Option.None()
+is actually called, but I don't know how to tell the
+typechecker that.
+
+Maybe we can add explicit type params to the function
+decl, and call it via something like Rust's turbofish?
+I had that once and then said "this is stupid we can
+always infer that from function args" and got rid of it.
+Welp! 
+-/
 type Option(@T) = sum
     None {},
     Some @T,