Test associated functions, cleanup codegen a bit

This commit is contained in:
Sofia 2025-07-27 20:04:54 +03:00
parent 537167fe4f
commit f3471473a2
3 changed files with 110 additions and 145 deletions

View File

@ -24,5 +24,5 @@ fn main() -> u32 {
print(from_str("i32: ") + i32::test(54) as u64); print(from_str("i32: ") + i32::test(54) as u64);
print(from_str("sizeof i32: ") + i32::sizeof()); print(from_str("sizeof i32: ") + i32::sizeof());
return Otus::test(&otus); return i32::sizeof() as u32;
} }

View File

@ -18,7 +18,7 @@ use crate::{
self, self,
implement::TypeCategory, implement::TypeCategory,
pass::{AssociatedFunctionKey, BinopKey}, pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType, CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement, TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
}, },
util::try_all, util::try_all,
@ -898,72 +898,7 @@ impl mir::Expression {
)) ))
} }
} }
mir::ExprKind::FunctionCall(call) => { mir::ExprKind::FunctionCall(call) => codegen_function_call(None, call, scope, state)?,
let ret_type_kind = call.return_type.known().expect("function return type unknown");
let ret_type = ret_type_kind.get_type(scope.type_values);
let params = try_all(
call.parameters
.iter()
.map(|e| e.codegen(scope, state))
.collect::<Vec<_>>(),
)
.map_err(|e| e.first().cloned().unwrap())?
.into_iter()
.map(|v| v.unwrap())
.collect::<Vec<_>>();
let callee = scope.functions.get(&call.name).expect("function not found!");
let val = callee.codegen(
&call.name,
params.as_slice(),
&call.return_type,
if let Some(debug) = &scope.debug {
call.meta.into_debug(scope.tokens, debug.scope)
} else {
None
},
scope,
)?;
let ptr = if ret_type_kind != TypeKind::Void {
let ptr = scope
.block
.build_named(&call.name, Instr::Alloca(ret_type.clone()))
.unwrap();
scope
.block
.build_named(format!("{}.store", call.name), Instr::Store(ptr, val.instr()))
.unwrap();
Some(ptr)
} else {
None
};
if let Some(ptr) = ptr {
if state.should_load {
Some(StackValue(
StackValueKind::Immutable(
scope
.block
.build_named(call.name.clone(), Instr::Load(ptr, ret_type))
.unwrap(),
),
ret_type_kind,
))
} else {
Some(StackValue(
StackValueKind::Immutable(ptr),
TypeKind::CodegenPtr(Box::new(ret_type_kind)),
))
}
} else {
None
}
}
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state)?, mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state)?,
mir::ExprKind::Block(block) => { mir::ExprKind::Block(block) => {
let inner = scope.function.block("inner"); let inner = scope.function.block("inner");
@ -1323,9 +1258,27 @@ impl mir::Expression {
} }
} }
} }
mir::ExprKind::AssociatedFunctionCall(ty, call) => { mir::ExprKind::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
};
if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location);
}
Ok(value)
}
}
fn codegen_function_call<'ctx, 'a>(
associated_type: Option<&TypeKind>,
call: &FunctionCall,
scope: &mut Scope<'ctx, 'a>,
state: &State,
) -> Result<Option<StackValue>, ErrorKind> {
let ret_type_kind = call.return_type.known().expect("function return type unknown"); let ret_type_kind = call.return_type.known().expect("function return type unknown");
let call_name = format!("{}::{}", ty, call.name); let call_name = if let Some(ty) = &associated_type {
format!("{}::{}", ty, call.name)
} else {
String::from(call.name.clone())
};
let ret_type = ret_type_kind.get_type(scope.type_values); let ret_type = ret_type_kind.get_type(scope.type_values);
@ -1340,9 +1293,16 @@ impl mir::Expression {
.map(|v| v.unwrap()) .map(|v| v.unwrap())
.collect::<Vec<_>>(); .collect::<Vec<_>>();
let location = if let Some(debug) = &scope.debug {
call.meta.into_debug(scope.tokens, debug.scope)
} else {
None
};
let val = if let Some(ty) = associated_type {
let assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone()); let assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone());
let intrinsic = get_intrinsic_assoc_func(&ty, &call.name); let intrinsic_def = get_intrinsic_assoc_func(&ty, &call.name);
let intrinsic_owned = intrinsic.map(|func_def| { let intrinsic = intrinsic_def.map(|func_def| {
let FunctionDefinitionKind::Intrinsic(intrinsic) = func_def.kind else { let FunctionDefinitionKind::Intrinsic(intrinsic) = func_def.kind else {
panic!(); panic!();
}; };
@ -1351,18 +1311,21 @@ impl mir::Expression {
let callee = scope let callee = scope
.assoc_functions .assoc_functions
.get(&assoc_key) .get(&assoc_key)
.or(intrinsic_owned.as_ref()) .or(intrinsic.as_ref())
.expect(&format!("Function {} does not exist!", call_name));
callee
.codegen(&call_name, params.as_slice(), &call.return_type, location, scope)
.unwrap()
} else {
let callee = scope
.functions
.get(&call.name)
.expect(&format!("Function {} does not exist!", call_name)); .expect(&format!("Function {} does not exist!", call_name));
let location = if let Some(debug) = &scope.debug { callee
call.meta.into_debug(scope.tokens, debug.scope)
} else {
None
};
let val = callee
.codegen(&call_name, params.as_slice(), &call.return_type, location, scope) .codegen(&call_name, params.as_slice(), &call.return_type, location, scope)
.unwrap(); .unwrap()
};
let ptr = if ret_type_kind != TypeKind::Void { let ptr = if ret_type_kind != TypeKind::Void {
let ptr = scope let ptr = scope
@ -1379,7 +1342,7 @@ impl mir::Expression {
None None
}; };
if let Some(ptr) = ptr { Ok(if let Some(ptr) = ptr {
if state.should_load { if state.should_load {
Some(StackValue( Some(StackValue(
StackValueKind::Immutable( StackValueKind::Immutable(
@ -1398,14 +1361,7 @@ impl mir::Expression {
} }
} else { } else {
None None
} })
}
};
if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location);
}
Ok(value)
}
} }
impl mir::IfExpression { impl mir::IfExpression {

View File

@ -143,3 +143,12 @@ fn array_short_compiles_well() {
fn imported_type_compiles_well() { fn imported_type_compiles_well() {
test(include_str!("../../examples/imported_type.reid"), "test", Some(0)); test(include_str!("../../examples/imported_type.reid"), "test", Some(0));
} }
#[test]
fn associated_functions() {
test(
include_str!("../../examples/associated_functions.reid"),
"test",
Some(32),
);
}