Skip to content

Commit b0a0f00

Browse files
committed
fix(diagnostic): param type check
1 parent b0d6666 commit b0a0f00

9 files changed

Lines changed: 327 additions & 289 deletions

File tree

crates/emmylua_code_analysis/src/diagnostic/checker/param_check/call_facts.rs

Lines changed: 24 additions & 72 deletions
Original file line numberDiff line numberDiff line change
@@ -42,74 +42,39 @@ impl CallFacts {
4242
&self,
4343
semantic_model: &SemanticModel,
4444
) -> (Vec<LuaType>, Vec<TextRange>) {
45-
self.inferred_arg_types_and_ranges(semantic_model)
46-
.into_iter()
47-
.unzip()
48-
}
49-
50-
pub(super) fn arg_types(&self, semantic_model: &SemanticModel) -> Vec<LuaType> {
51-
self.inferred_arg_types_and_ranges(semantic_model)
52-
.into_iter()
53-
.map(|(typ, _)| typ)
54-
.collect()
55-
}
45+
let mut cached = self.arg_types_and_ranges.borrow_mut();
46+
if cached.is_none() {
47+
*cached = Some(semantic_model.infer_expr_list_types(&self.arg_exprs, None));
48+
}
5649

57-
pub(super) fn param_count_compatible_funcs(
58-
&self,
59-
semantic_model: &SemanticModel,
60-
) -> Vec<Arc<LuaFunctionType>> {
61-
self.funcs
62-
.iter()
63-
.filter(|func| self.callable_accepts_arg_count(semantic_model, func))
50+
cached
51+
.as_ref()
6452
.cloned()
65-
.collect()
66-
}
67-
68-
pub(super) fn callable_accepts_arg_count(
69-
&self,
70-
semantic_model: &SemanticModel,
71-
func: &LuaFunctionType,
72-
) -> bool {
73-
let Some(call_count) = self.call_arg_count_range(semantic_model, func) else {
74-
// 如果调用数量无法确定, 保守保留候选, 避免误报 ParamTypeMismatch.
75-
return true;
76-
};
77-
let param_count = get_param_count_range(semantic_model.get_db(), &self.call_expr, func);
78-
79-
count_ranges_overlap(call_count, param_count)
53+
.unwrap_or_default()
54+
.into_iter()
55+
.unzip()
8056
}
8157

58+
// 计算当前调用表达式的实参列表能提供多少个实参槽位.
8259
pub(super) fn call_arg_count_range(
8360
&self,
8461
semantic_model: &SemanticModel,
8562
func: &LuaFunctionType,
8663
) -> Option<CountRange> {
87-
let mut count = self.base_call_arg_count_range(semantic_model)?;
64+
let mut count = self
65+
.base_call_arg_count_range
66+
.get_or_init(|| get_base_call_arg_count_range(semantic_model, &self.arg_exprs))
67+
.as_ref()
68+
.copied()?;
8869
if self.call_expr.is_colon_call() && !func.is_colon_define() {
70+
// 冒号调用普通函数时, `obj:foo(x)` 等价于 `obj.foo(obj, x)`.
71+
// 这里要把 receiver 计入调用侧的实参槽位.
8972
count.min += 1;
9073
count.max = count.max.map(|max| max + 1);
9174
}
9275

9376
Some(count)
9477
}
95-
96-
fn inferred_arg_types_and_ranges(
97-
&self,
98-
semantic_model: &SemanticModel,
99-
) -> Vec<(LuaType, TextRange)> {
100-
let mut cached = self.arg_types_and_ranges.borrow_mut();
101-
if cached.is_none() {
102-
*cached = Some(semantic_model.infer_expr_list_types(&self.arg_exprs, None));
103-
}
104-
105-
cached.as_ref().cloned().unwrap_or_default()
106-
}
107-
108-
fn base_call_arg_count_range(&self, semantic_model: &SemanticModel) -> Option<CountRange> {
109-
*self
110-
.base_call_arg_count_range
111-
.get_or_init(|| get_base_call_arg_count_range(semantic_model, &self.arg_exprs))
112-
}
11378
}
11479

