Skip to content

Commit

Permalink
generics
Browse files Browse the repository at this point in the history
  • Loading branch information
edg-l committed Jan 30, 2025
1 parent 883379c commit 72d9062
Show file tree
Hide file tree
Showing 6 changed files with 71 additions and 18 deletions.
11 changes: 11 additions & 0 deletions examples/generics_basic.con
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
mod GenericsBasic {
pub fn hello_generics<T>(x: T) -> T {
return x;
}

pub fn main() -> i32 {
let value: i32 = hello_generics::<i32>(4);

return value;
}
}
17 changes: 17 additions & 0 deletions src/codegen/compiler.rs
Original file line number Diff line number Diff line change
Expand Up @@ -23,6 +23,7 @@ use melior::{
},
Context as MeliorContext,
};
use tracing::info;

use super::errors::CodegenError;

Expand Down Expand Up @@ -94,6 +95,7 @@ pub(crate) fn compile_program(ctx: CodegenCtx) -> Result<(), CodegenError> {
/// Compiles the given module within the context.
fn compile_module(ctx: ModuleCodegenCtx) -> Result<(), CodegenError> {
let body = ctx.get_module_body();
info!("compiling module {:?}", body.id);

for fn_id in body.functions.iter() {
let ctx = FunctionCodegenCtx {
Expand Down Expand Up @@ -130,6 +132,14 @@ impl FunctionCodegenCtx<'_> {
.expect("function body should exist")
}

pub fn has_fn_body(&self) -> bool {
self.module_ctx
.ctx
.program
.functions
.contains_key(&self.function_id)
}

/// Gets the function argument types and return type.
pub fn get_fn_signature(&self) -> &(Vec<Ty>, Ty) {
self.module_ctx
Expand All @@ -147,9 +157,16 @@ impl FunctionCodegenCtx<'_> {

/// Compiles the given function IR.
fn compile_function(ctx: FunctionCodegenCtx) -> Result<(), CodegenError> {
if !ctx.has_fn_body() {
// todo: maybe remove polymorphic functions entirely from the list before so compile_function is never called.
// This is a polymorphic version of the function, so it has no fn body, skip it.
return Ok(());
}
let body = ctx.get_fn_body();
let body_signature = ctx.get_fn_signature();

info!("compiling function {}", body.name);

// Functions only have 1 region with multiple blocks within.
let region = Region::new();

Expand Down
28 changes: 18 additions & 10 deletions src/ir/lowering.rs
Original file line number Diff line number Diff line change
Expand Up @@ -236,7 +236,7 @@ fn lower_module(mut ctx: BuildCtx, module: &Module, id: DefId) -> Result<BuildCt
ModuleDefItem::Constant(_) => { /* already processed */ }
ModuleDefItem::Function(fn_def) => {
if fn_def.decl.generic_params.is_empty() {
ctx = lower_func(ctx, fn_def, id, None, None)?;
ctx = lower_func(ctx, fn_def, id, None, None)?.0;
}
}
ModuleDefItem::Type(_) => todo!(),
Expand All @@ -253,7 +253,7 @@ fn lower_module(mut ctx: BuildCtx, module: &Module, id: DefId) -> Result<BuildCt
}
ModuleDefItem::Impl(impl_block) => {
for info in &impl_block.methods {
ctx = lower_func(ctx, info, id, Some(&impl_block.target), None)?;
ctx = lower_func(ctx, info, id, Some(&impl_block.target), None)?.0;
}
}
}
Expand Down Expand Up @@ -384,7 +384,7 @@ fn lower_func(
module_id: DefId,
has_self: Option<&TypeDescriptor>,
generics: Option<&HashMap<String, TypeName>>,
) -> Result<BuildCtx, LoweringError> {
) -> Result<(BuildCtx, DefId), LoweringError> {
debug!("lowering function");
let is_intrinsic: Option<ConcreteIntrinsic> = None;

Expand All @@ -402,6 +402,7 @@ fn lower_func(
*body.symbols.functions.get(&func.decl.name.name).unwrap()
}
};
debug!("function id: {:?}", fn_id);

// Check if its a generic function
// If it is, lower it and save its id, to avoid lowering the same monomorphized function again.
Expand Down Expand Up @@ -444,7 +445,15 @@ fn lower_func(
.function_signatures
.insert(fn_id, (args_ty, ret_ty));
debug!("created with id={fn_id:?}");
ctx.body
.modules
.get_mut(&module_id)
.expect("module should exist")
.functions
.insert(fn_id);
}

debug!("new function id: {:?}", fn_id);
}

let mut builder = FnBodyBuilder {
Expand Down Expand Up @@ -590,9 +599,10 @@ fn lower_func(

let (mut ctx, body) = (builder.ctx, builder.body);
ctx.unresolved_function_signatures.remove(&body.id);
debug!("added function {} with id {:?} to ir", body.name, body.id);
ctx.body.functions.insert(body.id, body);

Ok(ctx)
Ok((ctx, fn_id))
}

fn lower_func_decl(
Expand Down Expand Up @@ -1434,8 +1444,8 @@ fn lower_fn_call(
// The id of the fn to call, in case its a method.
fn_id: Option<DefId>,
) -> Result<(Rvalue, Ty, Span), LoweringError> {
dbg!("lowering fn call");
let fn_id = {
debug!("lowering fn call");
let mut fn_id = {
let mod_body = builder.get_module_body();

if let Some(id) = fn_id {
Expand Down Expand Up @@ -1464,7 +1474,7 @@ fn lower_fn_call(
panic!();
}

dbg!("lowering generic fn");
debug!("lowering call to generic function");

for (generic_ty, generic_param) in info
.generics
Expand All @@ -1474,15 +1484,13 @@ fn lower_fn_call(
generic_map.insert(generic_param.name.name.clone(), generic_ty.clone());
}

builder.ctx = lower_func(
(builder.ctx, fn_id) = lower_func(
builder.ctx.clone(),
&generic_fn_def.clone(),
builder.local_module,
None,
Some(&generic_map),
)?;

dbg!("generic fn lowered");
}

let (args_ty, ret_ty) = {
Expand Down
7 changes: 0 additions & 7 deletions src/ir/lowering/common.rs
Original file line number Diff line number Diff line change
Expand Up @@ -42,13 +42,6 @@ pub struct GenericFn {
pub generics: Vec<String>,
}

#[derive(Debug, Clone, PartialEq, Eq, Hash)]
pub struct PolymorphicSignature {
pub id: DefId,
pub params: Vec<TypeDescriptor>,
pub ret_ty: Option<TypeDescriptor>,
}

#[derive(Debug, Clone)]
pub struct BuildCtx {
pub body: ProgramBody,
Expand Down
25 changes: 24 additions & 1 deletion src/ir/lowering/prepass.rs
Original file line number Diff line number Diff line change
Expand Up @@ -199,6 +199,10 @@ pub fn prepass_sub_module(
.functions
.insert(info.decl.name.name.clone(), next_id);
submodule.functions.insert(next_id);
if !info.decl.generic_params.is_empty() {
ctx.generic_fn_bodies.insert(next_id, info.clone());
}

ctx.unresolved_function_signatures.insert(
next_id,
(
Expand Down Expand Up @@ -253,7 +257,26 @@ pub fn prepass_sub_module(
),
);
}
ast::modules::ModuleDefItem::Impl(_impl_block) => todo!(),
ast::modules::ModuleDefItem::Impl(impl_block) => {
for info in &impl_block.methods {
let next_id = gen.next_defid();
submodule.symbols.methods.insert(
(impl_block.target.clone(), info.decl.name.name.clone()),
next_id,
);
submodule.functions.insert(next_id);
ctx.unresolved_function_signatures.insert(
next_id,
(
[impl_block.target.clone()]
.into_iter()
.chain(info.decl.params.iter().map(|x| &x.r#type).cloned())
.collect(),
info.decl.ret_type.clone(),
),
);
}
}
}
}

Expand Down
1 change: 1 addition & 0 deletions tests/examples.rs
Original file line number Diff line number Diff line change
Expand Up @@ -4,6 +4,7 @@ use test_case::test_case;

mod common;

#[test_case(include_str!("../examples/generics_basic.con"), "generics_basic", false, 4 ; "generics_basic.con")]
#[test_case(include_str!("../examples/borrow.con"), "borrow", false, 2 ; "borrow.con")]
#[test_case(include_str!("../examples/factorial_if.con"), "factorial_if", false, 24 ; "factorial_if.con")]
#[test_case(include_str!("../examples/fib_if.con"), "fib_if", false, 55 ; "fib_if.con")]
Expand Down

0 comments on commit 72d9062

Please sign in to comment.