use yog_ids::script_problem;
use super::Checker;
use super::context::Context;
use super::model::Type;
use crate::ast::{Expr, ExprKind, Method};
impl Checker<'_, '_, '_> {
fn group(&mut self, e: &Expr) -> Option<Vec<(Method, Context)>> {
let methods = match &e.kind {
ExprKind::Ident(name) if self.local(name).is_none() => self.callable(name),
ExprKind::Member {
expr,
name,
safe: false,
} => {
let on = self.quietly(|c| c.expr(expr));
let owner = match on.non_null() {
Type::Static(n, args) => Type::Own(n.clone(), args.clone()),
t => t.clone(),
};
if self.quietly(|c| c.own_member(&owner, &name.text)).known() {
return None;
}
self.own_methods(&owner, &name.text).unwrap_or_default()
}
_ => return None,
};
(!methods.is_empty()).then_some(methods)
}
pub(super) fn is_group(&mut self, e: &Expr) -> bool {
self.quietly(|c| c.group(e)).is_some()
}
pub(super) fn group_as(&mut self, e: &Expr, params: &[Type], ret: &Type) -> bool {
let Some(methods) = self.quietly(|c| c.group(e)) else {
return false;
};
if let ExprKind::Member { expr, .. } = &e.kind {
self.expr(expr);
}
let wanted = Type::Fn(params.to_vec(), Box::new(ret.clone()));
match self.of_shape(&methods, params, Some(ret)) {
Some((m, context)) => {
let used = self.method_use(&m, &context);
self.types.set_method(e, used);
self.types.set(e, wanted);
}
None => self.report.error(
script_problem::TYPE_MISMATCH,
e.span,
format!("no overload of this method is a `{wanted}`"),
),
}
true
}
pub(super) fn group_result(&mut self, e: &Expr, params: &[Type]) -> Option<Type> {
let methods = self.quietly(|c| c.group(e))?;
let (m, context) = self.of_shape(&methods, params, None)?;
Some(self.in_context(&context, |c| c.signature_types(&m)).1)
}
fn of_shape(
&mut self,
methods: &[(Method, Context)],
params: &[Type],
ret: Option<&Type>,
) -> Option<(Method, Context)> {
methods
.iter()
.find(|(m, context)| {
let (taken, given) = self.in_context(context, |c| c.signature_types(m));
taken.len() == params.len()
&& params.iter().zip(&taken).all(|(p, t)| p.converts_to(t))
&& ret.is_none_or(|r| given.converts_to(r))
})
.cloned()
}
}