mod resolve_signature_by_args;
use std::sync::Arc;
use emmylua_parser::{LuaAstNode, LuaCallExpr};
use crate::db_index::{DbIndex, LuaFunctionType, LuaType};
use super::{
LuaInferCache,
generic::instantiate_func_generic,
infer::{InferCallFuncResult, InferFailReason, infer_expr_list_types, try_infer_expr_no_flow},
};
pub(crate) use resolve_signature_by_args::{callable_accepts_args, resolve_signature_by_args};
pub fn resolve_signature(
db: &DbIndex,
cache: &mut LuaInferCache,
overloads: Vec<Arc<LuaFunctionType>>,
call_expr: LuaCallExpr,
is_generic: bool,
arg_count: Option<usize>,
) -> InferCallFuncResult {
let args = call_expr.get_args_list().ok_or(InferFailReason::None)?;
let mut declined_no_flow_arg_ranges = Vec::new();
let expr_types_with_ranges = infer_expr_list_types(
db,
cache,
args.get_args().collect::<Vec<_>>().as_slice(),
arg_count,
|db, cache, expr| {
if cache.is_no_flow() {
let expr_range = expr.get_range();
let Some(expr_type) = try_infer_expr_no_flow(db, cache, expr)? else {
if !is_generic {
declined_no_flow_arg_ranges.push(expr_range);
return Ok(LuaType::Unknown);
}
return Err(InferFailReason::None);
};
Ok(expr_type)
} else {
Ok(crate::infer_expr(db, cache, expr).unwrap_or(LuaType::Unknown))
}
},
)?;
let declined_no_flow_args = expr_types_with_ranges
.iter()
.map(|(_, range)| declined_no_flow_arg_ranges.contains(range))
.collect::<Vec<_>>();
let expr_types: Vec<_> = expr_types_with_ranges
.into_iter()
.map(|(ty, _)| ty)
.collect();
if is_generic {
resolve_signature_by_generic(db, cache, overloads, call_expr, expr_types, arg_count)
} else {
resolve_signature_by_args(
db,
&overloads,
&expr_types,
call_expr.is_colon_call(),
arg_count,
&declined_no_flow_args,
)
}
}
fn resolve_signature_by_generic(
db: &DbIndex,
cache: &mut LuaInferCache,
overloads: Vec<Arc<LuaFunctionType>>,
call_expr: LuaCallExpr,
expr_types: Vec<LuaType>,
arg_count: Option<usize>,
) -> InferCallFuncResult {
let mut instantiate_funcs = Vec::new();
for func in overloads {
let instantiate_func = instantiate_func_generic(db, cache, &func, call_expr.clone())?;
instantiate_funcs.push(Arc::new(instantiate_func));
}
resolve_signature_by_args(
db,
&instantiate_funcs,
&expr_types,
call_expr.is_colon_call(),
arg_count,
&[],
)
}