Skip to main content

luaur_analysis/methods/
constraint_generator_check_index_name.rs

1//! Source: `Analysis/src/ConstraintGenerator.cpp:3223-3279` (hand-ported)
2//! C++ `Inference ConstraintGenerator::checkIndexName(scope, key, indexee, index, indexLocation)`.
3use crate::enums::value_context::ValueContext;
4use crate::functions::get_mutable_type::get_mutable_type_id;
5use crate::functions::get_table_type::get_table_type;
6use crate::functions::in_conditional::in_conditional;
7use crate::records::blocked_type::BlockedType;
8use crate::records::constraint_generator::ConstraintGenerator;
9use crate::records::has_prop_constraint::HasPropConstraint;
10use crate::records::inference::Inference;
11use crate::records::refinement_key::RefinementKey;
12use crate::type_aliases::constraint_v::ConstraintV;
13use crate::type_aliases::scope_ptr_constraint_generator::ScopePtr;
14use crate::type_aliases::type_id::TypeId;
15use alloc::string::String;
16use luaur_ast::records::ast_expr::AstExpr;
17use luaur_ast::records::location::Location;
18
19impl ConstraintGenerator {
20    pub fn check_index_name(
21        &mut self,
22        scope: &ScopePtr,
23        key: *const RefinementKey,
24        indexee: *mut AstExpr,
25        index: &String,
26        index_location: Location,
27    ) -> Inference {
28        unsafe {
29            let obj = self.check_scope_ptr_ast_expr(scope, indexee).ty;
30            let mut result: TypeId = core::ptr::null();
31
32            // We optimize away the HasProp constraint in simple cases so that we can
33            // reason about updates to unsealed tables more accurately.
34
35            let mut tt = get_table_type(obj);
36
37            // This is a little bit iffy but I *believe* it is okay because, if the
38            // local's domain is going to be extended at all, it will be someplace after
39            // the current lexical position within the script.
40            if tt.is_none() {
41                if let Some(local_domain) = self.local_types.find(&obj) {
42                    if local_domain.size() == 1 {
43                        let first = local_domain.order[0];
44                        tt = get_table_type(first);
45                    }
46                }
47            }
48
49            if let Some(tt) = tt {
50                if let Some(prop) = tt.props.get(index) {
51                    if let Some(read_ty) = prop.read_ty {
52                        result = read_ty;
53                    }
54                }
55            }
56
57            if let Some(cached_has_prop_result) =
58                self.prop_index_pairs_seen.find(&(obj, index.clone()))
59            {
60                result = *cached_has_prop_result;
61            }
62
63            if result.is_null() {
64                result = (*self.arena).add_type(BlockedType::default());
65
66                let c = self.add_constraint_scope_ptr_location_constraint_v(
67                    scope,
68                    (*indexee).base.location,
69                    ConstraintV::HasProp(HasPropConstraint {
70                        result_type: result,
71                        subject_type: obj,
72                        prop: index.clone(),
73                        context: ValueContext::RValue,
74                        in_conditional: in_conditional(self.type_context),
75                        suppress_simplification: false,
76                    }),
77                );
78                let blocked = get_mutable_type_id::<BlockedType>(result);
79                (*blocked).set_owner(c as *const _);
80                *self
81                    .prop_index_pairs_seen
82                    .get_or_insert((obj, index.clone())) = result;
83            }
84
85            if !key.is_null() {
86                if let Some(ty) = self.lookup(
87                    scope,
88                    index_location,
89                    (*key).def as crate::type_aliases::def_id_def::DefId,
90                    false,
91                ) {
92                    let refinement = self
93                        .refinement_arena
94                        .proposition_refinement_key_type_id(key, (*self.builtin_types).truthyType);
95                    return Inference::inference_type_id_refinement_id(ty, refinement);
96                }
97
98                self.update_r_value_refinements_scope_ptr_def_id_type_id(
99                    scope,
100                    (*key).def as crate::type_aliases::def_id_def::DefId,
101                    result,
102                );
103            }
104
105            if !key.is_null() {
106                let refinement = self
107                    .refinement_arena
108                    .proposition_refinement_key_type_id(key, (*self.builtin_types).truthyType);
109                Inference::inference_type_id_refinement_id(result, refinement)
110            } else {
111                Inference::inference_type_id_refinement_id(result, core::ptr::null_mut())
112            }
113        }
114    }
115}