Skip to content

Commit 2dc2404

Browse files
committed
refactor complex type check, fix tuple check,
Fix #231
1 parent fc4aba9 commit 2dc2404

15 files changed

Lines changed: 911 additions & 690 deletions

File tree

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -16,3 +16,4 @@ mod overload_field;
1616
mod overload_test;
1717
mod static_cal_cmp;
1818
mod syntax_error_test;
19+
mod tuple_test;
Lines changed: 17 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,17 @@
1+
#[cfg(test)]
2+
mod tests {
3+
use crate::{DiagnosticCode, VirtualWorkspace};
4+
5+
#[test]
6+
fn test_issue_231() {
7+
let mut ws = VirtualWorkspace::new_with_init_std_lib();
8+
assert!(ws.check_code_for(
9+
DiagnosticCode::AssignTypeMismatch,
10+
r#"
11+
12+
--- @type [boolean, string]
13+
local ret = { coroutine.resume(coroutine.create(function () end), ...) }
14+
"#
15+
));
16+
}
17+
}

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -266,6 +266,7 @@ impl LuaType {
266266
match self {
267267
LuaType::Nil | LuaType::Any | LuaType::Unknown => true,
268268
LuaType::Union(u) => u.types.iter().any(|t| t.is_optional()),
269+
LuaType::Variadic(_) => true,
269270
_ => false,
270271
}
271272
}

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

