Skip to content

Commit 978b683

Browse files
authored
Merge pull request #845 from xuhuanzy/fix
update
2 parents 86ae47e + c2ef3e8 commit 978b683

File tree

30 files changed

+809
-274
lines changed

30 files changed

+809
-274
lines changed

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

Lines changed: 35 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -2,10 +2,10 @@ use std::sync::Arc;
22

33
use emmylua_parser::{
44
LuaAst, LuaAstNode, LuaDocAttributeType, LuaDocBinaryType, LuaDocConditionalType,
5-
LuaDocDescriptionOwner, LuaDocFuncType, LuaDocGenericDecl, LuaDocGenericType,
6-
LuaDocIndexAccessType, LuaDocInferType, LuaDocMappedType, LuaDocMultiLineUnionType,
7-
LuaDocObjectFieldKey, LuaDocObjectType, LuaDocStrTplType, LuaDocType, LuaDocUnaryType,
8-
LuaDocVariadicType, LuaLiteralToken, LuaSyntaxKind, LuaTypeBinaryOperator,
5+
LuaDocDescriptionOwner, LuaDocFuncType, LuaDocGenericDecl, LuaDocGenericDeclList,
6+
LuaDocGenericType, LuaDocIndexAccessType, LuaDocInferType, LuaDocMappedType,
7+
LuaDocMultiLineUnionType, LuaDocObjectFieldKey, LuaDocObjectType, LuaDocStrTplType, LuaDocType,
8+
LuaDocUnaryType, LuaDocVariadicType, LuaLiteralToken, LuaSyntaxKind, LuaTypeBinaryOperator,
99
LuaTypeUnaryOperator, LuaVarExpr,
1010
};
1111
use internment::ArcIntern;
@@ -469,6 +469,10 @@ fn infer_unary_type(analyzer: &mut DocAnalyzer, unary_type: &LuaDocUnaryType) ->
469469
}
470470

471471
fn infer_func_type(analyzer: &mut DocAnalyzer, func: &LuaDocFuncType) -> LuaType {
472+
if let Some(generic_list) = func.get_generic_decl_list() {
473+
register_inline_func_generics(analyzer, func, generic_list);
474+
}
475+
472476
let mut params_result = Vec::new();
473477
for param in func.get_params() {
474478
let name = if let Some(param) = param.get_name_token() {
@@ -544,6 +548,33 @@ fn infer_func_type(analyzer: &mut DocAnalyzer, func: &LuaDocFuncType) -> LuaType
544548
)
545549
}
546550

551+
fn register_inline_func_generics(
552+
analyzer: &mut DocAnalyzer,
553+
func: &LuaDocFuncType,
554+
generic_list: LuaDocGenericDeclList,
555+
) {
556+
let mut generics = Vec::new();
557+
for param in generic_list.get_generic_decl() {
558+
let Some(name_token) = param.get_name_token() else {
559+
continue;
560+
};
561+
562+
let constraint = param.get_type().map(|ty| infer_type(analyzer, ty));
563+
generics.push(GenericParam::new(
564+
SmolStr::new(name_token.get_name_text()),
565+
constraint,
566+
None,
567+
));
568+
}
569+
if generics.is_empty() {
570+
return;
571+
}
572+
573+
analyzer
574+
.generic_index
575+
.add_generic_scope(vec![func.get_range()], generics, true);
576+
}
577+
547578
fn get_colon_define(analyzer: &mut DocAnalyzer) -> Option<bool> {
548579
let owner = analyzer.comment.get_owner()?;
549580
if let LuaAst::LuaFuncStat(func_stat) = owner {

crates/emmylua_code_analysis/src/compilation/test/generic_test.rs

Lines changed: 47 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -631,4 +631,51 @@ mod test {
631631
"#,
632632
));
633633
}
634+
635+
#[test]
636+
fn test_issue_846() {
637+
let mut ws = VirtualWorkspace::new();
638+
639+
ws.def(
640+
r#"
641+
---@alias Parameters<T extends function> T extends (fun(...: infer P): any) and P or never
642+
643+
---@param x number
644+
---@param y number
645+
---@return number
646+
function pow(x, y) end
647+
648+
---@generic F
649+
---@param f F
650+
---@return Parameters<F>
651+
function return_params(f) end
652+
"#,
653+
);
654+
assert!(ws.check_code_for(
655+
DiagnosticCode::ParamTypeMismatch,
656+
r#"
657+
result = return_params(pow)
658+
"#,
659+
));
660+
let result_ty = ws.expr_ty("result");
661+
assert_eq!(ws.humanize_type(result_ty), "(number,number)");
662+
}
663+
664+
#[test]
665+
fn test_overload() {
666+
let mut ws = VirtualWorkspace::new();
667+
668+
assert!(ws.check_code_for(
669+
DiagnosticCode::ParamTypeMismatch,
670+
r#"
671+
---@class Expect
672+
---@overload fun<T>(actual: T): T
673+
local expect = {}
674+
675+
result = expect("")
676+
"#,
677+
));
678+
let result_ty = ws.expr_ty("result");
679+
assert_eq!(ws.humanize_type(result_ty), "string");
680+
}
634681
}

crates/emmylua_code_analysis/src/db_index/type/types.rs

