1use crate::enums::table_state::TableState;
2use crate::functions::contains_subscripted_definition::contains_subscripted_definition;
3use crate::functions::follow_type::follow_type_id;
4use crate::functions::get_type_alt_j::get_type_id;
5use crate::records::conjunction_refinement::Conjunction;
6use crate::records::constraint_generator::ConstraintGenerator;
7use crate::records::disjunction_refinement::Disjunction;
8use crate::records::equivalence::Equivalence;
9use crate::records::negation_refinement::Negation;
10use crate::records::negation_type::NegationType;
11use crate::records::property_type::Property;
12use crate::records::proposition_refinement::Proposition;
13use crate::records::refinement_partition::RefinementPartition;
14use crate::records::scope::Scope;
15use crate::records::table_type::TableType;
16use crate::records::variadic::Variadic;
17use crate::type_aliases::constraint_v::ConstraintV;
18use crate::type_aliases::def_id_def::DefId;
19use crate::type_aliases::name_type::Name;
20use crate::type_aliases::refinement_context::RefinementContext;
21use crate::type_aliases::refinement_id_refinement::RefinementId;
22use crate::type_aliases::refinement_refinement::{Refinement, RefinementMember};
23use alloc::collections::BTreeMap;
24use core::mem::ManuallyDrop;
25use luaur_ast::records::location::Location;
26use luaur_common::macros::luau_assert::LUAU_ASSERT;
27
28impl ConstraintGenerator {
29 pub fn compute_refinement(
33 &mut self,
34 scope: *mut Scope,
35 location: Location,
36 refinement: RefinementId,
37 refis: *mut RefinementContext,
38 sense: bool,
39 eq: bool,
40 constraints: *mut alloc::vec::Vec<ConstraintV>,
41 ) {
42 if refinement.is_null() {
43 return;
44 }
45
46 let refinement_ref: &Refinement = unsafe { &*refinement };
47
48 if let Some(variadic) = <Variadic as RefinementMember>::get_if(refinement_ref) {
49 for refi in variadic.refinements.clone() {
50 self.compute_refinement(scope, location, refi, refis, sense, eq, constraints);
51 }
52 } else if let Some(negation) = <Negation as RefinementMember>::get_if(refinement_ref) {
53 self.compute_refinement(
54 scope,
55 location,
56 negation.refinement,
57 refis,
58 !sense,
59 eq,
60 constraints,
61 );
62 } else if let Some(conjunction) = <Conjunction as RefinementMember>::get_if(refinement_ref)
63 {
64 let (lhs, rhs) = (conjunction.lhs, conjunction.rhs);
65 let mut lhs_refis = RefinementContext::default();
66 let mut rhs_refis = RefinementContext::default();
67
68 let lhs_target: *mut RefinementContext = if sense { refis } else { &mut lhs_refis };
69 self.compute_refinement(scope, location, lhs, lhs_target, sense, eq, constraints);
70 let rhs_target: *mut RefinementContext = if sense { refis } else { &mut rhs_refis };
71 self.compute_refinement(scope, location, rhs, rhs_target, sense, eq, constraints);
72
73 if !sense {
74 let sp =
75 ManuallyDrop::new(unsafe { alloc::sync::Arc::from_raw(scope as *const Scope) });
76 self.union_refinements(&sp, location, &lhs_refis, &rhs_refis, refis, constraints);
77 }
78 } else if let Some(disjunction) = <Disjunction as RefinementMember>::get_if(refinement_ref)
79 {
80 let (lhs, rhs) = (disjunction.lhs, disjunction.rhs);
81 let mut lhs_refis = RefinementContext::default();
82 let mut rhs_refis = RefinementContext::default();
83
84 let lhs_target: *mut RefinementContext = if sense { &mut lhs_refis } else { refis };
85 self.compute_refinement(scope, location, lhs, lhs_target, sense, eq, constraints);
86 let rhs_target: *mut RefinementContext = if sense { &mut rhs_refis } else { refis };
87 self.compute_refinement(scope, location, rhs, rhs_target, sense, eq, constraints);
88
89 if sense {
90 let sp =
91 ManuallyDrop::new(unsafe { alloc::sync::Arc::from_raw(scope as *const Scope) });
92 self.union_refinements(&sp, location, &lhs_refis, &rhs_refis, refis, constraints);
93 }
94 } else if let Some(equivalence) = <Equivalence as RefinementMember>::get_if(refinement_ref)
95 {
96 let (lhs, rhs) = (equivalence.lhs, equivalence.rhs);
97 self.compute_refinement(scope, location, lhs, refis, sense, true, constraints);
98 self.compute_refinement(scope, location, rhs, refis, sense, true, constraints);
99 } else if let Some(proposition) = <Proposition as RefinementMember>::get_if(refinement_ref)
100 {
101 let mut discriminant_ty = proposition.discriminantTy;
102 let prop_key = proposition.key;
103 let implicit_from_call = proposition.implicitFromCall;
104
105 if !sense {
107 let nt = unsafe { get_type_id::<NegationType>(follow_type_id(discriminant_ty)) };
108 if !nt.is_null() {
109 discriminant_ty = unsafe { (*nt).ty };
110 } else {
111 discriminant_ty = unsafe {
112 (*self.arena).add_type(NegationType {
113 ty: discriminant_ty,
114 })
115 };
116 }
117 }
118
119 if eq {
120 let sp =
121 ManuallyDrop::new(unsafe { alloc::sync::Arc::from_raw(scope as *const Scope) });
122 let singleton_func = unsafe { &(*self.builtin_types).typeFunctions.singleton_func };
123 discriminant_ty = self.create_type_function_instance(
124 singleton_func,
125 alloc::vec![discriminant_ty],
126 alloc::vec![],
127 &sp,
128 location,
129 );
130 }
131
132 let mut key = prop_key;
133 while !key.is_null() {
134 let key_def = unsafe { (*key).def } as DefId;
135
136 unsafe {
137 (*refis).insert(key_def, RefinementPartition::default());
138 (*refis)
139 .get_mut(&key_def)
140 .unwrap()
141 .discriminant_types
142 .push(discriminant_ty);
143 }
144
145 let prop_name = unsafe { (*key).propName.clone() };
147 let prop_name = match prop_name {
148 Some(n) => n,
149 None => break,
150 };
151
152 let mut props: BTreeMap<Name, Property> = BTreeMap::new();
153 props.insert(prop_name, Property::readonly(discriminant_ty));
154
155 let next_discriminant_ty = unsafe {
156 let tt = TableType::table_type_props_optional_table_indexer_type_level_scope_table_state(
157 &props,
158 None,
159 (*scope).level,
160 scope,
161 TableState::Sealed,
162 );
163 (*self.arena).add_type(tt)
164 };
165
166 discriminant_ty = next_discriminant_ty;
167
168 key = unsafe { (*key).parent };
169 }
170
171 let prop_def = unsafe { (*prop_key).def } as DefId;
173 LUAU_ASSERT!(unsafe { (*refis).get(&prop_def) }.is_some());
174 unsafe {
175 (*refis).get_mut(&prop_def).unwrap().should_append_nil_type = (sense || !eq)
176 && contains_subscripted_definition(prop_def)
177 && !implicit_from_call;
178 }
179 }
180 }
181}