Skip to content

Commit bbfa649

Browse files
authored
Merge pull request #315 from xuhuanzy/completion
some code
2 parents 63c42ea + ffdc938 commit bbfa649

36 files changed

+1592
-332
lines changed

crates/emmylua_code_analysis/src/compilation/analyzer/unresolve/resolve_closure.rs

Lines changed: 167 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,10 @@
1-
use emmylua_parser::{LuaAstNode, LuaExpr, LuaVarExpr};
1+
use emmylua_parser::{LuaAstNode, LuaTableExpr, LuaVarExpr};
22

33
use crate::{
4-
infer_call_expr_func, infer_expr, infer_table_field_value_should_be, DbIndex, InferFailReason,
5-
InferGuard, LuaDocParamInfo, LuaDocReturnInfo, LuaInferCache, LuaType, SignatureReturnStatus,
4+
infer_call_expr_func, infer_expr, infer_member_map, infer_table_should_be, DbIndex,
5+
InferFailReason, InferGuard, LuaDocParamInfo, LuaDocReturnInfo, LuaFunctionType, LuaInferCache,
6+
LuaMemberInfo, LuaSemanticDeclId, LuaSignatureId, LuaType, LuaTypeDeclId,
7+
SignatureReturnStatus,
68
};
79

810
use super::{
@@ -177,19 +179,28 @@ pub fn try_resolve_closure_parent_params(
177179
if !signature.param_docs.is_empty() {
178180
return Some(true);
179181
}
180-
182+
let self_type;
181183
let member_type = match &closure_params.parent_ast {
182184
UnResolveParentAst::LuaFuncStat(func_stat) => {
183185
let func_name = func_stat.get_func_name()?;
184186
match func_name {
185187
LuaVarExpr::IndexExpr(index_expr) => {
186-
infer_expr(db, cache, LuaExpr::IndexExpr(index_expr)).ok()?
188+
let typ = infer_expr(db, cache, index_expr.get_prefix_expr()?).ok()?;
189+
self_type = Some(typ.clone());
190+
191+
find_best_function_type(db, cache, &typ, &closure_params.signature_id)
187192
}
188-
LuaVarExpr::NameExpr(_) => return Some(true),
193+
_ => return Some(true),
189194
}
190195
}
191196
UnResolveParentAst::LuaTableField(table_field) => {
192-
infer_table_field_value_should_be(db, cache, table_field.clone()).ok()?
197+
let parnet_table_expr = table_field
198+
.get_parent::<LuaTableExpr>()
199+
.ok_or(InferFailReason::None)
200+
.ok()?;
201+
let typ = infer_table_should_be(db, cache, parnet_table_expr).ok()?;
202+
self_type = Some(typ.clone());
203+
find_best_function_type(db, cache, &typ, &closure_params.signature_id)
193204
}
194205
UnResolveParentAst::LuaAssignStat(assign) => {
195206
let (vars, exprs) = assign.get_var_and_expr_list();
@@ -198,20 +209,53 @@ pub fn try_resolve_closure_parent_params(
198209
.iter()
199210
.position(|expr| expr.get_position() == position)?;
200211
let var = vars.get(idx)?;
201-
202212
match var {
203213
LuaVarExpr::IndexExpr(index_expr) => {
204-
infer_expr(db, cache, LuaExpr::IndexExpr(index_expr.clone())).ok()?
214+
let typ = infer_expr(db, cache, index_expr.get_prefix_expr()?).ok()?;
215+
self_type = Some(typ.clone());
216+
find_best_function_type(db, cache, &typ, &closure_params.signature_id)
205217
}
206-
LuaVarExpr::NameExpr(_) => return Some(true),
218+
_ => return Some(true),
207219
}
208220
}
209221
};
210222

211-
let LuaType::DocFunction(doc_func) = member_type else {
223+
let Some(member_type) = member_type else {
212224
return Some(true);
213225
};
214226

227+
match &member_type {
228+
LuaType::DocFunction(doc_func) => {
229+
resolve_doc_function(db, closure_params, doc_func, self_type)
230+
}
231+
LuaType::Signature(id) => {
232+
if id == &closure_params.signature_id {
233+
return Some(true);
234+
}
235+
let signature = db.get_signature_index().get(id);
236+
237+
if let Some(signature) = signature {
238+
let fake_doc_function = LuaFunctionType::new(
239+
signature.is_async,
240+
signature.is_colon_define,
241+
signature.get_type_params(),
242+
signature.get_return_types(),
243+
);
244+
resolve_doc_function(db, closure_params, &fake_doc_function, self_type)
245+
} else {
246+
Some(true)
247+
}
248+
}
249+
_ => Some(true),
250+
}
251+
}
252+
253+
fn resolve_doc_function(
254+
db: &mut DbIndex,
255+
closure_params: &UnResolveParentClosureParams,
256+
doc_func: &LuaFunctionType,
257+
self_type: Option<LuaType>,
258+
) -> Option<bool> {
215259
let signature = db
216260
.get_signature_index_mut()
217261
.get_mut(&closure_params.signature_id)?;
@@ -220,17 +264,30 @@ pub fn try_resolve_closure_parent_params(
220264
signature.is_async = true;
221265
}
222266

223-
let colon_define = signature.is_colon_define;
224-
let mut params = doc_func.get_params();
225-
if colon_define {
226-
if params.len() > 1 {
227-
params = &params[1..];
228-
} else {
229-
params = &[];
267+
let mut doc_params = doc_func.get_params().to_vec();
268+
// doc_func 是往上追溯的有效签名, signature 是未解析的签名
269+
match (doc_func.is_colon_define(), signature.is_colon_define) {
270+
(true, true) | (false, false) => {}
271+
(true, false) => {
272+
// 原始签名是冒号定义, 但未解析的签名不是冒号定义, 即要插入第一个参数
273+
doc_params.insert(0, ("self".to_string(), Some(LuaType::SelfInfer)));
274+
}
275+
(false, true) => {
276+
// 原始签名不是冒号定义, 但未解析的签名是冒号定义, 即要删除第一个参数
277+
doc_params.remove(0);
278+
}
279+
}
280+
// 如果第一个参数是 self, 则需要将 self 的类型设置为 self_type
281+
if doc_params.get(0).map_or(false, |(_, typ)| match typ {
282+
Some(LuaType::SelfInfer) => true,
283+
_ => false,
284+
}) {
285+
if let Some(self_type) = self_type {
286+
doc_params[0].1 = Some(self_type);
230287
}
231288
}
232289

233-
for (index, param) in params.iter().enumerate() {
290+
for (index, param) in doc_params.iter().enumerate() {
234291
let name = signature.params.get(index).unwrap_or(&param.0);
235292
signature.param_docs.insert(
236293
index,
@@ -259,3 +316,94 @@ pub fn try_resolve_closure_parent_params(
259316

260317
Some(true)
261318
}
319+
320+
fn get_owner_type_id(db: &DbIndex, info: &LuaMemberInfo) -> Option<LuaTypeDeclId> {
321+
match &info.property_owner_id {
322+
Some(LuaSemanticDeclId::Member(member_id)) => {
323+
if let Some(owner) = db.get_member_index().get_current_owner(member_id) {
324+
return owner.get_type_id().cloned();
325+
}
326+
None
327+
}
328+
_ => None,
329+
}
330+
}
331+
332+
fn find_best_function_type(
333+
db: &DbIndex,
334+
cache: &mut LuaInferCache,
335+
prefix_type: &LuaType,
336+
signature_id: &LuaSignatureId,
337+
) -> Option<LuaType> {
338+
let member_info_map = infer_member_map(db, &prefix_type)?;
339+
let mut current_type_id = None;
340+
// 如果找不到证明是重定义
341+
let target_infos = member_info_map.into_values().find(|infos| {
342+
infos.iter().any(|info| match &info.typ {
343+
LuaType::Signature(id) => {
344+
if id == signature_id {
345+
current_type_id = get_owner_type_id(db, info);
346+
return true;
347+
}
348+
false
349+
}
350+
_ => false,
351+
})
352+
})?;
353+
// 找到第一个具有实际参数类型的签名
354+
target_infos.iter().find_map(|info| {
355+
// 所有者类型一致, 但我们找的是父类型
356+
if get_owner_type_id(db, info) == current_type_id {
357+
return None;
358+
}
359+
let function_type =
360+
get_final_function_type(db, cache, &info.typ).unwrap_or(info.typ.clone());
361+
let param_type_len = match &function_type {
362+
LuaType::Signature(id) => db
363+
.get_signature_index()
364+
.get(&id)
365+
.map(|sig| sig.param_docs.len())
366+
.unwrap_or(0),
367+
LuaType::DocFunction(doc_func) => doc_func
368+
.get_params()
369+
.iter()
370+
.filter(|(_, typ)| typ.is_some())
371+
.count(),
372+
_ => 0, // 跳过其他类型
373+
};
374+
if param_type_len > 0 {
375+
return Some(function_type.clone());
376+
}
377+
None
378+
})
379+
}
380+
381+
fn get_final_function_type(
382+
db: &DbIndex,
383+
cache: &mut LuaInferCache,
384+
origin: &LuaType,
385+
) -> Option<LuaType> {
386+
match origin {
387+
LuaType::Signature(_) => Some(origin.clone()),
388+
LuaType::DocFunction(_) => Some(origin.clone()),
389+
LuaType::Ref(decl_id) => {
390+
let decl = db.get_type_index().get_type_decl(decl_id)?;
391+
if decl.is_alias() {
392+
let origin_type = decl.get_alias_origin(db, None)?;
393+
get_final_function_type(db, cache, &origin_type)
394+
} else {
395+
Some(origin.clone())
396+
}
397+
}
398+
LuaType::Union(union_types) => {
399+
for typ in union_types.get_types() {
400+
let final_type = get_final_function_type(db, cache, typ);
401+
if final_type.is_some() {
402+
return final_type;
403+
}
404+
}
405+
None
406+
}
407+
_ => None,
408+
}
409+
}

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -72,6 +72,6 @@ mod test {
7272

7373
let c = ws.expr_ty("c");
7474
let c_desc = ws.humanize_type(c);
75-
assert_eq!(c_desc, "(string|nil)");
75+
assert_eq!(c_desc, "string?");
7676
}
7777
}

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

Lines changed: 136 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -51,4 +51,140 @@ mod test {
5151
let expected = ws.ty("Outfit_t");
5252
assert_eq!(ty, expected);
5353
}
54+
55+
#[test]
56+
fn test_table_field_function_param() {
57+
let mut ws = VirtualWorkspace::new();
58+
ws.def(
59+
r#"
60+
---@alias ProxyHandler.Getter fun(self: self, raw: any, key: any, receiver: table): any
61+
62+
---@class ProxyHandler
63+
---@field get ProxyHandler.Getter
64+
"#,
65+
);
66+
67+
ws.def(
68+
r#"
69+
70+
---@class A: ProxyHandler
71+
local A
72+
73+
function A:get(target, key, receiver, name)
74+
a = self
75+
end
76+
"#,
77+
);
78+
let ty = ws.expr_ty("a");
79+
let expected = ws.ty("A");
80+
assert_eq!(ws.humanize_type(ty), ws.humanize_type(expected));
81+
82+
ws.def(
83+
r#"
84+
85+
---@class B: ProxyHandler
86+
local B
87+
88+
B.get = function(self, target, key, receiver, name)
89+
b = self
90+
end
91+
"#,
92+
);
93+
let ty = ws.expr_ty("b");
94+
let expected = ws.ty("B");
95+
assert_eq!(ws.humanize_type(ty), ws.humanize_type(expected));
96+
97+
ws.def(
98+
r#"
99+
---@class C: ProxyHandler
100+
local C = {
101+
get = function(self, target, key, receiver, name)
102+
c = self
103+
end,
104+
}
105+
"#,
106+
);
107+
let ty = ws.expr_ty("c");
108+
let expected = ws.ty("C");
109+
assert_eq!(ws.humanize_type(ty), ws.humanize_type(expected));
110+
}
111+
112+
#[test]
113+
fn test_table_field_function_param_2() {
114+
let mut ws = VirtualWorkspace::new();
115+
116+
ws.def(
117+
r#"
118+
---@class ProxyHandler
119+
local P
120+
121+
---@param raw any
122+
---@param key any
123+
---@param receiver table
124+
---@return any
125+
function P:get(raw, key, receiver) end
126+
"#,
127+
);
128+
129+
ws.def(
130+
r#"
131+
---@class A: ProxyHandler
132+
local A
133+
134+
function A:get(raw, key, receiver)
135+
a = receiver
136+
end
137+
"#,
138+
);
139+
let ty = ws.expr_ty("a");
140+
let expected = ws.ty("table");
141+
assert_eq!(ws.humanize_type(ty), ws.humanize_type(expected));
142+
}
143+
144+
#[test]
145+
fn test_table_field_function_param_3() {
146+
let mut ws = VirtualWorkspace::new();
147+
148+
ws.def(
149+
r#"
150+
---@class SimpleClass.Meta
151+
---@field __defineSet fun(self: self, key: string, f: fun(self: self, value: any))
152+
153+
---@class Dep: SimpleClass.Meta
154+
local Dep
155+
Dep:__defineSet('subs', function(self, value)
156+
a = self
157+
end)
158+
"#,
159+
);
160+
let ty = ws.expr_ty("a");
161+
let expected = ws.ty("Dep");
162+
assert_eq!(ws.humanize_type(ty), ws.humanize_type(expected));
163+
}
164+
165+
#[test]
166+
fn test_table_field_function_param_4() {
167+
let mut ws = VirtualWorkspace::new();
168+
ws.def(r#"
169+
---@alias ProxyHandler.Getter fun(self: self, raw: any, key: any, receiver: table): any
170+
171+
---@class ProxyHandler
172+
---@field get? ProxyHandler.Getter
173+
"#
174+
);
175+
176+
ws.def(
177+
r#"
178+
---@class ShallowUnwrapHandlers: ProxyHandler
179+
local ShallowUnwrapHandlers = {
180+
get = function(self, target, key, receiver)
181+
a = self
182+
end,
183+
}
184+
"#,
185+
);
186+
let ty = ws.expr_ty("a");
187+
let expected = ws.ty("ShallowUnwrapHandlers");
188+
assert_eq!(ws.humanize_type(ty), ws.humanize_type(expected));
189+
}
54190
}

0 commit comments

Comments
 (0)