Skip to content

Commit 3bbfcee

Browse files
committed
Merge branch 'main' of github.com:EmmyLuaLs/emmylua-analyzer-rust
2 parents daecbc5 + 3e0bb16 commit 3bbfcee

50 files changed

Lines changed: 3056 additions & 363 deletions

File tree

Some content is hidden

Large Commits have some content hidden by default. Use the searchbox below for content that may be hidden.

crates/emmylua_code_analysis/resources/std/global.lua

Lines changed: 4 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -253,10 +253,11 @@ function pairs(t) end
253253
--- boolean), which is true if the call succeeds without errors. In such case,
254254
--- `pcall` also returns all results from the call, after this first result. In
255255
--- case of any error, `pcall` returns **false** plus the error message.
256-
---@generic T, R, R1
257-
---@param f sync fun(...: T...): R1, R...
256+
---@generic T, R
257+
---@param f sync fun(...: T...): R...
258258
---@param ... T...
259-
---@return boolean, R1|string, R...
259+
---@return_overload true, R...
260+
---@return_overload false, string
260261
function pcall(f, ...) end
261262

262263
---

crates/emmylua_code_analysis/src/compilation/analyzer/doc/attribute_tags.rs

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,6 +34,9 @@ pub fn analyze_tag_attribute_use(
3434
(LuaAst::LuaDocTagReturn(_), LuaSemanticDeclId::Signature(_)) => {
3535
return Some(());
3636
}
37+
(LuaAst::LuaDocTagReturnOverload(_), LuaSemanticDeclId::Signature(_)) => {
38+
return Some(());
39+
}
3740
_ => {}
3841
}
3942
}
@@ -147,7 +150,8 @@ fn attribute_find_doc(comment: &LuaSyntaxNode) -> Option<LuaSyntaxNode> {
147150
LuaKind::Syntax(
148151
LuaSyntaxKind::DocTagField
149152
| LuaSyntaxKind::DocTagParam
150-
| LuaSyntaxKind::DocTagReturn,
153+
| LuaSyntaxKind::DocTagReturn
154+
| LuaSyntaxKind::DocTagReturnOverload,
151155
) => {
152156
if let Some(node) = sibling.as_node() {
153157
return Some(node.clone());

crates/emmylua_code_analysis/src/compilation/analyzer/doc/tags.rs

Lines changed: 4 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -22,7 +22,7 @@ use super::{
2222
type_def_tags::{analyze_alias, analyze_class, analyze_enum, analyze_func_generic},
2323
type_ref_tags::{
2424
analyze_as, analyze_cast, analyze_module, analyze_other, analyze_overload, analyze_param,
25-
analyze_return, analyze_return_cast, analyze_see, analyze_type,
25+
analyze_return, analyze_return_cast, analyze_return_overload, analyze_see, analyze_type,
2626
},
2727
};
2828

@@ -55,6 +55,9 @@ pub fn analyze_tag(analyzer: &mut DocAnalyzer, tag: LuaDocTag) -> Option<()> {
5555
LuaDocTag::Return(return_tag) => {
5656
analyze_return(analyzer, return_tag)?;
5757
}
58+
LuaDocTag::ReturnOverload(return_overload_tag) => {
59+
analyze_return_overload(analyzer, return_overload_tag)?;
60+
}
5861
LuaDocTag::ReturnCast(return_cast) => {
5962
analyze_return_cast(analyzer, return_cast)?;
6063
}

crates/emmylua_code_analysis/src/compilation/analyzer/doc/type_ref_tags.rs

Lines changed: 55 additions & 25 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,8 @@
11
use emmylua_parser::{
22
LuaAst, LuaAstNode, LuaAstToken, LuaBlock, LuaDocDescriptionOwner, LuaDocTagAs, LuaDocTagCast,
33
LuaDocTagModule, LuaDocTagOther, LuaDocTagOverload, LuaDocTagParam, LuaDocTagReturn,
4-
LuaDocTagReturnCast, LuaDocTagSchema, LuaDocTagSee, LuaDocTagType, LuaExpr, LuaLocalName,
5-
LuaTokenKind, LuaVarExpr,
4+
LuaDocTagReturnCast, LuaDocTagReturnOverload, LuaDocTagSchema, LuaDocTagSee, LuaDocTagType,
5+
LuaExpr, LuaLocalName, LuaTokenKind, LuaVarExpr,
66
};
77

88
use super::{
@@ -16,8 +16,8 @@ use crate::{
1616
SignatureReturnStatus, TypeOps,
1717
compilation::analyzer::common::bind_type,
1818
db_index::{
19-
LuaDeclId, LuaDocParamInfo, LuaDocReturnInfo, LuaMemberId, LuaOperator, LuaSemanticDeclId,
20-
LuaSignatureId, LuaType,
19+
LuaDeclId, LuaDocParamInfo, LuaDocReturnInfo, LuaDocReturnOverloadInfo, LuaMemberId,
20+
LuaOperator, LuaSemanticDeclId, LuaSignatureId, LuaType,
2121
},
2222
};
2323
use crate::{
@@ -248,29 +248,59 @@ pub fn analyze_return(analyzer: &mut DocAnalyzer, tag: LuaDocTagReturn) -> Optio
248248
let description = tag
249249
.get_description()
250250
.map(|des| preprocess_description(&des.get_description_text(), None));
251+
let return_infos = tag
252+
.get_info_list()
253+
.into_iter()
254+
.map(|(doc_type, name_token)| LuaDocReturnInfo {
255+
name: name_token.map(|name| name.get_name_text().to_string()),
256+
type_ref: infer_type(analyzer, doc_type),
257+
description: description.clone(),
258+
attributes: None,
259+
})
260+
.collect::<Vec<_>>();
261+
262+
bind_signature_return_docs(analyzer, &tag, |signature| {
263+
signature.return_docs.extend(return_infos);
264+
})
265+
}
251266

252-
if let Some(closure) = find_owner_closure_or_report(analyzer, &tag) {
253-
let signature_id = LuaSignatureId::from_closure(analyzer.file_id, &closure);
254-
let returns = tag.get_info_list();
255-
for (doc_type, name_token) in returns {
256-
let name = name_token.map(|name| name.get_name_text().to_string());
257-
258-
let type_ref = infer_type(analyzer, doc_type);
259-
let return_info = LuaDocReturnInfo {
260-
name,
261-
type_ref,
262-
description: description.clone(),
263-
attributes: None,
264-
};
265-
266-
let signature = analyzer
267-
.db
268-
.get_signature_index_mut()
269-
.get_or_create(signature_id);
270-
signature.return_docs.push(return_info);
271-
signature.resolve_return = SignatureReturnStatus::DocResolve;
272-
}
267+
pub fn analyze_return_overload(
268+
analyzer: &mut DocAnalyzer,
269+
tag: LuaDocTagReturnOverload,
270+
) -> Option<()> {
271+
let description = tag
272+
.get_description()
273+
.map(|des| preprocess_description(&des.get_description_text(), None))
274+
.filter(|des| !des.is_empty());
275+
let overload_info = LuaDocReturnOverloadInfo {
276+
type_refs: tag
277+
.get_types()
278+
.map(|doc_type| infer_type(analyzer, doc_type))
279+
.collect(),
280+
description,
281+
};
282+
if overload_info.type_refs.is_empty() {
283+
return Some(());
273284
}
285+
286+
bind_signature_return_docs(analyzer, &tag, |signature| {
287+
signature.return_overloads.push(overload_info);
288+
})
289+
}
290+
291+
fn bind_signature_return_docs(
292+
analyzer: &mut DocAnalyzer,
293+
tag: &impl LuaAstNode,
294+
bind: impl FnOnce(&mut crate::LuaSignature),
295+
) -> Option<()> {
296+
let closure = find_owner_closure_or_report(analyzer, tag)?;
297+
let signature_id = LuaSignatureId::from_closure(analyzer.file_id, &closure);
298+
let signature = analyzer
299+
.db
300+
.get_signature_index_mut()
301+
.get_or_create(signature_id);
302+
bind(signature);
303+
signature.resolve_return = SignatureReturnStatus::DocResolve;
274304
Some(())
275305
}
276306

crates/emmylua_code_analysis/src/compilation/analyzer/flow/bind_analyze/stats.rs

Lines changed: 80 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,13 @@
11
use emmylua_parser::{
22
BinaryOperator, LuaAssignStat, LuaAst, LuaAstNode, LuaBlock, LuaBreakStat, LuaCallArgList,
33
LuaCallExprStat, LuaDoStat, LuaExpr, LuaForRangeStat, LuaForStat, LuaFuncStat, LuaGotoStat,
4-
LuaIfStat, LuaLabelStat, LuaLocalStat, LuaRepeatStat, LuaReturnStat, LuaVarExpr, LuaWhileStat,
4+
LuaIfStat, LuaLabelStat, LuaLocalName, LuaLocalStat, LuaRepeatStat, LuaReturnStat, LuaVarExpr,
5+
LuaWhileStat,
56
};
67

78
use crate::{
8-
AnalyzeError, DiagnosticCode, FlowId, FlowNodeKind, LuaClosureId, LuaDeclId,
9+
AnalyzeError, DeclMultiReturnRef, DeclMultiReturnRefAt, DiagnosticCode, FlowId, FlowNodeKind,
10+
LuaClosureId, LuaDeclId,
911
compilation::analyzer::flow::{
1012
bind_analyze::{
1113
bind_block, bind_each_child, bind_node,
@@ -33,13 +35,20 @@ pub fn bind_local_stat(
3335
}
3436
}
3537

36-
for value in values {
38+
for value in &values {
3739
// If there are more values than names, we still need to bind the values
3840
bind_expr(binder, value.clone(), current);
3941
}
4042

4143
let local_flow_id = binder.create_decl(local_stat.get_position());
4244
binder.add_antecedent(local_flow_id, current);
45+
bind_multi_return_refs(
46+
binder,
47+
&get_local_decl_ids(binder, &local_names),
48+
&values,
49+
local_stat.get_position(),
50+
local_flow_id,
51+
);
4352
local_flow_id
4453
}
4554

@@ -69,6 +78,27 @@ fn check_value_expr_is_check_expr(value_expr: LuaExpr) -> bool {
6978
}
7079
}
7180

81+
fn get_local_decl_ids(
82+
binder: &FlowBinder<'_>,
83+
local_names: &[LuaLocalName],
84+
) -> Vec<Option<LuaDeclId>> {
85+
local_names
86+
.iter()
87+
.map(|name| Some(LuaDeclId::new(binder.file_id, name.get_position())))
88+
.collect()
89+
}
90+
91+
fn get_var_decl_ids(binder: &FlowBinder<'_>, vars: &[LuaVarExpr]) -> Vec<Option<LuaDeclId>> {
92+
vars.iter()
93+
.map(|var| {
94+
binder
95+
.db
96+
.get_reference_index()
97+
.get_var_reference_decl(&binder.file_id, var.get_range())
98+
})
99+
.collect()
100+
}
101+
72102
pub fn bind_assign_stat(
73103
binder: &mut FlowBinder,
74104
assign_stat: LuaAssignStat,
@@ -91,10 +121,57 @@ pub fn bind_assign_stat(
91121
let assignment_kind = FlowNodeKind::Assignment(assign_stat.to_ptr());
92122
let flow_id = binder.create_node(assignment_kind);
93123
binder.add_antecedent(flow_id, current);
124+
bind_multi_return_refs(
125+
binder,
126+
&get_var_decl_ids(binder, &vars),
127+
&values,
128+
assign_stat.get_position(),
129+
flow_id,
130+
);
94131

95132
flow_id
96133
}
97134

135+
fn bind_multi_return_refs(
136+
binder: &mut FlowBinder,
137+
decl_ids: &[Option<LuaDeclId>],
138+
values: &[LuaExpr],
139+
position: rowan::TextSize,
140+
flow_id: FlowId,
141+
) {
142+
let tail_call = values.last().and_then(|value| match value {
143+
LuaExpr::CallExpr(call_expr) => Some((values.len() - 1, call_expr.to_ptr())),
144+
_ => None,
145+
});
146+
147+
for (i, decl_id) in decl_ids.iter().enumerate() {
148+
let Some(decl_id) = decl_id else {
149+
continue;
150+
};
151+
152+
let reference = tail_call.as_ref().and_then(|(last_value_idx, call_expr)| {
153+
if i < *last_value_idx {
154+
return None;
155+
}
156+
157+
Some(DeclMultiReturnRef {
158+
call_expr: call_expr.clone(),
159+
return_index: i - *last_value_idx,
160+
})
161+
});
162+
163+
binder
164+
.decl_multi_return_ref
165+
.entry(*decl_id)
166+
.or_default()
167+
.push(DeclMultiReturnRefAt {
168+
position,
169+
flow_id,
170+
reference,
171+
});
172+
}
173+
}
174+
98175
pub fn bind_call_expr_stat(
99176
binder: &mut FlowBinder,
100177
call_expr_stat: LuaCallExprStat,

crates/emmylua_code_analysis/src/compilation/analyzer/flow/binder.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,15 +6,16 @@ use rowan::TextSize;
66
use smol_str::SmolStr;
77

88
use crate::{
9-
AnalyzeError, DbIndex, FileId, FlowAntecedent, FlowId, FlowNode, FlowNodeKind, FlowTree,
10-
LuaClosureId, LuaDeclId,
9+
AnalyzeError, DbIndex, DeclMultiReturnRefAt, FileId, FlowAntecedent, FlowId, FlowNode,
10+
FlowNodeKind, FlowTree, LuaClosureId, LuaDeclId,
1111
};
1212

1313
#[derive(Debug)]
1414
pub struct FlowBinder<'a> {
1515
pub db: &'a mut DbIndex,
1616
pub file_id: FileId,
1717
pub decl_bind_expr_ref: HashMap<LuaDeclId, LuaAstPtr<LuaExpr>>,
18+
pub decl_multi_return_ref: HashMap<LuaDeclId, Vec<DeclMultiReturnRefAt>>,
1819
pub start: FlowId,
1920
pub unreachable: FlowId,
2021
pub loop_label: FlowId,
@@ -36,6 +37,7 @@ impl<'a> FlowBinder<'a> {
3637
flow_nodes: Vec::new(),
3738
multiple_antecedents: Vec::new(),
3839
decl_bind_expr_ref: HashMap::new(),
40+
decl_multi_return_ref: HashMap::new(),
3941
labels: HashMap::new(),
4042
start: FlowId::default(),
4143
unreachable: FlowId::default(),
@@ -189,6 +191,7 @@ impl<'a> FlowBinder<'a> {
189191
pub fn finish(self) -> FlowTree {
190192
FlowTree::new(
191193
self.decl_bind_expr_ref,
194+
self.decl_multi_return_ref,
192195
self.flow_nodes,
193196
self.multiple_antecedents,
194197
// self.labels,

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

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -31,15 +31,7 @@ pub fn analyze_chunk_return(analyzer: &mut LuaAnalyzer, chunk: LuaChunk) -> Opti
3131
.db
3232
.get_module_index_mut()
3333
.get_module_mut(analyzer.file_id)?;
34-
match expr_type {
35-
LuaType::Variadic(multi) => {
36-
let ty = multi.get_type(0)?;
37-
module_info.export_type = Some(ty.clone());
38-
}
39-
_ => {
40-
module_info.export_type = Some(expr_type);
41-
}
42-
}
34+
module_info.export_type = Some(expr_type.get_result_slot_type(0).unwrap_or(expr_type));
4335
module_info.semantic_id = semantic_id;
4436
break;
4537
}

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

Lines changed: 7 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -47,10 +47,8 @@ pub fn analyze_local_stat(analyzer: &mut LuaAnalyzer, local_stat: LuaLocalStat)
4747
};
4848

4949
match analyzer.infer_expr(&expr) {
50-
Ok(mut expr_type) => {
51-
if let LuaType::Variadic(multi) = expr_type {
52-
expr_type = multi.get_type(0)?.clone();
53-
}
50+
Ok(expr_type) => {
51+
let expr_type = expr_type.get_result_slot_type(0).unwrap_or(expr_type);
5452
let decl_id = LuaDeclId::new(analyzer.file_id, position);
5553
// 当`call`参数包含表时, 表可能未被分析, 需要延迟
5654
if let LuaType::Instance(instance) = &expr_type
@@ -106,12 +104,12 @@ pub fn analyze_local_stat(analyzer: &mut LuaAnalyzer, local_stat: LuaLocalStat)
106104
if let Some(last_expr) = last_expr {
107105
match analyzer.infer_expr(last_expr) {
108106
Ok(last_expr_type) => {
109-
if let LuaType::Variadic(variadic) = last_expr_type {
107+
if last_expr_type.contain_multi_return() {
110108
for i in expr_count..name_count {
111109
let name = name_list.get(i)?;
112110
let position = name.get_position();
113111
let decl_id = LuaDeclId::new(analyzer.file_id, position);
114-
let ret_type = variadic.get_type(i - expr_count + 1);
112+
let ret_type = last_expr_type.get_result_slot_type(i - expr_count + 1);
115113
if let Some(ret_type) = ret_type {
116114
bind_type(
117115
analyzer.db,
@@ -311,10 +309,7 @@ pub fn analyze_assign_stat(analyzer: &mut LuaAnalyzer, assign_stat: LuaAssignSta
311309
}
312310

313311
let expr_type = match analyzer.infer_expr(expr) {
314-
Ok(expr_type) => match expr_type {
315-
LuaType::Variadic(multi) => multi.get_type(0)?.clone(),
316-
_ => expr_type,
317-
},
312+
Ok(expr_type) => expr_type.get_result_slot_type(0).unwrap_or(expr_type),
318313
Err(InferFailReason::None) => LuaType::Unknown,
319314
Err(reason) => {
320315
match type_owner {
@@ -367,7 +362,7 @@ pub fn analyze_assign_stat(analyzer: &mut LuaAnalyzer, assign_stat: LuaAssignSta
367362
{
368363
match analyzer.infer_expr(last_expr) {
369364
Ok(last_expr_type) => {
370-
if last_expr_type.is_multi_return() {
365+
if last_expr_type.contain_multi_return() {
371366
for i in expr_count..var_count {
372367
let var = var_list.get(i)?;
373368
let type_owner = get_var_owner(analyzer, var.clone());
@@ -408,10 +403,7 @@ fn assign_merge_type_owner_and_expr_type(
408403
expr_type: &LuaType,
409404
idx: usize,
410405
) -> Option<()> {
411-
let mut expr_type = expr_type.clone();
412-
if let LuaType::Variadic(multi) = expr_type {
413-
expr_type = multi.get_type(idx).unwrap_or(&LuaType::Nil).clone();
414-
}
406+
let expr_type = expr_type.get_result_slot_type(idx).unwrap_or(LuaType::Nil);
415407

416408
bind_type(analyzer.db, type_owner, LuaTypeCache::InferType(expr_type));
417409

0 commit comments

Comments
 (0)