use crate::enums::polarity::Polarity;
use crate::enums::unify_result::UnifyResult;
use crate::functions::get_approximate_return_type_for_function_call_type_utils::get_approximate_return_type_for_function_call_type_id_dense_hash_set_type_id as get_approximate_return_type_for_function_call;
use crate::functions::instantiate_2_instantiation_2_alt_b::instantiate_2;
use crate::functions::track_interior_free_type::track_interior_free_type;
use crate::functions::track_interior_free_type_pack::track_interior_free_type_pack;
use crate::records::function_type::FunctionType;
use crate::records::overload_resolution::OverloadResolution;
use crate::records::overload_resolver::OverloadResolver;
use crate::records::subtyping::Subtyping;
use crate::records::type_function_context::TypeFunctionContext;
use crate::records::unifier_2::Unifier2;
use crate::type_aliases::type_id::TypeId;
use crate::type_aliases::type_pack_id::TypePackId;
use luaur_ast::records::location::Location;
use luaur_common::records::dense_hash_set::DenseHashSet;
pub fn solve_function_call(
ctx: *mut TypeFunctionContext,
location: Location,
fn_ty: TypeId,
args_pack: TypePackId,
) -> Option<TypePackId> {
let ctx_ref = unsafe { &*ctx };
let subtyping = Subtyping::subtyping_owned(
ctx_ref.builtins.as_ptr(),
ctx_ref.arena.as_ptr(),
ctx_ref.normalizer.as_ptr(),
ctx_ref.type_function_runtime.as_ptr(),
ctx_ref.ice.as_ptr(),
);
let mut resolver = OverloadResolver {
builtin_types: ctx_ref.builtins.as_ptr(),
arena: ctx_ref.arena.as_ptr(),
normalizer: ctx_ref.normalizer.as_ptr(),
type_function_runtime: ctx_ref.type_function_runtime.as_ptr(),
scope: ctx_ref.scope.as_ptr(),
ice: ctx_ref.ice.as_ptr(),
limits: unsafe { core::ptr::read(ctx_ref.limits.as_ptr() as *const _) },
subtyping,
call_loc: location,
};
let mut unique_types: DenseHashSet<TypeId> = DenseHashSet::new(core::ptr::null());
let resolution: OverloadResolution = resolver.resolve_overload(
fn_ty,
args_pack,
location,
&mut unique_types as *mut DenseHashSet<TypeId>,
false,
);
if resolution.ok.is_empty() && resolution.potential_overloads.is_empty() {
return None;
}
let selected = resolution.get_unambiguous_overload();
let selected_overload = selected.overload?;
let mut ret_pack = unsafe {
(*ctx_ref.arena.as_ptr()).fresh_type_pack(ctx_ref.scope.as_ptr(), Polarity::Positive)
};
let prospective_function = unsafe {
(*ctx_ref.arena.as_ptr()).add_type(FunctionType::function_type_new(
args_pack, ret_pack, None, false,
))
};
let mut unifier = Unifier2::unifier_2_not_null_type_arena_not_null_builtin_types_not_null_scope_not_null_internal_error_reporter(
ctx_ref.arena,
ctx_ref.builtins,
ctx_ref.scope,
ctx_ref.ice,
);
let unify_result = unifier.unify(selected_overload, prospective_function);
match unify_result {
UnifyResult::Ok => {}
UnifyResult::OccursCheckFailed => return None,
UnifyResult::TooComplex => return None,
}
if !unifier.generic_substitutions.empty() || !unifier.generic_pack_substitutions.empty() {
let mut subtyping2 = Subtyping::subtyping_owned(
ctx_ref.builtins.as_ptr(),
ctx_ref.arena.as_ptr(),
ctx_ref.normalizer.as_ptr(),
ctx_ref.type_function_runtime.as_ptr(),
ctx_ref.ice.as_ptr(),
);
let mut seen: DenseHashSet<TypeId> = DenseHashSet::new(core::ptr::null());
let new_ret_tp =
get_approximate_return_type_for_function_call(selected_overload, &mut seen)
.unwrap_or(unsafe { ctx_ref.builtins.as_ref().errorTypePack });
let subst = instantiate_2(
ctx_ref.arena.as_ptr(),
unifier.generic_substitutions.clone(),
unifier.generic_pack_substitutions.clone(),
&mut subtyping2 as *mut Subtyping,
ctx_ref.scope.as_ptr(),
new_ret_tp,
);
let subst = subst?;
ret_pack = subst;
}
for &ty in &unifier.new_fresh_types {
track_interior_free_type(ctx_ref.scope.as_ptr(), ty);
}
for &tp in &unifier.new_fresh_type_packs {
track_interior_free_type_pack(ctx_ref.scope.as_ptr(), tp);
}
Some(ret_pack)
}