Skip to content

Commit 1b588b7

Browse files
committed
perf: call completion
1 parent 098fb12 commit 1b588b7

1 file changed

Lines changed: 53 additions & 225 deletions

File tree

crates/emmylua_ls/src/handlers/completion/providers/function_provider.rs

Lines changed: 53 additions & 225 deletions
Original file line numberDiff line numberDiff line change
@@ -1,9 +1,8 @@
11
use emmylua_code_analysis::{
22
DbIndex, GenericTpl, InferGuard, InferGuardRef, LuaAliasCallKind, LuaAliasCallType,
3-
LuaDeclLocation, LuaFunctionType, LuaMember, LuaMemberKey, LuaMemberOwner, LuaMultiLineUnion,
4-
LuaSemanticDeclId, LuaStringTplType, LuaType, LuaTypeCache, LuaTypeDeclId, LuaUnionType,
5-
RenderLevel, SemanticDeclLevel, TypeSubstitutor, build_call_constraint_context, get_real_type,
6-
instantiate_type_generic, normalize_constraint_type,
3+
LuaDeclLocation, LuaFunctionType, LuaMemberKey, LuaMemberOwner, LuaMultiLineUnion,
4+
LuaStringTplType, LuaType, LuaTypeCache, LuaTypeDeclId, LuaUnionType, RenderLevel,
5+
filter_callable_overloads, get_real_type, normalize_constraint_type,
76
};
87
use emmylua_parser::{
98
LuaAssignStat, LuaAst, LuaAstNode, LuaAstToken, LuaCallArgList, LuaCallExpr, LuaClosureExpr,
@@ -12,7 +11,6 @@ use emmylua_parser::{
1211
};
1312
use itertools::Itertools;
1413
use lsp_types::{CompletionItem, Documentation};
15-
use std::sync::Arc;
1614

1715
use crate::handlers::{
1816
completion::{
@@ -325,236 +323,66 @@ fn infer_call_arg_list(
325323
token: LuaSyntaxToken,
326324
) -> Option<Vec<LuaType>> {
327325
let call_expr = call_arg_list.get_parent::<LuaCallExpr>()?;
328-
let mut param_idx = get_current_param_index(&call_expr, &token)?;
329-
let call_expr_func = builder
330-
.semantic_model
331-
.infer_call_expr_func(call_expr.clone(), Some(param_idx + 1))?;
332-
let colon_call = call_expr.is_colon_call();
333-
let colon_define = call_expr_func.is_colon_define();
334-
match (colon_call, colon_define) {
335-
(true, true) | (false, false) | (false, true) => {}
336-
(true, false) => {
337-
param_idx += 1;
338-
}
339-
}
340-
let constraint_substitutor = build_call_constraint_context(&builder.semantic_model, &call_expr)
341-
.map(|ctx| ctx.substitutor);
342-
let substitutor = constraint_substitutor.as_ref();
343-
let typ = call_expr_func
344-
.get_params()
345-
.get(param_idx)?
346-
.1
347-
.clone()
348-
.unwrap_or(LuaType::Unknown);
349-
let typ = resolve_param_type(builder, typ, substitutor);
350-
let mut types = Vec::new();
351-
types.push(typ);
352-
push_function_overloads_param(
353-
builder,
354-
&call_expr,
355-
call_expr_func.get_params(),
356-
param_idx,
357-
substitutor,
358-
&mut types,
359-
);
360-
Some(types.into_iter().unique().collect()) // 需要去重
361-
}
362-
363-
fn resolve_param_type(
364-
builder: &CompletionBuilder,
365-
mut typ: LuaType,
366-
substitutor: Option<&TypeSubstitutor>,
367-
) -> LuaType {
368-
let db = builder.semantic_model.get_db();
369-
if let Some(substitutor) = substitutor {
370-
typ = apply_substitutor_to_type(db, typ, substitutor);
371-
}
372-
normalize_constraint_type(db, typ)
373-
}
374-
375-
fn apply_substitutor_to_type(db: &DbIndex, typ: LuaType, substitutor: &TypeSubstitutor) -> LuaType {
376-
if let LuaType::Call(alias_call) = &typ {
377-
if alias_call.get_call_kind() == LuaAliasCallKind::KeyOf {
378-
let operands = alias_call
379-
.get_operands()
380-
.iter()
381-
.map(|operand| instantiate_type_generic(db, operand, substitutor))
382-
.collect::<Vec<_>>();
383-
return LuaType::Call(Arc::new(LuaAliasCallType::new(
384-
alias_call.get_call_kind(),
385-
operands,
386-
)));
387-
}
388-
}
389-
if let Some(alias_call) = rebuild_keyof_alias_call(db, &typ, substitutor) {
390-
return alias_call;
391-
}
392-
instantiate_type_generic(db, &typ, substitutor)
393-
}
394-
395-
fn rebuild_keyof_alias_call(
396-
db: &DbIndex,
397-
original_type: &LuaType,
398-
substitutor: &TypeSubstitutor,
399-
) -> Option<LuaType> {
400-
let tpl = match original_type {
401-
LuaType::TplRef(tpl) => tpl,
402-
_ => return None,
403-
};
404-
let constraint = tpl.get_constraint()?;
405-
let LuaType::Call(alias_call) = constraint else {
406-
return None;
407-
};
408-
if alias_call.get_call_kind() != LuaAliasCallKind::KeyOf {
409-
return None;
410-
}
411-
412-
let operands = alias_call
413-
.get_operands()
414-
.iter()
415-
.map(|operand| instantiate_type_generic(db, operand, substitutor))
416-
.collect::<Vec<_>>();
417-
Some(LuaType::Call(Arc::new(LuaAliasCallType::new(
418-
alias_call.get_call_kind(),
419-
operands,
420-
))))
421-
}
422-
423-
fn push_function_overloads_param(
424-
builder: &mut CompletionBuilder,
425-
call_expr: &LuaCallExpr,
426-
call_params: &[(String, Option<LuaType>)],
427-
param_idx: usize,
428-
substitutor: Option<&TypeSubstitutor>,
429-
types: &mut Vec<LuaType>,
430-
) -> Option<()> {
431-
let member_index = builder.semantic_model.get_db().get_member_index();
326+
let param_idx = get_current_param_index(&call_expr, &token)?;
432327
let prefix_expr = call_expr.get_prefix_expr()?;
433-
let semantic_decl = builder.semantic_model.find_decl(
434-
prefix_expr.syntax().clone().into(),
435-
SemanticDeclLevel::default(),
436-
)?;
437-
438-
// 收集函数类型
439-
let functions = match semantic_decl {
440-
LuaSemanticDeclId::Member(member_id) => {
441-
let member = member_index.get_member(&member_id)?;
442-
let key = member.get_key().to_path();
443-
let owner = member_index.get_current_owner(&member_id)?;
444-
let members = member_index.get_members(owner)?;
445-
let functions = filter_function_members(builder.semantic_model.get_db(), members, key);
446-
Some(functions)
447-
}
448-
LuaSemanticDeclId::LuaDecl(decl_id) => {
449-
let decl = builder
450-
.semantic_model
451-
.get_db()
452-
.get_decl_index()
453-
.get_decl(&decl_id)?;
328+
let prefix_type = builder.semantic_model.infer_expr(prefix_expr).ok()?;
329+
let call_arg_types = infer_call_arg_types(builder, &call_expr, Some(param_idx))?;
330+
let call_expr_funcs = filter_callable_overloads(
331+
builder.semantic_model.get_db(),
332+
&mut builder.semantic_model.get_cache().borrow_mut(),
333+
&prefix_type,
334+
&call_arg_types,
335+
&call_expr,
336+
Some(param_idx),
337+
true,
338+
)
339+
.ok()?;
454340

455-
let typ = builder
456-
.semantic_model
457-
.get_db()
458-
.get_type_index()
459-
.get_type_cache(&decl_id.into())
460-
.map(|cache| cache.as_type().clone())
461-
.unwrap_or(LuaType::Unknown);
462-
match typ {
463-
LuaType::Signature(_) | LuaType::DocFunction(_) => Some(vec![typ.clone()]),
464-
_ => {
465-
let key = decl.get_name();
466-
let type_id = LuaTypeDeclId::global(decl.get_name());
467-
let members = member_index.get_members(&LuaMemberOwner::Type(type_id))?;
468-
let functions = filter_function_members(
469-
builder.semantic_model.get_db(),
470-
members,
471-
key.to_string(),
472-
);
473-
Some(functions)
474-
}
475-
}
476-
}
477-
_ => None,
478-
}?;
479-
480-
// 获取重载函数列表
481-
let signature_index = builder.semantic_model.get_db().get_signature_index();
482-
let mut overloads = Vec::new();
483-
for function in functions {
484-
match function {
485-
LuaType::Signature(signature_id) => {
486-
if let Some(signature) = signature_index.get(&signature_id) {
487-
overloads.extend(signature.overloads.iter().cloned());
488-
}
489-
}
490-
LuaType::DocFunction(doc_function) => {
491-
overloads.push(doc_function);
341+
let mut types = Vec::new();
342+
for call_expr_func in call_expr_funcs {
343+
let mut param_idx = param_idx;
344+
let colon_call = call_expr.is_colon_call();
345+
let colon_define = call_expr_func.is_colon_define();
346+
match (colon_call, colon_define) {
347+
(true, true) | (false, false) | (false, true) => {}
348+
(true, false) => {
349+
param_idx += 1;
492350
}
493-
_ => {}
494351
}
495-
}
496-
497-
// 筛选匹配的参数类型并添加到结果中
498-
for overload in overloads.iter() {
499-
let overload_params = overload.get_params();
500-
501-
// 检查前面的参数是否匹配
502-
if !params_match_prefix(call_params, overload_params, param_idx) {
503-
continue;
504-
}
505-
506-
// 添加匹配的参数类型
507-
if let Some(param_type) = overload_params.get(param_idx).and_then(|p| p.1.clone()) {
508-
let param_type = resolve_param_type(builder, param_type, substitutor);
509-
types.push(param_type);
510-
}
511-
}
512352

513-
/// 过滤出函数类型的成员
514-
fn filter_function_members(
515-
db: &DbIndex,
516-
members: Vec<&LuaMember>,
517-
key: String,
518-
) -> Vec<LuaType> {
519-
let mut result_members = vec![];
520-
for member in members {
521-
if member.get_key().to_path() == key {
522-
let member_type = db
523-
.get_type_index()
524-
.get_type_cache(&member.get_id().into())
525-
.unwrap_or(&LuaTypeCache::InferType(LuaType::Unknown));
526-
if let LuaType::Signature(_) | LuaType::DocFunction(_) = member_type.as_type() {
527-
result_members.push(member_type.as_type().clone());
528-
}
529-
}
353+
if let Some(typ) = call_expr_func
354+
.get_params()
355+
.get(param_idx)
356+
.and_then(|param| param.1.clone())
357+
{
358+
types.push(normalize_constraint_type(
359+
builder.semantic_model.get_db(),
360+
typ,
361+
));
530362
}
531-
532-
result_members
533363
}
534364

535-
/// 判断前面的参数是否匹配
536-
fn params_match_prefix(
537-
call_params: &[(String, Option<LuaType>)],
538-
overload_params: &[(String, Option<LuaType>)],
539-
param_idx: usize,
540-
) -> bool {
541-
if param_idx == 0 {
542-
return true;
543-
}
544-
545-
for i in 0..param_idx {
546-
if let (Some(call_param), Some(overload_param)) =
547-
(call_params.get(i), overload_params.get(i))
548-
&& call_param.1 != overload_param.1
549-
{
550-
return false;
551-
}
552-
}
553-
554-
true
365+
if types.is_empty() {
366+
None
367+
} else {
368+
Some(types.into_iter().unique().collect())
555369
}
370+
}
556371

557-
Some(())
372+
fn infer_call_arg_types(
373+
builder: &CompletionBuilder,
374+
call_expr: &LuaCallExpr,
375+
arg_count: Option<usize>,
376+
) -> Option<Vec<LuaType>> {
377+
let args = call_expr.get_args_list()?.get_args().collect::<Vec<_>>();
378+
Some(
379+
builder
380+
.semantic_model
381+
.infer_expr_list_types(&args, arg_count)
382+
.into_iter()
383+
.map(|(typ, _)| typ)
384+
.collect(),
385+
)
558386
}
559387

560388
fn add_multi_line_union_member_completion(

0 commit comments

Comments
 (0)