Skip to content

Commit 6cc26f7

Browse files
committed
diagnostic: fix #242
1 parent 7d0525e commit 6cc26f7

File tree

3 files changed

+79
-6
lines changed

3 files changed

+79
-6
lines changed

crates/emmylua_code_analysis/src/db_index/module/mod.rs

+4
Original file line numberDiff line numberDiff line change
@@ -390,6 +390,10 @@ impl LuaModuleIndex {
390390
file_ids
391391
}
392392

393+
pub fn is_std(&self, file_id: &FileId) -> bool {
394+
self.get_std_file_ids().contains(file_id)
395+
}
396+
393397
pub fn get_main_workspace_file_ids(&self) -> Vec<FileId> {
394398
let mut file_ids = Vec::new();
395399
for module_info in self.file_module_map.values() {

crates/emmylua_code_analysis/src/diagnostic/checker/return_type_mismatch.rs

+38-6
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,9 @@
1-
use emmylua_parser::{LuaAstNode, LuaClosureExpr, LuaReturnStat};
2-
use rowan::TextRange;
1+
use emmylua_parser::{LuaAstNode, LuaClosureExpr, LuaExpr, LuaReturnStat};
2+
use rowan::{NodeOrToken, TextRange};
33

44
use crate::{
5-
humanize_type, DiagnosticCode, LuaSignatureId, LuaType, RenderLevel, SemanticModel,
6-
SignatureReturnStatus, TypeCheckFailReason, TypeCheckResult,
5+
humanize_type, DiagnosticCode, LuaSemanticDeclId, LuaSignatureId, LuaType, RenderLevel,
6+
SemanticModel, SignatureReturnStatus, TypeCheckFailReason, TypeCheckResult,
77
};
88

99
use super::{get_own_return_stats, DiagnosticContext};
@@ -46,7 +46,12 @@ fn check_return_stat(
4646
&return_stat.get_expr_list().collect::<Vec<_>>(),
4747
None,
4848
)?;
49-
let return_expr_types = infos.iter().map(|(typ, _)| typ.clone()).collect::<Vec<_>>();
49+
let mut return_expr_types = infos.iter().map(|(typ, _)| typ.clone()).collect::<Vec<_>>();
50+
// 解决 setmetatable 的返回值类型问题
51+
let setmetatable_index = has_setmetatable(semantic_model, return_stat);
52+
if let Some(setmetatable_index) = setmetatable_index {
53+
return_expr_types[setmetatable_index] = LuaType::Any;
54+
}
5055
let return_expr_ranges = infos
5156
.iter()
5257
.map(|(_, range)| range.clone())
@@ -59,7 +64,6 @@ fn check_return_stat(
5964
if return_expr_types.len() < index {
6065
break;
6166
}
62-
6367
check_variadic_return_type_match(
6468
context,
6569
semantic_model,
@@ -173,3 +177,31 @@ fn add_type_check_diagnostic(
173177
},
174178
}
175179
}
180+
181+
fn has_setmetatable(semantic_model: &SemanticModel, return_stat: &LuaReturnStat) -> Option<usize> {
182+
for (index, expr) in return_stat.get_expr_list().enumerate() {
183+
if let LuaExpr::CallExpr(call_expr) = expr {
184+
if let Some(prefix_expr) = call_expr.get_prefix_expr() {
185+
let semantic_info = semantic_model
186+
.get_semantic_info(NodeOrToken::Node(prefix_expr.syntax().clone().into()))?;
187+
188+
if let Some(LuaSemanticDeclId::LuaDecl(decl_id)) = semantic_info.semantic_decl {
189+
let decl = semantic_model.get_db().get_decl_index().get_decl(&decl_id);
190+
191+
if let Some(decl) = decl {
192+
if decl.is_global()
193+
&& semantic_model
194+
.get_db()
195+
.get_module_index()
196+
.is_std(&decl.get_file_id())
197+
&& decl.get_name() == "setmetatable"
198+
{
199+
return Some(index);
200+
}
201+
}
202+
}
203+
}
204+
}
205+
}
206+
None
207+
}

crates/emmylua_code_analysis/src/diagnostic/test/return_type_mismatch_test.rs

+37
Original file line numberDiff line numberDiff line change
@@ -2,6 +2,43 @@
22
mod tests {
33
use crate::{DiagnosticCode, VirtualWorkspace};
44

5+
#[test]
6+
fn test_issue_242() {
7+
let mut ws = VirtualWorkspace::new_with_init_std_lib();
8+
9+
assert!(ws.check_code_for_namespace(
10+
DiagnosticCode::ReturnTypeMismatch,
11+
r#"
12+
local setmetatable = setmetatable
13+
--- @class A
14+
local A = {}
15+
16+
function A:method() end
17+
18+
--- @return A
19+
function new()
20+
return setmetatable({}, { __index = A })
21+
end
22+
"#
23+
));
24+
25+
assert!(ws.check_code_for_namespace(
26+
DiagnosticCode::ReturnTypeMismatch,
27+
r#"
28+
--- @class A
29+
local A = {}
30+
A.__index = A
31+
32+
function A:method() end
33+
34+
--- @return A
35+
function new()
36+
return setmetatable({}, A)
37+
end
38+
"#
39+
));
40+
}
41+
542
#[test]
643
fn test_issue_220() {
744
let mut ws = VirtualWorkspace::new();

0 commit comments

Comments
 (0)