Skip to content

Commit eebd3d8

Browse files
authored
Merge pull request #361 from xuhuanzy/completion
fix
2 parents 9413d94 + 57e3ed0 commit eebd3d8

File tree

29 files changed

+894
-100
lines changed

29 files changed

+894
-100
lines changed

Cargo.toml

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ glob = "0.3"
4747
include_dir = "0.7.4"
4848
toml_edit = "0.22.23"
4949
itertools = "0.11.0"
50-
ariadne = { version = "0.5.0", features = ["auto-color"] }
50+
ariadne = { version = "0.5.0", features = ["auto-color"] }

crates/emmylua_code_analysis/src/compilation/analyzer/lua/stats.rs

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,7 +26,7 @@ pub fn analyze_local_stat(analyzer: &mut LuaAnalyzer, local_stat: LuaLocalStat)
2626
analyzer
2727
.db
2828
.get_type_index_mut()
29-
.bind_type(decl_id.into(), LuaTypeCache::InferType(LuaType::Nil));
29+
.bind_type(decl_id.into(), LuaTypeCache::InferType(LuaType::Unknown));
3030
}
3131

3232
return Some(());

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

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -138,7 +138,7 @@ pub fn try_resolve_table_field(
138138
LuaType::IntegerConst(i) => LuaMemberKey::Integer(i),
139139
_ => {
140140
if field_type.is_table() {
141-
LuaMemberKey::SyntaxId(field_expr.get_syntax_id())
141+
LuaMemberKey::Expr(field_type)
142142
} else {
143143
return None;
144144
}

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

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -449,6 +449,22 @@ end
449449
assert_eq!(c, c_expected);
450450
}
451451

452+
#[test]
453+
fn test_unknown_type() {
454+
let mut ws = VirtualWorkspace::new();
455+
456+
ws.def(
457+
r#"
458+
local a
459+
b = a
460+
"#,
461+
);
462+
463+
let b = ws.expr_ty("b");
464+
let b_expected = ws.ty("unknown");
465+
assert_eq!(b, b_expected);
466+
}
467+
452468
#[test]
453469
fn test_issue_367() {
454470
let mut ws = VirtualWorkspace::new();

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

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,7 @@ mod test {
4747
"#,
4848
);
4949
let left = ws.expr_ty("d");
50-
let right = ws.expr_ty("nil");
51-
assert_eq!(left, right);
50+
assert_eq!(ws.humanize_type(left), "1?");
5251
}
5352

5453
#[test]

crates/emmylua_code_analysis/src/db_index/member/lua_member.rs

Lines changed: 6 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@ use serde::{Deserialize, Serialize};
44
use smol_str::SmolStr;
55

66
use super::lua_member_feature::LuaMemberFeature;
7-
use crate::{FileId, GlobalId};
7+
use crate::{FileId, GlobalId, LuaType};
88

99
#[derive(Debug)]
1010
pub struct LuaMember {
@@ -93,7 +93,7 @@ pub enum LuaMemberKey {
9393
None,
9494
Integer(i64),
9595
Name(SmolStr),
96-
SyntaxId(LuaSyntaxId),
96+
Expr(LuaType),
9797
}
9898

9999
impl LuaMemberKey {
@@ -109,8 +109,8 @@ impl LuaMemberKey {
109109
matches!(self, LuaMemberKey::Integer(_))
110110
}
111111

112-
pub fn is_syntax_id(&self) -> bool {
113-
matches!(self, LuaMemberKey::SyntaxId(_))
112+
pub fn is_expr(&self) -> bool {
113+
matches!(self, LuaMemberKey::Expr(_))
114114
}
115115

116116
pub fn get_name(&self) -> Option<&str> {
@@ -134,7 +134,7 @@ impl LuaMemberKey {
134134
format!("[{}]", i)
135135
}
136136
LuaMemberKey::None => "".to_string(),
137-
LuaMemberKey::SyntaxId(_) => "".to_string(),
137+
LuaMemberKey::Expr(_) => "".to_string(),
138138
}
139139
}
140140
}
@@ -158,7 +158,7 @@ impl Ord for LuaMemberKey {
158158
(Name(a), Name(b)) => a.cmp(b),
159159
(Name(_), _) => std::cmp::Ordering::Less,
160160
(_, Name(_)) => std::cmp::Ordering::Greater,
161-
(SyntaxId(_), SyntaxId(_)) => std::cmp::Ordering::Equal,
161+
(Expr(_), Expr(_)) => std::cmp::Ordering::Equal,
162162
}
163163
}
164164
}

