11use std:: collections:: HashSet ;
22
3- use emmylua_parser:: { LuaExpr , LuaIndexExpr , LuaIndexKey , LuaIndexMemberExpr , PathTrait } ;
3+ use emmylua_parser:: {
4+ LuaAstNode , LuaExpr , LuaForStat , LuaIndexExpr , LuaIndexKey , LuaIndexMemberExpr , PathTrait ,
5+ UnaryOperator ,
6+ } ;
47use internment:: ArcIntern ;
58use rowan:: TextRange ;
69use smol_str:: SmolStr ;
@@ -13,7 +16,11 @@ use crate::{
1316 enum_variable_is_param,
1417 semantic:: {
1518 generic:: { instantiate_type_generic, TypeSubstitutor } ,
16- infer:: { infer_name:: get_name_expr_var_ref_id, narrow:: infer_expr_narrow_type, VarRefId } ,
19+ infer:: {
20+ infer_name:: get_name_expr_var_ref_id,
21+ narrow:: { get_var_expr_var_ref_id, infer_expr_narrow_type} ,
22+ VarRefId ,
23+ } ,
1724 member:: get_buildin_type_map_type_id,
1825 type_check:: { self , check_type_compact} ,
1926 InferGuard ,
@@ -182,9 +189,20 @@ fn infer_array_member(
182189 db : & DbIndex ,
183190 cache : & mut LuaInferCache ,
184191 array_type : & LuaArrayType ,
185- index_expr : LuaIndexMemberExpr ,
192+ index_member_expr : LuaIndexMemberExpr ,
186193) -> Result < LuaType , InferFailReason > {
187- let key = index_expr. get_index_key ( ) . ok_or ( InferFailReason :: None ) ?;
194+ let key = index_member_expr
195+ . get_index_key ( )
196+ . ok_or ( InferFailReason :: None ) ?;
197+ let index_prefix_expr = match index_member_expr {
198+ LuaIndexMemberExpr :: TableField ( _) => {
199+ return Ok ( array_type. get_base ( ) . clone ( ) ) ;
200+ }
201+ _ => index_member_expr
202+ . get_prefix_expr ( )
203+ . ok_or ( InferFailReason :: None ) ?,
204+ } ;
205+
188206 match key {
189207 LuaIndexKey :: Integer ( i) => {
190208 if !db. get_emmyrc ( ) . strict . array_index {
@@ -222,7 +240,13 @@ fn infer_array_member(
222240 return Ok ( base_type. clone ( ) ) ;
223241 }
224242 }
225- _ => { }
243+ _ => {
244+ if check_iter_var_range ( db, cache, & expr, index_prefix_expr)
245+ . unwrap_or ( false )
246+ {
247+ return Ok ( base_type. clone ( ) ) ;
248+ }
249+ }
226250 }
227251
228252 let result_type = match & base_type {
@@ -239,6 +263,48 @@ fn infer_array_member(
239263 }
240264}
241265
266+ fn check_iter_var_range (
267+ db : & DbIndex ,
268+ cache : & mut LuaInferCache ,
269+ may_iter_var : & LuaExpr ,
270+ prefix_expr : LuaExpr ,
271+ ) -> Option < bool > {
272+ let LuaExpr :: NameExpr ( name_expr) = may_iter_var else {
273+ return None ;
274+ } ;
275+
276+ let decl_id = db
277+ . get_reference_index ( )
278+ . get_var_reference_decl ( & cache. get_file_id ( ) , name_expr. get_range ( ) ) ?;
279+
280+ let decl = db. get_decl_index ( ) . get_decl ( & decl_id) ?;
281+ let decl_syntax_id = decl. get_syntax_id ( ) ;
282+ if !decl_syntax_id. is_token ( ) {
283+ return None ;
284+ }
285+
286+ let root = prefix_expr. get_root ( ) ;
287+ let token = decl_syntax_id. to_token_from_root ( & root) ?;
288+ let parent_node = token. parent ( ) ?;
289+ let for_stat = LuaForStat :: cast ( parent_node) ?;
290+ // get second expr
291+ let test_len_expr = for_stat. get_iter_expr ( ) . skip ( 1 ) . next ( ) ?;
292+ let LuaExpr :: UnaryExpr ( unary_expr) = test_len_expr else {
293+ return None ;
294+ } ;
295+
296+ let op = unary_expr. get_op_token ( ) ?;
297+ if op. get_op ( ) != UnaryOperator :: OpLen {
298+ return None ;
299+ }
300+
301+ let len_expr = unary_expr. get_expr ( ) ?;
302+ let len_expr_var_ref_id = get_var_expr_var_ref_id ( db, cache, len_expr) ?;
303+ let prefix_expr_var_ref_id = get_var_expr_var_ref_id ( db, cache, prefix_expr) ?;
304+
305+ Some ( len_expr_var_ref_id == prefix_expr_var_ref_id)
306+ }
307+
242308fn infer_table_member (
243309 db : & DbIndex ,
244310 cache : & mut LuaInferCache ,
0 commit comments