use crate::enums::subtyping_suppression_policy::SubtypingSuppressionPolicy;
use crate::enums::table_state::TableState;
use crate::enums::type_field::TypeField;
use crate::records::property_type::Property;
use crate::records::property_type_path::Property as PathProperty;
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::table_type::TableType;
use crate::type_aliases::component::Component;
use alloc::string::ToString;
use alloc::vec::Vec;
use luaur_common::FFlag;
fn path_property(name: &str, is_read: bool) -> Component {
Component::Property(PathProperty {
name: name.to_string(),
is_read,
})
}
fn index_result_component() -> Component {
Component::TypeField(TypeField::IndexResult)
}
impl Subtyping {
pub fn is_covariant_with_deprecated(
&mut self,
env: &mut SubtypingEnvironment,
sub_table: &TableType,
super_table: &TableType,
force_covariant_test: bool,
scope: *mut Scope,
) -> SubtypingResult {
let mut result = SubtypingResult {
is_subtype: true,
..Default::default()
};
if sub_table.props.is_empty()
&& sub_table.indexer.is_none()
&& sub_table.state == TableState::Sealed
&& super_table.indexer.is_some()
{
return SubtypingResult {
is_subtype: false,
..Default::default()
};
}
for (name, super_prop) in &super_table.props {
let mut results = Vec::new();
if let Some(sub_prop) = sub_table.props.get(name) {
results.push(
self.is_covariant_with_subtyping_environment_property_property_string_bool_not_null_scope(
env,
sub_prop,
super_prop,
name,
force_covariant_test,
scope,
),
);
} else if let Some(sub_indexer) = &sub_table.indexer {
let can_index_by_string = unsafe {
self.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
env,
(*self.builtin_types).stringType,
sub_indexer.index_type,
scope,
)
.is_subtype
};
if can_index_by_string {
if super_prop.is_shared() {
if FFlag::LuauReadOnlyIndexers.get() && sub_indexer.is_read_only {
let mut sr = SubtypingResult {
is_subtype: false,
..Default::default()
};
sr.with_sub_component(index_result_component());
sr.with_super_component(path_property(name, true));
results.push(sr);
} else {
let mut sr = self
.is_invariant_with_subtyping_environment_sub_ty_super_ty_not_null_scope(
env,
sub_indexer.index_result_type,
super_prop.read_ty.unwrap(),
scope,
);
sr.with_sub_component(index_result_component());
sr.with_super_component(path_property(name, true));
results.push(sr);
}
} else {
if let Some(super_read_ty) = super_prop.read_ty {
let mut sr = self
.is_covariant_with_subtyping_environment_type_id_type_id_not_null_scope(
env,
sub_indexer.index_result_type,
super_read_ty,
scope,
);
sr.with_sub_component(index_result_component());
sr.with_super_component(path_property(name, true));
results.push(sr);
}
if let Some(super_write_ty) = super_prop.write_ty {
if FFlag::LuauReadOnlyIndexers.get() && sub_indexer.is_read_only {
let mut sr = SubtypingResult {
is_subtype: false,
..Default::default()
};
sr.with_sub_component(index_result_component());
sr.with_super_component(path_property(name, false));
results.push(sr);
} else {
let mut sr = self
.is_contravariant_with_subtyping_environment_sub_ty_super_ty_not_null_scope(
env,
sub_indexer.index_result_type,
super_write_ty,
scope,
);
sr.with_sub_component(index_result_component());
sr.with_super_component(path_property(name, false));
results.push(sr);
}
}
}
}
} else if FFlag::LuauSubtypingMissingPropertiesAsNil.get() {
let nil_prop = unsafe { Property::readonly((*self.builtin_types).nilType) };
let mut sr =
self.is_covariant_with_subtyping_environment_property_property_string_bool_not_null_scope(
env,
&nil_prop,
super_prop,
name,
force_covariant_test,
scope,
);
sr.reasoning.clear();
results.push(sr);
}
if results.is_empty() {
return SubtypingResult {
is_subtype: false,
..Default::default()
};
}
let is_subtype = results.iter().all(|sr| sr.is_subtype);
if result.is_subtype && !is_subtype {
for sr in results {
result.and_also(sr, SubtypingSuppressionPolicy::Any);
}
} else {
for sr in results {
result.and_also(sr, SubtypingSuppressionPolicy::All);
}
}
}
if let Some(super_indexer) = &super_table.indexer {
if let Some(sub_indexer) = &sub_table.indexer {
let indexer_result = if FFlag::LuauReadOnlyIndexers.get() {
self.is_covariant_with_subtyping_environment_table_indexer_table_indexer_not_null_scope(
env,
sub_indexer,
super_indexer,
scope,
)
} else {
self.is_invariant_with_subtyping_environment_sub_ty_super_ty_not_null_scope(
env,
*sub_indexer,
*super_indexer,
scope,
)
};
result.and_also(indexer_result, SubtypingSuppressionPolicy::All);
} else if sub_table.state != TableState::Sealed {
return SubtypingResult {
is_subtype: true,
..Default::default()
};
} else {
return SubtypingResult {
is_subtype: false,
..Default::default()
};
}
}
result
}
}