11580
// 收集所有可调用的候选.
@@ -142,18 +107,19 @@ fn collect_diagnostic_callables(
142107
(!funcs.is_empty()).then_some(funcs)
143108
}
144109

110+
// 比较调用侧能提供的实参数量, 和函数侧能接受的形参数量是否有交集.
145111
pub(super) fn count_ranges_overlap(call_count: CountRange, param_count: CountRange) -> bool {
146-
// 调用方最多能提供的参数数量, 必须覆盖被调方至少需要的参数数量.
147112
let enough_args = call_count.max.is_none_or(|max| max >= param_count.min);
148-
// 调用方至少会提供的参数数量, 不能超过被调方最多能接收的参数数量.
149113
let not_too_many_args = param_count.max.is_none_or(|max| call_count.min <= max);
150114

151115
enough_args && not_too_many_args
152116
}
153117

154118
#[derive(Clone, Copy)]
155119
pub(super) struct CountRange {
120+
// 数量下界: 调用侧至少会提供多少, 或函数侧至少要求多少.
156121
pub(super) min: usize,
122+
// 数量上界: 调用侧最多会提供多少, 或函数侧最多接受多少; None 表示无上限.
157123
pub(super) max: Option<usize>,
158124
}
159125

@@ -182,13 +148,15 @@ fn get_base_call_arg_count_range(
182148
Some(count)
183149
}
184150

151+
// 计算当前候选函数签名能接受多少个形参槽位.
185152
pub(super) fn get_param_count_range(
186153
db: &DbIndex,
187-
call_expr: &LuaCallExpr,
188154
func: &LuaFunctionType,
155+
call_expr: &LuaCallExpr,
189156
) -> CountRange {
190157
let params = func.get_params();
191-
let self_offset = usize::from(needs_implicit_self_param(call_expr, func));
158+
// 如果以点调用但函数是冒号定义, 则表示需要传入 self 参数.
159+
let self_offset = usize::from(!call_expr.is_colon_call() && func.is_colon_define());
192160

193161
let mut min = self_offset;
194162
// 最小数量取最后一个非 nullable 形参, 因为前面的可选参数可以省略.
@@ -217,22 +185,6 @@ pub(super) fn get_param_count_range(
217185
CountRange { min, max }
218186
}
219187

220-
pub(super) fn adjusted_params(
221-
call_expr: &LuaCallExpr,
222-
func: &LuaFunctionType,
223-
) -> Vec<(String, Option<LuaType>)> {
224-
let mut params = func.get_params().to_vec();
225-
if needs_implicit_self_param(call_expr, func) {
226-
params.insert(0, ("self".to_string(), Some(LuaType::SelfInfer)));
227-
}
228-
229-
params
230-
}
231-
232-
fn needs_implicit_self_param(call_expr: &LuaCallExpr, func: &LuaFunctionType) -> bool {
233-
!call_expr.is_colon_call() && func.is_colon_define()
234-
}
235-
236188
pub(super) fn is_dots_expr(expr: &LuaExpr) -> bool {
237189
if let LuaExpr::LiteralExpr(literal_expr) = expr
238190
&& let Some(LuaLiteralToken::Dots(_)) = literal_expr.get_literal()

crates/emmylua_code_analysis/src/diagnostic/checker/param_check/mod.rs

Lines changed: 6 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -40,7 +40,12 @@ impl Checker for ParamCheckChecker {
4040
}
4141

4242
if check_param_type {
43-
type_mismatch::check_param_types(context, semantic_model, &facts);
43+
type_mismatch::check_param_types(
44+
context,
45+
semantic_model,
46+
&facts,
47+
check_param_count,
48+
);
4449
}
4550
}
4651
LuaAst::LuaClosureExpr(closure_expr) if check_param_count => {

0 commit comments

Comments
 (0)