use std::collections::{HashMap, HashSet};
use crate::ir::{IrModule, IrModuleNode};
use super::naming::qualified_name;
pub(in crate::ir::monomorphise) fn merge_imported_module_trees(
module: &mut IrModule,
imported_modules: &HashMap<Vec<String>, IrModule>,
) {
for (path, imported) in imported_modules {
if path.is_empty() {
continue;
}
let prefix = qualified_name(path, "");
let mut leaf = IrModuleNode::default();
for s in &imported.structs {
let q = format!("{prefix}{}", s.name);
if let Some(id) = module.struct_id(&q) {
leaf.structs.push(id);
}
}
for t in &imported.traits {
let q = format!("{prefix}{}", t.name);
if let Some(id) = module.trait_id(&q) {
leaf.traits.push(id);
}
}
for e in &imported.enums {
let q = format!("{prefix}{}", e.name);
if let Some(id) = module.enum_id(&q) {
leaf.enums.push(id);
}
}
for f in &imported.functions {
let q = format!("{prefix}{}", f.name);
if let Some(id) = module.function_id(&q) {
leaf.functions.push(id);
}
}
splice_module_node(&mut module.modules, path, leaf);
}
}
fn splice_module_node(parent_nodes: &mut Vec<IrModuleNode>, path: &[String], leaf: IrModuleNode) {
let Some((head, rest)) = path.split_first() else {
return;
};
if rest.is_empty() {
if let Some(existing) = parent_nodes.iter_mut().find(|n| &n.name == head) {
existing.structs.extend(leaf.structs);
existing.traits.extend(leaf.traits);
existing.enums.extend(leaf.enums);
existing.functions.extend(leaf.functions);
existing.modules.extend(leaf.modules);
} else {
let mut node = leaf;
node.name.clone_from(head);
parent_nodes.push(node);
}
return;
}
let idx = parent_nodes
.iter()
.position(|n| &n.name == head)
.unwrap_or_else(|| {
parent_nodes.push(IrModuleNode {
name: head.clone(),
..Default::default()
});
parent_nodes.len().saturating_sub(1)
});
let Some(node) = parent_nodes.get_mut(idx) else {
return;
};
splice_module_node(&mut node.modules, rest, leaf);
}
pub(in crate::ir::monomorphise) fn detect_import_cycle(
imported_modules: &HashMap<Vec<String>, IrModule>,
) -> Option<Vec<String>> {
let mut visited: HashSet<Vec<String>> = HashSet::new();
let mut on_stack: Vec<Vec<String>> = Vec::new();
for start in imported_modules.keys() {
if visited.contains(start) {
continue;
}
if let Some(cycle) = dfs_detect_cycle(start, imported_modules, &mut visited, &mut on_stack)
{
return Some(cycle);
}
}
None
}
fn dfs_detect_cycle(
node: &Vec<String>,
imported_modules: &HashMap<Vec<String>, IrModule>,
visited: &mut HashSet<Vec<String>>,
on_stack: &mut Vec<Vec<String>>,
) -> Option<Vec<String>> {
if on_stack.contains(node) {
return Some(node.clone());
}
if visited.contains(node) {
return None;
}
on_stack.push(node.clone());
if let Some(module) = imported_modules.get(node) {
for import in &module.imports {
if let Some(cycle) =
dfs_detect_cycle(&import.module_path, imported_modules, visited, on_stack)
{
return Some(cycle);
}
}
}
on_stack.pop();
visited.insert(node.clone());
None
}