luaur_analysis/methods/
subtyping_check_generic_bounds.rs1use crate::enums::normalization_result::NormalizationResult;
2use crate::enums::subtyping_suppression_policy::SubtypingSuppressionPolicy;
3use crate::records::generic_bounds::GenericBounds;
4use crate::records::generic_bounds_mismatch::GenericBoundsMismatch;
5use crate::records::intersection_builder::IntersectionBuilder;
6use crate::records::scope::Scope;
7use crate::records::subtyping::Subtyping;
8use crate::records::subtyping_environment::SubtypingEnvironment;
9use crate::records::subtyping_result::SubtypingResult;
10use crate::records::union_builder::UnionBuilder;
11
12use luaur_common::macros::luau_assert::LUAU_ASSERT;
13
14impl Subtyping {
15 pub fn subtyping_check_generic_bounds(
16 &mut self,
17 bounds: &GenericBounds,
18 env: &mut SubtypingEnvironment,
19 scope: *mut Scope,
20 generic_name: &str,
21 ) -> SubtypingResult {
22 let mut result = SubtypingResult {
23 is_subtype: true,
24 normalization_too_complex: false,
25 is_cacheable: true,
26 is_error_suppressing: false,
27 errors: Default::default(),
28 reasoning: Default::default(),
29 assumed_constraints: Default::default(),
30 generic_bounds_mismatches: Default::default(),
31 };
32
33 let mut aggregate_lower_bound = UnionBuilder::union_builder(self.arena, self.builtin_types);
34 aggregate_lower_bound.reserve(bounds.lower_bound.size());
35 for &t in &bounds.lower_bound.order {
36 if let Some(mapped_bounds) = env.mapped_generics.find(&t) {
37 if mapped_bounds.is_empty() {
38 continue;
39 }
40 }
41 aggregate_lower_bound.add(t);
42 }
43 let mut lower_bound = aggregate_lower_bound.build();
44
45 let mut aggregate_upper_bound =
46 IntersectionBuilder::intersection_builder(self.arena, self.builtin_types);
47 aggregate_upper_bound.reserve(bounds.upper_bound.size());
48 for &t in &bounds.upper_bound.order {
49 if let Some(mapped_bounds) = env.mapped_generics.find(&t) {
50 if mapped_bounds.is_empty() {
51 continue;
52 }
53 }
54 aggregate_upper_bound.add(t);
55 }
56 let mut upper_bound = aggregate_upper_bound.build();
57
58 if let Some(subst_lower_bound) = env.apply_mapped_generics(
59 self.builtin_types,
60 self.arena,
61 lower_bound,
62 self.ice_reporter,
63 ) {
64 lower_bound = subst_lower_bound;
65 }
66
67 if let Some(subst_upper_bound) = env.apply_mapped_generics(
68 self.builtin_types,
69 self.arena,
70 upper_bound,
71 self.ice_reporter,
72 ) {
73 upper_bound = subst_upper_bound;
74 }
75
76 let nt = unsafe { (*self.normalizer).normalize(upper_bound) };
81 let res = unsafe { (*self.normalizer).is_inhabited_normalized_type(&nt) };
82
83 if res == NormalizationResult::HitLimits {
84 result.normalization_too_complex = true;
85 } else if res == NormalizationResult::False {
86 result.is_subtype = false;
87 }
88
89 let mut bounds_env = SubtypingEnvironment {
90 parent: env as *mut SubtypingEnvironment,
91 mapped_generics: luaur_common::records::dense_hash_map::DenseHashMap::new(
92 core::ptr::null(),
93 ),
94 mapped_generic_packs:
95 crate::records::mapped_generic_environment::MappedGenericEnvironment {
96 frames: alloc::vec::Vec::new(),
97 current_scope_index: None,
98 },
99 substitutions: luaur_common::records::dense_hash_map::DenseHashMap::new(
100 core::ptr::null(),
101 ),
102 seen_set_cache: luaur_common::records::dense_hash_map::DenseHashMap::new((
103 core::ptr::null(),
104 core::ptr::null(),
105 )),
106 iteration_count: 0,
107 };
108 let mut bounds_result = self
109 .is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
110 &mut bounds_env,
111 lower_bound,
112 upper_bound,
113 scope,
114 );
115 bounds_result.reasoning.clear();
116
117 if res == NormalizationResult::False {
118 result
119 .generic_bounds_mismatches
120 .push(GenericBoundsMismatch::new(
121 generic_name,
122 bounds.lower_bound.clone(),
123 bounds.upper_bound.clone(),
124 ));
125 } else if !bounds_result.is_subtype {
126 let lower_error_suppression = unsafe {
128 crate::functions::should_suppress_errors_type_utils::should_suppress_errors(
129 self.normalizer,
130 lower_bound,
131 )
132 };
133 let upper_error_suppression = unsafe {
134 crate::functions::should_suppress_errors_type_utils::should_suppress_errors(
135 self.normalizer,
136 upper_bound,
137 )
138 };
139 match lower_error_suppression
140 .or_else(&upper_error_suppression)
141 .value
142 {
143 crate::enums::value::Value::Suppress => {}
144 crate::enums::value::Value::NormalizationFailed => {
145 result
146 .generic_bounds_mismatches
147 .push(GenericBoundsMismatch::new(
148 generic_name,
149 bounds.lower_bound.clone(),
150 bounds.upper_bound.clone(),
151 ));
152 }
153 crate::enums::value::Value::DoNotSuppress => {
154 result
155 .generic_bounds_mismatches
156 .push(GenericBoundsMismatch::new(
157 generic_name,
158 bounds.lower_bound.clone(),
159 bounds.upper_bound.clone(),
160 ));
161 }
162 _ => {
163 LUAU_ASSERT!(false);
164 }
165 }
166 }
167
168 result.and_also(bounds_result, SubtypingSuppressionPolicy::Any);
169
170 result
171 }
172}