luaur_analysis/methods/
constraint_generator_apply_refinements.rs1use crate::enums::refinements_op_kind::RefinementsOpKind;
2use crate::enums::value::Value;
3use crate::functions::must_defer_intersection::must_defer_intersection;
4use crate::functions::should_suppress_errors_type_utils::should_suppress_errors;
5use crate::records::constraint_generator::ConstraintGenerator;
6use crate::records::constraint_generator::ConstraintGenerator as _ConstraintGenerator;
7use crate::records::error_suppression::ErrorSuppression;
8use crate::records::normalization_too_complex::NormalizationTooComplex;
9use crate::type_aliases::constraint_v::ConstraintV;
10use crate::type_aliases::refinement_context::RefinementContext;
11use crate::type_aliases::refinement_id_refinement::RefinementId;
12use crate::type_aliases::scope_ptr_constraint_generator::ScopePtr;
13use crate::type_aliases::type_error_data::TypeErrorData;
14use crate::type_aliases::type_id::TypeId;
15use alloc::vec::Vec;
16use luaur_ast::records::location::Location;
17use luaur_common::macros::luau_assert::LUAU_ASSERT;
18
19impl ConstraintGenerator {
20 pub fn apply_refinements(
21 &mut self,
22 scope: &ScopePtr,
23 location: Location,
24 refinement: RefinementId,
25 ) {
26 if refinement.is_null() {
27 return;
28 }
29
30 let mut refinements: RefinementContext = RefinementContext::default();
31 let mut constraints: Vec<ConstraintV> = Vec::new();
32
33 self.compute_refinement(
34 scope.as_ref() as *const _ as *mut _,
35 location,
36 refinement,
37 &mut refinements,
38 true,
39 false,
40 &mut constraints,
41 );
42
43 let mut flush_constraints = |this: &mut ConstraintGenerator,
44 kind: RefinementsOpKind,
45 ty: TypeId,
46 discriminants: &mut Vec<TypeId>|
47 -> TypeId {
48 if discriminants.is_empty() {
49 return ty;
50 }
51
52 if kind == RefinementsOpKind::None {
53 LUAU_ASSERT!(false);
54 return ty;
55 }
56
57 let mut args = Vec::new();
58 args.push(ty);
59
60 let builtin_types = this.builtin_types;
61 let type_functions = unsafe { &(*builtin_types).typeFunctions };
62
63 let func = if kind == RefinementsOpKind::Intersect {
64 &type_functions.intersect_func
65 } else {
66 &type_functions.refine_func
67 };
68
69 LUAU_ASSERT!(!func.name.is_empty());
70 args.extend_from_slice(discriminants.as_slice());
71
72 let result_type =
73 this.create_type_function_instance(func, args, Vec::new(), scope, location);
74 discriminants.clear();
75 result_type
76 };
77
78 let scope_raw = scope.as_ref() as *const _ as *mut _;
79
80 for (def, partition) in refinements.iter() {
81 let def_ty = self.lookup(scope, location, *def, false);
82 let Some(def_ty) = def_ty else { continue };
83
84 let mut ty = def_ty;
85
86 let mut discriminants: Vec<TypeId> = Vec::new();
87 let mut kind = RefinementsOpKind::None;
88
89 let mut must_defer = must_defer_intersection(ty);
90
91 for dt in &partition.discriminant_types {
92 let dt_val = *dt;
93
94 must_defer = must_defer || must_defer_intersection(dt_val);
95
96 if must_defer {
97 if kind == RefinementsOpKind::Intersect {
98 ty = flush_constraints(self, kind, ty, &mut discriminants);
99 }
100 kind = RefinementsOpKind::Refine;
101 discriminants.push(dt_val);
102 } else {
103 let status: ErrorSuppression = should_suppress_errors(self.normalizer, ty);
104
105 if status.value == Value::NormalizationFailed {
106 self.report_error(location, NormalizationTooComplex::default().into());
107 }
108
109 if kind == RefinementsOpKind::Refine {
110 ty = flush_constraints(self, kind, ty, &mut discriminants);
111 }
112 kind = RefinementsOpKind::Intersect;
113
114 discriminants.push(dt_val);
115
116 if status.value == Value::Suppress {
117 ty = flush_constraints(self, kind, ty, &mut discriminants);
118 ty = self.make_union_scope_ptr_location_type_id_type_id(
119 scope_raw,
120 location,
121 ty,
122 unsafe { (*self.builtin_types).errorType },
123 );
124 }
125 }
126 }
127
128 if kind != RefinementsOpKind::None {
129 ty = flush_constraints(self, kind, ty, &mut discriminants);
130 }
131
132 if partition.should_append_nil_type {
133 ty = self.create_type_function_instance(
134 unsafe { &(*self.builtin_types).typeFunctions.weakoptional_func },
135 vec![ty],
136 Vec::new(),
137 scope,
138 location,
139 );
140 }
141
142 self.update_r_value_refinements_scope_ptr_def_id_type_id(scope, *def, ty);
143 }
144
145 for c in constraints {
146 self.add_constraint_scope_ptr_location_constraint_v(scope, location, c);
147 }
148 }
149}