crates/emmylua_code_analysis/src/db_index/type/humanize_type.rs

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -362,7 +362,7 @@ fn humanize_object_type(db: &DbIndex, object: &LuaObjectType, level: RenderLevel
362362
LuaMemberKey::Integer(i) => format!("[{}]: {}", i, ty_str),
363363
LuaMemberKey::Name(s) => format!("{}: {}", s, ty_str),
364364
LuaMemberKey::None => ty_str,
365-
LuaMemberKey::SyntaxId(_) => ty_str,
365+
LuaMemberKey::Expr(_) => ty_str,
366366
}
367367
})
368368
.collect::<Vec<_>>()
@@ -682,6 +682,6 @@ fn build_table_member_string(
682682
LuaMemberKey::Name(name) => format!("{name}{separator}{member_value}"),
683683
LuaMemberKey::Integer(i) => format!("[{i}]{separator}{member_value}"),
684684
LuaMemberKey::None => member_value,
685-
LuaMemberKey::SyntaxId(_) => member_value,
685+
LuaMemberKey::Expr(_) => member_value,
686686
}
687687
}

crates/emmylua_code_analysis/src/db_index/type/type_decl.rs

Lines changed: 0 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -174,7 +174,6 @@ pub struct LuaTypeDeclId {
174174
}
175175

