Skip to main content

luaur_analysis/methods/
constraint_graph_unblock_constraint.rs

1use crate::functions::to_string_to_string_alt_q::to_string_constraint_to_string_options;
2use crate::records::constraint::Constraint;
3use crate::records::constraint_graph::ConstraintGraph;
4use crate::records::to_string_options::ToStringOptions;
5use crate::records::type_ids::TypeIds;
6use crate::records::unblocked_types::UnblockedTypes;
7use crate::type_aliases::constraint_vertex::ConstraintVertex;
8use crate::type_aliases::type_pack_ids::TypePackIds;
9use core::ptr::NonNull;
10use luaur_common::FFlag;
11
12impl ConstraintGraph {
13    pub fn unblock_constraint(&mut self, c: NonNull<Constraint>) -> UnblockedTypes {
14        let mut result = UnblockedTypes {
15            types: TypeIds::type_ids(),
16            packs: TypePackIds::new(core::ptr::null_mut()),
17        };
18
19        // The reverse dependencies of this constraint should contain all of the types
20        // and type packs that this constraint may mutate, either as a free type or
21        // as a blocked type.
22        let c_ptr = c.as_ptr() as *const Constraint;
23        let reverse_deps = self.find_reverse_dependency_list(ConstraintVertex::V2(c_ptr));
24        let reverse_deps_ref = unsafe { reverse_deps.as_ref() };
25
26        for rdep in reverse_deps_ref.order.iter() {
27            // The C++ `for (auto rdep : *reverseDeps)` iterates only present entries.
28            if !reverse_deps_ref.contains(rdep.clone()) {
29                continue;
30            }
31
32            if let Some(ty) = rdep.get_if_0() {
33                let ty = *ty;
34                result.types.insert_type_id(ty);
35                let deps = self.find_dependency_list(ConstraintVertex::V0(ty));
36                let deps_mut = unsafe { &mut *deps.as_ptr() };
37                deps_mut.remove(ConstraintVertex::V2(c_ptr));
38            } else if let Some(tp) = rdep.get_if_1() {
39                let tp = *tp;
40                let _ = result.packs.insert(tp);
41                let deps = self.find_dependency_list(ConstraintVertex::V1(tp));
42                let deps_mut = unsafe { &mut *deps.as_ptr() };
43                deps_mut.remove(ConstraintVertex::V2(c_ptr));
44            } else if let Some(dep_cons) = rdep.get_if_2() {
45                let dep_cons = *dep_cons;
46                let deps = self.find_dependency_list(ConstraintVertex::V2(dep_cons));
47                let deps_mut = unsafe { &mut *deps.as_ptr() };
48                deps_mut.remove(ConstraintVertex::V2(c_ptr));
49                if FFlag::DebugLuauLogSolver.get() {
50                    let mut opts = ToStringOptions::default();
51                    opts.exhaustive = true;
52                    std::print!(
53                        "Unblocking count={}\t{}\n",
54                        deps_mut.size() as i32,
55                        to_string_constraint_to_string_options(unsafe { &*dep_cons }, &mut opts)
56                    );
57                }
58            } else {
59                luaur_common::macros::luau_assert::LUAU_ASSERT!(false);
60            }
61        }
62
63        /*
64         * This whole song and dance is to repair the constraint graph after we
65         * dispatch a constraint.
66         *
67         * We are assuming that, after a constraint has been dispatched, some
68         * number of mutations have been made to the type graph. Importantly: if a
69         * type has been mutated, then it was previously a reverse dependency of
70         * [c]. If that is the case, then we can walk the reverse deps of [c] and
71         * try to find bound types, shift their references over to their bounds,
72         * and "repair" the dependency graph without having to track every single
73         * [bind] call.
74         */
75
76        for ty in result.types.order.iter() {
77            self.repair_type_references_type_id(*ty);
78        }
79
80        let packs: alloc::vec::Vec<_> = result.packs.iter().copied().collect();
81        for type_pack in packs {
82            self.repair_type_references_type_pack_id(type_pack);
83        }
84
85        result
86    }
87}