thiiiiiiink this gets rid of @ sigils for type parameters.

Need to go through more tests and clean them up tho.
M src/ast.rs +1 -1
@@ 130,7 130,7 @@ impl Signature {
 
         let typenames: Vec<_> = self.typeparams.iter().map(|t| t.get_name()).collect();
         let typeargs = typenames.join(", ");
-        format!("({} | {}) {}", args, typeargs, self.rettype.get_name())
+        format!("(|{}| {}) {}", typeargs, args, self.rettype.get_name())
     }
 
     /// Transforms this signature into a new type.

          
M src/format.rs +0 -1
@@ 62,7 62,6 @@ fn unparse_decl(d: &Decl, out: &mut dyn 
                     } else {
                         first = false;
                     }
-                    paramstr += "@";
                     paramstr += &*t.val();
                 }
                 writeln!(out, "type {}({}) = {}", name, paramstr, tname)?;

          
M src/hir.rs +6 -5
@@ 99,7 99,7 @@ impl fmt::Display for Decl {
                 typ: typename,
                 init,
             } => {
-                write!(f, "const {}: {} = ", name, typename.get_name())?;
+                write!(f, "const {} {} = ", name, typename.get_name())?;
                 init.write(1, f)?;
                 writeln!(f)?;
             }

          
@@ 357,14 357,15 @@ impl Expr {
             } => {
                 write!(f, "(funcall ")?;
                 func.write(0, f)?;
+                write!(f, " |")?;
+                for ty in type_params {
+                    write!(f, "{},", ty.get_name())?;
+                }
+                write!(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 => {

          
M src/lib.rs +11 -0
@@ 166,6 166,17 @@ impl Type {
         accm
     }
 
+    /// Shortcut for a named type with no type params
+    pub fn named0(s: impl AsRef<str>) -> Self {
+        Type::Named(Sym::new(s), vec![])
+    }
+
+    /// Shortcut for a generic type
+    /// Not much shorter, but it keeps test cases cleaner I guess
+    pub fn generic(s: impl AsRef<str>) -> Self {
+        Type::Generic(Sym::new(s))
+    }
+
     /// Shortcut for getting the type for an unknown int
     pub fn iunknown() -> Self {
         Self::Prim(PrimType::UnknownInt)

          
M src/parser.rs +15 -16
@@ 102,8 102,6 @@ fn eat_block_comment(lex: &mut Lexer<Tok
 pub enum TokenKind {
     #[regex("[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_owned())]
     Ident(String),
-    //#[regex("@[a-zA-Z_][a-zA-Z0-9_]*", |lex| lex.slice().to_owned())]
-    //TypeIdent(String),
     #[regex("true|false", |lex| lex.slice().parse())]
     Bool(bool),
     #[regex("[0-9][0-9_]*I8",   |lex| make_int(lex, 1, true))]

          
@@ 670,7 668,6 @@ impl<'input> Parser<'input> {
                 if self.peek_is(T::RParen.discr()) {
                     break;
                 } else {
-                    self.expect(T::At);
                     let name = self.expect_ident();
                     params.push(name);
                 }

          
@@ 1387,10 1384,12 @@ impl<'input> Parser<'input> {
                     Type::Named(Sym::new(s), type_params)
                 }
             }
-            T::At => {
-                let s = self.expect_ident();
-                Type::Generic(s)
-            }
+            /*
+                    T::At => {
+                        let s = self.expect_ident();
+                        Type::Generic(s)
+                    }
+            */
             T::LBrace => self.try_parse_tuple_type()?,
             T::Fn => self.parse_fn_type(),
             T::Struct => self.try_parse_struct_type()?,

          
@@ 1576,9 1575,9 @@ mod tests {
 
     #[test]
     fn test_typedef_generics() {
-        test_decl_is("type bop(@T) = @T", || ast::Decl::TypeDef {
+        test_decl_is("type bop(T) = T", || ast::Decl::TypeDef {
             name: Sym::new("bop"),
-            typedecl: Type::Generic(Sym::new("T")),
+            typedecl: Type::Named(Sym::new("T"), vec![]),
             doc_comment: vec![],
             params: vec![Sym::new("T")],
         });

          
@@ 1648,7 1647,7 @@ type blar = I8
             "(x  Bool)",
             "(x  Bool,)",
             "(x  I32, y  Bool)",
-            "(x @X, y @Y)",
+            "(x X, y Y)",
             "(x  I32, y  Bool,)",
         ];
         test_parse_with(|p| p.parse_fn_args(), &valid_args)

          
@@ 1666,7 1665,7 @@ type blar = I8
             "(f fn(I32) I64, x I32) Bool",
             "(f fn(|| I32) I64, x I32) Bool",
             "(f fn(||) I64, x I32) Bool",
-            "(f fn(|@T| I32) I64, x I32) Bool",
+            "(f fn(|T| I32) I64, x I32) Bool",
             // now without explicit return types
             "()",
             "(x Bool)",

          
@@ 1678,7 1677,7 @@ type blar = I8
             "(f fn(I32), x I32)",
             "(f fn(|| I32), x I32)",
             "(f fn(||), x I32)",
-            "(f fn(|@T| I32), x I32)",
+            "(f fn(|T| I32), x I32)",
         ];
         test_parse_with(|p| p.parse_fn_signature(), &valid_args)
     }

          
@@ 1778,12 1777,12 @@ type blar = I8
     fn parse_fn_decls() {
         let valid_args = vec![
             "fn foo1(f I32) I32 = f end",
-            "fn foo2(|@T| f I32 ) I32 = f end",
-            "fn foo3(|@T|) {} = f end",
+            "fn foo2(|T| f I32 ) I32 = f end",
+            "fn foo3(|T|) {} = f end",
             "fn foo4(||) {} = f end",
             "fn foo5() {} = f end",
-            "fn foo6(f @T) @T = f end",
-            "fn foo7(|@T1, @T2, | f I32, g Bool, ) I32 = f end",
+            "fn foo6(f T) T = f end",
+            "fn foo7(|T1, T2, | f I32, g Bool, ) I32 = f end",
         ];
         test_parse_with(|p| p.parse_decl().unwrap(), &valid_args);
     }

          
M src/passes.rs +40 -37
@@ 105,6 105,7 @@ fn expr_map(
     expr: ExprNode,
     f_pre: &mut dyn FnMut(ExprNode) -> ExprNode,
     f_post: &mut dyn FnMut(ExprNode) -> ExprNode,
+    ft: &mut dyn FnMut(Type) -> Type,
 ) -> ExprNode {
     let thing = f_pre(expr);
     let exprfn = &mut |e| match e {

          
@@ 117,12 118,12 @@ fn expr_map(
         E::Break => e,
         E::EnumCtor { .. } => e,
         E::TupleCtor { body } => E::TupleCtor {
-            body: exprs_map(body, f_pre, f_post),
+            body: exprs_map(body, f_pre, f_post, ft),
         },
         E::StructCtor { body } => {
             let new_body = body
                 .into_iter()
-                .map(|(sym, vl)| (sym, expr_map(vl, f_pre, f_post)))
+                .map(|(sym, vl)| (sym, expr_map(vl, f_pre, f_post, ft)))
                 .collect();
             E::StructCtor { body: new_body }
         }

          
@@ 132,8 133,8 @@ fn expr_map(
             body,
         } => E::TypeCtor {
             name,
-            type_params,
-            body: expr_map(body, f_pre, f_post),
+            type_params: types_map(type_params, ft),
+            body: expr_map(body, f_pre, f_post, ft),
         },
         E::SumCtor {
             name,

          
@@ 142,41 143,41 @@ fn expr_map(
         } => E::SumCtor {
             name,
             variant,
-            body: expr_map(body, f_pre, f_post),
+            body: expr_map(body, f_pre, f_post, ft),
         },
         E::ArrayCtor { body } => E::ArrayCtor {
-            body: exprs_map(body, f_pre, f_post),
+            body: exprs_map(body, f_pre, f_post, ft),
         },
         E::TypeUnwrap { expr } => E::TypeUnwrap {
-            expr: expr_map(expr, f_pre, f_post),
+            expr: expr_map(expr, f_pre, f_post, ft),
         },
         E::TupleRef { expr, elt } => E::TupleRef {
-            expr: expr_map(expr, f_pre, f_post),
+            expr: expr_map(expr, f_pre, f_post, ft),
             elt,
         },
         E::StructRef { expr, elt } => E::StructRef {
-            expr: expr_map(expr, f_pre, f_post),
+            expr: expr_map(expr, f_pre, f_post, ft),
             elt,
         },
         E::ArrayRef { expr, idx } => E::ArrayRef {
-            expr: expr_map(expr, f_pre, f_post),
+            expr: expr_map(expr, f_pre, f_post, ft),
             idx,
         },
         E::Assign { lhs, rhs } => E::Assign {
-            lhs: expr_map(lhs, f_pre, f_post), // TODO: Think real hard about lvalues
-            rhs: expr_map(rhs, f_pre, f_post),
+            lhs: expr_map(lhs, f_pre, f_post, ft), // TODO: Think real hard about lvalues
+            rhs: expr_map(rhs, f_pre, f_post, ft),
         },
         E::BinOp { op, lhs, rhs } => E::BinOp {
             op,
-            lhs: expr_map(lhs, f_pre, f_post),
-            rhs: expr_map(rhs, f_pre, f_post),
+            lhs: expr_map(lhs, f_pre, f_post, ft),
+            rhs: expr_map(rhs, f_pre, f_post, ft),
         },
         E::UniOp { op, rhs } => E::UniOp {
             op,
-            rhs: expr_map(rhs, f_pre, f_post),
+            rhs: expr_map(rhs, f_pre, f_post, ft),
         },
         E::Block { body } => E::Block {
-            body: exprs_map(body, f_pre, f_post),
+            body: exprs_map(body, f_pre, f_post, ft),
         },
         E::Let {
             varname,

          
@@ 185,53 186,54 @@ fn expr_map(
             mutable,
         } => E::Let {
             varname,
-            typename,
-            init: expr_map(init, f_pre, f_post),
+            typename: typename.map(|t| type_map(t, ft)),
+            init: expr_map(init, f_pre, f_post, ft),
             mutable,
         },
         E::If { cases } => {
             let new_cases = cases
                 .into_iter()
                 .map(|(test, case)| {
-                    let new_test = expr_map(test, f_pre, f_post);
-                    let new_cases = exprs_map(case, f_pre, f_post);
+                    let new_test = expr_map(test, f_pre, f_post, ft);
+                    let new_cases = exprs_map(case, f_pre, f_post, ft);
                     (new_test, new_cases)
                 })
                 .collect();
             E::If { cases: new_cases }
         }
         E::Loop { body } => E::Loop {
-            body: exprs_map(body, f_pre, f_post),
+            body: exprs_map(body, f_pre, f_post, ft),
         },
         E::Return { retval } => E::Return {
-            retval: expr_map(retval, f_pre, f_post),
+            retval: expr_map(retval, f_pre, f_post, ft),
         },
         E::Funcall {
             func,
             params,
             type_params,
         } => {
-            let new_func = expr_map(func, f_pre, f_post);
-            let new_params = exprs_map(params, f_pre, f_post);
+            let new_func = expr_map(func, f_pre, f_post, ft);
+            let new_params = exprs_map(params, f_pre, f_post, ft);
+            let new_type_params = types_map(type_params, ft);
             E::Funcall {
                 func: new_func,
                 params: new_params,
-                type_params,
+                type_params: new_type_params,
             }
         }
         E::Lambda { signature, body } => E::Lambda {
             signature,
-            body: exprs_map(body, f_pre, f_post),
+            body: exprs_map(body, f_pre, f_post, ft),
         },
         E::Typecast { e, to } => E::Typecast {
-            e: expr_map(e, f_pre, f_post),
-            to,
+            e: expr_map(e, f_pre, f_post, ft),
+            to: type_map(to, ft),
         },
         E::Ref { expr } => E::Ref {
-            expr: expr_map(expr, f_pre, f_post),
+            expr: expr_map(expr, f_pre, f_post, ft),
         },
         E::Deref { expr } => E::Deref {
-            expr: expr_map(expr, f_pre, f_post),
+            expr: expr_map(expr, f_pre, f_post, ft),
         },
     };
     let post_thing = thing.map(exprfn);

          
@@ 239,11 241,11 @@ fn expr_map(
 }
 
 pub fn expr_map_pre(expr: ExprNode, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> ExprNode {
-    expr_map(expr, f, &mut id)
+    expr_map(expr, f, &mut id, &mut id)
 }
 
 pub fn expr_map_post(expr: ExprNode, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> ExprNode {
-    expr_map(expr, &mut id, f)
+    expr_map(expr, &mut id, f, &mut id)
 }
 
 /// Map functions over a list of exprs.

          
@@ 251,19 253,20 @@ fn exprs_map(
     exprs: Vec<ExprNode>,
     f_pre: &mut dyn FnMut(ExprNode) -> ExprNode,
     f_post: &mut dyn FnMut(ExprNode) -> ExprNode,
+    ft: &mut dyn FnMut(Type) -> Type,
 ) -> Vec<ExprNode> {
     exprs
         .into_iter()
-        .map(|e| expr_map(e, f_pre, f_post))
+        .map(|e| expr_map(e, f_pre, f_post, ft))
         .collect()
 }
 
 fn exprs_map_pre(exprs: Vec<ExprNode>, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> Vec<ExprNode> {
-    exprs_map(exprs, f, &mut id)
+    exprs_map(exprs, f, &mut id, &mut id)
 }
 
 fn _exprs_map_post(exprs: Vec<ExprNode>, f: &mut dyn FnMut(ExprNode) -> ExprNode) -> Vec<ExprNode> {
-    exprs_map(exprs, &mut id, f)
+    exprs_map(exprs, &mut id, f, &mut id)
 }
 
 fn decl_map_pre(

          
@@ 301,12 304,12 @@ fn decl_map(
         } => D::Function {
             name,
             signature: signature_map(signature, ft),
-            body: exprs_map(body, fe_pre, fe_post),
+            body: exprs_map(body, fe_pre, fe_post, ft),
         },
         D::Const { name, typ, init } => D::Const {
             name,
             typ: type_map(typ, ft),
-            init: expr_map(init, fe_pre, fe_post),
+            init: expr_map(init, fe_pre, fe_post, ft),
         },
         D::TypeDef {
             name,

          
M src/passes/generic_infer.rs +193 -9
@@ 2,24 2,208 @@ 
 //! if they are not declared.
 //! We could do this in the typechecker but I think it will be simpler as a preprocessing pass.
 
-use crate::hir::Ir;
+use crate::hir::{Decl as D, Expr as E, Ir, Signature};
 use crate::passes::*;
 
+// This is slightly bonkers and a big dependency inversion but it also does
+// *exactly* what we want.  :thonk:
+use crate::typeck::Symtbl;
 
-fn generic_infer_expr(expr: ExprNode) -> ExprNode {
+fn generic_infer_type(symtbl: &Symtbl, ty: Type) -> Type {
+    match ty {
+        Type::Named(nm, ref _tys) => {
+            if let Some(t) = symtbl.get_type(nm) {
+                // TODO: Do we have to recurse down the type params?
+                // or will type_map() do that for us?
+                // t should just be a Generic(nm), so we just replace this type with it.
+                t
+            } else {
+                // Not declared, just carry on
+                ty
+            }
+        }
+        _ => ty,
+    }
+}
+
+/*
+/// signature_map() doesn't do the correct thing here 'cause we have to
+/// shuffle around generic param
+fn generic_infer_sig(symtbl: &Symtbl, sig: Signature) -> Signature {
+    sig
+}
+    */
+
+/// Basically, if we see a Named type mentioned, we check to see if it's
+/// in the symtbl.  If it is, we replace it with a Generic.  Otherwise
+/// we leave it as is and let typeck decide whether or not it exists.
+fn generic_infer_expr(_symtbl: &Symtbl, expr: ExprNode) -> ExprNode {
     expr
 }
 
 pub(super) fn generic_infer(ir: Ir) -> Ir {
-    let generic_infer_expr = &mut generic_infer_expr;
-    let generic_infer_ty = &mut |ty| ty;
-    let new_decls: Vec<D> = ir
-        .decls
-        .into_iter()
-        .map(|decl| decl_map_pre(decl, generic_infer_expr, generic_infer_ty))
-        .collect();
+    let symtbl = Symtbl::default();
+    let generic_infer_expr = &mut |e| generic_infer_expr(&symtbl, e);
+    let generic_infer_ty = &mut |ty| generic_infer_type(&symtbl, ty);
+    // Fuck decl_map, it's not made for this.  So we'll just
+    // do it by hand.
+    let mut new_decls = vec![];
+    for decl in ir.decls {
+        let d = match decl {
+            D::Function {
+                name,
+                signature,
+                body,
+            } => {
+                let _guard = symtbl.push_scope();
+                for typeparam in &signature.typeparams {
+                    match typeparam {
+                        Type::Named(sym, _) if *sym == Sym::new("Tuple") => (),
+                        Type::Named(nm, _v) => {
+                            symtbl.add_type(*nm, &Type::Generic(*nm));
+                        }
+                        _ => (),
+                    }
+                }
+                let new_sig = signature_map(signature, generic_infer_ty);
+                D::Function {
+                    name,
+                    signature: new_sig,
+                    body: exprs_map(body, &mut id, generic_infer_expr, generic_infer_ty),
+                }
+            }
+            D::Const { name, typ, init } => {
+                let _guard = symtbl.push_scope();
+                for name in typ.get_type_params() {
+                    symtbl.add_type(name, &Type::Generic(name));
+                }
+                D::Const {
+                    name,
+                    typ: type_map(typ, generic_infer_ty),
+                    init: expr_map(init, &mut id, generic_infer_expr, generic_infer_ty),
+                }
+            }
+            D::TypeDef {
+                name,
+                params,
+                typedecl,
+            } => {
+                let _guard = symtbl.push_scope();
+                for name in &params {
+                    symtbl.add_type(*name, &Type::Generic(*name));
+                }
+                D::TypeDef {
+                    name,
+                    params,
+                    typedecl: type_map(typedecl, generic_infer_ty),
+                }
+            }
+            D::Import { .. } => decl,
+        };
+        new_decls.push(d);
+    }
     Ir {
         decls: new_decls,
         ..ir
     }
 }
+
+#[cfg(test)]
+mod tests {
+    use crate::hir::{Decl as D, Ir};
+    use crate::*;
+
+    #[test]
+    fn heckin_heck() {
+        let typedef = D::TypeDef {
+            name: Sym::new("thing"),
+            params: vec![Sym::new("T")],
+            typedecl: Type::Named(Sym::new("T"), vec![]),
+        };
+        let ir = Ir {
+            decls: vec![typedef],
+            filename: String::from("test"),
+            modulename: String::from("test"),
+        };
+        let res = super::generic_infer(ir);
+
+        let wanted_typedef = D::TypeDef {
+            name: Sym::new("thing"),
+            params: vec![Sym::new("T")],
+            typedecl: Type::generic("T"),
+        };
+
+        assert_eq!(res.decls[0], wanted_typedef);
+    }
+
+    #[test]
+    fn heckin_heck2() {
+        let structbody = [
+            (Sym::new("a"), Type::i32()),
+            (Sym::new("b"), Type::Named(Sym::new("T"), vec![])),
+        ];
+        let typedef = D::TypeDef {
+            name: Sym::new("thing"),
+            params: vec![Sym::new("T")],
+            typedecl: Type::Struct(BTreeMap::from(structbody), vec![]),
+        };
+        let ir = Ir {
+            decls: vec![typedef],
+            filename: String::from("test"),
+            modulename: String::from("test"),
+        };
+        let res = super::generic_infer(ir);
+
+        let wanted_structbody = [
+            (Sym::new("a"), Type::i32()),
+            (Sym::new("b"), Type::generic("T")),
+        ];
+        let wanted_typedef = D::TypeDef {
+            name: Sym::new("thing"),
+            params: vec![Sym::new("T")],
+            typedecl: Type::Struct(BTreeMap::from(wanted_structbody), vec![]),
+        };
+
+        assert_eq!(res.decls[0], wanted_typedef);
+    }
+
+    /// Todo: maybe check out nested functions?
+    #[test]
+    fn heckin_heck3() {
+        let sig1 = hir::Signature {
+            params: vec![
+                (Sym::new("a"), Type::named0("T")),
+                (Sym::new("b"), Type::named0("Something")),
+            ],
+            rettype: Type::Named(Sym::new("T"), vec![]),
+            typeparams: vec![Type::Named(Sym::new("T"), vec![])],
+        };
+        let f1 = D::Function {
+            name: Sym::new("foo"),
+            signature: sig1,
+            body: vec![],
+        };
+        let ir = Ir {
+            decls: vec![f1],
+            filename: String::from("test"),
+            modulename: String::from("test"),
+        };
+        let res = super::generic_infer(ir);
+
+        let wanted_sig = hir::Signature {
+            params: vec![
+                (Sym::new("a"), Type::generic("T")),
+                (Sym::new("b"), Type::named0("Something")),
+            ],
+            rettype: Type::generic("T"),
+            typeparams: vec![Type::generic("T")],
+        };
+        let wanted_f = D::Function {
+            name: Sym::new("foo"),
+            signature: wanted_sig,
+            body: vec![],
+        };
+
+        assert_eq!(res.decls[0], wanted_f);
+    }
+}

          
M src/typeck.rs +3 -3
@@ 929,7 929,7 @@ impl Symtbl {
             self.add_var(builtin.name, ty, false);
         }
     }
-    fn push_scope(&self) -> ScopeGuard {
+    pub(crate) fn push_scope(&self) -> ScopeGuard {
         self.frames.borrow_mut().push(ScopeFrame::default());
         ScopeGuard {
             scope: self.clone(),

          
@@ 956,7 956,7 @@ impl Symtbl {
         None
     }
 
-    fn add_type(&self, name: Sym, ty: &Type) {
+    pub(crate) fn add_type(&self, name: Sym, ty: &Type) {
         self.frames
             .borrow_mut()
             .last_mut()

          
@@ 965,7 965,7 @@ impl Symtbl {
             .insert(name, ty.to_owned());
     }
 
-    fn get_type(&self, ty: Sym) -> Option<Type> {
+    pub(crate) fn get_type(&self, ty: Sym) -> Option<Type> {
         for scope in self.frames.borrow().iter().rev() {
             let v = scope.types.get(&ty);
             if v.is_some() {

          
M tests/programs/test_struct4.gt +6 -3
@@ 4,17 4,19 @@ 
 --   status: success
 
 
-type Foo(@Thing) = struct
-    a: @Thing,
+type Foo(Thing) = struct
+    a: Thing,
     b: Bool
 end
 
-fn id(x @T) @T =
+fn id(|T| x T) T =
     x
 end
 
 
 fn main() {} =
+    {}
+/-
     let f1 Foo(I32) = id(Foo {
         .a = 3,
         .b = false

          
@@ 24,4 26,5 @@ fn main() {} =
         .a = true,
         .b = false
     })
+    -/
 end