Skip to content

Commit 0c22c20

Browse files
committed
fix for for range var
close #321 close #261
1 parent f1b9c35 commit 0c22c20

File tree

7 files changed

+181
-124
lines changed

7 files changed

+181
-124
lines changed

crates/emmylua_code_analysis/resources/std/global.lua

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -113,7 +113,7 @@ function getmetatable(object) end
113113
--- the first absent index.
114114
---@generic V
115115
---@param t V[] | table<any, V> | {[any]: V}
116-
---@return fun(tbl: any):int, std.NotNull<V>
116+
---@return fun(tbl: any):int, V
117117
function ipairs(t) end
118118

119119
---@alias std.loadmode
@@ -231,7 +231,7 @@ function next(table, index) end
231231
--- traversal.
232232
---@generic K, V
233233
---@param t table<K, V> | V[] | {[K]: V}
234-
---@return fun(tbl: any):K, std.NotNull<V>
234+
---@return fun(tbl: any):K, V
235235
function pairs(t) end
236236
---
237237
--- Calls function `f` with the given arguments in *protected mode*. This

crates/emmylua_code_analysis/src/compilation/analyzer/decl/stats.rs

Lines changed: 8 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4,8 +4,9 @@ use emmylua_parser::{
44
};
55

66
use crate::{
7+
compilation::analyzer::bind_type::bind_type,
78
db_index::{LocalAttribute, LuaDecl, LuaMember, LuaMemberKey},
8-
LuaDeclExtra, LuaMemberFeature, LuaMemberId, LuaSemanticDeclId, LuaSignatureId,
9+
LuaDeclExtra, LuaMemberFeature, LuaMemberId, LuaSemanticDeclId, LuaSignatureId, LuaType,
910
};
1011

1112
use super::{members::find_index_owner, DeclAnalyzer};
@@ -176,8 +177,13 @@ pub fn analyze_for_stat(analyzer: &mut DeclAnalyzer, stat: LuaForStat) -> Option
176177
},
177178
None,
178179
);
179-
180+
let decl_id = decl.get_id();
180181
analyzer.add_decl(decl);
182+
bind_type(
183+
analyzer.db,
184+
decl_id.into(),
185+
crate::LuaTypeCache::DocType(LuaType::Integer),
186+
);
181187

