use super::index::DefIndex;
use super::ladder::{resolve_ref, Resolution};
use super::scope::{FileContext, FileUsings};
use crate::graph::FragRef;
use std::collections::HashMap;
pub(super) fn resolve_ref_by_arity(
mut probe: FragRef,
arity: Option<usize>,
usings: &FileUsings,
ns: &str,
index: &DefIndex,
aliases: &HashMap<String, String>,
file_contexts: &HashMap<String, FileContext>,
) -> Resolution {
if let Some(n) = arity {
let full = aliases.get(&probe.name).unwrap_or(&probe.name);
let simple = full.rsplit('.').next().unwrap_or(full);
let shared = index.simple_name_to_defs.get(simple).map_or(0, Vec::len) >= 2;
if shared {
probe.type_arg_count = Some(n);
let exact = resolve_ref(&probe, usings, ns, index, aliases, file_contexts);
if !matches!(exact, Resolution::External) {
return exact;
}
probe.type_arg_count = None;
}
}
resolve_ref(&probe, usings, ns, index, aliases, file_contexts)
}
pub(super) fn resolve_receiver_type(
mut probe: FragRef,
arity: Option<usize>,
usings: &FileUsings,
ns: &str,
index: &DefIndex,
aliases: &HashMap<String, String>,
file_contexts: &HashMap<String, FileContext>,
) -> Resolution {
if probe.qualified.is_some() {
probe.type_arg_count = arity;
return resolve_ref(&probe, usings, ns, index, aliases, file_contexts);
}
if let Some(n) = arity {
if n >= 1 {
let full = aliases.get(&probe.name).unwrap_or(&probe.name);
let simple = full.rsplit('.').next().unwrap_or(full);
let shared = index.simple_name_to_defs.get(simple).map_or(0, Vec::len) >= 2;
if shared {
probe.type_arg_count = Some(n);
return resolve_ref(&probe, usings, ns, index, aliases, file_contexts);
}
}
}
resolve_ref_by_arity(probe, arity, usings, ns, index, aliases, file_contexts)
}
pub(super) fn base_arity(index: &DefIndex, idx: usize, base: &str) -> usize {
index.member_lists[idx]
.base_generic_args
.iter()
.find(|(k, _)| k == base)
.map_or(0, |(_, v)| v.len())
}
pub(super) fn method_arity_admits(
index: &DefIndex,
idx: usize,
member: &str,
arg_count: usize,
) -> bool {
match index.member_lists[idx].method_arities.get(member) {
Some(ranges) => ranges
.iter()
.any(|&(min, max)| min <= arg_count && (max == -1 || (arg_count as i64) <= max)),
None => true,
}
}
#[derive(Clone, Copy, Debug, PartialEq, Eq)]
pub(super) struct CallArity {
pub(super) values: usize,
pub(super) type_args: Option<usize>,
}
pub(super) fn call_arity(r: &FragRef) -> Option<CallArity> {
r.arg_count.map(|values| CallArity {
values,
type_args: r.method_type_arg_count,
})
}
pub(super) fn method_call_admits(
index: &DefIndex,
idx: usize,
member: &str,
call: CallArity,
) -> bool {
let lists = &index.member_lists[idx];
if let Some(written) = call.type_args {
let paired = !lists.unpaired_overload_names.iter().any(|n| n == member);
if let Some(overloads) = lists.overload_counts.get(member).filter(|_| paired) {
return overloads.iter().any(|&(min, max, count)| {
count == written && min <= call.values && (max == -1 || (call.values as i64) <= max)
});
}
}
method_arity_admits(index, idx, member, call.values)
}
pub(super) fn arity_accepts(entry: &crate::graph::FragExtensionMethod, call: CallArity) -> bool {
let values = call.values;
let in_range =
entry.arity_min <= values && (entry.arity_max == -1 || (values as i64) <= entry.arity_max);
in_range
&& match (call.type_args, entry.type_param_count) {
(Some(written), Some(declared)) => written == declared,
_ => true,
}
}
pub(super) fn generic_args_unify(
this_args: Option<&Vec<String>>,
receiver_args: Option<&Vec<String>>,
) -> bool {
match (this_args, receiver_args) {
(None, None) => true,
(Some(a), Some(b)) => {
a.len() == b.len() && a.iter().zip(b).all(|(x, y)| x == "*" || y == "*" || x == y)
}
_ => false,
}
}