use std::collections::HashMap;
use crate::error::CompilerError;
use crate::ir::{ImplTarget, IrModule};
use super::super::walkers::{walk_expr_types_mut, walk_function_types_mut};
use super::externalise::externalise_imported_refs;
use super::naming::qualified_name;
pub(in crate::ir::monomorphise) fn inline_imported_lets(
module: &mut IrModule,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
for (module_path, imported) in imported_modules {
for let_binding in &imported.lets {
if !let_binding.visibility.is_public() {
continue;
}
let qualified = qualified_name(module_path, &let_binding.name);
if module.has_let(&qualified) {
continue;
}
let mut clone = let_binding.clone();
clone.name.clone_from(&qualified);
externalise_imported_refs(&mut clone.ty, imported, module_path);
walk_expr_types_mut(&mut clone.value, &mut |ty| {
externalise_imported_refs(ty, imported, module_path);
});
module.add_let(clone);
}
}
}
pub(in crate::ir::monomorphise) fn inline_imported_impls(
module: &mut IrModule,
imported_modules: &HashMap<Vec<String>, IrModule>,
impl_remap: &mut HashMap<(Vec<String>, u32), u32>,
) {
for (module_path, imported) in imported_modules {
for (imported_idx, impl_block) in imported.impls.iter().enumerate() {
let new_target = match impl_block.target {
ImplTarget::Struct(imported_id) => {
let Some(s) = imported.structs.get(imported_id.0 as usize) else {
continue;
};
let qualified = qualified_name(module_path, &s.name);
let Some(local_id) = module.struct_id(&qualified) else {
continue;
};
ImplTarget::Struct(local_id)
}
ImplTarget::Enum(imported_id) => {
let Some(e) = imported.enums.get(imported_id.0 as usize) else {
continue;
};
let qualified = qualified_name(module_path, &e.name);
let Some(local_id) = module.enum_id(&qualified) else {
continue;
};
ImplTarget::Enum(local_id)
}
ImplTarget::Primitive(_) => continue,
};
let mut clone = impl_block.clone();
clone.target = new_target;
if let Some(tref) = &mut clone.trait_ref {
if let Some(t) = imported.traits.get(tref.trait_id.0 as usize) {
let qualified = qualified_name(module_path, &t.name);
if let Some(local_id) = module.trait_id(&qualified) {
tref.trait_id = local_id;
}
}
}
for method in &mut clone.functions {
walk_function_types_mut(method, &mut |ty| {
externalise_imported_refs(ty, imported, module_path);
});
}
let local_idx = u32::try_from(module.impls.len()).unwrap_or(u32::MAX);
module.impls.push(clone);
impl_remap.insert(
(
module_path.clone(),
u32::try_from(imported_idx).unwrap_or(u32::MAX),
),
local_idx,
);
}
}
}
pub(in crate::ir::monomorphise) fn inline_imported_functions(
module: &mut IrModule,
imported_modules: &HashMap<Vec<String>, IrModule>,
) -> Result<(), Vec<CompilerError>> {
let mut errors = Vec::new();
for (module_path, imported) in imported_modules {
for func in &imported.functions {
let qualified = qualified_name(module_path, &func.name);
if module.function_id(&qualified).is_some() {
continue;
}
let mut clone = func.clone();
clone.name.clone_from(&qualified);
walk_function_types_mut(&mut clone, &mut |ty| {
externalise_imported_refs(ty, imported, module_path);
});
if let Err(e) = module.add_function(qualified, clone) {
errors.push(e);
}
}
}
if errors.is_empty() {
Ok(())
} else {
Err(errors)
}
}