182188
Some(())
183189
}
Lines changed: 123 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,123 @@
1+
use std::sync::Arc;
2+
3+
use emmylua_parser::{LuaAstToken, LuaForRangeStat};
4+
5+
use crate::{
6+
compilation::analyzer::unresolve::UnResolveIterVar, DbIndex, InferFailReason, LuaDeclId,
7+
LuaFunctionType, LuaOperatorMetaMethod, LuaType, LuaTypeCache, TypeOps,
8+
};
9+
10+
use super::LuaAnalyzer;
11+
12+
pub fn analyze_for_range_stat(
13+
analyzer: &mut LuaAnalyzer,
14+
for_range_stat: LuaForRangeStat,
15+
) -> Option<()> {
16+
let var_name_list = for_range_stat.get_var_name_list();
17+
let first_iter_expr = for_range_stat.get_expr_list().next()?;
18+
let first_iter_type = analyzer.infer_expr(&first_iter_expr);
19+
20+
match first_iter_type {
21+
Ok(first_iter_type) => {
22+
let iter_doc_func = infer_for_range_iter_expr_func(analyzer.db, first_iter_type);
23+
24+
if let Some(doc_func) = iter_doc_func {
25+
let multi_return = doc_func.get_multi_return();
26+
let mut idx = 0;
27+
for var_name in var_name_list {
28+
let position = var_name.get_position();
29+
let decl_id = LuaDeclId::new(analyzer.file_id, position);
30+
let ret_type = multi_return
31+
.get_type(idx)
32+
.cloned()
33+
.unwrap_or(LuaType::Unknown);
34+
let ret_type = TypeOps::Remove.apply(&ret_type, &LuaType::Nil);
35+
analyzer
36+
.db
37+
.get_type_index_mut()
38+
.bind_type(decl_id.into(), LuaTypeCache::InferType(ret_type));
39+
idx += 1;
40+
}
41+
return Some(());
42+
} else {
43+
for var_name in var_name_list {
44+
let position = var_name.get_position();
45+
let decl_id = LuaDeclId::new(analyzer.file_id, position);
46+
analyzer
47+
.db
48+
.get_type_index_mut()
49+
.bind_type(decl_id.into(), LuaTypeCache::InferType(LuaType::Unknown));
50+
}
51+
return Some(());
52+
}
53+
}
54+
Err(InferFailReason::None) => {
55+
for var_name in var_name_list {
56+
let position = var_name.get_position();
57+
let decl_id = LuaDeclId::new(analyzer.file_id, position);
58+
analyzer
59+
.db
60+
.get_type_index_mut()
61+
.bind_type(decl_id.into(), LuaTypeCache::InferType(LuaType::Unknown));
62+
}
63+
return Some(());
64+
}
65+
Err(reason) => {
66+
let mut idx = 0;
67+
for var_name in var_name_list {
68+
let position = var_name.get_position();
69+
let decl_id = LuaDeclId::new(analyzer.file_id, position);
70+
let unresolved = UnResolveIterVar {
71+
file_id: analyzer.file_id,
72+
decl_id,
73+
iter_expr: first_iter_expr.clone(),
74+
ret_idx: idx,
75+
reason: reason.clone(),
76+
};
77+
analyzer.add_unresolved(unresolved.into());
78+
idx += 1;
79+
}
80+
}
81+
}
82+
83+
Some(())
84+
}
85+
86+
pub fn infer_for_range_iter_expr_func(
87+
db: &mut DbIndex,
88+
iter_expr_type: LuaType,
89+
) -> Option<Arc<LuaFunctionType>> {
90+
match iter_expr_type {
91+
LuaType::DocFunction(func) => Some(func),
92+
LuaType::Ref(type_decl_id) => {
93+
let type_decl = db.get_type_index().get_type_decl(&type_decl_id)?;
94+
if type_decl.is_alias() {
95+
let alias_origin = type_decl.get_alias_origin(db, None)?;
96+
match alias_origin {
97+
LuaType::DocFunction(doc_func) => Some(doc_func),
98+
_ => None,
99+
}
100+
} else if type_decl.is_class() {
101+
let operator_index = db.get_operator_index();
102+
let operator_ids = operator_index
103+
.get_operators(&type_decl_id.into(), LuaOperatorMetaMethod::Call)?;
104+
operator_ids
105+
.iter()
106+
.filter_map(|overload_id| {
107+
let operator = operator_index.get_operator(overload_id)?;
108+
let func = operator.get_operator_func();
109+
match func {
110+
LuaType::DocFunction(f) => {
111+
return Some(f.clone());
112+
}
113+
_ => None,
114+
}
115+
})
116+
.nth(0)
117+
} else {
118+
None
119+
}
120+
}
121+
_ => None,
122+
}
123+
}

crates/emmylua_code_analysis/src/compilation/analyzer/lua/mod.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,5 @@
11
mod closure;
2+
mod for_range_stat;
23
mod func_body;
34
mod metatable;
45
mod module;
@@ -9,12 +10,14 @@ use std::collections::HashMap;
910
use closure::analyze_closure;
1011
pub use closure::analyze_return_point;
1112
use emmylua_parser::{LuaAst, LuaAstNode, LuaExpr};
13+
use for_range_stat::analyze_for_range_stat;
14+
pub use for_range_stat::infer_for_range_iter_expr_func;
1215
pub use func_body::LuaReturnPoint;
1316
use metatable::analyze_setmetatable;
1417
use module::analyze_chunk_return;
1518
use stats::{
16-
analyze_assign_stat, analyze_for_range_stat, analyze_func_stat, analyze_local_func_stat,
17-
analyze_local_stat, analyze_table_field,
19+
analyze_assign_stat, analyze_func_stat, analyze_local_func_stat, analyze_local_stat,
20+
analyze_table_field,
1821
};
1922

