use crate::enums::normalization_result::NormalizationResult;
use crate::enums::subtyping_suppression_policy::SubtypingSuppressionPolicy;
use crate::records::generic_bounds::GenericBounds;
use crate::records::generic_bounds_mismatch::GenericBoundsMismatch;
use crate::records::intersection_builder::IntersectionBuilder;
use crate::records::scope::Scope;
use crate::records::subtyping::Subtyping;
use crate::records::subtyping_environment::SubtypingEnvironment;
use crate::records::subtyping_result::SubtypingResult;
use crate::records::union_builder::UnionBuilder;
use luaur_common::macros::luau_assert::LUAU_ASSERT;
impl Subtyping {
pub fn subtyping_check_generic_bounds(
&mut self,
bounds: &GenericBounds,
env: &mut SubtypingEnvironment,
scope: *mut Scope,
generic_name: &str,
) -> SubtypingResult {
let mut result = SubtypingResult {
is_subtype: true,
normalization_too_complex: false,
is_cacheable: true,
is_error_suppressing: false,
errors: Default::default(),
reasoning: Default::default(),
assumed_constraints: Default::default(),
generic_bounds_mismatches: Default::default(),
};
let mut aggregate_lower_bound = UnionBuilder::union_builder(self.arena, self.builtin_types);
aggregate_lower_bound.reserve(bounds.lower_bound.size());
for &t in &bounds.lower_bound.order {
if let Some(mapped_bounds) = env.mapped_generics.find(&t) {
if mapped_bounds.is_empty() {
continue;
}
}
aggregate_lower_bound.add(t);
}
let mut lower_bound = aggregate_lower_bound.build();
let mut aggregate_upper_bound =
IntersectionBuilder::intersection_builder(self.arena, self.builtin_types);
aggregate_upper_bound.reserve(bounds.upper_bound.size());
for &t in &bounds.upper_bound.order {
if let Some(mapped_bounds) = env.mapped_generics.find(&t) {
if mapped_bounds.is_empty() {
continue;
}
}
aggregate_upper_bound.add(t);
}
let mut upper_bound = aggregate_upper_bound.build();
if let Some(subst_lower_bound) = env.apply_mapped_generics(
self.builtin_types,
self.arena,
lower_bound,
self.ice_reporter,
) {
lower_bound = subst_lower_bound;
}
if let Some(subst_upper_bound) = env.apply_mapped_generics(
self.builtin_types,
self.arena,
upper_bound,
self.ice_reporter,
) {
upper_bound = subst_upper_bound;
}
let nt = unsafe { (*self.normalizer).normalize(upper_bound) };
let res = unsafe { (*self.normalizer).is_inhabited_normalized_type(&nt) };
if res == NormalizationResult::HitLimits {
result.normalization_too_complex = true;
} else if res == NormalizationResult::False {
result.is_subtype = false;
}
let mut bounds_env = SubtypingEnvironment {
parent: env as *mut SubtypingEnvironment,
mapped_generics: luaur_common::records::dense_hash_map::DenseHashMap::new(
core::ptr::null(),
),
mapped_generic_packs:
crate::records::mapped_generic_environment::MappedGenericEnvironment {
frames: alloc::vec::Vec::new(),
current_scope_index: None,
},
substitutions: luaur_common::records::dense_hash_map::DenseHashMap::new(
core::ptr::null(),
),
seen_set_cache: luaur_common::records::dense_hash_map::DenseHashMap::new((
core::ptr::null(),
core::ptr::null(),
)),
iteration_count: 0,
};
let mut bounds_result = self
.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
&mut bounds_env,
lower_bound,
upper_bound,
scope,
);
bounds_result.reasoning.clear();
if res == NormalizationResult::False {
result
.generic_bounds_mismatches
.push(GenericBoundsMismatch::new(
generic_name,
bounds.lower_bound.clone(),
bounds.upper_bound.clone(),
));
} else if !bounds_result.is_subtype {
let lower_error_suppression = unsafe {
crate::functions::should_suppress_errors_type_utils::should_suppress_errors(
self.normalizer,
lower_bound,
)
};
let upper_error_suppression = unsafe {
crate::functions::should_suppress_errors_type_utils::should_suppress_errors(
self.normalizer,
upper_bound,
)
};
match lower_error_suppression
.or_else(&upper_error_suppression)
.value
{
crate::enums::value::Value::Suppress => {}
crate::enums::value::Value::NormalizationFailed => {
result
.generic_bounds_mismatches
.push(GenericBoundsMismatch::new(
generic_name,
bounds.lower_bound.clone(),
bounds.upper_bound.clone(),
));
}
crate::enums::value::Value::DoNotSuppress => {
result
.generic_bounds_mismatches
.push(GenericBoundsMismatch::new(
generic_name,
bounds.lower_bound.clone(),
bounds.upper_bound.clone(),
));
}
_ => {
LUAU_ASSERT!(false);
}
}
}
result.and_also(bounds_result, SubtypingSuppressionPolicy::Any);
result
}
}