M src/backend/rust.rs +5 -1
@@ 389,7 389,11 @@ fn compile_expr(expr: &hir::ExprNode, tc
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 }
M src/hir.rs +17 -1
@@ 143,9 143,18 @@ impl Expr {
}
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 @@ pub enum Expr {
Funcall {
func: ExprNode,
params: Vec<ExprNode>,
+ /// 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<Sym, Type>,
},
Break,
Return {
@@ 604,6 619,7 @@ fn lower_expr(expr: &ast::Expr) -> ExprN
Funcall {
func: nfunc,
params: nparams,
+ type_params: Default::default(),
}
}
E::Break => Break,
M src/passes.rs +25 -2
@@ 31,7 31,7 @@ pub fn run_passes(ir: Ir) -> Ir {
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 @@ fn expr_map(expr: ExprNode, f: &mut dyn
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 @@ fn lambda_lift(ir: Ir) -> Ir {
////// 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<Type>)> = Default::default();
+ fn mangle_generic_name(s: Sym, tys: &[Type]) -> Sym {
+ todo!()
+ }
ir
}
M src/typeck.rs +13 -2
@@ 1034,7 1034,11 @@ fn typecheck_expr(
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 @@ fn typecheck_expr(
//
// 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);
M tests/programs/test_sum2.gt +3 -3
@@ 21,12 21,12 @@ always infer that from function args" an
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