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,