Skip to main content

luaur_analysis/methods/
overload_resolver_test_function_or_union.rs

1//! Source: `Analysis/src/OverloadResolver.cpp:550-593` (hand-ported)
2use crate::functions::follow_type::follow_type_id;
3use crate::functions::get_type_alt_j::get_type_id;
4use crate::records::cannot_call_non_function::CannotCallNonFunction;
5use crate::records::overload_resolution::OverloadResolution;
6use crate::records::overload_resolver::OverloadResolver;
7use crate::records::type_error::TypeError;
8use crate::records::union_type::UnionType;
9use crate::type_aliases::type_error_data::TypeErrorData;
10use crate::type_aliases::type_id::TypeId;
11use crate::type_aliases::type_pack_id::TypePackId;
12use luaur_ast::records::location::Location;
13use luaur_common::macros::luau_assert::LUAU_ASSERT;
14use luaur_common::records::dense_hash_set::DenseHashSet;
15use luaur_common::records::variant::Variant2;
16
17impl OverloadResolver {
18    pub fn test_function_or_union(
19        &mut self,
20        result: &mut OverloadResolution,
21        fn_ty: TypeId,
22        args_pack: TypePackId,
23        fn_location: Location,
24        unique_types: *mut DenseHashSet<TypeId>,
25    ) {
26        let fn_ty = unsafe { follow_type_id(fn_ty) };
27        LUAU_ASSERT!(fn_ty == unsafe { follow_type_id(fn_ty) });
28
29        let ut = unsafe { get_type_id::<UnionType>(fn_ty) };
30        if !ut.is_null() {
31            // A union of functions is a valid overload iff every type within it is a valid overload.
32
33            let mut inner_result = OverloadResolution {
34                ok: alloc::vec::Vec::new(),
35                non_functions: alloc::vec::Vec::new(),
36                potential_overloads: alloc::vec::Vec::new(),
37                incompatible_overloads: alloc::vec::Vec::new(),
38                arity_mismatches: alloc::vec::Vec::new(),
39                metamethods: DenseHashSet::new(core::ptr::null_mut()),
40            };
41            let options = unsafe { (*ut).options.clone() };
42            let mut count: usize = 0;
43            for t in options {
44                count += 1;
45                self.test_function_or_call_metamethod(
46                    &mut inner_result,
47                    t,
48                    args_pack,
49                    fn_location,
50                    unique_types,
51                );
52            }
53
54            if count == inner_result.ok.len() {
55                result.ok.push(fn_ty);
56            } else if count == inner_result.ok.len() + inner_result.potential_overloads.len() {
57                let mut all_constraints = alloc::vec::Vec::new();
58                for (_t, constraints) in inner_result.potential_overloads.iter() {
59                    all_constraints.extend(constraints.iter().cloned());
60                }
61
62                result.potential_overloads.push((fn_ty, all_constraints));
63            } else {
64                // FIXME: We should probably report something better here, but it's
65                // important for type checking that we include this.
66                let errors = alloc::vec![TypeError::type_error_location_type_error_data(
67                    fn_location,
68                    TypeErrorData::CannotCallNonFunction(CannotCallNonFunction { ty: fn_ty }),
69                )];
70                result
71                    .incompatible_overloads
72                    .push((fn_ty, Variant2::V1(errors)));
73            }
74        } else {
75            self.test_function_or_call_metamethod(
76                result,
77                fn_ty,
78                args_pack,
79                fn_location,
80                unique_types,
81            );
82        }
83    }
84}