Skip to main content

luaur_analysis/methods/
constraint_solver_push_constraint.rs

1//! `NotNull<Constraint> ConstraintSolver::pushConstraint(NotNull<Scope> scope, const Location& location, ConstraintV cv)`
2//! (`Analysis/src/ConstraintSolver.cpp:4094-4126`, hand-ported faithfully).
3
4use alloc::boxed::Box;
5use core::ptr::NonNull;
6
7use crate::enums::subtyping_variance::SubtypingVariance;
8use crate::records::code_too_complex::CodeTooComplex;
9use crate::records::constraint::Constraint;
10use crate::records::constraint_solver::ConstraintSolver;
11use crate::records::equality_constraint::EqualityConstraint;
12use crate::records::hash_subtype_constraint_record::HashSubtypeConstraintRecord;
13use crate::records::scope::Scope;
14use crate::records::subtype_constraint::SubtypeConstraint;
15use crate::records::subtype_constraint_record::SubtypeConstraintRecord;
16use crate::type_aliases::constraint_v::{ConstraintV, ConstraintVMember};
17use luaur_ast::records::location::Location;
18use luaur_common::records::dense_hash_table::DenseHasher;
19
20// C++ `size_t HashSubtypeConstraintRecord::operator()(const SubtypeConstraintRecord&)`
21// wired into the `DenseHashMap` hasher functor slot (the `operator()` body is
22// ported in `methods/hash_subtype_constraint_record_operator_call.rs`).
23impl DenseHasher<SubtypeConstraintRecord> for HashSubtypeConstraintRecord {
24    fn hash(&self, key: &SubtypeConstraintRecord) -> usize {
25        self.operator_call(key)
26    }
27}
28
29impl ConstraintSolver {
30    pub fn push_constraint(
31        &mut self,
32        scope: NonNull<Scope>,
33        location: Location,
34        cv: ConstraintV,
35    ) -> NonNull<Constraint> {
36        let mut scr: Option<SubtypeConstraintRecord> = None;
37        if let Some(sc) = SubtypeConstraint::get_if(&cv) {
38            scr = Some(SubtypeConstraintRecord {
39                subTy: sc.sub_type,
40                superTy: sc.super_type,
41                variance: SubtypingVariance::Covariant,
42            });
43        } else if let Some(ec) = EqualityConstraint::get_if(&cv) {
44            scr = Some(SubtypeConstraintRecord {
45                subTy: ec.assignment_type,
46                superTy: ec.result_type,
47                variance: SubtypingVariance::Invariant,
48            });
49        }
50
51        if let Some(record) = scr {
52            if let Some(f) = self.seen_constraints.find(&record) {
53                return NonNull::new(*f).unwrap();
54            }
55        }
56
57        let c: Box<Constraint> = Box::new(
58            Constraint::constraint_not_null_scope_location_constraint_v(scope, &location, cv),
59        );
60        let borrow: *mut Constraint = c.as_ref() as *const Constraint as *mut Constraint;
61
62        if let Some(record) = scr {
63            *self.seen_constraints.get_or_insert(record) = borrow;
64        }
65
66        self.solver_constraints.push(c);
67        self.unsolved_constraints.push(borrow as *const Constraint);
68
69        if self.solver_constraint_limit > 0 {
70            self.solver_constraint_limit -= 1;
71
72            if self.solver_constraint_limit == 0 {
73                self.report_error_type_error_data_location(
74                    CodeTooComplex::default().into(),
75                    &location,
76                );
77            }
78        }
79
80        NonNull::new(borrow).unwrap()
81    }
82}