Lines changed: 5 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -717,8 +717,11 @@ impl LuaFunctionType {
717717
{
718718
return false;
719719
}
720-
721-
semantic_model.type_check(owner_type, t).is_ok()
720+
if semantic_model.type_check(owner_type, t).is_ok() {
721+
return true;
722+
}
723+
// 如果名称是`self`, 则做更宽泛的检查
724+
name == "self" && semantic_model.type_check(t, owner_type).is_ok()
722725
}
723726
None => name == "self",
724727
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -288,6 +288,7 @@ fn check_table_expr_content(
288288
let Some(member_key) = semantic_model.get_member_key(&field_key) else {
289289
continue;
290290
};
291+
291292
let source_type = match semantic_model.infer_member_type(table_type, &member_key) {
292293
Ok(typ) => typ,
293294
Err(_) => {

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

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -966,4 +966,26 @@ return t
966966
"#
967967
));
968968
}
969+
970+
#[test]
971+
fn test_object_table() {
972+
let mut ws = VirtualWorkspace::new();
973+
ws.def(
974+
r#"
975+
---@alias A {[string]: string}
976+
977+
---@param matchers A
978+
function name(matchers)
979+
end
980+
"#,
981+
);
982+
assert!(!ws.check_code_for(
983+
DiagnosticCode::AssignTypeMismatch,
984+
r#"
985+
name({
986+
toBe = 1,
987+
})
988+
"#
989+
));
990+
}
969991
}

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

Lines changed: 63 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1355,4 +1355,67 @@ mod test {
13551355
"#,
13561356
));
13571357
}
1358+
1359+
#[test]
1360+
fn test_fix_issue_844() {
1361+
let mut ws = VirtualWorkspace::new();
1362+
ws.def(
1363+
r#"
1364+
---@alias Tester fun(customTesters: Tester[]): boolean?
1365+
1366+
---@generic V
1367+
---@param t V[]
1368+
---@return fun(tbl: any):int, V
1369+
function ipairs(t) end
1370+
"#,
1371+
);
1372+
assert!(ws.check_code_for(
1373+
DiagnosticCode::ParamTypeMismatch,
1374+
r#"
1375+
---@param newTesters Tester[]
1376+
local function addMatchers(newTesters)
1377+
for _, tester in ipairs(newTesters) do
1378+
end
1379+
end
1380+
"#
1381+
));
1382+
}
1383+
1384+
#[test]
1385+
fn test_pairs_1() {
1386+
let mut ws = VirtualWorkspace::new();
1387+
ws.def(
1388+
r#"
1389+
---@param value string
1390+
function aaaa(value)
1391+
end
1392+
1393+
---@generic K, V
1394+
---@param t {[K]: V} | V[]
1395+
---@return fun(tbl: any):K, V
1396+
function pairs(t) end
1397+
"#,
1398+
);
1399+
assert!(!ws.check_code_for(
1400+
DiagnosticCode::ParamTypeMismatch,
1401+
r#"
1402+
---@type {[string]: number}
1403+
local matchers = {}
1404+
for _, matcher in pairs(matchers) do
1405+
aaaa(matcher)
1406+
end
1407+
"#
1408+
));
1409+
assert!(!ws.check_code_for(
1410+
DiagnosticCode::ParamTypeMismatch,
1411+
r#"
1412+
---@alias MatchersObject {[string]: number}
1413+
---@type MatchersObject
1414+
local matchers = {}
1415+
for _, matcher in pairs(matchers) do
1416+
aaaa(matcher)
1417+
end
1418+
"#
1419+
));
1420+
}
13581421
}

crates/emmylua_code_analysis/src/semantic/generic/instantiate_type/instantiate_func_generic.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -76,6 +76,7 @@ pub fn instantiate_func_generic(
7676
if let Some(type_list) = call_expr.get_call_generic_type_list() {
7777
apply_call_generic_type_list(db, file_id, &mut context, &type_list);
7878
} else {
79+
// 没有指定泛型, 从调用参数中推断
7980
infer_generic_types_from_call(
8081
db,
8182
&mut context,
@@ -160,7 +161,6 @@ fn infer_generic_types_from_call(
160161
}
161162

162163
let arg_type = infer_expr(db, context.cache, call_arg_expr.clone())?;
163-
164164
match (func_param_type, &arg_type) {
165165
(LuaType::Variadic(variadic), _) => {
166166
let mut arg_types = vec![];

crates/emmylua_code_analysis/src/semantic/generic/instantiate_type/instantiate_special_generic.rs

Lines changed: 1 addition & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -42,7 +42,6 @@ pub fn instantiate_alias_call(
4242
if operands.len() != 1 {
4343
return LuaType::Unknown;
4444
}
45-
// let is_tuple = operands.len() == 1 && operands[0].is_tuple();
4645

4746
let members = get_keyof_members(db, &operands[0]).unwrap_or_default();
4847
let member_key_types = members
@@ -54,13 +53,6 @@ pub fn instantiate_alias_call(
5453
})
5554
.collect::<Vec<_>>();
5655
LuaType::Tuple(LuaTupleType::new(member_key_types, LuaTupleStatus::InferResolve).into())
57-
// if is_tuple {
58-
// LuaType::Tuple(
59-
// LuaTupleType::new(member_key_types, LuaTupleStatus::InferResolve).into(),
60-
// )
61-
// } else {
62-
// LuaType::from_vec(member_key_types)
63-
// }
6456
}
6557
// 条件类型不在此处理
6658
LuaAliasCallKind::Extends => {
@@ -285,7 +277,7 @@ fn instantiate_index_call(db: &DbIndex, owner: &LuaType, key: &LuaType) -> LuaTy
285277
}
286278
}
287279

288-
fn get_keyof_members(db: &DbIndex, prefix_type: &LuaType) -> Option<Vec<LuaMemberInfo>> {
280+
pub fn get_keyof_members(db: &DbIndex, prefix_type: &LuaType) -> Option<Vec<LuaMemberInfo>> {
289281
match prefix_type {
290282
LuaType::Variadic(variadic) => match variadic.deref() {
291283
VariadicType::Base(base) => Some(vec![LuaMemberInfo {

0 commit comments

Comments
 (0)