# HG changeset patch # User Simon Heath # Date 1678058630 18000 # Sun Mar 05 18:23:50 2023 -0500 # Node ID 801f00ce4caad34d67b059f50bd681f0fb84ecaf # Parent f5d33646ceee0860e0057522d8969acbdfe12956 Ah, TFW the typechecker catches bugs in your test programs. ...but sucks at telling you where it is so you go on a tangent to try to fix it. diff --git a/src/backend/rust.rs b/src/backend/rust.rs --- a/src/backend/rust.rs +++ b/src/backend/rust.rs @@ -389,7 +389,11 @@ compile_exprs(body, ";\n", tck) ) } - E::Funcall { func, params } => { + E::Funcall { + func, + params, + type_params: _, + } => { // We have to store an intermediate value for the func, 'cause // Rust has problems with things like this: // fn f1() -> i32 { 1 } diff --git a/src/hir.rs b/src/hir.rs --- a/src/hir.rs +++ b/src/hir.rs @@ -143,9 +143,18 @@ } writeln!(f, ")")?; } - Funcall { func, params } => { + Funcall { + func, + params, + type_params, + } => { write!(f, "(funcall ")?; func.write(0, f)?; + write!(f, "[")?; + for (nm, ty) in type_params { + write!(f, "{}={},", nm, ty.get_name())?; + } + write!(f, "] ")?; for b in params { b.write(indent + 1, f)?; write!(f, " ")?; @@ -358,6 +367,12 @@ Funcall { func: ExprNode, params: Vec, + /// Explicit type parameters, specified a la Rust's turbofish. + /// We don't actually have a syntax for this yet, certain functions + /// have these generated during lowering passes. + /// If a type param is not specified, the type checker will + /// attempt to infer it. + type_params: BTreeMap, }, Break, Return { @@ -604,6 +619,7 @@ Funcall { func: nfunc, params: nparams, + type_params: Default::default(), } } E::Break => Break, diff --git a/src/passes.rs b/src/passes.rs --- a/src/passes.rs +++ b/src/passes.rs @@ -31,7 +31,7 @@ pub fn run_typechecked_passes(ir: Ir, tck: &mut typeck::Tck) -> Ir { // let passes: &[TckPass] = &[nameify, enum_to_int]; //let passes: &[TckPass] = &[nameify, struct_to_tuple]; - let passes: &[TckPass] = &[struct_to_tuple]; + let passes: &[TckPass] = &[struct_to_tuple, monomorphize]; let res = passes.iter().fold(ir, |prev_ir, f| f(prev_ir, tck)); println!(); println!("{}", res); @@ -159,12 +159,17 @@ E::Return { retval } => E::Return { retval: expr_map(retval, f), }, - E::Funcall { func, params } => { + E::Funcall { + func, + params, + type_params, + } => { let new_func = expr_map(func, f); let new_params = exprs_map(params, f); E::Funcall { func: new_func, params: new_params, + type_params, } } E::Lambda { signature, body } => E::Lambda { @@ -482,7 +487,25 @@ ////// Monomorphization ////// +/// Ok, so what we have to do here is this: +/// FIRST, we scan through the entire program and find +/// all functions with generic params that are called, +/// and figure out what their generics are. (The expr's +/// type should have this info.) +/// +/// Then we have to go through and find where each of those functions +/// is defined, which should be at the toplevel since we've done +/// lambda-lifting. We make a copy of them with the types +/// substituted, with a new name. +/// +/// Then we have to rewrite the function call names to point at the monomorphized +/// functions. We can do this while collecting them, since we generate the +/// names from the signature. fn monomorphize(ir: Ir, _tck: &mut typeck::Tck) -> Ir { + let mut functioncalls: BTreeSet<(Sym, Vec)> = Default::default(); + fn mangle_generic_name(s: Sym, tys: &[Type]) -> Sym { + todo!() + } ir } diff --git a/src/typeck.rs b/src/typeck.rs --- a/src/typeck.rs +++ b/src/typeck.rs @@ -1034,7 +1034,11 @@ tck.set_expr_type(expr, rettype); Ok(rettype) } - Funcall { func, params } => { + Funcall { + func, + params, + type_params, + } => { // Oh, defined generics are "easy". // Each time I call a function I create new type // vars for its generic args. @@ -1081,7 +1085,14 @@ // // So we go through the generics the function declares and create // new type vars for each of them. - let heck = tck.instantiate(&actual_func_type, None); + // + // We also create type variables for any type paramss we've been + // given values to + let input_type_params = type_params + .iter() + .map(|(nm, ty)| (*nm, tck.insert_known(ty))) + .collect(); + let heck = tck.instantiate(&actual_func_type, Some(input_type_params)); tck.unify(symtbl, heck, funcall_var)?; tck.set_expr_type(expr, rettype_var); diff --git a/tests/programs/test_sum2.gt b/tests/programs/test_sum2.gt --- a/tests/programs/test_sum2.gt +++ b/tests/programs/test_sum2.gt @@ -21,12 +21,12 @@ Welp! -/ type Option(@T) = sum + Some @T, None {}, - Some @T, end fn main() {} = - let x = Option.None {} - let y = Option.Some(12) + let x Option(I32) = Option.None {} + let y Option(I32) = Option.Some(12) end