Skip to content

Commit ea306b9

Browse files
committed
fix #578
1 parent 1351438 commit ea306b9

File tree

3 files changed

+151
-3
lines changed

3 files changed

+151
-3
lines changed

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

Lines changed: 24 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1188,4 +1188,28 @@ mod test {
11881188
"#
11891189
));
11901190
}
1191+
1192+
#[test]
1193+
fn test_issue_574() {
1194+
let mut ws = VirtualWorkspace::new();
1195+
ws.def(
1196+
r#"
1197+
--- @param x { y: integer } & { z: string }
1198+
function foo(x) end
1199+
"#,
1200+
);
1201+
assert!(!ws.check_code_for(
1202+
DiagnosticCode::ParamTypeNotMatch,
1203+
r#"
1204+
foo({y = "", z = ""})
1205+
"#
1206+
));
1207+
1208+
assert!(ws.check_code_for(
1209+
DiagnosticCode::ParamTypeNotMatch,
1210+
r#"
1211+
foo({y = 1, z = ""})
1212+
"#
1213+
));
1214+
}
11911215
}
Lines changed: 114 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,114 @@
1+
use crate::{
2+
semantic::type_check::{check_general_type_compact, type_check_guard::TypeCheckGuard},
3+
DbIndex, LuaIntersectionType, LuaMemberOwner, LuaType, TypeCheckFailReason, TypeCheckResult,
4+
};
5+
6+
pub fn check_intersection_type_compact(
7+
db: &DbIndex,
8+
source_intersection: &LuaIntersectionType,
9+
compact_type: &LuaType,
10+
check_guard: TypeCheckGuard,
11+
) -> TypeCheckResult {
12+
match compact_type {
13+
LuaType::TableConst(range) => check_intersection_type_compact_table(
14+
db,
15+
source_intersection,
16+
LuaMemberOwner::Element(range.clone()),
17+
check_guard.next_level()?,
18+
),
19+
LuaType::Object(_) => {
20+
// 检查对象是否满足交叉类型的所有组成部分
21+
for intersection_component in source_intersection.get_types() {
22+
check_general_type_compact(
23+
db,
24+
intersection_component,
25+
compact_type,
26+
check_guard.next_level()?,
27+
)?;
28+
}
29+
Ok(())
30+
}
31+
LuaType::Intersection(compact_intersection) => {
32+
// 交叉类型对交叉类型:检查所有组成部分
33+
check_intersection_type_compact_intersection(
34+
db,
35+
source_intersection,
36+
compact_intersection,
37+
check_guard.next_level()?,
38+
)
39+
}
40+
LuaType::Table => Ok(()), // 通用表类型可以匹配任何交叉类型
41+
_ => {
42+
// 对于其他类型,检查是否至少满足一个组成部分
43+
for intersection_component in source_intersection.get_types() {
44+
if check_general_type_compact(
45+
db,
46+
intersection_component,
47+
compact_type,
48+
check_guard.next_level()?,
49+
)
50+
.is_ok()
51+
{
52+
return Ok(());
53+
}
54+
}
55+
Err(TypeCheckFailReason::TypeNotMatch)
56+
}
57+
}
58+
}
59+
60+
fn check_intersection_type_compact_table(
61+
db: &DbIndex,
62+
source_intersection: &LuaIntersectionType,
63+
table_owner: LuaMemberOwner,
64+
check_guard: TypeCheckGuard,
65+
) -> TypeCheckResult {
66+
// 交叉类型要求 TableConst 必须满足所有组成部分
67+
for intersection_component in source_intersection.get_types() {
68+
check_general_type_compact(
69+
db,
70+
intersection_component,
71+
&LuaType::TableConst(
72+
table_owner
73+
.get_element_range()
74+
.ok_or(TypeCheckFailReason::TypeNotMatch)?
75+
.clone(),
76+
),
77+
check_guard.next_level()?,
78+
)?;
79+
}
80+
81+
Ok(())
82+
}
83+
84+
fn check_intersection_type_compact_intersection(
85+
db: &DbIndex,
86+
source_intersection: &LuaIntersectionType,
87+
compact_intersection: &LuaIntersectionType,
88+
check_guard: TypeCheckGuard,
89+
) -> TypeCheckResult {
90+
// 检查源交叉类型的每个组成部分是否都能在目标交叉类型中找到匹配
91+
for source_component in source_intersection.get_types() {
92+
let mut component_matched = false;
93+
94+
for compact_component in compact_intersection.get_types() {
95+
if check_general_type_compact(
96+
db,
97+
source_component,
98+
compact_component,
99+
check_guard.next_level()?,
100+
)
101+
.is_ok()
102+
{
103+
component_matched = true;
104+
break;
105+
}
106+
}
107+
108+
if !component_matched {
109+
return Err(TypeCheckFailReason::TypeNotMatch);
110+
}
111+
}
112+
113+
Ok(())
114+
}

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

Lines changed: 13 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,11 @@
11
mod array_type_check;
2+
mod intersection_type_check;
23
mod object_type_check;
34
mod table_generic_check;
45
mod tuple_type_check;
56

67
use array_type_check::check_array_type_compact;
8+
use intersection_type_check::check_intersection_type_compact;
79
use object_type_check::check_object_type_compact;
810
use table_generic_check::check_table_generic_type_compact;
911
use tuple_type_check::check_tuple_type_compact;
@@ -52,6 +54,17 @@ pub fn check_complex_type_compact(
5254
result => return result,
5355
}
5456
}
57+
LuaType::Intersection(source_intersection) => {
58+
match check_intersection_type_compact(
59+
db,
60+
source_intersection,
61+
compact_type,
62+
check_guard,
63+
) {
64+
Err(TypeCheckFailReason::DonotCheck) => {}
65+
result => return result,
66+
}
67+
}
5568
LuaType::Union(union_type) => {
5669
match compact_type {
5770
LuaType::Union(compact_union) => {
@@ -92,9 +105,6 @@ pub fn check_complex_type_compact(
92105
check_guard.next_level()?,
93106
);
94107
}
95-
96-
// check later
97-
LuaType::Intersection(_) => return Ok(()),
98108
_ => {}
99109
}
100110
// Do I need to check union types?

0 commit comments

Comments
 (0)