176176
impl LuaTypeDeclId {
177-
#[allow(unused)]
178177
pub fn new_by_id(id: ArcIntern<SmolStr>) -> Self {
179178
Self { id }
180179
}

crates/emmylua_code_analysis/src/diagnostic/checker/check_field.rs

Lines changed: 80 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,6 @@
11
use std::collections::HashSet;
22

3-
use emmylua_parser::{LuaAst, LuaAstNode, LuaExpr, LuaIndexExpr, LuaIndexKey, LuaVarExpr};
4-
use internment::ArcIntern;
3+
use emmylua_parser::{LuaAst, LuaAstNode, LuaIndexExpr, LuaIndexKey, LuaVarExpr};
54

65
use crate::{DiagnosticCode, InferFailReason, LuaMemberKey, LuaType, SemanticModel};
76

@@ -65,7 +64,7 @@ fn check_index_expr(
6564

6665
let index_key = index_expr.get_index_key()?;
6766

68-
if is_valid_member(semantic_model, &prefix_typ, index_expr, &index_key).is_some() {
67+
if is_valid_member(semantic_model, &prefix_typ, index_expr, &index_key, code).is_some() {
6968
return Some(());
7069
}
7170

@@ -129,6 +128,7 @@ fn is_valid_member(
129128
prefix_typ: &LuaType,
130129
index_expr: &LuaIndexExpr,
131130
index_key: &LuaIndexKey,
131+
code: DiagnosticCode,
132132
) -> Option<()> {
133133
// 检查 member_info
134134
let need_add_diagnostic =
@@ -141,9 +141,19 @@ fn is_valid_member(
141141
return Some(());
142142
}
143143

144-
// 获取并验证 key_type
145-
let key_type = match index_key {
146-
LuaIndexKey::Expr(expr) => match semantic_model.infer_expr(expr.clone()) {
144+
match prefix_typ {
145+
LuaType::Global => return Some(()),
146+
LuaType::Userdata => return Some(()),
147+
LuaType::Array(typ) => {
148+
if typ.is_unknown() {
149+
return Some(());
150+
}
151+
}
152+
_ => {}
153+
}
154+
155+
let key_type = if let LuaIndexKey::Expr(expr) = index_key {
156+
match semantic_model.infer_expr(expr.clone()) {
147157
Ok(
148158
LuaType::Any
149159
| LuaType::Unknown
@@ -161,47 +171,83 @@ fn is_valid_member(
161171
Err(_) => {
162172
return None;
163173
}
164-
},
165-
LuaIndexKey::String(name) => LuaType::StringConst(ArcIntern::new(name.get_value().into())),
166-
LuaIndexKey::Integer(i) => LuaType::IntegerConst(i.get_int_value()),
167-
LuaIndexKey::Name(name) => {
168-
LuaType::StringConst(ArcIntern::new(name.get_name_text().into()))
169174
}
170-
LuaIndexKey::Idx(i) => LuaType::IntegerConst(i.clone() as i64),
175+
} else {
176+
return None;
171177
};
172178

173179
// 允许特定类型组合通过
174180
match (prefix_typ, &key_type) {
175181
(LuaType::Tuple(_), LuaType::Integer | LuaType::IntegerConst(_)) => return Some(()),
182+
(LuaType::Def(id), _) => {
183+
if let Some(decl) = semantic_model.get_db().get_type_index().get_type_decl(id) {
184+
if decl.is_class() {
185+
if code == DiagnosticCode::InjectField {
186+
return Some(());
187+
}
188+
if index_key.is_string() || matches!(key_type, LuaType::String) {
189+
return Some(());
190+
}
191+
}
192+
}
193+
}
176194
_ => {}
177195
}
178196

179-
// 解决`key`类型为联合名称时的报错(通常是`pairs`返回的`key`)
180-
let (key_name_set, key_type_set) = get_key_types(&key_type);
181-
if key_name_set.is_empty() && key_type_set.is_empty() {
197+
/*
198+
允许这种写法
199+
---@type string?
200+
local field
201+
local a = Class[field]
202+
*/
203+
let key_type_set = get_key_types(&key_type);
204+
if key_type_set.is_empty() {
182205
return None;
183206
}
207+
184208
let prefix_types = get_prefix_types(prefix_typ);
185209
for prefix_type in prefix_types {
186210
if let Some(members) = semantic_model.infer_member_infos(&prefix_type) {
187-
for info in members {
211+
for info in &members {
188212
match &info.key {
189-
LuaMemberKey::SyntaxId(syntax_id) => {
190-
let node =
191-
syntax_id.to_node_from_root(semantic_model.get_root().syntax())?;
192-
let expr = LuaExpr::cast(node)?;
193-
if let Ok(typ) = semantic_model.infer_expr(expr) {
194-
if key_type_set.contains(&typ) {
213+
LuaMemberKey::Expr(typ) => {
214+
if typ.is_string() {
215+
if key_type_set.iter().any(|typ| typ.is_string()) {
216+
return Some(());
217+
}
218+
} else if typ.is_integer() {
219+
if key_type_set.iter().any(|typ| typ.is_integer()) {
195220
return Some(());
196221
}
197222
}
198223
}
199-
_ => {
200-
let key_name = info.key.to_path();
201-
if key_name_set.contains(&key_name) {
224+
LuaMemberKey::Name(_) => {
225+
if key_type_set.iter().any(|typ| typ.is_string()) {
202226
return Some(());
203227
}
204228
}
229+
LuaMemberKey::Integer(_) => {
230+
if key_type_set.iter().any(|typ| typ.is_integer()) {
231+
return Some(());
232+
}
233+
}
234+
_ => {}
235+
}
236+
}
237+
if members.is_empty() {
238+
// 当没有任何成员信息且是 enum 类型时, 需要检查参数是否为自己
239+
if let LuaType::Ref(id) | LuaType::Def(id) = prefix_type {
240+
if let Some(decl) = semantic_model.get_db().get_type_index().get_type_decl(&id)
241+
{
242+
if decl.is_enum() {
243+
if key_type_set.iter().any(|typ| match typ {
244+
LuaType::Ref(key_id) | LuaType::Def(key_id) => id == *key_id,
245+
_ => false,
246+
}) {
247+
return Some(());
248+
}
249+
}
250+
}
205251
}
206252
}
207253
}
@@ -230,31 +276,28 @@ fn get_prefix_types(prefix_typ: &LuaType) -> HashSet<LuaType> {
230276
type_set
231277
}
232278

233-
fn get_key_types(typ: &LuaType) -> (HashSet<String>, HashSet<LuaType>) {
279+
fn get_key_types(typ: &LuaType) -> HashSet<LuaType> {
234280
let mut type_set = HashSet::new();
235-
let mut name_set = HashSet::new();
236281
let mut stack = vec![typ.clone()];
237282

238283
while let Some(current_type) = stack.pop() {
239-
// `DocStringConst`与`DocIntegerConst`用于处理`---@type 'a'|'b'`这种联合类型
240284
match &current_type {
241-
LuaType::StringConst(name) | LuaType::DocStringConst(name) => {
242-
name_set.insert(name.as_ref().to_string());
285+
LuaType::String => {
286+
type_set.insert(current_type);
243287
}
244-
LuaType::IntegerConst(i) | LuaType::DocIntegerConst(i) => {
245-
name_set.insert(format!("[{}]", i));
288+
LuaType::Integer => {
289+
type_set.insert(current_type);
246290
}
247291
LuaType::Union(union_typ) => {
248292
for t in union_typ.get_types() {
249293
stack.push(t.clone());
250294
}
251295
}
252-
_ => {
253-
if current_type.is_table() {
254-
type_set.insert(current_type);
255-
}
296+
LuaType::Ref(_) => {
297+
type_set.insert(current_type);
256298
}
299+
_ => {}
257300
}
258301
}
259-
(name_set, type_set)
302+
type_set
260303
}

crates/emmylua_code_analysis/src/diagnostic/checker/return_type_mismatch.rs

Lines changed: 34 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,6 @@
1-
use emmylua_parser::{LuaAstNode, LuaClosureExpr, LuaExpr, LuaReturnStat, LuaSyntaxKind};
1+
use emmylua_parser::{
2+
LuaAstNode, LuaClosureExpr, LuaExpr, LuaFuncStat, LuaReturnStat, LuaSyntaxKind, LuaVarExpr,
3+
};
24
use rowan::{NodeOrToken, TextRange};
35

46
use crate::{
@@ -32,15 +34,23 @@ fn check_closure_expr(
3234
return None;
3335
}
3436
let return_types = signature.get_return_types();
37+
let self_type = get_self_type(semantic_model, closure_expr);
3538
for return_stat in get_own_return_stats(closure_expr) {
36-
check_return_stat(context, semantic_model, &return_types, &return_stat);
39+
check_return_stat(
40+
context,
41+
semantic_model,
42+
&self_type,
43+
&return_types,
44+
&return_stat,
45+
);
3746
}
3847
Some(())
3948
}
4049

4150
fn check_return_stat(
4251
context: &mut DiagnosticContext,
4352
semantic_model: &SemanticModel,
53+
self_type: &Option<LuaType>,
4454
return_types: &[LuaType],
4555
return_stat: &LuaReturnStat,
4656
) -> Option<()> {
@@ -79,7 +89,14 @@ fn check_return_stat(
7989
};
8090

8191
let return_expr_type = return_expr_types.get(index).unwrap_or(&LuaType::Any);
82-
let result = semantic_model.type_check(return_type, return_expr_type);
92+
let mut check_type = return_type;
93+
if return_type.is_self_infer() {
94+
if let Some(self_type) = self_type {
95+
check_type = self_type;
96+
}
97+
}
98+
99+
let result = semantic_model.type_check(check_type, return_expr_type);
83100
if !result.is_ok() {
84101
add_type_check_diagnostic(
85102
context,
@@ -213,3 +230,17 @@ fn has_setmetatable(semantic_model: &SemanticModel, return_stat: &LuaReturnStat)
213230
}
214231
None
215232
}
233+
234+
/// 获取 self 实际类型
235+
fn get_self_type(semantic_model: &SemanticModel, closure_expr: &LuaClosureExpr) -> Option<LuaType> {
236+
let parent = closure_expr.syntax().parent()?;
237+
let func_stat = LuaFuncStat::cast(parent)?;
238+
let func_name = func_stat.get_func_name()?;
239+
match func_name {
240+
LuaVarExpr::IndexExpr(index_expr) => {
241+
let prefix_expr = index_expr.get_prefix_expr()?;
242+
semantic_model.infer_expr(prefix_expr).ok()
243+
}
244+
_ => None,
245+
}
246+
}

0 commit comments

Comments
 (0)