Skip to main content

luaur_analysis/methods/
apply_mapped_generics_clean_subtyping.rs

1use crate::functions::get_type_alt_j::get_type_id;
2use crate::records::apply_mapped_generics::ApplyMappedGenerics;
3use crate::records::generic_type::GenericType;
4use crate::records::intersection_builder::IntersectionBuilder;
5use crate::records::union_builder::UnionBuilder;
6use crate::type_aliases::type_id::TypeId;
7use luaur_common::macros::luau_assert::LUAU_ASSERT;
8
9impl ApplyMappedGenerics {
10    pub fn clean_type_id(&mut self, ty: TypeId) -> TypeId {
11        let bounds = unsafe { (*self.env).get_mapped_type_bounds(ty, self.ice_reporter) };
12        let lower_bound = &bounds.lower_bound;
13        let upper_bound = &bounds.upper_bound;
14
15        if upper_bound.empty() && lower_bound.empty() {
16            // No bounds for the generic we're mapping.
17            // In this case, unknown vs never is an arbitrary choice:
18            // ie, does it matter if we map add<A, A> to add<unknown, unknown> or add<never, never> in the context of subtyping?
19            // We choose unknown here, since it's closest to the original behavior.
20            unsafe { (*self.builtin_types).unknownType }
21        } else if !upper_bound.empty() {
22            let mut ib = IntersectionBuilder::intersection_builder(self.arena, self.builtin_types);
23            for &ub in &upper_bound.order {
24                // NOTE: The original implementation skips over generic
25                // types, but that seems incorrect to me.
26                if unsafe { get_type_id::<GenericType>(ub).is_null() } {
27                    ib.add(ub);
28                }
29            }
30            ib.build()
31        } else if !lower_bound.empty() {
32            let mut ub_builder = UnionBuilder::union_builder(self.arena, self.builtin_types);
33            for &lb in &lower_bound.order {
34                // NOTE: The original implementation skips over generic
35                // types, but that seems incorrect to me.
36                if unsafe { get_type_id::<GenericType>(lb).is_null() } {
37                    ub_builder.add(lb);
38                }
39            }
40            ub_builder.build()
41        } else {
42            LUAU_ASSERT!(false);
43            unsafe { (*self.builtin_types).unknownType }
44        }
45    }
46}