use crate::*; use std::collections::HashSet; pub struct MergeError<'a> { pub resolver: &'a Resolver, /// A list of source units involved in a cycle. pub cyclic_unit_ids: Vec, } impl MergeError<'_> { pub fn report(&self) { let message = "A cyclic dependency was found between the following files:"; let mut details = InkedString::new(); for id in &self.cyclic_unit_ids { let unit = &self.resolver.source_units[*id]; let path = &unit.source_unit.path(); match unit.source_unit.name() { Some(name) => { details.push(ink!("{name}")); details.push(ink!(" ({path})\n").dim()); } None => { details.push(ink!("{path}\n")); } }; // Print each parent involved in the dependency cycle. for parent_id in &unit.parent_ids { if !self.cyclic_unit_ids.contains(parent_id) { continue; } let parent_unit = &self.resolver.source_units[*parent_id]; let parent_path = &parent_unit.source_unit.path(); match parent_unit.source_unit.name() { Some(parent_name) => { details.push(ink!(" => {parent_name}")); details.push(ink!(" ({parent_path})\n").dim()); } None => { details.push(ink!(" => {parent_path}\n")); } }; // Report all referenced symbols that are defined by this parent. let mut reported_definition_ids = HashSet::new(); for reference in &self.resolver.resolved { if reference.tracked.source_id == *id { if reported_definition_ids.insert(reference.definition) { let definition = &self.resolver.definitions[reference.definition]; if definition.tracked.source_id == *parent_id { details.push(ink!(" {:?}\n", definition.tracked.symbol)); } } } } } } log_error(message, Some(details)); } }