Skip to content

Commit 4f53204

Browse files
committed
Prevent double variadic wrapping when inferring ...
This prevents situation when `...` is annotated as variadic (`@param ... T...`), and its type is inferred as `(T...)...`
1 parent c5a3506 commit 4f53204

3 files changed

Lines changed: 86 additions & 1 deletion

File tree

Lines changed: 80 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,80 @@
1+
#[cfg(test)]
2+
mod test {
3+
use crate::{FileId, LuaType, VirtualWorkspace};
4+
use emmylua_parser::LuaLocalStat;
5+
6+
fn get_type_of_first_local_assign(ws: &mut VirtualWorkspace, file_id: FileId) -> LuaType {
7+
let node: LuaLocalStat = ws.get_node(file_id);
8+
let expr = &node.get_value_exprs().next().unwrap();
9+
let semantic_model = ws.analysis.compilation.get_semantic_model(file_id).unwrap();
10+
semantic_model.infer_expr(expr.clone()).unwrap()
11+
}
12+
13+
#[test]
14+
fn test_dots_normal() {
15+
let mut ws = VirtualWorkspace::new();
16+
17+
let file_id = ws.def(
18+
r#"
19+
--- @param ... integer
20+
function foo(...)
21+
local a = { ... }
22+
end
23+
"#,
24+
);
25+
let a_ty = get_type_of_first_local_assign(&mut ws, file_id);
26+
let a_expected = ws.ty("integer[]");
27+
assert_eq!(a_ty, a_expected);
28+
}
29+
30+
#[test]
31+
fn test_dots_normal_variadic() {
32+
let mut ws = VirtualWorkspace::new();
33+
34+
let file_id = ws.def(
35+
r#"
36+
--- @param ... integer...
37+
function foo(...)
38+
local a = { ... }
39+
end
40+
"#,
41+
);
42+
let a_ty = get_type_of_first_local_assign(&mut ws, file_id);
43+
let a_expected = ws.ty("integer[]");
44+
assert_eq!(a_ty, a_expected);
45+
}
46+
47+
#[test]
48+
fn test_dots_generic() {
49+
let mut ws = VirtualWorkspace::new();
50+
51+
let file_id = ws.def(
52+
r#"
53+
--- @generic T
54+
--- @param ... T
55+
function foo(...)
56+
local a = { ... }
57+
end
58+
"#,
59+
);
60+
let a_ty = get_type_of_first_local_assign(&mut ws, file_id);
61+
assert_eq!(&ws.humanize_type(a_ty), "T[]");
62+
}
63+
64+
#[test]
65+
fn test_dots_variadic() {
66+
let mut ws = VirtualWorkspace::new();
67+
68+
let file_id = ws.def(
69+
r#"
70+
--- @generic T
71+
--- @param ... T...
72+
function foo(...)
73+
local a = { ... }
74+
end
75+
"#,
76+
);
77+
let a_ty = get_type_of_first_local_assign(&mut ws, file_id);
78+
assert_eq!(&ws.humanize_type(a_ty), "T[]");
79+
}
80+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -6,6 +6,7 @@ mod closure_param_infer_test;
66
mod closure_return_test;
77
mod decl_test;
88
mod diagnostic_disable_test;
9+
mod dots_infer_test;
910
mod export_test;
1011
mod flow;
1112
mod for_range_var_infer_test;

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

Lines changed: 5 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -139,7 +139,11 @@ fn infer_literal_expr(db: &DbIndex, config: &LuaInferCache, expr: LuaLiteralExpr
139139
Some(decl) if decl.is_global() => LuaType::Any,
140140
Some(decl) if decl.is_param() => {
141141
let base = infer_param(db, decl).unwrap_or(LuaType::Unknown);
142-
LuaType::Variadic(VariadicType::Base(base).into())
142+
if matches!(base, LuaType::Variadic(_)) {
143+
base
144+
} else {
145+
LuaType::Variadic(VariadicType::Base(base).into())
146+
}
143147
}
144148
_ => LuaType::Any, // 默认返回 Any
145149
};

0 commit comments

Comments
 (0)