luaur_analysis/functions/
are_compatible.rs1use crate::functions::follow_type::follow_type_id;
2use crate::functions::get_2::get2;
3use crate::functions::is_optional_or_free::is_optional_or_free;
4use crate::records::property_type::Property;
5use crate::records::table_type::TableType;
6use crate::type_aliases::type_id::TypeId;
7use luaur_common::macros::luau_assert::LUAU_ASSERT;
8
9unsafe fn missing_prop_is_compatible(left_prop: &Property, right_table: &TableType) -> bool {
15 if right_table.state == crate::enums::table_state::TableState::Free
16 || right_table.indexer.is_some()
17 {
18 return true;
19 }
20
21 if left_prop.is_read_only() || left_prop.is_shared() {
22 if is_optional_or_free(left_prop.read_ty.unwrap()) {
23 return true;
24 }
25 }
26
27 false
29}
30
31pub unsafe fn are_compatible(left: TypeId, right: TypeId) -> bool {
32 let p = get2::<TableType, TableType, TypeId>(follow_type_id(left), follow_type_id(right));
33 if p.first.is_null() {
34 return true;
35 }
36
37 let left_table = p.first;
38 LUAU_ASSERT!(!left_table.is_null());
39 let right_table = p.second;
40 LUAU_ASSERT!(!right_table.is_null());
41
42 let left_table = &*left_table;
43 let right_table = &*right_table;
44
45 for (_name, left_prop) in left_table.props.iter() {
46 let it = right_table.props.get(_name);
47 if it.is_none() {
48 if !missing_prop_is_compatible(left_prop, right_table) {
49 return false;
50 }
51 }
52 }
53
54 for (_name, right_prop) in right_table.props.iter() {
55 let it = left_table.props.get(_name);
56 if it.is_none() {
57 if !missing_prop_is_compatible(right_prop, left_table) {
58 return false;
59 }
60 }
61 }
62
63 true
64}