diff --git a/crates/emmylua_code_analysis/src/compilation/test/dots_infer_test.rs b/crates/emmylua_code_analysis/src/compilation/test/dots_infer_test.rs new file mode 100644 index 00000000..7db4c375 --- /dev/null +++ b/crates/emmylua_code_analysis/src/compilation/test/dots_infer_test.rs @@ -0,0 +1,80 @@ +#[cfg(test)] +mod test { + use crate::{FileId, LuaType, VirtualWorkspace}; + use emmylua_parser::LuaLocalStat; + + fn get_type_of_first_local_assign(ws: &mut VirtualWorkspace, file_id: FileId) -> LuaType { + let node: LuaLocalStat = ws.get_node(file_id); + let expr = &node.get_value_exprs().next().unwrap(); + let semantic_model = ws.analysis.compilation.get_semantic_model(file_id).unwrap(); + semantic_model.infer_expr(expr.clone()).unwrap() + } + + #[test] + fn test_dots_normal() { + let mut ws = VirtualWorkspace::new(); + + let file_id = ws.def( + r#" + --- @param ... integer + function foo(...) + local a = { ... } + end + "#, + ); + let a_ty = get_type_of_first_local_assign(&mut ws, file_id); + let a_expected = ws.ty("integer[]"); + assert_eq!(a_ty, a_expected); + } + + #[test] + fn test_dots_normal_variadic() { + let mut ws = VirtualWorkspace::new(); + + let file_id = ws.def( + r#" + --- @param ... integer... + function foo(...) + local a = { ... } + end + "#, + ); + let a_ty = get_type_of_first_local_assign(&mut ws, file_id); + let a_expected = ws.ty("integer[]"); + assert_eq!(a_ty, a_expected); + } + + #[test] + fn test_dots_generic() { + let mut ws = VirtualWorkspace::new(); + + let file_id = ws.def( + r#" + --- @generic T + --- @param ... T + function foo(...) + local a = { ... } + end + "#, + ); + let a_ty = get_type_of_first_local_assign(&mut ws, file_id); + assert_eq!(&ws.humanize_type(a_ty), "T[]"); + } + + #[test] + fn test_dots_variadic() { + let mut ws = VirtualWorkspace::new(); + + let file_id = ws.def( + r#" + --- @generic T + --- @param ... T... + function foo(...) + local a = { ... } + end + "#, + ); + let a_ty = get_type_of_first_local_assign(&mut ws, file_id); + assert_eq!(&ws.humanize_type(a_ty), "T[]"); + } +} diff --git a/crates/emmylua_code_analysis/src/compilation/test/mod.rs b/crates/emmylua_code_analysis/src/compilation/test/mod.rs index 58d8faec..27e44ada 100644 --- a/crates/emmylua_code_analysis/src/compilation/test/mod.rs +++ b/crates/emmylua_code_analysis/src/compilation/test/mod.rs @@ -6,6 +6,7 @@ mod closure_param_infer_test; mod closure_return_test; mod decl_test; mod diagnostic_disable_test; +mod dots_infer_test; mod export_test; mod flow; mod for_range_var_infer_test; diff --git a/crates/emmylua_code_analysis/src/semantic/infer/mod.rs b/crates/emmylua_code_analysis/src/semantic/infer/mod.rs index c2abdd81..4fc036e0 100644 --- a/crates/emmylua_code_analysis/src/semantic/infer/mod.rs +++ b/crates/emmylua_code_analysis/src/semantic/infer/mod.rs @@ -139,7 +139,11 @@ fn infer_literal_expr(db: &DbIndex, config: &LuaInferCache, expr: LuaLiteralExpr Some(decl) if decl.is_global() => LuaType::Any, Some(decl) if decl.is_param() => { let base = infer_param(db, decl).unwrap_or(LuaType::Unknown); - LuaType::Variadic(VariadicType::Base(base).into()) + if matches!(base, LuaType::Variadic(_)) { + base + } else { + LuaType::Variadic(VariadicType::Base(base).into()) + } } _ => LuaType::Any, // 默认返回 Any };