2023
use crate::{

crates/emmylua_code_analysis/src/compilation/analyzer/lua/stats.rs

Lines changed: 4 additions & 109 deletions
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,14 @@
11
use emmylua_parser::{
2-
BinaryOperator, LuaAssignStat, LuaAstNode, LuaAstToken, LuaExpr, LuaForRangeStat, LuaFuncStat,
3-
LuaIndexExpr, LuaLocalFuncStat, LuaLocalStat, LuaTableField, LuaVarExpr, PathTrait,
2+
BinaryOperator, LuaAssignStat, LuaAstNode, LuaExpr, LuaFuncStat, LuaIndexExpr,
3+
LuaLocalFuncStat, LuaLocalStat, LuaTableField, LuaVarExpr, PathTrait,
44
};
55

66
use crate::{
77
compilation::analyzer::{
88
bind_type::{add_member, bind_type},
9-
unresolve::{UnResolveDecl, UnResolveIterVar, UnResolveMember},
9+
unresolve::{UnResolveDecl, UnResolveMember},
1010
},
11-
db_index::{LuaDeclId, LuaMemberId, LuaMemberOwner, LuaOperatorMetaMethod, LuaType},
11+
db_index::{LuaDeclId, LuaMemberId, LuaMemberOwner, LuaType},
1212
InferFailReason, LuaTypeCache, LuaTypeOwner,
1313
};
1414

@@ -393,111 +393,6 @@ fn merge_type_owner_and_unresolve_expr(
393393
Some(())
394394
}
395395

396-
pub fn analyze_for_range_stat(
397-
analyzer: &mut LuaAnalyzer,
398-
for_range_stat: LuaForRangeStat,
399-
) -> Option<()> {
400-
let var_name_list = for_range_stat.get_var_name_list();
401-
let first_iter_expr = for_range_stat.get_expr_list().next()?;
402-
let first_iter_type = analyzer.infer_expr(&first_iter_expr);
403-
404-
match first_iter_type {
405-
Ok(first_iter_type) => {
406-
let iter_doc_func = match first_iter_type {
407-
LuaType::DocFunction(doc_func) => Some(doc_func),
408-
LuaType::Ref(type_decl_id) => {
409-
let type_decl = analyzer.db.get_type_index().get_type_decl(&type_decl_id)?;
410-
if type_decl.is_alias() {
411-
let alias_origin = type_decl.get_alias_origin(analyzer.db, None)?;
412-
match alias_origin {
413-
LuaType::DocFunction(doc_func) => Some(doc_func),
414-
_ => None,
415-
}
416-
} else if type_decl.is_class() {
417-
let operator_index = analyzer.db.get_operator_index();
418-
let operator_ids = operator_index
419-
.get_operators(&type_decl_id.into(), LuaOperatorMetaMethod::Call)?;
420-
operator_ids
421-
.iter()
422-
.filter_map(|overload_id| {
423-
let operator = operator_index.get_operator(overload_id)?;
424-
let func = operator.get_operator_func();
425-
match func {
426-
LuaType::DocFunction(f) => {
427-
return Some(f.clone());
428-
}
429-
_ => None,
430-
}
431-
})
432-
.nth(0)
433-
} else {
434-
None
435-
}
436-
}
437-
_ => None,
438-
};
439-
440-
if let Some(doc_func) = iter_doc_func {
441-
let multi_return = doc_func.get_multi_return();
442-
let mut idx = 0;
443-
for var_name in var_name_list {
444-
let position = var_name.get_position();
445-
let decl_id = LuaDeclId::new(analyzer.file_id, position);
446-
let ret_type = multi_return
447-
.get_type(idx)
448-
.unwrap_or(&LuaType::Unknown)
449-
.clone();
450-
analyzer
451-
.db
452-
.get_type_index_mut()
453-
.bind_type(decl_id.into(), LuaTypeCache::InferType(ret_type));
454-
idx += 1;
455-
}
456-
return Some(());
457-
} else {
458-
for var_name in var_name_list {
459-
let position = var_name.get_position();
460-
let decl_id = LuaDeclId::new(analyzer.file_id, position);
461-
analyzer
462-
.db
463-
.get_type_index_mut()
464-
.bind_type(decl_id.into(), LuaTypeCache::InferType(LuaType::Unknown));
465-
}
466-
return Some(());
467-
}
468-
}
469-
Err(InferFailReason::None) => {
470-
for var_name in var_name_list {
471-
let position = var_name.get_position();
472-
let decl_id = LuaDeclId::new(analyzer.file_id, position);
473-
analyzer
474-
.db
475-
.get_type_index_mut()
476-
.bind_type(decl_id.into(), LuaTypeCache::InferType(LuaType::Unknown));
477-
}
478-
return Some(());
479-
}
480-
Err(reason) => {
481-
let mut idx = 0;
482-
for var_name in var_name_list {
483-
let position = var_name.get_position();
484-
let decl_id = LuaDeclId::new(analyzer.file_id, position);
485-
let unresolved = UnResolveIterVar {
486-
file_id: analyzer.file_id,
487-
decl_id,
488-
iter_expr: first_iter_expr.clone(),
489-
ret_idx: idx,
490-
reason: reason.clone(),
491-
};
492-
analyzer.add_unresolved(unresolved.into());
493-
idx += 1;
494-
}
495-
}
496-
}
497-
498-
Some(())
499-
}
500-
501396
pub fn analyze_func_stat(analyzer: &mut LuaAnalyzer, func_stat: LuaFuncStat) -> Option<()> {
502397
let closure = func_stat.get_closure()?;
503398
let func_name = func_stat.get_func_name()?;

crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/resolve.rs

Lines changed: 20 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -5,12 +5,12 @@ use emmylua_parser::{LuaAstNode, LuaExpr, LuaLocalStat, LuaTableExpr};
55
use crate::{
66
compilation::analyzer::{
77
bind_type::{add_member, bind_type},
8-
lua::analyze_return_point,
8+
lua::{analyze_return_point, infer_for_range_iter_expr_func},
99
},
1010
db_index::{DbIndex, LuaMemberOwner, LuaType},
1111
semantic::{infer_expr, LuaInferCache},
1212
InFiled, InferFailReason, LuaDeclId, LuaMember, LuaMemberId, LuaMemberKey, LuaSemanticDeclId,
13-
LuaTypeCache, SignatureReturnStatus,
13+
LuaTypeCache, SignatureReturnStatus, TypeOps,
1414
};
1515

1616
use super::{
@@ -260,22 +260,33 @@ pub fn try_resolve_return_point(
260260
pub fn try_resolve_iter_var(
261261
db: &mut DbIndex,
262262
cache: &mut LuaInferCache,
263-
iter_var: &UnResolveIterVar,
263+
iter_var: &mut UnResolveIterVar,
264264
) -> Option<bool> {
265265
if !check_reach_reason(db, cache, &iter_var.reason).unwrap_or(false) {
266266
return None;
267267
}
268268

269-
let expr_type = infer_expr(db, cache, iter_var.iter_expr.clone()).ok()?;
270-
let func = match expr_type {
271-
LuaType::DocFunction(func) => func,
272-
_ => return Some(true),
269+
let expr_type = match infer_expr(db, cache, iter_var.iter_expr.clone()) {
270+
Ok(t) => t,
271+
Err(InferFailReason::None) => return Some(true),
272+
Err(reason) => {
273+
iter_var.reason = reason;
274+
return None;
275+
}
276+
};
277+
let func = match infer_for_range_iter_expr_func(db, expr_type.clone()) {
278+
Some(func) => func,
279+
None => {
280+
return Some(true);
281+
}
273282
};
274283

275284
let multi_return = func.get_multi_return();
276-
let iter_type = multi_return
285+
let mut iter_type = multi_return
277286
.get_type(iter_var.ret_idx)
278-
.unwrap_or(&LuaType::Nil);
287+
.cloned()
288+
.unwrap_or(LuaType::Unknown);
289+
iter_type = TypeOps::Remove.apply(&iter_type, &LuaType::Nil);
279290
let decl_id = iter_var.decl_id;
280291
bind_type(
281292
db,

0 commit comments

Comments
 (0)