use std::collections::HashMap;
use crate::ir::{ImplTarget, IrModule};
use super::super::walkers::{walk_expr_spans_mut, walk_function_spans_mut};
use super::naming::imported_path_of;
pub(in crate::ir::monomorphise) fn remap_imported_file_ids(
module: &mut IrModule,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
if imported_modules.is_empty() {
return;
}
let remaps = build_file_remap_table(module, imported_modules);
remap_function_file_ids(module, &remaps, imported_modules);
remap_struct_file_ids(module, &remaps, imported_modules);
remap_enum_file_ids(module, &remaps, imported_modules);
remap_let_file_ids(module, &remaps, imported_modules);
remap_impl_file_ids(module, &remaps, imported_modules);
}
fn build_file_remap_table(
module: &mut IrModule,
imported_modules: &HashMap<Vec<String>, IrModule>,
) -> HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>> {
let mut remaps: HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>> =
HashMap::with_capacity(imported_modules.len());
for (path, imported) in imported_modules {
let cap = imported.file_table.len().saturating_add(1);
let mut per_module: HashMap<crate::ir::FileId, crate::ir::FileId> =
HashMap::with_capacity(cap);
per_module.insert(crate::ir::FileId::SYNTHETIC, crate::ir::FileId::SYNTHETIC);
for (idx, file) in imported.file_table.iter().enumerate() {
let imported_id = crate::ir::FileId(u32::try_from(idx).unwrap_or(0).saturating_add(1));
let entry_id = module.register_file(file.clone());
per_module.insert(imported_id, entry_id);
}
remaps.insert(path.clone(), per_module);
}
remaps
}
fn remap_function_file_ids(
module: &mut IrModule,
remaps: &HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>>,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
let indices: Vec<(usize, Vec<String>)> = module
.functions
.iter()
.enumerate()
.filter_map(|(i, f)| imported_path_of(&f.name, imported_modules).map(|p| (i, p)))
.collect();
for (idx, source_path) in indices {
let Some(remap) = remaps.get(&source_path) else {
continue;
};
if let Some(func) = module.functions.get_mut(idx) {
apply_file_remap(&mut func.span, remap);
walk_function_spans_mut(func, &mut |s| apply_file_remap(s, remap));
}
}
}
fn remap_struct_file_ids(
module: &mut IrModule,
remaps: &HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>>,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
let indices: Vec<(usize, Vec<String>)> = module
.structs
.iter()
.enumerate()
.filter_map(|(i, s)| imported_path_of(&s.name, imported_modules).map(|p| (i, p)))
.collect();
for (idx, source_path) in indices {
let Some(remap) = remaps.get(&source_path) else {
continue;
};
if let Some(s) = module.structs.get_mut(idx) {
apply_file_remap(&mut s.span, remap);
for field in &mut s.fields {
apply_file_remap(&mut field.span, remap);
if let Some(d) = &mut field.default {
walk_expr_spans_mut(d, &mut |sp| apply_file_remap(sp, remap));
}
}
}
}
}
fn remap_enum_file_ids(
module: &mut IrModule,
remaps: &HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>>,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
let indices: Vec<(usize, Vec<String>)> = module
.enums
.iter()
.enumerate()
.filter_map(|(i, e)| imported_path_of(&e.name, imported_modules).map(|p| (i, p)))
.collect();
for (idx, source_path) in indices {
let Some(remap) = remaps.get(&source_path) else {
continue;
};
if let Some(e) = module.enums.get_mut(idx) {
apply_file_remap(&mut e.span, remap);
for variant in &mut e.variants {
apply_file_remap(&mut variant.span, remap);
for field in &mut variant.fields {
apply_file_remap(&mut field.span, remap);
if let Some(d) = &mut field.default {
walk_expr_spans_mut(d, &mut |sp| {
apply_file_remap(sp, remap);
});
}
}
}
}
}
}
fn remap_let_file_ids(
module: &mut IrModule,
remaps: &HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>>,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
let indices: Vec<(usize, Vec<String>)> = module
.lets
.iter()
.enumerate()
.filter_map(|(i, l)| imported_path_of(&l.name, imported_modules).map(|p| (i, p)))
.collect();
for (idx, source_path) in indices {
let Some(remap) = remaps.get(&source_path) else {
continue;
};
if let Some(l) = module.lets.get_mut(idx) {
apply_file_remap(&mut l.span, remap);
walk_expr_spans_mut(&mut l.value, &mut |sp| {
apply_file_remap(sp, remap);
});
}
}
}
fn remap_impl_file_ids(
module: &mut IrModule,
remaps: &HashMap<Vec<String>, HashMap<crate::ir::FileId, crate::ir::FileId>>,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
let sources: Vec<(usize, Option<Vec<String>>)> = module
.impls
.iter()
.enumerate()
.map(|(i, imp)| {
let source = match imp.target {
ImplTarget::Struct(id) => module
.get_struct(id)
.and_then(|s| imported_path_of(&s.name, imported_modules)),
ImplTarget::Enum(id) => module
.get_enum(id)
.and_then(|e| imported_path_of(&e.name, imported_modules)),
ImplTarget::Primitive(_) => None,
};
(i, source)
})
.collect();
for (idx, source_opt) in sources {
let Some(source_path) = source_opt else {
continue;
};
let Some(remap) = remaps.get(&source_path) else {
continue;
};
if let Some(imp) = module.impls.get_mut(idx) {
apply_file_remap(&mut imp.span, remap);
for method in &mut imp.functions {
apply_file_remap(&mut method.span, remap);
walk_function_spans_mut(method, &mut |sp| apply_file_remap(sp, remap));
}
}
}
}
fn apply_file_remap(
span: &mut crate::ir::IrSpan,
remap: &HashMap<crate::ir::FileId, crate::ir::FileId>,
) {
if let Some(new_file) = remap.get(&span.file).copied() {
span.file = new_file;
}
}