Lines changed: 4 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -167,6 +167,10 @@ fn handle_value_is_table_expr(
167167
let member_infos = semantic_model.infer_member_infos(&table_type)?;
168168
let fields = LuaTableExpr::cast(value_expr.syntax().clone())?.get_fields();
169169
for field in fields {
170+
if field.is_value_field() {
171+
continue;
172+
}
173+
170174
let field_key = field.get_field_key();
171175
if let Some(field_key) = field_key {
172176
let field_path_part = field_key.get_path_part();

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

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -141,7 +141,9 @@ fn add_type_check_diagnostic(
141141
Err(reason) => {
142142
let reason_message = match reason {
143143
TypeCheckFailReason::TypeNotMatchWithReason(reason) => reason,
144-
TypeCheckFailReason::TypeNotMatch => "".to_string(),
144+
TypeCheckFailReason::TypeNotMatch | TypeCheckFailReason::DonotCheck => {
145+
"".to_string()
146+
}
145147
TypeCheckFailReason::TypeRecursion => "type recursion".to_string(),
146148
};
147149
context.add_diagnostic(

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

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -177,6 +177,7 @@ fn add_type_check_diagnostic(
177177
None,
178178
);
179179
}
180+
TypeCheckFailReason::DonotCheck => {}
180181
},
181182
}
182183
}

crates/emmylua_code_analysis/src/semantic/infer/infer_call.rs

Lines changed: 10 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -359,7 +359,7 @@ fn unwrapp_return_type(
359359
}
360360

361361
LuaType::MuliReturn(multi) => {
362-
if is_last_expr(&call_expr) {
362+
if is_last_call_expr(&call_expr) {
363363
return Ok(return_type);
364364
}
365365

@@ -369,7 +369,7 @@ fn unwrapp_return_type(
369369
};
370370
}
371371
LuaType::Variadic(inner) => {
372-
if is_last_expr(&call_expr) {
372+
if is_last_call_expr(&call_expr) {
373373
return Ok(LuaType::MuliReturn(
374374
LuaMultiReturn::Base(inner.deref().clone()).into(),
375375
));
@@ -407,21 +407,22 @@ fn is_need_wrap_instance(
407407
return !call_expr.get_range().contains(inst.value.start());
408408
}
409409

410-
fn is_last_expr(call_expr: &LuaCallExpr) -> bool {
411-
let parent = call_expr.syntax().parent();
412-
if let Some(parent) = parent {
410+
fn is_last_call_expr(call_expr: &LuaCallExpr) -> bool {
411+
let mut opt_parent = call_expr.syntax().parent();
412+
while let Some(parent) = &opt_parent {
413413
match parent.kind().into() {
414414
LuaSyntaxKind::AssignStat
415415
| LuaSyntaxKind::LocalStat
416416
| LuaSyntaxKind::ReturnStat
417417
| LuaSyntaxKind::TableArrayExpr
418418
| LuaSyntaxKind::CallArgList => {
419419
let next_expr = call_expr.syntax().next_sibling();
420-
if next_expr.is_none() {
421-
return true;
422-
}
420+
return next_expr.is_none();
423421
}
424-
_ => {}
422+
LuaSyntaxKind::TableFieldValue => {
423+
opt_parent = parent.parent();
424+
}
425+
_ => return false,
425426
}
426427
}
427428

crates/emmylua_code_analysis/src/semantic/infer/infer_table.rs

Lines changed: 49 additions & 11 deletions
Original file line numberDiff line numberDiff line change
@@ -1,3 +1,5 @@
1+
use std::ops::Deref;
2+
13
use emmylua_parser::{
24
LuaAssignStat, LuaAst, LuaAstNode, LuaCallArgList, LuaCallExpr, LuaExpr, LuaIndexMemberExpr,
35
LuaLiteralToken, LuaLocalStat, LuaTableExpr, LuaTableField,
@@ -6,7 +8,7 @@ use emmylua_parser::{
68
use crate::{
79
db_index::{DbIndex, LuaType},
810
infer_call_expr_func, infer_expr, InferGuard, LuaDeclId, LuaInferCache, LuaMemberId,
9-
LuaTupleType,
11+
LuaMultiReturn, LuaTupleType,
1012
};
1113

1214
use super::{
@@ -44,29 +46,65 @@ fn infer_table_tuple_or_array(
4446
return Ok(LuaType::Array(first_type.into()));
4547
}
4648

47-
if let Some(last_field) = fields.last() {
48-
let last_value_expr = last_field.get_value_expr().ok_or(InferFailReason::None)?;
49-
if is_dots_expr(&last_value_expr).unwrap_or(false) {
50-
let dots_type = infer_expr(db, cache, last_value_expr)?;
51-
let typ = match &dots_type {
52-
LuaType::MuliReturn(multi) => multi.get_type(0).unwrap_or(&LuaType::Unknown),
53-
_ => &dots_type,
54-
};
49+
if let Some(first_field) = fields.first() {
50+
let first_value_expr = first_field.get_value_expr().ok_or(InferFailReason::None)?;
5551

56-
return Ok(LuaType::Array(typ.clone().into()));
52+
if is_dots_expr(&first_value_expr).unwrap_or(false) {
53+
let first_expr_type = infer_expr(db, cache, first_value_expr)?;
54+
match &first_expr_type {
55+
LuaType::MuliReturn(multi) => match &multi.deref() {
56+
LuaMultiReturn::Base(base) => {
57+
return Ok(LuaType::Array(base.clone().into()));
58+
}
59+
LuaMultiReturn::Multi(tuple) => {
60+
return Ok(LuaType::Tuple(LuaTupleType::new(tuple.clone()).into()));
61+
}
62+
},
63+
LuaType::Variadic(base) => {
64+
return Ok(LuaType::Array(base.clone().into()));
65+
}
66+
_ => {
67+
return Ok(LuaType::Array(first_expr_type.into()));
68+
}
69+
};
5770
}
5871
}
5972

6073
let mut types = Vec::new();
6174
for field in fields {
6275
let value_expr = field.get_value_expr().ok_or(InferFailReason::None)?;
6376
let typ = infer_expr(db, cache, value_expr)?;
64-
types.push(typ);
77+
match typ {
78+
LuaType::MuliReturn(multi) => flatten_multi_into_tuple(&mut types, &multi),
79+
_ => {
80+
types.push(typ);
81+
}
82+
}
6583
}
6684

6785
Ok(LuaType::Tuple(LuaTupleType::new(types).into()))
6886
}
6987

88+
fn flatten_multi_into_tuple(tuple_list: &mut Vec<LuaType>, multi: &LuaMultiReturn) {
89+
match multi {
90+
LuaMultiReturn::Base(base) => {
91+
tuple_list.push(LuaType::Variadic(base.clone().into()));
92+
}
93+
LuaMultiReturn::Multi(multi) => {
94+
for typ in multi {
95+
match typ {
96+
LuaType::MuliReturn(multi) => {
97+
flatten_multi_into_tuple(tuple_list, multi.deref());
98+
}
99+
_ => {
100+
tuple_list.push(typ.clone());
101+
}
102+
}
103+
}
104+
}
105+
}
106+
}
107+
70108
fn is_dots_expr(expr: &LuaExpr) -> Option<bool> {
71109
if let LuaExpr::LiteralExpr(literal) = expr {
72110
match literal.get_literal()? {

0 commit comments

Comments
 (0)