Skip to content

Commit 05a7d70

Browse files
committed
super keyof type check
1 parent b2ea548 commit 05a7d70

File tree

5 files changed

+125
-4
lines changed

5 files changed

+125
-4
lines changed

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

Lines changed: 36 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1418,4 +1418,40 @@ mod test {
14181418
"#
14191419
));
14201420
}
1421+
1422+
#[test]
1423+
fn test_key_of() {
1424+
let mut ws = VirtualWorkspace::new();
1425+
ws.def(
1426+
r#"
1427+
---@class SuiteHooks
1428+
---@field beforeAll string
1429+
---@field afterAll string
1430+
1431+
---@param name keyof SuiteHooks
1432+
function test(name)
1433+
end
1434+
"#,
1435+
);
1436+
assert!(!ws.check_code_for(
1437+
DiagnosticCode::ParamTypeMismatch,
1438+
r#"
1439+
test("a")
1440+
"#,
1441+
));
1442+
assert!(ws.check_code_for(
1443+
DiagnosticCode::ParamTypeMismatch,
1444+
r#"
1445+
test("beforeAll")
1446+
"#,
1447+
));
1448+
assert!(ws.check_code_for(
1449+
DiagnosticCode::ParamTypeMismatch,
1450+
r#"
1451+
---@type keyof SuiteHooks
1452+
local name
1453+
test(name)
1454+
"#,
1455+
));
1456+
}
14211457
}
Lines changed: 82 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,82 @@
1+
use std::sync::Arc;
2+
3+
use crate::{
4+
LuaAliasCallKind, LuaAliasCallType, LuaMemberKey, LuaType, LuaUnionType, TypeCheckFailReason,
5+
TypeCheckResult, get_keyof_members,
6+
semantic::type_check::{
7+
check_general_type_compact, type_check_context::TypeCheckContext,
8+
type_check_guard::TypeCheckGuard,
9+
},
10+
};
11+
12+
pub fn check_call_type_compact(
13+
context: &mut TypeCheckContext,
14+
source_call: &LuaAliasCallType,
15+
compact_type: &LuaType,
16+
check_guard: TypeCheckGuard,
17+
) -> TypeCheckResult {
18+
if let LuaAliasCallKind::KeyOf = source_call.get_call_kind() {
19+
let source_operands = source_call.get_operands().iter().collect::<Vec<_>>();
20+
if source_operands.len() != 1 {
21+
return Err(TypeCheckFailReason::TypeNotMatch);
22+
}
23+
match compact_type {
24+
LuaType::Call(compact_call) => {
25+
if compact_call.get_call_kind() == LuaAliasCallKind::KeyOf {
26+
if compact_call.as_ref() == source_call {
27+
return Ok(());
28+
}
29+
let compact_operands = compact_call.get_operands().iter().collect::<Vec<_>>();
30+
if compact_operands.len() != 1 {
31+
return Err(TypeCheckFailReason::TypeNotMatch);
32+
}
33+
34+
let source_key_types = LuaType::Union(Arc::new(LuaUnionType::from_vec(
35+
get_key_of_key_types(context, &source_operands[0]),
36+
)));
37+
let compact_key_types = LuaType::Union(Arc::new(LuaUnionType::from_vec(
38+
get_key_of_key_types(context, &compact_operands[0]),
39+
)));
40+
return check_general_type_compact(
41+
context,
42+
&source_key_types,
43+
&compact_key_types,
44+
check_guard.next_level()?,
45+
);
46+
}
47+
}
48+
_ => {
49+
let key_types = get_key_of_key_types(context, &source_operands[0]);
50+
for key_type in &key_types {
51+
match check_general_type_compact(
52+
context,
53+
&key_type,
54+
compact_type,
55+
check_guard.next_level()?,
56+
) {
57+
Ok(_) => return Ok(()),
58+
Err(e) if e.is_type_not_match() => {}
59+
Err(e) => return Err(e),
60+
}
61+
}
62+
return Err(TypeCheckFailReason::TypeNotMatch);
63+
}
64+
}
65+
}
66+
67+
// TODO: 实现其他 call 类型的检查
68+
Ok(())
69+
}
70+
71+
fn get_key_of_key_types(context: &TypeCheckContext, prefix_type: &LuaType) -> Vec<LuaType> {
72+
let members = get_keyof_members(context.db, prefix_type).unwrap_or_default();
73+
let key_types = members
74+
.iter()
75+
.filter_map(|m| match &m.key {
76+
LuaMemberKey::Integer(i) => Some(LuaType::DocIntegerConst(*i)),
77+
LuaMemberKey::Name(s) => Some(LuaType::DocStringConst(s.clone().into())),
78+
_ => None,
79+
})
80+
.collect::<Vec<_>>();
81+
key_types
82+
}

crates/emmylua_code_analysis/src/semantic/type_check/complex_type/mod.rs

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,12 @@
11
mod array_type_check;
2+
mod call_type_check;
23
mod intersection_type_check;
34
mod object_type_check;
45
mod table_generic_check;
56
mod tuple_type_check;
67

78
use array_type_check::check_array_type_compact;
9+
use call_type_check::check_call_type_compact;
810
use intersection_type_check::check_intersection_type_compact;
911
use object_type_check::check_object_type_compact;
1012
use table_generic_check::check_table_generic_type_compact;
@@ -122,6 +124,9 @@ pub fn check_complex_type_compact(
122124
LuaType::Generic(_) => {
123125
return Ok(());
124126
}
127+
LuaType::Call(alias_call) => {
128+
return check_call_type_compact(context, alias_call, compact_type, check_guard);
129+
}
125130
LuaType::MultiLineUnion(multi_union) => {
126131
let union = multi_union.to_union();
127132
return check_complex_type_compact(

crates/emmylua_code_analysis/src/semantic/type_check/mod.rs

Lines changed: 1 addition & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -137,13 +137,11 @@ fn check_general_type_compact(
137137
| LuaType::Union(_)
138138
| LuaType::Intersection(_)
139139
| LuaType::TableGeneric(_)
140+
| LuaType::Call(_)
140141
| LuaType::MultiLineUnion(_) => {
141142
check_complex_type_compact(context, &source, &compact_type, check_guard)
142143
}
143144

144-
// need think how to do that
145-
LuaType::Call(_) => Ok(()),
146-
147145
// generic type
148146
LuaType::Generic(generic) => {
149147
check_generic_type_compact(context, generic, &compact_type, check_guard)

crates/emmylua_ls/src/handlers/test/completion_test.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2375,7 +2375,7 @@ mod tests {
23752375
}
23762376

23772377
#[gtest]
2378-
fn test_modle_return_signature() -> Result<()> {
2378+
fn test_module_return_signature() -> Result<()> {
23792379
let mut ws = ProviderVirtualWorkspace::new();
23802380
ws.def_file(
23812381
"test.lua",

0 commit comments

Comments
 (0)