Skip to main content

luaur_analysis/functions/
quantify.rs

1use crate::functions::get_mutable_type::getMutable;
2use crate::records::free_type::FreeType;
3use crate::records::free_type_pack::FreeTypePack;
4use crate::records::function_type::FunctionType;
5use crate::records::generic_type_visitor::{GenericTypeVisitor, GenericTypeVisitorTrait};
6use crate::records::quantifier::Quantifier;
7use crate::records::table_type::TableType;
8use crate::records::type_level::TypeLevel;
9use crate::type_aliases::type_id::TypeId;
10use crate::type_aliases::type_pack_id::TypePackId;
11use core::ffi::c_void;
12use luaur_common::macros::luau_assert::LUAU_ASSERT;
13use luaur_common::records::dense_hash_set::DenseHashSet;
14
15// C++ `struct Quantifier final : TypeOnceVisitor` (Quantify.cpp:15). The
16// virtual `visit(...)` overrides live as the `GenericTypeVisitorTrait` impl
17// (the `IndexCollector`/`FindCyclicTypes` precedents) so `traverse` dispatches
18// into them; the bodies delegate to the inherent methods declared on the
19// sibling `quantifier_visit_quantify*` files.
20impl GenericTypeVisitorTrait for Quantifier {
21    type Seen = DenseHashSet<*mut c_void>;
22
23    fn visitor_base(&mut self) -> &mut GenericTypeVisitor<Self::Seen> {
24        &mut self.base.base
25    }
26
27    fn visit_type_id_free_type(&mut self, ty: TypeId, ftv: &FreeType) -> bool {
28        Quantifier::visit_type_id_free_type(self, ty, ftv)
29    }
30
31    fn visit_type_id_table_type(&mut self, ty: TypeId, ttv: &TableType) -> bool {
32        Quantifier::visit_type_id_table_type(self, ty, ttv)
33    }
34
35    fn visit_type_pack_id_free_type_pack(&mut self, tp: TypePackId, ftp: &FreeTypePack) -> bool {
36        Quantifier::visit_type_pack_id_free_type_pack(self, tp, ftp)
37    }
38}
39
40pub fn quantify(ty: TypeId, level: TypeLevel) {
41    let mut q = Quantifier::quantifier(level);
42    q.traverse_type_id(ty);
43
44    let ftv = unsafe { getMutable::<FunctionType>(ty) };
45    LUAU_ASSERT!(!ftv.is_null());
46    unsafe {
47        (*ftv).generics.extend(q.generics.iter().copied());
48        (*ftv).generic_packs.extend(q.generic_packs.iter().copied());
49    }
50}