use pedant_types::ReferenceKind;
use super::answer::Answer;
use super::implementations::{Implementations, InterfaceSlot};
use super::index::{Index, Slot};
pub(super) fn selected(
index: &Index,
implementations: &Implementations,
asked: (ReferenceKind, &str),
found: Box<[usize]>,
) -> Answer {
let (default, name) = asked;
let dispatched = found
.iter()
.any(|slot| index.slot(*slot).is_some_and(Slot::is_interface_method));
match dispatched {
true => Answer::dispatched(default, targets(index, implementations, name, &found)),
false => Answer::found(default, found, None),
}
}
fn targets(
index: &Index,
implementations: &Implementations,
name: &str,
found: &[usize],
) -> Box<[usize]> {
let mut reached: Vec<usize> = found.to_vec();
for slot in found.iter() {
reached.extend(implementing_methods(index, implementations, name, *slot));
}
reached.sort_unstable();
reached.dedup();
reached.into_boxed_slice()
}
fn implementing_methods(
index: &Index,
implementations: &Implementations,
name: &str,
method: usize,
) -> Vec<usize> {
let interface = index.slot(method).and_then(|slot| slot.holder);
interface
.into_iter()
.flat_map(|holder| implementations.implementors(InterfaceSlot::new(holder)))
.flat_map(|concrete| implementations.answering(*concrete, name))
.map(|member| member.slot)
.filter(|slot| index.slot(*slot).is_some_and(Slot::is_concrete_method))
.collect()
}