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("sizeof i32: ") + i32::sizeof());
return Otus::test(&otus);
return i32::sizeof() as u32;
}

View File

@ -18,7 +18,7 @@ use crate::{
self,
implement::TypeCategory,
pass::{AssociatedFunctionKey, BinopKey},
CustomTypeKey, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
CustomTypeKey, FunctionCall, FunctionDefinitionKind, NamedVariableRef, SourceModuleId, StructField, StructType,
TypeDefinition, TypeDefinitionKind, TypeKind, WhileStatement,
},
util::try_all,
@ -898,72 +898,7 @@ impl mir::Expression {
))
}
}
mir::ExprKind::FunctionCall(call) => {
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::FunctionCall(call) => codegen_function_call(None, call, scope, state)?,
mir::ExprKind::If(if_expression) => if_expression.codegen(scope, state)?,
mir::ExprKind::Block(block) => {
let inner = scope.function.block("inner");
@ -1323,83 +1258,7 @@ impl mir::Expression {
}
}
}
mir::ExprKind::AssociatedFunctionCall(ty, call) => {
let ret_type_kind = call.return_type.known().expect("function return type unknown");
let call_name = format!("{}::{}", ty, call.name);
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 assoc_key = AssociatedFunctionKey(ty.clone(), call.name.clone());
let intrinsic = get_intrinsic_assoc_func(&ty, &call.name);
let intrinsic_owned = intrinsic.map(|func_def| {
let FunctionDefinitionKind::Intrinsic(intrinsic) = func_def.kind else {
panic!();
};
ScopeFunctionKind::IntrinsicOwned(intrinsic)
});
let callee = scope
.assoc_functions
.get(&assoc_key)
.or(intrinsic_owned.as_ref())
.expect(&format!("Function {} does not exist!", call_name));
let location = if let Some(debug) = &scope.debug {
call.meta.into_debug(scope.tokens, debug.scope)
} else {
None
};
let val = callee
.codegen(&call_name, params.as_slice(), &call.return_type, location, scope)
.unwrap();
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::AssociatedFunctionCall(ty, call) => codegen_function_call(Some(ty), call, scope, state)?,
};
if let Some(value) = &value {
value.instr().maybe_location(&mut scope.block, location);
@ -1408,6 +1267,103 @@ impl mir::Expression {
}
}
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 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 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 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 intrinsic_def = get_intrinsic_assoc_func(&ty, &call.name);
let intrinsic = intrinsic_def.map(|func_def| {
let FunctionDefinitionKind::Intrinsic(intrinsic) = func_def.kind else {
panic!();
};
ScopeFunctionKind::IntrinsicOwned(intrinsic)
});
let callee = scope
.assoc_functions
.get(&assoc_key)
.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));
callee
.codegen(&call_name, params.as_slice(), &call.return_type, location, scope)
.unwrap()
};
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
};
Ok(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
})
}
impl mir::IfExpression {
fn codegen<'ctx, 'a>(&self, scope: &mut Scope<'ctx, 'a>, state: &State) -> Result<Option<StackValue>, ErrorKind> {
let condition = self.0.codegen(scope, state)?.unwrap();

View File

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