use std::collections::HashMap;
use super::Checker;
use super::generics::Bound;
use super::model::Type;
use super::own::TypeKey;
pub(super) type Bases = HashMap<TypeKey, Vec<Type>>;
impl Checker<'_, '_, '_> {
pub(super) fn type_bases(&mut self) {
let written: Vec<(TypeKey, Vec<String>, Vec<crate::ast::Type>)> = self
.own
.all()
.map(|(k, t)| (k.clone(), t.generics.clone(), t.bases.clone()))
.collect();
let mut bases = Bases::new();
self.quietly(|c| {
for (key, generics, written) in written {
let typed = c.as_declared(&key.name, &generics, |c| {
written.iter().map(|b| c.type_of(b)).collect()
});
bases.insert(key, typed);
}
});
self.bases = bases;
}
pub(super) fn member_lineage(&self, name: &str, args: &[Type]) -> Vec<(TypeKey, Vec<Type>)> {
let interface = |k: &TypeKey| self.own.of_key(k).is_some_and(|o| o.interface);
let lineage = self.lineage_of(name, args);
if lineage.first().is_some_and(|(k, _)| interface(k)) {
return lineage;
}
lineage.into_iter().filter(|(k, _)| !interface(k)).collect()
}
pub(super) fn lineage_of(&self, name: &str, args: &[Type]) -> Vec<(TypeKey, Vec<Type>)> {
let mut out = vec![(TypeKey::new(name, args.len()), args.to_vec())];
let mut i = 0;
while let Some((key, args)) = out.get(i).cloned() {
let bound: Bound = self.bound_of(&key.name, &args);
for base in self.bases.get(&key).into_iter().flatten() {
if let Type::Own(n, a) = base.substitute(&bound) {
let k = TypeKey::new(n, a.len());
if !out.iter().any(|(seen, _)| *seen == k) {
out.push((k, a));
}
}
}
i += 1;
}
let first = TypeKey::new(name, args.len());
for base in self.own.implicit_bases(&first) {
if !out.iter().any(|(k, _)| *k == base) {
out.push((base, Vec::new()));
}
}
out
}
pub(super) fn quietly<R>(&mut self, f: impl FnOnce(&mut Self) -> R) -> R {
let kept = std::mem::take(&mut self.report.out);
let out = f(self);
self.report.out = kept;
out
}
}