Skip to main content

luaur_analysis/methods/
constraint_solver_unify.rs

1//! `template<typename TID>
2//!  bool ConstraintSolver::unify(NotNull<const Constraint> constraint, TID subTy, TID superTy)`
3//! (`Analysis/src/ConstraintSolver.cpp:3833-3871`, hand-ported faithfully).
4
5use core::ptr::NonNull;
6
7use crate::enums::unify_result::UnifyResult;
8use crate::records::constraint::Constraint;
9use crate::records::constraint_solver::ConstraintSolver;
10use crate::records::internal_error_reporter::InternalErrorReporter;
11use crate::records::occurs_check_failed::OccursCheckFailed;
12use crate::records::scope::Scope;
13use crate::records::subtyping::Subtyping;
14use crate::records::subtyping_result::SubtypingResult;
15use crate::records::subtyping_unifier::SubtypingUnifier;
16use crate::records::unification_too_complex::UnificationTooComplex;
17use crate::type_aliases::type_id::TypeId;
18use crate::type_aliases::type_pack_id::TypePackId;
19
20/// Models the C++ `static_assert(std::is_same_v<TID, TypeId> || std::is_same_v<TID, TypePackId>)`
21/// plus the `if constexpr` split over the `Subtyping::isSubtype` overload.
22pub trait UnifyTid: Copy {
23    fn is_subtype_in(
24        self,
25        subtyping: &mut Subtyping,
26        super_ty: Self,
27        scope: *mut Scope,
28    ) -> SubtypingResult;
29}
30
31impl UnifyTid for TypeId {
32    fn is_subtype_in(
33        self,
34        subtyping: &mut Subtyping,
35        super_ty: Self,
36        scope: *mut Scope,
37    ) -> SubtypingResult {
38        subtyping.is_subtype_type_id_type_id_not_null_scope(self, super_ty, scope)
39    }
40}
41
42impl UnifyTid for TypePackId {
43    fn is_subtype_in(
44        self,
45        subtyping: &mut Subtyping,
46        super_ty: Self,
47        scope: *mut Scope,
48    ) -> SubtypingResult {
49        subtyping.is_subtype_type_pack_id_type_pack_id_not_null_scope_vector_type_id(
50            self,
51            super_ty,
52            scope,
53            &alloc::vec::Vec::new(),
54        )
55    }
56}
57
58impl ConstraintSolver {
59    pub fn constraint_solver_unify<TID: UnifyTid>(
60        &mut self,
61        constraint: *const Constraint,
62        sub_ty: TID,
63        super_ty: TID,
64    ) -> bool {
65        let scope = unsafe { (*constraint).scope };
66        let location = unsafe { (*constraint).location };
67        let ice_ptr =
68            &self.ice_reporter as *const InternalErrorReporter as *mut InternalErrorReporter;
69
70        let mut subtyping = Subtyping::subtyping_owned(
71            self.builtin_types,
72            self.arena,
73            self.normalizer,
74            self.type_function_runtime,
75            ice_ptr,
76        );
77        let mut stu = SubtypingUnifier::subtyping_unifier(self.arena, self.builtin_types, ice_ptr);
78
79        let mut result = sub_ty.is_subtype_in(&mut subtyping, super_ty, scope);
80
81        let unifier_result =
82            stu.dispatch_constraints(constraint, core::mem::take(&mut result.assumed_constraints));
83
84        for cv in unifier_result.outstanding_constraints.iter() {
85            let new_constraint =
86                self.push_constraint(NonNull::new(scope).unwrap(), location, cv.clone());
87            self.inherit_blocks(constraint, new_constraint.as_ptr());
88        }
89
90        for (ty, new_upper_bounds) in unifier_result.upper_bound_contributors.iter() {
91            let upper_bounds = self.upper_bound_contributors.get_or_insert(*ty);
92            upper_bounds.extend(new_upper_bounds.iter().cloned());
93        }
94
95        match unifier_result.unified {
96            UnifyResult::OccursCheckFailed => {
97                self.report_error_type_error_data_location(
98                    OccursCheckFailed::default().into(),
99                    &location,
100                );
101                false
102            }
103            UnifyResult::TooComplex => {
104                self.report_error_type_error_data_location(
105                    UnificationTooComplex::default().into(),
106                    &location,
107                );
108                false
109            }
110            UnifyResult::Ok => true,
111        }
112    }
113}